@underverse-ui/underverse 1.0.71 → 1.0.72

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
@@ -29039,6 +29039,19 @@ var import_lucide_react47 = require("lucide-react");
29039
29039
  var import_jsx_runtime82 = require("react/jsx-runtime");
29040
29040
  var FALLBACK_TABLE_ROW_HEIGHT = 44;
29041
29041
  var FALLBACK_TABLE_COLUMN_WIDTH = 160;
29042
+ var MENU_HOVER_PADDING = 18;
29043
+ var ROW_HANDLE_HOVER_WIDTH = 28;
29044
+ var COLUMN_HANDLE_HOVER_HEIGHT = 28;
29045
+ var ADD_COLUMN_HOVER_WIDTH = 24;
29046
+ var ADD_ROW_HOVER_HEIGHT = 24;
29047
+ var HANDLE_HOVER_RADIUS = 14;
29048
+ var DEFAULT_HOVER_STATE = {
29049
+ menuVisible: false,
29050
+ addColumnVisible: false,
29051
+ addRowVisible: false,
29052
+ rowHandleIndex: null,
29053
+ columnHandleIndex: null
29054
+ };
29042
29055
  function resolveElement(target) {
29043
29056
  if (target instanceof Element) return target;
29044
29057
  if (target instanceof Node) return target.parentElement;
@@ -29164,6 +29177,12 @@ function buildLayout(editor, surface, cell) {
29164
29177
  };
29165
29178
  }
29166
29179
  function getSelectedCell(editor) {
29180
+ const browserSelection = window.getSelection();
29181
+ const anchorElement = resolveElement(browserSelection?.anchorNode ?? null);
29182
+ const anchorCell = anchorElement?.closest?.("th,td");
29183
+ if (anchorCell instanceof HTMLTableCellElement) {
29184
+ return anchorCell;
29185
+ }
29167
29186
  const domAtPos = editor.view.domAtPos(editor.state.selection.from);
29168
29187
  return getCellFromTarget(domAtPos.node);
29169
29188
  }
