diff --git a/package.json b/package.json
index 66b0dcc8e..76f2193ef 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"react-colorscales": "^0.4.2",
"react-dom": "^16.2.0",
"react-select": "^1.0.0-rc.10",
+ "react-tabs": "^2.2.1",
"tinycolor2": "^1.4.1"
},
"devDependencies": {
diff --git a/src/components/containers/Panel.js b/src/components/containers/Panel.js
index e0458802f..ab586b392 100644
--- a/src/components/containers/Panel.js
+++ b/src/components/containers/Panel.js
@@ -106,7 +106,9 @@ class Panel extends Component {
);
return (
-
+
{
return (
@@ -39,13 +46,64 @@ class TraceAccordion extends Component {
}
},
};
- return {content ? content : null};
+ return (
+
+ {individualTraces ? individualTraces : null}
+
+ );
}
- return {content ? content : null};
+ if (canGroup && data.length > 1) {
+ const tracesByGroup = data.reduce((allTraces, next, index) => {
+ const traceType = plotlyTraceToCustomTrace(
+ fullData.filter(trace => trace.index === index)[0]
+ );
+ if (!allTraces[traceType]) {
+ allTraces[traceType] = [];
+ }
+ allTraces[traceType].push(index);
+ return allTraces;
+ }, {});
+
+ const groupedTraces = Object.keys(tracesByGroup).map(
+ (traceType, index) => {
+ return (
+
+ {this.props.children}
+
+ );
+ }
+ );
+ return (
+
+
+
+ {_('All Traces')}
+ {_('Individual')}
+
+
+ {groupedTraces ? groupedTraces : null}
+
+
+ {individualTraces ? individualTraces : null}
+
+
+
+ );
+ }
+ return (
+
+ {individualTraces ? individualTraces : null}
+
+ );
}
}
TraceAccordion.contextTypes = {
+ fullData: PropTypes.array,
data: PropTypes.array,
};
@@ -53,6 +111,7 @@ TraceAccordion.propTypes = {
localize: PropTypes.func,
children: PropTypes.node,
canAdd: PropTypes.bool,
+ canGroup: PropTypes.bool,
messageIfEmptyFold: PropTypes.string,
};
diff --git a/src/components/containers/__tests__/Fold-test.js b/src/components/containers/__tests__/Fold-test.js
index 2fcfe062c..753c9b4eb 100644
--- a/src/components/containers/__tests__/Fold-test.js
+++ b/src/components/containers/__tests__/Fold-test.js
@@ -11,7 +11,7 @@ describe('', () => {
const withoutDelete = mount(
-
+
@@ -22,7 +22,7 @@ describe('', () => {
const withDelete = mount(
-
+
@@ -36,7 +36,7 @@ describe('', () => {
mount(
-
+
diff --git a/src/components/containers/__tests__/Layout-test.js b/src/components/containers/__tests__/Layout-test.js
index a71b87682..e1b6512be 100644
--- a/src/components/containers/__tests__/Layout-test.js
+++ b/src/components/containers/__tests__/Layout-test.js
@@ -15,7 +15,7 @@ Layouts.forEach(Layout => {
const wrapper = mount(
-
+
@@ -35,7 +35,7 @@ Layouts.forEach(Layout => {
{...fixtures.scatter({layout: {width: 100}})}
>
-
+
diff --git a/src/components/containers/__tests__/Section-test.js b/src/components/containers/__tests__/Section-test.js
index bb05d54ef..d95300503 100644
--- a/src/components/containers/__tests__/Section-test.js
+++ b/src/components/containers/__tests__/Section-test.js
@@ -14,7 +14,7 @@ describe('Section', () => {
// mode is visible with scatter. Hole is not visible. Section should show.
const wrapper = mount(
-
+
{
// pull and hole are not scatter attrs. Section should not show.
const wrapper = mount(
-
-
-
+
+
+
)
@@ -85,8 +85,8 @@ describe('Section', () => {
const TraceSection = connectTraceToPlot(Section);
const wrapper = mount(
-
-
+
+
INFO
@@ -106,8 +106,8 @@ describe('Section', () => {
const TraceSection = connectTraceToPlot(Section);
const wrapper = mount(
-
-
+
+
INFO
@@ -123,8 +123,8 @@ describe('Section', () => {
const TraceSection = connectTraceToPlot(Section);
const wrapper = mount(
-
-
+
+
INFO
@@ -141,7 +141,7 @@ describe('TraceTypeSection', () => {
{
{
const wrapper = mount(
-
+
@@ -28,7 +28,7 @@ describe('CanvasSize', () => {
const wrapper = mount(
-
+
diff --git a/src/components/fields/__tests__/DataSelector-test.js b/src/components/fields/__tests__/DataSelector-test.js
index 6be9e79f5..805a293d6 100644
--- a/src/components/fields/__tests__/DataSelector-test.js
+++ b/src/components/fields/__tests__/DataSelector-test.js
@@ -16,7 +16,6 @@ function render(overrides = {}, children) {
{children}
)
- .find(`[traceIndex=1]`)
.find(`[attr="${attr}"]`)
.last();
}
@@ -64,7 +63,7 @@ describe('DataSelector', () => {
const wrapper = render(
{},
diff --git a/src/components/fields/__tests__/Radio-test.js b/src/components/fields/__tests__/Radio-test.js
index bb4018bde..e87b6b660 100644
--- a/src/components/fields/__tests__/Radio-test.js
+++ b/src/components/fields/__tests__/Radio-test.js
@@ -12,7 +12,7 @@ describe('', () => {
it('enables centering by default', () => {
const wrapper = mount(
-
+
', () => {
it('permits centering to be disabled', () => {
const wrapper = mount(
-
+
{
};
const wrapper = mount(
-
+
@@ -37,7 +37,7 @@ describe('TraceSelector', () => {
};
const wrapper = mount(
-
+
@@ -59,7 +59,7 @@ describe('TraceSelector', () => {
const wrapper = mount(
-
+
@@ -77,7 +77,7 @@ describe('TraceSelector', () => {
};
const wrapper = mount(
-
+
@@ -95,7 +95,7 @@ describe('TraceSelector', () => {
};
const wrapper = mount(
-
+
@@ -113,7 +113,7 @@ describe('TraceSelector', () => {
};
const wrapper = mount(
-
+
@@ -133,7 +133,7 @@ describe('TraceSelector', () => {
};
const wrapper = mount(
-
+
@@ -159,7 +159,7 @@ describe('TraceSelector', () => {
};
const wrapper = mount(
-
+
diff --git a/src/default_panels/StyleColorbarsPanel.js b/src/default_panels/StyleColorbarsPanel.js
index 5f3736315..311e97b92 100644
--- a/src/default_panels/StyleColorbarsPanel.js
+++ b/src/default_panels/StyleColorbarsPanel.js
@@ -18,7 +18,7 @@ import {
import {localize} from '../lib';
const StyleColorBarsPanel = ({localize: _}) => (
-
+
(
-
+
{
const wrapper = mount(
-
+
@@ -37,7 +37,7 @@ Layouts.forEach(Layout => {
{...fixtures.scatter({layout: {width: 100}})}
>
-
+
@@ -60,7 +60,7 @@ Layouts.forEach(Layout => {
{...fixtures.scatter({layout: {showlegend: true}})}
>
-
+
diff --git a/src/lib/__tests__/connectToContainer-test.js b/src/lib/__tests__/connectToContainer-test.js
index c56743294..30a54b110 100644
--- a/src/lib/__tests__/connectToContainer-test.js
+++ b/src/lib/__tests__/connectToContainer-test.js
@@ -20,7 +20,7 @@ describe('connectToContainer', () => {
const numeric = mount(
-
+
).find(Numeric);
diff --git a/src/lib/__tests__/connectTraceToPlot-test.js b/src/lib/__tests__/connectTraceToPlot-test.js
index 79236de8a..b38cf6719 100644
--- a/src/lib/__tests__/connectTraceToPlot-test.js
+++ b/src/lib/__tests__/connectTraceToPlot-test.js
@@ -19,7 +19,7 @@ Traces.forEach(Trace => {
const wrapper = mount(
-
+
@@ -36,7 +36,7 @@ Traces.forEach(Trace => {
const wrapper = mount(
-
+
@@ -58,7 +58,7 @@ Traces.forEach(Trace => {
const wrapper = mount(
-
+
@@ -76,7 +76,7 @@ Traces.forEach(Trace => {
const wrapper = mount(
-
+
)
diff --git a/src/lib/__tests__/nestedContainerConnections-test.js b/src/lib/__tests__/nestedContainerConnections-test.js
index 24d6425b0..221956fd0 100644
--- a/src/lib/__tests__/nestedContainerConnections-test.js
+++ b/src/lib/__tests__/nestedContainerConnections-test.js
@@ -41,7 +41,7 @@ describe('Plot Connection', () => {
);
mount(
-
+
)
.find('[attr="width"]')
@@ -70,7 +70,11 @@ describe('Plot Connection', () => {
const wrapper = mount(
)
@@ -100,9 +104,13 @@ describe('Plot Connection', () => {
mount(
-
+
@@ -139,9 +147,9 @@ describe('Plot Connection', () => {
const wrapper = mount(
-
+
diff --git a/src/lib/connectTraceToPlot.js b/src/lib/connectTraceToPlot.js
index 423c7f6e0..43050c3c2 100644
--- a/src/lib/connectTraceToPlot.js
+++ b/src/lib/connectTraceToPlot.js
@@ -24,11 +24,14 @@ export default function connectTraceToPlot(WrappedComponent) {
}
setLocals(props, context) {
- const {traceIndex} = props;
+ const {traceIndexes} = props;
const {data, fullData, plotly} = context;
- const trace = data[traceIndex] || {};
- const fullTraceIndex = findFullTraceIndex(fullData, traceIndex);
+ const trace = traceIndexes.length > 0 ? data[traceIndexes[0]] : {};
+ const fullTraceIndex =
+ traceIndexes.length > 0
+ ? findFullTraceIndex(fullData, traceIndexes[0])
+ : findFullTraceIndex(fullData, 0);
const fullTrace = fullData[fullTraceIndex] || {};
let getValObject;
@@ -53,12 +56,17 @@ export default function connectTraceToPlot(WrappedComponent) {
container: trace,
fullContainer: fullTrace,
};
- this.icon = renderTraceIcon(plotlyTraceToCustomTrace(trace));
- this.name = fullTrace.name;
- const DEFAULT_FIN_CHART_TRACE_NAME = ' - increasing';
- if (fullTrace.name.indexOf(DEFAULT_FIN_CHART_TRACE_NAME) && !trace.name) {
- this.name = fullTrace.name.replace(DEFAULT_FIN_CHART_TRACE_NAME, '');
+ if (trace && fullTrace) {
+ this.icon = renderTraceIcon(plotlyTraceToCustomTrace(trace));
+ this.name = fullTrace.name;
+ const DEFAULT_FIN_CHART_TRACE_NAME = ' - increasing';
+ if (
+ fullTrace.name.indexOf(DEFAULT_FIN_CHART_TRACE_NAME) &&
+ !trace.name
+ ) {
+ this.name = fullTrace.name.replace(DEFAULT_FIN_CHART_TRACE_NAME, '');
+ }
}
}
@@ -72,7 +80,7 @@ export default function connectTraceToPlot(WrappedComponent) {
type: EDITOR_ACTIONS.UPDATE_TRACES,
payload: {
update,
- traceIndexes: [this.props.traceIndex],
+ traceIndexes: this.props.traceIndexes,
},
});
}
@@ -82,7 +90,7 @@ export default function connectTraceToPlot(WrappedComponent) {
if (this.context.onUpdate) {
this.context.onUpdate({
type: EDITOR_ACTIONS.DELETE_TRACE,
- payload: {traceIndexes: [this.props.traceIndex]},
+ payload: {traceIndexes: this.props.traceIndexes},
});
}
}
@@ -99,7 +107,7 @@ export default function connectTraceToPlot(WrappedComponent) {
)}`;
TraceConnectedComponent.propTypes = {
- traceIndex: PropTypes.number.isRequired,
+ traceIndexes: PropTypes.arrayOf(PropTypes.number).isRequired,
};
TraceConnectedComponent.contextTypes = {
diff --git a/src/styles/components/containers/_fold.scss b/src/styles/components/containers/_fold.scss
index 6745c9e92..602eaacba 100644
--- a/src/styles/components/containers/_fold.scss
+++ b/src/styles/components/containers/_fold.scss
@@ -150,7 +150,6 @@
font-family: var(--font-family-body);
font-size: var(--font-size-small);
text-align: center;
- font-size: 13px;
color: var(--color-text-base);
}
}
@@ -159,12 +158,6 @@
border-width: 1px 1px 1px 1px;
}
}
-
- .panel {
- background-color: var(--fold-background);
- border-right: none;
- width: 100%;
- }
}
.fold + .fold {
diff --git a/src/styles/components/containers/_main.scss b/src/styles/components/containers/_main.scss
index 93140140e..fde545d50 100644
--- a/src/styles/components/containers/_main.scss
+++ b/src/styles/components/containers/_main.scss
@@ -4,3 +4,4 @@
@import "menupanel";
@import "info";
@import "modalbox";
+@import "tabs";
diff --git a/src/styles/components/containers/_panel.scss b/src/styles/components/containers/_panel.scss
index 0bc1880e4..14b8221fb 100644
--- a/src/styles/components/containers/_panel.scss
+++ b/src/styles/components/containers/_panel.scss
@@ -1,17 +1,30 @@
.panel {
flex-grow: 1;
- flex-shrink: 0;
- background-color: var(--panel-background);
+ overflow-x: hidden;
overflow-y: auto;
padding: var(--spacing-half-unit);
- border-right: var(--border-default);
box-sizing: border-box;
position: relative;
- width: calc(var(--panel-width));
+ display: flex;
+ flex-direction: column;
+ width: 100%;
@include scrollbar();
+
+ @at-root .plotly-editor__wrapper > .panel {
+ // These are for the first panel
+ background-color: var(--panel-background);
+ border-right: var(--border-default);
+ width: calc(var(--panel-width));
+ }
+ &__content {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ }
&__header {
margin-bottom: var(--spacing-half-unit);
display: flex;
+ flex-shrink: 0;
&__content {
flex-grow: 1;
}
@@ -75,4 +88,7 @@
}
}
}
+ &--no-padding {
+ padding: 0;
+ }
}
diff --git a/src/styles/components/containers/_tabs.scss b/src/styles/components/containers/_tabs.scss
new file mode 100644
index 000000000..aafecdc1e
--- /dev/null
+++ b/src/styles/components/containers/_tabs.scss
@@ -0,0 +1,86 @@
+.panel {
+ .react-tabs {
+ $tab-bar-height: 32px;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ &__tab {
+ &-list {
+ background: var(--color-background-medium);
+ margin: 0;
+ flex-shrink:0;
+ list-style: none;
+ display: flex;
+ align-items: flex-end;
+ padding-top: var(--spacing-half-unit);
+ padding-left: var(--spacing-half-unit);
+ padding-right: var(--spacing-half-unit);
+ padding-bottom: 0;
+ height: $tab-bar-height;
+ }
+ // Tab Styles
+ flex-grow: 1;
+ flex-shrink:0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing-quarter-unit);
+ color: var(--color-text-base);
+ font-size: var(--font-size-base);
+ background: var(--color-background-medium);
+ border: var(--border-default);
+ border-bottom: 0;
+ position: relative;
+ background: var(--color-background-light);
+ transition: border-color 0.15s ease-in-out;
+
+ &:first-of-type {
+ border-top-left-radius: var(--border-radius);
+ }
+ &:last-of-type {
+ border-top-right-radius: var(--border-radius);
+ }
+
+
+ &:hover {
+ background-color: var(--color-background-base);
+ cursor: pointer;
+ }
+
+ &--selected {
+ background-color: var(--color-background-base);
+ pointer-events: none;
+ margin-top: 0;
+ color: var(--color-text-active);
+ border-top-color: var(--color-accent);
+ border-top-width: 2px;
+
+ &::before {
+ position: absolute;
+ top: 100%;
+ width: 100%;
+ height: 1px;
+ content: '';
+ background-color: var(--color-background-base);
+ left: 0;
+ z-index: 4;
+ }
+ }
+ &:not(:first-of-type):not(:last-of-type) {
+ border-left: 0;
+ }
+ &:last-of-type {
+ border-left: none;
+ }
+ &-panel {
+ border-top: var(--border-default);
+ display: none;
+ &--selected {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ }
+ }
+ }
+ }
+}
diff --git a/src/styles/components/widgets/_radio-block.scss b/src/styles/components/widgets/_radio-block.scss
index 9c4825ef7..762ee0af8 100644
--- a/src/styles/components/widgets/_radio-block.scss
+++ b/src/styles/components/widgets/_radio-block.scss
@@ -1,7 +1,9 @@
.radio-block {
width: 100%;
line-height: var(--font-leading-head);
+ display: flex;
&__option {
+ flex-grow: 1;
padding: var(--spacing-quarter-unit) var(--spacing-half-unit);
background-color: var(--color-background-top);
border: var(--border-default);
diff --git a/src/styles/variables/_layout.scss b/src/styles/variables/_layout.scss
index 811645680..8d03afacf 100644
--- a/src/styles/variables/_layout.scss
+++ b/src/styles/variables/_layout.scss
@@ -2,4 +2,4 @@
* Layout
*/
$layout-panel-width: 345px;
-$layout-sidebar-width: 100px;
+$layout-sidebar-width: 120px;