instaui 0.1.4__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.
Files changed (82) hide show
  1. instaui/components/echarts/echarts.js +128 -0
  2. instaui/components/echarts/echarts.py +194 -0
  3. instaui/components/echarts/static/echarts.esm.min.js +45 -0
  4. instaui/components/element.py +50 -4
  5. instaui/components/html/__init__.py +30 -19
  6. instaui/components/html/_preset.py +4 -0
  7. instaui/components/html/heading.py +51 -0
  8. instaui/components/html/range.py +3 -0
  9. instaui/components/html/select.py +13 -31
  10. instaui/components/html/table.py +36 -0
  11. instaui/components/markdown/static/marked.esm.js +0 -1
  12. instaui/components/shiki_code/shiki_code.js +126 -0
  13. instaui/components/shiki_code/shiki_code.py +99 -0
  14. instaui/components/shiki_code/static/langs/css.mjs +5 -0
  15. instaui/components/shiki_code/static/langs/markdown.mjs +5 -0
  16. instaui/components/shiki_code/static/langs/python.mjs +5 -0
  17. instaui/components/shiki_code/static/langs/shell.mjs +2 -0
  18. instaui/components/shiki_code/static/langs/shellscript.mjs +5 -0
  19. instaui/components/shiki_code/static/shiki-core.js +5784 -0
  20. instaui/components/shiki_code/static/shiki-style.css +175 -0
  21. instaui/components/shiki_code/static/shiki-transformers.js +461 -0
  22. instaui/components/shiki_code/static/themes/vitesse-dark.mjs +2 -0
  23. instaui/components/shiki_code/static/themes/vitesse-light.mjs +2 -0
  24. instaui/components/value_element.py +7 -3
  25. instaui/consts.py +2 -1
  26. instaui/daisyui/__init__.py +8 -2
  27. instaui/daisyui/_index.py +5 -0
  28. instaui/daisyui/table.py +35 -0
  29. instaui/event/js_event.py +1 -0
  30. instaui/event/web_event.py +6 -7
  31. instaui/fastapi_server/server.py +4 -12
  32. instaui/handlers/event_handler.py +3 -1
  33. instaui/handlers/watch_handler.py +4 -0
  34. instaui/html_tools.py +40 -2
  35. instaui/runtime/_app.py +37 -3
  36. instaui/runtime/_link_manager.py +89 -0
  37. instaui/runtime/resource.py +19 -9
  38. instaui/shadcn_classless/_index.py +42 -0
  39. instaui/shadcn_classless/static/shadcn-classless.css +403 -0
  40. instaui/static/insta-ui.css +1 -1
  41. instaui/static/insta-ui.esm-browser.prod.js +1314 -1253
  42. instaui/static/insta-ui.js.map +1 -1
  43. instaui/static/instaui-tools-browser.js +511 -0
  44. instaui/static/templates/webview.html +78 -0
  45. instaui/tailwind/__init__.py +6 -0
  46. instaui/tailwind/_index.py +24 -0
  47. instaui/{static/tailwindcss.min.js → tailwind/static/tailwindcss-v3.min.js} +62 -62
  48. instaui/tailwind/static/tailwindcss-v4.min.js +8 -0
  49. instaui/template/_utils.py +23 -0
  50. instaui/template/webview_template.py +50 -0
  51. instaui/ui/__init__.py +8 -2
  52. instaui/ui/__init__.pyi +7 -1
  53. instaui/vars/event_context.py +4 -0
  54. instaui/vars/web_computed.py +30 -30
  55. instaui/watch/web_watch.py +5 -6
  56. instaui/webview/__init__.py +1 -0
  57. instaui/webview/_utils.py +8 -0
  58. instaui/webview/api.py +72 -0
  59. instaui/webview/func.py +114 -0
  60. instaui/webview/index.py +162 -0
  61. instaui/webview/resource.py +172 -0
  62. instaui/zero/func.py +19 -12
  63. instaui/zero/scope.py +46 -28
  64. {instaui-0.1.4.dist-info → instaui-0.1.5.dist-info}/METADATA +4 -1
  65. {instaui-0.1.4.dist-info → instaui-0.1.5.dist-info}/RECORD +67 -47
  66. instaui/components/highlight_code/code.js +0 -63
  67. instaui/components/highlight_code/code.py +0 -117
  68. instaui/components/highlight_code/static/core.min.js +0 -307
  69. instaui/components/highlight_code/static/languages/css.min.js +0 -31
  70. instaui/components/highlight_code/static/languages/javascript.min.js +0 -81
  71. instaui/components/highlight_code/static/languages/json.min.js +0 -8
  72. instaui/components/highlight_code/static/languages/python-repl.min.js +0 -5
  73. instaui/components/highlight_code/static/languages/python.min.js +0 -42
  74. instaui/components/highlight_code/static/languages/shell.min.js +0 -5
  75. instaui/components/highlight_code/static/styles/default.min.css +0 -9
  76. instaui/components/highlight_code/static/styles/github-dark-dimmed.min.css +0 -9
  77. instaui/components/highlight_code/static/styles/github-dark.min.css +0 -10
  78. instaui/components/highlight_code/static/styles/github.min.css +0 -10
  79. instaui/handlers/computed_handler.py +0 -42
  80. instaui/handlers/config_handler.py +0 -13
  81. {instaui-0.1.4.dist-info → instaui-0.1.5.dist-info}/LICENSE +0 -0
  82. {instaui-0.1.4.dist-info → instaui-0.1.5.dist-info}/WHEEL +0 -0
