Skip to content

Commit d0d8adb

Browse files
authored
Merge pull request #1763 from workaholicpanda/dev
Shorthand supports for dash-core-components
2 parents 17ca5c0 + 3489641 commit d0d8adb

25 files changed

+1127
-217
lines changed

CHANGELOG.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,143 @@
22
All notable changes to `dash` will be documented in this file.
33
This project adheres to [Semantic Versioning](https://semver.org/).
44

5+
## [Unreleased]
6+
7+
- [#1763](https://github.com/plotly/dash/pull/1763):
8+
## Dash and Dash Renderer
9+
10+
- `Input`, `State`, and `Output` now accept components instead of ID strings and Dash `callback` will auto-generate the component's ID under-the-hood if not supplied. This allows usage like:
11+
12+
```python
13+
my_input = dcc.Input()
14+
my_output = html.Div()
15+
app.layout = html.Div([my_input, my_output])
16+
17+
@dash.callback(Output(my_output, 'children'), Input(my_input, 'value'))
18+
def update(value):
19+
return f'You have entered {value}'
20+
```
21+
22+
Or, if using Python >=3.8 you can use the `:=` walrus operator:
23+
```python
24+
app.layout = html.Div([
25+
my_input := dcc.Input(),
26+
my_output := html.Div()
27+
])
28+
29+
@dash.callback(Output(my_output, 'children'), Input(my_input, 'value'))
30+
def update(value):
31+
return f'You have entered {value}'
32+
33+
```
34+
## Dash Core Components
35+
36+
### Rearranged Keyword Arguments & Flexible Types
37+
**`Dropdown`, `RadioItem`, and `Checklist`**
38+
- Rearranged Keyword Arguments - `options` & `value` are now the first two keywords which means they can be supplied as positional arguments without the keyword. Supplying the keywords (`options=` and `value=`) is still supported.
39+
- Flexible Types - `options` can be supplied in two new forms:
40+
1. An array of `string|number|bool` where `label` and `value` are equal to the items in the list.
41+
2. A dictionary where the keys and values set as `value` and `label` respectively.
42+
43+
Before:
44+
45+
```python
46+
dcc.Dropdown(
47+
options=[
48+
{'label': 'New York', 'value': 'New York'},
49+
{'label': 'Montreal', 'value': 'Montreal'},
50+
],
51+
value='New York'
52+
)
53+
```
54+
or
55+
56+
```python
57+
dcc.Dropdown(
58+
options=[
59+
{'label': 'New York', 'value': 'NYC'},
60+
{'label': 'Montreal', 'value': 'MTL'},
61+
],
62+
value='New York'
63+
)
64+
```
65+
66+
After:
67+
68+
```python
69+
dcc.Dropdown(['New York', 'Montreal'], 'New York')
70+
```
71+
Or
72+
73+
```python
74+
dcc.Dropdown({'NYC': 'New York', 'MTL': 'Montreal'}, 'New York')
75+
```
76+
77+
**`RangeSlider` & `Slider`**
78+
- Rearranged Keyword Arugments - `min`, `max`, and `step` are now the first three keyword arguments which means they can be supplied as positional arguments without the keyword.
79+
- Flexible Types
80+
- `step` will be calculated implicitly if not given.
81+
- `marks` will be auto generated if not given. It will use `min` and `max` and will respect `step` if supplied. Auto generated marks labels are SI unit formatted. Around 5 human-readable marks will be created.
82+
- To remove the Slider's marks, set `marks=None`.
83+
84+
Before:
85+
86+
```python
87+
dcc.Slider(marks={1: 2, 2: 2, 3: 3})
88+
```
89+
90+
After:
91+
```python
92+
dcc.Slider(min=1, max=3, step=1)
93+
```
94+
Or equivalently:
95+
```python
96+
dcc.Slider(1, 3, 1)
97+
```
98+
Step can also be omitted and the `Slider` will attempt to create a nice, human readable step with SI units and around 5 marks:
99+
```python
100+
dcc.Slider(0, 100)
101+
```
102+
103+
The SI units and ranges supported in `marks` are:
104+
* `µ` - micro, 10⁻⁶
105+
* `m` - milli, 10⁻³
106+
* `​` (none) - 10⁰
107+
* `k` - kilo, 10³
108+
* `M` - mega, 10⁶
109+
* `G` - giga, 10⁹
110+
* `T` - tera, 10¹²
111+
* `P` - peta, 10¹⁵
112+
* `E` - exa, 10¹⁸
113+
114+
_Ranges below 10µ are not supported by the Slider. This is a bug: https://github.com/plotly/dash/issues/1766_
115+
116+
**`DataTable`**
117+
118+
- Rearranged Keyword Arguments - `data` and `columns` the first twokeyword arguments which means they can be supplied as positional arguments without the keyword.
119+
- Inferred Properties - If `columns` isn't supplied then it is extracted from the the first row in `data`
120+
121+
Before:
122+
123+
```python
124+
dash_table.DataTable(data=df.to_dict('records'), columns=[{'name': i, 'id': i} for i in df.columns])
125+
```
126+
After:
127+
128+
```python
129+
dash_table.DataTable(data=df.to_dict('records'))
130+
```
131+
132+
### New Component Properties
133+
134+
**`Checklist` & `RadioItems`**
135+
136+
- A new property `inline` appends `display: inline-block` to `labelStyle`.
137+
138+
```python
139+
dcc.Checklist(inline=True)
140+
```
141+
5142
## [2.0.0] - 2021-08-03
6143

7144
## Dash and Dash Renderer

components/dash-core-components/src/components/Checklist.react.js

Lines changed: 114 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import PropTypes from 'prop-types';
22
import {append, includes, without} from 'ramda';
33
import React, {Component} from 'react';
4+
import {sanitizeOptions} from '../utils/optionTypes';
45

56
/**
67
* Checklist is a component that encapsulates several checkboxes.
@@ -22,8 +23,8 @@ export default class Checklist extends Component {
2223
style,
2324
loading_state,
2425
value,
26+
inline,
2527
} = this.props;
26-
2728
return (
2829
<div
2930
data-dash-is-loading={
@@ -33,77 +34,126 @@ export default class Checklist extends Component {
3334
style={style}
3435
className={className}
3536
>
36-
{options.map(option => (
37-
<label
38-
key={option.value}
39-
style={labelStyle}
40-
className={labelClassName}
41-
>
42-
<input
43-
checked={includes(option.value, value)}
44-
className={inputClassName}
45-
disabled={Boolean(option.disabled)}
46-
style={inputStyle}
47-
type="checkbox"
48-
onChange={() => {
49-
let newValue;
50-
if (includes(option.value, value)) {
51-
newValue = without([option.value], value);
52-
} else {
53-
newValue = append(option.value, value);
54-
}
55-
setProps({value: newValue});
56-
}}
57-
/>
58-
{option.label}
59-
</label>
60-
))}
37+
{sanitizeOptions(options).map(option => {
38+
return (
39+
<label
40+
key={option.value}
41+
style={Object.assign(
42+
{},
43+
labelStyle,
44+
inline ? {display: 'inline-block'} : {}
45+
)}
46+
className={labelClassName}
47+
>
48+
<input
49+
checked={includes(option.value, value)}
50+
className={inputClassName}
51+
disabled={Boolean(option.disabled)}
52+
style={inputStyle}
53+
type="checkbox"
54+
onChange={() => {
55+
let newValue;
56+
if (includes(option.value, value)) {
57+
newValue = without(
58+
[option.value],
59+
value
60+
);
61+
} else {
62+
newValue = append(option.value, value);
63+
}
64+
setProps({value: newValue});
65+
}}
66+
/>
67+
{option.label}
68+
</label>
69+
);
70+
})}
6171
</div>
6272
);
6373
}
6474
}
6575

6676
Checklist.propTypes = {
67-
/**
68-
* The ID of this component, used to identify dash components
69-
* in callbacks. The ID needs to be unique across all of the
70-
* components in an app.
71-
*/
72-
id: PropTypes.string,
73-
7477
/**
7578
* An array of options
7679
*/
77-
options: PropTypes.arrayOf(
78-
PropTypes.exact({
79-
/**
80-
* The checkbox's label
81-
*/
82-
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
83-
.isRequired,
84-
85-
/**
86-
* The value of the checkbox. This value
87-
* corresponds to the items specified in the
88-
* `value` property.
89-
*/
90-
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
91-
.isRequired,
92-
93-
/**
94-
* If true, this checkbox is disabled and can't be clicked on.
95-
*/
96-
disabled: PropTypes.bool,
97-
})
98-
),
80+
options: PropTypes.oneOfType([
81+
/**
82+
* Array of options where the label and the value are the same thing - [string|number|bool]
83+
*/
84+
PropTypes.arrayOf(
85+
PropTypes.oneOfType([
86+
PropTypes.string,
87+
PropTypes.number,
88+
PropTypes.bool,
89+
])
90+
),
91+
/**
92+
* Simpler `options` representation in dictionary format. The order is not guaranteed.
93+
* {`value1`: `label1`, `value2`: `label2`, ... }
94+
* which is equal to
95+
* [{label: `label1`, value: `value1`}, {label: `label2`, value: `value2`}, ...]
96+
*/
97+
PropTypes.object,
98+
/**
99+
* An array of options {label: [string|number], value: [string|number]},
100+
* an optional disabled field can be used for each option
101+
*/
102+
PropTypes.arrayOf(
103+
PropTypes.exact({
104+
/**
105+
* The option's label
106+
*/
107+
label: PropTypes.oneOfType([
108+
PropTypes.string,
109+
PropTypes.number,
110+
PropTypes.bool,
111+
]).isRequired,
112+
113+
/**
114+
* The value of the option. This value
115+
* corresponds to the items specified in the
116+
* `value` property.
117+
*/
118+
value: PropTypes.oneOfType([
119+
PropTypes.string,
120+
PropTypes.number,
121+
PropTypes.bool,
122+
]).isRequired,
123+
124+
/**
125+
* If true, this option is disabled and cannot be selected.
126+
*/
127+
disabled: PropTypes.bool,
128+
129+
/**
130+
* The HTML 'title' attribute for the option. Allows for
131+
* information on hover. For more information on this attribute,
132+
* see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title
133+
*/
134+
title: PropTypes.string,
135+
})
136+
),
137+
]),
99138

100139
/**
101140
* The currently selected value
102141
*/
103142
value: PropTypes.arrayOf(
104-
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
143+
PropTypes.oneOfType([
144+
PropTypes.string,
145+
PropTypes.number,
146+
PropTypes.bool,
147+
])
105148
),
106149

150+
/**
151+
* The ID of this component, used to identify dash components
152+
* in callbacks. The ID needs to be unique across all of the
153+
* components in an app.
154+
*/
155+
id: PropTypes.string,
156+
107157
/**
108158
* The class of the container (div)
109159
*/
@@ -187,6 +237,13 @@ Checklist.propTypes = {
187237
* session: window.sessionStorage, data is cleared once the browser quit.
188238
*/
189239
persistence_type: PropTypes.oneOf(['local', 'session', 'memory']),
240+
241+
/**
242+
* Indicates whether labelStyle should be inline or not
243+
* True: Automatically set { 'display': 'inline-block' } to labelStyle
244+
* False: No additional styles are passed into labelStyle.
245+
*/
246+
inline: PropTypes.bool,
190247
};
191248

192249
Checklist.defaultProps = {
@@ -198,4 +255,5 @@ Checklist.defaultProps = {
198255
value: [],
199256
persisted_props: ['value'],
200257
persistence_type: 'local',
258+
inline: false,
201259
};

0 commit comments

Comments
 (0)