@particle-academy/react-fancy 5.67.0 → 5.68.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Editor/Editor.context.ts","../src/components/Editor/EditorSourceToggle.tsx","../src/components/Editor/EditorFullScreenToggle.tsx","../src/components/Editor/EditorToolbar.tsx","../src/components/Editor/EditorToolbarSeparator.tsx","../src/components/Editor/EditorContent.tsx","../src/components/Editor/Editor.tsx"],"names":["jsx","useRef","useEffect","useMemo"],"mappings":"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","file":"chunk-TQ77ZWBD.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { RefObject } from \"react\";\nimport type { RenderExtension } from \"../ContentRenderer/extensions\";\n\nexport interface EditorContextValue {\n contentRef: RefObject<HTMLDivElement | null>;\n exec: (command: string, arg?: string) => void;\n insertText: (text: string) => void;\n wrapSelection: (before: string, after: string) => void;\n outputFormat: \"html\" | \"markdown\";\n lineSpacing: number;\n placeholder?: string;\n /** Merged render extensions (global + instance). */\n extensions: RenderExtension[];\n /** Whether the raw-source view (textarea) is showing instead of the rich-text surface. */\n showSource: boolean;\n /** Toggle/set the raw-source view. */\n setShowSource: (showSource: boolean) => void;\n /** Whether the editor currently covers the viewport. */\n fullScreen: boolean;\n /** Enter/leave full screen. Goes through `onFullScreenChange` when controlled. */\n setFullScreen: (fullScreen: boolean) => void;\n /** Initial HTML content to load into the editor on mount */\n _initialHtml: string;\n /** @internal Called by EditorContent on input events */\n _onInput: () => void;\n /** @internal Raw source value (`value` in `outputFormat`), for the source textarea. */\n _sourceValue: string;\n /** @internal Commit an edit made directly in the source textarea. */\n _onSourceInput: (value: string) => void;\n}\n\nexport const EditorContext = createContext<EditorContextValue | null>(null);\n\nexport function useEditor(): EditorContextValue {\n const ctx = useContext(EditorContext);\n if (!ctx) {\n throw new Error(\"useEditor must be used within an <Editor> component\");\n }\n return ctx;\n}\n","import { cn } from \"../../utils/cn\";\nimport { useEditor } from \"./Editor.context\";\nimport type { EditorSourceToggleProps } from \"./Editor.types\";\n\n/**\n * Toolbar button that reveals the raw HTML/Markdown behind the editor. Reads\n * `showSource` / `setShowSource` from context, so it works in the default\n * toolbar and in any custom toolbar composed with `useEditor()`.\n */\nexport function EditorSourceToggle({\n className,\n icon = \"</>\",\n title = \"Source\",\n activeTitle = \"Rich text\",\n}: EditorSourceToggleProps) {\n const { showSource, setShowSource } = useEditor();\n\n return (\n <button\n type=\"button\"\n onClick={() => setShowSource(!showSource)}\n title={showSource ? activeTitle : title}\n aria-pressed={showSource}\n data-react-fancy-editor-source-toggle=\"\"\n className={cn(\n \"inline-flex h-8 items-center justify-center rounded-md px-2 font-mono text-xs transition-colors\",\n showSource\n ? \"bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n : \"hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n className,\n )}\n >\n {icon}\n </button>\n );\n}\n\nEditorSourceToggle.displayName = \"EditorSourceToggle\";\n","import { cn } from \"../../utils/cn\";\nimport { FullScreenToggle } from \"../FullScreen/FullScreenToggle\";\nimport type { EditorFullScreenToggleProps } from \"./Editor.types\";\n\n/**\n * Toolbar button that takes the editor full screen and back. The shared\n * `FullScreen.Toggle`, styled for the editor toolbar and carrying the editor's\n * own handle (`data-react-fancy-editor-fullscreen-toggle`) next to the shared\n * one (`data-react-fancy-fullscreen-toggle`).\n */\nexport function EditorFullScreenToggle({ className, enterIcon, exitIcon }: EditorFullScreenToggleProps) {\n return (\n <FullScreenToggle\n data-react-fancy-editor-fullscreen-toggle=\"\"\n enterIcon={enterIcon}\n exitIcon={exitIcon}\n className={cn(className)}\n />\n );\n}\n\nEditorFullScreenToggle.displayName = \"EditorFullScreenToggle\";\n","import { cn } from \"../../utils/cn\";\nimport { useEditor } from \"./Editor.context\";\nimport { EditorSourceToggle } from \"./EditorSourceToggle\";\nimport { EditorFullScreenToggle } from \"./EditorFullScreenToggle\";\nimport type { EditorToolbarProps } from \"./Editor.types\";\n\nconst DEFAULT_ACTIONS = [\n { icon: \"B\", label: \"Bold\", command: \"bold\" },\n { icon: \"I\", label: \"Italic\", command: \"italic\" },\n { icon: \"U\", label: \"Underline\", command: \"underline\" },\n { icon: \"S\", label: \"Strikethrough\", command: \"strikeThrough\" },\n];\n\nexport function EditorToolbar({\n actions = DEFAULT_ACTIONS,\n onAction,\n children,\n className,\n showSourceToggle = true,\n showFullScreenToggle = false,\n toolbarExtra,\n}: EditorToolbarProps) {\n const { exec, showSource } = useEditor();\n // `null` / `false` / `undefined` render nothing, so they must not add a\n // wrapper either: an unused slot leaves the toolbar byte-identical.\n const hasExtra = toolbarExtra !== undefined && toolbarExtra !== null && toolbarExtra !== false;\n\n return (\n <div\n data-react-fancy-editor-toolbar=\"\"\n className={cn(\n \"flex shrink-0 items-center gap-0.5 border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-2 py-1.5 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n {children ?? (\n <>\n {actions.map((action) => (\n <button\n key={`${action.command}-${action.commandArg ?? \"\"}`}\n type=\"button\"\n // Rich-text commands don't apply to the raw-source textarea.\n disabled={showSource}\n onClick={() => {\n if (onAction) {\n onAction(action.command);\n } else {\n exec(action.command, action.commandArg);\n }\n }}\n title={action.label}\n className={cn(\n \"inline-flex h-8 w-8 items-center justify-center rounded-md text-sm transition-colors\",\n action.active\n ? \"bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n : \"hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n showSource && \"cursor-not-allowed opacity-40 hover:bg-transparent\",\n )}\n >\n {action.icon}\n </button>\n ))}\n {showSourceToggle && <EditorSourceToggle className=\"ml-auto\" />}\n {hasExtra && (\n <div\n data-react-fancy-editor-toolbar-extra=\"\"\n className={cn(\"flex items-center gap-0.5\", !showSourceToggle && \"ml-auto\")}\n >\n {toolbarExtra}\n </div>\n )}\n {showFullScreenToggle && (\n <EditorFullScreenToggle className={showSourceToggle || hasExtra ? undefined : \"ml-auto\"} />\n )}\n </>\n )}\n </div>\n );\n}\n\nEditorToolbar.displayName = \"EditorToolbar\";\n","export function EditorToolbarSeparator() {\n return (\n <span\n data-react-fancy-editor-toolbar-separator=\"\"\n className=\"mx-1 h-5 w-px bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]\"\n />\n );\n}\n\nEditorToolbarSeparator.displayName = \"EditorToolbarSeparator\";\n","import { useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { CodeView } from \"../CodeView\";\nimport { useEditor } from \"./Editor.context\";\nimport { proseClasses, extensionEditorClasses } from \"./editor.utils\";\nimport type { EditorContentProps } from \"./Editor.types\";\n\nexport function EditorContent({ className, maxHeight: maxHeightProp, sourceClassName }: EditorContentProps) {\n const {\n contentRef,\n lineSpacing,\n placeholder,\n extensions,\n outputFormat,\n showSource,\n _initialHtml,\n _onInput,\n _sourceValue,\n _onSourceInput,\n fullScreen,\n } = useEditor();\n // Full screen means \"fill the viewport\": a height cap would leave the bottom\n // of the screen empty under a scrolled box.\n const maxHeight = fullScreen ? undefined : maxHeightProp;\n // Tracks which seed HTML is currently in the contentEditable. Seeding on the\n // seed VALUE (not a one-shot boolean) re-seeds when the source view rewrites\n // `value`, while still never re-seeding on plain keystrokes — typing leaves\n // `_initialHtml` untouched, so `seededHtml.current === _initialHtml` holds.\n const seededHtml = useRef<string | null>(null);\n\n useEffect(() => {\n // Source view replaces the contentEditable in the tree, so it unmounts.\n // Forget what we seeded — the div that returns is a fresh, empty one and\n // must always be re-seeded, even if `value` was left untouched.\n if (showSource) {\n seededHtml.current = null;\n return;\n }\n const el = contentRef.current;\n if (el && seededHtml.current !== _initialHtml) {\n el.innerHTML = _initialHtml;\n seededHtml.current = _initialHtml;\n }\n }, [contentRef, _initialHtml, showSource]);\n\n const extClasses = useMemo(\n () => extensionEditorClasses(extensions),\n [extensions],\n );\n\n if (showSource) {\n // Raw-source view — a syntax-highlighted code surface (HTML highlighted;\n // markdown/plain un-highlighted), built on the shared fancy-file-commons\n // primitives. It's a DIRECT child of the flex-column editor root (no\n // wrapper — a nested flex box collapses the fill), so `flex-auto` makes it\n // fill the editor body when height-constrained and grow with content\n // (≥ minHeight) when not. `maxHeight` caps + scrolls.\n return (\n <CodeView\n value={_sourceValue}\n onChange={_onSourceInput}\n language={outputFormat === \"html\" ? \"html\" : \"plaintext\"}\n placeholder={placeholder}\n maxHeight={maxHeight}\n className={cn(\"min-h-0 flex-auto\", sourceClassName)}\n />\n );\n }\n\n return (\n <div\n ref={contentRef}\n contentEditable\n suppressContentEditableWarning\n data-react-fancy-editor-content=\"\"\n data-placeholder={placeholder}\n onInput={_onInput}\n style={{\n lineHeight: lineSpacing,\n maxHeight: maxHeight ? `${maxHeight}px` : undefined,\n }}\n className={cn(\n \"min-h-[120px] flex-auto overflow-y-auto px-4 py-3 text-sm outline-none\",\n \"focus:outline-none\",\n proseClasses,\n extClasses,\n \"empty:before:content-[attr(data-placeholder)] empty:before:text-zinc-400 empty:before:pointer-events-none\",\n className,\n )}\n />\n );\n}\n\nEditorContent.displayName = \"EditorContent\";\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { marked } from \"marked\";\nimport { cn } from \"../../utils/cn\";\nimport { sanitizeHtml } from \"../../utils/sanitize\";\nimport { useControllableState } from \"../../hooks\";\nimport { useFullScreen } from \"../../hooks/use-full-screen\";\nimport { FullScreenProvider } from \"../FullScreen/FullScreen.context\";\nimport { EditorContext } from \"./Editor.context\";\nimport { EditorToolbar } from \"./EditorToolbar\";\nimport { EditorToolbarSeparator } from \"./EditorToolbarSeparator\";\nimport { EditorSourceToggle } from \"./EditorSourceToggle\";\nimport { EditorContent } from \"./EditorContent\";\nimport { EditorFullScreenToggle } from \"./EditorFullScreenToggle\";\nimport { htmlToMarkdown, detectFormat, markdownToEditorHtml, type MarkdownSource } from \"./editor.utils\";\nimport { mergeExtensions } from \"../ContentRenderer/extensions\";\nimport { ContentRenderer } from \"../ContentRenderer/ContentRenderer\";\nimport { useFieldMode } from \"../inputs/mode/FieldMode.context\";\nimport type { EditorProps } from \"./Editor.types\";\n\ninterface Seed {\n html: string;\n /** Source map for source-preserving markdown output; null when there is none. */\n source: MarkdownSource | null;\n}\n\nfunction toHtml(\n value: string,\n outputFormat: \"html\" | \"markdown\",\n unsafe: boolean,\n valueFormat: \"markdown\" | \"html\" | \"auto\" = \"auto\",\n): Seed {\n if (!value) return { html: \"\", source: null };\n const sanitize = (html: string) => (unsafe ? html : sanitizeHtml(html));\n // An explicit valueFormat is authoritative — the sniff misclassifies\n // markdown that merely MENTIONS HTML-ish snippets (`<code>`, `<table`),\n // collapsing it into an innerHTML wall of text (#10).\n const format =\n valueFormat !== \"auto\"\n ? valueFormat\n : outputFormat === \"html\"\n ? \"html\"\n : detectFormat(value);\n if (format === \"html\") return { html: sanitize(value), source: null };\n // Markdown in, markdown out: tag each block with its source so untouched\n // blocks are emitted byte-identical.\n if (outputFormat === \"markdown\") return markdownToEditorHtml(value, sanitize);\n return { html: sanitize((marked.parse(value, { async: false }) as string).trim()), source: null };\n}\n\nfunction EditorRoot({\n children,\n className,\n value: controlledValue,\n defaultValue = \"\",\n onChange,\n outputFormat = \"html\",\n valueFormat = \"auto\",\n lineSpacing = 1.6,\n placeholder,\n mode: modeProp,\n extensions: instanceExtensions,\n unsafe = false,\n showSource: showSourceProp,\n defaultShowSource = false,\n onShowSourceChange,\n fullScreen: fullScreenProp,\n defaultFullScreen = false,\n onFullScreenChange,\n fullScreenMode = \"overlay\",\n copyButtons,\n clipboardWriter,\n onCopy,\n}: EditorProps) {\n const contentRef = useRef<HTMLDivElement | null>(null);\n const [value, setValue] = useControllableState(controlledValue, defaultValue, onChange);\n const [showSource, setShowSource] = useControllableState(\n showSourceProp,\n defaultShowSource,\n onShowSourceChange,\n );\n // Full screen is the element itself going `position: fixed`, not a portal:\n // reparenting would remount the contentEditable and lose the caret, the\n // browser's undo stack and the seeded HTML.\n const fs = useFullScreen<HTMLDivElement>({\n fullScreen: fullScreenProp,\n defaultFullScreen,\n onFullScreenChange,\n mode: fullScreenMode,\n });\n // View/edit mode — same resolution as the inputs: prop → <Form> context → \"edit\".\n const mode = useFieldMode(modeProp);\n const isView = mode === \"view\";\n\n // The value this editor last emitted through `onChange`. An incoming `value`\n // equal to it is our own keystroke echoing back; anything else came from\n // OUTSIDE — an async load, a host reset, a form repopulating.\n const lastEmitted = useRef<string | null>(null);\n\n // Bumped only on an external `value` change, so the seed memo below recomputes\n // for those and stays put while the user types. Without this, `value` was\n // excluded from the deps to avoid re-seeding on keystrokes, which also meant a\n // value arriving after mount was silently dropped and the editor stayed blank\n // forever (#15).\n const [externalSeed, setExternalSeed] = useState(0);\n useEffect(() => {\n if (value !== lastEmitted.current) setExternalSeed((n) => n + 1);\n }, [value]);\n\n const seed = useMemo(\n () => toHtml(value, outputFormat, unsafe, valueFormat),\n // Seed the contentEditable from the LIVE value when (re)entering edit mode —\n // and when returning from the raw-source view, which may have rewritten the\n // value out from under the rich-text surface. `value` itself stays out of\n // the deps so typing never re-seeds (which would fight the caret);\n // `externalSeed` covers the externally-driven case instead.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [isView, outputFormat, unsafe, valueFormat, showSource, externalSeed],\n );\n const initialHtml = seed.html;\n const seedSource = seed.source;\n\n const extensions = useMemo(\n () => mergeExtensions(instanceExtensions),\n [instanceExtensions],\n );\n\n const getOutputValue = useCallback(\n (html: string): string => {\n return outputFormat === \"markdown\" ? htmlToMarkdown(html, seedSource) : html;\n },\n [outputFormat, seedSource],\n );\n\n const handleInput = useCallback(() => {\n const el = contentRef.current;\n if (!el) return;\n const next = getOutputValue(el.innerHTML);\n // Record what we emitted BEFORE publishing it, so the value coming back in\n // is recognised as our own and does not trigger a re-seed mid-keystroke.\n lastEmitted.current = next;\n setValue(next);\n }, [setValue, getOutputValue]);\n\n const exec = useCallback(\n (command: string, arg?: string) => {\n const el = contentRef.current;\n if (!el) return;\n el.focus();\n document.execCommand(command, false, arg);\n handleInput();\n },\n [handleInput],\n );\n\n const insertText = useCallback(\n (text: string) => {\n const el = contentRef.current;\n if (!el) return;\n el.focus();\n document.execCommand(\"insertText\", false, text);\n handleInput();\n },\n [handleInput],\n );\n\n // The source textarea edits `value` directly — it is already the canonical\n // source in `outputFormat` (html or markdown), so no conversion round-trip.\n const handleSourceInput = useCallback(\n (next: string) => {\n // Also an internal emission — record it so typing in the source view is\n // not mistaken for an external change on every keystroke.\n lastEmitted.current = next;\n setValue(next);\n },\n [setValue],\n );\n\n const wrapSelection = useCallback(\n (before: string, after: string) => {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n const selectedText = range.toString();\n const el = contentRef.current;\n if (!el) return;\n el.focus();\n document.execCommand(\"insertText\", false, `${before}${selectedText}${after}`);\n handleInput();\n },\n [handleInput],\n );\n\n const contextValue = {\n contentRef,\n exec,\n insertText,\n wrapSelection,\n outputFormat,\n lineSpacing,\n placeholder,\n extensions,\n showSource,\n setShowSource,\n fullScreen: fs.fullScreen,\n setFullScreen: fs.setFullScreen,\n _initialHtml: initialHtml,\n _onInput: handleInput,\n _sourceValue: value,\n _onSourceInput: handleSourceInput,\n };\n\n // View mode — render the value read-only through ContentRenderer, matching the\n // editor's own format (markdown/html), instead of the editable toolbar+content\n // tree. Driven by `mode` / a `<Form mode=\"view\">`, exactly like the inputs.\n if (isView) {\n return (\n <FullScreenProvider value={fs}>\n <div\n {...fs.targetProps}\n data-react-fancy-editor=\"\"\n data-mode=\"view\"\n className={cn(\n \"overflow-hidden rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n // Read-only content taller than the viewport must scroll in place.\n fs.fullScreen && \"overflow-auto\",\n )}\n >\n <ContentRenderer\n value={value}\n format={valueFormat !== \"auto\" ? valueFormat : outputFormat}\n lineSpacing={lineSpacing}\n extensions={instanceExtensions}\n unsafe={unsafe}\n copyButtons={copyButtons}\n clipboardWriter={clipboardWriter}\n onCopy={onCopy}\n className=\"px-4 py-3\"\n />\n </div>\n </FullScreenProvider>\n );\n }\n\n return (\n <EditorContext.Provider value={contextValue}>\n <FullScreenProvider value={fs}>\n <div\n {...fs.targetProps}\n data-react-fancy-editor=\"\"\n data-mode=\"edit\"\n className={cn(\n \"flex flex-col overflow-hidden rounded-xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n className,\n )}\n >\n {children}\n </div>\n </FullScreenProvider>\n </EditorContext.Provider>\n );\n}\n\nconst ToolbarWithSeparator = Object.assign(EditorToolbar, {\n Separator: EditorToolbarSeparator,\n});\n\nexport const Editor = Object.assign(EditorRoot, {\n Toolbar: ToolbarWithSeparator,\n Content: EditorContent,\n SourceToggle: EditorSourceToggle,\n FullScreenToggle: EditorFullScreenToggle,\n});\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  require('./chunk-S3TRSECD.cjs');
4
- var chunkE5UU666U_cjs = require('./chunk-E5UU666U.cjs');
4
+ var chunk464QSZ4A_cjs = require('./chunk-464QSZ4A.cjs');
5
5
  require('./chunk-3U7PUZLI.cjs');
