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

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/LICENSE CHANGED
@@ -1,8 +1,105 @@
1
- MIT License
2
- Copyright (c) 2022 DXOS
1
+ # Functional Source License, Version 1.1, ALv2 Future License
3
2
 
4
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
+ ## Abbreviation
5
4
 
6
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5
+ FSL-1.1-Apache-2.0
7
6
 
8
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ ## Notice
8
+
9
+ Copyright 2026 DXOS
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
@@ -1,10 +1,11 @@
1
- // src/MarkdownBlock/MarkdownBlock.tsx
1
+ // src/MarkdownView/MarkdownView.tsx
2
2
  import React from "react";
3
3
  import ReactMarkdown from "react-markdown";
4
4
  import remarkGfm from "remark-gfm";
5
+ import { MediaPlayer } from "@dxos/react-ui";
5
6
  import { SyntaxHighlighter } from "@dxos/react-ui-syntax-highlighter";
6
7
  import { mx } from "@dxos/ui-theme";
7
- var MarkdownBlock = ({ classNames, children, components, content = "" }) => {
8
+ var MarkdownView = ({ classNames, children, components, content = "" }) => {
8
9
  return /* @__PURE__ */ React.createElement("div", {
9
10
  className: mx(classNames)
10
11
  }, /* @__PURE__ */ React.createElement(ReactMarkdown, {
@@ -34,6 +35,11 @@ var defaultComponents = {
34
35
  className: "pt-1 pb-1 text-accent-text text-base"
35
36
  }, children);
36
37
  },
38
+ h4: ({ children }) => {
39
+ return /* @__PURE__ */ React.createElement("h4", {
40
+ className: "pt-1 pb-1 uppercase text-base"
41
+ }, children);
42
+ },
37
43
  blockquote: ({ children, ...props }) => /* @__PURE__ */ React.createElement("blockquote", {
38
44
  className: "my-2 py-2 ps-4 border-l-4 border-accent-text text-accent-text",
39
45
  ...props
@@ -50,6 +56,24 @@ var defaultComponents = {
50
56
  rel: "noopener noreferrer",
51
57
  ...props
52
58
  }, children),
59
+ // Hide broken images: many markdown sources reference remote URLs that
60
+ // 404 or are blocked. Drop the element on load failure rather than
61
+ // leaving the browser's broken-image placeholder.
62
+ //
63
+ // Media URLs (mp4/mp3/etc. or legacy `iframe`-style embeds) are swapped to a
64
+ // native `<video>` / `<audio>` element by {@link MediaPlayer} so playable
65
+ // media in the source document renders inline.
66
+ img: ({ src, alt }) => {
67
+ if (!src) {
68
+ return null;
69
+ }
70
+ return /* @__PURE__ */ React.createElement(MediaPlayer, {
71
+ src,
72
+ alt,
73
+ mediaClassNames: "aspect-video w-full",
74
+ imgClassNames: "w-full"
75
+ });
76
+ },
53
77
  ol: ({ children, ...props }) => /* @__PURE__ */ React.createElement("ol", {
54
78
  className: "pt-1 pb-1 ps-6 leading-tight list-decimal",
55
79
  ...props
@@ -234,7 +258,7 @@ import { addEventListener } from "@dxos/async";
234
258
  import { runAndForwardErrors } from "@dxos/effect";
235
259
  import { ErrorBoundary, useDynamicRef, useStateWithRef, useThemeContext } from "@dxos/react-ui";
236
260
  import { useTextEditor } from "@dxos/react-ui-editor";
237
- import { createBasicExtensions, createThemeExtensions, decorateMarkdown, extendedMarkdown, navigateNextEffect, navigatePreviousEffect, preview, scroller, scrollerLineEffect, fader, typewriter, typewriterBypass, xmlTagContextEffect, xmlTagResetEffect, xmlTagUpdateEffect, xmlTags, autoScroll, documentSlots, xmlFormatting, xmlBlockDecoration } from "@dxos/ui-editor";
261
+ import { createBasicExtensions, createThemeExtensions, decorateMarkdown, extendedMarkdown, navigateNextEffect, navigatePreviousEffect, preview, scroller, crawlerLineEffect, fader, typewriter, typewriterBypass, xmlTagContextEffect, xmlTagResetEffect, xmlTagUpdateEffect, xmlTags, documentSlots, xmlFormatting, xmlBlockDecoration } from "@dxos/ui-editor";
238
262
  import { mx as mx2 } from "@dxos/ui-theme";
239
263
  import { isTruthy } from "@dxos/util";
240
264
 
@@ -405,14 +429,12 @@ var MarkdownStream = /* @__PURE__ */ forwardRef(({ classNames, debug, content, o
405
429
  view
406
430
  ]);
407
431
  return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("div", {
408
- role: "none",
409
432
  className: mx2("dx-container", classNames),
410
433
  ref: parentRef
411
434
  }), /* @__PURE__ */ React2.createElement(ErrorBoundary, {
412
435
  name: "markdown-stream"
413
436
  }, widgets.map(({ Component, root, id, props }) => /* @__PURE__ */ React2.createElement("div", {
414
- key: id,
415
- role: "none"
437
+ key: id
416
438
  }, /* @__PURE__ */ createPortal(/* @__PURE__ */ React2.createElement(Component, {
417
439
  view,
418
440
  ...props
@@ -471,9 +493,9 @@ var useMarkdownStreamTextEditor = (currentContent, { debug, registry, options, e
471
493
  ]
472
494
  }),
473
495
  scroller({
474
- overScroll: 80
496
+ overScroll: 80,
497
+ autoScroll: options?.autoScroll
475
498
  }),
476
- options?.autoScroll && autoScroll(),
477
499
  options?.typewriter && typewriter({
478
500
  cursor: options?.cursor,
479
501
  streamingTags: new Set(Object.entries(registry ?? {}).filter(([, def]) => def.streaming).map(([tag]) => tag))
@@ -550,7 +572,7 @@ var createMarkdownStreamController = ({ contentRef, viewRef, queueRef, onReset }
550
572
  /** Scroll to bottom. */
551
573
  scrollToBottom: (behavior) => {
552
574
  viewRef.current?.dispatch({
553
- effects: scrollerLineEffect.of({
575
+ effects: crawlerLineEffect.of({
554
576
  line: -1,
555
577
  behavior
556
578
  })
@@ -598,8 +620,8 @@ var createMarkdownStreamController = ({ contentRef, viewRef, queueRef, onReset }
598
620
  };
599
621
  };
600
622
  export {
601
- MarkdownBlock,
602
623
  MarkdownStream,
624
+ MarkdownView,
603
625
  createStreamer,
604
626
  renderObjectLink,
605
627
  splitFragments,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 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"]
3
+ "sources": ["../../../src/MarkdownView/MarkdownView.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 { MediaPlayer, type ThemedClassName } from '@dxos/react-ui';\nimport { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport { mx } from '@dxos/ui-theme';\n\nexport type MarkdownViewProps = 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 MarkdownView = ({ classNames, children, components, content = '' }: MarkdownViewProps) => {\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 h4: ({ children }) => {\n return <h4 className='pt-1 pb-1 uppercase text-base'>{children}</h4>;\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 // Hide broken images: many markdown sources reference remote URLs that\n // 404 or are blocked. Drop the element on load failure rather than\n // leaving the browser's broken-image placeholder.\n //\n // Media URLs (mp4/mp3/etc. or legacy `iframe`-style embeds) are swapped to a\n // native `<video>` / `<audio>` element by {@link MediaPlayer} so playable\n // media in the source document renders inline.\n img: ({ src, alt }) => {\n if (!src) {\n return null;\n }\n return <MediaPlayer src={src} alt={alt} mediaClassNames='aspect-video w-full' imgClassNames='w-full' />;\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 crawlerLineEffect,\n fader,\n typewriter,\n typewriterBypass,\n xmlTagContextEffect,\n xmlTagResetEffect,\n xmlTagUpdateEffect,\n xmlTags,\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, autoScroll: options?.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: crawlerLineEffect.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", "MediaPlayer", "SyntaxHighlighter", "mx", "MarkdownView", "classNames", "children", "components", "content", "div", "className", "remarkPlugins", "skipHtml", "defaultComponents", "h1", "h2", "h3", "h4", "blockquote", "props", "p", "a", "href", "target", "rel", "img", "src", "alt", "mediaClassNames", "imgClassNames", "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", "crawlerLineEffect", "fader", "typewriter", "typewriterBypass", "xmlTagContextEffect", "xmlTagResetEffect", "xmlTagUpdateEffect", "xmlTags", "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", "crawlerLineEffect", "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/MarkdownView/MarkdownView.tsx":{"bytes":12951,"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","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/MarkdownView/index.ts":{"bytes":388,"imports":[{"path":"src/MarkdownView/MarkdownView.tsx","kind":"import-statement","original":"./MarkdownView"}],"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":42839,"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":494,"imports":[{"path":"src/MarkdownView/index.ts","kind":"import-statement","original":"./MarkdownView"},{"path":"src/MarkdownStream/index.ts","kind":"import-statement","original":"./MarkdownStream"}],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":49143},"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","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":["MarkdownStream","MarkdownView","createStreamer","renderObjectLink","splitFragments","splitSentences","splitSpans","textStream"],"entryPoint":"src/index.ts","inputs":{"src/MarkdownView/MarkdownView.tsx":{"bytesInOutput":3652},"src/MarkdownView/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":9076},"src/MarkdownStream/footer.ts":{"bytesInOutput":2306}},"bytes":19281}}}
@@ -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,EAoB3B,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"}
@@ -1,7 +1,7 @@
1
1
  import React, { type PropsWithChildren } from 'react';
2
2
  import { type Options as ReactMarkdownOptions } from 'react-markdown';
3
3
  import { type ThemedClassName } from '@dxos/react-ui';
4
- export type MarkdownBlockProps = ThemedClassName<PropsWithChildren<{
4
+ export type MarkdownViewProps = ThemedClassName<PropsWithChildren<{
5
5
  content?: string;
6
6
  components?: ReactMarkdownOptions['components'];
7
7
  }>>;
@@ -11,5 +11,5 @@ export type MarkdownBlockProps = ThemedClassName<PropsWithChildren<{
11
11
  * markdown -> remark -> [mdast -> remark plugins] -> [hast -> rehype plugins] -> components -> react elements.
12
12
  * Consider using @dxos/react-ui-editor.
13
13
  */
14
- export declare const MarkdownBlock: ({ classNames, children, components, content }: MarkdownBlockProps) => React.JSX.Element;
15
- //# sourceMappingURL=MarkdownBlock.d.ts.map
14
+ export declare const MarkdownView: ({ classNames, children, components, content }: MarkdownViewProps) => React.JSX.Element;
15
+ //# sourceMappingURL=MarkdownView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownView.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownView/MarkdownView.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACtD,OAAsB,EAAE,KAAK,OAAO,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAInE,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAC7C,iBAAiB,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;CACjD,CAAC,CACH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,kDAAwD,iBAAiB,sBASjG,CAAC"}
@@ -1,11 +1,11 @@
1
1
  import { type StoryObj } from '@storybook/react-vite';
2
- import { MarkdownBlock } from './MarkdownBlock';
2
+ import { MarkdownView } from './MarkdownView';
3
3
  declare const meta: {
4
4
  title: string;
5
- component: ({ classNames, children, components, content }: import("./MarkdownBlock").MarkdownBlockProps) => import("react").JSX.Element;
5
+ component: ({ classNames, children, components, content }: import("./MarkdownView").MarkdownViewProps) => import("react").JSX.Element;
6
6
  decorators: import("@storybook/react").Decorator[];
7
7
  };
8
8
  export default meta;
9
- type Story = StoryObj<typeof MarkdownBlock>;
9
+ type Story = StoryObj<typeof MarkdownView>;
10
10
  export declare const Default: Story;
11
- //# sourceMappingURL=MarkdownBlock.stories.d.ts.map
11
+ //# sourceMappingURL=MarkdownView.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownView.stories.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownView/MarkdownView.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAMjE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI9C,QAAA,MAAM,IAAI;;;;CAI2B,CAAC;eAEvB,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,YAAY,CAAC,CAAC;AA+C3C,eAAO,MAAM,OAAO,EAAE,KAKrB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './MarkdownView';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownView/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC"}
@@ -1,3 +1,3 @@
1
- export * from './MarkdownBlock';
1
+ export * from './MarkdownView';
2
2
  export * from './MarkdownStream';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}