@lumir-company/editor 0.4.19 → 0.4.21
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 +35 -19
- package/dist/index.d.mts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +253 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +242 -31
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +13 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
48
48
|
var import_react37 = require("react");
|
|
49
49
|
var import_react38 = require("@blocknote/react");
|
|
50
50
|
var import_mantine = require("@blocknote/mantine");
|
|
51
|
-
var
|
|
51
|
+
var import_core10 = require("@blocknote/core");
|
|
52
52
|
var import_locales = require("@blocknote/core/locales");
|
|
53
53
|
|
|
54
54
|
// src/utils/cn.ts
|
|
@@ -1490,6 +1490,16 @@ var ColumnList = (0, import_core.createStronglyTypedTiptapNode)({
|
|
|
1490
1490
|
name: "columnList",
|
|
1491
1491
|
group: "childContainer bnBlock blockGroupChild",
|
|
1492
1492
|
content: "column column+",
|
|
1493
|
+
addAttributes() {
|
|
1494
|
+
return {
|
|
1495
|
+
// 블록별 중앙 세로 구분선 표시 여부(드래그핸들 메뉴에서 토글). data-divider로 렌더.
|
|
1496
|
+
showDivider: {
|
|
1497
|
+
default: false,
|
|
1498
|
+
parseHTML: (element) => element.getAttribute("data-divider") === "true",
|
|
1499
|
+
renderHTML: (attributes) => attributes.showDivider ? { "data-divider": "true" } : {}
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
},
|
|
1493
1503
|
parseHTML() {
|
|
1494
1504
|
return [{ tag: 'div[data-node-type="columnList"]' }];
|
|
1495
1505
|
},
|
|
@@ -1938,7 +1948,8 @@ var HtmlPreviewBlock = (0, import_react6.createReactBlockSpec)(
|
|
|
1938
1948
|
);
|
|
1939
1949
|
var ColumnListBlock = (0, import_core3.createBlockSpecFromStronglyTypedTiptapNode)(
|
|
1940
1950
|
ColumnList,
|
|
1941
|
-
|
|
1951
|
+
// showDivider를 블록 prop으로 등록 → onContentChange JSON 직렬화 + 재로드 라운드트립.
|
|
1952
|
+
{ showDivider: { default: false } }
|
|
1942
1953
|
);
|
|
1943
1954
|
var ColumnBlock = (0, import_core3.createBlockSpecFromStronglyTypedTiptapNode)(Column, {});
|
|
1944
1955
|
var schema = import_core3.BlockNoteSchema.create({
|
|
@@ -4099,9 +4110,56 @@ var TableAlignmentExtension = import_core6.Extension.create({
|
|
|
4099
4110
|
}
|
|
4100
4111
|
});
|
|
4101
4112
|
|
|
4113
|
+
// src/extensions/TableSelectAllExtension.ts
|
|
4114
|
+
var import_core7 = require("@tiptap/core");
|
|
4115
|
+
var import_prosemirror_tables3 = require("prosemirror-tables");
|
|
4116
|
+
var TableSelectAllExtension = import_core7.Extension.create({
|
|
4117
|
+
name: "lumirTableSelectAll",
|
|
4118
|
+
priority: 1e3,
|
|
4119
|
+
addKeyboardShortcuts() {
|
|
4120
|
+
return {
|
|
4121
|
+
"Mod-a": () => {
|
|
4122
|
+
const view = this.editor.view;
|
|
4123
|
+
const { state } = view;
|
|
4124
|
+
const sel = state.selection;
|
|
4125
|
+
const $from = sel.$from;
|
|
4126
|
+
let depth = -1;
|
|
4127
|
+
for (let d = $from.depth; d > 0; d--) {
|
|
4128
|
+
if ($from.node(d).type.name === "table") {
|
|
4129
|
+
depth = d;
|
|
4130
|
+
break;
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
if (depth < 0) return false;
|
|
4134
|
+
const table = $from.node(depth);
|
|
4135
|
+
const tableStart = $from.start(depth);
|
|
4136
|
+
const map = import_prosemirror_tables3.TableMap.get(table);
|
|
4137
|
+
const firstRel = map.map[0];
|
|
4138
|
+
const lastRel = map.map[map.map.length - 1];
|
|
4139
|
+
if (sel instanceof import_prosemirror_tables3.CellSelection) {
|
|
4140
|
+
const a = sel.$anchorCell.pos - tableStart;
|
|
4141
|
+
const h = sel.$headCell.pos - tableStart;
|
|
4142
|
+
if (Math.min(a, h) === firstRel && Math.max(a, h) === lastRel) {
|
|
4143
|
+
return false;
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
const tr = state.tr.setSelection(
|
|
4147
|
+
import_prosemirror_tables3.CellSelection.create(
|
|
4148
|
+
state.doc,
|
|
4149
|
+
tableStart + firstRel,
|
|
4150
|
+
tableStart + lastRel
|
|
4151
|
+
)
|
|
4152
|
+
);
|
|
4153
|
+
view.dispatch(tr);
|
|
4154
|
+
return true;
|
|
4155
|
+
}
|
|
4156
|
+
};
|
|
4157
|
+
}
|
|
4158
|
+
});
|
|
4159
|
+
|
|
4102
4160
|
// src/blocks/columns/insertColumns.ts
|
|
4103
4161
|
var import_prosemirror_state7 = require("prosemirror-state");
|
|
4104
|
-
function insertTwoColumns(editor) {
|
|
4162
|
+
function insertTwoColumns(editor, showDivider = false) {
|
|
4105
4163
|
const tiptap = editor?._tiptapEditor;
|
|
4106
4164
|
if (!tiptap) {
|
|
4107
4165
|
return false;
|
|
@@ -4128,7 +4186,7 @@ function insertTwoColumns(editor) {
|
|
|
4128
4186
|
const insertPos = $from.after(depth);
|
|
4129
4187
|
const mkBlock = () => blockContainer.create(null, paragraph.create());
|
|
4130
4188
|
const mkColumn = () => column.create(null, mkBlock());
|
|
4131
|
-
const list = columnList.create(
|
|
4189
|
+
const list = columnList.create({ showDivider }, [mkColumn(), mkColumn()]);
|
|
4132
4190
|
try {
|
|
4133
4191
|
let tr = state.tr.insert(insertPos, list);
|
|
4134
4192
|
try {
|
|
@@ -4146,7 +4204,7 @@ function insertTwoColumns(editor) {
|
|
|
4146
4204
|
var import_react30 = require("@blocknote/react");
|
|
4147
4205
|
|
|
4148
4206
|
// src/components/TextAlignButtonWithVA.tsx
|
|
4149
|
-
var
|
|
4207
|
+
var import_core8 = require("@blocknote/core");
|
|
4150
4208
|
var import_react20 = require("react");
|
|
4151
4209
|
var import_react21 = require("@blocknote/react");
|
|
4152
4210
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
@@ -4168,7 +4226,7 @@ var TextAlignButtonWithVA = (props) => {
|
|
|
4168
4226
|
const selectedBlocks = (0, import_react21.useSelectedBlocks)(editor);
|
|
4169
4227
|
const textAlignment = (0, import_react20.useMemo)(() => {
|
|
4170
4228
|
const block = selectedBlocks[0];
|
|
4171
|
-
if ((0,
|
|
4229
|
+
if ((0, import_core8.checkBlockHasDefaultProp)("textAlignment", block, editor)) {
|
|
4172
4230
|
return block.props.textAlignment;
|
|
4173
4231
|
}
|
|
4174
4232
|
if (block.type === "table") {
|
|
@@ -4177,7 +4235,7 @@ var TextAlignButtonWithVA = (props) => {
|
|
|
4177
4235
|
return;
|
|
4178
4236
|
}
|
|
4179
4237
|
const allCellsInTable = cellSelection.cells.map(
|
|
4180
|
-
({ row, col }) => (0,
|
|
4238
|
+
({ row, col }) => (0, import_core8.mapTableCell)(
|
|
4181
4239
|
block.content.rows[row].cells[col]
|
|
4182
4240
|
).props.textAlignment
|
|
4183
4241
|
);
|
|
@@ -4209,7 +4267,7 @@ var TextAlignButtonWithVA = (props) => {
|
|
|
4209
4267
|
}
|
|
4210
4268
|
}
|
|
4211
4269
|
tiptap.view?.dispatch(tr);
|
|
4212
|
-
} else if ((0,
|
|
4270
|
+
} else if ((0, import_core8.checkBlockTypeHasDefaultProp)("textAlignment", block.type, editor)) {
|
|
4213
4271
|
editor.updateBlock(block, {
|
|
4214
4272
|
props: { textAlignment: newAlignment }
|
|
4215
4273
|
});
|
|
@@ -4482,7 +4540,7 @@ function FontSizeButton2() {
|
|
|
4482
4540
|
}
|
|
4483
4541
|
|
|
4484
4542
|
// src/components/color/LumirColorControls.tsx
|
|
4485
|
-
var
|
|
4543
|
+
var import_core9 = require("@blocknote/core");
|
|
4486
4544
|
var import_react28 = require("@blocknote/react");
|
|
4487
4545
|
var import_react29 = require("react");
|
|
4488
4546
|
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
@@ -4730,7 +4788,7 @@ function LumirCellColorPickerButton(props) {
|
|
|
4730
4788
|
const updateColor = (color, type) => {
|
|
4731
4789
|
const newTable = props.block.content.rows.map((row) => ({
|
|
4732
4790
|
...row,
|
|
4733
|
-
cells: row.cells.map((cell) => (0,
|
|
4791
|
+
cells: row.cells.map((cell) => (0, import_core9.mapTableCell)(cell))
|
|
4734
4792
|
}));
|
|
4735
4793
|
if (type === "text") {
|
|
4736
4794
|
newTable[props.rowIndex].cells[props.colIndex].props.textColor = color;
|
|
@@ -4761,11 +4819,11 @@ function LumirCellColorPickerButton(props) {
|
|
|
4761
4819
|
textTitle: "\uC140 \uAE00\uC790\uC0C9",
|
|
4762
4820
|
backgroundTitle: "\uC140 \uBC30\uACBD",
|
|
4763
4821
|
text: editor.settings.tables.cellTextColor ? {
|
|
4764
|
-
color: (0,
|
|
4822
|
+
color: (0, import_core9.isTableCell)(currentCell) ? currentCell.props.textColor : "default",
|
|
4765
4823
|
setColor: (color) => updateColor(color, "text")
|
|
4766
4824
|
} : void 0,
|
|
4767
4825
|
background: editor.settings.tables.cellBackgroundColor ? {
|
|
4768
|
-
color: (0,
|
|
4826
|
+
color: (0, import_core9.isTableCell)(currentCell) ? currentCell.props.backgroundColor : "default",
|
|
4769
4827
|
setColor: (color) => updateColor(color, "background")
|
|
4770
4828
|
} : void 0
|
|
4771
4829
|
}
|
|
@@ -5654,7 +5712,7 @@ function liftFontSize(blocks) {
|
|
|
5654
5712
|
}
|
|
5655
5713
|
|
|
5656
5714
|
// src/utils/table-delete.ts
|
|
5657
|
-
var
|
|
5715
|
+
var import_prosemirror_tables4 = require("prosemirror-tables");
|
|
5658
5716
|
function measureRowHeights(view, tablePos) {
|
|
5659
5717
|
try {
|
|
5660
5718
|
const at = view?.domAtPos?.(tablePos + 1);
|
|
@@ -5673,7 +5731,7 @@ function measureRowHeights(view, tablePos) {
|
|
|
5673
5731
|
function buildDeleteColumnTr(state, tablePos, col, rowPx) {
|
|
5674
5732
|
const table = state.doc.nodeAt(tablePos);
|
|
5675
5733
|
if (!table || table.type.name !== "table") return null;
|
|
5676
|
-
const map =
|
|
5734
|
+
const map = import_prosemirror_tables4.TableMap.get(table);
|
|
5677
5735
|
const W = map.width;
|
|
5678
5736
|
const H = map.height;
|
|
5679
5737
|
if (col < 0 || col >= W || W <= 1) return null;
|
|
@@ -5779,9 +5837,9 @@ function removeFocusedRowOrColumn(editor, index, direction) {
|
|
|
5779
5837
|
const rowStart = state.doc.resolve(tableInside.posAtIndex(index) + 1);
|
|
5780
5838
|
const cellPos = state.doc.resolve(rowStart.posAtIndex(0));
|
|
5781
5839
|
const selState = state.apply(
|
|
5782
|
-
state.tr.setSelection(new
|
|
5840
|
+
state.tr.setSelection(new import_prosemirror_tables4.CellSelection(cellPos))
|
|
5783
5841
|
);
|
|
5784
|
-
return (0,
|
|
5842
|
+
return (0, import_prosemirror_tables4.deleteRow)(selState, (tr) => tiptap.view.dispatch(tr));
|
|
5785
5843
|
} catch {
|
|
5786
5844
|
return false;
|
|
5787
5845
|
}
|
|
@@ -5931,6 +5989,20 @@ function normalizeAlign(ta) {
|
|
|
5931
5989
|
if (v === "justify") return "justify";
|
|
5932
5990
|
return "";
|
|
5933
5991
|
}
|
|
5992
|
+
function mapVerticalAlign(v) {
|
|
5993
|
+
const s = (v || "").trim().toLowerCase();
|
|
5994
|
+
if (s === "middle" || s === "center") return "middle";
|
|
5995
|
+
if (s === "bottom") return "bottom";
|
|
5996
|
+
return null;
|
|
5997
|
+
}
|
|
5998
|
+
function fontSizeToPx(raw) {
|
|
5999
|
+
if (!raw) return null;
|
|
6000
|
+
const m = String(raw).trim().match(/^([\d.]+)\s*(px|pt)?$/i);
|
|
6001
|
+
if (!m) return null;
|
|
6002
|
+
const v = parseFloat(m[1]);
|
|
6003
|
+
if (!Number.isFinite(v) || v <= 0) return null;
|
|
6004
|
+
return (m[2] || "px").toLowerCase() === "pt" ? v * (96 / 72) : v;
|
|
6005
|
+
}
|
|
5934
6006
|
function applyCellFormatting(el, fmt) {
|
|
5935
6007
|
if (fmt.bgRgb && !fmt.bgTransparent) {
|
|
5936
6008
|
const v = nearestBackgroundColorValue(fmt.bgRgb);
|
|
@@ -5950,6 +6022,13 @@ function applyCellFormatting(el, fmt) {
|
|
|
5950
6022
|
if (fmt.bold) inner = `<strong>${inner}</strong>`;
|
|
5951
6023
|
el.innerHTML = inner;
|
|
5952
6024
|
}
|
|
6025
|
+
if (fmt.verticalAlign) {
|
|
6026
|
+
el.setAttribute("data-vertical-alignment", fmt.verticalAlign);
|
|
6027
|
+
}
|
|
6028
|
+
if (fmt.fontSizePx && Math.abs(fmt.fontSizePx - 14) > 1 && el.innerHTML.trim()) {
|
|
6029
|
+
const v = `${Math.round(fmt.fontSizePx)}px`;
|
|
6030
|
+
el.innerHTML = `<span data-style-type="fontSize" data-value="${v}" style="font-size:${v}">` + el.innerHTML + `</span>`;
|
|
6031
|
+
}
|
|
5953
6032
|
}
|
|
5954
6033
|
function readComputedFormat(el) {
|
|
5955
6034
|
const cs = getComputedStyle(el);
|
|
@@ -5963,7 +6042,13 @@ function readComputedFormat(el) {
|
|
|
5963
6042
|
align: normalizeAlign(cs.textAlign),
|
|
5964
6043
|
bold: fw === "bold" || fw === "bolder" || !isNaN(fwNum) && fwNum >= 600,
|
|
5965
6044
|
italic: (cs.fontStyle || "").toLowerCase().includes("italic"),
|
|
5966
|
-
underline: decoration.toLowerCase().includes("underline")
|
|
6045
|
+
underline: decoration.toLowerCase().includes("underline"),
|
|
6046
|
+
fontSizePx: fontSizeToPx(cs.fontSize),
|
|
6047
|
+
// ⚠️ computed vertical-align은 td 기본값이 "middle"이라 셀마다 잘못 붙는다.
|
|
6048
|
+
// 명시적 inline style / valign 속성만 읽는다(기본값 노이즈 방지).
|
|
6049
|
+
verticalAlign: mapVerticalAlign(
|
|
6050
|
+
el.style?.verticalAlign || el.getAttribute("valign")
|
|
6051
|
+
)
|
|
5967
6052
|
};
|
|
5968
6053
|
}
|
|
5969
6054
|
function readInlineFormat(el) {
|
|
@@ -5979,7 +6064,11 @@ function readInlineFormat(el) {
|
|
|
5979
6064
|
align: normalizeAlign(sm["text-align"] || el.getAttribute("align")),
|
|
5980
6065
|
bold: fw === "bold" || fw === "bolder" || parseInt(fw, 10) >= 600,
|
|
5981
6066
|
italic: (sm["font-style"] || "").toLowerCase().includes("italic"),
|
|
5982
|
-
underline: decoration.toLowerCase().includes("underline")
|
|
6067
|
+
underline: decoration.toLowerCase().includes("underline"),
|
|
6068
|
+
fontSizePx: fontSizeToPx(sm["font-size"]),
|
|
6069
|
+
verticalAlign: mapVerticalAlign(
|
|
6070
|
+
sm["vertical-align"] || el.getAttribute("valign")
|
|
6071
|
+
)
|
|
5983
6072
|
};
|
|
5984
6073
|
}
|
|
5985
6074
|
function normalizeExcelTableHtml(html) {
|
|
@@ -5993,7 +6082,7 @@ function normalizeExcelTableHtml(html) {
|
|
|
5993
6082
|
try {
|
|
5994
6083
|
host = document.createElement("div");
|
|
5995
6084
|
host.setAttribute("aria-hidden", "true");
|
|
5996
|
-
host.style.cssText = "position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;opacity:0;pointer-events:none";
|
|
6085
|
+
host.style.cssText = "position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;opacity:0;pointer-events:none;font-size:14px";
|
|
5997
6086
|
const shadow = host.attachShadow({ mode: "open" });
|
|
5998
6087
|
const styles = Array.from(doc.querySelectorAll("style")).map((s) => s.outerHTML).join("");
|
|
5999
6088
|
shadow.innerHTML = styles + doc.body.innerHTML;
|
|
@@ -6016,6 +6105,100 @@ function normalizeExcelTableHtml(html) {
|
|
|
6016
6105
|
}
|
|
6017
6106
|
}
|
|
6018
6107
|
|
|
6108
|
+
// src/utils/table-paste-fit.ts
|
|
6109
|
+
var MIN_COL_PX = 24;
|
|
6110
|
+
function toPx(raw, maxWidth) {
|
|
6111
|
+
if (!raw) return null;
|
|
6112
|
+
const m = String(raw).trim().match(/^([\d.]+)\s*(pt|px|%)?$/i);
|
|
6113
|
+
if (!m) return null;
|
|
6114
|
+
const v = parseFloat(m[1]);
|
|
6115
|
+
if (!Number.isFinite(v) || v <= 0) return null;
|
|
6116
|
+
const unit = (m[2] || "px").toLowerCase();
|
|
6117
|
+
if (unit === "pt") return v * (96 / 72);
|
|
6118
|
+
if (unit === "%") return v / 100 * maxWidth;
|
|
6119
|
+
return v;
|
|
6120
|
+
}
|
|
6121
|
+
function elWidthPx(el, maxWidth) {
|
|
6122
|
+
const styleW = el.style?.width;
|
|
6123
|
+
return toPx(styleW, maxWidth) ?? toPx(el.getAttribute("width"), maxWidth);
|
|
6124
|
+
}
|
|
6125
|
+
function readColumnWidths(table, maxWidth) {
|
|
6126
|
+
const colEls = table.querySelector("colgroup")?.querySelectorAll("col");
|
|
6127
|
+
if (colEls && colEls.length > 0) {
|
|
6128
|
+
const widths2 = [];
|
|
6129
|
+
let ok2 = true;
|
|
6130
|
+
colEls.forEach((c) => {
|
|
6131
|
+
const span = parseInt(c.getAttribute("span") || "1", 10) || 1;
|
|
6132
|
+
const w = elWidthPx(c, maxWidth);
|
|
6133
|
+
if (w == null) ok2 = false;
|
|
6134
|
+
for (let i = 0; i < span; i++) widths2.push(w ?? 0);
|
|
6135
|
+
});
|
|
6136
|
+
if (ok2 && widths2.length > 0) return widths2;
|
|
6137
|
+
}
|
|
6138
|
+
const firstRow = table.querySelector("tr");
|
|
6139
|
+
if (!firstRow) return null;
|
|
6140
|
+
const widths = [];
|
|
6141
|
+
let ok = true;
|
|
6142
|
+
Array.from(firstRow.children).forEach((cell) => {
|
|
6143
|
+
if (cell.tagName !== "TD" && cell.tagName !== "TH") return;
|
|
6144
|
+
const span = parseInt(cell.getAttribute("colspan") || "1", 10) || 1;
|
|
6145
|
+
const w = elWidthPx(cell, maxWidth);
|
|
6146
|
+
if (w == null) ok = false;
|
|
6147
|
+
const per = (w ?? 0) / span;
|
|
6148
|
+
for (let i = 0; i < span; i++) widths.push(per);
|
|
6149
|
+
});
|
|
6150
|
+
return ok && widths.length > 0 ? widths : null;
|
|
6151
|
+
}
|
|
6152
|
+
function fitWidths(widths, maxWidth) {
|
|
6153
|
+
const total = widths.reduce((a, b) => a + b, 0);
|
|
6154
|
+
if (total <= 0) return widths;
|
|
6155
|
+
const scale = total > maxWidth ? maxWidth / total : 1;
|
|
6156
|
+
return widths.map((w) => Math.max(MIN_COL_PX, Math.round(w * scale)));
|
|
6157
|
+
}
|
|
6158
|
+
function computeFittedColumnWidthsPerTable(html, maxWidth) {
|
|
6159
|
+
if (!html || typeof DOMParser === "undefined" || !(maxWidth > 0)) return [];
|
|
6160
|
+
let doc;
|
|
6161
|
+
try {
|
|
6162
|
+
doc = new DOMParser().parseFromString(html, "text/html");
|
|
6163
|
+
} catch {
|
|
6164
|
+
return [];
|
|
6165
|
+
}
|
|
6166
|
+
return Array.from(doc.querySelectorAll("table")).map((t) => {
|
|
6167
|
+
const widths = readColumnWidths(t, maxWidth);
|
|
6168
|
+
return widths ? fitWidths(widths, maxWidth) : null;
|
|
6169
|
+
});
|
|
6170
|
+
}
|
|
6171
|
+
function collectTableBlocks(blocks) {
|
|
6172
|
+
const out = [];
|
|
6173
|
+
const walk = (bs) => {
|
|
6174
|
+
for (const b of bs) {
|
|
6175
|
+
if (b?.type === "table") out.push(b);
|
|
6176
|
+
if (b?.children?.length) walk(b.children);
|
|
6177
|
+
}
|
|
6178
|
+
};
|
|
6179
|
+
walk(blocks || []);
|
|
6180
|
+
return out;
|
|
6181
|
+
}
|
|
6182
|
+
function applyFittedWidthsToNewTables(editor, beforeIds, perTable) {
|
|
6183
|
+
if (!editor || perTable.length === 0) return;
|
|
6184
|
+
const newTables = collectTableBlocks(editor.document).filter(
|
|
6185
|
+
(b) => !beforeIds.has(b.id)
|
|
6186
|
+
);
|
|
6187
|
+
newTables.forEach((tb, i) => {
|
|
6188
|
+
const widths = perTable[i];
|
|
6189
|
+
const current = tb?.content?.columnWidths;
|
|
6190
|
+
if (widths && Array.isArray(current) && current.length === widths.length) {
|
|
6191
|
+
try {
|
|
6192
|
+
editor.updateBlock(tb, {
|
|
6193
|
+
type: "table",
|
|
6194
|
+
content: { ...tb.content, columnWidths: widths }
|
|
6195
|
+
});
|
|
6196
|
+
} catch {
|
|
6197
|
+
}
|
|
6198
|
+
}
|
|
6199
|
+
});
|
|
6200
|
+
}
|
|
6201
|
+
|
|
6019
6202
|
// src/components/LumirEditor.tsx
|
|
6020
6203
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
6021
6204
|
var DEBUG_LOG = (loc, msg, data) => {
|
|
@@ -6442,7 +6625,9 @@ function LumirEditor({
|
|
|
6442
6625
|
// tableHandles prop으로 게이트(기존 grip 컨트롤러와 동일 게이트).
|
|
6443
6626
|
RowHeightExtension.configure({ resizable: tableHandles }),
|
|
6444
6627
|
// 표 블록 정렬(좌/가운데/우) attr.
|
|
6445
|
-
TableAlignmentExtension
|
|
6628
|
+
TableAlignmentExtension,
|
|
6629
|
+
// 셀 포커스 시 Ctrl/Cmd+A → 표 전체 선택.
|
|
6630
|
+
TableSelectAllExtension
|
|
6446
6631
|
]
|
|
6447
6632
|
},
|
|
6448
6633
|
placeholders: placeholder ? { default: placeholder, emptyDocument: placeholder } : void 0,
|
|
@@ -6548,7 +6733,14 @@ function LumirEditor({
|
|
|
6548
6733
|
hasFiles: !!event?.clipboardData?.files?.length
|
|
6549
6734
|
});
|
|
6550
6735
|
event.preventDefault();
|
|
6736
|
+
const pmDom = editor2.prosemirrorView?.dom;
|
|
6737
|
+
const maxWidth = pmDom?.clientWidth ? pmDom.clientWidth - 8 : 0;
|
|
6738
|
+
const fittedWidths = computeFittedColumnWidthsPerTable(pastedHtml, maxWidth);
|
|
6739
|
+
const beforeTableIds = new Set(
|
|
6740
|
+
collectTableBlocks(editor2.document).map((b) => b.id)
|
|
6741
|
+
);
|
|
6551
6742
|
editor2.pasteHTML(normalizeExcelTableHtml(pastedHtml));
|
|
6743
|
+
applyFittedWidthsToNewTables(editor2, beforeTableIds, fittedWidths);
|
|
6552
6744
|
return true;
|
|
6553
6745
|
}
|
|
6554
6746
|
const fileList = event?.clipboardData?.files ?? null;
|
|
@@ -7044,38 +7236,57 @@ function LumirEditor({
|
|
|
7044
7236
|
),
|
|
7045
7237
|
subtext: "HTML \uD30C\uC77C\uC744 \uBBF8\uB9AC\uBCF4\uAE30\uB85C \uC0BD\uC785"
|
|
7046
7238
|
};
|
|
7239
|
+
const columnIcon = (withDivider) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
7240
|
+
"svg",
|
|
7241
|
+
{
|
|
7242
|
+
width: "18",
|
|
7243
|
+
height: "18",
|
|
7244
|
+
viewBox: "0 0 24 24",
|
|
7245
|
+
fill: "none",
|
|
7246
|
+
stroke: "currentColor",
|
|
7247
|
+
strokeWidth: "2",
|
|
7248
|
+
strokeLinecap: "round",
|
|
7249
|
+
strokeLinejoin: "round",
|
|
7250
|
+
children: [
|
|
7251
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("rect", { x: "3", y: "4", width: "7", height: "16", rx: "1" }),
|
|
7252
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("rect", { x: "14", y: "4", width: "7", height: "16", rx: "1" }),
|
|
7253
|
+
withDivider && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("line", { x1: "12", y1: "3", x2: "12", y2: "21", strokeDasharray: "2 2" })
|
|
7254
|
+
]
|
|
7255
|
+
}
|
|
7256
|
+
);
|
|
7047
7257
|
const columnItem = {
|
|
7048
7258
|
title: "2\uB2E8 \uCEEC\uB7FC",
|
|
7049
|
-
onItemClick: () =>
|
|
7050
|
-
insertTwoColumns(editor);
|
|
7051
|
-
},
|
|
7259
|
+
onItemClick: () => insertTwoColumns(editor, false),
|
|
7052
7260
|
aliases: ["columns", "column", "2col", "\uB2E8", "\uCEEC\uB7FC", "\uB2E4\uB2E8", "\uBD84\uD560"],
|
|
7053
7261
|
group: "Basic blocks",
|
|
7054
|
-
icon:
|
|
7055
|
-
"svg",
|
|
7056
|
-
{
|
|
7057
|
-
width: "18",
|
|
7058
|
-
height: "18",
|
|
7059
|
-
viewBox: "0 0 24 24",
|
|
7060
|
-
fill: "none",
|
|
7061
|
-
stroke: "currentColor",
|
|
7062
|
-
strokeWidth: "2",
|
|
7063
|
-
strokeLinecap: "round",
|
|
7064
|
-
strokeLinejoin: "round",
|
|
7065
|
-
children: [
|
|
7066
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("rect", { x: "3", y: "4", width: "7", height: "16", rx: "1" }),
|
|
7067
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("rect", { x: "14", y: "4", width: "7", height: "16", rx: "1" })
|
|
7068
|
-
]
|
|
7069
|
-
}
|
|
7070
|
-
),
|
|
7262
|
+
icon: columnIcon(false),
|
|
7071
7263
|
subtext: "\uBE14\uB85D\uC744 \uC88C\uC6B0 2\uB2E8\uC73C\uB85C \uBC30\uCE58"
|
|
7072
7264
|
};
|
|
7073
|
-
const
|
|
7265
|
+
const columnDividerItem = {
|
|
7266
|
+
title: "2\uB2E8 \uCEEC\uB7FC (\uAD6C\uBD84\uC120)",
|
|
7267
|
+
onItemClick: () => insertTwoColumns(editor, true),
|
|
7268
|
+
aliases: [
|
|
7269
|
+
"columns divider",
|
|
7270
|
+
"\uAD6C\uBD84\uC120",
|
|
7271
|
+
"\uCEEC\uB7FC \uAD6C\uBD84\uC120",
|
|
7272
|
+
"2\uB2E8 \uAD6C\uBD84\uC120",
|
|
7273
|
+
"divider"
|
|
7274
|
+
],
|
|
7275
|
+
group: "Basic blocks",
|
|
7276
|
+
icon: columnIcon(true),
|
|
7277
|
+
subtext: "\uAC00\uC6B4\uB370 \uC138\uB85C \uAD6C\uBD84\uC120\uC774 \uC788\uB294 2\uB2E8 \uCEEC\uB7FC"
|
|
7278
|
+
};
|
|
7279
|
+
const allItems = [
|
|
7280
|
+
...filtered,
|
|
7281
|
+
htmlPreviewItem,
|
|
7282
|
+
columnItem,
|
|
7283
|
+
columnDividerItem
|
|
7284
|
+
];
|
|
7074
7285
|
if (linkPreview?.apiEndpoint) {
|
|
7075
7286
|
allItems.push({
|
|
7076
7287
|
title: "Link Preview",
|
|
7077
7288
|
onItemClick: () => {
|
|
7078
|
-
(0,
|
|
7289
|
+
(0, import_core10.insertOrUpdateBlock)(editor, {
|
|
7079
7290
|
type: "linkPreview",
|
|
7080
7291
|
props: { url: "" }
|
|
7081
7292
|
});
|