@underverse-ui/underverse 1.0.142 → 1.0.144

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
@@ -25741,6 +25741,45 @@ function getImageFiles(dataTransfer) {
25741
25741
  }
25742
25742
  return Array.from(byKey.values());
25743
25743
  }
25744
+ function getClipboardData(dataTransfer, type) {
25745
+ try {
25746
+ return dataTransfer.getData(type) ?? "";
25747
+ } catch {
25748
+ return "";
25749
+ }
25750
+ }
25751
+ function extractClipboardHtmlFragment(html) {
25752
+ const startMarker = "<!--StartFragment-->";
25753
+ const endMarker = "<!--EndFragment-->";
25754
+ const start = html.indexOf(startMarker);
25755
+ const end = html.indexOf(endMarker);
25756
+ if (start >= 0 && end > start) {
25757
+ return html.slice(start + startMarker.length, end);
25758
+ }
25759
+ return html;
25760
+ }
25761
+ function getClipboardTableHtml(dataTransfer) {
25762
+ const html = getClipboardData(dataTransfer, "text/html");
25763
+ if (!/<table(?:\s|>)/i.test(html)) return "";
25764
+ const fragment = extractClipboardHtmlFragment(html);
25765
+ if (typeof DOMParser !== "undefined") {
25766
+ const doc = new DOMParser().parseFromString(fragment, "text/html");
25767
+ const table = doc.querySelector("table");
25768
+ if (table) return table.outerHTML;
25769
+ }
25770
+ return fragment;
25771
+ }
25772
+ function escapeHtml(value) {
25773
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
25774
+ }
25775
+ function getClipboardTsvTableHtml(dataTransfer) {
25776
+ const text = getClipboardData(dataTransfer, "text/plain").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n+$/, "");
25777
+ if (!text.includes(" ")) return "";
25778
+ const rows = text.split("\n").map((row) => row.split(" "));
25779
+ if (rows.length === 0 || rows.every((row) => row.length < 2)) return "";
25780
+ const body = rows.map((row) => `<tr>${row.map((cell) => `<td>${escapeHtml(cell)}</td>`).join("")}</tr>`).join("");
25781
+ return `<table><tbody>${body}</tbody></table>`;
25782
+ }
25744
25783
  function fileToDataUrl(file) {
25745
25784
  return new Promise((resolve, reject) => {
25746
25785
  const reader = new FileReader();
@@ -25795,6 +25834,18 @@ var ClipboardImages = Extension2.create({
25795
25834
  props: {
25796
25835
  handlePaste: (_view, event) => {
25797
25836
  if (!event || !event.clipboardData) return false;
25837
+ const tableHtml = getClipboardTableHtml(event.clipboardData);
25838
+ if (tableHtml) {
25839
+ event.preventDefault();
25840
+ editor.chain().focus().insertContent(tableHtml).run();
25841
+ return true;
25842
+ }
25843
+ const tsvTableHtml = getClipboardTsvTableHtml(event.clipboardData);
25844
+ if (tsvTableHtml) {
25845
+ event.preventDefault();
25846
+ editor.chain().focus().insertContent(tsvTableHtml).run();
25847
+ return true;
25848
+ }
25798
25849
  const files = getImageFiles(event.clipboardData);
25799
25850
  if (files.length === 0) return false;
25800
25851
  event.preventDefault();
@@ -27147,7 +27198,7 @@ function buildUEditorExtensions({
27147
27198
  handleWidth: 10,
27148
27199
  allowTableNodeSelection: true,
27149
27200
  HTMLAttributes: {
27150
- class: "border-collapse w-full my-4"
27201
+ class: "border-collapse my-4"
27151
27202
  }
27152
27203
  }),
27153
27204
  table_row_default,
@@ -27230,6 +27281,7 @@ import {
27230
27281
  Subscript as SubscriptIcon,
27231
27282
  Superscript as SuperscriptIcon,
27232
27283
  Table as TableIcon,
27284
+ TableCellsMerge,
27233
27285
  Trash2 as Trash22,
27234
27286
  Type as Type2,
27235
27287
  Underline as UnderlineIcon,
@@ -27707,6 +27759,229 @@ var ImageInput = ({ onSubmit, onCancel }) => {
27707
27759
  ] });
27708
27760
  };
27709
27761
 
27762
+ // src/components/UEditor/table-cell-commands.ts
27763
+ import { TextSelection as TextSelection2 } from "@tiptap/pm/state";
27764
+ import { selectedRect, TableMap } from "@tiptap/pm/tables";
27765
+ function getCellSelectionPositions(selection) {
27766
+ const value = selection;
27767
+ const anchor = value.$anchorCell?.pos;
27768
+ const head = value.$headCell?.pos;
27769
+ return typeof anchor === "number" && typeof head === "number" ? { anchor, head } : null;
27770
+ }
27771
+ function findTableInfoFromCellPos(editor, cellPos) {
27772
+ const $pos = editor.state.doc.resolve(cellPos);
27773
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
27774
+ const node = $pos.node(depth);
27775
+ if (node.type.name === "table") {
27776
+ return {
27777
+ table: node,
27778
+ tablePos: $pos.before(depth),
27779
+ tableStart: $pos.start(depth)
27780
+ };
27781
+ }
27782
+ }
27783
+ return null;
27784
+ }
27785
+ function getFocusableCellPos(editor, cellPos) {
27786
+ const cellNode = editor.state.doc.nodeAt(cellPos);
27787
+ if (!cellNode) return cellPos + 1;
27788
+ let offset = cellPos + 1;
27789
+ let node = cellNode.firstChild ?? null;
27790
+ while (node && !node.isTextblock) {
27791
+ offset += 1;
27792
+ node = node.firstChild ?? null;
27793
+ }
27794
+ return node?.isTextblock ? offset + 1 : cellPos + 1;
27795
+ }
27796
+ function focusCell(editor, cellPos) {
27797
+ const selection = TextSelection2.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
27798
+ editor.view.dispatch(editor.state.tr.setSelection(selection));
27799
+ editor.view.focus();
27800
+ }
27801
+ function collectChildren(node) {
27802
+ const children = [];
27803
+ node.forEach((child) => children.push(child));
27804
+ return children;
27805
+ }
27806
+ function createEmptyCellNode(cellNode) {
27807
+ return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
27808
+ }
27809
+ function getSelectedTableRect(editor) {
27810
+ const cellSelection = getCellSelectionPositions(editor.state.selection);
27811
+ if (cellSelection) {
27812
+ const tableInfo = findTableInfoFromCellPos(editor, cellSelection.anchor);
27813
+ if (tableInfo) {
27814
+ const map = TableMap.get(tableInfo.table);
27815
+ const rect = map.rectBetween(
27816
+ cellSelection.anchor - tableInfo.tableStart,
27817
+ cellSelection.head - tableInfo.tableStart
27818
+ );
27819
+ return {
27820
+ ...rect,
27821
+ map,
27822
+ table: tableInfo.table,
27823
+ tableStart: tableInfo.tableStart
27824
+ };
27825
+ }
27826
+ }
27827
+ return selectedRect(editor.state);
27828
+ }
27829
+ function parsePixelWidth(value) {
27830
+ if (!value) return null;
27831
+ const parsed = Number.parseFloat(value);
27832
+ return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : null;
27833
+ }
27834
+ function getDomColumnWidths(editor, rect) {
27835
+ const tableDom = editor.view.nodeDOM(rect.tableStart - 1);
27836
+ if (!(tableDom instanceof HTMLTableElement)) return null;
27837
+ const cols = Array.from(tableDom.querySelectorAll("colgroup > col"));
27838
+ if (cols.length === 0) return null;
27839
+ const widths = [];
27840
+ for (let col = rect.left; col < rect.right; col += 1) {
27841
+ const colElement = cols[col];
27842
+ if (!colElement) return null;
27843
+ const width = parsePixelWidth(colElement.style.width) ?? parsePixelWidth(colElement.getAttribute("width")) ?? Math.round(colElement.getBoundingClientRect().width);
27844
+ if (!Number.isFinite(width) || width <= 0) return null;
27845
+ widths.push(width);
27846
+ }
27847
+ return widths.length > 0 ? widths : null;
27848
+ }
27849
+ function getNodeColumnWidths(rect) {
27850
+ const widths = [];
27851
+ for (let col = rect.left; col < rect.right; col += 1) {
27852
+ let width = null;
27853
+ const seen = /* @__PURE__ */ new Set();
27854
+ for (let row = 0; row < rect.map.height && width == null; row += 1) {
27855
+ const cellPos = rect.map.map[row * rect.map.width + col];
27856
+ if (seen.has(cellPos)) continue;
27857
+ seen.add(cellPos);
27858
+ const cell = rect.table.nodeAt(cellPos);
27859
+ const colwidth = cell?.attrs.colwidth;
27860
+ if (!Array.isArray(colwidth)) continue;
27861
+ const cellLeft = rect.map.colCount(cellPos);
27862
+ const widthIndex = col - cellLeft;
27863
+ const candidate = colwidth[widthIndex];
27864
+ if (typeof candidate === "number" && candidate > 0) {
27865
+ width = candidate;
27866
+ }
27867
+ }
27868
+ if (width == null) return null;
27869
+ widths.push(width);
27870
+ }
27871
+ return widths.length > 0 ? widths : null;
27872
+ }
27873
+ function getSelectedColumnWidths(editor, rect) {
27874
+ return getDomColumnWidths(editor, rect) ?? getNodeColumnWidths(rect);
27875
+ }
27876
+ function dispatchTableLayoutChange(editor) {
27877
+ editor.view.dom.dispatchEvent(new CustomEvent(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, { bubbles: true }));
27878
+ }
27879
+ function mergeTableCellsPreservingColumnWidths(editor) {
27880
+ const rect = getSelectedTableRect(editor);
27881
+ const widths = getSelectedColumnWidths(editor, rect);
27882
+ const merged = editor.chain().focus().mergeCells().run();
27883
+ if (!merged) return merged;
27884
+ if (!widths) {
27885
+ dispatchTableLayoutChange(editor);
27886
+ return merged;
27887
+ }
27888
+ const nextRect = getSelectedTableRect(editor);
27889
+ const cellPos = nextRect.map.map[nextRect.top * nextRect.map.width + nextRect.left];
27890
+ const absolutePos = nextRect.tableStart + cellPos;
27891
+ const node = editor.state.doc.nodeAt(absolutePos);
27892
+ if (!node) return merged;
27893
+ editor.view.dispatch(
27894
+ editor.state.tr.setNodeMarkup(absolutePos, node.type, {
27895
+ ...node.attrs,
27896
+ colwidth: widths
27897
+ })
27898
+ );
27899
+ dispatchTableLayoutChange(editor);
27900
+ return true;
27901
+ }
27902
+ function runTableCommandAtCellPos(editor, cellPos, command) {
27903
+ if (cellPos == null) return false;
27904
+ focusCell(editor, cellPos);
27905
+ return command(editor.chain().focus(null, { scrollIntoView: false })).run();
27906
+ }
27907
+ function getTableCornerCellPos(editor, activePos) {
27908
+ const tableInfo = findTableInfoFromCellPos(editor, activePos);
27909
+ if (!tableInfo) return null;
27910
+ const map = TableMap.get(tableInfo.table);
27911
+ return tableInfo.tableStart + map.positionAt(map.height - 1, map.width - 1, tableInfo.table);
27912
+ }
27913
+ function replaceTableAtCellPos(editor, cellPos, updateTable) {
27914
+ if (cellPos == null) return false;
27915
+ const tableInfo = findTableInfoFromCellPos(editor, cellPos);
27916
+ if (!tableInfo) return false;
27917
+ const nextTable = updateTable(tableInfo.table);
27918
+ if (!nextTable) return false;
27919
+ editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.tablePos, tableInfo.tablePos + tableInfo.table.nodeSize, nextTable));
27920
+ dispatchTableLayoutChange(editor);
27921
+ return true;
27922
+ }
27923
+ function duplicateTableRowAt(editor, rowIndex, cellPos) {
27924
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27925
+ const rows = collectChildren(tableNode);
27926
+ const rowNode = rows[rowIndex];
27927
+ if (!rowNode) return null;
27928
+ rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
27929
+ return tableNode.type.create(tableNode.attrs, rows);
27930
+ });
27931
+ }
27932
+ function clearTableRowAt(editor, rowIndex, cellPos) {
27933
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27934
+ const rows = collectChildren(tableNode);
27935
+ const rowNode = rows[rowIndex];
27936
+ if (!rowNode) return null;
27937
+ const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
27938
+ rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
27939
+ return tableNode.type.create(tableNode.attrs, rows);
27940
+ });
27941
+ }
27942
+ function duplicateTableColumnAt(editor, columnIndex, cellPos) {
27943
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27944
+ const rows = collectChildren(tableNode).map((rowNode) => {
27945
+ const cells = collectChildren(rowNode);
27946
+ const cellNode = cells[columnIndex];
27947
+ if (!cellNode) return rowNode;
27948
+ cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
27949
+ return rowNode.type.create(rowNode.attrs, cells);
27950
+ });
27951
+ return tableNode.type.create(tableNode.attrs, rows);
27952
+ });
27953
+ }
27954
+ function clearTableColumnAt(editor, columnIndex, cellPos) {
27955
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27956
+ const rows = collectChildren(tableNode).map((rowNode) => {
27957
+ const cells = collectChildren(rowNode);
27958
+ const cellNode = cells[columnIndex];
27959
+ if (!cellNode) return rowNode;
27960
+ cells[columnIndex] = createEmptyCellNode(cellNode);
27961
+ return rowNode.type.create(rowNode.attrs, cells);
27962
+ });
27963
+ return tableNode.type.create(tableNode.attrs, rows);
27964
+ });
27965
+ }
27966
+ function expandTableFromCell(editor, activeCellPos, rows, columns) {
27967
+ let cornerCellPos = getTableCornerCellPos(editor, activeCellPos);
27968
+ if (cornerCellPos == null) return false;
27969
+ for (let index = 0; index < rows; index += 1) {
27970
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addRowAfter());
27971
+ if (!ok) return false;
27972
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
27973
+ if (cornerCellPos == null) return false;
27974
+ }
27975
+ for (let index = 0; index < columns; index += 1) {
27976
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addColumnAfter());
27977
+ if (!ok) return false;
27978
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
27979
+ if (cornerCellPos == null) return false;
27980
+ }
27981
+ dispatchTableLayoutChange(editor);
27982
+ return true;
27983
+ }
27984
+
27710
27985
  // src/components/UEditor/typography-options.ts
