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
@@ -6,18 +6,19 @@ from typing import (
6
6
  Dict,
7
7
  )
8
8
  from typing_extensions import Literal
9
- from ex4nicegui.reactive.utils import ParameterClassifier, dataframe2col_str
9
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
10
+ from ex4nicegui.reactive.services.pandas_service import dataframe2col_str
11
+
10
12
  import ex4nicegui.utils.common as utils_common
11
13
  from ex4nicegui.utils.signals import (
12
14
  TGetterOrReadonlyRef,
13
- ReadonlyRef,
15
+ TReadonlyRef,
14
16
  is_ref,
15
17
  ref_computed,
16
18
  to_ref,
17
19
  _TMaybeRef as TMaybeRef,
18
20
  to_value,
19
21
  to_raw,
20
- on,
21
22
  RefWrapper,
22
23
  )
23
24
  from nicegui import ui
@@ -67,7 +68,7 @@ class TableBindableUi(BindableUi[ui.table]):
67
68
 
68
69
  self._arg_selection = selection
69
70
  self._arg_row_key = row_key
70
- self._selection_ref: ReadonlyRef[List[Any]] = to_ref([]) # type: ignore
71
+ self._selection_ref: TReadonlyRef[List[Any]] = to_ref([]) # type: ignore
71
72
 
72
73
  def on_selection(_):
73
74
  self._selection_ref.value = self.element.selected # type: ignore
@@ -182,7 +183,7 @@ class TableBindableUi(BindableUi[ui.table]):
182
183
  return self
183
184
 
184
185
  def bind_rows(self, ref_ui: TGetterOrReadonlyRef[List[Dict]]):
185
- @on(ref_ui, deep=True)
186
+ @self._ui_signal_on(ref_ui, deep=True)
186
187
  def _():
187
188
  ele = self.element
188
189
  ele._props["rows"] = list(to_raw(to_value(ref_ui)))
@@ -191,7 +192,7 @@ class TableBindableUi(BindableUi[ui.table]):
191
192
  return self
192
193
 
193
194
  def bind_columns(self, ref_ui: TGetterOrReadonlyRef[List[Dict]]):
194
- @on(ref_ui, deep=True)
195
+ @self._ui_signal_on(ref_ui, deep=True)
195
196
  def _():
196
197
  ele = self.element
197
198
  ele._props["columns"] = list(to_raw(to_value(ref_ui)))
@@ -1,5 +1,5 @@
1
1
  from typing import Any, Callable, 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
  TGetterOrReadonlyRef,
5
5
  to_value,
@@ -5,13 +5,11 @@ from typing import (
5
5
  Dict,
6
6
  cast,
7
7
  )
8
- from ex4nicegui.reactive.utils import ParameterClassifier
9
- from ex4nicegui.utils.apiEffect import ui_effect
8
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
10
9
  from ex4nicegui.utils.signals import (
11
10
  TGetterOrReadonlyRef,
12
11
  Ref,
13
12
  _TMaybeRef as TMaybeRef,
14
- effect,
15
13
  is_setter_ref,
16
14
  to_value,
17
15
  )
@@ -61,7 +59,7 @@ class TextareaBindableUi(BindableUi[ui.textarea]):
61
59
  return super().bind_prop(prop, ref_ui)
62
60
 
63
61
  def bind_value(self, ref_ui: TGetterOrReadonlyRef[str]):
64
- @ui_effect
62
+ @self._ui_effect
65
63
  def _():
66
64
  self.element.set_value(to_value(ref_ui))
67
65
 
@@ -95,7 +93,7 @@ class LazyTextareaBindableUi(TextareaBindableUi):
95
93
  ref = cast(Ref, org_value)
96
94
  ele = self.element
97
95
 
98
- @effect
96
+ @self._ui_effect
99
97
  def _():
100
98
  ele.value = ref.value
101
99
 
