instaui 0.1.15__py2.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.
Files changed (283) hide show
  1. instaui/__init__.py +9 -0
  2. instaui/_helper/observable_helper.py +45 -0
  3. instaui/arco/__init__.py +191 -0
  4. instaui/arco/_settings.py +25 -0
  5. instaui/arco/_use_tools/locale.py +50 -0
  6. instaui/arco/component_types.py +1019 -0
  7. instaui/arco/components/_utils.py +22 -0
  8. instaui/arco/components/affix.py +29 -0
  9. instaui/arco/components/alert.py +42 -0
  10. instaui/arco/components/anchor.py +42 -0
  11. instaui/arco/components/auto_complete.py +96 -0
  12. instaui/arco/components/avatar.py +55 -0
  13. instaui/arco/components/back_top.py +14 -0
  14. instaui/arco/components/badge.py +14 -0
  15. instaui/arco/components/breadcrumb.py +14 -0
  16. instaui/arco/components/button.py +43 -0
  17. instaui/arco/components/calendar.py +47 -0
  18. instaui/arco/components/card.py +14 -0
  19. instaui/arco/components/carousel.py +33 -0
  20. instaui/arco/components/cascader.py +111 -0
  21. instaui/arco/components/checkbox.py +32 -0
  22. instaui/arco/components/collapse.py +31 -0
  23. instaui/arco/components/color_picker.py +45 -0
  24. instaui/arco/components/comment.py +14 -0
  25. instaui/arco/components/config_provider.py +13 -0
  26. instaui/arco/components/date_picker.py +111 -0
  27. instaui/arco/components/descriptions.py +14 -0
  28. instaui/arco/components/divider.py +13 -0
  29. instaui/arco/components/drawer.py +98 -0
  30. instaui/arco/components/dropdown.py +45 -0
  31. instaui/arco/components/empty.py +14 -0
  32. instaui/arco/components/form.py +55 -0
  33. instaui/arco/components/icon.py +17 -0
  34. instaui/arco/components/image.py +33 -0
  35. instaui/arco/components/input.py +102 -0
  36. instaui/arco/components/input_number.py +97 -0
  37. instaui/arco/components/input_password.py +38 -0
  38. instaui/arco/components/input_search.py +37 -0
  39. instaui/arco/components/input_tag.py +110 -0
  40. instaui/arco/components/layout.py +13 -0
  41. instaui/arco/components/layout_content.py +6 -0
  42. instaui/arco/components/layout_footer.py +6 -0
  43. instaui/arco/components/layout_header.py +6 -0
  44. instaui/arco/components/layout_sider.py +53 -0
  45. instaui/arco/components/link.py +36 -0
  46. instaui/arco/components/list.py +68 -0
  47. instaui/arco/components/mention.py +97 -0
  48. instaui/arco/components/menu.py +88 -0
  49. instaui/arco/components/modal.py +97 -0
  50. instaui/arco/components/overflow_list.py +29 -0
  51. instaui/arco/components/page_header.py +29 -0
  52. instaui/arco/components/pagination.py +45 -0
  53. instaui/arco/components/pop_confirm.py +58 -0
  54. instaui/arco/components/popover.py +32 -0
  55. instaui/arco/components/progress.py +14 -0
  56. instaui/arco/components/radio.py +40 -0
  57. instaui/arco/components/radio_group.py +42 -0
  58. instaui/arco/components/rate.py +45 -0
  59. instaui/arco/components/resize_box.py +62 -0
  60. instaui/arco/components/result.py +14 -0
  61. instaui/arco/components/select.py +182 -0
  62. instaui/arco/components/skeleton.py +14 -0
  63. instaui/arco/components/slider.py +38 -0
  64. instaui/arco/components/space.py +14 -0
  65. instaui/arco/components/spin.py +14 -0
  66. instaui/arco/components/split.py +76 -0
  67. instaui/arco/components/statistic.py +14 -0
  68. instaui/arco/components/steps.py +32 -0
  69. instaui/arco/components/switch.py +57 -0
  70. instaui/arco/components/tab_pane.py +12 -0
  71. instaui/arco/components/table.py +276 -0
  72. instaui/arco/components/tabs.py +101 -0
  73. instaui/arco/components/tag.py +42 -0
  74. instaui/arco/components/textarea.py +84 -0
  75. instaui/arco/components/time_picker.py +76 -0
  76. instaui/arco/components/timeline.py +14 -0
  77. instaui/arco/components/tooltip.py +29 -0
  78. instaui/arco/components/transfer.py +58 -0
  79. instaui/arco/components/tree.py +120 -0
  80. instaui/arco/components/tree_select.py +86 -0
  81. instaui/arco/components/trigger.py +58 -0
  82. instaui/arco/components/typography.py +142 -0
  83. instaui/arco/components/upload.py +71 -0
  84. instaui/arco/components/verification_code.py +58 -0
  85. instaui/arco/components/watermark.py +14 -0
  86. instaui/arco/locales/__init__.py +4 -0
  87. instaui/arco/locales/_index.py +31 -0
  88. instaui/arco/locales/en_us.py +227 -0
  89. instaui/arco/locales/zh_cn.py +224 -0
  90. instaui/arco/setup.py +36 -0
  91. instaui/arco/static/instaui-arco.css +1 -0
  92. instaui/arco/static/instaui-arco.js +55771 -0
  93. instaui/arco/types.py +24 -0
  94. instaui/boot_info.py +43 -0
  95. instaui/common/jsonable.py +37 -0
  96. instaui/components/__init__.py +0 -0
  97. instaui/components/column.py +26 -0
  98. instaui/components/component.py +47 -0
  99. instaui/components/content.py +34 -0
  100. instaui/components/directive.py +55 -0
  101. instaui/components/element.py +573 -0
  102. instaui/components/grid.py +213 -0
  103. instaui/components/html/__init__.py +49 -0
  104. instaui/components/html/_mixins.py +34 -0
  105. instaui/components/html/_preset.py +4 -0
  106. instaui/components/html/button.py +38 -0
  107. instaui/components/html/checkbox.py +35 -0
  108. instaui/components/html/date.py +28 -0
  109. instaui/components/html/div.py +7 -0
  110. instaui/components/html/form.py +7 -0
  111. instaui/components/html/heading.py +51 -0
  112. instaui/components/html/input.py +28 -0
  113. instaui/components/html/label.py +21 -0
  114. instaui/components/html/li.py +17 -0
  115. instaui/components/html/link.py +31 -0
  116. instaui/components/html/number.py +34 -0
  117. instaui/components/html/paragraph.py +29 -0
  118. instaui/components/html/range.py +48 -0
  119. instaui/components/html/select.py +69 -0
  120. instaui/components/html/span.py +19 -0
  121. instaui/components/html/table.py +36 -0
  122. instaui/components/html/textarea.py +28 -0
  123. instaui/components/html/ul.py +20 -0
  124. instaui/components/label.py +5 -0
  125. instaui/components/markdown/markdown.js +33 -0
  126. instaui/components/markdown/markdown.py +41 -0
  127. instaui/components/markdown/static/github-markdown.css +12 -0
  128. instaui/components/markdown/static/marked.esm.js +2579 -0
  129. instaui/components/match.py +108 -0
  130. instaui/components/row.py +17 -0
  131. instaui/components/shiki_code/shiki_code.js +126 -0
  132. instaui/components/shiki_code/shiki_code.py +99 -0
  133. instaui/components/shiki_code/static/langs/css.mjs +5 -0
  134. instaui/components/shiki_code/static/langs/markdown.mjs +5 -0
  135. instaui/components/shiki_code/static/langs/python.mjs +5 -0
  136. instaui/components/shiki_code/static/langs/shell.mjs +2 -0
  137. instaui/components/shiki_code/static/langs/shellscript.mjs +5 -0
  138. instaui/components/shiki_code/static/shiki-core.js +5784 -0
  139. instaui/components/shiki_code/static/shiki-style.css +179 -0
  140. instaui/components/shiki_code/static/shiki-transformers.js +461 -0
  141. instaui/components/shiki_code/static/themes/vitesse-dark.mjs +2 -0
  142. instaui/components/shiki_code/static/themes/vitesse-light.mjs +2 -0
  143. instaui/components/slot.py +81 -0
  144. instaui/components/transition_group.py +9 -0
  145. instaui/components/value_element.py +52 -0
  146. instaui/components/vfor.py +142 -0
  147. instaui/components/vif.py +42 -0
  148. instaui/consts.py +23 -0
  149. instaui/dependencies/component_dependency.py +22 -0
  150. instaui/dependencies/plugin_dependency.py +28 -0
  151. instaui/event/event_mixin.py +12 -0
  152. instaui/event/js_event.py +82 -0
  153. instaui/event/vue_event.py +66 -0
  154. instaui/event/web_event.py +123 -0
  155. instaui/experimental/__init__.py +3 -0
  156. instaui/experimental/debug.py +48 -0
  157. instaui/extra_libs/_echarts.py +3 -0
  158. instaui/extra_libs/_import_error.py +9 -0
  159. instaui/extra_libs/_mermaid.py +3 -0
  160. instaui/extra_libs/_shiki_code.py +3 -0
  161. instaui/fastapi_server/_utils.py +42 -0
  162. instaui/fastapi_server/_uvicorn.py +37 -0
  163. instaui/fastapi_server/debug_mode_router.py +60 -0
  164. instaui/fastapi_server/dependency_router.py +28 -0
  165. instaui/fastapi_server/event_router.py +58 -0
  166. instaui/fastapi_server/middlewares.py +19 -0
  167. instaui/fastapi_server/request_context.py +19 -0
  168. instaui/fastapi_server/resource.py +30 -0
  169. instaui/fastapi_server/server.py +308 -0
  170. instaui/fastapi_server/watch_router.py +53 -0
  171. instaui/handlers/_utils.py +88 -0
  172. instaui/handlers/event_handler.py +60 -0
  173. instaui/handlers/watch_handler.py +61 -0
  174. instaui/html_tools.py +94 -0
  175. instaui/inject.py +33 -0
  176. instaui/js/__init__.py +4 -0
  177. instaui/js/js_output.py +15 -0
  178. instaui/js/lambda_func.py +35 -0
  179. instaui/launch_collector.py +52 -0
  180. instaui/page_info.py +13 -0
  181. instaui/runtime/__init__.py +29 -0
  182. instaui/runtime/_app.py +234 -0
  183. instaui/runtime/_inner_helper.py +9 -0
  184. instaui/runtime/_link_manager.py +89 -0
  185. instaui/runtime/context.py +47 -0
  186. instaui/runtime/dataclass.py +30 -0
  187. instaui/runtime/resource.py +65 -0
  188. instaui/runtime/scope.py +133 -0
  189. instaui/runtime/ui_state_scope.py +15 -0
  190. instaui/settings/__init__.py +4 -0
  191. instaui/settings/__settings.py +13 -0
  192. instaui/shadcn_classless/_index.py +42 -0
  193. instaui/shadcn_classless/static/shadcn-classless.css +403 -0
  194. instaui/skip.py +12 -0
  195. instaui/spa_router/__init__.py +26 -0
  196. instaui/spa_router/_components.py +35 -0
  197. instaui/spa_router/_file_base_utils.py +273 -0
  198. instaui/spa_router/_functions.py +122 -0
  199. instaui/spa_router/_install.py +11 -0
  200. instaui/spa_router/_route_model.py +117 -0
  201. instaui/spa_router/_router_box.py +40 -0
  202. instaui/spa_router/_router_output.py +22 -0
  203. instaui/spa_router/_router_param_var.py +51 -0
  204. instaui/spa_router/_types.py +4 -0
  205. instaui/spa_router/templates/page_routes +60 -0
  206. instaui/static/insta-ui.css +1 -0
  207. instaui/static/insta-ui.esm-browser.prod.js +3717 -0
  208. instaui/static/insta-ui.ico +0 -0
  209. instaui/static/insta-ui.js.map +1 -0
  210. instaui/static/instaui-tools-browser.js +511 -0
  211. instaui/static/templates/debug/sse.html +117 -0
  212. instaui/static/templates/web.html +74 -0
  213. instaui/static/templates/webview.html +78 -0
  214. instaui/static/templates/zero.html +71 -0
  215. instaui/static/vue.esm-browser.prod.js +9 -0
  216. instaui/static/vue.global.prod.js +9 -0
  217. instaui/static/vue.runtime.esm-browser.prod.js +5 -0
  218. instaui/systems/file_system.py +6 -0
  219. instaui/systems/func_system.py +119 -0
  220. instaui/systems/js_system.py +22 -0
  221. instaui/systems/module_system.py +46 -0
  222. instaui/systems/pydantic_system.py +27 -0
  223. instaui/systems/string_system.py +10 -0
  224. instaui/tailwind/__init__.py +6 -0
  225. instaui/tailwind/_index.py +24 -0
  226. instaui/tailwind/static/tailwindcss-v3.min.js +62 -0
  227. instaui/tailwind/static/tailwindcss-v4.min.js +8 -0
  228. instaui/template/__init__.py +4 -0
  229. instaui/template/_utils.py +23 -0
  230. instaui/template/env.py +7 -0
  231. instaui/template/web_template.py +49 -0
  232. instaui/template/webview_template.py +48 -0
  233. instaui/template/zero_template.py +105 -0
  234. instaui/ui/__init__.py +144 -0
  235. instaui/ui/__init__.pyi +149 -0
  236. instaui/ui/events.py +25 -0
  237. instaui/ui_functions/input_slient_data.py +16 -0
  238. instaui/ui_functions/server.py +15 -0
  239. instaui/ui_functions/str_format.py +36 -0
  240. instaui/ui_functions/ui_page.py +16 -0
  241. instaui/ui_functions/ui_types.py +13 -0
  242. instaui/ui_functions/url_location.py +33 -0
  243. instaui/vars/_types.py +8 -0
  244. instaui/vars/data.py +68 -0
  245. instaui/vars/element_ref.py +40 -0
  246. instaui/vars/event_context.py +49 -0
  247. instaui/vars/event_extend.py +0 -0
  248. instaui/vars/js_computed.py +117 -0
  249. instaui/vars/mixin_types/common_type.py +5 -0
  250. instaui/vars/mixin_types/element_binding.py +16 -0
  251. instaui/vars/mixin_types/observable.py +7 -0
  252. instaui/vars/mixin_types/pathable.py +14 -0
  253. instaui/vars/mixin_types/py_binding.py +13 -0
  254. instaui/vars/mixin_types/str_format_binding.py +8 -0
  255. instaui/vars/mixin_types/var_type.py +5 -0
  256. instaui/vars/path_var.py +90 -0
  257. instaui/vars/ref.py +103 -0
  258. instaui/vars/slot_prop.py +46 -0
  259. instaui/vars/state.py +97 -0
  260. instaui/vars/types.py +24 -0
  261. instaui/vars/vfor_item.py +204 -0
  262. instaui/vars/vue_computed.py +81 -0
  263. instaui/vars/web_computed.py +209 -0
  264. instaui/vars/web_view_computed.py +1 -0
  265. instaui/version.py +3 -0
  266. instaui/watch/_types.py +4 -0
  267. instaui/watch/_utils.py +3 -0
  268. instaui/watch/js_watch.py +110 -0
  269. instaui/watch/vue_watch.py +77 -0
  270. instaui/watch/web_watch.py +181 -0
  271. instaui/webview/__init__.py +2 -0
  272. instaui/webview/_utils.py +8 -0
  273. instaui/webview/api.py +72 -0
  274. instaui/webview/func.py +114 -0
  275. instaui/webview/index.py +161 -0
  276. instaui/webview/resource.py +172 -0
  277. instaui/zero/__init__.py +3 -0
  278. instaui/zero/func.py +123 -0
  279. instaui/zero/scope.py +109 -0
  280. instaui-0.1.15.dist-info/METADATA +152 -0
  281. instaui-0.1.15.dist-info/RECORD +283 -0
  282. instaui-0.1.15.dist-info/WHEEL +5 -0
  283. instaui-0.1.15.dist-info/licenses/LICENSE +21 -0