27711
27986
  function normalizeStyleValue(value) {
27712
27987
  return typeof value === "string" ? value.trim().replace(/^['"]|['"]$/g, "") : "";
@@ -27902,6 +28177,8 @@ var EditorToolbar = ({
27902
28177
  const currentTableAlign = tableAlignAttr === "center" || tableAlignAttr === "right" ? tableAlignAttr : "left";
27903
28178
  const isTableSelected = tableInfo !== null;
27904
28179
  const hasTableContext = isTableSelected || tableCommandAnchorPosRef.current !== null;
28180
+ const canMergeCells = hasTableContext && editor.can().mergeCells();
28181
+ const canSplitCell = hasTableContext && editor.can().splitCell();
27905
28182
  const currentFontFamily = normalizeStyleValue(textStyleAttrs.fontFamily);
27906
28183
  const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
27907
28184
  const currentTextColor = normalizeStyleValue(textStyleAttrs.color) || "inherit";
@@ -28577,409 +28854,187 @@ var EditorToolbar = ({
28577
28854
  {
28578
28855
  icon: AlignRight,
28579
28856
  label: t("tableMenu.alignRight"),
28580
- onClick: () => applyTableAlignment(editor, "right", tableCommandAnchorPos),
28581
- active: hasTableContext && currentTableAlign === "right",
28582
- disabled: !hasTableContext
28583
- }
28584
- ),
28585
- /* @__PURE__ */ jsx85("div", { className: "my-1 border-t" }),
28586
- /* @__PURE__ */ jsx85(
28587
- DropdownMenuItem,
28588
- {
28589
- icon: ArrowLeft,
28590
- label: t("tableMenu.addColumnBefore"),
28591
- onClick: () => editor.chain().focus().addColumnBefore().run(),
28592
- disabled: !hasTableContext || !editor.can().addColumnBefore()
28593
- }
28594
- ),
28595
- /* @__PURE__ */ jsx85(
28596
- DropdownMenuItem,
28597
- {
28598
- icon: ArrowDown,
28599
- label: t("tableMenu.addColumnAfter"),
28600
- onClick: () => editor.chain().focus().addColumnAfter().run(),
28601
- disabled: !hasTableContext || !editor.can().addColumnAfter()
28602
- }
28603
- ),
28604
- /* @__PURE__ */ jsx85(
28605
- DropdownMenuItem,
28606
- {
28607
- icon: ArrowUp,
28608
- label: t("tableMenu.addRowBefore"),
28609
- onClick: () => editor.chain().focus().addRowBefore().run(),
28610
- disabled: !hasTableContext || !editor.can().addRowBefore()
28611
- }
28612
- ),
28613
- /* @__PURE__ */ jsx85(
28614
- DropdownMenuItem,
28615
- {
28616
- icon: ArrowRight,
28617
- label: t("tableMenu.addRowAfter"),
28618
- onClick: () => editor.chain().focus().addRowAfter().run(),
28619
- disabled: !hasTableContext || !editor.can().addRowAfter()
28620
- }
28621
- ),
28622
- /* @__PURE__ */ jsx85("div", { className: "my-1 border-t" }),
28623
- /* @__PURE__ */ jsx85(
28624
- DropdownMenuItem,
28625
- {
28626
- icon: TableIcon,
28627
- label: t("tableMenu.toggleHeaderRow"),
28628
- onClick: () => editor.chain().focus().toggleHeaderRow().run(),
28629
- disabled: !hasTableContext || !editor.can().toggleHeaderRow()
28630
- }
28631
- ),
28632
- /* @__PURE__ */ jsx85(
28633
- DropdownMenuItem,
28634
- {
28635
- icon: TableIcon,
28636
- label: t("tableMenu.toggleHeaderColumn"),
28637
- onClick: () => editor.chain().focus().toggleHeaderColumn().run(),
28638
- disabled: !hasTableContext || !editor.can().toggleHeaderColumn()
28639
- }
28640
- ),
28641
- /* @__PURE__ */ jsx85("div", { className: "my-1 border-t" }),
28642
- /* @__PURE__ */ jsx85(
28643
- DropdownMenuItem,
28644
- {
28645
- icon: Trash22,
28646
- label: t("tableMenu.deleteColumn"),
28647
- onClick: () => editor.chain().focus().deleteColumn().run(),
28648
- disabled: !hasTableContext || !editor.can().deleteColumn()
28649
- }
28650
- ),
28651
- /* @__PURE__ */ jsx85(
28652
- DropdownMenuItem,
28653
- {
28654
- icon: Trash22,
28655
- label: t("tableMenu.deleteRow"),
28656
- onClick: () => editor.chain().focus().deleteRow().run(),
28657
- disabled: !hasTableContext || !editor.can().deleteRow()
28658
- }
28659
- ),
28660
- /* @__PURE__ */ jsx85(
28661
- DropdownMenuItem,
28662
- {
28663
- icon: Trash22,
28664
- label: t("tableMenu.deleteTable"),
28665
- onClick: () => editor.chain().focus().deleteTable().run(),
28666
- disabled: !hasTableContext || !editor.can().deleteTable()
28667
- }
28668
- )
28669
- ]
28670
- }
28671
- ),
28672
- /* @__PURE__ */ jsx85(ToolbarDivider, {}),
28673
- /* @__PURE__ */ jsx85(ToolbarButton, { onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: t("toolbar.undo"), children: /* @__PURE__ */ jsx85(UndoIcon, { className: "w-4 h-4" }) }),
28674
- /* @__PURE__ */ jsx85(ToolbarButton, { onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: t("toolbar.redo"), children: /* @__PURE__ */ jsx85(RedoIcon, { className: "w-4 h-4" }) })
28675
- ] });
28676
- };
28677
-
28678
- // src/components/UEditor/menus.tsx
28679
- import { useCallback as useCallback22, useEffect as useEffect36, useMemo as useMemo23, useRef as useRef33, useState as useState48 } from "react";
28680
- import { useEditorState as useEditorState2 } from "@tiptap/react";
28681
- import { isInTable as isSelectionInTable, setCellAttr } from "@tiptap/pm/tables";
28682
- import { createPortal as createPortal8 } from "react-dom";
28683
- import {
28684
- AlignCenter as AlignCenter2,
28685
- AlignLeft as AlignLeft2,
28686
- AlignRight as AlignRight2,
28687
- Bold as BoldIcon2,
28688
- ChevronDown as ChevronDown9,
28689
- Code as CodeIcon2,
28690
- Italic as ItalicIcon2,
28691
- Link as LinkIcon2,
28692
- Plus as Plus3,
28693
- RotateCcw as RotateCcw3,
28694
- Subscript as SubscriptIcon2,
28695
- Superscript as SuperscriptIcon2,
28696
- TableCellsMerge,
28697
- Trash2 as Trash23,
28698
- Type as Type3,
28699
- Underline as UnderlineIcon2,
28700
- Strikethrough as StrikethroughIcon2,
28701
- Edit2,
28702
- Unlink,
28703
- ExternalLink as ExternalLink3
28704
- } from "lucide-react";
28705
-
28706
- // src/components/UEditor/table-cell-commands.ts
28707
- import { TextSelection as TextSelection2 } from "@tiptap/pm/state";
28708
- import { selectedRect, TableMap } from "@tiptap/pm/tables";
28709
- function getCellSelectionPositions(selection) {
28710
- const value = selection;
28711
- const anchor = value.$anchorCell?.pos;
28712
- const head = value.$headCell?.pos;
28713
- return typeof anchor === "number" && typeof head === "number" ? { anchor, head } : null;
28714
- }
28715
- function findTableInfoFromCellPos(editor, cellPos) {
28716
- const $pos = editor.state.doc.resolve(cellPos);
28717
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
28718
- const node = $pos.node(depth);
28719
- if (node.type.name === "table") {
28720
- return {
28721
- table: node,
28722
- tablePos: $pos.before(depth),
28723
- tableStart: $pos.start(depth)
28724
- };
28725
- }
28726
- }
28727
- return null;
28728
- }
28729
- function getFocusableCellPos(editor, cellPos) {
28730
- const cellNode = editor.state.doc.nodeAt(cellPos);
28731
- if (!cellNode) return cellPos + 1;
28732
- let offset = cellPos + 1;
28733
- let node = cellNode.firstChild ?? null;
28734
- while (node && !node.isTextblock) {
28735
- offset += 1;
28736
- node = node.firstChild ?? null;
28737
- }
28738
- return node?.isTextblock ? offset + 1 : cellPos + 1;
28739
- }
28740
- function focusCell(editor, cellPos) {
28741
- const selection = TextSelection2.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
28742
- editor.view.dispatch(editor.state.tr.setSelection(selection));
28743
- editor.view.focus();
28744
- }
28745
- function collectChildren(node) {
28746
- const children = [];
28747
- node.forEach((child) => children.push(child));
28748
- return children;
28749
- }
28750
- function createEmptyCellNode(cellNode) {
28751
- return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
28752
- }
28753
- function getSelectedTableRect(editor) {
28754
- const cellSelection = getCellSelectionPositions(editor.state.selection);
28755
- if (cellSelection) {
28756
- const tableInfo = findTableInfoFromCellPos(editor, cellSelection.anchor);
28757
- if (tableInfo) {
28758
- const map = TableMap.get(tableInfo.table);
28759
- const rect = map.rectBetween(
28760
- cellSelection.anchor - tableInfo.tableStart,
28761
- cellSelection.head - tableInfo.tableStart
28762
- );
28763
- return {
28764
- ...rect,
28765
- map,
28766
- table: tableInfo.table,
28767
- tableStart: tableInfo.tableStart
28768
- };
28769
- }
28770
- }
28771
- return selectedRect(editor.state);
28772
- }
28773
- function parsePixelWidth(value) {
28774
- if (!value) return null;
28775
- const parsed = Number.parseFloat(value);
28776
- return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : null;
28777
- }
28778
- function getDomColumnWidths(editor, rect) {
28779
- const tableDom = editor.view.nodeDOM(rect.tableStart - 1);
28780
- if (!(tableDom instanceof HTMLTableElement)) return null;
28781
- const cols = Array.from(tableDom.querySelectorAll("colgroup > col"));
28782
- if (cols.length === 0) return null;
28783
- const widths = [];
28784
- for (let col = rect.left; col < rect.right; col += 1) {
28785
- const colElement = cols[col];
28786
- if (!colElement) return null;
28787
- const width = parsePixelWidth(colElement.style.width) ?? parsePixelWidth(colElement.getAttribute("width")) ?? Math.round(colElement.getBoundingClientRect().width);
28788
- if (!Number.isFinite(width) || width <= 0) return null;
28789
- widths.push(width);
28790
- }
28791
- return widths.length > 0 ? widths : null;
28792
- }
28793
- function getNodeColumnWidths(rect) {
28794
- const widths = [];
28795
- for (let col = rect.left; col < rect.right; col += 1) {
28796
- let width = null;
28797
- const seen = /* @__PURE__ */ new Set();
28798
- for (let row = 0; row < rect.map.height && width == null; row += 1) {
28799
- const cellPos = rect.map.map[row * rect.map.width + col];
28800
- if (seen.has(cellPos)) continue;
28801
- seen.add(cellPos);
28802
- const cell = rect.table.nodeAt(cellPos);
28803
- const colwidth = cell?.attrs.colwidth;
28804
- if (!Array.isArray(colwidth)) continue;
28805
- const cellLeft = rect.map.colCount(cellPos);
28806
- const widthIndex = col - cellLeft;
28807
- const candidate = colwidth[widthIndex];
28808
- if (typeof candidate === "number" && candidate > 0) {
28809
- width = candidate;
28810
- }
28811
- }
28812
- if (width == null) return null;
28813
- widths.push(width);
28814
- }
28815
- return widths.length > 0 ? widths : null;
28816
- }
28817
- function getSelectedColumnWidths(editor, rect) {
28818
- return getDomColumnWidths(editor, rect) ?? getNodeColumnWidths(rect);
28819
- }
28820
- function dispatchTableLayoutChange(editor) {
28821
- editor.view.dom.dispatchEvent(new CustomEvent(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, { bubbles: true }));
28822
- }
28823
- function mergeTableCellsPreservingColumnWidths(editor) {
28824
- const rect = getSelectedTableRect(editor);
28825
- const widths = getSelectedColumnWidths(editor, rect);
28826
- const merged = editor.chain().focus().mergeCells().run();
28827
- if (!merged) return merged;
28828
- if (!widths) {
28829
- dispatchTableLayoutChange(editor);
28830
- return merged;
28831
- }
28832
- const nextRect = getSelectedTableRect(editor);
28833
- const cellPos = nextRect.map.map[nextRect.top * nextRect.map.width + nextRect.left];
28834
- const absolutePos = nextRect.tableStart + cellPos;
28835
- const node = editor.state.doc.nodeAt(absolutePos);
28836
- if (!node) return merged;
28837
- editor.view.dispatch(
28838
- editor.state.tr.setNodeMarkup(absolutePos, node.type, {
28839
- ...node.attrs,
28840
- colwidth: widths
28841
- })
28842
- );
28843
- dispatchTableLayoutChange(editor);
28844
- return true;
28845
- }
28846
- function runTableCommandAtCellPos(editor, cellPos, command) {
28847
- if (cellPos == null) return false;
28848
- focusCell(editor, cellPos);
28849
- return command(editor.chain().focus(null, { scrollIntoView: false })).run();
28850
- }
28851
- function getTableCornerCellPos(editor, activePos) {
28852
- const tableInfo = findTableInfoFromCellPos(editor, activePos);
28853
- if (!tableInfo) return null;
28854
- const map = TableMap.get(tableInfo.table);
28855
- return tableInfo.tableStart + map.positionAt(map.height - 1, map.width - 1, tableInfo.table);
28856
- }
28857
- function replaceTableAtCellPos(editor, cellPos, updateTable) {
28858
- if (cellPos == null) return false;
28859
- const tableInfo = findTableInfoFromCellPos(editor, cellPos);
28860
- if (!tableInfo) return false;
28861
- const nextTable = updateTable(tableInfo.table);
28862
- if (!nextTable) return false;
28863
- editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.tablePos, tableInfo.tablePos + tableInfo.table.nodeSize, nextTable));
28864
- dispatchTableLayoutChange(editor);
28865
- return true;
28866
- }
28867
- function duplicateTableRowAt(editor, rowIndex, cellPos) {
28868
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28869
- const rows = collectChildren(tableNode);
28870
- const rowNode = rows[rowIndex];
28871
- if (!rowNode) return null;
28872
- rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
28873
- return tableNode.type.create(tableNode.attrs, rows);
28874
- });
28875
- }
28876
- function clearTableRowAt(editor, rowIndex, cellPos) {
28877
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28878
- const rows = collectChildren(tableNode);
28879
- const rowNode = rows[rowIndex];
28880
- if (!rowNode) return null;
28881
- const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
28882
- rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
28883
- return tableNode.type.create(tableNode.attrs, rows);
28884
- });
28885
- }
28886
- function duplicateTableColumnAt(editor, columnIndex, cellPos) {
28887
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28888
- const rows = collectChildren(tableNode).map((rowNode) => {
28889
- const cells = collectChildren(rowNode);
28890
- const cellNode = cells[columnIndex];
28891
- if (!cellNode) return rowNode;
28892
- cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
28893
- return rowNode.type.create(rowNode.attrs, cells);
28894
- });
28895
- return tableNode.type.create(tableNode.attrs, rows);
28896
- });
28897
- }
28898
- function clearTableColumnAt(editor, columnIndex, cellPos) {
28899
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28900
- const rows = collectChildren(tableNode).map((rowNode) => {
28901
- const cells = collectChildren(rowNode);
28902
- const cellNode = cells[columnIndex];
28903
- if (!cellNode) return rowNode;
28904
- cells[columnIndex] = createEmptyCellNode(cellNode);
28905
- return rowNode.type.create(rowNode.attrs, cells);
28906
- });
28907
- return tableNode.type.create(tableNode.attrs, rows);
28908
- });
28909
- }
28910
- function expandTableFromCell(editor, activeCellPos, rows, columns) {
28911
- let cornerCellPos = getTableCornerCellPos(editor, activeCellPos);
28912
- if (cornerCellPos == null) return false;
28913
- for (let index = 0; index < rows; index += 1) {
28914
- const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addRowAfter());
28915
- if (!ok) return false;
28916
- cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28917
- if (cornerCellPos == null) return false;
28918
- }
28919
- for (let index = 0; index < columns; index += 1) {
28920
- const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addColumnAfter());
28921
- if (!ok) return false;
28922
- cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28923
- if (cornerCellPos == null) return false;
28924
- }
28925
- dispatchTableLayoutChange(editor);
28926
- return true;
28927
- }
28857
+ onClick: () => applyTableAlignment(editor, "right", tableCommandAnchorPos),
28858
+ active: hasTableContext && currentTableAlign === "right",
28859
+ disabled: !hasTableContext
28860
+ }
28861
+ ),
28862
+ /* @__PURE__ */ jsx85("div", { className: "my-1 border-t" }),
28863
+ /* @__PURE__ */ jsx85(
28864
+ DropdownMenuItem,
28865
+ {
28866
+ icon: ArrowLeft,
28867
+ label: t("tableMenu.addColumnBefore"),
28868
+ onClick: () => editor.chain().focus().addColumnBefore().run(),
28869
+ disabled: !hasTableContext || !editor.can().addColumnBefore()
28870
+ }
28871
+ ),
28872
+ /* @__PURE__ */ jsx85(
28873
+ DropdownMenuItem,
28874
+ {
28875
+ icon: ArrowDown,
28876
+ label: t("tableMenu.addColumnAfter"),
28877
+ onClick: () => editor.chain().focus().addColumnAfter().run(),
28878
+ disabled: !hasTableContext || !editor.can().addColumnAfter()
28879
+ }
28880
+ ),
28881
+ /* @__PURE__ */ jsx85(
28882
+ DropdownMenuItem,
28883
+ {
28884
+ icon: ArrowUp,
28885
+ label: t("tableMenu.addRowBefore"),
28886
+ onClick: () => editor.chain().focus().addRowBefore().run(),
28887
+ disabled: !hasTableContext || !editor.can().addRowBefore()
28888
+ }
28889
+ ),
28890
+ /* @__PURE__ */ jsx85(
28891
+ DropdownMenuItem,
28892
+ {
28893
+ icon: ArrowRight,
28894
+ label: t("tableMenu.addRowAfter"),
28895
+ onClick: () => editor.chain().focus().addRowAfter().run(),
28896
+ disabled: !hasTableContext || !editor.can().addRowAfter()
28897
+ }
28898
+ ),
28899
+ /* @__PURE__ */ jsx85("div", { className: "my-1 border-t" }),
28900
+ /* @__PURE__ */ jsx85(
28901
+ DropdownMenuItem,
28902
+ {
28903
+ icon: TableIcon,
28904
+ label: t("tableMenu.toggleHeaderRow"),
28905
+ onClick: () => editor.chain().focus().toggleHeaderRow().run(),
28906
+ disabled: !hasTableContext || !editor.can().toggleHeaderRow()
28907
+ }
28908
+ ),
28909
+ /* @__PURE__ */ jsx85(
28910
+ DropdownMenuItem,
28911
+ {
28912
+ icon: TableIcon,
28913
+ label: t("tableMenu.toggleHeaderColumn"),
28914
+ onClick: () => editor.chain().focus().toggleHeaderColumn().run(),
28915
+ disabled: !hasTableContext || !editor.can().toggleHeaderColumn()
28916
+ }
28917
+ ),
28918
+ /* @__PURE__ */ jsx85("div", { className: "my-1 border-t" }),
28919
+ /* @__PURE__ */ jsx85(
28920
+ DropdownMenuItem,
28921
+ {
28922
+ icon: Trash22,
28923
+ label: t("tableMenu.deleteColumn"),
28924
+ onClick: () => editor.chain().focus().deleteColumn().run(),
28925
+ disabled: !hasTableContext || !editor.can().deleteColumn()
28926
+ }
28927
+ ),
28928
+ /* @__PURE__ */ jsx85(
28929
+ DropdownMenuItem,
28930
+ {
28931
+ icon: Trash22,
28932
+ label: t("tableMenu.deleteRow"),
28933
+ onClick: () => editor.chain().focus().deleteRow().run(),
28934
+ disabled: !hasTableContext || !editor.can().deleteRow()
28935
+ }
28936
+ ),
28937
+ /* @__PURE__ */ jsx85(
28938
+ DropdownMenuItem,
28939
+ {
28940
+ icon: Trash22,
28941
+ label: t("tableMenu.deleteTable"),
28942
+ onClick: () => editor.chain().focus().deleteTable().run(),
28943
+ disabled: !hasTableContext || !editor.can().deleteTable()
28944
+ }
28945
+ )
28946
+ ]
28947
+ }
28948
+ ),
28949
+ /* @__PURE__ */ jsx85(ToolbarDivider, {}),
28950
+ /* @__PURE__ */ jsx85(ToolbarButton, { onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: t("toolbar.undo"), children: /* @__PURE__ */ jsx85(UndoIcon, { className: "w-4 h-4" }) }),
28951
+ /* @__PURE__ */ jsx85(ToolbarButton, { onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: t("toolbar.redo"), children: /* @__PURE__ */ jsx85(RedoIcon, { className: "w-4 h-4" }) }),
28952
+ hasTableContext && /* @__PURE__ */ jsxs71(Fragment28, { children: [
28953
+ /* @__PURE__ */ jsx85(ToolbarDivider, {}),
28954
+ /* @__PURE__ */ jsx85(
28955
+ ToolbarButton,
28956
+ {
28957
+ onClick: () => editor.chain().focus().addColumnBefore().run(),
28958
+ disabled: !editor.can().addColumnBefore(),
28959
+ title: t("tableMenu.addColumnBefore"),
28960
+ children: /* @__PURE__ */ jsx85(ArrowLeft, { className: "w-4 h-4" })
28961
+ }
28962
+ ),
28963
+ /* @__PURE__ */ jsx85(
28964
+ ToolbarButton,
28965
+ {
28966
+ onClick: () => editor.chain().focus().addColumnAfter().run(),
28967
+ disabled: !editor.can().addColumnAfter(),
28968
+ title: t("tableMenu.addColumnAfter"),
28969
+ children: /* @__PURE__ */ jsx85(ArrowRight, { className: "w-4 h-4" })
28970
+ }
28971
+ ),
28972
+ /* @__PURE__ */ jsx85(
28973
+ ToolbarButton,
28974
+ {
28975
+ onClick: () => editor.chain().focus().addRowBefore().run(),
28976
+ disabled: !editor.can().addRowBefore(),
28977
+ title: t("tableMenu.addRowBefore"),
28978
+ children: /* @__PURE__ */ jsx85(ArrowUp, { className: "w-4 h-4" })
28979
+ }
28980
+ ),
28981
+ /* @__PURE__ */ jsx85(
28982
+ ToolbarButton,
28983
+ {
28984
+ onClick: () => editor.chain().focus().addRowAfter().run(),
28985
+ disabled: !editor.can().addRowAfter(),
28986
+ title: t("tableMenu.addRowAfter"),
28987
+ children: /* @__PURE__ */ jsx85(ArrowDown, { className: "w-4 h-4" })
28988
+ }
28989
+ ),
28990
+ /* @__PURE__ */ jsx85(
28991
+ ToolbarButton,
28992
+ {
28993
+ onClick: () => {
28994
+ if (canSplitCell) {
28995
+ editor.chain().focus().splitCell().run();
28996
+ return;
28997
+ }
28998
+ mergeTableCellsPreservingColumnWidths(editor);
28999
+ },
29000
+ active: canSplitCell,
29001
+ disabled: !canMergeCells && !canSplitCell,
29002
+ title: canSplitCell ? t("tableMenu.splitCell") : t("tableMenu.mergeCells"),
29003
+ children: /* @__PURE__ */ jsx85(TableCellsMerge, { className: "w-4 h-4" })
29004
+ }
29005
+ )
29006
+ ] })
29007
+ ] });
29008
+ };
28928
29009
 
