instaui 0.1.9__py3-none-any.whl → 0.1.10__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.
- instaui/_helper/observable_helper.py +11 -1
- instaui/arco/components/select.py +4 -1
- instaui/components/echarts/echarts.js +7 -5
- instaui/components/echarts/echarts.py +1 -1
- instaui/components/element.py +12 -22
- instaui/components/grid.py +63 -11
- instaui/components/html/paragraph.py +10 -0
- instaui/components/label.py +5 -0
- instaui/event/js_event.py +24 -0
- instaui/event/vue_event.py +66 -0
- instaui/event/web_event.py +36 -25
- instaui/handlers/_utils.py +27 -5
- instaui/static/insta-ui.css +1 -1
- instaui/static/insta-ui.esm-browser.prod.js +943 -932
- instaui/static/insta-ui.js.map +1 -1
- instaui/systems/func_system.py +15 -0
- instaui/ui/__init__.py +5 -1
- instaui/ui/__init__.pyi +5 -1
- instaui/ui_functions/ui_page.py +3 -3
- instaui/vars/js_computed.py +25 -1
- instaui/vars/state.py +15 -0
- instaui/vars/web_computed.py +36 -0
- instaui/watch/js_watch.py +37 -1
- instaui/watch/web_watch.py +53 -0
- instaui-0.1.10.dist-info/METADATA +153 -0
- {instaui-0.1.9.dist-info → instaui-0.1.10.dist-info}/RECORD +28 -26
- instaui-0.1.9.dist-info/METADATA +0 -153
- {instaui-0.1.9.dist-info → instaui-0.1.10.dist-info}/WHEEL +0 -0
- {instaui-0.1.9.dist-info → instaui-0.1.10.dist-info}/licenses/LICENSE +0 -0
instaui/systems/func_system.py
CHANGED
@@ -35,6 +35,21 @@ def get_fn_params_infos(fn: Callable) -> List[Tuple[str, type]]:
|
|
35
35
|
]
|
36
36
|
|
37
37
|
|
38
|
+
def is_last_param_args(fn):
|
39
|
+
"""
|
40
|
+
Returns:
|
41
|
+
bool: True if the last parameter of the function is `*args`, False otherwise.
|
42
|
+
"""
|
43
|
+
sig = inspect.signature(fn)
|
44
|
+
params = list(sig.parameters.values())
|
45
|
+
|
46
|
+
if not params:
|
47
|
+
return False
|
48
|
+
|
49
|
+
last_param = params[-1]
|
50
|
+
return last_param.kind == inspect.Parameter.VAR_POSITIONAL
|
51
|
+
|
52
|
+
|
38
53
|
def get_required_param_count(fn: Callable):
|
39
54
|
signature = inspect.signature(fn)
|
40
55
|
params = signature.parameters
|
instaui/ui/__init__.py
CHANGED
@@ -29,6 +29,7 @@ __all__ = [
|
|
29
29
|
"element",
|
30
30
|
"vfor",
|
31
31
|
"content",
|
32
|
+
"label",
|
32
33
|
"add_style",
|
33
34
|
"add_css_link",
|
34
35
|
"remove_css_link",
|
@@ -42,6 +43,7 @@ __all__ = [
|
|
42
43
|
"page",
|
43
44
|
"event",
|
44
45
|
"js_event",
|
46
|
+
"vue_event",
|
45
47
|
"event_context",
|
46
48
|
"TEventFn",
|
47
49
|
"server",
|
@@ -103,9 +105,11 @@ from instaui.components.vfor import VFor as vfor
|
|
103
105
|
from instaui.components.vif import VIf as vif
|
104
106
|
from instaui.components.match import Match as match
|
105
107
|
from instaui.components.content import Content as content
|
108
|
+
from instaui.components.label import label
|
106
109
|
|
107
|
-
from instaui.event.web_event import
|
110
|
+
from instaui.event.web_event import event, WebEvent as TEventFn
|
108
111
|
from instaui.event.js_event import js_event
|
112
|
+
from instaui.event.vue_event import vue_event
|
109
113
|
from instaui.vars.event_context import EventContext as event_context
|
110
114
|
from instaui.runtime.context import get_context as context
|
111
115
|
|
instaui/ui/__init__.pyi
CHANGED
@@ -29,6 +29,7 @@ __all__ = [
|
|
29
29
|
"element",
|
30
30
|
"vfor",
|
31
31
|
"content",
|
32
|
+
"label",
|
32
33
|
"add_style",
|
33
34
|
"add_css_link",
|
34
35
|
"remove_css_link",
|
@@ -42,6 +43,7 @@ __all__ = [
|
|
42
43
|
"page",
|
43
44
|
"event",
|
44
45
|
"js_event",
|
46
|
+
"vue_event",
|
45
47
|
"event_context",
|
46
48
|
"TEventFn",
|
47
49
|
"server",
|
@@ -103,9 +105,11 @@ from instaui.components.vfor import VFor as vfor
|
|
103
105
|
from instaui.components.vif import VIf as vif
|
104
106
|
from instaui.components.match import Match as match
|
105
107
|
from instaui.components.content import Content as content
|
108
|
+
from instaui.components.label import label
|
106
109
|
|
107
|
-
from instaui.event.web_event import
|
110
|
+
from instaui.event.web_event import event, WebEvent as TEventFn
|
108
111
|
from instaui.event.js_event import js_event
|
112
|
+
from instaui.event.vue_event import vue_event
|
109
113
|
from instaui.vars.event_context import EventContext as event_context
|
110
114
|
from instaui.runtime.context import get_context as context
|
111
115
|
|
instaui/ui_functions/ui_page.py
CHANGED
@@ -2,15 +2,15 @@ from typing import Callable
|
|
2
2
|
from instaui.launch_collector import get_launch_collector, PageInfo
|
3
3
|
|
4
4
|
|
5
|
-
def page(
|
5
|
+
def page(path: str = "/"):
|
6
6
|
"""Register a page route.
|
7
7
|
|
8
8
|
Args:
|
9
|
-
|
9
|
+
path (str): The route path.
|
10
10
|
"""
|
11
11
|
|
12
12
|
def wrapper(func: Callable):
|
13
|
-
get_launch_collector().register_page(PageInfo(
|
13
|
+
get_launch_collector().register_page(PageInfo(path, func))
|
14
14
|
return func
|
15
15
|
|
16
16
|
return wrapper
|
instaui/vars/js_computed.py
CHANGED
@@ -25,14 +25,34 @@ class JsComputed(
|
|
25
25
|
StrFormatBindingMixin,
|
26
26
|
ElementBindingMixin,
|
27
27
|
):
|
28
|
+
"""
|
29
|
+
A client-side computed property that evaluates JavaScript code to derive reactive values.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
inputs (typing.Optional[typing.Sequence[TObservableInput]], optional): Reactive data sources to monitor.
|
33
|
+
Changes to these values trigger re-computation.
|
34
|
+
code (str): JavaScript code to execute for computing the value.
|
35
|
+
async_init_value (typing.Optional[typing.Any], optional): Initial value to use before first successful async evaluation.
|
36
|
+
|
37
|
+
# Example:
|
38
|
+
.. code-block:: python
|
39
|
+
a = ui.state(0)
|
40
|
+
|
41
|
+
plus_one = ui.js_computed(inputs=[a], code="a=> a+1")
|
42
|
+
|
43
|
+
html.number(a)
|
44
|
+
ui.label(plus_one)
|
45
|
+
"""
|
46
|
+
|
28
47
|
BIND_TYPE = "var"
|
29
48
|
|
30
49
|
def __init__(
|
31
50
|
self,
|
32
51
|
*,
|
33
52
|
inputs: typing.Optional[typing.Sequence[TObservableInput]] = None,
|
34
|
-
code: str
|
53
|
+
code: str,
|
35
54
|
async_init_value: typing.Optional[typing.Any] = None,
|
55
|
+
deep_compare_on_input: bool = False,
|
36
56
|
) -> None:
|
37
57
|
self.code = code
|
38
58
|
|
@@ -46,6 +66,7 @@ class JsComputed(
|
|
46
66
|
)
|
47
67
|
|
48
68
|
self._async_init_value = async_init_value
|
69
|
+
self._deep_compare_on_input = deep_compare_on_input
|
49
70
|
|
50
71
|
def __to_binding_config(self):
|
51
72
|
return {
|
@@ -87,6 +108,9 @@ class JsComputed(
|
|
87
108
|
if self._async_init_value is not None:
|
88
109
|
data["asyncInit"] = self._async_init_value
|
89
110
|
|
111
|
+
if self._deep_compare_on_input is not False:
|
112
|
+
data["deepEqOnInput"] = 1
|
113
|
+
|
90
114
|
return data
|
91
115
|
|
92
116
|
|
instaui/vars/state.py
CHANGED
@@ -78,5 +78,20 @@ class StateModel(BaseModel, Jsonable):
|
|
78
78
|
|
79
79
|
|
80
80
|
def state(value: _T) -> _T:
|
81
|
+
"""
|
82
|
+
Creates a reactive state object that tracks changes and notifies dependencies.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
value (_T): The initial value to wrap in a reactive state container.
|
86
|
+
Can be any type (primitive, object, or complex data structure).
|
87
|
+
|
88
|
+
# Example:
|
89
|
+
.. code-block:: python
|
90
|
+
from instaui import ui,html
|
91
|
+
count = ui.state(0)
|
92
|
+
|
93
|
+
html.number(count)
|
94
|
+
ui.label(count)
|
95
|
+
"""
|
81
96
|
obj = RefProxy(_ProxyModel(value)) # type: ignore
|
82
97
|
return obj # type: ignore
|
instaui/vars/web_computed.py
CHANGED
@@ -50,6 +50,7 @@ class WebComputed(
|
|
50
50
|
extend_outputs: Optional[Sequence[CanOutputMixin]] = None,
|
51
51
|
init_value: Optional[R] = None,
|
52
52
|
evaluating: Optional[CanOutputMixin] = None,
|
53
|
+
deep_compare_on_input: bool = False,
|
53
54
|
debug_info: Optional[Dict] = None,
|
54
55
|
) -> None:
|
55
56
|
scope = get_current_scope()
|
@@ -65,6 +66,7 @@ class WebComputed(
|
|
65
66
|
self._fn = func
|
66
67
|
self._init_value = init_value
|
67
68
|
self._evaluating = evaluating
|
69
|
+
self._deep_compare_on_input = deep_compare_on_input
|
68
70
|
|
69
71
|
if debug_info is not None:
|
70
72
|
self.debug = debug_info
|
@@ -111,6 +113,9 @@ class WebComputed(
|
|
111
113
|
if self._evaluating:
|
112
114
|
data["running"] = self._evaluating._to_output_config()
|
113
115
|
|
116
|
+
if self._deep_compare_on_input is not False:
|
117
|
+
data["deepEqOnInput"] = 1
|
118
|
+
|
114
119
|
return data
|
115
120
|
|
116
121
|
# return {}
|
@@ -144,8 +149,38 @@ def web_computed(
|
|
144
149
|
extend_outputs: Optional[Sequence] = None,
|
145
150
|
init_value: Optional[Any] = None,
|
146
151
|
evaluating: Optional[Any] = None,
|
152
|
+
deep_compare_on_input: bool = False,
|
147
153
|
debug_info: Optional[Dict] = None,
|
148
154
|
):
|
155
|
+
"""
|
156
|
+
Creates a computed property decorator for reactive programming with dependency tracking.
|
157
|
+
|
158
|
+
This decorator factory wraps functions to create reactive computed properties that:
|
159
|
+
- Automatically re-evaluate when dependencies (inputs) change
|
160
|
+
- Cache results for performance optimization
|
161
|
+
- Support both synchronous and asynchronous computation patterns
|
162
|
+
|
163
|
+
Args:
|
164
|
+
inputs (Optional[Sequence], optional): Collection of reactive sources that trigger recomputation
|
165
|
+
when changed. These can be state objects or other computed properties.
|
166
|
+
extend_outputs (Optional[Sequence], optional): Additional outputs to notify when this computed value updates.
|
167
|
+
init_value (Optional[Any], optional): Initial value to return before first successful evaluation.
|
168
|
+
evaluating (Optional[Any], optional): Temporary value returned during asynchronous computation.
|
169
|
+
|
170
|
+
# Example:
|
171
|
+
.. code-block:: python
|
172
|
+
from instaui import ui,html
|
173
|
+
|
174
|
+
a = ui.state(0)
|
175
|
+
|
176
|
+
@ui.computed(inputs=[a])
|
177
|
+
def plus_one(a):
|
178
|
+
return a + 1
|
179
|
+
|
180
|
+
html.number(a)
|
181
|
+
ui.label(plus_one)
|
182
|
+
"""
|
183
|
+
|
149
184
|
def wrapper(func: Callable[P, R]):
|
150
185
|
return WebComputed(
|
151
186
|
func,
|
@@ -153,6 +188,7 @@ def web_computed(
|
|
153
188
|
extend_outputs=extend_outputs,
|
154
189
|
init_value=init_value,
|
155
190
|
evaluating=evaluating,
|
191
|
+
deep_compare_on_input=deep_compare_on_input,
|
156
192
|
debug_info=debug_info,
|
157
193
|
)
|
158
194
|
|
instaui/watch/js_watch.py
CHANGED
@@ -21,6 +21,8 @@ class JsWatch(Jsonable):
|
|
21
21
|
once: bool = False,
|
22
22
|
flush: typing.Optional[_types.TFlush] = None,
|
23
23
|
) -> None:
|
24
|
+
inputs = observable_helper.auto_made_inputs_to_slient(inputs, outputs)
|
25
|
+
|
24
26
|
get_current_scope().register_js_watch(self)
|
25
27
|
|
26
28
|
self.code = code
|
@@ -65,10 +67,44 @@ def js_watch(
|
|
65
67
|
*,
|
66
68
|
inputs: typing.Optional[typing.Sequence] = None,
|
67
69
|
outputs: typing.Optional[typing.Sequence] = None,
|
68
|
-
code: str
|
70
|
+
code: str,
|
69
71
|
immediate: bool = True,
|
70
72
|
deep: typing.Union[bool, int] = False,
|
71
73
|
once: bool = False,
|
72
74
|
flush: typing.Optional[_types.TFlush] = None,
|
73
75
|
):
|
76
|
+
"""
|
77
|
+
Creates a client-side observer that executes JavaScript code in response to reactive source changes.
|
78
|
+
|
79
|
+
Args:
|
80
|
+
inputs (typing.Optional[typing.Sequence], optional): Reactive sources to observe. Changes to these sources
|
81
|
+
trigger the watcher's JavaScript execution.
|
82
|
+
outputs (typing.Optional[typing.Sequence], optional): Output targets associated with this watcher. Used for
|
83
|
+
coordination with other observers.
|
84
|
+
code (str, optional): JavaScript code to execute when changes are detected. The code has access
|
85
|
+
to the current values of observed inputs through the `args` parameter.
|
86
|
+
immediate (bool, optional):If True, executes the watcher immediately after creation with current values. Defaults to True.
|
87
|
+
deep (typing.Union[bool, int], optional): Controls depth of change detection:
|
88
|
+
- True: Recursively tracks nested properties
|
89
|
+
- False: Shallow comparison only
|
90
|
+
- int: Maximum depth level to track (for complex objects).
|
91
|
+
Defaults to False.
|
92
|
+
once (bool, optional): If True, automatically stops observation after first trigger. Defaults to False.
|
93
|
+
flush (typing.Optional[_types.TFlush], optional): Controls when to flush updates:
|
94
|
+
- 'sync': Execute immediately on change
|
95
|
+
- 'post': Batch updates and execute after current tick
|
96
|
+
- 'pre': Execute before render phase (if applicable)
|
97
|
+
|
98
|
+
# Example:
|
99
|
+
.. code-block:: python
|
100
|
+
from instaui import ui, html
|
101
|
+
|
102
|
+
num = ui.state(0)
|
103
|
+
msg = ui.state('')
|
104
|
+
ui.js_watch(inputs=[num], outputs=[msg], code="num => `The number is ${num}`")
|
105
|
+
|
106
|
+
html.number(num)
|
107
|
+
ui.label(msg)
|
108
|
+
"""
|
109
|
+
|
74
110
|
return JsWatch(code, inputs, outputs, immediate, deep, once, flush)
|
instaui/watch/web_watch.py
CHANGED
@@ -32,6 +32,8 @@ class WebWatch(Jsonable, typing.Generic[P, R]):
|
|
32
32
|
flush: typing.Optional[_types.TFlush] = None,
|
33
33
|
_debug: typing.Optional[typing.Any] = None,
|
34
34
|
) -> None:
|
35
|
+
inputs = observable_helper.auto_made_inputs_to_slient(inputs, outputs)
|
36
|
+
|
35
37
|
get_current_scope().register_web_watch(self)
|
36
38
|
|
37
39
|
self._inputs, self._is_slient_inputs, self._is_data = (
|
@@ -107,6 +109,57 @@ def watch(
|
|
107
109
|
flush: typing.Optional[_types.TFlush] = None,
|
108
110
|
_debug: typing.Optional[typing.Any] = None,
|
109
111
|
):
|
112
|
+
"""
|
113
|
+
Creates an observer that tracks changes in reactive sources and triggers callbacks.
|
114
|
+
|
115
|
+
Args:
|
116
|
+
inputs (typing.Optional[typing.Sequence], optional): Reactive sources to observe (state objects or computed properties).
|
117
|
+
Changes to these sources trigger the watcher callback.
|
118
|
+
outputs (typing.Optional[typing.Sequence], optional): Output targets associated with this watcher.
|
119
|
+
Used for coordination with computed properties or other observers.
|
120
|
+
immediate (bool, optional): If True, executes callback immediately after creation with current values. Defaults to True.
|
121
|
+
deep (typing.Union[bool, int], optional): Controls depth of change detection:
|
122
|
+
- True: Recursively tracks nested properties
|
123
|
+
- False: Shallow comparison only
|
124
|
+
- int: Maximum depth level to track (for complex objects).
|
125
|
+
Defaults to True.
|
126
|
+
once (bool, optional): If True, automatically stops observation after first trigger. Defaults to False.
|
127
|
+
flush (typing.Optional[_types.TFlush], optional): Controls when to flush updates:
|
128
|
+
- 'sync': Execute immediately on change
|
129
|
+
- 'post': Batch updates and execute after current tick
|
130
|
+
- 'pre': Execute before render phase (if applicable)
|
131
|
+
|
132
|
+
# Example:
|
133
|
+
.. code-block:: python
|
134
|
+
from instaui import ui, html
|
135
|
+
|
136
|
+
num = ui.state(0)
|
137
|
+
msg = ui.state('')
|
138
|
+
|
139
|
+
@ui.watch(inputs=[num], outputs=[msg])
|
140
|
+
def when_num_change(num):
|
141
|
+
return f"The number is {num}"
|
142
|
+
|
143
|
+
html.number(num)
|
144
|
+
ui.label(msg)
|
145
|
+
|
146
|
+
list append:
|
147
|
+
.. code-block:: python
|
148
|
+
from instaui import ui, html
|
149
|
+
|
150
|
+
num = ui.state(0)
|
151
|
+
msg = ui.state([])
|
152
|
+
|
153
|
+
@ui.watch(inputs=[num, msg], outputs=[msg])
|
154
|
+
def when_num_change(num, msg:list):
|
155
|
+
msg.append(f"The number changed to {num}")
|
156
|
+
return msg
|
157
|
+
|
158
|
+
html.number(num)
|
159
|
+
ui.label(msg)
|
160
|
+
|
161
|
+
"""
|
162
|
+
|
110
163
|
def wrapper(func: typing.Callable[P, R]):
|
111
164
|
return WebWatch(
|
112
165
|
func,
|
@@ -0,0 +1,153 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: instaui
|
3
|
+
Version: 0.1.10
|
4
|
+
Summary: insta-ui is a Python-based UI library for rapidly building user interfaces.
|
5
|
+
Author-email: CrystalWindSnake <568166495@qq.com>
|
6
|
+
License-Expression: MIT
|
7
|
+
License-File: LICENSE
|
8
|
+
Keywords: gui,ui,web
|
9
|
+
Requires-Python: <3.13,>=3.8
|
10
|
+
Requires-Dist: jinja2>=3.1.6
|
11
|
+
Requires-Dist: orjson>=3.10.15
|
12
|
+
Requires-Dist: pydantic>=2.10.6
|
13
|
+
Requires-Dist: typing-extensions>=4.13.2
|
14
|
+
Provides-Extra: all
|
15
|
+
Requires-Dist: fastapi[standard]; extra == 'all'
|
16
|
+
Requires-Dist: pywebview; extra == 'all'
|
17
|
+
Requires-Dist: uvicorn; extra == 'all'
|
18
|
+
Provides-Extra: web
|
19
|
+
Requires-Dist: fastapi[standard]; extra == 'web'
|
20
|
+
Requires-Dist: pydantic<3.0.0,>=2.10.6; extra == 'web'
|
21
|
+
Requires-Dist: uvicorn; extra == 'web'
|
22
|
+
Provides-Extra: webview
|
23
|
+
Requires-Dist: pydantic<3.0.0,>=2.10.6; extra == 'webview'
|
24
|
+
Requires-Dist: pywebview; extra == 'webview'
|
25
|
+
Description-Content-Type: text/markdown
|
26
|
+
|
27
|
+
# insta-ui
|
28
|
+
|
29
|
+
<div align="center">
|
30
|
+
|
31
|
+
English| [简体中文](./README.md)
|
32
|
+
|
33
|
+
</div>
|
34
|
+
|
35
|
+
## 📖 Introduction
|
36
|
+
insta-ui is a Python-based UI library for quickly building user interfaces.
|
37
|
+
|
38
|
+
## ⚙️ Features
|
39
|
+
Three modes:
|
40
|
+
|
41
|
+
- Web mode: Generate web (stateless) applications.
|
42
|
+
- Web View mode: Generate web view applications that can be packaged as native apps (no need to start a web server).
|
43
|
+
- Zero mode: Generate pure HTML files that run directly in browsers without any dependencies.
|
44
|
+
|
45
|
+
|
46
|
+
## 📦 Installation
|
47
|
+
|
48
|
+
Zero mode:
|
49
|
+
|
50
|
+
```
|
51
|
+
pip install instaui -U
|
52
|
+
```
|
53
|
+
|
54
|
+
web mode
|
55
|
+
|
56
|
+
```
|
57
|
+
pip install instaui[web] -U
|
58
|
+
```
|
59
|
+
|
60
|
+
Web View mode
|
61
|
+
```
|
62
|
+
pip install instaui[webview] -U
|
63
|
+
```
|
64
|
+
|
65
|
+
|
66
|
+
## 🖥️ Quick Start
|
67
|
+
Below is a simple example of number summation. The result color changes dynamically based on the sum:
|
68
|
+
|
69
|
+
```python
|
70
|
+
from instaui import ui, arco
|
71
|
+
arco.use()
|
72
|
+
|
73
|
+
@ui.page('/')
|
74
|
+
def home():
|
75
|
+
num1 = ui.state(0)
|
76
|
+
num2 = ui.state(0)
|
77
|
+
|
78
|
+
# Automatically recalculates result when num1 or num2 changes
|
79
|
+
@ui.computed(inputs=[num1, num2])
|
80
|
+
def result(num1: int, num2: int):
|
81
|
+
return num1 + num2
|
82
|
+
|
83
|
+
# Automatically updates text_color when result changes
|
84
|
+
@ui.computed(inputs=[result])
|
85
|
+
def text_color(result: int):
|
86
|
+
return "red" if result % 2 == 0 else "blue"
|
87
|
+
|
88
|
+
# UI components
|
89
|
+
arco.input_number(num1)
|
90
|
+
ui.label("+")
|
91
|
+
arco.input_number(num2)
|
92
|
+
ui.label("=")
|
93
|
+
ui.label(result).style({"color": text_color})
|
94
|
+
|
95
|
+
ui.server().run()
|
96
|
+
```
|
97
|
+
|
98
|
+
Replace `ui.server().run()` with `ui.webview().run()` to switch to Web View mode:
|
99
|
+
|
100
|
+
```python
|
101
|
+
...
|
102
|
+
|
103
|
+
# ui.server().run()
|
104
|
+
ui.webview().run()
|
105
|
+
```
|
106
|
+
|
107
|
+
To execute computations on the client side instead of the server, use `ui.js_computed` instead of `ui.computed`:
|
108
|
+
|
109
|
+
```python
|
110
|
+
from instaui import ui, arco
|
111
|
+
arco.use()
|
112
|
+
|
113
|
+
@ui.page('/')
|
114
|
+
def home():
|
115
|
+
num1 = ui.state(0)
|
116
|
+
num2 = ui.state(0)
|
117
|
+
|
118
|
+
result = ui.js_computed(inputs=[num1, num2], code="(num1, num2) => num1 + num2")
|
119
|
+
text_color = ui.js_computed(inputs=[result], code="(result) => result % 2 === 0? 'red' : 'blue'")
|
120
|
+
|
121
|
+
# UI components
|
122
|
+
...
|
123
|
+
|
124
|
+
...
|
125
|
+
|
126
|
+
```
|
127
|
+
|
128
|
+
In this case, all interactions will run on the client side. Use `Zero mode` to generate a standalone HTML file:
|
129
|
+
|
130
|
+
```python
|
131
|
+
from instaui import ui, arco,zero
|
132
|
+
arco.use()
|
133
|
+
|
134
|
+
@ui.page('/')
|
135
|
+
def home():
|
136
|
+
num1 = ui.state(0)
|
137
|
+
num2 = ui.state(0)
|
138
|
+
|
139
|
+
result = ui.js_computed(inputs=[num1, num2], code="(num1, num2) => num1 + num2")
|
140
|
+
text_color = ui.js_computed(inputs=[result], code="(result) => result % 2 === 0? 'red' : 'blue'")
|
141
|
+
|
142
|
+
# UI components
|
143
|
+
arco.input_number(num1)
|
144
|
+
ui.label("+")
|
145
|
+
arco.input_number(num2)
|
146
|
+
ui.label("=")
|
147
|
+
ui.label(result).style({"color": text_color})
|
148
|
+
|
149
|
+
with zero() as z:
|
150
|
+
home()
|
151
|
+
z.to_html('index.html')
|
152
|
+
|
153
|
+
```
|