dash-startup-loading-plugin 1.0.1__tar.gz → 1.0.3__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 (32) hide show
  1. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/MANIFEST.in +1 -0
  2. {dash_startup_loading_plugin-1.0.1/src/dash_startup_loading_plugin.egg-info → dash_startup_loading_plugin-1.0.3}/PKG-INFO +14 -9
  3. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/README.md +13 -8
  4. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/README.zh-CN.md +11 -7
  5. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/pyproject.toml +7 -2
  6. dash_startup_loading_plugin-1.0.3/src/dash_startup_loading_plugin/README.md +265 -0
  7. dash_startup_loading_plugin-1.0.3/src/dash_startup_loading_plugin/README.zh-CN.md +253 -0
  8. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/__init__.py +1 -1
  9. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/plugin.py +1 -1
  10. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3/src/dash_startup_loading_plugin.egg-info}/PKG-INFO +14 -9
  11. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin.egg-info/SOURCES.txt +2 -0
  12. dash_startup_loading_plugin-1.0.3/tests/test_documentation.py +72 -0
  13. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/tests/test_plugin.py +9 -0
  14. dash_startup_loading_plugin-1.0.1/tests/test_documentation.py +0 -28
  15. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/LICENSE +0 -0
  16. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/setup.cfg +0 -0
  17. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/__init__.py +0 -0
  18. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/__main__.py +0 -0
  19. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/antd.py +0 -0
  20. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/basic.py +0 -0
  21. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/cli.py +0 -0
  22. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/fac.py +0 -0
  23. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/mantine.py +0 -0
  24. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/examples/shared.py +0 -0
  25. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/resources/loading.css +0 -0
  26. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/resources/loading.js +0 -0
  27. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin/resources/theme.js +0 -0
  28. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin.egg-info/dependency_links.txt +0 -0
  29. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin.egg-info/entry_points.txt +0 -0
  30. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin.egg-info/requires.txt +0 -0
  31. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/src/dash_startup_loading_plugin.egg-info/top_level.txt +0 -0
  32. {dash_startup_loading_plugin-1.0.1 → dash_startup_loading_plugin-1.0.3}/tests/test_examples.py +0 -0
@@ -1 +1,2 @@
1
1
  include README.zh-CN.md
2
+ include README.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dash-startup-loading-plugin
3
- Version: 1.0.1
3
+ Version: 1.0.3
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
@@ -14,7 +14,8 @@ Dynamic: license-file
14
14
 
15
15
  # dash-startup-loading-plugin
16
16
 
17
- [English](README.md) | [简体中文](README.zh-CN.md)
17
+ [English](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.md) |
18
+ [简体中文](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.zh-CN.md)
18
19
 
