@particle-academy/react-fancy 6.2.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.
- package/CHANGELOG.md +60 -0
- package/README.md +2 -0
- package/dist/autocomplete.cjs +5 -5
- package/dist/autocomplete.js +4 -4
- package/dist/breadcrumbs.cjs +2 -2
- package/dist/breadcrumbs.d.cts +13 -2
- package/dist/breadcrumbs.d.ts +13 -2
- package/dist/breadcrumbs.js +1 -1
- package/dist/card.cjs +8 -8
- package/dist/card.js +2 -2
- package/dist/chat-thread.cjs +5 -4
- package/dist/chat-thread.js +3 -2
- package/dist/{chunk-K7JOZQRK.cjs → chunk-2G6TIX5Q.cjs} +4 -4
- package/dist/{chunk-K7JOZQRK.cjs.map → chunk-2G6TIX5Q.cjs.map} +1 -1
- package/dist/chunk-5EW47IH7.js +194 -0
- package/dist/chunk-5EW47IH7.js.map +1 -0
- package/dist/{chunk-TH4JZAMK.js → chunk-5TP642UT.js} +4 -4
- package/dist/{chunk-TH4JZAMK.js.map → chunk-5TP642UT.js.map} +1 -1
- package/dist/chunk-6BB32POL.js +29 -0
- package/dist/chunk-6BB32POL.js.map +1 -0
- package/dist/{chunk-XIA2UAVO.js → chunk-6GVOW3UL.js} +4 -4
- package/dist/{chunk-XIA2UAVO.js.map → chunk-6GVOW3UL.js.map} +1 -1
- package/dist/{chunk-4JT2QANA.cjs → chunk-6H7ZN23X.cjs} +3 -3
- package/dist/{chunk-4JT2QANA.cjs.map → chunk-6H7ZN23X.cjs.map} +1 -1
- package/dist/chunk-7ZCNZUZK.cjs +183 -0
- package/dist/chunk-7ZCNZUZK.cjs.map +1 -0
- package/dist/chunk-AHZIT3CM.js +204 -0
- package/dist/chunk-AHZIT3CM.js.map +1 -0
- package/dist/{chunk-MP55W37V.cjs → chunk-BYO5RUDE.cjs} +4 -4
- package/dist/{chunk-MP55W37V.cjs.map → chunk-BYO5RUDE.cjs.map} +1 -1
- package/dist/{chunk-2XO6EYZ7.js → chunk-EENHSMV2.js} +3 -3
- package/dist/{chunk-2XO6EYZ7.js.map → chunk-EENHSMV2.js.map} +1 -1
- package/dist/{chunk-WJHPZS3U.js → chunk-GTS3QA7M.js} +11 -4
- package/dist/chunk-GTS3QA7M.js.map +1 -0
- package/dist/{chunk-7JLKOVHX.cjs → chunk-HLI6RB5V.cjs} +4 -4
- package/dist/{chunk-7JLKOVHX.cjs.map → chunk-HLI6RB5V.cjs.map} +1 -1
- package/dist/chunk-HZUKPYR3.cjs +31 -0
- package/dist/chunk-HZUKPYR3.cjs.map +1 -0
- package/dist/chunk-J2BWXCES.js +177 -0
- package/dist/chunk-J2BWXCES.js.map +1 -0
- package/dist/{chunk-CKO2KCUN.cjs → chunk-MPCZUZ4O.cjs} +7 -175
- package/dist/chunk-MPCZUZ4O.cjs.map +1 -0
- package/dist/{chunk-G7227RTY.cjs → chunk-NIAG6OF6.cjs} +4 -22
- package/dist/chunk-NIAG6OF6.cjs.map +1 -0
- package/dist/{chunk-FBWUXSKH.js → chunk-P24A2BIR.js} +4 -22
- package/dist/chunk-P24A2BIR.js.map +1 -0
- package/dist/{chunk-3AA2KGZG.js → chunk-QF2FODTG.js} +5 -173
- package/dist/chunk-QF2FODTG.js.map +1 -0
- package/dist/{chunk-A6NYZ3F5.js → chunk-RWU2MFUL.js} +4 -4
- package/dist/{chunk-A6NYZ3F5.js.map → chunk-RWU2MFUL.js.map} +1 -1
- package/dist/{chunk-EWE776WI.cjs → chunk-SKMORSBO.cjs} +11 -4
- package/dist/chunk-SKMORSBO.cjs.map +1 -0
- package/dist/{chunk-WF6AYHOS.js → chunk-UMDOSJUH.js} +4 -4
- package/dist/{chunk-WF6AYHOS.js.map → chunk-UMDOSJUH.js.map} +1 -1
- package/dist/{chunk-23KQF47X.js → chunk-UUEAFG6V.js} +3 -3
- package/dist/{chunk-23KQF47X.js.map → chunk-UUEAFG6V.js.map} +1 -1
- package/dist/chunk-VAVS6WRZ.cjs +206 -0
- package/dist/chunk-VAVS6WRZ.cjs.map +1 -0
- package/dist/{chunk-SRICSNL4.cjs → chunk-VQLPAYQF.cjs} +12 -12
- package/dist/{chunk-SRICSNL4.cjs.map → chunk-VQLPAYQF.cjs.map} +1 -1
- package/dist/chunk-Y3QAEF2P.cjs +196 -0
- package/dist/chunk-Y3QAEF2P.cjs.map +1 -0
- package/dist/{chunk-KSSTFLV2.cjs → chunk-Z44A7NPD.cjs} +6 -6
- package/dist/{chunk-KSSTFLV2.cjs.map → chunk-Z44A7NPD.cjs.map} +1 -1
- package/dist/code-block.cjs +19 -0
- package/dist/code-block.cjs.map +1 -0
- package/dist/code-block.d.cts +55 -0
- package/dist/code-block.d.ts +55 -0
- package/dist/code-block.js +10 -0
- package/dist/code-block.js.map +1 -0
- package/dist/code-view.cjs +3 -2
- package/dist/code-view.js +2 -1
- package/dist/composer.cjs +1 -1
- package/dist/composer.js +1 -1
- package/dist/content-renderer.cjs +5 -4
- package/dist/content-renderer.js +2 -1
- package/dist/dropdown.cjs +1 -1
- package/dist/dropdown.js +1 -1
- package/dist/editor.cjs +10 -8
- package/dist/editor.js +8 -6
- package/dist/index.cjs +125 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -28
- package/dist/index.js.map +1 -1
- package/dist/input.cjs +3 -3
- package/dist/input.js +3 -3
- package/dist/inputs.cjs +15 -15
- package/dist/inputs.js +6 -6
- package/dist/json-editor.cjs +16 -16
- package/dist/json-editor.js +5 -5
- package/dist/magic-wand.cjs +2 -2
- package/dist/magic-wand.js +2 -2
- package/dist/mobile-menu.cjs +1 -1
- package/dist/mobile-menu.js +1 -1
- package/dist/paste-pills.cjs +1 -1
- package/dist/paste-pills.js +1 -1
- package/dist/popover.cjs +1 -1
- package/dist/popover.js +1 -1
- package/dist/prompt-input.cjs +1 -1
- package/dist/prompt-input.js +1 -1
- package/dist/reason-tag.cjs +1 -1
- package/dist/reason-tag.js +1 -1
- package/dist/select.cjs +5 -5
- package/dist/select.js +4 -4
- package/dist/sidebar.cjs +1 -1
- package/dist/sidebar.js +1 -1
- package/dist/stepper.cjs +14 -0
- package/dist/stepper.cjs.map +1 -0
- package/dist/stepper.d.cts +72 -0
- package/dist/stepper.d.ts +72 -0
- package/dist/stepper.js +5 -0
- package/dist/stepper.js.map +1 -0
- package/dist/tooltip.cjs +1 -1
- package/dist/tooltip.js +1 -1
- package/docs/Breadcrumbs.md +10 -1
- package/docs/CodeBlock.md +84 -0
- package/docs/Stepper.md +124 -0
- package/package.json +21 -1
- package/dist/chunk-3AA2KGZG.js.map +0 -1
- package/dist/chunk-CKO2KCUN.cjs.map +0 -1
- package/dist/chunk-EWE776WI.cjs.map +0 -1
- package/dist/chunk-FBWUXSKH.js.map +0 -1
- package/dist/chunk-G7227RTY.cjs.map +0 -1
- package/dist/chunk-WJHPZS3U.js.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-
|
|
1415
|
-
//# sourceMappingURL=chunk-
|
|
1246
|
+
//# sourceMappingURL=chunk-MPCZUZ4O.cjs.map
|
|
1247
|
+
//# sourceMappingURL=chunk-MPCZUZ4O.cjs.map
|