@@ -11,7 +11,7 @@ from ex4nicegui.utils.signals import (
11
11
  from nicegui import ui
12
12
  from nicegui.events import handle_event
13
13
  from .base import BindableUi
14
- from .utils import _convert_kws_ref2value
14
+ from ex4nicegui.reactive.systems.reactive_system import convert_kws_ref2value
15
15
 
16
16
 
17
17
  class UploadResult:
@@ -57,7 +57,7 @@ class UploadBindableUi(BindableUi[ui.upload]):
57
57
  "auto_upload": auto_upload,
58
58
  }
59
59
 
60
- value_kws = _convert_kws_ref2value(kws)
60
+ value_kws = convert_kws_ref2value(kws)
61
61
 
62
62
  self._on_upload_callbacks = []
63
63
 
@@ -1,9 +1,9 @@
1
1
  from typing import Any, Optional, Callable
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,
6
- _TMaybeRef as TMaybeRef,
6
+ TMaybeRef,
7
7
  )
8
8
  from nicegui import ui
9
9
  from ex4nicegui.reactive.officials.base import BindableUi
@@ -0,0 +1,55 @@
1
+
2
+ const REGEX_NEWLINE = /[\r\n]/g;
3
+ const REGEX_START_SPACES = /^\s+/gm;
4
+
5
+ function getClasses(id) {
6
+ return `ex4ng-scoped-style-${id}`;
7
+ }
8
+
9
+ function removeInvalidChars(str) {
10
+ str = str.replace(REGEX_START_SPACES, '');
11
+ return str.replace(REGEX_NEWLINE, '');
12
+ }
13
+
14
+ function appendCSS(styleElement, cssText) {
15
+ // 获取已有的 CSS 内容
16
+ let existingCSS = styleElement.textContent || '';
17
+
18
+ // 如果已有的 CSS 内容不为空,添加一个空行作为分隔符
19
+ if (existingCSS.trim() !== '') {
20
+ existingCSS += '\n';
21
+ }
22
+
23
+ // 拼接新的 CSS 内容
24
+ existingCSS += cssText;
25
+
26
+ // 将新的 CSS 内容设置回 style 标签
27
+ styleElement.textContent = existingCSS;
28
+ }
29
+
30
+ export default {
31
+ template: `<template></template>`,
32
+ methods: {
33
+ createStyle(id, css) {
34
+ css = removeInvalidChars(css);
35
+
36
+ const classes = getClasses(id);
37
+ const target = document.querySelector(`style.${classes}`);
38
+ if (target) {
39
+ appendCSS(target, css);
40
+ } else {
41
+ const style = document.createElement('style');
42
+ style.classList.add(classes);
43
+ style.innerHTML = css;
44
+ document.head.appendChild(style);
45
+ }
46
+ },
47
+ removeStyle(id) {
48
+ const classes = getClasses(id);
49
+ const target = document.querySelector(`style.${classes}`);
50
+ if (target) {
51
+ target.remove();
52
+ }
53
+ },
54
+ },
55
+ };
@@ -0,0 +1,25 @@
1
+ from nicegui.element import Element
2
+ from ex4nicegui.helper import client_instance_locker
3
+ from nicegui import ui
4
+
5
+
6
+ class ScopedStyle(Element, component="scopedStyle.js"):
7
+ pass
8
+
9
+ @staticmethod
10
+ def get():
11
+ if not ui.context.slot_stack:
12
+ return None
13
+ return _scoped_style_factory.get_object(ui.context.client)
14
+
15
+ def create_style(self, element: Element, css: str):
16
+ element_id = f"c{element.id}"
17
+
18
+ self.run_method("createStyle", element_id, css)
19
+
20
+ def remove_style(self, element: Element):
21
+ element_id = f"c{element.id}"
22
+ self.run_method("removeStyle", element_id)
23
+
24
+
25
+ _scoped_style_factory = client_instance_locker.ClientInstanceLocker(ScopedStyle)
@@ -0,0 +1,31 @@
1
+ try:
2
+ import pandas as pd
3
+ except ImportError:
4
+ pass
5
+
6
+
7
+ def dataframe2col_str(df, copy=True):
8
+ if isinstance(df.columns, pd.MultiIndex):
9
+ raise ValueError(
10
+ "MultiIndex columns are not supported. "
11
+ "You can convert them to strings using something like "
12
+ '`df.columns = ["_".join(col) for col in df.columns.values]`.'
13
+ )
14
+
15
+ date_cols = df.columns[df.dtypes == "datetime64[ns]"]
16
+ time_cols = df.columns[df.dtypes == "timedelta64[ns]"]
17
+ complex_cols = df.columns[df.dtypes == "complex128"]
18
+ period_cols = df.columns[df.dtypes == "period[M]"]
19
+ if (
20
+ len(date_cols) != 0
21
+ or len(time_cols) != 0
22
+ or len(complex_cols) != 0
23
+ or len(period_cols) != 0
24
+ ):
25
+ df = df.copy() if copy else df
26
+ df[date_cols] = df[date_cols].astype(str)
27
+ df[time_cols] = df[time_cols].astype(str)
28
+ df[complex_cols] = df[complex_cols].astype(str)
29
+ df[period_cols] = df[period_cols].astype(str)
30
+
31
+ return df
@@ -5,36 +5,16 @@ from typing import (
5
5
  Iterable,
6
6
  List,
7
7
  Optional,
8
- Protocol,
9
8
  Tuple,
10
9
  cast,
11
- runtime_checkable,
12
- Union,
13
10
  )