@@ -7,6 +7,7 @@ from pathlib import Path
7
7
  import re
8
8
  from typing import (
9
9
  Any,
10
+ Callable,
10
11
  Dict,
11
12
  Iterable,
12
13
  List,
@@ -358,17 +359,58 @@ class Element(Component):
358
359
  *,
359
360
  css: Optional[Iterable[Path]] = None,
360
361
  externals: Optional[Dict[str, Path]] = None,
362
+ replace: bool = False,
361
363
  ):
362
364
  if not self.dependency:
363
365
  return
364
366
 
367
+ app = get_app_slot()
368
+ dep = self.dependency.copy()
369
+ if replace:
370
+ dep.css.clear()
371
+ dep.externals.clear()
372
+
365
373
  if css:
366
- self.dependency.css.update(css)
374
+ dep.css.update(css)
367
375
 
368
376
  if externals:
369
- self.dependency.externals.update(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.
370
383
 
371
- get_app_slot().use_component_dependency(self.dependency.copy(), replace=True)
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)
372
414
 
373
415
  def _to_json_dict(self):
374
416
  data = super()._to_json_dict()
@@ -420,7 +462,11 @@ class Element(Component):
420
462
  data["dir"] = list(self._directives.keys())
421
463
 
422
464
  if self.dependency:
423
- get_app_slot().use_component_dependency(self.dependency)
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
+ )
424
470
 
425
471
  if self._element_ref:
426
472
  scope = get_current_scope()
@@ -1,22 +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
- from .textarea import Textarea as textarea
17
-
18
- option = select.Option
19
-
20
1
  __all__ = [
21
2
  "span",
22
3
  "label",
@@ -35,4 +16,34 @@ __all__ = [
35
16
  "date",
36
17
  "link",
37
18
  "textarea",
19
+ "table",
20
+ "h1",
21
+ "h2",
22
+ "h3",
23
+ "h4",
24
+ "h5",
25
+ "h6",
38
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,4 @@
1
+ from instaui.shadcn_classless._index import use_shadcn_classless
2
+
3
+
4
+ use_shadcn_classless()
@@ -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)
@@ -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,71 +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, ui_vars.TMaybeRef[_T_Select_Value], None] = None,
24
+ value: Union[_T_Select_Value, TMaybeRef[_T_Select_Value], None] = None,
32
25
  *,
