@lumir-company/editor 0.4.13 → 0.4.15
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 +1588 -1511
- package/dist/api/link-preview.js.map +1 -1
- package/dist/api/link-preview.mjs.map +1 -1
- package/dist/index.js +1124 -128
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1138 -120
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +1241 -1041
- package/package.json +96 -94
package/dist/index.js
CHANGED
|
@@ -40,10 +40,11 @@ __export(index_exports, {
|
|
|
40
40
|
module.exports = __toCommonJS(index_exports);
|
|
41
41
|
|
|
42
42
|
// src/components/LumirEditor.tsx
|
|
43
|
-
var
|
|
44
|
-
var
|
|
43
|
+
var import_react30 = require("react");
|
|
44
|
+
var import_react31 = require("@blocknote/react");
|
|
45
45
|
var import_mantine = require("@blocknote/mantine");
|
|
46
|
-
var
|
|
46
|
+
var import_core5 = require("@blocknote/core");
|
|
47
|
+
var import_locales = require("@blocknote/core/locales");
|
|
47
48
|
|
|
48
49
|
// src/utils/cn.ts
|
|
49
50
|
function cn(...inputs) {
|
|
@@ -1834,6 +1835,66 @@ var TextStyleButton = ({
|
|
|
1834
1835
|
|
|
1835
1836
|
// src/components/FloatingMenu/components/AlignButton.tsx
|
|
1836
1837
|
var import_react9 = require("react");
|
|
1838
|
+
|
|
1839
|
+
// src/utils/prosemirror-table-utils.ts
|
|
1840
|
+
function getSelectedCellPositions(editor) {
|
|
1841
|
+
const tiptap = editor._tiptapEditor;
|
|
1842
|
+
if (!tiptap) return [];
|
|
1843
|
+
const { state } = tiptap;
|
|
1844
|
+
const { selection } = state;
|
|
1845
|
+
if (typeof selection.forEachCell === "function") {
|
|
1846
|
+
const positions = [];
|
|
1847
|
+
selection.forEachCell((_node, pos) => {
|
|
1848
|
+
positions.push(pos);
|
|
1849
|
+
});
|
|
1850
|
+
return positions;
|
|
1851
|
+
}
|
|
1852
|
+
const $pos = selection.$from;
|
|
1853
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
1854
|
+
const node = $pos.node(depth);
|
|
1855
|
+
if (node.type.name === "tableCell" || node.type.name === "tableHeader") {
|
|
1856
|
+
return [$pos.before(depth)];
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
return [];
|
|
1860
|
+
}
|
|
1861
|
+
function setCellAttrAtPositions(editor, positions, attr, value) {
|
|
1862
|
+
const tiptap = editor?._tiptapEditor;
|
|
1863
|
+
if (!tiptap || positions.length === 0) return false;
|
|
1864
|
+
let tr = tiptap.state.tr;
|
|
1865
|
+
let changed = false;
|
|
1866
|
+
for (const pos of positions) {
|
|
1867
|
+
const node = tr.doc.nodeAt(pos);
|
|
1868
|
+
if (node && (node.type.name === "tableCell" || node.type.name === "tableHeader")) {
|
|
1869
|
+
tr = tr.setNodeMarkup(pos, void 0, { ...node.attrs, [attr]: value });
|
|
1870
|
+
changed = true;
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
if (changed) {
|
|
1874
|
+
tiptap.view?.dispatch(tr);
|
|
1875
|
+
}
|
|
1876
|
+
return changed;
|
|
1877
|
+
}
|
|
1878
|
+
function setSelectedCellsAttr(editor, attr, value) {
|
|
1879
|
+
return setCellAttrAtPositions(
|
|
1880
|
+
editor,
|
|
1881
|
+
getSelectedCellPositions(editor),
|
|
1882
|
+
attr,
|
|
1883
|
+
value
|
|
1884
|
+
);
|
|
1885
|
+
}
|
|
1886
|
+
function isInTableCell(editor) {
|
|
1887
|
+
return getSelectedCellPositions(editor).length > 0;
|
|
1888
|
+
}
|
|
1889
|
+
function getFirstSelectedCellAttr(editor, attr) {
|
|
1890
|
+
const tiptap = editor?._tiptapEditor;
|
|
1891
|
+
const positions = getSelectedCellPositions(editor);
|
|
1892
|
+
if (!tiptap || positions.length === 0) return void 0;
|
|
1893
|
+
const node = tiptap.state.doc.nodeAt(positions[0]);
|
|
1894
|
+
return node?.attrs?.[attr];
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
// src/components/FloatingMenu/components/AlignButton.tsx
|
|
1837
1898
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1838
1899
|
var iconMap2 = {
|
|
1839
1900
|
left: Icons.alignLeft,
|
|
@@ -1851,6 +1912,9 @@ var AlignButton = ({
|
|
|
1851
1912
|
}) => {
|
|
1852
1913
|
const getCurrentAlignment = () => {
|
|
1853
1914
|
try {
|
|
1915
|
+
if (isInTableCell(editor)) {
|
|
1916
|
+
return getFirstSelectedCellAttr(editor, "textAlignment") || "left";
|
|
1917
|
+
}
|
|
1854
1918
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1855
1919
|
return block?.props?.textAlignment || "left";
|
|
1856
1920
|
} catch {
|
|
@@ -1860,6 +1924,9 @@ var AlignButton = ({
|
|
|
1860
1924
|
const isActive = getCurrentAlignment() === alignment;
|
|
1861
1925
|
const handleClick = (0, import_react9.useCallback)(() => {
|
|
1862
1926
|
try {
|
|
1927
|
+
if (setSelectedCellsAttr(editor, "textAlignment", alignment)) {
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1863
1930
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1864
1931
|
if (block && editor?.updateBlock) {
|
|
1865
1932
|
editor.updateBlock(block, { props: { textAlignment: alignment } });
|
|
@@ -2025,6 +2092,10 @@ var ColorButton = ({ editor, type }) => {
|
|
|
2025
2092
|
const colors = type === "text" ? TEXT_COLORS : BACKGROUND_COLORS;
|
|
2026
2093
|
const getCurrentColor = (0, import_react12.useCallback)(() => {
|
|
2027
2094
|
try {
|
|
2095
|
+
if (isInTableCell(editor)) {
|
|
2096
|
+
const attr = type === "text" ? "textColor" : "backgroundColor";
|
|
2097
|
+
return getFirstSelectedCellAttr(editor, attr) || "default";
|
|
2098
|
+
}
|
|
2028
2099
|
const activeStyles = editor?.getActiveStyles?.() || {};
|
|
2029
2100
|
if (type === "text" && activeStyles.textColor) {
|
|
2030
2101
|
return activeStyles.textColor;
|
|
@@ -2054,13 +2125,15 @@ var ColorButton = ({ editor, type }) => {
|
|
|
2054
2125
|
(color) => {
|
|
2055
2126
|
try {
|
|
2056
2127
|
if (!editor) return;
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2128
|
+
const attr = type === "text" ? "textColor" : "backgroundColor";
|
|
2129
|
+
if (!setSelectedCellsAttr(editor, attr, color)) {
|
|
2130
|
+
editor.toggleStyles(
|
|
2131
|
+
type === "text" ? { textColor: color } : { backgroundColor: color }
|
|
2132
|
+
);
|
|
2061
2133
|
}
|
|
2062
2134
|
setCurrentColor(color);
|
|
2063
2135
|
setIsOpen(false);
|
|
2136
|
+
setTimeout(() => editor.focus?.());
|
|
2064
2137
|
} catch (err) {
|
|
2065
2138
|
console.error(`Color apply failed:`, err);
|
|
2066
2139
|
}
|
|
@@ -2864,37 +2937,12 @@ var VerticalAlignmentExtension = import_core2.Extension.create({
|
|
|
2864
2937
|
});
|
|
2865
2938
|
|
|
2866
2939
|
// src/components/CustomFormattingToolbar.tsx
|
|
2867
|
-
var
|
|
2940
|
+
var import_react24 = require("@blocknote/react");
|
|
2868
2941
|
|
|
2869
2942
|
// src/components/TextAlignButtonWithVA.tsx
|
|
2870
2943
|
var import_core3 = require("@blocknote/core");
|
|
2871
2944
|
var import_react18 = require("react");
|
|
2872
2945
|
var import_react19 = require("@blocknote/react");
|
|
2873
|
-
|
|
2874
|
-
// src/utils/prosemirror-table-utils.ts
|
|
2875
|
-
function getSelectedCellPositions(editor) {
|
|
2876
|
-
const tiptap = editor._tiptapEditor;
|
|
2877
|
-
if (!tiptap) return [];
|
|
2878
|
-
const { state } = tiptap;
|
|
2879
|
-
const { selection } = state;
|
|
2880
|
-
if (typeof selection.forEachCell === "function") {
|
|
2881
|
-
const positions = [];
|
|
2882
|
-
selection.forEachCell((_node, pos) => {
|
|
2883
|
-
positions.push(pos);
|
|
2884
|
-
});
|
|
2885
|
-
return positions;
|
|
2886
|
-
}
|
|
2887
|
-
const $pos = selection.$from;
|
|
2888
|
-
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
2889
|
-
const node = $pos.node(depth);
|
|
2890
|
-
if (node.type.name === "tableCell" || node.type.name === "tableHeader") {
|
|
2891
|
-
return [$pos.before(depth)];
|
|
2892
|
-
}
|
|
2893
|
-
}
|
|
2894
|
-
return [];
|
|
2895
|
-
}
|
|
2896
|
-
|
|
2897
|
-
// src/components/TextAlignButtonWithVA.tsx
|
|
2898
2946
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2899
2947
|
var icons = {
|
|
2900
2948
|
left: /* @__PURE__ */ (0, import_jsx_runtime17.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_runtime17.jsx)("path", { d: "M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z" }) }),
|
|
@@ -3071,77 +3119,759 @@ var VerticalAlignButton = (props) => {
|
|
|
3071
3119
|
);
|
|
3072
3120
|
};
|
|
3073
3121
|
|
|
3074
|
-
// src/components/
|
|
3122
|
+
// src/components/color/LumirColorControls.tsx
|
|
3123
|
+
var import_core4 = require("@blocknote/core");
|
|
3124
|
+
var import_react22 = require("@blocknote/react");
|
|
3125
|
+
var import_react23 = require("react");
|
|
3075
3126
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
3076
|
-
var
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3127
|
+
var COLORS = [
|
|
3128
|
+
"default",
|
|
3129
|
+
"gray",
|
|
3130
|
+
"brown",
|
|
3131
|
+
"red",
|
|
3132
|
+
"orange",
|
|
3133
|
+
"yellow",
|
|
3134
|
+
"green",
|
|
3135
|
+
"blue",
|
|
3136
|
+
"purple",
|
|
3137
|
+
"pink"
|
|
3138
|
+
];
|
|
3139
|
+
function ColorIcon(props) {
|
|
3140
|
+
const textColor = props.textColor || "default";
|
|
3141
|
+
const backgroundColor = props.backgroundColor || "default";
|
|
3142
|
+
const size = props.size || 16;
|
|
3143
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3144
|
+
"div",
|
|
3145
|
+
{
|
|
3146
|
+
className: "bn-color-icon",
|
|
3147
|
+
"data-background-color": backgroundColor,
|
|
3148
|
+
"data-text-color": textColor,
|
|
3149
|
+
style: {
|
|
3150
|
+
pointerEvents: "none",
|
|
3151
|
+
fontSize: `${size * 0.75}px`,
|
|
3152
|
+
height: `${size}px`,
|
|
3153
|
+
lineHeight: `${size}px`,
|
|
3154
|
+
textAlign: "center",
|
|
3155
|
+
width: `${size}px`
|
|
3156
|
+
},
|
|
3157
|
+
children: "A"
|
|
3158
|
+
}
|
|
3159
|
+
);
|
|
3160
|
+
}
|
|
3161
|
+
function CellFillIcon({ size = 18 }) {
|
|
3162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3163
|
+
"svg",
|
|
3164
|
+
{
|
|
3165
|
+
width: size,
|
|
3166
|
+
height: size,
|
|
3167
|
+
viewBox: "0 0 24 24",
|
|
3168
|
+
fill: "currentColor",
|
|
3169
|
+
style: { pointerEvents: "none" },
|
|
3170
|
+
"aria-hidden": "true",
|
|
3171
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.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" })
|
|
3172
|
+
}
|
|
3173
|
+
);
|
|
3174
|
+
}
|
|
3175
|
+
function LumirColorPicker(props) {
|
|
3176
|
+
const Components = (0, import_react22.useComponentsContext)();
|
|
3177
|
+
const dict = (0, import_react22.useDictionary)();
|
|
3178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
3179
|
+
props.text ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
3180
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Components.Generic.Menu.Label, { children: props.textTitle ?? dict.color_picker.text_title }),
|
|
3181
|
+
COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3182
|
+
Components.Generic.Menu.Item,
|
|
3183
|
+
{
|
|
3184
|
+
onClick: () => {
|
|
3185
|
+
props.onClick?.();
|
|
3186
|
+
props.text.setColor(color);
|
|
3187
|
+
},
|
|
3188
|
+
"data-test": "text-color-" + color,
|
|
3189
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ColorIcon, { textColor: color, size: props.iconSize }),
|
|
3190
|
+
checked: props.text.color === color,
|
|
3191
|
+
children: dict.color_picker.colors[color]
|
|
3192
|
+
},
|
|
3193
|
+
"text-color-" + color
|
|
3194
|
+
))
|
|
3195
|
+
] }) : null,
|
|
3196
|
+
props.background ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
3197
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Components.Generic.Menu.Label, { children: props.backgroundTitle ?? dict.color_picker.background_title }),
|
|
3198
|
+
COLORS.map((color) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3199
|
+
Components.Generic.Menu.Item,
|
|
3200
|
+
{
|
|
3201
|
+
onClick: () => {
|
|
3202
|
+
props.onClick?.();
|
|
3203
|
+
props.background.setColor(color);
|
|
3204
|
+
},
|
|
3205
|
+
"data-test": "background-color-" + color,
|
|
3206
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ColorIcon, { backgroundColor: color, size: props.iconSize }),
|
|
3207
|
+
checked: props.background.color === color,
|
|
3208
|
+
children: dict.color_picker.colors[color]
|
|
3209
|
+
},
|
|
3210
|
+
"background-color-" + color
|
|
3211
|
+
))
|
|
3212
|
+
] }) : null
|
|
3213
|
+
] });
|
|
3214
|
+
}
|
|
3215
|
+
function LumirColorStyleButton() {
|
|
3216
|
+
const Components = (0, import_react22.useComponentsContext)();
|
|
3217
|
+
const editor = (0, import_react22.useBlockNoteEditor)();
|
|
3218
|
+
const ed = editor;
|
|
3219
|
+
const styleSchema = editor.schema.styleSchema;
|
|
3220
|
+
const textColorInSchema = styleSchema.textColor?.type === "textColor" && styleSchema.textColor?.propSchema === "string";
|
|
3221
|
+
const backgroundColorInSchema = styleSchema.backgroundColor?.type === "backgroundColor" && styleSchema.backgroundColor?.propSchema === "string";
|
|
3222
|
+
const selectedBlocks = (0, import_react22.useSelectedBlocks)(editor);
|
|
3223
|
+
const [currentTextColor, setCurrentTextColor] = (0, import_react23.useState)(
|
|
3224
|
+
textColorInSchema ? ed.getActiveStyles().textColor || "default" : "default"
|
|
3225
|
+
);
|
|
3226
|
+
const [currentBackgroundColor, setCurrentBackgroundColor] = (0, import_react23.useState)(
|
|
3227
|
+
backgroundColorInSchema ? ed.getActiveStyles().backgroundColor || "default" : "default"
|
|
3228
|
+
);
|
|
3229
|
+
(0, import_react22.useEditorContentOrSelectionChange)(() => {
|
|
3230
|
+
const active = ed.getActiveStyles();
|
|
3231
|
+
if (textColorInSchema) {
|
|
3232
|
+
setCurrentTextColor(active.textColor || "default");
|
|
3233
|
+
}
|
|
3234
|
+
if (backgroundColorInSchema) {
|
|
3235
|
+
setCurrentBackgroundColor(active.backgroundColor || "default");
|
|
3236
|
+
}
|
|
3237
|
+
}, editor);
|
|
3238
|
+
const setTextColor = (0, import_react23.useCallback)(
|
|
3239
|
+
(color) => {
|
|
3240
|
+
color === "default" ? ed.removeStyles({ textColor: color }) : ed.addStyles({ textColor: color });
|
|
3241
|
+
setTimeout(() => editor.focus());
|
|
3242
|
+
},
|
|
3243
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3244
|
+
[editor]
|
|
3245
|
+
);
|
|
3246
|
+
const setBackgroundColor = (0, import_react23.useCallback)(
|
|
3247
|
+
(color) => {
|
|
3248
|
+
color === "default" ? ed.removeStyles({ backgroundColor: color }) : ed.addStyles({ backgroundColor: color });
|
|
3249
|
+
setTimeout(() => editor.focus());
|
|
3250
|
+
},
|
|
3251
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3252
|
+
[editor]
|
|
3253
|
+
);
|
|
3254
|
+
const show = (0, import_react23.useMemo)(() => {
|
|
3255
|
+
if (!textColorInSchema && !backgroundColorInSchema) {
|
|
3256
|
+
return false;
|
|
3257
|
+
}
|
|
3258
|
+
for (const block of selectedBlocks) {
|
|
3259
|
+
if (block.content !== void 0) {
|
|
3260
|
+
return true;
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
return false;
|
|
3264
|
+
}, [backgroundColorInSchema, selectedBlocks, textColorInSchema]);
|
|
3265
|
+
if (!show || !editor.isEditable) {
|
|
3266
|
+
return null;
|
|
3267
|
+
}
|
|
3268
|
+
const tooltip = "\uD14D\uC2A4\uD2B8 \uC0C9\xB7\uBC30\uACBD";
|
|
3269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Components.Generic.Menu.Root, { children: [
|
|
3270
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3271
|
+
Components.FormattingToolbar.Button,
|
|
3272
|
+
{
|
|
3273
|
+
className: "bn-button",
|
|
3274
|
+
"data-test": "colors",
|
|
3275
|
+
label: tooltip,
|
|
3276
|
+
mainTooltip: tooltip,
|
|
3277
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3278
|
+
ColorIcon,
|
|
3279
|
+
{
|
|
3280
|
+
textColor: currentTextColor,
|
|
3281
|
+
backgroundColor: currentBackgroundColor,
|
|
3282
|
+
size: 20
|
|
3283
|
+
}
|
|
3284
|
+
)
|
|
3285
|
+
}
|
|
3286
|
+
) }),
|
|
3087
3287
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3088
|
-
|
|
3288
|
+
Components.Generic.Menu.Dropdown,
|
|
3289
|
+
{
|
|
3290
|
+
className: "bn-menu-dropdown bn-color-picker-dropdown",
|
|
3291
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3292
|
+
LumirColorPicker,
|
|
3293
|
+
{
|
|
3294
|
+
textTitle: "\uD14D\uC2A4\uD2B8 \uC0C9",
|
|
3295
|
+
backgroundTitle: "\uD14D\uC2A4\uD2B8 \uBC30\uACBD",
|
|
3296
|
+
text: textColorInSchema ? { color: currentTextColor, setColor: setTextColor } : void 0,
|
|
3297
|
+
background: backgroundColorInSchema ? { color: currentBackgroundColor, setColor: setBackgroundColor } : void 0
|
|
3298
|
+
}
|
|
3299
|
+
)
|
|
3300
|
+
}
|
|
3301
|
+
)
|
|
3302
|
+
] });
|
|
3303
|
+
}
|
|
3304
|
+
function LumirCellColorToolbarButton() {
|
|
3305
|
+
const Components = (0, import_react22.useComponentsContext)();
|
|
3306
|
+
const editor = (0, import_react22.useBlockNoteEditor)();
|
|
3307
|
+
const selectedBlocks = (0, import_react22.useSelectedBlocks)(editor);
|
|
3308
|
+
const isMultiCell = (0, import_react23.useMemo)(() => {
|
|
3309
|
+
if (selectedBlocks.length !== 1 || selectedBlocks[0].type !== "table") {
|
|
3310
|
+
return false;
|
|
3311
|
+
}
|
|
3312
|
+
const cs = editor.tableHandles?.getCellSelection();
|
|
3313
|
+
return !!cs && cs.cells.length > 1;
|
|
3314
|
+
}, [editor, selectedBlocks]);
|
|
3315
|
+
const stashRef = (0, import_react23.useRef)([]);
|
|
3316
|
+
const applyBackground = (0, import_react23.useCallback)(
|
|
3317
|
+
(color) => {
|
|
3318
|
+
const live = getSelectedCellPositions(editor);
|
|
3319
|
+
const positions = live.length > 0 ? live : stashRef.current;
|
|
3320
|
+
setCellAttrAtPositions(editor, positions, "backgroundColor", color);
|
|
3321
|
+
setTimeout(() => editor.focus());
|
|
3322
|
+
},
|
|
3323
|
+
[editor]
|
|
3324
|
+
);
|
|
3325
|
+
if (!editor.isEditable || !isMultiCell) {
|
|
3326
|
+
return null;
|
|
3327
|
+
}
|
|
3328
|
+
const tooltip = "\uC140 \uBC30\uACBD\uC0C9";
|
|
3329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
3330
|
+
Components.Generic.Menu.Root,
|
|
3331
|
+
{
|
|
3332
|
+
onOpenChange: (open) => {
|
|
3333
|
+
if (open) {
|
|
3334
|
+
stashRef.current = getSelectedCellPositions(editor);
|
|
3335
|
+
}
|
|
3336
|
+
},
|
|
3337
|
+
children: [
|
|
3338
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Components.Generic.Menu.Trigger, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3339
|
+
Components.FormattingToolbar.Button,
|
|
3340
|
+
{
|
|
3341
|
+
className: "bn-button",
|
|
3342
|
+
"data-test": "cell-colors",
|
|
3343
|
+
label: tooltip,
|
|
3344
|
+
mainTooltip: tooltip,
|
|
3345
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(CellFillIcon, { size: 18 })
|
|
3346
|
+
}
|
|
3347
|
+
) }),
|
|
3348
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3349
|
+
Components.Generic.Menu.Dropdown,
|
|
3350
|
+
{
|
|
3351
|
+
className: "bn-menu-dropdown bn-color-picker-dropdown",
|
|
3352
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3353
|
+
LumirColorPicker,
|
|
3354
|
+
{
|
|
3355
|
+
backgroundTitle: "\uC140 \uBC30\uACBD",
|
|
3356
|
+
background: { color: "default", setColor: applyBackground }
|
|
3357
|
+
}
|
|
3358
|
+
)
|
|
3359
|
+
}
|
|
3360
|
+
)
|
|
3361
|
+
]
|
|
3362
|
+
}
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
3365
|
+
function LumirCellColorPickerButton(props) {
|
|
3366
|
+
const Components = (0, import_react22.useComponentsContext)();
|
|
3367
|
+
const editor = (0, import_react22.useBlockNoteEditor)();
|
|
3368
|
+
const updateColor = (color, type) => {
|
|
3369
|
+
const newTable = props.block.content.rows.map((row) => ({
|
|
3370
|
+
...row,
|
|
3371
|
+
cells: row.cells.map((cell) => (0, import_core4.mapTableCell)(cell))
|
|
3372
|
+
}));
|
|
3373
|
+
if (type === "text") {
|
|
3374
|
+
newTable[props.rowIndex].cells[props.colIndex].props.textColor = color;
|
|
3375
|
+
} else {
|
|
3376
|
+
newTable[props.rowIndex].cells[props.colIndex].props.backgroundColor = color;
|
|
3377
|
+
}
|
|
3378
|
+
editor.updateBlock(props.block, {
|
|
3379
|
+
type: "table",
|
|
3380
|
+
content: { ...props.block.content, rows: newTable }
|
|
3381
|
+
});
|
|
3382
|
+
editor.setTextCursorPosition(props.block);
|
|
3383
|
+
};
|
|
3384
|
+
const currentCell = props.block.content.rows[props.rowIndex]?.cells?.[props.colIndex];
|
|
3385
|
+
if (!currentCell || editor.settings.tables.cellTextColor === false && editor.settings.tables.cellBackgroundColor === false) {
|
|
3386
|
+
return null;
|
|
3387
|
+
}
|
|
3388
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Components.Generic.Menu.Root, { position: "right", sub: true, children: [
|
|
3389
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Components.Generic.Menu.Trigger, { sub: true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Components.Generic.Menu.Item, { className: "bn-menu-item", subTrigger: true, children: "\uC140 \uC0C9\xB7\uBC30\uACBD" }) }),
|
|
3390
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3391
|
+
Components.Generic.Menu.Dropdown,
|
|
3392
|
+
{
|
|
3393
|
+
sub: true,
|
|
3394
|
+
className: "bn-menu-dropdown bn-color-picker-dropdown",
|
|
3395
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3396
|
+
LumirColorPicker,
|
|
3397
|
+
{
|
|
3398
|
+
iconSize: 18,
|
|
3399
|
+
textTitle: "\uC140 \uAE00\uC790\uC0C9",
|
|
3400
|
+
backgroundTitle: "\uC140 \uBC30\uACBD",
|
|
3401
|
+
text: editor.settings.tables.cellTextColor ? {
|
|
3402
|
+
color: (0, import_core4.isTableCell)(currentCell) ? currentCell.props.textColor : "default",
|
|
3403
|
+
setColor: (color) => updateColor(color, "text")
|
|
3404
|
+
} : void 0,
|
|
3405
|
+
background: editor.settings.tables.cellBackgroundColor ? {
|
|
3406
|
+
color: (0, import_core4.isTableCell)(currentCell) ? currentCell.props.backgroundColor : "default",
|
|
3407
|
+
setColor: (color) => updateColor(color, "background")
|
|
3408
|
+
} : void 0
|
|
3409
|
+
}
|
|
3410
|
+
)
|
|
3411
|
+
}
|
|
3412
|
+
)
|
|
3413
|
+
] });
|
|
3414
|
+
}
|
|
3415
|
+
function LumirTableCellMenu(props) {
|
|
3416
|
+
const Components = (0, import_react22.useComponentsContext)();
|
|
3417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3418
|
+
Components.Generic.Menu.Dropdown,
|
|
3419
|
+
{
|
|
3420
|
+
className: "bn-menu-dropdown bn-drag-handle-menu",
|
|
3421
|
+
children: props.children || /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
3422
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3423
|
+
import_react22.SplitButton,
|
|
3424
|
+
{
|
|
3425
|
+
block: props.block,
|
|
3426
|
+
rowIndex: props.rowIndex,
|
|
3427
|
+
colIndex: props.colIndex
|
|
3428
|
+
}
|
|
3429
|
+
),
|
|
3430
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3431
|
+
LumirCellColorPickerButton,
|
|
3432
|
+
{
|
|
3433
|
+
block: props.block,
|
|
3434
|
+
rowIndex: props.rowIndex,
|
|
3435
|
+
colIndex: props.colIndex
|
|
3436
|
+
}
|
|
3437
|
+
)
|
|
3438
|
+
] })
|
|
3439
|
+
}
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
// src/components/CustomFormattingToolbar.tsx
|
|
3444
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
3445
|
+
var CustomFormattingToolbar = () => {
|
|
3446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react24.FormattingToolbar, { children: [
|
|
3447
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.BlockTypeSelect, {}, "blockTypeSelect"),
|
|
3448
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.TableCellMergeButton, {}, "tableCellMergeButton"),
|
|
3449
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.FileCaptionButton, {}, "fileCaptionButton"),
|
|
3450
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.FileReplaceButton, {}, "replaceFileButton"),
|
|
3451
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.FileRenameButton, {}, "fileRenameButton"),
|
|
3452
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.FileDeleteButton, {}, "fileDeleteButton"),
|
|
3453
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.FileDownloadButton, {}, "fileDownloadButton"),
|
|
3454
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.FilePreviewButton, {}, "filePreviewButton"),
|
|
3455
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.BasicTextStyleButton, { basicTextStyle: "bold" }, "boldStyleButton"),
|
|
3456
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3457
|
+
import_react24.BasicTextStyleButton,
|
|
3089
3458
|
{
|
|
3090
3459
|
basicTextStyle: "italic"
|
|
3091
3460
|
},
|
|
3092
3461
|
"italicStyleButton"
|
|
3093
3462
|
),
|
|
3094
|
-
/* @__PURE__ */ (0,
|
|
3095
|
-
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3464
|
+
import_react24.BasicTextStyleButton,
|
|
3096
3465
|
{
|
|
3097
3466
|
basicTextStyle: "underline"
|
|
3098
3467
|
},
|
|
3099
3468
|
"underlineStyleButton"
|
|
3100
3469
|
),
|
|
3101
|
-
/* @__PURE__ */ (0,
|
|
3102
|
-
|
|
3470
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3471
|
+
import_react24.BasicTextStyleButton,
|
|
3103
3472
|
{
|
|
3104
3473
|
basicTextStyle: "strike"
|
|
3105
3474
|
},
|
|
3106
3475
|
"strikeStyleButton"
|
|
3107
3476
|
),
|
|
3108
|
-
/* @__PURE__ */ (0,
|
|
3109
|
-
/* @__PURE__ */ (0,
|
|
3477
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TextAlignButtonWithVA, { textAlignment: "left" }, "textAlignLeftButton"),
|
|
3478
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3110
3479
|
TextAlignButtonWithVA,
|
|
3111
3480
|
{
|
|
3112
3481
|
textAlignment: "center"
|
|
3113
3482
|
},
|
|
3114
3483
|
"textAlignCenterButton"
|
|
3115
3484
|
),
|
|
3116
|
-
/* @__PURE__ */ (0,
|
|
3117
|
-
/* @__PURE__ */ (0,
|
|
3485
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TextAlignButtonWithVA, { textAlignment: "right" }, "textAlignRightButton"),
|
|
3486
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3118
3487
|
VerticalAlignButton,
|
|
3119
3488
|
{
|
|
3120
3489
|
verticalAlignment: "top"
|
|
3121
3490
|
},
|
|
3122
3491
|
"verticalAlignTop"
|
|
3123
3492
|
),
|
|
3124
|
-
/* @__PURE__ */ (0,
|
|
3493
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3125
3494
|
VerticalAlignButton,
|
|
3126
3495
|
{
|
|
3127
3496
|
verticalAlignment: "middle"
|
|
3128
3497
|
},
|
|
3129
3498
|
"verticalAlignMiddle"
|
|
3130
3499
|
),
|
|
3131
|
-
/* @__PURE__ */ (0,
|
|
3500
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3132
3501
|
VerticalAlignButton,
|
|
3133
3502
|
{
|
|
3134
3503
|
verticalAlignment: "bottom"
|
|
3135
3504
|
},
|
|
3136
3505
|
"verticalAlignBottom"
|
|
3137
3506
|
),
|
|
3138
|
-
/* @__PURE__ */ (0,
|
|
3139
|
-
/* @__PURE__ */ (0,
|
|
3140
|
-
/* @__PURE__ */ (0,
|
|
3141
|
-
/* @__PURE__ */ (0,
|
|
3507
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LumirColorStyleButton, {}, "colorStyleButton"),
|
|
3508
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LumirCellColorToolbarButton, {}, "cellColorButton"),
|
|
3509
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.NestBlockButton, {}, "nestBlockButton"),
|
|
3510
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.UnnestBlockButton, {}, "unnestBlockButton"),
|
|
3511
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react24.CreateLinkButton, {}, "createLinkButton")
|
|
3142
3512
|
] });
|
|
3143
3513
|
};
|
|
3144
3514
|
|
|
3515
|
+
// src/components/LumirTableHandlesController.tsx
|
|
3516
|
+
var import_react27 = require("@blocknote/react");
|
|
3517
|
+
var import_react28 = require("@floating-ui/react");
|
|
3518
|
+
var import_react29 = require("react");
|
|
3519
|
+
|
|
3520
|
+
// src/components/hooks/useFocusedCellHandlePositioning.ts
|
|
3521
|
+
var import_react25 = require("@floating-ui/react");
|
|
3522
|
+
var import_react26 = require("react");
|
|
3523
|
+
function useFocusedCellHandlePositioning(cellEl, tbodyEl, orientation, show) {
|
|
3524
|
+
const { refs, floatingStyles, context } = (0, import_react25.useFloating)({
|
|
3525
|
+
open: show,
|
|
3526
|
+
placement: orientation === "row" ? "left" : orientation === "col" ? "top" : "right",
|
|
3527
|
+
// col/row: 가장자리 선(zero-size)에, cell: 셀 우측 보더에 14px hit-area 중앙 정렬(-7).
|
|
3528
|
+
middleware: [(0, import_react25.offset)(-7)],
|
|
3529
|
+
whileElementsMounted: import_react25.autoUpdate
|
|
3530
|
+
});
|
|
3531
|
+
const { isMounted, styles } = (0, import_react25.useTransitionStyles)(context);
|
|
3532
|
+
(0, import_react26.useEffect)(() => {
|
|
3533
|
+
if (!cellEl) {
|
|
3534
|
+
refs.setReference(null);
|
|
3535
|
+
return;
|
|
3536
|
+
}
|
|
3537
|
+
refs.setReference({
|
|
3538
|
+
contextElement: cellEl,
|
|
3539
|
+
getBoundingClientRect: () => {
|
|
3540
|
+
const c = cellEl.getBoundingClientRect();
|
|
3541
|
+
const t = tbodyEl?.getBoundingClientRect() ?? c;
|
|
3542
|
+
if (orientation === "col") {
|
|
3543
|
+
return new DOMRect(c.left, t.top, c.width, 0);
|
|
3544
|
+
}
|
|
3545
|
+
if (orientation === "row") {
|
|
3546
|
+
return new DOMRect(t.left, c.top, 0, c.height);
|
|
3547
|
+
}
|
|
3548
|
+
return c;
|
|
3549
|
+
}
|
|
3550
|
+
});
|
|
3551
|
+
}, [cellEl, tbodyEl, orientation, refs]);
|
|
3552
|
+
return (0, import_react26.useMemo)(
|
|
3553
|
+
() => ({
|
|
3554
|
+
isMounted,
|
|
3555
|
+
ref: refs.setFloating,
|
|
3556
|
+
// display는 CSS 클래스에서 제어한다(absolute 자식 stacking).
|
|
3557
|
+
style: {
|
|
3558
|
+
...styles,
|
|
3559
|
+
...floatingStyles
|
|
3560
|
+
}
|
|
3561
|
+
}),
|
|
3562
|
+
[floatingStyles, isMounted, refs.setFloating, styles]
|
|
3563
|
+
);
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
// src/components/LumirTableHandlesController.tsx
|
|
3567
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
3568
|
+
function syncCoreHoverToFocusedCell(cellEl) {
|
|
3569
|
+
const r = cellEl.getBoundingClientRect();
|
|
3570
|
+
cellEl.dispatchEvent(
|
|
3571
|
+
new MouseEvent("mousemove", {
|
|
3572
|
+
bubbles: true,
|
|
3573
|
+
cancelable: true,
|
|
3574
|
+
view: window,
|
|
3575
|
+
clientX: r.left + r.width / 2,
|
|
3576
|
+
clientY: r.top + r.height / 2
|
|
3577
|
+
})
|
|
3578
|
+
);
|
|
3579
|
+
}
|
|
3580
|
+
function LumirTableHandlesController() {
|
|
3581
|
+
const editor = (0, import_react27.useBlockNoteEditor)();
|
|
3582
|
+
const [focused, setFocused] = (0, import_react29.useState)(null);
|
|
3583
|
+
const [menuContainerRef, setMenuContainerRef] = (0, import_react29.useState)(null);
|
|
3584
|
+
const [overlayEl, setOverlayEl] = (0, import_react29.useState)(null);
|
|
3585
|
+
const [openMenu, setOpenMenu] = (0, import_react29.useState)(null);
|
|
3586
|
+
const frozenRef = (0, import_react29.useRef)(false);
|
|
3587
|
+
const menuOpenRef = (0, import_react29.useRef)(false);
|
|
3588
|
+
const draggingRef = (0, import_react29.useRef)(false);
|
|
3589
|
+
const recompute = (0, import_react29.useCallback)(() => {
|
|
3590
|
+
if (frozenRef.current) {
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3593
|
+
const th2 = editor.tableHandles;
|
|
3594
|
+
const view = editor.prosemirrorView;
|
|
3595
|
+
if (!th2 || !view) {
|
|
3596
|
+
setFocused(null);
|
|
3597
|
+
return;
|
|
3598
|
+
}
|
|
3599
|
+
let cellEl2 = null;
|
|
3600
|
+
try {
|
|
3601
|
+
const { node } = view.domAtPos(view.state.selection.from);
|
|
3602
|
+
const el = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
|
|
3603
|
+
cellEl2 = el?.closest?.("td, th") ?? null;
|
|
3604
|
+
} catch {
|
|
3605
|
+
cellEl2 = null;
|
|
3606
|
+
}
|
|
3607
|
+
if (!cellEl2 || !cellEl2.isConnected) {
|
|
3608
|
+
setFocused(null);
|
|
3609
|
+
return;
|
|
3610
|
+
}
|
|
3611
|
+
const blockId = cellEl2.closest("[data-id]")?.getAttribute("data-id");
|
|
3612
|
+
const block = blockId ? editor.getBlock(blockId) : void 0;
|
|
3613
|
+
if (!block || block.type !== "table") {
|
|
3614
|
+
setFocused(null);
|
|
3615
|
+
return;
|
|
3616
|
+
}
|
|
3617
|
+
const cellSel = th2.getCellSelection();
|
|
3618
|
+
if (!cellSel) {
|
|
3619
|
+
setFocused(null);
|
|
3620
|
+
return;
|
|
3621
|
+
}
|
|
3622
|
+
const widgetContainer = cellEl2.closest(".tableWrapper")?.querySelector(".table-widgets-container");
|
|
3623
|
+
const tbodyEl2 = cellEl2.closest("tbody");
|
|
3624
|
+
if (!widgetContainer || !tbodyEl2) {
|
|
3625
|
+
setFocused(null);
|
|
3626
|
+
return;
|
|
3627
|
+
}
|
|
3628
|
+
setFocused({
|
|
3629
|
+
block,
|
|
3630
|
+
rowIndex: cellSel.from.row,
|
|
3631
|
+
colIndex: cellSel.from.col,
|
|
3632
|
+
cellEl: cellEl2,
|
|
3633
|
+
tbodyEl: tbodyEl2,
|
|
3634
|
+
widgetContainer
|
|
3635
|
+
});
|
|
3636
|
+
}, [editor]);
|
|
3637
|
+
(0, import_react27.useEditorContentOrSelectionChange)(recompute, editor);
|
|
3638
|
+
(0, import_react29.useEffect)(() => {
|
|
3639
|
+
recompute();
|
|
3640
|
+
}, [recompute]);
|
|
3641
|
+
(0, import_react29.useEffect)(() => {
|
|
3642
|
+
const onUp = () => {
|
|
3643
|
+
requestAnimationFrame(() => {
|
|
3644
|
+
if (!menuOpenRef.current && !draggingRef.current && frozenRef.current) {
|
|
3645
|
+
frozenRef.current = false;
|
|
3646
|
+
recompute();
|
|
3647
|
+
}
|
|
3648
|
+
});
|
|
3649
|
+
};
|
|
3650
|
+
window.addEventListener("pointerup", onUp);
|
|
3651
|
+
return () => window.removeEventListener("pointerup", onUp);
|
|
3652
|
+
}, [recompute]);
|
|
3653
|
+
(0, import_react29.useEffect)(() => {
|
|
3654
|
+
const f = focused;
|
|
3655
|
+
if (!f || !overlayEl) {
|
|
3656
|
+
return;
|
|
3657
|
+
}
|
|
3658
|
+
const PAD = 1;
|
|
3659
|
+
const update = () => {
|
|
3660
|
+
const cr = f.cellEl.getBoundingClientRect();
|
|
3661
|
+
const tr = f.tbodyEl.getBoundingClientRect();
|
|
3662
|
+
const kr = f.widgetContainer.getBoundingClientRect();
|
|
3663
|
+
const x1 = openMenu === "row" ? tr.left : cr.left;
|
|
3664
|
+
const y1 = openMenu === "col" ? tr.top : cr.top;
|
|
3665
|
+
const x2 = openMenu === "row" ? tr.right : cr.right;
|
|
3666
|
+
const y2 = openMenu === "col" ? tr.bottom : cr.bottom;
|
|
3667
|
+
const dpr = window.devicePixelRatio || 1;
|
|
3668
|
+
const rd = (v) => Math.round(v * dpr) / dpr;
|
|
3669
|
+
const left = rd(x1 - kr.left) - PAD;
|
|
3670
|
+
const top = rd(y1 - kr.top) - PAD;
|
|
3671
|
+
const right = rd(x2 - kr.left) + PAD;
|
|
3672
|
+
const bottom = rd(y2 - kr.top) + PAD;
|
|
3673
|
+
overlayEl.style.transform = `translate(${left}px, ${top}px)`;
|
|
3674
|
+
overlayEl.style.width = `${right - left}px`;
|
|
3675
|
+
overlayEl.style.height = `${bottom - top}px`;
|
|
3676
|
+
};
|
|
3677
|
+
update();
|
|
3678
|
+
return (0, import_react28.autoUpdate)(f.cellEl, overlayEl, update);
|
|
3679
|
+
}, [focused, overlayEl, openMenu]);
|
|
3680
|
+
const cellEl = focused?.cellEl ?? null;
|
|
3681
|
+
const tbodyEl = focused?.tbodyEl ?? null;
|
|
3682
|
+
const show = focused !== null;
|
|
3683
|
+
const rowHandle = useFocusedCellHandlePositioning(cellEl, tbodyEl, "row", show);
|
|
3684
|
+
const colHandle = useFocusedCellHandlePositioning(cellEl, tbodyEl, "col", show);
|
|
3685
|
+
const cellHandle = useFocusedCellHandlePositioning(
|
|
3686
|
+
cellEl,
|
|
3687
|
+
tbodyEl,
|
|
3688
|
+
"cell",
|
|
3689
|
+
show
|
|
3690
|
+
);
|
|
3691
|
+
const th = editor.tableHandles;
|
|
3692
|
+
const coreState = (0, import_react27.useUIPluginState)(
|
|
3693
|
+
editor.tableHandles.onUpdate.bind(editor.tableHandles)
|
|
3694
|
+
);
|
|
3695
|
+
const { addOrRemoveColumnsButton, addOrRemoveRowsButton } = (0, import_react27.useExtendButtonsPositioning)(
|
|
3696
|
+
coreState?.showAddOrRemoveColumnsButton || false,
|
|
3697
|
+
coreState?.showAddOrRemoveRowsButton || false,
|
|
3698
|
+
coreState?.referencePosTable || null
|
|
3699
|
+
);
|
|
3700
|
+
const onStartExtend = (0, import_react29.useCallback)(() => {
|
|
3701
|
+
editor.tableHandles?.freezeHandles();
|
|
3702
|
+
}, [editor]);
|
|
3703
|
+
const onEndExtend = (0, import_react29.useCallback)(() => {
|
|
3704
|
+
editor.tableHandles?.unfreezeHandles();
|
|
3705
|
+
}, [editor]);
|
|
3706
|
+
const menuHandlers = (0, import_react29.useMemo)(() => {
|
|
3707
|
+
const mk = (kind) => ({
|
|
3708
|
+
freeze: () => {
|
|
3709
|
+
menuOpenRef.current = true;
|
|
3710
|
+
frozenRef.current = true;
|
|
3711
|
+
setOpenMenu(kind);
|
|
3712
|
+
editor.tableHandles?.freezeHandles();
|
|
3713
|
+
},
|
|
3714
|
+
unfreeze: () => {
|
|
3715
|
+
menuOpenRef.current = false;
|
|
3716
|
+
frozenRef.current = false;
|
|
3717
|
+
setOpenMenu(null);
|
|
3718
|
+
editor.tableHandles?.unfreezeHandles();
|
|
3719
|
+
recompute();
|
|
3720
|
+
}
|
|
3721
|
+
});
|
|
3722
|
+
return { col: mk("col"), row: mk("row"), cell: mk("cell") };
|
|
3723
|
+
}, [editor, recompute]);
|
|
3724
|
+
const onGutterPointerDown = (0, import_react29.useCallback)(() => {
|
|
3725
|
+
frozenRef.current = true;
|
|
3726
|
+
}, []);
|
|
3727
|
+
const onGutterPointerEnter = (0, import_react29.useCallback)(
|
|
3728
|
+
(e) => {
|
|
3729
|
+
if (e.buttons === 0 && focused) {
|
|
3730
|
+
syncCoreHoverToFocusedCell(focused.cellEl);
|
|
3731
|
+
}
|
|
3732
|
+
},
|
|
3733
|
+
[focused]
|
|
3734
|
+
);
|
|
3735
|
+
const makeDragStart = (0, import_react29.useCallback)(
|
|
3736
|
+
(dir) => (e) => {
|
|
3737
|
+
draggingRef.current = true;
|
|
3738
|
+
frozenRef.current = true;
|
|
3739
|
+
if (dir === "row") {
|
|
3740
|
+
editor.tableHandles?.rowDragStart(e);
|
|
3741
|
+
} else {
|
|
3742
|
+
editor.tableHandles?.colDragStart(e);
|
|
3743
|
+
}
|
|
3744
|
+
},
|
|
3745
|
+
[editor]
|
|
3746
|
+
);
|
|
3747
|
+
const onDragEnd = (0, import_react29.useCallback)(() => {
|
|
3748
|
+
editor.tableHandles?.dragEnd();
|
|
3749
|
+
draggingRef.current = false;
|
|
3750
|
+
frozenRef.current = false;
|
|
3751
|
+
recompute();
|
|
3752
|
+
}, [editor, recompute]);
|
|
3753
|
+
const noop = (0, import_react29.useCallback)(() => {
|
|
3754
|
+
}, []);
|
|
3755
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
3756
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref: setMenuContainerRef }),
|
|
3757
|
+
th && focused && menuContainerRef && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react28.FloatingPortal, { root: focused.widgetContainer, children: [
|
|
3758
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref: setOverlayEl, className: "lumir-tbl-cell-focus" }),
|
|
3759
|
+
colHandle.isMounted && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3760
|
+
"div",
|
|
3761
|
+
{
|
|
3762
|
+
ref: colHandle.ref,
|
|
3763
|
+
style: colHandle.style,
|
|
3764
|
+
className: "lumir-tbl-gutter-wrap lumir-tbl-gutter-wrap--col" + (openMenu === "col" ? " lumir-tbl-gutter-wrap--active" : ""),
|
|
3765
|
+
onPointerEnter: onGutterPointerEnter,
|
|
3766
|
+
onPointerDown: onGutterPointerDown,
|
|
3767
|
+
children: [
|
|
3768
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "lumir-tbl-gutter" }),
|
|
3769
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3770
|
+
import_react27.TableHandle,
|
|
3771
|
+
{
|
|
3772
|
+
editor,
|
|
3773
|
+
orientation: "column",
|
|
3774
|
+
index: focused.colIndex,
|
|
3775
|
+
block: focused.block,
|
|
3776
|
+
dragStart: makeDragStart("col"),
|
|
3777
|
+
dragEnd: onDragEnd,
|
|
3778
|
+
freezeHandles: menuHandlers.col.freeze,
|
|
3779
|
+
unfreezeHandles: menuHandlers.col.unfreeze,
|
|
3780
|
+
menuContainer: menuContainerRef,
|
|
3781
|
+
showOtherSide: noop,
|
|
3782
|
+
hideOtherSide: noop
|
|
3783
|
+
}
|
|
3784
|
+
) })
|
|
3785
|
+
]
|
|
3786
|
+
}
|
|
3787
|
+
),
|
|
3788
|
+
rowHandle.isMounted && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3789
|
+
"div",
|
|
3790
|
+
{
|
|
3791
|
+
ref: rowHandle.ref,
|
|
3792
|
+
style: rowHandle.style,
|
|
3793
|
+
className: "lumir-tbl-gutter-wrap lumir-tbl-gutter-wrap--row" + (openMenu === "row" ? " lumir-tbl-gutter-wrap--active" : ""),
|
|
3794
|
+
onPointerEnter: onGutterPointerEnter,
|
|
3795
|
+
onPointerDown: onGutterPointerDown,
|
|
3796
|
+
children: [
|
|
3797
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "lumir-tbl-gutter" }),
|
|
3798
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3799
|
+
import_react27.TableHandle,
|
|
3800
|
+
{
|
|
3801
|
+
editor,
|
|
3802
|
+
orientation: "row",
|
|
3803
|
+
index: focused.rowIndex,
|
|
3804
|
+
block: focused.block,
|
|
3805
|
+
dragStart: makeDragStart("row"),
|
|
3806
|
+
dragEnd: onDragEnd,
|
|
3807
|
+
freezeHandles: menuHandlers.row.freeze,
|
|
3808
|
+
unfreezeHandles: menuHandlers.row.unfreeze,
|
|
3809
|
+
menuContainer: menuContainerRef,
|
|
3810
|
+
showOtherSide: noop,
|
|
3811
|
+
hideOtherSide: noop
|
|
3812
|
+
}
|
|
3813
|
+
) })
|
|
3814
|
+
]
|
|
3815
|
+
}
|
|
3816
|
+
),
|
|
3817
|
+
cellHandle.isMounted && openMenu !== "col" && openMenu !== "row" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3818
|
+
"div",
|
|
3819
|
+
{
|
|
3820
|
+
ref: cellHandle.ref,
|
|
3821
|
+
style: cellHandle.style,
|
|
3822
|
+
className: "lumir-tbl-gutter-wrap lumir-tbl-gutter-wrap--cell" + (openMenu === "cell" ? " lumir-tbl-gutter-wrap--active" : ""),
|
|
3823
|
+
onPointerDown: onGutterPointerDown,
|
|
3824
|
+
children: [
|
|
3825
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "lumir-tbl-gutter" }),
|
|
3826
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "lumir-tbl-grip", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3827
|
+
import_react27.TableCellButton,
|
|
3828
|
+
{
|
|
3829
|
+
editor,
|
|
3830
|
+
rowIndex: focused.rowIndex,
|
|
3831
|
+
colIndex: focused.colIndex,
|
|
3832
|
+
block: focused.block,
|
|
3833
|
+
tableCellMenu: LumirTableCellMenu,
|
|
3834
|
+
menuContainer: menuContainerRef,
|
|
3835
|
+
freezeHandles: menuHandlers.cell.freeze,
|
|
3836
|
+
unfreezeHandles: menuHandlers.cell.unfreeze
|
|
3837
|
+
}
|
|
3838
|
+
) })
|
|
3839
|
+
]
|
|
3840
|
+
}
|
|
3841
|
+
)
|
|
3842
|
+
] }),
|
|
3843
|
+
th && coreState?.widgetContainer && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react28.FloatingPortal, { root: coreState.widgetContainer, children: [
|
|
3844
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref: addOrRemoveRowsButton.ref, style: addOrRemoveRowsButton.style, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3845
|
+
import_react27.ExtendButton,
|
|
3846
|
+
{
|
|
3847
|
+
editor,
|
|
3848
|
+
orientation: "addOrRemoveRows",
|
|
3849
|
+
block: coreState.block,
|
|
3850
|
+
onMouseDown: onStartExtend,
|
|
3851
|
+
onMouseUp: onEndExtend
|
|
3852
|
+
}
|
|
3853
|
+
) }),
|
|
3854
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3855
|
+
"div",
|
|
3856
|
+
{
|
|
3857
|
+
ref: addOrRemoveColumnsButton.ref,
|
|
3858
|
+
style: addOrRemoveColumnsButton.style,
|
|
3859
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3860
|
+
import_react27.ExtendButton,
|
|
3861
|
+
{
|
|
3862
|
+
editor,
|
|
3863
|
+
orientation: "addOrRemoveColumns",
|
|
3864
|
+
block: coreState.block,
|
|
3865
|
+
onMouseDown: onStartExtend,
|
|
3866
|
+
onMouseUp: onEndExtend
|
|
3867
|
+
}
|
|
3868
|
+
)
|
|
3869
|
+
}
|
|
3870
|
+
)
|
|
3871
|
+
] })
|
|
3872
|
+
] });
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3145
3875
|
// src/utils/table-vertical-alignment.ts
|
|
3146
3876
|
function injectVerticalAlignment(blocks, editor) {
|
|
3147
3877
|
const tiptap = editor?._tiptapEditor;
|
|
@@ -3224,6 +3954,235 @@ function patchBlocks(blocks, tableVAMap) {
|
|
|
3224
3954
|
});
|
|
3225
3955
|
}
|
|
3226
3956
|
|
|
3957
|
+
// src/utils/excel-paste.ts
|
|
3958
|
+
var NAMED_COLORS = {
|
|
3959
|
+
black: "#000000",
|
|
3960
|
+
white: "#ffffff",
|
|
3961
|
+
red: "#ff0000",
|
|
3962
|
+
green: "#008000",
|
|
3963
|
+
blue: "#0000ff",
|
|
3964
|
+
yellow: "#ffff00",
|
|
3965
|
+
orange: "#ffa500",
|
|
3966
|
+
purple: "#800080",
|
|
3967
|
+
gray: "#808080",
|
|
3968
|
+
grey: "#808080"
|
|
3969
|
+
};
|
|
3970
|
+
function parseCssColorToRgb(input) {
|
|
3971
|
+
if (!input) return null;
|
|
3972
|
+
const s = input.trim().toLowerCase();
|
|
3973
|
+
if (!s || s === "transparent" || s === "none" || s === "inherit") return null;
|
|
3974
|
+
let m = s.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/);
|
|
3975
|
+
if (m) {
|
|
3976
|
+
let h = m[1];
|
|
3977
|
+
if (h.length === 3)
|
|
3978
|
+
h = h.split("").map((c) => c + c).join("");
|
|
3979
|
+
return [
|
|
3980
|
+
parseInt(h.slice(0, 2), 16),
|
|
3981
|
+
parseInt(h.slice(2, 4), 16),
|
|
3982
|
+
parseInt(h.slice(4, 6), 16)
|
|
3983
|
+
];
|
|
3984
|
+
}
|
|
3985
|
+
m = s.match(/^rgba?\(([^)]+)\)$/);
|
|
3986
|
+
if (m) {
|
|
3987
|
+
const parts = m[1].split(",").map((x) => parseFloat(x.trim()));
|
|
3988
|
+
if (parts.length >= 3 && parts.slice(0, 3).every((n) => !isNaN(n))) {
|
|
3989
|
+
return [parts[0], parts[1], parts[2]];
|
|
3990
|
+
}
|
|
3991
|
+
return null;
|
|
3992
|
+
}
|
|
3993
|
+
if (NAMED_COLORS[s]) return parseCssColorToRgb(NAMED_COLORS[s]);
|
|
3994
|
+
return null;
|
|
3995
|
+
}
|
|
3996
|
+
function rgbToHsl([r, g, b]) {
|
|
3997
|
+
r /= 255;
|
|
3998
|
+
g /= 255;
|
|
3999
|
+
b /= 255;
|
|
4000
|
+
const max = Math.max(r, g, b);
|
|
4001
|
+
const min = Math.min(r, g, b);
|
|
4002
|
+
const l = (max + min) / 2;
|
|
4003
|
+
let h = 0;
|
|
4004
|
+
let s = 0;
|
|
4005
|
+
const d = max - min;
|
|
4006
|
+
if (d !== 0) {
|
|
4007
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
4008
|
+
switch (max) {
|
|
4009
|
+
case r:
|
|
4010
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) * 60;
|
|
4011
|
+
break;
|
|
4012
|
+
case g:
|
|
4013
|
+
h = ((b - r) / d + 2) * 60;
|
|
4014
|
+
break;
|
|
4015
|
+
default:
|
|
4016
|
+
h = ((r - g) / d + 4) * 60;
|
|
4017
|
+
break;
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
return [h, s, l];
|
|
4021
|
+
}
|
|
4022
|
+
var HUE_REFERENCE = [
|
|
4023
|
+
{ value: "red", hue: 0 },
|
|
4024
|
+
{ value: "brown", hue: 17 },
|
|
4025
|
+
{ value: "orange", hue: 30 },
|
|
4026
|
+
{ value: "yellow", hue: 46 },
|
|
4027
|
+
{ value: "green", hue: 150 },
|
|
4028
|
+
{ value: "blue", hue: 197 },
|
|
4029
|
+
{ value: "purple", hue: 262 },
|
|
4030
|
+
{ value: "pink", hue: 324 }
|
|
4031
|
+
];
|
|
4032
|
+
function hueDist(a, b) {
|
|
4033
|
+
const d = Math.abs(a - b) % 360;
|
|
4034
|
+
return d > 180 ? 360 - d : d;
|
|
4035
|
+
}
|
|
4036
|
+
function paletteValueFromRgb(rgb) {
|
|
4037
|
+
const [h, s, l] = rgbToHsl(rgb);
|
|
4038
|
+
if (s < 0.15) {
|
|
4039
|
+
if (l < 0.35) return "default";
|
|
4040
|
+
if (l > 0.85) return "default";
|
|
4041
|
+
return "gray";
|
|
4042
|
+
}
|
|
4043
|
+
let best = "gray";
|
|
4044
|
+
let bestDist = Infinity;
|
|
4045
|
+
for (const ref of HUE_REFERENCE) {
|
|
4046
|
+
const d = hueDist(h, ref.hue);
|
|
4047
|
+
if (d < bestDist) {
|
|
4048
|
+
bestDist = d;
|
|
4049
|
+
best = ref.value;
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
return best;
|
|
4053
|
+
}
|
|
4054
|
+
function nearestTextColorValue(rgb) {
|
|
4055
|
+
return paletteValueFromRgb(rgb);
|
|
4056
|
+
}
|
|
4057
|
+
function nearestBackgroundColorValue(rgb) {
|
|
4058
|
+
const [, s, l] = rgbToHsl(rgb);
|
|
4059
|
+
if (s < 0.12 && l > 0.85) return "default";
|
|
4060
|
+
return paletteValueFromRgb(rgb);
|
|
4061
|
+
}
|
|
4062
|
+
function parseStyle(style) {
|
|
4063
|
+
const out = {};
|
|
4064
|
+
style.split(";").forEach((decl) => {
|
|
4065
|
+
const idx = decl.indexOf(":");
|
|
4066
|
+
if (idx === -1) return;
|
|
4067
|
+
const k = decl.slice(0, idx).trim().toLowerCase();
|
|
4068
|
+
const v = decl.slice(idx + 1).trim();
|
|
4069
|
+
if (k) out[k] = v;
|
|
4070
|
+
});
|
|
4071
|
+
return out;
|
|
4072
|
+
}
|
|
4073
|
+
function colorFromBackgroundShorthand(value) {
|
|
4074
|
+
if (!value) return null;
|
|
4075
|
+
const direct = parseCssColorToRgb(value);
|
|
4076
|
+
if (direct) return direct;
|
|
4077
|
+
for (const token of value.split(/\s+/)) {
|
|
4078
|
+
const rgb = parseCssColorToRgb(token);
|
|
4079
|
+
if (rgb) return rgb;
|
|
4080
|
+
}
|
|
4081
|
+
return null;
|
|
4082
|
+
}
|
|
4083
|
+
function isTransparentColor(css) {
|
|
4084
|
+
if (!css) return true;
|
|
4085
|
+
const s = css.trim().toLowerCase();
|
|
4086
|
+
if (s === "transparent" || s === "none") return true;
|
|
4087
|
+
const m = s.match(/^rgba?\(([^)]+)\)$/);
|
|
4088
|
+
if (m) {
|
|
4089
|
+
const p = m[1].split(",").map((x) => parseFloat(x.trim()));
|
|
4090
|
+
if (p.length >= 4 && p[3] === 0) return true;
|
|
4091
|
+
}
|
|
4092
|
+
return false;
|
|
4093
|
+
}
|
|
4094
|
+
function normalizeAlign(ta) {
|
|
4095
|
+
const v = (ta || "").trim().toLowerCase();
|
|
4096
|
+
if (v === "right" || v === "end") return "right";
|
|
4097
|
+
if (v === "center") return "center";
|
|
4098
|
+
if (v === "justify") return "justify";
|
|
4099
|
+
return "";
|
|
4100
|
+
}
|
|
4101
|
+
function applyCellFormatting(el, fmt) {
|
|
4102
|
+
if (fmt.bgRgb && !fmt.bgTransparent) {
|
|
4103
|
+
const v = nearestBackgroundColorValue(fmt.bgRgb);
|
|
4104
|
+
if (v !== "default") el.setAttribute("data-background-color", v);
|
|
4105
|
+
}
|
|
4106
|
+
if (fmt.colorRgb) {
|
|
4107
|
+
const v = nearestTextColorValue(fmt.colorRgb);
|
|
4108
|
+
if (v !== "default") el.setAttribute("data-text-color", v);
|
|
4109
|
+
}
|
|
4110
|
+
if (["right", "center", "justify"].includes(fmt.align)) {
|
|
4111
|
+
el.setAttribute("data-text-alignment", fmt.align);
|
|
4112
|
+
}
|
|
4113
|
+
if ((fmt.bold || fmt.italic || fmt.underline) && el.innerHTML.trim()) {
|
|
4114
|
+
let inner = el.innerHTML;
|
|
4115
|
+
if (fmt.underline) inner = `<u>${inner}</u>`;
|
|
4116
|
+
if (fmt.italic) inner = `<em>${inner}</em>`;
|
|
4117
|
+
if (fmt.bold) inner = `<strong>${inner}</strong>`;
|
|
4118
|
+
el.innerHTML = inner;
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
function readComputedFormat(el) {
|
|
4122
|
+
const cs = getComputedStyle(el);
|
|
4123
|
+
const fw = cs.fontWeight;
|
|
4124
|
+
const fwNum = parseInt(fw, 10);
|
|
4125
|
+
const decoration = cs.textDecorationLine || cs.textDecoration || "";
|
|
4126
|
+
return {
|
|
4127
|
+
bgRgb: parseCssColorToRgb(cs.backgroundColor),
|
|
4128
|
+
bgTransparent: isTransparentColor(cs.backgroundColor),
|
|
4129
|
+
colorRgb: parseCssColorToRgb(cs.color),
|
|
4130
|
+
align: normalizeAlign(cs.textAlign),
|
|
4131
|
+
bold: fw === "bold" || fw === "bolder" || !isNaN(fwNum) && fwNum >= 600,
|
|
4132
|
+
italic: (cs.fontStyle || "").toLowerCase().includes("italic"),
|
|
4133
|
+
underline: decoration.toLowerCase().includes("underline")
|
|
4134
|
+
};
|
|
4135
|
+
}
|
|
4136
|
+
function readInlineFormat(el) {
|
|
4137
|
+
const sm = parseStyle(el.getAttribute("style") || "");
|
|
4138
|
+
const bgRaw = sm["background-color"] || sm["background"] || "";
|
|
4139
|
+
const bgRgb = colorFromBackgroundShorthand(bgRaw) || parseCssColorToRgb(el.getAttribute("bgcolor"));
|
|
4140
|
+
const fw = (sm["font-weight"] || "").toLowerCase();
|
|
4141
|
+
const decoration = sm["text-decoration"] || sm["text-decoration-line"] || "";
|
|
4142
|
+
return {
|
|
4143
|
+
bgRgb,
|
|
4144
|
+
bgTransparent: !bgRaw && !el.getAttribute("bgcolor"),
|
|
4145
|
+
colorRgb: parseCssColorToRgb(sm["color"]),
|
|
4146
|
+
align: normalizeAlign(sm["text-align"] || el.getAttribute("align")),
|
|
4147
|
+
bold: fw === "bold" || fw === "bolder" || parseInt(fw, 10) >= 600,
|
|
4148
|
+
italic: (sm["font-style"] || "").toLowerCase().includes("italic"),
|
|
4149
|
+
underline: decoration.toLowerCase().includes("underline")
|
|
4150
|
+
};
|
|
4151
|
+
}
|
|
4152
|
+
function normalizeExcelTableHtml(html) {
|
|
4153
|
+
if (!html || typeof DOMParser === "undefined") return html;
|
|
4154
|
+
try {
|
|
4155
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
4156
|
+
doc.querySelectorAll("script").forEach((s) => s.remove());
|
|
4157
|
+
if (!doc.querySelector("table")) return html;
|
|
4158
|
+
if (typeof document !== "undefined" && document.body && typeof HTMLElement !== "undefined" && typeof HTMLElement.prototype.attachShadow === "function") {
|
|
4159
|
+
let host = null;
|
|
4160
|
+
try {
|
|
4161
|
+
host = document.createElement("div");
|
|
4162
|
+
host.setAttribute("aria-hidden", "true");
|
|
4163
|
+
host.style.cssText = "position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;opacity:0;pointer-events:none";
|
|
4164
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
4165
|
+
const styles = Array.from(doc.querySelectorAll("style")).map((s) => s.outerHTML).join("");
|
|
4166
|
+
shadow.innerHTML = styles + doc.body.innerHTML;
|
|
4167
|
+
document.body.appendChild(host);
|
|
4168
|
+
shadow.querySelectorAll("td, th").forEach((node) => {
|
|
4169
|
+
applyCellFormatting(node, readComputedFormat(node));
|
|
4170
|
+
});
|
|
4171
|
+
const out = Array.from(shadow.querySelectorAll("table")).map((t) => t.outerHTML).join("");
|
|
4172
|
+
return out || html;
|
|
4173
|
+
} finally {
|
|
4174
|
+
if (host && host.parentNode) host.parentNode.removeChild(host);
|
|
4175
|
+
}
|
|
4176
|
+
}
|
|
4177
|
+
doc.querySelectorAll("td, th").forEach((node) => {
|
|
4178
|
+
applyCellFormatting(node, readInlineFormat(node));
|
|
4179
|
+
});
|
|
4180
|
+
return Array.from(doc.querySelectorAll("table")).map((t) => t.outerHTML).join("") || html;
|
|
4181
|
+
} catch {
|
|
4182
|
+
return html;
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
|
|
3227
4186
|
// src/constants/limits.ts
|
|
3228
4187
|
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
3229
4188
|
var MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;
|
|
@@ -3243,7 +4202,7 @@ var ALLOWED_VIDEO_EXTENSIONS = [
|
|
|
3243
4202
|
];
|
|
3244
4203
|
|
|
3245
4204
|
// src/components/LumirEditor.tsx
|
|
3246
|
-
var
|
|
4205
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3247
4206
|
var DEBUG_LOG = (loc, msg, data) => {
|
|
3248
4207
|
const p = fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
3249
4208
|
method: "POST",
|
|
@@ -3468,9 +4427,9 @@ var findBlockWithLink = (blocks, targetUrl) => {
|
|
|
3468
4427
|
return null;
|
|
3469
4428
|
};
|
|
3470
4429
|
var ConvertToPreviewButton = ({ url }) => {
|
|
3471
|
-
const editor = (0,
|
|
3472
|
-
const Components = (0,
|
|
3473
|
-
return /* @__PURE__ */ (0,
|
|
4430
|
+
const editor = (0, import_react31.useBlockNoteEditor)();
|
|
4431
|
+
const Components = (0, import_react31.useComponentsContext)();
|
|
4432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3474
4433
|
Components.LinkToolbar.Button,
|
|
3475
4434
|
{
|
|
3476
4435
|
className: "bn-button",
|
|
@@ -3489,29 +4448,29 @@ var ConvertToPreviewButton = ({ url }) => {
|
|
|
3489
4448
|
console.error("Convert to link preview failed:", err);
|
|
3490
4449
|
}
|
|
3491
4450
|
},
|
|
3492
|
-
icon: /* @__PURE__ */ (0,
|
|
3493
|
-
/* @__PURE__ */ (0,
|
|
3494
|
-
/* @__PURE__ */ (0,
|
|
3495
|
-
/* @__PURE__ */ (0,
|
|
4451
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
4452
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("rect", { x: "1", y: "3", width: "14", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.5", fill: "none" }),
|
|
4453
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("line", { x1: "1", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
4454
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("circle", { cx: "5", cy: "6.5", r: "1.5", stroke: "currentColor", strokeWidth: "1", fill: "none" })
|
|
3496
4455
|
] })
|
|
3497
4456
|
}
|
|
3498
4457
|
);
|
|
3499
4458
|
};
|
|
3500
4459
|
var CustomLinkToolbar = (props) => {
|
|
3501
|
-
const editor = (0,
|
|
3502
|
-
const Components = (0,
|
|
4460
|
+
const editor = (0, import_react31.useBlockNoteEditor)();
|
|
4461
|
+
const Components = (0, import_react31.useComponentsContext)();
|
|
3503
4462
|
const hasLinkPreview = !!editor?._linkPreviewApiEndpoint;
|
|
3504
|
-
return /* @__PURE__ */ (0,
|
|
4463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
3505
4464
|
Components.LinkToolbar.Root,
|
|
3506
4465
|
{
|
|
3507
4466
|
className: "bn-toolbar bn-link-toolbar",
|
|
3508
4467
|
onMouseEnter: props.stopHideTimer,
|
|
3509
4468
|
onMouseLeave: props.startHideTimer,
|
|
3510
4469
|
children: [
|
|
3511
|
-
/* @__PURE__ */ (0,
|
|
3512
|
-
/* @__PURE__ */ (0,
|
|
3513
|
-
/* @__PURE__ */ (0,
|
|
3514
|
-
hasLinkPreview && /* @__PURE__ */ (0,
|
|
4470
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.EditLinkButton, { url: props.url, text: props.text, editLink: props.editLink }),
|
|
4471
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.OpenLinkButton, { url: props.url }),
|
|
4472
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.DeleteLinkButton, { deleteLink: props.deleteLink }),
|
|
4473
|
+
hasLinkPreview && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ConvertToPreviewButton, { url: props.url })
|
|
3515
4474
|
]
|
|
3516
4475
|
}
|
|
3517
4476
|
);
|
|
@@ -3555,13 +4514,13 @@ function LumirEditor({
|
|
|
3555
4514
|
onError,
|
|
3556
4515
|
onImageDelete
|
|
3557
4516
|
}) {
|
|
3558
|
-
const [isUploading, setIsUploading] = (0,
|
|
3559
|
-
const [uploadProgress, setUploadProgress] = (0,
|
|
3560
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
3561
|
-
const floatingMenuFileInputRef = (0,
|
|
3562
|
-
const floatingMenuBlockRef = (0,
|
|
3563
|
-
const floatingMenuUploadStartTimeRef = (0,
|
|
3564
|
-
const handleError = (0,
|
|
4517
|
+
const [isUploading, setIsUploading] = (0, import_react30.useState)(false);
|
|
4518
|
+
const [uploadProgress, setUploadProgress] = (0, import_react30.useState)(null);
|
|
4519
|
+
const [errorMessage, setErrorMessage] = (0, import_react30.useState)(null);
|
|
4520
|
+
const floatingMenuFileInputRef = (0, import_react30.useRef)(null);
|
|
4521
|
+
const floatingMenuBlockRef = (0, import_react30.useRef)(null);
|
|
4522
|
+
const floatingMenuUploadStartTimeRef = (0, import_react30.useRef)(0);
|
|
4523
|
+
const handleError = (0, import_react30.useCallback)(
|
|
3565
4524
|
(error) => {
|
|
3566
4525
|
onError?.(error);
|
|
3567
4526
|
setErrorMessage(error.getUserMessage());
|
|
@@ -3569,10 +4528,10 @@ function LumirEditor({
|
|
|
3569
4528
|
},
|
|
3570
4529
|
[onError]
|
|
3571
4530
|
);
|
|
3572
|
-
const validatedContent = (0,
|
|
4531
|
+
const validatedContent = (0, import_react30.useMemo)(() => {
|
|
3573
4532
|
return ContentUtils.validateContent(initialContent, initialEmptyBlocks);
|
|
3574
4533
|
}, [initialContent, initialEmptyBlocks]);
|
|
3575
|
-
const tableConfig = (0,
|
|
4534
|
+
const tableConfig = (0, import_react30.useMemo)(() => {
|
|
3576
4535
|
return EditorConfig.getDefaultTableConfig(tables);
|
|
3577
4536
|
}, [
|
|
3578
4537
|
tables?.splitCells,
|
|
@@ -3580,10 +4539,10 @@ function LumirEditor({
|
|
|
3580
4539
|
tables?.cellTextColor,
|
|
3581
4540
|
tables?.headers
|
|
3582
4541
|
]);
|
|
3583
|
-
const headingConfig = (0,
|
|
4542
|
+
const headingConfig = (0, import_react30.useMemo)(() => {
|
|
3584
4543
|
return EditorConfig.getDefaultHeadingConfig(heading);
|
|
3585
4544
|
}, [heading?.levels?.join(",") ?? ""]);
|
|
3586
|
-
const disabledExtensions = (0,
|
|
4545
|
+
const disabledExtensions = (0, import_react30.useMemo)(() => {
|
|
3587
4546
|
return EditorConfig.getDisabledExtensions(
|
|
3588
4547
|
disableExtensions,
|
|
3589
4548
|
allowVideoUpload,
|
|
@@ -3591,18 +4550,18 @@ function LumirEditor({
|
|
|
3591
4550
|
allowFileUpload
|
|
3592
4551
|
);
|
|
3593
4552
|
}, [disableExtensions, allowVideoUpload, allowAudioUpload, allowFileUpload]);
|
|
3594
|
-
(0,
|
|
4553
|
+
(0, import_react30.useEffect)(() => {
|
|
3595
4554
|
DEBUG_LOG("LumirEditor:init:disabledExtensions", "snapshot", {
|
|
3596
4555
|
allowVideoUpload,
|
|
3597
4556
|
hasVideoInDisabled: disabledExtensions.includes("video"),
|
|
3598
4557
|
disabledList: disabledExtensions.slice(0, 15)
|
|
3599
4558
|
});
|
|
3600
4559
|
}, [allowVideoUpload, disabledExtensions]);
|
|
3601
|
-
const fileNameTransformRef = (0,
|
|
3602
|
-
(0,
|
|
4560
|
+
const fileNameTransformRef = (0, import_react30.useRef)(s3Upload?.fileNameTransform);
|
|
4561
|
+
(0, import_react30.useEffect)(() => {
|
|
3603
4562
|
fileNameTransformRef.current = s3Upload?.fileNameTransform;
|
|
3604
4563
|
}, [s3Upload?.fileNameTransform]);
|
|
3605
|
-
const memoizedS3Upload = (0,
|
|
4564
|
+
const memoizedS3Upload = (0, import_react30.useMemo)(() => {
|
|
3606
4565
|
if (!s3Upload) return void 0;
|
|
3607
4566
|
return {
|
|
3608
4567
|
apiEndpoint: s3Upload.apiEndpoint,
|
|
@@ -3631,10 +4590,19 @@ function LumirEditor({
|
|
|
3631
4590
|
s3Upload?.maxRetries,
|
|
3632
4591
|
s3Upload?.onProgress
|
|
3633
4592
|
]);
|
|
3634
|
-
const editor = (0,
|
|
4593
|
+
const editor = (0, import_react31.useCreateBlockNote)(
|
|
3635
4594
|
{
|
|
3636
4595
|
// HTML 미리보기 블록이 포함된 커스텀 스키마 사용
|
|
3637
4596
|
schema,
|
|
4597
|
+
// 모든 BlockNote UI 텍스트(테이블 드롭다운 등) 한글 적용 + "색깔"→"색"
|
|
4598
|
+
dictionary: {
|
|
4599
|
+
...import_locales.ko,
|
|
4600
|
+
drag_handle: { ...import_locales.ko.drag_handle, colors_menuitem: "\uC0C9" },
|
|
4601
|
+
formatting_toolbar: {
|
|
4602
|
+
...import_locales.ko.formatting_toolbar,
|
|
4603
|
+
colors: { ...import_locales.ko.formatting_toolbar.colors, tooltip: "\uC0C9" }
|
|
4604
|
+
}
|
|
4605
|
+
},
|
|
3638
4606
|
initialContent: validatedContent,
|
|
3639
4607
|
tables: tableConfig,
|
|
3640
4608
|
heading: headingConfig,
|
|
@@ -3742,6 +4710,16 @@ function LumirEditor({
|
|
|
3742
4710
|
return true;
|
|
3743
4711
|
}
|
|
3744
4712
|
}
|
|
4713
|
+
const pastedHtml = event?.clipboardData?.getData?.("text/html") || "";
|
|
4714
|
+
if (/<table[\s>]/i.test(pastedHtml)) {
|
|
4715
|
+
DEBUG_LOG("paste:step0:table", "table HTML detected, using pasteHTML", {
|
|
4716
|
+
htmlLen: pastedHtml.length,
|
|
4717
|
+
hasFiles: !!event?.clipboardData?.files?.length
|
|
4718
|
+
});
|
|
4719
|
+
event.preventDefault();
|
|
4720
|
+
editor2.pasteHTML(normalizeExcelTableHtml(pastedHtml));
|
|
4721
|
+
return true;
|
|
4722
|
+
}
|
|
3745
4723
|
const fileList = event?.clipboardData?.files ?? null;
|
|
3746
4724
|
const files = fileList ? Array.from(fileList) : [];
|
|
3747
4725
|
const acceptedFiles = files.filter(
|
|
@@ -3816,12 +4794,12 @@ function LumirEditor({
|
|
|
3816
4794
|
if (editor && linkPreview?.apiEndpoint) {
|
|
3817
4795
|
editor._linkPreviewApiEndpoint = linkPreview.apiEndpoint;
|
|
3818
4796
|
}
|
|
3819
|
-
(0,
|
|
4797
|
+
(0, import_react30.useEffect)(() => {
|
|
3820
4798
|
if (editor) {
|
|
3821
4799
|
editor.isEditable = editable;
|
|
3822
4800
|
}
|
|
3823
4801
|
}, [editor, editable]);
|
|
3824
|
-
(0,
|
|
4802
|
+
(0, import_react30.useEffect)(() => {
|
|
3825
4803
|
if (!editor || !onContentChange) return;
|
|
3826
4804
|
const handleContentChange = () => {
|
|
3827
4805
|
const blocks = editor.topLevelBlocks;
|
|
@@ -3830,13 +4808,13 @@ function LumirEditor({
|
|
|
3830
4808
|
};
|
|
3831
4809
|
return editor.onEditorContentChange(handleContentChange);
|
|
3832
4810
|
}, [editor, onContentChange]);
|
|
3833
|
-
const previousMediaUrlsRef = (0,
|
|
3834
|
-
(0,
|
|
4811
|
+
const previousMediaUrlsRef = (0, import_react30.useRef)(/* @__PURE__ */ new Set());
|
|
4812
|
+
(0, import_react30.useEffect)(() => {
|
|
3835
4813
|
if (!editor) return;
|
|
3836
4814
|
const initialBlocks = editor.topLevelBlocks;
|
|
3837
4815
|
previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);
|
|
3838
4816
|
}, [editor]);
|
|
3839
|
-
(0,
|
|
4817
|
+
(0, import_react30.useEffect)(() => {
|
|
3840
4818
|
if (!editor || !onImageDelete) return;
|
|
3841
4819
|
const handleMediaDeleteCheck = () => {
|
|
3842
4820
|
const currentBlocks = editor.topLevelBlocks;
|
|
@@ -3850,7 +4828,7 @@ function LumirEditor({
|
|
|
3850
4828
|
};
|
|
3851
4829
|
return editor.onEditorContentChange(handleMediaDeleteCheck);
|
|
3852
4830
|
}, [editor, onImageDelete]);
|
|
3853
|
-
(0,
|
|
4831
|
+
(0, import_react30.useEffect)(() => {
|
|
3854
4832
|
const el = editor?.domElement;
|
|
3855
4833
|
if (!el) return;
|
|
3856
4834
|
const handleDragOver = (e) => {
|
|
@@ -3981,20 +4959,20 @@ function LumirEditor({
|
|
|
3981
4959
|
el.removeEventListener("drop", handleDrop, { capture: true });
|
|
3982
4960
|
};
|
|
3983
4961
|
}, [editor, allowVideoUpload]);
|
|
3984
|
-
const computedSideMenu = (0,
|
|
4962
|
+
const computedSideMenu = (0, import_react30.useMemo)(() => {
|
|
3985
4963
|
return sideMenuAddButton ? sideMenu : false;
|
|
3986
4964
|
}, [sideMenuAddButton, sideMenu]);
|
|
3987
|
-
const DragHandleOnlySideMenu = (0,
|
|
3988
|
-
return (props) => /* @__PURE__ */ (0,
|
|
4965
|
+
const DragHandleOnlySideMenu = (0, import_react30.useMemo)(() => {
|
|
4966
|
+
return (props) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.SideMenu, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.DragHandleButton, { ...props }) });
|
|
3989
4967
|
}, []);
|
|
3990
|
-
return /* @__PURE__ */ (0,
|
|
4968
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
3991
4969
|
"div",
|
|
3992
4970
|
{
|
|
3993
4971
|
className: cn("lumirEditor", className),
|
|
3994
4972
|
style: { position: "relative", display: "flex", flexDirection: "column" },
|
|
3995
4973
|
children: [
|
|
3996
|
-
floatingMenu && editor && /* @__PURE__ */ (0,
|
|
3997
|
-
/* @__PURE__ */ (0,
|
|
4974
|
+
floatingMenu && editor && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
4975
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3998
4976
|
"input",
|
|
3999
4977
|
{
|
|
4000
4978
|
ref: floatingMenuFileInputRef,
|
|
@@ -4065,7 +5043,7 @@ function LumirEditor({
|
|
|
4065
5043
|
}
|
|
4066
5044
|
}
|
|
4067
5045
|
),
|
|
4068
|
-
/* @__PURE__ */ (0,
|
|
5046
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
4069
5047
|
FloatingMenu,
|
|
4070
5048
|
{
|
|
4071
5049
|
editor,
|
|
@@ -4097,7 +5075,7 @@ function LumirEditor({
|
|
|
4097
5075
|
}
|
|
4098
5076
|
)
|
|
4099
5077
|
] }),
|
|
4100
|
-
/* @__PURE__ */ (0,
|
|
5078
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
4101
5079
|
import_mantine.BlockNoteView,
|
|
4102
5080
|
{
|
|
4103
5081
|
editor,
|
|
@@ -4109,23 +5087,24 @@ function LumirEditor({
|
|
|
4109
5087
|
slashMenu: false,
|
|
4110
5088
|
emojiPicker,
|
|
4111
5089
|
filePanel,
|
|
4112
|
-
tableHandles,
|
|
5090
|
+
tableHandles: false,
|
|
4113
5091
|
onSelectionChange,
|
|
4114
5092
|
children: [
|
|
4115
|
-
|
|
4116
|
-
|
|
5093
|
+
tableHandles && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LumirTableHandlesController, {}),
|
|
5094
|
+
formattingToolbar && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5095
|
+
import_react31.FormattingToolbarController,
|
|
4117
5096
|
{
|
|
4118
5097
|
formattingToolbar: CustomFormattingToolbar
|
|
4119
5098
|
}
|
|
4120
5099
|
),
|
|
4121
|
-
linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ (0,
|
|
4122
|
-
/* @__PURE__ */ (0,
|
|
4123
|
-
|
|
5100
|
+
linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.LinkToolbarController, { linkToolbar: CustomLinkToolbar }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.LinkToolbarController, {})),
|
|
5101
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5102
|
+
import_react31.SuggestionMenuController,
|
|
4124
5103
|
{
|
|
4125
5104
|
triggerCharacter: "/",
|
|
4126
|
-
getItems: (0,
|
|
5105
|
+
getItems: (0, import_react30.useCallback)(
|
|
4127
5106
|
async (query) => {
|
|
4128
|
-
const items = (0,
|
|
5107
|
+
const items = (0, import_react31.getDefaultReactSlashMenuItems)(editor);
|
|
4129
5108
|
const filtered = items.filter((item) => {
|
|
4130
5109
|
const key = (item?.key || "").toString().toLowerCase();
|
|
4131
5110
|
const title = (item?.title || "").toString().toLowerCase();
|
|
@@ -4167,7 +5146,7 @@ function LumirEditor({
|
|
|
4167
5146
|
},
|
|
4168
5147
|
aliases: ["html", "preview", "\uC6F9", "\uC6F9\uD398\uC774\uC9C0"],
|
|
4169
5148
|
group: "Embeds",
|
|
4170
|
-
icon: /* @__PURE__ */ (0,
|
|
5149
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
4171
5150
|
"svg",
|
|
4172
5151
|
{
|
|
4173
5152
|
width: "18",
|
|
@@ -4179,8 +5158,8 @@ function LumirEditor({
|
|
|
4179
5158
|
strokeLinecap: "round",
|
|
4180
5159
|
strokeLinejoin: "round",
|
|
4181
5160
|
children: [
|
|
4182
|
-
/* @__PURE__ */ (0,
|
|
4183
|
-
/* @__PURE__ */ (0,
|
|
5161
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("polyline", { points: "16 18 22 12 16 6" }),
|
|
5162
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("polyline", { points: "8 6 2 12 8 18" })
|
|
4184
5163
|
]
|
|
4185
5164
|
}
|
|
4186
5165
|
),
|
|
@@ -4191,7 +5170,7 @@ function LumirEditor({
|
|
|
4191
5170
|
allItems.push({
|
|
4192
5171
|
title: "Link Preview",
|
|
4193
5172
|
onItemClick: () => {
|
|
4194
|
-
(0,
|
|
5173
|
+
(0, import_core5.insertOrUpdateBlock)(editor, {
|
|
4195
5174
|
type: "linkPreview",
|
|
4196
5175
|
props: { url: "" }
|
|
4197
5176
|
});
|
|
@@ -4205,7 +5184,7 @@ function LumirEditor({
|
|
|
4205
5184
|
"\uD504\uB9AC\uBDF0"
|
|
4206
5185
|
],
|
|
4207
5186
|
group: "Embeds",
|
|
4208
|
-
icon: /* @__PURE__ */ (0,
|
|
5187
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
4209
5188
|
"svg",
|
|
4210
5189
|
{
|
|
4211
5190
|
width: "18",
|
|
@@ -4217,14 +5196,31 @@ function LumirEditor({
|
|
|
4217
5196
|
strokeLinecap: "round",
|
|
4218
5197
|
strokeLinejoin: "round",
|
|
4219
5198
|
children: [
|
|
4220
|
-
/* @__PURE__ */ (0,
|
|
4221
|
-
/* @__PURE__ */ (0,
|
|
5199
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.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" }),
|
|
5200
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.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" })
|
|
4222
5201
|
]
|
|
4223
5202
|
}
|
|
4224
5203
|
),
|
|
4225
5204
|
subtext: "URL\uC758 \uBBF8\uB9AC\uBCF4\uAE30 \uCE74\uB4DC\uB97C \uC0BD\uC785"
|
|
4226
5205
|
});
|
|
4227
5206
|
}
|
|
5207
|
+
const enSlash = import_locales.en.slash_menu;
|
|
5208
|
+
for (const it of allItems) {
|
|
5209
|
+
const enEntry = it.key ? enSlash[it.key] : void 0;
|
|
5210
|
+
if (!enEntry) continue;
|
|
5211
|
+
const extra = [...enEntry.aliases ?? [], enEntry.title].filter((s) => Boolean(s)).map((s) => s.toLowerCase());
|
|
5212
|
+
it.aliases = Array.from(
|
|
5213
|
+
/* @__PURE__ */ new Set([...it.aliases ?? [], ...extra])
|
|
5214
|
+
);
|
|
5215
|
+
}
|
|
5216
|
+
const groupOrder = [];
|
|
5217
|
+
for (const it of allItems) {
|
|
5218
|
+
const g = it.group ?? "";
|
|
5219
|
+
if (!groupOrder.includes(g)) groupOrder.push(g);
|
|
5220
|
+
}
|
|
5221
|
+
allItems.sort(
|
|
5222
|
+
(a, b) => groupOrder.indexOf(a.group ?? "") - groupOrder.indexOf(b.group ?? "")
|
|
5223
|
+
);
|
|
4228
5224
|
if (!query) return allItems;
|
|
4229
5225
|
const q = query.toLowerCase();
|
|
4230
5226
|
return allItems.filter(
|
|
@@ -4237,21 +5233,21 @@ function LumirEditor({
|
|
|
4237
5233
|
)
|
|
4238
5234
|
}
|
|
4239
5235
|
),
|
|
4240
|
-
!sideMenuAddButton && /* @__PURE__ */ (0,
|
|
5236
|
+
!sideMenuAddButton && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.SideMenuController, { sideMenu: DragHandleOnlySideMenu })
|
|
4241
5237
|
]
|
|
4242
5238
|
}
|
|
4243
5239
|
),
|
|
4244
|
-
isUploading && /* @__PURE__ */ (0,
|
|
4245
|
-
/* @__PURE__ */ (0,
|
|
4246
|
-
uploadProgress !== null && /* @__PURE__ */ (0,
|
|
5240
|
+
isUploading && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "lumirEditor-upload-overlay", children: [
|
|
5241
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "lumirEditor-spinner" }),
|
|
5242
|
+
uploadProgress !== null && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "lumirEditor-upload-progress", children: [
|
|
4247
5243
|
uploadProgress,
|
|
4248
5244
|
"%"
|
|
4249
5245
|
] })
|
|
4250
5246
|
] }),
|
|
4251
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
4252
|
-
/* @__PURE__ */ (0,
|
|
4253
|
-
/* @__PURE__ */ (0,
|
|
4254
|
-
/* @__PURE__ */ (0,
|
|
5247
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "lumirEditor-error-toast", children: [
|
|
5248
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "lumirEditor-error-icon", children: "\u26A0\uFE0F" }),
|
|
5249
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "lumirEditor-error-message", children: errorMessage }),
|
|
5250
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
4255
5251
|
"button",
|
|
4256
5252
|
{
|
|
4257
5253
|
className: "lumirEditor-error-close",
|