@threadlabs/looma 0.1.9 → 0.1.11

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 (210) hide show
  1. package/dist/{chunk-UMFO4QNN.js → chunk-DYIMEQY7.js} +27 -26
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/looma.cjs.js +1 -1
  4. package/dist/cjs/ui-affordance-scope.cjs.entry.js +152 -0
  5. package/dist/cjs/ui-avatar-group.cjs.entry.js +1 -1
  6. package/dist/cjs/ui-avatar.cjs.entry.js +1 -1
  7. package/dist/cjs/ui-badge.cjs.entry.js +1 -1
  8. package/dist/cjs/ui-button.cjs.entry.js +1 -1
  9. package/dist/cjs/ui-checkbox.cjs.entry.js +1 -1
  10. package/dist/cjs/ui-context-menu.cjs.entry.js +1 -1
  11. package/dist/cjs/ui-dialog.cjs.entry.js +1 -1
  12. package/dist/cjs/ui-disclosure.cjs.entry.js +1 -1
  13. package/dist/cjs/ui-floating-action-button.cjs.entry.js +1 -1
  14. package/dist/cjs/ui-form-field.cjs.entry.js +1 -1
  15. package/dist/cjs/ui-icon-button.cjs.entry.js +4 -2
  16. package/dist/cjs/ui-input.cjs.entry.js +1 -1
  17. package/dist/cjs/ui-menu-item.cjs.entry.js +1 -1
  18. package/dist/cjs/ui-menu.cjs.entry.js +1 -1
  19. package/dist/cjs/ui-popover.cjs.entry.js +1 -1
  20. package/dist/cjs/ui-radio-group.cjs.entry.js +1 -1
  21. package/dist/cjs/ui-radio.cjs.entry.js +1 -1
  22. package/dist/cjs/ui-search-result-row.cjs.entry.js +1 -1
  23. package/dist/cjs/ui-search-shell.cjs.entry.js +1 -1
  24. package/dist/cjs/ui-select.cjs.entry.js +1 -1
  25. package/dist/cjs/ui-switch.cjs.entry.js +2 -2
  26. package/dist/cjs/ui-tabs.cjs.entry.js +1 -1
  27. package/dist/cjs/ui-textarea.cjs.entry.js +1 -1
  28. package/dist/cjs/ui-toast-region.cjs.entry.js +1 -1
  29. package/dist/cjs/ui-tooltip.cjs.entry.js +1 -1
  30. package/dist/cjs/ui-top-bar.cjs.entry.js +1 -1
  31. package/dist/collection/collection-manifest.json +1 -0
  32. package/dist/collection/components/ui-affordance-scope/ui-affordance-scope.css +8 -0
  33. package/dist/collection/components/ui-affordance-scope/ui-affordance-scope.js +70 -0
  34. package/dist/collection/components/ui-avatar/ui-avatar.js +1 -1
  35. package/dist/collection/components/ui-avatar-group/ui-avatar-group.js +1 -1
  36. package/dist/collection/components/ui-badge/ui-badge.js +1 -1
  37. package/dist/collection/components/ui-button/ui-button.js +1 -1
  38. package/dist/collection/components/ui-checkbox/ui-checkbox.js +1 -1
  39. package/dist/collection/components/ui-context-menu/ui-context-menu.js +1 -1
  40. package/dist/collection/components/ui-dialog/ui-dialog.js +1 -1
  41. package/dist/collection/components/ui-disclosure/ui-disclosure.js +1 -1
  42. package/dist/collection/components/ui-floating-action-button/ui-floating-action-button.js +1 -1
  43. package/dist/collection/components/ui-form-field/ui-form-field.js +1 -1
  44. package/dist/collection/components/ui-icon-button/ui-icon-button.css +53 -0
  45. package/dist/collection/components/ui-icon-button/ui-icon-button.js +23 -1
  46. package/dist/collection/components/ui-input/ui-input.js +1 -1
  47. package/dist/collection/components/ui-menu/ui-menu.js +1 -1
  48. package/dist/collection/components/ui-menu-item/ui-menu-item.js +1 -1
  49. package/dist/collection/components/ui-popover/ui-popover.js +1 -1
  50. package/dist/collection/components/ui-radio/ui-radio.js +1 -1
  51. package/dist/collection/components/ui-radio-group/ui-radio-group.js +1 -1
  52. package/dist/collection/components/ui-search-result-row/ui-search-result-row.js +1 -1
  53. package/dist/collection/components/ui-search-shell/ui-search-shell.js +1 -1
  54. package/dist/collection/components/ui-select/ui-select.js +1 -1
  55. package/dist/collection/components/ui-switch/ui-switch.js +2 -2
  56. package/dist/collection/components/ui-tabs/ui-tabs.js +1 -1
  57. package/dist/collection/components/ui-textarea/ui-textarea.js +1 -1
  58. package/dist/collection/components/ui-toast-region/ui-toast-region.js +1 -1
  59. package/dist/collection/components/ui-tooltip/ui-tooltip.js +1 -1
  60. package/dist/collection/components/ui-top-bar/ui-top-bar.js +1 -1
  61. package/dist/collection/overlay/positioning.js +135 -0
  62. package/dist/components/index.d.ts +2 -0
  63. package/dist/components/index.js +1 -1
  64. package/dist/components/{p-gHC_Ei92.js → p-QiwSQmKJ.js} +1 -1
  65. package/dist/components/ui-affordance-scope.d.ts +11 -0
  66. package/dist/components/ui-affordance-scope.js +1 -0
  67. package/dist/components/ui-avatar-group.js +1 -1
  68. package/dist/components/ui-avatar.js +1 -1
  69. package/dist/components/ui-badge.js +1 -1
  70. package/dist/components/ui-button.js +1 -1
  71. package/dist/components/ui-checkbox.js +1 -1
  72. package/dist/components/ui-context-menu.js +1 -1
  73. package/dist/components/ui-dialog.js +1 -1
  74. package/dist/components/ui-disclosure.js +1 -1
  75. package/dist/components/ui-floating-action-button.js +1 -1
  76. package/dist/components/ui-form-field.js +1 -1
  77. package/dist/components/ui-icon-button.js +1 -1
  78. package/dist/components/ui-input.js +1 -1
  79. package/dist/components/ui-menu-item.js +1 -1
  80. package/dist/components/ui-menu.js +1 -1
  81. package/dist/components/ui-popover.js +1 -1
  82. package/dist/components/ui-radio-group.js +1 -1
  83. package/dist/components/ui-radio.js +1 -1
  84. package/dist/components/ui-search-result-row.js +1 -1
  85. package/dist/components/ui-search-shell.js +1 -1
  86. package/dist/components/ui-select.js +1 -1
  87. package/dist/components/ui-switch.js +1 -1
  88. package/dist/components/ui-tabs.js +1 -1
  89. package/dist/components/ui-textarea.js +1 -1
  90. package/dist/components/ui-toast-region.js +1 -1
  91. package/dist/components/ui-tooltip.js +1 -1
  92. package/dist/components/ui-top-bar.js +1 -1
  93. package/dist/esm/loader.js +1 -1
  94. package/dist/esm/looma.js +1 -1
  95. package/dist/esm/ui-affordance-scope.entry.js +150 -0
  96. package/dist/esm/ui-avatar-group.entry.js +1 -1
  97. package/dist/esm/ui-avatar.entry.js +1 -1
  98. package/dist/esm/ui-badge.entry.js +1 -1
  99. package/dist/esm/ui-button.entry.js +1 -1
  100. package/dist/esm/ui-checkbox.entry.js +1 -1
  101. package/dist/esm/ui-context-menu.entry.js +1 -1
  102. package/dist/esm/ui-dialog.entry.js +1 -1
  103. package/dist/esm/ui-disclosure.entry.js +1 -1
  104. package/dist/esm/ui-floating-action-button.entry.js +1 -1
  105. package/dist/esm/ui-form-field.entry.js +1 -1
  106. package/dist/esm/ui-icon-button.entry.js +4 -2
  107. package/dist/esm/ui-input.entry.js +1 -1
  108. package/dist/esm/ui-menu-item.entry.js +1 -1
  109. package/dist/esm/ui-menu.entry.js +1 -1
  110. package/dist/esm/ui-popover.entry.js +1 -1
  111. package/dist/esm/ui-radio-group.entry.js +1 -1
  112. package/dist/esm/ui-radio.entry.js +1 -1
  113. package/dist/esm/ui-search-result-row.entry.js +1 -1
  114. package/dist/esm/ui-search-shell.entry.js +1 -1
  115. package/dist/esm/ui-select.entry.js +1 -1
  116. package/dist/esm/ui-switch.entry.js +2 -2
  117. package/dist/esm/ui-tabs.entry.js +1 -1
  118. package/dist/esm/ui-textarea.entry.js +1 -1
  119. package/dist/esm/ui-toast-region.entry.js +1 -1
  120. package/dist/esm/ui-tooltip.entry.js +1 -1
  121. package/dist/esm/ui-top-bar.entry.js +1 -1
  122. package/dist/index.cjs +306 -29
  123. package/dist/index.d.cts +42 -1
  124. package/dist/index.d.ts +42 -1
  125. package/dist/index.js +127 -2
  126. package/dist/looma/looma.esm.js +1 -1
  127. package/dist/looma/p-0198bb21.entry.js +1 -0
  128. package/dist/looma/{p-d39905f9.entry.js → p-051f578c.entry.js} +1 -1
  129. package/dist/looma/{p-c14233bc.entry.js → p-0584a051.entry.js} +1 -1
  130. package/dist/looma/{p-cb15e8e3.entry.js → p-078f9fb8.entry.js} +1 -1
  131. package/dist/looma/{p-dc857ed4.entry.js → p-0f45c5f0.entry.js} +1 -1
  132. package/dist/looma/{p-201243dc.entry.js → p-1681b218.entry.js} +1 -1
  133. package/dist/looma/{p-41d62a83.entry.js → p-2ae73d5b.entry.js} +1 -1
  134. package/dist/looma/{p-5a645647.entry.js → p-2ed7e241.entry.js} +1 -1
  135. package/dist/looma/{p-5717a4c4.entry.js → p-34417499.entry.js} +1 -1
  136. package/dist/looma/{p-610b2eca.entry.js → p-4b422d40.entry.js} +1 -1
  137. package/dist/looma/{p-15e619fd.entry.js → p-5ba9d496.entry.js} +1 -1
  138. package/dist/looma/p-5d4713a6.entry.js +1 -0
  139. package/dist/looma/{p-96de71ad.entry.js → p-624ba086.entry.js} +1 -1
  140. package/dist/looma/{p-01425a37.entry.js → p-65c25c94.entry.js} +1 -1
  141. package/dist/looma/{p-66a203a1.entry.js → p-7e94d90d.entry.js} +1 -1
  142. package/dist/looma/p-8c09c724.entry.js +1 -0
  143. package/dist/looma/{p-4c54d489.entry.js → p-8d5adb17.entry.js} +1 -1
  144. package/dist/looma/p-95340a13.entry.js +1 -0
  145. package/dist/looma/{p-07167650.entry.js → p-95cd639d.entry.js} +1 -1
  146. package/dist/looma/{p-03f0594b.entry.js → p-96f73d07.entry.js} +1 -1
  147. package/dist/looma/p-a33522a2.entry.js +1 -0
  148. package/dist/looma/{p-ee31c7b4.entry.js → p-a5127c7d.entry.js} +1 -1
  149. package/dist/looma/{p-dfcb2cca.entry.js → p-a9f46811.entry.js} +1 -1
  150. package/dist/looma/{p-93ce1c62.entry.js → p-b7aa4488.entry.js} +1 -1
  151. package/dist/looma/{p-5df568d8.entry.js → p-c6721aba.entry.js} +1 -1
  152. package/dist/looma/{p-3ecd7120.entry.js → p-d273b857.entry.js} +1 -1
  153. package/dist/looma/{p-24d7aa5b.entry.js → p-ed5abf6d.entry.js} +1 -1
  154. package/dist/types/components/ui-affordance-scope/ui-affordance-scope.d.ts +11 -0
  155. package/dist/types/components/ui-icon-button/ui-icon-button.d.ts +2 -0
  156. package/dist/types/components.d.ts +37 -0
  157. package/dist/types/overlay/positioning.d.ts +40 -0
  158. package/dist/ui-affordance-scope.entry-ZKUJ5AT4.js +144 -0
  159. package/dist/{ui-avatar-group.entry-S6DFXYB7.js → ui-avatar-group.entry-I4XM44BI.js} +2 -2
  160. package/dist/{ui-avatar.entry-MDRGXLWQ.js → ui-avatar.entry-ZZAMZAVF.js} +2 -2
  161. package/dist/{ui-badge.entry-RLL4YKPD.js → ui-badge.entry-DQXYMC3E.js} +2 -2
  162. package/dist/{ui-button.entry-IYMYLBFY.js → ui-button.entry-DM7BUZLI.js} +2 -2
  163. package/dist/{ui-checkbox.entry-K5FGWDG2.js → ui-checkbox.entry-X3PPWKIJ.js} +2 -2
  164. package/dist/{ui-context-menu.entry-KWXXJ3ZV.js → ui-context-menu.entry-KAW4NIFE.js} +2 -2
  165. package/dist/{ui-dialog.entry-RKHLQLQM.js → ui-dialog.entry-D23SNXWB.js} +2 -2
  166. package/dist/{ui-disclosure.entry-FRZKGEJP.js → ui-disclosure.entry-DOG6JZU7.js} +2 -2
  167. package/dist/{ui-floating-action-button.entry-BH4FDSTL.js → ui-floating-action-button.entry-VPQ7VBFS.js} +2 -2
  168. package/dist/{ui-form-field.entry-3CR2KSUH.js → ui-form-field.entry-SYZ6XSCG.js} +2 -2
  169. package/dist/ui-icon-button.entry-2SZBOIH5.js +26 -0
  170. package/dist/{ui-input.entry-5PQR37HS.js → ui-input.entry-PALICYLZ.js} +2 -2
  171. package/dist/{ui-menu-item.entry-2T3QWHLK.js → ui-menu-item.entry-W6TEFP5Y.js} +2 -2
  172. package/dist/{ui-menu.entry-Q5Z5YO5P.js → ui-menu.entry-7NARDV6S.js} +2 -2
  173. package/dist/{ui-popover.entry-4P2NWWAY.js → ui-popover.entry-ZXYHLDTP.js} +2 -2
  174. package/dist/{ui-radio-group.entry-QKPRNV26.js → ui-radio-group.entry-XEUKMD6J.js} +2 -2
  175. package/dist/{ui-radio.entry-O4DOMFNU.js → ui-radio.entry-4ABBHDLN.js} +2 -2
  176. package/dist/{ui-search-result-row.entry-BR5O3UCH.js → ui-search-result-row.entry-3HHM7OV4.js} +2 -2
  177. package/dist/{ui-search-shell.entry-2ZBP7SA3.js → ui-search-shell.entry-PJTFOBPT.js} +2 -2
  178. package/dist/{ui-select.entry-L75HQY72.js → ui-select.entry-A3RI5XCG.js} +2 -2
  179. package/dist/{ui-switch.entry-L5QWD3BT.js → ui-switch.entry-JNRS2YTN.js} +3 -3
  180. package/dist/{ui-tabs.entry-KWRD6Y7J.js → ui-tabs.entry-MQ4V5XCP.js} +2 -2
  181. package/dist/{ui-textarea.entry-JC3HPEBS.js → ui-textarea.entry-JJXJQZQR.js} +2 -2
  182. package/dist/{ui-toast-region.entry-C6KK4OM4.js → ui-toast-region.entry-STHVESL5.js} +2 -2
  183. package/dist/{ui-tooltip.entry-G5EOCWP4.js → ui-tooltip.entry-4W7CRIKI.js} +2 -2
  184. package/dist/{ui-top-bar.entry-YLKVAQFH.js → ui-top-bar.entry-WM3SS2HR.js} +2 -2
  185. package/editor/{chunk-OK5NARJI.js → chunk-4VGVEHU2.js} +244 -70
  186. package/editor/{chunk-NJ2KAMS2.js → chunk-F4AYF33M.js} +74 -34
  187. package/editor/extensions/index.d.ts +2 -2
  188. package/editor/extensions/index.js +1 -1
  189. package/editor/index.d.ts +1 -1
  190. package/editor/index.js +7 -2
  191. package/editor/table-overlay-jjvdARTJ.d.ts +95 -0
  192. package/editor/ui.d.ts +1 -1
  193. package/editor/ui.js +7 -2
  194. package/editor.css +232 -73
  195. package/layout/index.cjs +5 -0
  196. package/layout/index.css +22 -3
  197. package/layout/index.js +5 -0
  198. package/layout.css +24 -3
  199. package/package.json +1 -1
  200. package/tokens.css +9 -0
  201. package/vue/{chunk-5ELJ4UPG.js → chunk-YN4IUYVY.js} +14 -2
  202. package/vue/editor/index.js +94 -37
  203. package/vue/index.d.ts +5 -1
  204. package/vue/index.js +3 -1
  205. package/dist/looma/p-754cfff3.entry.js +0 -1
  206. package/dist/looma/p-940a931a.entry.js +0 -1
  207. package/dist/looma/p-941221ad.entry.js +0 -1
  208. package/dist/looma/p-955fb814.entry.js +0 -1
  209. package/dist/ui-icon-button.entry-LB54U25M.js +0 -24
  210. package/editor/table-overlay-Bq0F5xPg.d.ts +0 -64
