Skip to content

Commit 00b9b34

Browse files
authored
Merge branch 'dev' into codeflash/optimize-flatten_grouping-max6hy2z
2 parents 61ea742 + ed57bb0 commit 00b9b34

File tree

8 files changed

+157
-78
lines changed

8 files changed

+157
-78
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ This project adheres to [Semantic Versioning](https://semver.org/).
110110
- `defaultProps` on functional components now emits a deprecation warning.
111111
- Deprecation notice on strings refs.
112112

113+
## Added
114+
115+
- [#3068](https://github.com/plotly/dash/pull/3068) Add titles to labels in Checklist and RadioItems components
116+
113117
## Fixed
114118

115119
- [#3080](https://github.com/plotly/dash/pull/3080) Fix docstring generation for components using single-line or nonstandard-indent leading comments

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default class Checklist extends Component {
3737
...labelStyle,
3838
}}
3939
className={labelClassName}
40+
title={option.title}
4041
>
4142
<input
4243
checked={includes(option.value, value)}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export default class RadioItems extends Component {
4141
}}
4242
className={labelClassName}
4343
key={option.value}
44+
title={option.title}
4445
>
4546
<input
4647
checked={option.value === value}

components/dash-core-components/src/fragments/Graph.react.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,27 @@ class PlotlyGraph extends Component {
458458
});
459459
}
460460

