From 383db29f274bf6931cc64660372ffaf59e7efc07 Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Mon, 31 Jul 2017 23:10:46 -0700 Subject: [PATCH] Move sheet, sheet toolbar to JSX --- packages/client-app/src/sheet-toolbar.cjsx | 259 --------------- packages/client-app/src/sheet-toolbar.jsx | 364 +++++++++++++++++++++ packages/client-app/src/sheet.cjsx | 148 --------- packages/client-app/src/sheet.jsx | 214 ++++++++++++ 4 files changed, 578 insertions(+), 407 deletions(-) delete mode 100644 packages/client-app/src/sheet-toolbar.cjsx create mode 100644 packages/client-app/src/sheet-toolbar.jsx delete mode 100644 packages/client-app/src/sheet.cjsx create mode 100644 packages/client-app/src/sheet.jsx diff --git a/packages/client-app/src/sheet-toolbar.cjsx b/packages/client-app/src/sheet-toolbar.cjsx deleted file mode 100644 index cb490a3e4..000000000 --- a/packages/client-app/src/sheet-toolbar.cjsx +++ /dev/null @@ -1,259 +0,0 @@ -React = require 'react' -ReactDOM = require 'react-dom' -Sheet = require './sheet' -Flexbox = require('./components/flexbox').default -RetinaImg = require('./components/retina-img').default -Utils = require './flux/models/utils' -{remote} = require 'electron' -_str = require 'underscore.string' -_ = require 'underscore' - -{Actions, - ComponentRegistry, - WorkspaceStore} = require "nylas-exports" - -class ToolbarSpacer extends React.Component - @displayName: 'ToolbarSpacer' - @propTypes: - order: React.PropTypes.number - - render: => -
- -class WindowTitle extends React.Component - @displayName: "WindowTitle" - - constructor: (@props) -> - @state = NylasEnv.getLoadSettings() - - componentDidMount: -> - @unlisten = NylasEnv.onWindowPropsReceived (windowProps) => - @setState NylasEnv.getLoadSettings() - - componentWillUnmount: -> - @unlisten?() - - render: -> -
{@state.title}
- -Category = null -FocusedPerspectiveStore = null -class ToolbarBack extends React.Component - @displayName: 'ToolbarBack' - - # These stores are only required when this Toolbar is actually needed. - # This is because loading these stores has database side effects. - constructor: (@props) -> - Category ?= require('./flux/models/category').default - FocusedPerspectiveStore ?= require('./flux/stores/focused-perspective-store').default - @state = - categoryName: FocusedPerspectiveStore.current().name - - componentDidMount: => - @_unsubscriber = FocusedPerspectiveStore.listen => - @setState(categoryName: FocusedPerspectiveStore.current().name) - - componentWillUnmount: => - @_unsubscriber() if @_unsubscriber - - render: => - if @state.categoryName is Category.AllMailName - title = 'All Mail' - else if @state.categoryName - title = _str.titleize(@state.categoryName) - else - title = "Back" - -
- -
{title}
-
- - _onClick: => - Actions.popSheet() - -class ToolbarWindowControls extends React.Component - @displayName: 'ToolbarWindowControls' - constructor: (@props) -> - @state = {alt: false} - - componentDidMount: => - if process.platform is 'darwin' - window.addEventListener('keydown', @_onAlt) - window.addEventListener('keyup', @_onAlt) - - componentWillUnmount: => - if process.platform is 'darwin' - window.removeEventListener('keydown', @_onAlt) - window.removeEventListener('keyup', @_onAlt) - - render: => -
- - - -
- - _onAlt: (event) => - @setState(alt: event.altKey) if @state.alt isnt event.altKey - - _onMaximize: (event) => - if process.platform is 'darwin' and not event.altKey - NylasEnv.setFullScreen(!NylasEnv.isFullScreen()) - else - NylasEnv.maximize() - -class ToolbarMenuControl extends React.Component - @displayName: 'ToolbarMenuControl' - render: => -
- -
- - _openMenu: => - applicationMenu = remote.getGlobal('application').applicationMenu - applicationMenu.menu.popup(NylasEnv.getCurrentWindow()) - -ComponentRegistry.register ToolbarWindowControls, - location: WorkspaceStore.Sheet.Global.Toolbar.Left - -ComponentRegistry.register ToolbarMenuControl, - location: WorkspaceStore.Sheet.Global.Toolbar.Right - -class Toolbar extends React.Component - @displayName: 'Toolbar' - - @propTypes: - data: React.PropTypes.object - depth: React.PropTypes.number - - @childContextTypes: - sheetDepth: React.PropTypes.number - getChildContext: => - sheetDepth: @props.depth - - constructor: (@props) -> - @state = @_getStateFromStores() - - componentDidMount: => - @mounted = true - @unlisteners = [] - @unlisteners.push WorkspaceStore.listen (event) => - @setState(@_getStateFromStores()) - @unlisteners.push ComponentRegistry.listen (event) => - @setState(@_getStateFromStores()) - window.addEventListener("resize", @_onWindowResize) - window.requestAnimationFrame => @recomputeLayout() - - componentWillUnmount: => - @mounted = false - window.removeEventListener("resize", @_onWindowResize) - unlistener() for unlistener in @unlisteners - - componentWillReceiveProps: (props) => - @setState(@_getStateFromStores(props)) - - componentDidUpdate: => - # Wait for other components that are dirty (the actual columns in the sheet) - window.requestAnimationFrame => @recomputeLayout() - - shouldComponentUpdate: (nextProps, nextState) => - # This is very important. Because toolbar uses ReactCSSTransitionGroup, - # repetitive unnecessary updates can break animations and cause performance issues. - not Utils.isEqualReact(nextProps, @props) or not Utils.isEqualReact(nextState, @state) - - render: => - style = - position:'absolute' - width:'100%' - height:'100%' - zIndex: 1 - - toolbars = @state.columns.map (components, idx) => -
- {@_flexboxForComponents(components)} -
- -
- {toolbars} -
- - _flexboxForComponents: (components) => - elements = components.map (Component) => - - - - {elements} - - - - - recomputeLayout: => - # Yes this really happens - do not remove! - return unless @mounted - - # Find our item containers that are tied to specific columns - el = ReactDOM.findDOMNode(@) - columnToolbarEls = el.querySelectorAll('[data-column]') - - # Find the top sheet in the stack - sheet = document.querySelectorAll("[name='Sheet']")[@props.depth] - return unless sheet - - # Position item containers so they have the position and width - # as their respective columns in the top sheet - for columnToolbarEl in columnToolbarEls - column = columnToolbarEl.dataset.column - columnEl = sheet.querySelector("[data-column='#{column}']") - continue unless columnEl - - columnToolbarEl.style.display = 'inherit' - columnToolbarEl.style.left = "#{columnEl.offsetLeft}px" - columnToolbarEl.style.width = "#{columnEl.offsetWidth}px" - - # Record our overall height for sheets - remote.getCurrentWindow().setSheetOffset(el.clientHeight) - - _onWindowResize: => - @recomputeLayout() - - _getStateFromStores: (props) => - props ?= @props - state = - mode: WorkspaceStore.layoutMode() - columns: [] - columnNames: [] - - # Add items registered to Regions in the current sheet - if @props.data?.columns[state.mode]? - for loc in @props.data.columns[state.mode] - continue if WorkspaceStore.isLocationHidden(loc) - entries = ComponentRegistry.findComponentsMatching({location: loc.Toolbar, mode: state.mode}) - state.columns.push(entries) - state.columnNames.push(loc.Toolbar.id.split(":")[0]) if entries - - # Add left items registered to the Sheet instead of to a Region - for loc in [WorkspaceStore.Sheet.Global, @props.data] - entries = ComponentRegistry.findComponentsMatching({location: loc.Toolbar.Left, mode: state.mode}) - state.columns[0]?.push(entries...) - if @props.depth > 0 - state.columns[0]?.push(ToolbarBack) - - # Add right items registered to the Sheet instead of to a Region - for loc in [WorkspaceStore.Sheet.Global, @props.data] - entries = ComponentRegistry.findComponentsMatching({location: loc.Toolbar.Right, mode: state.mode}) - state.columns[state.columns.length - 1]?.push(entries...) - if state.mode is "popout" - state.columns[0]?.push(WindowTitle) - - state - -module.exports = Toolbar diff --git a/packages/client-app/src/sheet-toolbar.jsx b/packages/client-app/src/sheet-toolbar.jsx new file mode 100644 index 000000000..e992f4a5e --- /dev/null +++ b/packages/client-app/src/sheet-toolbar.jsx @@ -0,0 +1,364 @@ +/* eslint react/prefer-stateless-function: 0 */ +/* eslint global-require: 0 */ +import React from 'react' +import ReactDOM from 'react-dom' +import {remote} from 'electron' +import _str from 'underscore.string' +import { + Actions, + ComponentRegistry, + WorkspaceStore, +} from "nylas-exports"; + +import Flexbox from './components/flexbox' +import RetinaImg from './components/retina-img' +import Utils from './flux/models/utils' + +let Category = null; +let FocusedPerspectiveStore = null; + +class ToolbarSpacer extends React.Component { + static displayName = 'ToolbarSpacer'; + static propTypes = { + order: React.PropTypes.number, + }; + + render() { + return ( +
+ ); + } +} + +class WindowTitle extends React.Component { + static displayName = "WindowTitle"; + + constructor(props) { + super(props); + this.state = NylasEnv.getLoadSettings(); + } + + componentDidMount() { + this.unlisten = NylasEnv.onWindowPropsReceived(() => + this.setState(NylasEnv.getLoadSettings()) + ); + } + + componentWillUnmount() { + if (this.unlisten) { + this.unlisten(); + } + } + + render() { + return ( +
{this.state.title}
+ ); + } +} + +class ToolbarBack extends React.Component { + static displayName = 'ToolbarBack'; + + // These stores are only required when this Toolbar is actually needed. + // This is because loading these stores has database side effects. + constructor(props) { + super(props); + Category = Category || require('./flux/models/category').default + FocusedPerspectiveStore = FocusedPerspectiveStore || require('./flux/stores/focused-perspective-store').default + this.state = { + categoryName: FocusedPerspectiveStore.current().name, + } + } + + componentDidMount() { + this._unsubscriber = FocusedPerspectiveStore.listen(() => + this.setState({categoryName: FocusedPerspectiveStore.current().name}) + ); + } + + componentWillUnmount() { + if (this._unsubscriber) { + this._unsubscriber(); + } + } + + _onClick = () => { + Actions.popSheet(); + } + + render() { + let title = "Back"; + if (this.state.categoryName === Category.AllMailName) { + title = 'All Mail' + } else if (this.state.categoryName) { + title = _str.titleize(this.state.categoryName); + } + return ( +
+ +
{title}
+
+ ); + } +} + +class ToolbarWindowControls extends React.Component { + static displayName = 'ToolbarWindowControls'; + + constructor(props) { + super(props); + this.state = {alt: false}; + } + + componentDidMount() { + if (process.platform === 'darwin') { + window.addEventListener('keydown', this._onAlt); + window.addEventListener('keyup', this._onAlt); + } + } + + componentWillUnmount() { + if (process.platform === 'darwin') { + window.removeEventListener('keydown', this._onAlt); + window.removeEventListener('keyup', this._onAlt); + } + } + + _onAlt = (event) => { + if (this.state.alt !== event.altKey) { + this.setState({alt: event.altKey}); + } + } + + _onMaximize = (event) => { + if (process.platform === 'darwin' && !event.altKey) { + NylasEnv.setFullScreen(!NylasEnv.isFullScreen()); + } else { + NylasEnv.maximize(); + } + } + + render() { + return ( +
+
+ ); + } +} + +class ToolbarMenuControl extends React.Component { + static displayName = 'ToolbarMenuControl'; + + _onOpenMenu = () => { + const {applicationMenu} = remote.getGlobal('application'); + applicationMenu.menu.popup(NylasEnv.getCurrentWindow()); + } + + render() { + return ( +
+ +
+ ); + } +} + +ComponentRegistry.register(ToolbarWindowControls, { + location: WorkspaceStore.Sheet.Global.Toolbar.Left, +}); + +ComponentRegistry.register(ToolbarMenuControl, { + location: WorkspaceStore.Sheet.Global.Toolbar.Right, +}); + +export default class Toolbar extends React.Component { + static displayName= 'Toolbar'; + + static propTypes = { + data: React.PropTypes.object, + depth: React.PropTypes.number, + } + + static childContextTypes = { + sheetDepth: React.PropTypes.number, + } + + constructor(props) { + super(props); + this.state = this._getStateFromStores(); + } + + getChildContext() { + return { + sheetDepth: this.props.depth, + } + } + + componentDidMount() { + this.mounted = true + this.unlisteners = [] + this.unlisteners.push(WorkspaceStore.listen(() => + this.setState(this._getStateFromStores()) + )); + this.unlisteners.push(ComponentRegistry.listen(() => + this.setState(this._getStateFromStores()) + )); + window.addEventListener("resize", this._onWindowResize) + window.requestAnimationFrame(() => this.recomputeLayout()); + } + + componentWillReceiveProps(props) { + this.setState(this._getStateFromStores(props)); + } + + shouldComponentUpdate(nextProps, nextState) { + // This is very important. Because toolbar uses ReactCSSTransitionGroup, + // repetitive unnecessary updates can break animations and cause performance issues. + return !Utils.isEqualReact(nextProps, this.props) || !Utils.isEqualReact(nextState, this.state); + } + + componentDidUpdate() { + // Wait for other components that are dirty (the actual columns in the sheet) + window.requestAnimationFrame(() => this.recomputeLayout()); + } + + componentWillUnmount() { + this.mounted = false + window.removeEventListener("resize", this._onWindowResize); + for (const u of this.unlisteners) { + u(); + } + } + + recomputeLayout() { + // Yes this really happens - do not remove! + if (!this.mounted) { + return; + } + + // Find our item containers that are tied to specific columns + const el = ReactDOM.findDOMNode(this); + const columnToolbarEls = el.querySelectorAll('[data-column]'); + + // Find the top sheet in the stack + const sheet = document.querySelectorAll("[name='Sheet']")[this.props.depth]; + if (!sheet) { + return; + } + + // Position item containers so they have the position and width + // as their respective columns in the top sheet + for (const columnToolbarEl of columnToolbarEls) { + const column = columnToolbarEl.dataset.column; + const columnEl = sheet.querySelector(`[data-column='${column}']`); + if (!columnEl) { + continue; + } + + columnToolbarEl.style.display = 'inherit' + columnToolbarEl.style.left = `${columnEl.offsetLeft}px` + columnToolbarEl.style.width = `${columnEl.offsetWidth}px`; + } + + // Record our overall height for sheets + remote.getCurrentWindow().setSheetOffset(el.clientHeight); + } + + _onWindowResize = () => { + this.recomputeLayout(); + } + + _getStateFromStores(props = this.props) { + const state = { + mode: WorkspaceStore.layoutMode(), + columns: [], + columnNames: [], + } + + // Add items registered to Regions in the current sheet + if (props.data && props.data.columns[state.mode]) { + for (const loc of props.data.columns[state.mode]) { + if (WorkspaceStore.isLocationHidden(loc)) { + continue; + } + const entries = ComponentRegistry.findComponentsMatching({location: loc.Toolbar, mode: state.mode}); + state.columns.push(entries); + if (entries) { + state.columnNames.push(loc.Toolbar.id.split(":")[0]); + } + } + } + + // Add left items registered to the Sheet instead of to a Region + if (state.columns.length > 0) { + for (const loc of [WorkspaceStore.Sheet.Global, props.data]) { + const entries = ComponentRegistry.findComponentsMatching({location: loc.Toolbar.Left, mode: state.mode}) + state.columns[0].push(...entries); + } + if (props.depth > 0) { + state.columns[0].push(ToolbarBack); + } + + // Add right items registered to the Sheet instead of to a Region + for (const loc of [WorkspaceStore.Sheet.Global, props.data]) { + const entries = ComponentRegistry.findComponentsMatching({location: loc.Toolbar.Right, mode: state.mode}) + state.columns[state.columns.length - 1].push(...entries); + } + + if (state.mode === "popout") { + state.columns[0].push(WindowTitle); + } + } + + return state; + } + + _flexboxForComponents(components) { + const elements = components.map((Component) => + + ); + return ( + + {elements} + + + + ); + } + + render() { + const style = { + position: 'absolute', + width: '100%', + height: '100%', + zIndex: 1, + }; + + const toolbars = this.state.columns.map((components, idx) => +
+ {this._flexboxForComponents(components)} +
+ ); + + return ( +
+ {toolbars} +
+ ); + } +} diff --git a/packages/client-app/src/sheet.cjsx b/packages/client-app/src/sheet.cjsx deleted file mode 100644 index 422a2c221..000000000 --- a/packages/client-app/src/sheet.cjsx +++ /dev/null @@ -1,148 +0,0 @@ -React = require 'react' -_ = require 'underscore' -{Actions,ComponentRegistry, WorkspaceStore} = require "nylas-exports" -RetinaImg = require('./components/retina-img').default -Flexbox = require('./components/flexbox').default -InjectedComponentSet = require('./components/injected-component-set').default -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 - - @defaultProps: - onColumnSizeChanged: -> - - @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(@) - minWidth = 0 - minWidth += col.minWidth for col in @state.columns - NylasEnv.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/ - -
- - {@_columnFlexboxElements()} - -
- - _columnFlexboxElements: => - @state.columns.map (column, idx) => - {maxWidth, minWidth, handle, location, width} = column - if minWidth != maxWidth and maxWidth < FLEX - - - - else - style = - height: '100%' - minWidth: minWidth - overflow: 'hidden' - if maxWidth < FLEX - style.width = maxWidth - else - style.flex = 1 - - - _onColumnResize: (column, width) => - NylasEnv.storeColumnWidth(id: column.location.id, width: width) - @props.onColumnSizeChanged(@) - - _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 - width = NylasEnv.getColumnWidth(location.id) - col = {maxWidth, minWidth, location, width} - 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 diff --git a/packages/client-app/src/sheet.jsx b/packages/client-app/src/sheet.jsx new file mode 100644 index 000000000..9b0b72fb3 --- /dev/null +++ b/packages/client-app/src/sheet.jsx @@ -0,0 +1,214 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import {Utils, ComponentRegistry, WorkspaceStore} from "nylas-exports"; +import InjectedComponentSet from './components/injected-component-set'; +import ResizableRegion from './components/resizable-region'; +import Flexbox from './components/flexbox'; + +const FLEX = 10000; + +export default class Sheet extends React.Component { + static displayName = 'Sheet'; + + static propTypes = { + data: PropTypes.object.isRequired, + depth: PropTypes.number.isRequired, + onColumnSizeChanged: PropTypes.func, + } + + static defaultProps = { + onColumnSizeChanged: () => {}, + }; + + static childContextTypes = { + sheetDepth: React.PropTypes.number, + } + + constructor(props) { + super(props); + this.unlisteners = []; + this.state = this._getStateFromStores(); + } + + getChildContext() { + return { + sheetDepth: this.props.depth, + }; + } + + componentDidMount() { + this.unlisteners.push(ComponentRegistry.listen(() => + this.setState(this._getStateFromStores()) + )); + this.unlisteners.push(WorkspaceStore.listen(() => + this.setState(this._getStateFromStores()) + )); + } + + shouldComponentUpdate(nextProps, nextState) { + return !Utils.isEqualReact(nextProps, this.props) || !Utils.isEqualReact(nextState, this.state); + } + + componentDidUpdate() { + this.props.onColumnSizeChanged(this); + const minWidth = this.state.columns.reduce((sum, col) => sum + col.minWidth, 0); + NylasEnv.setMinimumWidth(minWidth); + } + + componentWillUnmount() { + for (const u of this.unlisteners) { + u(); + } + this.unlisteners = []; + } + + + _columnFlexboxElements() { + return this.state.columns.map((column, idx) => { + const {maxWidth, minWidth, handle, location, width} = column; + + if (minWidth !== maxWidth && maxWidth < FLEX) { + return ( + this._onColumnResize(column, w)} + initialWidth={width} + minWidth={minWidth} + maxWidth={maxWidth} + handle={handle} + > + + + ); + } + + const style = { + height: '100%', + minWidth: minWidth, + overflow: 'hidden', + } + if (maxWidth < FLEX) { + style.width = maxWidth; + } else { + style.flex = 1; + } + return ( + + ); + }); + } + + _onColumnResize = (column, width) => { + NylasEnv.storeColumnWidth({id: column.location.id, width: width}); + this.props.onColumnSizeChanged(this); + } + + _getStateFromStores() { + const state = { + mode: WorkspaceStore.layoutMode(), + columns: [], + } + + let widest = -1; + let widestWidth = -1; + + const data = this.props.data || {}; + + if (data.columns[state.mode]) { + data.columns[state.mode].forEach((location, idx) => { + if (WorkspaceStore.isLocationHidden(location)) { + return; + } + const entries = ComponentRegistry.findComponentsMatching({ + location: location, + mode: state.mode, + }); + + const maxWidth = entries.reduce((m, {containerStyles}) => { + if (containerStyles && containerStyles.maxWidth !== undefined && containerStyles.maxWidth < m) { + return containerStyles.maxWidth; + } + return m; + }, 10000); + + const minWidth = entries.reduce((m, {containerStyles}) => { + if (containerStyles && containerStyles.minWidth !== undefined && containerStyles.minWidth > m) { + return containerStyles.minWidth; + } + return m; + }, 0); + + const width = NylasEnv.getColumnWidth(location.id); + const col = {maxWidth, minWidth, location, width}; + 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) + for (let i = 0; i < widest; i++) { + state.columns[i].handle = ResizableRegion.Handle.Right; + } + for (let i = widest; i < state.columns.length; i++) { + state.columns[i].handle = ResizableRegion.Handle.Left; + } + } + return state; + } + + render() { + const 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/ + + return ( +
+ + {this._columnFlexboxElements()} + +
+ ); + } +}