@@ -3,6 +3,7 @@ import {
3
3
  } from "./chunk-CX4QDKSV.js";
4
4
 
5
5
  // src/table-context-menu.ts
6
+ import { clampRectToViewport, getVisualViewportRect } from "@threadlabs/looma/core";
6
7
  var TAG = "ui-editor-table-context-menu";
7
8
  function dispatchTableAction(element, action) {
8
9
  element.dispatchEvent(
@@ -68,14 +69,11 @@ if (typeof HTMLElement !== "undefined") {
68
69
  if (!menu) return;
69
70
  menu.style.translate = "";
70
71
  const rect = menu.getBoundingClientRect();
71
- const gutter = 12;
72
- const visualViewport = window.visualViewport;
73
- const viewportLeft = visualViewport?.offsetLeft ?? 0;
74
- const viewportTop = visualViewport?.offsetTop ?? 0;
75
- const viewportRight = viewportLeft + (visualViewport?.width ?? window.innerWidth);
76
- const viewportBottom = viewportTop + (visualViewport?.height ?? window.innerHeight);
77
- const offsetX = rect.right > viewportRight - gutter ? viewportRight - gutter - rect.right : Math.max(0, viewportLeft + gutter - rect.left);
78
- const offsetY = rect.bottom > viewportBottom - gutter ? viewportBottom - gutter - rect.bottom : Math.max(0, viewportTop + gutter - rect.top);
72
+ const { x: offsetX, y: offsetY } = clampRectToViewport(
73
+ rect,
74
+ getVisualViewportRect(window),
75
+ 12
76
+ );
79
77
  if (offsetX !== 0 || offsetY !== 0) {
80
78
  menu.style.translate = `${offsetX}px ${offsetY}px`;
81
79
  }
@@ -107,6 +105,7 @@ if (typeof HTMLElement !== "undefined") {
107
105
  {
108
106
  heading: "Cells",
109
107
  actions: [
108
+ { action: "clear-cells", label: "Clear selected cells" },
110
109
  { action: "merge-cells", label: "Merge cells", can: "can-merge-cells" },
111
110
  { action: "split-cell", label: "Split cell", can: "can-split-cell" }
112
111
  ]
@@ -126,7 +125,7 @@ if (typeof HTMLElement !== "undefined") {
126
125
  }
127
126
  return {
128
127
  ...section,
129
- actions: section.actions.filter((action) => this.getBoolAttr(action.can))
128
+ actions: section.actions.filter((action) => !action.can || this.getBoolAttr(action.can))
130
129
  };
131
130
  }).filter((section) => "backgrounds" in section ? section.backgrounds.length > 0 : section.actions.length > 0);
132
131
  let html = '<div class="ui-editor-table-context-menu" role="menu">';
@@ -277,6 +276,7 @@ if (typeof HTMLElement !== "undefined") {
277
276
  {
278
277
  heading: "Cells",
279
278
  actions: [
279
+ { action: "clear-cells", label: "Clear selected cells" },
280
280
  { action: "merge-cells", label: "Merge selected cells", can: "can-merge-cells" },
281
281
  { action: "split-cell", label: "Split merged cell", can: "can-split-cell" }
282
282
  ]
@@ -292,7 +292,7 @@ if (typeof HTMLElement !== "undefined") {
292
292
  ];
293
293
  const availableOverflowSections = overflowSections.map((section) => ({
294
294
  ...section,
295
- actions: section.actions.filter((action) => this.getBoolAttr(action.can))
295
+ actions: section.actions.filter((action) => !action.can || this.getBoolAttr(action.can))
296
296
  })).filter((section) => section.actions.length > 0);
297
297
  this.innerHTML = [
298
298
  '<div class="ui-editor-table-toolbar" role="toolbar" aria-label="Table actions">',
@@ -467,17 +467,112 @@ if (typeof HTMLElement !== "undefined") {
467
467
  }
468
468
 
469
469
  // src/table-overlay.ts
470
+ import {
471
+ createProximityCoordinator
472
+ } from "@threadlabs/looma/core";
470
473
  var TAG4 = "ui-editor-table-overlay";
471
474
  var DEFAULT_ROWS = 3;
472
475
  var DEFAULT_COLS = 3;
476
+ function sameNumbers(left, right) {
477
+ return left.length === right.length && left.every((value, index) => value === right[index]);
478
+ }
479
+ function sameActiveCell(left, right) {
480
+ if (left === right) return true;
481
+ if (!left || !right) return false;
482
+ return left.left === right.left && left.top === right.top && left.width === right.width && left.height === right.height && left.rowIndex === right.rowIndex && left.columnIndex === right.columnIndex;
483
+ }
484
+ function sameGeometry(left, right) {
485
+ if (left === right) return true;
486
+ if (!left || !right) return false;
487
+ return sameNumbers(left.rowBoundaries, right.rowBoundaries) && sameNumbers(left.columnBoundaries, right.columnBoundaries) && sameActiveCell(left.activeCell, right.activeCell);
488
+ }
489
+ function mapTableCells(table) {
490
+ const rows = Array.from(table.rows);
491
+ const grid = [];
492
+ const coordinates = /* @__PURE__ */ new Map();
493
+ rows.forEach((row, rowIndex) => {
494
+ grid[rowIndex] ??= [];
495
+ let columnIndex = 0;
496
+ for (const cell of Array.from(row.cells)) {
497
+ while (grid[rowIndex]?.[columnIndex]) columnIndex += 1;
498
+ coordinates.set(cell, { rowIndex, columnIndex });
499
+ const rowSpan = cell.rowSpan === 0 ? rows.length - rowIndex : Math.max(1, cell.rowSpan);
500
+ const columnSpan = Math.max(1, cell.colSpan);
501
+ for (let rowOffset = 0; rowOffset < rowSpan; rowOffset += 1) {
502
+ const gridRow = grid[rowIndex + rowOffset] ??= [];
503
+ for (let columnOffset = 0; columnOffset < columnSpan; columnOffset += 1) {
504
+ gridRow[columnIndex + columnOffset] = cell;
505
+ }
506
+ }
507
+ columnIndex += columnSpan;
508
+ }
509
+ });
510
+ return { grid, coordinates };
511
+ }
512
+ function resolveTableCellAt(table, rowIndex, columnIndex) {
513
+ return mapTableCells(table).grid[rowIndex]?.[columnIndex] ?? null;
514
+ }
515
+ function uniqueSorted(values) {
516
+ return values.sort((left, right) => left - right).filter((value, index, all) => index === 0 || Math.abs(value - (all[index - 1] ?? value)) >= 0.5).map((value) => Math.round(value * 100) / 100);
517
+ }
518
+ function measureTableOverlayGeometry(table, activeCell) {
519
+ const tableRect = table.getBoundingClientRect();
520
+ const rows = Array.from(table.rows);
521
+ const cells = rows.flatMap((row) => Array.from(row.cells));
522
+ const { coordinates } = mapTableCells(table);
523
+ const rowBoundaries = uniqueSorted(rows.flatMap((row) => {
524
+ const rect = row.getBoundingClientRect();
525
+ return [rect.top - tableRect.top, rect.bottom - tableRect.top];
526
+ }));
527
+ const columnBoundaries = uniqueSorted(cells.flatMap((cell) => {
528
+ const rect = cell.getBoundingClientRect();
529
+ return [rect.left - tableRect.left, rect.right - tableRect.left];
530
+ }));
531
+ if (!activeCell || !table.contains(activeCell)) {
532
+ return { rowBoundaries, columnBoundaries, activeCell: null };
533
+ }
534
+ const cellRect = activeCell.getBoundingClientRect();
535
+ const coordinate = coordinates.get(activeCell);
536
+ return {
537
+ rowBoundaries,
538
+ columnBoundaries,
539
+ activeCell: {
540
+ left: Math.round((cellRect.left - tableRect.left) * 100) / 100,
541
+ top: Math.round((cellRect.top - tableRect.top) * 100) / 100,
542
+ width: Math.round(cellRect.width * 100) / 100,
543
+ height: Math.round(cellRect.height * 100) / 100,
544
+ rowIndex: coordinate?.rowIndex ?? 0,
545
+ columnIndex: coordinate?.columnIndex ?? 0
546
+ }
547
+ };
548
+ }
549
+ function finiteNumbers(value) {
550
+ if (!value) return [];
551
+ const values = value.split(",").map((part) => Number(part.trim()));
552
+ return values.every(Number.isFinite) ? values : [];
553
+ }
554
+ function fallbackBoundaries(segments, length) {
555
+ return Array.from({ length: segments + 1 }, (_, index) => index * length / segments);
556
+ }
473
557
  if (typeof HTMLElement !== "undefined") {
474
558
  class UIEditorTableOverlayElement extends HTMLElement {
475
559
  static get observedAttributes() {
476
- return ["open", "rows", "cols"];
560
+ return ["open", "rows", "cols", "row-boundaries", "column-boundaries", "active-cell"];
477
561
  }
478
562
  #rows = DEFAULT_ROWS;
479
563
  #cols = DEFAULT_COLS;
480
564
  #activeControlKey = null;
565
+ #proximity = null;
566
+ #geometry = null;
567
+ #renderPending = false;
568
+ get geometry() {
569
+ return this.#geometry;
570
+ }
571
+ set geometry(value) {
572
+ if (sameGeometry(this.#geometry, value)) return;
573
+ this.#geometry = value;
574
+ this.#scheduleRender();
575
+ }
481
576
  connectedCallback() {
482
577
  this.#rows = this.#readBoundedNumber("rows", DEFAULT_ROWS);
483
578
  this.#cols = this.#readBoundedNumber("cols", DEFAULT_COLS);
@@ -487,6 +582,10 @@ if (typeof HTMLElement !== "undefined") {
487
582
  this.addEventListener("pointerout", this.onPointerOut);
488
583
  this.addEventListener("focusin", this.onFocusIn);
489
584
  this.addEventListener("focusout", this.onFocusOut);
585
+ this.#proximity = createProximityCoordinator(this, {
586
+ pointerTarget: this.ownerDocument,
587
+ anchorSelector: ".ui-editor-table-overlay__handle[data-ui-affordance]"
588
+ });
490
589
  }
491
590
  disconnectedCallback() {
492
591
  this.removeEventListener("click", this.onClick);
@@ -494,68 +593,139 @@ if (typeof HTMLElement !== "undefined") {
494
593
  this.removeEventListener("pointerout", this.onPointerOut);
495
594
  this.removeEventListener("focusin", this.onFocusIn);
496
595
  this.removeEventListener("focusout", this.onFocusOut);
596
+ this.#proximity?.destroy();
597
+ this.#proximity = null;
497
598
  }
498
599
  attributeChangedCallback(name) {
499
600
  if (name === "rows") this.#rows = this.#readBoundedNumber("rows", DEFAULT_ROWS);
500
601
  if (name === "cols") this.#cols = this.#readBoundedNumber("cols", DEFAULT_COLS);
501
- this.render();
602
+ this.#scheduleRender();
603
+ }
604
+ #scheduleRender() {
605
+ if (!this.isConnected || this.#renderPending) return;
606
+ this.#renderPending = true;
607
+ queueMicrotask(() => {
608
+ this.#renderPending = false;
609
+ if (this.isConnected) this.render();
610
+ });
502
611
  }
503
612
  #readBoundedNumber(name, fallback) {
504
- const parsed = parseInt(this.getAttribute(name) ?? String(fallback), 10);
505
- if (!Number.isFinite(parsed)) {
506
- return fallback;
507
- }
508
- return Math.min(100, Math.max(1, parsed));
613
+ const parsed = Number.parseInt(this.getAttribute(name) ?? String(fallback), 10);
614
+ return Number.isFinite(parsed) ? Math.min(100, Math.max(1, parsed)) : fallback;
615
+ }
616
+ #boundaries(name, segments) {
617
+ if (this.#geometry) {
618
+ return name === "row-boundaries" ? this.#geometry.rowBoundaries : this.#geometry.columnBoundaries;
619
+ }
620
+ const explicit = finiteNumbers(this.getAttribute(name));
621
+ if (explicit.length === segments + 1) return explicit;
622
+ const length = name === "row-boundaries" ? this.getBoundingClientRect().height : this.getBoundingClientRect().width;
623
+ return fallbackBoundaries(segments, length);
624
+ }
625
+ #activeCell() {
626
+ if (this.#geometry) return this.#geometry.activeCell;
627
+ const values = finiteNumbers(this.getAttribute("active-cell"));
628
+ if (values.length !== 6) return null;
629
+ const [left, top, width, height, rowIndex, columnIndex] = values;
630
+ if (left === void 0 || top === void 0 || width === void 0 || height === void 0 || rowIndex === void 0 || columnIndex === void 0) return null;
631
+ return { left, top, width, height, rowIndex, columnIndex };
632
+ }
633
+ dispatch(detail) {
634
+ this.dispatchEvent(new CustomEvent(
635
+ "looma-editor-table-overlay-action",
636
+ { detail, bubbles: true, composed: true }
637
+ ));
509
638
  }
510
639
  onClick = (event) => {
511
- const target = event.target.closest("[data-action]");
512
- if (!target) {
640
+ const target = event.target.closest("button[data-action]");
641
+ if (!target) return;
642
+ const action = target.dataset.action;
643
+ if (!action) return;
644
+ if (action === "select-row" || action === "select-column") {
645
+ const rowIndex = Number.parseInt(target.dataset.rowIndex ?? "", 10);
646
+ const columnIndex = Number.parseInt(target.dataset.columnIndex ?? "", 10);
647
+ if (Number.isFinite(rowIndex) && Number.isFinite(columnIndex)) {
648
+ this.dispatch({ action, rowIndex, columnIndex });
649
+ }
513
650
  return;
514
651
  }
515
- const action = target.getAttribute("data-action");
516
- const boundaryIndex = parseInt(target.getAttribute("data-boundary-index") ?? "-1", 10);
517
- if (!action || !Number.isFinite(boundaryIndex) || boundaryIndex < 0) {
652
+ if (action === "open-cell-menu") {
653
+ const rowIndex = Number.parseInt(target.dataset.rowIndex ?? "", 10);
654
+ const columnIndex = Number.parseInt(target.dataset.columnIndex ?? "", 10);
655
+ if (!Number.isFinite(rowIndex) || !Number.isFinite(columnIndex)) return;
656
+ const rect = target.getBoundingClientRect();
657
+ this.dispatch({
658
+ action,
659
+ rowIndex,
660
+ columnIndex,
661
+ anchor: { left: rect.left, top: rect.top, right: rect.right, bottom: rect.bottom }
662
+ });
518
663
  return;
519
664
  }
520
- this.dispatchEvent(
521
- new CustomEvent("looma-editor-table-overlay-action", {
522
- detail: { action, boundaryIndex },
523
- bubbles: true,
524
- composed: true
525
- })
526
- );
665
+ const boundaryIndex = Number.parseInt(target.dataset.boundaryIndex ?? "", 10);
666
+ if (!Number.isFinite(boundaryIndex) || boundaryIndex < 0) return;
667
+ this.dispatch({ action, boundaryIndex });
527
668
  };
528
669
  onPointerOver = (event) => {
529
670
  const control = event.target.closest("[data-control-key]");
530
671
  this.#setActiveControl(control?.dataset.controlKey ?? null);
531
672
  };
532
673
  onPointerOut = (event) => {
533
- const relatedTarget = event.relatedTarget;
534
- const nextControl = relatedTarget instanceof Element ? relatedTarget.closest("[data-control-key]") : null;
535
- this.#setActiveControl(nextControl?.dataset.controlKey ?? null);
674
+ const related = event.relatedTarget;
675
+ const next = related instanceof Element ? related.closest("[data-control-key]") : null;
676
+ this.#setActiveControl(next?.dataset.controlKey ?? null);
536
677
  };
537
678
  onFocusIn = (event) => {
538
679
  const control = event.target.closest("[data-control-key]");
539
680
  this.#setActiveControl(control?.dataset.controlKey ?? null);
540
681
  };
541
682
  onFocusOut = (event) => {
542
- const relatedTarget = event.relatedTarget;
543
- const nextControl = relatedTarget instanceof Element ? relatedTarget.closest("[data-control-key]") : null;
544
- this.#setActiveControl(nextControl?.dataset.controlKey ?? null);
683
+ const related = event.relatedTarget;
684
+ const next = related instanceof Element ? related.closest("[data-control-key]") : null;
685
+ this.#setActiveControl(next?.dataset.controlKey ?? null);
545
686
  };
546
687
  #setActiveControl(controlKey) {
547
- if (this.#activeControlKey === controlKey) {
548
- return;
549
- }
688
+ if (this.#activeControlKey === controlKey) return;
550
689
  this.#activeControlKey = controlKey;
551
690
  this.#syncActiveControl();
552
691
  }
553
692
  #syncActiveControl() {
554
- const controls = this.querySelectorAll("[data-control-key]");
555
- controls.forEach((control) => {
556
- control.dataset.active = this.#activeControlKey && control.dataset.controlKey === this.#activeControlKey ? "true" : "false";
693
+ this.querySelectorAll("[data-control-key]").forEach((control) => {
694
+ control.dataset.active = this.#activeControlKey === control.dataset.controlKey ? "true" : "false";
557
695
  });
558
696
  }
697
+ #insertionControl(axis, index, position) {
698
+ const first = index === 0;
699
+ const action = axis === "row" ? first ? "add-row-before" : "add-row-after" : first ? "add-column-before" : "add-column-after";
700
+ const noun = axis === "row" ? "row" : "column";
701
+ const relation = first ? axis === "row" ? "above" : "left" : axis === "row" ? "below" : "right";
702
+ const label = `Insert ${noun} ${relation}`;
703
+ const controlKey = `${axis}:${index}`;
704
+ const positionStyle = axis === "row" ? `top:${position}px;` : `left:${position}px;`;
705
+ return [
706
+ `<div class="ui-editor-table-overlay__control ui-editor-table-overlay__control--${axis}"`,
707
+ ` style="${positionStyle}" data-control-key="${controlKey}"`,
708
+ ` data-active="${this.#activeControlKey === controlKey ? "true" : "false"}">`,
709
+ '<span class="ui-editor-table-overlay__line" aria-hidden="true"></span>',
710
+ '<span class="ui-editor-table-overlay__guide" data-ui-guide aria-hidden="true"></span>',
711
+ `<button type="button" class="ui-editor-table-overlay__handle" data-ui-affordance="insert-${noun}"`,
712
+ ` data-action="${action}" data-boundary-index="${index}" aria-label="${label}">`,
713
+ '<span aria-hidden="true">+</span>',
714
+ `<span class="ui-editor-table-overlay__tooltip" role="tooltip">${label}</span>`,
715
+ "</button>",
716
+ "</div>"
717
+ ].join("");
718
+ }
719
+ #activeCellControls(cell) {
720
+ const centerX = cell.left + cell.width / 2;
721
+ const centerY = cell.top + cell.height / 2;
722
+ const indexes = `data-row-index="${cell.rowIndex}" data-column-index="${cell.columnIndex}"`;
723
+ return [
724
+ `<button type="button" class="ui-editor-table-overlay__selector ui-editor-table-overlay__selector--row" style="top:${centerY}px" data-action="select-row" ${indexes} title="Select row" aria-label="Select row"><span aria-hidden="true"></span></button>`,
725
+ `<button type="button" class="ui-editor-table-overlay__selector ui-editor-table-overlay__selector--column" style="left:${centerX}px" data-action="select-column" ${indexes} title="Select column" aria-label="Select column"><span aria-hidden="true"></span></button>`,
726
+ `<button type="button" class="ui-editor-table-overlay__cell-menu" style="left:${cell.left + cell.width - 30}px;top:${cell.top + 6}px" data-action="open-cell-menu" ${indexes} title="Cell actions" aria-label="Cell actions"><span aria-hidden="true">\u2304</span></button>`
727
+ ].join("");
728
+ }
559
729
  render() {
560
730
  const open = this.hasAttribute("open") && this.getAttribute("open") !== "false";
561
731
  this.hidden = !open;
@@ -563,24 +733,22 @@ if (typeof HTMLElement !== "undefined") {
563
733
  this.#setActiveControl(null);
564
734
  return;
565
735
  }
566
- let html = '<div class="ui-editor-table-overlay" aria-label="Table insertion controls">';
567
- html += '<div class="ui-editor-table-overlay__rows">';
568
- for (let i = 0; i <= this.#rows; i++) {
569
- const action = i === 0 ? "add-row-before" : "add-row-after";
570
- const controlKey = `row:${i}`;
571
- html += `<button type="button" class="ui-editor-table-overlay__control ui-editor-table-overlay__control--row" style="--ui-editor-table-overlay-boundary-index:${i};--ui-editor-table-overlay-segments:${this.#rows};" data-action="${action}" data-boundary-index="${i}" data-control-key="${controlKey}" data-active="${this.#activeControlKey === controlKey ? "true" : "false"}" aria-label="Add row"><span class="ui-editor-table-overlay__handle" aria-hidden="true">+</span></button>`;
572
- }
573
- html += "</div>";
574
- html += '<div class="ui-editor-table-overlay__cols">';
575
- for (let i = 0; i <= this.#cols; i++) {
576
- const action = i === 0 ? "add-column-before" : "add-column-after";
577
- const controlKey = `col:${i}`;
578
- html += `<button type="button" class="ui-editor-table-overlay__control ui-editor-table-overlay__control--col" style="--ui-editor-table-overlay-boundary-index:${i};--ui-editor-table-overlay-segments:${this.#cols};" data-action="${action}" data-boundary-index="${i}" data-control-key="${controlKey}" data-active="${this.#activeControlKey === controlKey ? "true" : "false"}" aria-label="Add column"><span class="ui-editor-table-overlay__handle" aria-hidden="true">+</span></button>`;
579
- }
580
- html += "</div>";
581
- html += "</div>";
582
- this.innerHTML = html;
736
+ const rows = this.#boundaries("row-boundaries", this.#rows);
737
+ const columns = this.#boundaries("column-boundaries", this.#cols);
738
+ const cell = this.#activeCell();
739
+ this.innerHTML = [
740
+ '<div class="ui-editor-table-overlay" aria-label="Table controls">',
741
+ '<div class="ui-editor-table-overlay__rows">',
742
+ rows.map((position, index) => this.#insertionControl("row", index, position)).join(""),
743
+ "</div>",
744
+ '<div class="ui-editor-table-overlay__cols">',
745
+ columns.map((position, index) => this.#insertionControl("col", index, position)).join(""),
746
+ "</div>",
747
+ cell ? this.#activeCellControls(cell) : "",
748
+ "</div>"
749
+ ].join("");
583
750
  this.#syncActiveControl();
751
+ this.#proximity?.refresh();
584
752
  }
585
753
  }
586
754
  if (typeof window !== "undefined" && !customElements.get(TAG4)) {
@@ -589,6 +757,7 @@ if (typeof HTMLElement !== "undefined") {
589
757
  }
590
758
 
591
759
  // src/slash-menu.ts
760
+ import { getVisualViewportRect as getVisualViewportRect2 } from "@threadlabs/looma/core";
592
761
  var TAG5 = "ui-editor-slash-menu";
593
762
  var MOBILE_BREAKPOINT = 768;
594
763
  var MENU_HEIGHT_ESTIMATE = 320;
@@ -737,9 +906,9 @@ if (typeof HTMLElement !== "undefined") {
737
906
  this.style.display = "none";
738
907
  return;
739
908
  }
740
- const visualViewport = window.visualViewport;
741
- const viewportWidth = visualViewport?.width ?? window.innerWidth;
742
- const viewportHeight = visualViewport?.height ?? window.innerHeight;
909
+ const viewport = getVisualViewportRect2(window);
910
+ const viewportWidth = viewport.width;
911
+ const viewportHeight = viewport.height;
743
912
  this.style.display = "block";
744
913
  this.style.position = "fixed";
745
914
  this.style.zIndex = "500";
@@ -749,30 +918,30 @@ if (typeof HTMLElement !== "undefined") {
749
918
  MENU_HEIGHT_ESTIMATE,
750
919
  Math.max(0, viewportHeight - toolbarReserve)
751
920
  );
752
- this.style.left = `${visualViewport?.offsetLeft ?? 0}px`;
921
+ this.style.left = `${viewport.left}px`;
753
922
  this.style.right = "";
754
923
  this.style.bottom = "";
755
- this.style.top = `${(visualViewport?.offsetTop ?? 0) + viewportHeight - menuHeight - toolbarReserve}px`;
924
+ this.style.top = `${viewport.top + viewportHeight - menuHeight - toolbarReserve}px`;
756
925
  this.style.width = `${viewportWidth}px`;
757
926
  this.style.maxHeight = `${menuHeight}px`;
758
927
  return;
759
928
  }
760
929
  let top;
761
- const spaceBelow = viewportHeight - rect.bottom - OFFSET;
762
- const spaceAbove = rect.top - OFFSET;
930
+ const spaceBelow = viewport.bottom - rect.bottom - OFFSET;
931
+ const spaceAbove = rect.top - viewport.top - OFFSET;
763
932
  if (spaceBelow >= MENU_HEIGHT_ESTIMATE || spaceBelow >= spaceAbove) {
764
933
  top = rect.bottom + OFFSET;
765
934
  } else {
766
935
  top = rect.top - OFFSET - MENU_HEIGHT_ESTIMATE;
767
936
  }
768
937
  let left = rect.left;
769
- if (left + MENU_WIDTH > viewportWidth - 8) {
770
- left = viewportWidth - MENU_WIDTH - 8;
938
+ if (left + MENU_WIDTH > viewport.right - 8) {
939
+ left = viewport.right - MENU_WIDTH - 8;
771
940
  }
772
- if (left < 8) {
773
- left = 8;
941
+ if (left < viewport.left + 8) {
942
+ left = viewport.left + 8;
774
943
  }
775
- this.style.top = `${Math.max(8, top)}px`;
944
+ this.style.top = `${Math.max(viewport.top + 8, top)}px`;
776
945
  this.style.left = `${left}px`;
777
946
  this.style.right = "";
778
947
  this.style.bottom = "";
@@ -840,3 +1009,8 @@ if (typeof HTMLElement !== "undefined") {
840
1009
  customElements.define(TAG6, UIEditorToolbarElement);
841
1010
  }
842
1011
  }
1012
+
1013
+ export {
1014
+ resolveTableCellAt,
1015
+ measureTableOverlayGeometry
1016
+ };
@@ -5307,6 +5307,10 @@ var TableHeader = Node18.create({
5307
5307
  // src/extensions/table-formatting.ts
5308
5308
  var LoomaTable = Table.configure({
5309
5309
  resizable: true,
5310
+ // Tiptap also uses this as its inward coordinate probe. The 5px default can
5311
+ // resolve to the row around an empty minimum-width cell instead of the cell.
5312
+ handleWidth: 3,
5313
+ cellMinWidth: 112,
5310
5314
  lastColumnResizable: false
5311
5315
  });
5312
5316
  function normalizeTableCellAlignment(value) {
@@ -5470,7 +5474,14 @@ function getDefaultEditorExtensions(options = {}) {
5470
5474
 
5471
5475
  // src/extensions/table-commands.ts
5472
5476
  import { TextSelection as TextSelection4 } from "@tiptap/pm/state";
5473
- import { TableMap } from "@tiptap/pm/tables";
5477
+ import {
5478
+ addColumn,
5479
+ addRow,
5480
+ CellSelection as CellSelection2,
5481
+ cellAround,
5482
+ deleteCellSelection,
5483
+ TableMap
5484
+ } from "@tiptap/pm/tables";
5474
5485
  var NO_TABLE_CAPABILITIES = {
5475
5486
  canAddRowBefore: false,
5476
5487
  canAddRowAfter: false,
@@ -5548,6 +5559,14 @@ function handleTableAction(editor, detail) {
5548
5559
  return editor.chain().focus().deleteColumn().run();
5549
5560
  case "delete-table":
5550
5561
  return editor.chain().focus().deleteTable().run();
5562
+ case "clear-cells": {
5563
+ if (!(editor.state.selection instanceof CellSelection2)) {
5564
+ const cellPos = findSelectedCellPosition(editor);
5565
+ if (cellPos === null) return false;
5566
+ if (!editor.commands.setCellSelection({ anchorCell: cellPos })) return false;
5567
+ }
5568
+ return deleteCellSelection(editor.state, editor.view.dispatch);
5569
+ }
5551
5570
  case "merge-cells":
5552
5571
  return editor.chain().focus().mergeCells().run();
5553
5572
  case "split-cell":
@@ -5619,17 +5638,6 @@ function normalizeColumnWidths(widths, availableWidth, minWidth) {
5619
5638
  );
5620
5639
  return distributeWidthDelta(scaled, availableWidth, minWidth);
5621
5640
  }
5622
- function getTextPositionInCell(tablePos, table, rowIndex, colIndex) {
5623
- let pos = tablePos + 1;
5624
- for (let r = 0; r < rowIndex; r++) {
5625
- pos += table.child(r).nodeSize;
5626
- }
5627
- const row = table.child(rowIndex);
5628
- for (let c = 0; c < colIndex; c++) {
5629
- pos += row.child(c).nodeSize;
5630
- }
5631
- return pos + 3;
5632
- }
5633
5641
  function findTable(editor) {
5634
5642
  const { $from } = editor.state.selection;
5635
5643
  for (let d = $from.depth; d > 0; d--) {
@@ -5640,6 +5648,26 @@ function findTable(editor) {
5640
5648
  }
5641
5649
  return null;
5642
5650
  }
5651
+ function findSelectedCellPosition(editor) {
5652
+ return cellAround(editor.state.selection.$from)?.pos ?? null;
5653
+ }
5654
+ function selectTableAxis(editor, axis, rowIndex, columnIndex) {
5655
+ const tableInfo = findTable(editor);
5656
+ if (!tableInfo) return false;
5657
+ const { pos: tablePos, node: table } = tableInfo;
5658
+ const map = TableMap.get(table);
5659
+ const row = Math.min(Math.max(0, rowIndex), map.height - 1);
5660
+ const column = Math.min(Math.max(0, columnIndex), map.width - 1);
5661
+ const start = axis === "row" ? map.positionAt(row, 0, table) : map.positionAt(0, column, table);
5662
+ const end = axis === "row" ? map.positionAt(row, map.width - 1, table) : map.positionAt(map.height - 1, column, table);
5663
+ const tableStart = tablePos + 1;
5664
+ if (!editor.commands.setCellSelection({
5665
+ anchorCell: tableStart + start,
5666
+ headCell: tableStart + end
5667
+ })) return false;
5668
+ editor.commands.focus();
5669
+ return true;
5670
+ }
5643
5671
  function insertTableAtRange(editor, range, options = {}) {
5644
5672
  const rows = Math.min(10, Math.max(1, options.rows ?? 3));
5645
5673
  const cols = Math.min(10, Math.max(1, options.cols ?? 3));
@@ -5700,45 +5728,57 @@ function normalizeActiveTableColumnWidths(editor, tableElement, minWidth = 25) {
5700
5728
  function handleTableOverlayAction(editor, detail) {
5701
5729
  const tableInfo = findTable(editor);
5702
5730
  if (!tableInfo) return false;
5703
- const { action, boundaryIndex } = detail;
5731
+ const { action } = detail;
5732
+ if (action === "select-row" || action === "select-column") {
5733
+ return selectTableAxis(
5734
+ editor,
5735
+ action === "select-row" ? "row" : "column",
5736
+ detail.rowIndex,
5737
+ detail.columnIndex
5738
+ );
5739
+ }
5740
+ if (action === "open-cell-menu") return true;
5741
+ if (!("boundaryIndex" in detail)) return false;
5742
+ const { boundaryIndex } = detail;
5704
5743
  const { pos: tablePos, node: table } = tableInfo;
5705
- const rows = table.childCount;
5706
- const cols = rows > 0 ? table.child(0).childCount : 0;
5707
- let cellPos;
5708
- let command;
5744
+ const map = TableMap.get(table);
5745
+ const rect = {
5746
+ map,
5747
+ table,
5748
+ tableStart: tablePos + 1,
5749
+ left: 0,
5750
+ top: 0,
5751
+ right: map.width,
5752
+ bottom: map.height
5753
+ };
5754
+ let transaction = editor.state.tr;
5709
5755
  switch (action) {
5710
5756
  case "add-row-before": {
5711
- const rowIndex = Math.min(boundaryIndex, rows - 1);
5712
- if (rowIndex < 0) return false;
5713
- cellPos = getTextPositionInCell(tablePos, table, rowIndex, 0);
5714
- command = () => editor.chain().focus().setTextSelection(cellPos).addRowBefore().run();
5757
+ if (boundaryIndex !== 0) return false;
5758
+ transaction = addRow(transaction, rect, 0);
5715
5759
  break;
5716
5760
  }
5717
5761
  case "add-row-after": {
5718
- const rowIndex = Math.min(boundaryIndex - 1, rows - 1);
5719
- if (rowIndex < 0) return false;
5720
- cellPos = getTextPositionInCell(tablePos, table, rowIndex, 0);
5721
- command = () => editor.chain().focus().setTextSelection(cellPos).addRowAfter().run();
5762
+ if (boundaryIndex < 1 || boundaryIndex > map.height) return false;
5763
+ transaction = addRow(transaction, rect, boundaryIndex);
5722
5764
  break;
5723
5765
  }
5724
5766
  case "add-column-before": {
5725
- const colIndex = Math.min(boundaryIndex, cols - 1);
5726
- if (colIndex < 0) return false;
5727
- cellPos = getTextPositionInCell(tablePos, table, 0, colIndex);
5728
- command = () => editor.chain().focus().setTextSelection(cellPos).addColumnBefore().run();
5767
+ if (boundaryIndex !== 0) return false;
5768
+ transaction = addColumn(transaction, rect, 0);
5729
5769
  break;
5730
5770
  }
5731
5771
  case "add-column-after": {
5732
- const colIndex = Math.min(boundaryIndex - 1, cols - 1);
5733
- if (colIndex < 0) return false;
5734
- cellPos = getTextPositionInCell(tablePos, table, 0, colIndex);
5735
- command = () => editor.chain().focus().setTextSelection(cellPos).addColumnAfter().run();
5772
+ if (boundaryIndex < 1 || boundaryIndex > map.width) return false;
5773
+ transaction = addColumn(transaction, rect, boundaryIndex);
5736
5774
  break;
5737
5775
  }
5738
5776
  default:
5739
5777
  return false;
5740
5778
  }
5741
- return command();
5779
+ editor.view.dispatch(transaction);
5780
+ editor.commands.focus();
5781
+ return true;
5742
5782
  }
5743
5783
 
5744
5784
  // src/extensions/slash-command.ts
@@ -1,6 +1,6 @@
1
1
  import { AnyExtension, Editor, Range, Extension } from '@tiptap/core';
2
- import { d as TableContextMenuActionEventDetail, f as TableOverlayActionEventDetail } from '../table-overlay-Bq0F5xPg.js';
3
- export { a as TABLE_CELL_BACKGROUND_PRESETS } from '../table-overlay-Bq0F5xPg.js';
2
+ import { d as TableContextMenuActionEventDetail, g as TableOverlayActionEventDetail } from '../table-overlay-jjvdARTJ.js';
3
+ export { a as TABLE_CELL_BACKGROUND_PRESETS } from '../table-overlay-jjvdARTJ.js';
4
4
 
5
5
  /**
6
6
  * Default Tiptap extension preset for Looma editor.
@@ -18,7 +18,7 @@ import {
18
18
  setActiveTableCellAlignment,
19
19
  setActiveTableCellBackground,
20
20
  shouldShowTextFormattingToolbar
21
- } from "../chunk-NJ2KAMS2.js";
21
+ } from "../chunk-F4AYF33M.js";
22
22
  import {
23
23
  TABLE_CELL_BACKGROUND_PRESETS
24
24
  } from "../chunk-CX4QDKSV.js";
package/editor/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { T as TABLE_CELL_BACKGROUND_OPTIONS, a as TABLE_CELL_BACKGROUND_PRESETS, b as TableCellBackgroundAction, c as TableContextMenuAction, d as TableContextMenuActionEventDetail, e as TableOverlayAction, f as TableOverlayActionEventDetail, d as TableToolbarActionEventDetail } from './table-overlay-Bq0F5xPg.js';
1
+ export { A as ActiveCellRect, T as TABLE_CELL_BACKGROUND_OPTIONS, a as TABLE_CELL_BACKGROUND_PRESETS, b as TableCellBackgroundAction, c as TableContextMenuAction, d as TableContextMenuActionEventDetail, e as TableInsertionAction, f as TableOverlayAction, g as TableOverlayActionEventDetail, h as TableOverlayGeometry, d as TableToolbarActionEventDetail, m as measureTableOverlayGeometry, r as resolveTableCellAt } from './table-overlay-jjvdARTJ.js';
2
2
  export { InsertTableEventDetail, SlashMenuAnchorRect, SlashMenuHighlightEventDetail, SlashMenuItem, SlashMenuSelectEventDetail } from './ui.js';
3
3
  export { ActiveTableUiState, DefaultEditorExtensionsOptions, InsertTableAtRangeOptions, LoomaSlashCommand, LoomaSlashCommandContext, LoomaSlashCommand as LoomaSlashCommandItem, LoomaSlashCommandOptions, LoomaSlashMenuSnapshot, LoomaTable, LoomaTableCell, LoomaTableHeader, LoomaTableKit, TableActionCapabilities, TableCellAlignment, TableCellBackground, createLoomaSlashCommandExtension, getActiveTableCellAlignment, getActiveTableCellBackground, getActiveTableUiState, getDefaultEditorExtensions, getDefaultSlashCommands, getLoomaTableExtensions, handleTableAction, handleTableOverlayAction, insertTableAtRange, normalizeActiveTableColumnWidths, setActiveTableCellAlignment, setActiveTableCellBackground, shouldShowTextFormattingToolbar } from './extensions/index.js';
4
4
  import '@tiptap/core';