@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.js CHANGED
@@ -28946,6 +28946,19 @@ import {
28946
28946
  import { Fragment as Fragment27, jsx as jsx81, jsxs as jsxs71 } from "react/jsx-runtime";
28947
28947
  var FALLBACK_TABLE_ROW_HEIGHT = 44;
28948
28948
  var FALLBACK_TABLE_COLUMN_WIDTH = 160;
28949
+ var MENU_HOVER_PADDING = 18;
28950
+ var ROW_HANDLE_HOVER_WIDTH = 28;
28951
+ var COLUMN_HANDLE_HOVER_HEIGHT = 28;
28952
+ var ADD_COLUMN_HOVER_WIDTH = 24;
28953
+ var ADD_ROW_HOVER_HEIGHT = 24;
28954
+ var HANDLE_HOVER_RADIUS = 14;
28955
+ var DEFAULT_HOVER_STATE = {
28956
+ menuVisible: false,
28957
+ addColumnVisible: false,
28958
+ addRowVisible: false,
28959
+ rowHandleIndex: null,
28960
+ columnHandleIndex: null
28961
+ };
28949
28962
  function resolveElement(target) {
28950
28963
  if (target instanceof Element) return target;
28951
28964
  if (target instanceof Node) return target.parentElement;
@@ -29071,6 +29084,12 @@ function buildLayout(editor, surface, cell) {
29071
29084
  };
29072
29085
  }
29073
29086
  function getSelectedCell(editor) {
29087
+ const browserSelection = window.getSelection();
29088
+ const anchorElement = resolveElement(browserSelection?.anchorNode ?? null);
29089
+ const anchorCell = anchorElement?.closest?.("th,td");
29090
+ if (anchorCell instanceof HTMLTableCellElement) {
29091
+ return anchorCell;
29092
+ }
29074
29093
  const domAtPos = editor.view.domAtPos(editor.state.selection.from);
29075
29094
  return getCellFromTarget(domAtPos.node);
29076
29095
  }
@@ -29099,6 +29118,7 @@ function TableControls({ editor, containerRef }) {
29099
29118
  const t = useSmartTranslations("UEditor");
29100
29119
  const [layout, setLayout] = React74.useState(null);
29101
29120
  const [dragPreview, setDragPreview] = React74.useState(null);
29121
+ const [hoverState, setHoverState] = React74.useState(DEFAULT_HOVER_STATE);
29102
29122
  const layoutRef = React74.useRef(null);
29103
29123
  const dragStateRef = React74.useRef(null);
29104
29124
  React74.useEffect(() => {
@@ -29130,17 +29150,50 @@ function TableControls({ editor, containerRef }) {
29130
29150
  setDragPreview(null);
29131
29151
  document.body.style.cursor = "";
29132
29152
  }, []);
29153
+ const updateHoverState = React74.useCallback((event) => {
29154
+ const activeLayout = layoutRef.current;
29155
+ const surface = containerRef.current;
29156
+ if (!activeLayout || !surface || dragStateRef.current) {
29157
+ setHoverState(DEFAULT_HOVER_STATE);
29158
+ return;
29159
+ }
29160
+ const surfaceRect = surface.getBoundingClientRect();
29161
+ const relativeX = event.clientX - surfaceRect.left + surface.scrollLeft;
29162
+ const relativeY = event.clientY - surfaceRect.top + surface.scrollTop;
29163
+ 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;
29164
+ 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;
29165
+ 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;
29166
+ const addColumnVisible = relativeX >= activeLayout.tableLeft + activeLayout.tableWidth && relativeX <= activeLayout.tableLeft + activeLayout.tableWidth + ADD_COLUMN_HOVER_WIDTH && relativeY >= activeLayout.tableTop && relativeY <= activeLayout.tableTop + activeLayout.tableHeight;
29167
+ const addRowVisible = relativeY >= activeLayout.tableTop + activeLayout.tableHeight && relativeY <= activeLayout.tableTop + activeLayout.tableHeight + ADD_ROW_HOVER_HEIGHT && relativeX >= activeLayout.tableLeft && relativeX <= activeLayout.tableLeft + activeLayout.tableWidth;
29168
+ setHoverState((prev) => {
29169
+ if (prev.menuVisible === menuVisible && prev.addColumnVisible === addColumnVisible && prev.addRowVisible === addRowVisible && prev.rowHandleIndex === rowHandleIndex && prev.columnHandleIndex === columnHandleIndex) {
29170
+ return prev;
29171
+ }
29172
+ return {
29173
+ menuVisible,
29174
+ addColumnVisible,
29175
+ addRowVisible,
29176
+ rowHandleIndex,
29177
+ columnHandleIndex
29178
+ };
29179
+ });
29180
+ }, [containerRef]);
29133
29181
  React74.useEffect(() => {
29134
29182
  const proseMirror = editor.view.dom;
29135
29183
  const surface = containerRef.current;
29136
29184
  if (!surface) return void 0;
29137
29185
  const handleMouseOver = (event) => {
29138
29186
  if (dragStateRef.current) return;
29139
- syncFromCell(getCellFromTarget(event.target));
29187
+ const cell = getCellFromTarget(event.target);
29188
+ if (!cell) return;
29189
+ syncFromCell(cell);
29190
+ };
29191
+ const handleSurfaceMouseMove = (event) => {
29192
+ updateHoverState(event);
29140
29193
  };
29141
29194
  const handleMouseLeave = () => {
29142
29195
  if (dragStateRef.current) return;
29143
- syncFromSelection();
29196
+ setHoverState(DEFAULT_HOVER_STATE);
29144
29197
  };
29145
29198
  const handleFocusIn = () => {
29146
29199
  if (dragStateRef.current) return;
@@ -29149,6 +29202,7 @@ function TableControls({ editor, containerRef }) {
29149
29202
  proseMirror.addEventListener("mouseover", handleMouseOver);
29150
29203
  proseMirror.addEventListener("mouseleave", handleMouseLeave);
29151
29204
  proseMirror.addEventListener("focusin", handleFocusIn);
29205
+ surface.addEventListener("mousemove", handleSurfaceMouseMove);
29152
29206
  surface.addEventListener("scroll", refreshCurrentLayout, { passive: true });
29153
29207
  window.addEventListener("resize", refreshCurrentLayout);
29154
29208
  editor.on("selectionUpdate", syncFromSelection);
@@ -29158,12 +29212,13 @@ function TableControls({ editor, containerRef }) {
29158
29212
  proseMirror.removeEventListener("mouseover", handleMouseOver);
29159
29213
  proseMirror.removeEventListener("mouseleave", handleMouseLeave);
29160
29214
  proseMirror.removeEventListener("focusin", handleFocusIn);
29215
+ surface.removeEventListener("mousemove", handleSurfaceMouseMove);
29161
29216
  surface.removeEventListener("scroll", refreshCurrentLayout);
29162
29217
  window.removeEventListener("resize", refreshCurrentLayout);
29163
29218
  editor.off("selectionUpdate", syncFromSelection);
29164
29219
  editor.off("update", refreshCurrentLayout);
29165
29220
  };
29166
- }, [clearDrag, containerRef, editor, refreshCurrentLayout, syncFromCell, syncFromSelection]);
29221
+ }, [clearDrag, containerRef, editor, refreshCurrentLayout, syncFromCell, syncFromSelection, updateHoverState]);
29167
29222
  const runAtCellPos = React74.useCallback((cellPos, command, options) => {
29168
29223
  if (cellPos == null) return false;
29169
29224
  focusCell(editor, cellPos);
@@ -29253,6 +29308,7 @@ function TableControls({ editor, containerRef }) {
29253
29308
  return true;
29254
29309
  }, [runAtCornerCell, syncFromSelection]);
29255
29310
  const canExpandTable = Boolean(layout);
29311
+ const controlsVisible = dragPreview !== null;
29256
29312
  React74.useEffect(() => {
29257
29313
  const handleMouseMove = (event) => {
29258
29314
  const dragState = dragStateRef.current;
@@ -29464,107 +29520,147 @@ function TableControls({ editor, containerRef }) {
29464
29520
  const expandPreviewHeight = dragPreview?.kind === "add-row" ? layout.tableHeight + dragPreview.previewRows * layout.avgRowHeight : layout.tableHeight;
29465
29521
  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;
29466
29522
  return /* @__PURE__ */ jsxs71(Fragment27, { children: [
29467
- layout.rowHandles.map((rowHandle) => /* @__PURE__ */ jsx81("div", { className: "absolute z-30", style: { top: Math.max(8, rowHandle.center - 12), left: rowHandleLeft }, children: /* @__PURE__ */ jsx81(
29468
- DropdownMenu,
29469
- {
29470
- placement: "right",
29471
- items: getRowHandleMenuItems(rowHandle),
29472
- trigger: /* @__PURE__ */ jsx81(
29473
- "button",
29474
- {
29475
- type: "button",
29476
- "aria-label": `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29477
- title: `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29478
- onMouseDown: (event) => {
29479
- event.preventDefault();
29480
- event.stopPropagation();
29481
- dragStateRef.current = {
29482
- kind: "row",
29483
- originIndex: rowHandle.index,
29484
- targetIndex: rowHandle.index,
29485
- anchorPos: rowHandle.cellPos
29486
- };
29487
- setDragPreview({
29488
- kind: "row",
29489
- originIndex: rowHandle.index,
29490
- targetIndex: rowHandle.index,
29491
- targetStart: rowHandle.start,
29492
- targetSize: rowHandle.size
29493
- });
29494
- document.body.style.cursor = "grabbing";
29495
- },
29496
- className: cn(
29497
- "inline-flex h-6 w-6 items-center justify-center rounded-full",
29498
- "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29499
- "transition-colors hover:bg-accent hover:text-foreground"
29500
- ),
29501
- children: /* @__PURE__ */ jsx81(GripVertical3, { className: "h-3.5 w-3.5" })
29502
- }
29503
- )
29504
- }
29505
- ) }, `row-handle-${rowHandle.index}`)),
29506
- layout.columnHandles.map((columnHandle) => /* @__PURE__ */ jsx81("div", { className: "absolute z-30", style: { top: columnHandleTop, left: Math.max(8, columnHandle.center - 12) }, children: /* @__PURE__ */ jsx81(
29507
- DropdownMenu,
29508
- {
29509
- placement: "bottom-start",
29510
- items: getColumnHandleMenuItems(columnHandle),
29511
- trigger: /* @__PURE__ */ jsx81(
29512
- "button",
29513
- {
29514
- type: "button",
29515
- "aria-label": `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29516
- title: `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29517
- onMouseDown: (event) => {
29518
- event.preventDefault();
29519
- event.stopPropagation();
29520
- dragStateRef.current = {
29521
- kind: "column",
29522
- originIndex: columnHandle.index,
29523
- targetIndex: columnHandle.index,
29524
- anchorPos: columnHandle.cellPos
29525
- };
29526
- setDragPreview({
29527
- kind: "column",
29528
- originIndex: columnHandle.index,
29529
- targetIndex: columnHandle.index,
29530
- targetStart: columnHandle.start,
29531
- targetSize: columnHandle.size
29532
- });
29533
- document.body.style.cursor = "grabbing";
29534
- },
29535
- className: cn(
29536
- "inline-flex h-6 w-6 items-center justify-center rounded-full",
29537
- "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29538
- "transition-colors hover:bg-accent hover:text-foreground"
29539
- ),
29540
- children: /* @__PURE__ */ jsx81(GripHorizontal, { className: "h-3.5 w-3.5" })
29541
- }
29542
- )
29543
- }
29544
- ) }, `column-handle-${columnHandle.index}`)),
29545
- /* @__PURE__ */ jsx81("div", { className: "pointer-events-none absolute z-30", style: { top: menuTop, left: menuLeft }, children: /* @__PURE__ */ jsx81(
29546
- DropdownMenu,
29523
+ layout.rowHandles.map((rowHandle) => {
29524
+ const visible = controlsVisible || hoverState.rowHandleIndex === rowHandle.index;
29525
+ if (!visible) return null;
29526
+ return /* @__PURE__ */ jsx81(
29527
+ "div",
29528
+ {
29529
+ className: "absolute z-30",
29530
+ style: {
29531
+ top: Math.max(8, rowHandle.center - 12),
29532
+ left: rowHandleLeft
29533
+ },
29534
+ children: /* @__PURE__ */ jsx81(
29535
+ DropdownMenu,
29536
+ {
29537
+ placement: "right",
29538
+ items: getRowHandleMenuItems(rowHandle),
29539
+ trigger: /* @__PURE__ */ jsx81(
29540
+ "button",
29541
+ {
29542
+ type: "button",
29543
+ "aria-label": `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29544
+ title: `${t("tableMenu.dragRow")} ${rowHandle.index + 1}`,
29545
+ onMouseDown: (event) => {
29546
+ event.preventDefault();
29547
+ event.stopPropagation();
29548
+ dragStateRef.current = {
29549
+ kind: "row",
29550
+ originIndex: rowHandle.index,
29551
+ targetIndex: rowHandle.index,
29552
+ anchorPos: rowHandle.cellPos
29553
+ };
29554
+ setDragPreview({
29555
+ kind: "row",
29556
+ originIndex: rowHandle.index,
29557
+ targetIndex: rowHandle.index,
29558
+ targetStart: rowHandle.start,
29559
+ targetSize: rowHandle.size
29560
+ });
29561
+ document.body.style.cursor = "grabbing";
29562
+ },
29563
+ className: cn(
29564
+ "inline-flex h-6 w-6 items-center justify-center rounded-full",
29565
+ "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29566
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29567
+ ),
29568
+ children: /* @__PURE__ */ jsx81(GripVertical3, { className: "h-3.5 w-3.5" })
29569
+ }
29570
+ )
29571
+ }
29572
+ )
29573
+ },
29574
+ `row-handle-${rowHandle.index}`
29575
+ );
29576
+ }),
29577
+ layout.columnHandles.map((columnHandle) => {
29578
+ const visible = controlsVisible || hoverState.columnHandleIndex === columnHandle.index;
29579
+ if (!visible) return null;
29580
+ return /* @__PURE__ */ jsx81(
29581
+ "div",
29582
+ {
29583
+ className: "absolute z-30",
29584
+ style: {
29585
+ top: columnHandleTop,
29586
+ left: Math.max(8, columnHandle.center - 12)
29587
+ },
29588
+ children: /* @__PURE__ */ jsx81(
29589
+ DropdownMenu,
29590
+ {
29591
+ placement: "bottom-start",
29592
+ items: getColumnHandleMenuItems(columnHandle),
29593
+ trigger: /* @__PURE__ */ jsx81(
29594
+ "button",
29595
+ {
29596
+ type: "button",
29597
+ "aria-label": `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29598
+ title: `${t("tableMenu.dragColumn")} ${columnHandle.index + 1}`,
29599
+ onMouseDown: (event) => {
29600
+ event.preventDefault();
29601
+ event.stopPropagation();
29602
+ dragStateRef.current = {
29603
+ kind: "column",
29604
+ originIndex: columnHandle.index,
29605
+ targetIndex: columnHandle.index,
29606
+ anchorPos: columnHandle.cellPos
29607
+ };
29608
+ setDragPreview({
29609
+ kind: "column",
29610
+ originIndex: columnHandle.index,
29611
+ targetIndex: columnHandle.index,
29612
+ targetStart: columnHandle.start,
29613
+ targetSize: columnHandle.size
29614
+ });
29615
+ document.body.style.cursor = "grabbing";
29616
+ },
29617
+ className: cn(
29618
+ "inline-flex h-6 w-6 items-center justify-center rounded-full",
29619
+ "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29620
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29621
+ ),
29622
+ children: /* @__PURE__ */ jsx81(GripHorizontal, { className: "h-3.5 w-3.5" })
29623
+ }
29624
+ )
29625
+ }
29626
+ )
29627
+ },
29628
+ `column-handle-${columnHandle.index}`
29629
+ );
29630
+ }),
29631
+ (controlsVisible || hoverState.menuVisible) && /* @__PURE__ */ jsx81(
29632
+ "div",
29547
29633
  {
29548
- placement: "bottom-start",
29549
- items: menuItems,
29550
- trigger: /* @__PURE__ */ jsx81(
29551
- "button",
29634
+ className: "absolute z-30",
29635
+ style: {
29636
+ top: menuTop,
29637
+ left: menuLeft
29638
+ },
29639
+ children: /* @__PURE__ */ jsx81(
29640
+ DropdownMenu,
29552
29641
  {
29553
- type: "button",
29554
- "aria-label": t("tableMenu.openControls"),
29555
- title: t("tableMenu.openControls"),
29556
- onMouseDown: (event) => event.preventDefault(),
29557
- className: cn(
29558
- "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-full",
29559
- "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29560
- "transition-colors hover:bg-accent hover:text-foreground"
29561
- ),
29562
- children: /* @__PURE__ */ jsx81(MoreHorizontal2, { className: "h-4 w-4" })
29642
+ placement: "bottom-start",
29643
+ items: menuItems,
29644
+ trigger: /* @__PURE__ */ jsx81(
29645
+ "button",
29646
+ {
29647
+ type: "button",
29648
+ "aria-label": t("tableMenu.openControls"),
29649
+ title: t("tableMenu.openControls"),
29650
+ onMouseDown: (event) => event.preventDefault(),
29651
+ className: cn(
29652
+ "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-full",
29653
+ "border border-border/70 bg-background/95 text-muted-foreground shadow-sm backdrop-blur",
29654
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground"
29655
+ ),
29656
+ children: /* @__PURE__ */ jsx81(MoreHorizontal2, { className: "h-4 w-4" })
29657
+ }
29658
+ )
29563
29659
  }
29564
29660
  )
29565
29661
  }
29566
- ) }),
29567
- /* @__PURE__ */ jsx81(
29662
+ ),
29663
+ (controlsVisible || hoverState.addColumnVisible) && /* @__PURE__ */ jsx81(
29568
29664
  "button",
29569
29665
  {
29570
29666
  type: "button",
@@ -29582,13 +29678,18 @@ function TableControls({ editor, containerRef }) {
29582
29678
  className: cn(
29583
29679
  "absolute z-30 inline-flex items-center justify-center rounded-md",
29584
29680
  "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
29585
- "transition-colors hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29681
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29586
29682
  ),
29587
- style: { top: columnRailTop, left: columnRailLeft, width: 18, height: layout.tableHeight },
29683
+ style: {
29684
+ top: columnRailTop,
29685
+ left: columnRailLeft,
29686
+ width: 18,
29687
+ height: layout.tableHeight
29688
+ },
29588
29689
  children: /* @__PURE__ */ jsx81("span", { className: "text-sm font-medium leading-none", children: "+" })
29589
29690
  }
29590
29691
  ),
29591
- /* @__PURE__ */ jsx81(
29692
+ (controlsVisible || hoverState.addRowVisible) && /* @__PURE__ */ jsx81(
29592
29693
  "button",
29593
29694
  {
29594
29695
  type: "button",
@@ -29606,9 +29707,14 @@ function TableControls({ editor, containerRef }) {
29606
29707
  className: cn(
29607
29708
  "absolute z-30 inline-flex items-center justify-center rounded-md",
29608
29709
  "border border-border/70 bg-muted/40 text-muted-foreground shadow-sm backdrop-blur",
29609
- "transition-colors hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29710
+ "transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
29610
29711
  ),
29611
- style: { top: rowRailTop, left: rowRailLeft, width: layout.tableWidth, height: 16 },
29712
+ style: {
29713
+ top: rowRailTop,
29714
+ left: rowRailLeft,
29715
+ width: layout.tableWidth,
29716
+ height: 16
29717
+ },
29612
29718
  children: /* @__PURE__ */ jsx81("span", { className: "text-sm font-medium leading-none", children: "+" })
29613
29719
  }
29614
29720
  ),
@@ -29743,6 +29849,19 @@ function resolveEventElement(target) {
29743
29849
  if (target instanceof Node) return target.parentElement;
29744
29850
  return null;
29745
29851
  }
29852
+ function getSelectionTableCell(view) {
29853
+ const browserSelection = window.getSelection();
29854
+ const anchorElement = resolveEventElement(browserSelection?.anchorNode ?? null);
29855
+ const anchorCell = anchorElement?.closest?.("th,td");
29856
+ if (anchorCell instanceof HTMLElement) {
29857
+ return anchorCell;
29858
+ }
29859
+ const { from } = view.state.selection;
29860
+ const domAtPos = view.domAtPos(from);
29861
+ const element = resolveEventElement(domAtPos.node);
29862
+ const cell = element?.closest?.("th,td");
29863
+ return cell instanceof HTMLElement ? cell : null;
29864
+ }
29746
29865
  function isRowResizeHotspot(cell, clientX, clientY) {
29747
29866
  const rect = cell.getBoundingClientRect();
29748
29867
  const nearBottom = rect.bottom - clientY <= TABLE_RESIZE_HIT_ZONE;
@@ -29769,6 +29888,16 @@ function getRelativeBoundaryMetrics(surface, table, row, cell) {
29769
29888
  columnRight: cellRect.right - surfaceRect.left + surface.scrollLeft
29770
29889
  };
29771
29890
  }
29891
+ function getRelativeCellMetrics(surface, cell) {
29892
+ const surfaceRect = surface.getBoundingClientRect();
29893
+ const cellRect = cell.getBoundingClientRect();
29894
+ return {
29895
+ left: cellRect.left - surfaceRect.left + surface.scrollLeft,
29896
+ top: cellRect.top - surfaceRect.top + surface.scrollTop,
29897
+ width: cellRect.width,
29898
+ height: cellRect.height
29899
+ };
29900
+ }
29772
29901
  var UEditor = React75.forwardRef(({
29773
29902
  content = "",
29774
29903
  onChange,
@@ -29796,6 +29925,9 @@ var UEditor = React75.forwardRef(({
29796
29925
  const editorContentRef = useRef32(null);
29797
29926
  const tableColumnGuideRef = useRef32(null);
29798
29927
  const tableRowGuideRef = useRef32(null);
29928
+ const activeTableCellHighlightRef = useRef32(null);
29929
+ const hoveredTableCellRef = useRef32(null);
29930
+ const activeTableCellRef = useRef32(null);
29799
29931
  const rowResizeStateRef = useRef32(null);
29800
29932
  const setEditorResizeCursor = React75.useCallback((cursor) => {
29801
29933
  const proseMirror = editorContentRef.current?.querySelector(".ProseMirror");
@@ -29822,6 +29954,36 @@ var UEditor = React75.forwardRef(({
29822
29954
  hideColumnGuide();
29823
29955
  hideRowGuide();
29824
29956
  }, [hideColumnGuide, hideRowGuide, setEditorResizeCursor]);
29957
+ const updateActiveCellHighlight = React75.useCallback((cell) => {
29958
+ const surface = editorContentRef.current;
29959
+ const highlight = activeTableCellHighlightRef.current;
29960
+ if (!highlight) return;
29961
+ if (!surface || !cell) {
29962
+ highlight.style.display = "none";
29963
+ return;
29964
+ }
29965
+ const metrics = getRelativeCellMetrics(surface, cell);
29966
+ highlight.style.display = "block";
29967
+ highlight.style.left = `${metrics.left}px`;
29968
+ highlight.style.top = `${metrics.top}px`;
29969
+ highlight.style.width = `${metrics.width}px`;
29970
+ highlight.style.height = `${metrics.height}px`;
29971
+ }, []);
29972
+ const setActiveTableCell = React75.useCallback((cell) => {
29973
+ if (activeTableCellRef.current === cell) return;
29974
+ activeTableCellRef.current = cell;
29975
+ updateActiveCellHighlight(activeTableCellRef.current);
29976
+ }, [updateActiveCellHighlight]);
29977
+ const clearActiveTableCell = React75.useCallback(() => {
29978
+ activeTableCellRef.current = null;
29979
+ updateActiveCellHighlight(null);
29980
+ }, [updateActiveCellHighlight]);
29981
+ const setHoveredTableCell = React75.useCallback((cell) => {
29982
+ hoveredTableCellRef.current = cell;
29983
+ }, []);
29984
+ const clearHoveredTableCell = React75.useCallback(() => {
29985
+ hoveredTableCellRef.current = null;
29986
+ }, []);
29825
29987
  const showColumnGuide = React75.useCallback((table, row, cell) => {
29826
29988
  const surface = editorContentRef.current;
29827
29989
  const guide = tableColumnGuideRef.current;
@@ -30003,6 +30165,10 @@ var UEditor = React75.forwardRef(({
30003
30165
  onJsonChange?.(editor2.getJSON());
30004
30166
  }
30005
30167
  });
30168
+ const syncActiveTableCellFromSelection = React75.useCallback(() => {
30169
+ if (!editor) return;
30170
+ setActiveTableCell(getSelectionTableCell(editor.view));
30171
+ }, [editor, setActiveTableCell]);
30006
30172
  useImperativeHandle3(
30007
30173
  ref,
30008
30174
  () => ({
@@ -30035,9 +30201,27 @@ var UEditor = React75.forwardRef(({
30035
30201
  useEffect35(() => {
30036
30202
  if (!editor) return void 0;
30037
30203
  const proseMirror = editor.view.dom;
30204
+ const surface = editorContentRef.current;
30205
+ let selectionSyncTimeoutId = 0;
30206
+ const scheduleActiveCellSync = (fallbackCell = null) => {
30207
+ requestAnimationFrame(() => {
30208
+ setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
30209
+ });
30210
+ window.clearTimeout(selectionSyncTimeoutId);
30211
+ selectionSyncTimeoutId = window.setTimeout(() => {
30212
+ setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
30213
+ }, 0);
30214
+ };
30215
+ const handleSelectionChange = () => {
30216
+ scheduleActiveCellSync();
30217
+ };
30218
+ const handleActiveCellLayoutChange = () => {
30219
+ updateActiveCellHighlight(activeTableCellRef.current);
30220
+ };
30038
30221
  const handleEditorMouseMove = (event) => {
30039
30222
  const activeRowResize = rowResizeStateRef.current;
30040
30223
  if (activeRowResize) {
30224
+ setHoveredTableCell(activeRowResize.cellElement);
30041
30225
  showRowGuide(activeRowResize.tableElement, activeRowResize.rowElement, activeRowResize.cellElement);
30042
30226
  return;
30043
30227
  }
@@ -30048,12 +30232,15 @@ var UEditor = React75.forwardRef(({
30048
30232
  }
30049
30233
  const cell = target.closest("th,td");
30050
30234
  if (!(cell instanceof HTMLElement)) {
30235
+ clearHoveredTableCell();
30051
30236
  clearAllTableResizeHover();
30052
30237
  return;
30053
30238
  }
30239
+ setHoveredTableCell(cell);
30054
30240
  const row = cell.closest("tr");
30055
30241
  const table = cell.closest("table");
30056
30242
  if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
30243
+ clearHoveredTableCell();
30057
30244
  clearAllTableResizeHover();
30058
30245
  return;
30059
30246
  }
@@ -30072,6 +30259,7 @@ var UEditor = React75.forwardRef(({
30072
30259
  clearAllTableResizeHover();
30073
30260
  };
30074
30261
  const handleEditorMouseLeave = () => {
30262
+ clearHoveredTableCell();
30075
30263
  if (!rowResizeStateRef.current) {
30076
30264
  clearAllTableResizeHover();
30077
30265
  }
@@ -30079,15 +30267,24 @@ var UEditor = React75.forwardRef(({
30079
30267
  const handleEditorMouseDown = (event) => {
30080
30268
  if (event.button !== 0) return;
30081
30269
  const target = resolveEventElement(event.target);
30082
- if (!(target instanceof Element)) return;
30270
+ if (!(target instanceof Element)) {
30271
+ clearActiveTableCell();
30272
+ return;
30273
+ }
30083
30274
  const cell = target.closest("th,td");
30084
- if (!(cell instanceof HTMLTableCellElement)) return;
30275
+ if (!(cell instanceof HTMLTableCellElement)) {
30276
+ clearActiveTableCell();
30277
+ return;
30278
+ }
30279
+ setActiveTableCell(cell);
30280
+ scheduleActiveCellSync(cell);
30085
30281
  const row = cell.closest("tr");
30086
30282
  const table = cell.closest("table");
30087
30283
  if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) return;
30088
30284
  if (!isRowResizeHotspot(cell, event.clientX, event.clientY)) {
30089
30285
  return;
30090
30286
  }
30287
+ setHoveredTableCell(cell);
30091
30288
  const rowInfo = findTableRowNodeInfo(editor.view, row);
30092
30289
  if (!rowInfo) return;
30093
30290
  rowResizeStateRef.current = {
@@ -30148,6 +30345,7 @@ var UEditor = React75.forwardRef(({
30148
30345
  clearPreviewRowHeight(state.rowElement);
30149
30346
  rowResizeStateRef.current = null;
30150
30347
  document.body.style.cursor = "";
30348
+ clearHoveredTableCell();
30151
30349
  clearAllTableResizeHover();
30152
30350
  };
30153
30351
  const handleWindowBlur = () => {
@@ -30156,30 +30354,53 @@ var UEditor = React75.forwardRef(({
30156
30354
  clearPreviewRowHeight(state.rowElement);
30157
30355
  rowResizeStateRef.current = null;
30158
30356
  document.body.style.cursor = "";
30357
+ clearHoveredTableCell();
30159
30358
  clearAllTableResizeHover();
30160
30359
  };
30161
30360
  proseMirror.addEventListener("mousemove", handleEditorMouseMove);
30162
30361
  proseMirror.addEventListener("mouseleave", handleEditorMouseLeave);
30163
30362
  proseMirror.addEventListener("mousedown", handleEditorMouseDown);
30363
+ proseMirror.addEventListener("click", handleSelectionChange);
30364
+ proseMirror.addEventListener("mouseup", handleSelectionChange);
30365
+ proseMirror.addEventListener("keyup", handleSelectionChange);
30366
+ proseMirror.addEventListener("focusin", handleSelectionChange);
30367
+ document.addEventListener("selectionchange", handleSelectionChange);
30368
+ surface?.addEventListener("scroll", handleActiveCellLayoutChange, { passive: true });
30369
+ window.addEventListener("resize", handleActiveCellLayoutChange);
30164
30370
  window.addEventListener("mousemove", handlePointerMove);
30165
30371
  document.addEventListener("pointermove", handlePointerMove);
30166
30372
  window.addEventListener("mouseup", handlePointerUp);
30167
30373
  document.addEventListener("pointerup", handlePointerUp);
30168
30374
  window.addEventListener("blur", handleWindowBlur);
30375
+ editor.on("selectionUpdate", syncActiveTableCellFromSelection);
30376
+ editor.on("focus", syncActiveTableCellFromSelection);
30377
+ syncActiveTableCellFromSelection();
30169
30378
  return () => {
30170
30379
  proseMirror.removeEventListener("mousemove", handleEditorMouseMove);
30171
30380
  proseMirror.removeEventListener("mouseleave", handleEditorMouseLeave);
30172
30381
  proseMirror.removeEventListener("mousedown", handleEditorMouseDown);
30382
+ proseMirror.removeEventListener("click", handleSelectionChange);
30383
+ proseMirror.removeEventListener("mouseup", handleSelectionChange);
30384
+ proseMirror.removeEventListener("keyup", handleSelectionChange);
30385
+ proseMirror.removeEventListener("focusin", handleSelectionChange);
30386
+ document.removeEventListener("selectionchange", handleSelectionChange);
30387
+ surface?.removeEventListener("scroll", handleActiveCellLayoutChange);
30388
+ window.removeEventListener("resize", handleActiveCellLayoutChange);
30173
30389
  window.removeEventListener("mousemove", handlePointerMove);
30174
30390
  document.removeEventListener("pointermove", handlePointerMove);
30175
30391
  window.removeEventListener("mouseup", handlePointerUp);
30176
30392
  document.removeEventListener("pointerup", handlePointerUp);
30177
30393
  window.removeEventListener("blur", handleWindowBlur);
30394
+ editor.off("selectionUpdate", syncActiveTableCellFromSelection);
30395
+ editor.off("focus", syncActiveTableCellFromSelection);
30396
+ window.clearTimeout(selectionSyncTimeoutId);
30178
30397
  document.body.style.cursor = "";
30398
+ clearActiveTableCell();
30399
+ clearHoveredTableCell();
30179
30400
  clearAllTableResizeHover();
30180
30401
  rowResizeStateRef.current = null;
30181
30402
  };
30182
- }, [clearAllTableResizeHover, editor, hideColumnGuide, hideRowGuide, showColumnGuide, showRowGuide]);
30403
+ }, [clearActiveTableCell, clearAllTableResizeHover, clearHoveredTableCell, editor, hideColumnGuide, hideRowGuide, setHoveredTableCell, showColumnGuide, showRowGuide, syncActiveTableCellFromSelection, updateActiveCellHighlight]);
30183
30404
  if (!editor) {
30184
30405
  return /* @__PURE__ */ jsx82(
30185
30406
  "div",
@@ -30231,6 +30452,14 @@ var UEditor = React75.forwardRef(({
30231
30452
  className: "pointer-events-none absolute z-20 bg-primary opacity-0 transition-opacity duration-100"
30232
30453
  }
30233
30454
  ),
30455
+ /* @__PURE__ */ jsx82(
30456
+ "span",
30457
+ {
30458
+ ref: activeTableCellHighlightRef,
30459
+ "aria-hidden": "true",
30460
+ 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"
30461
+ }
30462
+ ),
30234
30463
  editable && /* @__PURE__ */ jsx82(TableControls, { editor, containerRef: editorContentRef }),
30235
30464
  /* @__PURE__ */ jsx82(
30236
30465
  EditorContent,