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.
- instaui/__init__.py +9 -0
- instaui/_helper/observable_helper.py +45 -0
- instaui/arco/__init__.py +191 -0
- instaui/arco/_settings.py +25 -0
- instaui/arco/_use_tools/locale.py +50 -0
- instaui/arco/component_types.py +1019 -0
- instaui/arco/components/_utils.py +22 -0
- instaui/arco/components/affix.py +29 -0
- instaui/arco/components/alert.py +42 -0
- instaui/arco/components/anchor.py +42 -0
- instaui/arco/components/auto_complete.py +96 -0
- instaui/arco/components/avatar.py +55 -0
- instaui/arco/components/back_top.py +14 -0
- instaui/arco/components/badge.py +14 -0
- instaui/arco/components/breadcrumb.py +14 -0
- instaui/arco/components/button.py +43 -0
- instaui/arco/components/calendar.py +47 -0
- instaui/arco/components/card.py +14 -0
- instaui/arco/components/carousel.py +33 -0
- instaui/arco/components/cascader.py +111 -0
- instaui/arco/components/checkbox.py +32 -0
- instaui/arco/components/collapse.py +31 -0
- instaui/arco/components/color_picker.py +45 -0
- instaui/arco/components/comment.py +14 -0
- instaui/arco/components/config_provider.py +13 -0
- instaui/arco/components/date_picker.py +111 -0
- instaui/arco/components/descriptions.py +14 -0
- instaui/arco/components/divider.py +13 -0
- instaui/arco/components/drawer.py +98 -0
- instaui/arco/components/dropdown.py +45 -0
- instaui/arco/components/empty.py +14 -0
- instaui/arco/components/form.py +55 -0
- instaui/arco/components/icon.py +17 -0
- instaui/arco/components/image.py +33 -0
- instaui/arco/components/input.py +102 -0
- instaui/arco/components/input_number.py +97 -0
- instaui/arco/components/input_password.py +38 -0
- instaui/arco/components/input_search.py +37 -0
- instaui/arco/components/input_tag.py +110 -0
- instaui/arco/components/layout.py +13 -0
- instaui/arco/components/layout_content.py +6 -0
- instaui/arco/components/layout_footer.py +6 -0
- instaui/arco/components/layout_header.py +6 -0
- instaui/arco/components/layout_sider.py +53 -0
- instaui/arco/components/link.py +36 -0
- instaui/arco/components/list.py +68 -0
- instaui/arco/components/mention.py +97 -0
- instaui/arco/components/menu.py +88 -0
- instaui/arco/components/modal.py +97 -0
- instaui/arco/components/overflow_list.py +29 -0
- instaui/arco/components/page_header.py +29 -0
- instaui/arco/components/pagination.py +45 -0
- instaui/arco/components/pop_confirm.py +58 -0
- instaui/arco/components/popover.py +32 -0
- instaui/arco/components/progress.py +14 -0
- instaui/arco/components/radio.py +40 -0
- instaui/arco/components/radio_group.py +42 -0
- instaui/arco/components/rate.py +45 -0
- instaui/arco/components/resize_box.py +62 -0
- instaui/arco/components/result.py +14 -0
- instaui/arco/components/select.py +182 -0
- instaui/arco/components/skeleton.py +14 -0
- instaui/arco/components/slider.py +38 -0
- instaui/arco/components/space.py +14 -0
- instaui/arco/components/spin.py +14 -0
- instaui/arco/components/split.py +76 -0
- instaui/arco/components/statistic.py +14 -0
- instaui/arco/components/steps.py +32 -0
- instaui/arco/components/switch.py +57 -0
- instaui/arco/components/tab_pane.py +12 -0
- instaui/arco/components/table.py +276 -0
- instaui/arco/components/tabs.py +101 -0
- instaui/arco/components/tag.py +42 -0
- instaui/arco/components/textarea.py +84 -0
- instaui/arco/components/time_picker.py +76 -0
- instaui/arco/components/timeline.py +14 -0
- instaui/arco/components/tooltip.py +29 -0
- instaui/arco/components/transfer.py +58 -0
- instaui/arco/components/tree.py +120 -0
- instaui/arco/components/tree_select.py +86 -0
- instaui/arco/components/trigger.py +58 -0
- instaui/arco/components/typography.py +142 -0
- instaui/arco/components/upload.py +71 -0
- instaui/arco/components/verification_code.py +58 -0
- instaui/arco/components/watermark.py +14 -0
- instaui/arco/locales/__init__.py +4 -0
- instaui/arco/locales/_index.py +31 -0
- instaui/arco/locales/en_us.py +227 -0
- instaui/arco/locales/zh_cn.py +224 -0
- instaui/arco/setup.py +36 -0
- instaui/arco/static/instaui-arco.css +1 -0
- instaui/arco/static/instaui-arco.js +55771 -0
- instaui/arco/types.py +24 -0
- instaui/boot_info.py +43 -0
- instaui/common/jsonable.py +37 -0
- instaui/components/__init__.py +0 -0
- instaui/components/column.py +26 -0
- instaui/components/component.py +47 -0
- instaui/components/content.py +34 -0
- instaui/components/directive.py +55 -0
- instaui/components/element.py +573 -0
- instaui/components/grid.py +213 -0
- instaui/components/html/__init__.py +49 -0
- instaui/components/html/_mixins.py +34 -0
- instaui/components/html/_preset.py +4 -0
- instaui/components/html/button.py +38 -0
- instaui/components/html/checkbox.py +35 -0
- instaui/components/html/date.py +28 -0
- instaui/components/html/div.py +7 -0
- instaui/components/html/form.py +7 -0
- instaui/components/html/heading.py +51 -0
- instaui/components/html/input.py +28 -0
- instaui/components/html/label.py +21 -0
- instaui/components/html/li.py +17 -0
- instaui/components/html/link.py +31 -0
- instaui/components/html/number.py +34 -0
- instaui/components/html/paragraph.py +29 -0
- instaui/components/html/range.py +48 -0
- instaui/components/html/select.py +69 -0
- instaui/components/html/span.py +19 -0
- instaui/components/html/table.py +36 -0
- instaui/components/html/textarea.py +28 -0
- instaui/components/html/ul.py +20 -0
- instaui/components/label.py +5 -0
- instaui/components/markdown/markdown.js +33 -0
- instaui/components/markdown/markdown.py +41 -0
- instaui/components/markdown/static/github-markdown.css +12 -0
- instaui/components/markdown/static/marked.esm.js +2579 -0
- instaui/components/match.py +108 -0
- instaui/components/row.py +17 -0
- instaui/components/shiki_code/shiki_code.js +126 -0
- instaui/components/shiki_code/shiki_code.py +99 -0
- instaui/components/shiki_code/static/langs/css.mjs +5 -0
- instaui/components/shiki_code/static/langs/markdown.mjs +5 -0
- instaui/components/shiki_code/static/langs/python.mjs +5 -0
- instaui/components/shiki_code/static/langs/shell.mjs +2 -0
- instaui/components/shiki_code/static/langs/shellscript.mjs +5 -0
- instaui/components/shiki_code/static/shiki-core.js +5784 -0
- instaui/components/shiki_code/static/shiki-style.css +179 -0
- instaui/components/shiki_code/static/shiki-transformers.js +461 -0
- instaui/components/shiki_code/static/themes/vitesse-dark.mjs +2 -0
- instaui/components/shiki_code/static/themes/vitesse-light.mjs +2 -0
- instaui/components/slot.py +81 -0
- instaui/components/transition_group.py +9 -0
- instaui/components/value_element.py +52 -0
- instaui/components/vfor.py +142 -0
- instaui/components/vif.py +42 -0
- instaui/consts.py +23 -0
- instaui/dependencies/component_dependency.py +22 -0
- instaui/dependencies/plugin_dependency.py +28 -0
- instaui/event/event_mixin.py +12 -0
- instaui/event/js_event.py +82 -0
- instaui/event/vue_event.py +66 -0
- instaui/event/web_event.py +123 -0
- instaui/experimental/__init__.py +3 -0
- instaui/experimental/debug.py +48 -0
- instaui/extra_libs/_echarts.py +3 -0
- instaui/extra_libs/_import_error.py +9 -0
- instaui/extra_libs/_mermaid.py +3 -0
- instaui/extra_libs/_shiki_code.py +3 -0
- instaui/fastapi_server/_utils.py +42 -0
- instaui/fastapi_server/_uvicorn.py +37 -0
- instaui/fastapi_server/debug_mode_router.py +60 -0
- instaui/fastapi_server/dependency_router.py +28 -0
- instaui/fastapi_server/event_router.py +58 -0
- instaui/fastapi_server/middlewares.py +19 -0
- instaui/fastapi_server/request_context.py +19 -0
- instaui/fastapi_server/resource.py +30 -0
- instaui/fastapi_server/server.py +308 -0
- instaui/fastapi_server/watch_router.py +53 -0
- instaui/handlers/_utils.py +88 -0
- instaui/handlers/event_handler.py +60 -0
- instaui/handlers/watch_handler.py +61 -0
- instaui/html_tools.py +94 -0
- instaui/inject.py +33 -0
- instaui/js/__init__.py +4 -0
- instaui/js/js_output.py +15 -0
- instaui/js/lambda_func.py +35 -0
- instaui/launch_collector.py +52 -0
- instaui/page_info.py +13 -0
- instaui/runtime/__init__.py +29 -0
- instaui/runtime/_app.py +234 -0
- instaui/runtime/_inner_helper.py +9 -0
- instaui/runtime/_link_manager.py +89 -0
- instaui/runtime/context.py +47 -0
- instaui/runtime/dataclass.py +30 -0
- instaui/runtime/resource.py +65 -0
- instaui/runtime/scope.py +133 -0
- instaui/runtime/ui_state_scope.py +15 -0
- instaui/settings/__init__.py +4 -0
- instaui/settings/__settings.py +13 -0
- instaui/shadcn_classless/_index.py +42 -0
- instaui/shadcn_classless/static/shadcn-classless.css +403 -0
- instaui/skip.py +12 -0
- instaui/spa_router/__init__.py +26 -0
- instaui/spa_router/_components.py +35 -0
- instaui/spa_router/_file_base_utils.py +273 -0
- instaui/spa_router/_functions.py +122 -0
- instaui/spa_router/_install.py +11 -0
- instaui/spa_router/_route_model.py +117 -0
- instaui/spa_router/_router_box.py +40 -0
- instaui/spa_router/_router_output.py +22 -0
- instaui/spa_router/_router_param_var.py +51 -0
- instaui/spa_router/_types.py +4 -0
- instaui/spa_router/templates/page_routes +60 -0
- instaui/static/insta-ui.css +1 -0
- instaui/static/insta-ui.esm-browser.prod.js +3717 -0
- instaui/static/insta-ui.ico +0 -0
- instaui/static/insta-ui.js.map +1 -0
- instaui/static/instaui-tools-browser.js +511 -0
- instaui/static/templates/debug/sse.html +117 -0
- instaui/static/templates/web.html +74 -0
- instaui/static/templates/webview.html +78 -0
- instaui/static/templates/zero.html +71 -0
- instaui/static/vue.esm-browser.prod.js +9 -0
- instaui/static/vue.global.prod.js +9 -0
- instaui/static/vue.runtime.esm-browser.prod.js +5 -0
- instaui/systems/file_system.py +6 -0
- instaui/systems/func_system.py +119 -0
- instaui/systems/js_system.py +22 -0
- instaui/systems/module_system.py +46 -0
- instaui/systems/pydantic_system.py +27 -0
- instaui/systems/string_system.py +10 -0
- instaui/tailwind/__init__.py +6 -0
- instaui/tailwind/_index.py +24 -0
- instaui/tailwind/static/tailwindcss-v3.min.js +62 -0
- instaui/tailwind/static/tailwindcss-v4.min.js +8 -0
- instaui/template/__init__.py +4 -0
- instaui/template/_utils.py +23 -0
- instaui/template/env.py +7 -0
- instaui/template/web_template.py +49 -0
- instaui/template/webview_template.py +48 -0
- instaui/template/zero_template.py +105 -0
- instaui/ui/__init__.py +144 -0
- instaui/ui/__init__.pyi +149 -0
- instaui/ui/events.py +25 -0
- instaui/ui_functions/input_slient_data.py +16 -0
- instaui/ui_functions/server.py +15 -0
- instaui/ui_functions/str_format.py +36 -0
- instaui/ui_functions/ui_page.py +16 -0
- instaui/ui_functions/ui_types.py +13 -0
- instaui/ui_functions/url_location.py +33 -0
- instaui/vars/_types.py +8 -0
- instaui/vars/data.py +68 -0
- instaui/vars/element_ref.py +40 -0
- instaui/vars/event_context.py +49 -0
- instaui/vars/event_extend.py +0 -0
- instaui/vars/js_computed.py +117 -0
- instaui/vars/mixin_types/common_type.py +5 -0
- instaui/vars/mixin_types/element_binding.py +16 -0
- instaui/vars/mixin_types/observable.py +7 -0
- instaui/vars/mixin_types/pathable.py +14 -0
- instaui/vars/mixin_types/py_binding.py +13 -0
- instaui/vars/mixin_types/str_format_binding.py +8 -0
- instaui/vars/mixin_types/var_type.py +5 -0
- instaui/vars/path_var.py +90 -0
- instaui/vars/ref.py +103 -0
- instaui/vars/slot_prop.py +46 -0
- instaui/vars/state.py +97 -0
- instaui/vars/types.py +24 -0
- instaui/vars/vfor_item.py +204 -0
- instaui/vars/vue_computed.py +81 -0
- instaui/vars/web_computed.py +209 -0
- instaui/vars/web_view_computed.py +1 -0
- instaui/version.py +3 -0
- instaui/watch/_types.py +4 -0
- instaui/watch/_utils.py +3 -0
- instaui/watch/js_watch.py +110 -0
- instaui/watch/vue_watch.py +77 -0
- instaui/watch/web_watch.py +181 -0
- instaui/webview/__init__.py +2 -0
- instaui/webview/_utils.py +8 -0
- instaui/webview/api.py +72 -0
- instaui/webview/func.py +114 -0
- instaui/webview/index.py +161 -0
- instaui/webview/resource.py +172 -0
- instaui/zero/__init__.py +3 -0
- instaui/zero/func.py +123 -0
- instaui/zero/scope.py +109 -0
- instaui-0.1.15.dist-info/METADATA +152 -0
- instaui-0.1.15.dist-info/RECORD +283 -0
- instaui-0.1.15.dist-info/WHEEL +5 -0
- instaui-0.1.15.dist-info/licenses/LICENSE +21 -0
instaui/js/js_output.py
ADDED
@@ -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
|
+
]
|
instaui/runtime/_app.py
ADDED
@@ -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
|