14
-
15
- from ex4nicegui.utils.signals import is_ref, to_value, is_setter_ref
11
+ from nicegui import ui
12
+ from ex4nicegui.utils.signals import is_ref, is_setter_ref
16
13
  from nicegui.events import handle_event
17
-
18
- try:
19
- import pandas as pd
20
- except ImportError:
21
- pass
22
-
23
-
24
- @runtime_checkable
25
- class GetItemProtocol(Protocol):
26
- def __getitem__(self, key):
27
- ...
28
-
29
-
30
- @runtime_checkable
31
- class SetItemProtocol(Protocol):
32
- def __setitem__(self, key, value):
33
- ...
34
-
35
-
36
- def _convert_kws_ref2value(kws: Dict) -> Dict:
37
- return {key: to_value(value) for key, value in kws.items()}
14
+ from ex4nicegui.reactive.systems.reactive_system import (
15
+ convert_kws_ref2value,
16
+ inject_method,
17
+ )
38
18
 
39
19
 
40
20
  class ParameterClassifier:
@@ -75,7 +55,7 @@ class ParameterClassifier:
75
55
  )
76
56
 
77
57
  def get_values_kws(self) -> Dict:
78
- value_kws = _convert_kws_ref2value(
58
+ value_kws = convert_kws_ref2value(
79
59
  {k: v for k, v in self._args.items() if k not in self.events}
80
60
  )
81
61
 
@@ -105,43 +85,5 @@ class ParameterClassifier:
105
85
  }
106
86
 
107
87
 