6
6
  require('./chunk-XCZZVRBY.cjs');
7
7
  require('./chunk-MXWR3T3N.cjs');
@@ -11,15 +11,15 @@ require('./chunk-ZU5Q77OT.cjs');
11
11
 
12
12
  Object.defineProperty(exports, "ContentRenderer", {
13
13
  enumerable: true,
14
- get: function () { return chunkE5UU666U_cjs.ContentRenderer; }
14
+ get: function () { return chunk464QSZ4A_cjs.ContentRenderer; }
15
15
  });
16
16
  Object.defineProperty(exports, "registerExtension", {
17
17
  enumerable: true,
18
- get: function () { return chunkE5UU666U_cjs.registerExtension; }
18
+ get: function () { return chunk464QSZ4A_cjs.registerExtension; }
19
19
  });
20
20
  Object.defineProperty(exports, "registerExtensions", {
21
21
  enumerable: true,
22
- get: function () { return chunkE5UU666U_cjs.registerExtensions; }
22
+ get: function () { return chunk464QSZ4A_cjs.registerExtensions; }
23
23
  });
24
24
  //# sourceMappingURL=content-renderer.cjs.map
25
25
  //# sourceMappingURL=content-renderer.cjs.map
@@ -1,79 +1,10 @@
1
1
  import * as react from 'react';
