@dxos/react-ui-markdown 0.8.4-main.cb12b3f963 → 0.8.4-main.dfabb4ec29

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.
@@ -405,14 +405,12 @@ var MarkdownStream = /* @__PURE__ */ forwardRef(({ classNames, debug, content, o
405
405
  view
406
406
  ]);
407
407
  return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("div", {
408
- role: "none",
409
408
  className: mx2("dx-container", classNames),
410
409
  ref: parentRef
411
410
  }), /* @__PURE__ */ React2.createElement(ErrorBoundary, {
412
411
  name: "markdown-stream"
413
412
  }, widgets.map(({ Component, root, id, props }) => /* @__PURE__ */ React2.createElement("div", {
414
- key: id,
415
- role: "none"
413
+ key: id
416
414
  }, /* @__PURE__ */ createPortal(/* @__PURE__ */ React2.createElement(Component, {
417
415
  view,
418
416
  ...props
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/MarkdownBlock/MarkdownBlock.tsx", "../../../src/MarkdownStream/stream.ts", "../../../src/MarkdownStream/testing/testing.ts", "../../../src/MarkdownStream/MarkdownStream.tsx", "../../../src/MarkdownStream/footer.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type PropsWithChildren } from 'react';\nimport ReactMarkdown, { type Options as ReactMarkdownOptions } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport { mx } from '@dxos/ui-theme';\n\nexport type MarkdownBlockProps = ThemedClassName<\n PropsWithChildren<{\n content?: string;\n components?: ReactMarkdownOptions['components'];\n }>\n>;\n\n/**\n * Transforms markdown text into react elements.\n * https://github.com/remarkjs/react-markdown\n * markdown -> remark -> [mdast -> remark plugins] -> [hast -> rehype plugins] -> components -> react elements.\n * Consider using @dxos/react-ui-editor.\n */\nexport const MarkdownBlock = ({ classNames, children, components, content = '' }: MarkdownBlockProps) => {\n return (\n <div className={mx(classNames)}>\n <ReactMarkdown remarkPlugins={[remarkGfm]} skipHtml components={{ ...defaultComponents, ...components }}>\n {content}\n </ReactMarkdown>\n {children}\n </div>\n );\n};\n\nconst defaultComponents: ReactMarkdownOptions['components'] = {\n h1: ({ children }) => {\n return <h1 className='pt-1 pb-1 text-accent-text text-xl'>{children}</h1>;\n },\n h2: ({ children }) => {\n return <h2 className='pt-1 pb-1 text-accent-text text-lg'>{children}</h2>;\n },\n h3: ({ children }) => {\n return <h3 className='pt-1 pb-1 text-accent-text text-base'>{children}</h3>;\n },\n blockquote: ({ children, ...props }) => (\n <blockquote className='my-2 py-2 ps-4 border-l-4 border-accent-text text-accent-text' {...props}>\n {children}\n </blockquote>\n ),\n p: ({ children }) => {\n return <div className='pt-1 pb-1'>{children}</div>;\n },\n a: ({ children, href, ...props }) => (\n <a\n href={href}\n className='text-primary-500 hover:text-primary-500' // TODO(burdon): Use link token.\n target='_blank'\n rel='noopener noreferrer'\n {...props}\n >\n {children}\n </a>\n ),\n ol: ({ children, ...props }) => (\n <ol className='pt-1 pb-1 ps-6 leading-tight list-decimal' {...props}>\n {children}\n </ol>\n ),\n ul: ({ children, ...props }) => (\n <ul className='pt-1 pb-1 ps-6 leading-tight list-disc' {...props}>\n {children}\n </ul>\n ),\n li: ({ children, ...props }) => (\n <li className='' {...props}>\n {children}\n </li>\n ),\n pre: ({ children }) => children,\n code: ({ children, className, node }) => {\n const [, language] = /language-(\\w+)/.exec(className || '') || [];\n const inline = !className && node?.position?.start.line === node?.position?.end.line;\n if (inline) {\n return <code className='rounded-xs bg-group-surface px-1 py-0.5 text-sm text-info-text'>{children}</code>;\n }\n\n return (\n <SyntaxHighlighter\n language={language}\n classNames='mt-2 mb-2 p-2 border border-separator rounded-xs text-sm bg-group-surface'\n copyButton\n PreTag='pre'\n >\n {children}\n </SyntaxHighlighter>\n );\n },\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Stream from 'effect/Stream';\n\nimport { Obj } from '@dxos/echo';\n\nexport const renderObjectLink = (obj: Obj.Unknown, block?: boolean) =>\n `${block ? '!' : ''}[${Obj.getLabel(obj)}](${Obj.getDXN(obj).toString()})`;\n\nexport type StreamerOptions = {\n /**\n * How to subdivide plain-text spans before emitting them downstream.\n * - `'span'` (default) — keep entire spans intact; one CM dispatch per chunk that arrived at the source.\n * - `'word'` — split text spans at whitespace boundaries (whitespace runs become their own tokens).\n * - `'character'` — split text spans into individual characters.\n * XML/HTML fragments (`<tag>…</tag>`, self-closing tags, hyphenated custom elements) are always\n * emitted as one token regardless of `chunkSize`, otherwise widget mounting would see partial markup.\n */\n chunkSize?: 'character' | 'word' | 'span';\n /**\n * Inter-token delay in ms. Default `0`. Useful for slowing down rapid bursts so the\n * downstream renderer (CodeMirror) can show a visible streaming cadence even when the\n * source emits large chunks at once.\n */\n delayMs?: number;\n};\n\n/**\n * Streams tokens to the consumer, keeping XML/HTML fragments intact.\n *\n * The cadence is controlled by `options.chunkSize`. `'span'` (default) preserves the\n * one-token-per-source-chunk behaviour the function had originally. Use `'word'` or\n * `'character'` to decouple the visible cadence from the source's chunk size — useful when\n * the AI service emits large partial blocks but you want a smoother typewriter effect.\n */\nexport const createStreamer = (\n source: Stream.Stream<string>,\n { chunkSize = 'span', delayMs = 0 }: StreamerOptions = {},\n) => {\n const subdivide =\n chunkSize === 'span'\n ? (token: string) => [token]\n : (token: string) => (isXmlFragment(token) ? [token] : splitTextSpan(token, chunkSize));\n\n let stream: Stream.Stream<string> = source.pipe(\n Stream.flatMap((chunk) => Stream.fromIterable(splitFragments(chunk).flatMap(subdivide))),\n );\n if (delayMs > 0) {\n stream = stream.pipe(Stream.tap(() => Effect.sleep(`${delayMs} millis`)));\n }\n return stream;\n};\n\n/** A token starts with `<` if and only if it is an XML/HTML fragment produced by `splitFragments`. */\nconst isXmlFragment = (token: string): boolean => token.startsWith('<');\n\n/**\n * Subdivide a non-XML text span into smaller tokens. `'word'` splits into runs of non-whitespace\n * and runs of whitespace as separate tokens (so the renderer can display whitespace cadence too).\n */\nconst splitTextSpan = (span: string, chunkSize: 'character' | 'word'): string[] => {\n if (chunkSize === 'character') {\n return [...span];\n }\n return span.match(/\\s+|\\S+/g) ?? [span];\n};\n\n/** Matches opening tag names, including custom elements with hyphens (e.g. dom-widget). */\nconst OPENING_TAG_NAME = /^<([a-zA-Z][\\w-]*)(?:\\s[^>]*)?>/;\n\n/**\n * Splits text into chunks, preserving XML/HTML fragments.\n */\nexport const splitFragments = (text: string): string[] => {\n // First tokenize with tags to get tags as complete tokens.\n const initialTokens = splitSpans(text);\n const tokens: string[] = [];\n\n let i = 0;\n while (i < initialTokens.length) {\n const token = initialTokens[i];\n\n // Check if this is an opening tag.\n if (token.startsWith('<') && !token.startsWith('</') && !token.endsWith('/>')) {\n const tagMatch = token.match(OPENING_TAG_NAME);\n if (tagMatch) {\n const tagName = tagMatch[1];\n const closingTag = `</${tagName}>`;\n\n // Collect tokens until we find the closing tag.\n let fragment = token;\n let foundClosing = false;\n let j = i + 1;\n while (j < initialTokens.length) {\n fragment += initialTokens[j];\n if (initialTokens[j] === closingTag) {\n foundClosing = true;\n break;\n }\n j++;\n }\n\n if (foundClosing) {\n // Return the complete element as one token.\n tokens.push(fragment);\n i = j + 1;\n } else {\n // No closing tag found, just add the opening tag.\n tokens.push(token);\n i++;\n }\n } else {\n // Not a valid opening tag.\n tokens.push(token);\n i++;\n }\n } else {\n // Not an opening tag (could be closing tag, self-closing, or regular character).\n tokens.push(token);\n i++;\n }\n }\n\n return tokens;\n};\n\n// TODO(burdon): Split into paragraphs and tags.\n// export const tokenizeWithTags = (text: string): string[] => {\n// const tokens: string[] = [];\n// let i = 0;\n// while (i < text.length) {\n// if (text[i] === '<') {\n// // Find the closing bracket.\n// const closeIndex = text.indexOf('>', i);\n// if (closeIndex !== -1) {\n// // Include the complete tag.\n// tokens.push(text.slice(i, closeIndex + 1));\n// i = closeIndex + 1;\n// } else {\n// // No closing bracket found, return the entire remaining fragment.\n// tokens.push(text.slice(i));\n// break;\n// }\n// } else {\n// // Regular character.\n// tokens.push(text[i]);\n// i++;\n// }\n// }\n// return tokens;\n// };\n\nexport const splitSpans = (text: string): string[] => {\n const spans: string[] = [];\n let currentText = '';\n\n let i = 0;\n while (i < text.length) {\n if (text[i] === '<') {\n // If we have accumulated text, split it into sentences and push them.\n if (currentText) {\n // const sentences = splitSentences(currentText);\n // spans.push(...sentences);\n spans.push(currentText);\n currentText = '';\n }\n\n // Find the closing bracket.\n const closeIndex = text.indexOf('>', i);\n if (closeIndex !== -1) {\n // Include the complete tag.\n spans.push(text.slice(i, closeIndex + 1));\n i = closeIndex + 1;\n } else {\n // No closing bracket found, treat the rest as text.\n currentText = text.slice(i);\n break;\n }\n } else {\n // Accumulate regular text.\n currentText += text[i];\n i++;\n }\n }\n\n // Push any remaining text split into sentences.\n if (currentText) {\n spans.push(currentText);\n // const sentences = splitSentences(currentText);\n // spans.push(...sentences);\n }\n\n return spans;\n};\n\n/**\n * Split text into sentences, preserving the sentence-ending punctuation.\n */\nexport const splitSentences = (text: string): string[] => {\n // Match sentences ending with ., !, or ? followed by space or end of string.\n // This regex captures the sentence including its ending punctuation.\n const sentenceRegex = /[^.!?]*[.!?]+(?:\\s+|$)/g;\n const sentences: string[] = [];\n let lastIndex = 0;\n let match;\n\n while ((match = sentenceRegex.exec(text)) !== null) {\n sentences.push(match[0]);\n lastIndex = match.index + match[0].length;\n }\n\n // If there's remaining text that doesn't end with punctuation, include it.\n if (lastIndex < text.length) {\n const remaining = text.slice(lastIndex);\n if (remaining) {\n sentences.push(remaining);\n }\n }\n\n // If no sentences were found, return the original text.\n if (sentences.length === 0 && text) {\n sentences.push(text);\n }\n\n return sentences;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\n/**\n * Options for the streaming text generator.\n */\nexport type TextStreamOptions = {\n /** Delay between chunks in ms. */\n chunkDelay?: number;\n /** Variance in timing (0-1). */\n variance?: number;\n /** Number of words per chunk. */\n wordsPerChunk?: number;\n};\n\n/**\n * Simulates word-by-word streaming (more natural for LLMs).\n */\nexport async function* textStream(\n text: string,\n options: TextStreamOptions = {},\n): AsyncGenerator<string, void, unknown> {\n const { chunkDelay = 100, variance = 0.3, wordsPerChunk = 3 } = options;\n\n // Split into words while preserving whitespace.\n const words = text.match(/\\S+|\\s+/g) || [];\n\n let i = 0;\n while (i < words.length) {\n // Collect multiple words for this chunk.\n const chunkWords: string[] = [];\n\n // Add words up to wordsPerChunk (counting only non-whitespace as words).\n let wordCount = 0;\n while (i < words.length && wordCount < wordsPerChunk) {\n const word = words[i];\n chunkWords.push(word);\n\n // Only count non-whitespace as words.\n if (word.trim()) {\n wordCount++;\n }\n i++;\n }\n\n // Yield the chunk.\n const chunk = chunkWords.join('');\n yield chunk;\n\n // Calculate delay based on chunk length.\n const varianceMultiplier = 1 + (Math.random() - 0.5) * variance * 2;\n const delay = chunkDelay * varianceMultiplier;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorSelection, type Extension, Transaction } from '@codemirror/state';\nimport { type EditorView } from '@codemirror/view';\nimport * as Effect from 'effect/Effect';\nimport * as Fiber from 'effect/Fiber';\nimport * as Queue from 'effect/Queue';\nimport * as Stream from 'effect/Stream';\nimport React, {\n forwardRef,\n type ReactNode,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type RefObject,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { addEventListener } from '@dxos/async';\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { ErrorBoundary, type ThemedClassName, useDynamicRef, useStateWithRef, useThemeContext } from '@dxos/react-ui';\nimport { useTextEditor, type UseTextEditor } from '@dxos/react-ui-editor';\nimport {\n type AutoScrollProps,\n type XmlTagsOptions,\n type XmlWidgetState,\n type XmlWidgetStateManager,\n createBasicExtensions,\n createThemeExtensions,\n decorateMarkdown,\n extendedMarkdown,\n navigateNextEffect,\n navigatePreviousEffect,\n preview,\n scroller,\n scrollerLineEffect,\n fader,\n typewriter,\n typewriterBypass,\n xmlTagContextEffect,\n xmlTagResetEffect,\n xmlTagUpdateEffect,\n xmlTags,\n autoScroll,\n documentSlots,\n xmlFormatting,\n xmlBlockDecoration,\n} from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\nimport { isTruthy } from '@dxos/util';\n\nimport { setFooterVisibleEffect, footer } from './footer';\nimport { type StreamerOptions, createStreamer } from './stream';\nexport interface MarkdownStreamController extends XmlWidgetStateManager {\n get length(): number | undefined;\n focus: () => void;\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n navigateNext: () => void;\n navigatePrevious: () => void;\n setContext: (context: any) => void;\n setContent: (text: string) => Promise<void>;\n append: (text: string) => Promise<void>;\n}\n\nexport type MarkdownStreamEvent = {\n type: 'submit';\n value: string | null;\n};\n\nexport type MarkdownStreamProps = ThemedClassName<\n {\n debug?: boolean;\n\n /** Initial content. */\n content?: string;\n\n /** View options. */\n options?: {\n autoScroll?: boolean;\n typewriter?: boolean;\n cursor?: boolean;\n fader?: boolean;\n\n /**\n * Streaming cadence. See {@link StreamerOptions}.\n * Use `'word'` or `'character'` to break large source chunks into smaller CM dispatches —\n * useful when the AI service emits big partial blocks but you want a smoother typewriter\n * effect. Combine with `streamDelayMs` to add a per-token sleep.\n * Default: `'span'` (one CM dispatch per source chunk; current behaviour).\n */\n streamCadence?: StreamerOptions['chunkSize'];\n\n /**\n * Per-token delay (ms) for the streaming queue. Default `0`.\n */\n streamDelayMs?: number;\n };\n\n /**\n * Optional React subtree rendered as a CodeMirror block-widget decoration anchored at\n * `doc.length`. Scrolls with the document content (lives inside `cm-content`'s flow).\n * Visibility tracks the truthiness of the prop.\n */\n footer?: ReactNode;\n\n /**\n * Extra CodeMirror extensions appended after the built-in stack — use for keymaps or\n * other host-level behaviour (e.g. `Mod-d` to toggle debug) that should apply when the\n * document is focused.\n */\n extensions?: Extension;\n\n /** Event handler. */\n onEvent?: (event: MarkdownStreamEvent) => void;\n } & (XmlTagsOptions & AutoScrollProps)\n>;\n\n/**\n * Codemirror-based markdown editor with xml tag widtgets and streaming support.\n */\nexport const MarkdownStream = forwardRef<MarkdownStreamController | null, MarkdownStreamProps>(\n ({ classNames, debug, content, options, registry, extensions, footer, onEvent }, forwardedRef) => {\n // Store current content so that we can toggle debug mode. Default to '' so the\n // `append()` path (which does `contentRef.current += text`) doesn't concatenate\n // against `undefined` and stamp `\"undefined\"` into the transcript snapshot.\n const contentRef = useRef(content ?? '');\n\n // DOM node for the footer block widget — populated when its decoration mounts.\n const [footerRoot, setFooterRoot] = useState<HTMLElement | null>(null);\n\n // Codemirror editor.\n const { parentRef, view, viewRef, widgets } = useMarkdownStreamTextEditor(contentRef, {\n debug,\n registry,\n options,\n extensions,\n setFooterRoot: footer ? setFooterRoot : undefined,\n });\n\n // Show the status footer.\n const footerVisible = !!footer;\n useEffect(() => {\n view?.dispatch({ effects: setFooterVisibleEffect.of(footerVisible) });\n }, [view, footerVisible]);\n\n // Streaming text queue.\n const [queue, setQueue, queueRef] = useStateWithRef(Effect.runSync(Queue.unbounded<string>()));\n\n // Reset document.\n const onReset = useCallback(\n async (text: string) => {\n contentRef.current = text;\n if (!viewRef.current) {\n return;\n }\n\n // Set content and scroll to bottom.\n viewRef.current.dispatch({\n effects: [xmlTagContextEffect.of(null), xmlTagResetEffect.of(null)],\n changes: [{ from: 0, to: viewRef.current.state.doc.length, insert: text }],\n annotations: typewriterBypass.of(true),\n selection: EditorSelection.cursor(text.length),\n });\n\n // New queue.\n setQueue(Effect.runSync(Queue.unbounded<string>()));\n },\n [contentRef, viewRef, setQueue],\n );\n\n // Controller API.\n useImperativeHandle(\n forwardedRef,\n () => createMarkdownStreamController({ contentRef, viewRef, queueRef, onReset }),\n [onReset],\n );\n\n // Widget events.\n useEffect(() => {\n if (!parentRef.current) {\n return;\n }\n\n // TODO(burdon): Replace this hack with a custom event listener from widgets.\n return addEventListener(parentRef.current, 'click', (event) => {\n const button = (event.target as HTMLElement).closest('[data-action=\"submit\"]');\n if (button?.getAttribute('data-action') === 'submit') {\n onEvent?.({\n type: 'submit',\n value: button.getAttribute('data-value'),\n });\n }\n });\n }, [view, parentRef, onEvent]);\n\n // Consume queue and update document.\n useMarkdownStreamQueue(view, queue, {\n chunkSize: options?.streamCadence,\n delayMs: options?.streamDelayMs,\n });\n\n // Cleanup.\n useEffect(() => {\n return () => {\n view?.destroy();\n };\n }, [view]);\n\n return (\n <>\n {/* Markdown editor. */}\n <div role='none' className={mx('dx-container', classNames)} ref={parentRef} />\n\n {/* React widgets are rendered in portals outside of the editor. */}\n <ErrorBoundary name='markdown-stream'>\n {widgets.map(({ Component, root, id, props }) => (\n <div key={id} role='none'>\n {createPortal(<Component view={view} {...props} />, root)}\n </div>\n ))}\n {footerRoot && footerVisible && createPortal(footer, footerRoot)}\n </ErrorBoundary>\n </>\n );\n },\n);\n\ntype MarkdownStreamTextEditorParams = Pick<MarkdownStreamProps, 'debug' | 'registry' | 'options' | 'extensions'> & {\n setFooterRoot?: (el: HTMLElement | null) => void;\n};\n\ntype MarkdownStreamTextEditorResult = UseTextEditor & {\n viewRef: RefObject<EditorView | null>;\n widgets: XmlWidgetState[];\n};\n\n/**\n * Read-only markdown editor configured for streaming (theme, markdown extensions, XML widgets).\n */\nconst useMarkdownStreamTextEditor = (\n currentContent: RefObject<string | undefined>,\n { debug, registry, options, extensions: extraExtensions, setFooterRoot }: MarkdownStreamTextEditorParams,\n): MarkdownStreamTextEditorResult => {\n const { themeMode } = useThemeContext();\n\n // Active widgets.\n const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);\n\n // Editor.\n const { view, parentRef } = useTextEditor(() => {\n const content = currentContent.current;\n return {\n initialValue: content,\n selection: EditorSelection.cursor(content?.length ?? 0),\n extensions: [\n createBasicExtensions({\n lineWrapping: true,\n readOnly: true,\n }),\n createThemeExtensions({\n slots: documentSlots,\n scrollbarThin: true,\n syntaxHighlighting: true,\n themeMode,\n }),\n xmlFormatting({ skip: debug ? [] : ['prompt'] }),\n !debug &&\n [\n extendedMarkdown({ registry }),\n decorateMarkdown({\n // `dxn:` links/images are reference widgets owned by `preview()` (PreviewInlineWidget /\n // PreviewBlockWidget). Skipping them here avoids `decorateMarkdown` adding a\n // non-functional `LinkButton` anchor on top of the same node — e.g. for\n // `[DXOS](dxn:echo:BNPMIBEDJLRIILYUYZVM6GT64VWI6WPPZ:01KQ889PZBRNHAEECV0ANFAYX7)`.\n skip: (node) => (node.name === 'Link' || node.name === 'Image') && node.url.startsWith('dxn:'),\n }),\n preview(),\n // NOTE: An ancestor element must set `data-hue` so `.dx-panel` resolves to the user's\n // hue tokens (see `packages/ui/ui-theme/src/css/components/panel.css`). Tailwind picks\n // up these utility classes from this source file.\n xmlBlockDecoration({\n tag: 'prompt',\n lineClass: 'cm-prompt-line my-8',\n contentClass: 'cm-prompt-bubble dx-panel px-2 py-1.5 rounded-sm [&_*]:text-inherit!',\n hideTags: true,\n }),\n xmlTags({ registry, setWidgets, bookmarks: ['prompt'] }),\n scroller({ overScroll: 80 }),\n options?.autoScroll && autoScroll(),\n options?.typewriter &&\n typewriter({\n cursor: options?.cursor,\n streamingTags: new Set(\n Object.entries(registry ?? {})\n .filter(([, def]) => def.streaming)\n .map(([tag]) => tag),\n ),\n }),\n options?.fader && fader(),\n setFooterRoot && footer(setFooterRoot),\n ].filter(isTruthy),\n extraExtensions,\n ].filter(isTruthy),\n };\n }, [\n themeMode,\n registry,\n debug,\n options?.autoScroll,\n options?.typewriter,\n options?.cursor,\n options?.fader,\n extraExtensions,\n ]);\n\n const viewRef = useDynamicRef(view);\n return { view, viewRef, parentRef, widgets };\n};\n\n/**\n * Consumes streaming text from the queue and appends it to the editor document.\n */\nconst useMarkdownStreamQueue = (\n view: EditorView | null,\n queue: Queue.Queue<string>,\n streamerOptions?: StreamerOptions,\n) => {\n const chunkSize = streamerOptions?.chunkSize;\n const delayMs = streamerOptions?.delayMs;\n useEffect(() => {\n if (!view) {\n return;\n }\n\n // Consume queue and update document.\n const fork = Stream.fromQueue(queue).pipe(\n (source) => createStreamer(source, { chunkSize, delayMs }),\n Stream.runForEach((text) =>\n Effect.sync(() => {\n const scrollTop = view.scrollDOM.scrollTop;\n view.dispatch({\n changes: [{ from: view.state.doc.length, insert: text }],\n annotations: Transaction.remote.of(true),\n scrollIntoView: false,\n });\n\n // Prevent autoscrolling.\n requestAnimationFrame(() => {\n view.scrollDOM.scrollTop = scrollTop;\n });\n }),\n ),\n Effect.runFork,\n );\n\n return () => {\n void runAndForwardErrors(Fiber.interrupt(fork));\n };\n }, [view, queue, chunkSize, delayMs]);\n};\n\ntype MarkdownStreamControllerDeps = {\n contentRef: RefObject<string | undefined>;\n viewRef: RefObject<EditorView | null>;\n queueRef: RefObject<Queue.Queue<string>>;\n onReset: (text: string) => Promise<void>;\n};\n\n/**\n * External controller API.\n */\nconst createMarkdownStreamController = ({\n contentRef,\n viewRef,\n queueRef,\n onReset,\n}: MarkdownStreamControllerDeps): MarkdownStreamController => {\n return {\n get length() {\n return viewRef.current?.state.doc.length;\n },\n\n /** Focus the editor. */\n focus: () => {\n viewRef.current?.focus();\n },\n\n /** Scroll to bottom. */\n scrollToBottom: (behavior?: ScrollBehavior) => {\n viewRef.current?.dispatch({\n effects: scrollerLineEffect.of({ line: -1, behavior }),\n });\n },\n\n /** Navigate previous prompt. */\n navigatePrevious: () => {\n viewRef.current?.dispatch({\n effects: navigatePreviousEffect.of(),\n });\n },\n\n /** Navigate next prompt. */\n navigateNext: () => {\n viewRef.current?.dispatch({\n effects: navigateNextEffect.of(),\n });\n },\n\n /** Set the context for widgets (XML tags). */\n setContext: (context: any) => {\n viewRef.current?.dispatch({\n effects: xmlTagContextEffect.of(context),\n });\n },\n\n /** Reset document. */\n setContent: onReset,\n\n /** Append to queue (and stream). */\n append: async (text: string) => {\n contentRef.current += text;\n if (text.length) {\n // Always go through the streaming queue, even when the doc starts empty. Skipping the\n // queue in that case (via `onReset`) bypasses the `typewriter` extension's transaction filter\n // and the first chunk lands in one CM dispatch — defeating the typewriter for any\n // consumer (e.g. ChatThread) where the first delta is large because upstream batching\n // collected several streaming partials before React rendered.\n const queue = queueRef.current;\n if (queue) {\n await runAndForwardErrors(Queue.offer(queue, text));\n }\n }\n },\n\n /** Update widget state. */\n updateWidget: (id: string, value: any) => {\n viewRef.current?.dispatch({\n effects: xmlTagUpdateEffect.of({ id, value }),\n });\n },\n } satisfies MarkdownStreamController;\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, WidgetType } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\nimport { typewriterDrainingEffect } from '@dxos/ui-editor';\n\n/**\n * Host-controlled visibility intent. The footer block widget is rendered only when this is\n * `true` AND typewriter is not actively draining its typewriter buffer — the latter is observed\n * through {@link typewriterDrainingEffect}. Removing the decoration during a drip avoids the\n * scroll-measure conflict between CM's view-line model and the floating absolute child.\n */\nexport const setFooterVisibleEffect = StateEffect.define<boolean>();\n\ntype FooterState = {\n /** Host wants the footer rendered. */\n wanted: boolean;\n /** Typewriter is actively dripping into the document. */\n draining: boolean;\n decorations: DecorationSet;\n};\n\n/**\n * Renders a host-supplied React subtree as a CodeMirror block widget anchored at\n * `doc.length`. The widget lives inside the document, so it scrolls with content.\n *\n * Toggle the host-intent visibility via {@link setFooterVisibleEffect}. The widget is also\n * automatically removed while {@link typewriterDrainingEffect} reports `true` and re-mounted\n * once the typewriter's buffer drains — this prevents the block widget from interfering with CM's\n * view-line measurement during the typewriter drip.\n *\n * For pure doc edits (no visibility transition), the decoration's position is mapped\n * through the change set so insertions at the end translate the anchor without destroying\n * the widget's DOM.\n */\nexport const footer = (setRoot: (el: HTMLElement | null) => void): Extension => {\n const widget = new FooterWidget(setRoot);\n const buildSet = (length: number): DecorationSet =>\n Decoration.set([Decoration.widget({ widget, block: true, side: 1 }).range(length)]);\n\n const field = StateField.define<FooterState>({\n create: () => ({ wanted: false, draining: false, decorations: Decoration.none }),\n update: (state, tr) => {\n let { wanted, draining, decorations } = state;\n for (const effect of tr.effects) {\n if (effect.is(setFooterVisibleEffect)) {\n wanted = effect.value;\n }\n if (effect.is(typewriterDrainingEffect)) {\n draining = effect.value;\n }\n }\n\n // Also gate on the document being non-empty: there's nothing for the footer to anchor\n // below, and rendering it on a blank doc looks like detached chrome.\n const docLength = tr.state.doc.length;\n const visible = wanted && !draining && docLength > 0;\n const wasVisible = decorations.size > 0;\n if (visible !== wasVisible) {\n decorations = visible ? buildSet(docLength) : Decoration.none;\n } else if (tr.docChanged && decorations.size > 0) {\n // Position-map the existing decoration so insertions at the end translate the\n // widget anchor without destroying the DOM (`widget.eq` is identity-true).\n decorations = decorations.map(tr.changes);\n }\n\n return { wanted, draining, decorations };\n },\n provide: (f) => EditorView.decorations.from(f, (state) => state.decorations),\n });\n\n return [field];\n};\n\n/**\n * Block widget rendered at the end of the document. The DOM element is reported via\n * `setRoot` so the host React component can `createPortal` arbitrary content into it.\n */\nclass FooterWidget extends WidgetType {\n constructor(private readonly _setRoot: (el: HTMLElement | null) => void) {\n super();\n }\n\n // Singleton equality so CM keeps the same DOM element across decoration rebuilds —\n // the React subtree portaled into it is not unmounted on every doc change.\n override eq(_other: this): boolean {\n return true;\n }\n\n override ignoreEvent(): boolean {\n return true;\n }\n\n override toDOM(): HTMLElement {\n // The outer block-widget element is `position: relative` with zero flow height so it\n // does not push the document layout (autoScroll, line measurement, etc. ignore it).\n // The inner element is `position: absolute`, taking the React subtree out of flow — it\n // renders as a floating layer anchored to the doc tail without consuming space.\n const inner = Domino.of('div')\n .classNames('cm-stream-footer-content')\n .style({ position: 'absolute', left: '0', top: '0' });\n\n const el = Domino.of('div')\n .classNames('cm-stream-footer')\n .style({ position: 'relative', height: '0' })\n .append(inner);\n\n this._setRoot(inner.root);\n return el.root;\n }\n\n override destroy(): void {\n this._setRoot(null);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["React", "ReactMarkdown", "remarkGfm", "SyntaxHighlighter", "mx", "MarkdownBlock", "classNames", "children", "components", "content", "div", "className", "remarkPlugins", "skipHtml", "defaultComponents", "h1", "h2", "h3", "blockquote", "props", "p", "a", "href", "target", "rel", "ol", "ul", "li", "pre", "code", "node", "language", "exec", "inline", "position", "start", "line", "end", "copyButton", "PreTag", "Effect", "Stream", "Obj", "renderObjectLink", "obj", "block", "getLabel", "getDXN", "toString", "createStreamer", "source", "chunkSize", "delayMs", "subdivide", "token", "isXmlFragment", "splitTextSpan", "stream", "pipe", "flatMap", "chunk", "fromIterable", "splitFragments", "tap", "sleep", "startsWith", "span", "match", "OPENING_TAG_NAME", "text", "initialTokens", "splitSpans", "tokens", "i", "length", "endsWith", "tagMatch", "tagName", "closingTag", "fragment", "foundClosing", "j", "push", "spans", "currentText", "closeIndex", "indexOf", "slice", "splitSentences", "sentenceRegex", "sentences", "lastIndex", "exec", "index", "remaining", "textStream", "text", "options", "chunkDelay", "variance", "wordsPerChunk", "words", "match", "i", "length", "chunkWords", "wordCount", "word", "push", "trim", "chunk", "join", "varianceMultiplier", "Math", "random", "delay", "Promise", "resolve", "setTimeout", "EditorSelection", "Transaction", "Effect", "Fiber", "Queue", "Stream", "React", "forwardRef", "useCallback", "useEffect", "useImperativeHandle", "useRef", "useState", "createPortal", "addEventListener", "runAndForwardErrors", "ErrorBoundary", "useDynamicRef", "useStateWithRef", "useThemeContext", "useTextEditor", "createBasicExtensions", "createThemeExtensions", "decorateMarkdown", "extendedMarkdown", "navigateNextEffect", "navigatePreviousEffect", "preview", "scroller", "scrollerLineEffect", "fader", "typewriter", "typewriterBypass", "xmlTagContextEffect", "xmlTagResetEffect", "xmlTagUpdateEffect", "xmlTags", "autoScroll", "documentSlots", "xmlFormatting", "xmlBlockDecoration", "mx", "isTruthy", "StateEffect", "StateField", "Decoration", "EditorView", "WidgetType", "Domino", "typewriterDrainingEffect", "setFooterVisibleEffect", "define", "footer", "setRoot", "widget", "FooterWidget", "buildSet", "length", "set", "block", "side", "range", "field", "create", "wanted", "draining", "decorations", "none", "update", "state", "tr", "effect", "effects", "is", "value", "docLength", "doc", "visible", "wasVisible", "size", "docChanged", "map", "changes", "provide", "f", "from", "_setRoot", "eq", "_other", "ignoreEvent", "toDOM", "inner", "of", "classNames", "style", "position", "left", "top", "el", "height", "append", "root", "destroy", "MarkdownStream", "forwardRef", "classNames", "debug", "content", "options", "registry", "extensions", "footer", "onEvent", "forwardedRef", "contentRef", "useRef", "footerRoot", "setFooterRoot", "useState", "parentRef", "view", "viewRef", "widgets", "useMarkdownStreamTextEditor", "undefined", "footerVisible", "useEffect", "dispatch", "effects", "setFooterVisibleEffect", "of", "queue", "setQueue", "queueRef", "useStateWithRef", "runSync", "unbounded", "onReset", "useCallback", "text", "current", "xmlTagContextEffect", "xmlTagResetEffect", "changes", "from", "to", "state", "doc", "length", "insert", "annotations", "typewriterBypass", "selection", "EditorSelection", "cursor", "useImperativeHandle", "createMarkdownStreamController", "addEventListener", "event", "button", "target", "closest", "getAttribute", "type", "value", "useMarkdownStreamQueue", "chunkSize", "streamCadence", "delayMs", "streamDelayMs", "destroy", "React", "div", "role", "className", "mx", "ref", "ErrorBoundary", "name", "map", "Component", "root", "id", "props", "key", "createPortal", "currentContent", "extraExtensions", "themeMode", "useThemeContext", "setWidgets", "useTextEditor", "initialValue", "createBasicExtensions", "lineWrapping", "readOnly", "createThemeExtensions", "slots", "documentSlots", "scrollbarThin", "syntaxHighlighting", "xmlFormatting", "skip", "extendedMarkdown", "decorateMarkdown", "node", "url", "startsWith", "preview", "xmlBlockDecoration", "tag", "lineClass", "contentClass", "hideTags", "xmlTags", "bookmarks", "scroller", "overScroll", "autoScroll", "typewriter", "streamingTags", "Set", "Object", "entries", "filter", "def", "streaming", "fader", "isTruthy", "useDynamicRef", "streamerOptions", "fork", "fromQueue", "pipe", "source", "createStreamer", "runForEach", "sync", "scrollTop", "scrollDOM", "Transaction", "remote", "scrollIntoView", "requestAnimationFrame", "runFork", "runAndForwardErrors", "interrupt", "focus", "scrollToBottom", "behavior", "scrollerLineEffect", "line", "navigatePrevious", "navigatePreviousEffect", "navigateNext", "navigateNextEffect", "setContext", "context", "setContent", "append", "offer", "updateWidget", "xmlTagUpdateEffect"]
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type PropsWithChildren } from 'react';\nimport ReactMarkdown, { type Options as ReactMarkdownOptions } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport { mx } from '@dxos/ui-theme';\n\nexport type MarkdownBlockProps = ThemedClassName<\n PropsWithChildren<{\n content?: string;\n components?: ReactMarkdownOptions['components'];\n }>\n>;\n\n/**\n * Transforms markdown text into react elements.\n * https://github.com/remarkjs/react-markdown\n * markdown -> remark -> [mdast -> remark plugins] -> [hast -> rehype plugins] -> components -> react elements.\n * Consider using @dxos/react-ui-editor.\n */\nexport const MarkdownBlock = ({ classNames, children, components, content = '' }: MarkdownBlockProps) => {\n return (\n <div className={mx(classNames)}>\n <ReactMarkdown remarkPlugins={[remarkGfm]} skipHtml components={{ ...defaultComponents, ...components }}>\n {content}\n </ReactMarkdown>\n {children}\n </div>\n );\n};\n\nconst defaultComponents: ReactMarkdownOptions['components'] = {\n h1: ({ children }) => {\n return <h1 className='pt-1 pb-1 text-accent-text text-xl'>{children}</h1>;\n },\n h2: ({ children }) => {\n return <h2 className='pt-1 pb-1 text-accent-text text-lg'>{children}</h2>;\n },\n h3: ({ children }) => {\n return <h3 className='pt-1 pb-1 text-accent-text text-base'>{children}</h3>;\n },\n blockquote: ({ children, ...props }) => (\n <blockquote className='my-2 py-2 ps-4 border-l-4 border-accent-text text-accent-text' {...props}>\n {children}\n </blockquote>\n ),\n p: ({ children }) => {\n return <div className='pt-1 pb-1'>{children}</div>;\n },\n a: ({ children, href, ...props }) => (\n <a\n href={href}\n className='text-primary-500 hover:text-primary-500' // TODO(burdon): Use link token.\n target='_blank'\n rel='noopener noreferrer'\n {...props}\n >\n {children}\n </a>\n ),\n ol: ({ children, ...props }) => (\n <ol className='pt-1 pb-1 ps-6 leading-tight list-decimal' {...props}>\n {children}\n </ol>\n ),\n ul: ({ children, ...props }) => (\n <ul className='pt-1 pb-1 ps-6 leading-tight list-disc' {...props}>\n {children}\n </ul>\n ),\n li: ({ children, ...props }) => (\n <li className='' {...props}>\n {children}\n </li>\n ),\n pre: ({ children }) => children,\n code: ({ children, className, node }) => {\n const [, language] = /language-(\\w+)/.exec(className || '') || [];\n const inline = !className && node?.position?.start.line === node?.position?.end.line;\n if (inline) {\n return <code className='rounded-xs bg-group-surface px-1 py-0.5 text-sm text-info-text'>{children}</code>;\n }\n\n return (\n <SyntaxHighlighter\n language={language}\n classNames='mt-2 mb-2 p-2 border border-separator rounded-xs text-sm bg-group-surface'\n copyButton\n PreTag='pre'\n >\n {children}\n </SyntaxHighlighter>\n );\n },\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Stream from 'effect/Stream';\n\nimport { Obj } from '@dxos/echo';\n\nexport const renderObjectLink = (obj: Obj.Unknown, block?: boolean) =>\n `${block ? '!' : ''}[${Obj.getLabel(obj)}](${Obj.getDXN(obj).toString()})`;\n\nexport type StreamerOptions = {\n /**\n * How to subdivide plain-text spans before emitting them downstream.\n * - `'span'` (default) — keep entire spans intact; one CM dispatch per chunk that arrived at the source.\n * - `'word'` — split text spans at whitespace boundaries (whitespace runs become their own tokens).\n * - `'character'` — split text spans into individual characters.\n * XML/HTML fragments (`<tag>…</tag>`, self-closing tags, hyphenated custom elements) are always\n * emitted as one token regardless of `chunkSize`, otherwise widget mounting would see partial markup.\n */\n chunkSize?: 'character' | 'word' | 'span';\n /**\n * Inter-token delay in ms. Default `0`. Useful for slowing down rapid bursts so the\n * downstream renderer (CodeMirror) can show a visible streaming cadence even when the\n * source emits large chunks at once.\n */\n delayMs?: number;\n};\n\n/**\n * Streams tokens to the consumer, keeping XML/HTML fragments intact.\n *\n * The cadence is controlled by `options.chunkSize`. `'span'` (default) preserves the\n * one-token-per-source-chunk behaviour the function had originally. Use `'word'` or\n * `'character'` to decouple the visible cadence from the source's chunk size — useful when\n * the AI service emits large partial blocks but you want a smoother typewriter effect.\n */\nexport const createStreamer = (\n source: Stream.Stream<string>,\n { chunkSize = 'span', delayMs = 0 }: StreamerOptions = {},\n) => {\n const subdivide =\n chunkSize === 'span'\n ? (token: string) => [token]\n : (token: string) => (isXmlFragment(token) ? [token] : splitTextSpan(token, chunkSize));\n\n let stream: Stream.Stream<string> = source.pipe(\n Stream.flatMap((chunk) => Stream.fromIterable(splitFragments(chunk).flatMap(subdivide))),\n );\n if (delayMs > 0) {\n stream = stream.pipe(Stream.tap(() => Effect.sleep(`${delayMs} millis`)));\n }\n return stream;\n};\n\n/** A token starts with `<` if and only if it is an XML/HTML fragment produced by `splitFragments`. */\nconst isXmlFragment = (token: string): boolean => token.startsWith('<');\n\n/**\n * Subdivide a non-XML text span into smaller tokens. `'word'` splits into runs of non-whitespace\n * and runs of whitespace as separate tokens (so the renderer can display whitespace cadence too).\n */\nconst splitTextSpan = (span: string, chunkSize: 'character' | 'word'): string[] => {\n if (chunkSize === 'character') {\n return [...span];\n }\n return span.match(/\\s+|\\S+/g) ?? [span];\n};\n\n/** Matches opening tag names, including custom elements with hyphens (e.g. dom-widget). */\nconst OPENING_TAG_NAME = /^<([a-zA-Z][\\w-]*)(?:\\s[^>]*)?>/;\n\n/**\n * Splits text into chunks, preserving XML/HTML fragments.\n */\nexport const splitFragments = (text: string): string[] => {\n // First tokenize with tags to get tags as complete tokens.\n const initialTokens = splitSpans(text);\n const tokens: string[] = [];\n\n let i = 0;\n while (i < initialTokens.length) {\n const token = initialTokens[i];\n\n // Check if this is an opening tag.\n if (token.startsWith('<') && !token.startsWith('</') && !token.endsWith('/>')) {\n const tagMatch = token.match(OPENING_TAG_NAME);\n if (tagMatch) {\n const tagName = tagMatch[1];\n const closingTag = `</${tagName}>`;\n\n // Collect tokens until we find the closing tag.\n let fragment = token;\n let foundClosing = false;\n let j = i + 1;\n while (j < initialTokens.length) {\n fragment += initialTokens[j];\n if (initialTokens[j] === closingTag) {\n foundClosing = true;\n break;\n }\n j++;\n }\n\n if (foundClosing) {\n // Return the complete element as one token.\n tokens.push(fragment);\n i = j + 1;\n } else {\n // No closing tag found, just add the opening tag.\n tokens.push(token);\n i++;\n }\n } else {\n // Not a valid opening tag.\n tokens.push(token);\n i++;\n }\n } else {\n // Not an opening tag (could be closing tag, self-closing, or regular character).\n tokens.push(token);\n i++;\n }\n }\n\n return tokens;\n};\n\n// TODO(burdon): Split into paragraphs and tags.\n// export const tokenizeWithTags = (text: string): string[] => {\n// const tokens: string[] = [];\n// let i = 0;\n// while (i < text.length) {\n// if (text[i] === '<') {\n// // Find the closing bracket.\n// const closeIndex = text.indexOf('>', i);\n// if (closeIndex !== -1) {\n// // Include the complete tag.\n// tokens.push(text.slice(i, closeIndex + 1));\n// i = closeIndex + 1;\n// } else {\n// // No closing bracket found, return the entire remaining fragment.\n// tokens.push(text.slice(i));\n// break;\n// }\n// } else {\n// // Regular character.\n// tokens.push(text[i]);\n// i++;\n// }\n// }\n// return tokens;\n// };\n\nexport const splitSpans = (text: string): string[] => {\n const spans: string[] = [];\n let currentText = '';\n\n let i = 0;\n while (i < text.length) {\n if (text[i] === '<') {\n // If we have accumulated text, split it into sentences and push them.\n if (currentText) {\n // const sentences = splitSentences(currentText);\n // spans.push(...sentences);\n spans.push(currentText);\n currentText = '';\n }\n\n // Find the closing bracket.\n const closeIndex = text.indexOf('>', i);\n if (closeIndex !== -1) {\n // Include the complete tag.\n spans.push(text.slice(i, closeIndex + 1));\n i = closeIndex + 1;\n } else {\n // No closing bracket found, treat the rest as text.\n currentText = text.slice(i);\n break;\n }\n } else {\n // Accumulate regular text.\n currentText += text[i];\n i++;\n }\n }\n\n // Push any remaining text split into sentences.\n if (currentText) {\n spans.push(currentText);\n // const sentences = splitSentences(currentText);\n // spans.push(...sentences);\n }\n\n return spans;\n};\n\n/**\n * Split text into sentences, preserving the sentence-ending punctuation.\n */\nexport const splitSentences = (text: string): string[] => {\n // Match sentences ending with ., !, or ? followed by space or end of string.\n // This regex captures the sentence including its ending punctuation.\n const sentenceRegex = /[^.!?]*[.!?]+(?:\\s+|$)/g;\n const sentences: string[] = [];\n let lastIndex = 0;\n let match;\n\n while ((match = sentenceRegex.exec(text)) !== null) {\n sentences.push(match[0]);\n lastIndex = match.index + match[0].length;\n }\n\n // If there's remaining text that doesn't end with punctuation, include it.\n if (lastIndex < text.length) {\n const remaining = text.slice(lastIndex);\n if (remaining) {\n sentences.push(remaining);\n }\n }\n\n // If no sentences were found, return the original text.\n if (sentences.length === 0 && text) {\n sentences.push(text);\n }\n\n return sentences;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\n/**\n * Options for the streaming text generator.\n */\nexport type TextStreamOptions = {\n /** Delay between chunks in ms. */\n chunkDelay?: number;\n /** Variance in timing (0-1). */\n variance?: number;\n /** Number of words per chunk. */\n wordsPerChunk?: number;\n};\n\n/**\n * Simulates word-by-word streaming (more natural for LLMs).\n */\nexport async function* textStream(\n text: string,\n options: TextStreamOptions = {},\n): AsyncGenerator<string, void, unknown> {\n const { chunkDelay = 100, variance = 0.3, wordsPerChunk = 3 } = options;\n\n // Split into words while preserving whitespace.\n const words = text.match(/\\S+|\\s+/g) || [];\n\n let i = 0;\n while (i < words.length) {\n // Collect multiple words for this chunk.\n const chunkWords: string[] = [];\n\n // Add words up to wordsPerChunk (counting only non-whitespace as words).\n let wordCount = 0;\n while (i < words.length && wordCount < wordsPerChunk) {\n const word = words[i];\n chunkWords.push(word);\n\n // Only count non-whitespace as words.\n if (word.trim()) {\n wordCount++;\n }\n i++;\n }\n\n // Yield the chunk.\n const chunk = chunkWords.join('');\n yield chunk;\n\n // Calculate delay based on chunk length.\n const varianceMultiplier = 1 + (Math.random() - 0.5) * variance * 2;\n const delay = chunkDelay * varianceMultiplier;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorSelection, type Extension, Transaction } from '@codemirror/state';\nimport { type EditorView } from '@codemirror/view';\nimport * as Effect from 'effect/Effect';\nimport * as Fiber from 'effect/Fiber';\nimport * as Queue from 'effect/Queue';\nimport * as Stream from 'effect/Stream';\nimport React, {\n forwardRef,\n type ReactNode,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type RefObject,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { addEventListener } from '@dxos/async';\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { ErrorBoundary, type ThemedClassName, useDynamicRef, useStateWithRef, useThemeContext } from '@dxos/react-ui';\nimport { useTextEditor, type UseTextEditor } from '@dxos/react-ui-editor';\nimport {\n type AutoScrollProps,\n type XmlTagsOptions,\n type XmlWidgetState,\n type XmlWidgetStateManager,\n createBasicExtensions,\n createThemeExtensions,\n decorateMarkdown,\n extendedMarkdown,\n navigateNextEffect,\n navigatePreviousEffect,\n preview,\n scroller,\n scrollerLineEffect,\n fader,\n typewriter,\n typewriterBypass,\n xmlTagContextEffect,\n xmlTagResetEffect,\n xmlTagUpdateEffect,\n xmlTags,\n autoScroll,\n documentSlots,\n xmlFormatting,\n xmlBlockDecoration,\n} from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\nimport { isTruthy } from '@dxos/util';\n\nimport { setFooterVisibleEffect, footer } from './footer';\nimport { type StreamerOptions, createStreamer } from './stream';\nexport interface MarkdownStreamController extends XmlWidgetStateManager {\n get length(): number | undefined;\n focus: () => void;\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n navigateNext: () => void;\n navigatePrevious: () => void;\n setContext: (context: any) => void;\n setContent: (text: string) => Promise<void>;\n append: (text: string) => Promise<void>;\n}\n\nexport type MarkdownStreamEvent = {\n type: 'submit';\n value: string | null;\n};\n\nexport type MarkdownStreamProps = ThemedClassName<\n {\n debug?: boolean;\n\n /** Initial content. */\n content?: string;\n\n /** View options. */\n options?: {\n autoScroll?: boolean;\n typewriter?: boolean;\n cursor?: boolean;\n fader?: boolean;\n\n /**\n * Streaming cadence. See {@link StreamerOptions}.\n * Use `'word'` or `'character'` to break large source chunks into smaller CM dispatches —\n * useful when the AI service emits big partial blocks but you want a smoother typewriter\n * effect. Combine with `streamDelayMs` to add a per-token sleep.\n * Default: `'span'` (one CM dispatch per source chunk; current behaviour).\n */\n streamCadence?: StreamerOptions['chunkSize'];\n\n /**\n * Per-token delay (ms) for the streaming queue. Default `0`.\n */\n streamDelayMs?: number;\n };\n\n /**\n * Optional React subtree rendered as a CodeMirror block-widget decoration anchored at\n * `doc.length`. Scrolls with the document content (lives inside `cm-content`'s flow).\n * Visibility tracks the truthiness of the prop.\n */\n footer?: ReactNode;\n\n /**\n * Extra CodeMirror extensions appended after the built-in stack — use for keymaps or\n * other host-level behaviour (e.g. `Mod-d` to toggle debug) that should apply when the\n * document is focused.\n */\n extensions?: Extension;\n\n /** Event handler. */\n onEvent?: (event: MarkdownStreamEvent) => void;\n } & (XmlTagsOptions & AutoScrollProps)\n>;\n\n/**\n * Codemirror-based markdown editor with xml tag widtgets and streaming support.\n */\nexport const MarkdownStream = forwardRef<MarkdownStreamController | null, MarkdownStreamProps>(\n ({ classNames, debug, content, options, registry, extensions, footer, onEvent }, forwardedRef) => {\n // Store current content so that we can toggle debug mode. Default to '' so the\n // `append()` path (which does `contentRef.current += text`) doesn't concatenate\n // against `undefined` and stamp `\"undefined\"` into the transcript snapshot.\n const contentRef = useRef(content ?? '');\n\n // DOM node for the footer block widget — populated when its decoration mounts.\n const [footerRoot, setFooterRoot] = useState<HTMLElement | null>(null);\n\n // Codemirror editor.\n const { parentRef, view, viewRef, widgets } = useMarkdownStreamTextEditor(contentRef, {\n debug,\n registry,\n options,\n extensions,\n setFooterRoot: footer ? setFooterRoot : undefined,\n });\n\n // Show the status footer.\n const footerVisible = !!footer;\n useEffect(() => {\n view?.dispatch({ effects: setFooterVisibleEffect.of(footerVisible) });\n }, [view, footerVisible]);\n\n // Streaming text queue.\n const [queue, setQueue, queueRef] = useStateWithRef(Effect.runSync(Queue.unbounded<string>()));\n\n // Reset document.\n const onReset = useCallback(\n async (text: string) => {\n contentRef.current = text;\n if (!viewRef.current) {\n return;\n }\n\n // Set content and scroll to bottom.\n viewRef.current.dispatch({\n effects: [xmlTagContextEffect.of(null), xmlTagResetEffect.of(null)],\n changes: [{ from: 0, to: viewRef.current.state.doc.length, insert: text }],\n annotations: typewriterBypass.of(true),\n selection: EditorSelection.cursor(text.length),\n });\n\n // New queue.\n setQueue(Effect.runSync(Queue.unbounded<string>()));\n },\n [contentRef, viewRef, setQueue],\n );\n\n // Controller API.\n useImperativeHandle(\n forwardedRef,\n () => createMarkdownStreamController({ contentRef, viewRef, queueRef, onReset }),\n [onReset],\n );\n\n // Widget events.\n useEffect(() => {\n if (!parentRef.current) {\n return;\n }\n\n // TODO(burdon): Replace this hack with a custom event listener from widgets.\n return addEventListener(parentRef.current, 'click', (event) => {\n const button = (event.target as HTMLElement).closest('[data-action=\"submit\"]');\n if (button?.getAttribute('data-action') === 'submit') {\n onEvent?.({\n type: 'submit',\n value: button.getAttribute('data-value'),\n });\n }\n });\n }, [view, parentRef, onEvent]);\n\n // Consume queue and update document.\n useMarkdownStreamQueue(view, queue, {\n chunkSize: options?.streamCadence,\n delayMs: options?.streamDelayMs,\n });\n\n // Cleanup.\n useEffect(() => {\n return () => {\n view?.destroy();\n };\n }, [view]);\n\n return (\n <>\n {/* Markdown editor. */}\n <div className={mx('dx-container', classNames)} ref={parentRef} />\n\n {/* React widgets are rendered in portals outside of the editor. */}\n <ErrorBoundary name='markdown-stream'>\n {widgets.map(({ Component, root, id, props }) => (\n <div key={id}>{createPortal(<Component view={view} {...props} />, root)}</div>\n ))}\n {footerRoot && footerVisible && createPortal(footer, footerRoot)}\n </ErrorBoundary>\n </>\n );\n },\n);\n\ntype MarkdownStreamTextEditorParams = Pick<MarkdownStreamProps, 'debug' | 'registry' | 'options' | 'extensions'> & {\n setFooterRoot?: (el: HTMLElement | null) => void;\n};\n\ntype MarkdownStreamTextEditorResult = UseTextEditor & {\n viewRef: RefObject<EditorView | null>;\n widgets: XmlWidgetState[];\n};\n\n/**\n * Read-only markdown editor configured for streaming (theme, markdown extensions, XML widgets).\n */\nconst useMarkdownStreamTextEditor = (\n currentContent: RefObject<string | undefined>,\n { debug, registry, options, extensions: extraExtensions, setFooterRoot }: MarkdownStreamTextEditorParams,\n): MarkdownStreamTextEditorResult => {\n const { themeMode } = useThemeContext();\n\n // Active widgets.\n const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);\n\n // Editor.\n const { view, parentRef } = useTextEditor(() => {\n const content = currentContent.current;\n return {\n initialValue: content,\n selection: EditorSelection.cursor(content?.length ?? 0),\n extensions: [\n createBasicExtensions({\n lineWrapping: true,\n readOnly: true,\n }),\n createThemeExtensions({\n slots: documentSlots,\n scrollbarThin: true,\n syntaxHighlighting: true,\n themeMode,\n }),\n xmlFormatting({ skip: debug ? [] : ['prompt'] }),\n !debug &&\n [\n extendedMarkdown({ registry }),\n decorateMarkdown({\n // `dxn:` links/images are reference widgets owned by `preview()` (PreviewInlineWidget /\n // PreviewBlockWidget). Skipping them here avoids `decorateMarkdown` adding a\n // non-functional `LinkButton` anchor on top of the same node — e.g. for\n // `[DXOS](dxn:echo:BNPMIBEDJLRIILYUYZVM6GT64VWI6WPPZ:01KQ889PZBRNHAEECV0ANFAYX7)`.\n skip: (node) => (node.name === 'Link' || node.name === 'Image') && node.url.startsWith('dxn:'),\n }),\n preview(),\n // NOTE: An ancestor element must set `data-hue` so `.dx-panel` resolves to the user's\n // hue tokens (see `packages/ui/ui-theme/src/css/components/panel.css`). Tailwind picks\n // up these utility classes from this source file.\n xmlBlockDecoration({\n tag: 'prompt',\n lineClass: 'cm-prompt-line my-8',\n contentClass: 'cm-prompt-bubble dx-panel px-2 py-1.5 rounded-sm [&_*]:text-inherit!',\n hideTags: true,\n }),\n xmlTags({ registry, setWidgets, bookmarks: ['prompt'] }),\n scroller({ overScroll: 80 }),\n options?.autoScroll && autoScroll(),\n options?.typewriter &&\n typewriter({\n cursor: options?.cursor,\n streamingTags: new Set(\n Object.entries(registry ?? {})\n .filter(([, def]) => def.streaming)\n .map(([tag]) => tag),\n ),\n }),\n options?.fader && fader(),\n setFooterRoot && footer(setFooterRoot),\n ].filter(isTruthy),\n extraExtensions,\n ].filter(isTruthy),\n };\n }, [\n themeMode,\n registry,\n debug,\n options?.autoScroll,\n options?.typewriter,\n options?.cursor,\n options?.fader,\n extraExtensions,\n ]);\n\n const viewRef = useDynamicRef(view);\n return { view, viewRef, parentRef, widgets };\n};\n\n/**\n * Consumes streaming text from the queue and appends it to the editor document.\n */\nconst useMarkdownStreamQueue = (\n view: EditorView | null,\n queue: Queue.Queue<string>,\n streamerOptions?: StreamerOptions,\n) => {\n const chunkSize = streamerOptions?.chunkSize;\n const delayMs = streamerOptions?.delayMs;\n useEffect(() => {\n if (!view) {\n return;\n }\n\n // Consume queue and update document.\n const fork = Stream.fromQueue(queue).pipe(\n (source) => createStreamer(source, { chunkSize, delayMs }),\n Stream.runForEach((text) =>\n Effect.sync(() => {\n const scrollTop = view.scrollDOM.scrollTop;\n view.dispatch({\n changes: [{ from: view.state.doc.length, insert: text }],\n annotations: Transaction.remote.of(true),\n scrollIntoView: false,\n });\n\n // Prevent autoscrolling.\n requestAnimationFrame(() => {\n view.scrollDOM.scrollTop = scrollTop;\n });\n }),\n ),\n Effect.runFork,\n );\n\n return () => {\n void runAndForwardErrors(Fiber.interrupt(fork));\n };\n }, [view, queue, chunkSize, delayMs]);\n};\n\ntype MarkdownStreamControllerDeps = {\n contentRef: RefObject<string | undefined>;\n viewRef: RefObject<EditorView | null>;\n queueRef: RefObject<Queue.Queue<string>>;\n onReset: (text: string) => Promise<void>;\n};\n\n/**\n * External controller API.\n */\nconst createMarkdownStreamController = ({\n contentRef,\n viewRef,\n queueRef,\n onReset,\n}: MarkdownStreamControllerDeps): MarkdownStreamController => {\n return {\n get length() {\n return viewRef.current?.state.doc.length;\n },\n\n /** Focus the editor. */\n focus: () => {\n viewRef.current?.focus();\n },\n\n /** Scroll to bottom. */\n scrollToBottom: (behavior?: ScrollBehavior) => {\n viewRef.current?.dispatch({\n effects: scrollerLineEffect.of({ line: -1, behavior }),\n });\n },\n\n /** Navigate previous prompt. */\n navigatePrevious: () => {\n viewRef.current?.dispatch({\n effects: navigatePreviousEffect.of(),\n });\n },\n\n /** Navigate next prompt. */\n navigateNext: () => {\n viewRef.current?.dispatch({\n effects: navigateNextEffect.of(),\n });\n },\n\n /** Set the context for widgets (XML tags). */\n setContext: (context: any) => {\n viewRef.current?.dispatch({\n effects: xmlTagContextEffect.of(context),\n });\n },\n\n /** Reset document. */\n setContent: onReset,\n\n /** Append to queue (and stream). */\n append: async (text: string) => {\n contentRef.current += text;\n if (text.length) {\n // Always go through the streaming queue, even when the doc starts empty. Skipping the\n // queue in that case (via `onReset`) bypasses the `typewriter` extension's transaction filter\n // and the first chunk lands in one CM dispatch — defeating the typewriter for any\n // consumer (e.g. ChatThread) where the first delta is large because upstream batching\n // collected several streaming partials before React rendered.\n const queue = queueRef.current;\n if (queue) {\n await runAndForwardErrors(Queue.offer(queue, text));\n }\n }\n },\n\n /** Update widget state. */\n updateWidget: (id: string, value: any) => {\n viewRef.current?.dispatch({\n effects: xmlTagUpdateEffect.of({ id, value }),\n });\n },\n } satisfies MarkdownStreamController;\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, WidgetType } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\nimport { typewriterDrainingEffect } from '@dxos/ui-editor';\n\n/**\n * Host-controlled visibility intent. The footer block widget is rendered only when this is\n * `true` AND typewriter is not actively draining its typewriter buffer — the latter is observed\n * through {@link typewriterDrainingEffect}. Removing the decoration during a drip avoids the\n * scroll-measure conflict between CM's view-line model and the floating absolute child.\n */\nexport const setFooterVisibleEffect = StateEffect.define<boolean>();\n\ntype FooterState = {\n /** Host wants the footer rendered. */\n wanted: boolean;\n /** Typewriter is actively dripping into the document. */\n draining: boolean;\n decorations: DecorationSet;\n};\n\n/**\n * Renders a host-supplied React subtree as a CodeMirror block widget anchored at\n * `doc.length`. The widget lives inside the document, so it scrolls with content.\n *\n * Toggle the host-intent visibility via {@link setFooterVisibleEffect}. The widget is also\n * automatically removed while {@link typewriterDrainingEffect} reports `true` and re-mounted\n * once the typewriter's buffer drains — this prevents the block widget from interfering with CM's\n * view-line measurement during the typewriter drip.\n *\n * For pure doc edits (no visibility transition), the decoration's position is mapped\n * through the change set so insertions at the end translate the anchor without destroying\n * the widget's DOM.\n */\nexport const footer = (setRoot: (el: HTMLElement | null) => void): Extension => {\n const widget = new FooterWidget(setRoot);\n const buildSet = (length: number): DecorationSet =>\n Decoration.set([Decoration.widget({ widget, block: true, side: 1 }).range(length)]);\n\n const field = StateField.define<FooterState>({\n create: () => ({ wanted: false, draining: false, decorations: Decoration.none }),\n update: (state, tr) => {\n let { wanted, draining, decorations } = state;\n for (const effect of tr.effects) {\n if (effect.is(setFooterVisibleEffect)) {\n wanted = effect.value;\n }\n if (effect.is(typewriterDrainingEffect)) {\n draining = effect.value;\n }\n }\n\n // Also gate on the document being non-empty: there's nothing for the footer to anchor\n // below, and rendering it on a blank doc looks like detached chrome.\n const docLength = tr.state.doc.length;\n const visible = wanted && !draining && docLength > 0;\n const wasVisible = decorations.size > 0;\n if (visible !== wasVisible) {\n decorations = visible ? buildSet(docLength) : Decoration.none;\n } else if (tr.docChanged && decorations.size > 0) {\n // Position-map the existing decoration so insertions at the end translate the\n // widget anchor without destroying the DOM (`widget.eq` is identity-true).\n decorations = decorations.map(tr.changes);\n }\n\n return { wanted, draining, decorations };\n },\n provide: (f) => EditorView.decorations.from(f, (state) => state.decorations),\n });\n\n return [field];\n};\n\n/**\n * Block widget rendered at the end of the document. The DOM element is reported via\n * `setRoot` so the host React component can `createPortal` arbitrary content into it.\n */\nclass FooterWidget extends WidgetType {\n constructor(private readonly _setRoot: (el: HTMLElement | null) => void) {\n super();\n }\n\n // Singleton equality so CM keeps the same DOM element across decoration rebuilds —\n // the React subtree portaled into it is not unmounted on every doc change.\n override eq(_other: this): boolean {\n return true;\n }\n\n override ignoreEvent(): boolean {\n return true;\n }\n\n override toDOM(): HTMLElement {\n // The outer block-widget element is `position: relative` with zero flow height so it\n // does not push the document layout (autoScroll, line measurement, etc. ignore it).\n // The inner element is `position: absolute`, taking the React subtree out of flow — it\n // renders as a floating layer anchored to the doc tail without consuming space.\n const inner = Domino.of('div')\n .classNames('cm-stream-footer-content')\n .style({ position: 'absolute', left: '0', top: '0' });\n\n const el = Domino.of('div')\n .classNames('cm-stream-footer')\n .style({ position: 'relative', height: '0' })\n .append(inner);\n\n this._setRoot(inner.root);\n return el.root;\n }\n\n override destroy(): void {\n this._setRoot(null);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["React", "ReactMarkdown", "remarkGfm", "SyntaxHighlighter", "mx", "MarkdownBlock", "classNames", "children", "components", "content", "div", "className", "remarkPlugins", "skipHtml", "defaultComponents", "h1", "h2", "h3", "blockquote", "props", "p", "a", "href", "target", "rel", "ol", "ul", "li", "pre", "code", "node", "language", "exec", "inline", "position", "start", "line", "end", "copyButton", "PreTag", "Effect", "Stream", "Obj", "renderObjectLink", "obj", "block", "getLabel", "getDXN", "toString", "createStreamer", "source", "chunkSize", "delayMs", "subdivide", "token", "isXmlFragment", "splitTextSpan", "stream", "pipe", "flatMap", "chunk", "fromIterable", "splitFragments", "tap", "sleep", "startsWith", "span", "match", "OPENING_TAG_NAME", "text", "initialTokens", "splitSpans", "tokens", "i", "length", "endsWith", "tagMatch", "tagName", "closingTag", "fragment", "foundClosing", "j", "push", "spans", "currentText", "closeIndex", "indexOf", "slice", "splitSentences", "sentenceRegex", "sentences", "lastIndex", "exec", "index", "remaining", "textStream", "text", "options", "chunkDelay", "variance", "wordsPerChunk", "words", "match", "i", "length", "chunkWords", "wordCount", "word", "push", "trim", "chunk", "join", "varianceMultiplier", "Math", "random", "delay", "Promise", "resolve", "setTimeout", "EditorSelection", "Transaction", "Effect", "Fiber", "Queue", "Stream", "React", "forwardRef", "useCallback", "useEffect", "useImperativeHandle", "useRef", "useState", "createPortal", "addEventListener", "runAndForwardErrors", "ErrorBoundary", "useDynamicRef", "useStateWithRef", "useThemeContext", "useTextEditor", "createBasicExtensions", "createThemeExtensions", "decorateMarkdown", "extendedMarkdown", "navigateNextEffect", "navigatePreviousEffect", "preview", "scroller", "scrollerLineEffect", "fader", "typewriter", "typewriterBypass", "xmlTagContextEffect", "xmlTagResetEffect", "xmlTagUpdateEffect", "xmlTags", "autoScroll", "documentSlots", "xmlFormatting", "xmlBlockDecoration", "mx", "isTruthy", "StateEffect", "StateField", "Decoration", "EditorView", "WidgetType", "Domino", "typewriterDrainingEffect", "setFooterVisibleEffect", "define", "footer", "setRoot", "widget", "FooterWidget", "buildSet", "length", "set", "block", "side", "range", "field", "create", "wanted", "draining", "decorations", "none", "update", "state", "tr", "effect", "effects", "is", "value", "docLength", "doc", "visible", "wasVisible", "size", "docChanged", "map", "changes", "provide", "f", "from", "_setRoot", "eq", "_other", "ignoreEvent", "toDOM", "inner", "of", "classNames", "style", "position", "left", "top", "el", "height", "append", "root", "destroy", "MarkdownStream", "forwardRef", "classNames", "debug", "content", "options", "registry", "extensions", "footer", "onEvent", "forwardedRef", "contentRef", "useRef", "footerRoot", "setFooterRoot", "useState", "parentRef", "view", "viewRef", "widgets", "useMarkdownStreamTextEditor", "undefined", "footerVisible", "useEffect", "dispatch", "effects", "setFooterVisibleEffect", "of", "queue", "setQueue", "queueRef", "useStateWithRef", "runSync", "unbounded", "onReset", "useCallback", "text", "current", "xmlTagContextEffect", "xmlTagResetEffect", "changes", "from", "to", "state", "doc", "length", "insert", "annotations", "typewriterBypass", "selection", "EditorSelection", "cursor", "useImperativeHandle", "createMarkdownStreamController", "addEventListener", "event", "button", "target", "closest", "getAttribute", "type", "value", "useMarkdownStreamQueue", "chunkSize", "streamCadence", "delayMs", "streamDelayMs", "destroy", "React", "div", "className", "mx", "ref", "ErrorBoundary", "name", "map", "Component", "root", "id", "props", "key", "createPortal", "currentContent", "extraExtensions", "themeMode", "useThemeContext", "setWidgets", "useTextEditor", "initialValue", "createBasicExtensions", "lineWrapping", "readOnly", "createThemeExtensions", "slots", "documentSlots", "scrollbarThin", "syntaxHighlighting", "xmlFormatting", "skip", "extendedMarkdown", "decorateMarkdown", "node", "url", "startsWith", "preview", "xmlBlockDecoration", "tag", "lineClass", "contentClass", "hideTags", "xmlTags", "bookmarks", "scroller", "overScroll", "autoScroll", "typewriter", "streamingTags", "Set", "Object", "entries", "filter", "def", "streaming", "fader", "isTruthy", "useDynamicRef", "streamerOptions", "fork", "fromQueue", "pipe", "source", "createStreamer", "runForEach", "sync", "scrollTop", "scrollDOM", "Transaction", "remote", "scrollIntoView", "requestAnimationFrame", "runFork", "runAndForwardErrors", "interrupt", "focus", "scrollToBottom", "behavior", "scrollerLineEffect", "line", "navigatePrevious", "navigatePreviousEffect", "navigateNext", "navigateNextEffect", "setContext", "context", "setContent", "append", "offer", "updateWidget", "xmlTagUpdateEffect"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"src/MarkdownBlock/MarkdownBlock.tsx":{"bytes":10499,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"react-markdown","kind":"import-statement","external":true},{"path":"remark-gfm","kind":"import-statement","external":true},{"path":"@dxos/react-ui-syntax-highlighter","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true}],"format":"esm"},"src/MarkdownBlock/index.ts":{"bytes":389,"imports":[{"path":"src/MarkdownBlock/MarkdownBlock.tsx","kind":"import-statement","original":"./MarkdownBlock"}],"format":"esm"},"src/MarkdownStream/stream.ts":{"bytes":22287,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true}],"format":"esm"},"src/MarkdownStream/testing/testing.ts":{"bytes":4746,"imports":[],"format":"esm"},"src/MarkdownStream/testing/index.ts":{"bytes":375,"imports":[{"path":"src/MarkdownStream/testing/testing.ts","kind":"import-statement","original":"./testing"}],"format":"esm"},"src/MarkdownStream/footer.ts":{"bytes":14624,"imports":[{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"@codemirror/view","kind":"import-statement","external":true},{"path":"@dxos/ui","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true}],"format":"esm"},"src/MarkdownStream/MarkdownStream.tsx":{"bytes":43069,"imports":[{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Fiber","kind":"import-statement","external":true},{"path":"effect/Queue","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react-dom","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"src/MarkdownStream/footer.ts","kind":"import-statement","original":"./footer"},{"path":"src/MarkdownStream/stream.ts","kind":"import-statement","original":"./stream"}],"format":"esm"},"src/MarkdownStream/index.ts":{"bytes":563,"imports":[{"path":"src/MarkdownStream/stream.ts","kind":"import-statement","original":"./stream"},{"path":"src/MarkdownStream/testing/index.ts","kind":"import-statement","original":"./testing"},{"path":"src/MarkdownStream/MarkdownStream.tsx","kind":"import-statement","original":"./MarkdownStream"}],"format":"esm"},"src/index.ts":{"bytes":495,"imports":[{"path":"src/MarkdownBlock/index.ts","kind":"import-statement","original":"./MarkdownBlock"},{"path":"src/MarkdownStream/index.ts","kind":"import-statement","original":"./MarkdownStream"}],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":48228},"dist/lib/browser/index.mjs":{"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"react-markdown","kind":"import-statement","external":true},{"path":"remark-gfm","kind":"import-statement","external":true},{"path":"@dxos/react-ui-syntax-highlighter","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Fiber","kind":"import-statement","external":true},{"path":"effect/Queue","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react-dom","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"@codemirror/view","kind":"import-statement","external":true},{"path":"@dxos/ui","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true}],"exports":["MarkdownBlock","MarkdownStream","createStreamer","renderObjectLink","splitFragments","splitSentences","splitSpans","textStream"],"entryPoint":"src/index.ts","inputs":{"src/MarkdownBlock/MarkdownBlock.tsx":{"bytesInOutput":2804},"src/MarkdownBlock/index.ts":{"bytesInOutput":0},"src/index.ts":{"bytesInOutput":0},"src/MarkdownStream/stream.ts":{"bytesInOutput":3135},"src/MarkdownStream/index.ts":{"bytesInOutput":0},"src/MarkdownStream/testing/testing.ts":{"bytesInOutput":701},"src/MarkdownStream/testing/index.ts":{"bytesInOutput":0},"src/MarkdownStream/MarkdownStream.tsx":{"bytesInOutput":9128},"src/MarkdownStream/footer.ts":{"bytesInOutput":2306}},"bytes":18488}}}
1
+ {"inputs":{"src/MarkdownBlock/MarkdownBlock.tsx":{"bytes":10499,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"react-markdown","kind":"import-statement","external":true},{"path":"remark-gfm","kind":"import-statement","external":true},{"path":"@dxos/react-ui-syntax-highlighter","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true}],"format":"esm"},"src/MarkdownBlock/index.ts":{"bytes":389,"imports":[{"path":"src/MarkdownBlock/MarkdownBlock.tsx","kind":"import-statement","original":"./MarkdownBlock"}],"format":"esm"},"src/MarkdownStream/stream.ts":{"bytes":22287,"imports":[{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true}],"format":"esm"},"src/MarkdownStream/testing/testing.ts":{"bytes":4746,"imports":[],"format":"esm"},"src/MarkdownStream/testing/index.ts":{"bytes":375,"imports":[{"path":"src/MarkdownStream/testing/testing.ts","kind":"import-statement","original":"./testing"}],"format":"esm"},"src/MarkdownStream/footer.ts":{"bytes":14624,"imports":[{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"@codemirror/view","kind":"import-statement","external":true},{"path":"@dxos/ui","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true}],"format":"esm"},"src/MarkdownStream/MarkdownStream.tsx":{"bytes":42909,"imports":[{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Fiber","kind":"import-statement","external":true},{"path":"effect/Queue","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react-dom","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"src/MarkdownStream/footer.ts","kind":"import-statement","original":"./footer"},{"path":"src/MarkdownStream/stream.ts","kind":"import-statement","original":"./stream"}],"format":"esm"},"src/MarkdownStream/index.ts":{"bytes":563,"imports":[{"path":"src/MarkdownStream/stream.ts","kind":"import-statement","original":"./stream"},{"path":"src/MarkdownStream/testing/index.ts","kind":"import-statement","original":"./testing"},{"path":"src/MarkdownStream/MarkdownStream.tsx","kind":"import-statement","original":"./MarkdownStream"}],"format":"esm"},"src/index.ts":{"bytes":495,"imports":[{"path":"src/MarkdownBlock/index.ts","kind":"import-statement","original":"./MarkdownBlock"},{"path":"src/MarkdownStream/index.ts","kind":"import-statement","original":"./MarkdownStream"}],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":48143},"dist/lib/browser/index.mjs":{"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"react-markdown","kind":"import-statement","external":true},{"path":"remark-gfm","kind":"import-statement","external":true},{"path":"@dxos/react-ui-syntax-highlighter","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"@dxos/echo","kind":"import-statement","external":true},{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"effect/Effect","kind":"import-statement","external":true},{"path":"effect/Fiber","kind":"import-statement","external":true},{"path":"effect/Queue","kind":"import-statement","external":true},{"path":"effect/Stream","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react-dom","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/effect","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@codemirror/state","kind":"import-statement","external":true},{"path":"@codemirror/view","kind":"import-statement","external":true},{"path":"@dxos/ui","kind":"import-statement","external":true},{"path":"@dxos/ui-editor","kind":"import-statement","external":true}],"exports":["MarkdownBlock","MarkdownStream","createStreamer","renderObjectLink","splitFragments","splitSentences","splitSpans","textStream"],"entryPoint":"src/index.ts","inputs":{"src/MarkdownBlock/MarkdownBlock.tsx":{"bytesInOutput":2804},"src/MarkdownBlock/index.ts":{"bytesInOutput":0},"src/index.ts":{"bytesInOutput":0},"src/MarkdownStream/stream.ts":{"bytesInOutput":3135},"src/MarkdownStream/index.ts":{"bytesInOutput":0},"src/MarkdownStream/testing/testing.ts":{"bytesInOutput":701},"src/MarkdownStream/testing/index.ts":{"bytesInOutput":0},"src/MarkdownStream/MarkdownStream.tsx":{"bytesInOutput":9092},"src/MarkdownStream/footer.ts":{"bytesInOutput":2306}},"bytes":18452}}}
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownStream.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownStream/MarkdownStream.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,EAAe,MAAM,mBAAmB,CAAC;AAMjF,OAAO,KAAK,EAAE,EAEZ,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAKf,OAAO,EAAiB,KAAK,eAAe,EAAmD,MAAM,gBAAgB,CAAC;AAEtH,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,cAAc,EAEnB,KAAK,qBAAqB,EAqB3B,MAAM,iBAAiB,CAAC;AAKzB,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,UAAU,CAAC;AAChE,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACrE,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,cAAc,EAAE,CAAC,QAAQ,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,UAAU,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAC/C;IACE,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,oBAAoB;IACpB,OAAO,CAAC,EAAE;QACR,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;QAEhB;;;;;;WAMG;QACH,aAAa,CAAC,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;QAE7C;;WAEG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IAEF;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB,qBAAqB;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAChD,GAAG,CAAC,cAAc,GAAG,eAAe,CAAC,CACvC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;YAjDf,OAAO;IAEf,uBAAuB;cACb,MAAM;IAEhB,oBAAoB;cACV;QACR,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;QAEhB;;;;;;WAMG;QACH,aAAa,CAAC,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;QAE7C;;WAEG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAED;;;;OAIG;aACM,SAAS;IAElB;;;;OAIG;iBACU,SAAS;IAEtB,qBAAqB;cACX,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI;;;yDAgHjD,CAAC"}
1
+ {"version":3,"file":"MarkdownStream.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownStream/MarkdownStream.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAmB,KAAK,SAAS,EAAe,MAAM,mBAAmB,CAAC;AAMjF,OAAO,KAAK,EAAE,EAEZ,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAKf,OAAO,EAAiB,KAAK,eAAe,EAAmD,MAAM,gBAAgB,CAAC;AAEtH,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,cAAc,EAEnB,KAAK,qBAAqB,EAqB3B,MAAM,iBAAiB,CAAC;AAKzB,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,UAAU,CAAC;AAChE,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACrE,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,cAAc,EAAE,CAAC,QAAQ,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,UAAU,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAC/C;IACE,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,oBAAoB;IACpB,OAAO,CAAC,EAAE;QACR,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;QAEhB;;;;;;WAMG;QACH,aAAa,CAAC,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;QAE7C;;WAEG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IAEF;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB,qBAAqB;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAChD,GAAG,CAAC,cAAc,GAAG,eAAe,CAAC,CACvC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc;YAjDf,OAAO;IAEf,uBAAuB;cACb,MAAM;IAEhB,oBAAoB;cACV;QACR,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;QAEhB;;;;;;WAMG;QACH,aAAa,CAAC,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;QAE7C;;WAEG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB;IAED;;;;OAIG;aACM,SAAS;IAElB;;;;OAIG;iBACU,SAAS;IAEtB,qBAAqB;cACX,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI;;;yDA8GjD,CAAC"}