ex4nicegui 0.8.4__py3-none-any.whl → 0.8.6__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.
@@ -1,5 +1,6 @@
1
1
  from typing import (
2
2
  Any,
3
+ Dict,
3
4
  Optional,
4
5
  )
5
6
  from dataclasses import dataclass, fields
@@ -11,16 +12,16 @@ from nicegui.events import (
11
12
 
12
13
  @dataclass(**KWONLY_SLOTS)
13
14
  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
15
+ componentType: Optional[str] = None
16
+ seriesType: Optional[str] = None
17
+ seriesIndex: Optional[int] = None
18
+ seriesName: Optional[str] = None
19
+ name: Optional[str] = None
20
+ dataIndex: Optional[int] = None
21
+ data: Optional[Dict] = None
22
+ dataType: Optional[str] = None
23
+ value: Optional[Any] = None
24
+ color: Optional[str] = None
24
25
 
25
26
 
26
27
  _Mouse_Event_Arguments_Fields = [f.name for f in fields(EChartsMouseEventArguments)]
@@ -26,19 +26,6 @@ def create_event_handler_args(
26
26
  event_name: _T_event_name, e: GenericEventArguments
27
27
  ) -> UiEventArguments:
28
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
- )
29
+ return EChartsMouseEventArguments(sender=e.sender, client=e.client, **e.args)
43
30
 
44
31
  return GenericEventArguments(sender=e.sender, client=e.client, args=e.args)
@@ -59,7 +59,9 @@ from .officials.toggle import ToggleBindableUi as toggle
59
59
  from .officials.avatar import AvatarBindableUi as avatar
60
60
  from .officials.badge import BadgeBindableUi as badge
61
61
  from .officials.range import RangeBindableUi as range
62
-
62
+ from .officials.range import LazyRangeBindableUi as lazy_range
63
+ from .officials.tree import TreeBindableUi as tree
64
+ from .officials.spinner import SpinnerBindableUi as spinner
63
65
 
64
66
  from .local_file_picker import local_file_picker
65
67
  from .UseDraggable.UseDraggable import use_draggable
@@ -142,4 +144,7 @@ __all__ = [
142
144
  "avatar",
143
145
  "badge",
144
146
  "range",
147
+ "lazy_range",
148
+ "tree",
149
+ "spinner",
145
150
  ]
@@ -8,14 +8,21 @@ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
8
8
 
9
9
  from nicegui import ui
10
10
  from .base import BindableUi
11
- from ex4nicegui.utils.signals import _TMaybeRef as TMaybeRef
11
+ from ex4nicegui.utils.signals import (
12
+ _TMaybeRef as TMaybeRef,
13
+ TGetterOrReadonlyRef,
14
+ to_value,
15
+ )
16
+
17
+
18
+ _T_Template = Union[TMaybeRef[str], TMaybeRef[int]]
12
19
 
13
20
 
14
21
  class GridBindableUi(BindableUi[ui.grid]):
15
22
  def __init__(
16
23
  self,
17
- rows: Optional[TMaybeRef[Union[int, str]]] = None,
18
- columns: Optional[TMaybeRef[Union[int, str]]] = None,
24
+ rows: Optional[_T_Template] = None,
25
+ columns: Optional[_T_Template] = None,
19
26
  ) -> None:
20
27
  pc = ParameterClassifier(locals(), maybeRefs=["rows", "columns"], events=[])
21
28
 
@@ -25,6 +32,39 @@ class GridBindableUi(BindableUi[ui.grid]):
25
32
  for key, value in pc.get_bindings().items():
26
33
  self.bind_prop(key, value) # type: ignore
27
34
 
