diff --git a/CHANGELOG.md b/CHANGELOG.md index 967700d49a..b41c37c8e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,143 @@ All notable changes to `dash` will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [Unreleased] + +- [#1763](https://github.com/plotly/dash/pull/1763): + ## Dash and Dash Renderer + + - `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: + + ```python + my_input = dcc.Input() + my_output = html.Div() + app.layout = html.Div([my_input, my_output]) + + @dash.callback(Output(my_output, 'children'), Input(my_input, 'value')) + def update(value): + return f'You have entered {value}' + ``` + + Or, if using Python >=3.8 you can use the `:=` walrus operator: + ```python + app.layout = html.Div([ + my_input := dcc.Input(), + my_output := html.Div() + ]) + + @dash.callback(Output(my_output, 'children'), Input(my_input, 'value')) + def update(value): + return f'You have entered {value}' + + ``` + ## Dash Core Components + + ### Rearranged Keyword Arguments & Flexible Types + **`Dropdown`, `RadioItem`, and `Checklist`** + - 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. + - Flexible Types - `options` can be supplied in two new forms: + 1. An array of `string|number|bool` where `label` and `value` are equal to the items in the list. + 2. A dictionary where the keys and values set as `value` and `label` respectively. + + Before: + + ```python + dcc.Dropdown( + options=[ + {'label': 'New York', 'value': 'New York'}, + {'label': 'Montreal', 'value': 'Montreal'}, + ], + value='New York' + ) + ``` + or + + ```python + dcc.Dropdown( + options=[ + {'label': 'New York', 'value': 'NYC'}, + {'label': 'Montreal', 'value': 'MTL'}, + ], + value='New York' + ) + ``` + + After: + + ```python + dcc.Dropdown(['New York', 'Montreal'], 'New York') + ``` + Or + + ```python + dcc.Dropdown({'NYC': 'New York', 'MTL': 'Montreal'}, 'New York') + ``` + + **`RangeSlider` & `Slider`** + - 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. + - Flexible Types + - `step` will be calculated implicitly if not given. + - `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. + - To remove the Slider's marks, set `marks=None`. + + Before: + + ```python + dcc.Slider(marks={1: 2, 2: 2, 3: 3}) + ``` + + After: + ```python + dcc.Slider(min=1, max=3, step=1) + ``` + Or equivalently: + ```python + dcc.Slider(1, 3, 1) + ``` + Step can also be omitted and the `Slider` will attempt to create a nice, human readable step with SI units and around 5 marks: + ```python + dcc.Slider(0, 100) + ``` + + The SI units and ranges supported in `marks` are: + * `µ` - micro, 10⁻⁶ + * `m` - milli, 10⁻³ + * `​` (none) - 10⁰ + * `k` - kilo, 10³ + * `M` - mega, 10⁶ + * `G` - giga, 10⁹ + * `T` - tera, 10¹² + * `P` - peta, 10¹⁵ + * `E` - exa, 10¹⁸ + + _Ranges below 10µ are not supported by the Slider. This is a bug: https://github.com/plotly/dash/issues/1766_ + + **`DataTable`** + + - Rearranged Keyword Arguments - `data` and `columns` the first twokeyword arguments which means they can be supplied as positional arguments without the keyword. + - Inferred Properties - If `columns` isn't supplied then it is extracted from the the first row in `data` + + Before: + + ```python + dash_table.DataTable(data=df.to_dict('records'), columns=[{'name': i, 'id': i} for i in df.columns]) + ``` + After: + + ```python + dash_table.DataTable(data=df.to_dict('records')) + ``` + + ### New Component Properties + + **`Checklist` & `RadioItems`** + + - A new property `inline` appends `display: inline-block` to `labelStyle`. + + ```python + dcc.Checklist(inline=True) + ``` + ## [2.0.0] - 2021-08-03 ## Dash and Dash Renderer diff --git a/components/dash-core-components/src/components/Checklist.react.js b/components/dash-core-components/src/components/Checklist.react.js index 22f3d68af5..fc9a207982 100644 --- a/components/dash-core-components/src/components/Checklist.react.js +++ b/components/dash-core-components/src/components/Checklist.react.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import {append, includes, without} from 'ramda'; import React, {Component} from 'react'; +import {sanitizeOptions} from '../utils/optionTypes'; /** * Checklist is a component that encapsulates several checkboxes. @@ -22,8 +23,8 @@ export default class Checklist extends Component { style, loading_state, value, + inline, } = this.props; - return (
- {options.map(option => ( - - ))} + {sanitizeOptions(options).map(option => { + return ( + + ); + })}
); } } Checklist.propTypes = { - /** - * The ID of this component, used to identify dash components - * in callbacks. The ID needs to be unique across all of the - * components in an app. - */ - id: PropTypes.string, - /** * An array of options */ - options: PropTypes.arrayOf( - PropTypes.exact({ - /** - * The checkbox's label - */ - label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - .isRequired, - - /** - * The value of the checkbox. This value - * corresponds to the items specified in the - * `value` property. - */ - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - .isRequired, - - /** - * If true, this checkbox is disabled and can't be clicked on. - */ - disabled: PropTypes.bool, - }) - ), + options: PropTypes.oneOfType([ + /** + * Array of options where the label and the value are the same thing - [string|number|bool] + */ + PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]) + ), + /** + * Simpler `options` representation in dictionary format. The order is not guaranteed. + * {`value1`: `label1`, `value2`: `label2`, ... } + * which is equal to + * [{label: `label1`, value: `value1`}, {label: `label2`, value: `value2`}, ...] + */ + PropTypes.object, + /** + * An array of options {label: [string|number], value: [string|number]}, + * an optional disabled field can be used for each option + */ + PropTypes.arrayOf( + PropTypes.exact({ + /** + * The option's label + */ + label: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]).isRequired, + + /** + * The value of the option. This value + * corresponds to the items specified in the + * `value` property. + */ + value: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]).isRequired, + + /** + * If true, this option is disabled and cannot be selected. + */ + disabled: PropTypes.bool, + + /** + * The HTML 'title' attribute for the option. Allows for + * information on hover. For more information on this attribute, + * see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title + */ + title: PropTypes.string, + }) + ), + ]), /** * The currently selected value */ value: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]) ), + /** + * The ID of this component, used to identify dash components + * in callbacks. The ID needs to be unique across all of the + * components in an app. + */ + id: PropTypes.string, + /** * The class of the container (div) */ @@ -187,6 +237,13 @@ Checklist.propTypes = { * session: window.sessionStorage, data is cleared once the browser quit. */ persistence_type: PropTypes.oneOf(['local', 'session', 'memory']), + + /** + * Indicates whether labelStyle should be inline or not + * True: Automatically set { 'display': 'inline-block' } to labelStyle + * False: No additional styles are passed into labelStyle. + */ + inline: PropTypes.bool, }; Checklist.defaultProps = { @@ -198,4 +255,5 @@ Checklist.defaultProps = { value: [], persisted_props: ['value'], persistence_type: 'local', + inline: false, }; diff --git a/components/dash-core-components/src/components/Dropdown.react.js b/components/dash-core-components/src/components/Dropdown.react.js index 604cebfe7c..f329443b8d 100644 --- a/components/dash-core-components/src/components/Dropdown.react.js +++ b/components/dash-core-components/src/components/Dropdown.react.js @@ -25,46 +25,65 @@ export default class Dropdown extends Component { } Dropdown.propTypes = { - /** - * The ID of this component, used to identify dash components - * in callbacks. The ID needs to be unique across all of the - * components in an app. - */ - id: PropTypes.string, - /** * An array of options {label: [string|number], value: [string|number]}, * an optional disabled field can be used for each option */ - options: PropTypes.arrayOf( - PropTypes.exact({ - /** - * The dropdown's label - */ - label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - .isRequired, - - /** - * The value of the dropdown. This value - * corresponds to the items specified in the - * `value` property. - */ - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - .isRequired, - - /** - * If true, this option is disabled and cannot be selected. - */ - disabled: PropTypes.bool, - - /** - * The HTML 'title' attribute for the option. Allows for - * information on hover. For more information on this attribute, - * see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title - */ - title: PropTypes.string, - }) - ), + options: PropTypes.oneOfType([ + /** + * Array of options where the label and the value are the same thing - [string|number|bool] + */ + PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]) + ), + /** + * Simpler `options` representation in dictionary format. The order is not guaranteed. + * {`value1`: `label1`, `value2`: `label2`, ... } + * which is equal to + * [{label: `label1`, value: `value1`}, {label: `label2`, value: `value2`}, ...] + */ + PropTypes.object, + /** + * An array of options {label: [string|number], value: [string|number]}, + * an optional disabled field can be used for each option + */ + PropTypes.arrayOf( + PropTypes.exact({ + /** + * The option's label + */ + label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + .isRequired, + + /** + * The value of the option. This value + * corresponds to the items specified in the + * `value` property. + */ + value: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]).isRequired, + + /** + * If true, this option is disabled and cannot be selected. + */ + disabled: PropTypes.bool, + + /** + * The HTML 'title' attribute for the option. Allows for + * information on hover. For more information on this attribute, + * see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title + */ + title: PropTypes.string, + }) + ), + ]), /** * The value of the input. If `multi` is false (the default) @@ -77,11 +96,23 @@ Dropdown.propTypes = { value: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, + PropTypes.bool, PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number, + PropTypes.bool, + ]) ), ]), + /** + * The ID of this component, used to identify dash components + * in callbacks. The ID needs to be unique across all of the + * components in an app. + */ + id: PropTypes.string, + /** * height of each option. Can be increased when label lengths would wrap around */ diff --git a/components/dash-core-components/src/components/RadioItems.react.js b/components/dash-core-components/src/components/RadioItems.react.js index 8c2ef151b1..fe6d8e42c1 100644 --- a/components/dash-core-components/src/components/RadioItems.react.js +++ b/components/dash-core-components/src/components/RadioItems.react.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, {Component} from 'react'; import './css/react-select@1.0.0-rc.3.min.css'; +import {sanitizeOptions} from '../utils/optionTypes'; /** * RadioItems is a component that encapsulates several radio item inputs. @@ -23,6 +24,7 @@ export default class RadioItems extends Component { setProps, loading_state, value, + inline, } = this.props; let ids = {}; @@ -38,9 +40,13 @@ export default class RadioItems extends Component { className={className} style={style} > - {options.map(option => ( + {sanitizeOptions(options).map(option => (