Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit 9683135

Browse files
committed
first pass at a Tabs component
1 parent 85a7573 commit 9683135

File tree

6 files changed

+245
-4
lines changed

6 files changed

+245
-4
lines changed

dash_core_components/__init__.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import sys as _sys
44
from .version import __version__
55

6+
npm_package_version = '0.13.0-rc8'
7+
68
_current_path = _os.path.dirname(_os.path.abspath(__file__))
79

810
_components = _dash.development.component_loader.load_components(
@@ -21,9 +23,9 @@
2123
{
2224
"relative_package_path": "bundle.js",
2325
"external_url": (
24-
"https://unpkg.com/dash-core-components@0.13.0-rc3"
26+
"https://unpkg.com/dash-core-components@{}"
2527
"/dash_core_components/bundle.js"
26-
),
28+
).format(npm_package_version),
2729
"namespace": "dash_core_components"
2830
}
2931
]
@@ -42,7 +44,7 @@
4244
"https://unpkg.com/[email protected]/styles.css",
4345
"https://unpkg.com/[email protected]/styles.css",
4446
"https://unpkg.com/[email protected]/assets/index.css",
45-
"https://unpkg.com/dash-core-components@{}/dash_core_components/[email protected]".format(__version__)
47+
"https://unpkg.com/dash-core-components@{}/dash_core_components/[email protected]".format(npm_package_version)
4648
],
4749
"namespace": "dash_core_components"
4850
}

dash_core_components/metadata.json

