@cyberyozh/text-editor 0.3.2 → 0.4.0
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 +35 -43
- package/dist/editor.css.map +1 -1
- package/dist/editor.d.mts +5 -1
- package/dist/editor.d.ts +5 -1
- package/dist/editor.js +351 -314
- package/dist/editor.js.map +1 -1
- package/dist/editor.mjs +269 -232
- package/dist/editor.mjs.map +1 -1
- package/dist/styles/index.css +35 -43
- package/package.json +1 -1
- package/src/editor/components/dialog-error/dialog-error.css +35 -0
- package/src/editor/components/dialog-error/dialog-error.tsx +65 -0
- package/src/editor/components/dialog-error/index.ts +1 -0
- package/src/editor/components/index.ts +1 -0
- package/src/editor/dialogs/add-link-dialog/add-link-dialog.css +0 -9
- package/src/editor/dialogs/add-link-dialog/add-link-dialog.tsx +2 -2
- package/src/editor/dialogs/add-video-dialog/add-video-dialog.css +0 -9
- package/src/editor/dialogs/add-video-dialog/add-video-dialog.tsx +2 -2
- package/src/editor/dialogs/image-dialog/image-dialog.css +1 -29
- package/src/editor/dialogs/image-dialog/image-dialog.tsx +7 -13
- package/src/editor/index.ts +1 -0
- package/src/styles/components.css +1 -0
- package/src/translations/en.json +4 -4
- package/src/translations/ru.json +4 -4
- package/src/types/common.ts +3 -0
- package/src/types/index.ts +1 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/is-combined-error.ts +9 -0
package/dist/styles/index.css
CHANGED
|
@@ -158,6 +158,40 @@
|
|
|
158
158
|
padding: 24px;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
/* src/editor/components/dialog-error/dialog-error.css */
|
|
162
|
+
.dialog-error {
|
|
163
|
+
position: relative;
|
|
164
|
+
padding: 8px 12px;
|
|
165
|
+
border: 1px solid var(--ui-error-border);
|
|
166
|
+
border-radius: 4px;
|
|
167
|
+
background-color: var(--ui-error-bg);
|
|
168
|
+
color: var(--ui-error-text);
|
|
169
|
+
font-size: 13px;
|
|
170
|
+
}
|
|
171
|
+
.dialog-error-list {
|
|
172
|
+
margin: 0;
|
|
173
|
+
padding-left: 16px;
|
|
174
|
+
}
|
|
175
|
+
.dialog-error-clear-button {
|
|
176
|
+
display: flex;
|
|
177
|
+
position: absolute;
|
|
178
|
+
top: 8px;
|
|
179
|
+
right: 8px;
|
|
180
|
+
align-items: center;
|
|
181
|
+
justify-content: center;
|
|
182
|
+
width: 20px;
|
|
183
|
+
height: 20px;
|
|
184
|
+
padding: 0;
|
|
185
|
+
border: none;
|
|
186
|
+
background-color: transparent;
|
|
187
|
+
cursor: pointer;
|
|
188
|
+
}
|
|
189
|
+
.dialog-error-clear-button svg {
|
|
190
|
+
width: 14px;
|
|
191
|
+
height: 14px;
|
|
192
|
+
color: var(--ui-error-text);
|
|
193
|
+
}
|
|
194
|
+
|
|
161
195
|
/* src/editor/dialogs/add-katex-dialog/add-katex-dialog.css */
|
|
162
196
|
.katex-dialog-title {
|
|
163
197
|
margin: 0 0 16px 0;
|
|
@@ -298,14 +332,6 @@
|
|
|
298
332
|
.link-dialog-input::placeholder {
|
|
299
333
|
color: var(--tiptap-color-text-placeholder);
|
|
300
334
|
}
|
|
301
|
-
.link-dialog-error {
|
|
302
|
-
padding: 8px 12px;
|
|
303
|
-
border: 1px solid var(--ui-error-border);
|
|
304
|
-
border-radius: 4px;
|
|
305
|
-
background-color: var(--ui-error-bg);
|
|
306
|
-
color: var(--ui-error-text);
|
|
307
|
-
font-size: 13px;
|
|
308
|
-
}
|
|
309
335
|
.link-dialog-actions {
|
|
310
336
|
display: flex;
|
|
311
337
|
justify-content: flex-end;
|
|
@@ -423,14 +449,6 @@
|
|
|
423
449
|
.video-dialog-platform-list li {
|
|
424
450
|
margin: 4px 0;
|
|
425
451
|
}
|
|
426
|
-
.video-dialog-error {
|
|
427
|
-
padding: 8px 12px;
|
|
428
|
-
border: 1px solid var(--ui-error-border);
|
|
429
|
-
border-radius: 4px;
|
|
430
|
-
background-color: var(--ui-error-bg);
|
|
431
|
-
color: var(--ui-error-text);
|
|
432
|
-
font-size: 13px;
|
|
433
|
-
}
|
|
434
452
|
.video-dialog-actions {
|
|
435
453
|
display: flex;
|
|
436
454
|
justify-content: flex-end;
|
|
@@ -563,34 +581,8 @@
|
|
|
563
581
|
background: var(--ui-secondary-bg);
|
|
564
582
|
color: var(--ui-text-primary);
|
|
565
583
|
}
|
|
566
|
-
.image-dialog-error {
|
|
567
|
-
position: relative;
|
|
584
|
+
.image-dialog-error-spacing {
|
|
568
585
|
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
586
|
}
|
|
595
587
|
|
|
596
588
|
/* src/styles/components.css */
|
package/package.json
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.dialog-error {
|
|
2
|
+
position: relative;
|
|
3
|
+
padding: 8px 12px;
|
|
4
|
+
border: 1px solid var(--ui-error-border);
|
|
5
|
+
border-radius: 4px;
|
|
6
|
+
background-color: var(--ui-error-bg);
|
|
7
|
+
color: var(--ui-error-text);
|
|
8
|
+
font-size: 13px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.dialog-error-list {
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding-left: 16px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.dialog-error-clear-button {
|
|
17
|
+
display: flex;
|
|
18
|
+
position: absolute;
|
|
19
|
+
top: 8px;
|
|
20
|
+
right: 8px;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
width: 20px;
|
|
24
|
+
height: 20px;
|
|
25
|
+
padding: 0;
|
|
26
|
+
border: none;
|
|
27
|
+
background-color: transparent;
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.dialog-error-clear-button svg {
|
|
32
|
+
width: 14px;
|
|
33
|
+
height: 14px;
|
|
34
|
+
color: var(--ui-error-text);
|
|
35
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { isCombinedError } from "@/utils";
|
|
4
|
+
|
|
5
|
+
import { TiptapX } from "../../../icons";
|
|
6
|
+
import { useTiptapTranslations } from "../../context";
|
|
7
|
+
import { useMemo } from "react";
|
|
8
|
+
|
|
9
|
+
interface DialogErrorProps {
|
|
10
|
+
error: unknown;
|
|
11
|
+
onClose?: () => void;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const DialogError = ({ error, onClose, className }: DialogErrorProps) => {
|
|
16
|
+
const translations = useTiptapTranslations();
|
|
17
|
+
|
|
18
|
+
const renderedMessage = useMemo(() => {
|
|
19
|
+
if (typeof error === "string") {
|
|
20
|
+
return error || translations.common.unknownError;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (isCombinedError(error)) {
|
|
24
|
+
const safeErrors = error.cause.filter((e) => Boolean(e.message));
|
|
25
|
+
const errorsToDisplay =
|
|
26
|
+
safeErrors.length === error.cause.length
|
|
27
|
+
? safeErrors
|
|
28
|
+
: [new Error(translations.common.unknownError), ...safeErrors];
|
|
29
|
+
|
|
30
|
+
if (errorsToDisplay.length === 1) {
|
|
31
|
+
return errorsToDisplay[0].message;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<ul className="dialog-error-list">
|
|
36
|
+
{errorsToDisplay.map((cause, index) => (
|
|
37
|
+
<li key={`${index}_${cause.message}`}>{cause.message}</li>
|
|
38
|
+
))}
|
|
39
|
+
</ul>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (error instanceof Error) {
|
|
44
|
+
return error.message || translations.common.unknownError;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return translations.common.unknownError;
|
|
48
|
+
}, [error, translations]);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className={`dialog-error ${className || ""}`}>
|
|
52
|
+
{renderedMessage}
|
|
53
|
+
{onClose && (
|
|
54
|
+
<button
|
|
55
|
+
type="button"
|
|
56
|
+
className="dialog-error-clear-button"
|
|
57
|
+
onClick={onClose}
|
|
58
|
+
aria-label={translations.common.clearError}
|
|
59
|
+
>
|
|
60
|
+
<TiptapX />
|
|
61
|
+
</button>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DialogError } from './dialog-error';
|
|
@@ -48,15 +48,6 @@
|
|
|
48
48
|
color: var(--tiptap-color-text-placeholder);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
.link-dialog-error {
|
|
52
|
-
padding: 8px 12px;
|
|
53
|
-
border: 1px solid var(--ui-error-border);
|
|
54
|
-
border-radius: 4px;
|
|
55
|
-
background-color: var(--ui-error-bg);
|
|
56
|
-
color: var(--ui-error-text);
|
|
57
|
-
font-size: 13px;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
51
|
.link-dialog-actions {
|
|
61
52
|
display: flex;
|
|
62
53
|
justify-content: flex-end;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
|
4
4
|
|
|
5
|
-
import { CommonModal } from "../../components";
|
|
5
|
+
import { CommonModal, DialogError } from "../../components";
|
|
6
6
|
import { useTiptapTranslations } from "../../context";
|
|
7
7
|
import { LinkDialogContextProps } from "@/types/link";
|
|
8
8
|
|
|
@@ -186,7 +186,7 @@ export const AddLinkDialog = ({
|
|
|
186
186
|
<p className="link-dialog-help-text">{translations.link.addNofollowHelp}</p>
|
|
187
187
|
</div>
|
|
188
188
|
|
|
189
|
-
{error && <
|
|
189
|
+
{error && <DialogError error={error} />}
|
|
190
190
|
</div>
|
|
191
191
|
|
|
192
192
|
<div className="link-dialog-actions">
|
|
@@ -83,15 +83,6 @@
|
|
|
83
83
|
margin: 4px 0;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
.video-dialog-error {
|
|
87
|
-
padding: 8px 12px;
|
|
88
|
-
border: 1px solid var(--ui-error-border);
|
|
89
|
-
border-radius: 4px;
|
|
90
|
-
background-color: var(--ui-error-bg);
|
|
91
|
-
color: var(--ui-error-text);
|
|
92
|
-
font-size: 13px;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
86
|
.video-dialog-actions {
|
|
96
87
|
display: flex;
|
|
97
88
|
justify-content: flex-end;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
|
4
4
|
|
|
5
|
-
import { CommonModal } from "../../components";
|
|
5
|
+
import { CommonModal, DialogError } from "../../components";
|
|
6
6
|
import { detectVideoHosting, VideoHosting } from "../../../utils/detect-video-hosting";
|
|
7
7
|
import { useTiptapTranslations } from "../../context";
|
|
8
8
|
|
|
@@ -128,7 +128,7 @@ export const AddVideoDialog = ({ open, onClose, onVideoAdd }: AddVideoDialogProp
|
|
|
128
128
|
</ul>
|
|
129
129
|
</div>
|
|
130
130
|
|
|
131
|
-
{error && <
|
|
131
|
+
{error && <DialogError error={error} />}
|
|
132
132
|
</div>
|
|
133
133
|
|
|
134
134
|
<div className="video-dialog-actions">
|
|
@@ -101,34 +101,6 @@
|
|
|
101
101
|
color: var(--ui-text-primary);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
.image-dialog-error {
|
|
105
|
-
position: relative;
|
|
104
|
+
.image-dialog-error-spacing {
|
|
106
105
|
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
106
|
}
|
|
@@ -4,7 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
|
|
|
4
4
|
|
|
5
5
|
import { TiptapX } from "../../../icons";
|
|
6
6
|
|
|
7
|
-
import { Button, CommonModal, Input } from "../../components";
|
|
7
|
+
import { Button, CommonModal, DialogError, Input } from "../../components";
|
|
8
8
|
import { ImageUploadHandler, TiptapImageAttrs, ImageGetHandler, FigureAttrs } from "../../../types";
|
|
9
9
|
import { resolveImageSrc } from "../../../utils/image-src-resolver";
|
|
10
10
|
import { useTiptapTranslations } from "../../context";
|
|
@@ -219,7 +219,7 @@ export const ImageDialog = ({
|
|
|
219
219
|
|
|
220
220
|
handleClose();
|
|
221
221
|
} catch (error) {
|
|
222
|
-
setFileUploadError(error instanceof Error ? error : new Error(translations.
|
|
222
|
+
setFileUploadError(error instanceof Error ? error : new Error(translations.common.unknownError));
|
|
223
223
|
} finally {
|
|
224
224
|
setIsUploading(false);
|
|
225
225
|
}
|
|
@@ -334,17 +334,11 @@ export const ImageDialog = ({
|
|
|
334
334
|
</div>
|
|
335
335
|
</div>
|
|
336
336
|
{fileUploadError && (
|
|
337
|
-
<
|
|
338
|
-
{fileUploadError
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
onClick={() => setFileUploadError(null)}
|
|
343
|
-
aria-label={translations.imageDialog.clearError}
|
|
344
|
-
>
|
|
345
|
-
<TiptapX />
|
|
346
|
-
</button>
|
|
347
|
-
</div>
|
|
337
|
+
<DialogError
|
|
338
|
+
error={fileUploadError}
|
|
339
|
+
onClose={() => setFileUploadError(null)}
|
|
340
|
+
className="image-dialog-error-spacing"
|
|
341
|
+
/>
|
|
348
342
|
)}
|
|
349
343
|
<div className="image-dialog-actions">
|
|
350
344
|
<Button
|
package/src/editor/index.ts
CHANGED
|
@@ -2,3 +2,4 @@ export { Tiptap, type TiptapProps, type KatexDialogContextProps } from "./editor
|
|
|
2
2
|
export type { SupportedLanguage as TiptapSupportedLanguages } from "../utils/get-translations";
|
|
3
3
|
export { type JSONContent } from "@tiptap/react";
|
|
4
4
|
export { htmlToTiptapContent } from "../utils/html-to-tiptap-content";
|
|
5
|
+
export { type CombinedErrors as TipTapCombinedErrors } from '@/types/common'
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
@import "../editor/components/button/button.css";
|
|
3
3
|
@import "../editor/components/input/input.css";
|
|
4
4
|
@import "../editor/components/common-modal/common-modal.css";
|
|
5
|
+
@import "../editor/components/dialog-error/dialog-error.css";
|
|
5
6
|
|
|
6
7
|
/* Dialog Styles */
|
|
7
8
|
@import "../editor/dialogs/add-katex-dialog/add-katex-dialog.css";
|
package/src/translations/en.json
CHANGED
|
@@ -113,9 +113,7 @@
|
|
|
113
113
|
"captionPlaceholder": "Description under image...",
|
|
114
114
|
"save": "Save",
|
|
115
115
|
"add": "Add",
|
|
116
|
-
"invalidFileType": "
|
|
117
|
-
"unknownError": "Unknown error",
|
|
118
|
-
"clearError": "Clear error"
|
|
116
|
+
"invalidFileType": "Invalid file format."
|
|
119
117
|
},
|
|
120
118
|
"videoUpload": {
|
|
121
119
|
"title": "Add video",
|
|
@@ -160,6 +158,8 @@
|
|
|
160
158
|
"words": ["word", "words", "words"]
|
|
161
159
|
},
|
|
162
160
|
"common": {
|
|
163
|
-
"cancel": "Cancel"
|
|
161
|
+
"cancel": "Cancel",
|
|
162
|
+
"unknownError": "Unknown error",
|
|
163
|
+
"clearError": "Clear error"
|
|
164
164
|
}
|
|
165
165
|
}
|
package/src/translations/ru.json
CHANGED
|
@@ -113,9 +113,7 @@
|
|
|
113
113
|
"captionPlaceholder": "Описание под изображением...",
|
|
114
114
|
"save": "Сохранить",
|
|
115
115
|
"add": "Добавить",
|
|
116
|
-
"invalidFileType": "
|
|
117
|
-
"unknownError": "Неизвестная ошибка",
|
|
118
|
-
"clearError": "Сбросить ошибку"
|
|
116
|
+
"invalidFileType": "Неверный формат файла."
|
|
119
117
|
},
|
|
120
118
|
"videoUpload": {
|
|
121
119
|
"title": "Добавить видео",
|
|
@@ -160,6 +158,8 @@
|
|
|
160
158
|
"words": ["слово", "слова", "слов"]
|
|
161
159
|
},
|
|
162
160
|
"common": {
|
|
163
|
-
"cancel": "Отменить"
|
|
161
|
+
"cancel": "Отменить",
|
|
162
|
+
"unknownError": "Неизвестная ошибка",
|
|
163
|
+
"clearError": "Сбросить ошибку"
|
|
164
164
|
}
|
|
165
165
|
}
|
package/src/types/index.ts
CHANGED
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CombinedErrors } from "@/types";
|
|
2
|
+
|
|
3
|
+
export function isCombinedError(error: unknown): error is CombinedErrors {
|
|
4
|
+
return (
|
|
5
|
+
error instanceof Error &&
|
|
6
|
+
Array.isArray(error?.cause) &&
|
|
7
|
+
error.cause.length > 0 && error.cause.every((e) => e instanceof Error)
|
|
8
|
+
);
|
|
9
|
+
}
|