35
+ def bind_prop(self, prop: str, value: TGetterOrReadonlyRef):
36
+ if prop == "rows":
37
+ return self.bind_rows(value)
38
+
39
+ if prop == "columns":
40
+ return self.bind_columns(value)
41
+
42
+ return super().bind_prop(prop, value)
43
+
44
+ def bind_rows(self, rows: TGetterOrReadonlyRef[Union[int, str]]):
45
+ def template():
46
+ _rows = to_value(rows)
47
+ return (
48
+ f"repeat({_rows}, minmax(0, 1fr))" if isinstance(_rows, int) else _rows
49
+ )
50
+
51
+ self.bind_style({"grid-template-rows": template})
52
+
53
+ return self
54
+
55
+ def bind_columns(self, columns: TGetterOrReadonlyRef[Union[int, str]]):
56
+ def template():
57
+ _columns = to_value(columns)
58
+ return (
59
+ f"repeat({_columns}, minmax(0, 1fr))"
60
+ if isinstance(_columns, int)
61
+ else _columns
62
+ )
63
+
64
+ self.bind_style({"grid-template-columns": template})
65
+
66
+ return self
67
+
28
68
  def __enter__(self):
29
69
  self.element.__enter__()
30
70
  return self
@@ -64,9 +64,32 @@ class InputBindableUi(
64
64
  if prop == "password":
65
65
  return self.bind_password(value)
66
66
 
67
+ if prop == "autocomplete":
68
+ return self.bind_autocomplete(value)
69
+
67
70
  return super().bind_prop(prop, value)
68
71
 
72
+ def bind_autocomplete(self, autocomplete: TGetterOrReadonlyRef[List[str]]):
73
+ """Binds the autocomplete attribute of the input element.
74
+
75
+ Args:
76
+ autocomplete (TGetterOrReadonlyRef[List[str]]): The getter or readonly reference to the autocomplete list.
77
+ """
78
+
79
+ @self._ui_signal_on(autocomplete)
80
+ def _():
81
+ self.element.set_autocomplete(to_value(autocomplete))
82
+
83
+ return self
84
+
69
85
  def bind_password(self, password: TGetterOrReadonlyRef[bool]):
86
+ """Binds the password attribute of the input element.
87
+
88
+ Args:
89
+ password (TGetterOrReadonlyRef[bool]): The getter or readonly reference to the password state.
90
+
91
+ """
92
+
70
93
  @self._ui_signal_on(password)
71
94
  def _():
72
95
  self.element._props["type"] = "password" if to_value(password) else "text"
@@ -8,6 +8,9 @@ from typing import (
8
8
  Union,
9
9
  )
10
10
  from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
11
+ from ex4nicegui.reactive.systems.reactive_system import (
12
+ convert_to_none_if_outside_options,
13
+ )
11
14
  from ex4nicegui.utils.signals import (
12
15
  TGetterOrReadonlyRef,
13
16
  _TMaybeRef as TMaybeRef,
@@ -51,8 +54,8 @@ class RadioBindableUi(BindableUi[ui.radio], ValueElementMixin[Any]):
51
54
  return self.element.value
52
55
 
53
56
  def bind_prop(self, prop: str, value: TGetterOrReadonlyRef):
54
- if ValueElementMixin._bind_specified_props(self, prop, value):
55
- return self
57
+ if prop == "value":
58
+ return self.bind_value(value)
56
59
 
57
60
  if prop == "options":
58
61
  return self.bind_options(value)
@@ -66,3 +69,11 @@ class RadioBindableUi(BindableUi[ui.radio], ValueElementMixin[Any]):
66
69
  self.element.set_options(to_value(options))
67
70
 
68
71
  return self
72
+
73
+ def bind_value(self, value: TGetterOrReadonlyRef):
74
+ @self._ui_signal_on(value, deep=True)
75
+ def _():
76
+ new_value = convert_to_none_if_outside_options(value, self.element.options)
77
+ self.element.set_value(new_value)
78
+
79
+ return self
@@ -1,11 +1,13 @@
1
1
  from typing import Any, Callable, Optional, Dict, cast
2
2
 
3
3
 
4
+ from ex4nicegui.utils.signals import to_value, is_setter_ref
4
5
  from ex4nicegui.utils.signals import (
5
6
  _TMaybeRef as TMaybeRef,
6
7
  )
7
8
 
8
9
  from nicegui import ui
10
+ from nicegui.events import handle_event
9
11
  from ex4nicegui.reactive.base import BindableUi, DisableableMixin
10
12
  from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
11
13
  from ex4nicegui.reactive.mixins.value_element import ValueElementMixin
@@ -43,3 +45,43 @@ class RangeBindableUi(
43
45
  @property
44
46
  def value(self):
45
47
  return cast(Dict[str, int], self.element.value)
48
+
49
+
50
+ class LazyRangeBindableUi(
51
+ RangeBindableUi,
52
+ ):
53
+ def __init__(
54
+ self,
55
+ *,
56
+ min: TMaybeRef[float], # pylint: disable=redefined-builtin
57
+ max: TMaybeRef[float], # pylint: disable=redefined-builtin
58
+ step: TMaybeRef[float] = 1.0,
59
+ value: Optional[TMaybeRef[Dict[str, int]]] = None,
60
+ on_change: Optional[Callable[..., Any]] = None,
61
+ on_update: Optional[Callable[..., Any]] = None,
62
+ ) -> None:
63
+ """A lazy version of `rxui.range` that only updates the value when the user releases the range.
64
+
65
+ Args:
66
+ min (TMaybeRef[float]): lower bound of the range
67
+ max (TMaybeRef[float]): upper bound of the range
68
+ step (TMaybeRef[float], optional): step size. Defaults to 1.0.
69
+ value (Optional[TMaybeRef[Dict[str, int]]], optional): initial value to set min and max position of the range. Defaults to None.
70
+ on_change (Optional[Callable[..., Any]], optional): callback which is invoked when the user releases the range. Defaults to None.
71
+ on_update (Optional[Callable[..., Any]], optional): callback which is invoked when the component needs to change. Defaults to None.
72
+ """
73
+ super().__init__(
74
+ min=min,
75
+ max=max,
76
+ step=step,
77
+ value=lambda: to_value(value), # type: ignore
78
+ on_change=on_update,
79
+ )
80
+
81
+ if is_setter_ref(value):
82
+
83
+ def new_on_change(e):
84
+ value.set_value(e.args) # type: ignore
85
+ handle_event(on_change, e)
86
+
87
+ self.on("change", new_on_change)
@@ -4,7 +4,6 @@ from typing import (
4
4
  List,
5
5
  Optional,
6
6
  TypeVar,
7
- cast,
8
7
  Dict,
9
8
  Union,
10
9
  )
@@ -16,7 +15,6 @@ from ex4nicegui.utils.signals import (
16
15
  to_raw,
17
16
  )
18
17
  from nicegui import ui
19
- from nicegui.elements.mixins.value_element import ValueElement
20
18
  from .base import BindableUi
21
19
 
22
20
  T = TypeVar("T")
@@ -94,6 +92,6 @@ class SelectBindableUi(BindableUi[ui.select]):
94
92
  @self._ui_signal_on(value, deep=True)
95
93
  def _():
96
94
  ParameterClassifier.mark_event_source_as_internal(self.element)
97
- cast(ValueElement, self.element).set_value(to_raw(to_value(value)) or None)
95
+ self.element.set_value(to_raw(to_value(value)) or None)
98
96
 
99
97
  return self
@@ -0,0 +1,43 @@
1
+ from typing import Optional
2
+
3
+
4
+ from ex4nicegui.utils.signals import (
5
+ TGetterOrReadonlyRef,
6
+ _TMaybeRef as TMaybeRef,
7
+ )
8
+
9
+ from nicegui import ui
10
+ from ex4nicegui.reactive.base import BindableUi
11
+ from ex4nicegui.reactive.mixins.textColor import TextColorableMixin
12
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
13
+
14
+ from nicegui.elements.spinner import SpinnerTypes
15
+
16
+
17
+ class SpinnerBindableUi(BindableUi[ui.spinner], TextColorableMixin):
18
+ def __init__(
19
+ self,
20
+ type: Optional[SpinnerTypes] = "default",
21
+ *,
22
+ size: TMaybeRef[str] = "1em",
23
+ color: Optional[TMaybeRef[str]] = "primary",
24
+ thickness: TMaybeRef[float] = 5.0,
25
+ ) -> None:
26
+ pc = ParameterClassifier(
27
+ locals(), maybeRefs=["type", "size", "color", "thickness"]
28
+ )
29
+
30
+ value_kws = pc.get_values_kws()
31
+ element = ui.spinner(**value_kws)
32
+ super().__init__(element) # type: ignore
33
+
34
+ for key, value in pc.get_bindings().items():
35
+ self.bind_prop(key, value) # type: ignore
36
+
37
+ def bind_prop(self, prop: str, value: TGetterOrReadonlyRef):
38
+ if prop == "type":
39
+ raise ValueError("type cannot be bound")
40
+ elif prop == "color":
41
+ return self.bind_color(value)
42
+
43
+ return super().bind_prop(prop, value)
@@ -8,11 +8,13 @@ from typing import (
8
8
  Union,
9
9
  )
10
10
  from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
11
+ from ex4nicegui.reactive.systems.reactive_system import (
12
+ convert_to_none_if_outside_options,
13
+ )
11
14
  from ex4nicegui.utils.signals import (
12
15
  TGetterOrReadonlyRef,
13
16
  _TMaybeRef as TMaybeRef,
14
17
  to_value,
15
- to_raw,
16
18
  )
17
19
  from nicegui import ui
18
20
  from .base import BindableUi
@@ -83,7 +85,7 @@ class ToggleBindableUi(BindableUi[ui.toggle]):
83
85
  def bind_value(self, value: TGetterOrReadonlyRef):
84
86
  @self._ui_signal_on(value, deep=True)
85
87
  def _():
86
- ParameterClassifier.mark_event_source_as_internal(self.element)
87
- self.element.set_value(to_raw(to_value(value)) or None)
88
+ new_value = convert_to_none_if_outside_options(value, self.element.options)
89
+ self.element.set_value(new_value)
88
90
 
89
91
  return self
@@ -0,0 +1,86 @@
1
+ from typing import List, Literal, Optional, Dict
2
+
3
+ from ex4nicegui.utils.signals import (
4
+ _TMaybeRef as TMaybeRef,
5
+ )
6
+
7
+ from nicegui import ui
8
+ from nicegui.events import Handler, ValueChangeEventArguments
9
+ from .base import BindableUi
10
+ from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
11
+
12
+
13
+ class TreeBindableUi(
14
+ BindableUi[ui.tree],
15
+ ):
16
+ def __init__(
17
+ self,
18
+ nodes: TMaybeRef[List[Dict]],
19
+ *,
20
+ selected: Optional[TMaybeRef[str]] = None,
21
+ node_key: str = "id",
22
+ label_key: str = "label",
23
+ children_key: str = "children",
24
+ on_select: Optional[Handler[ValueChangeEventArguments]] = None,
25
+ on_expand: Optional[Handler[ValueChangeEventArguments]] = None,
26
+ on_tick: Optional[Handler[ValueChangeEventArguments]] = None,
27
+ tick_strategy: Optional[
28
+ TMaybeRef[Literal["leaf", "leaf-filtered", "strict"]]
29
+ ] = None,
30
+ ) -> None:
31
+ """Tree
32
+
33
+ Display hierarchical data using Quasar's `QTree <https://quasar.dev/vue-components/tree>`_ component.
34
+
35
+ If using IDs, make sure they are unique within the whole tree.
36
+
37
+ To use checkboxes and ``on_tick``, set the ``tick_strategy`` parameter to "leaf", "leaf-filtered" or "strict".
38
+
39
+
40
+ Args:
41
+ nodes (TMaybeRef[List[Dict]]): hierarchical list of node objects
42
+ selected (Optional[TMaybeRef[str]], optional): Key of node currently selected. Defaults to None.
43
+ node_key (str, optional): property name of each node object that holds its unique id. Defaults to "id".
44
+ label_key (str, optional): property name of each node object that holds its label. Defaults to "label".
45
+ children_key (str, optional): property name of each node object that holds its list of children. Defaults to "children".
46
+ on_select (Optional[Handler[ValueChangeEventArguments]], optional): callback which is invoked when the node selection changes. Defaults to None.
47
+ on_expand (Optional[Handler[ValueChangeEventArguments]], optional): callback which is invoked when the node expansion changes. Defaults to None.
48
+ on_tick (Optional[Handler[ValueChangeEventArguments]], optional): callback which is invoked when a node is ticked or unticked. Defaults to None.
49
+ tick_strategy (Optional[ TMaybeRef[Literal[&quot;leaf&quot;, &quot;leaf, optional): whether and how to use checkboxes. Defaults to None.
50
+
51
+
52
+ Example:
53
+ .. code-block:: python
54
+ from ex4nicegui import to_ref, rxui
55
+
56
+ selected = to_ref("")
57
+ nodes = to_ref(
58
+ [
59
+ {"id": "numbers", "children": [{"id": "1"}, {"id": "2"}]},
60
+ {"id": "letters", "children": [{"id": "A"}, {"id": "B"}]},
61
+ ]
62
+ )
63
+
64
+ rxui.label(lambda: f"Selected node: {selected.value}")
65
+ rxui.tree(nodes, selected=selected, label_key="id")
66
+ """
67
+ pc = ParameterClassifier(
68
+ locals(),
69
+ maybeRefs=[
70
+ "nodes",
71
+ "node_key",
72
+ "label_key",
73
+ "children_key",
74
+ "tick_strategy",
75
+ ],
76
+ v_model=("selected", "on_select"),
77
+ events=["on_select", "on_expand", "on_tick"],
78
+ )
79
+
80
+ value_kws = pc.get_values_kws()
81
+ value_kws.pop("selected")
82
+ element = ui.tree(**value_kws)
83
+ super().__init__(element) # type: ignore
84
+
85
+ for key, value in pc.get_bindings().items():
86
+ self.bind_prop(key, value) # type: ignore
@@ -1,5 +1,5 @@
1
- from typing import Callable, Dict
2
- from ex4nicegui.utils.signals import to_value, to_raw
1
+ from typing import Callable, Dict, List, Union
2
+ from ex4nicegui.utils.signals import to_value, to_raw, TGetterOrReadonlyRef
3
3
 
4
4
 
5
5
  def convert_kws_ref2value(kws: Dict) -> Dict:
@@ -19,3 +19,14 @@ def inject_method(obj, method_name: str, new_handle: Callable):
19
19
  raise AttributeError(
20
20
  f"'{type(obj).__name__}' object has no attribute '{method_name}'."
21
21
  )
22
+
23
+
24
+ def convert_to_none_if_outside_options(
25
+ value: TGetterOrReadonlyRef, options: Union[List, Dict]
26
+ ):
27
+ new_value = to_raw(to_value(value))
28
+
29
+ if new_value not in options:
30
+ new_value = None
31
+
32
+ return new_value
@@ -0,0 +1,5 @@
1
+ from .functions.dark import UseDark as use_dark
2
+ from .functions.breakpoint import UseBreakpoints as use_breakpoints
3
+ from .functions.qr_code import UseQRCode as use_qr_code
4
+
5
+ __all__ = ["use_dark", "use_breakpoints", "use_qr_code"]