@particle-academy/react-fancy 6.3.0 → 6.4.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -0
  3. package/dist/autocomplete.cjs +5 -5
  4. package/dist/autocomplete.js +4 -4
  5. package/dist/card.cjs +8 -8
  6. package/dist/card.js +2 -2
  7. package/dist/chat-thread.cjs +5 -4
  8. package/dist/chat-thread.js +3 -2
  9. package/dist/{chunk-K7JOZQRK.cjs → chunk-2G6TIX5Q.cjs} +4 -4
  10. package/dist/{chunk-K7JOZQRK.cjs.map → chunk-2G6TIX5Q.cjs.map} +1 -1
  11. package/dist/{chunk-TH4JZAMK.js → chunk-5TP642UT.js} +4 -4
  12. package/dist/{chunk-TH4JZAMK.js.map → chunk-5TP642UT.js.map} +1 -1
  13. package/dist/chunk-6BB32POL.js +29 -0
  14. package/dist/chunk-6BB32POL.js.map +1 -0
  15. package/dist/{chunk-XIA2UAVO.js → chunk-6GVOW3UL.js} +4 -4
  16. package/dist/{chunk-XIA2UAVO.js.map → chunk-6GVOW3UL.js.map} +1 -1
  17. package/dist/{chunk-4JT2QANA.cjs → chunk-6H7ZN23X.cjs} +3 -3
  18. package/dist/{chunk-4JT2QANA.cjs.map → chunk-6H7ZN23X.cjs.map} +1 -1
  19. package/dist/chunk-7ZCNZUZK.cjs +183 -0
  20. package/dist/chunk-7ZCNZUZK.cjs.map +1 -0
  21. package/dist/chunk-AHZIT3CM.js +204 -0
  22. package/dist/chunk-AHZIT3CM.js.map +1 -0
  23. package/dist/{chunk-MP55W37V.cjs → chunk-BYO5RUDE.cjs} +4 -4
  24. package/dist/{chunk-MP55W37V.cjs.map → chunk-BYO5RUDE.cjs.map} +1 -1
  25. package/dist/{chunk-2XO6EYZ7.js → chunk-EENHSMV2.js} +3 -3
  26. package/dist/{chunk-2XO6EYZ7.js.map → chunk-EENHSMV2.js.map} +1 -1
  27. package/dist/{chunk-7JLKOVHX.cjs → chunk-HLI6RB5V.cjs} +4 -4
  28. package/dist/{chunk-7JLKOVHX.cjs.map → chunk-HLI6RB5V.cjs.map} +1 -1
  29. package/dist/chunk-HZUKPYR3.cjs +31 -0
  30. package/dist/chunk-HZUKPYR3.cjs.map +1 -0
  31. package/dist/chunk-J2BWXCES.js +177 -0
  32. package/dist/chunk-J2BWXCES.js.map +1 -0
  33. package/dist/{chunk-CKO2KCUN.cjs → chunk-MPCZUZ4O.cjs} +7 -175
  34. package/dist/chunk-MPCZUZ4O.cjs.map +1 -0
  35. package/dist/{chunk-G7227RTY.cjs → chunk-NIAG6OF6.cjs} +4 -22
  36. package/dist/chunk-NIAG6OF6.cjs.map +1 -0
  37. package/dist/{chunk-FBWUXSKH.js → chunk-P24A2BIR.js} +4 -22
  38. package/dist/chunk-P24A2BIR.js.map +1 -0
  39. package/dist/{chunk-3AA2KGZG.js → chunk-QF2FODTG.js} +5 -173
  40. package/dist/chunk-QF2FODTG.js.map +1 -0
  41. package/dist/{chunk-A6NYZ3F5.js → chunk-RWU2MFUL.js} +4 -4
  42. package/dist/{chunk-A6NYZ3F5.js.map → chunk-RWU2MFUL.js.map} +1 -1
  43. package/dist/{chunk-WF6AYHOS.js → chunk-UMDOSJUH.js} +4 -4
  44. package/dist/{chunk-WF6AYHOS.js.map → chunk-UMDOSJUH.js.map} +1 -1
  45. package/dist/{chunk-23KQF47X.js → chunk-UUEAFG6V.js} +3 -3
  46. package/dist/{chunk-23KQF47X.js.map → chunk-UUEAFG6V.js.map} +1 -1
  47. package/dist/chunk-VAVS6WRZ.cjs +206 -0
  48. package/dist/chunk-VAVS6WRZ.cjs.map +1 -0
  49. package/dist/{chunk-SRICSNL4.cjs → chunk-VQLPAYQF.cjs} +12 -12
  50. package/dist/{chunk-SRICSNL4.cjs.map → chunk-VQLPAYQF.cjs.map} +1 -1
  51. package/dist/{chunk-KSSTFLV2.cjs → chunk-Z44A7NPD.cjs} +6 -6
  52. package/dist/{chunk-KSSTFLV2.cjs.map → chunk-Z44A7NPD.cjs.map} +1 -1
  53. package/dist/code-block.cjs +19 -0
  54. package/dist/code-block.cjs.map +1 -0
  55. package/dist/code-block.d.cts +55 -0
  56. package/dist/code-block.d.ts +55 -0
  57. package/dist/code-block.js +10 -0
  58. package/dist/code-block.js.map +1 -0
  59. package/dist/code-view.cjs +3 -2
  60. package/dist/code-view.js +2 -1
  61. package/dist/composer.cjs +1 -1
  62. package/dist/composer.js +1 -1
  63. package/dist/content-renderer.cjs +5 -4
  64. package/dist/content-renderer.js +2 -1
  65. package/dist/dropdown.cjs +1 -1
  66. package/dist/dropdown.js +1 -1
  67. package/dist/editor.cjs +10 -8
  68. package/dist/editor.js +8 -6
  69. package/dist/index.cjs +114 -107
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/index.d.cts +1 -0
  72. package/dist/index.d.ts +1 -0
  73. package/dist/index.js +28 -25
  74. package/dist/index.js.map +1 -1
  75. package/dist/input.cjs +3 -3
  76. package/dist/input.js +3 -3
  77. package/dist/inputs.cjs +10 -10
  78. package/dist/inputs.js +5 -5
  79. package/dist/json-editor.cjs +16 -16
  80. package/dist/json-editor.js +5 -5
  81. package/dist/magic-wand.cjs +2 -2
  82. package/dist/magic-wand.js +2 -2
  83. package/dist/mobile-menu.cjs +1 -1
  84. package/dist/mobile-menu.js +1 -1
  85. package/dist/paste-pills.cjs +1 -1
  86. package/dist/paste-pills.js +1 -1
  87. package/dist/popover.cjs +1 -1
  88. package/dist/popover.js +1 -1
  89. package/dist/prompt-input.cjs +1 -1
  90. package/dist/prompt-input.js +1 -1
  91. package/dist/reason-tag.cjs +1 -1
  92. package/dist/reason-tag.js +1 -1
  93. package/dist/select.cjs +5 -5
  94. package/dist/select.js +4 -4
  95. package/dist/sidebar.cjs +1 -1
  96. package/dist/sidebar.js +1 -1
  97. package/dist/tooltip.cjs +1 -1
  98. package/dist/tooltip.js +1 -1
  99. package/docs/CodeBlock.md +84 -0
  100. package/package.json +11 -1
  101. package/dist/chunk-3AA2KGZG.js.map +0 -1
  102. package/dist/chunk-CKO2KCUN.cjs.map +0 -1
  103. package/dist/chunk-FBWUXSKH.js.map +0 -1
  104. package/dist/chunk-G7227RTY.cjs.map +0 -1