461+
getStyle() {
462+
const {responsive} = this.props;
463+
let {style} = this.props;
464+
465+
// When there is no forced responsive style, return the original style property
466+
if (!responsive) {
467+
return style;
468+
}
469+
470+
// Otherwise, if the height is not set, we make the graph size equal to the parent one
471+
if (!style) {
472+
style = {};
473+
}
474+
475+
if (!style.height) {
476+
return Object.assign({height: '100%'}, style);
477+
}
478+
479+
return style;
480+
}
481+
461482
componentDidMount() {
462483
const p = this.plot(this.props);
463484
this._queue = this.amendTraces(p, {}, this.props);
@@ -516,7 +537,8 @@ class PlotlyGraph extends Component {
516537
}
517538

518539
render() {
519-
const {className, id, style} = this.props;
540+
const {className, id} = this.props;
541+
const style = this.getStyle();
520542

521543
return (
522544
<LoadingElement

components/dash-core-components/tests/integration/dropdown/test_option_title_prop.py

Lines changed: 0 additions & 70 deletions
This file was deleted.

components/dash-core-components/tests/integration/graph/test_graph_responsive.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import numpy as np
2+
import plotly.graph_objects as go
13
import pytest
24
import flaky
35

@@ -138,8 +140,38 @@ def resize(n_clicks, style):
138140
assert dash_dcc.get_logs() == []
139141

140142

143+
def test_grrs002_responsive_parent_height(dash_dcc):
144+
app = Dash(__name__, eager_loading=True)
145+
146+
x, y = np.random.uniform(size=50), np.random.uniform(size=50)
147+
148+
fig = go.Figure(
149+
data=[go.Scattergl(x=x, y=y, mode="markers")],
150+
layout=dict(margin=dict(l=0, r=0, t=0, b=0), height=600, width=600),
151+
)
152+
153+
app.layout = html.Div(
154+
dcc.Graph(
155+
id="graph",
156+
figure=fig,
157+
responsive=True,
158+
),
159+
style={"borderStyle": "solid", "height": 300, "width": 100},
160+
)
161+
162+
dash_dcc.start_server(app)
163+
164+
wait.until(
165+
lambda: dash_dcc.wait_for_element("#graph svg.main-svg").size.get("height", -1)
166+
== 300,
167+
3,
168+
)
169+
170+
assert dash_dcc.get_logs() == []
171+
172+
141173
@flaky.flaky(max_runs=3)
142-
def test_grrs002_graph(dash_dcc):
174+
def test_grrs003_graph(dash_dcc):
143175
app = Dash(__name__)
144176

145177
app.layout = html.Div(
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# -*- coding: UTF-8 -*-
2+
3+
from dash.testing import wait
4+
from dash import Dash, Input, Output, dcc, html
5+
6+
7+
def test_ddot001_dropdown_radioitems_checklist_option_title(dash_dcc):
8+
app = Dash(__name__)
9+
10+
options = [
11+
{"label": "New York City", "value": "NYC"},
12+
{"label": "Montréal", "value": "MTL"},
13+
{"label": "San Francisco", "value": "SF"},
14+
]
15+
16+
app.layout = html.Div(
17+
[
18+
dcc.Input(
19+
id="title_input",
20+
type="text",
21+
placeholder="Enter a title for New York City",
22+
),
23+
dcc.Dropdown(id="dropdown_1", options=options, multi=True, value="NYC"),
24+
dcc.Dropdown(id="dropdown_2", options=options, multi=False, value="NYC"),
25+
dcc.Checklist(
26+
id="checklist_1",
27+
options=options,
28+
value=["NYC"],
29+
labelClassName="Select-value-label",
30+
),
31+
dcc.RadioItems(
32+
id="radioitems_1",
33+
options=options,
34+
value="NYC",
35+
labelClassName="Select-value-label",
36+
),
37+
]
38+
)
39+
40+
ids = ["dropdown_1", "dropdown_2", "checklist_1", "radioitems_1"]
41+
42+
for id in ids:
43+
44+
@app.callback(Output(id, "options"), [Input("title_input", "value")])
45+
def add_title_to_option(title):
46+
return [
47+
{"label": "New York City", "title": title, "value": "NYC"},
48+
{"label": "Montréal", "value": "MTL"},
49+
{"label": "San Francisco", "value": "SF"},
50+
]
51+
52+
dash_dcc.start_server(app)
53+
54+
elements = [
55+
dash_dcc.wait_for_element("#dropdown_1 .Select-value"),
56+
dash_dcc.wait_for_element("#dropdown_2 .Select-value"),
57+
dash_dcc.wait_for_element("#checklist_1 .Select-value-label"),
58+
dash_dcc.wait_for_element("#radioitems_1 .Select-value-label"),
59+
]
60+
61+
component_title_input = dash_dcc.wait_for_element("#title_input")
62+
63+
# Empty string title ('') (default for no title)
64+
65+
for element in elements:
66+
wait.until(lambda: element.get_attribute("title") == "", 3)
67+
68+
component_title_input.send_keys("The Big Apple")
69+
70+
for element in elements:
71+
wait.until(lambda: element.get_attribute("title") == "The Big Apple", 3)
72+
73+
dash_dcc.clear_input(component_title_input)
74+
75+
component_title_input.send_keys("Gotham City?")
76+
77+
for element in elements:
78+
wait.until(lambda: element.get_attribute("title") == "Gotham City?", 3)
79+
80+
dash_dcc.clear_input(component_title_input)
81+
82+
for element in elements:
83+
wait.until(lambda: element.get_attribute("title") == "", 3)
84+
85+
assert dash_dcc.get_logs() == []

dash/dash.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,17 +2342,21 @@ def update(pathname_, search_, **states):
23422342

23432343
# Set validation_layout
23442344
if not self.config.suppress_callback_exceptions:
2345-
self.validation_layout = html.Div(
2346-
[
2347-
page["layout"]() if callable(page["layout"]) else page["layout"]
2348-
for page in _pages.PAGE_REGISTRY.values()
2349-
]
2350-
+ [
2345+
layout = self.layout
2346+
if not isinstance(layout, list):
2347+
layout = [
23512348
# pylint: disable=not-callable
23522349
self.layout()
23532350
if callable(self.layout)
23542351
else self.layout
23552352
]
2353+
2354+
self.validation_layout = html.Div(
2355+
[
2356+
page["layout"]() if callable(page["layout"]) else page["layout"]
2357+
for page in _pages.PAGE_REGISTRY.values()
2358+
]
2359+
+ layout
23562360
)
23572361
if _ID_CONTENT not in self.validation_layout:
23582362
raise Exception("`dash.page_container` not found in the layout")

0 commit comments

Comments
 (0)