108
- def get_attribute(obj: Union[object, GetItemProtocol], name: Union[str, int]) -> Any:
109
- if isinstance(obj, (GetItemProtocol)):
110
- return obj[name]
111
- return getattr(obj, name) # type: ignore
112
-
113
-
114
- def set_attribute(
115
- obj: Union[object, SetItemProtocol], name: Union[str, int], value: Any
116
- ) -> None:
117
- if isinstance(obj, SetItemProtocol):
118
- obj[name] = value
119
- else:
120
- setattr(obj, name, value) # type: ignore
121
-
122
-
123
- def dataframe2col_str(df, copy=True):
124
- if isinstance(df.columns, pd.MultiIndex):
125
- raise ValueError(
126
- "MultiIndex columns are not supported. "
127
- "You can convert them to strings using something like "
128
- '`df.columns = ["_".join(col) for col in df.columns.values]`.'
129
- )
130
-
131
- date_cols = df.columns[df.dtypes == "datetime64[ns]"]
132
- time_cols = df.columns[df.dtypes == "timedelta64[ns]"]
133
- complex_cols = df.columns[df.dtypes == "complex128"]
134
- period_cols = df.columns[df.dtypes == "period[M]"]
135
- if (
136
- len(date_cols) != 0
137
- or len(time_cols) != 0
138
- or len(complex_cols) != 0
139
- or len(period_cols) != 0
140
- ):
141
- df = df.copy() if copy else df
142
- df[date_cols] = df[date_cols].astype(str)
143
- df[time_cols] = df[time_cols].astype(str)
144
- df[complex_cols] = df[complex_cols].astype(str)
145
- df[period_cols] = df[period_cols].astype(str)
146
-
147
- return df
88
+ def inject_handle_delete(element: ui.element, on_delete: Callable[[], None]):
89
+ inject_method(element, "_handle_delete", on_delete)
@@ -0,0 +1,157 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal
4
+
5
+ from nicegui import ui
6
+ from nicegui.elements.mixins.color_elements import (
7
+ QUASAR_COLORS,
8
+ TAILWIND_COLORS,
9
+ )
10
+
11
+ from functools import lru_cache
12
+
13
+
14
+ _color_system_type = Literal["QUASAR", "TAILWIND", "STYLE"]
15
+
16
+
17
+ def get_text_color_info(name: str):
18
+ system_type: _color_system_type = "STYLE"
19
+
20
+ if name in QUASAR_COLORS:
21
+ system_type = "QUASAR"
22
+ elif name in TAILWIND_COLORS:
23
+ system_type = "TAILWIND"
24
+ name = f"text-{name}"
25
+ else:
26
+ pass
27
+
28
+ return system_type, name
29
+
30
+
31
+ def get_bg_color_info(color: str):
32
+ system_type: _color_system_type = "STYLE"
33
+
34
+ if color in QUASAR_COLORS:
35
+ system_type = "QUASAR"
36
+ elif color in TAILWIND_COLORS:
37
+ system_type = "TAILWIND"
38
+ color = f"bg-{color}"
39
+ else:
40
+ pass
41
+
42
+ return system_type, color
43
+
44
+
45
+ def _remove_text_color_from_quasar(element: ui.element, color: str):
46
+ color_prop = getattr(element, "TEXT_COLOR_PROP", None)
47
+ if color_prop:
48
+ element._props.pop(color_prop, None)
49
+
50
+
51
+ def _remove_text_color_from_tailwind(element: ui.element, color: str):
52
+ color = f"text-{color}"
53
+ element._classes.remove(color)
54
+
55
+
56
+ def _remove_text_color(element: ui.element, color: str):
57
+ element._style.pop("color", None)
58
+
59
+
60
+ def _add_text_color_from_quasar(element: ui.element, color: str):
61
+ color_prop = getattr(element, "TEXT_COLOR_PROP", None)
62
+ if color_prop:
63
+ element._props[color_prop] = color
64
+
65
+
66
+ def _add_text_color_from_tailwind(element: ui.element, color: str):
67
+ color = f"text-{color}"
68
+ element.classes(color)
69
+
70
+
71
+ def _add_text_color(element: ui.element, color: str):
72
+ element._style["color"] = f"{color} !important"
73
+
74
+
75
+ @lru_cache(maxsize=10)
76
+ def _query_text_color(color: str, add_handler=True):
77
+ if color in QUASAR_COLORS:
78
+ return (
79
+ _add_text_color_from_quasar
80
+ if add_handler
81
+ else _remove_text_color_from_quasar
82
+ )
83
+ elif color in TAILWIND_COLORS:
84
+ return (
85
+ _add_text_color_from_tailwind
86
+ if add_handler
87
+ else _remove_text_color_from_tailwind
88
+ )
89
+ elif color is not None:
90
+ return _add_text_color if add_handler else _remove_text_color
91
+
92
+
93
+ def remove_text_color(element: ui.element, color: str):
94
+ handler = _query_text_color(color, add_handler=False)
95
+ if handler:
96
+ handler(element, color)
97
+
98
+
99
+ def add_text_color(element: ui.element, color: str):
100
+ handler = _query_text_color(color)
101
+ if handler:
102
+ handler(element, color)
103
+
104
+
105
+ # background color handlers
106
+
107
+
108
+ def _remove_bg_from_quasar(element: ui.element, color: str):
109
+ color_prop = getattr(element, "BACKGROUND_COLOR_PROP", None)
110
+ if color_prop:
111
+ element._props.pop(color_prop, None)
112
+
113
+
114
+ def _remove_bg_from_tailwind(element: ui.element, color: str):
115
+ color = f"bg-{color}"
116
+ element._classes.remove(color)
117
+
118
+
119
+ def _remove_background_color(element: ui.element, color: str):
120
+ element._style.pop("background-color", None)
121
+
122
+
123
+ def _add_bg_from_quasar(element: ui.element, color: str):
124
+ color_prop = getattr(element, "BACKGROUND_COLOR_PROP", None)
125
+ if color_prop:
126
+ element._props[color_prop] = color
127
+
128
+
129
+ def _add_bg_from_tailwind(element: ui.element, color: str):
130
+ color = f"bg-{color}"
131
+ element.classes(color)
132
+
133
+
134
+ def _add_background_color(element: ui.element, color: str):
135
+ element._style["background-color"] = f"{color} !important"
136
+
137
+
138
+ @lru_cache(maxsize=10)
139
+ def _query_background_color(color: str, add_handler=True):
140
+ if color in QUASAR_COLORS:
141
+ return _add_bg_from_quasar if add_handler else _remove_bg_from_quasar
142
+ elif color in TAILWIND_COLORS:
143
+ return _add_bg_from_tailwind if add_handler else _remove_bg_from_tailwind
144
+ elif color is not None:
145
+ return _add_background_color if add_handler else _remove_background_color
146
+
147
+
148
+ def remove_background_color(element: ui.element, color: str):
149
+ handler = _query_background_color(color, add_handler=False)
150
+ if handler:
151
+ handler(element, color)
152
+
153
+
154
+ def add_background_color(element: ui.element, color: str):
155
+ handler = _query_background_color(color)
156
+ if handler:
157
+ handler(element, color)
@@ -0,0 +1,33 @@
1
+ from typing import (
2
+ Any,
3
+ Protocol,
4
+ runtime_checkable,
5
+ Union,
6
+ )
7
+
8
+
9
+ @runtime_checkable
10
+ class GetItemProtocol(Protocol):
11
+ def __getitem__(self, key):
12
+ ...
13
+
14
+
15
+ @runtime_checkable
16
+ class SetItemProtocol(Protocol):
17
+ def __setitem__(self, key, value):
18
+ ...
19
+
20
+
21
+ def get_attribute(obj: Union[object, GetItemProtocol], name: Union[str, int]) -> Any:
22
+ if isinstance(obj, (GetItemProtocol)):
23
+ return obj[name]
24
+ return getattr(obj, name) # type: ignore
25
+
26
+
27
+ def set_attribute(
28
+ obj: Union[object, SetItemProtocol], name: Union[str, int], value: Any
29
+ ) -> None:
30
+ if isinstance(obj, SetItemProtocol):
31
+ obj[name] = value
32
+ else:
33
+ setattr(obj, name, value) # type: ignore
@@ -0,0 +1,21 @@
1
+ from typing import Callable, Dict
2
+ from ex4nicegui.utils.signals import to_value
3
+
4
+
5
+ def convert_kws_ref2value(kws: Dict) -> Dict:
6
+ return {key: to_value(value) for key, value in kws.items()}
7
+
8
+
9
+ def inject_method(obj, method_name: str, new_handle: Callable):
10
+ if hasattr(obj, method_name):
11
+ original_method = getattr(obj, method_name)
12
+
13
+ def injected_method(*args, **kwargs):
14
+ new_handle(*args, **kwargs)
15
+ return original_method(*args, **kwargs)
16
+
17
+ setattr(obj, method_name, injected_method)
18
+ else:
19
+ raise AttributeError(
20
+ f"'{type(obj).__name__}' object has no attribute '{method_name}'."
21
+ )
@@ -4,7 +4,7 @@ from nicegui.dataclasses import KWONLY_SLOTS
4
4
  from nicegui.events import handle_event, UiEventArguments
