vue-stream-markdown 0.0.0-alpha.0 → 0.1.0

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 (34) hide show
  1. package/README.md +18 -19
  2. package/dist/{button-D8xx1WIP.js → button-DRLfKbvc.js} +1 -1
  3. package/dist/button-DYIERZf1.js +5 -0
  4. package/dist/{code-CP6mPwkq.js → code-D5-TPyJ2.js} +7 -7
  5. package/dist/code-block-Cs17aZ52.js +9 -0
  6. package/dist/{code-block-C4D_QNTq.js → code-block-fsdBN3mX.js} +5 -5
  7. package/dist/{composables-qhB1h_ed.js → composables-5Y9QWb9D.js} +97 -13
  8. package/dist/dropdown-BegRJmej.js +5 -0
  9. package/dist/error-component-BkdZ6n2L.js +4 -0
  10. package/dist/{error-component-CzarUjhh.js → error-component-DftqHZwH.js} +1 -1
  11. package/dist/{image-heJSlrNv.js → image-dNQ1WKcM.js} +53 -49
  12. package/dist/index.d.ts +45 -33
  13. package/dist/index.js +23 -324
  14. package/dist/{inline-math-B4XO1wMP.js → inline-math-D8LY9Xgq.js} +2 -2
  15. package/dist/{link-DOtoFtxu.js → link-Dkfv0bTE.js} +2 -2
  16. package/dist/{math-Byka28HI.js → math-G8p5HNSV.js} +2 -2
  17. package/dist/{mermaid-X0AFRzfF.js → mermaid-BAFHxaTS.js} +12 -8
  18. package/dist/{previewers-Drlf7IQF.js → previewers-CZxK6T54.js} +1 -1
  19. package/dist/{segmented-BEtO1eyl.js → segmented-CpwUFPie.js} +1 -1
  20. package/dist/segmented-DQFlS2_3.js +6 -0
  21. package/dist/{shiki-vToM7Pz1.js → shiki-CxPfBPEr.js} +1 -1
  22. package/dist/{table-DjkiVd9L.js → table-BSGtENN1.js} +9 -4
  23. package/dist/{tooltip-RiXixMIt.js → tooltip-CTUn3Ask.js} +1 -1
  24. package/dist/tooltip-TCy0JVGe.js +4 -0
  25. package/dist/{zoom-container-BfUO3Ocp.js → zoom-container-BR9gRA9_.js} +2 -2
  26. package/dist/zoom-container-qe4wO3zY.js +6 -0
  27. package/package.json +13 -9
  28. package/dist/button-BClRCjnc.js +0 -5
  29. package/dist/code-block-Dzw63Lki.js +0 -9
  30. package/dist/dropdown-Ca_PKF_d.js +0 -5
  31. package/dist/error-component-CLEJmPmM.js +0 -4
  32. package/dist/segmented-CWoQcX-H.js +0 -6
  33. package/dist/tooltip-Ac_2x9ps.js +0 -4
  34. package/dist/zoom-container-BDEP09K9.js +0 -6
package/README.md CHANGED
@@ -5,40 +5,38 @@
5
5
 