@@ -0,0 +1,177 @@
1
+ import { Button } from './chunk-4GPH7HOR.js';
2
+ import { createContext, useRef, useContext, useState, useMemo, useLayoutEffect, useEffect, useCallback } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
+
6
+ var FEEDBACK_MS = 2e3;
7
+ var WRITE_TIMEOUT_MS = 5e3;
8
+ var CopyContext = createContext(null);
9
+ async function defaultClipboardWriter(payload) {
10
+ const clip = typeof navigator !== "undefined" ? navigator.clipboard : void 0;
11
+ if (!clip) throw new Error("Clipboard API unavailable");
12
+ const Item = globalThis.ClipboardItem;
13
+ if (payload.html && Item && typeof clip.write === "function") {
14
+ try {
15
+ await clip.write([
16
+ new Item({
17
+ "text/html": new Blob([payload.html], { type: "text/html" }),
18
+ "text/plain": new Blob([payload.text], { type: "text/plain" })
19
+ })
20
+ ]);
21
+ return;
22
+ } catch {
23
+ }
24
+ }
25
+ if (typeof clip.writeText !== "function") throw new Error("Clipboard writeText unavailable");
26
+ await clip.writeText(payload.text);
27
+ }
28
+ async function runWriter(writer, payload) {
29
+ let timer;
30
+ try {
31
+ const result = await Promise.race([
32
+ Promise.resolve().then(() => writer(payload)),
33
+ new Promise((resolve) => {
34
+ timer = setTimeout(() => resolve(false), WRITE_TIMEOUT_MS);
35
+ })
36
+ ]);
37
+ return result !== false;
38
+ } catch {
39
+ return false;
40
+ } finally {
41
+ if (timer) clearTimeout(timer);
42
+ }
43
+ }
44
+ function codeText(pre, fromMarkdown) {
45
+ const text = (pre.querySelector("code") ?? pre).textContent ?? "";
46
+ return fromMarkdown && text.endsWith("\n") ? text.slice(0, -1) : text;
47
+ }
48
+ function tableTsv(table) {
49
+ const rows = [];
50
+ for (const tr of Array.from(table.querySelectorAll("tr"))) {
51
+ if (tr.closest("table") !== table) continue;
52
+ const cells = Array.from(tr.children).filter((c) => c.tagName === "TD" || c.tagName === "TH");
53
+ rows.push(cells.map((c) => cellText(c)).join(" "));
54
+ }
55
+ return rows.join("\n");
56
+ }
57
+ function cellText(cell) {
58
+ const clone = cell.cloneNode(true);
59
+ for (const br of Array.from(clone.querySelectorAll("br"))) br.replaceWith(" ");
60
+ return (clone.textContent ?? "").replace(/[\t\r\n]+/g, " ").replace(/ {2,}/g, " ").trim();
61
+ }
62
+ function HtmlChunk({
63
+ html,
64
+ fromMarkdown,
65
+ tail = false
66
+ }) {
67
+ const ref = useRef(null);
68
+ const ctx = useContext(CopyContext);
69
+ const [targets, setTargets] = useState([]);
70
+ const code = ctx?.code ?? false;
71
+ const table = ctx?.table ?? false;
72
+ const holdLastCode = tail && (ctx?.holdTailCode ?? false);
73
+ const inner = useMemo(() => ({ __html: html }), [html]);
74
+ useLayoutEffect(() => {
75
+ const root = ref.current;
76
+ if (!root || !code && !table) {
77
+ setTargets([]);
78
+ return;
79
+ }
80
+ const found = [];
81
+ const selector = [code && "pre", table && "table"].filter(Boolean).join(",");
82
+ const inProgress = holdLastCode ? Array.from(root.querySelectorAll("pre")).pop() : void 0;
83
+ for (const el of Array.from(root.querySelectorAll(selector))) {
84
+ if (el === inProgress) continue;
85
+ const kind = el.tagName === "PRE" ? "code" : "table";
86
+ const wrapper = document.createElement("div");
87
+ wrapper.setAttribute("data-react-fancy-content-copy-block", kind);
88
+ wrapper.className = kind === "code" ? "group relative" : "group relative flex flex-col";
89
+ wrapper.style.position = "relative";
90
+ const host = document.createElement("div");
91
+ host.setAttribute("data-react-fancy-content-copy-host", "");
92
+ host.className = kind === "code" ? "absolute right-2 top-2 z-10" : "flex justify-end";
93
+ el.replaceWith(wrapper);
94
+ if (kind === "table") wrapper.append(host, el);
95
+ else wrapper.append(el, host);
96
+ found.push({ kind, el, host });
97
+ }
98
+ setTargets(found);
99
+ return () => {
100
+ for (const t of found) {
101
+ const wrapper = t.host.parentElement;
102
+ if (wrapper?.parentNode) wrapper.replaceWith(t.el);
103
+ }
104
+ };
105
+ }, [html, code, table, holdLastCode]);
106
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
107
+ /* @__PURE__ */ jsx("div", { ref, dangerouslySetInnerHTML: inner }),
108
+ targets.map(
109
+ (t, i) => createPortal(
110
+ /* @__PURE__ */ jsx(CopyButton, { kind: t.kind, target: t.el, fromMarkdown }),
111
+ t.host,
112
+ `${i}`
113
+ )
114
+ )
115
+ ] });
116
+ }
117
+ function CopyButton({
118
+ kind,
119
+ target,
120
+ fromMarkdown
121
+ }) {
122
+ const ctx = useContext(CopyContext);
123
+ const [state, setState] = useState("idle");
124
+ const timer = useRef(void 0);
125
+ const btn = useRef(null);
126
+ useEffect(() => () => clearTimeout(timer.current), []);
127
+ const onClick = useCallback(async () => {
128
+ if (!ctx || !btn.current) return;
129
+ const text = kind === "code" ? codeText(target, fromMarkdown) : tableTsv(target);
130
+ const ok = await ctx.copy({ kind, text, html: target.outerHTML }, btn.current);
131
+ setState(ok ? "copied" : "failed");
132
+ clearTimeout(timer.current);
133
+ timer.current = setTimeout(() => setState("idle"), FEEDBACK_MS);
134
+ }, [ctx, kind, target, fromMarkdown]);
135
+ const idleLabel = kind === "code" ? "Copy code" : "Copy table";
136
+ const label = state === "copied" ? "Copied" : state === "failed" ? "Copy failed" : idleLabel;
137
+ return /* @__PURE__ */ jsx(
138
+ Button,
139
+ {
140
+ ref: btn,
141
+ type: "button",
142
+ size: "xs",
143
+ variant: "ghost",
144
+ icon: state === "copied" ? "check" : state === "failed" ? "x" : "copy",
145
+ "aria-label": label,
146
+ title: label,
147
+ "data-react-fancy-content-copy": kind,
148
+ "data-copy-state": state,
149
+ onClick,
150
+ className: kind === "code" ? "text-zinc-300 hover:bg-zinc-800 hover:text-white opacity-70 group-hover:opacity-100 focus-visible:opacity-100" : "opacity-70 group-hover:opacity-100 focus-visible:opacity-100"
151
+ }
152
+ );
153
+ }
154
+ function useCopyPipeline({
155
+ writer,
156
+ onCopy,
157
+ rootRef,
158
+ announce
159
+ }) {
160
+ const latest = useRef({ writer, onCopy, announce });
161
+ latest.current = { writer, onCopy, announce };
162
+ return useCallback(
163
+ async (payload, button) => {
164
+ const { writer: w, onCopy: report, announce: say } = latest.current;
165
+ const ok = await runWriter(w ?? defaultClipboardWriter, payload);
166
+ say(ok ? "Copied" : "Copy failed");
167
+ const all = rootRef.current ? Array.from(rootRef.current.querySelectorAll("[data-react-fancy-content-copy]")) : [];
168
+ report?.({ ...payload, index: all.indexOf(button), ok });
169
+ return ok;
170
+ },
171
+ [rootRef]
172
+ );
173
+ }
174
+
175
+ export { CopyContext, HtmlChunk, defaultClipboardWriter, runWriter, useCopyPipeline };
176
+ //# sourceMappingURL=chunk-J2BWXCES.js.map
177
+ //# sourceMappingURL=chunk-J2BWXCES.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ContentRenderer/copy.tsx"],"names":[],"mappings":"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","file":"chunk-J2BWXCES.js","sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"../Button/Button\";\nimport type {\n ContentClipboardPayload,\n ContentClipboardWriter,\n ContentCopyEvent,\n ContentCopyKind,\n} from \"./ContentRenderer.types\";\n\n/** How long the check icon stays after a copy. */\nconst FEEDBACK_MS = 2000;\n/** A clipboard write that never settles is a silent failure; give up after this. */\nconst WRITE_TIMEOUT_MS = 5000;\n\nexport interface CopyContextValue {\n code: boolean;\n table: boolean;\n /** Write, announce, and report one copy. Resolves to whether it worked. */\n copy: (payload: ContentClipboardPayload, button: HTMLElement) => Promise<boolean>;\n /**\n * Progressive streaming closed an open code fence: the last code block of\n * the tail chunk is still arriving and gets no copy button until it closes.\n */\n holdTailCode?: boolean;\n}\n\nexport const CopyContext = createContext<CopyContextValue | null>(null);\n\n/**\n * Default clipboard writer: text/html + text/plain via `ClipboardItem` where\n * the browser has it, else (or if that write rejects) plain `writeText`.\n * Throws when nothing could be written, so the caller can say so.\n */\nexport async function defaultClipboardWriter(payload: ContentClipboardPayload): Promise<void> {\n const clip = typeof navigator !== \"undefined\" ? navigator.clipboard : undefined;\n if (!clip) throw new Error(\"Clipboard API unavailable\");\n\n const Item = (globalThis as { ClipboardItem?: typeof ClipboardItem }).ClipboardItem;\n if (payload.html && Item && typeof clip.write === \"function\") {\n try {\n await clip.write([\n new Item({\n \"text/html\": new Blob([payload.html], { type: \"text/html\" }),\n \"text/plain\": new Blob([payload.text], { type: \"text/plain\" }),\n }),\n ]);\n return;\n } catch {\n // Rich write refused (permissions, unsupported type): fall back to text.\n }\n }\n if (typeof clip.writeText !== \"function\") throw new Error(\"Clipboard writeText unavailable\");\n await clip.writeText(payload.text);\n}\n\n/** Run a writer, treating a throw, a rejection, `false`, or a hang as failure. */\nexport async function runWriter(\n writer: ContentClipboardWriter,\n payload: ContentClipboardPayload,\n): Promise<boolean> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n Promise.resolve().then(() => writer(payload)),\n new Promise<false>((resolve) => {\n timer = setTimeout(() => resolve(false), WRITE_TIMEOUT_MS);\n }),\n ]);\n return result !== false;\n } catch {\n return false;\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** Code exactly as written: the `<code>` text, minus the newline marked appends. */\nexport function codeText(pre: HTMLElement, fromMarkdown: boolean): string {\n const text = (pre.querySelector(\"code\") ?? pre).textContent ?? \"\";\n return fromMarkdown && text.endsWith(\"\\n\") ? text.slice(0, -1) : text;\n}\n\n/** A table as TSV: tab between cells, newline between rows, no trailing newline. */\nexport function tableTsv(table: HTMLTableElement): string {\n const rows: string[] = [];\n for (const tr of Array.from(table.querySelectorAll(\"tr\"))) {\n // Only this table's own cells, not those of a table nested in a cell.\n if (tr.closest(\"table\") !== table) continue;\n const cells = Array.from(tr.children).filter((c) => c.tagName === \"TD\" || c.tagName === \"TH\");\n rows.push(cells.map((c) => cellText(c)).join(\"\\t\"));\n }\n return rows.join(\"\\n\");\n}\n\nfunction cellText(cell: Element): string {\n const clone = cell.cloneNode(true) as Element;\n for (const br of Array.from(clone.querySelectorAll(\"br\"))) br.replaceWith(\" \");\n return (clone.textContent ?? \"\").replace(/[\\t\\r\\n]+/g, \" \").replace(/ {2,}/g, \" \").trim();\n}\n\ninterface Target {\n kind: ContentCopyKind;\n el: HTMLElement;\n host: HTMLElement;\n}\n\n/**\n * Sanitised HTML rendered with `dangerouslySetInnerHTML`, plus a react-fancy\n * copy `Button` portalled next to every `<pre>` and `<table>` in it.\n *\n * Each block is wrapped in a `data-react-fancy-content-copy-block` element and\n * the button lives beside the block, never inside it, so the button's own text\n * can never end up in what is copied.\n */\nexport function HtmlChunk({\n html,\n fromMarkdown,\n tail = false,\n}: {\n html: string;\n fromMarkdown: boolean;\n /** This chunk is the last thing rendered, so it holds any block still arriving. */\n tail?: boolean;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const ctx = useContext(CopyContext);\n const [targets, setTargets] = useState<Target[]>([]);\n const code = ctx?.code ?? false;\n const table = ctx?.table ?? false;\n const holdLastCode = tail && (ctx?.holdTailCode ?? false);\n // React 19 re-assigns innerHTML whenever this prop is a NEW object, even\n // with the same string, which would wipe the wrappers on every re-render\n // (including the one that mounts the buttons). One object per string.\n const inner = useMemo(() => ({ __html: html }), [html]);\n\n useLayoutEffect(() => {\n const root = ref.current;\n if (!root || (!code && !table)) {\n setTargets([]);\n return;\n }\n const found: Target[] = [];\n const selector = [code && \"pre\", table && \"table\"].filter(Boolean).join(\",\");\n const inProgress = holdLastCode ? Array.from(root.querySelectorAll(\"pre\")).pop() : undefined;\n for (const el of Array.from(root.querySelectorAll<HTMLElement>(selector))) {\n if (el === inProgress) continue;\n const kind: ContentCopyKind = el.tagName === \"PRE\" ? \"code\" : \"table\";\n const wrapper = document.createElement(\"div\");\n wrapper.setAttribute(\"data-react-fancy-content-copy-block\", kind);\n wrapper.className = kind === \"code\" ? \"group relative\" : \"group relative flex flex-col\";\n // Inline too: the code button is absolute, and a host whose Tailwind\n // never generated `relative` would let it escape the block (genie#1290).\n wrapper.style.position = \"relative\";\n const host = document.createElement(\"div\");\n host.setAttribute(\"data-react-fancy-content-copy-host\", \"\");\n host.className =\n kind === \"code\" ? \"absolute right-2 top-2 z-10\" : \"flex justify-end\";\n el.replaceWith(wrapper);\n if (kind === \"table\") wrapper.append(host, el);\n else wrapper.append(el, host);\n found.push({ kind, el, host });\n }\n setTargets(found);\n return () => {\n for (const t of found) {\n const wrapper = t.host.parentElement;\n if (wrapper?.parentNode) wrapper.replaceWith(t.el);\n }\n };\n }, [html, code, table, holdLastCode]);\n\n return (\n <>\n <div ref={ref} dangerouslySetInnerHTML={inner} />\n {targets.map((t, i) =>\n createPortal(\n <CopyButton kind={t.kind} target={t.el} fromMarkdown={fromMarkdown} />,\n t.host,\n `${i}`,\n ),\n )}\n </>\n );\n}\n\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\nfunction CopyButton({\n kind,\n target,\n fromMarkdown,\n}: {\n kind: ContentCopyKind;\n target: HTMLElement;\n fromMarkdown: boolean;\n}) {\n const ctx = useContext(CopyContext);\n const [state, setState] = useState<CopyState>(\"idle\");\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const btn = useRef<HTMLButtonElement>(null);\n\n useEffect(() => () => clearTimeout(timer.current), []);\n\n const onClick = useCallback(async () => {\n if (!ctx || !btn.current) return;\n const text =\n kind === \"code\" ? codeText(target, fromMarkdown) : tableTsv(target as HTMLTableElement);\n const ok = await ctx.copy({ kind, text, html: target.outerHTML }, btn.current);\n setState(ok ? \"copied\" : \"failed\");\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setState(\"idle\"), FEEDBACK_MS);\n }, [ctx, kind, target, fromMarkdown]);\n\n const idleLabel = kind === \"code\" ? \"Copy code\" : \"Copy table\";\n const label = state === \"copied\" ? \"Copied\" : state === \"failed\" ? \"Copy failed\" : idleLabel;\n\n return (\n <Button\n ref={btn}\n type=\"button\"\n size=\"xs\"\n variant=\"ghost\"\n icon={state === \"copied\" ? \"check\" : state === \"failed\" ? \"x\" : \"copy\"}\n aria-label={label}\n title={label}\n data-react-fancy-content-copy={kind}\n data-copy-state={state}\n onClick={onClick}\n className={\n kind === \"code\"\n ? \"text-zinc-300 hover:bg-zinc-800 hover:text-white opacity-70 group-hover:opacity-100 focus-visible:opacity-100\"\n : \"opacity-70 group-hover:opacity-100 focus-visible:opacity-100\"\n }\n />\n );\n}\n\n/** Build the copy pipeline a ContentRenderer root shares with its chunks. */\nexport function useCopyPipeline({\n writer,\n onCopy,\n rootRef,\n announce,\n}: {\n writer: ContentClipboardWriter | undefined;\n onCopy: ((event: ContentCopyEvent) => void) | undefined;\n rootRef: RefObject<HTMLElement | null>;\n announce: (message: string) => void;\n}) {\n // Read the latest props at click time without re-creating the context.\n const latest = useRef({ writer, onCopy, announce });\n latest.current = { writer, onCopy, announce };\n\n return useCallback(\n async (payload: ContentClipboardPayload, button: HTMLElement) => {\n const { writer: w, onCopy: report, announce: say } = latest.current;\n const ok = await runWriter(w ?? defaultClipboardWriter, payload);\n say(ok ? \"Copied\" : \"Copy failed\");\n const all = rootRef.current\n ? Array.from(rootRef.current.querySelectorAll(\"[data-react-fancy-content-copy]\"))\n : [];\n report?.({ ...payload, index: all.indexOf(button), ok });\n return ok;\n },\n [rootRef],\n );\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ var chunk7ZCNZUZK_cjs = require('./chunk-7ZCNZUZK.cjs');
3
4
  var chunk2C64OVOZ_cjs = require('./chunk-2C64OVOZ.cjs');