28929
29010
  // src/components/UEditor/menus.tsx
29011
+ import { useCallback as useCallback22, useEffect as useEffect36, useMemo as useMemo23, useRef as useRef33, useState as useState48 } from "react";
29012
+ import { useEditorState as useEditorState2 } from "@tiptap/react";
29013
+ import { isInTable as isSelectionInTable, setCellAttr } from "@tiptap/pm/tables";
29014
+ import { createPortal as createPortal8 } from "react-dom";
29015
+ import {
29016
+ AlignCenter as AlignCenter2,
29017
+ AlignLeft as AlignLeft2,
29018
+ AlignRight as AlignRight2,
29019
+ Bold as BoldIcon2,
29020
+ ChevronDown as ChevronDown9,
29021
+ Code as CodeIcon2,
29022
+ Italic as ItalicIcon2,
29023
+ Link as LinkIcon2,
29024
+ Plus as Plus3,
29025
+ RotateCcw as RotateCcw3,
29026
+ Subscript as SubscriptIcon2,
29027
+ Superscript as SuperscriptIcon2,
29028
+ TableCellsMerge as TableCellsMerge2,
29029
+ Trash2 as Trash23,
29030
+ Type as Type3,
29031
+ Underline as UnderlineIcon2,
29032
+ Strikethrough as StrikethroughIcon2,
29033
+ Edit2,
29034
+ Unlink,
29035
+ ExternalLink as ExternalLink3
29036
+ } from "lucide-react";
28930
29037
  import { Fragment as Fragment29, jsx as jsx86, jsxs as jsxs72 } from "react/jsx-runtime";
