diff --git a/src/DefaultEditor.js b/src/DefaultEditor.js index eb65e1330..629b654e4 100644 --- a/src/DefaultEditor.js +++ b/src/DefaultEditor.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { AxesSelector, AxesRange, + CanvasSize, ColorPicker, DataSelector, Dropdown, @@ -14,8 +15,10 @@ import { PanelMenuWrapper, Radio, Section, - SubPanel, + MenuPanel, + SymbolSelector, TraceAccordion, + TraceMarkerSection, TraceSelector, } from './components'; import {DEFAULT_FONTS} from './constants'; @@ -25,32 +28,6 @@ const LayoutPanel = connectLayoutToPlot(Panel); const AxesFold = connectAxesToLayout(Fold); class DefaultEditor extends Component { - constructor(props, context) { - super(props, context); - - const capitalize = s => s.charAt(0).toUpperCase() + s.substring(1); - - // Filter out Polar "area" type as it is fairly broken and we want to present - // scatter with fill as an "area" chart type for convenience. - const traceTypes = Object.keys(context.plotSchema.traces).filter( - t => t !== 'area' - ); - - const labels = traceTypes.map(capitalize); - this.traceOptions = traceTypes.map((t, i) => ({ - label: labels[i], - value: t, - })); - - const i = this.traceOptions.findIndex(opt => opt.value === 'scatter'); - this.traceOptions.splice( - i + 1, - 0, - {label: 'Line', value: 'line'}, - {label: 'Area', value: 'area'} - ); - } - render() { const _ = this.props.localize; @@ -62,7 +39,6 @@ class DefaultEditor extends Component { label="Plot Type" attr="type" clearable={false} - options={this.traceOptions} show /> @@ -114,6 +90,18 @@ class DefaultEditor extends Component { +
+ +
+
-
- + - - - + + - - -
+ + + +
- - - + - + + + + + + + + + + @@ -218,21 +237,21 @@ class DefaultEditor extends Component {
- - - - - - - - - - - - - - - + {/* + + + + + + + + + + + + + + */} @@ -278,7 +297,7 @@ class DefaultEditor extends Component { />
- +
{_( @@ -303,7 +322,7 @@ class DefaultEditor extends Component { ]} />
-
+ + + {this.props.label} + + + {isOpen ? ( + {this.props.children} + ) : null} + + ); + } +} + +MenuPanel.propTypes = { + children: PropTypes.node, + iconClass: PropTypes.string, + show: PropTypes.bool, + ownline: PropTypes.bool, + question: PropTypes.bool, + label: PropTypes.string, +}; diff --git a/src/components/containers/ModalBox.js b/src/components/containers/ModalBox.js new file mode 100644 index 000000000..c1ec315d6 --- /dev/null +++ b/src/components/containers/ModalBox.js @@ -0,0 +1,24 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; + +export default class ModalBox extends Component { + render() { + let style; + if (this.props.backgroundColor) { + style = {backgroundColor: this.props.backgroundColor}; + } + + return ( +
+
+
{this.props.children}
+
+ ); + } +} + +ModalBox.propTypes = { + backgroundColor: PropTypes.string, + children: PropTypes.node, + onClose: PropTypes.func, +}; diff --git a/src/components/containers/Section.js b/src/components/containers/Section.js index 7ba68da10..264f390ad 100644 --- a/src/components/containers/Section.js +++ b/src/components/containers/Section.js @@ -1,4 +1,4 @@ -import SubPanel from './SubPanel'; +import MenuPanel from './MenuPanel'; import React, {Component, cloneElement} from 'react'; import PropTypes from 'prop-types'; import unpackPlotProps from '../../lib/unpackPlotProps'; @@ -12,7 +12,7 @@ class Section extends Component { super(props, context); this.children = null; - this.subPanel = null; + this.menuPanel = null; this.processAndSetChildren(context); } @@ -28,45 +28,50 @@ class Section extends Component { } const attrChildren = []; - let subPanel = null; + let menuPanel = null; for (let i = 0; i < children.length; i++) { const child = children[i]; if (!child) { continue; } - if (child.type === SubPanel) { - // Process the first subPanel. Ignore the rest. - if (subPanel) { + if (child.type === MenuPanel) { + // Process the first menuPanel. Ignore the rest. + if (menuPanel) { continue; } - subPanel = child; + menuPanel = child; continue; } const isAttr = Boolean(child.props.attr); - const plotProps = isAttr - ? unpackPlotProps(child.props, context, child.type) - : {isVisible: true}; + let plotProps; + if (child.plotProps) { + plotProps = child.plotProps; + } else if (isAttr) { + plotProps = unpackPlotProps(child.props, context, child.type); + } else { + plotProps = {isVisible: true}; + } const childProps = Object.assign({plotProps}, child.props); childProps.key = i; attrChildren.push(cloneElement(child, childProps)); } this.children = attrChildren.length ? attrChildren : null; - this.subPanel = subPanel; + this.menuPanel = menuPanel; } render() { const hasVisibleChildren = (this.children && this.children.some(childIsVisible)) || - Boolean(this.subPanel); + Boolean(this.menuPanel); return hasVisibleChildren ? (
{this.props.name} - {this.subPanel} + {this.menuPanel}
{this.children}
diff --git a/src/components/containers/SubPanel.js b/src/components/containers/SubPanel.js deleted file mode 100644 index 941065d0b..000000000 --- a/src/components/containers/SubPanel.js +++ /dev/null @@ -1,67 +0,0 @@ -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; - -export default class SubPanel extends Component { - constructor() { - super(); - this.state = {isVisible: false}; - - this.toggleVisibility = this.toggleVisibility.bind(this); - } - - subpanelClasses() { - if (this.props.iconClass) { - return { - iconClass: `subpanel__icon ${this.props.iconClass}`, - spanClass: 'subpanel__icon-span', - }; - } else if (this.props.question) { - return { - iconClass: 'subpanel__icon plotlyjs_editor__icon-question-circle', - spanClass: `subpanel__icon-span subpanel__icon-span--question`, - }; - } - return { - iconClass: 'subpanel__icon plotlyjs_editor__icon-cog', - spanClass: 'subpanel__icon-span subpanel__icon-span--cog', - }; - } - - toggleVisibility() { - this.setState({isVisible: !this.state.isVisible}); - } - - render() { - const isVisible = this.props.show || this.state.isVisible; - const containerClass = classnames('subpanel__container', { - 'subpanel__container--ownline': this.props.ownline, - }); - - const {iconClass, spanClass} = this.subpanelClasses(); - - return ( -
- - {this.props.label} - - - {isVisible ? ( -
-
-
{this.props.children}
-
- ) : null} -
- ); - } -} - -SubPanel.propTypes = { - children: PropTypes.node, - iconClass: PropTypes.string, - show: PropTypes.bool, - ownline: PropTypes.bool, - question: PropTypes.bool, - label: PropTypes.string, -}; diff --git a/src/components/containers/TraceAccordion.js b/src/components/containers/TraceAccordion.js index ae9cddfae..1b024861c 100644 --- a/src/components/containers/TraceAccordion.js +++ b/src/components/containers/TraceAccordion.js @@ -7,38 +7,34 @@ import {connectTraceToPlot} from '../../lib'; const TraceFold = connectTraceToPlot(Fold); export default class TraceAccordion extends Component { - constructor(props, context) { + constructor(props) { super(props); this.addTrace = this.addTrace.bind(this); - this.renderPanel = this.renderPanel.bind(this); - } - - renderPanel(d, i) { - return ( - - {this.props.children} - - ); } addTrace() { - this.context.onUpdate && + if (this.context.onUpdate) { this.context.onUpdate({ type: EDITOR_ACTIONS.ADD_TRACE, }); + } } render() { const data = this.context.data || []; return (
- {this.props.canAdd && ( + {this.props.canAdd ? ( Add - )} - {data.map(this.renderPanel)} + ) : null} + {data.map((d, i) => ( + + {this.props.children} + + ))}
); } @@ -50,5 +46,6 @@ TraceAccordion.contextTypes = { }; TraceAccordion.propTypes = { + children: PropTypes.node, canAdd: PropTypes.bool, }; diff --git a/src/components/containers/TraceMarkerSection.js b/src/components/containers/TraceMarkerSection.js new file mode 100644 index 000000000..287ea7665 --- /dev/null +++ b/src/components/containers/TraceMarkerSection.js @@ -0,0 +1,41 @@ +import Section from './Section'; +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import localize from '../../lib/localize'; + +class TraceMarkerSection extends Component { + constructor(props, context) { + super(props, context); + this.setLocals(context); + } + + componentWillReceiveProps(nextProps, nextContext) { + this.setLocals(nextContext); + } + + setLocals(context) { + const _ = this.props.localize; + const traceType = context.fullContainer.type; + if (traceType === 'bar') { + this.name = _('Bars'); + } else { + this.name = _('Points'); + } + } + + render() { + return
{this.props.children}
; + } +} + +TraceMarkerSection.propTypes = { + children: PropTypes.node, + localize: PropTypes.func, + name: PropTypes.string, +}; + +TraceMarkerSection.contextTypes = { + fullContainer: PropTypes.object, +}; + +export default localize(TraceMarkerSection); diff --git a/src/components/containers/__tests__/Layout-test.js b/src/components/containers/__tests__/Layout-test.js index 3597717fc..a24cadf30 100644 --- a/src/components/containers/__tests__/Layout-test.js +++ b/src/components/containers/__tests__/Layout-test.js @@ -3,13 +3,13 @@ import {Fold, Panel, Section} from '..'; import NumericInput from '../../widgets/NumericInputStatefulWrapper'; import React from 'react'; import {EDITOR_ACTIONS} from '../../../constants'; -import {TestEditor, fixtures, plotly} from '../../../lib/test-utils'; +import {TestEditor, fixtures} from '../../../lib/test-utils'; import {connectLayoutToPlot} from '../../../lib'; import {mount} from 'enzyme'; const Layouts = [Panel, Fold, Section].map(connectLayoutToPlot); const Editor = props => ( - + ); Layouts.forEach(Layout => { diff --git a/src/components/containers/__tests__/Section-test.js b/src/components/containers/__tests__/Section-test.js index 702d9e9d9..3bb47a7e0 100644 --- a/src/components/containers/__tests__/Section-test.js +++ b/src/components/containers/__tests__/Section-test.js @@ -1,8 +1,8 @@ import React from 'react'; import Section from '../Section'; -import SubPanel from '../SubPanel'; +import MenuPanel from '../MenuPanel'; import {Flaglist, Info, Numeric} from '../../fields'; -import {TestEditor, fixtures, plotly} from '../../../lib/test-utils'; +import {TestEditor, fixtures} from '../../../lib/test-utils'; import {connectTraceToPlot} from '../../../lib'; import {mount} from 'enzyme'; @@ -12,11 +12,7 @@ describe('Section', () => { it('is visible if it contains any visible children', () => { // mode is visible with scatter. Hole is not visible. Section should show. const wrapper = mount( - + { it('is visible if it contains any non attr children', () => { const wrapper = mount( - +
INFO
@@ -69,11 +61,7 @@ describe('Section', () => { it('is not visible if it contains no visible children', () => { // pull and hole are not scatter attrs. Section should not show. const wrapper = mount( - + @@ -91,20 +79,16 @@ describe('Section', () => { expect(wrapper.find(Numeric).exists()).toBe(false); }); - it('will render first subPanel even with no visible attrs', () => { + it('will render first menuPanel even with no visible attrs', () => { const wrapper = mount( - +
- + INFO - - + + MISINFORMATION - +
).find('[name="test-section"]'); diff --git a/src/components/containers/index.js b/src/components/containers/index.js index af6ee56e2..7284a63eb 100644 --- a/src/components/containers/index.js +++ b/src/components/containers/index.js @@ -1,7 +1,8 @@ -import SubPanel from './SubPanel'; +import MenuPanel from './MenuPanel'; import Fold from './Fold'; import Panel from './Panel'; import Section from './Section'; import TraceAccordion from './TraceAccordion'; +import TraceMarkerSection from './TraceMarkerSection'; -export {SubPanel, Fold, Panel, Section, TraceAccordion}; +export {MenuPanel, Fold, Panel, Section, TraceAccordion, TraceMarkerSection}; diff --git a/src/components/fields/CanvasSize.js b/src/components/fields/CanvasSize.js new file mode 100644 index 000000000..23de502b1 --- /dev/null +++ b/src/components/fields/CanvasSize.js @@ -0,0 +1,25 @@ +import Numeric from './Numeric'; +import React, {Component} from 'react'; +import {connectToContainer} from '../../lib'; + +class CanvasSize extends Component { + static modifyPlotProps(props, context, plotProps) { + if (!plotProps.isVisible) { + return; + } + const {fullContainer} = plotProps; + if (fullContainer && fullContainer.autosize) { + plotProps.isVisible = false; + } + } + + render() { + return ; + } +} + +CanvasSize.propTypes = { + ...Numeric.propTypes, +}; + +export default connectToContainer(CanvasSize); diff --git a/src/components/fields/DataSelector.js b/src/components/fields/DataSelector.js index 1f31b244b..7189b56bb 100644 --- a/src/components/fields/DataSelector.js +++ b/src/components/fields/DataSelector.js @@ -45,7 +45,9 @@ class DataSelector extends Component { updatePlot(value) { const attr = this.dataSrcExists ? this.srcAttr : this.props.attr; - this.props.updateContainer && this.props.updateContainer({[attr]: value}); + if (this.props.updateContainer) { + this.props.updateContainer({[attr]: value}); + } } render() { diff --git a/src/components/fields/Field.js b/src/components/fields/Field.js index 617b45b3a..cd0c795bc 100644 --- a/src/components/fields/Field.js +++ b/src/components/fields/Field.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React, {Component} from 'react'; -import SubPanel from '../containers/SubPanel'; +import MenuPanel from '../containers/MenuPanel'; import classnames from 'classnames'; import {bem, localize} from '../../lib'; import {multiValueText} from '../../lib/constants'; @@ -48,11 +48,11 @@ class Field extends Component {
{children} {multiValued ? ( - +
{_(multiValueText.title)}
{_(multiValueText.text)}
{_(multiValueText.subText)}
-
+ ) : null}
{postfix ? ( diff --git a/src/components/fields/Numeric.js b/src/components/fields/Numeric.js index 9632515d1..7a6a20496 100644 --- a/src/components/fields/Numeric.js +++ b/src/components/fields/Numeric.js @@ -28,7 +28,7 @@ Numeric.propTypes = { fullValue: PropTypes.func, min: PropTypes.number, max: PropTypes.number, - showArrows: PropTypes.number, + showArrows: PropTypes.bool, step: PropTypes.number, updatePlot: PropTypes.func, ...Field.propTypes, diff --git a/src/components/fields/SymbolSelector.js b/src/components/fields/SymbolSelector.js new file mode 100644 index 000000000..2a58b1bb7 --- /dev/null +++ b/src/components/fields/SymbolSelector.js @@ -0,0 +1,58 @@ +import Field from './Field'; +import PropTypes from 'prop-types'; +import React, {Component} from 'react'; +import SymbolSelectorWidget from '../widgets/SymbolSelector'; +import nestedProperty from 'plotly.js/src/lib/nested_property'; +import {SYMBOLS} from '../../lib/constants'; +import {connectToContainer} from '../../lib'; + +class SymbolSelector extends Component { + render() { + const {fullContainer, fullValue, updatePlot} = this.props; + + const markerColor = nestedProperty(fullContainer, 'marker.color').get(); + const borderWidth = nestedProperty( + fullContainer, + 'marker.line.width' + ).get(); + + let borderColor = markerColor; + if (borderWidth) { + borderColor = nestedProperty(fullContainer, 'marker.line.color').get(); + } + + let symbolOptions; + if (this.props.is3D) { + symbolOptions = SYMBOLS.filter(option => { + return option.threeD; + }); + } else { + symbolOptions = [...SYMBOLS]; + } + + return ( + + + + ); + } +} + +SymbolSelector.propTypes = { + defaultValue: PropTypes.number, + fullValue: PropTypes.func, + updatePlot: PropTypes.func, + ...Field.propTypes, +}; + +SymbolSelector.defaultProps = { + showArrows: true, +}; + +export default connectToContainer(SymbolSelector); diff --git a/src/components/fields/TraceSelector.js b/src/components/fields/TraceSelector.js index 2032d6901..95dec45b7 100644 --- a/src/components/fields/TraceSelector.js +++ b/src/components/fields/TraceSelector.js @@ -4,14 +4,68 @@ import React, {Component} from 'react'; import nestedProperty from 'plotly.js/src/lib/nested_property'; import {connectToContainer} from '../../lib'; +function computeTraceOptionsFromSchema(schema) { + const capitalize = s => s.charAt(0).toUpperCase() + s.substring(1); + + // Filter out Polar "area" type as it is fairly broken and we want to present + // scatter with fill as an "area" chart type for convenience. + const traceTypes = Object.keys(schema.traces).filter(t => t !== 'area'); + + const labels = traceTypes.map(capitalize); + const traceOptions = traceTypes.map((t, i) => ({ + label: labels[i], + value: t, + })); + + const i = traceOptions.findIndex(opt => opt.value === 'scatter'); + traceOptions.splice( + i + 1, + 0, + {label: 'Line', value: 'line'}, + {label: 'Area', value: 'area'} + ); + + return traceOptions; +} + class TraceSelector extends Component { constructor(props, context) { super(props, context); this.updatePlot = this.updatePlot.bind(this); this.fullValue = this.fullValue.bind(this); - const scatterAttrs = this.context.plotSchema.traces.scatter.attributes; - this.fillTypes = scatterAttrs.fill.values.filter(v => v !== 'none'); + let fillMeta; + if (props.getValObject) { + fillMeta = props.getValObject('fill'); + } + if (fillMeta) { + this.fillTypes = fillMeta.values.filter(v => v !== 'none'); + } else { + this.fillTypes = [ + 'tozeroy', + 'tozerox', + 'tonexty', + 'tonextx', + 'toself', + 'tonext', + ]; + } + + this.setLocals(props, context); + } + + setLocals(props, context) { + if (props.traceOptions) { + this.traceOptions = props.traceOptions; + } else if (context.plotSchema) { + this.traceOptions = computeTraceOptionsFromSchema(context.plotSchema); + } else { + this.traceOptions = [{label: 'Scatter', value: 'scatter'}]; + } + } + + componentWillReceiveProps(nextProps, nextContext) { + this.setLocals(nextProps, nextContext); } updatePlot(value) { @@ -26,18 +80,19 @@ class TraceSelector extends Component { update = {type: value}; } - this.props.updateContainer && this.props.updateContainer(update); + if (this.props.updateContainer) { + this.props.updateContainer(update); + } } fullValue() { - const type = this.props.fullValue(); + const {container, fullValue} = this.props; + const type = fullValue(); - // we use gd.data instead of fullData so that we can show the trace - // even if the trace is not visible due to missing data. - // If we used fullData mode or fill will be undefined as the fullTrace - // isn't computed when not visible. - const mode = nestedProperty(this.props.trace, 'mode').get(); - const fill = nestedProperty(this.props.trace, 'fill').get(); + // If we used fullData mode or fill it may be undefined if the fullTrace + // is not visible and therefore does not have these values computed. + const mode = nestedProperty(container, 'mode').get(); + const fill = nestedProperty(container, 'fill').get(); if (type === 'scatter' && this.fillTypes.includes(fill)) { return 'area'; @@ -54,6 +109,7 @@ class TraceSelector extends Component { const props = Object.assign({}, this.props, { fullValue: this.fullValue, updatePlot: this.updatePlot, + options: this.traceOptions, }); return ; @@ -64,4 +120,11 @@ TraceSelector.contextTypes = { plotSchema: PropTypes.object, }; +TraceSelector.propTypes = { + getValObject: PropTypes.func, + container: PropTypes.object.isRequired, + fullValue: PropTypes.func.isRequired, + updateContainer: PropTypes.func, +}; + export default connectToContainer(TraceSelector); diff --git a/src/components/fields/index.js b/src/components/fields/index.js index 3a5dcfeff..2d3d9e199 100644 --- a/src/components/fields/index.js +++ b/src/components/fields/index.js @@ -1,5 +1,6 @@ import AxesRange from './AxesRange'; import AxesSelector from './AxesSelector'; +import CanvasSize from './CanvasSize'; import ColorPicker from './Color'; import Dropdown from './Dropdown'; import Flaglist from './Flaglist'; @@ -7,11 +8,13 @@ import Info from './Info'; import Radio from './Radio'; import DataSelector from './DataSelector'; import Numeric from './Numeric'; +import SymbolSelector from './SymbolSelector'; import TraceSelector from './TraceSelector'; export { AxesRange, AxesSelector, + CanvasSize, ColorPicker, Dropdown, Flaglist, @@ -19,5 +22,6 @@ export { Radio, DataSelector, Numeric, + SymbolSelector, TraceSelector, }; diff --git a/src/components/index.js b/src/components/index.js index d4d22f525..42ac7373e 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,6 +1,7 @@ import { AxesRange, AxesSelector, + CanvasSize, ColorPicker, Dropdown, Flaglist, @@ -8,16 +9,25 @@ import { Radio, DataSelector, Numeric, + SymbolSelector, TraceSelector, } from './fields'; -import {SubPanel, Fold, Panel, Section, TraceAccordion} from './containers'; +import { + MenuPanel, + Fold, + Panel, + Section, + TraceAccordion, + TraceMarkerSection, +} from './containers'; import PanelMenuWrapper from './PanelMenuWrapper'; export { AxesSelector, AxesRange, - SubPanel, + MenuPanel, + CanvasSize, ColorPicker, DataSelector, Dropdown, @@ -29,6 +39,8 @@ export { PanelMenuWrapper, Radio, Section, + SymbolSelector, TraceAccordion, + TraceMarkerSection, TraceSelector, }; diff --git a/src/components/widgets/EditableText.js b/src/components/widgets/EditableText.js index 7dd41616c..43f5ef9a8 100644 --- a/src/components/widgets/EditableText.js +++ b/src/components/widgets/EditableText.js @@ -89,8 +89,8 @@ EditableText.propTypes = { // Called on input keyDown events onKeyDown: PropTypes.func, - // Input value property - text: PropTypes.string, + // Input value property ... + text: PropTypes.any, // Input properties placeholder: PropTypes.string, diff --git a/src/components/widgets/SymbolSelector.js b/src/components/widgets/SymbolSelector.js new file mode 100644 index 000000000..f96fcdbd5 --- /dev/null +++ b/src/components/widgets/SymbolSelector.js @@ -0,0 +1,143 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import tinyColor from 'tinycolor2'; +import ModalBox from '../containers/ModalBox'; + +const tooLightFactor = 0.8; + +function tooLight(color) { + const hslColor = tinyColor(color).toHsl(); + return hslColor.l > tooLightFactor; +} + +export default class SymbolSelector extends Component { + constructor(props) { + super(props); + this.state = { + isOpen: false, + }; + this.togglePanel = this.togglePanel.bind(this); + } + + shouldComponentUpdate(nextProps, nextState) { + const {markerColor, borderColor} = this.props; + const { + markerColor: nextMarkerColor, + borderColor: nextBorderColor, + } = nextProps; + + return ( + this.props.value !== nextProps.value || + this.state.isOpen !== nextState.isOpen || + markerColor !== nextMarkerColor || + borderColor !== nextBorderColor + ); + } + + togglePanel() { + this.setState({isOpen: !this.state.isOpen}); + } + + renderActiveOption() { + const {markerColor, borderColor, symbolOptions, value} = this.props; + const currentSymbol = symbolOptions.find(symbol => symbol.value === value); + if (!currentSymbol) { + return ( + + {'-'} + + ); + } + + const symbolStyle = { + stroke: currentSymbol.fill === 'none' ? markerColor : borderColor, + strokeOpacity: '1', + strokeWidth: '2px', + fill: currentSymbol.fill === 'none' ? 'none' : markerColor, + }; + + return ( + + + + + + + + ); + } + + renderOptions() { + const {markerColor, borderColor, symbolOptions} = this.props; + return symbolOptions.map(option => { + const {fill, value, label} = option; + + const symbolStyle = { + stroke: fill === 'none' ? markerColor : borderColor, + strokeOpacity: '1', + strokeWidth: '2px', + fill: fill === 'none' ? 'none' : markerColor, + }; + return ( +
+ + + + + +
+ ); + }); + } + + render() { + const {isOpen} = this.state; + const {markerColor} = this.props; + + // TODO link these colors into theme + const backgroundColor = tooLight(markerColor) ? '#bec8d9' : 'white'; + + return ( +
+
+ + {this.renderActiveOption()} + + + + +
+ {isOpen ? ( + + {this.renderOptions()} + + ) : null} +
+ ); + } +} + +SymbolSelector.propTypes = { + markerColor: PropTypes.string, + borderColor: PropTypes.string, + value: PropTypes.string, + onChange: PropTypes.func, + symbolOptions: PropTypes.array, +}; diff --git a/src/index.js b/src/index.js index 4bf8453ba..15c16f022 100644 --- a/src/index.js +++ b/src/index.js @@ -12,7 +12,7 @@ import {EDITOR_ACTIONS} from './constants'; import { AxesRange, AxesSelector, - SubPanel, + CanvasSize, ColorPicker, DataSelector, Dropdown, @@ -25,14 +25,18 @@ import { PanelMenuWrapper, Radio, Section, + MenuPanel, + SymbolSelector, TraceAccordion, + TraceMarkerSection, TraceSelector, } from './components'; export { AxesRange, AxesSelector, - SubPanel, + MenuPanel, + CanvasSize, ColorPicker, DataSelector, Dropdown, @@ -47,7 +51,9 @@ export { PanelMenuWrapper, Radio, Section, + SymbolSelector, TraceAccordion, + TraceMarkerSection, TraceSelector, connectAxesToLayout, connectLayoutToPlot, diff --git a/src/lib/connectAxesToLayout.js b/src/lib/connectAxesToLayout.js index 27e38ba9c..2af048572 100644 --- a/src/lib/connectAxesToLayout.js +++ b/src/lib/connectAxesToLayout.js @@ -34,10 +34,12 @@ function deepCopyPublic(value) { /* * Test that we can connectLayoutToPlot(connectAxesToLayout(Panel)) */ -function setMultiValuedContainer(intoObj, fromObj, key, searchArrays) { +function setMultiValuedContainer(intoObj, fromObj, key, config = {}) { var intoVal = intoObj[key], fromVal = fromObj[key]; + var searchArrays = config.searchArrays; + // don't merge private attrs if ( (typeof key === 'string' && key.charAt(0) === '_') || @@ -126,18 +128,22 @@ export default function connectAxesToLayout(WrappedComponent) { setLocals(nextProps, nextState, nextContext) { const {plotly, graphDiv, container, fullContainer} = nextContext; const {axesTarget} = nextState; - this.axes = plotly.Axes.list(graphDiv); + if (plotly) { + this.axes = plotly.Axes.list(graphDiv); + } else { + this.axes = []; + } this.axesOptions = computeAxesOptions(fullContainer, this.axes); if (axesTarget === 'allaxes') { const multiValuedContainer = deepCopyPublic(this.axes[0]); - this.axes - .slice(1) - .forEach(ax => - Object.keys(ax).forEach(key => - setMultiValuedContainer(multiValuedContainer, ax, key) - ) - ); + this.axes.slice(1).forEach(ax => + Object.keys(ax).forEach(key => + setMultiValuedContainer(multiValuedContainer, ax, key, { + searchArrays: true, + }) + ) + ); this.fullContainer = multiValuedContainer; this.defaultContainer = this.axes[0]; // what should this be set to? Probably doesn't matter. @@ -214,8 +220,8 @@ export default function connectAxesToLayout(WrappedComponent) { container: PropTypes.object.isRequired, fullContainer: PropTypes.object.isRequired, graphDiv: PropTypes.object.isRequired, - plotly: PropTypes.object.isRequired, - updateContainer: PropTypes.func.isRequired, + plotly: PropTypes.object, + updateContainer: PropTypes.func, }; AxesConnectedComponent.childContextTypes = { diff --git a/src/lib/connectLayoutToPlot.js b/src/lib/connectLayoutToPlot.js index 3bbe3ea41..00e474c52 100644 --- a/src/lib/connectLayoutToPlot.js +++ b/src/lib/connectLayoutToPlot.js @@ -14,12 +14,17 @@ export default function connectLayoutToPlot(WrappedComponent) { getChildContext() { const {layout, fullLayout, plotly} = this.context; - return { - getValObject: attr => + + let getValObject; + if (plotly) { + getValObject = attr => plotly.PlotSchema.getLayoutValObject( fullLayout, nestedProperty({}, attr).parts - ), + ); + } + return { + getValObject, updateContainer: this.updateContainer, container: layout, fullContainer: fullLayout, @@ -48,7 +53,7 @@ export default function connectLayoutToPlot(WrappedComponent) { LayoutConnectedComponent.contextTypes = { layout: PropTypes.object, fullLayout: PropTypes.object, - plotly: PropTypes.object.isRequired, + plotly: PropTypes.object, onUpdate: PropTypes.func, }; diff --git a/src/lib/connectTraceToPlot.js b/src/lib/connectTraceToPlot.js index d581ded89..4d2c8120b 100644 --- a/src/lib/connectTraceToPlot.js +++ b/src/lib/connectTraceToPlot.js @@ -20,12 +20,18 @@ export default function connectTraceToPlot(WrappedComponent) { const trace = data[traceIndex] || {}; const fullTraceIndex = findFullTraceIndex(fullData, traceIndex); const fullTrace = fullData[fullTraceIndex] || {}; - return { - getValObject: attr => + + let getValObject; + if (plotly) { + getValObject = attr => plotly.PlotSchema.getTraceValObject( fullTrace, nestedProperty({}, attr).parts - ), + ); + } + + return { + getValObject, updateContainer: this.updateTrace, deleteContainer: this.deleteTrace, container: trace, @@ -70,7 +76,7 @@ export default function connectTraceToPlot(WrappedComponent) { TraceConnectedComponent.contextTypes = { fullData: PropTypes.array, data: PropTypes.array, - plotly: PropTypes.object.isRequired, + plotly: PropTypes.object, onUpdate: PropTypes.func, }; diff --git a/src/lib/constants.js b/src/lib/constants.js index 807b86b90..10093cb01 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -23,442 +23,399 @@ export const multiValueText = { 'because the X and Y tabs contain different settings.', }; -/* -export const CLEAR_WORKSPACE = "WORKSPACE_CLEAR_WORKSPACE"; - -export const EDIT_MODE = { - ANALYSIS: "WORKSPACE_EDIT_MODE_ANALYSIS", - GRAPH: "WORKSPACE_EDIT_MODE_GRAPH", - STYLE: "WORKSPACE_EDIT_MODE_STYLE", - SHARE: "WORKSPACE_EDIT_MODE_SHARE", - EXPORT: "WORKSPACE_EDIT_MODE_EXPORT", - JSON: "WORKSPACE_EDIT_MODE_JSON", -}; - -export const STYLE_MODE = { - TRACES: "WORKSPACE_STYLE_MODE_TRACES", - LAYOUT: "WORKSPACE_STYLE_MODE_LAYOUT", - NOTES: "WORKSPACE_STYLE_MODE_NOTES", - AXES: "WORKSPACE_STYLE_MODE_AXES", - LEGEND: "WORKSPACE_STYLE_MODE_LEGEND", - COLOR_BARS: "WORKSPACE_STYLE_MODE_COLOR_BARS", - SHAPES: "WORKSPACE_STYLE_MODE_SHAPES", - MAPBOX_LAYERS: "WORKSPACE_STYLE_MODE_MAPBOX_LAYERS", - IMAGES: "WORKSPACE_STYLE_MODE_IMAGES", - MOBILE: "WORKSPACE_STYLE_MODE_MOBILE", -}; - -export const GRAPH_MODE = { - CREATE: "WORKSPACE_GRAPH_MODE_CREATE", - FILTER: "WORKSPACE_GRAPH_MODE_FILTER", - GROUPBY: "WORKSPACE_GRAPH_MODE_GROUPBY", -}; - -export const ADD_PLOT_ID = "WORKSPACE_ADD_PLOT_ID"; -export const ADD_PLOT_SOURCE = "WORKSPACE_ADD_PLOT_SOURCE"; -export const ADD_PLOT_SOURCE_SHARE_KEY = "WORKSPACE_ADD_PLOT_SOURCE_SHARE_KEY"; -export const UPDATE_PLOT_DIRTY = "WORKSPACE_UPDATE_PLOT_DIRTY"; - -export const ADD_SHARE_FID = "WORKSPACE_ADD_SHARE_FID"; - -// Spec used to create the EditSidebar Buttons -export const EDIT_MODE_MENU_ITEMS = [ +export const SYMBOLS = [ { - mode: EDIT_MODE.GRAPH, - text: "Graph", + value: 'circle', + alias: 0, + label: 'M5,0A5,5 0 1,1 0,-5A5,5 0 0,1 5,0Z', + threeD: true, + gl: true, }, { - mode: EDIT_MODE.STYLE, - text: "Style", + value: 'circle-open', + alias: 0, + label: 'M5,0A5,5 0 1,1 0,-5A5,5 0 0,1 5,0Z', + fill: 'none', + threeD: true, + gl: true, }, { - mode: EDIT_MODE.ANALYSIS, - text: "Analysis", + value: 'circle-open-dot', + alias: 0, + label: 'M5,0A5,5 0 1,1 0,-5A5,5 0 0,1 5,0ZM0,0.5L0.5,0L0,-0.5L-0.5,0Z', + fill: 'none', }, + + {value: 'square', alias: 1, label: 'M5,5H-5V-5H5Z', threeD: true, gl: true}, { - mode: EDIT_MODE.JSON, - text: "JSON", + value: 'square-open', + alias: 1, + label: 'M5,5H-5V-5H5Z', + fill: 'none', + threeD: true, + gl: true, }, { - mode: EDIT_MODE.EXPORT, - text: "Export", + value: 'square-open-dot', + alias: 1, + label: 'M5,5H-5V-5H5ZM0,0.5L0.5,0L0,-0.5L-0.5,0Z', + fill: 'none', }, -]; -export const STYLE_MODE_MENU_ITEMS = [ { - mode: STYLE_MODE.TRACES, - text: "Traces", + value: 'diamond', + alias: 2, + label: 'M6.5,0L0,6.5L-6.5,0L0,-6.5Z', + threeD: true, + gl: true, }, { - mode: STYLE_MODE.LAYOUT, - text: "Layout", + value: 'diamond-open', + alias: 2, + label: 'M6.5,0L0,6.5L-6.5,0L0,-6.5Z', + fill: 'none', + threeD: true, + gl: true, }, { - mode: STYLE_MODE.NOTES, - text: "Notes", + value: 'diamond-open-dot', + alias: 2, + label: 'M6.5,0L0,6.5L-6.5,0L0,-6.5ZM0,0.5L0.5,0L0,-0.5L-0.5,0Z', + fill: 'none', }, + { - mode: STYLE_MODE.AXES, - text: "Axes", + value: 'cross', + alias: 3, + label: 'M6,2H2V6H-2V2H-6V-2H-2V-6H2V-2H6Z', + threeD: true, + gl: true, }, { - mode: STYLE_MODE.LEGEND, - text: "Legend", + value: 'cross-open', + alias: 3, + label: 'M6,2H2V6H-2V2H-6V-2H-2V-6H2V-2H6Z', + fill: 'none', + gl: true, }, + { - mode: STYLE_MODE.COLOR_BARS, - text: "Color Bars", + value: 'x', + alias: 4, + label: + 'M0,2.83l2.83,2.83l2.83,-2.83l-2.83,-2.83l2.83,-2.83l-2.83,-2.83l-2.83,2.83l-2.83,-2.83l-2.83,2.83l2.83,2.83l-2.83,2.83l2.83,2.83Z', + threeD: true, + gl: true, }, { - mode: STYLE_MODE.SHAPES, - text: "Shapes", + value: 'x-open', + alias: 4, + label: + 'M0,2.83l2.83,2.83l2.83,-2.83l-2.83,-2.83l2.83,-2.83l-2.83,-2.83l-2.83,2.83l-2.83,-2.83l-2.83,2.83l2.83,2.83l-2.83,2.83l2.83,2.83Z', + fill: 'none', + gl: true, }, + + {value: 'triangle-up', alias: 5, label: 'M-5.77,2.5H5.77L0,-5Z', gl: true}, { - mode: STYLE_MODE.MAPBOX_LAYERS, - text: "GeoJSON", + value: 'triangle-up-open', + alias: 5, + label: 'M-5.77,2.5H5.77L0,-5Z', + fill: 'none', + gl: true, }, + + {value: 'triangle-down', alias: 6, label: 'M-5.77,-2.5H5.77L0,5Z', gl: true}, { - mode: STYLE_MODE.IMAGES, - text: "Images", + value: 'triangle-down-open', + alias: 6, + label: 'M-5.77,-2.5H5.77L0,5Z', + fill: 'none', + gl: true, }, + + {value: 'triangle-left', alias: 7, label: 'M2.5,-5.77V5.77L-5,0Z', gl: true}, { - mode: STYLE_MODE.MOBILE, - text: "Mobile", + value: 'triangle-left-open', + alias: 7, + label: 'M2.5,-5.77V5.77L-5,0Z', + fill: 'none', + gl: true, }, -]; -export const GRAPH_MODE_MENU_ITEMS = [ + {value: 'triangle-right', alias: 8, label: 'M-2.5,-5.77V5.77L5,0Z', gl: true}, { - mode: GRAPH_MODE.CREATE, - text: "create", + value: 'triangle-right-open', + alias: 8, + label: 'M-2.5,-5.77V5.77L5,0Z', + fill: 'none', + gl: true, }, + + {value: 'triangle-ne', alias: 9, label: 'M-6,-3H3V6Z', gl: true}, { - mode: GRAPH_MODE.FILTER, - text: "filter", + value: 'triangle-ne-open', + alias: 9, + label: 'M-6,-3H3V6Z', + fill: 'none', + gl: true, }, + + {value: 'triangle-se', alias: 10, label: 'M3,-6V3H-6Z', gl: true}, { - mode: GRAPH_MODE.GROUPBY, - text: "group", + value: 'triangle-se-open', + alias: 10, + label: 'M3,-6V3H-6Z', + fill: 'none', + gl: true, }, -]; - -// temp / saved state of fids and column uids -export const UPDATE_COLUMN_ID_MAP = "WORKSPACE_UPDATE_COLUMN_ID_MAP"; -export const UPDATE_FID_MAP = "WORKSPACE_UPDATE_FID_MAP"; -export const UPDATE_LAST_SAVED = "WORKSPACE_UPDATE_LAST_SAVED"; -export const MARK_FID_AS_UNSAVED = "WORKSPACE_MARK_FID_AS_UNSAVED"; -export const REMOVE_COLUMN_IDS_FROM_COLUMN_ID_MAP = - "WORKSPACE_REMOVE_COLUMN_IDS_FROM_COLUMN_ID_MAP"; -// panels -export const EDIT_MODES = Object.keys(EDIT_MODE).map(k => EDIT_MODE[k]); -export const STYLE_MODES = Object.keys(STYLE_MODE).map(k => STYLE_MODE[k]); -export const GRAPH_MODES = Object.keys(GRAPH_MODE).map(k => GRAPH_MODE[k]); -export const SELECT_EDIT_MODE = "WORKSPACE_SELECT_EDIT_MODE"; -export const SELECT_STYLE_MODE = "WORKSPACE_SELECT_STYLE_MODE"; -export const SELECT_GRAPH_MODE = "WORKSPACE_SELECT_GRAPH_MODE"; - -// figure -export const ADD_BREAKPOINT = "WORKSPACE_ADD_BREAKPOINT"; -export const DELETE_BREAKPOINT = "WORKSPACE_DELETE_BREAKPOINT"; -export const PLOTLY_RELAYOUT = "WORKSPACE_RELAYOUT"; -export const PLOTLY_RESTYLE = "WORKSPACE_RESTYLE"; -export const PLOTLY_NEW_PLOT = "WORKSPACE_NEW_PLOT"; -export const PLOTLY_ADD_FRAMES = "WORKSPACE_ADD_FRAMES"; -export const PLOTLY_DELETE_FRAMES = "WORKSPACE_DELETE_FRAMES"; -export const SELECT_FRAME = "WORKSPACE_SELECT_FRAME"; -export const SET_BASE_LAYOUT = "WORKSPACE_SET_BASE_LAYOUT"; -export const SET_BREAKPOINT = "WORKSPACE_SET_BREAKPOINT"; - -// annotations -export const INLINE_STYLE_LINK = "LINK"; -export const INLINE_STYLE_SUPER = "SUPERSCRIPT"; -export const INLINE_STYLE_SUB = "SUBSCRIPT"; - -// columns and tables -export const MERGE_COLUMNS_AND_TABLES = "WORKSPACE_MERGE_COLUMNS_AND_TABLES"; -export const UPDATE_TABLE = "UPDATE_TABLE"; -export const ADD_EMPTY_TABLE = "WORKSPACE_ADD_EMTPY_TABLE"; -export const SELECT_TABLE = "WORKSPACE_SELECT_TABLE"; -export const OVERWRITE_SOURCE = "WORKSPACE_OVERWRITE_SOURCE"; -export const REMOVE_TABLE = "WORKSPACE_REMOVE_TABLE"; -export const REMOVE_COLUMNS_FROM_TABLE = "WORKSPACE_REMOVE_COLUMNS_FROM_TABLE"; - -// encoding -export const ASSIGN_COLUMN = "WORKSPACE_ASSIGN_COLUMN"; -export const SWITCH_CHART_TYPE = "WORKSPACE_SWITCH_CHART_TYPE"; -export const NEW_ENCODING_LAYER = "WORKSPACE_NEW_ENCODING_LAYER"; -export const REMOVE_ENCODING_LAYER = "WORKSPACE_REMOVE_ENCODING_LAYER"; -export const SET_ENCODING = "WORKSPACE_SET_ENCODING"; -export const DEFAULT_ENCODING_TYPE = "scatter"; - -// analyses -export const UPDATE_ANALYSIS = "WORKSPACE_UPDATE_ANALYSIS"; -export const ADD_ANALYSIS = "WORKSPACE_ADD_ANALYSIS"; -export const REMOVE_ANALYSIS = "WORKSPACE_REMOVE_ANALYSIS"; -export const UPDATE_ANALYSIS_META = "WORKSPACE_UPDATE_ANALYSIS_META"; - -// HOT -export const MAX_HOT_ROWS = 5000; -export const CONTEXT_MENU_SOURCE = "WORKSPACE_CONTEXT_MENU_SOURCE"; -export const SORT_SOURCE = "WORKSPACE_SORT_SOURCE"; -export const INSERT_HEADERS_ABOVE_SOURCE = - "WORKSPACE_INSERT_HEADERS_ABOVE_SOURCE"; -export const CONTEXT_MENU_KEYS = { - CLEAR_HEADERS: "WORKSPACE_CONTEXT_MENU_KEYS_CLEAR_HEADERS", - COL_LEFT: "WORKSPACE_CONTEXT_MENU_KEYS_COL_LEFT", - COL_RIGHT: "WORKSPACE_CONTEXT_MENU_KEYS_COL_RIGHT", - INSERT_HEADERS_ABOVE: "WORKSPACE_CONTEXT_MENU_KEYS_INSERT_HEADERS_ABOVE", - REMOVE_COL: "WORKSPACE_CONTEXT_MENU_KEYS_REMOVE_COL", - REMOVE_ROW: "WORKSPACE_CONTEXT_MENU_KEYS_REMOVE_ROW", - RENAME_HEADER: "WORKSPACE_CONTEXT_MENU_KEYS_RENAME_HEADER", - RESET_SORT: "WORKSPACE_CONTEXT_MENU_KEYS_RESET_SORT", - ROW_ABOVE: "WORKSPACE_CONTEXT_MENU_KEYS_ROW_ABOVE", - ROW_BELOW: "WORKSPACE_CONTEXT_MENU_KEYS_ROW_BELOW", - SET_HEADERS: "WORKSPACE_CONTEXT_MENU_KEYS_SET_HEADERS", - SORT_ASCENDING: "WORKSPACE_CONTEXT_MENU_KEYS_SORT_ASCENDING", - SORT_DESCENDING: "WORKSPACE_CONTEXT_MENU_KEYS_SORT_DESCENDING", - TRANSPOSE_TABLE: "WORKSPACE_CONTEXT_MENU_KEYS_TRANSPOSE_TABLE", -}; - -// style panels -export const CONTROL_TYPES = { - FONT: "FONT", - COLOR: "COLOR", - ANCHOR_SELECTOR: "ANCHOR_SELECTOR", - DASH: "DASH", - SYMBOL: "SYMBOL", - RADIO: "RADIO", - TEXTAREA: "TEXTAREA", - ANNOTATION_EDITOR: "ANNOTATION_EDITOR", - MAPBOX_ACCESS_TOKEN: "MAPBOX_ACCESS_TOKEN", - NUMERIC_INPUT: "NUMERIC_INPUT", - FLAGLIST_CHECKBOX: "FLAGLIST_CHECKBOX", - COLUMN_INPUT: "COLUMN_INPUT", - COLOR_PALETTE: "COLOR_PALETTE", - DATETIME_INPUT: "DATETIME_INPUT", - DATETIME_DURATION: "DATETIME_DURATION", - DROPDOWN_SELECTOR: "DROPDOWN_SELECTOR", - DROPDOWN_WITH_TEXT_INPUT: "DROPDOWN_WITH_TEXT_INPUT", - RANGE: "RANGE", - SLIDER: "SLIDER", - INPUT_SLIDER: "INPUT_SLIDER", - BUTTON: "BUTTON", - RANGE_SELECTOR_BUTTONS: "RANGE_SELECTOR_BUTTONS", - TEXT_INPUT: "TEXT_INPUT", - UPLOAD_SHAPE_FILE: "UPLOAD_SHAPE_FILE", - UPLOAD_IMAGE_FILE: "UPLOAD_IMAGE_FILE", - REF_CONTROL: "REF_CONTROL", - ANCHOR: "ANCHOR", - MAPBOX_STYLE_URL: "MAPBOX_STYLE_URL", - ORIENTATION: "ORIENTATION", - NOTE: "NOTE", - ARROW: "ARROW", -}; - -// encoding panel -export const ENCODING_ATTRIBUTE_TYPES = { - PLOTLYJS: "PLOTLYJS", - ENCODING: "ENCODING", -}; - -// import modal -export const IMPORT_MODES = { - EXAMPLES: "EXAMPLES", - SQL: "SQL", - URL: "URL", - UPLOAD: "UPLOAD", -}; - -export const ORG_IMPORT_MODES = { - DATASET: "DATASET", - NOTEBOOK: "NOTEBOOK", - PRESENTATION: "PRESENTATION", -}; - -export const IMPORT_EXAMPLE_URL = - "https://raw.githubusercontent.com/plotly/datasets/master/iris.csv"; - -export const CHART_TYPE_ICON = { - animation: "icon-animation", - area: "icon-plot-area", - bar: "icon-plot-bar", - box: "icon-plot-box", - candlestick: "icon-candlestick", - cartesianArea: "icon-plot-area", - choropleth: "icon-choropleth", - contour: "icon-contour", - errorbars: "icon-error-bars", - heatmap: "icon-plot-heatmap", - histogram2d: "icon-plot-2d-hist", - histogram2dcontour: "icon-plot-2d-hist", - histogram: "icon-plot-hist", - line: "icon-plot-line", - mesh3d: "icon-mesh3d", - ohlc: "icon-ohlc", - pie: "icon-pie-chart", - scatter3d: "icon-plot-3d-scatter", - line3d: "icon-plot-3d-line", - scatter: "icon-plot-scatter", - scattergeo: "icon-scatter-chart", - scattermapbox: "icon-scatter-chart", - scatterternary: "icon-ternary-scatter", - surface: "icon-plot-3d-surface", - timeseries: "icon-time-series", -}; + {value: 'triangle-sw', alias: 11, label: 'M6,3H-3V-6Z', gl: true}, + { + value: 'triangle-sw-open', + alias: 11, + label: 'M6,3H-3V-6Z', + fill: 'none', + gl: true, + }, -export const ALL_AXES = [ - { - axisTypeIdentifier: "AxesSpec", - typeQuery: "cartesian", - identifier: "xaxis", - defaultAxis: "xaxis", - options: [ - { value: "allaxes", label: "All", title: "All Axes" }, - { value: "xaxis", label: "X", title: "X Axes", singular: "X axis" }, - { value: "yaxis", label: "Y", title: "Y Axes", singular: "Y axis" }, - ], - }, - { - axisTypeIdentifier: "AxesSpec", - typeQuery: "gl2d", - identifier: "xaxis", - defaultAxis: "xaxis", - options: [ - { value: "allaxes", label: "All", title: "All Axes" }, - { value: "xaxis", label: "X", title: "X Axes", singular: "X axis" }, - { value: "yaxis", label: "Y", title: "Y Axes", singular: "Y axis" }, - ], - }, - { - axisTypeIdentifier: "GeoSpec", - typeQuery: "geo", - identifier: "geo", - defaultAxis: "lonaxis", - options: [ - { value: "lataxis", label: "Latitude", title: "Latitude" }, - { value: "lonaxis", label: "Longitude", title: "Longitude" }, - ], - }, - { - axisTypeIdentifier: "SceneSpec", - typeQuery: "gl3d", - identifier: "scene", - defaultAxis: "xaxis", - options: [ - { value: "allaxes", label: "All", title: "All Axes" }, - { value: "xaxis", label: "X", title: "X Axes", singular: "X axis" }, - { value: "yaxis", label: "Y", title: "Y Axes", singular: "Y axis" }, - { value: "zaxis", label: "Z", title: "Z Axes", singular: "Z axis" }, - ], - }, - { - axisTypeIdentifier: "TernarySpec", - typeQuery: "ternary", - identifier: "ternary", - defaultAxis: "aaxis", - options: [ - { value: "aaxis", label: "A", title: "A Axes", singular: "A Axis" }, - { value: "baxis", label: "B", title: "B Axes", singular: "B Axis" }, - { value: "caxis", label: "C", title: "C Axes", singular: "C Axis" }, - ], - }, - { - typeQuery: "pie", - options: "NO_AXES", + {value: 'triangle-nw', alias: 12, label: 'M-3,6V-3H6Z', gl: true}, + { + value: 'triangle-nw-open', + alias: 12, + label: 'M-3,6V-3H6Z', + fill: 'none', + gl: true, }, -]; -// Layout specification for CategorizedSelectTrace -export const CHART_CATEGORY = { - BUSINESS: "BUSINESS", - SCIENCE: "SCIENCE", - CHARTS_3D: "CHARTS_3D", - FINANCIAL: "FINANCIAL", - STATISTICS: "STATISTICS", - MAPS: "MAPS", -}; + { + value: 'pentagon', + alias: 13, + label: 'M4.76,-1.54L2.94,4.05H-2.94L-4.76,-1.54L0,-5Z', + gl: true, + }, + { + value: 'pentagon-open', + alias: 13, + label: 'M4.76,-1.54L2.94,4.05H-2.94L-4.76,-1.54L0,-5Z', + fill: 'none', + gl: true, + }, -export const CATEGORY_LAYOUT = [ - { category: CHART_CATEGORY.BUSINESS, label: "Business" }, - { category: CHART_CATEGORY.SCIENCE, label: "Science" }, - { category: CHART_CATEGORY.CHARTS_3D, label: "3d charts" }, - { category: CHART_CATEGORY.FINANCIAL, label: "Finance" }, - { category: CHART_CATEGORY.STATISTICS, label: "Statistics" }, - { category: CHART_CATEGORY.MAPS, label: "Maps" }, -]; + { + value: 'hexagon', + alias: 14, + label: 'M4.33,-2.5V2.5L0,5L-4.33,2.5V-2.5L0,-5Z', + gl: true, + }, + { + value: 'hexagon-open', + alias: 14, + label: 'M4.33,-2.5V2.5L0,5L-4.33,2.5V-2.5L0,-5Z', + fill: 'none', + gl: true, + }, -// ShareModalTabs -export const SHARE_MODAL_TAB_OPTIONS = { - LINK_AND_PRIVACY: "Link & Privacy", - COLLABORATORS: "Collaborate", - EMBED: "Embed", -}; + { + value: 'hexagon2', + alias: 15, + label: 'M-2.5,4.33H2.5L5,0L2.5,-4.33H-2.5L-5,0Z', + gl: true, + }, + { + value: 'hexagon2-open', + alias: 15, + label: 'M-2.5,4.33H2.5L5,0L2.5,-4.33H-2.5L-5,0Z', + fill: 'none', + gl: true, + }, -export const SHARE_MODAL_TABS = Object.keys(SHARE_MODAL_TAB_OPTIONS).map(k => { - return SHARE_MODAL_TAB_OPTIONS[k]; -}); + { + value: 'octagon', + alias: 16, + label: + 'M-1.92,-4.62H1.92L4.62,-1.92V1.92L1.92,4.62H-1.92L-4.62,1.92V-1.92Z', + }, + { + value: 'octagon-open', + alias: 16, + label: + 'M-1.92,-4.62H1.92L4.62,-1.92V1.92L1.92,4.62H-1.92L-4.62,1.92V-1.92Z', + fill: 'none', + }, -// 1x1px transparent gif: https://css-tricks.com/snippets/html/base64-encode-of-1x1px-transparent-gif/ -export const IMAGE_PLACEHOLDER = - "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; + { + value: 'star', + alias: 17, + label: + 'M1.58,-2.16H6.66L2.54,0.83L4.12,5.66L0,2.67L-4.12,5.66L-2.54,0.83L-6.66,-2.16H-1.58L0,-7Z', + gl: true, + }, + { + value: 'star-open', + alias: 17, + label: + 'M1.58,-2.16H6.66L2.54,0.83L4.12,5.66L0,2.67L-4.12,5.66L-2.54,0.83L-6.66,-2.16H-1.58L0,-7Z', + fill: 'none', + gl: true, + }, -export const MAPBOX_ERROR_TYPES = { - INVALID_JSON: "INVALID_JSON", - FAILED_REQUEST: "FAILED_REQUEST", - FAILED_PARSING: "FAILED_PARSING", - UNKNOWN: "UNKNOWN", -}; + { + value: 'hexagram', + alias: 18, + label: + 'M-3.8,0l-1.9,-3.3h3.8l1.9,-3.3l1.9,3.3h3.8l-1.9,3.3l1.9,3.3h-3.8l-1.9,3.3l-1.9,-3.3h-3.8Z', + }, + { + value: 'hexagram-open', + alias: 18, + label: + 'M-3.8,0l-1.9,-3.3h3.8l1.9,-3.3l1.9,3.3h3.8l-1.9,3.3l1.9,3.3h-3.8l-1.9,3.3l-1.9,-3.3h-3.8Z', + fill: 'none', + }, -export const WORKSPACE_PLOT_ID = "js-main-plotly-workspace-plot"; + { + value: 'star-triangle-up', + alias: 19, + label: + 'M-6.93,4A 20,20 0 0 1 6.93,4A 20,20 0 0 1 0,-8A 20,20 0 0 1 -6.93,4Z', + }, + { + value: 'star-triangle-up-open', + alias: 19, + label: + 'M-6.93,4A 20,20 0 0 1 6.93,4A 20,20 0 0 1 0,-8A 20,20 0 0 1 -6.93,4Z', + fill: 'none', + }, -export const WORKSPACE_CONTAINER = document.getElementById("main"); -export const WORKSPACE_PLACEHOLDER = document.getElementById( - "placeholderworkspace" -); + { + value: 'star-triangle-down', + alias: 20, + label: + 'M6.93,-4A 20,20 0 0 1 -6.93,-4A 20,20 0 0 1 0,8A 20,20 0 0 1 6.93,-4Z', + }, + { + value: 'star-triangle-down-open', + alias: 20, + label: + 'M6.93,-4A 20,20 0 0 1 -6.93,-4A 20,20 0 0 1 0,8A 20,20 0 0 1 6.93,-4Z', + fill: 'none', + }, -const IS_TRANSFORM = true; + { + value: 'star-square', + alias: 21, + label: + 'M-5.5,-5.5A 10,10 0 0 1 -5.5,5.5A 10,10 0 0 1 5.5,5.5A 10,10 0 0 1 5.5,-5.5A 10,10 0 0 1 -5.5,-5.5Z', + }, + { + value: 'star-square-open', + alias: 21, + label: + 'M-5.5,-5.5A 10,10 0 0 1 -5.5,5.5A 10,10 0 0 1 5.5,5.5A 10,10 0 0 1 5.5,-5.5A 10,10 0 0 1 -5.5,-5.5Z', + fill: 'none', + }, -// quadruplet containing [CONSTANT_NAME TYPE LABEL IS_TRANSFORM]. -export const ANALYSES = [ - [ - "DESCRIPTIVE", - "descriptive-statistics", - "Descriptive statistics", - !IS_TRANSFORM, - ], - ["ANOVA_TEST", "anova", "ANOVA", !IS_TRANSFORM], - ["CHI_SQUARED_TEST", "chi-squared-test", "Chi-squared test", !IS_TRANSFORM], - ["T_TEST", "t-test", "T-test (two-tailed, independent)", !IS_TRANSFORM], - ["CORRELATION", "column-correlation", "Column correlation", !IS_TRANSFORM], - ["FIT", "fit", "Curve fitting", IS_TRANSFORM], - ["AVERAGE", "average", "Average", IS_TRANSFORM], - ["MOVING_AVERAGE", "moving-average", "Moving average", IS_TRANSFORM], -]; + { + value: 'star-diamond', + alias: 22, + label: + 'M-7,0A 9.5,9.5 0 0 1 0,7A 9.5,9.5 0 0 1 7,0A 9.5,9.5 0 0 1 0,-7A 9.5,9.5 0 0 1 -7,0Z', + }, + { + value: 'star-diamond-open', + alias: 22, + label: + 'M-7,0A 9.5,9.5 0 0 1 0,7A 9.5,9.5 0 0 1 7,0A 9.5,9.5 0 0 1 0,-7A 9.5,9.5 0 0 1 -7,0Z', + fill: 'none', + }, -export const ANALYSES_TYPES = ANALYSES.reduce((accum, [name, type]) => { - accum[name] = type; - return accum; -}, {}); + { + value: 'diamond-tall', + alias: 23, + label: 'M0,7L3.5,0L0,-7L-3.5,0Z', + gl: true, + }, + { + value: 'diamond-tall-open', + alias: 23, + label: 'M0,7L3.5,0L0,-7L-3.5,0Z', + fill: 'none', + gl: true, + }, -export const ANALYSES_TYPES_TO_LABELS = ANALYSES.reduce( - (accum, [, type, label]) => { - accum[type] = label; - return accum; + {value: 'diamond-wide', alias: 24, label: 'M0,3.5L7,0L0,-3.5L-7,0Z'}, + { + value: 'diamond-wide-open', + alias: 24, + label: 'M0,3.5L7,0L0,-3.5L-7,0Z', + fill: 'none', }, - {} -); -// used by WorkspaceActions to search for linked transforms inside traces -export const TRANSFORM_TYPES = ANALYSES.filter( - ([, , , isTransform]) => isTransform -).map(([, type]) => type); + {value: 'hourglass', alias: 25, label: 'M5,5H-5L5,-5H-5Z'}, + {value: 'bowtie', alias: 26, label: 'M5,5V-5L-5,5V-5Z', gl: true}, + { + value: 'cross-thin-open', + alias: 33, + label: 'M0,7V-7M7,0H-7', + fill: 'none', + gl: true, + }, + { + value: 'x-thin-open', + alias: 34, + label: 'M5,5L-5,-5M5,-5L-5,5', + fill: 'none', + }, + { + value: 'asterisk-open', + alias: 35, + label: 'M0,6V-6M6,0H-6M4.25,4.25L-4.25,-4.25M4.25,-4.25L-4.25,4.25', + fill: 'none', + gl: true, + }, -// Constants relating to the user interface + { + value: 'hash-open', + alias: 36, + label: 'M2.5,5V-5m-5,0V5M5,2.5H-5m0,-5H5', + fill: 'none', + }, + { + value: 'hash-open-dot', + alias: 36, + label: 'M2.5,5V-5m-5,0V5M5,2.5H-5m0,-5H5M0,0.5L0.5,0L0,-0.5L-0.5,0Z', + fill: 'none', + }, -export const RETURN_KEY = "Enter"; -export const ESCAPE_KEY = "Escape"; -export const COMMAND_KEY = "Meta"; -export const CONTROL_KEY = "Control"; -*/ + { + value: 'y-up-open', + alias: 37, + label: 'M-6,4L0,0M6,4L0,0M0,-8L0,0', + fill: 'none', + gl: true, + }, + { + value: 'y-down-open', + alias: 38, + label: 'M-6,-4L0,0M6,-4L0,0M0,8L0,0', + fill: 'none', + gl: true, + }, + { + value: 'y-left-open', + alias: 39, + label: 'M4,6L0,0M4,-6L0,0M-8,0L0,0', + fill: 'none', + }, + { + value: 'y-right-open', + alias: 40, + label: 'M-4,6L0,0M-4,-6L0,0M8,0L0,0', + fill: 'none', + }, + {value: 'line-ew-open', alias: 41, label: 'M7,0H-7', fill: 'none', gl: true}, + {value: 'line-ns-open', alias: 42, label: 'M0,7V-7', fill: 'none', gl: true}, + {value: 'line-ne-open', alias: 43, label: 'M5,-5L-5,5', fill: 'none'}, + {value: 'line-nw-open', alias: 44, label: 'M5,5L-5,-5', fill: 'none'}, +]; diff --git a/src/lib/unpackPlotProps.js b/src/lib/unpackPlotProps.js index 37feb16e7..1d53e5b0f 100644 --- a/src/lib/unpackPlotProps.js +++ b/src/lib/unpackPlotProps.js @@ -3,7 +3,13 @@ import isNumeric from 'fast-isnumeric'; import {MULTI_VALUED, MULTI_VALUED_PLACEHOLDER} from './constants'; export default function unpackPlotProps(props, context, ComponentClass) { - const {container, defaultContainer, fullContainer, updateContainer} = context; + const { + container, + getValObject, + defaultContainer, + fullContainer, + updateContainer, + } = context; if (!container || !fullContainer) { throw new Error( @@ -28,7 +34,10 @@ export default function unpackPlotProps(props, context, ComponentClass) { } // Property descriptions and meta: - const attrMeta = context.getValObject(props.attr) || {}; + let attrMeta; + if (getValObject) { + attrMeta = context.getValObject(props.attr) || {}; + } // Update data functions: const updatePlot = v => updateContainer && updateContainer({[props.attr]: v}); @@ -46,6 +55,7 @@ export default function unpackPlotProps(props, context, ComponentClass) { attrMeta, container, defaultValue, + getValObject, fullContainer, fullValue, isVisible, @@ -54,11 +64,13 @@ export default function unpackPlotProps(props, context, ComponentClass) { multiValued, }; - if (isNumeric(attrMeta.max)) { - plotProps.max = attrMeta.max; - } - if (isNumeric(attrMeta.min)) { - plotProps.min = attrMeta.min; + if (attrMeta) { + if (isNumeric(attrMeta.max)) { + plotProps.max = attrMeta.max; + } + if (isNumeric(attrMeta.min)) { + plotProps.min = attrMeta.min; + } } // Give Component Classes the space to modify plotProps: diff --git a/src/styles/_helpers.scss b/src/styles/_helpers.scss index 99c9d7695..80b462bc2 100644 --- a/src/styles/_helpers.scss +++ b/src/styles/_helpers.scss @@ -1,3 +1,3 @@ .\+flex { display: flex; } .\+cursor-clickable { cursor: pointer; } -.\+hover-grey:hover{ color: $color-gray-dark; } +.\+hover-grey:hover{ color: $color-active-text; } diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index 03e1800af..c633e6ef9 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -21,3 +21,15 @@ @error "'#{$value}' is not a valid z-index value"; } } + +@mixin clearfix() { + &:before, + &:after { + content: " "; + display: table; + } + + &:after { + clear: both; + } +} diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss deleted file mode 100644 index cebe2621e..000000000 --- a/src/styles/_variables.scss +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SIZING AND WEIGHTS - */ -$font-weight-light: 300; -$font-weight-normal: 400; -$font-weight-semibold: 600; -$font-size-small: 12px; -$font-size-medium: 14px; -$h5-size: 16px !default; - -/* - * SPACING - */ -$base-spacing-unit: 24px !default; -$half-spacing-unit: 12px; -$quarter-spacing-unit: 6px; -$sixth-spacing-unit: 4px; -$eighth-spacing-unit: 3px; - -/* - * BORDERS - */ -$border-radius: 2px; -$border-radius-5: 5px; - -/* - * COLORS - */ -$color-black-dark: #000; -$color-black-paleish: #333; -$color-black-pale: #666; -$color-black: #111; -$color-navyblue: #284576; -$color-blue: #119DFF; -$color-blue-dark: darken($color-blue, 20%); -$color-blue-pale: #45a9ff; -$color-blue-paleish: #2391fe; -$color-cyan-pale: #9bd1ff; -$color-gold: #f7bd0c; -$color-gray-blue: #69738a; -$color-gray-blue-pale: #bec8d9; -$color-gray-dark: #888; -$color-gray-light: #ddd; -$color-gray: #ccc; -$color-green-cyan: #53cf9d; -$color-green-pale: #dff0d8; -$color-green: #3c763d; -$color-red-pale: #f2dede; -$color-red: #a94442; -$color-white-blue: #f4faff; -$color-white-dark: #eee; -$color-white-darkish: #f8f8f8; -$color-white: #ffffff; - -// --- -// Text and Backgrounds -// --- -$color-rhino-core: #2a3f5f; // Active state text, emphasized text -$color-rhino-dark: #506784; // Default text color -$color-rhino-medium-1: #a2b1c6; -$color-rhino-medium-2: #c8d4e3; // Border Default -$color-rhino-light-1: #dfe8f3; // Border Secondary -$color-rhino-light-2: #ebf0f8; // Button Secondary -$color-rhino-light-3: #f3f6fa; // Page Background -$color-rhino-light-4: #fafbfd; // Modal Tabbed Content Background - - -// --- -// Primary -// -- -$color-dodger: #119DFF; // Accent -$color-dodger-shade: #0D76BF; // Link Hover - -// --- -// Accent -// --- -$color-aqua: #09ffff; -$color-aqua-shade: #19d3f3; // Body Text -$color-lavender: #e763fa; -$color-lavender-shade: #ab63fa; -$color-cornflower: #636efa; -$color-emerald: #00cc96; // CTA's on blue backgrounds -$color-sienna: #ef553b; // CTA's on blue backgrounds - -// --- -// Buttons -// --- -$color-button-default: #119dff; -$color-button-hover: #0f89df; -$color-button-active: #0d76bf; - -/* - * COMPONENT - */ -$fold-border: 1px solid $color-gray-blue-pale; diff --git a/src/styles/components/containers/_fold.scss b/src/styles/components/containers/_fold.scss index 4d1616e77..c91f1f9a8 100644 --- a/src/styles/components/containers/_fold.scss +++ b/src/styles/components/containers/_fold.scss @@ -15,8 +15,8 @@ clear: both; padding: 6px 12px; color: #ffffff; - font-size: 13px; - line-height: 13px; + font-size: $font-size; + line-height: $font-size; border: 1px solid #a2b1c6; background-color: #a2b1c6; height: 15px; diff --git a/src/styles/components/containers/_info.scss b/src/styles/components/containers/_info.scss index 49b4070a2..812e6c2cf 100644 --- a/src/styles/components/containers/_info.scss +++ b/src/styles/components/containers/_info.scss @@ -1,5 +1,5 @@ .info__title { - color: $color-blue-pale; + color: $color-link-light; font-size: $font-size-medium; font-weight: $font-weight-normal; line-height: 18px; @@ -8,14 +8,14 @@ .info__text { padding: $quarter-spacing-unit $half-spacing-unit; - color: $color-rhino-dark; + color: $color-secondary-text; font-size: $font-size-small; font-weight: $font-weight-light; line-height: 18px; } .info__sub-text { - color: $color-navyblue; + color: $color-brand; font-size: $font-size-small; font-weight: $font-weight-light; line-height: 14px; diff --git a/src/styles/components/containers/_main.scss b/src/styles/components/containers/_main.scss index 7072badaa..93140140e 100644 --- a/src/styles/components/containers/_main.scss +++ b/src/styles/components/containers/_main.scss @@ -3,3 +3,4 @@ @import "section"; @import "menupanel"; @import "info"; +@import "modalbox"; diff --git a/src/styles/components/containers/_menupanel.scss b/src/styles/components/containers/_menupanel.scss index eb050858e..34992627b 100644 --- a/src/styles/components/containers/_menupanel.scss +++ b/src/styles/components/containers/_menupanel.scss @@ -1,48 +1,20 @@ -.subpanel { - position: absolute; - border-radius: 2px; - text-transform: none; - text-align: left; - border: $fold-border; - - align-content: center; - box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.2); - left: 0; - right: 0; - - margin: 0 24px; - min-width: 200px; - background-color: $color-white; - - @include z-index("cloud"); -} - -.subpanel__cover { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - @include z-index("underground"); -} - -.subpanel__container { +.menupanel { padding-top: 0; } -.subpanel__container--ownline { +.menupanel--ownline { padding-top: 6px; } -.subpanel__icon-span { +.menupanel__icon-span { font-size: $font-size-small; } -.subpanel__icon-span--question { - color: $color-blue-pale; +.menupanel__icon-span--question { + color: $color-link-light; } -.subpanel__icon { +.menupanel__icon { padding-left: 6px; padding-right: 6px; vertical-align: middle; diff --git a/src/styles/components/containers/_modalbox.scss b/src/styles/components/containers/_modalbox.scss new file mode 100644 index 000000000..cd1f7faad --- /dev/null +++ b/src/styles/components/containers/_modalbox.scss @@ -0,0 +1,27 @@ +.modalbox { + position: absolute; + border-radius: 2px; + text-transform: none; + text-align: left; + border: 1px solid $color-border; + + align-content: center; + box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.2); + left: 0; + right: 0; + + margin: 0 24px; + min-width: 200px; + background-color: $color-white; + + @include z-index("cloud"); +} + +.modalbox__cover { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + @include z-index("underground"); +} diff --git a/src/styles/components/containers/_panel.scss b/src/styles/components/containers/_panel.scss index 803289860..e1c87e408 100644 --- a/src/styles/components/containers/_panel.scss +++ b/src/styles/components/containers/_panel.scss @@ -5,7 +5,7 @@ bottom: 5px; right: 1px; margin-left: 100px; - background-color: $color-rhino-light-3; + background-color: $color-panel-background; overflow-y: scroll; padding-left: $half-spacing-unit; padding-right: $half-spacing-unit; diff --git a/src/styles/components/containers/_section.scss b/src/styles/components/containers/_section.scss index 52351ae03..d85c61b17 100644 --- a/src/styles/components/containers/_section.scss +++ b/src/styles/components/containers/_section.scss @@ -1,10 +1,10 @@ .section__heading { display: flex; - font-size: 13px; - color: #69738a; + font-size: $font-size; + color: $color-header-text; font-weight: 400; cursor: default; - background-color: #F4FAFF; + background-color: $color-section-header-background; padding: 6px 12px; clear: both; text-transform: capitalize; diff --git a/src/styles/components/fields/_field.scss b/src/styles/components/fields/_field.scss new file mode 100644 index 000000000..ef5a68dd0 --- /dev/null +++ b/src/styles/components/fields/_field.scss @@ -0,0 +1,59 @@ +.field { + align-items: center; + border-top: 1px solid #f8f8f9; + color: #6D6D6D; + display: flex; + font-size: $font-size; + font-weight: $font-weight-light; + justify-content: flex-start; + line-height: $font-size; + min-height: 32px; + padding: 6px 0; + width: 100%; +} + +.field:not(:last-child) { + border-bottom: 1px solid #f8f8f9; +} + +.field__no-title { + width: 100%; + padding: 0 12px; +} + +.field__no-title--center { + text-align: center; +} + +.field__title { + padding-left: 0.5em; + color: #69738a; + font-size: 14px; + width: 36%; + display: inline-block; +} + +.field__widget { + width: 64%; + padding-left: 12px; + display: inline-block; + padding-right: 12px; +} + +.field__widget--postfix { + width: 50%; + padding-right: 0px; +} + +.field__title { + width: 30%; + padding-left: 12px; + display: inline-block; + line-height: 18px; + text-transform: capitalize; +} + +.field__title-text { + text-transform: capitalize; + cursor: default; +} diff --git a/src/styles/components/fields/_main.scss b/src/styles/components/fields/_main.scss index 2e049daac..3c7187a9b 100644 --- a/src/styles/components/fields/_main.scss +++ b/src/styles/components/fields/_main.scss @@ -1,59 +1,2 @@ -.field { - align-items: center; - border-top: 1px solid #f8f8f9; - color: #6D6D6D; - display: flex; - font-size: 13px; - font-weight: $font-weight-light; - justify-content: flex-start; - line-height: 13px; - min-height: 32px; - padding: 6px 0; - width: 100%; -} - -.field:not(:last-child) { - border-bottom: 1px solid #f8f8f9; -} - -.field__no-title { - width: 100%; - padding: 0 12px; -} - -.field__no-title--center { - text-align: center; -} - -.field__title { - padding-left: 0.5em; - color: #69738a; - font-size: 14px; - width: 36%; - display: inline-block; -} - -.field__widget { - width: 64%; - padding-left: 18px; - display: inline-block; - padding-right: 12px; -} - -.field__widget--postfix { - width: 50%; - padding-right: 0px; -} - -.field__title { - width: 30%; - padding-left: 12px; - display: inline-block; - line-height: 18px; - text-transform: capitalize; -} - -.field__title-text { - text-transform: capitalize; - cursor: default; -} +@import 'field'; +@import 'symbolselector'; diff --git a/src/styles/components/fields/_symbolselector.scss b/src/styles/components/fields/_symbolselector.scss new file mode 100644 index 000000000..029ae848e --- /dev/null +++ b/src/styles/components/fields/_symbolselector.scss @@ -0,0 +1,38 @@ +.symbol-selector__toggle { + border: 1px solid $color-border; + border-radius: 4px; + width: 80px; + cursor: pointer; + padding: $quarter-spacing-unit 10px; + @include clearfix(); +} + +.symbol-selector__toggle__option { + float: left; +} + +.symbol-selector__toggle__caret { + float: right; + color: $color-secondary-text; +} + +.symbol-selector__menu { + max-width: 225px; + position: absolute; + @include z-index("orbit"); + border: 1px solid $color-border; + padding: $font-size; + box-shadow: 2px 2px $font-size $color-border-secondary; +border-radius: $border-radius; +left: $base-spacing-unit; +} + + .symbol-selector__item { + display: inline; + } + + .symbol-selector__symbol { + &:hover { + background-color: $color-border; + } + } diff --git a/src/styles/components/widgets/_colorpicker.scss b/src/styles/components/widgets/_colorpicker.scss index 561050d11..05f762586 100644 --- a/src/styles/components/widgets/_colorpicker.scss +++ b/src/styles/components/widgets/_colorpicker.scss @@ -1,6 +1,5 @@ $swatch-size: 20px; $colorpicker-width: 250px; -$colorpicker-border-color: #bbb; $saturation-picker-height: 160px; $slider-picker-height: 10px; @@ -43,7 +42,7 @@ $slider-picker-height: 10px; width: 32px; height: 32px; border-radius: 50%; - border: 1px solid $color-gray-light; + border: 1px solid $color-border-secondary; vertical-align: middle; padding-top: $sixth-spacing-unit; padding-left: $sixth-spacing-unit; @@ -52,7 +51,7 @@ $slider-picker-height: 10px; .colorpicker__selected-color { margin-left: $half-spacing-unit; - color: $color-black-pale; + color: $color-text; font-weight: $font-weight-light; font-size: $font-size-small; display: inline-block; @@ -67,17 +66,11 @@ $slider-picker-height: 10px; vertical-align: middle; } -.toolLabel { - color: $color-black-pale; - font-size: $font-size-small; - font-weight: $font-weight-light; -} - %colorpicker__component { position: relative; overflow: hidden; margin: 0 $half-spacing-unit; - border: 1px solid $colorpicker-border-color; + border: 1px solid $color-border; border-radius: $border-radius / 2; cursor: pointer; } diff --git a/src/styles/components/widgets/_numeric-input.scss b/src/styles/components/widgets/_numeric-input.scss index 8b9a4b066..853bf29c7 100644 --- a/src/styles/components/widgets/_numeric-input.scss +++ b/src/styles/components/widgets/_numeric-input.scss @@ -5,7 +5,7 @@ .numeric-input__number { display: inline-block; - border: 1px solid #bec8d9; + border: 1px solid $color-border; background: white; cursor: text; overflow: hidden; @@ -14,7 +14,7 @@ text-align: left; border-radius: 2px; padding: 6px 6px 6px 12px; - width: 80px; + width: 62px; vertical-align: middle; font-size: inherit; color: inherit; @@ -39,8 +39,8 @@ background-color: #f8f8f9; border: 1px solid #bec8d9; border-radius: 1px; - width: 13px; - height: 13px; + width: $font-size; + height: $font-size; line-height: 12px; text-align: center; } diff --git a/src/styles/icons/_icons.scss b/src/styles/icons/_icons.scss index c369663db..359fc8139 100644 --- a/src/styles/icons/_icons.scss +++ b/src/styles/icons/_icons.scss @@ -1,6 +1,6 @@ @font-face { font-family: "react-plotlyjs-editor"; - src: url('data:font/truetype;charset=utf-8;base64,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') format("truetype"); + src: url('data:font/truetype;charset=utf-8;base64,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') format("truetype"); font-weight: normal; font-style: normal; } @@ -37,3 +37,9 @@ .plotlyjs_editor__icon-question-circle:before { content: "\62"; } +.plotlyjs_editor__.icon-caret-down:before { + content: "\63"; +} +.plotlyjs_editor__.icon-angle-down:before { + content: "\64"; +} diff --git a/src/styles/main.scss b/src/styles/main.scss index e84c6aa38..69b3c3c8e 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -1,5 +1,5 @@ @charset 'utf-8'; -@import 'variables'; +@import 'variables/main'; @import 'mixins'; @import 'helpers'; @import 'icons/main'; diff --git a/src/styles/variables/_defaults.scss b/src/styles/variables/_defaults.scss new file mode 100644 index 000000000..15971946e --- /dev/null +++ b/src/styles/variables/_defaults.scss @@ -0,0 +1,90 @@ +/* + * SIZING AND WEIGHTS + */ +$default-font-weight-light: 300; +$default-font-weight-normal: 400; +$default-font-weight-semibold: 600; +$default-font-size: 13px; +$default-font-size-small: 12px; +$default-font-size-medium: 14px; +$default-h5-size: 16px !default; + +/* + * SPACING + */ +$default-base-spacing-unit: 24px !default; +$default-half-spacing-unit: 12px; +$default-quarter-spacing-unit: 6px; +$default-sixth-spacing-unit: 4px; +$default-eighth-spacing-unit: 3px; + +/* + * BORDERS + */ +$default-border-radius: 2px; +$default-border-radius-5: 5px; + +/* + * COLORS + */ +$default-color-black-dark: #000; +$default-color-black-paleish: #333; +$default-color-black-pale: #666; +$default-color-black: #111; +$default-color-navyblue: #284576; +$default-color-blue: #119DFF; +$default-color-blue-dark: darken($default-color-blue, 20%); +$default-color-blue-pale: #45a9ff; +$default-color-blue-paleish: #2391fe; +$default-color-cyan-pale: #9bd1ff; +$default-color-gold: #f7bd0c; +$default-color-gray-blue: #69738a; +$default-color-gray-blue-pale: #bec8d9; +$default-color-gray-dark: #888; +$default-color-gray-light: #ddd; +$default-color-gray: #ccc; +$default-color-green-cyan: #53cf9d; +$default-color-green-pale: #dff0d8; +$default-color-green: #3c763d; +$default-color-red-pale: #f2dede; +$default-color-red: #a94442; +$default-color-white-blue: #f4faff; +$default-color-white-dark: #eee; +$default-color-white-darkish: #f8f8f8; +$default-color-white: #ffffff; + +// --- +// Text and Backgrounds +// --- +$default-color-rhino-core: #2a3f5f; // Active state text, emphasized text +$default-color-rhino-dark: #506784; // Default text color +$default-color-rhino-medium-1: #a2b1c6; +$default-color-rhino-medium-2: #c8d4e3; // Border Default +$default-color-rhino-light-1: #dfe8f3; // Border Secondary +$default-color-rhino-light-2: #ebf0f8; // Button Secondary +$default-color-rhino-light-3: #f3f6fa; // Page Background +$default-color-rhino-light-4: #fafbfd; // Modal Tabbed Content Background + +// --- +// Primary +// -- +$default-color-dodger: #119DFF; // Accent +$default-color-dodger-shade: #0D76BF; // Link Hover + +// --- +// Accent +// --- +$default-color-aqua: #09ffff; +$default-color-aqua-shade: #19d3f3; // Body Text +$default-color-lavender: #e763fa; +$default-color-lavender-shade: #ab63fa; +$default-color-cornflower: #636efa; +$default-color-emerald: #00cc96; // CTA's on blue backgrounds +$default-color-sienna: #ef553b; // CTA's on blue backgrounds + +// --- +// Buttons +// --- +$default-color-button-default: #119dff; +$default-color-button-hover: #0f89df; +$default-color-button-active: #0d76bf; diff --git a/src/styles/variables/_main.scss b/src/styles/variables/_main.scss new file mode 100644 index 000000000..d62a1ea89 --- /dev/null +++ b/src/styles/variables/_main.scss @@ -0,0 +1,51 @@ +@import 'defaults'; + + +$font-weight-light: $default-font-weight-light; +$font-weight-normal: $default-font-weight-normal; +$font-weight-semibold: $default-font-weight-semibold; +$font-size: $default-font-size; +$font-size-small: $default-font-size-small; +$font-size-medium: $default-font-size-medium; +$h5-size: $default-h5-size; + +/* + * SPACING + */ +$base-spacing-unit: $default-base-spacing-unit; +$half-spacing-unit: $default-half-spacing-unit; +$quarter-spacing-unit: $default-quarter-spacing-unit; +$sixth-spacing-unit: $default-sixth-spacing-unit; +$eighth-spacing-unit: $default-eighth-spacing-unit; + +/* + * BORDERS + */ +$border-radius: $default-border-radius; +$border-radius-5: $default-border-radius-5; + +/* + * COLORS + */ + +// base +$color-brand: $default-color-navyblue; +$color-white: $default-color-white; +$color-highlight-darker: $default-color-gray-blue-pale; + +// text +$color-active-text: $default-color-rhino-core; +$color-text: $default-color-rhino-dark; +$color-secondary-text: $default-color-rhino-medium-1; +$color-header-text: $default-color-rhino-core; +$color-link-light: $default-color-blue-pale; + +// backgrounds +$color-panel-background: $default-color-white; +$color-section-header-background: $default-color-white-blue; + +// themes +$color-border: $default-color-rhino-medium-2; +$color-border-secondary: $default-color-rhino-light-1; +$color-button-secondary: $default-color-rhino-light-2; +$color-page-background: $default-color-rhino-light-3;