@smoothstream/vue 0.1.3 → 0.1.5

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.
package/README.md CHANGED
@@ -32,4 +32,23 @@ Each mounted component represents one append-only response. Give a different
32
32
  response a new Vue `key`. Static rendering is SSR-safe; browser-only playback,
33
33
  resource loading, highlighting, and clipboard work begin after mounting.
34
34
 
35
+ Pass Vue components for semantic elements produced by Markdown:
36
+
37
+ ```vue
38
+ <script setup lang="ts">
39
+ import AppLink from "./AppLink.vue";
40
+
41
+ const components = { a: AppLink };
42
+ </script>
43
+
44
+ <template>
45
+ <Smoothstream :components="components" :markdown="message.content" />
46
+ </template>
47
+ ```
48
+
49
+ Overrides receive their content through the default slot. Preserve fallthrough
50
+ attributes so Smoothstream can retain its reveal, safety, layout, and
51
+ accessibility behavior. Fenced code and renderer-owned controls are not
52
+ component override targets.
53
+
35
54
  Default reveal mechanics and prose styling are loaded automatically.
package/dist/base.css CHANGED
@@ -94,6 +94,17 @@
94
94
  visibility: hidden;
95
95
  }
96
96
 
97
+ /* Inline code paints only revealed characters; this sibling reserves the rest. */
98
+ [data-smoothstream-code-reserve] {
99
+ visibility: hidden;
100
+ pointer-events: none;
101
+ user-select: none;
102
+ }
103
+
104
+ [data-smoothstream-code-reserve]::after {
105
+ content: attr(data-smoothstream-code-reserve);
106
+ }
107
+
97
108
  [data-smoothstream-kind="text"],
98
109
  [data-smoothstream-kind="inline"],
99
110
  [data-smoothstream-kind="link"] {
@@ -118,6 +129,24 @@
118
129
  cubic-bezier(0.22, 1, 0.36, 1) var(--smoothstream-animation-delay, 0ms) both;
119
130
  }
120
131
 
