@underverse-ui/underverse 1.0.141 → 1.0.143

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
@@ -25431,6 +25431,7 @@ var import_extension_typography = __toESM(require("@tiptap/extension-typography"
25431
25431
  var import_extension_subscript = __toESM(require("@tiptap/extension-subscript"), 1);
25432
25432
  var import_extension_superscript = __toESM(require("@tiptap/extension-superscript"), 1);
25433
25433
  var import_extension_horizontal_rule = __toESM(require("@tiptap/extension-horizontal-rule"), 1);
25434
+ var import_extension_gapcursor = __toESM(require("@tiptap/extension-gapcursor"), 1);
25434
25435
  var import_lowlight = require("lowlight");
25435
25436
 
25436
25437
  // src/components/UEditor/slash-command.tsx
@@ -26206,7 +26207,6 @@ var import_core8 = require("@tiptap/core");
26206
26207
  var import_react54 = require("@tiptap/react");
26207
26208
  var import_jsx_runtime81 = require("react/jsx-runtime");
26208
26209
  var MIN_IMAGE_SIZE_PX = 40;
26209
- var AXIS_LOCK_THRESHOLD_PX = 4;
26210
26210
  var IMAGE_LAYOUTS = /* @__PURE__ */ new Set(["block", "left", "right"]);
26211
26211
  var IMAGE_WIDTH_PRESETS = /* @__PURE__ */ new Set(["sm", "md", "lg"]);
26212
26212
  function toNullableNumber(value) {
@@ -26247,6 +26247,41 @@ function getImageLayoutStyles(layout) {
26247
26247
  }
26248
26248
  return {};
26249
26249
  }
26250
+ function getAspectRatio({
26251
+ img,
26252
+ widthAttr,
26253
+ heightAttr,
26254
+ fallbackWidth,
26255
+ fallbackHeight
26256
+ }) {
26257
+ if (widthAttr && heightAttr) return widthAttr / heightAttr;
26258
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) return img.naturalWidth / img.naturalHeight;
26259
+ if (fallbackWidth > 0 && fallbackHeight > 0) return fallbackWidth / fallbackHeight;
26260
+ return 1;
26261
+ }
26262
+ function sizeFromWidth(width, aspect, maxWidth) {
26263
+ let nextW = clamp8(width, MIN_IMAGE_SIZE_PX, maxWidth);
26264
+ let nextH = nextW / aspect;
26265
+ if (nextH < MIN_IMAGE_SIZE_PX) {
26266
+ nextH = MIN_IMAGE_SIZE_PX;
26267
+ nextW = clamp8(nextH * aspect, MIN_IMAGE_SIZE_PX, maxWidth);
26268
+ nextH = nextW / aspect;
26269
+ }
26270
+ return { width: nextW, height: nextH };
26271
+ }
26272
+ function sizeFromHeight(height, aspect, maxWidth) {
26273
+ let nextH = Math.max(MIN_IMAGE_SIZE_PX, height);
26274
+ let nextW = nextH * aspect;
26275
+ if (nextW > maxWidth) {
26276
+ nextW = maxWidth;
26277
+ nextH = nextW / aspect;
26278
+ }
26279
+ if (nextW < MIN_IMAGE_SIZE_PX) {
26280
+ nextW = MIN_IMAGE_SIZE_PX;
26281
+ nextH = nextW / aspect;
26282
+ }
26283
+ return { width: nextW, height: nextH };
26284
+ }
26250
26285
  function ResizableImageNodeView(props) {
26251
26286
  const { node, selected, updateAttributes, editor, getPos } = props;
26252
26287
  const wrapperRef = (0, import_react53.useRef)(null);
@@ -26257,7 +26292,6 @@ function ResizableImageNodeView(props) {
26257
26292
  const heightAttr = toNullableNumber(node.attrs["height"]);
26258
26293
  const textAlign = String(node.attrs["textAlign"] ?? "");
26259
26294
  const imageLayout = parseImageLayout(node.attrs["imageLayout"]);
26260
- const preserveAspectByDefault = imageLayout === "left" || imageLayout === "right";
26261
26295
  const dragStateRef = (0, import_react53.useRef)(null);
26262
26296
  (0, import_react53.useEffect)(() => {
26263
26297
  const img = imgRef.current;
@@ -26281,7 +26315,13 @@ function ResizableImageNodeView(props) {
26281
26315
  const maxW = editorEl ? editorEl.getBoundingClientRect().width : Number.POSITIVE_INFINITY;
26282
26316
  const startW = Math.max(MIN_IMAGE_SIZE_PX, rect.width);
26283
26317
  const startH = Math.max(MIN_IMAGE_SIZE_PX, rect.height);
26284
- const aspect = startH > 0 ? startW / startH : 1;
26318
+ const aspect = getAspectRatio({
26319
+ img,
26320
+ widthAttr,
26321
+ heightAttr,
26322
+ fallbackWidth: startW,
26323
+ fallbackHeight: startH
26324
+ });
26285
26325
  dragStateRef.current = {
26286
26326
  pointerId: event.pointerId,
26287
26327
  startX: event.clientX,
@@ -26290,7 +26330,6 @@ function ResizableImageNodeView(props) {
26290
26330
  startH,
26291
26331
  lastW: startW,
26292
26332
  lastH: startH,
26293
- axis: null,
26294
26333
  aspect,
26295
26334
  maxW: Math.max(MIN_IMAGE_SIZE_PX, maxW)
26296
26335
  };
@@ -26304,24 +26343,9 @@ function ResizableImageNodeView(props) {
26304
26343
  if (event.pointerId !== drag.pointerId) return;
26305
26344
  const dx = event.clientX - drag.startX;
26306
26345
  const dy = event.clientY - drag.startY;
26307
- let nextW = drag.startW;
26308
- let nextH = drag.startH;
26309
- const shouldPreserveAspect = preserveAspectByDefault ? !event.ctrlKey : event.ctrlKey;
26310
- if (shouldPreserveAspect) {
26311
- if (Math.abs(dx) >= Math.abs(dy)) {
26312
- nextW = clamp8(drag.startW + dx, MIN_IMAGE_SIZE_PX, drag.maxW);
26313
- nextH = clamp8(nextW / drag.aspect, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
26314
- } else {
26315
- nextH = clamp8(drag.startH + dy, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
26316
- nextW = clamp8(nextH * drag.aspect, MIN_IMAGE_SIZE_PX, drag.maxW);
26317
- }
26318
- } else {
26319
- if (!drag.axis && (Math.abs(dx) > AXIS_LOCK_THRESHOLD_PX || Math.abs(dy) > AXIS_LOCK_THRESHOLD_PX)) {
26320
- drag.axis = Math.abs(dx) >= Math.abs(dy) ? "x" : "y";
26321
- }
26322
- if (drag.axis === "x") nextW = clamp8(drag.startW + dx, MIN_IMAGE_SIZE_PX, drag.maxW);
26323
- if (drag.axis === "y") nextH = clamp8(drag.startH + dy, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
26324
- }
26346
+ const nextSize = Math.abs(dx) >= Math.abs(dy) ? sizeFromWidth(drag.startW + dx, drag.aspect, drag.maxW) : sizeFromHeight(drag.startH + dy, drag.aspect, drag.maxW);
26347
+ const nextW = nextSize.width;
26348
+ const nextH = nextSize.height;
26325
26349
  drag.lastW = nextW;
26326
26350
  drag.lastH = nextH;
26327
26351
  img.style.width = `${Math.round(nextW)}px`;
@@ -27244,6 +27268,7 @@ function buildUEditorExtensions({
27244
27268
  }
27245
27269
  }),
27246
27270
  import_extension_horizontal_rule.default,
27271
+ import_extension_gapcursor.default,
27247
27272
  import_extension_link.default.configure({
27248
27273
  openOnClick: false,
27249
27274
  protocols: ["http", "https", "mailto", "tel"],
@@ -27277,7 +27302,7 @@ function buildUEditorExtensions({
27277
27302
  handleWidth: 10,
27278
27303
  allowTableNodeSelection: true,
27279
27304
  HTMLAttributes: {
27280
- class: "border-collapse w-full my-4"
27305
+ class: "border-collapse my-4"
27281
27306
  }
27282
27307
  }),
27283
27308
  table_row_default,
@@ -27593,6 +27618,43 @@ function isSelectedImage(editor) {
27593
27618
  const { selection } = editor.state;
27594
27619
  return selection instanceof import_state6.NodeSelection && selection.node.type.name === "image";
27595
27620
  }
27621
+ function toPositiveNumber(value) {
27622
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
27623
+ if (typeof value === "string") {
27624
+ const parsed = Number.parseInt(value, 10);
27625
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
27626
+ }
27627
+ return null;
27628
+ }
27629
+ function getImageElementAtSelection(editor, pos) {
27630
+ const nodeDom = editor.view.nodeDOM(pos);
27631
+ if (!(nodeDom instanceof HTMLElement)) return null;
27632
+ if (nodeDom.tagName === "IMG") return nodeDom;
27633
+ return nodeDom.querySelector("img");
27634
+ }
27635
+ function getImageAspectRatio(editor, attrs, pos) {
27636
+ const widthAttr = toPositiveNumber(attrs.width);
27637
+ const heightAttr = toPositiveNumber(attrs.height);
27638
+ if (widthAttr && heightAttr) return widthAttr / heightAttr;
27639
+ const imageElement = typeof pos === "number" ? getImageElementAtSelection(editor, pos) : null;
27640
+ if (!imageElement) return null;
27641
+ if (imageElement.naturalWidth > 0 && imageElement.naturalHeight > 0) {
27642
+ return imageElement.naturalWidth / imageElement.naturalHeight;
27643
+ }
27644
+ const rect = imageElement.getBoundingClientRect();
27645
+ if (rect.width > 0 && rect.height > 0) return rect.width / rect.height;
27646
+ const width = toPositiveNumber(imageElement.getAttribute("width")) ?? toPositiveNumber(imageElement.style.width);
27647
+ const height = toPositiveNumber(imageElement.getAttribute("height")) ?? toPositiveNumber(imageElement.style.height);
27648
+ return width && height ? width / height : null;
27649
+ }
27650
+ function getImagePresetAttributes(editor, width, preset, attrs, pos) {
27651
+ const aspect = getImageAspectRatio(editor, attrs, pos);
27652
+ return {
27653
+ width,
27654
+ height: aspect ? Math.round(width / aspect) : toPositiveNumber(attrs.height),
27655
+ imageWidthPreset: preset
27656
+ };
27657
+ }
27596
27658
  function applyImageLayout(editor, layout) {
27597
27659
  const { state, view } = editor;
27598
27660
  const { selection, schema } = state;
@@ -27627,15 +27689,15 @@ function applyImageWidthPreset(editor, preset) {
27627
27689
  const mode = attrs.imageLayout === "left" || attrs.imageLayout === "right" ? "wrap" : "block";
27628
27690
  const width = IMAGE_WIDTHS_BY_LAYOUT[mode][preset];
27629
27691
  if (!isSelectedImage(editor)) {
27630
- editor.chain().focus().updateAttributes("image", { width, imageWidthPreset: preset }).run();
27692
+ editor.chain().focus().updateAttributes("image", getImagePresetAttributes(editor, width, preset, attrs)).run();
27631
27693
  return;
27632
27694
  }
27633
27695
  const { state, view } = editor;
27634
27696
  const selection = state.selection;
27697
+ const nextAttrs = getImagePresetAttributes(editor, width, preset, selection.node.attrs, selection.from);
27635
27698
  const transaction = state.tr.setNodeMarkup(selection.from, void 0, {
27636
27699
  ...selection.node.attrs,
27637
- width,
27638
- imageWidthPreset: preset
27700
+ ...nextAttrs
27639
27701
  });
27640
27702
  view.dispatch(transaction.scrollIntoView());
27641
27703
  view.focus();
@@ -27763,6 +27825,229 @@ var ImageInput = ({ onSubmit, onCancel }) => {
27763
27825
  ] });
27764
27826
  };
27765
27827
 
27828
+ // src/components/UEditor/table-cell-commands.ts
27829
+ var import_state7 = require("@tiptap/pm/state");
27830
+ var import_tables = require("@tiptap/pm/tables");
27831
+ function getCellSelectionPositions(selection) {
27832
+ const value = selection;
27833
+ const anchor = value.$anchorCell?.pos;
27834
+ const head = value.$headCell?.pos;
27835
+ return typeof anchor === "number" && typeof head === "number" ? { anchor, head } : null;
27836
+ }
27837
+ function findTableInfoFromCellPos(editor, cellPos) {
27838
+ const $pos = editor.state.doc.resolve(cellPos);
27839
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
27840
+ const node = $pos.node(depth);
27841
+ if (node.type.name === "table") {
27842
+ return {
27843
+ table: node,
27844
+ tablePos: $pos.before(depth),
27845
+ tableStart: $pos.start(depth)
27846
+ };
27847
+ }
27848
+ }
27849
+ return null;
27850
+ }
27851
+ function getFocusableCellPos(editor, cellPos) {
27852
+ const cellNode = editor.state.doc.nodeAt(cellPos);
27853
+ if (!cellNode) return cellPos + 1;
27854
+ let offset = cellPos + 1;
27855
+ let node = cellNode.firstChild ?? null;
27856
+ while (node && !node.isTextblock) {
27857
+ offset += 1;
27858
+ node = node.firstChild ?? null;
27859
+ }
27860
+ return node?.isTextblock ? offset + 1 : cellPos + 1;
27861
+ }
27862
+ function focusCell(editor, cellPos) {
27863
+ const selection = import_state7.TextSelection.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
27864
+ editor.view.dispatch(editor.state.tr.setSelection(selection));
27865
+ editor.view.focus();
27866
+ }
27867
+ function collectChildren(node) {
27868
+ const children = [];
27869
+ node.forEach((child) => children.push(child));
27870
+ return children;
27871
+ }
27872
+ function createEmptyCellNode(cellNode) {
27873
+ return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
27874
+ }
27875
+ function getSelectedTableRect(editor) {
27876
+ const cellSelection = getCellSelectionPositions(editor.state.selection);
27877
+ if (cellSelection) {
27878
+ const tableInfo = findTableInfoFromCellPos(editor, cellSelection.anchor);
27879
+ if (tableInfo) {
27880
+ const map = import_tables.TableMap.get(tableInfo.table);
27881
+ const rect = map.rectBetween(
27882
+ cellSelection.anchor - tableInfo.tableStart,
27883
+ cellSelection.head - tableInfo.tableStart
27884
+ );
27885
+ return {
27886
+ ...rect,
27887
+ map,
27888
+ table: tableInfo.table,
27889
+ tableStart: tableInfo.tableStart
27890
+ };
27891
+ }
27892
+ }
27893
+ return (0, import_tables.selectedRect)(editor.state);
27894
+ }
27895
+ function parsePixelWidth(value) {
27896
+ if (!value) return null;
27897
+ const parsed = Number.parseFloat(value);
27898
+ return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : null;
27899
+ }
27900
+ function getDomColumnWidths(editor, rect) {
27901
+ const tableDom = editor.view.nodeDOM(rect.tableStart - 1);
27902
+ if (!(tableDom instanceof HTMLTableElement)) return null;
27903
+ const cols = Array.from(tableDom.querySelectorAll("colgroup > col"));
27904
+ if (cols.length === 0) return null;
27905
+ const widths = [];
27906
+ for (let col = rect.left; col < rect.right; col += 1) {
27907
+ const colElement = cols[col];
27908
+ if (!colElement) return null;
27909
+ const width = parsePixelWidth(colElement.style.width) ?? parsePixelWidth(colElement.getAttribute("width")) ?? Math.round(colElement.getBoundingClientRect().width);
27910
+ if (!Number.isFinite(width) || width <= 0) return null;
27911
+ widths.push(width);
27912
+ }
27913
+ return widths.length > 0 ? widths : null;
27914
+ }
27915
+ function getNodeColumnWidths(rect) {
27916
+ const widths = [];
27917
+ for (let col = rect.left; col < rect.right; col += 1) {
27918
+ let width = null;
27919
+ const seen = /* @__PURE__ */ new Set();
27920
+ for (let row = 0; row < rect.map.height && width == null; row += 1) {
27921
+ const cellPos = rect.map.map[row * rect.map.width + col];
27922
+ if (seen.has(cellPos)) continue;
27923
+ seen.add(cellPos);
27924
+ const cell = rect.table.nodeAt(cellPos);
27925
+ const colwidth = cell?.attrs.colwidth;
27926
+ if (!Array.isArray(colwidth)) continue;
27927
+ const cellLeft = rect.map.colCount(cellPos);
27928
+ const widthIndex = col - cellLeft;
27929
+ const candidate = colwidth[widthIndex];
27930
+ if (typeof candidate === "number" && candidate > 0) {
27931
+ width = candidate;
27932
+ }
27933
+ }
27934
+ if (width == null) return null;
27935
+ widths.push(width);
27936
+ }
27937
+ return widths.length > 0 ? widths : null;
27938
+ }
27939
+ function getSelectedColumnWidths(editor, rect) {
27940
+ return getDomColumnWidths(editor, rect) ?? getNodeColumnWidths(rect);
27941
+ }
27942
+ function dispatchTableLayoutChange(editor) {
27943
+ editor.view.dom.dispatchEvent(new CustomEvent(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, { bubbles: true }));
27944
+ }
27945
+ function mergeTableCellsPreservingColumnWidths(editor) {
27946
+ const rect = getSelectedTableRect(editor);
27947
+ const widths = getSelectedColumnWidths(editor, rect);
27948
+ const merged = editor.chain().focus().mergeCells().run();
27949
+ if (!merged) return merged;
27950
+ if (!widths) {
27951
+ dispatchTableLayoutChange(editor);
27952
+ return merged;
27953
+ }
27954
+ const nextRect = getSelectedTableRect(editor);
27955
+ const cellPos = nextRect.map.map[nextRect.top * nextRect.map.width + nextRect.left];
27956
+ const absolutePos = nextRect.tableStart + cellPos;
27957
+ const node = editor.state.doc.nodeAt(absolutePos);
27958
+ if (!node) return merged;
27959
+ editor.view.dispatch(
27960
+ editor.state.tr.setNodeMarkup(absolutePos, node.type, {
27961
+ ...node.attrs,
27962
+ colwidth: widths
27963
+ })
27964
+ );
27965
+ dispatchTableLayoutChange(editor);
27966
+ return true;
27967
+ }
27968
+ function runTableCommandAtCellPos(editor, cellPos, command) {
27969
+ if (cellPos == null) return false;
27970
+ focusCell(editor, cellPos);
27971
+ return command(editor.chain().focus(null, { scrollIntoView: false })).run();
27972
+ }
27973
+ function getTableCornerCellPos(editor, activePos) {
27974
+ const tableInfo = findTableInfoFromCellPos(editor, activePos);
27975
+ if (!tableInfo) return null;
27976
+ const map = import_tables.TableMap.get(tableInfo.table);
27977
+ return tableInfo.tableStart + map.positionAt(map.height - 1, map.width - 1, tableInfo.table);
27978
+ }
27979
+ function replaceTableAtCellPos(editor, cellPos, updateTable) {
27980
+ if (cellPos == null) return false;
27981
+ const tableInfo = findTableInfoFromCellPos(editor, cellPos);
27982
+ if (!tableInfo) return false;
27983
+ const nextTable = updateTable(tableInfo.table);
27984
+ if (!nextTable) return false;
27985
+ editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.tablePos, tableInfo.tablePos + tableInfo.table.nodeSize, nextTable));
27986
+ dispatchTableLayoutChange(editor);
27987
+ return true;
27988
+ }
27989
+ function duplicateTableRowAt(editor, rowIndex, cellPos) {
27990
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
27991
+ const rows = collectChildren(tableNode);
27992
+ const rowNode = rows[rowIndex];
27993
+ if (!rowNode) return null;
27994
+ rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
27995
+ return tableNode.type.create(tableNode.attrs, rows);
27996
+ });
27997
+ }
27998
+ function clearTableRowAt(editor, rowIndex, cellPos) {
27999
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28000
+ const rows = collectChildren(tableNode);
28001
+ const rowNode = rows[rowIndex];
28002
+ if (!rowNode) return null;
28003
+ const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
28004
+ rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
28005
+ return tableNode.type.create(tableNode.attrs, rows);
28006
+ });
28007
+ }
28008
+ function duplicateTableColumnAt(editor, columnIndex, cellPos) {
28009
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28010
+ const rows = collectChildren(tableNode).map((rowNode) => {
28011
+ const cells = collectChildren(rowNode);
28012
+ const cellNode = cells[columnIndex];
28013
+ if (!cellNode) return rowNode;
28014
+ cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
28015
+ return rowNode.type.create(rowNode.attrs, cells);
28016
+ });
28017
+ return tableNode.type.create(tableNode.attrs, rows);
28018
+ });
28019
+ }
28020
+ function clearTableColumnAt(editor, columnIndex, cellPos) {
28021
+ return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28022
+ const rows = collectChildren(tableNode).map((rowNode) => {
28023
+ const cells = collectChildren(rowNode);
28024
+ const cellNode = cells[columnIndex];
28025
+ if (!cellNode) return rowNode;
28026
+ cells[columnIndex] = createEmptyCellNode(cellNode);
28027
+ return rowNode.type.create(rowNode.attrs, cells);
28028
+ });
28029
+ return tableNode.type.create(tableNode.attrs, rows);
28030
+ });
28031
+ }
28032
+ function expandTableFromCell(editor, activeCellPos, rows, columns) {
28033
+ let cornerCellPos = getTableCornerCellPos(editor, activeCellPos);
28034
+ if (cornerCellPos == null) return false;
28035
+ for (let index = 0; index < rows; index += 1) {
28036
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addRowAfter());
28037
+ if (!ok) return false;
28038
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28039
+ if (cornerCellPos == null) return false;
28040
+ }
28041
+ for (let index = 0; index < columns; index += 1) {
28042
+ const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addColumnAfter());
28043
+ if (!ok) return false;
28044
+ cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28045
+ if (cornerCellPos == null) return false;
28046
+ }
28047
+ dispatchTableLayoutChange(editor);
28048
+ return true;
28049
+ }
28050
+
27766
28051
  // src/components/UEditor/typography-options.ts
