ex4nicegui 0.2.3__py3-none-any.whl → 0.2.5__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 +1 -1
- ex4nicegui/reactive/__index.py +1 -31
- ex4nicegui/reactive/officials/__init__.py +37 -0
- ex4nicegui/reactive/officials/aggrid.py +81 -0
- ex4nicegui/reactive/officials/base.py +167 -0
- ex4nicegui/reactive/officials/button.py +86 -0
- ex4nicegui/reactive/officials/card.py +59 -0
- ex4nicegui/reactive/officials/checkbox.py +68 -0
- ex4nicegui/reactive/officials/color_picker.py +101 -0
- ex4nicegui/reactive/officials/date.py +85 -0
- ex4nicegui/reactive/officials/drawer.py +88 -0
- ex4nicegui/reactive/officials/echarts.py +70 -0
- ex4nicegui/reactive/officials/html.py +66 -0
- ex4nicegui/reactive/officials/icon.py +62 -0
- ex4nicegui/reactive/officials/image.py +54 -0
- ex4nicegui/reactive/officials/input.py +116 -0
- ex4nicegui/reactive/officials/label.py +67 -0
- ex4nicegui/reactive/officials/radio.py +80 -0
- ex4nicegui/reactive/officials/row.py +21 -0
- ex4nicegui/reactive/officials/select.py +93 -0
- ex4nicegui/reactive/officials/slider.py +97 -0
- ex4nicegui/reactive/officials/switch.py +72 -0
- ex4nicegui/reactive/officials/table.py +144 -0
- ex4nicegui/reactive/officials/textarea.py +103 -0
- ex4nicegui/reactive/officials/upload.py +78 -0
- ex4nicegui/reactive/officials/utils.py +11 -0
- {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/METADATA +1 -1
- ex4nicegui-0.2.5.dist-info/RECORD +56 -0
- ex4nicegui/reactive/officials.py +0 -1585
- ex4nicegui-0.2.3.dist-info/RECORD +0 -33
- {ex4nicegui-0.2.3.data → ex4nicegui-0.2.5.data}/data/ECharts/ECharts.js +0 -0
- {ex4nicegui-0.2.3.data → ex4nicegui-0.2.5.data}/data/UseDraggable/UseDraggable.js +0 -0
- {ex4nicegui-0.2.3.data → ex4nicegui-0.2.5.data}/data/useMouse/UseMouse.js +0 -0
- {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/LICENSE +0 -0
- {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/WHEEL +0 -0
- {ex4nicegui-0.2.3.dist-info → ex4nicegui-0.2.5.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from typing import Any, Callable, List, Optional, TypeVar, cast
|
|
2
|
+
from typing_extensions import TypedDict
|
|
3
|
+
from signe import effect
|
|
4
|
+
from ex4nicegui.utils.signals import (
|
|
5
|
+
ReadonlyRef,
|
|
6
|
+
is_ref,
|
|
7
|
+
_TMaybeRef as TMaybeRef,
|
|
8
|
+
)
|
|
9
|
+
from nicegui import ui
|
|
10
|
+
from .base import SingleValueBindableUi
|
|
11
|
+
from .utils import _convert_kws_ref2value
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_TDateRange = TypedDict("_TDateRange", {"from": str, "to": str})
|
|
15
|
+
|
|
16
|
+
_TDateValue = TypeVar(
|
|
17
|
+
"_TDateValue", str, List[str], _TDateRange, List[_TDateRange], None
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DateBindableUi(SingleValueBindableUi[_TDateValue, ui.date]):
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
value: Optional[TMaybeRef[_TDateValue]] = None,
|
|
25
|
+
*,
|
|
26
|
+
mask: TMaybeRef[str] = "YYYY-MM-DD",
|
|
27
|
+
on_change: Optional[Callable[..., Any]] = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Date Input
|
|
30
|
+
|
|
31
|
+
This element is based on Quasar's `QDate <https://quasar.dev/vue-components/date>`_ component.
|
|
32
|
+
The date is a string in the format defined by the `mask` parameter.
|
|
33
|
+
|
|
34
|
+
You can also use the `range` or `multiple` props to select a range of dates or multiple dates::
|
|
35
|
+
|
|
36
|
+
ui.date({'from': '2023-01-01', 'to': '2023-01-05'}).props('range')
|
|
37
|
+
ui.date(['2023-01-01', '2023-01-02', '2023-01-03']).props('multiple')
|
|
38
|
+
ui.date([{'from': '2023-01-01', 'to': '2023-01-05'}, '2023-01-07']).props('multiple range')
|
|
39
|
+
|
|
40
|
+
:param value: the initial date
|
|
41
|
+
:param mask: the format of the date string (default: 'YYYY-MM-DD')
|
|
42
|
+
:param on_change: callback to execute when changing the date
|
|
43
|
+
"""
|
|
44
|
+
kws = {
|
|
45
|
+
"value": value,
|
|
46
|
+
"mask": mask,
|
|
47
|
+
"on_change": on_change,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
51
|
+
|
|
52
|
+
element = ui.date(**value_kws)
|
|
53
|
+
|
|
54
|
+
super().__init__(value, element) # type: ignore
|
|
55
|
+
|
|
56
|
+
for key, value in kws.items():
|
|
57
|
+
if is_ref(value) and key != "value":
|
|
58
|
+
self.bind_prop(key, value) # type: ignore
|
|
59
|
+
|
|
60
|
+
self._ex_setup()
|
|
61
|
+
|
|
62
|
+
def _ex_setup(self):
|
|
63
|
+
ele = self.element
|
|
64
|
+
|
|
65
|
+
@effect
|
|
66
|
+
def _():
|
|
67
|
+
ele.value = self.value
|
|
68
|
+
|
|
69
|
+
def onModelValueChanged(e):
|
|
70
|
+
self._ref.value = e.args[0] or "" # type: ignore
|
|
71
|
+
|
|
72
|
+
ele.on("update:modelValue", handler=onModelValueChanged)
|
|
73
|
+
|
|
74
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
75
|
+
if prop == "value":
|
|
76
|
+
return self.bind_value(ref_ui)
|
|
77
|
+
|
|
78
|
+
return super().bind_prop(prop, ref_ui)
|
|
79
|
+
|
|
80
|
+
def bind_value(self, ref_ui: ReadonlyRef[bool]):
|
|
81
|
+
@effect
|
|
82
|
+
def _():
|
|
83
|
+
self.element.on_value_change(ref_ui.value)
|
|
84
|
+
|
|
85
|
+
return self
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Any,
|
|
3
|
+
)
|
|
4
|
+
from typing_extensions import Literal
|
|
5
|
+
from signe import effect
|
|
6
|
+
from ex4nicegui.utils.signals import (
|
|
7
|
+
to_value,
|
|
8
|
+
is_ref,
|
|
9
|
+
_TMaybeRef as TMaybeRef,
|
|
10
|
+
)
|
|
11
|
+
from nicegui import ui
|
|
12
|
+
from nicegui.page_layout import Drawer
|
|
13
|
+
from .base import SingleValueBindableUi
|
|
14
|
+
from .utils import _convert_kws_ref2value
|
|
15
|
+
|
|
16
|
+
_TDrawerSide = Literal["left", "right"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DrawerBindableUi(SingleValueBindableUi[bool, Drawer]):
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
side: TMaybeRef[_TDrawerSide] = "left",
|
|
23
|
+
overlay: TMaybeRef[bool] = False,
|
|
24
|
+
*,
|
|
25
|
+
value: TMaybeRef[bool] = True,
|
|
26
|
+
fixed: TMaybeRef[bool] = False,
|
|
27
|
+
bordered: TMaybeRef[bool] = True,
|
|
28
|
+
elevated: TMaybeRef[bool] = False,
|
|
29
|
+
top_corner: TMaybeRef[bool] = False,
|
|
30
|
+
bottom_corner: TMaybeRef[bool] = False,
|
|
31
|
+
) -> None:
|
|
32
|
+
kws = {
|
|
33
|
+
"side": side,
|
|
34
|
+
"overlay": overlay,
|
|
35
|
+
"value": value,
|
|
36
|
+
"fixed": fixed,
|
|
37
|
+
"bordered": bordered,
|
|
38
|
+
"elevated": elevated,
|
|
39
|
+
"top_corner": top_corner,
|
|
40
|
+
"bottom_corner": bottom_corner,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
44
|
+
del value_kws["side"]
|
|
45
|
+
del value_kws["overlay"]
|
|
46
|
+
|
|
47
|
+
element = None
|
|
48
|
+
|
|
49
|
+
if to_value(side) == "left":
|
|
50
|
+
element = ui.left_drawer(**value_kws)
|
|
51
|
+
else:
|
|
52
|
+
element = ui.right_drawer(**value_kws)
|
|
53
|
+
|
|
54
|
+
element.style(f"background-color:rgba(25, 118, 210,0.3)")
|
|
55
|
+
element.classes("flex flex-col gap-4")
|
|
56
|
+
|
|
57
|
+
init_value = (
|
|
58
|
+
element._props["model-value"]
|
|
59
|
+
if "model-value" in element._props
|
|
60
|
+
else element._props["show-if-above"]
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
super().__init__(value, element)
|
|
64
|
+
|
|
65
|
+
@effect
|
|
66
|
+
def _():
|
|
67
|
+
value = "true" if self.value else "false"
|
|
68
|
+
element.props(f":model-value={value}")
|
|
69
|
+
|
|
70
|
+
def on_update(e):
|
|
71
|
+
self._ref.value = e.args
|
|
72
|
+
|
|
73
|
+
element.on("update:modelValue", on_update)
|
|
74
|
+
|
|
75
|
+
for key, value in kws.items():
|
|
76
|
+
if is_ref(value):
|
|
77
|
+
self.bind_prop(key, value) # type: ignore
|
|
78
|
+
|
|
79
|
+
def toggle(self):
|
|
80
|
+
self.element.toggle()
|
|
81
|
+
return self
|
|
82
|
+
|
|
83
|
+
def __enter__(self):
|
|
84
|
+
self.element.__enter__()
|
|
85
|
+
return self
|
|
86
|
+
|
|
87
|
+
def __exit__(self, *_: Any):
|
|
88
|
+
self.element.__exit__(*_)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Dict,
|
|
3
|
+
)
|
|
4
|
+
from signe import effect
|
|
5
|
+
from ex4nicegui.utils.signals import (
|
|
6
|
+
ReadonlyRef,
|
|
7
|
+
is_ref,
|
|
8
|
+
ref_computed,
|
|
9
|
+
_TMaybeRef as TMaybeRef,
|
|
10
|
+
)
|
|
11
|
+
from .base import BindableUi
|
|
12
|
+
from .utils import _convert_kws_ref2value
|
|
13
|
+
from ex4nicegui.reactive.ECharts.ECharts import echarts
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EChartsBindableUi(BindableUi[echarts]):
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
options: TMaybeRef[Dict],
|
|
20
|
+
) -> None:
|
|
21
|
+
kws = {
|
|
22
|
+
"options": options,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
26
|
+
|
|
27
|
+
element = echarts(**value_kws)
|
|
28
|
+
|
|
29
|
+
super().__init__(element)
|
|
30
|
+
|
|
31
|
+
for key, value in kws.items():
|
|
32
|
+
if is_ref(value):
|
|
33
|
+
self.bind_prop(key, value) # type: ignore
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _pyecharts2opts(chart):
|
|
37
|
+
import simplejson as json
|
|
38
|
+
from pyecharts.charts.chart import Base
|
|
39
|
+
|
|
40
|
+
if isinstance(chart, Base):
|
|
41
|
+
return json.loads(chart.dump_options())
|
|
42
|
+
|
|
43
|
+
return {}
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def from_pyecharts(chart: TMaybeRef):
|
|
47
|
+
if is_ref(chart):
|
|
48
|
+
|
|
49
|
+
@ref_computed
|
|
50
|
+
def chart_opt():
|
|
51
|
+
return EChartsBindableUi._pyecharts2opts(chart.value)
|
|
52
|
+
|
|
53
|
+
return EChartsBindableUi(chart_opt)
|
|
54
|
+
|
|
55
|
+
return EChartsBindableUi(EChartsBindableUi._pyecharts2opts(chart))
|
|
56
|
+
|
|
57
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
58
|
+
if prop == "options":
|
|
59
|
+
return self.bind_options(ref_ui)
|
|
60
|
+
|
|
61
|
+
return super().bind_prop(prop, ref_ui)
|
|
62
|
+
|
|
63
|
+
def bind_options(self, ref_ui: ReadonlyRef[Dict]):
|
|
64
|
+
@effect
|
|
65
|
+
def _():
|
|
66
|
+
ele = self.element
|
|
67
|
+
ele.update_options(ref_ui.value)
|
|
68
|
+
ele.update()
|
|
69
|
+
|
|
70
|
+
return self
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from signe import effect
|
|
3
|
+
from ex4nicegui.utils.signals import (
|
|
4
|
+
ReadonlyRef,
|
|
5
|
+
is_ref,
|
|
6
|
+
_TMaybeRef as TMaybeRef,
|
|
7
|
+
)
|
|
8
|
+
from nicegui import ui
|
|
9
|
+
from .base import SingleValueBindableUi
|
|
10
|
+
from .utils import _convert_kws_ref2value
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class HtmlBindableUi(SingleValueBindableUi[str, ui.html]):
|
|
14
|
+
@staticmethod
|
|
15
|
+
def _setup_(binder: "HtmlBindableUi"):
|
|
16
|
+
first = True
|
|
17
|
+
|
|
18
|
+
@effect
|
|
19
|
+
def _():
|
|
20
|
+
nonlocal first
|
|
21
|
+
|
|
22
|
+
async def task():
|
|
23
|
+
pass
|
|
24
|
+
await ui.run_javascript(
|
|
25
|
+
f"getElement({binder.element.id}).innerText= '{binder.value}' ",
|
|
26
|
+
respond=False,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if not first:
|
|
30
|
+
asyncio.run(task())
|
|
31
|
+
else:
|
|
32
|
+
first = False
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
content: TMaybeRef[str] = "",
|
|
37
|
+
) -> None:
|
|
38
|
+
kws = {
|
|
39
|
+
"content": content,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
43
|
+
|
|
44
|
+
element = ui.html(**value_kws)
|
|
45
|
+
|
|
46
|
+
super().__init__(content, element)
|
|
47
|
+
|
|
48
|
+
for key, value in kws.items():
|
|
49
|
+
if is_ref(value):
|
|
50
|
+
self.bind_prop(key, value) # type: ignore
|
|
51
|
+
|
|
52
|
+
HtmlBindableUi._setup_(self)
|
|
53
|
+
|
|
54
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
55
|
+
if prop == "color":
|
|
56
|
+
return self.bind_color(ref_ui)
|
|
57
|
+
|
|
58
|
+
return super().bind_prop(prop, ref_ui)
|
|
59
|
+
|
|
60
|
+
def bind_color(self, ref_ui: ReadonlyRef):
|
|
61
|
+
@effect
|
|
62
|
+
def _():
|
|
63
|
+
ele = self.element
|
|
64
|
+
color = ref_ui.value
|
|
65
|
+
ele._style["color"] = color
|
|
66
|
+
ele.update()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Optional,
|
|
3
|
+
cast,
|
|
4
|
+
)
|
|
5
|
+
from signe import effect
|
|
6
|
+
from ex4nicegui.utils.signals import (
|
|
7
|
+
ReadonlyRef,
|
|
8
|
+
is_ref,
|
|
9
|
+
_TMaybeRef as TMaybeRef,
|
|
10
|
+
)
|
|
11
|
+
from nicegui import ui
|
|
12
|
+
from nicegui.elements.mixins.color_elements import (
|
|
13
|
+
TextColorElement,
|
|
14
|
+
)
|
|
15
|
+
from .base import SingleValueBindableUi, _bind_color
|
|
16
|
+
from .utils import _convert_kws_ref2value
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class IconBindableUi(SingleValueBindableUi[str, ui.icon]):
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
name: TMaybeRef[str],
|
|
23
|
+
*,
|
|
24
|
+
size: Optional[TMaybeRef[str]] = None,
|
|
25
|
+
color: Optional[TMaybeRef[str]] = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
kws = {
|
|
28
|
+
"name": name,
|
|
29
|
+
"size": size,
|
|
30
|
+
"color": color,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
34
|
+
|
|
35
|
+
element = ui.icon(**value_kws)
|
|
36
|
+
|
|
37
|
+
super().__init__(name, element)
|
|
38
|
+
|
|
39
|
+
for key, value in kws.items():
|
|
40
|
+
if is_ref(value):
|
|
41
|
+
self.bind_prop(key, value) # type: ignore
|
|
42
|
+
|
|
43
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
44
|
+
if prop == "name":
|
|
45
|
+
return self.bind_name(ref_ui)
|
|
46
|
+
|
|
47
|
+
if prop == "color":
|
|
48
|
+
return self.bind_color(ref_ui)
|
|
49
|
+
|
|
50
|
+
return super().bind_prop(prop, ref_ui)
|
|
51
|
+
|
|
52
|
+
def bind_color(self, ref_ui: ReadonlyRef):
|
|
53
|
+
return _bind_color(self, ref_ui)
|
|
54
|
+
|
|
55
|
+
def bind_name(self, ref_ui: ReadonlyRef):
|
|
56
|
+
@effect
|
|
57
|
+
def _():
|
|
58
|
+
ele = cast(TextColorElement, self.element)
|
|
59
|
+
ele._props["name"] = ref_ui.value
|
|
60
|
+
ele.update()
|
|
61
|
+
|
|
62
|
+
return self
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import (
|
|
3
|
+
Union,
|
|
4
|
+
)
|
|
5
|
+
from signe import effect
|
|
6
|
+
from ex4nicegui.utils.signals import (
|
|
7
|
+
ReadonlyRef,
|
|
8
|
+
is_ref,
|
|
9
|
+
_TMaybeRef as TMaybeRef,
|
|
10
|
+
)
|
|
11
|
+
from nicegui import ui
|
|
12
|
+
from .base import SingleValueBindableUi
|
|
13
|
+
from .utils import _convert_kws_ref2value
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ImageBindableUi(SingleValueBindableUi[Union[str, Path], ui.image]):
|
|
17
|
+
@staticmethod
|
|
18
|
+
def _setup_(binder: "ImageBindableUi"):
|
|
19
|
+
@effect
|
|
20
|
+
def _():
|
|
21
|
+
binder.element.on_source_change(binder.value)
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
source: Union[TMaybeRef[str], TMaybeRef[Path]] = "",
|
|
26
|
+
) -> None:
|
|
27
|
+
kws = {
|
|
28
|
+
"source": source,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
32
|
+
|
|
33
|
+
element = ui.image(**value_kws)
|
|
34
|
+
|
|
35
|
+
super().__init__(source, element) # type: ignore
|
|
36
|
+
|
|
37
|
+
for key, value in kws.items():
|
|
38
|
+
if is_ref(value):
|
|
39
|
+
self.bind_prop(key, value) # type: ignore
|
|
40
|
+
|
|
41
|
+
# ImageBindableUi._setup_(self)
|
|
42
|
+
|
|
43
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
44
|
+
if prop == "source":
|
|
45
|
+
return self.bind_source(ref_ui)
|
|
46
|
+
|
|
47
|
+
return super().bind_prop(prop, ref_ui)
|
|
48
|
+
|
|
49
|
+
def bind_source(self, ref_ui: ReadonlyRef[Union[str, Path]]):
|
|
50
|
+
@effect
|
|
51
|
+
def _():
|
|
52
|
+
ele = self.element
|
|
53
|
+
source = ref_ui.value
|
|
54
|
+
ele.on_source_change(source)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Any,
|
|
3
|
+
Callable,
|
|
4
|
+
List,
|
|
5
|
+
Optional,
|
|
6
|
+
Dict,
|
|
7
|
+
)
|
|
8
|
+
from signe import effect
|
|
9
|
+
from ex4nicegui.utils.signals import (
|
|
10
|
+
ReadonlyRef,
|
|
11
|
+
is_ref,
|
|
12
|
+
_TMaybeRef as TMaybeRef,
|
|
13
|
+
)
|
|
14
|
+
from nicegui import ui
|
|
15
|
+
from .base import SingleValueBindableUi
|
|
16
|
+
from .utils import _convert_kws_ref2value
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class InputBindableUi(SingleValueBindableUi[str, ui.input]):
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
label: Optional[TMaybeRef[str]] = None,
|
|
23
|
+
*,
|
|
24
|
+
placeholder: Optional[TMaybeRef[str]] = None,
|
|
25
|
+
value: TMaybeRef[str] = "",
|
|
26
|
+
password: TMaybeRef[bool] = False,
|
|
27
|
+
password_toggle_button: TMaybeRef[bool] = False,
|
|
28
|
+
on_change: Optional[Callable[..., Any]] = None,
|
|
29
|
+
autocomplete: Optional[TMaybeRef[List[str]]] = None,
|
|
30
|
+
validation: Dict[str, Callable[..., bool]] = {},
|
|
31
|
+
) -> None:
|
|
32
|
+
kws = {
|
|
33
|
+
"label": label,
|
|
34
|
+
"placeholder": placeholder,
|
|
35
|
+
"value": value,
|
|
36
|
+
"password": password,
|
|
37
|
+
"password_toggle_button": password_toggle_button,
|
|
38
|
+
"autocomplete": autocomplete,
|
|
39
|
+
"validation": validation,
|
|
40
|
+
"on_change": on_change,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
44
|
+
|
|
45
|
+
element = ui.input(**value_kws)
|
|
46
|
+
|
|
47
|
+
super().__init__(value, element)
|
|
48
|
+
|
|
49
|
+
for key, value in kws.items():
|
|
50
|
+
if is_ref(value) and key != "value":
|
|
51
|
+
self.bind_prop(key, value) # type: ignore
|
|
52
|
+
|
|
53
|
+
self._ex_setup()
|
|
54
|
+
|
|
55
|
+
def _ex_setup(self):
|
|
56
|
+
ele = self.element
|
|
57
|
+
|
|
58
|
+
@effect
|
|
59
|
+
def _():
|
|
60
|
+
ele.value = self.value
|
|
61
|
+
|
|
62
|
+
def onModelValueChanged(e):
|
|
63
|
+
self._ref.value = e.args or "" # type: ignore
|
|
64
|
+
|
|
65
|
+
ele.on("update:modelValue", handler=onModelValueChanged)
|
|
66
|
+
|
|
67
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
68
|
+
if prop == "value":
|
|
69
|
+
return self.bind_value(ref_ui)
|
|
70
|
+
|
|
71
|
+
return super().bind_prop(prop, ref_ui)
|
|
72
|
+
|
|
73
|
+
def bind_value(self, ref_ui: ReadonlyRef[bool]):
|
|
74
|
+
@effect
|
|
75
|
+
def _():
|
|
76
|
+
self.element.on_value_change(ref_ui.value)
|
|
77
|
+
|
|
78
|
+
return self
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class LazyInputBindableUi(InputBindableUi):
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
label: Optional[TMaybeRef[str]] = None,
|
|
85
|
+
*,
|
|
86
|
+
placeholder: Optional[TMaybeRef[str]] = None,
|
|
87
|
+
value: TMaybeRef[str] = "",
|
|
88
|
+
password: TMaybeRef[bool] = False,
|
|
89
|
+
password_toggle_button: TMaybeRef[bool] = False,
|
|
90
|
+
on_change: Optional[Callable[..., Any]] = None,
|
|
91
|
+
autocomplete: Optional[TMaybeRef[List[str]]] = None,
|
|
92
|
+
validation: Dict[str, Callable[..., bool]] = {},
|
|
93
|
+
) -> None:
|
|
94
|
+
super().__init__(
|
|
95
|
+
label,
|
|
96
|
+
placeholder=placeholder,
|
|
97
|
+
value=value,
|
|
98
|
+
password=password,
|
|
99
|
+
password_toggle_button=password_toggle_button,
|
|
100
|
+
on_change=on_change,
|
|
101
|
+
autocomplete=autocomplete,
|
|
102
|
+
validation=validation,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _ex_setup(self):
|
|
106
|
+
ele = self.element
|
|
107
|
+
|
|
108
|
+
@effect
|
|
109
|
+
def _():
|
|
110
|
+
ele.value = self.value
|
|
111
|
+
|
|
112
|
+
def onValueChanged():
|
|
113
|
+
self._ref.value = ele.value or ""
|
|
114
|
+
|
|
115
|
+
ele.on("blur", onValueChanged)
|
|
116
|
+
ele.on("keyup.enter", onValueChanged)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from signe import effect
|
|
2
|
+
from ex4nicegui.utils.signals import (
|
|
3
|
+
ReadonlyRef,
|
|
4
|
+
is_ref,
|
|
5
|
+
_TMaybeRef as TMaybeRef,
|
|
6
|
+
)
|
|
7
|
+
from nicegui import ui
|
|
8
|
+
from .base import SingleValueBindableUi
|
|
9
|
+
from .utils import _convert_kws_ref2value
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LabelBindableUi(SingleValueBindableUi[str, ui.label]):
|
|
13
|
+
@staticmethod
|
|
14
|
+
def _setup_(binder: "LabelBindableUi"):
|
|
15
|
+
def onValueChanged(e):
|
|
16
|
+
binder._ref.value = e.args["label"] # type: ignore
|
|
17
|
+
|
|
18
|
+
@effect
|
|
19
|
+
def _():
|
|
20
|
+
binder.element.text = binder.value
|
|
21
|
+
|
|
22
|
+
binder.element.on("update:modelValue", handler=onValueChanged)
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
text: TMaybeRef[str] = "",
|
|
27
|
+
) -> None:
|
|
28
|
+
kws = {
|
|
29
|
+
"text": text,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
33
|
+
|
|
34
|
+
element = ui.label(**value_kws)
|
|
35
|
+
|
|
36
|
+
super().__init__(text, element)
|
|
37
|
+
|
|
38
|
+
for key, value in kws.items():
|
|
39
|
+
if is_ref(value):
|
|
40
|
+
self.bind_prop(key, value) # type: ignore
|
|
41
|
+
|
|
42
|
+
LabelBindableUi._setup_(self)
|
|
43
|
+
|
|
44
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
45
|
+
if prop == "text":
|
|
46
|
+
return self.bind_text(ref_ui)
|
|
47
|
+
|
|
48
|
+
if prop == "color":
|
|
49
|
+
return self.bind_color(ref_ui)
|
|
50
|
+
|
|
51
|
+
return super().bind_prop(prop, ref_ui)
|
|
52
|
+
|
|
53
|
+
def bind_color(self, ref_ui: ReadonlyRef):
|
|
54
|
+
@effect
|
|
55
|
+
def _():
|
|
56
|
+
ele = self.element
|
|
57
|
+
color = ref_ui.value
|
|
58
|
+
ele._style["color"] = color
|
|
59
|
+
ele.update()
|
|
60
|
+
|
|
61
|
+
def bind_text(self, ref_ui: ReadonlyRef):
|
|
62
|
+
@effect
|
|
63
|
+
def _():
|
|
64
|
+
self.element.on_text_change(str(ref_ui.value))
|
|
65
|
+
# self.element.update()
|
|
66
|
+
|
|
67
|
+
return self
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Any,
|
|
3
|
+
Callable,
|
|
4
|
+
List,
|
|
5
|
+
Optional,
|
|
6
|
+
TypeVar,
|
|
7
|
+
cast,
|
|
8
|
+
Dict,
|
|
9
|
+
Union,
|
|
10
|
+
)
|
|
11
|
+
from signe import effect
|
|
12
|
+
from ex4nicegui.utils.signals import (
|
|
13
|
+
ReadonlyRef,
|
|
14
|
+
is_ref,
|
|
15
|
+
_TMaybeRef as TMaybeRef,
|
|
16
|
+
)
|
|
17
|
+
from nicegui import ui
|
|
18
|
+
from nicegui.elements.mixins.value_element import ValueElement
|
|
19
|
+
from .base import SingleValueBindableUi
|
|
20
|
+
from .utils import _convert_kws_ref2value
|
|
21
|
+
|
|
22
|
+
T = TypeVar("T")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RadioBindableUi(SingleValueBindableUi[bool, ui.radio]):
|
|
26
|
+
@staticmethod
|
|
27
|
+
def _setup_(binder: "RadioBindableUi"):
|
|
28
|
+
def onValueChanged(e):
|
|
29
|
+
binder._ref.value = binder.element.options[e.args] # type: ignore
|
|
30
|
+
|
|
31
|
+
@effect
|
|
32
|
+
def _():
|
|
33
|
+
binder.element.value = binder.value
|
|
34
|
+
|
|
35
|
+
binder.element.on("update:modelValue", handler=onValueChanged)
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
options: Union[TMaybeRef[List], TMaybeRef[Dict]],
|
|
40
|
+
*,
|
|
41
|
+
value: TMaybeRef[Any] = None,
|
|
42
|
+
on_change: Optional[Callable[..., Any]] = None,
|
|
43
|
+
) -> None:
|
|
44
|
+
kws = {"options": options, "value": value, "on_change": on_change}
|
|
45
|
+
|
|
46
|
+
value_kws = _convert_kws_ref2value(kws)
|
|
47
|
+
|
|
48
|
+
element = ui.radio(**value_kws)
|
|
49
|
+
|
|
50
|
+
super().__init__(value, element)
|
|
51
|
+
|
|
52
|
+
for key, value in kws.items():
|
|
53
|
+
if is_ref(value):
|
|
54
|
+
self.bind_prop(key, value)
|
|
55
|
+
|
|
56
|
+
RadioBindableUi._setup_(self)
|
|
57
|
+
|
|
58
|
+
def bind_prop(self, prop: str, ref_ui: ReadonlyRef):
|
|
59
|
+
if prop == "value":
|
|
60
|
+
return self.bind_value(ref_ui)
|
|
61
|
+
|
|
62
|
+
if prop == "options":
|
|
63
|
+
return self.bind_options(ref_ui)
|
|
64
|
+
|
|
65
|
+
return super().bind_prop(prop, ref_ui)
|
|
66
|
+
|
|
67
|
+
def bind_options(self, ref_ui: ReadonlyRef):
|
|
68
|
+
@effect
|
|
69
|
+
def _():
|
|
70
|
+
self.element.options = ref_ui.value
|
|
71
|
+
self.element.update()
|
|
72
|
+
|
|
73
|
+
return self
|
|
74
|
+
|
|
75
|
+
def bind_value(self, ref_ui: ReadonlyRef):
|
|
76
|
+
@effect
|
|
77
|
+
def _():
|
|
78
|
+
cast(ValueElement, self.element).on_value_change(ref_ui.value)
|
|
79
|
+
|
|
80
|
+
return self
|