quoin-editor 2.0.5 → 2.1.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 (215) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/MIGRATION.md +1 -1
  3. package/README.md +4 -3
  4. package/dist/ai.cjs +124 -94
  5. package/dist/ai.d.cts +7 -0
  6. package/dist/ai.d.ts +7 -0
  7. package/dist/ai.js +50 -20
  8. package/dist/ai.js.map +1 -1
  9. package/dist/catalogue.cjs +28 -26
  10. package/dist/catalogue.js +19 -17
  11. package/dist/catalogue.js.map +1 -1
  12. package/dist/{chunk-JGEDJYIV.cjs → chunk-2FUWXPPC.cjs} +92 -98
  13. package/dist/{chunk-NHNW5DK3.js → chunk-3F76QQ65.js} +6 -6
  14. package/dist/{chunk-NHNW5DK3.js.map → chunk-3F76QQ65.js.map} +1 -1
  15. package/dist/{chunk-DBOZFNWU.js → chunk-3QYFAAQR.js} +3 -3
  16. package/dist/{chunk-DBOZFNWU.js.map → chunk-3QYFAAQR.js.map} +1 -1
  17. package/dist/{chunk-I7X7B3WD.cjs → chunk-4JDRDPLC.cjs} +17 -8
  18. package/dist/{chunk-EBSDPHPS.cjs → chunk-4UFWFV43.cjs} +1060 -719
  19. package/dist/{chunk-LM3DHROX.cjs → chunk-5AUIA4B3.cjs} +2 -2
  20. package/dist/{chunk-3INFNIGN.cjs → chunk-5H3BB5VJ.cjs} +131 -78
  21. package/dist/{chunk-DJU25PFC.cjs → chunk-5L2NSIHZ.cjs} +11 -11
  22. package/dist/{chunk-W376L2GM.js → chunk-6Y7JAWYY.js} +8 -8
  23. package/dist/chunk-6Y7JAWYY.js.map +1 -0
  24. package/dist/{chunk-UDBLZILE.js → chunk-ATKDXQEY.js} +12 -7
  25. package/dist/{chunk-UDBLZILE.js.map → chunk-ATKDXQEY.js.map} +1 -1
  26. package/dist/{chunk-A2IQHMIH.js → chunk-BE2SYPK5.js} +49 -54
  27. package/dist/chunk-BE2SYPK5.js.map +1 -0
  28. package/dist/{chunk-PURYVDC3.cjs → chunk-CFICD2JP.cjs} +21 -16
  29. package/dist/{chunk-3HW3WRYC.cjs → chunk-CSIUXYRU.cjs} +2 -2
  30. package/dist/{chunk-N7BSFDDM.cjs → chunk-DBKL524I.cjs} +23 -23
  31. package/dist/{chunk-XE3IYW5B.js → chunk-DEFYFIWW.js} +90 -37
  32. package/dist/chunk-DEFYFIWW.js.map +1 -0
  33. package/dist/{chunk-7E43TURF.cjs → chunk-ECI3PSMS.cjs} +7 -7
  34. package/dist/{chunk-4G645EYO.js → chunk-F73QEF7E.js} +5 -5
  35. package/dist/{chunk-4G645EYO.js.map → chunk-F73QEF7E.js.map} +1 -1
  36. package/dist/{chunk-KHRVCTQQ.cjs → chunk-FUT7XLMP.cjs} +61 -74
  37. package/dist/{chunk-7J63427U.cjs → chunk-GQSBOBOM.cjs} +375 -320
  38. package/dist/{chunk-LU3T3JB4.js → chunk-HPNSQWRD.js} +15 -28
  39. package/dist/chunk-HPNSQWRD.js.map +1 -0
  40. package/dist/{chunk-7Y4B7NHO.js → chunk-I34BFOLL.js} +18 -11
  41. package/dist/chunk-I34BFOLL.js.map +1 -0
  42. package/dist/{chunk-AJT54OMZ.js → chunk-IFRXEFQH.js} +9 -15
  43. package/dist/chunk-IFRXEFQH.js.map +1 -0
  44. package/dist/{chunk-YYW33WUL.cjs → chunk-K3XWVRL4.cjs} +8 -8
  45. package/dist/{chunk-LSI4RMTY.js → chunk-L5L6YNLT.js} +3 -3
  46. package/dist/{chunk-LSI4RMTY.js.map → chunk-L5L6YNLT.js.map} +1 -1
  47. package/dist/{chunk-2BPXVQBP.js → chunk-MO4UMXMT.js} +238 -86
  48. package/dist/chunk-MO4UMXMT.js.map +1 -0
  49. package/dist/{chunk-2QKFRKOP.cjs → chunk-N25EH2GZ.cjs} +351 -205
  50. package/dist/{chunk-CSPCDVCT.js → chunk-NCV2ML25.js} +3 -3
  51. package/dist/{chunk-CSPCDVCT.js.map → chunk-NCV2ML25.js.map} +1 -1
  52. package/dist/{chunk-NUQ64S5B.cjs → chunk-OJSKSQTL.cjs} +26 -26
  53. package/dist/chunk-PIWMU4BV.js +9 -0
  54. package/dist/chunk-PIWMU4BV.js.map +1 -0
  55. package/dist/chunk-QFGWSFOI.cjs +10 -0
  56. package/dist/{chunk-GPTJYWGS.js → chunk-RNBLVGWY.js} +3 -3
  57. package/dist/{chunk-GPTJYWGS.js.map → chunk-RNBLVGWY.js.map} +1 -1
  58. package/dist/{chunk-5RBMZGKV.js → chunk-TL2MJOWM.js} +325 -57
  59. package/dist/chunk-TL2MJOWM.js.map +1 -0
  60. package/dist/{chunk-YEDPBYO5.cjs → chunk-UDQ52EEC.cjs} +4 -4
  61. package/dist/{chunk-EIWPJWY3.js → chunk-UE2NQPNG.js} +5 -5
  62. package/dist/{chunk-EIWPJWY3.js.map → chunk-UE2NQPNG.js.map} +1 -1
  63. package/dist/{chunk-BE2YHZXA.cjs → chunk-ULV3SCYP.cjs} +26 -15
  64. package/dist/{chunk-WDBFGX3U.cjs → chunk-VTTMJGWP.cjs} +72 -77
  65. package/dist/{chunk-556PFYES.js → chunk-WK4UGDZN.js} +290 -235
  66. package/dist/chunk-WK4UGDZN.js.map +1 -0
  67. package/dist/{chunk-JZF6UQH5.cjs → chunk-WMKA37NJ.cjs} +12 -12
  68. package/dist/{chunk-F2ZK6Z52.js → chunk-Y26F2X4E.js} +3 -3
  69. package/dist/{chunk-F2ZK6Z52.js.map → chunk-Y26F2X4E.js.map} +1 -1
  70. package/dist/{chunk-FK7EBZPX.cjs → chunk-Z5EEDCRI.cjs} +549 -276
  71. package/dist/{chunk-G6NBQYMM.js → chunk-ZGFZRVQA.js} +817 -478
  72. package/dist/chunk-ZGFZRVQA.js.map +1 -0
  73. package/dist/{chunk-QLVX7MPS.js → chunk-ZQF45LA4.js} +19 -8
  74. package/dist/chunk-ZQF45LA4.js.map +1 -0
  75. package/dist/comments.cjs +127 -65
  76. package/dist/comments.d.cts +35 -2
  77. package/dist/comments.d.ts +35 -2
  78. package/dist/comments.js +73 -12
  79. package/dist/comments.js.map +1 -1
  80. package/dist/{diagram-extension-22x_njXB.d.ts → diagram-extension-BMlh8GCw.d.ts} +1 -1
  81. package/dist/{diagram-extension-C_FSkoj9.d.cts → diagram-extension-gmndUpti.d.cts} +1 -1
  82. package/dist/diagram.cjs +10 -9
  83. package/dist/diagram.d.cts +2 -2
  84. package/dist/diagram.d.ts +2 -2
  85. package/dist/diagram.js +7 -6
  86. package/dist/diff.cjs +25 -25
  87. package/dist/diff.js +3 -3
  88. package/dist/docx.cjs +31 -30
  89. package/dist/docx.js +5 -4
  90. package/dist/docx.js.map +1 -1
  91. package/dist/embed.cjs +10 -9
  92. package/dist/embed.js +8 -7
  93. package/dist/{emoji-extension-Dk5IQLZf.d.cts → emoji-extension-DD9CQTQj.d.cts} +1 -1
  94. package/dist/{emoji-extension-C832oGeT.d.ts → emoji-extension-U_PWZ2fX.d.ts} +1 -1
  95. package/dist/emoji.cjs +10 -9
  96. package/dist/emoji.d.cts +2 -2
  97. package/dist/emoji.d.ts +2 -2
  98. package/dist/emoji.js +7 -6
  99. package/dist/engine.cjs +58 -58
  100. package/dist/engine.d.cts +3 -3
  101. package/dist/engine.d.ts +3 -3
  102. package/dist/engine.js +3 -3
  103. package/dist/{find-extension-DmK9_N81.d.ts → find-extension-BGlqooZi.d.ts} +1 -1
  104. package/dist/{find-extension-BfruAPLi.d.cts → find-extension-BPnAJ8bY.d.cts} +1 -1
  105. package/dist/find.cjs +11 -10
  106. package/dist/find.d.cts +1 -1
  107. package/dist/find.d.ts +1 -1
  108. package/dist/find.js +7 -6
  109. package/dist/headless.cjs +70 -69
  110. package/dist/headless.d.cts +33 -10
  111. package/dist/headless.d.ts +33 -10
  112. package/dist/headless.js +5 -4
  113. package/dist/highlight.cjs +7 -6
  114. package/dist/highlight.js +6 -5
  115. package/dist/highlight.js.map +1 -1
  116. package/dist/{index-3fYvwqUZ.d.cts → index-DN7vRKFw.d.cts} +1 -1
  117. package/dist/{index-CgxnzCO5.d.ts → index-DyIYI3PM.d.ts} +1 -1
  118. package/dist/index.cjs +82 -81
  119. package/dist/index.d.cts +19 -12
  120. package/dist/index.d.ts +19 -12
  121. package/dist/index.js +6 -5
  122. package/dist/{labels-CiCxj2jP.d.cts → labels-BJORhN93.d.ts} +10 -5
  123. package/dist/{labels-BhRJYo46.d.ts → labels-CVYJ2-1X.d.cts} +10 -5
  124. package/dist/locale-ar.cjs +10 -0
  125. package/dist/locale-ar.d.cts +1 -1
  126. package/dist/locale-ar.d.ts +1 -1
  127. package/dist/locale-ar.js +10 -0
  128. package/dist/locale-ar.js.map +1 -1
  129. package/dist/locale-de.cjs +4 -0
  130. package/dist/locale-de.d.cts +1 -1
  131. package/dist/locale-de.d.ts +1 -1
  132. package/dist/locale-de.js +4 -0
  133. package/dist/locale-de.js.map +1 -1
  134. package/dist/locale-es.cjs +4 -0
  135. package/dist/locale-es.d.cts +1 -1
  136. package/dist/locale-es.d.ts +1 -1
  137. package/dist/locale-es.js +4 -0
  138. package/dist/locale-es.js.map +1 -1
  139. package/dist/locale-fr.cjs +4 -0
  140. package/dist/locale-fr.d.cts +1 -1
  141. package/dist/locale-fr.d.ts +1 -1
  142. package/dist/locale-fr.js +4 -0
  143. package/dist/locale-fr.js.map +1 -1
  144. package/dist/locale-ja.cjs +4 -0
  145. package/dist/locale-ja.d.cts +1 -1
  146. package/dist/locale-ja.d.ts +1 -1
  147. package/dist/locale-ja.js +4 -0
  148. package/dist/locale-ja.js.map +1 -1
  149. package/dist/locale-pt.cjs +4 -0
  150. package/dist/locale-pt.d.cts +1 -1
  151. package/dist/locale-pt.d.ts +1 -1
  152. package/dist/locale-pt.js +4 -0
  153. package/dist/locale-pt.js.map +1 -1
  154. package/dist/locale-zh.cjs +4 -0
  155. package/dist/locale-zh.d.cts +1 -1
  156. package/dist/locale-zh.d.ts +1 -1
  157. package/dist/locale-zh.js +4 -0
  158. package/dist/locale-zh.js.map +1 -1
  159. package/dist/math.cjs +11 -10
  160. package/dist/math.js +9 -8
  161. package/dist/mention.cjs +11 -10
  162. package/dist/mention.js +9 -8
  163. package/dist/{node-reveal-DY6bimv3.d.cts → node-reveal-Be7Xa0BL.d.cts} +1 -1
  164. package/dist/{node-reveal-BnFcnHhz.d.ts → node-reveal-CftIEqF_.d.ts} +1 -1
  165. package/dist/palette-DuIFHYHc.d.cts +10 -0
  166. package/dist/palette-DuIFHYHc.d.ts +10 -0
  167. package/dist/presence.cjs +39 -38
  168. package/dist/presence.js +8 -7
  169. package/dist/presence.js.map +1 -1
  170. package/dist/source.cjs +10 -9
  171. package/dist/source.d.cts +1 -1
  172. package/dist/source.d.ts +1 -1
  173. package/dist/source.js +6 -5
  174. package/dist/source.js.map +1 -1
  175. package/dist/{stats-extension-Dmw0Ujxe.d.ts → stats-extension-Bbpr593p.d.ts} +1 -1
  176. package/dist/{stats-extension-D5HySF0a.d.cts → stats-extension-D7FaeydW.d.cts} +1 -1
  177. package/dist/stats.cjs +12 -10
  178. package/dist/stats.d.cts +2 -2
  179. package/dist/stats.d.ts +2 -2
  180. package/dist/stats.js +9 -7
  181. package/dist/styles.css +1 -1
  182. package/dist/{table-extension-7LkLNK6Q.d.cts → table-extension-DNijjmxV.d.cts} +1 -1
  183. package/dist/{table-extension-DEpV0DnP.d.ts → table-extension-Dp6FYGPh.d.ts} +1 -1
  184. package/dist/table.cjs +26 -25
  185. package/dist/table.d.cts +4 -3
  186. package/dist/table.d.ts +4 -3
  187. package/dist/table.js +7 -6
  188. package/dist/{toc-extension-Dvh37bWQ.d.cts → toc-extension-BGEVAmSY.d.cts} +1 -1
  189. package/dist/{toc-extension-SVckrFmb.d.ts → toc-extension-DZIe40eV.d.ts} +1 -1
  190. package/dist/toc.cjs +10 -9
  191. package/dist/toc.d.cts +2 -2
  192. package/dist/toc.d.ts +2 -2
  193. package/dist/toc.js +7 -6
  194. package/dist/{types-DMuuDBVh.d.ts → types-Byu2a9qk.d.ts} +6 -1
  195. package/dist/{types-Bzhq5AXj.d.cts → types-DdDlCyyZ.d.cts} +6 -1
  196. package/dist/view.cjs +4 -4
  197. package/dist/view.js +2 -2
  198. package/dist/yjs.cjs +121 -121
  199. package/dist/yjs.d.cts +2 -2
  200. package/dist/yjs.d.ts +2 -2
  201. package/dist/yjs.js +5 -5
  202. package/package.json +4 -3
  203. package/dist/chunk-2BPXVQBP.js.map +0 -1
  204. package/dist/chunk-556PFYES.js.map +0 -1
  205. package/dist/chunk-5RBMZGKV.js.map +0 -1
  206. package/dist/chunk-7Y4B7NHO.js.map +0 -1
  207. package/dist/chunk-A2IQHMIH.js.map +0 -1
  208. package/dist/chunk-AJT54OMZ.js.map +0 -1
  209. package/dist/chunk-G6NBQYMM.js.map +0 -1
  210. package/dist/chunk-LU3T3JB4.js.map +0 -1
  211. package/dist/chunk-QLVX7MPS.js.map +0 -1
  212. package/dist/chunk-W376L2GM.js.map +0 -1
  213. package/dist/chunk-XE3IYW5B.js.map +0 -1
  214. package/dist/palette-BrX-hEd-.d.cts +0 -4
  215. package/dist/palette-BrX-hEd-.d.ts +0 -4
