@underverse-ui/underverse 1.0.135 → 1.0.137

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1006,6 +1006,8 @@ var en_default = {
1006
1006
  deleteTable: "Delete Table",
1007
1007
  toggleHeaderRow: "Toggle Header Row",
1008
1008
  toggleHeaderColumn: "Toggle Header Column",
1009
+ mergeCells: "Merge Cells",
1010
+ splitCell: "Split Cell",
1009
1011
  openControls: "Open Table Controls",
1010
1012
  quickAddColumnAfter: "Quick Add Column After",
1011
1013
  quickAddRowAfter: "Quick Add Row After",
@@ -1276,6 +1278,8 @@ var vi_default = {
1276
1278
  deleteTable: "X\xF3a b\u1EA3ng",
1277
1279
  toggleHeaderRow: "B\u1EADt/t\u1EAFt h\xE0ng ti\xEAu \u0111\u1EC1",
1278
1280
  toggleHeaderColumn: "B\u1EADt/t\u1EAFt c\u1ED9t ti\xEAu \u0111\u1EC1",
1281
+ mergeCells: "G\u1ED9p \xF4",
1282
+ splitCell: "T\xE1ch \xF4",
1279
1283
  openControls: "M\u1EDF \u0111i\u1EC1u khi\u1EC3n b\u1EA3ng",
1280
1284
  quickAddColumnAfter: "Th\xEAm nhanh c\u1ED9t sau",
1281
1285
  quickAddRowAfter: "Th\xEAm nhanh h\xE0ng sau",
@@ -1545,6 +1549,8 @@ var ko_default = {
1545
1549
  deleteTable: "\uD45C \uC0AD\uC81C",
1546
1550
  toggleHeaderRow: "\uD5E4\uB354 \uD589 \uC804\uD658",
1547
1551
  toggleHeaderColumn: "\uD5E4\uB354 \uC5F4 \uC804\uD658",
1552
+ mergeCells: "\uC140 \uBCD1\uD569",
1553
+ splitCell: "\uC140 \uBD84\uD560",
1548
1554
  openControls: "\uD45C \uCEE8\uD2B8\uB864 \uC5F4\uAE30",
1549
1555
  quickAddColumnAfter: "\uC624\uB978\uCABD \uC5F4 \uBE60\uB974\uAC8C \uCD94\uAC00",
1550
1556
  quickAddRowAfter: "\uC544\uB798 \uD589 \uBE60\uB974\uAC8C \uCD94\uAC00",
@@ -1814,6 +1820,8 @@ var ja_default = {
1814
1820
  deleteTable: "\u8868\u3092\u524A\u9664",
1815
1821
  toggleHeaderRow: "\u30D8\u30C3\u30C0\u30FC\u884C\u3092\u5207\u308A\u66FF\u3048",
1816
1822
  toggleHeaderColumn: "\u30D8\u30C3\u30C0\u30FC\u5217\u3092\u5207\u308A\u66FF\u3048",
1823
+ mergeCells: "\u30BB\u30EB\u3092\u7D50\u5408",
1824
+ splitCell: "\u30BB\u30EB\u3092\u5206\u5272",
1817
1825
  openControls: "\u8868\u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\u3092\u958B\u304F",
1818
1826
  quickAddColumnAfter: "\u53F3\u5074\u306B\u5217\u3092\u3059\u3070\u3084\u304F\u8FFD\u52A0",
1819
1827
  quickAddRowAfter: "\u4E0B\u306B\u884C\u3092\u3059\u3070\u3084\u304F\u8FFD\u52A0",
@@ -9343,6 +9351,7 @@ var DatePicker = ({
9343
9351
  {
9344
9352
  ref: inputRef,
9345
9353
  type: "text",
9354
+ "aria-label": value ? formatDateDisplay(value) : placeholder || t("placeholder"),
9346
9355
  disabled,
9347
9356
  placeholder: placeholder || t("placeholder"),
9348
9357
  value: isFocused ? inputValue : value ? formatDateDisplay(value) : "",
@@ -9360,8 +9369,7 @@ var DatePicker = ({
9360
9369
  },
9361
9370
  className: "w-full bg-transparent border-none outline-none focus:outline-none p-0 text-foreground font-medium placeholder-muted-foreground/60 min-w-0"
9362
9371
  }
9363
- ),
9364
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "sr-only", children: value ? formatDateDisplay(value) : placeholder || t("placeholder") })
9372
+ )
9365
9373
  ] }),
9366
9374
  /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
9367
9375
  value && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
@@ -10091,6 +10099,7 @@ var DateRangePicker = ({
10091
10099
  {
10092
10100
  ref: inputRef,
10093
10101
  type: "text",
10102
+ "aria-label": tempStart ? displayLabel : placeholder,
10094
10103
  disabled,
10095
10104
  placeholder,
10096
10105
  value: isFocused ? inputValue : tempStart ? displayLabel : "",
@@ -10108,8 +10117,7 @@ var DateRangePicker = ({
10108
10117
  },
10109
10118
  className: "w-full bg-transparent border-none outline-none focus:outline-none p-0 text-foreground font-medium placeholder-muted-foreground/60 min-w-0"
10110
10119
  }
10111
- ),
10112
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "sr-only", children: tempStart ? displayLabel : placeholder })
10120
+ )
10113
10121
  ] }),
10114
10122
  /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: cn("transition-all duration-300 text-muted-foreground group-hover:text-foreground", isOpen && "rotate-180 text-primary"), children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("svg", { className: cn(sizeStyles8[size].navIcon), fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
10115
10123
  ]
@@ -10787,12 +10795,12 @@ function MonthYearPicker({
10787
10795
  className
10788
10796
  ),
10789
10797
  children: [
10790
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2.5", children: [
10798
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2.5", children: [
10791
10799
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
10792
10800
  "div",
10793
10801
  {
10794
10802
  className: cn(
10795
- "flex items-center justify-center transition-colors duration-300",
10803
+ "flex shrink-0 items-center justify-center transition-colors duration-300",
10796
10804
  effectiveError ? "text-destructive" : success ? "text-success" : open ? "text-primary" : "text-muted-foreground group-hover:text-primary"
10797
10805
  ),
10798
10806
  children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react16.Calendar, { className: cn(sz.icon, "transition-transform duration-300", open && "rotate-12") })
@@ -10801,12 +10809,12 @@ function MonthYearPicker({
10801
10809
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
10802
10810
  "span",
10803
10811
  {
10804
- className: cn("truncate font-medium transition-colors duration-200", !hasValue && "text-muted-foreground", hasValue && "text-foreground"),
10812
+ className: cn("min-w-0 truncate font-medium transition-colors duration-200", !hasValue && "text-muted-foreground", hasValue && "text-foreground"),
10805
10813
  children: hasValue ? display : placeholder
10806
10814
  }
10807
10815
  )
10808
10816
  ] }),
10809
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: cn("ml-2 transition-all duration-300 text-muted-foreground group-hover:text-foreground", open && "rotate-180 text-primary"), children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react16.ChevronDown, { className: sz.icon }) })
10817
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: cn("ml-2 shrink-0 transition-all duration-300 text-muted-foreground group-hover:text-foreground", open && "rotate-180 text-primary"), children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react16.ChevronDown, { className: sz.icon }) })
10810
10818
  ]
10811
10819
  }
10812
10820
  );
