instaui 0.1.0__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 (152) hide show
  1. instaui/__init__.py +9 -0
  2. instaui/_helper/observable_helper.py +35 -0
  3. instaui/boot_info.py +43 -0
  4. instaui/common/jsonable.py +37 -0
  5. instaui/components/__init__.py +0 -0
  6. instaui/components/column.py +18 -0
  7. instaui/components/component.py +47 -0
  8. instaui/components/content.py +34 -0
  9. instaui/components/directive.py +55 -0
  10. instaui/components/element.py +462 -0
  11. instaui/components/grid.py +80 -0
  12. instaui/components/html/__init__.py +36 -0
  13. instaui/components/html/_mixins.py +34 -0
  14. instaui/components/html/button.py +38 -0
  15. instaui/components/html/checkbox.py +42 -0
  16. instaui/components/html/date.py +28 -0
  17. instaui/components/html/div.py +7 -0
  18. instaui/components/html/form.py +7 -0
  19. instaui/components/html/input.py +28 -0
  20. instaui/components/html/label.py +21 -0
  21. instaui/components/html/li.py +17 -0
  22. instaui/components/html/link.py +31 -0
  23. instaui/components/html/number.py +34 -0
  24. instaui/components/html/paragraph.py +19 -0
  25. instaui/components/html/range.py +45 -0
  26. instaui/components/html/select.py +93 -0
  27. instaui/components/html/span.py +19 -0
  28. instaui/components/html/ul.py +20 -0
  29. instaui/components/match.py +106 -0
  30. instaui/components/row.py +19 -0
  31. instaui/components/slot.py +82 -0
  32. instaui/components/transition_group.py +9 -0
  33. instaui/components/value_element.py +48 -0
  34. instaui/components/vfor.py +140 -0
  35. instaui/components/vif.py +38 -0
  36. instaui/consts.py +18 -0
  37. instaui/dependencies/__init__.py +15 -0
  38. instaui/dependencies/component_registrar.py +82 -0
  39. instaui/dependencies/installer.py +5 -0
  40. instaui/event/event_mixin.py +12 -0
  41. instaui/event/js_event.py +57 -0
  42. instaui/event/web_event.py +108 -0
  43. instaui/experimental/__init__.py +4 -0
  44. instaui/experimental/debug.py +48 -0
  45. instaui/fastapi_server/_utils.py +42 -0
  46. instaui/fastapi_server/_uvicorn.py +37 -0
  47. instaui/fastapi_server/config_router.py +60 -0
  48. instaui/fastapi_server/debug_mode_router.py +61 -0
  49. instaui/fastapi_server/event_router.py +58 -0
  50. instaui/fastapi_server/middlewares.py +19 -0
  51. instaui/fastapi_server/request_context.py +19 -0
  52. instaui/fastapi_server/server.py +246 -0
  53. instaui/fastapi_server/watch_router.py +53 -0
  54. instaui/handlers/_utils.py +66 -0
  55. instaui/handlers/computed_handler.py +42 -0
  56. instaui/handlers/config_handler.py +13 -0
  57. instaui/handlers/event_handler.py +58 -0
  58. instaui/handlers/watch_handler.py +57 -0
  59. instaui/html_tools.py +139 -0
  60. instaui/inject.py +33 -0
  61. instaui/js/__init__.py +4 -0
  62. instaui/js/js_output.py +15 -0
  63. instaui/js/lambda_func.py +35 -0
  64. instaui/launch_collector.py +52 -0
  65. instaui/page_info.py +23 -0
  66. instaui/runtime/__init__.py +29 -0
  67. instaui/runtime/_app.py +206 -0
  68. instaui/runtime/_inner_helper.py +9 -0
  69. instaui/runtime/context.py +47 -0
  70. instaui/runtime/dataclass.py +30 -0
  71. instaui/runtime/resource.py +87 -0
  72. instaui/runtime/scope.py +107 -0
  73. instaui/runtime/ui_state_scope.py +15 -0
  74. instaui/settings/__init__.py +4 -0
  75. instaui/settings/__settings.py +13 -0
  76. instaui/skip.py +12 -0
  77. instaui/spa_router/__init__.py +26 -0
  78. instaui/spa_router/_components.py +35 -0
  79. instaui/spa_router/_file_base_utils.py +264 -0
  80. instaui/spa_router/_functions.py +122 -0
  81. instaui/spa_router/_install.py +11 -0
  82. instaui/spa_router/_route_model.py +139 -0
  83. instaui/spa_router/_router_box.py +40 -0
  84. instaui/spa_router/_router_output.py +22 -0
  85. instaui/spa_router/_router_param_var.py +51 -0
  86. instaui/spa_router/_types.py +4 -0
  87. instaui/spa_router/templates/page_routes +59 -0
  88. instaui/static/insta-ui.css +1 -0
  89. instaui/static/insta-ui.esm-browser.prod.js +3663 -0
  90. instaui/static/insta-ui.iife.js +29 -0
  91. instaui/static/insta-ui.iife.js.map +1 -0
  92. instaui/static/insta-ui.js.map +1 -0
  93. instaui/static/tailwindcss.min.js +62 -0
  94. instaui/static/templates/debug/sse.html +117 -0
  95. instaui/static/templates/web.html +118 -0
  96. instaui/static/templates/zero.html +55 -0
  97. instaui/static/vue.esm-browser.prod.js +9 -0
  98. instaui/static/vue.global.prod.js +9 -0
  99. instaui/static/vue.runtime.esm-browser.prod.js +5 -0
  100. instaui/systems/file_system.py +17 -0
  101. instaui/systems/func_system.py +104 -0
  102. instaui/systems/js_system.py +22 -0
  103. instaui/systems/pydantic_system.py +27 -0
  104. instaui/systems/string_system.py +10 -0
  105. instaui/template/__init__.py +4 -0
  106. instaui/template/env.py +7 -0
  107. instaui/template/web_template.py +55 -0
  108. instaui/template/zero_template.py +24 -0
  109. instaui/ui/__init__.py +121 -0
  110. instaui/ui/events.py +25 -0
  111. instaui/ui_functions/input_slient_data.py +16 -0
  112. instaui/ui_functions/server.py +13 -0
  113. instaui/ui_functions/str_format.py +36 -0
  114. instaui/ui_functions/ui_page.py +31 -0
  115. instaui/ui_functions/ui_types.py +13 -0
  116. instaui/ui_functions/url_location.py +33 -0
  117. instaui/vars/__init__.py +13 -0
  118. instaui/vars/_types.py +8 -0
  119. instaui/vars/_utils.py +12 -0
  120. instaui/vars/data.py +68 -0
  121. instaui/vars/element_ref.py +42 -0
  122. instaui/vars/event_context.py +45 -0
  123. instaui/vars/event_extend.py +0 -0
  124. instaui/vars/js_computed.py +95 -0
  125. instaui/vars/mixin_types/common_type.py +5 -0
  126. instaui/vars/mixin_types/element_binding.py +10 -0
  127. instaui/vars/mixin_types/observable.py +7 -0
  128. instaui/vars/mixin_types/pathable.py +14 -0
  129. instaui/vars/mixin_types/py_binding.py +13 -0
  130. instaui/vars/mixin_types/str_format_binding.py +8 -0
  131. instaui/vars/mixin_types/var_type.py +5 -0
  132. instaui/vars/path_var.py +89 -0
  133. instaui/vars/ref.py +103 -0
  134. instaui/vars/slot_prop.py +46 -0
  135. instaui/vars/state.py +82 -0
  136. instaui/vars/types.py +24 -0
  137. instaui/vars/vfor_item.py +204 -0
  138. instaui/vars/vue_computed.py +82 -0
  139. instaui/vars/web_computed.py +157 -0
  140. instaui/vars/web_view_computed.py +1 -0
  141. instaui/version.py +3 -0
  142. instaui/watch/_types.py +4 -0
  143. instaui/watch/_utils.py +3 -0
  144. instaui/watch/js_watch.py +74 -0
  145. instaui/watch/vue_watch.py +61 -0
  146. instaui/watch/web_watch.py +123 -0
  147. instaui/zero/__init__.py +3 -0
  148. instaui/zero/scope.py +9 -0
  149. instaui-0.1.0.dist-info/LICENSE +21 -0
  150. instaui-0.1.0.dist-info/METADATA +154 -0
  151. instaui-0.1.0.dist-info/RECORD +152 -0
  152. instaui-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Union