@@ -29192,6 +29211,7 @@ function TableControls({ editor, containerRef }) {
29192
29211
  const t = useSmartTranslations("UEditor");
29193
29212
  const [layout, setLayout] = import_react52.default.useState(null);
29194
29213
  const [dragPreview, setDragPreview] = import_react52.default.useState(null);
29214
+ const [hoverState, setHoverState] = import_react52.default.useState(DEFAULT_HOVER_STATE);
29195
29215
  const layoutRef = import_react52.default.useRef(null);
29196
29216
  const dragStateRef = import_react52.default.useRef(null);
29197
29217
  import_react52.default.useEffect(() => {
@@ -29223,17 +29243,50 @@ function TableControls({ editor, containerRef }) {
29223
29243
  setDragPreview(null);
29224
29244
  document.body.style.cursor = "";
29225
29245
  }, []);
29246
+ const updateHoverState = import_react52.default.useCallback((event) => {
29247
+ const activeLayout = layoutRef.current;
29248
+ const surface = containerRef.current;
29249
+ if (!activeLayout || !surface || dragStateRef.current) {
29250
+ setHoverState(DEFAULT_HOVER_STATE);
29251
+ return;
29252
+ }
29253
+ const surfaceRect = surface.getBoundingClientRect();
29254
+ const relativeX = event.clientX - surfaceRect.left + surface.scrollLeft;
29255
+ const relativeY = event.clientY - surfaceRect.top + surface.scrollTop;
29256
+ const rowHandleIndex = activeLayout.rowHandles.find((rowHandle) => relativeX >= activeLayout.tableLeft - ROW_HANDLE_HOVER_WIDTH && relativeX <= activeLayout.tableLeft && Math.abs(relativeY - rowHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
29257
+ const columnHandleIndex = activeLayout.columnHandles.find((columnHandle) => relativeY >= activeLayout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= activeLayout.tableTop && Math.abs(relativeX - columnHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
29258
+ const menuVisible = relativeX >= activeLayout.tableLeft - MENU_HOVER_PADDING && relativeX <= activeLayout.tableLeft + 42 && relativeY >= activeLayout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= activeLayout.tableTop + MENU_HOVER_PADDING;
29259
+ const addColumnVisible = relativeX >= activeLayout.tableLeft + activeLayout.tableWidth && relativeX <= activeLayout.tableLeft + activeLayout.tableWidth + ADD_COLUMN_HOVER_WIDTH && relativeY >= activeLayout.tableTop && relativeY <= activeLayout.tableTop + activeLayout.tableHeight;
29260
+ const addRowVisible = relativeY >= activeLayout.tableTop + activeLayout.tableHeight && relativeY <= activeLayout.tableTop + activeLayout.tableHeight + ADD_ROW_HOVER_HEIGHT && relativeX >= activeLayout.tableLeft && relativeX <= activeLayout.tableLeft + activeLayout.tableWidth;
29261
+ setHoverState((prev) => {
29262
+ if (prev.menuVisible === menuVisible && prev.addColumnVisible === addColumnVisible && prev.addRowVisible === addRowVisible && prev.rowHandleIndex === rowHandleIndex && prev.columnHandleIndex === columnHandleIndex) {
29263
+ return prev;
29264
+ }
29265
+ return {
29266
+ menuVisible,
29267
+ addColumnVisible,
29268
+ addRowVisible,
29269
+ rowHandleIndex,
29270
+ columnHandleIndex
29271
+ };
29272
+ });
29273
+ }, [containerRef]);
29226
29274
  import_react52.default.useEffect(() => {
29227
29275
  const proseMirror = editor.view.dom;
29228
29276
  const surface = containerRef.current;
29229
29277
  if (!surface) return void 0;
29230
29278
  const handleMouseOver = (event) => {
29231
29279
  if (dragStateRef.current) return;
29232
- syncFromCell(getCellFromTarget(event.target));
29280
+ const cell = getCellFromTarget(event.target);
29281
+ if (!cell) return;
29282
+ syncFromCell(cell);
29283
+ };
29284
+ const handleSurfaceMouseMove = (event) => {
29285
+ updateHoverState(event);
29233
29286
  };
29234
29287
  const handleMouseLeave = () => {
29235
29288
  if (dragStateRef.current) return;
29236
- syncFromSelection();
29289
+ setHoverState(DEFAULT_HOVER_STATE);
29237
29290
  };
29238
29291
  const handleFocusIn = () => {
29239
29292
  if (dragStateRef.current) return;
@@ -29242,6 +29295,7 @@ function TableControls({ editor, containerRef }) {
29242
29295
  proseMirror.addEventListener("mouseover", handleMouseOver);
29243
29296
  proseMirror.addEventListener("mouseleave", handleMouseLeave);
29244
29297
  proseMirror.addEventListener("focusin", handleFocusIn);
29298
+ surface.addEventListener("mousemove", handleSurfaceMouseMove);
29245
29299
  surface.addEventListener("scroll", refreshCurrentLayout, { passive: true });
29246
29300
  window.addEventListener("resize", refreshCurrentLayout);
29247
29301
  editor.on("selectionUpdate", syncFromSelection);
@@ -29251,12 +29305,13 @@ function TableControls({ editor, containerRef }) {
29251
29305
  proseMirror.removeEventListener("mouseover", handleMouseOver);
29252
29306
  proseMirror.removeEventListener("mouseleave", handleMouseLeave);
29253
29307
  proseMirror.removeEventListener("focusin", handleFocusIn);
29308
+ surface.removeEventListener("mousemove", handleSurfaceMouseMove);
29254
29309
  surface.removeEventListener("scroll", refreshCurrentLayout);
29255
29310
  window.removeEventListener("resize", refreshCurrentLayout);
29256
29311
  editor.off("selectionUpdate", syncFromSelection);
29257
29312
  editor.off("update", refreshCurrentLayout);
29258
29313
  };
29259
- }, [clearDrag, containerRef, editor, refreshCurrentLayout, syncFromCell, syncFromSelection]);
29314
+ }, [clearDrag, containerRef, editor, refreshCurrentLayout, syncFromCell, syncFromSelection, updateHoverState]);
29260
29315
  const runAtCellPos = import_react52.default.useCallback((cellPos, command, options) => {
29261
29316
  if (cellPos == null) return false;
29262
29317
  focusCell(editor, cellPos);
@@ -29346,6 +29401,7 @@ function TableControls({ editor, containerRef }) {
29346
29401
  return true;
29347
29402
  }, [runAtCornerCell, syncFromSelection]);
29348
29403
  const canExpandTable = Boolean(layout);
29404
+ const controlsVisible = dragPreview !== null;
29349
29405
  import_react52.default.useEffect(() => {
29350
29406
  const handleMouseMove = (event) => {
29351
29407
  const dragState = dragStateRef.current;
@@ -29557,107 +29613,147 @@ function TableControls({ editor, containerRef }) {
29557
29613
  const expandPreviewHeight = dragPreview?.kind === "add-row" ? layout.tableHeight + dragPreview.previewRows * layout.avgRowHeight : layout.tableHeight;
29558
29614
  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;
29559
29615
  return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(import_jsx_runtime82.Fragment, { children: [
29560
- layout.rowHandles.map((rowHandle) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "absolute z-30", style: { top: Math.max(8, rowHandle.center - 12), left: rowHandleLeft }, children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29561
- DropdownMenu,
29562
- {
29563
- placement: "right",
29564
- items: getRowHandleMenuItems(rowHandle),
29565
- trigger: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29566
- "button",
29567
- {
29568
- type: "button",
29569
- "aria-label": `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29570
- title: `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29571
- onMouseDown: (event) => {
29572
- event.preventDefault();
29573
- event.stopPropagation();
29574
- dragStateRef.current = {
29575
- kind: "row",
29576
- originIndex: rowHandle.index,
29577
- targetIndex: rowHandle.index,
29578
- anchorPos: rowHandle.cellPos
29579
- };
29580
- setDragPreview({
29581
- kind: "row",
29582
- originIndex: rowHandle.index,
29583
- targetIndex: rowHandle.index,
29584
- targetStart: rowHandle.start,
29585
- targetSize: rowHandle.size
29586
- });
29587
- document.body.style.cursor = "grabbing";
29588
- },
29589
- className: cn(
29590
- "inline-flex h-6 w-6 items-center justify-center rounded-full",
29591
- "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29592
- "transition-colors hover:bg-accent hover:text-foreground"
29593
- ),
29594
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react47.GripVertical, { className: "h-3.5 w-3.5" })
29595
- }
29596
- )
29597
- }
29598
- ) }, `row-handle-${rowHandle.index}`)),
29599
- layout.columnHandles.map((columnHandle) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "absolute z-30", style: { top: columnHandleTop, left: Math.max(8, columnHandle.center - 12) }, children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29600
- DropdownMenu,
29601
- {
29602
- placement: "bottom-start",
29603
- items: getColumnHandleMenuItems(columnHandle),
29604
- trigger: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29605
- "button",
29606
- {
29607
- type: "button",
29608
- "aria-label": `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29609
- title: `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29610
- onMouseDown: (event) => {
29611
- event.preventDefault();
29612
- event.stopPropagation();
29613
- dragStateRef.current = {
29614
- kind: "column",
29615
- originIndex: columnHandle.index,
29616
- targetIndex: columnHandle.index,
29617
- anchorPos: columnHandle.cellPos
29618
- };
29619
- setDragPreview({
29620
- kind: "column",
29621
- originIndex: columnHandle.index,
29622
- targetIndex: columnHandle.index,
29623
- targetStart: columnHandle.start,
29624
- targetSize: columnHandle.size
29625
- });
29626
- document.body.style.cursor = "grabbing";
29627
- },
29628
- className: cn(
29629
- "inline-flex h-6 w-6 items-center justify-center rounded-full",
29630
- "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29631
- "transition-colors hover:bg-accent hover:text-foreground"
29632
- ),
29633
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react47.GripHorizontal, { className: "h-3.5 w-3.5" })
29634
- }
29635
- )
29636
- }
29637
- ) }, `column-handle-${columnHandle.index}`)),
29638
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "pointer-events-none absolute z-30", style: { top: menuTop, left: menuLeft }, children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29639
- DropdownMenu,
29616
+ layout.rowHandles.map((rowHandle) => {
29617
+ const visible = controlsVisible || hoverState.rowHandleIndex === rowHandle.index;
29618
+ if (!visible) return null;
29619
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29620
+ "div",
29621
+ {
29622
+ className: "absolute z-30",
29623
+ style: {
29624
+ top: Math.max(8, rowHandle.center - 12),
29625
+ left: rowHandleLeft
29626
+ },
29627
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29628
+ DropdownMenu,
29629
+ {
29630
+ placement: "right",
29631
+ items: getRowHandleMenuItems(rowHandle),
29632
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29633
+ "button",
29634
+ {
29635
+ type: "button",
29636
+ "aria-label": `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29637
+ title: `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29638
+ onMouseDown: (event) => {
29639
+ event.preventDefault();
29640
+ event.stopPropagation();
29641
+ dragStateRef.current = {
29642
+ kind: "row",
29643
+ originIndex: rowHandle.index,
29644
+ targetIndex: rowHandle.index,
29645
+ anchorPos: rowHandle.cellPos
29646
+ };
29647
+ setDragPreview({
29648
+ kind: "row",
29649
+ originIndex: rowHandle.index,
29650
+ targetIndex: rowHandle.index,
29651
+ targetStart: rowHandle.start,
29652
+ targetSize: rowHandle.size
29653
+ });
29654
+ document.body.style.cursor = "grabbing";
29655
+ },
29656
+ className: cn(
29657
+ "inline-flex h-6 w-6 items-center justify-center rounded-full",
29658
+ "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29659
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29660
+ ),
29661
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react47.GripVertical, { className: "h-3.5 w-3.5" })
29662
+ }
29663
+ )
29664
+ }
29665
+ )
29666
+ },
29667
+ `row-handle-${rowHandle.index}`
29668
+ );
29669
+ }),
29670
+ layout.columnHandles.map((columnHandle) => {
29671
+ const visible = controlsVisible || hoverState.columnHandleIndex === columnHandle.index;
29672
+ if (!visible) return null;
29673
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29674
+ "div",
29675
+ {
29676
+ className: "absolute z-30",
29677
+ style: {
29678
+ top: columnHandleTop,
29679
+ left: Math.max(8, columnHandle.center - 12)
29680
+ },
29681
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29682
+ DropdownMenu,
29683
+ {
29684
+ placement: "bottom-start",
29685
+ items: getColumnHandleMenuItems(columnHandle),
29686
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29687
+ "button",
29688
+ {
29689
+ type: "button",
29690
+ "aria-label": `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29691
+ title: `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29692
+ onMouseDown: (event) => {
29693
+ event.preventDefault();
29694
+ event.stopPropagation();
29695
+ dragStateRef.current = {
29696
+ kind: "column",
29697
+ originIndex: columnHandle.index,
29698
+ targetIndex: columnHandle.index,
29699
+ anchorPos: columnHandle.cellPos
29700
+ };
29701
+ setDragPreview({
29702
+ kind: "column",
29703
+ originIndex: columnHandle.index,
29704
+ targetIndex: columnHandle.index,
29705
+ targetStart: columnHandle.start,
29706
+ targetSize: columnHandle.size
29707
+ });
29708
+ document.body.style.cursor = "grabbing";
29709
+ },
29710
+ className: cn(
29711
+ "inline-flex h-6 w-6 items-center justify-center rounded-full",
29712
+ "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29713
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29714
+ ),
29715
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react47.GripHorizontal, { className: "h-3.5 w-3.5" })
29716
+ }
29717
+ )
29718
+ }
29719
+ )
29720
+ },
29721
+ `column-handle-${columnHandle.index}`
29722
+ );
29723
+ }),
29724
+ (controlsVisible || hoverState.menuVisible) && /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29725
+ "div",
29640
29726
  {
29641
- placement: "bottom-start",
29642
- items: menuItems,
29643
- trigger: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29644
- "button",
29727
+ className: "absolute z-30",
29728
+ style: {
29729
+ top: menuTop,
29730
+ left: menuLeft
29731
+ },
29732
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29733
+ DropdownMenu,
29645
29734
  {
29646
- type: "button",
29647
- "aria-label": t("tableMenu.openControls"),
29648
- title: t("tableMenu.openControls"),
29649
- onMouseDown: (event) => event.preventDefault(),
29650
- className: cn(
29651
- "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-full",
29652
- "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29653
- "transition-colors hover:bg-accent hover:text-foreground"
29654
- ),
29655
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react47.MoreHorizontal, { className: "h-4 w-4" })
29735
+ placement: "bottom-start",
29736
+ items: menuItems,
29737
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29738
+ "button",
29739
+ {
29740
+ type: "button",
29741
+ "aria-label": t("tableMenu.openControls"),
29742
+ title: t("tableMenu.openControls"),
29743
+ onMouseDown: (event) => event.preventDefault(),
29744
+ className: cn(
29745
+ "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-full",
29746
+ "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29747
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29748
+ ),
29749
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react47.MoreHorizontal, { className: "h-4 w-4" })
29750
+ }
29751
+ )
29656
29752
  }
