Mailspring/src/sheet.cjsx
Ben Gotow e69da22e5e feat(sidebar): Hierarchical folders/labels in the sidebar, rendering perf
Summary:
Fix label sorting... apparently we just synced them in creation date order

Allow labels / folders to be nested using separators `.`, `/`, and `\`

Allow collapsing of nested labels in sidebar

Add overflow hidden to some core flexboxes, which dramatically reduces repaints because it knows columns will not overflow into other columns

Prevent scroll region contents from re-rendering all the time, not sure why this works

Add test for account sidebar store

Test Plan: Run new test of AccountSidebarStore

Reviewers: evan

Reviewed By: evan

Differential Revision: https://phab.nylas.com/D2181
2015-10-22 10:53:57 -07:00

137 lines
5 KiB
CoffeeScript

React = require 'react'
_ = require 'underscore'
{Actions,ComponentRegistry, WorkspaceStore} = require "nylas-exports"
RetinaImg = require './components/retina-img'
Flexbox = require './components/flexbox'
InjectedComponentSet = require './components/injected-component-set'
ResizableRegion = require './components/resizable-region'
FLEX = 10000
class Sheet extends React.Component
@displayName = 'Sheet'
@propTypes =
data: React.PropTypes.object.isRequired
depth: React.PropTypes.number.isRequired
onColumnSizeChanged: React.PropTypes.func
@childContextTypes:
sheetDepth: React.PropTypes.number
getChildContext: =>
sheetDepth: @props.depth
constructor: (@props) ->
@state = @_getStateFromStores()
componentDidMount: =>
@unlisteners ?= []
@unlisteners.push ComponentRegistry.listen (event) =>
@setState(@_getStateFromStores())
@unlisteners.push WorkspaceStore.listen (event) =>
@setState(@_getStateFromStores())
componentDidUpdate: =>
@props.onColumnSizeChanged(@) if @props.onColumnSizeChanged
minWidth = 0
minWidth += col.minWidth for col in @state.columns
atom.setMinimumWidth(minWidth)
shouldComponentUpdate: (nextProps, nextState) =>
not _.isEqual(nextProps, @props) or not _.isEqual(nextState, @state)
componentWillUnmount: =>
unlisten() for unlisten in @unlisteners
render: =>
style =
position:'absolute'
width:'100%'
height:'100%'
zIndex: 1
# Note - setting the z-index of the sheet is important, even though it's
# always 1. Assigning a z-index creates a "stacking context" in the browser,
# so z-indexes inside the sheet are relative to each other, but something in
# one sheet cannot be on top of something in another sheet.
# http://philipwalton.com/articles/what-no-one-told-you-about-z-index/
<div name={"Sheet"}
style={style}
className={"sheet mode-#{@state.mode}"}
data-id={@props.data.id}>
<Flexbox direction="row" style={overflow: 'hidden'}>
{@_columnFlexboxElements()}
</Flexbox>
</div>
_columnFlexboxElements: =>
@state.columns.map ({maxWidth, minWidth, handle, location}, idx) =>
if minWidth != maxWidth and maxWidth < FLEX
<ResizableRegion key={"#{@props.data.id}:#{idx}"}
name={"#{@props.data.id}:#{idx}"}
className={"column-#{location.id}"}
style={height:'100%'}
data-column={idx}
onResize={ => @props.onColumnSizeChanged(@) }
minWidth={minWidth}
maxWidth={maxWidth}
handle={handle}>
<InjectedComponentSet direction="column" matching={location: location, mode: @state.mode}/>
</ResizableRegion>
else
style =
height: '100%'
minWidth: minWidth
overflow: 'hidden'
if maxWidth < FLEX
style.width = maxWidth
else
style.flex = 1
<InjectedComponentSet direction="column"
key={"#{@props.data.id}:#{idx}"}
name={"#{@props.data.id}:#{idx}"}
className={"column-#{location.id}"}
data-column={idx}
style={style}
matching={location: location, mode: @state.mode}/>
_getStateFromStores: =>
state =
mode: WorkspaceStore.layoutMode()
columns: []
widest = -1
widestWidth = -1
if @props.data?.columns[state.mode]?
for location, idx in @props.data.columns[state.mode]
continue if WorkspaceStore.isLocationHidden(location)
entries = ComponentRegistry.findComponentsMatching({location: location, mode: state.mode})
maxWidth = _.reduce entries, ((m,component) -> Math.min(component.containerStyles?.maxWidth ? 10000, m)), 10000
minWidth = _.reduce entries, ((m,component) -> Math.max(component.containerStyles?.minWidth ? 0, m)), 0
col = {maxWidth, minWidth, location}
state.columns.push(col)
if maxWidth > widestWidth
widestWidth = maxWidth
widest = idx
if state.columns.length > 0
# Once we've accumulated all the React components for the columns,
# ensure that at least one column has a huge max-width so that the columns
# expand to fill the window. This may make items in the column unhappy, but
# we pick the column with the highest max-width so the effect is minimal.
state.columns[widest].maxWidth = FLEX
# Assign flexible edges based on whether items are to the left or right
# of the flexible column (which has no edges)
state.columns[i].handle = ResizableRegion.Handle.Right for i in [0..widest-1] by 1
state.columns[i].handle = ResizableRegion.Handle.Left for i in [widest..state.columns.length-1] by 1
state
_pop: =>
Actions.popSheet()
module.exports = Sheet