ex4nicegui 0.8.10__py3-none-any.whl → 0.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ex4nicegui/__init__.py +3 -2
- ex4nicegui/bi/dataSource.py +1 -2
- ex4nicegui/bi/elements/ui_aggrid.py +1 -2
- ex4nicegui/bi/protocols.py +10 -20
- ex4nicegui/layout/rxFlex/index.py +0 -1
- ex4nicegui/reactive/EChartsComponent/ECharts.js +1 -1
- ex4nicegui/reactive/EChartsComponent/ECharts.py +1 -5
- ex4nicegui/reactive/UseDraggable/UseDraggable.py +3 -3
- ex4nicegui/reactive/__init__.py +2 -3
- ex4nicegui/reactive/_vmodel.py +150 -0
- ex4nicegui/reactive/base.py +2 -3
- ex4nicegui/reactive/deferredTask.py +2 -5
- ex4nicegui/reactive/mermaid/{mermaid.js → ex4ng_mermaid.js} +1 -1
- ex4nicegui/reactive/mermaid/mermaid.py +1 -6
- ex4nicegui/reactive/mixins/flexLayout.py +4 -8
- ex4nicegui/reactive/mixins/value_element.py +1 -2
- ex4nicegui/reactive/officials/echarts.py +1 -1
- ex4nicegui/reactive/systems/object_system.py +2 -4
- ex4nicegui/reactive/usePagination.py +2 -4
- ex4nicegui/reactive/vfor.py +1 -0
- ex4nicegui/toolbox/core/vue_use.py +1 -1
- ex4nicegui/utils/apiEffect.py +1 -2
- ex4nicegui/utils/clientScope.py +5 -8
- ex4nicegui/utils/effect.py +1 -2
- ex4nicegui/utils/page_state.py +70 -0
- ex4nicegui/utils/proxy/descriptor.py +0 -1
- ex4nicegui/utils/refComputed.py +1 -2
- ex4nicegui/utils/refreshable.py +122 -0
- ex4nicegui/utils/signals.py +5 -88
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/METADATA +62 -21
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/RECORD +54 -80
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/WHEEL +1 -1
- ex4nicegui/gsap/__init__.py +0 -23
- ex4nicegui/gsap/gsap.py +0 -145
- ex4nicegui/gsap/timeline.js +0 -56
- ex4nicegui/gsap/timeline.py +0 -78
- ex4nicegui/gsap/wrapGsap.js +0 -48
- ex4nicegui/libs/gsap/.DS_Store +0 -0
- ex4nicegui/libs/gsap/CSSPlugin.js +0 -1577
- ex4nicegui/libs/gsap/CSSRulePlugin.js +0 -134
- ex4nicegui/libs/gsap/CustomEase.js +0 -371
- ex4nicegui/libs/gsap/Draggable.js +0 -2699
- ex4nicegui/libs/gsap/EasePack.js +0 -212
- ex4nicegui/libs/gsap/EaselPlugin.js +0 -341
- ex4nicegui/libs/gsap/Flip.js +0 -1518
- ex4nicegui/libs/gsap/MotionPathPlugin.js +0 -368
- ex4nicegui/libs/gsap/Observer.js +0 -686
- ex4nicegui/libs/gsap/PixiPlugin.js +0 -461
- ex4nicegui/libs/gsap/ScrollToPlugin.js +0 -273
- ex4nicegui/libs/gsap/ScrollTrigger.js +0 -2658
- ex4nicegui/libs/gsap/TextPlugin.js +0 -166
- ex4nicegui/libs/gsap/__init__.py +0 -0
- ex4nicegui/libs/gsap/all.js +0 -31
- ex4nicegui/libs/gsap/gsap-core.js +0 -4487
- ex4nicegui/libs/gsap/gsap.mjs +0 -6
- ex4nicegui/libs/gsap/utils/__init__.py +0 -0
- ex4nicegui/libs/gsap/utils/matrix.js +0 -420
- ex4nicegui/libs/gsap/utils/paths.js +0 -1487
- ex4nicegui/libs/gsap/utils/strings.js +0 -107
- ex4nicegui/reactive/local_file_picker.py +0 -208
- ex4nicegui/reactive/vmodel.py +0 -237
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info/licenses}/LICENSE +0 -0
ex4nicegui/__init__.py
CHANGED
|
@@ -8,8 +8,6 @@ from ex4nicegui.utils.types import (
|
|
|
8
8
|
)
|
|
9
9
|
from ex4nicegui.utils.scheduler import next_tick
|
|
10
10
|
from ex4nicegui.utils.signals import (
|
|
11
|
-
effect,
|
|
12
|
-
effect_refreshable,
|
|
13
11
|
to_raw,
|
|
14
12
|
is_ref,
|
|
15
13
|
to_ref,
|
|
@@ -23,9 +21,11 @@ from ex4nicegui.utils.signals import (
|
|
|
23
21
|
batch,
|
|
24
22
|
is_reactive,
|
|
25
23
|
)
|
|
24
|
+
from ex4nicegui.utils.refreshable import effect, effect_refreshable
|
|
26
25
|
from ex4nicegui.utils.asyncComputed import async_computed
|
|
27
26
|
from ex4nicegui.utils.clientScope import new_scope
|
|
28
27
|
from ex4nicegui.reactive.EChartsComponent.ECharts import reset_echarts_dependencies
|
|
28
|
+
from ex4nicegui.utils.page_state import PageState
|
|
29
29
|
from .version import __version__
|
|
30
30
|
|
|
31
31
|
__all__ = [
|
|
@@ -53,5 +53,6 @@ __all__ = [
|
|
|
53
53
|
"new_scope",
|
|
54
54
|
"next_tick",
|
|
55
55
|
"reset_echarts_dependencies",
|
|
56
|
+
"PageState",
|
|
56
57
|
"__version__",
|
|
57
58
|
]
|
ex4nicegui/bi/dataSource.py
CHANGED
|
@@ -182,8 +182,7 @@ class DataSource:
|
|
|
182
182
|
|
|
183
183
|
@ng_client.on_disconnect
|
|
184
184
|
def _(e: Client):
|
|
185
|
-
|
|
186
|
-
self._component_map.remove_client(e.id)
|
|
185
|
+
self._component_map.remove_client(e.id)
|
|
187
186
|
|
|
188
187
|
info = ComponentInfo(
|
|
189
188
|
ComponentInfoKey(client_id, element_id), update_callback, uiResult=ui_result
|
|
@@ -57,8 +57,7 @@ def ui_aggrid(
|
|
|
57
57
|
data = self._dataSource.get_filtered_data(cp)
|
|
58
58
|
new_opts = self._dataSource._idataSource.get_aggrid_options(data)
|
|
59
59
|
options = _merge_options(fixed_options, new_opts)
|
|
60
|
-
cp.
|
|
61
|
-
cp.update()
|
|
60
|
+
cp.options = {**options, "theme": kwargs.get("theme", "quartz")}
|
|
62
61
|
|
|
63
62
|
self._dataSource._register_component(cp.id, on_source_update)
|
|
64
63
|
|
ex4nicegui/bi/protocols.py
CHANGED
|
@@ -9,14 +9,11 @@ from ex4nicegui.utils import common as utils_common
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class IDataSourceAble(Protocol):
|
|
12
|
-
def get_data(self) -> Any:
|
|
13
|
-
...
|
|
12
|
+
def get_data(self) -> Any: ...
|
|
14
13
|
|
|
15
|
-
def reload(self, data) -> None:
|
|
16
|
-
...
|
|
14
|
+
def reload(self, data) -> None: ...
|
|
17
15
|
|
|
18
|
-
def apply_filters(self, data, filters: List[_TFilterCallback]) -> Any:
|
|
19
|
-
...
|
|
16
|
+
def apply_filters(self, data, filters: List[_TFilterCallback]) -> Any: ...
|
|
20
17
|
|
|
21
18
|
def duplicates_column_values(
|
|
22
19
|
self,
|
|
@@ -25,30 +22,23 @@ class IDataSourceAble(Protocol):
|
|
|
25
22
|
*,
|
|
26
23
|
exclude_null_value=True,
|
|
27
24
|
sort_options: Optional[_TDuplicates_column_values_sort_options] = None,
|
|
28
|
-
) -> List:
|
|
29
|
-
...
|
|
25
|
+
) -> List: ...
|
|
30
26
|
|
|
31
|
-
def get_aggrid_options(self, data) -> Dict:
|
|
32
|
-
...
|
|
27
|
+
def get_aggrid_options(self, data) -> Dict: ...
|
|
33
28
|
|
|
34
|
-
def get_table_options(self, data) -> Dict:
|
|
35
|
-
...
|
|
29
|
+
def get_table_options(self, data) -> Dict: ...
|
|
36
30
|
|
|
37
|
-
def slider_check(self, data, column_name: str) -> None:
|
|
38
|
-
...
|
|
31
|
+
def slider_check(self, data, column_name: str) -> None: ...
|
|
39
32
|
|
|
40
33
|
def slider_min_max(
|
|
41
34
|
self, data, column_name: str
|
|
42
|
-
) -> Tuple[Optional[float], Optional[float]]:
|
|
43
|
-
...
|
|
35
|
+
) -> Tuple[Optional[float], Optional[float]]: ...
|
|
44
36
|
|
|
45
|
-
def range_check(self, data, column_name: str) -> None:
|
|
46
|
-
...
|
|
37
|
+
def range_check(self, data, column_name: str) -> None: ...
|
|
47
38
|
|
|
48
39
|
def range_min_max(
|
|
49
40
|
self, data, column_name: str
|
|
50
|
-
) -> Tuple[Optional[float], Optional[float]]:
|
|
51
|
-
...
|
|
41
|
+
) -> Tuple[Optional[float], Optional[float]]: ...
|
|
52
42
|
|
|
53
43
|
|
|
54
44
|
class CallableDataSourceAble(IDataSourceAble):
|
|
@@ -11,18 +11,14 @@ from nicegui.events import handle_event, UiEventArguments, GenericEventArguments
|
|
|
11
11
|
from nicegui.element import Element
|
|
12
12
|
from nicegui.awaitable_response import AwaitableResponse
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
import nicegui
|
|
15
14
|
|
|
16
15
|
from .types import (
|
|
17
16
|
_T_event_name,
|
|
18
17
|
)
|
|
19
18
|
from .utils import get_bound_event_args, create_event_handler_args
|
|
20
19
|
|
|
21
|
-
NG_ROOT = Path(nicegui.__file__).parent / "elements"
|
|
22
|
-
libraries = [NG_ROOT / "lib/echarts/echarts.min.js"]
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
class echarts(Element, component="ECharts.js", dependencies=libraries): # type: ignore
|
|
21
|
+
class echarts(Element, component="ECharts.js"):
|
|
26
22
|
def __init__(
|
|
27
23
|
self,
|
|
28
24
|
options: Optional[dict] = None,
|
|
@@ -125,9 +125,9 @@ class UseDraggable(Element, component="UseDraggable.js"):
|
|
|
125
125
|
self.on("update", inner_handler, args=_Update_Args)
|
|
126
126
|
|
|
127
127
|
def apply(self, target: Element):
|
|
128
|
-
assert (
|
|
129
|
-
|
|
130
|
-
)
|
|
128
|
+
assert self.__target_id is None, (
|
|
129
|
+
"draggable can only be applied to one current element"
|
|
130
|
+
)
|
|
131
131
|
self.__target_id = target.id
|
|
132
132
|
self._props["elementId"] = self.__target_id
|
|
133
133
|
# self.run_method("applyTargetId", str(self.__target_id))
|
ex4nicegui/reactive/__init__.py
CHANGED
|
@@ -63,7 +63,7 @@ from .officials.range import LazyRangeBindableUi as lazy_range
|
|
|
63
63
|
from .officials.tree import TreeBindableUi as tree
|
|
64
64
|
from .officials.spinner import SpinnerBindableUi as spinner
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
from .UseDraggable.UseDraggable import use_draggable
|
|
68
68
|
from .useMouse.UseMouse import use_mouse
|
|
69
69
|
|
|
@@ -73,7 +73,7 @@ from .fileWatcher import FilesWatcher
|
|
|
73
73
|
from .mermaid.mermaid import Mermaid as mermaid
|
|
74
74
|
from .officials.dialog import DialogBindableUi as dialog
|
|
75
75
|
from .vfor import vfor, VforStore
|
|
76
|
-
from .
|
|
76
|
+
from ._vmodel import vmodel
|
|
77
77
|
from .view_model import ViewModel, var, cached_var, list_var, dict_var
|
|
78
78
|
|
|
79
79
|
pagination = q_pagination
|
|
@@ -89,7 +89,6 @@ __all__ = [
|
|
|
89
89
|
"circular_progress",
|
|
90
90
|
"knob",
|
|
91
91
|
"UploadResult",
|
|
92
|
-
"local_file_picker",
|
|
93
92
|
"use_draggable",
|
|
94
93
|
"use_mouse",
|
|
95
94
|
"use_pagination",
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import warnings
|
|
3
|
+
from ex4nicegui.utils.signals import (
|
|
4
|
+
RefWrapper,
|
|
5
|
+
TRef,
|
|
6
|
+
to_raw,
|
|
7
|
+
to_ref_wrapper,
|
|
8
|
+
to_value,
|
|
9
|
+
is_reactive,
|
|
10
|
+
is_ref,
|
|
11
|
+
)
|
|
12
|
+
from typing import (
|
|
13
|
+
Any,
|
|
14
|
+
Union,
|
|
15
|
+
cast,
|
|
16
|
+
Tuple,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from ex4nicegui.reactive.systems.object_system import get_attribute, set_attribute
|
|
20
|
+
from ex4nicegui.utils.types import _TMaybeRef as TMaybeRef, Ref
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_writeable_wrapper(ref_obj: TRef, attrs: Tuple[Union[str, int], ...]):
|
|
24
|
+
if not attrs:
|
|
25
|
+
|
|
26
|
+
def maybe_ref_getter():
|
|
27
|
+
return to_value(ref_obj)
|
|
28
|
+
|
|
29
|
+
def reactive_getter():
|
|
30
|
+
return to_raw(ref_obj)
|
|
31
|
+
|
|
32
|
+
def setter(value):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
wrapper = to_ref_wrapper(
|
|
36
|
+
reactive_getter if is_reactive(ref_obj) else maybe_ref_getter,
|
|
37
|
+
setter,
|
|
38
|
+
)
|
|
39
|
+
wrapper._is_readonly = False
|
|
40
|
+
return wrapper
|
|
41
|
+
|
|
42
|
+
def getter():
|
|
43
|
+
obj = get_attribute(to_value(ref_obj), attrs[0])
|
|
44
|
+
for attr in attrs[1:]:
|
|
45
|
+
obj = get_attribute(obj, attr)
|
|
46
|
+
|
|
47
|
+
return obj
|
|
48
|
+
|
|
49
|
+
def setter(value):
|
|
50
|
+
obj = to_value(ref_obj)
|
|
51
|
+
|
|
52
|
+
for attr in attrs[:-1]:
|
|
53
|
+
obj = get_attribute(obj, attr)
|
|
54
|
+
|
|
55
|
+
set_attribute(obj, attrs[-1], value)
|
|
56
|
+
|
|
57
|
+
wrapper = to_ref_wrapper(
|
|
58
|
+
getter,
|
|
59
|
+
setter,
|
|
60
|
+
)
|
|
61
|
+
wrapper._is_readonly = False
|
|
62
|
+
return wrapper
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def vmodel(ref_obj: Union[TRef[Any], Any], *attrs: Union[str, int]) -> Any:
|
|
66
|
+
"""Create a two-way binding on a form input element or a component.
|
|
67
|
+
|
|
68
|
+
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#vmodel
|
|
69
|
+
@中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#vmodel
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
expr (Any): _description_
|
|
73
|
+
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
.. code-block:: python
|
|
77
|
+
from ex4nicegui.reactive import rxui
|
|
78
|
+
from ex4nicegui import deep_ref
|
|
79
|
+
|
|
80
|
+
data = deep_ref({"a": 1, "b": [1, 2, 3, 4]})
|
|
81
|
+
|
|
82
|
+
rxui.label(lambda: f"{data.value=!s}")
|
|
83
|
+
|
|
84
|
+
# No binding effect
|
|
85
|
+
rxui.input(value=data.value["a"])
|
|
86
|
+
|
|
87
|
+
# readonly binding
|
|
88
|
+
rxui.input(value=lambda: data.value["a"])
|
|
89
|
+
|
|
90
|
+
# two-way binding
|
|
91
|
+
rxui.input(value=rxui.vmodel(data.value,'a'))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
if not is_ref(ref_obj):
|
|
97
|
+
result = cast(Any, ref_obj)
|
|
98
|
+
for attr in attrs:
|
|
99
|
+
result = result[attr]
|
|
100
|
+
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
if isinstance(ref_obj, RefWrapper):
|
|
104
|
+
ref_obj._is_readonly = False
|
|
105
|
+
|
|
106
|
+
if attrs:
|
|
107
|
+
wrapper = create_writeable_wrapper(ref_obj, attrs)
|
|
108
|
+
|
|
109
|
+
return cast(
|
|
110
|
+
TRef,
|
|
111
|
+
wrapper,
|
|
112
|
+
)
|
|
113
|
+
else:
|
|
114
|
+
warnings.warn(
|
|
115
|
+
"""Maybe you don't need to use vmodel""",
|
|
116
|
+
stacklevel=2,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return cast(
|
|
120
|
+
TRef,
|
|
121
|
+
ref_obj,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def vmodel_with_index(ref: Ref, index: TMaybeRef[int], *keys: Union[str, int]) -> Ref:
|
|
126
|
+
proxy = ref.value
|
|
127
|
+
|
|
128
|
+
def getter():
|
|
129
|
+
item = proxy[to_value(index)]
|
|
130
|
+
result = item
|
|
131
|
+
|
|
132
|
+
for k in keys:
|
|
133
|
+
result = get_attribute(result, k)
|
|
134
|
+
return result
|
|
135
|
+
|
|
136
|
+
def setter(value):
|
|
137
|
+
item = proxy[to_value(index)]
|
|
138
|
+
|
|
139
|
+
if len(keys) == 1:
|
|
140
|
+
set_attribute(item, keys[0], value)
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
obj = get_attribute(item, keys[0])
|
|
144
|
+
|
|
145
|
+
for k in keys[1:-1]:
|
|
146
|
+
set_attribute(obj, k, get_attribute(obj, k))
|
|
147
|
+
|
|
148
|
+
set_attribute(obj, keys[-1], value)
|
|
149
|
+
|
|
150
|
+
return RefWrapper(getter, setter) # type: ignore
|
ex4nicegui/reactive/base.py
CHANGED
|
@@ -25,7 +25,7 @@ from ex4nicegui.utils.signals import (
|
|
|
25
25
|
)
|
|
26
26
|
from ex4nicegui.utils.clientScope import new_scope
|
|
27
27
|
from ex4nicegui.utils.types import _TMaybeRef as TMaybeRef
|
|
28
|
-
from nicegui import
|
|
28
|
+
from nicegui import ui
|
|
29
29
|
from nicegui.elements.mixins.text_element import TextElement
|
|
30
30
|
from nicegui.elements.mixins.value_element import ValueElement
|
|
31
31
|
from ex4nicegui.reactive.services.reactive_service import inject_handle_delete
|
|
@@ -58,7 +58,6 @@ class BindableUi(Generic[TWidget]):
|
|
|
58
58
|
def __init__(self, element: TWidget) -> None:
|
|
59
59
|
self._element = element
|
|
60
60
|
inject_handle_delete(self.element, self._on_element_delete)
|
|
61
|
-
self.tailwind = Tailwind(cast(ui.element, self._element))
|
|
62
61
|
self._effect_scope = new_scope()
|
|
63
62
|
self.__used_scope_style = False
|
|
64
63
|
|
|
@@ -185,7 +184,7 @@ class BindableUi(Generic[TWidget]):
|
|
|
185
184
|
|
|
186
185
|
def props_str():
|
|
187
186
|
props_dict = (
|
|
188
|
-
f"""{name if isinstance(raw_value,bool) else f"{name}='{raw_value}'"}"""
|
|
187
|
+
f"""{name if isinstance(raw_value, bool) else f"{name}='{raw_value}'"}"""
|
|
189
188
|
for name, value in props.items()
|
|
190
189
|
if (raw_value := to_value(value))
|
|
191
190
|
)
|
|
@@ -15,11 +15,8 @@ class DeferredTask:
|
|
|
15
15
|
task()
|
|
16
16
|
|
|
17
17
|
# Avoid events becoming ineffective due to page refresh when sharing the client.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# note:https://github.com/CrystalWindSnake/ex4nicegui/issues/227
|
|
21
|
-
self._tasks.clear()
|
|
22
|
-
client.connect_handlers.remove(on_client_connect) # type: ignore
|
|
18
|
+
self._tasks.clear()
|
|
19
|
+
client.connect_handlers.remove(on_client_connect) # type: ignore
|
|
23
20
|
|
|
24
21
|
ui.context.client.on_connect(on_client_connect)
|
|
25
22
|
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
from typing import Callable, List, Optional
|
|
2
2
|
from nicegui.elements.mixins.content_element import ContentElement
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
import nicegui
|
|
5
4
|
from dataclasses import dataclass
|
|
6
5
|
from nicegui.events import UiEventArguments
|
|
7
6
|
from nicegui.dataclasses import KWONLY_SLOTS
|
|
8
7
|
|
|
9
|
-
NG_ROOT = Path(nicegui.__file__).parent / "elements"
|
|
10
|
-
|
|
11
8
|
EX4_LIBS_ROOT = Path(__file__).parent.parent.parent / "libs"
|
|
12
9
|
|
|
13
10
|
dependencies = [
|
|
14
|
-
NG_ROOT / "lib/mermaid/mermaid.esm.min.mjs",
|
|
15
11
|
EX4_LIBS_ROOT / "d3/*.js",
|
|
16
|
-
NG_ROOT / "lib/mermaid/*.js",
|
|
17
12
|
]
|
|
18
13
|
|
|
19
14
|
|
|
@@ -24,7 +19,7 @@ class NodeClickEventArguments(UiEventArguments):
|
|
|
24
19
|
|
|
25
20
|
class Mermaid( # type: ignore
|
|
26
21
|
ContentElement,
|
|
27
|
-
component="
|
|
22
|
+
component="ex4ng_mermaid.js",
|
|
28
23
|
dependencies=dependencies, # type: ignore
|
|
29
24
|
):
|
|
30
25
|
CONTENT_PROP = "content"
|
|
@@ -13,11 +13,9 @@ class FlexWrapMixin(Protocol):
|
|
|
13
13
|
_ui_signal_on: Callable[[Callable[..., Any]], signe.Effect[None]]
|
|
14
14
|
|
|
15
15
|
@property
|
|
16
|
-
def element(self) -> ui.element:
|
|
17
|
-
...
|
|
16
|
+
def element(self) -> ui.element: ...
|
|
18
17
|
|
|
19
|
-
def bind_style(self, classes) -> Self:
|
|
20
|
-
...
|
|
18
|
+
def bind_style(self, classes) -> Self: ...
|
|
21
19
|
|
|
22
20
|
def bind_wrap(self, value: TMaybeRef[bool]) -> Self:
|
|
23
21
|
return self.bind_style(
|
|
@@ -35,11 +33,9 @@ class FlexAlignItemsMixin(Protocol):
|
|
|
35
33
|
_ui_signal_on: Callable[[Callable[..., Any]], signe.Effect[None]]
|
|
36
34
|
|
|
37
35
|
@property
|
|
38
|
-
def element(self) -> ui.element:
|
|
39
|
-
...
|
|
36
|
+
def element(self) -> ui.element: ...
|
|
40
37
|
|
|
41
|
-
def bind_classes(self, classes) -> Self:
|
|
42
|
-
...
|
|
38
|
+
def bind_classes(self, classes) -> Self: ...
|
|
43
39
|
|
|
44
40
|
def bind_align_items(self, value: TMaybeRef[str]):
|
|
45
41
|
return self.bind_classes(lambda: f"items-{to_value(value)}")
|
|
@@ -10,8 +10,7 @@ class ValueElementMixin(Protocol, Generic[T]):
|
|
|
10
10
|
_ui_signal_on: Callable[[Callable[..., Any]], signe.Effect[None]]
|
|
11
11
|
|
|
12
12
|
@property
|
|
13
|
-
def element(self) -> ValueElement:
|
|
14
|
-
...
|
|
13
|
+
def element(self) -> ValueElement: ...
|
|
15
14
|
|
|
16
15
|
def bind_value(self, value: TMaybeRef[T]):
|
|
17
16
|
@self._ui_signal_on(value) # type: ignore
|
|
@@ -140,7 +140,7 @@ class EChartsBindableUi(BindableUi[echarts]):
|
|
|
140
140
|
const value = {{
|
|
141
141
|
src: '{src}',
|
|
142
142
|
type: '{type}',
|
|
143
|
-
specialAreas: {json.dumps(special_areas).decode(
|
|
143
|
+
specialAreas: {json.dumps(special_areas).decode("utf-8")}
|
|
144
144
|
}}
|
|
145
145
|
|
|
146
146
|
window.ex4ngEchartsMapTasks.set('{map_name}', value);
|
|
@@ -8,14 +8,12 @@ from typing import (
|
|
|
8
8
|
|
|
9
9
|
@runtime_checkable
|
|
10
10
|
class GetItemProtocol(Protocol):
|
|
11
|
-
def __getitem__(self, key):
|
|
12
|
-
...
|
|
11
|
+
def __getitem__(self, key): ...
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
@runtime_checkable
|
|
16
15
|
class SetItemProtocol(Protocol):
|
|
17
|
-
def __setitem__(self, key, value):
|
|
18
|
-
...
|
|
16
|
+
def __setitem__(self, key, value): ...
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
def get_attribute(obj: Union[object, GetItemProtocol], name: Union[str, int]) -> Any:
|
|
@@ -17,11 +17,9 @@ def _clamp(value, min_v, max_v) -> int:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class _SourceProtocol(Protocol):
|
|
20
|
-
def __len__(self) -> int:
|
|
21
|
-
...
|
|
20
|
+
def __len__(self) -> int: ...
|
|
22
21
|
|
|
23
|
-
def __getitem__(self, __idx: slice) -> Any:
|
|
24
|
-
...
|
|
22
|
+
def __getitem__(self, __idx: slice) -> Any: ...
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
class PaginationRef:
|
ex4nicegui/reactive/vfor.py
CHANGED
ex4nicegui/utils/apiEffect.py
CHANGED
ex4nicegui/utils/clientScope.py
CHANGED
|
@@ -34,14 +34,11 @@ class NgClientScopeManager:
|
|
|
34
34
|
if client.id not in self._client_scope_map:
|
|
35
35
|
self._client_scope_map[client.id] = NgScopeSuite()
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if e.id in self._client_scope_map:
|
|
43
|
-
self._client_scope_map[e.id]._top_scope.dispose() # type: ignore
|
|
44
|
-
del self._client_scope_map[e.id]
|
|
37
|
+
@client.on_disconnect
|
|
38
|
+
def _(e: Client):
|
|
39
|
+
if e.id in self._client_scope_map:
|
|
40
|
+
self._client_scope_map[e.id]._top_scope.dispose() # type: ignore
|
|
41
|
+
del self._client_scope_map[e.id]
|
|
45
42
|
|
|
46
43
|
return self._client_scope_map[client.id]
|
|
47
44
|
|
ex4nicegui/utils/effect.py
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from typing import ClassVar
|
|
2
|
+
from typing_extensions import Self
|
|
3
|
+
from contextvars import ContextVar
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PageState:
|
|
7
|
+
"""
|
|
8
|
+
A base class for defining per-page reactive state containers.
|
|
9
|
+
|
|
10
|
+
Each subclass of `PageState` provides an isolated state context that is automatically
|
|
11
|
+
managed through a `ContextVar`. When used inside different `ui.page` definitions,
|
|
12
|
+
each page will maintain its own independent instance of the subclass, ensuring
|
|
13
|
+
states do not interfere across pages.
|
|
14
|
+
|
|
15
|
+
Subclasses should define reactive variables (e.g., created via `to_ref`) within
|
|
16
|
+
their `__init__` method. The instance can then be accessed anywhere in the same
|
|
17
|
+
page context using `MyState.get()` — without needing to pass it through function parameters.
|
|
18
|
+
|
|
19
|
+
Typical use cases include sharing state across multiple components or functions
|
|
20
|
+
within the same page.
|
|
21
|
+
|
|
22
|
+
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#PageState
|
|
23
|
+
@中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#PageState
|
|
24
|
+
|
|
25
|
+
# Example:
|
|
26
|
+
.. code-block:: python
|
|
27
|
+
from ex4nicegui import rxui, to_ref, PageState
|
|
28
|
+
from nicegui import ui
|
|
29
|
+
|
|
30
|
+
class MyState(PageState):
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self.a = to_ref(1.0)
|
|
33
|
+
|
|
34
|
+
def sub_view():
|
|
35
|
+
state = MyState.get()
|
|
36
|
+
rxui.label(lambda: f"{state.a.value=}")
|
|
37
|
+
|
|
38
|
+
@ui.page('/')
|
|
39
|
+
def _():
|
|
40
|
+
state = MyState.get()
|
|
41
|
+
rxui.number(value=state.a)
|
|
42
|
+
sub_view()
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
_ctx: ClassVar[ContextVar["PageState"]]
|
|
46
|
+
|
|
47
|
+
def __init_subclass__(cls, **kwargs):
|
|
48
|
+
super().__init_subclass__(**kwargs)
|
|
49
|
+
cls._ctx = ContextVar(f"{cls.__name__}_ctx")
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def get(cls) -> Self:
|
|
53
|
+
"""
|
|
54
|
+
Retrieves the current instance of the page state for this subclass.
|
|
55
|
+
|
|
56
|
+
If no instance exists yet in the current context, a new one is created
|
|
57
|
+
and stored. Subsequent calls within the same page will return the same instance.
|
|
58
|
+
|
|
59
|
+
This method allows components and functions within the same page
|
|
60
|
+
to share reactive state seamlessly without passing references explicitly.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Self: The current `PageState` subclass instance associated with this page.
|
|
64
|
+
"""
|
|
65
|
+
inst = cls._ctx.get(None)
|
|
66
|
+
|
|
67
|
+
if inst is None:
|
|
68
|
+
inst = cls()
|
|
69
|
+
cls._ctx.set(inst)
|
|
70
|
+
return inst # type: ignore
|
ex4nicegui/utils/refComputed.py
CHANGED
|
@@ -64,8 +64,7 @@ def ref_computed(
|
|
|
64
64
|
debug_trigger: Optional[Callable[..., None]] = None,
|
|
65
65
|
priority_level: int = 1,
|
|
66
66
|
debug_name: Optional[str] = None,
|
|
67
|
-
) -> Callable[[Callable[..., T]], ReadonlyRef[T]]:
|
|
68
|
-
...
|
|
67
|
+
) -> Callable[[Callable[..., T]], ReadonlyRef[T]]: ...
|
|
69
68
|
|
|
70
69
|
|
|
71
70
|
def ref_computed(
|