@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.cjs CHANGED
@@ -25896,6 +25896,45 @@ function getImageFiles(dataTransfer) {
25896
25896
  }
25897
25897
  return Array.from(byKey.values());
25898
25898
  }
25899
+ function getClipboardData(dataTransfer, type) {
25900
+ try {
25901
+ return dataTransfer.getData(type) ?? "";
25902
+ } catch {
25903
+ return "";
25904
+ }
25905
+ }
25906
+ function extractClipboardHtmlFragment(html) {
25907
+ const startMarker = "<!--StartFragment-->";
25908
+ const endMarker = "<!--EndFragment-->";
25909
+ const start = html.indexOf(startMarker);
25910
+ const end = html.indexOf(endMarker);
25911
+ if (start >= 0 && end > start) {
25912
+ return html.slice(start + startMarker.length, end);
25913
+ }
25914
+ return html;
25915
+ }
25916
+ function getClipboardTableHtml(dataTransfer) {
25917
+ const html = getClipboardData(dataTransfer, "text/html");
25918
+ if (!/<table(?:\s|>)/i.test(html)) return "";
25919
+ const fragment = extractClipboardHtmlFragment(html);
25920
+ if (typeof DOMParser !== "undefined") {
25921
+ const doc = new DOMParser().parseFromString(fragment, "text/html");
25922
+ const table = doc.querySelector("table");
25923
+ if (table) return table.outerHTML;
25924
+ }
25925
+ return fragment;
25926
+ }
25927
+ function escapeHtml(value) {
25928
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
25929
+ }
25930
+ function getClipboardTsvTableHtml(dataTransfer) {
25931
+ const text = getClipboardData(dataTransfer, "text/plain").replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n+$/, "");
25932
+ if (!text.includes(" ")) return "";
25933
+ const rows = text.split("\n").map((row) => row.split(" "));
25934
+ if (rows.length === 0 || rows.every((row) => row.length < 2)) return "";
25935
+ const body = rows.map((row) => `<tr>${row.map((cell) => `<td>${escapeHtml(cell)}</td>`).join("")}</tr>`).join("");
25936
+ return `<table><tbody>${body}</tbody></table>`;
25937
+ }
25899
25938
  function fileToDataUrl(file) {
25900
25939
  return new Promise((resolve, reject) => {
25901
25940
  const reader = new FileReader();
@@ -25950,6 +25989,18 @@ var ClipboardImages = import_core5.Extension.create({
25950
25989
  props: {
25951
25990
  handlePaste: (_view, event) => {
25952
25991
  if (!event || !event.clipboardData) return false;
25992
+ const tableHtml = getClipboardTableHtml(event.clipboardData);
25993
+ if (tableHtml) {
25994
+ event.preventDefault();
25995
+ editor.chain().focus().insertContent(tableHtml).run();
25996
+ return true;
25997
+ }
25998
+ const tsvTableHtml = getClipboardTsvTableHtml(event.clipboardData);
25999
+ if (tsvTableHtml) {
26000
+ event.preventDefault();
26001
+ editor.chain().focus().insertContent(tsvTableHtml).run();
26002
+ return true;
26003
+ }
25953
26004
  const files = getImageFiles(event.clipboardData);
25954
26005
  if (files.length === 0) return false;
25955
26006
  event.preventDefault();
@@ -27302,7 +27353,7 @@ function buildUEditorExtensions({
27302
27353
  handleWidth: 10,
27303
27354
  allowTableNodeSelection: true,
27304
27355
  HTMLAttributes: {
27305
- class: "border-collapse w-full my-4"
27356
+ class: "border-collapse my-4"
27306
27357
  }
27307
27358
  }),
27308
27359
  table_row_default,
@@ -27825,6 +27876,229 @@ var ImageInput = ({ onSubmit, onCancel }) => {
27825
27876
  ] });
27826
27877
  };
27827
27878
 
27879
+ // src/components/UEditor/table-cell-commands.ts
27880
+ var import_state7 = require("@tiptap/pm/state");
27881
+ var import_tables = require("@tiptap/pm/tables");
27882
+ function getCellSelectionPositions(selection) {
27883
+ const value = selection;
27884
+ const anchor = value.$anchorCell?.pos;
27885
+ const head = value.$headCell?.pos;
27886
+ return typeof anchor === "number" && typeof head === "number" ? { anchor, head } : null;
27887
+ }
27888
+ function findTableInfoFromCellPos(editor, cellPos) {
27889
+ const $pos = editor.state.doc.resolve(cellPos);
27890
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
27891
+ const node = $pos.node(depth);
27892
+ if (node.type.name === "table") {
27893
+ return {
27894
+ table: node,
27895
+ tablePos: $pos.before(depth),
27896
+ tableStart: $pos.start(depth)
27897
+ };
27898
+ }
27899
+ }
27900
+ return null;
27901
+ }
27902
+ function getFocusableCellPos(editor, cellPos) {
27903
+ const cellNode = editor.state.doc.nodeAt(cellPos);
27904
+ if (!cellNode) return cellPos + 1;
27905
+ let offset = cellPos + 1;
27906
+ let node = cellNode.firstChild ?? null;
27907
+ while (node && !node.isTextblock) {
27908
+ offset += 1;
27909
+ node = node.firstChild ?? null;
27910
+ }
27911
+ return node?.isTextblock ? offset + 1 : cellPos + 1;
27912
+ }
27913
+ function focusCell(editor, cellPos) {
27914
+ const selection = import_state7.TextSelection.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
27915
+ editor.view.dispatch(editor.state.tr.setSelection(selection));
27916
+ editor.view.focus();
27917
+ }
27918
+ function collectChildren(node) {
27919
+ const children = [];
27920
+ node.forEach((child) => children.push(child));
27921
+ return children;
27922
+ }
27923
+ function createEmptyCellNode(cellNode) {
27924
+ return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
27925
+ }
27926
+ function getSelectedTableRect(editor) {
27927
+ const cellSelection = getCellSelectionPositions(editor.state.selection);
27928
+ if (cellSelection) {
27929
+ const tableInfo = findTableInfoFromCellPos(editor, cellSelection.anchor);
27930
+ if (tableInfo) {
27931
+ const map = import_tables.TableMap.get(tableInfo.table);
27932
+ const rect = map.rectBetween(
27933
+ cellSelection.anchor - tableInfo.tableStart,
27934
+ cellSelection.head - tableInfo.tableStart
27935
+ );
27936
+ return {
27937
+ ...rect,
27938
+ map,
27939
+ table: tableInfo.table,
27940
+ tableStart: tableInfo.tableStart
27941
+ };
27942
+ }
27943
+ }
27944
+ return (0, import_tables.selectedRect)(editor.state);
27945
+ }
27946
+ function parsePixelWidth(value) {
27947
+ if (!value) return null;
27948
+ const parsed = Number.parseFloat(value);
27949
+ return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : null;
27950
+ }
27951
+ function getDomColumnWidths(editor, rect) {
27952
+ const tableDom = editor.view.nodeDOM(rect.tableStart - 1);
27953
+ if (!(tableDom instanceof HTMLTableElement)) return null;
27954
+ const cols = Array.from(tableDom.querySelectorAll("colgroup > col"));
27955
+ if (cols.length === 0) return null;
27956
+ const widths = [];
27957
+ for (let col = rect.left; col < rect.right; col += 1) {
27958
+ const colElement = cols[col];
27959
+ if (!colElement) return null;
27960
+ const width = parsePixelWidth(colElement.style.width) ?? parsePixelWidth(colElement.getAttribute("width")) ?? Math.round(colElement.getBoundingClientRect().width);
27961
+ if (!Number.isFinite(width) || width <= 0) return null;
27962
+ widths.push(width);
27963
+ }
27964
+ return widths.length > 0 ? widths : null;
27965
+ }
27966
+ function getNodeColumnWidths(rect) {
27967
+ const widths = [];
27968
+ for (let col = rect.left; col < rect.right; col += 1) {
27969
+ let width = null;
27970
+ const seen = /* @__PURE__ */ new Set();
27971
+ for (let row = 0; row < rect.map.height && width == null; row += 1) {
27972
+ const cellPos = rect.map.map[row * rect.map.width + col];
27973
+ if (seen.has(cellPos)) continue;
27974
+ seen.add(cellPos);
27975
+ const cell = rect.table.nodeAt(cellPos);
27976
+ const colwidth = cell?.attrs.colwidth;
27977
+ if (!Array.isArray(colwidth)) continue;
27978
+ const cellLeft = rect.map.colCount(cellPos);
27979
+ const widthIndex = col - cellLeft;
27980
+ const candidate = colwidth[widthIndex];
27981
+ if (typeof candidate === "number" && candidate > 0) {
27982
+ width = candidate;
27983
+ }
27984
+ }
27985
+ if (width == null) return null;
27986
+ widths.push(width);
27987
+ }
27988
+ return widths.length > 0 ? widths : null;
27989
+ }
27990
+ function getSelectedColumnWidths(editor, rect) {
27991
+ return getDomColumnWidths(editor, rect) ?? getNodeColumnWidths(rect);
27992
+ }
27993
+ function dispatchTableLayoutChange(editor) {
27994
+ editor.view.dom.dispatchEvent(new CustomEvent(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, { bubbles: true }));
27995
+ }
27996
+ function mergeTableCellsPreservingColumnWidths(editor) {
27997
+ const rect = getSelectedTableRect(editor);
27998
+ const widths = getSelectedColumnWidths(editor, rect);
27999
+ const merged = editor.chain().focus().mergeCells().run();
28000
+ if (!merged) return merged;
28001
+ if (!widths) {
28002
+ dispatchTableLayoutChange(editor);
28003
+ return merged;
28004
+ }
28005
+ const nextRect = getSelectedTableRect(editor);
28006
+ const cellPos = nextRect.map.map[nextRect.top * nextRect.map.width + nextRect.left];
28007
+ const absolutePos = nextRect.tableStart + cellPos;
28008
+ const node = editor.state.doc.nodeAt(absolutePos);
28009
+ if (!node) return merged;
28010
+ editor.view.dispatch(
28011
+ editor.state.tr.setNodeMarkup(absolutePos, node.type, {
28012
+ ...node.attrs,
28013
+ colwidth: widths
28014
+ })
28015
+ );
28016
+ dispatchTableLayoutChange(editor);
28017
+ return true;
28018
+ }
28019
+ function runTableCommandAtCellPos(editor, cellPos, command) {
28020
+ if (cellPos == null) return false;
28021
+ focusCell(editor, cellPos);
28022
+ return command(editor.chain().focus(null, { scrollIntoView: false })).run();
28023
+ }
28024
+ function getTableCornerCellPos(editor, activePos) {
28025
+ const tableInfo = findTableInfoFromCellPos(editor, activePos);
28026
+ if (!tableInfo) return null;
28027
+ const map = import_tables.TableMap.get(tableInfo.table);
28028
+ return tableInfo.tableStart + map.positionAt(map.height - 1, map.width - 1, tableInfo.table);
28029
+ }
28030
+ function replaceTableAtCellPos(editor, cellPos, updateTable) {
28031
+ if (cellPos == null) return false;
28032
+ const tableInfo = findTableInfoFromCellPos(editor, cellPos);
28033
+ if (!tableInfo) return false;
28034
+ const nextTable = updateTable(tableInfo.table);
28035
+ if (!nextTable) return false;
28036
+ editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.tablePos, tableInfo.tablePos + tableInfo.table.nodeSize, nextTable));
28037
+ dispatchTableLayoutChange(editor);
28038
+ return true;
28039
+ }
28040
+ function duplicateTableRowAt(editor, rowIndex, cellPos) {
28041
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28042
+ const rows = collectChildren(tableNode);
28043
+ const rowNode = rows[rowIndex];
28044
+ if (!rowNode) return null;
28045
+ rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
28046
+ return tableNode.type.create(tableNode.attrs, rows);
28047
+ });
28048
+ }
28049
+ function clearTableRowAt(editor, rowIndex, cellPos) {
28050
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28051
+ const rows = collectChildren(tableNode);
28052
+ const rowNode = rows[rowIndex];
28053
+ if (!rowNode) return null;
28054
+ const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
28055
+ rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
28056
+ return tableNode.type.create(tableNode.attrs, rows);
28057
+ });
28058
+ }
28059
+ function duplicateTableColumnAt(editor, columnIndex, cellPos) {
28060
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28061
+ const rows = collectChildren(tableNode).map((rowNode) => {
28062
+ const cells = collectChildren(rowNode);
28063
+ const cellNode = cells[columnIndex];
28064
+ if (!cellNode) return rowNode;
28065
+ cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
28066
+ return rowNode.type.create(rowNode.attrs, cells);
28067
+ });
28068
+ return tableNode.type.create(tableNode.attrs, rows);
28069
+ });
28070
+ }
28071
+ function clearTableColumnAt(editor, columnIndex, cellPos) {
28072
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28073
+ const rows = collectChildren(tableNode).map((rowNode) => {
28074
+ const cells = collectChildren(rowNode);
28075
+ const cellNode = cells[columnIndex];
28076
+ if (!cellNode) return rowNode;
28077
+ cells[columnIndex] = createEmptyCellNode(cellNode);
28078
+ return rowNode.type.create(rowNode.attrs, cells);
28079
+ });
28080
+ return tableNode.type.create(tableNode.attrs, rows);
28081
+ });
28082
+ }
28083
+ function expandTableFromCell(editor, activeCellPos, rows, columns) {
28084
+ let cornerCellPos = getTableCornerCellPos(editor, activeCellPos);
28085
+ if (cornerCellPos == null) return false;
28086
+ for (let index = 0; index < rows; index += 1) {
28087
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addRowAfter());
28088
+ if (!ok) return false;
28089
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28090
+ if (cornerCellPos == null) return false;
28091
+ }
28092
+ for (let index = 0; index < columns; index += 1) {
28093
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addColumnAfter());
28094
+ if (!ok) return false;
28095
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28096
+ if (cornerCellPos == null) return false;
28097
+ }
28098
+ dispatchTableLayoutChange(editor);
28099
+ return true;
28100
+ }
28101
+
27828
28102
  // src/components/UEditor/typography-options.ts