28931
- var FloatingSlashCommandMenu = ({ editor, onClose }) => {
28932
- const t = useSmartTranslations("UEditor");
28933
- const messages = useMemo23(() => buildSlashCommandMessages(t), [t]);
28934
- const items = useMemo23(() => buildSlashCommandItems({ query: "", messages }), [messages]);
28935
- const listRef = useRef33(null);
28936
- useEffect36(() => {
28937
- const handleKeyDown2 = (event) => {
28938
- if (event.key === "Escape") {
28939
- event.preventDefault();
28940
- onClose();
28941
- return;
28942
- }
28943
- const handled = listRef.current?.onKeyDown({ event }) ?? false;
28944
- if (handled) {
28945
- event.preventDefault();
28946
- }
28947
- };
28948
- document.addEventListener("keydown", handleKeyDown2);
28949
- return () => document.removeEventListener("keydown", handleKeyDown2);
28950
- }, [onClose]);
28951
- return /* @__PURE__ */ jsx86(
28952
- SlashCommandList,
28953
- {
28954
- ref: listRef,
28955
- items,
28956
- messages,
28957
- command: (item) => {
28958
- item.command({ editor });
28959
- onClose();
28960
- }
28961
- }
28962
- );
28963
- };
28964
- var FloatingMenuContent = ({ editor }) => {
28965
- const t = useSmartTranslations("UEditor");
28966
- const [showCommands, setShowCommands] = useState48(false);
28967
- if (showCommands) {
28968
- return /* @__PURE__ */ jsx86(FloatingSlashCommandMenu, { editor, onClose: () => setShowCommands(false) });
28969
- }
28970
- return /* @__PURE__ */ jsxs72(
28971
- "button",
28972
- {
28973
- type: "button",
28974
- onClick: () => setShowCommands(true),
28975
- className: "flex items-center gap-1 px-2 py-1.5 rounded-lg hover:bg-accent transition-all group",
28976
- children: [
28977
- /* @__PURE__ */ jsx86(Plus3, { className: "w-4 h-4 text-muted-foreground group-hover:text-foreground" }),
28978
- /* @__PURE__ */ jsx86("span", { className: "text-sm text-muted-foreground group-hover:text-foreground", children: t("floatingMenu.addBlock") })
28979
- ]
28980
- }
28981
- );
28982
- };
28983
29038
  function applyTableCellBackground(editor, color) {
28984
29039
  const value = color || null;
28985
29040
  const { state, view } = editor;
@@ -29463,7 +29518,7 @@ var BubbleMenuContent = ({
29463
29518
  active: canSplitCell,
29464
29519
  disabled: !canMergeCells && !canSplitCell,
29465
29520
  title: canSplitCell ? t("tableMenu.splitCell") || "Split cell" : t("tableMenu.mergeCells") || "Merge cells",
29466
- children: /* @__PURE__ */ jsx86(TableCellsMerge, { className: "w-4 h-4" })
29521
+ children: /* @__PURE__ */ jsx86(TableCellsMerge2, { className: "w-4 h-4" })
29467
29522
  }
29468
29523
  )
29469
29524
  ] }),
