ex4nicegui 0.2.3__py3-none-any.whl → 0.2.5__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.
Files changed (36) hide show
  1. ex4nicegui/__init__.py +1 -1
  2. ex4nicegui/reactive/__index.py +1 -31
  3. ex4nicegui/reactive/officials/__init__.py +37 -0
  4. ex4nicegui/reactive/officials/aggrid.py +81 -0
  5. ex4nicegui/reactive/officials/base.py +167 -0
  6. ex4nicegui/reactive/officials/button.py +86 -0
  7. ex4nicegui/reactive/officials/card.py +59 -0
  8. ex4nicegui/reactive/officials/checkbox.py +68 -0
  9. ex4nicegui/reactive/officials/color_picker.py +101 -0
  10. ex4nicegui/reactive/officials/date.py +85 -0
  11. ex4nicegui/reactive/officials/drawer.py +88 -0
  12. ex4nicegui/reactive/officials/echarts.py +70 -0
  13. ex4nicegui/reactive/officials/html.py +66 -0
  14. ex4nicegui/reactive/officials/icon.py +62 -0
  15. ex4nicegui/reactive/officials/image.py +54 -0
  16. ex4nicegui/reactive/officials/input.py +116 -0
  17. ex4nicegui/reactive/officials/label.py +67 -0
  18. ex4nicegui/reactive/officials/radio.py +80 -0
  19. ex4nicegui/reactive/officials/row.py +21 -0
  20. ex4nicegui/reactive/officials/select.py +93 -0
  21. ex4nicegui/reactive/officials/slider.py +97 -0
  22. ex4nicegui/reactive/officials/switch.py +72 -0
  23. ex4nicegui/reactive/officials/table.py +144 -0
  24. ex4nicegui/reactive/officials/textarea.py +103 -0
  25. ex4nicegui/reactive/officials/upload.py +78 -0
  26. ex4nicegui/reactive/officials/utils.py +11 -0
  27. {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/METADATA +1 -1
  28. ex4nicegui-0.2.5.dist-info/RECORD +56 -0
  29. ex4nicegui/reactive/officials.py +0 -1585
  30. ex4nicegui-0.2.3.dist-info/RECORD +0 -33
  31. {ex4nicegui-0.2.3.data → ex4nicegui-0.2.5.data}/data/ECharts/ECharts.js +0 -0
  32. {ex4nicegui-0.2.3.data → ex4nicegui-0.2.5.data}/data/UseDraggable/UseDraggable.js +0 -0
  33. {ex4nicegui-0.2.3.data → ex4nicegui-0.2.5.data}/data/useMouse/UseMouse.js +0 -0
  34. {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/LICENSE +0 -0
  35. {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/WHEEL +0 -0
  36. {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/top_level.txt +0 -0
@@ -1,1585 +0,0 @@
1
- from __future__ import annotations
2
- import asyncio
3
- from pathlib import Path
4
-
5
- from typing import (
6
- Any,
7
- Callable,
8
- List,
9
- Optional,
10
- TypeVar,
11
- Generic,
12
- cast,
13
- Dict,
14
- Union,
15
- overload,
16
- )
17
- from typing_extensions import Literal, Self
18
- from signe import effect
19
- from ex4nicegui.utils.signals import (
20
- ReadonlyRef,
21
- Ref,
22
- ref_computed,
23
- to_ref,
24
- to_value,
25
- is_ref,
26
- _TMaybeRef as TMaybeRef,
27
- )
28
- import ex4nicegui.utils.common as utils_common
29
- from nicegui import Tailwind, ui
30
- from nicegui import events as ng_events
31
- from nicegui.elements.mixins.text_element import TextElement
32
- from nicegui.elements.mixins.value_element import ValueElement
33
- from nicegui.elements.mixins.color_elements import (
34
- TextColorElement,
35
- QUASAR_COLORS,
36
- TAILWIND_COLORS,
37
- )
38
- from nicegui.page_layout import Drawer
39
- from ex4nicegui.reactive.ECharts.ECharts import echarts
40
-
41
- T = TypeVar("T")
42
-
43
- TWidget = TypeVar("TWidget")
44
-
45
-
46
- class BindableUi(Generic[TWidget]):
47
- def __init__(self, element: TWidget) -> None:
48
- self.__element = element
49
-
50
- def props(self, add: Optional[str] = None, *, remove: Optional[str] = None):
51
- cast(ui.element, self.element).props(add, remove=remove)
52
- return self
53
-
54
- def classes(
55
- self,
56
- add: Optional[str] = None,
57
- *,
58
- remove: Optional[str] = None,
59
- replace: Optional[str] = None,
60
- ):
61
- cast(ui.element, self.element).classes(add, remove=remove, replace=replace)
62
- return self
63
-
64
- def style(
65
- self,
66
- add: Optional[str] = None,
67
- *,
68
- remove: Optional[str] = None,
69
- replace: Optional[str] = None,
70
- ):
71
- cast(ui.element, self.element).style(add, remove=remove, replace=replace)
72
- return self
73
-
74
- @overload
75
- def tailwind(self, *tailwind: Tailwind) -> Self:
76
- ...
77
-
78
- @overload
79
- def tailwind(self, *classes: str) -> Self:
80
- ...
81
-
82
- def tailwind(self, *args):
83
- cast(ui.element, self.element).tailwind(*args)
84
- return self
85
-
86
- def tooltip(self, text: str) -> Self:
87
- cast(ui.element, self.element).tooltip(text)
88
- return self
89
-
90
- def add_slot(self, name: str, template: Optional[str] = None):
91
- """Add a slot to the element.
92
-
93
- :param name: name of the slot
94
- :param template: Vue template of the slot
95
- :return: the slot
96
- """
97
- return cast(ui.element, self.element).add_slot(name, template)
98
-
99
- @property
100
- def element(self):
101
- return self.__element
102
-
103
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
104
- if prop == "visible":
105
- return self.bind_visible(ref_ui)
106
-
107
- @effect
108
- def _():
109
- element = cast(ui.element, self.element)
110
- element._props[prop] = ref_ui.value
111
- element.update()
112
-
113
- return self
114
-
115
- def bind_visible(self, ref_ui: ReadonlyRef[bool]):
116
- @effect
117
- def _():
118
- element = cast(ui.element, self.element)
119
- element.set_visibility(ref_ui.value)
120
-
121
- return self
122
-
123
- def on(
124
- self,
125
- type: str,
126
- handler: Optional[Callable[..., Any]] = None,
127
- args: Optional[List[str]] = None,
128
- *,
129
- throttle: float = 0.0,
130
- leading_events: bool = True,
131
- trailing_events: bool = True,
132
- ):
133
- ele = cast(ui.element, self.element)
134
- ele.on(
135
- type,
136
- handler,
137
- args,
138
- throttle=throttle,
139
- leading_events=leading_events,
140
- trailing_events=trailing_events,
141
- )
142
-
143
- return self
144
-
145
- def clear(self) -> None:
146
- cast(ui.element, self.element).clear()
147
-
148
-
149
- class SingleValueBindableUi(BindableUi[TWidget], Generic[T, TWidget]):
150
- def __init__(self, value: TMaybeRef[T], element: TWidget) -> None:
151
- super().__init__(element)
152
- self._ref = to_ref(value)
153
-
154
- @property
155
- def value(self) -> T:
156
- return self._ref.value
157
-
158
- def bind_ref(self, ref: Ref[T]):
159
- @effect
160
- def _():
161
- ref.value = self._ref.value
162
-
163
- return self
164
-
165
-
166
- def _bind_color(bindable_ui: SingleValueBindableUi, ref_ui: ReadonlyRef):
167
- @effect
168
- def _():
169
- ele = cast(TextColorElement, bindable_ui.element)
170
- color = ref_ui.value
171
-
172
- if color in QUASAR_COLORS:
173
- ele._props[ele.TEXT_COLOR_PROP] = color
174
- elif color in TAILWIND_COLORS:
175
- ele.classes(replace=f"text-{color}")
176
- elif color is not None:
177
- ele._style["color"] = color
178
- ele.update()
179
-
180
- return bindable_ui
181
-
182
-
183
- class TextColorElementBindableUi(SingleValueBindableUi[T, TWidget]):
184
- def __init__(self, value: T, element: TWidget) -> None:
185
- super().__init__(value, element)
186
-
187
- ele = cast(TextColorElement, element)
188
-
189
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
190
- if prop == "name":
191
- return self.bind_name(ref_ui)
192
-
193
- if prop == "color":
194
- return self.bind_color(ref_ui)
195
-
196
- return super().bind_prop(prop, ref_ui)
197
-
198
- def bind_color(self, ref_ui: ReadonlyRef):
199
- return _bind_color(self, ref_ui)
200
-
201
- def bind_name(self, ref_ui: ReadonlyRef):
202
- @effect
203
- def _():
204
- ele = cast(TextColorElement, self.element)
205
- ele._props["name"] = ref_ui.value
206
- ele.update()
207
-
208
- return self
209
-
210
-
211
- def _convert_kws_ref2value(kws: Dict):
212
- return {key: to_value(value) for key, value in kws.items()}
213
-
214
-
215
- class SelectBindableUi(SingleValueBindableUi[T, ui.select]):
216
- @staticmethod
217
- def _setup_(binder: "SelectBindableUi"):
218
- def onValueChanged(e):
219
- binder._ref.value = e.args["label"] # type: ignore
220
-
221
- @effect
222
- def _():
223
- binder.element.value = binder.value
224
-
225
- binder.element.on("update:modelValue", handler=onValueChanged)
226
-
227
- def __init__(
228
- self,
229
- options: Union[TMaybeRef[List], TMaybeRef[Dict]],
230
- *,
231
- label: Optional[TMaybeRef[str]] = None,
232
- value: TMaybeRef[Any] = None,
233
- on_change: Optional[Callable[..., Any]] = None,
234
- with_input: TMaybeRef[bool] = False,
235
- multiple: TMaybeRef[bool] = False,
236
- clearable: TMaybeRef[bool] = False,
237
- ) -> None:
238
- kws = {
239
- "options": options,
240
- "label": label,
241
- "value": value,
242
- "on_change": on_change,
243
- "with_input": with_input,
244
- "multiple": multiple,
245
- "clearable": clearable,
246
- }
247
-
248
- value_kws = _convert_kws_ref2value(kws)
249
-
250
- element = ui.select(**value_kws)
251
- element.classes("min-w-[10rem]")
252
-
253
- super().__init__(value, element)
254
-
255
- for key, value in kws.items():
256
- if is_ref(value):
257
- self.bind_prop(key, value)
258
-
259
- SelectBindableUi._setup_(self)
260
-
261
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
262
- if prop == "value":
263
- return self.bind_text(ref_ui)
264
-
265
- if prop == "options":
266
- return self.bind_options(ref_ui)
267
-
268
- return super().bind_prop(prop, ref_ui)
269
-
270
- def bind_options(self, ref_ui: ReadonlyRef):
271
- @effect
272
- def _():
273
- self.element.options = ref_ui.value
274
- self.element.update()
275
-
276
- return self
277
-
278
- def bind_text(self, ref_ui: ReadonlyRef):
279
- @effect
280
- def _():
281
- cast(ValueElement, self.element).on_value_change(ref_ui.value)
282
-
283
- return self
284
-
285
-
286
- class RadioBindableUi(SingleValueBindableUi[bool, ui.radio]):
287
- @staticmethod
288
- def _setup_(binder: "RadioBindableUi"):
289
- def onValueChanged(e):
290
- binder._ref.value = binder.element.options[e.args] # type: ignore
291
-
292
- @effect
293
- def _():
294
- binder.element.value = binder.value
295
-
296
- binder.element.on("update:modelValue", handler=onValueChanged)
297
-
298
- def __init__(
299
- self,
300
- options: Union[TMaybeRef[List], TMaybeRef[Dict]],
301
- *,
302
- value: TMaybeRef[Any] = None,
303
- on_change: Optional[Callable[..., Any]] = None,
304
- ) -> None:
305
- kws = {"options": options, "value": value, "on_change": on_change}
306
-
307
- value_kws = _convert_kws_ref2value(kws)
308
-
309
- element = ui.radio(**value_kws)
310
-
311
- super().__init__(value, element)
312
-
313
- for key, value in kws.items():
314
- if is_ref(value):
315
- self.bind_prop(key, value)
316
-
317
- RadioBindableUi._setup_(self)
318
-
319
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
320
- if prop == "value":
321
- return self.bind_value(ref_ui)
322
-
323
- if prop == "options":
324
- return self.bind_options(ref_ui)
325
-
326
- return super().bind_prop(prop, ref_ui)
327
-
328
- def bind_options(self, ref_ui: ReadonlyRef):
329
- @effect
330
- def _():
331
- self.element.options = ref_ui.value
332
- self.element.update()
333
-
334
- return self
335
-
336
- def bind_value(self, ref_ui: ReadonlyRef):
337
- @effect
338
- def _():
339
- cast(ValueElement, self.element).on_value_change(ref_ui.value)
340
-
341
- return self
342
-
343
-
344
- class SwitchBindableUi(SingleValueBindableUi[bool, ui.switch]):
345
- @staticmethod
346
- def _setup_(binder: "SwitchBindableUi"):
347
- def onValueChanged(e):
348
- ele._send_update_on_value_change = ele.LOOPBACK
349
- cur_value = ele._event_args_to_value(e)
350
- ele.set_value(cur_value)
351
- ele._send_update_on_value_change = True
352
- binder._ref.value = cur_value
353
-
354
- ele = cast(ValueElement, binder.element)
355
-
356
- @effect
357
- def _():
358
- ele.value = binder.value
359
-
360
- ele.on("update:modelValue", onValueChanged, [None], throttle=0) # type: ignore
361
-
362
- def __init__(
363
- self,
364
- text: TMaybeRef[str] = "",
365
- *,
366
- value: TMaybeRef[bool] = False,
367
- on_change: Optional[Callable[..., Any]] = None,
368
- ) -> None:
369
- kws = {"text": text, "value": value, "on_change": on_change}
370
-
371
- value_kws = _convert_kws_ref2value(kws)
372
-
373
- element = ui.switch(**value_kws)
374
-
375
- super().__init__(value, element)
376
-
377
- for key, value in kws.items():
378
- if is_ref(value):
379
- self.bind_prop(key, value) # type: ignore
380
-
381
- SwitchBindableUi._setup_(self)
382
-
383
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
384
- if prop == "value":
385
- return self.bind_value(ref_ui)
386
-
387
- return super().bind_prop(prop, ref_ui)
388
-
389
- def bind_value(self, ref_ui: ReadonlyRef[bool]):
390
- @effect
391
- def _():
392
- self.element.on_value_change(ref_ui.value)
393
-
394
- return self
395
-
396
-
397
- class CheckboxBindableUi(SingleValueBindableUi[bool, ui.checkbox]):
398
- @staticmethod
399
- def _setup_(binder: "CheckboxBindableUi"):
400
- def onValueChanged(e):
401
- binder._ref.value = e.args # type: ignore
402
-
403
- ele = cast(ValueElement, binder.element)
404
-
405
- @effect
406
- def _():
407
- ele.value = binder.value
408
-
409
- ele.on("update:modelValue", handler=onValueChanged)
410
-
411
- def __init__(
412
- self,
413
- text: str = "",
414
- *,
415
- value: bool = False,
416
- on_change: Optional[Callable[..., Any]] = None,
417
- ) -> None:
418
- kws = {"text": text, "value": value, "on_change": on_change}
419
-
420
- value_kws = _convert_kws_ref2value(kws)
421
-
422
- element = ui.checkbox(**value_kws)
423
-
424
- super().__init__(value, element)
425
-
426
- for key, value in kws.items():
427
- if is_ref(value):
428
- self.bind_prop(key, value) # type: ignore
429
-
430
- CheckboxBindableUi._setup_(self)
431
-
432
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
433
- if prop == "value":
434
- return self.bind_value(ref_ui)
435
-
436
- return super().bind_prop(prop, ref_ui)
437
-
438
- def bind_value(self, ref_ui: ReadonlyRef[bool]):
439
- @effect
440
- def _():
441
- self.element.on_value_change(ref_ui.value)
442
-
443
- return self
444
-
445
-
446
- class DateBindableUi(SingleValueBindableUi[Optional[str], ui.date]):
447
- def __init__(
448
- self,
449
- value: TMaybeRef[Optional[str]] = None,
450
- *,
451
- mask: TMaybeRef[str] = "YYYY-MM-DD",
452
- on_change: Optional[Callable[..., Any]] = None,
453
- ) -> None:
454
- kws = {
455
- "value": value,
456
- "mask": mask,
457
- "on_change": on_change,
458
- }
459
-
460
- value_kws = _convert_kws_ref2value(kws)
461
-
462
- element = ui.date(**value_kws)
463
-
464
- super().__init__(value, element)
465
-
466
- for key, value in kws.items():
467
- if is_ref(value) and key != "value":
468
- self.bind_prop(key, value) # type: ignore
469
-
470
- self._ex_setup()
471
-
472
- def _ex_setup(self):
473
- ele = self.element
474
-
475
- @effect
476
- def _():
477
- ele.value = self.value
478
-
479
- def onModelValueChanged(e):
480
- self._ref.value = e.args[0] or "" # type: ignore
481
-
482
- ele.on("update:modelValue", handler=onModelValueChanged)
483
-
484
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
485
- if prop == "value":
486
- return self.bind_value(ref_ui)
487
-
488
- return super().bind_prop(prop, ref_ui)
489
-
490
- def bind_value(self, ref_ui: ReadonlyRef[bool]):
491
- @effect
492
- def _():
493
- self.element.on_value_change(ref_ui.value)
494
-
495
- return self
496
-
497
-
498
- class InputBindableUi(SingleValueBindableUi[str, ui.input]):
499
- def __init__(
500
- self,
501
- label: Optional[TMaybeRef[str]] = None,
502
- *,
503
- placeholder: Optional[TMaybeRef[str]] = None,
504
- value: TMaybeRef[str] = "",
505
- password: TMaybeRef[bool] = False,
506
- password_toggle_button: TMaybeRef[bool] = False,
507
- on_change: Optional[Callable[..., Any]] = None,
508
- autocomplete: Optional[TMaybeRef[List[str]]] = None,
509
- validation: Dict[str, Callable[..., bool]] = {},
510
- ) -> None:
511
- kws = {
512
- "label": label,
513
- "placeholder": placeholder,
514
- "value": value,
515
- "password": password,
516
- "password_toggle_button": password_toggle_button,
517
- "autocomplete": autocomplete,
518
- "validation": validation,
519
- "on_change": on_change,
520
- }
521
-
522
- value_kws = _convert_kws_ref2value(kws)
523
-
524
- element = ui.input(**value_kws)
525
-
526
- super().__init__(value, element)
527
-
528
- for key, value in kws.items():
529
- if is_ref(value) and key != "value":
530
- self.bind_prop(key, value) # type: ignore
531
-
532
- self._ex_setup()
533
-
534
- def _ex_setup(self):
535
- ele = self.element
536
-
537
- @effect
538
- def _():
539
- ele.value = self.value
540
-
541
- def onModelValueChanged(e):
542
- self._ref.value = e.args or "" # type: ignore
543
-
544
- ele.on("update:modelValue", handler=onModelValueChanged)
545
-
546
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
547
- if prop == "value":
548
- return self.bind_value(ref_ui)
549
-
550
- return super().bind_prop(prop, ref_ui)
551
-
552
- def bind_value(self, ref_ui: ReadonlyRef[bool]):
553
- @effect
554
- def _():
555
- self.element.on_value_change(ref_ui.value)
556
-
557
- return self
558
-
559
-
560
- class LazyInputBindableUi(InputBindableUi):
561
- def __init__(
562
- self,
563
- label: Optional[TMaybeRef[str]] = None,
564
- *,
565
- placeholder: Optional[TMaybeRef[str]] = None,
566
- value: TMaybeRef[str] = "",
567
- password: TMaybeRef[bool] = False,
568
- password_toggle_button: TMaybeRef[bool] = False,
569
- on_change: Optional[Callable[..., Any]] = None,
570
- autocomplete: Optional[TMaybeRef[List[str]]] = None,
571
- validation: Dict[str, Callable[..., bool]] = {},
572
- ) -> None:
573
- super().__init__(
574
- label,
575
- placeholder=placeholder,
576
- value=value,
577
- password=password,
578
- password_toggle_button=password_toggle_button,
579
- on_change=on_change,
580
- autocomplete=autocomplete,
581
- validation=validation,
582
- )
583
-
584
- def _ex_setup(self):
585
- ele = self.element
586
-
587
- @effect
588
- def _():
589
- ele.value = self.value
590
-
591
- def onValueChanged():
592
- self._ref.value = ele.value or ""
593
-
594
- ele.on("blur", onValueChanged)
595
- ele.on("keyup.enter", onValueChanged)
596
-
597
-
598
- _TSliderValue = TypeVar("_TSliderValue", float, int, None)
599
-
600
-
601
- class SliderBindableUi(SingleValueBindableUi[Optional[_TSliderValue], ui.slider]):
602
- def __init__(
603
- self,
604
- min: TMaybeRef[_TSliderValue],
605
- max: TMaybeRef[_TSliderValue],
606
- step: TMaybeRef[_TSliderValue] = 1.0,
607
- value: Optional[TMaybeRef[_TSliderValue]] = None,
608
- on_change: Optional[Callable[..., Any]] = None,
609
- ) -> None:
610
- kws = {
611
- "min": min,
612
- "max": max,
613
- "step": step,
614
- "value": value,
615
- "on_change": on_change,
616
- }
617
-
618
- value_kws = _convert_kws_ref2value(kws)
619
-
620
- element = ui.slider(**value_kws).props("label label-always switch-label-side")
621
-
622
- super().__init__(value, element) # type: ignore
623
-
624
- for key, value in kws.items():
625
- if is_ref(value) and key != "value":
626
- self.bind_prop(key, value) # type: ignore
627
-
628
- self._ex_setup()
629
-
630
- def _ex_setup(self):
631
- ele = self.element
632
-
633
- @effect
634
- def _():
635
- ele.value = self.value
636
-
637
- def onModelValueChanged(e):
638
- self._ref.value = e.args # type: ignore
639
-
640
- ele.on("update:modelValue", handler=onModelValueChanged)
641
-
642
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
643
- if prop == "value":
644
- return self.bind_value(ref_ui)
645
-
646
- return super().bind_prop(prop, ref_ui)
647
-
648
- def bind_value(self, ref_ui: ReadonlyRef[float]):
649
- @effect
650
- def _():
651
- self.element.on_value_change(ref_ui.value)
652
-
653
- return self
654
-
655
-
656
- class LazySliderBindableUi(SliderBindableUi):
657
- def __init__(
658
- self,
659
- min: TMaybeRef[_TSliderValue],
660
- max: TMaybeRef[_TSliderValue],
661
- step: TMaybeRef[_TSliderValue] = 1,
662
- value: TMaybeRef[_TSliderValue | None] = None,
663
- on_change: Callable[..., Any] | None = None,
664
- ) -> None:
665
- super().__init__(min, max, step, value, on_change)
666
-
667
- def _ex_setup(self):
668
- ele = self.element
669
-
670
- @effect
671
- def _():
672
- ele.value = self.value
673
-
674
- def onValueChanged():
675
- self._ref.value = ele.value
676
-
677
- ele.on("change", onValueChanged)
678
-
679
-
680
- class TextareaBindableUi(SingleValueBindableUi[str, ui.textarea]):
681
- def __init__(
682
- self,
683
- label: Optional[TMaybeRef[str]] = None,
684
- *,
685
- placeholder: Optional[TMaybeRef[str]] = None,
686
- value: TMaybeRef[str] = "",
687
- on_change: Optional[Callable[..., Any]] = None,
688
- validation: Dict[str, Callable[..., bool]] = {},
689
- ) -> None:
690
- kws = {
691
- "label": label,
692
- "placeholder": placeholder,
693
- "value": value,
694
- "validation": validation,
695
- "on_change": on_change,
696
- }
697
-
698
- value_kws = _convert_kws_ref2value(kws)
699
-
700
- element = ui.textarea(**value_kws)
701
-
702
- super().__init__(value, element)
703
-
704
- for key, value in kws.items():
705
- if is_ref(value) and key != "value":
706
- self.bind_prop(key, value) # type: ignore
707
-
708
- self._ex_setup()
709
-
710
- def _ex_setup(self):
711
- ele = self.element
712
-
713
- @effect
714
- def _():
715
- ele.value = self.value
716
-
717
- def onModelValueChanged(e):
718
- self._ref.value = e.args # type: ignore
719
-
720
- ele.on("update:modelValue", handler=onModelValueChanged)
721
-
722
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
723
- if prop == "value":
724
- return self.bind_value(ref_ui)
725
-
726
- return super().bind_prop(prop, ref_ui)
727
-
728
- def bind_value(self, ref_ui: ReadonlyRef[bool]):
729
- @effect
730
- def _():
731
- self.element.on_value_change(ref_ui.value)
732
-
733
- return self
734
-
735
-
736
- class LazyTextareaBindableUi(TextareaBindableUi):
737
- def __init__(
738
- self,
739
- label: Optional[TMaybeRef[str]] = None,
740
- *,
741
- placeholder: Optional[TMaybeRef[str]] = None,
742
- value: TMaybeRef[str] = "",
743
- on_change: Optional[Callable[..., Any]] = None,
744
- validation: Dict[str, Callable[..., bool]] = {},
745
- ) -> None:
746
- super().__init__(
747
- label,
748
- placeholder=placeholder,
749
- value=value,
750
- on_change=on_change,
751
- validation=validation,
752
- )
753
-
754
- def _ex_setup(self):
755
- ele = self.element
756
-
757
- @effect
758
- def _():
759
- ele.value = self.value
760
-
761
- def onValueChanged():
762
- self._ref.value = ele.value
763
-
764
- ele.on("blur", onValueChanged)
765
- ele.on("keyup.enter", onValueChanged)
766
-
767
-
768
- class LabelBindableUi(SingleValueBindableUi[str, ui.label]):
769
- @staticmethod
770
- def _setup_(binder: "LabelBindableUi"):
771
- def onValueChanged(e):
772
- binder._ref.value = e.args["label"] # type: ignore
773
-
774
- @effect
775
- def _():
776
- binder.element.text = binder.value
777
-
778
- binder.element.on("update:modelValue", handler=onValueChanged)
779
-
780
- def __init__(
781
- self,
782
- text: TMaybeRef[str] = "",
783
- ) -> None:
784
- kws = {
785
- "text": text,
786
- }
787
-
788
- value_kws = _convert_kws_ref2value(kws)
789
-
790
- element = ui.label(**value_kws)
791
-
792
- super().__init__(text, element)
793
-
794
- for key, value in kws.items():
795
- if is_ref(value):
796
- self.bind_prop(key, value) # type: ignore
797
-
798
- LabelBindableUi._setup_(self)
799
-
800
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
801
- if prop == "text":
802
- return self.bind_text(ref_ui)
803
-
804
- if prop == "color":
805
- return self.bind_color(ref_ui)
806
-
807
- return super().bind_prop(prop, ref_ui)
808
-
809
- def bind_color(self, ref_ui: ReadonlyRef):
810
- @effect
811
- def _():
812
- ele = self.element
813
- color = ref_ui.value
814
- ele._style["color"] = color
815
- ele.update()
816
-
817
- def bind_text(self, ref_ui: ReadonlyRef):
818
- @effect
819
- def _():
820
- self.element.on_text_change(str(ref_ui.value))
821
- # self.element.update()
822
-
823
- return self
824
-
825
-
826
- class IconBindableUi(SingleValueBindableUi[str, ui.icon]):
827
- def __init__(
828
- self,
829
- name: TMaybeRef[str],
830
- *,
831
- size: Optional[TMaybeRef[str]] = None,
832
- color: Optional[TMaybeRef[str]] = None,
833
- ) -> None:
834
- kws = {
835
- "name": name,
836
- "size": size,
837
- "color": color,
838
- }
839
-
840
- value_kws = _convert_kws_ref2value(kws)
841
-
842
- element = ui.icon(**value_kws)
843
-
844
- super().__init__(name, element)
845
-
846
- for key, value in kws.items():
847
- if is_ref(value):
848
- self.bind_prop(key, value) # type: ignore
849
-
850
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
851
- if prop == "name":
852
- return self.bind_name(ref_ui)
853
-
854
- if prop == "color":
855
- return self.bind_color(ref_ui)
856
-
857
- return super().bind_prop(prop, ref_ui)
858
-
859
- def bind_color(self, ref_ui: ReadonlyRef):
860
- return _bind_color(self, ref_ui)
861
-
862
- def bind_name(self, ref_ui: ReadonlyRef):
863
- @effect
864
- def _():
865
- ele = cast(TextColorElement, self.element)
866
- ele._props["name"] = ref_ui.value
867
- ele.update()
868
-
869
- return self
870
-
871
-
872
- class ButtonBindableUi(SingleValueBindableUi[str, ui.button]):
873
- def __init__(
874
- self,
875
- text: TMaybeRef[str] = "",
876
- *,
877
- on_click: Optional[Callable[..., Any]] = None,
878
- color: Optional[TMaybeRef[str]] = "primary",
879
- icon: Optional[TMaybeRef[str]] = None,
880
- ) -> None:
881
- kws = {
882
- "text": text,
883
- "color": color,
884
- "icon": icon,
885
- "on_click": on_click,
886
- }
887
-
888
- value_kws = _convert_kws_ref2value(kws)
889
-
890
- element = ui.button(**value_kws)
891
-
892
- super().__init__(text, element)
893
-
894
- for key, value in kws.items():
895
- if is_ref(value):
896
- self.bind_prop(key, value) # type: ignore
897
-
898
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
899
- if prop == "text":
900
- return self.bind_text(ref_ui)
901
- if prop == "icon":
902
- return self.bind_icon(ref_ui)
903
- if prop == "color":
904
- return self.bind_color(ref_ui)
905
-
906
- return super().bind_prop(prop, ref_ui)
907
-
908
- def bind_color(self, ref_ui: ReadonlyRef):
909
- return _bind_color(self, ref_ui)
910
-
911
- def bind_text(self, ref_ui: ReadonlyRef):
912
- @effect
913
- def _():
914
- ele = self.element
915
- ele._props["text"] = ref_ui.value
916
- ele.update()
917
-
918
- return self
919
-
920
- def bind_icon(self, ref_ui: ReadonlyRef):
921
- @effect
922
- def _():
923
- ele = self.element
924
- ele._props["icon"] = ref_ui.value
925
- ele.update()
926
-
927
- return self
928
-
929
- def bind_enabled(self, ref_ui: ReadonlyRef[bool]):
930
- @effect
931
- def _():
932
- self.element.on_enabled_change(ref_ui.value)
933
-
934
- return self
935
-
936
- def bind_disable(self, ref_ui: ReadonlyRef[bool]):
937
- @effect
938
- def _():
939
- self.element.on_enabled_change(not ref_ui.value)
940
-
941
- return self
942
-
943
-
944
- class ColorPickerBindableUi(SingleValueBindableUi[str, ui.color_picker]):
945
- def __init__(
946
- self,
947
- color: TMaybeRef[str] = "",
948
- *,
949
- on_pick: Optional[Callable[..., Any]] = None,
950
- value: TMaybeRef[bool] = False,
951
- ) -> None:
952
- kws = {
953
- "value": value,
954
- "on_pick": on_pick,
955
- }
956
-
957
- value_kws = _convert_kws_ref2value(kws)
958
-
959
- with ui.card().tight():
960
- element_menu = ui.color_picker(**value_kws)
961
- self._element_picker = element_menu.default_slot.children[0]
962
- self._element_picker.props(f'format-model="rgba"')
963
-
964
- ui.button(on_click=element_menu.open, icon="colorize")
965
-
966
- super().__init__(color, element_menu)
967
-
968
- for key, value in kws.items():
969
- if is_ref(value) and key != "color":
970
- self.bind_prop(key, value) # type: ignore
971
-
972
- self._ex_setup()
973
-
974
- def _ex_setup(self):
975
- ele = self._element_picker
976
-
977
- @effect
978
- def _():
979
- ele._props["modelValue"] = self.value
980
-
981
- def onModelValueChanged(e):
982
- self._ref.value = e.args # type: ignore
983
-
984
- ele.on("update:modelValue", handler=onModelValueChanged)
985
-
986
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
987
- if prop == "value":
988
- return self.bind_value(ref_ui)
989
-
990
- return super().bind_prop(prop, ref_ui)
991
-
992
- def bind_color(self, ref_ui: ReadonlyRef[str]):
993
- @effect
994
- def _():
995
- self._element_picker._props["modelValue"] = ref_ui.value
996
-
997
- return self
998
-
999
- def bind_value(self, ref_ui: ReadonlyRef[bool]):
1000
- @effect
1001
- def _():
1002
- self._element_picker._props["value"] = ref_ui.value
1003
-
1004
- return self
1005
-
1006
-
1007
- class ColorPickerLazyBindableUi(ColorPickerBindableUi):
1008
- def __init__(
1009
- self,
1010
- color: TMaybeRef[str] = "",
1011
- *,
1012
- on_pick: Callable[..., Any] | None = None,
1013
- value: TMaybeRef[bool] = False,
1014
- ) -> None:
1015
- super().__init__(color, on_pick=on_pick, value=value)
1016
-
1017
- def _ex_setup(self):
1018
- ele = self._element_picker
1019
-
1020
- # @effect
1021
- # def _():
1022
- # ele._props["modelValue"] = self.value
1023
-
1024
- def onModelValueChanged(e):
1025
- self._ref.value = e.args # type: ignore
1026
-
1027
- ele.on("change", handler=onModelValueChanged)
1028
-
1029
-
1030
- _TAggridValue = Dict
1031
-
1032
-
1033
- class AggridBindableUi(BindableUi[ui.aggrid]):
1034
- def __init__(
1035
- self,
1036
- options: TMaybeRef[Dict],
1037
- *,
1038
- html_columns: TMaybeRef[List[int]] = [],
1039
- theme: TMaybeRef[str] = "balham",
1040
- ) -> None:
1041
- kws = {
1042
- "options": options,
1043
- "html_columns": html_columns,
1044
- "theme": theme,
1045
- }
1046
-
1047
- value_kws = _convert_kws_ref2value(kws)
1048
-
1049
- element = ui.aggrid(**value_kws)
1050
-
1051
- super().__init__(element)
1052
-
1053
- for key, value in kws.items():
1054
- if is_ref(value):
1055
- self.bind_prop(key, value) # type: ignore
1056
-
1057
- @staticmethod
1058
- def from_pandas(df: TMaybeRef):
1059
- if is_ref(df):
1060
-
1061
- @ref_computed
1062
- def cp_convert_df():
1063
- return utils_common.convert_dataframe(df.value)
1064
-
1065
- @ref_computed
1066
- def cp_options():
1067
- columnDefs = [
1068
- {"headerName": col, "field": col}
1069
- for col in cp_convert_df.value.columns
1070
- ]
1071
- rowData = cp_convert_df.value.to_dict("records")
1072
- data = {"columnDefs": columnDefs, "rowData": rowData}
1073
- return data
1074
-
1075
- return AggridBindableUi(cp_options)
1076
-
1077
- columnDefs = [{"headerName": col, "field": col} for col in df.columns] # type: ignore
1078
- rowData = df.to_dict("records") # type: ignore
1079
- options = {"columnDefs": columnDefs, "rowData": rowData}
1080
- return AggridBindableUi(options)
1081
-
1082
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
1083
- if prop == "options":
1084
- return self.bind_options(ref_ui)
1085
-
1086
- return super().bind_prop(prop, ref_ui)
1087
-
1088
- def bind_options(self, ref_ui: ReadonlyRef[List[Dict]]):
1089
- @effect
1090
- def _():
1091
- ele = self.element
1092
- data = ref_ui.value
1093
- ele._props["options"].update(data)
1094
- ele.update()
1095
-
1096
- return self
1097
-
1098
-
1099
- class TableBindableUi(BindableUi[ui.table]):
1100
- def __init__(
1101
- self,
1102
- columns: TMaybeRef[List[Dict]],
1103
- rows: TMaybeRef[List[Dict]],
1104
- row_key: TMaybeRef[str] = "id",
1105
- title: Optional[TMaybeRef[str]] = None,
1106
- selection: Optional[TMaybeRef[Literal["single", "multiple"]]] = None,
1107
- pagination: Optional[TMaybeRef[int]] = 15,
1108
- on_select: Optional[Callable[..., Any]] = None,
1109
- ) -> None:
1110
- kws = {
1111
- "columns": columns,
1112
- "rows": rows,
1113
- "row_key": row_key,
1114
- "title": title,
1115
- "selection": selection,
1116
- "pagination": pagination,
1117
- "on_select": on_select,
1118
- }
1119
-
1120
- value_kws = _convert_kws_ref2value(kws)
1121
-
1122
- element = ui.table(**value_kws)
1123
-
1124
- super().__init__(element)
1125
-
1126
- for key, value in kws.items():
1127
- if is_ref(value):
1128
- self.bind_prop(key, value) # type: ignore
1129
-
1130
- @staticmethod
1131
- def from_pandas(df: TMaybeRef):
1132
- if is_ref(df):
1133
-
1134
- @ref_computed
1135
- def cp_convert_df():
1136
- return utils_common.convert_dataframe(df.value)
1137
-
1138
- @ref_computed
1139
- def cp_rows():
1140
- return cp_convert_df.value.to_dict("records")
1141
-
1142
- @ref_computed
1143
- def cp_cols():
1144
- return [
1145
- {
1146
- "name": col,
1147
- "label": col,
1148
- "field": col,
1149
- }
1150
- for col in cp_convert_df.value.columns
1151
- ]
1152
-
1153
- return TableBindableUi(cp_cols, cp_rows)
1154
-
1155
- df = utils_common.convert_dataframe(df)
1156
- rows = df.to_dict("records")
1157
-
1158
- cols = [
1159
- {
1160
- "name": col,
1161
- "label": col,
1162
- "field": col,
1163
- }
1164
- for col in df.columns
1165
- ]
1166
- return TableBindableUi(cols, rows)
1167
-
1168
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
1169
- if prop == "dataframe":
1170
- return self.bind_dataframe(ref_ui)
1171
-
1172
- if prop == "rows":
1173
- return self.bind_rows(ref_ui)
1174
-
1175
- if prop == "columns":
1176
- return self.bind_columns(ref_ui)
1177
-
1178
- return super().bind_prop(prop, ref_ui)
1179
-
1180
- def bind_dataframe(self, ref_df: ReadonlyRef):
1181
- @ref_computed
1182
- def cp_converted_df():
1183
- df = ref_df.value
1184
- return utils_common.convert_dataframe(df)
1185
-
1186
- @ref_computed
1187
- def cp_rows():
1188
- return cp_converted_df.value.to_dict("records")
1189
-
1190
- @ref_computed
1191
- def cp_cols():
1192
- return [
1193
- {
1194
- "name": col,
1195
- "label": col,
1196
- "field": col,
1197
- }
1198
- for col in cp_converted_df.value.columns
1199
- ]
1200
-
1201
- self.bind_rows(cp_rows).bind_columns(cp_cols)
1202
-
1203
- return self
1204
-
1205
- def bind_rows(self, ref_ui: ReadonlyRef[List[Dict]]):
1206
- @effect
1207
- def _():
1208
- ele = self.element
1209
- ele._props["rows"] = ref_ui.value
1210
- ele.update()
1211
-
1212
- return self
1213
-
1214
- def bind_columns(self, ref_ui: ReadonlyRef[List[Dict]]):
1215
- @effect
1216
- def _():
1217
- ele = self.element
1218
- ele._props["columns"] = ref_ui.value
1219
- ele.update()
1220
-
1221
- return self
1222
-
1223
-
1224
- _TDrawerSide = Literal["left", "right"]
1225
-
1226
-
1227
- class DrawerBindableUi(SingleValueBindableUi[bool, Drawer]):
1228
- def __init__(
1229
- self,
1230
- side: TMaybeRef[_TDrawerSide] = "left",
1231
- overlay: TMaybeRef[bool] = False,
1232
- *,
1233
- value: TMaybeRef[bool] = True,
1234
- fixed: TMaybeRef[bool] = False,
1235
- bordered: TMaybeRef[bool] = True,
1236
- elevated: TMaybeRef[bool] = False,
1237
- top_corner: TMaybeRef[bool] = False,
1238
- bottom_corner: TMaybeRef[bool] = False,
1239
- ) -> None:
1240
- kws = {
1241
- "side": side,
1242
- "overlay": overlay,
1243
- "value": value,
1244
- "fixed": fixed,
1245
- "bordered": bordered,
1246
- "elevated": elevated,
1247
- "top_corner": top_corner,
1248
- "bottom_corner": bottom_corner,
1249
- }
1250
-
1251
- value_kws = _convert_kws_ref2value(kws)
1252
- del value_kws["side"]
1253
- del value_kws["overlay"]
1254
-
1255
- element = None
1256
-
1257
- if to_value(side) == "left":
1258
- element = ui.left_drawer(**value_kws)
1259
- else:
1260
- element = ui.right_drawer(**value_kws)
1261
-
1262
- element.style(f"background-color:rgba(25, 118, 210,0.3)")
1263
- element.classes("flex flex-col gap-4")
1264
-
1265
- init_value = (
1266
- element._props["model-value"]
1267
- if "model-value" in element._props
1268
- else element._props["show-if-above"]
1269
- )
1270
-
1271
- super().__init__(value, element)
1272
-
1273
- @effect
1274
- def _():
1275
- value = "true" if self.value else "false"
1276
- element.props(f":model-value={value}")
1277
-
1278
- def on_update(e):
1279
- self._ref.value = e.args
1280
-
1281
- element.on("update:modelValue", on_update)
1282
-
1283
- for key, value in kws.items():
1284
- if is_ref(value):
1285
- self.bind_prop(key, value) # type: ignore
1286
-
1287
- def toggle(self):
1288
- self.element.toggle()
1289
- return self
1290
-
1291
- def __enter__(self):
1292
- self.element.__enter__()
1293
- return self
1294
-
1295
- def __exit__(self, *_: Any):
1296
- self.element.__exit__(*_)
1297
-
1298
-
1299
- class EChartsBindableUi(BindableUi[echarts]):
1300
- def __init__(
1301
- self,
1302
- options: TMaybeRef[Dict],
1303
- ) -> None:
1304
- kws = {
1305
- "options": options,
1306
- }
1307
-
1308
- value_kws = _convert_kws_ref2value(kws)
1309
-
1310
- element = echarts(**value_kws)
1311
-
1312
- super().__init__(element)
1313
-
1314
- for key, value in kws.items():
1315
- if is_ref(value):
1316
- self.bind_prop(key, value) # type: ignore
1317
-
1318
- @staticmethod
1319
- def _pyecharts2opts(chart):
1320
- import simplejson as json
1321
- from pyecharts.charts.chart import Base
1322
-
1323
- if isinstance(chart, Base):
1324
- return json.loads(chart.dump_options())
1325
-
1326
- return {}
1327
-
1328
- @staticmethod
1329
- def from_pyecharts(chart: TMaybeRef):
1330
- if is_ref(chart):
1331
-
1332
- @ref_computed
1333
- def chart_opt():
1334
- return EChartsBindableUi._pyecharts2opts(chart.value)
1335
-
1336
- return EChartsBindableUi(chart_opt)
1337
-
1338
- return EChartsBindableUi(EChartsBindableUi._pyecharts2opts(chart))
1339
-
1340
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
1341
- if prop == "options":
1342
- return self.bind_options(ref_ui)
1343
-
1344
- return super().bind_prop(prop, ref_ui)
1345
-
1346
- def bind_options(self, ref_ui: ReadonlyRef[Dict]):
1347
- @effect
1348
- def _():
1349
- ele = self.element
1350
- ele.update_options(ref_ui.value)
1351
- ele.update()
1352
-
1353
- return self
1354
-
1355
-
1356
- class RowBindableUi(BindableUi[ui.row]):
1357
- def __init__(
1358
- self,
1359
- ) -> None:
1360
- element = ui.row()
1361
-
1362
- super().__init__(element)
1363
-
1364
- def __enter__(self):
1365
- self.element.__enter__()
1366
- return self
1367
-
1368
- def __exit__(self, *_: Any):
1369
- self.element.__exit__(*_)
1370
-
1371
-
1372
- class CardBindableUi(BindableUi[ui.card]):
1373
- def __init__(
1374
- self,
1375
- ) -> None:
1376
- element = ui.card()
1377
-
1378
- super().__init__(element)
1379
-
1380
- def __enter__(self):
1381
- self.element.__enter__()
1382
- return self
1383
-
1384
- def __exit__(self, *_: Any):
1385
- self.element.__exit__(*_)
1386
-
1387
- def tight(self):
1388
- """Removes padding and gaps between nested elements."""
1389
- self.element._classes.clear()
1390
- self.element._style.clear()
1391
- return self
1392
-
1393
-
1394
- class CardSectionBindableUi(BindableUi[ui.card_section]):
1395
- def __init__(
1396
- self,
1397
- ) -> None:
1398
- element = ui.card_section()
1399
-
1400
- super().__init__(element)
1401
-
1402
- def __enter__(self):
1403
- self.element.__enter__()
1404
- return self
1405
-
1406
- def __exit__(self, *_: Any):
1407
- self.element.__exit__(*_)
1408
-
1409
-
1410
- class CardActionsBindableUi(BindableUi[ui.card_actions]):
1411
- def __init__(
1412
- self,
1413
- ) -> None:
1414
- element = ui.card_actions()
1415
-
1416
- super().__init__(element)
1417
-
1418
- def __enter__(self):
1419
- self.element.__enter__()
1420
- return self
1421
-
1422
- def __exit__(self, *_: Any):
1423
- self.element.__exit__(*_)
1424
-
1425
-
1426
- class HtmlBindableUi(SingleValueBindableUi[str, ui.html]):
1427
- @staticmethod
1428
- def _setup_(binder: "HtmlBindableUi"):
1429
- first = True
1430
-
1431
- @effect
1432
- def _():
1433
- nonlocal first
1434
-
1435
- async def task():
1436
- pass
1437
- await ui.run_javascript(
1438
- f"getElement({binder.element.id}).innerText= '{binder.value}' ",
1439
- respond=False,
1440
- )
1441
-
1442
- if not first:
1443
- asyncio.run(task())
1444
- else:
1445
- first = False
1446
-
1447
- def __init__(
1448
- self,
1449
- content: TMaybeRef[str] = "",
1450
- ) -> None:
1451
- kws = {
1452
- "content": content,
1453
- }
1454
-
1455
- value_kws = _convert_kws_ref2value(kws)
1456
-
1457
- element = ui.html(**value_kws)
1458
-
1459
- super().__init__(content, element)
1460
-
1461
- for key, value in kws.items():
1462
- if is_ref(value):
1463
- self.bind_prop(key, value) # type: ignore
1464
-
1465
- HtmlBindableUi._setup_(self)
1466
-
1467
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
1468
- if prop == "color":
1469
- return self.bind_color(ref_ui)
1470
-
1471
- return super().bind_prop(prop, ref_ui)
1472
-
1473
- def bind_color(self, ref_ui: ReadonlyRef):
1474
- @effect
1475
- def _():
1476
- ele = self.element
1477
- color = ref_ui.value
1478
- ele._style["color"] = color
1479
- ele.update()
1480
-
1481
-
1482
- class ImageBindableUi(SingleValueBindableUi[Union[str, Path], ui.image]):
1483
- @staticmethod
1484
- def _setup_(binder: "ImageBindableUi"):
1485
- @effect
1486
- def _():
1487
- binder.element.on_source_change(binder.value)
1488
-
1489
- def __init__(
1490
- self,
1491
- source: Union[TMaybeRef[str], TMaybeRef[Path]] = "",
1492
- ) -> None:
1493
- kws = {
1494
- "source": source,
1495
- }
1496
-
1497
- value_kws = _convert_kws_ref2value(kws)
1498
-
1499
- element = ui.image(**value_kws)
1500
-
1501
- super().__init__(source, element) # type: ignore
1502
-
1503
- for key, value in kws.items():
1504
- if is_ref(value):
1505
- self.bind_prop(key, value) # type: ignore
1506
-
1507
- # ImageBindableUi._setup_(self)
1508
-
1509
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
1510
- if prop == "source":
1511
- return self.bind_source(ref_ui)
1512
-
1513
- return super().bind_prop(prop, ref_ui)
1514
-
1515
- def bind_source(self, ref_ui: ReadonlyRef[Union[str, Path]]):
1516
- @effect
1517
- def _():
1518
- ele = self.element
1519
- source = ref_ui.value
1520
- ele.on_source_change(source)
1521
-
1522
-
1523
- class UploadResult:
1524
- def __init__(self, content: bytes = bytes(), name="", type=""):
1525
- self.content = content
1526
- self.name = name
1527
- self.type = type
1528
-
1529
- def get_bytes(self):
1530
- return self.content
1531
-
1532
- @property
1533
- def ready(self):
1534
- return len(self.content) > 0
1535
-
1536
-
1537
- class UploadBindableUi(SingleValueBindableUi[UploadResult, ui.upload]):
1538
- @staticmethod
1539
- def _setup_(binder: "UploadBindableUi"):
1540
- def on_upload(e: ng_events.UploadEventArguments):
1541
- binder._ref.value = UploadResult(e.content.read(), e.name, e.type)
1542
-
1543
- binder._on_upload_callbacks.append(on_upload)
1544
-
1545
- def __init__(
1546
- self,
1547
- multiple: TMaybeRef[bool] = False,
1548
- max_file_size: Optional[TMaybeRef[int]] = None,
1549
- max_total_size: Optional[TMaybeRef[int]] = None,
1550
- max_files: Optional[TMaybeRef[int]] = None,
1551
- on_upload: Optional[Callable[..., Any]] = None,
1552
- on_rejected: Optional[Callable[..., Any]] = None,
1553
- label: TMaybeRef[str] = "",
1554
- auto_upload: TMaybeRef[bool] = False,
1555
- ) -> None:
1556
- kws = {
1557
- "multiple": multiple,
1558
- "max_file_size": max_file_size,
1559
- "max_total_size": max_total_size,
1560
- "max_files": max_files,
1561
- "on_rejected": on_rejected,
1562
- "label": label,
1563
- "auto_upload": auto_upload,
1564
- }
1565
-
1566
- value_kws = _convert_kws_ref2value(kws)
1567
-
1568
- self._on_upload_callbacks = []
1569
-
1570
- def _on_upload(e: ng_events.UploadEventArguments):
1571
- for fn in self._on_upload_callbacks:
1572
- fn(e)
1573
-
1574
- if on_upload:
1575
- self._on_upload_callbacks.append(on_upload)
1576
-
1577
- element = ui.upload(**value_kws, on_upload=_on_upload)
1578
-
1579
- super().__init__(UploadResult(), element) # type: ignore
1580
-
1581
- for key, value in kws.items():
1582
- if is_ref(value):
1583
- self.bind_prop(key, value) # type: ignore
1584
-
1585
- UploadBindableUi._setup_(self)