@lumir-company/editor 0.4.16 → 0.4.18

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
@@ -45,10 +45,10 @@ __export(index_exports, {
45
45
  module.exports = __toCommonJS(index_exports);
46
46
 
47
47
  // src/components/LumirEditor.tsx
48
- var import_react34 = require("react");
49
- var import_react35 = require("@blocknote/react");
48
+ var import_react37 = require("react");
49
+ var import_react38 = require("@blocknote/react");
50
50
  var import_mantine = require("@blocknote/mantine");
51
- var import_core5 = require("@blocknote/core");
51
+ var import_core9 = require("@blocknote/core");
52
52
  var import_locales = require("@blocknote/core/locales");
53
53
 
54
54
  // src/utils/cn.ts
@@ -286,7 +286,7 @@ var createS3Uploader = (config) => {
286
286
 
287
287
  // src/blocks/HtmlPreview.tsx
288
288
  var import_react6 = require("@blocknote/react");
289
- var import_core = require("@blocknote/core");
289
+ var import_core3 = require("@blocknote/core");
290
290
 
291
291
  // src/blocks/LinkPreview.tsx
292
292
  var import_react = require("@blocknote/react");
@@ -1246,6 +1246,310 @@ var VideoBlock = (0, import_react3.createReactBlockSpec)(
1246
1246
  }
1247
1247
  );
1248
1248
 
1249
+ // src/blocks/columns/ColumnList.ts
1250
+ var import_core = require("@blocknote/core");
1251
+
1252
+ // src/blocks/columns/columnNormalization.ts
1253
+ var import_prosemirror_state = require("prosemirror-state");
1254
+ var columnNormalizationKey = new import_prosemirror_state.PluginKey("lumirColumnNormalization");
1255
+ function columnNormalization() {
1256
+ return new import_prosemirror_state.Plugin({
1257
+ key: columnNormalizationKey,
1258
+ appendTransaction(transactions, _oldState, newState) {
1259
+ if (!transactions.some((tr2) => tr2.docChanged)) {
1260
+ return null;
1261
+ }
1262
+ const lists = [];
1263
+ newState.doc.descendants((node, pos) => {
1264
+ if (node.type.name === "columnList") {
1265
+ lists.push({ pos, node });
1266
+ return false;
1267
+ }
1268
+ return void 0;
1269
+ });
1270
+ if (lists.length === 0) {
1271
+ return null;
1272
+ }
1273
+ const tr = newState.tr;
1274
+ let modified = false;
1275
+ for (let i = lists.length - 1; i >= 0; i--) {
1276
+ const { pos, node } = lists[i];
1277
+ const nonEmptyColumns = [];
1278
+ node.forEach((col) => {
1279
+ if (col.type.name === "column" && col.childCount > 0) {
1280
+ nonEmptyColumns.push(col);
1281
+ }
1282
+ });
1283
+ if (nonEmptyColumns.length >= 2) {
1284
+ continue;
1285
+ }
1286
+ const from = tr.mapping.map(pos);
1287
+ const to = tr.mapping.map(pos + node.nodeSize);
1288
+ const blocks = [];
1289
+ nonEmptyColumns.forEach((col) => {
1290
+ col.forEach((bc) => blocks.push(bc));
1291
+ });
1292
+ if (blocks.length > 0) {
1293
+ tr.replaceWith(from, to, blocks);
1294
+ } else {
1295
+ tr.delete(from, to);
1296
+ }
1297
+ modified = true;
1298
+ }
1299
+ return modified ? tr : null;
1300
+ }
1301
+ });
1302
+ }
1303
+
1304
+ // src/blocks/columns/columnDnd.ts
1305
+ var import_prosemirror_state2 = require("prosemirror-state");
1306
+ var import_prosemirror_view = require("prosemirror-view");
1307
+
1308
+ // src/blocks/columns/mergeColumns.ts
1309
+ function mergeBlocksIntoColumns(editor, draggedId, targetId, side) {
1310
+ if (!editor || !draggedId || !targetId || draggedId === targetId) {
1311
+ return false;
1312
+ }
1313
+ const dragged = editor.getBlock?.(draggedId);
1314
+ const target = editor.getBlock?.(targetId);
1315
+ if (!dragged || !target) {
1316
+ return false;
1317
+ }
1318
+ if (dragged.type === "columnList" || dragged.type === "column" || target.type === "columnList" || target.type === "column") {
1319
+ return false;
1320
+ }
1321
+ const columnList = {
1322
+ type: "columnList",
1323
+ children: side === "left" ? [
1324
+ { type: "column", children: [dragged] },
1325
+ { type: "column", children: [target] }
1326
+ ] : [
1327
+ { type: "column", children: [target] },
1328
+ { type: "column", children: [dragged] }
1329
+ ]
1330
+ };
1331
+ try {
1332
+ const run = () => {
1333
+ editor.removeBlocks([draggedId]);
1334
+ editor.replaceBlocks([targetId], [columnList]);
1335
+ };
1336
+ if (typeof editor.transact === "function") {
1337
+ editor.transact(run);
1338
+ } else {
1339
+ run();
1340
+ }
1341
+ return true;
1342
+ } catch {
1343
+ return false;
1344
+ }
1345
+ }
1346
+
1347
+ // src/blocks/columns/columnDnd.ts
1348
+ var columnDndKey = new import_prosemirror_state2.PluginKey("lumirColumnDnd");
1349
+ function edgeThreshold(width) {
1350
+ return Math.min(80, width * 0.3);
1351
+ }
1352
+ function topLevelBlockAtCoords(view, x, y) {
1353
+ const found = view.posAtCoords({ left: x, top: y });
1354
+ if (!found) {
1355
+ return null;
1356
+ }
1357
+ const $pos = view.state.doc.resolve(found.pos);
1358
+ for (let d = $pos.depth; d > 0; d--) {
1359
+ if ($pos.node(d).type.name === "blockContainer") {
1360
+ if (d !== 2 || $pos.node(d - 1).type.name !== "blockGroup") {
1361
+ return null;
1362
+ }
1363
+ const pos = $pos.before(d);
1364
+ const node = $pos.node(d);
1365
+ const dom = view.nodeDOM(pos);
1366
+ if (!dom || !node.attrs?.id) {
1367
+ return null;
1368
+ }
1369
+ return { pos, nodeSize: node.nodeSize, id: node.attrs.id, dom };
1370
+ }
1371
+ }
1372
+ return null;
1373
+ }
1374
+ function draggedBlockId(view) {
1375
+ const sel = view.state.selection;
1376
+ return sel?.node?.attrs?.id ?? null;
1377
+ }
1378
+ function setDnd(view, next) {
1379
+ const cur = columnDndKey.getState(view.state);
1380
+ if (cur && cur.targetPos === next.targetPos && cur.side === next.side) {
1381
+ return;
1382
+ }
1383
+ view.dispatch(view.state.tr.setMeta(columnDndKey, next));
1384
+ }
1385
+ var CLEARED = { targetPos: null, side: null };
1386
+ function columnDnd() {
1387
+ return new import_prosemirror_state2.Plugin({
1388
+ key: columnDndKey,
1389
+ state: {
1390
+ init: () => CLEARED,
1391
+ apply(tr, prev) {
1392
+ const meta = tr.getMeta(columnDndKey);
1393
+ if (meta) {
1394
+ return meta;
1395
+ }
1396
+ if (tr.docChanged && prev.targetPos !== null) {
1397
+ return CLEARED;
1398
+ }
1399
+ return prev;
1400
+ }
1401
+ },
1402
+ props: {
1403
+ handleDOMEvents: {
1404
+ dragover: (view, event) => {
1405
+ if (!view.dragging) {
1406
+ return false;
1407
+ }
1408
+ const target = topLevelBlockAtCoords(
1409
+ view,
1410
+ event.clientX,
1411
+ event.clientY
1412
+ );
1413
+ const draggedId = draggedBlockId(view);
1414
+ if (!target || !draggedId || target.id === draggedId) {
1415
+ setDnd(view, CLEARED);
1416
+ view.dom.classList.remove("lumir-col-dnd-active");
1417
+ return false;
1418
+ }
1419
+ const rect = target.dom.getBoundingClientRect();
1420
+ const th = edgeThreshold(rect.width);
1421
+ let side = null;
1422
+ if (event.clientX - rect.left <= th) {
1423
+ side = "left";
1424
+ } else if (rect.right - event.clientX <= th) {
1425
+ side = "right";
1426
+ }
1427
+ if (side) {
1428
+ setDnd(view, { targetPos: target.pos, side });
1429
+ view.dom.classList.add("lumir-col-dnd-active");
1430
+ } else {
1431
+ setDnd(view, CLEARED);
1432
+ view.dom.classList.remove("lumir-col-dnd-active");
1433
+ }
1434
+ return false;
1435
+ },
1436
+ dragend: (view) => {
1437
+ setDnd(view, CLEARED);
1438
+ view.dom.classList.remove("lumir-col-dnd-active");
1439
+ return false;
1440
+ },
1441
+ dragleave: (view, event) => {
1442
+ if (!event.relatedTarget) {
1443
+ setDnd(view, CLEARED);
1444
+ view.dom.classList.remove("lumir-col-dnd-active");
1445
+ }
1446
+ return false;
1447
+ }
1448
+ },
1449
+ handleDrop: (view, _event, _slice, _moved) => {
1450
+ const st = columnDndKey.getState(view.state);
1451
+ view.dom.classList.remove("lumir-col-dnd-active");
1452
+ if (!st || st.side === null || st.targetPos === null) {
1453
+ return false;
1454
+ }
1455
+ const draggedId = draggedBlockId(view);
1456
+ const targetNode = view.state.doc.nodeAt(st.targetPos);
1457
+ const targetId = targetNode?.attrs?.id;
1458
+ view.dispatch(view.state.tr.setMeta(columnDndKey, CLEARED));
1459
+ if (!draggedId || !targetId) {
1460
+ return false;
1461
+ }
1462
+ const editor = view.__lumirEditor;
1463
+ if (!editor) {
1464
+ return false;
1465
+ }
1466
+ const ok = mergeBlocksIntoColumns(editor, draggedId, targetId, st.side);
1467
+ return ok;
1468
+ },
1469
+ decorations: (state) => {
1470
+ const st = columnDndKey.getState(state);
1471
+ if (!st || st.side === null || st.targetPos === null) {
1472
+ return null;
1473
+ }
1474
+ const node = state.doc.nodeAt(st.targetPos);
1475
+ if (!node) {
1476
+ return null;
1477
+ }
1478
+ return import_prosemirror_view.DecorationSet.create(state.doc, [
1479
+ import_prosemirror_view.Decoration.node(st.targetPos, st.targetPos + node.nodeSize, {
1480
+ class: st.side === "left" ? "lumir-col-drop-left" : "lumir-col-drop-right"
1481
+ })
1482
+ ]);
1483
+ }
1484
+ }
1485
+ });
1486
+ }
1487
+
1488
+ // src/blocks/columns/ColumnList.ts
1489
+ var ColumnList = (0, import_core.createStronglyTypedTiptapNode)({
1490
+ name: "columnList",
1491
+ group: "childContainer bnBlock blockGroupChild",
1492
+ content: "column column+",
1493
+ parseHTML() {
1494
+ return [{ tag: 'div[data-node-type="columnList"]' }];
1495
+ },
1496
+ renderHTML({ HTMLAttributes }) {
1497
+ const dom = document.createElement("div");
1498
+ dom.className = "bn-column-list";
1499
+ dom.setAttribute("data-node-type", "columnList");
1500
+ for (const [attribute, value] of Object.entries(HTMLAttributes)) {
1501
+ if (attribute !== "class") {
1502
+ dom.setAttribute(attribute, value);
1503
+ }
1504
+ }
1505
+ return { dom, contentDOM: dom };
1506
+ },
1507
+ // columnNormalization: 빈 컬럼/1단 columnList 자동 복구(unwrap).
1508
+ // columnDnd: 블록을 다른 블록 좌/우로 드롭하면 2단 컬럼 생성.
1509
+ addProseMirrorPlugins() {
1510
+ return [columnNormalization(), columnDnd()];
1511
+ }
1512
+ });
1513
+
1514
+ // src/blocks/columns/Column.ts
1515
+ var import_core2 = require("@blocknote/core");
1516
+ var Column = (0, import_core2.createStronglyTypedTiptapNode)({
1517
+ name: "column",
1518
+ group: "bnBlock childContainer",
1519
+ content: "blockContainer+",
1520
+ addAttributes() {
1521
+ return {
1522
+ width: {
1523
+ default: 1,
1524
+ parseHTML: (element) => {
1525
+ const w = parseFloat(element.getAttribute("data-column-width") || "");
1526
+ return Number.isFinite(w) && w > 0 ? w : 1;
1527
+ },
1528
+ renderHTML: (attributes) => {
1529
+ if (!attributes.width || attributes.width === 1) {
1530
+ return {};
1531
+ }
1532
+ return { "data-column-width": String(attributes.width) };
1533
+ }
1534
+ }
1535
+ };
1536
+ },
1537
+ parseHTML() {
1538
+ return [{ tag: 'div[data-node-type="column"]' }];
1539
+ },
1540
+ renderHTML({ HTMLAttributes }) {
1541
+ const dom = document.createElement("div");
1542
+ dom.className = "bn-column";
1543
+ dom.setAttribute("data-node-type", "column");
1544
+ for (const [attribute, value] of Object.entries(HTMLAttributes)) {
1545
+ if (attribute !== "class") {
1546
+ dom.setAttribute(attribute, value);
1547
+ }
1548
+ }
1549
+ return { dom, contentDOM: dom };
1550
+ }
1551
+ });
1552
+
1249
1553
  // src/styles/FontSizeStyle.tsx
1250
1554
  var import_react5 = require("@blocknote/react");
1251
1555
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -1351,7 +1655,7 @@ var HtmlPreviewBlock = (0, import_react6.createReactBlockSpec)(
1351
1655
  setIsResizing(true);
1352
1656
  const startY = e.clientY;
1353
1657
  const startHeight = currentHeight;
1354
- const handleMouseMove = (moveEvent) => {
1658
+ const handleMouseMove2 = (moveEvent) => {
1355
1659
  const deltaY = moveEvent.clientY - startY;
1356
1660
  const newHeight = Math.min(
1357
1661
  MAX_HEIGHT,
@@ -1363,10 +1667,10 @@ var HtmlPreviewBlock = (0, import_react6.createReactBlockSpec)(
1363
1667
  };
1364
1668
  const handleMouseUp = () => {
1365
1669
  setIsResizing(false);
1366
- document.removeEventListener("mousemove", handleMouseMove);
1670
+ document.removeEventListener("mousemove", handleMouseMove2);
1367
1671
  document.removeEventListener("mouseup", handleMouseUp);
1368
1672
  };
1369
- document.addEventListener("mousemove", handleMouseMove);
1673
+ document.addEventListener("mousemove", handleMouseMove2);
1370
1674
  document.addEventListener("mouseup", handleMouseUp);
1371
1675
  },
1372
1676
  [currentHeight, props.editor, props.block]
@@ -1632,16 +1936,23 @@ var HtmlPreviewBlock = (0, import_react6.createReactBlockSpec)(
1632
1936
  }
1633
1937
  }
1634
1938
  );
1635
- var schema = import_core.BlockNoteSchema.create({
1939
+ var ColumnListBlock = (0, import_core3.createBlockSpecFromStronglyTypedTiptapNode)(
1940
+ ColumnList,
1941
+ {}
1942
+ );
1943
+ var ColumnBlock = (0, import_core3.createBlockSpecFromStronglyTypedTiptapNode)(Column, {});
1944
+ var schema = import_core3.BlockNoteSchema.create({
1636
1945
  blockSpecs: {
1637
- ...import_core.defaultBlockSpecs,
1946
+ ...import_core3.defaultBlockSpecs,
1638
1947
  htmlPreview: HtmlPreviewBlock,
1639
1948
  linkPreview: LinkPreviewBlock,
1640
- video: VideoBlock
1949
+ video: VideoBlock,
1950
+ columnList: ColumnListBlock,
1951
+ column: ColumnBlock
1641
1952
  },
1642
- inlineContentSpecs: import_core.defaultInlineContentSpecs,
1953
+ inlineContentSpecs: import_core3.defaultInlineContentSpecs,
1643
1954
  styleSpecs: {
1644
- ...import_core.defaultStyleSpecs,
1955
+ ...import_core3.defaultStyleSpecs,
1645
1956
  // 인라인 글자 크기. 저장 JSON 직렬화는 형제 키 방식(font-size-serialization.ts) 사용.
1646
1957
  fontSize: FontSize
1647
1958
  }
@@ -1785,7 +2096,7 @@ var UndoRedoButtons = ({ editor }) => {
1785
2096
  console.error("Redo failed:", err);
1786
2097
  }
1787
2098
  }, [editor]);
1788
- const handleMouseDown = (0, import_react8.useCallback)((e) => {
2099
+ const handleMouseDown2 = (0, import_react8.useCallback)((e) => {
1789
2100
  e.preventDefault();
1790
2101
  }, []);
1791
2102
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "lumir-toolbar-group", children: [
@@ -1794,7 +2105,7 @@ var UndoRedoButtons = ({ editor }) => {
1794
2105
  {
1795
2106
  className: "lumir-toolbar-btn",
1796
2107
  onClick: handleUndo,
1797
- onMouseDown: handleMouseDown,
2108
+ onMouseDown: handleMouseDown2,
1798
2109
  title: "\uC2E4\uD589 \uCDE8\uC18C",
1799
2110
  type: "button",
1800
2111
  children: Icons.undo
@@ -1805,7 +2116,7 @@ var UndoRedoButtons = ({ editor }) => {
1805
2116
  {
1806
2117
  className: "lumir-toolbar-btn",
1807
2118
  onClick: handleRedo,
1808
- onMouseDown: handleMouseDown,
2119
+ onMouseDown: handleMouseDown2,
1809
2120
  title: "\uB2E4\uC2DC \uC2E4\uD589",
1810
2121
  type: "button",
1811
2122
  children: Icons.redo
@@ -1849,7 +2160,7 @@ var TextStyleButton = ({
1849
2160
  console.error(`Toggle ${style} failed:`, err);
1850
2161
  }
1851
2162
  }, [editor, style]);
1852
- const handleMouseDown = (0, import_react9.useCallback)((e) => {
2163
+ const handleMouseDown2 = (0, import_react9.useCallback)((e) => {
1853
2164
  e.preventDefault();
1854
2165
  }, []);
1855
2166
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
@@ -1857,7 +2168,7 @@ var TextStyleButton = ({
1857
2168
  {
1858
2169
  className: cn("lumir-toolbar-btn", isActive && "is-active"),
1859
2170
  onClick: handleClick,
1860
- onMouseDown: handleMouseDown,
2171
+ onMouseDown: handleMouseDown2,
1861
2172
  title: titleMap[style],
1862
2173
  type: "button",
1863
2174
  children: iconMap[style]
@@ -1925,6 +2236,41 @@ function getFirstSelectedCellAttr(editor, attr) {
1925
2236
  const node = tiptap.state.doc.nodeAt(positions[0]);
1926
2237
  return node?.attrs?.[attr];
1927
2238
  }
2239
+ function findTableNodePos(tiptap, blockId) {
2240
+ let tablePos = -1;
2241
+ tiptap.state.doc.descendants((node, pos) => {
2242
+ if (tablePos !== -1) return false;
2243
+ if (node.type.name === "blockContainer" && node.attrs?.id === blockId && node.firstChild?.type.name === "table") {
2244
+ tablePos = pos + 1;
2245
+ return false;
2246
+ }
2247
+ return void 0;
2248
+ });
2249
+ return tablePos;
2250
+ }
2251
+ function setTableAlignment(editor, blockId, alignment) {
2252
+ const tiptap = editor?._tiptapEditor;
2253
+ if (!tiptap || !blockId) return false;
2254
+ const tablePos = findTableNodePos(tiptap, blockId);
2255
+ if (tablePos < 0) return false;
2256
+ const node = tiptap.state.doc.nodeAt(tablePos);
2257
+ if (!node || node.type.name !== "table") return false;
2258
+ tiptap.view?.dispatch(
2259
+ tiptap.state.tr.setNodeMarkup(tablePos, void 0, {
2260
+ ...node.attrs,
2261
+ tableAlignment: alignment
2262
+ })
2263
+ );
2264
+ return true;
2265
+ }
2266
+ function getTableAlignment(editor, blockId) {
2267
+ const tiptap = editor?._tiptapEditor;
2268
+ if (!tiptap || !blockId) return "left";
2269
+ const tablePos = findTableNodePos(tiptap, blockId);
2270
+ if (tablePos < 0) return "left";
2271
+ const node = tiptap.state.doc.nodeAt(tablePos);
2272
+ return node?.attrs?.tableAlignment || "left";
2273
+ }
1928
2274
 
1929
2275
  // src/components/FloatingMenu/components/AlignButton.tsx
1930
2276
  var import_jsx_runtime9 = require("react/jsx-runtime");
@@ -1967,7 +2313,7 @@ var AlignButton = ({
1967
2313
  console.error(`Set alignment ${alignment} failed:`, err);
1968
2314
  }
1969
2315
  }, [editor, alignment]);
1970
- const handleMouseDown = (0, import_react10.useCallback)((e) => {
2316
+ const handleMouseDown2 = (0, import_react10.useCallback)((e) => {
1971
2317
  e.preventDefault();
1972
2318
  }, []);
1973
2319
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
@@ -1975,7 +2321,7 @@ var AlignButton = ({
1975
2321
  {
1976
2322
  className: cn("lumir-toolbar-btn", isActive && "is-active"),
1977
2323
  onClick: handleClick,
1978
- onMouseDown: handleMouseDown,
2324
+ onMouseDown: handleMouseDown2,
1979
2325
  title: titleMap2[alignment],
1980
2326
  type: "button",
1981
2327
  children: iconMap2[alignment]
@@ -2017,7 +2363,7 @@ var ListButton = ({ editor, type }) => {
2017
2363
  console.error(`List toggle failed:`, err);
2018
2364
  }
2019
2365
  }, [editor, type]);
2020
- const handleMouseDown = (0, import_react11.useCallback)((e) => {
2366
+ const handleMouseDown2 = (0, import_react11.useCallback)((e) => {
2021
2367
  e.preventDefault();
2022
2368
  }, []);
2023
2369
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -2025,7 +2371,7 @@ var ListButton = ({ editor, type }) => {
2025
2371
  {
2026
2372
  className: cn("lumir-toolbar-btn", isActive && "is-active"),
2027
2373
  onClick: handleClick,
2028
- onMouseDown: handleMouseDown,
2374
+ onMouseDown: handleMouseDown2,
2029
2375
  title: titleMap3[type],
2030
2376
  type: "button",
2031
2377
  children: iconMap3[type]
@@ -2065,7 +2411,7 @@ var ImageButton = ({
2065
2411
  input.click();
2066
2412
  }
2067
2413
  }, [editor, onImageUpload]);
2068
- const handleMouseDown = (0, import_react12.useCallback)((e) => {
2414
+ const handleMouseDown2 = (0, import_react12.useCallback)((e) => {
2069
2415
  e.preventDefault();
2070
2416
  }, []);
2071
2417
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
@@ -2073,7 +2419,7 @@ var ImageButton = ({
2073
2419
  {
2074
2420
  className: "lumir-toolbar-btn",
2075
2421
  onClick: handleClick,
2076
- onMouseDown: handleMouseDown,
2422
+ onMouseDown: handleMouseDown2,
2077
2423
  title: "\uC774\uBBF8\uC9C0 \uC0BD\uC785",
2078
2424
  type: "button",
2079
2425
  children: Icons.image
@@ -2172,7 +2518,7 @@ var ColorButton = ({ editor, type }) => {
2172
2518
  },
2173
2519
  [editor, type]
2174
2520
  );
2175
- const handleMouseDown = (0, import_react13.useCallback)((e) => {
2521
+ const handleMouseDown2 = (0, import_react13.useCallback)((e) => {
2176
2522
  e.preventDefault();
2177
2523
  }, []);
2178
2524
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
@@ -2181,7 +2527,7 @@ var ColorButton = ({ editor, type }) => {
2181
2527
  {
2182
2528
  className: "lumir-toolbar-btn lumir-color-btn",
2183
2529
  onClick: () => setIsOpen(!isOpen),
2184
- onMouseDown: handleMouseDown,
2530
+ onMouseDown: handleMouseDown2,
2185
2531
  title: type === "text" ? "\uD14D\uC2A4\uD2B8 \uC0C9\uC0C1" : "\uBC30\uACBD \uC0C9\uC0C1",
2186
2532
  type: "button",
2187
2533
  children: [
@@ -2206,7 +2552,7 @@ var ColorButton = ({ editor, type }) => {
2206
2552
  currentColor === color.value && "is-active"
2207
2553
  ),
2208
2554
  onClick: () => handleColorSelect(color.value),
2209
- onMouseDown: handleMouseDown,
2555
+ onMouseDown: handleMouseDown2,
2210
2556
  title: color.name,
2211
2557
  style: { backgroundColor: color.hex },
2212
2558
  type: "button"
@@ -2258,7 +2604,7 @@ var FontSizeButton = ({ editor }) => {
2258
2604
  },
2259
2605
  [editor]
2260
2606
  );
2261
- const handleMouseDown = (0, import_react14.useCallback)((e) => {
2607
+ const handleMouseDown2 = (0, import_react14.useCallback)((e) => {
2262
2608
  e.preventDefault();
2263
2609
  }, []);
2264
2610
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
@@ -2267,7 +2613,7 @@ var FontSizeButton = ({ editor }) => {
2267
2613
  {
2268
2614
  className: "lumir-dropdown-btn lumir-font-size-btn",
2269
2615
  onClick: () => setIsOpen(!isOpen),
2270
- onMouseDown: handleMouseDown,
2616
+ onMouseDown: handleMouseDown2,
2271
2617
  title: "\uAE00\uC790 \uD06C\uAE30",
2272
2618
  type: "button",
2273
2619
  children: [
@@ -2285,7 +2631,7 @@ var FontSizeButton = ({ editor }) => {
2285
2631
  currentSize === "" && "is-active"
2286
2632
  ),
2287
2633
  onClick: () => handleSizeSelect(""),
2288
- onMouseDown: handleMouseDown,
2634
+ onMouseDown: handleMouseDown2,
2289
2635
  type: "button",
2290
2636
  children: DEFAULT_LABEL
2291
2637
  }
@@ -2298,7 +2644,7 @@ var FontSizeButton = ({ editor }) => {
2298
2644
  currentSize === size && "is-active"
2299
2645
  ),
2300
2646
  onClick: () => handleSizeSelect(size),
2301
- onMouseDown: handleMouseDown,
2647
+ onMouseDown: handleMouseDown2,
2302
2648
  type: "button",
2303
2649
  children: toLabel(size)
2304
2650
  },
@@ -2396,7 +2742,7 @@ var LinkButton = ({ editor }) => {
2396
2742
  setLinkUrl("");
2397
2743
  setErrorMsg(null);
2398
2744
  }, []);
2399
- const handleMouseDown = (0, import_react15.useCallback)((e) => {
2745
+ const handleMouseDown2 = (0, import_react15.useCallback)((e) => {
2400
2746
  e.preventDefault();
2401
2747
  }, []);
2402
2748
  const handleKeyDown = (0, import_react15.useCallback)(
@@ -2415,7 +2761,7 @@ var LinkButton = ({ editor }) => {
2415
2761
  {
2416
2762
  className: "lumir-toolbar-btn",
2417
2763
  onClick: () => setIsOpen(!isOpen),
2418
- onMouseDown: handleMouseDown,
2764
+ onMouseDown: handleMouseDown2,
2419
2765
  title: "\uB9C1\uD06C \uC0BD\uC785",
2420
2766
  type: "button",
2421
2767
  children: Icons.link
@@ -2435,7 +2781,7 @@ var LinkButton = ({ editor }) => {
2435
2781
  setErrorMsg(null);
2436
2782
  },
2437
2783
  onKeyDown: handleKeyDown,
2438
- onMouseDown: handleMouseDown
2784
+ onMouseDown: handleMouseDown2
2439
2785
  }
2440
2786
  ),
2441
2787
  errorMsg && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -2457,7 +2803,7 @@ var LinkButton = ({ editor }) => {
2457
2803
  type: "button",
2458
2804
  className: "lumir-link-btn lumir-link-cancel",
2459
2805
  onClick: handleCancel,
2460
- onMouseDown: handleMouseDown,
2806
+ onMouseDown: handleMouseDown2,
2461
2807
  children: "\uCDE8\uC18C"
2462
2808
  }
2463
2809
  ),
@@ -2466,7 +2812,7 @@ var LinkButton = ({ editor }) => {
2466
2812
  {
2467
2813
  type: "submit",
2468
2814
  className: "lumir-link-btn lumir-link-submit",
2469
- onMouseDown: handleMouseDown,
2815
+ onMouseDown: handleMouseDown2,
2470
2816
  disabled: !linkUrl.trim(),
2471
2817
  children: "\uD655\uC778"
2472
2818
  }
@@ -2502,7 +2848,7 @@ var TableButton = ({ editor }) => {
2502
2848
  console.error("Table insert failed:", err);
2503
2849
  }
2504
2850
  }, [editor]);
2505
- const handleMouseDown = (0, import_react16.useCallback)((e) => {
2851
+ const handleMouseDown2 = (0, import_react16.useCallback)((e) => {
2506
2852
  e.preventDefault();
2507
2853
  }, []);
2508
2854
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
@@ -2510,7 +2856,7 @@ var TableButton = ({ editor }) => {
2510
2856
  {
2511
2857
  className: "lumir-toolbar-btn",
2512
2858
  onClick: handleClick,
2513
- onMouseDown: handleMouseDown,
2859
+ onMouseDown: handleMouseDown2,
2514
2860
  title: "\uD14C\uC774\uBE14 \uC0BD\uC785",
2515
2861
  type: "button",
2516
2862
  children: Icons.table
@@ -2564,7 +2910,7 @@ var HTMLImportButton = ({
2564
2910
  const handleClick = (0, import_react17.useCallback)(() => {
2565
2911
  fileInputRef.current?.click();
2566
2912
  }, []);
2567
- const handleMouseDown = (0, import_react17.useCallback)((e) => {
2913
+ const handleMouseDown2 = (0, import_react17.useCallback)((e) => {
2568
2914
  e.preventDefault();
2569
2915
  }, []);
2570
2916
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
@@ -2583,7 +2929,7 @@ var HTMLImportButton = ({
2583
2929
  {
2584
2930
  className: "lumir-toolbar-btn",
2585
2931
  onClick: handleClick,
2586
- onMouseDown: handleMouseDown,
2932
+ onMouseDown: handleMouseDown2,
2587
2933
  title: "HTML Import",
2588
2934
  type: "button",
2589
2935
  children: Icons.htmlFile
@@ -2666,7 +3012,7 @@ var BlockTypeSelect = ({ editor }) => {
2666
3012
  console.error("Block type change failed:", err);
2667
3013
  }
2668
3014
  };
2669
- const handleMouseDown = (0, import_react18.useCallback)((e) => {
3015
+ const handleMouseDown2 = (0, import_react18.useCallback)((e) => {
2670
3016
  e.preventDefault();
2671
3017
  }, []);
2672
3018
  const getCurrentLabel = () => {
@@ -2703,7 +3049,7 @@ var BlockTypeSelect = ({ editor }) => {
2703
3049
  {
2704
3050
  className: "lumir-dropdown-btn lumir-block-type-btn",
2705
3051
  onClick: () => setIsOpen(!isOpen),
2706
- onMouseDown: handleMouseDown,
3052
+ onMouseDown: handleMouseDown2,
2707
3053
  type: "button",
2708
3054
  children: [
2709
3055
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "lumir-block-icon", children: BlockTypeIcons[getCurrentIcon()] }),
@@ -2722,7 +3068,7 @@ var BlockTypeSelect = ({ editor }) => {
2722
3068
  isActiveItem(bt) && "is-active"
2723
3069
  ),
2724
3070
  onClick: () => handleTypeChange(bt.type, bt.level, bt.isToggle),
2725
- onMouseDown: handleMouseDown,
3071
+ onMouseDown: handleMouseDown2,
2726
3072
  children: [
2727
3073
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "lumir-block-icon", children: BlockTypeIcons[bt.icon] }),
2728
3074
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "lumir-block-item-title", children: bt.label })
@@ -3032,8 +3378,8 @@ var LumirEditorError = class _LumirEditorError extends Error {
3032
3378
  };
3033
3379
 
3034
3380
  // src/extensions/VerticalAlignmentExtension.ts
3035
- var import_core2 = require("@tiptap/core");
3036
- var VerticalAlignmentExtension = import_core2.Extension.create({
3381
+ var import_core4 = require("@tiptap/core");
3382
+ var VerticalAlignmentExtension = import_core4.Extension.create({
3037
3383
  name: "verticalAlignment",
3038
3384
  addGlobalAttributes() {
3039
3385
  return [
@@ -3063,105 +3409,679 @@ var VerticalAlignmentExtension = import_core2.Extension.create({
3063
3409
  }
3064
3410
  });
3065
3411
 
3066
- // src/components/CustomFormattingToolbar.tsx
3067
- var import_react28 = require("@blocknote/react");
3412
+ // src/extensions/RowHeightExtension.ts
3413
+ var import_core5 = require("@tiptap/core");
3068
3414
 
3069
- // src/components/TextAlignButtonWithVA.tsx
3070
- var import_core3 = require("@blocknote/core");
3071
- var import_react20 = require("react");
3072
- var import_react21 = require("@blocknote/react");
3073
- var import_jsx_runtime19 = require("react/jsx-runtime");
3074
- var icons = {
3075
- left: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z" }) }),
3076
- center: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z" }) }),
3077
- right: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z" }) }),
3078
- justify: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zM3 3v2h18V3H3z" }) })
3079
- };
3080
- var tooltipMap = {
3081
- left: "\uC67C\uCABD \uC815\uB82C",
3082
- center: "\uAC00\uC6B4\uB370 \uC815\uB82C",
3083
- right: "\uC624\uB978\uCABD \uC815\uB82C",
3084
- justify: "\uC591\uCABD \uC815\uB82C"
3085
- };
3086
- var TextAlignButtonWithVA = (props) => {
3087
- const Components = (0, import_react21.useComponentsContext)();
3088
- const editor = (0, import_react21.useBlockNoteEditor)();
3089
- const selectedBlocks = (0, import_react21.useSelectedBlocks)(editor);
3090
- const textAlignment = (0, import_react20.useMemo)(() => {
3091
- const block = selectedBlocks[0];
3092
- if ((0, import_core3.checkBlockHasDefaultProp)("textAlignment", block, editor)) {
3093
- return block.props.textAlignment;
3415
+ // src/extensions/rowResizing.ts
3416
+ var import_prosemirror_state3 = require("prosemirror-state");
3417
+ var import_prosemirror_view2 = require("prosemirror-view");
3418
+ var import_prosemirror_tables = require("prosemirror-tables");
3419
+
3420
+ // src/constants/limits.ts
3421
+ var MAX_FILE_SIZE = 10 * 1024 * 1024;
3422
+ var MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;
3423
+ var BLOCKED_EXTENSIONS = [".svg", ".svgz"];
3424
+ var ALLOWED_VIDEO_MIME_TYPES = /* @__PURE__ */ new Set([
3425
+ "video/mp4",
3426
+ "video/webm",
3427
+ "video/ogg",
3428
+ "video/quicktime"
3429
+ // .mov
3430
+ ]);
3431
+ var ALLOWED_VIDEO_EXTENSIONS = [
3432
+ ".mp4",
3433
+ ".webm",
3434
+ ".ogg",
3435
+ ".mov"
3436
+ ];
3437
+ var ROW_RESIZE_MIN_HEIGHT = 24;
3438
+ var ROW_RESIZE_HANDLE_WIDTH = 5;
3439
+
3440
+ // src/extensions/rowResizing.ts
3441
+ var rowResizingPluginKey = new import_prosemirror_state3.PluginKey(
3442
+ "lumirRowResizing"
3443
+ );
3444
+ var RowResizeState = class _RowResizeState {
3445
+ constructor(activeHandle, dragging) {
3446
+ this.activeHandle = activeHandle;
3447
+ this.dragging = dragging;
3448
+ }
3449
+ apply(tr) {
3450
+ const action = tr.getMeta(rowResizingPluginKey);
3451
+ if (action && action.setHandle != null) {
3452
+ return new _RowResizeState(action.setHandle, null);
3094
3453
  }
3095
- if (block.type === "table") {
3096
- const cellSelection = editor.tableHandles?.getCellSelection();
3097
- if (!cellSelection) {
3098
- return;
3454
+ if (action && action.setDragging !== void 0) {
3455
+ return new _RowResizeState(this.activeHandle, action.setDragging);
3456
+ }
3457
+ if (this.activeHandle > -1 && tr.docChanged) {
3458
+ let handle = tr.mapping.map(this.activeHandle, -1);
3459
+ if (!(0, import_prosemirror_tables.pointsAtCell)(tr.doc.resolve(handle))) {
3460
+ handle = -1;
3099
3461
  }
3100
- const allCellsInTable = cellSelection.cells.map(
3101
- ({ row, col }) => (0, import_core3.mapTableCell)(
3102
- block.content.rows[row].cells[col]
3103
- ).props.textAlignment
3104
- );
3105
- const firstAlignment = allCellsInTable[0];
3106
- if (allCellsInTable.every((alignment) => alignment === firstAlignment)) {
3107
- return firstAlignment;
3462
+ return new _RowResizeState(handle, this.dragging);
3463
+ }
3464
+ return this;
3465
+ }
3466
+ };
3467
+ function rowResizing({
3468
+ handleWidth = ROW_RESIZE_HANDLE_WIDTH,
3469
+ minHeight = ROW_RESIZE_MIN_HEIGHT
3470
+ } = {}) {
3471
+ return new import_prosemirror_state3.Plugin({
3472
+ key: rowResizingPluginKey,
3473
+ state: {
3474
+ init() {
3475
+ return new RowResizeState(-1, null);
3476
+ },
3477
+ apply(tr, prev) {
3478
+ return prev.apply(tr);
3479
+ }
3480
+ },
3481
+ props: {
3482
+ attributes: (state) => {
3483
+ const pluginState = rowResizingPluginKey.getState(state);
3484
+ return pluginState && pluginState.activeHandle > -1 ? { class: "row-resize-cursor" } : {};
3485
+ },
3486
+ handleDOMEvents: {
3487
+ mousemove: (view, event) => {
3488
+ handleMouseMove(view, event, handleWidth);
3489
+ },
3490
+ mouseleave: (view) => {
3491
+ handleMouseLeave(view);
3492
+ },
3493
+ mousedown: (view, event) => {
3494
+ handleMouseDown(view, event, minHeight);
3495
+ }
3496
+ },
3497
+ decorations: (state) => {
3498
+ const pluginState = rowResizingPluginKey.getState(state);
3499
+ if (pluginState && pluginState.activeHandle > -1) {
3500
+ return handleDecorations(state, pluginState);
3501
+ }
3502
+ return void 0;
3108
3503
  }
3109
3504
  }
3505
+ });
3506
+ }
3507
+ function handleMouseMove(view, event, handleWidth) {
3508
+ if (!view.editable) {
3110
3509
  return;
3111
- }, [editor, selectedBlocks]);
3112
- const setTextAlignment = (0, import_react20.useCallback)(
3113
- (newAlignment) => {
3114
- editor.focus();
3115
- for (const block of selectedBlocks) {
3116
- if (block.type === "table") {
3117
- const tiptap = editor._tiptapEditor;
3118
- if (!tiptap) continue;
3119
- const positions = getSelectedCellPositions(editor);
3120
- if (positions.length === 0) continue;
3121
- const { state } = tiptap;
3122
- let tr = state.tr;
3123
- for (const pos of positions) {
3124
- const node = tr.doc.nodeAt(pos);
3125
- if (node) {
3126
- tr = tr.setNodeMarkup(pos, void 0, {
3127
- ...node.attrs,
3128
- textAlignment: newAlignment
3129
- });
3130
- }
3131
- }
3132
- tiptap.view?.dispatch(tr);
3133
- } else if ((0, import_core3.checkBlockTypeHasDefaultProp)("textAlignment", block.type, editor)) {
3134
- editor.updateBlock(block, {
3135
- props: { textAlignment: newAlignment }
3136
- });
3137
- }
3510
+ }
3511
+ const pluginState = rowResizingPluginKey.getState(view.state);
3512
+ if (!pluginState) {
3513
+ return;
3514
+ }
3515
+ if (!pluginState.dragging) {
3516
+ const target = domCellAround(event.target);
3517
+ let cell = -1;
3518
+ if (target) {
3519
+ const { top, bottom } = target.getBoundingClientRect();
3520
+ if (event.clientY - top <= handleWidth) {
3521
+ cell = edgeCell(view, event, "top", handleWidth);
3522
+ } else if (bottom - event.clientY <= handleWidth) {
3523
+ cell = edgeCell(view, event, "bottom", handleWidth);
3138
3524
  }
3139
- },
3140
- [editor, selectedBlocks]
3141
- );
3142
- const show = (0, import_react20.useMemo)(() => {
3143
- return !!selectedBlocks.find(
3144
- (block) => "textAlignment" in block.props || block.type === "table" && block.children
3145
- );
3146
- }, [selectedBlocks]);
3147
- if (!show || !editor.isEditable) {
3148
- return null;
3525
+ }
3526
+ if (cell !== pluginState.activeHandle) {
3527
+ updateHandle(view, cell);
3528
+ }
3149
3529
  }
3150
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3151
- Components.FormattingToolbar.Button,
3152
- {
3153
- className: "bn-button",
3154
- "data-test": `alignText${props.textAlignment.slice(0, 1).toUpperCase() + props.textAlignment.slice(1)}`,
3155
- onClick: () => setTextAlignment(props.textAlignment),
3156
- isSelected: textAlignment === props.textAlignment,
3157
- label: tooltipMap[props.textAlignment],
3158
- mainTooltip: tooltipMap[props.textAlignment],
3159
- icon: icons[props.textAlignment]
3530
+ }
3531
+ function handleMouseLeave(view) {
3532
+ if (!view.editable) {
3533
+ return;
3534
+ }
3535
+ const pluginState = rowResizingPluginKey.getState(view.state);
3536
+ if (pluginState && pluginState.activeHandle > -1 && !pluginState.dragging) {
3537
+ updateHandle(view, -1);
3538
+ }
3539
+ }
3540
+ function handleMouseDown(view, event, minHeight) {
3541
+ if (!view.editable) {
3542
+ return false;
3543
+ }
3544
+ const win = view.dom.ownerDocument.defaultView ?? window;
3545
+ const pluginState = rowResizingPluginKey.getState(view.state);
3546
+ if (!pluginState || pluginState.activeHandle === -1 || pluginState.dragging) {
3547
+ return false;
3548
+ }
3549
+ const startHeight = currentRowHeight(view, pluginState.activeHandle);
3550
+ setDragging(view, {
3551
+ startY: event.clientY,
3552
+ startHeight,
3553
+ currentHeight: startHeight
3554
+ });
3555
+ function finish(finishEvent) {
3556
+ win.removeEventListener("mouseup", finish);
3557
+ win.removeEventListener("mousemove", move);
3558
+ const ps = rowResizingPluginKey.getState(view.state);
3559
+ if (ps?.dragging) {
3560
+ const finalHeight = draggedHeight(ps.dragging, finishEvent, minHeight);
3561
+ setDragging(view, null);
3562
+ commitRowHeight(view, ps.activeHandle, finalHeight);
3563
+ }
3564
+ }
3565
+ function move(moveEvent) {
3566
+ if (moveEvent.buttons === 0 || moveEvent.buttons === void 0 && !moveEvent.which) {
3567
+ return finish(moveEvent);
3568
+ }
3569
+ const ps = rowResizingPluginKey.getState(view.state);
3570
+ if (!ps?.dragging) {
3571
+ return;
3572
+ }
3573
+ const h = draggedHeight(ps.dragging, moveEvent, minHeight);
3574
+ if (h !== ps.dragging.currentHeight) {
3575
+ setDragging(view, { ...ps.dragging, currentHeight: h });
3160
3576
  }
3577
+ }
3578
+ win.addEventListener("mouseup", finish);
3579
+ win.addEventListener("mousemove", move);
3580
+ event.preventDefault();
3581
+ return true;
3582
+ }
3583
+ function setDragging(view, dragging) {
3584
+ view.dispatch(
3585
+ view.state.tr.setMeta(rowResizingPluginKey, { setDragging: dragging })
3161
3586
  );
3162
- };
3163
-
3164
- // src/components/VerticalAlignButton.tsx
3587
+ }
3588
+ function currentRowHeight(view, cellPos) {
3589
+ const info = targetRowInfo(view, cellPos);
3590
+ const tr = rowTrElement(view, cellPos, info.row);
3591
+ return tr ? tr.offsetHeight : ROW_RESIZE_MIN_HEIGHT;
3592
+ }
3593
+ function commitRowHeight(view, cellPos, height) {
3594
+ const { table, map, start, row } = targetRowInfo(view, cellPos);
3595
+ const tr = view.state.tr;
3596
+ const seen = /* @__PURE__ */ new Set();
3597
+ for (let col = 0; col < map.width; col++) {
3598
+ const cellRelPos = map.map[row * map.width + col];
3599
+ if (seen.has(cellRelPos)) {
3600
+ continue;
3601
+ }
3602
+ seen.add(cellRelPos);
3603
+ const rect = map.findCell(cellRelPos);
3604
+ if (rect.bottom - 1 !== row) {
3605
+ continue;
3606
+ }
3607
+ const node = table.nodeAt(cellRelPos);
3608
+ if (!node || node.attrs.rowHeight === height) {
3609
+ continue;
3610
+ }
3611
+ tr.setNodeMarkup(start + cellRelPos, void 0, {
3612
+ ...node.attrs,
3613
+ rowHeight: height
3614
+ });
3615
+ }
3616
+ if (tr.docChanged) {
3617
+ view.dispatch(tr);
3618
+ }
3619
+ }
3620
+ function targetRowInfo(view, cellPos) {
3621
+ const $cell = view.state.doc.resolve(cellPos);
3622
+ const table = $cell.node(-1);
3623
+ const map = import_prosemirror_tables.TableMap.get(table);
3624
+ const start = $cell.start(-1);
3625
+ const rect = map.findCell($cell.pos - start);
3626
+ return { table, map, start, row: rect.bottom - 1, $cell };
3627
+ }
3628
+ function rowTrElement(view, cellPos, row) {
3629
+ let dom = view.nodeDOM(cellPos);
3630
+ while (dom && dom.nodeName !== "TABLE") {
3631
+ dom = dom.parentNode;
3632
+ }
3633
+ if (!dom) {
3634
+ return null;
3635
+ }
3636
+ return dom.rows[row] ?? null;
3637
+ }
3638
+ function domCellAround(target) {
3639
+ let node = target;
3640
+ while (node && node.nodeName !== "TD" && node.nodeName !== "TH") {
3641
+ node = node.classList?.contains("ProseMirror") ? null : node.parentNode;
3642
+ }
3643
+ return node;
3644
+ }
3645
+ function edgeCell(view, event, side, handleWidth) {
3646
+ const offset2 = side === "bottom" ? -handleWidth : handleWidth;
3647
+ const found = view.posAtCoords({
3648
+ left: event.clientX,
3649
+ top: event.clientY + offset2
3650
+ });
3651
+ if (!found) {
3652
+ return -1;
3653
+ }
3654
+ const $cell = (0, import_prosemirror_tables.cellAround)(view.state.doc.resolve(found.pos));
3655
+ if (!$cell) {
3656
+ return -1;
3657
+ }
3658
+ if (side === "bottom") {
3659
+ return $cell.pos;
3660
+ }
3661
+ const map = import_prosemirror_tables.TableMap.get($cell.node(-1));
3662
+ const start = $cell.start(-1);
3663
+ const index = map.map.indexOf($cell.pos - start);
3664
+ return index < map.width ? -1 : start + map.map[index - map.width];
3665
+ }
3666
+ function updateHandle(view, value) {
3667
+ view.dispatch(
3668
+ view.state.tr.setMeta(rowResizingPluginKey, { setHandle: value })
3669
+ );
3670
+ }
3671
+ function draggedHeight(dragging, event, minHeight) {
3672
+ const offset2 = event.clientY - dragging.startY;
3673
+ return Math.max(minHeight, dragging.startHeight + offset2);
3674
+ }
3675
+ function handleDecorations(state, pluginState) {
3676
+ const decorations = [];
3677
+ const $cell = state.doc.resolve(pluginState.activeHandle);
3678
+ const table = $cell.node(-1);
3679
+ if (!table) {
3680
+ return import_prosemirror_view2.DecorationSet.empty;
3681
+ }
3682
+ const map = import_prosemirror_tables.TableMap.get(table);
3683
+ const start = $cell.start(-1);
3684
+ const row = map.findCell($cell.pos - start).bottom - 1;
3685
+ const dragging = pluginState.dragging;
3686
+ const seen = /* @__PURE__ */ new Set();
3687
+ for (let col = 0; col < map.width; col++) {
3688
+ const cellRelPos = map.map[row * map.width + col];
3689
+ if (seen.has(cellRelPos)) {
3690
+ continue;
3691
+ }
3692
+ seen.add(cellRelPos);
3693
+ if (map.findCell(cellRelPos).bottom - 1 !== row) {
3694
+ continue;
3695
+ }
3696
+ const node = table.nodeAt(cellRelPos);
3697
+ if (!node) {
3698
+ continue;
3699
+ }
3700
+ const from = start + cellRelPos;
3701
+ const to = from + node.nodeSize;
3702
+ if (dragging) {
3703
+ decorations.push(
3704
+ import_prosemirror_view2.Decoration.node(from, to, {
3705
+ class: "row-resize-dragging",
3706
+ style: `height: ${dragging.currentHeight}px`
3707
+ })
3708
+ );
3709
+ }
3710
+ const handle = document.createElement("div");
3711
+ handle.className = "row-resize-handle";
3712
+ decorations.push(import_prosemirror_view2.Decoration.widget(to - 1, handle));
3713
+ }
3714
+ return import_prosemirror_view2.DecorationSet.create(state.doc, decorations);
3715
+ }
3716
+
3717
+ // src/extensions/tableCellAttrPreserve.ts
3718
+ var import_prosemirror_state4 = require("prosemirror-state");
3719
+ var tableCellAttrPreserveKey = new import_prosemirror_state4.PluginKey(
3720
+ "lumirTableCellAttrPreserve"
3721
+ );
3722
+ var PRESERVED_ATTRS = [
3723
+ { name: "rowHeight", default: null },
3724
+ { name: "verticalAlignment", default: "top" }
3725
+ ];
3726
+ function isMeaningful(attrName, value, def) {
3727
+ if (value === null || value === void 0) {
3728
+ return false;
3729
+ }
3730
+ return value !== def;
3731
+ }
3732
+ function meaningfulAttrs(node) {
3733
+ let out = null;
3734
+ for (const { name, default: def } of PRESERVED_ATTRS) {
3735
+ const v = node.attrs?.[name];
3736
+ if (isMeaningful(name, v, def)) {
3737
+ (out ?? (out = {}))[name] = v;
3738
+ }
3739
+ }
3740
+ return out;
3741
+ }
3742
+ function collectCellAttrs(doc) {
3743
+ const result = /* @__PURE__ */ new Map();
3744
+ doc.descendants((node) => {
3745
+ if (node.type.name !== "blockContainer") {
3746
+ return void 0;
3747
+ }
3748
+ const id = node.attrs?.id;
3749
+ const table = node.firstChild;
3750
+ if (!id || table?.type.name !== "table") {
3751
+ return void 0;
3752
+ }
3753
+ const cells = /* @__PURE__ */ new Map();
3754
+ let rowIndex = 0;
3755
+ table.forEach((rowNode) => {
3756
+ if (rowNode.type.name === "tableRow") {
3757
+ let cellIndex = 0;
3758
+ rowNode.forEach((cellNode) => {
3759
+ const attrs = meaningfulAttrs(cellNode);
3760
+ if (attrs) {
3761
+ cells.set(`${rowIndex}:${cellIndex}`, attrs);
3762
+ }
3763
+ cellIndex++;
3764
+ });
3765
+ rowIndex++;
3766
+ }
3767
+ });
3768
+ if (cells.size > 0) {
3769
+ result.set(id, cells);
3770
+ }
3771
+ return false;
3772
+ });
3773
+ return result;
3774
+ }
3775
+ function tableCellAttrPreserve() {
3776
+ return new import_prosemirror_state4.Plugin({
3777
+ key: tableCellAttrPreserveKey,
3778
+ appendTransaction(transactions, oldState, newState) {
3779
+ if (!transactions.some((tr2) => tr2.docChanged)) {
3780
+ return null;
3781
+ }
3782
+ const oldMap = collectCellAttrs(oldState.doc);
3783
+ if (oldMap.size === 0) {
3784
+ return null;
3785
+ }
3786
+ const tr = newState.tr;
3787
+ let changed = false;
3788
+ let curTableCells = null;
3789
+ let curRowIndex = -1;
3790
+ let curCellIndex = 0;
3791
+ newState.doc.descendants((node, pos) => {
3792
+ const name = node.type.name;
3793
+ if (name === "blockContainer") {
3794
+ const id = node.attrs?.id;
3795
+ const table = node.firstChild;
3796
+ if (id && table?.type.name === "table" && oldMap.has(id)) {
3797
+ curTableCells = oldMap.get(id);
3798
+ curRowIndex = -1;
3799
+ } else {
3800
+ curTableCells = null;
3801
+ }
3802
+ return void 0;
3803
+ }
3804
+ if (!curTableCells) {
3805
+ return void 0;
3806
+ }
3807
+ if (name === "tableRow") {
3808
+ curRowIndex++;
3809
+ curCellIndex = 0;
3810
+ return void 0;
3811
+ }
3812
+ if (name === "tableCell" || name === "tableHeader") {
3813
+ const wanted = curTableCells.get(`${curRowIndex}:${curCellIndex}`);
3814
+ curCellIndex++;
3815
+ if (wanted) {
3816
+ const patch = {};
3817
+ let needs = false;
3818
+ for (const { name: attrName, default: def } of PRESERVED_ATTRS) {
3819
+ if (!(attrName in wanted)) {
3820
+ continue;
3821
+ }
3822
+ const cur = node.attrs?.[attrName];
3823
+ if (cur === null || cur === void 0 || cur === def) {
3824
+ patch[attrName] = wanted[attrName];
3825
+ needs = true;
3826
+ }
3827
+ }
3828
+ if (needs) {
3829
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, ...patch });
3830
+ changed = true;
3831
+ }
3832
+ }
3833
+ return false;
3834
+ }
3835
+ return void 0;
3836
+ });
3837
+ return changed ? tr : null;
3838
+ }
3839
+ });
3840
+ }
3841
+
3842
+ // src/extensions/RowHeightExtension.ts
3843
+ var RowHeightExtension = import_core5.Extension.create({
3844
+ name: "rowHeight",
3845
+ addOptions() {
3846
+ return { resizable: true };
3847
+ },
3848
+ addGlobalAttributes() {
3849
+ return [
3850
+ {
3851
+ types: ["tableCell", "tableHeader"],
3852
+ attributes: {
3853
+ rowHeight: {
3854
+ default: null,
3855
+ parseHTML: (element) => {
3856
+ const fromStyle = parseInt(element.style?.height ?? "", 10);
3857
+ if (Number.isFinite(fromStyle) && fromStyle > 0) {
3858
+ return fromStyle;
3859
+ }
3860
+ const fromAttr = parseInt(
3861
+ element.getAttribute("data-row-height") ?? "",
3862
+ 10
3863
+ );
3864
+ return Number.isFinite(fromAttr) && fromAttr > 0 ? fromAttr : null;
3865
+ },
3866
+ renderHTML: (attributes) => {
3867
+ const h = attributes.rowHeight;
3868
+ if (!h || typeof h !== "number") {
3869
+ return {};
3870
+ }
3871
+ return { style: `height: ${h}px` };
3872
+ }
3873
+ }
3874
+ }
3875
+ }
3876
+ ];
3877
+ },
3878
+ addProseMirrorPlugins() {
3879
+ const plugins = [tableCellAttrPreserve()];
3880
+ if (this.options.resizable) {
3881
+ plugins.push(rowResizing());
3882
+ }
3883
+ return plugins;
3884
+ }
3885
+ });
3886
+
3887
+ // src/extensions/TableAlignmentExtension.ts
3888
+ var import_core6 = require("@tiptap/core");
3889
+ var import_prosemirror_state5 = require("prosemirror-state");
3890
+ var import_prosemirror_view3 = require("prosemirror-view");
3891
+ var tableAlignmentDecoKey = new import_prosemirror_state5.PluginKey("lumirTableAlignmentDeco");
3892
+ function tableAlignmentDecorationPlugin() {
3893
+ return new import_prosemirror_state5.Plugin({
3894
+ key: tableAlignmentDecoKey,
3895
+ props: {
3896
+ decorations(state) {
3897
+ const decorations = [];
3898
+ state.doc.descendants((node, pos) => {
3899
+ if (node.type.name === "table") {
3900
+ const align = node.attrs.tableAlignment;
3901
+ if (align && align !== "left") {
3902
+ decorations.push(
3903
+ import_prosemirror_view3.Decoration.node(pos, pos + node.nodeSize, {
3904
+ "data-table-alignment": align
3905
+ })
3906
+ );
3907
+ }
3908
+ return false;
3909
+ }
3910
+ return void 0;
3911
+ });
3912
+ return import_prosemirror_view3.DecorationSet.create(state.doc, decorations);
3913
+ }
3914
+ }
3915
+ });
3916
+ }
3917
+ var TableAlignmentExtension = import_core6.Extension.create({
3918
+ name: "tableAlignment",
3919
+ addGlobalAttributes() {
3920
+ return [
3921
+ {
3922
+ types: ["table"],
3923
+ attributes: {
3924
+ tableAlignment: {
3925
+ default: "left",
3926
+ parseHTML: (element) => element.getAttribute("data-table-alignment") || "left",
3927
+ renderHTML: (attributes) => {
3928
+ if (!attributes.tableAlignment || attributes.tableAlignment === "left") {
3929
+ return {};
3930
+ }
3931
+ return { "data-table-alignment": attributes.tableAlignment };
3932
+ }
3933
+ }
3934
+ }
3935
+ }
3936
+ ];
3937
+ },
3938
+ addProseMirrorPlugins() {
3939
+ return [tableAlignmentDecorationPlugin()];
3940
+ }
3941
+ });
3942
+
3943
+ // src/blocks/columns/insertColumns.ts
3944
+ var import_prosemirror_state6 = require("prosemirror-state");
3945
+ function insertTwoColumns(editor) {
3946
+ const tiptap = editor?._tiptapEditor;
3947
+ if (!tiptap) {
3948
+ return false;
3949
+ }
3950
+ const { state, schema: schema2 } = tiptap;
3951
+ const { blockContainer, paragraph, column, columnList } = schema2.nodes;
3952
+ if (!blockContainer || !paragraph || !column || !columnList) {
3953
+ return false;
3954
+ }
3955
+ const $from = state.selection.$from;
3956
+ for (let d = $from.depth; d > 0; d--) {
3957
+ const name = $from.node(d).type.name;
3958
+ if (name === "column" || name === "columnList") {
3959
+ return false;
3960
+ }
3961
+ }
3962
+ let depth = $from.depth;
3963
+ while (depth > 0 && $from.node(depth).type.name !== "blockContainer") {
3964
+ depth--;
3965
+ }
3966
+ if (depth === 0) {
3967
+ return false;
3968
+ }
3969
+ const insertPos = $from.after(depth);
3970
+ const mkBlock = () => blockContainer.create(null, paragraph.create());
3971
+ const mkColumn = () => column.create(null, mkBlock());
3972
+ const list = columnList.create(null, [mkColumn(), mkColumn()]);
3973
+ try {
3974
+ let tr = state.tr.insert(insertPos, list);
3975
+ try {
3976
+ tr = tr.setSelection(import_prosemirror_state6.TextSelection.create(tr.doc, insertPos + 4));
3977
+ } catch {
3978
+ }
3979
+ tiptap.view.dispatch(tr.scrollIntoView());
3980
+ return true;
3981
+ } catch {
3982
+ return false;
3983
+ }
3984
+ }
3985
+
3986
+ // src/components/CustomFormattingToolbar.tsx
3987
+ var import_react30 = require("@blocknote/react");
3988
+
3989
+ // src/components/TextAlignButtonWithVA.tsx
3990
+ var import_core7 = require("@blocknote/core");
3991
+ var import_react20 = require("react");
3992
+ var import_react21 = require("@blocknote/react");
3993
+ var import_jsx_runtime19 = require("react/jsx-runtime");
3994
+ var icons = {
3995
+ left: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z" }) }),
3996
+ center: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z" }) }),
3997
+ right: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z" }) }),
3998
+ justify: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("path", { d: "M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zM3 3v2h18V3H3z" }) })
3999
+ };
4000
+ var tooltipMap = {
4001
+ left: "\uC67C\uCABD \uC815\uB82C",
4002
+ center: "\uAC00\uC6B4\uB370 \uC815\uB82C",
4003
+ right: "\uC624\uB978\uCABD \uC815\uB82C",
4004
+ justify: "\uC591\uCABD \uC815\uB82C"
4005
+ };
4006
+ var TextAlignButtonWithVA = (props) => {
4007
+ const Components = (0, import_react21.useComponentsContext)();
4008
+ const editor = (0, import_react21.useBlockNoteEditor)();
4009
+ const selectedBlocks = (0, import_react21.useSelectedBlocks)(editor);
4010
+ const textAlignment = (0, import_react20.useMemo)(() => {
4011
+ const block = selectedBlocks[0];
4012
+ if ((0, import_core7.checkBlockHasDefaultProp)("textAlignment", block, editor)) {
4013
+ return block.props.textAlignment;
4014
+ }
4015
+ if (block.type === "table") {
4016
+ const cellSelection = editor.tableHandles?.getCellSelection();
4017
+ if (!cellSelection) {
4018
+ return;
4019
+ }
4020
+ const allCellsInTable = cellSelection.cells.map(
4021
+ ({ row, col }) => (0, import_core7.mapTableCell)(
4022
+ block.content.rows[row].cells[col]
4023
+ ).props.textAlignment
4024
+ );
4025
+ const firstAlignment = allCellsInTable[0];
4026
+ if (allCellsInTable.every((alignment) => alignment === firstAlignment)) {
4027
+ return firstAlignment;
4028
+ }
4029
+ }
4030
+ return;
4031
+ }, [editor, selectedBlocks]);
4032
+ const setTextAlignment = (0, import_react20.useCallback)(
4033
+ (newAlignment) => {
4034
+ editor.focus();
4035
+ for (const block of selectedBlocks) {
4036
+ if (block.type === "table") {
4037
+ const tiptap = editor._tiptapEditor;
4038
+ if (!tiptap) continue;
4039
+ const positions = getSelectedCellPositions(editor);
4040
+ if (positions.length === 0) continue;
4041
+ const { state } = tiptap;
4042
+ let tr = state.tr;
4043
+ for (const pos of positions) {
4044
+ const node = tr.doc.nodeAt(pos);
4045
+ if (node) {
4046
+ tr = tr.setNodeMarkup(pos, void 0, {
4047
+ ...node.attrs,
4048
+ textAlignment: newAlignment
4049
+ });
4050
+ }
4051
+ }
4052
+ tiptap.view?.dispatch(tr);
4053
+ } else if ((0, import_core7.checkBlockTypeHasDefaultProp)("textAlignment", block.type, editor)) {
4054
+ editor.updateBlock(block, {
4055
+ props: { textAlignment: newAlignment }
4056
+ });
4057
+ }
4058
+ }
4059
+ },
4060
+ [editor, selectedBlocks]
4061
+ );
4062
+ const show = (0, import_react20.useMemo)(() => {
4063
+ return !!selectedBlocks.find(
4064
+ (block) => "textAlignment" in block.props || block.type === "table" && block.children
4065
+ );
4066
+ }, [selectedBlocks]);
4067
+ if (!show || !editor.isEditable) {
4068
+ return null;
4069
+ }
4070
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4071
+ Components.FormattingToolbar.Button,
4072
+ {
4073
+ className: "bn-button",
4074
+ "data-test": `alignText${props.textAlignment.slice(0, 1).toUpperCase() + props.textAlignment.slice(1)}`,
4075
+ onClick: () => setTextAlignment(props.textAlignment),
4076
+ isSelected: textAlignment === props.textAlignment,
4077
+ label: tooltipMap[props.textAlignment],
4078
+ mainTooltip: tooltipMap[props.textAlignment],
4079
+ icon: icons[props.textAlignment]
4080
+ }
4081
+ );
4082
+ };
4083
+
4084
+ // src/components/VerticalAlignButton.tsx
3165
4085
  var import_react22 = require("react");
3166
4086
  var import_react23 = require("@blocknote/react");
3167
4087
  var import_jsx_runtime20 = require("react/jsx-runtime");
@@ -3246,14 +4166,74 @@ var VerticalAlignButton = (props) => {
3246
4166
  );
3247
4167
  };
3248
4168
 
3249
- // src/components/FontSizeButton.tsx
3250
- var import_react24 = require("@blocknote/react");
3251
- var import_react25 = require("react");
4169
+ // src/components/TableAlignButton.tsx
4170
+ var import_react24 = require("react");
4171
+ var import_react25 = require("@blocknote/react");
3252
4172
  var import_jsx_runtime21 = require("react/jsx-runtime");
4173
+ var icons3 = {
4174
+ left: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", children: [
4175
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "1.5", y: "4", width: "7", height: "8", rx: "1", fill: "currentColor", stroke: "none" }),
4176
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("line", { x1: "1.5", y1: "1.5", x2: "14.5", y2: "1.5" }),
4177
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("line", { x1: "1.5", y1: "14.5", x2: "14.5", y2: "14.5" })
4178
+ ] }),
4179
+ center: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", children: [
4180
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "4.5", y: "4", width: "7", height: "8", rx: "1", fill: "currentColor", stroke: "none" }),
4181
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("line", { x1: "1.5", y1: "1.5", x2: "14.5", y2: "1.5" }),
4182
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("line", { x1: "1.5", y1: "14.5", x2: "14.5", y2: "14.5" })
4183
+ ] }),
4184
+ right: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", children: [
4185
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "7.5", y: "4", width: "7", height: "8", rx: "1", fill: "currentColor", stroke: "none" }),
4186
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("line", { x1: "1.5", y1: "1.5", x2: "14.5", y2: "1.5" }),
4187
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("line", { x1: "1.5", y1: "14.5", x2: "14.5", y2: "14.5" })
4188
+ ] })
4189
+ };
4190
+ var tooltips2 = {
4191
+ left: "\uD45C \uC67C\uCABD \uC815\uB82C",
4192
+ center: "\uD45C \uAC00\uC6B4\uB370 \uC815\uB82C",
4193
+ right: "\uD45C \uC624\uB978\uCABD \uC815\uB82C"
4194
+ };
4195
+ var TableAlignButton = (props) => {
4196
+ const Components = (0, import_react25.useComponentsContext)();
4197
+ const editor = (0, import_react25.useBlockNoteEditor)();
4198
+ const selectedBlocks = (0, import_react25.useSelectedBlocks)(editor);
4199
+ const tableBlock = (0, import_react24.useMemo)(
4200
+ () => selectedBlocks.find((block) => block.type === "table"),
4201
+ [selectedBlocks]
4202
+ );
4203
+ const current = (0, import_react24.useMemo)(() => {
4204
+ if (!tableBlock?.id) return "left";
4205
+ return getTableAlignment(editor, tableBlock.id);
4206
+ }, [editor, tableBlock, selectedBlocks]);
4207
+ const apply = (0, import_react24.useCallback)(() => {
4208
+ if (!tableBlock?.id) return;
4209
+ editor.focus();
4210
+ setTableAlignment(editor, tableBlock.id, props.alignment);
4211
+ }, [editor, tableBlock, props.alignment]);
4212
+ if (!tableBlock || !editor.isEditable) {
4213
+ return null;
4214
+ }
4215
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4216
+ Components.FormattingToolbar.Button,
4217
+ {
4218
+ className: "bn-button",
4219
+ "data-test": `tableAlign${props.alignment.charAt(0).toUpperCase() + props.alignment.slice(1)}`,
4220
+ onClick: apply,
4221
+ isSelected: current === props.alignment,
4222
+ label: tooltips2[props.alignment],
4223
+ mainTooltip: tooltips2[props.alignment],
4224
+ icon: icons3[props.alignment]
4225
+ }
4226
+ );
4227
+ };
4228
+
4229
+ // src/components/FontSizeButton.tsx
4230
+ var import_react26 = require("@blocknote/react");
4231
+ var import_react27 = require("react");
4232
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3253
4233
  var DEFAULT_LABEL2 = "\uAE30\uBCF8";
3254
4234
  var toLabel2 = (size) => size.replace(/px$/, "");
3255
4235
  function FontSizeIcon({ size }) {
3256
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4236
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3257
4237
  "span",
3258
4238
  {
3259
4239
  style: {
@@ -3268,21 +4248,21 @@ function FontSizeIcon({ size }) {
3268
4248
  );
3269
4249
  }
3270
4250
  function FontSizeButton2() {
3271
- const Components = (0, import_react24.useComponentsContext)();
3272
- const editor = (0, import_react24.useBlockNoteEditor)();
4251
+ const Components = (0, import_react26.useComponentsContext)();
4252
+ const editor = (0, import_react26.useBlockNoteEditor)();
3273
4253
  const ed = editor;
3274
4254
  const styleSchema = editor.schema.styleSchema;
3275
4255
  const fontSizeInSchema = styleSchema.fontSize?.type === "fontSize" && styleSchema.fontSize?.propSchema === "string";
3276
- const selectedBlocks = (0, import_react24.useSelectedBlocks)(editor);
3277
- const [currentSize, setCurrentSize] = (0, import_react25.useState)(
4256
+ const selectedBlocks = (0, import_react26.useSelectedBlocks)(editor);
4257
+ const [currentSize, setCurrentSize] = (0, import_react27.useState)(
3278
4258
  fontSizeInSchema ? ed.getActiveStyles().fontSize || "" : ""
3279
4259
  );
3280
- (0, import_react24.useEditorContentOrSelectionChange)(() => {
4260
+ (0, import_react26.useEditorContentOrSelectionChange)(() => {
3281
4261
  if (fontSizeInSchema) {
3282
4262
  setCurrentSize(ed.getActiveStyles().fontSize || "");
3283
4263
  }
3284
4264
  }, editor);
3285
- const setFontSize = (0, import_react25.useCallback)(
4265
+ const setFontSize = (0, import_react27.useCallback)(
3286
4266
  (size) => {
3287
4267
  size === "" ? ed.removeStyles({ fontSize: "" }) : ed.addStyles({ fontSize: size });
3288
4268
  setTimeout(() => editor.focus());
@@ -3290,7 +4270,7 @@ function FontSizeButton2() {
3290
4270
  // eslint-disable-next-line react-hooks/exhaustive-deps
3291
4271
  [editor]
3292
4272
  );
3293
- const show = (0, import_react25.useMemo)(() => {
4273
+ const show = (0, import_react27.useMemo)(() => {
3294
4274
  if (!fontSizeInSchema) {
3295
4275
  return false;
3296
4276
  }
@@ -3305,20 +4285,20 @@ function FontSizeButton2() {
3305
4285
  return null;
3306
4286
  }
3307
4287
  const tooltip = "\uAE00\uC790 \uD06C\uAE30";
3308
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Components.Generic.Menu.Root, { children: [
3309
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4288
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Components.Generic.Menu.Root, { children: [
4289
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3310
4290
  Components.FormattingToolbar.Button,
3311
4291
  {
3312
4292
  className: "bn-button",
3313
4293
  "data-test": "font-size",
3314
4294
  label: tooltip,
3315
4295
  mainTooltip: tooltip,
3316
- icon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FontSizeIcon, { size: currentSize })
4296
+ icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FontSizeIcon, { size: currentSize })
3317
4297
  }
3318
4298
  ) }),
3319
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Components.Generic.Menu.Dropdown, { className: "bn-menu-dropdown", children: [
3320
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Components.Generic.Menu.Label, { children: "\uAE00\uC790 \uD06C\uAE30" }),
3321
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4299
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Components.Generic.Menu.Dropdown, { className: "bn-menu-dropdown", children: [
4300
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Label, { children: "\uAE00\uC790 \uD06C\uAE30" }),
4301
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3322
4302
  Components.Generic.Menu.Item,
3323
4303
  {
3324
4304
  onClick: () => setFontSize(""),
@@ -3328,7 +4308,7 @@ function FontSizeButton2() {
3328
4308
  },
3329
4309
  "font-size-default"
3330
4310
  ),
3331
- FONT_SIZE_PRESETS.map((size) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4311
+ FONT_SIZE_PRESETS.map((size) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3332
4312
  Components.Generic.Menu.Item,
3333
4313
  {
3334
4314
  onClick: () => setFontSize(size),
@@ -3343,10 +4323,10 @@ function FontSizeButton2() {
3343
4323
  }
3344
4324
 
3345
4325
  // src/components/color/LumirColorControls.tsx
3346
- var import_core4 = require("@blocknote/core");
3347
- var import_react26 = require("@blocknote/react");
3348
- var import_react27 = require("react");
3349
- var import_jsx_runtime22 = require("react/jsx-runtime");
4326
+ var import_core8 = require("@blocknote/core");
4327
+ var import_react28 = require("@blocknote/react");
4328
+ var import_react29 = require("react");
4329
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3350
4330
  var COLORS = [
3351
4331
  "default",
3352
4332
  "gray",
@@ -3363,7 +4343,7 @@ function ColorIcon(props) {
3363
4343
  const textColor = props.textColor || "default";
3364
4344
  const backgroundColor = props.backgroundColor || "default";
3365
4345
  const size = props.size || 16;
3366
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4346
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3367
4347
  "div",
3368
4348
  {
3369
4349
  className: "bn-color-icon",
@@ -3382,7 +4362,7 @@ function ColorIcon(props) {
3382
4362
  );
3383
4363
  }
3384
4364
  function CellFillIcon({ size = 18 }) {
3385
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4365
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3386
4366
  "svg",
3387
4367
  {
3388
4368
  width: size,
@@ -3391,17 +4371,17 @@ function CellFillIcon({ size = 18 }) {
3391
4371
  fill: "currentColor",
3392
4372
  style: { pointerEvents: "none" },
3393
4373
  "aria-hidden": "true",
3394
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("path", { d: "M16.56 8.94 7.62 0 6.21 1.41l2.38 2.38-5.15 5.15c-.59.59-.59 1.54 0 2.12l5.5 5.5c.29.29.68.44 1.06.44s.77-.15 1.06-.44l5.5-5.5c.59-.58.59-1.53 0-2.12zM5.21 10 10 5.21 14.79 10H5.21zM19 11.5s-2 2.17-2 3.5c0 1.1.9 2 2 2s2-.9 2-2c0-1.33-2-3.5-2-3.5z" })
4374
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("path", { d: "M16.56 8.94 7.62 0 6.21 1.41l2.38 2.38-5.15 5.15c-.59.59-.59 1.54 0 2.12l5.5 5.5c.29.29.68.44 1.06.44s.77-.15 1.06-.44l5.5-5.5c.59-.58.59-1.53 0-2.12zM5.21 10 10 5.21 14.79 10H5.21zM19 11.5s-2 2.17-2 3.5c0 1.1.9 2 2 2s2-.9 2-2c0-1.33-2-3.5-2-3.5z" })
3395
4375
  }
3396
4376
  );
3397
4377
  }
3398
4378
  function LumirColorPicker(props) {
3399
- const Components = (0, import_react26.useComponentsContext)();
3400
- const dict = (0, import_react26.useDictionary)();
3401
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3402
- props.text ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3403
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Label, { children: props.textTitle ?? dict.color_picker.text_title }),
3404
- COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4379
+ const Components = (0, import_react28.useComponentsContext)();
4380
+ const dict = (0, import_react28.useDictionary)();
4381
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
4382
+ props.text ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
4383
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Components.Generic.Menu.Label, { children: props.textTitle ?? dict.color_picker.text_title }),
4384
+ COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3405
4385
  Components.Generic.Menu.Item,
3406
4386
  {
3407
4387
  onClick: () => {
@@ -3409,16 +4389,16 @@ function LumirColorPicker(props) {
3409
4389
  props.text.setColor(color);
3410
4390
  },
3411
4391
  "data-test": "text-color-" + color,
3412
- icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ColorIcon, { textColor: color, size: props.iconSize }),
4392
+ icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ColorIcon, { textColor: color, size: props.iconSize }),
3413
4393
  checked: props.text.color === color,
3414
4394
  children: dict.color_picker.colors[color]
3415
4395
  },
3416
4396
  "text-color-" + color
3417
4397
  ))
3418
4398
  ] }) : null,
3419
- props.background ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3420
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Label, { children: props.backgroundTitle ?? dict.color_picker.background_title }),
3421
- COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4399
+ props.background ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
4400
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Components.Generic.Menu.Label, { children: props.backgroundTitle ?? dict.color_picker.background_title }),
4401
+ COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3422
4402
  Components.Generic.Menu.Item,
3423
4403
  {
3424
4404
  onClick: () => {
@@ -3426,7 +4406,7 @@ function LumirColorPicker(props) {
3426
4406
  props.background.setColor(color);
3427
4407
  },
3428
4408
  "data-test": "background-color-" + color,
3429
- icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ColorIcon, { backgroundColor: color, size: props.iconSize }),
4409
+ icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ColorIcon, { backgroundColor: color, size: props.iconSize }),
3430
4410
  checked: props.background.color === color,
3431
4411
  children: dict.color_picker.colors[color]
3432
4412
  },
@@ -3436,20 +4416,20 @@ function LumirColorPicker(props) {
3436
4416
  ] });
3437
4417
  }
3438
4418
  function LumirColorStyleButton() {
3439
- const Components = (0, import_react26.useComponentsContext)();
3440
- const editor = (0, import_react26.useBlockNoteEditor)();
4419
+ const Components = (0, import_react28.useComponentsContext)();
4420
+ const editor = (0, import_react28.useBlockNoteEditor)();
3441
4421
  const ed = editor;
3442
4422
  const styleSchema = editor.schema.styleSchema;
3443
4423
  const textColorInSchema = styleSchema.textColor?.type === "textColor" && styleSchema.textColor?.propSchema === "string";
3444
4424
  const backgroundColorInSchema = styleSchema.backgroundColor?.type === "backgroundColor" && styleSchema.backgroundColor?.propSchema === "string";
3445
- const selectedBlocks = (0, import_react26.useSelectedBlocks)(editor);
3446
- const [currentTextColor, setCurrentTextColor] = (0, import_react27.useState)(
4425
+ const selectedBlocks = (0, import_react28.useSelectedBlocks)(editor);
4426
+ const [currentTextColor, setCurrentTextColor] = (0, import_react29.useState)(
3447
4427
  textColorInSchema ? ed.getActiveStyles().textColor || "default" : "default"
3448
4428
  );
3449
- const [currentBackgroundColor, setCurrentBackgroundColor] = (0, import_react27.useState)(
4429
+ const [currentBackgroundColor, setCurrentBackgroundColor] = (0, import_react29.useState)(
3450
4430
  backgroundColorInSchema ? ed.getActiveStyles().backgroundColor || "default" : "default"
3451
4431
  );
3452
- (0, import_react26.useEditorContentOrSelectionChange)(() => {
4432
+ (0, import_react28.useEditorContentOrSelectionChange)(() => {
3453
4433
  const active = ed.getActiveStyles();
3454
4434
  if (textColorInSchema) {
3455
4435
  setCurrentTextColor(active.textColor || "default");
@@ -3458,7 +4438,7 @@ function LumirColorStyleButton() {
3458
4438
  setCurrentBackgroundColor(active.backgroundColor || "default");
3459
4439
  }
3460
4440
  }, editor);
3461
- const setTextColor = (0, import_react27.useCallback)(
4441
+ const setTextColor = (0, import_react29.useCallback)(
3462
4442
  (color) => {
3463
4443
  color === "default" ? ed.removeStyles({ textColor: color }) : ed.addStyles({ textColor: color });
3464
4444
  setTimeout(() => editor.focus());
@@ -3466,7 +4446,7 @@ function LumirColorStyleButton() {
3466
4446
  // eslint-disable-next-line react-hooks/exhaustive-deps
3467
4447
  [editor]
3468
4448
  );
3469
- const setBackgroundColor = (0, import_react27.useCallback)(
4449
+ const setBackgroundColor = (0, import_react29.useCallback)(
3470
4450
  (color) => {
3471
4451
  color === "default" ? ed.removeStyles({ backgroundColor: color }) : ed.addStyles({ backgroundColor: color });
3472
4452
  setTimeout(() => editor.focus());
@@ -3474,7 +4454,7 @@ function LumirColorStyleButton() {
3474
4454
  // eslint-disable-next-line react-hooks/exhaustive-deps
3475
4455
  [editor]
3476
4456
  );
3477
- const show = (0, import_react27.useMemo)(() => {
4457
+ const show = (0, import_react29.useMemo)(() => {
3478
4458
  if (!textColorInSchema && !backgroundColorInSchema) {
3479
4459
  return false;
3480
4460
  }
@@ -3489,15 +4469,15 @@ function LumirColorStyleButton() {
3489
4469
  return null;
3490
4470
  }
3491
4471
  const tooltip = "\uD14D\uC2A4\uD2B8 \uC0C9\xB7\uBC30\uACBD";
3492
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Components.Generic.Menu.Root, { children: [
3493
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4472
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Components.Generic.Menu.Root, { children: [
4473
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3494
4474
  Components.FormattingToolbar.Button,
3495
4475
  {
3496
4476
  className: "bn-button",
3497
4477
  "data-test": "colors",
3498
4478
  label: tooltip,
3499
4479
  mainTooltip: tooltip,
3500
- icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4480
+ icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3501
4481
  ColorIcon,
3502
4482
  {
3503
4483
  textColor: currentTextColor,
@@ -3507,11 +4487,11 @@ function LumirColorStyleButton() {
3507
4487
  )
3508
4488
  }
3509
4489
  ) }),
3510
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4490
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3511
4491
  Components.Generic.Menu.Dropdown,
3512
4492
  {
3513
4493
  className: "bn-menu-dropdown bn-color-picker-dropdown",
3514
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4494
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3515
4495
  LumirColorPicker,
3516
4496
  {
3517
4497
  textTitle: "\uD14D\uC2A4\uD2B8 \uC0C9",
@@ -3525,18 +4505,18 @@ function LumirColorStyleButton() {
3525
4505
  ] });
3526
4506
  }
3527
4507
  function LumirCellColorToolbarButton() {
3528
- const Components = (0, import_react26.useComponentsContext)();
3529
- const editor = (0, import_react26.useBlockNoteEditor)();
3530
- const selectedBlocks = (0, import_react26.useSelectedBlocks)(editor);
3531
- const isMultiCell = (0, import_react27.useMemo)(() => {
4508
+ const Components = (0, import_react28.useComponentsContext)();
4509
+ const editor = (0, import_react28.useBlockNoteEditor)();
4510
+ const selectedBlocks = (0, import_react28.useSelectedBlocks)(editor);
4511
+ const isMultiCell = (0, import_react29.useMemo)(() => {
3532
4512
  if (selectedBlocks.length !== 1 || selectedBlocks[0].type !== "table") {
3533
4513
  return false;
3534
4514
  }
3535
4515
  const cs = editor.tableHandles?.getCellSelection();
3536
4516
  return !!cs && cs.cells.length > 1;
3537
4517
  }, [editor, selectedBlocks]);
3538
- const stashRef = (0, import_react27.useRef)([]);
3539
- const applyBackground = (0, import_react27.useCallback)(
4518
+ const stashRef = (0, import_react29.useRef)([]);
4519
+ const applyBackground = (0, import_react29.useCallback)(
3540
4520
  (color) => {
3541
4521
  const live = getSelectedCellPositions(editor);
3542
4522
  const positions = live.length > 0 ? live : stashRef.current;
@@ -3549,7 +4529,7 @@ function LumirCellColorToolbarButton() {
3549
4529
  return null;
3550
4530
  }
3551
4531
  const tooltip = "\uC140 \uBC30\uACBD\uC0C9";
3552
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4532
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3553
4533
  Components.Generic.Menu.Root,
3554
4534
  {
3555
4535
  onOpenChange: (open) => {
@@ -3558,21 +4538,21 @@ function LumirCellColorToolbarButton() {
3558
4538
  }
3559
4539
  },
3560
4540
  children: [
3561
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4541
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3562
4542
  Components.FormattingToolbar.Button,
3563
4543
  {
3564
4544
  className: "bn-button",
3565
4545
  "data-test": "cell-colors",
3566
4546
  label: tooltip,
3567
4547
  mainTooltip: tooltip,
3568
- icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CellFillIcon, { size: 18 })
4548
+ icon: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CellFillIcon, { size: 18 })
3569
4549
  }
3570
4550
  ) }),
3571
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4551
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3572
4552
  Components.Generic.Menu.Dropdown,
3573
4553
  {
3574
4554
  className: "bn-menu-dropdown bn-color-picker-dropdown",
3575
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4555
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3576
4556
  LumirColorPicker,
3577
4557
  {
3578
4558
  backgroundTitle: "\uC140 \uBC30\uACBD",
@@ -3586,12 +4566,12 @@ function LumirCellColorToolbarButton() {
3586
4566
  );
3587
4567
  }
3588
4568
  function LumirCellColorPickerButton(props) {
3589
- const Components = (0, import_react26.useComponentsContext)();
3590
- const editor = (0, import_react26.useBlockNoteEditor)();
4569
+ const Components = (0, import_react28.useComponentsContext)();
4570
+ const editor = (0, import_react28.useBlockNoteEditor)();
3591
4571
  const updateColor = (color, type) => {
3592
4572
  const newTable = props.block.content.rows.map((row) => ({
3593
4573
  ...row,
3594
- cells: row.cells.map((cell) => (0, import_core4.mapTableCell)(cell))
4574
+ cells: row.cells.map((cell) => (0, import_core8.mapTableCell)(cell))
3595
4575
  }));
3596
4576
  if (type === "text") {
3597
4577
  newTable[props.rowIndex].cells[props.colIndex].props.textColor = color;
@@ -3608,25 +4588,25 @@ function LumirCellColorPickerButton(props) {
3608
4588
  if (!currentCell || editor.settings.tables.cellTextColor === false && editor.settings.tables.cellBackgroundColor === false) {
3609
4589
  return null;
3610
4590
  }
3611
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Components.Generic.Menu.Root, { position: "right", sub: true, children: [
3612
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Trigger, { sub: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Components.Generic.Menu.Item, { className: "bn-menu-item", subTrigger: true, children: "\uC140 \uC0C9\xB7\uBC30\uACBD" }) }),
3613
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4591
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Components.Generic.Menu.Root, { position: "right", sub: true, children: [
4592
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Components.Generic.Menu.Trigger, { sub: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Components.Generic.Menu.Item, { className: "bn-menu-item", subTrigger: true, children: "\uC140 \uC0C9\xB7\uBC30\uACBD" }) }),
4593
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3614
4594
  Components.Generic.Menu.Dropdown,
3615
4595
  {
3616
4596
  sub: true,
3617
4597
  className: "bn-menu-dropdown bn-color-picker-dropdown",
3618
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4598
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3619
4599
  LumirColorPicker,
3620
4600
  {
3621
4601
  iconSize: 18,
3622
4602
  textTitle: "\uC140 \uAE00\uC790\uC0C9",
3623
4603
  backgroundTitle: "\uC140 \uBC30\uACBD",
3624
4604
  text: editor.settings.tables.cellTextColor ? {
3625
- color: (0, import_core4.isTableCell)(currentCell) ? currentCell.props.textColor : "default",
4605
+ color: (0, import_core8.isTableCell)(currentCell) ? currentCell.props.textColor : "default",
3626
4606
  setColor: (color) => updateColor(color, "text")
3627
4607
  } : void 0,
3628
4608
  background: editor.settings.tables.cellBackgroundColor ? {
3629
- color: (0, import_core4.isTableCell)(currentCell) ? currentCell.props.backgroundColor : "default",
4609
+ color: (0, import_core8.isTableCell)(currentCell) ? currentCell.props.backgroundColor : "default",
3630
4610
  setColor: (color) => updateColor(color, "background")
3631
4611
  } : void 0
3632
4612
  }
@@ -3636,21 +4616,21 @@ function LumirCellColorPickerButton(props) {
3636
4616
  ] });
3637
4617
  }
3638
4618
  function LumirTableCellMenu(props) {
3639
- const Components = (0, import_react26.useComponentsContext)();
3640
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4619
+ const Components = (0, import_react28.useComponentsContext)();
4620
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3641
4621
  Components.Generic.Menu.Dropdown,
3642
4622
  {
3643
4623
  className: "bn-menu-dropdown bn-drag-handle-menu",
3644
- children: props.children || /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3645
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3646
- import_react26.SplitButton,
4624
+ children: props.children || /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
4625
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4626
+ import_react28.SplitButton,
3647
4627
  {
3648
4628
  block: props.block,
3649
4629
  rowIndex: props.rowIndex,
3650
4630
  colIndex: props.colIndex
3651
4631
  }
3652
4632
  ),
3653
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4633
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3654
4634
  LumirCellColorPickerButton,
3655
4635
  {
3656
4636
  block: props.block,
@@ -3664,96 +4644,164 @@ function LumirTableCellMenu(props) {
3664
4644
  }
3665
4645
 
3666
4646
  // src/components/CustomFormattingToolbar.tsx
3667
- var import_jsx_runtime23 = require("react/jsx-runtime");
4647
+ var import_jsx_runtime24 = require("react/jsx-runtime");
3668
4648
  var CustomFormattingToolbar = () => {
3669
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react28.FormattingToolbar, { children: [
3670
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.BlockTypeSelect, {}, "blockTypeSelect"),
3671
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.TableCellMergeButton, {}, "tableCellMergeButton"),
3672
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.FileCaptionButton, {}, "fileCaptionButton"),
3673
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.FileReplaceButton, {}, "replaceFileButton"),
3674
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.FileRenameButton, {}, "fileRenameButton"),
3675
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.FileDeleteButton, {}, "fileDeleteButton"),
3676
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.FileDownloadButton, {}, "fileDownloadButton"),
3677
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.FilePreviewButton, {}, "filePreviewButton"),
3678
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.BasicTextStyleButton, { basicTextStyle: "bold" }, "boldStyleButton"),
3679
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3680
- import_react28.BasicTextStyleButton,
4649
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react30.FormattingToolbar, { children: [
4650
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.BlockTypeSelect, {}, "blockTypeSelect"),
4651
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.TableCellMergeButton, {}, "tableCellMergeButton"),
4652
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.FileCaptionButton, {}, "fileCaptionButton"),
4653
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.FileReplaceButton, {}, "replaceFileButton"),
4654
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.FileRenameButton, {}, "fileRenameButton"),
4655
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.FileDeleteButton, {}, "fileDeleteButton"),
4656
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.FileDownloadButton, {}, "fileDownloadButton"),
4657
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.FilePreviewButton, {}, "filePreviewButton"),
4658
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.BasicTextStyleButton, { basicTextStyle: "bold" }, "boldStyleButton"),
4659
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4660
+ import_react30.BasicTextStyleButton,
3681
4661
  {
3682
4662
  basicTextStyle: "italic"
3683
4663
  },
3684
4664
  "italicStyleButton"
3685
4665
  ),
3686
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3687
- import_react28.BasicTextStyleButton,
4666
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4667
+ import_react30.BasicTextStyleButton,
3688
4668
  {
3689
4669
  basicTextStyle: "underline"
3690
4670
  },
3691
4671
  "underlineStyleButton"
3692
4672
  ),
3693
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3694
- import_react28.BasicTextStyleButton,
4673
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4674
+ import_react30.BasicTextStyleButton,
3695
4675
  {
3696
4676
  basicTextStyle: "strike"
3697
4677
  },
3698
4678
  "strikeStyleButton"
3699
4679
  ),
3700
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TextAlignButtonWithVA, { textAlignment: "left" }, "textAlignLeftButton"),
3701
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4680
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TextAlignButtonWithVA, { textAlignment: "left" }, "textAlignLeftButton"),
4681
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3702
4682
  TextAlignButtonWithVA,
3703
4683
  {
3704
4684
  textAlignment: "center"
3705
4685
  },
3706
4686
  "textAlignCenterButton"
3707
4687
  ),
3708
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TextAlignButtonWithVA, { textAlignment: "right" }, "textAlignRightButton"),
3709
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4688
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TextAlignButtonWithVA, { textAlignment: "right" }, "textAlignRightButton"),
4689
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3710
4690
  VerticalAlignButton,
3711
4691
  {
3712
4692
  verticalAlignment: "top"
3713
4693
  },
3714
4694
  "verticalAlignTop"
3715
4695
  ),
3716
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4696
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3717
4697
  VerticalAlignButton,
3718
4698
  {
3719
4699
  verticalAlignment: "middle"
3720
4700
  },
3721
4701
  "verticalAlignMiddle"
3722
4702
  ),
3723
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4703
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3724
4704
  VerticalAlignButton,
3725
4705
  {
3726
4706
  verticalAlignment: "bottom"
3727
4707
  },
3728
4708
  "verticalAlignBottom"
3729
4709
  ),
3730
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FontSizeButton2, {}, "fontSizeButton"),
3731
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LumirColorStyleButton, {}, "colorStyleButton"),
3732
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LumirCellColorToolbarButton, {}, "cellColorButton"),
3733
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.NestBlockButton, {}, "nestBlockButton"),
3734
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.UnnestBlockButton, {}, "unnestBlockButton"),
3735
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react28.CreateLinkButton, {}, "createLinkButton")
4710
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TableAlignButton, { alignment: "left" }, "tableAlignLeft"),
4711
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TableAlignButton, { alignment: "center" }, "tableAlignCenter"),
4712
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(TableAlignButton, { alignment: "right" }, "tableAlignRight"),
4713
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(FontSizeButton2, {}, "fontSizeButton"),
4714
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(LumirColorStyleButton, {}, "colorStyleButton"),
4715
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(LumirCellColorToolbarButton, {}, "cellColorButton"),
4716
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.NestBlockButton, {}, "nestBlockButton"),
4717
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.UnnestBlockButton, {}, "unnestBlockButton"),
4718
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react30.CreateLinkButton, {}, "createLinkButton")
3736
4719
  ] });
3737
4720
  };
3738
4721
 
3739
- // src/components/LumirTableHandlesController.tsx
4722
+ // src/components/LumirDragHandleMenu.tsx
3740
4723
  var import_react31 = require("@blocknote/react");
3741
- var import_react32 = require("@floating-ui/react");
3742
- var import_react33 = require("react");
4724
+ var import_jsx_runtime25 = require("react/jsx-runtime");
4725
+ var TABLE_ALIGN_ICONS = {
4726
+ left: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", children: [
4727
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("rect", { x: "1.5", y: "4", width: "7", height: "8", rx: "1", fill: "currentColor", stroke: "none" }),
4728
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("line", { x1: "1.5", y1: "1.5", x2: "14.5", y2: "1.5" }),
4729
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("line", { x1: "1.5", y1: "14.5", x2: "14.5", y2: "14.5" })
4730
+ ] }),
4731
+ center: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", children: [
4732
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("rect", { x: "4.5", y: "4", width: "7", height: "8", rx: "1", fill: "currentColor", stroke: "none" }),
4733
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("line", { x1: "1.5", y1: "1.5", x2: "14.5", y2: "1.5" }),
4734
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("line", { x1: "1.5", y1: "14.5", x2: "14.5", y2: "14.5" })
4735
+ ] }),
4736
+ right: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.4", children: [
4737
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("rect", { x: "7.5", y: "4", width: "7", height: "8", rx: "1", fill: "currentColor", stroke: "none" }),
4738
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("line", { x1: "1.5", y1: "1.5", x2: "14.5", y2: "1.5" }),
4739
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("line", { x1: "1.5", y1: "14.5", x2: "14.5", y2: "14.5" })
4740
+ ] })
4741
+ };
4742
+ var TABLE_ALIGN_LABELS = {
4743
+ left: "\uD45C \uC67C\uCABD \uC815\uB82C",
4744
+ center: "\uD45C \uAC00\uC6B4\uB370 \uC815\uB82C",
4745
+ right: "\uD45C \uC624\uB978\uCABD \uC815\uB82C"
4746
+ };
4747
+ function TableAlignmentItems(props) {
4748
+ const Components = (0, import_react31.useComponentsContext)();
4749
+ const editor = (0, import_react31.useBlockNoteEditor)();
4750
+ if (props.block?.type !== "table" || !props.block?.id) {
4751
+ return null;
4752
+ }
4753
+ const current = getTableAlignment(editor, props.block.id);
4754
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: ["left", "center", "right"].map((align) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4755
+ Components.Generic.Menu.Item,
4756
+ {
4757
+ icon: TABLE_ALIGN_ICONS[align],
4758
+ checked: current === align,
4759
+ onClick: () => {
4760
+ setTableAlignment(editor, props.block.id, align);
4761
+ editor.setTextCursorPosition(props.block.id);
4762
+ },
4763
+ children: TABLE_ALIGN_LABELS[align]
4764
+ },
4765
+ `tableAlign-${align}`
4766
+ )) });
4767
+ }
4768
+ var LumirDragHandleMenu = (props) => {
4769
+ const dict = (0, import_react31.useDictionary)();
4770
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react31.DragHandleMenu, { ...props, children: [
4771
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react31.RemoveBlockItem, { ...props, children: dict.drag_handle.delete_menuitem }),
4772
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react31.BlockColorsItem, { ...props, children: dict.drag_handle.colors_menuitem }),
4773
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react31.TableRowHeaderItem, { ...props, children: dict.drag_handle.header_row_menuitem }),
4774
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react31.TableColumnHeaderItem, { ...props, children: dict.drag_handle.header_column_menuitem }),
4775
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TableAlignmentItems, { block: props.block })
4776
+ ] });
4777
+ };
4778
+
4779
+ // src/components/LumirTableHandlesController.tsx
4780
+ var import_react34 = require("@blocknote/react");
4781
+ var import_react35 = require("@floating-ui/react");
4782
+ var import_react36 = require("react");
3743
4783
 
3744
4784
  // src/components/hooks/useFocusedCellHandlePositioning.ts
3745
- var import_react29 = require("@floating-ui/react");
3746
- var import_react30 = require("react");
4785
+ var import_react32 = require("@floating-ui/react");
4786
+ var import_react33 = require("react");
3747
4787
  function useFocusedCellHandlePositioning(cellEl, tbodyEl, orientation, show) {
3748
- const { refs, floatingStyles, context } = (0, import_react29.useFloating)({
4788
+ const { refs, floatingStyles, context, update } = (0, import_react32.useFloating)({
3749
4789
  open: show,
3750
4790
  placement: orientation === "row" ? "left" : orientation === "col" ? "top" : "right",
3751
4791
  // col/row: 가장자리 선(zero-size)에, cell: 셀 우측 보더에 14px hit-area 중앙 정렬(-7).
3752
- middleware: [(0, import_react29.offset)(-7)],
3753
- whileElementsMounted: import_react29.autoUpdate
4792
+ middleware: [(0, import_react32.offset)(-7)],
4793
+ whileElementsMounted: import_react32.autoUpdate
3754
4794
  });
3755
- const { isMounted, styles } = (0, import_react29.useTransitionStyles)(context);
3756
- (0, import_react30.useEffect)(() => {
4795
+ const { isMounted, styles } = (0, import_react32.useTransitionStyles)(context);
4796
+ (0, import_react33.useEffect)(() => {
4797
+ if (!show || !tbodyEl) {
4798
+ return;
4799
+ }
4800
+ const ro = new ResizeObserver(() => update());
4801
+ ro.observe(tbodyEl);
4802
+ return () => ro.disconnect();
4803
+ }, [show, tbodyEl, update]);
4804
+ (0, import_react33.useEffect)(() => {
3757
4805
  if (!cellEl) {
3758
4806
  refs.setReference(null);
3759
4807
  return;
@@ -3773,7 +4821,7 @@ function useFocusedCellHandlePositioning(cellEl, tbodyEl, orientation, show) {
3773
4821
  }
3774
4822
  });
3775
4823
  }, [cellEl, tbodyEl, orientation, refs]);
3776
- return (0, import_react30.useMemo)(
4824
+ return (0, import_react33.useMemo)(
3777
4825
  () => ({
3778
4826
  isMounted,
3779
4827
  ref: refs.setFloating,
@@ -3788,7 +4836,7 @@ function useFocusedCellHandlePositioning(cellEl, tbodyEl, orientation, show) {
3788
4836
  }
3789
4837
 
3790
4838
  // src/components/LumirTableHandlesController.tsx
3791
- var import_jsx_runtime24 = require("react/jsx-runtime");
4839
+ var import_jsx_runtime26 = require("react/jsx-runtime");
3792
4840
  function syncCoreHoverToFocusedCell(cellEl) {
3793
4841
  const r = cellEl.getBoundingClientRect();
3794
4842
  cellEl.dispatchEvent(
@@ -3802,15 +4850,18 @@ function syncCoreHoverToFocusedCell(cellEl) {
3802
4850
  );
3803
4851
  }
3804
4852
  function LumirTableHandlesController() {
3805
- const editor = (0, import_react31.useBlockNoteEditor)();
3806
- const [focused, setFocused] = (0, import_react33.useState)(null);
3807
- const [menuContainerRef, setMenuContainerRef] = (0, import_react33.useState)(null);
3808
- const [overlayEl, setOverlayEl] = (0, import_react33.useState)(null);
3809
- const [openMenu, setOpenMenu] = (0, import_react33.useState)(null);
3810
- const frozenRef = (0, import_react33.useRef)(false);
3811
- const menuOpenRef = (0, import_react33.useRef)(false);
3812
- const draggingRef = (0, import_react33.useRef)(false);
3813
- const recompute = (0, import_react33.useCallback)(() => {
4853
+ const editor = (0, import_react34.useBlockNoteEditor)();
4854
+ const [focused, setFocused] = (0, import_react36.useState)(null);
4855
+ const [menuContainerRef, setMenuContainerRef] = (0, import_react36.useState)(null);
4856
+ const [overlayEl, setOverlayEl] = (0, import_react36.useState)(null);
4857
+ const [openMenu, setOpenMenu] = (0, import_react36.useState)(null);
4858
+ const frozenRef = (0, import_react36.useRef)(false);
4859
+ const menuOpenRef = (0, import_react36.useRef)(false);
4860
+ const draggingRef = (0, import_react36.useRef)(false);
4861
+ (0, import_react36.useEffect)(() => {
4862
+ editor.__lumirActiveTableId = focused?.block?.id ?? null;
4863
+ }, [editor, focused]);
4864
+ const recompute = (0, import_react36.useCallback)(() => {
3814
4865
  if (frozenRef.current) {
3815
4866
  return;
3816
4867
  }
@@ -3858,11 +4909,11 @@ function LumirTableHandlesController() {
3858
4909
  widgetContainer
3859
4910
  });
3860
4911
  }, [editor]);
3861
- (0, import_react31.useEditorContentOrSelectionChange)(recompute, editor);
3862
- (0, import_react33.useEffect)(() => {
4912
+ (0, import_react34.useEditorContentOrSelectionChange)(recompute, editor);
4913
+ (0, import_react36.useEffect)(() => {
3863
4914
  recompute();
3864
4915
  }, [recompute]);
3865
- (0, import_react33.useEffect)(() => {
4916
+ (0, import_react36.useEffect)(() => {
3866
4917
  const onUp = () => {
3867
4918
  requestAnimationFrame(() => {
3868
4919
  if (!menuOpenRef.current && !draggingRef.current && frozenRef.current) {
@@ -3874,7 +4925,7 @@ function LumirTableHandlesController() {
3874
4925
  window.addEventListener("pointerup", onUp);
3875
4926
  return () => window.removeEventListener("pointerup", onUp);
3876
4927
  }, [recompute]);
3877
- (0, import_react33.useEffect)(() => {
4928
+ (0, import_react36.useEffect)(() => {
3878
4929
  const f = focused;
3879
4930
  if (!f || !overlayEl) {
3880
4931
  return;
@@ -3899,7 +4950,13 @@ function LumirTableHandlesController() {
3899
4950
  overlayEl.style.height = `${bottom - top}px`;
3900
4951
  };
3901
4952
  update();
3902
- return (0, import_react32.autoUpdate)(f.cellEl, overlayEl, update);
4953
+ const stopAutoUpdate = (0, import_react35.autoUpdate)(f.cellEl, overlayEl, update);
4954
+ const ro = new ResizeObserver(update);
4955
+ ro.observe(f.tbodyEl);
4956
+ return () => {
4957
+ stopAutoUpdate();
4958
+ ro.disconnect();
4959
+ };
3903
4960
  }, [focused, overlayEl, openMenu]);
3904
4961
  const cellEl = focused?.cellEl ?? null;
3905
4962
  const tbodyEl = focused?.tbodyEl ?? null;
@@ -3913,21 +4970,21 @@ function LumirTableHandlesController() {
3913
4970
  show
3914
4971
  );
3915
4972
  const th = editor.tableHandles;
3916
- const coreState = (0, import_react31.useUIPluginState)(
4973
+ const coreState = (0, import_react34.useUIPluginState)(
3917
4974
  editor.tableHandles.onUpdate.bind(editor.tableHandles)
3918
4975
  );
3919
- const { addOrRemoveColumnsButton, addOrRemoveRowsButton } = (0, import_react31.useExtendButtonsPositioning)(
4976
+ const { addOrRemoveColumnsButton, addOrRemoveRowsButton } = (0, import_react34.useExtendButtonsPositioning)(
3920
4977
  coreState?.showAddOrRemoveColumnsButton || false,
3921
4978
  coreState?.showAddOrRemoveRowsButton || false,
3922
4979
  coreState?.referencePosTable || null
3923
4980
  );
3924
- const onStartExtend = (0, import_react33.useCallback)(() => {
4981
+ const onStartExtend = (0, import_react36.useCallback)(() => {
3925
4982
  editor.tableHandles?.freezeHandles();
3926
4983
  }, [editor]);
3927
- const onEndExtend = (0, import_react33.useCallback)(() => {
4984
+ const onEndExtend = (0, import_react36.useCallback)(() => {
3928
4985
  editor.tableHandles?.unfreezeHandles();
3929
4986
  }, [editor]);
3930
- const menuHandlers = (0, import_react33.useMemo)(() => {
4987
+ const menuHandlers = (0, import_react36.useMemo)(() => {
3931
4988
  const mk = (kind) => ({
3932
4989
  freeze: () => {
3933
4990
  menuOpenRef.current = true;
@@ -3945,10 +5002,10 @@ function LumirTableHandlesController() {
3945
5002
  });
3946
5003
  return { col: mk("col"), row: mk("row"), cell: mk("cell") };
3947
5004
  }, [editor, recompute]);
3948
- const onGutterPointerDown = (0, import_react33.useCallback)(() => {
5005
+ const onGutterPointerDown = (0, import_react36.useCallback)(() => {
3949
5006
  frozenRef.current = true;
3950
5007
  }, []);
3951
- const onGutterPointerEnter = (0, import_react33.useCallback)(
5008
+ const onGutterPointerEnter = (0, import_react36.useCallback)(
3952
5009
  (e) => {
3953
5010
  if (e.buttons === 0 && focused) {
3954
5011
  syncCoreHoverToFocusedCell(focused.cellEl);
@@ -3956,7 +5013,7 @@ function LumirTableHandlesController() {
3956
5013
  },
3957
5014
  [focused]
3958
5015
  );
3959
- const makeDragStart = (0, import_react33.useCallback)(
5016
+ const makeDragStart = (0, import_react36.useCallback)(
3960
5017
  (dir) => (e) => {
3961
5018
  draggingRef.current = true;
3962
5019
  frozenRef.current = true;
@@ -3968,19 +5025,19 @@ function LumirTableHandlesController() {
3968
5025
  },
3969
5026
  [editor]
3970
5027
  );
3971
- const onDragEnd = (0, import_react33.useCallback)(() => {
5028
+ const onDragEnd = (0, import_react36.useCallback)(() => {
3972
5029
  editor.tableHandles?.dragEnd();
3973
5030
  draggingRef.current = false;
3974
5031
  frozenRef.current = false;
3975
5032
  recompute();
3976
5033
  }, [editor, recompute]);
3977
- const noop = (0, import_react33.useCallback)(() => {
5034
+ const noop = (0, import_react36.useCallback)(() => {
3978
5035
  }, []);
3979
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
3980
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: setMenuContainerRef }),
3981
- th && focused && menuContainerRef && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react32.FloatingPortal, { root: focused.widgetContainer, children: [
3982
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: setOverlayEl, className: "lumir-tbl-cell-focus" }),
3983
- colHandle.isMounted && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5036
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
5037
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: setMenuContainerRef }),
5038
+ th && focused && menuContainerRef && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react35.FloatingPortal, { root: focused.widgetContainer, children: [
5039
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: setOverlayEl, className: "lumir-tbl-cell-focus" }),
5040
+ colHandle.isMounted && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
3984
5041
  "div",
3985
5042
  {
3986
5043
  ref: colHandle.ref,
@@ -3989,9 +5046,9 @@ function LumirTableHandlesController() {
3989
5046
  onPointerEnter: onGutterPointerEnter,
3990
5047
  onPointerDown: onGutterPointerDown,
3991
5048
  children: [
3992
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "lumir-tbl-gutter" }),
3993
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3994
- import_react31.TableHandle,
5049
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "lumir-tbl-gutter" }),
5050
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5051
+ import_react34.TableHandle,
3995
5052
  {
3996
5053
  editor,
3997
5054
  orientation: "column",
@@ -4009,7 +5066,7 @@ function LumirTableHandlesController() {
4009
5066
  ]
4010
5067
  }
4011
5068
  ),
4012
- rowHandle.isMounted && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5069
+ rowHandle.isMounted && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
4013
5070
  "div",
4014
5071
  {
4015
5072
  ref: rowHandle.ref,
@@ -4018,9 +5075,9 @@ function LumirTableHandlesController() {
4018
5075
  onPointerEnter: onGutterPointerEnter,
4019
5076
  onPointerDown: onGutterPointerDown,
4020
5077
  children: [
4021
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "lumir-tbl-gutter" }),
4022
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4023
- import_react31.TableHandle,
5078
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "lumir-tbl-gutter" }),
5079
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5080
+ import_react34.TableHandle,
4024
5081
  {
4025
5082
  editor,
4026
5083
  orientation: "row",
@@ -4038,7 +5095,7 @@ function LumirTableHandlesController() {
4038
5095
  ]
4039
5096
  }
4040
5097
  ),
4041
- cellHandle.isMounted && openMenu !== "col" && openMenu !== "row" && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5098
+ cellHandle.isMounted && openMenu !== "col" && openMenu !== "row" && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
4042
5099
  "div",
4043
5100
  {
4044
5101
  ref: cellHandle.ref,
@@ -4046,9 +5103,9 @@ function LumirTableHandlesController() {
4046
5103
  className: "lumir-tbl-gutter-wrap lumir-tbl-gutter-wrap--cell" + (openMenu === "cell" ? " lumir-tbl-gutter-wrap--active" : ""),
4047
5104
  onPointerDown: onGutterPointerDown,
4048
5105
  children: [
4049
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "lumir-tbl-gutter" }),
4050
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4051
- import_react31.TableCellButton,
5106
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "lumir-tbl-gutter" }),
5107
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5108
+ import_react34.TableCellButton,
4052
5109
  {
4053
5110
  editor,
4054
5111
  rowIndex: focused.rowIndex,
@@ -4064,9 +5121,9 @@ function LumirTableHandlesController() {
4064
5121
  }
4065
5122
  )
4066
5123
  ] }),
4067
- th && coreState?.widgetContainer && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react32.FloatingPortal, { root: coreState.widgetContainer, children: [
4068
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: addOrRemoveRowsButton.ref, style: addOrRemoveRowsButton.style, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4069
- import_react31.ExtendButton,
5124
+ th && coreState?.widgetContainer && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react35.FloatingPortal, { root: coreState.widgetContainer, children: [
5125
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: addOrRemoveRowsButton.ref, style: addOrRemoveRowsButton.style, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5126
+ import_react34.ExtendButton,
4070
5127
  {
4071
5128
  editor,
4072
5129
  orientation: "addOrRemoveRows",
@@ -4075,13 +5132,13 @@ function LumirTableHandlesController() {
4075
5132
  onMouseUp: onEndExtend
4076
5133
  }
4077
5134
  ) }),
4078
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5135
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
4079
5136
  "div",
4080
5137
  {
4081
5138
  ref: addOrRemoveColumnsButton.ref,
4082
5139
  style: addOrRemoveColumnsButton.style,
4083
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4084
- import_react31.ExtendButton,
5140
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5141
+ import_react34.ExtendButton,
4085
5142
  {
4086
5143
  editor,
4087
5144
  orientation: "addOrRemoveColumns",
@@ -4097,15 +5154,17 @@ function LumirTableHandlesController() {
4097
5154
  }
4098
5155
 
4099
5156
  // src/utils/table-vertical-alignment.ts
4100
- function injectVerticalAlignment(blocks, editor) {
4101
- const tiptap = editor?._tiptapEditor;
4102
- if (!tiptap) return blocks;
4103
- const { doc } = tiptap.state;
4104
- const tableVAMap = buildTableVerticalAlignmentMap(doc);
4105
- if (tableVAMap.size === 0) return blocks;
4106
- return patchBlocks(blocks, tableVAMap);
5157
+ var CELL_ATTR_DEFAULTS = {
5158
+ verticalAlignment: "top",
5159
+ rowHeight: null
5160
+ };
5161
+ function isMeaningful2(attr, value) {
5162
+ if (value === null || value === void 0) {
5163
+ return false;
5164
+ }
5165
+ return value !== CELL_ATTR_DEFAULTS[attr];
4107
5166
  }
4108
- function buildTableVerticalAlignmentMap(doc) {
5167
+ function buildTableCellAttrMap(doc, attrs) {
4109
5168
  const result = /* @__PURE__ */ new Map();
4110
5169
  doc.descendants((node) => {
4111
5170
  if (node.type.name === "blockContainer") {
@@ -4118,9 +5177,15 @@ function buildTableVerticalAlignmentMap(doc) {
4118
5177
  if (rowNode.type.name === "tableRow") {
4119
5178
  let colIndex = 0;
4120
5179
  rowNode.forEach((cellNode) => {
4121
- const va = cellNode.attrs?.verticalAlignment;
4122
- if (va && va !== "top") {
4123
- cells.push({ row: rowIndex, col: colIndex, va });
5180
+ const props = {};
5181
+ for (const attr of attrs) {
5182
+ const value = cellNode.attrs?.[attr];
5183
+ if (isMeaningful2(attr, value)) {
5184
+ props[attr] = value;
5185
+ }
5186
+ }
5187
+ if (Object.keys(props).length > 0) {
5188
+ cells.push({ row: rowIndex, col: colIndex, props });
4124
5189
  }
4125
5190
  colIndex++;
4126
5191
  });
@@ -4136,18 +5201,21 @@ function buildTableVerticalAlignmentMap(doc) {
4136
5201
  });
4137
5202
  return result;
4138
5203
  }
4139
- function patchBlocks(blocks, tableVAMap) {
5204
+ function patchBlocks(blocks, cellAttrMap) {
4140
5205
  return blocks.map((block) => {
4141
5206
  if (block.type !== "table" || !block.id || !block.content) {
4142
5207
  if (block.children && block.children.length > 0) {
4143
5208
  return {
4144
5209
  ...block,
4145
- children: patchBlocks(block.children, tableVAMap)
5210
+ children: patchBlocks(
5211
+ block.children,
5212
+ cellAttrMap
5213
+ )
4146
5214
  };
4147
5215
  }
4148
5216
  return block;
4149
5217
  }
4150
- const cells = tableVAMap.get(block.id);
5218
+ const cells = cellAttrMap.get(block.id);
4151
5219
  if (!cells || cells.length === 0) {
4152
5220
  return block;
4153
5221
  }
@@ -4160,11 +5228,13 @@ function patchBlocks(blocks, tableVAMap) {
4160
5228
  const match = cells.find(
4161
5229
  (c) => c.row === rowIndex && c.col === colIndex
4162
5230
  );
4163
- if (!match) return cell;
5231
+ if (!match) {
5232
+ return cell;
5233
+ }
4164
5234
  if (cell && typeof cell === "object" && cell.type === "tableCell") {
4165
5235
  return {
4166
5236
  ...cell,
4167
- props: { ...cell.props, verticalAlignment: match.va }
5237
+ props: { ...cell.props, ...match.props }
4168
5238
  };
4169
5239
  }
4170
5240
  return cell;
@@ -4177,6 +5247,77 @@ function patchBlocks(blocks, tableVAMap) {
4177
5247
  };
4178
5248
  });
4179
5249
  }
5250
+ function injectTableCellAttrs(blocks, editor, attrs) {
5251
+ const tiptap = editor?._tiptapEditor;
5252
+ if (!tiptap) {
5253
+ return blocks;
5254
+ }
5255
+ const { doc } = tiptap.state;
5256
+ const cellAttrMap = buildTableCellAttrMap(doc, attrs);
5257
+ if (cellAttrMap.size === 0) {
5258
+ return blocks;
5259
+ }
5260
+ return patchBlocks(blocks, cellAttrMap);
5261
+ }
5262
+ var TABLE_BLOCK_ATTR_DEFAULTS = {
5263
+ tableAlignment: "left"
5264
+ };
5265
+ function buildTableBlockAttrMap(doc, attrs) {
5266
+ const result = /* @__PURE__ */ new Map();
5267
+ doc.descendants((node) => {
5268
+ if (node.type.name === "blockContainer") {
5269
+ const blockId = node.attrs?.id;
5270
+ const contentNode = node.firstChild;
5271
+ if (blockId && contentNode?.type.name === "table") {
5272
+ const props = {};
5273
+ for (const attr of attrs) {
5274
+ const value = contentNode.attrs?.[attr];
5275
+ if (value !== null && value !== void 0 && value !== TABLE_BLOCK_ATTR_DEFAULTS[attr]) {
5276
+ props[attr] = value;
5277
+ }
5278
+ }
5279
+ if (Object.keys(props).length > 0) {
5280
+ result.set(blockId, props);
5281
+ }
5282
+ }
5283
+ return false;
5284
+ }
5285
+ return void 0;
5286
+ });
5287
+ return result;
5288
+ }
5289
+ function patchTableBlockProps(blocks, attrMap) {
5290
+ return blocks.map((block) => {
5291
+ if (block.type === "table" && block.id && attrMap.has(block.id)) {
5292
+ return {
5293
+ ...block,
5294
+ props: { ...block.props, ...attrMap.get(block.id) }
5295
+ };
5296
+ }
5297
+ if (block.children && block.children.length > 0) {
5298
+ return {
5299
+ ...block,
5300
+ children: patchTableBlockProps(
5301
+ block.children,
5302
+ attrMap
5303
+ )
5304
+ };
5305
+ }
5306
+ return block;
5307
+ });
5308
+ }
5309
+ function injectTableBlockAttrs(blocks, editor) {
5310
+ const tiptap = editor?._tiptapEditor;
5311
+ if (!tiptap) {
5312
+ return blocks;
5313
+ }
5314
+ const { doc } = tiptap.state;
5315
+ const attrMap = buildTableBlockAttrMap(doc, ["tableAlignment"]);
5316
+ if (attrMap.size === 0) {
5317
+ return blocks;
5318
+ }
5319
+ return patchTableBlockProps(blocks, attrMap);
5320
+ }
4180
5321
 
4181
5322
  // src/utils/font-size-serialization.ts
4182
5323
  function mapPreservingRef(arr, fn) {
@@ -4262,6 +5403,140 @@ function liftFontSize(blocks) {
4262
5403
  return mapPreservingRef(blocks, (b) => mapBlock(b, "lift"));
4263
5404
  }
4264
5405
 
5406
+ // src/utils/table-delete.ts
5407
+ var import_prosemirror_tables2 = require("prosemirror-tables");
5408
+ function measureRowHeights(view, tablePos) {
5409
+ try {
5410
+ const at = view?.domAtPos?.(tablePos + 1);
5411
+ let el = at?.node;
5412
+ if (el && el.nodeType === 3) el = el.parentElement;
5413
+ const tableEl = el?.closest?.("table") ?? null;
5414
+ const body = tableEl?.tBodies?.[0];
5415
+ if (!body) return null;
5416
+ return Array.from(body.rows).map(
5417
+ (tr) => Math.round(tr.getBoundingClientRect().height)
5418
+ );
5419
+ } catch {
5420
+ return null;
5421
+ }
5422
+ }
5423
+ function buildDeleteColumnTr(state, tablePos, col, rowPx) {
5424
+ const table = state.doc.nodeAt(tablePos);
5425
+ if (!table || table.type.name !== "table") return null;
5426
+ const map = import_prosemirror_tables2.TableMap.get(table);
5427
+ const W = map.width;
5428
+ const H = map.height;
5429
+ if (col < 0 || col >= W || W <= 1) return null;
5430
+ const cells = [];
5431
+ const seen = /* @__PURE__ */ new Set();
5432
+ for (let r = 0; r < H; r++) {
5433
+ for (let c = 0; c < W; c++) {
5434
+ const pos = map.map[r * W + c];
5435
+ if (seen.has(pos)) continue;
5436
+ seen.add(pos);
5437
+ const node = table.nodeAt(pos);
5438
+ if (!node) continue;
5439
+ cells.push({
5440
+ node,
5441
+ top: r,
5442
+ left: c,
5443
+ rowspan: node.attrs.rowspan ?? 1,
5444
+ colspan: node.attrs.colspan ?? 1
5445
+ });
5446
+ }
5447
+ }
5448
+ const spansCol = (c) => c.left <= col && col < c.left + c.colspan;
5449
+ const isDropped = (c) => spansCol(c) && c.colspan === 1;
5450
+ const survivingByRow = new Array(H).fill(0);
5451
+ for (const c of cells) if (!isDropped(c)) survivingByRow[c.top]++;
5452
+ const rowDies = survivingByRow.map((n) => n === 0);
5453
+ const newRowIndex = [];
5454
+ let ni = 0;
5455
+ for (let r = 0; r < H; r++) newRowIndex[r] = rowDies[r] ? -1 : ni++;
5456
+ const newH = ni;
5457
+ if (newH === 0) return null;
5458
+ const newRows = Array.from({ length: newH }, () => []);
5459
+ for (const c of cells) {
5460
+ if (isDropped(c)) continue;
5461
+ const newColspan = c.colspan - (spansCol(c) ? 1 : 0);
5462
+ let dyingWithin = 0;
5463
+ for (let r = c.top; r < c.top + c.rowspan; r++) if (rowDies[r]) dyingWithin++;
5464
+ const newRowspan = Math.max(1, c.rowspan - dyingWithin);
5465
+ const attrs = { ...c.node.attrs, colspan: newColspan, rowspan: newRowspan };
5466
+ if (spansCol(c) && Array.isArray(attrs.colwidth) && attrs.colwidth.length) {
5467
+ const cw = attrs.colwidth.slice();
5468
+ cw.splice(col - c.left, 1);
5469
+ attrs.colwidth = cw.some((w) => w > 0) ? cw : null;
5470
+ }
5471
+ if (dyingWithin > 0 && rowPx) {
5472
+ let sum = 0;
5473
+ let ok = true;
5474
+ for (let r = c.top; r < c.top + c.rowspan; r++) {
5475
+ if (typeof rowPx[r] !== "number") {
5476
+ ok = false;
5477
+ break;
5478
+ }
5479
+ sum += rowPx[r];
5480
+ }
5481
+ if (ok && sum > 0) attrs.rowHeight = Math.round(sum);
5482
+ }
5483
+ const target = newRowIndex[c.top];
5484
+ if (target >= 0) newRows[target].push(c.node.type.create(attrs, c.node.content));
5485
+ }
5486
+ const rowType = table.child(0)?.type;
5487
+ if (!rowType) return null;
5488
+ const rowNodes = newRows.map((rowCells) => rowType.create(null, rowCells));
5489
+ const newTable = table.type.create(table.attrs, rowNodes);
5490
+ const tr = state.tr;
5491
+ tr.replaceWith(tablePos, tablePos + table.nodeSize, newTable);
5492
+ return tr.docChanged ? tr : null;
5493
+ }
5494
+ function removeFocusedRowOrColumn(editor, index, direction) {
5495
+ const tiptap = editor?._tiptapEditor;
5496
+ if (!tiptap) return false;
5497
+ const { state } = tiptap;
5498
+ let tablePos = -1;
5499
+ const activeId = editor?.__lumirActiveTableId;
5500
+ if (activeId) {
5501
+ const p = findTableNodePos(tiptap, activeId);
5502
+ if (p >= 0 && state.doc.nodeAt(p)?.type.name === "table") tablePos = p;
5503
+ }
5504
+ if (tablePos < 0) {
5505
+ const $from = state.selection.$from;
5506
+ for (let d = $from.depth; d > 0; d--) {
5507
+ if ($from.node(d).type.name === "table") {
5508
+ tablePos = $from.before(d);
5509
+ break;
5510
+ }
5511
+ }
5512
+ }
5513
+ if (tablePos < 0) {
5514
+ const vp = editor?.tableHandles?.view?.tablePos;
5515
+ if (typeof vp === "number" && state.doc.nodeAt(vp)?.type.name === "table") {
5516
+ tablePos = vp;
5517
+ }
5518
+ }
5519
+ if (tablePos < 0) return false;
5520
+ try {
5521
+ if (direction === "column") {
5522
+ const rowPx = measureRowHeights(tiptap.view, tablePos);
5523
+ const tr = buildDeleteColumnTr(state, tablePos, index, rowPx);
5524
+ if (!tr) return false;
5525
+ tiptap.view.dispatch(tr);
5526
+ return true;
5527
+ }
5528
+ const tableInside = state.doc.resolve(tablePos + 1);
5529
+ const rowStart = state.doc.resolve(tableInside.posAtIndex(index) + 1);
5530
+ const cellPos = state.doc.resolve(rowStart.posAtIndex(0));
5531
+ const selState = state.apply(
5532
+ state.tr.setSelection(new import_prosemirror_tables2.CellSelection(cellPos))
5533
+ );
5534
+ return (0, import_prosemirror_tables2.deleteRow)(selState, (tr) => tiptap.view.dispatch(tr));
5535
+ } catch {
5536
+ return false;
5537
+ }
5538
+ }
5539
+
4265
5540
  // src/utils/excel-paste.ts
4266
5541
  var NAMED_COLORS = {
4267
5542
  black: "#000000",
@@ -4491,26 +5766,8 @@ function normalizeExcelTableHtml(html) {
4491
5766
  }
4492
5767
  }
4493
5768
 
4494
- // src/constants/limits.ts
4495
- var MAX_FILE_SIZE = 10 * 1024 * 1024;
4496
- var MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;
4497
- var BLOCKED_EXTENSIONS = [".svg", ".svgz"];
4498
- var ALLOWED_VIDEO_MIME_TYPES = /* @__PURE__ */ new Set([
4499
- "video/mp4",
4500
- "video/webm",
4501
- "video/ogg",
4502
- "video/quicktime"
4503
- // .mov
4504
- ]);
4505
- var ALLOWED_VIDEO_EXTENSIONS = [
4506
- ".mp4",
4507
- ".webm",
4508
- ".ogg",
4509
- ".mov"
4510
- ];
4511
-
4512
5769
  // src/components/LumirEditor.tsx
4513
- var import_jsx_runtime25 = require("react/jsx-runtime");
5770
+ var import_jsx_runtime27 = require("react/jsx-runtime");
4514
5771
  var DEBUG_LOG = (loc, msg, data) => {
4515
5772
  const p = fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
4516
5773
  method: "POST",
@@ -4741,9 +5998,9 @@ var findBlockWithLink = (blocks, targetUrl) => {
4741
5998
  return null;
4742
5999
  };
4743
6000
  var ConvertToPreviewButton = ({ url }) => {
4744
- const editor = (0, import_react35.useBlockNoteEditor)();
4745
- const Components = (0, import_react35.useComponentsContext)();
4746
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6001
+ const editor = (0, import_react38.useBlockNoteEditor)();
6002
+ const Components = (0, import_react38.useComponentsContext)();
6003
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
4747
6004
  Components.LinkToolbar.Button,
4748
6005
  {
4749
6006
  className: "bn-button",
@@ -4762,29 +6019,29 @@ var ConvertToPreviewButton = ({ url }) => {
4762
6019
  console.error("Convert to link preview failed:", err);
4763
6020
  }
4764
6021
  },
4765
- icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
4766
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("rect", { x: "1", y: "3", width: "14", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.5", fill: "none" }),
4767
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("line", { x1: "1", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "1.5" }),
4768
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("circle", { cx: "5", cy: "6.5", r: "1.5", stroke: "currentColor", strokeWidth: "1", fill: "none" })
6022
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
6023
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("rect", { x: "1", y: "3", width: "14", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.5", fill: "none" }),
6024
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("line", { x1: "1", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "1.5" }),
6025
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("circle", { cx: "5", cy: "6.5", r: "1.5", stroke: "currentColor", strokeWidth: "1", fill: "none" })
4769
6026
  ] })
4770
6027
  }
4771
6028
  );
4772
6029
  };
4773
6030
  var CustomLinkToolbar = (props) => {
4774
- const editor = (0, import_react35.useBlockNoteEditor)();
4775
- const Components = (0, import_react35.useComponentsContext)();
6031
+ const editor = (0, import_react38.useBlockNoteEditor)();
6032
+ const Components = (0, import_react38.useComponentsContext)();
4776
6033
  const hasLinkPreview = !!editor?._linkPreviewApiEndpoint;
4777
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6034
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
4778
6035
  Components.LinkToolbar.Root,
4779
6036
  {
4780
6037
  className: "bn-toolbar bn-link-toolbar",
4781
6038
  onMouseEnter: props.stopHideTimer,
4782
6039
  onMouseLeave: props.startHideTimer,
4783
6040
  children: [
4784
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.EditLinkButton, { url: props.url, text: props.text, editLink: props.editLink }),
4785
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.OpenLinkButton, { url: props.url }),
4786
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.DeleteLinkButton, { deleteLink: props.deleteLink }),
4787
- hasLinkPreview && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ConvertToPreviewButton, { url: props.url })
6041
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.EditLinkButton, { url: props.url, text: props.text, editLink: props.editLink }),
6042
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.OpenLinkButton, { url: props.url }),
6043
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.DeleteLinkButton, { deleteLink: props.deleteLink }),
6044
+ hasLinkPreview && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ConvertToPreviewButton, { url: props.url })
4788
6045
  ]
4789
6046
  }
4790
6047
  );
@@ -4828,13 +6085,13 @@ function LumirEditor({
4828
6085
  onError,
4829
6086
  onImageDelete
4830
6087
  }) {
4831
- const [isUploading, setIsUploading] = (0, import_react34.useState)(false);
4832
- const [uploadProgress, setUploadProgress] = (0, import_react34.useState)(null);
4833
- const [errorMessage, setErrorMessage] = (0, import_react34.useState)(null);
4834
- const floatingMenuFileInputRef = (0, import_react34.useRef)(null);
4835
- const floatingMenuBlockRef = (0, import_react34.useRef)(null);
4836
- const floatingMenuUploadStartTimeRef = (0, import_react34.useRef)(0);
4837
- const handleError = (0, import_react34.useCallback)(
6088
+ const [isUploading, setIsUploading] = (0, import_react37.useState)(false);
6089
+ const [uploadProgress, setUploadProgress] = (0, import_react37.useState)(null);
6090
+ const [errorMessage, setErrorMessage] = (0, import_react37.useState)(null);
6091
+ const floatingMenuFileInputRef = (0, import_react37.useRef)(null);
6092
+ const floatingMenuBlockRef = (0, import_react37.useRef)(null);
6093
+ const floatingMenuUploadStartTimeRef = (0, import_react37.useRef)(0);
6094
+ const handleError = (0, import_react37.useCallback)(
4838
6095
  (error) => {
4839
6096
  onError?.(error);
4840
6097
  setErrorMessage(error.getUserMessage());
@@ -4842,12 +6099,12 @@ function LumirEditor({
4842
6099
  },
4843
6100
  [onError]
4844
6101
  );
4845
- const validatedContent = (0, import_react34.useMemo)(() => {
6102
+ const validatedContent = (0, import_react37.useMemo)(() => {
4846
6103
  return liftFontSize(
4847
6104
  ContentUtils.validateContent(initialContent, initialEmptyBlocks)
4848
6105
  );
4849
6106
  }, [initialContent, initialEmptyBlocks]);
4850
- const tableConfig = (0, import_react34.useMemo)(() => {
6107
+ const tableConfig = (0, import_react37.useMemo)(() => {
4851
6108
  return EditorConfig.getDefaultTableConfig(tables);
4852
6109
  }, [
4853
6110
  tables?.splitCells,
@@ -4855,10 +6112,10 @@ function LumirEditor({
4855
6112
  tables?.cellTextColor,
4856
6113
  tables?.headers
4857
6114
  ]);
4858
- const headingConfig = (0, import_react34.useMemo)(() => {
6115
+ const headingConfig = (0, import_react37.useMemo)(() => {
4859
6116
  return EditorConfig.getDefaultHeadingConfig(heading);
4860
6117
  }, [heading?.levels?.join(",") ?? ""]);
4861
- const disabledExtensions = (0, import_react34.useMemo)(() => {
6118
+ const disabledExtensions = (0, import_react37.useMemo)(() => {
4862
6119
  return EditorConfig.getDisabledExtensions(
4863
6120
  disableExtensions,
4864
6121
  allowVideoUpload,
@@ -4866,18 +6123,18 @@ function LumirEditor({
4866
6123
  allowFileUpload
4867
6124
  );
4868
6125
  }, [disableExtensions, allowVideoUpload, allowAudioUpload, allowFileUpload]);
4869
- (0, import_react34.useEffect)(() => {
6126
+ (0, import_react37.useEffect)(() => {
4870
6127
  DEBUG_LOG("LumirEditor:init:disabledExtensions", "snapshot", {
4871
6128
  allowVideoUpload,
4872
6129
  hasVideoInDisabled: disabledExtensions.includes("video"),
4873
6130
  disabledList: disabledExtensions.slice(0, 15)
4874
6131
  });
4875
6132
  }, [allowVideoUpload, disabledExtensions]);
4876
- const fileNameTransformRef = (0, import_react34.useRef)(s3Upload?.fileNameTransform);
4877
- (0, import_react34.useEffect)(() => {
6133
+ const fileNameTransformRef = (0, import_react37.useRef)(s3Upload?.fileNameTransform);
6134
+ (0, import_react37.useEffect)(() => {
4878
6135
  fileNameTransformRef.current = s3Upload?.fileNameTransform;
4879
6136
  }, [s3Upload?.fileNameTransform]);
4880
- const memoizedS3Upload = (0, import_react34.useMemo)(() => {
6137
+ const memoizedS3Upload = (0, import_react37.useMemo)(() => {
4881
6138
  if (!s3Upload) return void 0;
4882
6139
  return {
4883
6140
  apiEndpoint: s3Upload.apiEndpoint,
@@ -4906,7 +6163,7 @@ function LumirEditor({
4906
6163
  s3Upload?.maxRetries,
4907
6164
  s3Upload?.onProgress
4908
6165
  ]);
4909
- const editor = (0, import_react35.useCreateBlockNote)(
6166
+ const editor = (0, import_react38.useCreateBlockNote)(
4910
6167
  {
4911
6168
  // HTML 미리보기 블록이 포함된 커스텀 스키마 사용
4912
6169
  schema,
@@ -4928,7 +6185,14 @@ function LumirEditor({
4928
6185
  // 확장 비활성: 비디오/오디오/파일 제어
4929
6186
  disableExtensions: disabledExtensions,
4930
6187
  _tiptapOptions: {
4931
- extensions: [VerticalAlignmentExtension]
6188
+ extensions: [
6189
+ VerticalAlignmentExtension,
6190
+ // 행 높이 attr 등록은 항상(저장된 높이 렌더), 드래그 리사이즈 UI는
6191
+ // tableHandles prop으로 게이트(기존 grip 컨트롤러와 동일 게이트).
6192
+ RowHeightExtension.configure({ resizable: tableHandles }),
6193
+ // 표 블록 정렬(좌/가운데/우) attr.
6194
+ TableAlignmentExtension
6195
+ ]
4932
6196
  },
4933
6197
  placeholders: placeholder ? { default: placeholder, emptyDocument: placeholder } : void 0,
4934
6198
  tabBehavior,
@@ -5104,18 +6368,41 @@ function LumirEditor({
5104
6368
  memoizedS3Upload,
5105
6369
  allowVideoUpload,
5106
6370
  linkPreview?.apiEndpoint,
5107
- placeholder
6371
+ placeholder,
6372
+ // tableHandles 변경 시 RowHeightExtension의 resizable 게이트가 반영되도록 재생성
6373
+ tableHandles
5108
6374
  ]
5109
6375
  );
5110
6376
  if (editor && linkPreview?.apiEndpoint) {
5111
6377
  editor._linkPreviewApiEndpoint = linkPreview.apiEndpoint;
5112
6378
  }
5113
- (0, import_react34.useEffect)(() => {
6379
+ if (editor) {
6380
+ try {
6381
+ const view = editor.prosemirrorView;
6382
+ if (view) {
6383
+ view.__lumirEditor = editor;
6384
+ }
6385
+ } catch {
6386
+ }
6387
+ }
6388
+ (0, import_react37.useEffect)(() => {
5114
6389
  if (editor) {
5115
6390
  editor.isEditable = editable;
5116
6391
  }
5117
6392
  }, [editor, editable]);
5118
- (0, import_react34.useEffect)(() => {
6393
+ (0, import_react37.useEffect)(() => {
6394
+ if (!editor) return;
6395
+ const th = editor.tableHandles;
6396
+ if (!th || th.__lumirColDelPatched || typeof th.removeRowOrColumn !== "function")
6397
+ return;
6398
+ const orig = th.removeRowOrColumn.bind(th);
6399
+ th.removeRowOrColumn = (index, dir) => {
6400
+ if (removeFocusedRowOrColumn(editor, index, dir)) return;
6401
+ return orig(index, dir);
6402
+ };
6403
+ th.__lumirColDelPatched = true;
6404
+ }, [editor]);
6405
+ (0, import_react37.useEffect)(() => {
5119
6406
  if (!editor || !floatingMenu) return;
5120
6407
  const ft = editor.formattingToolbar;
5121
6408
  if (!ft?.onUpdate) return;
@@ -5128,22 +6415,30 @@ function LumirEditor({
5128
6415
  });
5129
6416
  return unsubscribe;
5130
6417
  }, [editor, floatingMenu]);
5131
- (0, import_react34.useEffect)(() => {
6418
+ (0, import_react37.useEffect)(() => {
5132
6419
  if (!editor || !onContentChange) return;
5133
6420
  const handleContentChange = () => {
5134
6421
  const blocks = editor.topLevelBlocks;
5135
- const patched = lowerFontSize(injectVerticalAlignment(blocks, editor));
6422
+ const patched = lowerFontSize(
6423
+ injectTableBlockAttrs(
6424
+ injectTableCellAttrs(blocks, editor, [
6425
+ "verticalAlignment",
6426
+ "rowHeight"
6427
+ ]),
6428
+ editor
6429
+ )
6430
+ );
5136
6431
  onContentChange(patched);
5137
6432
  };
5138
6433
  return editor.onEditorContentChange(handleContentChange);
5139
6434
  }, [editor, onContentChange]);
5140
- const previousMediaUrlsRef = (0, import_react34.useRef)(/* @__PURE__ */ new Set());
5141
- (0, import_react34.useEffect)(() => {
6435
+ const previousMediaUrlsRef = (0, import_react37.useRef)(/* @__PURE__ */ new Set());
6436
+ (0, import_react37.useEffect)(() => {
5142
6437
  if (!editor) return;
5143
6438
  const initialBlocks = editor.topLevelBlocks;
5144
6439
  previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);
5145
6440
  }, [editor]);
5146
- (0, import_react34.useEffect)(() => {
6441
+ (0, import_react37.useEffect)(() => {
5147
6442
  if (!editor || !onImageDelete) return;
5148
6443
  const handleMediaDeleteCheck = () => {
5149
6444
  const currentBlocks = editor.topLevelBlocks;
@@ -5157,7 +6452,7 @@ function LumirEditor({
5157
6452
  };
5158
6453
  return editor.onEditorContentChange(handleMediaDeleteCheck);
5159
6454
  }, [editor, onImageDelete]);
5160
- (0, import_react34.useEffect)(() => {
6455
+ (0, import_react37.useEffect)(() => {
5161
6456
  const el = editor?.domElement;
5162
6457
  if (!el) return;
5163
6458
  const handleDragOver = (e) => {
@@ -5288,20 +6583,20 @@ function LumirEditor({
5288
6583
  el.removeEventListener("drop", handleDrop, { capture: true });
5289
6584
  };
5290
6585
  }, [editor, allowVideoUpload]);
5291
- const computedSideMenu = (0, import_react34.useMemo)(() => {
6586
+ const computedSideMenu = (0, import_react37.useMemo)(() => {
5292
6587
  return sideMenuAddButton ? sideMenu : false;
5293
6588
  }, [sideMenuAddButton, sideMenu]);
5294
- const DragHandleOnlySideMenu = (0, import_react34.useMemo)(() => {
5295
- return (props) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.SideMenu, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.DragHandleButton, { ...props }) });
6589
+ const DragHandleOnlySideMenu = (0, import_react37.useMemo)(() => {
6590
+ return (props) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.SideMenu, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.DragHandleButton, { ...props, dragHandleMenu: LumirDragHandleMenu }) });
5296
6591
  }, []);
5297
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6592
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5298
6593
  "div",
5299
6594
  {
5300
6595
  className: cn("lumirEditor", className),
5301
6596
  style: { position: "relative", display: "flex", flexDirection: "column" },
5302
6597
  children: [
5303
- floatingMenu && editor && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
5304
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6598
+ floatingMenu && editor && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
6599
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5305
6600
  "input",
5306
6601
  {
5307
6602
  ref: floatingMenuFileInputRef,
@@ -5372,7 +6667,7 @@ function LumirEditor({
5372
6667
  }
5373
6668
  }
5374
6669
  ),
5375
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6670
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5376
6671
  FloatingMenu,
5377
6672
  {
5378
6673
  editor,
@@ -5404,7 +6699,7 @@ function LumirEditor({
5404
6699
  }
5405
6700
  )
5406
6701
  ] }),
5407
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6702
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5408
6703
  import_mantine.BlockNoteView,
5409
6704
  {
5410
6705
  editor,
@@ -5419,21 +6714,21 @@ function LumirEditor({
5419
6714
  tableHandles: false,
5420
6715
  onSelectionChange,
5421
6716
  children: [
5422
- tableHandles && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LumirTableHandlesController, {}),
5423
- formattingToolbar && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5424
- import_react35.FormattingToolbarController,
6717
+ tableHandles && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(LumirTableHandlesController, {}),
6718
+ formattingToolbar && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6719
+ import_react38.FormattingToolbarController,
5425
6720
  {
5426
6721
  formattingToolbar: CustomFormattingToolbar
5427
6722
  }
5428
6723
  ),
5429
- linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.LinkToolbarController, { linkToolbar: CustomLinkToolbar }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.LinkToolbarController, {})),
5430
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5431
- import_react35.SuggestionMenuController,
6724
+ linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.LinkToolbarController, { linkToolbar: CustomLinkToolbar }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.LinkToolbarController, {})),
6725
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
6726
+ import_react38.SuggestionMenuController,
5432
6727
  {
5433
6728
  triggerCharacter: "/",
5434
- getItems: (0, import_react34.useCallback)(
6729
+ getItems: (0, import_react37.useCallback)(
5435
6730
  async (query) => {
5436
- const items = (0, import_react35.getDefaultReactSlashMenuItems)(editor);
6731
+ const items = (0, import_react38.getDefaultReactSlashMenuItems)(editor);
5437
6732
  const filtered = items.filter((item) => {
5438
6733
  const key = (item?.key || "").toString().toLowerCase();
5439
6734
  const title = (item?.title || "").toString().toLowerCase();
@@ -5475,7 +6770,7 @@ function LumirEditor({
5475
6770
  },
5476
6771
  aliases: ["html", "preview", "\uC6F9", "\uC6F9\uD398\uC774\uC9C0"],
5477
6772
  group: "Embeds",
5478
- icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6773
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5479
6774
  "svg",
5480
6775
  {
5481
6776
  width: "18",
@@ -5487,19 +6782,45 @@ function LumirEditor({
5487
6782
  strokeLinecap: "round",
5488
6783
  strokeLinejoin: "round",
5489
6784
  children: [
5490
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("polyline", { points: "16 18 22 12 16 6" }),
5491
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("polyline", { points: "8 6 2 12 8 18" })
6785
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("polyline", { points: "16 18 22 12 16 6" }),
6786
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("polyline", { points: "8 6 2 12 8 18" })
5492
6787
  ]
5493
6788
  }
5494
6789
  ),
5495
6790
  subtext: "HTML \uD30C\uC77C\uC744 \uBBF8\uB9AC\uBCF4\uAE30\uB85C \uC0BD\uC785"
5496
6791
  };
5497
- const allItems = [...filtered, htmlPreviewItem];
6792
+ const columnItem = {
6793
+ title: "2\uB2E8 \uCEEC\uB7FC",
6794
+ onItemClick: () => {
6795
+ insertTwoColumns(editor);
6796
+ },
6797
+ aliases: ["columns", "column", "2col", "\uB2E8", "\uCEEC\uB7FC", "\uB2E4\uB2E8", "\uBD84\uD560"],
6798
+ group: "Basic blocks",
6799
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
6800
+ "svg",
6801
+ {
6802
+ width: "18",
6803
+ height: "18",
6804
+ viewBox: "0 0 24 24",
6805
+ fill: "none",
6806
+ stroke: "currentColor",
6807
+ strokeWidth: "2",
6808
+ strokeLinecap: "round",
6809
+ strokeLinejoin: "round",
6810
+ children: [
6811
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("rect", { x: "3", y: "4", width: "7", height: "16", rx: "1" }),
6812
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("rect", { x: "14", y: "4", width: "7", height: "16", rx: "1" })
6813
+ ]
6814
+ }
6815
+ ),
6816
+ subtext: "\uBE14\uB85D\uC744 \uC88C\uC6B0 2\uB2E8\uC73C\uB85C \uBC30\uCE58"
6817
+ };
6818
+ const allItems = [...filtered, htmlPreviewItem, columnItem];
5498
6819
  if (linkPreview?.apiEndpoint) {
5499
6820
  allItems.push({
5500
6821
  title: "Link Preview",
5501
6822
  onItemClick: () => {
5502
- (0, import_core5.insertOrUpdateBlock)(editor, {
6823
+ (0, import_core9.insertOrUpdateBlock)(editor, {
5503
6824
  type: "linkPreview",
5504
6825
  props: { url: "" }
5505
6826
  });
@@ -5513,7 +6834,7 @@ function LumirEditor({
5513
6834
  "\uD504\uB9AC\uBDF0"
5514
6835
  ],
5515
6836
  group: "Embeds",
5516
- icon: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
6837
+ icon: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
5517
6838
  "svg",
5518
6839
  {
5519
6840
  width: "18",
@@ -5525,8 +6846,8 @@ function LumirEditor({
5525
6846
  strokeLinecap: "round",
5526
6847
  strokeLinejoin: "round",
5527
6848
  children: [
5528
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
5529
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
6849
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
6850
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
5530
6851
  ]
5531
6852
  }
5532
6853
  ),
@@ -5562,21 +6883,21 @@ function LumirEditor({
5562
6883
  )
5563
6884
  }
5564
6885
  ),
5565
- !sideMenuAddButton && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react35.SideMenuController, { sideMenu: DragHandleOnlySideMenu })
6886
+ !sideMenuAddButton && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react38.SideMenuController, { sideMenu: DragHandleOnlySideMenu })
5566
6887
  ]
5567
6888
  }
5568
6889
  ),
5569
- isUploading && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "lumirEditor-upload-overlay", children: [
5570
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "lumirEditor-spinner" }),
5571
- uploadProgress !== null && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "lumirEditor-upload-progress", children: [
6890
+ isUploading && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "lumirEditor-upload-overlay", children: [
6891
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "lumirEditor-spinner" }),
6892
+ uploadProgress !== null && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "lumirEditor-upload-progress", children: [
5572
6893
  uploadProgress,
5573
6894
  "%"
5574
6895
  ] })
5575
6896
  ] }),
5576
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "lumirEditor-error-toast", children: [
5577
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "lumirEditor-error-icon", children: "\u26A0\uFE0F" }),
5578
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "lumirEditor-error-message", children: errorMessage }),
5579
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
6897
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "lumirEditor-error-toast", children: [
6898
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "lumirEditor-error-icon", children: "\u26A0\uFE0F" }),
6899
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "lumirEditor-error-message", children: errorMessage }),
6900
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5580
6901
  "button",
5581
6902
  {
5582
6903
  className: "lumirEditor-error-close",