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
@@ -0,0 +1,15 @@
1
+ from instaui.common.jsonable import Jsonable
2
+ from instaui.vars.mixin_types.py_binding import CanOutputMixin
3
+
4
+
5
+ class JsOutput(Jsonable, CanOutputMixin):
6
+ def __init__(self):
7
+ self.type = "jsOutput"
8
+
9
+ def _to_output_config(self):
10
+ return self._to_json_dict()
11
+
12
+ def _to_json_dict(self):
13
+ data = super()._to_json_dict()
14
+
15
+ return data
@@ -0,0 +1,35 @@
1
+ from typing import Dict
2
+ from instaui.common.jsonable import Jsonable
3
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
4
+
5
+
6
+ class LambdaFunc(Jsonable, ElementBindingMixin):
7
+ def __init__(
8
+ self, code: str, *, bindings: Dict[str, ElementBindingMixin], computed=False
9
+ ):
10
+ self.code = code
11
+ self.type = "js"
12
+ self._bindings = bindings
13
+ self._computed = computed
14
+
15
+ def _to_binding_config(self) -> Dict:
16
+ return self._to_json_dict()
17
+
18
+ def _to_js_binding_config(self):
19
+ return self._to_json_dict()
20
+
21
+ def _to_element_binding_config(self):
22
+ return self._to_json_dict()
23
+
24
+ def _to_json_dict(self):
25
+ data = super()._to_json_dict()
26
+
27
+ if self._bindings:
28
+ data["bind"] = {
29
+ k: v._to_element_binding_config() for k, v in self._bindings.items()
30
+ }
31
+
32
+ if self._computed is True:
33
+ data["ext"] = ["cpt"]
34
+
35
+ return data
@@ -0,0 +1,52 @@
1
+ from __future__ import annotations
2
+ from typing import Callable, Dict, List, Optional
3
+ from instaui.consts import _T_App_Mode
4
+ from instaui.page_info import PageInfo
5
+ from instaui.systems import func_system
6
+
7
+
8
+ class LaunchCollector:
9
+ _instance: Optional[LaunchCollector] = None
10
+
11
+ @classmethod
12
+ def get_instance(cls, *args, **kwargs):
13
+ if cls._instance is None:
14
+ cls._instance = cls(*args, **kwargs)
15
+ return cls._instance
16
+
17
+ def __init__(self) -> None:
18
+ self._page_router: Dict[str, PageInfo] = {}
19
+ self._page_request_lifespans: Dict[int, Callable] = {}
20
+ self._app_mode: _T_App_Mode = "web"
21
+
22
+ @property
23
+ def page_request_lifespans(self) -> List[Callable]:
24
+ return list(self._page_request_lifespans.values())
25
+
26
+ def register_page(self, info: PageInfo) -> None:
27
+ self._page_router[info.path] = info
28
+
29
+ def add_page_request_lifespan(self, lifespan: Callable) -> int:
30
+ """Register a function to be called on each page request.
31
+
32
+ Args:
33
+ lifespan (Callable): A function to be called on each page request.
34
+
35
+ Returns:
36
+ int: A unique key to identify the registered lifespan function.
37
+ """
38
+ key = id(lifespan)
39
+ self._page_request_lifespans[key] = func_system.make_fn_to_generator(lifespan)
40
+
41
+ return key
42
+
43
+ def remove_page_request_lifespan(self, key: int) -> None:
44
+ if key in self._page_request_lifespans:
45
+ del self._page_request_lifespans[key]
46
+
47
+ def set_app_mode(self, mode: _T_App_Mode) -> None:
48
+ self._app_mode = mode
49
+
50
+
51
+ def get_launch_collector() -> LaunchCollector:
52
+ return LaunchCollector.get_instance()
instaui/page_info.py ADDED
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+ from typing import Callable
3
+ from dataclasses import dataclass
4
+ from urllib.parse import quote
5
+
6
+
7
+ @dataclass
8
+ class PageInfo:
9
+ path: str
10
+ func: Callable
11
+
12
+ def create_key(self) -> str:
13
+ return quote(self.path)
@@ -0,0 +1,29 @@
1
+ from ._app import (
2
+ get_app_slot,
3
+ reset_app_slot,
4
+ new_app_slot,
5
+ use_default_app_slot,
6
+ get_slot_stacks,
7
+ pop_slot,
8
+ get_current_scope,
9
+ new_scope,
10
+ check_default_app_slot_or_error,
11
+ in_default_app_slot,
12
+ )
13
+ from ._inner_helper import check_web_only_mode_or_error
14
+ from .resource import HtmlResource
15
+
16
+ __all__ = [
17
+ "get_slot_stacks",
18
+ "new_scope",
19
+ "get_current_scope",
20
+ "get_app_slot",
21
+ "reset_app_slot",
22
+ "new_app_slot",
23
+ "use_default_app_slot",
24
+ "pop_slot",
25
+ "check_web_only_mode_or_error",
26
+ "check_default_app_slot_or_error",
27
+ "in_default_app_slot",
28
+ "HtmlResource",
29
+ ]
@@ -0,0 +1,234 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Set
4
+ from typing_extensions import Unpack, TypedDict
5
+ from instaui.common.jsonable import Jsonable
6
+ from .resource import HtmlResource
7
+ from instaui.consts import _T_App_Mode
8
+ from contextvars import ContextVar, Token
9
+ from contextlib import contextmanager
10
+ from instaui.runtime.scope import Scope, GlobalScope
11
+ from types import MappingProxyType
12
+
13
+ if TYPE_CHECKING:
14
+ from instaui.components.component import Component
15
+ from instaui.components.slot import Slot
16
+
17
+ from instaui.dependencies.component_dependency import ComponentDependencyInfo
18
+ from instaui.dependencies.plugin_dependency import PluginDependencyInfo
19
+ from instaui.spa_router._route_model import RouteCollector
20
+
21
+
22
+ class App(Jsonable):
23
+ _default_app_slot: ClassVar[Optional[App]] = None
24
+ _web_server_info: ClassVar[Optional[Dict]] = None
25
+
26
+ def __init__(self, *, mode: _T_App_Mode, meta: Optional[Dict] = None) -> None:
27
+ super().__init__()
28
+ self._scope_id_counter = 0
29
+ self._vfor_id_counter = 0
30
+ self._slot_id_counter = 0
31
+ self.mode: _T_App_Mode = mode
32
+ self.items: List[Component] = []
33
+ self.meta = meta
34
+ self._slots_stacks: List[Slot] = []
35
+
36
+ defalut_scope = self.create_scope()
37
+ self._scope_stack: List[Scope] = [defalut_scope]
38
+ self._scopes: List[Scope] = [defalut_scope]
39
+ self._html_resource = HtmlResource()
40
+ self._component_dependencies: Set[ComponentDependencyInfo] = set()
41
+ self._temp_component_dependencies: Dict[str, ComponentDependencyInfo] = {}
42
+ self._plugin_dependencies: Set[PluginDependencyInfo] = set()
43
+
44
+ self._page_path: Optional[str] = None
45
+ self._page_params: Dict[str, Any] = {}
46
+ self._query_params: Dict[str, Any] = {}
47
+ self._route_collector: Optional[RouteCollector] = None
48
+
49
+ @property
50
+ def page_path(self) -> str:
51
+ assert self._page_path is not None, "Page path is not set"
52
+ return self._page_path # type: ignore
53
+
54
+ @property
55
+ def page_params(self):
56
+ return MappingProxyType(self._page_params)
57
+
58
+ @property
59
+ def query_params(self):
60
+ return MappingProxyType(self._query_params)
61
+
62
+ def create_scope(self) -> Scope:
63
+ self._scope_id_counter += 1
64
+ scope = Scope(str(self._scope_id_counter))
65
+ return scope
66
+
67
+ def generate_vfor_id(self) -> str:
68
+ self._vfor_id_counter += 1
69
+ return str(self._vfor_id_counter)
70
+
71
+ def generate_slot_id(self) -> str:
72
+ self._slot_id_counter += 1
73
+ return str(self._slot_id_counter)
74
+
75
+ def reset_html_resource(self):
76
+ self._html_resource = HtmlResource()
77
+
78
+ def add_temp_component_dependency(self, dependency: ComponentDependencyInfo):
79
+ self._temp_component_dependencies[dependency.tag_name] = dependency
80
+
81
+ def get_temp_component_dependency(
82
+ self, tag_name: str, default: ComponentDependencyInfo
83
+ ) -> ComponentDependencyInfo:
84
+ return self._temp_component_dependencies.get(tag_name, default)
85
+
86
+ def has_temp_component_dependency(self, tag_name: str):
87
+ return tag_name in self._temp_component_dependencies
88
+
89
+ def use_component_dependency(
90
+ self, dependency: ComponentDependencyInfo, *, replace=False
91
+ ) -> None:
92
+ if replace:
93
+ self._component_dependencies.discard(dependency)
94
+
95
+ self._component_dependencies.add(dependency)
96
+
97
+ def use_plugin_dependency(self, dependency: PluginDependencyInfo) -> None:
98
+ self._plugin_dependencies.add(dependency)
99
+
100
+ def register_router(self, collector: RouteCollector) -> None:
101
+ self._route_collector = collector
102
+
103
+ def append_component_to_container(self, component: Component):
104
+ if self._slots_stacks:
105
+ self._slots_stacks[-1]._children.append(component)
106
+ else:
107
+ self.items.append(component)
108
+
109
+ def _to_json_dict(self):
110
+ data = super()._to_json_dict()
111
+
112
+ if self._page_path:
113
+ url_info = {"path": self.page_path}
114
+ if self._page_params:
115
+ url_info["params"] = self._page_params # type: ignore
116
+
117
+ data["url"] = url_info
118
+
119
+ assert len(self._scopes) == 1, "Only one scope is allowed"
120
+ data["scope"] = self._scopes[0]
121
+
122
+ if self._route_collector is not None:
123
+ data["router"] = self._route_collector.model_dump(
124
+ exclude_defaults=True, by_alias=True
125
+ )
126
+
127
+ if self._web_server_info is not None:
128
+ data["webInfo"] = self._web_server_info
129
+
130
+ return data
131
+
132
+ @classmethod
133
+ def _create_default(cls):
134
+ if cls._default_app_slot is None:
135
+ cls._default_app_slot = DefaultApp(mode="web")
136
+ return cls._default_app_slot
137
+
138
+
139
+ class DefaultApp(App):
140
+ _instance = None
141
+
142
+ def __new__(cls, *args, **kwargs):
143
+ if cls._instance is None:
144
+ cls._instance = super(DefaultApp, cls).__new__(cls)
145
+ return cls._instance
146
+
147
+ def create_scope(self) -> Scope:
148
+ self._scope_id_counter += 1
149
+ scope = GlobalScope(str(self._scope_id_counter))
150
+ return scope
151
+
152
+ def append_component_to_container(self, component: Component):
153
+ raise ValueError("Operations are not allowed outside of ui.page")
154
+
155
+
156
+ _app_var: ContextVar[App] = ContextVar("_app_var", default=App._create_default())
157
+
158
+
159
+ def use_default_app_slot():
160
+ assert App._default_app_slot is not None, "Default app slot is not set"
161
+ _app_var.set(App._default_app_slot)
162
+
163
+
164
+ def get_default_app_slot():
165
+ return App._create_default()
166
+
167
+
168
+ def get_app_slot() -> App:
169
+ return _app_var.get()
170
+
171
+
172
+ def get_current_scope():
173
+ current_scope = get_app_slot()._scope_stack[-1]
174
+ if current_scope is None:
175
+ raise ValueError("No current scope")
176
+ return current_scope
177
+
178
+
179
+ @contextmanager
180
+ def new_scope(*, append_to_app: bool = True):
181
+ app = get_app_slot()
182
+ scope = app.create_scope()
183
+
184
+ if append_to_app:
185
+ app._scopes.append(scope)
186
+
187
+ scope_stack = app._scope_stack
188
+ scope_stack.append(scope)
189
+
190
+ yield scope
191
+ scope_stack.pop()
192
+
193
+
194
+ def get_slot_stacks():
195
+ return get_app_slot()._slots_stacks
196
+
197
+
198
+ def pop_slot():
199
+ get_slot_stacks().pop()
200
+
201
+
202
+ def new_app_slot(mode: _T_App_Mode, app_meta: Optional[Dict] = None):
203
+ return _app_var.set(App(mode=mode, meta=app_meta))
204
+
205
+
206
+ def reset_app_slot(token: Token[App]):
207
+ _app_var.reset(token)
208
+
209
+
210
+ def in_default_app_slot():
211
+ return isinstance(get_app_slot(), DefaultApp)
212
+
213
+
214
+ def check_default_app_slot_or_error(
215
+ error_message="Operations are not allowed outside of ui.page",
216
+ ):
217
+ if isinstance(get_app_slot(), DefaultApp):
218
+ raise ValueError(error_message)
219
+
220
+
221
+ class TWebServerInfo(TypedDict, total=False):
222
+ watch_url: Optional[str]
223
+ watch_async_url: Optional[str]
224
+ event_url: Optional[str]
225
+ event_async_url: Optional[str]
226
+
227
+
228
+ def update_web_server_info(**kwargs: Unpack[TWebServerInfo]):
229
+ if App._web_server_info is None:
230
+ App._web_server_info = {}
231
+
232
+ data = {k: v for k, v in kwargs.items() if v is not None}
233
+
234
+ App._web_server_info.update(data)
@@ -0,0 +1,9 @@
1
+ from instaui.runtime.context import get_context
2
+
3
+
4
+ def check_web_only_mode_or_error(method_name: str = ""):
5
+ mode = get_context().app_mode
6
+ if mode != "web" and mode != "webview":
7
+ raise Exception(
8
+ f"{method_name} This is a web-only feature. Please use the 'web' or 'webview' mode."
9
+ )
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+ from typing import (
3
+ Callable,
4
+ Dict,
5
+ Generic,
6
+ List,
7
+ Literal,
8
+ Optional,
9
+ Tuple,
10
+ TypeVar,
11
+ Hashable,
12
+ )
13
+
14
+ _TLinkActionObj = TypeVar("_TLinkActionObj")
15
+
16
+ _DEFAULT_KEY_FN = lambda x: x # noqa: E731
17
+
18
+
19
+ class LinkManager(Generic[_TLinkActionObj]):
20
+ def __init__(
21
+ self, key_fn: Optional[Callable[[_TLinkActionObj], Hashable]] = None
22
+ ) -> None:
23
+ self._key_fn = key_fn or _DEFAULT_KEY_FN
24
+ self._actions_map: Dict[
25
+ Tuple[Literal["add", "remove"], Hashable], _TLinkActionObj
26
+ ] = {}
27
+
28
+ def add_link(
29
+ self,
30
+ obj: _TLinkActionObj,
31
+ ):
32
+ key = ("add", self._key_fn(obj))
33
+ self._actions_map[key] = obj
34
+
35
+ def remove_link(
36
+ self,
37
+ obj: _TLinkActionObj,
38
+ ):
39
+ key = ("remove", self._key_fn(obj))
40
+ self._actions_map[key] = obj
41
+
42
+ def get_valid_links(
43
+ self, secondary_manager: Optional[LinkManager] = None
44
+ ) -> List[_TLinkActionObj]:
45
+ secondary_maps = secondary_manager._actions_map if secondary_manager else {}
46
+ merger_map = {**secondary_maps, **self._actions_map}
47
+
48
+ result = {}
49
+
50
+ for (action, key), obj in merger_map.items():
51
+ if action == "add":
52
+ result[key] = obj
53
+ continue
54
+
55
+ if key in result:
56
+ del result[key]
57
+
58
+ return list(result.values())
59
+
60
+
61
+ if __name__ == "__main__":
62
+
63
+ def test_baes():
64
+ manager: LinkManager[str] = LinkManager()
65
+ manager.add_link("a")
66
+ manager.add_link("b")
67
+ manager.add_link("c")
68
+ manager.remove_link("b")
69
+
70
+ assert manager.get_valid_links() == ["a", "c"]
71
+
72
+ test_baes()
73
+
74
+ def test_with_other():
75
+ other: LinkManager[str] = LinkManager()
76
+ other.add_link("a")
77
+ other.add_link("b")
78
+ other.add_link("c")
79
+
80
+ manager1: LinkManager[str] = LinkManager()
81
+ manager1.add_link("b")
82
+ manager1.add_link("d")
83
+ manager1.add_link("e")
84
+ manager1.remove_link("a")
85
+ manager1.remove_link("b")
86
+
87
+ assert manager1.get_valid_links(other) == ["c", "d", "e"]
88
+
89
+ test_with_other()
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Dict, Optional
3
+ from instaui import consts
4
+ from ._app import get_app_slot
5
+
6
+
7
+ class Context:
8
+ _instance: Optional[Context] = None
9
+
10
+ @classmethod
11
+ def get_instance(cls, *args, **kwargs):
12
+ if cls._instance is None:
13
+ cls._instance = cls(*args, **kwargs)
14
+ return cls._instance
15
+
16
+ def __init__(self):
17
+ self._app_mode: consts._T_App_Mode = "web"
18
+ self._debug_mode: bool = False
19
+ self._page_params: Dict[str, Any] = {}
20
+
21
+ @property
22
+ def app_mode(self):
23
+ return self._app_mode
24
+
25
+ @property
26
+ def debug_mode(self):
27
+ return self._debug_mode
28
+
29
+ @property
30
+ def page_path(self):
31
+ return get_app_slot().page_path
32
+
33
+ @property
34
+ def page_params(self):
35
+ return get_app_slot().page_params
36
+
37
+ @property
38
+ def query_params(self):
39
+ return get_app_slot().query_params
40
+
41
+
42
+ def get_context():
43
+ return Context.get_instance()
44
+
45
+
46
+ def set_debug(debug=True):
47
+ get_context()._debug_mode = debug
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+ from pathlib import Path
3
+ from typing import Any, Dict, Union
4
+ from dataclasses import dataclass, field
5
+
6
+
7
+ @dataclass
8
+ class JsLink:
9
+ link: Union[str, Path]
10
+ attrs: Dict[str, Any] = field(default_factory=dict)
11
+
12
+ def create_attrs_str(self):
13
+ return " ".join(f'{k}="{v}"' for k, v in self.attrs.items() if v is not None)
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class VueAppUse:
18
+ name: str
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class VueAppComponent:
23
+ name: str
24
+ url: str
25
+
26
+
27
+ @dataclass
28
+ class ImportMaps:
29
+ name: str
30
+ url: str
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+ from pathlib import Path
3
+ from typing import Any, Dict, List, Optional, Set, Union
4
+ from .dataclass import JsLink, VueAppUse, VueAppComponent
5
+ from ._link_manager import LinkManager
6
+
7
+
8
+ class HtmlResource:
9
+ use_tailwind: Optional[bool] = None
10
+ title: Optional[str] = None
11
+ favicon: Optional[Path] = None
12
+
13
+ def __init__(self) -> None:
14
+ self._css_links_manager: LinkManager[Union[str, Path]] = LinkManager()
15
+ self._style_tags: List[str] = []
16
+ self._js_links_manager: LinkManager[JsLink] = LinkManager(
17
+ key_fn=lambda js_link: js_link.link
18
+ )
19
+ self._script_tags: List[str] = []
20
+ self._vue_app_use: Set[VueAppUse] = set()
21
+ self._vue_app_components: Set[VueAppComponent] = set()
22
+ self._import_maps: Dict[str, str] = {}
23
+ self._appConfig = "{}"
24
+
25
+ def add_css_link(self, link: Union[str, Path]):
26
+ self._css_links_manager.add_link(link)
27
+
28
+ def remove_css_link(self, link: Union[str, Path]):
29
+ self._css_links_manager.remove_link(link)
30
+
31
+ def add_style_tag(self, content: str):
32
+ self._style_tags.append(content)
33
+
34
+ def add_js_link(
35
+ self,
36
+ link: Union[str, Path],
37
+ *,
38
+ attrs: Optional[Dict[str, Any]] = None,
39
+ ):
40
+ self._js_links_manager.add_link(JsLink(link, attrs or {}))
41
+
42
+ def remove_js_link(self, link: Union[str, Path]):
43
+ self._js_links_manager.remove_link(JsLink(link))
44
+
45
+ def get_valid_js_links(self, default_js_links_manager: LinkManager) -> List[JsLink]:
46
+ return self._js_links_manager.get_valid_links(default_js_links_manager)
47
+
48
+ def get_valid_css_links(
49
+ self, default_css_links_manager: LinkManager[Union[str, Path]]
50
+ ) -> List[Union[str, Path]]:
51
+ return self._css_links_manager.get_valid_links(default_css_links_manager)
52
+
53
+ def add_script_tag(
54
+ self, content: str, script_attrs: Optional[Dict[str, Any]] = None
55
+ ):
56
+ self._script_tags.append(content)
57
+
58
+ def add_vue_app_use(self, name: str):
59
+ self._vue_app_use.add(VueAppUse(name))
60
+
61
+ def add_vue_app_component(self, name: str, url: str):
62
+ self._vue_app_components.add(VueAppComponent(name, url))
63
+
64
+ def add_import_map(self, name: str, link: str):
65
+ self._import_maps[name] = link