@puzzle-ui/ui 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +70 -70
  2. package/dist/components/actions/button/button.css +5 -2
  3. package/dist/components/actions/button-group/button-group.css +16 -17
  4. package/dist/components/data-display/badge/badge.css +15 -2
  5. package/dist/components/data-display/badge/index.cjs +13 -2
  6. package/dist/components/data-display/badge/index.cjs.map +1 -1
  7. package/dist/components/data-display/badge/index.d.cts +7 -2
  8. package/dist/components/data-display/badge/index.d.ts +7 -2
  9. package/dist/components/data-display/badge/index.js +13 -2
  10. package/dist/components/data-display/badge/index.js.map +1 -1
  11. package/dist/components/data-display/empty-state/empty-state.css +128 -0
  12. package/dist/components/data-display/empty-state/empty-state.utils.cjs +6 -0
  13. package/dist/components/data-display/empty-state/empty-state.utils.cjs.map +1 -0
  14. package/dist/components/data-display/empty-state/empty-state.utils.js +6 -0
  15. package/dist/components/data-display/empty-state/empty-state.utils.js.map +1 -0
  16. package/dist/components/data-display/empty-state/index.cjs +49 -0
  17. package/dist/components/data-display/empty-state/index.cjs.map +1 -0
  18. package/dist/components/data-display/empty-state/index.d.cts +19 -0
  19. package/dist/components/data-display/empty-state/index.d.ts +19 -0
  20. package/dist/components/data-display/empty-state/index.js +44 -0
  21. package/dist/components/data-display/empty-state/index.js.map +1 -0
  22. package/dist/components/data-display/rating/index.cjs +84 -0
  23. package/dist/components/data-display/rating/index.cjs.map +1 -0
  24. package/dist/components/data-display/rating/index.d.cts +3 -0
  25. package/dist/components/data-display/rating/index.d.ts +3 -0
  26. package/dist/components/data-display/rating/index.js +84 -0
  27. package/dist/components/data-display/rating/index.js.map +1 -0
  28. package/dist/components/data-display/rating/rating.css +72 -0
  29. package/dist/components/data-display/rating/rating.types.d.cts +15 -0
  30. package/dist/components/data-display/rating/rating.types.d.ts +15 -0
  31. package/dist/components/data-display/rating/rating.utils.cjs +27 -0
  32. package/dist/components/data-display/rating/rating.utils.cjs.map +1 -0
  33. package/dist/components/data-display/rating/rating.utils.js +25 -0
  34. package/dist/components/data-display/rating/rating.utils.js.map +1 -0
  35. package/dist/components/editors/text-editor/editor.cjs.map +1 -1
  36. package/dist/components/editors/text-editor/editor.js.map +1 -1
  37. package/dist/components/editors/text-editor/text-document.cjs.map +1 -1
  38. package/dist/components/editors/text-editor/text-document.js.map +1 -1
  39. package/dist/components/editors/text-editor/text-parser.cjs.map +1 -1
  40. package/dist/components/editors/text-editor/text-parser.js.map +1 -1
  41. package/dist/components/editors/text-editor/text-renderer.cjs.map +1 -1
  42. package/dist/components/editors/text-editor/text-renderer.js.map +1 -1
  43. package/dist/components/forms/autocomplete/index.cjs.map +1 -1
  44. package/dist/components/forms/autocomplete/index.js.map +1 -1
  45. package/dist/components/forms/checkbox/checkbox.css +2 -10
  46. package/dist/components/forms/color-picker/color-picker.css +351 -0
  47. package/dist/components/forms/color-picker/color-picker.types.d.cts +25 -0
  48. package/dist/components/forms/color-picker/color-picker.types.d.ts +25 -0
  49. package/dist/components/forms/color-picker/color-picker.utils.cjs +116 -0
  50. package/dist/components/forms/color-picker/color-picker.utils.cjs.map +1 -0
  51. package/dist/components/forms/color-picker/color-picker.utils.js +109 -0
  52. package/dist/components/forms/color-picker/color-picker.utils.js.map +1 -0
  53. package/dist/components/forms/color-picker/index.cjs +340 -0
  54. package/dist/components/forms/color-picker/index.cjs.map +1 -0
  55. package/dist/components/forms/color-picker/index.d.cts +3 -0
  56. package/dist/components/forms/color-picker/index.d.ts +3 -0
  57. package/dist/components/forms/color-picker/index.js +340 -0
  58. package/dist/components/forms/color-picker/index.js.map +1 -0
  59. package/dist/components/forms/file-upload/file-upload.utils.cjs.map +1 -1
  60. package/dist/components/forms/file-upload/file-upload.utils.js.map +1 -1
  61. package/dist/components/forms/input/number-input.js +5 -5
  62. package/dist/components/forms/input/number-input.js.map +1 -1
  63. package/dist/components/forms/input-group/index.d.cts +3 -0
  64. package/dist/components/forms/input-group/index.d.ts +3 -0
  65. package/dist/components/forms/input-group/input-group.cjs +18 -0
  66. package/dist/components/forms/input-group/input-group.cjs.map +1 -0
  67. package/dist/components/forms/input-group/input-group.css +62 -0
  68. package/dist/components/forms/input-group/input-group.d.cts +7 -0
  69. package/dist/components/forms/input-group/input-group.d.ts +7 -0
  70. package/dist/components/forms/input-group/input-group.js +18 -0
  71. package/dist/components/forms/input-group/input-group.js.map +1 -0
  72. package/dist/components/forms/input-group/input-group.types.d.cts +7 -0
  73. package/dist/components/forms/input-group/input-group.types.d.ts +7 -0
  74. package/dist/components/forms/input-group/input-group.utils.cjs +5 -0
  75. package/dist/components/forms/input-group/input-group.utils.cjs.map +1 -0
  76. package/dist/components/forms/input-group/input-group.utils.js +5 -0
  77. package/dist/components/forms/input-group/input-group.utils.js.map +1 -0
  78. package/dist/components/forms/radio-group/index.d.cts +2 -1
  79. package/dist/components/forms/radio-group/index.d.ts +2 -1
  80. package/dist/components/forms/select/index.cjs.map +1 -1
  81. package/dist/components/forms/select/index.js.map +1 -1
  82. package/dist/components/forms/slider/index.cjs +1 -1
  83. package/dist/components/forms/slider/index.cjs.map +1 -1
  84. package/dist/components/forms/slider/index.js +1 -1
  85. package/dist/components/forms/slider/index.js.map +1 -1
  86. package/dist/components/forms/stepper/index.d.cts +4 -2
  87. package/dist/components/forms/stepper/index.d.ts +4 -2
  88. package/dist/components/forms/time-picker/index.cjs +108 -0
  89. package/dist/components/forms/time-picker/index.cjs.map +1 -0
  90. package/dist/components/forms/time-picker/index.d.cts +3 -0
  91. package/dist/components/forms/time-picker/index.d.ts +3 -0
  92. package/dist/components/forms/time-picker/index.js +108 -0
  93. package/dist/components/forms/time-picker/index.js.map +1 -0
  94. package/dist/components/forms/time-picker/time-picker.css +166 -0
  95. package/dist/components/forms/time-picker/time-picker.types.d.cts +34 -0
  96. package/dist/components/forms/time-picker/time-picker.types.d.ts +34 -0
  97. package/dist/components/forms/time-picker/time-picker.utils.cjs +25 -0
  98. package/dist/components/forms/time-picker/time-picker.utils.cjs.map +1 -0
  99. package/dist/components/forms/time-picker/time-picker.utils.js +24 -0
  100. package/dist/components/forms/time-picker/time-picker.utils.js.map +1 -0
  101. package/dist/components/forms/token-input/index.cjs +189 -0
  102. package/dist/components/forms/token-input/index.cjs.map +1 -0
  103. package/dist/components/forms/token-input/index.d.cts +3 -0
  104. package/dist/components/forms/token-input/index.d.ts +3 -0
  105. package/dist/components/forms/token-input/index.js +189 -0
  106. package/dist/components/forms/token-input/index.js.map +1 -0
  107. package/dist/components/forms/token-input/token-input.css +145 -0
  108. package/dist/components/forms/token-input/token-input.types.d.cts +48 -0
  109. package/dist/components/forms/token-input/token-input.types.d.ts +48 -0
  110. package/dist/components/forms/token-input/token-input.utils.cjs +30 -0
  111. package/dist/components/forms/token-input/token-input.utils.cjs.map +1 -0
  112. package/dist/components/forms/token-input/token-input.utils.js +24 -0
  113. package/dist/components/forms/token-input/token-input.utils.js.map +1 -0
  114. package/dist/components/layout/aspect-ratio/aspect-ratio.css +14 -0
  115. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs +11 -0
  116. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs.map +1 -0
  117. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js +11 -0
  118. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js.map +1 -0
  119. package/dist/components/layout/aspect-ratio/index.cjs +16 -0
  120. package/dist/components/layout/aspect-ratio/index.cjs.map +1 -0
  121. package/dist/components/layout/aspect-ratio/index.d.cts +11 -0
  122. package/dist/components/layout/aspect-ratio/index.d.ts +11 -0
  123. package/dist/components/layout/aspect-ratio/index.js +16 -0
  124. package/dist/components/layout/aspect-ratio/index.js.map +1 -0
  125. package/dist/components/layout/container/container.css +1 -0
  126. package/dist/components/layout/page-layout/page-layout.css +1 -0
  127. package/dist/components/layout/resizable-panels/index.cjs +1 -1
  128. package/dist/components/layout/resizable-panels/index.cjs.map +1 -1
  129. package/dist/components/layout/resizable-panels/index.js +1 -1
  130. package/dist/components/layout/resizable-panels/index.js.map +1 -1
  131. package/dist/components/layout/resizable-panels/resizable-panels.utils.cjs.map +1 -1
  132. package/dist/components/layout/resizable-panels/resizable-panels.utils.js.map +1 -1
  133. package/dist/components/layout/scroll-area/index.cjs +27 -0
  134. package/dist/components/layout/scroll-area/index.cjs.map +1 -0
  135. package/dist/components/layout/scroll-area/index.d.cts +15 -0
  136. package/dist/components/layout/scroll-area/index.d.ts +15 -0
  137. package/dist/components/layout/scroll-area/index.js +27 -0
  138. package/dist/components/layout/scroll-area/index.js.map +1 -0
  139. package/dist/components/layout/scroll-area/scroll-area.css +25 -0
  140. package/dist/components/layout/scroll-area/scroll-area.utils.cjs +8 -0
  141. package/dist/components/layout/scroll-area/scroll-area.utils.cjs.map +1 -0
  142. package/dist/components/layout/scroll-area/scroll-area.utils.d.cts +2 -0
  143. package/dist/components/layout/scroll-area/scroll-area.utils.d.ts +2 -0
  144. package/dist/components/layout/scroll-area/scroll-area.utils.js +8 -0
  145. package/dist/components/layout/scroll-area/scroll-area.utils.js.map +1 -0
  146. package/dist/components/layout/section/index.cjs +10 -4
  147. package/dist/components/layout/section/index.cjs.map +1 -1
  148. package/dist/components/layout/section/index.d.cts +1 -1
  149. package/dist/components/layout/section/index.d.ts +1 -1
  150. package/dist/components/layout/section/index.js +11 -5
  151. package/dist/components/layout/section/index.js.map +1 -1
  152. package/dist/components/layout/section/section.css +9 -3
  153. package/dist/components/layout/section/types.d.cts +5 -5
  154. package/dist/components/layout/section/types.d.ts +5 -5
  155. package/dist/components/layout/separator/index.cjs +18 -0
  156. package/dist/components/layout/separator/index.cjs.map +1 -0
  157. package/dist/components/layout/separator/index.d.cts +17 -0
  158. package/dist/components/layout/separator/index.d.ts +17 -0
  159. package/dist/components/layout/separator/index.js +18 -0
  160. package/dist/components/layout/separator/index.js.map +1 -0
  161. package/dist/components/layout/separator/separator.css +15 -0
  162. package/dist/components/layout/separator/separator.utils.cjs +11 -0
  163. package/dist/components/layout/separator/separator.utils.cjs.map +1 -0
  164. package/dist/components/layout/separator/separator.utils.d.cts +2 -0
  165. package/dist/components/layout/separator/separator.utils.d.ts +2 -0
  166. package/dist/components/layout/separator/separator.utils.js +11 -0
  167. package/dist/components/layout/separator/separator.utils.js.map +1 -0
  168. package/dist/components/layout/stack/index.cjs +18 -2
  169. package/dist/components/layout/stack/index.cjs.map +1 -1
  170. package/dist/components/layout/stack/index.d.cts +8 -6
  171. package/dist/components/layout/stack/index.d.ts +8 -6
  172. package/dist/components/layout/stack/index.js +18 -2
  173. package/dist/components/layout/stack/index.js.map +1 -1
  174. package/dist/components/layout/stack/stack.css +118 -138
  175. package/dist/components/navigation/accordion/index.cjs.map +1 -1
  176. package/dist/components/navigation/accordion/index.js.map +1 -1
  177. package/dist/components/navigation/carousel/index.cjs +5 -2
  178. package/dist/components/navigation/carousel/index.cjs.map +1 -1
  179. package/dist/components/navigation/carousel/index.js +5 -2
  180. package/dist/components/navigation/carousel/index.js.map +1 -1
  181. package/dist/components/navigation/pagination/index.cjs +146 -0
  182. package/dist/components/navigation/pagination/index.cjs.map +1 -0
  183. package/dist/components/navigation/pagination/index.d.cts +3 -0
  184. package/dist/components/navigation/pagination/index.d.ts +3 -0
  185. package/dist/components/navigation/pagination/index.js +146 -0
  186. package/dist/components/navigation/pagination/index.js.map +1 -0
  187. package/dist/components/navigation/pagination/pagination.css +134 -0
  188. package/dist/components/navigation/pagination/pagination.types.d.cts +38 -0
  189. package/dist/components/navigation/pagination/pagination.types.d.ts +38 -0
  190. package/dist/components/navigation/pagination/pagination.utils.cjs +54 -0
  191. package/dist/components/navigation/pagination/pagination.utils.cjs.map +1 -0
  192. package/dist/components/navigation/pagination/pagination.utils.js +53 -0
  193. package/dist/components/navigation/pagination/pagination.utils.js.map +1 -0
  194. package/dist/components/navigation/tabs/index.d.cts +3 -2
  195. package/dist/components/navigation/tabs/index.d.ts +3 -2
  196. package/dist/components/navigation/tree-view/index.cjs.map +1 -1
  197. package/dist/components/navigation/tree-view/index.js.map +1 -1
  198. package/dist/components/overlays/context-menu/context-menu.css +151 -0
  199. package/dist/components/overlays/context-menu/context-menu.types.d.cts +69 -0
  200. package/dist/components/overlays/context-menu/context-menu.types.d.ts +69 -0
  201. package/dist/components/overlays/context-menu/context-menu.utils.cjs +46 -0
  202. package/dist/components/overlays/context-menu/context-menu.utils.cjs.map +1 -0
  203. package/dist/components/overlays/context-menu/context-menu.utils.js +40 -0
  204. package/dist/components/overlays/context-menu/context-menu.utils.js.map +1 -0
  205. package/dist/components/overlays/context-menu/index.cjs +830 -0
  206. package/dist/components/overlays/context-menu/index.cjs.map +1 -0
  207. package/dist/components/overlays/context-menu/index.d.cts +42 -0
  208. package/dist/components/overlays/context-menu/index.d.ts +42 -0
  209. package/dist/components/overlays/context-menu/index.js +818 -0
  210. package/dist/components/overlays/context-menu/index.js.map +1 -0
  211. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.cjs.map +1 -1
  212. package/dist/components/overlays/dropdown-menu/dropdown-menu-content.js.map +1 -1
  213. package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.cjs.map +1 -1
  214. package/dist/components/overlays/dropdown-menu/dropdown-menu.utils.js.map +1 -1
  215. package/dist/components/typography/heading.cjs +6 -2
  216. package/dist/components/typography/heading.cjs.map +1 -1
  217. package/dist/components/typography/heading.d.cts +3 -2
  218. package/dist/components/typography/heading.d.ts +3 -2
  219. package/dist/components/typography/heading.js +6 -2
  220. package/dist/components/typography/heading.js.map +1 -1
  221. package/dist/components/typography/text.cjs +6 -2
  222. package/dist/components/typography/text.cjs.map +1 -1
  223. package/dist/components/typography/text.d.cts +3 -2
  224. package/dist/components/typography/text.d.ts +3 -2
  225. package/dist/components/typography/text.js +6 -2
  226. package/dist/components/typography/text.js.map +1 -1
  227. package/dist/components/utilities/preview/index.cjs +89 -21
  228. package/dist/components/utilities/preview/index.cjs.map +1 -1
  229. package/dist/components/utilities/preview/index.d.cts +6 -2
  230. package/dist/components/utilities/preview/index.d.ts +6 -2
  231. package/dist/components/utilities/preview/index.js +89 -21
  232. package/dist/components/utilities/preview/index.js.map +1 -1
  233. package/dist/components/utilities/preview/preview.css +26 -11
  234. package/dist/components/utilities/transition/index.d.cts +1 -1
  235. package/dist/components/utilities/transition/index.d.ts +1 -1
  236. package/dist/index.cjs +136 -97
  237. package/dist/index.d.cts +23 -2
  238. package/dist/index.d.ts +23 -2
  239. package/dist/index.js +12 -1
  240. package/package.json +7 -6
