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.
- ex4nicegui/__init__.py +3 -2
- ex4nicegui/bi/elements/ui_echarts.py +2 -5
- ex4nicegui/libs/gsap/.DS_Store +0 -0
- ex4nicegui/libs/gsap/gsap.mjs +6 -0
- ex4nicegui/reactive/EChartsComponent/ECharts.js +69 -86
- ex4nicegui/reactive/EChartsComponent/ECharts.py +20 -103
- ex4nicegui/reactive/EChartsComponent/events.py +26 -0
- ex4nicegui/reactive/EChartsComponent/types.py +51 -0
- ex4nicegui/reactive/EChartsComponent/utils.py +44 -0
- ex4nicegui/reactive/deferredTask.py +29 -0
- ex4nicegui/reactive/officials/aggrid.py +3 -3
- ex4nicegui/reactive/officials/base.py +10 -0
- ex4nicegui/reactive/officials/button.py +4 -4
- ex4nicegui/reactive/officials/checkbox.py +3 -3
- ex4nicegui/reactive/officials/circular_progress.py +3 -3
- ex4nicegui/reactive/officials/color_picker.py +4 -4
- ex4nicegui/reactive/officials/column.py +3 -2
- ex4nicegui/reactive/officials/date.py +4 -9
- ex4nicegui/reactive/officials/echarts.py +39 -34
- ex4nicegui/reactive/officials/expansion.py +3 -2
- ex4nicegui/reactive/officials/icon.py +4 -4
- ex4nicegui/reactive/officials/image.py +3 -3
- ex4nicegui/reactive/officials/input.py +4 -4
- ex4nicegui/reactive/officials/knob.py +3 -3
- ex4nicegui/reactive/officials/label.py +4 -3
- ex4nicegui/reactive/officials/linear_progress.py +4 -4
- ex4nicegui/reactive/officials/number.py +24 -5
- ex4nicegui/reactive/officials/radio.py +4 -4
- ex4nicegui/reactive/officials/select.py +4 -4
- ex4nicegui/reactive/officials/slider.py +3 -3
- ex4nicegui/reactive/officials/switch.py +3 -3
- ex4nicegui/reactive/officials/tab_panels.py +14 -2
- ex4nicegui/reactive/officials/table.py +5 -4
- ex4nicegui/reactive/officials/tabs.py +3 -2
- ex4nicegui/reactive/officials/textarea.py +3 -3
- ex4nicegui/reactive/q_pagination.py +3 -2
- ex4nicegui/utils/clientScope.py +14 -6
- {ex4nicegui-0.6.5.dist-info → ex4nicegui-0.6.7.dist-info}/METADATA +1245 -1099
- {ex4nicegui-0.6.5.dist-info → ex4nicegui-0.6.7.dist-info}/RECORD +65 -60
- {ex4nicegui-0.6.5.dist-info → ex4nicegui-0.6.7.dist-info}/WHEEL +1 -2
- ex4nicegui-0.6.5.dist-info/top_level.txt +0 -1
- {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.
|
|
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[[
|
|
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
|
-
|
|
17
|
+
return response.text();
|
|
18
|
+
})
|
|
19
|
+
.then((data) => {
|
|
20
|
+
if (mapDataType === "svg") {
|
|
21
|
+
data = { svg: data }
|
|
22
|
+
}
|
|
5
23
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
intervalMs: 800,
|
|
10
|
-
...options
|
|
11
|
-
}
|
|
24
|
+
echarts.registerMap(mapName, data, specialAreas);
|
|
25
|
+
resolve();
|
|
26
|
+
});
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
let isDone = false
|
|
28
|
+
});
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
tasks.set(mapName, registerPromise);
|
|
31
|
+
}
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (tryTimes <= options.tryMaxTimes) {
|
|
24
|
-
fn(doneFn)
|
|
34
|
+
return tasks;
|
|
35
|
+
}
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
47
|
-
this.chart = echarts.init(this.$el, this.theme);
|
|
59
|
+
this.chart = echarts.init(this.$el, this.theme);
|
|
48
60
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
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
|
-
|
|
11
|
-
from
|
|
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
|
-
|
|
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:
|
|
176
|
-
handler:
|
|
98
|
+
event_name: _T_event_name,
|
|
99
|
+
handler: Callable[[UiEventArguments], None],
|
|
177
100
|
query: Optional[Union[str, Dict]] = None,
|
|
178
101
|
):
|
|
179
|
-
|
|
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
|
-
|
|
182
|
-
|
|
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
|
-
|
|
185
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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))
|