3
+
4
+ from instaui.components.value_element import ValueElement
5
+ from ._mixins import InputEventMixin
6
+
7
+ if TYPE_CHECKING:
8
+ from instaui.vars.types import TMaybeRef
9
+ from instaui.components.element import Element
10
+
11
+ _T_value = str
12
+
13
+
14
+ class Date(InputEventMixin, ValueElement[_T_value]):
15
+ def __init__(
16
+ self,
17
+ value: Union[_T_value, TMaybeRef[_T_value], None] = None,
18
+ *,
19
+ model_value: Union[_T_value, TMaybeRef[_T_value], None] = None,
20
+ ):
21
+ super().__init__("input", value, is_html_component=True)
22
+ self.props({"type": "date"})
23
+
24
+ if model_value is not None:
25
+ self.props({"value": model_value})
26
+
27
+ def _input_event_mixin_element(self) -> Element:
28
+ return self
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+ from instaui.components.element import Element
3
+
4
+
5
+ class Div(Element):
6
+ def __init__(self):
7
+ super().__init__("div")
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+ from instaui.components.element import Element
3
+
4
+
5
+ class Form(Element):
6
+ def __init__(self):
7
+ super().__init__("form")
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Optional, Union
3
+ from instaui.components.element import Element
4
+ from instaui.components.value_element import ValueElement
5
+
6
+ from ._mixins import InputEventMixin
7
+
8
+ if TYPE_CHECKING:
9
+ import instaui.vars as ui_vars
10
+
11
+
12
+ class Input(InputEventMixin, ValueElement[str]):
13
+ def __init__(
14
+ self,
15
+ value: Union[str, ui_vars.TMaybeRef[str], None] = None,
16
+ *,
17
+ model_value: Union[str, ui_vars.TMaybeRef[str], None] = None,
18
+ disabled: Optional[ui_vars.TMaybeRef[bool]] = None,
19
+ ):
20
+ super().__init__("input", value, is_html_component=True)
21
+
22
+ if disabled is not None:
23
+ self.props({"disabled": disabled})
24
+ if model_value is not None:
25
+ self.props({"value": model_value})
26
+
27
+ def _input_event_mixin_element(self) -> Element:
28
+ return self
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Any, Union
3
+ from instaui.components.element import Element
4
+
5
+ if TYPE_CHECKING:
6
+ import instaui.vars as ui_vars
7
+
8
+
9
+ class Label(Element):
10
+ def __init__(
11
+ self,
12
+ text: Union[Any, ui_vars.TMaybeRef[Any], None] = None,
13
+ ):
14
+ super().__init__("label")
15
+
16
+ if text is not None:
17
+ self.props(
18
+ {
19
+ "innerText": text,
20
+ }
21
+ )
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Any, Union
3
+ from instaui.components.element import Element
4
+
5
+ if TYPE_CHECKING:
6
+ from instaui.vars import TMaybeRef
7
+
8
+
9
+ class Li(Element):
10
+ def __init__(
11
+ self,
12
+ text: Union[Any, TMaybeRef[Any], None] = None,
13
+ ):
14
+ super().__init__("li")
15
+
16
+ if text:
17
+ self.props({"innerText": text})
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+ from typing import (
3
+ Optional,
4
+ )
5
+ from instaui.components.element import Element
6
+
7
+ from instaui.vars.types import TMaybeRef
8
+
9
+
10
+ class Link(Element):
11
+ def __init__(
12
+ self,
13
+ href: Optional[TMaybeRef[str]] = None,
14
+ *,
15
+ text: Optional[TMaybeRef[str]] = None,
16
+ ):
17
+ super().__init__("a")
18
+
19
+ if text is not None:
20
+ self.props(
21
+ {
22
+ "innerText": text,
23
+ }
24
+ )
25
+
26
+ if href is not None:
27
+ self.props(
28
+ {
29
+ "href": href,
30
+ }
31
+ )
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Optional, Union
3
+ from instaui.components.element import Element
4
+ from instaui.components.value_element import ValueElement
5
+ from ._mixins import InputEventMixin
6
+
7
+ if TYPE_CHECKING:
8
+ import instaui.vars as ui_vars
9
+
10
+
11
+ _T_value = Union[int, float]
12
+
13
+
14
+ class Number(InputEventMixin, ValueElement[_T_value]):
15
+ def __init__(
16
+ self,
17
+ value: Optional[ui_vars.TMaybeRef[_T_value]] = None,
18
+ *,
19
+ model_value: Optional[ui_vars.TMaybeRef[_T_value]] = None,
20
+ min: Optional[ui_vars.TMaybeRef[_T_value]] = None,
21
+ max: Optional[ui_vars.TMaybeRef[_T_value]] = None,
22
+ ):
23
+ super().__init__("input", value, is_html_component=True)
24
+ self.props({"type": "number"})
25
+
26
+ if min is not None:
27
+ self.props({"min": min})
28
+ if max is not None:
29
+ self.props({"max": max})
30
+ if model_value is not None:
31
+ self.props({"value": model_value})
32
+
33
+ def _input_event_mixin_element(self) -> Element:
34
+ return self
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Any, Union
3
+ from instaui.components.element import Element
4
+
5
+ if TYPE_CHECKING:
6
+ import instaui.vars as ui_vars
7
+
8
+
9
+ class Paragraph(Element):
10
+ def __init__(
11
+ self,
12
+ text: Union[str, ui_vars.TMaybeRef[Any]],
13
+ ):
14
+ super().__init__("p")
15
+ self.props(
16
+ {
17
+ "innerText": text,
18
+ }
19
+ )
@@ -0,0 +1,45 @@
1
+ from __future__ import annotations
2
+ from typing import List, Union
3
+ from instaui.components.element import Element
4
+ from instaui.components.value_element import ValueElement
5
+ from instaui import consts
6
+ from instaui.vars.types import TMaybeRef
7
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
8
+ from ._mixins import InputEventMixin
9
+
10
+ _T_value = Union[int, float]
11
+
12
+
13
+ class Range(InputEventMixin, ValueElement[_T_value]):
14
+ def __init__(
15
+ self,
16
+ value: Union[_T_value, TMaybeRef[_T_value], None] = None,
17
+ *,
18
+ min: Union[_T_value, TMaybeRef[_T_value], None] = None,
19
+ max: Union[_T_value, TMaybeRef[_T_value], None] = None,
20
+ ):
21
+ super().__init__("input", value, is_html_component=True)
22
+ self.props({"type": "range"})
23
+
24
+ if min is not None:
25
+ self.props({"min": min})
26
+ if max is not None:
27
+ self.props({"max": max})
28
+
29
+ def vmodel(
30
+ self,
31
+ value: ElementBindingMixin,
32
+ modifiers: Union[consts.TModifier, List[consts.TModifier], None] = None,
33
+ *,
34
+ prop_name: str = "value",
35
+ ):
36
+ modifiers = modifiers or []
37
+ if isinstance(modifiers, str):
38
+ modifiers = [modifiers]
39
+
40
+ modifiers_with_number = list(set([*modifiers, "number"]))
41
+
42
+ return super().vmodel(value, modifiers_with_number, prop_name=prop_name) # type: ignore
43
+
44
+ def _input_event_mixin_element(self) -> Element:
45
+ return self
@@ -0,0 +1,93 @@
1
+ from __future__ import annotations
2
+ from typing import (
3
+ TYPE_CHECKING,
4
+ Any,
5
+ Callable,
6
+ Dict,
7
+ List,
8
+ Literal,
9
+ Optional,
10
+ Self,
11
+ Union,
12
+ overload,
13
+ )
14
+
15
+ from instaui.vars import Ref
16
+ from instaui.components.value_element import ValueElement
17
+ from instaui.components.element import Element
18
+ from instaui.vars.types import TMaybeRef
19
+ from instaui.components.vfor import VFor
20
+
21
+ if TYPE_CHECKING:
22
+ import instaui.vars as ui_vars
23
+
24
+
25
+ _T_Select_Value = Union[List[str], str]
26
+
27
+
28
+ class Select(ValueElement[Union[List[str], str]]):
29
+ def __init__(
30
+ self,
31
+ value: Union[_T_Select_Value, ui_vars.TMaybeRef[_T_Select_Value], None] = None,
32
+ ):
33
+ super().__init__("select", value, is_html_component=True)
34
+
35
+ def vmodel(
36
+ self,
37
+ value: Ref[Any],
38
+ *modifiers: Literal["lazy"],
39
+ ):
40
+ return super().vmodel(value, *modifiers) # type: ignore
41
+
42
+ @overload
43
+ def on_change(self, handler: Callable, *, key: Optional[str] = None) -> Self: ...
44
+
45
+ @overload
46
+ def on_change(
47
+ self,
48
+ handler: str,
49
+ *,
50
+ bindings: Optional[Dict] = None,
51
+ key: Optional[str] = None,
52
+ ) -> Self: ...
53
+
54
+ def on_change(
55
+ self,
56
+ handler: Union[Callable, str],
57
+ *,
58
+ bindings: Optional[Dict] = None,
59
+ key: Optional[str] = None,
60
+ ):
61
+ self.on("change", handler, bindings=bindings, key=key) # type: ignore
62
+ return self
63
+
64
+ @classmethod
65
+ def from_list(
66
+ cls,
67
+ options: TMaybeRef[List],
68
+ ) -> Select:
69
+ with cls() as select:
70
+ with VFor(options) as item:
71
+ Select.Option(item) # type: ignore
72
+
73
+ return select
74
+
75
+ class Option(Element):
76
+ def __init__(
77
+ self,
78
+ text: Optional[ui_vars.TMaybeRef[str]] = None,
79
+ value: Optional[ui_vars.TMaybeRef[str]] = None,
80
+ disabled: Optional[ui_vars.TMaybeRef[bool]] = None,
81
+ ):
82
+ props = {
83
+ key: value
84
+ for key, value in {
85
+ "text": text,
86
+ "value": value,
87
+ "disabled": disabled,
88
+ }.items()
89
+ if value is not None
90
+ }
91
+ super().__init__("option")
92
+
93
+ self._props.update(props)
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Any, Union
3
+ from instaui.components.element import Element
4
+
5
+ if TYPE_CHECKING:
6
+ import instaui.vars as ui_vars
7
+
8
+
9
+ class Span(Element):
10
+ def __init__(
11
+ self,
12
+ text: Union[str, ui_vars.TMaybeRef[Any]],
13
+ ):
14
+ super().__init__("span")
15
+ self.props(
16
+ {
17
+ "innerText": text,
18
+ }
19
+ )
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+ from typing import List, Union
3
+ from instaui.components.element import Element
4
+ from .li import Li
5
+ from instaui.components.vfor import VFor
6
+
7
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
8
+
9
+
10
+ class Ul(Element):
11
+ def __init__(self):
12
+ super().__init__("ul")
13
+
14
+ @classmethod
15
+ def from_list(cls, data: Union[List, ElementBindingMixin[List]]) -> Ul:
16
+ with Ul() as ul:
17
+ with VFor(data) as items:
18
+ Li(items)
19
+
20
+ return ul
@@ -0,0 +1,106 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+ from instaui.components.component import Component
5
+ from instaui.runtime._app import new_scope
6
+
7
+ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
8
+
9
+
10
+ class Match(Component):
11
+ def __init__(self, on: ElementBindingMixin):
12
+ super().__init__("match")
13
+ self._on = on
14
+ self._default_case = None
15
+
16
+ def _to_json_dict(self):
17
+ data = super()._to_json_dict()
18
+ data["props"] = {
19
+ "on": self._on._to_element_binding_config(),
20
+ }
21
+ props: typing.Dict = data["props"]
22
+
23
+ props["case"] = [
24
+ item
25
+ for item in self._slot_manager.default._children
26
+ if isinstance(item, Case)
27
+ ]
28
+
29
+ if self._default_case:
30
+ props["default"] = self._default_case
31
+
32
+ data.pop("slots", None)
33
+
34
+ return data
35
+
36
+ def case(self, value: typing.Any) -> Case:
37
+ with self:
38
+ case = Case(value)
39
+
40
+ return case
41
+
42
+ def default(self) -> DefaultCase:
43
+ with self:
44
+ self._default_case = DefaultCase()
45
+
46
+ return self._default_case
47
+
48
+
49
+ class Case(Component):
50
+ def __init__(self, value: typing.Any):
51
+ super().__init__("case")
52
+ self._value = value
53
+ self.__scope_manager = new_scope(append_to_app=False)
54
+ self.__scope = None
55
+
56
+ def __enter__(self):
57
+ self.__scope = self.__scope_manager.__enter__()
58
+ return super().__enter__()
59
+
60
+ def __exit__(self, *_) -> None:
61
+ self.__scope_manager.__exit__(*_)
62
+ return super().__exit__(*_)
63
+
64
+ def _to_json_dict(self):
65
+ data = super()._to_json_dict()
66
+ data["props"] = {
67
+ "value": self._value,
68
+ }
69
+ props = data["props"]
70
+
71
+ props["scope"] = self.__scope
72
+
73
+ if self._slot_manager.has_slot():
74
+ props["items"] = self._slot_manager
75
+
76
+ data.pop("slots", None)
77
+ return data
78
+
79
+
80
+ class DefaultCase(Component):
81
+ def __init__(self):
82
+ super().__init__("default-case")
83
+
84
+ self.__scope_manager = new_scope(append_to_app=False)
85
+ self.__scope = None
86
+
87
+ def __enter__(self):
88
+ self.__scope = self.__scope_manager.__enter__()
89
+ return super().__enter__()
90
+
91
+ def __exit__(self, *_) -> None:
92
+ self.__scope_manager.__exit__(*_)
93
+ return super().__exit__(*_)
94
+
95
+ def _to_json_dict(self):
96
+ data = super()._to_json_dict()
97
+ data["props"] = {}
98
+ props = data["props"]
99
+
100
+ props["scope"] = self.__scope
101
+
102
+ if self._slot_manager.has_slot():
103
+ props["items"] = self._slot_manager
104
+
105
+ data.pop("slots", None)
106
+ return data
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+ from typing import (
3
+ TypeVar,
4
+ )
5
+ from instaui.components.element import Element
6
+
7
+ _T = TypeVar("_T")
8
+
9
+
10
+ class Row(Element):
11
+ def __init__(
12
+ self,
13
+ ):
14
+ super().__init__("div")
15
+ self.style("display: flex; flex-direction: row;")
16
+
17
+
18
+ def gap(self, value: str) -> Row:
19
+ return self.style({"gap": value})
@@ -0,0 +1,82 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Dict, List, Optional, Set, Union
4
+ from instaui.common.jsonable import Jsonable
5
+ from instaui.runtime import get_slot_stacks, pop_slot
6
+ from instaui.runtime._app import get_app_slot
7
+ from instaui.vars.slot_prop import BindingSlotPropItem
8
+
9
+ if TYPE_CHECKING:
10
+ from instaui.components.component import Component
11
+ from instaui.components.vfor import VFor
12
+
13
+ _DEFAULT_SLOT_NAME = ":"
14
+
15
+
16
+ class SlotManager(Jsonable):
17
+ def __init__(self) -> None:
18
+ super().__init__()
19
+ self._slots: Dict[str, Slot] = {}
20
+
21
+ def get_slot(self, name: str) -> Slot:
22
+ name = _DEFAULT_SLOT_NAME if name == "default" else name
23
+
24
+ if name not in self._slots:
25
+ self._slots[name] = Slot(name)
26
+
27
+ return self._slots[name]
28
+
29
+ @property
30
+ def default(self):
31
+ return self.get_slot(_DEFAULT_SLOT_NAME)
32
+
33
+ def _to_json_dict(self):
34
+ if (
35
+ len(self._slots) == 1
36
+ and _DEFAULT_SLOT_NAME in self._slots
37
+ and (not self._slots[_DEFAULT_SLOT_NAME]._has_props_use())
38
+ ):
39
+ return self._slots[_DEFAULT_SLOT_NAME]._children
40
+
41
+ return {name: slot._to_json_dict() for name, slot in self._slots.items()}
42
+
43
+ def has_slot(self) -> bool:
44
+ return len(self._slots) > 0
45
+
46
+
47
+ class Slot(Jsonable):
48
+ def __init__(self, name: str) -> None:
49
+ super().__init__()
50
+
51
+ self._id: Optional[str] = None
52
+ self._name = name
53
+ self._children: List[Union[Component, VFor]] = []
54
+ self._props_use_name: Set[str] = set()
55
+
56
+ def _has_props_use(self):
57
+ return len(self._props_use_name) > 0
58
+
59
+ def props(self, name: str):
60
+ if self._id is None:
61
+ self._id = get_app_slot().generate_slot_id()
62
+
63
+ self._props_use_name.add(name)
64
+ return BindingSlotPropItem(self._id, name)
65
+
66
+ def __enter__(self):
67
+ get_slot_stacks().append(self)
68
+ return self
69
+
70
+ def __exit__(self, *_):
71
+ pop_slot()
72
+
73
+ def _to_json_dict(self):
74
+ data = super()._to_json_dict()
75
+
76
+ if self._children:
77
+ data["items"] = self._children
78
+
79
+ if self._props_use_name:
80
+ data["props"] = {"id": self._id, "use": list(self._props_use_name)}
81
+
82
+ return data
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+ from instaui.components.element import Element
3
+
4
+
5
+ class TransitionGroup(Element):
6
+ def __init__(
7
+ self,
8
+ ):
9
+ super().__init__("ts-group")
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+ from typing import (
3
+ Generic,
4
+ List,
5
+ Optional,
6
+ Union,
7
+ TypeVar,
8
+ )
9
+ from instaui.components.element import Element
10
+ from instaui import consts
11
+
12
+ from instaui.vars.types import TMaybeRef
13
+ from instaui.vars.web_computed import WebComputed
14
+
15
+
16
+ _T = TypeVar("_T")
17
+
18
+
19
+ class ValueElement(Element, Generic[_T]):
20
+ def __init__(
21
+ self,
22
+ tag: Optional[str] = None,
23
+ value: Union[_T, TMaybeRef[_T], None] = None,
24
+ is_html_component: bool = False,
25
+ value_name: str = "value",
26
+ ):
27
+ super().__init__(tag)
28
+ self.__is_html_component = is_html_component
29
+
30
+ if value is not None:
31
+ if isinstance(value, WebComputed):
32
+ self.props({value_name:value})
33
+ else:
34
+ self.vmodel(value, prop_name=value_name)
35
+
36
+ def vmodel(
37
+ self,
38
+ value,
39
+ modifiers: Union[consts.TModifier, List[consts.TModifier], None] = None,
40
+ *,
41
+ prop_name: str = "value",
42
+ ):
43
+ return super().vmodel(
44
+ value,
45
+ modifiers,
46
+ prop_name=prop_name,
47
+ is_html_component=self.__is_html_component,
48
+ )