dash-startup-loading-plugin 0.2.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.
Files changed (18) hide show
  1. {dash_startup_loading_plugin-0.2.0/src/dash_startup_loading_plugin.egg-info → dash_startup_loading_plugin-0.3.0}/PKG-INFO +124 -136
  2. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/README.md +119 -133
  3. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/pyproject.toml +6 -3
  4. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/__init__.py +6 -2
  5. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/plugin.py +56 -14
  6. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0/src/dash_startup_loading_plugin.egg-info}/PKG-INFO +124 -136
  7. dash_startup_loading_plugin-0.3.0/src/dash_startup_loading_plugin.egg-info/requires.txt +7 -0
  8. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/tests/test_plugin.py +44 -1
  9. dash_startup_loading_plugin-0.2.0/src/dash_startup_loading_plugin.egg-info/requires.txt +0 -4
  10. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/LICENSE +0 -0
  11. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/setup.cfg +0 -0
  12. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/resources/startup-loading.css +0 -0
  13. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/resources/startup-loading.js +0 -0
  14. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin/resources/startup-theme.js +0 -0
  15. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin.egg-info/SOURCES.txt +0 -0
  16. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin.egg-info/dependency_links.txt +0 -0
  17. {dash_startup_loading_plugin-0.2.0 → dash_startup_loading_plugin-0.3.0}/src/dash_startup_loading_plugin.egg-info/entry_points.txt +0 -0
  18. {dash_startup_loading_plugin-0.2.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.2.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,hooks
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>=3.0.3
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
@@ -51,7 +53,7 @@ discovery, resource hooks, and the index hook described in the official
51
53
  ## Installation
52
54
 
53
55
  ```bash
54
- pip install "dash-startup-loading-plugin>=0.2.0"
56
+ pip install "dash-startup-loading-plugin>=0.3.0"
55
57
  ```
56
58
 
57
59
  The package declares the following entry point:
@@ -66,6 +68,16 @@ package therefore enables the default startup overlay for Dash applications in
66
68
  that Python environment; an explicit import is only needed when changing its
67
69
  configuration or using its Python API.
68
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
+
69
81
  ## What's new in 0.2.0
70
82
 
71
83
  - Resolves the loading background before first paint from a persisted
@@ -104,25 +116,33 @@ from dash import Dash, html
104
116
  from dash_startup_loading_plugin import configure
105
117
 
106
118
  configure(
107
- required_selectors=["#page-header", "#sidebar-menu"],
119
+ required_selectors=["#usage-header", "#usage-sidebar-menu"],
108
120
  pending_selector="[data-dac-async-placeholder]",
109
121
  timeout_ms=6000,
110
- minimum_display_ms=200,
111
122
  fade_duration_ms=160,
112
- color="#1677ff",
113
- dark_color="#4096ff",
114
123
  )
115
124
 
116
125
  app = Dash(__name__)
117
126
  app.layout = html.Div(
118
127
  [
119
- html.Header("Dashboard", id="page-header"),
120
- html.Nav("Navigation", id="sidebar-menu"),
128
+ html.Header("Dashboard", id="usage-header"),
129
+ html.Nav("Navigation", id="usage-sidebar-menu"),
121
130
  ]
122
131
  )
123
132
  ```
124
133
 
125
- See [`examples/basic.py`](examples/basic.py) for a runnable example.
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
+ ```
126
146
 
127
147
  ## Readiness behavior
128
148
 
@@ -192,29 +212,105 @@ parsed. This isolates the overlay styling without changing classes or data
192
212
  attributes owned by Tailwind, Dash Mantine Components, or the application.
193
213
  The stylesheet also adjusts its animation for `prefers-reduced-motion`.
194
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
+
195
254
  ### Dash Ant Design persistence
196
255
 
197
- `dash_antd_components.ConfigProvider` can persist its `theme` prop. The startup
198
- plugin reads that same Dash persistence record on the next page load:
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:
199
262
 
200
263
  ```python
201
264
  import dash_antd_components as dac
202
- from dash_startup_loading_plugin import configure
265
+ from dash import Input, Output, clientside_callback
266
+ from dash_startup_loading_plugin import configure_antd
203
267
 
204
- configure(dash_theme_component_id="theme-provider")
268
+ configure_antd()
205
269
 
206
270
  provider = dac.ConfigProvider(
207
- app_content,
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
+ ],
208
282
  id="theme-provider",
209
- persistence=True,
210
- persisted_props=["theme"],
211
- persistence_type="local",
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",
212
310
  )
213
311
  ```
214
312
 
215
- Update `theme-provider.theme` from a regular or clientside callback. Dash stores
216
- the UI edit, `ConfigProvider` restores it after mount, and the startup plugin
217
- uses it for the loading background before mount. See
313
+ See
218
314
  [`examples/basic.py`](examples/basic.py) for the complete switcher.
219
315
 
220
316
  ### Custom loader markup
@@ -242,12 +338,18 @@ configuration. Never populate it with user input.
242
338
  from dash_startup_loading_plugin import (
243
339
  StartupLoadingConfig,
244
340
  configure,
341
+ configure_antd,
342
+ configure_mantine,
245
343
  get_config,
246
344
  reset_config,
247
345
  )
248
346
  ```
249
347
 
250
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.
251
353
  - `get_config()` returns the current immutable configuration.
252
354
  - `reset_config()` restores all defaults. It is primarily useful in tests.
253
355
  - `StartupLoadingConfig` is the frozen dataclass containing all options.
@@ -345,120 +447,6 @@ This is expected with automatic `dash_hooks` discovery. Use a dedicated virtual
345
447
  environment, uninstall the package where it is not wanted, or call
346
448
  `configure(enabled=False)` before constructing those Dash apps.
347
449
 
348
- ## Development
349
-
350
- Clone the repository, then install the project and test dependencies:
351
-
352
- ```bash
353
- uv sync --extra test
354
- ```
355
-
356
- Run the tests and example:
357
-
358
- ```bash
359
- uv run pytest
360
- uv run --with dash-ant-design python examples/basic.py
361
- ```
362
-
363
- The example uses `dash_antd_components.ConfigProvider` to demonstrate native
364
- theme persistence, so `dash-ant-design` is an example-only dependency rather
365
- than a runtime dependency of the plugin.
366
-
367
- Build the source distribution and wheel:
368
-
369
- ```bash
370
- uv build
371
- ```
372
-
373
- ## Publishing to PyPI
374
-
375
- PyPI does not allow replacing an existing distribution file. Confirm that the
376
- version in `pyproject.toml` is new before building, then create the artifacts
377
- from a clean `dist/` directory:
378
-
379
- ```bash
380
- rm -rf build dist src/*.egg-info
381
- uv lock
382
- uv run --extra test pytest
383
- uvx ruff check src tests examples
384
- uv build
385
- uvx twine check dist/*
386
- ```
387
-
388
- Inspect the resulting files before upload:
389
-
390
- ```bash
391
- ls -lh dist/
392
- unzip -l dist/dash_startup_loading_plugin-0.2.0-py3-none-any.whl
393
- tar -tzf dist/dash_startup_loading_plugin-0.2.0.tar.gz
394
- uv publish --dry-run dist/*
395
- ```
396
-
397
- ### TestPyPI
398
-
399
- Create a TestPyPI API token, then upload to its legacy upload endpoint:
400
-
401
- ```bash
402
- export UV_PUBLISH_TOKEN="pypi-your-test-token"
403
- uv publish \
404
- --publish-url https://test.pypi.org/legacy/ \
405
- --check-url https://test.pypi.org/simple/ \
406
- dist/*
407
- unset UV_PUBLISH_TOKEN
408
- ```
409
-
410
- Test installation in an isolated environment:
411
-
412
- ```bash
413
- uv run --isolated \
414
- --index-url https://test.pypi.org/simple/ \
415
- --extra-index-url https://pypi.org/simple/ \
416
- --with dash-startup-loading-plugin==0.2.0 \
417
- python -c "import dash_startup_loading_plugin; print('import ok')"
418
- ```
419
-
420
- The extra PyPI index is needed because TestPyPI may not contain the plugin's
421
- runtime dependencies.
422
-
423
- ### PyPI with an API token
424
-
425
- Create a project-scoped PyPI token and publish the checked artifacts:
426
-
427
- ```bash
428
- export UV_PUBLISH_TOKEN="pypi-your-project-token"
429
- uv publish dist/*
430
- unset UV_PUBLISH_TOKEN
431
- ```
432
-
433
- Do not place tokens in `pyproject.toml`, shell history, source control, or CI
434
- logs.
435
-
436
- ### PyPI Trusted Publishing
437
-
438
- For CI releases, configure the repository and workflow as a Trusted Publisher
439
- in the PyPI project settings. The publishing job needs the
440
- `id-token: write` permission and can upload without a long-lived token:
441
-
442
- ```yaml
443
- permissions:
444
- contents: read
445
- id-token: write
446
-
447
- steps:
448
- - uses: actions/checkout@v4
449
- - uses: astral-sh/setup-uv@v8
450
- - run: uv build
451
- - run: uv publish --trusted-publishing always
452
- ```
453
-
454
- After publishing, verify the release:
455
-
456
- ```bash
457
- uv run --isolated \
458
- --with dash-startup-loading-plugin==0.2.0 \
459
- python -c "import dash_startup_loading_plugin; print('import ok')"
460
- ```
461
-
462
450
  ## License
463
451
 
464
452
  MIT. See [`LICENSE`](LICENSE).
@@ -35,7 +35,7 @@ discovery, resource hooks, and the index hook described in the official
35
35
  ## Installation
36
36
 
37
37
  ```bash
38
- pip install "dash-startup-loading-plugin>=0.2.0"
38
+ pip install "dash-startup-loading-plugin>=0.3.0"
39
39
  ```
40
40
 
41
41
  The package declares the following entry point:
@@ -50,6 +50,16 @@ package therefore enables the default startup overlay for Dash applications in
50
50
  that Python environment; an explicit import is only needed when changing its
51
51
  configuration or using its Python API.
52
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
+
53
63
  ## What's new in 0.2.0
54
64
 
55
65
  - Resolves the loading background before first paint from a persisted
@@ -88,25 +98,33 @@ from dash import Dash, html
88
98
  from dash_startup_loading_plugin import configure
89
99
 
90
100
  configure(
91
- required_selectors=["#page-header", "#sidebar-menu"],
101
+ required_selectors=["#usage-header", "#usage-sidebar-menu"],
92
102
  pending_selector="[data-dac-async-placeholder]",
93
103
  timeout_ms=6000,
94
- minimum_display_ms=200,
95
104
  fade_duration_ms=160,
96
- color="#1677ff",
97
- dark_color="#4096ff",
98
105
  )
99
106
 
100
107
  app = Dash(__name__)
101
108
  app.layout = html.Div(
102
109
  [
103
- html.Header("Dashboard", id="page-header"),
104
- html.Nav("Navigation", id="sidebar-menu"),
110
+ html.Header("Dashboard", id="usage-header"),
111
+ html.Nav("Navigation", id="usage-sidebar-menu"),
105
112
  ]
106
113
  )
107
114
  ```
108
115
 
109
- See [`examples/basic.py`](examples/basic.py) for a runnable example.
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
+ ```
110
128
 
111
129
  ## Readiness behavior
112
130
 
@@ -176,29 +194,105 @@ parsed. This isolates the overlay styling without changing classes or data
176
194
  attributes owned by Tailwind, Dash Mantine Components, or the application.
177
195
  The stylesheet also adjusts its animation for `prefers-reduced-motion`.
178
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
+
179
236
  ### Dash Ant Design persistence
180
237
 
181
- `dash_antd_components.ConfigProvider` can persist its `theme` prop. The startup
182
- plugin reads that same Dash persistence record on the next page load:
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:
183
244
 
184
245
  ```python
185
246
  import dash_antd_components as dac
186
- from dash_startup_loading_plugin import configure
247
+ from dash import Input, Output, clientside_callback
248
+ from dash_startup_loading_plugin import configure_antd
187
249
 
188
- configure(dash_theme_component_id="theme-provider")
250
+ configure_antd()
189
251
 
190
252
  provider = dac.ConfigProvider(
191
- app_content,
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
+ ],
192
264
  id="theme-provider",
193
- persistence=True,
194
- persisted_props=["theme"],
195
- persistence_type="local",
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",
196
292
  )
197
293
  ```
198
294
 
199
- Update `theme-provider.theme` from a regular or clientside callback. Dash stores
200
- the UI edit, `ConfigProvider` restores it after mount, and the startup plugin
201
- uses it for the loading background before mount. See
295
+ See
202
296
  [`examples/basic.py`](examples/basic.py) for the complete switcher.
203
297
 
204
298
  ### Custom loader markup
@@ -226,12 +320,18 @@ configuration. Never populate it with user input.
226
320
  from dash_startup_loading_plugin import (
227
321
  StartupLoadingConfig,
228
322
  configure,
323
+ configure_antd,
324
+ configure_mantine,
229
325
  get_config,
230
326
  reset_config,
231
327
  )
232
328
  ```
233
329
 
234
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.
235
335
  - `get_config()` returns the current immutable configuration.
236
336
  - `reset_config()` restores all defaults. It is primarily useful in tests.
237
337
  - `StartupLoadingConfig` is the frozen dataclass containing all options.
@@ -329,120 +429,6 @@ This is expected with automatic `dash_hooks` discovery. Use a dedicated virtual
329
429
  environment, uninstall the package where it is not wanted, or call
330
430
  `configure(enabled=False)` before constructing those Dash apps.
331
431
 
332
- ## Development
333
-
334
- Clone the repository, then install the project and test dependencies:
335
-
336
- ```bash
337
- uv sync --extra test
338
- ```
339
-
340
- Run the tests and example:
341
-
342
- ```bash
343
- uv run pytest
344
- uv run --with dash-ant-design python examples/basic.py
345
- ```
346
-
347
- The example uses `dash_antd_components.ConfigProvider` to demonstrate native
348
- theme persistence, so `dash-ant-design` is an example-only dependency rather
349
- than a runtime dependency of the plugin.
350
-
351
- Build the source distribution and wheel:
352
-
353
- ```bash
354
- uv build
355
- ```
356
-
357
- ## Publishing to PyPI
358
-
359
- PyPI does not allow replacing an existing distribution file. Confirm that the
360
- version in `pyproject.toml` is new before building, then create the artifacts
361
- from a clean `dist/` directory:
362
-
363
- ```bash
364
- rm -rf build dist src/*.egg-info
365
- uv lock
366
- uv run --extra test pytest
367
- uvx ruff check src tests examples
368
- uv build
369
- uvx twine check dist/*
370
- ```
371
-
372
- Inspect the resulting files before upload:
373
-
374
- ```bash
375
- ls -lh dist/
376
- unzip -l dist/dash_startup_loading_plugin-0.2.0-py3-none-any.whl
377
- tar -tzf dist/dash_startup_loading_plugin-0.2.0.tar.gz
378
- uv publish --dry-run dist/*
379
- ```
380
-
381
- ### TestPyPI
382
-
383
- Create a TestPyPI API token, then upload to its legacy upload endpoint:
384
-
385
- ```bash
386
- export UV_PUBLISH_TOKEN="pypi-your-test-token"
387
- uv publish \
388
- --publish-url https://test.pypi.org/legacy/ \
389
- --check-url https://test.pypi.org/simple/ \
390
- dist/*
391
- unset UV_PUBLISH_TOKEN
392
- ```
393
-
394
- Test installation in an isolated environment:
395
-
396
- ```bash
397
- uv run --isolated \
398
- --index-url https://test.pypi.org/simple/ \
399
- --extra-index-url https://pypi.org/simple/ \
400
- --with dash-startup-loading-plugin==0.2.0 \
401
- python -c "import dash_startup_loading_plugin; print('import ok')"
402
- ```
403
-
404
- The extra PyPI index is needed because TestPyPI may not contain the plugin's
405
- runtime dependencies.
406
-
407
- ### PyPI with an API token
408
-
409
- Create a project-scoped PyPI token and publish the checked artifacts:
410
-
411
- ```bash
412
- export UV_PUBLISH_TOKEN="pypi-your-project-token"
413
- uv publish dist/*
414
- unset UV_PUBLISH_TOKEN
415
- ```
416
-
417
- Do not place tokens in `pyproject.toml`, shell history, source control, or CI
418
- logs.
419
-
420
- ### PyPI Trusted Publishing
421
-
422
- For CI releases, configure the repository and workflow as a Trusted Publisher
423
- in the PyPI project settings. The publishing job needs the
424
- `id-token: write` permission and can upload without a long-lived token:
425
-
426
- ```yaml
427
- permissions:
428
- contents: read
429
- id-token: write
430
-
431
- steps:
432
- - uses: actions/checkout@v4
433
- - uses: astral-sh/setup-uv@v8
434
- - run: uv build
435
- - run: uv publish --trusted-publishing always
436
- ```
437
-
438
- After publishing, verify the release:
439
-
440
- ```bash
441
- uv run --isolated \
442
- --with dash-startup-loading-plugin==0.2.0 \
443
- python -c "import dash_startup_loading_plugin; print('import ok')"
444
- ```
445
-
446
432
  ## License
447
433
 
448
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.2.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", "hooks"]
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>=3.0.3",
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"
@@ -5,11 +5,13 @@ from importlib.metadata import PackageNotFoundError, version
5
5
  try:
6
6
  __version__ = version("dash-startup-loading-plugin")
7
7
  except PackageNotFoundError: # pragma: no cover - source tree fallback
8
- __version__ = "0.2.0"
8
+ __version__ = "0.3.0"
9
9
 
10
- from .plugin import ( # noqa: E402
10
+ from .plugin import (
11
11
  StartupLoadingConfig,
12
12
  configure,
13
+ configure_antd,
14
+ configure_mantine,
13
15
  get_config,
14
16
  reset_config,
15
17
  )
@@ -18,6 +20,8 @@ __all__ = [
18
20
  "StartupLoadingConfig",
19
21
  "__version__",
20
22
  "configure",
23
+ "configure_antd",
24
+ "configure_mantine",
21
25
  "get_config",
22
26
  "reset_config",
23
27
  ]
@@ -4,12 +4,13 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  import re
7
+ from collections.abc import Iterable
7
8
  from dataclasses import asdict, dataclass, fields, replace
8
9
  from functools import lru_cache
9
10
  from html import escape
10
11
  from importlib.resources import files
11
12
  from threading import RLock
12
- from typing import Any, Iterable
13
+ from typing import Any
13
14
 
14
15
  from dash import hooks
15
16
 
@@ -17,6 +18,9 @@ _OVERLAY_MARKER = "data-dash-startup-loading"
17
18
  _BODY_PATTERN = re.compile(r"<body(?:\s[^>]*)?>", flags=re.IGNORECASE)
18
19
  _HEAD_END_PATTERN = re.compile(r"</head\s*>", flags=re.IGNORECASE)
19
20
  _CONFIG_LOCK = RLock()
21
+ _ANTD_LIGHT_BACKGROUND = "#ffffff"
22
+ _ANTD_DARK_BACKGROUND = "#121212"
23
+ _mantine_prerender_registered = False
20
24
 
21
25
 
22
26
  @dataclass(frozen=True)
@@ -78,8 +82,7 @@ def _validate(config: StartupLoadingConfig) -> StartupLoadingConfig:
78
82
  if config.theme_mode not in {"auto", "light", "dark"}:
79
83
  raise ValueError("theme_mode must be 'auto', 'light', or 'dark'")
80
84
  if config.dash_theme_component_id is not None and (
81
- not isinstance(config.dash_theme_component_id, str)
82
- or not config.dash_theme_component_id.strip()
85
+ not isinstance(config.dash_theme_component_id, str) or not config.dash_theme_component_id.strip()
83
86
  ):
84
87
  raise ValueError("dash_theme_component_id must be None or a non-empty string")
85
88
  for name in ("minimum_display_ms", "fade_duration_ms", "spinner_size_px", "spinner_stroke_px"):
@@ -109,6 +112,54 @@ def configure(**changes: Any) -> StartupLoadingConfig:
109
112
  return _config
110
113
 
111
114
 
115
+ def configure_mantine(**changes: Any) -> StartupLoadingConfig:
116
+ """Configure seamless startup colors for Dash Mantine Components.
117
+
118
+ Dash Mantine Components remains an optional dependency. This helper reads
119
+ its active default theme and registers its pre-render color-scheme hook.
120
+ Explicit keyword arguments override all integration defaults.
121
+ """
122
+
123
+ try:
124
+ import dash_mantine_components as dmc
125
+ except ImportError as error:
126
+ raise RuntimeError(
127
+ "configure_mantine requires dash-mantine-components>=2.6.0"
128
+ ) from error
129
+
130
+ pre_render_color_scheme = getattr(dmc, "pre_render_color_scheme", None)
131
+ if pre_render_color_scheme is None:
132
+ raise RuntimeError(
133
+ "configure_mantine requires dash-mantine-components>=2.6.0"
134
+ )
135
+
136
+ theme = dmc.DEFAULT_THEME
137
+ changes.setdefault("background", theme["white"])
138
+ changes.setdefault("dark_background", theme["colors"]["dark"][7])
139
+ changes.setdefault("pending_selector", None)
140
+
141
+ global _mantine_prerender_registered
142
+ with _CONFIG_LOCK:
143
+ if not _mantine_prerender_registered:
144
+ pre_render_color_scheme()
145
+ _mantine_prerender_registered = True
146
+
147
+ return configure(**changes)
148
+
149
+
150
+ def configure_antd(**changes: Any) -> StartupLoadingConfig:
151
+ """Configure startup colors for Dash Ant Design.
152
+
153
+ Explicit keyword arguments override the integration defaults, including
154
+ ``background`` and ``dark_background`` when the application's Ant Design
155
+ theme customizes its light or dark background token.
156
+ """
157
+
158
+ changes.setdefault("background", _ANTD_LIGHT_BACKGROUND)
159
+ changes.setdefault("dark_background", _ANTD_DARK_BACKGROUND)
160
+ return configure(**changes)
161
+
162
+
112
163
  def get_config() -> StartupLoadingConfig:
113
164
  """Return the active immutable configuration."""
114
165
 
@@ -181,12 +232,7 @@ def _overlay_html(config: StartupLoadingConfig) -> str:
181
232
 
182
233
  @lru_cache(maxsize=2)
183
234
  def _resource_text(name: str) -> str:
184
- return (
185
- files("dash_startup_loading_plugin")
186
- .joinpath("resources", name)
187
- .read_text(encoding="utf-8")
188
- .strip()
189
- )
235
+ return files("dash_startup_loading_plugin").joinpath("resources", name).read_text(encoding="utf-8").strip()
190
236
 
191
237
 
192
238
  def _inline_head_resources(app_index: str, config: StartupLoadingConfig) -> str:
@@ -218,11 +264,7 @@ def _inject_overlay(app_index: str) -> str:
218
264
  body_match = _BODY_PATTERN.search(app_index)
219
265
  assert body_match is not None
220
266
  position = body_match.end()
221
- script = (
222
- '<script data-dash-startup-loading-resource="script">'
223
- f"{_resource_text('startup-loading.js')}"
224
- "</script>"
225
- )
267
+ script = f'<script data-dash-startup-loading-resource="script">{_resource_text("startup-loading.js")}</script>'
226
268
  return app_index[:position] + _overlay_html(config) + script + app_index[position:]
227
269
 
228
270
 
@@ -1,17 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dash-startup-loading-plugin
3
- Version: 0.2.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,hooks
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>=3.0.3
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
@@ -51,7 +53,7 @@ discovery, resource hooks, and the index hook described in the official
51
53
  ## Installation
52
54
 
53
55
  ```bash
54
- pip install "dash-startup-loading-plugin>=0.2.0"
56
+ pip install "dash-startup-loading-plugin>=0.3.0"
55
57
  ```
56
58
 
57
59
  The package declares the following entry point:
@@ -66,6 +68,16 @@ package therefore enables the default startup overlay for Dash applications in
66
68
  that Python environment; an explicit import is only needed when changing its
67
69
  configuration or using its Python API.
68
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
+
69
81
  ## What's new in 0.2.0
70
82
 
71
83
  - Resolves the loading background before first paint from a persisted
@@ -104,25 +116,33 @@ from dash import Dash, html
104
116
  from dash_startup_loading_plugin import configure
105
117
 
106
118
  configure(
107
- required_selectors=["#page-header", "#sidebar-menu"],
119
+ required_selectors=["#usage-header", "#usage-sidebar-menu"],
108
120
  pending_selector="[data-dac-async-placeholder]",
109
121
  timeout_ms=6000,
110
- minimum_display_ms=200,
111
122
  fade_duration_ms=160,
112
- color="#1677ff",
113
- dark_color="#4096ff",
114
123
  )
115
124
 
116
125
  app = Dash(__name__)
117
126
  app.layout = html.Div(
118
127
  [
119
- html.Header("Dashboard", id="page-header"),
120
- html.Nav("Navigation", id="sidebar-menu"),
128
+ html.Header("Dashboard", id="usage-header"),
129
+ html.Nav("Navigation", id="usage-sidebar-menu"),
121
130
  ]
122
131
  )
123
132
  ```
124
133
 
125
- See [`examples/basic.py`](examples/basic.py) for a runnable example.
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
+ ```
126
146
 
127
147
  ## Readiness behavior
128
148
 
@@ -192,29 +212,105 @@ parsed. This isolates the overlay styling without changing classes or data
192
212
  attributes owned by Tailwind, Dash Mantine Components, or the application.
193
213
  The stylesheet also adjusts its animation for `prefers-reduced-motion`.
194
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
+
195
254
  ### Dash Ant Design persistence
196
255
 
197
- `dash_antd_components.ConfigProvider` can persist its `theme` prop. The startup
198
- plugin reads that same Dash persistence record on the next page load:
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:
199
262
 
200
263
  ```python
201
264
  import dash_antd_components as dac
202
- from dash_startup_loading_plugin import configure
265
+ from dash import Input, Output, clientside_callback
266
+ from dash_startup_loading_plugin import configure_antd
203
267
 
204
- configure(dash_theme_component_id="theme-provider")
268
+ configure_antd()
205
269
 
206
270
  provider = dac.ConfigProvider(
207
- app_content,
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
+ ],
208
282
  id="theme-provider",
209
- persistence=True,
210
- persisted_props=["theme"],
211
- persistence_type="local",
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",
212
310
  )
213
311
  ```
214
312
 
215
- Update `theme-provider.theme` from a regular or clientside callback. Dash stores
216
- the UI edit, `ConfigProvider` restores it after mount, and the startup plugin
217
- uses it for the loading background before mount. See
313
+ See
218
314
  [`examples/basic.py`](examples/basic.py) for the complete switcher.
219
315
 
220
316
  ### Custom loader markup
@@ -242,12 +338,18 @@ configuration. Never populate it with user input.
242
338
  from dash_startup_loading_plugin import (
243
339
  StartupLoadingConfig,
244
340
  configure,
341
+ configure_antd,
342
+ configure_mantine,
245
343
  get_config,
246
344
  reset_config,
247
345
  )
248
346
  ```
249
347
 
250
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.
251
353
  - `get_config()` returns the current immutable configuration.
252
354
  - `reset_config()` restores all defaults. It is primarily useful in tests.
253
355
  - `StartupLoadingConfig` is the frozen dataclass containing all options.
@@ -345,120 +447,6 @@ This is expected with automatic `dash_hooks` discovery. Use a dedicated virtual
345
447
  environment, uninstall the package where it is not wanted, or call
346
448
  `configure(enabled=False)` before constructing those Dash apps.
347
449
 
348
- ## Development
349
-
350
- Clone the repository, then install the project and test dependencies:
351
-
352
- ```bash
353
- uv sync --extra test
354
- ```
355
-
356
- Run the tests and example:
357
-
358
- ```bash
359
- uv run pytest
360
- uv run --with dash-ant-design python examples/basic.py
361
- ```
362
-
363
- The example uses `dash_antd_components.ConfigProvider` to demonstrate native
364
- theme persistence, so `dash-ant-design` is an example-only dependency rather
365
- than a runtime dependency of the plugin.
366
-
367
- Build the source distribution and wheel:
368
-
369
- ```bash
370
- uv build
371
- ```
372
-
373
- ## Publishing to PyPI
374
-
375
- PyPI does not allow replacing an existing distribution file. Confirm that the
376
- version in `pyproject.toml` is new before building, then create the artifacts
377
- from a clean `dist/` directory:
378
-
379
- ```bash
380
- rm -rf build dist src/*.egg-info
381
- uv lock
382
- uv run --extra test pytest
383
- uvx ruff check src tests examples
384
- uv build
385
- uvx twine check dist/*
386
- ```
387
-
388
- Inspect the resulting files before upload:
389
-
390
- ```bash
391
- ls -lh dist/
392
- unzip -l dist/dash_startup_loading_plugin-0.2.0-py3-none-any.whl
393
- tar -tzf dist/dash_startup_loading_plugin-0.2.0.tar.gz
394
- uv publish --dry-run dist/*
395
- ```
396
-
397
- ### TestPyPI
398
-
399
- Create a TestPyPI API token, then upload to its legacy upload endpoint:
400
-
401
- ```bash
402
- export UV_PUBLISH_TOKEN="pypi-your-test-token"
403
- uv publish \
404
- --publish-url https://test.pypi.org/legacy/ \
405
- --check-url https://test.pypi.org/simple/ \
406
- dist/*
407
- unset UV_PUBLISH_TOKEN
408
- ```
409
-
410
- Test installation in an isolated environment:
411
-
412
- ```bash
413
- uv run --isolated \
414
- --index-url https://test.pypi.org/simple/ \
415
- --extra-index-url https://pypi.org/simple/ \
416
- --with dash-startup-loading-plugin==0.2.0 \
417
- python -c "import dash_startup_loading_plugin; print('import ok')"
418
- ```
419
-
420
- The extra PyPI index is needed because TestPyPI may not contain the plugin's
421
- runtime dependencies.
422
-
423
- ### PyPI with an API token
424
-
425
- Create a project-scoped PyPI token and publish the checked artifacts:
426
-
427
- ```bash
428
- export UV_PUBLISH_TOKEN="pypi-your-project-token"
429
- uv publish dist/*
430
- unset UV_PUBLISH_TOKEN
431
- ```
432
-
433
- Do not place tokens in `pyproject.toml`, shell history, source control, or CI
434
- logs.
435
-
436
- ### PyPI Trusted Publishing
437
-
438
- For CI releases, configure the repository and workflow as a Trusted Publisher
439
- in the PyPI project settings. The publishing job needs the
440
- `id-token: write` permission and can upload without a long-lived token:
441
-
442
- ```yaml
443
- permissions:
444
- contents: read
445
- id-token: write
446
-
447
- steps:
448
- - uses: actions/checkout@v4
449
- - uses: astral-sh/setup-uv@v8
450
- - run: uv build
451
- - run: uv publish --trusted-publishing always
452
- ```
453
-
454
- After publishing, verify the release:
455
-
456
- ```bash
457
- uv run --isolated \
458
- --with dash-startup-loading-plugin==0.2.0 \
459
- python -c "import dash_startup_loading_plugin; print('import ok')"
460
- ```
461
-
462
450
  ## License
463
451
 
464
452
  MIT. See [`LICENSE`](LICENSE).
@@ -0,0 +1,7 @@
1
+ dash==4.4.1
2
+
3
+ [mantine]
4
+ dash-mantine-components>=2.6.0
5
+
6
+ [test]
7
+ pytest>=8
@@ -1,12 +1,21 @@
1
1
  import html
2
2
  import json
3
3
  import re
4
+ import sys
4
5
  from importlib.resources import files
6
+ from types import SimpleNamespace
5
7
 
6
8
  import pytest
7
9
  from dash import Dash
8
10
  from dash import html as dash_html
9
- from dash_startup_loading_plugin import configure, get_config, reset_config
11
+
12
+ from dash_startup_loading_plugin import (
13
+ configure,
14
+ configure_antd,
15
+ configure_mantine,
16
+ get_config,
17
+ reset_config,
18
+ )
10
19
  from dash_startup_loading_plugin.plugin import _inject_overlay
11
20
 
12
21
 
@@ -99,6 +108,40 @@ def test_configuration_validation():
99
108
  assert get_config().required_selectors == ("#react-entry-point",)
100
109
 
101
110
 
111
+ def test_mantine_configuration_uses_semantic_theme_defaults(monkeypatch):
112
+ calls = []
113
+ fake_dmc = SimpleNamespace(
114
+ DEFAULT_THEME={
115
+ "white": "#fff",
116
+ "colors": {"dark": [""] * 7 + ["#242424"]},
117
+ },
118
+ pre_render_color_scheme=lambda: calls.append("registered"),
119
+ )
120
+ monkeypatch.setitem(sys.modules, "dash_mantine_components", fake_dmc)
121
+ monkeypatch.setattr(
122
+ "dash_startup_loading_plugin.plugin._mantine_prerender_registered",
123
+ False,
124
+ )
125
+
126
+ config = configure_mantine(minimum_display_ms=200)
127
+
128
+ assert config.background == "#fff"
129
+ assert config.dark_background == "#242424"
130
+ assert config.pending_selector is None
131
+ assert config.minimum_display_ms == 200
132
+ assert calls == ["registered"]
133
+
134
+
135
+ def test_antd_configuration_matches_library_backgrounds_and_allows_overrides():
136
+ config = configure_antd()
137
+ assert config.background == "#ffffff"
138
+ assert config.dark_background == "#121212"
139
+
140
+ config = configure_antd(background="#f5f5f5", dark_background="#202020")
141
+ assert config.background == "#f5f5f5"
142
+ assert config.dark_background == "#202020"
143
+
144
+
102
145
  def test_resolved_startup_theme_controls_overlay_colors():
103
146
  css = (
104
147
  files("dash_startup_loading_plugin")
@@ -1,4 +0,0 @@
1
- dash>=3.0.3
2
-
3
- [test]
4
- pytest>=8