@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.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/components/LumirEditor.tsx
|
|
4
|
-
import { useEffect as
|
|
4
|
+
import { useEffect as useEffect8, useMemo, useCallback as useCallback14, useState as useState8, useRef as useRef9 } from "react";
|
|
5
5
|
import {
|
|
6
6
|
useCreateBlockNote,
|
|
7
7
|
SideMenu as BlockSideMenu,
|
|
@@ -65,7 +65,10 @@ var createS3Uploader = (config) => {
|
|
|
65
65
|
path,
|
|
66
66
|
fileNameTransform,
|
|
67
67
|
appendUUID,
|
|
68
|
-
preserveExtension = true
|
|
68
|
+
preserveExtension = true,
|
|
69
|
+
onProgress,
|
|
70
|
+
uploadTimeoutMs = 12e4,
|
|
71
|
+
maxRetries = 2
|
|
69
72
|
} = config;
|
|
70
73
|
if (!apiEndpoint || apiEndpoint.trim() === "") {
|
|
71
74
|
throw new Error(
|
|
@@ -104,6 +107,15 @@ var createS3Uploader = (config) => {
|
|
|
104
107
|
}
|
|
105
108
|
return `${env}/${path}/${filename}`;
|
|
106
109
|
};
|
|
110
|
+
const debugLog = (loc, msg, data) => {
|
|
111
|
+
const p = fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "b73262" },
|
|
114
|
+
body: JSON.stringify({ sessionId: "b73262", location: loc, message: msg, data, timestamp: Date.now() })
|
|
115
|
+
});
|
|
116
|
+
if (p && typeof p.catch === "function") p.catch(() => {
|
|
117
|
+
});
|
|
118
|
+
};
|
|
107
119
|
return async (file) => {
|
|
108
120
|
try {
|
|
109
121
|
if (!apiEndpoint || apiEndpoint.trim() === "") {
|
|
@@ -112,11 +124,26 @@ var createS3Uploader = (config) => {
|
|
|
112
124
|
);
|
|
113
125
|
}
|
|
114
126
|
const fileName = generateHierarchicalFileName(file);
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
);
|
|
127
|
+
const contentType = file.type || "application/octet-stream";
|
|
128
|
+
const presignedUrlFull = `${apiEndpoint}?key=${encodeURIComponent(fileName)}&contentType=${encodeURIComponent(contentType)}`;
|
|
129
|
+
const tPresigned = Date.now();
|
|
130
|
+
debugLog("s3:step1:presignedReq", "fetching presigned URL", {
|
|
131
|
+
fileName,
|
|
132
|
+
contentType,
|
|
133
|
+
apiEndpoint
|
|
134
|
+
});
|
|
135
|
+
const response = await fetch(presignedUrlFull);
|
|
136
|
+
debugLog("s3:step2:presignedRes", "presigned response", {
|
|
137
|
+
ok: response.ok,
|
|
138
|
+
status: response.status,
|
|
139
|
+
elapsedMs: Date.now() - tPresigned
|
|
140
|
+
});
|
|
118
141
|
if (!response.ok) {
|
|
119
142
|
const errorText = await response.text() || "";
|
|
143
|
+
debugLog("s3:step2b:presignedErr", "presigned failed", {
|
|
144
|
+
status: response.status,
|
|
145
|
+
errorText: errorText.slice(0, 200)
|
|
146
|
+
});
|
|
120
147
|
throw new Error(
|
|
121
148
|
`Failed to get presigned URL: ${response.statusText}, ${errorText}`
|
|
122
149
|
);
|
|
@@ -125,17 +152,64 @@ var createS3Uploader = (config) => {
|
|
|
125
152
|
const { presignedUrl, publicUrl } = responseData;
|
|
126
153
|
const validatedPresignedUrl = validateS3Url(presignedUrl, "presignedUrl");
|
|
127
154
|
const validatedPublicUrl = validateS3Url(publicUrl, "publicUrl");
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
155
|
+
const tPut = Date.now();
|
|
156
|
+
debugLog("s3:step3:putReq", "S3 PUT request", { publicUrlLen: validatedPublicUrl?.length });
|
|
157
|
+
let lastError;
|
|
158
|
+
const attempts = maxRetries + 1;
|
|
159
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
160
|
+
try {
|
|
161
|
+
if (onProgress && typeof XMLHttpRequest !== "undefined") {
|
|
162
|
+
await new Promise((resolve, reject) => {
|
|
163
|
+
const xhr = new XMLHttpRequest();
|
|
164
|
+
xhr.timeout = uploadTimeoutMs;
|
|
165
|
+
xhr.upload.onprogress = (e) => {
|
|
166
|
+
if (e.lengthComputable) {
|
|
167
|
+
onProgress(Math.min(100, Math.round(e.loaded / e.total * 100)));
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
xhr.onload = () => {
|
|
171
|
+
if (xhr.status >= 200 && xhr.status < 300) resolve();
|
|
172
|
+
else reject(new Error(`Failed to upload file: ${xhr.statusText}`));
|
|
173
|
+
};
|
|
174
|
+
xhr.onerror = () => reject(new Error("Upload failed"));
|
|
175
|
+
xhr.ontimeout = () => reject(new Error("Upload timeout"));
|
|
176
|
+
xhr.open("PUT", validatedPresignedUrl);
|
|
177
|
+
xhr.setRequestHeader("Content-Type", file.type || "application/octet-stream");
|
|
178
|
+
xhr.send(file);
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
const controller = new AbortController();
|
|
182
|
+
const timeoutId = setTimeout(() => controller.abort(), uploadTimeoutMs);
|
|
183
|
+
const uploadResponse = await fetch(validatedPresignedUrl, {
|
|
184
|
+
method: "PUT",
|
|
185
|
+
headers: {
|
|
186
|
+
"Content-Type": file.type || "application/octet-stream"
|
|
187
|
+
},
|
|
188
|
+
body: file,
|
|
189
|
+
signal: controller.signal
|
|
190
|
+
});
|
|
191
|
+
clearTimeout(timeoutId);
|
|
192
|
+
debugLog("s3:step4:putRes", "S3 PUT response", {
|
|
193
|
+
ok: uploadResponse.ok,
|
|
194
|
+
status: uploadResponse.status,
|
|
195
|
+
putElapsedMs: Date.now() - tPut
|
|
196
|
+
});
|
|
197
|
+
if (!uploadResponse.ok) {
|
|
198
|
+
throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
debugLog("s3:step5:return", "returning publicUrl", { urlPrefix: validatedPublicUrl.slice(0, 80) });
|
|
202
|
+
return validatedPublicUrl;
|
|
203
|
+
} catch (err) {
|
|
204
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
205
|
+
if (attempt < attempts - 1) {
|
|
206
|
+
debugLog("s3:putRetry", "PUT failed, retrying", { attempt: attempt + 1, attempts });
|
|
207
|
+
} else {
|
|
208
|
+
throw lastError;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
137
211
|
}
|
|
138
|
-
|
|
212
|
+
throw lastError ?? new Error("Upload failed");
|
|
139
213
|
} catch (error) {
|
|
140
214
|
console.error("S3 upload failed:", error);
|
|
141
215
|
throw error;
|
|
@@ -144,7 +218,7 @@ var createS3Uploader = (config) => {
|
|
|
144
218
|
};
|
|
145
219
|
|
|
146
220
|
// src/blocks/HtmlPreview.tsx
|
|
147
|
-
import { createReactBlockSpec as
|
|
221
|
+
import { createReactBlockSpec as createReactBlockSpec3 } from "@blocknote/react";
|
|
148
222
|
import {
|
|
149
223
|
defaultBlockSpecs,
|
|
150
224
|
BlockNoteSchema,
|
|
@@ -855,9 +929,254 @@ var LinkPreviewBlock = createReactBlockSpec(
|
|
|
855
929
|
}
|
|
856
930
|
);
|
|
857
931
|
|
|
932
|
+
// src/blocks/VideoBlock.tsx
|
|
933
|
+
import { createReactBlockSpec as createReactBlockSpec2 } from "@blocknote/react";
|
|
934
|
+
import { useState as useState2, useCallback as useCallback2, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
935
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
936
|
+
var MIN_VIDEO_WIDTH = 200;
|
|
937
|
+
var MAX_VIDEO_WIDTH = 1200;
|
|
938
|
+
var MIN_VIDEO_HEIGHT = 120;
|
|
939
|
+
var MAX_VIDEO_HEIGHT = 600;
|
|
940
|
+
var DEFAULT_VIDEO_WIDTH = 640;
|
|
941
|
+
var DEFAULT_VIDEO_HEIGHT = 360;
|
|
942
|
+
var VideoBlockCard = ({
|
|
943
|
+
url,
|
|
944
|
+
editable,
|
|
945
|
+
width,
|
|
946
|
+
onWidthChange,
|
|
947
|
+
height,
|
|
948
|
+
onHeightChange,
|
|
949
|
+
onContextMenuBlock
|
|
950
|
+
}) => {
|
|
951
|
+
const [resizeParams, setResizeParams] = useState2(
|
|
952
|
+
void 0
|
|
953
|
+
);
|
|
954
|
+
const [localWidth, setLocalWidth] = useState2(width);
|
|
955
|
+
const [localHeight, setLocalHeight] = useState2(height);
|
|
956
|
+
const wrapperRef = useRef2(null);
|
|
957
|
+
useEffect2(() => {
|
|
958
|
+
setLocalWidth(width);
|
|
959
|
+
}, [width]);
|
|
960
|
+
useEffect2(() => {
|
|
961
|
+
setLocalHeight(height);
|
|
962
|
+
}, [height]);
|
|
963
|
+
useEffect2(() => {
|
|
964
|
+
if (!resizeParams) return;
|
|
965
|
+
const onMouseMove = (e) => {
|
|
966
|
+
if (resizeParams.handleUsed === "bottom") {
|
|
967
|
+
const delta = e.clientY - resizeParams.initialClientY;
|
|
968
|
+
setLocalHeight(
|
|
969
|
+
Math.min(
|
|
970
|
+
Math.max(resizeParams.initialHeight + delta, MIN_VIDEO_HEIGHT),
|
|
971
|
+
MAX_VIDEO_HEIGHT
|
|
972
|
+
)
|
|
973
|
+
);
|
|
974
|
+
} else {
|
|
975
|
+
const delta = resizeParams.handleUsed === "left" ? resizeParams.initialClientX - e.clientX : e.clientX - resizeParams.initialClientX;
|
|
976
|
+
setLocalWidth(
|
|
977
|
+
Math.min(
|
|
978
|
+
Math.max(resizeParams.initialWidth + delta, MIN_VIDEO_WIDTH),
|
|
979
|
+
wrapperRef.current?.parentElement?.clientWidth || MAX_VIDEO_WIDTH
|
|
980
|
+
)
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
const onMouseUp = () => {
|
|
985
|
+
const handle = resizeParams.handleUsed;
|
|
986
|
+
setResizeParams(void 0);
|
|
987
|
+
if (handle === "bottom") {
|
|
988
|
+
if (localHeight != null && onHeightChange) onHeightChange(localHeight);
|
|
989
|
+
} else {
|
|
990
|
+
if (localWidth != null && onWidthChange) onWidthChange(localWidth);
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
window.addEventListener("mousemove", onMouseMove);
|
|
994
|
+
window.addEventListener("mouseup", onMouseUp);
|
|
995
|
+
return () => {
|
|
996
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
997
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
998
|
+
};
|
|
999
|
+
}, [resizeParams, localWidth, localHeight, onWidthChange, onHeightChange]);
|
|
1000
|
+
const handleLeftDown = useCallback2((e) => {
|
|
1001
|
+
e.preventDefault();
|
|
1002
|
+
e.stopPropagation();
|
|
1003
|
+
setResizeParams({
|
|
1004
|
+
handleUsed: "left",
|
|
1005
|
+
initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,
|
|
1006
|
+
initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,
|
|
1007
|
+
initialClientX: e.clientX,
|
|
1008
|
+
initialClientY: e.clientY
|
|
1009
|
+
});
|
|
1010
|
+
}, [localHeight]);
|
|
1011
|
+
const handleRightDown = useCallback2((e) => {
|
|
1012
|
+
e.preventDefault();
|
|
1013
|
+
e.stopPropagation();
|
|
1014
|
+
setResizeParams({
|
|
1015
|
+
handleUsed: "right",
|
|
1016
|
+
initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,
|
|
1017
|
+
initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,
|
|
1018
|
+
initialClientX: e.clientX,
|
|
1019
|
+
initialClientY: e.clientY
|
|
1020
|
+
});
|
|
1021
|
+
}, [localHeight]);
|
|
1022
|
+
const handleBottomDown = useCallback2((e) => {
|
|
1023
|
+
e.preventDefault();
|
|
1024
|
+
e.stopPropagation();
|
|
1025
|
+
setResizeParams({
|
|
1026
|
+
handleUsed: "bottom",
|
|
1027
|
+
initialWidth: wrapperRef.current?.clientWidth ?? DEFAULT_VIDEO_WIDTH,
|
|
1028
|
+
initialHeight: localHeight ?? DEFAULT_VIDEO_HEIGHT,
|
|
1029
|
+
initialClientX: e.clientX,
|
|
1030
|
+
initialClientY: e.clientY
|
|
1031
|
+
});
|
|
1032
|
+
}, [localHeight]);
|
|
1033
|
+
const resizeCursor = resizeParams ? resizeParams.handleUsed === "bottom" ? "ns-resize" : "ew-resize" : "default";
|
|
1034
|
+
const [hovered, setHovered] = useState2(false);
|
|
1035
|
+
return /* @__PURE__ */ jsxs2(
|
|
1036
|
+
"div",
|
|
1037
|
+
{
|
|
1038
|
+
ref: wrapperRef,
|
|
1039
|
+
className: "lumir-video-block-wrapper",
|
|
1040
|
+
onContextMenu: onContextMenuBlock,
|
|
1041
|
+
style: {
|
|
1042
|
+
position: "relative",
|
|
1043
|
+
width: localWidth != null ? `${localWidth}px` : void 0,
|
|
1044
|
+
maxWidth: "100%",
|
|
1045
|
+
cursor: resizeCursor,
|
|
1046
|
+
transition: resizeParams ? "none" : "box-shadow 0.2s"
|
|
1047
|
+
},
|
|
1048
|
+
onMouseEnter: () => {
|
|
1049
|
+
if (!resizeParams) setHovered(true);
|
|
1050
|
+
},
|
|
1051
|
+
onMouseLeave: () => {
|
|
1052
|
+
if (!resizeParams) setHovered(false);
|
|
1053
|
+
},
|
|
1054
|
+
children: [
|
|
1055
|
+
editable && (hovered || resizeParams) && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1056
|
+
/* @__PURE__ */ jsx2(
|
|
1057
|
+
"div",
|
|
1058
|
+
{
|
|
1059
|
+
className: "lumir-resize-handle",
|
|
1060
|
+
style: { left: "4px" },
|
|
1061
|
+
onMouseDown: handleLeftDown
|
|
1062
|
+
}
|
|
1063
|
+
),
|
|
1064
|
+
/* @__PURE__ */ jsx2(
|
|
1065
|
+
"div",
|
|
1066
|
+
{
|
|
1067
|
+
className: "lumir-resize-handle",
|
|
1068
|
+
style: { right: "4px" },
|
|
1069
|
+
onMouseDown: handleRightDown
|
|
1070
|
+
}
|
|
1071
|
+
)
|
|
1072
|
+
] }),
|
|
1073
|
+
/* @__PURE__ */ jsxs2(
|
|
1074
|
+
"div",
|
|
1075
|
+
{
|
|
1076
|
+
style: {
|
|
1077
|
+
width: "100%",
|
|
1078
|
+
height: `${localHeight ?? DEFAULT_VIDEO_HEIGHT}px`,
|
|
1079
|
+
overflow: "hidden",
|
|
1080
|
+
backgroundColor: "#000",
|
|
1081
|
+
borderRadius: "6px"
|
|
1082
|
+
},
|
|
1083
|
+
children: [
|
|
1084
|
+
/* @__PURE__ */ jsx2(
|
|
1085
|
+
"video",
|
|
1086
|
+
{
|
|
1087
|
+
src: url,
|
|
1088
|
+
controls: true,
|
|
1089
|
+
playsInline: true,
|
|
1090
|
+
style: {
|
|
1091
|
+
width: "100%",
|
|
1092
|
+
height: "100%",
|
|
1093
|
+
objectFit: "contain",
|
|
1094
|
+
display: "block"
|
|
1095
|
+
},
|
|
1096
|
+
onContextMenu: (e) => e.preventDefault()
|
|
1097
|
+
}
|
|
1098
|
+
),
|
|
1099
|
+
editable && (hovered || resizeParams) && /* @__PURE__ */ jsx2(
|
|
1100
|
+
"div",
|
|
1101
|
+
{
|
|
1102
|
+
className: "lumir-resize-handle-bottom",
|
|
1103
|
+
onMouseDown: handleBottomDown
|
|
1104
|
+
}
|
|
1105
|
+
)
|
|
1106
|
+
]
|
|
1107
|
+
}
|
|
1108
|
+
)
|
|
1109
|
+
]
|
|
1110
|
+
}
|
|
1111
|
+
);
|
|
1112
|
+
};
|
|
1113
|
+
var VideoBlock = createReactBlockSpec2(
|
|
1114
|
+
{
|
|
1115
|
+
type: "video",
|
|
1116
|
+
propSchema: {
|
|
1117
|
+
url: { default: "" },
|
|
1118
|
+
previewWidth: { default: 640 },
|
|
1119
|
+
previewHeight: { default: 360 }
|
|
1120
|
+
},
|
|
1121
|
+
content: "none"
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
render: (props) => {
|
|
1125
|
+
const url = props.block.props.url ?? "";
|
|
1126
|
+
const editable = props.editor.isEditable;
|
|
1127
|
+
const handleContextMenu = useCallback2((e) => {
|
|
1128
|
+
e.preventDefault();
|
|
1129
|
+
e.stopPropagation();
|
|
1130
|
+
}, []);
|
|
1131
|
+
if (!url) {
|
|
1132
|
+
return /* @__PURE__ */ jsx2(
|
|
1133
|
+
"div",
|
|
1134
|
+
{
|
|
1135
|
+
className: "lumir-video-block-placeholder",
|
|
1136
|
+
onContextMenu: handleContextMenu,
|
|
1137
|
+
style: {
|
|
1138
|
+
width: "100%",
|
|
1139
|
+
maxWidth: `${DEFAULT_VIDEO_WIDTH}px`,
|
|
1140
|
+
height: `${DEFAULT_VIDEO_HEIGHT}px`,
|
|
1141
|
+
backgroundColor: "#1a1a1a",
|
|
1142
|
+
borderRadius: "6px",
|
|
1143
|
+
display: "flex",
|
|
1144
|
+
alignItems: "center",
|
|
1145
|
+
justifyContent: "center",
|
|
1146
|
+
color: "rgba(255,255,255,0.5)",
|
|
1147
|
+
fontSize: "14px"
|
|
1148
|
+
},
|
|
1149
|
+
children: "\uBE44\uB514\uC624 URL \uC5C6\uC74C"
|
|
1150
|
+
}
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
return /* @__PURE__ */ jsx2(
|
|
1154
|
+
VideoBlockCard,
|
|
1155
|
+
{
|
|
1156
|
+
url,
|
|
1157
|
+
editable,
|
|
1158
|
+
width: props.block.props.previewWidth,
|
|
1159
|
+
onWidthChange: (newWidth) => {
|
|
1160
|
+
props.editor.updateBlock(props.block, {
|
|
1161
|
+
props: { previewWidth: newWidth }
|
|
1162
|
+
});
|
|
1163
|
+
},
|
|
1164
|
+
height: props.block.props.previewHeight,
|
|
1165
|
+
onHeightChange: (newHeight) => {
|
|
1166
|
+
props.editor.updateBlock(props.block, {
|
|
1167
|
+
props: { previewHeight: newHeight }
|
|
1168
|
+
});
|
|
1169
|
+
},
|
|
1170
|
+
onContextMenuBlock: handleContextMenu
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
|
|
858
1177
|
// src/blocks/HtmlPreview.tsx
|
|
859
|
-
import { useState as
|
|
860
|
-
import { jsx as
|
|
1178
|
+
import { useState as useState3, useRef as useRef3, useCallback as useCallback3, useEffect as useEffect3 } from "react";
|
|
1179
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
861
1180
|
var MIN_HEIGHT = 100;
|
|
862
1181
|
var MAX_HEIGHT = 1200;
|
|
863
1182
|
var ensureCharset = (html) => {
|
|
@@ -895,7 +1214,7 @@ var createSecureBlobUrl = (htmlContent) => {
|
|
|
895
1214
|
});
|
|
896
1215
|
return URL.createObjectURL(blob);
|
|
897
1216
|
};
|
|
898
|
-
var HtmlPreviewBlock =
|
|
1217
|
+
var HtmlPreviewBlock = createReactBlockSpec3(
|
|
899
1218
|
{
|
|
900
1219
|
type: "htmlPreview",
|
|
901
1220
|
propSchema: {
|
|
@@ -913,15 +1232,15 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
913
1232
|
},
|
|
914
1233
|
{
|
|
915
1234
|
render: (props) => {
|
|
916
|
-
const [isExpanded, setIsExpanded] =
|
|
917
|
-
const [isResizing, setIsResizing] =
|
|
918
|
-
const [blobUrl, setBlobUrl] =
|
|
919
|
-
const containerRef =
|
|
1235
|
+
const [isExpanded, setIsExpanded] = useState3(true);
|
|
1236
|
+
const [isResizing, setIsResizing] = useState3(false);
|
|
1237
|
+
const [blobUrl, setBlobUrl] = useState3("");
|
|
1238
|
+
const containerRef = useRef3(null);
|
|
920
1239
|
const htmlContent = props.block.props.htmlContent || "";
|
|
921
1240
|
const fileName = props.block.props.fileName || "HTML Document";
|
|
922
1241
|
const savedHeight = props.block.props.height || "400px";
|
|
923
1242
|
const currentHeight = parseInt(savedHeight, 10) || 400;
|
|
924
|
-
|
|
1243
|
+
useEffect3(() => {
|
|
925
1244
|
if (htmlContent) {
|
|
926
1245
|
const url = createSecureBlobUrl(htmlContent);
|
|
927
1246
|
setBlobUrl(url);
|
|
@@ -930,7 +1249,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
930
1249
|
};
|
|
931
1250
|
}
|
|
932
1251
|
}, [htmlContent]);
|
|
933
|
-
const handleResizeStart =
|
|
1252
|
+
const handleResizeStart = useCallback3(
|
|
934
1253
|
(e) => {
|
|
935
1254
|
e.preventDefault();
|
|
936
1255
|
e.stopPropagation();
|
|
@@ -957,7 +1276,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
957
1276
|
},
|
|
958
1277
|
[currentHeight, props.editor, props.block]
|
|
959
1278
|
);
|
|
960
|
-
const handleExport =
|
|
1279
|
+
const handleExport = useCallback3(
|
|
961
1280
|
(e) => {
|
|
962
1281
|
e.stopPropagation();
|
|
963
1282
|
const safeFileName = sanitizeFileName(fileName);
|
|
@@ -978,7 +1297,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
978
1297
|
},
|
|
979
1298
|
[htmlContent, fileName]
|
|
980
1299
|
);
|
|
981
|
-
const handleOpenNewWindow =
|
|
1300
|
+
const handleOpenNewWindow = useCallback3(
|
|
982
1301
|
(e) => {
|
|
983
1302
|
e.stopPropagation();
|
|
984
1303
|
if (typeof window === "undefined") return;
|
|
@@ -992,7 +1311,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
992
1311
|
},
|
|
993
1312
|
[htmlContent]
|
|
994
1313
|
);
|
|
995
|
-
return /* @__PURE__ */
|
|
1314
|
+
return /* @__PURE__ */ jsxs3(
|
|
996
1315
|
"div",
|
|
997
1316
|
{
|
|
998
1317
|
ref: containerRef,
|
|
@@ -1008,7 +1327,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1008
1327
|
boxShadow: "none"
|
|
1009
1328
|
},
|
|
1010
1329
|
children: [
|
|
1011
|
-
/* @__PURE__ */
|
|
1330
|
+
/* @__PURE__ */ jsxs3(
|
|
1012
1331
|
"div",
|
|
1013
1332
|
{
|
|
1014
1333
|
style: {
|
|
@@ -1020,7 +1339,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1020
1339
|
borderBottom: isExpanded ? "1px solid #e0e0e0" : "none"
|
|
1021
1340
|
},
|
|
1022
1341
|
children: [
|
|
1023
|
-
/* @__PURE__ */
|
|
1342
|
+
/* @__PURE__ */ jsxs3(
|
|
1024
1343
|
"div",
|
|
1025
1344
|
{
|
|
1026
1345
|
style: {
|
|
@@ -1032,7 +1351,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1032
1351
|
},
|
|
1033
1352
|
onClick: () => setIsExpanded(!isExpanded),
|
|
1034
1353
|
children: [
|
|
1035
|
-
/* @__PURE__ */
|
|
1354
|
+
/* @__PURE__ */ jsx3(
|
|
1036
1355
|
"svg",
|
|
1037
1356
|
{
|
|
1038
1357
|
width: "16",
|
|
@@ -1047,15 +1366,15 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1047
1366
|
transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)",
|
|
1048
1367
|
transition: "transform 0.2s"
|
|
1049
1368
|
},
|
|
1050
|
-
children: /* @__PURE__ */
|
|
1369
|
+
children: /* @__PURE__ */ jsx3("polyline", { points: "6 9 12 15 18 9" })
|
|
1051
1370
|
}
|
|
1052
1371
|
),
|
|
1053
|
-
/* @__PURE__ */
|
|
1372
|
+
/* @__PURE__ */ jsx3("span", { style: { fontWeight: 500, fontSize: "14px" }, children: fileName })
|
|
1054
1373
|
]
|
|
1055
1374
|
}
|
|
1056
1375
|
),
|
|
1057
|
-
/* @__PURE__ */
|
|
1058
|
-
/* @__PURE__ */
|
|
1376
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
1377
|
+
/* @__PURE__ */ jsx3(
|
|
1059
1378
|
"button",
|
|
1060
1379
|
{
|
|
1061
1380
|
onClick: handleOpenNewWindow,
|
|
@@ -1078,7 +1397,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1078
1397
|
onMouseLeave: (e) => {
|
|
1079
1398
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
1080
1399
|
},
|
|
1081
|
-
children: /* @__PURE__ */
|
|
1400
|
+
children: /* @__PURE__ */ jsxs3(
|
|
1082
1401
|
"svg",
|
|
1083
1402
|
{
|
|
1084
1403
|
width: "16",
|
|
@@ -1090,15 +1409,15 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1090
1409
|
strokeLinecap: "round",
|
|
1091
1410
|
strokeLinejoin: "round",
|
|
1092
1411
|
children: [
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
/* @__PURE__ */
|
|
1095
|
-
/* @__PURE__ */
|
|
1412
|
+
/* @__PURE__ */ jsx3("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
|
|
1413
|
+
/* @__PURE__ */ jsx3("polyline", { points: "15 3 21 3 21 9" }),
|
|
1414
|
+
/* @__PURE__ */ jsx3("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
1096
1415
|
]
|
|
1097
1416
|
}
|
|
1098
1417
|
)
|
|
1099
1418
|
}
|
|
1100
1419
|
),
|
|
1101
|
-
/* @__PURE__ */
|
|
1420
|
+
/* @__PURE__ */ jsx3(
|
|
1102
1421
|
"button",
|
|
1103
1422
|
{
|
|
1104
1423
|
onClick: handleExport,
|
|
@@ -1121,7 +1440,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1121
1440
|
onMouseLeave: (e) => {
|
|
1122
1441
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
1123
1442
|
},
|
|
1124
|
-
children: /* @__PURE__ */
|
|
1443
|
+
children: /* @__PURE__ */ jsxs3(
|
|
1125
1444
|
"svg",
|
|
1126
1445
|
{
|
|
1127
1446
|
width: "16",
|
|
@@ -1133,9 +1452,9 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1133
1452
|
strokeLinecap: "round",
|
|
1134
1453
|
strokeLinejoin: "round",
|
|
1135
1454
|
children: [
|
|
1136
|
-
/* @__PURE__ */
|
|
1137
|
-
/* @__PURE__ */
|
|
1138
|
-
/* @__PURE__ */
|
|
1455
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
1456
|
+
/* @__PURE__ */ jsx3("polyline", { points: "7 10 12 15 17 10" }),
|
|
1457
|
+
/* @__PURE__ */ jsx3("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
|
|
1139
1458
|
]
|
|
1140
1459
|
}
|
|
1141
1460
|
)
|
|
@@ -1145,7 +1464,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1145
1464
|
]
|
|
1146
1465
|
}
|
|
1147
1466
|
),
|
|
1148
|
-
isExpanded && /* @__PURE__ */
|
|
1467
|
+
isExpanded && /* @__PURE__ */ jsxs3(
|
|
1149
1468
|
"div",
|
|
1150
1469
|
{
|
|
1151
1470
|
style: {
|
|
@@ -1154,7 +1473,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1154
1473
|
position: "relative"
|
|
1155
1474
|
},
|
|
1156
1475
|
children: [
|
|
1157
|
-
/* @__PURE__ */
|
|
1476
|
+
/* @__PURE__ */ jsx3(
|
|
1158
1477
|
"iframe",
|
|
1159
1478
|
{
|
|
1160
1479
|
src: blobUrl || "about:blank",
|
|
@@ -1171,7 +1490,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1171
1490
|
loading: "lazy"
|
|
1172
1491
|
}
|
|
1173
1492
|
),
|
|
1174
|
-
/* @__PURE__ */
|
|
1493
|
+
/* @__PURE__ */ jsx3(
|
|
1175
1494
|
"div",
|
|
1176
1495
|
{
|
|
1177
1496
|
onMouseDown: handleResizeStart,
|
|
@@ -1196,7 +1515,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1196
1515
|
e.currentTarget.style.backgroundColor = "transparent";
|
|
1197
1516
|
}
|
|
1198
1517
|
},
|
|
1199
|
-
children: /* @__PURE__ */
|
|
1518
|
+
children: /* @__PURE__ */ jsx3(
|
|
1200
1519
|
"div",
|
|
1201
1520
|
{
|
|
1202
1521
|
style: {
|
|
@@ -1221,6 +1540,7 @@ var HtmlPreviewBlock = createReactBlockSpec2(
|
|
|
1221
1540
|
var schema = BlockNoteSchema.create({
|
|
1222
1541
|
blockSpecs: {
|
|
1223
1542
|
...defaultBlockSpecs,
|
|
1543
|
+
video: VideoBlock,
|
|
1224
1544
|
htmlPreview: HtmlPreviewBlock,
|
|
1225
1545
|
linkPreview: LinkPreviewBlock
|
|
1226
1546
|
},
|
|
@@ -1229,60 +1549,60 @@ var schema = BlockNoteSchema.create({
|
|
|
1229
1549
|
});
|
|
1230
1550
|
|
|
1231
1551
|
// src/components/FloatingMenu/index.tsx
|
|
1232
|
-
import { useState as
|
|
1552
|
+
import { useState as useState7, useEffect as useEffect7, useRef as useRef8 } from "react";
|
|
1233
1553
|
|
|
1234
1554
|
// src/components/FloatingMenu/Icons.tsx
|
|
1235
|
-
import { jsx as
|
|
1555
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1236
1556
|
var Icons = {
|
|
1237
|
-
undo: /* @__PURE__ */
|
|
1238
|
-
redo: /* @__PURE__ */
|
|
1239
|
-
bold: /* @__PURE__ */
|
|
1240
|
-
italic: /* @__PURE__ */
|
|
1241
|
-
underline: /* @__PURE__ */
|
|
1242
|
-
strikethrough: /* @__PURE__ */
|
|
1243
|
-
alignLeft: /* @__PURE__ */
|
|
1244
|
-
alignCenter: /* @__PURE__ */
|
|
1245
|
-
alignRight: /* @__PURE__ */
|
|
1246
|
-
bulletList: /* @__PURE__ */
|
|
1247
|
-
numberedList: /* @__PURE__ */
|
|
1248
|
-
image: /* @__PURE__ */
|
|
1249
|
-
expandMore: /* @__PURE__ */
|
|
1250
|
-
textColor: /* @__PURE__ */
|
|
1251
|
-
bgColor: /* @__PURE__ */
|
|
1252
|
-
/* @__PURE__ */
|
|
1253
|
-
/* @__PURE__ */
|
|
1557
|
+
undo: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1558
|
+
redo: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1559
|
+
bold: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1560
|
+
italic: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" }) }),
|
|
1561
|
+
underline: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1562
|
+
strikethrough: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z" }) }),
|
|
1563
|
+
alignLeft: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z" }) }),
|
|
1564
|
+
alignCenter: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z" }) }),
|
|
1565
|
+
alignRight: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z" }) }),
|
|
1566
|
+
bulletList: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1567
|
+
numberedList: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z" }) }),
|
|
1568
|
+
image: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1569
|
+
expandMore: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx4("path", { d: "M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" }) }),
|
|
1570
|
+
textColor: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z" }) }),
|
|
1571
|
+
bgColor: /* @__PURE__ */ jsxs4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1572
|
+
/* @__PURE__ */ jsx4("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" }),
|
|
1573
|
+
/* @__PURE__ */ jsx4("path", { fillOpacity: ".36", d: "M0 20h24v4H0z" })
|
|
1254
1574
|
] }),
|
|
1255
|
-
link: /* @__PURE__ */
|
|
1256
|
-
chevronRight: /* @__PURE__ */
|
|
1257
|
-
chevronLeft: /* @__PURE__ */
|
|
1258
|
-
table: /* @__PURE__ */
|
|
1259
|
-
htmlFile: /* @__PURE__ */
|
|
1575
|
+
link: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1576
|
+
chevronRight: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" }) }),
|
|
1577
|
+
chevronLeft: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" }) }),
|
|
1578
|
+
table: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1579
|
+
htmlFile: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) })
|
|
1260
1580
|
};
|
|
1261
1581
|
var BlockTypeIcons = {
|
|
1262
|
-
paragraph: /* @__PURE__ */
|
|
1263
|
-
h1: /* @__PURE__ */
|
|
1264
|
-
h2: /* @__PURE__ */
|
|
1265
|
-
h3: /* @__PURE__ */
|
|
1266
|
-
h4: /* @__PURE__ */
|
|
1267
|
-
h5: /* @__PURE__ */
|
|
1268
|
-
h6: /* @__PURE__ */
|
|
1269
|
-
toggleH1: /* @__PURE__ */
|
|
1270
|
-
/* @__PURE__ */
|
|
1271
|
-
/* @__PURE__ */
|
|
1582
|
+
paragraph: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M5 5h14v2H5zM5 11h14v2H5zM5 17h10v2H5z" }) }),
|
|
1583
|
+
h1: /* @__PURE__ */ jsx4("span", { className: "lumir-block-icon-text", children: "H1" }),
|
|
1584
|
+
h2: /* @__PURE__ */ jsx4("span", { className: "lumir-block-icon-text", children: "H2" }),
|
|
1585
|
+
h3: /* @__PURE__ */ jsx4("span", { className: "lumir-block-icon-text", children: "H3" }),
|
|
1586
|
+
h4: /* @__PURE__ */ jsx4("span", { className: "lumir-block-icon-text", children: "H4" }),
|
|
1587
|
+
h5: /* @__PURE__ */ jsx4("span", { className: "lumir-block-icon-text", children: "H5" }),
|
|
1588
|
+
h6: /* @__PURE__ */ jsx4("span", { className: "lumir-block-icon-text", children: "H6" }),
|
|
1589
|
+
toggleH1: /* @__PURE__ */ jsxs4("span", { className: "lumir-block-icon-toggle", children: [
|
|
1590
|
+
/* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ jsx4("path", { d: "M8 5v14l11-7z" }) }),
|
|
1591
|
+
/* @__PURE__ */ jsx4("span", { children: "H1" })
|
|
1272
1592
|
] }),
|
|
1273
|
-
toggleH2: /* @__PURE__ */
|
|
1274
|
-
/* @__PURE__ */
|
|
1275
|
-
/* @__PURE__ */
|
|
1593
|
+
toggleH2: /* @__PURE__ */ jsxs4("span", { className: "lumir-block-icon-toggle", children: [
|
|
1594
|
+
/* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ jsx4("path", { d: "M8 5v14l11-7z" }) }),
|
|
1595
|
+
/* @__PURE__ */ jsx4("span", { children: "H2" })
|
|
1276
1596
|
] }),
|
|
1277
|
-
toggleH3: /* @__PURE__ */
|
|
1278
|
-
/* @__PURE__ */
|
|
1279
|
-
/* @__PURE__ */
|
|
1597
|
+
toggleH3: /* @__PURE__ */ jsxs4("span", { className: "lumir-block-icon-toggle", children: [
|
|
1598
|
+
/* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ jsx4("path", { d: "M8 5v14l11-7z" }) }),
|
|
1599
|
+
/* @__PURE__ */ jsx4("span", { children: "H3" })
|
|
1280
1600
|
] }),
|
|
1281
|
-
quote: /* @__PURE__ */
|
|
1282
|
-
codeBlock: /* @__PURE__ */
|
|
1283
|
-
toggleList: /* @__PURE__ */
|
|
1284
|
-
/* @__PURE__ */
|
|
1285
|
-
/* @__PURE__ */
|
|
1601
|
+
quote: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z" }) }),
|
|
1602
|
+
codeBlock: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1603
|
+
toggleList: /* @__PURE__ */ jsxs4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1604
|
+
/* @__PURE__ */ jsx4("path", { d: "M10 6h10v2H10zM10 11h10v2H10zM10 16h10v2H10z" }),
|
|
1605
|
+
/* @__PURE__ */ jsx4(
|
|
1286
1606
|
"path",
|
|
1287
1607
|
{
|
|
1288
1608
|
d: "M4 8l4 4-4 4",
|
|
@@ -1294,15 +1614,15 @@ var BlockTypeIcons = {
|
|
|
1294
1614
|
}
|
|
1295
1615
|
)
|
|
1296
1616
|
] }),
|
|
1297
|
-
bulletList: /* @__PURE__ */
|
|
1298
|
-
/* @__PURE__ */
|
|
1299
|
-
/* @__PURE__ */
|
|
1300
|
-
/* @__PURE__ */
|
|
1301
|
-
/* @__PURE__ */
|
|
1617
|
+
bulletList: /* @__PURE__ */ jsxs4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1618
|
+
/* @__PURE__ */ jsx4("circle", { cx: "4", cy: "6", r: "1.5" }),
|
|
1619
|
+
/* @__PURE__ */ jsx4("circle", { cx: "4", cy: "12", r: "1.5" }),
|
|
1620
|
+
/* @__PURE__ */ jsx4("circle", { cx: "4", cy: "18", r: "1.5" }),
|
|
1621
|
+
/* @__PURE__ */ jsx4("path", { d: "M8 5h12v2H8zM8 11h12v2H8zM8 17h12v2H8z" })
|
|
1302
1622
|
] }),
|
|
1303
|
-
numberedList: /* @__PURE__ */
|
|
1304
|
-
checkList: /* @__PURE__ */
|
|
1305
|
-
/* @__PURE__ */
|
|
1623
|
+
numberedList: /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx4("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z" }) }),
|
|
1624
|
+
checkList: /* @__PURE__ */ jsxs4("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
|
|
1625
|
+
/* @__PURE__ */ jsx4(
|
|
1306
1626
|
"rect",
|
|
1307
1627
|
{
|
|
1308
1628
|
x: "3",
|
|
@@ -1315,7 +1635,7 @@ var BlockTypeIcons = {
|
|
|
1315
1635
|
strokeWidth: "1.5"
|
|
1316
1636
|
}
|
|
1317
1637
|
),
|
|
1318
|
-
/* @__PURE__ */
|
|
1638
|
+
/* @__PURE__ */ jsx4(
|
|
1319
1639
|
"path",
|
|
1320
1640
|
{
|
|
1321
1641
|
d: "M4.5 7l1.5 1.5 3-3",
|
|
@@ -1326,8 +1646,8 @@ var BlockTypeIcons = {
|
|
|
1326
1646
|
strokeLinejoin: "round"
|
|
1327
1647
|
}
|
|
1328
1648
|
),
|
|
1329
|
-
/* @__PURE__ */
|
|
1330
|
-
/* @__PURE__ */
|
|
1649
|
+
/* @__PURE__ */ jsx4("path", { d: "M12 6h8v2h-8z" }),
|
|
1650
|
+
/* @__PURE__ */ jsx4(
|
|
1331
1651
|
"rect",
|
|
1332
1652
|
{
|
|
1333
1653
|
x: "3",
|
|
@@ -1340,37 +1660,37 @@ var BlockTypeIcons = {
|
|
|
1340
1660
|
strokeWidth: "1.5"
|
|
1341
1661
|
}
|
|
1342
1662
|
),
|
|
1343
|
-
/* @__PURE__ */
|
|
1663
|
+
/* @__PURE__ */ jsx4("path", { d: "M12 16h8v2h-8z" })
|
|
1344
1664
|
] })
|
|
1345
1665
|
};
|
|
1346
1666
|
|
|
1347
1667
|
// src/components/FloatingMenu/components/ToolbarDivider.tsx
|
|
1348
|
-
import { jsx as
|
|
1349
|
-
var ToolbarDivider = () => /* @__PURE__ */
|
|
1668
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1669
|
+
var ToolbarDivider = () => /* @__PURE__ */ jsx5("div", { className: "lumir-toolbar-divider" });
|
|
1350
1670
|
|
|
1351
1671
|
// src/components/FloatingMenu/components/UndoRedoButtons.tsx
|
|
1352
|
-
import { useCallback as
|
|
1353
|
-
import { jsx as
|
|
1672
|
+
import { useCallback as useCallback4 } from "react";
|
|
1673
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1354
1674
|
var UndoRedoButtons = ({ editor }) => {
|
|
1355
|
-
const handleUndo =
|
|
1675
|
+
const handleUndo = useCallback4(() => {
|
|
1356
1676
|
try {
|
|
1357
1677
|
editor?.undo?.();
|
|
1358
1678
|
} catch (err) {
|
|
1359
1679
|
console.error("Undo failed:", err);
|
|
1360
1680
|
}
|
|
1361
1681
|
}, [editor]);
|
|
1362
|
-
const handleRedo =
|
|
1682
|
+
const handleRedo = useCallback4(() => {
|
|
1363
1683
|
try {
|
|
1364
1684
|
editor?.redo?.();
|
|
1365
1685
|
} catch (err) {
|
|
1366
1686
|
console.error("Redo failed:", err);
|
|
1367
1687
|
}
|
|
1368
1688
|
}, [editor]);
|
|
1369
|
-
const handleMouseDown =
|
|
1689
|
+
const handleMouseDown = useCallback4((e) => {
|
|
1370
1690
|
e.preventDefault();
|
|
1371
1691
|
}, []);
|
|
1372
|
-
return /* @__PURE__ */
|
|
1373
|
-
/* @__PURE__ */
|
|
1692
|
+
return /* @__PURE__ */ jsxs5("div", { className: "lumir-toolbar-group", children: [
|
|
1693
|
+
/* @__PURE__ */ jsx6(
|
|
1374
1694
|
"button",
|
|
1375
1695
|
{
|
|
1376
1696
|
className: "lumir-toolbar-btn",
|
|
@@ -1381,7 +1701,7 @@ var UndoRedoButtons = ({ editor }) => {
|
|
|
1381
1701
|
children: Icons.undo
|
|
1382
1702
|
}
|
|
1383
1703
|
),
|
|
1384
|
-
/* @__PURE__ */
|
|
1704
|
+
/* @__PURE__ */ jsx6(
|
|
1385
1705
|
"button",
|
|
1386
1706
|
{
|
|
1387
1707
|
className: "lumir-toolbar-btn",
|
|
@@ -1396,8 +1716,8 @@ var UndoRedoButtons = ({ editor }) => {
|
|
|
1396
1716
|
};
|
|
1397
1717
|
|
|
1398
1718
|
// src/components/FloatingMenu/components/TextStyleButton.tsx
|
|
1399
|
-
import { useCallback as
|
|
1400
|
-
import { jsx as
|
|
1719
|
+
import { useCallback as useCallback5 } from "react";
|
|
1720
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1401
1721
|
var iconMap = {
|
|
1402
1722
|
bold: Icons.bold,
|
|
1403
1723
|
italic: Icons.italic,
|
|
@@ -1423,17 +1743,17 @@ var TextStyleButton = ({
|
|
|
1423
1743
|
}
|
|
1424
1744
|
};
|
|
1425
1745
|
const isActive = getIsActive();
|
|
1426
|
-
const handleClick =
|
|
1746
|
+
const handleClick = useCallback5(() => {
|
|
1427
1747
|
try {
|
|
1428
1748
|
editor?.toggleStyles?.({ [style]: true });
|
|
1429
1749
|
} catch (err) {
|
|
1430
1750
|
console.error(`Toggle ${style} failed:`, err);
|
|
1431
1751
|
}
|
|
1432
1752
|
}, [editor, style]);
|
|
1433
|
-
const handleMouseDown =
|
|
1753
|
+
const handleMouseDown = useCallback5((e) => {
|
|
1434
1754
|
e.preventDefault();
|
|
1435
1755
|
}, []);
|
|
1436
|
-
return /* @__PURE__ */
|
|
1756
|
+
return /* @__PURE__ */ jsx7(
|
|
1437
1757
|
"button",
|
|
1438
1758
|
{
|
|
1439
1759
|
className: cn("lumir-toolbar-btn", isActive && "is-active"),
|
|
@@ -1447,8 +1767,8 @@ var TextStyleButton = ({
|
|
|
1447
1767
|
};
|
|
1448
1768
|
|
|
1449
1769
|
// src/components/FloatingMenu/components/AlignButton.tsx
|
|
1450
|
-
import { useCallback as
|
|
1451
|
-
import { jsx as
|
|
1770
|
+
import { useCallback as useCallback6 } from "react";
|
|
1771
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1452
1772
|
var iconMap2 = {
|
|
1453
1773
|
left: Icons.alignLeft,
|
|
1454
1774
|
center: Icons.alignCenter,
|
|
@@ -1472,7 +1792,7 @@ var AlignButton = ({
|
|
|
1472
1792
|
}
|
|
1473
1793
|
};
|
|
1474
1794
|
const isActive = getCurrentAlignment() === alignment;
|
|
1475
|
-
const handleClick =
|
|
1795
|
+
const handleClick = useCallback6(() => {
|
|
1476
1796
|
try {
|
|
1477
1797
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1478
1798
|
if (block && editor?.updateBlock) {
|
|
@@ -1482,10 +1802,10 @@ var AlignButton = ({
|
|
|
1482
1802
|
console.error(`Set alignment ${alignment} failed:`, err);
|
|
1483
1803
|
}
|
|
1484
1804
|
}, [editor, alignment]);
|
|
1485
|
-
const handleMouseDown =
|
|
1805
|
+
const handleMouseDown = useCallback6((e) => {
|
|
1486
1806
|
e.preventDefault();
|
|
1487
1807
|
}, []);
|
|
1488
|
-
return /* @__PURE__ */
|
|
1808
|
+
return /* @__PURE__ */ jsx8(
|
|
1489
1809
|
"button",
|
|
1490
1810
|
{
|
|
1491
1811
|
className: cn("lumir-toolbar-btn", isActive && "is-active"),
|
|
@@ -1499,8 +1819,8 @@ var AlignButton = ({
|
|
|
1499
1819
|
};
|
|
1500
1820
|
|
|
1501
1821
|
// src/components/FloatingMenu/components/ListButton.tsx
|
|
1502
|
-
import { useCallback as
|
|
1503
|
-
import { jsx as
|
|
1822
|
+
import { useCallback as useCallback7 } from "react";
|
|
1823
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1504
1824
|
var iconMap3 = {
|
|
1505
1825
|
bullet: Icons.bulletList,
|
|
1506
1826
|
numbered: Icons.numberedList
|
|
@@ -1520,7 +1840,7 @@ var ListButton = ({ editor, type }) => {
|
|
|
1520
1840
|
}
|
|
1521
1841
|
};
|
|
1522
1842
|
const isActive = getIsActive();
|
|
1523
|
-
const handleClick =
|
|
1843
|
+
const handleClick = useCallback7(() => {
|
|
1524
1844
|
try {
|
|
1525
1845
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1526
1846
|
if (block && editor?.updateBlock) {
|
|
@@ -1532,10 +1852,10 @@ var ListButton = ({ editor, type }) => {
|
|
|
1532
1852
|
console.error(`List toggle failed:`, err);
|
|
1533
1853
|
}
|
|
1534
1854
|
}, [editor, type]);
|
|
1535
|
-
const handleMouseDown =
|
|
1855
|
+
const handleMouseDown = useCallback7((e) => {
|
|
1536
1856
|
e.preventDefault();
|
|
1537
1857
|
}, []);
|
|
1538
|
-
return /* @__PURE__ */
|
|
1858
|
+
return /* @__PURE__ */ jsx9(
|
|
1539
1859
|
"button",
|
|
1540
1860
|
{
|
|
1541
1861
|
className: cn("lumir-toolbar-btn", isActive && "is-active"),
|
|
@@ -1549,13 +1869,13 @@ var ListButton = ({ editor, type }) => {
|
|
|
1549
1869
|
};
|
|
1550
1870
|
|
|
1551
1871
|
// src/components/FloatingMenu/components/ImageButton.tsx
|
|
1552
|
-
import { useCallback as
|
|
1553
|
-
import { jsx as
|
|
1872
|
+
import { useCallback as useCallback8 } from "react";
|
|
1873
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1554
1874
|
var ImageButton = ({
|
|
1555
1875
|
editor,
|
|
1556
1876
|
onImageUpload
|
|
1557
1877
|
}) => {
|
|
1558
|
-
const handleClick =
|
|
1878
|
+
const handleClick = useCallback8(() => {
|
|
1559
1879
|
if (onImageUpload) {
|
|
1560
1880
|
onImageUpload();
|
|
1561
1881
|
} else {
|
|
@@ -1580,10 +1900,10 @@ var ImageButton = ({
|
|
|
1580
1900
|
input.click();
|
|
1581
1901
|
}
|
|
1582
1902
|
}, [editor, onImageUpload]);
|
|
1583
|
-
const handleMouseDown =
|
|
1903
|
+
const handleMouseDown = useCallback8((e) => {
|
|
1584
1904
|
e.preventDefault();
|
|
1585
1905
|
}, []);
|
|
1586
|
-
return /* @__PURE__ */
|
|
1906
|
+
return /* @__PURE__ */ jsx10(
|
|
1587
1907
|
"button",
|
|
1588
1908
|
{
|
|
1589
1909
|
className: "lumir-toolbar-btn",
|
|
@@ -1597,7 +1917,7 @@ var ImageButton = ({
|
|
|
1597
1917
|
};
|
|
1598
1918
|
|
|
1599
1919
|
// src/components/FloatingMenu/components/ColorButton.tsx
|
|
1600
|
-
import { useState as
|
|
1920
|
+
import { useState as useState4, useEffect as useEffect4, useRef as useRef4, useCallback as useCallback9 } from "react";
|
|
1601
1921
|
|
|
1602
1922
|
// src/constants/colors.ts
|
|
1603
1923
|
var TEXT_COLORS = [
|
|
@@ -1631,13 +1951,13 @@ var getHexFromColorValue = (value, type) => {
|
|
|
1631
1951
|
};
|
|
1632
1952
|
|
|
1633
1953
|
// src/components/FloatingMenu/components/ColorButton.tsx
|
|
1634
|
-
import { jsx as
|
|
1954
|
+
import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1635
1955
|
var ColorButton = ({ editor, type }) => {
|
|
1636
|
-
const [isOpen, setIsOpen] =
|
|
1637
|
-
const [currentColor, setCurrentColor] =
|
|
1638
|
-
const dropdownRef =
|
|
1956
|
+
const [isOpen, setIsOpen] = useState4(false);
|
|
1957
|
+
const [currentColor, setCurrentColor] = useState4("default");
|
|
1958
|
+
const dropdownRef = useRef4(null);
|
|
1639
1959
|
const colors = type === "text" ? TEXT_COLORS : BACKGROUND_COLORS;
|
|
1640
|
-
const getCurrentColor =
|
|
1960
|
+
const getCurrentColor = useCallback9(() => {
|
|
1641
1961
|
try {
|
|
1642
1962
|
const activeStyles = editor?.getActiveStyles?.() || {};
|
|
1643
1963
|
if (type === "text" && activeStyles.textColor) {
|
|
@@ -1649,13 +1969,13 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1649
1969
|
}
|
|
1650
1970
|
return "default";
|
|
1651
1971
|
}, [editor, type]);
|
|
1652
|
-
|
|
1972
|
+
useEffect4(() => {
|
|
1653
1973
|
if (isOpen) {
|
|
1654
1974
|
const color = getCurrentColor();
|
|
1655
1975
|
setCurrentColor(color);
|
|
1656
1976
|
}
|
|
1657
1977
|
}, [isOpen, getCurrentColor]);
|
|
1658
|
-
|
|
1978
|
+
useEffect4(() => {
|
|
1659
1979
|
const handleClickOutside = (e) => {
|
|
1660
1980
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1661
1981
|
setIsOpen(false);
|
|
@@ -1664,7 +1984,7 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1664
1984
|
document.addEventListener("mousedown", handleClickOutside);
|
|
1665
1985
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1666
1986
|
}, []);
|
|
1667
|
-
const handleColorSelect =
|
|
1987
|
+
const handleColorSelect = useCallback9(
|
|
1668
1988
|
(color) => {
|
|
1669
1989
|
try {
|
|
1670
1990
|
if (!editor) return;
|
|
@@ -1681,11 +2001,11 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1681
2001
|
},
|
|
1682
2002
|
[editor, type]
|
|
1683
2003
|
);
|
|
1684
|
-
const handleMouseDown =
|
|
2004
|
+
const handleMouseDown = useCallback9((e) => {
|
|
1685
2005
|
e.preventDefault();
|
|
1686
2006
|
}, []);
|
|
1687
|
-
return /* @__PURE__ */
|
|
1688
|
-
/* @__PURE__ */
|
|
2007
|
+
return /* @__PURE__ */ jsxs6("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
|
|
2008
|
+
/* @__PURE__ */ jsxs6(
|
|
1689
2009
|
"button",
|
|
1690
2010
|
{
|
|
1691
2011
|
className: "lumir-toolbar-btn lumir-color-btn",
|
|
@@ -1695,7 +2015,7 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1695
2015
|
type: "button",
|
|
1696
2016
|
children: [
|
|
1697
2017
|
type === "text" ? Icons.textColor : Icons.bgColor,
|
|
1698
|
-
/* @__PURE__ */
|
|
2018
|
+
/* @__PURE__ */ jsx11(
|
|
1699
2019
|
"span",
|
|
1700
2020
|
{
|
|
1701
2021
|
className: "lumir-color-indicator",
|
|
@@ -1707,7 +2027,7 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1707
2027
|
]
|
|
1708
2028
|
}
|
|
1709
2029
|
),
|
|
1710
|
-
isOpen && /* @__PURE__ */
|
|
2030
|
+
isOpen && /* @__PURE__ */ jsx11("div", { className: "lumir-dropdown-menu lumir-color-menu", children: /* @__PURE__ */ jsx11("div", { className: "lumir-color-grid", children: colors.map((color) => /* @__PURE__ */ jsx11(
|
|
1711
2031
|
"button",
|
|
1712
2032
|
{
|
|
1713
2033
|
className: cn(
|
|
@@ -1726,8 +2046,8 @@ var ColorButton = ({ editor, type }) => {
|
|
|
1726
2046
|
};
|
|
1727
2047
|
|
|
1728
2048
|
// src/components/FloatingMenu/components/LinkButton.tsx
|
|
1729
|
-
import { useState as
|
|
1730
|
-
import { jsx as
|
|
2049
|
+
import { useState as useState5, useEffect as useEffect5, useRef as useRef5, useCallback as useCallback10 } from "react";
|
|
2050
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1731
2051
|
var isDangerousProtocol = (url) => {
|
|
1732
2052
|
const trimmedUrl = url.trim().toLowerCase();
|
|
1733
2053
|
const dangerousPatterns = [
|
|
@@ -1753,13 +2073,13 @@ var normalizeUrl = (url) => {
|
|
|
1753
2073
|
return `https://${trimmedUrl}`;
|
|
1754
2074
|
};
|
|
1755
2075
|
var LinkButton = ({ editor }) => {
|
|
1756
|
-
const [isOpen, setIsOpen] =
|
|
1757
|
-
const [linkUrl, setLinkUrl] =
|
|
1758
|
-
const [errorMsg, setErrorMsg] =
|
|
1759
|
-
const dropdownRef =
|
|
1760
|
-
const inputRef =
|
|
1761
|
-
const hasSelectionRef =
|
|
1762
|
-
|
|
2076
|
+
const [isOpen, setIsOpen] = useState5(false);
|
|
2077
|
+
const [linkUrl, setLinkUrl] = useState5("");
|
|
2078
|
+
const [errorMsg, setErrorMsg] = useState5(null);
|
|
2079
|
+
const dropdownRef = useRef5(null);
|
|
2080
|
+
const inputRef = useRef5(null);
|
|
2081
|
+
const hasSelectionRef = useRef5(false);
|
|
2082
|
+
useEffect5(() => {
|
|
1763
2083
|
const handleClickOutside = (e) => {
|
|
1764
2084
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1765
2085
|
setIsOpen(false);
|
|
@@ -1770,7 +2090,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1770
2090
|
document.addEventListener("mousedown", handleClickOutside);
|
|
1771
2091
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1772
2092
|
}, []);
|
|
1773
|
-
|
|
2093
|
+
useEffect5(() => {
|
|
1774
2094
|
if (isOpen && inputRef.current) {
|
|
1775
2095
|
try {
|
|
1776
2096
|
const selectedText = editor?.getSelectedText?.() || "";
|
|
@@ -1781,7 +2101,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1781
2101
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
1782
2102
|
}
|
|
1783
2103
|
}, [isOpen, editor]);
|
|
1784
|
-
const handleSubmit =
|
|
2104
|
+
const handleSubmit = useCallback10(
|
|
1785
2105
|
(e) => {
|
|
1786
2106
|
e?.preventDefault();
|
|
1787
2107
|
setErrorMsg(null);
|
|
@@ -1808,15 +2128,15 @@ var LinkButton = ({ editor }) => {
|
|
|
1808
2128
|
},
|
|
1809
2129
|
[editor, linkUrl]
|
|
1810
2130
|
);
|
|
1811
|
-
const handleCancel =
|
|
2131
|
+
const handleCancel = useCallback10(() => {
|
|
1812
2132
|
setIsOpen(false);
|
|
1813
2133
|
setLinkUrl("");
|
|
1814
2134
|
setErrorMsg(null);
|
|
1815
2135
|
}, []);
|
|
1816
|
-
const handleMouseDown =
|
|
2136
|
+
const handleMouseDown = useCallback10((e) => {
|
|
1817
2137
|
e.preventDefault();
|
|
1818
2138
|
}, []);
|
|
1819
|
-
const handleKeyDown =
|
|
2139
|
+
const handleKeyDown = useCallback10(
|
|
1820
2140
|
(e) => {
|
|
1821
2141
|
if (e.key === "Enter") {
|
|
1822
2142
|
handleSubmit();
|
|
@@ -1826,8 +2146,8 @@ var LinkButton = ({ editor }) => {
|
|
|
1826
2146
|
},
|
|
1827
2147
|
[handleSubmit, handleCancel]
|
|
1828
2148
|
);
|
|
1829
|
-
return /* @__PURE__ */
|
|
1830
|
-
/* @__PURE__ */
|
|
2149
|
+
return /* @__PURE__ */ jsxs7("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
|
|
2150
|
+
/* @__PURE__ */ jsx12(
|
|
1831
2151
|
"button",
|
|
1832
2152
|
{
|
|
1833
2153
|
className: "lumir-toolbar-btn",
|
|
@@ -1838,8 +2158,8 @@ var LinkButton = ({ editor }) => {
|
|
|
1838
2158
|
children: Icons.link
|
|
1839
2159
|
}
|
|
1840
2160
|
),
|
|
1841
|
-
isOpen && /* @__PURE__ */
|
|
1842
|
-
/* @__PURE__ */
|
|
2161
|
+
isOpen && /* @__PURE__ */ jsx12("div", { className: "lumir-dropdown-menu lumir-link-menu", children: /* @__PURE__ */ jsxs7("form", { onSubmit: handleSubmit, className: "lumir-link-form", children: [
|
|
2162
|
+
/* @__PURE__ */ jsx12(
|
|
1843
2163
|
"input",
|
|
1844
2164
|
{
|
|
1845
2165
|
ref: inputRef,
|
|
@@ -1855,7 +2175,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1855
2175
|
onMouseDown: handleMouseDown
|
|
1856
2176
|
}
|
|
1857
2177
|
),
|
|
1858
|
-
errorMsg && /* @__PURE__ */
|
|
2178
|
+
errorMsg && /* @__PURE__ */ jsx12(
|
|
1859
2179
|
"div",
|
|
1860
2180
|
{
|
|
1861
2181
|
style: {
|
|
@@ -1867,8 +2187,8 @@ var LinkButton = ({ editor }) => {
|
|
|
1867
2187
|
children: errorMsg
|
|
1868
2188
|
}
|
|
1869
2189
|
),
|
|
1870
|
-
/* @__PURE__ */
|
|
1871
|
-
/* @__PURE__ */
|
|
2190
|
+
/* @__PURE__ */ jsxs7("div", { className: "lumir-link-actions", children: [
|
|
2191
|
+
/* @__PURE__ */ jsx12(
|
|
1872
2192
|
"button",
|
|
1873
2193
|
{
|
|
1874
2194
|
type: "button",
|
|
@@ -1878,7 +2198,7 @@ var LinkButton = ({ editor }) => {
|
|
|
1878
2198
|
children: "\uCDE8\uC18C"
|
|
1879
2199
|
}
|
|
1880
2200
|
),
|
|
1881
|
-
/* @__PURE__ */
|
|
2201
|
+
/* @__PURE__ */ jsx12(
|
|
1882
2202
|
"button",
|
|
1883
2203
|
{
|
|
1884
2204
|
type: "submit",
|
|
@@ -1894,10 +2214,10 @@ var LinkButton = ({ editor }) => {
|
|
|
1894
2214
|
};
|
|
1895
2215
|
|
|
1896
2216
|
// src/components/FloatingMenu/components/TableButton.tsx
|
|
1897
|
-
import { useCallback as
|
|
1898
|
-
import { jsx as
|
|
2217
|
+
import { useCallback as useCallback11 } from "react";
|
|
2218
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1899
2219
|
var TableButton = ({ editor }) => {
|
|
1900
|
-
const handleClick =
|
|
2220
|
+
const handleClick = useCallback11(() => {
|
|
1901
2221
|
try {
|
|
1902
2222
|
const block = editor?.getTextCursorPosition()?.block;
|
|
1903
2223
|
if (!block || !editor?.insertBlocks) return;
|
|
@@ -1919,10 +2239,10 @@ var TableButton = ({ editor }) => {
|
|
|
1919
2239
|
console.error("Table insert failed:", err);
|
|
1920
2240
|
}
|
|
1921
2241
|
}, [editor]);
|
|
1922
|
-
const handleMouseDown =
|
|
2242
|
+
const handleMouseDown = useCallback11((e) => {
|
|
1923
2243
|
e.preventDefault();
|
|
1924
2244
|
}, []);
|
|
1925
|
-
return /* @__PURE__ */
|
|
2245
|
+
return /* @__PURE__ */ jsx13(
|
|
1926
2246
|
"button",
|
|
1927
2247
|
{
|
|
1928
2248
|
className: "lumir-toolbar-btn",
|
|
@@ -1936,13 +2256,13 @@ var TableButton = ({ editor }) => {
|
|
|
1936
2256
|
};
|
|
1937
2257
|
|
|
1938
2258
|
// src/components/FloatingMenu/components/HTMLImportButton.tsx
|
|
1939
|
-
import { useCallback as
|
|
1940
|
-
import { Fragment as
|
|
2259
|
+
import { useCallback as useCallback12, useRef as useRef6 } from "react";
|
|
2260
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1941
2261
|
var HTMLImportButton = ({
|
|
1942
2262
|
editor
|
|
1943
2263
|
}) => {
|
|
1944
|
-
const fileInputRef =
|
|
1945
|
-
const handleFileUpload =
|
|
2264
|
+
const fileInputRef = useRef6(null);
|
|
2265
|
+
const handleFileUpload = useCallback12(
|
|
1946
2266
|
(e) => {
|
|
1947
2267
|
const file = e.target.files?.[0];
|
|
1948
2268
|
if (!file) return;
|
|
@@ -1978,14 +2298,14 @@ var HTMLImportButton = ({
|
|
|
1978
2298
|
},
|
|
1979
2299
|
[editor]
|
|
1980
2300
|
);
|
|
1981
|
-
const handleClick =
|
|
2301
|
+
const handleClick = useCallback12(() => {
|
|
1982
2302
|
fileInputRef.current?.click();
|
|
1983
2303
|
}, []);
|
|
1984
|
-
const handleMouseDown =
|
|
2304
|
+
const handleMouseDown = useCallback12((e) => {
|
|
1985
2305
|
e.preventDefault();
|
|
1986
2306
|
}, []);
|
|
1987
|
-
return /* @__PURE__ */
|
|
1988
|
-
/* @__PURE__ */
|
|
2307
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
2308
|
+
/* @__PURE__ */ jsx14(
|
|
1989
2309
|
"input",
|
|
1990
2310
|
{
|
|
1991
2311
|
ref: fileInputRef,
|
|
@@ -1995,7 +2315,7 @@ var HTMLImportButton = ({
|
|
|
1995
2315
|
style: { display: "none" }
|
|
1996
2316
|
}
|
|
1997
2317
|
),
|
|
1998
|
-
/* @__PURE__ */
|
|
2318
|
+
/* @__PURE__ */ jsx14(
|
|
1999
2319
|
"button",
|
|
2000
2320
|
{
|
|
2001
2321
|
className: "lumir-toolbar-btn",
|
|
@@ -2010,8 +2330,8 @@ var HTMLImportButton = ({
|
|
|
2010
2330
|
};
|
|
2011
2331
|
|
|
2012
2332
|
// src/components/FloatingMenu/components/BlockTypeSelect.tsx
|
|
2013
|
-
import { useState as
|
|
2014
|
-
import { jsx as
|
|
2333
|
+
import { useState as useState6, useEffect as useEffect6, useRef as useRef7, useCallback as useCallback13 } from "react";
|
|
2334
|
+
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2015
2335
|
var blockTypeCategories = [
|
|
2016
2336
|
{
|
|
2017
2337
|
category: "Headings",
|
|
@@ -2041,8 +2361,8 @@ var blockTypes = blockTypeCategories.flatMap(
|
|
|
2041
2361
|
(cat) => cat.items
|
|
2042
2362
|
);
|
|
2043
2363
|
var BlockTypeSelect = ({ editor }) => {
|
|
2044
|
-
const [isOpen, setIsOpen] =
|
|
2045
|
-
const dropdownRef =
|
|
2364
|
+
const [isOpen, setIsOpen] = useState6(false);
|
|
2365
|
+
const dropdownRef = useRef7(null);
|
|
2046
2366
|
const getCurrentBlock = () => {
|
|
2047
2367
|
try {
|
|
2048
2368
|
return editor?.getTextCursorPosition()?.block;
|
|
@@ -2054,7 +2374,7 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2054
2374
|
const currentType = currentBlock?.type || "paragraph";
|
|
2055
2375
|
const currentLevel = currentBlock?.props?.level;
|
|
2056
2376
|
const isCurrentToggle = currentType === "heading" && currentBlock?.props?.isToggleable === true;
|
|
2057
|
-
|
|
2377
|
+
useEffect6(() => {
|
|
2058
2378
|
const handleClickOutside = (e) => {
|
|
2059
2379
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
2060
2380
|
setIsOpen(false);
|
|
@@ -2083,7 +2403,7 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2083
2403
|
console.error("Block type change failed:", err);
|
|
2084
2404
|
}
|
|
2085
2405
|
};
|
|
2086
|
-
const handleMouseDown =
|
|
2406
|
+
const handleMouseDown = useCallback13((e) => {
|
|
2087
2407
|
e.preventDefault();
|
|
2088
2408
|
}, []);
|
|
2089
2409
|
const getCurrentLabel = () => {
|
|
@@ -2114,8 +2434,8 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2114
2434
|
}
|
|
2115
2435
|
return currentType === bt.type;
|
|
2116
2436
|
};
|
|
2117
|
-
return /* @__PURE__ */
|
|
2118
|
-
/* @__PURE__ */
|
|
2437
|
+
return /* @__PURE__ */ jsxs9("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
|
|
2438
|
+
/* @__PURE__ */ jsxs9(
|
|
2119
2439
|
"button",
|
|
2120
2440
|
{
|
|
2121
2441
|
className: "lumir-dropdown-btn lumir-block-type-btn",
|
|
@@ -2123,15 +2443,15 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2123
2443
|
onMouseDown: handleMouseDown,
|
|
2124
2444
|
type: "button",
|
|
2125
2445
|
children: [
|
|
2126
|
-
/* @__PURE__ */
|
|
2127
|
-
/* @__PURE__ */
|
|
2446
|
+
/* @__PURE__ */ jsx15("span", { className: "lumir-block-icon", children: BlockTypeIcons[getCurrentIcon()] }),
|
|
2447
|
+
/* @__PURE__ */ jsx15("span", { className: "lumir-block-label", children: getCurrentLabel() }),
|
|
2128
2448
|
Icons.expandMore
|
|
2129
2449
|
]
|
|
2130
2450
|
}
|
|
2131
2451
|
),
|
|
2132
|
-
isOpen && /* @__PURE__ */
|
|
2133
|
-
/* @__PURE__ */
|
|
2134
|
-
category.items.map((bt) => /* @__PURE__ */
|
|
2452
|
+
isOpen && /* @__PURE__ */ jsx15("div", { className: "lumir-dropdown-menu lumir-block-menu", children: blockTypeCategories.map((category) => /* @__PURE__ */ jsxs9("div", { className: "lumir-block-category", children: [
|
|
2453
|
+
/* @__PURE__ */ jsx15("div", { className: "lumir-block-category-title", children: category.category }),
|
|
2454
|
+
category.items.map((bt) => /* @__PURE__ */ jsxs9(
|
|
2135
2455
|
"button",
|
|
2136
2456
|
{
|
|
2137
2457
|
className: cn(
|
|
@@ -2141,8 +2461,8 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2141
2461
|
onClick: () => handleTypeChange(bt.type, bt.level, bt.isToggle),
|
|
2142
2462
|
onMouseDown: handleMouseDown,
|
|
2143
2463
|
children: [
|
|
2144
|
-
/* @__PURE__ */
|
|
2145
|
-
/* @__PURE__ */
|
|
2464
|
+
/* @__PURE__ */ jsx15("span", { className: "lumir-block-icon", children: BlockTypeIcons[bt.icon] }),
|
|
2465
|
+
/* @__PURE__ */ jsx15("span", { className: "lumir-block-item-title", children: bt.label })
|
|
2146
2466
|
]
|
|
2147
2467
|
},
|
|
2148
2468
|
bt.icon
|
|
@@ -2152,7 +2472,7 @@ var BlockTypeSelect = ({ editor }) => {
|
|
|
2152
2472
|
};
|
|
2153
2473
|
|
|
2154
2474
|
// src/components/FloatingMenu/index.tsx
|
|
2155
|
-
import { Fragment as
|
|
2475
|
+
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2156
2476
|
var COMPACT_BREAKPOINT = 700;
|
|
2157
2477
|
var MINIMIZED_BREAKPOINT = 400;
|
|
2158
2478
|
var FloatingMenu = ({
|
|
@@ -2161,12 +2481,12 @@ var FloatingMenu = ({
|
|
|
2161
2481
|
className,
|
|
2162
2482
|
onImageUpload
|
|
2163
2483
|
}) => {
|
|
2164
|
-
const wrapperRef =
|
|
2165
|
-
const [isCompact, setIsCompact] =
|
|
2166
|
-
const [isMinimizable, setIsMinimizable] =
|
|
2167
|
-
const [isMinimized, setIsMinimized] =
|
|
2168
|
-
const [, setSelectionTick] =
|
|
2169
|
-
|
|
2484
|
+
const wrapperRef = useRef8(null);
|
|
2485
|
+
const [isCompact, setIsCompact] = useState7(false);
|
|
2486
|
+
const [isMinimizable, setIsMinimizable] = useState7(false);
|
|
2487
|
+
const [isMinimized, setIsMinimized] = useState7(false);
|
|
2488
|
+
const [, setSelectionTick] = useState7(0);
|
|
2489
|
+
useEffect7(() => {
|
|
2170
2490
|
if (!editor) return;
|
|
2171
2491
|
let debounceTimer = null;
|
|
2172
2492
|
const DEBOUNCE_DELAY = 150;
|
|
@@ -2190,7 +2510,7 @@ var FloatingMenu = ({
|
|
|
2190
2510
|
unsubscribeContent?.();
|
|
2191
2511
|
};
|
|
2192
2512
|
}, [editor]);
|
|
2193
|
-
|
|
2513
|
+
useEffect7(() => {
|
|
2194
2514
|
const checkWidth = () => {
|
|
2195
2515
|
if (wrapperRef.current) {
|
|
2196
2516
|
const width = wrapperRef.current.offsetWidth;
|
|
@@ -2205,8 +2525,8 @@ var FloatingMenu = ({
|
|
|
2205
2525
|
}
|
|
2206
2526
|
return () => resizeObserver.disconnect();
|
|
2207
2527
|
}, []);
|
|
2208
|
-
const MinimizedLayout = () => /* @__PURE__ */
|
|
2209
|
-
/* @__PURE__ */
|
|
2528
|
+
const MinimizedLayout = () => /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
2529
|
+
/* @__PURE__ */ jsx16(
|
|
2210
2530
|
"button",
|
|
2211
2531
|
{
|
|
2212
2532
|
className: "lumir-toolbar-button lumir-toggle-button",
|
|
@@ -2217,117 +2537,117 @@ var FloatingMenu = ({
|
|
|
2217
2537
|
children: isMinimized ? Icons.chevronRight : Icons.chevronLeft
|
|
2218
2538
|
}
|
|
2219
2539
|
),
|
|
2220
|
-
!isMinimized && /* @__PURE__ */
|
|
2221
|
-
/* @__PURE__ */
|
|
2222
|
-
/* @__PURE__ */
|
|
2223
|
-
/* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2226
|
-
/* @__PURE__ */
|
|
2227
|
-
/* @__PURE__ */
|
|
2228
|
-
/* @__PURE__ */
|
|
2229
|
-
/* @__PURE__ */
|
|
2230
|
-
/* @__PURE__ */
|
|
2540
|
+
!isMinimized && /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
2541
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2542
|
+
/* @__PURE__ */ jsx16(UndoRedoButtons, { editor }),
|
|
2543
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2544
|
+
/* @__PURE__ */ jsx16("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ jsx16(BlockTypeSelect, { editor }) }),
|
|
2545
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2546
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2547
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "bold" }),
|
|
2548
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "italic" }),
|
|
2549
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "underline" }),
|
|
2550
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "strike" })
|
|
2231
2551
|
] }),
|
|
2232
|
-
/* @__PURE__ */
|
|
2233
|
-
/* @__PURE__ */
|
|
2234
|
-
/* @__PURE__ */
|
|
2235
|
-
/* @__PURE__ */
|
|
2236
|
-
/* @__PURE__ */
|
|
2552
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2553
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2554
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "left" }),
|
|
2555
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "center" }),
|
|
2556
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "right" })
|
|
2237
2557
|
] }),
|
|
2238
|
-
/* @__PURE__ */
|
|
2239
|
-
/* @__PURE__ */
|
|
2240
|
-
/* @__PURE__ */
|
|
2241
|
-
/* @__PURE__ */
|
|
2558
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2559
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2560
|
+
/* @__PURE__ */ jsx16(ListButton, { editor, type: "bullet" }),
|
|
2561
|
+
/* @__PURE__ */ jsx16(ListButton, { editor, type: "numbered" })
|
|
2242
2562
|
] }),
|
|
2243
|
-
/* @__PURE__ */
|
|
2244
|
-
/* @__PURE__ */
|
|
2245
|
-
/* @__PURE__ */
|
|
2246
|
-
/* @__PURE__ */
|
|
2563
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2564
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2565
|
+
/* @__PURE__ */ jsx16(ColorButton, { editor, type: "text" }),
|
|
2566
|
+
/* @__PURE__ */ jsx16(ColorButton, { editor, type: "background" })
|
|
2247
2567
|
] }),
|
|
2248
|
-
/* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2250
|
-
/* @__PURE__ */
|
|
2251
|
-
/* @__PURE__ */
|
|
2252
|
-
/* @__PURE__ */
|
|
2253
|
-
/* @__PURE__ */
|
|
2568
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2569
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2570
|
+
/* @__PURE__ */ jsx16(ImageButton, { editor, onImageUpload }),
|
|
2571
|
+
/* @__PURE__ */ jsx16(LinkButton, { editor }),
|
|
2572
|
+
/* @__PURE__ */ jsx16(TableButton, { editor }),
|
|
2573
|
+
/* @__PURE__ */ jsx16(HTMLImportButton, { editor })
|
|
2254
2574
|
] })
|
|
2255
2575
|
] })
|
|
2256
2576
|
] });
|
|
2257
|
-
const SingleRowLayout = () => /* @__PURE__ */
|
|
2258
|
-
/* @__PURE__ */
|
|
2259
|
-
/* @__PURE__ */
|
|
2260
|
-
/* @__PURE__ */
|
|
2261
|
-
/* @__PURE__ */
|
|
2262
|
-
/* @__PURE__ */
|
|
2263
|
-
/* @__PURE__ */
|
|
2264
|
-
/* @__PURE__ */
|
|
2265
|
-
/* @__PURE__ */
|
|
2266
|
-
/* @__PURE__ */
|
|
2577
|
+
const SingleRowLayout = () => /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
2578
|
+
/* @__PURE__ */ jsx16(UndoRedoButtons, { editor }),
|
|
2579
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2580
|
+
/* @__PURE__ */ jsx16("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ jsx16(BlockTypeSelect, { editor }) }),
|
|
2581
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2582
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2583
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "bold" }),
|
|
2584
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "italic" }),
|
|
2585
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "underline" }),
|
|
2586
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "strike" })
|
|
2267
2587
|
] }),
|
|
2268
|
-
/* @__PURE__ */
|
|
2269
|
-
/* @__PURE__ */
|
|
2270
|
-
/* @__PURE__ */
|
|
2271
|
-
/* @__PURE__ */
|
|
2272
|
-
/* @__PURE__ */
|
|
2588
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2589
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2590
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "left" }),
|
|
2591
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "center" }),
|
|
2592
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "right" })
|
|
2273
2593
|
] }),
|
|
2274
|
-
/* @__PURE__ */
|
|
2275
|
-
/* @__PURE__ */
|
|
2276
|
-
/* @__PURE__ */
|
|
2277
|
-
/* @__PURE__ */
|
|
2594
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2595
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2596
|
+
/* @__PURE__ */ jsx16(ListButton, { editor, type: "bullet" }),
|
|
2597
|
+
/* @__PURE__ */ jsx16(ListButton, { editor, type: "numbered" })
|
|
2278
2598
|
] }),
|
|
2279
|
-
/* @__PURE__ */
|
|
2280
|
-
/* @__PURE__ */
|
|
2281
|
-
/* @__PURE__ */
|
|
2282
|
-
/* @__PURE__ */
|
|
2599
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2600
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2601
|
+
/* @__PURE__ */ jsx16(ColorButton, { editor, type: "text" }),
|
|
2602
|
+
/* @__PURE__ */ jsx16(ColorButton, { editor, type: "background" })
|
|
2283
2603
|
] }),
|
|
2284
|
-
/* @__PURE__ */
|
|
2285
|
-
/* @__PURE__ */
|
|
2286
|
-
/* @__PURE__ */
|
|
2287
|
-
/* @__PURE__ */
|
|
2288
|
-
/* @__PURE__ */
|
|
2289
|
-
/* @__PURE__ */
|
|
2604
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2605
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2606
|
+
/* @__PURE__ */ jsx16(ImageButton, { editor, onImageUpload }),
|
|
2607
|
+
/* @__PURE__ */ jsx16(LinkButton, { editor }),
|
|
2608
|
+
/* @__PURE__ */ jsx16(TableButton, { editor }),
|
|
2609
|
+
/* @__PURE__ */ jsx16(HTMLImportButton, { editor })
|
|
2290
2610
|
] })
|
|
2291
2611
|
] });
|
|
2292
|
-
const TwoRowLayout = () => /* @__PURE__ */
|
|
2293
|
-
/* @__PURE__ */
|
|
2294
|
-
/* @__PURE__ */
|
|
2295
|
-
/* @__PURE__ */
|
|
2296
|
-
/* @__PURE__ */
|
|
2297
|
-
/* @__PURE__ */
|
|
2298
|
-
/* @__PURE__ */
|
|
2299
|
-
/* @__PURE__ */
|
|
2300
|
-
/* @__PURE__ */
|
|
2612
|
+
const TwoRowLayout = () => /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
2613
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-row", children: [
|
|
2614
|
+
/* @__PURE__ */ jsx16(UndoRedoButtons, { editor }),
|
|
2615
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2616
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2617
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "bold" }),
|
|
2618
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "italic" }),
|
|
2619
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "underline" }),
|
|
2620
|
+
/* @__PURE__ */ jsx16(TextStyleButton, { editor, style: "strike" })
|
|
2301
2621
|
] }),
|
|
2302
|
-
/* @__PURE__ */
|
|
2303
|
-
/* @__PURE__ */
|
|
2304
|
-
/* @__PURE__ */
|
|
2305
|
-
/* @__PURE__ */
|
|
2306
|
-
/* @__PURE__ */
|
|
2622
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2623
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2624
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "left" }),
|
|
2625
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "center" }),
|
|
2626
|
+
/* @__PURE__ */ jsx16(AlignButton, { editor, alignment: "right" })
|
|
2307
2627
|
] }),
|
|
2308
|
-
/* @__PURE__ */
|
|
2309
|
-
/* @__PURE__ */
|
|
2310
|
-
/* @__PURE__ */
|
|
2311
|
-
/* @__PURE__ */
|
|
2628
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2629
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2630
|
+
/* @__PURE__ */ jsx16(ListButton, { editor, type: "bullet" }),
|
|
2631
|
+
/* @__PURE__ */ jsx16(ListButton, { editor, type: "numbered" })
|
|
2312
2632
|
] })
|
|
2313
2633
|
] }),
|
|
2314
|
-
/* @__PURE__ */
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
/* @__PURE__ */
|
|
2317
|
-
/* @__PURE__ */
|
|
2318
|
-
/* @__PURE__ */
|
|
2319
|
-
/* @__PURE__ */
|
|
2634
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-row", children: [
|
|
2635
|
+
/* @__PURE__ */ jsx16("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ jsx16(BlockTypeSelect, { editor }) }),
|
|
2636
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2637
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2638
|
+
/* @__PURE__ */ jsx16(ColorButton, { editor, type: "text" }),
|
|
2639
|
+
/* @__PURE__ */ jsx16(ColorButton, { editor, type: "background" })
|
|
2320
2640
|
] }),
|
|
2321
|
-
/* @__PURE__ */
|
|
2322
|
-
/* @__PURE__ */
|
|
2323
|
-
/* @__PURE__ */
|
|
2324
|
-
/* @__PURE__ */
|
|
2325
|
-
/* @__PURE__ */
|
|
2326
|
-
/* @__PURE__ */
|
|
2641
|
+
/* @__PURE__ */ jsx16(ToolbarDivider, {}),
|
|
2642
|
+
/* @__PURE__ */ jsxs10("div", { className: "lumir-toolbar-group", children: [
|
|
2643
|
+
/* @__PURE__ */ jsx16(ImageButton, { editor, onImageUpload }),
|
|
2644
|
+
/* @__PURE__ */ jsx16(LinkButton, { editor }),
|
|
2645
|
+
/* @__PURE__ */ jsx16(TableButton, { editor }),
|
|
2646
|
+
/* @__PURE__ */ jsx16(HTMLImportButton, { editor })
|
|
2327
2647
|
] })
|
|
2328
2648
|
] })
|
|
2329
2649
|
] });
|
|
2330
|
-
return /* @__PURE__ */
|
|
2650
|
+
return /* @__PURE__ */ jsx16(
|
|
2331
2651
|
"div",
|
|
2332
2652
|
{
|
|
2333
2653
|
ref: wrapperRef,
|
|
@@ -2337,7 +2657,7 @@ var FloatingMenu = ({
|
|
|
2337
2657
|
className
|
|
2338
2658
|
),
|
|
2339
2659
|
"data-position": position,
|
|
2340
|
-
children: /* @__PURE__ */
|
|
2660
|
+
children: /* @__PURE__ */ jsx16(
|
|
2341
2661
|
"div",
|
|
2342
2662
|
{
|
|
2343
2663
|
className: cn(
|
|
@@ -2346,7 +2666,7 @@ var FloatingMenu = ({
|
|
|
2346
2666
|
isMinimizable && "is-minimizable",
|
|
2347
2667
|
isMinimized && "is-minimized"
|
|
2348
2668
|
),
|
|
2349
|
-
children: isMinimizable ? /* @__PURE__ */
|
|
2669
|
+
children: isMinimizable ? /* @__PURE__ */ jsx16(MinimizedLayout, {}) : isCompact ? /* @__PURE__ */ jsx16(TwoRowLayout, {}) : /* @__PURE__ */ jsx16(SingleRowLayout, {})
|
|
2350
2670
|
}
|
|
2351
2671
|
)
|
|
2352
2672
|
}
|
|
@@ -2417,15 +2737,14 @@ var LumirEditorError = class _LumirEditorError extends Error {
|
|
|
2417
2737
|
}
|
|
2418
2738
|
/**
|
|
2419
2739
|
* 잘못된 파일 형식 에러 생성
|
|
2740
|
+
* @param allowVideoUpload true이면 "image and video" 메시지 사용
|
|
2420
2741
|
*/
|
|
2421
|
-
static invalidFileType(fileName) {
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
}
|
|
2428
|
-
);
|
|
2742
|
+
static invalidFileType(fileName, allowVideoUpload) {
|
|
2743
|
+
const message = allowVideoUpload === true ? `Invalid file type: ${fileName}. Only image and video files are allowed.` : `Invalid file type: ${fileName}. Only image files are allowed.`;
|
|
2744
|
+
return new _LumirEditorError(message, {
|
|
2745
|
+
code: "INVALID_FILE_TYPE",
|
|
2746
|
+
context: { fileName }
|
|
2747
|
+
});
|
|
2429
2748
|
}
|
|
2430
2749
|
/**
|
|
2431
2750
|
* S3 설정 에러 생성
|
|
@@ -2448,10 +2767,38 @@ var LumirEditorError = class _LumirEditorError extends Error {
|
|
|
2448
2767
|
|
|
2449
2768
|
// src/constants/limits.ts
|
|
2450
2769
|
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
2770
|
+
var MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;
|
|
2451
2771
|
var BLOCKED_EXTENSIONS = [".svg", ".svgz"];
|
|
2772
|
+
var ALLOWED_VIDEO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
2773
|
+
"video/mp4",
|
|
2774
|
+
"video/webm",
|
|
2775
|
+
"video/ogg",
|
|
2776
|
+
"video/quicktime"
|
|
2777
|
+
// .mov
|
|
2778
|
+
]);
|
|
2779
|
+
var ALLOWED_VIDEO_EXTENSIONS = [
|
|
2780
|
+
".mp4",
|
|
2781
|
+
".webm",
|
|
2782
|
+
".ogg",
|
|
2783
|
+
".mov"
|
|
2784
|
+
];
|
|
2452
2785
|
|
|
2453
2786
|
// src/components/LumirEditor.tsx
|
|
2454
|
-
import { jsx as
|
|
2787
|
+
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2788
|
+
var DEBUG_LOG = (loc, msg, data) => {
|
|
2789
|
+
fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
2790
|
+
method: "POST",
|
|
2791
|
+
headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "b73262" },
|
|
2792
|
+
body: JSON.stringify({
|
|
2793
|
+
sessionId: "b73262",
|
|
2794
|
+
location: loc,
|
|
2795
|
+
message: msg,
|
|
2796
|
+
data,
|
|
2797
|
+
timestamp: Date.now()
|
|
2798
|
+
})
|
|
2799
|
+
}).catch(() => {
|
|
2800
|
+
});
|
|
2801
|
+
};
|
|
2455
2802
|
var ContentUtils = class {
|
|
2456
2803
|
/**
|
|
2457
2804
|
* JSON 문자열의 유효성을 검증합니다
|
|
@@ -2580,6 +2927,25 @@ var isImageFile = (file) => {
|
|
|
2580
2927
|
}
|
|
2581
2928
|
return file.type?.startsWith("image/") || !file.type && /\.(png|jpe?g|gif|webp|bmp)$/i.test(fileName);
|
|
2582
2929
|
};
|
|
2930
|
+
var isVideoFile = (file) => {
|
|
2931
|
+
const sizeOk = file.size > 0 && file.size <= MAX_VIDEO_FILE_SIZE;
|
|
2932
|
+
const fileName = file.name?.toLowerCase() || "";
|
|
2933
|
+
const mimeMatch = ALLOWED_VIDEO_MIME_TYPES.has(file.type);
|
|
2934
|
+
const videoPrefix = typeof file.type === "string" && file.type.startsWith("video/");
|
|
2935
|
+
const extMatch = !file.type && ALLOWED_VIDEO_EXTENSIONS.some((ext) => fileName.endsWith(ext));
|
|
2936
|
+
const result = sizeOk && (mimeMatch || videoPrefix || extMatch);
|
|
2937
|
+
DEBUG_LOG("isVideoFile:check", "result", {
|
|
2938
|
+
fileName: file.name,
|
|
2939
|
+
fileType: file.type,
|
|
2940
|
+
fileSize: file.size,
|
|
2941
|
+
sizeOk,
|
|
2942
|
+
mimeMatch,
|
|
2943
|
+
videoPrefix,
|
|
2944
|
+
extMatch,
|
|
2945
|
+
result
|
|
2946
|
+
});
|
|
2947
|
+
return result;
|
|
2948
|
+
};
|
|
2583
2949
|
var isHtmlFile = (file) => {
|
|
2584
2950
|
return file.size > 0 && (file.type === "text/html" || file.name?.toLowerCase().endsWith(".html") || file.name?.toLowerCase().endsWith(".htm"));
|
|
2585
2951
|
};
|
|
@@ -2593,15 +2959,17 @@ var escapeHtml = (str) => {
|
|
|
2593
2959
|
};
|
|
2594
2960
|
return str.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
|
|
2595
2961
|
};
|
|
2596
|
-
var
|
|
2962
|
+
var extractMediaUrls = (blocks) => {
|
|
2597
2963
|
const urls = /* @__PURE__ */ new Set();
|
|
2598
2964
|
const traverse = (blockList) => {
|
|
2599
2965
|
for (const block of blockList) {
|
|
2600
2966
|
if (block.type === "image" && block.props?.url) {
|
|
2601
2967
|
const url = block.props.url;
|
|
2602
|
-
if (typeof url === "string" && url.trim())
|
|
2603
|
-
|
|
2604
|
-
|
|
2968
|
+
if (typeof url === "string" && url.trim()) urls.add(url);
|
|
2969
|
+
}
|
|
2970
|
+
if (block.type === "video" && block.props?.url) {
|
|
2971
|
+
const url = block.props.url;
|
|
2972
|
+
if (typeof url === "string" && url.trim()) urls.add(url);
|
|
2605
2973
|
}
|
|
2606
2974
|
if (block.children && Array.isArray(block.children)) {
|
|
2607
2975
|
traverse(block.children);
|
|
@@ -2611,12 +2979,10 @@ var extractImageUrls = (blocks) => {
|
|
|
2611
2979
|
traverse(blocks);
|
|
2612
2980
|
return urls;
|
|
2613
2981
|
};
|
|
2614
|
-
var
|
|
2982
|
+
var findDeletedMediaUrls = (previousUrls, currentUrls) => {
|
|
2615
2983
|
const deleted = [];
|
|
2616
2984
|
previousUrls.forEach((url) => {
|
|
2617
|
-
if (!currentUrls.has(url))
|
|
2618
|
-
deleted.push(url);
|
|
2619
|
-
}
|
|
2985
|
+
if (!currentUrls.has(url)) deleted.push(url);
|
|
2620
2986
|
});
|
|
2621
2987
|
return deleted;
|
|
2622
2988
|
};
|
|
@@ -2642,7 +3008,7 @@ var findBlockWithLink = (blocks, targetUrl) => {
|
|
|
2642
3008
|
var ConvertToPreviewButton = ({ url }) => {
|
|
2643
3009
|
const editor = useBlockNoteEditor();
|
|
2644
3010
|
const Components = useComponentsContext();
|
|
2645
|
-
return /* @__PURE__ */
|
|
3011
|
+
return /* @__PURE__ */ jsx17(
|
|
2646
3012
|
Components.LinkToolbar.Button,
|
|
2647
3013
|
{
|
|
2648
3014
|
className: "bn-button",
|
|
@@ -2661,10 +3027,10 @@ var ConvertToPreviewButton = ({ url }) => {
|
|
|
2661
3027
|
console.error("Convert to link preview failed:", err);
|
|
2662
3028
|
}
|
|
2663
3029
|
},
|
|
2664
|
-
icon: /* @__PURE__ */
|
|
2665
|
-
/* @__PURE__ */
|
|
2666
|
-
/* @__PURE__ */
|
|
2667
|
-
/* @__PURE__ */
|
|
3030
|
+
icon: /* @__PURE__ */ jsxs11("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
3031
|
+
/* @__PURE__ */ jsx17("rect", { x: "1", y: "3", width: "14", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.5", fill: "none" }),
|
|
3032
|
+
/* @__PURE__ */ jsx17("line", { x1: "1", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
3033
|
+
/* @__PURE__ */ jsx17("circle", { cx: "5", cy: "6.5", r: "1.5", stroke: "currentColor", strokeWidth: "1", fill: "none" })
|
|
2668
3034
|
] })
|
|
2669
3035
|
}
|
|
2670
3036
|
);
|
|
@@ -2673,17 +3039,17 @@ var CustomLinkToolbar = (props) => {
|
|
|
2673
3039
|
const editor = useBlockNoteEditor();
|
|
2674
3040
|
const Components = useComponentsContext();
|
|
2675
3041
|
const hasLinkPreview = !!editor?._linkPreviewApiEndpoint;
|
|
2676
|
-
return /* @__PURE__ */
|
|
3042
|
+
return /* @__PURE__ */ jsxs11(
|
|
2677
3043
|
Components.LinkToolbar.Root,
|
|
2678
3044
|
{
|
|
2679
3045
|
className: "bn-toolbar bn-link-toolbar",
|
|
2680
3046
|
onMouseEnter: props.stopHideTimer,
|
|
2681
3047
|
onMouseLeave: props.startHideTimer,
|
|
2682
3048
|
children: [
|
|
2683
|
-
/* @__PURE__ */
|
|
2684
|
-
/* @__PURE__ */
|
|
2685
|
-
/* @__PURE__ */
|
|
2686
|
-
hasLinkPreview && /* @__PURE__ */
|
|
3049
|
+
/* @__PURE__ */ jsx17(EditLinkButton, { url: props.url, text: props.text, editLink: props.editLink }),
|
|
3050
|
+
/* @__PURE__ */ jsx17(OpenLinkButton, { url: props.url }),
|
|
3051
|
+
/* @__PURE__ */ jsx17(DeleteLinkButton, { deleteLink: props.deleteLink }),
|
|
3052
|
+
hasLinkPreview && /* @__PURE__ */ jsx17(ConvertToPreviewButton, { url: props.url })
|
|
2687
3053
|
]
|
|
2688
3054
|
}
|
|
2689
3055
|
);
|
|
@@ -2725,9 +3091,13 @@ function LumirEditor({
|
|
|
2725
3091
|
onError,
|
|
2726
3092
|
onImageDelete
|
|
2727
3093
|
}) {
|
|
2728
|
-
const [isUploading, setIsUploading] =
|
|
2729
|
-
const [
|
|
2730
|
-
const
|
|
3094
|
+
const [isUploading, setIsUploading] = useState8(false);
|
|
3095
|
+
const [uploadProgress, setUploadProgress] = useState8(null);
|
|
3096
|
+
const [errorMessage, setErrorMessage] = useState8(null);
|
|
3097
|
+
const floatingMenuFileInputRef = useRef9(null);
|
|
3098
|
+
const floatingMenuBlockRef = useRef9(null);
|
|
3099
|
+
const floatingMenuUploadStartTimeRef = useRef9(0);
|
|
3100
|
+
const handleError = useCallback14(
|
|
2731
3101
|
(error) => {
|
|
2732
3102
|
onError?.(error);
|
|
2733
3103
|
setErrorMessage(error.getUserMessage());
|
|
@@ -2757,8 +3127,15 @@ function LumirEditor({
|
|
|
2757
3127
|
allowFileUpload
|
|
2758
3128
|
);
|
|
2759
3129
|
}, [disableExtensions, allowVideoUpload, allowAudioUpload, allowFileUpload]);
|
|
2760
|
-
|
|
2761
|
-
|
|
3130
|
+
useEffect8(() => {
|
|
3131
|
+
DEBUG_LOG("LumirEditor:init:disabledExtensions", "snapshot", {
|
|
3132
|
+
allowVideoUpload,
|
|
3133
|
+
hasVideoInDisabled: disabledExtensions.includes("video"),
|
|
3134
|
+
disabledList: disabledExtensions.slice(0, 15)
|
|
3135
|
+
});
|
|
3136
|
+
}, [allowVideoUpload, disabledExtensions]);
|
|
3137
|
+
const fileNameTransformRef = useRef9(s3Upload?.fileNameTransform);
|
|
3138
|
+
useEffect8(() => {
|
|
2762
3139
|
fileNameTransformRef.current = s3Upload?.fileNameTransform;
|
|
2763
3140
|
}, [s3Upload?.fileNameTransform]);
|
|
2764
3141
|
const memoizedS3Upload = useMemo(() => {
|
|
@@ -2769,6 +3146,12 @@ function LumirEditor({
|
|
|
2769
3146
|
path: s3Upload.path,
|
|
2770
3147
|
appendUUID: s3Upload.appendUUID,
|
|
2771
3148
|
preserveExtension: s3Upload.preserveExtension,
|
|
3149
|
+
uploadTimeoutMs: s3Upload.uploadTimeoutMs,
|
|
3150
|
+
maxRetries: s3Upload.maxRetries,
|
|
3151
|
+
onProgress: (percent) => {
|
|
3152
|
+
setUploadProgress(percent);
|
|
3153
|
+
s3Upload.onProgress?.(percent);
|
|
3154
|
+
},
|
|
2772
3155
|
// 최신 콜백을 항상 사용하도록 ref를 통해 접근
|
|
2773
3156
|
fileNameTransform: (originalName, file) => {
|
|
2774
3157
|
return fileNameTransformRef.current ? fileNameTransformRef.current(originalName, file) : originalName;
|
|
@@ -2779,7 +3162,10 @@ function LumirEditor({
|
|
|
2779
3162
|
s3Upload?.env,
|
|
2780
3163
|
s3Upload?.path,
|
|
2781
3164
|
s3Upload?.appendUUID,
|
|
2782
|
-
s3Upload?.preserveExtension
|
|
3165
|
+
s3Upload?.preserveExtension,
|
|
3166
|
+
s3Upload?.uploadTimeoutMs,
|
|
3167
|
+
s3Upload?.maxRetries,
|
|
3168
|
+
s3Upload?.onProgress
|
|
2783
3169
|
]);
|
|
2784
3170
|
const editor = useCreateBlockNote(
|
|
2785
3171
|
{
|
|
@@ -2797,18 +3183,44 @@ function LumirEditor({
|
|
|
2797
3183
|
tabBehavior,
|
|
2798
3184
|
trailingBlock,
|
|
2799
3185
|
uploadFile: async (file) => {
|
|
2800
|
-
|
|
2801
|
-
|
|
3186
|
+
const allowedImage = isImageFile(file);
|
|
3187
|
+
const allowedVideo = allowVideoUpload && isVideoFile(file);
|
|
3188
|
+
DEBUG_LOG("uploadFile:step1:entry", "editor uploadFile callback invoked", {
|
|
3189
|
+
fileName: file.name,
|
|
3190
|
+
fileType: file.type,
|
|
3191
|
+
fileSize: file.size,
|
|
3192
|
+
allowVideoUpload,
|
|
3193
|
+
allowedImage,
|
|
3194
|
+
allowedVideo
|
|
3195
|
+
});
|
|
3196
|
+
if (!allowedImage && !allowedVideo) {
|
|
3197
|
+
const error = LumirEditorError.invalidFileType(
|
|
3198
|
+
file.name,
|
|
3199
|
+
allowVideoUpload
|
|
3200
|
+
);
|
|
2802
3201
|
handleError(error);
|
|
2803
3202
|
throw error;
|
|
2804
3203
|
}
|
|
2805
3204
|
try {
|
|
2806
|
-
|
|
3205
|
+
setUploadProgress(0);
|
|
3206
|
+
let fileUrl;
|
|
3207
|
+
const branch = uploadFile ? "custom" : memoizedS3Upload?.apiEndpoint ? "s3" : "none";
|
|
3208
|
+
DEBUG_LOG("uploadFile:step2:branch", "upload path", {
|
|
3209
|
+
branch,
|
|
3210
|
+
hasCustomUploadFile: !!uploadFile,
|
|
3211
|
+
hasS3ApiEndpoint: !!memoizedS3Upload?.apiEndpoint
|
|
3212
|
+
});
|
|
2807
3213
|
if (uploadFile) {
|
|
2808
|
-
|
|
3214
|
+
const t0 = Date.now();
|
|
3215
|
+
DEBUG_LOG("uploadFile:step3a:custom", "calling custom uploadFile", { fileName: file.name });
|
|
3216
|
+
fileUrl = await uploadFile(file);
|
|
3217
|
+
DEBUG_LOG("uploadFile:step3a:done", "custom uploadFile returned", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });
|
|
2809
3218
|
} else if (memoizedS3Upload?.apiEndpoint) {
|
|
3219
|
+
const t0 = Date.now();
|
|
3220
|
+
DEBUG_LOG("uploadFile:step3b:s3", "calling S3 uploader", { fileName: file.name });
|
|
2810
3221
|
const s3Uploader = createS3Uploader(memoizedS3Upload);
|
|
2811
|
-
|
|
3222
|
+
fileUrl = await s3Uploader(file);
|
|
3223
|
+
DEBUG_LOG("uploadFile:step3b:done", "S3 uploader returned", { urlLen: fileUrl?.length, elapsedMs: Date.now() - t0 });
|
|
2812
3224
|
} else {
|
|
2813
3225
|
const error = LumirEditorError.s3ConfigError(
|
|
2814
3226
|
"No upload method available. Please provide uploadFile or s3Upload configuration."
|
|
@@ -2816,8 +3228,16 @@ function LumirEditor({
|
|
|
2816
3228
|
handleError(error);
|
|
2817
3229
|
throw error;
|
|
2818
3230
|
}
|
|
2819
|
-
|
|
3231
|
+
DEBUG_LOG("uploadFile:step4:success", "returning URL", {
|
|
3232
|
+
fileName: file.name,
|
|
3233
|
+
urlPrefix: fileUrl.slice(0, 80)
|
|
3234
|
+
});
|
|
3235
|
+
return fileUrl;
|
|
2820
3236
|
} catch (error) {
|
|
3237
|
+
DEBUG_LOG("uploadFile:step5:catch", "uploadFile threw", {
|
|
3238
|
+
fileName: file.name,
|
|
3239
|
+
errorMessage: error instanceof Error ? error.message : String(error)
|
|
3240
|
+
});
|
|
2821
3241
|
if (error instanceof LumirEditorError) {
|
|
2822
3242
|
throw error;
|
|
2823
3243
|
}
|
|
@@ -2827,6 +3247,8 @@ function LumirEditor({
|
|
|
2827
3247
|
);
|
|
2828
3248
|
handleError(lumirError);
|
|
2829
3249
|
throw lumirError;
|
|
3250
|
+
} finally {
|
|
3251
|
+
setUploadProgress(null);
|
|
2830
3252
|
}
|
|
2831
3253
|
},
|
|
2832
3254
|
pasteHandler: (ctx) => {
|
|
@@ -2855,7 +3277,15 @@ function LumirEditor({
|
|
|
2855
3277
|
}
|
|
2856
3278
|
const fileList = event?.clipboardData?.files ?? null;
|
|
2857
3279
|
const files = fileList ? Array.from(fileList) : [];
|
|
2858
|
-
const acceptedFiles = files.filter(
|
|
3280
|
+
const acceptedFiles = files.filter(
|
|
3281
|
+
(f) => isImageFile(f) || allowVideoUpload && isVideoFile(f)
|
|
3282
|
+
);
|
|
3283
|
+
DEBUG_LOG("paste:step1:files", "paste clipboard files", {
|
|
3284
|
+
filesCount: files.length,
|
|
3285
|
+
acceptedCount: acceptedFiles.length,
|
|
3286
|
+
fileNames: files.map((f) => f.name),
|
|
3287
|
+
acceptedNames: acceptedFiles.map((f) => f.name)
|
|
3288
|
+
});
|
|
2859
3289
|
if (files.length > 0 && acceptedFiles.length === 0) {
|
|
2860
3290
|
event.preventDefault();
|
|
2861
3291
|
return true;
|
|
@@ -2869,13 +3299,26 @@ function LumirEditor({
|
|
|
2869
3299
|
try {
|
|
2870
3300
|
for (const file of acceptedFiles) {
|
|
2871
3301
|
try {
|
|
3302
|
+
DEBUG_LOG("paste:step2:upload", "calling uploadFile for paste", {
|
|
3303
|
+
fileName: file.name,
|
|
3304
|
+
fileType: file.type
|
|
3305
|
+
});
|
|
2872
3306
|
const url = await editor2.uploadFile(file);
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
3307
|
+
if (isImageFile(file)) {
|
|
3308
|
+
editor2.pasteHTML(
|
|
3309
|
+
`<img src="${escapeHtml(url)}" alt="image" />`
|
|
3310
|
+
);
|
|
3311
|
+
} else if (isVideoFile(file)) {
|
|
3312
|
+
const currentBlock = editor2.getTextCursorPosition().block;
|
|
3313
|
+
editor2.insertBlocks(
|
|
3314
|
+
[{ type: "video", props: { url } }],
|
|
3315
|
+
currentBlock,
|
|
3316
|
+
"after"
|
|
3317
|
+
);
|
|
3318
|
+
}
|
|
2876
3319
|
} catch (err) {
|
|
2877
3320
|
console.warn(
|
|
2878
|
-
"
|
|
3321
|
+
"Upload failed, skipped:",
|
|
2879
3322
|
file.name || "",
|
|
2880
3323
|
err
|
|
2881
3324
|
);
|
|
@@ -2898,6 +3341,7 @@ function LumirEditor({
|
|
|
2898
3341
|
trailingBlock,
|
|
2899
3342
|
uploadFile,
|
|
2900
3343
|
memoizedS3Upload,
|
|
3344
|
+
allowVideoUpload,
|
|
2901
3345
|
linkPreview?.apiEndpoint,
|
|
2902
3346
|
placeholder
|
|
2903
3347
|
]
|
|
@@ -2905,12 +3349,12 @@ function LumirEditor({
|
|
|
2905
3349
|
if (editor && linkPreview?.apiEndpoint) {
|
|
2906
3350
|
editor._linkPreviewApiEndpoint = linkPreview.apiEndpoint;
|
|
2907
3351
|
}
|
|
2908
|
-
|
|
3352
|
+
useEffect8(() => {
|
|
2909
3353
|
if (editor) {
|
|
2910
3354
|
editor.isEditable = editable;
|
|
2911
3355
|
}
|
|
2912
3356
|
}, [editor, editable]);
|
|
2913
|
-
|
|
3357
|
+
useEffect8(() => {
|
|
2914
3358
|
if (!editor || !onContentChange) return;
|
|
2915
3359
|
const handleContentChange = () => {
|
|
2916
3360
|
const blocks = editor.topLevelBlocks;
|
|
@@ -2918,27 +3362,27 @@ function LumirEditor({
|
|
|
2918
3362
|
};
|
|
2919
3363
|
return editor.onEditorContentChange(handleContentChange);
|
|
2920
3364
|
}, [editor, onContentChange]);
|
|
2921
|
-
const
|
|
2922
|
-
|
|
3365
|
+
const previousMediaUrlsRef = useRef9(/* @__PURE__ */ new Set());
|
|
3366
|
+
useEffect8(() => {
|
|
2923
3367
|
if (!editor) return;
|
|
2924
3368
|
const initialBlocks = editor.topLevelBlocks;
|
|
2925
|
-
|
|
3369
|
+
previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);
|
|
2926
3370
|
}, [editor]);
|
|
2927
|
-
|
|
3371
|
+
useEffect8(() => {
|
|
2928
3372
|
if (!editor || !onImageDelete) return;
|
|
2929
|
-
const
|
|
3373
|
+
const handleMediaDeleteCheck = () => {
|
|
2930
3374
|
const currentBlocks = editor.topLevelBlocks;
|
|
2931
|
-
const currentUrls =
|
|
2932
|
-
const previousUrls =
|
|
2933
|
-
const deletedUrls =
|
|
3375
|
+
const currentUrls = extractMediaUrls(currentBlocks);
|
|
3376
|
+
const previousUrls = previousMediaUrlsRef.current;
|
|
3377
|
+
const deletedUrls = findDeletedMediaUrls(previousUrls, currentUrls);
|
|
2934
3378
|
deletedUrls.forEach((url) => {
|
|
2935
3379
|
onImageDelete(url);
|
|
2936
3380
|
});
|
|
2937
|
-
|
|
3381
|
+
previousMediaUrlsRef.current = currentUrls;
|
|
2938
3382
|
};
|
|
2939
|
-
return editor.onEditorContentChange(
|
|
3383
|
+
return editor.onEditorContentChange(handleMediaDeleteCheck);
|
|
2940
3384
|
}, [editor, onImageDelete]);
|
|
2941
|
-
|
|
3385
|
+
useEffect8(() => {
|
|
2942
3386
|
const el = editor?.domElement;
|
|
2943
3387
|
if (!el) return;
|
|
2944
3388
|
const handleDragOver = (e) => {
|
|
@@ -2958,11 +3402,31 @@ function LumirEditor({
|
|
|
2958
3402
|
const items = Array.from(e.dataTransfer.items ?? []);
|
|
2959
3403
|
const files = items.filter((it) => it.kind === "file").map((it) => it.getAsFile()).filter((f) => !!f);
|
|
2960
3404
|
const imageFiles = files.filter(isImageFile);
|
|
3405
|
+
const videoFiles = allowVideoUpload ? files.filter(isVideoFile) : [];
|
|
2961
3406
|
const htmlFiles = files.filter(isHtmlFile);
|
|
2962
|
-
|
|
3407
|
+
DEBUG_LOG("drop:step1:files", "drop received", {
|
|
3408
|
+
filesCount: files.length,
|
|
3409
|
+
imageCount: imageFiles.length,
|
|
3410
|
+
videoCount: videoFiles.length,
|
|
3411
|
+
htmlCount: htmlFiles.length,
|
|
3412
|
+
allowVideoUpload,
|
|
3413
|
+
firstFile: files[0] ? {
|
|
3414
|
+
name: files[0].name,
|
|
3415
|
+
type: files[0].type,
|
|
3416
|
+
size: files[0].size,
|
|
3417
|
+
isImage: isImageFile(files[0]),
|
|
3418
|
+
isVideo: isVideoFile(files[0])
|
|
3419
|
+
} : null
|
|
3420
|
+
});
|
|
3421
|
+
if (imageFiles.length === 0 && htmlFiles.length === 0 && videoFiles.length === 0)
|
|
3422
|
+
return;
|
|
2963
3423
|
(async () => {
|
|
2964
3424
|
setIsUploading(true);
|
|
2965
3425
|
try {
|
|
3426
|
+
DEBUG_LOG("drop:step2:async", "drop async started", {
|
|
3427
|
+
imageCount: imageFiles.length,
|
|
3428
|
+
videoCount: videoFiles.length
|
|
3429
|
+
});
|
|
2966
3430
|
for (const file of imageFiles) {
|
|
2967
3431
|
try {
|
|
2968
3432
|
if (editor?.uploadFile) {
|
|
@@ -2981,6 +3445,34 @@ function LumirEditor({
|
|
|
2981
3445
|
);
|
|
2982
3446
|
}
|
|
2983
3447
|
}
|
|
3448
|
+
DEBUG_LOG("drop:step3:videoLoop", "video loop start", {
|
|
3449
|
+
videoCount: videoFiles.length,
|
|
3450
|
+
names: videoFiles.map((f) => f.name)
|
|
3451
|
+
});
|
|
3452
|
+
for (const file of videoFiles) {
|
|
3453
|
+
try {
|
|
3454
|
+
if (editor?.uploadFile) {
|
|
3455
|
+
DEBUG_LOG("drop:step4:videoUpload", "calling uploadFile for video", {
|
|
3456
|
+
fileName: file.name
|
|
3457
|
+
});
|
|
3458
|
+
const url = await editor.uploadFile(file);
|
|
3459
|
+
if (url && typeof url === "string") {
|
|
3460
|
+
const currentBlock = editor.getTextCursorPosition().block;
|
|
3461
|
+
editor.insertBlocks(
|
|
3462
|
+
[{ type: "video", props: { url } }],
|
|
3463
|
+
currentBlock,
|
|
3464
|
+
"after"
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
} catch (err) {
|
|
3469
|
+
console.warn(
|
|
3470
|
+
"Video upload failed, skipped:",
|
|
3471
|
+
file.name || "",
|
|
3472
|
+
err
|
|
3473
|
+
);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
2984
3476
|
for (const file of htmlFiles) {
|
|
2985
3477
|
try {
|
|
2986
3478
|
const htmlContent = await file.text();
|
|
@@ -3020,56 +3512,124 @@ function LumirEditor({
|
|
|
3020
3512
|
});
|
|
3021
3513
|
el.removeEventListener("drop", handleDrop, { capture: true });
|
|
3022
3514
|
};
|
|
3023
|
-
}, [editor]);
|
|
3515
|
+
}, [editor, allowVideoUpload]);
|
|
3024
3516
|
const computedSideMenu = useMemo(() => {
|
|
3025
3517
|
return sideMenuAddButton ? sideMenu : false;
|
|
3026
3518
|
}, [sideMenuAddButton, sideMenu]);
|
|
3027
3519
|
const DragHandleOnlySideMenu = useMemo(() => {
|
|
3028
|
-
return (props) => /* @__PURE__ */
|
|
3520
|
+
return (props) => /* @__PURE__ */ jsx17(BlockSideMenu, { ...props, children: /* @__PURE__ */ jsx17(DragHandleButton, { ...props }) });
|
|
3029
3521
|
}, []);
|
|
3030
|
-
return /* @__PURE__ */
|
|
3522
|
+
return /* @__PURE__ */ jsxs11(
|
|
3031
3523
|
"div",
|
|
3032
3524
|
{
|
|
3033
3525
|
className: cn("lumirEditor", className),
|
|
3034
3526
|
style: { position: "relative", display: "flex", flexDirection: "column" },
|
|
3035
3527
|
children: [
|
|
3036
|
-
floatingMenu && editor && /* @__PURE__ */
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3528
|
+
floatingMenu && editor && /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
3529
|
+
/* @__PURE__ */ jsx17(
|
|
3530
|
+
"input",
|
|
3531
|
+
{
|
|
3532
|
+
ref: floatingMenuFileInputRef,
|
|
3533
|
+
type: "file",
|
|
3534
|
+
accept: allowVideoUpload ? "image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov" : "image/*",
|
|
3535
|
+
style: {
|
|
3536
|
+
position: "absolute",
|
|
3537
|
+
left: "-9999px",
|
|
3538
|
+
opacity: 0,
|
|
3539
|
+
pointerEvents: "none"
|
|
3540
|
+
},
|
|
3541
|
+
onChange: async (e) => {
|
|
3542
|
+
const inputEl = e.target;
|
|
3543
|
+
const file = inputEl.files?.[0];
|
|
3544
|
+
DEBUG_LOG("FloatingMenu:step3:onchange", "file input onchange fired", {
|
|
3545
|
+
hasFile: !!file,
|
|
3546
|
+
fileName: file?.name,
|
|
3547
|
+
fileType: file?.type,
|
|
3548
|
+
fileSize: file?.size,
|
|
3549
|
+
hasUploadFile: !!editor?.uploadFile
|
|
3550
|
+
});
|
|
3551
|
+
const blockToInsertAfter = floatingMenuBlockRef.current;
|
|
3552
|
+
if (file && editor.uploadFile && blockToInsertAfter) {
|
|
3553
|
+
const allowedImage = isImageFile(file);
|
|
3554
|
+
const allowedVideo = allowVideoUpload && isVideoFile(file);
|
|
3555
|
+
DEBUG_LOG("FloatingMenu:step4:fileCheck", "allowed check", {
|
|
3556
|
+
fileName: file.name,
|
|
3557
|
+
allowedImage,
|
|
3558
|
+
allowedVideo
|
|
3559
|
+
});
|
|
3560
|
+
if (allowedImage || allowedVideo) {
|
|
3561
|
+
try {
|
|
3562
|
+
setIsUploading(true);
|
|
3563
|
+
floatingMenuUploadStartTimeRef.current = Date.now();
|
|
3564
|
+
DEBUG_LOG("FloatingMenu:step5:uploadStart", "calling editor.uploadFile", {
|
|
3565
|
+
fileName: file.name
|
|
3566
|
+
});
|
|
3567
|
+
const url = await editor.uploadFile(file);
|
|
3568
|
+
const blockType = allowedVideo ? "video" : "image";
|
|
3569
|
+
const elapsedMs = Date.now() - floatingMenuUploadStartTimeRef.current;
|
|
3570
|
+
DEBUG_LOG("FloatingMenu:step6:uploadDone", "upload returned, inserting block", {
|
|
3571
|
+
blockType,
|
|
3572
|
+
blockId: blockToInsertAfter.id,
|
|
3573
|
+
urlLen: url?.length,
|
|
3574
|
+
elapsedMs
|
|
3575
|
+
});
|
|
3576
|
+
editor.insertBlocks(
|
|
3577
|
+
[
|
|
3578
|
+
{
|
|
3579
|
+
type: blockType,
|
|
3580
|
+
props: { url }
|
|
3581
|
+
}
|
|
3582
|
+
],
|
|
3583
|
+
blockToInsertAfter,
|
|
3584
|
+
"after"
|
|
3585
|
+
);
|
|
3586
|
+
} catch (err) {
|
|
3587
|
+
DEBUG_LOG("FloatingMenu:step7:catch", "upload or insert failed", {
|
|
3588
|
+
errMsg: err instanceof Error ? err.message : String(err)
|
|
3589
|
+
});
|
|
3590
|
+
console.error("Upload failed:", err);
|
|
3591
|
+
} finally {
|
|
3592
|
+
setIsUploading(false);
|
|
3593
|
+
}
|
|
3065
3594
|
}
|
|
3066
3595
|
}
|
|
3067
|
-
|
|
3068
|
-
|
|
3596
|
+
inputEl.value = "";
|
|
3597
|
+
}
|
|
3069
3598
|
}
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3599
|
+
),
|
|
3600
|
+
/* @__PURE__ */ jsx17(
|
|
3601
|
+
FloatingMenu,
|
|
3602
|
+
{
|
|
3603
|
+
editor,
|
|
3604
|
+
position: floatingMenuPosition,
|
|
3605
|
+
onImageUpload: () => {
|
|
3606
|
+
DEBUG_LOG("FloatingMenu:step1:click", "upload button clicked", {
|
|
3607
|
+
allowVideoUpload
|
|
3608
|
+
});
|
|
3609
|
+
let blockToInsertAfter;
|
|
3610
|
+
try {
|
|
3611
|
+
blockToInsertAfter = editor.getTextCursorPosition().block;
|
|
3612
|
+
} catch (err) {
|
|
3613
|
+
DEBUG_LOG("FloatingMenu:step1b:error", "getTextCursorPosition failed", {
|
|
3614
|
+
err: err instanceof Error ? err.message : String(err)
|
|
3615
|
+
});
|
|
3616
|
+
return;
|
|
3617
|
+
}
|
|
3618
|
+
floatingMenuBlockRef.current = blockToInsertAfter;
|
|
3619
|
+
const input = floatingMenuFileInputRef.current;
|
|
3620
|
+
if (!input) return;
|
|
3621
|
+
input.accept = allowVideoUpload ? "image/*,video/mp4,video/webm,video/ogg,video/quicktime,.mov" : "image/*";
|
|
3622
|
+
input.value = "";
|
|
3623
|
+
DEBUG_LOG("FloatingMenu:step2:inputReady", "persistent input ref, about to click", {
|
|
3624
|
+
accept: input.accept
|
|
3625
|
+
});
|
|
3626
|
+
DEBUG_LOG("FloatingMenu:step2b:click", "input.click() about to be called", {});
|
|
3627
|
+
input.click();
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
)
|
|
3631
|
+
] }),
|
|
3632
|
+
/* @__PURE__ */ jsxs11(
|
|
3073
3633
|
BlockNoteView,
|
|
3074
3634
|
{
|
|
3075
3635
|
editor,
|
|
@@ -3084,19 +3644,21 @@ function LumirEditor({
|
|
|
3084
3644
|
tableHandles,
|
|
3085
3645
|
onSelectionChange,
|
|
3086
3646
|
children: [
|
|
3087
|
-
linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */
|
|
3088
|
-
/* @__PURE__ */
|
|
3647
|
+
linkToolbar && (linkPreview?.apiEndpoint ? /* @__PURE__ */ jsx17(LinkToolbarController, { linkToolbar: CustomLinkToolbar }) : /* @__PURE__ */ jsx17(LinkToolbarController, {})),
|
|
3648
|
+
/* @__PURE__ */ jsx17(
|
|
3089
3649
|
SuggestionMenuController,
|
|
3090
3650
|
{
|
|
3091
3651
|
triggerCharacter: "/",
|
|
3092
|
-
getItems:
|
|
3652
|
+
getItems: useCallback14(
|
|
3093
3653
|
async (query) => {
|
|
3094
3654
|
const items = getDefaultReactSlashMenuItems(editor);
|
|
3095
3655
|
const filtered = items.filter((item) => {
|
|
3096
3656
|
const key = (item?.key || "").toString().toLowerCase();
|
|
3097
3657
|
const title = (item?.title || "").toString().toLowerCase();
|
|
3098
|
-
if (
|
|
3099
|
-
|
|
3658
|
+
if (key === "video" || title.includes("video"))
|
|
3659
|
+
return allowVideoUpload;
|
|
3660
|
+
if (["audio", "file"].includes(key)) return false;
|
|
3661
|
+
if (title.includes("audio") || title.includes("file"))
|
|
3100
3662
|
return false;
|
|
3101
3663
|
return true;
|
|
3102
3664
|
});
|
|
@@ -3131,7 +3693,7 @@ function LumirEditor({
|
|
|
3131
3693
|
},
|
|
3132
3694
|
aliases: ["html", "preview", "\uC6F9", "\uC6F9\uD398\uC774\uC9C0"],
|
|
3133
3695
|
group: "Embeds",
|
|
3134
|
-
icon: /* @__PURE__ */
|
|
3696
|
+
icon: /* @__PURE__ */ jsxs11(
|
|
3135
3697
|
"svg",
|
|
3136
3698
|
{
|
|
3137
3699
|
width: "18",
|
|
@@ -3143,8 +3705,8 @@ function LumirEditor({
|
|
|
3143
3705
|
strokeLinecap: "round",
|
|
3144
3706
|
strokeLinejoin: "round",
|
|
3145
3707
|
children: [
|
|
3146
|
-
/* @__PURE__ */
|
|
3147
|
-
/* @__PURE__ */
|
|
3708
|
+
/* @__PURE__ */ jsx17("polyline", { points: "16 18 22 12 16 6" }),
|
|
3709
|
+
/* @__PURE__ */ jsx17("polyline", { points: "8 6 2 12 8 18" })
|
|
3148
3710
|
]
|
|
3149
3711
|
}
|
|
3150
3712
|
),
|
|
@@ -3169,7 +3731,7 @@ function LumirEditor({
|
|
|
3169
3731
|
"\uD504\uB9AC\uBDF0"
|
|
3170
3732
|
],
|
|
3171
3733
|
group: "Embeds",
|
|
3172
|
-
icon: /* @__PURE__ */
|
|
3734
|
+
icon: /* @__PURE__ */ jsxs11(
|
|
3173
3735
|
"svg",
|
|
3174
3736
|
{
|
|
3175
3737
|
width: "18",
|
|
@@ -3181,8 +3743,8 @@ function LumirEditor({
|
|
|
3181
3743
|
strokeLinecap: "round",
|
|
3182
3744
|
strokeLinejoin: "round",
|
|
3183
3745
|
children: [
|
|
3184
|
-
/* @__PURE__ */
|
|
3185
|
-
/* @__PURE__ */
|
|
3746
|
+
/* @__PURE__ */ jsx17("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
|
|
3747
|
+
/* @__PURE__ */ jsx17("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
3186
3748
|
]
|
|
3187
3749
|
}
|
|
3188
3750
|
),
|
|
@@ -3197,19 +3759,25 @@ function LumirEditor({
|
|
|
3197
3759
|
)
|
|
3198
3760
|
);
|
|
3199
3761
|
},
|
|
3200
|
-
[editor, linkPreview?.apiEndpoint]
|
|
3762
|
+
[editor, allowVideoUpload, linkPreview?.apiEndpoint]
|
|
3201
3763
|
)
|
|
3202
3764
|
}
|
|
3203
3765
|
),
|
|
3204
|
-
!sideMenuAddButton && /* @__PURE__ */
|
|
3766
|
+
!sideMenuAddButton && /* @__PURE__ */ jsx17(SideMenuController, { sideMenu: DragHandleOnlySideMenu })
|
|
3205
3767
|
]
|
|
3206
3768
|
}
|
|
3207
3769
|
),
|
|
3208
|
-
isUploading && /* @__PURE__ */
|
|
3209
|
-
|
|
3210
|
-
/* @__PURE__ */
|
|
3211
|
-
|
|
3212
|
-
|
|
3770
|
+
isUploading && /* @__PURE__ */ jsxs11("div", { className: "lumirEditor-upload-overlay", children: [
|
|
3771
|
+
/* @__PURE__ */ jsx17("div", { className: "lumirEditor-spinner" }),
|
|
3772
|
+
uploadProgress !== null && /* @__PURE__ */ jsxs11("span", { className: "lumirEditor-upload-progress", children: [
|
|
3773
|
+
uploadProgress,
|
|
3774
|
+
"%"
|
|
3775
|
+
] })
|
|
3776
|
+
] }),
|
|
3777
|
+
errorMessage && /* @__PURE__ */ jsxs11("div", { className: "lumirEditor-error-toast", children: [
|
|
3778
|
+
/* @__PURE__ */ jsx17("span", { className: "lumirEditor-error-icon", children: "\u26A0\uFE0F" }),
|
|
3779
|
+
/* @__PURE__ */ jsx17("span", { className: "lumirEditor-error-message", children: errorMessage }),
|
|
3780
|
+
/* @__PURE__ */ jsx17(
|
|
3213
3781
|
"button",
|
|
3214
3782
|
{
|
|
3215
3783
|
className: "lumirEditor-error-close",
|