@@ -1,14 +1,13 @@
1
- import { Table, FOCUS_RING, interceptKeys, DropdownMenuCheckboxItem, DropdownMenuSeparator, DropdownMenuRadioGroup, DropdownMenuRadioItem, MenuIcon, keepFocus, Plus, DropdownMenu, DropdownMenuTrigger, GripVertical, GripHorizontal, DropdownMenuContent, bubblePart, returnFocusToText, AlignLeft, AlignCenter, AlignRight, DropdownMenuItem, ArrowUpToLine, ArrowDownToLine, ArrowUp, ArrowDown, Trash, ArrowLeftToLine, ArrowRightToLine, ArrowLeft, ArrowRight } from './chunk-G6NBQYMM.js';
2
- import { useEditorState, EditableRegion, useReadOnly, useIsomorphicLayoutEffect, isComposingKey, handleCopy, inlineDirection, neighbourBlock, NATIVE_INTERACTION, posToDom, isOnFirstLine, isOnLastLine, caretClientRect, lineEdgeRect, caretFromPoint, domToPos } from './chunk-2BPXVQBP.js';
1
+ import { Table, FOCUS_RING, interceptKeys, watchDirection, DropdownMenuCheckboxItem, DropdownMenuSeparator, DropdownMenuRadioGroup, DropdownMenuRadioItem, MenuIcon, keepFocus, Plus, DropdownMenu, DropdownMenuTrigger, GripVertical, GripHorizontal, DropdownMenuContent, bubblePart, returnFocusToText, AlignLeft, AlignCenter, AlignRight, DropdownMenuItem, ArrowUpToLine, ArrowDownToLine, ArrowUp, ArrowDown, Trash, ArrowLeftToLine, ArrowRightToLine, ArrowLeft, ArrowRight } from './chunk-ZGFZRVQA.js';
2
+ import { useEditorState, EditableRegion, useReadOnly, useIsomorphicLayoutEffect, isComposingKey, neighbourBlock, NATIVE_INTERACTION, inlineDirection, posToDom, isOnFirstLine, isOnLastLine, caretClientRect, lineEdgeRect, caretFromPoint, domToPos, arrowAsWritten } from './chunk-MO4UMXMT.js';
3
3
  import { mergeLabels } from './chunk-DLQCTGC3.js';
