nicegui-bootstrap-components 0.1.0__py3-none-any.whl
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.
- nicegui_bootstrap_components/__init__.py +7 -0
- nicegui_bootstrap_components/_base.py +590 -0
- nicegui_bootstrap_components/_host.py +259 -0
- nicegui_bootstrap_components/assets.py +371 -0
- nicegui_bootstrap_components/bs/__init__.py +267 -0
- nicegui_bootstrap_components/bs/_actions.py +232 -0
- nicegui_bootstrap_components/bs/_alert_spinner.py +423 -0
- nicegui_bootstrap_components/bs/_carousel.py +312 -0
- nicegui_bootstrap_components/bs/_choices.py +779 -0
- nicegui_bootstrap_components/bs/_content.py +1343 -0
- nicegui_bootstrap_components/bs/_forms.py +378 -0
- nicegui_bootstrap_components/bs/_inputs.py +560 -0
- nicegui_bootstrap_components/bs/_layout.py +341 -0
- nicegui_bootstrap_components/bs/_nav.py +650 -0
- nicegui_bootstrap_components/bs/_navbar.py +445 -0
- nicegui_bootstrap_components/bs/_overlay_root.py +73 -0
- nicegui_bootstrap_components/bs/_overlays.py +2633 -0
- nicegui_bootstrap_components/bs/_scope.py +28 -0
- nicegui_bootstrap_components/bs/_tabs.py +605 -0
- nicegui_bootstrap_components/bs/_toast.py +137 -0
- nicegui_bootstrap_components/bs/_tooltip_popover.py +537 -0
- nicegui_bootstrap_components/contracts/dbc-2.0.4.json +16811 -0
- nicegui_bootstrap_components/dbc/__init__.py +108 -0
- nicegui_bootstrap_components/icons.py +29 -0
- nicegui_bootstrap_components/persist.py +201 -0
- nicegui_bootstrap_components/py.typed +0 -0
- nicegui_bootstrap_components/static/dist/fonts/bootstrap-icons.woff +0 -0
- nicegui_bootstrap_components/static/dist/fonts/bootstrap-icons.woff2 +0 -0
- nicegui_bootstrap_components/static/dist/ngbs-bootstrap-unscoped.css +12047 -0
- nicegui_bootstrap_components/static/dist/ngbs-bootstrap.css +12057 -0
- nicegui_bootstrap_components/static/dist/ngbs-cerulean-unscoped.css +12338 -0
- nicegui_bootstrap_components/static/dist/ngbs-cerulean.css +12348 -0
- nicegui_bootstrap_components/static/dist/ngbs-compat-unscoped.css +12 -0
- nicegui_bootstrap_components/static/dist/ngbs-compat.css +12 -0
- nicegui_bootstrap_components/static/dist/ngbs-cosmo-unscoped.css +11825 -0
- nicegui_bootstrap_components/static/dist/ngbs-cosmo.css +11835 -0
- nicegui_bootstrap_components/static/dist/ngbs-cyborg-unscoped.css +12213 -0
- nicegui_bootstrap_components/static/dist/ngbs-cyborg.css +12223 -0
- nicegui_bootstrap_components/static/dist/ngbs-darkly-unscoped.css +12143 -0
- nicegui_bootstrap_components/static/dist/ngbs-darkly.css +12153 -0
- nicegui_bootstrap_components/static/dist/ngbs-flatly-unscoped.css +12129 -0
- nicegui_bootstrap_components/static/dist/ngbs-flatly.css +12139 -0
- nicegui_bootstrap_components/static/dist/ngbs-grid-unscoped.css +4084 -0
- nicegui_bootstrap_components/static/dist/ngbs-grid.css +4094 -0
- nicegui_bootstrap_components/static/dist/ngbs-host-unscoped.css +9 -0
- nicegui_bootstrap_components/static/dist/ngbs-host.css +9 -0
- nicegui_bootstrap_components/static/dist/ngbs-icons-bootstrap.css +5 -0
- nicegui_bootstrap_components/static/dist/ngbs-icons-fontawesome.css +9 -0
- nicegui_bootstrap_components/static/dist/ngbs-journal-unscoped.css +12112 -0
- nicegui_bootstrap_components/static/dist/ngbs-journal.css +12122 -0
- nicegui_bootstrap_components/static/dist/ngbs-litera-unscoped.css +12214 -0
- nicegui_bootstrap_components/static/dist/ngbs-litera.css +12224 -0
- nicegui_bootstrap_components/static/dist/ngbs-lumen-unscoped.css +12377 -0
- nicegui_bootstrap_components/static/dist/ngbs-lumen.css +12387 -0
- nicegui_bootstrap_components/static/dist/ngbs-lux-unscoped.css +12048 -0
- nicegui_bootstrap_components/static/dist/ngbs-lux.css +12058 -0
- nicegui_bootstrap_components/static/dist/ngbs-materia-unscoped.css +13197 -0
- nicegui_bootstrap_components/static/dist/ngbs-materia.css +13207 -0
- nicegui_bootstrap_components/static/dist/ngbs-minty-unscoped.css +12184 -0
- nicegui_bootstrap_components/static/dist/ngbs-minty.css +12194 -0
- nicegui_bootstrap_components/static/dist/ngbs-morph-unscoped.css +12829 -0
- nicegui_bootstrap_components/static/dist/ngbs-morph.css +12839 -0
- nicegui_bootstrap_components/static/dist/ngbs-pulse-unscoped.css +11901 -0
- nicegui_bootstrap_components/static/dist/ngbs-pulse.css +11911 -0
- nicegui_bootstrap_components/static/dist/ngbs-quartz-unscoped.css +12625 -0
- nicegui_bootstrap_components/static/dist/ngbs-quartz.css +12635 -0
- nicegui_bootstrap_components/static/dist/ngbs-sandstone-unscoped.css +12214 -0
- nicegui_bootstrap_components/static/dist/ngbs-sandstone.css +12224 -0
- nicegui_bootstrap_components/static/dist/ngbs-simplex-unscoped.css +12199 -0
- nicegui_bootstrap_components/static/dist/ngbs-simplex.css +12209 -0
- nicegui_bootstrap_components/static/dist/ngbs-sketchy-unscoped.css +12518 -0
- nicegui_bootstrap_components/static/dist/ngbs-sketchy.css +12528 -0
- nicegui_bootstrap_components/static/dist/ngbs-slate-unscoped.css +12527 -0
- nicegui_bootstrap_components/static/dist/ngbs-slate.css +12537 -0
- nicegui_bootstrap_components/static/dist/ngbs-solar-unscoped.css +12152 -0
- nicegui_bootstrap_components/static/dist/ngbs-solar.css +12162 -0
- nicegui_bootstrap_components/static/dist/ngbs-spacelab-unscoped.css +12279 -0
- nicegui_bootstrap_components/static/dist/ngbs-spacelab.css +12289 -0
- nicegui_bootstrap_components/static/dist/ngbs-superhero-unscoped.css +12223 -0
- nicegui_bootstrap_components/static/dist/ngbs-superhero.css +12233 -0
- nicegui_bootstrap_components/static/dist/ngbs-united-unscoped.css +12090 -0
- nicegui_bootstrap_components/static/dist/ngbs-united.css +12100 -0
- nicegui_bootstrap_components/static/dist/ngbs-vapor-unscoped.css +12556 -0
- nicegui_bootstrap_components/static/dist/ngbs-vapor.css +12566 -0
- nicegui_bootstrap_components/static/dist/ngbs-yeti-unscoped.css +12333 -0
- nicegui_bootstrap_components/static/dist/ngbs-yeti.css +12343 -0
- nicegui_bootstrap_components/static/dist/ngbs-zephyr-unscoped.css +12296 -0
- nicegui_bootstrap_components/static/dist/ngbs-zephyr.css +12306 -0
- nicegui_bootstrap_components/static/prototype-ngbs.css +541 -0
- nicegui_bootstrap_components/static/webfonts/fa-brands-400.ttf +0 -0
- nicegui_bootstrap_components/static/webfonts/fa-brands-400.woff2 +0 -0
- nicegui_bootstrap_components/static/webfonts/fa-regular-400.ttf +0 -0
- nicegui_bootstrap_components/static/webfonts/fa-regular-400.woff2 +0 -0
- nicegui_bootstrap_components/static/webfonts/fa-solid-900.ttf +0 -0
- nicegui_bootstrap_components/static/webfonts/fa-solid-900.woff2 +0 -0
- nicegui_bootstrap_components/static/webfonts/fa-v4compatibility.ttf +0 -0
- nicegui_bootstrap_components/static/webfonts/fa-v4compatibility.woff2 +0 -0
- nicegui_bootstrap_components/theme.py +238 -0
- nicegui_bootstrap_components/themes.py +131 -0
- nicegui_bootstrap_components-0.1.0.dist-info/METADATA +234 -0
- nicegui_bootstrap_components-0.1.0.dist-info/RECORD +103 -0
- nicegui_bootstrap_components-0.1.0.dist-info/WHEEL +4 -0
- nicegui_bootstrap_components-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"""Alert and Spinner family (native + compat sibling types)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from nicegui import ui
|
|
10
|
+
|
|
11
|
+
from .._base import (
|
|
12
|
+
BootstrapElement,
|
|
13
|
+
make_surface_classes,
|
|
14
|
+
normalize_style,
|
|
15
|
+
resolve_class_name,
|
|
16
|
+
)
|
|
17
|
+
from .._host import set_element_text
|
|
18
|
+
from ._overlays import _adopt_into, _ensure_overlay_runtime, _portal_to_overlay_root
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"Alert",
|
|
22
|
+
"DbcAlert",
|
|
23
|
+
"alert",
|
|
24
|
+
"Spinner",
|
|
25
|
+
"DbcSpinner",
|
|
26
|
+
"spinner",
|
|
27
|
+
"alert_structural_classes",
|
|
28
|
+
"spinner_structural_classes",
|
|
29
|
+
"spinner_color_css",
|
|
30
|
+
"spinner_is_visible",
|
|
31
|
+
"spinner_fullscreen_classes",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
_SEMANTIC_COLORS: tuple[str, ...] = (
|
|
35
|
+
"primary",
|
|
36
|
+
"secondary",
|
|
37
|
+
"success",
|
|
38
|
+
"danger",
|
|
39
|
+
"warning",
|
|
40
|
+
"info",
|
|
41
|
+
"light",
|
|
42
|
+
"dark",
|
|
43
|
+
)
|
|
44
|
+
_SPINNER_TYPES: tuple[str, ...] = ("border", "grow")
|
|
45
|
+
_SPINNER_SIZES: tuple[str, ...] = ("sm",)
|
|
46
|
+
_SPINNER_DISPLAYS: tuple[str, ...] = ("auto", "show", "hide")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def alert_structural_classes(
|
|
50
|
+
*,
|
|
51
|
+
color: str,
|
|
52
|
+
dismissable: bool = False,
|
|
53
|
+
fade: bool = True,
|
|
54
|
+
is_open: bool = True,
|
|
55
|
+
) -> list[str]:
|
|
56
|
+
"""Return Bootstrap ``alert`` classes. Unknown colors raise ``ValueError``."""
|
|
57
|
+
if color not in _SEMANTIC_COLORS:
|
|
58
|
+
raise ValueError(f"Unknown Alert color {color!r}")
|
|
59
|
+
classes = ["alert", f"alert-{color}"]
|
|
60
|
+
if dismissable:
|
|
61
|
+
classes.append("alert-dismissible")
|
|
62
|
+
if fade:
|
|
63
|
+
classes.append("fade")
|
|
64
|
+
if is_open:
|
|
65
|
+
classes.append("show")
|
|
66
|
+
elif not is_open:
|
|
67
|
+
classes.append("d-none")
|
|
68
|
+
return classes
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def spinner_structural_classes(
|
|
72
|
+
*,
|
|
73
|
+
type: str = "border",
|
|
74
|
+
size: str | None = None,
|
|
75
|
+
color: str | None = None,
|
|
76
|
+
) -> list[str]:
|
|
77
|
+
"""Return Bootstrap spinner classes. Unknown type or size raise ``ValueError``."""
|
|
78
|
+
if type not in _SPINNER_TYPES:
|
|
79
|
+
raise ValueError(f"Unknown Spinner type {type!r}; expected 'border' or 'grow'")
|
|
80
|
+
if size is not None and size not in _SPINNER_SIZES:
|
|
81
|
+
raise ValueError(f"Unknown Spinner size {size!r}; expected 'sm' or None")
|
|
82
|
+
classes = [f"spinner-{type}"]
|
|
83
|
+
if size is not None:
|
|
84
|
+
classes.append(f"spinner-{type}-{size}")
|
|
85
|
+
if color is not None and color in _SEMANTIC_COLORS:
|
|
86
|
+
classes.append(f"text-{color}")
|
|
87
|
+
return classes
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def spinner_color_css(color: str | None) -> str | None:
|
|
91
|
+
"""Return an inline CSS color for arbitrary (non-semantic) spinner colors."""
|
|
92
|
+
if color is None or color in _SEMANTIC_COLORS:
|
|
93
|
+
return None
|
|
94
|
+
return color
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def spinner_is_visible(
|
|
98
|
+
*,
|
|
99
|
+
display: str = "auto",
|
|
100
|
+
loading: bool | None = None,
|
|
101
|
+
has_children: bool = False,
|
|
102
|
+
fullscreen: bool = False,
|
|
103
|
+
) -> bool:
|
|
104
|
+
"""Return whether the spinner graphic should be shown."""
|
|
105
|
+
if display not in _SPINNER_DISPLAYS:
|
|
106
|
+
raise ValueError(f"Unknown Spinner display {display!r}; expected 'auto', 'show', or 'hide'")
|
|
107
|
+
if display == "hide":
|
|
108
|
+
return False
|
|
109
|
+
if display == "show":
|
|
110
|
+
return True
|
|
111
|
+
if loading is not None:
|
|
112
|
+
return bool(loading)
|
|
113
|
+
if fullscreen:
|
|
114
|
+
return True
|
|
115
|
+
return not has_children
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def spinner_fullscreen_classes() -> list[str]:
|
|
119
|
+
"""Return classes for a fullscreen spinner overlay root."""
|
|
120
|
+
return [
|
|
121
|
+
"position-fixed",
|
|
122
|
+
"top-0",
|
|
123
|
+
"start-0",
|
|
124
|
+
"w-100",
|
|
125
|
+
"h-100",
|
|
126
|
+
"d-flex",
|
|
127
|
+
"align-items-center",
|
|
128
|
+
"justify-content-center",
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _spinner_node_css(
|
|
133
|
+
*,
|
|
134
|
+
color: str | None,
|
|
135
|
+
spinner_style: dict[str, Any] | None,
|
|
136
|
+
) -> str | None:
|
|
137
|
+
parts: list[str] = []
|
|
138
|
+
extra = spinner_color_css(color)
|
|
139
|
+
if extra is not None:
|
|
140
|
+
parts.append(f"color: {extra}")
|
|
141
|
+
if spinner_style:
|
|
142
|
+
css_val: Any = normalize_style(spinner_style)
|
|
143
|
+
if isinstance(css_val, dict):
|
|
144
|
+
css_val = "; ".join(f"{key}: {value}" for key, value in css_val.items())
|
|
145
|
+
text = str(css_val).strip().rstrip(";")
|
|
146
|
+
if text:
|
|
147
|
+
parts.append(text)
|
|
148
|
+
if not parts:
|
|
149
|
+
return None
|
|
150
|
+
return "; ".join(parts)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _mount_spinner_label() -> None:
|
|
154
|
+
label = ui.element("span").classes("visually-hidden")
|
|
155
|
+
setter = getattr(label, "set_text", None)
|
|
156
|
+
if callable(setter):
|
|
157
|
+
setter("Loading...")
|
|
158
|
+
else:
|
|
159
|
+
set_element_text(label, "Loading...")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _deactivate_timer(timer: Any) -> None:
|
|
163
|
+
with contextlib.suppress(Exception):
|
|
164
|
+
timer.deactivate()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _attach_passed_children(host: Any, children: object) -> None:
|
|
168
|
+
"""Place constructor children onto ``host`` without using ``children=`` on init."""
|
|
169
|
+
if children is None:
|
|
170
|
+
return
|
|
171
|
+
if isinstance(children, str):
|
|
172
|
+
setter = getattr(host, "set_text", None)
|
|
173
|
+
if callable(setter):
|
|
174
|
+
setter(children)
|
|
175
|
+
else:
|
|
176
|
+
set_element_text(host, children)
|
|
177
|
+
return
|
|
178
|
+
_adopt_into(host, children)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class _AlertImpl(BootstrapElement):
|
|
182
|
+
"""Private Alert implementation."""
|
|
183
|
+
|
|
184
|
+
component_name = "Alert"
|
|
185
|
+
children_kind = "auto"
|
|
186
|
+
reserved_classes = ("alert",)
|
|
187
|
+
|
|
188
|
+
def __init__(
|
|
189
|
+
self,
|
|
190
|
+
children: object = None,
|
|
191
|
+
*,
|
|
192
|
+
_surface: str,
|
|
193
|
+
color: str = "primary",
|
|
194
|
+
dismissable: bool = False,
|
|
195
|
+
fade: bool = True,
|
|
196
|
+
is_open: bool = True,
|
|
197
|
+
duration: int | None = None,
|
|
198
|
+
on_dismiss: Callable[..., Any] | None = None,
|
|
199
|
+
**kwargs: Any,
|
|
200
|
+
) -> None:
|
|
201
|
+
self._surface = _surface
|
|
202
|
+
if duration is not None:
|
|
203
|
+
duration_ms = int(duration)
|
|
204
|
+
if duration_ms < 0:
|
|
205
|
+
raise ValueError("Alert duration must be None or a non-negative integer")
|
|
206
|
+
self._duration: int | None = duration_ms
|
|
207
|
+
else:
|
|
208
|
+
self._duration = None
|
|
209
|
+
self._structural_classes = tuple(
|
|
210
|
+
alert_structural_classes(
|
|
211
|
+
color=color,
|
|
212
|
+
dismissable=bool(dismissable),
|
|
213
|
+
fade=bool(fade),
|
|
214
|
+
is_open=bool(is_open),
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
self._is_open = bool(is_open)
|
|
218
|
+
self._fade = bool(fade)
|
|
219
|
+
self._on_dismiss = on_dismiss
|
|
220
|
+
self._timer: Any | None = None
|
|
221
|
+
super().__init__(None, tag="div", **kwargs)
|
|
222
|
+
self._props["role"] = "alert"
|
|
223
|
+
_attach_passed_children(self, children)
|
|
224
|
+
if dismissable:
|
|
225
|
+
with self:
|
|
226
|
+
close = ui.element("button").classes("btn-close")
|
|
227
|
+
close._props["type"] = "button"
|
|
228
|
+
close._props["aria-label"] = "Close"
|
|
229
|
+
close.on("click", self._handle_dismiss)
|
|
230
|
+
self._arm_duration_timer()
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
def is_open(self) -> bool:
|
|
234
|
+
return self._is_open
|
|
235
|
+
|
|
236
|
+
@is_open.setter
|
|
237
|
+
def is_open(self, value: bool) -> None:
|
|
238
|
+
wanted = bool(value)
|
|
239
|
+
if wanted == self._is_open:
|
|
240
|
+
return
|
|
241
|
+
if wanted:
|
|
242
|
+
self._is_open = True
|
|
243
|
+
self._apply_open_classes()
|
|
244
|
+
self._arm_duration_timer()
|
|
245
|
+
else:
|
|
246
|
+
self._handle_dismiss()
|
|
247
|
+
|
|
248
|
+
def _apply_open_classes(self) -> None:
|
|
249
|
+
if self._is_open:
|
|
250
|
+
if self._fade:
|
|
251
|
+
self.classes(add="show", remove="d-none")
|
|
252
|
+
else:
|
|
253
|
+
self.classes(remove="d-none")
|
|
254
|
+
elif self._fade:
|
|
255
|
+
self.classes(remove="show")
|
|
256
|
+
else:
|
|
257
|
+
self.classes(add="d-none")
|
|
258
|
+
|
|
259
|
+
def _cancel_timer(self) -> None:
|
|
260
|
+
timer = self._timer
|
|
261
|
+
self._timer = None
|
|
262
|
+
if timer is not None:
|
|
263
|
+
_deactivate_timer(timer)
|
|
264
|
+
|
|
265
|
+
def _arm_duration_timer(self) -> None:
|
|
266
|
+
self._cancel_timer()
|
|
267
|
+
if self._duration is not None and self._duration > 0 and self._is_open:
|
|
268
|
+
self._timer = ui.timer(
|
|
269
|
+
self._duration / 1000.0,
|
|
270
|
+
self._handle_dismiss,
|
|
271
|
+
once=True,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
def _handle_dismiss(self, *_args: Any, **_kwargs: Any) -> None:
|
|
275
|
+
if not self._is_open:
|
|
276
|
+
return
|
|
277
|
+
self._is_open = False
|
|
278
|
+
self._cancel_timer()
|
|
279
|
+
self._apply_open_classes()
|
|
280
|
+
if self._on_dismiss is not None:
|
|
281
|
+
self._on_dismiss()
|
|
282
|
+
|
|
283
|
+
def _handle_delete(self) -> None:
|
|
284
|
+
self._cancel_timer()
|
|
285
|
+
super()._handle_delete()
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
Alert, DbcAlert = make_surface_classes("Alert", globals())
|
|
289
|
+
alert = Alert
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class _SpinnerImpl(BootstrapElement):
|
|
293
|
+
"""Private Spinner implementation."""
|
|
294
|
+
|
|
295
|
+
component_name = "Spinner"
|
|
296
|
+
children_kind = "auto"
|
|
297
|
+
reserved_classes: tuple[str, ...] = ()
|
|
298
|
+
|
|
299
|
+
def __init__(
|
|
300
|
+
self,
|
|
301
|
+
children: object = None,
|
|
302
|
+
*,
|
|
303
|
+
_surface: str,
|
|
304
|
+
color: str | None = None,
|
|
305
|
+
type: str = "border",
|
|
306
|
+
size: str | None = None,
|
|
307
|
+
loading: bool | None = None,
|
|
308
|
+
display: str = "auto",
|
|
309
|
+
delay_show: int | None = None,
|
|
310
|
+
delay_hide: int | None = None,
|
|
311
|
+
fullscreen: bool = False,
|
|
312
|
+
spinner_style: dict[str, Any] | None = None,
|
|
313
|
+
spinner_class_name: str | None = None,
|
|
314
|
+
spinnerClassName: str | None = None,
|
|
315
|
+
**kwargs: Any,
|
|
316
|
+
) -> None:
|
|
317
|
+
self._surface = _surface
|
|
318
|
+
spinner_classes = spinner_structural_classes(type=type, size=size, color=color)
|
|
319
|
+
has_children = children is not None
|
|
320
|
+
visible = spinner_is_visible(
|
|
321
|
+
display=display,
|
|
322
|
+
loading=loading,
|
|
323
|
+
has_children=has_children,
|
|
324
|
+
fullscreen=bool(fullscreen),
|
|
325
|
+
)
|
|
326
|
+
if delay_show is not None:
|
|
327
|
+
delay_show_ms = int(delay_show)
|
|
328
|
+
if delay_show_ms < 0:
|
|
329
|
+
raise ValueError("Spinner delay_show must be None or a non-negative integer")
|
|
330
|
+
self._delay_show: int | None = delay_show_ms
|
|
331
|
+
else:
|
|
332
|
+
self._delay_show = None
|
|
333
|
+
if delay_hide is not None:
|
|
334
|
+
delay_hide_ms = int(delay_hide)
|
|
335
|
+
if delay_hide_ms < 0:
|
|
336
|
+
raise ValueError("Spinner delay_hide must be None or a non-negative integer")
|
|
337
|
+
self._delay_hide: int | None = delay_hide_ms
|
|
338
|
+
else:
|
|
339
|
+
self._delay_hide = None
|
|
340
|
+
use_wrapper = has_children or bool(fullscreen)
|
|
341
|
+
if use_wrapper:
|
|
342
|
+
wrapper = spinner_fullscreen_classes() if fullscreen else []
|
|
343
|
+
self._structural_classes = tuple(wrapper)
|
|
344
|
+
else:
|
|
345
|
+
classes = list(spinner_classes)
|
|
346
|
+
if not visible:
|
|
347
|
+
classes.append("d-none")
|
|
348
|
+
self._structural_classes = tuple(classes)
|
|
349
|
+
self._fullscreen = bool(fullscreen)
|
|
350
|
+
self._delay_timers: list[Any] = []
|
|
351
|
+
if fullscreen:
|
|
352
|
+
_ensure_overlay_runtime()
|
|
353
|
+
super().__init__(None, tag="div", **kwargs)
|
|
354
|
+
resolved_cn: str | None = None
|
|
355
|
+
if spinner_class_name is not None or spinnerClassName is not None:
|
|
356
|
+
resolved_cn = resolve_class_name(spinner_class_name, spinnerClassName, self._surface)
|
|
357
|
+
inline = _spinner_node_css(color=color, spinner_style=spinner_style)
|
|
358
|
+
if use_wrapper:
|
|
359
|
+
_attach_passed_children(self, children)
|
|
360
|
+
with self:
|
|
361
|
+
spinner_el = ui.element("div")
|
|
362
|
+
spinner_el.classes(" ".join(spinner_classes))
|
|
363
|
+
if resolved_cn:
|
|
364
|
+
spinner_el.classes(resolved_cn)
|
|
365
|
+
if not visible:
|
|
366
|
+
spinner_el.classes(add="d-none")
|
|
367
|
+
spinner_el._props["role"] = "status"
|
|
368
|
+
if inline:
|
|
369
|
+
spinner_el._props["style"] = inline
|
|
370
|
+
with spinner_el:
|
|
371
|
+
_mount_spinner_label()
|
|
372
|
+
self._spinner_el: Any = spinner_el
|
|
373
|
+
else:
|
|
374
|
+
self._spinner_el = self
|
|
375
|
+
self._props["role"] = "status"
|
|
376
|
+
if resolved_cn:
|
|
377
|
+
self.classes(resolved_cn)
|
|
378
|
+
if inline:
|
|
379
|
+
existing = self._props.get("style")
|
|
380
|
+
if existing:
|
|
381
|
+
self._props["style"] = f"{existing}; {inline}"
|
|
382
|
+
else:
|
|
383
|
+
self._props["style"] = inline
|
|
384
|
+
with self:
|
|
385
|
+
_mount_spinner_label()
|
|
386
|
+
if visible and self._delay_show is not None and self._delay_show > 0:
|
|
387
|
+
self._set_spinner_visible(False)
|
|
388
|
+
self._delay_timers.append(
|
|
389
|
+
ui.timer(self._delay_show / 1000.0, self._show_spinner, once=True)
|
|
390
|
+
)
|
|
391
|
+
elif (not visible) and self._delay_hide is not None and self._delay_hide > 0:
|
|
392
|
+
self._set_spinner_visible(True)
|
|
393
|
+
self._delay_timers.append(
|
|
394
|
+
ui.timer(self._delay_hide / 1000.0, self._hide_spinner, once=True)
|
|
395
|
+
)
|
|
396
|
+
if fullscreen:
|
|
397
|
+
_portal_to_overlay_root(self)
|
|
398
|
+
|
|
399
|
+
def _set_spinner_visible(self, visible: bool) -> None:
|
|
400
|
+
if visible:
|
|
401
|
+
self._spinner_el.classes(remove="d-none")
|
|
402
|
+
else:
|
|
403
|
+
self._spinner_el.classes(add="d-none")
|
|
404
|
+
|
|
405
|
+
def _show_spinner(self) -> None:
|
|
406
|
+
self._set_spinner_visible(True)
|
|
407
|
+
|
|
408
|
+
def _hide_spinner(self) -> None:
|
|
409
|
+
self._set_spinner_visible(False)
|
|
410
|
+
|
|
411
|
+
def _clear_delay_timers(self) -> None:
|
|
412
|
+
timers = self._delay_timers
|
|
413
|
+
self._delay_timers = []
|
|
414
|
+
for timer in timers:
|
|
415
|
+
_deactivate_timer(timer)
|
|
416
|
+
|
|
417
|
+
def _handle_delete(self) -> None:
|
|
418
|
+
self._clear_delay_timers()
|
|
419
|
+
super()._handle_delete()
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
Spinner, DbcSpinner = make_surface_classes("Spinner", globals())
|
|
423
|
+
spinner = Spinner
|