27829
28103
  function normalizeStyleValue(value) {
27830
28104
  return typeof value === "string" ? value.trim().replace(/^['"]|['"]$/g, "") : "";
@@ -28020,6 +28294,8 @@ var EditorToolbar = ({
28020
28294
  const currentTableAlign = tableAlignAttr === "center" || tableAlignAttr === "right" ? tableAlignAttr : "left";
28021
28295
  const isTableSelected = tableInfo !== null;
28022
28296
  const hasTableContext = isTableSelected || tableCommandAnchorPosRef.current !== null;
28297
+ const canMergeCells = hasTableContext && editor.can().mergeCells();
28298
+ const canSplitCell = hasTableContext && editor.can().splitCell();
28023
28299
  const currentFontFamily = normalizeStyleValue(textStyleAttrs.fontFamily);
28024
28300
  const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
28025
28301
  const currentTextColor = normalizeStyleValue(textStyleAttrs.color) || "inherit";
@@ -28675,408 +28951,186 @@ var EditorToolbar = ({
28675
28951
  {
28676
28952
  icon: import_lucide_react48.AlignLeft,
28677
28953
  label: t("tableMenu.alignLeft"),
28678
- onClick: () => applyTableAlignment(editor, "left", tableCommandAnchorPos),
28679
- active: hasTableContext && currentTableAlign === "left",
28680
- disabled: !hasTableContext
28681
- }
28682
- ),
28683
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28684
- DropdownMenuItem,
28685
- {
28686
- icon: import_lucide_react48.AlignCenter,
28687
- label: t("tableMenu.alignCenter"),
28688
- onClick: () => applyTableAlignment(editor, "center", tableCommandAnchorPos),
28689
- active: hasTableContext && currentTableAlign === "center",
28690
- disabled: !hasTableContext
28691
- }
28692
- ),
28693
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28694
- DropdownMenuItem,
28695
- {
28696
- icon: import_lucide_react48.AlignRight,
28697
- label: t("tableMenu.alignRight"),
28698
- onClick: () => applyTableAlignment(editor, "right", tableCommandAnchorPos),
28699
- active: hasTableContext && currentTableAlign === "right",
28700
- disabled: !hasTableContext
28701
- }
28702
- ),
28703
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "my-1 border-t" }),
28704
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28705
- DropdownMenuItem,
28706
- {
28707
- icon: import_lucide_react48.ArrowLeft,
28708
- label: t("tableMenu.addColumnBefore"),
28709
- onClick: () => editor.chain().focus().addColumnBefore().run(),
28710
- disabled: !hasTableContext || !editor.can().addColumnBefore()
28711
- }
28712
- ),
28713
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28714
- DropdownMenuItem,
28715
- {
28716
- icon: import_lucide_react48.ArrowDown,
28717
- label: t("tableMenu.addColumnAfter"),
28718
- onClick: () => editor.chain().focus().addColumnAfter().run(),
28719
- disabled: !hasTableContext || !editor.can().addColumnAfter()
28720
- }
28721
- ),
28722
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28723
- DropdownMenuItem,
28724
- {
28725
- icon: import_lucide_react48.ArrowUp,
28726
- label: t("tableMenu.addRowBefore"),
28727
- onClick: () => editor.chain().focus().addRowBefore().run(),
28728
- disabled: !hasTableContext || !editor.can().addRowBefore()
28729
- }
28730
- ),
28731
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28732
- DropdownMenuItem,
28733
- {
28734
- icon: import_lucide_react48.ArrowRight,
28735
- label: t("tableMenu.addRowAfter"),
28736
- onClick: () => editor.chain().focus().addRowAfter().run(),
28737
- disabled: !hasTableContext || !editor.can().addRowAfter()
28738
- }
28739
- ),
28740
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "my-1 border-t" }),
28741
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28742
- DropdownMenuItem,
28743
- {
28744
- icon: import_lucide_react48.Table,
28745
- label: t("tableMenu.toggleHeaderRow"),
28746
- onClick: () => editor.chain().focus().toggleHeaderRow().run(),
28747
- disabled: !hasTableContext || !editor.can().toggleHeaderRow()
28748
- }
28749
- ),
28750
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28751
- DropdownMenuItem,
28752
- {
28753
- icon: import_lucide_react48.Table,
28754
- label: t("tableMenu.toggleHeaderColumn"),
28755
- onClick: () => editor.chain().focus().toggleHeaderColumn().run(),
28756
- disabled: !hasTableContext || !editor.can().toggleHeaderColumn()
28757
- }
28758
- ),
28759
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "my-1 border-t" }),
28760
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28761
- DropdownMenuItem,
28762
- {
28763
- icon: import_lucide_react48.Trash2,
28764
- label: t("tableMenu.deleteColumn"),
28765
- onClick: () => editor.chain().focus().deleteColumn().run(),
28766
- disabled: !hasTableContext || !editor.can().deleteColumn()
28767
- }
28768
- ),
28769
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28770
- DropdownMenuItem,
28771
- {
28772
- icon: import_lucide_react48.Trash2,
28773
- label: t("tableMenu.deleteRow"),
28774
- onClick: () => editor.chain().focus().deleteRow().run(),
28775
- disabled: !hasTableContext || !editor.can().deleteRow()
28776
- }
28777
- ),
28778
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28779
- DropdownMenuItem,
28780
- {
28781
- icon: import_lucide_react48.Trash2,
28782
- label: t("tableMenu.deleteTable"),
28783
- onClick: () => editor.chain().focus().deleteTable().run(),
28784
- disabled: !hasTableContext || !editor.can().deleteTable()
28785
- }
28786
- )
28787
- ]
28788
- }
28789
- ),
28790
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarDivider, {}),
28791
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarButton, { onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: t("toolbar.undo"), children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.Undo, { className: "w-4 h-4" }) }),
28792
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarButton, { onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: t("toolbar.redo"), children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.Redo, { className: "w-4 h-4" }) })
28793
- ] });
28794
- };
28795
-
28796
- // src/components/UEditor/menus.tsx
28797
- var import_react62 = require("react");
28798
- var import_react63 = require("@tiptap/react");
28799
- var import_tables2 = require("@tiptap/pm/tables");
28800
- var import_react_dom8 = require("react-dom");
28801
- var import_lucide_react49 = require("lucide-react");
28802
-
28803
- // src/components/UEditor/table-cell-commands.ts
28804
- var import_state7 = require("@tiptap/pm/state");
28805
- var import_tables = require("@tiptap/pm/tables");
28806
- function getCellSelectionPositions(selection) {
28807
- const value = selection;
28808
- const anchor = value.$anchorCell?.pos;
28809
- const head = value.$headCell?.pos;
28810
- return typeof anchor === "number" && typeof head === "number" ? { anchor, head } : null;
28811
- }
28812
- function findTableInfoFromCellPos(editor, cellPos) {
28813
- const $pos = editor.state.doc.resolve(cellPos);
28814
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
28815
- const node = $pos.node(depth);
28816
- if (node.type.name === "table") {
28817
- return {
28818
- table: node,
28819
- tablePos: $pos.before(depth),
28820
- tableStart: $pos.start(depth)
28821
- };
28822
- }
28823
- }
28824
- return null;
28825
- }
28826
- function getFocusableCellPos(editor, cellPos) {
28827
- const cellNode = editor.state.doc.nodeAt(cellPos);
28828
- if (!cellNode) return cellPos + 1;
28829
- let offset = cellPos + 1;
28830
- let node = cellNode.firstChild ?? null;
28831
- while (node && !node.isTextblock) {
28832
- offset += 1;
28833
- node = node.firstChild ?? null;
28834
- }
28835
- return node?.isTextblock ? offset + 1 : cellPos + 1;
28836
- }
28837
- function focusCell(editor, cellPos) {
28838
- const selection = import_state7.TextSelection.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
28839
- editor.view.dispatch(editor.state.tr.setSelection(selection));
28840
- editor.view.focus();
28841
- }
28842
- function collectChildren(node) {
28843
- const children = [];
28844
- node.forEach((child) => children.push(child));
28845
- return children;
28846
- }
28847
- function createEmptyCellNode(cellNode) {
28848
- return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
28849
- }
28850
- function getSelectedTableRect(editor) {
28851
- const cellSelection = getCellSelectionPositions(editor.state.selection);
28852
- if (cellSelection) {
28853
- const tableInfo = findTableInfoFromCellPos(editor, cellSelection.anchor);
28854
- if (tableInfo) {
28855
- const map = import_tables.TableMap.get(tableInfo.table);
28856
- const rect = map.rectBetween(
28857
- cellSelection.anchor - tableInfo.tableStart,
28858
- cellSelection.head - tableInfo.tableStart
28859
- );
28860
- return {
28861
- ...rect,
28862
- map,
28863
- table: tableInfo.table,
28864
- tableStart: tableInfo.tableStart
28865
- };
28866
- }
28867
- }
28868
- return (0, import_tables.selectedRect)(editor.state);
28869
- }
28870
- function parsePixelWidth(value) {
28871
- if (!value) return null;
28872
- const parsed = Number.parseFloat(value);
28873
- return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : null;
28874
- }
28875
- function getDomColumnWidths(editor, rect) {
28876
- const tableDom = editor.view.nodeDOM(rect.tableStart - 1);
28877
- if (!(tableDom instanceof HTMLTableElement)) return null;
28878
- const cols = Array.from(tableDom.querySelectorAll("colgroup > col"));
28879
- if (cols.length === 0) return null;
28880
- const widths = [];
28881
- for (let col = rect.left; col < rect.right; col += 1) {
28882
- const colElement = cols[col];
28883
- if (!colElement) return null;
28884
- const width = parsePixelWidth(colElement.style.width) ?? parsePixelWidth(colElement.getAttribute("width")) ?? Math.round(colElement.getBoundingClientRect().width);
28885
- if (!Number.isFinite(width) || width <= 0) return null;
28886
- widths.push(width);
28887
- }
28888
- return widths.length > 0 ? widths : null;
28889
- }
28890
- function getNodeColumnWidths(rect) {
28891
- const widths = [];
28892
- for (let col = rect.left; col < rect.right; col += 1) {
28893
- let width = null;
28894
- const seen = /* @__PURE__ */ new Set();
28895
- for (let row = 0; row < rect.map.height && width == null; row += 1) {
28896
- const cellPos = rect.map.map[row * rect.map.width + col];
28897
- if (seen.has(cellPos)) continue;
28898
- seen.add(cellPos);
28899
- const cell = rect.table.nodeAt(cellPos);
28900
- const colwidth = cell?.attrs.colwidth;
28901
- if (!Array.isArray(colwidth)) continue;
28902
- const cellLeft = rect.map.colCount(cellPos);
28903
- const widthIndex = col - cellLeft;
28904
- const candidate = colwidth[widthIndex];
28905
- if (typeof candidate === "number" && candidate > 0) {
28906
- width = candidate;
28907
- }
28908
- }
28909
- if (width == null) return null;
28910
- widths.push(width);
28911
- }
28912
- return widths.length > 0 ? widths : null;
28913
- }
28914
- function getSelectedColumnWidths(editor, rect) {
28915
- return getDomColumnWidths(editor, rect) ?? getNodeColumnWidths(rect);
28916
- }
28917
- function dispatchTableLayoutChange(editor) {
28918
- editor.view.dom.dispatchEvent(new CustomEvent(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, { bubbles: true }));
28919
- }
28920
- function mergeTableCellsPreservingColumnWidths(editor) {
28921
- const rect = getSelectedTableRect(editor);
28922
- const widths = getSelectedColumnWidths(editor, rect);
28923
- const merged = editor.chain().focus().mergeCells().run();
28924
- if (!merged) return merged;
28925
- if (!widths) {
28926
- dispatchTableLayoutChange(editor);
28927
- return merged;
28928
- }
28929
- const nextRect = getSelectedTableRect(editor);
28930
- const cellPos = nextRect.map.map[nextRect.top * nextRect.map.width + nextRect.left];
28931
- const absolutePos = nextRect.tableStart + cellPos;
28932
- const node = editor.state.doc.nodeAt(absolutePos);
28933
- if (!node) return merged;
28934
- editor.view.dispatch(
28935
- editor.state.tr.setNodeMarkup(absolutePos, node.type, {
28936
- ...node.attrs,
28937
- colwidth: widths
28938
- })
28939
- );
28940
- dispatchTableLayoutChange(editor);
28941
- return true;
28942
- }
28943
- function runTableCommandAtCellPos(editor, cellPos, command) {
28944
- if (cellPos == null) return false;
28945
- focusCell(editor, cellPos);
28946
- return command(editor.chain().focus(null, { scrollIntoView: false })).run();
28947
- }
28948
- function getTableCornerCellPos(editor, activePos) {
28949
- const tableInfo = findTableInfoFromCellPos(editor, activePos);
28950
- if (!tableInfo) return null;
28951
- const map = import_tables.TableMap.get(tableInfo.table);
28952
- return tableInfo.tableStart + map.positionAt(map.height - 1, map.width - 1, tableInfo.table);
28953
- }
28954
- function replaceTableAtCellPos(editor, cellPos, updateTable) {
28955
- if (cellPos == null) return false;
28956
- const tableInfo = findTableInfoFromCellPos(editor, cellPos);
28957
- if (!tableInfo) return false;
28958
- const nextTable = updateTable(tableInfo.table);
28959
- if (!nextTable) return false;
28960
- editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.tablePos, tableInfo.tablePos + tableInfo.table.nodeSize, nextTable));
28961
- dispatchTableLayoutChange(editor);
28962
- return true;
28963
- }
28964
- function duplicateTableRowAt(editor, rowIndex, cellPos) {
28965
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28966
- const rows = collectChildren(tableNode);
28967
- const rowNode = rows[rowIndex];
28968
- if (!rowNode) return null;
28969
- rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
28970
- return tableNode.type.create(tableNode.attrs, rows);
28971
- });
28972
- }
28973
- function clearTableRowAt(editor, rowIndex, cellPos) {
28974
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28975
- const rows = collectChildren(tableNode);
28976
- const rowNode = rows[rowIndex];
28977
- if (!rowNode) return null;
28978
- const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
28979
- rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
28980
- return tableNode.type.create(tableNode.attrs, rows);
28981
- });
28982
- }
28983
- function duplicateTableColumnAt(editor, columnIndex, cellPos) {
28984
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28985
- const rows = collectChildren(tableNode).map((rowNode) => {
28986
- const cells = collectChildren(rowNode);
28987
- const cellNode = cells[columnIndex];
28988
- if (!cellNode) return rowNode;
28989
- cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
28990
- return rowNode.type.create(rowNode.attrs, cells);
28991
- });
28992
- return tableNode.type.create(tableNode.attrs, rows);
28993
- });
28994
- }
28995
- function clearTableColumnAt(editor, columnIndex, cellPos) {
28996
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28997
- const rows = collectChildren(tableNode).map((rowNode) => {
28998
- const cells = collectChildren(rowNode);
28999
- const cellNode = cells[columnIndex];
29000
- if (!cellNode) return rowNode;
29001
- cells[columnIndex] = createEmptyCellNode(cellNode);
29002
- return rowNode.type.create(rowNode.attrs, cells);
29003
- });
29004
- return tableNode.type.create(tableNode.attrs, rows);
29005
- });
29006
- }
29007
- function expandTableFromCell(editor, activeCellPos, rows, columns) {
29008
- let cornerCellPos = getTableCornerCellPos(editor, activeCellPos);
29009
- if (cornerCellPos == null) return false;
29010
- for (let index = 0; index < rows; index += 1) {
29011
- const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addRowAfter());
29012
- if (!ok) return false;
29013
- cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
29014
- if (cornerCellPos == null) return false;
29015
- }
29016
- for (let index = 0; index < columns; index += 1) {
29017
- const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addColumnAfter());
29018
- if (!ok) return false;
29019
- cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
29020
- if (cornerCellPos == null) return false;
29021
- }
29022
- dispatchTableLayoutChange(editor);
29023
- return true;
29024
- }
28954
+ onClick: () => applyTableAlignment(editor, "left", tableCommandAnchorPos),
28955
+ active: hasTableContext && currentTableAlign === "left",
28956
+ disabled: !hasTableContext
28957
+ }
28958
+ ),
28959
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28960
+ DropdownMenuItem,
28961
+ {
28962
+ icon: import_lucide_react48.AlignCenter,
28963
+ label: t("tableMenu.alignCenter"),
28964
+ onClick: () => applyTableAlignment(editor, "center", tableCommandAnchorPos),
28965
+ active: hasTableContext && currentTableAlign === "center",
28966
+ disabled: !hasTableContext
28967
+ }
28968
+ ),
28969
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28970
+ DropdownMenuItem,
28971
+ {
28972
+ icon: import_lucide_react48.AlignRight,
28973
+ label: t("tableMenu.alignRight"),
28974
+ onClick: () => applyTableAlignment(editor, "right", tableCommandAnchorPos),
28975
+ active: hasTableContext && currentTableAlign === "right",
28976
+ disabled: !hasTableContext
28977
+ }
28978
+ ),
28979
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "my-1 border-t" }),
28980
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28981
+ DropdownMenuItem,
28982
+ {
28983
+ icon: import_lucide_react48.ArrowLeft,
28984
+ label: t("tableMenu.addColumnBefore"),
28985
+ onClick: () => editor.chain().focus().addColumnBefore().run(),
28986
+ disabled: !hasTableContext || !editor.can().addColumnBefore()
28987
+ }
28988
+ ),
28989
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28990
+ DropdownMenuItem,
28991
+ {
28992
+ icon: import_lucide_react48.ArrowDown,
28993
+ label: t("tableMenu.addColumnAfter"),
28994
+ onClick: () => editor.chain().focus().addColumnAfter().run(),
28995
+ disabled: !hasTableContext || !editor.can().addColumnAfter()
28996
+ }
28997
+ ),
28998
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
28999
+ DropdownMenuItem,
29000
+ {
29001
+ icon: import_lucide_react48.ArrowUp,
29002
+ label: t("tableMenu.addRowBefore"),
29003
+ onClick: () => editor.chain().focus().addRowBefore().run(),
29004
+ disabled: !hasTableContext || !editor.can().addRowBefore()
29005
+ }
29006
+ ),
29007
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29008
+ DropdownMenuItem,
29009
+ {
29010
+ icon: import_lucide_react48.ArrowRight,
29011
+ label: t("tableMenu.addRowAfter"),
29012
+ onClick: () => editor.chain().focus().addRowAfter().run(),
29013
+ disabled: !hasTableContext || !editor.can().addRowAfter()
29014
+ }
29015
+ ),
29016
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "my-1 border-t" }),
29017
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29018
+ DropdownMenuItem,
29019
+ {
29020
+ icon: import_lucide_react48.Table,
29021
+ label: t("tableMenu.toggleHeaderRow"),
29022
+ onClick: () => editor.chain().focus().toggleHeaderRow().run(),
29023
+ disabled: !hasTableContext || !editor.can().toggleHeaderRow()
29024
+ }
29025
+ ),
29026
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29027
+ DropdownMenuItem,
29028
+ {
29029
+ icon: import_lucide_react48.Table,
29030
+ label: t("tableMenu.toggleHeaderColumn"),
29031
+ onClick: () => editor.chain().focus().toggleHeaderColumn().run(),
29032
+ disabled: !hasTableContext || !editor.can().toggleHeaderColumn()
29033
+ }
29034
+ ),
29035
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "my-1 border-t" }),
29036
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29037
+ DropdownMenuItem,
29038
+ {
29039
+ icon: import_lucide_react48.Trash2,
29040
+ label: t("tableMenu.deleteColumn"),
29041
+ onClick: () => editor.chain().focus().deleteColumn().run(),
29042
+ disabled: !hasTableContext || !editor.can().deleteColumn()
29043
+ }
29044
+ ),
29045
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29046
+ DropdownMenuItem,
29047
+ {
29048
+ icon: import_lucide_react48.Trash2,
29049
+ label: t("tableMenu.deleteRow"),
29050
+ onClick: () => editor.chain().focus().deleteRow().run(),
29051
+ disabled: !hasTableContext || !editor.can().deleteRow()
29052
+ }
29053
+ ),
29054
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29055
+ DropdownMenuItem,
29056
+ {
29057
+ icon: import_lucide_react48.Trash2,
29058
+ label: t("tableMenu.deleteTable"),
29059
+ onClick: () => editor.chain().focus().deleteTable().run(),
29060
+ disabled: !hasTableContext || !editor.can().deleteTable()
29061
+ }
29062
+ )
29063
+ ]
29064
+ }
29065
+ ),
29066
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarDivider, {}),
29067
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarButton, { onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: t("toolbar.undo"), children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.Undo, { className: "w-4 h-4" }) }),
29068
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarButton, { onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: t("toolbar.redo"), children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.Redo, { className: "w-4 h-4" }) }),
29069
+ hasTableContext && /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(import_jsx_runtime85.Fragment, { children: [
29070
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarDivider, {}),
29071
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29072
+ ToolbarButton,
29073
+ {
29074
+ onClick: () => editor.chain().focus().addColumnBefore().run(),
29075
+ disabled: !editor.can().addColumnBefore(),
29076
+ title: t("tableMenu.addColumnBefore"),
29077
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowLeft, { className: "w-4 h-4" })
29078
+ }
29079
+ ),
29080
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29081
+ ToolbarButton,
29082
+ {
29083
+ onClick: () => editor.chain().focus().addColumnAfter().run(),
29084
+ disabled: !editor.can().addColumnAfter(),
29085
+ title: t("tableMenu.addColumnAfter"),
29086
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowRight, { className: "w-4 h-4" })
29087
+ }
29088
+ ),
29089
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29090
+ ToolbarButton,
29091
+ {
29092
+ onClick: () => editor.chain().focus().addRowBefore().run(),
29093
+ disabled: !editor.can().addRowBefore(),
29094
+ title: t("tableMenu.addRowBefore"),
29095
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowUp, { className: "w-4 h-4" })
29096
+ }
29097
+ ),
29098
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29099
+ ToolbarButton,
29100
+ {
29101
+ onClick: () => editor.chain().focus().addRowAfter().run(),
29102
+ disabled: !editor.can().addRowAfter(),
29103
+ title: t("tableMenu.addRowAfter"),
29104
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowDown, { className: "w-4 h-4" })
29105
+ }
29106
+ ),
29107
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29108
+ ToolbarButton,
29109
+ {
29110
+ onClick: () => {
29111
+ if (canSplitCell) {
29112
+ editor.chain().focus().splitCell().run();
29113
+ return;
29114
+ }
29115
+ mergeTableCellsPreservingColumnWidths(editor);
29116
+ },
29117
+ active: canSplitCell,
29118
+ disabled: !canMergeCells && !canSplitCell,
29119
+ title: canSplitCell ? t("tableMenu.splitCell") : t("tableMenu.mergeCells"),
29120
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.TableCellsMerge, { className: "w-4 h-4" })
29121
+ }
29122
+ )
29123
+ ] })
29124
+ ] });
29125
+ };
29025
29126
 
