instaui 0.1.3__py3-none-any.whl → 0.1.5__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/components/content.py +4 -4
- instaui/components/echarts/echarts.js +128 -0
- instaui/components/echarts/echarts.py +194 -0
- instaui/components/echarts/static/echarts.esm.min.js +45 -0
- instaui/components/element.py +103 -13
- instaui/components/html/__init__.py +31 -18
- instaui/components/html/_preset.py +4 -0
- instaui/components/html/heading.py +51 -0
- instaui/components/html/range.py +3 -0
- instaui/components/html/select.py +16 -35
- instaui/components/html/table.py +36 -0
- instaui/components/html/textarea.py +28 -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/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 +175 -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/value_element.py +7 -3
- instaui/components/vfor.py +1 -1
- instaui/consts.py +2 -1
- instaui/daisyui/__init__.py +26 -0
- instaui/daisyui/_index.py +20 -0
- instaui/daisyui/button.py +38 -0
- instaui/daisyui/checkbox.py +17 -0
- instaui/daisyui/static/daisyui.css +1 -0
- instaui/daisyui/static/themes.css +1 -0
- instaui/daisyui/table.py +35 -0
- instaui/dependencies/component_dependency.py +11 -5
- instaui/event/js_event.py +1 -0
- instaui/event/web_event.py +6 -7
- instaui/fastapi_server/dependency_router.py +4 -3
- instaui/fastapi_server/resource.py +12 -16
- instaui/fastapi_server/server.py +34 -24
- instaui/handlers/event_handler.py +3 -1
- instaui/handlers/watch_handler.py +4 -0
- instaui/html_tools.py +44 -2
- instaui/inject.py +3 -3
- instaui/runtime/_app.py +43 -4
- instaui/runtime/_link_manager.py +89 -0
- instaui/runtime/resource.py +21 -8
- instaui/shadcn_classless/_index.py +42 -0
- instaui/shadcn_classless/static/shadcn-classless.css +403 -0
- instaui/spa_router/_functions.py +1 -1
- instaui/spa_router/_route_model.py +1 -1
- instaui/static/insta-ui.css +1 -1
- instaui/static/insta-ui.esm-browser.prod.js +1308 -1252
- instaui/static/insta-ui.js.map +1 -1
- instaui/static/instaui-tools-browser.js +511 -0
- instaui/static/templates/webview.html +78 -0
- instaui/systems/module_system.py +30 -0
- instaui/tailwind/__init__.py +6 -0
- instaui/tailwind/_index.py +24 -0
- instaui/{static/tailwindcss.min.js → tailwind/static/tailwindcss-v3.min.js} +62 -62
- instaui/tailwind/static/tailwindcss-v4.min.js +8 -0
- instaui/template/_utils.py +23 -0
- instaui/template/webview_template.py +50 -0
- instaui/template/zero_template.py +18 -17
- instaui/ui/__build_init.py +73 -0
- instaui/ui/__init__.py +74 -58
- instaui/ui/__init__.pyi +135 -0
- instaui/ui/events.py +1 -1
- instaui/ui_functions/server.py +3 -1
- instaui/vars/event_context.py +4 -0
- instaui/vars/web_computed.py +30 -30
- instaui/watch/web_watch.py +5 -6
- instaui/webview/__init__.py +1 -0
- instaui/webview/_utils.py +8 -0
- instaui/webview/api.py +72 -0
- instaui/webview/func.py +114 -0
- instaui/webview/index.py +162 -0
- instaui/webview/resource.py +172 -0
- instaui/zero/func.py +31 -23
- instaui/zero/scope.py +110 -4
- {instaui-0.1.3.dist-info → instaui-0.1.5.dist-info}/METADATA +4 -1
- {instaui-0.1.3.dist-info → instaui-0.1.5.dist-info}/RECORD +88 -44
- instaui/handlers/computed_handler.py +0 -42
- instaui/handlers/config_handler.py +0 -13
- instaui/static/insta-ui.iife.js +0 -29
- instaui/static/insta-ui.iife.js.map +0 -1
- instaui/zero/test.html +0 -44
- {instaui-0.1.3.dist-info → instaui-0.1.5.dist-info}/LICENSE +0 -0
- {instaui-0.1.3.dist-info → instaui-0.1.5.dist-info}/WHEEL +0 -0
instaui/components/element.py
CHANGED
@@ -7,10 +7,13 @@ from pathlib import Path
|
|
7
7
|
import re
|
8
8
|
from typing import (
|
9
9
|
Any,
|
10
|
+
Callable,
|
10
11
|
Dict,
|
12
|
+
Iterable,
|
11
13
|
List,
|
12
14
|
ClassVar,
|
13
15
|
Optional,
|
16
|
+
Set,
|
14
17
|
Tuple,
|
15
18
|
Union,
|
16
19
|
cast,
|
@@ -35,6 +38,7 @@ from instaui.vars.mixin_types.element_binding import ElementBindingMixin
|
|
35
38
|
|
36
39
|
if TYPE_CHECKING:
|
37
40
|
from instaui.event.event_mixin import EventMixin
|
41
|
+
from instaui.vars.types import TMaybeRef
|
38
42
|
|
39
43
|
|
40
44
|
# Refer to the NiceGUI project.
|
@@ -103,7 +107,7 @@ class Element(Component):
|
|
103
107
|
cls,
|
104
108
|
*,
|
105
109
|
esm: Union[str, Path, None] = None,
|
106
|
-
externals: Optional[
|
110
|
+
externals: Optional[Dict[str, Path]] = None,
|
107
111
|
css: Union[List[Union[str, Path]], None] = None,
|
108
112
|
) -> None:
|
109
113
|
super().__init_subclass__()
|
@@ -112,18 +116,21 @@ class Element(Component):
|
|
112
116
|
esm = _make_dependency_path(esm, cls)
|
113
117
|
|
114
118
|
if externals:
|
115
|
-
externals =
|
119
|
+
externals = {
|
120
|
+
key: _make_dependency_path(value, cls)
|
121
|
+
for key, value in externals.items()
|
122
|
+
}
|
116
123
|
|
117
124
|
if css:
|
118
|
-
css =
|
125
|
+
css = set(_make_dependency_path(c, cls) for c in css) # type: ignore
|
119
126
|
|
120
127
|
tag_name = f"instaui-{esm.stem}"
|
121
128
|
|
122
129
|
cls.dependency = ComponentDependencyInfo(
|
123
130
|
tag_name=tag_name,
|
124
131
|
esm=esm,
|
125
|
-
externals=cast(
|
126
|
-
css=cast(
|
132
|
+
externals=cast(Dict[str, Path], externals or {}),
|
133
|
+
css=cast(Set[Path], css or set()),
|
127
134
|
)
|
128
135
|
|
129
136
|
cls._default_props = copy(cls._default_props)
|
@@ -225,32 +232,53 @@ class Element(Component):
|
|
225
232
|
@overload
|
226
233
|
def classes(self, add: str) -> Self: ...
|
227
234
|
@overload
|
228
|
-
def classes(self, add: Dict[str,
|
235
|
+
def classes(self, add: Dict[str, TMaybeRef[bool]]) -> Self: ...
|
229
236
|
|
230
237
|
@overload
|
231
|
-
def classes(self, add:
|
238
|
+
def classes(self, add: TMaybeRef[str]) -> Self: ...
|
232
239
|
|
233
240
|
def classes(
|
234
241
|
self,
|
235
242
|
add: Union[
|
236
243
|
str,
|
237
|
-
Dict[str,
|
238
|
-
|
244
|
+
Dict[str, TMaybeRef[bool]],
|
245
|
+
TMaybeRef[str],
|
239
246
|
VForItem,
|
240
247
|
],
|
241
248
|
) -> Self:
|
249
|
+
"""Add classes to the component.
|
250
|
+
|
251
|
+
Args:
|
252
|
+
add (Union[ str, Dict[str, TMaybeRef[bool]], TMaybeRef[str], VForItem, ]): classes to add.
|
253
|
+
|
254
|
+
|
255
|
+
Examples:
|
256
|
+
.. code-block:: python
|
257
|
+
|
258
|
+
elemelt = html.span('test')
|
259
|
+
elemelt.classes('class1 class2')
|
260
|
+
|
261
|
+
# dynamically classes
|
262
|
+
class_name = ui.state('x')
|
263
|
+
elemelt.classes(class_name)
|
264
|
+
|
265
|
+
# apply name if True
|
266
|
+
apply = ui.state(True)
|
267
|
+
elemelt.classes({'x': apply})
|
268
|
+
"""
|
269
|
+
|
242
270
|
if isinstance(add, str):
|
243
271
|
self._str_classes = self._update_classes(self._str_classes, add)
|
244
272
|
|
245
273
|
if isinstance(add, dict):
|
246
|
-
self._dict_classes.update(**add)
|
274
|
+
self._dict_classes.update(**add) # type: ignore
|
247
275
|
|
248
276
|
if isinstance(add, ElementBindingMixin):
|
249
277
|
self._bind_str_classes.append(add) # type: ignore
|
250
278
|
|
251
279
|
return self
|
252
280
|
|
253
|
-
def style(self, add: Union[str, Dict[str, Any],
|
281
|
+
def style(self, add: Union[str, Dict[str, Any], TMaybeRef[str]]) -> Self:
|
254
282
|
if isinstance(add, dict):
|
255
283
|
add = {key: value for key, value in add.items()}
|
256
284
|
|
@@ -262,7 +290,7 @@ class Element(Component):
|
|
262
290
|
self._style.update(new_style)
|
263
291
|
return self
|
264
292
|
|
265
|
-
def props(self, add: Union[str, Dict[str, Any],
|
293
|
+
def props(self, add: Union[str, Dict[str, Any], TMaybeRef]) -> Self:
|
266
294
|
if isinstance(add, ElementBindingMixin):
|
267
295
|
self._proxy_props.append(add)
|
268
296
|
return self
|
@@ -326,6 +354,64 @@ class Element(Component):
|
|
326
354
|
self._element_ref = ref
|
327
355
|
return self
|
328
356
|
|
357
|
+
def update_dependencies(
|
358
|
+
self,
|
359
|
+
*,
|
360
|
+
css: Optional[Iterable[Path]] = None,
|
361
|
+
externals: Optional[Dict[str, Path]] = None,
|
362
|
+
replace: bool = False,
|
363
|
+
):
|
364
|
+
if not self.dependency:
|
365
|
+
return
|
366
|
+
|
367
|
+
app = get_app_slot()
|
368
|
+
dep = self.dependency.copy()
|
369
|
+
if replace:
|
370
|
+
dep.css.clear()
|
371
|
+
dep.externals.clear()
|
372
|
+
|
373
|
+
if css:
|
374
|
+
dep.css.update(css)
|
375
|
+
|
376
|
+
if externals:
|
377
|
+
dep.externals.update(externals)
|
378
|
+
|
379
|
+
app.add_temp_component_dependency(dep)
|
380
|
+
|
381
|
+
def use(self, *use_fns: Callable[[Self], None]) -> Self:
|
382
|
+
"""Use functions to the component object.
|
383
|
+
|
384
|
+
Args:
|
385
|
+
use_fns (Callable[[Self], None]): The list of use functions.
|
386
|
+
|
387
|
+
Examples:
|
388
|
+
.. code-block:: python
|
389
|
+
def use_red_color(element: html.paragraph):
|
390
|
+
element.style('color: red')
|
391
|
+
|
392
|
+
html.paragraph('Hello').use(use_red_color)
|
393
|
+
"""
|
394
|
+
|
395
|
+
for fn in use_fns:
|
396
|
+
fn(self)
|
397
|
+
return self
|
398
|
+
|
399
|
+
@classmethod
|
400
|
+
def use_init(cls, init_fn: Callable[[type[Self]], Self]) -> Self:
|
401
|
+
"""Use this method to initialize the component.
|
402
|
+
|
403
|
+
Args:
|
404
|
+
init_fn (Callable[[type[Self]], Self]): The initialization function.
|
405
|
+
|
406
|
+
Examples:
|
407
|
+
.. code-block:: python
|
408
|
+
def fack_init(cls: type[html.table]) -> html.table:
|
409
|
+
return cls(columns=['name', 'age'],rows = [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}])
|
410
|
+
|
411
|
+
ui.table.use_init(fack_init)
|
412
|
+
"""
|
413
|
+
return init_fn(cls)
|
414
|
+
|
329
415
|
def _to_json_dict(self):
|
330
416
|
data = super()._to_json_dict()
|
331
417
|
|
@@ -376,7 +462,11 @@ class Element(Component):
|
|
376
462
|
data["dir"] = list(self._directives.keys())
|
377
463
|
|
378
464
|
if self.dependency:
|
379
|
-
get_app_slot()
|
465
|
+
app_slot = get_app_slot()
|
466
|
+
tag_name = self.dependency.tag_name
|
467
|
+
app_slot.use_component_dependency(
|
468
|
+
app_slot.get_temp_component_dependency(tag_name, self.dependency)
|
469
|
+
)
|
380
470
|
|
381
471
|
if self._element_ref:
|
382
472
|
scope = get_current_scope()
|
@@ -1,21 +1,3 @@
|
|
1
|
-
from .span import Span as span
|
2
|
-
from .label import Label as label
|
3
|
-
from .paragraph import Paragraph as paragraph
|
4
|
-
from .input import Input as input
|
5
|
-
from .number import Number as number
|
6
|
-
from .button import Button as button
|
7
|
-
from .checkbox import Checkbox as checkbox
|
8
|
-
from .form import Form as form
|
9
|
-
from .select import Select as select
|
10
|
-
from .ul import Ul as ul
|
11
|
-
from .li import Li as li
|
12
|
-
from .div import Div as div
|
13
|
-
from .range import Range as range
|
14
|
-
from .date import Date as date
|
15
|
-
from .link import Link as link
|
16
|
-
|
17
|
-
option = select.Option
|
18
|
-
|
19
1
|
__all__ = [
|
20
2
|
"span",
|
21
3
|
"label",
|
@@ -33,4 +15,35 @@ __all__ = [
|
|
33
15
|
"range",
|
34
16
|
"date",
|
35
17
|
"link",
|
18
|
+
"textarea",
|
19
|
+
"table",
|
20
|
+
"h1",
|
21
|
+
"h2",
|
22
|
+
"h3",
|
23
|
+
"h4",
|
24
|
+
"h5",
|
25
|
+
"h6",
|
36
26
|
]
|
27
|
+
|
28
|
+
from .span import Span as span
|
29
|
+
from .label import Label as label
|
30
|
+
from .paragraph import Paragraph as paragraph
|
31
|
+
from .input import Input as input
|
32
|
+
from .number import Number as number
|
33
|
+
from .button import Button as button
|
34
|
+
from .checkbox import Checkbox as checkbox
|
35
|
+
from .form import Form as form
|
36
|
+
from .select import Select as select
|
37
|
+
from .ul import Ul as ul
|
38
|
+
from .li import Li as li
|
39
|
+
from .div import Div as div
|
40
|
+
from .range import Range as range
|
41
|
+
from .date import Date as date
|
42
|
+
from .link import Link as link
|
43
|
+
from .textarea import Textarea as textarea
|
44
|
+
from .table import Table as table
|
45
|
+
from .heading import H1 as h1, H2 as h2, H3 as h3, H4 as h4, H5 as h5, H6 as h6
|
46
|
+
|
47
|
+
option = select.Option
|
48
|
+
|
49
|
+
from . import _preset # noqa: E402, F401
|
@@ -0,0 +1,51 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import TYPE_CHECKING, Any, Literal, Union
|
3
|
+
from instaui.components.element import Element
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
import instaui.vars as ui_vars
|
7
|
+
|
8
|
+
|
9
|
+
class Heading(Element):
|
10
|
+
def __init__(
|
11
|
+
self,
|
12
|
+
text: Union[str, ui_vars.TMaybeRef[Any]],
|
13
|
+
*,
|
14
|
+
level: Literal[1, 2, 3, 4, 5, 6] = 1,
|
15
|
+
):
|
16
|
+
super().__init__(f"h{level}")
|
17
|
+
self.props(
|
18
|
+
{
|
19
|
+
"innerText": text,
|
20
|
+
}
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
class H1(Heading):
|
25
|
+
def __init__(self, text: Union[str, ui_vars.TMaybeRef[Any]]):
|
26
|
+
super().__init__(text, level=1)
|
27
|
+
|
28
|
+
|
29
|
+
class H2(Heading):
|
30
|
+
def __init__(self, text: Union[str, ui_vars.TMaybeRef[Any]]):
|
31
|
+
super().__init__(text, level=2)
|
32
|
+
|
33
|
+
|
34
|
+
class H3(Heading):
|
35
|
+
def __init__(self, text: Union[str, ui_vars.TMaybeRef[Any]]):
|
36
|
+
super().__init__(text, level=3)
|
37
|
+
|
38
|
+
|
39
|
+
class H4(Heading):
|
40
|
+
def __init__(self, text: Union[str, ui_vars.TMaybeRef[Any]]):
|
41
|
+
super().__init__(text, level=4)
|
42
|
+
|
43
|
+
|
44
|
+
class H5(Heading):
|
45
|
+
def __init__(self, text: Union[str, ui_vars.TMaybeRef[Any]]):
|
46
|
+
super().__init__(text, level=5)
|
47
|
+
|
48
|
+
|
49
|
+
class H6(Heading):
|
50
|
+
def __init__(self, text: Union[str, ui_vars.TMaybeRef[Any]]):
|
51
|
+
super().__init__(text, level=6)
|
instaui/components/html/range.py
CHANGED
@@ -17,6 +17,7 @@ class Range(InputEventMixin, ValueElement[_T_value]):
|
|
17
17
|
*,
|
18
18
|
min: Union[_T_value, TMaybeRef[_T_value], None] = None,
|
19
19
|
max: Union[_T_value, TMaybeRef[_T_value], None] = None,
|
20
|
+
step: Union[_T_value, TMaybeRef[_T_value], None] = None,
|
20
21
|
):
|
21
22
|
super().__init__("input", value, is_html_component=True)
|
22
23
|
self.props({"type": "range"})
|
@@ -25,6 +26,8 @@ class Range(InputEventMixin, ValueElement[_T_value]):
|
|
25
26
|
self.props({"min": min})
|
26
27
|
if max is not None:
|
27
28
|
self.props({"max": max})
|
29
|
+
if step is not None:
|
30
|
+
self.props({"step": step})
|
28
31
|
|
29
32
|
def vmodel(
|
30
33
|
self,
|
@@ -1,72 +1,53 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from typing import (
|
3
3
|
TYPE_CHECKING,
|
4
|
-
Any,
|
5
4
|
Callable,
|
6
5
|
Dict,
|
7
6
|
List,
|
8
|
-
Literal,
|
9
7
|
Optional,
|
10
8
|
Union,
|
11
9
|
overload,
|
12
10
|
)
|
13
11
|
from typing_extensions import Self
|
14
|
-
|
15
|
-
from instaui.vars import Ref
|
16
12
|
from instaui.components.value_element import ValueElement
|
17
13
|
from instaui.components.element import Element
|
14
|
+
from instaui.event.event_mixin import EventMixin
|
18
15
|
from instaui.vars.types import TMaybeRef
|
19
16
|
from instaui.components.vfor import VFor
|
20
17
|
|
21
|
-
if TYPE_CHECKING:
|
22
|
-
import instaui.vars as ui_vars
|
23
|
-
|
24
|
-
|
25
18
|
_T_Select_Value = Union[List[str], str]
|
26
19
|
|
27
20
|
|
28
21
|
class Select(ValueElement[Union[List[str], str]]):
|
29
22
|
def __init__(
|
30
23
|
self,
|
31
|
-
value: Union[_T_Select_Value,
|
24
|
+
value: Union[_T_Select_Value, TMaybeRef[_T_Select_Value], None] = None,
|
25
|
+
*,
|
26
|
+
model_value: Union[str, TMaybeRef[str], None] = None,
|
32
27
|
):
|
33
28
|
super().__init__("select", value, is_html_component=True)
|
34
29
|
|
35
|
-
|
36
|
-
|
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: ...
|
30
|
+
if model_value is not None:
|
31
|
+
self.props({"value": model_value})
|
53
32
|
|
54
33
|
def on_change(
|
55
34
|
self,
|
56
|
-
handler:
|
35
|
+
handler: EventMixin,
|
57
36
|
*,
|
58
|
-
|
59
|
-
key: Optional[str] = None,
|
37
|
+
extends: Optional[List] = None,
|
60
38
|
):
|
61
|
-
self.on("change", handler
|
39
|
+
self.on("change", handler)
|
62
40
|
return self
|
63
41
|
|
64
42
|
@classmethod
|
65
43
|
def from_list(
|
66
44
|
cls,
|
67
45
|
options: TMaybeRef[List],
|
46
|
+
value: Union[_T_Select_Value, TMaybeRef[_T_Select_Value], None] = None,
|
47
|
+
*,
|
48
|
+
model_value: Union[str, TMaybeRef[str], None] = None,
|
68
49
|
) -> Select:
|
69
|
-
with cls() as select:
|
50
|
+
with cls(value, model_value=model_value) as select:
|
70
51
|
with VFor(options) as item:
|
71
52
|
Select.Option(item) # type: ignore
|
72
53
|
|
@@ -75,9 +56,9 @@ class Select(ValueElement[Union[List[str], str]]):
|
|
75
56
|
class Option(Element):
|
76
57
|
def __init__(
|
77
58
|
self,
|
78
|
-
text: Optional[
|
79
|
-
value: Optional[
|
80
|
-
disabled: Optional[
|
59
|
+
text: Optional[TMaybeRef[str]] = None,
|
60
|
+
value: Optional[TMaybeRef[str]] = None,
|
61
|
+
disabled: Optional[TMaybeRef[bool]] = None,
|
81
62
|
):
|
82
63
|
props = {
|
83
64
|
key: value
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
3
|
+
from instaui.components.element import Element
|
4
|
+
from instaui.components.content import Content
|
5
|
+
from instaui.components.vfor import VFor
|
6
|
+
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
import instaui.vars as ui_vars
|
9
|
+
|
10
|
+
|
11
|
+
class Table(Element):
|
12
|
+
def __init__(
|
13
|
+
self,
|
14
|
+
columns: Union[List[str], ui_vars.TMaybeRef[List[str]], None] = None,
|
15
|
+
rows: Union[List[List[Any]], ui_vars.TMaybeRef[List[List[Any]]], None] = None,
|
16
|
+
):
|
17
|
+
"""Create a table element.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
columns (Union[List[str], ui_vars.TMaybeRef[List[str]], None], optional): A list of column headers or a reactive reference to such a list. Defaults to None.
|
21
|
+
rows (Union[List[List[Any]], ui_vars.TMaybeRef[List[List[Any]]], None], optional): A list of row data, where each row is a list of cell values, or a reactive reference to such a list. Defaults to None.
|
22
|
+
"""
|
23
|
+
super().__init__("table")
|
24
|
+
|
25
|
+
with self:
|
26
|
+
with Element("thead"), Element("tr"):
|
27
|
+
with VFor(columns) as col: # type: ignore
|
28
|
+
with Element("th"):
|
29
|
+
Content(col)
|
30
|
+
|
31
|
+
with Element("tbody"):
|
32
|
+
with VFor(rows) as row: # type: ignore
|
33
|
+
with Element("tr"):
|
34
|
+
with VFor(row) as cell: # type: ignore
|
35
|
+
with Element("td"):
|
36
|
+
Content(cell)
|
@@ -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 Textarea(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__("textarea", 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,33 @@
|
|
1
|
+
import { h, computed } from "vue";
|
2
|
+
import { marked } from "marked";
|
3
|
+
|
4
|
+
export default {
|
5
|
+
props: ['content'],
|
6
|
+
setup(props) {
|
7
|
+
|
8
|
+
const md = computed(() => marked.parse(
|
9
|
+
cleanMultilineString(props.content)
|
10
|
+
))
|
11
|
+
|
12
|
+
return () => h("div", { class: 'markdown-body', innerHTML: md.value });
|
13
|
+
}
|
14
|
+
|
15
|
+
}
|
16
|
+
|
17
|
+
function cleanMultilineString(text) {
|
18
|
+
const lines = text.split(/\r?\n/);
|
19
|
+
|
20
|
+
while (lines.length && lines[0].trim() === '') {
|
21
|
+
lines.shift();
|
22
|
+
}
|
23
|
+
|
24
|
+
while (lines.length && lines[lines.length - 1].trim() === '') {
|
25
|
+
lines.pop();
|
26
|
+
}
|
27
|
+
|
28
|
+
if (lines.length > 0) {
|
29
|
+
lines[0] = lines[0].replace(/^[\t ]+/, '');
|
30
|
+
}
|
31
|
+
|
32
|
+
return lines.join('\n');
|
33
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
from instaui import ui
|
3
|
+
|
4
|
+
_STATIC_DIR = Path(__file__).parent / "static"
|
5
|
+
_CORE_JS_FILE = _STATIC_DIR / "marked.esm.js"
|
6
|
+
_GITHUB_MARKDOWN_CSS_FILE = _STATIC_DIR / "github-markdown.css"
|
7
|
+
|
8
|
+
_IMPORT_MAPS = {
|
9
|
+
"marked": _CORE_JS_FILE,
|
10
|
+
}
|
11
|
+
|
12
|
+
|
13
|
+
class Markdown(
|
14
|
+
ui.element,
|
15
|
+
esm="./markdown.js",
|
16
|
+
externals=_IMPORT_MAPS,
|
17
|
+
css=[_GITHUB_MARKDOWN_CSS_FILE],
|
18
|
+
):
|
19
|
+
def __init__(self, content: ui.TMaybeRef[str]):
|
20
|
+
super().__init__()
|
21
|
+
self.props({"content": _clean_multiline_string(content)})
|
22
|
+
|
23
|
+
|
24
|
+
def _clean_multiline_string(text: ui.TMaybeRef[str]) -> ui.TMaybeRef[str]:
|
25
|
+
if not isinstance(text, str):
|
26
|
+
return text
|
27
|
+
|
28
|
+
if not text:
|
29
|
+
return ""
|
30
|
+
|
31
|
+
lines = text.splitlines()
|
32
|
+
|
33
|
+
while lines and lines[0].strip() == "":
|
34
|
+
lines.pop(0)
|
35
|
+
while lines and lines[-1].strip() == "":
|
36
|
+
lines.pop()
|
37
|
+
|
38
|
+
if lines:
|
39
|
+
lines[0] = lines[0].lstrip()
|
40
|
+
|
41
|
+
return "\n".join(lines)
|