Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Simple component that takes in props and renders.

* `<TraceAccordion />`: `<Panel />` whose children are replicated into `<Folds />` connected to traces via `connectTraceToPlot()`.
* `<LayoutPanel />`: `<Panel />` whose children are connected to the `layout` figure key
* `<LayoutSection />`: `<Section />` whose children are connected to the `layout` figure key
* `<TraceRequiredPanel />`: `<LayoutPanel />` renders `<PanelEmpty />` if no trace data is set, can add extra conditions (i.e. an array of functions that will be run) with the `extraConditions` prop and a matching array with extraEmptyPanelMessages to show when those conditions are not met.
* `<AnnotationAccordion />`: `<Panel />` whose children are replicated into `<Folds />` connected to annotations via `connectAnnotationToLayout()`. For use in a `<LayoutPanel />`.
* `<ShapeAccordion />`: `<Panel />` whose children are replicated into `<Folds />` connected to shapes via `connectShapeToLayout()`. For use in a `<LayoutPanel />`.
Expand All @@ -117,7 +118,6 @@ For use in containers bound to traces e.g. as children of `<TraceAccordion />`:
* `<LineDashSelector />`: renders as a `<Dropdown />` useful for `data[].line.dash`
* `<LineShapeSelector />`: renders as a `<Dropdown />` useful for `data[].line.shape`
* `<SymbolSelector />`: renders as a `<Dropdown />` useful for `data[].marker.symbol`
* `<LayoutNumericFraction />` and `<LayoutNumericFractionInverse />`: renders as a `<Numeric />` for use in trace-connected containers where normal `<Numerics />` would be bound to the `data` key instead of the `layout` key in the figure e.g. `layout.bargap` or `layout.barwidth`.
* `<PositioningRef />`: renders as a `<Dropdown />` useful for `layout.*.xref/yref` where the allowable values are `paper|[axis]`
* `<ErrorBars/>`: renders a set of controls that control a trace's error bars (`visibility`, `type`, `value`, `valueminus`, `array`, `arrayminus`)

Expand Down
40 changes: 9 additions & 31 deletions src/EditorControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import DefaultEditor from './DefaultEditor';
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {bem} from './lib';
import {maybeClearAxisTypes} from './shame';
import {
shamefullyClearAxisTypes,
shamefullyAdjustAxisRef,
shamefullyAdjustGeo,
} from './shame';
import {EDITOR_ACTIONS} from './lib/constants';
import isNumeric from 'fast-isnumeric';
import nestedProperty from 'plotly.js/src/lib/nested_property';
Expand Down Expand Up @@ -43,31 +47,6 @@ class EditorControls extends Component {
};
}

maybeAdjustAxisRef(payload) {
const {graphDiv} = this.props;
if (payload.tracesNeedingAxisAdjustment) {
payload.tracesNeedingAxisAdjustment.forEach(trace => {
const axis = trace[payload.axisAttrToAdjust].charAt(0);
const currentAxisIdNumber = Number(
trace[payload.axisAttrToAdjust].slice(1)
);
const adjustedAxisIdNumber = currentAxisIdNumber - 1;

const currentAxisLayoutProperties = {
...graphDiv.layout[payload.axisAttrToAdjust + currentAxisIdNumber],
};

// for cases when we're adjusting x2 => x, so that it becomes x not x1
graphDiv.data[trace.index][payload.axisAttrToAdjust] =
adjustedAxisIdNumber === 1 ? axis : axis + adjustedAxisIdNumber;

graphDiv.layout[
payload.axisAttrToAdjust + adjustedAxisIdNumber
] = currentAxisLayoutProperties;
});
}
}

