@alfadocs/ui-kit-debug 1.44.0 → 1.45.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/dist/_chunks/ai-sparkle-DXeP_6a0.js +52 -0
- package/dist/_chunks/ai-sparkle-DXeP_6a0.js.map +1 -0
- package/dist/_chunks/{calendar-workspace-DBYAtdyd.js → calendar-workspace-B7KvZ1_D.js} +2 -2
- package/dist/_chunks/{calendar-workspace-DBYAtdyd.js.map → calendar-workspace-B7KvZ1_D.js.map} +1 -1
- package/dist/_chunks/{notes-panel-CY4KmDo-.js → notes-panel-Dkk9QPPX.js} +2 -2
- package/dist/_chunks/{notes-panel-CY4KmDo-.js.map → notes-panel-Dkk9QPPX.js.map} +1 -1
- package/dist/_chunks/{rich-text-editor-BYE6kK4u.js → rich-text-editor-BrAvNajV.js} +1207 -1267
- package/dist/_chunks/rich-text-editor-BrAvNajV.js.map +1 -0
- package/dist/_chunks/use-ai-sparkle-CyQSRTCe.js +103 -0
- package/dist/_chunks/use-ai-sparkle-CyQSRTCe.js.map +1 -0
- package/dist/agent-catalog.json +1 -1
- package/dist/components/ai-sparkle/ai-sparkle.d.ts +24 -0
- package/dist/components/ai-sparkle/ai-sparkle.d.ts.map +1 -0
- package/dist/components/ai-sparkle/index.d.ts +3 -0
- package/dist/components/ai-sparkle/index.d.ts.map +1 -0
- package/dist/components/ai-sparkle/index.js +5 -0
- package/dist/components/ai-sparkle/index.js.map +1 -0
- package/dist/components/index.d.ts +3 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/notes-panel/index.js +1 -1
- package/dist/components/rich-text-editor/index.js +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +64 -56
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-ai-sparkle.d.ts +109 -0
- package/dist/hooks/use-ai-sparkle.d.ts.map +1 -0
- package/dist/index.js +1106 -1102
- package/dist/index.js.map +1 -1
- package/dist/patterns/calendar/index.js +1 -1
- package/package.json +1 -1
- package/dist/_chunks/rich-text-editor-BYE6kK4u.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text-editor-BrAvNajV.js","sources":["../../node_modules/lucide-react/dist/esm/icons/baseline.mjs","../../node_modules/lucide-react/dist/esm/icons/between-horizontal-end.mjs","../../node_modules/lucide-react/dist/esm/icons/between-horizontal-start.mjs","../../node_modules/lucide-react/dist/esm/icons/between-vertical-end.mjs","../../node_modules/lucide-react/dist/esm/icons/between-vertical-start.mjs","../../node_modules/lucide-react/dist/esm/icons/bold.mjs","../../node_modules/lucide-react/dist/esm/icons/book-dashed.mjs","../../node_modules/lucide-react/dist/esm/icons/braces.mjs","../../node_modules/lucide-react/dist/esm/icons/columns-2.mjs","../../node_modules/lucide-react/dist/esm/icons/heading-2.mjs","../../node_modules/lucide-react/dist/esm/icons/heading-3.mjs","../../node_modules/lucide-react/dist/esm/icons/italic.mjs","../../node_modules/lucide-react/dist/esm/icons/link.mjs","../../node_modules/lucide-react/dist/esm/icons/list-ordered.mjs","../../node_modules/lucide-react/dist/esm/icons/list.mjs","../../node_modules/lucide-react/dist/esm/icons/paint-bucket.mjs","../../node_modules/lucide-react/dist/esm/icons/paint-roller.mjs","../../node_modules/lucide-react/dist/esm/icons/palette.mjs","../../node_modules/lucide-react/dist/esm/icons/panel-left.mjs","../../node_modules/lucide-react/dist/esm/icons/panel-right.mjs","../../node_modules/lucide-react/dist/esm/icons/panel-top-dashed.mjs","../../node_modules/lucide-react/dist/esm/icons/panel-top.mjs","../../node_modules/lucide-react/dist/esm/icons/pencil-sparkles.mjs","../../node_modules/lucide-react/dist/esm/icons/pilcrow.mjs","../../node_modules/lucide-react/dist/esm/icons/quote.mjs","../../node_modules/lucide-react/dist/esm/icons/redo-2.mjs","../../node_modules/lucide-react/dist/esm/icons/rows-2.mjs","../../node_modules/lucide-react/dist/esm/icons/spell-check.mjs","../../node_modules/lucide-react/dist/esm/icons/strikethrough.mjs","../../node_modules/lucide-react/dist/esm/icons/table.mjs","../../node_modules/lucide-react/dist/esm/icons/text-align-center.mjs","../../node_modules/lucide-react/dist/esm/icons/text-align-end.mjs","../../node_modules/lucide-react/dist/esm/icons/text-align-start.mjs","../../node_modules/lucide-react/dist/esm/icons/underline.mjs","../../node_modules/lucide-react/dist/esm/icons/wand-sparkles.mjs","../../node_modules/lucide-react/dist/esm/icons/wrench.mjs","../../src/components/rich-text-editor/rich-text-editor.agent.ts","../../src/components/rich-text-editor/help-me-write-overlay.tsx","../../src/components/rich-text-editor/editor-toolbar.tsx","../../src/components/rich-text-editor/rich-text-editor.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M4 20h16\", key: \"14thso\" }],\n [\"path\", { d: \"m6 16 6-12 6 12\", key: \"1b4byz\" }],\n [\"path\", { d: \"M8 12h8\", key: \"1wcyev\" }]\n];\nconst Baseline = createLucideIcon(\"baseline\", __iconNode);\n\nexport { __iconNode, Baseline as default };\n//# sourceMappingURL=baseline.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"13\", height: \"7\", x: \"3\", y: \"3\", rx: \"1\", key: \"11xb64\" }],\n [\"path\", { d: \"m22 15-3-3 3-3\", key: \"26chmm\" }],\n [\"rect\", { width: \"13\", height: \"7\", x: \"3\", y: \"14\", rx: \"1\", key: \"k6ky7n\" }]\n];\nconst BetweenHorizontalEnd = createLucideIcon(\"between-horizontal-end\", __iconNode);\n\nexport { __iconNode, BetweenHorizontalEnd as default };\n//# sourceMappingURL=between-horizontal-end.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"13\", height: \"7\", x: \"8\", y: \"3\", rx: \"1\", key: \"pkso9a\" }],\n [\"path\", { d: \"m2 9 3 3-3 3\", key: \"1agib5\" }],\n [\"rect\", { width: \"13\", height: \"7\", x: \"8\", y: \"14\", rx: \"1\", key: \"1q5fc1\" }]\n];\nconst BetweenHorizontalStart = createLucideIcon(\"between-horizontal-start\", __iconNode);\n\nexport { __iconNode, BetweenHorizontalStart as default };\n//# sourceMappingURL=between-horizontal-start.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"7\", height: \"13\", x: \"3\", y: \"3\", rx: \"1\", key: \"1fdu0f\" }],\n [\"path\", { d: \"m9 22 3-3 3 3\", key: \"17z65a\" }],\n [\"rect\", { width: \"7\", height: \"13\", x: \"14\", y: \"3\", rx: \"1\", key: \"1squn4\" }]\n];\nconst BetweenVerticalEnd = createLucideIcon(\"between-vertical-end\", __iconNode);\n\nexport { __iconNode, BetweenVerticalEnd as default };\n//# sourceMappingURL=between-vertical-end.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"7\", height: \"13\", x: \"3\", y: \"8\", rx: \"1\", key: \"1fjrkv\" }],\n [\"path\", { d: \"m15 2-3 3-3-3\", key: \"1uh6eb\" }],\n [\"rect\", { width: \"7\", height: \"13\", x: \"14\", y: \"8\", rx: \"1\", key: \"w3fjg8\" }]\n];\nconst BetweenVerticalStart = createLucideIcon(\"between-vertical-start\", __iconNode);\n\nexport { __iconNode, BetweenVerticalStart as default };\n//# sourceMappingURL=between-vertical-start.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n { d: \"M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8\", key: \"mg9rjx\" }\n ]\n];\nconst Bold = createLucideIcon(\"bold\", __iconNode);\n\nexport { __iconNode, Bold as default };\n//# sourceMappingURL=bold.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 17h1.5\", key: \"1gkc67\" }],\n [\"path\", { d: \"M12 22h1.5\", key: \"1my7sn\" }],\n [\"path\", { d: \"M12 2h1.5\", key: \"19tvb7\" }],\n [\"path\", { d: \"M17.5 22H19a1 1 0 0 0 1-1\", key: \"10akbh\" }],\n [\"path\", { d: \"M17.5 2H19a1 1 0 0 1 1 1v1.5\", key: \"1vrfjs\" }],\n [\"path\", { d: \"M20 14v3h-2.5\", key: \"1naeju\" }],\n [\"path\", { d: \"M20 8.5V10\", key: \"1ctpfu\" }],\n [\"path\", { d: \"M4 10V8.5\", key: \"1o3zg5\" }],\n [\"path\", { d: \"M4 19.5V14\", key: \"ob81pf\" }],\n [\"path\", { d: \"M4 4.5A2.5 2.5 0 0 1 6.5 2H8\", key: \"s8vcyb\" }],\n [\"path\", { d: \"M8 22H6.5a1 1 0 0 1 0-5H8\", key: \"1cu73q\" }]\n];\nconst BookDashed = createLucideIcon(\"book-dashed\", __iconNode);\n\nexport { __iconNode, BookDashed as default };\n//# sourceMappingURL=book-dashed.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n { d: \"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1\", key: \"ezmyqa\" }\n ],\n [\n \"path\",\n {\n d: \"M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1\",\n key: \"e1hn23\"\n }\n ]\n];\nconst Braces = createLucideIcon(\"braces\", __iconNode);\n\nexport { __iconNode, Braces as default };\n//# sourceMappingURL=braces.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M12 3v18\", key: \"108xh3\" }]\n];\nconst Columns2 = createLucideIcon(\"columns-2\", __iconNode);\n\nexport { __iconNode, Columns2 as default };\n//# sourceMappingURL=columns-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M4 12h8\", key: \"17cfdx\" }],\n [\"path\", { d: \"M4 18V6\", key: \"1rz3zl\" }],\n [\"path\", { d: \"M12 18V6\", key: \"zqpxq5\" }],\n [\"path\", { d: \"M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1\", key: \"9jr5yi\" }]\n];\nconst Heading2 = createLucideIcon(\"heading-2\", __iconNode);\n\nexport { __iconNode, Heading2 as default };\n//# sourceMappingURL=heading-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M4 12h8\", key: \"17cfdx\" }],\n [\"path\", { d: \"M4 18V6\", key: \"1rz3zl\" }],\n [\"path\", { d: \"M12 18V6\", key: \"zqpxq5\" }],\n [\"path\", { d: \"M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2\", key: \"68ncm8\" }],\n [\"path\", { d: \"M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2\", key: \"1ejuhz\" }]\n];\nconst Heading3 = createLucideIcon(\"heading-3\", __iconNode);\n\nexport { __iconNode, Heading3 as default };\n//# sourceMappingURL=heading-3.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"line\", { x1: \"19\", x2: \"10\", y1: \"4\", y2: \"4\", key: \"15jd3p\" }],\n [\"line\", { x1: \"14\", x2: \"5\", y1: \"20\", y2: \"20\", key: \"bu0au3\" }],\n [\"line\", { x1: \"15\", x2: \"9\", y1: \"4\", y2: \"20\", key: \"uljnxc\" }]\n];\nconst Italic = createLucideIcon(\"italic\", __iconNode);\n\nexport { __iconNode, Italic as default };\n//# sourceMappingURL=italic.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\", key: \"1cjeqo\" }],\n [\"path\", { d: \"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\", key: \"19qd67\" }]\n];\nconst Link = createLucideIcon(\"link\", __iconNode);\n\nexport { __iconNode, Link as default };\n//# sourceMappingURL=link.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M11 5h10\", key: \"1cz7ny\" }],\n [\"path\", { d: \"M11 12h10\", key: \"1438ji\" }],\n [\"path\", { d: \"M11 19h10\", key: \"11t30w\" }],\n [\"path\", { d: \"M4 4h1v5\", key: \"10yrso\" }],\n [\"path\", { d: \"M4 9h2\", key: \"r1h2o0\" }],\n [\"path\", { d: \"M6.5 20H3.4c0-1 2.6-1.925 2.6-3.5a1.5 1.5 0 0 0-2.6-1.02\", key: \"xtkcd5\" }]\n];\nconst ListOrdered = createLucideIcon(\"list-ordered\", __iconNode);\n\nexport { __iconNode, ListOrdered as default };\n//# sourceMappingURL=list-ordered.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M3 5h.01\", key: \"18ugdj\" }],\n [\"path\", { d: \"M3 12h.01\", key: \"nlz23k\" }],\n [\"path\", { d: \"M3 19h.01\", key: \"noohij\" }],\n [\"path\", { d: \"M8 5h13\", key: \"1pao27\" }],\n [\"path\", { d: \"M8 12h13\", key: \"1za7za\" }],\n [\"path\", { d: \"M8 19h13\", key: \"m83p4d\" }]\n];\nconst List = createLucideIcon(\"list\", __iconNode);\n\nexport { __iconNode, List as default };\n//# sourceMappingURL=list.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M11 7 6 2\", key: \"1jwth8\" }],\n [\"path\", { d: \"M18.992 12H2.041\", key: \"xw1gg\" }],\n [\n \"path\",\n {\n d: \"M21.145 18.38A3.34 3.34 0 0 1 20 16.5a3.3 3.3 0 0 1-1.145 1.88c-.575.46-.855 1.02-.855 1.595A2 2 0 0 0 20 22a2 2 0 0 0 2-2.025c0-.58-.285-1.13-.855-1.595\",\n key: \"1nkol4\"\n }\n ],\n [\n \"path\",\n {\n d: \"m8.5 4.5 2.148-2.148a1.205 1.205 0 0 1 1.704 0l7.296 7.296a1.205 1.205 0 0 1 0 1.704l-7.592 7.592a3.615 3.615 0 0 1-5.112 0l-3.888-3.888a3.615 3.615 0 0 1 0-5.112L5.67 7.33\",\n key: \"1nk1rd\"\n }\n ]\n];\nconst PaintBucket = createLucideIcon(\"paint-bucket\", __iconNode);\n\nexport { __iconNode, PaintBucket as default };\n//# sourceMappingURL=paint-bucket.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"16\", height: \"6\", x: \"2\", y: \"2\", rx: \"2\", key: \"jcyz7m\" }],\n [\"path\", { d: \"M10 16v-2a2 2 0 0 1 2-2h8a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2\", key: \"1b9h7c\" }],\n [\"rect\", { width: \"4\", height: \"6\", x: \"8\", y: \"16\", rx: \"1\", key: \"d6e7yl\" }]\n];\nconst PaintRoller = createLucideIcon(\"paint-roller\", __iconNode);\n\nexport { __iconNode, PaintRoller as default };\n//# sourceMappingURL=paint-roller.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z\",\n key: \"e79jfc\"\n }\n ],\n [\"circle\", { cx: \"13.5\", cy: \"6.5\", r: \".5\", fill: \"currentColor\", key: \"1okk4w\" }],\n [\"circle\", { cx: \"17.5\", cy: \"10.5\", r: \".5\", fill: \"currentColor\", key: \"f64h9f\" }],\n [\"circle\", { cx: \"6.5\", cy: \"12.5\", r: \".5\", fill: \"currentColor\", key: \"qy21gx\" }],\n [\"circle\", { cx: \"8.5\", cy: \"7.5\", r: \".5\", fill: \"currentColor\", key: \"fotxhn\" }]\n];\nconst Palette = createLucideIcon(\"palette\", __iconNode);\n\nexport { __iconNode, Palette as default };\n//# sourceMappingURL=palette.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M9 3v18\", key: \"fh3hqa\" }]\n];\nconst PanelLeft = createLucideIcon(\"panel-left\", __iconNode);\n\nexport { __iconNode, PanelLeft as default };\n//# sourceMappingURL=panel-left.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M15 3v18\", key: \"14nvp0\" }]\n];\nconst PanelRight = createLucideIcon(\"panel-right\", __iconNode);\n\nexport { __iconNode, PanelRight as default };\n//# sourceMappingURL=panel-right.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M14 9h1\", key: \"l0svgy\" }],\n [\"path\", { d: \"M19 9h2\", key: \"te2zfg\" }],\n [\"path\", { d: \"M3 9h2\", key: \"1h4ldw\" }],\n [\"path\", { d: \"M9 9h1\", key: \"15jzuz\" }]\n];\nconst PanelTopDashed = createLucideIcon(\"panel-top-dashed\", __iconNode);\n\nexport { __iconNode, PanelTopDashed as default };\n//# sourceMappingURL=panel-top-dashed.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M3 9h18\", key: \"1pudct\" }]\n];\nconst PanelTop = createLucideIcon(\"panel-top\", __iconNode);\n\nexport { __iconNode, PanelTop as default };\n//# sourceMappingURL=panel-top.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M10 3H8\", key: \"mzdi2d\" }],\n [\"path\", { d: \"m15.007 5.008 3.987 3.986\", key: \"1scubj\" }],\n [\"path\", { d: \"M20 15v4\", key: \"nmhudv\" }],\n [\n \"path\",\n {\n d: \"M21.174 6.813a2.82 2.82 0 0 0-3.986-3.987L3.842 16.175a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\",\n key: \"fs0856\"\n }\n ],\n [\"path\", { d: \"M22 17h-4\", key: \"1sj068\" }],\n [\"path\", { d: \"M4 5v4\", key: \"13jjxc\" }],\n [\"path\", { d: \"M6 7H2\", key: \"8zbtv0\" }],\n [\"path\", { d: \"M9 2v2\", key: \"165o2o\" }]\n];\nconst PencilSparkles = createLucideIcon(\"pencil-sparkles\", __iconNode);\n\nexport { __iconNode, PencilSparkles as default };\n//# sourceMappingURL=pencil-sparkles.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M13 4v16\", key: \"8vvj80\" }],\n [\"path\", { d: \"M17 4v16\", key: \"7dpous\" }],\n [\"path\", { d: \"M19 4H9.5a4.5 4.5 0 0 0 0 9H13\", key: \"sh4n9v\" }]\n];\nconst Pilcrow = createLucideIcon(\"pilcrow\", __iconNode);\n\nexport { __iconNode, Pilcrow as default };\n//# sourceMappingURL=pilcrow.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\",\n key: \"rib7q0\"\n }\n ],\n [\n \"path\",\n {\n d: \"M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\",\n key: \"1ymkrd\"\n }\n ]\n];\nconst Quote = createLucideIcon(\"quote\", __iconNode);\n\nexport { __iconNode, Quote as default };\n//# sourceMappingURL=quote.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m15 14 5-5-5-5\", key: \"12vg1m\" }],\n [\"path\", { d: \"M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13\", key: \"6uklza\" }]\n];\nconst Redo2 = createLucideIcon(\"redo-2\", __iconNode);\n\nexport { __iconNode, Redo2 as default };\n//# sourceMappingURL=redo-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M3 12h18\", key: \"1i2n21\" }]\n];\nconst Rows2 = createLucideIcon(\"rows-2\", __iconNode);\n\nexport { __iconNode, Rows2 as default };\n//# sourceMappingURL=rows-2.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"m6 16 6-12 6 12\", key: \"1b4byz\" }],\n [\"path\", { d: \"M8 12h8\", key: \"1wcyev\" }],\n [\"path\", { d: \"m16 20 2 2 4-4\", key: \"13tcca\" }]\n];\nconst SpellCheck = createLucideIcon(\"spell-check\", __iconNode);\n\nexport { __iconNode, SpellCheck as default };\n//# sourceMappingURL=spell-check.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M16 4H9a3 3 0 0 0-2.83 4\", key: \"43sutm\" }],\n [\"path\", { d: \"M14 12a4 4 0 0 1 0 8H6\", key: \"nlfj13\" }],\n [\"line\", { x1: \"4\", x2: \"20\", y1: \"12\", y2: \"12\", key: \"1e0a9i\" }]\n];\nconst Strikethrough = createLucideIcon(\"strikethrough\", __iconNode);\n\nexport { __iconNode, Strikethrough as default };\n//# sourceMappingURL=strikethrough.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M12 3v18\", key: \"108xh3\" }],\n [\"rect\", { width: \"18\", height: \"18\", x: \"3\", y: \"3\", rx: \"2\", key: \"afitv7\" }],\n [\"path\", { d: \"M3 9h18\", key: \"1pudct\" }],\n [\"path\", { d: \"M3 15h18\", key: \"5xshup\" }]\n];\nconst Table = createLucideIcon(\"table\", __iconNode);\n\nexport { __iconNode, Table as default };\n//# sourceMappingURL=table.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M21 5H3\", key: \"1fi0y6\" }],\n [\"path\", { d: \"M17 12H7\", key: \"16if0g\" }],\n [\"path\", { d: \"M19 19H5\", key: \"vjpgq2\" }]\n];\nconst TextAlignCenter = createLucideIcon(\"text-align-center\", __iconNode);\n\nexport { __iconNode, TextAlignCenter as default };\n//# sourceMappingURL=text-align-center.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M21 5H3\", key: \"1fi0y6\" }],\n [\"path\", { d: \"M21 12H9\", key: \"dn1m92\" }],\n [\"path\", { d: \"M21 19H7\", key: \"4cu937\" }]\n];\nconst TextAlignEnd = createLucideIcon(\"text-align-end\", __iconNode);\n\nexport { __iconNode, TextAlignEnd as default };\n//# sourceMappingURL=text-align-end.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M21 5H3\", key: \"1fi0y6\" }],\n [\"path\", { d: \"M15 12H3\", key: \"6jk70r\" }],\n [\"path\", { d: \"M17 19H3\", key: \"z6ezky\" }]\n];\nconst TextAlignStart = createLucideIcon(\"text-align-start\", __iconNode);\n\nexport { __iconNode, TextAlignStart as default };\n//# sourceMappingURL=text-align-start.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\"path\", { d: \"M6 4v6a6 6 0 0 0 12 0V4\", key: \"9kb039\" }],\n [\"line\", { x1: \"4\", x2: \"20\", y1: \"20\", y2: \"20\", key: \"nun2al\" }]\n];\nconst Underline = createLucideIcon(\"underline\", __iconNode);\n\nexport { __iconNode, Underline as default };\n//# sourceMappingURL=underline.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72\",\n key: \"ul74o6\"\n }\n ],\n [\"path\", { d: \"m14 7 3 3\", key: \"1r5n42\" }],\n [\"path\", { d: \"M5 6v4\", key: \"ilb8ba\" }],\n [\"path\", { d: \"M19 14v4\", key: \"blhpug\" }],\n [\"path\", { d: \"M10 2v2\", key: \"7u0qdc\" }],\n [\"path\", { d: \"M7 8H3\", key: \"zfb6yr\" }],\n [\"path\", { d: \"M21 16h-4\", key: \"1cnmox\" }],\n [\"path\", { d: \"M11 3H9\", key: \"1obp7u\" }]\n];\nconst WandSparkles = createLucideIcon(\"wand-sparkles\", __iconNode);\n\nexport { __iconNode, WandSparkles as default };\n//# sourceMappingURL=wand-sparkles.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z\",\n key: \"1ngwbx\"\n }\n ]\n];\nconst Wrench = createLucideIcon(\"wrench\", __iconNode);\n\nexport { __iconNode, Wrench as default };\n//# sourceMappingURL=wrench.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { EditorFormat, RichTextEditorHandle } from './rich-text-editor';\n\nexport const richTextEditorAgent: AgentAdapter<RichTextEditorHandle> = {\n id: 'rich-text-editor',\n capabilities: ['edit_inline'],\n state: {\n html: {\n type: 'string',\n descriptionKey: 'ui.agent.richTextEditor.state.html',\n description: 'Sanitised HTML representation of the editor content.',\n read: (handle) => handle.getHTML(),\n },\n text: {\n type: 'string',\n descriptionKey: 'ui.agent.richTextEditor.state.text',\n description: 'Plain-text content of the editor (tags stripped).',\n read: (handle) => handle.getText(),\n },\n markdown: {\n type: 'string',\n descriptionKey: 'ui.agent.richTextEditor.state.markdown',\n description:\n 'Markdown representation of the editor content. The Redactor engine has no native Markdown serialiser, so this is always empty — read `html` instead.',\n read: (handle) => handle.getMarkdown(),\n },\n aiBusy: {\n type: 'boolean',\n descriptionKey: 'ui.agent.richTextEditor.state.aiBusy',\n description:\n 'True while a one-shot AI action (a practice template, spelling or auto-format) is rewriting the note. Read `html` once it is false.',\n read: (handle) => handle.isAiBusy(),\n },\n },\n // Image wrap/align/resize are intentionally NOT agent actions — they target\n // the ephemeral click-selected image the handle can't address. Agents emit\n // `<img class=\"wysiwyg-img-*\" style=\"width:N%\">` via set_content instead.\n actions: {\n set_content: {\n // Replaces the whole document — discards whatever the user had typed.\n safety: 'destructive',\n argsType: '{ html: string }',\n argsSchema: {\n type: 'object',\n properties: {\n html: {\n type: 'string',\n description: 'Replacement HTML (sanitised via DOMPurify).',\n },\n },\n required: ['html'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.richTextEditor.actions.setContent',\n description: 'Replace the editor content. Loses unsaved input.',\n invoke: (handle, args: { html: string }) => {\n handle.setContent(args.html);\n },\n },\n insert_at_cursor: {\n // Reversible via the editor's own undo stack — write, not destructive.\n safety: 'write',\n argsType: '{ content: string; asHtml?: boolean }',\n argsSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'Content to insert at the caret.',\n },\n asHtml: {\n type: 'boolean',\n description:\n 'Treat content as HTML (sanitised). Pass false for plain text. Defaults to true.',\n },\n },\n required: ['content'],\n },\n descriptionKey: 'ui.agent.richTextEditor.actions.insertAtCursor',\n description:\n 'Insert content at the caret (replacing any selection). HTML is sanitised; pass asHtml:false for plain text. Seam for merge/template variables and AI-generated drafts.',\n examples: [\n {\n args: { content: '{{patient.firstName}}', asHtml: false },\n note: 'Insert a merge variable as plain text.',\n },\n ],\n invoke: (handle, args: { content: string; asHtml?: boolean }) => {\n handle.insertAtCursor(args.content, { asHtml: args.asHtml });\n },\n },\n apply_format: {\n // Reversible via undo — write, not destructive.\n safety: 'write',\n argsType:\n \"{ format: 'bold' | 'italic' | 'strikethrough' | 'bulletedList' | 'numberedList' | 'heading' | 'quote' | 'paragraph' }\",\n argsSchema: {\n type: 'object',\n properties: {\n format: {\n type: 'string',\n enum: [\n 'bold',\n 'italic',\n 'strikethrough',\n 'bulletedList',\n 'numberedList',\n 'heading',\n 'quote',\n 'paragraph',\n ],\n description: 'Block or inline format to toggle/apply.',\n },\n },\n required: ['format'],\n },\n descriptionKey: 'ui.agent.richTextEditor.actions.applyFormat',\n description:\n 'Toggle/apply a block or inline format on the current selection (bold, italic, strikethrough, bulleted/numbered list, heading, quote, paragraph).',\n examples: [{ args: { format: 'bold' }, note: 'Bold the selection.' }],\n invoke: (handle, args: { format: EditorFormat }) => {\n handle.applyFormat(args.format);\n },\n },\n clear: {\n // Empties the document — loses unsaved input.\n safety: 'destructive',\n idempotent: true,\n descriptionKey: 'ui.agent.richTextEditor.actions.clear',\n description: 'Empty the editor. Loses unsaved input.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n focus: {\n safety: 'read',\n idempotent: true,\n descriptionKey: 'ui.agent.richTextEditor.actions.focus',\n description: 'Move keyboard focus to the editor surface.',\n invoke: (handle) => {\n handle.focus();\n },\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'rich-text-editor' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* HelpMeWriteOverlay — the \"Help me write\" flow on the non-modal */\n/* EditorOverlay (Gemini / Mac Mail style): a slim docked bar with a */\n/* one-row composer (mic · prompt · Write) → a preview of the draft with */\n/* Discard / Try again / Insert. */\n/* */\n/* The kit owns the UI; the backend call is the consumer's */\n/* `onRequestAiDraft({ prompt, signal })`. When `onDictate` is supplied */\n/* the composer grows a mic that streams transcripts INTO the prompt */\n/* (the same consumer dictation seam the editor FAB uses). The returned */\n/* draft is previewed (sanitised via SafeHtml) and only inserted on */\n/* confirm — sanitisation of the inserted value happens again at the */\n/* editor seam. */\n/* ------------------------------------------------------------------ */\n\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Check, Mic, RotateCcw, Send, Square, X } from 'lucide-react';\n\nimport { IconButton } from '../button';\nimport { Spinner } from '../spinner';\nimport { TextArea } from '../text-area';\nimport { SafeHtml } from '../_shared/safe-html';\nimport { EditorOverlay } from '../editor-overlay';\n\nexport interface HelpMeWriteOverlayProps {\n open: boolean;\n onClose: () => void;\n onRequestAiDraft: (ctx: {\n prompt: string;\n signal: AbortSignal;\n }) => Promise<string>;\n onInsert: (draft: string) => void;\n /** Preview + insert the draft as HTML (default) or plain text. */\n previewAsHtml?: boolean;\n privacyNotice?: ReactNode;\n /**\n * Voice dictation into the prompt. Same seam as the editor's `onDictate`:\n * the consumer runs mic + transcription and pushes text back; the kit appends\n * finals to the prompt. When omitted, the composer shows no mic.\n */\n onDictate?: (ctx: {\n signal: AbortSignal;\n onPartialTranscript: (text: string) => void;\n onFinalTranscript: (text: string) => void;\n }) => Promise<void>;\n}\n\n// Force the recording mic solid-destructive (red). IconButton's base\n// `aria-pressed:bg-muted` (for IconButtonGroup toggles) would otherwise\n// out-specify the intent fill, so the override is marked important.\nconst RECORDING_MIC =\n 'ds:aria-pressed:!bg-[var(--destructive)] ds:aria-pressed:!text-[var(--destructive-foreground)]';\n\n// Pin the action buttons to the input's height (--min-target-size, 44/48px) so\n// the composer's input + mic + send line up exactly. IconButton md is h-10\n// (40px), below the TextArea md min-height, so force the match (important wins\n// over the size variant). Scales with the accessible theme for free.\nconst ACTION_SIZE = 'ds:!size-[var(--min-target-size)]';\n\nconst noticeClass =\n 'ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--muted-foreground)]';\nconst errorClass =\n 'ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--destructive)]';\nconst previewClass = [\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[color-mix(in_srgb,var(--background)_70%,transparent)]',\n 'ds:p-[var(--spacing-sm)] ds:[max-block-size:10rem] ds:overflow-y-auto',\n 'ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--foreground)]',\n // The preview renders arbitrary model-generated rich text, and the\n // `rich-text` SafeHtml profile allows ul/ol/li. Inside a\n // [data-component] preflight's list reset still applies and the host\n // undo deliberately does not reach, so markers and indent have to be\n // asked for explicitly — otherwise a generated bullet list previews as\n // flush, marker-less lines.\n 'ds:[&_ul]:list-disc ds:[&_ol]:list-decimal',\n 'ds:[&_ul]:ps-[var(--spacing-md)] ds:[&_ol]:ps-[var(--spacing-md)]',\n].join(' ');\n\n// Join a base string with appended dictation text, inserting a single space\n// only when the base doesn't already end in whitespace.\nfunction joinWith(base: string, extra: string): string {\n if (!extra) return base;\n if (!base) return extra;\n return /\\s$/.test(base) ? `${base}${extra}` : `${base} ${extra}`;\n}\n\nexport function HelpMeWriteOverlay({\n open,\n onClose,\n onRequestAiDraft,\n onInsert,\n previewAsHtml = true,\n privacyNotice,\n onDictate,\n}: HelpMeWriteOverlayProps): React.JSX.Element {\n const { t } = useTranslation();\n const promptId = useId();\n const errorId = useId();\n const [prompt, setPrompt] = useState('');\n const [loading, setLoading] = useState(false);\n const [errored, setErrored] = useState(false);\n const [draft, setDraft] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n /* ---- In-prompt voice dictation (consumer runs mic + STT) ---- */\n const [isDictating, setIsDictating] = useState(false);\n const [interim, setInterim] = useState('');\n // Drives the visually-hidden live region: announces the listening status on\n // start and each committed phrase as it lands. The interim text shows in the\n // read-only field, but SR users can't perceive a read-only value change, so\n // the polite region gives them the same feedback.\n const [dictationAnnouncement, setDictationAnnouncement] = useState('');\n const dictateAbortRef = useRef<AbortController | null>(null);\n\n const stopDictation = useCallback(() => {\n dictateAbortRef.current?.abort();\n }, []);\n\n const startDictation = useCallback(() => {\n if (!onDictate) return;\n const controller = new AbortController();\n dictateAbortRef.current = controller;\n setIsDictating(true);\n setInterim('');\n setDictationAnnouncement(t('editor.ai.listening'));\n onDictate({\n signal: controller.signal,\n onPartialTranscript: (text: string): void => {\n if (controller.signal.aborted) return;\n setInterim(text);\n },\n onFinalTranscript: (text: string): void => {\n if (controller.signal.aborted) return;\n const trimmed = text.trim();\n setInterim('');\n if (trimmed) {\n setPrompt((p) => joinWith(p, trimmed));\n setDictationAnnouncement(trimmed);\n }\n },\n })\n .catch(() => {\n /* dictation errors are non-fatal here — the user can type instead */\n })\n .finally(() => {\n setInterim('');\n if (dictateAbortRef.current === controller) {\n dictateAbortRef.current = null;\n setIsDictating(false);\n setDictationAnnouncement('');\n }\n });\n }, [onDictate, t]);\n\n const toggleDictation = useCallback(() => {\n if (isDictating) stopDictation();\n else startDictation();\n }, [isDictating, startDictation, stopDictation]);\n\n // Fresh state each time it opens; abort any in-flight request/dictation on close.\n useEffect(() => {\n if (open) {\n setPrompt('');\n setLoading(false);\n setErrored(false);\n setDraft(null);\n setInterim('');\n setDictationAnnouncement('');\n } else {\n abortRef.current?.abort();\n abortRef.current = null;\n dictateAbortRef.current?.abort();\n }\n }, [open]);\n useEffect(\n () => () => {\n abortRef.current?.abort();\n dictateAbortRef.current?.abort();\n },\n [],\n );\n\n const generate = useCallback(() => {\n const trimmed = prompt.trim();\n if (!trimmed || loading) return;\n stopDictation();\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n setErrored(false);\n setLoading(true);\n onRequestAiDraft({ prompt: trimmed, signal: controller.signal })\n .then((result) => {\n if (controller.signal.aborted) return;\n setDraft(result);\n setLoading(false);\n })\n .catch((err: unknown) => {\n if (\n controller.signal.aborted ||\n (err &&\n typeof err === 'object' &&\n 'name' in err &&\n (err as { name?: string }).name === 'AbortError')\n ) {\n return;\n }\n setErrored(true);\n setLoading(false);\n });\n }, [prompt, loading, onRequestAiDraft, stopDictation]);\n\n const insert = useCallback(() => {\n if (draft == null) return;\n onInsert(draft);\n onClose();\n }, [draft, onInsert, onClose]);\n\n const hasDraft = draft != null;\n // While dictating, show committed prompt + live interim; the field is\n // read-only so the streamed text isn't fought over by onChange.\n const fieldValue = isDictating ? joinWith(prompt, interim) : prompt;\n\n return (\n <EditorOverlay\n open={open}\n onClose={onClose}\n ariaLabel={t('editor.ai.dialogTitle')}\n >\n {hasDraft ? (\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <IconButton\n size=\"md\"\n intent=\"outline\"\n className={ACTION_SIZE}\n icon={<X />}\n aria-label={t('common.close')}\n onClick={onClose}\n />\n <div className=\"ds:min-w-0 ds:flex-1\">\n {previewAsHtml ? (\n <SafeHtml\n html={draft as string}\n profile=\"rich-text\"\n className={previewClass}\n tabIndex={0}\n aria-label={t('editor.ai.dialogTitle')}\n />\n ) : (\n // Focusable so a keyboard user can scroll a long draft preview\n // (mirrors the SafeHtml preview branch above). The lint rule's\n // tabIndex allowlist doesn't cover a scrollable, non-interactive\n // text region.\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex\n <p className={previewClass} tabIndex={0}>\n {draft}\n </p>\n )}\n </div>\n <IconButton\n size=\"md\"\n intent=\"outline\"\n className={`${ACTION_SIZE} ds:rounded-full`}\n icon={<RotateCcw />}\n aria-label={t('editor.ai.retry')}\n onClick={() => setDraft(null)}\n />\n <IconButton\n size=\"md\"\n intent=\"primary\"\n className={`${ACTION_SIZE} ds:bg-[image:var(--gradient-brand)] ds:rounded-full`}\n icon={<Check />}\n aria-label={t('common.confirm')}\n onClick={insert}\n />\n </div>\n ) : (\n <>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n <IconButton\n size=\"md\"\n intent=\"outline\"\n className={ACTION_SIZE}\n icon={<X />}\n aria-label={t('common.close')}\n onClick={onClose}\n />\n <div className=\"ds:min-w-0 ds:flex-1\">\n <TextArea\n id={promptId}\n size=\"md\"\n value={fieldValue}\n onChange={(event) => setPrompt(event.target.value)}\n placeholder={t('editor.ai.promptPlaceholder')}\n aria-label={t('editor.ai.promptLabel')}\n autoResize\n minRows={1}\n maxRows={3}\n readOnly={isDictating}\n tone={errored ? 'error' : 'default'}\n aria-describedby={errored ? errorId : undefined}\n />\n </div>\n {onDictate ? (\n <IconButton\n size=\"md\"\n intent=\"outline\"\n className={\n isDictating ? `${ACTION_SIZE} ${RECORDING_MIC}` : ACTION_SIZE\n }\n icon={\n isDictating ? <Square className=\"ds:fill-current\" /> : <Mic />\n }\n aria-pressed={isDictating}\n aria-label={\n isDictating\n ? t('editor.ai.dictateStop')\n : t('editor.ai.dictateStart')\n }\n onClick={toggleDictation}\n />\n ) : null}\n <IconButton\n size=\"md\"\n intent=\"primary\"\n icon={loading ? <Spinner size=\"sm\" variant=\"pulse\" /> : <Send />}\n className={`${ACTION_SIZE} ds:bg-[image:var(--gradient-brand)] ds:rounded-full`}\n disabled={loading || !prompt.trim()}\n aria-busy={loading || undefined}\n aria-label={t('editor.ai.generate')}\n onClick={generate}\n />\n </div>\n {onDictate ? (\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {dictationAnnouncement}\n </p>\n ) : null}\n {errored ? (\n <p id={errorId} role=\"alert\" className={errorClass}>\n {t('editor.ai.error')}\n </p>\n ) : privacyNotice ? (\n <p className={noticeClass}>{privacyNotice}</p>\n ) : null}\n </>\n )}\n </EditorOverlay>\n );\n}\n","/* ------------------------------------------------------------------ */\n/* EditorToolbar — the kit's OWN toolbar for RichTextEditor. */\n/* */\n/* Redactor renders with `toolbar: false` (no native toolbar); this DS */\n/* toolbar drives the editor through Redactor's command API via `run` */\n/* and, for surfaces that would otherwise use Redactor's own modals */\n/* (link, image), through DS Dialogs + the `insertHtml` seam so EVERY */\n/* interactive surface is a kit component. Colour uses the DS */\n/* ColorPicker; the style menu is a labelled menu button; table offers */\n/* a size-grid insert + contextual row/column/header ops. */\n/* ------------------------------------------------------------------ */\n\nimport {\n Fragment,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type ReactNode,\n type RefObject,\n} from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n Baseline,\n BetweenHorizontalEnd,\n BetweenHorizontalStart,\n BetweenVerticalEnd,\n BetweenVerticalStart,\n Bold,\n BookDashed,\n Braces,\n ChevronDown,\n Columns2,\n Heading2,\n Heading3,\n Highlighter,\n Image as ImageIcon,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Ellipsis,\n PaintBucket,\n PaintRoller,\n PanelLeft,\n PanelRight,\n PanelTop,\n PanelTopDashed,\n Palette,\n Pilcrow,\n Redo2,\n Plus,\n Quote,\n Rows2,\n Settings,\n Strikethrough,\n Table as TableIcon,\n TextAlignCenter,\n TextAlignEnd,\n TextAlignStart,\n Trash2,\n Underline,\n Undo2,\n Wrench,\n} from 'lucide-react';\nimport { cva } from 'class-variance-authority';\nimport * as RadixPopover from '@radix-ui/react-popover';\nimport type {\n RichTextEditorAiTemplate,\n RichTextEditorVariable,\n} from './rich-text-editor';\nimport { VariablesMenu, type VariablesMenuVariable } from '../variables-menu';\n\nimport { Button, IconButton } from '../button';\nimport { TooltipProvider } from '../tooltip';\nimport { Popover } from '../popover';\nimport { DropdownMenu } from '../dropdown-menu';\nimport { Dialog } from '../dialog';\nimport { ColorPicker } from '../color-picker';\nimport { TextInput } from '../text-input';\nimport { Checkbox } from '../checkbox';\nimport { FileUpload } from '../file-upload';\n\nexport type EditorToolbarPreset = 'minimal' | 'standard' | 'full';\n\nexport interface EditorToolbarProps {\n /** Dispatch a Redactor command (and refresh active state). */\n run: (command: string, ...args: unknown[]) => void;\n /** Active formats at the caret — toggle buttons render pressed. */\n active: ReadonlySet<string>;\n preset: EditorToolbarPreset;\n /** Insert sanitised HTML at the caret (link / image / table). */\n insertHtml: (html: string) => void;\n /** Insert a table — list-aware (drops it after a list, never inside an <li>). */\n insertTable: (html: string) => void;\n /** Save the editor selection before a DS popover/dialog takes focus. */\n saveSelection: () => void;\n /** Restore the saved selection before applying. */\n restoreSelection: () => void;\n /** Current selected text — prefills the link dialog's text field. */\n getSelectedText: () => string;\n /** Upload an image file and resolve its URL (image dialog's upload area). */\n uploadImage?: (file: File, signal?: AbortSignal) => Promise<string>;\n /** Show the text-colour control. */\n enableColor?: boolean;\n /** Show the image control (consumer set an image-upload URL). */\n enableImage?: boolean;\n /** Show the table control (consumer loaded the table plugin). */\n enableTable?: boolean;\n /**\n * Show an \"Editor extensions\" tools affordance (marketplace tools), placed\n * inline at the end of the toolbar. Currently a visual placeholder — not\n * wired to a menu.\n */\n showExtensions?: boolean;\n /** Template variables for the \"Insert variable\" menu (hidden when empty). */\n variables?: RichTextEditorVariable[];\n /** Most-recently-used tokens, most recent first — rendered as the menu's\n * \"Recent\" group (max 3). Forwarded from `RichTextEditor`. */\n recentVariableTokens?: string[];\n /** Insert a variable chip at the saved caret. */\n insertVariable?: (token: string) => void;\n}\n\n/** i18n key + English fallback (for keys not yet in every locale). */\ntype L = [string, string];\n\ninterface ToolbarItem {\n id: string;\n icon: ReactNode;\n label: L;\n command: [string, ...unknown[]];\n /** When set, the button is a toggle and presses when `active` has this key. */\n toggle?: string;\n}\n\nconst ITEMS: Record<string, ToolbarItem> = {\n // Redactor's own history. AI rewrites push onto it too (see\n // `pushUndoState` in rich-text-editor.tsx), so Undo steps back over them.\n undo: {\n id: 'undo',\n icon: <Undo2 />,\n label: ['editor.undo', 'Undo'],\n command: ['module.buffer.undo'],\n },\n redo: {\n id: 'redo',\n icon: <Redo2 />,\n label: ['editor.redo', 'Redo'],\n command: ['module.buffer.redo'],\n },\n bold: {\n id: 'bold',\n icon: <Bold />,\n label: ['editor.bold', 'Bold'],\n command: ['module.inline.format', { tag: 'b' }],\n toggle: 'bold',\n },\n italic: {\n id: 'italic',\n icon: <Italic />,\n label: ['editor.italic', 'Italic'],\n command: ['module.inline.format', { tag: 'i' }],\n toggle: 'italic',\n },\n underline: {\n id: 'underline',\n icon: <Underline />,\n label: ['editor.underline', 'Underline'],\n command: ['module.inline.format', { tag: 'u' }],\n toggle: 'underline',\n },\n strike: {\n id: 'strike',\n icon: <Strikethrough />,\n label: ['editor.strike', 'Strikethrough'],\n command: ['module.inline.format', { tag: 'del' }],\n toggle: 'strike',\n },\n ul: {\n id: 'ul',\n icon: <List />,\n label: ['editor.list.bullet', 'Bulleted list'],\n command: ['module.list.toggle', 'ul'],\n toggle: 'ul',\n },\n ol: {\n id: 'ol',\n icon: <ListOrdered />,\n label: ['editor.list.ordered', 'Numbered list'],\n command: ['module.list.toggle', 'ol'],\n toggle: 'ol',\n },\n};\n\n// Block-format options. `id` matches the active token emitted by the editor\n// (paragraph / h2 / h3 / quote) so the labelled button shows the active style.\nconst FORMAT_OPTIONS: { id: string; tag: string; icon: ReactNode; label: L }[] =\n [\n {\n id: 'paragraph',\n tag: 'p',\n icon: <Pilcrow />,\n label: ['editor.paragraph', 'Paragraph'],\n },\n {\n id: 'h2',\n tag: 'h2',\n icon: <Heading2 />,\n label: ['editor.heading2', 'Heading 2'],\n },\n {\n id: 'h3',\n tag: 'h3',\n icon: <Heading3 />,\n label: ['editor.heading3', 'Heading 3'],\n },\n {\n id: 'quote',\n tag: 'blockquote',\n icon: <Quote />,\n label: ['editor.quote', 'Quote'],\n },\n ];\n\nconst PRESETS: Record<EditorToolbarPreset, string[]> = {\n minimal: ['bold', 'italic', 'underline', 'link'],\n standard: [\n 'undo',\n 'redo',\n 'format',\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'ul',\n 'ol',\n 'link',\n ],\n full: [\n 'undo',\n 'redo',\n 'format',\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'ul',\n 'ol',\n 'link',\n ],\n};\n\n// Table ops mirror EXACTLY the commands platform's Redactor table plugin\n// exposes (verified against platform/web/static/redactor/_plugins/table) — it\n// has no merge/split/align commands, so neither do we.\nconst TABLE_OPS: { id: string; command: string; icon: ReactNode; label: L }[] =\n [\n {\n id: 'rowAbove',\n command: 'plugin.table.addRowAbove',\n icon: <BetweenHorizontalStart />,\n label: ['editor.table.rowAbove', 'Add row above'],\n },\n {\n id: 'rowBelow',\n command: 'plugin.table.addRowBelow',\n icon: <BetweenHorizontalEnd />,\n label: ['editor.table.rowBelow', 'Add row below'],\n },\n {\n id: 'colLeft',\n command: 'plugin.table.addColumnLeft',\n icon: <BetweenVerticalStart />,\n label: ['editor.table.columnLeft', 'Add column left'],\n },\n {\n id: 'colRight',\n command: 'plugin.table.addColumnRight',\n icon: <BetweenVerticalEnd />,\n label: ['editor.table.columnRight', 'Add column right'],\n },\n {\n id: 'addHead',\n command: 'plugin.table.addHead',\n icon: <PanelTop />,\n label: ['editor.table.addHeader', 'Add header row'],\n },\n {\n id: 'deleteHead',\n command: 'plugin.table.deleteHead',\n icon: <PanelTopDashed />,\n label: ['editor.table.deleteHeader', 'Remove header row'],\n },\n {\n id: 'deleteRow',\n command: 'plugin.table.deleteRow',\n icon: <Rows2 />,\n label: ['editor.table.deleteRow', 'Delete row'],\n },\n {\n id: 'deleteColumn',\n command: 'plugin.table.deleteColumn',\n icon: <Columns2 />,\n label: ['editor.table.deleteColumn', 'Delete column'],\n },\n {\n id: 'deleteTable',\n command: 'plugin.table.deleteTable',\n icon: <Trash2 />,\n label: ['editor.table.deleteTable', 'Delete table'],\n },\n ];\n\nconst TABLE_GRID = 6; // max rows/cols offered by the size picker\n\n// Outer element: query container ('toolbar') + visual chrome. The flex row\n// lives in `toolbarRowClass` on an inner child so `container-type` is never set\n// on the flex parent (that would blockify the inline-flowing controls).\nconst toolbarClass = cva(\n [\n 'ds:@container/toolbar',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--background)] ds:p-[var(--spacing-xs)]',\n 'ds:shadow-[var(--shadow-md)]',\n ].join(' '),\n);\n\nconst toolbarRowClass =\n 'ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]';\n\nconst dividerClass =\n 'ds:self-stretch ds:[inline-size:var(--border-width-sm)] ds:bg-[var(--border)] ds:[margin-inline:var(--spacing-2xs)]';\n\nconst fieldLabelClass =\n 'ds:text-[length:var(--font-size-sm)] ds:font-medium ds:text-[color:var(--foreground)]';\n\n// Escape a string for safe interpolation; insertHtml re-sanitises via DOMPurify,\n// but encoding here keeps the constructed markup well-formed first.\nfunction esc(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\n/* ------------------------------------------------------------------ */\n/* Style — labelled menu button */\n/* ------------------------------------------------------------------ */\n\n/* ------------------------------------------------------------------ */\n/* Insert variable */\n/* ------------------------------------------------------------------ */\n\nfunction VariableMenu({\n variables,\n recentVariableTokens,\n insertVariable,\n saveSelection,\n}: {\n variables: RichTextEditorVariable[];\n recentVariableTokens?: string[];\n insertVariable: (token: string) => void;\n saveSelection: () => void;\n}): React.JSX.Element {\n const { t } = useTranslation();\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const triggerRef = useRef<HTMLButtonElement>(null);\n // After a pick the caret goes back into the editor, so skip Radix's focus\n // return to the trigger. A plain dismiss (Escape) still returns there.\n const pickedRef = useRef(false);\n\n const menuVariables: VariablesMenuVariable[] = variables;\n\n return (\n <RadixPopover.Root\n open={open}\n onOpenChange={(next) => {\n // Snapshot the caret while it is still in the editor.\n if (next) saveSelection();\n setOpen(next);\n if (next) setQuery('');\n }}\n >\n <RadixPopover.Trigger asChild>\n <IconButton\n ref={triggerRef}\n size=\"sm\"\n intent=\"ghost\"\n icon={<Braces />}\n aria-label={t('editor.insertVariable', 'Insert variable')}\n />\n </RadixPopover.Trigger>\n <RadixPopover.Portal>\n <RadixPopover.Content\n align=\"start\"\n sideOffset={4}\n onCloseAutoFocus={(event) => {\n if (pickedRef.current) {\n event.preventDefault();\n pickedRef.current = false;\n }\n }}\n >\n <VariablesMenu\n variables={menuVariables}\n recentTokens={recentVariableTokens}\n query={query}\n onQueryChange={setQuery}\n searchFocusable\n aria-label={t('editor.insertVariable', 'Insert variable')}\n onSelect={(variable) => {\n pickedRef.current = true;\n insertVariable(variable.token);\n setOpen(false);\n }}\n onClose={() => setOpen(false)}\n />\n </RadixPopover.Content>\n </RadixPopover.Portal>\n </RadixPopover.Root>\n );\n}\n\nfunction StyleMenu({\n run,\n active,\n onTriggerDown,\n}: {\n run: EditorToolbarProps['run'];\n active: ReadonlySet<string>;\n onTriggerDown: (event: { preventDefault: () => void }) => void;\n}): React.JSX.Element {\n const { t } = useTranslation();\n const current =\n FORMAT_OPTIONS.find((o) => active.has(o.id)) ?? FORMAT_OPTIONS[0];\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <Button\n size=\"sm\"\n intent=\"ghost\"\n startIcon={current.icon}\n endIcon={<ChevronDown />}\n // Accessible name includes the current format so it (a) survives the\n // icon-only state below @md and (b) contains the visible label when\n // shown, satisfying WCAG 2.5.3 Label in Name.\n aria-label={`${t('editor.format', 'Paragraph style')}: ${t(\n current.label[0],\n current.label[1],\n )}`}\n onMouseDown={onTriggerDown}\n >\n {/* Drop the text label on a narrow toolbar — the start icon + chevron\n still convey \"current style + menu\", and the aria-label carries the\n accessible name. Shown again from 448px. The threshold is px, not\n the `@md` rem alias — container-query `rem` follows the host root\n font-size and misfires off a non-16px root. */}\n <span className=\"ds:hidden ds:@[448px]/toolbar:inline\">\n {t(current.label[0], current.label[1])}\n </span>\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"start\">\n {FORMAT_OPTIONS.map((opt) => (\n <DropdownMenu.Item\n key={opt.id}\n startIcon={opt.icon}\n onSelect={() => run('module.block.format', { tag: opt.tag })}\n >\n {t(opt.label[0], opt.label[1])}\n </DropdownMenu.Item>\n ))}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Link — DS Dialog */\n/* ------------------------------------------------------------------ */\n\nfunction LinkDialog({\n insertHtml,\n saveSelection,\n restoreSelection,\n getSelectedText,\n}: Pick<\n EditorToolbarProps,\n 'insertHtml' | 'saveSelection' | 'restoreSelection' | 'getSelectedText'\n>): React.JSX.Element {\n const { t } = useTranslation();\n const [open, setOpen] = useState(false);\n const [url, setUrl] = useState('');\n const [text, setText] = useState('');\n const [newTab, setNewTab] = useState(false);\n const urlId = useId();\n const textId = useId();\n\n const reset = (): void => {\n setUrl('');\n setText('');\n setNewTab(false);\n };\n\n const handleInsert = (): void => {\n const href = url.trim();\n if (!href) return;\n const label = text.trim() || href;\n const tab = newTab ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : '';\n const html = `<a href=\"${esc(href)}\"${tab}>${esc(label)}</a>`;\n setOpen(false);\n reset();\n window.requestAnimationFrame(() => {\n restoreSelection();\n insertHtml(html);\n });\n };\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n <Dialog.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<LinkIcon />}\n aria-label={t('editor.link.insert', 'Insert link')}\n // Save the selection synchronously (before focus leaves the editor);\n // no preventDefault — the modal Dialog needs normal focus handling.\n onMouseDown={() => {\n saveSelection();\n setText(getSelectedText());\n }}\n />\n </Dialog.Trigger>\n <Dialog.Content>\n <Dialog.Header>\n <Dialog.Title>{t('editor.link.insert', 'Insert link')}</Dialog.Title>\n </Dialog.Header>\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <label htmlFor={urlId} className={fieldLabelClass}>\n {t('editor.link.url', 'URL')}\n </label>\n <TextInput\n id={urlId}\n type=\"url\"\n value={url}\n onChange={(event) => setUrl(event.target.value)}\n placeholder=\"https://…\"\n />\n </div>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <label htmlFor={textId} className={fieldLabelClass}>\n {t('editor.link.text', 'Text to display')}\n </label>\n <TextInput\n id={textId}\n value={text}\n onChange={(event) => setText(event.target.value)}\n placeholder={t('editor.link.textPlaceholder', 'Link text')}\n />\n </div>\n <Checkbox\n checked={newTab}\n onCheckedChange={(checked) => setNewTab(checked === true)}\n label={t('editor.link.newTab', 'Open in new tab')}\n />\n </Dialog.Body>\n <Dialog.Footer>\n <Dialog.Close asChild>\n <Button intent=\"secondary\">{t('common.cancel')}</Button>\n </Dialog.Close>\n <Button onClick={handleInsert} disabled={!url.trim()}>\n {t('editor.link.insertAction', 'Insert')}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Image — DS Dialog */\n/* ------------------------------------------------------------------ */\n\nfunction ImageDialog({\n insertHtml,\n saveSelection,\n restoreSelection,\n uploadImage,\n}: Pick<\n EditorToolbarProps,\n 'insertHtml' | 'saveSelection' | 'restoreSelection' | 'uploadImage'\n>): React.JSX.Element {\n const { t } = useTranslation();\n const [open, setOpen] = useState(false);\n const [src, setSrc] = useState('');\n const [alt, setAlt] = useState('');\n const srcId = useId();\n const altId = useId();\n\n const insertImage = (url: string, altText: string): void => {\n const html = `<img src=\"${esc(url)}\" alt=\"${esc(altText)}\" loading=\"lazy\">`;\n setOpen(false);\n setSrc('');\n setAlt('');\n window.requestAnimationFrame(() => {\n restoreSelection();\n insertHtml(html);\n });\n };\n\n const handleInsert = (): void => {\n const url = src.trim();\n if (url) insertImage(url, alt.trim());\n };\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n <Dialog.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<ImageIcon />}\n aria-label={t('editor.image.insert', 'Insert image')}\n // No preventDefault — the modal Dialog needs normal focus handling.\n onMouseDown={() => saveSelection()}\n />\n </Dialog.Trigger>\n <Dialog.Content>\n <Dialog.Header>\n <Dialog.Title>\n {t('editor.image.insert', 'Insert image')}\n </Dialog.Title>\n </Dialog.Header>\n <Dialog.Body className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n {uploadImage ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span className={fieldLabelClass}>\n {t('editor.image.upload', 'Upload')}\n </span>\n <FileUpload\n variant=\"dropzone\"\n accept={{\n 'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'],\n }}\n maxFiles={1}\n onUpload={async (file, { signal }) => {\n const url = await uploadImage(file, signal);\n insertImage(url, file.name);\n }}\n />\n <span className=\"ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--muted-foreground)]\">\n {t('editor.image.orUrl', 'Or paste an image URL')}\n </span>\n </div>\n ) : null}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <label htmlFor={srcId} className={fieldLabelClass}>\n {t('editor.image.url', 'Image URL')}\n </label>\n <TextInput\n id={srcId}\n type=\"url\"\n value={src}\n onChange={(event) => setSrc(event.target.value)}\n placeholder=\"https://…\"\n />\n </div>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <label htmlFor={altId} className={fieldLabelClass}>\n {t('editor.image.alt', 'Alt text')}\n </label>\n <TextInput\n id={altId}\n value={alt}\n onChange={(event) => setAlt(event.target.value)}\n placeholder={t(\n 'editor.image.altPlaceholder',\n 'Describe the image',\n )}\n />\n </div>\n </Dialog.Body>\n <Dialog.Footer>\n <Dialog.Close asChild>\n <Button intent=\"secondary\">{t('common.cancel')}</Button>\n </Dialog.Close>\n <Button onClick={handleInsert} disabled={!src.trim()}>\n {t('editor.image.insertAction', 'Insert')}\n </Button>\n </Dialog.Footer>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Colour — DS ColorPicker */\n/* ------------------------------------------------------------------ */\n\nfunction ColourControl({\n run,\n saveSelection,\n restoreSelection,\n}: Pick<\n EditorToolbarProps,\n 'run' | 'saveSelection' | 'restoreSelection'\n>): React.JSX.Element {\n const { t } = useTranslation();\n // Colour-picker seed value: a text-colour picker emits arbitrary, user-chosen\n // colours, so a literal hex default (rather than a brand token) is correct.\n // eslint-disable-next-line no-restricted-syntax\n const [colour, setColour] = useState('#1f2a5c');\n\n // Apply on pick — a colour control shouldn't need a separate \"Apply\" step.\n // The picker is compact (swatch-only), so onChange fires once per swatch\n // click; mirror Redactor's fontcolor plugin (toggle <span> with a colour\n // style — `type: 'toggle'` is required for the format to apply).\n const applyColour = (hex: string): void => {\n setColour(hex);\n restoreSelection();\n run('module.inline.format', {\n tag: 'span',\n style: { color: hex },\n type: 'toggle',\n });\n };\n const removeColour = (): void => {\n restoreSelection();\n run('module.inline.remove', { style: 'color' });\n };\n\n return (\n <Popover onOpenChange={(o) => o && saveSelection()}>\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Palette />}\n aria-label={t('editor.textColor', 'Text colour')}\n onMouseDown={(event) => {\n event.preventDefault();\n saveSelection();\n }}\n />\n </Popover.Trigger>\n <Popover.Content side=\"bottom\" align=\"start\">\n <Popover.Heading>\n {t('editor.textColor', 'Text colour')}\n </Popover.Heading>\n <div className=\"ds:pt-[var(--spacing-sm)]\">\n <ColorPicker\n variant=\"inline\"\n size=\"sm\"\n value={colour}\n onChange={applyColour}\n />\n </div>\n <div className=\"ds:mt-[var(--spacing-sm)] ds:flex ds:items-center ds:justify-end\">\n <Button size=\"sm\" intent=\"secondary\" onClick={removeColour}>\n {t('editor.color.remove', 'Remove colour')}\n </Button>\n </div>\n </Popover.Content>\n </Popover>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Highlight — DS ColorPicker applied as a text background */\n/* ------------------------------------------------------------------ */\n\nfunction HighlightControl({\n run,\n saveSelection,\n restoreSelection,\n}: Pick<\n EditorToolbarProps,\n 'run' | 'saveSelection' | 'restoreSelection'\n>): React.JSX.Element {\n const { t } = useTranslation();\n // Highlight seed value: a highlight picker emits arbitrary, user-chosen\n // colours, so a literal hex default (rather than a brand token) is correct.\n // eslint-disable-next-line no-restricted-syntax\n const [colour, setColour] = useState('#fff3a3');\n\n // Apply on pick. Highlight is the same inline <span> as text colour, but the\n // style key is `background-color` (mirrors Redactor's fontcolor \"Highlight\").\n const applyHighlight = (hex: string): void => {\n setColour(hex);\n restoreSelection();\n run('module.inline.format', {\n tag: 'span',\n style: { 'background-color': hex },\n type: 'toggle',\n });\n };\n const removeHighlight = (): void => {\n restoreSelection();\n run('module.inline.remove', { style: 'background-color' });\n };\n\n return (\n <Popover onOpenChange={(o) => o && saveSelection()}>\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Highlighter />}\n aria-label={t('editor.highlightColor', 'Highlight')}\n onMouseDown={(event) => {\n event.preventDefault();\n saveSelection();\n }}\n />\n </Popover.Trigger>\n <Popover.Content side=\"bottom\" align=\"start\">\n <Popover.Heading>\n {t('editor.highlightColor', 'Highlight')}\n </Popover.Heading>\n <div className=\"ds:pt-[var(--spacing-sm)]\">\n <ColorPicker\n variant=\"inline\"\n size=\"sm\"\n value={colour}\n onChange={applyHighlight}\n />\n </div>\n <div className=\"ds:mt-[var(--spacing-sm)] ds:flex ds:items-center ds:justify-end\">\n <Button size=\"sm\" intent=\"secondary\" onClick={removeHighlight}>\n {t('editor.highlight.remove', 'Remove highlight')}\n </Button>\n </div>\n </Popover.Content>\n </Popover>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Table — size-grid insert + contextual ops */\n/* ------------------------------------------------------------------ */\n\nfunction buildTable(rows: number, cols: number): string {\n const cells = Array.from({ length: cols }, () => '<td><br></td>').join('');\n const body = Array.from({ length: rows }, () => `<tr>${cells}</tr>`).join('');\n return `<table><tbody>${body}</tbody></table>`;\n}\n\nfunction TableControl({\n run,\n insertTable,\n active,\n}: Pick<\n EditorToolbarProps,\n 'run' | 'insertTable' | 'active'\n>): React.JSX.Element {\n const { t } = useTranslation();\n const [hover, setHover] = useState<{ r: number; c: number }>({ r: 0, c: 0 });\n const inTable = active.has('table');\n\n return (\n <Popover onOpenChange={(o) => !o && setHover({ r: 0, c: 0 })}>\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<TableIcon />}\n aria-label={t('editor.table.insert', 'Insert table')}\n onMouseDown={(event) => event.preventDefault()}\n />\n </Popover.Trigger>\n <Popover.Content side=\"bottom\" align=\"start\">\n {inTable ? (\n // Caret is already inside a table — offer the manage ops only, never\n // a nested-table insert (mirrors Redactor's native dropdown, which\n // disables \"insert table\" while the caret is in a table).\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {TABLE_OPS.map((op) => (\n <button\n key={op.id}\n type=\"button\"\n onClick={() => run(op.command)}\n className=\"ds:flex ds:items-center ds:gap-[var(--spacing-sm)] ds:rounded-[var(--radius-sm)] ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-2xs)] ds:text-start ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--foreground)] ds:hover:bg-[var(--muted)]\"\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:size-4 ds:shrink-0 ds:items-center ds:justify-center ds:text-[color:var(--muted-foreground)]\"\n >\n {op.icon}\n </span>\n {t(op.label[0], op.label[1])}\n </button>\n ))}\n </div>\n ) : (\n <>\n <Popover.Heading>\n {t('editor.table.insert', 'Insert table')}\n </Popover.Heading>\n <div\n role=\"group\"\n aria-label={t('editor.table.sizePicker', 'Table size')}\n className=\"ds:mt-[var(--spacing-sm)] ds:grid ds:w-fit ds:grid-cols-6 ds:gap-[var(--spacing-2xs)]\"\n onMouseLeave={() => setHover({ r: 0, c: 0 })}\n >\n {Array.from({ length: TABLE_GRID * TABLE_GRID }, (_, i) => {\n const r = Math.floor(i / TABLE_GRID) + 1;\n const c = (i % TABLE_GRID) + 1;\n const on = r <= hover.r && c <= hover.c;\n return (\n <button\n key={i}\n type=\"button\"\n aria-label={t('editor.table.sizeCell', '{{r}}×{{c}}', {\n r,\n c,\n })}\n onMouseEnter={() => setHover({ r, c })}\n onClick={() => insertTable(buildTable(r, c))}\n className={`ds:size-5 ds:rounded-[var(--radius-sm)] ds:border ds:border-[color:var(--border)] ${\n on ? 'ds:bg-[var(--primary)]' : 'ds:bg-[var(--muted)]'\n }`}\n />\n );\n })}\n </div>\n <p className=\"ds:mt-[var(--spacing-xs)] ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--muted-foreground)]\">\n {hover.r > 0\n ? t('editor.table.sizeCell', '{{r}}×{{c}}', {\n r: hover.r,\n c: hover.c,\n })\n : t('editor.table.sizeHint', 'Pick a size')}\n </p>\n </>\n )}\n </Popover.Content>\n </Popover>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Floating in-cell table toolbar */\n/* */\n/* Appears anchored above the table whenever the caret is inside one, */\n/* so the common row/column ops are one click away without opening the */\n/* toolbar menu. Dispatches the same `plugin.table.*` commands via the */\n/* shared `run` seam; the toolbar TableControl menu stays as the place */\n/* for inserting tables and header ops. */\n/* ------------------------------------------------------------------ */\n\nconst TABLE_OP_BY_ID: Record<string, (typeof TABLE_OPS)[number]> =\n Object.fromEntries(TABLE_OPS.map((op) => [op.id, op]));\n\nconst tableFloatClass = [\n 'ds:absolute ds:z-20 ds:flex ds:items-center ds:gap-[var(--spacing-2xs)]',\n 'ds:[inset-block-start:var(--rte-tt-top)] ds:[inset-inline-start:var(--rte-tt-start)]',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--popover)] ds:p-[var(--spacing-2xs)] ds:shadow-[var(--shadow-lg)]',\n].join(' ');\n\nexport interface TableFloatingToolbarProps {\n active: ReadonlySet<string>;\n run: EditorToolbarProps['run'];\n /** Positioned container the bar is absolutely placed within. */\n areaRef: RefObject<HTMLDivElement | null>;\n /** The <table> the caret is currently inside (relative to this editor). */\n getActiveTableEl: () => HTMLElement | null;\n /** Show the cell/row background-colour controls (fontcolor plugin loaded). */\n enableColor?: boolean;\n /** Snapshot the current cell before a colour popover takes focus. */\n saveTableCell: () => void;\n /** Set/clear a background colour on the current cell or its row. */\n applyTableBackground: (scope: 'cell' | 'row', colour: string | null) => void;\n}\n\n// Colour-control seed: an arbitrary user-chosen background, so a literal hex\n// default is correct (mirrors ColourControl / HighlightControl).\n// eslint-disable-next-line no-restricted-syntax\nconst TABLE_BG_SEED = '#fde68a';\n\n// One cell/row background-colour control: an icon trigger → compact ColorPicker\n// (applies on pick) + a clear action. The cell is captured on open (saveTableCell)\n// because the popover takes focus; `onOpenChange` lets the bar stay mounted.\nfunction TableBgColourControl({\n scope,\n icon,\n label,\n onOpenChange,\n saveTableCell,\n applyTableBackground,\n}: {\n scope: 'cell' | 'row';\n icon: ReactNode;\n label: string;\n onOpenChange: (open: boolean) => void;\n saveTableCell: () => void;\n applyTableBackground: (scope: 'cell' | 'row', colour: string | null) => void;\n}): React.JSX.Element {\n const { t } = useTranslation();\n const [colour, setColour] = useState(TABLE_BG_SEED);\n return (\n <Popover\n onOpenChange={(open) => {\n onOpenChange(open);\n if (open) saveTableCell();\n }}\n >\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={icon}\n tooltip={label}\n onMouseDown={(event) => event.preventDefault()}\n />\n </Popover.Trigger>\n <Popover.Content side=\"bottom\" align=\"center\">\n <ColorPicker\n variant=\"inline\"\n size=\"sm\"\n value={colour}\n onChange={(hex) => {\n setColour(hex);\n applyTableBackground(scope, hex);\n }}\n />\n <Button\n size=\"sm\"\n intent=\"ghost\"\n className=\"ds:mt-[var(--spacing-xs)] ds:w-full\"\n onClick={() => applyTableBackground(scope, null)}\n >\n {t('editor.table.clearColor', 'Clear colour')}\n </Button>\n </Popover.Content>\n </Popover>\n );\n}\n\nexport function TableFloatingToolbar({\n active,\n run,\n areaRef,\n getActiveTableEl,\n enableColor = false,\n saveTableCell,\n applyTableBackground,\n}: TableFloatingToolbarProps): React.JSX.Element | null {\n const { t } = useTranslation();\n const inTable = active.has('table');\n const [pos, setPos] = useState<{\n top: number;\n start: number;\n rtl: boolean;\n } | null>(null);\n\n // Keep the bar mounted while a colour popover is open: opening it can move\n // focus out of the editor, dropping `table` from `active`, which would\n // otherwise unmount the bar (and close the popover) mid-interaction.\n const colourOpenCount = useRef(0);\n const [colourOpen, setColourOpen] = useState(false);\n const handleColourOpenChange = useCallback((open: boolean): void => {\n colourOpenCount.current = Math.max(\n 0,\n colourOpenCount.current + (open ? 1 : -1),\n );\n setColourOpen(colourOpenCount.current > 0);\n }, []);\n\n useEffect(() => {\n // Freeze tracking while a colour popover is open (the caret may have left\n // the editor); resume when it closes.\n if (colourOpen) return;\n if (!inTable || typeof window === 'undefined') {\n setPos(null);\n return;\n }\n const recompute = (): void => {\n const area = areaRef.current;\n const table = getActiveTableEl();\n if (!area || !table) {\n setPos(null);\n return;\n }\n const a = area.getBoundingClientRect();\n const r = table.getBoundingClientRect();\n const rtl = getComputedStyle(area).direction === 'rtl';\n // Float just above the table's block-start edge, clamped to the container\n // top so it never renders above the editing surface. 44 ≈ the bar's own\n // height (one --min-target-size row) plus a small gap.\n const top = Math.max(0, r.top - a.top - 44);\n // Anchor `start` to the table's inline CENTRE; the render translates the\n // bar back by half its own width so it sits centred over the table.\n const center = rtl\n ? a.right - r.right + r.width / 2\n : r.left - a.left + r.width / 2;\n setPos({ top, start: Math.max(0, center), rtl });\n };\n recompute();\n // While the caret stays in the table the bar must track it: cell edits and\n // add-row/column grow the table (ResizeObserver), and the surface or the\n // viewport can scroll/resize.\n const ro = new ResizeObserver(recompute);\n const area = areaRef.current;\n const table = getActiveTableEl();\n if (area) ro.observe(area);\n if (table) ro.observe(table);\n window.addEventListener('scroll', recompute, true);\n window.addEventListener('resize', recompute);\n return () => {\n ro.disconnect();\n window.removeEventListener('scroll', recompute, true);\n window.removeEventListener('resize', recompute);\n };\n }, [inTable, colourOpen, areaRef, getActiveTableEl]);\n\n if ((!inTable && !colourOpen) || !pos) return null;\n\n // Ordered render groups; 'colour' is the cell/row background controls.\n const groups: (string[] | 'colour')[] = [\n ['rowAbove', 'rowBelow'],\n ['colLeft', 'colRight'],\n ['addHead'],\n ...(enableColor ? (['colour'] as const) : []),\n ['deleteRow', 'deleteColumn'],\n ['deleteTable'],\n ];\n\n return (\n // Tooltips disambiguate the icon-only ops on hover (and provide each\n // button's accessible name via IconButton's `tooltip` prop). Radix Tooltip\n // needs a provider ancestor, so scope one to the bar.\n <TooltipProvider>\n <div\n // role=\"group\", not \"toolbar\": these controls are independent tab\n // stops with no roving-focus / arrow-key navigation, so advertising the\n // WAI-ARIA toolbar contract would be a false promise. role=\"group\" keeps\n // the labelled grouping without committing to single-tab-stop semantics.\n role=\"group\"\n aria-label={t('editor.table.toolbar', 'Table tools')}\n // Centre on the table: --rte-tt-start is the table's inline centre, so\n // pull back by half the bar's width (mirrored for RTL).\n className={`${tableFloatClass} ${pos.rtl ? 'ds:translate-x-1/2' : 'ds:-translate-x-1/2'}`}\n // eslint-disable-next-line react/forbid-dom-props -- runtime-computed position injected via CSS custom properties (23-constraints §Runtime-computed dimensions); the inset rules live in the class\n style={{\n ['--rte-tt-top' as string]: `${pos.top}px`,\n ['--rte-tt-start' as string]: `${pos.start}px`,\n }}\n >\n {groups.map((group, gi) => (\n <Fragment key={group === 'colour' ? 'colour' : group[0]}>\n {gi > 0 ? (\n <span aria-hidden=\"true\" className={dividerClass} />\n ) : null}\n {group === 'colour' ? (\n <>\n <TableBgColourControl\n scope=\"cell\"\n icon={<PaintBucket />}\n label={t('editor.table.cellColor', 'Cell colour')}\n onOpenChange={handleColourOpenChange}\n saveTableCell={saveTableCell}\n applyTableBackground={applyTableBackground}\n />\n <TableBgColourControl\n scope=\"row\"\n icon={<PaintRoller />}\n label={t('editor.table.rowColor', 'Row colour')}\n onOpenChange={handleColourOpenChange}\n saveTableCell={saveTableCell}\n applyTableBackground={applyTableBackground}\n />\n </>\n ) : (\n group.map((opId) => {\n const op = TABLE_OP_BY_ID[opId];\n return (\n <IconButton\n key={opId}\n size=\"sm\"\n intent=\"ghost\"\n icon={op.icon}\n tooltip={t(op.label[0], op.label[1])}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => run(op.command)}\n />\n );\n })\n )}\n </Fragment>\n ))}\n </div>\n </TooltipProvider>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* ImageFloatingToolbar — contextual image controls + resize handles */\n/* */\n/* Framed over the selected image, so text-wrap (inline / wrap-left / */\n/* wrap-right) and block alignment (left / centre / right) are one */\n/* click away and the four corner handles resize it by pointer drag or */\n/* keyboard. DS-native parity with platform's Redactor imageAlignment + */\n/* imageResize plugins (HTP-4954): the SAME `wysiwyg-img-*` classes are */\n/* applied so saved HTML round-trips byte-for-byte across surfaces, and */\n/* the width is an inline % so it never overflows the editable. */\n/* Redactor's own resizer is off (imageResizable:false) — this is the */\n/* single, keyboard-accessible resize UI. */\n/* ------------------------------------------------------------------ */\n\n/* Layout classes — byte-identical to platform's imageAlignment plugin. */\nexport const IMAGE_FLOW_CLASSES = [\n 'wysiwyg-img-inline',\n 'wysiwyg-img-wrap-left',\n 'wysiwyg-img-wrap-right',\n] as const;\n\nexport const IMAGE_ALIGN_CLASSES = [\n 'wysiwyg-img-align-left',\n 'wysiwyg-img-align-center',\n 'wysiwyg-img-align-right',\n] as const;\n\n/** The layout class currently set within a group on `el` (or '' for none). */\nexport function selectedImageClass(\n el: HTMLElement,\n group: readonly string[],\n): string {\n return group.find((c) => el.classList.contains(c)) ?? '';\n}\n\n/** The image's rendered width as a whole-percent of its editable box. */\nexport function imageWidthPercent(img: HTMLElement): number {\n const box = img.closest('.redactor-in');\n const boxWidth = box instanceof HTMLElement ? box.clientWidth : 0;\n const imgWidth = img.getBoundingClientRect().width;\n if (boxWidth <= 0 || imgWidth <= 0) return IMG_MAX_PCT;\n return Math.round(Math.min(IMG_MAX_PCT, (imgWidth / boxWidth) * 100));\n}\n\nconst IMG_MIN_PCT = 10;\nconst IMG_MAX_PCT = 100;\nconst IMG_STEP = 5;\nconst IMG_STEP_COARSE = 10;\n\nconst clampPct = (pct: number): number =>\n Math.min(IMG_MAX_PCT, Math.max(IMG_MIN_PCT, Math.round(pct)));\n\n// Text-flow group: how surrounding text relates to the image. `inline` keeps\n// it in the line; the wrap options float it and flow text down the other side.\nconst IMAGE_FLOW_OPS: { id: string; icon: ReactNode; label: L }[] = [\n {\n id: 'wysiwyg-img-inline',\n icon: <Baseline />,\n label: ['editor.image.inline', 'Inline with text'],\n },\n {\n id: 'wysiwyg-img-wrap-left',\n icon: <PanelLeft />,\n label: ['editor.image.wrapLeft', 'Wrap left'],\n },\n {\n id: 'wysiwyg-img-wrap-right',\n icon: <PanelRight />,\n label: ['editor.image.wrapRight', 'Wrap right'],\n },\n];\n\n// Block-alignment group: where a non-wrapped image sits across the column.\nconst IMAGE_ALIGN_OPS: { id: string; icon: ReactNode; label: L }[] = [\n {\n id: 'wysiwyg-img-align-left',\n icon: <TextAlignStart />,\n label: ['editor.image.alignLeft', 'Align left'],\n },\n {\n id: 'wysiwyg-img-align-center',\n icon: <TextAlignCenter />,\n label: ['editor.image.alignCenter', 'Align centre'],\n },\n {\n id: 'wysiwyg-img-align-right',\n icon: <TextAlignEnd />,\n label: ['editor.image.alignRight', 'Align right'],\n },\n];\n\n// Four corner handles. `sign` is the horizontal grow direction for a pointer\n// drag (the inline-end corners grow rightward, the inline-start ones leftward);\n// it is flipped again for RTL at interaction time. The cursor is physical.\nconst IMAGE_CORNERS: {\n id: 'tl' | 'tr' | 'bl' | 'br';\n pos: string;\n cursor: string;\n sign: 1 | -1;\n labelKey: string;\n labelFallback: string;\n}[] = [\n {\n id: 'tl',\n pos: 'ds:[inset-block-start:calc(var(--spacing-md)*-0.5)] ds:[inset-inline-start:calc(var(--spacing-md)*-0.5)]',\n cursor: 'ds:cursor-nwse-resize',\n sign: -1,\n labelKey: 'editor.image.resizeTopStart',\n labelFallback: 'Resize image, top-start corner',\n },\n {\n id: 'tr',\n pos: 'ds:[inset-block-start:calc(var(--spacing-md)*-0.5)] ds:[inset-inline-end:calc(var(--spacing-md)*-0.5)]',\n cursor: 'ds:cursor-nesw-resize',\n sign: 1,\n labelKey: 'editor.image.resizeTopEnd',\n labelFallback: 'Resize image, top-end corner',\n },\n {\n id: 'bl',\n pos: 'ds:[inset-block-end:calc(var(--spacing-md)*-0.5)] ds:[inset-inline-start:calc(var(--spacing-md)*-0.5)]',\n cursor: 'ds:cursor-nesw-resize',\n sign: -1,\n labelKey: 'editor.image.resizeBottomStart',\n labelFallback: 'Resize image, bottom-start corner',\n },\n {\n id: 'br',\n pos: 'ds:[inset-block-end:calc(var(--spacing-md)*-0.5)] ds:[inset-inline-end:calc(var(--spacing-md)*-0.5)]',\n cursor: 'ds:cursor-nwse-resize',\n sign: 1,\n labelKey: 'editor.image.resizeBottomEnd',\n labelFallback: 'Resize image, bottom-end corner',\n },\n];\n\n// Selection frame outlined over the image; pointer-events off so clicks still\n// reach the image, re-enabled per handle. Rect injected via custom properties.\nconst imageFrameClass = [\n 'ds:absolute ds:z-20 ds:pointer-events-none',\n 'ds:[inset-block-start:var(--rte-img-top)] ds:[inset-inline-start:var(--rte-img-start)]',\n 'ds:[inline-size:var(--rte-img-width)] ds:[block-size:var(--rte-img-height)]',\n 'ds:rounded-[var(--radius-2xs)]',\n 'ds:[outline-style:solid] ds:[outline-width:var(--border-width-md)]',\n 'ds:[outline-color:var(--accent)] ds:[outline-offset:var(--focus-ring-offset)]',\n].join(' ');\n\n// One corner handle: a small accent square whose CENTRE sits on the corner.\n// Centred via per-corner negative-half-size insets (see IMAGE_CORNERS.pos) —\n// logical insets so it stays correct under RTL, with no physical transform.\nconst imageHandleClass = [\n 'ds:absolute ds:pointer-events-auto ds:touch-none',\n 'ds:[inline-size:var(--spacing-md)] ds:[block-size:var(--spacing-md)]',\n 'ds:rounded-[var(--radius-2xs)] ds:shadow-[var(--shadow-sm)]',\n 'ds:bg-[var(--accent)] ds:border ds:border-[color:var(--background)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:[outline-offset:var(--focus-ring-offset)]',\n 'ds:forced-colors:bg-[CanvasText]',\n].join(' ');\n\n// Controls bar, centred above the frame (mirrors tableFloatClass).\nconst imageBarClass = [\n 'ds:absolute ds:z-20 ds:flex ds:items-center ds:gap-[var(--spacing-2xs)]',\n 'ds:[inset-block-start:var(--rte-img-bar-top)] ds:[inset-inline-start:var(--rte-img-center)]',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--popover)] ds:p-[var(--spacing-2xs)] ds:shadow-[var(--shadow-lg)]',\n].join(' ');\n\nexport interface ImageFloatingToolbarProps {\n /** Positioned container the frame + bar are absolutely placed within. */\n areaRef: RefObject<HTMLDivElement | null>;\n /** The <img> currently selected in THIS editor, or null. */\n activeImageEl: HTMLElement | null;\n /** Apply/replace a `wysiwyg-img-*` class within its group on the image. */\n applyImageClass: (className: string) => void;\n /** Set the image width as a % of its editable box (clamped 10–100). */\n setImageWidth: (pct: number) => void;\n}\n\nexport function ImageFloatingToolbar({\n areaRef,\n activeImageEl: img,\n applyImageClass,\n setImageWidth,\n}: ImageFloatingToolbarProps): React.JSX.Element | null {\n const { t } = useTranslation();\n const [pos, setPos] = useState<{\n top: number;\n start: number;\n width: number;\n height: number;\n center: number;\n barTop: number;\n pct: number;\n rtl: boolean;\n } | null>(null);\n\n // Pointer-drag state (one active pointer at a time).\n const dragRef = useRef<{\n pointerId: number;\n startX: number;\n startPct: number;\n sign: number;\n } | null>(null);\n\n useEffect(() => {\n if (!img || typeof window === 'undefined') {\n setPos(null);\n return;\n }\n const recompute = (): void => {\n const area = areaRef.current;\n if (!area) {\n setPos(null);\n return;\n }\n const a = area.getBoundingClientRect();\n const r = img.getBoundingClientRect();\n const rtl = getComputedStyle(area).direction === 'rtl';\n const top = r.top - a.top;\n // Anchor inline-start from the writing-direction start edge.\n const start = rtl ? a.right - r.right : r.left - a.left;\n const center = start + r.width / 2;\n // 44 ≈ the bar's own height (one --min-target-size row) plus a small gap.\n const barTop = Math.max(0, top - 44);\n setPos({\n top,\n start: Math.max(0, start),\n width: r.width,\n height: r.height,\n center: Math.max(0, center),\n barTop,\n pct: imageWidthPercent(img),\n rtl,\n });\n };\n recompute();\n // The image rect moves when it resizes, when align / wrap / width change,\n // when the document reflows, or when the surface / viewport scrolls.\n // ResizeObserver catches size changes; a MutationObserver on the EDITABLE\n // catches the class / attribute / childList changes that REPOSITION the\n // image without resizing it (it observes the editable, not the frame — a\n // sibling — so it never reacts to its own output); scroll/resize cover the\n // viewport.\n const ro = new ResizeObserver(recompute);\n ro.observe(img);\n const area = areaRef.current;\n if (area) ro.observe(area);\n const editable = img.closest('.redactor-in');\n let mo: MutationObserver | null = null;\n if (editable) {\n mo = new MutationObserver(recompute);\n mo.observe(editable, {\n subtree: true,\n childList: true,\n characterData: true,\n attributes: true,\n attributeFilter: ['class', 'style', 'width', 'height', 'src'],\n });\n }\n window.addEventListener('scroll', recompute, true);\n window.addEventListener('resize', recompute);\n return () => {\n ro.disconnect();\n mo?.disconnect();\n window.removeEventListener('scroll', recompute, true);\n window.removeEventListener('resize', recompute);\n };\n }, [img, areaRef]);\n\n const onHandlePointerDown = useCallback(\n (corner: (typeof IMAGE_CORNERS)[number]) =>\n (event: React.PointerEvent<HTMLDivElement>): void => {\n if (!event.isPrimary || !pos) return;\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n dragRef.current = {\n pointerId: event.pointerId,\n startX: event.clientX,\n startPct: pos.pct,\n sign: corner.sign * (pos.rtl ? -1 : 1),\n };\n },\n [pos],\n );\n\n const onHandlePointerMove = useCallback(\n (event: React.PointerEvent<HTMLDivElement>): void => {\n const drag = dragRef.current;\n if (!drag || event.pointerId !== drag.pointerId || !img) return;\n const box = img.closest('.redactor-in');\n const boxWidth = box instanceof HTMLElement ? box.clientWidth : 0;\n if (boxWidth <= 0) return;\n const deltaPct =\n ((drag.sign * (event.clientX - drag.startX)) / boxWidth) * 100;\n setImageWidth(clampPct(drag.startPct + deltaPct));\n },\n [img, setImageWidth],\n );\n\n const onHandlePointerEnd = useCallback(\n (event: React.PointerEvent<HTMLDivElement>): void => {\n const drag = dragRef.current;\n if (!drag || event.pointerId !== drag.pointerId) return;\n event.currentTarget.releasePointerCapture(event.pointerId);\n dragRef.current = null;\n },\n [],\n );\n\n const onHandleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>): void => {\n if (!pos) return;\n let next: number | null = null;\n const step = event.shiftKey ? IMG_STEP_COARSE : IMG_STEP;\n switch (event.key) {\n // Up / right always grow; down / left always shrink — independent of\n // which corner has focus, so the gesture reads the same everywhere.\n case 'ArrowRight':\n case 'ArrowUp':\n next = pos.pct + step;\n break;\n case 'ArrowLeft':\n case 'ArrowDown':\n next = pos.pct - step;\n break;\n case 'Home':\n next = IMG_MIN_PCT;\n break;\n case 'End':\n next = IMG_MAX_PCT;\n break;\n default:\n return;\n }\n event.preventDefault();\n setImageWidth(clampPct(next));\n },\n [pos, setImageWidth],\n );\n\n if (!img || !pos) return null;\n\n const flowActive = selectedImageClass(img, IMAGE_FLOW_CLASSES);\n const alignActive = selectedImageClass(img, IMAGE_ALIGN_CLASSES);\n const widthText = t('editor.image.widthAnnounce', {\n width: pos.pct,\n defaultValue: '{{width}} percent',\n });\n\n return (\n <>\n {/* Selection frame + corner resize handles. */}\n <div\n className={imageFrameClass}\n // eslint-disable-next-line react/forbid-dom-props -- runtime-measured image rect injected via CSS custom properties (23-constraints §Runtime-computed dimensions); the inset/size rules live in the class\n style={{\n ['--rte-img-top' as string]: `${pos.top}px`,\n ['--rte-img-start' as string]: `${pos.start}px`,\n ['--rte-img-width' as string]: `${pos.width}px`,\n ['--rte-img-height' as string]: `${pos.height}px`,\n }}\n >\n {IMAGE_CORNERS.map((corner) => (\n <div\n key={corner.id}\n role=\"slider\"\n tabIndex={0}\n aria-label={t(corner.labelKey, corner.labelFallback)}\n aria-orientation=\"horizontal\"\n aria-valuemin={IMG_MIN_PCT}\n aria-valuemax={IMG_MAX_PCT}\n aria-valuenow={pos.pct}\n aria-valuetext={widthText}\n className={`${imageHandleClass} ${corner.pos} ${corner.cursor}`}\n onPointerDown={onHandlePointerDown(corner)}\n onPointerMove={onHandlePointerMove}\n onPointerUp={onHandlePointerEnd}\n onPointerCancel={onHandlePointerEnd}\n onKeyDown={onHandleKeyDown}\n />\n ))}\n </div>\n\n {/* Wrap + alignment controls, centred above the frame. */}\n <TooltipProvider>\n <div\n role=\"group\"\n aria-label={t('editor.image.toolbar', 'Image tools')}\n className={`${imageBarClass} ${pos.rtl ? 'ds:translate-x-1/2' : 'ds:-translate-x-1/2'}`}\n // eslint-disable-next-line react/forbid-dom-props -- runtime-computed anchor injected via CSS custom properties; the inset rules live in the class\n style={{\n ['--rte-img-bar-top' as string]: `${pos.barTop}px`,\n ['--rte-img-center' as string]: `${pos.center}px`,\n }}\n >\n {[IMAGE_FLOW_OPS, IMAGE_ALIGN_OPS].map((group, gi) => (\n <Fragment key={gi === 0 ? 'flow' : 'align'}>\n {gi > 0 ? (\n <span aria-hidden=\"true\" className={dividerClass} />\n ) : null}\n {group.map((op) => {\n const isActive =\n gi === 0 ? flowActive === op.id : alignActive === op.id;\n return (\n <IconButton\n key={op.id}\n size=\"sm\"\n intent=\"ghost\"\n icon={op.icon}\n aria-pressed={isActive}\n tooltip={t(op.label[0], op.label[1])}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => applyImageClass(op.id)}\n />\n );\n })}\n </Fragment>\n ))}\n </div>\n </TooltipProvider>\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* AiTemplatesMenu — the practice templates, from the AI pill or the */\n/* selection bubble. Picking one runs it straight away. */\n/* ------------------------------------------------------------------ */\n\nexport interface AiTemplatesMenuProps {\n templates: RichTextEditorAiTemplate[];\n onPick: (template: RichTextEditorAiTemplate) => void;\n /** Shows \"Manage templates\" / \"Create your first template\". */\n onManage?: (mode: 'list' | 'create') => void;\n /** Nothing to rewrite: the run items disable, the library stays readable. */\n noteEmpty: boolean;\n onOpenChange?: (open: boolean) => void;\n /** The trigger element (rendered `asChild`). */\n trigger: ReactNode;\n /** The pill sits at the editor's bottom edge, so the menu opens upward. */\n side?: 'top' | 'bottom';\n}\n\nexport function AiTemplatesMenu({\n templates,\n onPick,\n onManage,\n noteEmpty,\n onOpenChange,\n trigger,\n side = 'top',\n}: AiTemplatesMenuProps): React.JSX.Element {\n const { t } = useTranslation();\n const hintId = useId();\n return (\n <DropdownMenu.Root onOpenChange={onOpenChange}>\n <DropdownMenu.Trigger asChild>{trigger}</DropdownMenu.Trigger>\n <DropdownMenu.Content side={side} align=\"end\" sideOffset={8}>\n <DropdownMenu.Label>\n {templates.length > 0\n ? t('editor.ai.templatesGroup')\n : t('editor.ai.noTemplates')}\n </DropdownMenu.Label>\n {templates.map((template) => (\n <DropdownMenu.Item\n key={template.id}\n startIcon={<BookDashed />}\n description={template.description || undefined}\n // On an empty note the item stays focusable (so the hint below\n // is read with it) but does nothing.\n aria-disabled={noteEmpty || undefined}\n aria-describedby={noteEmpty ? hintId : undefined}\n className=\"ds:aria-disabled:opacity-50 ds:aria-disabled:cursor-not-allowed\"\n onSelect={(event) => {\n if (noteEmpty) {\n event.preventDefault();\n return;\n }\n onPick(template);\n }}\n >\n {template.name}\n </DropdownMenu.Item>\n ))}\n {noteEmpty && templates.length > 0 ? (\n <p\n id={hintId}\n className=\"ds:m-0 ds:px-[var(--spacing-sm)] ds:py-[var(--spacing-2xs)] ds:text-[length:var(--font-size-xs)] ds:text-[color:var(--muted-foreground)]\"\n >\n {t('editor.ai.templatesNoteEmpty')}\n </p>\n ) : null}\n {onManage && templates.length === 0 ? (\n <DropdownMenu.Item\n startIcon={<Plus />}\n onSelect={() => onManage('create')}\n >\n {t('editor.ai.createFirstTemplate')}\n </DropdownMenu.Item>\n ) : null}\n {onManage && templates.length > 0 ? (\n <>\n <DropdownMenu.Separator />\n <DropdownMenu.Item\n startIcon={<Settings />}\n onSelect={() => onManage('list')}\n >\n {t('editor.ai.manageTemplates')}\n </DropdownMenu.Item>\n </>\n ) : null}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* SelectionFloatingToolbar — the bubble over a text selection */\n/* */\n/* Quick formats (B / I / U / S) and the host's AI actions, anchored */\n/* above the selection. A pointer convenience: every control also lives */\n/* in the toolbar or the AI pill, so keyboard users lose nothing. */\n/* ------------------------------------------------------------------ */\n\nconst selectionFloatClass = [\n 'ds:absolute ds:z-20 ds:flex ds:items-center ds:gap-[var(--spacing-2xs)]',\n 'ds:[inset-block-start:var(--rte-sel-top)] ds:[inset-inline-start:var(--rte-sel-start)]',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--popover)] ds:p-[var(--spacing-2xs)] ds:shadow-[var(--shadow-lg)]',\n].join(' ');\n\nconst SELECTION_FORMATS = ['bold', 'italic', 'underline', 'strike'] as const;\n\nexport interface SelectionFloatingToolbarProps {\n active: ReadonlySet<string>;\n run: EditorToolbarProps['run'];\n /** Positioned container the bubble is absolutely placed within. */\n areaRef: RefObject<HTMLDivElement | null>;\n /** This editor's editable root (`.redactor-in`). */\n getEditorRoot: () => Element | null;\n /** Hide it (an AI action runs, a panel is open). */\n suppressed?: boolean;\n /** Keep it mounted while a menu opened from it is showing. */\n holdOpen?: boolean;\n /** The AI actions, after the formats. */\n children?: ReactNode;\n}\n\nexport function SelectionFloatingToolbar({\n active,\n run,\n areaRef,\n getEditorRoot,\n suppressed = false,\n holdOpen = false,\n children,\n}: SelectionFloatingToolbarProps): React.JSX.Element | null {\n const { t } = useTranslation();\n const barRef = useRef<HTMLDivElement>(null);\n const [pos, setPos] = useState<{\n top: number;\n start: number;\n rtl: boolean;\n } | null>(null);\n const holdOpenRef = useRef(holdOpen);\n useEffect(() => {\n holdOpenRef.current = holdOpen;\n }, [holdOpen]);\n\n useEffect(() => {\n if (suppressed || typeof window === 'undefined') {\n setPos(null);\n return undefined;\n }\n // While the pointer is dragging out a selection the bubble would chase\n // it; show it once the pointer is released.\n let dragging = false;\n let frame = 0;\n let remeasured = false;\n let dismissed = false;\n const recompute = (): void => {\n // A menu from the bubble is open: stay where we are.\n if (holdOpenRef.current || dragging) return;\n if (dismissed) {\n setPos(null);\n return;\n }\n const area = areaRef.current;\n const root = getEditorRoot();\n const sel = window.getSelection();\n if (\n !area ||\n !root ||\n !sel ||\n sel.rangeCount === 0 ||\n sel.isCollapsed ||\n !area.contains(document.activeElement)\n ) {\n setPos(null);\n return;\n }\n const range = sel.getRangeAt(0);\n if (!root.contains(range.commonAncestorContainer)) {\n setPos(null);\n return;\n }\n if (!range.toString().trim()) {\n setPos(null);\n return;\n }\n const a = area.getBoundingClientRect();\n const r = range.getBoundingClientRect();\n const rtl = getComputedStyle(area).direction === 'rtl';\n // 48 ≈ the bubble's height (one --min-target-size row plus its\n // padding) and a gap; flip below the selection when there is no room\n // above.\n const above = r.top - a.top - 48;\n const top = above >= 0 ? above : r.bottom - a.top + 8;\n const width = barRef.current?.offsetWidth ?? 0;\n const centre = rtl\n ? a.right - r.right + r.width / 2\n : r.left - a.left + r.width / 2;\n // Keep the whole bubble inside the editor.\n const half = width / 2;\n const start = Math.min(\n Math.max(centre, half),\n Math.max(half, a.width - half),\n );\n setPos({ top, start, rtl });\n // First show: the bubble has no width yet, so clamp again once it has.\n if (width === 0 && !remeasured) {\n remeasured = true;\n frame = requestAnimationFrame(recompute);\n }\n };\n const schedule = (): void => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(recompute);\n };\n const onPointerDown = (event: PointerEvent): void => {\n const root = getEditorRoot();\n if (root && event.target instanceof Node && root.contains(event.target)) {\n dragging = true;\n setPos(null);\n }\n };\n // `pointercancel` too: a touch long-press ends in it, not in pointerup.\n const onPointerUp = (): void => {\n if (!dragging) return;\n dragging = false;\n schedule();\n };\n // Escape hides the bubble until the selection changes (WCAG 1.4.13).\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return;\n const area = areaRef.current;\n if (!area || !area.contains(document.activeElement)) return;\n dismissed = true;\n setPos(null);\n };\n const onSelectionChange = (): void => {\n dismissed = false;\n schedule();\n };\n document.addEventListener('selectionchange', onSelectionChange);\n document.addEventListener('focusin', schedule);\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('pointerup', onPointerUp, true);\n document.addEventListener('pointercancel', onPointerUp, true);\n window.addEventListener('scroll', schedule, true);\n window.addEventListener('resize', schedule);\n schedule();\n return () => {\n cancelAnimationFrame(frame);\n document.removeEventListener('selectionchange', onSelectionChange);\n document.removeEventListener('focusin', schedule);\n document.removeEventListener('keydown', onKeyDown, true);\n document.removeEventListener('pointerdown', onPointerDown, true);\n document.removeEventListener('pointerup', onPointerUp, true);\n document.removeEventListener('pointercancel', onPointerUp, true);\n window.removeEventListener('scroll', schedule, true);\n window.removeEventListener('resize', schedule);\n };\n }, [suppressed, areaRef, getEditorRoot]);\n\n if (suppressed || !pos) return null;\n\n return (\n <TooltipProvider>\n <div\n ref={barRef}\n // role=\"group\", not \"toolbar\": independent tab stops with no roving\n // focus (same reasoning as the table bar).\n role=\"group\"\n aria-label={t('editor.ai.selectionTools')}\n data-component-part=\"selection-toolbar\"\n className={`${selectionFloatClass} ${pos.rtl ? 'ds:translate-x-1/2' : 'ds:-translate-x-1/2'}`}\n // eslint-disable-next-line react/forbid-dom-props -- runtime-computed position injected via CSS custom properties (23-constraints §Runtime-computed dimensions); the inset rules live in the class\n style={{\n ['--rte-sel-top' as string]: `${pos.top}px`,\n ['--rte-sel-start' as string]: `${pos.start}px`,\n }}\n >\n {SELECTION_FORMATS.map((id) => {\n const item = ITEMS[id];\n return (\n <IconButton\n key={id}\n size=\"sm\"\n intent=\"ghost\"\n icon={item.icon}\n tooltip={t(item.label[0], item.label[1])}\n aria-pressed={item.toggle ? active.has(item.toggle) : undefined}\n // Keep the selection: the command formats it.\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => run(...item.command)}\n />\n );\n })}\n {children ? (\n <>\n <span aria-hidden=\"true\" className={dividerClass} />\n {children}\n </>\n ) : null}\n </div>\n </TooltipProvider>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Toolbar */\n/* ------------------------------------------------------------------ */\n\nexport function EditorToolbar({\n run,\n active,\n preset,\n insertHtml,\n insertTable,\n saveSelection,\n restoreSelection,\n getSelectedText,\n uploadImage,\n enableColor = false,\n enableImage = false,\n enableTable = false,\n showExtensions = false,\n variables,\n recentVariableTokens,\n insertVariable,\n}: EditorToolbarProps): React.JSX.Element {\n const { t } = useTranslation();\n // Keep toolbar clicks from stealing the editor's selection.\n const keepSelection = (event: { preventDefault: () => void }): void =>\n event.preventDefault();\n\n // Render a simple command button by id, gated by the active preset.\n const has = (id: string): boolean => PRESETS[preset].includes(id);\n const btn = (id: string): React.JSX.Element | null => {\n if (!has(id)) return null;\n const item = ITEMS[id];\n return (\n <IconButton\n key={item.id}\n size=\"sm\"\n intent=\"ghost\"\n icon={item.icon}\n aria-label={t(item.label[0], item.label[1])}\n aria-pressed={item.toggle ? active.has(item.toggle) : undefined}\n onMouseDown={keepSelection}\n onClick={() => run(...item.command)}\n />\n );\n };\n const Divider = (): React.JSX.Element => (\n <span aria-hidden=\"true\" className={dividerClass} />\n );\n\n // Standard toolbar grouping (matches Google Docs / Word / TinyMCE order):\n // style ▸ inline (B/I/U/S + colour/highlight) ▸ lists ▸ insert ▸ extensions.\n const styleGroup = has('format');\n // History first, as in Google Docs and Word.\n const historyNodes = [btn('undo'), btn('redo')].filter(Boolean);\n\n // Primary controls — always inline (style + B/I/U/S + colour/highlight).\n const inlineNodes = [\n btn('bold'),\n btn('italic'),\n btn('underline'),\n btn('strike'),\n enableColor ? (\n <ColourControl\n key=\"colour\"\n run={run}\n saveSelection={saveSelection}\n restoreSelection={restoreSelection}\n />\n ) : null,\n enableColor ? (\n <HighlightControl\n key=\"highlight\"\n run={run}\n saveSelection={saveSelection}\n restoreSelection={restoreSelection}\n />\n ) : null,\n ].filter(Boolean);\n const hasPrimary =\n historyNodes.length > 0 || styleGroup || inlineNodes.length > 0;\n\n // Secondary controls — lists ▸ insert ▸ extensions. These collapse into the\n // right-hand \"More\" popover on a narrow toolbar (below the @sm breakpoint)\n // instead of wrapping the bar onto a second line.\n const listsNodes = [btn('ul'), btn('ol')].filter(Boolean);\n const insertNodes = [\n has('link') ? (\n <LinkDialog\n key=\"link\"\n insertHtml={insertHtml}\n saveSelection={saveSelection}\n restoreSelection={restoreSelection}\n getSelectedText={getSelectedText}\n />\n ) : null,\n enableImage ? (\n <ImageDialog\n key=\"image\"\n insertHtml={insertHtml}\n saveSelection={saveSelection}\n restoreSelection={restoreSelection}\n uploadImage={uploadImage}\n />\n ) : null,\n enableTable ? (\n <TableControl\n key=\"table\"\n run={run}\n insertTable={insertTable}\n active={active}\n />\n ) : null,\n variables && variables.length > 0 && insertVariable ? (\n <VariableMenu\n key=\"variables\"\n variables={variables}\n recentVariableTokens={recentVariableTokens}\n insertVariable={insertVariable}\n saveSelection={saveSelection}\n />\n ) : null,\n ].filter(Boolean);\n const extensionNodes = showExtensions\n ? [\n <IconButton\n key=\"extensions\"\n size=\"sm\"\n intent=\"ghost\"\n icon={<Wrench />}\n aria-label={t('editor.extensions', 'Editor extensions')}\n // Placeholder affordance: no handler is wired yet, so the control\n // must not be operable — an enabled button with no onClick fails\n // SC 4.1.2. Disable it until a marketplace handler is connected.\n disabled\n onMouseDown={keepSelection}\n />,\n ]\n : [];\n\n const secondarySubgroups = [listsNodes, insertNodes, extensionNodes].filter(\n (group) => group.length > 0,\n );\n const hasSecondary = secondarySubgroups.length > 0;\n\n // Render the secondary subgroups separated by dividers. `leadingDivider`\n // controls whether a divider precedes the first subgroup (true inline, where\n // the primary controls sit before it; false inside the More popover).\n const renderSecondary = (leadingDivider: boolean): ReactNode =>\n secondarySubgroups.map((group, index) => (\n <Fragment key={index}>\n {index > 0 || leadingDivider ? <Divider /> : null}\n {group}\n </Fragment>\n ));\n\n return (\n // Outer element is the query container + visual chrome; the flex row is an\n // inner child so `container-type` never lands on the flex parent (which\n // would blockify the inline controls).\n <div className={toolbarClass()} data-component=\"editor-toolbar\">\n <div\n // role=\"group\", not \"toolbar\": every control is its own tab stop with\n // no roving focus / arrow-key handling, so the toolbar contract would\n // be false. role=\"group\" keeps the labelled grouping without the\n // single-tab-stop + arrow-navigation promise.\n role=\"group\"\n aria-label={t('editor.toolbarLabel')}\n className={toolbarRowClass}\n >\n {/* History */}\n {historyNodes}\n {historyNodes.length > 0 && (styleGroup || inlineNodes.length > 0) ? (\n <Divider />\n ) : null}\n\n {/* Block style */}\n {styleGroup ? (\n <StyleMenu run={run} active={active} onTriggerDown={keepSelection} />\n ) : null}\n\n {/* Inline formatting */}\n {styleGroup && inlineNodes.length > 0 ? <Divider /> : null}\n {inlineNodes}\n\n {hasSecondary ? (\n <>\n {/* Secondary controls inline — shown from 384px. px, not the `@sm`\n rem alias: container-query `rem` follows the host root\n font-size and misfires off a non-16px root. */}\n <div className=\"ds:hidden ds:@[384px]/toolbar:contents\">\n {renderSecondary(hasPrimary)}\n </div>\n\n {/* Overflow \"More\" menu — replaces the inline secondary controls\n below @sm so the bar never wraps onto a second line. */}\n <div className=\"ds:contents ds:@[384px]/toolbar:hidden\">\n {hasPrimary ? <Divider /> : null}\n <Popover>\n <Popover.Trigger asChild>\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n icon={<Ellipsis />}\n aria-label={t('editor.more', 'More options')}\n onMouseDown={keepSelection}\n />\n </Popover.Trigger>\n <Popover.Content side=\"bottom\" align=\"end\">\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n {renderSecondary(false)}\n </div>\n </Popover.Content>\n </Popover>\n </div>\n </>\n ) : null}\n </div>\n </div>\n );\n}\n","/* ------------------------------------------------------------------ */\n/* RichTextEditor — thin, secure wrapper over Redactor (Imperavi). */\n/* */\n/* LICENCE-SAFETY MODEL (read first): */\n/* Redactor is a COMMERCIAL editor and `@alfadocs/ui-kit` publishes */\n/* to PUBLIC npm — so redactor.js bytes MUST NOT enter `dist/`. This */\n/* wrapper never imports Redactor; it resolves a Redactor factory at */\n/* runtime from a `redactor` prop or the UMD globals `window.$R` / */\n/* `window.Redactor` that the CONSUMER's licensed build sets */\n/* (platform ships `web/static/redactor/redactor.js`). With no */\n/* factory found, the editor renders a graceful plain <textarea>. */\n/* Storybook loads a vendored dev-only build via preview-head.html. */\n/* */\n/* - Toolbar/buttons/dropdowns/shortcuts are owned entirely by Redactor */\n/* itself. The kit only skins them via `redactor-theme.css` and feeds */\n/* button presets + lang strings. */\n/* - Security: all inbound HTML (value/defaultValue/setContent) and the */\n/* editor's outbound `changed` HTML run through DOMPurify with an */\n/* explicit FORBID list. Outbound HTML also gets `loading=\"lazy\"` on */\n/* images and platform's empty-placeholder normalisation. */\n/* - Backend-coupled features (image upload, help-me-write, */\n/* voice-recording) are CONSUMER-PROVIDED via `imageUploadUrl` / */\n/* `plugins` / `options`; the kit never bakes a backend route in. */\n/* - i18n: placeholder/aria via `t('editor.placeholder')`; Redactor's */\n/* own `lang` is derived from the active locale (not hardcoded). */\n/* ------------------------------------------------------------------ */\n\nimport {\n Fragment,\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n Mic,\n SpellCheck,\n PencilSparkles,\n Square,\n WandSparkles,\n BookDashed,\n ChevronDown,\n} from 'lucide-react';\n\nimport '../../tokens/themes/bridges/redactor-theme.css';\n\nimport { sanitiseHtml as sanitiseShared } from '../_shared/safe-html';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { useAiSparkle } from '../../hooks/use-ai-sparkle';\nimport { Spinner } from '../spinner';\nimport { AiSparkle } from '../ai-sparkle';\nimport { Button, IconButton } from '../button';\nimport {\n AiConsentBanner,\n type AiConsentBannerHeadingLevel,\n} from '../ai-consent-banner';\nimport { richTextEditorAgent } from './rich-text-editor.agent';\nimport { HelpMeWriteOverlay } from './help-me-write-overlay';\nimport { EditorOverlay } from '../editor-overlay';\nimport {\n AiTemplatesMenu,\n EditorToolbar,\n ImageFloatingToolbar,\n SelectionFloatingToolbar,\n TableFloatingToolbar,\n IMAGE_FLOW_CLASSES,\n IMAGE_ALIGN_CLASSES,\n} from './editor-toolbar';\nimport {\n VariablesMenu,\n type VariablesMenuHandle,\n type VariablesMenuVariable,\n} from '../variables-menu';\n\n/* ------------------------------------------------------------------ */\n/* Sanitisation */\n/* ------------------------------------------------------------------ */\n\n// Single sanitiser surface (constraints §8): the editor routes every inbound\n// and outbound HTML string through the shared `rich-text` DOMPurify profile in\n// `_shared/safe-html.tsx`, so one audit covers the whole kit. The wrapper adds\n// only editor-specific shaping (normalizeEditorValue + withLazyImages) around it.\nfunction sanitiseHtml(input: string): string {\n return sanitiseShared(input, 'rich-text');\n}\n\n// Mirror platform's RedactorWysiwyg `normalizeEditorValue` (RedactorWysiwyg.js\n// :26-44): map Redactor's empty placeholders to '' for the emptiness test, but\n// preserve image-only HTML so embedded-image notes aren't dropped on save.\nfunction normalizeEditorValue(html = ''): string {\n const normalized = String(html).trim();\n if (\n normalized === '' ||\n normalized === '<p><br></p>' ||\n normalized === '<p> </p>'\n ) {\n return '';\n }\n const contentWithoutTags = normalized\n .replace(/<br\\s*\\/?>/gi, '')\n .replace(/ /gi, '')\n .replace(/<[^>]+>/g, '')\n .trim();\n if (contentWithoutTags === '' && /<img\\b[^>]*>/i.test(normalized)) {\n return normalized;\n }\n return contentWithoutTags === '' ? '' : normalized;\n}\n\n// Inject `loading=\"lazy\"` on any <img> lacking it (platform parity).\nfunction withLazyImages(html: string): string {\n return html.replace(\n /<img(?![^>]*\\sloading=)([^>]*)>/gi,\n '<img loading=\"lazy\"$1>',\n );\n}\n\n// Template variables use Redactor's native `variable` component: a span it\n// treats as one non-editable unit (arrow keys step over it, Backspace removes\n// it whole). The same markup as platform's Redactor `variable` plugin, so\n// content round-trips between the two.\nconst VARIABLE_TOKEN = /^[A-Za-z0-9_]+$/;\nconst VARIABLE_IN_TEXT = /\\[\\[([A-Za-z0-9_]+)\\]\\]/g;\n\n// Editor-only marker on an invalid variable chip; never saved.\nconst INVALID_VARIABLE_CLASS = 'rte-variable-invalid';\nconst INVALID_CLASS_IN_HTML = new RegExp(\n `\\\\s*\\\\b${INVALID_VARIABLE_CLASS}\\\\b`,\n 'g',\n);\n\n// Strip what the editor adds to variable chips for display only (the label,\n// the hover title, the invalid marker), so saved HTML is exactly the plain\n// variable span platform's plugin writes.\nfunction stripEditorMarkers(html: string): string {\n if (!html.includes('data-redactor-type=\"variable\"')) return html;\n return html.replace(\n /<span\\b[^>]*data-redactor-type=\"variable\"[^>]*>/g,\n (tag) =>\n tag\n .replace(/\\s(?:data-label|title)=\"[^\"]*\"/g, '')\n .replace(INVALID_CLASS_IN_HTML, '')\n .replace(/\\sclass=\"\"/g, ''),\n );\n}\n\n// Every `[[TOKEN]]` in the document, chip or bare text, in order.\nfunction variableTokensIn(html: string): string[] {\n const text = html.replace(/<[^>]*>/g, ' ');\n return Array.from(text.matchAll(VARIABLE_IN_TEXT), (match) => match[1]);\n}\n\n// An AI call rejected because the practice is out of credits. Matched by\n// name so hosts (and the help-me-write-templates pattern's\n// `AiCreditsExhaustedError`) need not import a class from the component.\nfunction isCreditsExhausted(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'name' in err &&\n (err as { name?: string }).name === 'AiCreditsExhaustedError'\n );\n}\n\nfunction isAbortError(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'name' in err &&\n (err as { name?: string }).name === 'AbortError'\n );\n}\n\ntype OneShotKind = 'proofread' | 'format' | 'template';\n\n/** What one AI action rewrites, captured when the reader asked for it. */\ninterface AiTarget {\n scope: 'selection' | 'document';\n /** The selection, kept to write the result back over it. */\n range: Range | null;\n html: string;\n text: string;\n}\n\n// Serialise a cloned selection. An inert <template> holds it, so nothing\n// in it loads or runs.\nfunction fragmentHtml(fragment: DocumentFragment): string {\n const holder = document.createElement('template');\n holder.content.appendChild(fragment);\n return holder.innerHTML;\n}\n\n// Plain text of an HTML string, parsed inertly.\nfunction htmlText(html: string): string {\n const holder = document.createElement('template');\n holder.innerHTML = html;\n return (holder.content.textContent ?? '').replace(/\\s+/g, ' ').trim();\n}\n\n// The characters of an HTML string without tags or any whitespace, for\n// \"did the words change?\" checks: wrapping text in a chip must compare\n// equal however the markup around it is spaced.\nfunction plainText(html: string): string {\n return html\n .replace(/<[^>]*>/g, '')\n .replace(/ /gi, '')\n .replace(/[\\s\\u200B\\uFEFF]+/g, '');\n}\n\n// Caret position as a character offset into the editable's text, so it can\n// be put back after a rewrite that keeps the text but replaces the DOM.\nfunction caretTextOffset(root: Element): number | null {\n const sel = window.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const range = sel.getRangeAt(0);\n if (!root.contains(range.startContainer)) return null;\n const before = document.createRange();\n before.selectNodeContents(root);\n before.setEnd(range.startContainer, range.startOffset);\n return before.toString().length;\n}\n\nfunction placeCaretAtTextOffset(root: Element, offset: number): void {\n const sel = window.getSelection();\n if (!sel) return;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n let seen = 0;\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n const text = node as Text;\n if (seen + text.data.length >= offset) {\n const range = document.createRange();\n const chip = text.parentElement?.closest(\n '[data-redactor-type=\"variable\"]',\n );\n // Never inside a chip: land just after it.\n if (chip) range.setStartAfter(chip);\n else range.setStart(text, offset - seen);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n return;\n }\n seen += text.data.length;\n }\n}\n\nfunction variableHtml(token: string): string {\n return `<span data-redactor-type=\"variable\">[[${token}]]</span>`;\n}\n\n// Known variables, keyed by lower-case token → the host's spelling, so a\n// hand-typed `[[nome]]` resolves to the host's `NOME`.\ntype VariableLookup = ReadonlyMap<string, string>;\n\n// Wrap bare `[[TOKEN]]` text for the host's known variables in the variable\n// span, so content typed before the menu existed renders as chips too.\nfunction wrapVariableTokens(html: string, tokens: VariableLookup): string {\n if (\n tokens.size === 0 ||\n !html.includes('[[') ||\n typeof DOMParser === 'undefined'\n ) {\n return html;\n }\n const doc = new DOMParser().parseFromString(\n `<body>${html}</body>`,\n 'text/html',\n );\n const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);\n const targets: Text[] = [];\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n const text = node as Text;\n if (text.parentElement?.closest('[data-redactor-type=\"variable\"]')) {\n continue;\n }\n if (text.data.includes('[[')) targets.push(text);\n }\n let changed = false;\n for (const text of targets) {\n const frag = doc.createDocumentFragment();\n let last = 0;\n for (const match of text.data.matchAll(VARIABLE_IN_TEXT)) {\n const token = tokens.get(match[1].toLowerCase());\n if (!token || match.index === undefined) continue;\n frag.append(text.data.slice(last, match.index));\n const span = doc.createElement('span');\n span.setAttribute('data-redactor-type', 'variable');\n span.textContent = `[[${token}]]`;\n frag.append(span);\n last = match.index + match[0].length;\n }\n if (last === 0) continue;\n frag.append(text.data.slice(last));\n text.replaceWith(frag);\n changed = true;\n }\n return changed ? doc.body.innerHTML : html;\n}\n\n// Pull the uploaded image URL out of a Redactor-style imageUpload response.\n// Handles the common shapes: `{ file: { url } }`, `{ url }`, `{ data: { url } }`,\n// and the multi-file map `{ \"1\": { url }, … }`.\nfunction extractUploadedUrl(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const rec = data as Record<string, unknown>;\n const fromNode = (node: unknown): string | undefined => {\n if (node && typeof node === 'object' && 'url' in node) {\n const url = (node as { url?: unknown }).url;\n return typeof url === 'string' ? url : undefined;\n }\n return undefined;\n };\n if (typeof rec.url === 'string') return rec.url;\n return (\n fromNode(rec.file) ??\n fromNode(rec.data) ??\n Object.values(rec).map(fromNode).find(Boolean)\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Redactor factory resolution (external — never bundled) */\n/* ------------------------------------------------------------------ */\n\nexport type RedactorFactory = (\n selector: string | HTMLElement,\n command?: unknown,\n ...args: unknown[]\n) => unknown;\n\nfunction resolveRedactor(injected?: RedactorFactory): RedactorFactory | null {\n if (injected) return injected;\n if (typeof window === 'undefined') return null;\n const w = window as unknown as {\n $R?: RedactorFactory;\n Redactor?: RedactorFactory;\n };\n return w.$R ?? w.Redactor ?? null;\n}\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type RichTextEditorToolbar = 'minimal' | 'standard' | 'full';\n\n/**\n * Patient AI-consent gate for the Help-me-write action and both dictation\n * mics (the editor's own, and the one inside the Help-me-write overlay).\n * Omit entirely for today's ungated behaviour — no existing host breaks.\n *\n * Present and `granted: false`: the affordances stay visible (this never\n * hides a control), but opening one shows the kit's `AiConsentBanner` in\n * the same docked slot instead of calling `onRequestAiDraft` / `onDictate`.\n * When `granted` flips `true` the reader carries on without reopening\n * anything — the editor resumes exactly the action it gated.\n *\n * Present and `granted: true`: normal behaviour, and the Help-me-write\n * privacy notice records that consent was given.\n */\nexport interface AiConsentGate {\n /** Whether AI consent has already been recorded for the current patient. */\n granted: boolean;\n /** When consent was granted — passed straight to `AiConsentBanner`. */\n grantedAt?: string | number | Date;\n /** Who granted consent — passed straight to `AiConsentBanner`. */\n grantedBy?: string;\n /** Whether the signed-in reader may grant consent. Default `true`; treated\n * as `false` when `onGrant` is absent, so no dead Grant control shows. */\n canGrant?: boolean;\n /** The grant is being persisted server-side (host-driven busy state). */\n pending?: boolean;\n /**\n * Fired when the reader confirms the grant in the banner. A returned\n * promise drives the banner's own pending/Spinner state until it settles,\n * in addition to (or absent) a host-supplied `pending`.\n */\n onGrant?: () => void | Promise<void>;\n}\n\n/** A template variable the toolbar's \"Insert variable\" menu offers. */\nexport interface RichTextEditorVariable {\n /** Inserted as `[[token]]`. Letters, digits and underscores only. */\n token: string;\n /** Human label shown in the menu (translated by the host). */\n label: string;\n /** Optional second line in the menu (reserved for a future resolved-value\n * preview — not rendered yet). */\n description?: string;\n /**\n * One of the fixed catalogue groups the VariablesMenu renders as section\n * headers: `patient`, `appointment`, `practice`, `operator`, `document`.\n * Any other value (or omitting it) lands the variable in the menu's\n * \"Other\" group at the end.\n */\n group?:\n | 'patient'\n | 'appointment'\n | 'practice'\n | 'operator'\n | 'document'\n | string;\n}\n\n/** A practice template the AI pill's Templates menu offers. */\nexport interface RichTextEditorAiTemplate {\n id: string;\n name: string;\n /** Second line in the menu. */\n description?: string;\n /** @deprecated The host's order is the menu order. Ignored. */\n isDefault?: boolean;\n}\n\n/**\n * What a one-shot AI action rewrites: the selection when there is one, else\n * the whole document. Resolve with the rewritten HTML for that same scope.\n */\nexport interface RichTextEditorAiActionRequest {\n html: string;\n /** `html` as plain text. */\n text: string;\n scope: 'selection' | 'document';\n signal: AbortSignal;\n}\n\n/** Practice templates as an AI pill segment (and in the selection bubble). */\nexport interface RichTextEditorAiTemplates {\n /** In menu order, first to last. */\n templates: RichTextEditorAiTemplate[];\n /** The AI call. Reject with an error named `AiCreditsExhaustedError` on 402. */\n onRun: (\n request: RichTextEditorAiActionRequest & {\n template: RichTextEditorAiTemplate;\n },\n ) => Promise<string>;\n /** Shows \"Manage templates\" / \"Create your first template\". */\n onManage?: (mode: 'list' | 'create') => void;\n}\n\n/** Fired after a one-shot AI action rewrote the note. */\nexport interface RichTextEditorAiApplied {\n action: 'proofread' | 'format' | 'template';\n template?: RichTextEditorAiTemplate;\n scope: 'selection' | 'document';\n /** The document before the change. */\n previousHtml: string;\n /** Puts `previousHtml` back. */\n undo: () => void;\n}\n\n/** What a host's own Help-me-write surface gets from `renderHelpMeWrite`. */\nexport interface HelpMeWriteRenderContext {\n /** Whether the surface should show (consent is already granted). */\n open: boolean;\n onClose: () => void;\n /**\n * What the reader asked about: `'document'` from the AI pill (use the\n * whole note as context; `insertAtSelection` inserts at the caret) or\n * `'selection'` from the selection bubble (`selectionText` is the context,\n * and `insertAtSelection` replaces it).\n */\n scope: 'document' | 'selection';\n /** Text of the selection when opened from the bubble; '' otherwise. */\n selectionText: string;\n getHTML: () => string;\n getText: () => string;\n /** Insert at the saved caret, replacing the saved selection if any. */\n insertAtSelection: (html: string) => void;\n /** Insert just after the saved selection (or at the saved caret). */\n insertAfterSelection: (html: string) => void;\n /** Replace the whole document. */\n setContent: (html: string) => void;\n /** The editor's own dictation seam, for a mic inside the surface. */\n onDictate?: RichTextEditorProps['onDictate'];\n /** The kit's privacy notice, including the consent-recorded line. */\n privacyNotice: ReactNode;\n /**\n * Opened because dictation ran out of AI credits (its `onDictate` rejected\n * with an error named `AiCreditsExhaustedError`): show the out-of-credits\n * state rather than the prompt.\n */\n creditsExhausted: boolean;\n}\n\nexport interface RichTextEditorProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** HTML initial value (uncontrolled). Runs through DOMPurify. */\n defaultValue?: string;\n /** Controlled value (HTML). Sanitised; synced with a skip-once caret guard. */\n value?: string;\n /** Emits on every change — debounced 100ms. `markdown` is '' (Redactor has no serializer). */\n onChange?: (payload: { html: string; markdown: string }) => void;\n /** Toolbar preset → Redactor `buttons`. */\n toolbar?: RichTextEditorToolbar;\n /** Placeholder text — translates via useTranslation if omitted. */\n placeholder?: string;\n /** Read-only mode. */\n readOnly?: boolean;\n /** Accessible name for the editing region. */\n ariaLabel?: string;\n /** Size variant for the minimum block-size of the editing region. */\n minHeight?: 'sm' | 'md' | 'lg' | 'fill';\n /** Show a right-aligned editor-extensions affordance (visual placeholder). */\n showExtensions?: boolean;\n /** Extra class names on the wrapper. */\n className?: string;\n\n /* --- Redactor-specific seams (all CONSUMER-PROVIDED) --- */\n /** Inject the Redactor factory explicitly; else `window.$R` / `window.Redactor`. */\n redactor?: RedactorFactory;\n /** Raw Redactor options, deep-merged LAST over the kit defaults (callbacks reserved). */\n options?: Record<string, unknown>;\n /** Redactor plugin names to enable (the consumer must register/load them). */\n plugins?: string[];\n /** Redactor lang code; default derived from the active i18n locale. */\n lang?: string;\n /** Consumer image-upload endpoint → Redactor `imageUpload`. Omitted if absent. */\n imageUploadUrl?: string;\n /**\n * Upload an image yourself (your own API client, auth or storage) and\n * resolve its URL. Wins over `imageUploadUrl` for the toolbar's image\n * dialog; either one shows the insert-image control.\n */\n onUploadImage?: (file: File, signal?: AbortSignal) => Promise<string>;\n /** App keyboard-shortcut seam (e.g. Ctrl/Cmd+Enter to save). */\n onKeyDown?: (event: KeyboardEvent) => void;\n\n /* --- AI assistance (DS-native UI; backend stays consumer-provided) --- */\n /**\n * Help-me-write. When provided, a DS \"Help me write\" action appears; the kit\n * opens a dialog, calls this with the prompt + an AbortSignal, sanitises the\n * returned draft and inserts it at the caret. The backend call / auth /\n * practiceId all live in the consumer's implementation — never in the kit.\n */\n onRequestAiDraft?: (ctx: {\n prompt: string;\n signal: AbortSignal;\n }) => Promise<string>;\n /** Whether `onRequestAiDraft` returns HTML (default) or plain text. */\n aiDraftFormat?: 'html' | 'text';\n /** Override the compliance notice shown in the Help-me-write dialog. */\n aiPrivacyNotice?: ReactNode;\n /**\n * Patient AI-consent gate for Help-me-write + both mics. See\n * `AiConsentGate`. Omit for today's ungated behaviour.\n */\n aiConsent?: AiConsentGate;\n /**\n * Heading level for the `AiConsentBanner` shown while the gate is open —\n * forwarded straight to its own `headingLevel` so it nests correctly under\n * whatever heading the host has above this editor (axe `heading-order`).\n * Default `5` (the banner's own default) suits a standalone editor with no\n * heading directly above it; a host wrapping the editor under its own\n * heading (e.g. `NotesPanel`'s `h2`) should pass one level below it.\n */\n aiConsentHeadingLevel?: AiConsentBannerHeadingLevel;\n /**\n * Voice dictation. When provided, a DS mic toggle + live-transcript region\n * appear. The kit owns the UI; the consumer runs mic capture + transcription\n * inside the callback and pushes text back via `onPartialTranscript` (drives\n * the live region) and `onFinalTranscript` (sanitised + inserted at the\n * caret). Resolve when the session ends; honour `signal` to stop. All\n * mic / transcription / backend logic stays consumer-side.\n */\n onDictate?: (ctx: {\n signal: AbortSignal;\n onPartialTranscript: (text: string) => void;\n onFinalTranscript: (text: string) => void;\n }) => Promise<void>;\n /**\n * One-shot AI actions (CONSUMER-PROVIDED backend). Each gets the HTML to\n * rewrite (the selection if there is one, else the whole document) and\n * resolves with the rewritten HTML, which replaces that same scope. While\n * one runs the editor is disabled with a spinner. `onProofread` corrects\n * spelling/grammar; `onAutoFormat` tidies structure/formatting. Each adds a\n * pill segment and a selection-bubble button. Gated by `aiConsent`.\n */\n onProofread?: (ctx: RichTextEditorAiActionRequest) => Promise<string>;\n onAutoFormat?: (ctx: RichTextEditorAiActionRequest) => Promise<string>;\n /** Practice templates: a Templates pill segment that runs one in one click. */\n aiTemplates?: RichTextEditorAiTemplates;\n /** After a one-shot action rewrote the note; use it to offer Undo. */\n onAiApplied?: (applied: RichTextEditorAiApplied) => void;\n /**\n * Sparkle the AI pill when it appears, while an action runs and when the\n * result lands. Default `true`; motion is off under reduced motion and in\n * the accessible themes. The pill carries `data-ai-sparkle` for styling.\n */\n aiSparkle?: boolean;\n /**\n * A bubble over a text selection with quick formats and the AI actions.\n * Default: on when the editor has any AI action (templates, proofread,\n * auto-format or Help me write).\n */\n selectionToolbar?: boolean;\n /**\n * Template variables. When provided, the toolbar gains an \"Insert variable\"\n * menu that inserts `[[TOKEN]]` as a chip (Redactor's native `variable`\n * component, the same markup as platform's plugin). Bare `[[TOKEN]]` text\n * for these tokens in inbound content renders as a chip too.\n */\n variables?: RichTextEditorVariable[];\n /**\n * Most-recently-used variable tokens, most recent first. Rendered as a\n * \"Recent\" group pinned above the catalogue (max 3 shown). The kit never\n * persists this itself — the host owns storage (see `onVariableInserted`\n * and the `usePersistentState` example in this component's `.mdx`).\n */\n recentVariableTokens?: string[];\n /**\n * Fires with the token whenever a variable is inserted from either the\n * toolbar button or the `[[` caret menu — the seam a host uses to build\n * `recentVariableTokens`. Does not fire for typed `[[TOKEN]]` text that\n * becomes a chip on its own (only for a menu pick).\n */\n onVariableInserted?: (token: string) => void;\n /**\n * Decide whether a `[[TOKEN]]` is valid. Default: it is one of `variables`\n * (any letter case). Invalid tokens render as error chips with a message\n * under the editor, and are reported through `onVariableValidityChange`.\n */\n validateVariable?: (token: string) => boolean;\n /**\n * The invalid `[[TOKEN]]`s in the document, each once, whenever that set\n * changes (`[]` when all are valid). Use it to block saving.\n */\n onVariableValidityChange?: (invalidTokens: string[]) => void;\n /**\n * Bring your own Help-me-write surface (e.g. with practice templates). The\n * kit keeps the FAB segment, the consent gate and resume-after-grant, and\n * calls this instead of rendering its own overlay. Render an\n * `EditorOverlay` from it to dock in the same slot. Wins over the built-in\n * overlay when both this and `onRequestAiDraft` are set.\n */\n renderHelpMeWrite?: (ctx: HelpMeWriteRenderContext) => ReactNode;\n /**\n * An AI call ran out of credits: `onDictate` rejected with an error named\n * `AiCreditsExhaustedError`. With `renderHelpMeWrite` the kit also opens\n * that surface on its out-of-credits state; without it, the dictation\n * error line shows.\n */\n onAiCreditsExhausted?: () => void;\n}\n\n/** Block/inline formats the editor can toggle via `applyFormat`. */\nexport type EditorFormat =\n | 'bold'\n | 'italic'\n | 'strikethrough'\n | 'bulletedList'\n | 'numberedList'\n | 'heading'\n | 'quote'\n | 'paragraph';\n\n// Maps each format to its Redactor command (shared with the toolbar).\nconst FORMAT_COMMANDS: Record<EditorFormat, [string, ...unknown[]]> = {\n bold: ['module.inline.format', { tag: 'b' }],\n italic: ['module.inline.format', { tag: 'i' }],\n strikethrough: ['module.inline.format', { tag: 'del' }],\n bulletedList: ['module.list.toggle', 'ul'],\n numberedList: ['module.list.toggle', 'ol'],\n heading: ['module.block.format', { tag: 'h2' }],\n quote: ['module.block.format', { tag: 'blockquote' }],\n paragraph: ['module.block.format', { tag: 'p' }],\n};\n\nexport interface RichTextEditorHandle {\n getHTML: () => string;\n /** Plain-text content of the editor (tags stripped). */\n getText: () => string;\n /** Always '' — Redactor has no native Markdown serializer (see MDX). */\n getMarkdown: () => string;\n /** A one-shot AI action (template, spelling, auto-format) is running. */\n isAiBusy: () => boolean;\n /** HTML goes through DOMPurify before reaching Redactor. */\n setContent: (html: string) => void;\n /**\n * Insert content at the caret (replacing any selection). HTML is\n * DOMPurify-sanitised; pass `{ asHtml: false }` for a plain-text insert.\n * Works with the degraded <textarea> too. This is the seam for inserting\n * merge/template variables and AI-generated drafts.\n */\n insertAtCursor: (content: string, opts?: { asHtml?: boolean }) => void;\n /** Toggle/apply a block or inline format on the current selection. */\n applyFormat: (format: EditorFormat) => void;\n focus: () => void;\n clear: () => void;\n}\n\n// Map the kit's locale codes to Redactor's lang-file codes where they differ\n// (Redactor ships zh_cn / zh_tw / pt_br; the kit uses zh / pt). RTL (ar/fa/he)\n// pass through — direction is handled by the document dir, not the lang code.\nconst REDACTOR_LANG: Record<string, string> = {\n zh: 'zh_cn',\n pt: 'pt_br',\n};\n\nfunction toRedactorLang(locale: string): string {\n const base = locale.split('-')[0];\n return REDACTOR_LANG[base] ?? base ?? 'en';\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva(\n 'redactor-theme-alfadocs ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]',\n);\n\n// Variable typeahead — VariablesMenu anchored at the caret. This wrapper only\n// positions it (via two custom properties it sets on itself); the menu's own\n// chrome (border/shadow/radius/surface) lives in the component.\nconst typeaheadWrapperClass = [\n 'ds:absolute ds:z-30',\n 'ds:[inset-inline-start:var(--rte-typeahead-x)] ds:[inset-block-start:var(--rte-typeahead-y)]',\n].join(' ');\n\n// Degraded-mode plain textarea (Redactor not found) — looks like a kit field.\nconst degradedTextareaVariants = cva(\n [\n 'ds:block ds:[inline-size:100%]',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:shadow-[var(--shadow-md)]',\n 'ds:font-[family-name:var(--font-sans)] ds:text-[length:var(--font-size-base)]',\n 'ds:p-[var(--spacing-md)] ds:[min-block-size:var(--rich-text-editor-min-block-size)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n);\n\n// Split-FAB segment: an icon button inside the primary pill (record |\n// help-me-write). Transparent on the pill with an INSET focus ring (the pill\n// clips overflow, so the ring must be inset).\nconst fabSegmentBase = [\n 'ds:inline-flex ds:items-center ds:justify-center',\n 'ds:[min-block-size:var(--min-target-size)] ds:[min-inline-size:var(--min-target-size)]',\n 'ds:text-[color:var(--primary-foreground)]',\n 'ds:transition-colors',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--primary-foreground)]',\n 'ds:focus-visible:[outline-offset:calc(var(--focus-ring-width)*-1)]',\n].join(' ');\n\n// Idle segment: a translucent-white hover overlay over the pill.\nconst fabSegmentIdle = `${fabSegmentBase} ds:hover:bg-[color-mix(in_srgb,var(--primary-foreground)_15%,transparent)]`;\n\n// Recording mic: a solid destructive (red) fill that stays red on hover so the\n// \"stop\" state reads as live recording. Deliberately no aria-pressed translucent\n// overlay — its attribute selector out-specifies the red and would wash it out.\nconst fabSegmentRecording = `${fabSegmentBase} ds:bg-[var(--destructive)] ds:hover:bg-[color-mix(in_srgb,var(--destructive)_88%,var(--primary-foreground))]`;\n\n/** One pill segment: a button, or the trigger of the Templates menu. */\ninterface FabSegment {\n key: string;\n icon: ReactNode;\n label: string;\n onClick?: () => void;\n recording?: boolean;\n running?: boolean;\n menu?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* RichTextEditor */\n/* ------------------------------------------------------------------ */\n\nexport const RichTextEditor = forwardRef<\n RichTextEditorHandle,\n RichTextEditorProps\n>(\n (\n {\n id,\n defaultValue,\n value,\n onChange,\n toolbar = 'standard',\n placeholder,\n readOnly = false,\n ariaLabel,\n minHeight,\n showExtensions,\n className,\n redactor,\n options,\n plugins,\n lang,\n imageUploadUrl,\n onUploadImage,\n onKeyDown,\n onRequestAiDraft,\n aiDraftFormat = 'html',\n aiPrivacyNotice,\n aiConsent,\n aiConsentHeadingLevel,\n onDictate,\n onProofread,\n onAutoFormat,\n aiTemplates,\n onAiApplied,\n aiSparkle = true,\n selectionToolbar,\n variables,\n recentVariableTokens,\n onVariableInserted,\n validateVariable,\n onVariableValidityChange,\n renderHelpMeWrite,\n onAiCreditsExhausted,\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const rawId = useId();\n const editorId = useMemo(\n () => `rte-${rawId.replace(/[^a-zA-Z0-9-_]/g, '')}`,\n [rawId],\n );\n const selector = `#${editorId}`;\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const redactorRef = useRef<RedactorFactory | null>(null);\n // Skip-once guard: Redactor's `changed` already pushed this value out via\n // onChange, so the controlled-value effect must not echo it back with\n // setCode (which resets the caret to position 0). Mirrors platform.\n const skipNextPropSyncRef = useRef(false);\n // Mirrors the live readOnly state for imperative ops: Redactor blocks every\n // command except `disableReadOnly` while read-only, so writes (setContent /\n // clear / insertAtCursor / controlled-value sync) must lift it first.\n const readOnlyRef = useRef(readOnly);\n const wrapperRef = useRef<HTMLDivElement>(null);\n // The positioned editing-surface container — the floating table toolbar is\n // absolutely placed within it.\n const editorAreaRef = useRef<HTMLDivElement>(null);\n const [degraded, setDegraded] = useState(false);\n const [aiOpen, setAiOpen] = useState(false);\n // Selection text captured when Help-me-write opened (renderHelpMeWrite).\n const [aiSelectionText, setAiSelectionText] = useState('');\n // What Help-me-write was opened about: the whole note, or the selection.\n const [aiScope, setAiScope] = useState<'document' | 'selection'>(\n 'document',\n );\n // Help-me-write was opened by a dictation that ran out of AI credits.\n const [aiCreditsExhausted, setAiCreditsExhausted] = useState(false);\n const onAiCreditsExhaustedRef = useRef(onAiCreditsExhausted);\n const renderHelpMeWriteRef = useRef(renderHelpMeWrite);\n useEffect(() => {\n onAiCreditsExhaustedRef.current = onAiCreditsExhausted;\n renderHelpMeWriteRef.current = renderHelpMeWrite;\n }, [onAiCreditsExhausted, renderHelpMeWrite]);\n const aiRangeRef = useRef<Range | null>(null);\n\n // Known variable tokens — drives the toolbar menu and the inbound chip\n // wrapping. The ref serves the mount-time seed and the imperative writes.\n const variableTokens = useMemo<VariableLookup>(\n () =>\n new Map(\n (variables ?? [])\n .map((variable) => variable.token)\n .filter((token) => VARIABLE_TOKEN.test(token))\n .map((token) => [token.toLowerCase(), token] as const),\n ),\n [variables],\n );\n // Display labels for the chips, by lower-case token.\n const variableLabels = useMemo(\n () =>\n new Map(\n (variables ?? []).map(\n (variable) =>\n [variable.token.toLowerCase(), variable.label] as const,\n ),\n ),\n [variables],\n );\n const variableTokensRef = useRef(variableTokens);\n useEffect(() => {\n variableTokensRef.current = variableTokens;\n }, [variableTokens]);\n\n // Variables offered by VariablesMenu (both anchors) — malformed tokens\n // never reach the menu, matching the inbound-chip validity rule above.\n const menuVariables = useMemo<VariablesMenuVariable[]>(\n () => (variables ?? []).filter((v) => VARIABLE_TOKEN.test(v.token)),\n [variables],\n );\n\n // Variable validity: the host's check, else \"one of `variables`\".\n // The host's check lives in a ref, so an inline `validateVariable`\n // doesn't re-run the whole-document check on every render.\n const validateRef = useRef(validateVariable);\n useEffect(() => {\n validateRef.current = validateVariable;\n }, [validateVariable]);\n const hasValidator = validateVariable !== undefined;\n const isVariableValid = useCallback(\n (token: string): boolean =>\n hasValidator && validateRef.current\n ? validateRef.current(token)\n : variableTokens.has(token.toLowerCase()),\n [hasValidator, variableTokens],\n );\n const variablesEnabled = variableTokens.size > 0 || hasValidator;\n const [invalidVariables, setInvalidVariables] = useState<string[]>([]);\n const onValidityRef = useRef(onVariableValidityChange);\n useEffect(() => {\n onValidityRef.current = onVariableValidityChange;\n }, [onVariableValidityChange]);\n // Re-check every chip + bare token; flag invalid chips in the DOM (the\n // marker class is stripped from everything the editor hands out).\n const checkVariablesRef = useRef<() => void>(() => {});\n // Active formats at the caret (bold/italic/strike/ul/ol/heading) — drives\n // the custom toolbar's pressed state; refreshed on Redactor's `observe`.\n const [activeFormats, setActiveFormats] = useState<ReadonlySet<string>>(\n () => new Set(),\n );\n // The <img> the user has selected (clicked) in this editor's editable, or\n // null — drives the ImageFloatingToolbar (wrap / align / resize). The ref\n // mirrors the state so the apply seams read the live element synchronously.\n const activeImageElRef = useRef<HTMLElement | null>(null);\n const [activeImageEl, setActiveImageEl] = useState<HTMLElement | null>(\n null,\n );\n const selectImage = useCallback((el: HTMLElement | null): void => {\n activeImageElRef.current = el;\n setActiveImageEl(el);\n }, []);\n\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n // The last HTML handed to the host's onChange (to skip no-op changes).\n const lastHostHtmlRef = useRef<string | null>(null);\n const onChangeRef = useRef<RichTextEditorProps['onChange']>(onChange);\n const onKeyDownRef = useRef<RichTextEditorProps['onKeyDown']>(onKeyDown);\n useEffect(() => {\n onChangeRef.current = onChange;\n onKeyDownRef.current = onKeyDown;\n }, [onChange, onKeyDown]);\n\n // Initial content is computed once (controlled `value` is then synced by\n // the effect below). Sanitised before it ever reaches Redactor.\n const initialContentRef = useRef<string>(\n (() => {\n const raw = value ?? defaultValue ?? '';\n return raw ? sanitiseHtml(raw) : '';\n })(),\n );\n\n // Read the current editor HTML. Redactor's `source.getCode` is blocked while\n // read-only (returns undefined), so fall back to the synced source textarea\n // — never toggle read-only just to read.\n const readCode = useCallback((): string => {\n const R = redactorRef.current;\n if (R) {\n try {\n const code = R(selector, 'source.getCode');\n if (typeof code === 'string') return stripEditorMarkers(code);\n } catch {\n /* fall through to the source textarea */\n }\n }\n return textareaRef.current?.value ?? '';\n }, [selector]);\n\n useEffect(() => {\n checkVariablesRef.current = (): void => {\n if (!variablesEnabled) {\n setInvalidVariables((prev) => (prev.length ? [] : prev));\n return;\n }\n const root = wrapperRef.current?.querySelector('.redactor-in');\n root\n ?.querySelectorAll('[data-redactor-type=\"variable\"]')\n .forEach((chip) => {\n const match = /^\\[\\[([A-Za-z0-9_]+)\\]\\]$/.exec(\n chip.textContent ?? '',\n );\n const invalid = !match || !isVariableValid(match[1]);\n // Change the DOM only when something differs, so the check\n // never loops on itself through Redactor's change sync.\n if (chip.classList.contains(INVALID_VARIABLE_CLASS) !== invalid) {\n chip.classList.toggle(INVALID_VARIABLE_CLASS, invalid);\n }\n // The chip shows the host's label (CSS reads data-label); the\n // hover title keeps the real token in view.\n const label = match\n ? (variableLabels.get(match[1].toLowerCase()) ?? match[1])\n : (chip.textContent ?? '');\n if (chip.getAttribute('data-label') !== label) {\n chip.setAttribute('data-label', label);\n }\n const title = chip.textContent ?? '';\n if (chip.getAttribute('title') !== title) {\n chip.setAttribute('title', title);\n }\n });\n const invalid = Array.from(\n new Set(\n variableTokensIn(readCode()).filter(\n (token) => !isVariableValid(token),\n ),\n ),\n );\n setInvalidVariables((prev) =>\n prev.length === invalid.length &&\n prev.every((token, index) => token === invalid[index])\n ? prev\n : invalid,\n );\n };\n checkVariablesRef.current();\n }, [variablesEnabled, isVariableValid, variableLabels, readCode]);\n\n // Mark the editing region invalid and point it at the message.\n useEffect(() => {\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const target = root ?? textareaRef.current;\n if (!target) return;\n if (invalidVariables.length > 0) {\n target.setAttribute('aria-invalid', 'true');\n target.setAttribute('aria-describedby', `${editorId}-variables-error`);\n } else {\n target.removeAttribute('aria-invalid');\n target.removeAttribute('aria-describedby');\n }\n }, [invalidVariables, editorId, degraded]);\n\n // Report the invalid set to the host whenever it changes, and report\n // `[]` once when validation turns off, so a host that blocked Save on\n // invalid tokens unblocks it.\n const validityReportedRef = useRef(false);\n useEffect(() => {\n if (variablesEnabled) {\n validityReportedRef.current = true;\n onValidityRef.current?.(invalidVariables);\n } else if (validityReportedRef.current) {\n validityReportedRef.current = false;\n onValidityRef.current?.([]);\n }\n }, [invalidVariables, variablesEnabled]);\n\n // A different `validateVariable` function can change what is valid:\n // re-check the document (the check itself only touches the DOM and\n // state when something differs, so an inline function costs a scan).\n useEffect(() => {\n if (validateVariable) checkVariablesRef.current();\n }, [validateVariable]);\n\n // Dispatch a mutating Redactor command, transparently lifting read-only\n // (which blocks every command but `disableReadOnly`) and restoring it after.\n // Returns false when Redactor is absent or the call failed so the caller can\n // fall back to the degraded <textarea>.\n const dispatchWrite = useCallback(\n (command: string, ...args: unknown[]): boolean => {\n const R = redactorRef.current;\n if (!R) return false;\n const wasReadOnly = readOnlyRef.current;\n if (wasReadOnly) {\n try {\n R(selector, 'disableReadOnly');\n } catch {\n /* ignore */\n }\n }\n try {\n R(selector, command, ...args);\n return true;\n } catch {\n return false;\n } finally {\n if (wasReadOnly) {\n try {\n R(selector, 'enableReadOnly');\n } catch {\n // Restore failed — the editor may be left editable. Surface it in\n // DEV; the next readOnly-sync tick re-asserts it on a prop change.\n if (import.meta.env.DEV) {\n console.warn(\n '[RichTextEditor] failed to restore read-only after a write; the editor may be left editable.',\n );\n }\n }\n }\n }\n },\n [selector],\n );\n\n // Insert content at the caret, sanitised, with a degraded <textarea> splice\n // fallback. Shared by the imperative handle (merge variables) and the\n // Help-me-write dialog (AI drafts).\n const insertAtCursor = useCallback(\n (content: string, opts?: { asHtml?: boolean }): void => {\n const asHtml = opts?.asHtml ?? true;\n const payload = asHtml ? sanitiseHtml(content) : content;\n const command = asHtml\n ? 'insertion.insertHtml'\n : 'insertion.insertText';\n if (dispatchWrite(command, payload)) return;\n const ta = textareaRef.current;\n if (!ta) return;\n const start = ta.selectionStart ?? ta.value.length;\n const end = ta.selectionEnd ?? ta.value.length;\n ta.value = ta.value.slice(0, start) + payload + ta.value.slice(end);\n const caret = start + payload.length;\n try {\n ta.setSelectionRange(caret, caret);\n } catch {\n /* selection API unavailable */\n }\n onChangeRef.current?.({ html: sanitiseHtml(ta.value), markdown: '' });\n },\n [dispatchWrite],\n );\n\n // Last in-editor selection range — see updateActiveFormats / restoreSelection.\n const lastRangeRef = useRef<Range | null>(null);\n\n // Recompute the active inline/block formats at the caret (scoped to THIS\n // editor's `.redactor-in`) for the custom toolbar's pressed state.\n const updateActiveFormats = useCallback((): void => {\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const selection =\n typeof window !== 'undefined' ? window.getSelection() : null;\n const next = new Set<string>();\n if (\n root &&\n selection &&\n selection.anchorNode &&\n root.contains(selection.anchorNode) &&\n typeof document.queryCommandState === 'function'\n ) {\n // Track the live in-editor range so a focus-stealing DS popover/dialog\n // can restore EXACTLY here — needed because Redactor's insertHtml wraps\n // the insert in a fresh <p> when no selection is active at insert time.\n if (selection.rangeCount > 0) {\n lastRangeRef.current = selection.getRangeAt(0).cloneRange();\n }\n // queryCommandState reads the selection's EFFECTIVE format (it handles\n // range boundaries + nesting), unlike walking the anchor's ancestors —\n // which misses a format when the anchor sits just outside the wrapper.\n try {\n if (document.queryCommandState('bold')) next.add('bold');\n if (document.queryCommandState('italic')) next.add('italic');\n if (document.queryCommandState('underline')) next.add('underline');\n if (document.queryCommandState('strikeThrough')) next.add('strike');\n if (document.queryCommandState('insertUnorderedList')) next.add('ul');\n if (document.queryCommandState('insertOrderedList')) next.add('ol');\n const block = String(\n document.queryCommandValue('formatBlock') || '',\n ).toLowerCase();\n // Add both the generic 'heading' token and the specific block tag\n // (h2/h3/quote/paragraph) so the toolbar's labelled style button can\n // show the active style by name.\n if (/^h[1-6]$/.test(block)) {\n next.add('heading');\n next.add(block);\n } else if (block === 'blockquote') {\n next.add('quote');\n } else {\n next.add('paragraph');\n }\n // Table context — drives the contextual table ops in the toolbar.\n const anchorEl =\n selection.anchorNode.nodeType === Node.TEXT_NODE\n ? selection.anchorNode.parentElement\n : (selection.anchorNode as Element | null);\n if (\n anchorEl &&\n root.contains(anchorEl) &&\n anchorEl.closest('table')\n ) {\n next.add('table');\n }\n } catch {\n /* queryCommand unsupported in this environment */\n }\n }\n setActiveFormats((prev) =>\n prev.size === next.size && [...next].every((f) => prev.has(f))\n ? prev\n : next,\n );\n }, []);\n\n // Run a Redactor command from the custom toolbar, then refresh active state.\n const runCommand = useCallback(\n (command: string, ...args: unknown[]): void => {\n dispatchWrite(command, ...args);\n // Defer the active-state read: let Redactor finish applying the command\n // and the selection settle first, otherwise un-toggling a format reads\n // the stale pre-change DOM and the button stays pressed.\n if (typeof window !== 'undefined') {\n window.requestAnimationFrame(() => updateActiveFormats());\n } else {\n updateActiveFormats();\n }\n },\n [dispatchWrite, updateActiveFormats],\n );\n\n // Inline-format keyboard shortcuts (Cmd/Ctrl + B/I/U). Redactor ships these\n // natively, but with `toolbar: false` its shortcut fires yet silently no-ops\n // (it preventDefaults the key, then its inline.format applies nothing). So\n // the kit owns them: intercept on the editor in the capture phase — before\n // Redactor's own keydown listener — and route through the SAME runCommand\n // path the toolbar uses (which works). stopImmediatePropagation suppresses\n // Redactor's dead handler; preventDefault suppresses the browser's native\n // execCommand so the format applies exactly once.\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (!wrapper) return undefined;\n // Local key→command map (the same inline commands the toolbar buttons\n // fire) so this owns nothing on the public format API.\n const SHORTCUT_COMMANDS: Record<string, [string, ...unknown[]]> = {\n b: ['module.inline.format', { tag: 'b' }],\n i: ['module.inline.format', { tag: 'i' }],\n u: ['module.inline.format', { tag: 'u' }],\n };\n const onKeyDownCapture = (event: KeyboardEvent): void => {\n if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey)\n return;\n if (event.isComposing) return;\n const command = SHORTCUT_COMMANDS[event.key.toLowerCase()];\n if (!command) return;\n // Only when the caret is in this editor's editable, and it's writable.\n const editable = wrapper.querySelector('.redactor-in');\n if (\n !editable ||\n !(event.target instanceof Node) ||\n !editable.contains(event.target) ||\n readOnlyRef.current\n )\n return;\n event.preventDefault();\n event.stopImmediatePropagation();\n runCommand(...command);\n };\n wrapper.addEventListener('keydown', onKeyDownCapture, true);\n return () =>\n wrapper.removeEventListener('keydown', onKeyDownCapture, true);\n }, [runCommand]);\n\n // Insert sanitised HTML at the caret — the toolbar's link/image dialogs use\n // this (DOMPurify runs inside insertAtCursor) instead of Redactor's native\n // modals.\n const insertHtml = useCallback(\n (html: string): void => {\n insertAtCursor(html, { asHtml: true });\n if (typeof window !== 'undefined') {\n window.requestAnimationFrame(() => updateActiveFormats());\n }\n },\n [insertAtCursor, updateActiveFormats],\n );\n\n /* ---- Variable typeahead + typed-token chips ------------------ */\n // Typing `[[` opens the VariablesMenu, anchored at the caret, which\n // filters as you type; a fully typed `[[token]]` becomes a chip on its\n // closing `]]` (known tokens take the host's spelling; unknown ones stay\n // as typed and the validity check flags them). Grouping/filtering/active-\n // row bookkeeping all live in VariablesMenu — this wrapper only tracks\n // where the `[[query` text sits (to replace it on pick) and where to\n // position the popover.\n const [typeahead, setTypeahead] = useState<{\n query: string;\n left: number;\n top: number;\n } | null>(null);\n // Where the `[[query` text sits, to replace it on pick.\n const typeaheadAnchorRef = useRef<{\n node: Text;\n start: number;\n end: number;\n } | null>(null);\n const typeaheadId = `${editorId}-variables`;\n const caretMenuRef = useRef<VariablesMenuHandle>(null);\n const [caretActiveDescendant, setCaretActiveDescendant] = useState<\n string | undefined\n >(undefined);\n\n const closeTypeahead = useCallback((): void => {\n typeaheadAnchorRef.current = null;\n setTypeahead(null);\n }, []);\n\n // Replace `[[query` (or a full `[[token]]`) with a chip.\n const insertVariableAt = useCallback(\n (token: string, anchor: { node: Text; start: number; end: number }) => {\n const sel = window.getSelection();\n if (!sel) return;\n const range = document.createRange();\n range.setStart(anchor.node, anchor.start);\n range.setEnd(anchor.node, anchor.end);\n sel.removeAllRanges();\n sel.addRange(range);\n insertHtml(variableHtml(token));\n window.requestAnimationFrame(() => checkVariablesRef.current());\n },\n [insertHtml],\n );\n\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (!wrapper || !variablesEnabled) return undefined;\n const onInput = (): void => {\n const root = wrapper.querySelector('.redactor-in');\n const sel = window.getSelection();\n if (!root || !sel || sel.rangeCount === 0 || !sel.isCollapsed) {\n closeTypeahead();\n return;\n }\n const { startContainer, startOffset } = sel.getRangeAt(0);\n if (\n startContainer.nodeType !== Node.TEXT_NODE ||\n !root.contains(startContainer) ||\n (startContainer.parentElement?.closest(\n '[data-redactor-type=\"variable\"]',\n ) ?? null) !== null\n ) {\n closeTypeahead();\n return;\n }\n const node = startContainer as Text;\n const before = node.data.slice(0, startOffset);\n const full = /\\[\\[([A-Za-z0-9_]+)\\]\\]$/.exec(before);\n if (full) {\n closeTypeahead();\n insertVariableAt(\n variableTokens.get(full[1].toLowerCase()) ?? full[1],\n { node, start: startOffset - full[0].length, end: startOffset },\n );\n return;\n }\n const open = /\\[\\[([A-Za-z0-9_ ]{0,40})$/.exec(before);\n const area = editorAreaRef.current;\n if (!open || !area || (variables ?? []).length === 0) {\n closeTypeahead();\n return;\n }\n const anchor = {\n node,\n start: startOffset - open[0].length,\n end: startOffset,\n };\n typeaheadAnchorRef.current = anchor;\n const range = document.createRange();\n range.setStart(node, anchor.start);\n range.setEnd(node, anchor.end);\n const rect = range.getBoundingClientRect();\n const box = area.getBoundingClientRect();\n // Inline-start offset, mirrored for RTL.\n const rtl = getComputedStyle(area).direction === 'rtl';\n setTypeahead({\n query: open[1],\n left: rtl ? box.right - rect.right : rect.left - box.left,\n top: rect.bottom - box.top + 4,\n });\n };\n // Capture phase, ahead of Redactor's own Enter handling. Navigation,\n // selection and Escape are all forwarded to VariablesMenu's own\n // handler; character input and Backspace are left alone — they\n // mutate the document text, which the `onInput` listener above\n // re-reads on every keystroke (including a Backspace past the `[[`\n // trigger, which naturally fails the `open` regex and closes the menu).\n const onKeyDown = (event: KeyboardEvent): void => {\n if (!typeaheadAnchorRef.current) return;\n if (\n !['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter', 'Escape'].includes(\n event.key,\n )\n ) {\n return;\n }\n const handled = caretMenuRef.current?.handleKeyDown(event) ?? false;\n if (handled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n }\n };\n const onFocusOut = (): void => closeTypeahead();\n wrapper.addEventListener('input', onInput);\n wrapper.addEventListener('keydown', onKeyDown, true);\n wrapper.addEventListener('focusout', onFocusOut);\n return () => {\n wrapper.removeEventListener('input', onInput);\n wrapper.removeEventListener('keydown', onKeyDown, true);\n wrapper.removeEventListener('focusout', onFocusOut);\n };\n }, [\n variablesEnabled,\n variableTokens,\n variables,\n insertVariableAt,\n closeTypeahead,\n ]);\n\n // Combobox wiring on the editing region while the menu is open — focus\n // stays on `.redactor-in` throughout, so it (not the menu) plays the\n // combobox role.\n useEffect(() => {\n const root = wrapperRef.current?.querySelector('.redactor-in');\n if (!root) return;\n if (typeahead) {\n root.setAttribute('aria-expanded', 'true');\n // VariablesMenu's actual listbox id — it's `${id}-list`, not the\n // wrapper id passed in as `id={typeaheadId}` on the menu itself.\n root.setAttribute('aria-controls', `${typeaheadId}-list`);\n if (caretActiveDescendant) {\n root.setAttribute('aria-activedescendant', caretActiveDescendant);\n } else {\n root.removeAttribute('aria-activedescendant');\n }\n } else {\n root.removeAttribute('aria-expanded');\n root.removeAttribute('aria-controls');\n root.removeAttribute('aria-activedescendant');\n }\n }, [typeahead, typeaheadId, caretActiveDescendant]);\n\n const handleCaretVariableSelect = useCallback(\n (variable: RichTextEditorVariable): void => {\n const anchor = typeaheadAnchorRef.current;\n closeTypeahead();\n if (anchor) insertVariableAt(variable.token, anchor);\n onVariableInserted?.(variable.token);\n },\n [closeTypeahead, insertVariableAt, onVariableInserted],\n );\n\n const handleCaretVariableClose = useCallback((): void => {\n closeTypeahead();\n }, [closeTypeahead]);\n\n const handleCaretQueryChange = useCallback((query: string): void => {\n // The caret anchor's query is driven by the document text itself (see\n // `onInput` above) — this only exists so VariablesMenu's `query` prop\n // has a setter to call for its own controlled `<input>` echo. Typing\n // into that input never happens in caret mode (it's not focusable), so\n // this is effectively a no-op safety net, not a real code path.\n setTypeahead((prev) => (prev ? { ...prev, query } : prev));\n }, []);\n\n // Save / restore the editor selection around a DS popover/dialog (which\n // takes focus and would otherwise collapse the caret). Backed by Redactor's\n // selection module; no-ops in the degraded textarea.\n const saveSelection = useCallback((): void => {\n // Snapshot the current in-editor range synchronously (before a trigger's\n // focus move can collapse it), in addition to the observe-driven tracking.\n if (typeof window !== 'undefined') {\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const sel = window.getSelection();\n if (\n root &&\n sel &&\n sel.rangeCount > 0 &&\n sel.anchorNode &&\n root.contains(sel.anchorNode)\n ) {\n lastRangeRef.current = sel.getRangeAt(0).cloneRange();\n }\n }\n const R = redactorRef.current;\n if (R) {\n try {\n R(selector, 'selection.save');\n } catch {\n /* selection module unavailable */\n }\n }\n }, [selector]);\n\n const restoreSelection = useCallback((): void => {\n const R = redactorRef.current;\n if (!R) return;\n // Re-focus the editor, then re-apply the tracked DOM range. This is more\n // reliable than Redactor's marker-based restore when a modal's focus trap\n // moved focus before the markers were set — without an active selection\n // Redactor's insertHtml wraps the insert in a new <p> (the link/image\n // \"block\" bug). Fall back to the marker restore if no range was tracked.\n // Capture the tracked range BEFORE editor.focus: focusing fires Redactor's\n // `observe`, which runs updateActiveFormats and overwrites lastRangeRef with\n // the post-focus caret (editor start). Reading it first preserves the\n // user's real selection (otherwise colour/link land at the top of the doc).\n const range = lastRangeRef.current;\n try {\n R(selector, 'editor.focus');\n } catch {\n /* ignore */\n }\n if (range && typeof window !== 'undefined') {\n const sel = window.getSelection();\n if (sel) {\n try {\n sel.removeAllRanges();\n sel.addRange(range);\n return;\n } catch {\n /* range no longer valid — fall through to marker restore */\n }\n }\n }\n try {\n R(selector, 'selection.restore');\n } catch {\n /* selection module unavailable */\n }\n }, [selector]);\n\n // Current selected text (for prefilling the link dialog's text field).\n const getSelectedText = useCallback((): string => {\n if (typeof window === 'undefined') return '';\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const selection = window.getSelection();\n if (\n !root ||\n !selection ||\n !selection.anchorNode ||\n !root.contains(selection.anchorNode)\n ) {\n return '';\n }\n return selection.toString();\n }, []);\n\n // The <table> the caret is currently inside (scoped to THIS editor's\n // `.redactor-in`), or null — drives the floating in-cell table toolbar's\n // visibility + anchor. Mirrors the table detection in updateActiveFormats.\n const getActiveTableEl = useCallback((): HTMLElement | null => {\n if (typeof window === 'undefined') return null;\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const selection = window.getSelection();\n if (!root || !selection || selection.rangeCount === 0) return null;\n const node = selection.anchorNode;\n const el =\n node && node.nodeType === Node.TEXT_NODE\n ? node.parentElement\n : (node as Element | null);\n if (!el || !root.contains(el)) return null;\n return el.closest('table');\n }, []);\n\n // The <td>/<th> the caret is in (scoped to this editor) — backs the table\n // background-colour controls.\n const lastCellRef = useRef<HTMLElement | null>(null);\n const getActiveCellEl = useCallback((): HTMLElement | null => {\n if (typeof window === 'undefined') return null;\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const selection = window.getSelection();\n if (!root || !selection || selection.rangeCount === 0) return null;\n const node = selection.anchorNode;\n const el =\n node && node.nodeType === Node.TEXT_NODE\n ? node.parentElement\n : (node as Element | null);\n if (!el || !root.contains(el)) return null;\n return el.closest('td,th') as HTMLElement | null;\n }, []);\n\n // Snapshot the current cell before a colour popover steals focus.\n const saveTableCell = useCallback((): void => {\n lastCellRef.current = getActiveCellEl();\n }, [getActiveCellEl]);\n\n // Apply (colour) or clear (colour === null) a background on the saved cell,\n // or every cell in its row. Redactor has no cell-styling command, so this\n // mutates the editable DOM directly, takes a best-effort undo snapshot, then\n // hard-syncs so the change lands in the source + fires `changed` → onChange.\n const applyTableBackground = useCallback(\n (scope: 'cell' | 'row', colour: string | null): void => {\n const cell = lastCellRef.current ?? getActiveCellEl();\n if (!cell) return;\n const targets: HTMLElement[] =\n scope === 'row'\n ? Array.from(cell.closest('tr')?.children ?? [cell]).filter(\n (n): n is HTMLElement =>\n n instanceof HTMLElement &&\n (n.tagName === 'TD' || n.tagName === 'TH'),\n )\n : [cell];\n const R = redactorRef.current;\n if (R) {\n try {\n R(selector, 'module.buffer.trigger');\n } catch {\n /* undo buffer unavailable — colour still applies */\n }\n }\n for (const el of targets) {\n if (colour) el.style.setProperty('background-color', colour);\n else el.style.removeProperty('background-color');\n }\n if (R) {\n try {\n R(selector, 'broadcast', 'hardsync');\n } catch {\n /* sync unavailable */\n }\n }\n if (typeof window !== 'undefined') {\n window.requestAnimationFrame(() => updateActiveFormats());\n }\n },\n [getActiveCellEl, selector, updateActiveFormats],\n );\n\n // Track which image is selected: a click inside the editable selects the\n // clicked <img> (or clears when it lands on non-image content); Escape\n // deselects; focus leaving the whole editor clears. Clicks on the floating\n // controls (outside `.redactor-in`) keep the current selection so its bar\n // stays reachable. Scoped to THIS editor's wrapper.\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (typeof window === 'undefined' || !wrapper) return undefined;\n const onClick = (event: MouseEvent): void => {\n const editable = wrapper.querySelector('.redactor-in');\n const target = event.target;\n if (\n !editable ||\n !(target instanceof Node) ||\n !editable.contains(target)\n )\n return;\n const img = target instanceof Element ? target.closest('img') : null;\n selectImage(img && editable.contains(img) ? img : null);\n };\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape' && activeImageElRef.current) {\n selectImage(null);\n }\n };\n const onFocusOut = (event: FocusEvent): void => {\n const next = event.relatedTarget;\n if (!(next instanceof Node) || !wrapper.contains(next)) {\n selectImage(null);\n }\n };\n wrapper.addEventListener('click', onClick);\n wrapper.addEventListener('keydown', onKeyDown);\n wrapper.addEventListener('focusout', onFocusOut);\n return () => {\n wrapper.removeEventListener('click', onClick);\n wrapper.removeEventListener('keydown', onKeyDown);\n wrapper.removeEventListener('focusout', onFocusOut);\n };\n }, [selectImage]);\n\n // Apply (or replace) a `wysiwyg-img-*` layout class within its group on the\n // selected image. Mirrors applyTableBackground: snapshot undo, mutate the\n // editable DOM directly (Redactor has no image-class command), then hard-\n // sync so the change lands in the source + fires `changed` → onChange.\n const applyImageClass = useCallback(\n (className: string): void => {\n const img = activeImageElRef.current;\n if (!img) return;\n const group = (IMAGE_FLOW_CLASSES as readonly string[]).includes(\n className,\n )\n ? IMAGE_FLOW_CLASSES\n : IMAGE_ALIGN_CLASSES;\n const R = redactorRef.current;\n if (R) {\n try {\n R(selector, 'module.buffer.trigger');\n } catch {\n /* undo buffer unavailable — class still applies */\n }\n }\n for (const c of group) img.classList.remove(c);\n img.classList.add(className);\n if (R) {\n try {\n R(selector, 'broadcast', 'hardsync');\n } catch {\n /* sync unavailable */\n }\n }\n if (typeof window !== 'undefined') {\n window.requestAnimationFrame(() => updateActiveFormats());\n }\n },\n [selector, updateActiveFormats],\n );\n\n // Set the selected image's width as a % of its editable box. The width is\n // an inline style (the only continuous-value carrier; survives the rich-\n // text DOMPurify profile) — same runtime-DOM-mutation seam as the table\n // colour control, not a JSX inline style.\n const setImageWidth = useCallback(\n (pct: number): void => {\n const img = activeImageElRef.current;\n if (!img) return;\n const R = redactorRef.current;\n if (R) {\n try {\n R(selector, 'module.buffer.trigger');\n } catch {\n /* undo buffer unavailable — width still applies */\n }\n }\n img.style.setProperty('width', `${pct}%`);\n if (R) {\n try {\n R(selector, 'broadcast', 'hardsync');\n } catch {\n /* sync unavailable */\n }\n }\n if (typeof window !== 'undefined') {\n window.requestAnimationFrame(() => updateActiveFormats());\n }\n },\n [selector, updateActiveFormats],\n );\n\n // Insert a table, but never inside a list item — tables can't live in an\n // <li> and the nested markup hides the table UI. When the caret is in a\n // list, drop it after the whole list so the table lands as its own block.\n const insertTable = useCallback(\n (html: string): void => {\n const R = redactorRef.current;\n if (R && typeof window !== 'undefined') {\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const selection = window.getSelection();\n const node = selection?.anchorNode;\n const el =\n node && node.nodeType === Node.TEXT_NODE\n ? node.parentElement\n : (node as Element | null);\n const list = el && root?.contains(el) ? el.closest('ul,ol') : null;\n if (list) {\n try {\n R(selector, 'caret.setAfter', list);\n } catch {\n /* caret module unavailable — falls back to cursor insert */\n }\n }\n }\n insertHtml(html);\n // Redactor's insertion leaves a stray trailing whitespace text node in\n // the final cell (<td><br> </td>); that space renders as a second line\n // and makes the last row taller WHILE EDITING. The saved source is\n // already clean (cleaner.output strips it), so just tidy the live\n // editable so every row renders at one line.\n if (typeof window !== 'undefined') {\n window.requestAnimationFrame(() => {\n const root = wrapperRef.current?.querySelector('.redactor-in');\n root?.querySelectorAll('table td, table th').forEach((cell) => {\n let last = cell.lastChild;\n while (\n last &&\n last.nodeType === Node.TEXT_NODE &&\n !(last.textContent ?? '').trim()\n ) {\n const prev = last.previousSibling;\n cell.removeChild(last);\n last = prev;\n }\n });\n });\n }\n },\n [insertHtml, selector],\n );\n\n // Upload an image file to the consumer's endpoint (mirrors Redactor's\n // imageUpload config) and resolve the stored URL — the image dialog's\n // upload tab uses this so users can upload, not just paste a URL.\n const uploadImage = useCallback(\n async (file: File, signal?: AbortSignal): Promise<string> => {\n if (onUploadImage) return onUploadImage(file, signal);\n if (!imageUploadUrl) throw new Error('No image upload URL configured.');\n const form = new FormData();\n form.append('file', file);\n const res = await fetch(imageUploadUrl, {\n method: 'POST',\n body: form,\n credentials: 'same-origin',\n signal,\n });\n if (!res.ok) throw new Error(`Image upload failed (${res.status}).`);\n const url = extractUploadedUrl(await res.json());\n if (!url) throw new Error('Image upload response contained no URL.');\n return url;\n },\n [imageUploadUrl, onUploadImage],\n );\n\n /* ---- Voice dictation (DS UI; consumer runs mic + transcription) - */\n const dictateAbortRef = useRef<AbortController | null>(null);\n const interimRef = useRef<HTMLElement | null>(null);\n const [isDictating, setIsDictating] = useState(false);\n const [dictationErrored, setDictationErrored] = useState(false);\n // Drives the visually-hidden live region: announces the listening status on\n // start and each committed phrase as it lands, so screen-reader users get\n // the same feedback sighted users get from the grey interim span + caret.\n const [dictationAnnouncement, setDictationAnnouncement] = useState('');\n\n // Live (interim) speech shown in the editor as a grey, non-editable span\n // with a blinking caret; replaced by committed text on each final phrase.\n const clearInterim = useCallback((): void => {\n const el = interimRef.current;\n if (el?.parentNode) el.parentNode.removeChild(el);\n interimRef.current = null;\n }, []);\n\n const showInterim = useCallback((text: string): void => {\n const root = wrapperRef.current?.querySelector(\n '.redactor-in',\n ) as HTMLElement | null;\n if (!root) return;\n let el = interimRef.current;\n if (!el || !root.contains(el)) {\n el = document.createElement('span');\n el.setAttribute('data-rte-interim', '');\n el.setAttribute('contenteditable', 'false');\n const selection = window.getSelection();\n if (\n selection &&\n selection.rangeCount > 0 &&\n root.contains(selection.anchorNode)\n ) {\n const range = selection.getRangeAt(0);\n range.collapse(false);\n range.insertNode(el);\n } else {\n root.appendChild(el);\n }\n interimRef.current = el;\n }\n el.textContent = text;\n }, []);\n\n const stopDictation = useCallback(() => {\n // Abort but keep the ref: the in-flight session's `.finally` clears it\n // (and resets state) only when it's still the current session, so a normal\n // stop resets while a stale settle after a newer start does not.\n dictateAbortRef.current?.abort();\n }, []);\n\n // Whether the caret sits straight after a non-space character.\n const followsText = useCallback((): boolean => {\n if (typeof window === 'undefined') return false;\n const sel = window.getSelection();\n const root = wrapperRef.current?.querySelector('.redactor-in');\n if (!sel || sel.rangeCount === 0 || !root) return false;\n const { startContainer, startOffset } = sel.getRangeAt(0);\n if (!root.contains(startContainer)) return false;\n if (startContainer.nodeType !== Node.TEXT_NODE || startOffset === 0) {\n return false;\n }\n const before = (startContainer as Text).data.charAt(startOffset - 1);\n return /\\S/.test(before) && before !== '\\u00a0';\n }, []);\n\n // Hard stop, whatever the UI state: no consent, no AI call.\n const aiBlocked = aiConsent !== undefined && !aiConsent.granted;\n // A dictation started from the selection bubble replaces that selection\n // with the first phrase it hears; later phrases carry on at the caret.\n const dictationRangeRef = useRef<Range | null>(null);\n const startDictation = useCallback(() => {\n if (!onDictate || aiBlocked) return;\n const controller = new AbortController();\n dictateAbortRef.current = controller;\n setDictationErrored(false);\n setIsDictating(true);\n setDictationAnnouncement(t('editor.ai.listening'));\n clearInterim();\n onDictate({\n signal: controller.signal,\n // Interim text shows live in the editor (grey + caret); each final\n // replaces it with committed text at the caret.\n onPartialTranscript: (text: string): void => {\n if (controller.signal.aborted) return;\n showInterim(text);\n },\n onFinalTranscript: (text: string): void => {\n if (controller.signal.aborted) return;\n clearInterim();\n const trimmed = text.trim();\n if (trimmed) {\n const replacing = dictationRangeRef.current;\n if (replacing) {\n // Put the selection back and type over it.\n dictationRangeRef.current = null;\n lastRangeRef.current = replacing;\n restoreSelection();\n insertAtCursor(`${trimmed} `, { asHtml: false });\n setDictationAnnouncement(trimmed);\n return;\n }\n // Keep a space between the dictated phrase and the word before\n // the caret (e.g. dictating at the end of a sentence).\n const lead = followsText() ? ' ' : '';\n insertAtCursor(`${lead}${trimmed} `, { asHtml: false });\n // Announce the committed phrase; it replaces the interim text the\n // SR could not perceive (the grey span is aria-hidden DOM injected\n // outside React's tree).\n setDictationAnnouncement(trimmed);\n }\n },\n })\n .catch((err: unknown) => {\n if (\n controller.signal.aborted ||\n (err &&\n typeof err === 'object' &&\n 'name' in err &&\n (err as { name?: string }).name === 'AbortError')\n ) {\n return;\n }\n if (isCreditsExhausted(err)) {\n // Out of AI credits: tell the host, and show the host's\n // Help-me-write surface straight on its out-of-credits state.\n onAiCreditsExhaustedRef.current?.();\n if (renderHelpMeWriteRef.current) {\n setAiCreditsExhausted(true);\n setAiOpen(true);\n return;\n }\n }\n setDictationErrored(true);\n })\n .finally(() => {\n clearInterim();\n // Only the session that still owns the ref resets state — a stale\n // settle (a newer session already started) must not clobber it.\n if (dictateAbortRef.current === controller) {\n dictateAbortRef.current = null;\n setIsDictating(false);\n setDictationAnnouncement('');\n }\n });\n }, [\n onDictate,\n aiBlocked,\n insertAtCursor,\n restoreSelection,\n clearInterim,\n showInterim,\n followsText,\n t,\n ]);\n\n // Abort dictation on unmount.\n useEffect(() => () => dictateAbortRef.current?.abort(), []);\n\n /* ---- AI consent gate (Help-me-write + both mics) -------------- */\n // Which gated action the reader was trying to do — drives the banner's\n // docked slot AND the resume-after-grant behaviour below. Both mics\n // (this editor's own, and the one inside HelpMeWriteOverlay) and the\n // Help-me-write action share one gate: the overlay's own mic can only\n // ever be reached once the overlay is open, and the overlay itself\n // never opens while ungated (the banner takes its slot instead), so\n // gating write + this editor's mic gates all three entry points.\n // 'action' is a one-shot (template / proofread / auto-format): it sends\n // the note to the AI, so it waits behind the same gate.\n type AiConsentPendingAction = 'write' | 'dictate' | 'action';\n const [aiGateReason, setAiGateReason] =\n useState<AiConsentPendingAction | null>(null);\n const resumeAfterGrantRef = useRef<AiConsentPendingAction | null>(null);\n const pendingAiActionRef = useRef<(() => void) | null>(null);\n const [localGrantPending, setLocalGrantPending] = useState(false);\n const grantPending = (aiConsent?.pending ?? false) || localGrantPending;\n\n // Set only by a Grant click HERE. A `granted` that flips for any other\n // reason (another patient, another tab) must not start an AI action.\n const grantRequestedRef = useRef(false);\n\n const closeAiGate = useCallback((): void => {\n resumeAfterGrantRef.current = null;\n pendingAiActionRef.current = null;\n grantRequestedRef.current = false;\n setAiGateReason(null);\n }, []);\n\n const handleGrantConsent = useCallback((): void => {\n grantRequestedRef.current = true;\n const result = aiConsent?.onGrant?.();\n if (result && typeof (result as Promise<void>).then === 'function') {\n setLocalGrantPending(true);\n Promise.resolve(result)\n .catch(() => {\n /* the host surfaces its own failure UI via `aiConsent.pending` /\n a fresh `granted: false` — nothing to do here */\n })\n .finally(() => setLocalGrantPending(false));\n }\n }, [aiConsent]);\n\n // \"the user can carry on without reopening anything\": when `granted`\n // flips true while a gate is open for an action the reader tried, resume\n // exactly that action instead of leaving them to reopen it by hand.\n const prevGrantedRef = useRef(aiConsent?.granted ?? true);\n useEffect(() => {\n const wasGranted = prevGrantedRef.current;\n prevGrantedRef.current = aiConsent?.granted ?? true;\n if (!wasGranted && aiConsent?.granted && resumeAfterGrantRef.current) {\n const reason = resumeAfterGrantRef.current;\n const requestedHere = grantRequestedRef.current;\n resumeAfterGrantRef.current = null;\n grantRequestedRef.current = false;\n setAiGateReason(null);\n const pendingAction = pendingAiActionRef.current;\n pendingAiActionRef.current = null;\n if (!requestedHere) return;\n if (reason === 'write') {\n setAiOpen(true);\n } else if (reason === 'action') {\n pendingAction?.();\n } else {\n restoreSelection();\n startDictation();\n }\n }\n }, [aiConsent?.granted, restoreSelection, startDictation]);\n\n // Consent withdrawn (or the patient changed) mid-use: close the\n // Help-me-write overlay, with its own mic, and stop any recording.\n useEffect(() => {\n if (!aiBlocked) return;\n setAiOpen(false);\n if (isDictating) stopDictation();\n }, [aiBlocked, isDictating, stopDictation]);\n\n // Start dictation from either mic — gated when consent is present and\n // not yet granted. Stopping an in-progress recording is never gated.\n const handleDictateClick = useCallback(\n (scope: 'document' | 'selection' = 'document'): void => {\n if (isDictating) {\n stopDictation();\n return;\n }\n saveSelection();\n // From the bubble, the dictation replaces the text it was asked\n // about — that is what every bubble action does.\n const range = lastRangeRef.current;\n dictationRangeRef.current =\n scope === 'selection' && range && !range.collapsed\n ? range.cloneRange()\n : null;\n if (aiBlocked) {\n resumeAfterGrantRef.current = 'dictate';\n setAiGateReason('dictate');\n return;\n }\n startDictation();\n },\n [isDictating, stopDictation, aiBlocked, saveSelection, startDictation],\n );\n\n // Open Help-me-write — gated the same way.\n const handleWriteClick = useCallback(\n (scope: 'document' | 'selection' = 'document'): void => {\n saveSelection();\n const range = lastRangeRef.current;\n // Snapshot where Help-me-write was opened: a draft lands there even if\n // the reader clicks elsewhere in the note while it is generating. From\n // the pill it is about the whole note and goes in at the caret (a\n // selection is not overwritten); from the bubble it replaces the\n // selection it was asked about.\n const saved = range ? range.cloneRange() : null;\n const onSelection =\n scope === 'selection' && Boolean(saved && !saved.collapsed);\n if (saved && !onSelection) saved.collapse(false);\n aiRangeRef.current = saved;\n setAiScope(onSelection ? 'selection' : 'document');\n setAiSelectionText(onSelection && saved ? saved.toString() : '');\n if (aiBlocked) {\n resumeAfterGrantRef.current = 'write';\n setAiGateReason('write');\n return;\n }\n setAiOpen(true);\n },\n [saveSelection, aiBlocked],\n );\n\n // The Help-me-write privacy notice says consent was recorded when\n // granted (not when or by whom: that detail lives in the consent banner);\n // any consumer-supplied `aiPrivacyNotice` still appears alongside it.\n const consentPrivacyNotice = useMemo<ReactNode>(() => {\n if (!aiConsent?.granted) return aiPrivacyNotice;\n return (\n <>\n {t(\n 'editor.ai.consentRecorded',\n 'AI assistance consent has been recorded.',\n )}\n {aiPrivacyNotice ? <> {aiPrivacyNotice}</> : null}\n </>\n );\n }, [aiConsent, aiPrivacyNotice, t]);\n\n /* ---- One-shot AI actions (template / proofread / auto-format) ---- */\n // Which one-shot action is running (drives the pill's Stop segment + the\n // editor's disabled scrim); only one runs at a time.\n const [oneShot, setOneShot] = useState<OneShotKind | null>(null);\n const [aiActionErrored, setAiActionErrored] = useState(false);\n // The note changed under a running action, so its result was refused.\n const [aiActionStale, setAiActionStale] = useState(false);\n // Polite announcements for one-shot actions (the scrim is aria-hidden).\n const [aiAnnouncement, setAiAnnouncement] = useState('');\n // The pill segment of the last action, to put focus back on it.\n const lastOneShotRef = useRef<OneShotKind | null>(null);\n // The pill's sparkle: on first show, while an action runs, as it lands.\n // Owned by `useAiSparkle` — see src/hooks/use-ai-sparkle.ts.\n const aiSparkleState = useAiSparkle({ enabled: aiSparkle });\n const {\n start: startAiSparkle,\n land: landAiSparkle,\n reset: resetAiSparkle,\n } = aiSparkleState;\n const oneShotAbortRef = useRef<AbortController | null>(null);\n const onAiAppliedRef = useRef(onAiApplied);\n useEffect(() => {\n onAiAppliedRef.current = onAiApplied;\n }, [onAiApplied]);\n\n // Bubble buttons keep the selection they act on.\n const keepSelectionOnPress = (event: { preventDefault: () => void }) =>\n event.preventDefault();\n\n // Put the current document on Redactor's undo stack, so the toolbar's\n // Undo (and Ctrl/Cmd+Z) steps back over an AI rewrite.\n const pushUndoState = useCallback(\n (html: string): void => {\n const R = redactorRef.current;\n if (!R) return;\n try {\n const app = R(selector) as {\n broadcast?: (name: string, ...args: unknown[]) => void;\n } | null;\n app?.broadcast?.('state', false, html);\n } catch {\n /* buffer module unavailable */\n }\n },\n [selector],\n );\n\n // While an AI action runs the surface is read-only, so keystrokes cannot\n // race the rewrite. `dispatchWrite` lifts and restores it around the\n // kit's own writes, so the result still lands.\n const aiLockedRef = useRef(false);\n const setAiLock = useCallback(\n (locked: boolean): void => {\n const R = redactorRef.current;\n if (!R || aiLockedRef.current === locked) return;\n aiLockedRef.current = locked;\n // A host-driven read-only editor stays read-only afterwards.\n const target = locked || readOnly;\n readOnlyRef.current = target;\n try {\n R(selector, target ? 'enableReadOnly' : 'disableReadOnly');\n } catch {\n /* read-only module unavailable */\n }\n },\n [selector, readOnly],\n );\n\n // Replace the whole document; `[[TOKEN]]` text in AI output becomes chips.\n const writeDocument = useCallback(\n (html: string): void => {\n const safe = wrapVariableTokens(\n sanitiseHtml(html),\n variableTokensRef.current,\n );\n // The degraded <textarea> takes the markup as its value.\n if (!dispatchWrite('source.setCode', safe) && textareaRef.current) {\n textareaRef.current.value = safe;\n }\n onChangeRef.current?.({ html: safe, markdown: '' });\n },\n [dispatchWrite],\n );\n\n // What an AI action works on. The pill always means the whole note; the\n // selection bubble means the live selection (the whole note only when\n // that selection has no words).\n const captureAiTarget = useCallback(\n (prefer: 'document' | 'selection'): AiTarget => {\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const sel =\n typeof window !== 'undefined' ? window.getSelection() : null;\n if (\n prefer === 'selection' &&\n root &&\n sel &&\n sel.rangeCount > 0 &&\n !sel.isCollapsed\n ) {\n const range = sel.getRangeAt(0);\n if (root.contains(range.commonAncestorContainer)) {\n const text = range.toString();\n if (text.trim()) {\n return {\n scope: 'selection',\n range: range.cloneRange(),\n html: fragmentHtml(range.cloneContents()),\n text,\n };\n }\n }\n }\n const html = readCode();\n return { scope: 'document', range: null, html, text: htmlText(html) };\n },\n [readCode],\n );\n\n const runAiAction = useCallback(\n (\n kind: OneShotKind,\n fn: (request: RichTextEditorAiActionRequest) => Promise<string>,\n target: AiTarget,\n template?: RichTextEditorAiTemplate,\n ): void => {\n if (oneShotAbortRef.current) return; // one at a time\n if (!target.text.trim()) return;\n const controller = new AbortController();\n oneShotAbortRef.current = controller;\n setOneShot(kind);\n setAiActionStale(false);\n lastOneShotRef.current = kind;\n setAiAnnouncement(t('editor.ai.generating'));\n setAiActionErrored(false);\n if (aiSparkle) startAiSparkle();\n // Snapshot BEFORE locking: Redactor blocks `source.getCode` too\n // while read-only, so a read taken after the lock is not the note.\n const previousHtml = readCode();\n setAiLock(true);\n Promise.resolve(\n fn({\n html: target.html,\n text: target.text,\n scope: target.scope,\n signal: controller.signal,\n }),\n )\n .then((result) => {\n if (controller.signal.aborted) return;\n // Unlock first: reading and writing the document both need it.\n setAiLock(false);\n const draft = String(result ?? '');\n // The note changed while the AI was working (a host write, or a\n // controlled value sync): never write a stale rewrite over it.\n if (readCode() !== previousHtml) {\n setAiActionStale(true);\n setAiAnnouncement('');\n return;\n }\n // An empty answer would delete the text: treat it as a failure.\n if (!htmlText(draft)) {\n setAiActionErrored(true);\n setAiAnnouncement('');\n return;\n }\n pushUndoState(previousHtml);\n if (target.scope === 'selection' && target.range) {\n // The selection went away mid-run (content was replaced):\n // never write a selection's rewrite over the wrong text.\n if (!target.range.startContainer.isConnected) {\n setAiActionErrored(true);\n setAiAnnouncement('');\n return;\n }\n lastRangeRef.current = target.range;\n restoreSelection();\n // `[[TOKEN]]` text becomes chips, as in the whole-note path.\n const safe = wrapVariableTokens(\n sanitiseHtml(draft),\n variableTokensRef.current,\n );\n if (!dispatchWrite('insertion.insertHtml', safe)) {\n insertAtCursor(draft, { asHtml: true });\n }\n } else {\n writeDocument(draft);\n }\n if (aiSparkle) landAiSparkle();\n setAiAnnouncement(t('editor.ai.actionDone'));\n onAiAppliedRef.current?.({\n action: kind,\n template,\n scope: target.scope,\n previousHtml,\n undo: () => writeDocument(previousHtml),\n });\n })\n .catch((err: unknown) => {\n setAiLock(false);\n if (controller.signal.aborted || isAbortError(err)) return;\n if (isCreditsExhausted(err)) {\n // Same as dictation: tell the host, and open its Help-me-write\n // surface on the out-of-credits state when it has one.\n onAiCreditsExhaustedRef.current?.();\n if (renderHelpMeWriteRef.current) {\n setAiCreditsExhausted(true);\n setAiOpen(true);\n return;\n }\n }\n setAiActionErrored(true);\n setAiAnnouncement('');\n })\n .finally(() => {\n if (oneShotAbortRef.current === controller) {\n oneShotAbortRef.current = null;\n setAiLock(false);\n setOneShot(null);\n resetAiSparkle();\n }\n });\n },\n [\n aiSparkle,\n startAiSparkle,\n landAiSparkle,\n resetAiSparkle,\n setAiLock,\n readCode,\n restoreSelection,\n dispatchWrite,\n insertAtCursor,\n writeDocument,\n pushUndoState,\n t,\n ],\n );\n\n // Run an action now, or behind the consent gate (resumed after a grant).\n const requestAiAction = useCallback(\n (\n kind: OneShotKind,\n fn: (request: RichTextEditorAiActionRequest) => Promise<string>,\n target: AiTarget,\n template?: RichTextEditorAiTemplate,\n ): void => {\n if (aiBlocked) {\n pendingAiActionRef.current = () =>\n runAiAction(kind, fn, target, template);\n resumeAfterGrantRef.current = 'action';\n setAiGateReason('action');\n return;\n }\n runAiAction(kind, fn, target, template);\n },\n [aiBlocked, runAiAction],\n );\n\n // The pill's and the bubble's Templates menu run the picked template.\n const runTemplate = useCallback(\n (template: RichTextEditorAiTemplate, target: AiTarget): void => {\n const run = aiTemplates?.onRun;\n if (!run) return;\n requestAiAction(\n 'template',\n (request) => run({ ...request, template }),\n target,\n template,\n );\n },\n [aiTemplates, requestAiAction],\n );\n\n // Cancel a running one-shot. Clears the UI immediately (and aborts the\n // signal) rather than waiting on the promise, so the user always recovers\n // even if the consumer's call ignores the signal / hangs — the settle\n // guards (aborted + ref identity) then make the late result a no-op.\n const cancelOneShot = useCallback((): void => {\n oneShotAbortRef.current?.abort();\n oneShotAbortRef.current = null;\n setAiLock(false);\n setOneShot(null);\n setAiAnnouncement('');\n resetAiSparkle();\n }, [setAiLock, resetAiSparkle]);\n\n // Focus follows the action. Starting one unmounts what was focused (the\n // menu item, or the bubble button) and ending it swaps the Stop segment\n // back; when focus fell to <body>, put it on the action's pill segment.\n const pillRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const kind = oneShot ?? lastOneShotRef.current;\n if (!kind) return undefined;\n const part = kind === 'template' ? 'ai-templates' : `ai-${kind}`;\n const frame = requestAnimationFrame(() => {\n const active = document.activeElement;\n if (active && active !== document.body && active.isConnected) return;\n pillRef.current\n ?.querySelector<HTMLElement>(`[data-component-part=\"${part}\"]`)\n ?.focus();\n });\n return () => cancelAnimationFrame(frame);\n }, [oneShot]);\n\n // Abort an in-flight one-shot on unmount.\n useEffect(() => () => oneShotAbortRef.current?.abort(), []);\n\n /* ---- Init Redactor once (or degrade gracefully) -------------- */\n useEffect(() => {\n const ta = textareaRef.current;\n if (!ta) return undefined;\n // Seed the host textarea imperatively: Redactor reads it on init, and in\n // degraded mode it stays as the textarea's shown value. (Done here, not\n // via `defaultValue`, because `degraded` flips after mount so a\n // `defaultValue` prop would never apply.)\n ta.value = initialContentRef.current;\n // Check variables in the seeded content (the plain-textarea path\n // never reaches the post-init check below).\n checkVariablesRef.current();\n const R = resolveRedactor(redactor);\n if (!R) {\n setDegraded(true);\n if (import.meta.env.DEV) {\n console.warn(\n '[RichTextEditor] Redactor not found on window.$R / window.Redactor and no `redactor` prop supplied; rendering a plain textarea.',\n );\n }\n return undefined;\n }\n redactorRef.current = R;\n // Existing `[[TOKEN]]` text for the host's variables renders as chips.\n ta.value = wrapVariableTokens(ta.value, variableTokensRef.current);\n\n const kitDefaults: Record<string, unknown> = {\n lang: lang ?? toRedactorLang(i18n.language || 'en'),\n // The kit renders its OWN toolbar (EditorToolbar) and drives Redactor\n // via the command API, so Redactor's native toolbar is suppressed.\n toolbar: false,\n plugins: plugins ?? [],\n placeholder: placeholder ?? t('editor.placeholder'),\n toolbarFixed: false,\n // Platform parity (RedactorWysiwyg.js:84): no inline shortcode expansion.\n shortcodes: false,\n // The kit owns image editing: ImageFloatingToolbar provides DS-native,\n // keyboard-accessible resize + wrap/align, so Redactor's own image\n // popup AND its single-handle drag-resizer are both disabled to avoid a\n // second, untokenised, mouse-only UI competing with ours.\n imageEditable: false,\n imageResizable: false,\n };\n const imageUploadOption = imageUploadUrl\n ? { imageUpload: imageUploadUrl }\n : {};\n\n const consumerCallbacks =\n (options?.callbacks as Record<string, unknown> | undefined) ?? {};\n\n const finalOptions: Record<string, unknown> = {\n ...kitDefaults,\n ...imageUploadOption,\n ...(options ?? {}),\n // Re-pin safety-critical keys LAST so consumer `options` can't override\n // the sanitising change handler or re-enable Redactor's native image UI\n // (the kit's ImageFloatingToolbar replaces both — see kitDefaults above).\n imageEditable: false,\n imageResizable: false,\n callbacks: {\n ...consumerCallbacks,\n changed(html: string): void {\n checkVariablesRef.current();\n const normalized = normalizeEditorValue(\n withLazyImages(stripEditorMarkers(html)),\n );\n const safe = sanitiseHtml(normalized);\n // A display-only rewrite (late variables wrapped into chips) keeps\n // the text; skip its change events for a short window. A real\n // edit changes the text, so it is never swallowed.\n const rewrite = displayRewriteRef.current;\n if (\n rewrite &&\n Date.now() < rewrite.until &&\n plainText(safe) === rewrite.text\n ) {\n lastHostHtmlRef.current = safe;\n return;\n }\n // Editor-only attributes (chip labels, the invalid marker) are\n // stripped above, so their changes reach here identical: skip.\n if (safe === lastHostHtmlRef.current) return;\n lastHostHtmlRef.current = safe;\n skipNextPropSyncRef.current = true;\n if (!onChangeRef.current) return;\n if (debounceRef.current) clearTimeout(debounceRef.current);\n debounceRef.current = setTimeout(() => {\n onChangeRef.current?.({ html: safe, markdown: '' });\n }, 100);\n },\n keydown(event: KeyboardEvent): void {\n onKeyDownRef.current?.(event);\n },\n observe(): void {\n updateActiveFormats();\n },\n },\n };\n\n try {\n R(selector, finalOptions);\n // The seeded content is what the host already has: a change event\n // that only re-serialises it (Redactor may fire one after init)\n // does not reach onChange.\n lastHostHtmlRef.current = sanitiseHtml(\n normalizeEditorValue(withLazyImages(readCode())),\n );\n // Flag any invalid variables already in the seeded content.\n checkVariablesRef.current();\n // Redactor's read-only commands are camel-cased `enableReadOnly` /\n // `disableReadOnly` in this build (lower-case `enableReadonly` is a\n // silent no-op). Guarded so an unknown command stays inert.\n if (readOnly) {\n try {\n R(selector, 'enableReadOnly');\n } catch {\n /* readonly command unsupported in this Redactor build */\n }\n }\n } catch {\n setDegraded(true);\n }\n\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n try {\n // Platform forgets to destroy and leaks; we clean up on unmount.\n R(selector, 'destroy');\n } catch {\n /* already torn down */\n }\n redactorRef.current = null;\n };\n // Init once — option changes after mount are not re-applied (matches the\n // editor's uncontrolled-internals model); value/readOnly sync below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n /* ---- Variables that arrive after init -------------------------- */\n // Bare `[[TOKEN]]` text already in the note becomes chips when the host's\n // `variables` load late (for example after a fetch). Only rewrites the\n // document when a token actually wraps.\n const wrappedTokensRef = useRef(variableTokens);\n // The text a late-variables rewrite keeps, and until when its change\n // events are display-only.\n const displayRewriteRef = useRef<{ text: string; until: number } | null>(\n null,\n );\n useEffect(() => {\n if (wrappedTokensRef.current === variableTokens) return;\n wrappedTokensRef.current = variableTokens;\n if (!redactorRef.current || variableTokens.size === 0) return;\n const current = readCode();\n const wrapped = wrapVariableTokens(current, variableTokens);\n if (wrapped !== current) {\n // Display-only: the text is unchanged, so the host is not told\n // (see `changed`). Keep the caret where the user was typing.\n const root = wrapperRef.current?.querySelector('.redactor-in');\n const focused =\n root !== null &&\n root !== undefined &&\n root.contains(document.activeElement);\n const caret = focused && root ? caretTextOffset(root) : null;\n displayRewriteRef.current = {\n text: plainText(current),\n until: Date.now() + 1000,\n };\n dispatchWrite('source.setCode', wrapped);\n const after = wrapperRef.current?.querySelector('.redactor-in');\n if (caret !== null && after) placeCaretAtTextOffset(after, caret);\n }\n window.requestAnimationFrame(() => checkVariablesRef.current());\n }, [variableTokens, readCode, dispatchWrite]);\n\n /* ---- Keep controlled `value` in sync (skip-once caret guard) - */\n useEffect(() => {\n if (!redactorRef.current || value === undefined) return;\n if (skipNextPropSyncRef.current) {\n skipNextPropSyncRef.current = false;\n return;\n }\n const safe = wrapVariableTokens(\n sanitiseHtml(normalizeEditorValue(value)),\n variableTokensRef.current,\n );\n const current = normalizeEditorValue(readCode());\n if (current !== safe) dispatchWrite('source.setCode', safe);\n }, [value, readCode, dispatchWrite]);\n\n /* ---- Keep readOnly in sync ----------------------------------- */\n useEffect(() => {\n readOnlyRef.current = readOnly;\n const R = redactorRef.current;\n if (!R) return;\n try {\n R(selector, readOnly ? 'enableReadOnly' : 'disableReadOnly');\n } catch {\n /* readonly command unsupported in this Redactor build */\n }\n }, [readOnly, selector]);\n\n /* ---- Degraded fallback: reflect controlled `value` ----------- */\n // Without Redactor the host textarea is uncontrolled (seeded once on init),\n // so it would otherwise ignore external `value` updates. Sync imperatively\n // (a controlled `value=` would warn when `degraded` flips after mount), and\n // skip while focused so we never reset the user's caret mid-type.\n useEffect(() => {\n if (!degraded || value === undefined) return;\n const ta = textareaRef.current;\n if (!ta) return;\n const safe = sanitiseHtml(value);\n if (ta.value !== safe && document.activeElement !== ta) {\n ta.value = safe;\n }\n }, [degraded, value]);\n\n /* ---- Imperative handle --------------------------------------- */\n const handle = useMemo<RichTextEditorHandle>(\n () => ({\n getHTML(): string {\n return readCode();\n },\n getText(): string {\n return readCode()\n .replace(/<[^>]*>/g, ' ')\n .replace(/ /gi, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n },\n getMarkdown(): string {\n return '';\n },\n isAiBusy(): boolean {\n return oneShotAbortRef.current !== null;\n },\n setContent(html: string): void {\n const safe = sanitiseHtml(html);\n if (\n dispatchWrite(\n 'source.setCode',\n wrapVariableTokens(safe, variableTokensRef.current),\n )\n ) {\n return;\n }\n if (textareaRef.current) textareaRef.current.value = safe;\n },\n insertAtCursor,\n applyFormat(format): void {\n const command = FORMAT_COMMANDS[format];\n if (command) runCommand(...command);\n },\n focus(): void {\n const R = redactorRef.current;\n if (R) {\n try {\n R(selector, 'editor.focus');\n return;\n } catch {\n /* fall through */\n }\n }\n textareaRef.current?.focus();\n },\n clear(): void {\n if (dispatchWrite('source.setCode', '')) return;\n if (textareaRef.current) textareaRef.current.value = '';\n },\n }),\n [selector, readCode, dispatchWrite, insertAtCursor, runCommand],\n );\n useImperativeHandle(ref, () => handle, [handle]);\n useAgentRegistration(richTextEditorAgent, handle, id);\n\n /* ---- Degraded-mode change handler ---------------------------- */\n const handleDegradedChange = useCallback(\n (event: ChangeEvent<HTMLTextAreaElement>): void => {\n checkVariablesRef.current();\n onChangeRef.current?.({\n html: sanitiseHtml(event.target.value),\n markdown: '',\n });\n },\n [],\n );\n\n // Accessible name for the editing region — a dedicated label, not the\n // placeholder, so the region's name and its placeholder hint don't collide.\n const resolvedLabel = ariaLabel ?? t('editor.regionLabel');\n const resolvedPlaceholder = placeholder ?? t('editor.placeholder');\n\n /* ---- Normalise Redactor's editing-surface ARIA --------------- */\n // Redactor renders the surface as a role=\"presentation\" contenteditable and,\n // while empty, points aria-labelledby at its hidden voice region — invalid\n // ARIA (axe: aria-prohibited-attr, since aria-labelledby can't sit on a\n // presentational node). Promote it to a properly-named textbox and keep it\n // that way as Redactor toggles the placeholder state. Redactor's own kit\n // usages never hit this because they all seed content (no empty placeholder).\n useEffect(() => {\n if (degraded) return undefined;\n const editable = wrapperRef.current?.querySelector('.redactor-in');\n if (!editable) return undefined;\n const normalise = () => {\n if (editable.getAttribute('role') !== 'textbox')\n editable.setAttribute('role', 'textbox');\n if (editable.getAttribute('aria-multiline') !== 'true')\n editable.setAttribute('aria-multiline', 'true');\n if (editable.getAttribute('aria-label') !== resolvedLabel)\n editable.setAttribute('aria-label', resolvedLabel);\n if (editable.hasAttribute('aria-labelledby'))\n editable.removeAttribute('aria-labelledby');\n };\n normalise();\n const observer = new MutationObserver(normalise);\n observer.observe(editable, {\n attributes: true,\n attributeFilter: ['role', 'aria-labelledby'],\n });\n return () => observer.disconnect();\n }, [degraded, resolvedLabel]);\n\n // AI FAB segments — rendered as one pill in this order: dictation · spelling\n // & grammar · auto-format · Alia. The two one-shot actions show a spinner\n // while running; everything else is disabled meanwhile.\n const busy = oneShot !== null;\n // Insert a template variable chip at the caret the toolbar saved. The\n // degraded <textarea> gets the plain token instead of markup.\n const insertVariable = useCallback(\n (token: string): void => {\n if (!VARIABLE_TOKEN.test(token)) return;\n if (degraded) {\n insertAtCursor(`[[${token}]]`, { asHtml: false });\n } else {\n restoreSelection();\n insertHtml(variableHtml(token));\n }\n onVariableInserted?.(token);\n },\n [\n degraded,\n insertAtCursor,\n restoreSelection,\n insertHtml,\n onVariableInserted,\n ],\n );\n\n // The Templates menu captures its target when it opens: picking an item\n // moves focus into the menu, so the selection must be read first.\n const templateTargetRef = useRef<AiTarget | null>(null);\n const [templateNoteEmpty, setTemplateNoteEmpty] = useState(false);\n const [templatesMenuOpen, setTemplatesMenuOpen] = useState(false);\n const handleTemplatesOpenChange = useCallback(\n (open: boolean, source: 'document' | 'selection'): void => {\n setTemplatesMenuOpen(open);\n if (!open) return;\n const target = captureAiTarget(source);\n templateTargetRef.current = target;\n setTemplateNoteEmpty(!target.text.trim());\n },\n [captureAiTarget],\n );\n const pickTemplate = useCallback(\n (template: RichTextEditorAiTemplate): void => {\n const target = templateTargetRef.current ?? captureAiTarget('document');\n templateTargetRef.current = null;\n runTemplate(template, target);\n },\n [captureAiTarget, runTemplate],\n );\n\n // A one-shot pill or bubble button: runs the action, or stops it.\n const oneShotButton = (\n kind: 'proofread' | 'format',\n fn:\n | ((request: RichTextEditorAiActionRequest) => Promise<string>)\n | undefined,\n ): FabSegment | null => {\n if (!fn) return null;\n const running = oneShot === kind;\n return {\n key: kind,\n // While running, the segment becomes a Stop/Cancel button (progress\n // shows on the scrim spinner).\n icon: running ? (\n <Square aria-hidden=\"true\" className=\"ds:size-5 ds:fill-current\" />\n ) : kind === 'proofread' ? (\n <SpellCheck aria-hidden=\"true\" className=\"ds:size-5\" />\n ) : (\n <WandSparkles aria-hidden=\"true\" className=\"ds:size-5\" />\n ),\n label: running\n ? t('common.cancel')\n : kind === 'proofread'\n ? t('editor.ai.proofread', 'Check spelling & grammar')\n : t('editor.ai.autoFormat', 'Auto-format document'),\n onClick: running\n ? cancelOneShot\n : () => requestAiAction(kind, fn, captureAiTarget('document')),\n running,\n };\n };\n\n const fabSegments: FabSegment[] = [];\n if (onDictate) {\n fabSegments.push({\n key: 'dictate',\n icon: isDictating ? (\n <Square aria-hidden=\"true\" className=\"ds:size-5 ds:fill-current\" />\n ) : (\n <Mic aria-hidden=\"true\" className=\"ds:size-5\" />\n ),\n label: isDictating\n ? t('editor.ai.dictateStop')\n : t('editor.ai.dictateStart'),\n onClick: () => handleDictateClick('document'),\n recording: isDictating,\n });\n }\n if (aiTemplates) {\n const running = oneShot === 'template';\n fabSegments.push({\n key: 'templates',\n icon: running ? (\n <Square aria-hidden=\"true\" className=\"ds:size-5 ds:fill-current\" />\n ) : (\n <BookDashed aria-hidden=\"true\" className=\"ds:size-5\" />\n ),\n label: running ? t('common.cancel') : t('editor.ai.templates'),\n onClick: running ? cancelOneShot : undefined,\n running,\n menu: !running,\n });\n }\n const proofreadSegment = oneShotButton('proofread', onProofread);\n if (proofreadSegment) fabSegments.push(proofreadSegment);\n const formatSegment = oneShotButton('format', onAutoFormat);\n if (formatSegment) fabSegments.push(formatSegment);\n if (onRequestAiDraft || renderHelpMeWrite) {\n fabSegments.push({\n key: 'write',\n icon: <PencilSparkles aria-hidden=\"true\" className=\"ds:size-5\" />,\n label: t('editor.ai.helpMeWrite'),\n onClick: () => handleWriteClick('document'),\n });\n }\n\n // The Templates menu, shared by the pill and the selection bubble.\n const renderTemplatesMenu = (\n trigger: ReactNode,\n source: 'document' | 'selection',\n ): ReactNode =>\n aiTemplates ? (\n <AiTemplatesMenu\n side={source === 'document' ? 'top' : 'bottom'}\n templates={aiTemplates.templates}\n onPick={pickTemplate}\n onManage={aiTemplates.onManage}\n noteEmpty={templateNoteEmpty}\n onOpenChange={(open) => handleTemplatesOpenChange(open, source)}\n trigger={trigger}\n />\n ) : null;\n\n const canWrite = Boolean(onRequestAiDraft || renderHelpMeWrite);\n const hasAiActions = Boolean(\n aiTemplates || onProofread || onAutoFormat || canWrite || onDictate,\n );\n const showSelectionToolbar =\n !degraded && !readOnly && (selectionToolbar ?? hasAiActions);\n const getEditorRoot = useCallback(\n (): Element | null =>\n wrapperRef.current?.querySelector('.redactor-in') ?? null,\n [],\n );\n\n return (\n <div\n ref={wrapperRef}\n className={[wrapperVariants(), className].filter(Boolean).join(' ')}\n data-component=\"rich-text-editor\"\n data-component-id={id}\n data-min-height={minHeight}\n >\n {!degraded && !readOnly ? (\n <EditorToolbar\n run={runCommand}\n active={activeFormats}\n preset={toolbar}\n insertHtml={insertHtml}\n insertTable={insertTable}\n saveSelection={saveSelection}\n restoreSelection={restoreSelection}\n getSelectedText={getSelectedText}\n uploadImage={\n imageUploadUrl || onUploadImage ? uploadImage : undefined\n }\n enableColor={plugins?.includes('fontcolor') ?? false}\n enableImage={Boolean(imageUploadUrl || onUploadImage)}\n enableTable={plugins?.includes('table') ?? false}\n showExtensions={showExtensions}\n variables={menuVariables}\n recentVariableTokens={recentVariableTokens}\n insertVariable={insertVariable}\n />\n ) : null}\n <div className=\"ds:relative\" ref={editorAreaRef}>\n <textarea\n ref={textareaRef}\n id={editorId}\n aria-label={resolvedLabel}\n aria-multiline=\"true\"\n aria-busy={busy || undefined}\n placeholder={resolvedPlaceholder}\n onChange={degraded ? handleDegradedChange : undefined}\n readOnly={degraded ? readOnly : undefined}\n className={degraded ? degradedTextareaVariants() : undefined}\n />\n {/* While a one-shot AI action runs, dim + block the editor (it's being\n rewritten) with a centred spinner; the running FAB segment turns\n into a Stop/Cancel button. */}\n {busy ? (\n <div\n aria-hidden=\"true\"\n className=\"ds:absolute ds:inset-0 ds:z-[5] ds:flex ds:items-center ds:justify-center ds:cursor-wait ds:rounded-[var(--radius-md)] ds:bg-[color-mix(in_srgb,var(--background)_40%,transparent)]\"\n >\n <Spinner size=\"lg\" variant=\"prism\" />\n </div>\n ) : null}\n {/* AI affordances — the FAB + Alia popout. Wrapped in a zero-height\n STICKY dock (its only children are absolute) so in a long document\n they ride the viewport's block-end instead of scrolling off at the\n editor's bottom; the FAB/overlay keep their absolute positioning,\n now anchored to this dock. */}\n <div className=\"ds:sticky ds:bottom-0 ds:z-10\">\n {fabSegments.length > 0 ? (\n <div\n ref={pillRef}\n className=\"ds:absolute ds:[inset-block-end:var(--spacing-md)] ds:[inset-inline-end:var(--spacing-md)] ds:z-10\"\n data-ai-sparkle={aiSparkleState.props['data-ai-sparkle']}\n >\n <div className=\"ds:relative ds:flex ds:items-center ds:overflow-hidden ds:rounded-full ds:bg-[var(--primary)] ds:bg-[image:var(--gradient-brand)] ds:shadow-[0_8px_24px_color-mix(in_srgb,var(--primary)_35%,transparent)]\">\n {fabSegments.map((seg, i) => {\n const segmentButton = (\n <button\n type=\"button\"\n onClick={seg.onClick}\n aria-pressed={seg.recording || undefined}\n aria-busy={seg.running || undefined}\n aria-haspopup={seg.menu ? 'menu' : undefined}\n data-component-part={`ai-${seg.key}`}\n disabled={(busy && !seg.running) || undefined}\n aria-label={seg.label}\n className={\n seg.recording ? fabSegmentRecording : fabSegmentIdle\n }\n >\n {seg.icon}\n </button>\n );\n return (\n <Fragment key={seg.key}>\n {i > 0 ? (\n <span\n aria-hidden=\"true\"\n className=\"ds:self-stretch ds:[inline-size:var(--border-width-sm)] ds:bg-[color-mix(in_srgb,var(--primary-foreground)_35%,transparent)]\"\n />\n ) : null}\n {seg.menu\n ? renderTemplatesMenu(segmentButton, 'document')\n : segmentButton}\n </Fragment>\n );\n })}\n {/* Sparkle: a light sweep across the pill. Decorative. */}\n {aiSparkleState.state ? (\n <span\n aria-hidden=\"true\"\n className={`ds:pointer-events-none ds:absolute ds:inset-0 ds:-translate-x-full ds:bg-[linear-gradient(90deg,transparent,color-mix(in_srgb,var(--primary-foreground)_45%,transparent),transparent)] ${aiSparkleState.props.className}`}\n />\n ) : null}\n </div>\n <AiSparkle state={aiSparkleState.state} />\n </div>\n ) : null}\n {renderHelpMeWrite ? (\n renderHelpMeWrite({\n open: aiOpen && !aiBlocked,\n onClose: () => {\n setAiOpen(false);\n setAiCreditsExhausted(false);\n },\n selectionText: aiSelectionText,\n scope: aiScope,\n creditsExhausted: aiCreditsExhausted,\n getHTML: handle.getHTML,\n getText: handle.getText,\n insertAtSelection: (html: string): void => {\n if (aiRangeRef.current) {\n lastRangeRef.current = aiRangeRef.current.cloneRange();\n }\n restoreSelection();\n insertAtCursor(html, { asHtml: true });\n },\n insertAfterSelection: (html: string): void => {\n const range = aiRangeRef.current ?? lastRangeRef.current;\n if (range) {\n const after = range.cloneRange();\n after.collapse(false);\n lastRangeRef.current = after;\n }\n restoreSelection();\n insertAtCursor(html, { asHtml: true });\n },\n setContent: handle.setContent,\n onDictate,\n privacyNotice: consentPrivacyNotice,\n })\n ) : onRequestAiDraft ? (\n <HelpMeWriteOverlay\n open={aiOpen && !aiBlocked}\n onClose={() => setAiOpen(false)}\n onRequestAiDraft={onRequestAiDraft}\n onInsert={(draft) => {\n // Restore the caret saved when the FAB opened the overlay, so\n // the draft lands where the user was, not at the doc start.\n restoreSelection();\n insertAtCursor(draft, { asHtml: aiDraftFormat !== 'text' });\n }}\n previewAsHtml={aiDraftFormat !== 'text'}\n privacyNotice={consentPrivacyNotice}\n onDictate={onDictate}\n />\n ) : null}\n {/* AI consent gate — takes the SAME docked slot as the\n Help-me-write overlay (and stands in for the mic's own\n affordance, which has no overlay of its own) whenever\n `aiConsent` is present and not yet granted. Never mounted\n alongside HelpMeWriteOverlay: `aiOpen` is only ever set once\n `aiConsent.granted` is true (or `aiConsent` is absent). */}\n {aiConsent ? (\n <EditorOverlay\n open={aiGateReason !== null}\n onClose={closeAiGate}\n ariaLabel={t(\n 'editor.ai.consentRegionLabel',\n 'AI assistance consent for this document',\n )}\n // No `title` header: that would put the header's close button\n // BEFORE the banner's own Grant checkbox in DOM order, and\n // EditorOverlay auto-focuses the first focusable descendant —\n // the checkbox (or the dialog itself, in the no-permission\n // state) must win that race, not the close affordance. The\n // close control lives in the footer instead, AFTER the\n // banner, so it never precedes it.\n footer={\n <Button intent=\"ghost\" size=\"sm\" onClick={closeAiGate}>\n {t('common.close')}\n </Button>\n }\n >\n <AiConsentBanner\n granted={aiConsent.granted}\n grantedAt={aiConsent.grantedAt}\n grantedBy={aiConsent.grantedBy}\n // No handler, no Grant control: never a dead button.\n canGrant={\n (aiConsent.canGrant ?? true) &&\n aiConsent.onGrant !== undefined\n }\n pending={grantPending}\n onGrantConsent={handleGrantConsent}\n headingLevel={aiConsentHeadingLevel}\n aria-label={t(\n 'editor.ai.consentRegionLabel',\n 'AI assistance consent for this document',\n )}\n />\n </EditorOverlay>\n ) : null}\n </div>\n {/* Rendered LAST inside the positioned container (after the Redactor-\n managed textarea/box) so its conditional mount never asks React to\n insertBefore the textarea, which Redactor moves into its own box\n (that would throw \"node ... is not a child of this node\"). */}\n {!degraded && !readOnly && (plugins?.includes('table') ?? false) ? (\n <TableFloatingToolbar\n active={activeFormats}\n run={runCommand}\n areaRef={editorAreaRef}\n getActiveTableEl={getActiveTableEl}\n enableColor={plugins?.includes('fontcolor') ?? false}\n saveTableCell={saveTableCell}\n applyTableBackground={applyTableBackground}\n />\n ) : null}\n {/* Image wrap / align / resize — appears when an image is selected.\n Works on any embedded image, so it's gated only on edit mode (not\n on a plugin). Rendered after the table bar for the same reason it\n is: never inserted before the Redactor-managed textarea. */}\n {!degraded && !readOnly ? (\n <ImageFloatingToolbar\n areaRef={editorAreaRef}\n activeImageEl={activeImageEl}\n applyImageClass={applyImageClass}\n setImageWidth={setImageWidth}\n />\n ) : null}\n {/* Selection bubble: formats + AI actions over selected text.\n Rendered after the other floating bars for the same reason. */}\n {showSelectionToolbar ? (\n <SelectionFloatingToolbar\n active={activeFormats}\n run={runCommand}\n areaRef={editorAreaRef}\n getEditorRoot={getEditorRoot}\n suppressed={busy || aiOpen || aiGateReason !== null}\n holdOpen={templatesMenuOpen}\n >\n {hasAiActions ? (\n <>\n {/* Dictating over a selection replaces it. */}\n {onDictate ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n data-component-part=\"selection-ai-dictate\"\n onMouseDown={keepSelectionOnPress}\n icon={isDictating ? <Square /> : <Mic />}\n aria-pressed={isDictating}\n tooltip={\n isDictating\n ? t('editor.ai.dictateStop')\n : t('editor.ai.dictateStart')\n }\n onClick={() => handleDictateClick('selection')}\n />\n ) : null}\n {aiTemplates\n ? renderTemplatesMenu(\n <Button\n size=\"sm\"\n intent=\"ghost\"\n data-component-part=\"selection-ai-templates\"\n onMouseDown={keepSelectionOnPress}\n startIcon={<BookDashed />}\n endIcon={<ChevronDown />}\n >\n {t('editor.ai.templates')}\n </Button>,\n 'selection',\n )\n : null}\n {onProofread ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n data-component-part=\"selection-ai-proofread\"\n onMouseDown={keepSelectionOnPress}\n icon={<SpellCheck />}\n tooltip={t('editor.ai.proofread')}\n onClick={() =>\n requestAiAction(\n 'proofread',\n onProofread,\n captureAiTarget('selection'),\n )\n }\n />\n ) : null}\n {onAutoFormat ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n data-component-part=\"selection-ai-format\"\n onMouseDown={keepSelectionOnPress}\n icon={<WandSparkles />}\n tooltip={t('editor.ai.autoFormat')}\n onClick={() =>\n requestAiAction(\n 'format',\n onAutoFormat,\n captureAiTarget('selection'),\n )\n }\n />\n ) : null}\n {canWrite ? (\n <IconButton\n size=\"sm\"\n intent=\"ghost\"\n data-component-part=\"selection-ai-write\"\n onMouseDown={keepSelectionOnPress}\n icon={<PencilSparkles />}\n tooltip={t('editor.ai.helpMeWrite')}\n onClick={() => handleWriteClick('selection')}\n />\n ) : null}\n </>\n ) : null}\n </SelectionFloatingToolbar>\n ) : null}\n {typeahead ? (\n <div\n className={typeaheadWrapperClass}\n // eslint-disable-next-line react/forbid-dom-props -- runtime-computed caret position injected via CSS custom properties (23-constraints §Runtime-computed dimensions); the inset rules live in the class\n style={{\n ['--rte-typeahead-x' as string]: `${typeahead.left}px`,\n ['--rte-typeahead-y' as string]: `${typeahead.top}px`,\n }}\n >\n <VariablesMenu\n ref={caretMenuRef}\n id={typeaheadId}\n variables={menuVariables}\n recentTokens={recentVariableTokens}\n query={typeahead.query}\n onQueryChange={handleCaretQueryChange}\n onSelect={handleCaretVariableSelect}\n onClose={handleCaretVariableClose}\n searchFocusable={false}\n onActiveDescendantChange={setCaretActiveDescendant}\n />\n </div>\n ) : null}\n </div>\n {onDictate ? (\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {dictationAnnouncement}\n </p>\n ) : null}\n {invalidVariables.length > 0 ? (\n <p\n id={`${editorId}-variables-error`}\n role=\"alert\"\n className=\"ds:m-0 ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--destructive)]\"\n >\n {t('editor.variableInvalid', {\n tokens: invalidVariables\n .map((token) => `[[${token}]]`)\n .join(', '),\n })}\n </p>\n ) : null}\n {onDictate && dictationErrored ? (\n <p\n role=\"alert\"\n className=\"ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--destructive)]\"\n >\n {t('editor.ai.dictationError')}\n </p>\n ) : null}\n {aiTemplates || onProofread || onAutoFormat ? (\n <p className=\"ds:sr-only\" role=\"status\" aria-live=\"polite\">\n {aiAnnouncement}\n </p>\n ) : null}\n {aiActionErrored || aiActionStale ? (\n <p\n role=\"alert\"\n className=\"ds:text-[length:var(--font-size-sm)] ds:text-[color:var(--destructive)]\"\n >\n {aiActionStale\n ? t('editor.ai.actionStale')\n : t('editor.ai.actionError')}\n </p>\n ) : null}\n </div>\n );\n },\n);\n\nRichTextEditor.displayName = 'RichTextEditor';\n\nexport { wrapperVariants };\n"],"names":["__iconNode","Baseline","createLucideIcon","BetweenHorizontalEnd","BetweenHorizontalStart","BetweenVerticalEnd","BetweenVerticalStart","Bold","BookDashed","Braces","Columns2","Heading2","Heading3","Italic","Link","ListOrdered","List","PaintBucket","PaintRoller","Palette","PanelLeft","PanelRight","PanelTopDashed","PanelTop","PencilSparkles","Pilcrow","Quote","Redo2","Rows2","SpellCheck","Strikethrough","Table","TextAlignCenter","TextAlignEnd","TextAlignStart","Underline","WandSparkles","Wrench","richTextEditorAgent","handle","args","RECORDING_MIC","ACTION_SIZE","noticeClass","errorClass","previewClass","joinWith","base","extra","HelpMeWriteOverlay","open","onClose","onRequestAiDraft","onInsert","previewAsHtml","privacyNotice","onDictate","t","useTranslation","promptId","useId","errorId","prompt","setPrompt","useState","loading","setLoading","errored","setErrored","draft","setDraft","abortRef","useRef","isDictating","setIsDictating","interim","setInterim","dictationAnnouncement","setDictationAnnouncement","dictateAbortRef","stopDictation","useCallback","_a","startDictation","controller","text","trimmed","p","toggleDictation","useEffect","_b","generate","result","err","insert","hasDraft","fieldValue","jsx","EditorOverlay","jsxs","IconButton","X","SafeHtml","RotateCcw","Check","Fragment","TextArea","event","Square","Mic","Spinner","Send","ITEMS","Undo2","FORMAT_OPTIONS","PRESETS","TABLE_OPS","Trash2","TABLE_GRID","toolbarClass","cva","toolbarRowClass","dividerClass","fieldLabelClass","esc","value","VariableMenu","variables","recentVariableTokens","insertVariable","saveSelection","setOpen","query","setQuery","triggerRef","pickedRef","menuVariables","RadixPopover","next","VariablesMenu","variable","StyleMenu","run","active","onTriggerDown","current","o","DropdownMenu","Button","ChevronDown","opt","LinkDialog","insertHtml","restoreSelection","getSelectedText","url","setUrl","setText","newTab","setNewTab","urlId","textId","reset","handleInsert","href","label","tab","html","Dialog","LinkIcon","TextInput","Checkbox","checked","ImageDialog","uploadImage","src","setSrc","alt","setAlt","srcId","altId","insertImage","altText","ImageIcon","FileUpload","file","signal","ColourControl","colour","setColour","applyColour","hex","removeColour","Popover","ColorPicker","HighlightControl","applyHighlight","removeHighlight","Highlighter","buildTable","rows","cols","cells","TableControl","insertTable","hover","setHover","inTable","TableIcon","op","_","i","r","c","on","TABLE_OP_BY_ID","tableFloatClass","TABLE_BG_SEED","TableBgColourControl","scope","icon","onOpenChange","saveTableCell","applyTableBackground","TableFloatingToolbar","areaRef","getActiveTableEl","enableColor","pos","setPos","colourOpenCount","colourOpen","setColourOpen","handleColourOpenChange","recompute","area","table","a","rtl","top","center","ro","groups","TooltipProvider","group","gi","opId","IMAGE_FLOW_CLASSES","IMAGE_ALIGN_CLASSES","selectedImageClass","el","imageWidthPercent","img","box","boxWidth","imgWidth","IMG_MAX_PCT","IMG_MIN_PCT","IMG_STEP","IMG_STEP_COARSE","clampPct","pct","IMAGE_FLOW_OPS","IMAGE_ALIGN_OPS","IMAGE_CORNERS","imageFrameClass","imageHandleClass","imageBarClass","ImageFloatingToolbar","applyImageClass","setImageWidth","dragRef","start","barTop","editable","mo","onHandlePointerDown","corner","onHandlePointerMove","drag","deltaPct","onHandlePointerEnd","onHandleKeyDown","step","flowActive","alignActive","widthText","isActive","AiTemplatesMenu","templates","onPick","onManage","noteEmpty","trigger","side","hintId","template","Plus","Settings","selectionFloatClass","SELECTION_FORMATS","SelectionFloatingToolbar","getEditorRoot","suppressed","holdOpen","children","barRef","holdOpenRef","dragging","frame","remeasured","dismissed","root","sel","range","above","width","centre","half","schedule","onPointerDown","onPointerUp","onKeyDown","onSelectionChange","id","item","EditorToolbar","preset","enableImage","enableTable","showExtensions","keepSelection","has","btn","Divider","styleGroup","historyNodes","inlineNodes","hasPrimary","listsNodes","insertNodes","extensionNodes","secondarySubgroups","hasSecondary","renderSecondary","leadingDivider","index","Ellipsis","sanitiseHtml","input","sanitiseShared","normalizeEditorValue","normalized","contentWithoutTags","withLazyImages","VARIABLE_TOKEN","VARIABLE_IN_TEXT","INVALID_VARIABLE_CLASS","INVALID_CLASS_IN_HTML","stripEditorMarkers","tag","variableTokensIn","match","isCreditsExhausted","isAbortError","fragmentHtml","fragment","holder","htmlText","plainText","caretTextOffset","before","placeCaretAtTextOffset","offset","walker","seen","node","chip","variableHtml","token","wrapVariableTokens","tokens","doc","targets","changed","frag","last","span","extractUploadedUrl","data","rec","fromNode","resolveRedactor","injected","w","FORMAT_COMMANDS","REDACTOR_LANG","toRedactorLang","locale","wrapperVariants","typeaheadWrapperClass","degradedTextareaVariants","fabSegmentBase","fabSegmentIdle","fabSegmentRecording","RichTextEditor","forwardRef","defaultValue","onChange","toolbar","placeholder","readOnly","ariaLabel","minHeight","className","redactor","options","plugins","lang","imageUploadUrl","onUploadImage","aiDraftFormat","aiPrivacyNotice","aiConsent","aiConsentHeadingLevel","onProofread","onAutoFormat","aiTemplates","onAiApplied","aiSparkle","selectionToolbar","onVariableInserted","validateVariable","onVariableValidityChange","renderHelpMeWrite","onAiCreditsExhausted","ref","i18n","rawId","editorId","useMemo","selector","textareaRef","redactorRef","skipNextPropSyncRef","readOnlyRef","wrapperRef","editorAreaRef","degraded","setDegraded","aiOpen","setAiOpen","aiSelectionText","setAiSelectionText","aiScope","setAiScope","aiCreditsExhausted","setAiCreditsExhausted","onAiCreditsExhaustedRef","renderHelpMeWriteRef","aiRangeRef","variableTokens","variableLabels","variableTokensRef","v","validateRef","hasValidator","isVariableValid","variablesEnabled","invalidVariables","setInvalidVariables","onValidityRef","checkVariablesRef","activeFormats","setActiveFormats","activeImageElRef","activeImageEl","setActiveImageEl","selectImage","debounceRef","lastHostHtmlRef","onChangeRef","onKeyDownRef","initialContentRef","raw","readCode","R","code","prev","invalid","title","target","validityReportedRef","dispatchWrite","command","wasReadOnly","insertAtCursor","content","opts","asHtml","payload","ta","end","caret","lastRangeRef","updateActiveFormats","selection","block","anchorEl","runCommand","wrapper","SHORTCUT_COMMANDS","onKeyDownCapture","typeahead","setTypeahead","typeaheadAnchorRef","typeaheadId","caretMenuRef","caretActiveDescendant","setCaretActiveDescendant","closeTypeahead","insertVariableAt","anchor","onInput","startContainer","startOffset","full","rect","onFocusOut","handleCaretVariableSelect","handleCaretVariableClose","handleCaretQueryChange","lastCellRef","getActiveCellEl","cell","n","onClick","list","form","res","interimRef","dictationErrored","setDictationErrored","clearInterim","showInterim","followsText","aiBlocked","dictationRangeRef","replacing","lead","aiGateReason","setAiGateReason","resumeAfterGrantRef","pendingAiActionRef","localGrantPending","setLocalGrantPending","grantPending","grantRequestedRef","closeAiGate","handleGrantConsent","prevGrantedRef","wasGranted","reason","requestedHere","pendingAction","handleDictateClick","handleWriteClick","saved","onSelection","consentPrivacyNotice","oneShot","setOneShot","aiActionErrored","setAiActionErrored","aiActionStale","setAiActionStale","aiAnnouncement","setAiAnnouncement","lastOneShotRef","aiSparkleState","useAiSparkle","startAiSparkle","landAiSparkle","resetAiSparkle","oneShotAbortRef","onAiAppliedRef","keepSelectionOnPress","pushUndoState","app","aiLockedRef","setAiLock","locked","writeDocument","safe","captureAiTarget","prefer","runAiAction","kind","fn","previousHtml","requestAiAction","runTemplate","request","cancelOneShot","pillRef","part","kitDefaults","imageUploadOption","consumerCallbacks","finalOptions","rewrite","displayRewriteRef","wrappedTokensRef","wrapped","after","format","useImperativeHandle","useAgentRegistration","handleDegradedChange","resolvedLabel","resolvedPlaceholder","normalise","observer","busy","templateTargetRef","templateNoteEmpty","setTemplateNoteEmpty","templatesMenuOpen","setTemplatesMenuOpen","handleTemplatesOpenChange","source","pickTemplate","oneShotButton","running","fabSegments","proofreadSegment","formatSegment","renderTemplatesMenu","canWrite","hasAiActions","showSelectionToolbar","seg","segmentButton","AiSparkle","AiConsentBanner"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]}
|