ex4nicegui 0.6.8__py3-none-any.whl → 0.6.9__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.
- ex4nicegui/__init__.py +2 -0
- ex4nicegui/helper/client_instance_locker.py +4 -4
- ex4nicegui/reactive/__init__.py +4 -0
- ex4nicegui/reactive/base.py +426 -0
- ex4nicegui/reactive/deferredTask.py +3 -2
- ex4nicegui/reactive/mixins/backgroundColor.py +41 -0
- ex4nicegui/reactive/mixins/disableable.py +44 -0
- ex4nicegui/reactive/mixins/textColor.py +66 -0
- ex4nicegui/reactive/officials/base.py +4 -453
- ex4nicegui/reactive/officials/button.py +35 -2
- ex4nicegui/reactive/officials/chip.py +102 -0
- ex4nicegui/reactive/officials/circular_progress.py +4 -2
- ex4nicegui/reactive/officials/grid.py +3 -2
- ex4nicegui/reactive/officials/icon.py +2 -5
- ex4nicegui/reactive/officials/knob.py +4 -0
- ex4nicegui/reactive/officials/label.py +2 -9
- ex4nicegui/reactive/officials/linear_progress.py +2 -5
- ex4nicegui/reactive/officials/slider.py +1 -1
- ex4nicegui/reactive/officials/tab_panels.py +108 -2
- ex4nicegui/reactive/scopedStyle.py +4 -1
- ex4nicegui/reactive/systems/color_system.py +132 -0
- ex4nicegui/utils/apiEffect.py +5 -1
- ex4nicegui/utils/effect.py +3 -2
- ex4nicegui/utils/scheduler.py +20 -4
- {ex4nicegui-0.6.8.dist-info → ex4nicegui-0.6.9.dist-info}/METADATA +29 -1
- {ex4nicegui-0.6.8.dist-info → ex4nicegui-0.6.9.dist-info}/RECORD +28 -24
- ex4nicegui/reactive/services/color_service.py +0 -56
- {ex4nicegui-0.6.8.dist-info → ex4nicegui-0.6.9.dist-info}/LICENSE +0 -0
- {ex4nicegui-0.6.8.dist-info → ex4nicegui-0.6.9.dist-info}/WHEEL +0 -0
|
@@ -1,454 +1,5 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Any,
|
|
6
|
-
Callable,
|
|
7
|
-
Dict,
|
|
8
|
-
List,
|
|
9
|
-
Optional,
|
|
10
|
-
Protocol,
|
|
11
|
-
TypeVar,
|
|
12
|
-
Generic,
|
|
13
|
-
Union,
|
|
14
|
-
cast,
|
|
15
|
-
overload,
|
|
1
|
+
from ex4nicegui.reactive.base import (
|
|
2
|
+
BindableUi, # noqa: F401
|
|
3
|
+
DisableableMixin, # noqa: F401
|
|
4
|
+
DisableableBindableUi, # noqa: F401
|
|
16
5
|
)
|
|
17
|
-
|
|
18
|
-
from typing_extensions import Self
|
|
19
|
-
from ex4nicegui.utils.apiEffect import ui_effect
|
|
20
|
-
import signe
|
|
21
|
-
from ex4nicegui.utils.signals import (
|
|
22
|
-
TGetterOrReadonlyRef,
|
|
23
|
-
to_value,
|
|
24
|
-
is_ref,
|
|
25
|
-
WatchedState,
|
|
26
|
-
on,
|
|
27
|
-
)
|
|
28
|
-
from ex4nicegui.utils.clientScope import new_scope
|
|
29
|
-
from nicegui import Tailwind, ui
|
|
30
|
-
from nicegui.elements.mixins.text_element import TextElement
|
|
31
|
-
from nicegui.elements.mixins.disableable_element import DisableableElement
|
|
32
|
-
from ex4nicegui.reactive.services.reactive_service import inject_handle_delete
|
|
33
|
-
from ex4nicegui.reactive.scopedStyle import ScopedStyle
|
|
34
|
-
from functools import partial
|
|
35
|
-
|
|
36
|
-
T = TypeVar("T")
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
TWidget = TypeVar("TWidget", bound=ui.element)
|
|
40
|
-
|
|
41
|
-
_T_bind_classes_type_dict = Dict[str, TGetterOrReadonlyRef[bool]]
|
|
42
|
-
_T_bind_classes_type_ref_dict = TGetterOrReadonlyRef[Dict[str, bool]]
|
|
43
|
-
_T_bind_classes_type_single = TGetterOrReadonlyRef[str]
|
|
44
|
-
_T_bind_classes_type_array = List[_T_bind_classes_type_single]
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
_T_bind_classes_type = Union[
|
|
48
|
-
_T_bind_classes_type_dict,
|
|
49
|
-
_T_bind_classes_type_ref_dict,
|
|
50
|
-
_T_bind_classes_type_single,
|
|
51
|
-
_T_bind_classes_type_array,
|
|
52
|
-
]
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class BindableUi(Generic[TWidget]):
|
|
56
|
-
def __init__(self, element: TWidget) -> None:
|
|
57
|
-
self._element = element
|
|
58
|
-
inject_handle_delete(self.element, self._on_element_delete)
|
|
59
|
-
self.tailwind = Tailwind(cast(ui.element, self._element))
|
|
60
|
-
self._effect_scope = new_scope()
|
|
61
|
-
|
|
62
|
-
def _on_element_delete(self):
|
|
63
|
-
self._effect_scope.dispose()
|
|
64
|
-
scope_style = ScopedStyle.get()
|
|
65
|
-
if scope_style:
|
|
66
|
-
scope_style.remove_style(self.element)
|
|
67
|
-
|
|
68
|
-
@property
|
|
69
|
-
def _ui_effect(self):
|
|
70
|
-
return partial(ui_effect, scope=self._effect_scope)
|
|
71
|
-
|
|
72
|
-
@property
|
|
73
|
-
def _ui_signal_on(self):
|
|
74
|
-
return partial(on, scope=self._effect_scope)
|
|
75
|
-
|
|
76
|
-
def props(self, add: Optional[str] = None, *, remove: Optional[str] = None):
|
|
77
|
-
cast(ui.element, self.element).props(add, remove=remove)
|
|
78
|
-
return self
|
|
79
|
-
|
|
80
|
-
def classes(
|
|
81
|
-
self,
|
|
82
|
-
add: Optional[str] = None,
|
|
83
|
-
*,
|
|
84
|
-
remove: Optional[str] = None,
|
|
85
|
-
replace: Optional[str] = None,
|
|
86
|
-
):
|
|
87
|
-
cast(ui.element, self.element).classes(add, remove=remove, replace=replace)
|
|
88
|
-
return self
|
|
89
|
-
|
|
90
|
-
def style(
|
|
91
|
-
self,
|
|
92
|
-
add: Optional[str] = None,
|
|
93
|
-
*,
|
|
94
|
-
remove: Optional[str] = None,
|
|
95
|
-
replace: Optional[str] = None,
|
|
96
|
-
):
|
|
97
|
-
cast(ui.element, self.element).style(add, remove=remove, replace=replace)
|
|
98
|
-
return self
|
|
99
|
-
|
|
100
|
-
def __enter__(self) -> Self:
|
|
101
|
-
self.element.__enter__()
|
|
102
|
-
return self
|
|
103
|
-
|
|
104
|
-
def __exit__(self, *_):
|
|
105
|
-
self.element.default_slot.__exit__(*_)
|
|
106
|
-
|
|
107
|
-
def tooltip(self, text: str) -> Self:
|
|
108
|
-
cast(ui.element, self.element).tooltip(text)
|
|
109
|
-
return self
|
|
110
|
-
|
|
111
|
-
def add_slot(self, name: str, template: Optional[str] = None):
|
|
112
|
-
"""Add a slot to the element.
|
|
113
|
-
|
|
114
|
-
:param name: name of the slot
|
|
115
|
-
:param template: Vue template of the slot
|
|
116
|
-
:return: the slot
|
|
117
|
-
"""
|
|
118
|
-
return cast(ui.element, self.element).add_slot(name, template)
|
|
119
|
-
|
|
120
|
-
@property
|
|
121
|
-
def element(self):
|
|
122
|
-
return self._element
|
|
123
|
-
|
|
124
|
-
def delete(self) -> None:
|
|
125
|
-
"""Delete the element."""
|
|
126
|
-
self.element.delete()
|
|
127
|
-
|
|
128
|
-
def move(
|
|
129
|
-
self, target_container: Optional[ui.element] = None, target_index: int = -1
|
|
130
|
-
):
|
|
131
|
-
"""Move the element to another container.
|
|
132
|
-
|
|
133
|
-
:param target_container: container to move the element to (default: the parent container)
|
|
134
|
-
:param target_index: index within the target slot (default: append to the end)
|
|
135
|
-
"""
|
|
136
|
-
return self.element.move(target_container, target_index)
|
|
137
|
-
|
|
138
|
-
def remove(self, element: Union[ui.element, int]) -> None:
|
|
139
|
-
"""Remove a child element.
|
|
140
|
-
|
|
141
|
-
:param element: either the element instance or its ID
|
|
142
|
-
"""
|
|
143
|
-
return self.element.remove(element)
|
|
144
|
-
|
|
145
|
-
def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef[Any]):
|
|
146
|
-
"""data binding is manipulating an element's property
|
|
147
|
-
|
|
148
|
-
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#bind_prop
|
|
149
|
-
@中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#bind_prop
|
|
150
|
-
|
|
151
|
-
Args:
|
|
152
|
-
prop (str): property name
|
|
153
|
-
ref_ui (TGetterOrReadonlyRef[Any]): a reference to the value to bind to
|
|
154
|
-
|
|
155
|
-
"""
|
|
156
|
-
if prop == "visible":
|
|
157
|
-
return self.bind_visible(ref_ui)
|
|
158
|
-
|
|
159
|
-
if prop == "text" and isinstance(self.element, TextElement):
|
|
160
|
-
|
|
161
|
-
@self._ui_effect
|
|
162
|
-
def _():
|
|
163
|
-
cast(TextElement, self.element).set_text(to_value(ref_ui))
|
|
164
|
-
self.element.update()
|
|
165
|
-
|
|
166
|
-
@self._ui_effect
|
|
167
|
-
def _():
|
|
168
|
-
element = cast(ui.element, self.element)
|
|
169
|
-
element._props[prop] = to_value(ref_ui)
|
|
170
|
-
element.update()
|
|
171
|
-
|
|
172
|
-
return self
|
|
173
|
-
|
|
174
|
-
def bind_visible(self, ref_ui: TGetterOrReadonlyRef[bool]):
|
|
175
|
-
@self._ui_effect
|
|
176
|
-
def _():
|
|
177
|
-
element = cast(ui.element, self.element)
|
|
178
|
-
element.set_visibility(to_value(ref_ui))
|
|
179
|
-
|
|
180
|
-
return self
|
|
181
|
-
|
|
182
|
-
def bind_not_visible(self, ref_ui: TGetterOrReadonlyRef[bool]):
|
|
183
|
-
return self.bind_visible(lambda: not to_value(ref_ui))
|
|
184
|
-
|
|
185
|
-
def on(
|
|
186
|
-
self,
|
|
187
|
-
type: str,
|
|
188
|
-
handler: Optional[Callable[..., Any]] = None,
|
|
189
|
-
args: Optional[List[str]] = None,
|
|
190
|
-
*,
|
|
191
|
-
throttle: float = 0.0,
|
|
192
|
-
leading_events: bool = True,
|
|
193
|
-
trailing_events: bool = True,
|
|
194
|
-
):
|
|
195
|
-
ele = cast(ui.element, self.element)
|
|
196
|
-
ele.on(
|
|
197
|
-
type,
|
|
198
|
-
handler,
|
|
199
|
-
args,
|
|
200
|
-
throttle=throttle,
|
|
201
|
-
leading_events=leading_events,
|
|
202
|
-
trailing_events=trailing_events,
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
return self
|
|
206
|
-
|
|
207
|
-
def clear(self) -> None:
|
|
208
|
-
cast(ui.element, self.element).clear()
|
|
209
|
-
|
|
210
|
-
@overload
|
|
211
|
-
def bind_classes(self, classes: Dict[str, TGetterOrReadonlyRef[bool]]):
|
|
212
|
-
...
|
|
213
|
-
|
|
214
|
-
@overload
|
|
215
|
-
def bind_classes(self, classes: TGetterOrReadonlyRef[Dict[str, bool]]):
|
|
216
|
-
...
|
|
217
|
-
|
|
218
|
-
@overload
|
|
219
|
-
def bind_classes(self, classes: List[TGetterOrReadonlyRef[str]]):
|
|
220
|
-
...
|
|
221
|
-
|
|
222
|
-
@overload
|
|
223
|
-
def bind_classes(self, classes: TGetterOrReadonlyRef[str]):
|
|
224
|
-
...
|
|
225
|
-
|
|
226
|
-
def bind_classes(self, classes: _T_bind_classes_type):
|
|
227
|
-
"""data binding is manipulating an element's class list
|
|
228
|
-
|
|
229
|
-
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#bind-class-names
|
|
230
|
-
@中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#%E7%BB%91%E5%AE%9A%E7%B1%BB%E5%90%8D
|
|
231
|
-
|
|
232
|
-
Args:
|
|
233
|
-
classes (_T_bind_classes_type): dict of refs | ref to dict | str ref | list of refs
|
|
234
|
-
|
|
235
|
-
## usage
|
|
236
|
-
|
|
237
|
-
bind class names with dict,value is bool ref, for example:
|
|
238
|
-
|
|
239
|
-
```python
|
|
240
|
-
bg_color = to_ref(True)
|
|
241
|
-
has_error = to_ref(False)
|
|
242
|
-
|
|
243
|
-
rxui.label('Hello').bind_classes({'bg-blue':bg_color, 'text-red':has_error})
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
bind list of class names with ref
|
|
247
|
-
|
|
248
|
-
```python
|
|
249
|
-
color = to_ref('red')
|
|
250
|
-
bg_color = lambda: f"bg-{color.value}"
|
|
251
|
-
|
|
252
|
-
rxui.label('Hello').bind_classes([bg_color])
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
bind single class name with ref
|
|
256
|
-
|
|
257
|
-
```python
|
|
258
|
-
color = to_ref('red')
|
|
259
|
-
bg_color = lambda: f"bg-{color.value}"
|
|
260
|
-
|
|
261
|
-
rxui.label('Hello').bind_classes(bg_color)
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
"""
|
|
265
|
-
if isinstance(classes, dict):
|
|
266
|
-
for name, ref_obj in classes.items():
|
|
267
|
-
|
|
268
|
-
@self._ui_effect
|
|
269
|
-
def _(name=name, ref_obj=ref_obj):
|
|
270
|
-
if to_value(ref_obj):
|
|
271
|
-
self.classes(add=name)
|
|
272
|
-
else:
|
|
273
|
-
self.classes(remove=name)
|
|
274
|
-
|
|
275
|
-
elif is_ref(classes) or isinstance(classes, Callable):
|
|
276
|
-
ref_obj = to_value(classes) # type: ignore
|
|
277
|
-
|
|
278
|
-
if isinstance(ref_obj, dict):
|
|
279
|
-
|
|
280
|
-
@self._ui_effect
|
|
281
|
-
def _():
|
|
282
|
-
for name, value in cast(Dict, to_value(classes)).items(): # type: ignore
|
|
283
|
-
if value:
|
|
284
|
-
self.classes(add=name)
|
|
285
|
-
else:
|
|
286
|
-
self.classes(remove=name)
|
|
287
|
-
else:
|
|
288
|
-
self._bind_single_class(cast(_T_bind_classes_type_single, classes))
|
|
289
|
-
|
|
290
|
-
elif isinstance(classes, list):
|
|
291
|
-
for ref_name in classes:
|
|
292
|
-
self._bind_single_class(ref_name)
|
|
293
|
-
|
|
294
|
-
return self
|
|
295
|
-
|
|
296
|
-
def _bind_single_class(self, class_name: _T_bind_classes_type_single):
|
|
297
|
-
if is_ref(class_name) or isinstance(class_name, Callable):
|
|
298
|
-
|
|
299
|
-
@on(class_name)
|
|
300
|
-
def _(state: WatchedState):
|
|
301
|
-
self.classes(add=state.current, remove=state.previous)
|
|
302
|
-
else:
|
|
303
|
-
self.classes(class_name) # type: ignore
|
|
304
|
-
|
|
305
|
-
return self
|
|
306
|
-
|
|
307
|
-
def bind_style(self, style: Dict[str, TGetterOrReadonlyRef[Any]]):
|
|
308
|
-
"""data binding is manipulating an element's style
|
|
309
|
-
|
|
310
|
-
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#bind-style
|
|
311
|
-
@中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#bind-style
|
|
312
|
-
|
|
313
|
-
Args:
|
|
314
|
-
style (Dict[str, Union[ReadonlyRef[str], Ref[str]]]): dict of style name and ref value
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
## usage
|
|
318
|
-
```python
|
|
319
|
-
bg_color = to_ref("blue")
|
|
320
|
-
text_color = to_ref("red")
|
|
321
|
-
|
|
322
|
-
rxui.label("test").bind_style(
|
|
323
|
-
{
|
|
324
|
-
"background-color": bg_color,
|
|
325
|
-
"color": text_color,
|
|
326
|
-
}
|
|
327
|
-
)
|
|
328
|
-
```
|
|
329
|
-
"""
|
|
330
|
-
if isinstance(style, dict):
|
|
331
|
-
for name, ref_obj in style.items():
|
|
332
|
-
if is_ref(ref_obj) or isinstance(ref_obj, Callable):
|
|
333
|
-
|
|
334
|
-
@self._ui_effect
|
|
335
|
-
def _(name=name, ref_obj=ref_obj):
|
|
336
|
-
self.element._style[name] = str(to_value(ref_obj))
|
|
337
|
-
self.element.update()
|
|
338
|
-
|
|
339
|
-
return self
|
|
340
|
-
|
|
341
|
-
def scoped_style(self, selector: str, style: Union[str, Path]):
|
|
342
|
-
"""add scoped style to the element
|
|
343
|
-
|
|
344
|
-
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#scoped_style
|
|
345
|
-
@中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#scoped_style
|
|
346
|
-
|
|
347
|
-
Args:
|
|
348
|
-
selector (str): css selector
|
|
349
|
-
style (Union[str, Path]): path to css file or inline style string
|
|
350
|
-
|
|
351
|
-
## usage
|
|
352
|
-
```python
|
|
353
|
-
# all children of the element will have red outline, excluding itself
|
|
354
|
-
with rxui.row().scoped_style("*", "outline: 1px solid red;") as row:
|
|
355
|
-
ui.label("Hello")
|
|
356
|
-
ui.label("World")
|
|
357
|
-
|
|
358
|
-
# all children of the element will have red outline, including the element itself
|
|
359
|
-
with rxui.row().scoped_style(":self *", "outline: 1px solid red;") as row:
|
|
360
|
-
ui.label("Hello")
|
|
361
|
-
ui.label("World")
|
|
362
|
-
|
|
363
|
-
# all children of the element will have red outline when element is hovered
|
|
364
|
-
with rxui.row().scoped_style(":hover *", "outline: 1px solid red;") as row:
|
|
365
|
-
ui.label("Hello")
|
|
366
|
-
ui.label("World")
|
|
367
|
-
|
|
368
|
-
# all children of the element and itself will have red outline when element is hovered
|
|
369
|
-
with rxui.row().scoped_style(":self:hover *", "outline: 1px solid red;") as row:
|
|
370
|
-
ui.label("Hello")
|
|
371
|
-
ui.label("World")
|
|
372
|
-
```
|
|
373
|
-
"""
|
|
374
|
-
|
|
375
|
-
is_css_file = isinstance(style, Path)
|
|
376
|
-
|
|
377
|
-
if is_css_file:
|
|
378
|
-
style = style.read_text(encoding="utf-8")
|
|
379
|
-
|
|
380
|
-
id = f"c{self.element.id}"
|
|
381
|
-
selector_with_self = _utils._parent_id_with_selector(id, selector, is_css_file)
|
|
382
|
-
css = ""
|
|
383
|
-
if is_css_file:
|
|
384
|
-
css = f"{selector_with_self} {style}"
|
|
385
|
-
else:
|
|
386
|
-
css = f"{selector_with_self}{{{style}}}"
|
|
387
|
-
|
|
388
|
-
scope_style = ScopedStyle.get()
|
|
389
|
-
assert scope_style, "can not find scope style"
|
|
390
|
-
scope_style.create_style(self.element, css)
|
|
391
|
-
|
|
392
|
-
return self
|
|
393
|
-
|
|
394
|
-
def update(self):
|
|
395
|
-
"""Update the element on the client side."""
|
|
396
|
-
self.element.update()
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
class _utils:
|
|
400
|
-
@staticmethod
|
|
401
|
-
def _parent_id_with_selector(
|
|
402
|
-
parent_id: str, selector: str, is_css_file=False
|
|
403
|
-
) -> str:
|
|
404
|
-
selector_with_self = f"#{parent_id}"
|
|
405
|
-
|
|
406
|
-
selector = selector.strip()
|
|
407
|
-
if (not selector) and (not is_css_file):
|
|
408
|
-
selector = "* "
|
|
409
|
-
|
|
410
|
-
if selector.startswith(":self"):
|
|
411
|
-
selector = selector[5:].lstrip()
|
|
412
|
-
parent_selector = f"#{parent_id}"
|
|
413
|
-
if selector.startswith(":"):
|
|
414
|
-
parent_selector = f"{parent_selector}{selector.split()[0]}"
|
|
415
|
-
|
|
416
|
-
selector_with_self = f"{parent_selector},{selector_with_self}"
|
|
417
|
-
|
|
418
|
-
if not selector.startswith(":"):
|
|
419
|
-
selector_with_self = selector_with_self + " "
|
|
420
|
-
|
|
421
|
-
selector_with_self = selector_with_self + selector
|
|
422
|
-
return selector_with_self
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
_T_DisableableBinder = TypeVar("_T_DisableableBinder", bound=DisableableElement)
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
class DisableableMixin(Protocol):
|
|
429
|
-
_ui_effect: Callable[[Callable[..., Any]], signe.Effect[None]]
|
|
430
|
-
|
|
431
|
-
@property
|
|
432
|
-
def element(self) -> DisableableElement:
|
|
433
|
-
...
|
|
434
|
-
|
|
435
|
-
def bind_enabled(self, ref_ui: TGetterOrReadonlyRef[bool]):
|
|
436
|
-
@self._ui_effect
|
|
437
|
-
def _():
|
|
438
|
-
value = to_value(ref_ui)
|
|
439
|
-
self.element.set_enabled(value)
|
|
440
|
-
self.element._handle_enabled_change(value)
|
|
441
|
-
|
|
442
|
-
return self
|
|
443
|
-
|
|
444
|
-
def bind_disable(self, ref_ui: TGetterOrReadonlyRef[bool]):
|
|
445
|
-
@self._ui_effect
|
|
446
|
-
def _():
|
|
447
|
-
value = not to_value(ref_ui)
|
|
448
|
-
self.element.set_enabled(value)
|
|
449
|
-
self.element._handle_enabled_change(value)
|
|
450
|
-
|
|
451
|
-
return self
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
DisableableBindableUi = DisableableMixin
|
|
@@ -10,10 +10,21 @@ from ex4nicegui.utils.signals import (
|
|
|
10
10
|
to_value,
|
|
11
11
|
)
|
|
12
12
|
from nicegui import ui
|
|
13
|
-
from .base import
|
|
13
|
+
from .base import (
|
|
14
|
+
BindableUi,
|
|
15
|
+
DisableableMixin,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from ex4nicegui.reactive.mixins.backgroundColor import BackgroundColorableMixin
|
|
19
|
+
from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
|
|
14
20
|
|
|
15
21
|
|
|
16
|
-
class ButtonBindableUi(
|
|
22
|
+
class ButtonBindableUi(
|
|
23
|
+
BindableUi[ui.button],
|
|
24
|
+
DisableableMixin,
|
|
25
|
+
BackgroundColorableMixin,
|
|
26
|
+
TextColorableMixin,
|
|
27
|
+
):
|
|
17
28
|
def __init__(
|
|
18
29
|
self,
|
|
19
30
|
text: TMaybeRef[str] = "",
|
|
@@ -38,9 +49,31 @@ class ButtonBindableUi(BindableUi[ui.button], DisableableMixin):
|
|
|
38
49
|
return self.bind_text(ref_ui)
|
|
39
50
|
if prop == "icon":
|
|
40
51
|
return self.bind_icon(ref_ui)
|
|
52
|
+
if prop == "color":
|
|
53
|
+
return self.bind_color(ref_ui)
|
|
41
54
|
|
|
42
55
|
return super().bind_prop(prop, ref_ui)
|
|
43
56
|
|
|
57
|
+
def bind_color(self, ref_ui: TGetterOrReadonlyRef[str]):
|
|
58
|
+
"""Binds the background color of the button.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
ref_ui (TGetterOrReadonlyRef[str]): Getter or readonly reference to the color.
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
BackgroundColorableMixin.bind_color(self, ref_ui)
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
def bind_text_color(self, ref_ui: TGetterOrReadonlyRef[str]):
|
|
68
|
+
"""Binds the text color of the button.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
ref_ui (TGetterOrReadonlyRef[str]): Getter or readonly reference to the color.
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
TextColorableMixin.bind_color(self, ref_ui)
|
|
75
|
+
return self
|
|
76
|
+
|
|
44
77
|
def bind_text(self, ref_ui: TGetterOrReadonlyRef):
|
|
45
78
|
@self._ui_effect
|
|
46
79
|
def _():
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from typing import Any, Callable, Optional
|
|
2
|
+
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
3
|
+
from ex4nicegui.utils.signals import (
|
|
4
|
+
TGetterOrReadonlyRef,
|
|
5
|
+
to_value,
|
|
6
|
+
_TMaybeRef as TMaybeRef,
|
|
7
|
+
)
|
|
8
|
+
from nicegui import ui
|
|
9
|
+
from .base import BindableUi
|
|
10
|
+
from ex4nicegui.reactive.mixins.backgroundColor import BackgroundColorableMixin
|
|
11
|
+
from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ChipBindableUi(
|
|
15
|
+
BindableUi[ui.chip],
|
|
16
|
+
BackgroundColorableMixin,
|
|
17
|
+
TextColorableMixin,
|
|
18
|
+
):
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
text: TMaybeRef[str] = "",
|
|
22
|
+
*,
|
|
23
|
+
icon: Optional[TMaybeRef[str]] = None,
|
|
24
|
+
color: Optional[TMaybeRef[str]] = "primary",
|
|
25
|
+
text_color: Optional[TMaybeRef[str]] = None,
|
|
26
|
+
on_click: Optional[Callable[..., Any]] = None,
|
|
27
|
+
selectable: TMaybeRef[bool] = False,
|
|
28
|
+
selected: TMaybeRef[bool] = False,
|
|
29
|
+
on_selection_change: Optional[Callable[..., Any]] = None,
|
|
30
|
+
removable: TMaybeRef[bool] = False,
|
|
31
|
+
on_value_change: Optional[Callable[..., Any]] = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
pc = ParameterClassifier(
|
|
34
|
+
locals(),
|
|
35
|
+
maybeRefs=[
|
|
36
|
+
"text",
|
|
37
|
+
"icon",
|
|
38
|
+
"color",
|
|
39
|
+
"text_color",
|
|
40
|
+
"selectable",
|
|
41
|
+
"selected",
|
|
42
|
+
"removable",
|
|
43
|
+
],
|
|
44
|
+
events=["on_click", "on_selection_change", "on_value_change"],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
element = ui.chip(**pc.get_values_kws())
|
|
48
|
+
super().__init__(element)
|
|
49
|
+
|
|
50
|
+
for key, value in pc.get_bindings().items():
|
|
51
|
+
self.bind_prop(key, value) # type: ignore
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def text(self):
|
|
55
|
+
return self.element.text
|
|
56
|
+
|
|
57
|
+
def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef):
|
|
58
|
+
if prop == "text":
|
|
59
|
+
return self.bind_text(ref_ui)
|
|
60
|
+
|
|
61
|
+
if prop == "color":
|
|
62
|
+
return self.bind_color(ref_ui)
|
|
63
|
+
if prop == "text-color":
|
|
64
|
+
return self.bind_text_color(ref_ui)
|
|
65
|
+
|
|
66
|
+
return super().bind_prop(prop, ref_ui)
|
|
67
|
+
|
|
68
|
+
def bind_color(self, color: TGetterOrReadonlyRef):
|
|
69
|
+
"""Binds the background color property of the chip to a ui element.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
color (TGetterOrReadonlyRef): background color ui element or getter function
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
BackgroundColorableMixin.bind_color(self, color)
|
|
76
|
+
return self
|
|
77
|
+
|
|
78
|
+
def bind_text_color(self, color: TGetterOrReadonlyRef):
|
|
79
|
+
"""Binds the text color property of the chip to a ui element.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
color (TGetterOrReadonlyRef): text color ui element or getter function
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
TextColorableMixin.bind_color(self, color)
|
|
87
|
+
return self
|
|
88
|
+
|
|
89
|
+
def bind_text(self, text: TGetterOrReadonlyRef):
|
|
90
|
+
"""Binds the text property of the chip to a ui element.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
text (TGetterOrReadonlyRef): text ui element or getter function
|
|
94
|
+
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
@self._ui_effect
|
|
98
|
+
def _():
|
|
99
|
+
self.element.set_text(str(to_value(text)))
|
|
100
|
+
self.element.update()
|
|
101
|
+
|
|
102
|
+
return self
|
|
@@ -10,11 +10,11 @@ from ex4nicegui.utils.signals import (
|
|
|
10
10
|
)
|
|
11
11
|
from nicegui import ui
|
|
12
12
|
from .base import BindableUi, DisableableMixin
|
|
13
|
+
from ex4nicegui.reactive.mixins.backgroundColor import BackgroundColorableMixin
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class CircularProgressBindableUi(
|
|
16
|
-
BindableUi[ui.circular_progress],
|
|
17
|
-
DisableableMixin,
|
|
17
|
+
BindableUi[ui.circular_progress], DisableableMixin, BackgroundColorableMixin
|
|
18
18
|
):
|
|
19
19
|
def __init__(
|
|
20
20
|
self,
|
|
@@ -52,6 +52,8 @@ class CircularProgressBindableUi(
|
|
|
52
52
|
def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef):
|
|
53
53
|
if prop == "value":
|
|
54
54
|
return self.bind_value(ref_ui)
|
|
55
|
+
if prop == "color":
|
|
56
|
+
return self.bind_color(ref_ui)
|
|
55
57
|
|
|
56
58
|
return super().bind_prop(prop, ref_ui)
|
|
57
59
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import (
|
|
2
2
|
Any,
|
|
3
3
|
Optional,
|
|
4
|
+
Union,
|
|
4
5
|
)
|
|
5
6
|
|
|
6
7
|
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
@@ -13,8 +14,8 @@ from ex4nicegui.utils.signals import _TMaybeRef as TMaybeRef
|
|
|
13
14
|
class GridBindableUi(BindableUi[ui.grid]):
|
|
14
15
|
def __init__(
|
|
15
16
|
self,
|
|
16
|
-
rows: Optional[TMaybeRef[int]] = None,
|
|
17
|
-
columns: Optional[TMaybeRef[int]] = None,
|
|
17
|
+
rows: Optional[TMaybeRef[Union[int, str]]] = None,
|
|
18
|
+
columns: Optional[TMaybeRef[Union[int, str]]] = None,
|
|
18
19
|
) -> None:
|
|
19
20
|
pc = ParameterClassifier(locals(), maybeRefs=["rows", "columns"], events=[])
|
|
20
21
|
|
|
@@ -13,10 +13,10 @@ from nicegui.elements.mixins.color_elements import (
|
|
|
13
13
|
TextColorElement,
|
|
14
14
|
)
|
|
15
15
|
from .base import BindableUi
|
|
16
|
-
from ex4nicegui.reactive.
|
|
16
|
+
from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class IconBindableUi(BindableUi[ui.icon]):
|
|
19
|
+
class IconBindableUi(BindableUi[ui.icon], TextColorableMixin):
|
|
20
20
|
def __init__(
|
|
21
21
|
self,
|
|
22
22
|
name: TMaybeRef[str],
|
|
@@ -43,9 +43,6 @@ class IconBindableUi(BindableUi[ui.icon]):
|
|
|
43
43
|
|
|
44
44
|
return super().bind_prop(prop, ref_ui)
|
|
45
45
|
|
|
46
|
-
def bind_color(self, ref_ui: TGetterOrReadonlyRef):
|
|
47
|
-
return color_service.bind_color(self, ref_ui)
|
|
48
|
-
|
|
49
46
|
def bind_name(self, ref_ui: TGetterOrReadonlyRef):
|
|
50
47
|
@self._ui_effect
|
|
51
48
|
def _():
|
|
@@ -11,11 +11,13 @@ from ex4nicegui.utils.signals import (
|
|
|
11
11
|
)
|
|
12
12
|
from nicegui import ui
|
|
13
13
|
from .base import BindableUi, DisableableMixin
|
|
14
|
+
from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class KnobBindableUi(
|
|
17
18
|
BindableUi[ui.knob],
|
|
18
19
|
DisableableMixin,
|
|
20
|
+
TextColorableMixin,
|
|
19
21
|
):
|
|
20
22
|
def __init__(
|
|
21
23
|
self,
|
|
@@ -62,6 +64,8 @@ class KnobBindableUi(
|
|
|
62
64
|
def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef):
|
|
63
65
|
if prop == "value":
|
|
64
66
|
return self.bind_value(ref_ui)
|
|
67
|
+
if prop == "color":
|
|
68
|
+
return self.bind_color(ref_ui)
|
|
65
69
|
|
|
66
70
|
return super().bind_prop(prop, ref_ui)
|
|
67
71
|
|