29657
29753
  )
29658
29754
  }
29659
- ) }),
29660
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29755
+ ),
29756
+ (controlsVisible || hoverState.addColumnVisible) && /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29661
29757
  "button",
29662
29758
  {
29663
29759
  type: "button",
@@ -29675,13 +29771,18 @@ function TableControls({ editor, containerRef }) {
29675
29771
  className: cn(
29676
29772
  "absolute z-30 inline-flex items-center justify-center rounded-md",
29677
29773
  "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
29678
- "transition-colors hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29774
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29679
29775
  ),
29680
- style: { top: columnRailTop, left: columnRailLeft, width: 18, height: layout.tableHeight },
29776
+ style: {
29777
+ top: columnRailTop,
29778
+ left: columnRailLeft,
29779
+ width: 18,
29780
+ height: layout.tableHeight
29781
+ },
29681
29782
  children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "text-sm font-medium leading-none", children: "+" })
29682
29783
  }
29683
29784
  ),
29684
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29785
+ (controlsVisible || hoverState.addRowVisible) && /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
29685
29786
  "button",
29686
29787
  {
29687
29788
  type: "button",
@@ -29699,9 +29800,14 @@ function TableControls({ editor, containerRef }) {
29699
29800
  className: cn(
29700
29801
  "absolute z-30 inline-flex items-center justify-center rounded-md",
29701
29802
  "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
29702
- "transition-colors hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29803
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29703
29804
  ),
29704
- style: { top: rowRailTop, left: rowRailLeft, width: layout.tableWidth, height: 16 },
29805
+ style: {
29806
+ top: rowRailTop,
29807
+ left: rowRailLeft,
29808
+ width: layout.tableWidth,
29809
+ height: 16
29810
+ },
29705
29811
  children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "text-sm font-medium leading-none", children: "+" })