@@ -1 +1 @@
1
- {"version":3,"file":"editor.cjs","names":["getOrderedSelection","isCollapsedSelection","forwardRef","useState","normalizeTextDocument","createTextDocument","createTextSelection","useRef","useCallback","applyMark","setTextVariant","setTextAlign","getTextAlign","setListType","getListType","insertDocumentAtSelection","insertTextAtSelection","parseHtmlToDocument","parseMarkdownToDocument","cn"],"sources":["../../../../src/components/editors/text-editor/editor.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { ClipboardEvent, FormEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport {\n applyMark,\n createTextDocument,\n createTextSelection,\n getOrderedSelection,\n insertDocumentAtSelection,\n insertTextAtSelection,\n isCollapsedSelection,\n normalizeTextDocument,\n setTextVariant,\n setTextAlign,\n setListType,\n getListType,\n getTextAlign,\n} from \"./text-document\";\nimport { parseHtmlToDocument, parseMarkdownToDocument } from \"./text-parser\";\nimport type {\n TextBlockVariant,\n TextDocument,\n TextMark,\n TextPoint,\n TextSelection,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\nimport \"./text-editor.css\";\n\ntype TextEditorHandle = {\n focus: () => void;\n getDocument: () => TextDocument;\n getSelection: () => TextSelection;\n getActiveMarks: () => TextMark[];\n isActive: (mark: TextMark) => boolean;\n getActiveTextVariant: () => TextBlockVariant | null;\n isTextVariantActive: (variant: TextBlockVariant) => boolean;\n toggleMark: (mark: TextMark) => void;\n setTextVariant: (variant: TextBlockVariant) => void;\n setTextAlign: (align: TextAlign) => void;\n isTextAlignActive: (align: TextAlign) => boolean;\n setListType: (listType: TextListType | null) => void;\n isListTypeActive: (listType: TextListType) => boolean;\n insertText: (text: string) => void;\n replaceSelection: (document: TextDocument) => void;\n undo: () => void;\n redo: () => void;\n canUndo: () => boolean;\n canRedo: () => boolean;\n};\n\ntype EditorProps = {\n /** Controlled document. Use the same object emitted by onChange when updating it. */\n value?: TextDocument;\n /** Initial document for uncontrolled use. */\n defaultValue?: TextDocument;\n onChange?: (document: TextDocument) => void;\n onSelectionChange?: (selection: TextSelection) => void;\n onActiveMarksChange?: (marks: TextMark[]) => void;\n onActiveTextVariantChange?: (variant: TextBlockVariant | null) => void;\n placeholder?: string;\n className?: string;\n readOnly?: boolean;\n autoFocus?: boolean;\n \"aria-label\"?: string;\n};\n\ntype HistoryEntry = {\n document: TextDocument;\n selection: TextSelection;\n};\n\ntype HistoryState = {\n undo: HistoryEntry[];\n redo: HistoryEntry[];\n lastInputType: string;\n lastInputAt: number;\n};\n\ntype DomPoint = {\n node: Node;\n offset: number;\n};\n\nconst isInside = (root: HTMLElement, node: Node | null): node is Node =>\n node != null && (node === root || root.contains(node));\n\nconst nodeTextLength = (node: Node): number => {\n if (node.nodeType === Node.TEXT_NODE) return node.textContent?.length ?? 0;\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n return node.hasAttribute(\"data-puzzle-placeholder\") ? 0 : 1;\n }\n\n return Array.from(node.childNodes).reduce(\n (total, child) => total + nodeTextLength(child),\n 0,\n );\n};\n\nconst measureBeforePoint = (\n current: Node,\n target: Node,\n targetOffset: number,\n): number | null => {\n if (current === target) {\n if (current.nodeType === Node.TEXT_NODE) {\n return Math.max(\n 0,\n Math.min(targetOffset, current.textContent?.length ?? 0),\n );\n }\n\n return Array.from(current.childNodes)\n .slice(0, targetOffset)\n .reduce((total, child) => total + nodeTextLength(child), 0);\n }\n\n let total = 0;\n for (const child of Array.from(current.childNodes)) {\n if (child === target || child.contains(target)) {\n const nested = measureBeforePoint(child, target, targetOffset);\n return nested == null ? null : total + nested;\n }\n total += nodeTextLength(child);\n }\n\n return null;\n};\n\nconst pointFromDom = (\n root: HTMLElement,\n node: Node,\n offset: number,\n): TextPoint | null => {\n if (!isInside(root, node)) return null;\n\n if (node === root) {\n const blocks = Array.from(root.children) as HTMLElement[];\n if (!blocks.length) return null;\n const blockIndex = Math.max(0, Math.min(offset, blocks.length - 1));\n const blockElement = blocks[blockIndex];\n return {\n block: blockIndex,\n offset: offset >= blocks.length ? nodeTextLength(blockElement) : 0,\n };\n }\n\n const markedBlock =\n node instanceof Element\n ? node.closest<HTMLElement>(\"[data-puzzle-editor-block]\")\n : node.parentElement?.closest<HTMLElement>(\"[data-puzzle-editor-block]\");\n let directChild: Node | null = node;\n while (directChild && directChild.parentNode !== root) {\n directChild = directChild.parentNode;\n }\n const blockElement =\n markedBlock ?? (directChild instanceof HTMLElement ? directChild : null);\n\n if (!blockElement || !root.contains(blockElement)) return null;\n\n const block = Array.from(root.children).indexOf(blockElement);\n if (block < 0) return null;\n\n const measured = measureBeforePoint(blockElement, node, offset);\n const contentLength = nodeTextLength(blockElement);\n return {\n block,\n offset: Math.max(0, Math.min(measured ?? 0, contentLength)),\n };\n};\n\nconst selectionFromDom = (root: HTMLElement): TextSelection | null => {\n const selection = root.ownerDocument.defaultView?.getSelection();\n if (!selection?.anchorNode || !selection.focusNode) return null;\n if (\n !root.contains(selection.anchorNode) ||\n !root.contains(selection.focusNode)\n ) {\n return null;\n }\n\n const anchor = pointFromDom(\n root,\n selection.anchorNode,\n selection.anchorOffset,\n );\n const focus = pointFromDom(root, selection.focusNode, selection.focusOffset);\n return anchor && focus ? { anchor, focus } : null;\n};\n\nconst collectDomPoints = (\n root: HTMLElement,\n): {\n points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }>;\n length: number;\n} => {\n const points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }> = [];\n let length = 0;\n\n const visit = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const nodeLength = node.textContent?.length ?? 0;\n if (nodeLength) {\n points.push({ start: length, length: nodeLength, node, kind: \"text\" });\n length += nodeLength;\n }\n return;\n }\n\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n points.push({ start: length, length: 1, node, kind: \"break\" });\n length += 1;\n }\n return;\n }\n\n for (const child of Array.from(node.childNodes)) visit(child);\n };\n\n visit(root);\n return { points, length };\n};\n\nconst domPointFromPoint = (\n blockElement: HTMLElement,\n targetOffset: number,\n): DomPoint => {\n const { points, length } = collectDomPoints(blockElement);\n const offset = Math.max(0, Math.min(targetOffset, length));\n\n for (const point of points) {\n const end = point.start + point.length;\n if (point.kind === \"text\" && offset <= end) {\n return {\n node: point.node,\n offset: Math.max(0, Math.min(offset - point.start, point.length)),\n };\n }\n\n if (point.kind === \"break\" && offset <= end) {\n const br = point.node as Element;\n const parent = br.parentNode;\n if (!parent) break;\n const index = Array.prototype.indexOf.call(\n parent.childNodes,\n br,\n ) as number;\n return {\n node: parent,\n offset: index + (offset === end ? 1 : 0),\n };\n }\n }\n\n const last = points[points.length - 1];\n if (last?.kind === \"text\") {\n return { node: last.node, offset: last.length };\n }\n\n return { node: blockElement, offset: blockElement.childNodes.length };\n};\n\nconst setDomSelection = (root: HTMLElement, selection: TextSelection) => {\n const anchorBlock = root.children.item(\n selection.anchor.block,\n ) as HTMLElement | null;\n const focusBlock = root.children.item(\n selection.focus.block,\n ) as HTMLElement | null;\n if (!anchorBlock || !focusBlock) return;\n\n const anchor = domPointFromPoint(anchorBlock, selection.anchor.offset);\n const focus = domPointFromPoint(focusBlock, selection.focus.offset);\n const domSelection = root.ownerDocument.defaultView?.getSelection();\n if (!domSelection) return;\n\n try {\n if (typeof domSelection.setBaseAndExtent === \"function\") {\n domSelection.setBaseAndExtent(\n anchor.node,\n anchor.offset,\n focus.node,\n focus.offset,\n );\n return;\n }\n\n const range = root.ownerDocument.createRange();\n const ordered = getOrderedSelection(selection);\n const startBlock = root.children.item(\n ordered.start.block,\n ) as HTMLElement | null;\n const endBlock = root.children.item(\n ordered.end.block,\n ) as HTMLElement | null;\n if (!startBlock || !endBlock) return;\n const start = domPointFromPoint(startBlock, ordered.start.offset);\n const end = domPointFromPoint(endBlock, ordered.end.offset);\n range.setStart(start.node, start.offset);\n range.setEnd(end.node, end.offset);\n domSelection.removeAllRanges();\n domSelection.addRange(range);\n } catch {\n // The DOM may have changed between render and selection restoration.\n }\n};\n\n/**\n * Render the canonical document into a contenteditable element without making\n * React responsible for its children. Browsers mutate contenteditable DOM while\n * editing (for example, Backspace may remove a placeholder <br> itself). React\n * must therefore not reconcile those descendants as React-owned nodes.\n */\nconst renderDocumentToDom = (root: HTMLElement, textDocument: TextDocument) => {\n const ownerDocument = root.ownerDocument;\n const fragment = ownerDocument.createDocumentFragment();\n\n for (const block of textDocument.content) {\n const blockElement = ownerDocument.createElement(\"p\");\n blockElement.className = `puzzle-text-editor__block puzzle-typography-${block.variant}`;\n blockElement.dataset.puzzleEditorBlock = \"true\";\n blockElement.dataset.puzzleVariant = block.variant;\n if (block.align) {\n blockElement.dataset.puzzleAlign = block.align;\n blockElement.style.textAlign = block.align;\n }\n if (block.listType) blockElement.dataset.puzzleListType = block.listType;\n\n if (!block.children.length) {\n const placeholder = ownerDocument.createElement(\"br\");\n placeholder.dataset.puzzlePlaceholder = \"true\";\n blockElement.appendChild(placeholder);\n } else {\n for (const inline of block.children) {\n const inlineElement = ownerDocument.createElement(\"span\");\n const content = ownerDocument.createDocumentFragment();\n const parts = inline.text.split(\"\\n\");\n\n parts.forEach((part, index) => {\n if (index > 0) content.appendChild(ownerDocument.createElement(\"br\"));\n if (part) content.appendChild(ownerDocument.createTextNode(part));\n });\n\n let node: Node = content;\n for (const mark of [...(inline.marks ?? [])].reverse()) {\n const tagName =\n mark === \"bold\"\n ? \"strong\"\n : mark === \"italic\"\n ? \"em\"\n : mark === \"underline\"\n ? \"u\"\n : \"s\";\n const wrapper = ownerDocument.createElement(tagName);\n wrapper.appendChild(node);\n node = wrapper;\n }\n\n inlineElement.appendChild(node);\n blockElement.appendChild(inlineElement);\n }\n }\n\n fragment.appendChild(blockElement);\n }\n\n root.replaceChildren(fragment);\n};\n\nconst isMark = (value: string): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst documentsEqual = (left: TextDocument, right: TextDocument): boolean =>\n JSON.stringify(left) === JSON.stringify(right);\n\nconst getMarksForSelection = (\n document: TextDocument,\n selection: TextSelection,\n pendingMarks: TextMark[] = [],\n pendingMarksOverride = false,\n): TextMark[] => {\n if (isCollapsedSelection(selection)) {\n if (pendingMarksOverride) return [...pendingMarks];\n const block = document.content[selection.focus.block];\n if (!block) return [];\n const offset = selection.focus.offset;\n let position = 0;\n let previous: TextMark[] | undefined;\n for (const inline of block.children) {\n const end = position + inline.text.length;\n if (offset > position && offset <= end) return [...(inline.marks ?? [])];\n if (offset === position && previous) return [...previous];\n if (offset < end) return [...(inline.marks ?? [])];\n previous = inline.marks ?? [];\n position = end;\n }\n return [...(previous ?? [])];\n }\n const { start, end } = getOrderedSelection(selection);\n let commonMarks: Set<TextMark> | null = null;\n let foundText = false;\n document.content.forEach((block, blockIndex) => {\n if (blockIndex < start.block || blockIndex > end.block) return;\n const from = blockIndex === start.block ? start.offset : 0;\n const to =\n blockIndex === end.block\n ? end.offset\n : block.children.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n if (to <= from) return;\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = inlineStart + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n foundText = true;\n const marks = new Set(inline.marks ?? []);\n commonMarks =\n commonMarks == null\n ? marks\n : new Set([...commonMarks].filter((mark) => marks.has(mark)));\n }\n });\n return foundText && commonMarks ? [...commonMarks] : [];\n};\n\nconst getVariantForSelection = (\n document: TextDocument,\n selection: TextSelection,\n): TextBlockVariant | null => {\n if (!document.content.length) return null;\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const variants = document.content\n .slice(start.block, lastBlock + 1)\n .map((block) => block.variant);\n return variants.length && variants.every((variant) => variant === variants[0])\n ? variants[0]\n : null;\n};\n\nconst Editor = forwardRef<TextEditorHandle, EditorProps>(\n (\n {\n value,\n defaultValue,\n onChange,\n onSelectionChange,\n onActiveMarksChange,\n onActiveTextVariantChange,\n placeholder,\n className,\n readOnly = false,\n autoFocus = false,\n \"aria-label\": ariaLabel = \"Text editor\",\n },\n forwardedRef,\n ) => {\n const [documentState, setDocumentState] = useState<TextDocument>(() =>\n normalizeTextDocument(value ?? defaultValue ?? createTextDocument()),\n );\n const [selectionState, setSelectionState] = useState<TextSelection>(() =>\n createTextSelection(),\n );\n const editableRef = useRef<HTMLDivElement | null>(null);\n const documentRef = useRef(documentState);\n const selectionRef = useRef(selectionState);\n const restoreSelectionRef = useRef<TextSelection | null>(null);\n // Contenteditable descendants are managed imperatively, never by React.\n // Skip rendering after native input because the browser has already edited\n // the DOM and rebuilding it would disrupt composition/selection.\n const renderDomOnDocumentChangeRef = useRef(true);\n const inputTypeRef = useRef(\"\");\n const selectionBeforeInputRef = useRef<TextSelection>(selectionState);\n const pendingMarksRef = useRef<TextMark[]>([]);\n const pendingMarksOverrideRef = useRef(false);\n const historyRef = useRef<HistoryState>({\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n });\n\n const updateSelection = useCallback(\n (nextSelection: TextSelection) => {\n selectionRef.current = nextSelection;\n setSelectionState(nextSelection);\n onSelectionChange?.(nextSelection);\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n nextSelection,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n );\n onActiveTextVariantChange?.(\n getVariantForSelection(documentRef.current, nextSelection),\n );\n },\n [onSelectionChange, onActiveMarksChange, onActiveTextVariantChange],\n );\n\n const restoreSelection = useCallback((nextSelection: TextSelection) => {\n const root = editableRef.current;\n if (!root) return;\n setDomSelection(root, nextSelection);\n }, []);\n\n const focus = useCallback(() => {\n const root = editableRef.current;\n if (!root) return;\n root.focus({ preventScroll: true });\n restoreSelection(selectionRef.current);\n }, [restoreSelection]);\n\n const clearTypingGroup = useCallback(() => {\n historyRef.current.lastInputAt = 0;\n historyRef.current.lastInputType = \"\";\n }, []);\n\n const pushHistory = useCallback(\n (document: TextDocument, selection: TextSelection) => {\n historyRef.current.undo.push({ document, selection });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n historyRef.current.redo = [];\n clearTypingGroup();\n },\n [clearTypingGroup],\n );\n\n const emitDocument = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n const normalized = normalizeTextDocument(nextDocument);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n setDocumentState(normalized);\n onChange?.(normalized);\n },\n [onChange, updateSelection],\n );\n\n const commitTransform = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n if (documentsEqual(documentRef.current, nextDocument)) {\n updateSelection(nextSelection);\n restoreSelectionRef.current = nextSelection;\n return;\n }\n\n pushHistory(documentRef.current, selectionRef.current);\n emitDocument(nextDocument, nextSelection);\n },\n [emitDocument, pushHistory, updateSelection],\n );\n\n const undo = useCallback(() => {\n const history = historyRef.current;\n const previous = history.undo.pop();\n if (!previous) return;\n history.redo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(previous.document, previous.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const redo = useCallback(() => {\n const history = historyRef.current;\n const next = history.redo.pop();\n if (!next) return;\n history.undo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(next.document, next.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const getActiveMarks = useCallback(\n (): TextMark[] =>\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n [],\n );\n\n const isActive = useCallback(\n (mark: TextMark): boolean => getActiveMarks().includes(mark),\n [getActiveMarks],\n );\n\n const getActiveTextVariant = useCallback(\n (): TextBlockVariant | null =>\n getVariantForSelection(documentRef.current, selectionRef.current),\n [],\n );\n\n const isTextVariantActive = useCallback(\n (variant: TextBlockVariant): boolean =>\n getActiveTextVariant() === variant,\n [getActiveTextVariant],\n );\n\n const toggleMark = useCallback(\n (mark: TextMark) => {\n focus();\n const selection = selectionRef.current;\n if (isCollapsedSelection(selection)) {\n const pending = new Set(getActiveMarks());\n if (pending.has(mark)) pending.delete(mark);\n else pending.add(mark);\n pendingMarksRef.current = [\"bold\", \"italic\", \"underline\", \"strike\"]\n .filter(isMark)\n .filter((item) => pending.has(item));\n pendingMarksOverrideRef.current = true;\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n true,\n ),\n );\n return;\n }\n\n commitTransform(applyMark(documentRef.current, selection, mark));\n },\n [commitTransform, focus, getActiveMarks, onActiveMarksChange],\n );\n\n const changeVariant = useCallback(\n (variant: TextBlockVariant) => {\n focus();\n commitTransform(\n setTextVariant(documentRef.current, selectionRef.current, variant),\n );\n },\n [commitTransform, focus],\n );\n\n const changeAlign = useCallback(\n (align: TextAlign) => {\n focus();\n commitTransform(\n setTextAlign(documentRef.current, selectionRef.current, align),\n );\n },\n [commitTransform, focus],\n );\n\n const isTextAlignActive = useCallback((align: TextAlign): boolean => {\n const currentAlign = getTextAlign(\n documentRef.current,\n selectionRef.current,\n );\n return (\n currentAlign === align || (currentAlign === null && align === \"left\")\n );\n }, []);\n\n const changeListType = useCallback(\n (listType: TextListType | null) => {\n focus();\n commitTransform(\n setListType(documentRef.current, selectionRef.current, listType),\n );\n },\n [commitTransform, focus],\n );\n\n const isListTypeActive = useCallback((listType: TextListType): boolean => {\n return getListType(documentRef.current, selectionRef.current, listType);\n }, []);\n\n const replaceSelection = useCallback(\n (insertedDocument: TextDocument) => {\n focus();\n const result = insertDocumentAtSelection(\n documentRef.current,\n selectionRef.current,\n insertedDocument,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n const insertText = useCallback(\n (text: string) => {\n focus();\n const result = insertTextAtSelection(\n documentRef.current,\n selectionRef.current,\n text,\n pendingMarksRef.current,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n focus,\n getDocument: () => documentRef.current,\n getSelection: () => selectionRef.current,\n getActiveMarks,\n isActive,\n getActiveTextVariant,\n isTextVariantActive,\n toggleMark,\n setTextVariant: changeVariant,\n setTextAlign: changeAlign,\n isTextAlignActive,\n setListType: changeListType,\n isListTypeActive,\n insertText,\n replaceSelection,\n undo,\n redo,\n canUndo: () => historyRef.current.undo.length > 0,\n canRedo: () => historyRef.current.redo.length > 0,\n }),\n [\n changeAlign,\n changeListType,\n changeVariant,\n focus,\n isTextAlignActive,\n getActiveMarks,\n getActiveTextVariant,\n insertText,\n isActive,\n isTextVariantActive,\n redo,\n replaceSelection,\n toggleMark,\n undo,\n ],\n );\n\n useEffect(() => {\n if (!value || value === documentRef.current) return;\n const normalized = normalizeTextDocument(value);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n const selection = createTextSelection();\n selectionRef.current = selection;\n restoreSelectionRef.current = selection;\n historyRef.current = {\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n };\n setDocumentState(normalized);\n updateSelection(selection);\n }, [value, updateSelection]);\n\n useLayoutEffect(() => {\n const root = editableRef.current;\n if (!root) return;\n\n if (renderDomOnDocumentChangeRef.current) {\n renderDocumentToDom(root, documentState);\n }\n // Each document-state commit consumes the render decision. Native input\n // skips a DOM render; commands/external value changes explicitly enable it.\n renderDomOnDocumentChangeRef.current = true;\n\n const selection = restoreSelectionRef.current;\n if (!selection) return;\n restoreSelectionRef.current = null;\n restoreSelection(selection);\n }, [documentState, restoreSelection]);\n\n useEffect(() => {\n onActiveMarksChange?.(getActiveMarks());\n onActiveTextVariantChange?.(getActiveTextVariant());\n }, [\n getActiveMarks,\n getActiveTextVariant,\n onActiveMarksChange,\n onActiveTextVariantChange,\n ]);\n\n useEffect(() => {\n if (autoFocus) focus();\n }, [autoFocus, focus]);\n\n useEffect(() => {\n const ownerDocument = editableRef.current?.ownerDocument;\n if (!ownerDocument) return;\n\n const onSelectionChangeInDocument = () => {\n const root = editableRef.current;\n if (!root) return;\n const next = selectionFromDom(root);\n if (!next) return;\n const current = selectionRef.current;\n if (\n next.anchor.block === current.anchor.block &&\n next.anchor.offset === current.anchor.offset &&\n next.focus.block === current.focus.block &&\n next.focus.offset === current.focus.offset\n ) {\n return;\n }\n updateSelection(next);\n };\n\n ownerDocument.addEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n return () =>\n ownerDocument.removeEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n }, [updateSelection]);\n\n const handleBeforeInput = (event: FormEvent<HTMLDivElement>) => {\n const nativeEvent = event.nativeEvent as InputEvent;\n const inputType = nativeEvent.inputType ?? \"\";\n inputTypeRef.current = inputType;\n selectionBeforeInputRef.current =\n selectionFromDom(event.currentTarget) ?? selectionRef.current;\n\n if (inputType === \"historyUndo\") {\n event.preventDefault();\n undo();\n } else if (inputType === \"historyRedo\") {\n event.preventDefault();\n redo();\n }\n };\n\n const handleInput = (event: FormEvent<HTMLDivElement>) => {\n const root = event.currentTarget;\n const previousDocument = documentRef.current;\n const beforeSelection = selectionBeforeInputRef.current;\n const inputType = inputTypeRef.current;\n let nextDocument = parseHtmlToDocument(root.innerHTML);\n const nextSelection = selectionFromDom(root) ?? selectionRef.current;\n\n if (\n pendingMarksRef.current.length &&\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" || inputType === \"insertCompositionText\")\n ) {\n const insertedRange = {\n anchor: beforeSelection.anchor,\n focus: nextSelection.focus,\n };\n if (!isCollapsedSelection(insertedRange)) {\n for (const mark of pendingMarksRef.current) {\n nextDocument = applyMark(nextDocument, insertedRange, mark, true);\n }\n }\n }\n\n if (documentsEqual(previousDocument, nextDocument)) {\n updateSelection(nextSelection);\n return;\n }\n\n const now = Date.now();\n const canGroup =\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"deleteContentBackward\" ||\n inputType === \"deleteContentForward\") &&\n historyRef.current.lastInputType === inputType &&\n now - historyRef.current.lastInputAt < 800;\n\n if (!canGroup) {\n historyRef.current.undo.push({\n document: previousDocument,\n selection: beforeSelection,\n });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n }\n\n historyRef.current.redo = [];\n historyRef.current.lastInputType = inputType;\n historyRef.current.lastInputAt = now;\n documentRef.current = normalizeTextDocument(nextDocument);\n if (\n inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"insertFromPaste\"\n ) {\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n }\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n renderDomOnDocumentChangeRef.current = false;\n setDocumentState(documentRef.current);\n onChange?.(documentRef.current);\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLDivElement>) => {\n if (readOnly) return;\n event.preventDefault();\n const currentSelection = selectionFromDom(event.currentTarget);\n if (currentSelection) updateSelection(currentSelection);\n const html = event.clipboardData.getData(\"text/html\");\n const plainText = event.clipboardData.getData(\"text/plain\");\n if (!html.trim() && !plainText) return;\n const parsed = html.trim()\n ? parseHtmlToDocument(html)\n : parseMarkdownToDocument(plainText);\n replaceSelection(parsed);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const modifier = event.metaKey || event.ctrlKey;\n if (!modifier) return;\n const key = event.key.toLowerCase();\n\n if (key === \"z\") {\n event.preventDefault();\n if (event.shiftKey) redo();\n else undo();\n } else if (key === \"y\") {\n event.preventDefault();\n redo();\n } else if (key === \"b\") {\n event.preventDefault();\n toggleMark(\"bold\");\n } else if (key === \"i\") {\n event.preventDefault();\n toggleMark(\"italic\");\n } else if (key === \"u\") {\n event.preventDefault();\n toggleMark(\"underline\");\n } else if (key === \"x\" && event.shiftKey) {\n event.preventDefault();\n toggleMark(\"strike\");\n }\n };\n\n const handleKeyUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n const handleMouseUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n return (\n <div\n ref={editableRef}\n className={cn(\"puzzle-text-editor\", className)}\n contentEditable={!readOnly}\n suppressContentEditableWarning\n role=\"textbox\"\n aria-label={ariaLabel}\n aria-multiline=\"true\"\n aria-readonly={readOnly || undefined}\n data-placeholder={placeholder}\n data-empty={\n documentState.content.every((block) =>\n block.children.every((inline) => !inline.text),\n )\n ? \"true\"\n : undefined\n }\n spellCheck\n onBeforeInput={handleBeforeInput}\n onInput={handleInput}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onMouseUp={handleMouseUp}\n onFocus={handleKeyUp}\n />\n );\n },\n);\n\nEditor.displayName = \"Editor\";\n\nexport { Editor, type TextEditorHandle, type EditorProps };\n"],"mappings":"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"}
1
+ {"version":3,"file":"editor.cjs","names":["getOrderedSelection","isCollapsedSelection","forwardRef","useState","normalizeTextDocument","createTextDocument","createTextSelection","useRef","useCallback","applyMark","setTextVariant","setTextAlign","getTextAlign","setListType","getListType","insertDocumentAtSelection","insertTextAtSelection","parseHtmlToDocument","parseMarkdownToDocument","cn"],"sources":["../../../../src/components/editors/text-editor/editor.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { ClipboardEvent, FormEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport {\n applyMark,\n createTextDocument,\n createTextSelection,\n getOrderedSelection,\n insertDocumentAtSelection,\n insertTextAtSelection,\n isCollapsedSelection,\n normalizeTextDocument,\n setTextVariant,\n setTextAlign,\n setListType,\n getListType,\n getTextAlign,\n} from \"./text-document\";\nimport { parseHtmlToDocument, parseMarkdownToDocument } from \"./text-parser\";\nimport type {\n TextBlockVariant,\n TextDocument,\n TextMark,\n TextPoint,\n TextSelection,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\nimport \"./text-editor.css\";\n\ntype TextEditorHandle = {\n focus: () => void;\n getDocument: () => TextDocument;\n getSelection: () => TextSelection;\n getActiveMarks: () => TextMark[];\n isActive: (mark: TextMark) => boolean;\n getActiveTextVariant: () => TextBlockVariant | null;\n isTextVariantActive: (variant: TextBlockVariant) => boolean;\n toggleMark: (mark: TextMark) => void;\n setTextVariant: (variant: TextBlockVariant) => void;\n setTextAlign: (align: TextAlign) => void;\n isTextAlignActive: (align: TextAlign) => boolean;\n setListType: (listType: TextListType | null) => void;\n isListTypeActive: (listType: TextListType) => boolean;\n insertText: (text: string) => void;\n replaceSelection: (document: TextDocument) => void;\n undo: () => void;\n redo: () => void;\n canUndo: () => boolean;\n canRedo: () => boolean;\n};\n\ntype EditorProps = {\n /** Controlled document. Use the same object emitted by onChange when updating it. */\n value?: TextDocument;\n /** Initial document for uncontrolled use. */\n defaultValue?: TextDocument;\n onChange?: (document: TextDocument) => void;\n onSelectionChange?: (selection: TextSelection) => void;\n onActiveMarksChange?: (marks: TextMark[]) => void;\n onActiveTextVariantChange?: (variant: TextBlockVariant | null) => void;\n placeholder?: string;\n className?: string;\n readOnly?: boolean;\n autoFocus?: boolean;\n \"aria-label\"?: string;\n};\n\ntype HistoryEntry = {\n document: TextDocument;\n selection: TextSelection;\n};\n\ntype HistoryState = {\n undo: HistoryEntry[];\n redo: HistoryEntry[];\n lastInputType: string;\n lastInputAt: number;\n};\n\ntype DomPoint = {\n node: Node;\n offset: number;\n};\n\nconst isInside = (root: HTMLElement, node: Node | null): node is Node =>\n node != null && (node === root || root.contains(node));\n\nconst nodeTextLength = (node: Node): number => {\n if (node.nodeType === Node.TEXT_NODE) return node.textContent?.length ?? 0;\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n return node.hasAttribute(\"data-puzzle-placeholder\") ? 0 : 1;\n }\n\n return Array.from(node.childNodes).reduce(\n (total, child) => total + nodeTextLength(child),\n 0,\n );\n};\n\nconst measureBeforePoint = (\n current: Node,\n target: Node,\n targetOffset: number,\n): number | null => {\n if (current === target) {\n if (current.nodeType === Node.TEXT_NODE) {\n return Math.max(\n 0,\n Math.min(targetOffset, current.textContent?.length ?? 0),\n );\n }\n\n return Array.from(current.childNodes)\n .slice(0, targetOffset)\n .reduce((total, child) => total + nodeTextLength(child), 0);\n }\n\n let total = 0;\n for (const child of Array.from(current.childNodes)) {\n if (child === target || child.contains(target)) {\n const nested = measureBeforePoint(child, target, targetOffset);\n return nested == null ? null : total + nested;\n }\n total += nodeTextLength(child);\n }\n\n return null;\n};\n\nconst pointFromDom = (\n root: HTMLElement,\n node: Node,\n offset: number,\n): TextPoint | null => {\n if (!isInside(root, node)) return null;\n\n if (node === root) {\n const blocks = Array.from(root.children) as HTMLElement[];\n if (!blocks.length) return null;\n const blockIndex = Math.max(0, Math.min(offset, blocks.length - 1));\n const blockElement = blocks[blockIndex]!;\n return {\n block: blockIndex,\n offset: offset >= blocks.length ? nodeTextLength(blockElement) : 0,\n };\n }\n\n const markedBlock =\n node instanceof Element\n ? node.closest<HTMLElement>(\"[data-puzzle-editor-block]\")\n : node.parentElement?.closest<HTMLElement>(\"[data-puzzle-editor-block]\");\n let directChild: Node | null = node;\n while (directChild && directChild.parentNode !== root) {\n directChild = directChild.parentNode;\n }\n const blockElement =\n markedBlock ?? (directChild instanceof HTMLElement ? directChild : null);\n\n if (!blockElement || !root.contains(blockElement)) return null;\n\n const block = Array.from(root.children).indexOf(blockElement);\n if (block < 0) return null;\n\n const measured = measureBeforePoint(blockElement, node, offset);\n const contentLength = nodeTextLength(blockElement);\n return {\n block,\n offset: Math.max(0, Math.min(measured ?? 0, contentLength)),\n };\n};\n\nconst selectionFromDom = (root: HTMLElement): TextSelection | null => {\n const selection = root.ownerDocument.defaultView?.getSelection();\n if (!selection?.anchorNode || !selection.focusNode) return null;\n if (\n !root.contains(selection.anchorNode) ||\n !root.contains(selection.focusNode)\n ) {\n return null;\n }\n\n const anchor = pointFromDom(\n root,\n selection.anchorNode,\n selection.anchorOffset,\n );\n const focus = pointFromDom(root, selection.focusNode, selection.focusOffset);\n return anchor && focus ? { anchor, focus } : null;\n};\n\nconst collectDomPoints = (\n root: HTMLElement,\n): {\n points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }>;\n length: number;\n} => {\n const points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }> = [];\n let length = 0;\n\n const visit = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const nodeLength = node.textContent?.length ?? 0;\n if (nodeLength) {\n points.push({ start: length, length: nodeLength, node, kind: \"text\" });\n length += nodeLength;\n }\n return;\n }\n\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n points.push({ start: length, length: 1, node, kind: \"break\" });\n length += 1;\n }\n return;\n }\n\n for (const child of Array.from(node.childNodes)) visit(child);\n };\n\n visit(root);\n return { points, length };\n};\n\nconst domPointFromPoint = (\n blockElement: HTMLElement,\n targetOffset: number,\n): DomPoint => {\n const { points, length } = collectDomPoints(blockElement);\n const offset = Math.max(0, Math.min(targetOffset, length));\n\n for (const point of points) {\n const end = point.start + point.length;\n if (point.kind === \"text\" && offset <= end) {\n return {\n node: point.node,\n offset: Math.max(0, Math.min(offset - point.start, point.length)),\n };\n }\n\n if (point.kind === \"break\" && offset <= end) {\n const br = point.node as Element;\n const parent = br.parentNode;\n if (!parent) break;\n const index = Array.prototype.indexOf.call(\n parent.childNodes,\n br,\n ) as number;\n return {\n node: parent,\n offset: index + (offset === end ? 1 : 0),\n };\n }\n }\n\n const last = points[points.length - 1];\n if (last?.kind === \"text\") {\n return { node: last.node, offset: last.length };\n }\n\n return { node: blockElement, offset: blockElement.childNodes.length };\n};\n\nconst setDomSelection = (root: HTMLElement, selection: TextSelection) => {\n const anchorBlock = root.children.item(\n selection.anchor.block,\n ) as HTMLElement | null;\n const focusBlock = root.children.item(\n selection.focus.block,\n ) as HTMLElement | null;\n if (!anchorBlock || !focusBlock) return;\n\n const anchor = domPointFromPoint(anchorBlock, selection.anchor.offset);\n const focus = domPointFromPoint(focusBlock, selection.focus.offset);\n const domSelection = root.ownerDocument.defaultView?.getSelection();\n if (!domSelection) return;\n\n try {\n if (typeof domSelection.setBaseAndExtent === \"function\") {\n domSelection.setBaseAndExtent(\n anchor.node,\n anchor.offset,\n focus.node,\n focus.offset,\n );\n return;\n }\n\n const range = root.ownerDocument.createRange();\n const ordered = getOrderedSelection(selection);\n const startBlock = root.children.item(\n ordered.start.block,\n ) as HTMLElement | null;\n const endBlock = root.children.item(\n ordered.end.block,\n ) as HTMLElement | null;\n if (!startBlock || !endBlock) return;\n const start = domPointFromPoint(startBlock, ordered.start.offset);\n const end = domPointFromPoint(endBlock, ordered.end.offset);\n range.setStart(start.node, start.offset);\n range.setEnd(end.node, end.offset);\n domSelection.removeAllRanges();\n domSelection.addRange(range);\n } catch {\n // The DOM may have changed between render and selection restoration.\n }\n};\n\n/**\n * Render the canonical document into a contenteditable element without making\n * React responsible for its children. Browsers mutate contenteditable DOM while\n * editing (for example, Backspace may remove a placeholder <br> itself). React\n * must therefore not reconcile those descendants as React-owned nodes.\n */\nconst renderDocumentToDom = (root: HTMLElement, textDocument: TextDocument) => {\n const ownerDocument = root.ownerDocument;\n const fragment = ownerDocument.createDocumentFragment();\n\n for (const block of textDocument.content) {\n const blockElement = ownerDocument.createElement(\"p\");\n blockElement.className = `puzzle-text-editor__block puzzle-typography-${block.variant}`;\n blockElement.dataset.puzzleEditorBlock = \"true\";\n blockElement.dataset.puzzleVariant = block.variant;\n if (block.align) {\n blockElement.dataset.puzzleAlign = block.align;\n blockElement.style.textAlign = block.align;\n }\n if (block.listType) blockElement.dataset.puzzleListType = block.listType;\n\n if (!block.children.length) {\n const placeholder = ownerDocument.createElement(\"br\");\n placeholder.dataset.puzzlePlaceholder = \"true\";\n blockElement.appendChild(placeholder);\n } else {\n for (const inline of block.children) {\n const inlineElement = ownerDocument.createElement(\"span\");\n const content = ownerDocument.createDocumentFragment();\n const parts = inline.text.split(\"\\n\");\n\n parts.forEach((part, index) => {\n if (index > 0) content.appendChild(ownerDocument.createElement(\"br\"));\n if (part) content.appendChild(ownerDocument.createTextNode(part));\n });\n\n let node: Node = content;\n for (const mark of [...(inline.marks ?? [])].reverse()) {\n const tagName =\n mark === \"bold\"\n ? \"strong\"\n : mark === \"italic\"\n ? \"em\"\n : mark === \"underline\"\n ? \"u\"\n : \"s\";\n const wrapper = ownerDocument.createElement(tagName);\n wrapper.appendChild(node);\n node = wrapper;\n }\n\n inlineElement.appendChild(node);\n blockElement.appendChild(inlineElement);\n }\n }\n\n fragment.appendChild(blockElement);\n }\n\n root.replaceChildren(fragment);\n};\n\nconst isMark = (value: string): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst documentsEqual = (left: TextDocument, right: TextDocument): boolean =>\n JSON.stringify(left) === JSON.stringify(right);\n\nconst getMarksForSelection = (\n document: TextDocument,\n selection: TextSelection,\n pendingMarks: TextMark[] = [],\n pendingMarksOverride = false,\n): TextMark[] => {\n if (isCollapsedSelection(selection)) {\n if (pendingMarksOverride) return [...pendingMarks];\n const block = document.content[selection.focus.block];\n if (!block) return [];\n const offset = selection.focus.offset;\n let position = 0;\n let previous: TextMark[] | undefined;\n for (const inline of block.children) {\n const end = position + inline.text.length;\n if (offset > position && offset <= end) return [...(inline.marks ?? [])];\n if (offset === position && previous) return [...previous];\n if (offset < end) return [...(inline.marks ?? [])];\n previous = inline.marks ?? [];\n position = end;\n }\n return [...(previous ?? [])];\n }\n const { start, end } = getOrderedSelection(selection);\n let commonMarks: Set<TextMark> | null = null;\n let foundText = false;\n document.content.forEach((block, blockIndex) => {\n if (blockIndex < start.block || blockIndex > end.block) return;\n const from = blockIndex === start.block ? start.offset : 0;\n const to =\n blockIndex === end.block\n ? end.offset\n : block.children.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n if (to <= from) return;\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = inlineStart + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n foundText = true;\n const marks = new Set(inline.marks ?? []);\n commonMarks =\n commonMarks == null\n ? marks\n : new Set([...commonMarks].filter((mark) => marks.has(mark)));\n }\n });\n return foundText && commonMarks ? [...commonMarks] : [];\n};\n\nconst getVariantForSelection = (\n document: TextDocument,\n selection: TextSelection,\n): TextBlockVariant | null => {\n if (!document.content.length) return null;\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const variants = document.content\n .slice(start.block, lastBlock + 1)\n .map((block) => block.variant);\n return variants.length && variants.every((variant) => variant === variants[0])\n ? variants[0]!\n : null;\n};\n\nconst Editor = forwardRef<TextEditorHandle, EditorProps>(\n (\n {\n value,\n defaultValue,\n onChange,\n onSelectionChange,\n onActiveMarksChange,\n onActiveTextVariantChange,\n placeholder,\n className,\n readOnly = false,\n autoFocus = false,\n \"aria-label\": ariaLabel = \"Text editor\",\n },\n forwardedRef,\n ) => {\n const [documentState, setDocumentState] = useState<TextDocument>(() =>\n normalizeTextDocument(value ?? defaultValue ?? createTextDocument()),\n );\n const [selectionState, setSelectionState] = useState<TextSelection>(() =>\n createTextSelection(),\n );\n const editableRef = useRef<HTMLDivElement | null>(null);\n const documentRef = useRef(documentState);\n const selectionRef = useRef(selectionState);\n const restoreSelectionRef = useRef<TextSelection | null>(null);\n // Contenteditable descendants are managed imperatively, never by React.\n // Skip rendering after native input because the browser has already edited\n // the DOM and rebuilding it would disrupt composition/selection.\n const renderDomOnDocumentChangeRef = useRef(true);\n const inputTypeRef = useRef(\"\");\n const selectionBeforeInputRef = useRef<TextSelection>(selectionState);\n const pendingMarksRef = useRef<TextMark[]>([]);\n const pendingMarksOverrideRef = useRef(false);\n const historyRef = useRef<HistoryState>({\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n });\n\n const updateSelection = useCallback(\n (nextSelection: TextSelection) => {\n selectionRef.current = nextSelection;\n setSelectionState(nextSelection);\n onSelectionChange?.(nextSelection);\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n nextSelection,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n );\n onActiveTextVariantChange?.(\n getVariantForSelection(documentRef.current, nextSelection),\n );\n },\n [onSelectionChange, onActiveMarksChange, onActiveTextVariantChange],\n );\n\n const restoreSelection = useCallback((nextSelection: TextSelection) => {\n const root = editableRef.current;\n if (!root) return;\n setDomSelection(root, nextSelection);\n }, []);\n\n const focus = useCallback(() => {\n const root = editableRef.current;\n if (!root) return;\n root.focus({ preventScroll: true });\n restoreSelection(selectionRef.current);\n }, [restoreSelection]);\n\n const clearTypingGroup = useCallback(() => {\n historyRef.current.lastInputAt = 0;\n historyRef.current.lastInputType = \"\";\n }, []);\n\n const pushHistory = useCallback(\n (document: TextDocument, selection: TextSelection) => {\n historyRef.current.undo.push({ document, selection });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n historyRef.current.redo = [];\n clearTypingGroup();\n },\n [clearTypingGroup],\n );\n\n const emitDocument = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n const normalized = normalizeTextDocument(nextDocument);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n setDocumentState(normalized);\n onChange?.(normalized);\n },\n [onChange, updateSelection],\n );\n\n const commitTransform = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n if (documentsEqual(documentRef.current, nextDocument)) {\n updateSelection(nextSelection);\n restoreSelectionRef.current = nextSelection;\n return;\n }\n\n pushHistory(documentRef.current, selectionRef.current);\n emitDocument(nextDocument, nextSelection);\n },\n [emitDocument, pushHistory, updateSelection],\n );\n\n const undo = useCallback(() => {\n const history = historyRef.current;\n const previous = history.undo.pop();\n if (!previous) return;\n history.redo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(previous.document, previous.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const redo = useCallback(() => {\n const history = historyRef.current;\n const next = history.redo.pop();\n if (!next) return;\n history.undo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(next.document, next.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const getActiveMarks = useCallback(\n (): TextMark[] =>\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n [],\n );\n\n const isActive = useCallback(\n (mark: TextMark): boolean => getActiveMarks().includes(mark),\n [getActiveMarks],\n );\n\n const getActiveTextVariant = useCallback(\n (): TextBlockVariant | null =>\n getVariantForSelection(documentRef.current, selectionRef.current),\n [],\n );\n\n const isTextVariantActive = useCallback(\n (variant: TextBlockVariant): boolean =>\n getActiveTextVariant() === variant,\n [getActiveTextVariant],\n );\n\n const toggleMark = useCallback(\n (mark: TextMark) => {\n focus();\n const selection = selectionRef.current;\n if (isCollapsedSelection(selection)) {\n const pending = new Set(getActiveMarks());\n if (pending.has(mark)) pending.delete(mark);\n else pending.add(mark);\n pendingMarksRef.current = [\"bold\", \"italic\", \"underline\", \"strike\"]\n .filter(isMark)\n .filter((item) => pending.has(item));\n pendingMarksOverrideRef.current = true;\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n true,\n ),\n );\n return;\n }\n\n commitTransform(applyMark(documentRef.current, selection, mark));\n },\n [commitTransform, focus, getActiveMarks, onActiveMarksChange],\n );\n\n const changeVariant = useCallback(\n (variant: TextBlockVariant) => {\n focus();\n commitTransform(\n setTextVariant(documentRef.current, selectionRef.current, variant),\n );\n },\n [commitTransform, focus],\n );\n\n const changeAlign = useCallback(\n (align: TextAlign) => {\n focus();\n commitTransform(\n setTextAlign(documentRef.current, selectionRef.current, align),\n );\n },\n [commitTransform, focus],\n );\n\n const isTextAlignActive = useCallback((align: TextAlign): boolean => {\n const currentAlign = getTextAlign(\n documentRef.current,\n selectionRef.current,\n );\n return (\n currentAlign === align || (currentAlign === null && align === \"left\")\n );\n }, []);\n\n const changeListType = useCallback(\n (listType: TextListType | null) => {\n focus();\n commitTransform(\n setListType(documentRef.current, selectionRef.current, listType),\n );\n },\n [commitTransform, focus],\n );\n\n const isListTypeActive = useCallback((listType: TextListType): boolean => {\n return getListType(documentRef.current, selectionRef.current, listType);\n }, []);\n\n const replaceSelection = useCallback(\n (insertedDocument: TextDocument) => {\n focus();\n const result = insertDocumentAtSelection(\n documentRef.current,\n selectionRef.current,\n insertedDocument,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n const insertText = useCallback(\n (text: string) => {\n focus();\n const result = insertTextAtSelection(\n documentRef.current,\n selectionRef.current,\n text,\n pendingMarksRef.current,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n focus,\n getDocument: () => documentRef.current,\n getSelection: () => selectionRef.current,\n getActiveMarks,\n isActive,\n getActiveTextVariant,\n isTextVariantActive,\n toggleMark,\n setTextVariant: changeVariant,\n setTextAlign: changeAlign,\n isTextAlignActive,\n setListType: changeListType,\n isListTypeActive,\n insertText,\n replaceSelection,\n undo,\n redo,\n canUndo: () => historyRef.current.undo.length > 0,\n canRedo: () => historyRef.current.redo.length > 0,\n }),\n [\n changeAlign,\n changeListType,\n changeVariant,\n focus,\n isTextAlignActive,\n getActiveMarks,\n getActiveTextVariant,\n insertText,\n isActive,\n isTextVariantActive,\n redo,\n replaceSelection,\n toggleMark,\n undo,\n ],\n );\n\n useEffect(() => {\n if (!value || value === documentRef.current) return;\n const normalized = normalizeTextDocument(value);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n const selection = createTextSelection();\n selectionRef.current = selection;\n restoreSelectionRef.current = selection;\n historyRef.current = {\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n };\n setDocumentState(normalized);\n updateSelection(selection);\n }, [value, updateSelection]);\n\n useLayoutEffect(() => {\n const root = editableRef.current;\n if (!root) return;\n\n if (renderDomOnDocumentChangeRef.current) {\n renderDocumentToDom(root, documentState);\n }\n // Each document-state commit consumes the render decision. Native input\n // skips a DOM render; commands/external value changes explicitly enable it.\n renderDomOnDocumentChangeRef.current = true;\n\n const selection = restoreSelectionRef.current;\n if (!selection) return;\n restoreSelectionRef.current = null;\n restoreSelection(selection);\n }, [documentState, restoreSelection]);\n\n useEffect(() => {\n onActiveMarksChange?.(getActiveMarks());\n onActiveTextVariantChange?.(getActiveTextVariant());\n }, [\n getActiveMarks,\n getActiveTextVariant,\n onActiveMarksChange,\n onActiveTextVariantChange,\n ]);\n\n useEffect(() => {\n if (autoFocus) focus();\n }, [autoFocus, focus]);\n\n useEffect(() => {\n const ownerDocument = editableRef.current?.ownerDocument;\n if (!ownerDocument) return;\n\n const onSelectionChangeInDocument = () => {\n const root = editableRef.current;\n if (!root) return;\n const next = selectionFromDom(root);\n if (!next) return;\n const current = selectionRef.current;\n if (\n next.anchor.block === current.anchor.block &&\n next.anchor.offset === current.anchor.offset &&\n next.focus.block === current.focus.block &&\n next.focus.offset === current.focus.offset\n ) {\n return;\n }\n updateSelection(next);\n };\n\n ownerDocument.addEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n return () =>\n ownerDocument.removeEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n }, [updateSelection]);\n\n const handleBeforeInput = (event: FormEvent<HTMLDivElement>) => {\n const nativeEvent = event.nativeEvent as InputEvent;\n const inputType = nativeEvent.inputType ?? \"\";\n inputTypeRef.current = inputType;\n selectionBeforeInputRef.current =\n selectionFromDom(event.currentTarget) ?? selectionRef.current;\n\n if (inputType === \"historyUndo\") {\n event.preventDefault();\n undo();\n } else if (inputType === \"historyRedo\") {\n event.preventDefault();\n redo();\n }\n };\n\n const handleInput = (event: FormEvent<HTMLDivElement>) => {\n const root = event.currentTarget;\n const previousDocument = documentRef.current;\n const beforeSelection = selectionBeforeInputRef.current;\n const inputType = inputTypeRef.current;\n let nextDocument = parseHtmlToDocument(root.innerHTML);\n const nextSelection = selectionFromDom(root) ?? selectionRef.current;\n\n if (\n pendingMarksRef.current.length &&\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" || inputType === \"insertCompositionText\")\n ) {\n const insertedRange = {\n anchor: beforeSelection.anchor,\n focus: nextSelection.focus,\n };\n if (!isCollapsedSelection(insertedRange)) {\n for (const mark of pendingMarksRef.current) {\n nextDocument = applyMark(nextDocument, insertedRange, mark, true);\n }\n }\n }\n\n if (documentsEqual(previousDocument, nextDocument)) {\n updateSelection(nextSelection);\n return;\n }\n\n const now = Date.now();\n const canGroup =\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"deleteContentBackward\" ||\n inputType === \"deleteContentForward\") &&\n historyRef.current.lastInputType === inputType &&\n now - historyRef.current.lastInputAt < 800;\n\n if (!canGroup) {\n historyRef.current.undo.push({\n document: previousDocument,\n selection: beforeSelection,\n });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n }\n\n historyRef.current.redo = [];\n historyRef.current.lastInputType = inputType;\n historyRef.current.lastInputAt = now;\n documentRef.current = normalizeTextDocument(nextDocument);\n if (\n inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"insertFromPaste\"\n ) {\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n }\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n renderDomOnDocumentChangeRef.current = false;\n setDocumentState(documentRef.current);\n onChange?.(documentRef.current);\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLDivElement>) => {\n if (readOnly) return;\n event.preventDefault();\n const currentSelection = selectionFromDom(event.currentTarget);\n if (currentSelection) updateSelection(currentSelection);\n const html = event.clipboardData.getData(\"text/html\");\n const plainText = event.clipboardData.getData(\"text/plain\");\n if (!html.trim() && !plainText) return;\n const parsed = html.trim()\n ? parseHtmlToDocument(html)\n : parseMarkdownToDocument(plainText);\n replaceSelection(parsed);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const modifier = event.metaKey || event.ctrlKey;\n if (!modifier) return;\n const key = event.key.toLowerCase();\n\n if (key === \"z\") {\n event.preventDefault();\n if (event.shiftKey) redo();\n else undo();\n } else if (key === \"y\") {\n event.preventDefault();\n redo();\n } else if (key === \"b\") {\n event.preventDefault();\n toggleMark(\"bold\");\n } else if (key === \"i\") {\n event.preventDefault();\n toggleMark(\"italic\");\n } else if (key === \"u\") {\n event.preventDefault();\n toggleMark(\"underline\");\n } else if (key === \"x\" && event.shiftKey) {\n event.preventDefault();\n toggleMark(\"strike\");\n }\n };\n\n const handleKeyUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n const handleMouseUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n return (\n <div\n ref={editableRef}\n className={cn(\"puzzle-text-editor\", className)}\n contentEditable={!readOnly}\n suppressContentEditableWarning\n role=\"textbox\"\n aria-label={ariaLabel}\n aria-multiline=\"true\"\n aria-readonly={readOnly || undefined}\n data-placeholder={placeholder}\n data-empty={\n documentState.content.every((block) =>\n block.children.every((inline) => !inline.text),\n )\n ? \"true\"\n : undefined\n }\n spellCheck\n onBeforeInput={handleBeforeInput}\n onInput={handleInput}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onMouseUp={handleMouseUp}\n onFocus={handleKeyUp}\n />\n );\n },\n);\n\nEditor.displayName = \"Editor\";\n\nexport { Editor, type TextEditorHandle, type EditorProps };\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"editor.js","names":[],"sources":["../../../../src/components/editors/text-editor/editor.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { ClipboardEvent, FormEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport {\n applyMark,\n createTextDocument,\n createTextSelection,\n getOrderedSelection,\n insertDocumentAtSelection,\n insertTextAtSelection,\n isCollapsedSelection,\n normalizeTextDocument,\n setTextVariant,\n setTextAlign,\n setListType,\n getListType,\n getTextAlign,\n} from \"./text-document\";\nimport { parseHtmlToDocument, parseMarkdownToDocument } from \"./text-parser\";\nimport type {\n TextBlockVariant,\n TextDocument,\n TextMark,\n TextPoint,\n TextSelection,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\nimport \"./text-editor.css\";\n\ntype TextEditorHandle = {\n focus: () => void;\n getDocument: () => TextDocument;\n getSelection: () => TextSelection;\n getActiveMarks: () => TextMark[];\n isActive: (mark: TextMark) => boolean;\n getActiveTextVariant: () => TextBlockVariant | null;\n isTextVariantActive: (variant: TextBlockVariant) => boolean;\n toggleMark: (mark: TextMark) => void;\n setTextVariant: (variant: TextBlockVariant) => void;\n setTextAlign: (align: TextAlign) => void;\n isTextAlignActive: (align: TextAlign) => boolean;\n setListType: (listType: TextListType | null) => void;\n isListTypeActive: (listType: TextListType) => boolean;\n insertText: (text: string) => void;\n replaceSelection: (document: TextDocument) => void;\n undo: () => void;\n redo: () => void;\n canUndo: () => boolean;\n canRedo: () => boolean;\n};\n\ntype EditorProps = {\n /** Controlled document. Use the same object emitted by onChange when updating it. */\n value?: TextDocument;\n /** Initial document for uncontrolled use. */\n defaultValue?: TextDocument;\n onChange?: (document: TextDocument) => void;\n onSelectionChange?: (selection: TextSelection) => void;\n onActiveMarksChange?: (marks: TextMark[]) => void;\n onActiveTextVariantChange?: (variant: TextBlockVariant | null) => void;\n placeholder?: string;\n className?: string;\n readOnly?: boolean;\n autoFocus?: boolean;\n \"aria-label\"?: string;\n};\n\ntype HistoryEntry = {\n document: TextDocument;\n selection: TextSelection;\n};\n\ntype HistoryState = {\n undo: HistoryEntry[];\n redo: HistoryEntry[];\n lastInputType: string;\n lastInputAt: number;\n};\n\ntype DomPoint = {\n node: Node;\n offset: number;\n};\n\nconst isInside = (root: HTMLElement, node: Node | null): node is Node =>\n node != null && (node === root || root.contains(node));\n\nconst nodeTextLength = (node: Node): number => {\n if (node.nodeType === Node.TEXT_NODE) return node.textContent?.length ?? 0;\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n return node.hasAttribute(\"data-puzzle-placeholder\") ? 0 : 1;\n }\n\n return Array.from(node.childNodes).reduce(\n (total, child) => total + nodeTextLength(child),\n 0,\n );\n};\n\nconst measureBeforePoint = (\n current: Node,\n target: Node,\n targetOffset: number,\n): number | null => {\n if (current === target) {\n if (current.nodeType === Node.TEXT_NODE) {\n return Math.max(\n 0,\n Math.min(targetOffset, current.textContent?.length ?? 0),\n );\n }\n\n return Array.from(current.childNodes)\n .slice(0, targetOffset)\n .reduce((total, child) => total + nodeTextLength(child), 0);\n }\n\n let total = 0;\n for (const child of Array.from(current.childNodes)) {\n if (child === target || child.contains(target)) {\n const nested = measureBeforePoint(child, target, targetOffset);\n return nested == null ? null : total + nested;\n }\n total += nodeTextLength(child);\n }\n\n return null;\n};\n\nconst pointFromDom = (\n root: HTMLElement,\n node: Node,\n offset: number,\n): TextPoint | null => {\n if (!isInside(root, node)) return null;\n\n if (node === root) {\n const blocks = Array.from(root.children) as HTMLElement[];\n if (!blocks.length) return null;\n const blockIndex = Math.max(0, Math.min(offset, blocks.length - 1));\n const blockElement = blocks[blockIndex];\n return {\n block: blockIndex,\n offset: offset >= blocks.length ? nodeTextLength(blockElement) : 0,\n };\n }\n\n const markedBlock =\n node instanceof Element\n ? node.closest<HTMLElement>(\"[data-puzzle-editor-block]\")\n : node.parentElement?.closest<HTMLElement>(\"[data-puzzle-editor-block]\");\n let directChild: Node | null = node;\n while (directChild && directChild.parentNode !== root) {\n directChild = directChild.parentNode;\n }\n const blockElement =\n markedBlock ?? (directChild instanceof HTMLElement ? directChild : null);\n\n if (!blockElement || !root.contains(blockElement)) return null;\n\n const block = Array.from(root.children).indexOf(blockElement);\n if (block < 0) return null;\n\n const measured = measureBeforePoint(blockElement, node, offset);\n const contentLength = nodeTextLength(blockElement);\n return {\n block,\n offset: Math.max(0, Math.min(measured ?? 0, contentLength)),\n };\n};\n\nconst selectionFromDom = (root: HTMLElement): TextSelection | null => {\n const selection = root.ownerDocument.defaultView?.getSelection();\n if (!selection?.anchorNode || !selection.focusNode) return null;\n if (\n !root.contains(selection.anchorNode) ||\n !root.contains(selection.focusNode)\n ) {\n return null;\n }\n\n const anchor = pointFromDom(\n root,\n selection.anchorNode,\n selection.anchorOffset,\n );\n const focus = pointFromDom(root, selection.focusNode, selection.focusOffset);\n return anchor && focus ? { anchor, focus } : null;\n};\n\nconst collectDomPoints = (\n root: HTMLElement,\n): {\n points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }>;\n length: number;\n} => {\n const points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }> = [];\n let length = 0;\n\n const visit = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const nodeLength = node.textContent?.length ?? 0;\n if (nodeLength) {\n points.push({ start: length, length: nodeLength, node, kind: \"text\" });\n length += nodeLength;\n }\n return;\n }\n\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n points.push({ start: length, length: 1, node, kind: \"break\" });\n length += 1;\n }\n return;\n }\n\n for (const child of Array.from(node.childNodes)) visit(child);\n };\n\n visit(root);\n return { points, length };\n};\n\nconst domPointFromPoint = (\n blockElement: HTMLElement,\n targetOffset: number,\n): DomPoint => {\n const { points, length } = collectDomPoints(blockElement);\n const offset = Math.max(0, Math.min(targetOffset, length));\n\n for (const point of points) {\n const end = point.start + point.length;\n if (point.kind === \"text\" && offset <= end) {\n return {\n node: point.node,\n offset: Math.max(0, Math.min(offset - point.start, point.length)),\n };\n }\n\n if (point.kind === \"break\" && offset <= end) {\n const br = point.node as Element;\n const parent = br.parentNode;\n if (!parent) break;\n const index = Array.prototype.indexOf.call(\n parent.childNodes,\n br,\n ) as number;\n return {\n node: parent,\n offset: index + (offset === end ? 1 : 0),\n };\n }\n }\n\n const last = points[points.length - 1];\n if (last?.kind === \"text\") {\n return { node: last.node, offset: last.length };\n }\n\n return { node: blockElement, offset: blockElement.childNodes.length };\n};\n\nconst setDomSelection = (root: HTMLElement, selection: TextSelection) => {\n const anchorBlock = root.children.item(\n selection.anchor.block,\n ) as HTMLElement | null;\n const focusBlock = root.children.item(\n selection.focus.block,\n ) as HTMLElement | null;\n if (!anchorBlock || !focusBlock) return;\n\n const anchor = domPointFromPoint(anchorBlock, selection.anchor.offset);\n const focus = domPointFromPoint(focusBlock, selection.focus.offset);\n const domSelection = root.ownerDocument.defaultView?.getSelection();\n if (!domSelection) return;\n\n try {\n if (typeof domSelection.setBaseAndExtent === \"function\") {\n domSelection.setBaseAndExtent(\n anchor.node,\n anchor.offset,\n focus.node,\n focus.offset,\n );\n return;\n }\n\n const range = root.ownerDocument.createRange();\n const ordered = getOrderedSelection(selection);\n const startBlock = root.children.item(\n ordered.start.block,\n ) as HTMLElement | null;\n const endBlock = root.children.item(\n ordered.end.block,\n ) as HTMLElement | null;\n if (!startBlock || !endBlock) return;\n const start = domPointFromPoint(startBlock, ordered.start.offset);\n const end = domPointFromPoint(endBlock, ordered.end.offset);\n range.setStart(start.node, start.offset);\n range.setEnd(end.node, end.offset);\n domSelection.removeAllRanges();\n domSelection.addRange(range);\n } catch {\n // The DOM may have changed between render and selection restoration.\n }\n};\n\n/**\n * Render the canonical document into a contenteditable element without making\n * React responsible for its children. Browsers mutate contenteditable DOM while\n * editing (for example, Backspace may remove a placeholder <br> itself). React\n * must therefore not reconcile those descendants as React-owned nodes.\n */\nconst renderDocumentToDom = (root: HTMLElement, textDocument: TextDocument) => {\n const ownerDocument = root.ownerDocument;\n const fragment = ownerDocument.createDocumentFragment();\n\n for (const block of textDocument.content) {\n const blockElement = ownerDocument.createElement(\"p\");\n blockElement.className = `puzzle-text-editor__block puzzle-typography-${block.variant}`;\n blockElement.dataset.puzzleEditorBlock = \"true\";\n blockElement.dataset.puzzleVariant = block.variant;\n if (block.align) {\n blockElement.dataset.puzzleAlign = block.align;\n blockElement.style.textAlign = block.align;\n }\n if (block.listType) blockElement.dataset.puzzleListType = block.listType;\n\n if (!block.children.length) {\n const placeholder = ownerDocument.createElement(\"br\");\n placeholder.dataset.puzzlePlaceholder = \"true\";\n blockElement.appendChild(placeholder);\n } else {\n for (const inline of block.children) {\n const inlineElement = ownerDocument.createElement(\"span\");\n const content = ownerDocument.createDocumentFragment();\n const parts = inline.text.split(\"\\n\");\n\n parts.forEach((part, index) => {\n if (index > 0) content.appendChild(ownerDocument.createElement(\"br\"));\n if (part) content.appendChild(ownerDocument.createTextNode(part));\n });\n\n let node: Node = content;\n for (const mark of [...(inline.marks ?? [])].reverse()) {\n const tagName =\n mark === \"bold\"\n ? \"strong\"\n : mark === \"italic\"\n ? \"em\"\n : mark === \"underline\"\n ? \"u\"\n : \"s\";\n const wrapper = ownerDocument.createElement(tagName);\n wrapper.appendChild(node);\n node = wrapper;\n }\n\n inlineElement.appendChild(node);\n blockElement.appendChild(inlineElement);\n }\n }\n\n fragment.appendChild(blockElement);\n }\n\n root.replaceChildren(fragment);\n};\n\nconst isMark = (value: string): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst documentsEqual = (left: TextDocument, right: TextDocument): boolean =>\n JSON.stringify(left) === JSON.stringify(right);\n\nconst getMarksForSelection = (\n document: TextDocument,\n selection: TextSelection,\n pendingMarks: TextMark[] = [],\n pendingMarksOverride = false,\n): TextMark[] => {\n if (isCollapsedSelection(selection)) {\n if (pendingMarksOverride) return [...pendingMarks];\n const block = document.content[selection.focus.block];\n if (!block) return [];\n const offset = selection.focus.offset;\n let position = 0;\n let previous: TextMark[] | undefined;\n for (const inline of block.children) {\n const end = position + inline.text.length;\n if (offset > position && offset <= end) return [...(inline.marks ?? [])];\n if (offset === position && previous) return [...previous];\n if (offset < end) return [...(inline.marks ?? [])];\n previous = inline.marks ?? [];\n position = end;\n }\n return [...(previous ?? [])];\n }\n const { start, end } = getOrderedSelection(selection);\n let commonMarks: Set<TextMark> | null = null;\n let foundText = false;\n document.content.forEach((block, blockIndex) => {\n if (blockIndex < start.block || blockIndex > end.block) return;\n const from = blockIndex === start.block ? start.offset : 0;\n const to =\n blockIndex === end.block\n ? end.offset\n : block.children.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n if (to <= from) return;\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = inlineStart + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n foundText = true;\n const marks = new Set(inline.marks ?? []);\n commonMarks =\n commonMarks == null\n ? marks\n : new Set([...commonMarks].filter((mark) => marks.has(mark)));\n }\n });\n return foundText && commonMarks ? [...commonMarks] : [];\n};\n\nconst getVariantForSelection = (\n document: TextDocument,\n selection: TextSelection,\n): TextBlockVariant | null => {\n if (!document.content.length) return null;\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const variants = document.content\n .slice(start.block, lastBlock + 1)\n .map((block) => block.variant);\n return variants.length && variants.every((variant) => variant === variants[0])\n ? variants[0]\n : null;\n};\n\nconst Editor = forwardRef<TextEditorHandle, EditorProps>(\n (\n {\n value,\n defaultValue,\n onChange,\n onSelectionChange,\n onActiveMarksChange,\n onActiveTextVariantChange,\n placeholder,\n className,\n readOnly = false,\n autoFocus = false,\n \"aria-label\": ariaLabel = \"Text editor\",\n },\n forwardedRef,\n ) => {\n const [documentState, setDocumentState] = useState<TextDocument>(() =>\n normalizeTextDocument(value ?? defaultValue ?? createTextDocument()),\n );\n const [selectionState, setSelectionState] = useState<TextSelection>(() =>\n createTextSelection(),\n );\n const editableRef = useRef<HTMLDivElement | null>(null);\n const documentRef = useRef(documentState);\n const selectionRef = useRef(selectionState);\n const restoreSelectionRef = useRef<TextSelection | null>(null);\n // Contenteditable descendants are managed imperatively, never by React.\n // Skip rendering after native input because the browser has already edited\n // the DOM and rebuilding it would disrupt composition/selection.\n const renderDomOnDocumentChangeRef = useRef(true);\n const inputTypeRef = useRef(\"\");\n const selectionBeforeInputRef = useRef<TextSelection>(selectionState);\n const pendingMarksRef = useRef<TextMark[]>([]);\n const pendingMarksOverrideRef = useRef(false);\n const historyRef = useRef<HistoryState>({\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n });\n\n const updateSelection = useCallback(\n (nextSelection: TextSelection) => {\n selectionRef.current = nextSelection;\n setSelectionState(nextSelection);\n onSelectionChange?.(nextSelection);\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n nextSelection,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n );\n onActiveTextVariantChange?.(\n getVariantForSelection(documentRef.current, nextSelection),\n );\n },\n [onSelectionChange, onActiveMarksChange, onActiveTextVariantChange],\n );\n\n const restoreSelection = useCallback((nextSelection: TextSelection) => {\n const root = editableRef.current;\n if (!root) return;\n setDomSelection(root, nextSelection);\n }, []);\n\n const focus = useCallback(() => {\n const root = editableRef.current;\n if (!root) return;\n root.focus({ preventScroll: true });\n restoreSelection(selectionRef.current);\n }, [restoreSelection]);\n\n const clearTypingGroup = useCallback(() => {\n historyRef.current.lastInputAt = 0;\n historyRef.current.lastInputType = \"\";\n }, []);\n\n const pushHistory = useCallback(\n (document: TextDocument, selection: TextSelection) => {\n historyRef.current.undo.push({ document, selection });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n historyRef.current.redo = [];\n clearTypingGroup();\n },\n [clearTypingGroup],\n );\n\n const emitDocument = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n const normalized = normalizeTextDocument(nextDocument);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n setDocumentState(normalized);\n onChange?.(normalized);\n },\n [onChange, updateSelection],\n );\n\n const commitTransform = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n if (documentsEqual(documentRef.current, nextDocument)) {\n updateSelection(nextSelection);\n restoreSelectionRef.current = nextSelection;\n return;\n }\n\n pushHistory(documentRef.current, selectionRef.current);\n emitDocument(nextDocument, nextSelection);\n },\n [emitDocument, pushHistory, updateSelection],\n );\n\n const undo = useCallback(() => {\n const history = historyRef.current;\n const previous = history.undo.pop();\n if (!previous) return;\n history.redo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(previous.document, previous.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const redo = useCallback(() => {\n const history = historyRef.current;\n const next = history.redo.pop();\n if (!next) return;\n history.undo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(next.document, next.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const getActiveMarks = useCallback(\n (): TextMark[] =>\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n [],\n );\n\n const isActive = useCallback(\n (mark: TextMark): boolean => getActiveMarks().includes(mark),\n [getActiveMarks],\n );\n\n const getActiveTextVariant = useCallback(\n (): TextBlockVariant | null =>\n getVariantForSelection(documentRef.current, selectionRef.current),\n [],\n );\n\n const isTextVariantActive = useCallback(\n (variant: TextBlockVariant): boolean =>\n getActiveTextVariant() === variant,\n [getActiveTextVariant],\n );\n\n const toggleMark = useCallback(\n (mark: TextMark) => {\n focus();\n const selection = selectionRef.current;\n if (isCollapsedSelection(selection)) {\n const pending = new Set(getActiveMarks());\n if (pending.has(mark)) pending.delete(mark);\n else pending.add(mark);\n pendingMarksRef.current = [\"bold\", \"italic\", \"underline\", \"strike\"]\n .filter(isMark)\n .filter((item) => pending.has(item));\n pendingMarksOverrideRef.current = true;\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n true,\n ),\n );\n return;\n }\n\n commitTransform(applyMark(documentRef.current, selection, mark));\n },\n [commitTransform, focus, getActiveMarks, onActiveMarksChange],\n );\n\n const changeVariant = useCallback(\n (variant: TextBlockVariant) => {\n focus();\n commitTransform(\n setTextVariant(documentRef.current, selectionRef.current, variant),\n );\n },\n [commitTransform, focus],\n );\n\n const changeAlign = useCallback(\n (align: TextAlign) => {\n focus();\n commitTransform(\n setTextAlign(documentRef.current, selectionRef.current, align),\n );\n },\n [commitTransform, focus],\n );\n\n const isTextAlignActive = useCallback((align: TextAlign): boolean => {\n const currentAlign = getTextAlign(\n documentRef.current,\n selectionRef.current,\n );\n return (\n currentAlign === align || (currentAlign === null && align === \"left\")\n );\n }, []);\n\n const changeListType = useCallback(\n (listType: TextListType | null) => {\n focus();\n commitTransform(\n setListType(documentRef.current, selectionRef.current, listType),\n );\n },\n [commitTransform, focus],\n );\n\n const isListTypeActive = useCallback((listType: TextListType): boolean => {\n return getListType(documentRef.current, selectionRef.current, listType);\n }, []);\n\n const replaceSelection = useCallback(\n (insertedDocument: TextDocument) => {\n focus();\n const result = insertDocumentAtSelection(\n documentRef.current,\n selectionRef.current,\n insertedDocument,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n const insertText = useCallback(\n (text: string) => {\n focus();\n const result = insertTextAtSelection(\n documentRef.current,\n selectionRef.current,\n text,\n pendingMarksRef.current,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n focus,\n getDocument: () => documentRef.current,\n getSelection: () => selectionRef.current,\n getActiveMarks,\n isActive,\n getActiveTextVariant,\n isTextVariantActive,\n toggleMark,\n setTextVariant: changeVariant,\n setTextAlign: changeAlign,\n isTextAlignActive,\n setListType: changeListType,\n isListTypeActive,\n insertText,\n replaceSelection,\n undo,\n redo,\n canUndo: () => historyRef.current.undo.length > 0,\n canRedo: () => historyRef.current.redo.length > 0,\n }),\n [\n changeAlign,\n changeListType,\n changeVariant,\n focus,\n isTextAlignActive,\n getActiveMarks,\n getActiveTextVariant,\n insertText,\n isActive,\n isTextVariantActive,\n redo,\n replaceSelection,\n toggleMark,\n undo,\n ],\n );\n\n useEffect(() => {\n if (!value || value === documentRef.current) return;\n const normalized = normalizeTextDocument(value);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n const selection = createTextSelection();\n selectionRef.current = selection;\n restoreSelectionRef.current = selection;\n historyRef.current = {\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n };\n setDocumentState(normalized);\n updateSelection(selection);\n }, [value, updateSelection]);\n\n useLayoutEffect(() => {\n const root = editableRef.current;\n if (!root) return;\n\n if (renderDomOnDocumentChangeRef.current) {\n renderDocumentToDom(root, documentState);\n }\n // Each document-state commit consumes the render decision. Native input\n // skips a DOM render; commands/external value changes explicitly enable it.\n renderDomOnDocumentChangeRef.current = true;\n\n const selection = restoreSelectionRef.current;\n if (!selection) return;\n restoreSelectionRef.current = null;\n restoreSelection(selection);\n }, [documentState, restoreSelection]);\n\n useEffect(() => {\n onActiveMarksChange?.(getActiveMarks());\n onActiveTextVariantChange?.(getActiveTextVariant());\n }, [\n getActiveMarks,\n getActiveTextVariant,\n onActiveMarksChange,\n onActiveTextVariantChange,\n ]);\n\n useEffect(() => {\n if (autoFocus) focus();\n }, [autoFocus, focus]);\n\n useEffect(() => {\n const ownerDocument = editableRef.current?.ownerDocument;\n if (!ownerDocument) return;\n\n const onSelectionChangeInDocument = () => {\n const root = editableRef.current;\n if (!root) return;\n const next = selectionFromDom(root);\n if (!next) return;\n const current = selectionRef.current;\n if (\n next.anchor.block === current.anchor.block &&\n next.anchor.offset === current.anchor.offset &&\n next.focus.block === current.focus.block &&\n next.focus.offset === current.focus.offset\n ) {\n return;\n }\n updateSelection(next);\n };\n\n ownerDocument.addEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n return () =>\n ownerDocument.removeEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n }, [updateSelection]);\n\n const handleBeforeInput = (event: FormEvent<HTMLDivElement>) => {\n const nativeEvent = event.nativeEvent as InputEvent;\n const inputType = nativeEvent.inputType ?? \"\";\n inputTypeRef.current = inputType;\n selectionBeforeInputRef.current =\n selectionFromDom(event.currentTarget) ?? selectionRef.current;\n\n if (inputType === \"historyUndo\") {\n event.preventDefault();\n undo();\n } else if (inputType === \"historyRedo\") {\n event.preventDefault();\n redo();\n }\n };\n\n const handleInput = (event: FormEvent<HTMLDivElement>) => {\n const root = event.currentTarget;\n const previousDocument = documentRef.current;\n const beforeSelection = selectionBeforeInputRef.current;\n const inputType = inputTypeRef.current;\n let nextDocument = parseHtmlToDocument(root.innerHTML);\n const nextSelection = selectionFromDom(root) ?? selectionRef.current;\n\n if (\n pendingMarksRef.current.length &&\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" || inputType === \"insertCompositionText\")\n ) {\n const insertedRange = {\n anchor: beforeSelection.anchor,\n focus: nextSelection.focus,\n };\n if (!isCollapsedSelection(insertedRange)) {\n for (const mark of pendingMarksRef.current) {\n nextDocument = applyMark(nextDocument, insertedRange, mark, true);\n }\n }\n }\n\n if (documentsEqual(previousDocument, nextDocument)) {\n updateSelection(nextSelection);\n return;\n }\n\n const now = Date.now();\n const canGroup =\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"deleteContentBackward\" ||\n inputType === \"deleteContentForward\") &&\n historyRef.current.lastInputType === inputType &&\n now - historyRef.current.lastInputAt < 800;\n\n if (!canGroup) {\n historyRef.current.undo.push({\n document: previousDocument,\n selection: beforeSelection,\n });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n }\n\n historyRef.current.redo = [];\n historyRef.current.lastInputType = inputType;\n historyRef.current.lastInputAt = now;\n documentRef.current = normalizeTextDocument(nextDocument);\n if (\n inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"insertFromPaste\"\n ) {\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n }\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n renderDomOnDocumentChangeRef.current = false;\n setDocumentState(documentRef.current);\n onChange?.(documentRef.current);\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLDivElement>) => {\n if (readOnly) return;\n event.preventDefault();\n const currentSelection = selectionFromDom(event.currentTarget);\n if (currentSelection) updateSelection(currentSelection);\n const html = event.clipboardData.getData(\"text/html\");\n const plainText = event.clipboardData.getData(\"text/plain\");\n if (!html.trim() && !plainText) return;\n const parsed = html.trim()\n ? parseHtmlToDocument(html)\n : parseMarkdownToDocument(plainText);\n replaceSelection(parsed);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const modifier = event.metaKey || event.ctrlKey;\n if (!modifier) return;\n const key = event.key.toLowerCase();\n\n if (key === \"z\") {\n event.preventDefault();\n if (event.shiftKey) redo();\n else undo();\n } else if (key === \"y\") {\n event.preventDefault();\n redo();\n } else if (key === \"b\") {\n event.preventDefault();\n toggleMark(\"bold\");\n } else if (key === \"i\") {\n event.preventDefault();\n toggleMark(\"italic\");\n } else if (key === \"u\") {\n event.preventDefault();\n toggleMark(\"underline\");\n } else if (key === \"x\" && event.shiftKey) {\n event.preventDefault();\n toggleMark(\"strike\");\n }\n };\n\n const handleKeyUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n const handleMouseUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n return (\n <div\n ref={editableRef}\n className={cn(\"puzzle-text-editor\", className)}\n contentEditable={!readOnly}\n suppressContentEditableWarning\n role=\"textbox\"\n aria-label={ariaLabel}\n aria-multiline=\"true\"\n aria-readonly={readOnly || undefined}\n data-placeholder={placeholder}\n data-empty={\n documentState.content.every((block) =>\n block.children.every((inline) => !inline.text),\n )\n ? \"true\"\n : undefined\n }\n spellCheck\n onBeforeInput={handleBeforeInput}\n onInput={handleInput}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onMouseUp={handleMouseUp}\n onFocus={handleKeyUp}\n />\n );\n },\n);\n\nEditor.displayName = \"Editor\";\n\nexport { Editor, type TextEditorHandle, type EditorProps };\n"],"mappings":"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"}
1
+ {"version":3,"file":"editor.js","names":[],"sources":["../../../../src/components/editors/text-editor/editor.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { ClipboardEvent, FormEvent, KeyboardEvent } from \"react\";\nimport { cn } from \"@puzzle-ui/core\";\nimport {\n applyMark,\n createTextDocument,\n createTextSelection,\n getOrderedSelection,\n insertDocumentAtSelection,\n insertTextAtSelection,\n isCollapsedSelection,\n normalizeTextDocument,\n setTextVariant,\n setTextAlign,\n setListType,\n getListType,\n getTextAlign,\n} from \"./text-document\";\nimport { parseHtmlToDocument, parseMarkdownToDocument } from \"./text-parser\";\nimport type {\n TextBlockVariant,\n TextDocument,\n TextMark,\n TextPoint,\n TextSelection,\n TextAlign,\n TextListType,\n} from \"./text-editor.types\";\nimport \"./text-editor.css\";\n\ntype TextEditorHandle = {\n focus: () => void;\n getDocument: () => TextDocument;\n getSelection: () => TextSelection;\n getActiveMarks: () => TextMark[];\n isActive: (mark: TextMark) => boolean;\n getActiveTextVariant: () => TextBlockVariant | null;\n isTextVariantActive: (variant: TextBlockVariant) => boolean;\n toggleMark: (mark: TextMark) => void;\n setTextVariant: (variant: TextBlockVariant) => void;\n setTextAlign: (align: TextAlign) => void;\n isTextAlignActive: (align: TextAlign) => boolean;\n setListType: (listType: TextListType | null) => void;\n isListTypeActive: (listType: TextListType) => boolean;\n insertText: (text: string) => void;\n replaceSelection: (document: TextDocument) => void;\n undo: () => void;\n redo: () => void;\n canUndo: () => boolean;\n canRedo: () => boolean;\n};\n\ntype EditorProps = {\n /** Controlled document. Use the same object emitted by onChange when updating it. */\n value?: TextDocument;\n /** Initial document for uncontrolled use. */\n defaultValue?: TextDocument;\n onChange?: (document: TextDocument) => void;\n onSelectionChange?: (selection: TextSelection) => void;\n onActiveMarksChange?: (marks: TextMark[]) => void;\n onActiveTextVariantChange?: (variant: TextBlockVariant | null) => void;\n placeholder?: string;\n className?: string;\n readOnly?: boolean;\n autoFocus?: boolean;\n \"aria-label\"?: string;\n};\n\ntype HistoryEntry = {\n document: TextDocument;\n selection: TextSelection;\n};\n\ntype HistoryState = {\n undo: HistoryEntry[];\n redo: HistoryEntry[];\n lastInputType: string;\n lastInputAt: number;\n};\n\ntype DomPoint = {\n node: Node;\n offset: number;\n};\n\nconst isInside = (root: HTMLElement, node: Node | null): node is Node =>\n node != null && (node === root || root.contains(node));\n\nconst nodeTextLength = (node: Node): number => {\n if (node.nodeType === Node.TEXT_NODE) return node.textContent?.length ?? 0;\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n return node.hasAttribute(\"data-puzzle-placeholder\") ? 0 : 1;\n }\n\n return Array.from(node.childNodes).reduce(\n (total, child) => total + nodeTextLength(child),\n 0,\n );\n};\n\nconst measureBeforePoint = (\n current: Node,\n target: Node,\n targetOffset: number,\n): number | null => {\n if (current === target) {\n if (current.nodeType === Node.TEXT_NODE) {\n return Math.max(\n 0,\n Math.min(targetOffset, current.textContent?.length ?? 0),\n );\n }\n\n return Array.from(current.childNodes)\n .slice(0, targetOffset)\n .reduce((total, child) => total + nodeTextLength(child), 0);\n }\n\n let total = 0;\n for (const child of Array.from(current.childNodes)) {\n if (child === target || child.contains(target)) {\n const nested = measureBeforePoint(child, target, targetOffset);\n return nested == null ? null : total + nested;\n }\n total += nodeTextLength(child);\n }\n\n return null;\n};\n\nconst pointFromDom = (\n root: HTMLElement,\n node: Node,\n offset: number,\n): TextPoint | null => {\n if (!isInside(root, node)) return null;\n\n if (node === root) {\n const blocks = Array.from(root.children) as HTMLElement[];\n if (!blocks.length) return null;\n const blockIndex = Math.max(0, Math.min(offset, blocks.length - 1));\n const blockElement = blocks[blockIndex]!;\n return {\n block: blockIndex,\n offset: offset >= blocks.length ? nodeTextLength(blockElement) : 0,\n };\n }\n\n const markedBlock =\n node instanceof Element\n ? node.closest<HTMLElement>(\"[data-puzzle-editor-block]\")\n : node.parentElement?.closest<HTMLElement>(\"[data-puzzle-editor-block]\");\n let directChild: Node | null = node;\n while (directChild && directChild.parentNode !== root) {\n directChild = directChild.parentNode;\n }\n const blockElement =\n markedBlock ?? (directChild instanceof HTMLElement ? directChild : null);\n\n if (!blockElement || !root.contains(blockElement)) return null;\n\n const block = Array.from(root.children).indexOf(blockElement);\n if (block < 0) return null;\n\n const measured = measureBeforePoint(blockElement, node, offset);\n const contentLength = nodeTextLength(blockElement);\n return {\n block,\n offset: Math.max(0, Math.min(measured ?? 0, contentLength)),\n };\n};\n\nconst selectionFromDom = (root: HTMLElement): TextSelection | null => {\n const selection = root.ownerDocument.defaultView?.getSelection();\n if (!selection?.anchorNode || !selection.focusNode) return null;\n if (\n !root.contains(selection.anchorNode) ||\n !root.contains(selection.focusNode)\n ) {\n return null;\n }\n\n const anchor = pointFromDom(\n root,\n selection.anchorNode,\n selection.anchorOffset,\n );\n const focus = pointFromDom(root, selection.focusNode, selection.focusOffset);\n return anchor && focus ? { anchor, focus } : null;\n};\n\nconst collectDomPoints = (\n root: HTMLElement,\n): {\n points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }>;\n length: number;\n} => {\n const points: Array<{\n start: number;\n length: number;\n node: Node;\n kind: \"text\" | \"break\";\n }> = [];\n let length = 0;\n\n const visit = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) {\n const nodeLength = node.textContent?.length ?? 0;\n if (nodeLength) {\n points.push({ start: length, length: nodeLength, node, kind: \"text\" });\n length += nodeLength;\n }\n return;\n }\n\n if (node instanceof Element && node.tagName.toLowerCase() === \"br\") {\n if (!node.hasAttribute(\"data-puzzle-placeholder\")) {\n points.push({ start: length, length: 1, node, kind: \"break\" });\n length += 1;\n }\n return;\n }\n\n for (const child of Array.from(node.childNodes)) visit(child);\n };\n\n visit(root);\n return { points, length };\n};\n\nconst domPointFromPoint = (\n blockElement: HTMLElement,\n targetOffset: number,\n): DomPoint => {\n const { points, length } = collectDomPoints(blockElement);\n const offset = Math.max(0, Math.min(targetOffset, length));\n\n for (const point of points) {\n const end = point.start + point.length;\n if (point.kind === \"text\" && offset <= end) {\n return {\n node: point.node,\n offset: Math.max(0, Math.min(offset - point.start, point.length)),\n };\n }\n\n if (point.kind === \"break\" && offset <= end) {\n const br = point.node as Element;\n const parent = br.parentNode;\n if (!parent) break;\n const index = Array.prototype.indexOf.call(\n parent.childNodes,\n br,\n ) as number;\n return {\n node: parent,\n offset: index + (offset === end ? 1 : 0),\n };\n }\n }\n\n const last = points[points.length - 1];\n if (last?.kind === \"text\") {\n return { node: last.node, offset: last.length };\n }\n\n return { node: blockElement, offset: blockElement.childNodes.length };\n};\n\nconst setDomSelection = (root: HTMLElement, selection: TextSelection) => {\n const anchorBlock = root.children.item(\n selection.anchor.block,\n ) as HTMLElement | null;\n const focusBlock = root.children.item(\n selection.focus.block,\n ) as HTMLElement | null;\n if (!anchorBlock || !focusBlock) return;\n\n const anchor = domPointFromPoint(anchorBlock, selection.anchor.offset);\n const focus = domPointFromPoint(focusBlock, selection.focus.offset);\n const domSelection = root.ownerDocument.defaultView?.getSelection();\n if (!domSelection) return;\n\n try {\n if (typeof domSelection.setBaseAndExtent === \"function\") {\n domSelection.setBaseAndExtent(\n anchor.node,\n anchor.offset,\n focus.node,\n focus.offset,\n );\n return;\n }\n\n const range = root.ownerDocument.createRange();\n const ordered = getOrderedSelection(selection);\n const startBlock = root.children.item(\n ordered.start.block,\n ) as HTMLElement | null;\n const endBlock = root.children.item(\n ordered.end.block,\n ) as HTMLElement | null;\n if (!startBlock || !endBlock) return;\n const start = domPointFromPoint(startBlock, ordered.start.offset);\n const end = domPointFromPoint(endBlock, ordered.end.offset);\n range.setStart(start.node, start.offset);\n range.setEnd(end.node, end.offset);\n domSelection.removeAllRanges();\n domSelection.addRange(range);\n } catch {\n // The DOM may have changed between render and selection restoration.\n }\n};\n\n/**\n * Render the canonical document into a contenteditable element without making\n * React responsible for its children. Browsers mutate contenteditable DOM while\n * editing (for example, Backspace may remove a placeholder <br> itself). React\n * must therefore not reconcile those descendants as React-owned nodes.\n */\nconst renderDocumentToDom = (root: HTMLElement, textDocument: TextDocument) => {\n const ownerDocument = root.ownerDocument;\n const fragment = ownerDocument.createDocumentFragment();\n\n for (const block of textDocument.content) {\n const blockElement = ownerDocument.createElement(\"p\");\n blockElement.className = `puzzle-text-editor__block puzzle-typography-${block.variant}`;\n blockElement.dataset.puzzleEditorBlock = \"true\";\n blockElement.dataset.puzzleVariant = block.variant;\n if (block.align) {\n blockElement.dataset.puzzleAlign = block.align;\n blockElement.style.textAlign = block.align;\n }\n if (block.listType) blockElement.dataset.puzzleListType = block.listType;\n\n if (!block.children.length) {\n const placeholder = ownerDocument.createElement(\"br\");\n placeholder.dataset.puzzlePlaceholder = \"true\";\n blockElement.appendChild(placeholder);\n } else {\n for (const inline of block.children) {\n const inlineElement = ownerDocument.createElement(\"span\");\n const content = ownerDocument.createDocumentFragment();\n const parts = inline.text.split(\"\\n\");\n\n parts.forEach((part, index) => {\n if (index > 0) content.appendChild(ownerDocument.createElement(\"br\"));\n if (part) content.appendChild(ownerDocument.createTextNode(part));\n });\n\n let node: Node = content;\n for (const mark of [...(inline.marks ?? [])].reverse()) {\n const tagName =\n mark === \"bold\"\n ? \"strong\"\n : mark === \"italic\"\n ? \"em\"\n : mark === \"underline\"\n ? \"u\"\n : \"s\";\n const wrapper = ownerDocument.createElement(tagName);\n wrapper.appendChild(node);\n node = wrapper;\n }\n\n inlineElement.appendChild(node);\n blockElement.appendChild(inlineElement);\n }\n }\n\n fragment.appendChild(blockElement);\n }\n\n root.replaceChildren(fragment);\n};\n\nconst isMark = (value: string): value is TextMark =>\n value === \"bold\" ||\n value === \"italic\" ||\n value === \"underline\" ||\n value === \"strike\";\n\nconst documentsEqual = (left: TextDocument, right: TextDocument): boolean =>\n JSON.stringify(left) === JSON.stringify(right);\n\nconst getMarksForSelection = (\n document: TextDocument,\n selection: TextSelection,\n pendingMarks: TextMark[] = [],\n pendingMarksOverride = false,\n): TextMark[] => {\n if (isCollapsedSelection(selection)) {\n if (pendingMarksOverride) return [...pendingMarks];\n const block = document.content[selection.focus.block];\n if (!block) return [];\n const offset = selection.focus.offset;\n let position = 0;\n let previous: TextMark[] | undefined;\n for (const inline of block.children) {\n const end = position + inline.text.length;\n if (offset > position && offset <= end) return [...(inline.marks ?? [])];\n if (offset === position && previous) return [...previous];\n if (offset < end) return [...(inline.marks ?? [])];\n previous = inline.marks ?? [];\n position = end;\n }\n return [...(previous ?? [])];\n }\n const { start, end } = getOrderedSelection(selection);\n let commonMarks: Set<TextMark> | null = null;\n let foundText = false;\n document.content.forEach((block, blockIndex) => {\n if (blockIndex < start.block || blockIndex > end.block) return;\n const from = blockIndex === start.block ? start.offset : 0;\n const to =\n blockIndex === end.block\n ? end.offset\n : block.children.reduce(\n (total, inline) => total + inline.text.length,\n 0,\n );\n if (to <= from) return;\n let position = 0;\n for (const inline of block.children) {\n const inlineStart = position;\n const inlineEnd = inlineStart + inline.text.length;\n position = inlineEnd;\n if (inlineEnd <= from || inlineStart >= to) continue;\n foundText = true;\n const marks = new Set(inline.marks ?? []);\n commonMarks =\n commonMarks == null\n ? marks\n : new Set([...commonMarks].filter((mark) => marks.has(mark)));\n }\n });\n return foundText && commonMarks ? [...commonMarks] : [];\n};\n\nconst getVariantForSelection = (\n document: TextDocument,\n selection: TextSelection,\n): TextBlockVariant | null => {\n if (!document.content.length) return null;\n const { start, end } = getOrderedSelection(selection);\n const lastBlock = isCollapsedSelection(selection)\n ? start.block\n : end.offset === 0 && end.block > start.block\n ? end.block - 1\n : end.block;\n const variants = document.content\n .slice(start.block, lastBlock + 1)\n .map((block) => block.variant);\n return variants.length && variants.every((variant) => variant === variants[0])\n ? variants[0]!\n : null;\n};\n\nconst Editor = forwardRef<TextEditorHandle, EditorProps>(\n (\n {\n value,\n defaultValue,\n onChange,\n onSelectionChange,\n onActiveMarksChange,\n onActiveTextVariantChange,\n placeholder,\n className,\n readOnly = false,\n autoFocus = false,\n \"aria-label\": ariaLabel = \"Text editor\",\n },\n forwardedRef,\n ) => {\n const [documentState, setDocumentState] = useState<TextDocument>(() =>\n normalizeTextDocument(value ?? defaultValue ?? createTextDocument()),\n );\n const [selectionState, setSelectionState] = useState<TextSelection>(() =>\n createTextSelection(),\n );\n const editableRef = useRef<HTMLDivElement | null>(null);\n const documentRef = useRef(documentState);\n const selectionRef = useRef(selectionState);\n const restoreSelectionRef = useRef<TextSelection | null>(null);\n // Contenteditable descendants are managed imperatively, never by React.\n // Skip rendering after native input because the browser has already edited\n // the DOM and rebuilding it would disrupt composition/selection.\n const renderDomOnDocumentChangeRef = useRef(true);\n const inputTypeRef = useRef(\"\");\n const selectionBeforeInputRef = useRef<TextSelection>(selectionState);\n const pendingMarksRef = useRef<TextMark[]>([]);\n const pendingMarksOverrideRef = useRef(false);\n const historyRef = useRef<HistoryState>({\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n });\n\n const updateSelection = useCallback(\n (nextSelection: TextSelection) => {\n selectionRef.current = nextSelection;\n setSelectionState(nextSelection);\n onSelectionChange?.(nextSelection);\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n nextSelection,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n );\n onActiveTextVariantChange?.(\n getVariantForSelection(documentRef.current, nextSelection),\n );\n },\n [onSelectionChange, onActiveMarksChange, onActiveTextVariantChange],\n );\n\n const restoreSelection = useCallback((nextSelection: TextSelection) => {\n const root = editableRef.current;\n if (!root) return;\n setDomSelection(root, nextSelection);\n }, []);\n\n const focus = useCallback(() => {\n const root = editableRef.current;\n if (!root) return;\n root.focus({ preventScroll: true });\n restoreSelection(selectionRef.current);\n }, [restoreSelection]);\n\n const clearTypingGroup = useCallback(() => {\n historyRef.current.lastInputAt = 0;\n historyRef.current.lastInputType = \"\";\n }, []);\n\n const pushHistory = useCallback(\n (document: TextDocument, selection: TextSelection) => {\n historyRef.current.undo.push({ document, selection });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n historyRef.current.redo = [];\n clearTypingGroup();\n },\n [clearTypingGroup],\n );\n\n const emitDocument = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n const normalized = normalizeTextDocument(nextDocument);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n setDocumentState(normalized);\n onChange?.(normalized);\n },\n [onChange, updateSelection],\n );\n\n const commitTransform = useCallback(\n (nextDocument: TextDocument, nextSelection = selectionRef.current) => {\n if (documentsEqual(documentRef.current, nextDocument)) {\n updateSelection(nextSelection);\n restoreSelectionRef.current = nextSelection;\n return;\n }\n\n pushHistory(documentRef.current, selectionRef.current);\n emitDocument(nextDocument, nextSelection);\n },\n [emitDocument, pushHistory, updateSelection],\n );\n\n const undo = useCallback(() => {\n const history = historyRef.current;\n const previous = history.undo.pop();\n if (!previous) return;\n history.redo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(previous.document, previous.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const redo = useCallback(() => {\n const history = historyRef.current;\n const next = history.redo.pop();\n if (!next) return;\n history.undo.push({\n document: documentRef.current,\n selection: selectionRef.current,\n });\n clearTypingGroup();\n emitDocument(next.document, next.selection);\n }, [clearTypingGroup, emitDocument]);\n\n const getActiveMarks = useCallback(\n (): TextMark[] =>\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n pendingMarksOverrideRef.current,\n ),\n [],\n );\n\n const isActive = useCallback(\n (mark: TextMark): boolean => getActiveMarks().includes(mark),\n [getActiveMarks],\n );\n\n const getActiveTextVariant = useCallback(\n (): TextBlockVariant | null =>\n getVariantForSelection(documentRef.current, selectionRef.current),\n [],\n );\n\n const isTextVariantActive = useCallback(\n (variant: TextBlockVariant): boolean =>\n getActiveTextVariant() === variant,\n [getActiveTextVariant],\n );\n\n const toggleMark = useCallback(\n (mark: TextMark) => {\n focus();\n const selection = selectionRef.current;\n if (isCollapsedSelection(selection)) {\n const pending = new Set(getActiveMarks());\n if (pending.has(mark)) pending.delete(mark);\n else pending.add(mark);\n pendingMarksRef.current = [\"bold\", \"italic\", \"underline\", \"strike\"]\n .filter(isMark)\n .filter((item) => pending.has(item));\n pendingMarksOverrideRef.current = true;\n onActiveMarksChange?.(\n getMarksForSelection(\n documentRef.current,\n selectionRef.current,\n pendingMarksRef.current,\n true,\n ),\n );\n return;\n }\n\n commitTransform(applyMark(documentRef.current, selection, mark));\n },\n [commitTransform, focus, getActiveMarks, onActiveMarksChange],\n );\n\n const changeVariant = useCallback(\n (variant: TextBlockVariant) => {\n focus();\n commitTransform(\n setTextVariant(documentRef.current, selectionRef.current, variant),\n );\n },\n [commitTransform, focus],\n );\n\n const changeAlign = useCallback(\n (align: TextAlign) => {\n focus();\n commitTransform(\n setTextAlign(documentRef.current, selectionRef.current, align),\n );\n },\n [commitTransform, focus],\n );\n\n const isTextAlignActive = useCallback((align: TextAlign): boolean => {\n const currentAlign = getTextAlign(\n documentRef.current,\n selectionRef.current,\n );\n return (\n currentAlign === align || (currentAlign === null && align === \"left\")\n );\n }, []);\n\n const changeListType = useCallback(\n (listType: TextListType | null) => {\n focus();\n commitTransform(\n setListType(documentRef.current, selectionRef.current, listType),\n );\n },\n [commitTransform, focus],\n );\n\n const isListTypeActive = useCallback((listType: TextListType): boolean => {\n return getListType(documentRef.current, selectionRef.current, listType);\n }, []);\n\n const replaceSelection = useCallback(\n (insertedDocument: TextDocument) => {\n focus();\n const result = insertDocumentAtSelection(\n documentRef.current,\n selectionRef.current,\n insertedDocument,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n const insertText = useCallback(\n (text: string) => {\n focus();\n const result = insertTextAtSelection(\n documentRef.current,\n selectionRef.current,\n text,\n pendingMarksRef.current,\n );\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n commitTransform(result.document, result.selection);\n },\n [commitTransform, focus],\n );\n\n useImperativeHandle(\n forwardedRef,\n () => ({\n focus,\n getDocument: () => documentRef.current,\n getSelection: () => selectionRef.current,\n getActiveMarks,\n isActive,\n getActiveTextVariant,\n isTextVariantActive,\n toggleMark,\n setTextVariant: changeVariant,\n setTextAlign: changeAlign,\n isTextAlignActive,\n setListType: changeListType,\n isListTypeActive,\n insertText,\n replaceSelection,\n undo,\n redo,\n canUndo: () => historyRef.current.undo.length > 0,\n canRedo: () => historyRef.current.redo.length > 0,\n }),\n [\n changeAlign,\n changeListType,\n changeVariant,\n focus,\n isTextAlignActive,\n getActiveMarks,\n getActiveTextVariant,\n insertText,\n isActive,\n isTextVariantActive,\n redo,\n replaceSelection,\n toggleMark,\n undo,\n ],\n );\n\n useEffect(() => {\n if (!value || value === documentRef.current) return;\n const normalized = normalizeTextDocument(value);\n renderDomOnDocumentChangeRef.current = true;\n documentRef.current = normalized;\n const selection = createTextSelection();\n selectionRef.current = selection;\n restoreSelectionRef.current = selection;\n historyRef.current = {\n undo: [],\n redo: [],\n lastInputType: \"\",\n lastInputAt: 0,\n };\n setDocumentState(normalized);\n updateSelection(selection);\n }, [value, updateSelection]);\n\n useLayoutEffect(() => {\n const root = editableRef.current;\n if (!root) return;\n\n if (renderDomOnDocumentChangeRef.current) {\n renderDocumentToDom(root, documentState);\n }\n // Each document-state commit consumes the render decision. Native input\n // skips a DOM render; commands/external value changes explicitly enable it.\n renderDomOnDocumentChangeRef.current = true;\n\n const selection = restoreSelectionRef.current;\n if (!selection) return;\n restoreSelectionRef.current = null;\n restoreSelection(selection);\n }, [documentState, restoreSelection]);\n\n useEffect(() => {\n onActiveMarksChange?.(getActiveMarks());\n onActiveTextVariantChange?.(getActiveTextVariant());\n }, [\n getActiveMarks,\n getActiveTextVariant,\n onActiveMarksChange,\n onActiveTextVariantChange,\n ]);\n\n useEffect(() => {\n if (autoFocus) focus();\n }, [autoFocus, focus]);\n\n useEffect(() => {\n const ownerDocument = editableRef.current?.ownerDocument;\n if (!ownerDocument) return;\n\n const onSelectionChangeInDocument = () => {\n const root = editableRef.current;\n if (!root) return;\n const next = selectionFromDom(root);\n if (!next) return;\n const current = selectionRef.current;\n if (\n next.anchor.block === current.anchor.block &&\n next.anchor.offset === current.anchor.offset &&\n next.focus.block === current.focus.block &&\n next.focus.offset === current.focus.offset\n ) {\n return;\n }\n updateSelection(next);\n };\n\n ownerDocument.addEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n return () =>\n ownerDocument.removeEventListener(\n \"selectionchange\",\n onSelectionChangeInDocument,\n );\n }, [updateSelection]);\n\n const handleBeforeInput = (event: FormEvent<HTMLDivElement>) => {\n const nativeEvent = event.nativeEvent as InputEvent;\n const inputType = nativeEvent.inputType ?? \"\";\n inputTypeRef.current = inputType;\n selectionBeforeInputRef.current =\n selectionFromDom(event.currentTarget) ?? selectionRef.current;\n\n if (inputType === \"historyUndo\") {\n event.preventDefault();\n undo();\n } else if (inputType === \"historyRedo\") {\n event.preventDefault();\n redo();\n }\n };\n\n const handleInput = (event: FormEvent<HTMLDivElement>) => {\n const root = event.currentTarget;\n const previousDocument = documentRef.current;\n const beforeSelection = selectionBeforeInputRef.current;\n const inputType = inputTypeRef.current;\n let nextDocument = parseHtmlToDocument(root.innerHTML);\n const nextSelection = selectionFromDom(root) ?? selectionRef.current;\n\n if (\n pendingMarksRef.current.length &&\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" || inputType === \"insertCompositionText\")\n ) {\n const insertedRange = {\n anchor: beforeSelection.anchor,\n focus: nextSelection.focus,\n };\n if (!isCollapsedSelection(insertedRange)) {\n for (const mark of pendingMarksRef.current) {\n nextDocument = applyMark(nextDocument, insertedRange, mark, true);\n }\n }\n }\n\n if (documentsEqual(previousDocument, nextDocument)) {\n updateSelection(nextSelection);\n return;\n }\n\n const now = Date.now();\n const canGroup =\n isCollapsedSelection(beforeSelection) &&\n (inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"deleteContentBackward\" ||\n inputType === \"deleteContentForward\") &&\n historyRef.current.lastInputType === inputType &&\n now - historyRef.current.lastInputAt < 800;\n\n if (!canGroup) {\n historyRef.current.undo.push({\n document: previousDocument,\n selection: beforeSelection,\n });\n if (historyRef.current.undo.length > 100)\n historyRef.current.undo.shift();\n }\n\n historyRef.current.redo = [];\n historyRef.current.lastInputType = inputType;\n historyRef.current.lastInputAt = now;\n documentRef.current = normalizeTextDocument(nextDocument);\n if (\n inputType === \"insertText\" ||\n inputType === \"insertCompositionText\" ||\n inputType === \"insertFromPaste\"\n ) {\n pendingMarksRef.current = [];\n pendingMarksOverrideRef.current = false;\n }\n restoreSelectionRef.current = nextSelection;\n updateSelection(nextSelection);\n renderDomOnDocumentChangeRef.current = false;\n setDocumentState(documentRef.current);\n onChange?.(documentRef.current);\n };\n\n const handlePaste = (event: ClipboardEvent<HTMLDivElement>) => {\n if (readOnly) return;\n event.preventDefault();\n const currentSelection = selectionFromDom(event.currentTarget);\n if (currentSelection) updateSelection(currentSelection);\n const html = event.clipboardData.getData(\"text/html\");\n const plainText = event.clipboardData.getData(\"text/plain\");\n if (!html.trim() && !plainText) return;\n const parsed = html.trim()\n ? parseHtmlToDocument(html)\n : parseMarkdownToDocument(plainText);\n replaceSelection(parsed);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const modifier = event.metaKey || event.ctrlKey;\n if (!modifier) return;\n const key = event.key.toLowerCase();\n\n if (key === \"z\") {\n event.preventDefault();\n if (event.shiftKey) redo();\n else undo();\n } else if (key === \"y\") {\n event.preventDefault();\n redo();\n } else if (key === \"b\") {\n event.preventDefault();\n toggleMark(\"bold\");\n } else if (key === \"i\") {\n event.preventDefault();\n toggleMark(\"italic\");\n } else if (key === \"u\") {\n event.preventDefault();\n toggleMark(\"underline\");\n } else if (key === \"x\" && event.shiftKey) {\n event.preventDefault();\n toggleMark(\"strike\");\n }\n };\n\n const handleKeyUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n const handleMouseUp = () => {\n const root = editableRef.current;\n const next = root ? selectionFromDom(root) : null;\n if (next) updateSelection(next);\n };\n\n return (\n <div\n ref={editableRef}\n className={cn(\"puzzle-text-editor\", className)}\n contentEditable={!readOnly}\n suppressContentEditableWarning\n role=\"textbox\"\n aria-label={ariaLabel}\n aria-multiline=\"true\"\n aria-readonly={readOnly || undefined}\n data-placeholder={placeholder}\n data-empty={\n documentState.content.every((block) =>\n block.children.every((inline) => !inline.text),\n )\n ? \"true\"\n : undefined\n }\n spellCheck\n onBeforeInput={handleBeforeInput}\n onInput={handleInput}\n onPaste={handlePaste}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onMouseUp={handleMouseUp}\n onFocus={handleKeyUp}\n />\n );\n },\n);\n\nEditor.displayName = \"Editor\";\n\nexport { Editor, type TextEditorHandle, type EditorProps };\n"],"mappings":"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"}