@lumir-company/editor 0.4.4 → 0.4.6
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 +1315 -1091
- package/dist/index.d.mts +50 -68
- package/dist/index.d.ts +50 -68
- package/dist/index.js +997 -429
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +983 -415
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +990 -964
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -40,8 +40,8 @@ __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_react18 = require("react");
|
|
44
|
+
var import_react19 = require("@blocknote/react");
|
|
45
45
|
var import_mantine = require("@blocknote/mantine");
|
|
46
46
|
var import_core2 = require("@blocknote/core");
|
|
47
47
|
|
|
@@ -91,7 +91,10 @@ var createS3Uploader = (config) => {
|
|
|
91
91
|
path,
|
|
92
92
|
fileNameTransform,
|
|
93
93
|
appendUUID,
|
|
94
|
-
preserveExtension = true
|
|
94
|
+
preserveExtension = true,
|
|
95
|
+
onProgress,
|
|
96
|
+
uploadTimeoutMs = 12e4,
|
|
97
|
+
maxRetries = 2
|
|
95
98
|
} = config;
|
|
96
99
|
if (!apiEndpoint || apiEndpoint.trim() === "") {
|
|
97
100
|
throw new Error(
|
|
@@ -130,6 +133,15 @@ var createS3Uploader = (config) => {
|
|
|
130
133
|
}
|
|
131
134
|
return `${env}/${path}/${filename}`;
|
|
132
135
|
};
|
|
136
|
+
const debugLog = (loc, msg, data) => {
|
|
137
|
+
const p = fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "b73262" },
|
|
140
|
+
body: JSON.stringify({ sessionId: "b73262", location: loc, message: msg, data, timestamp: Date.now() })
|
|
141
|
+
});
|
|
142
|
+
if (p && typeof p.catch === "function") p.catch(() => {
|
|
143
|
+
});
|
|
144
|
+
};
|
|
133
145
|
return async (file) => {
|
|
134
146
|
try {
|
|
135
147
|
if (!apiEndpoint || apiEndpoint.trim() === "") {
|
|
@@ -138,11 +150,26 @@ var createS3Uploader = (config) => {
|
|
|
138
150
|
);
|
|
139
151
|
}
|
|
140
152
|
const fileName = generateHierarchicalFileName(file);
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
);
|
|
153
|
+
const contentType = file.type || "application/octet-stream";
|
|
154
|
+
const presignedUrlFull = `${apiEndpoint}?key=${encodeURIComponent(fileName)}&contentType=${encodeURIComponent(contentType)}`;
|
|
155
|
+
const tPresigned = Date.now();
|
|
156
|
+
debugLog("s3:step1:presignedReq", "fetching presigned URL", {
|
|
157
|
+
fileName,
|
|
158
|
+
contentType,
|
|
159
|
+
apiEndpoint
|
|
160
|
+
});
|
|
161
|
+
const response = await fetch(presignedUrlFull);
|
|
162
|
+
debugLog("s3:step2:presignedRes", "presigned response", {
|
|
163
|
+
ok: response.ok,
|
|
164
|
+
status: response.status,
|
|
165
|
+
elapsedMs: Date.now() - tPresigned
|
|
166
|
+
});
|
|
144
167
|
if (!response.ok) {
|
|
145
168
|
const errorText = await response.text() || "";
|
|
169
|
+
debugLog("s3:step2b:presignedErr", "presigned failed", {
|
|
170
|
+
status: response.status,
|
|
171
|
+
errorText: errorText.slice(0, 200)
|
|
172
|
+
});
|
|
146
173
|
throw new Error(
|
|
147
174
|
`Failed to get presigned URL: ${response.statusText}, ${errorText}`
|
|
148
175
|
);
|
|
@@ -151,17 +178,64 @@ var createS3Uploader = (config) => {
|
|
|
151
178
|
const { presignedUrl, publicUrl } = responseData;
|
|
152
179
|
const validatedPresignedUrl = validateS3Url(presignedUrl, "presignedUrl");
|
|
153
180
|
const validatedPublicUrl = validateS3Url(publicUrl, "publicUrl");
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
181
|
+
const tPut = Date.now();
|
|
182
|
+
debugLog("s3:step3:putReq", "S3 PUT request", { publicUrlLen: validatedPublicUrl?.length });
|
|
183
|
+
let lastError;
|
|
184
|
+
const attempts = maxRetries + 1;
|
|
185
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
186
|
+
try {
|
|
187
|
+
if (onProgress && typeof XMLHttpRequest !== "undefined") {
|
|
188
|
+
await new Promise((resolve, reject) => {
|
|
189
|
+
const xhr = new XMLHttpRequest();
|
|
190
|
+
xhr.timeout = uploadTimeoutMs;
|
|
191
|
+
xhr.upload.onprogress = (e) => {
|
|
192
|
+
if (e.lengthComputable) {
|
|
193
|
+
onProgress(Math.min(100, Math.round(e.loaded / e.total * 100)));
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
xhr.onload = () => {
|
|
197
|
+
if (xhr.status >= 200 && xhr.status < 300) resolve();
|
|
198
|
+
else reject(new Error(`Failed to upload file: ${xhr.statusText}`));
|
|
199
|
+
};
|
|
200
|
+
xhr.onerror = () => reject(new Error("Upload failed"));
|
|
201
|
+
xhr.ontimeout = () => reject(new Error("Upload timeout"));
|
|
202
|
+
xhr.open("PUT", validatedPresignedUrl);
|
|
203
|
+
xhr.setRequestHeader("Content-Type", file.type || "application/octet-stream");
|
|
204
|
+
xhr.send(file);
|
|
205
|
+
});
|
|
206
|
+
} else {
|
|
207
|
+
const controller = new AbortController();
|
|
208
|
+
const timeoutId = setTimeout(() => controller.abort(), uploadTimeoutMs);
|
|
209
|
+
const uploadResponse = await fetch(validatedPresignedUrl, {
|
|
210
|
+
method: "PUT",
|
|
211
|
+
headers: {
|
|
212
|
+
"Content-Type": file.type || "application/octet-stream"
|
|
213
|
+
},
|
|
214
|
+
body: file,
|
|
215
|
+
signal: controller.signal
|
|
216
|
+
});
|
|
217
|
+
clearTimeout(timeoutId);
|
|
218
|
+
debugLog("s3:step4:putRes", "S3 PUT response", {
|
|
219
|
+
ok: uploadResponse.ok,
|
|
220
|
+
status: uploadResponse.status,
|
|
221
|
+
putElapsedMs: Date.now() - tPut
|
|
222
|
+
});
|
|
223
|
+
if (!uploadResponse.ok) {
|
|
224
|
+
throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
debugLog("s3:step5:return", "returning publicUrl", { urlPrefix: validatedPublicUrl.slice(0, 80) });
|
|
228
|
+
return validatedPublicUrl;
|
|
229
|
+
} catch (err) {
|
|
230
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
231
|
+
if (attempt < attempts - 1) {
|
|
232
|
+
debugLog("s3:putRetry", "PUT failed, retrying", { attempt: attempt + 1, attempts });
|
|
233
|
+
} else {
|
|
234
|
+
throw lastError;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
163
237
|
}
|
|
164
|
-
|
|
238
|
+
throw lastError ?? new Error("Upload failed");
|
|
165
239
|
} catch (error) {
|
|
166
240
|
console.error("S3 upload failed:", error);
|
|
167
241
|
throw error;
|
|
@@ -170,7 +244,7 @@ var createS3Uploader = (config) => {
|
|
|
170
244
|
};
|
|
171
245
|
|
|
172
246
|
// src/blocks/HtmlPreview.tsx
|
|
173
|
-
var
|
|
247
|
+
var import_react5 = require("@blocknote/react");
|
|
174
248
|
var import_core = require("@blocknote/core");
|
|
175
249
|
|
|
176
250
|
// src/blocks/LinkPreview.tsx
|
|
@@ -876,9 +950,254 @@ var LinkPreviewBlock = (0, import_react.createReactBlockSpec)(
|
|
|
876
950
|
}
|
|
877
951
|
);
|
|
878
952
|
|
|
879
|
-
// src/blocks/
|
|
953
|
+
// src/blocks/VideoBlock.tsx
|
|
954
|
+
var import_react3 = require("@blocknote/react");
|
|
880
955
|
var import_react4 = require("react");
|
|
881
956
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
957
|
+
var MIN_VIDEO_WIDTH = 200;
|
|
958
|
+
var MAX_VIDEO_WIDTH = 1200;
|
|
959
|
+
var MIN_VIDEO_HEIGHT = 120;
|
|
960
|
+
var MAX_VIDEO_HEIGHT = 600;
|
|
961
|
+
var DEFAULT_VIDEO_WIDTH = 640;
|
|
962
|
+
var DEFAULT_VIDEO_HEIGHT = 360;
|
|
963
|
+
var VideoBlockCard = ({
|
|
964
|
+
url,
|
|
965
|
+
editable,
|
|
966
|
+
width,
|
|
967
|
+
onWidthChange,
|
|
968
|
+
height,
|
|
969
|
+
onHeightChange,
|
|
970
|
+
onContextMenuBlock
|
|
971
|
+
}) => {
|
|
972
|
+
const [resizeParams, setResizeParams] = (0, import_react4.useState)(
|
|
973
|
+
void 0
|
|
974
|
+
);
|
|
975
|
+
const [localWidth, setLocalWidth] = (0, import_react4.useState)(width);
|
|
976
|
+
const [localHeight, setLocalHeight] = (0, import_react4.useState)(height);
|
|
977
|
+
const wrapperRef = (0, import_react4.useRef)(null);
|
|
978
|
+
(0, import_react4.useEffect)(() => {
|
|
979
|
+
setLocalWidth(width);
|
|
980
|
+
}, [width]);
|
|
981
|
+
(0, import_react4.useEffect)(() => {
|
|
982
|
+
setLocalHeight(height);
|
|
983
|
+
}, [height]);
|
|
984
|
+
(0, import_react4.useEffect)(() => {
|
|
985
|
+
if (!resizeParams) return;
|
|
986
|
+
const onMouseMove = (e) => {
|
|
987
|
+
if (resizeParams.handleUsed === "bottom") {
|
|
988
|
+
const delta = e.clientY - resizeParams.initialClientY;
|
|
989
|
+
setLocalHeight(
|
|
990
|
+
Math.min(
|
|
991
|
+
Math.max(resizeParams.initialHeight + delta, MIN_VIDEO_HEIGHT),
|
|
992
|
+
MAX_VIDEO_HEIGHT
|
|
993
|
+
)
|
|
994
|
+
);
|
|
995
|
+
} else {
|
|
996
|
+
const delta = resizeParams.handleUsed === "left" ? resizeParams.initialClientX - e.clientX : e.clientX - resizeParams.initialClientX;
|
|
997
|
+
setLocalWidth(
|
|
998
|
+
Math.min(
|
|
999
|
+
Math.max(resizeParams.initialWidth + delta, MIN_VIDEO_WIDTH),
|
|
1000
|
+
wrapperRef.current?.parentElement?.clientWidth || MAX_VIDEO_WIDTH
|
|
1001
|
+
)
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
const onMouseUp = () => {
|
|
1006
|
+
const handle = resizeParams.handleUsed;
|
|
1007
|
+
setResizeParams(void 0);
|
|
1008
|
+
if (handle === "bottom") {
|
|
1009
|
+
if (localHeight != null && onHeightChange) onHeightChange(localHeight);
|
|
1010
|
+
} else {
|
|
1011
|
+
if (localWidth != null && onWidthChange) onWidthChange(localWidth);
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
window.addEventListener("mousemove", onMouseMove);
|
|
1015
|
+
window.addEventListener("mouseup", onMouseUp);
|
|
1016
|
+
return () => {
|
|
1017
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
1018
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
1019
|
+
};
|
|
1020
|
+
}, [resizeParams, localWidth, localHeight, onWidthChange, onHeightChange]);
|
|
1021
|
+
const handleLeftDown = (0, import_react4.useCallback)((e) => {
|
|
1022
|
+
e.preventDefault();
|
|
1023
|
+
e.stopPropagation();
|
|
1024
|
+
setResizeParams({
|
|
1025
|
+
handleUsed: "left",
|
|
1026
|
+
initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,
|
|
1027
|
+
initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,
|
|
1028
|
+
initialClientX: e.clientX,
|
|
1029
|
+
initialClientY: e.clientY
|
|
1030
|
+
});
|
|
1031
|
+
}, [localHeight]);
|
|
1032
|
+
const handleRightDown = (0, import_react4.useCallback)((e) => {
|
|
1033
|
+
e.preventDefault();
|
|
1034
|
+
e.stopPropagation();
|
|
1035
|
+
setResizeParams({
|
|
1036
|
+
handleUsed: "right",
|
|
1037
|
+
initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,
|
|
1038
|
+
initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,
|
|
1039
|
+
initialClientX: e.clientX,
|
|
1040
|
+
initialClientY: e.clientY
|
|
1041
|
+
});
|
|
1042
|
+
}, [localHeight]);
|
|
1043
|
+
const handleBottomDown = (0, import_react4.useCallback)((e) => {
|
|
1044
|
+
e.preventDefault();
|
|
1045
|
+
e.stopPropagation();
|
|
1046
|
+
setResizeParams({
|
|
1047
|
+
handleUsed: "bottom",
|
|
1048
|
+
initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,
|
|
1049
|
+
initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,
|
|
1050
|
+
initialClientX: e.clientX,
|
|
1051
|
+
initialClientY: e.clientY
|
|
1052
|
+
});
|
|
1053
|
+
}, [localHeight]);
|
|
1054
|
+
const resizeCursor = resizeParams ? resizeParams.handleUsed === "bottom" ? "ns-resize" : "ew-resize" : "default";
|
|
1055
|
+
const [hovered, setHovered] = (0, import_react4.useState)(false);
|
|
1056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1057
|
+
"div",
|
|
1058
|
+
{
|
|
1059
|
+
ref: wrapperRef,
|
|
1060
|
+
className: "lumir-video-block-wrapper",
|
|
1061
|
+
onContextMenu: onContextMenuBlock,
|
|
1062
|
+
style: {
|
|
1063
|
+
position: "relative",
|
|
1064
|
+
width: localWidth != null ? `${localWidth}px` : void 0,
|
|
1065
|
+
maxWidth: "100%",
|
|
1066
|
+
cursor: resizeCursor,
|
|
1067
|
+
transition: resizeParams ? "none" : "box-shadow 0.2s"
|
|
1068
|
+
},
|
|
1069
|
+
onMouseEnter: () => {
|
|
1070
|
+
if (!resizeParams) setHovered(true);
|
|
1071
|
+
},
|
|
1072
|
+
onMouseLeave: () => {
|
|
1073
|
+
if (!resizeParams) setHovered(false);
|
|
1074
|
+
},
|
|
1075
|
+
children: [
|
|
1076
|
+
editable && (hovered || resizeParams) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
1077
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1078
|
+
"div",
|
|
1079
|
+
{
|
|
1080
|
+
className: "lumir-resize-handle",
|
|
1081
|
+
style: { left: "4px" },
|
|
1082
|
+
onMouseDown: handleLeftDown
|
|
1083
|
+
}
|
|
1084
|
+
),
|
|
1085
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1086
|
+
"div",
|
|
1087
|
+
{
|
|
1088
|
+
className: "lumir-resize-handle",
|
|
1089
|
+
style: { right: "4px" },
|
|
1090
|
+
onMouseDown: handleRightDown
|
|
1091
|
+
}
|
|
1092
|
+
)
|
|
1093
|
+
] }),
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1095
|
+
"div",
|
|
1096
|
+
{
|
|
1097
|
+
style: {
|
|
1098
|
+
width: "100%",
|
|
1099
|
+
height: `${localHeight ?? DEFAULT_VIDEO_HEIGHT}px`,
|
|
1100
|
+
overflow: "hidden",
|
|
1101
|
+
backgroundColor: "#000",
|
|
1102
|
+
borderRadius: "6px"
|
|
1103
|
+
},
|
|
1104
|
+
children: [
|
|
1105
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1106
|
+
"video",
|
|
1107
|
+
{
|
|
1108
|
+
src: url,
|
|
1109
|
+
controls: true,
|
|
1110
|
+
playsInline: true,
|
|
1111
|
+
style: {
|
|
1112
|
+
width: "100%",
|
|
1113
|
+
height: "100%",
|
|
1114
|
+
objectFit: "contain",
|
|
1115
|
+
display: "block"
|
|
1116
|
+
},
|
|
1117
|
+
onContextMenu: (e) => e.preventDefault()
|
|
1118
|
+
}
|
|
1119
|
+
),
|
|
1120
|
+
editable && (hovered || resizeParams) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1121
|
+
"div",
|
|
1122
|
+
{
|
|
1123
|
+
className: "lumir-resize-handle-bottom",
|
|
1124
|
+
onMouseDown: handleBottomDown
|
|
1125
|
+
}
|
|
1126
|
+
)
|
|
1127
|
+
]
|
|
1128
|
+
}
|
|
1129
|
+
)
|
|
1130
|
+
]
|
|
1131
|
+
}
|
|
1132
|
+
);
|
|
1133
|
+
};
|
|
1134
|
+
var VideoBlock = (0, import_react3.createReactBlockSpec)(
|
|
1135
|
+
{
|
|
1136
|
+
type: "video",
|
|
1137
|
+
propSchema: {
|
|
1138
|
+
url: { default: "" },
|
|
1139
|
+
previewWidth: { default: 640 },
|
|
1140
|
+
previewHeight: { default: 360 }
|
|
1141
|
+
},
|
|
1142
|
+
content: "none"
|
|
1143
|
+
},
|
|
1144
|
+
{
|
|
1145
|
+
render: (props) => {
|
|
1146
|
+
const url = props.block.props.url ?? "";
|
|
1147
|
+
const editable = props.editor.isEditable;
|
|
1148
|
+
const handleContextMenu = (0, import_react4.useCallback)((e) => {
|
|
1149
|
+
e.preventDefault();
|
|
1150
|
+
e.stopPropagation();
|
|
1151
|
+
}, []);
|
|
1152
|
+
if (!url) {
|
|
1153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1154
|
+
"div",
|
|
1155
|
+
{
|
|
1156
|
+
className: "lumir-video-block-placeholder",
|
|
1157
|
+
onContextMenu: handleContextMenu,
|
|
1158
|
+
style: {
|
|
1159
|
+
width: "100%",
|
|
1160
|
+
maxWidth: `${DEFAULT_VIDEO_WIDTH}px`,
|
|
1161
|
+
height: `${DEFAULT_VIDEO_HEIGHT}px`,
|
|
1162
|
+
backgroundColor: "#1a1a1a",
|
|
1163
|
+
borderRadius: "6px",
|
|
1164
|
+
display: "flex",
|
|
1165
|
+
alignItems: "center",
|
|
1166
|
+
justifyContent: "center",
|
|
1167
|
+
color: "rgba(255,255,255,0.5)",
|
|
1168
|
+
fontSize: "14px"
|
|
1169
|
+
},
|
|
1170
|
+
children: "\uBE44\uB514\uC624 URL \uC5C6\uC74C"
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1175
|
+
VideoBlockCard,
|
|
1176
|
+
{
|
|
1177
|
+
url,
|
|
1178
|
+
editable,
|
|
1179
|
+
width: props.block.props.previewWidth,
|
|
1180
|
+
onWidthChange: (newWidth) => {
|
|
1181
|
+
props.editor.updateBlock(props.block, {
|
|
1182
|
+
props: { previewWidth: newWidth }
|
|
1183
|
+
});
|
|
1184
|
+
},
|
|
1185
|
+
height: props.block.props.previewHeight,
|
|
1186
|
+
onHeightChange: (newHeight) => {
|
|
1187
|
+
props.editor.updateBlock(props.block, {
|
|
1188
|
+
props: { previewHeight: newHeight }
|
|
1189
|
+
});
|
|
1190
|
+
},
|
|
1191
|
+
onContextMenuBlock: handleContextMenu
|
|
1192
|
+
}
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
);
|
|
1197
|
+
|
|
1198
|
+
// src/blocks/HtmlPreview.tsx
|
|
1199
|
+
var import_react6 = require("react");
|
|
1200
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
882
1201
|
var MIN_HEIGHT = 100;
|
|
883
1202
|
var MAX_HEIGHT = 1200;
|
|
884
1203
|
var ensureCharset = (html) => {
|
|
@@ -916,7 +1235,7 @@ var createSecureBlobUrl = (htmlContent) => {
|
|
|
916
1235
|
});
|
|
917
1236
|
return URL.createObjectURL(blob);
|
|
918
1237
|
};
|
|
919
|
-
var HtmlPreviewBlock = (0,
|
|
1238
|
+
var HtmlPreviewBlock = (0, import_react5.createReactBlockSpec)(
|
|
920
1239
|
{
|
|
921
1240
|
type: "htmlPreview",
|
|
922
1241
|
propSchema: {
|
|
@@ -934,15 +1253,15 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
934
1253
|
},
|
|
935
1254
|
{
|
|
936
1255
|
render: (props) => {
|
|
937
|
-
const [isExpanded, setIsExpanded] = (0,
|
|
938
|
-
const [isResizing, setIsResizing] = (0,
|
|
939
|
-
const [blobUrl, setBlobUrl] = (0,
|
|
940
|
-
const containerRef = (0,
|
|
1256
|
+
const [isExpanded, setIsExpanded] = (0, import_react6.useState)(true);
|
|
1257
|
+
const [isResizing, setIsResizing] = (0, import_react6.useState)(false);
|
|
1258
|
+
const [blobUrl, setBlobUrl] = (0, import_react6.useState)("");
|
|
1259
|
+
const containerRef = (0, import_react6.useRef)(null);
|
|
941
1260
|
const htmlContent = props.block.props.htmlContent || "";
|
|
942
1261
|
const fileName = props.block.props.fileName || "HTML Document";
|
|
943
1262
|
const savedHeight = props.block.props.height || "400px";
|
|
944
1263
|
const currentHeight = parseInt(savedHeight, 10) || 400;
|
|
945
|
-
(0,
|
|
1264
|
+
(0, import_react6.useEffect)(() => {
|
|
946
1265
|
if (htmlContent) {
|
|
947
1266
|
const url = createSecureBlobUrl(htmlContent);
|
|
948
1267
|
setBlobUrl(url);
|
|
@@ -951,7 +1270,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
951
1270
|
};
|
|
952
1271
|
}
|
|
953
1272
|
}, [htmlContent]);
|
|
954
|
-
const handleResizeStart = (0,
|
|
1273
|
+
const handleResizeStart = (0, import_react6.useCallback)(
|
|
955
1274
|
(e) => {
|
|
956
1275
|
e.preventDefault();
|
|
957
1276
|
e.stopPropagation();
|
|
@@ -978,7 +1297,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
978
1297
|
},
|
|
979
1298
|
[currentHeight, props.editor, props.block]
|
|
980
1299
|
);
|
|
981
|
-
const handleExport = (0,
|
|
1300
|
+
const handleExport = (0, import_react6.useCallback)(
|
|
982
1301
|
(e) => {
|
|
983
1302
|
e.stopPropagation();
|
|
984
1303
|
const safeFileName = sanitizeFileName(fileName);
|
|
@@ -999,7 +1318,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
999
1318
|
},
|
|
1000
1319
|
[htmlContent, fileName]
|
|
1001
1320
|
);
|
|
1002
|
-
const handleOpenNewWindow = (0,
|
|
1321
|
+
const handleOpenNewWindow = (0, import_react6.useCallback)(
|
|
1003
1322
|
(e) => {
|
|
1004
1323
|
e.stopPropagation();
|
|
1005
1324
|
if (typeof window === "undefined") return;
|
|
@@ -1013,7 +1332,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1013
1332
|
},
|
|
1014
1333
|
[htmlContent]
|
|
1015
1334
|
);
|
|
1016
|
-
return /* @__PURE__ */ (0,
|
|
1335
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1017
1336
|
"div",
|
|
1018
1337
|
{
|
|
1019
1338
|
ref: containerRef,
|
|
@@ -1029,7 +1348,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1029
1348
|
boxShadow: "none"
|
|
1030
1349
|
},
|
|
1031
1350
|
children: [
|
|
1032
|
-
/* @__PURE__ */ (0,
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1033
1352
|
"div",
|
|
1034
1353
|
{
|
|
1035
1354
|
style: {
|
|
@@ -1041,7 +1360,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1041
1360
|
borderBottom: isExpanded ? "1px solid #e0e0e0" : "none"
|
|
1042
1361
|
},
|
|
1043
1362
|
children: [
|
|
1044
|
-
/* @__PURE__ */ (0,
|
|
1363
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1045
1364
|
"div",
|
|
1046
1365
|
{
|
|
1047
1366
|
style: {
|
|
@@ -1053,7 +1372,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1053
1372
|
},
|
|
1054
1373
|
onClick: () => setIsExpanded(!isExpanded),
|
|
1055
1374
|
children: [
|
|
1056
|
-
/* @__PURE__ */ (0,
|
|
1375
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1057
1376
|
"svg",
|
|
1058
1377
|
{
|
|
1059
1378
|
width: "16",
|
|
@@ -1068,15 +1387,15 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1068
1387
|
transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)",
|
|
1069
1388
|
transition: "transform 0.2s"
|
|
1070
1389
|
},
|
|
1071
|
-
children: /* @__PURE__ */ (0,
|
|
1390
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "6 9 12 15 18 9" })
|
|
1072
1391
|
}
|
|
1073
1392
|
),
|
|
1074
|
-
/* @__PURE__ */ (0,
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontWeight: 500, fontSize: "14px" }, children: fileName })
|
|
1075
1394
|
]
|
|
1076
1395
|
}
|
|
1077
1396
|
),
|
|
1078
|
-
/* @__PURE__ */ (0,
|
|
1079
|
-
/* @__PURE__ */ (0,
|
|
1397
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1080
1399
|
"button",
|
|
1081
1400
|
{
|
|
1082
1401
|
onClick: handleOpenNewWindow,
|
|
@@ -1099,7 +1418,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1099
1418
|
onMouseLeave: (e) => {
|
|
1100
1419
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
1101
1420
|
},
|
|
1102
|
-
children: /* @__PURE__ */ (0,
|
|
1421
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1103
1422
|
"svg",
|
|
1104
1423
|
{
|
|
1105
1424
|
width: "16",
|
|
@@ -1111,15 +1430,15 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1111
1430
|
strokeLinecap: "round",
|
|
1112
1431
|
strokeLinejoin: "round",
|
|
1113
1432
|
children: [
|
|
1114
|
-
/* @__PURE__ */ (0,
|
|
1115
|
-
/* @__PURE__ */ (0,
|
|
1116
|
-
/* @__PURE__ */ (0,
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
1117
1436
|
]
|
|
1118
1437
|
}
|
|
1119
1438
|
)
|
|
1120
1439
|
}
|
|
1121
1440
|
),
|
|
1122
|
-
/* @__PURE__ */ (0,
|
|
1441
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1123
1442
|
"button",
|
|
1124
1443
|
{
|
|
1125
1444
|
onClick: handleExport,
|
|
@@ -1142,7 +1461,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1142
1461
|
onMouseLeave: (e) => {
|
|
1143
1462
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
1144
1463
|
},
|
|
1145
|
-
children: /* @__PURE__ */ (0,
|
|
1464
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1146
1465
|
"svg",
|
|
1147
1466
|
{
|
|
1148
1467
|
width: "16",
|
|
@@ -1154,9 +1473,9 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1154
1473
|
strokeLinecap: "round",
|
|
1155
1474
|
strokeLinejoin: "round",
|
|
1156
1475
|
children: [
|
|
1157
|
-
/* @__PURE__ */ (0,
|
|
1158
|
-
/* @__PURE__ */ (0,
|
|
1159
|
-
/* @__PURE__ */ (0,
|
|
1476
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1477
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "7 10 12 15 17 10" }),
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
|
|
1160
1479
|
]
|
|
1161
1480
|
}
|
|
1162
1481
|
)
|
|
@@ -1166,7 +1485,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1166
1485
|
]
|
|
1167
1486
|
}
|
|
1168
1487
|
),
|
|
1169
|
-
isExpanded && /* @__PURE__ */ (0,
|
|
1488
|
+
isExpanded && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1170
1489
|
"div",
|
|
1171
1490
|
{
|
|
1172
1491
|
style: {
|
|
@@ -1175,7 +1494,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1175
1494
|
position: "relative"
|
|
1176
1495
|
},
|
|
1177
1496
|
children: [
|
|
1178
|
-
/* @__PURE__ */ (0,
|
|
1497
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1179
1498
|
"iframe",
|
|
1180
1499
|
{
|
|
1181
1500
|
src: blobUrl || "about:blank",
|
|
@@ -1192,7 +1511,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1192
1511
|
loading: "lazy"
|
|
1193
1512
|
}
|
|
1194
1513
|
),
|
|
1195
|
-
/* @__PURE__ */ (0,
|
|
1514
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1196
1515
|
"div",
|
|
1197
1516
|
{
|
|
1198
1517
|
onMouseDown: handleResizeStart,
|
|
@@ -1217,7 +1536,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1217
1536
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
1218
1537
|
}
|
|
1219
1538
|
},
|
|
1220
|
-
children: /* @__PURE__ */ (0,
|
|
1539
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1221
1540
|
"div",
|
|
1222
1541
|
{
|
|
1223
1542
|
style: {
|
|
@@ -1242,6 +1561,7 @@ var HtmlPreviewBlock = (0, import_react3.createReactBlockSpec)(
|
|
|
1242
1561
|
var schema = import_core.BlockNoteSchema.create({
|
|
1243
1562
|
blockSpecs: {
|
|
1244
1563
|
...import_core.defaultBlockSpecs,
|
|
1564
|
+
video: VideoBlock,
|
|
1245
1565
|
htmlPreview: HtmlPreviewBlock,
|
|
1246
1566
|
linkPreview: LinkPreviewBlock
|
|
1247
1567
|
},
|
|
@@ -1250,60 +1570,60 @@ var schema = import_core.BlockNoteSchema.create({
|
|
|
1250
1570
|
});
|
|
1251
1571
|
|
|
1252
1572
|
// src/components/FloatingMenu/index.tsx
|
|
1253
|
-
var
|
|
1573
|
+
var import_react17 = require("react");
|
|
1254
1574
|
|
|
1255
1575
|
// src/components/FloatingMenu/Icons.tsx
|
|
1256
|
-
var
|
|
1576
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1257
1577
|
var Icons = {
|
|
1258
|
-
undo: /* @__PURE__ */ (0,
|
|
1259
|
-
redo: /* @__PURE__ */ (0,
|
|
1260
|
-
bold: /* @__PURE__ */ (0,
|
|
1261
|
-
italic: /* @__PURE__ */ (0,
|
|
1262
|
-
underline: /* @__PURE__ */ (0,
|
|
1263
|
-
strikethrough: /* @__PURE__ */ (0,
|
|
1264
|
-
alignLeft: /* @__PURE__ */ (0,
|
|
1265
|
-
alignCenter: /* @__PURE__ */ (0,
|
|
1266
|
-
alignRight: /* @__PURE__ */ (0,
|
|
1267
|
-
bulletList: /* @__PURE__ */ (0,
|
|
1268
|
-
numberedList: /* @__PURE__ */ (0,
|
|
1269
|
-
image: /* @__PURE__ */ (0,
|
|
1270
|
-
expandMore: /* @__PURE__ */ (0,
|
|
1271
|
-
textColor: /* @__PURE__ */ (0,
|
|
1272
|
-
bgColor: /* @__PURE__ */ (0,
|
|
1273
|
-
/* @__PURE__ */ (0,
|
|
1274
|
-
/* @__PURE__ */ (0,
|
|
1578
|
+
undo: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z" }) }),
|
|
1579
|
+
redo: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z" }) }),
|
|
1580
|
+
bold: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z" }) }),
|
|
1581
|
+
italic: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" }) }),
|
|
1582
|
+
underline: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z" }) }),
|
|
1583
|
+
strikethrough: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z" }) }),
|
|
1584
|
+
alignLeft: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z" }) }),
|
|
1585
|
+
alignCenter: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z" }) }),
|
|
1586
|
+
alignRight: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z" }) }),
|
|
1587
|
+
bulletList: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z" }) }),
|
|
1588
|
+
numberedList: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z" }) }),
|
|
1589
|
+
image: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z" }) }),
|
|
1590
|
+
expandMore: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" }) }),
|
|
1591
|
+
textColor: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z" }) }),
|
|
1592
|
+
bgColor: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16.56 8.94L7.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 10L10 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" }),
|
|
1594
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { fillOpacity: ".36", d: "M0 20h24v4H0z" })
|
|
1275
1595
|
] }),
|
|
1276
|
-
link: /* @__PURE__ */ (0,
|
|
1277
|
-
chevronRight: /* @__PURE__ */ (0,
|
|
1278
|
-
chevronLeft: /* @__PURE__ */ (0,
|
|
1279
|
-
table: /* @__PURE__ */ (0,
|
|
1280
|
-
htmlFile: /* @__PURE__ */ (0,
|
|
1596
|
+
link: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" }) }),
|
|
1597
|
+
chevronRight: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" }) }),
|
|
1598
|
+
chevronLeft: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" }) }),
|
|
1599
|
+
table: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M20 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM10 17H5v-2h5v2zm0-4H5v-2h5v2zm0-4H5V7h5v2zm9 8h-7v-2h7v2zm0-4h-7v-2h7v2zm0-4h-7V7h7v2z" }) }),
|
|
1600
|
+
htmlFile: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 2v5h5l-5-5zm-4 14H7v-1h2v1zm0-2H7v-1h2v1zm-2-2h2v1H7v-1zm4 4h-2v-1h2v1zm0-2h-2v-1h2v1zm0-2h-2v-1h2v1zm6 4h-4v-1h4v1zm0-2h-4v-1h4v1zm0-2h-4v-1h4v1z" }) })
|
|
1281
1601
|
};
|
|
1282
1602
|
var BlockTypeIcons = {
|
|
1283
|
-
paragraph: /* @__PURE__ */ (0,
|
|
1284
|
-
h1: /* @__PURE__ */ (0,
|
|
1285
|
-
h2: /* @__PURE__ */ (0,
|
|
1286
|
-
h3: /* @__PURE__ */ (0,
|
|
1287
|
-
h4: /* @__PURE__ */ (0,
|
|
1288
|
-
h5: /* @__PURE__ */ (0,
|
|
1289
|
-
h6: /* @__PURE__ */ (0,
|
|
1290
|
-
toggleH1: /* @__PURE__ */ (0,
|
|
1291
|
-
/* @__PURE__ */ (0,
|
|
1292
|
-
/* @__PURE__ */ (0,
|
|
1603
|
+
paragraph: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5 5h14v2H5zM5 11h14v2H5zM5 17h10v2H5z" }) }),
|
|
1604
|
+
h1: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lumir-block-icon-text", children: "H1" }),
|
|
1605
|
+
h2: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lumir-block-icon-text", children: "H2" }),
|
|
1606
|
+
h3: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lumir-block-icon-text", children: "H3" }),
|
|
1607
|
+
h4: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lumir-block-icon-text", children: "H4" }),
|
|
1608
|
+
h5: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lumir-block-icon-text", children: "H5" }),
|
|
1609
|
+
h6: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "lumir-block-icon-text", children: "H6" }),
|
|
1610
|
+
toggleH1: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "lumir-block-icon-toggle", children: [
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M8 5v14l11-7z" }) }),
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "H1" })
|
|
1293
1613
|
] }),
|
|
1294
|
-
toggleH2: /* @__PURE__ */ (0,
|
|
1295
|
-
/* @__PURE__ */ (0,
|
|
1296
|
-
/* @__PURE__ */ (0,
|
|
1614
|
+
toggleH2: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "lumir-block-icon-toggle", children: [
|
|
1615
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M8 5v14l11-7z" }) }),
|
|
1616
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "H2" })
|
|
1297
1617
|
] }),
|
|
1298
|
-
toggleH3: /* @__PURE__ */ (0,
|
|
1299
|
-
/* @__PURE__ */ (0,
|
|
1300
|
-
/* @__PURE__ */ (0,
|
|
1618
|
+
toggleH3: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "lumir-block-icon-toggle", children: [
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M8 5v14l11-7z" }) }),
|
|
1620
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "H3" })
|
|
1301
1621
|
] }),
|
|
1302
|
-
quote: /* @__PURE__ */ (0,
|
|
1303
|
-
codeBlock: /* @__PURE__ */ (0,
|
|
1304
|
-
toggleList: /* @__PURE__ */ (0,
|
|
1305
|
-
/* @__PURE__ */ (0,
|
|
1306
|
-
/* @__PURE__ */ (0,
|
|
1622
|
+
quote: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z" }) }),
|
|
1623
|
+
codeBlock: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z" }) }),
|
|
1624
|
+
toggleList: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M10 6h10v2H10zM10 11h10v2H10zM10 16h10v2H10z" }),
|
|
1626
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1307
1627
|
"path",
|
|
1308
1628
|
{
|
|
1309
1629
|
d: "M4 8l4 4-4 4",
|
|
@@ -1315,15 +1635,15 @@ var BlockTypeIcons = {
|
|
|
1315
1635
|
}
|
|
1316
1636
|
)
|
|
1317
1637
|
] }),
|
|
1318
|
-
bulletList: /* @__PURE__ */ (0,
|
|
1319
|
-
/* @__PURE__ */ (0,
|
|
1320
|
-
/* @__PURE__ */ (0,
|
|
1321
|
-
/* @__PURE__ */ (0,
|
|
1322
|
-
/* @__PURE__ */ (0,
|
|
1638
|
+
bulletList: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1639
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "4", cy: "6", r: "1.5" }),
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "4", cy: "12", r: "1.5" }),
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "4", cy: "18", r: "1.5" }),
|
|
1642
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M8 5h12v2H8zM8 11h12v2H8zM8 17h12v2H8z" })
|
|
1323
1643
|
] }),
|
|
1324
|
-
numberedList: /* @__PURE__ */ (0,
|
|
1325
|
-
checkList: /* @__PURE__ */ (0,
|
|
1326
|
-
/* @__PURE__ */ (0,
|
|
1644
|
+
numberedList: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z" }) }),
|
|
1645
|
+
checkList: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1327
1647
|
"rect",
|
|
1328
1648
|
{
|
|
1329
1649
|
x: "3",
|
|
@@ -1336,7 +1656,7 @@ var BlockTypeIcons = {
|
|
|
1336
1656
|
strokeWidth: "1.5"
|
|
1337
1657
|
}
|
|
1338
1658
|
),
|
|
1339
|
-
/* @__PURE__ */ (0,
|
|
1659
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1340
1660
|
"path",
|
|
1341
1661
|
{
|
|
1342
1662
|
d: "M4.5 7l1.5 1.5 3-3",
|
|
@@ -1347,8 +1667,8 @@ var BlockTypeIcons = {
|
|
|
1347
1667
|
strokeLinejoin: "round"
|
|
1348
1668
|
}
|
|
1349
1669
|
),
|
|
1350
|
-
/* @__PURE__ */ (0,
|
|
1351
|
-
/* @__PURE__ */ (0,
|
|
1670
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 6h8v2h-8z" }),
|
|
1671
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1352
1672
|
"rect",
|
|
1353
1673
|
{
|
|
1354
1674
|
x: "3",
|
|
@@ -1361,37 +1681,37 @@ var BlockTypeIcons = {
|
|
|
1361
1681
|
strokeWidth: "1.5"
|
|
1362
1682
|
}
|
|
1363
1683
|
),
|
|
1364
|
-
/* @__PURE__ */ (0,
|
|
1684
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 16h8v2h-8z" })
|
|
1365
1685
|
] })
|
|
1366
1686
|
};
|
|
1367
1687
|
|
|
1368
1688
|
// src/components/FloatingMenu/components/ToolbarDivider.tsx
|
|
1369
|
-
var
|
|
1370
|
-
var ToolbarDivider = () => /* @__PURE__ */ (0,
|
|
1689
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1690
|
+
var ToolbarDivider = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lumir-toolbar-divider" });
|
|
1371
1691
|
|
|
1372
1692
|
// src/components/FloatingMenu/components/UndoRedoButtons.tsx
|
|
1373
|
-
var
|
|
1374
|
-
var
|
|
1693
|
+
var import_react7 = require("react");
|
|
1694
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1375
1695
|
var UndoRedoButtons = ({ editor }) => {
|
|
1376
|
-
const handleUndo = (0,
|
|
1696
|
+
const handleUndo = (0, import_react7.useCallback)(() => {
|
|
1377
1697
|
try {
|
|
1378
1698
|
editor?.undo?.();
|
|
1379
1699
|
} catch (err) {
|
|
1380
1700
|
console.error("Undo failed:", err);
|
|
1381
1701
|
}
|
|
1382
1702
|
}, [editor]);
|
|
1383
|
-
const handleRedo = (0,
|
|
1703
|
+
const handleRedo = (0, import_react7.useCallback)(() => {
|
|
1384
1704
|
try {
|
|
1385
1705
|
editor?.redo?.();
|
|
1386
1706
|
} catch (err) {
|
|
1387
1707
|
console.error("Redo failed:", err);
|
|
1388
1708
|
}
|
|
1389
1709
|
}, [editor]);
|
|
1390
|
-
const handleMouseDown = (0,
|
|
1710
|
+
const handleMouseDown = (0, import_react7.useCallback)((e) => {
|
|
1391
1711
|
e.preventDefault();
|
|
1392
1712
|
}, []);
|
|
1393
|
-
return /* @__PURE__ */ (0,
|
|
1394
|
-
/* @__PURE__ */ (0,
|
|
1713
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
1714
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1395
1715
|
"button",
|
|
1396
1716
|
{
|
|
1397
1717
|
className: "lumir-toolbar-btn",
|
|
@@ -1402,7 +1722,7 @@ var UndoRedoButtons = ({ editor }) => {
|
|
|
1402
1722
|
children: Icons.undo
|
|
1403
1723
|
}
|
|
1404
1724
|
),
|
|
1405
|
-
/* @__PURE__ */ (0,
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1406
1726
|
"button",
|
|
1407
1727
|
{
|
|
1408
1728
|
className: "lumir-toolbar-btn",
|
|
@@ -1417,8 +1737,8 @@ var UndoRedoButtons = ({ editor }) => {
|
|
|
1417
1737
|
};
|
|
1418
1738
|
|
|
1419
1739
|
// src/components/FloatingMenu/components/TextStyleButton.tsx
|
|
1420
|
-
var
|
|
1421
|
-
var
|
|
1740
|
+
var import_react8 = require("react");
|
|
1741
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1422
1742
|
var iconMap = {
|
|
1423
1743
|
bold: Icons.bold,
|
|
1424
1744
|
italic: Icons.italic,
|
|
@@ -1444,17 +1764,17 @@ var TextStyleButton = ({
|
|
|
1444
1764
|
}
|
|
1445
1765
|
};
|
|
1446
1766
|
const isActive = getIsActive();
|
|
1447
|
-
const handleClick = (0,
|
|
1767
|
+
const handleClick = (0, import_react8.useCallback)(() => {
|
|
1448
1768
|
try {
|
|
1449
1769
|
editor?.toggleStyles?.({ [style]: true });
|
|
1450
1770
|
} catch (err) {
|
|
1451
1771
|
console.error(`Toggle ${style} failed:`, err);
|
|
1452
1772
|
}
|
|
1453
1773
|
}, [editor, style]);
|
|
1454
|
-
const handleMouseDown = (0,
|
|
1774
|
+
const handleMouseDown = (0, import_react8.useCallback)((e) => {
|
|
1455
1775
|
e.preventDefault();
|
|
1456
1776
|
}, []);
|
|
1457
|
-
return /* @__PURE__ */ (0,
|
|
1777
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1458
1778
|
"button",
|
|
1459
1779
|
{
|
|
1460
1780
|
className: cn("lumir-toolbar-btn", isActive && "is-active"),
|
|
@@ -1468,8 +1788,8 @@ var TextStyleButton = ({
|
|
|
1468
1788
|
};
|
|
1469
1789
|
|
|
1470
1790
|
// src/components/FloatingMenu/components/AlignButton.tsx
|
|
1471
|
-
var
|
|
1472
|
-
var
|
|
1791
|
+
var import_react9 = require("react");
|
|
1792
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1473
1793
|
var iconMap2 = {
|
|
1474
1794
|
left: Icons.alignLeft,
|
|
1475
1795
|
center: Icons.alignCenter,
|
|
@@ -1493,7 +1813,7 @@ var AlignButton = ({
|
|
|
1493
1813
|
}
|
|
1494
1814
|
};
|
|
1495
1815
|
const isActive = getCurrentAlignment() === alignment;
|
|
1496
|
-
const handleClick = (0,
|
|
1816
|
+
const handleClick = (0, import_react9.useCallback)(() => {
|
|
1497
1817
|
try {
|
|
1498
1818
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1499
1819
|
if (block && editor?.updateBlock) {
|
|
@@ -1503,10 +1823,10 @@ var AlignButton = ({
|
|
|
1503
1823
|
console.error(`Set alignment ${alignment} failed:`, err);
|
|
1504
1824
|
}
|
|
1505
1825
|
}, [editor, alignment]);
|
|
1506
|
-
const handleMouseDown = (0,
|
|
1826
|
+
const handleMouseDown = (0, import_react9.useCallback)((e) => {
|
|
1507
1827
|
e.preventDefault();
|
|
1508
1828
|
}, []);
|
|
1509
|
-
return /* @__PURE__ */ (0,
|
|
1829
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1510
1830
|
"button",
|
|
1511
1831
|
{
|
|
1512
1832
|
className: cn("lumir-toolbar-btn", isActive && "is-active"),
|
|
@@ -1520,8 +1840,8 @@ var AlignButton = ({
|
|
|
1520
1840
|
};
|
|
1521
1841
|
|
|
1522
1842
|
// src/components/FloatingMenu/components/ListButton.tsx
|
|
1523
|
-
var
|
|
1524
|
-
var
|
|
1843
|
+
var import_react10 = require("react");
|
|
1844
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1525
1845
|
var iconMap3 = {
|
|
1526
1846
|
bullet: Icons.bulletList,
|
|
1527
1847
|
numbered: Icons.numberedList
|
|
@@ -1541,7 +1861,7 @@ var ListButton = ({ editor, type }) => {
|
|
|
1541
1861
|
}
|
|
1542
1862
|
};
|
|
1543
1863
|
const isActive = getIsActive();
|
|
1544
|
-
const handleClick = (0,
|
|
1864
|
+
const handleClick = (0, import_react10.useCallback)(() => {
|
|
1545
1865
|
try {
|
|
1546
1866
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1547
1867
|
if (block && editor?.updateBlock) {
|
|
@@ -1553,10 +1873,10 @@ var ListButton = ({ editor, type }) => {
|
|
|
1553
1873
|
console.error(`List toggle failed:`, err);
|
|
1554
1874
|
}
|
|
1555
1875
|
}, [editor, type]);
|
|
1556
|
-
const handleMouseDown = (0,
|
|
1876
|
+
const handleMouseDown = (0, import_react10.useCallback)((e) => {
|
|
1557
1877
|
e.preventDefault();
|
|
1558
1878
|
}, []);
|
|
1559
|
-
return /* @__PURE__ */ (0,
|
|
1879
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1560
1880
|
"button",
|
|
1561
1881
|
{
|
|
1562
1882
|
className: cn("lumir-toolbar-btn", isActive && "is-active"),
|
|
@@ -1570,13 +1890,13 @@ var ListButton = ({ editor, type }) => {
|
|
|
1570
1890
|
};
|
|
1571
1891
|
|
|
1572
1892
|
// src/components/FloatingMenu/components/ImageButton.tsx
|
|
1573
|
-
var
|
|
1574
|
-
var
|
|
1893
|
+
var import_react11 = require("react");
|
|
1894
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1575
1895
|
var ImageButton = ({
|
|
1576
1896
|
editor,
|
|
1577
1897
|
onImageUpload
|
|
1578
1898
|
}) => {
|
|
1579
|
-
const handleClick = (0,
|
|
1899
|
+
const handleClick = (0, import_react11.useCallback)(() => {
|
|
1580
1900
|
if (onImageUpload) {
|
|
1581
1901
|
onImageUpload();
|
|
1582
1902
|
} else {
|
|
@@ -1601,10 +1921,10 @@ var ImageButton = ({
|
|
|
1601
1921
|
input.click();
|
|
1602
1922
|
}
|
|
1603
1923
|
}, [editor, onImageUpload]);
|
|
1604
|
-
const handleMouseDown = (0,
|
|
1924
|
+
const handleMouseDown = (0, import_react11.useCallback)((e) => {
|
|
1605
1925
|
e.preventDefault();
|
|
1606
1926
|
}, []);
|
|
1607
|
-
return /* @__PURE__ */ (0,
|
|
1927
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1608
1928
|
"button",
|
|
1609
1929
|
{
|
|
1610
1930
|
className: "lumir-toolbar-btn",
|
|
@@ -1618,7 +1938,7 @@ var ImageButton = ({
|
|
|
1618
1938
|
};
|
|
1619
1939
|
|
|
1620
1940
|
// src/components/FloatingMenu/components/ColorButton.tsx
|
|
1621
|
-
var
|
|
1941
|
+
var import_react12 = require("react");
|
|
1622
1942
|
|
|
1623
1943
|
// src/constants/colors.ts
|
|
1624
1944
|
var TEXT_COLORS = [
|
|
@@ -1652,13 +1972,13 @@ var getHexFromColorValue = (value, type) => {
|
|
|
1652
1972
|
};
|
|
1653
1973
|
|
|
1654
1974
|
// src/components/FloatingMenu/components/ColorButton.tsx
|
|
1655
|
-
var
|
|
1975
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1656
1976
|
var ColorButton = ({ editor, type }) => {
|
|
1657
|
-
const [isOpen, setIsOpen] = (0,
|
|
1658
|
-
const [currentColor, setCurrentColor] = (0,
|
|
1659
|
-
const dropdownRef = (0,
|
|
1977
|
+
const [isOpen, setIsOpen] = (0, import_react12.useState)(false);
|
|
1978
|
+
const [currentColor, setCurrentColor] = (0, import_react12.useState)("default");
|
|
1979
|
+
const dropdownRef = (0, import_react12.useRef)(null);
|
|
1660
1980
|
const colors = type === "text" ? TEXT_COLORS : BACKGROUND_COLORS;
|
|
1661
|
-
const getCurrentColor = (0,
|
|
1981
|
+
const getCurrentColor = (0, import_react12.useCallback)(() => {
|
|
1662
1982
|
try {
|
|
1663
1983
|
const activeStyles = editor?.getActiveStyles?.() || {};
|
|
1664
1984
|
if (type === "text" && activeStyles.textColor) {
|
|
@@ -1670,13 +1990,13 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1670
1990
|
}
|
|
1671
1991
|
return "default";
|
|
1672
1992
|
}, [editor, type]);
|
|
1673
|
-
(0,
|
|
1993
|
+
(0, import_react12.useEffect)(() => {
|
|
1674
1994
|
if (isOpen) {
|
|
1675
1995
|
const color = getCurrentColor();
|
|
1676
1996
|
setCurrentColor(color);
|
|
1677
1997
|
}
|
|
1678
1998
|
}, [isOpen, getCurrentColor]);
|
|
1679
|
-
(0,
|
|
1999
|
+
(0, import_react12.useEffect)(() => {
|
|
1680
2000
|
const handleClickOutside = (e) => {
|
|
1681
2001
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1682
2002
|
setIsOpen(false);
|
|
@@ -1685,7 +2005,7 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1685
2005
|
document.addEventListener("mousedown", handleClickOutside);
|
|
1686
2006
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1687
2007
|
}, []);
|
|
1688
|
-
const handleColorSelect = (0,
|
|
2008
|
+
const handleColorSelect = (0, import_react12.useCallback)(
|
|
1689
2009
|
(color) => {
|
|
1690
2010
|
try {
|
|
1691
2011
|
if (!editor) return;
|
|
@@ -1702,11 +2022,11 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1702
2022
|
},
|
|
1703
2023
|
[editor, type]
|
|
1704
2024
|
);
|
|
1705
|
-
const handleMouseDown = (0,
|
|
2025
|
+
const handleMouseDown = (0, import_react12.useCallback)((e) => {
|
|
1706
2026
|
e.preventDefault();
|
|
1707
2027
|
}, []);
|
|
1708
|
-
return /* @__PURE__ */ (0,
|
|
1709
|
-
/* @__PURE__ */ (0,
|
|
2028
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
|
|
2029
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1710
2030
|
"button",
|
|
1711
2031
|
{
|
|
1712
2032
|
className: "lumir-toolbar-btn lumir-color-btn",
|
|
@@ -1716,7 +2036,7 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1716
2036
|
type: "button",
|
|
1717
2037
|
children: [
|
|
1718
2038
|
type === "text" ? Icons.textColor : Icons.bgColor,
|
|
1719
|
-
/* @__PURE__ */ (0,
|
|
2039
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1720
2040
|
"span",
|
|
1721
2041
|
{
|
|
1722
2042
|
className: "lumir-color-indicator",
|
|
@@ -1728,7 +2048,7 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1728
2048
|
]
|
|
1729
2049
|
}
|
|
1730
2050
|
),
|
|
1731
|
-
isOpen && /* @__PURE__ */ (0,
|
|
2051
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "lumir-dropdown-menu lumir-color-menu", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "lumir-color-grid", children: colors.map((color) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1732
2052
|
"button",
|
|
1733
2053
|
{
|
|
1734
2054
|
className: cn(
|
|
@@ -1747,8 +2067,8 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1747
2067
|
};
|
|
1748
2068
|
|
|
1749
2069
|
// src/components/FloatingMenu/components/LinkButton.tsx
|
|
1750
|
-
var
|
|
1751
|
-
var
|
|
2070
|
+
var import_react13 = require("react");
|
|
2071
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1752
2072
|
var isDangerousProtocol = (url) => {
|
|
1753
2073
|
const trimmedUrl = url.trim().toLowerCase();
|
|
1754
2074
|
const dangerousPatterns = [
|
|
@@ -1774,13 +2094,13 @@ var normalizeUrl = (url) => {
|
|
|
1774
2094
|
return `https://${trimmedUrl}`;
|
|
1775
2095
|
};
|
|
1776
2096
|
var LinkButton = ({ editor }) => {
|
|
1777
|
-
const [isOpen, setIsOpen] = (0,
|
|
1778
|
-
const [linkUrl, setLinkUrl] = (0,
|
|
1779
|
-
const [errorMsg, setErrorMsg] = (0,
|
|
1780
|
-
const dropdownRef = (0,
|
|
1781
|
-
const inputRef = (0,
|
|
1782
|
-
const hasSelectionRef = (0,
|
|
1783
|
-
(0,
|
|
2097
|
+
const [isOpen, setIsOpen] = (0, import_react13.useState)(false);
|
|
2098
|
+
const [linkUrl, setLinkUrl] = (0, import_react13.useState)("");
|
|
2099
|
+
const [errorMsg, setErrorMsg] = (0, import_react13.useState)(null);
|
|
2100
|
+
const dropdownRef = (0, import_react13.useRef)(null);
|
|
2101
|
+
const inputRef = (0, import_react13.useRef)(null);
|
|
2102
|
+
const hasSelectionRef = (0, import_react13.useRef)(false);
|
|
2103
|
+
(0, import_react13.useEffect)(() => {
|
|
1784
2104
|
const handleClickOutside = (e) => {
|
|
1785
2105
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1786
2106
|
setIsOpen(false);
|
|
@@ -1791,7 +2111,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1791
2111
|
document.addEventListener("mousedown", handleClickOutside);
|
|
1792
2112
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1793
2113
|
}, []);
|
|
1794
|
-
(0,
|
|
2114
|
+
(0, import_react13.useEffect)(() => {
|
|
1795
2115
|
if (isOpen && inputRef.current) {
|
|
1796
2116
|
try {
|
|
1797
2117
|
const selectedText = editor?.getSelectedText?.() || "";
|
|
@@ -1802,7 +2122,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1802
2122
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
1803
2123
|
}
|
|
1804
2124
|
}, [isOpen, editor]);
|
|
1805
|
-
const handleSubmit = (0,
|
|
2125
|
+
const handleSubmit = (0, import_react13.useCallback)(
|
|
1806
2126
|
(e) => {
|
|
1807
2127
|
e?.preventDefault();
|
|
1808
2128
|
setErrorMsg(null);
|
|
@@ -1829,15 +2149,15 @@ var LinkButton = ({ editor }) => {
|
|
|
1829
2149
|
},
|
|
1830
2150
|
[editor, linkUrl]
|
|
1831
2151
|
);
|
|
1832
|
-
const handleCancel = (0,
|
|
2152
|
+
const handleCancel = (0, import_react13.useCallback)(() => {
|
|
1833
2153
|
setIsOpen(false);
|
|
1834
2154
|
setLinkUrl("");
|
|
1835
2155
|
setErrorMsg(null);
|
|
1836
2156
|
}, []);
|
|
1837
|
-
const handleMouseDown = (0,
|
|
2157
|
+
const handleMouseDown = (0, import_react13.useCallback)((e) => {
|
|
1838
2158
|
e.preventDefault();
|
|
1839
2159
|
}, []);
|
|
1840
|
-
const handleKeyDown = (0,
|
|
2160
|
+
const handleKeyDown = (0, import_react13.useCallback)(
|
|
1841
2161
|
(e) => {
|
|
1842
2162
|
if (e.key === "Enter") {
|
|
1843
2163
|
handleSubmit();
|
|
@@ -1847,8 +2167,8 @@ var LinkButton = ({ editor }) => {
|
|
|
1847
2167
|
},
|
|
1848
2168
|
[handleSubmit, handleCancel]
|
|
1849
2169
|
);
|
|
1850
|
-
return /* @__PURE__ */ (0,
|
|
1851
|
-
/* @__PURE__ */ (0,
|
|
2170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
|
|
2171
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1852
2172
|
"button",
|
|
1853
2173
|
{
|
|
1854
2174
|
className: "lumir-toolbar-btn",
|
|
@@ -1859,8 +2179,8 @@ var LinkButton = ({ editor }) => {
|
|
|
1859
2179
|
children: Icons.link
|
|
1860
2180
|
}
|
|
1861
2181
|
),
|
|
1862
|
-
isOpen && /* @__PURE__ */ (0,
|
|
1863
|
-
/* @__PURE__ */ (0,
|
|
2182
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "lumir-dropdown-menu lumir-link-menu", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("form", { onSubmit: handleSubmit, className: "lumir-link-form", children: [
|
|
2183
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1864
2184
|
"input",
|
|
1865
2185
|
{
|
|
1866
2186
|
ref: inputRef,
|
|
@@ -1876,7 +2196,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1876
2196
|
onMouseDown: handleMouseDown
|
|
1877
2197
|
}
|
|
1878
2198
|
),
|
|
1879
|
-
errorMsg && /* @__PURE__ */ (0,
|
|
2199
|
+
errorMsg && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1880
2200
|
"div",
|
|
1881
2201
|
{
|
|
1882
2202
|
style: {
|
|
@@ -1888,8 +2208,8 @@ var LinkButton = ({ editor }) => {
|
|
|
1888
2208
|
children: errorMsg
|
|
1889
2209
|
}
|
|
1890
2210
|
),
|
|
1891
|
-
/* @__PURE__ */ (0,
|
|
1892
|
-
/* @__PURE__ */ (0,
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "lumir-link-actions", children: [
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1893
2213
|
"button",
|
|
1894
2214
|
{
|
|
1895
2215
|
type: "button",
|
|
@@ -1899,7 +2219,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1899
2219
|
children: "\uCDE8\uC18C"
|
|
1900
2220
|
}
|
|
1901
2221
|
),
|
|
1902
|
-
/* @__PURE__ */ (0,
|
|
2222
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1903
2223
|
"button",
|
|
1904
2224
|
{
|
|
1905
2225
|
type: "submit",
|
|
@@ -1915,10 +2235,10 @@ var LinkButton = ({ editor }) => {
|
|
|
1915
2235
|
};
|
|
1916
2236
|
|
|
1917
2237
|
// src/components/FloatingMenu/components/TableButton.tsx
|
|
1918
|
-
var
|
|
1919
|
-
var
|
|
2238
|
+
var import_react14 = require("react");
|
|
2239
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1920
2240
|
var TableButton = ({ editor }) => {
|
|
1921
|
-
const handleClick = (0,
|
|
2241
|
+
const handleClick = (0, import_react14.useCallback)(() => {
|
|
1922
2242
|
try {
|
|
1923
2243
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1924
2244
|
if (!block || !editor?.insertBlocks) return;
|
|
@@ -1940,10 +2260,10 @@ var TableButton = ({ editor }) => {
|
|
|
1940
2260
|
console.error("Table insert failed:", err);
|
|
1941
2261
|
}
|
|
1942
2262
|
}, [editor]);
|
|
1943
|
-
const handleMouseDown = (0,
|
|
2263
|
+
const handleMouseDown = (0, import_react14.useCallback)((e) => {
|
|
1944
2264
|
e.preventDefault();
|
|
1945
2265
|
}, []);
|
|
1946
|
-
return /* @__PURE__ */ (0,
|
|
2266
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1947
2267
|
"button",
|
|
1948
2268
|
{
|
|
1949
2269
|
className: "lumir-toolbar-btn",
|
|
@@ -1957,13 +2277,13 @@ var TableButton = ({ editor }) => {
|
|
|
1957
2277
|
};
|
|
1958
2278
|
|
|
1959
2279
|
// src/components/FloatingMenu/components/HTMLImportButton.tsx
|
|
1960
|
-
var
|
|
1961
|
-
var
|
|
2280
|
+
var import_react15 = require("react");
|
|
2281
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1962
2282
|
var HTMLImportButton = ({
|
|
1963
2283
|
editor
|
|
1964
2284
|
}) => {
|
|
1965
|
-
const fileInputRef = (0,
|
|
1966
|
-
const handleFileUpload = (0,
|
|
2285
|
+
const fileInputRef = (0, import_react15.useRef)(null);
|
|
2286
|
+
const handleFileUpload = (0, import_react15.useCallback)(
|
|
1967
2287
|
(e) => {
|
|
1968
2288
|
const file = e.target.files?.[0];
|
|
1969
2289
|
if (!file) return;
|
|
@@ -1999,14 +2319,14 @@ var HTMLImportButton = ({
|
|
|
1999
2319
|
},
|
|
2000
2320
|
[editor]
|
|
2001
2321
|
);
|
|
2002
|
-
const handleClick = (0,
|
|
2322
|
+
const handleClick = (0, import_react15.useCallback)(() => {
|
|
2003
2323
|
fileInputRef.current?.click();
|
|
2004
2324
|
}, []);
|
|
2005
|
-
const handleMouseDown = (0,
|
|
2325
|
+
const handleMouseDown = (0, import_react15.useCallback)((e) => {
|
|
2006
2326
|
e.preventDefault();
|
|
2007
2327
|
}, []);
|
|
2008
|
-
return /* @__PURE__ */ (0,
|
|
2009
|
-
/* @__PURE__ */ (0,
|
|
2328
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2010
2330
|
"input",
|
|
2011
2331
|
{
|
|
2012
2332
|
ref: fileInputRef,
|
|
@@ -2016,7 +2336,7 @@ var HTMLImportButton = ({
|
|
|
2016
2336
|
style: { display: "none" }
|
|
2017
2337
|
}
|
|
2018
2338
|
),
|
|
2019
|
-
/* @__PURE__ */ (0,
|
|
2339
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2020
2340
|
"button",
|
|
2021
2341
|
{
|
|
2022
2342
|
className: "lumir-toolbar-btn",
|
|
@@ -2031,8 +2351,8 @@ var HTMLImportButton = ({
|
|
|
2031
2351
|
};
|
|
2032
2352
|
|
|
2033
2353
|
// src/components/FloatingMenu/components/BlockTypeSelect.tsx
|
|
2034
|
-
var
|
|
2035
|
-
var
|
|
2354
|
+
var import_react16 = require("react");
|
|
2355
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2036
2356
|
var blockTypeCategories = [
|
|
2037
2357
|
{
|
|
2038
2358
|
category: "Headings",
|
|
@@ -2062,8 +2382,8 @@ var blockTypes = blockTypeCategories.flatMap(
|
|
|
2062
2382
|
(cat) => cat.items
|
|
2063
2383
|
);
|
|
2064
2384
|
var BlockTypeSelect = ({ editor }) => {
|
|
2065
|
-
const [isOpen, setIsOpen] = (0,
|
|
2066
|
-
const dropdownRef = (0,
|
|
2385
|
+
const [isOpen, setIsOpen] = (0, import_react16.useState)(false);
|
|
2386
|
+
const dropdownRef = (0, import_react16.useRef)(null);
|
|
2067
2387
|
const getCurrentBlock = () => {
|
|
2068
2388
|
try {
|
|
2069
2389
|
return editor?.getTextCursorPosition()?.block;
|
|
@@ -2075,7 +2395,7 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2075
2395
|
const currentType = currentBlock?.type || "paragraph";
|
|
2076
2396
|
const currentLevel = currentBlock?.props?.level;
|
|
2077
2397
|
const isCurrentToggle = currentType === "heading" && currentBlock?.props?.isToggleable === true;
|
|
2078
|
-
(0,
|
|
2398
|
+
(0, import_react16.useEffect)(() => {
|
|
2079
2399
|
const handleClickOutside = (e) => {
|
|
2080
2400
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
2081
2401
|
setIsOpen(false);
|
|
@@ -2104,7 +2424,7 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2104
2424
|
console.error("Block type change failed:", err);
|
|
2105
2425
|
}
|
|
2106
2426
|
};
|
|
2107
|
-
const handleMouseDown = (0,
|
|
2427
|
+
const handleMouseDown = (0, import_react16.useCallback)((e) => {
|
|
2108
2428
|
e.preventDefault();
|
|
2109
2429
|
}, []);
|
|
2110
2430
|
const getCurrentLabel = () => {
|
|
@@ -2135,8 +2455,8 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2135
2455
|
}
|
|
2136
2456
|
return currentType === bt.type;
|
|
2137
2457
|
};
|
|
2138
|
-
return /* @__PURE__ */ (0,
|
|
2139
|
-
/* @__PURE__ */ (0,
|
|
2458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2140
2460
|
"button",
|
|
2141
2461
|
{
|
|
2142
2462
|
className: "lumir-dropdown-btn lumir-block-type-btn",
|
|
@@ -2144,15 +2464,15 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2144
2464
|
onMouseDown: handleMouseDown,
|
|
2145
2465
|
type: "button",
|
|
2146
2466
|
children: [
|
|
2147
|
-
/* @__PURE__ */ (0,
|
|
2148
|
-
/* @__PURE__ */ (0,
|
|
2467
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "lumir-block-icon", children: BlockTypeIcons[getCurrentIcon()] }),
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "lumir-block-label", children: getCurrentLabel() }),
|
|
2149
2469
|
Icons.expandMore
|
|
2150
2470
|
]
|
|
2151
2471
|
}
|
|
2152
2472
|
),
|
|
2153
|
-
isOpen && /* @__PURE__ */ (0,
|
|
2154
|
-
/* @__PURE__ */ (0,
|
|
2155
|
-
category.items.map((bt) => /* @__PURE__ */ (0,
|
|
2473
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "lumir-dropdown-menu lumir-block-menu", children: blockTypeCategories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "lumir-block-category", children: [
|
|
2474
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "lumir-block-category-title", children: category.category }),
|
|
2475
|
+
category.items.map((bt) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2156
2476
|
"button",
|
|
2157
2477
|
{
|
|
2158
2478
|
className: cn(
|
|
@@ -2162,8 +2482,8 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2162
2482
|
onClick: () => handleTypeChange(bt.type, bt.level, bt.isToggle),
|
|
2163
2483
|
onMouseDown: handleMouseDown,
|
|
2164
2484
|
children: [
|
|
2165
|
-
/* @__PURE__ */ (0,
|
|
2166
|
-
/* @__PURE__ */ (0,
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "lumir-block-icon", children: BlockTypeIcons[bt.icon] }),
|
|
2486
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "lumir-block-item-title", children: bt.label })
|
|
2167
2487
|
]
|
|
2168
2488
|
},
|
|
2169
2489
|
bt.icon
|
|
@@ -2173,7 +2493,7 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2173
2493
|
};
|
|
2174
2494
|
|
|
2175
2495
|
// src/components/FloatingMenu/index.tsx
|
|
2176
|
-
var
|
|
2496
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2177
2497
|
var COMPACT_BREAKPOINT = 700;
|
|
2178
2498
|
var MINIMIZED_BREAKPOINT = 400;
|
|
2179
2499
|
var FloatingMenu = ({
|
|
@@ -2182,12 +2502,12 @@ var FloatingMenu = ({
|
|
|
2182
2502
|
className,
|
|
2183
2503
|
onImageUpload
|
|
2184
2504
|
}) => {
|
|
2185
|
-
const wrapperRef = (0,
|
|
2186
|
-
const [isCompact, setIsCompact] = (0,
|
|
2187
|
-
const [isMinimizable, setIsMinimizable] = (0,
|
|
2188
|
-
const [isMinimized, setIsMinimized] = (0,
|
|
2189
|
-
const [, setSelectionTick] = (0,
|
|
2190
|
-
(0,
|
|
2505
|
+
const wrapperRef = (0, import_react17.useRef)(null);
|
|
2506
|
+
const [isCompact, setIsCompact] = (0, import_react17.useState)(false);
|
|
2507
|
+
const [isMinimizable, setIsMinimizable] = (0, import_react17.useState)(false);
|
|
2508
|
+
const [isMinimized, setIsMinimized] = (0, import_react17.useState)(false);
|
|
2509
|
+
const [, setSelectionTick] = (0, import_react17.useState)(0);
|
|
2510
|
+
(0, import_react17.useEffect)(() => {
|
|
2191
2511
|
if (!editor) return;
|
|
2192
2512
|
let debounceTimer = null;
|
|
2193
2513
|
const DEBOUNCE_DELAY = 150;
|
|
@@ -2211,7 +2531,7 @@ var FloatingMenu = ({
|
|
|
2211
2531
|
unsubscribeContent?.();
|
|
2212
2532
|
};
|
|
2213
2533
|
}, [editor]);
|
|
2214
|
-
(0,
|
|
2534
|
+
(0, import_react17.useEffect)(() => {
|
|
2215
2535
|
const checkWidth = () => {
|
|
2216
2536
|
if (wrapperRef.current) {
|
|
2217
2537
|
const width = wrapperRef.current.offsetWidth;
|
|
@@ -2226,8 +2546,8 @@ var FloatingMenu = ({
|
|
|
2226
2546
|
}
|
|
2227
2547
|
return () => resizeObserver.disconnect();
|
|
2228
2548
|
}, []);
|
|
2229
|
-
const MinimizedLayout = () => /* @__PURE__ */ (0,
|
|
2230
|
-
/* @__PURE__ */ (0,
|
|
2549
|
+
const MinimizedLayout = () => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2231
2551
|
"button",
|
|
2232
2552
|
{
|
|
2233
2553
|
className: "lumir-toolbar-button lumir-toggle-button",
|
|
@@ -2238,117 +2558,117 @@ var FloatingMenu = ({
|
|
|
2238
2558
|
children: isMinimized ? Icons.chevronRight : Icons.chevronLeft
|
|
2239
2559
|
}
|
|
2240
2560
|
),
|
|
2241
|
-
!isMinimized && /* @__PURE__ */ (0,
|
|
2242
|
-
/* @__PURE__ */ (0,
|
|
2243
|
-
/* @__PURE__ */ (0,
|
|
2244
|
-
/* @__PURE__ */ (0,
|
|
2245
|
-
/* @__PURE__ */ (0,
|
|
2246
|
-
/* @__PURE__ */ (0,
|
|
2247
|
-
/* @__PURE__ */ (0,
|
|
2248
|
-
/* @__PURE__ */ (0,
|
|
2249
|
-
/* @__PURE__ */ (0,
|
|
2250
|
-
/* @__PURE__ */ (0,
|
|
2251
|
-
/* @__PURE__ */ (0,
|
|
2561
|
+
!isMinimized && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
2562
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2563
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UndoRedoButtons, { editor }),
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2565
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BlockTypeSelect, { editor }) }),
|
|
2566
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2567
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "bold" }),
|
|
2569
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "italic" }),
|
|
2570
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "underline" }),
|
|
2571
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "strike" })
|
|
2252
2572
|
] }),
|
|
2253
|
-
/* @__PURE__ */ (0,
|
|
2254
|
-
/* @__PURE__ */ (0,
|
|
2255
|
-
/* @__PURE__ */ (0,
|
|
2256
|
-
/* @__PURE__ */ (0,
|
|
2257
|
-
/* @__PURE__ */ (0,
|
|
2573
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2574
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2575
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "left" }),
|
|
2576
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "center" }),
|
|
2577
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "right" })
|
|
2258
2578
|
] }),
|
|
2259
|
-
/* @__PURE__ */ (0,
|
|
2260
|
-
/* @__PURE__ */ (0,
|
|
2261
|
-
/* @__PURE__ */ (0,
|
|
2262
|
-
/* @__PURE__ */ (0,
|
|
2579
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2580
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2581
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ListButton, { editor, type: "bullet" }),
|
|
2582
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ListButton, { editor, type: "numbered" })
|
|
2263
2583
|
] }),
|
|
2264
|
-
/* @__PURE__ */ (0,
|
|
2265
|
-
/* @__PURE__ */ (0,
|
|
2266
|
-
/* @__PURE__ */ (0,
|
|
2267
|
-
/* @__PURE__ */ (0,
|
|
2584
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2585
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2586
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorButton, { editor, type: "text" }),
|
|
2587
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorButton, { editor, type: "background" })
|
|
2268
2588
|
] }),
|
|
2269
|
-
/* @__PURE__ */ (0,
|
|
2270
|
-
/* @__PURE__ */ (0,
|
|
2271
|
-
/* @__PURE__ */ (0,
|
|
2272
|
-
/* @__PURE__ */ (0,
|
|
2273
|
-
/* @__PURE__ */ (0,
|
|
2274
|
-
/* @__PURE__ */ (0,
|
|
2589
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2591
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ImageButton, { editor, onImageUpload }),
|
|
2592
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LinkButton, { editor }),
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TableButton, { editor }),
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(HTMLImportButton, { editor })
|
|
2275
2595
|
] })
|
|
2276
2596
|
] })
|
|
2277
2597
|
] });
|
|
2278
|
-
const SingleRowLayout = () => /* @__PURE__ */ (0,
|
|
2279
|
-
/* @__PURE__ */ (0,
|
|
2280
|
-
/* @__PURE__ */ (0,
|
|
2281
|
-
/* @__PURE__ */ (0,
|
|
2282
|
-
/* @__PURE__ */ (0,
|
|
2283
|
-
/* @__PURE__ */ (0,
|
|
2284
|
-
/* @__PURE__ */ (0,
|
|
2285
|
-
/* @__PURE__ */ (0,
|
|
2286
|
-
/* @__PURE__ */ (0,
|
|
2287
|
-
/* @__PURE__ */ (0,
|
|
2598
|
+
const SingleRowLayout = () => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
2599
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UndoRedoButtons, { editor }),
|
|
2600
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2601
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BlockTypeSelect, { editor }) }),
|
|
2602
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2603
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "bold" }),
|
|
2605
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "italic" }),
|
|
2606
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "underline" }),
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "strike" })
|
|
2288
2608
|
] }),
|
|
2289
|
-
/* @__PURE__ */ (0,
|
|
2290
|
-
/* @__PURE__ */ (0,
|
|
2291
|
-
/* @__PURE__ */ (0,
|
|
2292
|
-
/* @__PURE__ */ (0,
|
|
2293
|
-
/* @__PURE__ */ (0,
|
|
2609
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2610
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "left" }),
|
|
2612
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "center" }),
|
|
2613
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "right" })
|
|
2294
2614
|
] }),
|
|
2295
|
-
/* @__PURE__ */ (0,
|
|
2296
|
-
/* @__PURE__ */ (0,
|
|
2297
|
-
/* @__PURE__ */ (0,
|
|
2298
|
-
/* @__PURE__ */ (0,
|
|
2615
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2616
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2617
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ListButton, { editor, type: "bullet" }),
|
|
2618
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ListButton, { editor, type: "numbered" })
|
|
2299
2619
|
] }),
|
|
2300
|
-
/* @__PURE__ */ (0,
|
|
2301
|
-
/* @__PURE__ */ (0,
|
|
2302
|
-
/* @__PURE__ */ (0,
|
|
2303
|
-
/* @__PURE__ */ (0,
|
|
2620
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorButton, { editor, type: "text" }),
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorButton, { editor, type: "background" })
|
|
2304
2624
|
] }),
|
|
2305
|
-
/* @__PURE__ */ (0,
|
|
2306
|
-
/* @__PURE__ */ (0,
|
|
2307
|
-
/* @__PURE__ */ (0,
|
|
2308
|
-
/* @__PURE__ */ (0,
|
|
2309
|
-
/* @__PURE__ */ (0,
|
|
2310
|
-
/* @__PURE__ */ (0,
|
|
2625
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2626
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2627
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ImageButton, { editor, onImageUpload }),
|
|
2628
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LinkButton, { editor }),
|
|
2629
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TableButton, { editor }),
|
|
2630
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(HTMLImportButton, { editor })
|
|
2311
2631
|
] })
|
|
2312
2632
|
] });
|
|
2313
|
-
const TwoRowLayout = () => /* @__PURE__ */ (0,
|
|
2314
|
-
/* @__PURE__ */ (0,
|
|
2315
|
-
/* @__PURE__ */ (0,
|
|
2316
|
-
/* @__PURE__ */ (0,
|
|
2317
|
-
/* @__PURE__ */ (0,
|
|
2318
|
-
/* @__PURE__ */ (0,
|
|
2319
|
-
/* @__PURE__ */ (0,
|
|
2320
|
-
/* @__PURE__ */ (0,
|
|
2321
|
-
/* @__PURE__ */ (0,
|
|
2633
|
+
const TwoRowLayout = () => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
2634
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-row", children: [
|
|
2635
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(UndoRedoButtons, { editor }),
|
|
2636
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "bold" }),
|
|
2639
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "italic" }),
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "underline" }),
|
|
2641
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TextStyleButton, { editor, style: "strike" })
|
|
2322
2642
|
] }),
|
|
2323
|
-
/* @__PURE__ */ (0,
|
|
2324
|
-
/* @__PURE__ */ (0,
|
|
2325
|
-
/* @__PURE__ */ (0,
|
|
2326
|
-
/* @__PURE__ */ (0,
|
|
2327
|
-
/* @__PURE__ */ (0,
|
|
2643
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2645
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "left" }),
|
|
2646
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "center" }),
|
|
2647
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AlignButton, { editor, alignment: "right" })
|
|
2328
2648
|
] }),
|
|
2329
|
-
/* @__PURE__ */ (0,
|
|
2330
|
-
/* @__PURE__ */ (0,
|
|
2331
|
-
/* @__PURE__ */ (0,
|
|
2332
|
-
/* @__PURE__ */ (0,
|
|
2649
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2650
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2651
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ListButton, { editor, type: "bullet" }),
|
|
2652
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ListButton, { editor, type: "numbered" })
|
|
2333
2653
|
] })
|
|
2334
2654
|
] }),
|
|
2335
|
-
/* @__PURE__ */ (0,
|
|
2336
|
-
/* @__PURE__ */ (0,
|
|
2337
|
-
/* @__PURE__ */ (0,
|
|
2338
|
-
/* @__PURE__ */ (0,
|
|
2339
|
-
/* @__PURE__ */ (0,
|
|
2340
|
-
/* @__PURE__ */ (0,
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-row", children: [
|
|
2656
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BlockTypeSelect, { editor }) }),
|
|
2657
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2658
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2659
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorButton, { editor, type: "text" }),
|
|
2660
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ColorButton, { editor, type: "background" })
|
|
2341
2661
|
] }),
|
|
2342
|
-
/* @__PURE__ */ (0,
|
|
2343
|
-
/* @__PURE__ */ (0,
|
|
2344
|
-
/* @__PURE__ */ (0,
|
|
2345
|
-
/* @__PURE__ */ (0,
|
|
2346
|
-
/* @__PURE__ */ (0,
|
|
2347
|
-
/* @__PURE__ */ (0,
|
|
2662
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToolbarDivider, {}),
|
|
2663
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "lumir-toolbar-group", children: [
|
|
2664
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ImageButton, { editor, onImageUpload }),
|
|
2665
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LinkButton, { editor }),
|
|
2666
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TableButton, { editor }),
|
|
2667
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(HTMLImportButton, { editor })
|
|
2348
2668
|
] })
|
|
2349
2669
|
] })
|
|
2350
2670
|
] });
|
|
2351
|
-
return /* @__PURE__ */ (0,
|
|
2671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2352
2672
|
"div",
|
|
2353
2673
|
{
|
|
2354
2674
|
ref: wrapperRef,
|
|
@@ -2358,7 +2678,7 @@ var FloatingMenu = ({
|
|
|
2358
2678
|
className
|
|
2359
2679
|
),
|
|
2360
2680
|
"data-position": position,
|
|
2361
|
-
children: /* @__PURE__ */ (0,
|
|
2681
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2362
2682
|
"div",
|
|
2363
2683
|
{
|
|
2364
2684
|
className: cn(
|
|
@@ -2367,7 +2687,7 @@ var FloatingMenu = ({
|
|
|
2367
2687
|
isMinimizable && "is-minimizable",
|
|
2368
2688
|
isMinimized && "is-minimized"
|
|
2369
2689
|
),
|
|
2370
|
-
children: isMinimizable ? /* @__PURE__ */ (0,
|
|
2690
|
+
children: isMinimizable ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MinimizedLayout, {}) : isCompact ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TwoRowLayout, {}) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SingleRowLayout, {})
|
|
2371
2691
|
}
|
|
2372
2692
|
)
|
|
2373
2693
|
}
|
|
@@ -2438,15 +2758,14 @@ var LumirEditorError = class _LumirEditorError extends Error {
|
|
|
2438
2758
|
}
|
|
2439
2759
|
/**
|
|
2440
2760
|
* 잘못된 파일 형식 에러 생성
|
|
2761
|
+
* @param allowVideoUpload true이면 "image and video" 메시지 사용
|
|
2441
2762
|
*/
|
|
2442
|
-
static invalidFileType(fileName) {
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
}
|
|
2449
|
-
);
|
|
2763
|
+
static invalidFileType(fileName, allowVideoUpload) {
|
|
2764
|
+
const message = allowVideoUpload === true ? `Invalid file type: ${fileName}. Only image and video files are allowed.` : `Invalid file type: ${fileName}. Only image files are allowed.`;
|
|
2765
|
+
return new _LumirEditorError(message, {
|
|
2766
|
+
code: "INVALID_FILE_TYPE",
|
|
2767
|
+
context: { fileName }
|
|
2768
|
+
});
|
|
2450
2769
|
}
|
|
2451
2770
|
/**
|
|
2452
2771
|
* S3 설정 에러 생성
|
|
@@ -2469,10 +2788,38 @@ var LumirEditorError = class _LumirEditorError extends Error {
|
|
|
2469
2788
|
|
|
2470
2789
|
// src/constants/limits.ts
|
|
2471
2790
|
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
2791
|
+
var MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;
|
|
2472
2792
|
var BLOCKED_EXTENSIONS = [".svg", ".svgz"];
|
|
2793
|
+
var ALLOWED_VIDEO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
2794
|
+
"video/mp4",
|
|
2795
|
+
"video/webm",
|
|
2796
|
+
"video/ogg",
|
|
2797
|
+
"video/quicktime"
|
|
2798
|
+
// .mov
|
|
2799
|
+
]);
|
|
2800
|
+
var ALLOWED_VIDEO_EXTENSIONS = [
|
|
2801
|
+
".mp4",
|
|
2802
|
+
".webm",
|
|
2803
|
+
".ogg",
|
|
2804
|
+
".mov"
|
|
2805
|
+
];
|
|
2473
2806
|
|
|
2474
2807
|
// src/components/LumirEditor.tsx
|
|
2475
|
-
var
|
|
2808
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2809
|
+
var DEBUG_LOG = (loc, msg, data) => {
|
|
2810
|
+
fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
2811
|
+
method: "POST",
|
|
2812
|
+
headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "b73262" },
|
|
2813
|
+
body: JSON.stringify({
|
|
2814
|
+
sessionId: "b73262",
|
|
2815
|
+
location: loc,
|
|
2816
|
+
message: msg,
|
|
2817
|
+
data,
|
|
2818
|
+
timestamp: Date.now()
|
|
2819
|
+
})
|
|
2820
|
+
}).catch(() => {
|
|
2821
|
+
});
|
|
2822
|
+
};
|
|
2476
2823
|
var ContentUtils = class {
|
|
2477
2824
|
/**
|
|
2478
2825
|
* JSON 문자열의 유효성을 검증합니다
|
|
@@ -2601,6 +2948,25 @@ var isImageFile = (file) => {
|
|
|
2601
2948
|
}
|
|
2602
2949
|
return file.type?.startsWith("image/") || !file.type && /\.(png|jpe?g|gif|webp|bmp)$/i.test(fileName);
|
|
2603
2950
|
};
|
|
2951
|
+
var isVideoFile = (file) => {
|
|
2952
|
+
const sizeOk = file.size > 0 && file.size <= MAX_VIDEO_FILE_SIZE;
|
|
2953
|
+
const fileName = file.name?.toLowerCase() || "";
|
|
2954
|
+
const mimeMatch = ALLOWED_VIDEO_MIME_TYPES.has(file.type);
|
|
2955
|
+
const videoPrefix = typeof file.type === "string" && file.type.startsWith("video/");
|
|
2956
|
+
const extMatch = !file.type && ALLOWED_VIDEO_EXTENSIONS.some((ext) => fileName.endsWith(ext));
|
|
2957
|
+
const result = sizeOk && (mimeMatch || videoPrefix || extMatch);
|
|
2958
|
+
DEBUG_LOG("isVideoFile:check", "result", {
|
|
2959
|
+
fileName: file.name,
|
|
2960
|
+
fileType: file.type,
|
|
2961
|
+
fileSize: file.size,
|
|
2962
|
+
sizeOk,
|
|
2963
|
+
mimeMatch,
|
|
2964
|
+
videoPrefix,
|
|
2965
|
+
extMatch,
|
|
2966
|
+
result
|
|
2967
|
+
});
|
|
2968
|
+
return result;
|
|
2969
|
+
};
|
|
2604
2970
|
var isHtmlFile = (file) => {
|
|
2605
2971
|
return file.size > 0 && (file.type === "text/html" || file.name?.toLowerCase().endsWith(".html") || file.name?.toLowerCase().endsWith(".htm"));
|
|
2606
2972
|
};
|
|
@@ -2614,15 +2980,17 @@ var escapeHtml = (str) => {
|
|
|
2614
2980
|
};
|
|
2615
2981
|
return str.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
|
|
2616
2982
|
};
|
|
2617
|
-
var
|
|
2983
|
+
var extractMediaUrls = (blocks) => {
|
|
2618
2984
|
const urls = /* @__PURE__ */ new Set();
|
|
2619
2985
|
const traverse = (blockList) => {
|
|
2620
2986
|
for (const block of blockList) {
|
|
2621
2987
|
if (block.type === "image" && block.props?.url) {
|
|
2622
2988
|
const url = block.props.url;
|
|
2623
|
-
if (typeof url === "string" && url.trim())
|
|
2624
|
-
|
|
2625
|
-
|
|
2989
|
+
if (typeof url === "string" && url.trim()) urls.add(url);
|
|
2990
|
+
}
|
|
2991
|
+
if (block.type === "video" && block.props?.url) {
|
|
2992
|
+
const url = block.props.url;
|
|
2993
|
+
if (typeof url === "string" && url.trim()) urls.add(url);
|
|
2626
2994
|
}
|
|
2627
2995
|
if (block.children && Array.isArray(block.children)) {
|
|
2628
2996
|
traverse(block.children);
|
|
@@ -2632,12 +3000,10 @@ var extractImageUrls = (blocks) => {
|
|
|
2632
3000
|
traverse(blocks);
|
|
2633
3001
|
return urls;
|
|
2634
3002
|
};
|
|
2635
|
-
var
|
|
3003
|
+
var findDeletedMediaUrls = (previousUrls, currentUrls) => {
|
|
2636
3004
|
const deleted = [];
|
|
2637
3005
|
previousUrls.forEach((url) => {
|
|
2638
|
-
if (!currentUrls.has(url))
|
|
2639
|
-
deleted.push(url);
|
|
2640
|
-
}
|
|
3006
|
+
if (!currentUrls.has(url)) deleted.push(url);
|
|
2641
3007
|
});
|
|
2642
3008
|
return deleted;
|
|
2643
3009
|
};
|
|
@@ -2661,9 +3027,9 @@ var findBlockWithLink = (blocks, targetUrl) => {
|
|
|
2661
3027
|
return null;
|
|
2662
3028
|
};
|
|
2663
3029
|
var ConvertToPreviewButton = ({ url }) => {
|
|
2664
|
-
const editor = (0,
|
|
2665
|
-
const Components = (0,
|
|
2666
|
-
return /* @__PURE__ */ (0,
|
|
3030
|
+
const editor = (0, import_react19.useBlockNoteEditor)();
|
|
3031
|
+
const Components = (0, import_react19.useComponentsContext)();
|
|
3032
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
2667
3033
|
Components.LinkToolbar.Button,
|
|
2668
3034
|
{
|
|
2669
3035
|
className: "bn-button",
|
|
@@ -2682,29 +3048,29 @@ var ConvertToPreviewButton = ({ url }) => {
|
|
|
2682
3048
|
console.error("Convert to link preview failed:", err);
|
|
2683
3049
|
}
|
|
2684
3050
|
},
|
|
2685
|
-
icon: /* @__PURE__ */ (0,
|
|
2686
|
-
/* @__PURE__ */ (0,
|
|
2687
|
-
/* @__PURE__ */ (0,
|
|
2688
|
-
/* @__PURE__ */ (0,
|
|
3051
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
3052
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("rect", { x: "1", y: "3", width: "14", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.5", fill: "none" }),
|
|
3053
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("line", { x1: "1", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
3054
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("circle", { cx: "5", cy: "6.5", r: "1.5", stroke: "currentColor", strokeWidth: "1", fill: "none" })
|
|
2689
3055
|
] })
|
|
2690
3056
|
}
|
|
2691
3057
|
);
|
|
2692
3058
|
};
|
|
2693
3059
|
var CustomLinkToolbar = (props) => {
|
|
2694
|
-
const editor = (0,
|
|
2695
|
-
const Components = (0,
|
|
3060
|
+
const editor = (0, import_react19.useBlockNoteEditor)();
|
|
3061
|
+
const Components = (0, import_react19.useComponentsContext)();
|
|
2696
3062
|
const hasLinkPreview = !!editor?._linkPreviewApiEndpoint;
|
|
2697
|
-
return /* @__PURE__ */ (0,
|
|
3063
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
2698
3064
|
Components.LinkToolbar.Root,
|
|
2699
3065
|
{
|
|
2700
3066
|
className: "bn-toolbar bn-link-toolbar",
|
|
2701
3067
|
onMouseEnter: props.stopHideTimer,
|
|
2702
3068
|
onMouseLeave: props.startHideTimer,
|
|
2703
3069
|
children: [
|
|
2704
|
-
/* @__PURE__ */ (0,
|
|
2705
|
-
/* @__PURE__ */ (0,
|
|
2706
|
-
/* @__PURE__ */ (0,
|
|
2707
|
-
hasLinkPreview && /* @__PURE__ */ (0,
|
|
3070
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.EditLinkButton, { url: props.url, text: props.text, editLink: props.editLink }),
|
|
3071
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.OpenLinkButton, { url: props.url }),
|
|
3072
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.DeleteLinkButton, { deleteLink: props.deleteLink }),
|
|
3073
|
+
hasLinkPreview && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ConvertToPreviewButton, { url: props.url })
|
|
2708
3074
|
]
|
|
2709
3075
|
}
|
|
2710
3076
|
);
|
|
@@ -2746,9 +3112,13 @@ function LumirEditor({
|
|
|
2746
3112
|
onError,
|
|
2747
3113
|
onImageDelete
|
|
2748
3114
|
}) {
|
|
2749
|
-
const [isUploading, setIsUploading] = (0,
|
|
2750
|
-
const [
|
|
2751
|
-
const
|
|
3115
|
+
const [isUploading, setIsUploading] = (0, import_react18.useState)(false);
|
|
3116
|
+
const [uploadProgress, setUploadProgress] = (0, import_react18.useState)(null);
|
|
3117
|
+
const [errorMessage, setErrorMessage] = (0, import_react18.useState)(null);
|
|
3118
|
+
const floatingMenuFileInputRef = (0, import_react18.useRef)(null);
|
|
3119
|
+
const floatingMenuBlockRef = (0, import_react18.useRef)(null);
|
|
3120
|
+
const floatingMenuUploadStartTimeRef = (0, import_react18.useRef)(0);
|
|
3121
|
+
const handleError = (0, import_react18.useCallback)(
|
|
2752
3122
|
(error) => {
|
|
2753
3123
|
onError?.(error);
|
|
2754
3124
|
setErrorMessage(error.getUserMessage());
|
|
@@ -2756,10 +3126,10 @@ function LumirEditor({
|
|
|
2756
3126
|
},
|
|
2757
3127
|
[onError]
|
|
2758
3128
|
);
|
|
2759
|
-
const validatedContent = (0,
|
|
3129
|
+
const validatedContent = (0, import_react18.useMemo)(() => {
|
|
2760
3130
|
return ContentUtils.validateContent(initialContent, initialEmptyBlocks);
|
|
2761
3131
|
}, [initialContent, initialEmptyBlocks]);
|
|
2762
|
-
const tableConfig = (0,
|
|
3132
|
+
const tableConfig = (0, import_react18.useMemo)(() => {
|
|
2763
3133
|
return EditorConfig.getDefaultTableConfig(tables);
|
|
2764
3134
|
}, [
|
|
2765
3135
|
tables?.splitCells,
|
|
@@ -2767,10 +3137,10 @@ function LumirEditor({
|
|
|
2767
3137
|
tables?.cellTextColor,
|
|
2768
3138
|
tables?.headers
|
|
2769
3139
|
]);
|
|
2770
|
-
const headingConfig = (0,
|
|
3140
|
+
const headingConfig = (0, import_react18.useMemo)(() => {
|
|
2771
3141
|
return EditorConfig.getDefaultHeadingConfig(heading);
|
|
2772
3142
|
}, [heading?.levels?.join(",") ?? ""]);
|
|
2773
|
-
const disabledExtensions = (0,
|
|
3143
|
+
const disabledExtensions = (0, import_react18.useMemo)(() => {
|
|
2774
3144
|
return EditorConfig.getDisabledExtensions(
|
|
2775
3145
|
disableExtensions,
|
|
2776
3146
|
allowVideoUpload,
|
|
@@ -2778,11 +3148,18 @@ function LumirEditor({
|
|
|
2778
3148
|
allowFileUpload
|
|
2779
3149
|
);
|
|
2780
3150
|
}, [disableExtensions, allowVideoUpload, allowAudioUpload, allowFileUpload]);
|
|
2781
|
-
|
|
2782
|
-
|
|
3151
|
+
(0, import_react18.useEffect)(() => {
|
|
3152
|
+
DEBUG_LOG("LumirEditor:init:disabledExtensions", "snapshot", {
|
|
3153
|
+
allowVideoUpload,
|
|
3154
|
+
hasVideoInDisabled: disabledExtensions.includes("video"),
|
|
3155
|
+
disabledList: disabledExtensions.slice(0, 15)
|
|
3156
|
+
});
|
|
3157
|
+
}, [allowVideoUpload, disabledExtensions]);
|
|
3158
|
+
const fileNameTransformRef = (0, import_react18.useRef)(s3Upload?.fileNameTransform);
|
|
3159
|
+
(0, import_react18.useEffect)(() => {
|
|
2783
3160
|
fileNameTransformRef.current = s3Upload?.fileNameTransform;
|
|
2784
3161
|
}, [s3Upload?.fileNameTransform]);
|
|
2785
|
-
const memoizedS3Upload = (0,
|
|
3162
|
+
const memoizedS3Upload = (0, import_react18.useMemo)(() => {
|
|
2786
3163
|
if (!s3Upload) return void 0;
|
|
2787
3164
|
return {
|
|
2788
3165
|
apiEndpoint: s3Upload.apiEndpoint,
|
|
@@ -2790,6 +3167,12 @@ function LumirEditor({
|
|
|
2790
3167
|
path: s3Upload.path,
|
|
2791
3168
|
appendUUID: s3Upload.appendUUID,
|
|
2792
3169
|
preserveExtension: s3Upload.preserveExtension,
|
|
3170
|
+
uploadTimeoutMs: s3Upload.uploadTimeoutMs,
|
|
3171
|
+
maxRetries: s3Upload.maxRetries,
|
|
3172
|
+
onProgress: (percent) => {
|
|
3173
|
+
setUploadProgress(percent);
|
|
3174
|
+
s3Upload.onProgress?.(percent);
|
|
3175
|
+
},
|
|
2793
3176
|
// 최신 콜백을 항상 사용하도록 ref를 통해 접근
|
|
2794
3177
|
fileNameTransform: (originalName, file) => {
|
|
2795
3178
|
return fileNameTransformRef.current ? fileNameTransformRef.current(originalName, file) : originalName;
|
|
@@ -2800,9 +3183,12 @@ function LumirEditor({
|
|
|
2800
3183
|
s3Upload?.env,
|
|
2801
3184
|
s3Upload?.path,
|
|
2802
3185
|
s3Upload?.appendUUID,
|
|
2803
|
-
s3Upload?.preserveExtension
|
|
3186
|
+
s3Upload?.preserveExtension,
|
|
3187
|
+
s3Upload?.uploadTimeoutMs,
|
|
3188
|
+
s3Upload?.maxRetries,
|
|
3189
|
+
s3Upload?.onProgress
|
|
2804
3190
|
]);
|
|
2805
|
-
const editor = (0,
|
|
3191
|
+
const editor = (0, import_react19.useCreateBlockNote)(
|
|
2806
3192
|
{
|
|
2807
3193
|
// HTML 미리보기 블록이 포함된 커스텀 스키마 사용
|
|
2808
3194
|
schema,
|
|
@@ -2818,18 +3204,44 @@ function LumirEditor({
|
|
|
2818
3204
|
tabBehavior,
|
|
2819
3205
|
trailingBlock,
|
|
2820
3206
|
uploadFile: async (file) => {
|
|
2821
|
-
|
|
2822
|
-
|
|
3207
|
+
const allowedImage = isImageFile(file);
|
|
3208
|
+
const allowedVideo = allowVideoUpload && isVideoFile(file);
|
|
3209
|
+
DEBUG_LOG("uploadFile:step1:entry", "editor uploadFile callback invoked", {
|
|
3210
|
+
fileName: file.name,
|
|
3211
|
+
fileType: file.type,
|
|
3212
|
+
fileSize: file.size,
|
|
3213
|
+
allowVideoUpload,
|
|
3214
|
+
allowedImage,
|
|
3215
|
+
allowedVideo
|
|
3216
|
+
});
|
|
3217
|
+
if (!allowedImage && !allowedVideo) {
|
|
3218
|
+
const error = LumirEditorError.invalidFileType(
|
|
3219
|
+
file.name,
|
|
3220
|
+
allowVideoUpload
|
|
3221
|
+
);
|
|
2823
3222
|
handleError(error);
|
|
2824
3223
|
throw error;
|
|
2825
3224
|
}
|
|
2826
3225
|
try {
|
|
2827
|
-
|
|
3226
|
+
setUploadProgress(0);
|
|
3227
|
+
let fileUrl;
|
|
3228
|
+
const branch = uploadFile ? "custom" : memoizedS3Upload?.apiEndpoint ? "s3" : "none";
|
|
3229
|
+
DEBUG_LOG("uploadFile:step2:branch", "upload path", {
|
|
3230
|
+
branch,
|
|
3231
|
+
hasCustomUploadFile: !!uploadFile,
|
|
3232
|
+
hasS3ApiEndpoint: !!memoizedS3Upload?.apiEndpoint
|
|
3233
|
+
});
|
|
2828
3234
|
if (uploadFile) {
|
|
2829
|
-
|
|
3235
|
+
const t0 = Date.now();
|
|
3236
|
+
DEBUG_LOG("uploadFile:step3a:custom", "calling custom uploadFile", { fileName: file.name });
|
|
3237
|
+
fileUrl = await uploadFile(file);
|
|
3238
|
+
DEBUG_LOG("uploadFile:step3a:done", "custom uploadFile returned", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });
|
|
2830
3239
|
} else if (memoizedS3Upload?.apiEndpoint) {
|
|
3240
|
+
const t0 = Date.now();
|
|
3241
|
+
DEBUG_LOG("uploadFile:step3b:s3", "calling S3 uploader", { fileName: file.name });
|
|
2831
3242
|
const s3Uploader = createS3Uploader(memoizedS3Upload);
|
|
2832
|
-
|
|
3243
|
+
fileUrl = await s3Uploader(file);
|
|
3244
|
+
DEBUG_LOG("uploadFile:step3b:done", "S3 uploader returned", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });
|
|
2833
3245
|
} else {
|
|
2834
3246
|
const error = LumirEditorError.s3ConfigError(
|
|
2835
3247
|
"No upload method available. Please provide uploadFile or s3Upload configuration."
|
|
@@ -2837,8 +3249,16 @@ function LumirEditor({
|
|
|
2837
3249
|
handleError(error);
|
|
2838
3250
|
throw error;
|
|
2839
3251
|
}
|
|
2840
|
-
|
|
3252
|
+
DEBUG_LOG("uploadFile:step4:success", "returning URL", {
|
|
3253
|
+
fileName: file.name,
|
|
3254
|
+
urlPrefix: fileUrl.slice(0, 80)
|
|
3255
|
+
});
|
|
3256
|
+
return fileUrl;
|
|
2841
3257
|
} catch (error) {
|
|
3258
|
+
DEBUG_LOG("uploadFile:step5:catch", "uploadFile threw", {
|
|
3259
|
+
fileName: file.name,
|
|
3260
|
+
errorMessage: error instanceof Error ? error.message : String(error)
|
|
3261
|
+
});
|
|
2842
3262
|
if (error instanceof LumirEditorError) {
|
|
2843
3263
|
throw error;
|
|
2844
3264
|
}
|
|
@@ -2848,6 +3268,8 @@ function LumirEditor({
|
|
|
2848
3268
|
);
|
|
2849
3269
|
handleError(lumirError);
|
|
2850
3270
|
throw lumirError;
|
|
3271
|
+
} finally {
|
|
3272
|
+
setUploadProgress(null);
|
|
2851
3273
|
}
|
|
2852
3274
|
},
|
|
2853
3275
|
pasteHandler: (ctx) => {
|
|
@@ -2876,7 +3298,15 @@ function LumirEditor({
|
|
|
2876
3298
|
}
|
|
2877
3299
|
const fileList = event?.clipboardData?.files ?? null;
|
|
2878
3300
|
const files = fileList ? Array.from(fileList) : [];
|
|
2879
|
-
const acceptedFiles = files.filter(
|
|
3301
|
+
const acceptedFiles = files.filter(
|
|
3302
|
+
(f) => isImageFile(f) || allowVideoUpload && isVideoFile(f)
|
|
3303
|
+
);
|
|
3304
|
+
DEBUG_LOG("paste:step1:files", "paste clipboard files", {
|
|
3305
|
+
filesCount: files.length,
|
|
3306
|
+
acceptedCount: acceptedFiles.length,
|
|
3307
|
+
fileNames: files.map((f) => f.name),
|
|
3308
|
+
acceptedNames: acceptedFiles.map((f) => f.name)
|
|
3309
|
+
});
|
|
2880
3310
|
if (files.length > 0 && acceptedFiles.length === 0) {
|
|
2881
3311
|
event.preventDefault();
|
|
2882
3312
|
return true;
|
|
@@ -2890,13 +3320,26 @@ function LumirEditor({
|
|
|
2890
3320
|
try {
|
|
2891
3321
|
for (const file of acceptedFiles) {
|
|
2892
3322
|
try {
|
|
3323
|
+
DEBUG_LOG("paste:step2:upload", "calling uploadFile for paste", {
|
|
3324
|
+
fileName: file.name,
|
|
3325
|
+
fileType: file.type
|
|
3326
|
+
});
|
|
2893
3327
|
const url = await editor2.uploadFile(file);
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
3328
|
+
if (isImageFile(file)) {
|
|
3329
|
+
editor2.pasteHTML(
|
|
3330
|
+
`<img src="${escapeHtml(url)}" alt="image" />`
|
|
3331
|
+
);
|
|
3332
|
+
} else if (isVideoFile(file)) {
|
|
3333
|
+
const currentBlock = editor2.getTextCursorPosition().block;
|
|
3334
|
+
editor2.insertBlocks(
|
|
3335
|
+
[{ type: "video", props: { url } }],
|
|
3336
|
+
currentBlock,
|
|
3337
|
+
"after"
|
|
3338
|
+
);
|
|
3339
|
+
}
|
|
2897
3340
|
} catch (err) {
|
|
2898
3341
|
console.warn(
|
|
2899
|
-
"
|
|
3342
|
+
"Upload failed, skipped:",
|
|
2900
3343
|
file.name || "",
|
|
2901
3344
|
err
|
|
2902
3345
|
);
|
|
@@ -2919,6 +3362,7 @@ function LumirEditor({
|
|
|
2919
3362
|
trailingBlock,
|
|
2920
3363
|
uploadFile,
|
|
2921
3364
|
memoizedS3Upload,
|
|
3365
|
+
allowVideoUpload,
|
|
2922
3366
|
linkPreview?.apiEndpoint,
|
|
2923
3367
|
placeholder
|
|
2924
3368
|
]
|
|
@@ -2926,12 +3370,12 @@ function LumirEditor({
|
|
|
2926
3370
|
if (editor && linkPreview?.apiEndpoint) {
|
|
2927
3371
|
editor._linkPreviewApiEndpoint = linkPreview.apiEndpoint;
|
|
2928
3372
|
}
|
|
2929
|
-
(0,
|
|
3373
|
+
(0, import_react18.useEffect)(() => {
|
|
2930
3374
|
if (editor) {
|
|
2931
3375
|
editor.isEditable = editable;
|
|
2932
3376
|
}
|
|
2933
3377
|
}, [editor, editable]);
|
|
2934
|
-
(0,
|
|
3378
|
+
(0, import_react18.useEffect)(() => {
|
|
2935
3379
|
if (!editor || !onContentChange) return;
|
|
2936
3380
|
const handleContentChange = () => {
|
|
2937
3381
|
const blocks = editor.topLevelBlocks;
|
|
@@ -2939,27 +3383,27 @@ function LumirEditor({
|
|
|
2939
3383
|
};
|
|
2940
3384
|
return editor.onEditorContentChange(handleContentChange);
|
|
2941
3385
|
}, [editor, onContentChange]);
|
|
2942
|
-
const
|
|
2943
|
-
(0,
|
|
3386
|
+
const previousMediaUrlsRef = (0, import_react18.useRef)(/* @__PURE__ */ new Set());
|
|
3387
|
+
(0, import_react18.useEffect)(() => {
|
|
2944
3388
|
if (!editor) return;
|
|
2945
3389
|
const initialBlocks = editor.topLevelBlocks;
|
|
2946
|
-
|
|
3390
|
+
previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);
|
|
2947
3391
|
}, [editor]);
|
|
2948
|
-
(0,
|
|
3392
|
+
(0, import_react18.useEffect)(() => {
|
|
2949
3393
|
if (!editor || !onImageDelete) return;
|
|
2950
|
-
const
|
|
3394
|
+
const handleMediaDeleteCheck = () => {
|
|
2951
3395
|
const currentBlocks = editor.topLevelBlocks;
|
|
2952
|
-
const currentUrls =
|
|
2953
|
-
const previousUrls =
|
|
2954
|
-
const deletedUrls =
|
|
3396
|
+
const currentUrls = extractMediaUrls(currentBlocks);
|
|
3397
|
+
const previousUrls = previousMediaUrlsRef.current;
|
|
3398
|
+
const deletedUrls = findDeletedMediaUrls(previousUrls, currentUrls);
|
|
2955
3399
|
deletedUrls.forEach((url) => {
|
|
2956
3400
|
onImageDelete(url);
|
|
2957
3401
|
});
|
|
2958
|
-
|
|
3402
|
+
previousMediaUrlsRef.current = currentUrls;
|
|
2959
3403
|
};
|
|
2960
|
-
return editor.onEditorContentChange(
|
|
3404
|
+
return editor.onEditorContentChange(handleMediaDeleteCheck);
|
|
2961
3405
|
}, [editor, onImageDelete]);
|
|
2962
|
-
(0,
|
|
3406
|
+
(0, import_react18.useEffect)(() => {
|
|
2963
3407
|
const el = editor?.domElement;
|
|
2964
3408
|
if (!el) return;
|
|
2965
3409
|
const handleDragOver = (e) => {
|
|
@@ -2979,11 +3423,31 @@ function LumirEditor({
|
|
|
2979
3423
|
const items = Array.from(e.dataTransfer.items ?? []);
|
|
2980
3424
|
const files = items.filter((it) => it.kind === "file").map((it) => it.getAsFile()).filter((f) => !!f);
|
|
2981
3425
|
const imageFiles = files.filter(isImageFile);
|
|
3426
|
+
const videoFiles = allowVideoUpload ? files.filter(isVideoFile) : [];
|
|
2982
3427
|
const htmlFiles = files.filter(isHtmlFile);
|
|
2983
|
-
|
|
3428
|
+
DEBUG_LOG("drop:step1:files", "drop received", {
|
|
3429
|
+
filesCount: files.length,
|
|
3430
|
+
imageCount: imageFiles.length,
|
|
3431
|
+
videoCount: videoFiles.length,
|
|
3432
|
+
htmlCount: htmlFiles.length,
|
|
3433
|
+
allowVideoUpload,
|
|
3434
|
+
firstFile: files[0] ? {
|
|
3435
|
+
name: files[0].name,
|
|
3436
|
+
type: files[0].type,
|
|
3437
|
+
size: files[0].size,
|
|
3438
|
+
isImage: isImageFile(files[0]),
|
|
3439
|
+
isVideo: isVideoFile(files[0])
|
|
3440
|
+
} : null
|
|
3441
|
+
});
|
|
3442
|
+
if (imageFiles.length === 0 && htmlFiles.length === 0 && videoFiles.length === 0)
|
|
3443
|
+
return;
|
|
2984
3444
|
(async () => {
|
|
2985
3445
|
setIsUploading(true);
|
|
2986
3446
|
try {
|
|
3447
|
+
DEBUG_LOG("drop:step2:async", "drop async started", {
|
|
3448
|
+
imageCount: imageFiles.length,
|
|
3449
|
+
videoCount: videoFiles.length
|
|
3450
|
+
});
|
|
2987
3451
|
for (const file of imageFiles) {
|
|
2988
3452
|
try {
|
|
2989
3453
|
if (editor?.uploadFile) {
|
|
@@ -3002,6 +3466,34 @@ function LumirEditor({
|
|
|
3002
3466
|
);
|
|
3003
3467
|
}
|
|
3004
3468
|
}
|
|
3469
|
+
DEBUG_LOG("drop:step3:videoLoop", "video loop start", {
|
|
3470
|
+
videoCount: videoFiles.length,
|
|
3471
|
+
names: videoFiles.map((f) => f.name)
|
|
3472
|
+
});
|
|
3473
|
+
for (const file of videoFiles) {
|
|
3474
|
+
try {
|
|
3475
|
+
if (editor?.uploadFile) {
|
|
3476
|
+
DEBUG_LOG("drop:step4:videoUpload", "calling uploadFile for video", {
|
|
3477
|
+
fileName: file.name
|
|
3478
|
+
});
|
|
3479
|
+
const url = await editor.uploadFile(file);
|
|
3480
|
+
if (url && typeof url === "string") {
|
|
3481
|
+
const currentBlock = editor.getTextCursorPosition().block;
|
|
3482
|
+
editor.insertBlocks(
|
|
3483
|
+
[{ type: "video", props: { url } }],
|
|
3484
|
+
currentBlock,
|
|
3485
|
+
"after"
|
|
3486
|
+
);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
} catch (err) {
|
|
3490
|
+
console.warn(
|
|
3491
|
+
"Video upload failed, skipped:",
|
|
3492
|
+
file.name || "",
|
|
3493
|
+
err
|
|
3494
|
+
);
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3005
3497
|
for (const file of htmlFiles) {
|
|
3006
3498
|
try {
|
|
3007
3499
|
const htmlContent = await file.text();
|
|
@@ -3041,56 +3533,124 @@ function LumirEditor({
|
|
|
3041
3533
|
});
|
|
3042
3534
|
el.removeEventListener("drop", handleDrop, { capture: true });
|
|
3043
3535
|
};
|
|
3044
|
-
}, [editor]);
|
|
3045
|
-
const computedSideMenu = (0,
|
|
3536
|
+
}, [editor, allowVideoUpload]);
|
|
3537
|
+
const computedSideMenu = (0, import_react18.useMemo)(() => {
|
|
3046
3538
|
return sideMenuAddButton ? sideMenu : false;
|
|
3047
3539
|
}, [sideMenuAddButton, sideMenu]);
|
|
3048
|
-
const DragHandleOnlySideMenu = (0,
|
|
3049
|
-
return (props) => /* @__PURE__ */ (0,
|
|
3540
|
+
const DragHandleOnlySideMenu = (0, import_react18.useMemo)(() => {
|
|
3541
|
+
return (props) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.SideMenu, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.DragHandleButton, { ...props }) });
|
|
3050
3542
|
}, []);
|
|
3051
|
-
return /* @__PURE__ */ (0,
|
|
3543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3052
3544
|
"div",
|
|
3053
3545
|
{
|
|
3054
3546
|
className: cn("lumirEditor", className),
|
|
3055
3547
|
style: { position: "relative", display: "flex", flexDirection: "column" },
|
|
3056
3548
|
children: [
|
|
3057
|
-
floatingMenu && editor && /* @__PURE__ */ (0,
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3549
|
+
floatingMenu && editor && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
3550
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3551
|
+
"input",
|
|
3552
|
+
{
|
|
3553
|
+
ref: floatingMenuFileInputRef,
|
|
3554
|
+
type: "file",
|
|
3555
|
+
accept: allowVideoUpload ? "image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov" : "image/*",
|
|
3556
|
+
style: {
|
|
3557
|
+
position: "absolute",
|
|
3558
|
+
left: "-9999px",
|
|
3559
|
+
opacity: 0,
|
|
3560
|
+
pointerEvents: "none"
|
|
3561
|
+
},
|
|
3562
|
+
onChange: async (e) => {
|
|
3563
|
+
const inputEl = e.target;
|
|
3564
|
+
const file = inputEl.files?.[0];
|
|
3565
|
+
DEBUG_LOG("FloatingMenu:step3:onchange", "file input onchange fired", {
|
|
3566
|
+
hasFile: !!file,
|
|
3567
|
+
fileName: file?.name,
|
|
3568
|
+
fileType: file?.type,
|
|
3569
|
+
fileSize: file?.size,
|
|
3570
|
+
hasUploadFile: !!editor?.uploadFile
|
|
3571
|
+
});
|
|
3572
|
+
const blockToInsertAfter = floatingMenuBlockRef.current;
|
|
3573
|
+
if (file && editor.uploadFile && blockToInsertAfter) {
|
|
3574
|
+
const allowedImage = isImageFile(file);
|
|
3575
|
+
const allowedVideo = allowVideoUpload && isVideoFile(file);
|
|
3576
|
+
DEBUG_LOG("FloatingMenu:step4:fileCheck", "allowed check", {
|
|
3577
|
+
fileName: file.name,
|
|
3578
|
+
allowedImage,
|
|
3579
|
+
allowedVideo
|
|
3580
|
+
});
|
|
3581
|
+
if (allowedImage || allowedVideo) {
|
|
3582
|
+
try {
|
|
3583
|
+
setIsUploading(true);
|
|
3584
|
+
floatingMenuUploadStartTimeRef.current = Date.now();
|
|
3585
|
+
DEBUG_LOG("FloatingMenu:step5:uploadStart", "calling editor.uploadFile", {
|
|
3586
|
+
fileName: file.name
|
|
3587
|
+
});
|
|
3588
|
+
const url = await editor.uploadFile(file);
|
|
3589
|
+
const blockType = allowedVideo ? "video" : "image";
|
|
3590
|
+
const elapsedMs = Date.now() - floatingMenuUploadStartTimeRef.current;
|
|
3591
|
+
DEBUG_LOG("FloatingMenu:step6:uploadDone", "upload returned, inserting block", {
|
|
3592
|
+
blockType,
|
|
3593
|
+
blockId: blockToInsertAfter.id,
|
|
3594
|
+
urlLen: url?.length,
|
|
3595
|
+
elapsedMs
|
|
3596
|
+
});
|
|
3597
|
+
editor.insertBlocks(
|
|
3598
|
+
[
|
|
3599
|
+
{
|
|
3600
|
+
type: blockType,
|
|
3601
|
+
props: { url }
|
|
3602
|
+
}
|
|
3603
|
+
],
|
|
3604
|
+
blockToInsertAfter,
|
|
3605
|
+
"after"
|
|
3606
|
+
);
|
|
3607
|
+
} catch (err) {
|
|
3608
|
+
DEBUG_LOG("FloatingMenu:step7:catch", "upload or insert failed", {
|
|
3609
|
+
errMsg: err instanceof Error ? err.message : String(err)
|
|
3610
|
+
});
|
|
3611
|
+
console.error("Upload failed:", err);
|
|
3612
|
+
} finally {
|
|
3613
|
+
setIsUploading(false);
|
|
3614
|
+
}
|
|
3086
3615
|
}
|
|
3087
3616
|
}
|
|
3088
|
-
|
|
3089
|
-
|
|
3617
|
+
inputEl.value = "";
|
|
3618
|
+
}
|
|
3090
3619
|
}
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3620
|
+
),
|
|
3621
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3622
|
+
FloatingMenu,
|
|
3623
|
+
{
|
|
3624
|
+
editor,
|
|
3625
|
+
position: floatingMenuPosition,
|
|
3626
|
+
onImageUpload: () => {
|
|
3627
|
+
DEBUG_LOG("FloatingMenu:step1:click", "upload button clicked", {
|
|
3628
|
+
allowVideoUpload
|
|
3629
|
+
});
|
|
3630
|
+
let blockToInsertAfter;
|
|
3631
|
+
try {
|
|
3632
|
+
blockToInsertAfter = editor.getTextCursorPosition().block;
|
|
3633
|
+
} catch (err) {
|
|
3634
|
+
DEBUG_LOG("FloatingMenu:step1b:error", "getTextCursorPosition failed", {
|
|
3635
|
+
err: err instanceof Error ? err.message : String(err)
|
|
3636
|
+
});
|
|
3637
|
+
return;
|
|
3638
|
+
}
|
|
3639
|
+
floatingMenuBlockRef.current = blockToInsertAfter;
|
|
3640
|
+
const input = floatingMenuFileInputRef.current;
|
|
3641
|
+
if (!input) return;
|
|
3642
|
+
input.accept = allowVideoUpload ? "image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov" : "image/*";
|
|
3643
|
+
input.value = "";
|
|
3644
|
+
DEBUG_LOG("FloatingMenu:step2:inputReady", "persistent input ref, about to click", {
|
|
3645
|
+
accept: input.accept
|
|
3646
|
+
});
|
|
3647
|
+
DEBUG_LOG("FloatingMenu:step2b:click", "input.click() about to be called", {});
|
|
3648
|
+
input.click();
|
|
3649
|
+
}
|
|
3650
|
+
}
|
|
3651
|
+
)
|
|
3652
|
+
] }),
|
|
3653
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3094
3654
|
import_mantine.BlockNoteView,
|
|
3095
3655
|
{
|
|
3096
3656
|
editor,
|
|
@@ -3105,19 +3665,21 @@ function LumirEditor({
|
|
|
3105
3665
|
tableHandles,
|
|
3106
3666
|
onSelectionChange,
|
|
3107
3667
|
children: [
|
|
3108
|
-
linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ (0,
|
|
3109
|
-
/* @__PURE__ */ (0,
|
|
3110
|
-
|
|
3668
|
+
linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.LinkToolbarController, { linkToolbar: CustomLinkToolbar }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.LinkToolbarController, {})),
|
|
3669
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3670
|
+
import_react19.SuggestionMenuController,
|
|
3111
3671
|
{
|
|
3112
3672
|
triggerCharacter: "/",
|
|
3113
|
-
getItems: (0,
|
|
3673
|
+
getItems: (0, import_react18.useCallback)(
|
|
3114
3674
|
async (query) => {
|
|
3115
|
-
const items = (0,
|
|
3675
|
+
const items = (0, import_react19.getDefaultReactSlashMenuItems)(editor);
|
|
3116
3676
|
const filtered = items.filter((item) => {
|
|
3117
3677
|
const key = (item?.key || "").toString().toLowerCase();
|
|
3118
3678
|
const title = (item?.title || "").toString().toLowerCase();
|
|
3119
|
-
if (
|
|
3120
|
-
|
|
3679
|
+
if (key === "video" || title.includes("video"))
|
|
3680
|
+
return allowVideoUpload;
|
|
3681
|
+
if (["audio", "file"].includes(key)) return false;
|
|
3682
|
+
if (title.includes("audio") || title.includes("file"))
|
|
3121
3683
|
return false;
|
|
3122
3684
|
return true;
|
|
3123
3685
|
});
|
|
@@ -3152,7 +3714,7 @@ function LumirEditor({
|
|
|
3152
3714
|
},
|
|
3153
3715
|
aliases: ["html", "preview", "\uC6F9", "\uC6F9\uD398\uC774\uC9C0"],
|
|
3154
3716
|
group: "Embeds",
|
|
3155
|
-
icon: /* @__PURE__ */ (0,
|
|
3717
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3156
3718
|
"svg",
|
|
3157
3719
|
{
|
|
3158
3720
|
width: "18",
|
|
@@ -3164,8 +3726,8 @@ function LumirEditor({
|
|
|
3164
3726
|
strokeLinecap: "round",
|
|
3165
3727
|
strokeLinejoin: "round",
|
|
3166
3728
|
children: [
|
|
3167
|
-
/* @__PURE__ */ (0,
|
|
3168
|
-
/* @__PURE__ */ (0,
|
|
3729
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("polyline", { points: "16 18 22 12 16 6" }),
|
|
3730
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("polyline", { points: "8 6 2 12 8 18" })
|
|
3169
3731
|
]
|
|
3170
3732
|
}
|
|
3171
3733
|
),
|
|
@@ -3190,7 +3752,7 @@ function LumirEditor({
|
|
|
3190
3752
|
"\uD504\uB9AC\uBDF0"
|
|
3191
3753
|
],
|
|
3192
3754
|
group: "Embeds",
|
|
3193
|
-
icon: /* @__PURE__ */ (0,
|
|
3755
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3194
3756
|
"svg",
|
|
3195
3757
|
{
|
|
3196
3758
|
width: "18",
|
|
@@ -3202,8 +3764,8 @@ function LumirEditor({
|
|
|
3202
3764
|
strokeLinecap: "round",
|
|
3203
3765
|
strokeLinejoin: "round",
|
|
3204
3766
|
children: [
|
|
3205
|
-
/* @__PURE__ */ (0,
|
|
3206
|
-
/* @__PURE__ */ (0,
|
|
3767
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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" }),
|
|
3768
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.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" })
|
|
3207
3769
|
]
|
|
3208
3770
|
}
|
|
3209
3771
|
),
|
|
@@ -3218,19 +3780,25 @@ function LumirEditor({
|
|
|
3218
3780
|
)
|
|
3219
3781
|
);
|
|
3220
3782
|
},
|
|
3221
|
-
[editor, linkPreview?.apiEndpoint]
|
|
3783
|
+
[editor, allowVideoUpload, linkPreview?.apiEndpoint]
|
|
3222
3784
|
)
|
|
3223
3785
|
}
|
|
3224
3786
|
),
|
|
3225
|
-
!sideMenuAddButton && /* @__PURE__ */ (0,
|
|
3787
|
+
!sideMenuAddButton && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react19.SideMenuController, { sideMenu: DragHandleOnlySideMenu })
|
|
3226
3788
|
]
|
|
3227
3789
|
}
|
|
3228
3790
|
),
|
|
3229
|
-
isUploading && /* @__PURE__ */ (0,
|
|
3230
|
-
|
|
3231
|
-
/* @__PURE__ */ (0,
|
|
3232
|
-
|
|
3233
|
-
|
|
3791
|
+
isUploading && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "lumirEditor-upload-overlay", children: [
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "lumirEditor-spinner" }),
|
|
3793
|
+
uploadProgress !== null && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "lumirEditor-upload-progress", children: [
|
|
3794
|
+
uploadProgress,
|
|
3795
|
+
"%"
|
|
3796
|
+
] })
|
|
3797
|
+
] }),
|
|
3798
|
+
errorMessage && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "lumirEditor-error-toast", children: [
|
|
3799
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "lumirEditor-error-icon", children: "\u26A0\uFE0F" }),
|
|
3800
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "lumirEditor-error-message", children: errorMessage }),
|
|
3801
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3234
3802
|
"button",
|
|
3235
3803
|
{
|
|
3236
3804
|
className: "lumirEditor-error-close",
|