@lumir-company/editor 0.4.14 → 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 +85 -8
- package/dist/index.js +885 -128
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +899 -120
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +241 -41
- package/package.json +4 -2
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;
|
|
@@ -3472,7 +4202,7 @@ var ALLOWED_VIDEO_EXTENSIONS = [
|
|
|
3472
4202
|
];
|
|
3473
4203
|
|
|
3474
4204
|
// src/components/LumirEditor.tsx
|
|
3475
|
-
var
|
|
4205
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3476
4206
|
var DEBUG_LOG = (loc, msg, data) => {
|
|
3477
4207
|
const p = fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
3478
4208
|
method: "POST",
|
|
@@ -3697,9 +4427,9 @@ var findBlockWithLink = (blocks, targetUrl) => {
|
|
|
3697
4427
|
return null;
|
|
3698
4428
|
};
|
|
3699
4429
|
var ConvertToPreviewButton = ({ url }) => {
|
|
3700
|
-
const editor = (0,
|
|
3701
|
-
const Components = (0,
|
|
3702
|
-
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)(
|
|
3703
4433
|
Components.LinkToolbar.Button,
|
|
3704
4434
|
{
|
|
3705
4435
|
className: "bn-button",
|
|
@@ -3718,29 +4448,29 @@ var ConvertToPreviewButton = ({ url }) => {
|
|
|
3718
4448
|
console.error("Convert to link preview failed:", err);
|
|
3719
4449
|
}
|
|
3720
4450
|
},
|
|
3721
|
-
icon: /* @__PURE__ */ (0,
|
|
3722
|
-
/* @__PURE__ */ (0,
|
|
3723
|
-
/* @__PURE__ */ (0,
|
|
3724
|
-
/* @__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" })
|
|
3725
4455
|
] })
|
|
3726
4456
|
}
|
|
3727
4457
|
);
|
|
3728
4458
|
};
|
|
3729
4459
|
var CustomLinkToolbar = (props) => {
|
|
3730
|
-
const editor = (0,
|
|
3731
|
-
const Components = (0,
|
|
4460
|
+
const editor = (0, import_react31.useBlockNoteEditor)();
|
|
4461
|
+
const Components = (0, import_react31.useComponentsContext)();
|
|
3732
4462
|
const hasLinkPreview = !!editor?._linkPreviewApiEndpoint;
|
|
3733
|
-
return /* @__PURE__ */ (0,
|
|
4463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
3734
4464
|
Components.LinkToolbar.Root,
|
|
3735
4465
|
{
|
|
3736
4466
|
className: "bn-toolbar bn-link-toolbar",
|
|
3737
4467
|
onMouseEnter: props.stopHideTimer,
|
|
3738
4468
|
onMouseLeave: props.startHideTimer,
|
|
3739
4469
|
children: [
|
|
3740
|
-
/* @__PURE__ */ (0,
|
|
3741
|
-
/* @__PURE__ */ (0,
|
|
3742
|
-
/* @__PURE__ */ (0,
|
|
3743
|
-
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 })
|
|
3744
4474
|
]
|
|
3745
4475
|
}
|
|
3746
4476
|
);
|
|
@@ -3784,13 +4514,13 @@ function LumirEditor({
|
|
|
3784
4514
|
onError,
|
|
3785
4515
|
onImageDelete
|
|
3786
4516
|
}) {
|
|
3787
|
-
const [isUploading, setIsUploading] = (0,
|
|
3788
|
-
const [uploadProgress, setUploadProgress] = (0,
|
|
3789
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
3790
|
-
const floatingMenuFileInputRef = (0,
|
|
3791
|
-
const floatingMenuBlockRef = (0,
|
|
3792
|
-
const floatingMenuUploadStartTimeRef = (0,
|
|
3793
|
-
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)(
|
|
3794
4524
|
(error) => {
|
|
3795
4525
|
onError?.(error);
|
|
3796
4526
|
setErrorMessage(error.getUserMessage());
|
|
@@ -3798,10 +4528,10 @@ function LumirEditor({
|
|
|
3798
4528
|
},
|
|
3799
4529
|
[onError]
|
|
3800
4530
|
);
|
|
3801
|
-
const validatedContent = (0,
|
|
4531
|
+
const validatedContent = (0, import_react30.useMemo)(() => {
|
|
3802
4532
|
return ContentUtils.validateContent(initialContent, initialEmptyBlocks);
|
|
3803
4533
|
}, [initialContent, initialEmptyBlocks]);
|
|
3804
|
-
const tableConfig = (0,
|
|
4534
|
+
const tableConfig = (0, import_react30.useMemo)(() => {
|
|
3805
4535
|
return EditorConfig.getDefaultTableConfig(tables);
|
|
3806
4536
|
}, [
|
|
3807
4537
|
tables?.splitCells,
|
|
@@ -3809,10 +4539,10 @@ function LumirEditor({
|
|
|
3809
4539
|
tables?.cellTextColor,
|
|
3810
4540
|
tables?.headers
|
|
3811
4541
|
]);
|
|
3812
|
-
const headingConfig = (0,
|
|
4542
|
+
const headingConfig = (0, import_react30.useMemo)(() => {
|
|
3813
4543
|
return EditorConfig.getDefaultHeadingConfig(heading);
|
|
3814
4544
|
}, [heading?.levels?.join(",") ?? ""]);
|
|
3815
|
-
const disabledExtensions = (0,
|
|
4545
|
+
const disabledExtensions = (0, import_react30.useMemo)(() => {
|
|
3816
4546
|
return EditorConfig.getDisabledExtensions(
|
|
3817
4547
|
disableExtensions,
|
|
3818
4548
|
allowVideoUpload,
|
|
@@ -3820,18 +4550,18 @@ function LumirEditor({
|
|
|
3820
4550
|
allowFileUpload
|
|
3821
4551
|
);
|
|
3822
4552
|
}, [disableExtensions, allowVideoUpload, allowAudioUpload, allowFileUpload]);
|
|
3823
|
-
(0,
|
|
4553
|
+
(0, import_react30.useEffect)(() => {
|
|
3824
4554
|
DEBUG_LOG("LumirEditor:init:disabledExtensions", "snapshot", {
|
|
3825
4555
|
allowVideoUpload,
|
|
3826
4556
|
hasVideoInDisabled: disabledExtensions.includes("video"),
|
|
3827
4557
|
disabledList: disabledExtensions.slice(0, 15)
|
|
3828
4558
|
});
|
|
3829
4559
|
}, [allowVideoUpload, disabledExtensions]);
|
|
3830
|
-
const fileNameTransformRef = (0,
|
|
3831
|
-
(0,
|
|
4560
|
+
const fileNameTransformRef = (0, import_react30.useRef)(s3Upload?.fileNameTransform);
|
|
4561
|
+
(0, import_react30.useEffect)(() => {
|
|
3832
4562
|
fileNameTransformRef.current = s3Upload?.fileNameTransform;
|
|
3833
4563
|
}, [s3Upload?.fileNameTransform]);
|
|
3834
|
-
const memoizedS3Upload = (0,
|
|
4564
|
+
const memoizedS3Upload = (0, import_react30.useMemo)(() => {
|
|
3835
4565
|
if (!s3Upload) return void 0;
|
|
3836
4566
|
return {
|
|
3837
4567
|
apiEndpoint: s3Upload.apiEndpoint,
|
|
@@ -3860,10 +4590,19 @@ function LumirEditor({
|
|
|
3860
4590
|
s3Upload?.maxRetries,
|
|
3861
4591
|
s3Upload?.onProgress
|
|
3862
4592
|
]);
|
|
3863
|
-
const editor = (0,
|
|
4593
|
+
const editor = (0, import_react31.useCreateBlockNote)(
|
|
3864
4594
|
{
|
|
3865
4595
|
// HTML 미리보기 블록이 포함된 커스텀 스키마 사용
|
|
3866
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
|
+
},
|
|
3867
4606
|
initialContent: validatedContent,
|
|
3868
4607
|
tables: tableConfig,
|
|
3869
4608
|
heading: headingConfig,
|
|
@@ -4055,12 +4794,12 @@ function LumirEditor({
|
|
|
4055
4794
|
if (editor && linkPreview?.apiEndpoint) {
|
|
4056
4795
|
editor._linkPreviewApiEndpoint = linkPreview.apiEndpoint;
|
|
4057
4796
|
}
|
|
4058
|
-
(0,
|
|
4797
|
+
(0, import_react30.useEffect)(() => {
|
|
4059
4798
|
if (editor) {
|
|
4060
4799
|
editor.isEditable = editable;
|
|
4061
4800
|
}
|
|
4062
4801
|
}, [editor, editable]);
|
|
4063
|
-
(0,
|
|
4802
|
+
(0, import_react30.useEffect)(() => {
|
|
4064
4803
|
if (!editor || !onContentChange) return;
|
|
4065
4804
|
const handleContentChange = () => {
|
|
4066
4805
|
const blocks = editor.topLevelBlocks;
|
|
@@ -4069,13 +4808,13 @@ function LumirEditor({
|
|
|
4069
4808
|
};
|
|
4070
4809
|
return editor.onEditorContentChange(handleContentChange);
|
|
4071
4810
|
}, [editor, onContentChange]);
|
|
4072
|
-
const previousMediaUrlsRef = (0,
|
|
4073
|
-
(0,
|
|
4811
|
+
const previousMediaUrlsRef = (0, import_react30.useRef)(/* @__PURE__ */ new Set());
|
|
4812
|
+
(0, import_react30.useEffect)(() => {
|
|
4074
4813
|
if (!editor) return;
|
|
4075
4814
|
const initialBlocks = editor.topLevelBlocks;
|
|
4076
4815
|
previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);
|
|
4077
4816
|
}, [editor]);
|
|
4078
|
-
(0,
|
|
4817
|
+
(0, import_react30.useEffect)(() => {
|
|
4079
4818
|
if (!editor || !onImageDelete) return;
|
|
4080
4819
|
const handleMediaDeleteCheck = () => {
|
|
4081
4820
|
const currentBlocks = editor.topLevelBlocks;
|
|
@@ -4089,7 +4828,7 @@ function LumirEditor({
|
|
|
4089
4828
|
};
|
|
4090
4829
|
return editor.onEditorContentChange(handleMediaDeleteCheck);
|
|
4091
4830
|
}, [editor, onImageDelete]);
|
|
4092
|
-
(0,
|
|
4831
|
+
(0, import_react30.useEffect)(() => {
|
|
4093
4832
|
const el = editor?.domElement;
|
|
4094
4833
|
if (!el) return;
|
|
4095
4834
|
const handleDragOver = (e) => {
|
|
@@ -4220,20 +4959,20 @@ function LumirEditor({
|
|
|
4220
4959
|
el.removeEventListener("drop", handleDrop, { capture: true });
|
|
4221
4960
|
};
|
|
4222
4961
|
}, [editor, allowVideoUpload]);
|
|
4223
|
-
const computedSideMenu = (0,
|
|
4962
|
+
const computedSideMenu = (0, import_react30.useMemo)(() => {
|
|
4224
4963
|
return sideMenuAddButton ? sideMenu : false;
|
|
4225
4964
|
}, [sideMenuAddButton, sideMenu]);
|
|
4226
|
-
const DragHandleOnlySideMenu = (0,
|
|
4227
|
-
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 }) });
|
|
4228
4967
|
}, []);
|
|
4229
|
-
return /* @__PURE__ */ (0,
|
|
4968
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
4230
4969
|
"div",
|
|
4231
4970
|
{
|
|
4232
4971
|
className: cn("lumirEditor", className),
|
|
4233
4972
|
style: { position: "relative", display: "flex", flexDirection: "column" },
|
|
4234
4973
|
children: [
|
|
4235
|
-
floatingMenu && editor && /* @__PURE__ */ (0,
|
|
4236
|
-
/* @__PURE__ */ (0,
|
|
4974
|
+
floatingMenu && editor && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
4975
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
4237
4976
|
"input",
|
|
4238
4977
|
{
|
|
4239
4978
|
ref: floatingMenuFileInputRef,
|
|
@@ -4304,7 +5043,7 @@ function LumirEditor({
|
|
|
4304
5043
|
}
|
|
4305
5044
|
}
|
|
4306
5045
|
),
|
|
4307
|
-
/* @__PURE__ */ (0,
|
|
5046
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
4308
5047
|
FloatingMenu,
|
|
4309
5048
|
{
|
|
4310
5049
|
editor,
|
|
@@ -4336,7 +5075,7 @@ function LumirEditor({
|
|
|
4336
5075
|
}
|
|
4337
5076
|
)
|
|
4338
5077
|
] }),
|
|
4339
|
-
/* @__PURE__ */ (0,
|
|
5078
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
4340
5079
|
import_mantine.BlockNoteView,
|
|
4341
5080
|
{
|
|
4342
5081
|
editor,
|
|
@@ -4348,23 +5087,24 @@ function LumirEditor({
|
|
|
4348
5087
|
slashMenu: false,
|
|
4349
5088
|
emojiPicker,
|
|
4350
5089
|
filePanel,
|
|
4351
|
-
tableHandles,
|
|
5090
|
+
tableHandles: false,
|
|
4352
5091
|
onSelectionChange,
|
|
4353
5092
|
children: [
|
|
4354
|
-
|
|
4355
|
-
|
|
5093
|
+
tableHandles && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LumirTableHandlesController, {}),
|
|
5094
|
+
formattingToolbar && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5095
|
+
import_react31.FormattingToolbarController,
|
|
4356
5096
|
{
|
|
4357
5097
|
formattingToolbar: CustomFormattingToolbar
|
|
4358
5098
|
}
|
|
4359
5099
|
),
|
|
4360
|
-
linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ (0,
|
|
4361
|
-
/* @__PURE__ */ (0,
|
|
4362
|
-
|
|
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,
|
|
4363
5103
|
{
|
|
4364
5104
|
triggerCharacter: "/",
|
|
4365
|
-
getItems: (0,
|
|
5105
|
+
getItems: (0, import_react30.useCallback)(
|
|
4366
5106
|
async (query) => {
|
|
4367
|
-
const items = (0,
|
|
5107
|
+
const items = (0, import_react31.getDefaultReactSlashMenuItems)(editor);
|
|
4368
5108
|
const filtered = items.filter((item) => {
|
|
4369
5109
|
const key = (item?.key || "").toString().toLowerCase();
|
|
4370
5110
|
const title = (item?.title || "").toString().toLowerCase();
|
|
@@ -4406,7 +5146,7 @@ function LumirEditor({
|
|
|
4406
5146
|
},
|
|
4407
5147
|
aliases: ["html", "preview", "\uC6F9", "\uC6F9\uD398\uC774\uC9C0"],
|
|
4408
5148
|
group: "Embeds",
|
|
4409
|
-
icon: /* @__PURE__ */ (0,
|
|
5149
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
4410
5150
|
"svg",
|
|
4411
5151
|
{
|
|
4412
5152
|
width: "18",
|
|
@@ -4418,8 +5158,8 @@ function LumirEditor({
|
|
|
4418
5158
|
strokeLinecap: "round",
|
|
4419
5159
|
strokeLinejoin: "round",
|
|
4420
5160
|
children: [
|
|
4421
|
-
/* @__PURE__ */ (0,
|
|
4422
|
-
/* @__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" })
|
|
4423
5163
|
]
|
|
4424
5164
|
}
|
|
4425
5165
|
),
|
|
@@ -4430,7 +5170,7 @@ function LumirEditor({
|
|
|
4430
5170
|
allItems.push({
|
|
4431
5171
|
title: "Link Preview",
|
|
4432
5172
|
onItemClick: () => {
|
|
4433
|
-
(0,
|
|
5173
|
+
(0, import_core5.insertOrUpdateBlock)(editor, {
|
|
4434
5174
|
type: "linkPreview",
|
|
4435
5175
|
props: { url: "" }
|
|
4436
5176
|
});
|
|
@@ -4444,7 +5184,7 @@ function LumirEditor({
|
|
|
4444
5184
|
"\uD504\uB9AC\uBDF0"
|
|
4445
5185
|
],
|
|
4446
5186
|
group: "Embeds",
|
|
4447
|
-
icon: /* @__PURE__ */ (0,
|
|
5187
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
4448
5188
|
"svg",
|
|
4449
5189
|
{
|
|
4450
5190
|
width: "18",
|
|
@@ -4456,14 +5196,31 @@ function LumirEditor({
|
|
|
4456
5196
|
strokeLinecap: "round",
|
|
4457
5197
|
strokeLinejoin: "round",
|
|
4458
5198
|
children: [
|
|
4459
|
-
/* @__PURE__ */ (0,
|
|
4460
|
-
/* @__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" })
|
|
4461
5201
|
]
|
|
4462
5202
|
}
|
|
4463
5203
|
),
|
|
4464
5204
|
subtext: "URL\uC758 \uBBF8\uB9AC\uBCF4\uAE30 \uCE74\uB4DC\uB97C \uC0BD\uC785"
|
|
4465
5205
|
});
|
|
4466
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
|
+
);
|
|
4467
5224
|
if (!query) return allItems;
|
|
4468
5225
|
const q = query.toLowerCase();
|
|
4469
5226
|
return allItems.filter(
|
|
@@ -4476,21 +5233,21 @@ function LumirEditor({
|
|
|
4476
5233
|
)
|
|
4477
5234
|
}
|
|
4478
5235
|
),
|
|
4479
|
-
!sideMenuAddButton && /* @__PURE__ */ (0,
|
|
5236
|
+
!sideMenuAddButton && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react31.SideMenuController, { sideMenu: DragHandleOnlySideMenu })
|
|
4480
5237
|
]
|
|
4481
5238
|
}
|
|
4482
5239
|
),
|
|
4483
|
-
isUploading && /* @__PURE__ */ (0,
|
|
4484
|
-
/* @__PURE__ */ (0,
|
|
4485
|
-
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: [
|
|
4486
5243
|
uploadProgress,
|
|
4487
5244
|
"%"
|
|
4488
5245
|
] })
|
|
4489
5246
|
] }),
|
|
4490
|
-
errorMessage && /* @__PURE__ */ (0,
|
|
4491
|
-
/* @__PURE__ */ (0,
|
|
4492
|
-
/* @__PURE__ */ (0,
|
|
4493
|
-
/* @__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)(
|
|
4494
5251
|
"button",
|
|
4495
5252
|
{
|
|
4496
5253
|
className: "lumirEditor-error-close",
|