29706
29812
  }
29707
29813
  ),
@@ -29836,6 +29942,19 @@ function resolveEventElement(target) {
29836
29942
  if (target instanceof Node) return target.parentElement;
29837
29943
  return null;
29838
29944
  }
29945
+ function getSelectionTableCell(view) {
29946
+ const browserSelection = window.getSelection();
29947
+ const anchorElement = resolveEventElement(browserSelection?.anchorNode ?? null);
29948
+ const anchorCell = anchorElement?.closest?.("th,td");
29949
+ if (anchorCell instanceof HTMLElement) {
29950
+ return anchorCell;
29951
+ }
29952
+ const { from } = view.state.selection;
29953
+ const domAtPos = view.domAtPos(from);
29954
+ const element = resolveEventElement(domAtPos.node);
29955
+ const cell = element?.closest?.("th,td");
29956
+ return cell instanceof HTMLElement ? cell : null;
29957
+ }
29839
29958
  function isRowResizeHotspot(cell, clientX, clientY) {
29840
29959
  const rect = cell.getBoundingClientRect();
29841
29960
  const nearBottom = rect.bottom - clientY <= TABLE_RESIZE_HIT_ZONE;
@@ -29862,6 +29981,16 @@ function getRelativeBoundaryMetrics(surface, table, row, cell) {
29862
29981
  columnRight: cellRect.right - surfaceRect.left + surface.scrollLeft
29863
29982
  };
29864
29983
  }