@@ -29606,54 +29661,6 @@ var CustomBubbleMenu = ({
29606
29661
  document.body
29607
29662
  );
29608
29663
  };
29609
- var CustomFloatingMenu = ({ editor }) => {
29610
- const FLOATING_MENU_OFFSET = 16;
29611
- const [isVisible, setIsVisible] = useState48(false);
29612
- const [position, setPosition] = useState48({ top: 0, left: 0 });
29613
- useEffect36(() => {
29614
- const updatePosition = () => {
29615
- const { state, view } = editor;
29616
- const { $from, empty } = state.selection;
29617
- const isEmptyTextBlock = $from.parent.isTextblock && $from.parent.type.name === "paragraph" && $from.parent.textContent === "" && empty;
29618
- if (!isEmptyTextBlock || !view.hasFocus()) {
29619
- setIsVisible(false);
29620
- return;
29621
- }
29622
- const coords = view.coordsAtPos($from.pos);
29623
- setPosition({ top: coords.top - FLOATING_MENU_OFFSET, left: coords.left });
29624
- setIsVisible(true);
29625
- };
29626
- const handleBlur = () => setIsVisible(false);
29627
- editor.on("selectionUpdate", updatePosition);
29628
- editor.on("focus", updatePosition);
29629
- editor.on("blur", handleBlur);
29630
- editor.on("update", updatePosition);
29631
- return () => {
29632
- editor.off("selectionUpdate", updatePosition);
29633
- editor.off("focus", updatePosition);
29634
- editor.off("blur", handleBlur);
29635
- editor.off("update", updatePosition);
29636
- };
29637
- }, [editor]);
29638
- if (!isVisible) return null;
29639
- return createPortal8(
29640
- /* @__PURE__ */ jsx86(
29641
- "div",
29642
- {
29643
- "data-popover": true,
29644
- className: "fixed z-99999 rounded-2xl border border-border/50 bg-card text-card-foreground shadow-lg backdrop-blur-sm overflow-hidden animate-in fade-in-0 slide-in-from-bottom-2",
29645
- style: {
29646
- top: `${position.top}px`,
29647
- left: `${position.left}px`,
29648
- transform: "translate(-50%, -100%)"
29649
- },
29650
- onMouseDown: (e) => e.preventDefault(),
29651
- children: /* @__PURE__ */ jsx86(FloatingMenuContent, { editor })
29652
- }
29653
- ),
29654
- document.body
29655
- );
29656
- };
29657
29664
 