4
5
  var chunkNZHVDWOM_cjs = require('./chunk-NZHVDWOM.cjs');
5
6
  var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
6
7
  var marked = require('marked');
7
8
  var react = require('react');
8
- var reactDom = require('react-dom');
9
9
  var jsxRuntime = require('react/jsx-runtime');
10
10
 
11
11
  // src/components/ContentRenderer/extensions.ts
@@ -1046,174 +1046,6 @@ function streamingProgressive(src, tags, markdown) {
1046
1046
  for (let k = stack.length - 1; k >= 0; k--) out += `</${stack[k].name}>`;
1047
1047
  return { source: out, openFence: fence !== null };
1048
1048
  }
1049
- var FEEDBACK_MS = 2e3;
1050
- var WRITE_TIMEOUT_MS = 5e3;
1051
- var CopyContext = react.createContext(null);
1052
- async function defaultClipboardWriter(payload) {
1053
- const clip = typeof navigator !== "undefined" ? navigator.clipboard : void 0;
1054
- if (!clip) throw new Error("Clipboard API unavailable");
1055
- const Item = globalThis.ClipboardItem;
1056
- if (payload.html && Item && typeof clip.write === "function") {
1057
- try {
1058
- await clip.write([
1059
- new Item({
1060
- "text/html": new Blob([payload.html], { type: "text/html" }),
1061
- "text/plain": new Blob([payload.text], { type: "text/plain" })
1062
- })
1063
- ]);
1064
- return;
1065
- } catch {
1066
- }
1067
- }
1068
- if (typeof clip.writeText !== "function") throw new Error("Clipboard writeText unavailable");
1069
- await clip.writeText(payload.text);
1070
- }
1071
- async function runWriter(writer, payload) {
1072
- let timer;
1073
- try {
1074
- const result = await Promise.race([
1075
- Promise.resolve().then(() => writer(payload)),
1076
- new Promise((resolve) => {
1077
- timer = setTimeout(() => resolve(false), WRITE_TIMEOUT_MS);
1078
- })
1079
- ]);
1080
- return result !== false;
1081
- } catch {
1082
- return false;
1083
- } finally {
1084
- if (timer) clearTimeout(timer);
1085
- }
1086
- }
1087
- function codeText(pre, fromMarkdown) {
1088
- const text = (pre.querySelector("code") ?? pre).textContent ?? "";
1089
- return fromMarkdown && text.endsWith("\n") ? text.slice(0, -1) : text;
1090
- }
1091
- function tableTsv(table) {
1092
- const rows = [];
1093
- for (const tr of Array.from(table.querySelectorAll("tr"))) {
1094
- if (tr.closest("table") !== table) continue;
1095
- const cells = Array.from(tr.children).filter((c) => c.tagName === "TD" || c.tagName === "TH");
1096
- rows.push(cells.map((c) => cellText(c)).join(" "));
1097
- }
1098
- return rows.join("\n");
1099
- }
1100
- function cellText(cell) {
1101
- const clone = cell.cloneNode(true);
1102
- for (const br of Array.from(clone.querySelectorAll("br"))) br.replaceWith(" ");
1103
- return (clone.textContent ?? "").replace(/[\t\r\n]+/g, " ").replace(/ {2,}/g, " ").trim();
1104
- }
1105
- function HtmlChunk({
1106
- html,
1107
- fromMarkdown,
1108
- tail = false
1109
- }) {
1110
- const ref = react.useRef(null);
1111
- const ctx = react.useContext(CopyContext);
1112
- const [targets, setTargets] = react.useState([]);
1113
- const code = ctx?.code ?? false;
1114
- const table = ctx?.table ?? false;
1115
- const holdLastCode = tail && (ctx?.holdTailCode ?? false);
1116
- const inner = react.useMemo(() => ({ __html: html }), [html]);
1117
- react.useLayoutEffect(() => {
1118
- const root = ref.current;
1119
- if (!root || !code && !table) {
1120
- setTargets([]);
1121
- return;
1122
- }
1123
- const found = [];
1124
- const selector = [code && "pre", table && "table"].filter(Boolean).join(",");
1125
- const inProgress = holdLastCode ? Array.from(root.querySelectorAll("pre")).pop() : void 0;
1126
- for (const el of Array.from(root.querySelectorAll(selector))) {
1127
- if (el === inProgress) continue;
1128
- const kind = el.tagName === "PRE" ? "code" : "table";
1129
- const wrapper = document.createElement("div");
1130
- wrapper.setAttribute("data-react-fancy-content-copy-block", kind);
1131
- wrapper.className = kind === "code" ? "group relative" : "group relative flex flex-col";
1132
- wrapper.style.position = "relative";
1133
- const host = document.createElement("div");
1134
- host.setAttribute("data-react-fancy-content-copy-host", "");
1135
- host.className = kind === "code" ? "absolute right-2 top-2 z-10" : "flex justify-end";
1136
- el.replaceWith(wrapper);
1137
- if (kind === "table") wrapper.append(host, el);
1138
- else wrapper.append(el, host);
1139
- found.push({ kind, el, host });
1140
- }
1141
- setTargets(found);
1142
- return () => {
1143
- for (const t of found) {
1144
- const wrapper = t.host.parentElement;
1145
- if (wrapper?.parentNode) wrapper.replaceWith(t.el);
1146
- }
1147
- };
1148
- }, [html, code, table, holdLastCode]);
1149
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1150
- /* @__PURE__ */ jsxRuntime.jsx("div", { ref, dangerouslySetInnerHTML: inner }),
1151
- targets.map(
1152
- (t, i) => reactDom.createPortal(
1153
- /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { kind: t.kind, target: t.el, fromMarkdown }),
1154
- t.host,
1155
- `${i}`
1156
- )
1157
- )
1158
- ] });
1159
- }
1160
- function CopyButton({
1161
- kind,
1162
- target,
1163
- fromMarkdown
1164
- }) {
1165
- const ctx = react.useContext(CopyContext);
1166
- const [state, setState] = react.useState("idle");
1167
- const timer = react.useRef(void 0);
1168
- const btn = react.useRef(null);
1169
- react.useEffect(() => () => clearTimeout(timer.current), []);
1170
- const onClick = react.useCallback(async () => {
1171
- if (!ctx || !btn.current) return;
1172
- const text = kind === "code" ? codeText(target, fromMarkdown) : tableTsv(target);
1173
- const ok = await ctx.copy({ kind, text, html: target.outerHTML }, btn.current);
1174
- setState(ok ? "copied" : "failed");
1175
- clearTimeout(timer.current);
1176
- timer.current = setTimeout(() => setState("idle"), FEEDBACK_MS);
1177
- }, [ctx, kind, target, fromMarkdown]);
1178
- const idleLabel = kind === "code" ? "Copy code" : "Copy table";
1179
- const label = state === "copied" ? "Copied" : state === "failed" ? "Copy failed" : idleLabel;
1180
- return /* @__PURE__ */ jsxRuntime.jsx(
1181
- chunkNZHVDWOM_cjs.Button,
1182
- {
1183
- ref: btn,
1184
- type: "button",
1185
- size: "xs",
1186
- variant: "ghost",
1187
- icon: state === "copied" ? "check" : state === "failed" ? "x" : "copy",
1188
- "aria-label": label,
1189
- title: label,
1190
- "data-react-fancy-content-copy": kind,
1191
- "data-copy-state": state,
1192
- onClick,
1193
- className: kind === "code" ? "text-zinc-300 hover:bg-zinc-800 hover:text-white opacity-70 group-hover:opacity-100 focus-visible:opacity-100" : "opacity-70 group-hover:opacity-100 focus-visible:opacity-100"
1194
- }
1195
- );
1196
- }
1197
- function useCopyPipeline({
1198
- writer,
1199
- onCopy,
1200
- rootRef,
1201
- announce
1202
- }) {
1203
- const latest = react.useRef({ writer, onCopy, announce });
1204
- latest.current = { writer, onCopy, announce };
1205
- return react.useCallback(
1206
- async (payload, button) => {
1207
- const { writer: w, onCopy: report, announce: say } = latest.current;
1208
- const ok = await runWriter(w ?? defaultClipboardWriter, payload);
1209
- say(ok ? "Copied" : "Copy failed");
1210
- const all = rootRef.current ? Array.from(rootRef.current.querySelectorAll("[data-react-fancy-content-copy]")) : [];
1211
- report?.({ ...payload, index: all.indexOf(button), ok });
1212
- return ok;
1213
- },
1214
- [rootRef]
1215
- );
1216
- }
1217
1049
  var MAX_DEPTH = 8;
