smartrte-core 0.2.1 → 1.0.0-beta.2

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 (329) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +23 -0
  3. package/dist/command.d.ts +8 -8
  4. package/dist/editor.d.ts +32 -0
  5. package/dist/editor.js +121 -0
  6. package/dist/foundation/annotations/index.d.ts +2 -0
  7. package/dist/foundation/annotations/index.js +2 -0
  8. package/dist/foundation/annotations/range.d.ts +54 -0
  9. package/dist/foundation/annotations/range.js +158 -0
  10. package/dist/foundation/annotations/types.d.ts +33 -0
  11. package/dist/foundation/annotations/types.js +1 -0
  12. package/dist/foundation/atom/commands.d.ts +11 -0
  13. package/dist/foundation/atom/commands.js +118 -0
  14. package/dist/foundation/atom/composition.d.ts +8 -0
  15. package/dist/foundation/atom/composition.js +22 -0
  16. package/dist/foundation/atom/declarations.d.ts +2 -0
  17. package/dist/foundation/atom/declarations.js +17 -0
  18. package/dist/foundation/atom/formats.d.ts +24 -0
  19. package/dist/foundation/atom/formats.js +105 -0
  20. package/dist/foundation/atom/index.d.ts +10 -0
  21. package/dist/foundation/atom/index.js +10 -0
  22. package/dist/foundation/atom/lifecycle.d.ts +12 -0
  23. package/dist/foundation/atom/lifecycle.js +41 -0
  24. package/dist/foundation/atom/persistence.d.ts +3 -0
  25. package/dist/foundation/atom/persistence.js +20 -0
  26. package/dist/foundation/atom/plugin.d.ts +20 -0
  27. package/dist/foundation/atom/plugin.js +55 -0
  28. package/dist/foundation/atom/schema.d.ts +3 -0
  29. package/dist/foundation/atom/schema.js +29 -0
  30. package/dist/foundation/atom/security.d.ts +10 -0
  31. package/dist/foundation/atom/security.js +20 -0
  32. package/dist/foundation/atom/selection.d.ts +3 -0
  33. package/dist/foundation/atom/selection.js +4 -0
  34. package/dist/foundation/atom/types.d.ts +47 -0
  35. package/dist/foundation/atom/types.js +1 -0
  36. package/dist/foundation/block/commands.d.ts +17 -0
  37. package/dist/foundation/block/commands.js +197 -0
  38. package/dist/foundation/block/formats.d.ts +33 -0
  39. package/dist/foundation/block/formats.js +57 -0
  40. package/dist/foundation/block/index.d.ts +5 -0
  41. package/dist/foundation/block/index.js +5 -0
  42. package/dist/foundation/block/input.d.ts +19 -0
  43. package/dist/foundation/block/input.js +67 -0
  44. package/dist/foundation/block/plugin.d.ts +26 -0
  45. package/dist/foundation/block/plugin.js +79 -0
  46. package/dist/foundation/block/schema.d.ts +49 -0
  47. package/dist/foundation/block/schema.js +27 -0
  48. package/dist/foundation/block/types.d.ts +40 -0
  49. package/dist/foundation/block/types.js +1 -0
  50. package/dist/foundation/boundaries.d.ts +11 -0
  51. package/dist/foundation/boundaries.js +117 -0
  52. package/dist/foundation/clipboard/detection.d.ts +3 -0
  53. package/dist/foundation/clipboard/detection.js +29 -0
  54. package/dist/foundation/clipboard/diagnostics.d.ts +24 -0
  55. package/dist/foundation/clipboard/diagnostics.js +59 -0
  56. package/dist/foundation/clipboard/index.d.ts +8 -0
  57. package/dist/foundation/clipboard/index.js +8 -0
  58. package/dist/foundation/clipboard/insertion.d.ts +22 -0
  59. package/dist/foundation/clipboard/insertion.js +210 -0
  60. package/dist/foundation/clipboard/normalizers.d.ts +8 -0
  61. package/dist/foundation/clipboard/normalizers.js +229 -0
  62. package/dist/foundation/clipboard/pipeline.d.ts +13 -0
  63. package/dist/foundation/clipboard/pipeline.js +58 -0
  64. package/dist/foundation/clipboard/sanitizer.d.ts +3 -0
  65. package/dist/foundation/clipboard/sanitizer.js +58 -0
  66. package/dist/foundation/clipboard/serialization.d.ts +5 -0
  67. package/dist/foundation/clipboard/serialization.js +33 -0
  68. package/dist/foundation/clipboard/transfer.d.ts +11 -0
  69. package/dist/foundation/clipboard/transfer.js +108 -0
  70. package/dist/foundation/clipboard/types.d.ts +65 -0
  71. package/dist/foundation/clipboard/types.js +1 -0
  72. package/dist/foundation/collab/index.d.ts +3 -0
  73. package/dist/foundation/collab/index.js +3 -0
  74. package/dist/foundation/collab/rebase.d.ts +28 -0
  75. package/dist/foundation/collab/rebase.js +82 -0
  76. package/dist/foundation/collab/transform.d.ts +73 -0
  77. package/dist/foundation/collab/transform.js +251 -0
  78. package/dist/foundation/collab/types.d.ts +52 -0
  79. package/dist/foundation/collab/types.js +1 -0
  80. package/dist/foundation/comments/fromSelection.d.ts +16 -0
  81. package/dist/foundation/comments/fromSelection.js +24 -0
  82. package/dist/foundation/comments/index.d.ts +3 -0
  83. package/dist/foundation/comments/index.js +3 -0
  84. package/dist/foundation/comments/rebase.d.ts +31 -0
  85. package/dist/foundation/comments/rebase.js +43 -0
  86. package/dist/foundation/comments/types.d.ts +37 -0
  87. package/dist/foundation/comments/types.js +1 -0
  88. package/dist/foundation/diff/documentDiff.d.ts +12 -0
  89. package/dist/foundation/diff/documentDiff.js +148 -0
  90. package/dist/foundation/diff/index.d.ts +3 -0
  91. package/dist/foundation/diff/index.js +3 -0
  92. package/dist/foundation/diff/textDiff.d.ts +12 -0
  93. package/dist/foundation/diff/textDiff.js +114 -0
  94. package/dist/foundation/diff/types.d.ts +74 -0
  95. package/dist/foundation/diff/types.js +1 -0
  96. package/dist/foundation/editor.d.ts +138 -0
  97. package/dist/foundation/editor.js +398 -0
  98. package/dist/foundation/formats/codec.d.ts +45 -0
  99. package/dist/foundation/formats/codec.js +1 -0
  100. package/dist/foundation/formats/docx/export.d.ts +4 -0
  101. package/dist/foundation/formats/docx/export.js +285 -0
  102. package/dist/foundation/formats/docx/import.d.ts +9 -0
  103. package/dist/foundation/formats/docx/import.js +37 -0
  104. package/dist/foundation/formats/docx/nestingGuard.d.ts +40 -0
  105. package/dist/foundation/formats/docx/nestingGuard.js +66 -0
  106. package/dist/foundation/formats/docx/portableAtoms.d.ts +4 -0
  107. package/dist/foundation/formats/docx/portableAtoms.js +66 -0
  108. package/dist/foundation/formats/docx/styledImport.d.ts +10 -0
  109. package/dist/foundation/formats/docx/styledImport.js +205 -0
  110. package/dist/foundation/formats/featureCodecs.d.ts +37 -0
  111. package/dist/foundation/formats/featureCodecs.js +69 -0
  112. package/dist/foundation/formats/fidelity.d.ts +31 -0
  113. package/dist/foundation/formats/fidelity.js +123 -0
  114. package/dist/foundation/formats/index.d.ts +7 -0
  115. package/dist/foundation/formats/index.js +7 -0
  116. package/dist/foundation/formats/pdf/format.d.ts +29 -0
  117. package/dist/foundation/formats/pdf/format.js +190 -0
  118. package/dist/foundation/history.d.ts +20 -0
  119. package/dist/foundation/history.js +121 -0
  120. package/dist/foundation/identity.d.ts +8 -0
  121. package/dist/foundation/identity.js +30 -0
  122. package/dist/foundation/index.d.ts +30 -0
  123. package/dist/foundation/index.js +30 -0
  124. package/dist/foundation/list/commands.d.ts +28 -0
  125. package/dist/foundation/list/commands.js +422 -0
  126. package/dist/foundation/list/formats.d.ts +21 -0
  127. package/dist/foundation/list/formats.js +813 -0
  128. package/dist/foundation/list/index.d.ts +8 -0
  129. package/dist/foundation/list/index.js +8 -0
  130. package/dist/foundation/list/input.d.ts +35 -0
  131. package/dist/foundation/list/input.js +320 -0
  132. package/dist/foundation/list/plugin.d.ts +21 -0
  133. package/dist/foundation/list/plugin.js +71 -0
  134. package/dist/foundation/list/presets.d.ts +16 -0
  135. package/dist/foundation/list/presets.js +21 -0
  136. package/dist/foundation/list/schema.d.ts +35 -0
  137. package/dist/foundation/list/schema.js +29 -0
  138. package/dist/foundation/list/shadow.d.ts +54 -0
  139. package/dist/foundation/list/shadow.js +75 -0
  140. package/dist/foundation/list/shadowCorpus.d.ts +10 -0
  141. package/dist/foundation/list/shadowCorpus.js +41 -0
  142. package/dist/foundation/list/types.d.ts +50 -0
  143. package/dist/foundation/list/types.js +1 -0
  144. package/dist/foundation/mapping.d.ts +11 -0
  145. package/dist/foundation/mapping.js +40 -0
  146. package/dist/foundation/marks/canonical.d.ts +9 -0
  147. package/dist/foundation/marks/canonical.js +72 -0
  148. package/dist/foundation/marks/commands.d.ts +21 -0
  149. package/dist/foundation/marks/commands.js +136 -0
  150. package/dist/foundation/marks/dom.d.ts +2 -0
  151. package/dist/foundation/marks/dom.js +46 -0
  152. package/dist/foundation/marks/editor.d.ts +8 -0
  153. package/dist/foundation/marks/editor.js +50 -0
  154. package/dist/foundation/marks/formats.d.ts +37 -0
  155. package/dist/foundation/marks/formats.js +49 -0
  156. package/dist/foundation/marks/hardBreak.d.ts +8 -0
  157. package/dist/foundation/marks/hardBreak.js +80 -0
  158. package/dist/foundation/marks/index.d.ts +11 -0
  159. package/dist/foundation/marks/index.js +11 -0
  160. package/dist/foundation/marks/normalization.d.ts +2 -0
  161. package/dist/foundation/marks/normalization.js +49 -0
  162. package/dist/foundation/marks/plugin.d.ts +14 -0
  163. package/dist/foundation/marks/plugin.js +63 -0
  164. package/dist/foundation/marks/resolveMarkRun.d.ts +8 -0
  165. package/dist/foundation/marks/resolveMarkRun.js +47 -0
  166. package/dist/foundation/marks/schema.d.ts +167 -0
  167. package/dist/foundation/marks/schema.js +50 -0
  168. package/dist/foundation/marks/stored.d.ts +2 -0
  169. package/dist/foundation/marks/stored.js +31 -0
  170. package/dist/foundation/marks/types.d.ts +40 -0
  171. package/dist/foundation/marks/types.js +1 -0
  172. package/dist/foundation/modelDom.d.ts +38 -0
  173. package/dist/foundation/modelDom.js +327 -0
  174. package/dist/foundation/normalization.d.ts +22 -0
  175. package/dist/foundation/normalization.js +132 -0
  176. package/dist/foundation/operations.d.ts +28 -0
  177. package/dist/foundation/operations.js +568 -0
  178. package/dist/foundation/plugin/builtins.d.ts +10 -0
  179. package/dist/foundation/plugin/builtins.js +27 -0
  180. package/dist/foundation/plugin/dispatch.d.ts +33 -0
  181. package/dist/foundation/plugin/dispatch.js +34 -0
  182. package/dist/foundation/plugin/index.d.ts +4 -0
  183. package/dist/foundation/plugin/index.js +4 -0
  184. package/dist/foundation/plugin/registry.d.ts +36 -0
  185. package/dist/foundation/plugin/registry.js +115 -0
  186. package/dist/foundation/plugin/types.d.ts +141 -0
  187. package/dist/foundation/plugin/types.js +13 -0
  188. package/dist/foundation/positions.d.ts +20 -0
  189. package/dist/foundation/positions.js +121 -0
  190. package/dist/foundation/schema.d.ts +57 -0
  191. package/dist/foundation/schema.js +371 -0
  192. package/dist/foundation/schemaBuilder.d.ts +41 -0
  193. package/dist/foundation/schemaBuilder.js +96 -0
  194. package/dist/foundation/scope/index.d.ts +2 -0
  195. package/dist/foundation/scope/index.js +2 -0
  196. package/dist/foundation/scope/resolveScope.d.ts +13 -0
  197. package/dist/foundation/scope/resolveScope.js +860 -0
  198. package/dist/foundation/scope/types.d.ts +122 -0
  199. package/dist/foundation/scope/types.js +1 -0
  200. package/dist/foundation/security/urlPolicy.d.ts +21 -0
  201. package/dist/foundation/security/urlPolicy.js +75 -0
  202. package/dist/foundation/structural/contentTarget.d.ts +21 -0
  203. package/dist/foundation/structural/contentTarget.js +51 -0
  204. package/dist/foundation/structural/index.d.ts +2 -0
  205. package/dist/foundation/structural/index.js +2 -0
  206. package/dist/foundation/structural/move.d.ts +7 -0
  207. package/dist/foundation/structural/move.js +35 -0
  208. package/dist/foundation/suggestions/index.d.ts +3 -0
  209. package/dist/foundation/suggestions/index.js +3 -0
  210. package/dist/foundation/suggestions/inline.d.ts +64 -0
  211. package/dist/foundation/suggestions/inline.js +116 -0
  212. package/dist/foundation/suggestions/structural.d.ts +40 -0
  213. package/dist/foundation/suggestions/structural.js +47 -0
  214. package/dist/foundation/suggestions/types.d.ts +19 -0
  215. package/dist/foundation/suggestions/types.js +1 -0
  216. package/dist/foundation/surface/index.d.ts +3 -0
  217. package/dist/foundation/surface/index.js +3 -0
  218. package/dist/foundation/surface/input.d.ts +127 -0
  219. package/dist/foundation/surface/input.js +1761 -0
  220. package/dist/foundation/surface/renderer.d.ts +84 -0
  221. package/dist/foundation/surface/renderer.js +974 -0
  222. package/dist/foundation/surface/types.d.ts +48 -0
  223. package/dist/foundation/surface/types.js +1 -0
  224. package/dist/foundation/table/commands.d.ts +31 -0
  225. package/dist/foundation/table/commands.js +470 -0
  226. package/dist/foundation/table/formats.d.ts +27 -0
  227. package/dist/foundation/table/formats.js +40 -0
  228. package/dist/foundation/table/grid.d.ts +8 -0
  229. package/dist/foundation/table/grid.js +178 -0
  230. package/dist/foundation/table/index.d.ts +6 -0
  231. package/dist/foundation/table/index.js +6 -0
  232. package/dist/foundation/table/plugin.d.ts +23 -0
  233. package/dist/foundation/table/plugin.js +119 -0
  234. package/dist/foundation/table/schema.d.ts +2 -0
  235. package/dist/foundation/table/schema.js +38 -0
  236. package/dist/foundation/table/selection.d.ts +7 -0
  237. package/dist/foundation/table/selection.js +35 -0
  238. package/dist/foundation/table/types.d.ts +109 -0
  239. package/dist/foundation/table/types.js +1 -0
  240. package/dist/foundation/transactions.d.ts +41 -0
  241. package/dist/foundation/transactions.js +90 -0
  242. package/dist/foundation/types.d.ts +261 -0
  243. package/dist/foundation/types.js +1 -0
  244. package/dist/foundation/versioning/diffVersions.d.ts +5 -0
  245. package/dist/foundation/versioning/diffVersions.js +3 -0
  246. package/dist/foundation/versioning/index.d.ts +2 -0
  247. package/dist/foundation/versioning/index.js +2 -0
  248. package/dist/foundation/versioning/types.d.ts +17 -0
  249. package/dist/foundation/versioning/types.js +1 -0
  250. package/dist/history.d.ts +20 -0
  251. package/dist/history.js +165 -0
  252. package/dist/html/compatibility.js +7 -1
  253. package/dist/index.d.ts +1 -14
  254. package/dist/index.js +9 -14
  255. package/dist/legacy/index.d.ts +45 -0
  256. package/dist/legacy/index.js +45 -0
  257. package/dist/legacyCommands/alignment.d.ts +20 -0
  258. package/dist/{commands → legacyCommands}/alignment.js +17 -0
  259. package/dist/legacyCommands/blocks.d.ts +14 -0
  260. package/dist/legacyCommands/blocks.js +105 -0
  261. package/dist/legacyCommands/checklist.d.ts +11 -0
  262. package/dist/legacyCommands/checklist.js +45 -0
  263. package/dist/legacyCommands/code.d.ts +15 -0
  264. package/dist/{commands → legacyCommands}/code.js +25 -1
  265. package/dist/legacyCommands/formula.d.ts +7 -0
  266. package/dist/legacyCommands/formula.js +67 -0
  267. package/dist/legacyCommands/inlineAtoms.d.ts +7 -0
  268. package/dist/legacyCommands/inlineAtoms.js +58 -0
  269. package/dist/legacyCommands/list.d.ts +38 -0
  270. package/dist/legacyCommands/list.js +477 -0
  271. package/dist/{commands → legacyCommands}/marks.d.ts +3 -0
  272. package/dist/{commands → legacyCommands}/marks.js +28 -11
  273. package/dist/legacyCommands/media.d.ts +31 -0
  274. package/dist/legacyCommands/media.js +205 -0
  275. package/dist/legacyCommands/move.d.ts +14 -0
  276. package/dist/legacyCommands/move.js +91 -0
  277. package/dist/legacyCommands/table.d.ts +91 -0
  278. package/dist/legacyCommands/table.js +547 -0
  279. package/dist/listPresets.d.ts +12 -0
  280. package/dist/listPresets.js +6 -0
  281. package/dist/listScope.d.ts +27 -0
  282. package/dist/listScope.js +104 -0
  283. package/dist/markdown/compatibility.d.ts +2 -0
  284. package/dist/markdown/compatibility.js +94 -2
  285. package/dist/marks.d.ts +5 -5
  286. package/dist/model.d.ts +65 -9
  287. package/dist/plugin.d.ts +15 -0
  288. package/dist/plugin.js +31 -0
  289. package/dist/plugins/alignment.d.ts +3 -0
  290. package/dist/plugins/alignment.js +6 -0
  291. package/dist/plugins/basicFormatting.d.ts +9 -0
  292. package/dist/plugins/basicFormatting.js +24 -0
  293. package/dist/plugins/blockType.d.ts +3 -0
  294. package/dist/plugins/blockType.js +6 -0
  295. package/dist/plugins/blockquote.d.ts +3 -0
  296. package/dist/plugins/blockquote.js +6 -0
  297. package/dist/plugins/checklist.d.ts +3 -0
  298. package/dist/plugins/checklist.js +10 -0
  299. package/dist/plugins/codeBlock.d.ts +3 -0
  300. package/dist/plugins/codeBlock.js +6 -0
  301. package/dist/plugins/formula.d.ts +3 -0
  302. package/dist/plugins/formula.js +9 -0
  303. package/dist/plugins/list.d.ts +3 -0
  304. package/dist/plugins/list.js +10 -0
  305. package/dist/plugins/media.d.ts +3 -0
  306. package/dist/plugins/media.js +12 -0
  307. package/dist/plugins/move.d.ts +3 -0
  308. package/dist/plugins/move.js +9 -0
  309. package/dist/plugins/table.d.ts +3 -0
  310. package/dist/plugins/table.js +22 -0
  311. package/dist/preset.d.ts +12 -0
  312. package/dist/preset.js +40 -0
  313. package/dist/schema.d.ts +22 -0
  314. package/dist/schema.js +333 -0
  315. package/dist/security/urlPolicy.d.ts +1 -17
  316. package/dist/security/urlPolicy.js +3 -69
  317. package/dist/selection.d.ts +1 -1
  318. package/dist/selectionMapping.d.ts +4 -0
  319. package/dist/selectionMapping.js +222 -0
  320. package/dist/table.d.ts +3 -3
  321. package/dist/transaction.d.ts +35 -12
  322. package/dist/transaction.js +174 -28
  323. package/dist/tree.d.ts +8 -2
  324. package/dist/tree.js +44 -0
  325. package/package.json +27 -8
  326. package/dist/commands/alignment.d.ts +0 -18
  327. package/dist/commands/code.d.ts +0 -13
  328. package/dist/commands/list.d.ts +0 -20
  329. package/dist/commands/list.js +0 -52
