ex4nicegui 0.6.5__py3-none-any.whl → 0.6.7__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 (42) hide show
  1. ex4nicegui/__init__.py +3 -2
  2. ex4nicegui/bi/elements/ui_echarts.py +2 -5
  3. ex4nicegui/libs/gsap/.DS_Store +0 -0
  4. ex4nicegui/libs/gsap/gsap.mjs +6 -0
  5. ex4nicegui/reactive/EChartsComponent/ECharts.js +69 -86
  6. ex4nicegui/reactive/EChartsComponent/ECharts.py +20 -103
  7. ex4nicegui/reactive/EChartsComponent/events.py +26 -0
  8. ex4nicegui/reactive/EChartsComponent/types.py +51 -0
  9. ex4nicegui/reactive/EChartsComponent/utils.py +44 -0
  10. ex4nicegui/reactive/deferredTask.py +29 -0
  11. ex4nicegui/reactive/officials/aggrid.py +3 -3
  12. ex4nicegui/reactive/officials/base.py +10 -0
  13. ex4nicegui/reactive/officials/button.py +4 -4
  14. ex4nicegui/reactive/officials/checkbox.py +3 -3
  15. ex4nicegui/reactive/officials/circular_progress.py +3 -3
  16. ex4nicegui/reactive/officials/color_picker.py +4 -4
  17. ex4nicegui/reactive/officials/column.py +3 -2
  18. ex4nicegui/reactive/officials/date.py +4 -9
  19. ex4nicegui/reactive/officials/echarts.py +39 -34
  20. ex4nicegui/reactive/officials/expansion.py +3 -2
  21. ex4nicegui/reactive/officials/icon.py +4 -4
  22. ex4nicegui/reactive/officials/image.py +3 -3
  23. ex4nicegui/reactive/officials/input.py +4 -4
  24. ex4nicegui/reactive/officials/knob.py +3 -3
  25. ex4nicegui/reactive/officials/label.py +4 -3
  26. ex4nicegui/reactive/officials/linear_progress.py +4 -4
  27. ex4nicegui/reactive/officials/number.py +24 -5
  28. ex4nicegui/reactive/officials/radio.py +4 -4
  29. ex4nicegui/reactive/officials/select.py +4 -4
  30. ex4nicegui/reactive/officials/slider.py +3 -3
  31. ex4nicegui/reactive/officials/switch.py +3 -3
  32. ex4nicegui/reactive/officials/tab_panels.py +14 -2
  33. ex4nicegui/reactive/officials/table.py +5 -4
  34. ex4nicegui/reactive/officials/tabs.py +3 -2
  35. ex4nicegui/reactive/officials/textarea.py +3 -3
  36. ex4nicegui/reactive/q_pagination.py +3 -2
  37. ex4nicegui/utils/clientScope.py +14 -6
  38. {ex4nicegui-0.6.5.dist-info → ex4nicegui-0.6.7.dist-info}/METADATA +1245 -1099
  39. {ex4nicegui-0.6.5.dist-info → ex4nicegui-0.6.7.dist-info}/RECORD +65 -60
  40. {ex4nicegui-0.6.5.dist-info → ex4nicegui-0.6.7.dist-info}/WHEEL +1 -2
  41. ex4nicegui-0.6.5.dist-info/top_level.txt +0 -1
  42. {ex4nicegui-0.6.5.dist-info → ex4nicegui-0.6.7.dist-info}/LICENSE +0 -0
ex4nicegui/__init__.py CHANGED
@@ -20,7 +20,7 @@ from ex4nicegui.utils.signals import (
20
20
  is_reactive,
21
21
  )
22
22
  from ex4nicegui.utils.asyncComputed import async_computed
23
-
23
+ from ex4nicegui.utils.clientScope import new_scope
24
24
 