2
- import { R as RenderExtension } from './extensions-DiByZIpD.cjs';
3
- export { C as ContentSegment, a as RenderExtensionProps, r as registerExtension, b as registerExtensions } from './extensions-DiByZIpD.cjs';
4
-
5
- /** What a copy button copies. */
6
- type ContentCopyKind = "code" | "table";
7
- /** What is handed to a clipboard writer. */
8
- interface ContentClipboardPayload {
9
- kind: ContentCopyKind;
10
- /**
11
- * Plain text. For code: exactly the code between the fences, with no
12
- * language label and no added trailing newline. For a table: TSV (tab
13
- * between cells, newline between rows, no trailing newline).
14
- */
15
- text: string;
16
- /** The block's sanitised HTML (`<pre>…</pre>` or `<table>…</table>`), for rich paste. */
17
- html: string;
18
- }
19
- /**
20
- * Writes one copy to the clipboard. Throwing, rejecting, or returning `false`
21
- * means the copy failed; the failure is announced, never swallowed.
22
- */
23
- type ContentClipboardWriter = (payload: ContentClipboardPayload) => void | boolean | Promise<void | boolean>;
24
- /** Reported through `onCopy` after every copy attempt. */
25
- interface ContentCopyEvent extends ContentClipboardPayload {
26
- /** Position of the button among this renderer's copy buttons, in document order. */
27
- index: number;
28
- /** Whether the clipboard write succeeded. */
29
- ok: boolean;
30
- }
31
- interface ContentRendererProps {
32
- value: string;
33
- format?: "html" | "markdown" | "auto";
34
- lineSpacing?: number;
35
- className?: string;
36
- /** Per-instance render extensions. Merged with any globally-registered extensions. */
37
- extensions?: RenderExtension[];
38
- /**
39
- * Skip HTML sanitization. By default, rendered output is sanitized to remove
40
- * `<script>`, `<iframe>`, event handlers, and `javascript:` URIs. Pass
41
- * `unsafe` only when the input is fully trusted (e.g. server-rendered
42
- * markdown from your own CMS).
43
- * @default false
44
- */
45
- unsafe?: boolean;
46
- /**
47
- * Copy buttons on code blocks and tables. `false` turns them all off; an
48
- * object turns kinds off individually (`{ table: false }`).
49
- * @default true
50
- */
51
- copyButtons?: boolean | {
52
- code?: boolean;
53
- table?: boolean;
54
- };
55
- /** Called after every copy attempt, successful or not. */
56
- onCopy?: (event: ContentCopyEvent) => void;
57
- /**
58
- * Host-supplied clipboard writer, for environments where
59
- * `navigator.clipboard` is unreliable (e.g. a sandboxed Electron window:
60
- * pass one that calls Electron's `clipboard`). The default writes
61
- * text/html + text/plain via `ClipboardItem`, falling back to `writeText`.
62
- */
63
- clipboardWriter?: ContentClipboardWriter;
64
- /**
65
- * The value is still arriving. Holds back an unfinished trailing custom tag
66
- * (of a registered extension) or code fence, so a partial `<result` or
67
- * half a code block never flashes as raw text. Set it back to `false` when
68
- * the stream ends and everything renders.
69
- * @default false
70
- */
71
- streaming?: boolean;
72
- }
2
+ import { d as ContentRendererProps } from './ContentRenderer.types-RO_l7_6N.cjs';
3
+ export { C as ContentClipboardPayload, a as ContentClipboardWriter, b as ContentCopyEvent, c as ContentCopyKind, g as ContentSegment, R as RenderExtension, e as RenderExtensionProps, r as registerExtension, f as registerExtensions } from './ContentRenderer.types-RO_l7_6N.cjs';
73
4
 
