dash-startup-loading-plugin 0.1.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dash_startup_loading_plugin-0.1.0/src/dash_startup_loading_plugin.egg-info → dash_startup_loading_plugin-0.3.0}/PKG-INFO +190 -46
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/README.md +185 -43
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/pyproject.toml +6 -3
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/__init__.py +6 -2
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/plugin.py +98 -21
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/resources/startup-loading.css +6 -8
- dash_startup_loading_plugin-0.3.0/src/dash_startup_loading_plugin/resources/startup-theme.js +102 -0
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0/src/dash_startup_loading_plugin.egg-info}/PKG-INFO +190 -46
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin.egg-info/SOURCES.txt +1 -0
- dash_startup_loading_plugin-0.3.0/src/dash_startup_loading_plugin.egg-info/requires.txt +7 -0
- dash_startup_loading_plugin-0.3.0/tests/test_plugin.py +196 -0
- dash_startup_loading_plugin-0.1.0/src/dash_startup_loading_plugin.egg-info/requires.txt +0 -4
- dash_startup_loading_plugin-0.1.0/tests/test_plugin.py +0 -104
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/LICENSE +0 -0
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/setup.cfg +0 -0
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/resources/startup-loading.js +0 -0
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin.egg-info/dependency_links.txt +0 -0
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin.egg-info/entry_points.txt +0 -0
- {dash_startup_loading_plugin-0.1.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin.egg-info/top_level.txt +0 -0
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dash-startup-loading-plugin
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A configurable full-screen startup loading overlay for Dash apps, packaged as a Dash Hooks plugin.
|
|
5
5
|
Author-email: Ethan Zhang <ethan.zhang2016@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
Keywords: dash,plotly,loading,plugin
|
|
7
|
+
Keywords: dash,plotly,loading,plugin
|
|
8
8
|
Classifier: Framework :: Dash
|
|
9
9
|
Requires-Python: >=3.9
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
|
-
Requires-Dist: dash
|
|
12
|
+
Requires-Dist: dash==4.4.1
|
|
13
13
|
Provides-Extra: test
|
|
14
14
|
Requires-Dist: pytest>=8; extra == "test"
|
|
15
|
+
Provides-Extra: mantine
|
|
16
|
+
Requires-Dist: dash-mantine-components>=2.6.0; extra == "mantine"
|
|
15
17
|
Dynamic: license-file
|
|
16
18
|
|
|
17
19
|
# dash-startup-loading-plugin
|
|
@@ -20,10 +22,10 @@ Dynamic: license-file
|
|
|
20
22
|
that displays a full-screen loading overlay while a Dash application performs
|
|
21
23
|
its initial browser-side startup.
|
|
22
24
|
|
|
23
|
-
The overlay
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
The overlay, CSS, and JavaScript are injected into the final HTML document with
|
|
26
|
+
`hooks.index`, so they are available before Dash and React mount the application
|
|
27
|
+
layout without additional startup resource requests. An app does not need to
|
|
28
|
+
copy assets or replace Dash's `index_string`.
|
|
27
29
|
|
|
28
30
|
## Features
|
|
29
31
|
|
|
@@ -32,8 +34,10 @@ does not need to copy assets or replace Dash's `index_string`.
|
|
|
32
34
|
- Waits for real rendered content and optional app-specific readiness selectors.
|
|
33
35
|
- Can wait for lazy-loading placeholders to disappear.
|
|
34
36
|
- Includes a timeout fallback, minimum display time, and fade-out transition.
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
+
- Inlines its small startup CSS and JavaScript, avoiding two additional requests.
|
|
38
|
+
- Resolves light and dark themes before first paint from Dash component
|
|
39
|
+
persistence, Tailwind root classes, Mantine color-scheme state, or the
|
|
40
|
+
operating-system preference.
|
|
37
41
|
- Exposes a small browser API and emits a completion event.
|
|
38
42
|
- Requires no changes to the app layout or callbacks.
|
|
39
43
|
|
|
@@ -49,7 +53,7 @@ discovery, resource hooks, and the index hook described in the official
|
|
|
49
53
|
## Installation
|
|
50
54
|
|
|
51
55
|
```bash
|
|
52
|
-
pip install dash-startup-loading-plugin
|
|
56
|
+
pip install "dash-startup-loading-plugin>=0.3.0"
|
|
53
57
|
```
|
|
54
58
|
|
|
55
59
|
The package declares the following entry point:
|
|
@@ -64,6 +68,27 @@ package therefore enables the default startup overlay for Dash applications in
|
|
|
64
68
|
that Python environment; an explicit import is only needed when changing its
|
|
65
69
|
configuration or using its Python API.
|
|
66
70
|
|
|
71
|
+
## What's new in 0.3.0
|
|
72
|
+
|
|
73
|
+
- Adds `configure_antd()` with matching `#ffffff` and `#121212` loading
|
|
74
|
+
backgrounds plus explicit light/dark overrides.
|
|
75
|
+
- Adds `configure_mantine()` with theme defaults sourced from Dash Mantine
|
|
76
|
+
Components and its pre-render color-scheme hook.
|
|
77
|
+
- Updates the Dash Ant Design example for the structured
|
|
78
|
+
`ConfigProvider.theme.algorithm` API.
|
|
79
|
+
- Adds a Dash Mantine Components example with persisted theme switching.
|
|
80
|
+
|
|
81
|
+
## What's new in 0.2.0
|
|
82
|
+
|
|
83
|
+
- Resolves the loading background before first paint from a persisted
|
|
84
|
+
`dash_antd_components.ConfigProvider.theme`.
|
|
85
|
+
- Supports Tailwind's `html.dark` and `html.light` classes.
|
|
86
|
+
- Supports Dash Mantine Components' `data-mantine-color-scheme` attribute and
|
|
87
|
+
`mantine-color-scheme-value` localStorage entry.
|
|
88
|
+
- Adds `theme_mode` and `dash_theme_component_id` configuration.
|
|
89
|
+
- Keeps the startup CSS and JavaScript inline, so theme detection does not add
|
|
90
|
+
network requests before Dash mounts.
|
|
91
|
+
|
|
67
92
|
## Quick start
|
|
68
93
|
|
|
69
94
|
The defaults work without any plugin-specific code:
|
|
@@ -91,25 +116,33 @@ from dash import Dash, html
|
|
|
91
116
|
from dash_startup_loading_plugin import configure
|
|
92
117
|
|
|
93
118
|
configure(
|
|
94
|
-
required_selectors=["#
|
|
119
|
+
required_selectors=["#usage-header", "#usage-sidebar-menu"],
|
|
95
120
|
pending_selector="[data-dac-async-placeholder]",
|
|
96
121
|
timeout_ms=6000,
|
|
97
|
-
minimum_display_ms=200,
|
|
98
122
|
fade_duration_ms=160,
|
|
99
|
-
color="#1677ff",
|
|
100
|
-
dark_color="#4096ff",
|
|
101
123
|
)
|
|
102
124
|
|
|
103
125
|
app = Dash(__name__)
|
|
104
126
|
app.layout = html.Div(
|
|
105
127
|
[
|
|
106
|
-
html.Header("Dashboard", id="
|
|
107
|
-
html.Nav("Navigation", id="sidebar-menu"),
|
|
128
|
+
html.Header("Dashboard", id="usage-header"),
|
|
129
|
+
html.Nav("Navigation", id="usage-sidebar-menu"),
|
|
108
130
|
]
|
|
109
131
|
)
|
|
110
132
|
```
|
|
111
133
|
|
|
112
|
-
|
|
134
|
+
Runnable examples:
|
|
135
|
+
|
|
136
|
+
- [`examples/basic.py`](examples/basic.py): Dash Ant Design theme persistence.
|
|
137
|
+
- [`examples/mantine_theme.py`](examples/mantine_theme.py):
|
|
138
|
+
Dash Mantine Components with a persisted light/dark theme switch.
|
|
139
|
+
|
|
140
|
+
Run the Mantine example with:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pip install -e ".[mantine]"
|
|
144
|
+
python examples/mantine_theme.py
|
|
145
|
+
```
|
|
113
146
|
|
|
114
147
|
## Readiness behavior
|
|
115
148
|
|
|
@@ -152,14 +185,133 @@ immutable `StartupLoadingConfig` instance.
|
|
|
152
185
|
| `dark_background` | `"#0f0f0f"` | Dark-theme background color. |
|
|
153
186
|
| `color` | `"#1677ff"` | Light-theme spinner/current color. |
|
|
154
187
|
| `dark_color` | `"#4096ff"` | Dark-theme spinner/current color. |
|
|
188
|
+
| `theme_mode` | `"auto"` | Startup theme policy: `"auto"`, `"light"`, or `"dark"`. Auto follows persisted or active app state, then the operating-system preference. |
|
|
189
|
+
| `dash_theme_component_id` | `None` | Preferred Dash component ID when reading a persisted `theme` prop. When omitted, the first compatible persisted theme is used. |
|
|
155
190
|
| `spinner_size_px` | `28` | Default spinner width and height in pixels. |
|
|
156
191
|
| `spinner_stroke_px` | `3` | Default spinner stroke width in pixels. |
|
|
157
192
|
| `hide_default_loading` | `True` | Hide Dash's built-in initial `._dash-loading` indicator while the overlay is present. |
|
|
158
193
|
| `custom_loader_html` | `None` | Trusted HTML that replaces the default spinner. |
|
|
159
194
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
195
|
+
With `theme_mode="auto"`, the inline head bootstrap resolves the startup theme
|
|
196
|
+
in this order:
|
|
197
|
+
|
|
198
|
+
1. The persisted Dash `theme` for `dash_theme_component_id`, when configured.
|
|
199
|
+
2. An existing `html.dark` or `html.light` class, including Tailwind's manual
|
|
200
|
+
dark-mode convention.
|
|
201
|
+
3. `data-theme`, `data-color-scheme`, or `data-mantine-color-scheme` on
|
|
202
|
+
`<html>`.
|
|
203
|
+
4. Other Dash local persistence entries for a component's `theme` prop. Set
|
|
204
|
+
`dash_theme_component_id` when an app contains more than one persisted
|
|
205
|
+
theme-capable component.
|
|
206
|
+
5. Dash Mantine Components' `mantine-color-scheme-value` localStorage entry,
|
|
207
|
+
followed by the common `theme`, `color-theme`, and `color-scheme` keys.
|
|
208
|
+
6. `prefers-color-scheme`.
|
|
209
|
+
|
|
210
|
+
The result is written to `data-dash-startup-loading-theme` before the body is
|
|
211
|
+
parsed. This isolates the overlay styling without changing classes or data
|
|
212
|
+
attributes owned by Tailwind, Dash Mantine Components, or the application.
|
|
213
|
+
The stylesheet also adjusts its animation for `prefers-reduced-motion`.
|
|
214
|
+
|
|
215
|
+
### Dash Mantine Components
|
|
216
|
+
|
|
217
|
+
Dash Mantine Components 2.6 and later includes `ColorSchemeToggle`, which
|
|
218
|
+
switches the active color scheme without a callback and persists it in
|
|
219
|
+
`mantine-color-scheme-value`. The startup plugin reads that value before Dash
|
|
220
|
+
and React mount. To make the loading transition seamless, use Mantine's current
|
|
221
|
+
default dark body color for the overlay:
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
import dash_mantine_components as dmc
|
|
225
|
+
from dash_startup_loading_plugin import configure_mantine
|
|
226
|
+
|
|
227
|
+
configure_mantine()
|
|
228
|
+
|
|
229
|
+
app.layout = dmc.MantineProvider(
|
|
230
|
+
[
|
|
231
|
+
dmc.ColorSchemeToggle(
|
|
232
|
+
lightIcon=dmc.Text("☀"),
|
|
233
|
+
darkIcon=dmc.Text("☾"),
|
|
234
|
+
),
|
|
235
|
+
dmc.Text("Application content", id="app-ready"),
|
|
236
|
+
],
|
|
237
|
+
defaultColorScheme="auto",
|
|
238
|
+
)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
See
|
|
242
|
+
[`examples/mantine_theme.py`](examples/mantine_theme.py)
|
|
243
|
+
for the complete runnable example.
|
|
244
|
+
|
|
245
|
+
`configure_mantine()` keeps DMC optional. When used, it registers DMC's
|
|
246
|
+
pre-render color-scheme hook, disables the Dash Ant Design placeholder check,
|
|
247
|
+
and derives the light and dark loading backgrounds from DMC's active default
|
|
248
|
+
theme. Any explicit configuration still takes precedence:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
configure_mantine(dark_background="#202020")
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Dash Ant Design persistence
|
|
255
|
+
|
|
256
|
+
Current `dash_antd_components.ConfigProvider.theme` accepts a structured theme
|
|
257
|
+
configuration whose `algorithm` is `"default"`, `"dark"`, `"compact"`, or an
|
|
258
|
+
array of those values. Persist a user-facing system/light/dark selector, resolve
|
|
259
|
+
the system preference in a clientside callback, and store the semantic choice
|
|
260
|
+
in the small conventional `localStorage["theme"]` value that the startup plugin
|
|
261
|
+
reads before Dash mounts:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
import dash_antd_components as dac
|
|
265
|
+
from dash import Input, Output, clientside_callback
|
|
266
|
+
from dash_startup_loading_plugin import configure_antd
|
|
267
|
+
|
|
268
|
+
configure_antd()
|
|
269
|
+
|
|
270
|
+
provider = dac.ConfigProvider(
|
|
271
|
+
[
|
|
272
|
+
app_content,
|
|
273
|
+
dac.Segmented(
|
|
274
|
+
id="theme-mode",
|
|
275
|
+
options=["system", "light", "dark"],
|
|
276
|
+
value="system",
|
|
277
|
+
persistence=True,
|
|
278
|
+
persisted_props=["value"],
|
|
279
|
+
persistence_type="local",
|
|
280
|
+
),
|
|
281
|
+
],
|
|
282
|
+
id="theme-provider",
|
|
283
|
+
theme={"algorithm": "default"},
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
clientside_callback(
|
|
287
|
+
"""function(mode) {
|
|
288
|
+
localStorage.setItem("theme", JSON.stringify(mode));
|
|
289
|
+
const dark = mode === "dark" || (
|
|
290
|
+
mode === "system"
|
|
291
|
+
&& window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
292
|
+
);
|
|
293
|
+
return {algorithm: dark ? "dark" : "default"};
|
|
294
|
+
}""",
|
|
295
|
+
Output("theme-provider", "theme"),
|
|
296
|
+
Input("theme-mode", "value"),
|
|
297
|
+
)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
The selector owns the semantic `"system"` state; `ConfigProvider` receives only
|
|
301
|
+
the algorithms allowed by its current API. `configure_antd()` uses `#ffffff`
|
|
302
|
+
and `#121212`, matching the component library's default light and dark
|
|
303
|
+
backgrounds. If the application customizes either background, pass the same
|
|
304
|
+
values explicitly:
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
configure_antd(
|
|
308
|
+
background="#f5f5f5",
|
|
309
|
+
dark_background="#202020",
|
|
310
|
+
)
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
See
|
|
314
|
+
[`examples/basic.py`](examples/basic.py) for the complete switcher.
|
|
163
315
|
|
|
164
316
|
### Custom loader markup
|
|
165
317
|
|
|
@@ -186,12 +338,18 @@ configuration. Never populate it with user input.
|
|
|
186
338
|
from dash_startup_loading_plugin import (
|
|
187
339
|
StartupLoadingConfig,
|
|
188
340
|
configure,
|
|
341
|
+
configure_antd,
|
|
342
|
+
configure_mantine,
|
|
189
343
|
get_config,
|
|
190
344
|
reset_config,
|
|
191
345
|
)
|
|
192
346
|
```
|
|
193
347
|
|
|
194
348
|
- `configure(**changes)` validates and applies a partial configuration update.
|
|
349
|
+
- `configure_antd(**changes)` matches the loading backgrounds to Dash Ant
|
|
350
|
+
Design's light and dark themes and accepts explicit overrides.
|
|
351
|
+
- `configure_mantine(**changes)` applies DMC theme defaults and registers DMC's
|
|
352
|
+
pre-render color-scheme hook.
|
|
195
353
|
- `get_config()` returns the current immutable configuration.
|
|
196
354
|
- `reset_config()` restores all defaults. It is primarily useful in tests.
|
|
197
355
|
- `StartupLoadingConfig` is the frozen dataclass containing all options.
|
|
@@ -241,11 +399,18 @@ configure(
|
|
|
241
399
|
)
|
|
242
400
|
```
|
|
243
401
|
|
|
244
|
-
The plugin preserves Dash's normal index template, injects
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
402
|
+
The plugin preserves Dash's normal index template, injects its stylesheet before
|
|
403
|
+
`</head>`, and inserts the overlay followed by its startup script directly after
|
|
404
|
+
the opening `<body>` tag. The source CSS and JavaScript remain package resources
|
|
405
|
+
for maintainability, but the browser receives them inline and makes no separate
|
|
406
|
+
request for either file. The index hook uses priority `100`, so it runs before
|
|
407
|
+
lower-priority index hooks. If multiple hooks share the same priority, Dash does
|
|
408
|
+
not guarantee their relative order.
|
|
409
|
+
|
|
410
|
+
Because the resources are inline, applications with a strict Content Security
|
|
411
|
+
Policy must permit the injected style and script, or add nonce support in a
|
|
412
|
+
customized deployment. The previous external-resource form is more suitable
|
|
413
|
+
when a policy forbids all inline code.
|
|
249
414
|
|
|
250
415
|
## Scope and process model
|
|
251
416
|
|
|
@@ -282,27 +447,6 @@ This is expected with automatic `dash_hooks` discovery. Use a dedicated virtual
|
|
|
282
447
|
environment, uninstall the package where it is not wanted, or call
|
|
283
448
|
`configure(enabled=False)` before constructing those Dash apps.
|
|
284
449
|
|
|
285
|
-
## Development
|
|
286
|
-
|
|
287
|
-
Clone the repository, then install the project and test dependencies:
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
uv sync --extra test
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Run the tests and example:
|
|
294
|
-
|
|
295
|
-
```bash
|
|
296
|
-
uv run pytest
|
|
297
|
-
uv run python examples/basic.py
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
Build the source distribution and wheel:
|
|
301
|
-
|
|
302
|
-
```bash
|
|
303
|
-
uv build
|
|
304
|
-
```
|
|
305
|
-
|
|
306
450
|
## License
|
|
307
451
|
|
|
308
452
|
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
that displays a full-screen loading overlay while a Dash application performs
|
|
5
5
|
its initial browser-side startup.
|
|
6
6
|
|
|
7
|
-
The overlay
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
The overlay, CSS, and JavaScript are injected into the final HTML document with
|
|
8
|
+
`hooks.index`, so they are available before Dash and React mount the application
|
|
9
|
+
layout without additional startup resource requests. An app does not need to
|
|
10
|
+
copy assets or replace Dash's `index_string`.
|
|
11
11
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
@@ -16,8 +16,10 @@ does not need to copy assets or replace Dash's `index_string`.
|
|
|
16
16
|
- Waits for real rendered content and optional app-specific readiness selectors.
|
|
17
17
|
- Can wait for lazy-loading placeholders to disappear.
|
|
18
18
|
- Includes a timeout fallback, minimum display time, and fade-out transition.
|
|
19
|
-
-
|
|
20
|
-
|
|
19
|
+
- Inlines its small startup CSS and JavaScript, avoiding two additional requests.
|
|
20
|
+
- Resolves light and dark themes before first paint from Dash component
|
|
21
|
+
persistence, Tailwind root classes, Mantine color-scheme state, or the
|
|
22
|
+
operating-system preference.
|
|
21
23
|
- Exposes a small browser API and emits a completion event.
|
|
22
24
|
- Requires no changes to the app layout or callbacks.
|
|
23
25
|
|
|
@@ -33,7 +35,7 @@ discovery, resource hooks, and the index hook described in the official
|
|
|
33
35
|
## Installation
|
|
34
36
|
|
|
35
37
|
```bash
|
|
36
|
-
pip install dash-startup-loading-plugin
|
|
38
|
+
pip install "dash-startup-loading-plugin>=0.3.0"
|
|
37
39
|
```
|
|
38
40
|
|
|
39
41
|
The package declares the following entry point:
|
|
@@ -48,6 +50,27 @@ package therefore enables the default startup overlay for Dash applications in
|
|
|
48
50
|
that Python environment; an explicit import is only needed when changing its
|
|
49
51
|
configuration or using its Python API.
|
|
50
52
|
|
|
53
|
+
## What's new in 0.3.0
|
|
54
|
+
|
|
55
|
+
- Adds `configure_antd()` with matching `#ffffff` and `#121212` loading
|
|
56
|
+
backgrounds plus explicit light/dark overrides.
|
|
57
|
+
- Adds `configure_mantine()` with theme defaults sourced from Dash Mantine
|
|
58
|
+
Components and its pre-render color-scheme hook.
|
|
59
|
+
- Updates the Dash Ant Design example for the structured
|
|
60
|
+
`ConfigProvider.theme.algorithm` API.
|
|
61
|
+
- Adds a Dash Mantine Components example with persisted theme switching.
|
|
62
|
+
|
|
63
|
+
## What's new in 0.2.0
|
|
64
|
+
|
|
65
|
+
- Resolves the loading background before first paint from a persisted
|
|
66
|
+
`dash_antd_components.ConfigProvider.theme`.
|
|
67
|
+
- Supports Tailwind's `html.dark` and `html.light` classes.
|
|
68
|
+
- Supports Dash Mantine Components' `data-mantine-color-scheme` attribute and
|
|
69
|
+
`mantine-color-scheme-value` localStorage entry.
|
|
70
|
+
- Adds `theme_mode` and `dash_theme_component_id` configuration.
|
|
71
|
+
- Keeps the startup CSS and JavaScript inline, so theme detection does not add
|
|
72
|
+
network requests before Dash mounts.
|
|
73
|
+
|
|
51
74
|
## Quick start
|
|
52
75
|
|
|
53
76
|
The defaults work without any plugin-specific code:
|
|
@@ -75,25 +98,33 @@ from dash import Dash, html
|
|
|
75
98
|
from dash_startup_loading_plugin import configure
|
|
76
99
|
|
|
77
100
|
configure(
|
|
78
|
-
required_selectors=["#
|
|
101
|
+
required_selectors=["#usage-header", "#usage-sidebar-menu"],
|
|
79
102
|
pending_selector="[data-dac-async-placeholder]",
|
|
80
103
|
timeout_ms=6000,
|
|
81
|
-
minimum_display_ms=200,
|
|
82
104
|
fade_duration_ms=160,
|
|
83
|
-
color="#1677ff",
|
|
84
|
-
dark_color="#4096ff",
|
|
85
105
|
)
|
|
86
106
|
|
|
87
107
|
app = Dash(__name__)
|
|
88
108
|
app.layout = html.Div(
|
|
89
109
|
[
|
|
90
|
-
html.Header("Dashboard", id="
|
|
91
|
-
html.Nav("Navigation", id="sidebar-menu"),
|
|
110
|
+
html.Header("Dashboard", id="usage-header"),
|
|
111
|
+
html.Nav("Navigation", id="usage-sidebar-menu"),
|
|
92
112
|
]
|
|
93
113
|
)
|
|
94
114
|
```
|
|
95
115
|
|
|
96
|
-
|
|
116
|
+
Runnable examples:
|
|
117
|
+
|
|
118
|
+
- [`examples/basic.py`](examples/basic.py): Dash Ant Design theme persistence.
|
|
119
|
+
- [`examples/mantine_theme.py`](examples/mantine_theme.py):
|
|
120
|
+
Dash Mantine Components with a persisted light/dark theme switch.
|
|
121
|
+
|
|
122
|
+
Run the Mantine example with:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install -e ".[mantine]"
|
|
126
|
+
python examples/mantine_theme.py
|
|
127
|
+
```
|
|
97
128
|
|
|
98
129
|
## Readiness behavior
|
|
99
130
|
|
|
@@ -136,14 +167,133 @@ immutable `StartupLoadingConfig` instance.
|
|
|
136
167
|
| `dark_background` | `"#0f0f0f"` | Dark-theme background color. |
|
|
137
168
|
| `color` | `"#1677ff"` | Light-theme spinner/current color. |
|
|
138
169
|
| `dark_color` | `"#4096ff"` | Dark-theme spinner/current color. |
|
|
170
|
+
| `theme_mode` | `"auto"` | Startup theme policy: `"auto"`, `"light"`, or `"dark"`. Auto follows persisted or active app state, then the operating-system preference. |
|
|
171
|
+
| `dash_theme_component_id` | `None` | Preferred Dash component ID when reading a persisted `theme` prop. When omitted, the first compatible persisted theme is used. |
|
|
139
172
|
| `spinner_size_px` | `28` | Default spinner width and height in pixels. |
|
|
140
173
|
| `spinner_stroke_px` | `3` | Default spinner stroke width in pixels. |
|
|
141
174
|
| `hide_default_loading` | `True` | Hide Dash's built-in initial `._dash-loading` indicator while the overlay is present. |
|
|
142
175
|
| `custom_loader_html` | `None` | Trusted HTML that replaces the default spinner. |
|
|
143
176
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
177
|
+
With `theme_mode="auto"`, the inline head bootstrap resolves the startup theme
|
|
178
|
+
in this order:
|
|
179
|
+
|
|
180
|
+
1. The persisted Dash `theme` for `dash_theme_component_id`, when configured.
|
|
181
|
+
2. An existing `html.dark` or `html.light` class, including Tailwind's manual
|
|
182
|
+
dark-mode convention.
|
|
183
|
+
3. `data-theme`, `data-color-scheme`, or `data-mantine-color-scheme` on
|
|
184
|
+
`<html>`.
|
|
185
|
+
4. Other Dash local persistence entries for a component's `theme` prop. Set
|
|
186
|
+
`dash_theme_component_id` when an app contains more than one persisted
|
|
187
|
+
theme-capable component.
|
|
188
|
+
5. Dash Mantine Components' `mantine-color-scheme-value` localStorage entry,
|
|
189
|
+
followed by the common `theme`, `color-theme`, and `color-scheme` keys.
|
|
190
|
+
6. `prefers-color-scheme`.
|
|
191
|
+
|
|
192
|
+
The result is written to `data-dash-startup-loading-theme` before the body is
|
|
193
|
+
parsed. This isolates the overlay styling without changing classes or data
|
|
194
|
+
attributes owned by Tailwind, Dash Mantine Components, or the application.
|
|
195
|
+
The stylesheet also adjusts its animation for `prefers-reduced-motion`.
|
|
196
|
+
|
|
197
|
+
### Dash Mantine Components
|
|
198
|
+
|
|
199
|
+
Dash Mantine Components 2.6 and later includes `ColorSchemeToggle`, which
|
|
200
|
+
switches the active color scheme without a callback and persists it in
|
|
201
|
+
`mantine-color-scheme-value`. The startup plugin reads that value before Dash
|
|
202
|
+
and React mount. To make the loading transition seamless, use Mantine's current
|
|
203
|
+
default dark body color for the overlay:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
import dash_mantine_components as dmc
|
|
207
|
+
from dash_startup_loading_plugin import configure_mantine
|
|
208
|
+
|
|
209
|
+
configure_mantine()
|
|
210
|
+
|
|
211
|
+
app.layout = dmc.MantineProvider(
|
|
212
|
+
[
|
|
213
|
+
dmc.ColorSchemeToggle(
|
|
214
|
+
lightIcon=dmc.Text("☀"),
|
|
215
|
+
darkIcon=dmc.Text("☾"),
|
|
216
|
+
),
|
|
217
|
+
dmc.Text("Application content", id="app-ready"),
|
|
218
|
+
],
|
|
219
|
+
defaultColorScheme="auto",
|
|
220
|
+
)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
See
|
|
224
|
+
[`examples/mantine_theme.py`](examples/mantine_theme.py)
|
|
225
|
+
for the complete runnable example.
|
|
226
|
+
|
|
227
|
+
`configure_mantine()` keeps DMC optional. When used, it registers DMC's
|
|
228
|
+
pre-render color-scheme hook, disables the Dash Ant Design placeholder check,
|
|
229
|
+
and derives the light and dark loading backgrounds from DMC's active default
|
|
230
|
+
theme. Any explicit configuration still takes precedence:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
configure_mantine(dark_background="#202020")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Dash Ant Design persistence
|
|
237
|
+
|
|
238
|
+
Current `dash_antd_components.ConfigProvider.theme` accepts a structured theme
|
|
239
|
+
configuration whose `algorithm` is `"default"`, `"dark"`, `"compact"`, or an
|
|
240
|
+
array of those values. Persist a user-facing system/light/dark selector, resolve
|
|
241
|
+
the system preference in a clientside callback, and store the semantic choice
|
|
242
|
+
in the small conventional `localStorage["theme"]` value that the startup plugin
|
|
243
|
+
reads before Dash mounts:
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
import dash_antd_components as dac
|
|
247
|
+
from dash import Input, Output, clientside_callback
|
|
248
|
+
from dash_startup_loading_plugin import configure_antd
|
|
249
|
+
|
|
250
|
+
configure_antd()
|
|
251
|
+
|
|
252
|
+
provider = dac.ConfigProvider(
|
|
253
|
+
[
|
|
254
|
+
app_content,
|
|
255
|
+
dac.Segmented(
|
|
256
|
+
id="theme-mode",
|
|
257
|
+
options=["system", "light", "dark"],
|
|
258
|
+
value="system",
|
|
259
|
+
persistence=True,
|
|
260
|
+
persisted_props=["value"],
|
|
261
|
+
persistence_type="local",
|
|
262
|
+
),
|
|
263
|
+
],
|
|
264
|
+
id="theme-provider",
|
|
265
|
+
theme={"algorithm": "default"},
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
clientside_callback(
|
|
269
|
+
"""function(mode) {
|
|
270
|
+
localStorage.setItem("theme", JSON.stringify(mode));
|
|
271
|
+
const dark = mode === "dark" || (
|
|
272
|
+
mode === "system"
|
|
273
|
+
&& window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
274
|
+
);
|
|
275
|
+
return {algorithm: dark ? "dark" : "default"};
|
|
276
|
+
}""",
|
|
277
|
+
Output("theme-provider", "theme"),
|
|
278
|
+
Input("theme-mode", "value"),
|
|
279
|
+
)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The selector owns the semantic `"system"` state; `ConfigProvider` receives only
|
|
283
|
+
the algorithms allowed by its current API. `configure_antd()` uses `#ffffff`
|
|
284
|
+
and `#121212`, matching the component library's default light and dark
|
|
285
|
+
backgrounds. If the application customizes either background, pass the same
|
|
286
|
+
values explicitly:
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
configure_antd(
|
|
290
|
+
background="#f5f5f5",
|
|
291
|
+
dark_background="#202020",
|
|
292
|
+
)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
See
|
|
296
|
+
[`examples/basic.py`](examples/basic.py) for the complete switcher.
|
|
147
297
|
|
|
148
298
|
### Custom loader markup
|
|
149
299
|
|
|
@@ -170,12 +320,18 @@ configuration. Never populate it with user input.
|
|
|
170
320
|
from dash_startup_loading_plugin import (
|
|
171
321
|
StartupLoadingConfig,
|
|
172
322
|
configure,
|
|
323
|
+
configure_antd,
|
|
324
|
+
configure_mantine,
|
|
173
325
|
get_config,
|
|
174
326
|
reset_config,
|
|
175
327
|
)
|
|
176
328
|
```
|
|
177
329
|
|
|
178
330
|
- `configure(**changes)` validates and applies a partial configuration update.
|
|
331
|
+
- `configure_antd(**changes)` matches the loading backgrounds to Dash Ant
|
|
332
|
+
Design's light and dark themes and accepts explicit overrides.
|
|
333
|
+
- `configure_mantine(**changes)` applies DMC theme defaults and registers DMC's
|
|
334
|
+
pre-render color-scheme hook.
|
|
179
335
|
- `get_config()` returns the current immutable configuration.
|
|
180
336
|
- `reset_config()` restores all defaults. It is primarily useful in tests.
|
|
181
337
|
- `StartupLoadingConfig` is the frozen dataclass containing all options.
|
|
@@ -225,11 +381,18 @@ configure(
|
|
|
225
381
|
)
|
|
226
382
|
```
|
|
227
383
|
|
|
228
|
-
The plugin preserves Dash's normal index template, injects
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
384
|
+
The plugin preserves Dash's normal index template, injects its stylesheet before
|
|
385
|
+
`</head>`, and inserts the overlay followed by its startup script directly after
|
|
386
|
+
the opening `<body>` tag. The source CSS and JavaScript remain package resources
|
|
387
|
+
for maintainability, but the browser receives them inline and makes no separate
|
|
388
|
+
request for either file. The index hook uses priority `100`, so it runs before
|
|
389
|
+
lower-priority index hooks. If multiple hooks share the same priority, Dash does
|
|
390
|
+
not guarantee their relative order.
|
|
391
|
+
|
|
392
|
+
Because the resources are inline, applications with a strict Content Security
|
|
393
|
+
Policy must permit the injected style and script, or add nonce support in a
|
|
394
|
+
customized deployment. The previous external-resource form is more suitable
|
|
395
|
+
when a policy forbids all inline code.
|
|
233
396
|
|
|
234
397
|
## Scope and process model
|
|
235
398
|
|
|
@@ -266,27 +429,6 @@ This is expected with automatic `dash_hooks` discovery. Use a dedicated virtual
|
|
|
266
429
|
environment, uninstall the package where it is not wanted, or call
|
|
267
430
|
`configure(enabled=False)` before constructing those Dash apps.
|
|
268
431
|
|
|
269
|
-
## Development
|
|
270
|
-
|
|
271
|
-
Clone the repository, then install the project and test dependencies:
|
|
272
|
-
|
|
273
|
-
```bash
|
|
274
|
-
uv sync --extra test
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
Run the tests and example:
|
|
278
|
-
|
|
279
|
-
```bash
|
|
280
|
-
uv run pytest
|
|
281
|
-
uv run python examples/basic.py
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
Build the source distribution and wheel:
|
|
285
|
-
|
|
286
|
-
```bash
|
|
287
|
-
uv build
|
|
288
|
-
```
|
|
289
|
-
|
|
290
432
|
## License
|
|
291
433
|
|
|
292
434
|
MIT. See [`LICENSE`](LICENSE).
|
|
@@ -4,25 +4,28 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dash-startup-loading-plugin"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "A configurable full-screen startup loading overlay for Dash apps, packaged as a Dash Hooks plugin."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "Ethan Zhang", email = "ethan.zhang2016@gmail.com" }
|
|
13
13
|
]
|
|
14
|
-
keywords = ["dash", "plotly", "loading", "plugin"
|
|
14
|
+
keywords = ["dash", "plotly", "loading", "plugin"]
|
|
15
15
|
classifiers = ["Framework :: Dash"]
|
|
16
16
|
license = "MIT"
|
|
17
17
|
license-files = ["LICENSE"]
|
|
18
18
|
dependencies = [
|
|
19
|
-
"dash
|
|
19
|
+
"dash==4.4.1",
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
[project.optional-dependencies]
|
|
23
23
|
test = [
|
|
24
24
|
"pytest>=8",
|
|
25
25
|
]
|
|
26
|
+
mantine = [
|
|
27
|
+
"dash-mantine-components>=2.6.0",
|
|
28
|
+
]
|
|
26
29
|
|
|
27
30
|
[project.entry-points."dash_hooks"]
|
|
28
31
|
dash_startup_loading_plugin = "dash_startup_loading_plugin"
|