29658
29665
  // src/components/UEditor/CharacterCount.tsx
29659
29666
  import { jsxs as jsxs73 } from "react/jsx-runtime";
@@ -34439,8 +34446,8 @@ function TableAddRails({
34439
34446
  const visibleTableHeight = Math.min(layout.tableHeight, layout.viewportHeight);
34440
34447
  const columnRailTop = layout.tableTop;
34441
34448
  const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
34442
- const rowRailTop = layout.tableTop + visibleTableHeight + ADD_ROW_RAIL_GAP;
34443
- const rowRailLeft = layout.tableLeft;
34449
+ const rowRailTop = layout.wrapperTop + layout.wrapperHeight + ADD_ROW_RAIL_GAP;
34450
+ const rowRailLeft = Math.max(layout.tableLeft, layout.wrapperLeft);
34444
34451
  const showColumnRail = controlsVisible || addColumnVisible;
34445
34452
  const showRowRail = controlsVisible || addRowVisible;
34446
34453
  return /* @__PURE__ */ jsxs75(Fragment32, { children: [
@@ -35070,6 +35077,7 @@ function TableControls({ editor, containerRef }) {
35070
35077
  const proseMirror = editor.view.dom;
35071
35078
  const surface = containerRef.current;
35072
35079
  if (!surface) return void 0;
35080
+ const scrollListenerOptions = { passive: true, capture: true };
35073
35081
  const handleMouseOver = (event) => {
35074
35082
  if (dragStateRef.current) return;
35075
35083
  const cell = getCellFromTarget(event.target);
@@ -35095,7 +35103,7 @@ function TableControls({ editor, containerRef }) {
35095
35103
  proseMirror.addEventListener("focusin", handleFocusIn);
35096
35104
  surface.addEventListener("mouseover", handleSurfaceMouseMove);
35097
35105
  surface.addEventListener("mousemove", handleSurfaceMouseMove);
35098
- surface.addEventListener("scroll", refreshCurrentLayout, { passive: true });
35106
+ surface.addEventListener("scroll", refreshCurrentLayout, scrollListenerOptions);
35099
35107
  surface.addEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, refreshCurrentLayout);
35100
35108
  window.addEventListener("resize", refreshCurrentLayout);
35101
35109
  editor.on("selectionUpdate", syncFromSelection);
@@ -35109,7 +35117,7 @@ function TableControls({ editor, containerRef }) {
35109
35117
  proseMirror.removeEventListener("focusin", handleFocusIn);
35110
35118
  surface.removeEventListener("mouseover", handleSurfaceMouseMove);
35111
35119
  surface.removeEventListener("mousemove", handleSurfaceMouseMove);
35112
- surface.removeEventListener("scroll", refreshCurrentLayout);
35120
+ surface.removeEventListener("scroll", refreshCurrentLayout, scrollListenerOptions);
35113
35121
  surface.removeEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, refreshCurrentLayout);
35114
35122
  window.removeEventListener("resize", refreshCurrentLayout);
35115
35123
  editor.off("selectionUpdate", syncFromSelection);
@@ -35550,6 +35558,7 @@ var UEDITOR_PROSEMIRROR_CLASS_NAME = cn(
35550
35558
  "[&_.tableWrapper::-webkit-scrollbar-thumb]:border-transparent",
35551
35559
  "[&_.tableWrapper::-webkit-scrollbar-thumb]:bg-border/70",
35552
35560
  "[&_.tableWrapper::-webkit-scrollbar-thumb:hover]:bg-muted-foreground/45",
35561
+ "[&_table]:w-auto",
35553
35562
  "[&_table]:table-fixed",
35554
35563
  "[&_table]:overflow-hidden",
35555
35564
  "[&_table]:select-text",
@@ -35578,7 +35587,7 @@ var UEDITOR_PROSEMIRROR_CLASS_NAME = cn(
35578
35587
  "[&_.column-resize-handle]:top-[-1px]",
35579
35588
  "[&_.column-resize-handle]:bottom-[-1px]",
35580
35589
  "[&_.column-resize-handle]:right-[-5px]",
35581
- "[&_.column-resize-handle]:z-10",
35590
+ "[&_.column-resize-handle]:z-30",
35582
35591
  "[&_.column-resize-handle]:w-2.5",
35583
35592
  "[&_.column-resize-handle]:bg-transparent",
35584
35593
  "[&_.column-resize-handle]:rounded-none",
@@ -35832,26 +35841,31 @@ function useUEditorTableInteractions(editor, editable = true) {
35832
35841
  const activeTableCellRef = useRef35(null);
35833
35842
  const suppressActiveCellHighlightRef = useRef35(false);
35834
35843
  const tableLayoutSyncFrameRef = useRef35(null);
35844
+ const getProseMirrorElement = React80.useCallback(() => {
35845
+ return editorContentRef.current?.querySelector(".ProseMirror");
35846
+ }, []);
35835
35847
  const setEditorResizeCursor = React80.useCallback((cursor) => {
35836
- const proseMirror = editorContentRef.current?.querySelector(".ProseMirror");
35848
+ const proseMirror = getProseMirrorElement();
35837
35849
  if (proseMirror) {
35838
35850
  proseMirror.style.cursor = cursor;
35839
35851
  }
35840
- }, []);
35852
+ }, [getProseMirrorElement]);
35841
35853
  const hideColumnGuide = React80.useCallback(() => {
35842
35854
  editorContentRef.current?.classList.remove("resize-cursor");
35855
+ getProseMirrorElement()?.classList.remove("resize-cursor");
35843
35856
  const guide = tableColumnGuideRef.current;
35844
35857
  if (guide) {
35845
35858
  guide.style.opacity = "0";
35846
35859
  }
35847
- }, []);
35860
+ }, [getProseMirrorElement]);
35848
35861
  const hideRowGuide = React80.useCallback(() => {
35849
35862
  editorContentRef.current?.classList.remove("resize-row-cursor");
35863
+ getProseMirrorElement()?.classList.remove("resize-row-cursor");
35850
35864
  const guide = tableRowGuideRef.current;
35851
35865
  if (guide) {
35852
35866
  guide.style.opacity = "0";
35853
35867
  }
35854
- }, []);
35868
+ }, [getProseMirrorElement]);
35855
35869
  const clearAllTableResizeHover = React80.useCallback(() => {
35856
35870
  setEditorResizeCursor("");
35857
35871
  hideColumnGuide();
@@ -35881,7 +35895,10 @@ function useUEditorTableInteractions(editor, editable = true) {
35881
35895
  });
35882
35896
  }, [updateActiveCellHighlight]);
35883
35897
  const setActiveTableCell = React80.useCallback((cell) => {
35884
- if (activeTableCellRef.current === cell) return;
35898
+ if (activeTableCellRef.current === cell) {
35899
+ updateActiveCellHighlight(cell);
35900
+ return;
35901
+ }
35885
35902
  activeTableCellRef.current = cell;
35886
35903
  updateActiveCellHighlight(activeTableCellRef.current);
35887
35904
  }, [updateActiveCellHighlight]);
@@ -35906,8 +35923,9 @@ function useUEditorTableInteractions(editor, editable = true) {
35906
35923
  guide.style.height = `${metrics.height}px`;
35907
35924
  guide.style.opacity = "1";
35908
35925
  surface.classList.add("resize-cursor");
35926
+ getProseMirrorElement()?.classList.add("resize-cursor");
35909
35927
  setEditorResizeCursor("col-resize");
35910
- }, [setEditorResizeCursor]);
35928
+ }, [getProseMirrorElement, setEditorResizeCursor]);
35911
35929
  const showRowGuide = React80.useCallback((table, row, cell) => {
35912
35930
  const surface = editorContentRef.current;
35913
35931
  const guide = tableRowGuideRef.current;
@@ -35919,8 +35937,9 @@ function useUEditorTableInteractions(editor, editable = true) {
35919
35937
  guide.style.height = `${ROW_RESIZE_LINE_THICKNESS}px`;
35920
35938
  guide.style.opacity = "1";
35921
35939
  surface.classList.add("resize-row-cursor");
35940
+ getProseMirrorElement()?.classList.add("resize-row-cursor");
35922
35941
  setEditorResizeCursor("row-resize");
35923
- }, [setEditorResizeCursor]);
35942
+ }, [getProseMirrorElement, setEditorResizeCursor]);
35924
35943
  const {
35925
35944
  beginResize,
35926
35945
  cancelResize,
@@ -35939,19 +35958,32 @@ function useUEditorTableInteractions(editor, editable = true) {
35939
35958
  });