33
- model_value: Union[str, ui_vars.TMaybeRef[str], None] = None,
26
+ model_value: Union[str, TMaybeRef[str], None] = None,
34
27
  ):
35
28
  super().__init__("select", value, is_html_component=True)
36
29
 
37
30
  if model_value is not None:
38
31
  self.props({"value": model_value})
39
32
 
40
- @overload
41
- def on_change(self, handler: Callable, *, key: Optional[str] = None) -> Self: ...
42
-
43
- @overload
44
33
  def on_change(
45
34
  self,
46
- handler: str,
35
+ handler: EventMixin,
47
36
  *,
48
- bindings: Optional[Dict] = None,
49
- key: Optional[str] = None,
50
- ) -> Self: ...
51
-
52
- def on_change(
53
- self,
54
- handler: Union[Callable, str],
55
- *,
56
- bindings: Optional[Dict] = None,
57
- key: Optional[str] = None,
37
+ extends: Optional[List] = None,
58
38
  ):
59
- self.on("change", handler, bindings=bindings, key=key) # type: ignore
39
+ self.on("change", handler)
60
40
  return self
61
41
 
62
42
  @classmethod
63
43
  def from_list(
64
44
  cls,
65
45
  options: TMaybeRef[List],
66
- value: Union[_T_Select_Value, ui_vars.TMaybeRef[_T_Select_Value], None] = None,
46
+ value: Union[_T_Select_Value, TMaybeRef[_T_Select_Value], None] = None,
47
+ *,
48
+ model_value: Union[str, TMaybeRef[str], None] = None,
67
49
  ) -> Select:
68
- with cls(value) as select:
50
+ with cls(value, model_value=model_value) as select:
69
51
  with VFor(options) as item:
70
52
  Select.Option(item) # type: ignore
71
53
 
@@ -74,9 +56,9 @@ class Select(ValueElement[Union[List[str], str]]):
74
56
  class Option(Element):
75
57
  def __init__(
76
58
  self,
77
- text: Optional[ui_vars.TMaybeRef[str]] = None,
78
- value: Optional[ui_vars.TMaybeRef[str]] = None,
79
- disabled: Optional[ui_vars.TMaybeRef[bool]] = None,
59
+ text: Optional[TMaybeRef[str]] = None,
60
+ value: Optional[TMaybeRef[str]] = None,
61
+ disabled: Optional[TMaybeRef[bool]] = None,
80
62
  ):
81
63
  props = {
82
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)
@@ -2577,4 +2577,3 @@ const parser = _Parser.parse;
2577
2577
  const lexer = _Lexer.lex;
2578
2578
 
2579
2579
  export { _Hooks as Hooks, _Lexer as Lexer, Marked, _Parser as Parser, _Renderer as Renderer, _TextRenderer as TextRenderer, _Tokenizer as Tokenizer, _defaults as defaults, _getDefaults as getDefaults, lexer, marked, options, parse, parseInline, parser, setOptions, use, walkTokens };
