@particle-academy/react-fancy 5.66.0 → 5.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/dist/ContentRenderer.types-RO_l7_6N.d.cts +137 -0
  3. package/dist/ContentRenderer.types-RO_l7_6N.d.ts +137 -0
  4. package/dist/button.cjs +3 -4
  5. package/dist/button.js +1 -2
  6. package/dist/{chunk-J44EV6SP.js → chunk-23AVEYUP.js} +3 -3
  7. package/dist/{chunk-J44EV6SP.js.map → chunk-23AVEYUP.js.map} +1 -1
  8. package/dist/{chunk-L24LUSEE.js → chunk-2LQR4EAN.js} +553 -35
  9. package/dist/chunk-2LQR4EAN.js.map +1 -0
  10. package/dist/{chunk-C5YX5XVL.cjs → chunk-3U7PUZLI.cjs} +214 -4
  11. package/dist/chunk-3U7PUZLI.cjs.map +1 -0
  12. package/dist/{chunk-MCQJFMDP.cjs → chunk-464QSZ4A.cjs} +553 -35
  13. package/dist/chunk-464QSZ4A.cjs.map +1 -0
  14. package/dist/{chunk-QP35Z2WB.js → chunk-BL5IKSB3.js} +3 -3
  15. package/dist/{chunk-QP35Z2WB.js.map → chunk-BL5IKSB3.js.map} +1 -1
  16. package/dist/{chunk-4EUDW2WU.js → chunk-DCAD2JPP.js} +3 -3
  17. package/dist/{chunk-4EUDW2WU.js.map → chunk-DCAD2JPP.js.map} +1 -1
  18. package/dist/{chunk-ATIDUWY6.cjs → chunk-E4DXICU3.cjs} +19 -13
  19. package/dist/chunk-E4DXICU3.cjs.map +1 -0
  20. package/dist/{chunk-TLRRMYNV.js → chunk-OXERDFFF.js} +212 -4
  21. package/dist/chunk-OXERDFFF.js.map +1 -0
  22. package/dist/{chunk-SYEHWUM5.cjs → chunk-RALJMI7C.cjs} +4 -4
  23. package/dist/{chunk-SYEHWUM5.cjs.map → chunk-RALJMI7C.cjs.map} +1 -1
  24. package/dist/{chunk-UM4JXBRZ.cjs → chunk-S3NB6LDV.cjs} +4 -4
  25. package/dist/{chunk-UM4JXBRZ.cjs.map → chunk-S3NB6LDV.cjs.map} +1 -1
  26. package/dist/{chunk-MCQWTOTV.cjs → chunk-SAG6DHQK.cjs} +6 -6
  27. package/dist/{chunk-MCQWTOTV.cjs.map → chunk-SAG6DHQK.cjs.map} +1 -1
  28. package/dist/{chunk-CAUEKGMR.js → chunk-TQ77ZWBD.js} +11 -5
  29. package/dist/chunk-TQ77ZWBD.js.map +1 -0
  30. package/dist/{chunk-7HXFEYOV.cjs → chunk-U5LKNGHU.cjs} +15 -15
  31. package/dist/{chunk-7HXFEYOV.cjs.map → chunk-U5LKNGHU.cjs.map} +1 -1
  32. package/dist/{chunk-M52S3TFI.js → chunk-WFR7HKJL.js} +3 -3
  33. package/dist/{chunk-M52S3TFI.js.map → chunk-WFR7HKJL.js.map} +1 -1
  34. package/dist/content-renderer.cjs +7 -5
  35. package/dist/content-renderer.d.cts +4 -21
  36. package/dist/content-renderer.d.ts +4 -21
  37. package/dist/content-renderer.js +4 -2
  38. package/dist/editor.cjs +6 -5
  39. package/dist/editor.d.cts +19 -2
  40. package/dist/editor.d.ts +19 -2
  41. package/dist/editor.js +4 -3
  42. package/dist/index.cjs +37 -38
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.d.cts +2 -2
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.js +7 -8
  47. package/dist/index.js.map +1 -1
  48. package/dist/json-editor.cjs +13 -14
  49. package/dist/json-editor.js +2 -3
  50. package/dist/magic-wand.cjs +3 -4
  51. package/dist/magic-wand.js +2 -3
  52. package/dist/prompt-input.cjs +5 -6
  53. package/dist/prompt-input.js +2 -3
  54. package/dist/reason-tag.cjs +3 -4
  55. package/dist/reason-tag.js +2 -3
  56. package/docs/ContentRenderer.md +192 -3
  57. package/docs/Editor.md +38 -0
  58. package/package.json +1 -1
  59. package/dist/chunk-6TBRBN7H.js +0 -212
  60. package/dist/chunk-6TBRBN7H.js.map +0 -1
  61. package/dist/chunk-ATIDUWY6.cjs.map +0 -1
  62. package/dist/chunk-C5YX5XVL.cjs.map +0 -1
  63. package/dist/chunk-CAUEKGMR.js.map +0 -1
  64. package/dist/chunk-L24LUSEE.js.map +0 -1
  65. package/dist/chunk-MCQJFMDP.cjs.map +0 -1
  66. package/dist/chunk-TLRRMYNV.js.map +0 -1
  67. package/dist/chunk-X2FC7ODX.cjs +0 -215
  68. package/dist/chunk-X2FC7ODX.cjs.map +0 -1
  69. package/dist/extensions-6PVd3-vB.d.cts +0 -38
  70. package/dist/extensions-6PVd3-vB.d.ts +0 -38