1218
1050
  function lastIndexWith(items, renders) {
1219
1051
  for (let i = items.length - 1; i >= 0; i--) if (renders(items[i])) return i;
@@ -1287,13 +1119,13 @@ function RenderedContent({
1287
1119
  const renderHtml = (content) => unsafe ? content : chunkNZHVDWOM_cjs.sanitizeHtml(content);
1288
1120
  if (segments.length === 0) return null;
1289
1121
  if (segments.length === 1 && segments[0].type === "html") {
1290
- return /* @__PURE__ */ jsxRuntime.jsx(HtmlChunk, { html: renderHtml(segments[0].content), fromMarkdown, tail });
1122
+ return /* @__PURE__ */ jsxRuntime.jsx(chunk7ZCNZUZK_cjs.HtmlChunk, { html: renderHtml(segments[0].content), fromMarkdown, tail });
1291
1123
  }
1292
1124
  const last = tail ? lastIndexWith(segments, (s) => s.type === "extension" || s.content.trim() !== "") : -1;
1293
1125
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments.map((segment, i) => {
1294
1126
  if (segment.type === "html") {
1295
1127
  return segment.content ? /* @__PURE__ */ jsxRuntime.jsx(
1296
- HtmlChunk,
1128
+ chunk7ZCNZUZK_cjs.HtmlChunk,
1297
1129
  {
1298
1130
  html: renderHtml(segment.content),
1299
1131
  fromMarkdown,
@@ -1357,7 +1189,7 @@ function ContentRenderer({
1357
1189
  setAnnouncement("");
1358
1190
  queueMicrotask(() => setAnnouncement(message));
1359
1191
  }, []);
1360
- const copy = useCopyPipeline({ writer: clipboardWriter, onCopy, rootRef, announce });
1192
+ const copy = chunk7ZCNZUZK_cjs.useCopyPipeline({ writer: clipboardWriter, onCopy, rootRef, announce });
1361
1193
  const copyContext = react.useMemo(
1362
1194
  () => ({ code: codeOn, table: tableOn, copy, holdTailCode: openFence }),
1363
1195
  [codeOn, tableOn, copy, openFence]
@@ -1373,7 +1205,7 @@ function ContentRenderer({
1373
1205
  style: contain ? { lineHeight: lineSpacing, position: "relative" } : { lineHeight: lineSpacing },
1374
1206
  className: chunkZU5Q77OT_cjs.cn("text-sm", proseClasses, className),
1375
1207
  children: [
1376
- /* @__PURE__ */ jsxRuntime.jsx(CopyContext.Provider, { value: copyContext, children: /* @__PURE__ */ jsxRuntime.jsx(
1208
+ /* @__PURE__ */ jsxRuntime.jsx(chunk7ZCNZUZK_cjs.CopyContext.Provider, { value: copyContext, children: /* @__PURE__ */ jsxRuntime.jsx(
1377
1209
  ContentBody,
1378
1210
  {
1379
1211
  source,
@@ -1411,5 +1243,5 @@ exports.proseClasses = proseClasses;
1411
1243
  exports.registerExtension = registerExtension;
1412
1244
  exports.registerExtensions = registerExtensions;
1413
1245
  exports.renderMarkdown = renderMarkdown;
1414
- //# sourceMappingURL=chunk-CKO2KCUN.cjs.map
1415
- //# sourceMappingURL=chunk-CKO2KCUN.cjs.map
1246
+ //# sourceMappingURL=chunk-MPCZUZ4O.cjs.map
1247
+ //# sourceMappingURL=chunk-MPCZUZ4O.cjs.map