handleUpdate({type, payload}) {
const {graphDiv} = this.props;

Expand All @@ -77,11 +56,8 @@ class EditorControls extends Component {
this.props.beforeUpdateTraces(payload);
}

// until we start utilizing Plotly.react in `react-plotly.js`
// force clear axes types when a `src` has changed.
maybeClearAxisTypes(graphDiv, payload.traceIndexes, payload.update);

this.maybeAdjustAxisRef(payload);
shamefullyClearAxisTypes(graphDiv, payload);
shamefullyAdjustAxisRef(graphDiv, payload);

for (let i = 0; i < payload.traceIndexes.length; i++) {
for (const attr in payload.update) {
Expand All @@ -108,6 +84,8 @@ class EditorControls extends Component {
break;

case EDITOR_ACTIONS.UPDATE_LAYOUT:
shamefullyAdjustGeo(graphDiv, payload);

if (this.props.beforeUpdateLayout) {
this.props.beforeUpdateLayout(payload);
}
Expand Down
14 changes: 4 additions & 10 deletions src/components/containers/AxesFold.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,12 @@ import React, {Component} from 'react';
import {connectAxesToLayout} from 'lib';

class AxesFold extends Component {
renderAxesSelector() {
if (this.props.options.length > 1) {
return <AxesSelector axesOptions={this.props.options} />;
}
return null;
}

render() {
return this.props.children ? (
const {children, options} = this.props;
return options.length && children ? (
<Fold {...this.props}>
{this.renderAxesSelector()}
{this.props.children}
{options.length === 1 ? null : <AxesSelector axesOptions={options} />}
{children}
</Fold>
) : null;
}
Expand Down
17 changes: 5 additions & 12 deletions src/components/containers/Fold.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,18 @@ class Fold extends Component {
this.foldVisible = false;

React.Children.forEach(nextProps.children, child => {
if (!child) {
if (!child || this.foldVisible) {
return;
}

if (child.props.attr) {
// attr components force fold open if they are visible
let plotProps;
if (child.type.supplyPlotProps) {
plotProps = child.type.supplyPlotProps(child.props, nextContext);
if (child.type.modifyPlotProps) {
child.type.modifyPlotProps(child.props, nextContext, plotProps);
}
} else {
plotProps = unpackPlotProps(child.props, nextContext);
const plotProps = unpackPlotProps(child.props, nextContext);
if (child.type.modifyPlotProps) {
child.type.modifyPlotProps(child.props, nextContext, plotProps);
}

if (plotProps.isVisible) {
this.foldVisible = true;
}
this.foldVisible = this.foldVisible || plotProps.isVisible;
return;
}

Expand Down
39 changes: 16 additions & 23 deletions src/components/containers/Section.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {Component, cloneElement} from 'react';
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {
containerConnectedContextTypes,
Expand All @@ -11,45 +11,38 @@ class Section extends Component {
constructor(props, context) {
super(props, context);

this.children = null;
this.sectionVisible = false;

this.processAndSetChildren(props, context);
this.determineVisibility(props, context);
}

componentWillReceiveProps(nextProps, nextContext) {
this.processAndSetChildren(nextProps, nextContext);
this.determineVisibility(nextProps, nextContext);
}

processAndSetChildren(nextProps, nextContext) {
determineVisibility(nextProps, nextContext) {
const {isVisible} = unpackPlotProps(nextProps, nextContext);
this.sectionVisible = isVisible === true;
this.sectionVisible = Boolean(isVisible);

React.Children.forEach(nextProps.children, child => {
if (!child || this.foldVisible) {
return;
}

this.children = React.Children.map(nextProps.children, child => {
if (child.props.attr) {
let plotProps;
if (child.type.supplyPlotProps) {
plotProps = child.type.supplyPlotProps(child.props, nextContext);
if (child.type.modifyPlotProps) {
child.type.modifyPlotProps(child.props, nextContext, plotProps);
}
} else {
plotProps = unpackPlotProps(child.props, nextContext);
const plotProps = unpackPlotProps(child.props, nextContext);
if (child.type.modifyPlotProps) {
child.type.modifyPlotProps(child.props, nextContext, plotProps);
}

// assign plotProps as a prop of children. If they are connectedToContainer
// it will see plotProps and skip recomputing them.
this.sectionVisible = this.sectionVisible || plotProps.isVisible;
return cloneElement(child, {plotProps});
return;
}

if (!(child.type.plotly_editor_traits || {}).no_visibility_forcing) {
// non-attr components force visibility (unless they don't via traits)
this.sectionVisible = true;
return child;
return;
}

return child;
});
}

Expand All @@ -60,7 +53,7 @@ class Section extends Component {
return (
<div className="section">
{this.props.name && <SectionHeader name={this.props.name} />}
{this.children}
{this.props.children}
</div>
);
}
Expand Down
2 changes: 0 additions & 2 deletions src/components/containers/__tests__/Section-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ describe('Section', () => {
).find(Section);

expect(wrapper.children().length).toBe(1);
expect(wrapper.find(Flaglist).props().plotProps.isVisible).toBe(true);
expect(wrapper.find(Numeric).props().plotProps.isVisible).toBe(false);
});

it('is visible if it contains any non attr children', () => {
Expand Down
3 changes: 2 additions & 1 deletion src/components/containers/derived.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
import {connectLayoutToPlot, containerConnectedContextTypes} from 'lib';

const LayoutPanel = connectLayoutToPlot(Panel);
const LayoutSection = connectLayoutToPlot(Section);

const TraceTypeSection = (props, context) => {
const {fullContainer, fullData} = context;
Expand Down Expand Up @@ -34,4 +35,4 @@ TraceTypeSection.defaultProps = {
traceTypes: [],
};

export {LayoutPanel, TraceTypeSection};
export {LayoutPanel, LayoutSection, TraceTypeSection};
3 changes: 2 additions & 1 deletion src/components/containers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Section from './Section';
import TraceAccordion from './TraceAccordion';
import TransformAccordion from './TransformAccordion';
import TraceMarkerSection from './TraceMarkerSection';
import {LayoutPanel, TraceTypeSection} from './derived';
import {LayoutPanel, LayoutSection, TraceTypeSection} from './derived';
import TraceRequiredPanel from './TraceRequiredPanel';
import SingleSidebarItem from './SingleSidebarItem';
import ModalProvider from './ModalProvider';
Expand All @@ -35,6 +35,7 @@ export {
TraceMarkerSection,
TraceRequiredPanel,
LayoutPanel,
LayoutSection,
AxesFold,
SingleSidebarItem,
TraceTypeSection,
Expand Down
2 changes: 0 additions & 2 deletions src/components/fields/AxisCreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
traceTypeToAxisType,
getAxisTitle,
axisIdToAxisName,
unpackPlotProps,
} from 'lib';

class UnconnectedNewAxisCreator extends Component {
Expand Down Expand Up @@ -184,7 +183,6 @@ AxisCreator.contextTypes = {
};

export default connectToContainer(AxisCreator, {
supplyPlotProps: (props, context) => unpackPlotProps(props, {...context}),
modifyPlotProps: (props, context, plotProps) => {
const {data} = context;
const {fullContainer} = plotProps;
Expand Down
5 changes: 1 addition & 4 deletions src/components/fields/__tests__/TraceSelector-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ describe('TraceSelector', () => {
...fixtures.scatter({data: [{mode: null, xsrc: null, ysrc: null}]}),
onUpdate: jest.fn(),
};

const wrapper = mount(
<TestEditor {...editorProps} plotly={plotly}>
<TraceSection traceIndexes={[0]}>
Expand All @@ -23,8 +24,6 @@ describe('TraceSelector', () => {
).find(TraceSelector);

const innerDropdown = wrapper.find(Dropdown);

expect(wrapper.props().plotProps.container.mode).toBe('markers');
expect(innerDropdown.prop('value')).toEqual('scatter');
});

Expand All @@ -44,7 +43,6 @@ describe('TraceSelector', () => {
).find(TraceSelector);

const innerDropdown = wrapper.find(Dropdown);

expect(innerDropdown.prop('value')).toEqual('line');
});

Expand All @@ -66,7 +64,6 @@ describe('TraceSelector', () => {
).find(TraceSelector);

const innerDropdown = wrapper.find(Dropdown);
expect(wrapper.props().plotProps.container.mode).toBe('lines+markers');
expect(innerDropdown.prop('value')).toEqual('line');
});

Expand Down
Loading