@@ -1,215 +0,0 @@
1
- 'use strict';
2
-
3
- // src/utils/sanitize.ts
4
- var DANGEROUS_TAGS = /* @__PURE__ */ new Set([
5
- "script",
6
- "style",
7
- "iframe",
8
- "object",
9
- "embed",
10
- "link",
11
- "meta",
12
- "base",
13
- "form",
14
- // A <title> anywhere in the document retitles the host's tab.
15
- "title"
16
- ]);
17
- var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "xlink:href"]);
18
- var SAFE_PROTOCOL = /^(?:https?:|mailto:|tel:|sms:|ftp:|#|\/|\.\/|\.\.\/|[^:]*$)/i;
19
- function sanitizeHref(href) {
20
- if (href == null) return void 0;
21
- const trimmed = href.trim();
22
- if (!trimmed) return void 0;
23
- return SAFE_PROTOCOL.test(trimmed) ? trimmed : void 0;
24
- }
25
- function stripDangerousAttrs(el) {
26
- const names = [];
27
- for (let i = 0; i < el.attributes.length; i++) {
28
- names.push(el.attributes[i].name);
29
- }
30
- for (const name of names) {
31
- const lower = name.toLowerCase();
32
- if (lower.startsWith("on")) {
33
- el.removeAttribute(name);
34
- continue;
35
- }
36
- if (URL_ATTRS.has(lower)) {
37
- const sanitized = sanitizeHref(el.getAttribute(name));
38
- if (sanitized === void 0) {
39
- el.removeAttribute(name);
40
- } else {
41
- el.setAttribute(name, sanitized);
42
- }
43
- continue;
44
- }
45
- if (lower === "srcdoc") {
46
- el.removeAttribute(name);
47
- }
48
- }
49
- }
50
- function walk(el, removeQueue) {
51
- const tag = el.tagName.toLowerCase();
52
- if (DANGEROUS_TAGS.has(tag)) {
53
- removeQueue.push(el);
54
- return;
55
- }
56
- stripDangerousAttrs(el);
57
- const children = Array.from(el.children);
58
- for (const child of children) {
59
- walk(child, removeQueue);
60
- }
61
- }
62
- var ALWAYS_REMOVED_TAGS = /* @__PURE__ */ new Set([
63
- ...DANGEROUS_TAGS,
64
- "frame",
65
- "frameset",
66
- "applet",
67
- "template",
68
- "noscript",
69
- "noembed",
70
- "noframes",
71
- "xmp",
72
- "plaintext",
73
- // Foreign content: namespace confusion is how mutation XSS gets past
74
- // sanitisers that re-serialise, as this one does.
75
- "svg",
76
- "math"
77
- ]);
78
- var ALLOWLIST_URL_ATTRS = /* @__PURE__ */ new Set([
79
- "href",
80
- "src",
81
- "action",
82
- "formaction",
83
- "cite",
84
- "poster",
85
- "background",
86
- "ping",
87
- "xlink:href"
88
- ]);
89
- var NEVER_ALLOWED_ATTRS = /* @__PURE__ */ new Set(["srcdoc", "srcset"]);
90
- var NEVER_ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["javascript:", "vbscript:"]);
91
- var DEFAULT_SCHEMES = ["http:", "https:", "mailto:"];
92
- var SCHEME = /^([a-z][a-z0-9+.-]*:)/i;
93
- var SLASH = 47;
94
- var BACKSLASH = 92;
95
- function lowerAll(list) {
96
- return (list ?? []).map((s) => s.toLowerCase());
97
- }
98
- function toPolicy(options) {
99
- const tagAttrs = /* @__PURE__ */ new Map();
100
- let globalAttrs = [];
101
- const attrs = options.allowedAttributes;
102
- if (Array.isArray(attrs)) {
103
- globalAttrs = lowerAll(attrs);
104
- } else if (attrs) {
105
- for (const [tag, list] of Object.entries(attrs)) {
106
- if (tag === "*") globalAttrs = lowerAll(list);
107
- else tagAttrs.set(tag.toLowerCase(), lowerAll(list));
108
- }
109
- }
110
- return {
111
- tags: new Set(lowerAll(options.allowedTags)),
112
- globalAttrs,
113
- tagAttrs,
114
- schemes: new Set(lowerAll(options.allowedSchemes ?? DEFAULT_SCHEMES)),
115
- allowRelative: options.allowRelative === true
116
- };
117
- }
118
- function attrListed(name, list) {
119
- if (!list) return false;
120
- for (const entry of list) {
121
- if (entry === name) return true;
122
- if (entry.endsWith("*") && name.startsWith(entry.slice(0, -1))) return true;
123
- }
124
- return false;
125
- }
126
- function stripControlAndSpace(value) {
127
- let out = "";
128
- for (let i = 0; i < value.length; i++) {
129
- if (value.charCodeAt(i) > 32) out += value[i];
130
- }
131
- return out;
132
- }
133
- function urlAllowed(value, policy) {
134
- const url = stripControlAndSpace(value);
135
- const match = SCHEME.exec(url);
136
- if (match) {
137
- const scheme = match[1].toLowerCase();
138
- return !NEVER_ALLOWED_SCHEMES.has(scheme) && policy.schemes.has(scheme);
139
- }
140
- if (!policy.allowRelative) return false;
141
- const a = url.charCodeAt(0);
142
- const b = url.charCodeAt(1);
143
- const isSlash = (c) => c === SLASH || c === BACKSLASH;
144
- return !(isSlash(a) && isSlash(b));
145
- }
146
- function cleanAttributes(el, tag, policy) {
147
- const names = [];
148
- for (let i = 0; i < el.attributes.length; i++) {
149
- names.push(el.attributes[i].name);
150
- }
151
- for (const name of names) {
152
- const lower = name.toLowerCase();
153
- const keep = !lower.startsWith("on") && !NEVER_ALLOWED_ATTRS.has(lower) && (attrListed(lower, policy.globalAttrs) || attrListed(lower, policy.tagAttrs.get(tag))) && (!ALLOWLIST_URL_ATTRS.has(lower) || urlAllowed(el.getAttribute(name) ?? "", policy));
154
- if (!keep) el.removeAttribute(name);
155
- }
156
- }
157
- function cleanChildren(parent, policy) {
158
- for (const node of Array.from(parent.childNodes)) {
159
- if (node.nodeType === 3) continue;
160
- if (node.nodeType !== 1) {
161
- parent.removeChild(node);
162
- continue;
163
- }
164
- const el = node;
165
- const tag = el.tagName.toLowerCase();
166
- if (ALWAYS_REMOVED_TAGS.has(tag)) {
167
- parent.removeChild(el);
168
- continue;
169
- }
170
- cleanChildren(el, policy);
171
- if (!policy.tags.has(tag)) {
172
- while (el.firstChild) parent.insertBefore(el.firstChild, el);
173
- parent.removeChild(el);
174
- continue;
175
- }
176
- cleanAttributes(el, tag, policy);
177
- }
178
- }
179
- function escapeText(text) {
180
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
181
- }
182
- function sanitizeAllowlist(html, options) {
183
- if (typeof window === "undefined" || typeof DOMParser === "undefined") {
184
- return escapeText(html);
185
- }
186
- const doc = new DOMParser().parseFromString(`<body>${html}</body>`, "text/html");
187
- const body = doc.body;
188
- if (!body) return "";
189
- cleanChildren(body, toPolicy(options));
190
- return body.innerHTML;
191
- }
192
- function sanitizeHtml(html, options) {
193
- if (options !== void 0 && options !== null) {
194
- return sanitizeAllowlist(html, options);
195
- }
196
- if (typeof window === "undefined" || typeof DOMParser === "undefined") {
197
- return html;
198
- }
199
- const doc = new DOMParser().parseFromString(`<body>${html}</body>`, "text/html");
200
- const body = doc.body;
201
- if (!body) return html;
202
- const removeQueue = [];
203
- for (const child of Array.from(body.children)) {
204
- walk(child, removeQueue);
205
- }
206
- for (const el of removeQueue) {
207
- el.parentNode?.removeChild(el);
208
- }
209
- return body.innerHTML;
210
- }
211
-
212
- exports.sanitizeHref = sanitizeHref;
213
- exports.sanitizeHtml = sanitizeHtml;
214
- //# sourceMappingURL=chunk-X2FC7ODX.cjs.map
215
- //# sourceMappingURL=chunk-X2FC7ODX.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/sanitize.ts"],"names":[],"mappings":"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","file":"chunk-X2FC7ODX.cjs","sourcesContent":["/**\n * HTML and URL sanitization utilities.\n *\n * Hand-rolled (no third-party deps) using browser-native `DOMParser`. Designed\n * for the trust model \"consumer passes user-generated markdown/HTML to a\n * react-fancy component\" — strips script tags, event handlers, and dangerous\n * URI schemes from `href`/`src` attributes.\n *\n * For server-side rendering (no `window`), `sanitizeHtml` returns the input\n * unchanged. Consumers SSR-rendering untrusted content should sanitize on the\n * server with their own pipeline.\n */\n\nconst DANGEROUS_TAGS = new Set([\n \"script\",\n \"style\",\n \"iframe\",\n \"object\",\n \"embed\",\n \"link\",\n \"meta\",\n \"base\",\n \"form\",\n // A <title> anywhere in the document retitles the host's tab.\n \"title\",\n]);\n\nconst URL_ATTRS = new Set([\"href\", \"src\", \"action\", \"formaction\", \"xlink:href\"]);\n\nconst SAFE_PROTOCOL = /^(?:https?:|mailto:|tel:|sms:|ftp:|#|\\/|\\.\\/|\\.\\.\\/|[^:]*$)/i;\n\n/**\n * Validate a URL/href against an allow-list of safe protocols. Returns the\n * input if safe, or `undefined` if it begins with a dangerous scheme like\n * `javascript:`, `data:`, or `vbscript:`. Relative URLs and fragment links\n * are allowed.\n */\nexport function sanitizeHref(href: string | undefined | null): string | undefined {\n if (href == null) return undefined;\n const trimmed = href.trim();\n if (!trimmed) return undefined;\n return SAFE_PROTOCOL.test(trimmed) ? trimmed : undefined;\n}\n\nfunction stripDangerousAttrs(el: Element): void {\n // Collect names first; mutating during iteration is awkward with NamedNodeMap.\n const names: string[] = [];\n for (let i = 0; i < el.attributes.length; i++) {\n names.push(el.attributes[i].name);\n }\n\n for (const name of names) {\n const lower = name.toLowerCase();\n\n // All on* event handlers\n if (lower.startsWith(\"on\")) {\n el.removeAttribute(name);\n continue;\n }\n\n // URL attributes — protocol-filter\n if (URL_ATTRS.has(lower)) {\n const sanitized = sanitizeHref(el.getAttribute(name));\n if (sanitized === undefined) {\n el.removeAttribute(name);\n } else {\n el.setAttribute(name, sanitized);\n }\n continue;\n }\n\n // srcdoc executes JS in the iframe — drop wholesale\n if (lower === \"srcdoc\") {\n el.removeAttribute(name);\n }\n }\n}\n\nfunction walk(el: Element, removeQueue: Element[]): void {\n const tag = el.tagName.toLowerCase();\n\n if (DANGEROUS_TAGS.has(tag)) {\n removeQueue.push(el);\n return;\n }\n\n stripDangerousAttrs(el);\n\n const children = Array.from(el.children);\n for (const child of children) {\n walk(child, removeQueue);\n }\n}\n\n/**\n * Allowlist options for {@link sanitizeHtml}. Passing ANY options object\n * (even `{}`) switches from the default blocklist to allowlist mode, where\n * everything not listed is removed.\n */\nexport interface SanitizeHtmlOptions {\n /**\n * Tags to keep, e.g. `[\"p\", \"a\", \"strong\"]`. A tag that is not listed is\n * removed but its text and (cleaned) children are kept. Default: none, so\n * only text survives.\n *\n * Some tags are removed WITH their content even when listed, because no\n * attribute filtering makes them safe: `script`, `style`, `iframe`, `frame`,\n * `frameset`, `object`, `embed`, `applet`, `link`, `meta`, `base`, `form`,\n * `title`, `template`, `noscript`, `noembed`, `noframes`, `xmp`,\n * `plaintext`, `svg` and `math`.\n */\n allowedTags?: readonly string[];\n /**\n * Attributes to keep. Either one list for every allowed tag, or a map from\n * tag name to its list, where the key `\"*\"` applies to every tag. A trailing\n * `*` matches a prefix (`\"data-*\"`, `\"aria-*\"`). Default: none.\n *\n * Never kept, even when listed: event handlers (`on*`), `srcdoc` and\n * `srcset`.\n */\n allowedAttributes?: readonly string[] | Readonly<Record<string, readonly string[]>>;\n /**\n * URL schemes allowed in URL attributes (`href`, `src`, `action`,\n * `formaction`, `cite`, `poster`, `background`, `ping`, `xlink:href`), with\n * the colon: `[\"https:\", \"mailto:\"]`. A URL attribute whose scheme is not\n * listed is removed. Default: `[\"http:\", \"https:\", \"mailto:\"]`.\n *\n * `javascript:` and `vbscript:` are never kept, even when listed.\n */\n allowedSchemes?: readonly string[];\n /**\n * Keep URLs with no scheme that stay on this site: `/x`, `x/y`, `../x`,\n * `?q`, `#frag`. Protocol-relative URLs (`//host/x`, and the backslash\n * spellings a browser treats the same way) leave the site and are always\n * removed. Default: `false`.\n */\n allowRelative?: boolean;\n}\n\n/** Removed with their content in allowlist mode, whatever the options say. */\nconst ALWAYS_REMOVED_TAGS = new Set([\n ...DANGEROUS_TAGS,\n \"frame\",\n \"frameset\",\n \"applet\",\n \"template\",\n \"noscript\",\n \"noembed\",\n \"noframes\",\n \"xmp\",\n \"plaintext\",\n // Foreign content: namespace confusion is how mutation XSS gets past\n // sanitisers that re-serialise, as this one does.\n \"svg\",\n \"math\",\n]);\n\nconst ALLOWLIST_URL_ATTRS = new Set([\n \"href\",\n \"src\",\n \"action\",\n \"formaction\",\n \"cite\",\n \"poster\",\n \"background\",\n \"ping\",\n \"xlink:href\",\n]);\n\nconst NEVER_ALLOWED_ATTRS = new Set([\"srcdoc\", \"srcset\"]);\n\nconst NEVER_ALLOWED_SCHEMES = new Set([\"javascript:\", \"vbscript:\"]);\n\nconst DEFAULT_SCHEMES = [\"http:\", \"https:\", \"mailto:\"];\n\nconst SCHEME = /^([a-z][a-z0-9+.-]*:)/i;\n\nconst SLASH = 47;\nconst BACKSLASH = 92;\n\ninterface Policy {\n tags: Set<string>;\n globalAttrs: string[];\n tagAttrs: Map<string, string[]>;\n schemes: Set<string>;\n allowRelative: boolean;\n}\n\nfunction lowerAll(list: readonly string[] | undefined): string[] {\n return (list ?? []).map((s) => s.toLowerCase());\n}\n\nfunction toPolicy(options: SanitizeHtmlOptions): Policy {\n const tagAttrs = new Map<string, string[]>();\n let globalAttrs: string[] = [];\n const attrs = options.allowedAttributes;\n if (Array.isArray(attrs)) {\n globalAttrs = lowerAll(attrs);\n } else if (attrs) {\n for (const [tag, list] of Object.entries(attrs as Record<string, readonly string[]>)) {\n if (tag === \"*\") globalAttrs = lowerAll(list);\n else tagAttrs.set(tag.toLowerCase(), lowerAll(list));\n }\n }\n return {\n tags: new Set(lowerAll(options.allowedTags)),\n globalAttrs,\n tagAttrs,\n schemes: new Set(lowerAll(options.allowedSchemes ?? DEFAULT_SCHEMES)),\n allowRelative: options.allowRelative === true,\n };\n}\n\nfunction attrListed(name: string, list: string[] | undefined): boolean {\n if (!list) return false;\n for (const entry of list) {\n if (entry === name) return true;\n if (entry.endsWith(\"*\") && name.startsWith(entry.slice(0, -1))) return true;\n }\n return false;\n}\n\n/**\n * Browsers ignore ASCII whitespace and control characters inside a URL's\n * scheme (`java<TAB>script:` runs), so judge the URL with them removed.\n */\nfunction stripControlAndSpace(value: string): string {\n let out = \"\";\n for (let i = 0; i < value.length; i++) {\n if (value.charCodeAt(i) > 32) out += value[i];\n }\n return out;\n}\n\nfunction urlAllowed(value: string, policy: Policy): boolean {\n const url = stripControlAndSpace(value);\n const match = SCHEME.exec(url);\n if (match) {\n const scheme = match[1].toLowerCase();\n return !NEVER_ALLOWED_SCHEMES.has(scheme) && policy.schemes.has(scheme);\n }\n if (!policy.allowRelative) return false;\n const a = url.charCodeAt(0);\n const b = url.charCodeAt(1);\n const isSlash = (c: number) => c === SLASH || c === BACKSLASH;\n // `//host`, and its backslash spellings, is another site.\n return !(isSlash(a) && isSlash(b));\n}\n\nfunction cleanAttributes(el: Element, tag: string, policy: Policy): void {\n const names: string[] = [];\n for (let i = 0; i < el.attributes.length; i++) {\n names.push(el.attributes[i].name);\n }\n for (const name of names) {\n const lower = name.toLowerCase();\n const keep =\n !lower.startsWith(\"on\") &&\n !NEVER_ALLOWED_ATTRS.has(lower) &&\n (attrListed(lower, policy.globalAttrs) || attrListed(lower, policy.tagAttrs.get(tag))) &&\n (!ALLOWLIST_URL_ATTRS.has(lower) || urlAllowed(el.getAttribute(name) ?? \"\", policy));\n if (!keep) el.removeAttribute(name);\n }\n}\n\nfunction cleanChildren(parent: Node, policy: Policy): void {\n for (const node of Array.from(parent.childNodes)) {\n if (node.nodeType === 3) continue; // text\n if (node.nodeType !== 1) {\n // comments, processing instructions, CDATA\n parent.removeChild(node);\n continue;\n }\n const el = node as Element;\n const tag = el.tagName.toLowerCase();\n if (ALWAYS_REMOVED_TAGS.has(tag)) {\n parent.removeChild(el);\n continue;\n }\n cleanChildren(el, policy);\n if (!policy.tags.has(tag)) {\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n parent.removeChild(el);\n continue;\n }\n cleanAttributes(el, tag, policy);\n }\n}\n\nfunction escapeText(text: string): string {\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction sanitizeAllowlist(html: string, options: SanitizeHtmlOptions): string {\n if (typeof window === \"undefined\" || typeof DOMParser === \"undefined\") {\n // Fail closed: with no parser we cannot tell markup from text, so the\n // whole input is returned as escaped text rather than passed through.\n return escapeText(html);\n }\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, \"text/html\");\n const body = doc.body;\n if (!body) return \"\";\n cleanChildren(body, toPolicy(options));\n return body.innerHTML;\n}\n\n/**\n * Sanitize an HTML string.\n *\n * **With no options** (the default blocklist): removes dangerous tags (script,\n * iframe, etc.), event-handler attributes (`onclick`, `onerror`, ...), and\n * dangerous URI schemes in `href`/`src` attributes. Everything else is kept.\n * In non-browser environments returns the input unchanged — sanitize on the\n * server in those cases.\n *\n * **With options** (allowlist mode): keeps ONLY the listed tags, attributes and\n * URL schemes; see {@link SanitizeHtmlOptions}. The allowlist can only narrow:\n * event handlers, `javascript:` URLs and script-capable tags never survive,\n * even when listed. In non-browser environments the input is returned as\n * escaped text (fail closed).\n *\n * Uses the browser's `DOMParser`.\n */\nexport function sanitizeHtml(html: string, options?: SanitizeHtmlOptions): string {\n if (options !== undefined && options !== null) {\n return sanitizeAllowlist(html, options);\n }\n if (typeof window === \"undefined\" || typeof DOMParser === \"undefined\") {\n return html;\n }\n\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, \"text/html\");\n const body = doc.body;\n if (!body) return html;\n\n const removeQueue: Element[] = [];\n for (const child of Array.from(body.children)) {\n walk(child, removeQueue);\n }\n\n for (const el of removeQueue) {\n el.parentNode?.removeChild(el);\n }\n\n return body.innerHTML;\n}\n"]}
@@ -1,38 +0,0 @@
1
- import { ComponentType } from 'react';
2
-
3
- /** Props passed to every render-extension component. */
4
- interface RenderExtensionProps {
5
- /** The inner content of the custom tag (raw string). */
6
- content: string;
7
- /** Parsed HTML attributes from the opening tag. */
8
- attributes: Record<string, string>;
9
- }
10
- /** Registers a custom tag with a React component for rendering. */
11
- interface RenderExtension {
12
- /** Tag name to match, e.g. "questions", "thinking". Case-insensitive. */
13
- tag: string;
14
- /** React component that renders the matched tag. */
15
- component: ComponentType<RenderExtensionProps>;
16
- /**
17
- * Whether this is a block-level element.
18
- * Block extensions are wrapped in a `<div>`, inline in a `<span>`.
19
- * @default true
20
- */
21
- block?: boolean;
22
- }
23
- /** A parsed segment — either raw HTML or a matched extension tag. */
24
- type ContentSegment = {
25
- type: "html";
26
- content: string;
27
- } | {
28
- type: "extension";
29
- tag: string;
30
- content: string;
31
- attributes: Record<string, string>;
32
- };
33
- /** Register a single render extension globally (available to all ContentRenderer and Editor instances). */
34
- declare function registerExtension(extension: RenderExtension): void;
35
- /** Register multiple render extensions globally. */
36
- declare function registerExtensions(extensions: RenderExtension[]): void;
37
-
38
- export { type ContentSegment as C, type RenderExtension as R, type RenderExtensionProps as a, registerExtensions as b, registerExtension as r };
@@ -1,38 +0,0 @@
1
- import { ComponentType } from 'react';
2
-
3
- /** Props passed to every render-extension component. */
4
- interface RenderExtensionProps {
5
- /** The inner content of the custom tag (raw string). */
6
- content: string;
7
- /** Parsed HTML attributes from the opening tag. */
8
- attributes: Record<string, string>;
9
- }
10
- /** Registers a custom tag with a React component for rendering. */
11
- interface RenderExtension {
12
- /** Tag name to match, e.g. "questions", "thinking". Case-insensitive. */
13
- tag: string;
14
- /** React component that renders the matched tag. */
15
- component: ComponentType<RenderExtensionProps>;
16
- /**
17
- * Whether this is a block-level element.
18
- * Block extensions are wrapped in a `<div>`, inline in a `<span>`.
19
- * @default true
20
- */
21
- block?: boolean;
22
- }
23
- /** A parsed segment — either raw HTML or a matched extension tag. */
24
- type ContentSegment = {
25
- type: "html";
26
- content: string;
27
- } | {
28
- type: "extension";
29
- tag: string;
30
- content: string;
31
- attributes: Record<string, string>;
32
- };
33
- /** Register a single render extension globally (available to all ContentRenderer and Editor instances). */
34
- declare function registerExtension(extension: RenderExtension): void;
35
- /** Register multiple render extensions globally. */
36
- declare function registerExtensions(extensions: RenderExtension[]): void;
37
-
38
- export { type ContentSegment as C, type RenderExtension as R, type RenderExtensionProps as a, registerExtensions as b, registerExtension as r };