29026
29127
  // src/components/UEditor/menus.tsx
29128
+ var import_react62 = require("react");
29129
+ var import_react63 = require("@tiptap/react");
29130
+ var import_tables2 = require("@tiptap/pm/tables");
29131
+ var import_react_dom8 = require("react-dom");
29132
+ var import_lucide_react49 = require("lucide-react");
29027
29133
  var import_jsx_runtime86 = require("react/jsx-runtime");
29028
- var FloatingSlashCommandMenu = ({ editor, onClose }) => {
29029
- const t = useSmartTranslations("UEditor");
29030
- const messages = (0, import_react62.useMemo)(() => buildSlashCommandMessages(t), [t]);
29031
- const items = (0, import_react62.useMemo)(() => buildSlashCommandItems({ query: "", messages }), [messages]);
29032
- const listRef = (0, import_react62.useRef)(null);
29033
- (0, import_react62.useEffect)(() => {
29034
- const handleKeyDown2 = (event) => {
29035
- if (event.key === "Escape") {
29036
- event.preventDefault();
29037
- onClose();
29038
- return;
29039
- }
29040
- const handled = listRef.current?.onKeyDown({ event }) ?? false;
29041
- if (handled) {
29042
- event.preventDefault();
29043
- }
29044
- };
29045
- document.addEventListener("keydown", handleKeyDown2);
29046
- return () => document.removeEventListener("keydown", handleKeyDown2);
29047
- }, [onClose]);
29048
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
29049
- SlashCommandList,
29050
- {
29051
- ref: listRef,
29052
- items,
29053
- messages,
29054
- command: (item) => {
29055
- item.command({ editor });
29056
- onClose();
29057
- }
29058
- }
29059
- );
29060
- };
29061
- var FloatingMenuContent = ({ editor }) => {
29062
- const t = useSmartTranslations("UEditor");
29063
- const [showCommands, setShowCommands] = (0, import_react62.useState)(false);
29064
- if (showCommands) {
29065
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(FloatingSlashCommandMenu, { editor, onClose: () => setShowCommands(false) });
29066
- }
29067
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
29068
- "button",
29069
- {
29070
- type: "button",
29071
- onClick: () => setShowCommands(true),
29072
- className: "flex items-center gap-1 px-2 py-1.5 rounded-lg hover:bg-accent transition-all group",
29073
- children: [
29074
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_lucide_react49.Plus, { className: "w-4 h-4 text-muted-foreground group-hover:text-foreground" }),
29075
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "text-sm text-muted-foreground group-hover:text-foreground", children: t("floatingMenu.addBlock") })
29076
- ]
29077
- }
29078
- );
29079
- };
29080
29134
  function applyTableCellBackground(editor, color) {
29081
29135
  const value = color || null;
29082
29136
  const { state, view } = editor;
@@ -29703,54 +29757,6 @@ var CustomBubbleMenu = ({
29703
29757
  document.body
29704
29758
  );
29705
29759
  };
29706
- var CustomFloatingMenu = ({ editor }) => {
29707
- const FLOATING_MENU_OFFSET = 16;
29708
- const [isVisible, setIsVisible] = (0, import_react62.useState)(false);
29709
- const [position, setPosition] = (0, import_react62.useState)({ top: 0, left: 0 });
29710
- (0, import_react62.useEffect)(() => {
29711
- const updatePosition = () => {
29712
- const { state, view } = editor;
29713
- const { $from, empty } = state.selection;
29714
- const isEmptyTextBlock = $from.parent.isTextblock && $from.parent.type.name === "paragraph" && $from.parent.textContent === "" && empty;
29715
- if (!isEmptyTextBlock || !view.hasFocus()) {
29716
- setIsVisible(false);
29717
- return;
29718
- }
29719
- const coords = view.coordsAtPos($from.pos);
29720
- setPosition({ top: coords.top - FLOATING_MENU_OFFSET, left: coords.left });
29721
- setIsVisible(true);
29722
- };
29723
- const handleBlur = () => setIsVisible(false);
29724
- editor.on("selectionUpdate", updatePosition);
29725
- editor.on("focus", updatePosition);
29726
- editor.on("blur", handleBlur);
29727
- editor.on("update", updatePosition);
29728
- return () => {
29729
- editor.off("selectionUpdate", updatePosition);
29730
- editor.off("focus", updatePosition);
29731
- editor.off("blur", handleBlur);
29732
- editor.off("update", updatePosition);
29733
- };
29734
- }, [editor]);
29735
- if (!isVisible) return null;
29736
- return (0, import_react_dom8.createPortal)(
29737
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
29738
- "div",
29739
- {
29740
- "data-popover": true,
29741
- 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",
29742
- style: {
29743
- top: `${position.top}px`,
29744
- left: `${position.left}px`,
29745
- transform: "translate(-50%, -100%)"
29746
- },
29747
- onMouseDown: (e) => e.preventDefault(),
29748
- children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(FloatingMenuContent, { editor })
29749
- }
29750
- ),
29751
- document.body
29752
- );
29753
- };
29754
29760
 