29984
+ function getRelativeCellMetrics(surface, cell) {
29985
+ const surfaceRect = surface.getBoundingClientRect();
29986
+ const cellRect = cell.getBoundingClientRect();
29987
+ return {
29988
+ left: cellRect.left - surfaceRect.left + surface.scrollLeft,
29989
+ top: cellRect.top - surfaceRect.top + surface.scrollTop,
29990
+ width: cellRect.width,
29991
+ height: cellRect.height
29992
+ };
29993
+ }
29865
29994
  var UEditor = import_react53.default.forwardRef(({
29866
29995
  content = "",
29867
29996
  onChange,
@@ -29889,6 +30018,9 @@ var UEditor = import_react53.default.forwardRef(({
29889
30018
  const editorContentRef = (0, import_react53.useRef)(null);
29890
30019
  const tableColumnGuideRef = (0, import_react53.useRef)(null);
29891
30020
  const tableRowGuideRef = (0, import_react53.useRef)(null);
30021
+ const activeTableCellHighlightRef = (0, import_react53.useRef)(null);
30022
+ const hoveredTableCellRef = (0, import_react53.useRef)(null);
30023
+ const activeTableCellRef = (0, import_react53.useRef)(null);
29892
30024
  const rowResizeStateRef = (0, import_react53.useRef)(null);
29893
30025
  const setEditorResizeCursor = import_react53.default.useCallback((cursor) => {
29894
30026
  const proseMirror = editorContentRef.current?.querySelector(".ProseMirror");
@@ -29915,6 +30047,36 @@ var UEditor = import_react53.default.forwardRef(({
29915
30047
  hideColumnGuide();
29916
30048
  hideRowGuide();
29917
30049
  }, [hideColumnGuide, hideRowGuide, setEditorResizeCursor]);
30050
+ const updateActiveCellHighlight = import_react53.default.useCallback((cell) => {
30051
+ const surface = editorContentRef.current;
30052
+ const highlight = activeTableCellHighlightRef.current;
30053
+ if (!highlight) return;
30054
+ if (!surface || !cell) {
30055
+ highlight.style.display = "none";
30056
+ return;
30057
+ }
30058
+ const metrics = getRelativeCellMetrics(surface, cell);
30059
+ highlight.style.display = "block";
30060
+ highlight.style.left = `${metrics.left}px`;
30061
+ highlight.style.top = `${metrics.top}px`;
30062
+ highlight.style.width = `${metrics.width}px`;
30063
+ highlight.style.height = `${metrics.height}px`;
30064
+ }, []);
30065
+ const setActiveTableCell = import_react53.default.useCallback((cell) => {
30066
+ if (activeTableCellRef.current === cell) return;
30067
+ activeTableCellRef.current = cell;
30068
+ updateActiveCellHighlight(activeTableCellRef.current);
30069
+ }, [updateActiveCellHighlight]);
30070
+ const clearActiveTableCell = import_react53.default.useCallback(() => {
30071
+ activeTableCellRef.current = null;
30072
+ updateActiveCellHighlight(null);
30073
+ }, [updateActiveCellHighlight]);
30074
+ const setHoveredTableCell = import_react53.default.useCallback((cell) => {
30075
+ hoveredTableCellRef.current = cell;
30076
+ }, []);
30077
+ const clearHoveredTableCell = import_react53.default.useCallback(() => {
30078
+ hoveredTableCellRef.current = null;
30079
+ }, []);
29918
30080
  const showColumnGuide = import_react53.default.useCallback((table, row, cell) => {
29919
30081
  const surface = editorContentRef.current;
29920
30082
  const guide = tableColumnGuideRef.current;
@@ -30096,6 +30258,10 @@ var UEditor = import_react53.default.forwardRef(({
30096
30258
  onJsonChange?.(editor2.getJSON());
30097
30259
  }
30098
30260
  });
30261
+ const syncActiveTableCellFromSelection = import_react53.default.useCallback(() => {
30262
+ if (!editor) return;
30263
+ setActiveTableCell(getSelectionTableCell(editor.view));
30264
+ }, [editor, setActiveTableCell]);
30099
30265
  (0, import_react53.useImperativeHandle)(
30100
30266
  ref,
30101
30267
  () => ({
@@ -30128,9 +30294,27 @@ var UEditor = import_react53.default.forwardRef(({
30128
30294
  (0, import_react53.useEffect)(() => {
30129
30295
  if (!editor) return void 0;
30130
30296
  const proseMirror = editor.view.dom;
30297
+ const surface = editorContentRef.current;
30298
+ let selectionSyncTimeoutId = 0;
30299
+ const scheduleActiveCellSync = (fallbackCell = null) => {
30300
+ requestAnimationFrame(() => {
30301
+ setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
30302
+ });
30303
+ window.clearTimeout(selectionSyncTimeoutId);
30304
+ selectionSyncTimeoutId = window.setTimeout(() => {
30305
+ setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
30306
+ }, 0);
30307
+ };
30308
+ const handleSelectionChange = () => {
30309
+ scheduleActiveCellSync();
30310
+ };
30311
+ const handleActiveCellLayoutChange = () => {
30312
+ updateActiveCellHighlight(activeTableCellRef.current);
30313
+ };
30131
30314
  const handleEditorMouseMove = (event) => {
30132
30315
  const activeRowResize = rowResizeStateRef.current;
30133
30316
  if (activeRowResize) {
30317
+ setHoveredTableCell(activeRowResize.cellElement);
30134
30318
  showRowGuide(activeRowResize.tableElement, activeRowResize.rowElement, activeRowResize.cellElement);
30135
30319
  return;
30136
30320
  }
@@ -30141,12 +30325,15 @@ var UEditor = import_react53.default.forwardRef(({
30141
30325
  }
30142
30326
  const cell = target.closest("th,td");
30143
30327
  if (!(cell instanceof HTMLElement)) {
30328
+ clearHoveredTableCell();
30144
30329
  clearAllTableResizeHover();
30145
30330
  return;
30146
30331
  }
30332
+ setHoveredTableCell(cell);
30147
30333
  const row = cell.closest("tr");
30148
30334
  const table = cell.closest("table");
30149
30335
  if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
30336
+ clearHoveredTableCell();
30150
30337
  clearAllTableResizeHover();
30151
30338
  return;
30152
30339
  }
@@ -30165,6 +30352,7 @@ var UEditor = import_react53.default.forwardRef(({
30165
30352
  clearAllTableResizeHover();
30166
30353
  };
30167
30354
  const handleEditorMouseLeave = () => {
30355
+ clearHoveredTableCell();
30168
30356
  if (!rowResizeStateRef.current) {
30169
30357
  clearAllTableResizeHover();
30170
30358
  }
@@ -30172,15 +30360,24 @@ var UEditor = import_react53.default.forwardRef(({
30172
30360
  const handleEditorMouseDown = (event) => {
30173
30361
  if (event.button !== 0) return;
30174
30362
  const target = resolveEventElement(event.target);
30175
- if (!(target instanceof Element)) return;
30363
+ if (!(target instanceof Element)) {
30364
+ clearActiveTableCell();
30365
+ return;
30366
+ }
30176
30367
  const cell = target.closest("th,td");
30177
- if (!(cell instanceof HTMLTableCellElement)) return;
30368
+ if (!(cell instanceof HTMLTableCellElement)) {
30369
+ clearActiveTableCell();
30370
+ return;
30371
+ }
30372
+ setActiveTableCell(cell);
30373
+ scheduleActiveCellSync(cell);
30178
30374
  const row = cell.closest("tr");
30179
30375
  const table = cell.closest("table");
30180
30376
  if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) return;
30181
30377
  if (!isRowResizeHotspot(cell, event.clientX, event.clientY)) {
30182
30378
  return;
30183
30379
  }
30380
+ setHoveredTableCell(cell);
30184
30381
  const rowInfo = findTableRowNodeInfo(editor.view, row);
30185
30382
  if (!rowInfo) return;
30186
30383
  rowResizeStateRef.current = {
@@ -30241,6 +30438,7 @@ var UEditor = import_react53.default.forwardRef(({
30241
30438
  clearPreviewRowHeight(state.rowElement);
30242
30439
  rowResizeStateRef.current = null;
30243
30440
  document.body.style.cursor = "";
30441
+ clearHoveredTableCell();
30244
30442
  clearAllTableResizeHover();
30245
30443
  };
30246
30444
  const handleWindowBlur = () => {
@@ -30249,30 +30447,53 @@ var UEditor = import_react53.default.forwardRef(({
30249
30447
  clearPreviewRowHeight(state.rowElement);
30250
30448
  rowResizeStateRef.current = null;
30251
30449
  document.body.style.cursor = "";
30450
+ clearHoveredTableCell();
30252
30451
  clearAllTableResizeHover();
30253
30452
  };
30254
30453
  proseMirror.addEventListener("mousemove", handleEditorMouseMove);
30255
30454
  proseMirror.addEventListener("mouseleave", handleEditorMouseLeave);
30256
30455
  proseMirror.addEventListener("mousedown", handleEditorMouseDown);
30456
+ proseMirror.addEventListener("click", handleSelectionChange);
30457
+ proseMirror.addEventListener("mouseup", handleSelectionChange);
30458
+ proseMirror.addEventListener("keyup", handleSelectionChange);
30459
+ proseMirror.addEventListener("focusin", handleSelectionChange);
30460
+ document.addEventListener("selectionchange", handleSelectionChange);
30461
+ surface?.addEventListener("scroll", handleActiveCellLayoutChange, { passive: true });
30462
+ window.addEventListener("resize", handleActiveCellLayoutChange);
30257
30463
  window.addEventListener("mousemove", handlePointerMove);
30258
30464
  document.addEventListener("pointermove", handlePointerMove);
30259
30465
  window.addEventListener("mouseup", handlePointerUp);
30260
30466
  document.addEventListener("pointerup", handlePointerUp);
30261
30467
  window.addEventListener("blur", handleWindowBlur);
30468
+ editor.on("selectionUpdate", syncActiveTableCellFromSelection);
30469
+ editor.on("focus", syncActiveTableCellFromSelection);
30470
+ syncActiveTableCellFromSelection();
30262
30471
  return () => {
30263
30472
  proseMirror.removeEventListener("mousemove", handleEditorMouseMove);
30264
30473
  proseMirror.removeEventListener("mouseleave", handleEditorMouseLeave);
30265
30474
  proseMirror.removeEventListener("mousedown", handleEditorMouseDown);
30475
+ proseMirror.removeEventListener("click", handleSelectionChange);
30476
+ proseMirror.removeEventListener("mouseup", handleSelectionChange);
30477
+ proseMirror.removeEventListener("keyup", handleSelectionChange);
30478
+ proseMirror.removeEventListener("focusin", handleSelectionChange);
30479
+ document.removeEventListener("selectionchange", handleSelectionChange);
30480
+ surface?.removeEventListener("scroll", handleActiveCellLayoutChange);
30481
+ window.removeEventListener("resize", handleActiveCellLayoutChange);
30266
30482
  window.removeEventListener("mousemove", handlePointerMove);
30267
30483
  document.removeEventListener("pointermove", handlePointerMove);
30268
30484
  window.removeEventListener("mouseup", handlePointerUp);
30269
30485
  document.removeEventListener("pointerup", handlePointerUp);
30270
30486
  window.removeEventListener("blur", handleWindowBlur);
30487
+ editor.off("selectionUpdate", syncActiveTableCellFromSelection);
30488
+ editor.off("focus", syncActiveTableCellFromSelection);
30489
+ window.clearTimeout(selectionSyncTimeoutId);
30271
30490
  document.body.style.cursor = "";
30491
+ clearActiveTableCell();
30492
+ clearHoveredTableCell();
30272
30493
  clearAllTableResizeHover();
30273
30494
  rowResizeStateRef.current = null;
30274
30495
  };
30275
- }, [clearAllTableResizeHover, editor, hideColumnGuide, hideRowGuide, showColumnGuide, showRowGuide]);
30496
+ }, [clearActiveTableCell, clearAllTableResizeHover, clearHoveredTableCell, editor, hideColumnGuide, hideRowGuide, setHoveredTableCell, showColumnGuide, showRowGuide, syncActiveTableCellFromSelection, updateActiveCellHighlight]);
30276
30497
  if (!editor) {
30277
30498
  return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
30278
30499
  "div",
@@ -30324,6 +30545,14 @@ var UEditor = import_react53.default.forwardRef(({
30324
30545
  className: "pointer-events-none absolute z-20 bg-primary opacity-0 transition-opacity duration-100"
30325
30546
  }
30326
30547
  ),
30548
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
30549
+ "span",
30550
+ {
30551
+ ref: activeTableCellHighlightRef,
30552
+ "aria-hidden": "true",
30553
+ className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-[#2383e2] bg-[#2383e2]/[0.06] transition-[left,top,width,height] duration-100"
30554
+ }
30555
+ ),
30327
30556
  editable && /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(TableControls, { editor, containerRef: editorContentRef }),
30328
30557
  /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
30329
30558
  import_react54.EditorContent,