74
5
  declare function ContentRenderer({ value, format, lineSpacing, className, extensions: instanceExtensions, unsafe, copyButtons, onCopy, clipboardWriter, streaming, }: ContentRendererProps): react.JSX.Element;
75
6
  declare namespace ContentRenderer {
76
7
  var displayName: string;
77
8
  }
78
9
 
79
- export { type ContentClipboardPayload, type ContentClipboardWriter, type ContentCopyEvent, type ContentCopyKind, ContentRenderer, type ContentRendererProps, RenderExtension };
10
+ export { ContentRenderer, ContentRendererProps };
@@ -1,79 +1,10 @@
1
1
  import * as react from 'react';
2
- import { R as RenderExtension } from './extensions-DiByZIpD.js';
3
- export { C as ContentSegment, a as RenderExtensionProps, r as registerExtension, b as registerExtensions } from './extensions-DiByZIpD.js';
4
-
5
- /** What a copy button copies. */
6
- type ContentCopyKind = "code" | "table";
7
- /** What is handed to a clipboard writer. */
8
- interface ContentClipboardPayload {
9
- kind: ContentCopyKind;
10
- /**
11
- * Plain text. For code: exactly the code between the fences, with no
12
- * language label and no added trailing newline. For a table: TSV (tab
13
- * between cells, newline between rows, no trailing newline).
14
- */
15
- text: string;
16
- /** The block's sanitised HTML (`<pre>…</pre>` or `<table>…</table>`), for rich paste. */
17
- html: string;
18
- }
19
- /**
20
- * Writes one copy to the clipboard. Throwing, rejecting, or returning `false`
21
- * means the copy failed; the failure is announced, never swallowed.
22
- */
23
- type ContentClipboardWriter = (payload: ContentClipboardPayload) => void | boolean | Promise<void | boolean>;
24
- /** Reported through `onCopy` after every copy attempt. */
25
- interface ContentCopyEvent extends ContentClipboardPayload {
26
- /** Position of the button among this renderer's copy buttons, in document order. */
27
- index: number;
28
- /** Whether the clipboard write succeeded. */
29
- ok: boolean;
30
- }
31
- interface ContentRendererProps {
32
- value: string;
33
- format?: "html" | "markdown" | "auto";
34
- lineSpacing?: number;
35
- className?: string;
36
- /** Per-instance render extensions. Merged with any globally-registered extensions. */
37
- extensions?: RenderExtension[];
38
- /**
39
- * Skip HTML sanitization. By default, rendered output is sanitized to remove
40
- * `<script>`, `<iframe>`, event handlers, and `javascript:` URIs. Pass
41
- * `unsafe` only when the input is fully trusted (e.g. server-rendered
42
- * markdown from your own CMS).
43
- * @default false
44
- */
45
- unsafe?: boolean;
46
- /**
47
- * Copy buttons on code blocks and tables. `false` turns them all off; an
48
- * object turns kinds off individually (`{ table: false }`).
49
- * @default true
50
- */
51
- copyButtons?: boolean | {
52
- code?: boolean;
53
- table?: boolean;
54
- };
55
- /** Called after every copy attempt, successful or not. */
56
- onCopy?: (event: ContentCopyEvent) => void;
57
- /**
58
- * Host-supplied clipboard writer, for environments where
59
- * `navigator.clipboard` is unreliable (e.g. a sandboxed Electron window:
60
- * pass one that calls Electron's `clipboard`). The default writes
61
- * text/html + text/plain via `ClipboardItem`, falling back to `writeText`.
62
- */
63
- clipboardWriter?: ContentClipboardWriter;
64
- /**
65
- * The value is still arriving. Holds back an unfinished trailing custom tag
66
- * (of a registered extension) or code fence, so a partial `<result` or
67
- * half a code block never flashes as raw text. Set it back to `false` when
68
- * the stream ends and everything renders.
69
- * @default false
70
- */
71
- streaming?: boolean;
72
- }
2
+ import { d as ContentRendererProps } from './ContentRenderer.types-RO_l7_6N.js';
3
+ export { C as ContentClipboardPayload, a as ContentClipboardWriter, b as ContentCopyEvent, c as ContentCopyKind, g as ContentSegment, R as RenderExtension, e as RenderExtensionProps, r as registerExtension, f as registerExtensions } from './ContentRenderer.types-RO_l7_6N.js';
73
4
 
