@particle-academy/react-fancy 5.65.0 → 5.67.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 +74 -0
- package/dist/{PastePills.types-CDyotkUb.d.cts → PastePills.types-CpXzsuwJ.d.cts} +2 -0
- package/dist/{PastePills.types-CDyotkUb.d.ts → PastePills.types-CpXzsuwJ.d.ts} +2 -0
- package/dist/{PastedFilesInput-CrgNoEBd.d.ts → PastedFilesInput-Bt3KSTVN.d.ts} +1 -1
- package/dist/{PastedFilesInput-DQ1eZaHk.d.cts → PastedFilesInput-CUQeOeOA.d.cts} +1 -1
- package/dist/button.cjs +3 -4
- package/dist/button.js +1 -2
- package/dist/{chunk-COXHFZR6.js → chunk-23AVEYUP.js} +14 -8
- package/dist/chunk-23AVEYUP.js.map +1 -0
- package/dist/{chunk-C5YX5XVL.cjs → chunk-3U7PUZLI.cjs} +214 -4
- package/dist/chunk-3U7PUZLI.cjs.map +1 -0
- package/dist/{chunk-ATIDUWY6.cjs → chunk-4S5DFN5N.cjs} +12 -12
- package/dist/{chunk-ATIDUWY6.cjs.map → chunk-4S5DFN5N.cjs.map} +1 -1
- package/dist/{chunk-CMC2TOEQ.cjs → chunk-6CAXLP7D.cjs} +6 -6
- package/dist/{chunk-CMC2TOEQ.cjs.map → chunk-6CAXLP7D.cjs.map} +1 -1
- package/dist/{chunk-TQGRXJ74.cjs → chunk-7FYRFNPX.cjs} +9 -9
- package/dist/{chunk-TQGRXJ74.cjs.map → chunk-7FYRFNPX.cjs.map} +1 -1
- package/dist/{chunk-MVVHUTXA.js → chunk-B4LVQ4QI.js} +3 -3
- package/dist/{chunk-MVVHUTXA.js.map → chunk-B4LVQ4QI.js.map} +1 -1
- package/dist/{chunk-QP35Z2WB.js → chunk-BL5IKSB3.js} +3 -3
- package/dist/{chunk-QP35Z2WB.js.map → chunk-BL5IKSB3.js.map} +1 -1
- package/dist/{chunk-SZH7TFME.js → chunk-DCAD2JPP.js} +4 -4
- package/dist/{chunk-SZH7TFME.js.map → chunk-DCAD2JPP.js.map} +1 -1
- package/dist/{chunk-MCQJFMDP.cjs → chunk-E5UU666U.cjs} +478 -36
- package/dist/chunk-E5UU666U.cjs.map +1 -0
- package/dist/{chunk-L24LUSEE.js → chunk-FXOT4P4P.js} +478 -36
- package/dist/chunk-FXOT4P4P.js.map +1 -0
- package/dist/{chunk-CAUEKGMR.js → chunk-HEY4SMS2.js} +4 -4
- package/dist/{chunk-CAUEKGMR.js.map → chunk-HEY4SMS2.js.map} +1 -1
- package/dist/{chunk-QNQNGARW.cjs → chunk-HFK5SBNM.cjs} +27 -9
- package/dist/chunk-HFK5SBNM.cjs.map +1 -0
- package/dist/{chunk-TLRRMYNV.js → chunk-OXERDFFF.js} +212 -4
- package/dist/chunk-OXERDFFF.js.map +1 -0
- package/dist/{chunk-ELFTEJBT.js → chunk-QSGAFKK2.js} +3 -3
- package/dist/{chunk-ELFTEJBT.js.map → chunk-QSGAFKK2.js.map} +1 -1
- package/dist/{chunk-SYEHWUM5.cjs → chunk-RALJMI7C.cjs} +4 -4
- package/dist/{chunk-SYEHWUM5.cjs.map → chunk-RALJMI7C.cjs.map} +1 -1
- package/dist/{chunk-UM4JXBRZ.cjs → chunk-S3NB6LDV.cjs} +4 -4
- package/dist/{chunk-UM4JXBRZ.cjs.map → chunk-S3NB6LDV.cjs.map} +1 -1
- package/dist/{chunk-C463C4MM.cjs → chunk-SAG6DHQK.cjs} +22 -16
- package/dist/chunk-SAG6DHQK.cjs.map +1 -0
- package/dist/{chunk-4XHG6Q42.cjs → chunk-U5LKNGHU.cjs} +21 -21
- package/dist/{chunk-4XHG6Q42.cjs.map → chunk-U5LKNGHU.cjs.map} +1 -1
- package/dist/{chunk-M52S3TFI.js → chunk-WFR7HKJL.js} +3 -3
- package/dist/{chunk-M52S3TFI.js.map → chunk-WFR7HKJL.js.map} +1 -1
- package/dist/{chunk-NILA2LZY.js → chunk-YIKXJWO4.js} +27 -9
- package/dist/chunk-YIKXJWO4.js.map +1 -0
- package/dist/composer.cjs +4 -4
- package/dist/composer.d.cts +2 -2
- package/dist/composer.d.ts +2 -2
- package/dist/composer.js +2 -2
- package/dist/content-renderer.cjs +7 -5
- package/dist/content-renderer.d.cts +56 -4
- package/dist/content-renderer.d.ts +56 -4
- package/dist/content-renderer.js +4 -2
- package/dist/editor.cjs +6 -5
- package/dist/editor.d.cts +1 -1
- package/dist/editor.d.ts +1 -1
- package/dist/editor.js +4 -3
- package/dist/{extensions-6PVd3-vB.d.cts → extensions-DiByZIpD.d.cts} +26 -3
- package/dist/{extensions-6PVd3-vB.d.ts → extensions-DiByZIpD.d.ts} +26 -3
- package/dist/{index-CCJVT9Hu.d.cts → index-DWtSViJ3.d.cts} +7 -1
- package/dist/{index-DRlltbdV.d.ts → index-XR5t8bTq.d.ts} +7 -1
- package/dist/index.cjs +47 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +10 -11
- package/dist/index.js.map +1 -1
- package/dist/input.cjs +3 -3
- package/dist/input.d.cts +1 -1
- package/dist/input.d.ts +1 -1
- package/dist/input.js +2 -2
- package/dist/inputs.cjs +3 -3
- package/dist/inputs.d.cts +1 -1
- package/dist/inputs.d.ts +1 -1
- package/dist/inputs.js +2 -2
- package/dist/json-editor.cjs +15 -16
- package/dist/json-editor.js +4 -5
- package/dist/magic-wand.cjs +3 -4
- package/dist/magic-wand.js +2 -3
- package/dist/paste-pills.cjs +14 -14
- package/dist/paste-pills.d.cts +3 -3
- package/dist/paste-pills.d.ts +3 -3
- package/dist/paste-pills.js +1 -1
- package/dist/prompt-input.cjs +6 -7
- package/dist/prompt-input.d.cts +2 -2
- package/dist/prompt-input.d.ts +2 -2
- package/dist/prompt-input.js +3 -4
- package/dist/reason-tag.cjs +3 -4
- package/dist/reason-tag.js +2 -3
- package/docs/ContentRenderer.md +138 -3
- package/docs/PromptInput.md +24 -1
- package/package.json +1 -1
- package/dist/chunk-6TBRBN7H.js +0 -212
- package/dist/chunk-6TBRBN7H.js.map +0 -1
- package/dist/chunk-C463C4MM.cjs.map +0 -1
- package/dist/chunk-C5YX5XVL.cjs.map +0 -1
- package/dist/chunk-COXHFZR6.js.map +0 -1
- package/dist/chunk-L24LUSEE.js.map +0 -1
- package/dist/chunk-MCQJFMDP.cjs.map +0 -1
- package/dist/chunk-NILA2LZY.js.map +0 -1
- package/dist/chunk-QNQNGARW.cjs.map +0 -1
- package/dist/chunk-TLRRMYNV.js.map +0 -1
- package/dist/chunk-X2FC7ODX.cjs +0 -215
- package/dist/chunk-X2FC7ODX.cjs.map +0 -1
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk3U7PUZLI_cjs = require('./chunk-3U7PUZLI.cjs');
|
|
4
4
|
var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
|
|
5
5
|
var marked = require('marked');
|
|
6
6
|
var react = require('react');
|
|
7
|
+
var reactDom = require('react-dom');
|
|
7
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
9
|
|
|
9
10
|
// src/components/ContentRenderer/extensions.ts
|
|
11
|
+
var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "xlink:href"]);
|
|
12
|
+
function safeAttributes(attrs) {
|
|
13
|
+
const out = {};
|
|
14
|
+
for (const [name, value] of Object.entries(attrs)) {
|
|
15
|
+
const lower = name.toLowerCase();
|
|
16
|
+
if (lower.startsWith("on") || lower === "srcdoc") continue;
|
|
17
|
+
if (URL_ATTRS.has(lower)) {
|
|
18
|
+
const safe = chunk3U7PUZLI_cjs.sanitizeHref(value);
|
|
19
|
+
if (safe === void 0) continue;
|
|
20
|
+
out[name] = safe;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
out[name] = value;
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
function tagAttributes(raw, unsafe) {
|
|
28
|
+
const attrs = raw ? parseAttributes(raw) : {};
|
|
29
|
+
return unsafe ? attrs : safeAttributes(attrs);
|
|
30
|
+
}
|
|
10
31
|
var globalRegistry = [];
|
|
11
32
|
function registerExtension(extension) {
|
|
12
33
|
const idx = globalRegistry.findIndex(
|
|
@@ -88,7 +109,7 @@ function markdownToRawHtml(markdown) {
|
|
|
88
109
|
return marked.marked.parse(markdown ?? "", { async: false });
|
|
89
110
|
}
|
|
90
111
|
function renderMarkdown(markdown, sanitize) {
|
|
91
|
-
return
|
|
112
|
+
return chunk3U7PUZLI_cjs.sanitizeHtml(markdownToRawHtml(markdown), sanitize);
|
|
92
113
|
}
|
|
93
114
|
var proseClasses = [
|
|
94
115
|
"[&_h1]:text-2xl [&_h1]:font-bold [&_h1]:mt-4 [&_h1]:mb-2",
|
|
@@ -813,67 +834,488 @@ function extensionEditorClasses(extensions) {
|
|
|
813
834
|
].join(" ");
|
|
814
835
|
}).join(" ");
|
|
815
836
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
837
|
+
|
|
838
|
+
// src/components/ContentRenderer/markdown-blocks.ts
|
|
839
|
+
var FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})(.*)$/;
|
|
840
|
+
function escapeRegExp(s) {
|
|
841
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
842
|
+
}
|
|
843
|
+
function maskInlineCode(line) {
|
|
844
|
+
let out = "";
|
|
845
|
+
let i = 0;
|
|
846
|
+
while (i < line.length) {
|
|
847
|
+
if (line[i] !== "`") {
|
|
848
|
+
out += line[i];
|
|
849
|
+
i++;
|
|
850
|
+
continue;
|
|
851
|
+
}
|
|
852
|
+
let n = 0;
|
|
853
|
+
while (line[i + n] === "`") n++;
|
|
854
|
+
const fence = "`".repeat(n);
|
|
855
|
+
let search = i + n;
|
|
856
|
+
let close = -1;
|
|
857
|
+
while (search < line.length) {
|
|
858
|
+
const at = line.indexOf(fence, search);
|
|
859
|
+
if (at < 0) break;
|
|
860
|
+
let len = 0;
|
|
861
|
+
while (line[at + len] === "`") len++;
|
|
862
|
+
if (len === n) {
|
|
863
|
+
close = at;
|
|
864
|
+
break;
|
|
865
|
+
}
|
|
866
|
+
search = at + len;
|
|
867
|
+
}
|
|
868
|
+
if (close < 0) {
|
|
869
|
+
out += fence;
|
|
870
|
+
i += n;
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
out += " ".repeat(close + n - i);
|
|
874
|
+
i = close + n;
|
|
875
|
+
}
|
|
876
|
+
return out;
|
|
877
|
+
}
|
|
878
|
+
function scan(src, names, trackFences) {
|
|
879
|
+
const tokens = [];
|
|
880
|
+
let openFenceStart = -1;
|
|
881
|
+
if (names.length === 0 && !trackFences) return { tokens, openFenceStart };
|
|
882
|
+
const tagRe = names.length ? new RegExp(`<(\\/?)(${names.map(escapeRegExp).join("|")})(?=[\\s>/])([^>]*)>`, "gi") : null;
|
|
883
|
+
let fence = null;
|
|
884
|
+
let pos = 0;
|
|
885
|
+
while (pos <= src.length) {
|
|
886
|
+
const nl = src.indexOf("\n", pos);
|
|
887
|
+
const lineEnd = nl < 0 ? src.length : nl;
|
|
888
|
+
const line = src.slice(pos, lineEnd);
|
|
889
|
+
if (trackFences) {
|
|
890
|
+
if (fence) {
|
|
891
|
+
const close = new RegExp(`^ {0,3}${fence.char === "`" ? "`" : "~"}{${fence.len},}\\s*$`);
|
|
892
|
+
if (close.test(line)) {
|
|
893
|
+
fence = null;
|
|
894
|
+
openFenceStart = -1;
|
|
895
|
+
}
|
|
896
|
+
pos = lineEnd + 1;
|
|
897
|
+
if (nl < 0) break;
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
const m = FENCE_OPEN.exec(line);
|
|
901
|
+
if (m && !(m[1][0] === "`" && m[2].includes("`"))) {
|
|
902
|
+
fence = { char: m[1][0], len: m[1].length };
|
|
903
|
+
openFenceStart = pos;
|
|
904
|
+
pos = lineEnd + 1;
|
|
905
|
+
if (nl < 0) break;
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
if (tagRe) {
|
|
910
|
+
const masked = trackFences ? maskInlineCode(line) : line;
|
|
911
|
+
const indent2 = /^ {0,3}/.exec(masked)[0].length;
|
|
912
|
+
tagRe.lastIndex = 0;
|
|
913
|
+
let t;
|
|
914
|
+
while ((t = tagRe.exec(masked)) !== null) {
|
|
915
|
+
const isClose = t[1] === "/";
|
|
916
|
+
const attrs = t[3];
|
|
917
|
+
if (isClose && attrs.trim() !== "") continue;
|
|
918
|
+
if (!isClose && attrs.trimEnd().endsWith("/")) continue;
|
|
919
|
+
tokens.push({
|
|
920
|
+
kind: isClose ? "close" : "open",
|
|
921
|
+
name: t[2].toLowerCase(),
|
|
922
|
+
start: pos + t.index,
|
|
923
|
+
end: pos + t.index + t[0].length,
|
|
924
|
+
attrs: isClose ? "" : attrs.trim(),
|
|
925
|
+
lineStart: t.index === indent2
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
if (nl < 0) break;
|
|
930
|
+
pos = lineEnd + 1;
|
|
931
|
+
}
|
|
932
|
+
return { tokens, openFenceStart };
|
|
933
|
+
}
|
|
934
|
+
function splitMarkdownBlocks(src, tags) {
|
|
935
|
+
const names = tags.map((t) => t.toLowerCase());
|
|
936
|
+
if (names.length === 0) return src ? [{ type: "markdown", source: src }] : [];
|
|
937
|
+
const { tokens } = scan(src, names, true);
|
|
938
|
+
const blocks = [];
|
|
939
|
+
let cursor = 0;
|
|
940
|
+
let i = 0;
|
|
941
|
+
while (i < tokens.length) {
|
|
942
|
+
const open = tokens[i];
|
|
943
|
+
if (open.kind !== "open" || !open.lineStart || open.start < cursor) {
|
|
944
|
+
i++;
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
let depth = 0;
|
|
948
|
+
let closeIdx = -1;
|
|
949
|
+
for (let j = i; j < tokens.length; j++) {
|
|
950
|
+
const t = tokens[j];
|
|
951
|
+
if (t.name !== open.name) continue;
|
|
952
|
+
depth += t.kind === "open" ? 1 : -1;
|
|
953
|
+
if (depth === 0) {
|
|
954
|
+
closeIdx = j;
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
if (closeIdx < 0) {
|
|
959
|
+
i++;
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
962
|
+
const close = tokens[closeIdx];
|
|
963
|
+
if (open.start > cursor) blocks.push({ type: "markdown", source: src.slice(cursor, open.start) });
|
|
964
|
+
blocks.push({ type: "tag", tag: open.name, attrs: open.attrs, body: src.slice(open.end, close.start) });
|
|
965
|
+
cursor = close.end;
|
|
966
|
+
i = closeIdx + 1;
|
|
967
|
+
}
|
|
968
|
+
if (cursor < src.length) blocks.push({ type: "markdown", source: src.slice(cursor) });
|
|
969
|
+
return blocks;
|
|
970
|
+
}
|
|
971
|
+
function streamingCut(src, tags, markdown) {
|
|
972
|
+
const names = tags.map((t) => t.toLowerCase());
|
|
973
|
+
const { tokens, openFenceStart } = scan(src, names, markdown);
|
|
974
|
+
let cut = src.length;
|
|
975
|
+
if (openFenceStart >= 0) cut = Math.min(cut, openFenceStart);
|
|
976
|
+
const stack = [];
|
|
977
|
+
for (const t of tokens) {
|
|
978
|
+
if (t.start >= cut) break;
|
|
979
|
+
if (t.kind === "open") {
|
|
980
|
+
stack.push(t);
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
for (let k = stack.length - 1; k >= 0; k--) {
|
|
984
|
+
if (stack[k].name === t.name) {
|
|
985
|
+
stack.length = k;
|
|
986
|
+
break;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (stack.length) cut = Math.min(cut, stack[0].start);
|
|
991
|
+
const lastLineStart = src.lastIndexOf("\n", cut - 1) + 1;
|
|
992
|
+
const lastLine = src.slice(lastLineStart, cut);
|
|
993
|
+
if (markdown && /^ {0,3}(`{1,2}|~{1,2})$/.test(lastLine)) {
|
|
994
|
+
return Math.min(cut, lastLineStart);
|
|
995
|
+
}
|
|
996
|
+
if (names.length) {
|
|
997
|
+
const masked = markdown ? maskInlineCode(lastLine) : lastLine;
|
|
998
|
+
const lt = masked.lastIndexOf("<");
|
|
999
|
+
if (lt >= 0) {
|
|
1000
|
+
const m = /^<(\/?)([A-Za-z][\w-]*)?([^>]*)$/.exec(masked.slice(lt));
|
|
1001
|
+
if (m) {
|
|
1002
|
+
const name = (m[2] ?? "").toLowerCase();
|
|
1003
|
+
const rest = m[3];
|
|
1004
|
+
let partial = false;
|
|
1005
|
+
if (!name) partial = rest === "";
|
|
1006
|
+
else if (names.includes(name)) partial = rest === "" || /^\s/.test(rest);
|
|
1007
|
+
else partial = rest === "" && names.some((n) => n.startsWith(name));
|
|
1008
|
+
if (partial) cut = Math.min(cut, lastLineStart + lt);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return cut;
|
|
1013
|
+
}
|
|
1014
|
+
var FEEDBACK_MS = 2e3;
|
|
1015
|
+
var WRITE_TIMEOUT_MS = 5e3;
|
|
1016
|
+
var CopyContext = react.createContext(null);
|
|
1017
|
+
async function defaultClipboardWriter(payload) {
|
|
1018
|
+
const clip = typeof navigator !== "undefined" ? navigator.clipboard : void 0;
|
|
1019
|
+
if (!clip) throw new Error("Clipboard API unavailable");
|
|
1020
|
+
const Item = globalThis.ClipboardItem;
|
|
1021
|
+
if (payload.html && Item && typeof clip.write === "function") {
|
|
1022
|
+
try {
|
|
1023
|
+
await clip.write([
|
|
1024
|
+
new Item({
|
|
1025
|
+
"text/html": new Blob([payload.html], { type: "text/html" }),
|
|
1026
|
+
"text/plain": new Blob([payload.text], { type: "text/plain" })
|
|
1027
|
+
})
|
|
1028
|
+
]);
|
|
1029
|
+
return;
|
|
1030
|
+
} catch {
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
if (typeof clip.writeText !== "function") throw new Error("Clipboard writeText unavailable");
|
|
1034
|
+
await clip.writeText(payload.text);
|
|
1035
|
+
}
|
|
1036
|
+
async function runWriter(writer, payload) {
|
|
1037
|
+
let timer;
|
|
1038
|
+
try {
|
|
1039
|
+
const result = await Promise.race([
|
|
1040
|
+
Promise.resolve().then(() => writer(payload)),
|
|
1041
|
+
new Promise((resolve) => {
|
|
1042
|
+
timer = setTimeout(() => resolve(false), WRITE_TIMEOUT_MS);
|
|
1043
|
+
})
|
|
1044
|
+
]);
|
|
1045
|
+
return result !== false;
|
|
1046
|
+
} catch {
|
|
1047
|
+
return false;
|
|
1048
|
+
} finally {
|
|
1049
|
+
if (timer) clearTimeout(timer);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
function codeText(pre, fromMarkdown) {
|
|
1053
|
+
const text = (pre.querySelector("code") ?? pre).textContent ?? "";
|
|
1054
|
+
return fromMarkdown && text.endsWith("\n") ? text.slice(0, -1) : text;
|
|
1055
|
+
}
|
|
1056
|
+
function tableTsv(table) {
|
|
1057
|
+
const rows = [];
|
|
1058
|
+
for (const tr of Array.from(table.querySelectorAll("tr"))) {
|
|
1059
|
+
if (tr.closest("table") !== table) continue;
|
|
1060
|
+
const cells = Array.from(tr.children).filter((c) => c.tagName === "TD" || c.tagName === "TH");
|
|
1061
|
+
rows.push(cells.map((c) => cellText(c)).join(" "));
|
|
1062
|
+
}
|
|
1063
|
+
return rows.join("\n");
|
|
1064
|
+
}
|
|
1065
|
+
function cellText(cell) {
|
|
1066
|
+
const clone = cell.cloneNode(true);
|
|
1067
|
+
for (const br of Array.from(clone.querySelectorAll("br"))) br.replaceWith(" ");
|
|
1068
|
+
return (clone.textContent ?? "").replace(/[\t\r\n]+/g, " ").replace(/ {2,}/g, " ").trim();
|
|
1069
|
+
}
|
|
1070
|
+
function HtmlChunk({ html, fromMarkdown }) {
|
|
1071
|
+
const ref = react.useRef(null);
|
|
1072
|
+
const ctx = react.useContext(CopyContext);
|
|
1073
|
+
const [targets, setTargets] = react.useState([]);
|
|
1074
|
+
const code = ctx?.code ?? false;
|
|
1075
|
+
const table = ctx?.table ?? false;
|
|
1076
|
+
const inner = react.useMemo(() => ({ __html: html }), [html]);
|
|
1077
|
+
react.useLayoutEffect(() => {
|
|
1078
|
+
const root = ref.current;
|
|
1079
|
+
if (!root || !code && !table) {
|
|
1080
|
+
setTargets([]);
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
const found = [];
|
|
1084
|
+
const selector = [code && "pre", table && "table"].filter(Boolean).join(",");
|
|
1085
|
+
for (const el of Array.from(root.querySelectorAll(selector))) {
|
|
1086
|
+
const kind = el.tagName === "PRE" ? "code" : "table";
|
|
1087
|
+
const wrapper = document.createElement("div");
|
|
1088
|
+
wrapper.setAttribute("data-react-fancy-content-copy-block", kind);
|
|
1089
|
+
wrapper.className = kind === "code" ? "group relative" : "group relative flex flex-col";
|
|
1090
|
+
const host = document.createElement("div");
|
|
1091
|
+
host.setAttribute("data-react-fancy-content-copy-host", "");
|
|
1092
|
+
host.className = kind === "code" ? "absolute right-2 top-2 z-10" : "flex justify-end";
|
|
1093
|
+
el.replaceWith(wrapper);
|
|
1094
|
+
if (kind === "table") wrapper.append(host, el);
|
|
1095
|
+
else wrapper.append(el, host);
|
|
1096
|
+
found.push({ kind, el, host });
|
|
1097
|
+
}
|
|
1098
|
+
setTargets(found);
|
|
1099
|
+
return () => {
|
|
1100
|
+
for (const t of found) {
|
|
1101
|
+
const wrapper = t.host.parentElement;
|
|
1102
|
+
if (wrapper?.parentNode) wrapper.replaceWith(t.el);
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
}, [html, code, table]);
|
|
1106
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1107
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref, dangerouslySetInnerHTML: inner }),
|
|
1108
|
+
targets.map(
|
|
1109
|
+
(t, i) => reactDom.createPortal(
|
|
1110
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { kind: t.kind, target: t.el, fromMarkdown }),
|
|
1111
|
+
t.host,
|
|
1112
|
+
`${i}`
|
|
1113
|
+
)
|
|
1114
|
+
)
|
|
1115
|
+
] });
|
|
1116
|
+
}
|
|
1117
|
+
function CopyButton({
|
|
1118
|
+
kind,
|
|
1119
|
+
target,
|
|
1120
|
+
fromMarkdown
|
|
820
1121
|
}) {
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
1122
|
+
const ctx = react.useContext(CopyContext);
|
|
1123
|
+
const [state, setState] = react.useState("idle");
|
|
1124
|
+
const timer = react.useRef(void 0);
|
|
1125
|
+
const btn = react.useRef(null);
|
|
1126
|
+
react.useEffect(() => () => clearTimeout(timer.current), []);
|
|
1127
|
+
const onClick = react.useCallback(async () => {
|
|
1128
|
+
if (!ctx || !btn.current) return;
|
|
1129
|
+
const text = kind === "code" ? codeText(target, fromMarkdown) : tableTsv(target);
|
|
1130
|
+
const ok = await ctx.copy({ kind, text, html: target.outerHTML }, btn.current);
|
|
1131
|
+
setState(ok ? "copied" : "failed");
|
|
1132
|
+
clearTimeout(timer.current);
|
|
1133
|
+
timer.current = setTimeout(() => setState("idle"), FEEDBACK_MS);
|
|
1134
|
+
}, [ctx, kind, target, fromMarkdown]);
|
|
1135
|
+
const idleLabel = kind === "code" ? "Copy code" : "Copy table";
|
|
1136
|
+
const label = state === "copied" ? "Copied" : state === "failed" ? "Copy failed" : idleLabel;
|
|
1137
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1138
|
+
chunk3U7PUZLI_cjs.Button,
|
|
1139
|
+
{
|
|
1140
|
+
ref: btn,
|
|
1141
|
+
type: "button",
|
|
1142
|
+
size: "xs",
|
|
1143
|
+
variant: "ghost",
|
|
1144
|
+
icon: state === "copied" ? "check" : state === "failed" ? "x" : "copy",
|
|
1145
|
+
"aria-label": label,
|
|
1146
|
+
title: label,
|
|
1147
|
+
"data-react-fancy-content-copy": kind,
|
|
1148
|
+
"data-copy-state": state,
|
|
1149
|
+
onClick,
|
|
1150
|
+
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"
|
|
1151
|
+
}
|
|
824
1152
|
);
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1153
|
+
}
|
|
1154
|
+
function useCopyPipeline({
|
|
1155
|
+
writer,
|
|
1156
|
+
onCopy,
|
|
1157
|
+
rootRef,
|
|
1158
|
+
announce
|
|
1159
|
+
}) {
|
|
1160
|
+
const latest = react.useRef({ writer, onCopy, announce });
|
|
1161
|
+
latest.current = { writer, onCopy, announce };
|
|
1162
|
+
return react.useCallback(
|
|
1163
|
+
async (payload, button) => {
|
|
1164
|
+
const { writer: w, onCopy: report, announce: say } = latest.current;
|
|
1165
|
+
const ok = await runWriter(w ?? defaultClipboardWriter, payload);
|
|
1166
|
+
say(ok ? "Copied" : "Copy failed");
|
|
1167
|
+
const all = rootRef.current ? Array.from(rootRef.current.querySelectorAll("[data-react-fancy-content-copy]")) : [];
|
|
1168
|
+
report?.({ ...payload, index: all.indexOf(button), ok });
|
|
1169
|
+
return ok;
|
|
1170
|
+
},
|
|
1171
|
+
[rootRef]
|
|
828
1172
|
);
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1173
|
+
}
|
|
1174
|
+
var MAX_DEPTH = 8;
|
|
1175
|
+
function ContentBody({ source, format, extensions, unsafe, depth = 0 }) {
|
|
1176
|
+
const active = depth >= MAX_DEPTH ? [] : extensions;
|
|
1177
|
+
const blocks = react.useMemo(() => {
|
|
1178
|
+
if (format !== "markdown") return null;
|
|
1179
|
+
const mdTags = active.filter((e) => e.markdown).map((e) => e.tag);
|
|
1180
|
+
return splitMarkdownBlocks(source, mdTags);
|
|
1181
|
+
}, [source, format, active]);
|
|
1182
|
+
if (!blocks) {
|
|
1183
|
+
const html = unsafe ? source : chunk3U7PUZLI_cjs.sanitizeHtml(source);
|
|
1184
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RenderedContent, { html, extensions: active, unsafe, fromMarkdown: false, depth });
|
|
832
1185
|
}
|
|
833
|
-
|
|
834
|
-
|
|
1186
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: blocks.map((block, i) => {
|
|
1187
|
+
if (block.type === "markdown") {
|
|
1188
|
+
const raw = markdownToRawHtml(block.source);
|
|
1189
|
+
const html = unsafe ? raw : chunk3U7PUZLI_cjs.sanitizeHtml(raw);
|
|
1190
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1191
|
+
RenderedContent,
|
|
1192
|
+
{
|
|
1193
|
+
html,
|
|
1194
|
+
extensions: active,
|
|
1195
|
+
unsafe,
|
|
1196
|
+
fromMarkdown: true,
|
|
1197
|
+
depth
|
|
1198
|
+
},
|
|
1199
|
+
i
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
const ext = active.find((e) => e.tag.toLowerCase() === block.tag);
|
|
1203
|
+
if (!ext) return null;
|
|
1204
|
+
const Component = ext.component;
|
|
1205
|
+
const Wrapper = ext.block !== false ? "div" : "span";
|
|
1206
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { "data-render-extension": block.tag, children: /* @__PURE__ */ jsxRuntime.jsx(Component, { content: block.body, attributes: tagAttributes(block.attrs, unsafe), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1207
|
+
ContentBody,
|
|
1208
|
+
{
|
|
1209
|
+
source: block.body,
|
|
1210
|
+
format: "markdown",
|
|
1211
|
+
extensions: active,
|
|
1212
|
+
unsafe,
|
|
1213
|
+
depth: depth + 1
|
|
1214
|
+
}
|
|
1215
|
+
) }) }, i);
|
|
1216
|
+
}) });
|
|
1217
|
+
}
|
|
1218
|
+
function RenderedContent({ html, extensions, unsafe, fromMarkdown, depth }) {
|
|
1219
|
+
const segments = react.useMemo(() => parseSegments(html, extensions), [html, extensions]);
|
|
1220
|
+
const renderHtml = (content) => unsafe ? content : chunk3U7PUZLI_cjs.sanitizeHtml(content);
|
|
1221
|
+
if (segments.length === 0) return null;
|
|
1222
|
+
if (segments.length === 1 && segments[0].type === "html") {
|
|
1223
|
+
return /* @__PURE__ */ jsxRuntime.jsx(HtmlChunk, { html: renderHtml(segments[0].content), fromMarkdown });
|
|
835
1224
|
}
|
|
836
1225
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments.map((segment, i) => {
|
|
837
1226
|
if (segment.type === "html") {
|
|
838
|
-
return segment.content ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1227
|
+
return segment.content ? /* @__PURE__ */ jsxRuntime.jsx(HtmlChunk, { html: renderHtml(segment.content), fromMarkdown }, i) : null;
|
|
839
1228
|
}
|
|
840
|
-
const ext = extensions.find(
|
|
841
|
-
(e) => e.tag.toLowerCase() === segment.tag
|
|
842
|
-
);
|
|
1229
|
+
const ext = extensions.find((e) => e.tag.toLowerCase() === segment.tag);
|
|
843
1230
|
if (!ext) return null;
|
|
844
1231
|
const Component = ext.component;
|
|
845
|
-
const
|
|
846
|
-
const
|
|
847
|
-
|
|
1232
|
+
const Wrapper = ext.block !== false ? "div" : "span";
|
|
1233
|
+
const children = ext.markdown ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1234
|
+
ContentBody,
|
|
1235
|
+
{
|
|
1236
|
+
source: segment.content,
|
|
1237
|
+
format: "html",
|
|
1238
|
+
extensions,
|
|
1239
|
+
unsafe,
|
|
1240
|
+
depth: depth + 1
|
|
1241
|
+
}
|
|
1242
|
+
) : void 0;
|
|
1243
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { "data-render-extension": segment.tag, children: /* @__PURE__ */ jsxRuntime.jsx(Component, { content: segment.content, attributes: segment.attributes, children }) }, i);
|
|
848
1244
|
}) });
|
|
849
1245
|
}
|
|
850
1246
|
RenderedContent.displayName = "RenderedContent";
|
|
1247
|
+
ContentBody.displayName = "ContentBody";
|
|
851
1248
|
function ContentRenderer({
|
|
852
1249
|
value,
|
|
853
1250
|
format = "auto",
|
|
854
1251
|
lineSpacing = 1.6,
|
|
855
1252
|
className,
|
|
856
1253
|
extensions: instanceExtensions,
|
|
857
|
-
unsafe = false
|
|
1254
|
+
unsafe = false,
|
|
1255
|
+
copyButtons = true,
|
|
1256
|
+
onCopy,
|
|
1257
|
+
clipboardWriter,
|
|
1258
|
+
streaming = false
|
|
858
1259
|
}) {
|
|
859
1260
|
const extensions = react.useMemo(
|
|
860
1261
|
() => mergeExtensions(instanceExtensions),
|
|
861
1262
|
[instanceExtensions]
|
|
862
1263
|
);
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1264
|
+
const safe = value ?? "";
|
|
1265
|
+
const resolvedFormat = format === "auto" ? detectFormat(safe) : format;
|
|
1266
|
+
const source = react.useMemo(() => {
|
|
1267
|
+
if (!streaming) return safe;
|
|
1268
|
+
const cut = streamingCut(
|
|
1269
|
+
safe,
|
|
1270
|
+
extensions.map((e) => e.tag),
|
|
1271
|
+
resolvedFormat === "markdown"
|
|
1272
|
+
);
|
|
1273
|
+
return safe.slice(0, cut);
|
|
1274
|
+
}, [safe, streaming, extensions, resolvedFormat]);
|
|
1275
|
+
const codeOn = copyButtons === true || typeof copyButtons === "object" && copyButtons.code !== false;
|
|
1276
|
+
const tableOn = copyButtons === true || typeof copyButtons === "object" && copyButtons.table !== false;
|
|
1277
|
+
const copyOn = codeOn || tableOn;
|
|
1278
|
+
const rootRef = react.useRef(null);
|
|
1279
|
+
const [announcement, setAnnouncement] = react.useState("");
|
|
1280
|
+
const announce = react.useCallback((message) => {
|
|
1281
|
+
setAnnouncement("");
|
|
1282
|
+
queueMicrotask(() => setAnnouncement(message));
|
|
1283
|
+
}, []);
|
|
1284
|
+
const copy = useCopyPipeline({ writer: clipboardWriter, onCopy, rootRef, announce });
|
|
1285
|
+
const copyContext = react.useMemo(
|
|
1286
|
+
() => ({ code: codeOn, table: tableOn, copy }),
|
|
1287
|
+
[codeOn, tableOn, copy]
|
|
1288
|
+
);
|
|
1289
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
871
1290
|
"div",
|
|
872
1291
|
{
|
|
1292
|
+
ref: rootRef,
|
|
873
1293
|
"data-react-fancy-content-renderer": "",
|
|
1294
|
+
"data-streaming": streaming ? "true" : void 0,
|
|
874
1295
|
style: { lineHeight: lineSpacing },
|
|
875
1296
|
className: chunkZU5Q77OT_cjs.cn("text-sm", proseClasses, className),
|
|
876
|
-
children:
|
|
1297
|
+
children: [
|
|
1298
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyContext.Provider, { value: copyContext, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1299
|
+
ContentBody,
|
|
1300
|
+
{
|
|
1301
|
+
source,
|
|
1302
|
+
format: resolvedFormat,
|
|
1303
|
+
extensions,
|
|
1304
|
+
unsafe
|
|
1305
|
+
}
|
|
1306
|
+
) }),
|
|
1307
|
+
copyOn && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1308
|
+
"span",
|
|
1309
|
+
{
|
|
1310
|
+
role: "status",
|
|
1311
|
+
"aria-live": "polite",
|
|
1312
|
+
"aria-atomic": "true",
|
|
1313
|
+
"data-react-fancy-content-renderer-live": "",
|
|
1314
|
+
className: "sr-only",
|
|
1315
|
+
children: announcement
|
|
1316
|
+
}
|
|
1317
|
+
)
|
|
1318
|
+
]
|
|
877
1319
|
}
|
|
878
1320
|
);
|
|
879
1321
|
}
|
|
@@ -889,5 +1331,5 @@ exports.proseClasses = proseClasses;
|
|
|
889
1331
|
exports.registerExtension = registerExtension;
|
|
890
1332
|
exports.registerExtensions = registerExtensions;
|
|
891
1333
|
exports.renderMarkdown = renderMarkdown;
|
|
892
|
-
//# sourceMappingURL=chunk-
|
|
893
|
-
//# sourceMappingURL=chunk-
|
|
1334
|
+
//# sourceMappingURL=chunk-E5UU666U.cjs.map
|
|
1335
|
+
//# sourceMappingURL=chunk-E5UU666U.cjs.map
|