@smoothstream/vue 0.1.4 → 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/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.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
 
@@ -185,8 +186,58 @@ var webNodeToVue = (node, components, copyContext) => {
185
186
  };
186
187
  var webNodesToVue = (nodes, components) => nodes.map((node) => webNodeToVue(node, components));
187
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
+ }
235
+ }
236
+ };
237
+
188
238
  // src/Smoothstream.ts
189
239
  var COMPLETION_ANNOUNCEMENT = "Content ready.";
240
+ var nextClientFootnoteInstance = 0;
190
241
  var REDUCED_MOTION_QUERY = "(prefers-reduced-motion: reduce)";
191
242
  var PHASE_SELECTOR = "[data-smoothstream-animation-start]";
192
243
  var PHASE_PROPERTY = "--smoothstream-animation-delay";
@@ -252,6 +303,7 @@ var Smoothstream = defineComponent2({
252
303
  }
253
304
  },
254
305
  setup(props, { attrs }) {
306
+ let footnoteIdPrefix = `smoothstream-${useId()}-`;
255
307
  const root = ref2(null);
256
308
  const mounted = ref2(false);
257
309
  const motionDisabled = ref2(props.reducedMotion === "always");
@@ -269,6 +321,7 @@ var Smoothstream = defineComponent2({
269
321
  const completionAnnouncement = ref2("");
270
322
  let session = new StreamingSession(browserClock, {
271
323
  duration: props.duration,
324
+ footnoteIdPrefix,
272
325
  interval: props.interval
273
326
  });
274
327
  let presentationCache = createWebPresentationCache();
@@ -491,6 +544,7 @@ var Smoothstream = defineComponent2({
491
544
  presentationCache = createWebPresentationCache();
492
545
  session = new StreamingSession(browserClock, {
493
546
  duration: props.duration,
547
+ footnoteIdPrefix,
494
548
  interval: props.interval
495
549
  });
496
550
  requestedSource = props.markdown;
@@ -571,8 +625,23 @@ var Smoothstream = defineComponent2({
571
625
  announcedSource = input.source;
572
626
  completionAnnouncement.value = COMPLETION_ANNOUNCEMENT;
573
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
+ };
574
641
  const afterRender = () => {
642
+ ensureUniqueFootnoteIds();
575
643
  synchronizeAnimationPhases();
644
+ if (root.value) synchronizeInlineCodeReservations(root.value);
576
645
  publishCompletionIfReady();
577
646
  };
578
647
  watch2(
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 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 watch,\n type PropType,\n type VNode,\n} from \"vue\";\nimport { webNodesToVue } from \"./render-web\";\nimport type {\n SmoothstreamMode,\n SmoothstreamComponents,\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 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 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 }), 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"],"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":"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","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.4",
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
  }