@cyberyozh/text-editor 0.3.0 → 0.3.2
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/editor.css +29 -0
- package/dist/editor.css.map +1 -1
- package/dist/editor.js +37 -4
- package/dist/editor.js.map +1 -1
- package/dist/editor.mjs +37 -4
- package/dist/editor.mjs.map +1 -1
- package/dist/styles/index.css +29 -0
- package/package.json +1 -1
- package/src/editor/dialogs/image-dialog/image-dialog.css +32 -0
- package/src/editor/dialogs/image-dialog/image-dialog.tsx +33 -1
- package/src/editor/handlers/insertion-handlers.ts +1 -2
- package/src/translations/en.json +4 -1
- package/src/translations/ru.json +4 -1
package/dist/styles/index.css
CHANGED
|
@@ -563,6 +563,35 @@
|
|
|
563
563
|
background: var(--ui-secondary-bg);
|
|
564
564
|
color: var(--ui-text-primary);
|
|
565
565
|
}
|
|
566
|
+
.image-dialog-error {
|
|
567
|
+
position: relative;
|
|
568
|
+
margin-bottom: 16px;
|
|
569
|
+
padding: 8px 12px;
|
|
570
|
+
border: 1px solid var(--ui-error-border);
|
|
571
|
+
border-radius: 4px;
|
|
572
|
+
background-color: var(--ui-error-bg);
|
|
573
|
+
color: var(--ui-error-text);
|
|
574
|
+
font-size: 13px;
|
|
575
|
+
}
|
|
576
|
+
.image-dialog-error-clear-button {
|
|
577
|
+
display: flex;
|
|
578
|
+
position: absolute;
|
|
579
|
+
top: 8px;
|
|
580
|
+
right: 8px;
|
|
581
|
+
align-items: center;
|
|
582
|
+
justify-content: center;
|
|
583
|
+
width: 20px;
|
|
584
|
+
height: 20px;
|
|
585
|
+
padding: 0;
|
|
586
|
+
border: none;
|
|
587
|
+
background-color: transparent;
|
|
588
|
+
cursor: pointer;
|
|
589
|
+
}
|
|
590
|
+
.image-dialog-error-clear-button svg {
|
|
591
|
+
width: 14px;
|
|
592
|
+
height: 14px;
|
|
593
|
+
color: var(--ui-error-text);
|
|
594
|
+
}
|
|
566
595
|
|
|
567
596
|
/* src/styles/components.css */
|
|
568
597
|
|
package/package.json
CHANGED
|
@@ -100,3 +100,35 @@
|
|
|
100
100
|
background: var(--ui-secondary-bg);
|
|
101
101
|
color: var(--ui-text-primary);
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
.image-dialog-error {
|
|
105
|
+
position: relative;
|
|
106
|
+
margin-bottom: 16px;
|
|
107
|
+
padding: 8px 12px;
|
|
108
|
+
border: 1px solid var(--ui-error-border);
|
|
109
|
+
border-radius: 4px;
|
|
110
|
+
background-color: var(--ui-error-bg);
|
|
111
|
+
color: var(--ui-error-text);
|
|
112
|
+
font-size: 13px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.image-dialog-error-clear-button {
|
|
116
|
+
display: flex;
|
|
117
|
+
position: absolute;
|
|
118
|
+
top: 8px;
|
|
119
|
+
right: 8px;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
width: 20px;
|
|
123
|
+
height: 20px;
|
|
124
|
+
padding: 0;
|
|
125
|
+
border: none;
|
|
126
|
+
background-color: transparent;
|
|
127
|
+
cursor: pointer;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.image-dialog-error-clear-button svg {
|
|
131
|
+
width: 14px;
|
|
132
|
+
height: 14px;
|
|
133
|
+
color: var(--ui-error-text);
|
|
134
|
+
}
|
|
@@ -90,13 +90,26 @@ export const ImageDialog = ({
|
|
|
90
90
|
height: constrainedDimensions.height,
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
+
const [fileUploadError, setFileUploadError] = useState<Error | null>(null);
|
|
94
|
+
|
|
93
95
|
const handleSelectFile = (file: File | undefined) => {
|
|
96
|
+
setFileUploadError(null);
|
|
97
|
+
|
|
94
98
|
if (!file) return;
|
|
95
99
|
|
|
100
|
+
if (!file.type.startsWith('image/')) {
|
|
101
|
+
setFileUploadError(new Error(translations.imageDialog.invalidFileType));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
96
105
|
const imageUrl = URL.createObjectURL(file);
|
|
97
106
|
const img = new Image();
|
|
98
107
|
img.src = imageUrl;
|
|
99
108
|
|
|
109
|
+
img.onerror = () => {
|
|
110
|
+
setFileUploadError(new Error(translations.imageDialog.invalidFileType));
|
|
111
|
+
};
|
|
112
|
+
|
|
100
113
|
img.onload = () => {
|
|
101
114
|
const naturalWidth = img.width;
|
|
102
115
|
const naturalHeight = img.height;
|
|
@@ -189,6 +202,7 @@ export const ImageDialog = ({
|
|
|
189
202
|
if (!formState.file) return;
|
|
190
203
|
|
|
191
204
|
setIsUploading(true);
|
|
205
|
+
|
|
192
206
|
try {
|
|
193
207
|
const result = await uploadHandler(formState.file);
|
|
194
208
|
|
|
@@ -204,6 +218,8 @@ export const ImageDialog = ({
|
|
|
204
218
|
});
|
|
205
219
|
|
|
206
220
|
handleClose();
|
|
221
|
+
} catch (error) {
|
|
222
|
+
setFileUploadError(error instanceof Error ? error : new Error(translations.imageDialog.unknownError));
|
|
207
223
|
} finally {
|
|
208
224
|
setIsUploading(false);
|
|
209
225
|
}
|
|
@@ -223,7 +239,9 @@ export const ImageDialog = ({
|
|
|
223
239
|
handleClose();
|
|
224
240
|
};
|
|
225
241
|
|
|
226
|
-
const
|
|
242
|
+
const isEditMode = mode === "edit";
|
|
243
|
+
const canSave = isEditMode || Boolean(formState.file);
|
|
244
|
+
const handleSave = isEditMode ? handleEditImage : handleAddImage;
|
|
227
245
|
|
|
228
246
|
const handleClose = () => {
|
|
229
247
|
clearImageFormFields();
|
|
@@ -315,6 +333,19 @@ export const ImageDialog = ({
|
|
|
315
333
|
)}
|
|
316
334
|
</div>
|
|
317
335
|
</div>
|
|
336
|
+
{fileUploadError && (
|
|
337
|
+
<div className="image-dialog-error">
|
|
338
|
+
{fileUploadError.message || translations.imageDialog.unknownError}
|
|
339
|
+
<button
|
|
340
|
+
type="button"
|
|
341
|
+
className="image-dialog-error-clear-button"
|
|
342
|
+
onClick={() => setFileUploadError(null)}
|
|
343
|
+
aria-label={translations.imageDialog.clearError}
|
|
344
|
+
>
|
|
345
|
+
<TiptapX />
|
|
346
|
+
</button>
|
|
347
|
+
</div>
|
|
348
|
+
)}
|
|
318
349
|
<div className="image-dialog-actions">
|
|
319
350
|
<Button
|
|
320
351
|
type="button"
|
|
@@ -328,6 +359,7 @@ export const ImageDialog = ({
|
|
|
328
359
|
isLoading={isUploading}
|
|
329
360
|
type="button"
|
|
330
361
|
onClick={handleSave}
|
|
362
|
+
disabled={!canSave}
|
|
331
363
|
>
|
|
332
364
|
{saveButtonText}
|
|
333
365
|
</Button>
|
|
@@ -17,11 +17,10 @@ export function useInsertionHandlers(imageHandlers?: ImageHandlers) {
|
|
|
17
17
|
}, [insertedImage, activeDialog]);
|
|
18
18
|
|
|
19
19
|
function genericInsertionHandler(file: File | undefined, event: Event) {
|
|
20
|
-
if (!file || !file.type.startsWith("image/")) return;
|
|
21
|
-
|
|
22
20
|
event.preventDefault();
|
|
23
21
|
event.stopPropagation();
|
|
24
22
|
|
|
23
|
+
if (!file || !file.type.startsWith("image/")) return;
|
|
25
24
|
if (!imageHandlers?.upload) return;
|
|
26
25
|
|
|
27
26
|
setInsertedImage(file);
|
package/src/translations/en.json
CHANGED
|
@@ -112,7 +112,10 @@
|
|
|
112
112
|
"captionLabel": "Image caption",
|
|
113
113
|
"captionPlaceholder": "Description under image...",
|
|
114
114
|
"save": "Save",
|
|
115
|
-
"add": "Add"
|
|
115
|
+
"add": "Add",
|
|
116
|
+
"invalidFileType": "File is not an image",
|
|
117
|
+
"unknownError": "Unknown error",
|
|
118
|
+
"clearError": "Clear error"
|
|
116
119
|
},
|
|
117
120
|
"videoUpload": {
|
|
118
121
|
"title": "Add video",
|
package/src/translations/ru.json
CHANGED
|
@@ -112,7 +112,10 @@
|
|
|
112
112
|
"captionLabel": "Подпись к изображению",
|
|
113
113
|
"captionPlaceholder": "Описание под изображением...",
|
|
114
114
|
"save": "Сохранить",
|
|
115
|
-
"add": "Добавить"
|
|
115
|
+
"add": "Добавить",
|
|
116
|
+
"invalidFileType": "Файл не является изображением",
|
|
117
|
+
"unknownError": "Неизвестная ошибка",
|
|
118
|
+
"clearError": "Сбросить ошибку"
|
|
116
119
|
},
|
|
117
120
|
"videoUpload": {
|
|
118
121
|
"title": "Добавить видео",
|