35940
35959
  const syncActiveTableCellFromSelection = React80.useCallback(() => {
35941
35960
  if (!editor) return;
35961
+ if (!editor.isFocused) {
35962
+ clearActiveTableCell();
35963
+ return;
35964
+ }
35942
35965
  setActiveTableCell(getSelectionTableCell(editor.view));
35943
- }, [editor, setActiveTableCell]);
35966
+ }, [clearActiveTableCell, editor, setActiveTableCell]);
35944
35967
  useEffect37(() => {
35945
35968
  if (!editor || !editable) return void 0;
35946
35969
  const proseMirror = editor.view.dom;
35947
35970
  const surface = editorContentRef.current;
35948
35971
  let selectionSyncTimeoutId = 0;
35972
+ const scrollListenerOptions = { passive: true, capture: true };
35949
35973
  const scheduleActiveCellSync = (fallbackCell = null) => {
35950
35974
  requestAnimationFrame(() => {
35975
+ if (!editor.isFocused) {
35976
+ clearActiveTableCell();
35977
+ return;
35978
+ }
35951
35979
  setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
35952
35980
  });
35953
35981
  window.clearTimeout(selectionSyncTimeoutId);
35954
35982
  selectionSyncTimeoutId = window.setTimeout(() => {
35983
+ if (!editor.isFocused) {
35984
+ clearActiveTableCell();
35985
+ return;
35986
+ }
35955
35987
  setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
35956
35988
  }, 0);
35957
35989
  };
@@ -36055,13 +36087,15 @@ function useUEditorTableInteractions(editor, editable = true) {
36055
36087
  proseMirror.addEventListener("keyup", handleSelectionChange);
36056
36088
  proseMirror.addEventListener("focusin", handleSelectionChange);
36057
36089
  document.addEventListener("selectionchange", handleSelectionChange);
36058
- surface?.addEventListener("scroll", handleActiveCellLayoutChange, { passive: true });
36090
+ surface?.addEventListener("scroll", handleActiveCellLayoutChange, scrollListenerOptions);
36059
36091
  window.addEventListener("resize", handleActiveCellLayoutChange);
36060
36092
  document.addEventListener("pointermove", handlePointerMove);
36061
36093
  document.addEventListener("pointerup", handlePointerUp);
36062
36094
  window.addEventListener("blur", handleWindowBlur);
36063
36095
  editor.on("selectionUpdate", syncActiveTableCellFromSelection);
36064
36096
  editor.on("focus", syncActiveTableCellFromSelection);
36097
+ editor.on("blur", clearActiveTableCell);
36098
+ editor.on("update", scheduleTableLayoutSync);
36065
36099
  syncActiveTableCellFromSelection();
36066
36100
  return () => {
36067
36101
  proseMirror.removeEventListener("mousemove", handleEditorMouseMove);
@@ -36072,13 +36106,15 @@ function useUEditorTableInteractions(editor, editable = true) {
36072
36106
  proseMirror.removeEventListener("keyup", handleSelectionChange);
36073
36107
  proseMirror.removeEventListener("focusin", handleSelectionChange);
36074
36108
  document.removeEventListener("selectionchange", handleSelectionChange);
36075
- surface?.removeEventListener("scroll", handleActiveCellLayoutChange);
36109
+ surface?.removeEventListener("scroll", handleActiveCellLayoutChange, scrollListenerOptions);
36076
36110
  window.removeEventListener("resize", handleActiveCellLayoutChange);
36077
36111
  document.removeEventListener("pointermove", handlePointerMove);
36078
36112
  document.removeEventListener("pointerup", handlePointerUp);
36079
36113
  window.removeEventListener("blur", handleWindowBlur);
36080
36114
  editor.off("selectionUpdate", syncActiveTableCellFromSelection);
36081
36115
  editor.off("focus", syncActiveTableCellFromSelection);
36116
+ editor.off("blur", clearActiveTableCell);
36117
+ editor.off("update", scheduleTableLayoutSync);
36082
36118
  window.clearTimeout(selectionSyncTimeoutId);
36083
36119
  if (tableLayoutSyncFrameRef.current !== null) {
36084
36120
  window.cancelAnimationFrame(tableLayoutSyncFrameRef.current);
@@ -36091,7 +36127,7 @@ function useUEditorTableInteractions(editor, editable = true) {
36091
36127
  clearHoveredTableCell();
36092
36128
  clearAllTableResizeHover();
36093
36129
  };
36094
- }, [beginResize, cancelResize, cleanupRowResize, clearActiveTableCell, clearAllTableResizeHover, clearHoveredTableCell, editable, editor, handleRowResizePointerMove, handleRowResizePointerUp, hideColumnGuide, hideRowGuide, isRowResizing, showColumnGuide, showRowGuide, syncActiveRowResizeGuide, syncActiveTableCellFromSelection, updateActiveCellHighlight]);
36130
+ }, [beginResize, cancelResize, cleanupRowResize, clearActiveTableCell, clearAllTableResizeHover, clearHoveredTableCell, editable, editor, handleRowResizePointerMove, handleRowResizePointerUp, hideColumnGuide, hideRowGuide, isRowResizing, scheduleTableLayoutSync, showColumnGuide, showRowGuide, syncActiveRowResizeGuide, syncActiveTableCellFromSelection, updateActiveCellHighlight]);
36095
36131
  return {
36096
36132
  editorContentRef,
36097
36133
  tableColumnGuideRef,
@@ -36110,6 +36146,7 @@ import {
36110
36146
  AlignRight as AlignRight4,
36111
36147
  Bold as BoldIcon3,
36112
36148
  Code as CodeIcon3,
36149
+ Eye as Eye3,
36113
36150
  FileCode as FileCode4,
36114
36151
  Heading1 as Heading1Icon2,
36115
36152
  Heading2 as Heading2Icon2,
@@ -36620,6 +36657,13 @@ var MenuBar = ({
36620
36657
  const openPreviewDialog = () => {
36621
36658
  setShowPreviewDialog(true);
36622
36659
  };
36660
+ const handlePreview = () => {
36661
+ if (onPreview) {
36662
+ onPreview();
36663
+ return;
36664
+ }
36665
+ openPreviewDialog();
36666
+ };
36623
36667
  const applySourceHtml = () => {
36624
36668
  editor.chain().focus().setContent(sourceHtml).run();
36625
36669
  setShowSourceDialog(false);
@@ -36731,7 +36775,7 @@ var MenuBar = ({
36731
36775
  { label: t("menubar.edit"), items: buildEditMenuItems(t, editor), open: void 0, onOpenChange: void 0 },
36732
36776
  {
36733
36777
  label: t("menubar.view"),
36734
- items: buildViewMenuItems(t, { containerRef, onSourceCode, openSourceDialog, onPreview, openPreviewDialog }),
36778
+ items: buildViewMenuItems(t, { containerRef, onSourceCode, openSourceDialog, onPreview: handlePreview, openPreviewDialog }),
36735
36779
  open: void 0,
36736
36780
  onOpenChange: void 0
36737
36781
  },
@@ -36768,17 +36812,33 @@ var MenuBar = ({
36768
36812
  onChange: (e) => handleImageFiles(e.target.files)
36769
36813
  }
36770
36814
  ),
36771
- /* @__PURE__ */ jsx92("div", { className: "flex items-center gap-0.5 border-b border-border/35 bg-muted/20 px-1.5 py-0.5", children: menus.map(({ label, items, open, onOpenChange }) => /* @__PURE__ */ jsx92(
36772
- DropdownMenu,
36773
- {
36774
- trigger: /* @__PURE__ */ jsx92(MenuBarTrigger, { children: label }),
36775
- placement: "bottom-start",
36776
- isOpen: open,
36777
- onOpenChange,
36778
- children: renderMenuItems(items)
36779
- },
36780
- label
36781
- )) }),
36815
+ /* @__PURE__ */ jsxs77("div", { className: "flex items-center gap-0.5 border-b border-border/35 bg-muted/20 px-1.5 py-0.5", children: [
36816
+ menus.map(({ label, items, open, onOpenChange }) => /* @__PURE__ */ jsx92(
36817
+ DropdownMenu,
36818
+ {
36819
+ trigger: /* @__PURE__ */ jsx92(MenuBarTrigger, { children: label }),
36820
+ placement: "bottom-start",
36821
+ isOpen: open,
36822
+ onOpenChange,
36823
+ children: renderMenuItems(items)
36824
+ },
36825
+ label
36826
+ )),
36827
+ /* @__PURE__ */ jsx92(
36828
+ "button",
36829
+ {
36830
+ type: "button",
36831
+ onClick: handlePreview,
36832
+ "aria-label": t("menubar.preview"),
36833
+ title: t("menubar.preview"),
36834
+ className: cn(
36835
+ "ml-auto inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors",
36836
+ "hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1"
36837
+ ),
36838
+ children: /* @__PURE__ */ jsx92(Eye3, { className: "h-4 w-4", "aria-hidden": "true" })
36839
+ }
36840
+ )
36841
+ ] }),
36782
36842
  /* @__PURE__ */ jsx92(
36783
36843
  Modal_default,
36784
36844
  {
@@ -36832,8 +36892,14 @@ var MenuBar = ({
36832
36892
  "div",
36833
36893
  {
36834
36894
  "data-testid": "preview-content",
36835
- className: "prose prose-sm sm:prose dark:prose-invert max-w-none p-2",
36836
- dangerouslySetInnerHTML: { __html: editor.getHTML() }
36895
+ className: "max-h-[70vh] overflow-y-auto overscroll-contain pr-2",
36896
+ children: /* @__PURE__ */ jsx92(
36897
+ "div",
36898
+ {
36899
+ className: UEDITOR_PROSEMIRROR_CLASS_NAME,
36900
+ dangerouslySetInnerHTML: { __html: editor.getHTML() }
36901
+ }
36902
+ )
36837
36903
  }
36838
36904
  )
36839
36905
  }
@@ -36861,7 +36927,6 @@ var UEditor = React82.forwardRef(({
36861
36927
  autofocus = false,
36862
36928
  showToolbar = true,
36863
36929
  showBubbleMenu = true,
36864
- showFloatingMenu = false,
36865
36930
  showCharacterCount = true,
36866
36931
  maxCharacters,
36867
36932
  minHeight = "200px",
@@ -37063,7 +37128,6 @@ var UEditor = React82.forwardRef(({
37063
37128
  lineHeights
37064
37129
  }
37065
37130
  ),
37066
- editable && showFloatingMenu && /* @__PURE__ */ jsx93(CustomFloatingMenu, { editor }),
37067
37131
  /* @__PURE__ */ jsxs78(
37068
37132
  "div",
37069
37133
  {
@@ -37096,7 +37160,7 @@ var UEditor = React82.forwardRef(({
37096
37160
  ref: activeTableCellHighlightRef,
37097
37161
  "aria-hidden": "true",
37098
37162
  "data-ueditor-active-cell-highlight": "",
37099
- className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10 transition-[left,top,width,height] duration-100"
37163
+ className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10"
37100
37164
  }
37101
37165
  ),
37102
37166
  editable && /* @__PURE__ */ jsx93(TableControls, { editor, containerRef: editorContentRef }),