instaui/vars/state.py ADDED
@@ -0,0 +1,97 @@
1
+ from typing import Dict, Tuple, TypeVar
2
+
3
+ from instaui import ui
4
+ from instaui.vars.mixin_types.py_binding import CanInputMixin, CanOutputMixin
5
+ from instaui.vars.mixin_types.observable import ObservableMixin
6
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
7
+ from instaui.vars.mixin_types.pathable import CanPathPropMixin
8
+ from instaui.vars.mixin_types.str_format_binding import StrFormatBindingMixin
9
+ from instaui.common.jsonable import Jsonable
10
+
11
+ from pydantic import BaseModel, RootModel
12
+
13
+ _T = TypeVar("_T")
14
+
15
+
16
+ _ProxyModel = RootModel
17
+
18
+
19
+ class RefProxy(
20
+ CanInputMixin,
21
+ ObservableMixin,
22
+ CanOutputMixin,
23
+ CanPathPropMixin,
24
+ StrFormatBindingMixin,
25
+ ElementBindingMixin,
26
+ Jsonable,
27
+ ):
28
+ def __init__(self, instance: BaseModel) -> None:
29
+ data = instance.model_dump()
30
+ self._ref_ = ui.ref(data)
31
+ self._prop_names_ = set(data.keys()) if isinstance(data, dict) else set()
32
+
33
+ def __getattribute__(self, name):
34
+ if name not in super().__getattribute__("_prop_names_"):
35
+ return super().__getattribute__(name)
36
+
37
+ return super().__getattribute__("_ref_")[name]
38
+
39
+ def __getitem__(self, name):
40
+ return super().__getattribute__("_ref_")[name]
41
+
42
+ def inverse(self):
43
+ return super().__getattribute__("_ref_").inverse()
44
+
45
+ def __add__(self, other: str):
46
+ return super().__getattribute__("_ref_") + other
47
+
48
+ def __radd__(self, other: str):
49
+ return other + super().__getattribute__("_ref_")
50
+
51
+ def _to_element_binding_config(self) -> Dict:
52
+ return super().__getattribute__("_ref_")._to_element_binding_config()
53
+
54
+ def _to_input_config(self):
55
+ return super().__getattribute__("_ref_")._to_input_config()
56
+
57
+ def _to_observable_config(self):
58
+ return super().__getattribute__("_ref_")._to_observable_config()
59
+
60
+ def _to_path_prop_binding_config(self) -> Dict:
61
+ return super().__getattribute__("_ref_")._to_path_prop_binding_config()
62
+
63
+ def _to_output_config(self):
64
+ return super().__getattribute__("_ref_")._to_output_config()
65
+
66
+ def _to_str_format_binding(self, order: int) -> Tuple[str, str]:
67
+ return super().__getattribute__("_ref_")._to_str_format_binding(order)
68
+
69
+ def _to_json_dict(self):
70
+ return super().__getattribute__("_ref_")._to_json_dict()
71
+
72
+
73
+ class StateModel(BaseModel, Jsonable):
74
+ pass
75
+
76
+ def _to_json_dict(self):
77
+ return self.model_dump()
78
+
79
+
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
+ """
96
+ obj = RefProxy(_ProxyModel(value)) # type: ignore
97
+ return obj # type: ignore
instaui/vars/types.py ADDED
@@ -0,0 +1,24 @@
1
+ from typing import Any, Union
2
+ from .ref import Ref
3
+ from .js_computed import JsComputed
4
+ from .vue_computed import VueComputed
5
+ from .web_computed import WebComputed
6
+
7
+
8
+ from ._types import _T_Value
9
+ from .mixin_types.element_binding import ElementBindingMixin
10
+
11
+
12
+ TRefOrComputed = Union[
13
+ Ref[_T_Value],
14
+ VueComputed,
15
+ JsComputed,
16
+ WebComputed[Any, _T_Value],
17
+ ]
18
+ TMaybeRef = Union[
19
+ ElementBindingMixin[_T_Value],
20
+ WebComputed,
21
+ VueComputed,
22
+ JsComputed,
23
+ _T_Value,
24
+ ]
@@ -0,0 +1,204 @@
1
+ from __future__ import annotations
2
+ from typing import Dict, Generic, Tuple, TypeVar, TYPE_CHECKING, Union, cast
3
+ from contextlib import contextmanager
4
+
5
+ from instaui.common.jsonable import Jsonable
6
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
7
+ from instaui.vars.mixin_types.py_binding import CanInputMixin, CanOutputMixin
8
+ from instaui.vars.mixin_types.pathable import CanPathPropMixin
9
+ from instaui.vars.mixin_types.str_format_binding import StrFormatBindingMixin
10
+ from instaui.vars.mixin_types.observable import ObservableMixin
11
+ from instaui.vars.path_var import PathVar
12
+
13
+ if TYPE_CHECKING:
14
+ from instaui.components.vfor import VFor
15
+
16
+ _T = TypeVar("_T")
17
+
18
+
19
+ class VForItemProxy(
20
+ PathVar,
21
+ CanInputMixin,
22
+ ObservableMixin,
23
+ CanOutputMixin,
24
+ CanPathPropMixin,
25
+ StrFormatBindingMixin,
26
+ ElementBindingMixin,
27
+ Jsonable,
28
+ Generic[_T],
29
+ ):
30
+ def __init__(self, vfor_item: VForItem[_T]):
31
+ self._vfor_item = vfor_item
32
+
33
+ def __getattr__(self, name: str):
34
+ return self._vfor_item[name]
35
+
36
+ def __getitem__(self, name):
37
+ return super().__getattribute__("_vfor_item")[name]
38
+
39
+ def _to_element_binding_config(self) -> Dict:
40
+ return super().__getattribute__("_vfor_item")._to_element_binding_config()
41
+
42
+ def _to_input_config(self):
43
+ return super().__getattribute__("_vfor_item")._to_input_config()
44
+
45
+ def _to_path_prop_binding_config(self) -> Dict:
46
+ return super().__getattribute__("_vfor_item")._to_path_prop_binding_config()
47
+
48
+ def _to_output_config(self):
49
+ return super().__getattribute__("_vfor_item")._to_output_config()
50
+
51
+ def _to_str_format_binding(self, order: int) -> Tuple[str, str]:
52
+ return super().__getattribute__("_vfor_item")._to_str_format_binding(order)
53
+
54
+ def _to_pathable_binding_config(self) -> Dict:
55
+ return super().__getattribute__("_vfor_item")._to_pathable_binding_config()
56
+
57
+ def _to_observable_config(self):
58
+ return super().__getattribute__("_vfor_item")._to_observable_config()
59
+
60
+ def _to_json_dict(self):
61
+ return super().__getattribute__("_vfor_item")._to_json_dict()
62
+
63
+
64
+ class VForItem(
65
+ PathVar,
66
+ CanInputMixin,
67
+ ObservableMixin,
68
+ CanOutputMixin,
69
+ CanPathPropMixin,
70
+ ElementBindingMixin[_T],
71
+ StrFormatBindingMixin,
72
+ Generic[_T],
73
+ ):
74
+ VAR_Type = "vf"
75
+
76
+ def __init__(self, vfor: VFor):
77
+ super().__init__()
78
+ self._vfor = vfor
79
+
80
+ @property
81
+ def dict_key(self):
82
+ return self._vfor.current[1]
83
+
84
+ @property
85
+ def dict_value(self):
86
+ return self._vfor.current[0]
87
+
88
+ @property
89
+ def proxy(self):
90
+ return cast(_T, VForItemProxy(self))
91
+
92
+ def _to_binding_config(self) -> Union[Jsonable, Dict]:
93
+ return self._to_json_dict()
94
+
95
+ def _to_element_binding_config(self):
96
+ return self._to_json_dict()
97
+
98
+ def _to_input_config(self):
99
+ return self._to_json_dict()
100
+
101
+ def _to_output_config(self):
102
+ return self._to_json_dict()
103
+
104
+ def _to_path_prop_binding_config(self) -> Dict:
105
+ return self._to_json_dict()
106
+
107
+ def _to_pathable_binding_config(self) -> Dict:
108
+ return self._to_json_dict()
109
+
110
+ def _to_observable_config(self):
111
+ return self._to_json_dict()
112
+
113
+ def _to_json_dict(self):
114
+ data: Dict = {
115
+ "type": self.VAR_Type,
116
+ "fid": self._vfor._fid,
117
+ }
118
+
119
+ return data
120
+
121
+
122
+ class VForIndex(
123
+ CanInputMixin,
124
+ CanPathPropMixin,
125
+ ElementBindingMixin,
126
+ StrFormatBindingMixin,
127
+ ):
128
+ def __init__(self, vfor: VFor):
129
+ super().__init__()
130
+ self._vfor = vfor
131
+
132
+ def _to_element_binding_config(self):
133
+ return self._to_json_dict()
134
+
135
+ def _to_input_config(self):
136
+ return self._to_json_dict()
137
+
138
+ def _to_path_prop_binding_config(self) -> Dict:
139
+ return self._to_json_dict()
140
+
141
+ def _to_json_dict(self):
142
+ return {
143
+ "type": "vf-i",
144
+ "fid": self._vfor._fid,
145
+ }
146
+
147
+
148
+ class VForDict(
149
+ CanInputMixin,
150
+ CanOutputMixin,
151
+ StrFormatBindingMixin,
152
+ ElementBindingMixin,
153
+ Jsonable,
154
+ ):
155
+ def __init__(self, vfor: VFor):
156
+ self._vfor = vfor
157
+
158
+ @property
159
+ def dict_key(self):
160
+ return self._vfor.current[1]
161
+
162
+ @property
163
+ def dict_value(self):
164
+ return self._vfor.current[0]
165
+
166
+ @contextmanager
167
+ def with_index(self):
168
+ self.__enter__()
169
+ yield self, cast(int, VForIndex(self._vfor))
170
+
171
+ def __enter__(self):
172
+ self._vfor.__enter__()
173
+ return self
174
+
175
+ def __exit__(self, *_) -> None:
176
+ return self._vfor.__exit__(*_)
177
+
178
+ def _to_element_binding_config(self) -> Dict:
179
+ return self.dict_value._to_element_binding_config()
180
+
181
+ def _to_input_config(self):
182
+ return self.dict_value._to_input_config()
183
+
184
+ def _to_output_config(self):
185
+ return self.dict_value._to_output_config()
186
+
187
+ def _to_json_dict(self):
188
+ return self.dict_value._to_json_dict()
189
+
190
+
191
+ class VForWithIndex(Generic[_T]):
192
+ def __init__(self, vfor: VFor[_T]):
193
+ self._vfor = vfor
194
+
195
+ def __enter__(self):
196
+ self._vfor.__enter__()
197
+ return cast(_T, self._vfor.current.proxy), cast(int, VForIndex(self._vfor))
198
+
199
+ def __exit__(self, *_) -> None:
200
+ return self._vfor.__exit__(*_)
201
+
202
+
203
+ TVForItem = VForItem
204
+ TVForIndex = VForIndex
@@ -0,0 +1,81 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Dict, Mapping, Optional, Union
3
+
4
+ from instaui.common.jsonable import Jsonable
5
+
6
+ from instaui.runtime._app import get_current_scope
7
+ from instaui.vars.path_var import PathVar
8
+ from instaui.vars.mixin_types.var_type import VarMixin
9
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
10
+ from instaui.vars.mixin_types.py_binding import CanInputMixin
11
+ from instaui.vars.mixin_types.pathable import CanPathPropMixin
12
+ from instaui.vars.mixin_types.str_format_binding import StrFormatBindingMixin
13
+ from instaui.vars.mixin_types.observable import ObservableMixin
14
+
15
+
16
+ class VueComputed(
17
+ Jsonable,
18
+ PathVar,
19
+ VarMixin,
20
+ CanInputMixin,
21
+ ObservableMixin,
22
+ CanPathPropMixin,
23
+ StrFormatBindingMixin,
24
+ ElementBindingMixin,
25
+ ):
26
+ BIND_TYPE = "var"
27
+
28
+ def __init__(
29
+ self,
30
+ fn_code: str,
31
+ bindings: Optional[Mapping[str, Union[ElementBindingMixin, Any]]] = None,
32
+ ) -> None:
33
+ self.code = fn_code
34
+ scope = get_current_scope()
35
+ scope.register_vue_computed(self)
36
+
37
+ self._sid = scope.id
38
+ self._id = scope.generate_vars_id()
39
+
40
+ if bindings:
41
+ const_bind = []
42
+ self.bind = {}
43
+
44
+ for k, v in bindings.items():
45
+ is_binding = isinstance(v, ElementBindingMixin)
46
+ self.bind[k] = v._to_element_binding_config() if is_binding else v
47
+ const_bind.append(int(not is_binding))
48
+
49
+ if any(i == 1 for i in const_bind):
50
+ self.const = const_bind
51
+
52
+ def __to_binding_config(self):
53
+ return {
54
+ "type": self.BIND_TYPE,
55
+ "id": self._id,
56
+ "sid": self._sid,
57
+ }
58
+
59
+ def _to_input_config(self):
60
+ return self.__to_binding_config()
61
+
62
+ def _to_path_prop_binding_config(self) -> Dict:
63
+ return self.__to_binding_config()
64
+
65
+ def _to_element_binding_config(self):
66
+ return self.__to_binding_config()
67
+
68
+ def _to_pathable_binding_config(self) -> Dict:
69
+ return self.__to_binding_config()
70
+
71
+ def _to_observable_config(self):
72
+ return self.__to_binding_config()
73
+
74
+ def _to_json_dict(self):
75
+ data = super()._to_json_dict()
76
+ data["sid"] = self._sid
77
+ data["id"] = self._id
78
+ return data
79
+
80
+
81
+ TVueComputed = VueComputed
@@ -0,0 +1,209 @@
1
+ from __future__ import annotations
2
+ import inspect
3
+ from typing import (
4
+ Any,
5
+ Callable,
6
+ Dict,
7
+ Generic,
8
+ Optional,
9
+ Sequence,
10
+ TypeVar,
11
+ )
12
+ from typing_extensions import ParamSpec
13
+
14
+ from instaui.common.jsonable import Jsonable
15
+ from instaui.runtime._app import get_app_slot, get_current_scope
16
+ from instaui.handlers import watch_handler
17
+
18
+ from instaui.vars.path_var import PathVar
19
+ from instaui.vars.mixin_types.py_binding import CanInputMixin, CanOutputMixin
20
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
21
+ from instaui.vars.mixin_types.pathable import CanPathPropMixin
22
+ from instaui.vars.mixin_types.str_format_binding import StrFormatBindingMixin
23
+ from instaui.vars.mixin_types.observable import ObservableMixin
24
+ from instaui.vars.mixin_types.common_type import TObservableInput
25
+ from instaui._helper import observable_helper
26
+
27
+ _SYNC_TYPE = "sync"
28
+ _ASYNC_TYPE = "async"
29
+
30
+ P = ParamSpec("P")
31
+ R = TypeVar("R")
32
+
33
+
34
+ class WebComputed(
35
+ Jsonable,
36
+ PathVar,
37
+ CanInputMixin,
38
+ ObservableMixin,
39
+ CanPathPropMixin,
40
+ StrFormatBindingMixin,
41
+ ElementBindingMixin[R],
42
+ Generic[P, R],
43
+ ):
44
+ BIND_TYPE = "var"
45
+
46
+ def __init__(
47
+ self,
48
+ func: Callable[P, R],
49
+ inputs: Optional[Sequence[TObservableInput]] = None,
50
+ extend_outputs: Optional[Sequence[CanOutputMixin]] = None,
51
+ init_value: Optional[R] = None,
52
+ evaluating: Optional[CanOutputMixin] = None,
53
+ deep_compare_on_input: bool = False,
54
+ debug_info: Optional[Dict] = None,
55
+ ) -> None:
56
+ scope = get_current_scope()
57
+
58
+ self._sid = scope.id
59
+ self._id = scope.generate_vars_id()
60
+ get_current_scope().register_web_computed(self)
61
+
62
+ self._org_inputs = inputs or []
63
+
64
+ self._inputs, self._is_slient_inputs, self._is_data = (
65
+ observable_helper.analyze_observable_inputs(list(inputs or []))
66
+ )
67
+ self._outputs = [output._to_output_config() for output in extend_outputs or []]
68
+ self._fn = func
69
+ self._init_value = init_value
70
+ self._evaluating = evaluating
71
+ self._deep_compare_on_input = deep_compare_on_input
72
+ self.__be_used = False
73
+
74
+ if debug_info is not None:
75
+ self.debug = debug_info
76
+
77
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
78
+ return self._fn(*args, **kwargs)
79
+
80
+ def _to_json_dict(self):
81
+ data = super()._to_json_dict()
82
+
83
+ app = get_app_slot()
84
+
85
+ hkey = watch_handler.create_handler_key(
86
+ page_path=app.page_path,
87
+ handler=self._fn,
88
+ )
89
+
90
+ watch_handler.register_handler(hkey, self._fn, len(self._outputs) + 1)
91
+
92
+ data["id"] = self._id
93
+ data["sid"] = self._sid
94
+
95
+ if self._inputs:
96
+ data["inputs"] = self._inputs
97
+
98
+ if self._outputs:
99
+ data["outputs"] = self._outputs
100
+
101
+ if sum(self._is_slient_inputs) > 0:
102
+ data["slient"] = self._is_slient_inputs
103
+
104
+ if sum(self._is_data) > 0:
105
+ data["data"] = self._is_data
106
+
107
+ data["fType"] = (
108
+ _ASYNC_TYPE if inspect.iscoroutinefunction(self._fn) else _SYNC_TYPE
109
+ )
110
+ data["key"] = hkey
111
+ if self._init_value is not None:
112
+ data["init"] = self._init_value
113
+
114
+ if self._evaluating:
115
+ data["running"] = self._evaluating._to_output_config()
116
+
117
+ if self._deep_compare_on_input is not False:
118
+ data["deepEqOnInput"] = 1
119
+
120
+ return data
121
+
122
+ def __to_binding_config(self):
123
+ return {
124
+ "type": self.BIND_TYPE,
125
+ "id": self._id,
126
+ "sid": self._sid,
127
+ }
128
+
129
+ def _to_pathable_binding_config(self) -> Dict:
130
+ return self.__to_binding_config()
131
+
132
+ def _to_path_prop_binding_config(self) -> Dict:
133
+ return self.__to_binding_config()
134
+
135
+ def _to_input_config(self):
136
+ return self.__to_binding_config()
137
+
138
+ def _to_element_binding_config(self):
139
+ return self.__to_binding_config()
140
+
141
+ def _to_observable_config(self):
142
+ return self.__to_binding_config()
143
+
144
+ def _mark_used(self):
145
+ if self.__be_used:
146
+ return
147
+
148
+ self.__be_used = True
149
+ for input_ in self._org_inputs:
150
+ if isinstance(input_, ElementBindingMixin):
151
+ input_._mark_used()
152
+
153
+ def _is_used(self):
154
+ return self.__be_used
155
+
156
+
157
+ def web_computed(
158
+ *,
159
+ inputs: Optional[Sequence] = None,
160
+ extend_outputs: Optional[Sequence] = None,
161
+ init_value: Optional[Any] = None,
162
+ evaluating: Optional[Any] = None,
163
+ deep_compare_on_input: bool = False,
164
+ debug_info: Optional[Dict] = None,
165
+ ):
166
+ """
167
+ Creates a computed property decorator for reactive programming with dependency tracking.
168
+
169
+ This decorator factory wraps functions to create reactive computed properties that:
170
+ - Automatically re-evaluate when dependencies (inputs) change
171
+ - Cache results for performance optimization
172
+ - Support both synchronous and asynchronous computation patterns
173
+
174
+ Args:
175
+ inputs (Optional[Sequence], optional): Collection of reactive sources that trigger recomputation
176
+ when changed. These can be state objects or other computed properties.
177
+ extend_outputs (Optional[Sequence], optional): Additional outputs to notify when this computed value updates.
178
+ init_value (Optional[Any], optional): Initial value to return before first successful evaluation.
179
+ evaluating (Optional[Any], optional): Temporary value returned during asynchronous computation.
180
+
181
+ # Example:
182
+ .. code-block:: python
183
+ from instaui import ui,html
184
+
185
+ a = ui.state(0)
186
+
187
+ @ui.computed(inputs=[a])
188
+ def plus_one(a):
189
+ return a + 1
190
+
191
+ html.number(a)
192
+ ui.label(plus_one)
193
+ """
194
+
195
+ def wrapper(func: Callable[P, R]):
196
+ return WebComputed(
197
+ func,
198
+ inputs=inputs,
199
+ extend_outputs=extend_outputs,
200
+ init_value=init_value,
201
+ evaluating=evaluating,
202
+ deep_compare_on_input=deep_compare_on_input,
203
+ debug_info=debug_info,
204
+ )
205
+
206
+ return wrapper
207
+
208
+
209
+ TComputed = WebComputed
@@ -0,0 +1 @@
1
+ from __future__ import annotations
instaui/version.py ADDED
@@ -0,0 +1,3 @@
1
+ import importlib.metadata
2
+
3
+ __version__: str = importlib.metadata.version("instaui")
@@ -0,0 +1,4 @@
1
+ from typing import Literal
2
+
3
+
4
+ TFlush = Literal["pre", "post", "sync"]
@@ -0,0 +1,3 @@
1
+ def assert_deep(deep):
2
+ if isinstance(deep, int):
3
+ assert deep >= 0, "deep must be greater than or equal to 0"