@dxos/react-ui-markdown 0.8.4-main.dfabb4ec29 → 0.8.4-main.effb148878
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 +102 -5
- package/dist/lib/browser/index.mjs +32 -9
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/MarkdownStream/MarkdownStream.d.ts.map +1 -1
- package/dist/types/src/MarkdownStream/stream.d.ts.map +1 -1
- package/dist/types/src/{MarkdownBlock/MarkdownBlock.d.ts → MarkdownView/MarkdownView.d.ts} +3 -3
- package/dist/types/src/MarkdownView/MarkdownView.d.ts.map +1 -0
- package/dist/types/src/{MarkdownBlock/MarkdownBlock.stories.d.ts → MarkdownView/MarkdownView.stories.d.ts} +4 -4
- package/dist/types/src/MarkdownView/MarkdownView.stories.d.ts.map +1 -0
- package/dist/types/src/MarkdownView/index.d.ts +2 -0
- package/dist/types/src/MarkdownView/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +33 -33
- package/src/MarkdownStream/MarkdownStream.tsx +4 -6
- package/src/MarkdownStream/stream.ts +1 -1
- package/src/{MarkdownBlock/MarkdownBlock.stories.tsx → MarkdownView/MarkdownView.stories.tsx} +6 -6
- package/src/{MarkdownBlock/MarkdownBlock.tsx → MarkdownView/MarkdownView.tsx} +19 -3
- package/src/{MarkdownBlock → MarkdownView}/index.ts +1 -1
- package/src/index.ts +1 -1
- package/dist/types/src/MarkdownBlock/MarkdownBlock.d.ts.map +0 -1
- package/dist/types/src/MarkdownBlock/MarkdownBlock.stories.d.ts.map +0 -1
- package/dist/types/src/MarkdownBlock/index.d.ts +0 -2
- package/dist/types/src/MarkdownBlock/index.d.ts.map +0 -1
package/LICENSE
CHANGED
|
@@ -1,8 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
Copyright (c) 2022 DXOS
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
## Abbreviation
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
FSL-1.1-Apache-2.0
|
|
7
6
|
|
|
8
|
-
|
|
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/
|
|
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
|
|
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,23 @@ 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
|
+
classNames: "w-full"
|
|
74
|
+
});
|
|
75
|
+
},
|
|
53
76
|
ol: ({ children, ...props }) => /* @__PURE__ */ React.createElement("ol", {
|
|
54
77
|
className: "pt-1 pb-1 ps-6 leading-tight list-decimal",
|
|
55
78
|
...props
|
|
@@ -84,7 +107,7 @@ var defaultComponents = {
|
|
|
84
107
|
import * as Effect from "effect/Effect";
|
|
85
108
|
import * as Stream from "effect/Stream";
|
|
86
109
|
import { Obj } from "@dxos/echo";
|
|
87
|
-
var renderObjectLink = (obj, block) => `${block ? "!" : ""}[${Obj.getLabel(obj)}](${Obj.
|
|
110
|
+
var renderObjectLink = (obj, block) => `${block ? "!" : ""}[${Obj.getLabel(obj)}](${Obj.getURI(obj)})`;
|
|
88
111
|
var createStreamer = (source, { chunkSize = "span", delayMs = 0 } = {}) => {
|
|
89
112
|
const subdivide = chunkSize === "span" ? (token) => [
|
|
90
113
|
token
|
|
@@ -234,7 +257,7 @@ import { addEventListener } from "@dxos/async";
|
|
|
234
257
|
import { runAndForwardErrors } from "@dxos/effect";
|
|
235
258
|
import { ErrorBoundary, useDynamicRef, useStateWithRef, useThemeContext } from "@dxos/react-ui";
|
|
236
259
|
import { useTextEditor } from "@dxos/react-ui-editor";
|
|
237
|
-
import { createBasicExtensions, createThemeExtensions, decorateMarkdown, extendedMarkdown, navigateNextEffect, navigatePreviousEffect, preview, scroller,
|
|
260
|
+
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
261
|
import { mx as mx2 } from "@dxos/ui-theme";
|
|
239
262
|
import { isTruthy } from "@dxos/util";
|
|
240
263
|
|
|
@@ -458,7 +481,7 @@ var useMarkdownStreamTextEditor = (currentContent, { debug, registry, options, e
|
|
|
458
481
|
xmlBlockDecoration({
|
|
459
482
|
tag: "prompt",
|
|
460
483
|
lineClass: "cm-prompt-line my-8",
|
|
461
|
-
contentClass: "cm-prompt-bubble dx-panel px-2 py-1.5 rounded-sm [&_*]:text-inherit!",
|
|
484
|
+
contentClass: "cm-prompt-bubble dx-panel px-2 py-1.5 box-decoration-clone rounded-sm [&_*]:text-inherit!",
|
|
462
485
|
hideTags: true
|
|
463
486
|
}),
|
|
464
487
|
xmlTags({
|
|
@@ -469,9 +492,9 @@ var useMarkdownStreamTextEditor = (currentContent, { debug, registry, options, e
|
|
|
469
492
|
]
|
|
470
493
|
}),
|
|
471
494
|
scroller({
|
|
472
|
-
overScroll: 80
|
|
495
|
+
overScroll: 80,
|
|
496
|
+
autoScroll: options?.autoScroll
|
|
473
497
|
}),
|
|
474
|
-
options?.autoScroll && autoScroll(),
|
|
475
498
|
options?.typewriter && typewriter({
|
|
476
499
|
cursor: options?.cursor,
|
|
477
500
|
streamingTags: new Set(Object.entries(registry ?? {}).filter(([, def]) => def.streaming).map(([tag]) => tag))
|
|
@@ -548,7 +571,7 @@ var createMarkdownStreamController = ({ contentRef, viewRef, queueRef, onReset }
|
|
|
548
571
|
/** Scroll to bottom. */
|
|
549
572
|
scrollToBottom: (behavior) => {
|
|
550
573
|
viewRef.current?.dispatch({
|
|
551
|
-
effects:
|
|
574
|
+
effects: crawlerLineEffect.of({
|
|
552
575
|
line: -1,
|
|
553
576
|
behavior
|
|
554
577
|
})
|
|
@@ -596,8 +619,8 @@ var createMarkdownStreamController = ({ contentRef, viewRef, queueRef, onReset }
|
|
|
596
619
|
};
|
|
597
620
|
};
|
|
598
621
|
export {
|
|
599
|
-
MarkdownBlock,
|
|
600
622
|
MarkdownStream,
|
|
623
|
+
MarkdownView,
|
|
601
624
|
createStreamer,
|
|
602
625
|
renderObjectLink,
|
|
603
626
|
splitFragments,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type PropsWithChildren } from 'react';\nimport ReactMarkdown, { type Options as ReactMarkdownOptions } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport { mx } from '@dxos/ui-theme';\n\nexport type MarkdownBlockProps = ThemedClassName<\n PropsWithChildren<{\n content?: string;\n components?: ReactMarkdownOptions['components'];\n }>\n>;\n\n/**\n * Transforms markdown text into react elements.\n * https://github.com/remarkjs/react-markdown\n * markdown -> remark -> [mdast -> remark plugins] -> [hast -> rehype plugins] -> components -> react elements.\n * Consider using @dxos/react-ui-editor.\n */\nexport const MarkdownBlock = ({ classNames, children, components, content = '' }: MarkdownBlockProps) => {\n return (\n <div className={mx(classNames)}>\n <ReactMarkdown remarkPlugins={[remarkGfm]} skipHtml components={{ ...defaultComponents, ...components }}>\n {content}\n </ReactMarkdown>\n {children}\n </div>\n );\n};\n\nconst defaultComponents: ReactMarkdownOptions['components'] = {\n h1: ({ children }) => {\n return <h1 className='pt-1 pb-1 text-accent-text text-xl'>{children}</h1>;\n },\n h2: ({ children }) => {\n return <h2 className='pt-1 pb-1 text-accent-text text-lg'>{children}</h2>;\n },\n h3: ({ children }) => {\n return <h3 className='pt-1 pb-1 text-accent-text text-base'>{children}</h3>;\n },\n blockquote: ({ children, ...props }) => (\n <blockquote className='my-2 py-2 ps-4 border-l-4 border-accent-text text-accent-text' {...props}>\n {children}\n </blockquote>\n ),\n p: ({ children }) => {\n return <div className='pt-1 pb-1'>{children}</div>;\n },\n a: ({ children, href, ...props }) => (\n <a\n href={href}\n className='text-primary-500 hover:text-primary-500' // TODO(burdon): Use link token.\n target='_blank'\n rel='noopener noreferrer'\n {...props}\n >\n {children}\n </a>\n ),\n ol: ({ children, ...props }) => (\n <ol className='pt-1 pb-1 ps-6 leading-tight list-decimal' {...props}>\n {children}\n </ol>\n ),\n ul: ({ children, ...props }) => (\n <ul className='pt-1 pb-1 ps-6 leading-tight list-disc' {...props}>\n {children}\n </ul>\n ),\n li: ({ children, ...props }) => (\n <li className='' {...props}>\n {children}\n </li>\n ),\n pre: ({ children }) => children,\n code: ({ children, className, node }) => {\n const [, language] = /language-(\\w+)/.exec(className || '') || [];\n const inline = !className && node?.position?.start.line === node?.position?.end.line;\n if (inline) {\n return <code className='rounded-xs bg-group-surface px-1 py-0.5 text-sm text-info-text'>{children}</code>;\n }\n\n return (\n <SyntaxHighlighter\n language={language}\n classNames='mt-2 mb-2 p-2 border border-separator rounded-xs text-sm bg-group-surface'\n copyButton\n PreTag='pre'\n >\n {children}\n </SyntaxHighlighter>\n );\n },\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Stream from 'effect/Stream';\n\nimport { Obj } from '@dxos/echo';\n\nexport const renderObjectLink = (obj: Obj.Unknown, block?: boolean) =>\n `${block ? '!' : ''}[${Obj.getLabel(obj)}](${Obj.getDXN(obj).toString()})`;\n\nexport type StreamerOptions = {\n /**\n * How to subdivide plain-text spans before emitting them downstream.\n * - `'span'` (default) — keep entire spans intact; one CM dispatch per chunk that arrived at the source.\n * - `'word'` — split text spans at whitespace boundaries (whitespace runs become their own tokens).\n * - `'character'` — split text spans into individual characters.\n * XML/HTML fragments (`<tag>…</tag>`, self-closing tags, hyphenated custom elements) are always\n * emitted as one token regardless of `chunkSize`, otherwise widget mounting would see partial markup.\n */\n chunkSize?: 'character' | 'word' | 'span';\n /**\n * Inter-token delay in ms. Default `0`. Useful for slowing down rapid bursts so the\n * downstream renderer (CodeMirror) can show a visible streaming cadence even when the\n * source emits large chunks at once.\n */\n delayMs?: number;\n};\n\n/**\n * Streams tokens to the consumer, keeping XML/HTML fragments intact.\n *\n * The cadence is controlled by `options.chunkSize`. `'span'` (default) preserves the\n * one-token-per-source-chunk behaviour the function had originally. Use `'word'` or\n * `'character'` to decouple the visible cadence from the source's chunk size — useful when\n * the AI service emits large partial blocks but you want a smoother typewriter effect.\n */\nexport const createStreamer = (\n source: Stream.Stream<string>,\n { chunkSize = 'span', delayMs = 0 }: StreamerOptions = {},\n) => {\n const subdivide =\n chunkSize === 'span'\n ? (token: string) => [token]\n : (token: string) => (isXmlFragment(token) ? [token] : splitTextSpan(token, chunkSize));\n\n let stream: Stream.Stream<string> = source.pipe(\n Stream.flatMap((chunk) => Stream.fromIterable(splitFragments(chunk).flatMap(subdivide))),\n );\n if (delayMs > 0) {\n stream = stream.pipe(Stream.tap(() => Effect.sleep(`${delayMs} millis`)));\n }\n return stream;\n};\n\n/** A token starts with `<` if and only if it is an XML/HTML fragment produced by `splitFragments`. */\nconst isXmlFragment = (token: string): boolean => token.startsWith('<');\n\n/**\n * Subdivide a non-XML text span into smaller tokens. `'word'` splits into runs of non-whitespace\n * and runs of whitespace as separate tokens (so the renderer can display whitespace cadence too).\n */\nconst splitTextSpan = (span: string, chunkSize: 'character' | 'word'): string[] => {\n if (chunkSize === 'character') {\n return [...span];\n }\n return span.match(/\\s+|\\S+/g) ?? [span];\n};\n\n/** Matches opening tag names, including custom elements with hyphens (e.g. dom-widget). */\nconst OPENING_TAG_NAME = /^<([a-zA-Z][\\w-]*)(?:\\s[^>]*)?>/;\n\n/**\n * Splits text into chunks, preserving XML/HTML fragments.\n */\nexport const splitFragments = (text: string): string[] => {\n // First tokenize with tags to get tags as complete tokens.\n const initialTokens = splitSpans(text);\n const tokens: string[] = [];\n\n let i = 0;\n while (i < initialTokens.length) {\n const token = initialTokens[i];\n\n // Check if this is an opening tag.\n if (token.startsWith('<') && !token.startsWith('</') && !token.endsWith('/>')) {\n const tagMatch = token.match(OPENING_TAG_NAME);\n if (tagMatch) {\n const tagName = tagMatch[1];\n const closingTag = `</${tagName}>`;\n\n // Collect tokens until we find the closing tag.\n let fragment = token;\n let foundClosing = false;\n let j = i + 1;\n while (j < initialTokens.length) {\n fragment += initialTokens[j];\n if (initialTokens[j] === closingTag) {\n foundClosing = true;\n break;\n }\n j++;\n }\n\n if (foundClosing) {\n // Return the complete element as one token.\n tokens.push(fragment);\n i = j + 1;\n } else {\n // No closing tag found, just add the opening tag.\n tokens.push(token);\n i++;\n }\n } else {\n // Not a valid opening tag.\n tokens.push(token);\n i++;\n }\n } else {\n // Not an opening tag (could be closing tag, self-closing, or regular character).\n tokens.push(token);\n i++;\n }\n }\n\n return tokens;\n};\n\n// TODO(burdon): Split into paragraphs and tags.\n// export const tokenizeWithTags = (text: string): string[] => {\n// const tokens: string[] = [];\n// let i = 0;\n// while (i < text.length) {\n// if (text[i] === '<') {\n// // Find the closing bracket.\n// const closeIndex = text.indexOf('>', i);\n// if (closeIndex !== -1) {\n// // Include the complete tag.\n// tokens.push(text.slice(i, closeIndex + 1));\n// i = closeIndex + 1;\n// } else {\n// // No closing bracket found, return the entire remaining fragment.\n// tokens.push(text.slice(i));\n// break;\n// }\n// } else {\n// // Regular character.\n// tokens.push(text[i]);\n// i++;\n// }\n// }\n// return tokens;\n// };\n\nexport const splitSpans = (text: string): string[] => {\n const spans: string[] = [];\n let currentText = '';\n\n let i = 0;\n while (i < text.length) {\n if (text[i] === '<') {\n // If we have accumulated text, split it into sentences and push them.\n if (currentText) {\n // const sentences = splitSentences(currentText);\n // spans.push(...sentences);\n spans.push(currentText);\n currentText = '';\n }\n\n // Find the closing bracket.\n const closeIndex = text.indexOf('>', i);\n if (closeIndex !== -1) {\n // Include the complete tag.\n spans.push(text.slice(i, closeIndex + 1));\n i = closeIndex + 1;\n } else {\n // No closing bracket found, treat the rest as text.\n currentText = text.slice(i);\n break;\n }\n } else {\n // Accumulate regular text.\n currentText += text[i];\n i++;\n }\n }\n\n // Push any remaining text split into sentences.\n if (currentText) {\n spans.push(currentText);\n // const sentences = splitSentences(currentText);\n // spans.push(...sentences);\n }\n\n return spans;\n};\n\n/**\n * Split text into sentences, preserving the sentence-ending punctuation.\n */\nexport const splitSentences = (text: string): string[] => {\n // Match sentences ending with ., !, or ? followed by space or end of string.\n // This regex captures the sentence including its ending punctuation.\n const sentenceRegex = /[^.!?]*[.!?]+(?:\\s+|$)/g;\n const sentences: string[] = [];\n let lastIndex = 0;\n let match;\n\n while ((match = sentenceRegex.exec(text)) !== null) {\n sentences.push(match[0]);\n lastIndex = match.index + match[0].length;\n }\n\n // If there's remaining text that doesn't end with punctuation, include it.\n if (lastIndex < text.length) {\n const remaining = text.slice(lastIndex);\n if (remaining) {\n sentences.push(remaining);\n }\n }\n\n // If no sentences were found, return the original text.\n if (sentences.length === 0 && text) {\n sentences.push(text);\n }\n\n return sentences;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\n/**\n * Options for the streaming text generator.\n */\nexport type TextStreamOptions = {\n /** Delay between chunks in ms. */\n chunkDelay?: number;\n /** Variance in timing (0-1). */\n variance?: number;\n /** Number of words per chunk. */\n wordsPerChunk?: number;\n};\n\n/**\n * Simulates word-by-word streaming (more natural for LLMs).\n */\nexport async function* textStream(\n text: string,\n options: TextStreamOptions = {},\n): AsyncGenerator<string, void, unknown> {\n const { chunkDelay = 100, variance = 0.3, wordsPerChunk = 3 } = options;\n\n // Split into words while preserving whitespace.\n const words = text.match(/\\S+|\\s+/g) || [];\n\n let i = 0;\n while (i < words.length) {\n // Collect multiple words for this chunk.\n const chunkWords: string[] = [];\n\n // Add words up to wordsPerChunk (counting only non-whitespace as words).\n let wordCount = 0;\n while (i < words.length && wordCount < wordsPerChunk) {\n const word = words[i];\n chunkWords.push(word);\n\n // Only count non-whitespace as words.\n if (word.trim()) {\n wordCount++;\n }\n i++;\n }\n\n // Yield the chunk.\n const chunk = chunkWords.join('');\n yield chunk;\n\n // Calculate delay based on chunk length.\n const varianceMultiplier = 1 + (Math.random() - 0.5) * variance * 2;\n const delay = chunkDelay * varianceMultiplier;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorSelection, type Extension, Transaction } from '@codemirror/state';\nimport { type EditorView } from '@codemirror/view';\nimport * as Effect from 'effect/Effect';\nimport * as Fiber from 'effect/Fiber';\nimport * as Queue from 'effect/Queue';\nimport * as Stream from 'effect/Stream';\nimport React, {\n forwardRef,\n type ReactNode,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type RefObject,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { addEventListener } from '@dxos/async';\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { ErrorBoundary, type ThemedClassName, useDynamicRef, useStateWithRef, useThemeContext } from '@dxos/react-ui';\nimport { useTextEditor, type UseTextEditor } from '@dxos/react-ui-editor';\nimport {\n type AutoScrollProps,\n type XmlTagsOptions,\n type XmlWidgetState,\n type XmlWidgetStateManager,\n createBasicExtensions,\n createThemeExtensions,\n decorateMarkdown,\n extendedMarkdown,\n navigateNextEffect,\n navigatePreviousEffect,\n preview,\n scroller,\n scrollerLineEffect,\n fader,\n typewriter,\n typewriterBypass,\n xmlTagContextEffect,\n xmlTagResetEffect,\n xmlTagUpdateEffect,\n xmlTags,\n autoScroll,\n documentSlots,\n xmlFormatting,\n xmlBlockDecoration,\n} from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\nimport { isTruthy } from '@dxos/util';\n\nimport { setFooterVisibleEffect, footer } from './footer';\nimport { type StreamerOptions, createStreamer } from './stream';\nexport interface MarkdownStreamController extends XmlWidgetStateManager {\n get length(): number | undefined;\n focus: () => void;\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n navigateNext: () => void;\n navigatePrevious: () => void;\n setContext: (context: any) => void;\n setContent: (text: string) => Promise<void>;\n append: (text: string) => Promise<void>;\n}\n\nexport type MarkdownStreamEvent = {\n type: 'submit';\n value: string | null;\n};\n\nexport type MarkdownStreamProps = ThemedClassName<\n {\n debug?: boolean;\n\n /** Initial content. */\n content?: string;\n\n /** View options. */\n options?: {\n autoScroll?: boolean;\n typewriter?: boolean;\n cursor?: boolean;\n fader?: boolean;\n\n /**\n * Streaming cadence. See {@link StreamerOptions}.\n * Use `'word'` or `'character'` to break large source chunks into smaller CM dispatches —\n * useful when the AI service emits big partial blocks but you want a smoother typewriter\n * effect. Combine with `streamDelayMs` to add a per-token sleep.\n * Default: `'span'` (one CM dispatch per source chunk; current behaviour).\n */\n streamCadence?: StreamerOptions['chunkSize'];\n\n /**\n * Per-token delay (ms) for the streaming queue. Default `0`.\n */\n streamDelayMs?: number;\n };\n\n /**\n * Optional React subtree rendered as a CodeMirror block-widget decoration anchored at\n * `doc.length`. Scrolls with the document content (lives inside `cm-content`'s flow).\n * Visibility tracks the truthiness of the prop.\n */\n footer?: ReactNode;\n\n /**\n * Extra CodeMirror extensions appended after the built-in stack — use for keymaps or\n * other host-level behaviour (e.g. `Mod-d` to toggle debug) that should apply when the\n * document is focused.\n */\n extensions?: Extension;\n\n /** Event handler. */\n onEvent?: (event: MarkdownStreamEvent) => void;\n } & (XmlTagsOptions & AutoScrollProps)\n>;\n\n/**\n * Codemirror-based markdown editor with xml tag widtgets and streaming support.\n */\nexport const MarkdownStream = forwardRef<MarkdownStreamController | null, MarkdownStreamProps>(\n ({ classNames, debug, content, options, registry, extensions, footer, onEvent }, forwardedRef) => {\n // Store current content so that we can toggle debug mode. Default to '' so the\n // `append()` path (which does `contentRef.current += text`) doesn't concatenate\n // against `undefined` and stamp `\"undefined\"` into the transcript snapshot.\n const contentRef = useRef(content ?? '');\n\n // DOM node for the footer block widget — populated when its decoration mounts.\n const [footerRoot, setFooterRoot] = useState<HTMLElement | null>(null);\n\n // Codemirror editor.\n const { parentRef, view, viewRef, widgets } = useMarkdownStreamTextEditor(contentRef, {\n debug,\n registry,\n options,\n extensions,\n setFooterRoot: footer ? setFooterRoot : undefined,\n });\n\n // Show the status footer.\n const footerVisible = !!footer;\n useEffect(() => {\n view?.dispatch({ effects: setFooterVisibleEffect.of(footerVisible) });\n }, [view, footerVisible]);\n\n // Streaming text queue.\n const [queue, setQueue, queueRef] = useStateWithRef(Effect.runSync(Queue.unbounded<string>()));\n\n // Reset document.\n const onReset = useCallback(\n async (text: string) => {\n contentRef.current = text;\n if (!viewRef.current) {\n return;\n }\n\n // Set content and scroll to bottom.\n viewRef.current.dispatch({\n effects: [xmlTagContextEffect.of(null), xmlTagResetEffect.of(null)],\n changes: [{ from: 0, to: viewRef.current.state.doc.length, insert: text }],\n annotations: typewriterBypass.of(true),\n selection: EditorSelection.cursor(text.length),\n });\n\n // New queue.\n setQueue(Effect.runSync(Queue.unbounded<string>()));\n },\n [contentRef, viewRef, setQueue],\n );\n\n // Controller API.\n useImperativeHandle(\n forwardedRef,\n () => createMarkdownStreamController({ contentRef, viewRef, queueRef, onReset }),\n [onReset],\n );\n\n // Widget events.\n useEffect(() => {\n if (!parentRef.current) {\n return;\n }\n\n // TODO(burdon): Replace this hack with a custom event listener from widgets.\n return addEventListener(parentRef.current, 'click', (event) => {\n const button = (event.target as HTMLElement).closest('[data-action=\"submit\"]');\n if (button?.getAttribute('data-action') === 'submit') {\n onEvent?.({\n type: 'submit',\n value: button.getAttribute('data-value'),\n });\n }\n });\n }, [view, parentRef, onEvent]);\n\n // Consume queue and update document.\n useMarkdownStreamQueue(view, queue, {\n chunkSize: options?.streamCadence,\n delayMs: options?.streamDelayMs,\n });\n\n // Cleanup.\n useEffect(() => {\n return () => {\n view?.destroy();\n };\n }, [view]);\n\n return (\n <>\n {/* Markdown editor. */}\n <div className={mx('dx-container', classNames)} ref={parentRef} />\n\n {/* React widgets are rendered in portals outside of the editor. */}\n <ErrorBoundary name='markdown-stream'>\n {widgets.map(({ Component, root, id, props }) => (\n <div key={id}>{createPortal(<Component view={view} {...props} />, root)}</div>\n ))}\n {footerRoot && footerVisible && createPortal(footer, footerRoot)}\n </ErrorBoundary>\n </>\n );\n },\n);\n\ntype MarkdownStreamTextEditorParams = Pick<MarkdownStreamProps, 'debug' | 'registry' | 'options' | 'extensions'> & {\n setFooterRoot?: (el: HTMLElement | null) => void;\n};\n\ntype MarkdownStreamTextEditorResult = UseTextEditor & {\n viewRef: RefObject<EditorView | null>;\n widgets: XmlWidgetState[];\n};\n\n/**\n * Read-only markdown editor configured for streaming (theme, markdown extensions, XML widgets).\n */\nconst useMarkdownStreamTextEditor = (\n currentContent: RefObject<string | undefined>,\n { debug, registry, options, extensions: extraExtensions, setFooterRoot }: MarkdownStreamTextEditorParams,\n): MarkdownStreamTextEditorResult => {\n const { themeMode } = useThemeContext();\n\n // Active widgets.\n const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);\n\n // Editor.\n const { view, parentRef } = useTextEditor(() => {\n const content = currentContent.current;\n return {\n initialValue: content,\n selection: EditorSelection.cursor(content?.length ?? 0),\n extensions: [\n createBasicExtensions({\n lineWrapping: true,\n readOnly: true,\n }),\n createThemeExtensions({\n slots: documentSlots,\n scrollbarThin: true,\n syntaxHighlighting: true,\n themeMode,\n }),\n xmlFormatting({ skip: debug ? [] : ['prompt'] }),\n !debug &&\n [\n extendedMarkdown({ registry }),\n decorateMarkdown({\n // `dxn:` links/images are reference widgets owned by `preview()` (PreviewInlineWidget /\n // PreviewBlockWidget). Skipping them here avoids `decorateMarkdown` adding a\n // non-functional `LinkButton` anchor on top of the same node — e.g. for\n // `[DXOS](dxn:echo:BNPMIBEDJLRIILYUYZVM6GT64VWI6WPPZ:01KQ889PZBRNHAEECV0ANFAYX7)`.\n skip: (node) => (node.name === 'Link' || node.name === 'Image') && node.url.startsWith('dxn:'),\n }),\n preview(),\n // NOTE: An ancestor element must set `data-hue` so `.dx-panel` resolves to the user's\n // hue tokens (see `packages/ui/ui-theme/src/css/components/panel.css`). Tailwind picks\n // up these utility classes from this source file.\n xmlBlockDecoration({\n tag: 'prompt',\n lineClass: 'cm-prompt-line my-8',\n contentClass: 'cm-prompt-bubble dx-panel px-2 py-1.5 rounded-sm [&_*]:text-inherit!',\n hideTags: true,\n }),\n xmlTags({ registry, setWidgets, bookmarks: ['prompt'] }),\n scroller({ overScroll: 80 }),\n options?.autoScroll && autoScroll(),\n options?.typewriter &&\n typewriter({\n cursor: options?.cursor,\n streamingTags: new Set(\n Object.entries(registry ?? {})\n .filter(([, def]) => def.streaming)\n .map(([tag]) => tag),\n ),\n }),\n options?.fader && fader(),\n setFooterRoot && footer(setFooterRoot),\n ].filter(isTruthy),\n extraExtensions,\n ].filter(isTruthy),\n };\n }, [\n themeMode,\n registry,\n debug,\n options?.autoScroll,\n options?.typewriter,\n options?.cursor,\n options?.fader,\n extraExtensions,\n ]);\n\n const viewRef = useDynamicRef(view);\n return { view, viewRef, parentRef, widgets };\n};\n\n/**\n * Consumes streaming text from the queue and appends it to the editor document.\n */\nconst useMarkdownStreamQueue = (\n view: EditorView | null,\n queue: Queue.Queue<string>,\n streamerOptions?: StreamerOptions,\n) => {\n const chunkSize = streamerOptions?.chunkSize;\n const delayMs = streamerOptions?.delayMs;\n useEffect(() => {\n if (!view) {\n return;\n }\n\n // Consume queue and update document.\n const fork = Stream.fromQueue(queue).pipe(\n (source) => createStreamer(source, { chunkSize, delayMs }),\n Stream.runForEach((text) =>\n Effect.sync(() => {\n const scrollTop = view.scrollDOM.scrollTop;\n view.dispatch({\n changes: [{ from: view.state.doc.length, insert: text }],\n annotations: Transaction.remote.of(true),\n scrollIntoView: false,\n });\n\n // Prevent autoscrolling.\n requestAnimationFrame(() => {\n view.scrollDOM.scrollTop = scrollTop;\n });\n }),\n ),\n Effect.runFork,\n );\n\n return () => {\n void runAndForwardErrors(Fiber.interrupt(fork));\n };\n }, [view, queue, chunkSize, delayMs]);\n};\n\ntype MarkdownStreamControllerDeps = {\n contentRef: RefObject<string | undefined>;\n viewRef: RefObject<EditorView | null>;\n queueRef: RefObject<Queue.Queue<string>>;\n onReset: (text: string) => Promise<void>;\n};\n\n/**\n * External controller API.\n */\nconst createMarkdownStreamController = ({\n contentRef,\n viewRef,\n queueRef,\n onReset,\n}: MarkdownStreamControllerDeps): MarkdownStreamController => {\n return {\n get length() {\n return viewRef.current?.state.doc.length;\n },\n\n /** Focus the editor. */\n focus: () => {\n viewRef.current?.focus();\n },\n\n /** Scroll to bottom. */\n scrollToBottom: (behavior?: ScrollBehavior) => {\n viewRef.current?.dispatch({\n effects: scrollerLineEffect.of({ line: -1, behavior }),\n });\n },\n\n /** Navigate previous prompt. */\n navigatePrevious: () => {\n viewRef.current?.dispatch({\n effects: navigatePreviousEffect.of(),\n });\n },\n\n /** Navigate next prompt. */\n navigateNext: () => {\n viewRef.current?.dispatch({\n effects: navigateNextEffect.of(),\n });\n },\n\n /** Set the context for widgets (XML tags). */\n setContext: (context: any) => {\n viewRef.current?.dispatch({\n effects: xmlTagContextEffect.of(context),\n });\n },\n\n /** Reset document. */\n setContent: onReset,\n\n /** Append to queue (and stream). */\n append: async (text: string) => {\n contentRef.current += text;\n if (text.length) {\n // Always go through the streaming queue, even when the doc starts empty. Skipping the\n // queue in that case (via `onReset`) bypasses the `typewriter` extension's transaction filter\n // and the first chunk lands in one CM dispatch — defeating the typewriter for any\n // consumer (e.g. ChatThread) where the first delta is large because upstream batching\n // collected several streaming partials before React rendered.\n const queue = queueRef.current;\n if (queue) {\n await runAndForwardErrors(Queue.offer(queue, text));\n }\n }\n },\n\n /** Update widget state. */\n updateWidget: (id: string, value: any) => {\n viewRef.current?.dispatch({\n effects: xmlTagUpdateEffect.of({ id, value }),\n });\n },\n } satisfies MarkdownStreamController;\n};\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, WidgetType } from '@codemirror/view';\n\nimport { Domino } from '@dxos/ui';\nimport { typewriterDrainingEffect } from '@dxos/ui-editor';\n\n/**\n * Host-controlled visibility intent. The footer block widget is rendered only when this is\n * `true` AND typewriter is not actively draining its typewriter buffer — the latter is observed\n * through {@link typewriterDrainingEffect}. Removing the decoration during a drip avoids the\n * scroll-measure conflict between CM's view-line model and the floating absolute child.\n */\nexport const setFooterVisibleEffect = StateEffect.define<boolean>();\n\ntype FooterState = {\n /** Host wants the footer rendered. */\n wanted: boolean;\n /** Typewriter is actively dripping into the document. */\n draining: boolean;\n decorations: DecorationSet;\n};\n\n/**\n * Renders a host-supplied React subtree as a CodeMirror block widget anchored at\n * `doc.length`. The widget lives inside the document, so it scrolls with content.\n *\n * Toggle the host-intent visibility via {@link setFooterVisibleEffect}. The widget is also\n * automatically removed while {@link typewriterDrainingEffect} reports `true` and re-mounted\n * once the typewriter's buffer drains — this prevents the block widget from interfering with CM's\n * view-line measurement during the typewriter drip.\n *\n * For pure doc edits (no visibility transition), the decoration's position is mapped\n * through the change set so insertions at the end translate the anchor without destroying\n * the widget's DOM.\n */\nexport const footer = (setRoot: (el: HTMLElement | null) => void): Extension => {\n const widget = new FooterWidget(setRoot);\n const buildSet = (length: number): DecorationSet =>\n Decoration.set([Decoration.widget({ widget, block: true, side: 1 }).range(length)]);\n\n const field = StateField.define<FooterState>({\n create: () => ({ wanted: false, draining: false, decorations: Decoration.none }),\n update: (state, tr) => {\n let { wanted, draining, decorations } = state;\n for (const effect of tr.effects) {\n if (effect.is(setFooterVisibleEffect)) {\n wanted = effect.value;\n }\n if (effect.is(typewriterDrainingEffect)) {\n draining = effect.value;\n }\n }\n\n // Also gate on the document being non-empty: there's nothing for the footer to anchor\n // below, and rendering it on a blank doc looks like detached chrome.\n const docLength = tr.state.doc.length;\n const visible = wanted && !draining && docLength > 0;\n const wasVisible = decorations.size > 0;\n if (visible !== wasVisible) {\n decorations = visible ? buildSet(docLength) : Decoration.none;\n } else if (tr.docChanged && decorations.size > 0) {\n // Position-map the existing decoration so insertions at the end translate the\n // widget anchor without destroying the DOM (`widget.eq` is identity-true).\n decorations = decorations.map(tr.changes);\n }\n\n return { wanted, draining, decorations };\n },\n provide: (f) => EditorView.decorations.from(f, (state) => state.decorations),\n });\n\n return [field];\n};\n\n/**\n * Block widget rendered at the end of the document. The DOM element is reported via\n * `setRoot` so the host React component can `createPortal` arbitrary content into it.\n */\nclass FooterWidget extends WidgetType {\n constructor(private readonly _setRoot: (el: HTMLElement | null) => void) {\n super();\n }\n\n // Singleton equality so CM keeps the same DOM element across decoration rebuilds —\n // the React subtree portaled into it is not unmounted on every doc change.\n override eq(_other: this): boolean {\n return true;\n }\n\n override ignoreEvent(): boolean {\n return true;\n }\n\n override toDOM(): HTMLElement {\n // The outer block-widget element is `position: relative` with zero flow height so it\n // does not push the document layout (autoScroll, line measurement, etc. ignore it).\n // The inner element is `position: absolute`, taking the React subtree out of flow — it\n // renders as a floating layer anchored to the doc tail without consuming space.\n const inner = Domino.of('div')\n .classNames('cm-stream-footer-content')\n .style({ position: 'absolute', left: '0', top: '0' });\n\n const el = Domino.of('div')\n .classNames('cm-stream-footer')\n .style({ position: 'relative', height: '0' })\n .append(inner);\n\n this._setRoot(inner.root);\n return el.root;\n }\n\n override destroy(): void {\n this._setRoot(null);\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["React", "ReactMarkdown", "remarkGfm", "SyntaxHighlighter", "mx", "
|
|
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} classNames='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.getURI(obj)})`;\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 box-decoration-clone 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": ";AAIA,OAAOA,WAAuC;AAC9C,OAAOC,mBAA6D;AACpE,OAAOC,eAAe;AAEtB,SAASC,mBAAyC;AAClD,SAASC,yBAAyB;AAClC,SAASC,UAAU;AAeZ,IAAMC,eAAe,CAAC,EAAEC,YAAYC,UAAUC,YAAYC,UAAU,GAAE,MAAqB;AAChG,SACE,sBAAA,cAACC,OAAAA;IAAIC,WAAWP,GAAGE,UAAAA;KACjB,sBAAA,cAACN,eAAAA;IAAcY,eAAe;MAACX;;IAAYY,UAAAA;IAASL,YAAY;MAAE,GAAGM;MAAmB,GAAGN;IAAW;KACnGC,OAAAA,GAEFF,QAAAA;AAGP;AAEA,IAAMO,oBAAwD;EAC5DC,IAAI,CAAC,EAAER,SAAQ,MAAE;AACf,WAAO,sBAAA,cAACQ,MAAAA;MAAGJ,WAAU;OAAsCJ,QAAAA;EAC7D;EACAS,IAAI,CAAC,EAAET,SAAQ,MAAE;AACf,WAAO,sBAAA,cAACS,MAAAA;MAAGL,WAAU;OAAsCJ,QAAAA;EAC7D;EACAU,IAAI,CAAC,EAAEV,SAAQ,MAAE;AACf,WAAO,sBAAA,cAACU,MAAAA;MAAGN,WAAU;OAAwCJ,QAAAA;EAC/D;EACAW,IAAI,CAAC,EAAEX,SAAQ,MAAE;AACf,WAAO,sBAAA,cAACW,MAAAA;MAAGP,WAAU;OAAiCJ,QAAAA;EACxD;EACAY,YAAY,CAAC,EAAEZ,UAAU,GAAGa,MAAAA,MAC1B,sBAAA,cAACD,cAAAA;IAAWR,WAAU;IAAiE,GAAGS;KACvFb,QAAAA;EAGLc,GAAG,CAAC,EAAEd,SAAQ,MAAE;AACd,WAAO,sBAAA,cAACG,OAAAA;MAAIC,WAAU;OAAaJ,QAAAA;EACrC;EACAe,GAAG,CAAC,EAAEf,UAAUgB,MAAM,GAAGH,MAAAA,MACvB,sBAAA,cAACE,KAAAA;IACCC;IACAZ,WAAU;IACVa,QAAO;IACPC,KAAI;IACH,GAAGL;KAEHb,QAAAA;;;;;;;;EAULmB,KAAK,CAAC,EAAEC,KAAKC,IAAG,MAAE;AAChB,QAAI,CAACD,KAAK;AACR,aAAO;IACT;AACA,WAAO,sBAAA,cAACzB,aAAAA;MAAYyB;MAAUC;MAAUtB,YAAW;;EACrD;EACAuB,IAAI,CAAC,EAAEtB,UAAU,GAAGa,MAAAA,MAClB,sBAAA,cAACS,MAAAA;IAAGlB,WAAU;IAA6C,GAAGS;KAC3Db,QAAAA;EAGLuB,IAAI,CAAC,EAAEvB,UAAU,GAAGa,MAAAA,MAClB,sBAAA,cAACU,MAAAA;IAAGnB,WAAU;IAA0C,GAAGS;KACxDb,QAAAA;EAGLwB,IAAI,CAAC,EAAExB,UAAU,GAAGa,MAAAA,MAClB,sBAAA,cAACW,MAAAA;IAAGpB,WAAU;IAAI,GAAGS;KAClBb,QAAAA;EAGLyB,KAAK,CAAC,EAAEzB,SAAQ,MAAOA;EACvB0B,MAAM,CAAC,EAAE1B,UAAUI,WAAWuB,KAAI,MAAE;AAClC,UAAM,CAAA,EAAGC,QAAAA,IAAY,iBAAiBC,KAAKzB,aAAa,EAAA,KAAO,CAAA;AAC/D,UAAM0B,SAAS,CAAC1B,aAAauB,MAAMI,UAAUC,MAAMC,SAASN,MAAMI,UAAUG,IAAID;AAChF,QAAIH,QAAQ;AACV,aAAO,sBAAA,cAACJ,QAAAA;QAAKtB,WAAU;SAAkEJ,QAAAA;IAC3F;AAEA,WACE,sBAAA,cAACJ,mBAAAA;MACCgC;MACA7B,YAAW;MACXoC,YAAAA;MACAC,QAAO;OAENpC,QAAAA;EAGP;AACF;;;AC/GA,YAAYqC,YAAY;AACxB,YAAYC,YAAY;AAExB,SAASC,WAAW;AAEb,IAAMC,mBAAmB,CAACC,KAAkBC,UACjD,GAAGA,QAAQ,MAAM,EAAA,IAAMH,IAAII,SAASF,GAAAA,CAAAA,KAASF,IAAIK,OAAOH,GAAAA,CAAAA;AA4BnD,IAAMI,iBAAiB,CAC5BC,QACA,EAAEC,YAAY,QAAQC,UAAU,EAAC,IAAsB,CAAC,MAAC;AAEzD,QAAMC,YACJF,cAAc,SACV,CAACG,UAAkB;IAACA;MACpB,CAACA,UAAmBC,cAAcD,KAAAA,IAAS;IAACA;MAASE,cAAcF,OAAOH,SAAAA;AAEhF,MAAIM,SAAgCP,OAAOQ,KAClCC,eAAQ,CAACC,UAAiBC,oBAAaC,eAAeF,KAAAA,EAAOD,QAAQN,SAAAA,CAAAA,CAAAA,CAAAA;AAE9E,MAAID,UAAU,GAAG;AACfK,aAASA,OAAOC,KAAYK,WAAI,MAAaC,aAAM,GAAGZ,OAAAA,SAAgB,CAAA,CAAA;EACxE;AACA,SAAOK;AACT;AAGA,IAAMF,gBAAgB,CAACD,UAA2BA,MAAMW,WAAW,GAAA;AAMnE,IAAMT,gBAAgB,CAACU,MAAcf,cAAAA;AACnC,MAAIA,cAAc,aAAa;AAC7B,WAAO;SAAIe;;EACb;AACA,SAAOA,KAAKC,MAAM,UAAA,KAAe;IAACD;;AACpC;AAGA,IAAME,mBAAmB;AAKlB,IAAMN,iBAAiB,CAACO,SAAAA;AAE7B,QAAMC,gBAAgBC,WAAWF,IAAAA;AACjC,QAAMG,SAAmB,CAAA;AAEzB,MAAIC,IAAI;AACR,SAAOA,IAAIH,cAAcI,QAAQ;AAC/B,UAAMpB,QAAQgB,cAAcG,CAAAA;AAG5B,QAAInB,MAAMW,WAAW,GAAA,KAAQ,CAACX,MAAMW,WAAW,IAAA,KAAS,CAACX,MAAMqB,SAAS,IAAA,GAAO;AAC7E,YAAMC,WAAWtB,MAAMa,MAAMC,gBAAAA;AAC7B,UAAIQ,UAAU;AACZ,cAAMC,UAAUD,SAAS,CAAA;AACzB,cAAME,aAAa,KAAKD,OAAAA;AAGxB,YAAIE,WAAWzB;AACf,YAAI0B,eAAe;AACnB,YAAIC,IAAIR,IAAI;AACZ,eAAOQ,IAAIX,cAAcI,QAAQ;AAC/BK,sBAAYT,cAAcW,CAAAA;AAC1B,cAAIX,cAAcW,CAAAA,MAAOH,YAAY;AACnCE,2BAAe;AACf;UACF;AACAC;QACF;AAEA,YAAID,cAAc;AAEhBR,iBAAOU,KAAKH,QAAAA;AACZN,cAAIQ,IAAI;QACV,OAAO;AAELT,iBAAOU,KAAK5B,KAAAA;AACZmB;QACF;MACF,OAAO;AAELD,eAAOU,KAAK5B,KAAAA;AACZmB;MACF;IACF,OAAO;AAELD,aAAOU,KAAK5B,KAAAA;AACZmB;IACF;EACF;AAEA,SAAOD;AACT;AA4BO,IAAMD,aAAa,CAACF,SAAAA;AACzB,QAAMc,QAAkB,CAAA;AACxB,MAAIC,cAAc;AAElB,MAAIX,IAAI;AACR,SAAOA,IAAIJ,KAAKK,QAAQ;AACtB,QAAIL,KAAKI,CAAAA,MAAO,KAAK;AAEnB,UAAIW,aAAa;AAGfD,cAAMD,KAAKE,WAAAA;AACXA,sBAAc;MAChB;AAGA,YAAMC,aAAahB,KAAKiB,QAAQ,KAAKb,CAAAA;AACrC,UAAIY,eAAe,IAAI;AAErBF,cAAMD,KAAKb,KAAKkB,MAAMd,GAAGY,aAAa,CAAA,CAAA;AACtCZ,YAAIY,aAAa;MACnB,OAAO;AAELD,sBAAcf,KAAKkB,MAAMd,CAAAA;AACzB;MACF;IACF,OAAO;AAELW,qBAAef,KAAKI,CAAAA;AACpBA;IACF;EACF;AAGA,MAAIW,aAAa;AACfD,UAAMD,KAAKE,WAAAA;EAGb;AAEA,SAAOD;AACT;AAKO,IAAMK,iBAAiB,CAACnB,SAAAA;AAG7B,QAAMoB,gBAAgB;AACtB,QAAMC,YAAsB,CAAA;AAC5B,MAAIC,YAAY;AAChB,MAAIxB;AAEJ,UAAQA,QAAQsB,cAAcG,KAAKvB,IAAAA,OAAW,MAAM;AAClDqB,cAAUR,KAAKf,MAAM,CAAA,CAAE;AACvBwB,gBAAYxB,MAAM0B,QAAQ1B,MAAM,CAAA,EAAGO;EACrC;AAGA,MAAIiB,YAAYtB,KAAKK,QAAQ;AAC3B,UAAMoB,YAAYzB,KAAKkB,MAAMI,SAAAA;AAC7B,QAAIG,WAAW;AACbJ,gBAAUR,KAAKY,SAAAA;IACjB;EACF;AAGA,MAAIJ,UAAUhB,WAAW,KAAKL,MAAM;AAClCqB,cAAUR,KAAKb,IAAAA;EACjB;AAEA,SAAOqB;AACT;;;ACjNA,gBAAuBK,WACrBC,MACAC,UAA6B,CAAC,GAAC;AAE/B,QAAM,EAAEC,aAAa,KAAKC,WAAW,KAAKC,gBAAgB,EAAC,IAAKH;AAGhE,QAAMI,QAAQL,KAAKM,MAAM,UAAA,KAAe,CAAA;AAExC,MAAIC,IAAI;AACR,SAAOA,IAAIF,MAAMG,QAAQ;AAEvB,UAAMC,aAAuB,CAAA;AAG7B,QAAIC,YAAY;AAChB,WAAOH,IAAIF,MAAMG,UAAUE,YAAYN,eAAe;AACpD,YAAMO,OAAON,MAAME,CAAAA;AACnBE,iBAAWG,KAAKD,IAAAA;AAGhB,UAAIA,KAAKE,KAAI,GAAI;AACfH;MACF;AACAH;IACF;AAGA,UAAMO,QAAQL,WAAWM,KAAK,EAAA;AAC9B,UAAMD;AAGN,UAAME,qBAAqB,KAAKC,KAAKC,OAAM,IAAK,OAAOf,WAAW;AAClE,UAAMgB,QAAQjB,aAAac;AAC3B,UAAM,IAAII,QAAQ,CAACC,YAAYC,WAAWD,SAASF,KAAAA,CAAAA;EACrD;AACF;;;ACnDA,SAASI,iBAAiCC,mBAAmB;AAE7D,YAAYC,aAAY;AACxB,YAAYC,WAAW;AACvB,YAAYC,WAAW;AACvB,YAAYC,aAAY;AACxB,OAAOC,UACLC,YAEAC,aACAC,WACAC,qBACAC,QACAC,gBAEK;AACP,SAASC,oBAAoB;AAE7B,SAASC,wBAAwB;AACjC,SAASC,2BAA2B;AACpC,SAASC,eAAqCC,eAAeC,iBAAiBC,uBAAuB;AACrG,SAASC,qBAAyC;AAClD,SAKEC,uBACAC,uBACAC,kBACAC,kBACAC,oBACAC,wBACAC,SACAC,UACAC,mBACAC,OACAC,YACAC,kBACAC,qBACAC,mBACAC,oBACAC,SACAC,eACAC,eACAC,0BACK;AACP,SAASC,MAAAA,WAAU;AACnB,SAASC,gBAAgB;;;AChDzB,SAAyBC,aAAaC,kBAAkB;AACxD,SAASC,YAAgCC,YAAYC,kBAAkB;AAEvE,SAASC,cAAc;AACvB,SAASC,gCAAgC;AAQlC,IAAMC,yBAAyBP,YAAYQ,OAAM;AAuBjD,IAAMC,SAAS,CAACC,YAAAA;AACrB,QAAMC,SAAS,IAAIC,aAAaF,OAAAA;AAChC,QAAMG,WAAW,CAACC,WAChBZ,WAAWa,IAAI;IAACb,WAAWS,OAAO;MAAEA;MAAQK,OAAO;MAAMC,MAAM;IAAE,CAAA,EAAGC,MAAMJ,MAAAA;GAAQ;AAEpF,QAAMK,QAAQlB,WAAWO,OAAoB;IAC3CY,QAAQ,OAAO;MAAEC,QAAQ;MAAOC,UAAU;MAAOC,aAAarB,WAAWsB;IAAK;IAC9EC,QAAQ,CAACC,OAAOC,OAAAA;AACd,UAAI,EAAEN,QAAQC,UAAUC,YAAW,IAAKG;AACxC,iBAAWE,UAAUD,GAAGE,SAAS;AAC/B,YAAID,OAAOE,GAAGvB,sBAAAA,GAAyB;AACrCc,mBAASO,OAAOG;QAClB;AACA,YAAIH,OAAOE,GAAGxB,wBAAAA,GAA2B;AACvCgB,qBAAWM,OAAOG;QACpB;MACF;AAIA,YAAMC,YAAYL,GAAGD,MAAMO,IAAInB;AAC/B,YAAMoB,UAAUb,UAAU,CAACC,YAAYU,YAAY;AACnD,YAAMG,aAAaZ,YAAYa,OAAO;AACtC,UAAIF,YAAYC,YAAY;AAC1BZ,sBAAcW,UAAUrB,SAASmB,SAAAA,IAAa9B,WAAWsB;MAC3D,WAAWG,GAAGU,cAAcd,YAAYa,OAAO,GAAG;AAGhDb,sBAAcA,YAAYe,IAAIX,GAAGY,OAAO;MAC1C;AAEA,aAAO;QAAElB;QAAQC;QAAUC;MAAY;IACzC;IACAiB,SAAS,CAACC,MAAMtC,WAAWoB,YAAYmB,KAAKD,GAAG,CAACf,UAAUA,MAAMH,WAAW;EAC7E,CAAA;AAEA,SAAO;IAACJ;;AACV;AAMA,IAAMP,eAAN,cAA2BR,WAAAA;;EACzB,YAA6BuC,UAA4C;AACvE,UAAK,GAAA,KADsBA,WAAAA;EAE7B;;;EAISC,GAAGC,QAAuB;AACjC,WAAO;EACT;EAESC,cAAuB;AAC9B,WAAO;EACT;EAESC,QAAqB;AAK5B,UAAMC,QAAQ3C,OAAO4C,GAAG,KAAA,EACrBC,WAAW,0BAAA,EACXC,MAAM;MAAEC,UAAU;MAAYC,MAAM;MAAKC,KAAK;IAAI,CAAA;AAErD,UAAMC,KAAKlD,OAAO4C,GAAG,KAAA,EAClBC,WAAW,kBAAA,EACXC,MAAM;MAAEC,UAAU;MAAYI,QAAQ;IAAI,CAAA,EAC1CC,OAAOT,KAAAA;AAEV,SAAKL,SAASK,MAAMU,IAAI;AACxB,WAAOH,GAAGG;EACZ;EAESC,UAAgB;AACvB,SAAKhB,SAAS,IAAA;EAChB;AACF;;;ADKO,IAAMiB,iBAAiBC,2BAC5B,CAAC,EAAEC,YAAYC,OAAOC,SAASC,SAASC,UAAUC,YAAYC,QAAAA,SAAQC,QAAO,GAAIC,iBAAAA;AAI/E,QAAMC,aAAaC,OAAOR,WAAW,EAAA;AAGrC,QAAM,CAACS,YAAYC,aAAAA,IAAiBC,SAA6B,IAAA;AAGjE,QAAM,EAAEC,WAAWC,MAAMC,SAASC,QAAO,IAAKC,4BAA4BT,YAAY;IACpFR;IACAG;IACAD;IACAE;IACAO,eAAeN,UAASM,gBAAgBO;EAC1C,CAAA;AAGA,QAAMC,gBAAgB,CAAC,CAACd;AACxBe,YAAU,MAAA;AACRN,UAAMO,SAAS;MAAEC,SAASC,uBAAuBC,GAAGL,aAAAA;IAAe,CAAA;EACrE,GAAG;IAACL;IAAMK;GAAc;AAGxB,QAAM,CAACM,OAAOC,UAAUC,QAAAA,IAAYC,gBAAuBC,gBAAcC,gBAAS,CAAA,CAAA;AAGlF,QAAMC,UAAUC,YACd,OAAOC,SAAAA;AACLzB,eAAW0B,UAAUD;AACrB,QAAI,CAAClB,QAAQmB,SAAS;AACpB;IACF;AAGAnB,YAAQmB,QAAQb,SAAS;MACvBC,SAAS;QAACa,oBAAoBX,GAAG,IAAA;QAAOY,kBAAkBZ,GAAG,IAAA;;MAC7Da,SAAS;QAAC;UAAEC,MAAM;UAAGC,IAAIxB,QAAQmB,QAAQM,MAAMC,IAAIC;UAAQC,QAAQV;QAAK;;MACxEW,aAAaC,iBAAiBrB,GAAG,IAAA;MACjCsB,WAAWC,gBAAgBC,OAAOf,KAAKS,MAAM;IAC/C,CAAA;AAGAhB,aAAgBG,gBAAcC,gBAAS,CAAA,CAAA;EACzC,GACA;IAACtB;IAAYO;IAASW;GAAS;AAIjCuB,sBACE1C,cACA,MAAM2C,+BAA+B;IAAE1C;IAAYO;IAASY;IAAUI;EAAQ,CAAA,GAC9E;IAACA;GAAQ;AAIXX,YAAU,MAAA;AACR,QAAI,CAACP,UAAUqB,SAAS;AACtB;IACF;AAGA,WAAOiB,iBAAiBtC,UAAUqB,SAAS,SAAS,CAACkB,UAAAA;AACnD,YAAMC,SAAUD,MAAME,OAAuBC,QAAQ,wBAAA;AACrD,UAAIF,QAAQG,aAAa,aAAA,MAAmB,UAAU;AACpDlD,kBAAU;UACRmD,MAAM;UACNC,OAAOL,OAAOG,aAAa,YAAA;QAC7B,CAAA;MACF;IACF,CAAA;EACF,GAAG;IAAC1C;IAAMD;IAAWP;GAAQ;AAG7BqD,yBAAuB7C,MAAMW,OAAO;IAClCmC,WAAW1D,SAAS2D;IACpBC,SAAS5D,SAAS6D;EACpB,CAAA;AAGA3C,YAAU,MAAA;AACR,WAAO,MAAA;AACLN,YAAMkD,QAAAA;IACR;EACF,GAAG;IAAClD;GAAK;AAET,SACE,gBAAAmD,OAAA,cAAAA,OAAA,UAAA,MAEE,gBAAAA,OAAA,cAACC,OAAAA;IAAIC,WAAWC,IAAG,gBAAgBrE,UAAAA;IAAasE,KAAKxD;MAGrD,gBAAAoD,OAAA,cAACK,eAAAA;IAAcC,MAAK;KACjBvD,QAAQwD,IAAI,CAAC,EAAEC,WAAWC,MAAMC,IAAIC,MAAK,MACxC,gBAAAX,OAAA,cAACC,OAAAA;IAAIW,KAAKF;KAAKG,6BAAa,gBAAAb,OAAA,cAACQ,WAAAA;IAAU3D;IAAa,GAAG8D;MAAWF,IAAAA,CAAAA,CAAAA,GAEnEhE,cAAcS,iBAAiB2D,6BAAazE,SAAQK,UAAAA,CAAAA,CAAAA;AAI7D,CAAA;AAeF,IAAMO,8BAA8B,CAClC8D,gBACA,EAAE/E,OAAOG,UAAUD,SAASE,YAAY4E,iBAAiBrE,cAAa,MAAkC;AAExG,QAAM,EAAEsE,UAAS,IAAKC,gBAAAA;AAGtB,QAAM,CAAClE,SAASmE,UAAAA,IAAcvE,SAA2B,CAAA,CAAE;AAG3D,QAAM,EAAEE,MAAMD,UAAS,IAAKuE,cAAc,MAAA;AACxC,UAAMnF,UAAU8E,eAAe7C;AAC/B,WAAO;MACLmD,cAAcpF;MACd6C,WAAWC,gBAAgBC,OAAO/C,SAASyC,UAAU,CAAA;MACrDtC,YAAY;QACVkF,sBAAsB;UACpBC,cAAc;UACdC,UAAU;QACZ,CAAA;QACAC,sBAAsB;UACpBC,OAAOC;UACPC,eAAe;UACfC,oBAAoB;UACpBZ;QACF,CAAA;QACAa,cAAc;UAAEC,MAAM/F,QAAQ,CAAA,IAAK;YAAC;;QAAU,CAAA;QAC9C,CAACA,SACC;UACEgG,iBAAiB;YAAE7F;UAAS,CAAA;UAC5B8F,iBAAiB;;;;;YAKfF,MAAM,CAACG,UAAUA,KAAK3B,SAAS,UAAU2B,KAAK3B,SAAS,YAAY2B,KAAKC,IAAIC,WAAW,MAAA;UACzF,CAAA;UACAC,QAAAA;;;;UAIAC,mBAAmB;YACjBC,KAAK;YACLC,WAAW;YACXC,cAAc;YACdC,UAAU;UACZ,CAAA;UACAC,QAAQ;YAAExG;YAAUgF;YAAYyB,WAAW;cAAC;;UAAU,CAAA;UACtDC,SAAS;YAAEC,YAAY;YAAIC,YAAY7G,SAAS6G;UAAW,CAAA;UAC3D7G,SAAS8G,cACPA,WAAW;YACThE,QAAQ9C,SAAS8C;YACjBiE,eAAe,IAAIC,IACjBC,OAAOC,QAAQjH,YAAY,CAAC,CAAA,EACzBkH,OAAO,CAAC,CAAA,EAAGC,GAAAA,MAASA,IAAIC,SAAS,EACjC/C,IAAI,CAAC,CAAC+B,GAAAA,MAASA,GAAAA,CAAAA;UAEtB,CAAA;UACFrG,SAASsH,SAASA,MAAAA;UAClB7G,iBAAiBN,OAAOM,aAAAA;UACxB0G,OAAOI,QAAAA;QACXzC;QACAqC,OAAOI,QAAAA;IACX;EACF,GAAG;IACDxC;IACA9E;IACAH;IACAE,SAAS6G;IACT7G,SAAS8G;IACT9G,SAAS8C;IACT9C,SAASsH;IACTxC;GACD;AAED,QAAMjE,UAAU2G,cAAc5G,IAAAA;AAC9B,SAAO;IAAEA;IAAMC;IAASF;IAAWG;EAAQ;AAC7C;AAKA,IAAM2C,yBAAyB,CAC7B7C,MACAW,OACAkG,oBAAAA;AAEA,QAAM/D,YAAY+D,iBAAiB/D;AACnC,QAAME,UAAU6D,iBAAiB7D;AACjC1C,YAAU,MAAA;AACR,QAAI,CAACN,MAAM;AACT;IACF;AAGA,UAAM8G,OAAcC,kBAAUpG,KAAAA,EAAOqG,KACnC,CAACC,WAAWC,eAAeD,QAAQ;MAAEnE;MAAWE;IAAQ,CAAA,GACjDmE,mBAAW,CAAChG,SACViG,aAAK,MAAA;AACV,YAAMC,YAAYrH,KAAKsH,UAAUD;AACjCrH,WAAKO,SAAS;QACZgB,SAAS;UAAC;YAAEC,MAAMxB,KAAK0B,MAAMC,IAAIC;YAAQC,QAAQV;UAAK;;QACtDW,aAAayF,YAAYC,OAAO9G,GAAG,IAAA;QACnC+G,gBAAgB;MAClB,CAAA;AAGAC,4BAAsB,MAAA;AACpB1H,aAAKsH,UAAUD,YAAYA;MAC7B,CAAA;IACF,CAAA,CAAA,GAEKM,eAAO;AAGhB,WAAO,MAAA;AACL,WAAKC,oBAA0BC,gBAAUf,IAAAA,CAAAA;IAC3C;EACF,GAAG;IAAC9G;IAAMW;IAAOmC;IAAWE;GAAQ;AACtC;AAYA,IAAMZ,iCAAiC,CAAC,EACtC1C,YACAO,SACAY,UACAI,QAAO,MACsB;AAC7B,SAAO;IACL,IAAIW,SAAS;AACX,aAAO3B,QAAQmB,SAASM,MAAMC,IAAIC;IACpC;;IAGAkG,OAAO,MAAA;AACL7H,cAAQmB,SAAS0G,MAAAA;IACnB;;IAGAC,gBAAgB,CAACC,aAAAA;AACf/H,cAAQmB,SAASb,SAAS;QACxBC,SAASyH,kBAAkBvH,GAAG;UAAEwH,MAAM;UAAIF;QAAS,CAAA;MACrD,CAAA;IACF;;IAGAG,kBAAkB,MAAA;AAChBlI,cAAQmB,SAASb,SAAS;QACxBC,SAAS4H,uBAAuB1H,GAAE;MACpC,CAAA;IACF;;IAGA2H,cAAc,MAAA;AACZpI,cAAQmB,SAASb,SAAS;QACxBC,SAAS8H,mBAAmB5H,GAAE;MAChC,CAAA;IACF;;IAGA6H,YAAY,CAACC,YAAAA;AACXvI,cAAQmB,SAASb,SAAS;QACxBC,SAASa,oBAAoBX,GAAG8H,OAAAA;MAClC,CAAA;IACF;;IAGAC,YAAYxH;;IAGZyH,QAAQ,OAAOvH,SAAAA;AACbzB,iBAAW0B,WAAWD;AACtB,UAAIA,KAAKS,QAAQ;AAMf,cAAMjB,QAAQE,SAASO;AACvB,YAAIT,OAAO;AACT,gBAAMiH,oBAA0Be,YAAMhI,OAAOQ,IAAAA,CAAAA;QAC/C;MACF;IACF;;IAGAyH,cAAc,CAAC/E,IAAYjB,UAAAA;AACzB3C,cAAQmB,SAASb,SAAS;QACxBC,SAASqI,mBAAmBnI,GAAG;UAAEmD;UAAIjB;QAAM,CAAA;MAC7C,CAAA;IACF;EACF;AACF;",
|
|
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", "ol", "ul", "li", "pre", "code", "node", "language", "exec", "inline", "position", "start", "line", "end", "copyButton", "PreTag", "Effect", "Stream", "Obj", "renderObjectLink", "obj", "block", "getLabel", "getURI", "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/
|
|
1
|
+
{"inputs":{"src/MarkdownView/MarkdownView.tsx":{"bytes":12780,"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":22232,"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":42888,"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":49042},"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":3603},"src/MarkdownView/index.ts":{"bytesInOutput":0},"src/index.ts":{"bytesInOutput":0},"src/MarkdownStream/stream.ts":{"bytesInOutput":3124},"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":9097},"src/MarkdownStream/footer.ts":{"bytesInOutput":2306}},"bytes":19242}}}
|
|
@@ -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,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownStream/stream.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEjC,eAAO,MAAM,gBAAgB,QAAS,GAAG,CAAC,OAAO,UAAU,OAAO,
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownStream/stream.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEjC,eAAO,MAAM,gBAAgB,QAAS,GAAG,CAAC,OAAO,UAAU,OAAO,WACD,CAAC;AAElE,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;IAC1C;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,WACjB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,2BACQ,eAAe,wCAcrD,CAAC;AAmBF;;GAEG;AACH,eAAO,MAAM,cAAc,SAAU,MAAM,KAAG,MAAM,EAmDnD,CAAC;AA4BF,eAAO,MAAM,UAAU,SAAU,MAAM,KAAG,MAAM,EAyC/C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,SAAU,MAAM,KAAG,MAAM,EA2BnD,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
|
|
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
|
|
15
|
-
//# sourceMappingURL=
|
|
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 {
|
|
2
|
+
import { MarkdownView } from './MarkdownView';
|
|
3
3
|
declare const meta: {
|
|
4
4
|
title: string;
|
|
5
|
-
component: ({ classNames, children, components, content }: import("./
|
|
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
|
|
9
|
+
type Story = StoryObj<typeof MarkdownView>;
|
|
10
10
|
export declare const Default: Story;
|
|
11
|
-
//# sourceMappingURL=
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/MarkdownView/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC"}
|