25
25
  __all__ = [
26
26
  "async_computed",
@@ -43,6 +43,7 @@ __all__ = [
43
43
  "batch",
44
44
  "to_raw",
45
45
  "is_setter_ref",
46
+ "new_scope",
46
47
  ]
47
48
 
48
- __version__ = "0.6.5"
49
+ __version__ = "0.6.6"
@@ -2,10 +2,7 @@ from __future__ import annotations
2
2
  from typing import TYPE_CHECKING, Any, Callable, Dict, Union, cast
3
3
  from nicegui.events import UiEventArguments
4
4
  from ex4nicegui.reactive import rxui
5
- from ex4nicegui.reactive.EChartsComponent.ECharts import (
6
- EChartsMouseEventArguments,
7
- echarts,
8
- )
5
+ from ex4nicegui.reactive.EChartsComponent.ECharts import echarts
9
6
  from nicegui import ui
10
7
  from ex4nicegui.bi.dataSource import DataSource
11
8
  from .models import UiResult
@@ -21,7 +18,7 @@ class EChartsResult(UiResult[echarts]):
21
18
  super().__init__(element, dataSource)
22
19
  self.chart_update = chart_update
23
20
 
24
- def on_chart_click(self, handler: Callable[[EChartsMouseEventArguments], Any]):
21
+ def on_chart_click(self, handler: Callable[[UiEventArguments], Any]):
25
22
  return self.element.echarts_on("click", handler)
26
23
 
27
24
  def on_chart_click_blank(self, handler: Callable[[UiEventArguments], Any]):
Binary file
@@ -0,0 +1,6 @@
1
+ import { gsap, Power0, Power1, Power2, Power3, Power4, Linear, Quad, Cubic, Quart, Quint, Strong, Elastic, Back, SteppedEase, Bounce, Sine, Expo, Circ, TweenLite, TimelineLite, TimelineMax } from "./gsap-core.js";
2
+ import { CSSPlugin } from "./CSSPlugin.js";
3
+ var gsapWithCSS = gsap.registerPlugin(CSSPlugin) || gsap,
4
+ // to protect from tree shaking
5
+ TweenMaxWithCSS = gsapWithCSS.core.Tween;
6
+ export { gsapWithCSS as gsap, gsapWithCSS as default, CSSPlugin, TweenMaxWithCSS as TweenMax, TweenLite, TimelineMax, TimelineLite, Power0, Power1, Power2, Power3, Power4, Linear, Quad, Cubic, Quart, Quint, Strong, Elastic, Back, SteppedEase, Bounce, Sine, Expo, Circ };
@@ -1,83 +1,89 @@
1
1
  import { convertDynamicProperties } from "../../static/utils/dynamic_properties.js";
2
2
 
3
+ function collectMapRegisterTask() {
4
+ const tasks = new Map();
5
+
6
+ if (typeof window.ex4ngEchartsMapTasks !== "undefined") {
7
+
8
+ for (const [mapName, opt] of window.ex4ngEchartsMapTasks.entries()) {
9
+ const { src, type: mapDataType, specialAreas } = opt;
10
+ const registerPromise = new Promise((resolve, reject) => {
11
+ fetch(src)
12
+ .then((response) => {
13
+ if (mapDataType === "genJSON") {
14
+ return response.json();
15
+ }
3
16
 
4
- function retry(fn, options = {}) {
17
+ return response.text();
18
+ })
19
+ .then((data) => {
20
+ if (mapDataType === "svg") {
21
+ data = { svg: data }
22
+ }
5
23
 
6
- options = {
7
- error: 'Maximum number of tries exceeded',
8
- tryMaxTimes: 5,
9
- intervalMs: 800,
10
- ...options
11
- }
24
+ echarts.registerMap(mapName, data, specialAreas);
25
+ resolve();
26
+ });
12
27
 
13
- let tryTimes = 0
14
- let isDone = false
28
+ });
15
29
 
16
- const doneFn = () => {
17
- isDone = true
30
+ tasks.set(mapName, registerPromise);
31
+ }
18
32
  }
19
33
 
20
- function callback() {
21
- tryTimes += 1
22
-
23
- if (tryTimes <= options.tryMaxTimes) {
24
- fn(doneFn)
34
+ return tasks;
35
+ }
25
36
 
26
- if (isDone) {
27
- clearInterval(task)
28
- }
37
+ function hasMapOrGeo(options) {
38
+ if (options) {
39
+ const hasMapSeries = options.series && Array.isArray(options.series) &&
40
+ options.series.some(seriesItem =>
41
+ seriesItem.type === 'map' ||
42
+ seriesItem.type === 'lines'
43
+ );
29
44
 
30
- } else {
31
- console.error(options.error)
32
- clearInterval(task)
33
- }
45
+ const hasGeoConfig = options.geo && (typeof options.geo === 'object' || Array.isArray(options.geo));
34
46
 
47
+ return hasMapSeries || hasGeoConfig;
35
48
  }
36
-
37
- callback();
38
- const task = setInterval(callback, options.intervalMs);
49
+ return false;
39
50
  }
40
51
 
52
+ const mapRegisterTasks = collectMapRegisterTask();
41
53
 
42
54
  export default {
43
55
  template: "<div></div>",
44
- mounted() {
56
+ async mounted() {
57
+ await this.$nextTick(); // wait for Tailwind classes to be applied
45
58
 
46
- function initChart() {
47
- this.chart = echarts.init(this.$el, this.theme);
59
+ this.chart = echarts.init(this.$el, this.theme);
48
60
 
49
- if (this.options) {
50
- this.update_chart();
51
- } else {
52
- const fn = new Function('return ' + this.code)()
53
- fn(this.chart)
54
- this.$emit("__update_options_from_client", this.chart.getOption())
55
- }
56
- this.chart.getZr().on("click", (e) => {
57
- if (!e.target) {
58
- this.$emit("clickBlank")
59
- }
60
- });
61
- this.resizeObs = new ResizeObserver(this.chart.resize)
61
+ this.resizeObs = new ResizeObserver(this.chart.resize)
62
+
63
+ // Prevent interruption of chart animations due to resize operations.
64
+ // It is recommended to register the callbacks for such an event before setOption.
65
+ const createResizeObserver = () => {
62
66
  this.resizeObs.observe(this.$el);
63
- }
67
+ this.chart.off("finished", createResizeObserver);
68
+ };
69
+ this.chart.on("finished", createResizeObserver);
64
70
 
65
- initChart = initChart.bind(this)
66
-
67
- retry((done) => {
68
- try {
69
- initChart()
70
- done()
71
- } catch (e) {
72
- if (e instanceof TypeError && e.message === `Cannot read properties of undefined (reading 'regions')`) {
73
- echarts.dispose(this.chart)
74
- return
75
- } else {
76
- done()
77
- throw e;
78
- }
71
+ if (this.options) {
72
+ if (hasMapOrGeo(this.options)) {
73
+ await Promise.all(Array.from(mapRegisterTasks.values()));
79
74
  }
80
- }, { error: 'Maximum number of retries echart init' })
75
+ this.update_chart();
76
+ } else {
77
+ const fn = new Function('return ' + this.code)()
78
+ await Promise.all(Array.from(mapRegisterTasks.values()));
79
+ fn(this.chart, echarts)
80
+ this.$emit("__update_options_from_client", this.chart.getOption())
81
+ }
82
+ this.chart.getZr().on("click", (e) => {
83
+ if (!e.target) {
84
+ this.$emit("clickBlank")
85
+ }
86
+ });
81
87
 
82
88
  },
83
89
  beforeDestroy() {
@@ -94,33 +100,10 @@ export default {
94
100
  this.chart.setOption(this.options, opts ?? { notMerge: this.chart.options?.series.length != this.options.series.length });
95
101
  },
96
102
 
97
-
98
- echarts_on(eventName, query, callbackId) {
99
-
100
- retry((done) => {
101
- if (this.chart) {
102
-
103
- this.chart.on(eventName, query, (e) => {
104
- const eventParams = {
105
- componentType: e.componentType,
106
- seriesType: e.seriesType,
107
- seriesIndex: e.seriesIndex,
108
- seriesName: e.seriesName,
109
- name: e.name,
110
- dataIndex: e.dataIndex,
111
- data: e.data,
112
- dataType: e.dataType,
113
- value: e.value,
114
- color: e.color,
115
- }
116
-
117
- this.$emit('event_on', { params: eventParams, callbackId })
118
- })
119
-
120
- done()
121
- }
122
- }, { error: 'Maximum number of retries on echarts event' })
123
-
103
+ echarts_on(eventName, query) {
104
+ this.chart.on(eventName.replace(/^chart:/, ''), query, (e) => {
105
+ this.$emit(eventName, e);
106
+ });
124
107
  },
125
108
 
126
109
  run_chart_method(name, ...args) {
@@ -128,7 +111,7 @@ export default {
128
111
  name = name.slice(1);
129
112
  args = args.map((arg) => new Function("return " + arg)());
130
113
  }
131
- return this.chart[name](...args);
114
+ return runMethod(this.chart, name, args);
132
115
  },
133
116
  },
134
117
  props: {
@@ -3,70 +3,26 @@ from typing import (
3
3
  Any,
4
4
  Callable,
5
5
  Dict,
6
- List,
7
6
  Optional,
8
7
  Union,
9
8
  )
10
- from typing_extensions import Literal
11
- from dataclasses import dataclass
12
- from nicegui.dataclasses import KWONLY_SLOTS
13
- from nicegui.events import (
14
- handle_event,
15
- UiEventArguments,
16
- )
9
+
10
+ from nicegui.events import handle_event, UiEventArguments, GenericEventArguments
17
11
  from nicegui.element import Element
18
12
  from nicegui.awaitable_response import AwaitableResponse
19
- from nicegui import ui
20
13
  from pathlib import Path
21
14
  import nicegui
22
- import uuid
15
+
16
+ from .types import (
17
+ _T_event_name,
18
+ )
19
+ from ex4nicegui.reactive.deferredTask import DeferredTask
20
+ from .utils import get_bound_event_args, create_event_handler_args
23
21
 
24
22
  NG_ROOT = Path(nicegui.__file__).parent / "elements"
25
23
  libraries = [NG_ROOT / "lib/echarts/echarts.min.js"]
26
24
 
27
25
 
28
- _Chart_Click_Args = [
29
- "componentType",
30
- "seriesType",
31
- "seriesIndex",
32
- "seriesName",
33
- "name",
34
- "dataIndex",
35
- "data",
36
- "dataType",
37
- "value",
38
- "color",
39
- ]
40
-
41
-
42
- @dataclass(**KWONLY_SLOTS)
43
- class EChartsMouseEventArguments(UiEventArguments):
44
- componentType: str
45
- seriesType: str
46
- seriesIndex: int
47
- seriesName: str
48
- name: str
49
- dataIndex: int
50
- data: dict
51
- dataType: Optional[str]
52
- value: Any
53
- color: str
54
-
55
-
56
- _T_echats_on_callback = Callable[[EChartsMouseEventArguments], Any]
57
- _T_mouse_event_name = Literal[
58
- "click",
59
- "dblclick",
60
- "mousedown",
61
- "mousemove",
62
- "mouseup",
63
- "mouseover",
64
- "mouseout",
65
- "globalout",
66
- "contextmenu",
67
- ]
68
-
69
-
70
26
  class echarts(Element, component="ECharts.js", libraries=libraries): # type: ignore
71
27
  def __init__(
72
28
  self,
@@ -74,6 +30,7 @@ class echarts(Element, component="ECharts.js", libraries=libraries): # type: ig
74
30
  code: Optional[str] = None,
75
31
  ) -> None:
76
32
  super().__init__()
33
+ self.__deferred_task = DeferredTask()
77
34
 
78
35
  if (options is None) and (bool(code) is False):
79
36
  raise ValueError("At least one of options and code must be valid.")
@@ -89,36 +46,6 @@ class echarts(Element, component="ECharts.js", libraries=libraries): # type: ig
89
46
  self._props["options"] = options
90
47
  self._props["code"] = code
91
48
 
92
- self._echarts_on_tasks: List[Callable] = []
93
- self._echarts_on_callback_map: Dict[str, _T_echats_on_callback] = {}
94
-
95
- async def on_client_connect(
96
- client: nicegui.Client,
97
- ) -> Any:
98
- await client.connected()
99
-
100
- for func in self._echarts_on_tasks:
101
- func()
102
-
103
- client.connect_handlers.remove(on_client_connect) # type: ignore
104
-
105
- ui.context.client.on_connect(on_client_connect)
106
-
107
- def echartsOn_handler(e):
108
- callbackId = e.args["callbackId"]
109
- params: Dict = e.args["params"]
110
- params["dataType"] = params.get("dataType")
111
-
112
- if callbackId in self._echarts_on_callback_map:
113
- event_args = EChartsMouseEventArguments(
114
- sender=e.sender, client=e.client, **params
115
- )
116
- handler = self._echarts_on_callback_map[callbackId]
117
-
118
- handle_event(handler, event_args)
119
-
120
- self.on("event_on", echartsOn_handler)
121
-
122
49
  def update_chart(
123
50
  self,
124
51
  merge_opts: Optional[dict] = None,
@@ -164,34 +91,24 @@ class echarts(Element, component="ECharts.js", libraries=libraries): # type: ig
164
91
  ),
165
92
  )
166
93
 
167
- self.on(
168
- "clickBlank",
169
- inner_handler,
170
- _Chart_Click_Args,
171
- )
94
+ self.on("clickBlank", inner_handler)
172
95
 
173
96
  def echarts_on(
174
97
  self,
175
- event_name: _T_mouse_event_name,
176
- handler: _T_echats_on_callback,
98
+ event_name: _T_event_name,
99
+ handler: Callable[[UiEventArguments], None],
177
100
  query: Optional[Union[str, Dict]] = None,
178
101
  ):
179
- if not ui.context.client.has_socket_connection:
102
+ def org_handler(e: GenericEventArguments) -> None:
103
+ event_args = create_event_handler_args(event_name, e)
104
+ handle_event(handler, event_args)
180
105
 
181
- def task_func():
182
- self.echarts_on(event_name, handler, query)
106
+ ui_event_name = f"chart:{event_name}"
107
+ super().on(ui_event_name, org_handler, args=get_bound_event_args(event_name))
183
108
 
184
- self._echarts_on_tasks.append(task_func)
185
- return
186
-
187
- callback_id = uuid.uuid4().hex
188
- self.run_method(
189
- "echarts_on",
190
- event_name,
191
- query,
192
- callback_id,
193
- )
194
- self._echarts_on_callback_map[callback_id] = handler
109
+ @self.__deferred_task.register
110
+ def _():
111
+ self.run_method("echarts_on", ui_event_name, query)
195
112
 
196
113
  def run_chart_method(
197
114
  self, name: str, *args, timeout: float = 1, check_interval: float = 0.01
@@ -0,0 +1,26 @@
1
+ from typing import (
2
+ Any,
3
+ Optional,
4
+ )
5
+ from dataclasses import dataclass, fields
6
+ from nicegui.dataclasses import KWONLY_SLOTS
7
+ from nicegui.events import (
8
+ UiEventArguments,
9
+ )
10
+
11
+
12
+ @dataclass(**KWONLY_SLOTS)
13
+ class EChartsMouseEventArguments(UiEventArguments):
14
+ componentType: str
15
+ seriesType: str
16
+ seriesIndex: int
17
+ seriesName: str
18
+ name: str
19
+ dataIndex: int
20
+ data: dict
21
+ dataType: Optional[str]
22
+ value: Any
23
+ color: str
24
+
25
+
26
+ _Mouse_Event_Arguments_Fields = [f.name for f in fields(EChartsMouseEventArguments)]
@@ -0,0 +1,51 @@
1
+ from typing import (
2
+ Union,
3
+ )
4
+ from typing_extensions import Literal
5
+
6
+
7
+ _T_mouse_event_name = Literal[
8
+ "click",
9
+ "dblclick",
10
+ "mousedown",
11
+ "mousemove",
12
+ "mouseup",
13
+ "mouseover",
14
+ "mouseout",
15
+ "globalout",
16
+ "contextmenu",
17
+ ]
18
+
19
+ _T_generic_event_name = Literal[
20
+ "highlight",
21
+ "downplay",
22
+ "selectchanged",
23
+ "legendselectchanged",
24
+ "legendselected",
25
+ "legendunselected",
26
+ "legendselectall",
27
+ "legendinverseselect",
28
+ "legendscroll",
29
+ "datazoom",
30
+ "datarangeselected",
31
+ "graphroam",
32
+ "georoam",
33
+ "treeroam",
34
+ "timelinechanged",
35
+ "timelineplaychanged",
36
+ "restore",
37
+ "dataviewchanged",
38
+ "magictypechanged",
39
+ "geoselectchanged",
40
+ "geoselected",
41
+ "geounselected",
42
+ "axisareaselected",
43
+ "brush",
44
+ "brushEnd",
45
+ "brushselected",
46
+ "globalcursortaken",
47
+ "rendered",
48
+ "finished",
49
+ ]
50
+
51
+ _T_event_name = Union[_T_mouse_event_name, _T_generic_event_name]
@@ -0,0 +1,44 @@
1
+ from typing import List, Optional
2
+ import typing
3
+ from .types import _T_event_name, _T_mouse_event_name
4
+ from .events import EChartsMouseEventArguments, _Mouse_Event_Arguments_Fields
5
+ from nicegui.events import UiEventArguments, GenericEventArguments
6
+ from functools import lru_cache
7
+
8
+
9
+ @lru_cache(maxsize=1)
10
+ def _get_mouse_event_names():
11
+ return set(typing.get_args(_T_mouse_event_name))
12
+
13
+
14
+ def is_mouse_event(event_name: _T_event_name) -> bool:
15
+ return event_name in _get_mouse_event_names()
16
+
17
+
18
+ def get_bound_event_args(event_name: _T_event_name) -> Optional[List[str]]:
19
+ if is_mouse_event(event_name):
20
+ return _Mouse_Event_Arguments_Fields
21
+
22
+ return None
23
+
24
+
25
+ def create_event_handler_args(
26
+ event_name: _T_event_name, e: GenericEventArguments
27
+ ) -> UiEventArguments:
28
+ if is_mouse_event(event_name):
29
+ return EChartsMouseEventArguments(
30
+ sender=e.sender,
31
+ client=e.client,
32
+ componentType=e.args["componentType"],
33
+ seriesType=e.args["seriesType"],
34
+ seriesIndex=e.args["seriesIndex"],
35
+ seriesName=e.args["seriesName"],
36
+ name=e.args["name"],
37
+ dataIndex=e.args["dataIndex"],
38
+ data=e.args["data"],
39
+ dataType=e.args.get("dataType"),
40
+ value=e.args["value"],
41
+ color=e.args["color"],
42
+ )
43
+
44
+ return GenericEventArguments(sender=e.sender, client=e.client, args=e.args)
@@ -0,0 +1,29 @@
1
+ from typing import Callable
2
+ from nicegui import ui, Client as ng_client
3
+
4
+
5
+ class DeferredTask:
6
+ def __init__(self):
7
+ self._tasks = []
8
+
9
+ async def on_client_connect(
10
+ client: ng_client,
11
+ ):
12
+ await client.connected()
13
+
14
+ for task in self._tasks:
15
+ task()
16
+
17
+ self._tasks.clear()
18
+
19
+ # Avoid events becoming ineffective due to page refresh when sharing the client.
20
+ if not client.shared:
21
+ client.connect_handlers.remove(on_client_connect) # type: ignore
22
+
23
+ ui.context.client.on_connect(on_client_connect)
24
+
25
+ def register(self, task: Callable[..., None]):
26
+ if ui.context.client.has_socket_connection:
27
+ task()
28
+ else:
29
+ self._tasks.append(task)
@@ -6,11 +6,11 @@ from typing import (
6
6
  Optional,
7
7
  )
8
8
  from ex4nicegui.utils.signals import (
9
- ReadonlyRef,
10
9
  is_ref,
11
10
  ref_computed,
12
11
  to_value,
13
12
  _TMaybeRef as TMaybeRef,
13
+ TGetterOrReadonlyRef,
14
14
  )
15
15
  from ex4nicegui.utils.apiEffect import ui_effect
16
16
  from nicegui import ui
@@ -78,13 +78,13 @@ class AggridBindableUi(BindableUi[ui.aggrid]):
78
78
  options = {"columnDefs": columnDefs, "rowData": rowData}
79
79
  return cls(options, **org_kws)
80
80
 
81
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef[Any]):
81
+ def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef[Any]):
82
82
  if prop == "options":
83
83
  return self.bind_options(ref_ui)
84
84
 
85
85
  return super().bind_prop(prop, ref_ui)
86
86
 
87
- def bind_options(self, ref_ui: ReadonlyRef[List[Dict]]):
87
+ def bind_options(self, ref_ui: TGetterOrReadonlyRef[List[Dict]]):
88
88
  @ui_effect
89
89
  def _():
90
90
  ele = self.element
@@ -128,6 +128,16 @@ class BindableUi(Generic[TWidget]):
128
128
  return self.element.remove(element)
129
129
 
130
130
  def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef[Any]):
131
+ """data binding is manipulating an element's property
132
+
133
+ @see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#bind_prop
134
+ @中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#bind_prop
135
+
136
+ Args:
137
+ prop (str): property name
138
+ ref_ui (TGetterOrReadonlyRef[Any]): a reference to the value to bind to
139
+
140
+ """
131
141
  if prop == "visible":
132
142
  return self.bind_visible(ref_ui)
133
143
 
@@ -5,7 +5,7 @@ from typing import (
5
5
  )
6
6
  from ex4nicegui.reactive.utils import ParameterClassifier
7
7
  from ex4nicegui.utils.signals import (
8
- ReadonlyRef,
8
+ TGetterOrReadonlyRef,
9
9
  _TMaybeRef as TMaybeRef,
10
10
  to_value,
11
11
  )
@@ -33,7 +33,7 @@ class ButtonBindableUi(BindableUi[ui.button], DisableableMixin):
33
33
  for key, value in pc.get_bindings().items():
34
34
  self.bind_prop(key, value) # type: ignore
35
35
 
36
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
36
+ def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef):
37
37
  if prop == "text":
38
38
  return self.bind_text(ref_ui)
39
39
  if prop == "icon":
@@ -41,7 +41,7 @@ class ButtonBindableUi(BindableUi[ui.button], DisableableMixin):
41
41
 
42
42
  return super().bind_prop(prop, ref_ui)
43
43
 
44
- def bind_text(self, ref_ui: ReadonlyRef):
44
+ def bind_text(self, ref_ui: TGetterOrReadonlyRef):
45
45
  @self._ui_effect
46
46
  def _():
47
47
  ele = self.element
@@ -50,7 +50,7 @@ class ButtonBindableUi(BindableUi[ui.button], DisableableMixin):
50
50
 
51
51
  return self
52
52
 
53
- def bind_icon(self, ref_ui: ReadonlyRef):
53
+ def bind_icon(self, ref_ui: TGetterOrReadonlyRef[str]):
54
54
  @self._ui_effect
55
55
  def _():
56
56
  ele = self.element
@@ -7,7 +7,7 @@ from typing import (
7
7
  from ex4nicegui.reactive.utils import ParameterClassifier
8
8
  from ex4nicegui.utils.apiEffect import ui_effect
9
9
  from ex4nicegui.utils.signals import (
10
- ReadonlyRef,
10
+ TGetterOrReadonlyRef,
11
11
  _TMaybeRef as TMaybeRef,
12
12
  to_value,
13
13
  )
@@ -44,13 +44,13 @@ class CheckboxBindableUi(BindableUi[ui.checkbox], DisableableMixin):
44
44
  def value(self):
45
45
  return self.element.value
46
46
 
47
- def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
47
+ def bind_prop(self, prop: str, ref_ui: TGetterOrReadonlyRef):
48
48
  if prop == "value":
49
49
  return self.bind_value(ref_ui)
50
50
 
51
51
  return super().bind_prop(prop, ref_ui)
52
52
 
53
- def bind_value(self, ref_ui: ReadonlyRef[bool]):
53
+ def bind_value(self, ref_ui: TGetterOrReadonlyRef[bool]):
54
54
  @ui_effect
55
55
  def _():
56
56
  self.element.set_value(to_value(ref_ui))