@lumir-company/editor 0.4.18 → 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 +47 -18
- package/dist/index.d.mts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +523 -57
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +510 -44
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +45 -0
- 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({
|
|
@@ -3436,6 +3447,8 @@ var ALLOWED_VIDEO_EXTENSIONS = [
|
|
|
3436
3447
|
];
|
|
3437
3448
|
var ROW_RESIZE_MIN_HEIGHT = 24;
|
|
3438
3449
|
var ROW_RESIZE_HANDLE_WIDTH = 5;
|
|
3450
|
+
var TABLE_SCALE_MIN_COL_WIDTH = 24;
|
|
3451
|
+
var TABLE_SCALE_MAX = 6;
|
|
3439
3452
|
|
|
3440
3453
|
// src/extensions/rowResizing.ts
|
|
3441
3454
|
var rowResizingPluginKey = new import_prosemirror_state3.PluginKey(
|
|
@@ -3714,9 +3727,165 @@ function handleDecorations(state, pluginState) {
|
|
|
3714
3727
|
return import_prosemirror_view2.DecorationSet.create(state.doc, decorations);
|
|
3715
3728
|
}
|
|
3716
3729
|
|
|
3717
|
-
// src/extensions/
|
|
3730
|
+
// src/extensions/tableScaling.ts
|
|
3718
3731
|
var import_prosemirror_state4 = require("prosemirror-state");
|
|
3719
|
-
var
|
|
3732
|
+
var import_prosemirror_view3 = require("prosemirror-view");
|
|
3733
|
+
var import_prosemirror_tables2 = require("prosemirror-tables");
|
|
3734
|
+
var tableScalingPluginKey = new import_prosemirror_state4.PluginKey(
|
|
3735
|
+
"lumirTableScaling"
|
|
3736
|
+
);
|
|
3737
|
+
function tableScaling() {
|
|
3738
|
+
return new import_prosemirror_state4.Plugin({
|
|
3739
|
+
key: tableScalingPluginKey,
|
|
3740
|
+
state: {
|
|
3741
|
+
init: () => null,
|
|
3742
|
+
apply(tr, prev) {
|
|
3743
|
+
const meta = tr.getMeta(tableScalingPluginKey);
|
|
3744
|
+
if (meta !== void 0) return meta.preview;
|
|
3745
|
+
if (prev && tr.docChanged) {
|
|
3746
|
+
return { ...prev, tablePos: tr.mapping.map(prev.tablePos, -1) };
|
|
3747
|
+
}
|
|
3748
|
+
return prev;
|
|
3749
|
+
}
|
|
3750
|
+
},
|
|
3751
|
+
props: {
|
|
3752
|
+
decorations(state) {
|
|
3753
|
+
const p = tableScalingPluginKey.getState(state);
|
|
3754
|
+
return p ? buildHeightDecorations(state, p) : null;
|
|
3755
|
+
}
|
|
3756
|
+
},
|
|
3757
|
+
view: (view) => ({
|
|
3758
|
+
update: () => {
|
|
3759
|
+
const p = tableScalingPluginKey.getState(view.state);
|
|
3760
|
+
if (p) applyColgroupPreview(view, p);
|
|
3761
|
+
}
|
|
3762
|
+
})
|
|
3763
|
+
});
|
|
3764
|
+
}
|
|
3765
|
+
function setTableScalePreview(view, preview) {
|
|
3766
|
+
view.dispatch(view.state.tr.setMeta(tableScalingPluginKey, { preview }));
|
|
3767
|
+
}
|
|
3768
|
+
function measureTableForScale(view, tablePos) {
|
|
3769
|
+
const tableEl = findTableEl(view.nodeDOM(tablePos));
|
|
3770
|
+
const node = view.state.doc.nodeAt(tablePos);
|
|
3771
|
+
if (!tableEl || !node || node.type.name !== "table") return null;
|
|
3772
|
+
const map = import_prosemirror_tables2.TableMap.get(node);
|
|
3773
|
+
const rect = tableEl.getBoundingClientRect();
|
|
3774
|
+
const body = tableEl.tBodies[0];
|
|
3775
|
+
const rowHeights = body ? Array.from(body.rows).map((tr) => tr.getBoundingClientRect().height) : [];
|
|
3776
|
+
const colWidths = measureColWidths(tableEl, map.width);
|
|
3777
|
+
if (rowHeights.length !== map.height || colWidths.length !== map.width) {
|
|
3778
|
+
return null;
|
|
3779
|
+
}
|
|
3780
|
+
return {
|
|
3781
|
+
tablePos,
|
|
3782
|
+
colWidths,
|
|
3783
|
+
rowHeights,
|
|
3784
|
+
origW: rect.width,
|
|
3785
|
+
origH: rect.height,
|
|
3786
|
+
scale: 1
|
|
3787
|
+
};
|
|
3788
|
+
}
|
|
3789
|
+
function commitTableScale(view, preview) {
|
|
3790
|
+
const { state } = view;
|
|
3791
|
+
const { tablePos, colWidths, rowHeights, scale } = preview;
|
|
3792
|
+
const table = state.doc.nodeAt(tablePos);
|
|
3793
|
+
if (!table || table.type.name !== "table") return;
|
|
3794
|
+
const map = import_prosemirror_tables2.TableMap.get(table);
|
|
3795
|
+
const start = tablePos + 1;
|
|
3796
|
+
const tr = state.tr;
|
|
3797
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3798
|
+
for (const relPos of map.map) {
|
|
3799
|
+
if (seen.has(relPos)) continue;
|
|
3800
|
+
seen.add(relPos);
|
|
3801
|
+
const node = table.nodeAt(relPos);
|
|
3802
|
+
if (!node) continue;
|
|
3803
|
+
const rect = map.findCell(relPos);
|
|
3804
|
+
const colwidth = [];
|
|
3805
|
+
for (let c = rect.left; c < rect.right; c++) {
|
|
3806
|
+
colwidth.push(Math.round((colWidths[c] ?? 0) * scale));
|
|
3807
|
+
}
|
|
3808
|
+
let h = 0;
|
|
3809
|
+
for (let r = rect.top; r < rect.bottom; r++) h += rowHeights[r] ?? 0;
|
|
3810
|
+
const rowHeight = Math.round(h * scale);
|
|
3811
|
+
tr.setNodeMarkup(start + relPos, void 0, {
|
|
3812
|
+
...node.attrs,
|
|
3813
|
+
colwidth: colwidth.some((w) => w > 0) ? colwidth : null,
|
|
3814
|
+
rowHeight: rowHeight > 0 ? rowHeight : null
|
|
3815
|
+
});
|
|
3816
|
+
}
|
|
3817
|
+
if (tr.docChanged) view.dispatch(tr);
|
|
3818
|
+
}
|
|
3819
|
+
function measureColWidths(tableEl, width) {
|
|
3820
|
+
const widths = new Array(width).fill(0);
|
|
3821
|
+
const colgroup = tableEl.querySelector("colgroup");
|
|
3822
|
+
if (colgroup && colgroup.children.length === width) {
|
|
3823
|
+
let allSet = true;
|
|
3824
|
+
for (let i = 0; i < width; i++) {
|
|
3825
|
+
const w = parseFloat(colgroup.children[i].style.width);
|
|
3826
|
+
if (Number.isFinite(w) && w > 0) widths[i] = w;
|
|
3827
|
+
else allSet = false;
|
|
3828
|
+
}
|
|
3829
|
+
if (allSet) return widths;
|
|
3830
|
+
}
|
|
3831
|
+
const firstRow = tableEl.tBodies[0]?.rows[0];
|
|
3832
|
+
if (firstRow) {
|
|
3833
|
+
let col = 0;
|
|
3834
|
+
for (const cell of Array.from(firstRow.cells)) {
|
|
3835
|
+
const span = cell.colSpan || 1;
|
|
3836
|
+
const w = cell.getBoundingClientRect().width / span;
|
|
3837
|
+
for (let s = 0; s < span && col < width; s++) widths[col++] = w;
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
return widths;
|
|
3841
|
+
}
|
|
3842
|
+
function applyColgroupPreview(view, p) {
|
|
3843
|
+
const tableEl = findTableEl(view.nodeDOM(p.tablePos));
|
|
3844
|
+
const colgroup = tableEl?.querySelector("colgroup");
|
|
3845
|
+
if (!colgroup) return;
|
|
3846
|
+
const cols = colgroup.children;
|
|
3847
|
+
for (let i = 0; i < cols.length && i < p.colWidths.length; i++) {
|
|
3848
|
+
cols[i].style.width = Math.round(p.colWidths[i] * p.scale) + "px";
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
function buildHeightDecorations(state, p) {
|
|
3852
|
+
const table = state.doc.nodeAt(p.tablePos);
|
|
3853
|
+
if (!table || table.type.name !== "table") return import_prosemirror_view3.DecorationSet.empty;
|
|
3854
|
+
const map = import_prosemirror_tables2.TableMap.get(table);
|
|
3855
|
+
const start = p.tablePos + 1;
|
|
3856
|
+
const decorations = [];
|
|
3857
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3858
|
+
for (const relPos of map.map) {
|
|
3859
|
+
if (seen.has(relPos)) continue;
|
|
3860
|
+
seen.add(relPos);
|
|
3861
|
+
const node = table.nodeAt(relPos);
|
|
3862
|
+
if (!node) continue;
|
|
3863
|
+
const rect = map.findCell(relPos);
|
|
3864
|
+
let h = 0;
|
|
3865
|
+
for (let r = rect.top; r < rect.bottom; r++) h += p.rowHeights[r] ?? 0;
|
|
3866
|
+
const from = start + relPos;
|
|
3867
|
+
const to = from + node.nodeSize;
|
|
3868
|
+
decorations.push(
|
|
3869
|
+
import_prosemirror_view3.Decoration.node(from, to, {
|
|
3870
|
+
class: "lumir-table-scale-dragging",
|
|
3871
|
+
style: `height: ${Math.round(h * p.scale)}px`
|
|
3872
|
+
})
|
|
3873
|
+
);
|
|
3874
|
+
}
|
|
3875
|
+
return import_prosemirror_view3.DecorationSet.create(state.doc, decorations);
|
|
3876
|
+
}
|
|
3877
|
+
function findTableEl(dom) {
|
|
3878
|
+
if (!dom) return null;
|
|
3879
|
+
const el = dom;
|
|
3880
|
+
if (el.nodeName === "TABLE") return el;
|
|
3881
|
+
const inner = el.querySelector?.("table");
|
|
3882
|
+
if (inner) return inner;
|
|
3883
|
+
return el.closest?.("table") ?? null;
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
// src/extensions/tableCellAttrPreserve.ts
|
|
3887
|
+
var import_prosemirror_state5 = require("prosemirror-state");
|
|
3888
|
+
var tableCellAttrPreserveKey = new import_prosemirror_state5.PluginKey(
|
|
3720
3889
|
"lumirTableCellAttrPreserve"
|
|
3721
3890
|
);
|
|
3722
3891
|
var PRESERVED_ATTRS = [
|
|
@@ -3773,7 +3942,7 @@ function collectCellAttrs(doc) {
|
|
|
3773
3942
|
return result;
|
|
3774
3943
|
}
|
|
3775
3944
|
function tableCellAttrPreserve() {
|
|
3776
|
-
return new
|
|
3945
|
+
return new import_prosemirror_state5.Plugin({
|
|
3777
3946
|
key: tableCellAttrPreserveKey,
|
|
3778
3947
|
appendTransaction(transactions, oldState, newState) {
|
|
3779
3948
|
if (!transactions.some((tr2) => tr2.docChanged)) {
|
|
@@ -3879,6 +4048,7 @@ var RowHeightExtension = import_core5.Extension.create({
|
|
|
3879
4048
|
const plugins = [tableCellAttrPreserve()];
|
|
3880
4049
|
if (this.options.resizable) {
|
|
3881
4050
|
plugins.push(rowResizing());
|
|
4051
|
+
plugins.push(tableScaling());
|
|
3882
4052
|
}
|
|
3883
4053
|
return plugins;
|
|
3884
4054
|
}
|
|
@@ -3886,11 +4056,11 @@ var RowHeightExtension = import_core5.Extension.create({
|
|
|
3886
4056
|
|
|
3887
4057
|
// src/extensions/TableAlignmentExtension.ts
|
|
3888
4058
|
var import_core6 = require("@tiptap/core");
|
|
3889
|
-
var
|
|
3890
|
-
var
|
|
3891
|
-
var tableAlignmentDecoKey = new
|
|
4059
|
+
var import_prosemirror_state6 = require("prosemirror-state");
|
|
4060
|
+
var import_prosemirror_view4 = require("prosemirror-view");
|
|
4061
|
+
var tableAlignmentDecoKey = new import_prosemirror_state6.PluginKey("lumirTableAlignmentDeco");
|
|
3892
4062
|
function tableAlignmentDecorationPlugin() {
|
|
3893
|
-
return new
|
|
4063
|
+
return new import_prosemirror_state6.Plugin({
|
|
3894
4064
|
key: tableAlignmentDecoKey,
|
|
3895
4065
|
props: {
|
|
3896
4066
|
decorations(state) {
|
|
@@ -3900,7 +4070,7 @@ function tableAlignmentDecorationPlugin() {
|
|
|
3900
4070
|
const align = node.attrs.tableAlignment;
|
|
3901
4071
|
if (align && align !== "left") {
|
|
3902
4072
|
decorations.push(
|
|
3903
|
-
|
|
4073
|
+
import_prosemirror_view4.Decoration.node(pos, pos + node.nodeSize, {
|
|
3904
4074
|
"data-table-alignment": align
|
|
3905
4075
|
})
|
|
3906
4076
|
);
|
|
@@ -3909,7 +4079,7 @@ function tableAlignmentDecorationPlugin() {
|
|
|
3909
4079
|
}
|
|
3910
4080
|
return void 0;
|
|
3911
4081
|
});
|
|
3912
|
-
return
|
|
4082
|
+
return import_prosemirror_view4.DecorationSet.create(state.doc, decorations);
|
|
3913
4083
|
}
|
|
3914
4084
|
}
|
|
3915
4085
|
});
|
|
@@ -3940,9 +4110,56 @@ var TableAlignmentExtension = import_core6.Extension.create({
|
|
|
3940
4110
|
}
|
|
3941
4111
|
});
|
|
3942
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
|
+
|
|
3943
4160
|
// src/blocks/columns/insertColumns.ts
|
|
3944
|
-
var
|
|
3945
|
-
function insertTwoColumns(editor) {
|
|
4161
|
+
var import_prosemirror_state7 = require("prosemirror-state");
|
|
4162
|
+
function insertTwoColumns(editor, showDivider = false) {
|
|
3946
4163
|
const tiptap = editor?._tiptapEditor;
|
|
3947
4164
|
if (!tiptap) {
|
|
3948
4165
|
return false;
|
|
@@ -3969,11 +4186,11 @@ function insertTwoColumns(editor) {
|
|
|
3969
4186
|
const insertPos = $from.after(depth);
|
|
3970
4187
|
const mkBlock = () => blockContainer.create(null, paragraph.create());
|
|
3971
4188
|
const mkColumn = () => column.create(null, mkBlock());
|
|
3972
|
-
const list = columnList.create(
|
|
4189
|
+
const list = columnList.create({ showDivider }, [mkColumn(), mkColumn()]);
|
|
3973
4190
|
try {
|
|
3974
4191
|
let tr = state.tr.insert(insertPos, list);
|
|
3975
4192
|
try {
|
|
3976
|
-
tr = tr.setSelection(
|
|
4193
|
+
tr = tr.setSelection(import_prosemirror_state7.TextSelection.create(tr.doc, insertPos + 4));
|
|
3977
4194
|
} catch {
|
|
3978
4195
|
}
|
|
3979
4196
|
tiptap.view.dispatch(tr.scrollIntoView());
|
|
@@ -3987,7 +4204,7 @@ function insertTwoColumns(editor) {
|
|
|
3987
4204
|
var import_react30 = require("@blocknote/react");
|
|
3988
4205
|
|
|
3989
4206
|
// src/components/TextAlignButtonWithVA.tsx
|
|
3990
|
-
var
|
|
4207
|
+
var import_core8 = require("@blocknote/core");
|
|
3991
4208
|
var import_react20 = require("react");
|
|
3992
4209
|
var import_react21 = require("@blocknote/react");
|
|
3993
4210
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
@@ -4009,7 +4226,7 @@ var TextAlignButtonWithVA = (props) => {
|
|
|
4009
4226
|
const selectedBlocks = (0, import_react21.useSelectedBlocks)(editor);
|
|
4010
4227
|
const textAlignment = (0, import_react20.useMemo)(() => {
|
|
4011
4228
|
const block = selectedBlocks[0];
|
|
4012
|
-
if ((0,
|
|
4229
|
+
if ((0, import_core8.checkBlockHasDefaultProp)("textAlignment", block, editor)) {
|
|
4013
4230
|
return block.props.textAlignment;
|
|
4014
4231
|
}
|
|
4015
4232
|
if (block.type === "table") {
|
|
@@ -4018,7 +4235,7 @@ var TextAlignButtonWithVA = (props) => {
|
|
|
4018
4235
|
return;
|
|
4019
4236
|
}
|
|
4020
4237
|
const allCellsInTable = cellSelection.cells.map(
|
|
4021
|
-
({ row, col }) => (0,
|
|
4238
|
+
({ row, col }) => (0, import_core8.mapTableCell)(
|
|
4022
4239
|
block.content.rows[row].cells[col]
|
|
4023
4240
|
).props.textAlignment
|
|
4024
4241
|
);
|
|
@@ -4050,7 +4267,7 @@ var TextAlignButtonWithVA = (props) => {
|
|
|
4050
4267
|
}
|
|
4051
4268
|
}
|
|
4052
4269
|
tiptap.view?.dispatch(tr);
|
|
4053
|
-
} else if ((0,
|
|
4270
|
+
} else if ((0, import_core8.checkBlockTypeHasDefaultProp)("textAlignment", block.type, editor)) {
|
|
4054
4271
|
editor.updateBlock(block, {
|
|
4055
4272
|
props: { textAlignment: newAlignment }
|
|
4056
4273
|
});
|
|
@@ -4323,7 +4540,7 @@ function FontSizeButton2() {
|
|
|
4323
4540
|
}
|
|
4324
4541
|
|
|
4325
4542
|
// src/components/color/LumirColorControls.tsx
|
|
4326
|
-
var
|
|
4543
|
+
var import_core9 = require("@blocknote/core");
|
|
4327
4544
|
var import_react28 = require("@blocknote/react");
|
|
4328
4545
|
var import_react29 = require("react");
|
|
4329
4546
|
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
@@ -4571,7 +4788,7 @@ function LumirCellColorPickerButton(props) {
|
|
|
4571
4788
|
const updateColor = (color, type) => {
|
|
4572
4789
|
const newTable = props.block.content.rows.map((row) => ({
|
|
4573
4790
|
...row,
|
|
4574
|
-
cells: row.cells.map((cell) => (0,
|
|
4791
|
+
cells: row.cells.map((cell) => (0, import_core9.mapTableCell)(cell))
|
|
4575
4792
|
}));
|
|
4576
4793
|
if (type === "text") {
|
|
4577
4794
|
newTable[props.rowIndex].cells[props.colIndex].props.textColor = color;
|
|
@@ -4602,11 +4819,11 @@ function LumirCellColorPickerButton(props) {
|
|
|
4602
4819
|
textTitle: "\uC140 \uAE00\uC790\uC0C9",
|
|
4603
4820
|
backgroundTitle: "\uC140 \uBC30\uACBD",
|
|
4604
4821
|
text: editor.settings.tables.cellTextColor ? {
|
|
4605
|
-
color: (0,
|
|
4822
|
+
color: (0, import_core9.isTableCell)(currentCell) ? currentCell.props.textColor : "default",
|
|
4606
4823
|
setColor: (color) => updateColor(color, "text")
|
|
4607
4824
|
} : void 0,
|
|
4608
4825
|
background: editor.settings.tables.cellBackgroundColor ? {
|
|
4609
|
-
color: (0,
|
|
4826
|
+
color: (0, import_core9.isTableCell)(currentCell) ? currentCell.props.backgroundColor : "default",
|
|
4610
4827
|
setColor: (color) => updateColor(color, "background")
|
|
4611
4828
|
} : void 0
|
|
4612
4829
|
}
|
|
@@ -4787,9 +5004,14 @@ var import_react33 = require("react");
|
|
|
4787
5004
|
function useFocusedCellHandlePositioning(cellEl, tbodyEl, orientation, show) {
|
|
4788
5005
|
const { refs, floatingStyles, context, update } = (0, import_react32.useFloating)({
|
|
4789
5006
|
open: show,
|
|
4790
|
-
placement: orientation === "row" ? "left" : orientation === "col" ? "top" : "right",
|
|
4791
|
-
// col/row
|
|
4792
|
-
|
|
5007
|
+
placement: orientation === "row" ? "left" : orientation === "col" ? "top" : orientation === "corner" ? "bottom-start" : "right",
|
|
5008
|
+
// col/row/cell: 가장자리에 14px hit-area 중앙 정렬(-7).
|
|
5009
|
+
// corner: 18px hit-zone이 표 우하단 모서리에 걸치도록 위/좌로 살짝 당김(모서리 hover 자연).
|
|
5010
|
+
middleware: [
|
|
5011
|
+
(0, import_react32.offset)(
|
|
5012
|
+
orientation === "corner" ? { mainAxis: -6, crossAxis: -6 } : -7
|
|
5013
|
+
)
|
|
5014
|
+
],
|
|
4793
5015
|
whileElementsMounted: import_react32.autoUpdate
|
|
4794
5016
|
});
|
|
4795
5017
|
const { isMounted, styles } = (0, import_react32.useTransitionStyles)(context);
|
|
@@ -4817,6 +5039,9 @@ function useFocusedCellHandlePositioning(cellEl, tbodyEl, orientation, show) {
|
|
|
4817
5039
|
if (orientation === "row") {
|
|
4818
5040
|
return new DOMRect(t.left, c.top, 0, c.height);
|
|
4819
5041
|
}
|
|
5042
|
+
if (orientation === "corner") {
|
|
5043
|
+
return new DOMRect(t.right, t.bottom, 0, 0);
|
|
5044
|
+
}
|
|
4820
5045
|
return c;
|
|
4821
5046
|
}
|
|
4822
5047
|
});
|
|
@@ -4834,6 +5059,33 @@ function useFocusedCellHandlePositioning(cellEl, tbodyEl, orientation, show) {
|
|
|
4834
5059
|
[floatingStyles, isMounted, refs.setFloating, styles]
|
|
4835
5060
|
);
|
|
4836
5061
|
}
|
|
5062
|
+
function useTableCornerPositioning(referencePosTable, show) {
|
|
5063
|
+
const { refs, floatingStyles, context } = (0, import_react32.useFloating)({
|
|
5064
|
+
open: show,
|
|
5065
|
+
placement: "bottom-start",
|
|
5066
|
+
// 18px hit-zone을 모서리에서 안쪽(위/좌)으로 당겨 표 위에 걸치게 한다.
|
|
5067
|
+
middleware: [(0, import_react32.offset)({ mainAxis: -12, crossAxis: -12 })],
|
|
5068
|
+
whileElementsMounted: import_react32.autoUpdate
|
|
5069
|
+
});
|
|
5070
|
+
const { isMounted, styles } = (0, import_react32.useTransitionStyles)(context);
|
|
5071
|
+
(0, import_react33.useEffect)(() => {
|
|
5072
|
+
if (!referencePosTable) {
|
|
5073
|
+
refs.setReference(null);
|
|
5074
|
+
return;
|
|
5075
|
+
}
|
|
5076
|
+
refs.setReference({
|
|
5077
|
+
getBoundingClientRect: () => new DOMRect(referencePosTable.right, referencePosTable.bottom, 0, 0)
|
|
5078
|
+
});
|
|
5079
|
+
}, [referencePosTable, refs]);
|
|
5080
|
+
return (0, import_react33.useMemo)(
|
|
5081
|
+
() => ({
|
|
5082
|
+
isMounted,
|
|
5083
|
+
ref: refs.setFloating,
|
|
5084
|
+
style: { ...styles, ...floatingStyles }
|
|
5085
|
+
}),
|
|
5086
|
+
[floatingStyles, isMounted, refs.setFloating, styles]
|
|
5087
|
+
);
|
|
5088
|
+
}
|
|
4837
5089
|
|
|
4838
5090
|
// src/components/LumirTableHandlesController.tsx
|
|
4839
5091
|
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
@@ -4984,6 +5236,10 @@ function LumirTableHandlesController() {
|
|
|
4984
5236
|
const onEndExtend = (0, import_react36.useCallback)(() => {
|
|
4985
5237
|
editor.tableHandles?.unfreezeHandles();
|
|
4986
5238
|
}, [editor]);
|
|
5239
|
+
const tableCorner = useTableCornerPositioning(
|
|
5240
|
+
coreState?.referencePosTable ?? null,
|
|
5241
|
+
!!coreState?.widgetContainer
|
|
5242
|
+
);
|
|
4987
5243
|
const menuHandlers = (0, import_react36.useMemo)(() => {
|
|
4988
5244
|
const mk = (kind) => ({
|
|
4989
5245
|
freeze: () => {
|
|
@@ -5033,6 +5289,48 @@ function LumirTableHandlesController() {
|
|
|
5033
5289
|
}, [editor, recompute]);
|
|
5034
5290
|
const noop = (0, import_react36.useCallback)(() => {
|
|
5035
5291
|
}, []);
|
|
5292
|
+
const onScaleStart = (0, import_react36.useCallback)(
|
|
5293
|
+
(e) => {
|
|
5294
|
+
e.preventDefault();
|
|
5295
|
+
e.stopPropagation();
|
|
5296
|
+
const view = editor.prosemirrorView;
|
|
5297
|
+
const blockId = coreState?.block?.id;
|
|
5298
|
+
if (!view || !blockId) return;
|
|
5299
|
+
const tablePos = findTableNodePos(editor._tiptapEditor, blockId);
|
|
5300
|
+
if (tablePos < 0) return;
|
|
5301
|
+
const base = measureTableForScale(view, tablePos);
|
|
5302
|
+
if (!base) return;
|
|
5303
|
+
const minScale = Math.max(
|
|
5304
|
+
TABLE_SCALE_MIN_COL_WIDTH / Math.max(1, Math.min(...base.colWidths)),
|
|
5305
|
+
ROW_RESIZE_MIN_HEIGHT / Math.max(1, Math.min(...base.rowHeights))
|
|
5306
|
+
);
|
|
5307
|
+
const startX = e.clientX;
|
|
5308
|
+
const startY = e.clientY;
|
|
5309
|
+
let current = base;
|
|
5310
|
+
editor.tableHandles?.freezeHandles();
|
|
5311
|
+
const onMove = (me) => {
|
|
5312
|
+
if (me.buttons === 0) return onUp();
|
|
5313
|
+
const newW = base.origW + (me.clientX - startX);
|
|
5314
|
+
const newH = base.origH + (me.clientY - startY);
|
|
5315
|
+
const scale = Math.min(
|
|
5316
|
+
TABLE_SCALE_MAX,
|
|
5317
|
+
Math.max(minScale, Math.max(newW / base.origW, newH / base.origH))
|
|
5318
|
+
);
|
|
5319
|
+
current = { ...base, scale };
|
|
5320
|
+
setTableScalePreview(view, current);
|
|
5321
|
+
};
|
|
5322
|
+
const onUp = () => {
|
|
5323
|
+
window.removeEventListener("pointermove", onMove);
|
|
5324
|
+
window.removeEventListener("pointerup", onUp);
|
|
5325
|
+
setTableScalePreview(view, null);
|
|
5326
|
+
commitTableScale(view, current);
|
|
5327
|
+
editor.tableHandles?.unfreezeHandles();
|
|
5328
|
+
};
|
|
5329
|
+
window.addEventListener("pointermove", onMove);
|
|
5330
|
+
window.addEventListener("pointerup", onUp);
|
|
5331
|
+
},
|
|
5332
|
+
[editor, coreState]
|
|
5333
|
+
);
|
|
5036
5334
|
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
5037
5335
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: setMenuContainerRef }),
|
|
5038
5336
|
th && focused && menuContainerRef && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react35.FloatingPortal, { root: focused.widgetContainer, children: [
|
|
@@ -5148,6 +5446,16 @@ function LumirTableHandlesController() {
|
|
|
5148
5446
|
}
|
|
5149
5447
|
)
|
|
5150
5448
|
}
|
|
5449
|
+
),
|
|
5450
|
+
tableCorner.isMounted && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
5451
|
+
"div",
|
|
5452
|
+
{
|
|
5453
|
+
ref: tableCorner.ref,
|
|
5454
|
+
style: tableCorner.style,
|
|
5455
|
+
className: "lumir-tbl-scale-handle",
|
|
5456
|
+
title: "\uD45C \uD06C\uAE30 \uC870\uC808 (\uC885\uD6A1\uBE44 \uACE0\uC815)",
|
|
5457
|
+
onPointerDown: onScaleStart
|
|
5458
|
+
}
|
|
5151
5459
|
)
|
|
5152
5460
|
] })
|
|
5153
5461
|
] });
|
|
@@ -5404,7 +5712,7 @@ function liftFontSize(blocks) {
|
|
|
5404
5712
|
}
|
|
5405
5713
|
|
|
5406
5714
|
// src/utils/table-delete.ts
|
|
5407
|
-
var
|
|
5715
|
+
var import_prosemirror_tables4 = require("prosemirror-tables");
|
|
5408
5716
|
function measureRowHeights(view, tablePos) {
|
|
5409
5717
|
try {
|
|
5410
5718
|
const at = view?.domAtPos?.(tablePos + 1);
|
|
@@ -5423,7 +5731,7 @@ function measureRowHeights(view, tablePos) {
|
|
|
5423
5731
|
function buildDeleteColumnTr(state, tablePos, col, rowPx) {
|
|
5424
5732
|
const table = state.doc.nodeAt(tablePos);
|
|
5425
5733
|
if (!table || table.type.name !== "table") return null;
|
|
5426
|
-
const map =
|
|
5734
|
+
const map = import_prosemirror_tables4.TableMap.get(table);
|
|
5427
5735
|
const W = map.width;
|
|
5428
5736
|
const H = map.height;
|
|
5429
5737
|
if (col < 0 || col >= W || W <= 1) return null;
|
|
@@ -5529,9 +5837,9 @@ function removeFocusedRowOrColumn(editor, index, direction) {
|
|
|
5529
5837
|
const rowStart = state.doc.resolve(tableInside.posAtIndex(index) + 1);
|
|
5530
5838
|
const cellPos = state.doc.resolve(rowStart.posAtIndex(0));
|
|
5531
5839
|
const selState = state.apply(
|
|
5532
|
-
state.tr.setSelection(new
|
|
5840
|
+
state.tr.setSelection(new import_prosemirror_tables4.CellSelection(cellPos))
|
|
5533
5841
|
);
|
|
5534
|
-
return (0,
|
|
5842
|
+
return (0, import_prosemirror_tables4.deleteRow)(selState, (tr) => tiptap.view.dispatch(tr));
|
|
5535
5843
|
} catch {
|
|
5536
5844
|
return false;
|
|
5537
5845
|
}
|
|
@@ -5681,6 +5989,20 @@ function normalizeAlign(ta) {
|
|
|
5681
5989
|
if (v === "justify") return "justify";
|
|
5682
5990
|
return "";
|
|
5683
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
|
+
}
|
|
5684
6006
|
function applyCellFormatting(el, fmt) {
|
|
5685
6007
|
if (fmt.bgRgb && !fmt.bgTransparent) {
|
|
5686
6008
|
const v = nearestBackgroundColorValue(fmt.bgRgb);
|
|
@@ -5700,6 +6022,13 @@ function applyCellFormatting(el, fmt) {
|
|
|
5700
6022
|
if (fmt.bold) inner = `<strong>${inner}</strong>`;
|
|
5701
6023
|
el.innerHTML = inner;
|
|
5702
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
|
+
}
|
|
5703
6032
|
}
|
|
5704
6033
|
function readComputedFormat(el) {
|
|
5705
6034
|
const cs = getComputedStyle(el);
|
|
@@ -5713,7 +6042,13 @@ function readComputedFormat(el) {
|
|
|
5713
6042
|
align: normalizeAlign(cs.textAlign),
|
|
5714
6043
|
bold: fw === "bold" || fw === "bolder" || !isNaN(fwNum) && fwNum >= 600,
|
|
5715
6044
|
italic: (cs.fontStyle || "").toLowerCase().includes("italic"),
|
|
5716
|
-
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
|
+
)
|
|
5717
6052
|
};
|
|
5718
6053
|
}
|
|
5719
6054
|
function readInlineFormat(el) {
|
|
@@ -5729,7 +6064,11 @@ function readInlineFormat(el) {
|
|
|
5729
6064
|
align: normalizeAlign(sm["text-align"] || el.getAttribute("align")),
|
|
5730
6065
|
bold: fw === "bold" || fw === "bolder" || parseInt(fw, 10) >= 600,
|
|
5731
6066
|
italic: (sm["font-style"] || "").toLowerCase().includes("italic"),
|
|
5732
|
-
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
|
+
)
|
|
5733
6072
|
};
|
|
5734
6073
|
}
|
|
5735
6074
|
function normalizeExcelTableHtml(html) {
|
|
@@ -5743,7 +6082,7 @@ function normalizeExcelTableHtml(html) {
|
|
|
5743
6082
|
try {
|
|
5744
6083
|
host = document.createElement("div");
|
|
5745
6084
|
host.setAttribute("aria-hidden", "true");
|
|
5746
|
-
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";
|
|
5747
6086
|
const shadow = host.attachShadow({ mode: "open" });
|
|
5748
6087
|
const styles = Array.from(doc.querySelectorAll("style")).map((s) => s.outerHTML).join("");
|
|
5749
6088
|
shadow.innerHTML = styles + doc.body.innerHTML;
|
|
@@ -5766,6 +6105,100 @@ function normalizeExcelTableHtml(html) {
|
|
|
5766
6105
|
}
|
|
5767
6106
|
}
|
|
5768
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
|
+
|
|
5769
6202
|
// src/components/LumirEditor.tsx
|
|
5770
6203
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
5771
6204
|
var DEBUG_LOG = (loc, msg, data) => {
|
|
@@ -6078,6 +6511,7 @@ function LumirEditor({
|
|
|
6078
6511
|
className = "",
|
|
6079
6512
|
placeholder,
|
|
6080
6513
|
sideMenuAddButton = false,
|
|
6514
|
+
columnDivider = false,
|
|
6081
6515
|
floatingMenu = false,
|
|
6082
6516
|
floatingMenuPosition = "sticky",
|
|
6083
6517
|
// callbacks / refs
|
|
@@ -6191,7 +6625,9 @@ function LumirEditor({
|
|
|
6191
6625
|
// tableHandles prop으로 게이트(기존 grip 컨트롤러와 동일 게이트).
|
|
6192
6626
|
RowHeightExtension.configure({ resizable: tableHandles }),
|
|
6193
6627
|
// 표 블록 정렬(좌/가운데/우) attr.
|
|
6194
|
-
TableAlignmentExtension
|
|
6628
|
+
TableAlignmentExtension,
|
|
6629
|
+
// 셀 포커스 시 Ctrl/Cmd+A → 표 전체 선택.
|
|
6630
|
+
TableSelectAllExtension
|
|
6195
6631
|
]
|
|
6196
6632
|
},
|
|
6197
6633
|
placeholders: placeholder ? { default: placeholder, emptyDocument: placeholder } : void 0,
|
|
@@ -6297,7 +6733,14 @@ function LumirEditor({
|
|
|
6297
6733
|
hasFiles: !!event?.clipboardData?.files?.length
|
|
6298
6734
|
});
|
|
6299
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
|
+
);
|
|
6300
6742
|
editor2.pasteHTML(normalizeExcelTableHtml(pastedHtml));
|
|
6743
|
+
applyFittedWidthsToNewTables(editor2, beforeTableIds, fittedWidths);
|
|
6301
6744
|
return true;
|
|
6302
6745
|
}
|
|
6303
6746
|
const fileList = event?.clipboardData?.files ?? null;
|
|
@@ -6592,7 +7035,11 @@ function LumirEditor({
|
|
|
6592
7035
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
6593
7036
|
"div",
|
|
6594
7037
|
{
|
|
6595
|
-
className: cn(
|
|
7038
|
+
className: cn(
|
|
7039
|
+
"lumirEditor",
|
|
7040
|
+
columnDivider && "lumir-column-divider",
|
|
7041
|
+
className
|
|
7042
|
+
),
|
|
6596
7043
|
style: { position: "relative", display: "flex", flexDirection: "column" },
|
|
6597
7044
|
children: [
|
|
6598
7045
|
floatingMenu && editor && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
@@ -6789,38 +7236,57 @@ function LumirEditor({
|
|
|
6789
7236
|
),
|
|
6790
7237
|
subtext: "HTML \uD30C\uC77C\uC744 \uBBF8\uB9AC\uBCF4\uAE30\uB85C \uC0BD\uC785"
|
|
6791
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
|
+
);
|
|
6792
7257
|
const columnItem = {
|
|
6793
7258
|
title: "2\uB2E8 \uCEEC\uB7FC",
|
|
6794
|
-
onItemClick: () =>
|
|
6795
|
-
insertTwoColumns(editor);
|
|
6796
|
-
},
|
|
7259
|
+
onItemClick: () => insertTwoColumns(editor, false),
|
|
6797
7260
|
aliases: ["columns", "column", "2col", "\uB2E8", "\uCEEC\uB7FC", "\uB2E4\uB2E8", "\uBD84\uD560"],
|
|
6798
7261
|
group: "Basic blocks",
|
|
6799
|
-
icon:
|
|
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
|
-
),
|
|
7262
|
+
icon: columnIcon(false),
|
|
6816
7263
|
subtext: "\uBE14\uB85D\uC744 \uC88C\uC6B0 2\uB2E8\uC73C\uB85C \uBC30\uCE58"
|
|
6817
7264
|
};
|
|
6818
|
-
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
|
+
];
|
|
6819
7285
|
if (linkPreview?.apiEndpoint) {
|
|
6820
7286
|
allItems.push({
|
|
6821
7287
|
title: "Link Preview",
|
|
6822
7288
|
onItemClick: () => {
|
|
6823
|
-
(0,
|
|
7289
|
+
(0, import_core10.insertOrUpdateBlock)(editor, {
|
|
6824
7290
|
type: "linkPreview",
|
|
6825
7291
|
props: { url: "" }
|
|
6826
7292
|
});
|