ex4nicegui 0.6.7__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.
Files changed (75) hide show
  1. ex4nicegui/__init__.py +12 -6
  2. ex4nicegui/gsap/__init__.py +11 -0
  3. ex4nicegui/helper/__init__.py +4 -0
  4. ex4nicegui/helper/client_instance_locker.py +31 -0
  5. ex4nicegui/reactive/__init__.py +4 -0
  6. ex4nicegui/reactive/base.py +426 -0
  7. ex4nicegui/reactive/deferredTask.py +3 -2
  8. ex4nicegui/reactive/local_file_picker.py +1 -2
  9. ex4nicegui/reactive/mixins/backgroundColor.py +41 -0
  10. ex4nicegui/reactive/mixins/disableable.py +44 -0
  11. ex4nicegui/reactive/mixins/textColor.py +66 -0
  12. ex4nicegui/reactive/officials/aggrid.py +4 -4
  13. ex4nicegui/reactive/officials/base.py +4 -351
  14. ex4nicegui/reactive/officials/button.py +36 -3
  15. ex4nicegui/reactive/officials/checkbox.py +2 -3
  16. ex4nicegui/reactive/officials/chip.py +102 -0
  17. ex4nicegui/reactive/officials/circular_progress.py +6 -5
  18. ex4nicegui/reactive/officials/color_picker.py +3 -4
  19. ex4nicegui/reactive/officials/column.py +1 -1
  20. ex4nicegui/reactive/officials/date.py +2 -3
  21. ex4nicegui/reactive/officials/drawer.py +2 -3
  22. ex4nicegui/reactive/officials/echarts.py +2 -3
  23. ex4nicegui/reactive/officials/expansion.py +2 -3
  24. ex4nicegui/reactive/officials/grid.py +4 -3
  25. ex4nicegui/reactive/officials/html.py +1 -3
  26. ex4nicegui/reactive/officials/icon.py +5 -9
  27. ex4nicegui/reactive/officials/image.py +2 -4
  28. ex4nicegui/reactive/officials/input.py +4 -6
  29. ex4nicegui/reactive/officials/knob.py +6 -4
  30. ex4nicegui/reactive/officials/label.py +3 -10
  31. ex4nicegui/reactive/officials/linear_progress.py +5 -9
  32. ex4nicegui/reactive/officials/number.py +3 -6
  33. ex4nicegui/reactive/officials/radio.py +3 -5
  34. ex4nicegui/reactive/officials/row.py +1 -1
  35. ex4nicegui/reactive/officials/select.py +3 -5
  36. ex4nicegui/reactive/officials/slider.py +4 -6
  37. ex4nicegui/reactive/officials/switch.py +2 -4
  38. ex4nicegui/reactive/officials/tab.py +1 -1
  39. ex4nicegui/reactive/officials/tab_panel.py +1 -1
  40. ex4nicegui/reactive/officials/tab_panels.py +109 -3
  41. ex4nicegui/reactive/officials/table.py +7 -6
  42. ex4nicegui/reactive/officials/tabs.py +1 -1
  43. ex4nicegui/reactive/officials/textarea.py +3 -5
  44. ex4nicegui/reactive/officials/upload.py +2 -2
  45. ex4nicegui/reactive/q_pagination.py +2 -2
  46. ex4nicegui/reactive/scopedStyle.js +55 -0
  47. ex4nicegui/reactive/scopedStyle.py +25 -0
  48. ex4nicegui/reactive/services/pandas_service.py +31 -0
  49. ex4nicegui/reactive/{utils.py → services/reactive_service.py} +9 -67
  50. ex4nicegui/reactive/systems/color_system.py +157 -0
  51. ex4nicegui/reactive/systems/object_system.py +33 -0
  52. ex4nicegui/reactive/systems/reactive_system.py +21 -0
  53. ex4nicegui/reactive/useMouse/UseMouse.py +4 -4
  54. ex4nicegui/reactive/usePagination.py +1 -1
  55. ex4nicegui/reactive/vfor.py +1 -2
  56. ex4nicegui/reactive/vmodel.py +1 -1
  57. ex4nicegui/utils/apiEffect.py +5 -1
  58. ex4nicegui/utils/effect.py +3 -2
  59. ex4nicegui/utils/refComputed.py +147 -0
  60. ex4nicegui/utils/refWrapper.py +57 -0
  61. ex4nicegui/utils/scheduler.py +20 -4
  62. ex4nicegui/utils/signals.py +51 -192
  63. ex4nicegui/utils/types.py +16 -0
  64. ex4nicegui/version.py +3 -0
  65. {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/METADATA +61 -4
  66. {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/RECORD +68 -58
  67. ex4nicegui/reactive/EChartsComponent/__init__.py +0 -0
  68. ex4nicegui/reactive/UseDraggable/__init__.py +0 -0
  69. ex4nicegui/reactive/dropZone/__init__.py +0 -0
  70. ex4nicegui/reactive/mermaid/__init__.py +0 -0
  71. ex4nicegui/reactive/officials/__init__.py +0 -1
  72. ex4nicegui/reactive/officials/utils.py +0 -11
  73. ex4nicegui/reactive/useMouse/__init__.py +0 -0
  74. {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/LICENSE +0 -0
  75. {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/WHEEL +0 -0
@@ -1,7 +1,7 @@
1
1
  from typing import (
2
2
  Any,
3
3
  )
4
- from ex4nicegui.reactive.utils import ParameterClassifier
4
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
5
5
  from ex4nicegui.utils.signals import (
6
6
  TGetterOrReadonlyRef,
7
7
  _TMaybeRef as TMaybeRef,
@@ -1,7 +1,6 @@
1
1
  from typing import Any, Callable, List, Optional, TypeVar
2
2
  from typing_extensions import TypedDict
3
- from ex4nicegui.reactive.utils import ParameterClassifier
4
- from ex4nicegui.utils.apiEffect import ui_effect
3
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
5
4
 
6
5
  from ex4nicegui.utils.signals import (
7
6
  TGetterOrReadonlyRef,
@@ -70,7 +69,7 @@ class DateBindableUi(BindableUi[ui.date]):
70
69
  return super().bind_prop(prop, ref_ui)
71
70
 
72
71
  def bind_value(self, ref_ui: TGetterOrReadonlyRef[bool]):
73
- @ui_effect
72
+ @self._ui_effect
74
73
  def _():
75
74
  self.element.set_value(to_value(ref_ui))
76
75
 
@@ -2,8 +2,7 @@ from typing import (
2
2
  Any,
3
3
  )
4
4
  from typing_extensions import Literal
5
- from ex4nicegui.reactive.utils import ParameterClassifier
6
- from ex4nicegui.utils.apiEffect import ui_effect
5
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
7
6
 
8
7
  from ex4nicegui.utils.signals import (
9
8
  is_setter_ref,
@@ -61,7 +60,7 @@ class DrawerBindableUi(BindableUi[Drawer]):
61
60
 
62
61
  super().__init__(element) # type: ignore
63
62
 
64
- @ui_effect
63
+ @self._ui_effect
65
64
  def _():
66
65
  mvalue = "true" if to_value(value) else "false"
67
66
  element.props(f":model-value={mvalue}")
@@ -1,6 +1,6 @@
1
1
  from pathlib import Path
2
2
  from typing import Any, Callable, Dict, List, Union, cast, Optional, Literal
3
- from ex4nicegui.reactive.utils import ParameterClassifier
3
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
4
4
  from ex4nicegui.utils.signals import (
5
5
  TGetterOrReadonlyRef,
6
6
  is_ref,
@@ -8,7 +8,6 @@ from ex4nicegui.utils.signals import (
8
8
  _TMaybeRef as TMaybeRef,
9
9
  to_value,
10
10
  to_raw,
11
- on,
12
11
  )
13
12
  from .base import BindableUi
14
13
  from ex4nicegui.reactive.EChartsComponent.ECharts import echarts
@@ -141,7 +140,7 @@ class EChartsBindableUi(BindableUi[echarts]):
141
140
  return super().bind_prop(prop, ref_ui)
142
141
 
143
142
  def bind_options(self, ref_ui: TGetterOrReadonlyRef[Dict]):
144
- @on(ref_ui)
143
+ @self._ui_signal_on(ref_ui)
145
144
  def _():
146
145
  ele = self.element
147
146
  ele.update_options(to_raw(to_value(ref_ui)), self.__update_setting)
@@ -1,7 +1,6 @@
1
1
  from typing import Any, Optional, Callable
2
2
  from nicegui import ui
3
- from ex4nicegui.reactive.utils import ParameterClassifier
4
- from ex4nicegui.utils.apiEffect import ui_effect
3
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
5
4
  from ex4nicegui.utils.signals import (
6
5
  TGetterOrReadonlyRef,
7
6
  _TMaybeRef as TMaybeRef,
@@ -53,7 +52,7 @@ class ExpansionBindableUi(BindableUi[ui.expansion]):
53
52
  return super().bind_prop(prop, ref_ui)
54
53
 
55
54
  def bind_value(self, ref_ui: TGetterOrReadonlyRef):
56
- @ui_effect
55
+ @self._ui_effect
57
56
  def _():
58
57
  self.element.set_value(to_value(ref_ui))
59
58
 
@@ -1,9 +1,10 @@
1
1
  from typing import (
2
2
  Any,
3
3
  Optional,
4
+ Union,
4
5
  )
5
6
 
6
- from ex4nicegui.reactive.utils import ParameterClassifier
7
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
7
8
 
8
9
  from nicegui import ui
9
10
  from .base import BindableUi
@@ -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
 
@@ -1,5 +1,3 @@
1
- from ex4nicegui.utils.apiEffect import ui_effect
2
-
3
1
  from ex4nicegui.utils.signals import (
4
2
  _TMaybeRef as TMaybeRef,
5
3
  to_value,
@@ -20,7 +18,7 @@ class html(BindableUi[HtmlComponent]):
20
18
 
21
19
  super().__init__(element)
22
20
 
23
- @ui_effect
21
+ @self._ui_effect
24
22
  def _():
25
23
  element._props["content"] = to_value(content)
26
24
  element.update()
@@ -2,9 +2,7 @@ from typing import (
2
2
  Optional,
3
3
  cast,
4
4
  )
5
- from ex4nicegui.reactive.utils import ParameterClassifier
6
- from ex4nicegui.utils.apiEffect import ui_effect
7
-
5
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
8
6
  from ex4nicegui.utils.signals import (
9
7
  TGetterOrReadonlyRef,
10
8
  _TMaybeRef as TMaybeRef,
@@ -14,10 +12,11 @@ from nicegui import ui
14
12
  from nicegui.elements.mixins.color_elements import (
15
13
  TextColorElement,
16
14
  )
17
- from .base import BindableUi, _bind_color
15
+ from .base import BindableUi
16
+ from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
18
17
 
19
18
 
20
- class IconBindableUi(BindableUi[ui.icon]):
19
+ class IconBindableUi(BindableUi[ui.icon], TextColorableMixin):
21
20
  def __init__(
22
21
  self,
23
22
  name: TMaybeRef[str],
@@ -44,11 +43,8 @@ class IconBindableUi(BindableUi[ui.icon]):
44
43
 
45
44
  return super().bind_prop(prop, ref_ui)
46
45
 
47
- def bind_color(self, ref_ui: TGetterOrReadonlyRef):
48
- return _bind_color(self, ref_ui)
49
-
50
46
  def bind_name(self, ref_ui: TGetterOrReadonlyRef):
51
- @ui_effect
47
+ @self._ui_effect
52
48
  def _():
53
49
  ele = cast(TextColorElement, self.element)
54
50
  ele._props["name"] = to_value(ref_ui)
@@ -2,9 +2,7 @@ from pathlib import Path
2
2
  from typing import (
3
3
  Union,
4
4
  )
5
- from ex4nicegui.reactive.utils import ParameterClassifier
6
- from ex4nicegui.utils.apiEffect import ui_effect
7
-
5
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
8
6
  from ex4nicegui.utils.signals import (
9
7
  TGetterOrReadonlyRef,
10
8
  _TMaybeRef as TMaybeRef,
@@ -34,6 +32,6 @@ class ImageBindableUi(BindableUi[ui.image]):
34
32
  return super().bind_prop(prop, ref_ui)
35
33
 
36
34
  def bind_source(self, ref_ui: TGetterOrReadonlyRef[Union[str, Path]]):
37
- @ui_effect
35
+ @self._ui_effect
38
36
  def _():
39
37
  self.element.set_source(to_value(ref_ui))
@@ -1,12 +1,10 @@
1
1
  from typing import Any, Callable, List, Optional, Dict, cast
2
- from ex4nicegui.utils.apiEffect import ui_effect
3
2
 
4
3
 
5
4
  from ex4nicegui.utils.signals import (
6
5
  TGetterOrReadonlyRef,
7
6
  Ref,
8
7
  _TMaybeRef as TMaybeRef,
9
- effect,
10
8
  is_setter_ref,
11
9
  to_value,
12
10
  )
@@ -14,7 +12,7 @@ from ex4nicegui.utils.signals import (
14
12
  from nicegui import ui
15
13
  from nicegui.events import handle_event
16
14
  from .base import BindableUi, DisableableMixin
17
- from ex4nicegui.reactive.utils import ParameterClassifier
15
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
18
16
 
19
17
 
20
18
  class InputBindableUi(BindableUi[ui.input], DisableableMixin):
@@ -62,7 +60,7 @@ class InputBindableUi(BindableUi[ui.input], DisableableMixin):
62
60
  return super().bind_prop(prop, ref_ui)
63
61
 
64
62
  def bind_value(self, ref_ui: TGetterOrReadonlyRef[str]):
65
- @ui_effect
63
+ @self._ui_effect
66
64
  def _():
67
65
  self.element.set_value(to_value(ref_ui))
68
66
  self.element.update()
@@ -70,7 +68,7 @@ class InputBindableUi(BindableUi[ui.input], DisableableMixin):
70
68
  return self
71
69
 
72
70
  def bind_password(self, ref_ui: TGetterOrReadonlyRef[bool]):
73
- @ui_effect
71
+ @self._ui_effect
74
72
  def _():
75
73
  self.element._props["type"] = "password" if to_value(ref_ui) else "text"
76
74
  self.element.update()
@@ -116,7 +114,7 @@ class LazyInputBindableUi(InputBindableUi):
116
114
 
117
115
  ele = self.element
118
116
 
119
- @effect
117
+ @self._ui_effect
120
118
  def _():
121
119
  ele.value = ref.value
122
120
 
@@ -3,9 +3,7 @@ from typing import (
3
3
  Callable,
4
4
  Optional,
5
5
  )
6
- from ex4nicegui.reactive.utils import ParameterClassifier
7
- from ex4nicegui.utils.apiEffect import ui_effect
8
-
6
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
9
7
  from ex4nicegui.utils.signals import (
10
8
  _TMaybeRef as TMaybeRef,
11
9
  to_value,
@@ -13,11 +11,13 @@ from ex4nicegui.utils.signals import (
13
11
  )
14
12
  from nicegui import ui
15
13
  from .base import BindableUi, DisableableMixin
14
+ from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
16
15
 
17
16
 
18
17
  class KnobBindableUi(
19
18
  BindableUi[ui.knob],
20
19
  DisableableMixin,
20
+ TextColorableMixin,
21
21
  ):
22
22
  def __init__(
23
23
  self,
@@ -64,11 +64,13 @@ class KnobBindableUi(
64
64
  def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef):
65
65
  if prop == "value":
66
66
  return self.bind_value(ref_ui)
67
+ if prop == "color":
68
+ return self.bind_color(ref_ui)
67
69
 
68
70
  return super().bind_prop(prop, ref_ui)
69
71
 
70
72
  def bind_value(self, ref_ui: TGetterOrReadonlyRef[float]):
71
- @ui_effect
73
+ @self._ui_effect
72
74
  def _():
73
75
  self.element.set_value(to_value(ref_ui))
74
76
 
@@ -1,5 +1,5 @@
1
1
  from typing import Any
2
- from ex4nicegui.reactive.utils import ParameterClassifier
2
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
3
3
  from ex4nicegui.utils.signals import (
4
4
  TGetterOrReadonlyRef,
5
5
  to_value,
@@ -7,9 +7,10 @@ from ex4nicegui.utils.signals import (
7
7
  )
8
8
  from nicegui import ui
9
9
  from .base import BindableUi
10
+ from ex4nicegui.reactive.mixins.textColor import HtmlTextColorableMixin
10
11
 
11
12
 
12
- class LabelBindableUi(BindableUi[ui.label]):
13
+ class LabelBindableUi(BindableUi[ui.label], HtmlTextColorableMixin):
13
14
  def __init__(
14
15
  self,
15
16
  text: TMaybeRef[Any] = "",
@@ -35,14 +36,6 @@ class LabelBindableUi(BindableUi[ui.label]):
35
36
 
36
37
  return super().bind_prop(prop, ref_ui)
37
38
 
38
- def bind_color(self, ref_ui: TGetterOrReadonlyRef):
39
- @self._ui_effect
40
- def _():
41
- ele = self.element
42
- color = to_value(ref_ui)
43
- ele._style["color"] = color
44
- ele.update()
45
-
46
39
  def bind_text(self, ref_ui: TGetterOrReadonlyRef):
47
40
  @self._ui_effect
48
41
  def _():
@@ -1,9 +1,7 @@
1
1
  from typing import (
2
2
  Optional,
3
3
  )
4
- from ex4nicegui.reactive.utils import ParameterClassifier
5
- from ex4nicegui.utils.apiEffect import ui_effect
6
-
4
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
7
5
  from ex4nicegui.utils.signals import (
8
6
  TGetterOrReadonlyRef,
9
7
  _TMaybeRef as TMaybeRef,
@@ -11,10 +9,11 @@ from ex4nicegui.utils.signals import (
11
9
  )
12
10
  from nicegui import ui
13
11
 
14
- from .base import BindableUi, _bind_color
12
+ from .base import BindableUi
13
+ from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
15
14
 
16
15
 
17
- class LinearProgressBindableUi(BindableUi[ui.linear_progress]):
16
+ class LinearProgressBindableUi(BindableUi[ui.linear_progress], TextColorableMixin):
18
17
  def __init__(
19
18
  self,
20
19
  value: TMaybeRef[float] = 0.0,
@@ -56,11 +55,8 @@ class LinearProgressBindableUi(BindableUi[ui.linear_progress]):
56
55
 
57
56
  return super().bind_prop(prop, ref_ui)
58
57
 
59
- def bind_color(self, ref_ui: TGetterOrReadonlyRef):
60
- return _bind_color(self, ref_ui)
61
-
62
58
  def bind_value(self, ref_ui: TGetterOrReadonlyRef):
63
- @ui_effect
59
+ @self._ui_effect
64
60
  def _():
65
61
  self.element.set_value(to_value(ref_ui))
66
62
 
@@ -6,14 +6,11 @@ from typing import (
6
6
  Dict,
7
7
  Union,
8
8
  )
9
- from ex4nicegui.reactive.utils import ParameterClassifier
10
- from ex4nicegui.utils.apiEffect import ui_effect
11
-
9
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
12
10
  from ex4nicegui.utils.signals import (
13
11
  TGetterOrReadonlyRef,
14
12
  _TMaybeRef as TMaybeRef,
15
13
  to_value,
16
- on,
17
14
  )
18
15
  from nicegui import ui
19
16
  from .base import BindableUi
@@ -83,14 +80,14 @@ class NumberBindableUi(BindableUi[ui.number]):
83
80
  return super().bind_prop(prop, ref_ui)
84
81
 
85
82
  def bind_value(self, ref_ui: TGetterOrReadonlyRef[float]):
86
- @ui_effect
83
+ @self._ui_effect
87
84
  def _():
88
85
  self.element.set_value(to_value(ref_ui))
89
86
 
90
87
  return self
91
88
 
92
89
  def _bind_precision(self, ref_ui: TGetterOrReadonlyRef[int]):
93
- @on(ref_ui, onchanges=True)
90
+ @self._ui_signal_on(ref_ui, onchanges=True)
94
91
  def _():
95
92
  self.element.precision = to_value(ref_ui)
96
93
  self.element.sanitize()
@@ -8,9 +8,7 @@ from typing import (
8
8
  Dict,
9
9
  Union,
10
10
  )
11
- from ex4nicegui.reactive.utils import ParameterClassifier
12
- from ex4nicegui.utils.apiEffect import ui_effect
13
-
11
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
14
12
  from ex4nicegui.utils.signals import (
15
13
  TGetterOrReadonlyRef,
16
14
  _TMaybeRef as TMaybeRef,
@@ -63,14 +61,14 @@ class RadioBindableUi(BindableUi[ui.radio]):
63
61
  return super().bind_prop(prop, ref_ui)
64
62
 
65
63
  def bind_options(self, ref_ui: TGetterOrReadonlyRef):
66
- @ui_effect
64
+ @self._ui_effect
67
65
  def _():
68
66
  self.element.set_options(to_value(ref_ui))
69
67
 
70
68
  return self
71
69
 
72
70
  def bind_value(self, ref_ui: TGetterOrReadonlyRef):
73
- @ui_effect
71
+ @self._ui_effect
74
72
  def _():
75
73
  cast(ValueElement, self.element).set_value(to_value(ref_ui))
76
74
 
@@ -1,7 +1,7 @@
1
1
  from typing import (
2
2
  Any,
3
3
  )
4
- from ex4nicegui.reactive.utils import ParameterClassifier
4
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
5
5
  from ex4nicegui.utils.signals import (
6
6
  _TMaybeRef as TMaybeRef,
7
7
  )
@@ -8,9 +8,7 @@ from typing import (
8
8
  Dict,
9
9
  Union,
10
10
  )
11
- from ex4nicegui.reactive.utils import ParameterClassifier
12
- from ex4nicegui.utils.apiEffect import ui_effect
13
-
11
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
14
12
  from ex4nicegui.utils.signals import (
15
13
  TGetterOrReadonlyRef,
16
14
  _TMaybeRef as TMaybeRef,
@@ -85,14 +83,14 @@ class SelectBindableUi(BindableUi[ui.select]):
85
83
  return super().bind_prop(prop, ref_ui)
86
84
 
87
85
  def bind_options(self, ref_ui: TGetterOrReadonlyRef):
88
- @ui_effect()
86
+ @self._ui_effect()
89
87
  def _():
90
88
  self.element.set_options(to_value(ref_ui))
91
89
 
92
90
  return self
93
91
 
94
92
  def bind_value(self, ref_ui: TGetterOrReadonlyRef):
95
- @ui_effect()
93
+ @self._ui_effect()
96
94
  def _():
97
95
  cast(ValueElement, self.element).set_value(to_value(ref_ui) or None)
98
96
 
@@ -5,9 +5,7 @@ from typing import (
5
5
  TypeVar,
6
6
  cast,
7
7
  )
8
- from ex4nicegui.reactive.utils import ParameterClassifier
9
- from ex4nicegui.utils.apiEffect import ui_effect
10
-
8
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
11
9
  from ex4nicegui.utils.signals import (
12
10
  TGetterOrReadonlyRef,
13
11
  Ref,
@@ -32,7 +30,7 @@ class SliderBindableUi(
32
30
  min: TMaybeRef[_TSliderValue],
33
31
  max: TMaybeRef[_TSliderValue],
34
32
  step: TMaybeRef[_TSliderValue] = 1.0,
35
- value: TMaybeRef[_TSliderValue] = None,
33
+ value: Optional[TMaybeRef[_TSliderValue]] = None,
36
34
  on_change: Optional[Callable[..., Any]] = None,
37
35
  ) -> None:
38
36
  pc = ParameterClassifier(
@@ -67,7 +65,7 @@ class SliderBindableUi(
67
65
  return super().bind_prop(prop, ref_ui)
68
66
 
69
67
  def bind_value(self, ref_ui: TGetterOrReadonlyRef[float]):
70
- @ui_effect
68
+ @self._ui_effect
71
69
  def _():
72
70
  self.element.set_value(to_value(ref_ui))
73
71
  self.element.update()
@@ -95,7 +93,7 @@ class LazySliderBindableUi(SliderBindableUi):
95
93
  ref = cast(Ref, org_value)
96
94
  ele = self.element
97
95
 
98
- @ui_effect
96
+ @self._ui_effect
99
97
  def _():
100
98
  ele.value = ref.value
101
99
 
@@ -4,9 +4,7 @@ from typing import (
4
4
  Optional,
5
5
  TypeVar,
6
6
  )
7
- from ex4nicegui.reactive.utils import ParameterClassifier
8
- from ex4nicegui.utils.apiEffect import ui_effect
9
-
7
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
10
8
  from ex4nicegui.utils.signals import (
11
9
  TGetterOrReadonlyRef,
12
10
  _TMaybeRef as TMaybeRef,
@@ -56,7 +54,7 @@ class SwitchBindableUi(BindableUi[ui.switch]):
56
54
  return super().bind_prop(prop, ref_ui)
57
55
 
58
56
  def bind_value(self, ref_ui: TGetterOrReadonlyRef[bool]):
59
- @ui_effect
57
+ @self._ui_effect
60
58
  def _():
61
59
  self.element.set_value(to_value(ref_ui))
62
60
 
@@ -1,5 +1,5 @@
1
1
  from typing import Dict, Optional
2
- from ex4nicegui.reactive.utils import ParameterClassifier
2
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
3
3
  from ex4nicegui.utils.signals import (
4
4
  to_value,
5
5
  _TMaybeRef as TMaybeRef,
@@ -1,4 +1,4 @@
1
- from ex4nicegui.reactive.utils import ParameterClassifier
1
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
2
2
  from ex4nicegui.utils.signals import (
3
3
  _TMaybeRef as TMaybeRef,
4
4
  )
@@ -1,11 +1,14 @@
1
- from typing import Any, Callable, Optional
2
- from ex4nicegui.reactive.utils import ParameterClassifier
1
+ import inspect
2
+ from typing import Any, Awaitable, Callable, Optional, Union
3
+ from weakref import WeakValueDictionary
4
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
3
5
  from ex4nicegui.utils.signals import (
4
6
  TGetterOrReadonlyRef,
5
7
  to_value,
6
8
  _TMaybeRef as TMaybeRef,
7
9
  )
8
- from nicegui import ui
10
+ from ex4nicegui.utils.scheduler import next_tick
11
+ from nicegui import ui, background_tasks, core
9
12
  from .base import BindableUi
10
13
 
11
14
 
@@ -56,3 +59,106 @@ class TabPanelsBindableUi(BindableUi[ui.tab_panels]):
56
59
  @self._ui_effect
57
60
  def _():
58
61
  self.element.set_value(to_value(ref_ui))
62
+
63
+
64
+ class lazy_tab_panel(ui.tab_panel):
65
+ def __init__(self, name: str) -> None:
66
+ super().__init__(name)
67
+ self._build_fn = None
68
+
69
+ def try_run_build_fn(self):
70
+ if self._build_fn:
71
+ _helper.run_build_fn(self, self._props["name"])
72
+ self._build_fn = None
73
+
74
+ def build_fn(self, fn: Callable[..., Union[None, Awaitable]]):
75
+ self._build_fn = fn
76
+ return fn
77
+
78
+
79
+ class LazyTabPanelsBindableUi(TabPanelsBindableUi):
80
+ def __init__(
81
+ self,
82
+ value: Optional[TMaybeRef[str]] = None,
83
+ *,
84
+ on_change: Optional[Callable[..., Any]] = None,
85
+ animated: TMaybeRef[bool] = True,
86
+ keep_alive: TMaybeRef[bool] = True,
87
+ ) -> None:
88
+ """Lazy Tab Panels
89
+
90
+ @see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#lazy_tab_panels
91
+ @中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#lazy_tab_panels
92
+
93
+ Args:
94
+ value (Optional[TMaybeRef[str]], optional): The value of the tab panel. Defaults to None.
95
+ on_change (Optional[Callable[..., Any]], optional): The callback function when the value of the tab panel changes. Defaults to None.
96
+ animated (TMaybeRef[bool], optional): Whether to animate the tab panel. Defaults to True.
97
+ keep_alive (TMaybeRef[bool], optional): Whether to keep the tab panel alive. Defaults to True.
98
+ """
99
+ super().__init__(
100
+ value, on_change=on_change, animated=animated, keep_alive=keep_alive
101
+ )
102
+
103
+ self.__panels: WeakValueDictionary[str, lazy_tab_panel] = WeakValueDictionary()
104
+
105
+ if value:
106
+
107
+ @self._ui_effect
108
+ def _():
109
+ current_value = to_value(value)
110
+ if current_value in self.__panels:
111
+ panel = self.__panels[current_value]
112
+
113
+ @next_tick
114
+ def _():
115
+ panel.try_run_build_fn()
116
+
117
+ def add_tab_panel(self, name: str):
118
+ def decorator(fn: Callable[..., Union[None, Awaitable]]):
119
+ with self:
120
+ panel = lazy_tab_panel(name)
121
+ str_name = panel._props["name"]
122
+ self.__panels[str_name] = panel
123
+ panel.build_fn(fn)
124
+
125
+ if self.value == name:
126
+ panel.try_run_build_fn()
127
+
128
+ return panel
129
+
130
+ return decorator
131
+
132
+
133
+ class _helper:
134
+ @staticmethod
135
+ def run_build_fn(panel: lazy_tab_panel, name: str) -> None:
136
+ """ """
137
+ fn = panel._build_fn
138
+ if fn is None:
139
+ return
140
+ try:
141
+ expects_arguments = any(
142
+ p.default is inspect.Parameter.empty
143
+ and p.kind is not inspect.Parameter.VAR_POSITIONAL
144
+ and p.kind is not inspect.Parameter.VAR_KEYWORD
145
+ for p in inspect.signature(fn).parameters.values()
146
+ )
147
+
148
+ with panel:
149
+ result = fn(name) if expects_arguments else fn()
150
+ if isinstance(result, Awaitable):
151
+ # NOTE: await an awaitable result even if the handler is not a coroutine (like a lambda statement)
152
+ async def wait_for_result():
153
+ with panel:
154
+ try:
155
+ await result
156
+ except Exception as e:
157
+ core.app.handle_exception(e)
158
+
159
+ if core.loop and core.loop.is_running():
160
+ background_tasks.create(wait_for_result(), name=str(fn))
161
+ else:
162
+ core.app.on_startup(wait_for_result())
163
+ except Exception as e:
164
+ core.app.handle_exception(e)