@@ -12492,12 +12500,12 @@ function TimePicker({
12492
12500
  className
12493
12501
  ),
12494
12502
  children: [
12495
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-2.5", children: [
12503
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2.5", children: [
12496
12504
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
12497
12505
  "div",
12498
12506
  {
12499
12507
  className: cn(
12500
- "flex items-center justify-center transition-colors duration-300",
12508
+ "flex shrink-0 items-center justify-center transition-colors duration-300",
12501
12509
  effectiveError ? "text-destructive" : success ? "text-success" : open ? "text-primary" : "text-muted-foreground group-hover:text-primary"
12502
12510
  ),
12503
12511
  children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react18.Clock, { className: cn(sz.icon, "transition-transform duration-300", open && "rotate-12") })
@@ -12507,7 +12515,7 @@ function TimePicker({
12507
12515
  "span",
12508
12516
  {
12509
12517
  className: cn(
12510
- "truncate font-medium transition-colors duration-200",
12518
+ "min-w-0 truncate font-medium transition-colors duration-200",
12511
12519
  !hasCommittedValue && "text-muted-foreground",
12512
12520
  hasCommittedValue ? "text-foreground" : ""
12513
12521
  ),
@@ -12515,7 +12523,7 @@ function TimePicker({
12515
12523
  }
12516
12524
  )
12517
12525
  ] }),
12518
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: cn("ml-2 transition-all duration-300 text-muted-foreground group-hover:text-foreground", open && "rotate-180 text-primary"), children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("svg", { className: sz.icon, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
12526
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: cn("ml-2 shrink-0 transition-all duration-300 text-muted-foreground group-hover:text-foreground", open && "rotate-180 text-primary"), children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("svg", { className: sz.icon, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
12519
12527
  ]
12520
12528
  }
12521
12529
  );
@@ -13145,8 +13153,8 @@ var DateTimePicker = ({
13145
13153
  effectiveError && "border-destructive/60 bg-destructive/5"
13146
13154
  ),
13147
13155
  children: [
13148
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "truncate", children: displayValue || placeholder || "Select date & time" }),
13149
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
13156
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate text-left", children: displayValue || placeholder || "Select date & time" }),
13157
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex shrink-0 items-center gap-2 text-muted-foreground", children: [
13150
13158
  value && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
13151
13159
  "span",
13152
13160
  {
@@ -25510,6 +25518,109 @@ var letter_spacing_default = LetterSpacing;
25510
25518
  var import_extension_table = require("@tiptap/extension-table");
25511
25519
  var import_state4 = require("@tiptap/pm/state");
25512
25520
 
25521
+ // src/components/UEditor/table-dom-utils.ts
25522
+ var MIN_TABLE_ROW_HEIGHT = 36;
25523
+ var COLUMN_RESIZE_LINE_THICKNESS = 2;
25524
+ var ROW_RESIZE_LINE_THICKNESS = 2;
25525
+ var UEDITOR_TABLE_LAYOUT_CHANGE_EVENT = "ueditor-table-layout-change";
25526
+ var TABLE_RESIZE_HIT_ZONE = 10;
25527
+ function findTableRowNodeInfo(view, rowElement) {
25528
+ const firstCell = rowElement.querySelector("th,td");
25529
+ if (!firstCell) return null;
25530
+ const cellPos = view.posAtDOM(firstCell, 0);
25531
+ const $pos = view.state.doc.resolve(cellPos);
25532
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
25533
+ const node = $pos.node(depth);
25534
+ if (node.type.name === "tableRow") {
25535
+ return {
25536
+ pos: $pos.before(depth),
25537
+ node
25538
+ };
25539
+ }
25540
+ }
25541
+ return null;
25542
+ }
25543
+ function resolveEventElement(target) {
25544
+ if (target instanceof Element) return target;
25545
+ if (target instanceof Node) return target.parentElement;
25546
+ return null;
25547
+ }
25548
+ function getSelectionTableCell(view) {
25549
+ const browserSelection = window.getSelection();
25550
+ const anchorElement = resolveEventElement(browserSelection?.anchorNode ?? null);
25551
+ const anchorCell = anchorElement?.closest?.("th,td");
25552
+ if (anchorCell instanceof HTMLElement) {
25553
+ return anchorCell;
25554
+ }
25555
+ const { from } = view.state.selection;
25556
+ const domAtPos = view.domAtPos(from);
25557
+ const element = resolveEventElement(domAtPos.node);
25558
+ const cell = element?.closest?.("th,td");
25559
+ return cell instanceof HTMLElement ? cell : null;
25560
+ }
25561
+ function isRowResizeHotspot(cell, clientX, clientY) {
25562
+ const rect = cell.getBoundingClientRect();
25563
+ const nearBottom = rect.bottom - clientY <= TABLE_RESIZE_HIT_ZONE;
25564
+ const nearRight = rect.right - clientX <= TABLE_RESIZE_HIT_ZONE;
25565
+ return nearBottom && !nearRight;
25566
+ }
25567
+ function isColumnResizeHotspot(cell, clientX, clientY) {
25568
+ const rect = cell.getBoundingClientRect();
25569
+ const nearRight = rect.right - clientX <= TABLE_RESIZE_HIT_ZONE;
25570
+ const nearBottom = rect.bottom - clientY <= TABLE_RESIZE_HIT_ZONE;
25571
+ return nearRight && !nearBottom;
25572
+ }
25573
+ function getRelativeBoundaryMetrics(surface, table, row, cell) {
25574
+ const surfaceRect = surface.getBoundingClientRect();
25575
+ const tableRect = table.getBoundingClientRect();
25576
+ const rowRect = row.getBoundingClientRect();
25577
+ const cellRect = cell.getBoundingClientRect();
25578
+ return {
25579
+ left: tableRect.left - surfaceRect.left + surface.scrollLeft,
25580
+ top: tableRect.top - surfaceRect.top + surface.scrollTop,
25581
+ width: tableRect.width,
25582
+ height: tableRect.height,
25583
+ rowBottom: rowRect.bottom - surfaceRect.top + surface.scrollTop,
25584
+ columnRight: cellRect.right - surfaceRect.left + surface.scrollLeft
25585
+ };
25586
+ }
25587
+ function getRelativeCellMetrics(surface, cell) {
25588
+ const surfaceRect = surface.getBoundingClientRect();
25589
+ const cellRect = cell.getBoundingClientRect();
25590
+ return {
25591
+ left: cellRect.left - surfaceRect.left + surface.scrollLeft,
25592
+ top: cellRect.top - surfaceRect.top + surface.scrollTop,
25593
+ width: cellRect.width,
25594
+ height: cellRect.height
25595
+ };
25596
+ }
25597
+ function getRelativeSelectedCellsMetrics(surface) {
25598
+ const selectedCells = Array.from(
25599
+ surface.querySelectorAll("td.selectedCell, th.selectedCell")
25600
+ );
25601
+ if (selectedCells.length === 0) {
25602
+ return null;
25603
+ }
25604
+ const surfaceRect = surface.getBoundingClientRect();
25605
+ let left = Number.POSITIVE_INFINITY;
25606
+ let top = Number.POSITIVE_INFINITY;
25607
+ let right = Number.NEGATIVE_INFINITY;
25608
+ let bottom = Number.NEGATIVE_INFINITY;
25609
+ selectedCells.forEach((cell) => {
25610
+ const rect = cell.getBoundingClientRect();
25611
+ left = Math.min(left, rect.left);
25612
+ top = Math.min(top, rect.top);
25613
+ right = Math.max(right, rect.right);
25614
+ bottom = Math.max(bottom, rect.bottom);
25615
+ });
25616
+ return {
25617
+ left: left - surfaceRect.left + surface.scrollLeft,
25618
+ top: top - surfaceRect.top + surface.scrollTop,
25619
+ width: right - left,
25620
+ height: bottom - top
25621
+ };
25622
+ }
25623
+
25513
25624
  // src/components/UEditor/table-align-utils.ts
25514
25625
  function findTableNodeInfoAtResolvedPos($pos) {
25515
25626
  for (let depth = $pos.depth; depth > 0; depth -= 1) {
@@ -25537,11 +25648,13 @@ function applyTableAlignment(editor, tableAlign, anchorPos) {
25537
25648
  editor.view.dispatch(
25538
25649
  editor.state.tr.setNodeMarkup(tableInfo.pos, tableInfo.node.type, {
25539
25650
  ...tableInfo.node.attrs,
25540
- tableAlign
25651
+ textAlign: tableAlign
25541
25652
  })
25542
25653
  );
25654
+ const domAtTable = editor.view.domAtPos(Math.min(tableInfo.pos + 1, editor.state.doc.content.size)).node;
25655
+ const domAtTableElement = resolveEventElement(domAtTable);
25543
25656
  const tableDom = editor.view.nodeDOM(tableInfo.pos);
25544
- const tableElement = tableDom instanceof HTMLTableElement ? tableDom : tableDom instanceof HTMLElement ? tableDom.querySelector("table") : null;
25657
+ const tableElement = domAtTableElement?.closest?.("table") ?? (tableDom instanceof HTMLTableElement ? tableDom : tableDom instanceof HTMLElement ? tableDom.querySelector("table") : null) ?? (editor.view.dom.querySelectorAll("table").length === 1 ? editor.view.dom.querySelector("table") : null);
25545
25658
  if (tableElement instanceof HTMLTableElement) {
25546
25659
  if (tableAlign) {
25547
25660
  tableElement.setAttribute("data-table-align", tableAlign);
@@ -25590,25 +25703,30 @@ function renderTableAlignStyle(tableAlign) {
25590
25703
  }
25591
25704
  }
25592
25705
  var UEditorTable = import_extension_table.Table.extend({
25593
- addAttributes() {
25594
- return {
25595
- ...this.parent?.(),
25596
- tableAlign: {
25597
- default: null,
25598
- parseHTML: (element) => {
25599
- if (!(element instanceof HTMLElement)) return null;
25600
- return parseTableAlign(element);
25601
- },
25602
- renderHTML: (attributes) => {
25603
- const tableAlign = normalizeTableAlign(attributes.tableAlign);
25604
- if (!tableAlign) return {};
25605
- return {
25606
- "data-table-align": tableAlign,
25607
- style: renderTableAlignStyle(tableAlign)
25608
- };
25706
+ addGlobalAttributes() {
25707
+ return [
25708
+ ...this.parent?.() ?? [],
25709
+ {
25710
+ types: ["table"],
25711
+ attributes: {
25712
+ textAlign: {
25713
+ default: null,
25714
+ parseHTML: (element) => {
25715
+ if (!(element instanceof HTMLElement)) return null;
25716
+ return parseTableAlign(element);
25717
+ },
25718
+ renderHTML: (attributes) => {
25719
+ const tableAlign = normalizeTableAlign(attributes.textAlign);
25720
+ if (!tableAlign) return {};
25721
+ return {
25722
+ "data-table-align": tableAlign,
25723
+ style: renderTableAlignStyle(tableAlign)
25724
+ };
25725
+ }
25726
+ }
25609
25727
  }
25610
25728
  }
25611
- };
25729
+ ];
25612
25730
  },
25613
25731
  addCommands() {
25614
25732
  return {
@@ -25619,7 +25737,7 @@ var UEditorTable = import_extension_table.Table.extend({
25619
25737
  dispatch?.(
25620
25738
  state.tr.setNodeMarkup(tableInfo.pos, tableInfo.node.type, {
25621
25739
  ...tableInfo.node.attrs,
25622
- tableAlign
25740
+ textAlign: tableAlign
25623
25741
  })
25624
25742
  );
25625
25743
  return true;
@@ -25630,7 +25748,7 @@ var UEditorTable = import_extension_table.Table.extend({
25630
25748
  dispatch?.(
25631
25749
  state.tr.setNodeMarkup(tableInfo.pos, tableInfo.node.type, {
25632
25750
  ...tableInfo.node.attrs,
25633
- tableAlign: null
25751
+ textAlign: null
25634
25752
  })
25635
25753
  );
25636
25754
  return true;
@@ -25639,6 +25757,7 @@ var UEditorTable = import_extension_table.Table.extend({
25639
25757
  },
25640
25758
  addProseMirrorPlugins() {
25641
25759
  return [
25760
+ ...this.parent?.() ?? [],
25642
25761
  new import_state4.Plugin({
25643
25762
  appendTransaction(_transactions, _oldState, newState) {
25644
25763
  const { doc, schema } = newState;
@@ -26337,6 +26456,24 @@ function getDefaultLetterSpacings() {
26337
26456
 
26338
26457
  // src/components/UEditor/toolbar.tsx
26339
26458
  var import_jsx_runtime81 = require("react/jsx-runtime");
26459
+ function getTableAnchorPos(editor) {
26460
+ const tableInfo = findTableNodeInfoFromState(editor.state);
26461
+ if (tableInfo) return editor.state.selection.from;
26462
+ const selectionAnchor = resolveEventElement(window.getSelection()?.anchorNode ?? null);
26463
+ const selectionCell2 = selectionAnchor?.closest?.("th,td");
26464
+ if (selectionCell2 instanceof HTMLTableCellElement && editor.view.dom.contains(selectionCell2)) {
26465
+ return editor.view.posAtDOM(selectionCell2, 0) + 1;
26466
+ }
26467
+ const activeElement = document.activeElement instanceof Element ? document.activeElement : null;
26468
+ const activeCell = activeElement?.closest?.("th,td");
26469
+ if (activeCell instanceof HTMLTableCellElement && editor.view.dom.contains(activeCell)) {
26470
+ return editor.view.posAtDOM(activeCell, 0) + 1;
26471
+ }
26472
+ const tables = editor.view.dom.querySelectorAll("table");
26473
+ if (tables.length !== 1) return null;
26474
+ const firstCell = tables[0]?.querySelector("th,td");
26475
+ return firstCell instanceof HTMLTableCellElement ? editor.view.posAtDOM(firstCell, 0) + 1 : null;
26476
+ }
26340
26477
  function fileToDataUrl2(file) {
26341
26478
  return new Promise((resolve, reject) => {
26342
26479
  const reader = new FileReader();
@@ -26443,12 +26580,15 @@ var EditorToolbar = ({
26443
26580
  const [imageUploadError, setImageUploadError] = (0, import_react49.useState)(null);
26444
26581
  const isImageSelected = editor.isActive("image");
26445
26582
  const imageAttrs = editor.getAttributes("image");
26446
- const tableAttrs = editor.getAttributes("table");
26583
+ const tableAnchorPos = getTableAnchorPos(editor);
26584
+ const tableInfo = tableAnchorPos == null ? null : findTableNodeInfoFromState(editor.state, tableAnchorPos);
26585
+ const tableAttrs = tableInfo?.node.attrs ?? editor.getAttributes("table");
26447
26586
  const textStyleAttrs = editor.getAttributes("textStyle");
26448
26587
  const imageLayout = imageAttrs.imageLayout === "left" || imageAttrs.imageLayout === "right" ? imageAttrs.imageLayout : "block";
26449
26588
  const imageWidthPreset = imageAttrs.imageWidthPreset === "sm" || imageAttrs.imageWidthPreset === "md" || imageAttrs.imageWidthPreset === "lg" ? imageAttrs.imageWidthPreset : null;
26450
- const currentTableAlign = tableAttrs.tableAlign === "center" || tableAttrs.tableAlign === "right" ? tableAttrs.tableAlign : "left";
26451
- const isTableSelected = editor.isActive("table");
26589
+ const tableAlignAttr = tableAttrs.tableAlign ?? tableAttrs.textAlign;
26590
+ const currentTableAlign = tableAlignAttr === "center" || tableAlignAttr === "right" ? tableAlignAttr : "left";
26591
+ const isTableSelected = tableInfo !== null;
26452
26592
  const hasTableContext = isTableSelected || tableCommandAnchorPosRef.current !== null;
26453
26593
  const currentFontFamily = normalizeStyleValue(textStyleAttrs.fontFamily);
26454
26594
  const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
@@ -26466,6 +26606,7 @@ var EditorToolbar = ({
26466
26606
  const currentLineHeightLabel = availableLineHeights.find((option) => normalizeStyleValue(option.value) === currentLineHeight)?.label ?? t("toolbar.lineHeightDefault");
26467
26607
  const currentLetterSpacingLabel = availableLetterSpacings.find((option) => normalizeStyleValue(option.value) === currentLetterSpacing)?.label ?? t("toolbar.letterSpacingDefault");
26468
26608
  const displayedFontFamilyLabel = currentFontFamily ? currentFontFamilyLabel : availableFontFamilies[0]?.label ?? t("toolbar.fontDefault");
26609
+ const tableCommandAnchorPos = tableCommandAnchorPosRef.current ?? tableAnchorPos ?? void 0;
26469
26610
  const insertImageFiles = async (files) => {
26470
26611
  if (files.length === 0) return;
26471
26612
  setIsUploadingImage(true);
@@ -27068,7 +27209,7 @@ var EditorToolbar = ({
27068
27209
  isOpen: isTableMenuOpen,
27069
27210
  onOpenChange: (open) => {
27070
27211
  setIsTableMenuOpen(open);
27071
- tableCommandAnchorPosRef.current = open && editor.isActive("table") ? editor.state.selection.$from.pos : null;
27212
+ tableCommandAnchorPosRef.current = open ? getTableAnchorPos(editor) : null;
27072
27213
  },
27073
27214
  trigger: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(ToolbarButton, { onClick: () => {
27074
27215
  }, title: t("toolbar.table"), children: [
@@ -27094,7 +27235,7 @@ var EditorToolbar = ({
27094
27235
  {
27095
27236
  icon: import_lucide_react44.AlignLeft,
27096
27237
  label: t("tableMenu.alignLeft"),
27097
- onClick: () => applyTableAlignment(editor, "left", tableCommandAnchorPosRef.current ?? void 0),
27238
+ onClick: () => applyTableAlignment(editor, "left", tableCommandAnchorPos),
27098
27239
  active: hasTableContext && currentTableAlign === "left",
27099
27240
  disabled: !hasTableContext
27100
27241
  }
@@ -27104,7 +27245,7 @@ var EditorToolbar = ({
27104
27245
  {
27105
27246
  icon: import_lucide_react44.AlignCenter,
27106
27247
  label: t("tableMenu.alignCenter"),
27107
- onClick: () => applyTableAlignment(editor, "center", tableCommandAnchorPosRef.current ?? void 0),
27248
+ onClick: () => applyTableAlignment(editor, "center", tableCommandAnchorPos),
27108
27249
  active: hasTableContext && currentTableAlign === "center",
27109
27250
  disabled: !hasTableContext
27110
27251
  }
@@ -27114,7 +27255,7 @@ var EditorToolbar = ({
27114
27255
  {
27115
27256
  icon: import_lucide_react44.AlignRight,
27116
27257
  label: t("tableMenu.alignRight"),
27117
- onClick: () => applyTableAlignment(editor, "right", tableCommandAnchorPosRef.current ?? void 0),
27258
+ onClick: () => applyTableAlignment(editor, "right", tableCommandAnchorPos),
27118
27259
  active: hasTableContext && currentTableAlign === "right",
27119
27260
  disabled: !hasTableContext
27120
27261
  }
@@ -27215,9 +27356,234 @@ var EditorToolbar = ({
27215
27356
  // src/components/UEditor/menus.tsx
27216
27357
  var import_react51 = require("react");
27217
27358
  var import_react52 = require("@tiptap/react");
27218
- var import_tables = require("@tiptap/pm/tables");
27359
+ var import_tables2 = require("@tiptap/pm/tables");
27219
27360
  var import_react_dom8 = require("react-dom");
27220
27361
  var import_lucide_react45 = require("lucide-react");
27362
+
27363
+ // src/components/UEditor/table-cell-commands.ts
27364
+ var import_state6 = require("@tiptap/pm/state");
27365
+ var import_tables = require("@tiptap/pm/tables");
27366
+ function getCellSelectionPositions(selection) {
27367
+ const value = selection;
27368
+ const anchor = value.$anchorCell?.pos;
27369
+ const head = value.$headCell?.pos;
27370
+ return typeof anchor === "number" && typeof head === "number" ? { anchor, head } : null;
27371
+ }
27372
+ function findTableInfoFromCellPos(editor, cellPos) {
27373
+ const $pos = editor.state.doc.resolve(cellPos);
27374
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
27375
+ const node = $pos.node(depth);
27376
+ if (node.type.name === "table") {
27377
+ return {
27378
+ table: node,
27379
+ tablePos: $pos.before(depth),
27380
+ tableStart: $pos.start(depth)
27381
+ };
27382
+ }
27383
+ }
27384
+ return null;
27385
+ }
27386
+ function getFocusableCellPos(editor, cellPos) {
27387
+ const cellNode = editor.state.doc.nodeAt(cellPos);
27388
+ if (!cellNode) return cellPos + 1;
27389
+ let offset = cellPos + 1;
27390
+ let node = cellNode.firstChild ?? null;
27391
+ while (node && !node.isTextblock) {
27392
+ offset += 1;
27393
+ node = node.firstChild ?? null;
27394
+ }
27395
+ return node?.isTextblock ? offset + 1 : cellPos + 1;
27396
+ }
27397
+ function focusCell(editor, cellPos) {
27398
+ const selection = import_state6.TextSelection.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
27399
+ editor.view.dispatch(editor.state.tr.setSelection(selection));
27400
+ editor.view.focus();
27401
+ }
27402
+ function collectChildren(node) {
27403
+ const children = [];
27404
+ node.forEach((child) => children.push(child));
27405
+ return children;
27406
+ }
27407
+ function createEmptyCellNode(cellNode) {
27408
+ return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
27409
+ }
27410
+ function getSelectedTableRect(editor) {
27411
+ const cellSelection = getCellSelectionPositions(editor.state.selection);
27412
+ if (cellSelection) {
27413
+ const tableInfo = findTableInfoFromCellPos(editor, cellSelection.anchor);
27414
+ if (tableInfo) {
27415
+ const map = import_tables.TableMap.get(tableInfo.table);
27416
+ const rect = map.rectBetween(
27417
+ cellSelection.anchor - tableInfo.tableStart,
27418
+ cellSelection.head - tableInfo.tableStart
27419
+ );
27420
+ return {
27421
+ ...rect,
27422
+ map,
27423
+ table: tableInfo.table,
27424
+ tableStart: tableInfo.tableStart
27425
+ };
27426
+ }
27427
+ }
27428
+ return (0, import_tables.selectedRect)(editor.state);
27429
+ }
27430
+ function parsePixelWidth(value) {
27431
+ if (!value) return null;
27432
+ const parsed = Number.parseFloat(value);
27433
+ return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : null;
27434
+ }
27435
+ function getDomColumnWidths(editor, rect) {
27436
+ const tableDom = editor.view.nodeDOM(rect.tableStart - 1);
27437
+ if (!(tableDom instanceof HTMLTableElement)) return null;
27438
+ const cols = Array.from(tableDom.querySelectorAll("colgroup > col"));
27439
+ if (cols.length === 0) return null;
27440
+ const widths = [];
27441
+ for (let col = rect.left; col < rect.right; col += 1) {
27442
+ const colElement = cols[col];
27443
+ if (!colElement) return null;
27444
+ const width = parsePixelWidth(colElement.style.width) ?? parsePixelWidth(colElement.getAttribute("width")) ?? Math.round(colElement.getBoundingClientRect().width);
27445
+ if (!Number.isFinite(width) || width <= 0) return null;
27446
+ widths.push(width);
27447
+ }
27448
+ return widths.length > 0 ? widths : null;
27449
+ }
27450
+ function getNodeColumnWidths(rect) {
27451
+ const widths = [];
27452
+ for (let col = rect.left; col < rect.right; col += 1) {
27453
+ let width = null;
27454
+ const seen = /* @__PURE__ */ new Set();
27455
+ for (let row = 0; row < rect.map.height && width == null; row += 1) {
27456
+ const cellPos = rect.map.map[row * rect.map.width + col];
27457
+ if (seen.has(cellPos)) continue;
27458
+ seen.add(cellPos);
27459
+ const cell = rect.table.nodeAt(cellPos);
27460
+ const colwidth = cell?.attrs.colwidth;
27461
+ if (!Array.isArray(colwidth)) continue;
27462
+ const cellLeft = rect.map.colCount(cellPos);
27463
+ const widthIndex = col - cellLeft;
27464
+ const candidate = colwidth[widthIndex];
27465
+ if (typeof candidate === "number" && candidate > 0) {
27466
+ width = candidate;
27467
+ }
27468
+ }
27469
+ if (width == null) return null;
27470
+ widths.push(width);
27471
+ }
27472
+ return widths.length > 0 ? widths : null;
27473
+ }
27474
+ function getSelectedColumnWidths(editor, rect) {
27475
+ return getDomColumnWidths(editor, rect) ?? getNodeColumnWidths(rect);
27476
+ }
27477
+ function dispatchTableLayoutChange(editor) {
27478
+ editor.view.dom.dispatchEvent(new CustomEvent(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, { bubbles: true }));
27479
+ }
27480
+ function mergeTableCellsPreservingColumnWidths(editor) {
27481
+ const rect = getSelectedTableRect(editor);
27482
+ const widths = getSelectedColumnWidths(editor, rect);
27483
+ const merged = editor.chain().focus().mergeCells().run();
27484
+ if (!merged) return merged;
27485
+ if (!widths) {
27486
+ dispatchTableLayoutChange(editor);
27487
+ return merged;
27488
+ }
27489
+ const nextRect = getSelectedTableRect(editor);
27490
+ const cellPos = nextRect.map.map[nextRect.top * nextRect.map.width + nextRect.left];
27491
+ const absolutePos = nextRect.tableStart + cellPos;
27492
+ const node = editor.state.doc.nodeAt(absolutePos);
27493
+ if (!node) return merged;
27494
+ editor.view.dispatch(
27495
+ editor.state.tr.setNodeMarkup(absolutePos, node.type, {
27496
+ ...node.attrs,
27497
+ colwidth: widths
27498
+ })
27499
+ );
27500
+ dispatchTableLayoutChange(editor);
27501
+ return true;
27502
+ }
27503
+ function runTableCommandAtCellPos(editor, cellPos, command) {
27504
+ if (cellPos == null) return false;
27505
+ focusCell(editor, cellPos);
27506
+ return command(editor.chain().focus(null, { scrollIntoView: false })).run();
27507
+ }
27508
+ function getTableCornerCellPos(editor, activePos) {
27509
+ const tableInfo = findTableInfoFromCellPos(editor, activePos);
27510
+ if (!tableInfo) return null;
27511
+ const map = import_tables.TableMap.get(tableInfo.table);
27512
+ return tableInfo.tableStart + map.positionAt(map.height - 1, map.width - 1, tableInfo.table);
27513
+ }
27514
+ function replaceTableAtCellPos(editor, cellPos, updateTable) {
27515
+ if (cellPos == null) return false;
27516
+ const tableInfo = findTableInfoFromCellPos(editor, cellPos);
27517
+ if (!tableInfo) return false;
27518
+ const nextTable = updateTable(tableInfo.table);
27519
+ if (!nextTable) return false;
27520
+ editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.tablePos, tableInfo.tablePos + tableInfo.table.nodeSize, nextTable));
27521
+ dispatchTableLayoutChange(editor);
27522
+ return true;
27523
+ }
27524
+ function duplicateTableRowAt(editor, rowIndex, cellPos) {
27525
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27526
+ const rows = collectChildren(tableNode);
27527
+ const rowNode = rows[rowIndex];
27528
+ if (!rowNode) return null;
27529
+ rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
27530
+ return tableNode.type.create(tableNode.attrs, rows);
27531
+ });
27532
+ }
27533
+ function clearTableRowAt(editor, rowIndex, cellPos) {
27534
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27535
+ const rows = collectChildren(tableNode);
27536
+ const rowNode = rows[rowIndex];
27537
+ if (!rowNode) return null;
27538
+ const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
27539
+ rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
27540
+ return tableNode.type.create(tableNode.attrs, rows);
27541
+ });
27542
+ }
27543
+ function duplicateTableColumnAt(editor, columnIndex, cellPos) {
27544
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27545
+ const rows = collectChildren(tableNode).map((rowNode) => {
27546
+ const cells = collectChildren(rowNode);
27547
+ const cellNode = cells[columnIndex];
27548
+ if (!cellNode) return rowNode;
27549
+ cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
27550
+ return rowNode.type.create(rowNode.attrs, cells);
27551
+ });
27552
+ return tableNode.type.create(tableNode.attrs, rows);
27553
+ });
27554
+ }
27555
+ function clearTableColumnAt(editor, columnIndex, cellPos) {
27556
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27557
+ const rows = collectChildren(tableNode).map((rowNode) => {
27558
+ const cells = collectChildren(rowNode);
27559
+ const cellNode = cells[columnIndex];
27560
+ if (!cellNode) return rowNode;
27561
+ cells[columnIndex] = createEmptyCellNode(cellNode);
27562
+ return rowNode.type.create(rowNode.attrs, cells);
27563
+ });
27564
+ return tableNode.type.create(tableNode.attrs, rows);
27565
+ });
27566
+ }
27567
+ function expandTableFromCell(editor, activeCellPos, rows, columns) {
27568
+ let cornerCellPos = getTableCornerCellPos(editor, activeCellPos);
27569
+ if (cornerCellPos == null) return false;
27570
+ for (let index = 0; index < rows; index += 1) {
27571
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addRowAfter());
27572
+ if (!ok) return false;
27573
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
27574
+ if (cornerCellPos == null) return false;
27575
+ }
27576
+ for (let index = 0; index < columns; index += 1) {
27577
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addColumnAfter());
27578
+ if (!ok) return false;
27579
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
27580
+ if (cornerCellPos == null) return false;
27581
+ }
27582
+ dispatchTableLayoutChange(editor);
27583
+ return true;
27584
+ }
27585
+
27586
+ // src/components/UEditor/menus.tsx
27221
27587
  var import_jsx_runtime82 = require("react/jsx-runtime");
27222
27588
  var FloatingSlashCommandMenu = ({ editor, onClose }) => {
27223
27589
  const t = useSmartTranslations("UEditor");
@@ -27274,7 +27640,7 @@ var FloatingMenuContent = ({ editor }) => {
27274
27640
  function applyTableCellBackground(editor, color) {
27275
27641
  const value = color || null;
27276
27642
  const { state, view } = editor;
27277
- const applied = (0, import_tables.setCellAttr)("backgroundColor", value)(state, view.dispatch.bind(view));
27643
+ const applied = (0, import_tables2.setCellAttr)("backgroundColor", value)(state, view.dispatch.bind(view));
27278
27644
  if (applied) {
27279
27645
  view.focus();
27280
27646
  return;
@@ -27306,7 +27672,9 @@ var BubbleMenuContent = ({
27306
27672
  const currentTextColor = normalizeStyleValue(textStyleAttrs.color) || "inherit";
27307
27673
  const currentHighlightColor = normalizeStyleValue(editor.getAttributes("highlight").color) || "";
27308
27674
  const currentCellBgColor = normalizeStyleValue(editor.getAttributes("tableCell").backgroundColor || editor.getAttributes("tableHeader").backgroundColor) || "";
27309
- const isInTable2 = (0, import_tables.isInTable)(editor.state);
27675
+ const isInTable2 = (0, import_tables2.isInTable)(editor.state);
27676
+ const canMergeCells = isInTable2 && editor.can().mergeCells();
27677
+ const canSplitCell = isInTable2 && editor.can().splitCell();
27310
27678
  const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
27311
27679
  const currentLineHeight = normalizeStyleValue(textStyleAttrs.lineHeight);
27312
27680
  const quickFontSizes = (0, import_react51.useMemo)(
@@ -27601,15 +27969,33 @@ var BubbleMenuContent = ({
27601
27969
  ),
27602
27970
  /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(ToolbarButton, { onClick: () => setActiveColorPalette("text"), title: t("colors.textColor"), children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(TextColorIcon, { color: currentTextColor }) }),
27603
27971
  /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(ToolbarButton, { onClick: () => setActiveColorPalette("highlight"), active: editor.isActive("highlight"), title: t("colors.highlight"), children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(HighlightColorIcon, { color: currentHighlightColor }) }),
27604
- isInTable2 && /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
27605
- ToolbarButton,
27606
- {
27607
- onClick: () => setActiveColorPalette("cell-bg"),
27608
- active: Boolean(currentCellBgColor),
27609
- title: t("tableMenu.cellBackground") || "Cell background",
27610
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(CellBgColorIcon, { color: currentCellBgColor })
27611
- }
27612
- ),
27972
+ isInTable2 && /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(import_jsx_runtime82.Fragment, { children: [
27973
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
27974
+ ToolbarButton,
27975
+ {
27976
+ onClick: () => setActiveColorPalette("cell-bg"),
27977
+ active: Boolean(currentCellBgColor),
27978
+ title: t("tableMenu.cellBackground") || "Cell background",
27979
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(CellBgColorIcon, { color: currentCellBgColor })
27980
+ }
27981
+ ),
27982
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
27983
+ ToolbarButton,
27984
+ {
27985
+ onClick: () => {
27986
+ if (canSplitCell) {
27987
+ editor.chain().focus().splitCell().run();
27988
+ return;
27989
+ }
27990
+ mergeTableCellsPreservingColumnWidths(editor);
27991
+ },
27992
+ active: canSplitCell,
27993
+ disabled: !canMergeCells && !canSplitCell,
27994
+ title: canSplitCell ? t("tableMenu.splitCell") || "Split cell" : t("tableMenu.mergeCells") || "Merge cells",
27995
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react45.TableCellsMerge, { className: "w-4 h-4" })
27996
+ }
27997
+ )
27998
+ ] }),
27613
27999
  /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
27614
28000
  ToolbarButton,
27615
28001
  {
@@ -28101,7 +28487,7 @@ function findDiffEnd(a, b, posA, posB) {
28101
28487
  posB -= size;
28102
28488
  }
28103
28489
  }
28104
- var Fragment28 = class _Fragment {
28490
+ var Fragment29 = class _Fragment {
28105
28491
  /**
28106
28492
  @internal
28107
28493
  */
@@ -28393,7 +28779,7 @@ var Fragment28 = class _Fragment {
28393
28779
  throw new RangeError("Can not convert " + nodes + " to a Fragment" + (nodes.nodesBetween ? " (looks like multiple versions of prosemirror-model were loaded)" : ""));
28394
28780
  }
28395
28781
  };
28396
- Fragment28.empty = new Fragment28([], 0);
28782
+ Fragment29.empty = new Fragment29([], 0);
28397
28783
  var found = { index: 0, offset: 0 };
28398
28784
  function retIndex(index, offset) {
28399
28785
  found.index = index;
@@ -28618,7 +29004,7 @@ var Slice = class _Slice {
28618
29004
  let openStart = json.openStart || 0, openEnd = json.openEnd || 0;
28619
29005
  if (typeof openStart != "number" || typeof openEnd != "number")
28620
29006
  throw new RangeError("Invalid input for Slice.fromJSON");
28621
- return new _Slice(Fragment28.fromJSON(schema, json.content), openStart, openEnd);
29007
+ return new _Slice(Fragment29.fromJSON(schema, json.content), openStart, openEnd);
28622
29008
  }
28623
29009
  /**
28624
29010
  Create a slice from a fragment by taking the maximum possible
@@ -28633,7 +29019,7 @@ var Slice = class _Slice {
28633
29019
  return new _Slice(fragment, openStart, openEnd);
28634
29020
  }
28635
29021
  };
28636
- Slice.empty = new Slice(Fragment28.empty, 0, 0);
29022
+ Slice.empty = new Slice(Fragment29.empty, 0, 0);
28637
29023
  function removeRange(content, from, to) {
28638
29024
  let { index, offset } = content.findIndex(from), child = content.maybeChild(index);
28639
29025
  let { index: indexTo, offset: offsetTo } = content.findIndex(to);
@@ -28731,7 +29117,7 @@ function replaceThreeWay($from, $start, $end, $to, depth) {
28731
29117
  addNode(close(openEnd, replaceTwoWay($end, $to, depth + 1)), content);
28732
29118
  }
28733
29119
  addRange($to, null, depth, content);
28734
- return new Fragment28(content);
29120
+ return new Fragment29(content);
28735
29121
  }
28736
29122
  function replaceTwoWay($from, $to, depth) {
28737
29123
  let content = [];
@@ -28741,13 +29127,13 @@ function replaceTwoWay($from, $to, depth) {
28741
29127
  addNode(close(type, replaceTwoWay($from, $to, depth + 1)), content);
28742
29128
  }
28743
29129
  addRange($to, null, depth, content);
28744
- return new Fragment28(content);
29130
+ return new Fragment29(content);
28745
29131
  }
28746
29132
  function prepareSliceForReplace(slice, $along) {
28747
29133
  let extra = $along.depth - slice.openStart, parent = $along.node(extra);
28748
29134
  let node = parent.copy(slice.content);
28749
29135
  for (let i = extra - 1; i >= 0; i--)
28750
- node = $along.node(i).copy(Fragment28.from(node));
29136
+ node = $along.node(i).copy(Fragment29.from(node));
28751
29137
  return {
28752
29138
  start: node.resolveNoCache(slice.openStart + extra),
28753
29139
  end: node.resolveNoCache(node.content.size - slice.openEnd - extra)
@@ -29086,7 +29472,7 @@ var Node2 = class _Node {
29086
29472
  this.type = type;
29087
29473
  this.attrs = attrs;
29088
29474
  this.marks = marks;
29089
- this.content = content || Fragment28.empty;
29475
+ this.content = content || Fragment29.empty;
29090
29476
  }
29091
29477
  /**
29092
29478
  The array of this node's child nodes.
@@ -29391,7 +29777,7 @@ var Node2 = class _Node {
29391
29777
  can optionally pass `start` and `end` indices into the
29392
29778
  replacement fragment.
29393
29779
  */
29394
- canReplace(from, to, replacement = Fragment28.empty, start = 0, end = replacement.childCount) {
29780
+ canReplace(from, to, replacement = Fragment29.empty, start = 0, end = replacement.childCount) {
29395
29781
  let one = this.contentMatchAt(from).matchFragment(replacement, start, end);
29396
29782
  let two = one && one.matchFragment(this.content, to);
29397
29783
  if (!two || !two.validEnd)
@@ -29473,7 +29859,7 @@ var Node2 = class _Node {
29473
29859
  throw new RangeError("Invalid text node in JSON");
29474
29860
  return schema.text(json.text, marks);
29475
29861
  }
29476
- let content = Fragment28.fromJSON(schema, json.content);
29862
+ let content = Fragment29.fromJSON(schema, json.content);
29477
29863
  let node = schema.nodeType(json.type).create(json.attrs, content, marks);
29478
29864
  node.type.checkAttrs(node.attrs);
29479
29865
  return node;
@@ -29569,7 +29955,7 @@ var ContentMatch = class _ContentMatch {
29569
29955
  function search(match, types) {
29570
29956
  let finished = match.matchFragment(after, startIndex);
29571
29957
  if (finished && (!toEnd || finished.validEnd))
29572
- return Fragment28.from(types.map((tp) => tp.createAndFill()));
29958
+ return Fragment29.from(types.map((tp) => tp.createAndFill()));
29573
29959
  for (let i = 0; i < match.next.length; i++) {
29574
29960
  let { type, next } = match.next[i];
29575
29961
  if (!(type.isText || type.hasRequiredAttrs()) && seen.indexOf(next) == -1) {
@@ -30137,7 +30523,7 @@ function mapFragment(fragment, f, parent) {
30137
30523
  child = f(child, parent, i);
30138
30524
  mapped.push(child);
30139
30525
  }
30140
- return Fragment28.fromArray(mapped);
30526
+ return Fragment29.fromArray(mapped);
30141
30527
  }
30142
30528
  var AddMarkStep = class _AddMarkStep extends Step {
30143
30529
  /**
@@ -30254,7 +30640,7 @@ var AddNodeMarkStep = class _AddNodeMarkStep extends Step {
30254
30640
  if (!node)
30255
30641
  return StepResult.fail("No node at mark step's position");
30256
30642
  let updated = node.type.create(node.attrs, null, this.mark.addToSet(node.marks));
30257
- return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment28.from(updated), 0, node.isLeaf ? 0 : 1));
30643
+ return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment29.from(updated), 0, node.isLeaf ? 0 : 1));
30258
30644
  }
30259
30645
  invert(doc) {
30260
30646
  let node = doc.nodeAt(this.pos);
@@ -30300,7 +30686,7 @@ var RemoveNodeMarkStep = class _RemoveNodeMarkStep extends Step {
30300
30686
  if (!node)
30301
30687
  return StepResult.fail("No node at mark step's position");
30302
30688
  let updated = node.type.create(node.attrs, null, this.mark.removeFromSet(node.marks));
30303
- return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment28.from(updated), 0, node.isLeaf ? 0 : 1));
30689
+ return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment29.from(updated), 0, node.isLeaf ? 0 : 1));
30304
30690
  }
30305
30691
  invert(doc) {
30306
30692
  let node = doc.nodeAt(this.pos);
@@ -30501,7 +30887,7 @@ var AttrStep = class _AttrStep extends Step {
30501
30887
  attrs[name] = node.attrs[name];
30502
30888
  attrs[this.attr] = this.value;
30503
30889
  let updated = node.type.create(attrs, null, node.marks);
30504
- return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment28.from(updated), 0, node.isLeaf ? 0 : 1));
30890
+ return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment29.from(updated), 0, node.isLeaf ? 0 : 1));
30505
30891
  }
30506
30892
  getMap() {
30507
30893
  return StepMap.empty;
@@ -30678,7 +31064,7 @@ var Selection = class {
30678
31064
  found.
30679
31065
  */
30680
31066
  static findFrom($pos, dir, textOnly = false) {
30681
- let inner = $pos.parent.inlineContent ? new TextSelection2($pos) : findSelectionIn($pos.node(0), $pos.parent, $pos.pos, $pos.index(), dir, textOnly);
31067
+ let inner = $pos.parent.inlineContent ? new TextSelection3($pos) : findSelectionIn($pos.node(0), $pos.parent, $pos.pos, $pos.index(), dir, textOnly);
30682
31068
  if (inner)
30683
31069
  return inner;
30684
31070
  for (let depth = $pos.depth - 1; depth >= 0; depth--) {
@@ -30747,7 +31133,7 @@ var Selection = class {
30747
31133
  returns the bookmark for that.
30748
31134
  */
30749
31135
  getBookmark() {
30750
- return TextSelection2.between(this.$anchor, this.$head).getBookmark();
31136
+ return TextSelection3.between(this.$anchor, this.$head).getBookmark();
30751
31137
  }
30752
31138
  };
30753
31139
  Selection.prototype.visible = true;
@@ -30767,7 +31153,7 @@ function checkTextSelection($pos) {
30767
31153
  console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")");
30768
31154
  }
30769
31155
  }
30770
- var TextSelection2 = class _TextSelection extends Selection {
31156
+ var TextSelection3 = class _TextSelection extends Selection {
30771
31157
  /**
30772
31158
  Construct a text selection between the given points.
30773
31159
  */
@@ -30853,7 +31239,7 @@ var TextSelection2 = class _TextSelection extends Selection {
30853
31239
  return new _TextSelection($anchor, $head);
30854
31240
  }
30855
31241
  };
30856
- Selection.jsonID("text", TextSelection2);
31242
+ Selection.jsonID("text", TextSelection3);
30857
31243
  var TextBookmark = class _TextBookmark {
30858
31244
  constructor(anchor, head) {
30859
31245
  this.anchor = anchor;
@@ -30863,7 +31249,7 @@ var TextBookmark = class _TextBookmark {
30863
31249
  return new _TextBookmark(mapping.map(this.anchor), mapping.map(this.head));
30864
31250
  }
30865
31251
  resolve(doc) {
30866
- return TextSelection2.between(doc.resolve(this.anchor), doc.resolve(this.head));
31252
+ return TextSelection3.between(doc.resolve(this.anchor), doc.resolve(this.head));
30867
31253
  }
30868
31254
  };
30869
31255
  var NodeSelection2 = class _NodeSelection extends Selection {
@@ -30885,7 +31271,7 @@ var NodeSelection2 = class _NodeSelection extends Selection {
30885
31271
  return new _NodeSelection($pos);
30886
31272
  }
30887
31273
  content() {
30888
- return new Slice(Fragment28.from(this.node), 0, 0);
31274
+ return new Slice(Fragment29.from(this.node), 0, 0);
30889
31275
  }
30890
31276
  eq(other) {
30891
31277
  return other instanceof _NodeSelection && other.anchor == this.anchor;
@@ -30982,7 +31368,7 @@ var AllBookmark = {
30982
31368
  };
30983
31369
  function findSelectionIn(doc, node, pos, index, dir, text = false) {
30984
31370
  if (node.inlineContent)
30985
- return TextSelection2.create(doc, pos);
31371
+ return TextSelection3.create(doc, pos);
30986
31372
  for (let i = index - (dir > 0 ? 0 : 1); dir > 0 ? i < node.childCount : i >= 0; i += dir) {
30987
31373
  let child = node.child(i);
30988
31374
  if (!child.isAtom) {
@@ -31288,7 +31674,7 @@ if (typeof WeakMap != "undefined") {
31288
31674
  return cache[cachePos++] = value;
31289
31675
  };
31290
31676
  }
31291
- var TableMap = class {
31677
+ var TableMap2 = class {
31292
31678
  constructor(width, height, map, problems) {
31293
31679
  this.width = width;
31294
31680
  this.height = height;
@@ -31425,7 +31811,7 @@ function computeMap(table) {
31425
31811
  pos++;
31426
31812
  }
31427
31813
  if (width === 0 || height === 0) (problems || (problems = [])).push({ type: "zero_sized" });
31428
- const tableMap = new TableMap(width, height, map, problems);
31814
+ const tableMap = new TableMap2(width, height, map, problems);
31429
31815
  let badWidths = false;
31430
31816
  for (let i = 0; !badWidths && i < colWidths.length; i += 2) if (colWidths[i] != null && colWidths[i + 1] < height) badWidths = true;
31431
31817
  if (badWidths) findBadColWidths(tableMap, colWidths, table);
@@ -31529,7 +31915,7 @@ function inSameTable($cellA, $cellB) {
31529
31915
  }
31530
31916
  function nextCell($pos, axis, dir) {
31531
31917
  const table = $pos.node(-1);
31532
- const map = TableMap.get(table);
31918
+ const map = TableMap2.get(table);
31533
31919
  const tableStart = $pos.start(-1);
31534
31920
  const moved = map.nextCell($pos.pos - tableStart, axis, dir);
31535
31921
  return moved == null ? null : $pos.node(0).resolve(tableStart + moved);
@@ -31549,7 +31935,7 @@ function removeColSpan(attrs, pos, n = 1) {
31549
31935
  var CellSelection = class CellSelection2 extends Selection {
31550
31936
  constructor($anchorCell, $headCell = $anchorCell) {
31551
31937
  const table = $anchorCell.node(-1);
31552
- const map = TableMap.get(table);
31938
+ const map = TableMap2.get(table);
31553
31939
  const tableStart = $anchorCell.start(-1);
31554
31940
  const rect = map.rectBetween($anchorCell.pos - tableStart, $headCell.pos - tableStart);
31555
31941
  const doc = $anchorCell.node(0);
@@ -31574,11 +31960,11 @@ var CellSelection = class CellSelection2 extends Selection {
31574
31960
  else if (tableChanged && this.isColSelection()) return CellSelection2.colSelection($anchorCell, $headCell);
31575
31961
  else return new CellSelection2($anchorCell, $headCell);
31576
31962
  }
31577
- return TextSelection2.between($anchorCell, $headCell);
31963
+ return TextSelection3.between($anchorCell, $headCell);
31578
31964
  }
31579
31965
  content() {
31580
31966
  const table = this.$anchorCell.node(-1);
31581
- const map = TableMap.get(table);
31967
+ const map = TableMap2.get(table);
31582
31968
  const tableStart = this.$anchorCell.start(-1);
31583
31969
  const rect = map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart);
31584
31970
  const seen = {};
@@ -31613,10 +31999,10 @@ var CellSelection = class CellSelection2 extends Selection {
31613
31999
  }
31614
32000
  rowContent.push(cell);
31615
32001
  }
31616
- rows.push(table.child(row).copy(Fragment28.from(rowContent)));
32002
+ rows.push(table.child(row).copy(Fragment29.from(rowContent)));
31617
32003
  }
31618
32004
  const fragment = this.isColSelection() && this.isRowSelection() ? table : rows;
31619
- return new Slice(Fragment28.from(fragment), 1, 1);
32005
+ return new Slice(Fragment29.from(fragment), 1, 1);
31620
32006
  }
31621
32007
  replace(tr, content = Slice.empty) {
31622
32008
  const mapFrom = tr.steps.length, ranges = this.ranges;
@@ -31628,11 +32014,11 @@ var CellSelection = class CellSelection2 extends Selection {
31628
32014
  if (sel) tr.setSelection(sel);
31629
32015
  }
31630
32016
  replaceWith(tr, node) {
31631
- this.replace(tr, new Slice(Fragment28.from(node), 0, 0));
32017
+ this.replace(tr, new Slice(Fragment29.from(node), 0, 0));
31632
32018
  }
31633
32019
  forEachCell(f) {
31634
32020
  const table = this.$anchorCell.node(-1);
31635
- const map = TableMap.get(table);
32021
+ const map = TableMap2.get(table);
31636
32022
  const tableStart = this.$anchorCell.start(-1);
31637
32023
  const cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart));
31638
32024
  for (let i = 0; i < cells.length; i++) f(table.nodeAt(cells[i]), tableStart + cells[i]);
@@ -31647,7 +32033,7 @@ var CellSelection = class CellSelection2 extends Selection {
31647
32033
  }
31648
32034
  static colSelection($anchorCell, $headCell = $anchorCell) {
31649
32035
  const table = $anchorCell.node(-1);
31650
- const map = TableMap.get(table);
32036
+ const map = TableMap2.get(table);
31651
32037
  const tableStart = $anchorCell.start(-1);
31652
32038
  const anchorRect = map.findCell($anchorCell.pos - tableStart);
31653
32039
  const headRect = map.findCell($headCell.pos - tableStart);
@@ -31663,7 +32049,7 @@ var CellSelection = class CellSelection2 extends Selection {
31663
32049
  }
31664
32050
  isRowSelection() {
31665
32051
  const table = this.$anchorCell.node(-1);
31666
- const map = TableMap.get(table);
32052
+ const map = TableMap2.get(table);
31667
32053
  const tableStart = this.$anchorCell.start(-1);
31668
32054
  const anchorLeft = map.colCount(this.$anchorCell.pos - tableStart);
31669
32055
  const headLeft = map.colCount(this.$headCell.pos - tableStart);
@@ -31677,7 +32063,7 @@ var CellSelection = class CellSelection2 extends Selection {
31677
32063
  }
31678
32064
  static rowSelection($anchorCell, $headCell = $anchorCell) {
31679
32065
  const table = $anchorCell.node(-1);
31680
- const map = TableMap.get(table);
32066
+ const map = TableMap2.get(table);
31681
32067
  const tableStart = $anchorCell.start(-1);
31682
32068
  const anchorRect = map.findCell($anchorCell.pos - tableStart);
31683
32069
  const headRect = map.findCell($headCell.pos - tableStart);
@@ -31726,7 +32112,7 @@ var CellBookmark = class CellBookmark2 {
31726
32112
  };
31727
32113
  var fixTablesKey = new PluginKey3("fix-tables");
31728
32114
  function convertTableNodeToArrayOfRows(tableNode) {
31729
- const map = TableMap.get(tableNode);
32115
+ const map = TableMap2.get(tableNode);
31730
32116
  const rows = [];
31731
32117
  const rowCount = map.height;
31732
32118
  const colCount$1 = map.width;
@@ -31757,7 +32143,7 @@ function convertTableNodeToArrayOfRows(tableNode) {
31757
32143
  }
31758
32144
  function convertArrayOfRowsToTableNode(tableNode, arrayOfNodes) {
31759
32145
  const newRows = [];
31760
- const map = TableMap.get(tableNode);
32146
+ const map = TableMap2.get(tableNode);
31761
32147
  const rowCount = map.height;
31762
32148
  const colCount$1 = map.width;
31763
32149
  for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
@@ -31806,7 +32192,7 @@ function findParentNode(predicate, $pos) {
31806
32192
  function getCellsInColumn(columnIndex, selection) {
31807
32193
  const table = findTable(selection.$from);
31808
32194
  if (!table) return;
31809
- const map = TableMap.get(table.node);
32195
+ const map = TableMap2.get(table.node);
31810
32196
  if (columnIndex < 0 || columnIndex > map.width - 1) return;
31811
32197
  return map.cellsInRect({
31812
32198
  left: columnIndex,
@@ -31827,7 +32213,7 @@ function getCellsInColumn(columnIndex, selection) {
31827
32213
  function getCellsInRow(rowIndex, selection) {
31828
32214
  const table = findTable(selection.$from);
31829
32215
  if (!table) return;
31830
- const map = TableMap.get(table.node);
32216
+ const map = TableMap2.get(table.node);
31831
32217
  if (rowIndex < 0 || rowIndex > map.height - 1) return;
31832
32218
  return map.cellsInRect({
31833
32219
  left: 0,
@@ -31956,7 +32342,7 @@ function moveColumn(moveColParams) {
31956
32342
  const newTable = moveTableColumn$1(table.node, indexesOriginColumn, indexesTargetColumn, 0);
31957
32343
  tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
31958
32344
  if (!select) return true;
31959
- const map = TableMap.get(newTable);
32345
+ const map = TableMap2.get(newTable);
31960
32346
  const start = table.start;
31961
32347
  const index = targetIndex;
31962
32348
  const lastCell = map.positionAt(map.height - 1, index, newTable);
@@ -31984,7 +32370,7 @@ function moveRow(moveRowParams) {
31984
32370
  const newTable = moveTableRow$1(table.node, indexesOriginRow, indexesTargetRow, 0);
31985
32371
  tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
31986
32372
  if (!select) return true;
31987
- const map = TableMap.get(newTable);
32373
+ const map = TableMap2.get(newTable);
31988
32374
  const start = table.start;
31989
32375
  const index = targetIndex;
31990
32376
  const lastCell = map.positionAt(index, map.width - 1, newTable);
@@ -31999,12 +32385,12 @@ function moveTableRow$1(table, indexesOrigin, indexesTarget, direction) {
31999
32385
  rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction);
32000
32386
  return convertArrayOfRowsToTableNode(table, rows);
32001
32387
  }
32002
- function selectedRect(state) {
32388
+ function selectedRect2(state) {
32003
32389
  const sel = state.selection;
32004
32390
  const $pos = selectionCell(state);
32005
32391
  const table = $pos.node(-1);
32006
32392
  const tableStart = $pos.start(-1);
32007
- const map = TableMap.get(table);
32393
+ const map = TableMap2.get(table);
32008
32394
  return {
32009
32395
  ...sel instanceof CellSelection ? map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart) : map.findCell($pos.pos - tableStart),
32010
32396
  tableStart,
@@ -32017,7 +32403,7 @@ function deprecated_toggleHeader(type) {
32017
32403
  if (!isInTable(state)) return false;
32018
32404
  if (dispatch) {
32019
32405
  const types = tableNodeTypes(state.schema);
32020
- const rect = selectedRect(state), tr = state.tr;
32406
+ const rect = selectedRect2(state), tr = state.tr;
32021
32407
  const cells = rect.map.cellsInRect(type == "column" ? {
32022
32408
  left: rect.left,
32023
32409
  top: 0,
@@ -32057,7 +32443,7 @@ function toggleHeader(type, options) {
32057
32443
  if (!isInTable(state)) return false;
32058
32444
  if (dispatch) {
32059
32445
  const types = tableNodeTypes(state.schema);
32060
- const rect = selectedRect(state), tr = state.tr;
32446
+ const rect = selectedRect2(state), tr = state.tr;
32061
32447
  const isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
32062
32448
  const isHeaderColumnEnabled = isHeaderEnabledByType("column", rect, types);
32063
32449
  const selectionStartsAt = (type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false) ? 1 : 0;
@@ -32189,7 +32575,7 @@ function shiftArrow(axis, dir) {
32189
32575
  };
32190
32576
  }
32191
32577
  function atEndOfCell(view, axis, dir) {
32192
- if (!(view.state.selection instanceof TextSelection2)) return null;
32578
+ if (!(view.state.selection instanceof TextSelection3)) return null;
32193
32579
  const { $head } = view.state.selection;
32194
32580
  for (let d = $head.depth - 1; d >= 0; d--) {
32195
32581
  const parent = $head.node(d);
@@ -32205,152 +32591,482 @@ function atEndOfCell(view, axis, dir) {
32205
32591
  var columnResizingPluginKey = new PluginKey3("tableColumnResizing");
32206
32592
 
32207
32593
  // src/components/UEditor/table-controls.tsx
32208
- var import_lucide_react46 = require("lucide-react");
32209
-
32210
- // src/components/UEditor/table-dom-utils.ts
32211
- var MIN_TABLE_ROW_HEIGHT = 36;
32212
- var COLUMN_RESIZE_LINE_THICKNESS = 2;
32213
- var ROW_RESIZE_LINE_THICKNESS = 2;
32214
- var UEDITOR_TABLE_LAYOUT_CHANGE_EVENT = "ueditor-table-layout-change";
32215
- var TABLE_RESIZE_HIT_ZONE = 10;
32216
- function findTableRowNodeInfo(view, rowElement) {
32217
- const firstCell = rowElement.querySelector("th,td");
32218
- if (!firstCell) return null;
32219
- const cellPos = view.posAtDOM(firstCell, 0);
32220
- const $pos = view.state.doc.resolve(cellPos);
32221
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
32222
- const node = $pos.node(depth);
32223
- if (node.type.name === "tableRow") {
32224
- return {
32225
- pos: $pos.before(depth),
32226
- node
32227
- };
32228
- }
32229
- }
32230
- return null;
32231
- }
32232
- function resolveEventElement(target) {
32233
- if (target instanceof Element) return target;
32234
- if (target instanceof Node) return target.parentElement;
32235
- return null;
32236
- }
32237
- function getSelectionTableCell(view) {
32238
- const browserSelection = window.getSelection();
32239
- const anchorElement = resolveEventElement(browserSelection?.anchorNode ?? null);
32240
- const anchorCell = anchorElement?.closest?.("th,td");
32241
- if (anchorCell instanceof HTMLElement) {
32242
- return anchorCell;
32243
- }
32244
- const { from } = view.state.selection;
32245
- const domAtPos = view.domAtPos(from);
32246
- const element = resolveEventElement(domAtPos.node);
32247
- const cell = element?.closest?.("th,td");
32248
- return cell instanceof HTMLElement ? cell : null;
32249
- }
32250
- function isRowResizeHotspot(cell, clientX, clientY) {
32251
- const rect = cell.getBoundingClientRect();
32252
- const nearBottom = rect.bottom - clientY <= TABLE_RESIZE_HIT_ZONE;
32253
- const nearRight = rect.right - clientX <= TABLE_RESIZE_HIT_ZONE;
32254
- return nearBottom && !nearRight;
32255
- }
32256
- function isColumnResizeHotspot(cell, clientX, clientY) {
32257
- const rect = cell.getBoundingClientRect();
32258
- const nearRight = rect.right - clientX <= TABLE_RESIZE_HIT_ZONE;
32259
- const nearBottom = rect.bottom - clientY <= TABLE_RESIZE_HIT_ZONE;
32260
- return nearRight && !nearBottom;
32261
- }
32262
- function getRelativeBoundaryMetrics(surface, table, row, cell) {
32263
- const surfaceRect = surface.getBoundingClientRect();
32264
- const tableRect = table.getBoundingClientRect();
32265
- const rowRect = row.getBoundingClientRect();
32266
- const cellRect = cell.getBoundingClientRect();
32267
- return {
32268
- left: tableRect.left - surfaceRect.left + surface.scrollLeft,
32269
- top: tableRect.top - surfaceRect.top + surface.scrollTop,
32270
- width: tableRect.width,
32271
- height: tableRect.height,
32272
- rowBottom: rowRect.bottom - surfaceRect.top + surface.scrollTop,
32273
- columnRight: cellRect.right - surfaceRect.left + surface.scrollLeft
32274
- };
32275
- }
32276
- function getRelativeCellMetrics(surface, cell) {
32277
- const surfaceRect = surface.getBoundingClientRect();
32278
- const cellRect = cell.getBoundingClientRect();
32279
- return {
32280
- left: cellRect.left - surfaceRect.left + surface.scrollLeft,
32281
- top: cellRect.top - surfaceRect.top + surface.scrollTop,
32282
- width: cellRect.width,
32283
- height: cellRect.height
32284
- };
32285
- }
32286
- function getRelativeSelectedCellsMetrics(surface) {
32287
- const selectedCells = Array.from(
32288
- surface.querySelectorAll("td.selectedCell, th.selectedCell")
32289
- );
32290
- if (selectedCells.length === 0) {
32291
- return null;
32292
- }
32293
- const surfaceRect = surface.getBoundingClientRect();
32294
- let left = Number.POSITIVE_INFINITY;
32295
- let top = Number.POSITIVE_INFINITY;
32296
- let right = Number.NEGATIVE_INFINITY;
32297
- let bottom = Number.NEGATIVE_INFINITY;
32298
- selectedCells.forEach((cell) => {
32299
- const rect = cell.getBoundingClientRect();
32300
- left = Math.min(left, rect.left);
32301
- top = Math.min(top, rect.top);
32302
- right = Math.max(right, rect.right);
32303
- bottom = Math.max(bottom, rect.bottom);
32304
- });
32305
- return {
32306
- left: left - surfaceRect.left + surface.scrollLeft,
32307
- top: top - surfaceRect.top + surface.scrollTop,
32308
- width: right - left,
32309
- height: bottom - top
32310
- };
32311
- }
32594
+ var import_lucide_react48 = require("lucide-react");
32312
32595
 
32313
- // src/components/UEditor/table-controls.tsx
32314
- var import_jsx_runtime84 = require("react/jsx-runtime");
32315
- var FALLBACK_TABLE_ROW_HEIGHT = 44;
32316
- var FALLBACK_TABLE_COLUMN_WIDTH = 160;
32596
+ // src/components/UEditor/table-hover-state.ts
32317
32597
  var MENU_HOVER_PADDING = 18;
32318
32598
  var ROW_HANDLE_HOVER_WIDTH = 28;
32319
32599
  var COLUMN_HANDLE_HOVER_HEIGHT = 28;
32320
- var TABLE_MENU_TOP_OFFSET = 10;
32321
- var ADD_COLUMN_RAIL_GAP = 4;
32322
- var ADD_ROW_RAIL_GAP = 4;
32323
32600
  var ADD_COLUMN_HOVER_WIDTH = 24;
32324
32601
  var ADD_ROW_HOVER_HEIGHT = 24;
32325
32602
  var HANDLE_HOVER_RADIUS = 14;
32326
- var IDLE_HANDLE_SCALE = "0.78";
32327
- var DEFAULT_HOVER_STATE = {
32603
+ var DEFAULT_TABLE_HOVER_STATE = {
32328
32604
  menuVisible: false,
32329
32605
  addColumnVisible: false,
32330
32606
  addRowVisible: false,
32331
32607
  rowHandleIndex: null,
32332
32608
  columnHandleIndex: null
32333
32609
  };
32334
- function resolveElement(target) {
32335
- if (target instanceof Element) return target;
32336
- if (target instanceof Node) return target.parentElement;
32337
- return null;
32610
+ function areTableHoverStatesEqual(left, right) {
32611
+ return left.menuVisible === right.menuVisible && left.addColumnVisible === right.addColumnVisible && left.addRowVisible === right.addRowVisible && left.rowHandleIndex === right.rowHandleIndex && left.columnHandleIndex === right.columnHandleIndex;
32338
32612
  }
32339
- function nearestIndex(centers, position) {
32340
- let bestIndex = 0;
32341
- let bestDistance = Number.POSITIVE_INFINITY;
32342
- centers.forEach((center, index) => {
32343
- const distance = Math.abs(center - position);
32344
- if (distance < bestDistance) {
32345
- bestDistance = distance;
32346
- bestIndex = index;
32613
+ function buildTableHoverState({
32614
+ event,
32615
+ layout,
32616
+ surface
32617
+ }) {
32618
+ const surfaceRect = surface.getBoundingClientRect();
32619
+ const relativeX = event.clientX - surfaceRect.left + surface.scrollLeft;
32620
+ const relativeY = event.clientY - surfaceRect.top + surface.scrollTop;
32621
+ const targetElement = resolveEventElement(event.target);
32622
+ const directRowHandle = targetElement?.closest?.("[data-row-handle-index]");
32623
+ const directColumnHandle = targetElement?.closest?.("[data-column-handle-index]");
32624
+ const directTableMenu = targetElement?.closest?.("[data-table-control='table-menu']");
32625
+ const directAddColumn = targetElement?.closest?.("[data-table-control='add-column']");
32626
+ const directAddRow = targetElement?.closest?.("[data-table-control='add-row']");
32627
+ const directRowHandleIndex = directRowHandle instanceof HTMLElement ? Number.parseInt(directRowHandle.dataset.rowHandleIndex ?? "", 10) : Number.NaN;
32628
+ const directColumnHandleIndex = directColumnHandle instanceof HTMLElement ? Number.parseInt(directColumnHandle.dataset.columnHandleIndex ?? "", 10) : Number.NaN;
32629
+ const visibleTableWidth = Math.min(layout.tableWidth, layout.viewportWidth);
32630
+ const visibleTableHeight = Math.min(layout.tableHeight, layout.viewportHeight);
32631
+ const isMouseInTable = relativeX >= layout.tableLeft && relativeX <= layout.tableLeft + layout.tableWidth && relativeY >= layout.tableTop && relativeY <= layout.tableTop + layout.tableHeight;
32632
+ const rowHandleIndex = Number.isFinite(directRowHandleIndex) ? directRowHandleIndex : layout.rowHandles.find((rowHandle) => relativeX >= layout.tableLeft - ROW_HANDLE_HOVER_WIDTH && relativeX <= layout.tableLeft && Math.abs(relativeY - rowHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
32633
+ const columnHandleIndex = Number.isFinite(directColumnHandleIndex) ? directColumnHandleIndex : layout.columnHandles.find((columnHandle) => relativeY >= layout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= layout.tableTop && Math.abs(relativeX - columnHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
32634
+ const menuVisible = Boolean(directTableMenu) || isMouseInTable || relativeX >= layout.tableLeft - MENU_HOVER_PADDING && relativeX <= layout.tableLeft + 42 && relativeY >= layout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= layout.tableTop + MENU_HOVER_PADDING;
32635
+ const lastRow = layout.rowHandles[layout.rowHandles.length - 1];
32636
+ const lastCol = layout.columnHandles[layout.columnHandles.length - 1];
32637
+ const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >= layout.tableTop && relativeY <= layout.tableTop + visibleTableHeight : false;
32638
+ const addColumnVisible = Boolean(directAddColumn) || relativeX >= layout.tableLeft + visibleTableWidth && relativeX <= layout.tableLeft + visibleTableWidth + ADD_COLUMN_HOVER_WIDTH && relativeY >= layout.tableTop && relativeY <= layout.tableTop + visibleTableHeight || isMouseInLastColumn;
32639
+ const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >= layout.tableLeft && relativeX <= layout.tableLeft + visibleTableWidth : false;
32640
+ const addRowVisible = Boolean(directAddRow) || relativeY >= layout.tableTop + visibleTableHeight && relativeY <= layout.tableTop + visibleTableHeight + ADD_ROW_HOVER_HEIGHT && relativeX >= layout.tableLeft && relativeX <= layout.tableLeft + visibleTableWidth || isMouseInLastRow;
32641
+ return {
32642
+ menuVisible,
32643
+ addColumnVisible,
32644
+ addRowVisible,
32645
+ rowHandleIndex,
32646
+ columnHandleIndex
32647
+ };
32648
+ }
32649
+
32650
+ // src/components/UEditor/table-drag-preview.tsx
32651
+ var import_jsx_runtime84 = require("react/jsx-runtime");
32652
+ function TableDragPreview({
32653
+ columnDragLabel,
32654
+ dragPreview,
32655
+ layout,
32656
+ rowDragLabel
32657
+ }) {
32658
+ if (!dragPreview) return null;
32659
+ const expandPreviewWidth = dragPreview.kind === "add-column" ? layout.tableWidth + dragPreview.previewCols * layout.avgColumnWidth : layout.tableWidth;
32660
+ const expandPreviewHeight = dragPreview.kind === "add-row" ? layout.tableHeight + dragPreview.previewRows * layout.avgRowHeight : layout.tableHeight;
32661
+ const dragStatusText = dragPreview.kind === "row" ? `${rowDragLabel} ${dragPreview.originIndex + 1} -> ${dragPreview.targetIndex + 1}` : dragPreview.kind === "column" ? `${columnDragLabel} ${dragPreview.originIndex + 1} -> ${dragPreview.targetIndex + 1}` : dragPreview.kind === "add-row" ? `+${dragPreview.previewRows}R` : `+${dragPreview.previewCols}C`;
32662
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
32663
+ dragPreview.kind === "row" && /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
32664
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32665
+ "div",
32666
+ {
32667
+ "aria-hidden": "true",
32668
+ className: "pointer-events-none absolute z-20 rounded-lg border border-primary/20 bg-primary/10",
32669
+ style: {
32670
+ top: dragPreview.targetStart,
32671
+ left: layout.tableLeft,
32672
+ width: layout.tableWidth,
32673
+ height: dragPreview.targetSize
32674
+ }
32675
+ }
32676
+ ),
32677
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32678
+ "div",
32679
+ {
32680
+ "aria-hidden": "true",
32681
+ className: "pointer-events-none absolute z-20 rounded-full bg-primary/80",
32682
+ style: {
32683
+ top: dragPreview.targetStart + dragPreview.targetSize / 2 - 1,
32684
+ left: layout.tableLeft,
32685
+ width: layout.tableWidth,
32686
+ height: 2
32687
+ }
32688
+ }
32689
+ )
32690
+ ] }),
32691
+ dragPreview.kind === "column" && /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
32692
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32693
+ "div",
32694
+ {
32695
+ "aria-hidden": "true",
32696
+ className: "pointer-events-none absolute z-20 rounded-lg border border-primary/20 bg-primary/10",
32697
+ style: {
32698
+ top: layout.tableTop,
32699
+ left: dragPreview.targetStart,
32700
+ width: dragPreview.targetSize,
32701
+ height: layout.tableHeight
32702
+ }
32703
+ }
32704
+ ),
32705
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32706
+ "div",
32707
+ {
32708
+ "aria-hidden": "true",
32709
+ className: "pointer-events-none absolute z-20 rounded-full bg-primary/80",
32710
+ style: {
32711
+ top: layout.tableTop,
32712
+ left: dragPreview.targetStart + dragPreview.targetSize / 2 - 1,
32713
+ width: 2,
32714
+ height: layout.tableHeight
32715
+ }
32716
+ }
32717
+ )
32718
+ ] }),
32719
+ (dragPreview.kind === "add-row" || dragPreview.kind === "add-column") && /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32720
+ "div",
32721
+ {
32722
+ "aria-hidden": "true",
32723
+ className: "pointer-events-none absolute z-20 rounded-xl border border-dashed border-primary/70 bg-primary/5",
32724
+ style: {
32725
+ top: layout.tableTop,
32726
+ left: layout.tableLeft,
32727
+ width: expandPreviewWidth,
32728
+ height: expandPreviewHeight
32729
+ }
32730
+ }
32731
+ ),
32732
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32733
+ "div",
32734
+ {
32735
+ role: "status",
32736
+ className: "pointer-events-none absolute z-30 rounded-full border border-primary/20 bg-background/95 px-2 py-1 text-[11px] font-medium text-foreground shadow-sm backdrop-blur",
32737
+ style: {
32738
+ top: dragPreview.kind === "add-row" || dragPreview.kind === "add-column" ? layout.tableTop + expandPreviewHeight + 8 : layout.tableTop - 40,
32739
+ left: dragPreview.kind === "add-row" || dragPreview.kind === "add-column" ? layout.tableLeft + Math.max(0, expandPreviewWidth - 84) : layout.tableLeft + Math.max(0, layout.tableWidth - 108)
32740
+ },
32741
+ children: dragStatusText
32742
+ }
32743
+ )
32744
+ ] });
32745
+ }
32746
+
32747
+ // src/components/UEditor/table-add-rails.tsx
32748
+ var import_jsx_runtime85 = require("react/jsx-runtime");
32749
+ var ADD_COLUMN_RAIL_GAP = 4;
32750
+ var ADD_ROW_RAIL_GAP = 4;
32751
+ function TableAddRails({
32752
+ addColumnVisible,
32753
+ addRowVisible,
32754
+ canExpandTable,
32755
+ controlsVisible,
32756
+ layout,
32757
+ onStartAddColumn,
32758
+ onStartAddRow,
32759
+ quickAddColumnLabel,
32760
+ quickAddRowLabel
32761
+ }) {
32762
+ const visibleTableWidth = Math.min(layout.tableWidth, layout.viewportWidth);
32763
+ const visibleTableHeight = Math.min(layout.tableHeight, layout.viewportHeight);
32764
+ const columnRailTop = layout.tableTop;
32765
+ const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
32766
+ const rowRailTop = layout.tableTop + visibleTableHeight + ADD_ROW_RAIL_GAP;
32767
+ const rowRailLeft = layout.tableLeft;
32768
+ const showColumnRail = controlsVisible || addColumnVisible;
32769
+ const showRowRail = controlsVisible || addRowVisible;
32770
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(import_jsx_runtime85.Fragment, { children: [
32771
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
32772
+ Tooltip,
32773
+ {
32774
+ placement: "right",
32775
+ content: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-xs font-medium", children: quickAddColumnLabel }),
32776
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
32777
+ "button",
32778
+ {
32779
+ type: "button",
32780
+ "data-table-control": "add-column",
32781
+ "aria-label": quickAddColumnLabel,
32782
+ onMouseDown: (event) => {
32783
+ event.preventDefault();
32784
+ event.stopPropagation();
32785
+ if (!canExpandTable) return;
32786
+ onStartAddColumn();
32787
+ },
32788
+ disabled: !canExpandTable,
32789
+ className: cn(
32790
+ "absolute z-30 inline-flex items-center justify-center rounded-md",
32791
+ "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
32792
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
32793
+ ),
32794
+ style: {
32795
+ top: showColumnRail ? columnRailTop : columnRailTop + Math.max(0, visibleTableHeight / 2 - 24),
32796
+ left: columnRailLeft,
32797
+ width: showColumnRail ? 18 : 12,
32798
+ height: showColumnRail ? visibleTableHeight : 48,
32799
+ opacity: showColumnRail ? 1 : 0,
32800
+ transform: showColumnRail ? "scale(1)" : "scale(0.92)",
32801
+ pointerEvents: showColumnRail ? "auto" : "none"
32802
+ },
32803
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-sm font-medium leading-none", children: "+" })
32804
+ }
32805
+ )
32806
+ }
32807
+ ),
32808
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
32809
+ Tooltip,
32810
+ {
32811
+ placement: "bottom",
32812
+ content: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-xs font-medium", children: quickAddRowLabel }),
32813
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
32814
+ "button",
32815
+ {
32816
+ type: "button",
32817
+ "data-table-control": "add-row",
32818
+ "aria-label": quickAddRowLabel,
32819
+ onMouseDown: (event) => {
32820
+ event.preventDefault();
32821
+ event.stopPropagation();
32822
+ if (!canExpandTable) return;
32823
+ onStartAddRow();
32824
+ },
32825
+ disabled: !canExpandTable,
32826
+ className: cn(
32827
+ "absolute z-30 inline-flex items-center justify-center rounded-md",
32828
+ "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
32829
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
32830
+ ),
32831
+ style: {
32832
+ top: rowRailTop,
32833
+ left: showRowRail ? rowRailLeft : rowRailLeft + Math.max(0, visibleTableWidth / 2 - 24),
32834
+ width: showRowRail ? visibleTableWidth : 48,
32835
+ height: showRowRail ? 16 : 12,
32836
+ opacity: showRowRail ? 1 : 0,
32837
+ transform: showRowRail ? "scale(1)" : "scale(0.92)",
32838
+ pointerEvents: showRowRail ? "auto" : "none"
32839
+ },
32840
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-sm font-medium leading-none", children: "+" })
32841
+ }
32842
+ )
32843
+ }
32844
+ )
32845
+ ] });
32846
+ }
32847
+
32848
+ // src/components/UEditor/table-control-menu.tsx
32849
+ var import_lucide_react46 = require("lucide-react");
32850
+ var import_jsx_runtime86 = require("react/jsx-runtime");
32851
+ function TableControlMenu({
32852
+ controlsVisible,
32853
+ isOpen,
32854
+ items,
32855
+ label,
32856
+ left,
32857
+ menuVisible,
32858
+ onOpenChange,
32859
+ top
32860
+ }) {
32861
+ const shown = controlsVisible || menuVisible || isOpen;
32862
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
32863
+ "div",
32864
+ {
32865
+ className: "absolute z-30",
32866
+ "data-table-control": "table-menu",
32867
+ style: {
32868
+ top,
32869
+ left
32870
+ },
32871
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
32872
+ Tooltip,
32873
+ {
32874
+ placement: "top",
32875
+ disabled: isOpen,
32876
+ content: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "text-xs font-medium", children: label }),
32877
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
32878
+ DropdownMenu,
32879
+ {
32880
+ placement: "bottom-start",
32881
+ isOpen,
32882
+ onOpenChange,
32883
+ contentClassName: "p-2",
32884
+ items,
32885
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
32886
+ "button",
32887
+ {
32888
+ type: "button",
32889
+ "aria-label": label,
32890
+ onMouseDown: (event) => event.preventDefault(),
32891
+ className: cn(
32892
+ "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-full",
32893
+ "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
32894
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
32895
+ ),
32896
+ style: {
32897
+ opacity: shown ? 1 : 0,
32898
+ transform: shown ? "scale(1)" : "scale(0.82)",
32899
+ pointerEvents: shown ? "auto" : "none"
32900
+ },
32901
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_lucide_react46.MoreHorizontal, { className: "h-4 w-4" })
32902
+ }
32903
+ )
32904
+ }
32905
+ ) })
32906
+ }
32907
+ )
32347
32908
  }
32348
- });
32349
- return bestIndex;
32909
+ );
32350
32910
  }
32911
+
32912
+ // src/components/UEditor/table-axis-handles.tsx
32913
+ var import_lucide_react47 = require("lucide-react");
32914
+ var import_jsx_runtime87 = require("react/jsx-runtime");
32915
+ var IDLE_HANDLE_SCALE = "0.78";
32916
+ function TableRowHandles({
32917
+ activeRowIndex,
32918
+ controlsVisible,
32919
+ getMenuItems,
32920
+ hoverRowHandleIndex,
32921
+ onOpenMenuChange,
32922
+ onStartDrag,
32923
+ openMenuKey,
32924
+ rowDragLabel,
32925
+ rowHandleLeft,
32926
+ rowHandles
32927
+ }) {
32928
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_jsx_runtime87.Fragment, { children: rowHandles.map((rowHandle) => {
32929
+ const menuKey = `row:${rowHandle.index}`;
32930
+ const isActive = rowHandle.index === activeRowIndex;
32931
+ const visible = controlsVisible || hoverRowHandleIndex === rowHandle.index || openMenuKey === menuKey;
32932
+ const isShown = visible || isActive;
32933
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
32934
+ "div",
32935
+ {
32936
+ className: "absolute z-30",
32937
+ "data-row-handle-index": rowHandle.index,
32938
+ style: {
32939
+ top: Math.max(8, rowHandle.center - 12),
32940
+ left: rowHandleLeft
32941
+ },
32942
+ children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
32943
+ Tooltip,
32944
+ {
32945
+ placement: "right",
32946
+ disabled: openMenuKey === menuKey || !visible && isActive,
32947
+ content: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "text-xs font-medium", children: `${rowDragLabel} ${rowHandle.index + 1}` }),
32948
+ children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
32949
+ DropdownMenu,
32950
+ {
32951
+ placement: "right",
32952
+ isOpen: openMenuKey === menuKey,
32953
+ onOpenChange: (open) => onOpenMenuChange(menuKey, open),
32954
+ contentClassName: "p-2",
32955
+ items: getMenuItems(rowHandle),
32956
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
32957
+ "button",
32958
+ {
32959
+ type: "button",
32960
+ "aria-label": `${rowDragLabel} ${rowHandle.index + 1}`,
32961
+ onMouseDown: (event) => {
32962
+ event.preventDefault();
32963
+ event.stopPropagation();
32964
+ onStartDrag(rowHandle);
32965
+ },
32966
+ className: cn(
32967
+ "inline-flex h-6 w-6 items-center justify-center rounded-full transition-[opacity,transform,colors,border,background-color] duration-150",
32968
+ visible ? "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur hover:bg-accent hover:text-foreground cursor-grab active:cursor-grabbing" : "border-transparent bg-transparent cursor-pointer"
32969
+ ),
32970
+ style: {
32971
+ opacity: isShown ? 1 : 0,
32972
+ transform: isShown ? "scale(1)" : `scale(${IDLE_HANDLE_SCALE})`,
32973
+ pointerEvents: isShown ? "auto" : "none"
32974
+ },
32975
+ children: visible ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react47.GripVertical, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "h-3 w-1 rounded-full bg-muted-foreground/50 hover:bg-muted-foreground" })
32976
+ }
32977
+ )
32978
+ }
32979
+ ) })
32980
+ }
32981
+ )
32982
+ },
32983
+ `row-handle-${rowHandle.index}`
32984
+ );
32985
+ }) });
32986
+ }
32987
+ function TableColumnHandles({
32988
+ activeColumnIndex,
32989
+ columnDragLabel,
32990
+ columnHandleTop,
32991
+ columnHandles,
32992
+ controlsVisible,
32993
+ getMenuItems,
32994
+ hoverColumnHandleIndex,
32995
+ onOpenMenuChange,
32996
+ onStartDrag,
32997
+ openMenuKey
32998
+ }) {
32999
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_jsx_runtime87.Fragment, { children: columnHandles.map((columnHandle) => {
33000
+ const menuKey = `column:${columnHandle.index}`;
33001
+ const isActive = columnHandle.index === activeColumnIndex;
33002
+ const visible = controlsVisible || hoverColumnHandleIndex === columnHandle.index || openMenuKey === menuKey;
33003
+ const isShown = visible || isActive;
33004
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
33005
+ "div",
33006
+ {
33007
+ className: "absolute z-30",
33008
+ "data-column-handle-index": columnHandle.index,
33009
+ style: {
33010
+ top: columnHandleTop,
33011
+ left: Math.max(8, columnHandle.center - 12)
33012
+ },
33013
+ children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
33014
+ Tooltip,
33015
+ {
33016
+ placement: "top",
33017
+ disabled: openMenuKey === menuKey || !visible && isActive,
33018
+ content: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "text-xs font-medium", children: `${columnDragLabel} ${columnHandle.index + 1}` }),
33019
+ children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
33020
+ DropdownMenu,
33021
+ {
33022
+ placement: "bottom-start",
33023
+ isOpen: openMenuKey === menuKey,
33024
+ onOpenChange: (open) => onOpenMenuChange(menuKey, open),
33025
+ contentClassName: "p-2",
33026
+ items: getMenuItems(columnHandle),
33027
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
33028
+ "button",
33029
+ {
33030
+ type: "button",
33031
+ "aria-label": `${columnDragLabel} ${columnHandle.index + 1}`,
33032
+ onMouseDown: (event) => {
33033
+ event.preventDefault();
33034
+ event.stopPropagation();
33035
+ onStartDrag(columnHandle);
33036
+ },
33037
+ className: cn(
33038
+ "inline-flex h-6 w-6 items-center justify-center rounded-full transition-[opacity,transform,colors,border,background-color] duration-150",
33039
+ visible ? "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur hover:bg-accent hover:text-foreground cursor-grab active:cursor-grabbing" : "border-transparent bg-transparent cursor-pointer"
33040
+ ),
33041
+ style: {
33042
+ opacity: isShown ? 1 : 0,
33043
+ transform: isShown ? "scale(1)" : `scale(${IDLE_HANDLE_SCALE})`,
33044
+ pointerEvents: isShown ? "auto" : "none"
33045
+ },
33046
+ children: visible ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react47.GripHorizontal, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "h-1 w-3 rounded-full bg-muted-foreground/50 hover:bg-muted-foreground" })
33047
+ }
33048
+ )
33049
+ }
33050
+ ) })
33051
+ }
33052
+ )
33053
+ },
33054
+ `column-handle-${columnHandle.index}`
33055
+ );
33056
+ }) });
33057
+ }
33058
+
33059
+ // src/components/UEditor/table-layout-model.ts
33060
+ var FALLBACK_TABLE_ROW_HEIGHT = 44;
33061
+ var FALLBACK_TABLE_COLUMN_WIDTH = 160;
32351
33062
  function metricOrFallback(value, fallback) {
32352
33063
  return Number.isFinite(value) && value > 0 ? value : fallback;
32353
33064
  }
33065
+ function parsePixelMetric(value) {
33066
+ if (!value) return null;
33067
+ const parsed = Number.parseFloat(value);
33068
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
33069
+ }
32354
33070
  function getPrimaryCell(table) {
32355
33071
  const cell = table.querySelector("th,td");
32356
33072
  return cell instanceof HTMLTableCellElement ? cell : null;
@@ -32362,7 +33078,7 @@ function getLastCell(table) {
32362
33078
  return cell instanceof HTMLTableCellElement ? cell : null;
32363
33079
  }
32364
33080
  function getCellFromTarget(target) {
32365
- const element = resolveElement(target);
33081
+ const element = resolveEventElement(target);
32366
33082
  if (!element) return null;
32367
33083
  const directCell = element.closest("th,td");
32368
33084
  if (directCell instanceof HTMLTableCellElement) {
@@ -32388,25 +33104,135 @@ function findTableInfo(editor, pos) {
32388
33104
  }
32389
33105
  return null;
32390
33106
  }
32391
- function getLastCellPosFromState(editor, pos) {
32392
- const tableInfo = findTableInfo(editor, pos);
32393
- if (!tableInfo) return null;
32394
- const map = TableMap.get(tableInfo.node);
32395
- return tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node);
33107
+ function getCellRelativePosFromDomPos(map, tableStart, domPos) {
33108
+ const relativeDomPos = domPos - tableStart;
33109
+ const seen = /* @__PURE__ */ new Set();
33110
+ for (const relativeCellPos of map.map) {
33111
+ if (seen.has(relativeCellPos)) continue;
33112
+ seen.add(relativeCellPos);
33113
+ if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
33114
+ return relativeCellPos;
33115
+ }
33116
+ }
33117
+ return null;
33118
+ }
33119
+ function buildLogicalColumnMetrics({
33120
+ editor,
33121
+ surface,
33122
+ surfaceRect,
33123
+ tableElement,
33124
+ tableInfo,
33125
+ tableLeft,
33126
+ tableWidth
33127
+ }) {
33128
+ const map = TableMap2.get(tableInfo.node);
33129
+ const fallbackWidth = metricOrFallback(tableWidth / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
33130
+ const firstRow = tableElement.rows.item(0);
33131
+ const visualColumns = [];
33132
+ if (firstRow) {
33133
+ for (const tableCell of Array.from(firstRow.cells)) {
33134
+ if (!(tableCell instanceof HTMLTableCellElement)) continue;
33135
+ const cellPos = editor.view.posAtDOM(tableCell, 0);
33136
+ const relativeCellPos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
33137
+ if (relativeCellPos == null) continue;
33138
+ const cellMapRect = map.findCell(relativeCellPos);
33139
+ const cellRect = tableCell.getBoundingClientRect();
33140
+ const cellStart = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + cellMapRect.left * fallbackWidth;
33141
+ const size = metricOrFallback(cellRect.width, fallbackWidth * Math.max(1, cellMapRect.right - cellMapRect.left));
33142
+ visualColumns.push({
33143
+ index: cellMapRect.left,
33144
+ cellPos: tableInfo.start + relativeCellPos,
33145
+ start: cellStart,
33146
+ size,
33147
+ center: cellStart + size / 2
33148
+ });
33149
+ }
33150
+ }
33151
+ if (visualColumns.length > 0) {
33152
+ return visualColumns.sort((a, b) => a.index - b.index);
33153
+ }
33154
+ const cols = Array.from(tableElement.querySelectorAll("colgroup > col"));
33155
+ const parsedWidths = cols.slice(0, map.width).map((col) => parsePixelMetric(col.style.width) ?? parsePixelMetric(col.getAttribute("width")));
33156
+ const hasCompleteColWidths = parsedWidths.length >= map.width && parsedWidths.every((width) => typeof width === "number");
33157
+ let cursor = tableLeft;
33158
+ return Array.from({ length: map.width }, (_, index) => {
33159
+ const size = hasCompleteColWidths ? parsedWidths[index] : fallbackWidth;
33160
+ const start = hasCompleteColWidths ? cursor : tableLeft + index * fallbackWidth;
33161
+ cursor += size;
33162
+ return {
33163
+ index,
33164
+ cellPos: tableInfo.start + map.positionAt(0, index, tableInfo.node),
33165
+ start,
33166
+ size,
33167
+ center: start + size / 2
33168
+ };
33169
+ });
33170
+ }
33171
+ function buildLogicalRowMetrics({
33172
+ editor,
33173
+ surface,
33174
+ surfaceRect,
33175
+ tableInfo,
33176
+ rows,
33177
+ tableTop,
33178
+ tableHeight,
33179
+ cornerCell
33180
+ }) {
33181
+ const map = TableMap2.get(tableInfo.node);
33182
+ const fallbackHeight = metricOrFallback(tableHeight / map.height, FALLBACK_TABLE_ROW_HEIGHT);
33183
+ const visualRows = [];
33184
+ const seenCellPositions = /* @__PURE__ */ new Set();
33185
+ for (let rowIndex = 0; rowIndex < map.height; rowIndex += 1) {
33186
+ const relativeCellPos = map.map[rowIndex * map.width];
33187
+ if (seenCellPositions.has(relativeCellPos)) continue;
33188
+ seenCellPositions.add(relativeCellPos);
33189
+ const cellMapRect = map.findCell(relativeCellPos);
33190
+ const cellDom = editor.view.nodeDOM(tableInfo.start + relativeCellPos);
33191
+ const tableCell = cellDom instanceof HTMLTableCellElement ? cellDom : null;
33192
+ if (tableCell) {
33193
+ const cellRect = tableCell.getBoundingClientRect();
33194
+ const start = cellRect.height > 0 ? cellRect.top - surfaceRect.top + surface.scrollTop : tableTop + cellMapRect.top * fallbackHeight;
33195
+ const size = metricOrFallback(cellRect.height, fallbackHeight * Math.max(1, cellMapRect.bottom - cellMapRect.top));
33196
+ visualRows.push({
33197
+ index: cellMapRect.top,
33198
+ cellPos: tableInfo.start + relativeCellPos,
33199
+ start,
33200
+ size,
33201
+ center: start + size / 2
33202
+ });
33203
+ }
33204
+ }
33205
+ if (visualRows.length > 0) {
33206
+ return visualRows.sort((a, b) => a.index - b.index);
33207
+ }
33208
+ return rows.map((tableRow, index) => {
33209
+ const rowRect = tableRow.getBoundingClientRect();
33210
+ const anchorCell = tableRow.cells.item(0) ?? cornerCell;
33211
+ const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * fallbackHeight;
33212
+ const size = metricOrFallback(rowRect.height, fallbackHeight);
33213
+ return {
33214
+ index,
33215
+ cellPos: editor.view.posAtDOM(anchorCell, 0),
33216
+ start,
33217
+ size,
33218
+ center: start + size / 2
33219
+ };
33220
+ });
32396
33221
  }
32397
- function buildLayout(editor, surface, cell) {
33222
+ function buildTableControlLayout(editor, surface, cell) {
32398
33223
  const row = cell.closest("tr");
32399
33224
  const table = cell.closest("table");
32400
33225
  if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
32401
33226
  return null;
32402
33227
  }
32403
33228
  const rows = Array.from(table.rows).filter((item) => item instanceof HTMLTableRowElement);
32404
- const referenceRow = rows[0];
32405
- const referenceCells = Array.from(referenceRow?.cells ?? []).filter((item) => item instanceof HTMLTableCellElement);
32406
33229
  const cornerCell = getLastCell(table);
32407
- if (rows.length === 0 || referenceCells.length === 0 || !(cornerCell instanceof HTMLTableCellElement)) {
33230
+ const cellPos = editor.view.posAtDOM(cell, 0);
33231
+ const tableInfo = findTableInfo(editor, cellPos);
33232
+ if (rows.length === 0 || !tableInfo || !(cornerCell instanceof HTMLTableCellElement)) {
32408
33233
  return null;
32409
33234
  }
33235
+ const map = TableMap2.get(tableInfo.node);
32410
33236
  const surfaceRect = surface.getBoundingClientRect();
32411
33237
  const tableRect = table.getBoundingClientRect();
32412
33238
  const wrapperElement = table.closest(".tableWrapper");
@@ -32415,8 +33241,8 @@ function buildLayout(editor, surface, cell) {
32415
33241
  const tableLeft = tableRect.left - surfaceRect.left + surface.scrollLeft;
32416
33242
  const tableTop = tableRect.top - surfaceRect.top + surface.scrollTop;
32417
33243
  const avgRowHeight = metricOrFallback(tableRect.height / rows.length, FALLBACK_TABLE_ROW_HEIGHT);
32418
- const avgColumnWidth = metricOrFallback(tableRect.width / referenceCells.length, FALLBACK_TABLE_COLUMN_WIDTH);
32419
- const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * referenceCells.length);
33244
+ const avgColumnWidth = metricOrFallback(tableRect.width / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
33245
+ const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * map.width);
32420
33246
  const tableHeight = metricOrFallback(tableRect.height, avgRowHeight * rows.length);
32421
33247
  const wrapperLeft = wrapperRect.left - surfaceRect.left + surface.scrollLeft;
32422
33248
  const wrapperTop = wrapperRect.top - surfaceRect.top + surface.scrollTop;
@@ -32426,36 +33252,33 @@ function buildLayout(editor, surface, cell) {
32426
33252
  const viewportHeight = metricOrFallback(wrapper?.clientHeight ?? wrapperRect.height, tableHeight);
32427
33253
  const verticalScrollbarWidth = Math.max(0, Math.round(wrapperWidth - viewportWidth));
32428
33254
  const horizontalScrollbarHeight = Math.max(0, Math.round(wrapperHeight - viewportHeight));
32429
- const rowHandles = rows.map((tableRow, index) => {
32430
- const rowRect = tableRow.getBoundingClientRect();
32431
- const anchorCell = tableRow.cells.item(0) ?? cornerCell;
32432
- const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * avgRowHeight;
32433
- const size = metricOrFallback(rowRect.height, avgRowHeight);
32434
- return {
32435
- index,
32436
- cellPos: editor.view.posAtDOM(anchorCell, 0),
32437
- start,
32438
- size,
32439
- center: start + size / 2
32440
- };
33255
+ const rowHandles = buildLogicalRowMetrics({
33256
+ editor,
33257
+ surface,
33258
+ surfaceRect,
33259
+ tableInfo,
33260
+ rows,
33261
+ tableTop,
33262
+ tableHeight,
33263
+ cornerCell
32441
33264
  });
32442
- const columnHandles = referenceCells.map((tableCell, index) => {
32443
- const cellRect = tableCell.getBoundingClientRect();
32444
- const start = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + index * avgColumnWidth;
32445
- const size = metricOrFallback(cellRect.width, avgColumnWidth);
32446
- return {
32447
- index,
32448
- cellPos: editor.view.posAtDOM(tableCell, 0),
32449
- start,
32450
- size,
32451
- center: start + size / 2
32452
- };
33265
+ const columnHandles = buildLogicalColumnMetrics({
33266
+ editor,
33267
+ surface,
33268
+ surfaceRect,
33269
+ tableElement: table,
33270
+ tableInfo,
33271
+ tableLeft,
33272
+ tableWidth
32453
33273
  });
33274
+ const activeCellRelativePos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
33275
+ const activeCellRect = activeCellRelativePos != null ? map.findCell(activeCellRelativePos) : { left: cell.cellIndex, top: row.rowIndex };
33276
+ const normalizedCellPos = activeCellRelativePos != null ? tableInfo.start + activeCellRelativePos : cellPos;
32454
33277
  return {
32455
- cellPos: editor.view.posAtDOM(cell, 0),
32456
- cornerCellPos: editor.view.posAtDOM(cornerCell, 0),
32457
- activeRowIndex: row.rowIndex,
32458
- activeColumnIndex: cell.cellIndex,
33278
+ cellPos: normalizedCellPos,
33279
+ cornerCellPos: tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node),
33280
+ activeRowIndex: activeCellRect.top,
33281
+ activeColumnIndex: activeCellRect.left,
32459
33282
  tableLeft,
32460
33283
  tableTop,
32461
33284
  tableWidth,
@@ -32474,9 +33297,25 @@ function buildLayout(editor, surface, cell) {
32474
33297
  columnHandles
32475
33298
  };
32476
33299
  }
33300
+
33301
+ // src/components/UEditor/table-controls.tsx
33302
+ var import_jsx_runtime88 = require("react/jsx-runtime");
33303
+ var TABLE_MENU_TOP_OFFSET = 10;
33304
+ function nearestIndex(centers, position) {
33305
+ let bestIndex = 0;
33306
+ let bestDistance = Number.POSITIVE_INFINITY;
33307
+ centers.forEach((center, index) => {
33308
+ const distance = Math.abs(center - position);
33309
+ if (distance < bestDistance) {
33310
+ bestDistance = distance;
33311
+ bestIndex = index;
33312
+ }
33313
+ });
33314
+ return bestIndex;
33315
+ }
32477
33316
  function getSelectedCell(editor) {
32478
33317
  const browserSelection = window.getSelection();
32479
- const anchorElement = resolveElement(browserSelection?.anchorNode ?? null);
33318
+ const anchorElement = resolveEventElement(browserSelection?.anchorNode ?? null);
32480
33319
  const anchorCell = anchorElement?.closest?.("th,td");
32481
33320
  if (anchorCell instanceof HTMLTableCellElement) {
32482
33321
  return anchorCell;
@@ -32484,35 +33323,15 @@ function getSelectedCell(editor) {
32484
33323
  const domAtPos = editor.view.domAtPos(editor.state.selection.from);
32485
33324
  return getCellFromTarget(domAtPos.node);
32486
33325
  }
32487
- function getFocusableCellPos(editor, cellPos) {
32488
- const cellNode = editor.state.doc.nodeAt(cellPos);
32489
- if (!cellNode) return cellPos + 1;
32490
- let offset = cellPos + 1;
32491
- let node = cellNode.firstChild ?? null;
32492
- while (node && !node.isTextblock) {
32493
- offset += 1;
32494
- node = node.firstChild ?? null;
32495
- }
32496
- return node?.isTextblock ? offset + 1 : cellPos + 1;
32497
- }
32498
- function focusCell(editor, cellPos) {
32499
- const selection = TextSelection2.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
32500
- editor.view.dispatch(editor.state.tr.setSelection(selection));
32501
- editor.view.focus();
32502
- }
32503
- function collectChildren(node) {
32504
- const children = [];
32505
- node.forEach((child) => children.push(child));
32506
- return children;
32507
- }
32508
33326
  function TableControls({ editor, containerRef }) {
32509
33327
  const t = useSmartTranslations("UEditor");
32510
33328
  const [layout, setLayout] = import_react53.default.useState(null);
32511
33329
  const [dragPreview, setDragPreview] = import_react53.default.useState(null);
32512
- const [hoverState, setHoverState] = import_react53.default.useState(DEFAULT_HOVER_STATE);
33330
+ const [hoverState, setHoverState] = import_react53.default.useState(DEFAULT_TABLE_HOVER_STATE);
32513
33331
  const [openMenuKey, setOpenMenuKey] = import_react53.default.useState(null);
32514
33332
  const layoutRef = import_react53.default.useRef(null);
32515
33333
  const dragStateRef = import_react53.default.useRef(null);
33334
+ const syncFrameRef = import_react53.default.useRef(null);
32516
33335
  import_react53.default.useEffect(() => {
32517
33336
  layoutRef.current = layout;
32518
33337
  }, [layout]);
@@ -32522,11 +33341,24 @@ function TableControls({ editor, containerRef }) {
32522
33341
  setLayout(null);
32523
33342
  return;
32524
33343
  }
32525
- setLayout(buildLayout(editor, surface, cell));
33344
+ setLayout(buildTableControlLayout(editor, surface, cell));
32526
33345
  }, [containerRef, editor]);
32527
33346
  const syncFromSelection = import_react53.default.useCallback(() => {
32528
33347
  syncFromCell(getSelectedCell(editor));
32529
33348
  }, [editor, syncFromCell]);
33349
+ const scheduleSyncFromSelection = import_react53.default.useCallback(() => {
33350
+ if (syncFrameRef.current !== null) return;
33351
+ syncFrameRef.current = window.requestAnimationFrame(() => {
33352
+ syncFrameRef.current = null;
33353
+ syncFromSelection();
33354
+ });
33355
+ }, [syncFromSelection]);
33356
+ import_react53.default.useEffect(() => () => {
33357
+ if (syncFrameRef.current !== null) {
33358
+ window.cancelAnimationFrame(syncFrameRef.current);
33359
+ syncFrameRef.current = null;
33360
+ }
33361
+ }, []);
32530
33362
  const refreshCurrentLayout = import_react53.default.useCallback(() => {
32531
33363
  setLayout((prev) => {
32532
33364
  if (!prev) return prev;
@@ -32534,7 +33366,7 @@ function TableControls({ editor, containerRef }) {
32534
33366
  if (!surface) return null;
32535
33367
  const node = editor.view.nodeDOM(prev.cellPos);
32536
33368
  const cell = getCellFromTarget(node) ?? getSelectedCell(editor);
32537
- return cell ? buildLayout(editor, surface, cell) : null;
33369
+ return cell ? buildTableControlLayout(editor, surface, cell) : null;
32538
33370
  });
32539
33371
  }, [containerRef, editor]);
32540
33372
  const clearDrag = import_react53.default.useCallback(() => {
@@ -32546,43 +33378,16 @@ function TableControls({ editor, containerRef }) {
32546
33378
  const activeLayout = layoutRef.current;
32547
33379
  const surface = containerRef.current;
32548
33380
  if (!activeLayout || !surface || dragStateRef.current) {
32549
- setHoverState(DEFAULT_HOVER_STATE);
33381
+ setHoverState(DEFAULT_TABLE_HOVER_STATE);
32550
33382
  return;
32551
33383
  }
32552
- const surfaceRect = surface.getBoundingClientRect();
32553
- const relativeX = event.clientX - surfaceRect.left + surface.scrollLeft;
32554
- const relativeY = event.clientY - surfaceRect.top + surface.scrollTop;
32555
- const targetElement = resolveElement(event.target);
32556
- const directRowHandle = targetElement?.closest?.("[data-row-handle-index]");
32557
- const directColumnHandle = targetElement?.closest?.("[data-column-handle-index]");
32558
- const directTableMenu = targetElement?.closest?.("[data-table-control='table-menu']");
32559
- const directAddColumn = targetElement?.closest?.("[data-table-control='add-column']");
32560
- const directAddRow = targetElement?.closest?.("[data-table-control='add-row']");
32561
- const directRowHandleIndex = directRowHandle instanceof HTMLElement ? Number.parseInt(directRowHandle.dataset.rowHandleIndex ?? "", 10) : Number.NaN;
32562
- const directColumnHandleIndex = directColumnHandle instanceof HTMLElement ? Number.parseInt(directColumnHandle.dataset.columnHandleIndex ?? "", 10) : Number.NaN;
32563
- const visibleTableWidth2 = Math.min(activeLayout.tableWidth, activeLayout.viewportWidth);
32564
- const visibleTableHeight2 = Math.min(activeLayout.tableHeight, activeLayout.viewportHeight);
32565
- const isMouseInTable = relativeX >= activeLayout.tableLeft && relativeX <= activeLayout.tableLeft + activeLayout.tableWidth && relativeY >= activeLayout.tableTop && relativeY <= activeLayout.tableTop + activeLayout.tableHeight;
32566
- const rowHandleIndex = Number.isFinite(directRowHandleIndex) ? directRowHandleIndex : activeLayout.rowHandles.find((rowHandle) => relativeX >= activeLayout.tableLeft - ROW_HANDLE_HOVER_WIDTH && relativeX <= activeLayout.tableLeft && Math.abs(relativeY - rowHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
32567
- const columnHandleIndex = Number.isFinite(directColumnHandleIndex) ? directColumnHandleIndex : activeLayout.columnHandles.find((columnHandle) => relativeY >= activeLayout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= activeLayout.tableTop && Math.abs(relativeX - columnHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
32568
- const menuVisible = Boolean(directTableMenu) || isMouseInTable || relativeX >= activeLayout.tableLeft - MENU_HOVER_PADDING && relativeX <= activeLayout.tableLeft + 42 && relativeY >= activeLayout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= activeLayout.tableTop + MENU_HOVER_PADDING;
32569
- const lastRow = activeLayout.rowHandles[activeLayout.rowHandles.length - 1];
32570
- const lastCol = activeLayout.columnHandles[activeLayout.columnHandles.length - 1];
32571
- const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >= activeLayout.tableTop && relativeY <= activeLayout.tableTop + visibleTableHeight2 : false;
32572
- const addColumnVisible = Boolean(directAddColumn) || relativeX >= activeLayout.tableLeft + visibleTableWidth2 && relativeX <= activeLayout.tableLeft + visibleTableWidth2 + ADD_COLUMN_HOVER_WIDTH && relativeY >= activeLayout.tableTop && relativeY <= activeLayout.tableTop + visibleTableHeight2 || isMouseInLastColumn;
32573
- const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >= activeLayout.tableLeft && relativeX <= activeLayout.tableLeft + visibleTableWidth2 : false;
32574
- const addRowVisible = Boolean(directAddRow) || relativeY >= activeLayout.tableTop + visibleTableHeight2 && relativeY <= activeLayout.tableTop + visibleTableHeight2 + ADD_ROW_HOVER_HEIGHT && relativeX >= activeLayout.tableLeft && relativeX <= activeLayout.tableLeft + visibleTableWidth2 || isMouseInLastRow;
33384
+ const nextState = buildTableHoverState({
33385
+ event,
33386
+ layout: activeLayout,
33387
+ surface
33388
+ });
32575
33389
  setHoverState((prev) => {
32576
- if (prev.menuVisible === menuVisible && prev.addColumnVisible === addColumnVisible && prev.addRowVisible === addRowVisible && prev.rowHandleIndex === rowHandleIndex && prev.columnHandleIndex === columnHandleIndex) {
32577
- return prev;
32578
- }
32579
- return {
32580
- menuVisible,
32581
- addColumnVisible,
32582
- addRowVisible,
32583
- rowHandleIndex,
32584
- columnHandleIndex
32585
- };
33390
+ return areTableHoverStatesEqual(prev, nextState) ? prev : nextState;
32586
33391
  });
32587
33392
  }, [containerRef]);
32588
33393
  import_react53.default.useEffect(() => {
@@ -32600,14 +33405,17 @@ function TableControls({ editor, containerRef }) {
32600
33405
  };
32601
33406
  const handleMouseLeave = () => {
32602
33407
  if (dragStateRef.current) return;
32603
- setHoverState(DEFAULT_HOVER_STATE);
33408
+ setHoverState(DEFAULT_TABLE_HOVER_STATE);
32604
33409
  };
32605
- const handleFocusIn = () => {
33410
+ const handleFocusIn = (event) => {
32606
33411
  if (dragStateRef.current) return;
32607
- syncFromSelection();
33412
+ const cell = event ? getCellFromTarget(event.target) : null;
33413
+ syncFromCell(cell ?? getSelectedCell(editor));
32608
33414
  };
32609
33415
  proseMirror.addEventListener("mouseover", handleMouseOver);
32610
33416
  proseMirror.addEventListener("mouseleave", handleMouseLeave);
33417
+ proseMirror.addEventListener("click", handleFocusIn);
33418
+ proseMirror.addEventListener("mouseup", handleFocusIn);
32611
33419
  proseMirror.addEventListener("focusin", handleFocusIn);
32612
33420
  surface.addEventListener("mouseover", handleSurfaceMouseMove);
32613
33421
  surface.addEventListener("mousemove", handleSurfaceMouseMove);
@@ -32620,6 +33428,8 @@ function TableControls({ editor, containerRef }) {
32620
33428
  return () => {
32621
33429
  proseMirror.removeEventListener("mouseover", handleMouseOver);
32622
33430
  proseMirror.removeEventListener("mouseleave", handleMouseLeave);
33431
+ proseMirror.removeEventListener("click", handleFocusIn);
33432
+ proseMirror.removeEventListener("mouseup", handleFocusIn);
32623
33433
  proseMirror.removeEventListener("focusin", handleFocusIn);
32624
33434
  surface.removeEventListener("mouseover", handleSurfaceMouseMove);
32625
33435
  surface.removeEventListener("mousemove", handleSurfaceMouseMove);
@@ -32631,98 +33441,90 @@ function TableControls({ editor, containerRef }) {
32631
33441
  };
32632
33442
  }, [clearDrag, containerRef, editor, refreshCurrentLayout, syncFromCell, syncFromSelection, updateHoverState]);
32633
33443
  const runAtCellPos = import_react53.default.useCallback((cellPos, command, options) => {
32634
- if (cellPos == null) return false;
32635
- focusCell(editor, cellPos);
32636
- const result = command(editor.chain().focus(null, { scrollIntoView: false })).run();
33444
+ const result = runTableCommandAtCellPos(editor, cellPos, command);
32637
33445
  if (options?.sync !== false) {
32638
- requestAnimationFrame(syncFromSelection);
33446
+ scheduleSyncFromSelection();
32639
33447
  }
32640
33448
  return result;
32641
- }, [editor, syncFromSelection]);
33449
+ }, [editor, scheduleSyncFromSelection]);
32642
33450
  const runAtActiveCell = import_react53.default.useCallback((command, options) => {
32643
33451
  return runAtCellPos(layoutRef.current?.cellPos ?? null, command, options);
32644
33452
  }, [runAtCellPos]);
32645
- const getCurrentCornerCellPos = import_react53.default.useCallback(() => {
32646
- const activePos = layoutRef.current?.cellPos ?? editor.state.selection.from;
32647
- return getLastCellPosFromState(editor, activePos);
32648
- }, [editor]);
32649
- const runAtCornerCell = import_react53.default.useCallback((command, options) => {
32650
- return runAtCellPos(getCurrentCornerCellPos(), command, options);
32651
- }, [getCurrentCornerCellPos, runAtCellPos]);
32652
- const replaceTableAtCellPos = import_react53.default.useCallback((cellPos, updateTable) => {
32653
- if (cellPos == null) return false;
32654
- const tableInfo = findTableInfo(editor, cellPos);
32655
- if (!tableInfo) return false;
32656
- const nextTable = updateTable(tableInfo.node);
32657
- if (!nextTable) return false;
32658
- editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.pos, tableInfo.pos + tableInfo.node.nodeSize, nextTable));
32659
- requestAnimationFrame(syncFromSelection);
32660
- return true;
32661
- }, [editor, syncFromSelection]);
32662
- const createEmptyCellNode = import_react53.default.useCallback((cellNode) => {
32663
- return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
32664
- }, []);
32665
33453
  const duplicateRowAt = import_react53.default.useCallback((rowIndex, cellPos) => {
32666
- return replaceTableAtCellPos(cellPos, (tableNode) => {
32667
- const rows = collectChildren(tableNode);
32668
- const rowNode = rows[rowIndex];
32669
- if (!rowNode) return null;
32670
- rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
32671
- return tableNode.type.create(tableNode.attrs, rows);
32672
- });
32673
- }, [replaceTableAtCellPos]);
33454
+ const result = duplicateTableRowAt(editor, rowIndex, cellPos);
33455
+ scheduleSyncFromSelection();
33456
+ return result;
33457
+ }, [editor, scheduleSyncFromSelection]);
32674
33458
  const clearRowAt = import_react53.default.useCallback((rowIndex, cellPos) => {
32675
- return replaceTableAtCellPos(cellPos, (tableNode) => {
32676
- const rows = collectChildren(tableNode);
32677
- const rowNode = rows[rowIndex];
32678
- if (!rowNode) return null;
32679
- const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
32680
- rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
32681
- return tableNode.type.create(tableNode.attrs, rows);
32682
- });
32683
- }, [createEmptyCellNode, replaceTableAtCellPos]);
33459
+ const result = clearTableRowAt(editor, rowIndex, cellPos);
33460
+ scheduleSyncFromSelection();
33461
+ return result;
33462
+ }, [editor, scheduleSyncFromSelection]);
32684
33463
  const duplicateColumnAt = import_react53.default.useCallback((columnIndex, cellPos) => {
32685
- return replaceTableAtCellPos(cellPos, (tableNode) => {
32686
- const rows = collectChildren(tableNode).map((rowNode) => {
32687
- const cells = collectChildren(rowNode);
32688
- const cellNode = cells[columnIndex];
32689
- if (!cellNode) return rowNode;
32690
- cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
32691
- return rowNode.type.create(rowNode.attrs, cells);
32692
- });
32693
- return tableNode.type.create(tableNode.attrs, rows);
32694
- });
32695
- }, [replaceTableAtCellPos]);
33464
+ const result = duplicateTableColumnAt(editor, columnIndex, cellPos);
33465
+ scheduleSyncFromSelection();
33466
+ return result;
33467
+ }, [editor, scheduleSyncFromSelection]);
32696
33468
  const clearColumnAt = import_react53.default.useCallback((columnIndex, cellPos) => {
32697
- return replaceTableAtCellPos(cellPos, (tableNode) => {
32698
- const rows = collectChildren(tableNode).map((rowNode) => {
32699
- const cells = collectChildren(rowNode);
32700
- const cellNode = cells[columnIndex];
32701
- if (!cellNode) return rowNode;
32702
- cells[columnIndex] = createEmptyCellNode(cellNode);
32703
- return rowNode.type.create(rowNode.attrs, cells);
32704
- });
32705
- return tableNode.type.create(tableNode.attrs, rows);
32706
- });
32707
- }, [createEmptyCellNode, replaceTableAtCellPos]);
33469
+ const result = clearTableColumnAt(editor, columnIndex, cellPos);
33470
+ scheduleSyncFromSelection();
33471
+ return result;
33472
+ }, [editor, scheduleSyncFromSelection]);
32708
33473
  const expandTableBy = import_react53.default.useCallback((rows, cols) => {
32709
- let ok = true;
32710
- for (let index = 0; index < rows; index += 1) {
32711
- ok = runAtCornerCell((chain) => chain.addRowAfter(), { sync: false });
32712
- if (!ok) return false;
32713
- }
32714
- for (let index = 0; index < cols; index += 1) {
32715
- ok = runAtCornerCell((chain) => chain.addColumnAfter(), { sync: false });
32716
- if (!ok) return false;
32717
- }
32718
- requestAnimationFrame(syncFromSelection);
32719
- return true;
32720
- }, [runAtCornerCell, syncFromSelection]);
33474
+ const activeCellPos = layoutRef.current?.cellPos ?? editor.state.selection.from;
33475
+ const result = expandTableFromCell(editor, activeCellPos, rows, cols);
33476
+ scheduleSyncFromSelection();
33477
+ return result;
33478
+ }, [editor, scheduleSyncFromSelection]);
32721
33479
  const canExpandTable = Boolean(layout);
32722
33480
  const controlsVisible = dragPreview !== null;
32723
33481
  const tableMenuOpen = openMenuKey === "table";
32724
- const getRowMenuKey = import_react53.default.useCallback((index) => `row:${index}`, []);
32725
- const getColumnMenuKey = import_react53.default.useCallback((index) => `column:${index}`, []);
33482
+ const startAddColumnDrag = import_react53.default.useCallback(() => {
33483
+ setOpenMenuKey(null);
33484
+ dragStateRef.current = { kind: "add-column", previewCols: 1 };
33485
+ setDragPreview({ kind: "add-column", previewCols: 1 });
33486
+ document.body.style.cursor = "ew-resize";
33487
+ }, []);
33488
+ const startAddRowDrag = import_react53.default.useCallback(() => {
33489
+ setOpenMenuKey(null);
33490
+ dragStateRef.current = { kind: "add-row", previewRows: 1 };
33491
+ setDragPreview({ kind: "add-row", previewRows: 1 });
33492
+ document.body.style.cursor = "ns-resize";
33493
+ }, []);
33494
+ const startRowDrag = import_react53.default.useCallback((rowHandle) => {
33495
+ setOpenMenuKey(null);
33496
+ dragStateRef.current = {
33497
+ kind: "row",
33498
+ originIndex: rowHandle.index,
33499
+ targetIndex: rowHandle.index,
33500
+ anchorPos: rowHandle.cellPos
33501
+ };
33502
+ setDragPreview({
33503
+ kind: "row",
33504
+ originIndex: rowHandle.index,
33505
+ targetIndex: rowHandle.index,
33506
+ targetStart: rowHandle.start,
33507
+ targetSize: rowHandle.size
33508
+ });
33509
+ document.body.style.cursor = "grabbing";
33510
+ }, []);
33511
+ const startColumnDrag = import_react53.default.useCallback((columnHandle) => {
33512
+ setOpenMenuKey(null);
33513
+ dragStateRef.current = {
33514
+ kind: "column",
33515
+ originIndex: columnHandle.index,
33516
+ targetIndex: columnHandle.index,
33517
+ anchorPos: columnHandle.cellPos
33518
+ };
33519
+ setDragPreview({
33520
+ kind: "column",
33521
+ originIndex: columnHandle.index,
33522
+ targetIndex: columnHandle.index,
33523
+ targetStart: columnHandle.start,
33524
+ targetSize: columnHandle.size
33525
+ });
33526
+ document.body.style.cursor = "grabbing";
33527
+ }, []);
32726
33528
  import_react53.default.useEffect(() => {
32727
33529
  const handleMouseMove = (event) => {
32728
33530
  const dragState = dragStateRef.current;
@@ -32733,9 +33535,10 @@ function TableControls({ editor, containerRef }) {
32733
33535
  const relativeX = event.clientX - surfaceRect.left + surface.scrollLeft;
32734
33536
  const relativeY = event.clientY - surfaceRect.top + surface.scrollTop;
32735
33537
  if (dragState.kind === "row") {
32736
- const targetIndex = nearestIndex(activeLayout.rowHandles.map((item) => item.center), relativeY);
33538
+ const targetHandleIndex = nearestIndex(activeLayout.rowHandles.map((item) => item.center), relativeY);
33539
+ const targetRow = activeLayout.rowHandles[targetHandleIndex];
33540
+ const targetIndex = targetRow.index;
32737
33541
  dragState.targetIndex = targetIndex;
32738
- const targetRow = activeLayout.rowHandles[targetIndex];
32739
33542
  setDragPreview({
32740
33543
  kind: "row",
32741
33544
  originIndex: dragState.originIndex,
@@ -32747,9 +33550,10 @@ function TableControls({ editor, containerRef }) {
32747
33550
  return;
32748
33551
  }
32749
33552
  if (dragState.kind === "column") {
32750
- const targetIndex = nearestIndex(activeLayout.columnHandles.map((item) => item.center), relativeX);
33553
+ const targetHandleIndex = nearestIndex(activeLayout.columnHandles.map((item) => item.center), relativeX);
33554
+ const targetColumn = activeLayout.columnHandles[targetHandleIndex];
33555
+ const targetIndex = targetColumn.index;
32751
33556
  dragState.targetIndex = targetIndex;
32752
- const targetColumn = activeLayout.columnHandles[targetIndex];
32753
33557
  setDragPreview({
32754
33558
  kind: "column",
32755
33559
  originIndex: dragState.originIndex,
@@ -32782,7 +33586,7 @@ function TableControls({ editor, containerRef }) {
32782
33586
  pos: dragState.anchorPos,
32783
33587
  select: true
32784
33588
  })(editor.state, editor.view.dispatch);
32785
- requestAnimationFrame(syncFromSelection);
33589
+ scheduleSyncFromSelection();
32786
33590
  }
32787
33591
  if (dragState.kind === "column" && dragState.originIndex !== dragState.targetIndex) {
32788
33592
  moveTableColumn({
@@ -32791,7 +33595,7 @@ function TableControls({ editor, containerRef }) {
32791
33595
  pos: dragState.anchorPos,
32792
33596
  select: true
32793
33597
  })(editor.state, editor.view.dispatch);
32794
- requestAnimationFrame(syncFromSelection);
33598
+ scheduleSyncFromSelection();
32795
33599
  }
32796
33600
  if (dragState.kind === "add-row") {
32797
33601
  expandTableBy(dragState.previewRows, 0);
@@ -32809,70 +33613,70 @@ function TableControls({ editor, containerRef }) {
32809
33613
  window.removeEventListener("mouseup", handleMouseUp);
32810
33614
  window.removeEventListener("blur", clearDrag);
32811
33615
  };
32812
- }, [clearDrag, containerRef, editor, expandTableBy, syncFromSelection]);
33616
+ }, [clearDrag, containerRef, editor, expandTableBy, scheduleSyncFromSelection]);
32813
33617
  const menuItems = import_react53.default.useMemo(() => {
32814
33618
  if (!layout) return [];
32815
33619
  return [
32816
33620
  {
32817
33621
  label: t("tableMenu.alignLeft"),
32818
- icon: import_lucide_react46.AlignLeft,
33622
+ icon: import_lucide_react48.AlignLeft,
32819
33623
  onClick: () => applyTableAlignment(editor, "left", layout.cellPos)
32820
33624
  },
32821
33625
  {
32822
33626
  label: t("tableMenu.alignCenter"),
32823
- icon: import_lucide_react46.AlignCenter,
33627
+ icon: import_lucide_react48.AlignCenter,
32824
33628
  onClick: () => applyTableAlignment(editor, "center", layout.cellPos)
32825
33629
  },
32826
33630
  {
32827
33631
  label: t("tableMenu.alignRight"),
32828
- icon: import_lucide_react46.AlignRight,
33632
+ icon: import_lucide_react48.AlignRight,
32829
33633
  onClick: () => applyTableAlignment(editor, "right", layout.cellPos)
32830
33634
  },
32831
33635
  {
32832
33636
  label: t("tableMenu.addColumnBefore"),
32833
- icon: import_lucide_react46.ArrowLeft,
33637
+ icon: import_lucide_react48.ArrowLeft,
32834
33638
  onClick: () => runAtActiveCell((chain) => chain.addColumnBefore())
32835
33639
  },
32836
33640
  {
32837
33641
  label: t("tableMenu.addColumnAfter"),
32838
- icon: import_lucide_react46.ArrowRight,
33642
+ icon: import_lucide_react48.ArrowRight,
32839
33643
  onClick: () => runAtActiveCell((chain) => chain.addColumnAfter())
32840
33644
  },
32841
33645
  {
32842
33646
  label: t("tableMenu.addRowBefore"),
32843
- icon: import_lucide_react46.ArrowUp,
33647
+ icon: import_lucide_react48.ArrowUp,
32844
33648
  onClick: () => runAtActiveCell((chain) => chain.addRowBefore())
32845
33649
  },
32846
33650
  {
32847
33651
  label: t("tableMenu.addRowAfter"),
32848
- icon: import_lucide_react46.ArrowDown,
33652
+ icon: import_lucide_react48.ArrowDown,
32849
33653
  onClick: () => runAtActiveCell((chain) => chain.addRowAfter())
32850
33654
  },
32851
33655
  {
32852
33656
  label: t("tableMenu.toggleHeaderRow"),
32853
- icon: import_lucide_react46.Table,
33657
+ icon: import_lucide_react48.Table,
32854
33658
  onClick: () => runAtActiveCell((chain) => chain.toggleHeaderRow())
32855
33659
  },
32856
33660
  {
32857
33661
  label: t("tableMenu.toggleHeaderColumn"),
32858
- icon: import_lucide_react46.Table,
33662
+ icon: import_lucide_react48.Table,
32859
33663
  onClick: () => runAtActiveCell((chain) => chain.toggleHeaderColumn())
32860
33664
  },
32861
33665
  {
32862
33666
  label: t("tableMenu.deleteColumn"),
32863
- icon: import_lucide_react46.Trash2,
33667
+ icon: import_lucide_react48.Trash2,
32864
33668
  onClick: () => runAtActiveCell((chain) => chain.deleteColumn()),
32865
33669
  destructive: true
32866
33670
  },
32867
33671
  {
32868
33672
  label: t("tableMenu.deleteRow"),
32869
- icon: import_lucide_react46.Trash2,
33673
+ icon: import_lucide_react48.Trash2,
32870
33674
  onClick: () => runAtActiveCell((chain) => chain.deleteRow()),
32871
33675
  destructive: true
32872
33676
  },
32873
33677
  {
32874
33678
  label: t("tableMenu.deleteTable"),
32875
- icon: import_lucide_react46.Trash2,
33679
+ icon: import_lucide_react48.Trash2,
32876
33680
  onClick: () => runAtActiveCell((chain) => chain.deleteTable()),
32877
33681
  destructive: true
32878
33682
  }
@@ -32881,27 +33685,27 @@ function TableControls({ editor, containerRef }) {
32881
33685
  const getRowHandleMenuItems = import_react53.default.useCallback((rowHandle) => [
32882
33686
  {
32883
33687
  label: t("tableMenu.addRowBefore"),
32884
- icon: import_lucide_react46.ArrowUp,
33688
+ icon: import_lucide_react48.ArrowUp,
32885
33689
  onClick: () => runAtCellPos(rowHandle.cellPos, (chain) => chain.addRowBefore())
32886
33690
  },
32887
33691
  {
32888
33692
  label: t("tableMenu.addRowAfter"),
32889
- icon: import_lucide_react46.ArrowDown,
33693
+ icon: import_lucide_react48.ArrowDown,
32890
33694
  onClick: () => runAtCellPos(rowHandle.cellPos, (chain) => chain.addRowAfter())
32891
33695
  },
32892
33696
  {
32893
33697
  label: t("tableMenu.duplicateRow"),
32894
- icon: import_lucide_react46.Copy,
33698
+ icon: import_lucide_react48.Copy,
32895
33699
  onClick: () => duplicateRowAt(rowHandle.index, rowHandle.cellPos)
32896
33700
  },
32897
33701
  {
32898
33702
  label: t("tableMenu.clearRowContents"),
32899
- icon: import_lucide_react46.Table,
33703
+ icon: import_lucide_react48.Table,
32900
33704
  onClick: () => clearRowAt(rowHandle.index, rowHandle.cellPos)
32901
33705
  },
32902
33706
  {
32903
33707
  label: t("tableMenu.deleteRow"),
32904
- icon: import_lucide_react46.Trash2,
33708
+ icon: import_lucide_react48.Trash2,
32905
33709
  onClick: () => runAtCellPos(rowHandle.cellPos, (chain) => chain.deleteRow()),
32906
33710
  destructive: true
32907
33711
  }
@@ -32909,27 +33713,27 @@ function TableControls({ editor, containerRef }) {
32909
33713
  const getColumnHandleMenuItems = import_react53.default.useCallback((columnHandle) => [
32910
33714
  {
32911
33715
  label: t("tableMenu.addColumnBefore"),
32912
- icon: import_lucide_react46.ArrowLeft,
33716
+ icon: import_lucide_react48.ArrowLeft,
32913
33717
  onClick: () => runAtCellPos(columnHandle.cellPos, (chain) => chain.addColumnBefore())
32914
33718
  },
32915
33719
  {
32916
33720
  label: t("tableMenu.addColumnAfter"),
32917
- icon: import_lucide_react46.ArrowRight,
33721
+ icon: import_lucide_react48.ArrowRight,
32918
33722
  onClick: () => runAtCellPos(columnHandle.cellPos, (chain) => chain.addColumnAfter())
32919
33723
  },
32920
33724
  {
32921
33725
  label: t("tableMenu.duplicateColumn"),
32922
- icon: import_lucide_react46.Copy,
33726
+ icon: import_lucide_react48.Copy,
32923
33727
  onClick: () => duplicateColumnAt(columnHandle.index, columnHandle.cellPos)
32924
33728
  },
32925
33729
  {
32926
33730
  label: t("tableMenu.clearColumnContents"),
32927
- icon: import_lucide_react46.Table,
33731
+ icon: import_lucide_react48.Table,
32928
33732
  onClick: () => clearColumnAt(columnHandle.index, columnHandle.cellPos)
32929
33733
  },
32930
33734
  {
32931
33735
  label: t("tableMenu.deleteColumn"),
32932
- icon: import_lucide_react46.Trash2,
33736
+ icon: import_lucide_react48.Trash2,
32933
33737
  onClick: () => runAtCellPos(columnHandle.cellPos, (chain) => chain.deleteColumn()),
32934
33738
  destructive: true
32935
33739
  }
@@ -32941,373 +33745,77 @@ function TableControls({ editor, containerRef }) {
32941
33745
  const menuLeft = Math.max(8, layout.tableLeft);
32942
33746
  const rowHandleLeft = layout.tableLeft - 12;
32943
33747
  const columnHandleTop = layout.tableTop - 12;
32944
- const visibleTableWidth = Math.min(layout.tableWidth, layout.viewportWidth);
32945
- const visibleTableHeight = Math.min(layout.tableHeight, layout.viewportHeight);
32946
- const columnRailTop = layout.tableTop;
32947
- const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
32948
- const rowRailTop = layout.tableTop + visibleTableHeight + ADD_ROW_RAIL_GAP;
32949
- const rowRailLeft = layout.tableLeft;
32950
- const expandPreviewWidth = dragPreview?.kind === "add-column" ? layout.tableWidth + dragPreview.previewCols * layout.avgColumnWidth : layout.tableWidth;
32951
- const expandPreviewHeight = dragPreview?.kind === "add-row" ? layout.tableHeight + dragPreview.previewRows * layout.avgRowHeight : layout.tableHeight;
32952
- const dragStatusText = dragPreview?.kind === "row" ? `${t("tableMenu.dragRow")} ${dragPreview.originIndex + 1} -> ${dragPreview.targetIndex + 1}` : dragPreview?.kind === "column" ? `${t("tableMenu.dragColumn")} ${dragPreview.originIndex + 1} -> ${dragPreview.targetIndex + 1}` : dragPreview?.kind === "add-row" ? `+${dragPreview.previewRows}R` : dragPreview?.kind === "add-column" ? `+${dragPreview.previewCols}C` : null;
32953
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
32954
- layout.rowHandles.map((rowHandle) => {
32955
- const menuKey = getRowMenuKey(rowHandle.index);
32956
- const isActive = rowHandle.index === layout.activeRowIndex;
32957
- const visible = controlsVisible || hoverState.rowHandleIndex === rowHandle.index || openMenuKey === menuKey;
32958
- const isShown = visible || isActive;
32959
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32960
- "div",
32961
- {
32962
- className: "absolute z-30",
32963
- "data-row-handle-index": rowHandle.index,
32964
- style: {
32965
- top: Math.max(8, rowHandle.center - 12),
32966
- left: rowHandleLeft
32967
- },
32968
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32969
- Tooltip,
32970
- {
32971
- placement: "right",
32972
- disabled: openMenuKey === menuKey || !visible && isActive,
32973
- content: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-xs font-medium", children: `${t("tableMenu.dragRow")} ${rowHandle.index + 1}` }),
32974
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32975
- DropdownMenu,
32976
- {
32977
- placement: "right",
32978
- isOpen: openMenuKey === menuKey,
32979
- onOpenChange: (open) => {
32980
- setOpenMenuKey((prev) => open ? menuKey : prev === menuKey ? null : prev);
32981
- },
32982
- contentClassName: "p-2",
32983
- items: getRowHandleMenuItems(rowHandle),
32984
- trigger: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
32985
- "button",
32986
- {
32987
- type: "button",
32988
- "aria-label": `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
32989
- onMouseDown: (event) => {
32990
- event.preventDefault();
32991
- event.stopPropagation();
32992
- setOpenMenuKey(null);
32993
- dragStateRef.current = {
32994
- kind: "row",
32995
- originIndex: rowHandle.index,
32996
- targetIndex: rowHandle.index,
32997
- anchorPos: rowHandle.cellPos
32998
- };
32999
- setDragPreview({
33000
- kind: "row",
33001
- originIndex: rowHandle.index,
33002
- targetIndex: rowHandle.index,
33003
- targetStart: rowHandle.start,
33004
- targetSize: rowHandle.size
33005
- });
33006
- document.body.style.cursor = "grabbing";
33007
- },
33008
- className: cn(
33009
- "inline-flex h-6 w-6 items-center justify-center rounded-full transition-[opacity,transform,colors,border,background-color] duration-150",
33010
- visible ? "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur hover:bg-accent hover:text-foreground cursor-grab active:cursor-grabbing" : "border-transparent bg-transparent cursor-pointer"
33011
- ),
33012
- style: {
33013
- opacity: isShown ? 1 : 0,
33014
- transform: isShown ? "scale(1)" : `scale(${IDLE_HANDLE_SCALE})`,
33015
- pointerEvents: isShown ? "auto" : "none"
33016
- },
33017
- children: visible ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(import_lucide_react46.GripVertical, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "h-3 w-1 rounded-full bg-muted-foreground/50 hover:bg-muted-foreground" })
33018
- }
33019
- )
33020
- }
33021
- ) })
33022
- }
33023
- )
33024
- },
33025
- `row-handle-${rowHandle.index}`
33026
- );
33027
- }),
33028
- layout.columnHandles.map((columnHandle) => {
33029
- const menuKey = getColumnMenuKey(columnHandle.index);
33030
- const isActive = columnHandle.index === layout.activeColumnIndex;
33031
- const visible = controlsVisible || hoverState.columnHandleIndex === columnHandle.index || openMenuKey === menuKey;
33032
- const isShown = visible || isActive;
33033
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33034
- "div",
33035
- {
33036
- className: "absolute z-30",
33037
- "data-column-handle-index": columnHandle.index,
33038
- style: {
33039
- top: columnHandleTop,
33040
- left: Math.max(8, columnHandle.center - 12)
33041
- },
33042
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33043
- Tooltip,
33044
- {
33045
- placement: "top",
33046
- disabled: openMenuKey === menuKey || !visible && isActive,
33047
- content: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-xs font-medium", children: `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}` }),
33048
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33049
- DropdownMenu,
33050
- {
33051
- placement: "bottom-start",
33052
- isOpen: openMenuKey === menuKey,
33053
- onOpenChange: (open) => {
33054
- setOpenMenuKey((prev) => open ? menuKey : prev === menuKey ? null : prev);
33055
- },
33056
- contentClassName: "p-2",
33057
- items: getColumnHandleMenuItems(columnHandle),
33058
- trigger: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33059
- "button",
33060
- {
33061
- type: "button",
33062
- "aria-label": `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
33063
- onMouseDown: (event) => {
33064
- event.preventDefault();
33065
- event.stopPropagation();
33066
- setOpenMenuKey(null);
33067
- dragStateRef.current = {
33068
- kind: "column",
33069
- originIndex: columnHandle.index,
33070
- targetIndex: columnHandle.index,
33071
- anchorPos: columnHandle.cellPos
33072
- };
33073
- setDragPreview({
33074
- kind: "column",
33075
- originIndex: columnHandle.index,
33076
- targetIndex: columnHandle.index,
33077
- targetStart: columnHandle.start,
33078
- targetSize: columnHandle.size
33079
- });
33080
- document.body.style.cursor = "grabbing";
33081
- },
33082
- className: cn(
33083
- "inline-flex h-6 w-6 items-center justify-center rounded-full transition-[opacity,transform,colors,border,background-color] duration-150",
33084
- visible ? "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur hover:bg-accent hover:text-foreground cursor-grab active:cursor-grabbing" : "border-transparent bg-transparent cursor-pointer"
33085
- ),
33086
- style: {
33087
- opacity: isShown ? 1 : 0,
33088
- transform: isShown ? "scale(1)" : `scale(${IDLE_HANDLE_SCALE})`,
33089
- pointerEvents: isShown ? "auto" : "none"
33090
- },
33091
- children: visible ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(import_lucide_react46.GripHorizontal, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "h-1 w-3 rounded-full bg-muted-foreground/50 hover:bg-muted-foreground" })
33092
- }
33093
- )
33094
- }
33095
- ) })
33096
- }
33097
- )
33098
- },
33099
- `column-handle-${columnHandle.index}`
33100
- );
33101
- }),
33102
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33103
- "div",
33748
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(import_jsx_runtime88.Fragment, { children: [
33749
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
33750
+ TableRowHandles,
33104
33751
  {
33105
- className: "absolute z-30",
33106
- "data-table-control": "table-menu",
33107
- style: {
33108
- top: menuTop,
33109
- left: menuLeft
33752
+ activeRowIndex: layout.activeRowIndex,
33753
+ controlsVisible,
33754
+ getMenuItems: getRowHandleMenuItems,
33755
+ hoverRowHandleIndex: hoverState.rowHandleIndex,
33756
+ onOpenMenuChange: (menuKey, open) => {
33757
+ setOpenMenuKey((prev) => open ? menuKey : prev === menuKey ? null : prev);
33110
33758
  },
33111
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33112
- Tooltip,
33113
- {
33114
- placement: "top",
33115
- disabled: tableMenuOpen,
33116
- content: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-xs font-medium", children: t("tableMenu.openControls") }),
33117
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33118
- DropdownMenu,
33119
- {
33120
- placement: "bottom-start",
33121
- isOpen: tableMenuOpen,
33122
- onOpenChange: (open) => {
33123
- setOpenMenuKey((prev) => open ? "table" : prev === "table" ? null : prev);
33124
- },
33125
- contentClassName: "p-2",
33126
- items: menuItems,
33127
- trigger: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33128
- "button",
33129
- {
33130
- type: "button",
33131
- "aria-label": t("tableMenu.openControls"),
33132
- onMouseDown: (event) => event.preventDefault(),
33133
- className: cn(
33134
- "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-full",
33135
- "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
33136
- "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
33137
- ),
33138
- style: {
33139
- opacity: controlsVisible || hoverState.menuVisible || tableMenuOpen ? 1 : 0,
33140
- transform: controlsVisible || hoverState.menuVisible || tableMenuOpen ? "scale(1)" : "scale(0.82)",
33141
- pointerEvents: controlsVisible || hoverState.menuVisible || tableMenuOpen ? "auto" : "none"
33142
- },
33143
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(import_lucide_react46.MoreHorizontal, { className: "h-4 w-4" })
33144
- }
33145
- )
33146
- }
33147
- ) })
33148
- }
33149
- )
33759
+ onStartDrag: startRowDrag,
33760
+ openMenuKey,
33761
+ rowDragLabel: t("tableMenu.dragRow"),
33762
+ rowHandleLeft,
33763
+ rowHandles: layout.rowHandles
33150
33764
  }
33151
33765
  ),
33152
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33153
- Tooltip,
33766
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
33767
+ TableColumnHandles,
33154
33768
  {
33155
- placement: "right",
33156
- content: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-xs font-medium", children: t("tableMenu.quickAddColumnAfter") }),
33157
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33158
- "button",
33159
- {
33160
- type: "button",
33161
- "data-table-control": "add-column",
33162
- "aria-label": t("tableMenu.quickAddColumnAfter"),
33163
- onMouseDown: (event) => {
33164
- event.preventDefault();
33165
- event.stopPropagation();
33166
- setOpenMenuKey(null);
33167
- if (!canExpandTable) return;
33168
- dragStateRef.current = { kind: "add-column", previewCols: 1 };
33169
- setDragPreview({ kind: "add-column", previewCols: 1 });
33170
- document.body.style.cursor = "ew-resize";
33171
- },
33172
- disabled: !canExpandTable,
33173
- className: cn(
33174
- "absolute z-30 inline-flex items-center justify-center rounded-md",
33175
- "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
33176
- "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
33177
- ),
33178
- style: {
33179
- top: controlsVisible || hoverState.addColumnVisible ? columnRailTop : columnRailTop + Math.max(0, visibleTableHeight / 2 - 24),
33180
- left: columnRailLeft,
33181
- width: controlsVisible || hoverState.addColumnVisible ? 18 : 12,
33182
- height: controlsVisible || hoverState.addColumnVisible ? visibleTableHeight : 48,
33183
- opacity: controlsVisible || hoverState.addColumnVisible ? 1 : 0,
33184
- transform: controlsVisible || hoverState.addColumnVisible ? "scale(1)" : "scale(0.92)",
33185
- pointerEvents: controlsVisible || hoverState.addColumnVisible ? "auto" : "none"
33186
- },
33187
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-sm font-medium leading-none", children: "+" })
33188
- }
33189
- )
33769
+ activeColumnIndex: layout.activeColumnIndex,
33770
+ columnDragLabel: t("tableMenu.dragColumn"),
33771
+ columnHandleTop,
33772
+ columnHandles: layout.columnHandles,
33773
+ controlsVisible,
33774
+ getMenuItems: getColumnHandleMenuItems,
33775
+ hoverColumnHandleIndex: hoverState.columnHandleIndex,
33776
+ onOpenMenuChange: (menuKey, open) => {
33777
+ setOpenMenuKey((prev) => open ? menuKey : prev === menuKey ? null : prev);
33778
+ },
33779
+ onStartDrag: startColumnDrag,
33780
+ openMenuKey
33190
33781
  }
33191
33782
  ),
33192
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33193
- Tooltip,
33783
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
33784
+ TableControlMenu,
33194
33785
  {
33195
- placement: "bottom",
33196
- content: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-xs font-medium", children: t("tableMenu.quickAddRowAfter") }),
33197
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33198
- "button",
33199
- {
33200
- type: "button",
33201
- "data-table-control": "add-row",
33202
- "aria-label": t("tableMenu.quickAddRowAfter"),
33203
- onMouseDown: (event) => {
33204
- event.preventDefault();
33205
- event.stopPropagation();
33206
- setOpenMenuKey(null);
33207
- if (!canExpandTable) return;
33208
- dragStateRef.current = { kind: "add-row", previewRows: 1 };
33209
- setDragPreview({ kind: "add-row", previewRows: 1 });
33210
- document.body.style.cursor = "ns-resize";
33211
- },
33212
- disabled: !canExpandTable,
33213
- className: cn(
33214
- "absolute z-30 inline-flex items-center justify-center rounded-md",
33215
- "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
33216
- "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
33217
- ),
33218
- style: {
33219
- top: rowRailTop,
33220
- left: controlsVisible || hoverState.addRowVisible ? rowRailLeft : rowRailLeft + Math.max(0, visibleTableWidth / 2 - 24),
33221
- width: controlsVisible || hoverState.addRowVisible ? visibleTableWidth : 48,
33222
- height: controlsVisible || hoverState.addRowVisible ? 16 : 12,
33223
- opacity: controlsVisible || hoverState.addRowVisible ? 1 : 0,
33224
- transform: controlsVisible || hoverState.addRowVisible ? "scale(1)" : "scale(0.92)",
33225
- pointerEvents: controlsVisible || hoverState.addRowVisible ? "auto" : "none"
33226
- },
33227
- children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-sm font-medium leading-none", children: "+" })
33228
- }
33229
- )
33786
+ controlsVisible,
33787
+ isOpen: tableMenuOpen,
33788
+ items: menuItems,
33789
+ label: t("tableMenu.openControls"),
33790
+ left: menuLeft,
33791
+ menuVisible: hoverState.menuVisible,
33792
+ onOpenChange: (open) => {
33793
+ setOpenMenuKey((prev) => open ? "table" : prev === "table" ? null : prev);
33794
+ },
33795
+ top: menuTop
33230
33796
  }
33231
33797
  ),
33232
- dragPreview?.kind === "row" && /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
33233
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33234
- "div",
33235
- {
33236
- "aria-hidden": "true",
33237
- className: "pointer-events-none absolute z-20 rounded-lg border border-primary/20 bg-primary/10",
33238
- style: {
33239
- top: dragPreview.targetStart,
33240
- left: layout.tableLeft,
33241
- width: layout.tableWidth,
33242
- height: dragPreview.targetSize
33243
- }
33244
- }
33245
- ),
33246
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33247
- "div",
33248
- {
33249
- "aria-hidden": "true",
33250
- className: "pointer-events-none absolute z-20 rounded-full bg-primary/80",
33251
- style: {
33252
- top: dragPreview.targetStart + dragPreview.targetSize / 2 - 1,
33253
- left: layout.tableLeft,
33254
- width: layout.tableWidth,
33255
- height: 2
33256
- }
33257
- }
33258
- )
33259
- ] }),
33260
- dragPreview?.kind === "column" && /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
33261
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33262
- "div",
33263
- {
33264
- "aria-hidden": "true",
33265
- className: "pointer-events-none absolute z-20 rounded-lg border border-primary/20 bg-primary/10",
33266
- style: {
33267
- top: layout.tableTop,
33268
- left: dragPreview.targetStart,
33269
- width: dragPreview.targetSize,
33270
- height: layout.tableHeight
33271
- }
33272
- }
33273
- ),
33274
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33275
- "div",
33276
- {
33277
- "aria-hidden": "true",
33278
- className: "pointer-events-none absolute z-20 rounded-full bg-primary/80",
33279
- style: {
33280
- top: layout.tableTop,
33281
- left: dragPreview.targetStart + dragPreview.targetSize / 2 - 1,
33282
- width: 2,
33283
- height: layout.tableHeight
33284
- }
33285
- }
33286
- )
33287
- ] }),
33288
- (dragPreview?.kind === "add-row" || dragPreview?.kind === "add-column") && /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(import_jsx_runtime84.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33289
- "div",
33798
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
33799
+ TableAddRails,
33290
33800
  {
33291
- "aria-hidden": "true",
33292
- className: "pointer-events-none absolute z-20 rounded-xl border border-dashed border-primary/70 bg-primary/5",
33293
- style: {
33294
- top: layout.tableTop,
33295
- left: layout.tableLeft,
33296
- width: expandPreviewWidth,
33297
- height: expandPreviewHeight
33298
- }
33801
+ addColumnVisible: hoverState.addColumnVisible,
33802
+ addRowVisible: hoverState.addRowVisible,
33803
+ canExpandTable,
33804
+ controlsVisible,
33805
+ layout,
33806
+ onStartAddColumn: startAddColumnDrag,
33807
+ onStartAddRow: startAddRowDrag,
33808
+ quickAddColumnLabel: t("tableMenu.quickAddColumnAfter"),
33809
+ quickAddRowLabel: t("tableMenu.quickAddRowAfter")
33299
33810
  }
33300
- ) }),
33301
- dragStatusText && /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
33302
- "div",
33811
+ ),
33812
+ /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
33813
+ TableDragPreview,
33303
33814
  {
33304
- role: "status",
33305
- className: "pointer-events-none absolute z-30 rounded-full border border-primary/20 bg-background/95 px-2 py-1 text-[11px] font-medium text-foreground shadow-sm backdrop-blur",
33306
- style: {
33307
- top: dragPreview?.kind === "add-row" || dragPreview?.kind === "add-column" ? layout.tableTop + expandPreviewHeight + 8 : layout.tableTop - 40,
33308
- left: dragPreview?.kind === "add-row" || dragPreview?.kind === "add-column" ? layout.tableLeft + Math.max(0, expandPreviewWidth - 84) : layout.tableLeft + Math.max(0, layout.tableWidth - 108)
33309
- },
33310
- children: dragStatusText
33815
+ columnDragLabel: t("tableMenu.dragColumn"),
33816
+ dragPreview,
33817
+ layout,
33818
+ rowDragLabel: t("tableMenu.dragRow")
33311
33819
  }
33312
33820
  )
33313
33821
  ] });
@@ -33906,7 +34414,7 @@ function useUEditorTableInteractions(editor, editable = true) {
33906
34414
  }
33907
34415
 
33908
34416
  // src/components/UEditor/UEditor.tsx
33909
- var import_jsx_runtime85 = require("react/jsx-runtime");
34417
+ var import_jsx_runtime89 = require("react/jsx-runtime");
33910
34418
  var UEditor = import_react56.default.forwardRef(({
33911
34419
  content = "",
33912
34420
  onChange,
@@ -34003,6 +34511,7 @@ var UEditor = import_react56.default.forwardRef(({
34003
34511
  (0, import_react56.useImperativeHandle)(
34004
34512
  ref,
34005
34513
  () => ({
34514
+ editor,
34006
34515
  prepareContentForSave: async ({ throwOnError = false } = {}) => {
34007
34516
  if (!inFlightPrepareRef.current) {
34008
34517
  const htmlSnapshot = editor?.getHTML() ?? content ?? "";
@@ -34033,7 +34542,7 @@ var UEditor = import_react56.default.forwardRef(({
34033
34542
  }
34034
34543
  }, [content, editor]);
34035
34544
  if (!editor) {
34036
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
34545
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
34037
34546
  "div",
34038
34547
  {
34039
34548
  className: cn("w-full rounded-lg border bg-background flex items-center justify-center text-muted-foreground", className),
@@ -34042,7 +34551,7 @@ var UEditor = import_react56.default.forwardRef(({
34042
34551
  }
34043
34552
  );
34044
34553
  }
34045
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
34554
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
34046
34555
  "div",
34047
34556
  {
34048
34557
  className: cn(
@@ -34057,7 +34566,7 @@ var UEditor = import_react56.default.forwardRef(({
34057
34566
  className
34058
34567
  ),
34059
34568
  children: [
34060
- editable && showToolbar && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
34569
+ editable && showToolbar && /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
34061
34570
  EditorToolbar,
34062
34571
  {
34063
34572
  editor,
@@ -34072,7 +34581,7 @@ var UEditor = import_react56.default.forwardRef(({
34072
34581
  letterSpacings
34073
34582
  }
34074
34583
  ),
34075
- editable && showBubbleMenu && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
34584
+ editable && showBubbleMenu && /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
34076
34585
  CustomBubbleMenu,
34077
34586
  {
34078
34587
  editor,
@@ -34080,8 +34589,8 @@ var UEditor = import_react56.default.forwardRef(({
34080
34589
  lineHeights
34081
34590
  }
34082
34591
  ),
34083
- editable && showFloatingMenu && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(CustomFloatingMenu, { editor }),
34084
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
34592
+ editable && showFloatingMenu && /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(CustomFloatingMenu, { editor }),
34593
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
34085
34594
  "div",
34086
34595
  {
34087
34596
  ref: editorContentRef,
@@ -34091,7 +34600,7 @@ var UEditor = import_react56.default.forwardRef(({
34091
34600
  maxHeight
34092
34601
  },
34093
34602
  children: [
34094
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
34603
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
34095
34604
  "span",
34096
34605
  {
34097
34606
  ref: tableColumnGuideRef,
@@ -34099,7 +34608,7 @@ var UEditor = import_react56.default.forwardRef(({
34099
34608
  className: "pointer-events-none absolute z-20 bg-primary opacity-0 transition-opacity duration-100"
34100
34609
  }
34101
34610
  ),
34102
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
34611
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
34103
34612
  "span",
34104
34613
  {
34105
34614
  ref: tableRowGuideRef,
@@ -34107,7 +34616,7 @@ var UEditor = import_react56.default.forwardRef(({
34107
34616
  className: "pointer-events-none absolute z-20 bg-primary opacity-0 transition-opacity duration-100"
34108
34617
  }
34109
34618
  ),
34110
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
34619
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
34111
34620
  "span",
34112
34621
  {
34113
34622
  ref: activeTableCellHighlightRef,
@@ -34116,8 +34625,8 @@ var UEditor = import_react56.default.forwardRef(({
34116
34625
  className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10 transition-[left,top,width,height] duration-100"
34117
34626
  }
34118
34627
  ),
34119
- editable && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(TableControls, { editor, containerRef: editorContentRef }),
34120
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
34628
+ editable && /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(TableControls, { editor, containerRef: editorContentRef }),
34629
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
34121
34630
  import_react57.EditorContent,
34122
34631
  {
34123
34632
  editor,
@@ -34127,7 +34636,7 @@ var UEditor = import_react56.default.forwardRef(({
34127
34636
  ]
34128
34637
  }
34129
34638
  ),
34130
- showCharacterCount && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(CharacterCountDisplay, { editor, maxCharacters })
34639
+ showCharacterCount && /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(CharacterCountDisplay, { editor, maxCharacters })
34131
34640
  ]
34132
34641
  }
34133
34642
  );