4
- import { createPluginKey, markCoverage, toggleMark, setMark, Transaction, textSelection, headBlockId, isParagraph, regionLength, primaryRegion, replaceBlockStep, insertBlocksStep, descendantsEnd, defineExtension, replaceInlineStep, isCollapsed, insertHardBreak, insertTextAt } from './chunk-5RBMZGKV.js';
5
- import { cellKey, blockById, inlineLength, requireBlockIndex, newId, countOf, sameItems, equalInline } from './chunk-7Y4B7NHO.js';
4
+ import { createPluginKey, markCoverage, toggleMark, setMark, Transaction, textSelection, cellOf, cellsBetween, headBlockId, isParagraph, regionLength, primaryRegion, replaceBlockStep, insertBlocksStep, descendantsEnd, defineExtension, deleteRange, isCollapsed, insertHardBreak, sliceFromClipboard, orderedRange, replaceInlineStep, insertTextAt, isTextFlow } from './chunk-TL2MJOWM.js';
5
+ import { cellKey, blockById, inlineLength, requireBlockIndex, newId, countOf, createBlockCodec, validWidths, sameItems, equalInline } from './chunk-I34BFOLL.js';
6
6
  import { memo, useCallback, useRef, useState, useEffect, useSyncExternalStore, Fragment as Fragment$1 } from 'react';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import { createPortal } from 'react-dom';
9
9
 
10
10
  // src/engine/commands/table-shape.ts