132
+ [data-smoothstream-kind="footnote"] {
133
+ animation: smoothstream-table-row-in var(--smoothstream-duration, 400ms)
134
+ cubic-bezier(0.22, 1, 0.36, 1) var(--smoothstream-animation-delay, 0ms) both;
135
+ }
136
+
137
+ /* The generated label names the note list for assistive technology. */
138
+ [data-footnotes] > .sr-only {
139
+ position: absolute;
140
+ width: 1px;
141
+ height: 1px;
142
+ padding: 0;
143
+ margin: -1px;
144
+ overflow: hidden;
145
+ clip: rect(0 0 0 0);
146
+ white-space: nowrap;
147
+ border: 0;
148
+ }
149
+
121
150
  [data-smoothstream-kind="image"] {
122
151
  animation: smoothstream-image-in var(--smoothstream-duration, 400ms)
123
152
  cubic-bezier(0.22, 1, 0.36, 1) var(--smoothstream-animation-delay, 0ms) both;
package/dist/index.d.ts CHANGED
@@ -2,14 +2,19 @@ import * as _smoothstream_core from '@smoothstream/core';
2
2
  import { MarkdownReveal, CodeHighlighter } from '@smoothstream/core';
3
3
  export { CodeHighlightLine, CodeHighlightPalette, CodeHighlightRequest, CodeHighlightResult, CodeHighlightToken, CodeHighlighter, CodeTokenStyle } from '@smoothstream/core';
4
4
  import * as vue from 'vue';
5
- import { PropType, VNode } from 'vue';
5
+ import { Component, PropType, VNode } from 'vue';
6
+ import { MarkdownComponentName } from '@smoothstream/core/web';
6
7
 
7
8
  type SmoothstreamMode = "streaming" | "static";
8
9
  type SmoothstreamReducedMotion = "system" | "always" | "never";
9
10
  type SmoothstreamReveal = MarkdownReveal;
11
+ type SmoothstreamComponentName = MarkdownComponentName;
12
+ type SmoothstreamComponents = Partial<Record<SmoothstreamComponentName, Component>>;
10
13
  interface SmoothstreamProps {
11
14
  /** Optional syntax highlighter for fenced code blocks. */
12
15
  codeHighlighter?: CodeHighlighter;
16
+ /** Vue component overrides for semantic elements originating in Markdown. */
17
+ components?: SmoothstreamComponents;
13
18
  /** Milliseconds spent animating each revealed character or word. @default 1000 */
14
19
  duration?: number;
15
20
  /** Base cadence in milliseconds; word mode preserves it while grouping characters. @default 3 */
@@ -30,6 +35,7 @@ interface SmoothstreamProps {
30
35
 
31
36
  declare const Smoothstream: vue.DefineComponent<vue.ExtractPropTypes<{
32
37
  codeHighlighter: PropType<CodeHighlighter | undefined>;
38
+ components: PropType<SmoothstreamComponents | undefined>;
33
39
  duration: {
34
40
  default: number;
35
41
  type: NumberConstructor;
@@ -66,6 +72,7 @@ declare const Smoothstream: vue.DefineComponent<vue.ExtractPropTypes<{
66
72
  [key: string]: any;
67
73
  }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
68
74
  codeHighlighter: PropType<CodeHighlighter | undefined>;
75
+ components: PropType<SmoothstreamComponents | undefined>;
69
76
  duration: {
70
77
  default: number;
71
78
  type: NumberConstructor;
@@ -109,4 +116,4 @@ declare const Smoothstream: vue.DefineComponent<vue.ExtractPropTypes<{
109
116
  unstyled: boolean;
110
117
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
111
118
 
112
- export { Smoothstream, type SmoothstreamMode, type SmoothstreamProps, type SmoothstreamReducedMotion, type SmoothstreamReveal };
119
+ export { Smoothstream, type SmoothstreamComponentName, type SmoothstreamComponents, type SmoothstreamMode, type SmoothstreamProps, type SmoothstreamReducedMotion, type SmoothstreamReveal };
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  shallowRef,
27
27
  Teleport,
28
28
  ref as ref2,
29
+ useId,
29
30
  watch as watch2
30
31
  } from "vue";
31
32
 
@@ -84,13 +85,13 @@ var writeClipboardText = async (button, value) => {
84
85
  textarea.remove();
85
86
  if (!copied) throw new Error("Clipboard copy is unavailable.");
86
87
  };
87
- var webChildrenToVue = (children, filterTableWhitespace, copyContext) => children.flatMap((child) => {
88
+ var webChildrenToVue = (children, filterTableWhitespace, components, copyContext) => children.flatMap((child) => {
88
89
  if (filterTableWhitespace && child.type === "text" && /^\s*$/u.test(child.value)) {
89
90
  return [];
90
91
  }
91
- return [webNodeToVue(child, copyContext)];
92
+ return [webNodeToVue(child, components, copyContext)];
92
93
  });
93
- var webElementToVue = (node, copyContext) => {
94
+ var webElementToVue = (node, components, copyContext) => {
94
95
  const properties = vueElementProperties(node);
95
96
  if (copyContext) {
96
97
  if (node.properties["data-smoothstream-code-copy"] === true) {
@@ -101,19 +102,25 @@ var webElementToVue = (node, copyContext) => {
101
102
  properties["data-state"] = copyContext.copied ? "check" : "copy";
102
103
  }
103
104
  }
104
- return h(
105
- node.tagName,
106
- { ...properties, key: node.key },
107
- webChildrenToVue(
108
- node.children,
109
- tableContainers.has(node.tagName),
110
- copyContext
111
- )
105
+ const children = webChildrenToVue(
106
+ node.children,
107
+ tableContainers.has(node.tagName),
108
+ components,
109
+ copyContext
112
110
  );
111
+ const override = node.markdownElement ? components?.[node.markdownElement] : void 0;
112
+ return override ? h(
113
+ override,
114
+ { ...properties, key: node.key },
115
+ { default: () => children }
116
+ ) : h(node.tagName, { ...properties, key: node.key }, children);
113
117
  };
114
118
  var WebCodeBlock = defineComponent({
115
119
  name: "SmoothstreamCodeBlock",
116
120
  props: {
121
+ components: {
122
+ type: Object
123
+ },
117
124
  node: {
118
125
  required: true,
119
126
  type: Object
@@ -160,27 +167,77 @@ var WebCodeBlock = defineComponent({
160
167
  }
161
168
  );
162
169
  };
163
- return () => webElementToVue(props.node, {
170
+ return () => webElementToVue(props.node, props.components, {
164
171
  copied: copied.value,
165
172
  copy
166
173
  });
167
174
  }
168
175
  });
169
- var webNodeToVue = (node, copyContext) => {
176
+ var webNodeToVue = (node, components, copyContext) => {
170
177
  if (node.type === "text") {
171
178
  const text = createTextVNode(node.value);
172
179
  text.key = node.key;
173
180
  return text;
174
181
  }
175
182
  if (!copyContext && node.tagName === "pre" && node.properties["data-smoothstream-code-block"] === true) {
176
- return h(WebCodeBlock, { key: node.key, node });
183
+ return h(WebCodeBlock, { components, key: node.key, node });
184
+ }
185
+ return webElementToVue(node, components, copyContext);
186
+ };
187
+ var webNodesToVue = (nodes, components) => nodes.map((node) => webNodeToVue(node, components));
188
+
189
+ // ../shared/inline-code-reserve.ts
190
+ var TEXT_METRIC_PROPERTIES = [
191
+ "direction",
192
+ "font-family",
193
+ "font-feature-settings",
194
+ "font-kerning",
195
+ "font-optical-sizing",
196
+ "font-size",
197
+ "font-size-adjust",
198
+ "font-stretch",
199
+ "font-style",
200
+ "font-synthesis",
201
+ "font-variant",
202
+ "font-variation-settings",
203
+ "font-weight",
204
+ "hyphens",
205
+ "letter-spacing",
206
+ "line-break",
207
+ "line-height",
208
+ "overflow-wrap",
209
+ "tab-size",
210
+ "text-orientation",
211
+ "text-rendering",
212
+ "text-transform",
213
+ "white-space",
214
+ "word-break",
215
+ "word-spacing",
216
+ "writing-mode"
217
+ ];
218
+ var synchronizeInlineCodeReservations = (root) => {
219
+ const view = root.ownerDocument.defaultView;
220
+ if (!view) return;
221
+ for (const reserve of root.querySelectorAll(
222
+ "[data-smoothstream-code-reserve]"
223
+ )) {
224
+ const code = reserve.previousElementSibling;
225
+ if (code?.localName !== "code") continue;
226
+ const computed2 = view.getComputedStyle(code);
227
+ for (const property of TEXT_METRIC_PROPERTIES) {
228
+ const value = computed2.getPropertyValue(property);
229
+ if (value && reserve.style.getPropertyValue(property) !== value) {
230
+ reserve.style.setProperty(property, value);
231
+ } else if (!value && reserve.style.getPropertyValue(property)) {
232
+ reserve.style.removeProperty(property);
233
+ }
234
+ }
177
235
  }
178
- return webElementToVue(node, copyContext);
179
236
  };
180
- var webNodesToVue = (nodes) => nodes.map((node) => webNodeToVue(node));
181
237
 
182
238
  // src/Smoothstream.ts
183
239
  var COMPLETION_ANNOUNCEMENT = "Content ready.";
240
+ var nextClientFootnoteInstance = 0;
184
241
  var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
185
242
  var PHASE_SELECTOR = "[data-smoothstream-animation-start]";
186
243
  var PHASE_PROPERTY = "--smoothstream-animation-delay";
@@ -211,6 +268,7 @@ var Smoothstream = defineComponent2({
211
268
  inheritAttrs: false,
212
269
  props: {
213
270
  codeHighlighter: Object,
271
+ components: Object,
214
272
  duration: {
215
273
  default: 1e3,
216
274
  type: Number
@@ -245,6 +303,7 @@ var Smoothstream = defineComponent2({
245
303
  }
246
304
  },
247
305
  setup(props, { attrs }) {
306
+ let footnoteIdPrefix = `smoothstream-${useId()}-`;
248
307
  const root = ref2(null);
249
308
  const mounted = ref2(false);
250
309
  const motionDisabled = ref2(props.reducedMotion === "always");
@@ -262,6 +321,7 @@ var Smoothstream = defineComponent2({
262
321
  const completionAnnouncement = ref2("");
263
322
  let session = new StreamingSession(browserClock, {
264
323
  duration: props.duration,
324
+ footnoteIdPrefix,
265
325
  interval: props.interval
266
326
  });
267
327
  let presentationCache = createWebPresentationCache();
@@ -484,6 +544,7 @@ var Smoothstream = defineComponent2({
484
544
  presentationCache = createWebPresentationCache();
485
545
  session = new StreamingSession(browserClock, {
486
546
  duration: props.duration,
547
+ footnoteIdPrefix,
487
548
  interval: props.interval
488
549
  });
489
550
  requestedSource = props.markdown;
@@ -564,8 +625,23 @@ var Smoothstream = defineComponent2({
564
625
  announcedSource = input.source;
565
626
  completionAnnouncement.value = COMPLETION_ANNOUNCEMENT;
566
627
  };
628
+ const ensureUniqueFootnoteIds = () => {
629
+ const element = root.value;
630
+ const reference = element?.querySelector(
631
+ "[data-footnote-ref][id]"
632
+ );
633
+ if (!element || !reference) return;
634
+ const duplicate = [...element.ownerDocument.querySelectorAll("[data-footnote-ref][id]")].some(
635
+ (candidate) => candidate.id === reference.id && !element.contains(candidate)
636
+ );
637
+ if (!duplicate) return;
638
+ footnoteIdPrefix = `smoothstream-vue-client-${++nextClientFootnoteInstance}-`;
639
+ resetSession();
640
+ };
567
641
  const afterRender = () => {
642
+ ensureUniqueFootnoteIds();
568
643
  synchronizeAnimationPhases();
644
+ if (root.value) synchronizeInlineCodeReservations(root.value);
569
645
  publishCompletionIfReady();
570
646
  };
571
647
  watch2(
@@ -662,7 +738,7 @@ var Smoothstream = defineComponent2({
662
738
  showLanguageLabels: props.codeHighlighter?.showLanguageLabels !== false,
663
739
  tree: input.plan.tree,
664
740
  units: input.plan.units
665
- }));
741
+ }), props.components);
666
742
  };
667
743
  return () => {
668
744
  const motion = props.mode === "streaming" && resolvedMotion.value === "pending" ? "pending" : resolvedMotion.value === "none" ? "none" : "animate";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Smoothstream.ts","../src/render-web.ts"],"sourcesContent":["import \"@smoothstream/styles/base.css\";\nimport \"@smoothstream/styles/styles.css\";\n\nexport { Smoothstream } from \"./Smoothstream\";\nexport type {\n SmoothstreamMode,\n SmoothstreamProps,\n SmoothstreamReducedMotion,\n SmoothstreamReveal,\n} from \"./types\";\nexport type {\n CodeHighlighter,\n CodeHighlightLine,\n CodeHighlightPalette,\n CodeHighlightRequest,\n CodeHighlightResult,\n CodeHighlightToken,\n CodeTokenStyle,\n} from \"@smoothstream/core\";\n","import {\n codeBlockRequestKey,\n resolveCodeHighlight,\n StreamingSession,\n unitsReadyForCodeHighlights,\n type Clock,\n type CodeBlockRequest,\n type CodeHighlighter,\n type ImageDescriptor,\n type ImageReadiness,\n type ResolvedCodeHighlight,\n type StreamingInputSnapshot,\n type StreamingPlaybackSnapshot,\n type StreamingPresentationSnapshot,\n} from \"@smoothstream/core\";\nimport {\n createWebPresentation,\n createWebPresentationCache,\n type WebPresentationCache,\n} from \"@smoothstream/core/web\";\nimport {\n computed,\n defineComponent,\n Fragment,\n h,\n mergeProps,\n nextTick,\n onBeforeUnmount,\n onMounted,\n onUpdated,\n shallowRef,\n Teleport,\n ref,\n watch,\n type PropType,\n type VNode,\n} from \"vue\";\nimport { webNodesToVue } from \"./render-web\";\nimport type {\n SmoothstreamMode,\n SmoothstreamReducedMotion,\n SmoothstreamReveal,\n} from \"./types\";\n\nconst COMPLETION_ANNOUNCEMENT = \"Content ready.\";\nconst REDUCED_MOTION_QUERY = \"(prefers-reduced-motion: reduce)\";\nconst PHASE_SELECTOR = \"[data-smoothstream-animation-start]\";\nconst PHASE_PROPERTY = \"--smoothstream-animation-delay\";\n\nconst screenReaderOnlyStyle = {\n border: 0,\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: \"1px\",\n margin: \"-1px\",\n overflow: \"hidden\",\n padding: 0,\n position: \"absolute\",\n whiteSpace: \"nowrap\",\n width: \"1px\",\n} as const;\n\nconst browserClock: Clock = {\n now: () =>\n typeof window === \"undefined\"\n ? 0\n : window.performance?.now() ?? Date.now(),\n};\n\nconst emptyPlayback = (): StreamingPlaybackSnapshot => ({\n animationComplete: true,\n immediate: false,\n now: 0,\n schedules: new Map(),\n visibleUnitCount: 0,\n});\n\ninterface PendingInput {\n readonly receiving: boolean;\n readonly source: string;\n}\n\ninterface SynchronizedPhase {\n readonly delay: string;\n readonly duration: number;\n readonly startAt: number;\n}\n\nexport const Smoothstream = defineComponent({\n name: \"Smoothstream\",\n inheritAttrs: false,\n props: {\n codeHighlighter: Object as PropType<CodeHighlighter | undefined>,\n duration: {\n default: 1_000,\n type: Number,\n },\n interval: {\n default: 3,\n type: Number,\n },\n markdown: {\n default: \"\",\n type: String,\n },\n mode: {\n default: \"streaming\",\n type: String as PropType<SmoothstreamMode>,\n },\n receiving: {\n default: false,\n type: Boolean,\n },\n reducedMotion: {\n default: \"system\",\n type: String as PropType<SmoothstreamReducedMotion>,\n },\n reveal: {\n default: \"character\",\n type: String as PropType<SmoothstreamReveal>,\n },\n unstyled: {\n default: false,\n type: Boolean,\n },\n },\n setup(props, { attrs }) {\n const root = ref<HTMLDivElement | null>(null);\n const mounted = ref(false);\n const motionDisabled = ref(props.reducedMotion === \"always\");\n const currentInput = shallowRef<StreamingInputSnapshot>();\n const currentPlayback = shallowRef<StreamingPlaybackSnapshot>(\n emptyPlayback(),\n );\n const codeHighlights = shallowRef<ReadonlyMap<number, ResolvedCodeHighlight>>(\n new Map(),\n );\n const imageReadiness = shallowRef<ReadonlyMap<string, ImageReadiness>>(\n new Map(),\n );\n const resourceNow = ref(0);\n const completionAnnouncement = ref(\"\");\n\n let session = new StreamingSession(browserClock, {\n duration: props.duration,\n interval: props.interval,\n });\n let presentationCache: WebPresentationCache = createWebPresentationCache();\n let lastPresentation: StreamingPresentationSnapshot | undefined;\n let requestedSource = props.markdown;\n let pendingInput: PendingInput | undefined = {\n receiving: props.receiving,\n source: props.markdown,\n };\n let inputFrame: number | undefined;\n let playbackFrame: number | undefined;\n let mediaQuery: MediaQueryList | undefined;\n let destroyed = false;\n let announcedSource: string | undefined;\n let completionRendered = false;\n\n const codeRequestsByBlock = new Map<number, string>();\n const codeSessionsByBlock = new Map<number, object>();\n const imageLoaders = new Map<string, HTMLImageElement>();\n const resourceTimers = new Set<number>();\n const synchronizedPhases = new WeakMap<HTMLElement, SynchronizedPhase>();\n let phasedElements = new Set<HTMLElement>();\n\n const resolvedMotion = computed<\"pending\" | \"animate\" | \"none\">(() => {\n if (props.reducedMotion === \"always\") return \"none\";\n if (props.reducedMotion === \"never\") return \"animate\";\n if (!mounted.value) return \"pending\";\n return motionDisabled.value ? \"none\" : \"animate\";\n });\n\n const presentationImmediate = (): boolean =>\n props.mode === \"static\" || resolvedMotion.value === \"none\";\n\n const requestFrame = (callback: FrameRequestCallback): number =>\n typeof window.requestAnimationFrame === \"function\"\n ? window.requestAnimationFrame(callback)\n : window.setTimeout(() => callback(browserClock.now()), 16);\n\n const cancelFrame = (frame: number): void => {\n if (typeof window.cancelAnimationFrame === \"function\") {\n window.cancelAnimationFrame(frame);\n } else {\n window.clearTimeout(frame);\n }\n };\n\n const playbackUnits = (\n input: StreamingInputSnapshot,\n ) => presentationImmediate()\n ? input.plan.units\n : unitsReadyForCodeHighlights(\n input.plan.units,\n props.codeHighlighter,\n codeHighlights.value,\n );\n\n const cancelPlaybackFrame = (): void => {\n if (playbackFrame === undefined || typeof window === \"undefined\") return;\n cancelFrame(playbackFrame);\n playbackFrame = undefined;\n };\n\n const ensurePlaybackFrame = (): void => {\n if (\n destroyed ||\n typeof window === \"undefined\" ||\n presentationImmediate() ||\n currentPlayback.value.animationComplete ||\n playbackFrame !== undefined\n ) {\n return;\n }\n\n playbackFrame = requestFrame(() => {\n playbackFrame = undefined;\n const previous = currentPlayback.value;\n const next = session.advance();\n if (\n next.visibleUnitCount !== previous.visibleUnitCount ||\n (next.animationComplete && !completionRendered)\n ) {\n completionRendered = next.animationComplete;\n currentPlayback.value = next;\n }\n ensurePlaybackFrame();\n });\n };\n\n const refreshPlayback = (input = currentInput.value): void => {\n if (!input) return;\n cancelPlaybackFrame();\n const units = playbackUnits(input);\n if (presentationImmediate()) {\n currentPlayback.value = session.immediate(input, units);\n } else if (mounted.value && resolvedMotion.value === \"animate\") {\n currentPlayback.value = session.schedule(input, units);\n } else {\n currentPlayback.value = emptyPlayback();\n }\n completionRendered = currentPlayback.value.animationComplete;\n ensurePlaybackFrame();\n };\n\n const publishResourceChange = (): void => {\n resourceNow.value = browserClock.now();\n };\n\n const ensureImages = (descriptors: ReadonlyArray<ImageDescriptor>): void => {\n if (\n typeof window === \"undefined\" ||\n presentationImmediate()\n ) {\n return;\n }\n\n for (const descriptor of descriptors) {\n if (\n imageLoaders.has(descriptor.id) ||\n imageReadiness.value.has(descriptor.id)\n ) {\n continue;\n }\n\n let finished = false;\n const finish = (\n status: ImageReadiness[\"status\"],\n image?: HTMLImageElement,\n ): void => {\n if (finished || destroyed) return;\n finished = true;\n imageLoaders.delete(descriptor.id);\n\n const readyAt = browserClock.now();\n const width = image?.naturalWidth ?? 0;\n const height = image?.naturalHeight ?? 0;\n const next = new Map(imageReadiness.value);\n next.set(\n descriptor.id,\n status === \"ready\" && width > 0 && height > 0\n ? { height, readyAt, status, width }\n : { readyAt, status },\n );\n imageReadiness.value = next;\n publishResourceChange();\n\n const timer = window.setTimeout(() => {\n resourceTimers.delete(timer);\n publishResourceChange();\n }, props.duration + 20);\n resourceTimers.add(timer);\n };\n\n if (descriptor.src.length === 0) {\n finish(\"error\");\n continue;\n }\n\n const image = new window.Image();\n imageLoaders.set(descriptor.id, image);\n image.decoding = \"async\";\n image.onerror = () => finish(\"error\");\n let decodeStarted = false;\n const handleLoad = (): void => {\n if (decodeStarted || finished) return;\n decodeStarted = true;\n const decoded = typeof image.decode === \"function\"\n ? image.decode().catch(() => undefined)\n : Promise.resolve();\n void decoded.then(() => finish(\"ready\", image));\n };\n image.onload = handleLoad;\n image.src = descriptor.src;\n if (image.complete && image.naturalWidth > 0) handleLoad();\n }\n };\n\n const commitCodeHighlight = (\n highlighter: CodeHighlighter,\n request: CodeBlockRequest,\n key: string,\n result: Parameters<typeof resolveCodeHighlight>[1],\n ): void => {\n if (\n destroyed ||\n props.codeHighlighter !== highlighter ||\n codeRequestsByBlock.get(request.blockStart) !== key\n ) {\n return;\n }\n\n const next = new Map(codeHighlights.value);\n next.set(\n request.blockStart,\n resolveCodeHighlight(\n request,\n result,\n codeHighlights.value.get(request.blockStart),\n ),\n );\n codeHighlights.value = next;\n refreshPlayback();\n };\n\n const ensureCodeHighlights = (\n requests: ReadonlyArray<CodeBlockRequest>,\n ): void => {\n const highlighter = props.codeHighlighter;\n if (!mounted.value || !highlighter) return;\n\n for (const request of requests) {\n const key = codeBlockRequestKey(request);\n const current = codeHighlights.value.get(request.blockStart);\n if (\n (current?.language === request.language &&\n current.code === request.code) ||\n codeRequestsByBlock.get(request.blockStart) === key\n ) {\n continue;\n }\n codeRequestsByBlock.set(request.blockStart, key);\n let privateSession = codeSessionsByBlock.get(request.blockStart);\n if (!privateSession) {\n privateSession = {};\n codeSessionsByBlock.set(request.blockStart, privateSession);\n }\n\n void Promise.resolve(highlighter.highlight({\n code: request.code,\n language: request.language,\n session: privateSession,\n })).then(\n (result) => commitCodeHighlight(highlighter, request, key, result),\n () => commitCodeHighlight(highlighter, request, key, undefined),\n );\n }\n };\n\n const flushInput = (): void => {\n const pending = pendingInput;\n pendingInput = undefined;\n if (!pending || destroyed) return;\n\n const input = session.prepareInput(\n pending.source,\n pending.receiving,\n props.reveal,\n );\n session.commitInput(input);\n currentInput.value = input;\n if (mounted.value) {\n ensureCodeHighlights(input.codeBlocks);\n ensureImages(input.images);\n }\n refreshPlayback(input);\n };\n\n const scheduleInputFlush = (): void => {\n if (!mounted.value || typeof window === \"undefined\") {\n flushInput();\n return;\n }\n if (inputFrame !== undefined) return;\n inputFrame = requestFrame(() => {\n inputFrame = undefined;\n flushInput();\n });\n };\n\n const clearResourceWork = (): void => {\n for (const image of imageLoaders.values()) {\n image.onload = null;\n image.onerror = null;\n }\n imageLoaders.clear();\n if (typeof window !== \"undefined\") {\n for (const timer of resourceTimers) window.clearTimeout(timer);\n }\n resourceTimers.clear();\n };\n\n const resetSession = (): void => {\n if (typeof window !== \"undefined\") {\n if (inputFrame !== undefined) cancelFrame(inputFrame);\n inputFrame = undefined;\n cancelPlaybackFrame();\n }\n clearResourceWork();\n codeRequestsByBlock.clear();\n codeSessionsByBlock.clear();\n codeHighlights.value = new Map();\n imageReadiness.value = new Map();\n resourceNow.value = 0;\n presentationCache = createWebPresentationCache();\n session = new StreamingSession(browserClock, {\n duration: props.duration,\n interval: props.interval,\n });\n requestedSource = props.markdown;\n pendingInput = {\n receiving: props.receiving,\n source: props.markdown,\n };\n announcedSource = undefined;\n completionAnnouncement.value = \"\";\n flushInput();\n };\n\n function handleMotionChange(event: MediaQueryListEvent): void {\n if (!event.matches || motionDisabled.value) return;\n motionDisabled.value = true;\n refreshPlayback();\n }\n\n const removeMediaListener = (): void => {\n if (!mediaQuery) return;\n if (typeof mediaQuery.removeEventListener === \"function\") {\n mediaQuery.removeEventListener(\"change\", handleMotionChange);\n } else {\n mediaQuery.removeListener?.(handleMotionChange);\n }\n mediaQuery = undefined;\n };\n\n const configureMotion = (): void => {\n removeMediaListener();\n if (\n !mounted.value ||\n typeof window === \"undefined\" ||\n props.reducedMotion !== \"system\" ||\n typeof window.matchMedia !== \"function\"\n ) {\n return;\n }\n mediaQuery = window.matchMedia(REDUCED_MOTION_QUERY);\n if (mediaQuery.matches) motionDisabled.value = true;\n if (typeof mediaQuery.addEventListener === \"function\") {\n mediaQuery.addEventListener(\"change\", handleMotionChange);\n } else {\n mediaQuery.addListener?.(handleMotionChange);\n }\n };\n\n const synchronizeAnimationPhases = (): void => {\n const element = root.value;\n if (!element) return;\n const now = browserClock.now();\n const nextElements = new Set<HTMLElement>();\n for (const animated of element.querySelectorAll<HTMLElement>(PHASE_SELECTOR)) {\n nextElements.add(animated);\n const startAt = Number(animated.dataset.smoothstreamAnimationStart);\n const duration = Number(animated.dataset.smoothstreamAnimationDuration);\n if (!Number.isFinite(startAt) || !Number.isFinite(duration)) continue;\n\n const synchronized = synchronizedPhases.get(animated);\n if (\n synchronized?.startAt === startAt &&\n synchronized.duration === duration\n ) {\n animated.style.setProperty(PHASE_PROPERTY, synchronized.delay);\n continue;\n }\n const currentTime = Math.max(0, Math.min(duration, now - startAt));\n const delay = String(-currentTime) + \"ms\";\n animated.style.setProperty(PHASE_PROPERTY, delay);\n synchronizedPhases.set(animated, { delay, duration, startAt });\n }\n\n for (const previous of phasedElements) {\n if (!nextElements.has(previous)) {\n previous.style.removeProperty(PHASE_PROPERTY);\n if (previous.style.length === 0) previous.removeAttribute(\"style\");\n }\n }\n phasedElements = nextElements;\n };\n\n const publishCompletionIfReady = (): void => {\n const input = currentInput.value;\n const presentation = lastPresentation;\n const element = root.value;\n if (\n props.mode !== \"streaming\" ||\n !mounted.value ||\n !input ||\n !presentation ||\n !element\n ) {\n return;\n }\n if (input.inputOpen) completionAnnouncement.value = \"\";\n if (\n input.inputOpen ||\n input.plan.tree.children.length === 0 ||\n !presentation.allPlannedUnitsCompacted ||\n element.querySelector(\"[data-smoothstream-unit]\") !== null ||\n announcedSource === input.source\n ) {\n return;\n }\n announcedSource = input.source;\n completionAnnouncement.value = COMPLETION_ANNOUNCEMENT;\n };\n\n const afterRender = (): void => {\n synchronizeAnimationPhases();\n publishCompletionIfReady();\n };\n\n watch(\n () => [props.markdown, props.receiving] as const,\n ([source, receiving]) => {\n if (!source.startsWith(requestedSource)) {\n throw new Error(\n \"Smoothstream Markdown must be append-only. Give a different response a new Vue key.\",\n );\n }\n requestedSource = source;\n pendingInput = { receiving, source };\n if (receiving || announcedSource !== source) {\n announcedSource = undefined;\n completionAnnouncement.value = \"\";\n }\n scheduleInputFlush();\n },\n { flush: \"sync\" },\n );\n\n watch(\n () => [props.duration, props.interval, props.mode, props.reveal] as const,\n resetSession,\n { flush: \"sync\" },\n );\n\n watch(\n () => props.codeHighlighter,\n () => {\n codeRequestsByBlock.clear();\n codeSessionsByBlock.clear();\n codeHighlights.value = new Map();\n const input = currentInput.value;\n if (input) ensureCodeHighlights(input.codeBlocks);\n refreshPlayback(input);\n },\n { flush: \"sync\" },\n );\n\n watch(\n () => props.reducedMotion,\n () => {\n configureMotion();\n const input = currentInput.value;\n if (input && !presentationImmediate()) ensureImages(input.images);\n refreshPlayback(input);\n },\n { flush: \"sync\" },\n );\n\n flushInput();\n\n onMounted(() => {\n mounted.value = true;\n configureMotion();\n const input = currentInput.value;\n if (input) {\n ensureCodeHighlights(input.codeBlocks);\n ensureImages(input.images);\n refreshPlayback(input);\n }\n void nextTick(afterRender);\n });\n\n onUpdated(afterRender);\n\n onBeforeUnmount(() => {\n destroyed = true;\n removeMediaListener();\n if (typeof window !== \"undefined\") {\n if (inputFrame !== undefined) cancelFrame(inputFrame);\n cancelPlaybackFrame();\n }\n clearResourceWork();\n codeRequestsByBlock.clear();\n codeSessionsByBlock.clear();\n });\n\n const renderContent = (): VNode[] => {\n const input = currentInput.value;\n if (\n !input ||\n (props.mode === \"streaming\" && resolvedMotion.value === \"pending\")\n ) {\n lastPresentation = undefined;\n return [];\n }\n const playback = currentPlayback.value;\n const now = Math.max(playback.now, resourceNow.value);\n const presentation = session.present(input, playback, { now });\n lastPresentation = presentation;\n return webNodesToVue(createWebPresentation({\n cache: presentationCache,\n codeHighlighterEnabled: props.codeHighlighter !== undefined,\n codeHighlights: codeHighlights.value,\n compactedBlockIds: presentation.compactedBlockIds,\n compactedUnitIds: presentation.compactedUnitIds,\n confirmedBlockIds: input.plan.confirmedBlockIds,\n images: imageReadiness.value,\n immediate: presentationImmediate(),\n now,\n reveal: input.reveal,\n schedules: presentation.schedules,\n showLanguageLabels: props.codeHighlighter?.showLanguageLabels !== false,\n tree: input.plan.tree,\n units: input.plan.units,\n }));\n };\n\n return () => {\n const motion = props.mode === \"streaming\" &&\n resolvedMotion.value === \"pending\"\n ? \"pending\"\n : resolvedMotion.value === \"none\"\n ? \"none\"\n : \"animate\";\n const rootNode = h(\n \"div\",\n mergeProps(attrs, {\n \"data-smoothstream\": true,\n \"data-smoothstream-mode\": props.mode,\n \"data-smoothstream-motion\": motion,\n \"data-smoothstream-reduced-motion\": props.reducedMotion,\n \"data-smoothstream-reveal\": props.reveal,\n \"data-smoothstream-theme\": props.unstyled ? undefined : \"default\",\n ref: root,\n style: {\n \"--smoothstream-duration\":\n String(resolvedMotion.value === \"none\" ? 0 : props.duration) +\n \"ms\",\n \"--smoothstream-interval\":\n String(resolvedMotion.value === \"none\" ? 0 : props.interval) +\n \"ms\",\n },\n }),\n renderContent(),\n );\n const announcer = props.mode === \"streaming\" && mounted.value\n ? h(Teleport, { to: \"body\" }, h(\"div\", {\n \"aria-atomic\": true,\n \"aria-live\": \"polite\",\n \"data-smoothstream-announcer\": true,\n role: \"status\",\n style: screenReaderOnlyStyle,\n }, completionAnnouncement.value))\n : null;\n return h(Fragment, null, [rootNode, announcer]);\n };\n },\n});\n","import { find, html, svg } from \"property-information\";\nimport {\n defineComponent,\n createTextVNode,\n h,\n onBeforeUnmount,\n ref,\n watch,\n type PropType,\n type VNode,\n} from \"vue\";\nimport type {\n WebElementNode,\n WebProperties,\n WebRenderNode,\n} from \"@smoothstream/core/web\";\n\ninterface VuePropertyInfo {\n readonly commaSeparated: boolean;\n readonly name: string;\n}\n\ninterface CopyContext {\n readonly copied: boolean;\n readonly copy: (event: MouseEvent) => void;\n}\n\nconst htmlPropertyInfoByName = new Map<string, VuePropertyInfo>();\nconst svgPropertyInfoByName = new Map<string, VuePropertyInfo>();\nconst tableContainers = new Set([\"table\", \"tbody\", \"tfoot\", \"thead\", \"tr\"]);\n\nconst vuePropertyInfo = (\n property: string,\n namespace: \"svg\" | undefined,\n): VuePropertyInfo => {\n const cache = namespace === \"svg\"\n ? svgPropertyInfoByName\n : htmlPropertyInfoByName;\n const cached = cache.get(property);\n if (cached) return cached;\n\n const information = find(namespace === \"svg\" ? svg : html, property);\n const result = {\n commaSeparated: information.commaSeparated,\n name: information.attribute,\n };\n cache.set(property, result);\n return result;\n};\n\nconst vueElementProperties = (\n node: WebElementNode,\n): Record<string, unknown> => {\n const result: Record<string, unknown> = {};\n for (const [property, originalValue] of Object.entries(node.properties)) {\n if (\n property === \"children\" ||\n originalValue === null ||\n originalValue === undefined ||\n (typeof originalValue === \"number\" && Number.isNaN(originalValue))\n ) {\n continue;\n }\n\n const information = vuePropertyInfo(property, node.namespace);\n result[information.name] = Array.isArray(originalValue)\n ? originalValue\n .map(String)\n .join(information.commaSeparated ? \", \" : \" \")\n .trim()\n : originalValue;\n }\n return result;\n};\n\nconst writeClipboardText = async (\n button: HTMLButtonElement,\n value: string,\n): Promise<void> => {\n const document = button.ownerDocument;\n const view = document.defaultView;\n if (!view) throw new Error(\"Clipboard copy requires a browser window.\");\n\n if (view.navigator.clipboard?.writeText) {\n await view.navigator.clipboard.writeText(value);\n return;\n }\n\n const textarea = document.createElement(\"textarea\");\n textarea.value = value;\n textarea.setAttribute(\"readonly\", \"\");\n textarea.style.position = \"fixed\";\n textarea.style.opacity = \"0\";\n document.body.append(textarea);\n textarea.select();\n const copied = document.execCommand?.(\"copy\") === true;\n textarea.remove();\n if (!copied) throw new Error(\"Clipboard copy is unavailable.\");\n};\n\nconst webChildrenToVue = (\n children: ReadonlyArray<WebRenderNode>,\n filterTableWhitespace: boolean,\n copyContext?: CopyContext,\n): VNode[] => children.flatMap((child) => {\n if (\n filterTableWhitespace &&\n child.type === \"text\" &&\n /^\\s*$/u.test(child.value)\n ) {\n return [];\n }\n return [webNodeToVue(child, copyContext)];\n});\n\nconst webElementToVue = (\n node: WebElementNode,\n copyContext?: CopyContext,\n): VNode => {\n const properties = vueElementProperties(node);\n if (copyContext) {\n if (node.properties[\"data-smoothstream-code-copy\"] === true) {\n properties.onClick = copyContext.copy;\n if (copyContext.copied) properties[\"aria-label\"] = \"Code copied\";\n }\n if (node.properties[\"data-smoothstream-code-icon-swap\"] === true) {\n properties[\"data-state\"] = copyContext.copied ? \"check\" : \"copy\";\n }\n }\n\n return h(\n node.tagName,\n { ...properties, key: node.key },\n webChildrenToVue(\n node.children,\n tableContainers.has(node.tagName),\n copyContext,\n ),\n );\n};\n\nconst WebCodeBlock = defineComponent({\n name: \"SmoothstreamCodeBlock\",\n props: {\n node: {\n required: true,\n type: Object as PropType<WebElementNode>,\n },\n },\n setup(props) {\n const copied = ref(false);\n let resetTimer: number | undefined;\n\n const clearResetTimer = (): void => {\n if (resetTimer === undefined) return;\n const view = typeof window === \"undefined\" ? undefined : window;\n view?.clearTimeout(resetTimer);\n resetTimer = undefined;\n };\n\n watch(\n () => props.node.codeCopyValue,\n () => {\n copied.value = false;\n clearResetTimer();\n },\n );\n\n onBeforeUnmount(clearResetTimer);\n\n const copy = (event: MouseEvent): void => {\n if (props.node.properties[\"data-smoothstream-code-copy-ready\"] !== true) {\n return;\n }\n const button = event.currentTarget as HTMLButtonElement | null;\n if (!button || button.localName !== \"button\") return;\n const code = props.node.codeCopyValue;\n if (code === undefined) return;\n void writeClipboardText(button, code).then(\n () => {\n copied.value = true;\n clearResetTimer();\n const view = button.ownerDocument.defaultView;\n if (!view) return;\n resetTimer = view.setTimeout(() => {\n copied.value = false;\n resetTimer = undefined;\n }, 2_000);\n },\n () => {\n copied.value = false;\n },\n );\n };\n\n return () => webElementToVue(props.node, {\n copied: copied.value,\n copy,\n });\n },\n});\n\nconst webNodeToVue = (\n node: WebRenderNode,\n copyContext?: CopyContext,\n): VNode => {\n if (node.type === \"text\") {\n const text = createTextVNode(node.value);\n text.key = node.key;\n return text;\n }\n if (\n !copyContext &&\n node.tagName === \"pre\" &&\n node.properties[\"data-smoothstream-code-block\"] === true\n ) {\n return h(WebCodeBlock, { key: node.key, node });\n }\n return webElementToVue(node, copyContext);\n};\n\nexport const webNodesToVue = (\n nodes: ReadonlyArray<WebRenderNode>,\n): VNode[] => nodes.map((node) => webNodeToVue(node));\n\nexport type { WebProperties };\n"],"mappings":"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","names":["defineComponent","h","onBeforeUnmount","ref","watch","defineComponent","ref","image","watch","onBeforeUnmount","h"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Smoothstream.ts","../src/render-web.ts","../../shared/inline-code-reserve.ts"],"sourcesContent":["import \"@smoothstream/styles/base.css\";\nimport \"@smoothstream/styles/styles.css\";\n\nexport { Smoothstream } from \"./Smoothstream\";\nexport type {\n SmoothstreamComponentName,\n SmoothstreamComponents,\n SmoothstreamMode,\n SmoothstreamProps,\n SmoothstreamReducedMotion,\n SmoothstreamReveal,\n} from \"./types\";\nexport type {\n CodeHighlighter,\n CodeHighlightLine,\n CodeHighlightPalette,\n CodeHighlightRequest,\n CodeHighlightResult,\n CodeHighlightToken,\n CodeTokenStyle,\n} from \"@smoothstream/core\";\n","import {\n codeBlockRequestKey,\n resolveCodeHighlight,\n StreamingSession,\n unitsReadyForCodeHighlights,\n type Clock,\n type CodeBlockRequest,\n type CodeHighlighter,\n type ImageDescriptor,\n type ImageReadiness,\n type ResolvedCodeHighlight,\n type StreamingInputSnapshot,\n type StreamingPlaybackSnapshot,\n type StreamingPresentationSnapshot,\n} from \"@smoothstream/core\";\nimport {\n createWebPresentation,\n createWebPresentationCache,\n type WebPresentationCache,\n} from \"@smoothstream/core/web\";\nimport {\n computed,\n defineComponent,\n Fragment,\n h,\n mergeProps,\n nextTick,\n onBeforeUnmount,\n onMounted,\n onUpdated,\n shallowRef,\n Teleport,\n ref,\n useId,\n watch,\n type PropType,\n type VNode,\n} from \"vue\";\nimport { webNodesToVue } from \"./render-web\";\nimport { synchronizeInlineCodeReservations } from \"../../shared/inline-code-reserve\";\nimport type {\n SmoothstreamMode,\n SmoothstreamComponents,\n SmoothstreamReducedMotion,\n SmoothstreamReveal,\n} from \"./types\";\n\nconst COMPLETION_ANNOUNCEMENT = \"Content ready.\";\nlet nextClientFootnoteInstance = 0;\nconst REDUCED_MOTION_QUERY = \"(prefers-reduced-motion: reduce)\";\nconst PHASE_SELECTOR = \"[data-smoothstream-animation-start]\";\nconst PHASE_PROPERTY = \"--smoothstream-animation-delay\";\n\nconst screenReaderOnlyStyle = {\n border: 0,\n clip: \"rect(0 0 0 0)\",\n clipPath: \"inset(50%)\",\n height: \"1px\",\n margin: \"-1px\",\n overflow: \"hidden\",\n padding: 0,\n position: \"absolute\",\n whiteSpace: \"nowrap\",\n width: \"1px\",\n} as const;\n\nconst browserClock: Clock = {\n now: () =>\n typeof window === \"undefined\"\n ? 0\n : window.performance?.now() ?? Date.now(),\n};\n\nconst emptyPlayback = (): StreamingPlaybackSnapshot => ({\n animationComplete: true,\n immediate: false,\n now: 0,\n schedules: new Map(),\n visibleUnitCount: 0,\n});\n\ninterface PendingInput {\n readonly receiving: boolean;\n readonly source: string;\n}\n\ninterface SynchronizedPhase {\n readonly delay: string;\n readonly duration: number;\n readonly startAt: number;\n}\n\nexport const Smoothstream = defineComponent({\n name: \"Smoothstream\",\n inheritAttrs: false,\n props: {\n codeHighlighter: Object as PropType<CodeHighlighter | undefined>,\n components: Object as PropType<SmoothstreamComponents | undefined>,\n duration: {\n default: 1_000,\n type: Number,\n },\n interval: {\n default: 3,\n type: Number,\n },\n markdown: {\n default: \"\",\n type: String,\n },\n mode: {\n default: \"streaming\",\n type: String as PropType<SmoothstreamMode>,\n },\n receiving: {\n default: false,\n type: Boolean,\n },\n reducedMotion: {\n default: \"system\",\n type: String as PropType<SmoothstreamReducedMotion>,\n },\n reveal: {\n default: \"character\",\n type: String as PropType<SmoothstreamReveal>,\n },\n unstyled: {\n default: false,\n type: Boolean,\n },\n },\n setup(props, { attrs }) {\n let footnoteIdPrefix = `smoothstream-${useId()}-`;\n const root = ref<HTMLDivElement | null>(null);\n const mounted = ref(false);\n const motionDisabled = ref(props.reducedMotion === \"always\");\n const currentInput = shallowRef<StreamingInputSnapshot>();\n const currentPlayback = shallowRef<StreamingPlaybackSnapshot>(\n emptyPlayback(),\n );\n const codeHighlights = shallowRef<ReadonlyMap<number, ResolvedCodeHighlight>>(\n new Map(),\n );\n const imageReadiness = shallowRef<ReadonlyMap<string, ImageReadiness>>(\n new Map(),\n );\n const resourceNow = ref(0);\n const completionAnnouncement = ref(\"\");\n\n let session = new StreamingSession(browserClock, {\n duration: props.duration,\n footnoteIdPrefix,\n interval: props.interval,\n });\n let presentationCache: WebPresentationCache = createWebPresentationCache();\n let lastPresentation: StreamingPresentationSnapshot | undefined;\n let requestedSource = props.markdown;\n let pendingInput: PendingInput | undefined = {\n receiving: props.receiving,\n source: props.markdown,\n };\n let inputFrame: number | undefined;\n let playbackFrame: number | undefined;\n let mediaQuery: MediaQueryList | undefined;\n let destroyed = false;\n let announcedSource: string | undefined;\n let completionRendered = false;\n\n const codeRequestsByBlock = new Map<number, string>();\n const codeSessionsByBlock = new Map<number, object>();\n const imageLoaders = new Map<string, HTMLImageElement>();\n const resourceTimers = new Set<number>();\n const synchronizedPhases = new WeakMap<HTMLElement, SynchronizedPhase>();\n let phasedElements = new Set<HTMLElement>();\n\n const resolvedMotion = computed<\"pending\" | \"animate\" | \"none\">(() => {\n if (props.reducedMotion === \"always\") return \"none\";\n if (props.reducedMotion === \"never\") return \"animate\";\n if (!mounted.value) return \"pending\";\n return motionDisabled.value ? \"none\" : \"animate\";\n });\n\n const presentationImmediate = (): boolean =>\n props.mode === \"static\" || resolvedMotion.value === \"none\";\n\n const requestFrame = (callback: FrameRequestCallback): number =>\n typeof window.requestAnimationFrame === \"function\"\n ? window.requestAnimationFrame(callback)\n : window.setTimeout(() => callback(browserClock.now()), 16);\n\n const cancelFrame = (frame: number): void => {\n if (typeof window.cancelAnimationFrame === \"function\") {\n window.cancelAnimationFrame(frame);\n } else {\n window.clearTimeout(frame);\n }\n };\n\n const playbackUnits = (\n input: StreamingInputSnapshot,\n ) => presentationImmediate()\n ? input.plan.units\n : unitsReadyForCodeHighlights(\n input.plan.units,\n props.codeHighlighter,\n codeHighlights.value,\n );\n\n const cancelPlaybackFrame = (): void => {\n if (playbackFrame === undefined || typeof window === \"undefined\") return;\n cancelFrame(playbackFrame);\n playbackFrame = undefined;\n };\n\n const ensurePlaybackFrame = (): void => {\n if (\n destroyed ||\n typeof window === \"undefined\" ||\n presentationImmediate() ||\n currentPlayback.value.animationComplete ||\n playbackFrame !== undefined\n ) {\n return;\n }\n\n playbackFrame = requestFrame(() => {\n playbackFrame = undefined;\n const previous = currentPlayback.value;\n const next = session.advance();\n if (\n next.visibleUnitCount !== previous.visibleUnitCount ||\n (next.animationComplete && !completionRendered)\n ) {\n completionRendered = next.animationComplete;\n currentPlayback.value = next;\n }\n ensurePlaybackFrame();\n });\n };\n\n const refreshPlayback = (input = currentInput.value): void => {\n if (!input) return;\n cancelPlaybackFrame();\n const units = playbackUnits(input);\n if (presentationImmediate()) {\n currentPlayback.value = session.immediate(input, units);\n } else if (mounted.value && resolvedMotion.value === \"animate\") {\n currentPlayback.value = session.schedule(input, units);\n } else {\n currentPlayback.value = emptyPlayback();\n }\n completionRendered = currentPlayback.value.animationComplete;\n ensurePlaybackFrame();\n };\n\n const publishResourceChange = (): void => {\n resourceNow.value = browserClock.now();\n };\n\n const ensureImages = (descriptors: ReadonlyArray<ImageDescriptor>): void => {\n if (\n typeof window === \"undefined\" ||\n presentationImmediate()\n ) {\n return;\n }\n\n for (const descriptor of descriptors) {\n if (\n imageLoaders.has(descriptor.id) ||\n imageReadiness.value.has(descriptor.id)\n ) {\n continue;\n }\n\n let finished = false;\n const finish = (\n status: ImageReadiness[\"status\"],\n image?: HTMLImageElement,\n ): void => {\n if (finished || destroyed) return;\n finished = true;\n imageLoaders.delete(descriptor.id);\n\n const readyAt = browserClock.now();\n const width = image?.naturalWidth ?? 0;\n const height = image?.naturalHeight ?? 0;\n const next = new Map(imageReadiness.value);\n next.set(\n descriptor.id,\n status === \"ready\" && width > 0 && height > 0\n ? { height, readyAt, status, width }\n : { readyAt, status },\n );\n imageReadiness.value = next;\n publishResourceChange();\n\n const timer = window.setTimeout(() => {\n resourceTimers.delete(timer);\n publishResourceChange();\n }, props.duration + 20);\n resourceTimers.add(timer);\n };\n\n if (descriptor.src.length === 0) {\n finish(\"error\");\n continue;\n }\n\n const image = new window.Image();\n imageLoaders.set(descriptor.id, image);\n image.decoding = \"async\";\n image.onerror = () => finish(\"error\");\n let decodeStarted = false;\n const handleLoad = (): void => {\n if (decodeStarted || finished) return;\n decodeStarted = true;\n const decoded = typeof image.decode === \"function\"\n ? image.decode().catch(() => undefined)\n : Promise.resolve();\n void decoded.then(() => finish(\"ready\", image));\n };\n image.onload = handleLoad;\n image.src = descriptor.src;\n if (image.complete && image.naturalWidth > 0) handleLoad();\n }\n };\n\n const commitCodeHighlight = (\n highlighter: CodeHighlighter,\n request: CodeBlockRequest,\n key: string,\n result: Parameters<typeof resolveCodeHighlight>[1],\n ): void => {\n if (\n destroyed ||\n props.codeHighlighter !== highlighter ||\n codeRequestsByBlock.get(request.blockStart) !== key\n ) {\n return;\n }\n\n const next = new Map(codeHighlights.value);\n next.set(\n request.blockStart,\n resolveCodeHighlight(\n request,\n result,\n codeHighlights.value.get(request.blockStart),\n ),\n );\n codeHighlights.value = next;\n refreshPlayback();\n };\n\n const ensureCodeHighlights = (\n requests: ReadonlyArray<CodeBlockRequest>,\n ): void => {\n const highlighter = props.codeHighlighter;\n if (!mounted.value || !highlighter) return;\n\n for (const request of requests) {\n const key = codeBlockRequestKey(request);\n const current = codeHighlights.value.get(request.blockStart);\n if (\n (current?.language === request.language &&\n current.code === request.code) ||\n codeRequestsByBlock.get(request.blockStart) === key\n ) {\n continue;\n }\n codeRequestsByBlock.set(request.blockStart, key);\n let privateSession = codeSessionsByBlock.get(request.blockStart);\n if (!privateSession) {\n privateSession = {};\n codeSessionsByBlock.set(request.blockStart, privateSession);\n }\n\n void Promise.resolve(highlighter.highlight({\n code: request.code,\n language: request.language,\n session: privateSession,\n })).then(\n (result) => commitCodeHighlight(highlighter, request, key, result),\n () => commitCodeHighlight(highlighter, request, key, undefined),\n );\n }\n };\n\n const flushInput = (): void => {\n const pending = pendingInput;\n pendingInput = undefined;\n if (!pending || destroyed) return;\n\n const input = session.prepareInput(\n pending.source,\n pending.receiving,\n props.reveal,\n );\n session.commitInput(input);\n currentInput.value = input;\n if (mounted.value) {\n ensureCodeHighlights(input.codeBlocks);\n ensureImages(input.images);\n }\n refreshPlayback(input);\n };\n\n const scheduleInputFlush = (): void => {\n if (!mounted.value || typeof window === \"undefined\") {\n flushInput();\n return;\n }\n if (inputFrame !== undefined) return;\n inputFrame = requestFrame(() => {\n inputFrame = undefined;\n flushInput();\n });\n };\n\n const clearResourceWork = (): void => {\n for (const image of imageLoaders.values()) {\n image.onload = null;\n image.onerror = null;\n }\n imageLoaders.clear();\n if (typeof window !== \"undefined\") {\n for (const timer of resourceTimers) window.clearTimeout(timer);\n }\n resourceTimers.clear();\n };\n\n const resetSession = (): void => {\n if (typeof window !== \"undefined\") {\n if (inputFrame !== undefined) cancelFrame(inputFrame);\n inputFrame = undefined;\n cancelPlaybackFrame();\n }\n clearResourceWork();\n codeRequestsByBlock.clear();\n codeSessionsByBlock.clear();\n codeHighlights.value = new Map();\n imageReadiness.value = new Map();\n resourceNow.value = 0;\n presentationCache = createWebPresentationCache();\n session = new StreamingSession(browserClock, {\n duration: props.duration,\n footnoteIdPrefix,\n interval: props.interval,\n });\n requestedSource = props.markdown;\n pendingInput = {\n receiving: props.receiving,\n source: props.markdown,\n };\n announcedSource = undefined;\n completionAnnouncement.value = \"\";\n flushInput();\n };\n\n function handleMotionChange(event: MediaQueryListEvent): void {\n if (!event.matches || motionDisabled.value) return;\n motionDisabled.value = true;\n refreshPlayback();\n }\n\n const removeMediaListener = (): void => {\n if (!mediaQuery) return;\n if (typeof mediaQuery.removeEventListener === \"function\") {\n mediaQuery.removeEventListener(\"change\", handleMotionChange);\n } else {\n mediaQuery.removeListener?.(handleMotionChange);\n }\n mediaQuery = undefined;\n };\n\n const configureMotion = (): void => {\n removeMediaListener();\n if (\n !mounted.value ||\n typeof window === \"undefined\" ||\n props.reducedMotion !== \"system\" ||\n typeof window.matchMedia !== \"function\"\n ) {\n return;\n }\n mediaQuery = window.matchMedia(REDUCED_MOTION_QUERY);\n if (mediaQuery.matches) motionDisabled.value = true;\n if (typeof mediaQuery.addEventListener === \"function\") {\n mediaQuery.addEventListener(\"change\", handleMotionChange);\n } else {\n mediaQuery.addListener?.(handleMotionChange);\n }\n };\n\n const synchronizeAnimationPhases = (): void => {\n const element = root.value;\n if (!element) return;\n const now = browserClock.now();\n const nextElements = new Set<HTMLElement>();\n for (const animated of element.querySelectorAll<HTMLElement>(PHASE_SELECTOR)) {\n nextElements.add(animated);\n const startAt = Number(animated.dataset.smoothstreamAnimationStart);\n const duration = Number(animated.dataset.smoothstreamAnimationDuration);\n if (!Number.isFinite(startAt) || !Number.isFinite(duration)) continue;\n\n const synchronized = synchronizedPhases.get(animated);\n if (\n synchronized?.startAt === startAt &&\n synchronized.duration === duration\n ) {\n animated.style.setProperty(PHASE_PROPERTY, synchronized.delay);\n continue;\n }\n const currentTime = Math.max(0, Math.min(duration, now - startAt));\n const delay = String(-currentTime) + \"ms\";\n animated.style.setProperty(PHASE_PROPERTY, delay);\n synchronizedPhases.set(animated, { delay, duration, startAt });\n }\n\n for (const previous of phasedElements) {\n if (!nextElements.has(previous)) {\n previous.style.removeProperty(PHASE_PROPERTY);\n if (previous.style.length === 0) previous.removeAttribute(\"style\");\n }\n }\n phasedElements = nextElements;\n };\n\n const publishCompletionIfReady = (): void => {\n const input = currentInput.value;\n const presentation = lastPresentation;\n const element = root.value;\n if (\n props.mode !== \"streaming\" ||\n !mounted.value ||\n !input ||\n !presentation ||\n !element\n ) {\n return;\n }\n if (input.inputOpen) completionAnnouncement.value = \"\";\n if (\n input.inputOpen ||\n input.plan.tree.children.length === 0 ||\n !presentation.allPlannedUnitsCompacted ||\n element.querySelector(\"[data-smoothstream-unit]\") !== null ||\n announcedSource === input.source\n ) {\n return;\n }\n announcedSource = input.source;\n completionAnnouncement.value = COMPLETION_ANNOUNCEMENT;\n };\n\n const ensureUniqueFootnoteIds = (): void => {\n const element = root.value;\n const reference = element?.querySelector<HTMLElement>(\n \"[data-footnote-ref][id]\",\n );\n if (!element || !reference) return;\n const duplicate = [...element.ownerDocument.querySelectorAll(\"[data-footnote-ref][id]\")]\n .some((candidate) =>\n candidate.id === reference.id && !element.contains(candidate)\n );\n if (!duplicate) return;\n footnoteIdPrefix = `smoothstream-vue-client-${++nextClientFootnoteInstance}-`;\n resetSession();\n };\n\n const afterRender = (): void => {\n ensureUniqueFootnoteIds();\n synchronizeAnimationPhases();\n if (root.value) synchronizeInlineCodeReservations(root.value);\n publishCompletionIfReady();\n };\n\n watch(\n () => [props.markdown, props.receiving] as const,\n ([source, receiving]) => {\n if (!source.startsWith(requestedSource)) {\n throw new Error(\n \"Smoothstream Markdown must be append-only. Give a different response a new Vue key.\",\n );\n }\n requestedSource = source;\n pendingInput = { receiving, source };\n if (receiving || announcedSource !== source) {\n announcedSource = undefined;\n completionAnnouncement.value = \"\";\n }\n scheduleInputFlush();\n },\n { flush: \"sync\" },\n );\n\n watch(\n () => [props.duration, props.interval, props.mode, props.reveal] as const,\n resetSession,\n { flush: \"sync\" },\n );\n\n watch(\n () => props.codeHighlighter,\n () => {\n codeRequestsByBlock.clear();\n codeSessionsByBlock.clear();\n codeHighlights.value = new Map();\n const input = currentInput.value;\n if (input) ensureCodeHighlights(input.codeBlocks);\n refreshPlayback(input);\n },\n { flush: \"sync\" },\n );\n\n watch(\n () => props.reducedMotion,\n () => {\n configureMotion();\n const input = currentInput.value;\n if (input && !presentationImmediate()) ensureImages(input.images);\n refreshPlayback(input);\n },\n { flush: \"sync\" },\n );\n\n flushInput();\n\n onMounted(() => {\n mounted.value = true;\n configureMotion();\n const input = currentInput.value;\n if (input) {\n ensureCodeHighlights(input.codeBlocks);\n ensureImages(input.images);\n refreshPlayback(input);\n }\n void nextTick(afterRender);\n });\n\n onUpdated(afterRender);\n\n onBeforeUnmount(() => {\n destroyed = true;\n removeMediaListener();\n if (typeof window !== \"undefined\") {\n if (inputFrame !== undefined) cancelFrame(inputFrame);\n cancelPlaybackFrame();\n }\n clearResourceWork();\n codeRequestsByBlock.clear();\n codeSessionsByBlock.clear();\n });\n\n const renderContent = (): VNode[] => {\n const input = currentInput.value;\n if (\n !input ||\n (props.mode === \"streaming\" && resolvedMotion.value === \"pending\")\n ) {\n lastPresentation = undefined;\n return [];\n }\n const playback = currentPlayback.value;\n const now = Math.max(playback.now, resourceNow.value);\n const presentation = session.present(input, playback, { now });\n lastPresentation = presentation;\n return webNodesToVue(createWebPresentation({\n cache: presentationCache,\n codeHighlighterEnabled: props.codeHighlighter !== undefined,\n codeHighlights: codeHighlights.value,\n compactedBlockIds: presentation.compactedBlockIds,\n compactedUnitIds: presentation.compactedUnitIds,\n confirmedBlockIds: input.plan.confirmedBlockIds,\n images: imageReadiness.value,\n immediate: presentationImmediate(),\n now,\n reveal: input.reveal,\n schedules: presentation.schedules,\n showLanguageLabels: props.codeHighlighter?.showLanguageLabels !== false,\n tree: input.plan.tree,\n units: input.plan.units,\n }), props.components);\n };\n\n return () => {\n const motion = props.mode === \"streaming\" &&\n resolvedMotion.value === \"pending\"\n ? \"pending\"\n : resolvedMotion.value === \"none\"\n ? \"none\"\n : \"animate\";\n const rootNode = h(\n \"div\",\n mergeProps(attrs, {\n \"data-smoothstream\": true,\n \"data-smoothstream-mode\": props.mode,\n \"data-smoothstream-motion\": motion,\n \"data-smoothstream-reduced-motion\": props.reducedMotion,\n \"data-smoothstream-reveal\": props.reveal,\n \"data-smoothstream-theme\": props.unstyled ? undefined : \"default\",\n ref: root,\n style: {\n \"--smoothstream-duration\":\n String(resolvedMotion.value === \"none\" ? 0 : props.duration) +\n \"ms\",\n \"--smoothstream-interval\":\n String(resolvedMotion.value === \"none\" ? 0 : props.interval) +\n \"ms\",\n },\n }),\n renderContent(),\n );\n const announcer = props.mode === \"streaming\" && mounted.value\n ? h(Teleport, { to: \"body\" }, h(\"div\", {\n \"aria-atomic\": true,\n \"aria-live\": \"polite\",\n \"data-smoothstream-announcer\": true,\n role: \"status\",\n style: screenReaderOnlyStyle,\n }, completionAnnouncement.value))\n : null;\n return h(Fragment, null, [rootNode, announcer]);\n };\n },\n});\n","import { find, html, svg } from \"property-information\";\nimport {\n defineComponent,\n createTextVNode,\n h,\n onBeforeUnmount,\n ref,\n watch,\n type PropType,\n type VNode,\n} from \"vue\";\nimport type { SmoothstreamComponents } from \"./types\";\nimport type {\n WebElementNode,\n WebProperties,\n WebRenderNode,\n} from \"@smoothstream/core/web\";\n\ninterface VuePropertyInfo {\n readonly commaSeparated: boolean;\n readonly name: string;\n}\n\ninterface CopyContext {\n readonly copied: boolean;\n readonly copy: (event: MouseEvent) => void;\n}\n\nconst htmlPropertyInfoByName = new Map<string, VuePropertyInfo>();\nconst svgPropertyInfoByName = new Map<string, VuePropertyInfo>();\nconst tableContainers = new Set([\"table\", \"tbody\", \"tfoot\", \"thead\", \"tr\"]);\n\nconst vuePropertyInfo = (\n property: string,\n namespace: \"svg\" | undefined,\n): VuePropertyInfo => {\n const cache = namespace === \"svg\"\n ? svgPropertyInfoByName\n : htmlPropertyInfoByName;\n const cached = cache.get(property);\n if (cached) return cached;\n\n const information = find(namespace === \"svg\" ? svg : html, property);\n const result = {\n commaSeparated: information.commaSeparated,\n name: information.attribute,\n };\n cache.set(property, result);\n return result;\n};\n\nconst vueElementProperties = (\n node: WebElementNode,\n): Record<string, unknown> => {\n const result: Record<string, unknown> = {};\n for (const [property, originalValue] of Object.entries(node.properties)) {\n if (\n property === \"children\" ||\n originalValue === null ||\n originalValue === undefined ||\n (typeof originalValue === \"number\" && Number.isNaN(originalValue))\n ) {\n continue;\n }\n\n const information = vuePropertyInfo(property, node.namespace);\n result[information.name] = Array.isArray(originalValue)\n ? originalValue\n .map(String)\n .join(information.commaSeparated ? \", \" : \" \")\n .trim()\n : originalValue;\n }\n return result;\n};\n\nconst writeClipboardText = async (\n button: HTMLButtonElement,\n value: string,\n): Promise<void> => {\n const document = button.ownerDocument;\n const view = document.defaultView;\n if (!view) throw new Error(\"Clipboard copy requires a browser window.\");\n\n if (view.navigator.clipboard?.writeText) {\n await view.navigator.clipboard.writeText(value);\n return;\n }\n\n const textarea = document.createElement(\"textarea\");\n textarea.value = value;\n textarea.setAttribute(\"readonly\", \"\");\n textarea.style.position = \"fixed\";\n textarea.style.opacity = \"0\";\n document.body.append(textarea);\n textarea.select();\n const copied = document.execCommand?.(\"copy\") === true;\n textarea.remove();\n if (!copied) throw new Error(\"Clipboard copy is unavailable.\");\n};\n\nconst webChildrenToVue = (\n children: ReadonlyArray<WebRenderNode>,\n filterTableWhitespace: boolean,\n components: SmoothstreamComponents | undefined,\n copyContext?: CopyContext,\n): VNode[] => children.flatMap((child) => {\n if (\n filterTableWhitespace &&\n child.type === \"text\" &&\n /^\\s*$/u.test(child.value)\n ) {\n return [];\n }\n return [webNodeToVue(child, components, copyContext)];\n});\n\nconst webElementToVue = (\n node: WebElementNode,\n components: SmoothstreamComponents | undefined,\n copyContext?: CopyContext,\n): VNode => {\n const properties = vueElementProperties(node);\n if (copyContext) {\n if (node.properties[\"data-smoothstream-code-copy\"] === true) {\n properties.onClick = copyContext.copy;\n if (copyContext.copied) properties[\"aria-label\"] = \"Code copied\";\n }\n if (node.properties[\"data-smoothstream-code-icon-swap\"] === true) {\n properties[\"data-state\"] = copyContext.copied ? \"check\" : \"copy\";\n }\n }\n\n const children = webChildrenToVue(\n node.children,\n tableContainers.has(node.tagName),\n components,\n copyContext,\n );\n const override = node.markdownElement\n ? components?.[node.markdownElement]\n : undefined;\n return override\n ? h(\n override,\n { ...properties, key: node.key },\n { default: () => children },\n )\n : h(node.tagName, { ...properties, key: node.key }, children);\n};\n\nconst WebCodeBlock = defineComponent({\n name: \"SmoothstreamCodeBlock\",\n props: {\n components: {\n type: Object as PropType<SmoothstreamComponents | undefined>,\n },\n node: {\n required: true,\n type: Object as PropType<WebElementNode>,\n },\n },\n setup(props) {\n const copied = ref(false);\n let resetTimer: number | undefined;\n\n const clearResetTimer = (): void => {\n if (resetTimer === undefined) return;\n const view = typeof window === \"undefined\" ? undefined : window;\n view?.clearTimeout(resetTimer);\n resetTimer = undefined;\n };\n\n watch(\n () => props.node.codeCopyValue,\n () => {\n copied.value = false;\n clearResetTimer();\n },\n );\n\n onBeforeUnmount(clearResetTimer);\n\n const copy = (event: MouseEvent): void => {\n if (props.node.properties[\"data-smoothstream-code-copy-ready\"] !== true) {\n return;\n }\n const button = event.currentTarget as HTMLButtonElement | null;\n if (!button || button.localName !== \"button\") return;\n const code = props.node.codeCopyValue;\n if (code === undefined) return;\n void writeClipboardText(button, code).then(\n () => {\n copied.value = true;\n clearResetTimer();\n const view = button.ownerDocument.defaultView;\n if (!view) return;\n resetTimer = view.setTimeout(() => {\n copied.value = false;\n resetTimer = undefined;\n }, 2_000);\n },\n () => {\n copied.value = false;\n },\n );\n };\n\n return () => webElementToVue(props.node, props.components, {\n copied: copied.value,\n copy,\n });\n },\n});\n\nconst webNodeToVue = (\n node: WebRenderNode,\n components: SmoothstreamComponents | undefined,\n copyContext?: CopyContext,\n): VNode => {\n if (node.type === \"text\") {\n const text = createTextVNode(node.value);\n text.key = node.key;\n return text;\n }\n if (\n !copyContext &&\n node.tagName === \"pre\" &&\n node.properties[\"data-smoothstream-code-block\"] === true\n ) {\n return h(WebCodeBlock, { components, key: node.key, node });\n }\n return webElementToVue(node, components, copyContext);\n};\n\nexport const webNodesToVue = (\n nodes: ReadonlyArray<WebRenderNode>,\n components?: SmoothstreamComponents,\n): VNode[] => nodes.map((node) => webNodeToVue(node, components));\n\nexport type { WebProperties };\n","const TEXT_METRIC_PROPERTIES = [\n \"direction\",\n \"font-family\",\n \"font-feature-settings\",\n \"font-kerning\",\n \"font-optical-sizing\",\n \"font-size\",\n \"font-size-adjust\",\n \"font-stretch\",\n \"font-style\",\n \"font-synthesis\",\n \"font-variant\",\n \"font-variation-settings\",\n \"font-weight\",\n \"hyphens\",\n \"letter-spacing\",\n \"line-break\",\n \"line-height\",\n \"overflow-wrap\",\n \"tab-size\",\n \"text-orientation\",\n \"text-rendering\",\n \"text-transform\",\n \"white-space\",\n \"word-break\",\n \"word-spacing\",\n \"writing-mode\",\n] as const;\n\n/** Match a layout-only suffix to the consumer's actual rendered inline code. */\nexport const synchronizeInlineCodeReservations = (root: HTMLElement): void => {\n const view = root.ownerDocument.defaultView;\n if (!view) return;\n\n for (const reserve of root.querySelectorAll<HTMLElement>(\n \"[data-smoothstream-code-reserve]\",\n )) {\n const code = reserve.previousElementSibling;\n if (code?.localName !== \"code\") continue;\n const computed = view.getComputedStyle(code);\n for (const property of TEXT_METRIC_PROPERTIES) {\n const value = computed.getPropertyValue(property);\n if (value && reserve.style.getPropertyValue(property) !== value) {\n reserve.style.setProperty(property, value);\n } else if (!value && reserve.style.getPropertyValue(property)) {\n reserve.style.removeProperty(property);\n }\n }\n }\n};\n"],"mappings":";AAAA,OAAO;AACP,OAAO;;;ACDP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAUK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA,mBAAAA;AAAA,EACA;AAAA,EACA,KAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAAC;AAAA,EACA;AAAA,EACA,SAAAC;AAAA,OAGK;;;ACrCP,SAAS,MAAM,MAAM,WAAW;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAkBP,IAAM,yBAAyB,oBAAI,IAA6B;AAChE,IAAM,wBAAwB,oBAAI,IAA6B;AAC/D,IAAM,kBAAkB,oBAAI,IAAI,CAAC,SAAS,SAAS,SAAS,SAAS,IAAI,CAAC;AAE1E,IAAM,kBAAkB,CACtB,UACA,cACoB;AACpB,QAAM,QAAQ,cAAc,QACxB,wBACA;AACJ,QAAM,SAAS,MAAM,IAAI,QAAQ;AACjC,MAAI,OAAQ,QAAO;AAEnB,QAAM,cAAc,KAAK,cAAc,QAAQ,MAAM,MAAM,QAAQ;AACnE,QAAM,SAAS;AAAA,IACb,gBAAgB,YAAY;AAAA,IAC5B,MAAM,YAAY;AAAA,EACpB;AACA,QAAM,IAAI,UAAU,MAAM;AAC1B,SAAO;AACT;AAEA,IAAM,uBAAuB,CAC3B,SAC4B;AAC5B,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,UAAU,aAAa,KAAK,OAAO,QAAQ,KAAK,UAAU,GAAG;AACvE,QACE,aAAa,cACb,kBAAkB,QAClB,kBAAkB,UACjB,OAAO,kBAAkB,YAAY,OAAO,MAAM,aAAa,GAChE;AACA;AAAA,IACF;AAEA,UAAM,cAAc,gBAAgB,UAAU,KAAK,SAAS;AAC5D,WAAO,YAAY,IAAI,IAAI,MAAM,QAAQ,aAAa,IAClD,cACC,IAAI,MAAM,EACV,KAAK,YAAY,iBAAiB,OAAO,GAAG,EAC5C,KAAK,IACN;AAAA,EACN;AACA,SAAO;AACT;AAEA,IAAM,qBAAqB,OACzB,QACA,UACkB;AAClB,QAAM,WAAW,OAAO;AACxB,QAAM,OAAO,SAAS;AACtB,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,2CAA2C;AAEtE,MAAI,KAAK,UAAU,WAAW,WAAW;AACvC,UAAM,KAAK,UAAU,UAAU,UAAU,KAAK;AAC9C;AAAA,EACF;AAEA,QAAM,WAAW,SAAS,cAAc,UAAU;AAClD,WAAS,QAAQ;AACjB,WAAS,aAAa,YAAY,EAAE;AACpC,WAAS,MAAM,WAAW;AAC1B,WAAS,MAAM,UAAU;AACzB,WAAS,KAAK,OAAO,QAAQ;AAC7B,WAAS,OAAO;AAChB,QAAM,SAAS,SAAS,cAAc,MAAM,MAAM;AAClD,WAAS,OAAO;AAChB,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,gCAAgC;AAC/D;AAEA,IAAM,mBAAmB,CACvB,UACA,uBACA,YACA,gBACY,SAAS,QAAQ,CAAC,UAAU;AACxC,MACE,yBACA,MAAM,SAAS,UACf,SAAS,KAAK,MAAM,KAAK,GACzB;AACA,WAAO,CAAC;AAAA,EACV;AACA,SAAO,CAAC,aAAa,OAAO,YAAY,WAAW,CAAC;AACtD,CAAC;AAED,IAAM,kBAAkB,CACtB,MACA,YACA,gBACU;AACV,QAAM,aAAa,qBAAqB,IAAI;AAC5C,MAAI,aAAa;AACf,QAAI,KAAK,WAAW,6BAA6B,MAAM,MAAM;AAC3D,iBAAW,UAAU,YAAY;AACjC,UAAI,YAAY,OAAQ,YAAW,YAAY,IAAI;AAAA,IACrD;AACA,QAAI,KAAK,WAAW,kCAAkC,MAAM,MAAM;AAChE,iBAAW,YAAY,IAAI,YAAY,SAAS,UAAU;AAAA,IAC5D;AAAA,EACF;AAEA,QAAM,WAAW;AAAA,IACf,KAAK;AAAA,IACL,gBAAgB,IAAI,KAAK,OAAO;AAAA,IAChC;AAAA,IACA;AAAA,EACF;AACA,QAAM,WAAW,KAAK,kBAClB,aAAa,KAAK,eAAe,IACjC;AACJ,SAAO,WACH;AAAA,IACE;AAAA,IACA,EAAE,GAAG,YAAY,KAAK,KAAK,IAAI;AAAA,IAC/B,EAAE,SAAS,MAAM,SAAS;AAAA,EAC5B,IACA,EAAE,KAAK,SAAS,EAAE,GAAG,YAAY,KAAK,KAAK,IAAI,GAAG,QAAQ;AAChE;AAEA,IAAM,eAAe,gBAAgB;AAAA,EACnC,MAAM;AAAA,EACN,OAAO;AAAA,IACL,YAAY;AAAA,MACV,MAAM;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,OAAO;AACX,UAAM,SAAS,IAAI,KAAK;AACxB,QAAI;AAEJ,UAAM,kBAAkB,MAAY;AAClC,UAAI,eAAe,OAAW;AAC9B,YAAM,OAAO,OAAO,WAAW,cAAc,SAAY;AACzD,YAAM,aAAa,UAAU;AAC7B,mBAAa;AAAA,IACf;AAEA;AAAA,MACE,MAAM,MAAM,KAAK;AAAA,MACjB,MAAM;AACJ,eAAO,QAAQ;AACf,wBAAgB;AAAA,MAClB;AAAA,IACF;AAEA,oBAAgB,eAAe;AAE/B,UAAM,OAAO,CAAC,UAA4B;AACxC,UAAI,MAAM,KAAK,WAAW,mCAAmC,MAAM,MAAM;AACvE;AAAA,MACF;AACA,YAAM,SAAS,MAAM;AACrB,UAAI,CAAC,UAAU,OAAO,cAAc,SAAU;AAC9C,YAAM,OAAO,MAAM,KAAK;AACxB,UAAI,SAAS,OAAW;AACxB,WAAK,mBAAmB,QAAQ,IAAI,EAAE;AAAA,QACpC,MAAM;AACJ,iBAAO,QAAQ;AACf,0BAAgB;AAChB,gBAAM,OAAO,OAAO,cAAc;AAClC,cAAI,CAAC,KAAM;AACX,uBAAa,KAAK,WAAW,MAAM;AACjC,mBAAO,QAAQ;AACf,yBAAa;AAAA,UACf,GAAG,GAAK;AAAA,QACV;AAAA,QACA,MAAM;AACJ,iBAAO,QAAQ;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,WAAO,MAAM,gBAAgB,MAAM,MAAM,MAAM,YAAY;AAAA,MACzD,QAAQ,OAAO;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;AAED,IAAM,eAAe,CACnB,MACA,YACA,gBACU;AACV,MAAI,KAAK,SAAS,QAAQ;AACxB,UAAM,OAAO,gBAAgB,KAAK,KAAK;AACvC,SAAK,MAAM,KAAK;AAChB,WAAO;AAAA,EACT;AACA,MACE,CAAC,eACD,KAAK,YAAY,SACjB,KAAK,WAAW,8BAA8B,MAAM,MACpD;AACA,WAAO,EAAE,cAAc,EAAE,YAAY,KAAK,KAAK,KAAK,KAAK,CAAC;AAAA,EAC5D;AACA,SAAO,gBAAgB,MAAM,YAAY,WAAW;AACtD;AAEO,IAAM,gBAAgB,CAC3B,OACA,eACY,MAAM,IAAI,CAAC,SAAS,aAAa,MAAM,UAAU,CAAC;;;AC9OhE,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,IAAM,oCAAoC,CAAC,SAA4B;AAC5E,QAAM,OAAO,KAAK,cAAc;AAChC,MAAI,CAAC,KAAM;AAEX,aAAW,WAAW,KAAK;AAAA,IACzB;AAAA,EACF,GAAG;AACD,UAAM,OAAO,QAAQ;AACrB,QAAI,MAAM,cAAc,OAAQ;AAChC,UAAMC,YAAW,KAAK,iBAAiB,IAAI;AAC3C,eAAW,YAAY,wBAAwB;AAC7C,YAAM,QAAQA,UAAS,iBAAiB,QAAQ;AAChD,UAAI,SAAS,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,OAAO;AAC/D,gBAAQ,MAAM,YAAY,UAAU,KAAK;AAAA,MAC3C,WAAW,CAAC,SAAS,QAAQ,MAAM,iBAAiB,QAAQ,GAAG;AAC7D,gBAAQ,MAAM,eAAe,QAAQ;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AACF;;;AFFA,IAAM,0BAA0B;AAChC,IAAI,6BAA6B;AACjC,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AAEvB,IAAM,wBAAwB;AAAA,EAC5B,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,OAAO;AACT;AAEA,IAAM,eAAsB;AAAA,EAC1B,KAAK,MACH,OAAO,WAAW,cACd,IACA,OAAO,aAAa,IAAI,KAAK,KAAK,IAAI;AAC9C;AAEA,IAAM,gBAAgB,OAAkC;AAAA,EACtD,mBAAmB;AAAA,EACnB,WAAW;AAAA,EACX,KAAK;AAAA,EACL,WAAW,oBAAI,IAAI;AAAA,EACnB,kBAAkB;AACpB;AAaO,IAAM,eAAeC,iBAAgB;AAAA,EAC1C,MAAM;AAAA,EACN,cAAc;AAAA,EACd,OAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,UAAU;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,UAAU;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,WAAW;AAAA,MACT,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,eAAe;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,IACA,UAAU;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,MAAM,GAAG;AACtB,QAAI,mBAAmB,gBAAgB,MAAM,CAAC;AAC9C,UAAM,OAAOC,KAA2B,IAAI;AAC5C,UAAM,UAAUA,KAAI,KAAK;AACzB,UAAM,iBAAiBA,KAAI,MAAM,kBAAkB,QAAQ;AAC3D,UAAM,eAAe,WAAmC;AACxD,UAAM,kBAAkB;AAAA,MACtB,cAAc;AAAA,IAChB;AACA,UAAM,iBAAiB;AAAA,MACrB,oBAAI,IAAI;AAAA,IACV;AACA,UAAM,iBAAiB;AAAA,MACrB,oBAAI,IAAI;AAAA,IACV;AACA,UAAM,cAAcA,KAAI,CAAC;AACzB,UAAM,yBAAyBA,KAAI,EAAE;AAErC,QAAI,UAAU,IAAI,iBAAiB,cAAc;AAAA,MAC/C,UAAU,MAAM;AAAA,MAChB;AAAA,MACA,UAAU,MAAM;AAAA,IAClB,CAAC;AACD,QAAI,oBAA0C,2BAA2B;AACzE,QAAI;AACJ,QAAI,kBAAkB,MAAM;AAC5B,QAAI,eAAyC;AAAA,MAC3C,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM;AAAA,IAChB;AACA,QAAI;AACJ,QAAI;AACJ,QAAI;AACJ,QAAI,YAAY;AAChB,QAAI;AACJ,QAAI,qBAAqB;AAEzB,UAAM,sBAAsB,oBAAI,IAAoB;AACpD,UAAM,sBAAsB,oBAAI,IAAoB;AACpD,UAAM,eAAe,oBAAI,IAA8B;AACvD,UAAM,iBAAiB,oBAAI,IAAY;AACvC,UAAM,qBAAqB,oBAAI,QAAwC;AACvE,QAAI,iBAAiB,oBAAI,IAAiB;AAE1C,UAAM,iBAAiB,SAAyC,MAAM;AACpE,UAAI,MAAM,kBAAkB,SAAU,QAAO;AAC7C,UAAI,MAAM,kBAAkB,QAAS,QAAO;AAC5C,UAAI,CAAC,QAAQ,MAAO,QAAO;AAC3B,aAAO,eAAe,QAAQ,SAAS;AAAA,IACzC,CAAC;AAED,UAAM,wBAAwB,MAC5B,MAAM,SAAS,YAAY,eAAe,UAAU;AAEtD,UAAM,eAAe,CAAC,aACpB,OAAO,OAAO,0BAA0B,aACpC,OAAO,sBAAsB,QAAQ,IACrC,OAAO,WAAW,MAAM,SAAS,aAAa,IAAI,CAAC,GAAG,EAAE;AAE9D,UAAM,cAAc,CAAC,UAAwB;AAC3C,UAAI,OAAO,OAAO,yBAAyB,YAAY;AACrD,eAAO,qBAAqB,KAAK;AAAA,MACnC,OAAO;AACL,eAAO,aAAa,KAAK;AAAA,MAC3B;AAAA,IACF;AAEA,UAAM,gBAAgB,CACpB,UACG,sBAAsB,IACvB,MAAM,KAAK,QACX;AAAA,MACA,MAAM,KAAK;AAAA,MACX,MAAM;AAAA,MACN,eAAe;AAAA,IACjB;AAEF,UAAM,sBAAsB,MAAY;AACtC,UAAI,kBAAkB,UAAa,OAAO,WAAW,YAAa;AAClE,kBAAY,aAAa;AACzB,sBAAgB;AAAA,IAClB;AAEA,UAAM,sBAAsB,MAAY;AACtC,UACE,aACA,OAAO,WAAW,eAClB,sBAAsB,KACtB,gBAAgB,MAAM,qBACtB,kBAAkB,QAClB;AACA;AAAA,MACF;AAEA,sBAAgB,aAAa,MAAM;AACjC,wBAAgB;AAChB,cAAM,WAAW,gBAAgB;AACjC,cAAM,OAAO,QAAQ,QAAQ;AAC7B,YACE,KAAK,qBAAqB,SAAS,oBAClC,KAAK,qBAAqB,CAAC,oBAC5B;AACA,+BAAqB,KAAK;AAC1B,0BAAgB,QAAQ;AAAA,QAC1B;AACA,4BAAoB;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,UAAM,kBAAkB,CAAC,QAAQ,aAAa,UAAgB;AAC5D,UAAI,CAAC,MAAO;AACZ,0BAAoB;AACpB,YAAM,QAAQ,cAAc,KAAK;AACjC,UAAI,sBAAsB,GAAG;AAC3B,wBAAgB,QAAQ,QAAQ,UAAU,OAAO,KAAK;AAAA,MACxD,WAAW,QAAQ,SAAS,eAAe,UAAU,WAAW;AAC9D,wBAAgB,QAAQ,QAAQ,SAAS,OAAO,KAAK;AAAA,MACvD,OAAO;AACL,wBAAgB,QAAQ,cAAc;AAAA,MACxC;AACA,2BAAqB,gBAAgB,MAAM;AAC3C,0BAAoB;AAAA,IACtB;AAEA,UAAM,wBAAwB,MAAY;AACxC,kBAAY,QAAQ,aAAa,IAAI;AAAA,IACvC;AAEA,UAAM,eAAe,CAAC,gBAAsD;AAC1E,UACE,OAAO,WAAW,eAClB,sBAAsB,GACtB;AACA;AAAA,MACF;AAEA,iBAAW,cAAc,aAAa;AACpC,YACE,aAAa,IAAI,WAAW,EAAE,KAC9B,eAAe,MAAM,IAAI,WAAW,EAAE,GACtC;AACA;AAAA,QACF;AAEA,YAAI,WAAW;AACf,cAAM,SAAS,CACb,QACAC,WACS;AACT,cAAI,YAAY,UAAW;AAC3B,qBAAW;AACX,uBAAa,OAAO,WAAW,EAAE;AAEjC,gBAAM,UAAU,aAAa,IAAI;AACjC,gBAAM,QAAQA,QAAO,gBAAgB;AACrC,gBAAM,SAASA,QAAO,iBAAiB;AACvC,gBAAM,OAAO,IAAI,IAAI,eAAe,KAAK;AACzC,eAAK;AAAA,YACH,WAAW;AAAA,YACX,WAAW,WAAW,QAAQ,KAAK,SAAS,IACxC,EAAE,QAAQ,SAAS,QAAQ,MAAM,IACjC,EAAE,SAAS,OAAO;AAAA,UACxB;AACA,yBAAe,QAAQ;AACvB,gCAAsB;AAEtB,gBAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,2BAAe,OAAO,KAAK;AAC3B,kCAAsB;AAAA,UACxB,GAAG,MAAM,WAAW,EAAE;AACtB,yBAAe,IAAI,KAAK;AAAA,QAC1B;AAEA,YAAI,WAAW,IAAI,WAAW,GAAG;AAC/B,iBAAO,OAAO;AACd;AAAA,QACF;AAEA,cAAM,QAAQ,IAAI,OAAO,MAAM;AAC/B,qBAAa,IAAI,WAAW,IAAI,KAAK;AACrC,cAAM,WAAW;AACjB,cAAM,UAAU,MAAM,OAAO,OAAO;AACpC,YAAI,gBAAgB;AACpB,cAAM,aAAa,MAAY;AAC7B,cAAI,iBAAiB,SAAU;AAC/B,0BAAgB;AAChB,gBAAM,UAAU,OAAO,MAAM,WAAW,aACpC,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS,IACpC,QAAQ,QAAQ;AACpB,eAAK,QAAQ,KAAK,MAAM,OAAO,SAAS,KAAK,CAAC;AAAA,QAChD;AACA,cAAM,SAAS;AACf,cAAM,MAAM,WAAW;AACvB,YAAI,MAAM,YAAY,MAAM,eAAe,EAAG,YAAW;AAAA,MAC3D;AAAA,IACF;AAEA,UAAM,sBAAsB,CAC1B,aACA,SACA,KACA,WACS;AACT,UACE,aACA,MAAM,oBAAoB,eAC1B,oBAAoB,IAAI,QAAQ,UAAU,MAAM,KAChD;AACA;AAAA,MACF;AAEA,YAAM,OAAO,IAAI,IAAI,eAAe,KAAK;AACzC,WAAK;AAAA,QACH,QAAQ;AAAA,QACR;AAAA,UACE;AAAA,UACA;AAAA,UACA,eAAe,MAAM,IAAI,QAAQ,UAAU;AAAA,QAC7C;AAAA,MACF;AACA,qBAAe,QAAQ;AACvB,sBAAgB;AAAA,IAClB;AAEA,UAAM,uBAAuB,CAC3B,aACS;AACT,YAAM,cAAc,MAAM;AAC1B,UAAI,CAAC,QAAQ,SAAS,CAAC,YAAa;AAEpC,iBAAW,WAAW,UAAU;AAC9B,cAAM,MAAM,oBAAoB,OAAO;AACvC,cAAM,UAAU,eAAe,MAAM,IAAI,QAAQ,UAAU;AAC3D,YACG,SAAS,aAAa,QAAQ,YAC7B,QAAQ,SAAS,QAAQ,QAC3B,oBAAoB,IAAI,QAAQ,UAAU,MAAM,KAChD;AACA;AAAA,QACF;AACA,4BAAoB,IAAI,QAAQ,YAAY,GAAG;AAC/C,YAAI,iBAAiB,oBAAoB,IAAI,QAAQ,UAAU;AAC/D,YAAI,CAAC,gBAAgB;AACnB,2BAAiB,CAAC;AAClB,8BAAoB,IAAI,QAAQ,YAAY,cAAc;AAAA,QAC5D;AAEA,aAAK,QAAQ,QAAQ,YAAY,UAAU;AAAA,UACzC,MAAM,QAAQ;AAAA,UACd,UAAU,QAAQ;AAAA,UAClB,SAAS;AAAA,QACX,CAAC,CAAC,EAAE;AAAA,UACF,CAAC,WAAW,oBAAoB,aAAa,SAAS,KAAK,MAAM;AAAA,UACjE,MAAM,oBAAoB,aAAa,SAAS,KAAK,MAAS;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,MAAY;AAC7B,YAAM,UAAU;AAChB,qBAAe;AACf,UAAI,CAAC,WAAW,UAAW;AAE3B,YAAM,QAAQ,QAAQ;AAAA,QACpB,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,MAAM;AAAA,MACR;AACA,cAAQ,YAAY,KAAK;AACzB,mBAAa,QAAQ;AACrB,UAAI,QAAQ,OAAO;AACjB,6BAAqB,MAAM,UAAU;AACrC,qBAAa,MAAM,MAAM;AAAA,MAC3B;AACA,sBAAgB,KAAK;AAAA,IACvB;AAEA,UAAM,qBAAqB,MAAY;AACrC,UAAI,CAAC,QAAQ,SAAS,OAAO,WAAW,aAAa;AACnD,mBAAW;AACX;AAAA,MACF;AACA,UAAI,eAAe,OAAW;AAC9B,mBAAa,aAAa,MAAM;AAC9B,qBAAa;AACb,mBAAW;AAAA,MACb,CAAC;AAAA,IACH;AAEA,UAAM,oBAAoB,MAAY;AACpC,iBAAW,SAAS,aAAa,OAAO,GAAG;AACzC,cAAM,SAAS;AACf,cAAM,UAAU;AAAA,MAClB;AACA,mBAAa,MAAM;AACnB,UAAI,OAAO,WAAW,aAAa;AACjC,mBAAW,SAAS,eAAgB,QAAO,aAAa,KAAK;AAAA,MAC/D;AACA,qBAAe,MAAM;AAAA,IACvB;AAEA,UAAM,eAAe,MAAY;AAC/B,UAAI,OAAO,WAAW,aAAa;AACjC,YAAI,eAAe,OAAW,aAAY,UAAU;AACpD,qBAAa;AACb,4BAAoB;AAAA,MACtB;AACA,wBAAkB;AAClB,0BAAoB,MAAM;AAC1B,0BAAoB,MAAM;AAC1B,qBAAe,QAAQ,oBAAI,IAAI;AAC/B,qBAAe,QAAQ,oBAAI,IAAI;AAC/B,kBAAY,QAAQ;AACpB,0BAAoB,2BAA2B;AAC/C,gBAAU,IAAI,iBAAiB,cAAc;AAAA,QAC3C,UAAU,MAAM;AAAA,QAChB;AAAA,QACA,UAAU,MAAM;AAAA,MAClB,CAAC;AACD,wBAAkB,MAAM;AACxB,qBAAe;AAAA,QACb,WAAW,MAAM;AAAA,QACjB,QAAQ,MAAM;AAAA,MAChB;AACA,wBAAkB;AAClB,6BAAuB,QAAQ;AAC/B,iBAAW;AAAA,IACb;AAEA,aAAS,mBAAmB,OAAkC;AAC5D,UAAI,CAAC,MAAM,WAAW,eAAe,MAAO;AAC5C,qBAAe,QAAQ;AACvB,sBAAgB;AAAA,IAClB;AAEA,UAAM,sBAAsB,MAAY;AACtC,UAAI,CAAC,WAAY;AACjB,UAAI,OAAO,WAAW,wBAAwB,YAAY;AACxD,mBAAW,oBAAoB,UAAU,kBAAkB;AAAA,MAC7D,OAAO;AACL,mBAAW,iBAAiB,kBAAkB;AAAA,MAChD;AACA,mBAAa;AAAA,IACf;AAEA,UAAM,kBAAkB,MAAY;AAClC,0BAAoB;AACpB,UACE,CAAC,QAAQ,SACT,OAAO,WAAW,eAClB,MAAM,kBAAkB,YACxB,OAAO,OAAO,eAAe,YAC7B;AACA;AAAA,MACF;AACA,mBAAa,OAAO,WAAW,oBAAoB;AACnD,UAAI,WAAW,QAAS,gBAAe,QAAQ;AAC/C,UAAI,OAAO,WAAW,qBAAqB,YAAY;AACrD,mBAAW,iBAAiB,UAAU,kBAAkB;AAAA,MAC1D,OAAO;AACL,mBAAW,cAAc,kBAAkB;AAAA,MAC7C;AAAA,IACF;AAEA,UAAM,6BAA6B,MAAY;AAC7C,YAAM,UAAU,KAAK;AACrB,UAAI,CAAC,QAAS;AACd,YAAM,MAAM,aAAa,IAAI;AAC7B,YAAM,eAAe,oBAAI,IAAiB;AAC1C,iBAAW,YAAY,QAAQ,iBAA8B,cAAc,GAAG;AAC5E,qBAAa,IAAI,QAAQ;AACzB,cAAM,UAAU,OAAO,SAAS,QAAQ,0BAA0B;AAClE,cAAM,WAAW,OAAO,SAAS,QAAQ,6BAA6B;AACtE,YAAI,CAAC,OAAO,SAAS,OAAO,KAAK,CAAC,OAAO,SAAS,QAAQ,EAAG;AAE7D,cAAM,eAAe,mBAAmB,IAAI,QAAQ;AACpD,YACE,cAAc,YAAY,WAC1B,aAAa,aAAa,UAC1B;AACA,mBAAS,MAAM,YAAY,gBAAgB,aAAa,KAAK;AAC7D;AAAA,QACF;AACA,cAAM,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,MAAM,OAAO,CAAC;AACjE,cAAM,QAAQ,OAAO,CAAC,WAAW,IAAI;AACrC,iBAAS,MAAM,YAAY,gBAAgB,KAAK;AAChD,2BAAmB,IAAI,UAAU,EAAE,OAAO,UAAU,QAAQ,CAAC;AAAA,MAC/D;AAEA,iBAAW,YAAY,gBAAgB;AACrC,YAAI,CAAC,aAAa,IAAI,QAAQ,GAAG;AAC/B,mBAAS,MAAM,eAAe,cAAc;AAC5C,cAAI,SAAS,MAAM,WAAW,EAAG,UAAS,gBAAgB,OAAO;AAAA,QACnE;AAAA,MACF;AACA,uBAAiB;AAAA,IACnB;AAEA,UAAM,2BAA2B,MAAY;AAC3C,YAAM,QAAQ,aAAa;AAC3B,YAAM,eAAe;AACrB,YAAM,UAAU,KAAK;AACrB,UACE,MAAM,SAAS,eACf,CAAC,QAAQ,SACT,CAAC,SACD,CAAC,gBACD,CAAC,SACD;AACA;AAAA,MACF;AACA,UAAI,MAAM,UAAW,wBAAuB,QAAQ;AACpD,UACE,MAAM,aACN,MAAM,KAAK,KAAK,SAAS,WAAW,KACpC,CAAC,aAAa,4BACd,QAAQ,cAAc,0BAA0B,MAAM,QACtD,oBAAoB,MAAM,QAC1B;AACA;AAAA,MACF;AACA,wBAAkB,MAAM;AACxB,6BAAuB,QAAQ;AAAA,IACjC;AAEA,UAAM,0BAA0B,MAAY;AAC1C,YAAM,UAAU,KAAK;AACrB,YAAM,YAAY,SAAS;AAAA,QACzB;AAAA,MACF;AACA,UAAI,CAAC,WAAW,CAAC,UAAW;AAC5B,YAAM,YAAY,CAAC,GAAG,QAAQ,cAAc,iBAAiB,yBAAyB,CAAC,EACpF;AAAA,QAAK,CAAC,cACL,UAAU,OAAO,UAAU,MAAM,CAAC,QAAQ,SAAS,SAAS;AAAA,MAC9D;AACF,UAAI,CAAC,UAAW;AAChB,yBAAmB,2BAA2B,EAAE,0BAA0B;AAC1E,mBAAa;AAAA,IACf;AAEA,UAAM,cAAc,MAAY;AAC9B,8BAAwB;AACxB,iCAA2B;AAC3B,UAAI,KAAK,MAAO,mCAAkC,KAAK,KAAK;AAC5D,+BAAyB;AAAA,IAC3B;AAEA,IAAAC;AAAA,MACE,MAAM,CAAC,MAAM,UAAU,MAAM,SAAS;AAAA,MACtC,CAAC,CAAC,QAAQ,SAAS,MAAM;AACvB,YAAI,CAAC,OAAO,WAAW,eAAe,GAAG;AACvC,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AACA,0BAAkB;AAClB,uBAAe,EAAE,WAAW,OAAO;AACnC,YAAI,aAAa,oBAAoB,QAAQ;AAC3C,4BAAkB;AAClB,iCAAuB,QAAQ;AAAA,QACjC;AACA,2BAAmB;AAAA,MACrB;AAAA,MACA,EAAE,OAAO,OAAO;AAAA,IAClB;AAEA,IAAAA;AAAA,MACE,MAAM,CAAC,MAAM,UAAU,MAAM,UAAU,MAAM,MAAM,MAAM,MAAM;AAAA,MAC/D;AAAA,MACA,EAAE,OAAO,OAAO;AAAA,IAClB;AAEA,IAAAA;AAAA,MACE,MAAM,MAAM;AAAA,MACZ,MAAM;AACJ,4BAAoB,MAAM;AAC1B,4BAAoB,MAAM;AAC1B,uBAAe,QAAQ,oBAAI,IAAI;AAC/B,cAAM,QAAQ,aAAa;AAC3B,YAAI,MAAO,sBAAqB,MAAM,UAAU;AAChD,wBAAgB,KAAK;AAAA,MACvB;AAAA,MACA,EAAE,OAAO,OAAO;AAAA,IAClB;AAEA,IAAAA;AAAA,MACE,MAAM,MAAM;AAAA,MACZ,MAAM;AACJ,wBAAgB;AAChB,cAAM,QAAQ,aAAa;AAC3B,YAAI,SAAS,CAAC,sBAAsB,EAAG,cAAa,MAAM,MAAM;AAChE,wBAAgB,KAAK;AAAA,MACvB;AAAA,MACA,EAAE,OAAO,OAAO;AAAA,IAClB;AAEA,eAAW;AAEX,cAAU,MAAM;AACd,cAAQ,QAAQ;AAChB,sBAAgB;AAChB,YAAM,QAAQ,aAAa;AAC3B,UAAI,OAAO;AACT,6BAAqB,MAAM,UAAU;AACrC,qBAAa,MAAM,MAAM;AACzB,wBAAgB,KAAK;AAAA,MACvB;AACA,WAAK,SAAS,WAAW;AAAA,IAC3B,CAAC;AAED,cAAU,WAAW;AAErB,IAAAC,iBAAgB,MAAM;AACpB,kBAAY;AACZ,0BAAoB;AACpB,UAAI,OAAO,WAAW,aAAa;AACjC,YAAI,eAAe,OAAW,aAAY,UAAU;AACpD,4BAAoB;AAAA,MACtB;AACA,wBAAkB;AAClB,0BAAoB,MAAM;AAC1B,0BAAoB,MAAM;AAAA,IAC5B,CAAC;AAED,UAAM,gBAAgB,MAAe;AACnC,YAAM,QAAQ,aAAa;AAC3B,UACE,CAAC,SACA,MAAM,SAAS,eAAe,eAAe,UAAU,WACxD;AACA,2BAAmB;AACnB,eAAO,CAAC;AAAA,MACV;AACA,YAAM,WAAW,gBAAgB;AACjC,YAAM,MAAM,KAAK,IAAI,SAAS,KAAK,YAAY,KAAK;AACpD,YAAM,eAAe,QAAQ,QAAQ,OAAO,UAAU,EAAE,IAAI,CAAC;AAC7D,yBAAmB;AACnB,aAAO,cAAc,sBAAsB;AAAA,QACzC,OAAO;AAAA,QACP,wBAAwB,MAAM,oBAAoB;AAAA,QAClD,gBAAgB,eAAe;AAAA,QAC/B,mBAAmB,aAAa;AAAA,QAChC,kBAAkB,aAAa;AAAA,QAC/B,mBAAmB,MAAM,KAAK;AAAA,QAC9B,QAAQ,eAAe;AAAA,QACvB,WAAW,sBAAsB;AAAA,QACjC;AAAA,QACA,QAAQ,MAAM;AAAA,QACd,WAAW,aAAa;AAAA,QACxB,oBAAoB,MAAM,iBAAiB,uBAAuB;AAAA,QAClE,MAAM,MAAM,KAAK;AAAA,QACjB,OAAO,MAAM,KAAK;AAAA,MACpB,CAAC,GAAG,MAAM,UAAU;AAAA,IACtB;AAEA,WAAO,MAAM;AACX,YAAM,SAAS,MAAM,SAAS,eAC1B,eAAe,UAAU,YACzB,YACA,eAAe,UAAU,SACvB,SACA;AACN,YAAM,WAAWC;AAAA,QACf;AAAA,QACA,WAAW,OAAO;AAAA,UAChB,qBAAqB;AAAA,UACrB,0BAA0B,MAAM;AAAA,UAChC,4BAA4B;AAAA,UAC5B,oCAAoC,MAAM;AAAA,UAC1C,4BAA4B,MAAM;AAAA,UAClC,2BAA2B,MAAM,WAAW,SAAY;AAAA,UACxD,KAAK;AAAA,UACL,OAAO;AAAA,YACL,2BACE,OAAO,eAAe,UAAU,SAAS,IAAI,MAAM,QAAQ,IAC3D;AAAA,YACF,2BACE,OAAO,eAAe,UAAU,SAAS,IAAI,MAAM,QAAQ,IAC3D;AAAA,UACJ;AAAA,QACF,CAAC;AAAA,QACD,cAAc;AAAA,MAChB;AACA,YAAM,YAAY,MAAM,SAAS,eAAe,QAAQ,QACpDA,GAAE,UAAU,EAAE,IAAI,OAAO,GAAGA,GAAE,OAAO;AAAA,QACnC,eAAe;AAAA,QACf,aAAa;AAAA,QACb,+BAA+B;AAAA,QAC/B,MAAM;AAAA,QACN,OAAO;AAAA,MACT,GAAG,uBAAuB,KAAK,CAAC,IAChC;AACJ,aAAOA,GAAE,UAAU,MAAM,CAAC,UAAU,SAAS,CAAC;AAAA,IAChD;AAAA,EACF;AACF,CAAC;","names":["defineComponent","h","onBeforeUnmount","ref","watch","computed","defineComponent","ref","image","watch","onBeforeUnmount","h"]}
package/dist/styles.css CHANGED
@@ -153,6 +153,8 @@
153
153
  --smoothstream-table-border-radius: 0.75rem;
154
154
  --smoothstream-table-margin-block: 0.75em;
155
155
  --smoothstream-image-margin-block: 1.5em;
156
+ --smoothstream-footnote-margin-block-start: 1.5em;
157
+ --smoothstream-footnote-border-color: var(--smoothstream-border-color);
156
158
  --smoothstream-table-header-background: color-mix(
157
159
  in srgb,
158
160
  var(--smoothstream-foreground) 3%,
@@ -279,6 +281,31 @@
279
281
  font-weight: 700;
280
282
  }
281
283
 
284
+ :where([data-smoothstream-theme="default"] [data-footnotes]) {
285
+ margin-block-start: var(--smoothstream-footnote-margin-block-start);
286
+ padding-block-start: 0.75em;
287
+ border-block-start: 1px solid var(--smoothstream-footnote-border-color);
288
+ font-size: 0.875em;
289
+ }
290
+
291
+ :where([data-smoothstream-theme="default"] [data-footnotes] > ol) {
292
+ margin-block: 0;
293
+ }
294
+
295
+ :where([data-smoothstream-theme="default"] sup:has(> [data-footnote-ref])) {
296
+ font-size: 0.75em;
297
+ }
298
+
299
+ :where([data-smoothstream-theme="default"] [data-footnote-ref]) {
300
+ font-weight: 700;
301
+ text-decoration: none;
302
+ }
303
+
304
+ :where([data-smoothstream-theme="default"] [data-footnote-backref]) {
305
+ margin-inline-start: 0.25em;
306
+ text-decoration: none;
307
+ }
308
+
282
309
  :where([data-smoothstream-theme="default"] ul > li)::marker {
283
310
  color: var(--smoothstream-bullet-color);
284
311
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smoothstream/vue",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Deterministic, paced Markdown reveal for Vue 3",
5
5
  "homepage": "https://smoothstream.ai",
6
6
  "repository": {
@@ -47,8 +47,8 @@
47
47
  "vue": "^3.5.0"
48
48
  },
49
49
  "dependencies": {
50
- "@smoothstream/core": "^0.1.3",
51
- "@smoothstream/styles": "^0.1.4",
50
+ "@smoothstream/core": "^0.1.7",
51
+ "@smoothstream/styles": "^0.1.6",
52
52
  "property-information": "^7.2.0"
53
53
  }
54
54
  }