29755
29761
  // src/components/UEditor/CharacterCount.tsx
29756
29762
  var import_jsx_runtime87 = require("react/jsx-runtime");
@@ -34525,8 +34531,8 @@ function TableAddRails({
34525
34531
  const visibleTableHeight = Math.min(layout.tableHeight, layout.viewportHeight);
34526
34532
  const columnRailTop = layout.tableTop;
34527
34533
  const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
34528
- const rowRailTop = layout.tableTop + visibleTableHeight + ADD_ROW_RAIL_GAP;
34529
- const rowRailLeft = layout.tableLeft;
34534
+ const rowRailTop = layout.wrapperTop + layout.wrapperHeight + ADD_ROW_RAIL_GAP;
34535
+ const rowRailLeft = Math.max(layout.tableLeft, layout.wrapperLeft);
34530
34536
  const showColumnRail = controlsVisible || addColumnVisible;
34531
34537
  const showRowRail = controlsVisible || addRowVisible;
34532
34538
  return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(import_jsx_runtime89.Fragment, { children: [
@@ -35156,6 +35162,7 @@ function TableControls({ editor, containerRef }) {
35156
35162
  const proseMirror = editor.view.dom;
35157
35163
  const surface = containerRef.current;
35158
35164
  if (!surface) return void 0;
35165
+ const scrollListenerOptions = { passive: true, capture: true };
35159
35166
  const handleMouseOver = (event) => {
35160
35167
  if (dragStateRef.current) return;
35161
35168
  const cell = getCellFromTarget(event.target);
@@ -35181,7 +35188,7 @@ function TableControls({ editor, containerRef }) {
35181
35188
  proseMirror.addEventListener("focusin", handleFocusIn);
35182
35189
  surface.addEventListener("mouseover", handleSurfaceMouseMove);
35183
35190
  surface.addEventListener("mousemove", handleSurfaceMouseMove);
35184
- surface.addEventListener("scroll", refreshCurrentLayout, { passive: true });
35191
+ surface.addEventListener("scroll", refreshCurrentLayout, scrollListenerOptions);
35185
35192
  surface.addEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, refreshCurrentLayout);
35186
35193
  window.addEventListener("resize", refreshCurrentLayout);
35187
35194
  editor.on("selectionUpdate", syncFromSelection);
@@ -35195,7 +35202,7 @@ function TableControls({ editor, containerRef }) {
35195
35202
  proseMirror.removeEventListener("focusin", handleFocusIn);
35196
35203
  surface.removeEventListener("mouseover", handleSurfaceMouseMove);
35197
35204
  surface.removeEventListener("mousemove", handleSurfaceMouseMove);
35198
- surface.removeEventListener("scroll", refreshCurrentLayout);
35205
+ surface.removeEventListener("scroll", refreshCurrentLayout, scrollListenerOptions);
35199
35206
  surface.removeEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, refreshCurrentLayout);
35200
35207
  window.removeEventListener("resize", refreshCurrentLayout);
35201
35208
  editor.off("selectionUpdate", syncFromSelection);
@@ -35636,6 +35643,7 @@ var UEDITOR_PROSEMIRROR_CLASS_NAME = cn(
35636
35643
  "[&_.tableWrapper::-webkit-scrollbar-thumb]:border-transparent",
35637
35644
  "[&_.tableWrapper::-webkit-scrollbar-thumb]:bg-border/70",
35638
35645
  "[&_.tableWrapper::-webkit-scrollbar-thumb:hover]:bg-muted-foreground/45",
35646
+ "[&_table]:w-auto",
35639
35647
  "[&_table]:table-fixed",
35640
35648
  "[&_table]:overflow-hidden",
35641
35649
  "[&_table]:select-text",
@@ -35664,7 +35672,7 @@ var UEDITOR_PROSEMIRROR_CLASS_NAME = cn(
35664
35672
  "[&_.column-resize-handle]:top-[-1px]",
35665
35673
  "[&_.column-resize-handle]:bottom-[-1px]",
35666
35674
  "[&_.column-resize-handle]:right-[-5px]",
35667
- "[&_.column-resize-handle]:z-10",
35675
+ "[&_.column-resize-handle]:z-30",
35668
35676
  "[&_.column-resize-handle]:w-2.5",
35669
35677
  "[&_.column-resize-handle]:bg-transparent",
35670
35678
  "[&_.column-resize-handle]:rounded-none",
@@ -35918,26 +35926,31 @@ function useUEditorTableInteractions(editor, editable = true) {
35918
35926
  const activeTableCellRef = (0, import_react66.useRef)(null);
35919
35927
  const suppressActiveCellHighlightRef = (0, import_react66.useRef)(false);
35920
35928
  const tableLayoutSyncFrameRef = (0, import_react66.useRef)(null);
35929
+ const getProseMirrorElement = import_react66.default.useCallback(() => {
35930
+ return editorContentRef.current?.querySelector(".ProseMirror");
35931
+ }, []);
35921
35932
  const setEditorResizeCursor = import_react66.default.useCallback((cursor) => {
35922
- const proseMirror = editorContentRef.current?.querySelector(".ProseMirror");
35933
+ const proseMirror = getProseMirrorElement();
35923
35934
  if (proseMirror) {
35924
35935
  proseMirror.style.cursor = cursor;
35925
35936
  }
35926
- }, []);
35937
+ }, [getProseMirrorElement]);
35927
35938
  const hideColumnGuide = import_react66.default.useCallback(() => {
35928
35939
  editorContentRef.current?.classList.remove("resize-cursor");
35940
+ getProseMirrorElement()?.classList.remove("resize-cursor");
35929
35941
  const guide = tableColumnGuideRef.current;
35930
35942
  if (guide) {
35931
35943
  guide.style.opacity = "0";
35932
35944
  }
35933
- }, []);
35945
+ }, [getProseMirrorElement]);
35934
35946
  const hideRowGuide = import_react66.default.useCallback(() => {
35935
35947
  editorContentRef.current?.classList.remove("resize-row-cursor");
35948
+ getProseMirrorElement()?.classList.remove("resize-row-cursor");
35936
35949
  const guide = tableRowGuideRef.current;
35937
35950
  if (guide) {
35938
35951
  guide.style.opacity = "0";
35939
35952
  }
35940
- }, []);
35953
+ }, [getProseMirrorElement]);
35941
35954
  const clearAllTableResizeHover = import_react66.default.useCallback(() => {
35942
35955
  setEditorResizeCursor("");
35943
35956
  hideColumnGuide();
@@ -35967,7 +35980,10 @@ function useUEditorTableInteractions(editor, editable = true) {
35967
35980
  });
35968
35981
  }, [updateActiveCellHighlight]);
35969
35982
  const setActiveTableCell = import_react66.default.useCallback((cell) => {
35970
- if (activeTableCellRef.current === cell) return;
35983
+ if (activeTableCellRef.current === cell) {
35984
+ updateActiveCellHighlight(cell);
35985
+ return;
35986
+ }
35971
35987
  activeTableCellRef.current = cell;
35972
35988
  updateActiveCellHighlight(activeTableCellRef.current);
35973
35989
  }, [updateActiveCellHighlight]);
@@ -35992,8 +36008,9 @@ function useUEditorTableInteractions(editor, editable = true) {
35992
36008
  guide.style.height = `${metrics.height}px`;
35993
36009
  guide.style.opacity = "1";
35994
36010
  surface.classList.add("resize-cursor");
36011
+ getProseMirrorElement()?.classList.add("resize-cursor");
35995
36012
  setEditorResizeCursor("col-resize");
35996
- }, [setEditorResizeCursor]);
36013
+ }, [getProseMirrorElement, setEditorResizeCursor]);
35997
36014
  const showRowGuide = import_react66.default.useCallback((table, row, cell) => {
35998
36015
  const surface = editorContentRef.current;
35999
36016
  const guide = tableRowGuideRef.current;
@@ -36005,8 +36022,9 @@ function useUEditorTableInteractions(editor, editable = true) {
36005
36022
  guide.style.height = `${ROW_RESIZE_LINE_THICKNESS}px`;
36006
36023
  guide.style.opacity = "1";
36007
36024
  surface.classList.add("resize-row-cursor");
36025
+ getProseMirrorElement()?.classList.add("resize-row-cursor");
36008
36026
  setEditorResizeCursor("row-resize");
36009
- }, [setEditorResizeCursor]);
36027
+ }, [getProseMirrorElement, setEditorResizeCursor]);
36010
36028
  const {
36011
36029
  beginResize,
36012
36030
  cancelResize,
@@ -36025,19 +36043,32 @@ function useUEditorTableInteractions(editor, editable = true) {
36025
36043
  });
