@lumir-company/editor 0.4.17 → 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/README.md +7 -0
- package/dist/index.js +149 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +149 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1478,6 +1478,13 @@ const url = await uploader(imageFile);
|
|
|
1478
1478
|
|
|
1479
1479
|
## 변경 로그
|
|
1480
1480
|
|
|
1481
|
+
### v0.4.18
|
|
1482
|
+
|
|
1483
|
+
- **표 열 삭제 버그 수정 (병합 셀 포함)**
|
|
1484
|
+
- 그립 메뉴로 첫 열/행 삭제 시, 그립 클릭으로 ProseMirror 선택이 표 밖으로 빠져 삭제가 무시되던 문제 수정(삭제 대상 표를 포커스 표 기준으로 결정적으로 탐색)
|
|
1485
|
+
- **세로 병합(rowspan) 인접 열**이 있을 때 첫 열이 삭제되지 않던 문제 수정 — 코어 prosemirror-tables가 행의 유일 셀을 지울 때 빈 셀을 남겨(`tableRow+` 스키마) `fixTables`가 원복하던 케이스. 열 삭제를 표 재구성 방식으로 변경해 colspan/rowspan 병합을 안전하게 처리
|
|
1486
|
+
- 병합 셀이 행 축소로 collapse될 때 **행 높이를 보존**(원래 차지하던 행 높이 합을 유지)
|
|
1487
|
+
|
|
1481
1488
|
### v0.4.17
|
|
1482
1489
|
|
|
1483
1490
|
- **표 행 높이(세로) 리사이즈**
|
package/dist/index.js
CHANGED
|
@@ -4858,6 +4858,9 @@ function LumirTableHandlesController() {
|
|
|
4858
4858
|
const frozenRef = (0, import_react36.useRef)(false);
|
|
4859
4859
|
const menuOpenRef = (0, import_react36.useRef)(false);
|
|
4860
4860
|
const draggingRef = (0, import_react36.useRef)(false);
|
|
4861
|
+
(0, import_react36.useEffect)(() => {
|
|
4862
|
+
editor.__lumirActiveTableId = focused?.block?.id ?? null;
|
|
4863
|
+
}, [editor, focused]);
|
|
4861
4864
|
const recompute = (0, import_react36.useCallback)(() => {
|
|
4862
4865
|
if (frozenRef.current) {
|
|
4863
4866
|
return;
|
|
@@ -5400,6 +5403,140 @@ function liftFontSize(blocks) {
|
|
|
5400
5403
|
return mapPreservingRef(blocks, (b) => mapBlock(b, "lift"));
|
|
5401
5404
|
}
|
|
5402
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
|
+
|
|
5403
5540
|
// src/utils/excel-paste.ts
|
|
5404
5541
|
var NAMED_COLORS = {
|
|
5405
5542
|
black: "#000000",
|
|
@@ -6253,6 +6390,18 @@ function LumirEditor({
|
|
|
6253
6390
|
editor.isEditable = editable;
|
|
6254
6391
|
}
|
|
6255
6392
|
}, [editor, editable]);
|
|
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]);
|
|
6256
6405
|
(0, import_react37.useEffect)(() => {
|
|
6257
6406
|
if (!editor || !floatingMenu) return;
|
|
6258
6407
|
const ft = editor.formattingToolbar;
|