2580
- //# sourceMappingURL=marked.esm.js.map
@@ -0,0 +1,126 @@
1
+ import { h, ref, watch, computed, normalizeClass as _normalizeClass } from "vue";
2
+ import { createHighlighter } from "@shiki";
3
+ import { useClipboard } from "@instaui-tools/browser";
4
+
5
+
6
+ const highlighterTask = createHighlighter({
7
+ themes: ["vitesse-dark", 'vitesse-light']
8
+ })
9
+ const getTransformersModule = transformersModuleGetter()
10
+
11
+
12
+ export default {
13
+ props: ['code', 'language', 'theme', 'themes', 'transformers', 'lineNumbers'],
14
+ setup(props) {
15
+ const { transformers: transformerNames = [], themes = {
16
+ light: 'vitesse-light',
17
+ dark: 'vitesse-dark'
18
+ } } = props;
19
+
20
+ const highlightedCode = ref('');
21
+ const realLanguage = computed(() => props.language || 'python')
22
+ const realTheme = computed(() => props.theme || 'light')
23
+ const realLineNumbers = computed(() => props.lineNumbers ?? true)
24
+ const classes = computed(() => {
25
+ return _normalizeClass([
26
+ `language-${realLanguage.value}`,
27
+ `theme-${realTheme.value}`,
28
+ `shiki-code`,
29
+ { 'line-numbers': realLineNumbers.value }
30
+ ])
31
+ })
32
+
33
+ watch([() => props.code, realTheme], async ([code, _]) => {
34
+ if (!code) {
35
+ return;
36
+ }
37
+ code = code.trim()
38
+ const highlighter = await highlighterTask;
39
+ const transformers = await getTransformers(transformerNames)
40
+
41
+ highlightedCode.value = await highlighter.codeToHtml(code, {
42
+ themes,
43
+ lang: realLanguage.value,
44
+ transformers,
45
+ defaultColor: realTheme.value,
46
+ colorReplacements: {
47
+ '#ffffff': '#f8f8f2'
48
+ }
49
+ });
50
+
51
+ }, { immediate: true });
52
+
53
+
54
+ // copy button
55
+ const { copyButtonClick, btnClasses } = readyCopyButton(props)
56
+
57
+ return () => h("div",
58
+ { class: classes.value },
59
+ [h("button", { class: btnClasses.value, title: "Copy Code", onClick: copyButtonClick }),
60
+ h("span", { class: "lang", }, realLanguage.value),
61
+ h('div', { innerHTML: highlightedCode.value, style: 'overflow:hidden;' })
62
+ ]
63
+ );
64
+ }
65
+
66
+ }
67
+
68
+
69
+ function readyCopyButton(props) {
70
+ const { copy, copied } = useClipboard({ source: props.code, legacy: true })
71
+
72
+ const btnClasses = computed(() => {
73
+ return _normalizeClass([
74
+ "copy",
75
+ { "copied": copied.value }
76
+ ])
77
+ })
78
+
79
+ /**
80
+ *
81
+ * @param {Event} e
82
+ */
83
+ function copyButtonClick(e) {
84
+ copy(props.code)
85
+
86
+ watch(copied, (copied) => {
87
+ if (!copied) {
88
+ e.target.blur()
89
+ }
90
+ }, { once: true })
91
+ }
92
+
93
+ return {
94
+ copyButtonClick,
95
+ btnClasses,
96
+ }
97
+ }
98
+
99
+
100
+ /**
101
+ *
102
+ * @param {string[]} names
103
+ */
104
+ async function getTransformers(names) {
105
+ if (names.length === 0) {
106
+ return [];
107
+ }
108
+
109
+ const tfModule = await getTransformersModule()
110
+ return names.map(name => {
111
+ const realName = `transformer${name.charAt(0).toUpperCase() + name.slice(1)}`
112
+ return tfModule[realName]()
113
+ })
114
+ }
115
+
116
+
117
+ function transformersModuleGetter() {
118
+ let module = null;
119
+
120
+ return async () => {
121
+ if (!module) {
122
+ module = await import(`@shiki/transformers`)
123
+ }
124
+ return module;
125
+ }
126
+ }
@@ -0,0 +1,99 @@
1
+ from __future__ import annotations
2
+ from pathlib import Path
3
+ from typing import Dict, Iterable, List, Literal, Optional
4
+ from instaui import ui
5
+ from instaui.runtime._app import get_app_slot
6
+ from instaui import consts
7
+
8
+ _STATIC_DIR = Path(__file__).parent / "static"
9
+ _THEME_DIR = _STATIC_DIR / "themes"
10
+ _LANG_DIR = _STATIC_DIR / "langs"
11
+ _SHIKI_CORE_FILE = _STATIC_DIR / "shiki-core.js"
12
+ _SHIKI_TRANSFORMERS_FILE = _STATIC_DIR / "shiki-transformers.js"
13
+ _STYLE = _STATIC_DIR / "shiki-style.css"
14
+
15
+
16
+ _LANGS_IMPORT_NAME = "@shiki/langs/"
17
+ _THEMES_IMPORT_NAME = "@shiki/themes/"
18
+
19
+ _IMPORT_MAPS = {
20
+ "@shiki": _SHIKI_CORE_FILE,
21
+ "@shiki/transformers": _SHIKI_TRANSFORMERS_FILE,
22
+ _LANGS_IMPORT_NAME: _LANG_DIR,
23
+ _THEMES_IMPORT_NAME: _THEME_DIR,
24
+ "@instaui-tools/browser": consts.TOOLS_BROWSER_JS_PATH,
25
+ }
26
+
27
+ _ZERO_IMPORT_MAPS = {
28
+ "@shiki": _SHIKI_CORE_FILE,
29
+ "@shiki/transformers": _SHIKI_TRANSFORMERS_FILE,
30
+ f"{_LANGS_IMPORT_NAME}python.mjs": _LANG_DIR / "python.mjs",
31
+ f"{_THEMES_IMPORT_NAME}vitesse-light.mjs": _THEME_DIR / "vitesse-light.mjs",
32
+ f"{_THEMES_IMPORT_NAME}vitesse-dark.mjs": _THEME_DIR / "vitesse-dark.mjs",
33
+ "@instaui-tools/browser": consts.TOOLS_BROWSER_JS_PATH,
34
+ }
35
+
36
+
37
+ class Code(
38
+ ui.element,
39
+ esm="./shiki_code.js",
40
+ externals=_IMPORT_MAPS,
41
+ css=[_STYLE],
42
+ ):
43
+ # _language_folder: ClassVar[Path] = _LANGUAGE_DIR
44
+
45
+ def __init__(
46
+ self,
47
+ code: ui.TMaybeRef[str],
48
+ *,
49
+ language: Optional[ui.TMaybeRef[str]] = None,
50
+ theme: Optional[ui.TMaybeRef[str]] = None,
51
+ themes: Optional[Dict[str, str]] = None,
52
+ transformers: Optional[List[TTransformerNames]] = None,
53
+ line_numbers: Optional[ui.TMaybeRef[bool]] = None,
54
+ ):
55
+ super().__init__()
56
+ self.props({"code": code})
57
+
58
+ if language:
59
+ self.props({"language": language})
60
+
61
+ if theme:
62
+ self.props({"theme": theme})
63
+
64
+ if themes:
65
+ self.props({"themes": themes})
66
+
67
+ if transformers:
68
+ self.props({"transformers": transformers})
69
+
70
+ if line_numbers is not None:
71
+ self.props({"lineNumbers": line_numbers})
72
+
73
+ def _to_json_dict(self):
74
+ self.use_zero_dependency()
75
+ return super()._to_json_dict()
76
+
77
+ def use_zero_dependency(self):
78
+ app = get_app_slot()
79
+ tag_name = self.dependency.tag_name # type: ignore
80
+
81
+ if app.mode != "zero" or app.has_temp_component_dependency(tag_name):
82
+ return
83
+
84
+ self.update_dependencies(
85
+ css=[_STYLE], externals=_ZERO_IMPORT_MAPS, replace=True
86
+ )
87
+
88
+ @staticmethod
89
+ def update_zero_dependency(add_languages: Optional[Iterable[str]] = None):
90
+ if isinstance(add_languages, str):
91
+ add_languages = [add_languages]
92
+
93
+ for lang in add_languages or []:
94
+ name = f"{_LANGS_IMPORT_NAME}{lang}.mjs"
95
+ path = _LANG_DIR / f"{lang}.mjs"
96
+ _ZERO_IMPORT_MAPS[name] = path
97
+
98
+
99
+ TTransformerNames = Literal["notationDiff"]