74
5
  declare function ContentRenderer({ value, format, lineSpacing, className, extensions: instanceExtensions, unsafe, copyButtons, onCopy, clipboardWriter, streaming, }: ContentRendererProps): react.JSX.Element;
75
6
  declare namespace ContentRenderer {
76
7
  var displayName: string;
77
8
  }
78
9
 
79
- export { type ContentClipboardPayload, type ContentClipboardWriter, type ContentCopyEvent, type ContentCopyKind, ContentRenderer, type ContentRendererProps, RenderExtension };
10
+ export { ContentRenderer, ContentRendererProps };
@@ -1,5 +1,5 @@
1
1
  import './chunk-AUTW5O4W.js';
2
- export { ContentRenderer, registerExtension, registerExtensions } from './chunk-FXOT4P4P.js';
2
+ export { ContentRenderer, registerExtension, registerExtensions } from './chunk-2LQR4EAN.js';
3
3
  import './chunk-OXERDFFF.js';
4
4
  import './chunk-45BBNJQD.js';
5
5
  import './chunk-J3A4Z2P7.js';
package/dist/editor.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var chunk4S5DFN5N_cjs = require('./chunk-4S5DFN5N.cjs');
3
+ var chunkE4DXICU3_cjs = require('./chunk-E4DXICU3.cjs');
4
4
  require('./chunk-A2JUTNE6.cjs');
5
5
  require('./chunk-T6YELZPJ.cjs');
6
6
  require('./chunk-VQJ5LJJH.cjs');
7
7
  require('./chunk-4GOOSZEK.cjs');
8
- require('./chunk-E5UU666U.cjs');
8
+ require('./chunk-464QSZ4A.cjs');
9
9
  require('./chunk-AIA5UNQ5.cjs');
10
10
  require('./chunk-G7227RTY.cjs');
11
11
  require('./chunk-TXTRTTG7.cjs');
@@ -25,11 +25,11 @@ require('./chunk-ZU5Q77OT.cjs');
25
25
 
26
26
  Object.defineProperty(exports, "Editor", {
27
27
  enumerable: true,
28
- get: function () { return chunk4S5DFN5N_cjs.Editor; }
28
+ get: function () { return chunkE4DXICU3_cjs.Editor; }
29
29
  });
30
30
  Object.defineProperty(exports, "useEditor", {
31
31
  enumerable: true,
32
- get: function () { return chunk4S5DFN5N_cjs.useEditor; }
32
+ get: function () { return chunkE4DXICU3_cjs.useEditor; }
33
33
  });
34
34
  //# sourceMappingURL=editor.cjs.map
35
35
  //# sourceMappingURL=editor.cjs.map
package/dist/editor.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, RefObject } from 'react';
3
- import { R as RenderExtension } from './extensions-DiByZIpD.cjs';
3
+ import { R as RenderExtension, d as ContentRendererProps } from './ContentRenderer.types-RO_l7_6N.cjs';
4
4
  import { F as FieldMode } from './inputs.types-duxPKadC.cjs';
5
5
  import { b as FullScreenMode } from './use-full-screen-BUke36LI.cjs';
6
6
  import './types-DJI492iY.cjs';
@@ -132,6 +132,23 @@ interface EditorProps {
132
132
  * @default false
133
133
  */
134
134
  unsafe?: boolean;
135
+ /**
136
+ * View mode only: copy buttons on code blocks and tables, forwarded to the
137
+ * `<ContentRenderer>` that renders the value. `false` turns them all off; an
138
+ * object turns kinds off individually (`{ table: false }`). Same type and
139
+ * default as ContentRenderer's `copyButtons`.
140
+ * @default true
141
+ */
142
+ copyButtons?: ContentRendererProps["copyButtons"];
143
+ /**
144
+ * View mode only: host-supplied clipboard writer, forwarded to
145
+ * `<ContentRenderer>`. Use it where `navigator.clipboard` is unreliable (a
146
+ * sandboxed Electron window). The default writes text/html + text/plain via
147
+ * `ClipboardItem`, falling back to `writeText`.
148
+ */
149
+ clipboardWriter?: ContentRendererProps["clipboardWriter"];
150
+ /** View mode only: called after every copy attempt, forwarded to `<ContentRenderer>`. */
151
+ onCopy?: ContentRendererProps["onCopy"];
135
152
  }
136
153
 
137
154
  declare function EditorToolbar({ actions, onAction, children, className, showSourceToggle, showFullScreenToggle, toolbarExtra, }: EditorToolbarProps): react.JSX.Element;
@@ -170,7 +187,7 @@ declare namespace EditorFullScreenToggle {
170
187
  var displayName: string;
171
188
  }