36026
36044
  const syncActiveTableCellFromSelection = import_react66.default.useCallback(() => {
36027
36045
  if (!editor) return;
36046
+ if (!editor.isFocused) {
36047
+ clearActiveTableCell();
36048
+ return;
36049
+ }
36028
36050
  setActiveTableCell(getSelectionTableCell(editor.view));
36029
- }, [editor, setActiveTableCell]);
36051
+ }, [clearActiveTableCell, editor, setActiveTableCell]);
36030
36052
  (0, import_react66.useEffect)(() => {
36031
36053
  if (!editor || !editable) return void 0;
36032
36054
  const proseMirror = editor.view.dom;
36033
36055
  const surface = editorContentRef.current;
36034
36056
  let selectionSyncTimeoutId = 0;
36057
+ const scrollListenerOptions = { passive: true, capture: true };
36035
36058
  const scheduleActiveCellSync = (fallbackCell = null) => {
36036
36059
  requestAnimationFrame(() => {
36060
+ if (!editor.isFocused) {
36061
+ clearActiveTableCell();
36062
+ return;
36063
+ }
36037
36064
  setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
36038
36065
  });
36039
36066
  window.clearTimeout(selectionSyncTimeoutId);
36040
36067
  selectionSyncTimeoutId = window.setTimeout(() => {
36068
+ if (!editor.isFocused) {
36069
+ clearActiveTableCell();
36070
+ return;
36071
+ }
36041
36072
  setActiveTableCell(getSelectionTableCell(editor.view) ?? fallbackCell);
36042
36073
  }, 0);
36043
36074
  };
@@ -36141,13 +36172,15 @@ function useUEditorTableInteractions(editor, editable = true) {
36141
36172
  proseMirror.addEventListener("keyup", handleSelectionChange);
36142
36173
  proseMirror.addEventListener("focusin", handleSelectionChange);
36143
36174
  document.addEventListener("selectionchange", handleSelectionChange);
36144
- surface?.addEventListener("scroll", handleActiveCellLayoutChange, { passive: true });
36175
+ surface?.addEventListener("scroll", handleActiveCellLayoutChange, scrollListenerOptions);
36145
36176
  window.addEventListener("resize", handleActiveCellLayoutChange);
36146
36177
  document.addEventListener("pointermove", handlePointerMove);
36147
36178
  document.addEventListener("pointerup", handlePointerUp);
36148
36179
  window.addEventListener("blur", handleWindowBlur);
36149
36180
  editor.on("selectionUpdate", syncActiveTableCellFromSelection);
36150
36181
  editor.on("focus", syncActiveTableCellFromSelection);
36182
+ editor.on("blur", clearActiveTableCell);
36183
+ editor.on("update", scheduleTableLayoutSync);
36151
36184
  syncActiveTableCellFromSelection();
36152
36185
  return () => {
36153
36186
  proseMirror.removeEventListener("mousemove", handleEditorMouseMove);
@@ -36158,13 +36191,15 @@ function useUEditorTableInteractions(editor, editable = true) {
36158
36191
  proseMirror.removeEventListener("keyup", handleSelectionChange);
36159
36192
  proseMirror.removeEventListener("focusin", handleSelectionChange);
36160
36193
  document.removeEventListener("selectionchange", handleSelectionChange);
36161
- surface?.removeEventListener("scroll", handleActiveCellLayoutChange);
36194
+ surface?.removeEventListener("scroll", handleActiveCellLayoutChange, scrollListenerOptions);
36162
36195
  window.removeEventListener("resize", handleActiveCellLayoutChange);
36163
36196
  document.removeEventListener("pointermove", handlePointerMove);
36164
36197
  document.removeEventListener("pointerup", handlePointerUp);
36165
36198
  window.removeEventListener("blur", handleWindowBlur);
36166
36199
  editor.off("selectionUpdate", syncActiveTableCellFromSelection);
36167
36200
  editor.off("focus", syncActiveTableCellFromSelection);
36201
+ editor.off("blur", clearActiveTableCell);
36202
+ editor.off("update", scheduleTableLayoutSync);
36168
36203
  window.clearTimeout(selectionSyncTimeoutId);
36169
36204
  if (tableLayoutSyncFrameRef.current !== null) {
36170
36205
  window.cancelAnimationFrame(tableLayoutSyncFrameRef.current);
@@ -36177,7 +36212,7 @@ function useUEditorTableInteractions(editor, editable = true) {
36177
36212
  clearHoveredTableCell();
36178
36213
  clearAllTableResizeHover();
36179
36214
  };
36180
- }, [beginResize, cancelResize, cleanupRowResize, clearActiveTableCell, clearAllTableResizeHover, clearHoveredTableCell, editable, editor, handleRowResizePointerMove, handleRowResizePointerUp, hideColumnGuide, hideRowGuide, isRowResizing, showColumnGuide, showRowGuide, syncActiveRowResizeGuide, syncActiveTableCellFromSelection, updateActiveCellHighlight]);
36215
+ }, [beginResize, cancelResize, cleanupRowResize, clearActiveTableCell, clearAllTableResizeHover, clearHoveredTableCell, editable, editor, handleRowResizePointerMove, handleRowResizePointerUp, hideColumnGuide, hideRowGuide, isRowResizing, scheduleTableLayoutSync, showColumnGuide, showRowGuide, syncActiveRowResizeGuide, syncActiveTableCellFromSelection, updateActiveCellHighlight]);
36181
36216
  return {
36182
36217
  editorContentRef,
36183
36218
  tableColumnGuideRef,
@@ -36679,6 +36714,13 @@ var MenuBar = ({
36679
36714
  const openPreviewDialog = () => {
36680
36715
  setShowPreviewDialog(true);
36681
36716
  };
36717
+ const handlePreview = () => {
36718
+ if (onPreview) {
36719
+ onPreview();
36720
+ return;
36721
+ }
36722
+ openPreviewDialog();
36723
+ };
36682
36724
  const applySourceHtml = () => {
36683
36725
  editor.chain().focus().setContent(sourceHtml).run();
36684
36726
  setShowSourceDialog(false);
@@ -36790,7 +36832,7 @@ var MenuBar = ({
36790
36832
  { label: t("menubar.edit"), items: buildEditMenuItems(t, editor), open: void 0, onOpenChange: void 0 },
36791
36833
  {
36792
36834
  label: t("menubar.view"),
36793
- items: buildViewMenuItems(t, { containerRef, onSourceCode, openSourceDialog, onPreview, openPreviewDialog }),
36835
+ items: buildViewMenuItems(t, { containerRef, onSourceCode, openSourceDialog, onPreview: handlePreview, openPreviewDialog }),
36794
36836
  open: void 0,
36795
36837
  onOpenChange: void 0
36796
36838
  },
@@ -36827,17 +36869,33 @@ var MenuBar = ({
36827
36869
  onChange: (e) => handleImageFiles(e.target.files)
36828
36870
  }
36829
36871
  ),
36830
- /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("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__ */ (0, import_jsx_runtime93.jsx)(
36831
- DropdownMenu,
36832
- {
36833
- trigger: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(MenuBarTrigger, { children: label }),
36834
- placement: "bottom-start",
36835
- isOpen: open,
36836
- onOpenChange,
36837
- children: renderMenuItems(items)
36838
- },
36839
- label
36840
- )) }),
36872
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)("div", { className: "flex items-center gap-0.5 border-b border-border/35 bg-muted/20 px-1.5 py-0.5", children: [
36873
+ menus.map(({ label, items, open, onOpenChange }) => /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
36874
+ DropdownMenu,
36875
+ {
36876
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(MenuBarTrigger, { children: label }),
36877
+ placement: "bottom-start",
36878
+ isOpen: open,
36879
+ onOpenChange,
36880
+ children: renderMenuItems(items)
36881
+ },
36882
+ label
36883
+ )),
36884
+ /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
36885
+ "button",
36886
+ {
36887
+ type: "button",
36888
+ onClick: handlePreview,
36889
+ "aria-label": t("menubar.preview"),
36890
+ title: t("menubar.preview"),
36891
+ className: cn(
36892
+ "ml-auto inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors",
36893
+ "hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1"
36894
+ ),
36895
+ children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(import_lucide_react53.Eye, { className: "h-4 w-4", "aria-hidden": "true" })
36896
+ }
36897
+ )
36898
+ ] }),
36841
36899
  /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
36842
36900
  Modal_default,
36843
36901
  {
@@ -36891,8 +36949,14 @@ var MenuBar = ({
36891
36949
  "div",
36892
36950
  {
36893
36951
  "data-testid": "preview-content",
36894
- className: "prose prose-sm sm:prose dark:prose-invert max-w-none p-2",
36895
- dangerouslySetInnerHTML: { __html: editor.getHTML() }
36952
+ className: "max-h-[70vh] overflow-y-auto overscroll-contain pr-2",
36953
+ children: /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
36954
+ "div",
36955
+ {
36956
+ className: UEDITOR_PROSEMIRROR_CLASS_NAME,
36957
+ dangerouslySetInnerHTML: { __html: editor.getHTML() }
36958
+ }
36959
+ )
36896
36960
  }
36897
36961
  )
36898
36962
  }
@@ -36920,7 +36984,6 @@ var UEditor = import_react69.default.forwardRef(({
36920
36984
  autofocus = false,
36921
36985
  showToolbar = true,
36922
36986
  showBubbleMenu = true,
36923
- showFloatingMenu = false,
36924
36987
  showCharacterCount = true,
36925
36988
  maxCharacters,
36926
36989
  minHeight = "200px",
@@ -37122,7 +37185,6 @@ var UEditor = import_react69.default.forwardRef(({
37122
37185
  lineHeights
37123
37186
  }
37124
37187
  ),
37125
- editable && showFloatingMenu && /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(CustomFloatingMenu, { editor }),
37126
37188
  /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)(
37127
37189
  "div",
37128
37190
  {
@@ -37155,7 +37217,7 @@ var UEditor = import_react69.default.forwardRef(({
37155
37217
  ref: activeTableCellHighlightRef,
37156
37218
  "aria-hidden": "true",
37157
37219
  "data-ueditor-active-cell-highlight": "",
37158
- className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10 transition-[left,top,width,height] duration-100"
37220
+ className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10"
37159
37221
  }
37160
37222
  ),
37161
37223
  editable && /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(TableControls, { editor, containerRef: editorContentRef }),