@lumir-company/editor 0.4.8 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -6
- package/dist/index.d.mts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +62 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +93 -93
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
- [파일명 커스터마이징](#파일명-커스터마이징)
|
|
19
19
|
- [커스텀 업로더](#2-커스텀-업로더)
|
|
20
20
|
- [동영상 업로드 및 임베딩](#동영상-업로드-및-임베딩)
|
|
21
|
+
- [업로드 진행률 표시](#업로드-진행률-표시-이미지동영상-공통)
|
|
21
22
|
- [이미지·동영상 업로드 상세 가이드](#이미지동영상-업로드-상세-가이드)
|
|
22
23
|
- [이미지·비디오 삭제](#이미지비디오-삭제)
|
|
23
24
|
- [HTML 미리보기](#html-미리보기)
|
|
@@ -457,6 +458,29 @@ const imageUrl = await s3Uploader(imageFile);
|
|
|
457
458
|
- **지원 형식**: MP4, WebM, OGG
|
|
458
459
|
- **삽입 경로**: 붙여넣기, 드래그 앤 드롭, 슬래시 메뉴("Video"), FloatingMenu 이미지/동영상 버튼
|
|
459
460
|
|
|
461
|
+
### 업로드 진행률 표시 (이미지·동영상 공통)
|
|
462
|
+
|
|
463
|
+
S3 업로드 시 `s3Upload.onProgress` 콜백을 지정하면 업로드 진행률(0~100%)을 받을 수 있습니다. 에디터는 내부적으로 이 값을 사용해 업로드 중 툴바에 **"n%"** 를 표시합니다. 동영상처럼 대용량 파일은 브라우저가 `progress` 이벤트를 자주 보내지 않을 수 있어, 내부적으로 **보간 로직**을 적용해 0→100만 보이지 않고 중간 진행률이 부드럽게 갱신되도록 했습니다.
|
|
464
|
+
|
|
465
|
+
```tsx
|
|
466
|
+
<LumirEditor
|
|
467
|
+
allowVideoUpload={true}
|
|
468
|
+
s3Upload={{
|
|
469
|
+
apiEndpoint: "/api/s3/presigned",
|
|
470
|
+
env: "production",
|
|
471
|
+
path: "videos",
|
|
472
|
+
appendUUID: true,
|
|
473
|
+
onProgress: (percent) => {
|
|
474
|
+
console.log(`업로드 진행률: ${percent}%`);
|
|
475
|
+
// 에디터 기본 UI에 이미 표시되며, 필요 시 자체 프로그레스 바 등에 연동 가능
|
|
476
|
+
},
|
|
477
|
+
}}
|
|
478
|
+
/>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
- **동작**: S3 PUT 요청 시에만 호출됩니다. Presigned URL 요청 단계에서는 호출되지 않습니다.
|
|
482
|
+
- **표시**: `onProgress`를 넘기면 에디터 툴바에 `n%`가 자동 표시되며, 업로드 완료 시 숨겨집니다.
|
|
483
|
+
|
|
460
484
|
### 데이터 내부 동영상 임베딩
|
|
461
485
|
|
|
462
486
|
동영상 블록은 `initialContent` / `onContentChange`에 포함됩니다. 저장 시 `{ type: "video", props: { url: "..." } }` 형태로 블록이 유지됩니다.
|
|
@@ -488,14 +512,34 @@ const imageUrl = await s3Uploader(imageFile);
|
|
|
488
512
|
|
|
489
513
|
- **MIME**: `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `image/bmp`
|
|
490
514
|
- **확장자**: `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.bmp`
|
|
491
|
-
- **용량**: 최대 10MB
|
|
515
|
+
- **용량**: 기본 최대 10MB. `maxImageFileSize`(바이트)로 변경 가능.
|
|
492
516
|
- **제외**: SVG (XSS 방지로 업로드 불가)
|
|
493
517
|
|
|
494
518
|
**동영상** (`allowVideoUpload={true}`일 때)
|
|
495
519
|
|
|
496
520
|
- **MIME**: `video/mp4`, `video/webm`, `video/ogg`, `video/quicktime`
|
|
497
521
|
- **확장자**: `.mp4`, `.webm`, `.ogg`, `.mov`
|
|
498
|
-
- **용량**: 최대 100MB
|
|
522
|
+
- **용량**: 기본 최대 100MB. `maxVideoFileSize`(바이트)로 변경 가능.
|
|
523
|
+
|
|
524
|
+
**업로드 타임아웃**: S3 업로드 시 PUT 요청 타임아웃은 `s3Upload.uploadTimeoutMs`로 설정합니다. 미설정 시 120초(120000ms)가 적용됩니다.
|
|
525
|
+
|
|
526
|
+
**용량 및 타임아웃 사용자 설정**
|
|
527
|
+
|
|
528
|
+
이미지·동영상 최대 용량과 S3 PUT 타임아웃을 props로 변경할 수 있습니다. 미설정 시 기본값(이미지 10MB, 동영상 100MB, 타임아웃 120초)이 적용됩니다.
|
|
529
|
+
|
|
530
|
+
```tsx
|
|
531
|
+
<LumirEditor
|
|
532
|
+
allowVideoUpload={true}
|
|
533
|
+
maxImageFileSize={5 * 1024 * 1024} // 5MB
|
|
534
|
+
maxVideoFileSize={200 * 1024 * 1024} // 200MB
|
|
535
|
+
s3Upload={{
|
|
536
|
+
apiEndpoint: "/api/s3/presigned",
|
|
537
|
+
env: "production",
|
|
538
|
+
path: "uploads",
|
|
539
|
+
uploadTimeoutMs: 180000, // 180초 (대용량 동영상 시 연장)
|
|
540
|
+
}}
|
|
541
|
+
/>
|
|
542
|
+
```
|
|
499
543
|
|
|
500
544
|
### 3. 삽입 경로 (공통)
|
|
501
545
|
|
|
@@ -643,7 +687,7 @@ Undo로 블록을 복원해도 이미 삭제 API를 호출했다면 서버 상
|
|
|
643
687
|
### 7. 에러 처리
|
|
644
688
|
|
|
645
689
|
- **지원하지 않는 형식**: 업로드 시 `LumirEditorError`가 발생할 수 있으며, `onError`로 처리할 수 있습니다.
|
|
646
|
-
- **용량 초과**: 이미지 10MB·동영상 100MB를 넘으면 업로드가 거부됩니다.
|
|
690
|
+
- **용량 초과**: 기본 한도(이미지 10MB·동영상 100MB)를 넘으면 업로드가 거부됩니다. `maxImageFileSize`, `maxVideoFileSize`로 한도를 변경할 수 있습니다.
|
|
647
691
|
- **업로드 실패**: `uploadFile` 또는 S3 업로드에서 예외가 나면 해당 파일만 삽입되지 않고, 콘솔에 경고가 출력됩니다.
|
|
648
692
|
|
|
649
693
|
```tsx
|
|
@@ -1049,8 +1093,10 @@ app.get("/api/link-preview", async (req, res) => {
|
|
|
1049
1093
|
| `editable` | `boolean` | `true` | 편집 가능 여부 |
|
|
1050
1094
|
| `placeholder` | `string` | `undefined` | 빈 블록 안내 텍스트 |
|
|
1051
1095
|
| `linkPreview` | `{ apiEndpoint: string }` | `undefined` | 링크 프리뷰 설정 |
|
|
1052
|
-
| `theme`
|
|
1053
|
-
| `className`
|
|
1096
|
+
| `theme` | `"light" \| "dark"` | `"light"` | 테마 |
|
|
1097
|
+
| `className` | `string` | `""` | CSS 클래스 |
|
|
1098
|
+
| `maxImageFileSize` | `number` | `undefined` | 이미지 최대 용량(바이트). 미설정 시 10MB |
|
|
1099
|
+
| `maxVideoFileSize` | `number` | `undefined` | 동영상 최대 용량(바이트). 미설정 시 100MB |
|
|
1054
1100
|
|
|
1055
1101
|
### S3UploaderConfig
|
|
1056
1102
|
|
|
@@ -1065,6 +1111,11 @@ interface S3UploaderConfig {
|
|
|
1065
1111
|
fileNameTransform?: (nameWithoutExt: string, file: File) => string; // 확장자 제외한 이름 변환
|
|
1066
1112
|
appendUUID?: boolean; // true: 파일명 뒤에 UUID 추가 (확장자 앞에 삽입)
|
|
1067
1113
|
preserveExtension?: boolean; // false: 확장자를 붙이지 않음 (기본: true)
|
|
1114
|
+
|
|
1115
|
+
// 선택 (업로드 동작)
|
|
1116
|
+
onProgress?: (percent: number) => void; // 업로드 진행률 0~100 콜백 (S3 PUT 시만 호출, 중간 진행률 보간 지원)
|
|
1117
|
+
uploadTimeoutMs?: number; // PUT 타임아웃(ms). 미설정 시 120000(120초). 대용량 동영상 시 연장 권장
|
|
1118
|
+
maxRetries?: number; // PUT 실패 시 재시도 횟수. 기본 2(최대 3회 시도)
|
|
1068
1119
|
}
|
|
1069
1120
|
```
|
|
1070
1121
|
|
|
@@ -1087,6 +1138,9 @@ interface LumirEditorProps {
|
|
|
1087
1138
|
fileNameTransform?: (nameWithoutExt: string, file: File) => string; // 확장자 제외한 이름 변환
|
|
1088
1139
|
appendUUID?: boolean; // UUID 자동 추가 (확장자 앞)
|
|
1089
1140
|
preserveExtension?: boolean; // 확장자 자동 붙이기 (기본: true)
|
|
1141
|
+
onProgress?: (percent: number) => void; // 업로드 진행률 0~100 (이미지·동영상 공통, 중간 진행률 보간)
|
|
1142
|
+
uploadTimeoutMs?: number; // PUT 타임아웃(ms). 기본 120000
|
|
1143
|
+
maxRetries?: number; // PUT 재시도 횟수. 기본 2
|
|
1090
1144
|
};
|
|
1091
1145
|
|
|
1092
1146
|
// === 콜백 ===
|
|
@@ -1124,6 +1178,8 @@ interface LumirEditorProps {
|
|
|
1124
1178
|
allowVideoUpload?: boolean; // 비디오 업로드 허용 (기본: false)
|
|
1125
1179
|
allowAudioUpload?: boolean; // 오디오 업로드 허용 (기본: false)
|
|
1126
1180
|
allowFileUpload?: boolean; // 일반 파일 업로드 허용 (기본: false)
|
|
1181
|
+
maxImageFileSize?: number; // 이미지 최대 파일 크기(바이트). 미설정 시 10MB
|
|
1182
|
+
maxVideoFileSize?: number; // 동영상 최대 파일 크기(바이트). 미설정 시 100MB
|
|
1127
1183
|
}
|
|
1128
1184
|
```
|
|
1129
1185
|
|
|
@@ -1328,9 +1384,25 @@ const url = await uploader(imageFile);
|
|
|
1328
1384
|
|
|
1329
1385
|
## 변경 로그
|
|
1330
1386
|
|
|
1387
|
+
### v0.4.10
|
|
1388
|
+
|
|
1389
|
+
- **동영상·이미지 업로드 진행률 표시**
|
|
1390
|
+
- S3 업로드 시 진행률이 0만 보이다가 100으로 바로 완료되던 문제 개선
|
|
1391
|
+
- `xhr.upload.onprogress`와 **보간 타이머**를 함께 사용해 중간 진행률(0→…→100)이 부드럽게 갱신되도록 변경
|
|
1392
|
+
- 업로드 시작 직후 `onProgress(0)` 호출, 완료 시 `onProgress(100)` 보장
|
|
1393
|
+
- README: `s3Upload.onProgress` 설명 및 업로드 진행률 표시 섹션 추가
|
|
1394
|
+
- README: `S3UploaderConfig`에 `onProgress`, `uploadTimeoutMs`, `maxRetries` 문서화
|
|
1395
|
+
|
|
1396
|
+
### v0.4.9
|
|
1397
|
+
|
|
1398
|
+
- **업로드 용량·타임아웃 사용자 설정**
|
|
1399
|
+
- `maxImageFileSize`, `maxVideoFileSize` prop 추가 (미설정 시 기본 10MB/100MB)
|
|
1400
|
+
- `isImageFile(file, maxSize?)`, `isVideoFile(file, maxSize?)` 시그니처 확장
|
|
1401
|
+
- README: 용량 및 타임아웃 설정 예시 및 `s3Upload.uploadTimeoutMs` 안내 보강
|
|
1402
|
+
|
|
1331
1403
|
### v0.4.8
|
|
1332
1404
|
|
|
1333
|
-
-
|
|
1405
|
+
- README update (video & image upload)
|
|
1334
1406
|
- 버전 배포
|
|
1335
1407
|
|
|
1336
1408
|
### v0.4.6
|
package/dist/index.d.mts
CHANGED
|
@@ -88,6 +88,10 @@ interface LumirEditorProps {
|
|
|
88
88
|
allowVideoUpload?: boolean;
|
|
89
89
|
allowAudioUpload?: boolean;
|
|
90
90
|
allowFileUpload?: boolean;
|
|
91
|
+
/** 이미지 최대 파일 크기(바이트). 미설정 시 기본 제한(10MB) 사용 */
|
|
92
|
+
maxImageFileSize?: number;
|
|
93
|
+
/** 동영상 최대 파일 크기(바이트). 미설정 시 기본 제한(100MB) 사용 */
|
|
94
|
+
maxVideoFileSize?: number;
|
|
91
95
|
tables?: {
|
|
92
96
|
splitCells?: boolean;
|
|
93
97
|
cellBackgroundColor?: boolean;
|
|
@@ -204,7 +208,7 @@ declare class EditorConfig {
|
|
|
204
208
|
*/
|
|
205
209
|
static getDisabledExtensions(userExtensions?: string[], allowVideo?: boolean, allowAudio?: boolean, allowFile?: boolean): string[];
|
|
206
210
|
}
|
|
207
|
-
declare function LumirEditor({ initialContent, initialEmptyBlocks, uploadFile, s3Upload, tables, heading, defaultStyles, disableExtensions, tabBehavior, trailingBlock, allowVideoUpload, allowAudioUpload, allowFileUpload, linkPreview, editable, theme, formattingToolbar, linkToolbar, sideMenu, emojiPicker, filePanel, tableHandles, onSelectionChange, className, placeholder, sideMenuAddButton, floatingMenu, floatingMenuPosition, onContentChange, onError, onImageDelete, }: LumirEditorProps): react_jsx_runtime.JSX.Element;
|
|
211
|
+
declare function LumirEditor({ initialContent, initialEmptyBlocks, uploadFile, s3Upload, tables, heading, defaultStyles, disableExtensions, tabBehavior, trailingBlock, allowVideoUpload, allowAudioUpload, allowFileUpload, maxImageFileSize, maxVideoFileSize, linkPreview, editable, theme, formattingToolbar, linkToolbar, sideMenu, emojiPicker, filePanel, tableHandles, onSelectionChange, className, placeholder, sideMenuAddButton, floatingMenu, floatingMenuPosition, onContentChange, onError, onImageDelete, }: LumirEditorProps): react_jsx_runtime.JSX.Element;
|
|
208
212
|
|
|
209
213
|
declare function cn(...inputs: (string | undefined | null | false)[]): string;
|
|
210
214
|
|
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,10 @@ interface LumirEditorProps {
|
|
|
88
88
|
allowVideoUpload?: boolean;
|
|
89
89
|
allowAudioUpload?: boolean;
|
|
90
90
|
allowFileUpload?: boolean;
|
|
91
|
+
/** 이미지 최대 파일 크기(바이트). 미설정 시 기본 제한(10MB) 사용 */
|
|
92
|
+
maxImageFileSize?: number;
|
|
93
|
+
/** 동영상 최대 파일 크기(바이트). 미설정 시 기본 제한(100MB) 사용 */
|
|
94
|
+
maxVideoFileSize?: number;
|
|
91
95
|
tables?: {
|
|
92
96
|
splitCells?: boolean;
|
|
93
97
|
cellBackgroundColor?: boolean;
|
|
@@ -204,7 +208,7 @@ declare class EditorConfig {
|
|
|
204
208
|
*/
|
|
205
209
|
static getDisabledExtensions(userExtensions?: string[], allowVideo?: boolean, allowAudio?: boolean, allowFile?: boolean): string[];
|
|
206
210
|
}
|
|
207
|
-
declare function LumirEditor({ initialContent, initialEmptyBlocks, uploadFile, s3Upload, tables, heading, defaultStyles, disableExtensions, tabBehavior, trailingBlock, allowVideoUpload, allowAudioUpload, allowFileUpload, linkPreview, editable, theme, formattingToolbar, linkToolbar, sideMenu, emojiPicker, filePanel, tableHandles, onSelectionChange, className, placeholder, sideMenuAddButton, floatingMenu, floatingMenuPosition, onContentChange, onError, onImageDelete, }: LumirEditorProps): react_jsx_runtime.JSX.Element;
|
|
211
|
+
declare function LumirEditor({ initialContent, initialEmptyBlocks, uploadFile, s3Upload, tables, heading, defaultStyles, disableExtensions, tabBehavior, trailingBlock, allowVideoUpload, allowAudioUpload, allowFileUpload, maxImageFileSize, maxVideoFileSize, linkPreview, editable, theme, formattingToolbar, linkToolbar, sideMenu, emojiPicker, filePanel, tableHandles, onSelectionChange, className, placeholder, sideMenuAddButton, floatingMenu, floatingMenuPosition, onContentChange, onError, onImageDelete, }: LumirEditorProps): react_jsx_runtime.JSX.Element;
|
|
208
212
|
|
|
209
213
|
declare function cn(...inputs: (string | undefined | null | false)[]): string;
|
|
210
214
|
|
package/dist/index.js
CHANGED
|
@@ -188,19 +188,54 @@ var createS3Uploader = (config) => {
|
|
|
188
188
|
await new Promise((resolve, reject) => {
|
|
189
189
|
const xhr = new XMLHttpRequest();
|
|
190
190
|
xhr.timeout = uploadTimeoutMs;
|
|
191
|
+
let lastReported = -1;
|
|
192
|
+
const REPORT_INTERVAL_MS = 100;
|
|
193
|
+
const simulatedCap = 90;
|
|
194
|
+
let simulatedPercent = 0;
|
|
195
|
+
const simId = setInterval(() => {
|
|
196
|
+
if (simulatedPercent >= simulatedCap) return;
|
|
197
|
+
simulatedPercent = Math.min(simulatedCap, simulatedPercent + 3);
|
|
198
|
+
const p = Math.min(100, simulatedPercent);
|
|
199
|
+
if (p > lastReported) {
|
|
200
|
+
lastReported = p;
|
|
201
|
+
onProgress(p);
|
|
202
|
+
}
|
|
203
|
+
}, REPORT_INTERVAL_MS);
|
|
204
|
+
const clearSim = () => {
|
|
205
|
+
clearInterval(simId);
|
|
206
|
+
};
|
|
191
207
|
xhr.upload.onprogress = (e) => {
|
|
192
208
|
if (e.lengthComputable) {
|
|
193
|
-
|
|
209
|
+
const p = Math.min(100, Math.round(e.loaded / e.total * 100));
|
|
210
|
+
if (p >= simulatedCap) clearSim();
|
|
211
|
+
const toReport = Math.max(p, simulatedPercent);
|
|
212
|
+
if (toReport > lastReported) {
|
|
213
|
+
lastReported = toReport;
|
|
214
|
+
onProgress(toReport);
|
|
215
|
+
}
|
|
194
216
|
}
|
|
195
217
|
};
|
|
196
218
|
xhr.onload = () => {
|
|
197
|
-
|
|
198
|
-
|
|
219
|
+
clearSim();
|
|
220
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
221
|
+
if (lastReported < 100) onProgress(100);
|
|
222
|
+
resolve();
|
|
223
|
+
} else {
|
|
224
|
+
reject(new Error(`Failed to upload file: ${xhr.statusText}`));
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
xhr.onerror = () => {
|
|
228
|
+
clearSim();
|
|
229
|
+
reject(new Error("Upload failed"));
|
|
230
|
+
};
|
|
231
|
+
xhr.ontimeout = () => {
|
|
232
|
+
clearSim();
|
|
233
|
+
reject(new Error("Upload timeout"));
|
|
199
234
|
};
|
|
200
|
-
xhr.onerror = () => reject(new Error("Upload failed"));
|
|
201
|
-
xhr.ontimeout = () => reject(new Error("Upload timeout"));
|
|
202
235
|
xhr.open("PUT", validatedPresignedUrl);
|
|
203
236
|
xhr.setRequestHeader("Content-Type", file.type || "application/octet-stream");
|
|
237
|
+
onProgress(0);
|
|
238
|
+
lastReported = 0;
|
|
204
239
|
xhr.send(file);
|
|
205
240
|
});
|
|
206
241
|
} else {
|
|
@@ -2817,7 +2852,7 @@ var ALLOWED_VIDEO_EXTENSIONS = [
|
|
|
2817
2852
|
// src/components/LumirEditor.tsx
|
|
2818
2853
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2819
2854
|
var DEBUG_LOG = (loc, msg, data) => {
|
|
2820
|
-
fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
2855
|
+
const p = fetch("http://127.0.0.1:7686/ingest/1f8ee1c5-0cf0-4ae7-91ed-5ea7ed17130a", {
|
|
2821
2856
|
method: "POST",
|
|
2822
2857
|
headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "b73262" },
|
|
2823
2858
|
body: JSON.stringify({
|
|
@@ -2827,7 +2862,8 @@ var DEBUG_LOG = (loc, msg, data) => {
|
|
|
2827
2862
|
data,
|
|
2828
2863
|
timestamp: Date.now()
|
|
2829
2864
|
})
|
|
2830
|
-
})
|
|
2865
|
+
});
|
|
2866
|
+
if (p && typeof p.catch === "function") p.catch(() => {
|
|
2831
2867
|
});
|
|
2832
2868
|
};
|
|
2833
2869
|
var ContentUtils = class {
|
|
@@ -2948,8 +2984,9 @@ var EditorConfig = class {
|
|
|
2948
2984
|
return Array.from(set);
|
|
2949
2985
|
}
|
|
2950
2986
|
};
|
|
2951
|
-
var isImageFile = (file) => {
|
|
2952
|
-
|
|
2987
|
+
var isImageFile = (file, maxSize) => {
|
|
2988
|
+
const limit = maxSize !== void 0 ? maxSize : MAX_FILE_SIZE;
|
|
2989
|
+
if (file.size === 0 || file.size > limit) {
|
|
2953
2990
|
return false;
|
|
2954
2991
|
}
|
|
2955
2992
|
const fileName = file.name?.toLowerCase() || "";
|
|
@@ -2958,8 +2995,9 @@ var isImageFile = (file) => {
|
|
|
2958
2995
|
}
|
|
2959
2996
|
return file.type?.startsWith("image/") || !file.type && /\.(png|jpe?g|gif|webp|bmp)$/i.test(fileName);
|
|
2960
2997
|
};
|
|
2961
|
-
var isVideoFile = (file) => {
|
|
2962
|
-
const
|
|
2998
|
+
var isVideoFile = (file, maxSize) => {
|
|
2999
|
+
const limit = maxSize !== void 0 ? maxSize : MAX_VIDEO_FILE_SIZE;
|
|
3000
|
+
const sizeOk = file.size > 0 && file.size <= limit;
|
|
2963
3001
|
const fileName = file.name?.toLowerCase() || "";
|
|
2964
3002
|
const mimeMatch = ALLOWED_VIDEO_MIME_TYPES.has(file.type);
|
|
2965
3003
|
const videoPrefix = typeof file.type === "string" && file.type.startsWith("video/");
|
|
@@ -3100,6 +3138,8 @@ function LumirEditor({
|
|
|
3100
3138
|
allowVideoUpload = false,
|
|
3101
3139
|
allowAudioUpload = false,
|
|
3102
3140
|
allowFileUpload = false,
|
|
3141
|
+
maxImageFileSize,
|
|
3142
|
+
maxVideoFileSize,
|
|
3103
3143
|
// link preview
|
|
3104
3144
|
linkPreview,
|
|
3105
3145
|
// view options
|
|
@@ -3214,8 +3254,8 @@ function LumirEditor({
|
|
|
3214
3254
|
tabBehavior,
|
|
3215
3255
|
trailingBlock,
|
|
3216
3256
|
uploadFile: async (file) => {
|
|
3217
|
-
const allowedImage = isImageFile(file);
|
|
3218
|
-
const allowedVideo = allowVideoUpload && isVideoFile(file);
|
|
3257
|
+
const allowedImage = isImageFile(file, maxImageFileSize);
|
|
3258
|
+
const allowedVideo = allowVideoUpload && isVideoFile(file, maxVideoFileSize);
|
|
3219
3259
|
DEBUG_LOG("uploadFile:step1:entry", "editor uploadFile callback invoked", {
|
|
3220
3260
|
fileName: file.name,
|
|
3221
3261
|
fileType: file.type,
|
|
@@ -3309,7 +3349,7 @@ function LumirEditor({
|
|
|
3309
3349
|
const fileList = event?.clipboardData?.files ?? null;
|
|
3310
3350
|
const files = fileList ? Array.from(fileList) : [];
|
|
3311
3351
|
const acceptedFiles = files.filter(
|
|
3312
|
-
(f) => isImageFile(f) || allowVideoUpload && isVideoFile(f)
|
|
3352
|
+
(f) => isImageFile(f, maxImageFileSize) || allowVideoUpload && isVideoFile(f, maxVideoFileSize)
|
|
3313
3353
|
);
|
|
3314
3354
|
DEBUG_LOG("paste:step1:files", "paste clipboard files", {
|
|
3315
3355
|
filesCount: files.length,
|
|
@@ -3335,11 +3375,11 @@ function LumirEditor({
|
|
|
3335
3375
|
fileType: file.type
|
|
3336
3376
|
});
|
|
3337
3377
|
const url = await editor2.uploadFile(file);
|
|
3338
|
-
if (isImageFile(file)) {
|
|
3378
|
+
if (isImageFile(file, maxImageFileSize)) {
|
|
3339
3379
|
editor2.pasteHTML(
|
|
3340
3380
|
`<img src="${escapeHtml(url)}" alt="image" />`
|
|
3341
3381
|
);
|
|
3342
|
-
} else if (isVideoFile(file)) {
|
|
3382
|
+
} else if (isVideoFile(file, maxVideoFileSize)) {
|
|
3343
3383
|
const currentBlock = editor2.getTextCursorPosition().block;
|
|
3344
3384
|
editor2.insertBlocks(
|
|
3345
3385
|
[{ type: "video", props: { url } }],
|
|
@@ -3432,8 +3472,8 @@ function LumirEditor({
|
|
|
3432
3472
|
e.stopPropagation();
|
|
3433
3473
|
const items = Array.from(e.dataTransfer.items ?? []);
|
|
3434
3474
|
const files = items.filter((it) => it.kind === "file").map((it) => it.getAsFile()).filter((f) => !!f);
|
|
3435
|
-
const imageFiles = files.filter(isImageFile);
|
|
3436
|
-
const videoFiles = allowVideoUpload ? files.filter(isVideoFile) : [];
|
|
3475
|
+
const imageFiles = files.filter((f) => isImageFile(f, maxImageFileSize));
|
|
3476
|
+
const videoFiles = allowVideoUpload ? files.filter((f) => isVideoFile(f, maxVideoFileSize)) : [];
|
|
3437
3477
|
const htmlFiles = files.filter(isHtmlFile);
|
|
3438
3478
|
DEBUG_LOG("drop:step1:files", "drop received", {
|
|
3439
3479
|
filesCount: files.length,
|
|
@@ -3445,8 +3485,8 @@ function LumirEditor({
|
|
|
3445
3485
|
name: files[0].name,
|
|
3446
3486
|
type: files[0].type,
|
|
3447
3487
|
size: files[0].size,
|
|
3448
|
-
isImage: isImageFile(files[0]),
|
|
3449
|
-
isVideo: isVideoFile(files[0])
|
|
3488
|
+
isImage: isImageFile(files[0], maxImageFileSize),
|
|
3489
|
+
isVideo: isVideoFile(files[0], maxVideoFileSize)
|
|
3450
3490
|
} : null
|
|
3451
3491
|
});
|
|
3452
3492
|
if (imageFiles.length === 0 && htmlFiles.length === 0 && videoFiles.length === 0)
|
|
@@ -3581,8 +3621,8 @@ function LumirEditor({
|
|
|
3581
3621
|
});
|
|
3582
3622
|
const blockToInsertAfter = floatingMenuBlockRef.current;
|
|
3583
3623
|
if (file && editor.uploadFile && blockToInsertAfter) {
|
|
3584
|
-
const allowedImage = isImageFile(file);
|
|
3585
|
-
const allowedVideo = allowVideoUpload && isVideoFile(file);
|
|
3624
|
+
const allowedImage = isImageFile(file, maxImageFileSize);
|
|
3625
|
+
const allowedVideo = allowVideoUpload && isVideoFile(file, maxVideoFileSize);
|
|
3586
3626
|
DEBUG_LOG("FloatingMenu:step4:fileCheck", "allowed check", {
|
|
3587
3627
|
fileName: file.name,
|
|
3588
3628
|
allowedImage,
|