@madie/madie-design-system 1.2.65 → 1.2.68
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/components/RichTextEditor/RichTextEditor.stories.js +20 -0
- package/components/RichTextEditor/index.jsx +93 -4
- package/dist/browser.js +1 -1
- package/dist/index.js +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components/_rich-text-editor.scss +6 -2
- package/styles/qppds/components/_rich-text-editor.scss +6 -2
- package/test/components/RichTextEditor.test.js +19 -2
|
@@ -63,4 +63,24 @@ export const DisabledTextEditor = () => {
|
|
|
63
63
|
/>
|
|
64
64
|
);
|
|
65
65
|
};
|
|
66
|
+
|
|
67
|
+
export const TextEditorWithError = () => {
|
|
68
|
+
const [value, setValue] = useState(
|
|
69
|
+
"<p>There is an error</p>"
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const handleChange = (selectedVal) => {
|
|
73
|
+
setValue(selectedVal);
|
|
74
|
+
};
|
|
75
|
+
return (
|
|
76
|
+
<RichTextEditor
|
|
77
|
+
label="Test Text Editor"
|
|
78
|
+
error={true}
|
|
79
|
+
helperText="This field is required"
|
|
80
|
+
required={true}
|
|
81
|
+
onChange={handleChange}
|
|
82
|
+
content={value}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
66
86
|
TextEditor.storyName = "Rich Text Editor";
|
|
@@ -11,7 +11,7 @@ import TableHeader from "@tiptap/extension-table-header";
|
|
|
11
11
|
import TableRow from "@tiptap/extension-table-row";
|
|
12
12
|
import Underline from "@tiptap/extension-underline";
|
|
13
13
|
import StarterKit from "@tiptap/starter-kit";
|
|
14
|
-
import { IconButton } from "@mui/material";
|
|
14
|
+
import { FormHelperText, IconButton } from "@mui/material";
|
|
15
15
|
import FormatBoldIcon from "@mui/icons-material/FormatBold";
|
|
16
16
|
import FormatItalicIcon from "@mui/icons-material/FormatItalic";
|
|
17
17
|
import FormatUnderlinedIcon from "@mui/icons-material/FormatUnderlined";
|
|
@@ -22,13 +22,19 @@ import TableChartIcon from "@mui/icons-material/TableChart";
|
|
|
22
22
|
import { Tooltip } from "@mui/material";
|
|
23
23
|
import { kebabCase } from "lodash";
|
|
24
24
|
import DOMPurify from "dompurify";
|
|
25
|
+
import { Strike } from "@tiptap/extension-strike";
|
|
25
26
|
|
|
26
27
|
const MenuBar = ({ editor, disabled }) => {
|
|
27
28
|
if (!editor) {
|
|
28
29
|
return null;
|
|
29
30
|
}
|
|
30
31
|
return (
|
|
31
|
-
<div
|
|
32
|
+
<div
|
|
33
|
+
className="control-group"
|
|
34
|
+
role="toolbar"
|
|
35
|
+
aria-label="Text formatting toolbar"
|
|
36
|
+
data-testid="rich-text-editor-toolbar"
|
|
37
|
+
>
|
|
32
38
|
<div className="button-group">
|
|
33
39
|
<Tooltip
|
|
34
40
|
data-testid="bold-tooltip"
|
|
@@ -42,8 +48,11 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
42
48
|
onClick={() =>
|
|
43
49
|
editor.chain().focus().toggleBold().run()
|
|
44
50
|
}
|
|
51
|
+
aria-label="Bold"
|
|
52
|
+
aria-pressed={editor.isActive("bold")}
|
|
45
53
|
className={editor.isActive("bold") ? "is-active" : ""}
|
|
46
54
|
disabled={disabled}
|
|
55
|
+
type="button"
|
|
47
56
|
>
|
|
48
57
|
<FormatBoldIcon />
|
|
49
58
|
</IconButton>
|
|
@@ -60,8 +69,11 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
60
69
|
onClick={() =>
|
|
61
70
|
editor.chain().focus().toggleItalic().run()
|
|
62
71
|
}
|
|
72
|
+
aria-label="Italic"
|
|
73
|
+
aria-pressed={editor.isActive("italic")}
|
|
63
74
|
className={editor.isActive("italic") ? "is-active" : ""}
|
|
64
75
|
disabled={disabled}
|
|
76
|
+
type="button"
|
|
65
77
|
>
|
|
66
78
|
<FormatItalicIcon />
|
|
67
79
|
</IconButton>
|
|
@@ -78,10 +90,13 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
78
90
|
onClick={() =>
|
|
79
91
|
editor.chain().focus().toggleUnderline().run()
|
|
80
92
|
}
|
|
93
|
+
aria-label="Underline"
|
|
94
|
+
aria-pressed={editor.isActive("underline")}
|
|
81
95
|
className={
|
|
82
96
|
editor.isActive("underline") ? "is-active" : ""
|
|
83
97
|
}
|
|
84
98
|
disabled={disabled}
|
|
99
|
+
type="button"
|
|
85
100
|
>
|
|
86
101
|
<FormatUnderlinedIcon />
|
|
87
102
|
</IconButton>
|
|
@@ -98,9 +113,12 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
98
113
|
onClick={() =>
|
|
99
114
|
editor.chain().focus().toggleStrike().run()
|
|
100
115
|
}
|
|
116
|
+
aria-label="Strikethrough"
|
|
117
|
+
aria-pressed={editor.isActive("strike")}
|
|
101
118
|
className={editor.isActive("strike") ? "is-active" : ""}
|
|
102
119
|
style={{ borderRight: "solid 1px #9c9c9c" }}
|
|
103
120
|
disabled={disabled}
|
|
121
|
+
type="button"
|
|
104
122
|
>
|
|
105
123
|
<StrikethroughSIcon />
|
|
106
124
|
</IconButton>
|
|
@@ -117,10 +135,13 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
117
135
|
onClick={() =>
|
|
118
136
|
editor.chain().focus().toggleOrderedList().run()
|
|
119
137
|
}
|
|
138
|
+
aria-label="Ordered List"
|
|
139
|
+
aria-pressed={editor.isActive("orderedList")}
|
|
120
140
|
className={
|
|
121
141
|
editor.isActive("orderedList") ? "is-active" : ""
|
|
122
142
|
}
|
|
123
143
|
disabled={disabled}
|
|
144
|
+
type="button"
|
|
124
145
|
>
|
|
125
146
|
<FormatListNumberedIcon />
|
|
126
147
|
</IconButton>
|
|
@@ -137,11 +158,14 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
137
158
|
onClick={() =>
|
|
138
159
|
editor.chain().focus().toggleBulletList().run()
|
|
139
160
|
}
|
|
161
|
+
aria-label="Bulleted List"
|
|
162
|
+
aria-pressed={editor.isActive("bulletList")}
|
|
140
163
|
className={
|
|
141
164
|
editor.isActive("bulletList") ? "is-active" : ""
|
|
142
165
|
}
|
|
143
166
|
style={{ borderRight: "solid 1px #9c9c9c" }}
|
|
144
167
|
disabled={disabled}
|
|
168
|
+
type="button"
|
|
145
169
|
>
|
|
146
170
|
<FormatListBulletedIcon />
|
|
147
171
|
</IconButton>
|
|
@@ -162,10 +186,12 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
162
186
|
withHeaderRow: true,
|
|
163
187
|
})
|
|
164
188
|
}
|
|
189
|
+
aria-label="Insert Table"
|
|
165
190
|
className={
|
|
166
191
|
editor.isActive("insertTable") ? "is-active" : ""
|
|
167
192
|
}
|
|
168
193
|
disabled={disabled}
|
|
194
|
+
type="button"
|
|
169
195
|
>
|
|
170
196
|
<TableChartIcon />
|
|
171
197
|
</IconButton>
|
|
@@ -176,11 +202,14 @@ const MenuBar = ({ editor, disabled }) => {
|
|
|
176
202
|
};
|
|
177
203
|
|
|
178
204
|
const RichTextEditor = ({
|
|
205
|
+
name,
|
|
179
206
|
id,
|
|
180
207
|
error = false,
|
|
208
|
+
helperText,
|
|
181
209
|
required = false,
|
|
182
210
|
label,
|
|
183
211
|
onChange,
|
|
212
|
+
onBlur,
|
|
184
213
|
content,
|
|
185
214
|
disabled = false,
|
|
186
215
|
readOnly = false,
|
|
@@ -200,6 +229,12 @@ const RichTextEditor = ({
|
|
|
200
229
|
TableHeader,
|
|
201
230
|
TableCell,
|
|
202
231
|
Underline,
|
|
232
|
+
Strike.extend({
|
|
233
|
+
strike: false, // disable default strike through
|
|
234
|
+
renderHTML({ HTMLAttributes }) {
|
|
235
|
+
return ["del", HTMLAttributes, 0];
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
203
238
|
],
|
|
204
239
|
shouldRerenderOnTransaction: false,
|
|
205
240
|
content,
|
|
@@ -211,12 +246,28 @@ const RichTextEditor = ({
|
|
|
211
246
|
},
|
|
212
247
|
[content, disabled]
|
|
213
248
|
);
|
|
249
|
+
|
|
250
|
+
React.useEffect(() => {
|
|
251
|
+
if (!editor || !onBlur || !name) return;
|
|
252
|
+
|
|
253
|
+
const handleBlur = () => {
|
|
254
|
+
onBlur({ target: { name } });
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
editor.on("blur", handleBlur);
|
|
258
|
+
|
|
259
|
+
return () => {
|
|
260
|
+
editor.off("blur", handleBlur);
|
|
261
|
+
};
|
|
262
|
+
}, [editor, onBlur, name]);
|
|
263
|
+
|
|
214
264
|
return (
|
|
215
265
|
<div
|
|
216
266
|
className="rich-text-editor"
|
|
217
267
|
data-testid={`${kebabCase(label)}-rich-text-editor`}
|
|
218
268
|
>
|
|
219
269
|
<InputLabel
|
|
270
|
+
id={`${id}-label`}
|
|
220
271
|
shrink
|
|
221
272
|
required={required}
|
|
222
273
|
error={error}
|
|
@@ -256,11 +307,33 @@ const RichTextEditor = ({
|
|
|
256
307
|
>
|
|
257
308
|
{label}
|
|
258
309
|
</InputLabel>
|
|
310
|
+
|
|
311
|
+
{helperText && (
|
|
312
|
+
<FormHelperText
|
|
313
|
+
tabIndex={0}
|
|
314
|
+
aria-live="polite"
|
|
315
|
+
id={`${id}-helper-text`}
|
|
316
|
+
data-testid={`${id}-helper-text`}
|
|
317
|
+
sx={[
|
|
318
|
+
{
|
|
319
|
+
margin: "4px 0px 0px 0px",
|
|
320
|
+
color: "#515151",
|
|
321
|
+
lineHeight: 1,
|
|
322
|
+
},
|
|
323
|
+
error && {
|
|
324
|
+
color: "#AE1C1C !important",
|
|
325
|
+
},
|
|
326
|
+
]}
|
|
327
|
+
>
|
|
328
|
+
{helperText}
|
|
329
|
+
</FormHelperText>
|
|
330
|
+
)}
|
|
331
|
+
|
|
259
332
|
{readOnly ? (
|
|
260
333
|
<p
|
|
261
334
|
className="rich-text-editor_read_only"
|
|
262
335
|
data-testid={`${id}-value`}
|
|
263
|
-
aria-labelledby={label}
|
|
336
|
+
aria-labelledby={`${id}-label`}
|
|
264
337
|
dangerouslySetInnerHTML={{
|
|
265
338
|
__html: content ? DOMPurify.sanitize(content) : "-",
|
|
266
339
|
}}
|
|
@@ -268,7 +341,20 @@ const RichTextEditor = ({
|
|
|
268
341
|
) : (
|
|
269
342
|
<>
|
|
270
343
|
<MenuBar editor={editor} disabled={disabled} />
|
|
271
|
-
<EditorContent
|
|
344
|
+
<EditorContent
|
|
345
|
+
id={id}
|
|
346
|
+
tabIndex={0}
|
|
347
|
+
data-testid="rich-text-editor-content"
|
|
348
|
+
editor={editor}
|
|
349
|
+
aria-labelledby={`${id}-label`}
|
|
350
|
+
aria-describedby={
|
|
351
|
+
helperText ? `${id}-helper-text` : undefined
|
|
352
|
+
}
|
|
353
|
+
aria-multiline="true"
|
|
354
|
+
aria-required={required || undefined}
|
|
355
|
+
aria-invalid={error || undefined}
|
|
356
|
+
className={`ProseMirror ${error ? "has-error" : ""}`}
|
|
357
|
+
/>
|
|
272
358
|
</>
|
|
273
359
|
)}
|
|
274
360
|
</div>
|
|
@@ -277,10 +363,13 @@ const RichTextEditor = ({
|
|
|
277
363
|
|
|
278
364
|
RichTextEditor.propTypes = {
|
|
279
365
|
id: PropTypes.string,
|
|
366
|
+
name: PropTypes.string,
|
|
280
367
|
error: PropTypes.bool,
|
|
368
|
+
helperText: PropTypes.string,
|
|
281
369
|
required: PropTypes.bool,
|
|
282
370
|
label: PropTypes.string,
|
|
283
371
|
onChange: PropTypes.func,
|
|
372
|
+
onBlur: PropTypes.func,
|
|
284
373
|
content: PropTypes.any,
|
|
285
374
|
disabled: PropTypes.bool,
|
|
286
375
|
readOnly: PropTypes.bool,
|