@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/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/LumirEditor.tsx
4
- import { useEffect as useEffect7, useMemo, useCallback as useCallback13, useState as useState7, useRef as useRef8 } from "react";
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 response = await fetch(
116
- `${apiEndpoint}?key=${encodeURIComponent(fileName)}`
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 uploadResponse = await fetch(validatedPresignedUrl, {
129
- method: "PUT",
130
- headers: {
131
- "Content-Type": file.type || "application/octet-stream"
132
- },
133
- body: file
134
- });
135
- if (!uploadResponse.ok) {
136
- throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
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
- return validatedPublicUrl;
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 createReactBlockSpec2 } from "@blocknote/react";
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 useState2, useRef as useRef2, useCallback as useCallback2, useEffect as useEffect2 } from "react";
860
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
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 = createReactBlockSpec2(
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] = useState2(true);
917
- const [isResizing, setIsResizing] = useState2(false);
918
- const [blobUrl, setBlobUrl] = useState2("");
919
- const containerRef = useRef2(null);
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
- useEffect2(() => {
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 = useCallback2(
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 = useCallback2(
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 = useCallback2(
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__ */ jsxs2(
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__ */ jsxs2(
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__ */ jsxs2(
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__ */ jsx2(
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__ */ jsx2("polyline", { points: "6 9 12 15 18 9" })
1369
+ children: /* @__PURE__ */ jsx3("polyline", { points: "6 9 12 15 18 9" })
1051
1370
  }
1052
1371
  ),
1053
- /* @__PURE__ */ jsx2("span", { style: { fontWeight: 500, fontSize: "14px" }, children: fileName })
1372
+ /* @__PURE__ */ jsx3("span", { style: { fontWeight: 500, fontSize: "14px" }, children: fileName })
1054
1373
  ]
1055
1374
  }
1056
1375
  ),
1057
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
1058
- /* @__PURE__ */ jsx2(
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__ */ jsxs2(
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__ */ jsx2("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
1094
- /* @__PURE__ */ jsx2("polyline", { points: "15 3 21 3 21 9" }),
1095
- /* @__PURE__ */ jsx2("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
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__ */ jsx2(
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__ */ jsxs2(
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__ */ jsx2("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1137
- /* @__PURE__ */ jsx2("polyline", { points: "7 10 12 15 17 10" }),
1138
- /* @__PURE__ */ jsx2("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
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__ */ jsxs2(
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__ */ jsx2(
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__ */ jsx2(
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__ */ jsx2(
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 useState6, useEffect as useEffect6, useRef as useRef7 } from "react";
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 jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1555
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1236
1556
  var Icons = {
1237
- undo: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1238
- redo: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1239
- bold: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1240
- italic: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z" }) }),
1241
- underline: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1242
- strikethrough: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z" }) }),
1243
- alignLeft: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z" }) }),
1244
- alignCenter: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z" }) }),
1245
- alignRight: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z" }) }),
1246
- bulletList: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1247
- numberedList: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z" }) }),
1248
- image: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1249
- expandMore: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx3("path", { d: "M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z" }) }),
1250
- textColor: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M11 3L5.5 17h2.25l1.12-3h6.25l1.12 3h2.25L13 3h-2zm-1.38 9L12 5.67 14.38 12H9.62z" }) }),
1251
- bgColor: /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
1252
- /* @__PURE__ */ jsx3("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" }),
1253
- /* @__PURE__ */ jsx3("path", { fillOpacity: ".36", d: "M0 20h24v4H0z" })
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__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1256
- chevronRight: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" }) }),
1257
- chevronLeft: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" }) }),
1258
- table: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1259
- htmlFile: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) })
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__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M5 5h14v2H5zM5 11h14v2H5zM5 17h10v2H5z" }) }),
1263
- h1: /* @__PURE__ */ jsx3("span", { className: "lumir-block-icon-text", children: "H1" }),
1264
- h2: /* @__PURE__ */ jsx3("span", { className: "lumir-block-icon-text", children: "H2" }),
1265
- h3: /* @__PURE__ */ jsx3("span", { className: "lumir-block-icon-text", children: "H3" }),
1266
- h4: /* @__PURE__ */ jsx3("span", { className: "lumir-block-icon-text", children: "H4" }),
1267
- h5: /* @__PURE__ */ jsx3("span", { className: "lumir-block-icon-text", children: "H5" }),
1268
- h6: /* @__PURE__ */ jsx3("span", { className: "lumir-block-icon-text", children: "H6" }),
1269
- toggleH1: /* @__PURE__ */ jsxs3("span", { className: "lumir-block-icon-toggle", children: [
1270
- /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ jsx3("path", { d: "M8 5v14l11-7z" }) }),
1271
- /* @__PURE__ */ jsx3("span", { children: "H1" })
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__ */ jsxs3("span", { className: "lumir-block-icon-toggle", children: [
1274
- /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ jsx3("path", { d: "M8 5v14l11-7z" }) }),
1275
- /* @__PURE__ */ jsx3("span", { children: "H2" })
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__ */ jsxs3("span", { className: "lumir-block-icon-toggle", children: [
1278
- /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "8", height: "8", children: /* @__PURE__ */ jsx3("path", { d: "M8 5v14l11-7z" }) }),
1279
- /* @__PURE__ */ jsx3("span", { children: "H3" })
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__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M6 17h3l2-4V7H5v6h3zm8 0h3l2-4V7h-6v6h3z" }) }),
1282
- codeBlock: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("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" }) }),
1283
- toggleList: /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
1284
- /* @__PURE__ */ jsx3("path", { d: "M10 6h10v2H10zM10 11h10v2H10zM10 16h10v2H10z" }),
1285
- /* @__PURE__ */ jsx3(
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__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
1298
- /* @__PURE__ */ jsx3("circle", { cx: "4", cy: "6", r: "1.5" }),
1299
- /* @__PURE__ */ jsx3("circle", { cx: "4", cy: "12", r: "1.5" }),
1300
- /* @__PURE__ */ jsx3("circle", { cx: "4", cy: "18", r: "1.5" }),
1301
- /* @__PURE__ */ jsx3("path", { d: "M8 5h12v2H8zM8 11h12v2H8zM8 17h12v2H8z" })
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__ */ jsx3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx3("path", { d: "M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z" }) }),
1304
- checkList: /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: [
1305
- /* @__PURE__ */ jsx3(
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__ */ jsx3(
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__ */ jsx3("path", { d: "M12 6h8v2h-8z" }),
1330
- /* @__PURE__ */ jsx3(
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__ */ jsx3("path", { d: "M12 16h8v2h-8z" })
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 jsx4 } from "react/jsx-runtime";
1349
- var ToolbarDivider = () => /* @__PURE__ */ jsx4("div", { className: "lumir-toolbar-divider" });
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 useCallback3 } from "react";
1353
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
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 = useCallback3(() => {
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 = useCallback3(() => {
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 = useCallback3((e) => {
1689
+ const handleMouseDown = useCallback4((e) => {
1370
1690
  e.preventDefault();
1371
1691
  }, []);
1372
- return /* @__PURE__ */ jsxs4("div", { className: "lumir-toolbar-group", children: [
1373
- /* @__PURE__ */ jsx5(
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__ */ jsx5(
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 useCallback4 } from "react";
1400
- import { jsx as jsx6 } from "react/jsx-runtime";
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 = useCallback4(() => {
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 = useCallback4((e) => {
1753
+ const handleMouseDown = useCallback5((e) => {
1434
1754
  e.preventDefault();
1435
1755
  }, []);
1436
- return /* @__PURE__ */ jsx6(
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 useCallback5 } from "react";
1451
- import { jsx as jsx7 } from "react/jsx-runtime";
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 = useCallback5(() => {
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 = useCallback5((e) => {
1805
+ const handleMouseDown = useCallback6((e) => {
1486
1806
  e.preventDefault();
1487
1807
  }, []);
1488
- return /* @__PURE__ */ jsx7(
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 useCallback6 } from "react";
1503
- import { jsx as jsx8 } from "react/jsx-runtime";
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 = useCallback6(() => {
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 = useCallback6((e) => {
1855
+ const handleMouseDown = useCallback7((e) => {
1536
1856
  e.preventDefault();
1537
1857
  }, []);
1538
- return /* @__PURE__ */ jsx8(
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 useCallback7 } from "react";
1553
- import { jsx as jsx9 } from "react/jsx-runtime";
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 = useCallback7(() => {
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 = useCallback7((e) => {
1903
+ const handleMouseDown = useCallback8((e) => {
1584
1904
  e.preventDefault();
1585
1905
  }, []);
1586
- return /* @__PURE__ */ jsx9(
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 useState3, useEffect as useEffect3, useRef as useRef3, useCallback as useCallback8 } from "react";
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 jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1954
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1635
1955
  var ColorButton = ({ editor, type }) => {
1636
- const [isOpen, setIsOpen] = useState3(false);
1637
- const [currentColor, setCurrentColor] = useState3("default");
1638
- const dropdownRef = useRef3(null);
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 = useCallback8(() => {
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
- useEffect3(() => {
1972
+ useEffect4(() => {
1653
1973
  if (isOpen) {
1654
1974
  const color = getCurrentColor();
1655
1975
  setCurrentColor(color);
1656
1976
  }
1657
1977
  }, [isOpen, getCurrentColor]);
1658
- useEffect3(() => {
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 = useCallback8(
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 = useCallback8((e) => {
2004
+ const handleMouseDown = useCallback9((e) => {
1685
2005
  e.preventDefault();
1686
2006
  }, []);
1687
- return /* @__PURE__ */ jsxs5("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
1688
- /* @__PURE__ */ jsxs5(
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__ */ jsx10(
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__ */ jsx10("div", { className: "lumir-dropdown-menu lumir-color-menu", children: /* @__PURE__ */ jsx10("div", { className: "lumir-color-grid", children: colors.map((color) => /* @__PURE__ */ jsx10(
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 useState4, useEffect as useEffect4, useRef as useRef4, useCallback as useCallback9 } from "react";
1730
- import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
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] = useState4(false);
1757
- const [linkUrl, setLinkUrl] = useState4("");
1758
- const [errorMsg, setErrorMsg] = useState4(null);
1759
- const dropdownRef = useRef4(null);
1760
- const inputRef = useRef4(null);
1761
- const hasSelectionRef = useRef4(false);
1762
- useEffect4(() => {
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
- useEffect4(() => {
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 = useCallback9(
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 = useCallback9(() => {
2131
+ const handleCancel = useCallback10(() => {
1812
2132
  setIsOpen(false);
1813
2133
  setLinkUrl("");
1814
2134
  setErrorMsg(null);
1815
2135
  }, []);
1816
- const handleMouseDown = useCallback9((e) => {
2136
+ const handleMouseDown = useCallback10((e) => {
1817
2137
  e.preventDefault();
1818
2138
  }, []);
1819
- const handleKeyDown = useCallback9(
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__ */ jsxs6("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
1830
- /* @__PURE__ */ jsx11(
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__ */ jsx11("div", { className: "lumir-dropdown-menu lumir-link-menu", children: /* @__PURE__ */ jsxs6("form", { onSubmit: handleSubmit, className: "lumir-link-form", children: [
1842
- /* @__PURE__ */ jsx11(
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__ */ jsx11(
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__ */ jsxs6("div", { className: "lumir-link-actions", children: [
1871
- /* @__PURE__ */ jsx11(
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__ */ jsx11(
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 useCallback10 } from "react";
1898
- import { jsx as jsx12 } from "react/jsx-runtime";
2217
+ import { useCallback as useCallback11 } from "react";
2218
+ import { jsx as jsx13 } from "react/jsx-runtime";
1899
2219
  var TableButton = ({ editor }) => {
1900
- const handleClick = useCallback10(() => {
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 = useCallback10((e) => {
2242
+ const handleMouseDown = useCallback11((e) => {
1923
2243
  e.preventDefault();
1924
2244
  }, []);
1925
- return /* @__PURE__ */ jsx12(
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 useCallback11, useRef as useRef5 } from "react";
1940
- import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
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 = useRef5(null);
1945
- const handleFileUpload = useCallback11(
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 = useCallback11(() => {
2301
+ const handleClick = useCallback12(() => {
1982
2302
  fileInputRef.current?.click();
1983
2303
  }, []);
1984
- const handleMouseDown = useCallback11((e) => {
2304
+ const handleMouseDown = useCallback12((e) => {
1985
2305
  e.preventDefault();
1986
2306
  }, []);
1987
- return /* @__PURE__ */ jsxs7(Fragment2, { children: [
1988
- /* @__PURE__ */ jsx13(
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__ */ jsx13(
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 useState5, useEffect as useEffect5, useRef as useRef6, useCallback as useCallback12 } from "react";
2014
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
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] = useState5(false);
2045
- const dropdownRef = useRef6(null);
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
- useEffect5(() => {
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 = useCallback12((e) => {
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__ */ jsxs8("div", { className: "lumir-dropdown-wrapper", ref: dropdownRef, children: [
2118
- /* @__PURE__ */ jsxs8(
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__ */ jsx14("span", { className: "lumir-block-icon", children: BlockTypeIcons[getCurrentIcon()] }),
2127
- /* @__PURE__ */ jsx14("span", { className: "lumir-block-label", children: getCurrentLabel() }),
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__ */ jsx14("div", { className: "lumir-dropdown-menu lumir-block-menu", children: blockTypeCategories.map((category) => /* @__PURE__ */ jsxs8("div", { className: "lumir-block-category", children: [
2133
- /* @__PURE__ */ jsx14("div", { className: "lumir-block-category-title", children: category.category }),
2134
- category.items.map((bt) => /* @__PURE__ */ jsxs8(
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__ */ jsx14("span", { className: "lumir-block-icon", children: BlockTypeIcons[bt.icon] }),
2145
- /* @__PURE__ */ jsx14("span", { className: "lumir-block-item-title", children: bt.label })
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 Fragment3, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
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 = useRef7(null);
2165
- const [isCompact, setIsCompact] = useState6(false);
2166
- const [isMinimizable, setIsMinimizable] = useState6(false);
2167
- const [isMinimized, setIsMinimized] = useState6(false);
2168
- const [, setSelectionTick] = useState6(0);
2169
- useEffect6(() => {
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
- useEffect6(() => {
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__ */ jsxs9(Fragment3, { children: [
2209
- /* @__PURE__ */ jsx15(
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__ */ jsxs9(Fragment3, { children: [
2221
- /* @__PURE__ */ jsx15(ToolbarDivider, {}),
2222
- /* @__PURE__ */ jsx15(UndoRedoButtons, { editor }),
2223
- /* @__PURE__ */ jsx15(ToolbarDivider, {}),
2224
- /* @__PURE__ */ jsx15("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ jsx15(BlockTypeSelect, { editor }) }),
2225
- /* @__PURE__ */ jsx15(ToolbarDivider, {}),
2226
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2227
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "bold" }),
2228
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "italic" }),
2229
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "underline" }),
2230
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "strike" })
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__ */ jsx15(ToolbarDivider, {}),
2233
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2234
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "left" }),
2235
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "center" }),
2236
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "right" })
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__ */ jsx15(ToolbarDivider, {}),
2239
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2240
- /* @__PURE__ */ jsx15(ListButton, { editor, type: "bullet" }),
2241
- /* @__PURE__ */ jsx15(ListButton, { editor, type: "numbered" })
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__ */ jsx15(ToolbarDivider, {}),
2244
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2245
- /* @__PURE__ */ jsx15(ColorButton, { editor, type: "text" }),
2246
- /* @__PURE__ */ jsx15(ColorButton, { editor, type: "background" })
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__ */ jsx15(ToolbarDivider, {}),
2249
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2250
- /* @__PURE__ */ jsx15(ImageButton, { editor, onImageUpload }),
2251
- /* @__PURE__ */ jsx15(LinkButton, { editor }),
2252
- /* @__PURE__ */ jsx15(TableButton, { editor }),
2253
- /* @__PURE__ */ jsx15(HTMLImportButton, { editor })
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__ */ jsxs9(Fragment3, { children: [
2258
- /* @__PURE__ */ jsx15(UndoRedoButtons, { editor }),
2259
- /* @__PURE__ */ jsx15(ToolbarDivider, {}),
2260
- /* @__PURE__ */ jsx15("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ jsx15(BlockTypeSelect, { editor }) }),
2261
- /* @__PURE__ */ jsx15(ToolbarDivider, {}),
2262
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2263
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "bold" }),
2264
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "italic" }),
2265
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "underline" }),
2266
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "strike" })
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__ */ jsx15(ToolbarDivider, {}),
2269
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2270
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "left" }),
2271
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "center" }),
2272
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "right" })
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__ */ jsx15(ToolbarDivider, {}),
2275
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2276
- /* @__PURE__ */ jsx15(ListButton, { editor, type: "bullet" }),
2277
- /* @__PURE__ */ jsx15(ListButton, { editor, type: "numbered" })
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__ */ jsx15(ToolbarDivider, {}),
2280
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2281
- /* @__PURE__ */ jsx15(ColorButton, { editor, type: "text" }),
2282
- /* @__PURE__ */ jsx15(ColorButton, { editor, type: "background" })
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__ */ jsx15(ToolbarDivider, {}),
2285
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2286
- /* @__PURE__ */ jsx15(ImageButton, { editor, onImageUpload }),
2287
- /* @__PURE__ */ jsx15(LinkButton, { editor }),
2288
- /* @__PURE__ */ jsx15(TableButton, { editor }),
2289
- /* @__PURE__ */ jsx15(HTMLImportButton, { editor })
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__ */ jsxs9(Fragment3, { children: [
2293
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-row", children: [
2294
- /* @__PURE__ */ jsx15(UndoRedoButtons, { editor }),
2295
- /* @__PURE__ */ jsx15(ToolbarDivider, {}),
2296
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2297
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "bold" }),
2298
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "italic" }),
2299
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "underline" }),
2300
- /* @__PURE__ */ jsx15(TextStyleButton, { editor, style: "strike" })
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__ */ jsx15(ToolbarDivider, {}),
2303
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2304
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "left" }),
2305
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "center" }),
2306
- /* @__PURE__ */ jsx15(AlignButton, { editor, alignment: "right" })
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__ */ jsx15(ToolbarDivider, {}),
2309
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2310
- /* @__PURE__ */ jsx15(ListButton, { editor, type: "bullet" }),
2311
- /* @__PURE__ */ jsx15(ListButton, { editor, type: "numbered" })
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__ */ jsxs9("div", { className: "lumir-toolbar-row", children: [
2315
- /* @__PURE__ */ jsx15("div", { className: "lumir-toolbar-group", children: /* @__PURE__ */ jsx15(BlockTypeSelect, { editor }) }),
2316
- /* @__PURE__ */ jsx15(ToolbarDivider, {}),
2317
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2318
- /* @__PURE__ */ jsx15(ColorButton, { editor, type: "text" }),
2319
- /* @__PURE__ */ jsx15(ColorButton, { editor, type: "background" })
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__ */ jsx15(ToolbarDivider, {}),
2322
- /* @__PURE__ */ jsxs9("div", { className: "lumir-toolbar-group", children: [
2323
- /* @__PURE__ */ jsx15(ImageButton, { editor, onImageUpload }),
2324
- /* @__PURE__ */ jsx15(LinkButton, { editor }),
2325
- /* @__PURE__ */ jsx15(TableButton, { editor }),
2326
- /* @__PURE__ */ jsx15(HTMLImportButton, { editor })
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__ */ jsx15(
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__ */ jsx15(
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__ */ jsx15(MinimizedLayout, {}) : isCompact ? /* @__PURE__ */ jsx15(TwoRowLayout, {}) : /* @__PURE__ */ jsx15(SingleRowLayout, {})
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
- return new _LumirEditorError(
2423
- `Invalid file type: ${fileName}. Only image files are allowed.`,
2424
- {
2425
- code: "INVALID_FILE_TYPE",
2426
- context: { fileName }
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 jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
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 extractImageUrls = (blocks) => {
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
- urls.add(url);
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 findDeletedImageUrls = (previousUrls, currentUrls) => {
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__ */ jsx16(
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__ */ jsxs10("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
2665
- /* @__PURE__ */ jsx16("rect", { x: "1", y: "3", width: "14", height: "10", rx: "2", stroke: "currentColor", strokeWidth: "1.5", fill: "none" }),
2666
- /* @__PURE__ */ jsx16("line", { x1: "1", y1: "9", x2: "15", y2: "9", stroke: "currentColor", strokeWidth: "1.5" }),
2667
- /* @__PURE__ */ jsx16("circle", { cx: "5", cy: "6.5", r: "1.5", stroke: "currentColor", strokeWidth: "1", fill: "none" })
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__ */ jsxs10(
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__ */ jsx16(EditLinkButton, { url: props.url, text: props.text, editLink: props.editLink }),
2684
- /* @__PURE__ */ jsx16(OpenLinkButton, { url: props.url }),
2685
- /* @__PURE__ */ jsx16(DeleteLinkButton, { deleteLink: props.deleteLink }),
2686
- hasLinkPreview && /* @__PURE__ */ jsx16(ConvertToPreviewButton, { url: props.url })
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] = useState7(false);
2729
- const [errorMessage, setErrorMessage] = useState7(null);
2730
- const handleError = useCallback13(
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
- const fileNameTransformRef = useRef8(s3Upload?.fileNameTransform);
2761
- useEffect7(() => {
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
- if (!isImageFile(file)) {
2801
- const error = LumirEditorError.invalidFileType(file.name);
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
- let imageUrl;
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
- imageUrl = await uploadFile(file);
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
- imageUrl = await s3Uploader(file);
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
- return imageUrl;
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(isImageFile);
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
- editor2.pasteHTML(
2874
- `<img src="${escapeHtml(url)}" alt="image" />`
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
- "Image upload failed, skipped:",
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
- useEffect7(() => {
3352
+ useEffect8(() => {
2909
3353
  if (editor) {
2910
3354
  editor.isEditable = editable;
2911
3355
  }
2912
3356
  }, [editor, editable]);
2913
- useEffect7(() => {
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 previousImageUrlsRef = useRef8(/* @__PURE__ */ new Set());
2922
- useEffect7(() => {
3365
+ const previousMediaUrlsRef = useRef9(/* @__PURE__ */ new Set());
3366
+ useEffect8(() => {
2923
3367
  if (!editor) return;
2924
3368
  const initialBlocks = editor.topLevelBlocks;
2925
- previousImageUrlsRef.current = extractImageUrls(initialBlocks);
3369
+ previousMediaUrlsRef.current = extractMediaUrls(initialBlocks);
2926
3370
  }, [editor]);
2927
- useEffect7(() => {
3371
+ useEffect8(() => {
2928
3372
  if (!editor || !onImageDelete) return;
2929
- const handleImageDeleteCheck = () => {
3373
+ const handleMediaDeleteCheck = () => {
2930
3374
  const currentBlocks = editor.topLevelBlocks;
2931
- const currentUrls = extractImageUrls(currentBlocks);
2932
- const previousUrls = previousImageUrlsRef.current;
2933
- const deletedUrls = findDeletedImageUrls(previousUrls, currentUrls);
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
- previousImageUrlsRef.current = currentUrls;
3381
+ previousMediaUrlsRef.current = currentUrls;
2938
3382
  };
2939
- return editor.onEditorContentChange(handleImageDeleteCheck);
3383
+ return editor.onEditorContentChange(handleMediaDeleteCheck);
2940
3384
  }, [editor, onImageDelete]);
2941
- useEffect7(() => {
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
- if (imageFiles.length === 0 && htmlFiles.length === 0) return;
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__ */ jsx16(BlockSideMenu, { ...props, children: /* @__PURE__ */ jsx16(DragHandleButton, { ...props }) });
3520
+ return (props) => /* @__PURE__ */ jsx17(BlockSideMenu, { ...props, children: /* @__PURE__ */ jsx17(DragHandleButton, { ...props }) });
3029
3521
  }, []);
3030
- return /* @__PURE__ */ jsxs10(
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__ */ jsx16(
3037
- FloatingMenu,
3038
- {
3039
- editor,
3040
- position: floatingMenuPosition,
3041
- onImageUpload: async () => {
3042
- const input = document.createElement("input");
3043
- input.type = "file";
3044
- input.accept = "image/*";
3045
- input.onchange = async (e) => {
3046
- const file = e.target.files?.[0];
3047
- if (file && editor.uploadFile) {
3048
- try {
3049
- setIsUploading(true);
3050
- const url = await editor.uploadFile(file);
3051
- editor.insertBlocks(
3052
- [
3053
- {
3054
- type: "image",
3055
- props: { url }
3056
- }
3057
- ],
3058
- editor.getTextCursorPosition().block,
3059
- "after"
3060
- );
3061
- } catch (err) {
3062
- console.error("Image upload failed:", err);
3063
- } finally {
3064
- setIsUploading(false);
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
- input.click();
3596
+ inputEl.value = "";
3597
+ }
3069
3598
  }
3070
- }
3071
- ),
3072
- /* @__PURE__ */ jsxs10(
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__ */ jsx16(LinkToolbarController, { linkToolbar: CustomLinkToolbar }) : /* @__PURE__ */ jsx16(LinkToolbarController, {})),
3088
- /* @__PURE__ */ jsx16(
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: useCallback13(
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 (["video", "audio", "file"].includes(key)) return false;
3099
- if (title.includes("video") || title.includes("audio") || title.includes("file"))
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__ */ jsxs10(
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__ */ jsx16("polyline", { points: "16 18 22 12 16 6" }),
3147
- /* @__PURE__ */ jsx16("polyline", { points: "8 6 2 12 8 18" })
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__ */ jsxs10(
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__ */ jsx16("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
3185
- /* @__PURE__ */ jsx16("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
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__ */ jsx16(SideMenuController, { sideMenu: DragHandleOnlySideMenu })
3766
+ !sideMenuAddButton && /* @__PURE__ */ jsx17(SideMenuController, { sideMenu: DragHandleOnlySideMenu })
3205
3767
  ]
3206
3768
  }
3207
3769
  ),
3208
- isUploading && /* @__PURE__ */ jsx16("div", { className: "lumirEditor-upload-overlay", children: /* @__PURE__ */ jsx16("div", { className: "lumirEditor-spinner" }) }),
3209
- errorMessage && /* @__PURE__ */ jsxs10("div", { className: "lumirEditor-error-toast", children: [
3210
- /* @__PURE__ */ jsx16("span", { className: "lumirEditor-error-icon", children: "\u26A0\uFE0F" }),
3211
- /* @__PURE__ */ jsx16("span", { className: "lumirEditor-error-message", children: errorMessage }),
3212
- /* @__PURE__ */ jsx16(
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",