19
20
  An installable [Dash Hooks plugin](https://dash.plotly.com/dash-plugins-using-hooks)
20
21
  that replaces Dash's initial loading presentation with a configurable
@@ -33,7 +34,7 @@ document.
33
34
  ## Installation
34
35
 
35
36
  ```bash
36
- pip install "dash-startup-loading-plugin>=1.0.1"
37
+ pip install "dash-startup-loading-plugin>=1.0.3"
37
38
  ```
38
39
 
39
40
  Dash discovers the plugin through its `dash_hooks` entry point. Installing the
@@ -61,6 +62,10 @@ if __name__ == "__main__":
61
62
  app.run(debug=True)
62
63
  ```
63
64
 
65
+ By default, the overlay only replaces Dash's built-in `._dash-loading`
66
+ animation and closes once Dash has rendered the application layout. Waiting
67
+ for lazy or asynchronous component placeholders is opt-in.
68
+
64
69
  Call `configure()` before creating `Dash` when custom behavior is needed:
65
70
 
66
71
  ```python
@@ -179,16 +184,16 @@ The overlay closes when:
179
184
  1. `root_selector` exists and no longer contains `._dash-loading`.
180
185
  2. The root contains rendered content.
181
186
  3. Every `required_selectors` entry exists.
182
- 4. No `pending_selector` node remains under the root.
187
+ 4. If `pending_selector` is configured, no matching node remains under the root.
183
188
  5. The conditions remain true for two animation frames.
184
189
 
185
190
  `timeout_ms` is a forced-dismiss fallback. `minimum_display_ms` applies to
186
191
  ready and manual dismissal, but does not delay a timeout.
187
192
 
188
- `pending_selector` delays dismissal while any matching element remains inside
189
- `root_selector`. It is useful for lazy or asynchronous placeholders that are
190
- mounted before the real content. Set it to an application-specific CSS
191
- selector, or use `None` when no pending-node check is needed:
193
+ `pending_selector` optionally delays dismissal while any matching element
194
+ remains inside `root_selector`. It is useful for lazy or asynchronous
195
+ placeholders that are mounted before the real content. The check is disabled
196
+ by default; opt in with an application-specific CSS selector:
192
197
 
193
198
  ```python
194
199
  configure(pending_selector="[data-async-placeholder]")
@@ -207,7 +212,7 @@ configure(pending_selector=None)
207
212
  | `aria_label` | `"Loading"` | Accessible status label. |
208
213
  | `root_selector` | `"#react-entry-point"` | Root observed for rendered content. |
209
214
  | `required_selectors` | `("#react-entry-point",)` | Selectors that must exist before dismissal. |
210
- | `pending_selector` | `"[data-dac-async-placeholder]"` | Selector checked under `root_selector`; dismissal waits until all matches disappear. Use `None` to disable. |
215
+ | `pending_selector` | `None` | Optional selector checked under `root_selector`; when configured, dismissal waits until all matches disappear. |
211
216
  | `timeout_ms` | `6000` | Forced-dismiss timeout; use `None` to disable. |
212
217
  | `minimum_display_ms` | `0` | Minimum display time. |
213
218
  | `fade_duration_ms` | `160` | Fade-out duration. |
@@ -1,6 +1,7 @@
1
1
  # dash-startup-loading-plugin
2
2
 
3
- [English](README.md) | [简体中文](README.zh-CN.md)
3
+ [English](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.md) |
4
+ [简体中文](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.zh-CN.md)
4
5
 
5
6
  An installable [Dash Hooks plugin](https://dash.plotly.com/dash-plugins-using-hooks)
6
7
  that replaces Dash's initial loading presentation with a configurable
@@ -19,7 +20,7 @@ document.
19
20
  ## Installation
20
21
 
21
22
  ```bash
22
- pip install "dash-startup-loading-plugin>=1.0.1"
23
+ pip install "dash-startup-loading-plugin>=1.0.3"
23
24
  ```
24
25
 
25
26
  Dash discovers the plugin through its `dash_hooks` entry point. Installing the
@@ -47,6 +48,10 @@ if __name__ == "__main__":
47
48
  app.run(debug=True)
48
49
  ```
49
50
 
51
+ By default, the overlay only replaces Dash's built-in `._dash-loading`
52
+ animation and closes once Dash has rendered the application layout. Waiting
53
+ for lazy or asynchronous component placeholders is opt-in.
54
+
50
55
  Call `configure()` before creating `Dash` when custom behavior is needed:
51
56
 
52
57
  ```python
@@ -165,16 +170,16 @@ The overlay closes when:
165
170
  1. `root_selector` exists and no longer contains `._dash-loading`.
166
171
  2. The root contains rendered content.
167
172
  3. Every `required_selectors` entry exists.
168
- 4. No `pending_selector` node remains under the root.
173
+ 4. If `pending_selector` is configured, no matching node remains under the root.
169
174
  5. The conditions remain true for two animation frames.
170
175
 
171
176
  `timeout_ms` is a forced-dismiss fallback. `minimum_display_ms` applies to
172
177
  ready and manual dismissal, but does not delay a timeout.
173
178
 
174
- `pending_selector` delays dismissal while any matching element remains inside
175
- `root_selector`. It is useful for lazy or asynchronous placeholders that are
176
- mounted before the real content. Set it to an application-specific CSS
177
- selector, or use `None` when no pending-node check is needed:
179
+ `pending_selector` optionally delays dismissal while any matching element
180
+ remains inside `root_selector`. It is useful for lazy or asynchronous
181
+ placeholders that are mounted before the real content. The check is disabled
182
+ by default; opt in with an application-specific CSS selector:
178
183
 
179
184
  ```python
180
185
  configure(pending_selector="[data-async-placeholder]")
@@ -193,7 +198,7 @@ configure(pending_selector=None)
193
198
  | `aria_label` | `"Loading"` | Accessible status label. |
194
199
  | `root_selector` | `"#react-entry-point"` | Root observed for rendered content. |
195
200
  | `required_selectors` | `("#react-entry-point",)` | Selectors that must exist before dismissal. |
196
- | `pending_selector` | `"[data-dac-async-placeholder]"` | Selector checked under `root_selector`; dismissal waits until all matches disappear. Use `None` to disable. |
201
+ | `pending_selector` | `None` | Optional selector checked under `root_selector`; when configured, dismissal waits until all matches disappear. |
197
202
  | `timeout_ms` | `6000` | Forced-dismiss timeout; use `None` to disable. |
198
203
  | `minimum_display_ms` | `0` | Minimum display time. |
199
204
  | `fade_duration_ms` | `160` | Fade-out duration. |
@@ -1,6 +1,7 @@
1
1
  # dash-startup-loading-plugin
2
2
 
3
- [English](README.md) | [简体中文](README.zh-CN.md)
3
+ [English](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.md) |
4
+ [简体中文](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.zh-CN.md)
4
5
 
5
6
  一个基于 [Dash Hooks 插件规范](https://dash.plotly.com/dash-plugins-using-hooks)
6
7
  的可安装插件,用于将 Dash 初始加载提示替换为可配置的全屏 loading 遮罩。
@@ -17,7 +18,7 @@
17
18
  ## 安装
18
19
 
19
20
  ```bash
20
- pip install "dash-startup-loading-plugin>=1.0.1"
21
+ pip install "dash-startup-loading-plugin>=1.0.3"
21
22
  ```
22
23
 
23
24
  Dash 会通过 `dash_hooks` entry point 自动发现插件。安装后,默认 loading
@@ -45,6 +46,9 @@ if __name__ == "__main__":
45
46
  app.run(debug=True)
46
47
  ```
47
48
 
49
+ 默认情况下,遮罩只替换 Dash 自带的 `._dash-loading` 动画,并在 Dash
50
+ 渲染出应用布局后关闭。等待懒加载或异步组件的占位节点消失属于可选行为。
51
+
48
52
  如需自定义行为,请在创建 `Dash` 实例前调用 `configure()`:
49
53
 
50
54
  ```python
@@ -159,15 +163,15 @@ dash-startup-loading-plugin examples.dash \
159
163
  1. `root_selector` 已存在,且内部不再包含 `._dash-loading`。
160
164
  2. 根节点中已有实际渲染内容。
161
165
  3. `required_selectors` 中的所有选择器都已匹配到节点。
162
- 4. 根节点中已不存在匹配 `pending_selector` 的节点。
166
+ 4. 如果配置了 `pending_selector`,根节点中已不存在匹配它的节点。
163
167
  5. 上述状态连续保持两个动画帧。
164
168
 
165
169
  `timeout_ms` 是强制关闭的安全兜底。`minimum_display_ms` 适用于正常就绪和
166
170
  手动关闭,但不会延迟 timeout。
167
171
 
168
- `pending_selector` 用于在异步或懒加载占位节点仍存在时延迟关闭遮罩。它只会
169
- 在 `root_selector` 内查找匹配节点。可以设置为应用自己的 CSS 选择器;如果
170
- 不需要检查占位节点,请设置为 `None`:
172
+ `pending_selector` 可用于在异步或懒加载占位节点仍存在时延迟关闭遮罩。它只会
173
+ 在 `root_selector` 内查找匹配节点。该检查默认关闭;如需等待异步组件加载完成,
174
+ 请显式设置为应用自己的 CSS 选择器:
171
175
 
172
176
  ```python
173
177
  configure(pending_selector="[data-async-placeholder]")
@@ -185,7 +189,7 @@ configure(pending_selector=None)
185
189
  | `aria_label` | `"Loading"` | 无障碍状态标签。 |
186
190
  | `root_selector` | `"#react-entry-point"` | 用于观察渲染内容的根节点。 |
187
191
  | `required_selectors` | `("#react-entry-point",)` | 关闭遮罩前必须存在的节点选择器。 |
188
- | `pending_selector` | `"[data-dac-async-placeholder]"` | 在 `root_selector` 内检查;所有匹配节点消失后才允许关闭。设置为 `None` 可禁用。 |
192
+ | `pending_selector` | `None` | 可选的根节点内选择器;配置后,所有匹配节点消失才允许关闭。 |
189
193
  | `timeout_ms` | `6000` | 强制关闭超时;设置为 `None` 可禁用。 |
190
194
  | `minimum_display_ms` | `0` | 最短显示时间。 |
191
195
  | `fade_duration_ms` | `160` | 淡出时长。 |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dash-startup-loading-plugin"
7
- version = "1.0.1"
7
+ version = "1.0.3"
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"
@@ -38,7 +38,12 @@ include-package-data = true
38
38
  where = ["src"]
39
39
 
40
40
  [tool.setuptools.package-data]
41
- dash_startup_loading_plugin = ["resources/*.css", "resources/*.js"]
41
+ dash_startup_loading_plugin = [
42
+ "README.md",
43
+ "README.zh-CN.md",
44
+ "resources/*.css",
45
+ "resources/*.js",
46
+ ]
42
47
 
43
48
  [tool.pytest.ini_options]
44
49
  addopts = "-q -p no:cacheprovider"
@@ -0,0 +1,265 @@
1
+ # dash-startup-loading-plugin
2
+
3
+ [English](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.md) |
4
+ [简体中文](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.zh-CN.md)
5
+
6
+ An installable [Dash Hooks plugin](https://dash.plotly.com/dash-plugins-using-hooks)
7
+ that replaces Dash's initial loading presentation with a configurable
8
+ full-screen overlay.
9
+
10
+ The plugin injects its CSS and JavaScript into Dash's normal index document
11
+ before React mounts. Applications do not need to copy assets or replace
12
+ `index_string`, and Dash's built-in `<div class="_dash-loading">` remains in the
13
+ document.
14
+
15
+ ## Requirements
16
+
17
+ - Python 3.9 or later
18
+ - Dash 3.0.3 or later
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install "dash-startup-loading-plugin>=1.0.3"
24
+ ```
25
+
26
+ Dash discovers the plugin through its `dash_hooks` entry point. Installing the
27
+ package enables the default loading overlay without an explicit import.
28
+
29
+ When Dash Ant Design (`dash_antd_components`) is installed, the plugin detects
30
+ it automatically and applies matching light and dark loading backgrounds.
31
+
32
+ ## Quick start
33
+
34
+ The default configuration requires no plugin-specific code:
35
+
36
+ ```python
37
+ from dash import Dash, html
38
+
39
+ app = Dash(__name__)
40
+ app.layout = html.Main(
41
+ [
42
+ html.H1("My Dash app"),
43
+ html.P("The overlay closes after this layout is ready."),
44
+ ]
45
+ )
46
+
47
+ if __name__ == "__main__":
48
+ app.run(debug=True)
49
+ ```
50
+
51
+ By default, the overlay only replaces Dash's built-in `._dash-loading`
52
+ animation and closes once Dash has rendered the application layout. Waiting
53
+ for lazy or asynchronous component placeholders is opt-in.
54
+
55
+ Call `configure()` before creating `Dash` when custom behavior is needed:
56
+
57
+ ```python
58
+ from dash import Dash, html
59
+ from dash_startup_loading_plugin import configure
60
+
61
+ configure(
62
+ required_selectors=["#header", "#sidebar-menu"],
63
+ pending_selector="[data-async-placeholder]",
64
+ timeout_ms=6000,
65
+ minimum_display_ms=250,
66
+ fade_duration_ms=180,
67
+ )
68
+
69
+ app = Dash(__name__)
70
+ app.layout = html.Main(
71
+ [
72
+ html.Header("Header", id="header"),
73
+ html.Nav("Sidebar", id="sidebar-menu"),
74
+ ]
75
+ )
76
+ ```
77
+
78
+ ## Component-library integrations
79
+
80
+ Component libraries are not dependencies of this package. Install only the
81
+ libraries used by the application.
82
+
83
+ ### Dash Ant Design
84
+
85
+ Dash Ant Design is detected automatically. `configure_dac()` is only required
86
+ to override its defaults:
87
+
88
+ ```bash
89
+ pip install dash-ant-design
90
+ ```
91
+
92
+ The plugin does not impose a Dash Ant Design version constraint. Use the
93
+ version compatible with the application's Python and Dash versions.
94
+
95
+ ```python
96
+ from dash_startup_loading_plugin import configure_dac
97
+
98
+ configure_dac(
99
+ background="#f5f5f5",
100
+ dark_background="#202020",
101
+ )
102
+ ```
103
+
104
+ ### Dash Mantine Components
105
+
106
+ `configure_dmc()` uses Mantine's active default theme and registers its
107
+ pre-render color-scheme hook:
108
+
109
+ ```bash
110
+ pip install dash-mantine-components
111
+ ```
112
+
113
+ ```python
114
+ from dash_startup_loading_plugin import configure_dmc
115
+
116
+ configure_dmc()
117
+ ```
118
+
119
+ ### feffery-antd-components
120
+
121
+ Use `configure_fac()` to match the loading overlay to
122
+ `AntdConfigProvider`:
123
+
124
+ ```bash
125
+ pip install feffery-antd-components
126
+ ```
127
+
128
+ The plugin does not pin a feffery-antd-components version. Compatibility is
129
+ determined by the installed component library.
130
+
131
+ ```python
132
+ from dash_startup_loading_plugin import configure_fac
133
+
134
+ configure_fac(required_selectors=["#fac-app-ready"])
135
+ ```
136
+
137
+ ## Installed examples
138
+
139
+ The package includes four runnable examples:
140
+
141
+ ```bash
142
+ # Dash
143
+ dash-startup-loading-plugin examples.dash
144
+
145
+ # Dash Mantine Components
146
+ dash-startup-loading-plugin examples.dash-mantine-components
147
+
148
+ # Dash Ant Design
149
+ dash-startup-loading-plugin examples.dash-ant-design
150
+
151
+ # feffery-antd-components
152
+ dash-startup-loading-plugin examples.feffery-antd-components
153
+ ```
154
+
155
+ Install the selected example's component library separately. If it cannot be
156
+ imported, the command reports the failed module and the corresponding
157
+ installation command.
158
+
159
+ Server options are available on every example:
160
+
161
+ ```bash
162
+ dash-startup-loading-plugin examples.dash \
163
+ --host 127.0.0.1 --port 8050 --debug
164
+ ```
165
+
166
+ ## Readiness behavior
167
+
168
+ The overlay closes when:
169
+
170
+ 1. `root_selector` exists and no longer contains `._dash-loading`.
171
+ 2. The root contains rendered content.
172
+ 3. Every `required_selectors` entry exists.
173
+ 4. If `pending_selector` is configured, no matching node remains under the root.
174
+ 5. The conditions remain true for two animation frames.
175
+
176
+ `timeout_ms` is a forced-dismiss fallback. `minimum_display_ms` applies to
177
+ ready and manual dismissal, but does not delay a timeout.
178
+
179
+ `pending_selector` optionally delays dismissal while any matching element
180
+ remains inside `root_selector`. It is useful for lazy or asynchronous
181
+ placeholders that are mounted before the real content. The check is disabled
182
+ by default; opt in with an application-specific CSS selector:
183
+
184
+ ```python
185
+ configure(pending_selector="[data-async-placeholder]")
186
+ configure(pending_selector=None)
187
+ ```
188
+
189
+ ## Configuration
190
+
191
+ `configure(**changes)` updates the process-wide immutable
192
+ `StartupLoadingConfig`.
193
+
194
+ | Option | Default | Description |
195
+ |---|---:|---|
196
+ | `enabled` | `True` | Enable index injection. |
197
+ | `overlay_id` | `"dash-loading"` | Injected overlay ID. |
198
+ | `aria_label` | `"Loading"` | Accessible status label. |
199
+ | `root_selector` | `"#react-entry-point"` | Root observed for rendered content. |
200
+ | `required_selectors` | `("#react-entry-point",)` | Selectors that must exist before dismissal. |
201
+ | `pending_selector` | `None` | Optional selector checked under `root_selector`; when configured, dismissal waits until all matches disappear. |
202
+ | `timeout_ms` | `6000` | Forced-dismiss timeout; use `None` to disable. |
203
+ | `minimum_display_ms` | `0` | Minimum display time. |
204
+ | `fade_duration_ms` | `160` | Fade-out duration. |
205
+ | `z_index` | `9999` | Overlay stacking order. |
206
+ | `background` | `"#ffffff"` | Light background. |
207
+ | `dark_background` | `"#0f0f0f"` | Dark background. |
208
+ | `color` | `"#1677ff"` | Light spinner color. |
209
+ | `dark_color` | `"#4096ff"` | Dark spinner color. |
210
+ | `theme_mode` | `"auto"` | `"auto"`, `"light"`, or `"dark"`. |
211
+ | `dash_theme_component_id` | `None` | Preferred persisted Dash theme component. |
212
+ | `spinner_size_px` | `28` | Spinner width and height. |
213
+ | `spinner_stroke_px` | `3` | Spinner stroke width. |
214
+ | `hide_default_loading` | `True` | Hide the visual `._dash-loading` indicator while the overlay exists. |
215
+ | `custom_loader_html` | `None` | Trusted HTML replacing the default spinner. |
216
+
217
+ `custom_loader_html` is inserted verbatim and must never contain untrusted
218
+ user input.
219
+
220
+ ## Python API
221
+
222
+ ```python
223
+ from dash_startup_loading_plugin import (
224
+ StartupLoadingConfig,
225
+ configure,
226
+ configure_dac,
227
+ configure_fac,
228
+ configure_dmc,
229
+ get_config,
230
+ reset_config,
231
+ )
232
+ ```
233
+
234
+ ## Browser API
235
+
236
+ ```javascript
237
+ // Recheck readiness.
238
+ window.dashLoading.check();
239
+
240
+ // Dismiss the default or a custom overlay.
241
+ window.dashLoading.finish();
242
+ window.dashLoading.finish("my-loading-overlay");
243
+ ```
244
+
245
+ Before fading out, the overlay emits a bubbling `dash-loading:ready` event.
246
+ `event.detail.reason` is `"ready"`, `"timeout"`, or `"manual"`.
247
+
248
+ ```javascript
249
+ document.addEventListener("dash-loading:ready", function (event) {
250
+ console.log(event.detail.reason);
251
+ });
252
+ ```
253
+
254
+ ## Notes
255
+
256
+ - Dash's hook and plugin configuration is process-wide. Use one configuration
257
+ per process.
258
+ - Resources are inlined, so strict Content Security Policy deployments must
259
+ allow the injected style and script.
260
+ - The overlay is only for initial application startup. Use `dcc.Loading` or
261
+ another callback-specific pattern for later callback execution.
262
+
263
+ ## License
264
+
265
+ MIT
@@ -0,0 +1,253 @@
1
+ # dash-startup-loading-plugin
2
+
3
+ [English](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.md) |
4
+ [简体中文](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.zh-CN.md)
5
+
6
+ 一个基于 [Dash Hooks 插件规范](https://dash.plotly.com/dash-plugins-using-hooks)
7
+ 的可安装插件,用于将 Dash 初始加载提示替换为可配置的全屏 loading 遮罩。
8
+
9
+ 插件会在 React 挂载前,将 CSS 和 JavaScript 注入 Dash 的标准 index
10
+ 文档。应用无需复制 assets,也无需替换 `index_string`。Dash 自带的
11
+ `<div class="_dash-loading">` 节点仍会保留。
12
+
13
+ ## 环境要求
14
+
15
+ - Python 3.9 或更高版本
16
+ - Dash 3.0.3 或更高版本
17
+
18
+ ## 安装
19
+
20
+ ```bash
21
+ pip install "dash-startup-loading-plugin>=1.0.3"
22
+ ```
23
+
24
+ Dash 会通过 `dash_hooks` entry point 自动发现插件。安装后,默认 loading
25
+ 效果会自动启用,无需在应用中显式导入。
26
+
27
+ 如果环境中安装了 Dash Ant Design(`dash_antd_components`),插件会自动
28
+ 识别并应用与其亮色、暗色主题匹配的 loading 背景。
29
+
30
+ ## 快速开始
31
+
32
+ 默认配置无需编写插件相关代码:
33
+
34
+ ```python
35
+ from dash import Dash, html
36
+
37
+ app = Dash(__name__)
38
+ app.layout = html.Main(
39
+ [
40
+ html.H1("My Dash app"),
41
+ html.P("The overlay closes after this layout is ready."),
42
+ ]
43
+ )
44
+
45
+ if __name__ == "__main__":
46
+ app.run(debug=True)
47
+ ```
48
+
49
+ 默认情况下,遮罩只替换 Dash 自带的 `._dash-loading` 动画,并在 Dash
50
+ 渲染出应用布局后关闭。等待懒加载或异步组件的占位节点消失属于可选行为。
51
+
52
+ 如需自定义行为,请在创建 `Dash` 实例前调用 `configure()`:
53
+
54
+ ```python
55
+ from dash import Dash, html
56
+ from dash_startup_loading_plugin import configure
57
+
58
+ configure(
59
+ required_selectors=["#header", "#sidebar-menu"],
60
+ pending_selector="[data-async-placeholder]",
61
+ timeout_ms=6000,
62
+ minimum_display_ms=250,
63
+ fade_duration_ms=180,
64
+ )
65
+
66
+ app = Dash(__name__)
67
+ app.layout = html.Main(
68
+ [
69
+ html.Header("Header", id="header"),
70
+ html.Nav("Sidebar", id="sidebar-menu"),
71
+ ]
72
+ )
73
+ ```
74
+
75
+ ## 组件库集成
76
+
77
+ 各组件库不是本插件的依赖。应用只需单独安装实际使用的组件库。
78
+
79
+ ### Dash Ant Design
80
+
81
+ 插件会自动识别 Dash Ant Design。只有需要覆盖默认配置时,才需要调用
82
+ `configure_dac()`:
83
+
84
+ ```bash
85
+ pip install dash-ant-design
86
+ ```
87
+
88
+ 本插件不限制 Dash Ant Design 的版本。请安装与应用所用 Python 和 Dash
89
+ 版本兼容的版本。
90
+
91
+ ```python
92
+ from dash_startup_loading_plugin import configure_dac
93
+
94
+ configure_dac(
95
+ background="#f5f5f5",
96
+ dark_background="#202020",
97
+ )
98
+ ```
99
+
100
+ ### Dash Mantine Components
101
+
102
+ `configure_dmc()` 会读取 Mantine 的当前默认主题,并注册其预渲染配色
103
+ hook:
104
+
105
+ ```bash
106
+ pip install dash-mantine-components
107
+ ```
108
+
109
+ ```python
110
+ from dash_startup_loading_plugin import configure_dmc
111
+
112
+ configure_dmc()
113
+ ```
114
+
115
+ ### feffery-antd-components
116
+
117
+ 使用 `configure_fac()` 使 loading 遮罩与 `AntdConfigProvider` 匹配:
118
+
119
+ ```bash
120
+ pip install feffery-antd-components
121
+ ```
122
+
123
+ 本插件不固定 feffery-antd-components 的版本,兼容性由已安装的组件库决定。
124
+
125
+ ```python
126
+ from dash_startup_loading_plugin import configure_fac
127
+
128
+ configure_fac(required_selectors=["#fac-app-ready"])
129
+ ```
130
+
131
+ ## 内置示例
132
+
133
+ 安装包中包含四个可直接运行的示例:
134
+
135
+ ```bash
136
+ # Dash
137
+ dash-startup-loading-plugin examples.dash
138
+
139
+ # Dash Mantine Components
140
+ dash-startup-loading-plugin examples.dash-mantine-components
141
+
142
+ # Dash Ant Design
143
+ dash-startup-loading-plugin examples.dash-ant-design
144
+
145
+ # feffery-antd-components
146
+ dash-startup-loading-plugin examples.feffery-antd-components
147
+ ```
148
+
149
+ 组件库需要单独安装。如果所选示例无法导入对应组件库,命令会显示导入失败的
150
+ 模块和安装命令。
151
+
152
+ 所有示例都支持服务器参数:
153
+
154
+ ```bash
155
+ dash-startup-loading-plugin examples.dash \
156
+ --host 127.0.0.1 --port 8050 --debug
157
+ ```
158
+
159
+ ## 就绪判断
160
+
161
+ 满足以下条件后,遮罩会关闭:
162
+
163
+ 1. `root_selector` 已存在,且内部不再包含 `._dash-loading`。
164
+ 2. 根节点中已有实际渲染内容。
165
+ 3. `required_selectors` 中的所有选择器都已匹配到节点。
166
+ 4. 如果配置了 `pending_selector`,根节点中已不存在匹配它的节点。
167
+ 5. 上述状态连续保持两个动画帧。
168
+
169
+ `timeout_ms` 是强制关闭的安全兜底。`minimum_display_ms` 适用于正常就绪和
170
+ 手动关闭,但不会延迟 timeout。
171
+
172
+ `pending_selector` 可用于在异步或懒加载占位节点仍存在时延迟关闭遮罩。它只会
173
+ 在 `root_selector` 内查找匹配节点。该检查默认关闭;如需等待异步组件加载完成,
174
+ 请显式设置为应用自己的 CSS 选择器:
175
+
176
+ ```python
177
+ configure(pending_selector="[data-async-placeholder]")
178
+ configure(pending_selector=None)
179
+ ```
180
+
181
+ ## 配置项
182
+
183
+ `configure(**changes)` 会更新进程级、不可变的 `StartupLoadingConfig`。
184
+
185
+ | 参数 | 默认值 | 说明 |
186
+ |---|---:|---|
187
+ | `enabled` | `True` | 是否启用 index 注入。 |
188
+ | `overlay_id` | `"dash-loading"` | 注入遮罩的 ID。 |
189
+ | `aria_label` | `"Loading"` | 无障碍状态标签。 |
190
+ | `root_selector` | `"#react-entry-point"` | 用于观察渲染内容的根节点。 |
191
+ | `required_selectors` | `("#react-entry-point",)` | 关闭遮罩前必须存在的节点选择器。 |
192
+ | `pending_selector` | `None` | 可选的根节点内选择器;配置后,所有匹配节点消失才允许关闭。 |
193
+ | `timeout_ms` | `6000` | 强制关闭超时;设置为 `None` 可禁用。 |
194
+ | `minimum_display_ms` | `0` | 最短显示时间。 |
195
+ | `fade_duration_ms` | `160` | 淡出时长。 |
196
+ | `z_index` | `9999` | 遮罩层级。 |
197
+ | `background` | `"#ffffff"` | 亮色背景。 |
198
+ | `dark_background` | `"#0f0f0f"` | 暗色背景。 |
199
+ | `color` | `"#1677ff"` | 亮色 spinner 颜色。 |
200
+ | `dark_color` | `"#4096ff"` | 暗色 spinner 颜色。 |
201
+ | `theme_mode` | `"auto"` | 可选 `"auto"`、`"light"` 或 `"dark"`。 |
202
+ | `dash_theme_component_id` | `None` | 优先读取主题状态的 Dash 持久化组件 ID。 |
203
+ | `spinner_size_px` | `28` | Spinner 宽度和高度。 |
204
+ | `spinner_stroke_px` | `3` | Spinner 描边宽度。 |
205
+ | `hide_default_loading` | `True` | 遮罩存在时隐藏 `._dash-loading` 的视觉效果。 |
206
+ | `custom_loader_html` | `None` | 替换默认 spinner 的可信 HTML。 |
207
+
208
+ `custom_loader_html` 会原样插入页面,禁止传入任何不可信的用户输入。
209
+
210
+ ## Python API
211
+
212
+ ```python
213
+ from dash_startup_loading_plugin import (
214
+ StartupLoadingConfig,
215
+ configure,
216
+ configure_dac,
217
+ configure_fac,
218
+ configure_dmc,
219
+ get_config,
220
+ reset_config,
221
+ )
222
+ ```
223
+
224
+ ## 浏览器 API
225
+
226
+ ```javascript
227
+ // 重新检查就绪条件。
228
+ window.dashLoading.check();
229
+
230
+ // 关闭默认或指定遮罩。
231
+ window.dashLoading.finish();
232
+ window.dashLoading.finish("my-loading-overlay");
233
+ ```
234
+
235
+ 淡出前,遮罩会触发可冒泡的 `dash-loading:ready` 事件。
236
+ `event.detail.reason` 为 `"ready"`、`"timeout"` 或 `"manual"`。
237
+
238
+ ```javascript
239
+ document.addEventListener("dash-loading:ready", function (event) {
240
+ console.log(event.detail.reason);
241
+ });
242
+ ```
243
+
244
+ ## 注意事项
245
+
246
+ - Dash hooks 和插件配置是进程级的,同一进程应共用一套配置。
247
+ - 资源以内联方式注入;严格 CSP 部署需要允许相应的 style 和 script。
248
+ - 本插件只处理应用初始启动。后续 callback loading 请使用 `dcc.Loading`
249
+ 或其他针对 callback 的方案。
250
+
251
+ ## License
252
+
253
+ MIT
@@ -5,7 +5,7 @@ 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__ = "1.0.1"
8
+ __version__ = "1.0.3"
9
9
 
10
10
  from .plugin import (
11
11
  StartupLoadingConfig,
@@ -37,7 +37,7 @@ class StartupLoadingConfig:
37
37
  aria_label: str = "Loading"
38
38
  root_selector: str = "#react-entry-point"
39
39
  required_selectors: tuple[str, ...] = ("#react-entry-point",)
40
- pending_selector: str | None = "[data-dac-async-placeholder]"
40
+ pending_selector: str | None = None
41
41
  timeout_ms: int | None = 6000
42
42
  minimum_display_ms: int = 0
43
43
  fade_duration_ms: int = 160
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dash-startup-loading-plugin
3
- Version: 1.0.1
3
+ Version: 1.0.3
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
@@ -14,7 +14,8 @@ Dynamic: license-file
14
14
 
15
15
  # dash-startup-loading-plugin
16
16
 
17
- [English](README.md) | [简体中文](README.zh-CN.md)
17
+ [English](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.md) |
18
+ [简体中文](https://github.com/C0deBeez/dash-startup-loading-plugin/blob/master/README.zh-CN.md)
18
19
 
19
20
  An installable [Dash Hooks plugin](https://dash.plotly.com/dash-plugins-using-hooks)
20
21
  that replaces Dash's initial loading presentation with a configurable
@@ -33,7 +34,7 @@ document.
33
34
  ## Installation
34
35
 
35
36
  ```bash
36
- pip install "dash-startup-loading-plugin>=1.0.1"
37
+ pip install "dash-startup-loading-plugin>=1.0.3"
37
38
  ```
38
39
 
39
40
  Dash discovers the plugin through its `dash_hooks` entry point. Installing the
@@ -61,6 +62,10 @@ if __name__ == "__main__":
61
62
  app.run(debug=True)
62
63
  ```
63
64
 
65
+ By default, the overlay only replaces Dash's built-in `._dash-loading`
66
+ animation and closes once Dash has rendered the application layout. Waiting
67
+ for lazy or asynchronous component placeholders is opt-in.
68
+
64
69
  Call `configure()` before creating `Dash` when custom behavior is needed:
65
70
 
66
71
  ```python
@@ -179,16 +184,16 @@ The overlay closes when:
179
184
  1. `root_selector` exists and no longer contains `._dash-loading`.
180
185
  2. The root contains rendered content.
181
186
  3. Every `required_selectors` entry exists.
182
- 4. No `pending_selector` node remains under the root.
187
+ 4. If `pending_selector` is configured, no matching node remains under the root.
183
188
  5. The conditions remain true for two animation frames.
184
189
 
185
190
  `timeout_ms` is a forced-dismiss fallback. `minimum_display_ms` applies to
186
191
  ready and manual dismissal, but does not delay a timeout.
187
192
 
188
- `pending_selector` delays dismissal while any matching element remains inside
189
- `root_selector`. It is useful for lazy or asynchronous placeholders that are
190
- mounted before the real content. Set it to an application-specific CSS
191
- selector, or use `None` when no pending-node check is needed:
193
+ `pending_selector` optionally delays dismissal while any matching element
194
+ remains inside `root_selector`. It is useful for lazy or asynchronous
195
+ placeholders that are mounted before the real content. The check is disabled
196
+ by default; opt in with an application-specific CSS selector:
192
197
 
193
198
  ```python
194
199
  configure(pending_selector="[data-async-placeholder]")
@@ -207,7 +212,7 @@ configure(pending_selector=None)
207
212
  | `aria_label` | `"Loading"` | Accessible status label. |
208
213
  | `root_selector` | `"#react-entry-point"` | Root observed for rendered content. |
209
214
  | `required_selectors` | `("#react-entry-point",)` | Selectors that must exist before dismissal. |
210
- | `pending_selector` | `"[data-dac-async-placeholder]"` | Selector checked under `root_selector`; dismissal waits until all matches disappear. Use `None` to disable. |
215
+ | `pending_selector` | `None` | Optional selector checked under `root_selector`; when configured, dismissal waits until all matches disappear. |
211
216
  | `timeout_ms` | `6000` | Forced-dismiss timeout; use `None` to disable. |
212
217
  | `minimum_display_ms` | `0` | Minimum display time. |
213
218
  | `fade_duration_ms` | `160` | Fade-out duration. |
@@ -3,6 +3,8 @@ MANIFEST.in
3
3
  README.md
4
4
  README.zh-CN.md
5
5
  pyproject.toml
6
+ src/dash_startup_loading_plugin/README.md
7
+ src/dash_startup_loading_plugin/README.zh-CN.md
6
8
  src/dash_startup_loading_plugin/__init__.py
7
9
  src/dash_startup_loading_plugin/plugin.py
8
10
  src/dash_startup_loading_plugin.egg-info/PKG-INFO
@@ -0,0 +1,72 @@
1
+ from pathlib import Path
2
+ import tomllib
3
+
4
+
5
+ PROJECT_ROOT = Path(__file__).resolve().parents[1]
6
+
7
+
8
+ def test_pypi_description_uses_english_readme():
9
+ pyproject = tomllib.loads(
10
+ (PROJECT_ROOT / "pyproject.toml").read_text(encoding="utf-8")
11
+ )
12
+
13
+ assert pyproject["project"]["readme"] == "README.md"
14
+ assert "An installable" in (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
15
+
16
+
17
+ def test_readmes_use_current_selector_and_installation_examples():
18
+ english = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
19
+ chinese = (PROJECT_ROOT / "README.zh-CN.md").read_text(encoding="utf-8")
20
+
21
+ for readme in (english, chinese):
22
+ assert "#header" in readme
23
+ assert "#sidebar-menu" in readme
24
+ assert "pending_selector" in readme
25
+ assert "pip install dash-ant-design" in readme
26
+ assert "pip install feffery-antd-components" in readme
27
+ assert "usage-header" not in readme
28
+ assert "usage-sidebar-menu" not in readme
29
+ assert "dash-ant-design # Python 3.10+" not in readme
30
+ assert "feffery-antd-components>=0.4.0" not in readme
31
+
32
+
33
+ def test_readmes_link_to_each_other():
34
+ english = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
35
+ chinese = (PROJECT_ROOT / "README.zh-CN.md").read_text(encoding="utf-8")
36
+
37
+ chinese_link = (
38
+ "[简体中文](https://github.com/C0deBeez/"
39
+ "dash-startup-loading-plugin/blob/master/README.zh-CN.md)"
40
+ )
41
+ english_link = (
42
+ "[English](https://github.com/C0deBeez/"
43
+ "dash-startup-loading-plugin/blob/master/README.md)"
44
+ )
45
+
46
+ for readme in (english, chinese):
47
+ assert chinese_link in readme
48
+ assert english_link in readme
49
+
50
+
51
+ def test_packaged_chinese_readme_matches_project_readme():
52
+ project_readme = (PROJECT_ROOT / "README.zh-CN.md").read_text(encoding="utf-8")
53
+ packaged_readme = (
54
+ PROJECT_ROOT
55
+ / "src"
56
+ / "dash_startup_loading_plugin"
57
+ / "README.zh-CN.md"
58
+ ).read_text(encoding="utf-8")
59
+
60
+ assert packaged_readme == project_readme
61
+
62
+
63
+ def test_packaged_english_readme_matches_project_readme():
64
+ project_readme = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
65
+ packaged_readme = (
66
+ PROJECT_ROOT
67
+ / "src"
68
+ / "dash_startup_loading_plugin"
69
+ / "README.md"
70
+ ).read_text(encoding="utf-8")
71
+
72
+ assert packaged_readme == project_readme
@@ -61,6 +61,15 @@ def test_injects_overlay_after_body_with_custom_attributes():
61
61
  assert result.count(" data-dash-loading ") == 1
62
62
  assert '<span class="dash-loading__spinner"' in result
63
63
  assert _data_config(result)["requiredSelectors"] == ["#react-entry-point"]
64
+ assert _data_config(result)["pendingSelector"] is None
65
+
66
+
67
+ def test_waiting_for_async_components_is_opt_in():
68
+ configure(pending_selector="[data-async-placeholder]")
69
+
70
+ result = _inject_overlay("<html><body><main></main></body></html>")
71
+
72
+ assert _data_config(result)["pendingSelector"] == "[data-async-placeholder]"
64
73
 
65
74
 
66
75
  def test_injection_is_idempotent_and_can_be_disabled():
@@ -1,28 +0,0 @@
1
- from pathlib import Path
2
-
3
-
4
- PROJECT_ROOT = Path(__file__).resolve().parents[1]
5
-
6
-
7
- def test_readmes_use_current_selector_and_installation_examples():
8
- english = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
9
- chinese = (PROJECT_ROOT / "README.zh-CN.md").read_text(encoding="utf-8")
10
-
11
- for readme in (english, chinese):
12
- assert "#header" in readme
13
- assert "#sidebar-menu" in readme
14
- assert "pending_selector" in readme
15
- assert "pip install dash-ant-design" in readme
16
- assert "pip install feffery-antd-components" in readme
17
- assert "usage-header" not in readme
18
- assert "usage-sidebar-menu" not in readme
19
- assert "dash-ant-design # Python 3.10+" not in readme
20
- assert "feffery-antd-components>=0.4.0" not in readme
21
-
22
-
23
- def test_readmes_link_to_each_other():
24
- english = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
25
- chinese = (PROJECT_ROOT / "README.zh-CN.md").read_text(encoding="utf-8")
26
-
27
- assert "[简体中文](README.zh-CN.md)" in english
28
- assert "[English](README.md)" in chinese