ex4nicegui 0.8.1__py3-none-any.whl → 0.8.3__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/reactive/EChartsComponent/ECharts.js +9 -1
- ex4nicegui/reactive/EChartsComponent/ECharts.py +4 -5
- ex4nicegui/reactive/base.py +2 -2
- ex4nicegui/reactive/officials/echarts.py +15 -1
- ex4nicegui/reactive/officials/radio.py +1 -0
- ex4nicegui/reactive/officials/select.py +1 -0
- ex4nicegui/reactive/officials/tab_panel.py +52 -1
- ex4nicegui/reactive/officials/tab_panels.py +20 -54
- ex4nicegui/reactive/officials/toggle.py +1 -0
- ex4nicegui/reactive/services/reactive_service.py +23 -1
- ex4nicegui/utils/proxy/string.py +14 -24
- {ex4nicegui-0.8.1.dist-info → ex4nicegui-0.8.3.dist-info}/METADATA +72 -1
- {ex4nicegui-0.8.1.dist-info → ex4nicegui-0.8.3.dist-info}/RECORD +15 -15
- {ex4nicegui-0.8.1.dist-info → ex4nicegui-0.8.3.dist-info}/LICENSE +0 -0
- {ex4nicegui-0.8.1.dist-info → ex4nicegui-0.8.3.dist-info}/WHEEL +0 -0
|
@@ -56,7 +56,8 @@ export default {
|
|
|
56
56
|
template: "<div></div>",
|
|
57
57
|
async mounted() {
|
|
58
58
|
await new Promise((resolve) => setTimeout(resolve, 0)); // wait for Tailwind classes to be applied
|
|
59
|
-
|
|
59
|
+
|
|
60
|
+
this.chart = echarts.init(this.$el, this.theme, this.initOptions);
|
|
60
61
|
this.resizeObs = new ResizeObserver(this.chart.resize)
|
|
61
62
|
|
|
62
63
|
// Prevent interruption of chart animations due to resize operations.
|
|
@@ -84,6 +85,11 @@ export default {
|
|
|
84
85
|
}
|
|
85
86
|
});
|
|
86
87
|
|
|
88
|
+
if (this.eventTasks) {
|
|
89
|
+
for (const [eventName, query] of Object.entries(this.eventTasks)) {
|
|
90
|
+
this.echarts_on(eventName, query);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
87
93
|
},
|
|
88
94
|
beforeDestroy() {
|
|
89
95
|
this.chart.dispose();
|
|
@@ -116,6 +122,8 @@ export default {
|
|
|
116
122
|
props: {
|
|
117
123
|
options: Object | undefined,
|
|
118
124
|
theme: String | Object | undefined,
|
|
125
|
+
initOptions: Object | undefined,
|
|
119
126
|
code: String | undefined,
|
|
127
|
+
eventTasks: Object | undefined,
|
|
120
128
|
},
|
|
121
129
|
};
|
|
@@ -16,7 +16,6 @@ import nicegui
|
|
|
16
16
|
from .types import (
|
|
17
17
|
_T_event_name,
|
|
18
18
|
)
|
|
19
|
-
from ex4nicegui.reactive.deferredTask import DeferredTask
|
|
20
19
|
from .utils import get_bound_event_args, create_event_handler_args
|
|
21
20
|
|
|
22
21
|
NG_ROOT = Path(nicegui.__file__).parent / "elements"
|
|
@@ -28,9 +27,9 @@ class echarts(Element, component="ECharts.js", dependencies=libraries): # type:
|
|
|
28
27
|
self,
|
|
29
28
|
options: Optional[dict] = None,
|
|
30
29
|
code: Optional[str] = None,
|
|
30
|
+
init_options: Optional[dict] = None,
|
|
31
31
|
) -> None:
|
|
32
32
|
super().__init__()
|
|
33
|
-
self.__deferred_task = DeferredTask()
|
|
34
33
|
|
|
35
34
|
if (options is None) and (bool(code) is False):
|
|
36
35
|
raise ValueError("At least one of options and code must be valid.")
|
|
@@ -45,6 +44,8 @@ class echarts(Element, component="ECharts.js", dependencies=libraries): # type:
|
|
|
45
44
|
|
|
46
45
|
self._props["options"] = options
|
|
47
46
|
self._props["code"] = code
|
|
47
|
+
self._props["initOptions"] = init_options
|
|
48
|
+
self._props["eventTasks"] = {}
|
|
48
49
|
|
|
49
50
|
def update_chart(
|
|
50
51
|
self,
|
|
@@ -107,9 +108,7 @@ class echarts(Element, component="ECharts.js", dependencies=libraries): # type:
|
|
|
107
108
|
ui_event_name = f"chart:{event_name}"
|
|
108
109
|
super().on(ui_event_name, org_handler, args=get_bound_event_args(event_name))
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
def _():
|
|
112
|
-
self.run_method("echarts_on", ui_event_name, query)
|
|
111
|
+
self._props["eventTasks"][ui_event_name] = query
|
|
113
112
|
|
|
114
113
|
def run_chart_method(
|
|
115
114
|
self, name: str, *args, timeout: float = 1
|
ex4nicegui/reactive/base.py
CHANGED
|
@@ -48,7 +48,7 @@ _T_bind_classes_type = Union[
|
|
|
48
48
|
_T_bind_classes_type_ref_dict,
|
|
49
49
|
_T_bind_classes_type_single,
|
|
50
50
|
_T_bind_classes_type_array,
|
|
51
|
-
Dict[str, bool],
|
|
51
|
+
Dict[str, TMaybeRef[bool]],
|
|
52
52
|
List[str],
|
|
53
53
|
]
|
|
54
54
|
|
|
@@ -271,7 +271,7 @@ class BindableUi(Generic[TWidget]):
|
|
|
271
271
|
def bind_classes(self, classes: Dict[str, TGetterOrReadonlyRef[bool]]) -> Self: ...
|
|
272
272
|
|
|
273
273
|
@overload
|
|
274
|
-
def bind_classes(self, classes: Dict[str, bool]) -> Self: ...
|
|
274
|
+
def bind_classes(self, classes: Dict[str, TMaybeRef[bool]]) -> Self: ...
|
|
275
275
|
|
|
276
276
|
@overload
|
|
277
277
|
def bind_classes(self, classes: TGetterOrReadonlyRef[Dict[str, bool]]) -> Self: ...
|
|
@@ -27,9 +27,23 @@ class EChartsBindableUi(BindableUi[echarts]):
|
|
|
27
27
|
options: Optional[TMaybeRef[Dict]] = None,
|
|
28
28
|
not_merge: TMaybeRef[Union[bool, None]] = None,
|
|
29
29
|
code: Optional[str] = None,
|
|
30
|
+
init_options: Optional[Dict] = None,
|
|
30
31
|
) -> None:
|
|
32
|
+
"""Create a new ECharts instance.
|
|
33
|
+
|
|
34
|
+
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#rxuiecharts
|
|
35
|
+
@中文文档 - https://gitee.com/carson_add/ex4nicegui#rxuiecharts
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
options (Optional[TMaybeRef[Dict]], optional): echart options. Defaults to None.
|
|
39
|
+
not_merge (TMaybeRef[Union[bool, None]], optional): merge options when chart update. Defaults to None.
|
|
40
|
+
code (Optional[str], optional): javascript code to initialize echart. Defaults to None.
|
|
41
|
+
init_options (Optional[Dict], optional): echart initialization options. Defaults to None.
|
|
42
|
+
"""
|
|
31
43
|
pc = ParameterClassifier(
|
|
32
|
-
locals(),
|
|
44
|
+
locals(),
|
|
45
|
+
maybeRefs=["options", "code", "init_options"],
|
|
46
|
+
exclude=["not_merge"],
|
|
33
47
|
)
|
|
34
48
|
|
|
35
49
|
value_kws = pc.get_values_kws()
|
|
@@ -62,6 +62,7 @@ class RadioBindableUi(BindableUi[ui.radio], ValueElementMixin[Any]):
|
|
|
62
62
|
def bind_options(self, options: TGetterOrReadonlyRef):
|
|
63
63
|
@self._ui_signal_on(options, deep=True)
|
|
64
64
|
def _():
|
|
65
|
+
ParameterClassifier.mark_event_source_as_internal(self.element)
|
|
65
66
|
self.element.set_options(to_value(options))
|
|
66
67
|
|
|
67
68
|
return self
|
|
@@ -93,6 +93,7 @@ class SelectBindableUi(BindableUi[ui.select]):
|
|
|
93
93
|
def bind_value(self, value: TGetterOrReadonlyRef):
|
|
94
94
|
@self._ui_signal_on(value, deep=True)
|
|
95
95
|
def _():
|
|
96
|
+
ParameterClassifier.mark_event_source_as_internal(self.element)
|
|
96
97
|
cast(ValueElement, self.element).set_value(to_raw(to_value(value)) or None)
|
|
97
98
|
|
|
98
99
|
return self
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import Awaitable, Callable, Union
|
|
1
3
|
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
2
4
|
from ex4nicegui.utils.signals import (
|
|
3
5
|
_TMaybeRef as TMaybeRef,
|
|
4
6
|
)
|
|
5
|
-
from nicegui import ui
|
|
7
|
+
from nicegui import ui, background_tasks, core
|
|
6
8
|
from .base import BindableUi
|
|
7
9
|
|
|
8
10
|
|
|
@@ -21,3 +23,52 @@ class TabPanelBindableUi(BindableUi[ui.tab_panel]):
|
|
|
21
23
|
|
|
22
24
|
for key, value in pc.get_bindings().items():
|
|
23
25
|
self.bind_prop(key, value) # type: ignore
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class lazy_tab_panel(TabPanelBindableUi):
|
|
29
|
+
def __init__(self, name: str) -> None:
|
|
30
|
+
super().__init__(name)
|
|
31
|
+
self._build_fn = None
|
|
32
|
+
|
|
33
|
+
def try_run_build_fn(self):
|
|
34
|
+
if self._build_fn:
|
|
35
|
+
_helper.run_build_fn(self, self.element._props["name"])
|
|
36
|
+
self._build_fn = None
|
|
37
|
+
|
|
38
|
+
def build_fn(self, fn: Callable[..., Union[None, Awaitable]]):
|
|
39
|
+
self._build_fn = fn
|
|
40
|
+
return fn
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _helper:
|
|
44
|
+
@staticmethod
|
|
45
|
+
def run_build_fn(panel: lazy_tab_panel, name: str) -> None:
|
|
46
|
+
""" """
|
|
47
|
+
fn = panel._build_fn
|
|
48
|
+
if fn is None:
|
|
49
|
+
return
|
|
50
|
+
try:
|
|
51
|
+
expects_arguments = any(
|
|
52
|
+
p.default is inspect.Parameter.empty
|
|
53
|
+
and p.kind is not inspect.Parameter.VAR_POSITIONAL
|
|
54
|
+
and p.kind is not inspect.Parameter.VAR_KEYWORD
|
|
55
|
+
for p in inspect.signature(fn).parameters.values()
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
with panel:
|
|
59
|
+
result = fn(name) if expects_arguments else fn()
|
|
60
|
+
if isinstance(result, Awaitable):
|
|
61
|
+
# NOTE: await an awaitable result even if the handler is not a coroutine (like a lambda statement)
|
|
62
|
+
async def wait_for_result():
|
|
63
|
+
with panel:
|
|
64
|
+
try:
|
|
65
|
+
await result
|
|
66
|
+
except Exception as e:
|
|
67
|
+
core.app.handle_exception(e)
|
|
68
|
+
|
|
69
|
+
if core.loop and core.loop.is_running():
|
|
70
|
+
background_tasks.create(wait_for_result(), name=str(fn))
|
|
71
|
+
else:
|
|
72
|
+
core.app.on_startup(wait_for_result())
|
|
73
|
+
except Exception as e:
|
|
74
|
+
core.app.handle_exception(e)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import inspect
|
|
2
1
|
from typing import Any, Awaitable, Callable, Optional, Union
|
|
3
2
|
from weakref import WeakValueDictionary
|
|
4
3
|
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
@@ -8,9 +7,10 @@ from ex4nicegui.utils.signals import (
|
|
|
8
7
|
_TMaybeRef as TMaybeRef,
|
|
9
8
|
)
|
|
10
9
|
from ex4nicegui.utils.scheduler import next_tick
|
|
11
|
-
from nicegui import ui
|
|
10
|
+
from nicegui import ui
|
|
12
11
|
from .base import BindableUi
|
|
13
12
|
from ex4nicegui.reactive.mixins.value_element import ValueElementMixin
|
|
13
|
+
from .tab_panel import lazy_tab_panel
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class TabPanelsBindableUi(BindableUi[ui.tab_panels], ValueElementMixin[bool]):
|
|
@@ -57,21 +57,6 @@ class TabPanelsBindableUi(BindableUi[ui.tab_panels], ValueElementMixin[bool]):
|
|
|
57
57
|
return super().bind_prop(prop, value)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
class lazy_tab_panel(ui.tab_panel):
|
|
61
|
-
def __init__(self, name: str) -> None:
|
|
62
|
-
super().__init__(name)
|
|
63
|
-
self._build_fn = None
|
|
64
|
-
|
|
65
|
-
def try_run_build_fn(self):
|
|
66
|
-
if self._build_fn:
|
|
67
|
-
_helper.run_build_fn(self, self._props["name"])
|
|
68
|
-
self._build_fn = None
|
|
69
|
-
|
|
70
|
-
def build_fn(self, fn: Callable[..., Union[None, Awaitable]]):
|
|
71
|
-
self._build_fn = fn
|
|
72
|
-
return fn
|
|
73
|
-
|
|
74
|
-
|
|
75
60
|
class LazyTabPanelsBindableUi(TabPanelsBindableUi):
|
|
76
61
|
def __init__(
|
|
77
62
|
self,
|
|
@@ -96,26 +81,32 @@ class LazyTabPanelsBindableUi(TabPanelsBindableUi):
|
|
|
96
81
|
value, on_change=on_change, animated=animated, keep_alive=keep_alive
|
|
97
82
|
)
|
|
98
83
|
|
|
99
|
-
self.
|
|
84
|
+
self._panels: WeakValueDictionary[str, lazy_tab_panel] = WeakValueDictionary()
|
|
100
85
|
|
|
101
86
|
if value:
|
|
102
87
|
|
|
103
88
|
@self._ui_effect
|
|
104
89
|
def _():
|
|
105
90
|
current_value = to_value(value)
|
|
106
|
-
if current_value in self.
|
|
107
|
-
panel = self.
|
|
91
|
+
if current_value in self._panels:
|
|
92
|
+
panel = self._panels[current_value]
|
|
108
93
|
|
|
109
94
|
@next_tick
|
|
110
95
|
def _():
|
|
111
96
|
panel.try_run_build_fn()
|
|
112
97
|
|
|
113
98
|
def add_tab_panel(self, name: str):
|
|
99
|
+
"""Add a tab panel.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
name (str): The name of the tab panel.
|
|
103
|
+
"""
|
|
104
|
+
|
|
114
105
|
def decorator(fn: Callable[..., Union[None, Awaitable]]):
|
|
115
106
|
with self:
|
|
116
107
|
panel = lazy_tab_panel(name)
|
|
117
|
-
str_name = panel._props["name"]
|
|
118
|
-
self.
|
|
108
|
+
str_name = panel.element._props["name"]
|
|
109
|
+
self._panels[str_name] = panel
|
|
119
110
|
panel.build_fn(fn)
|
|
120
111
|
|
|
121
112
|
if self.value == name:
|
|
@@ -125,36 +116,11 @@ class LazyTabPanelsBindableUi(TabPanelsBindableUi):
|
|
|
125
116
|
|
|
126
117
|
return decorator
|
|
127
118
|
|
|
119
|
+
def get_panel(self, name: str) -> lazy_tab_panel:
|
|
120
|
+
"""Get a tab panel by name.
|
|
128
121
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
"""
|
|
133
|
-
|
|
134
|
-
if fn is None:
|
|
135
|
-
return
|
|
136
|
-
try:
|
|
137
|
-
expects_arguments = any(
|
|
138
|
-
p.default is inspect.Parameter.empty
|
|
139
|
-
and p.kind is not inspect.Parameter.VAR_POSITIONAL
|
|
140
|
-
and p.kind is not inspect.Parameter.VAR_KEYWORD
|
|
141
|
-
for p in inspect.signature(fn).parameters.values()
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
with panel:
|
|
145
|
-
result = fn(name) if expects_arguments else fn()
|
|
146
|
-
if isinstance(result, Awaitable):
|
|
147
|
-
# NOTE: await an awaitable result even if the handler is not a coroutine (like a lambda statement)
|
|
148
|
-
async def wait_for_result():
|
|
149
|
-
with panel:
|
|
150
|
-
try:
|
|
151
|
-
await result
|
|
152
|
-
except Exception as e:
|
|
153
|
-
core.app.handle_exception(e)
|
|
154
|
-
|
|
155
|
-
if core.loop and core.loop.is_running():
|
|
156
|
-
background_tasks.create(wait_for_result(), name=str(fn))
|
|
157
|
-
else:
|
|
158
|
-
core.app.on_startup(wait_for_result())
|
|
159
|
-
except Exception as e:
|
|
160
|
-
core.app.handle_exception(e)
|
|
122
|
+
Args:
|
|
123
|
+
name (str): The name of the tab panel.
|
|
124
|
+
|
|
125
|
+
"""
|
|
126
|
+
return self._panels[name]
|
|
@@ -83,6 +83,7 @@ class ToggleBindableUi(BindableUi[ui.toggle]):
|
|
|
83
83
|
def bind_value(self, value: TGetterOrReadonlyRef):
|
|
84
84
|
@self._ui_signal_on(value, deep=True)
|
|
85
85
|
def _():
|
|
86
|
+
ParameterClassifier.mark_event_source_as_internal(self.element)
|
|
86
87
|
self.element.set_value(to_raw(to_value(value)) or None)
|
|
87
88
|
|
|
88
89
|
return self
|
|
@@ -18,6 +18,9 @@ from ex4nicegui.reactive.systems.reactive_system import (
|
|
|
18
18
|
from ex4nicegui.utils.proxy import is_base_type_proxy
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
_EVENT_SOURCE_INTERNAL_FLAG = "__ex4ng_set_value_from_signal_"
|
|
22
|
+
|
|
23
|
+
|
|
21
24
|
class ParameterClassifier:
|
|
22
25
|
def __init__(
|
|
23
26
|
self,
|
|
@@ -71,7 +74,14 @@ class ParameterClassifier:
|
|
|
71
74
|
if is_setter_ref(model_value):
|
|
72
75
|
|
|
73
76
|
def inject_on_change(e):
|
|
74
|
-
|
|
77
|
+
change_from_inner_signal = (
|
|
78
|
+
ParameterClassifier.get_event_source_internal_flag(e.sender)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if not change_from_inner_signal:
|
|
82
|
+
model_value.value = self.v_model_arg_getter(e) # type: ignore
|
|
83
|
+
|
|
84
|
+
ParameterClassifier.remove_event_source_internal_flag(e.sender)
|
|
75
85
|
handle_event(event, e)
|
|
76
86
|
|
|
77
87
|
value_kws.update({event_name: inject_on_change})
|
|
@@ -85,6 +95,18 @@ class ParameterClassifier:
|
|
|
85
95
|
if (k in self.maybeRefs and (is_ref(v) or isinstance(v, Callable)))
|
|
86
96
|
}
|
|
87
97
|
|
|
98
|
+
@staticmethod
|
|
99
|
+
def mark_event_source_as_internal(element: ui.element):
|
|
100
|
+
element.__dict__[_EVENT_SOURCE_INTERNAL_FLAG] = True
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def get_event_source_internal_flag(element: ui.element):
|
|
104
|
+
return element.__dict__.get(_EVENT_SOURCE_INTERNAL_FLAG, False)
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def remove_event_source_internal_flag(element: ui.element):
|
|
108
|
+
element.__dict__.pop(_EVENT_SOURCE_INTERNAL_FLAG, None)
|
|
109
|
+
|
|
88
110
|
|
|
89
111
|
def inject_handle_delete(element: ui.element, on_delete: Callable[[], None]):
|
|
90
112
|
inject_method(element, "_handle_delete", on_delete)
|
ex4nicegui/utils/proxy/string.py
CHANGED
|
@@ -58,8 +58,8 @@ class StringProxy(Proxy, str):
|
|
|
58
58
|
def count(
|
|
59
59
|
self,
|
|
60
60
|
sub: str,
|
|
61
|
-
start: Optional[SupportsIndex] =
|
|
62
|
-
end: Optional[SupportsIndex] =
|
|
61
|
+
start: Optional[SupportsIndex] = None,
|
|
62
|
+
end: Optional[SupportsIndex] = None,
|
|
63
63
|
/,
|
|
64
64
|
) -> int:
|
|
65
65
|
return self._ref.value.count(sub, start, end)
|
|
@@ -70,8 +70,8 @@ class StringProxy(Proxy, str):
|
|
|
70
70
|
def endswith(
|
|
71
71
|
self,
|
|
72
72
|
suffix: Union[str, Tuple[str, ...]],
|
|
73
|
-
start: Optional[SupportsIndex] =
|
|
74
|
-
end: Optional[SupportsIndex] =
|
|
73
|
+
start: Optional[SupportsIndex] = None,
|
|
74
|
+
end: Optional[SupportsIndex] = None,
|
|
75
75
|
/,
|
|
76
76
|
) -> bool:
|
|
77
77
|
return self._ref.value.endswith(suffix, start, end)
|
|
@@ -88,8 +88,8 @@ class StringProxy(Proxy, str):
|
|
|
88
88
|
def find(
|
|
89
89
|
self,
|
|
90
90
|
sub: str,
|
|
91
|
-
start: Optional[SupportsIndex] =
|
|
92
|
-
end: Optional[SupportsIndex] =
|
|
91
|
+
start: Optional[SupportsIndex] = None,
|
|
92
|
+
end: Optional[SupportsIndex] = None,
|
|
93
93
|
/,
|
|
94
94
|
) -> int:
|
|
95
95
|
return self._ref.value.find(sub, start, end)
|
|
@@ -109,8 +109,8 @@ class StringProxy(Proxy, str):
|
|
|
109
109
|
def index(
|
|
110
110
|
self,
|
|
111
111
|
sub: str,
|
|
112
|
-
start: Optional[SupportsIndex] =
|
|
113
|
-
end: Optional[SupportsIndex] =
|
|
112
|
+
start: Optional[SupportsIndex] = None,
|
|
113
|
+
end: Optional[SupportsIndex] = None,
|
|
114
114
|
/,
|
|
115
115
|
) -> int:
|
|
116
116
|
return self._ref.value.index(sub, start, end)
|
|
@@ -230,8 +230,8 @@ class StringProxy(Proxy, str):
|
|
|
230
230
|
def rfind(
|
|
231
231
|
self,
|
|
232
232
|
sub: str,
|
|
233
|
-
start: Optional[SupportsIndex] =
|
|
234
|
-
end: Optional[SupportsIndex] =
|
|
233
|
+
start: Optional[SupportsIndex] = None,
|
|
234
|
+
end: Optional[SupportsIndex] = None,
|
|
235
235
|
/,
|
|
236
236
|
) -> int:
|
|
237
237
|
return self._ref.value.rfind(sub, start, end)
|
|
@@ -239,8 +239,8 @@ class StringProxy(Proxy, str):
|
|
|
239
239
|
def rindex(
|
|
240
240
|
self,
|
|
241
241
|
sub: str,
|
|
242
|
-
start: Optional[SupportsIndex] =
|
|
243
|
-
end: Optional[SupportsIndex] =
|
|
242
|
+
start: Optional[SupportsIndex] = None,
|
|
243
|
+
end: Optional[SupportsIndex] = None,
|
|
244
244
|
/,
|
|
245
245
|
) -> int:
|
|
246
246
|
return self._ref.value.rindex(sub, start, end)
|
|
@@ -263,16 +263,6 @@ class StringProxy(Proxy, str):
|
|
|
263
263
|
def rpartition(self, sep: str, /) -> Tuple[str, str, str]:
|
|
264
264
|
return self._ref.value.rpartition(sep)
|
|
265
265
|
|
|
266
|
-
@overload
|
|
267
|
-
def rsplit(
|
|
268
|
-
self: LiteralString,
|
|
269
|
-
sep: Optional[LiteralString] = None,
|
|
270
|
-
maxsplit: SupportsIndex = -1,
|
|
271
|
-
) -> List[LiteralString]: ...
|
|
272
|
-
@overload
|
|
273
|
-
def rsplit(
|
|
274
|
-
self, sep: Optional[str] = None, maxsplit: SupportsIndex = -1
|
|
275
|
-
) -> List[str]: ... # type: ignore[misc]
|
|
276
266
|
def rsplit(
|
|
277
267
|
self, sep: Optional[str] = None, maxsplit: SupportsIndex = -1
|
|
278
268
|
) -> List[str]:
|
|
@@ -312,8 +302,8 @@ class StringProxy(Proxy, str):
|
|
|
312
302
|
def startswith(
|
|
313
303
|
self,
|
|
314
304
|
prefix: Union[str, Tuple[str, ...]],
|
|
315
|
-
start: Optional[SupportsIndex] =
|
|
316
|
-
end: Optional[SupportsIndex] =
|
|
305
|
+
start: Optional[SupportsIndex] = None,
|
|
306
|
+
end: Optional[SupportsIndex] = None,
|
|
317
307
|
/,
|
|
318
308
|
) -> bool:
|
|
319
309
|
return self._ref.value.startswith(prefix, start, end)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ex4nicegui
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: Extension library based on nicegui, providing data responsive,BI functionality modules
|
|
5
5
|
Home-page: https://github.com/CrystalWindSnake/ex4nicegui
|
|
6
6
|
License: MIT
|
|
@@ -358,6 +358,71 @@ def _():
|
|
|
358
358
|
|
|
359
359
|
> 建议总是通过 `.on` 指定依赖关系,避免预料之外的刷新
|
|
360
360
|
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
### 数据持久化
|
|
364
|
+
|
|
365
|
+
`ViewModel` 使用代理对象创建响应式数据,当需要保存数据时,可以使用 `rxui.ViewModel.to_value` 转换成普通数据.
|
|
366
|
+
|
|
367
|
+
下面的例子,点击按钮将显示 my_app 的状态数据字典。
|
|
368
|
+
```python
|
|
369
|
+
from nicegui import ui
|
|
370
|
+
from ex4nicegui import rxui
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
class MyApp(rxui.ViewModel):
|
|
374
|
+
a = 0
|
|
375
|
+
sign = "+"
|
|
376
|
+
b = 0
|
|
377
|
+
|
|
378
|
+
def show_data(self):
|
|
379
|
+
# >> {"a": 0, "sign": '+, "b": 0}
|
|
380
|
+
return rxui.ViewModel.to_value(self)
|
|
381
|
+
|
|
382
|
+
def show_a(self):
|
|
383
|
+
# >> 0
|
|
384
|
+
return rxui.ViewModel.to_value(self.a)
|
|
385
|
+
|
|
386
|
+
my_app = MyApp()
|
|
387
|
+
|
|
388
|
+
rxui.number(value=my_app.a, min=0, max=10)
|
|
389
|
+
rxui.radio(["+", "-", "*", "/"], value=my_app.sign)
|
|
390
|
+
rxui.number(value=my_app.b, min=0, max=10)
|
|
391
|
+
|
|
392
|
+
ui.button("show data", on_click=lambda: ui.notify(my_app.show_data()))
|
|
393
|
+
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
结合 `rxui.ViewModel.on_refs_changed` ,可以在数据变化时,自动保存数据到本地。
|
|
397
|
+
|
|
398
|
+
```python
|
|
399
|
+
from nicegui import ui
|
|
400
|
+
from ex4nicegui import rxui
|
|
401
|
+
from pathlib import Path
|
|
402
|
+
import json
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class MyApp(rxui.ViewModel):
|
|
406
|
+
a = 0
|
|
407
|
+
sign = "+"
|
|
408
|
+
b = 0
|
|
409
|
+
|
|
410
|
+
_json_path = Path(__file__).parent / "data.json"
|
|
411
|
+
|
|
412
|
+
def __init__(self):
|
|
413
|
+
super().__init__()
|
|
414
|
+
|
|
415
|
+
@rxui.ViewModel.on_refs_changed(self)
|
|
416
|
+
def _():
|
|
417
|
+
# a, sign, b 任意一个值变化时,自动保存到本地
|
|
418
|
+
self._json_path.write_text(json.dumps(self.show_data()))
|
|
419
|
+
|
|
420
|
+
def show_data(self):
|
|
421
|
+
return rxui.ViewModel.to_value(self)
|
|
422
|
+
...
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
|
|
361
426
|
|
|
362
427
|
---
|
|
363
428
|
|
|
@@ -371,6 +436,7 @@ def _():
|
|
|
371
436
|
- [二次计算缓存](#二次计算缓存)
|
|
372
437
|
- [列表](#列表)
|
|
373
438
|
- [列表循环](#列表循环)
|
|
439
|
+
- [数据持久化](#数据持久化)
|
|
374
440
|
- [apis](#apis)
|
|
375
441
|
- [ViewModel](#viewmodel)
|
|
376
442
|
- [使用列表](#使用列表)
|
|
@@ -1339,11 +1405,16 @@ with rxui.lazy_tab_panels(current_tab) as panels:
|
|
|
1339
1405
|
|
|
1340
1406
|
@panels.add_tab_panel("t1")
|
|
1341
1407
|
def _():
|
|
1408
|
+
# 通过 `panels.get_panel` 获取当前激活的 panel 组件
|
|
1409
|
+
panels.get_panel("t1").classes("bg-green")
|
|
1342
1410
|
ui.notify("Hello from t1")
|
|
1411
|
+
ui.label("This is t1")
|
|
1343
1412
|
|
|
1344
1413
|
@panels.add_tab_panel("t2")
|
|
1345
1414
|
def _():
|
|
1415
|
+
panels.get_panel("t2").style("background-color : red")
|
|
1346
1416
|
ui.notify("Hello from t2")
|
|
1417
|
+
ui.label("This is t2")
|
|
1347
1418
|
|
|
1348
1419
|
```
|
|
1349
1420
|
|
|
@@ -71,12 +71,12 @@ ex4nicegui/libs/gsap/utils/matrix.js,sha256=77scrxbQZXx4ex5HkvnT9IkhMG1rQoDNp4TS
|
|
|
71
71
|
ex4nicegui/libs/gsap/utils/paths.js,sha256=2SPaRHQ7zgba9cH8hGhkTYPCZdrrEhE2qhh6ECAEvSA,49314
|
|
72
72
|
ex4nicegui/libs/gsap/utils/strings.js,sha256=47G9slz5ltG9mDSwrfQDtWzzdV5QJ-AIMLRMNK0VSiM,10472
|
|
73
73
|
ex4nicegui/reactive/__init__.py,sha256=_VDZ79Gp9lo2NlaKKKT6rvrMWVNkUzTBHQnn0e6Q8Gk,4374
|
|
74
|
-
ex4nicegui/reactive/base.py,sha256=
|
|
74
|
+
ex4nicegui/reactive/base.py,sha256=aaNgolaDQMuMy_c2XCAtdRpOSXsn2engdJZoWqj9WU8,15926
|
|
75
75
|
ex4nicegui/reactive/deferredTask.py,sha256=g78TTG1EIkBxjPih01xmrCZw9OxQG93veSVSELWKfcU,987
|
|
76
76
|
ex4nicegui/reactive/dropZone/dropZone.js,sha256=7rSpFJX-Fk_W_NGZhOTyuEw0bzR-YUc8ZYPzQG9KzE0,2713
|
|
77
77
|
ex4nicegui/reactive/dropZone/dropZone.py,sha256=hg9UKTayff8v8Ek-n38h_3wX1Qmiotvdyv1Hsqilh5Y,2590
|
|
78
|
-
ex4nicegui/reactive/EChartsComponent/ECharts.js,sha256=
|
|
79
|
-
ex4nicegui/reactive/EChartsComponent/ECharts.py,sha256=
|
|
78
|
+
ex4nicegui/reactive/EChartsComponent/ECharts.js,sha256=K9sX34SMnghwDMCkl-IA7WsntxyryeRsboihkIwDb84,3852
|
|
79
|
+
ex4nicegui/reactive/EChartsComponent/ECharts.py,sha256=jLRdKqJWCtKHzNlFAX9ePAmzP1WSXRzBQAO0KHHkfBA,4258
|
|
80
80
|
ex4nicegui/reactive/EChartsComponent/events.py,sha256=_BtmLRcAIZciDQT5i1eFc-r3e0pBnAabW1BSl6uzhCc,570
|
|
81
81
|
ex4nicegui/reactive/EChartsComponent/types.py,sha256=_7AekG0IyzRpDEBZMtKRiZ3o3dUCcn6btegBk8c9Fig,1001
|
|
82
82
|
ex4nicegui/reactive/EChartsComponent/utils.py,sha256=a5r2fghC6IIZbyfUUR8TEkpLj9HPbcf8QHEBatXaL2M,1463
|
|
@@ -105,7 +105,7 @@ ex4nicegui/reactive/officials/column.py,sha256=fllKknMEUw7uNhmP7w4pgBT7HTDbpkN-d
|
|
|
105
105
|
ex4nicegui/reactive/officials/date.py,sha256=lRiJNrgs_oNo9AZTfTX_66dYL7az4co5rfRyIzvGAIo,2440
|
|
106
106
|
ex4nicegui/reactive/officials/dialog.py,sha256=3dyrvsUwM1Q7jr_PgLKt92KDA6Hris0DH90-sKamfFE,1297
|
|
107
107
|
ex4nicegui/reactive/officials/drawer.py,sha256=_Ro6stOh8U3igYMeDwI4omBgi1nld5berrAk9Dv5RVw,2346
|
|
108
|
-
ex4nicegui/reactive/officials/echarts.py,sha256=
|
|
108
|
+
ex4nicegui/reactive/officials/echarts.py,sha256=xRBKVbcCUwUGA8n7bw2eJj9FBQIayL4t_rzXZrjD3Pc,10895
|
|
109
109
|
ex4nicegui/reactive/officials/element.py,sha256=-qsHcxfF3fMfU0sJlKtTksX_wYPMIPJ_AgFcZbbI754,412
|
|
110
110
|
ex4nicegui/reactive/officials/expansion.py,sha256=8xwJa0SpsVhFxbYwYRZtf1ul9m4oYTjgmtrRI_lqF_0,1822
|
|
111
111
|
ex4nicegui/reactive/officials/grid.py,sha256=Bq83jejsxQSYVc9O1IE6JUgUndUm1uexb4fq9EZWjHQ,921
|
|
@@ -118,18 +118,18 @@ ex4nicegui/reactive/officials/knob.py,sha256=TPKrquOBD9fBI9aBipE0qYy22dQJCcX9wNZ
|
|
|
118
118
|
ex4nicegui/reactive/officials/label.py,sha256=kCair4NpFB7bvsPukMFcDBqDXk2BxOLzBQXSNx5EWuw,1428
|
|
119
119
|
ex4nicegui/reactive/officials/linear_progress.py,sha256=T-z8_68FxSwdFH0hBFMA2X0JEeLoVFpJyya5RHlf7U8,2045
|
|
120
120
|
ex4nicegui/reactive/officials/number.py,sha256=L_uMY-t5SONENI3b44DjSi7JwcdfYAldGZCvqX1h6Dw,2796
|
|
121
|
-
ex4nicegui/reactive/officials/radio.py,sha256=
|
|
121
|
+
ex4nicegui/reactive/officials/radio.py,sha256=l_PnmnirZ1_CYA0_jxbDfSVgM7m4NHzNOnCrNRyAmfI,1889
|
|
122
122
|
ex4nicegui/reactive/officials/row.py,sha256=ZWJnb6nC9XMfmRmzeVKnHwUnxrCpbxaEBJ3lSVj5m5s,1384
|
|
123
|
-
ex4nicegui/reactive/officials/select.py,sha256=
|
|
123
|
+
ex4nicegui/reactive/officials/select.py,sha256=pS9feUPcePIMxOTw4cZSKEIPAHf8G_CrkfNVSLkYY-Q,3130
|
|
124
124
|
ex4nicegui/reactive/officials/slider.py,sha256=9pA7CHlfkKY-kLQGWn4VOnMa2-tXHI04R1YA4xENIWI,2871
|
|
125
125
|
ex4nicegui/reactive/officials/switch.py,sha256=XMUdOVP357gGVNU_tjrBtxw5Xuk5MyhLhHI-6sTtCcc,1456
|
|
126
126
|
ex4nicegui/reactive/officials/tab.py,sha256=nyB7Ksc_tWG-RaAXiu3TTIJvkNeSa9AZdwHXuL2SsOE,1433
|
|
127
|
-
ex4nicegui/reactive/officials/tab_panel.py,sha256=
|
|
128
|
-
ex4nicegui/reactive/officials/tab_panels.py,sha256=
|
|
127
|
+
ex4nicegui/reactive/officials/tab_panel.py,sha256=yRgQBSCbrkcw59M8HlIWc2GaXhqC4awRQlYug0AkBtE,2501
|
|
128
|
+
ex4nicegui/reactive/officials/tab_panels.py,sha256=dN5anN03DlpDvkUP_QiY047i4mO7KQP3KUHAmMMVnOY,4592
|
|
129
129
|
ex4nicegui/reactive/officials/table.py,sha256=B_nX19UxwyxGKsxLuu2x4UNwxsapjTBw70RMBWDI8w0,6206
|
|
130
130
|
ex4nicegui/reactive/officials/tabs.py,sha256=kvAXeZkgi8USCyxislvjPmmWofZ31DMfiHqEObANpYU,1247
|
|
131
131
|
ex4nicegui/reactive/officials/textarea.py,sha256=_N6eDW_Cbn4Z4OEcjC4koHt0kEEaFEjDrLZ9Ju2NpsQ,3000
|
|
132
|
-
ex4nicegui/reactive/officials/toggle.py,sha256=
|
|
132
|
+
ex4nicegui/reactive/officials/toggle.py,sha256=7Dc6IIYzgsTwThE0pZegOaVe9x_GgL7a2E6Hsiuc1lg,2740
|
|
133
133
|
ex4nicegui/reactive/officials/tooltip.py,sha256=lkDOf5Z6vpDsO9Y-nsRRwdhmYVFb9YrWv7lQUNY4_Ho,1136
|
|
134
134
|
ex4nicegui/reactive/officials/upload.py,sha256=5SX2CFkf3s_4bPcnx0bmKRA4eYVlm0S8RBeQ7qHnqck,2395
|
|
135
135
|
ex4nicegui/reactive/q_pagination.py,sha256=nUszZ4fvCf4leQ1DpS70laCDf40RprbOex7SISbAEek,1555
|
|
@@ -137,7 +137,7 @@ ex4nicegui/reactive/rxui.py,sha256=gZ8ZEjGuJFKcedEZhcm4PIZguNkY-Wv5yQx80QnsBKI,3
|
|
|
137
137
|
ex4nicegui/reactive/scopedStyle.js,sha256=RtpfUwkpjMv_cbplkr2UtydKAxB5Dz7Sm6jRgPHRhow,1569
|
|
138
138
|
ex4nicegui/reactive/scopedStyle.py,sha256=aYP4sIFzAmPaLyZV8m9jqyuGmOcJnC-5s07UQnoNSag,738
|
|
139
139
|
ex4nicegui/reactive/services/pandas_service.py,sha256=XOoy6tZr4TpTyhewAH59eiSwVFxqwOipdM_j-mkGpdM,1043
|
|
140
|
-
ex4nicegui/reactive/services/reactive_service.py,sha256=
|
|
140
|
+
ex4nicegui/reactive/services/reactive_service.py,sha256=FT8tWCC_aMD1YK6V4jQreyGmQAbcWzKbaGGZ4ME-bKw,3659
|
|
141
141
|
ex4nicegui/reactive/systems/color_system.py,sha256=qXRTczxfILduHAVlNJqLSed-0x-LN6TyBSegYwW9vfk,4352
|
|
142
142
|
ex4nicegui/reactive/systems/object_system.py,sha256=bja9YNb4v5fVZl5gJvVA4HbwRssRp-2yFy3JBzNeKxA,752
|
|
143
143
|
ex4nicegui/reactive/systems/reactive_system.py,sha256=wyCSPdGuH1jOOkb2mXWRYVpdebjSm0qi9fuiVAkw5tA,701
|
|
@@ -169,7 +169,7 @@ ex4nicegui/utils/proxy/dict.py,sha256=r3qMT2RRvi2aUs8kzav2iNMGgBrFUWKsbHCAuz4P0F
|
|
|
169
169
|
ex4nicegui/utils/proxy/float.py,sha256=fdMUS7_xwypdDNscuZaUn3NA0vx8LGswAOc9kw0jK0c,5271
|
|
170
170
|
ex4nicegui/utils/proxy/int.py,sha256=0Y7L924Zzq6LWRZEmaTmoXf0J6kC0o5EtW--2Lk7SNw,7381
|
|
171
171
|
ex4nicegui/utils/proxy/list.py,sha256=bmjBMlO8UfJekL1nfGypMO21RKraIj1jw46-8QwfptE,4913
|
|
172
|
-
ex4nicegui/utils/proxy/string.py,sha256=
|
|
172
|
+
ex4nicegui/utils/proxy/string.py,sha256=BFZ5Uba47S68mMSoJFYFZqKjivJDz80vmEozxxfhUok,13861
|
|
173
173
|
ex4nicegui/utils/proxy/utils.py,sha256=8LawrZ8KmzP64iCmweFJh4kmwEvRxOp7MwV7AsnEMJM,148
|
|
174
174
|
ex4nicegui/utils/refComputed.py,sha256=Vb7fyi0wNieFeLfCjXl6wSzpws3i6_aeCka1s9dsc8E,4232
|
|
175
175
|
ex4nicegui/utils/refWrapper.py,sha256=gX5sdfC1P4UXmMYM6FwdImfLD39y02kq7Af6dIMDrZ8,1472
|
|
@@ -177,7 +177,7 @@ ex4nicegui/utils/scheduler.py,sha256=1gyq7Y2BkbwmPK_Q9kpRpc1MOC9H7xcpxuix-RZhN9k
|
|
|
177
177
|
ex4nicegui/utils/signals.py,sha256=Jz0jKFPrJIRV0Gye62Bgk2kGgod1KBvDhnF-W3lRm04,7373
|
|
178
178
|
ex4nicegui/utils/types.py,sha256=pE5WOSbcTHxaAhnT24FaZEd1B2Z_lTcsd46w0OKiMyc,359
|
|
179
179
|
ex4nicegui/version.py,sha256=NE7u1piESstg3xCtf5hhV4iedGs2qJQw9SiC3ZSpiio,90
|
|
180
|
-
ex4nicegui-0.8.
|
|
181
|
-
ex4nicegui-0.8.
|
|
182
|
-
ex4nicegui-0.8.
|
|
183
|
-
ex4nicegui-0.8.
|
|
180
|
+
ex4nicegui-0.8.3.dist-info/LICENSE,sha256=0KDDElS2dl-HIsWvbpy8ywbLzJMBFzXLev57LnMIZXs,1094
|
|
181
|
+
ex4nicegui-0.8.3.dist-info/METADATA,sha256=7Za7-7oAslhffh2RB0-PCPzxhsjCxLx_hA8c0uFgbws,44094
|
|
182
|
+
ex4nicegui-0.8.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
183
|
+
ex4nicegui-0.8.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|