172
189
 
173
- declare function EditorRoot({ children, className, value: controlledValue, defaultValue, onChange, outputFormat, valueFormat, lineSpacing, placeholder, mode: modeProp, extensions: instanceExtensions, unsafe, showSource: showSourceProp, defaultShowSource, onShowSourceChange, fullScreen: fullScreenProp, defaultFullScreen, onFullScreenChange, fullScreenMode, }: EditorProps): react.JSX.Element;
190
+ declare function EditorRoot({ children, className, value: controlledValue, defaultValue, onChange, outputFormat, valueFormat, lineSpacing, placeholder, mode: modeProp, extensions: instanceExtensions, unsafe, showSource: showSourceProp, defaultShowSource, onShowSourceChange, fullScreen: fullScreenProp, defaultFullScreen, onFullScreenChange, fullScreenMode, copyButtons, clipboardWriter, onCopy, }: EditorProps): react.JSX.Element;
174
191
  declare const Editor: typeof EditorRoot & {
175
192
  Toolbar: typeof EditorToolbar & {
176
193
  Separator: typeof EditorToolbarSeparator;
package/dist/editor.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, RefObject } from 'react';
3
- import { R as RenderExtension } from './extensions-DiByZIpD.js';
3
+ import { R as RenderExtension, d as ContentRendererProps } from './ContentRenderer.types-RO_l7_6N.js';
4
4
  import { F as FieldMode } from './inputs.types-DzGcqcPf.js';
5
5
  import { b as FullScreenMode } from './use-full-screen-BUke36LI.js';
6
6
  import './types-DJI492iY.js';
@@ -132,6 +132,23 @@ interface EditorProps {
132
132
  * @default false
133
133
  */
134
134
  unsafe?: boolean;
135
+ /**
136
+ * View mode only: copy buttons on code blocks and tables, forwarded to the
137
+ * `<ContentRenderer>` that renders the value. `false` turns them all off; an
138
+ * object turns kinds off individually (`{ table: false }`). Same type and
139
+ * default as ContentRenderer's `copyButtons`.
140
+ * @default true
141
+ */
142
+ copyButtons?: ContentRendererProps["copyButtons"];
143
+ /**
144
+ * View mode only: host-supplied clipboard writer, forwarded to
145
+ * `<ContentRenderer>`. Use it where `navigator.clipboard` is unreliable (a
146
+ * sandboxed Electron window). The default writes text/html + text/plain via
147
+ * `ClipboardItem`, falling back to `writeText`.
148
+ */
149
+ clipboardWriter?: ContentRendererProps["clipboardWriter"];
150
+ /** View mode only: called after every copy attempt, forwarded to `<ContentRenderer>`. */
151
+ onCopy?: ContentRendererProps["onCopy"];
135
152
  }
136
153
 
137
154
  declare function EditorToolbar({ actions, onAction, children, className, showSourceToggle, showFullScreenToggle, toolbarExtra, }: EditorToolbarProps): react.JSX.Element;
@@ -170,7 +187,7 @@ declare namespace EditorFullScreenToggle {
170
187
  var displayName: string;
171
188
  }
172
189
 
173
- declare function EditorRoot({ children, className, value: controlledValue, defaultValue, onChange, outputFormat, valueFormat, lineSpacing, placeholder, mode: modeProp, extensions: instanceExtensions, unsafe, showSource: showSourceProp, defaultShowSource, onShowSourceChange, fullScreen: fullScreenProp, defaultFullScreen, onFullScreenChange, fullScreenMode, }: EditorProps): react.JSX.Element;
190
+ declare function EditorRoot({ children, className, value: controlledValue, defaultValue, onChange, outputFormat, valueFormat, lineSpacing, placeholder, mode: modeProp, extensions: instanceExtensions, unsafe, showSource: showSourceProp, defaultShowSource, onShowSourceChange, fullScreen: fullScreenProp, defaultFullScreen, onFullScreenChange, fullScreenMode, copyButtons, clipboardWriter, onCopy, }: EditorProps): react.JSX.Element;
174
191
  declare const Editor: typeof EditorRoot & {
175
192
  Toolbar: typeof EditorToolbar & {
176
193
  Separator: typeof EditorToolbarSeparator;
package/dist/editor.js CHANGED
@@ -1,9 +1,9 @@
1
- export { Editor, useEditor } from './chunk-HEY4SMS2.js';
1
+ export { Editor, useEditor } from './chunk-TQ77ZWBD.js';
2
2
  import './chunk-2BXMMVQS.js';
3
3
  import './chunk-CPY7NHXM.js';
4
4
  import './chunk-RP43ZFZP.js';
5
5
  import './chunk-ZQ3VXRUY.js';
6
- import './chunk-FXOT4P4P.js';
6
+ import './chunk-2LQR4EAN.js';
7
7
  import './chunk-TJ66S5K6.js';
8
8
  import './chunk-FBWUXSKH.js';
9
9
  import './chunk-5U2DZ7AV.js';
package/dist/index.cjs CHANGED
@@ -78,12 +78,12 @@ require('./chunk-S3TRSECD.cjs');
78
78
  var chunkZ7SQMQTF_cjs = require('./chunk-Z7SQMQTF.cjs');
79
79
  var chunkAJPYGRLA_cjs = require('./chunk-AJPYGRLA.cjs');
80
80
  var chunkXZOBGKZL_cjs = require('./chunk-XZOBGKZL.cjs');
81
- var chunk4S5DFN5N_cjs = require('./chunk-4S5DFN5N.cjs');
81
+ var chunkE4DXICU3_cjs = require('./chunk-E4DXICU3.cjs');
82
82
  var chunkA2JUTNE6_cjs = require('./chunk-A2JUTNE6.cjs');
83
83
  var chunkT6YELZPJ_cjs = require('./chunk-T6YELZPJ.cjs');
84
84
  var chunkVQJ5LJJH_cjs = require('./chunk-VQJ5LJJH.cjs');
85
85
  var chunk4GOOSZEK_cjs = require('./chunk-4GOOSZEK.cjs');
86
- var chunkE5UU666U_cjs = require('./chunk-E5UU666U.cjs');
86
+ var chunk464QSZ4A_cjs = require('./chunk-464QSZ4A.cjs');
87
87
  var chunkAVU4JOYM_cjs = require('./chunk-AVU4JOYM.cjs');
88
88
  var chunkV5JTTLJP_cjs = require('./chunk-V5JTTLJP.cjs');
89
89
  var chunk4JT2QANA_cjs = require('./chunk-4JT2QANA.cjs');
@@ -652,11 +652,11 @@ Object.defineProperty(exports, "useDropdown", {
652
652
  });
653
653
  Object.defineProperty(exports, "Editor", {
654
654
  enumerable: true,
655
- get: function () { return chunk4S5DFN5N_cjs.Editor; }
655
+ get: function () { return chunkE4DXICU3_cjs.Editor; }
656
656
  });
657
657
  Object.defineProperty(exports, "useEditor", {
658
658
  enumerable: true,
659
- get: function () { return chunk4S5DFN5N_cjs.useEditor; }
659
+ get: function () { return chunkE4DXICU3_cjs.useEditor; }
660
660
  });
661
661
  Object.defineProperty(exports, "THEME_STORAGE_KEY", {
662
662
  enumerable: true,
@@ -720,19 +720,19 @@ Object.defineProperty(exports, "useFullScreen", {
720
720
  });
721
721
  Object.defineProperty(exports, "ContentRenderer", {
722
722
  enumerable: true,
723
- get: function () { return chunkE5UU666U_cjs.ContentRenderer; }
723
+ get: function () { return chunk464QSZ4A_cjs.ContentRenderer; }
724
724
  });
725
725
  Object.defineProperty(exports, "registerExtension", {
726
726
  enumerable: true,
727
- get: function () { return chunkE5UU666U_cjs.registerExtension; }
727
+ get: function () { return chunk464QSZ4A_cjs.registerExtension; }
728
728
  });
729
729
  Object.defineProperty(exports, "registerExtensions", {
730
730
  enumerable: true,
731
- get: function () { return chunkE5UU666U_cjs.registerExtensions; }
731
+ get: function () { return chunk464QSZ4A_cjs.registerExtensions; }
732
732
  });
733
733
  Object.defineProperty(exports, "renderMarkdown", {
734
734
  enumerable: true,
735
- get: function () { return chunkE5UU666U_cjs.renderMarkdown; }
735
+ get: function () { return chunk464QSZ4A_cjs.renderMarkdown; }
736
736
  });
737
737
  Object.defineProperty(exports, "Emoji", {
738
738
  enumerable: true,
package/dist/index.d.cts CHANGED
@@ -78,8 +78,8 @@ export { I as InlinePasteEditor, a as InlinePasteEditorHandle, P as PastedFilesI
78
78
  export { Chart, ChartAreaProps, ChartBarData, ChartBarProps, ChartCommonProps, ChartDonutData, ChartDonutProps, ChartHorizontalBarProps, ChartLineProps, ChartPieData, ChartPieProps, ChartSeries, ChartSparklineProps, ChartStackedBarProps } from './chart.cjs';
79
79
  export { Editor, EditorAction, EditorContentProps, EditorContextValue, EditorFullScreenToggleProps, EditorProps, EditorSourceToggleProps, EditorToolbarProps, useEditor } from './editor.cjs';
80
80
  export { CodeView, CodeViewProps } from './code-view.cjs';
81
- export { ContentClipboardPayload, ContentClipboardWriter, ContentCopyEvent, ContentCopyKind, ContentRenderer, ContentRendererProps } from './content-renderer.cjs';
82
- export { R as RenderExtension, a as RenderExtensionProps, r as registerExtension, b as registerExtensions } from './extensions-DiByZIpD.cjs';
81
+ export { ContentRenderer } from './content-renderer.cjs';
82
+ export { C as ContentClipboardPayload, a as ContentClipboardWriter, b as ContentCopyEvent, c as ContentCopyKind, d as ContentRendererProps, R as RenderExtension, e as RenderExtensionProps, r as registerExtension, f as registerExtensions } from './ContentRenderer.types-RO_l7_6N.cjs';
83
83
  export { Menu, MenuContextValue, MenuGroupProps, MenuItemProps, MenuOrientation, MenuProps, MenuSubmenuProps, useMenu } from './menu.cjs';
84
84
  export { Sidebar, SidebarCollapseMode, SidebarContextValue, SidebarGroupProps, SidebarItemProps, SidebarProps, SidebarSubmenuProps, SidebarToggleProps, useSidebar } from './sidebar.cjs';
85
85
  export { MobileMenu, MobileMenuBottomBarProps, MobileMenuContextValue, MobileMenuFlyoutProps, MobileMenuItemProps, MobileMenuSide, MobileMenuVariant, useMobileMenu } from './mobile-menu.cjs';
package/dist/index.d.ts CHANGED
@@ -78,8 +78,8 @@ export { I as InlinePasteEditor, a as InlinePasteEditorHandle, P as PastedFilesI
78
78
  export { Chart, ChartAreaProps, ChartBarData, ChartBarProps, ChartCommonProps, ChartDonutData, ChartDonutProps, ChartHorizontalBarProps, ChartLineProps, ChartPieData, ChartPieProps, ChartSeries, ChartSparklineProps, ChartStackedBarProps } from './chart.js';
79
79
  export { Editor, EditorAction, EditorContentProps, EditorContextValue, EditorFullScreenToggleProps, EditorProps, EditorSourceToggleProps, EditorToolbarProps, useEditor } from './editor.js';
80
80
  export { CodeView, CodeViewProps } from './code-view.js';
81
- export { ContentClipboardPayload, ContentClipboardWriter, ContentCopyEvent, ContentCopyKind, ContentRenderer, ContentRendererProps } from './content-renderer.js';
82
- export { R as RenderExtension, a as RenderExtensionProps, r as registerExtension, b as registerExtensions } from './extensions-DiByZIpD.js';
81
+ export { ContentRenderer } from './content-renderer.js';
82
+ export { C as ContentClipboardPayload, a as ContentClipboardWriter, b as ContentCopyEvent, c as ContentCopyKind, d as ContentRendererProps, R as RenderExtension, e as RenderExtensionProps, r as registerExtension, f as registerExtensions } from './ContentRenderer.types-RO_l7_6N.js';
83
83
  export { Menu, MenuContextValue, MenuGroupProps, MenuItemProps, MenuOrientation, MenuProps, MenuSubmenuProps, useMenu } from './menu.js';
84
84
  export { Sidebar, SidebarCollapseMode, SidebarContextValue, SidebarGroupProps, SidebarItemProps, SidebarProps, SidebarSubmenuProps, SidebarToggleProps, useSidebar } from './sidebar.js';
85
85
  export { MobileMenu, MobileMenuBottomBarProps, MobileMenuContextValue, MobileMenuFlyoutProps, MobileMenuItemProps, MobileMenuSide, MobileMenuVariant, useMobileMenu } from './mobile-menu.js';
package/dist/index.js CHANGED
@@ -76,12 +76,12 @@ import './chunk-AUTW5O4W.js';
76
76
  export { ContextMenu, useContextMenu } from './chunk-NSJBVV7R.js';
77
77
  export { Drawer, useDrawer } from './chunk-PXZRYL5I.js';
78
78
  export { Dropdown, useDropdown } from './chunk-BXPLERIJ.js';
79
- export { Editor, useEditor } from './chunk-HEY4SMS2.js';
79
+ export { Editor, useEditor } from './chunk-TQ77ZWBD.js';
80
80
  export { THEME_STORAGE_KEY, getThemePreference, initTheme, resolveTheme, setThemePreference, subscribeTheme, useId, useNodeRegistry, useTheme } from './chunk-2BXMMVQS.js';
81
81
  export { usePanZoom } from './chunk-CPY7NHXM.js';
82
82
  export { FullScreenContext, FullScreenProvider, FullScreenToggle, useFullScreenContext } from './chunk-RP43ZFZP.js';
83
83
  export { useFullScreen } from './chunk-ZQ3VXRUY.js';
84
- export { ContentRenderer, registerExtension, registerExtensions, renderMarkdown } from './chunk-FXOT4P4P.js';
84
+ export { ContentRenderer, registerExtension, registerExtensions, renderMarkdown } from './chunk-2LQR4EAN.js';
85
85
  export { Emoji } from './chunk-YTMQ2K64.js';
86
86
  export { EmojiSelect } from './chunk-WGRLNXNB.js';
87
87
  export { Card } from './chunk-2XO6EYZ7.js';
@@ -27,7 +27,7 @@ import { ContentRenderer } from "@particle-academy/react-fancy";
27
27
  | copyButtons | `boolean \| { code?: boolean; table?: boolean }` | `true` | Copy buttons on code blocks and tables. See **Copy buttons**. |
28
28
  | onCopy | `(event: ContentCopyEvent) => void` | - | Called after every copy attempt, successful or not |
29
29
  | clipboardWriter | `ContentClipboardWriter` | - | Host-supplied clipboard writer. See **Clipboard writer**. |
30
- | streaming | `boolean` | `false` | The value is still arriving: hold back an unfinished trailing tag or fence. See **Streaming**. |
30
+ | streaming | `boolean \| "progressive"` | `false` | The value is still arriving. `true` holds back an unfinished trailing tag or fence; `"progressive"` shows it as it fills. See **Streaming**. |
31
31
 
32
32
  ## Copy buttons
33
33
 
@@ -89,7 +89,8 @@ than state. Copy follows that:
89
89
  | `data-copy-state="idle" \| "copied" \| "failed"` | the copy button |
90
90
  | `data-react-fancy-content-copy-block="code" \| "table"` | the wrapper around the block |
91
91
  | `data-react-fancy-content-renderer-live` | the live region |
92
- | `data-streaming="true"` | the root, while `streaming` |
92
+ | `data-streaming="true"` | the root, while `streaming` (either mode) |
93
+ | `data-streaming-mode="progressive"` | the root, while `streaming="progressive"` |
93
94
 
94
95
  `onCopy` receives `{ kind, index, text, html, ok }`, where `index` is the
95
96
  button's position among this renderer's copy buttons in document order. Wire it
@@ -117,6 +118,50 @@ A `<` that cannot become a registered tag is prose and always renders
117
118
  A lone `<` at the very end is held for one chunk, because it may be the start of
118
119
  a tag. When `streaming` goes back to `false`, everything renders.
119
120
 
121
+ ### Progressive streaming
122
+
123
+ `streaming={true}` hides an open block until it closes. Pass
124
+ `streaming="progressive"` to show it as it fills instead:
125
+
126
+ ```tsx
127
+ <ContentRenderer
128
+ value={partial}
129
+ streaming={done ? false : "progressive"}
130
+ extensions={[resultTag]}
131
+ />
132
+ ```
133
+
134
+ - An open tag of a registered extension whose **opening tag is complete**
135
+ renders its component straight away, with the body that has arrived so far.
136
+ A `markdown` extension gets that body as `content` and rendered as
137
+ `children`, through the same pipeline as the final render: converted,
138
+ sanitised, nested extensions, copy buttons on finished blocks.
139
+ - An open code fence renders as a code block of what has arrived, in its
140
+ language. It gets **no copy button until it closes**; copying half a block
141
+ is never what anyone means, and a disabled button would still invite the
142
+ click. Finished code blocks and tables before it keep theirs.
143
+ - Still held back, exactly as in `streaming={true}`: a **partial opening tag**
144
+ (`<`, `<res`, `<result title="Do`), so it never flashes raw; a partial
145
+ closing tag (`</res`), with the body above it still showing; a fence marker
146
+ still arriving (` `` `). Also held: a fence opener line with no newline yet
147
+ (` ```ja `), because its language may be cut off.
148
+ - Inside an open fence, `<` is code and is never held.
149
+
150
+ It works by closing what is open: the open fence gets its own closing marker
151
+ and every open registered tag gets its closing tag, innermost first, and the
152
+ result renders normally. So the rendered body is the same one the final render
153
+ produces once the real closing tags arrive; only what is still to come is
154
+ missing.
155
+
156
+ The lifting rules below do not change in this mode. A `markdown` tag whose
157
+ opening tag is mid-line is not lifted while streaming, any more than it is once
158
+ it closes: it is matched in the HTML, as the final render will match it.
159
+
160
+ **Why a value of `streaming` rather than a second prop:** progressive is a way
161
+ of streaming, not something separate, and a separate boolean would add a
162
+ combination that means nothing (progressive while not streaming). A host that
163
+ already writes `streaming={!done}` changes one expression.
164
+
120
165
  ## Sanitization
121
166
 
122
167
  Since v2.5.0, `ContentRenderer` sanitizes its rendered output by default:
@@ -208,11 +253,20 @@ const resultTag: RenderExtension = {
208
253
  - `content` is the raw markdown body; `children` is that body rendered through
209
254
  the same pipeline as everything else: sanitised, with nested extensions and
210
255
  copy buttons. **Render `children`, not `content`.**
211
- - A tag is lifted when its opening tag starts a line and it has a matching
212
- closing tag. Same-name nesting is balanced, other markdown tags nest inside
213
- it, and a tag inside a code fence or inline code is left alone.
256
+ - A tag is lifted **only** when its opening tag starts a line (after at most
257
+ three spaces) **and** it has a matching closing tag. Same-name nesting is
258
+ balanced, other markdown tags nest inside it, and a tag inside a code fence
259
+ or inline code is left alone.
214
260
  - Anywhere else (mid-line, unclosed, or in HTML content) it is matched in the
215
261
  HTML as before, and `children` renders that HTML body.
262
+ - **Both conditions are deliberate and will stay.** A tag that starts a line
263
+ and closes is an unambiguous block. A mid-line `<result>` is text that
264
+ happens to contain a tag name, and an unclosed one has no end to its body, so
265
+ lifting either would turn prose (or a model quoting the tag) into a
266
+ component. To get a block, put the opening tag on its own line and close it.
267
+ `streaming="progressive"` renders an open block early, but it does so by
268
+ supplying the close the final render will see; it does not relax either
269
+ rule.
216
270
  - Nesting stops at depth 8: deeper bodies render as plain sanitised content.
217
271
 
218
272
  Sanitisation is unchanged by lifting. Every piece of markdown, including each