5
5
  from nicegui.element import Element
6
6
 
7
- from ex4nicegui.utils.signals import ReadonlyRef, batch, to_ref
7
+ from ex4nicegui.utils.signals import TReadonlyRef, batch, to_ref
8
8
 
9
9
  _Update_Args = [
10
10
  "x",
@@ -42,15 +42,15 @@ class UseMouse(Element, component="UseMouse.js"):
42
42
 
43
43
  @property
44
44
  def x(self):
45
- return cast(ReadonlyRef[float], self.__x)
45
+ return cast(TReadonlyRef[float], self.__x)
46
46
 
47
47
  @property
48
48
  def y(self):
49
- return cast(ReadonlyRef[float], self.__y)
49
+ return cast(TReadonlyRef[float], self.__y)
50
50
 
51
51
  @property
52
52
  def sourceType(self):
53
- return cast(ReadonlyRef[float], self.__sourceType)
53
+ return cast(TReadonlyRef[float], self.__sourceType)
54
54
 
55
55
  def on_update(self, handler: Optional[Callable[..., Any]]):
56
56
  def inner_handler(e):
@@ -4,7 +4,7 @@ from ex4nicegui.utils.signals import (
4
4
  to_ref,
5
5
  to_value,
6
6
  effect,
7
- _TMaybeRef as TMaybeRef,
7
+ TMaybeRef,
8
8
  )
9
9
  from typing import Any
10
10
  from typing_extensions import Protocol
@@ -26,9 +26,8 @@ from typing import (
26
26
  from functools import partial
27
27
  from dataclasses import dataclass
28
28
  from signe.core.scope import Scope
29
- from .utils import get_attribute
29
+ from ex4nicegui.reactive.systems.object_system import get_attribute
30
30
  from ex4nicegui.reactive.empty import Empty
31
- # from .transitionGroup import TransitionGroup
32
31
 
33
32
  _T = TypeVar("_T")
34
33
  _T_data = Union[List[Any], TGetterOrReadonlyRef[List[Any]], RefWrapper]
@@ -25,7 +25,7 @@ import tokenize
25
25
  import executing
26
26
  import ast
27
27
  import warnings
28
- from .utils import get_attribute, set_attribute
28
+ from ex4nicegui.reactive.systems.object_system import get_attribute, set_attribute
29
29
 
30
30
  _T = TypeVar("_T")
31
31
 
@@ -1,5 +1,6 @@
1
1
  import signe
2
2
  from signe.core.scope import Scope
3
+ from signe.core.consts import EffectState
3
4
  from typing import (
4
5
  TypeVar,
5
6
  overload,
@@ -88,7 +89,10 @@ def ui_effect(
88
89
  **kws,
89
90
  scope=scope or _CLIENT_SCOPE_MANAGER.get_current_scope(),
90
91
  )
91
- res.update()
92
+
93
+ res.trigger(EffectState.NEED_UPDATE)
94
+ scheduler.run()
95
+ # res.update()
92
96
 
93
97
  return res
94
98
 
@@ -1,4 +1,5 @@
1
1
  import signe
2
+ from signe.core.consts import EffectState
2
3
  from typing import (
3
4
  TypeVar,
4
5
  overload,
@@ -6,7 +7,6 @@ from typing import (
6
7
  Callable,
7
8
  Union,
8
9
  )
9
-
10
10
  from .scheduler import get_uiScheduler
11
11
  from .clientScope import _CLIENT_SCOPE_MANAGER
12
12
 
@@ -81,7 +81,8 @@ def effect(
81
81
  scope=_CLIENT_SCOPE_MANAGER.get_current_scope(),
82
82
  )
83
83
 
84
- res.update()
84
+ res.trigger(EffectState.NEED_UPDATE)
85
+ scheduler.run()
85
86
 
86
87
  return res
87
88