27767
28052
  function normalizeStyleValue(value) {
27768
28053
  return typeof value === "string" ? value.trim().replace(/^['"]|['"]$/g, "") : "";
@@ -27958,6 +28243,8 @@ var EditorToolbar = ({
27958
28243
  const currentTableAlign = tableAlignAttr === "center" || tableAlignAttr === "right" ? tableAlignAttr : "left";
27959
28244
  const isTableSelected = tableInfo !== null;
27960
28245
  const hasTableContext = isTableSelected || tableCommandAnchorPosRef.current !== null;
28246
+ const canMergeCells = hasTableContext && editor.can().mergeCells();
28247
+ const canSplitCell = hasTableContext && editor.can().splitCell();
27961
28248
  const currentFontFamily = normalizeStyleValue(textStyleAttrs.fontFamily);
27962
28249
  const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
27963
28250
  const currentTextColor = normalizeStyleValue(textStyleAttrs.color) || "inherit";
@@ -28727,241 +29014,71 @@ var EditorToolbar = ({
28727
29014
  ),
28728
29015
  /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarDivider, {}),
28729
29016
  /* @__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" }) }),
28730
- /* @__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" }) })
28731
- ] });
28732
- };
28733
-
28734
- // src/components/UEditor/menus.tsx
28735
- var import_react62 = require("react");
28736
- var import_react63 = require("@tiptap/react");
28737
- var import_tables2 = require("@tiptap/pm/tables");
28738
- var import_react_dom8 = require("react-dom");
28739
- var import_lucide_react49 = require("lucide-react");
28740
-
28741
- // src/components/UEditor/table-cell-commands.ts
28742
- var import_state7 = require("@tiptap/pm/state");
28743
- var import_tables = require("@tiptap/pm/tables");
28744
- function getCellSelectionPositions(selection) {
28745
- const value = selection;
28746
- const anchor = value.$anchorCell?.pos;
28747
- const head = value.$headCell?.pos;
28748
- return typeof anchor === "number" && typeof head === "number" ? { anchor, head } : null;
28749
- }
28750
- function findTableInfoFromCellPos(editor, cellPos) {
28751
- const $pos = editor.state.doc.resolve(cellPos);
28752
- for (let depth = $pos.depth; depth > 0; depth -= 1) {
28753
- const node = $pos.node(depth);
28754
- if (node.type.name === "table") {
28755
- return {
28756
- table: node,
28757
- tablePos: $pos.before(depth),
28758
- tableStart: $pos.start(depth)
28759
- };
28760
- }
28761
- }
28762
- return null;
28763
- }
28764
- function getFocusableCellPos(editor, cellPos) {
28765
- const cellNode = editor.state.doc.nodeAt(cellPos);
28766
- if (!cellNode) return cellPos + 1;
28767
- let offset = cellPos + 1;
28768
- let node = cellNode.firstChild ?? null;
28769
- while (node && !node.isTextblock) {
28770
- offset += 1;
28771
- node = node.firstChild ?? null;
28772
- }
28773
- return node?.isTextblock ? offset + 1 : cellPos + 1;
28774
- }
28775
- function focusCell(editor, cellPos) {
28776
- const selection = import_state7.TextSelection.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
28777
- editor.view.dispatch(editor.state.tr.setSelection(selection));
28778
- editor.view.focus();
28779
- }
28780
- function collectChildren(node) {
28781
- const children = [];
28782
- node.forEach((child) => children.push(child));
28783
- return children;
28784
- }
28785
- function createEmptyCellNode(cellNode) {
28786
- return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
28787
- }
28788
- function getSelectedTableRect(editor) {
28789
- const cellSelection = getCellSelectionPositions(editor.state.selection);
28790
- if (cellSelection) {
28791
- const tableInfo = findTableInfoFromCellPos(editor, cellSelection.anchor);
28792
- if (tableInfo) {
28793
- const map = import_tables.TableMap.get(tableInfo.table);
28794
- const rect = map.rectBetween(
28795
- cellSelection.anchor - tableInfo.tableStart,
28796
- cellSelection.head - tableInfo.tableStart
28797
- );
28798
- return {
28799
- ...rect,
28800
- map,
28801
- table: tableInfo.table,
28802
- tableStart: tableInfo.tableStart
28803
- };
28804
- }
28805
- }
28806
- return (0, import_tables.selectedRect)(editor.state);
28807
- }
28808
- function parsePixelWidth(value) {
28809
- if (!value) return null;
28810
- const parsed = Number.parseFloat(value);
28811
- return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : null;
28812
- }
28813
- function getDomColumnWidths(editor, rect) {
28814
- const tableDom = editor.view.nodeDOM(rect.tableStart - 1);
28815
- if (!(tableDom instanceof HTMLTableElement)) return null;
28816
- const cols = Array.from(tableDom.querySelectorAll("colgroup > col"));
28817
- if (cols.length === 0) return null;
28818
- const widths = [];
28819
- for (let col = rect.left; col < rect.right; col += 1) {
28820
- const colElement = cols[col];
28821
- if (!colElement) return null;
28822
- const width = parsePixelWidth(colElement.style.width) ?? parsePixelWidth(colElement.getAttribute("width")) ?? Math.round(colElement.getBoundingClientRect().width);
28823
- if (!Number.isFinite(width) || width <= 0) return null;
28824
- widths.push(width);
28825
- }
28826
- return widths.length > 0 ? widths : null;
28827
- }
28828
- function getNodeColumnWidths(rect) {
28829
- const widths = [];
28830
- for (let col = rect.left; col < rect.right; col += 1) {
28831
- let width = null;
28832
- const seen = /* @__PURE__ */ new Set();
28833
- for (let row = 0; row < rect.map.height && width == null; row += 1) {
28834
- const cellPos = rect.map.map[row * rect.map.width + col];
28835
- if (seen.has(cellPos)) continue;
28836
- seen.add(cellPos);
28837
- const cell = rect.table.nodeAt(cellPos);
28838
- const colwidth = cell?.attrs.colwidth;
28839
- if (!Array.isArray(colwidth)) continue;
28840
- const cellLeft = rect.map.colCount(cellPos);
28841
- const widthIndex = col - cellLeft;
28842
- const candidate = colwidth[widthIndex];
28843
- if (typeof candidate === "number" && candidate > 0) {
28844
- width = candidate;
28845
- }
28846
- }
28847
- if (width == null) return null;
28848
- widths.push(width);
28849
- }
28850
- return widths.length > 0 ? widths : null;
28851
- }
28852
- function getSelectedColumnWidths(editor, rect) {
28853
- return getDomColumnWidths(editor, rect) ?? getNodeColumnWidths(rect);
28854
- }
28855
- function dispatchTableLayoutChange(editor) {
28856
- editor.view.dom.dispatchEvent(new CustomEvent(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, { bubbles: true }));
28857
- }
28858
- function mergeTableCellsPreservingColumnWidths(editor) {
28859
- const rect = getSelectedTableRect(editor);
28860
- const widths = getSelectedColumnWidths(editor, rect);
28861
- const merged = editor.chain().focus().mergeCells().run();
28862
- if (!merged) return merged;
28863
- if (!widths) {
28864
- dispatchTableLayoutChange(editor);
28865
- return merged;
28866
- }
28867
- const nextRect = getSelectedTableRect(editor);
28868
- const cellPos = nextRect.map.map[nextRect.top * nextRect.map.width + nextRect.left];
28869
- const absolutePos = nextRect.tableStart + cellPos;
28870
- const node = editor.state.doc.nodeAt(absolutePos);
28871
- if (!node) return merged;
28872
- editor.view.dispatch(
28873
- editor.state.tr.setNodeMarkup(absolutePos, node.type, {
28874
- ...node.attrs,
28875
- colwidth: widths
28876
- })
28877
- );
28878
- dispatchTableLayoutChange(editor);
28879
- return true;
28880
- }
28881
- function runTableCommandAtCellPos(editor, cellPos, command) {
28882
- if (cellPos == null) return false;
28883
- focusCell(editor, cellPos);
28884
- return command(editor.chain().focus(null, { scrollIntoView: false })).run();
28885
- }
28886
- function getTableCornerCellPos(editor, activePos) {
28887
- const tableInfo = findTableInfoFromCellPos(editor, activePos);
28888
- if (!tableInfo) return null;
28889
- const map = import_tables.TableMap.get(tableInfo.table);
28890
- return tableInfo.tableStart + map.positionAt(map.height - 1, map.width - 1, tableInfo.table);
28891
- }
28892
- function replaceTableAtCellPos(editor, cellPos, updateTable) {
28893
- if (cellPos == null) return false;
28894
- const tableInfo = findTableInfoFromCellPos(editor, cellPos);
28895
- if (!tableInfo) return false;
28896
- const nextTable = updateTable(tableInfo.table);
28897
- if (!nextTable) return false;
28898
- editor.view.dispatch(editor.state.tr.replaceWith(tableInfo.tablePos, tableInfo.tablePos + tableInfo.table.nodeSize, nextTable));
28899
- dispatchTableLayoutChange(editor);
28900
- return true;
28901
- }
28902
- function duplicateTableRowAt(editor, rowIndex, cellPos) {
28903
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28904
- const rows = collectChildren(tableNode);
28905
- const rowNode = rows[rowIndex];
28906
- if (!rowNode) return null;
28907
- rows.splice(rowIndex + 1, 0, rowNode.copy(rowNode.content));
28908
- return tableNode.type.create(tableNode.attrs, rows);
28909
- });
28910
- }
28911
- function clearTableRowAt(editor, rowIndex, cellPos) {
28912
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28913
- const rows = collectChildren(tableNode);
28914
- const rowNode = rows[rowIndex];
28915
- if (!rowNode) return null;
28916
- const cells = collectChildren(rowNode).map((cellNode) => createEmptyCellNode(cellNode));
28917
- rows[rowIndex] = rowNode.type.create(rowNode.attrs, cells);
28918
- return tableNode.type.create(tableNode.attrs, rows);
28919
- });
28920
- }
28921
- function duplicateTableColumnAt(editor, columnIndex, cellPos) {
28922
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28923
- const rows = collectChildren(tableNode).map((rowNode) => {
28924
- const cells = collectChildren(rowNode);
28925
- const cellNode = cells[columnIndex];
28926
- if (!cellNode) return rowNode;
28927
- cells.splice(columnIndex + 1, 0, cellNode.copy(cellNode.content));
28928
- return rowNode.type.create(rowNode.attrs, cells);
28929
- });
28930
- return tableNode.type.create(tableNode.attrs, rows);
28931
- });
28932
- }
28933
- function clearTableColumnAt(editor, columnIndex, cellPos) {
28934
- return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
28935
- const rows = collectChildren(tableNode).map((rowNode) => {
28936
- const cells = collectChildren(rowNode);
28937
- const cellNode = cells[columnIndex];
28938
- if (!cellNode) return rowNode;
28939
- cells[columnIndex] = createEmptyCellNode(cellNode);
28940
- return rowNode.type.create(rowNode.attrs, cells);
28941
- });
28942
- return tableNode.type.create(tableNode.attrs, rows);
28943
- });
28944
- }
28945
- function expandTableFromCell(editor, activeCellPos, rows, columns) {
28946
- let cornerCellPos = getTableCornerCellPos(editor, activeCellPos);
28947
- if (cornerCellPos == null) return false;
28948
- for (let index = 0; index < rows; index += 1) {
28949
- const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addRowAfter());
28950
- if (!ok) return false;
28951
- cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28952
- if (cornerCellPos == null) return false;
28953
- }
28954
- for (let index = 0; index < columns; index += 1) {
28955
- const ok = runTableCommandAtCellPos(editor, cornerCellPos, (chain) => chain.addColumnAfter());
28956
- if (!ok) return false;
28957
- cornerCellPos = getTableCornerCellPos(editor, cornerCellPos);
28958
- if (cornerCellPos == null) return false;
28959
- }
28960
- dispatchTableLayoutChange(editor);
28961
- return true;
28962
- }
29017
+ /* @__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" }) }),
29018
+ hasTableContext && /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(import_jsx_runtime85.Fragment, { children: [
29019
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(ToolbarDivider, {}),
29020
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29021
+ ToolbarButton,
29022
+ {
29023
+ onClick: () => editor.chain().focus().addColumnBefore().run(),
29024
+ disabled: !editor.can().addColumnBefore(),
29025
+ title: t("tableMenu.addColumnBefore"),
29026
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowLeft, { className: "w-4 h-4" })
29027
+ }
29028
+ ),
29029
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29030
+ ToolbarButton,
29031
+ {
29032
+ onClick: () => editor.chain().focus().addColumnAfter().run(),
29033
+ disabled: !editor.can().addColumnAfter(),
29034
+ title: t("tableMenu.addColumnAfter"),
29035
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowRight, { className: "w-4 h-4" })
29036
+ }
29037
+ ),
29038
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29039
+ ToolbarButton,
29040
+ {
29041
+ onClick: () => editor.chain().focus().addRowBefore().run(),
29042
+ disabled: !editor.can().addRowBefore(),
29043
+ title: t("tableMenu.addRowBefore"),
29044
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowUp, { className: "w-4 h-4" })
29045
+ }
29046
+ ),
29047
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29048
+ ToolbarButton,
29049
+ {
29050
+ onClick: () => editor.chain().focus().addRowAfter().run(),
29051
+ disabled: !editor.can().addRowAfter(),
29052
+ title: t("tableMenu.addRowAfter"),
29053
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.ArrowDown, { className: "w-4 h-4" })
29054
+ }
29055
+ ),
29056
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
29057
+ ToolbarButton,
29058
+ {
29059
+ onClick: () => {
29060
+ if (canSplitCell) {
29061
+ editor.chain().focus().splitCell().run();
29062
+ return;
29063
+ }
29064
+ mergeTableCellsPreservingColumnWidths(editor);
29065
+ },
29066
+ active: canSplitCell,
29067
+ disabled: !canMergeCells && !canSplitCell,
29068
+ title: canSplitCell ? t("tableMenu.splitCell") : t("tableMenu.mergeCells"),
29069
+ children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(import_lucide_react48.TableCellsMerge, { className: "w-4 h-4" })
29070
+ }
29071
+ )
29072
+ ] })
29073
+ ] });
29074
+ };
28963
29075
 
28964
29076
  // src/components/UEditor/menus.tsx
29077
+ var import_react62 = require("react");
29078
+ var import_react63 = require("@tiptap/react");
29079
+ var import_tables2 = require("@tiptap/pm/tables");
29080
+ var import_react_dom8 = require("react-dom");
29081
+ var import_lucide_react49 = require("lucide-react");
28965
29082
  var import_jsx_runtime86 = require("react/jsx-runtime");
28966
29083
  var FloatingSlashCommandMenu = ({ editor, onClose }) => {
28967
29084
  const t = useSmartTranslations("UEditor");
@@ -29562,10 +29679,22 @@ var CustomBubbleMenu = ({
29562
29679
  setIsVisible(false);
29563
29680
  return;
29564
29681
  }
29565
- const start = view.coordsAtPos(from);
29566
- const end = view.coordsAtPos(to);
29567
- const left = (start.left + end.left) / 2;
29568
- const top = start.top - BUBBLE_MENU_OFFSET;
29682
+ let start;
29683
+ let end;
29684
+ try {
29685
+ start = view.coordsAtPos(from);
29686
+ end = view.coordsAtPos(to);
29687
+ } catch {
29688
+ clearShowTimeout();
29689
+ setIsVisible(false);
29690
+ return;
29691
+ }
29692
+ const viewportPadding = 8;
29693
+ const left = Math.min(
29694
+ window.innerWidth - viewportPadding,
29695
+ Math.max(viewportPadding, (start.left + end.left) / 2)
29696
+ );
29697
+ const top = Math.max(viewportPadding, start.top - BUBBLE_MENU_OFFSET);
29569
29698
  setPosition({ top, left });
29570
29699
  if (keepOpenRef.current) {
29571
29700
  clearShowTimeout();
@@ -29587,11 +29716,17 @@ var CustomBubbleMenu = ({
29587
29716
  editor.on("selectionUpdate", updatePosition);
29588
29717
  editor.on("focus", updatePosition);
29589
29718
  editor.on("blur", handleBlur);
29719
+ editor.on("transaction", updatePosition);
29720
+ editor.on("update", updatePosition);
29721
+ const animationFrameId = requestAnimationFrame(updatePosition);
29590
29722
  return () => {
29723
+ cancelAnimationFrame(animationFrameId);
29591
29724
  clearShowTimeout();
29592
29725
  editor.off("selectionUpdate", updatePosition);
29593
29726
  editor.off("focus", updatePosition);
29594
29727
  editor.off("blur", handleBlur);
29728
+ editor.off("transaction", updatePosition);
29729
+ editor.off("update", updatePosition);
29595
29730
  };
29596
29731
  }, [editor]);
29597
29732
  if (!isVisible) return null;
@@ -29601,7 +29736,7 @@ var CustomBubbleMenu = ({
29601
29736
  {
29602
29737
  ref: menuRef,
29603
29738
  "data-popover": true,
29604
- className: "fixed z-99999 flex rounded-xl border border-border/40 bg-card text-card-foreground shadow-lg backdrop-blur-sm overflow-hidden animate-in fade-in-0 zoom-in-95",
29739
+ className: "fixed z-[99999] flex rounded-xl border border-border/40 bg-card text-card-foreground shadow-lg backdrop-blur-sm overflow-hidden animate-in fade-in-0 zoom-in-95",
29605
29740
  style: {
29606
29741
  top: `${position.top}px`,
29607
29742
  left: `${position.left}px`,
@@ -35513,6 +35648,17 @@ var UEDITOR_PROSEMIRROR_CLASS_NAME = cn(
35513
35648
  "[&_.is-editor-empty]:before:float-left",
35514
35649
  "[&_.is-editor-empty]:before:pointer-events-none",
35515
35650
  "[&_.is-editor-empty]:before:h-0",
35651
+ "[&_.ProseMirror-gapcursor]:pointer-events-none",
35652
+ "[&_.ProseMirror-gapcursor]:absolute",
35653
+ "[&_.ProseMirror-gapcursor]:hidden",
35654
+ "[&_.ProseMirror-gapcursor:after]:content-['']",
35655
+ "[&_.ProseMirror-gapcursor:after]:block",
35656
+ "[&_.ProseMirror-gapcursor:after]:absolute",
35657
+ "[&_.ProseMirror-gapcursor:after]:top-[-2px]",
35658
+ "[&_.ProseMirror-gapcursor:after]:w-8",
35659
+ "[&_.ProseMirror-gapcursor:after]:border-t-2",
35660
+ "[&_.ProseMirror-gapcursor:after]:border-primary",
35661
+ "[&.ProseMirror-focused_.ProseMirror-gapcursor]:block",
35516
35662
  "[&_ul[data-type='taskList']]:list-none",
35517
35663
  "[&_ul[data-type='taskList']]:pl-0",
35518
35664
  "[&_ul[data-type='taskList']_li]:flex",
@@ -35545,6 +35691,7 @@ var UEDITOR_PROSEMIRROR_CLASS_NAME = cn(
35545
35691
  "[&_.tableWrapper::-webkit-scrollbar-thumb]:border-transparent",
35546
35692
  "[&_.tableWrapper::-webkit-scrollbar-thumb]:bg-border/70",
35547
35693
  "[&_.tableWrapper::-webkit-scrollbar-thumb:hover]:bg-muted-foreground/45",
35694
+ "[&_table]:w-auto",
35548
35695
  "[&_table]:table-fixed",
35549
35696
  "[&_table]:overflow-hidden",
35550
35697
  "[&_table]:select-text",
@@ -36800,7 +36947,7 @@ var MenuBar = ({
36800
36947
  "div",
36801
36948
  {
36802
36949
  "data-testid": "preview-content",
36803
- className: "prose prose-sm sm:prose dark:prose-invert max-w-none p-2",
36950
+ className: UEDITOR_PROSEMIRROR_CLASS_NAME,
36804
36951
  dangerouslySetInnerHTML: { __html: editor.getHTML() }
36805
36952
  }
36806
36953
  )