6
6
  A markdown renderer specially optimized for streaming scenarios, inspired by [streamdown](https://streamdown.ai/). Designed to achieve smoother streaming rendering through syntax inference and highly customizable rendering elements.
7
7
 
8
+ ```sh
9
+ pnpm add vue-stream-markdown
10
+ ```
11
+
8
12
  <br>
9
13
 
10
14
  <p align="center">
11
- <a href="#">📚 Documentation</a> |
12
- <a href="#">🤹‍♂️ Playground</a>
15
+ <a href="https://docs-vue-stream-markdown.netlify.app/">📚 Documentation</a> |
16
+ <a href="https://play-vue-stream-markdown.netlify.app/">🤹‍♂️ Playground</a>
13
17
  </p>
14
18
 
15
19
  <br>
16
20
 
17
- ```sh
18
- pnpm add vue-stream-markdown
19
- ```
20
-
21
21
  <p align='center'>
22
22
  <img src='./assets/screenshot.png' />
23
23
  </p>
24
24
 
25
25
  ## Features
26
26
 
27
- - 🚀 **Streaming-optimized rendering** - Incomplete node completion with loading states for images, tables, and code blocks to prevent visual jitter
28
- - **Incremental rendering** - Leverages [Shiki](https://shiki.style/)'s `codeToTokens` API for token-level updates, reducing DOM recreation overhead
29
- - 📊 **Progressive Mermaid rendering** - Throttled, streaming-friendly diagram rendering with loading states
30
- - 📐 **Beautiful LaTeX equations** - Render beautiful LaTeX equations with KaTeX support
31
- - 🎯 **Interactive controls** - Copy and download buttons for images, tables, and code blocks
32
- - 🎨 **Fully customizable** - Replace any AST node with your own Vue components
33
- - **Beautiful built-in typography** - No atomic CSS required (Tailwind/UnoCSS), self-contained styles
34
- - 🎨 **Theme-aware scoped styles** - Scoped styles under `.stream-markdown` with semantic `data-stream-markdown` attributes, following [shadcn/ui](https://ui.shadcn.com/) design system
35
- - 🌏 **CJK language support** - Following `streamdown` design, handles emphasis with ideographic punctuation
36
- - 🛡️ **Content hardening & security** - Built-in protection against malicious Markdown with URL validation and protocol blocking
37
- - 🔒 **TypeScript type safety** - Comprehensive type definitions with full IntelliSense support
27
+ - **Streaming-optimized rendering** - Incomplete node completion with loading states for images, tables, and code blocks to prevent visual jitter
28
+ - **Incremental rendering** - Leverages [Shiki](https://shiki.style/)'s `codeToTokens` API for token-level updates, reducing DOM recreation overhead
29
+ - **Progressive Mermaid rendering** - Throttled, streaming-friendly diagram rendering with loading states
30
+ - **Streaming LaTeX rendering** - Progressive math equation rendering with KaTeX support
31
+ - **Interactive controls** - Copy and download buttons for images, tables, and code blocks
32
+ - **Fully customizable** - Replace any AST node with your own Vue components
33
+ - **Theme-aware scoped styles** - Scoped styles under `.stream-markdown` with semantic `data-stream-markdown` attributes, following [shadcn/ui](https://ui.shadcn.com/) design system
34
+ - **Beautiful built-in typography** - No atomic CSS required (Tailwind/UnoCSS), self-contained styles
35
+ - **Content hardening & security** - Built-in protection against malicious Markdown with URL validation and protocol blocking
38
36
 
39
37
  ## Usage
40
38
 
41
- For detailed usage and API documentation, please refer to the [Documentation](#).
39
+ For detailed usage and API documentation, please refer to the [Documentation](https://docs-vue-stream-markdown.netlify.app/).
42
40
 
43
41
  ```vue
44
42
  <script setup lang="ts">
@@ -57,7 +55,7 @@ const content = ref('# Hello World\n\nThis is a markdown content.')
57
55
 
58
56
  ## Credit
59
57
 
60
- This project is inspired by [streamdown](https://streamdown.ai/) and even uses substantial source code from it.
58
+ This project is inspired by [streamdown](https://streamdown.ai/) and even uses some source code from it.
61
59
 
62
60
  This project also uses and benefits from:
63
61
 
@@ -65,6 +63,7 @@ This project also uses and benefits from:
65
63
  - [Shiki](https://shiki.style/) - Beautiful syntax highlighting
66
64
  - [Mermaid](https://mermaid.js.org/) - Diagramming and charting tool
67
65
  - [KaTeX](https://katex.org/) - Fast math typesetting library for the web
66
+ - [Remend](https://github.com/vercel/streamdown/tree/main/packages/remend) - Intelligently parses and styles incomplete Markdown blocks
68
67
 
69
68
  ## Troubleshooting
70
69
 
@@ -1,4 +1,4 @@
1
- import { t as tooltip_default } from "./tooltip-RiXixMIt.js";
1
+ import { t as tooltip_default } from "./tooltip-CTUn3Ask.js";
2
2
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, h, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, withCtx } from "vue";
3
3
 
4
4
  //#region src/components/dropdown.vue?vue&type=script&setup=true&lang.ts
@@ -0,0 +1,5 @@
1
+ import "./composables-5Y9QWb9D.js";
2
+ import "./tooltip-CTUn3Ask.js";
3
+ import { t as button_default } from "./button-DRLfKbvc.js";
4
+
5
+ export { button_default as default };
@@ -1,10 +1,10 @@
1
- import "./previewers-Drlf7IQF.js";
2
- import { r as useShiki } from "./composables-qhB1h_ed.js";
3
- import "./tooltip-RiXixMIt.js";
4
- import "./button-D8xx1WIP.js";
1
+ import "./previewers-CZxK6T54.js";
2
+ import { i as useShiki } from "./composables-5Y9QWb9D.js";
3
+ import "./tooltip-CTUn3Ask.js";
4
+ import "./button-DRLfKbvc.js";
5
5
  import "./modal-CuQR21UD.js";
6
- import { t as code_block_default } from "./code-block-C4D_QNTq.js";
7
- import "./segmented-BEtO1eyl.js";
6
+ import { t as code_block_default } from "./code-block-fsdBN3mX.js";
7
+ import "./segmented-CpwUFPie.js";
8
8
  import { computed, createBlock, createCommentVNode, defineAsyncComponent, defineComponent, mergeProps, normalizeProps, openBlock, resolveDynamicComponent, withCtx } from "vue";
9
9
 
10
10
  //#region src/components/renderers/code/index.vue?vue&type=script&setup=true&lang.ts
@@ -83,7 +83,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
83
83
  const { installed: hasShiki } = useShiki();
84
84
  const components = {
85
85
  vanilla: defineAsyncComponent(() => import("./vanilla-CA9QO96X.js")),
86
- shiki: defineAsyncComponent(() => import("./shiki-vToM7Pz1.js"))
86
+ shiki: defineAsyncComponent(() => import("./shiki-CxPfBPEr.js"))
87
87
  };
88
88
  const component = computed(() => {
89
89
  if (hasShiki.value) return components.shiki;
@@ -0,0 +1,9 @@
1
+ import "./previewers-CZxK6T54.js";
2
+ import "./composables-5Y9QWb9D.js";
3
+ import "./tooltip-CTUn3Ask.js";
4
+ import "./button-DRLfKbvc.js";
5
+ import "./modal-CuQR21UD.js";
6
+ import { t as code_block_default } from "./code-block-fsdBN3mX.js";
7
+ import "./segmented-CpwUFPie.js";
8
+
9
+ export { code_block_default as default };
@@ -1,8 +1,8 @@
1
- import { t as CODE_PREVIEWERS } from "./previewers-Drlf7IQF.js";
2
- import { F as LANGUAGE_ALIAS, I as LANGUAGE_EXTENSIONS, L as LANGUAGE_ICONS, O as save, R as useControls, i as useMermaid, j as ICONS, l as useI18n, z as useContext } from "./composables-qhB1h_ed.js";
3
- import { t as button_default } from "./button-D8xx1WIP.js";
1
+ import { t as CODE_PREVIEWERS } from "./previewers-CZxK6T54.js";
2
+ import { B as useContext, I as LANGUAGE_ALIAS, L as LANGUAGE_EXTENSIONS, M as ICONS, O as save, R as LANGUAGE_ICONS, a as useMermaid, u as useI18n, z as useControls } from "./composables-5Y9QWb9D.js";
3
+ import { t as button_default } from "./button-DRLfKbvc.js";
4
4
  import { t as modal_default } from "./modal-CuQR21UD.js";
5
- import { t as segmented_default } from "./segmented-BEtO1eyl.js";
5
+ import { t as segmented_default } from "./segmented-CpwUFPie.js";
6
6
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineAsyncComponent, defineComponent, mergeProps, normalizeClass, normalizeProps, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, toRefs, unref, useModel, vShow, watch, withCtx, withDirectives } from "vue";
7
7
  import { useClipboard } from "@vueuse/core";
8
8
 
@@ -208,7 +208,7 @@ var index_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
208
208
  const { t } = useI18n();
209
209
  const { isControlEnabled } = useControls({ controls });
210
210
  const { installed: hasMermaid } = useMermaid();
211
- const CodeNode = defineAsyncComponent(() => import("./code-CP6mPwkq.js"));
211
+ const CodeNode = defineAsyncComponent(() => import("./code-D5-TPyJ2.js"));
212
212
  const { onCopied } = useContext();
213
213
  const { copy, copied } = useClipboard({ legacy: true });
214
214
  const { saveMermaid } = useMermaid();
@@ -1,4 +1,5 @@
1
- import { computed, defineAsyncComponent, inject, provide, ref, unref, watch, watchEffect } from "vue";
1
+ import { computed, defineAsyncComponent, inject, onBeforeUnmount, provide, ref, toValue, unref, watch, watchEffect } from "vue";
2
+ import { useStyleTag } from "@vueuse/core";
2
3
  import { setDefaultProps } from "vue-tippy";
3
4
  import "tippy.js/dist/tippy.css";
4
5
  import "tippy.js/themes/light.css";
@@ -38,22 +39,31 @@ function useContext() {
38
39
  function useControls(options) {
39
40
  const controls = computed(() => unref(options.controls) ?? true);
40
41
  function isControlEnabled(key) {
42
+ try {
43
+ return getControlValue(key) !== false;
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+ function getControlValue(key) {
41
49
  try {
42
50
  const config = controls.value;
43
51
  if (typeof config === "boolean") return config;
44
52
  const path = key.split(".");
45
53
  let current = config;
46
54
  for (const part of path) {
47
- if (current === void 0 || current === null || typeof current !== "object") return true;
55
+ if (current === void 0 || current === null || typeof current !== "object") return void 0;
48
56
  current = current[part];
49
- if (typeof current === "boolean") return current;
50
57
  }
51
- return current === true;
58
+ return current;
52
59
  } catch {
53
- return false;
60
+ return;
54
61
  }
55
62
  }
56
- return { isControlEnabled };
63
+ return {
64
+ isControlEnabled,
65
+ getControlValue
66
+ };
57
67
  }
58
68
 
59
69
  //#endregion
@@ -64,7 +74,6 @@ const LANGUAGE_ALIAS = {};
64
74
  const LANGUAGE_EXTENSIONS = {
65
75
  "1c-query": "1cq",
66
76
  "1c": "1c",
67
- "文言": "wy",
68
77
  "abap": "abap",
69
78
  "actionscript-3": "as",
70
79
  "ada": "ada",
@@ -367,7 +376,8 @@ const LANGUAGE_EXTENSIONS = {
367
376
  "yml": "yml",
368
377
  "zenscript": "zs",
369
378
  "zig": "zig",
370
- "zsh": "zsh"
379
+ "zsh": "zsh",
380
+ "文言": "wy"
371
381
  };
372
382
  const LANGUAGE_ICONS = {
373
383
  "adoc": defineAsyncComponent(() => import("./asciidoc-BabXBDAL.js")),
@@ -576,6 +586,42 @@ const ICONS = {
576
586
  zoomOut: defineAsyncComponent(() => import("./zoomOut-qlzQyQli.js"))
577
587
  };
578
588
 
589
+ //#endregion
590
+ //#region src/constants/theme.ts
591
+ const SHADCN_SCHEMAS = [
592
+ "background",
593
+ "foreground",
594
+ "card",
595
+ "card-foreground",
596
+ "popover",
597
+ "popover-foreground",
598
+ "primary",
599
+ "primary-foreground",
600
+ "secondary",
601
+ "secondary-foreground",
602
+ "muted",
603
+ "muted-foreground",
604
+ "accent",
605
+ "accent-foreground",
606
+ "destructive",
607
+ "border",
608
+ "input",
609
+ "ring",
610
+ "chart-1",
611
+ "chart-2",
612
+ "chart-3",
613
+ "chart-4",
614
+ "chart-5",
615
+ "sidebar",
616
+ "sidebar-foreground",
617
+ "sidebar-primary",
618
+ "sidebar-primary-foreground",
619
+ "sidebar-accent",
620
+ "sidebar-accent-foreground",
621
+ "sidebar-border",
622
+ "sidebar-ring"
623
+ ];
624
+
579
625
  //#endregion
580
626
  //#region src/utils/harden.ts
581
627
  const safeProtocols = new Set([
@@ -916,10 +962,6 @@ function useHardenSanitizers(options) {
916
962
  };
917
963
  }
918
964
 
919
- //#endregion
920
- //#region src/composables/use-hsl-theme.ts
921
- function useHslTheme() {}
922
-
923
965
  //#endregion
924
966
  //#region src/locales/index.ts
925
967
  const SUPPORT_LANGUAGES = ["en-US", "zh-CN"];
@@ -1434,6 +1476,48 @@ function useShiki(options) {
1434
1476
  };
1435
1477
  }
1436
1478
 
1479
+ //#endregion
1480
+ //#region src/composables/use-tailwind-v3-theme.ts
1481
+ const reg = /^(?:hsl|rgb|oklch|lab|lch)\(/;
1482
+ function useTailwindV3Theme(options) {
1483
+ const { id, css, load, unload, isLoaded } = useStyleTag("", {
1484
+ id: "stream-markdown-tailwind-v3-theme",
1485
+ immediate: false
1486
+ });
1487
+ const styleScope = computed(() => unref(options.styleScope) || ".stream-markdown");
1488
+ const element = computed(() => {
1489
+ return toValue(options.element) || (typeof window !== "undefined" ? document.body : void 0);
1490
+ });
1491
+ function generateCSS() {
1492
+ if (!element.value || typeof window === "undefined") return;
1493
+ const computedStyle = window.getComputedStyle(element.value);
1494
+ const cssVariables = [];
1495
+ for (const schema of SHADCN_SCHEMAS) {
1496
+ const name = `--${schema}`;
1497
+ const value = computedStyle.getPropertyValue(name).trim();
1498
+ if (value && !reg.test(value)) cssVariables.push(` ${name}: hsl(${value});`);
1499
+ }
1500
+ if (cssVariables.length > 0) {
1501
+ css.value = `${styleScope.value} {\n${cssVariables.join("\n")}\n}`;
1502
+ load();
1503
+ } else {
1504
+ css.value = "";
1505
+ unload();
1506
+ }
1507
+ }
1508
+ watchEffect(generateCSS);
1509
+ onBeforeUnmount(unload);
1510
+ return {
1511
+ element,
1512
+ id,
1513
+ css,
1514
+ load,
1515
+ unload,
1516
+ isLoaded,
1517
+ generateCSS
1518
+ };
1519
+ }
1520
+
1437
1521
  //#endregion
1438
1522
  //#region src/composables/use-tippy.ts
1439
1523
  function useTippy(options) {
@@ -1564,4 +1648,4 @@ function useZoom(options = {}) {
1564
1648
  }
1565
1649
 
1566
1650
  //#endregion
1567
- export { transformUrl as A, findNodeParent as C, flow as D, hasShiki as E, LANGUAGE_ALIAS as F, LANGUAGE_EXTENSIONS as I, LANGUAGE_ICONS as L, DEFAULT_HARDEN_OPTIONS as M, DEFAULT_DARK_THEME as N, save as O, DEFAULT_LIGHT_THEME as P, useControls as R, findLastLeafNode as S, hasMermaid as T, escapeMarkdownTableCell as _, useMathRenderer as a, tableDataToMarkdown as b, useKatex as c, currentLocale as d, loadLocaleMessages as f, useHardenSanitizers as g, useHslTheme as h, useMermaid as i, ICONS as j, svgToPngBlob as k, useI18n as l, localesGlob as m, useTippy as n, throttle as o, localeMessages as p, useShiki as r, _defineProperty as s, useZoom as t, SUPPORT_LANGUAGES as u, extractTableDataFromElement as v, hasKatex as w, tableDataToTSV as x, tableDataToCSV as y, useContext as z };
1651
+ export { transformUrl as A, useContext as B, findNodeParent as C, flow as D, hasShiki as E, DEFAULT_LIGHT_THEME as F, LANGUAGE_ALIAS as I, LANGUAGE_EXTENSIONS as L, ICONS as M, DEFAULT_HARDEN_OPTIONS as N, save as O, DEFAULT_DARK_THEME as P, LANGUAGE_ICONS as R, findLastLeafNode as S, hasMermaid as T, escapeMarkdownTableCell as _, useMermaid as a, tableDataToMarkdown as b, _defineProperty as c, SUPPORT_LANGUAGES as d, currentLocale as f, useHardenSanitizers as g, localesGlob as h, useShiki as i, SHADCN_SCHEMAS as j, svgToPngBlob as k, useKatex as l, localeMessages as m, useTippy as n, useMathRenderer as o, loadLocaleMessages as p, useTailwindV3Theme as r, throttle as s, useZoom as t, useI18n as u, extractTableDataFromElement as v, hasKatex as w, tableDataToTSV as x, tableDataToCSV as y, useControls as z };
@@ -0,0 +1,5 @@
1
+ import "./composables-5Y9QWb9D.js";
2
+ import "./tooltip-CTUn3Ask.js";
3
+ import { n as dropdown_default } from "./button-DRLfKbvc.js";
4
+
5
+ export { dropdown_default as default };
@@ -0,0 +1,4 @@
1
+ import "./composables-5Y9QWb9D.js";
2
+ import { t as error_component_default } from "./error-component-DftqHZwH.js";
3
+
4
+ export { error_component_default as default };
@@ -1,4 +1,4 @@
1
- import { j as ICONS, l as useI18n } from "./composables-qhB1h_ed.js";
1
+ import { M as ICONS, u as useI18n } from "./composables-5Y9QWb9D.js";
2
2
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, openBlock, renderSlot, resolveDynamicComponent, toDisplayString } from "vue";
3
3
 
4
4
  //#region src/components/error-component.vue?vue&type=script&setup=true&lang.ts
@@ -1,7 +1,7 @@
1
- import { O as save, R as useControls, g as useHardenSanitizers, j as ICONS, l as useI18n } from "./composables-qhB1h_ed.js";
2
- import "./tooltip-RiXixMIt.js";
3
- import { t as button_default } from "./button-D8xx1WIP.js";
4
- import { t as error_component_default } from "./error-component-CzarUjhh.js";
1
+ import { M as ICONS, O as save, g as useHardenSanitizers, u as useI18n, z as useControls } from "./composables-5Y9QWb9D.js";
2
+ import "./tooltip-CTUn3Ask.js";
3
+ import { t as button_default } from "./button-DRLfKbvc.js";
4
+ import { t as error_component_default } from "./error-component-DftqHZwH.js";
5
5
  import { t as spin_default } from "./spin-Ds5W7qC_.js";
6
6
  import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, normalizeStyle, openBlock, ref, resolveDynamicComponent, toDisplayString, toRefs, unref, withCtx } from "vue";
7
7
 
@@ -97,7 +97,7 @@ var image_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
97
97
  var _props$imageOptions;
98
98
  return ((_props$imageOptions = props.imageOptions) === null || _props$imageOptions === void 0 ? void 0 : _props$imageOptions.fallback) ?? "";
99
99
  });
100
- const imageSrc = computed(() => loadError.value && fallback.value ? fallback.value : props.node.url);
100
+ const imageSrc = computed(() => fallbackAttempted.value && fallback.value ? fallback.value : props.node.url);
101
101
  const { transformedUrl, isHardenUrl } = useHardenSanitizers({
102
102
  url: imageSrc,
103
103
  hardenOptions,
@@ -158,51 +158,55 @@ var image_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCo
158
158
  style: normalizeStyle({ width: isLoading.value || !imageLoaded.value ? "100%" : "auto" }),
159
159
  onMouseenter: handleMouseEnter,
160
160
  onMouseleave: handleMouseLeave
161
- }, [createElementVNode("div", _hoisted_1, [!unref(isHardenUrl) ? (openBlock(), createElementBlock("div", {
162
- key: 0,
163
- ref_key: "maskRef",
164
- ref: maskRef,
165
- "data-stream-markdown": "image-mask"
166
- }, [!isLoading.value && showDownload.value ? (openBlock(), createBlock(button_default, {
167
- key: 0,
168
- "data-stream-markdown": "image-download-button",
169
- icon: unref(ICONS).download,
170
- name: unref(t)("button.download"),
171
- "icon-class": "test",
172
- "icon-width": 16,
173
- "icon-height": 16,
174
- "button-style": { backgroundColor: "color-mix(in oklab, var(--background) 90%, transparent)" },
175
- onClick: handleDownload
176
- }, null, 8, ["icon", "name"])) : createCommentVNode("v-if", true)], 512)) : createCommentVNode("v-if", true), createVNode(Transition, {
177
- name: "img-switch",
178
- mode: "out-in"
179
- }, {
180
- default: withCtx(() => [!isLoading.value && !unref(isHardenUrl) && typeof unref(transformedUrl) === "string" ? (openBlock(), createElementBlock("img", {
181
- ref_key: "imgRef",
182
- ref: imgRef,
183
- key: unref(transformedUrl),
184
- "data-stream-markdown": "image",
185
- src: unref(transformedUrl),
186
- alt: alt.value,
187
- title: title.value,
188
- style: normalizeStyle({
189
- opacity: isLoading.value ? 0 : 1,
190
- cursor: isLoading.value ? "default" : "pointer"
191
- }),
192
- loading: "lazy",
193
- decoding: "async",
194
- "data-zoomable": "",
195
- onLoad: handleLoaded,
196
- onError: handleError
197
- }, null, 44, _hoisted_2)) : (isLoading.value || !imageLoaded.value) && !unref(isHardenUrl) ? (openBlock(), createBlock(spin_default, { key: 1 })) : (openBlock(), createBlock(resolveDynamicComponent(Error.value), mergeProps({
198
- key: 2,
199
- variant: unref(isHardenUrl) ? "harden-image" : "image"
200
- }, props), {
201
- default: withCtx(() => [createTextVNode(toDisplayString(title.value), 1)]),
161
+ }, [createElementVNode("div", _hoisted_1, [
162
+ !unref(isHardenUrl) ? (openBlock(), createElementBlock("div", {
163
+ key: 0,
164
+ ref_key: "maskRef",
165
+ ref: maskRef,
166
+ "data-stream-markdown": "image-mask"
167
+ }, [!isLoading.value && showDownload.value ? (openBlock(), createBlock(button_default, {
168
+ key: 0,
169
+ "data-stream-markdown": "image-download-button",
170
+ icon: unref(ICONS).download,
171
+ name: unref(t)("button.download"),
172
+ "icon-class": "test",
173
+ "icon-width": 16,
174
+ "icon-height": 16,
175
+ "button-style": { backgroundColor: "color-mix(in oklab, var(--background) 90%, transparent)" },
176
+ onClick: handleDownload
177
+ }, null, 8, ["icon", "name"])) : createCommentVNode("v-if", true)], 512)) : createCommentVNode("v-if", true),
178
+ (isLoading.value || !imageLoaded.value) && !unref(isHardenUrl) ? (openBlock(), createBlock(spin_default, { key: 1 })) : createCommentVNode("v-if", true),
179
+ createVNode(Transition, {
180
+ name: "img-switch",
181
+ mode: "out-in"
182
+ }, {
183
+ default: withCtx(() => [!isLoading.value && !unref(isHardenUrl) && typeof unref(transformedUrl) === "string" ? (openBlock(), createElementBlock("img", {
184
+ ref_key: "imgRef",
185
+ ref: imgRef,
186
+ key: unref(transformedUrl),
187
+ "data-stream-markdown": "image",
188
+ src: unref(transformedUrl),
189
+ alt: alt.value,
190
+ title: title.value,
191
+ style: normalizeStyle({
192
+ opacity: isLoading.value ? 0 : 1,
193
+ cursor: isLoading.value ? "default" : "pointer"
194
+ }),
195
+ loading: "lazy",
196
+ decoding: "async",
197
+ "data-zoomable": "",
198
+ onLoad: handleLoaded,
199
+ onError: handleError
200
+ }, null, 44, _hoisted_2)) : unref(isHardenUrl) || loadError.value ? (openBlock(), createBlock(resolveDynamicComponent(Error.value), mergeProps({
201
+ key: 1,
202
+ variant: unref(isHardenUrl) ? "harden-image" : "image"
203
+ }, props), {
204
+ default: withCtx(() => [createTextVNode(toDisplayString(title.value), 1)]),
205
+ _: 1
206
+ }, 16, ["variant"])) : createCommentVNode("v-if", true)]),
202
207
  _: 1
203
- }, 16, ["variant"]))]),
204
- _: 1
205
- })]), showCaption.value && title.value ? (openBlock(), createElementBlock("figcaption", _hoisted_3, toDisplayString(title.value), 1)) : createCommentVNode("v-if", true)], 36);
208
+ })
209
+ ]), showCaption.value && title.value ? (openBlock(), createElementBlock("figcaption", _hoisted_3, toDisplayString(title.value), 1)) : createCommentVNode("v-if", true)], 36);
206
210
  };
207
211
  }
208
212
  });