11
- var CELL = /^cell:(\d+):(\d+)$/;
12
11
  var tableShape = (block) => ({
13
12
  rows: countOf(block.attrs.rows),
14
13
  cols: countOf(block.attrs.cols)
@@ -18,12 +17,7 @@ var columnAligns = (block, cols) => Array.from({ length: cols }, (_, col) => {
18
17
  const align = Array.isArray(block.attrs.align) ? block.attrs.align[col] : null;
19
18
  return ALIGNS.includes(align) ? align : null;
20
19
  });
21
- var validWidths = (value, cols) => Array.isArray(value) && value.length === cols && value.every((width) => typeof width === "number" && width > 0) ? value : null;
22
20
  var storedWidths = (block, cols) => validWidths(block.attrs.widths, cols);
23
- function cellOf(region) {
24
- const match = CELL.exec(region);
25
- return match === null ? null : [Number(match[1]), Number(match[2])];
26
- }
27
21
  function tableBlock(doc, id) {
28
22
  const block = blockById(doc, id);
29
23
  return block?.type === "TABLE" ? block : null;
@@ -83,85 +77,23 @@ function cellSelection(state) {
83
77
  }
84
78
  var between = (value, a, b) => value >= Math.min(a, b) && value <= Math.max(a, b);
85
79
  var rangeHasCell = ({ anchor, head }, [row, col]) => between(row, anchor[0], head[0]) && between(col, anchor[1], head[1]);
86
- function cellsInRange({ anchor, head }) {
87
- const cells = [];
88
- for (let row = Math.min(anchor[0], head[0]); row <= Math.max(anchor[0], head[0]); row++) {
89
- for (let col = Math.min(anchor[1], head[1]); col <= Math.max(anchor[1], head[1]); col++) cells.push([row, col]);
90
- }
91
- return cells;
92
- }
80
+ var cellsInRange = ({ anchor, head }) => cellsBetween(anchor, head);
93
81
  function selectCells(blockId, anchor, head) {
94
82
  return (state, dispatch) => {
95
83
  const block = tableBlock(state.doc, blockId);
96
84
  const { rows, cols } = block === null ? { rows: 0, cols: 0 } : tableShape(block);
97
85
  const inside = ([row, col]) => isIndex(row, rows) && isIndex(col, cols);
98
86
  if (block === null || !inside(anchor) || !inside(head)) return false;
99
- const end2 = cellKey(...head);
87
+ const end = cellKey(...head);
100
88
  const selection = textSelection(
101
89
  { block: blockId, region: cellKey(...anchor), offset: 0 },
102
- { block: blockId, region: end2, offset: inlineLength(block.regions[end2] ?? []) }
90
+ { block: blockId, region: end, offset: inlineLength(block.regions[end] ?? []) }
103
91
  );
104
92
  dispatch?.(new Transaction(state).setSelection(selection));
105
93
  return true;
106
94
  };
107
95
  }
108
96
 
109
- // src/engine/commands/cell-commands.ts
110
- function filledCells(doc, range) {
111
- const regions = blockById(doc, range.block)?.regions ?? {};
112
- return cellsInRange(range).flatMap((cell) => {
113
- const region = cellKey(...cell);
114
- const length = inlineLength(regions[region] ?? []);
115
- return length > 0 ? [{ region, length }] : [];
116
- });
117
- }
118
- function firstCell({ block, anchor, head }) {
119
- return { block, region: cellKey(Math.min(anchor[0], head[0]), Math.min(anchor[1], head[1])), offset: 0 };
120
- }
121
- function emptied(state, range) {
122
- const tr = new Transaction(state);
123
- for (const { region, length } of filledCells(state.doc, range)) {
124
- tr.step(replaceInlineStep(range.block, region, 0, length, []));
125
- }
126
- return tr;
127
- }
128
- var deleteCellContents = (state, dispatch) => {
129
- const range = cellSelection(state);
130
- if (range === null) return false;
131
- dispatch?.(emptied(state, range).setSelection(textSelection(firstCell(range))));
132
- return true;
133
- };
134
- function typeOverCells(text) {
135
- return (state, dispatch) => {
136
- const range = cellSelection(state);
137
- if (range === null || text === "") return false;
138
- const tr = emptied(state, range);
139
- dispatch?.(tr.setSelection(textSelection(insertTextAt(tr, state.schema, firstCell(range), text))));
140
- return true;
141
- };
142
- }
143
- function setCellsMark(type, attrs) {
144
- return (state, dispatch) => {
145
- const range = cellSelection(state);
146
- const cells = range === null ? [] : filledCells(state.doc, range);
147
- const regions = range === null ? void 0 : blockById(state.doc, range.block)?.regions;
148
- if (range === null || regions === void 0 || cells.length === 0) return false;
149
- const carried = cells.every(({ region }) => markCoverage(regions[region], type, attrs).every);
150
- const mark = carried ? toggleMark(type, attrs) : setMark(type, attrs);
151
- const tr = new Transaction(state);
152
- for (const { region, length } of cells) {
153
- const start = { block: range.block, region, offset: 0 };
154
- const whole = textSelection(start, { ...start, offset: length });
155
- mark({ ...state, doc: tr.doc, selection: whole, storedMarks: null }, (cell) => {
156
- for (const step of cell.steps) tr.step(step);
157
- });
158
- }
159
- if (!tr.docChanged) return false;
160
- dispatch?.(tr);
161
- return true;
162
- };
163
- }
164
-
165
97
  // src/extensions/table/controls-slot.ts
166
98
  var CONTROLS_SLOT = "data-quoin-table-controls";
167
99
  var controlsSlot = (controller, blockId) => controller.blockElement(blockId)?.querySelector(`[${CONTROLS_SLOT}]`) ?? null;
@@ -222,6 +154,60 @@ function useWidthPreview(controller, blockId) {
222
154
  return useSyncExternalStore(store.subscribe, read, read);
223
155
  }
224
156
 
157
+ // src/engine/commands/cell-commands.ts
158
+ function filledCells(doc, range) {
159
+ const regions = blockById(doc, range.block)?.regions ?? {};
160
+ return cellsInRange(range).flatMap((cell) => {
161
+ const region = cellKey(...cell);
162
+ const length = inlineLength(regions[region] ?? []);
163
+ return length > 0 ? [{ region, length }] : [];
164
+ });
165
+ }
166
+ function overCells(state, write) {
167
+ const { selection } = state;
168
+ if (cellSelection(state) === null || selection?.kind !== "text") return null;
169
+ const tr = new Transaction(state);
170
+ return tr.setSelection(textSelection(write(tr, deleteRange(tr, state.schema, selection.anchor, selection.head))));
171
+ }
172
+ var deleteCellContents = (state, dispatch) => {
173
+ const tr = overCells(state, (_, caret) => caret);
174
+ if (tr !== null) dispatch?.(tr);
175
+ return tr !== null;
176
+ };
177
+ function typeOverCells(content) {
178
+ return (state, dispatch) => {
179
+ if (content.length === 0) return false;
180
+ const tr = overCells(state, (into, caret) => {
181
+ if (typeof content === "string") return insertTextAt(into, state.schema, caret, content);
182
+ into.step(replaceInlineStep(caret.block, caret.region, caret.offset, caret.offset, content));
183
+ return { ...caret, offset: caret.offset + inlineLength(content) };
184
+ });
185
+ if (tr !== null) dispatch?.(tr);
186
+ return tr !== null;
187
+ };
188
+ }
189
+ function setCellsMark(type, attrs) {
190
+ return (state, dispatch) => {
191
+ const range = cellSelection(state);
192
+ const cells = range === null ? [] : filledCells(state.doc, range);
193
+ const regions = range === null ? void 0 : blockById(state.doc, range.block)?.regions;
194
+ if (range === null || regions === void 0 || cells.length === 0) return false;
195
+ const carried = cells.every(({ region }) => markCoverage(regions[region], type, attrs).every);
196
+ const mark = carried ? toggleMark(type, attrs) : setMark(type, attrs);
197
+ const tr = new Transaction(state);
198
+ for (const { region, length } of cells) {
199
+ const start = { block: range.block, region, offset: 0 };
200
+ const whole = textSelection(start, { ...start, offset: length });
201
+ mark({ ...state, doc: tr.doc, selection: whole, storedMarks: null }, (cell) => {
202
+ for (const step of cell.steps) tr.step(step);
203
+ });
204
+ }
205
+ if (!tr.docChanged) return false;
206
+ dispatch?.(tr);
207
+ return true;
208
+ };
209
+ }
210
+
225
211
  // src/engine/commands/table-commands.ts
226
212
  function changeTable(blockId, change, plan) {
227
213
  return (state, dispatch) => {
@@ -440,7 +426,7 @@ var tableKeymap = {
440
426
  };
441
427
 
442
428
  // src/extensions/table/use-cell-press.ts
443
- function cellOf2(element) {
429
+ function pressedCell(element) {
444
430
  const row = element.getAttribute("data-row");
445
431
  const col = element.getAttribute("data-col");
446
432
  return element.matches("td, th") && row !== null && col !== null ? [Number(row), Number(col)] : null;
@@ -450,7 +436,7 @@ function useCellPress(controller, blockId, table, editable) {
450
436
  const element = table.current;
451
437
  if (!editable || element === null) return;
452
438
  const onPointerDown = (event) => {
453
- const cell = event.button === 0 && event.pointerType !== "touch" ? cellOf2(event.target) : null;
439
+ const cell = event.button === 0 && event.pointerType !== "touch" ? pressedCell(event.target) : null;
454
440
  const block = cell && blockById(controller.editor.state.doc, blockId);
455
441
  if (!cell || !block) return;
456
442
  event.preventDefault();
@@ -479,87 +465,6 @@ function useRevealCell(controller, blockId) {
479
465
  host.closest("td, th")?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
480
466
  }, [controller, blockId, region]);
481
467
  }
482
-
483
- // src/extensions/table/vertical-cell-move.ts
484
- var VERTICAL = { ArrowUp: -1, ArrowDown: 1 };
485
- function caretAtGoal(controller, blockId, cell, direction) {
486
- const region = cellKey(...cell);
487
- const host = controller.registry.get(blockId, region);
488
- const { goalX } = controller;
489
- const line = host && lineEdgeRect(host, direction < 0);
490
- if (!host || !line || goalX === null) return null;
491
- const box = host.getBoundingClientRect();
492
- const x = Math.min(Math.max(goalX, box.left), box.right - 1);
493
- const point = caretFromPoint(host.ownerDocument, x, line.top + line.height / 2);
494
- const pos = point && domToPos(controller.registry, point.node, point.offset);
495
- return pos && pos.block === blockId && pos.region === region ? pos : null;
496
- }
497
- var plainArrow = (event) => event.altKey || event.ctrlKey || event.metaKey ? void 0 : VERTICAL[event.key];
498
- function caretOnEdgeLine(controller, head, direction) {
499
- const host = controller.registry.get(head.block, head.region);
500
- const point = posToDom(controller.registry, head);
501
- if (!host || !point || !(direction < 0 ? isOnFirstLine(host, point) : isOnLastLine(host, point))) return null;
502
- return { left: caretClientRect(point)?.left ?? null };
503
- }
504
- function columnAt(controller, blockId, row, x) {
505
- const cells = Array.from(controller.blockElement(blockId)?.querySelector("table")?.rows[row]?.cells ?? []);
506
- const index = cells.findIndex((cell) => x < cell.getBoundingClientRect().right);
507
- return index === -1 ? Math.max(cells.length - 1, 0) : index;
508
- }
509
- function enterTable(controller, blockId, event) {
510
- const direction = plainArrow(event);
511
- const { state } = controller.editor;
512
- const { selection } = state;
513
- const block = tableBlock(state.doc, blockId);
514
- if (direction === void 0 || event.shiftKey || block === null || selection?.kind !== "text") return false;
515
- if (!isCollapsed(selection) || neighbourBlock(state.doc, selection.head.block, direction)?.id !== blockId) return false;
516
- const caret = caretOnEdgeLine(controller, selection.head, direction);
517
- if (caret === null) return false;
518
- controller.goalX ??= caret.left;
519
- const { rows, cols } = tableShape(block);
520
- const row = direction > 0 ? 0 : rows - 1;
521
- const { goalX } = controller;
522
- const cell = [row, goalX === null ? direction > 0 ? 0 : cols - 1 : columnAt(controller, blockId, row, goalX)];
523
- const pos = caretAtGoal(controller, blockId, cell, direction) ?? cellPos(block, cell, direction < 0);
524
- controller.dispatch(controller.editor.createTransaction().setSelection(textSelection(pos)));
525
- return true;
526
- }
527
- function moveBetweenRows(controller, blockId, event) {
528
- const direction = plainArrow(event);
529
- const { state } = controller.editor;
530
- const caret = headCell(state);
531
- if (direction === void 0 || caret === null || caret.block.id !== blockId || state.selection?.kind !== "text") {
532
- return false;
533
- }
534
- const target = [caret.cell[0] + direction, caret.cell[1]];
535
- if (target[0] < 0 || target[0] >= caret.shape.rows) return false;
536
- const edge = caretOnEdgeLine(controller, caret.head, direction);
537
- if (edge === null) return false;
538
- controller.goalX ??= edge.left;
539
- const pos = caretAtGoal(controller, blockId, target, direction) ?? cellPos(caret.block, target, direction < 0);
540
- const selection = event.shiftKey ? textSelection(state.selection.anchor, pos) : textSelection(pos);
541
- controller.dispatch(controller.editor.createTransaction().setSelection(selection));
542
- return true;
543
- }
544
-
545
- // src/extensions/table/use-table-keys.ts
546
- var printable = (event) => [...event.key].length === 1 && !event.ctrlKey && !event.metaKey;
547
- function typeOver(controller, blockId, event) {
548
- if (cellSelection(controller.editor.state)?.block !== blockId || !printable(event)) return false;
549
- return controller.run(typeOverCells(event.key));
550
- }
551
- function useTableKeys(controller, blockId, editable) {
552
- useEffect(() => {
553
- if (!editable) return;
554
- const intercept = (event) => {
555
- if (isComposingKey(controller, event)) return false;
556
- const handled = typeOver(controller, blockId, event) || moveBetweenRows(controller, blockId, event) || enterTable(controller, blockId, event);
557
- if (handled) event.preventDefault();
558
- return handled;
559
- };
560
- return interceptKeys(controller, intercept);
561
- }, [controller, blockId, editable]);
562
- }
563
468
  var indexes = (from, to) => Array.from({ length: Math.max(to - from, 0) }, (_, i) => from + i);
564
469
  function TableBlock({ block, controller, labels }) {
565
470
  const readOnly = useReadOnly(controller);
@@ -569,7 +474,6 @@ function TableBlock({ block, controller, labels }) {
569
474
  const aligns = columnAligns(block, cols);
570
475
  const preview = useWidthPreview(controller, block.id);
571
476
  const widths = preview?.length === cols ? preview : storedWidths(block, cols);
572
- useTableKeys(controller, block.id, !readOnly);
573
477
  useCellPress(controller, block.id, table, !readOnly);
574
478
  useRevealCell(controller, block.id);
575
479
  const row = (index) => /* @__PURE__ */ jsx("tr", { children: indexes(0, cols).map((col) => /* @__PURE__ */ jsx(
@@ -630,7 +534,7 @@ var STEP = 10;
630
534
  var LARGE_STEP = 50;
631
535
  var clampWidth = (px) => Math.min(MAX_COLUMN_WIDTH, Math.max(MIN_COLUMN_WIDTH, Math.round(px)));
632
536
  function ColumnResizer(props) {
633
- const { controller, labels, blockId, col, drawn, style, resizerRef, onHold, onBack } = props;
537
+ const { controller, labels, blockId, col, drawn, direction, style, resizerRef, onHold, onBack } = props;
634
538
  const drag = useRef(null);
635
539
  const width = Math.round(drawn[col] ?? 0);
636
540
  const store = tableUiStore(controller);
@@ -641,8 +545,9 @@ function ColumnResizer(props) {
641
545
  if (isComposingKey(controller, event.nativeEvent)) return;
642
546
  const step = event.shiftKey ? LARGE_STEP : STEP;
643
547
  const tab = event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
644
- if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
645
- const next = clampWidth(width + (event.key === "ArrowLeft" ? -step : step));
548
+ const arrow = arrowAsWritten(event.key, direction);
549
+ if (arrow === "ArrowLeft" || arrow === "ArrowRight") {
550
+ const next = clampWidth(width + (arrow === "ArrowLeft" ? -step : step));
646
551
  if (next !== width) write(next, drawn);
647
552
  } else if (tab && event.shiftKey) onBack();
648
553
  else if (tab || event.key === "Escape") controller.focus();
@@ -658,7 +563,8 @@ function ColumnResizer(props) {
658
563
  const onPointerMove = (event) => {
659
564
  const current = drag.current;
660
565
  if (current === null) return;
661
- current.to = clampWidth(current.widths[col] + event.clientX - current.x);
566
+ const moved = event.clientX - current.x;
567
+ current.to = clampWidth(current.widths[col] + (direction === "rtl" ? -moved : moved));
662
568
  const widths = current.widths.map((px, i) => i === col ? current.to ?? px : px);
663
569
  store.set({ preview: { block: blockId, widths } });
664
570
  };
@@ -675,7 +581,7 @@ function ColumnResizer(props) {
675
581
  },
676
582
  [store]
677
583
  );
678
- const end2 = () => {
584
+ const end = () => {
679
585
  const ended = stop();
680
586
  if (ended?.to != null && ended.to !== Math.round(ended.widths[col])) write(ended.to, ended.widths);
681
587
  };
@@ -697,7 +603,7 @@ function ColumnResizer(props) {
697
603
  onKeyDown,
698
604
  onPointerDown,
699
605
  onPointerMove,
700
- onPointerUp: end2,
606
+ onPointerUp: end,
701
607
  onPointerCancel: stop
702
608
  }
703
609
  );
@@ -755,6 +661,49 @@ function HandleMenu({ controller, axis, label, style, items, open, onOpenChange,
755
661
  ] });
756
662
  }
757
663
 
664
+ // src/extensions/table/table-geometry.ts
665
+ function measureTable(table, origin) {
666
+ const box = table.getBoundingClientRect();
667
+ const first = table.rows[0];
668
+ return {
669
+ left: box.left - origin.left,
670
+ top: box.top - origin.top,
671
+ width: box.width,
672
+ height: box.height,
673
+ rows: Array.from(table.rows, (row) => {
674
+ const rect = row.getBoundingClientRect();
675
+ return { start: rect.top - origin.top, size: rect.height };
676
+ }),
677
+ cols: Array.from(first?.cells ?? [], (cell) => {
678
+ const rect = cell.getBoundingClientRect();
679
+ return { start: rect.left - origin.left, size: rect.width };
680
+ }),
681
+ direction: inlineDirection(table)
682
+ };
683
+ }
684
+ var sameSpans = (a, b) => a.length === b.length && a.every((span, i) => span.start === b[i].start && span.size === b[i].size);
685
+ var sameGeometry = (a, b) => a === b || a !== null && b !== null && a.left === b.left && a.top === b.top && a.width === b.width && a.height === b.height && a.direction === b.direction && sameSpans(a.rows, b.rows) && sameSpans(a.cols, b.cols);
686
+ var spanEnd = (span) => span.start + span.size;
687
+ var leadingEdge = (span, direction) => direction === "rtl" ? spanEnd(span) : span.start;
688
+ var trailingEdge = (span, direction) => direction === "rtl" ? span.start : spanEnd(span);
689
+ function spanAt(spans, at) {
690
+ const inside = spans.findIndex((span) => span.start <= at && at < spanEnd(span));
691
+ if (inside !== -1) return inside;
692
+ const distances = spans.map((span) => Math.min(Math.abs(span.start - at), Math.abs(spanEnd(span) - at)));
693
+ return distances.indexOf(Math.min(...distances));
694
+ }
695
+ function edgeNear(spans, at, reach, direction = "ltr") {
696
+ if (spans.length === 0) return null;
697
+ const last = trailingEdge(spans[spans.length - 1], direction);
698
+ const edges = [...spans.map((span) => leadingEdge(span, direction)), last];
699
+ const index = edges.findIndex((edge) => Math.abs(edge - at) <= reach);
700
+ return index === -1 ? null : index;
701
+ }
702
+ function edgeAt(spans, edge, direction = "ltr") {
703
+ if (edge === null || !Number.isInteger(edge) || edge < 0 || edge > spans.length || spans.length === 0) return null;
704
+ return edge === spans.length ? trailingEdge(spans[edge - 1], direction) : leadingEdge(spans[edge], direction);
705
+ }
706
+
758
707
  // src/extensions/table/table-menu-items.ts
759
708
  var item = (id, label, icon, command, done, options = {}) => ({ id, label, icon, command, done, ...options });
760
709
  function rowMenuItems(labels, blockId, row, { rows }) {
@@ -791,16 +740,12 @@ var alignItems = (labels) => [
791
740
  { value: "right", label: labels.alignRight, icon: AlignRight, done: labels.alignedRight }
792
741
  ];
793
742
  var BESIDE = 4;
794
- var end = (span) => span.start + span.size;
795
- function edgeOf(spans, edge) {
796
- if (edge === null || !Number.isInteger(edge) || edge < 0 || edge > spans.length || spans.length === 0) return null;
797
- return edge === spans.length ? end(spans[edge - 1]) : spans[edge].start;
798
- }
743
+ var besideRows = ({ left, width, direction }) => direction === "rtl" ? left + width + BESIDE : left - BESIDE;
799
744
  var middle = (span) => span.start + span.size / 2;
800
745
  var isTab = (event) => event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey;
801
746
  function TableHandles(props) {
802
747
  const { controller, labels, block, target, geometry, menu, onMenu, onHold, focusRequested, onFocused } = props;
803
- const direction = controller.root === null ? "ltr" : inlineDirection(controller.root);
748
+ const { direction } = geometry;
804
749
  const rowHandle = useRef(null);
805
750
  const columnHandle = useRef(null);
806
751
  const resizer = useRef(null);
@@ -810,8 +755,8 @@ function TableHandles(props) {
810
755
  const align = columnAligns(block, shape.cols)[col];
811
756
  const drawn = geometry.cols.map((span) => span.size);
812
757
  const { rowEdge, colEdge } = target;
813
- const rowInsertAt = edgeOf(geometry.rows, rowEdge);
814
- const columnInsertAt = edgeOf(geometry.cols, colEdge);
758
+ const rowInsertAt = edgeAt(geometry.rows, rowEdge);
759
+ const columnInsertAt = edgeAt(geometry.cols, colEdge, direction);
815
760
  useIsomorphicLayoutEffect(() => {
816
761
  if (!focusRequested) return;
817
762
  (columnHandle.current ?? rowHandle.current)?.focus();
@@ -841,7 +786,8 @@ function TableHandles(props) {
841
786
  blockId: block.id,
842
787
  col: index,
843
788
  drawn,
844
- style: { left: end(span), top: geometry.top, height: geometry.height },
789
+ direction,
790
+ style: { left: trailingEdge(span, direction), top: geometry.top, height: geometry.height },
845
791
  resizerRef: index === col ? resizer : void 0,
846
792
  onHold,
847
793
  onBack: () => (columnHandle.current ?? rowHandle.current)?.focus()
@@ -855,7 +801,7 @@ function TableHandles(props) {
855
801
  controller,
856
802
  axis: "row",
857
803
  label: labels.rowOptions(row + 1),
858
- style: place(geometry.left - BESIDE, middle(geometry.rows[row])),
804
+ style: place(besideRows(geometry), middle(geometry.rows[row])),
859
805
  items: rowMenuItems(labels, block.id, row, shape),
860
806
  open: menu === "row",
861
807
  onOpenChange: opener("row"),
@@ -907,7 +853,7 @@ function TableHandles(props) {
907
853
  "aria-label": labels.insertRowAt(rowEdge + 1),
908
854
  "data-axis": "row",
909
855
  className: "quoin-table-insert",
910
- style: place(geometry.left - BESIDE, rowInsertAt),
856
+ style: place(besideRows(geometry), rowInsertAt),
911
857
  onPointerDown: keepFocus,
912
858
  onMouseDown: keepFocus,
913
859
  onClick: () => run(addRow(block.id, rowEdge), labels.rowInserted),
@@ -931,40 +877,6 @@ function TableHandles(props) {
931
877
  )
932
878
  ] });
933
879
  }
934
-
935
- // src/extensions/table/table-geometry.ts
936
- function measureTable(table, origin) {
937
- const box = table.getBoundingClientRect();
938
- const first = table.rows[0];
939
- return {
940
- left: box.left - origin.left,
941
- top: box.top - origin.top,
942
- width: box.width,
943
- height: box.height,
944
- rows: Array.from(table.rows, (row) => {
945
- const rect = row.getBoundingClientRect();
946
- return { start: rect.top - origin.top, size: rect.height };
947
- }),
948
- cols: Array.from(first?.cells ?? [], (cell) => {
949
- const rect = cell.getBoundingClientRect();
950
- return { start: rect.left - origin.left, size: rect.width };
951
- })
952
- };
953
- }
954
- var sameSpans = (a, b) => a.length === b.length && a.every((span, i) => span.start === b[i].start && span.size === b[i].size);
955
- var sameGeometry = (a, b) => a === b || a !== null && b !== null && a.left === b.left && a.top === b.top && a.width === b.width && a.height === b.height && sameSpans(a.rows, b.rows) && sameSpans(a.cols, b.cols);
956
- function spanAt(spans, at) {
957
- const inside = spans.findIndex((span) => at < span.start + span.size);
958
- return inside === -1 ? spans.length - 1 : inside;
959
- }
960
- function edgeNear(spans, at, reach) {
961
- if (spans.length === 0) return null;
962
- const edges = [spans[0].start, ...spans.map((span) => span.start + span.size)];
963
- const index = edges.findIndex((edge) => Math.abs(edge - at) <= reach);
964
- return index === -1 ? null : index;
965
- }
966
-
967
- // src/extensions/table/use-table-geometry.ts
968
880
  function useTableGeometry(controller, blockId, slot) {
969
881
  const [geometry, setGeometry] = useState(null);
970
882
  useIsomorphicLayoutEffect(() => {
@@ -982,31 +894,103 @@ function useTableGeometry(controller, blockId, slot) {
982
894
  frame = view.requestAnimationFrame(measure);
983
895
  };
984
896
  const unsubscribe = controller.editor.subscribe(later);
897
+ const unwatch = watchDirection(table, later);
985
898
  const observer = new ResizeObserver(later);
986
899
  observer.observe(table);
987
900
  view.addEventListener("resize", later);
988
901
  return () => {
989
902
  view.cancelAnimationFrame(frame);
990
903
  unsubscribe();
904
+ unwatch();
991
905
  observer.disconnect();
992
906
  view.removeEventListener("resize", later);
993
907
  };
994
908
  }, [controller, blockId, slot]);
995
909
  return geometry;
996
910
  }
997
- function useCutCells(controller) {
911
+
912
+ // src/extensions/table/vertical-cell-move.ts
913
+ var VERTICAL = { ArrowUp: -1, ArrowDown: 1 };
914
+ function caretAtGoal(controller, blockId, cell, direction) {
915
+ const region = cellKey(...cell);
916
+ const host = controller.registry.get(blockId, region);
917
+ const { goalX } = controller;
918
+ const line = host && lineEdgeRect(host, direction < 0);
919
+ if (!host || !line || goalX === null) return null;
920
+ const box = host.getBoundingClientRect();
921
+ const x = Math.min(Math.max(goalX, box.left), box.right - 1);
922
+ const point = caretFromPoint(host.ownerDocument, x, line.top + line.height / 2);
923
+ const pos = point && domToPos(controller.registry, point.node, point.offset);
924
+ return pos && pos.block === blockId && pos.region === region ? pos : null;
925
+ }
926
+ var plainArrow = (event) => event.altKey || event.ctrlKey || event.metaKey ? void 0 : VERTICAL[event.key];
927
+ function caretOnEdgeLine(controller, head, direction) {
928
+ const host = controller.registry.get(head.block, head.region);
929
+ const point = posToDom(controller.registry, head);
930
+ if (!host || !point || !(direction < 0 ? isOnFirstLine(host, point) : isOnLastLine(host, point))) return null;
931
+ return { left: caretClientRect(point)?.left ?? null };
932
+ }
933
+ function columnAt(controller, blockId, row, x) {
934
+ const cells = Array.from(controller.blockElement(blockId)?.querySelector("table")?.rows[row]?.cells ?? []);
935
+ const spans = cells.map((cell) => {
936
+ const { left, width } = cell.getBoundingClientRect();
937
+ return { start: left, size: width };
938
+ });
939
+ return Math.max(spanAt(spans, x), 0);
940
+ }
941
+ function enterTable(controller, event) {
942
+ const direction = plainArrow(event);
943
+ const { state } = controller.editor;
944
+ const { selection } = state;
945
+ if (direction === void 0 || event.shiftKey || selection?.kind !== "text" || !isCollapsed(selection)) return false;
946
+ const block = neighbourBlock(state.doc, selection.head.block, direction);
947
+ if (block?.type !== "TABLE") return false;
948
+ const blockId = block.id;
949
+ const caret = caretOnEdgeLine(controller, selection.head, direction);
950
+ if (caret === null) return false;
951
+ controller.goalX ??= caret.left;
952
+ const { rows, cols } = tableShape(block);
953
+ const row = direction > 0 ? 0 : rows - 1;
954
+ const { goalX } = controller;
955
+ const cell = [row, goalX === null ? direction > 0 ? 0 : cols - 1 : columnAt(controller, blockId, row, goalX)];
956
+ const pos = caretAtGoal(controller, blockId, cell, direction) ?? cellPos(block, cell, direction < 0);
957
+ controller.dispatch(controller.editor.createTransaction().setSelection(textSelection(pos)));
958
+ return true;
959
+ }
960
+ function moveBetweenRows(controller, event) {
961
+ const direction = plainArrow(event);
962
+ const { state } = controller.editor;
963
+ const caret = headCell(state);
964
+ if (direction === void 0 || caret === null || state.selection?.kind !== "text") return false;
965
+ const blockId = caret.block.id;
966
+ const target = [caret.cell[0] + direction, caret.cell[1]];
967
+ if (target[0] < 0 || target[0] >= caret.shape.rows) return false;
968
+ const edge = caretOnEdgeLine(controller, caret.head, direction);
969
+ if (edge === null) return false;
970
+ controller.goalX ??= edge.left;
971
+ const pos = caretAtGoal(controller, blockId, target, direction) ?? cellPos(caret.block, target, direction < 0);
972
+ const selection = event.shiftKey ? textSelection(state.selection.anchor, pos) : textSelection(pos);
973
+ controller.dispatch(controller.editor.createTransaction().setSelection(selection));
974
+ return true;
975
+ }
976
+
977
+ // src/extensions/table/use-table-keys.ts
978
+ var printable = (event) => [...event.key].length === 1 && !event.ctrlKey && !event.metaKey;
979
+ function typeOver(controller, event) {
980
+ if (cellSelection(controller.editor.state) === null || !printable(event)) return false;
981
+ return controller.run(typeOverCells(event.key));
982
+ }
983
+ function useTableKeys(controller, editable) {
998
984
  useEffect(() => {
999
- const root = controller.root;
1000
- if (root === null) return;
1001
- const onCut = (event) => {
1002
- if (controller.readOnly || cellSelection(controller.editor.state) === null) return;
1003
- event.stopPropagation();
1004
- handleCopy(controller, event, false);
1005
- controller.run(deleteCellContents);
985
+ if (!editable) return;
986
+ const intercept = (event) => {
987
+ if (isComposingKey(controller, event)) return false;
988
+ const handled = typeOver(controller, event) || moveBetweenRows(controller, event) || enterTable(controller, event);
989
+ if (handled) event.preventDefault();
990
+ return handled;
1006
991
  };
1007
- root.addEventListener("cut", onCut, true);
1008
- return () => root.removeEventListener("cut", onCut, true);
1009
- }, [controller]);
992
+ return interceptKeys(controller, intercept);
993
+ }, [controller, editable]);
1010
994
  }
1011
995
  var EDGE_ZONE = 24;
1012
996
  var EDGE_REACH = 8;
@@ -1017,6 +1001,7 @@ function caretTarget(state) {
1017
1001
  const caret = headCell(state);
1018
1002
  return caret && { block: caret.block.id, row: caret.cell[0], col: caret.cell[1], rowEdge: null, colEdge: null };
1019
1003
  }
1004
+ var nearRowStarts = ({ left, width, direction }, x) => direction === "rtl" ? x > left + width - EDGE_ZONE : x < left + EDGE_ZONE;
1020
1005
  function pointerTarget(controller, event) {
1021
1006
  const blockId = controller.blockAt(event.target);
1022
1007
  const block = blockId === void 0 ? null : tableBlock(controller.editor.state.doc, blockId);
@@ -1027,8 +1012,8 @@ function pointerTarget(controller, event) {
1027
1012
  const row = spanAt(geometry.rows, y);
1028
1013
  const col = spanAt(geometry.cols, x);
1029
1014
  if (row < 0 || col < 0) return null;
1030
- const rowEdge = x < geometry.left + EDGE_ZONE ? edgeNear(geometry.rows, y, EDGE_REACH) : null;
1031
- const colEdge = y < geometry.top + EDGE_ZONE ? edgeNear(geometry.cols, x, EDGE_REACH) : null;
1015
+ const rowEdge = nearRowStarts(geometry, x) ? edgeNear(geometry.rows, y, EDGE_REACH) : null;
1016
+ const colEdge = y < geometry.top + EDGE_ZONE ? edgeNear(geometry.cols, x, EDGE_REACH, geometry.direction) : null;
1032
1017
  return { block: block.id, row, col, rowEdge, colEdge };
1033
1018
  }
1034
1019
  function shapeOf(state, blockId) {
@@ -1093,7 +1078,7 @@ function TableControls({ controller, labels }) {
1093
1078
  const [focusFor, setFocusFor] = useState(null);
1094
1079
  const [slot, setSlot] = useState(null);
1095
1080
  const target = useTableTarget(controller, held?.target ?? null);
1096
- useCutCells(controller);
1081
+ useTableKeys(controller, !readOnly);
1097
1082
  const blockId = target?.block ?? null;
1098
1083
  const block = useEditorState(
1099
1084
  controller,
@@ -1130,10 +1115,12 @@ function TableControls({ controller, labels }) {
1130
1115
  setHeld((current) => current?.menu === null ? null : current);
1131
1116
  }, []);
1132
1117
  useIsomorphicLayoutEffect(() => {
1133
- const drawn = block === null || readOnly ? null : controlsSlot(controller, block.id);
1134
- setSlot((current) => current === drawn ? current : drawn);
1118
+ const element = block === null || readOnly ? null : controlsSlot(controller, block.id);
1119
+ const drawn = element && block && { block: block.id, element };
1120
+ setSlot((current) => current?.element === drawn?.element && current?.block === drawn?.block ? current : drawn);
1135
1121
  });
1136
- if (target === null || block === null || readOnly || slot === null || !slot.isConnected) return null;
1122
+ const placed = slot !== null && slot.block === block?.id && slot.element.isConnected ? slot.element : null;
1123
+ if (target === null || block === null || readOnly || placed === null) return null;
1137
1124
  return createPortal(
1138
1125
  /* @__PURE__ */ jsx(
1139
1126
  PlacedHandles,
@@ -1142,7 +1129,7 @@ function TableControls({ controller, labels }) {
1142
1129
  labels,
1143
1130
  block,
1144
1131
  target,
1145
- slot,
1132
+ slot: placed,
1146
1133
  menu: held?.menu ?? null,
1147
1134
  onMenu,
1148
1135
  onHold,
@@ -1151,7 +1138,7 @@ function TableControls({ controller, labels }) {
1151
1138
  },
1152
1139
  block.id
1153
1140
  ),
1154
- slot
1141
+ placed
1155
1142
  );
1156
1143
  }
1157
1144
  function PlacedHandles({ slot, ...props }) {
@@ -1159,6 +1146,78 @@ function PlacedHandles({ slot, ...props }) {
1159
1146
  return geometry === null ? null : /* @__PURE__ */ jsx(TableHandles, { ...props, geometry });
1160
1147
  }
1161
1148
 
1149
+ // src/engine/commands/paste-cells.ts
1150
+ var unmoved = (cell) => cell;
1151
+ function grown(block, rows, cols) {
1152
+ const shape = tableShape(block);
1153
+ if (rows <= shape.rows && cols <= shape.cols) return null;
1154
+ const added = Math.max(cols - shape.cols, 0);
1155
+ const widths = storedWidths(block, shape.cols);
1156
+ return rebuiltTable(block, {
1157
+ rows: Math.max(rows, shape.rows),
1158
+ cols: shape.cols + added,
1159
+ source: (row, col) => row < shape.rows && col < shape.cols ? [row, col] : null,
1160
+ target: unmoved,
1161
+ landing: unmoved,
1162
+ attrs: {
1163
+ align: [...columnAligns(block, shape.cols), ...Array(added).fill(null)],
1164
+ ...widths && { widths: [...widths, ...Array(added).fill(widths[shape.cols - 1])] }
1165
+ }
1166
+ });
1167
+ }
1168
+ function pasteCells(source) {
1169
+ return (state, dispatch) => {
1170
+ const { doc, schema, selection } = state;
1171
+ const { rows, cols } = tableShape(source);
1172
+ if (selection?.kind !== "text" || rows === 0 || cols === 0) return false;
1173
+ const { anchor, head } = selection;
1174
+ const inCells = anchor.block === head.block && cellOf(anchor.region) !== null && cellOf(head.region) !== null;
1175
+ if (!inCells || tableBlock(doc, head.block) === null) return false;
1176
+ const tr = new Transaction(state).setOrigin("paste");
1177
+ const { from, to } = orderedRange(doc, anchor, head);
1178
+ const [top, left] = cellOf(deleteRange(tr, schema, from, to).region);
1179
+ const larger = grown(tableBlock(tr.doc, head.block), top + rows, left + cols);
1180
+ if (larger !== null) tr.step(replaceBlockStep(larger));
1181
+ const block = tableBlock(tr.doc, head.block);
1182
+ let caret = head;
1183
+ for (const [row, col] of cellsBetween([0, 0], [rows - 1, cols - 1])) {
1184
+ const region = cellKey(top + row, left + col);
1185
+ const content = source.regions[cellKey(row, col)] ?? [];
1186
+ const length = regionLength(block, region);
1187
+ if (length > 0 || content.length > 0) tr.step(replaceInlineStep(block.id, region, 0, length, content));
1188
+ caret = { block: block.id, region, offset: inlineLength(content) };
1189
+ }
1190
+ dispatch?.(tr.setSelection(textSelection(caret)));
1191
+ return true;
1192
+ };
1193
+ }
1194
+
1195
+ // src/extensions/table/paste-over-cells.ts
1196
+ function richBlocks(state, pasted) {
1197
+ const slice = pasted?.json || pasted?.html ? sliceFromClipboard({ json: pasted.json, html: pasted.html }) : null;
1198
+ if (slice === null) return null;
1199
+ const codec = createBlockCodec(state.schema);
1200
+ const blocks = slice.blocks.flatMap((block) => codec.toEngineBlocks(block));
1201
+ return { blocks, open: slice.openStart && slice.openEnd };
1202
+ }
1203
+ function lineOf(state, rich) {
1204
+ const [only] = rich?.blocks ?? [];
1205
+ if (!rich?.open || rich.blocks.length !== 1 || !isTextFlow(state.schema, only)) return void 0;
1206
+ return only.regions[primaryRegion(state.schema, only) ?? ""];
1207
+ }
1208
+ var pasteOverCells = {
1209
+ name: "table-cells",
1210
+ match(text, state, pasted) {
1211
+ const { doc, selection } = state;
1212
+ if (selection?.kind !== "text" || tableBlock(doc, selection.head.block) === null) return null;
1213
+ const rich = richBlocks(state, pasted);
1214
+ const [only] = rich?.blocks.length === 1 ? rich.blocks : [];
1215
+ if (only?.type === "TABLE") return pasteCells(only);
1216
+ if (cellSelection(state) === null) return null;
1217
+ return typeOverCells(lineOf(state, rich) ?? text.replace(/\r\n?/g, "\n"));
1218
+ }
1219
+ };
1220
+
1162
1221
  // src/extensions/table/table-labels.ts
1163
1222
  var englishTableLabels = {
1164
1223
  table: "Table",
@@ -1212,10 +1271,6 @@ var tableSlashItem = (labels) => ({
1212
1271
  command: () => insertTable(NEW_TABLE.rows, NEW_TABLE.cols)
1213
1272
  });
1214
1273
  var ABOVE_CORE_KEYS = 200;
1215
- var pasteOverCells = {
1216
- name: "table-cells",
1217
- match: (text, state) => cellSelection(state) === null ? null : typeOverCells(text.replace(/\r\n?/g, "\n"))
1218
- };
1219
1274
  function tableExtension(options = {}) {
1220
1275
  const labels = resolveTableLabels(options.labels);
1221
1276
  const TableRenderer = (props) => /* @__PURE__ */ jsx(TableBlock, { ...props, labels });
@@ -1237,5 +1292,5 @@ function tableExtension(options = {}) {
1237
1292
  }
1238
1293
 
1239
1294
  export { addColumn, addRow, cellSelection, cellSelectionKey, cellSelectionPlugin, cellsInRange, deleteCellContents, englishTableLabels, insertTable, moveColumn, moveRow, removeColumn, removeRow, selectCells, setCellsMark, setColumnAlign, setColumnWidth, tableExtension, toggleHeaderRow };
1240
- //# sourceMappingURL=chunk-556PFYES.js.map
1241
- //# sourceMappingURL=chunk-556PFYES.js.map
1295
+ //# sourceMappingURL=chunk-WK4UGDZN.js.map
1296
+ //# sourceMappingURL=chunk-WK4UGDZN.js.map