ex4nicegui 0.6.7__py3-none-any.whl → 0.6.9__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 +12 -6
- ex4nicegui/gsap/__init__.py +11 -0
- ex4nicegui/helper/__init__.py +4 -0
- ex4nicegui/helper/client_instance_locker.py +31 -0
- ex4nicegui/reactive/__init__.py +4 -0
- ex4nicegui/reactive/base.py +426 -0
- ex4nicegui/reactive/deferredTask.py +3 -2
- ex4nicegui/reactive/local_file_picker.py +1 -2
- ex4nicegui/reactive/mixins/backgroundColor.py +41 -0
- ex4nicegui/reactive/mixins/disableable.py +44 -0
- ex4nicegui/reactive/mixins/textColor.py +66 -0
- ex4nicegui/reactive/officials/aggrid.py +4 -4
- ex4nicegui/reactive/officials/base.py +4 -351
- ex4nicegui/reactive/officials/button.py +36 -3
- ex4nicegui/reactive/officials/checkbox.py +2 -3
- ex4nicegui/reactive/officials/chip.py +102 -0
- ex4nicegui/reactive/officials/circular_progress.py +6 -5
- ex4nicegui/reactive/officials/color_picker.py +3 -4
- ex4nicegui/reactive/officials/column.py +1 -1
- ex4nicegui/reactive/officials/date.py +2 -3
- ex4nicegui/reactive/officials/drawer.py +2 -3
- ex4nicegui/reactive/officials/echarts.py +2 -3
- ex4nicegui/reactive/officials/expansion.py +2 -3
- ex4nicegui/reactive/officials/grid.py +4 -3
- ex4nicegui/reactive/officials/html.py +1 -3
- ex4nicegui/reactive/officials/icon.py +5 -9
- ex4nicegui/reactive/officials/image.py +2 -4
- ex4nicegui/reactive/officials/input.py +4 -6
- ex4nicegui/reactive/officials/knob.py +6 -4
- ex4nicegui/reactive/officials/label.py +3 -10
- ex4nicegui/reactive/officials/linear_progress.py +5 -9
- ex4nicegui/reactive/officials/number.py +3 -6
- ex4nicegui/reactive/officials/radio.py +3 -5
- ex4nicegui/reactive/officials/row.py +1 -1
- ex4nicegui/reactive/officials/select.py +3 -5
- ex4nicegui/reactive/officials/slider.py +4 -6
- ex4nicegui/reactive/officials/switch.py +2 -4
- ex4nicegui/reactive/officials/tab.py +1 -1
- ex4nicegui/reactive/officials/tab_panel.py +1 -1
- ex4nicegui/reactive/officials/tab_panels.py +109 -3
- ex4nicegui/reactive/officials/table.py +7 -6
- ex4nicegui/reactive/officials/tabs.py +1 -1
- ex4nicegui/reactive/officials/textarea.py +3 -5
- ex4nicegui/reactive/officials/upload.py +2 -2
- ex4nicegui/reactive/q_pagination.py +2 -2
- ex4nicegui/reactive/scopedStyle.js +55 -0
- ex4nicegui/reactive/scopedStyle.py +25 -0
- ex4nicegui/reactive/services/pandas_service.py +31 -0
- ex4nicegui/reactive/{utils.py → services/reactive_service.py} +9 -67
- ex4nicegui/reactive/systems/color_system.py +157 -0
- ex4nicegui/reactive/systems/object_system.py +33 -0
- ex4nicegui/reactive/systems/reactive_system.py +21 -0
- ex4nicegui/reactive/useMouse/UseMouse.py +4 -4
- ex4nicegui/reactive/usePagination.py +1 -1
- ex4nicegui/reactive/vfor.py +1 -2
- ex4nicegui/reactive/vmodel.py +1 -1
- ex4nicegui/utils/apiEffect.py +5 -1
- ex4nicegui/utils/effect.py +3 -2
- ex4nicegui/utils/refComputed.py +147 -0
- ex4nicegui/utils/refWrapper.py +57 -0
- ex4nicegui/utils/scheduler.py +20 -4
- ex4nicegui/utils/signals.py +51 -192
- ex4nicegui/utils/types.py +16 -0
- ex4nicegui/version.py +3 -0
- {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/METADATA +61 -4
- {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/RECORD +68 -58
- ex4nicegui/reactive/EChartsComponent/__init__.py +0 -0
- ex4nicegui/reactive/UseDraggable/__init__.py +0 -0
- ex4nicegui/reactive/dropZone/__init__.py +0 -0
- ex4nicegui/reactive/mermaid/__init__.py +0 -0
- ex4nicegui/reactive/officials/__init__.py +0 -1
- ex4nicegui/reactive/officials/utils.py +0 -11
- ex4nicegui/reactive/useMouse/__init__.py +0 -0
- {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/LICENSE +0 -0
- {ex4nicegui-0.6.7.dist-info → ex4nicegui-0.6.9.dist-info}/WHEEL +0 -0
|
@@ -6,18 +6,19 @@ from typing import (
|
|
|
6
6
|
Dict,
|
|
7
7
|
)
|
|
8
8
|
from typing_extensions import Literal
|
|
9
|
-
from ex4nicegui.reactive.
|
|
9
|
+
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
10
|
+
from ex4nicegui.reactive.services.pandas_service import dataframe2col_str
|
|
11
|
+
|
|
10
12
|
import ex4nicegui.utils.common as utils_common
|
|
11
13
|
from ex4nicegui.utils.signals import (
|
|
12
14
|
TGetterOrReadonlyRef,
|
|
13
|
-
|
|
15
|
+
TReadonlyRef,
|
|
14
16
|
is_ref,
|
|
15
17
|
ref_computed,
|
|
16
18
|
to_ref,
|
|
17
19
|
_TMaybeRef as TMaybeRef,
|
|
18
20
|
to_value,
|
|
19
21
|
to_raw,
|
|
20
|
-
on,
|
|
21
22
|
RefWrapper,
|
|
22
23
|
)
|
|
23
24
|
from nicegui import ui
|
|
@@ -67,7 +68,7 @@ class TableBindableUi(BindableUi[ui.table]):
|
|
|
67
68
|
|
|
68
69
|
self._arg_selection = selection
|
|
69
70
|
self._arg_row_key = row_key
|
|
70
|
-
self._selection_ref:
|
|
71
|
+
self._selection_ref: TReadonlyRef[List[Any]] = to_ref([]) # type: ignore
|
|
71
72
|
|
|
72
73
|
def on_selection(_):
|
|
73
74
|
self._selection_ref.value = self.element.selected # type: ignore
|
|
@@ -182,7 +183,7 @@ class TableBindableUi(BindableUi[ui.table]):
|
|
|
182
183
|
return self
|
|
183
184
|
|
|
184
185
|
def bind_rows(self, ref_ui: TGetterOrReadonlyRef[List[Dict]]):
|
|
185
|
-
@
|
|
186
|
+
@self._ui_signal_on(ref_ui, deep=True)
|
|
186
187
|
def _():
|
|
187
188
|
ele = self.element
|
|
188
189
|
ele._props["rows"] = list(to_raw(to_value(ref_ui)))
|
|
@@ -191,7 +192,7 @@ class TableBindableUi(BindableUi[ui.table]):
|
|
|
191
192
|
return self
|
|
192
193
|
|
|
193
194
|
def bind_columns(self, ref_ui: TGetterOrReadonlyRef[List[Dict]]):
|
|
194
|
-
@
|
|
195
|
+
@self._ui_signal_on(ref_ui, deep=True)
|
|
195
196
|
def _():
|
|
196
197
|
ele = self.element
|
|
197
198
|
ele._props["columns"] = list(to_raw(to_value(ref_ui)))
|
|
@@ -5,13 +5,11 @@ from typing import (
|
|
|
5
5
|
Dict,
|
|
6
6
|
cast,
|
|
7
7
|
)
|
|
8
|
-
from ex4nicegui.reactive.
|
|
9
|
-
from ex4nicegui.utils.apiEffect import ui_effect
|
|
8
|
+
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
10
9
|
from ex4nicegui.utils.signals import (
|
|
11
10
|
TGetterOrReadonlyRef,
|
|
12
11
|
Ref,
|
|
13
12
|
_TMaybeRef as TMaybeRef,
|
|
14
|
-
effect,
|
|
15
13
|
is_setter_ref,
|
|
16
14
|
to_value,
|
|
17
15
|
)
|
|
@@ -61,7 +59,7 @@ class TextareaBindableUi(BindableUi[ui.textarea]):
|
|
|
61
59
|
return super().bind_prop(prop, ref_ui)
|
|
62
60
|
|
|
63
61
|
def bind_value(self, ref_ui: TGetterOrReadonlyRef[str]):
|
|
64
|
-
@
|
|
62
|
+
@self._ui_effect
|
|
65
63
|
def _():
|
|
66
64
|
self.element.set_value(to_value(ref_ui))
|
|
67
65
|
|
|
@@ -95,7 +93,7 @@ class LazyTextareaBindableUi(TextareaBindableUi):
|
|
|
95
93
|
ref = cast(Ref, org_value)
|
|
96
94
|
ele = self.element
|
|
97
95
|
|
|
98
|
-
@
|
|
96
|
+
@self._ui_effect
|
|
99
97
|
def _():
|
|
100
98
|
ele.value = ref.value
|
|
101
99
|
|
|
@@ -11,7 +11,7 @@ from ex4nicegui.utils.signals import (
|
|
|
11
11
|
from nicegui import ui
|
|
12
12
|
from nicegui.events import handle_event
|
|
13
13
|
from .base import BindableUi
|
|
14
|
-
from .
|
|
14
|
+
from ex4nicegui.reactive.systems.reactive_system import convert_kws_ref2value
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class UploadResult:
|
|
@@ -57,7 +57,7 @@ class UploadBindableUi(BindableUi[ui.upload]):
|
|
|
57
57
|
"auto_upload": auto_upload,
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
value_kws =
|
|
60
|
+
value_kws = convert_kws_ref2value(kws)
|
|
61
61
|
|
|
62
62
|
self._on_upload_callbacks = []
|
|
63
63
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import Any, Optional, Callable
|
|
2
|
-
from ex4nicegui.reactive.
|
|
2
|
+
from ex4nicegui.reactive.services.reactive_service import ParameterClassifier
|
|
3
3
|
from ex4nicegui.utils.signals import (
|
|
4
4
|
TGetterOrReadonlyRef,
|
|
5
5
|
to_value,
|
|
6
|
-
|
|
6
|
+
TMaybeRef,
|
|
7
7
|
)
|
|
8
8
|
from nicegui import ui
|
|
9
9
|
from ex4nicegui.reactive.officials.base import BindableUi
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
const REGEX_NEWLINE = /[\r\n]/g;
|
|
3
|
+
const REGEX_START_SPACES = /^\s+/gm;
|
|
4
|
+
|
|
5
|
+
function getClasses(id) {
|
|
6
|
+
return `ex4ng-scoped-style-${id}`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function removeInvalidChars(str) {
|
|
10
|
+
str = str.replace(REGEX_START_SPACES, '');
|
|
11
|
+
return str.replace(REGEX_NEWLINE, '');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function appendCSS(styleElement, cssText) {
|
|
15
|
+
// 获取已有的 CSS 内容
|
|
16
|
+
let existingCSS = styleElement.textContent || '';
|
|
17
|
+
|
|
18
|
+
// 如果已有的 CSS 内容不为空,添加一个空行作为分隔符
|
|
19
|
+
if (existingCSS.trim() !== '') {
|
|
20
|
+
existingCSS += '\n';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 拼接新的 CSS 内容
|
|
24
|
+
existingCSS += cssText;
|
|
25
|
+
|
|
26
|
+
// 将新的 CSS 内容设置回 style 标签
|
|
27
|
+
styleElement.textContent = existingCSS;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default {
|
|
31
|
+
template: `<template></template>`,
|
|
32
|
+
methods: {
|
|
33
|
+
createStyle(id, css) {
|
|
34
|
+
css = removeInvalidChars(css);
|
|
35
|
+
|
|
36
|
+
const classes = getClasses(id);
|
|
37
|
+
const target = document.querySelector(`style.${classes}`);
|
|
38
|
+
if (target) {
|
|
39
|
+
appendCSS(target, css);
|
|
40
|
+
} else {
|
|
41
|
+
const style = document.createElement('style');
|
|
42
|
+
style.classList.add(classes);
|
|
43
|
+
style.innerHTML = css;
|
|
44
|
+
document.head.appendChild(style);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
removeStyle(id) {
|
|
48
|
+
const classes = getClasses(id);
|
|
49
|
+
const target = document.querySelector(`style.${classes}`);
|
|
50
|
+
if (target) {
|
|
51
|
+
target.remove();
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from nicegui.element import Element
|
|
2
|
+
from ex4nicegui.helper import client_instance_locker
|
|
3
|
+
from nicegui import ui
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ScopedStyle(Element, component="scopedStyle.js"):
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def get():
|
|
11
|
+
if not ui.context.slot_stack:
|
|
12
|
+
return None
|
|
13
|
+
return _scoped_style_factory.get_object(ui.context.client)
|
|
14
|
+
|
|
15
|
+
def create_style(self, element: Element, css: str):
|
|
16
|
+
element_id = f"c{element.id}"
|
|
17
|
+
|
|
18
|
+
self.run_method("createStyle", element_id, css)
|
|
19
|
+
|
|
20
|
+
def remove_style(self, element: Element):
|
|
21
|
+
element_id = f"c{element.id}"
|
|
22
|
+
self.run_method("removeStyle", element_id)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_scoped_style_factory = client_instance_locker.ClientInstanceLocker(ScopedStyle)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
try:
|
|
2
|
+
import pandas as pd
|
|
3
|
+
except ImportError:
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def dataframe2col_str(df, copy=True):
|
|
8
|
+
if isinstance(df.columns, pd.MultiIndex):
|
|
9
|
+
raise ValueError(
|
|
10
|
+
"MultiIndex columns are not supported. "
|
|
11
|
+
"You can convert them to strings using something like "
|
|
12
|
+
'`df.columns = ["_".join(col) for col in df.columns.values]`.'
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
date_cols = df.columns[df.dtypes == "datetime64[ns]"]
|
|
16
|
+
time_cols = df.columns[df.dtypes == "timedelta64[ns]"]
|
|
17
|
+
complex_cols = df.columns[df.dtypes == "complex128"]
|
|
18
|
+
period_cols = df.columns[df.dtypes == "period[M]"]
|
|
19
|
+
if (
|
|
20
|
+
len(date_cols) != 0
|
|
21
|
+
or len(time_cols) != 0
|
|
22
|
+
or len(complex_cols) != 0
|
|
23
|
+
or len(period_cols) != 0
|
|
24
|
+
):
|
|
25
|
+
df = df.copy() if copy else df
|
|
26
|
+
df[date_cols] = df[date_cols].astype(str)
|
|
27
|
+
df[time_cols] = df[time_cols].astype(str)
|
|
28
|
+
df[complex_cols] = df[complex_cols].astype(str)
|
|
29
|
+
df[period_cols] = df[period_cols].astype(str)
|
|
30
|
+
|
|
31
|
+
return df
|
|
@@ -5,36 +5,16 @@ from typing import (
|
|
|
5
5
|
Iterable,
|
|
6
6
|
List,
|
|
7
7
|
Optional,
|
|
8
|
-
Protocol,
|
|
9
8
|
Tuple,
|
|
10
9
|
cast,
|
|
11
|
-
runtime_checkable,
|
|
12
|
-
Union,
|
|
13
10
|
)
|
|
14
|
-
|
|
15
|
-
from ex4nicegui.utils.signals import is_ref,
|
|
11
|
+
from nicegui import ui
|
|
12
|
+
from ex4nicegui.utils.signals import is_ref, is_setter_ref
|
|
16
13
|
from nicegui.events import handle_event
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
pass
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@runtime_checkable
|
|
25
|
-
class GetItemProtocol(Protocol):
|
|
26
|
-
def __getitem__(self, key):
|
|
27
|
-
...
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@runtime_checkable
|
|
31
|
-
class SetItemProtocol(Protocol):
|
|
32
|
-
def __setitem__(self, key, value):
|
|
33
|
-
...
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def _convert_kws_ref2value(kws: Dict) -> Dict:
|
|
37
|
-
return {key: to_value(value) for key, value in kws.items()}
|
|
14
|
+
from ex4nicegui.reactive.systems.reactive_system import (
|
|
15
|
+
convert_kws_ref2value,
|
|
16
|
+
inject_method,
|
|
17
|
+
)
|
|
38
18
|
|
|
39
19
|
|
|
40
20
|
class ParameterClassifier:
|
|
@@ -75,7 +55,7 @@ class ParameterClassifier:
|
|
|
75
55
|
)
|
|
76
56
|
|
|
77
57
|
def get_values_kws(self) -> Dict:
|
|
78
|
-
value_kws =
|
|
58
|
+
value_kws = convert_kws_ref2value(
|
|
79
59
|
{k: v for k, v in self._args.items() if k not in self.events}
|
|
80
60
|
)
|
|
81
61
|
|
|
@@ -105,43 +85,5 @@ class ParameterClassifier:
|
|
|
105
85
|
}
|
|
106
86
|
|
|
107
87
|
|
|
108
|
-
def
|
|
109
|
-
|
|
110
|
-
return obj[name]
|
|
111
|
-
return getattr(obj, name) # type: ignore
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def set_attribute(
|
|
115
|
-
obj: Union[object, SetItemProtocol], name: Union[str, int], value: Any
|
|
116
|
-
) -> None:
|
|
117
|
-
if isinstance(obj, SetItemProtocol):
|
|
118
|
-
obj[name] = value
|
|
119
|
-
else:
|
|
120
|
-
setattr(obj, name, value) # type: ignore
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def dataframe2col_str(df, copy=True):
|
|
124
|
-
if isinstance(df.columns, pd.MultiIndex):
|
|
125
|
-
raise ValueError(
|
|
126
|
-
"MultiIndex columns are not supported. "
|
|
127
|
-
"You can convert them to strings using something like "
|
|
128
|
-
'`df.columns = ["_".join(col) for col in df.columns.values]`.'
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
date_cols = df.columns[df.dtypes == "datetime64[ns]"]
|
|
132
|
-
time_cols = df.columns[df.dtypes == "timedelta64[ns]"]
|
|
133
|
-
complex_cols = df.columns[df.dtypes == "complex128"]
|
|
134
|
-
period_cols = df.columns[df.dtypes == "period[M]"]
|
|
135
|
-
if (
|
|
136
|
-
len(date_cols) != 0
|
|
137
|
-
or len(time_cols) != 0
|
|
138
|
-
or len(complex_cols) != 0
|
|
139
|
-
or len(period_cols) != 0
|
|
140
|
-
):
|
|
141
|
-
df = df.copy() if copy else df
|
|
142
|
-
df[date_cols] = df[date_cols].astype(str)
|
|
143
|
-
df[time_cols] = df[time_cols].astype(str)
|
|
144
|
-
df[complex_cols] = df[complex_cols].astype(str)
|
|
145
|
-
df[period_cols] = df[period_cols].astype(str)
|
|
146
|
-
|
|
147
|
-
return df
|
|
88
|
+
def inject_handle_delete(element: ui.element, on_delete: Callable[[], None]):
|
|
89
|
+
inject_method(element, "_handle_delete", on_delete)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from nicegui import ui
|
|
6
|
+
from nicegui.elements.mixins.color_elements import (
|
|
7
|
+
QUASAR_COLORS,
|
|
8
|
+
TAILWIND_COLORS,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from functools import lru_cache
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_color_system_type = Literal["QUASAR", "TAILWIND", "STYLE"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_text_color_info(name: str):
|
|
18
|
+
system_type: _color_system_type = "STYLE"
|
|
19
|
+
|
|
20
|
+
if name in QUASAR_COLORS:
|
|
21
|
+
system_type = "QUASAR"
|
|
22
|
+
elif name in TAILWIND_COLORS:
|
|
23
|
+
system_type = "TAILWIND"
|
|
24
|
+
name = f"text-{name}"
|
|
25
|
+
else:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
return system_type, name
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_bg_color_info(color: str):
|
|
32
|
+
system_type: _color_system_type = "STYLE"
|
|
33
|
+
|
|
34
|
+
if color in QUASAR_COLORS:
|
|
35
|
+
system_type = "QUASAR"
|
|
36
|
+
elif color in TAILWIND_COLORS:
|
|
37
|
+
system_type = "TAILWIND"
|
|
38
|
+
color = f"bg-{color}"
|
|
39
|
+
else:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
return system_type, color
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _remove_text_color_from_quasar(element: ui.element, color: str):
|
|
46
|
+
color_prop = getattr(element, "TEXT_COLOR_PROP", None)
|
|
47
|
+
if color_prop:
|
|
48
|
+
element._props.pop(color_prop, None)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _remove_text_color_from_tailwind(element: ui.element, color: str):
|
|
52
|
+
color = f"text-{color}"
|
|
53
|
+
element._classes.remove(color)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _remove_text_color(element: ui.element, color: str):
|
|
57
|
+
element._style.pop("color", None)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _add_text_color_from_quasar(element: ui.element, color: str):
|
|
61
|
+
color_prop = getattr(element, "TEXT_COLOR_PROP", None)
|
|
62
|
+
if color_prop:
|
|
63
|
+
element._props[color_prop] = color
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _add_text_color_from_tailwind(element: ui.element, color: str):
|
|
67
|
+
color = f"text-{color}"
|
|
68
|
+
element.classes(color)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _add_text_color(element: ui.element, color: str):
|
|
72
|
+
element._style["color"] = f"{color} !important"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@lru_cache(maxsize=10)
|
|
76
|
+
def _query_text_color(color: str, add_handler=True):
|
|
77
|
+
if color in QUASAR_COLORS:
|
|
78
|
+
return (
|
|
79
|
+
_add_text_color_from_quasar
|
|
80
|
+
if add_handler
|
|
81
|
+
else _remove_text_color_from_quasar
|
|
82
|
+
)
|
|
83
|
+
elif color in TAILWIND_COLORS:
|
|
84
|
+
return (
|
|
85
|
+
_add_text_color_from_tailwind
|
|
86
|
+
if add_handler
|
|
87
|
+
else _remove_text_color_from_tailwind
|
|
88
|
+
)
|
|
89
|
+
elif color is not None:
|
|
90
|
+
return _add_text_color if add_handler else _remove_text_color
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def remove_text_color(element: ui.element, color: str):
|
|
94
|
+
handler = _query_text_color(color, add_handler=False)
|
|
95
|
+
if handler:
|
|
96
|
+
handler(element, color)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def add_text_color(element: ui.element, color: str):
|
|
100
|
+
handler = _query_text_color(color)
|
|
101
|
+
if handler:
|
|
102
|
+
handler(element, color)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# background color handlers
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _remove_bg_from_quasar(element: ui.element, color: str):
|
|
109
|
+
color_prop = getattr(element, "BACKGROUND_COLOR_PROP", None)
|
|
110
|
+
if color_prop:
|
|
111
|
+
element._props.pop(color_prop, None)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _remove_bg_from_tailwind(element: ui.element, color: str):
|
|
115
|
+
color = f"bg-{color}"
|
|
116
|
+
element._classes.remove(color)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _remove_background_color(element: ui.element, color: str):
|
|
120
|
+
element._style.pop("background-color", None)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _add_bg_from_quasar(element: ui.element, color: str):
|
|
124
|
+
color_prop = getattr(element, "BACKGROUND_COLOR_PROP", None)
|
|
125
|
+
if color_prop:
|
|
126
|
+
element._props[color_prop] = color
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _add_bg_from_tailwind(element: ui.element, color: str):
|
|
130
|
+
color = f"bg-{color}"
|
|
131
|
+
element.classes(color)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _add_background_color(element: ui.element, color: str):
|
|
135
|
+
element._style["background-color"] = f"{color} !important"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@lru_cache(maxsize=10)
|
|
139
|
+
def _query_background_color(color: str, add_handler=True):
|
|
140
|
+
if color in QUASAR_COLORS:
|
|
141
|
+
return _add_bg_from_quasar if add_handler else _remove_bg_from_quasar
|
|
142
|
+
elif color in TAILWIND_COLORS:
|
|
143
|
+
return _add_bg_from_tailwind if add_handler else _remove_bg_from_tailwind
|
|
144
|
+
elif color is not None:
|
|
145
|
+
return _add_background_color if add_handler else _remove_background_color
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def remove_background_color(element: ui.element, color: str):
|
|
149
|
+
handler = _query_background_color(color, add_handler=False)
|
|
150
|
+
if handler:
|
|
151
|
+
handler(element, color)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def add_background_color(element: ui.element, color: str):
|
|
155
|
+
handler = _query_background_color(color)
|
|
156
|
+
if handler:
|
|
157
|
+
handler(element, color)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Any,
|
|
3
|
+
Protocol,
|
|
4
|
+
runtime_checkable,
|
|
5
|
+
Union,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class GetItemProtocol(Protocol):
|
|
11
|
+
def __getitem__(self, key):
|
|
12
|
+
...
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@runtime_checkable
|
|
16
|
+
class SetItemProtocol(Protocol):
|
|
17
|
+
def __setitem__(self, key, value):
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_attribute(obj: Union[object, GetItemProtocol], name: Union[str, int]) -> Any:
|
|
22
|
+
if isinstance(obj, (GetItemProtocol)):
|
|
23
|
+
return obj[name]
|
|
24
|
+
return getattr(obj, name) # type: ignore
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def set_attribute(
|
|
28
|
+
obj: Union[object, SetItemProtocol], name: Union[str, int], value: Any
|
|
29
|
+
) -> None:
|
|
30
|
+
if isinstance(obj, SetItemProtocol):
|
|
31
|
+
obj[name] = value
|
|
32
|
+
else:
|
|
33
|
+
setattr(obj, name, value) # type: ignore
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Callable, Dict
|
|
2
|
+
from ex4nicegui.utils.signals import to_value
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def convert_kws_ref2value(kws: Dict) -> Dict:
|
|
6
|
+
return {key: to_value(value) for key, value in kws.items()}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def inject_method(obj, method_name: str, new_handle: Callable):
|
|
10
|
+
if hasattr(obj, method_name):
|
|
11
|
+
original_method = getattr(obj, method_name)
|
|
12
|
+
|
|
13
|
+
def injected_method(*args, **kwargs):
|
|
14
|
+
new_handle(*args, **kwargs)
|
|
15
|
+
return original_method(*args, **kwargs)
|
|
16
|
+
|
|
17
|
+
setattr(obj, method_name, injected_method)
|
|
18
|
+
else:
|
|
19
|
+
raise AttributeError(
|
|
20
|
+
f"'{type(obj).__name__}' object has no attribute '{method_name}'."
|
|
21
|
+
)
|
|
@@ -4,7 +4,7 @@ from nicegui.dataclasses import KWONLY_SLOTS
|
|
|
4
4
|
from nicegui.events import handle_event, UiEventArguments
|
|
5
5
|
from nicegui.element import Element
|
|
6
6
|
|
|
7
|
-
from ex4nicegui.utils.signals import
|
|
7
|
+
from ex4nicegui.utils.signals import TReadonlyRef, batch, to_ref
|
|
8
8
|
|
|
9
9
|
_Update_Args = [
|
|
10
10
|
"x",
|
|
@@ -42,15 +42,15 @@ class UseMouse(Element, component="UseMouse.js"):
|
|
|
42
42
|
|
|
43
43
|
@property
|
|
44
44
|
def x(self):
|
|
45
|
-
return cast(
|
|
45
|
+
return cast(TReadonlyRef[float], self.__x)
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def y(self):
|
|
49
|
-
return cast(
|
|
49
|
+
return cast(TReadonlyRef[float], self.__y)
|
|
50
50
|
|
|
51
51
|
@property
|
|
52
52
|
def sourceType(self):
|
|
53
|
-
return cast(
|
|
53
|
+
return cast(TReadonlyRef[float], self.__sourceType)
|
|
54
54
|
|
|
55
55
|
def on_update(self, handler: Optional[Callable[..., Any]]):
|
|
56
56
|
def inner_handler(e):
|
ex4nicegui/reactive/vfor.py
CHANGED
|
@@ -26,9 +26,8 @@ from typing import (
|
|
|
26
26
|
from functools import partial
|
|
27
27
|
from dataclasses import dataclass
|
|
28
28
|
from signe.core.scope import Scope
|
|
29
|
-
from .
|
|
29
|
+
from ex4nicegui.reactive.systems.object_system import get_attribute
|
|
30
30
|
from ex4nicegui.reactive.empty import Empty
|
|
31
|
-
# from .transitionGroup import TransitionGroup
|
|
32
31
|
|
|
33
32
|
_T = TypeVar("_T")
|
|
34
33
|
_T_data = Union[List[Any], TGetterOrReadonlyRef[List[Any]], RefWrapper]
|
ex4nicegui/reactive/vmodel.py
CHANGED
ex4nicegui/utils/apiEffect.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import signe
|
|
2
2
|
from signe.core.scope import Scope
|
|
3
|
+
from signe.core.consts import EffectState
|
|
3
4
|
from typing import (
|
|
4
5
|
TypeVar,
|
|
5
6
|
overload,
|
|
@@ -88,7 +89,10 @@ def ui_effect(
|
|
|
88
89
|
**kws,
|
|
89
90
|
scope=scope or _CLIENT_SCOPE_MANAGER.get_current_scope(),
|
|
90
91
|
)
|
|
91
|
-
|
|
92
|
+
|
|
93
|
+
res.trigger(EffectState.NEED_UPDATE)
|
|
94
|
+
scheduler.run()
|
|
95
|
+
# res.update()
|
|
92
96
|
|
|
93
97
|
return res
|
|
94
98
|
|
ex4nicegui/utils/effect.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import signe
|
|
2
|
+
from signe.core.consts import EffectState
|
|
2
3
|
from typing import (
|
|
3
4
|
TypeVar,
|
|
4
5
|
overload,
|
|
@@ -6,7 +7,6 @@ from typing import (
|
|
|
6
7
|
Callable,
|
|
7
8
|
Union,
|
|
8
9
|
)
|
|
9
|
-
|
|
10
10
|
from .scheduler import get_uiScheduler
|
|
11
11
|
from .clientScope import _CLIENT_SCOPE_MANAGER
|
|
12
12
|
|
|
@@ -81,7 +81,8 @@ def effect(
|
|
|
81
81
|
scope=_CLIENT_SCOPE_MANAGER.get_current_scope(),
|
|
82
82
|
)
|
|
83
83
|
|
|
84
|
-
res.
|
|
84
|
+
res.trigger(EffectState.NEED_UPDATE)
|
|
85
|
+
scheduler.run()
|
|
85
86
|
|
|
86
87
|
return res
|
|
87
88
|
|