fix(message-list): get rid of flicker and add transitions

Test Plan: edgehill --test

Reviewers: bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D1841
This commit is contained in:
Evan Morikawa 2015-08-04 19:35:56 -07:00
parent 0fc50230e7
commit 9fe11bd655
5 changed files with 88 additions and 23 deletions

View file

@ -13,13 +13,13 @@ class MessageControls extends React.Component
render: =>
<div className="message-actions-wrap">
<div className="message-actions-ellipsis" onClick={@_onShowActionsMenu}>
<RetinaImg name={"message-actions-ellipsis.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</div>
<ButtonDropdown
primaryItem={<RetinaImg name="ic-message-button-reply.png" mode={RetinaImg.Mode.ContentIsMask}/>}
primaryClick={@_onReply}
menu={@_dropdownMenu()}/>
<div className="message-actions-ellipsis" onClick={@_onShowActionsMenu}>
<RetinaImg name={"message-actions-ellipsis.png"} mode={RetinaImg.Mode.ContentIsMask}/>
</div>
</div>
_dropdownMenu: ->

View file

@ -2,9 +2,9 @@ React = require 'react'
classNames = require 'classnames'
MessageItem = require './message-item'
PendingMessageItem = require './pending-message-item'
{DraftStore,
{Utils,
DraftStore,
MessageStore} = require 'nylas-exports'
{InjectedComponent} = require 'nylas-component-kit'
@ -35,6 +35,10 @@ class MessageItemContainer extends React.Component
if @props.message?.draft
@unlisten = DraftStore.listen @_onSendingStateChanged
shouldComponentUpdate: (nextProps, nextState) =>
not Utils.isEqualReact(nextProps, @props) or
not Utils.isEqualReact(nextState, @state)
componentWillUnmount: =>
@unlisten() if @unlisten
@ -43,19 +47,20 @@ class MessageItemContainer extends React.Component
render: =>
if @props.message.draft
if @state.isSending
@_renderMessage(PendingMessageItem)
@_renderMessage(pending: true)
else
@_renderComposer()
else
@_renderMessage(MessageItem)
@_renderMessage(pending: false)
_renderMessage: (component) =>
<component ref="message"
thread={@props.thread}
message={@props.message}
className={@_classNames()}
collapsed={@props.collapsed}
isLastMsg={@props.isLastMsg} />
_renderMessage: ({pending}) =>
<MessageItem ref="message"
pending={pending}
thread={@props.thread}
message={@props.message}
className={@_classNames()}
collapsed={@props.collapsed}
isLastMsg={@props.isLastMsg} />
_renderComposer: =>
props =

View file

@ -90,7 +90,11 @@ class MessageItem extends React.Component
</div>
_renderHeader: =>
<header className="message-header" onClick={@_onClickHeader}>
classes = classNames
"message-header": true
"pending": @props.pending
<header className={classes} onClick={@_onClickHeader}>
{@_renderHeaderSideItems()}
@ -171,11 +175,19 @@ class MessageItem extends React.Component
'no-quoted-text': not QuotedHTMLParser.hasQuotedHTML(@props.message.body)
'show-quoted-text': @state.showQuotedText
# This is used by subclasses of MessageItem.
# See {PendingMessageItem}
_renderHeaderSideItems: -> []
_renderHeaderSideItems: ->
styles =
position: "absolute"
marginTop: -2
<div className="pending-spinner" style={styles}>
<RetinaImg ref="spinner"
name="sending-spinner.gif"
mode={RetinaImg.Mode.ContentPreserve}/>
</div>
_renderHeaderDetailToggle: =>
return null if @props.pending
if @state.detailedHeaders
<div className="header-toggle-control"
style={top: "18px", left: "-14px"}

View file

@ -251,8 +251,19 @@ class MessageList extends React.Component
labels.map (label) =>
<MailLabel label={label} key={label.id} onRemove={ => @_onRemoveLabel(label) }/>
_renderReplyArea: =>
<div className="footer-reply-area-wrap" onClick={@_onClickReplyArea} key='reply-area'>
_renderReplyArea: ({noTransition}={}) =>
if @_hasReplyArea()
styles =
"height": 63
"borderTop": "1px dashed #ddd"
else
styles =
"height": 0
"border": 0
unless noTransition
styles["transition"] = "height 150ms"
<div className="footer-reply-area-wrap" style={styles} onClick={@_onClickReplyArea} key='reply-area'>
<div className="footer-reply-area">
<RetinaImg name="#{@_replyType()}-footer.png" mode={RetinaImg.Mode.ContentIsMask}/>
<span className="reply-text">Write a reply…</span>
@ -306,8 +317,7 @@ class MessageList extends React.Component
onRequestScrollTo={@_onChildScrollRequest} />
)
if @_hasReplyArea()
elements.push @_renderReplyArea()
elements.push @_renderReplyArea(noTransition: _.last(messages)?.draft)
return elements

View file

@ -257,6 +257,23 @@
padding-bottom: @spacing-standard;
padding-top: 19px;
&.pending {
.message-actions-wrap {
width: 0;
opacity: 0;
}
.pending-spinner {
opacity: 1;
}
}
.pending-spinner {
transition: opacity 100ms;
transition-delay: 50ms, 0ms;
transition-timing-function: ease-in;
opacity: 0;
}
.header-row {
margin-top: 0.5em;
color: @text-color-very-subtle;
@ -273,11 +290,22 @@
}
.message-actions-wrap {
transition: opacity 100ms, width 150ms;
transition-delay: 50ms, 0ms;
transition-timing-function: ease-in-out;
width: 98px;
height: 32px;
opacity: 1;
text-align: right;
.button-dropdown {
width: 76px;
}
}
.message-actions-ellipsis {
display: inline-block;
display: block;
float: left;
}
.message-actions {
@ -365,6 +393,8 @@
}
.footer-reply-area-wrap {
overflow: hidden;
width: calc(~"100% - 12px");
max-width: @message-max-width;
margin: -3px auto @spacing-double auto;
@ -415,8 +445,16 @@
///////////////////////////////
// message-participants.cjsx //
///////////////////////////////
.pending {
.message-participants {
padding-left: 34px;
}
}
.message-participants {
transition: padding-left 150ms;
transition-timing-function: ease-in-out;
&.collapsed:hover {cursor: default;}
.from-contact {