@underverse-ui/underverse 1.0.192 → 1.0.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -910,6 +910,19 @@ var en_default = {
910
910
  borderStyle: "Border Style",
911
911
  borderWidth: "Border Width",
912
912
  borderColor: "Border Color",
913
+ borderPosition: "Border placement",
914
+ borderMode: "Border mode",
915
+ borderDraw: "Draw borders",
916
+ borderErase: "Hide borders",
917
+ borderAll: "All borders",
918
+ borderOuter: "Outer borders",
919
+ borderInner: "Inner borders",
920
+ borderHorizontal: "Inner horizontal borders",
921
+ borderVertical: "Inner vertical borders",
922
+ borderTop: "Top border",
923
+ borderRight: "Right border",
924
+ borderBottom: "Bottom border",
925
+ borderLeft: "Left border",
913
926
  clearBorder: "Clear Border",
914
927
  formula: "Formula",
915
928
  formulaBar: "Formula bar",
@@ -1343,6 +1356,19 @@ var vi_default = {
1343
1356
  borderStyle: "Ki\u1EC3u vi\u1EC1n",
1344
1357
  borderWidth: "\u0110\u1ED9 d\xE0y vi\u1EC1n",
1345
1358
  borderColor: "M\xE0u vi\u1EC1n",
1359
+ borderPosition: "V\u1ECB tr\xED vi\u1EC1n",
1360
+ borderMode: "Ch\u1EBF \u0111\u1ED9 vi\u1EC1n",
1361
+ borderDraw: "V\u1EBD vi\u1EC1n",
1362
+ borderErase: "\u1EA8n c\u1EA1nh",
1363
+ borderAll: "T\u1EA5t c\u1EA3 vi\u1EC1n",
1364
+ borderOuter: "Vi\u1EC1n ngo\xE0i",
1365
+ borderInner: "Vi\u1EC1n trong",
1366
+ borderHorizontal: "Vi\u1EC1n ngang b\xEAn trong",
1367
+ borderVertical: "Vi\u1EC1n d\u1ECDc b\xEAn trong",
1368
+ borderTop: "Vi\u1EC1n tr\xEAn",
1369
+ borderRight: "Vi\u1EC1n ph\u1EA3i",
1370
+ borderBottom: "Vi\u1EC1n d\u01B0\u1EDBi",
1371
+ borderLeft: "Vi\u1EC1n tr\xE1i",
1346
1372
  clearBorder: "X\xF3a vi\u1EC1n",
1347
1373
  formula: "C\xF4ng th\u1EE9c",
1348
1374
  formulaBar: "Thanh c\xF4ng th\u1EE9c",
@@ -1776,6 +1802,19 @@ var ko_default = {
1776
1802
  borderStyle: "\uD14C\uB450\uB9AC \uC2A4\uD0C0\uC77C",
1777
1803
  borderWidth: "\uD14C\uB450\uB9AC \uB450\uAED8",
1778
1804
  borderColor: "\uD14C\uB450\uB9AC \uC0C9\uC0C1",
1805
+ borderPosition: "\uD14C\uB450\uB9AC \uC704\uCE58",
1806
+ borderMode: "\uD14C\uB450\uB9AC \uBAA8\uB4DC",
1807
+ borderDraw: "\uD14C\uB450\uB9AC \uADF8\uB9AC\uAE30",
1808
+ borderErase: "\uD14C\uB450\uB9AC \uC228\uAE30\uAE30",
1809
+ borderAll: "\uBAA8\uB4E0 \uD14C\uB450\uB9AC",
1810
+ borderOuter: "\uBC14\uAE65\uCABD \uD14C\uB450\uB9AC",
1811
+ borderInner: "\uC548\uCABD \uD14C\uB450\uB9AC",
1812
+ borderHorizontal: "\uC548\uCABD \uAC00\uB85C \uD14C\uB450\uB9AC",
1813
+ borderVertical: "\uC548\uCABD \uC138\uB85C \uD14C\uB450\uB9AC",
1814
+ borderTop: "\uC704\uCABD \uD14C\uB450\uB9AC",
1815
+ borderRight: "\uC624\uB978\uCABD \uD14C\uB450\uB9AC",
1816
+ borderBottom: "\uC544\uB798\uCABD \uD14C\uB450\uB9AC",
1817
+ borderLeft: "\uC67C\uCABD \uD14C\uB450\uB9AC",
1779
1818
  clearBorder: "\uD14C\uB450\uB9AC \uC9C0\uC6B0\uAE30",
1780
1819
  formula: "\uC218\uC2DD",
1781
1820
  formulaBar: "\uC218\uC2DD \uC785\uB825\uC904",
@@ -2209,6 +2248,19 @@ var ja_default = {
2209
2248
  borderStyle: "\u67A0\u7DDA\u30B9\u30BF\u30A4\u30EB",
2210
2249
  borderWidth: "\u67A0\u7DDA\u306E\u592A\u3055",
2211
2250
  borderColor: "\u67A0\u7DDA\u306E\u8272",
2251
+ borderPosition: "\u67A0\u7DDA\u306E\u4F4D\u7F6E",
2252
+ borderMode: "\u67A0\u7DDA\u30E2\u30FC\u30C9",
2253
+ borderDraw: "\u67A0\u7DDA\u3092\u5F15\u304F",
2254
+ borderErase: "\u67A0\u7DDA\u3092\u975E\u8868\u793A",
2255
+ borderAll: "\u3059\u3079\u3066\u306E\u67A0\u7DDA",
2256
+ borderOuter: "\u5916\u67A0",
2257
+ borderInner: "\u5185\u5074\u306E\u67A0\u7DDA",
2258
+ borderHorizontal: "\u5185\u5074\u306E\u6A2A\u7F6B\u7DDA",
2259
+ borderVertical: "\u5185\u5074\u306E\u7E26\u7F6B\u7DDA",
2260
+ borderTop: "\u4E0A\u7F6B\u7DDA",
2261
+ borderRight: "\u53F3\u7F6B\u7DDA",
2262
+ borderBottom: "\u4E0B\u7F6B\u7DDA",
2263
+ borderLeft: "\u5DE6\u7F6B\u7DDA",
2212
2264
  clearBorder: "\u67A0\u7DDA\u3092\u30AF\u30EA\u30A2",
2213
2265
  formula: "\u6570\u5F0F",
2214
2266
  formulaBar: "\u6570\u5F0F\u30D0\u30FC",
@@ -31816,7 +31868,7 @@ var CustomTableCell = TableCell2.extend({
31816
31868
  },
31817
31869
  textDirection: {
31818
31870
  default: null,
31819
- parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || element.style.writingMode === "vertical-rl" ? "vertical" : null,
31871
+ parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || ["sideways-lr", "vertical-lr", "vertical-rl"].includes(element.style.writingMode) ? "vertical" : null,
31820
31872
  renderHTML: (attributes) => attributes.textDirection === "vertical" ? { "data-text-direction": "vertical" } : {}
31821
31873
  }
31822
31874
  };
@@ -31835,7 +31887,7 @@ var CustomTableCell = TableCell2.extend({
31835
31887
  if (borderStyle) mergedStyle += `; border-style: ${borderStyle}`;
31836
31888
  if (borderWidth) mergedStyle += `; border-width: ${borderWidth}`;
31837
31889
  if (verticalAlign) mergedStyle += `; vertical-align: ${verticalAlign}`;
31838
- if (textDirection === "vertical") mergedStyle += "; writing-mode: vertical-rl; text-orientation: mixed";
31890
+ if (textDirection === "vertical") mergedStyle += "; writing-mode: sideways-lr; text-orientation: mixed";
31839
31891
  mergedStyle = mergedStyle.replace(/^;/, "").trim();
31840
31892
  return [
31841
31893
  "td",
@@ -31942,7 +31994,7 @@ var CustomTableHeader = TableHeader2.extend({
31942
31994
  },
31943
31995
  textDirection: {
31944
31996
  default: null,
31945
- parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || element.style.writingMode === "vertical-rl" ? "vertical" : null,
31997
+ parseHTML: (element) => element.getAttribute("data-text-direction") === "vertical" || ["sideways-lr", "vertical-lr", "vertical-rl"].includes(element.style.writingMode) ? "vertical" : null,
31946
31998
  renderHTML: (attributes) => attributes.textDirection === "vertical" ? { "data-text-direction": "vertical" } : {}
31947
31999
  }
31948
32000
  };
@@ -31961,7 +32013,7 @@ var CustomTableHeader = TableHeader2.extend({
31961
32013
  if (borderStyle) mergedStyle += `; border-style: ${borderStyle}`;
31962
32014
  if (borderWidth) mergedStyle += `; border-width: ${borderWidth}`;
31963
32015
  if (verticalAlign) mergedStyle += `; vertical-align: ${verticalAlign}`;
31964
- if (textDirection === "vertical") mergedStyle += "; writing-mode: vertical-rl; text-orientation: mixed";
32016
+ if (textDirection === "vertical") mergedStyle += "; writing-mode: sideways-lr; text-orientation: mixed";
31965
32017
  mergedStyle = mergedStyle.replace(/^;/, "").trim();
31966
32018
  return [
31967
32019
  "th",
@@ -34214,6 +34266,7 @@ import {
34214
34266
  Underline as UnderlineIcon2,
34215
34267
  Strikethrough as StrikethroughIcon2,
34216
34268
  Edit2,
34269
+ Eraser,
34217
34270
  Unlink,
34218
34271
  ExternalLink as ExternalLink3,
34219
34272
  Sigma as Sigma2,
@@ -34224,9 +34277,137 @@ import {
34224
34277
  ArrowRight as ArrowRight2
34225
34278
  } from "lucide-react";
34226
34279
 
34280
+ // src/components/UEditor/table-border-commands.ts
34281
+ import { selectedRect as selectedRect2 } from "@tiptap/pm/tables";
34282
+ var SIDES = ["top", "right", "bottom", "left"];
34283
+ var OPPOSITE_SIDE = {
34284
+ top: "bottom",
34285
+ right: "left",
34286
+ bottom: "top",
34287
+ left: "right"
34288
+ };
34289
+ function splitCssValues(value) {
34290
+ const values = [];
34291
+ let token = "";
34292
+ let parentheses = 0;
34293
+ for (const character of value.trim()) {
34294
+ if (/\s/.test(character) && parentheses === 0) {
34295
+ if (token) values.push(token);
34296
+ token = "";
34297
+ continue;
34298
+ }
34299
+ if (character === "(") parentheses += 1;
34300
+ if (character === ")") parentheses = Math.max(0, parentheses - 1);
34301
+ token += character;
34302
+ }
34303
+ if (token) values.push(token);
34304
+ return values;
34305
+ }
34306
+ function expandCssQuad(value, fallback) {
34307
+ const values = typeof value === "string" ? splitCssValues(value) : [];
34308
+ const [top = fallback, right = top, bottom = top, left = right] = values;
34309
+ return { top, right, bottom, left };
34310
+ }
34311
+ function serializeCssQuad({ top, right, bottom, left }) {
34312
+ if (top === right && top === bottom && top === left) return top;
34313
+ if (top === bottom && right === left) return `${top} ${right}`;
34314
+ if (right === left) return `${top} ${right} ${bottom}`;
34315
+ return `${top} ${right} ${bottom} ${left}`;
34316
+ }
34317
+ function getAppliedSides(position, cell, selection) {
34318
+ const outer = {
34319
+ top: cell.top === selection.top,
34320
+ right: cell.right === selection.right,
34321
+ bottom: cell.bottom === selection.bottom,
34322
+ left: cell.left === selection.left
34323
+ };
34324
+ const inner = {
34325
+ top: cell.top > selection.top,
34326
+ right: cell.right < selection.right,
34327
+ bottom: cell.bottom < selection.bottom,
34328
+ left: cell.left > selection.left
34329
+ };
34330
+ switch (position) {
34331
+ case "all":
34332
+ return { top: true, right: true, bottom: true, left: true };
34333
+ case "outer":
34334
+ return outer;
34335
+ case "inner":
34336
+ return inner;
34337
+ case "horizontal":
34338
+ return { top: inner.top, right: false, bottom: inner.bottom, left: false };
34339
+ case "vertical":
34340
+ return { top: false, right: inner.right, bottom: false, left: inner.left };
34341
+ default:
34342
+ return {
34343
+ top: position === "top" && outer.top,
34344
+ right: position === "right" && outer.right,
34345
+ bottom: position === "bottom" && outer.bottom,
34346
+ left: position === "left" && outer.left
34347
+ };
34348
+ }
34349
+ }
34350
+ function applyTableCellBorders(editor, position, format, options = {}) {
34351
+ const { state, view } = editor;
34352
+ const selection = selectedRect2(state);
34353
+ const transaction = state.tr;
34354
+ const cellPositions = new Set(selection.map.cellsInRect(selection));
34355
+ const sidesByCell = /* @__PURE__ */ new Map();
34356
+ const addSide = (cellPos, side) => {
34357
+ const sides = sidesByCell.get(cellPos) ?? /* @__PURE__ */ new Set();
34358
+ sides.add(side);
34359
+ sidesByCell.set(cellPos, sides);
34360
+ };
34361
+ const addAdjacentSides = (cell, side) => {
34362
+ const adjacentPositions = /* @__PURE__ */ new Set();
34363
+ if (side === "top" && cell.top > 0) {
34364
+ for (let col = cell.left; col < cell.right; col += 1) adjacentPositions.add(selection.map.map[(cell.top - 1) * selection.map.width + col]);
34365
+ } else if (side === "bottom" && cell.bottom < selection.map.height) {
34366
+ for (let col = cell.left; col < cell.right; col += 1) adjacentPositions.add(selection.map.map[cell.bottom * selection.map.width + col]);
34367
+ } else if (side === "left" && cell.left > 0) {
34368
+ for (let row = cell.top; row < cell.bottom; row += 1) adjacentPositions.add(selection.map.map[row * selection.map.width + cell.left - 1]);
34369
+ } else if (side === "right" && cell.right < selection.map.width) {
34370
+ for (let row = cell.top; row < cell.bottom; row += 1) adjacentPositions.add(selection.map.map[row * selection.map.width + cell.right]);
34371
+ }
34372
+ for (const adjacentPos of adjacentPositions) addSide(adjacentPos, OPPOSITE_SIDE[side]);
34373
+ };
34374
+ for (const relativePos of cellPositions) {
34375
+ const cell = selection.map.findCell(relativePos);
34376
+ const appliedSides = getAppliedSides(position, cell, selection);
34377
+ for (const side of SIDES) {
34378
+ if (!appliedSides[side]) continue;
34379
+ addSide(relativePos, side);
34380
+ addAdjacentSides(cell, side);
34381
+ }
34382
+ }
34383
+ for (const [relativePos, appliedSides] of sidesByCell) {
34384
+ const absolutePos = selection.tableStart + relativePos;
34385
+ const node = state.doc.nodeAt(absolutePos);
34386
+ if (!node) continue;
34387
+ const styles = expandCssQuad(node.attrs.borderStyle, "solid");
34388
+ const widths = expandCssQuad(node.attrs.borderWidth, "1px");
34389
+ const colors = expandCssQuad(node.attrs.borderColor, "#000000");
34390
+ for (const side of SIDES) {
34391
+ if (!appliedSides.has(side)) continue;
34392
+ styles[side] = format.style;
34393
+ widths[side] = format.width;
34394
+ colors[side] = format.color || "currentColor";
34395
+ }
34396
+ transaction.setNodeMarkup(absolutePos, void 0, {
34397
+ ...node.attrs,
34398
+ borderStyle: serializeCssQuad(styles),
34399
+ borderWidth: serializeCssQuad(widths),
34400
+ borderColor: serializeCssQuad(colors)
34401
+ });
34402
+ }
34403
+ if (transaction.docChanged) view.dispatch(transaction);
34404
+ if (options.focus ?? true) view.focus();
34405
+ return transaction.docChanged;
34406
+ }
34407
+
34227
34408
  // src/components/UEditor/table-formula-commands.ts
34228
34409
  import { TextSelection as TextSelection4 } from "@tiptap/pm/state";
34229
- import { selectedRect as selectedRect2, setCellAttr as setCellAttr2, TableMap as TableMap3 } from "@tiptap/pm/tables";
34410
+ import { selectedRect as selectedRect3, setCellAttr as setCellAttr2, TableMap as TableMap3 } from "@tiptap/pm/tables";
34230
34411
 
34231
34412
  // src/components/UEditor/table-formula.ts
34232
34413
  var CELL_ADDRESS_RE = /^([A-Z]+)([1-9]\d*)$/i;
@@ -35115,7 +35296,7 @@ function recalculateTableNode(tableNode, options) {
35115
35296
  return tableNode.type.create(tableNode.attrs, rows);
35116
35297
  }
35117
35298
  function recalculateSelectedTable(editor) {
35118
- const rect = selectedRect2(editor.state);
35299
+ const rect = selectedRect3(editor.state);
35119
35300
  const tableNode = rect.table;
35120
35301
  const nextTable = recalculateTableNode(tableNode);
35121
35302
  if (!nextTable) return false;
@@ -35259,6 +35440,32 @@ function BorderStylePreviewIcon({ style }) {
35259
35440
  }
35260
35441
  );
35261
35442
  }
35443
+ function BorderPositionPreviewIcon({ position }) {
35444
+ const showTop = position === "all" || position === "outer" || position === "top";
35445
+ const showRight = position === "all" || position === "outer" || position === "right";
35446
+ const showBottom = position === "all" || position === "outer" || position === "bottom";
35447
+ const showLeft = position === "all" || position === "outer" || position === "left";
35448
+ const showHorizontal = position === "all" || position === "inner" || position === "horizontal";
35449
+ const showVertical = position === "all" || position === "inner" || position === "vertical";
35450
+ return /* @__PURE__ */ jsxs76("svg", { "aria-hidden": "true", viewBox: "0 0 20 20", className: "h-5 w-5 fill-none stroke-current", children: [
35451
+ /* @__PURE__ */ jsx93(
35452
+ "path",
35453
+ {
35454
+ d: "M2 2H18V18H2Z M2 10H18 M10 2V18",
35455
+ className: "text-foreground opacity-70",
35456
+ stroke: "currentColor",
35457
+ strokeDasharray: "2 1.5",
35458
+ strokeWidth: "1.25"
35459
+ }
35460
+ ),
35461
+ showTop && /* @__PURE__ */ jsx93("path", { d: "M2 2H18", strokeWidth: "2" }),
35462
+ showRight && /* @__PURE__ */ jsx93("path", { d: "M18 2V18", strokeWidth: "2" }),
35463
+ showBottom && /* @__PURE__ */ jsx93("path", { d: "M2 18H18", strokeWidth: "2" }),
35464
+ showLeft && /* @__PURE__ */ jsx93("path", { d: "M2 2V18", strokeWidth: "2" }),
35465
+ showHorizontal && /* @__PURE__ */ jsx93("path", { d: "M2 10H18", strokeWidth: "2" }),
35466
+ showVertical && /* @__PURE__ */ jsx93("path", { d: "M10 2V18", strokeWidth: "2" })
35467
+ ] });
35468
+ }
35262
35469
  var BubbleMenuContent = ({
35263
35470
  editor,
35264
35471
  onKeepOpenChange,
@@ -35266,7 +35473,8 @@ var BubbleMenuContent = ({
35266
35473
  onRequestClose,
35267
35474
  fontSizes,
35268
35475
  lineHeights,
35269
- initialShowLinkInput = false
35476
+ initialShowLinkInput = false,
35477
+ cellBorderOpenRequest = 0
35270
35478
  }) => {
35271
35479
  const t = useSmartTranslations("UEditor");
35272
35480
  useEditorState2({
@@ -35279,6 +35487,11 @@ var BubbleMenuContent = ({
35279
35487
  useEffect37(() => {
35280
35488
  setShowLinkInput(initialShowLinkInput);
35281
35489
  }, [initialShowLinkInput]);
35490
+ useEffect37(() => {
35491
+ if (!cellBorderOpenRequest) return;
35492
+ setActiveColorPalette("cell-border");
35493
+ onKeepOpenChange?.(true);
35494
+ }, [cellBorderOpenRequest, onKeepOpenChange]);
35282
35495
  const [showTypographyPanel, setShowTypographyPanel] = useState50(false);
35283
35496
  const [showFormulaPanel, setShowFormulaPanel] = useState50(false);
35284
35497
  const [formulaDraft, setFormulaDraft] = useState50("");
@@ -35296,6 +35509,14 @@ var BubbleMenuContent = ({
35296
35509
  const currentCellNumberFormat = normalizeStyleValue(editor.getAttributes("tableCell").numberFormat || editor.getAttributes("tableHeader").numberFormat) || "text";
35297
35510
  const currentCellBorderStyle = editor.getAttributes("tableCell").borderStyle || editor.getAttributes("tableHeader").borderStyle || "solid";
35298
35511
  const currentCellBorderWidth = editor.getAttributes("tableCell").borderWidth || editor.getAttributes("tableHeader").borderWidth || "1px";
35512
+ const currentCellBorderColor = normalizeStyleValue(editor.getAttributes("tableCell").borderColor || editor.getAttributes("tableHeader").borderColor) || "#000000";
35513
+ const [borderStyleDraft, setBorderStyleDraft] = useState50(
35514
+ ["solid", "dashed", "dotted", "double"].includes(currentCellBorderStyle) ? currentCellBorderStyle : "solid"
35515
+ );
35516
+ const [borderWidthDraft, setBorderWidthDraft] = useState50(currentCellBorderWidth);
35517
+ const [borderColorDraft, setBorderColorDraft] = useState50(currentCellBorderColor);
35518
+ const [borderEditMode, setBorderEditMode] = useState50("draw");
35519
+ const [activeBorderPosition, setActiveBorderPosition] = useState50("all");
35299
35520
  const currentCellVerticalAlign = normalizeStyleValue(editor.getAttributes("tableCell").verticalAlign || editor.getAttributes("tableHeader").verticalAlign) || "";
35300
35521
  const currentCellTextDirection = normalizeStyleValue(editor.getAttributes("tableCell").textDirection || editor.getAttributes("tableHeader").textDirection) || "horizontal";
35301
35522
  const isInTable2 = isSelectionInTable(editor.state);
@@ -35352,21 +35573,60 @@ var BubbleMenuContent = ({
35352
35573
  onLinkInputOpenChange?.(false);
35353
35574
  onRequestClose?.();
35354
35575
  }, [onKeepOpenChange, onLinkInputOpenChange, onRequestClose]);
35355
- const applyTableCellAttributeAndClose = useCallback23((name, value) => {
35356
- applyTableCellAttribute2(editor, name, value, { focus: false });
35357
- closeTransientPanels();
35358
- }, [closeTransientPanels, editor]);
35359
- const clearTableCellBorderAndClose = useCallback23(() => {
35360
- applyTableCellAttribute2(editor, "borderColor", null, { focus: false });
35361
- applyTableCellAttribute2(editor, "borderStyle", null, { focus: false });
35362
- applyTableCellAttribute2(editor, "borderWidth", null, { focus: false });
35363
- closeTransientPanels();
35364
- }, [closeTransientPanels, editor]);
35365
- const applyTableCellBorderColorAndClose = useCallback23((color) => {
35366
- const value = color || null;
35367
- applyTableCellAttribute2(editor, "borderColor", value, { focus: false });
35368
- closeTransientPanels();
35369
- }, [closeTransientPanels, editor]);
35576
+ const selectTableCellBorderColor = useCallback23((color) => {
35577
+ const value = color || "currentColor";
35578
+ setBorderColorDraft(value);
35579
+ setBorderEditMode("draw");
35580
+ setActiveBorderPosition("all");
35581
+ applyTableCellBorders(editor, "all", {
35582
+ color: value,
35583
+ style: borderStyleDraft,
35584
+ width: borderWidthDraft
35585
+ }, { focus: false });
35586
+ setActiveColorPalette("cell-border");
35587
+ onKeepOpenChange?.(true);
35588
+ }, [borderStyleDraft, borderWidthDraft, editor, onKeepOpenChange]);
35589
+ const applyTableCellBorderPosition = useCallback23((position) => {
35590
+ setActiveBorderPosition(position);
35591
+ applyTableCellBorders(editor, position, {
35592
+ color: borderColorDraft,
35593
+ style: borderEditMode === "erase" ? "none" : borderStyleDraft,
35594
+ width: borderWidthDraft
35595
+ }, { focus: false });
35596
+ onKeepOpenChange?.(true);
35597
+ }, [borderColorDraft, borderEditMode, borderStyleDraft, borderWidthDraft, editor, onKeepOpenChange]);
35598
+ const applyTableCellBorderStyle = useCallback23((style) => {
35599
+ setBorderStyleDraft(style);
35600
+ setBorderEditMode("draw");
35601
+ setActiveBorderPosition("all");
35602
+ applyTableCellBorders(editor, "all", {
35603
+ color: borderColorDraft,
35604
+ style,
35605
+ width: borderWidthDraft
35606
+ }, { focus: false });
35607
+ onKeepOpenChange?.(true);
35608
+ }, [borderColorDraft, borderWidthDraft, editor, onKeepOpenChange]);
35609
+ const applyTableCellBorderWidth = useCallback23((width) => {
35610
+ setBorderWidthDraft(width);
35611
+ setBorderEditMode("draw");
35612
+ setActiveBorderPosition("all");
35613
+ applyTableCellBorders(editor, "all", {
35614
+ color: borderColorDraft,
35615
+ style: borderStyleDraft,
35616
+ width
35617
+ }, { focus: false });
35618
+ onKeepOpenChange?.(true);
35619
+ }, [borderColorDraft, borderStyleDraft, editor, onKeepOpenChange]);
35620
+ const clearTableCellBorders = useCallback23(() => {
35621
+ setActiveBorderPosition("all");
35622
+ setBorderEditMode("erase");
35623
+ applyTableCellBorders(editor, "all", {
35624
+ color: borderColorDraft,
35625
+ style: "none",
35626
+ width: borderWidthDraft
35627
+ }, { focus: false });
35628
+ onKeepOpenChange?.(true);
35629
+ }, [borderColorDraft, borderWidthDraft, editor, onKeepOpenChange]);
35370
35630
  const closeColorPalette = useCallback23(() => {
35371
35631
  setActiveColorPalette(null);
35372
35632
  onKeepOpenChange?.(false);
@@ -35420,27 +35680,104 @@ var BubbleMenuContent = ({
35420
35680
  const isTextPalette = activeColorPalette === "text";
35421
35681
  const isHighlightPalette = activeColorPalette === "highlight";
35422
35682
  if (activeColorPalette === "cell-border") {
35423
- const currentBorderColor = editor.getAttributes("tableCell").borderColor || editor.getAttributes("tableHeader").borderColor || "currentColor";
35424
- return /* @__PURE__ */ jsxs76("div", { className: "flex flex-col gap-2 p-2 w-56 text-sm", "data-ueditor-keep-open": true, children: [
35683
+ return /* @__PURE__ */ jsxs76("div", { className: "flex w-72 flex-col gap-2 p-2 text-sm", "data-ueditor-keep-open": true, children: [
35425
35684
  /* @__PURE__ */ jsx93("div", { className: "font-semibold text-xs text-muted-foreground uppercase tracking-wider mb-1", children: t("tableMenu.cellBorder") || "Cell Borders" }),
35685
+ /* @__PURE__ */ jsxs76("div", { className: "flex gap-2", children: [
35686
+ /* @__PURE__ */ jsxs76("div", { className: "min-w-0 flex-1", children: [
35687
+ /* @__PURE__ */ jsx93("label", { className: "mb-1 block text-xs text-muted-foreground", children: t("tableMenu.borderPosition") || "Border placement" }),
35688
+ /* @__PURE__ */ jsxs76("div", { className: "grid grid-cols-5 gap-1", role: "group", "aria-label": t("tableMenu.borderPosition") || "Border placement", children: [
35689
+ [
35690
+ ["all", "borderAll"],
35691
+ ["outer", "borderOuter"],
35692
+ ["inner", "borderInner"],
35693
+ ["horizontal", "borderHorizontal"],
35694
+ ["vertical", "borderVertical"],
35695
+ ["top", "borderTop"],
35696
+ ["right", "borderRight"],
35697
+ ["bottom", "borderBottom"],
35698
+ ["left", "borderLeft"]
35699
+ ].map(([position, labelKey]) => {
35700
+ const label = t(`tableMenu.${labelKey}`) || position;
35701
+ return /* @__PURE__ */ jsx93(
35702
+ "button",
35703
+ {
35704
+ type: "button",
35705
+ "aria-label": label,
35706
+ title: label,
35707
+ onMouseDown: (event) => event.preventDefault(),
35708
+ onClick: () => applyTableCellBorderPosition(position),
35709
+ className: cn(
35710
+ "inline-flex h-8 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted hover:text-primary",
35711
+ activeBorderPosition === position ? "bg-primary/10 text-primary" : "bg-muted/40"
35712
+ ),
35713
+ children: /* @__PURE__ */ jsx93(BorderPositionPreviewIcon, { position })
35714
+ },
35715
+ position
35716
+ );
35717
+ }),
35718
+ /* @__PURE__ */ jsx93(
35719
+ "button",
35720
+ {
35721
+ type: "button",
35722
+ "aria-label": t("tableMenu.clearBorder") || "Clear borders",
35723
+ title: t("tableMenu.clearBorder") || "Clear borders",
35724
+ onMouseDown: (event) => event.preventDefault(),
35725
+ onClick: clearTableCellBorders,
35726
+ className: "inline-flex h-8 items-center justify-center rounded-md bg-muted/40 text-destructive transition-colors hover:bg-destructive/10",
35727
+ children: /* @__PURE__ */ jsx93(BorderStylePreviewIcon, { style: "none" })
35728
+ }
35729
+ )
35730
+ ] })
35731
+ ] }),
35732
+ /* @__PURE__ */ jsxs76("div", { className: "flex flex-col gap-1 border-l border-border pl-2 pt-5", role: "group", "aria-label": t("tableMenu.borderMode") || "Border mode", children: [
35733
+ /* @__PURE__ */ jsx93(
35734
+ "button",
35735
+ {
35736
+ type: "button",
35737
+ "aria-label": t("tableMenu.borderDraw") || "Draw borders",
35738
+ title: t("tableMenu.borderDraw") || "Draw borders",
35739
+ onMouseDown: (event) => event.preventDefault(),
35740
+ onClick: () => setBorderEditMode("draw"),
35741
+ className: cn(
35742
+ "inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted",
35743
+ borderEditMode === "draw" ? "bg-primary/10 text-primary" : "text-muted-foreground"
35744
+ ),
35745
+ children: /* @__PURE__ */ jsx93(Edit2, { className: "h-4 w-4" })
35746
+ }
35747
+ ),
35748
+ /* @__PURE__ */ jsx93(
35749
+ "button",
35750
+ {
35751
+ type: "button",
35752
+ "aria-label": t("tableMenu.borderErase") || "Hide borders",
35753
+ title: t("tableMenu.borderErase") || "Hide borders",
35754
+ onMouseDown: (event) => event.preventDefault(),
35755
+ onClick: () => setBorderEditMode("erase"),
35756
+ className: cn(
35757
+ "inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted",
35758
+ borderEditMode === "erase" ? "bg-destructive/10 text-destructive" : "text-muted-foreground"
35759
+ ),
35760
+ children: /* @__PURE__ */ jsx93(Eraser, { className: "h-4 w-4" })
35761
+ }
35762
+ )
35763
+ ] })
35764
+ ] }),
35426
35765
  /* @__PURE__ */ jsxs76("div", { className: "flex flex-col gap-1", children: [
35427
35766
  /* @__PURE__ */ jsx93("label", { className: "text-xs text-muted-foreground", children: t("tableMenu.borderStyle") || "Border Style" }),
35428
- /* @__PURE__ */ jsx93("div", { className: "grid grid-cols-3 gap-1", role: "group", "aria-label": t("tableMenu.borderStyle") || "Border Style", children: [
35767
+ /* @__PURE__ */ jsx93("div", { className: "grid grid-cols-4 gap-1.5", role: "group", "aria-label": t("tableMenu.borderStyle") || "Border Style", children: [
35429
35768
  ["solid", "Solid"],
35430
35769
  ["dashed", "Dashed"],
35431
35770
  ["dotted", "Dotted"],
35432
- ["double", "Double"],
35433
- ["none", "None"]
35771
+ ["double", "Double"]
35434
35772
  ].map(([style, label]) => /* @__PURE__ */ jsxs76(
35435
35773
  "button",
35436
35774
  {
35437
35775
  type: "button",
35438
- "data-ueditor-close-on-select": true,
35439
35776
  onMouseDown: (event) => event.preventDefault(),
35440
- onClick: () => applyTableCellAttributeAndClose("borderStyle", style),
35777
+ onClick: () => applyTableCellBorderStyle(style),
35441
35778
  className: cn(
35442
- "inline-flex h-8 items-center justify-center gap-1.5 rounded-md px-2 text-xs font-medium transition-colors hover:bg-muted",
35443
- currentCellBorderStyle === style ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35779
+ "inline-flex h-8 min-w-0 items-center justify-center gap-1.5 rounded-md px-2.5 text-xs font-medium transition-colors hover:bg-muted",
35780
+ borderStyleDraft === style ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35444
35781
  ),
35445
35782
  children: [
35446
35783
  /* @__PURE__ */ jsx93(BorderStylePreviewIcon, { style }),
@@ -35456,12 +35793,11 @@ var BubbleMenuContent = ({
35456
35793
  "button",
35457
35794
  {
35458
35795
  type: "button",
35459
- "data-ueditor-close-on-select": true,
35460
35796
  onMouseDown: (event) => event.preventDefault(),
35461
- onClick: () => applyTableCellAttributeAndClose("borderWidth", width),
35797
+ onClick: () => applyTableCellBorderWidth(width),
35462
35798
  className: cn(
35463
35799
  "h-8 rounded-md px-2 text-xs font-medium transition-colors hover:bg-muted",
35464
- currentCellBorderWidth === width ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35800
+ borderWidthDraft === width ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
35465
35801
  ),
35466
35802
  children: width
35467
35803
  },
@@ -35481,33 +35817,22 @@ var BubbleMenuContent = ({
35481
35817
  {
35482
35818
  className: "w-4 h-4 rounded-full border border-border",
35483
35819
  style: {
35484
- backgroundColor: currentBorderColor
35820
+ backgroundColor: borderColorDraft
35485
35821
  }
35486
35822
  }
35487
35823
  )
35488
35824
  ]
35489
35825
  }
35490
- ),
35491
- /* @__PURE__ */ jsx93("div", { className: "flex items-center justify-between gap-2 mt-2 pt-2 border-t border-border", children: /* @__PURE__ */ jsx93(
35492
- "button",
35493
- {
35494
- type: "button",
35495
- "data-ueditor-close-on-select": true,
35496
- onClick: clearTableCellBorderAndClose,
35497
- className: "text-xs text-destructive hover:underline",
35498
- children: t("tableMenu.clearBorder") || "Clear Border"
35499
- }
35500
- ) })
35826
+ )
35501
35827
  ] });
35502
35828
  }
35503
35829
  if (activeColorPalette === "cell-border-color") {
35504
- const currentBorderColor = normalizeStyleValue(editor.getAttributes("tableCell").borderColor || editor.getAttributes("tableHeader").borderColor) || "";
35505
35830
  return /* @__PURE__ */ jsx93("div", { className: "w-56", "data-ueditor-keep-open": true, children: /* @__PURE__ */ jsx93(
35506
35831
  EditorColorPalette,
35507
35832
  {
35508
35833
  colors: borderColors,
35509
- currentColor: currentBorderColor,
35510
- onSelect: applyTableCellBorderColorAndClose,
35834
+ currentColor: borderColorDraft,
35835
+ onSelect: selectTableCellBorderColor,
35511
35836
  label: t("tableMenu.borderColor") || "Border Color"
35512
35837
  }
35513
35838
  ) });
@@ -36025,6 +36350,7 @@ var CustomBubbleMenu = ({
36025
36350
  const BUBBLE_MENU_ESTIMATED_HEIGHT = 44;
36026
36351
  const [isVisible, setIsVisible] = useState50(false);
36027
36352
  const [linkInputOpen, setLinkInputOpen] = useState50(false);
36353
+ const [cellBorderOpenRequest, setCellBorderOpenRequest] = useState50(0);
36028
36354
  const [position, setPosition2] = useState50({
36029
36355
  top: 0,
36030
36356
  left: 0,
@@ -36041,8 +36367,8 @@ var CustomBubbleMenu = ({
36041
36367
  if (!next) setLinkInputOpen(false);
36042
36368
  if (next) setIsVisible(true);
36043
36369
  }, []);
36044
- const closeBubbleMenu = useCallback23(() => {
36045
- suppressShowUntilRef.current = Date.now() + 1e3;
36370
+ const closeBubbleMenu = useCallback23((suppressShow = true) => {
36371
+ suppressShowUntilRef.current = suppressShow ? Date.now() + 1e3 : 0;
36046
36372
  keepOpenRef.current = false;
36047
36373
  setKeepOpenState(false);
36048
36374
  setLinkInputOpen(false);
@@ -36134,6 +36460,41 @@ var CustomBubbleMenu = ({
36134
36460
  editor.off("update", updatePosition);
36135
36461
  };
36136
36462
  }, [editor]);
36463
+ useEffect37(() => {
36464
+ if (!isVisible) return;
36465
+ const handlePointerDown = (event) => {
36466
+ const target = event.target;
36467
+ if (target && (menuRef.current?.contains(target) || target.closest("[data-ueditor-keep-open]"))) return;
36468
+ const table = target?.closest("table");
36469
+ if (table && editor.view.dom.contains(table)) return;
36470
+ closeBubbleMenu(false);
36471
+ };
36472
+ const handleKeyDown2 = (event) => {
36473
+ if (event.key === "Escape") closeBubbleMenu();
36474
+ };
36475
+ document.addEventListener("pointerdown", handlePointerDown, true);
36476
+ document.addEventListener("keydown", handleKeyDown2);
36477
+ return () => {
36478
+ document.removeEventListener("pointerdown", handlePointerDown, true);
36479
+ document.removeEventListener("keydown", handleKeyDown2);
36480
+ };
36481
+ }, [closeBubbleMenu, editor, isVisible]);
36482
+ useEffect37(() => {
36483
+ const handleTableDoubleClick = (event) => {
36484
+ const target = event.target;
36485
+ const cell = target?.closest("td,th");
36486
+ if (!cell || !editor.view.dom.contains(cell)) return;
36487
+ suppressShowUntilRef.current = 0;
36488
+ keepOpenRef.current = true;
36489
+ setKeepOpenState(true);
36490
+ setLinkInputOpen(false);
36491
+ setCellBorderOpenRequest((request) => request + 1);
36492
+ setIsVisible(true);
36493
+ requestAnimationFrame(() => editor.view.focus());
36494
+ };
36495
+ editor.view.dom.addEventListener("dblclick", handleTableDoubleClick);
36496
+ return () => editor.view.dom.removeEventListener("dblclick", handleTableDoubleClick);
36497
+ }, [editor]);
36137
36498
  if (!isVisible) return null;
36138
36499
  return createPortal8(
36139
36500
  /* @__PURE__ */ jsx93(
@@ -36174,7 +36535,8 @@ var CustomBubbleMenu = ({
36174
36535
  onRequestClose: closeBubbleMenu,
36175
36536
  fontSizes,
36176
36537
  lineHeights,
36177
- initialShowLinkInput: linkInputOpen
36538
+ initialShowLinkInput: linkInputOpen,
36539
+ cellBorderOpenRequest
36178
36540
  }
36179
36541
  )
36180
36542
  }
@@ -40626,7 +40988,7 @@ function moveTableRow$1(table, indexesOrigin, indexesTarget, direction) {
40626
40988
  rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction);
40627
40989
  return convertArrayOfRowsToTableNode(table, rows);
40628
40990
  }
40629
- function selectedRect3(state) {
40991
+ function selectedRect4(state) {
40630
40992
  const sel = state.selection;
40631
40993
  const $pos = selectionCell(state);
40632
40994
  const table = $pos.node(-1);
@@ -40644,7 +41006,7 @@ function deprecated_toggleHeader(type) {
40644
41006
  if (!isInTable(state)) return false;
40645
41007
  if (dispatch) {
40646
41008
  const types = tableNodeTypes2(state.schema);
40647
- const rect = selectedRect3(state), tr = state.tr;
41009
+ const rect = selectedRect4(state), tr = state.tr;
40648
41010
  const cells = rect.map.cellsInRect(type == "column" ? {
40649
41011
  left: rect.left,
40650
41012
  top: 0,
@@ -40684,7 +41046,7 @@ function toggleHeader(type, options) {
40684
41046
  if (!isInTable(state)) return false;
40685
41047
  if (dispatch) {
40686
41048
  const types = tableNodeTypes2(state.schema);
40687
- const rect = selectedRect3(state), tr = state.tr;
41049
+ const rect = selectedRect4(state), tr = state.tr;
40688
41050
  const isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
40689
41051
  const isHeaderColumnEnabled = isHeaderEnabledByType("column", rect, types);
40690
41052
  const selectionStartsAt = (type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false) ? 1 : 0;