@@ -0,0 +1,178 @@
1
+ import { createNodeId, isTextNode } from "../identity.js";
2
+ const positiveInt = (value) => Number.isInteger(value) && Number(value) > 0 ? Number(value) : 1;
3
+ const role = (node, wanted) => node.type === wanted;
4
+ const rowsOf = (table) => (table.children || []).filter((node) => !isTextNode(node) && role(node, "table_row"));
5
+ const cellsOf = (row) => (row.children || []).filter((node) => !isTextNode(node) && role(node, "table_cell"));
6
+ const intersects = (cell, rect) => cell.top < rect.bottom && cell.bottom > rect.top && cell.left < rect.right && cell.right > rect.left;
7
+ const contained = (cell, rect) => cell.top >= rect.top && cell.bottom <= rect.bottom && cell.left >= rect.left && cell.right <= rect.right;
8
+ const cache = new WeakMap();
9
+ export const occupancyGridFor = (table) => {
10
+ const cached = cache.get(table);
11
+ if (cached)
12
+ return cached;
13
+ const rows = rowsOf(table);
14
+ const slots = Array.from({ length: rows.length }, () => []);
15
+ const anchors = [];
16
+ rows.forEach((row, rowIndex) => {
17
+ let column = 0;
18
+ cellsOf(row).forEach((node, childIndex) => {
19
+ while (slots[rowIndex]?.[column])
20
+ column += 1;
21
+ const rowspan = positiveInt(node.attrs?.rowspan);
22
+ const colspan = positiveInt(node.attrs?.colspan);
23
+ const cell = {
24
+ cellId: node.id, top: rowIndex, left: column,
25
+ bottom: rowIndex + rowspan, right: column + colspan,
26
+ isAnchor: true, rowIndex, childIndex, node,
27
+ };
28
+ anchors.push(cell);
29
+ for (let r = cell.top; r < cell.bottom; r += 1) {
30
+ slots[r] || (slots[r] = []);
31
+ for (let c = cell.left; c < cell.right; c += 1)
32
+ if (!slots[r][c])
33
+ slots[r][c] = r === cell.top && c === cell.left
34
+ ? cell
35
+ : { ...cell, isAnchor: false };
36
+ }
37
+ column += colspan;
38
+ });
39
+ });
40
+ const columns = slots.reduce((width, row) => Math.max(width, row.length), 0);
41
+ const grid = Object.freeze({
42
+ tableId: table.id,
43
+ rows: rows.length,
44
+ columns,
45
+ anchors: Object.freeze(anchors),
46
+ at: (row, col) => slots[row]?.[col] || null,
47
+ anchorsIn: (rect) => anchors.filter((cell) => contained(cell, rect)),
48
+ coveredIn: (rect) => anchors.filter((cell) => intersects(cell, rect) && !contained(cell, rect)),
49
+ isRectangular: (rect) => {
50
+ if (rect.top < 0 || rect.left < 0 || rect.bottom > rows.length || rect.right > columns || rect.top >= rect.bottom || rect.left >= rect.right)
51
+ return false;
52
+ for (let row = rect.top; row < rect.bottom; row += 1)
53
+ for (let col = rect.left; col < rect.right; col += 1) {
54
+ const cell = slots[row]?.[col];
55
+ if (!cell || !contained(cell, rect))
56
+ return false;
57
+ }
58
+ return true;
59
+ },
60
+ });
61
+ cache.set(table, grid);
62
+ return grid;
63
+ };
64
+ export const validateTableGeometry = (table) => {
65
+ const issues = [];
66
+ const rows = rowsOf(table);
67
+ const slots = Array.from({ length: rows.length }, () => []);
68
+ rows.forEach((row, rowIndex) => {
69
+ let column = 0;
70
+ cellsOf(row).forEach((cell) => {
71
+ while (slots[rowIndex]?.[column])
72
+ column += 1;
73
+ const rowspan = positiveInt(cell.attrs?.rowspan);
74
+ const colspan = positiveInt(cell.attrs?.colspan);
75
+ if (rowIndex + rowspan > rows.length)
76
+ issues.push({ code: "overhang", row: rowIndex, column, cellId: cell.id, message: "Cell rowspan extends beyond the table." });
77
+ for (let r = rowIndex; r < Math.min(rows.length, rowIndex + rowspan); r += 1)
78
+ for (let c = column; c < column + colspan; c += 1) {
79
+ if (slots[r]?.[c])
80
+ issues.push({ code: "overlap", row: r, column: c, cellId: cell.id, message: "Two cells claim one logical coordinate." });
81
+ else
82
+ slots[r][c] = cell.id;
83
+ }
84
+ column += colspan;
85
+ });
86
+ });
87
+ const width = slots.reduce((max, row) => Math.max(max, row.length), 0);
88
+ slots.forEach((row, rowIndex) => {
89
+ if (row.length !== width)
90
+ issues.push({ code: "unequal-width", row: rowIndex, message: "Rows do not materialize the same logical width." });
91
+ for (let col = 0; col < width; col += 1)
92
+ if (!row[col])
93
+ issues.push({ code: "hole", row: rowIndex, column: col, message: "Logical coordinate is unclaimed." });
94
+ });
95
+ const grid = occupancyGridFor(table);
96
+ let leadingHeaderRows = 0;
97
+ while (leadingHeaderRows < grid.rows && Array.from({ length: grid.columns }, (_, col) => grid.at(leadingHeaderRows, col)?.node.attrs?.header === true).every(Boolean))
98
+ leadingHeaderRows += 1;
99
+ let leadingHeaderColumns = 0;
100
+ while (leadingHeaderColumns < grid.columns && Array.from({ length: grid.rows }, (_, row) => grid.at(row, leadingHeaderColumns)?.node.attrs?.header === true).every(Boolean))
101
+ leadingHeaderColumns += 1;
102
+ for (let row = 0; row < grid.rows; row += 1) {
103
+ for (let col = 0; col < grid.columns; col += 1) {
104
+ const header = grid.at(row, col)?.node.attrs?.header === true;
105
+ const expected = row < leadingHeaderRows || col < leadingHeaderColumns;
106
+ if (header !== expected)
107
+ issues.push({ code: "noncontiguous-header", row, column: col, cellId: grid.at(row, col)?.cellId, message: "Header cells must be the union of contiguous leading rows and columns." });
108
+ }
109
+ }
110
+ return issues;
111
+ };
112
+ const emptyCell = (cellId = createNodeId(), paragraphId = createNodeId()) => ({
113
+ type: "table_cell", id: cellId, attrs: { colspan: 1, rowspan: 1, header: false },
114
+ children: [{ type: "paragraph", id: paragraphId, children: [] }],
115
+ });
116
+ export const repairTableGeometry = (table) => {
117
+ const repairs = validateTableGeometry(table);
118
+ if (!repairs.length)
119
+ return { table, repairs };
120
+ const sourceRows = rowsOf(table);
121
+ const slots = Array.from({ length: sourceRows.length }, () => []);
122
+ const placements = [];
123
+ sourceRows.forEach((row, rowIndex) => {
124
+ let column = 0;
125
+ cellsOf(row).forEach((cell) => {
126
+ const rowspan = Math.min(positiveInt(cell.attrs?.rowspan), sourceRows.length - rowIndex);
127
+ const colspan = positiveInt(cell.attrs?.colspan);
128
+ const fits = (left) => {
129
+ for (let r = rowIndex; r < rowIndex + rowspan; r += 1)
130
+ for (let c = left; c < left + colspan; c += 1)
131
+ if (slots[r]?.[c])
132
+ return false;
133
+ return true;
134
+ };
135
+ while (!fits(column))
136
+ column += 1;
137
+ const normalized = { ...cell, attrs: { ...(cell.attrs || {}), rowspan, colspan, header: cell.attrs?.header === true } };
138
+ placements.push({ row: rowIndex, column, rowspan, colspan, cell: normalized });
139
+ for (let r = rowIndex; r < rowIndex + rowspan; r += 1)
140
+ for (let c = column; c < column + colspan; c += 1)
141
+ slots[r][c] = normalized;
142
+ column += colspan;
143
+ });
144
+ });
145
+ let width = slots.reduce((max, row) => Math.max(max, row.length), 0);
146
+ for (let row = 0; row < sourceRows.length; row += 1)
147
+ for (let col = 0; col < width; col += 1)
148
+ if (!slots[row][col]) {
149
+ const cell = emptyCell();
150
+ placements.push({ row, column: col, rowspan: 1, colspan: 1, cell });
151
+ slots[row][col] = cell;
152
+ }
153
+ width = slots.reduce((max, row) => Math.max(max, row.length), width);
154
+ // Preserve only header cells that already form complete leading rows or
155
+ // columns. A stray Word header in the middle is demoted; promoting all rows
156
+ // before it changes document semantics and surprises screen-reader users.
157
+ let headerRows = 0;
158
+ while (headerRows < sourceRows.length && Array.from({ length: width }, (_, col) => slots[headerRows]?.[col]?.attrs?.header === true).every(Boolean))
159
+ headerRows += 1;
160
+ let headerColumns = 0;
161
+ while (headerColumns < width && Array.from({ length: sourceRows.length }, (_, row) => slots[row]?.[headerColumns]?.attrs?.header === true).every(Boolean))
162
+ headerColumns += 1;
163
+ const keepHeader = new Set();
164
+ for (let row = 0; row < sourceRows.length; row += 1)
165
+ for (let col = 0; col < width; col += 1) {
166
+ const owner = slots[row]?.[col];
167
+ if (owner?.attrs?.header === true && (row < headerRows || col < headerColumns))
168
+ keepHeader.add(owner.id);
169
+ }
170
+ const rows = sourceRows.map((row, rowIndex) => ({
171
+ ...row,
172
+ children: placements.filter((placement) => placement.row === rowIndex).sort((a, b) => a.column - b.column).map(({ cell, rowspan, colspan }) => ({
173
+ ...cell,
174
+ attrs: { ...(cell.attrs || {}), rowspan, colspan, header: keepHeader.has(cell.id) },
175
+ })),
176
+ }));
177
+ return { table: { ...table, children: rows }, repairs };
178
+ };
@@ -0,0 +1,6 @@
1
+ export * from "./types.js";
2
+ export * from "./schema.js";
3
+ export * from "./grid.js";
4
+ export * from "./commands.js";
5
+ export * from "./formats.js";
6
+ export * from "./selection.js";
@@ -0,0 +1,6 @@
1
+ export * from "./types.js";
2
+ export * from "./schema.js";
3
+ export * from "./grid.js";
4
+ export * from "./commands.js";
5
+ export * from "./formats.js";
6
+ export * from "./selection.js";
@@ -0,0 +1,23 @@
1
+ import { type ContextMenuContribution, type PluginCommand } from "../plugin/types.js";
2
+ /**
3
+ * Wraps the fourteen existing, already-tested table commands
4
+ * (table/commands.ts's tableCommands) with the description Phase 10's doc
5
+ * generation needs. Every one already emits Phase 8c's fine-grained
6
+ * operations (insertNode/removeNode/moveNode/setNodeAttributes scoped to
7
+ * the affected row/cell, plus a cell-scoped replaceNode for merge) - this
8
+ * wrap does not touch that, it only adds metadata around commands that are
9
+ * already, individually, exactly what a PluginCommand's `run` needs.
10
+ */
11
+ export declare const tablePluginCommands: Record<string, PluginCommand>;
12
+ /**
13
+ * Phase 11.5 §2.3: table.insertRow/table.insertColumn need caller-generated
14
+ * ids (rowId/cellIds/paragraphIds) that can't live in a static `params` -
15
+ * the dispatching UI must merge fresh ids in at invocation time, the same
16
+ * way surface/input.ts's Tab handling special-cases list.indent/outdent's
17
+ * dynamic params. table.splitCell has the same requirement plus only
18
+ * applies to an already-merged cell, which needs more than a scope-kind
19
+ * check to detect - left out of this first pass rather than shown
20
+ * unconditionally. table.setHeader/moveRow/moveColumn already have
21
+ * dedicated toolbar buttons; not duplicated here.
22
+ */
23
+ export declare const tableContextMenuContributions: readonly ContextMenuContribution[];
@@ -0,0 +1,119 @@
1
+ import { definePluginCommand } from "../plugin/types.js";
2
+ import { tableCommands } from "./commands.js";
3
+ /**
4
+ * Wraps the fourteen existing, already-tested table commands
5
+ * (table/commands.ts's tableCommands) with the description Phase 10's doc
6
+ * generation needs. Every one already emits Phase 8c's fine-grained
7
+ * operations (insertNode/removeNode/moveNode/setNodeAttributes scoped to
8
+ * the affected row/cell, plus a cell-scoped replaceNode for merge) - this
9
+ * wrap does not touch that, it only adds metadata around commands that are
10
+ * already, individually, exactly what a PluginCommand's `run` needs.
11
+ */
12
+ export const tablePluginCommands = {
13
+ "table.insert": definePluginCommand({
14
+ id: "table.insert", run: tableCommands["table.insert"],
15
+ description: "Inserts a new table with the given row/column count at the current position.",
16
+ options: {
17
+ rows: { description: "Number of rows.", required: true },
18
+ columns: { description: "Number of columns.", required: true },
19
+ withHeader: { description: "Whether the first row is a header row." },
20
+ placement: { description: "\"before\" or \"after\" the current block." },
21
+ ids: { description: "Caller-provided ids for the table, its rows, cells, and paragraphs.", required: true },
22
+ },
23
+ }),
24
+ "table.remove": definePluginCommand({
25
+ id: "table.remove", run: tableCommands["table.remove"],
26
+ description: "Removes the selected table entirely.",
27
+ }),
28
+ "table.insertRow": definePluginCommand({
29
+ id: "table.insertRow", run: tableCommands["table.insertRow"],
30
+ description: "Inserts a new row into the selected table, bumping the rowspan of any cell whose span crosses the insertion point.",
31
+ options: {
32
+ position: { description: "\"before\" or \"after\" the current row." },
33
+ rowIndex: { description: "Explicit row index to insert at, instead of relative to the current row." },
34
+ rowId: { description: "Caller-provided id for the new row.", required: true },
35
+ cellIds: { description: "Caller-provided ids for the new row's cells." },
36
+ paragraphIds: { description: "Caller-provided ids for the new cells' paragraphs." },
37
+ },
38
+ }),
39
+ "table.removeRow": definePluginCommand({
40
+ id: "table.removeRow", run: tableCommands["table.removeRow"],
41
+ description: "Removes a row from the selected table, relocating any cell anchored there whose rowspan reaches further down.",
42
+ options: { rowIndex: { description: "The row index to remove; defaults to the current row." } },
43
+ }),
44
+ "table.insertColumn": definePluginCommand({
45
+ id: "table.insertColumn", run: tableCommands["table.insertColumn"],
46
+ description: "Inserts a new column into the selected table, one operation per affected row.",
47
+ options: {
48
+ position: { description: "\"before\" or \"after\" the current column." },
49
+ columnIndex: { description: "Explicit column index to insert at." },
50
+ cellIds: { description: "Caller-provided ids for the new column's cells, one per row needing one." },
51
+ paragraphIds: { description: "Caller-provided ids for the new cells' paragraphs." },
52
+ },
53
+ }),
54
+ "table.removeColumn": definePluginCommand({
55
+ id: "table.removeColumn", run: tableCommands["table.removeColumn"],
56
+ description: "Removes a column from the selected table, one operation per affected row.",
57
+ options: { columnIndex: { description: "The column index to remove; defaults to the current column." } },
58
+ }),
59
+ "table.mergeCells": definePluginCommand({
60
+ id: "table.mergeCells", run: tableCommands["table.mergeCells"],
61
+ description: "Merges the selected rectangular cell range into one cell, concatenating simple inline content or preserving block content.",
62
+ }),
63
+ "table.splitCell": definePluginCommand({
64
+ id: "table.splitCell", run: tableCommands["table.splitCell"],
65
+ description: "Splits a previously-merged cell back into its individual cells.",
66
+ options: { cellIds: { description: "Caller-provided ids for the newly-created cells.", required: true }, paragraphIds: { description: "Caller-provided ids for the new cells' paragraphs.", required: true } },
67
+ }),
68
+ "table.setHeader": definePluginCommand({
69
+ id: "table.setHeader", run: tableCommands["table.setHeader"],
70
+ description: "Sets which leading rows and/or columns of the table are headers.",
71
+ options: { target: { description: "\"row\", \"column\", \"both\", or \"none\".", required: true } },
72
+ }),
73
+ "table.setCellAttributes": definePluginCommand({
74
+ id: "table.setCellAttributes", run: tableCommands["table.setCellAttributes"],
75
+ description: "Sets attributes on the selected cell(s).",
76
+ options: { attrs: { description: "The attributes to set.", required: true } },
77
+ }),
78
+ "table.setColumnWidth": definePluginCommand({
79
+ id: "table.setColumnWidth", run: tableCommands["table.setColumnWidth"],
80
+ description: "Sets a single column's width.",
81
+ options: { index: { description: "The column index.", required: true }, width: { description: "The new width in pixels.", required: true } },
82
+ }),
83
+ "table.setRowHeight": definePluginCommand({
84
+ id: "table.setRowHeight", run: tableCommands["table.setRowHeight"],
85
+ description: "Sets a single row's height.",
86
+ options: { index: { description: "The row index.", required: true }, height: { description: "The new height in pixels.", required: true } },
87
+ }),
88
+ "table.moveRow": definePluginCommand({
89
+ id: "table.moveRow", run: tableCommands["table.moveRow"],
90
+ description: "Moves a row up or down, refusing moves that would split a rowspan.",
91
+ options: { direction: { description: "\"up\" or \"down\".", required: true }, index: { description: "The row index; defaults to the current row." } },
92
+ }),
93
+ "table.moveColumn": definePluginCommand({
94
+ id: "table.moveColumn", run: tableCommands["table.moveColumn"],
95
+ description: "Moves a column left or right, refusing moves that would split a colspan.",
96
+ options: { direction: { description: "\"left\" or \"right\".", required: true }, index: { description: "The column index; defaults to the current column." } },
97
+ }),
98
+ };
99
+ /**
100
+ * Phase 11.5 §2.3: table.insertRow/table.insertColumn need caller-generated
101
+ * ids (rowId/cellIds/paragraphIds) that can't live in a static `params` -
102
+ * the dispatching UI must merge fresh ids in at invocation time, the same
103
+ * way surface/input.ts's Tab handling special-cases list.indent/outdent's
104
+ * dynamic params. table.splitCell has the same requirement plus only
105
+ * applies to an already-merged cell, which needs more than a scope-kind
106
+ * check to detect - left out of this first pass rather than shown
107
+ * unconditionally. table.setHeader/moveRow/moveColumn already have
108
+ * dedicated toolbar buttons; not duplicated here.
109
+ */
110
+ export const tableContextMenuContributions = [
111
+ { id: "table.contextMenu.insertRowAbove", commandId: "table.insertRow", params: { position: "before" }, label: "Insert row above", scopeKinds: ["table-grid"] },
112
+ { id: "table.contextMenu.insertRowBelow", commandId: "table.insertRow", params: { position: "after" }, label: "Insert row below", scopeKinds: ["table-grid"] },
113
+ { id: "table.contextMenu.removeRow", commandId: "table.removeRow", label: "Delete row", scopeKinds: ["table-grid"] },
114
+ { id: "table.contextMenu.insertColumnLeft", commandId: "table.insertColumn", params: { position: "before" }, label: "Insert column left", scopeKinds: ["table-grid"] },
115
+ { id: "table.contextMenu.insertColumnRight", commandId: "table.insertColumn", params: { position: "after" }, label: "Insert column right", scopeKinds: ["table-grid"] },
116
+ { id: "table.contextMenu.removeColumn", commandId: "table.removeColumn", label: "Delete column", scopeKinds: ["table-grid"] },
117
+ { id: "table.contextMenu.mergeCells", commandId: "table.mergeCells", label: "Merge cells", scopeKinds: ["table-grid"] },
118
+ { id: "table.contextMenu.removeTable", commandId: "table.remove", label: "Delete table", scopeKinds: ["table-grid"] },
119
+ ];
@@ -0,0 +1,2 @@
1
+ import type { NodeSpec } from "../types.js";
2
+ export declare const tableNodeSpecs: readonly NodeSpec[];
@@ -0,0 +1,38 @@
1
+ const positiveInt = { default: 1, validate: (value) => Number.isInteger(value) && Number(value) >= 1 };
2
+ const optionalString = { validate: (value) => typeof value === "string" };
3
+ export const tableNodeSpecs = [
4
+ {
5
+ type: "table", group: "block", semanticRole: "table", content: "table_row+", isolating: false,
6
+ attributes: {
7
+ columnWidths: { validate: (value) => Array.isArray(value) && value.every((width) => Number.isFinite(width) && Number(width) > 0) },
8
+ caption: optionalString,
9
+ layout: { validate: (value) => value === "auto" || value === "fixed" },
10
+ },
11
+ },
12
+ // "table_cell*", not "+": a row every one of whose columns is covered by
13
+ // an earlier row's rowspan legitimately has zero own cells (e.g. after
14
+ // merging a selection that spans that row's full width). Row count still
15
+ // has to match grid.rows for rowspan bookkeeping, so the row node itself
16
+ // must exist even when empty - it cannot simply be deleted. See
17
+ // docs/bugs/table-row-empty-rowspan-coverage-rejected.md.
18
+ { type: "table_row", group: "block", semanticRole: "table-row", content: "table_cell*", attributes: { height: { validate: (value) => Number.isFinite(value) && Number(value) > 0 } } },
19
+ {
20
+ type: "table_cell", group: "block", semanticRole: "table-cell", content: "block+", isolating: true,
21
+ attributes: {
22
+ colspan: positiveInt, rowspan: positiveInt,
23
+ header: { default: false, validate: (value) => typeof value === "boolean" },
24
+ background: optionalString,
25
+ // `borders`: legacy uniform (all 4 sides) CSS border shorthand -
26
+ // still the only shape HTML paste-import ever produces. `borderTop`/
27
+ // `borderRight`/`borderBottom`/`borderLeft`: per-side overrides (the
28
+ // "which sides" control the border-options UI added) - each, when
29
+ // set, wins over `borders` for that one side only; see
30
+ // surface/renderer.ts's per-side application order. Independent
31
+ // optional strings rather than one structured attr so an unset side
32
+ // round-trips as simply absent, matching every other optional cell
33
+ // style attr in this schema.
34
+ borders: optionalString, borderTop: optionalString, borderRight: optionalString, borderBottom: optionalString, borderLeft: optionalString,
35
+ verticalAlign: { validate: (value) => value === "top" || value === "middle" || value === "bottom" },
36
+ },
37
+ },
38
+ ];
@@ -0,0 +1,7 @@
1
+ import type { PositionLookup } from "../scope/types.js";
2
+ import type { SmartElementNode, SmartSelection } from "../types.js";
3
+ import type { CellSelectionRect, Rect } from "./types.js";
4
+ /** Expands a logical rectangle until every intersected merged cell is fully contained. */
5
+ export declare const snapTableCellRect: (table: SmartElementNode, input: Rect) => CellSelectionRect;
6
+ /** Model cell selections store direction as anchor/head positions while the overlay consumes the snapped rectangle. */
7
+ export declare const cellSelectionFromIds: (anchorCellId: string, headCellId: string, positions: PositionLookup) => SmartSelection | null;
@@ -0,0 +1,35 @@
1
+ import { occupancyGridFor } from "./grid.js";
2
+ /** Expands a logical rectangle until every intersected merged cell is fully contained. */
3
+ export const snapTableCellRect = (table, input) => {
4
+ const grid = occupancyGridFor(table);
5
+ const rect = {
6
+ top: Math.max(0, Math.min(input.top, grid.rows - 1)),
7
+ left: Math.max(0, Math.min(input.left, grid.columns - 1)),
8
+ bottom: Math.max(1, Math.min(input.bottom, grid.rows)),
9
+ right: Math.max(1, Math.min(input.right, grid.columns)),
10
+ };
11
+ let changed = true;
12
+ while (changed) {
13
+ changed = false;
14
+ grid.anchors.forEach((cell) => {
15
+ if (cell.top < rect.bottom && cell.bottom > rect.top && cell.left < rect.right && cell.right > rect.left) {
16
+ const next = { top: Math.min(rect.top, cell.top), left: Math.min(rect.left, cell.left), bottom: Math.max(rect.bottom, cell.bottom), right: Math.max(rect.right, cell.right) };
17
+ if (next.top !== rect.top || next.left !== rect.left || next.bottom !== rect.bottom || next.right !== rect.right) {
18
+ Object.assign(rect, next);
19
+ changed = true;
20
+ }
21
+ }
22
+ });
23
+ }
24
+ const anchor = grid.at(rect.top, rect.left);
25
+ const head = grid.at(rect.bottom - 1, rect.right - 1);
26
+ if (!anchor || !head)
27
+ throw new Error("Cell selection rectangle does not resolve to a complete table grid.");
28
+ return { tableId: table.id, anchorCellId: anchor.cellId, headCellId: head.cellId, rect, cellIds: grid.anchorsIn(rect).map((cell) => cell.cellId) };
29
+ };
30
+ /** Model cell selections store direction as anchor/head positions while the overlay consumes the snapped rectangle. */
31
+ export const cellSelectionFromIds = (anchorCellId, headCellId, positions) => {
32
+ const anchor = positions.contentRangeOf(anchorCellId)?.from;
33
+ const head = positions.contentRangeOf(headCellId)?.to;
34
+ return anchor && head ? { type: "cell", anchor, head } : null;
35
+ };
@@ -0,0 +1,109 @@
1
+ import type { Attrs, SmartDocument, SmartElementNode, SmartOperation, SmartSchema } from "../types.js";
2
+ import type { PositionLookup, ResolvedScope } from "../scope/types.js";
3
+ export interface Rect {
4
+ readonly top: number;
5
+ readonly left: number;
6
+ /** Exclusive. */
7
+ readonly bottom: number;
8
+ /** Exclusive. */
9
+ readonly right: number;
10
+ }
11
+ export interface GridCell {
12
+ readonly cellId: string;
13
+ readonly top: number;
14
+ readonly left: number;
15
+ /** Exclusive. */
16
+ readonly bottom: number;
17
+ /** Exclusive. */
18
+ readonly right: number;
19
+ readonly isAnchor: boolean;
20
+ readonly rowIndex: number;
21
+ readonly childIndex: number;
22
+ readonly node: SmartElementNode;
23
+ }
24
+ export interface OccupancyGrid {
25
+ readonly tableId: string;
26
+ readonly rows: number;
27
+ readonly columns: number;
28
+ readonly anchors: readonly GridCell[];
29
+ at(row: number, col: number): GridCell | null;
30
+ anchorsIn(rect: Rect): GridCell[];
31
+ coveredIn(rect: Rect): GridCell[];
32
+ isRectangular(rect: Rect): boolean;
33
+ }
34
+ export interface TableGeometryIssue {
35
+ readonly code: "overlap" | "overhang" | "hole" | "unequal-width" | "noncontiguous-header" | "invalid-child";
36
+ readonly row: number;
37
+ readonly column?: number;
38
+ readonly cellId?: string;
39
+ readonly message: string;
40
+ }
41
+ export interface TableCommandContext {
42
+ readonly schema: SmartSchema;
43
+ readonly positions: PositionLookup;
44
+ }
45
+ export type TableCommand<P> = (document: SmartDocument, scope: ResolvedScope, params: P, ctx: TableCommandContext) => SmartOperation[];
46
+ export interface TableIds {
47
+ readonly tableId: string;
48
+ readonly rowIds: readonly string[];
49
+ readonly cellIds: readonly string[];
50
+ readonly paragraphIds: readonly string[];
51
+ }
52
+ export interface InsertTableParams {
53
+ readonly rows: number;
54
+ readonly columns: number;
55
+ readonly withHeader?: boolean;
56
+ readonly placement?: "before" | "after";
57
+ readonly ids: TableIds;
58
+ }
59
+ export interface RowParams {
60
+ readonly position?: "before" | "after";
61
+ readonly rowIndex?: number;
62
+ readonly rowId?: string;
63
+ readonly cellIds?: readonly string[];
64
+ readonly paragraphIds?: readonly string[];
65
+ }
66
+ export interface ColumnParams {
67
+ readonly position?: "before" | "after";
68
+ readonly columnIndex?: number;
69
+ readonly cellIds?: readonly string[];
70
+ readonly paragraphIds?: readonly string[];
71
+ }
72
+ export interface HeaderParams {
73
+ readonly target: "row" | "column" | "both" | "none";
74
+ }
75
+ export interface CellAttributesParams {
76
+ readonly attrs: Attrs;
77
+ }
78
+ /**
79
+ * `widths`, when supplied, seeds the full columnWidths array instead of
80
+ * the command's own `Array(columns).fill(120)` fallback - the command
81
+ * layer has no way to know a table's real *rendered* per-column widths
82
+ * (that's DOM state, not model state), so a caller that already measured
83
+ * them (a resize-handle UI, mid-drag) should pass them through rather
84
+ * than let every other column silently reset to a fabricated default.
85
+ */
86
+ export interface ColumnWidthParams {
87
+ readonly index: number;
88
+ readonly width: number;
89
+ readonly widths?: readonly number[];
90
+ }
91
+ export interface RowHeightParams {
92
+ readonly index: number;
93
+ readonly height: number;
94
+ }
95
+ export interface MoveTableAxisParams {
96
+ readonly direction: "up" | "down" | "left" | "right";
97
+ readonly index?: number;
98
+ }
99
+ export interface SplitCellParams {
100
+ readonly cellIds: readonly string[];
101
+ readonly paragraphIds: readonly string[];
102
+ }
103
+ export interface CellSelectionRect {
104
+ readonly tableId: string;
105
+ readonly anchorCellId: string;
106
+ readonly headCellId: string;
107
+ readonly rect: Rect;
108
+ readonly cellIds: readonly string[];
109
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import type { PersistedEditorDocument, SmartDocument, SmartSchema, SmartTransaction } from "./types.js";
2
+ export declare class StaleTransactionError extends Error {
3
+ constructor(expected: number, actual: number);
4
+ }
5
+ /**
6
+ * A transaction was behind the current revision, but not too far behind to
7
+ * rebase - and at least one of its operations could not be safely
8
+ * transformed against what was committed in the meantime (see
9
+ * collab/transform.ts's doc comment for exactly which shapes this covers:
10
+ * concurrent moves sharing an array, or a concurrent edit to content a
11
+ * merge absorbed). The transaction is rejected outright rather than
12
+ * partially or incorrectly applied - the caller (a real transport
13
+ * implementation, in 12b-server/transport) decides what happens to the
14
+ * user's edit from here (e.g. surface it for manual resolution, retry as a
15
+ * fresh transaction against current state, or convert it to a suggestion).
16
+ */
17
+ export declare class RebaseConflictError extends Error {
18
+ readonly reasons: readonly {
19
+ readonly operationIndex: number;
20
+ readonly reason: string;
21
+ }[];
22
+ constructor(reasons: readonly {
23
+ readonly operationIndex: number;
24
+ readonly reason: string;
25
+ }[]);
26
+ }
27
+ /**
28
+ * A transaction's baseRevision is older than anything this editor instance
29
+ * has retained (see FoundationEditor's revisionLogLimit) - there is not
30
+ * enough history left to rebase through. The caller must resync (reload
31
+ * the full document at the current revision, e.g. via replaceState) rather
32
+ * than attempt a partial rebase against an incomplete operation log.
33
+ */
34
+ export declare class ResyncRequiredError extends Error {
35
+ readonly atRevision: number;
36
+ constructor(atRevision: number);
37
+ }
38
+ export declare const invertTransaction: (transaction: SmartTransaction) => SmartTransaction;
39
+ export declare const assertTransactionSerializable: (transaction: SmartTransaction) => void;
40
+ export declare const applyTransactionAtomic: (state: PersistedEditorDocument, transaction: SmartTransaction, schema: SmartSchema) => PersistedEditorDocument;
41
+ export declare const documentsEqual: (left: SmartDocument, right: SmartDocument) => boolean;