+60
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,66 @@
23452345
}
23462346
}
23472347
},
2348+
"src/components/Tabs.react.js": {
2349+
"description": "",
2350+
"methods": [],
2351+
"props": {
2352+
"id": {
2353+
"type": {
2354+
"name": "string"
2355+
},
2356+
"required": false,
2357+
"description": ""
2358+
},
2359+
"style": {
2360+
"type": {
2361+
"name": "object"
2362+
},
2363+
"required": false,
2364+
"description": "Style object to be merged in with the parent level tabs"
2365+
},
2366+
"tabs": {
2367+
"type": {
2368+
"name": "arrayOf",
2369+
"value": {
2370+
"name": "shape",
2371+
"value": {
2372+
"label": {
2373+
"name": "string",
2374+
"description": "The checkbox's label",
2375+
"required": false
2376+
},
2377+
"value": {
2378+
"name": "string",
2379+
"description": "The value of the checkbox. This value\ncorresponds to the items specified in the\n`values` property.",
2380+
"required": false
2381+
}
2382+
}
2383+
}
2384+
},
2385+
"required": false,
2386+
"description": "An array of options"
2387+
},
2388+
"value": {
2389+
"type": {
2390+
"name": "string"
2391+
},
2392+
"required": false,
2393+
"description": "The currently selected tab"
2394+
},
2395+
"vertical": {
2396+
"type": {
2397+
"name": "bool"
2398+
},
2399+
"required": false,
2400+
"description": "Whether or not the tabs are rendered vertically",
2401+
"defaultValue": {
2402+
"value": "false",
2403+
"computed": false
2404+
}
2405+
}
2406+
}
2407+
},
23482408
"src/components/Textarea.react.js": {
23492409
"description": "A basic HTML textarea for entering multiline text.",
23502410
"methods": [],

images/tabs.gif

285 KB
Loading

src/components/Tabs.react.js

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import R from 'ramda';
2+
import React, {PropTypes} from 'react';
3+
4+
const STYLES = {
5+
border: '1px lightgrey solid'
6+
};
7+
8+
function Tab(props) {
9+
let style = {
10+
'borderLeft': STYLES.border,
11+
12+
'position': 'relative',
13+
'paddingTop': 10,
14+
'paddingBottom': 10,
15+
'cursor': props.isSelected ? 'default' : 'pointer',
16+
'boxSizing': 'border-box',
17+
'backgroundColor': props.isSelected ? 'white' : 'rgb(253, 253, 253)'
18+
};
19+
20+
if (props.vertical) {
21+
style = R.merge(style, {
22+
'display': 'block',
23+
'borderTop': STYLES.border,
24+
'borderBottom': props.isLast ? STYLES.border : null,
25+
'borderLeft': props.isSelected ? 'rgb(68, 126, 255) 2px solid': STYLES.border,
26+
'textAlign': 'left',
27+
'paddingLeft': '5px'
28+
});
29+
} else {
30+
style = R.merge(style, {
31+
'display': 'inline-block',
32+
'borderRight': props.isLast ? STYLES.border : null,
33+
'borderTopLeftRadius': props.isFirst ? 2 : 0,
34+
'borderTopRightRadius': props.isLast ? 2 : 0,
35+
'borderTop': props.isSelected ? 'rgb(68, 126, 255) 2px solid' : STYLES.border,
36+
'width': `calc(100% / ${props.nTabs})`,
37+
'textAlign': 'center',
38+
'paddingLeft': 20,
39+
'paddingRight': 20
40+
});
41+
}
42+
43+
return (
44+
<div style={style} onClick={props.onClick} key={props.value}>
45+
{props.label}
46+
47+
{props.isSelected && !props.vertical ? <div style={{
48+
'position': 'absolute',
49+
'display': 'block',
50+
'content': '',
51+
'bottom': '-1px',
52+
'height': '1px',
53+
'left': 0,
54+
'right': 0,
55+
'background-color': 'white'
56+
}}/> : null}
57+
58+
{props.isSelected && props.vertical ? <div style={{
59+
'position': 'absolute',
60+
'display': 'block',
61+
'content': '',
62+
'height': '100%',
63+
'width': '1px',
64+
'right': '-1px',
65+
'top': '0px',
66+
'background-color': 'white'
67+
}}/> : null}
68+
69+
</div>
70+
)
71+
}
72+
73+
74+
function Tabs(props) {
75+
return (
76+
<div>
77+
<div style={R.merge({
78+
'borderBottom': props.vertical ? null : STYLES.border,
79+
'borderRight': props.vertical ? STYLES.border : null,
80+
'boxSizing': 'border-box'
81+
}, props.style)}>
82+
{props.tabs.map((t, i) => {
83+
return Tab(R.merge(t, {
84+
isLast: i === props.tabs.length - 1,
85+
isFirst: i === 0,
86+
onClick: () => props.setProps({value: t.value}),
87+
isSelected: t.value === props.value,
88+
nTabs: props.tabs.length,
89+
vertical: props.vertical
90+
}));
91+
})}
92+
</div>
93+
</div>
94+
);
95+
}
96+
97+
98+
Tabs.propTypes = {
99+
id: PropTypes.string,
100+
101+
/**
102+
* Style object to be merged in with the parent level tabs
103+
*/
104+
style: PropTypes.object,
105+
106+
/**
107+
* An array of options
108+
*/
109+
tabs: PropTypes.arrayOf(PropTypes.shape({
110+
/**
111+
* The checkbox's label
112+
*/
113+
label: PropTypes.string,
114+
115+
/**
116+
* The value of the checkbox. This value
117+
* corresponds to the items specified in the
118+
* `values` property.
119+
*/
120+
value: PropTypes.string
121+
})),
122+
123+
/**
124+
* The currently selected tab
125+
*/
126+
value: PropTypes.string,
127+
128+
/**
129+
* Whether or not the tabs are rendered vertically
130+
*/
131+
vertical: PropTypes.bool
132+
}
133+
134+
Tabs.defaultProps = {
135+
vertical: false
136+
}
137+
138+
export default Tabs;

src/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Textarea from './components/Textarea.react';
1515
import DatePickerSingle from './components/DatePickerSingle.react';
1616
import DatePickerRange from './components/DatePickerRange.react';
1717
import Upload from './components/Upload.react';
18+
import Tabs from './components/Tabs.react';
1819

1920
export {
2021
Checklist,
@@ -32,5 +33,6 @@ export {
3233
Textarea,
3334
DatePickerSingle,
3435
DatePickerRange,
35-
Upload
36+
Upload,
37+
Tabs
3638
};

test/test_integration.py

+39
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,45 @@ def test_gallery(self):
203203
html.Div(id='waitfor'),
204204
html.Label('Upload'),
205205
dcc.Upload(),
206+
207+
html.Label('Horizontal Tabs'),
208+
html.Div([
209+
dcc.Tabs(
210+
tabs=[
211+
{'label': 'Market Value', 'value': 1},
212+
{'label': 'Usage Over Time', 'value': 2},
213+
{'label': 'Predictions', 'value': 3},
214+
{'label': 'Target Pricing', 'value': 4},
215+
],
216+
value=3,
217+
id='tabs',
218+
vertical=vertical
219+
),
220+
html.Div(id='tab-output')
221+
], style={
222+
'width': '80%',
223+
'fontFamily': 'Sans-Serif',
224+
'margin-left': 'auto',
225+
'margin-right': 'auto'
226+
}),
227+
228+
html.Label('Vertical Tabs'),
229+
dcc.Tabs(
230+
tabs=[
231+
{'label': 'Market Value', 'value': 1},
232+
{'label': 'Usage Over Time', 'value': 2},
233+
{'label': 'Predictions', 'value': 3},
234+
{'label': 'Target Pricing', 'value': 4},
235+
],
236+
value=3,
237+
id='tabs',
238+
vertical=vertical,
239+
style={
240+
'borderRight': 'thin lightgrey solid',
241+
'textAlign': 'left'
242+
}
243+
),
244+
206245
html.Label('Dropdown'),
207246
dcc.Dropdown(
208247
options=[

0 commit comments

Comments
 (0)