@rh-support/components 2.5.214 → 2.5.222

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.
Files changed (46) hide show
  1. package/lib/esm/ConfirmationModal/ConfirmationDialog.js +1 -1
  2. package/lib/esm/Functional/CaseContactsSelectorExternal.d.ts +0 -2
  3. package/lib/esm/Functional/CaseContactsSelectorExternal.d.ts.map +1 -1
  4. package/lib/esm/Functional/CaseContactsSelectorExternal.js +82 -156
  5. package/lib/esm/MarkdownEditor/MarkdownEditor.d.ts +49 -0
  6. package/lib/esm/MarkdownEditor/MarkdownEditor.d.ts.map +1 -0
  7. package/lib/esm/MarkdownEditor/MarkdownEditor.js +601 -0
  8. package/lib/esm/MarkdownEditor/index.d.ts +2 -0
  9. package/lib/esm/MarkdownEditor/index.d.ts.map +1 -0
  10. package/lib/esm/MarkdownEditor/index.js +1 -0
  11. package/lib/esm/MarkdownEditor/markdownEditor.css +223 -0
  12. package/lib/esm/OwnerTypeaheadDropdown/OwnerTypeaheadDropdown.d.ts +0 -2
  13. package/lib/esm/OwnerTypeaheadDropdown/OwnerTypeaheadDropdown.d.ts.map +1 -1
  14. package/lib/esm/OwnerTypeaheadDropdown/OwnerTypeaheadDropdown.js +3 -8
  15. package/lib/esm/PhoneInput/PhoneInput.d.ts.map +1 -1
  16. package/lib/esm/PhoneInput/PhoneInput.js +1 -38
  17. package/lib/esm/Table/TablePagination.d.ts +0 -1
  18. package/lib/esm/Table/TablePagination.d.ts.map +1 -1
  19. package/lib/esm/Table/TablePagination.js +1 -1
  20. package/lib/esm/helperFunctions/errorMessage.d.ts +1 -2
  21. package/lib/esm/helperFunctions/errorMessage.d.ts.map +1 -1
  22. package/lib/esm/helperFunctions/errorMessage.js +5 -19
  23. package/lib/esm/hooks/useCopyToClipboard.d.ts +1 -1
  24. package/lib/esm/hooks/useCopyToClipboard.d.ts.map +1 -1
  25. package/lib/esm/hooks/useCopyToClipboard.js +1 -3
  26. package/lib/esm/index.d.ts +1 -2
  27. package/lib/esm/index.d.ts.map +1 -1
  28. package/lib/esm/index.js +1 -3
  29. package/package.json +7 -9
  30. package/lib/esm/CustomDatePicker/CustomDatePicker.d.ts +0 -18
  31. package/lib/esm/CustomDatePicker/CustomDatePicker.d.ts.map +0 -1
  32. package/lib/esm/CustomDatePicker/CustomDatePicker.js +0 -27
  33. package/lib/esm/CustomDatePicker/customDatePicker.css +0 -52
  34. package/lib/esm/CustomDatePicker/index.d.ts +0 -2
  35. package/lib/esm/CustomDatePicker/index.d.ts.map +0 -1
  36. package/lib/esm/CustomDatePicker/index.js +0 -1
  37. package/lib/esm/RichTextEditor/RichTextEditor.d.ts +0 -45
  38. package/lib/esm/RichTextEditor/RichTextEditor.d.ts.map +0 -1
  39. package/lib/esm/RichTextEditor/RichTextEditor.js +0 -463
  40. package/lib/esm/RichTextEditor/index.d.ts +0 -4
  41. package/lib/esm/RichTextEditor/index.d.ts.map +0 -1
  42. package/lib/esm/RichTextEditor/index.js +0 -2
  43. package/lib/esm/RichTextEditor/richTextEditor.css +0 -148
  44. package/lib/esm/RichTextEditor/useQuillEditor.d.ts +0 -20
  45. package/lib/esm/RichTextEditor/useQuillEditor.d.ts.map +0 -1
  46. package/lib/esm/RichTextEditor/useQuillEditor.js +0 -81
@@ -1,52 +0,0 @@
1
- .custom-date-picker--input-only {
2
- display: block;
3
- width: 100%;
4
- --pf-v6-c-date-picker__input--c-form-control--Width: 100%;
5
- }
6
-
7
- .custom-date-picker--has-error .pf-v6-c-form-control {
8
- --pf-v6-c-form-control--BorderColor: var(--pf-t--global--border--color--status--danger--default);
9
- }
10
-
11
- .custom-date-picker--external-validation .pf-v6-c-date-picker__helper-text {
12
- display: none;
13
- }
14
-
15
- .custom-date-picker--input-only .pf-v6-c-input-group {
16
- display: block;
17
- }
18
-
19
- .custom-date-picker--input-only .pf-v6-c-input-group__item:first-child {
20
- width: 100%;
21
- }
22
-
23
- .custom-date-picker--input-only .pf-v6-c-input-group__item:last-child {
24
- display: none;
25
- }
26
-
27
- .pf-v6-c-popover.custom-date-picker-popover {
28
- --pf-v6-c-popover--MaxWidth: 18.5rem;
29
- max-width: 18.5rem;
30
- width: 18.5rem;
31
- }
32
-
33
- .pf-v6-c-popover.custom-date-picker-popover .pf-v6-c-calendar-month {
34
- --pf-v6-c-calendar-month--PaddingBlockStart: var(--pf-t--global--spacer--sm);
35
- --pf-v6-c-calendar-month--PaddingInlineEnd: var(--pf-t--global--spacer--sm);
36
- --pf-v6-c-calendar-month--PaddingBlockEnd: var(--pf-t--global--spacer--sm);
37
- --pf-v6-c-calendar-month--PaddingInlineStart: var(--pf-t--global--spacer--sm);
38
- --pf-v6-c-calendar-month__header--MarginBlockEnd: var(--pf-t--global--spacer--sm);
39
- --pf-v6-c-calendar-month__date--Width: 2.25rem;
40
- --pf-v6-c-calendar-month__date--Height: 2.25rem;
41
- --pf-v6-c-calendar-month__day--PaddingBlockEnd: var(--pf-t--global--spacer--xs);
42
- width: 100%;
43
- }
44
-
45
- .pf-v6-c-popover.custom-date-picker-popover .pf-v6-c-calendar-month__header-month .pf-v6-c-menu-toggle {
46
- width: 100% !important;
47
- max-width: 6.5rem;
48
- }
49
-
50
- .pf-v6-c-popover.custom-date-picker-popover .pf-v6-c-calendar-month__calendar {
51
- width: 100%;
52
- }
@@ -1,2 +0,0 @@
1
- export * from './CustomDatePicker';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/CustomDatePicker/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
@@ -1 +0,0 @@
1
- export * from './CustomDatePicker';
@@ -1,45 +0,0 @@
1
- import './richTextEditor.css';
2
- import Quill from 'quill';
3
- import React from 'react';
4
- export interface IRichTextEditorProps {
5
- /** HTML string value */
6
- value: string;
7
- /** Called with HTML string on change */
8
- onChange: (html: string) => void;
9
- /** Emit plain text for char counting or previews */
10
- onChangePlainText?: (text: string) => void;
11
- /** Placeholder text when editor is empty */
12
- placeholder?: string;
13
- /** Disable the editor */
14
- disabled?: boolean;
15
- /** CSS class for the outer container */
16
- className?: string;
17
- /** Unique ID */
18
- id?: string;
19
- /** Hide the formatting toolbar */
20
- hideToolbar?: boolean;
21
- /** Character limit (counted against plain text) */
22
- charLimit?: number;
23
- /** Threshold to show character counter */
24
- minCharsForCounter?: number;
25
- /** Callback when character limit is exceeded */
26
- onCharLimitExceeded?: (exceeded: boolean) => void;
27
- /** Editor height */
28
- height?: string | number;
29
- /** Focus handler */
30
- onFocus?: () => void;
31
- /** Blur handler */
32
- onBlur?: () => void;
33
- /** Ref binding for programmatic access to the Quill instance */
34
- bindEditor?: (editor: Quill) => void;
35
- /** Accessible label */
36
- 'aria-label'?: string;
37
- /**
38
- * Async callback invoked when the user selects an image file (via toolbar or paste).
39
- * Must upload the file and return the image URL to embed.
40
- */
41
- onImageUpload?: (file: File) => Promise<string>;
42
- }
43
- export declare function RichTextEditor(props: Readonly<IRichTextEditorProps>): React.JSX.Element;
44
- export default RichTextEditor;
45
- //# sourceMappingURL=RichTextEditor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA+B9B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAmD,MAAM,OAAO,CAAC;AAMxE,MAAM,WAAW,oBAAoB;IACjC,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,mBAAmB;IACnB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,gEAAgE;IAChE,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,KAAK,IAAI,CAAC;IACrC,uBAAuB;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACnD;AAQD,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,qBA2uBnE;AAED,eAAe,cAAc,CAAC"}
@@ -1,463 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import './richTextEditor.css';
11
- import { Button, ButtonVariant, Dropdown, DropdownItem, DropdownList, FormGroup, MenuToggle, Modal, ModalBody, ModalFooter, ModalHeader, ModalVariant, TextInput, Toolbar, ToolbarGroup, } from '@patternfly/react-core';
12
- import AlignCenterIcon from '@patternfly/react-icons/dist/js/icons/align-center-icon';
13
- import AlignJustifyIcon from '@patternfly/react-icons/dist/js/icons/align-justify-icon';
14
- import AlignLeftIcon from '@patternfly/react-icons/dist/js/icons/align-left-icon';
15
- import AlignRightIcon from '@patternfly/react-icons/dist/js/icons/align-right-icon';
16
- import CaretDownIcon from '@patternfly/react-icons/dist/js/icons/caret-down-icon';
17
- import IndentIcon from '@patternfly/react-icons/dist/js/icons/indent-icon';
18
- import LinkIcon from '@patternfly/react-icons/dist/js/icons/link-icon';
19
- import ListOlIcon from '@patternfly/react-icons/dist/js/icons/list-ol-icon';
20
- import ListUlIcon from '@patternfly/react-icons/dist/js/icons/list-ul-icon';
21
- import OutdentIcon from '@patternfly/react-icons/dist/js/icons/outdent-icon';
22
- import RemoveFormatIcon from '@patternfly/react-icons/dist/js/icons/remove-format-icon';
23
- import StrikethroughIcon from '@patternfly/react-icons/dist/js/icons/strikethrough-icon';
24
- import React, { useCallback, useEffect, useRef, useState } from 'react';
25
- import { useTranslation } from 'react-i18next';
26
- import { ToastNotification } from '../ToastNotification';
27
- import { useQuillEditor } from './useQuillEditor';
28
- const defaultCharLimit = 32000;
29
- const defaultMinCharsForCounter = 31800;
30
- const ALLOWED_IMAGE_TYPES = new Set(['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml']);
31
- const IMAGE_SIZE_LIMIT = 2 * 1024 * 1024; // 2 MB
32
- export function RichTextEditor(props) {
33
- const { t } = useTranslation();
34
- const { value, onChange, onChangePlainText, placeholder = '', disabled = false, className = '', id = 'rich-text-editor', hideToolbar = false, charLimit = defaultCharLimit, minCharsForCounter = defaultMinCharsForCounter, onCharLimitExceeded, height, onFocus, onBlur, bindEditor, 'aria-label': ariaLabel, onImageUpload, } = props;
35
- const [isHeadingDropdownOpen, setIsHeadingDropdownOpen] = useState(false);
36
- const [charCount, setCharCount] = useState(0);
37
- const charLimitExceededRef = useRef(false);
38
- const [isLinkModalOpen, setIsLinkModalOpen] = useState(false);
39
- const [linkUrl, setLinkUrl] = useState('');
40
- const [linkText, setLinkText] = useState('');
41
- const savedSelectionRef = useRef(null);
42
- const [isImageModalOpen, setIsImageModalOpen] = useState(false);
43
- const [imageUrl, setImageUrl] = useState('');
44
- const [imageUrlError, setImageUrlError] = useState('');
45
- const savedImageSelectionRef = useRef(null);
46
- const [, setIsImageUploading] = useState(false);
47
- const fileInputRef = useRef(null);
48
- const { editorRef, quillRef, activeFormat, setActiveFormat, setContents, setReadOnly } = useQuillEditor({
49
- placeholder,
50
- readOnly: disabled,
51
- onChange: (html) => {
52
- onChange(html);
53
- },
54
- onChangePlainText: (text) => {
55
- onChangePlainText === null || onChangePlainText === void 0 ? void 0 : onChangePlainText(text);
56
- setCharCount(text.length);
57
- },
58
- onFocus,
59
- onBlur,
60
- });
61
- // Sync external value into Quill when it changes externally
62
- useEffect(() => {
63
- setContents(value);
64
- }, [value, setContents]);
65
- // Sync disabled state
66
- useEffect(() => {
67
- setReadOnly(disabled);
68
- }, [disabled, setReadOnly]);
69
- // Bind editor ref externally
70
- useEffect(() => {
71
- if (quillRef.current && bindEditor) {
72
- bindEditor(quillRef.current);
73
- }
74
- }, [bindEditor, quillRef]);
75
- // Character limit exceeded callback
76
- useEffect(() => {
77
- const exceeded = charCount > charLimit;
78
- if (exceeded !== charLimitExceededRef.current) {
79
- charLimitExceededRef.current = exceeded;
80
- onCharLimitExceeded === null || onCharLimitExceeded === void 0 ? void 0 : onCharLimitExceeded(exceeded);
81
- }
82
- }, [charCount, charLimit, onCharLimitExceeded]);
83
- const onImageUploadRef = useRef(onImageUpload);
84
- onImageUploadRef.current = onImageUpload;
85
- useEffect(() => {
86
- const editorEl = editorRef.current;
87
- if (!editorEl || !onImageUploadRef.current)
88
- return;
89
- const handlePaste = (e) => __awaiter(this, void 0, void 0, function* () {
90
- var _a;
91
- if (!((_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.items))
92
- return;
93
- const imageItem = Array.from(e.clipboardData.items).find((item) => item.type.startsWith('image/') && ALLOWED_IMAGE_TYPES.has(item.type));
94
- if (!imageItem)
95
- return;
96
- const file = imageItem.getAsFile();
97
- if (!file)
98
- return;
99
- if (file.size > IMAGE_SIZE_LIMIT) {
100
- e.preventDefault();
101
- e.stopPropagation();
102
- return;
103
- }
104
- e.preventDefault();
105
- e.stopPropagation();
106
- const quill = quillRef.current;
107
- if (!quill)
108
- return;
109
- const range = quill.getSelection() || { index: quill.getLength() - 1, length: 0 };
110
- setIsImageUploading(true);
111
- try {
112
- const url = yield onImageUploadRef.current(file);
113
- if (url) {
114
- quill.insertEmbed(range.index, 'image', url);
115
- quill.setSelection(range.index + 1, 0, 'silent');
116
- }
117
- }
118
- catch (_b) {
119
- // Error handled by the consumer's upload implementation
120
- }
121
- finally {
122
- setIsImageUploading(false);
123
- }
124
- });
125
- editorEl.addEventListener('paste', handlePaste);
126
- return () => {
127
- editorEl.removeEventListener('paste', handlePaste);
128
- };
129
- // eslint-disable-next-line react-hooks/exhaustive-deps
130
- }, [editorRef, quillRef]);
131
- const formatToggle = useCallback((format, value) => {
132
- const quill = quillRef.current;
133
- if (!quill)
134
- return;
135
- const selection = quill.getSelection();
136
- if (!selection)
137
- return;
138
- const newValue = value !== null && value !== void 0 ? value : !activeFormat[format];
139
- quill.format(format, newValue);
140
- setActiveFormat((prev) => {
141
- const next = Object.assign({}, prev);
142
- if (newValue) {
143
- next[format] = newValue;
144
- }
145
- else {
146
- delete next[format];
147
- }
148
- return next;
149
- });
150
- }, [activeFormat, quillRef, setActiveFormat]);
151
- const onLinkClick = useCallback(() => {
152
- const quill = quillRef.current;
153
- if (!quill)
154
- return;
155
- const range = quill.getSelection();
156
- if (!range)
157
- return;
158
- if (activeFormat.link) {
159
- quill.format('link', false);
160
- setActiveFormat((prev) => {
161
- const next = Object.assign({}, prev);
162
- delete next.link;
163
- return next;
164
- });
165
- }
166
- else {
167
- savedSelectionRef.current = { index: range.index, length: range.length };
168
- setLinkText(range.length > 0 ? quill.getText(range.index, range.length).trim() : '');
169
- setLinkUrl('');
170
- setIsLinkModalOpen(true);
171
- }
172
- }, [activeFormat, quillRef, setActiveFormat]);
173
- const onLinkInsert = useCallback(() => {
174
- const quill = quillRef.current;
175
- const saved = savedSelectionRef.current;
176
- const url = linkUrl.trim();
177
- const text = linkText.trim() || url;
178
- if (!quill || !saved || !url)
179
- return;
180
- if (saved.length > 0) {
181
- quill.setSelection(saved.index, saved.length, 'silent');
182
- quill.format('link', url);
183
- }
184
- else {
185
- quill.insertText(saved.index, text, 'link', url, 'user');
186
- quill.setSelection(saved.index + text.length, 0, 'silent');
187
- }
188
- setActiveFormat((prev) => (Object.assign(Object.assign({}, prev), { link: url })));
189
- savedSelectionRef.current = null;
190
- setIsLinkModalOpen(false);
191
- setLinkUrl('');
192
- setLinkText('');
193
- }, [linkUrl, linkText, quillRef, setActiveFormat]);
194
- const onLinkCancel = useCallback(() => {
195
- savedSelectionRef.current = null;
196
- setIsLinkModalOpen(false);
197
- setLinkText('');
198
- setLinkUrl('');
199
- }, []);
200
- const handleFileInputChange = useCallback((e) => __awaiter(this, void 0, void 0, function* () {
201
- var _a;
202
- const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
203
- if (fileInputRef.current)
204
- fileInputRef.current.value = '';
205
- if (!file || !onImageUpload)
206
- return;
207
- if (!ALLOWED_IMAGE_TYPES.has(file.type)) {
208
- ToastNotification.addDangerMessage(t('Invalid file type. Only JPEG, PNG, GIF, and SVG images are allowed.'));
209
- return;
210
- }
211
- if (file.size > IMAGE_SIZE_LIMIT) {
212
- ToastNotification.addDangerMessage(t('File is too large. Maximum size is 2 MB.'));
213
- return;
214
- }
215
- const quill = quillRef.current;
216
- const saved = savedImageSelectionRef.current;
217
- if (!quill || !saved)
218
- return;
219
- setIsImageUploading(true);
220
- try {
221
- const url = yield onImageUpload(file);
222
- if (url) {
223
- quill.focus();
224
- quill.setSelection(saved.index, saved.length, 'silent');
225
- quill.insertEmbed(saved.index, 'image', url);
226
- }
227
- }
228
- catch (_b) {
229
- ToastNotification.addDangerMessage(t('Failed to upload image.'));
230
- }
231
- finally {
232
- setIsImageUploading(false);
233
- savedImageSelectionRef.current = null;
234
- }
235
- }), [onImageUpload, quillRef, t]);
236
- const onImageInsert = useCallback(() => {
237
- const quill = quillRef.current;
238
- const saved = savedImageSelectionRef.current;
239
- if (!quill || !saved || !imageUrl.trim())
240
- return;
241
- const url = imageUrl.trim();
242
- try {
243
- const parsed = new URL(url);
244
- if (parsed.hostname !== 'redhat.com' && !parsed.hostname.endsWith('.redhat.com')) {
245
- setImageUrlError(t('Only *.redhat.com URLs are allowed'));
246
- return;
247
- }
248
- }
249
- catch (_a) {
250
- setImageUrlError(t('Only *.redhat.com URLs are allowed'));
251
- return;
252
- }
253
- quill.setSelection(saved.index, saved.length, 'silent');
254
- quill.insertEmbed(saved.index, 'image', url);
255
- savedImageSelectionRef.current = null;
256
- setIsImageModalOpen(false);
257
- setImageUrl('');
258
- setImageUrlError('');
259
- }, [imageUrl, quillRef, t]);
260
- const onImageCancel = useCallback(() => {
261
- savedImageSelectionRef.current = null;
262
- setIsImageModalOpen(false);
263
- setImageUrl('');
264
- setImageUrlError('');
265
- }, []);
266
- const onImageUrlChange = useCallback((_e, val) => {
267
- setImageUrl(val);
268
- if (val.trim()) {
269
- try {
270
- const parsed = new URL(val.trim());
271
- if (parsed.hostname !== 'redhat.com' && !parsed.hostname.endsWith('.redhat.com')) {
272
- setImageUrlError(t('Only *.redhat.com URLs are allowed'));
273
- }
274
- else {
275
- setImageUrlError('');
276
- }
277
- }
278
- catch (_a) {
279
- setImageUrlError(t('Only *.redhat.com URLs are allowed'));
280
- }
281
- }
282
- else {
283
- setImageUrlError('');
284
- }
285
- }, [t]);
286
- const onImageUrlKeyDown = useCallback((e) => {
287
- if (e.key === 'Enter') {
288
- e.preventDefault();
289
- onImageInsert();
290
- }
291
- }, [onImageInsert]);
292
- const onLinkTextChange = useCallback((_e, val) => {
293
- setLinkText(val);
294
- }, []);
295
- const onLinkUrlChange = useCallback((_e, val) => {
296
- setLinkUrl(val);
297
- }, []);
298
- const onLinkUrlKeyDown = useCallback((e) => {
299
- if (e.key === 'Enter') {
300
- e.preventDefault();
301
- onLinkInsert();
302
- }
303
- }, [onLinkInsert]);
304
- const onToolbarMouseDown = useCallback((e) => {
305
- e.preventDefault();
306
- }, []);
307
- const onBoldClick = useCallback(() => formatToggle('bold'), [formatToggle]);
308
- const onItalicClick = useCallback(() => formatToggle('italic'), [formatToggle]);
309
- const onUnderlineClick = useCallback(() => formatToggle('underline'), [formatToggle]);
310
- const onStrikethroughClick = useCallback(() => formatToggle('strike'), [formatToggle]);
311
- const onIndentClick = useCallback(() => {
312
- const quill = quillRef.current;
313
- if (!quill)
314
- return;
315
- const range = quill.getSelection();
316
- if (!range)
317
- return;
318
- const current = quill.getFormat(range).indent || 0;
319
- quill.format('indent', current + 1);
320
- setActiveFormat((prev) => (Object.assign(Object.assign({}, prev), { indent: current + 1 })));
321
- }, [quillRef, setActiveFormat]);
322
- const onOutdentClick = useCallback(() => {
323
- const quill = quillRef.current;
324
- if (!quill)
325
- return;
326
- const range = quill.getSelection();
327
- if (!range)
328
- return;
329
- const current = quill.getFormat(range).indent || 0;
330
- if (current > 0) {
331
- quill.format('indent', current - 1 || false);
332
- setActiveFormat((prev) => (Object.assign(Object.assign({}, prev), { indent: current - 1 || false })));
333
- }
334
- }, [quillRef, setActiveFormat]);
335
- const onAlignClick = useCallback((alignment) => {
336
- const quill = quillRef.current;
337
- if (!quill)
338
- return;
339
- const range = quill.getSelection();
340
- if (!range)
341
- return;
342
- const currentAlign = activeFormat.align || false;
343
- const newValue = currentAlign === alignment ? false : alignment;
344
- quill.format('align', newValue);
345
- setActiveFormat((prev) => {
346
- const next = Object.assign({}, prev);
347
- if (newValue) {
348
- next.align = newValue;
349
- }
350
- else {
351
- delete next.align;
352
- }
353
- return next;
354
- });
355
- }, [activeFormat.align, quillRef, setActiveFormat]);
356
- const onAlignLeftClick = useCallback(() => onAlignClick(false), [onAlignClick]);
357
- const onAlignCenterClick = useCallback(() => onAlignClick('center'), [onAlignClick]);
358
- const onAlignRightClick = useCallback(() => onAlignClick('right'), [onAlignClick]);
359
- const onAlignJustifyClick = useCallback(() => onAlignClick('justify'), [onAlignClick]);
360
- const onRemoveFormatClick = useCallback(() => {
361
- const quill = quillRef.current;
362
- if (!quill)
363
- return;
364
- const range = quill.getSelection();
365
- if (!range)
366
- return;
367
- if (range.length === 0) {
368
- const [line, offset] = quill.getLine(range.index);
369
- if (line) {
370
- quill.removeFormat(range.index - offset, line.length());
371
- }
372
- }
373
- else {
374
- quill.removeFormat(range.index, range.length);
375
- }
376
- setActiveFormat(quill.getFormat(range));
377
- }, [quillRef, setActiveFormat]);
378
- const onHeadingSelect = useCallback(() => setIsHeadingDropdownOpen(false), []);
379
- const onHeadingToggleClick = useCallback(() => setIsHeadingDropdownOpen((prev) => !prev), []);
380
- const onHeading1Click = useCallback(() => formatToggle('header', 1), [formatToggle]);
381
- const onHeading2Click = useCallback(() => formatToggle('header', 2), [formatToggle]);
382
- const onHeading3Click = useCallback(() => formatToggle('header', 3), [formatToggle]);
383
- const onHeadingNormalClick = useCallback(() => formatToggle('header', false), [formatToggle]);
384
- const onBulletListClick = useCallback(() => formatToggle('list', activeFormat.list === 'bullet' ? false : 'bullet'), [formatToggle, activeFormat.list]);
385
- const onOrderedListClick = useCallback(() => formatToggle('list', activeFormat.list === 'ordered' ? false : 'ordered'), [formatToggle, activeFormat.list]);
386
- const headingToggleRenderer = useCallback((toggleRef) => {
387
- const headingLevel = activeFormat.header;
388
- const label = headingLevel ? `Heading ${headingLevel}` : 'Normal';
389
- return (React.createElement(MenuToggle, { ref: toggleRef, onClick: onHeadingToggleClick, isDisabled: disabled, variant: "plain", "aria-label": `Text style: ${label}`, className: `richtext-toolbar-btn ${headingLevel ? 'pf-m-active' : ''}` },
390
- React.createElement("span", { className: "toggle-content" },
391
- label,
392
- " ",
393
- React.createElement(CaretDownIcon, { className: "dropdown-caret" }))));
394
- }, [activeFormat.header, disabled, onHeadingToggleClick]);
395
- const editorStyle = {};
396
- if (height) {
397
- editorStyle.height = typeof height === 'number' ? `${height}px` : height;
398
- }
399
- const showCounter = charCount >= minCharsForCounter;
400
- const isOverLimit = charCount > charLimit;
401
- return (React.createElement("div", { id: id, className: `richtext-editor-container ${className}` },
402
- !hideToolbar && (React.createElement(Toolbar, { className: "richtext-toolbar", role: "toolbar", "aria-label": "Formatting options", onMouseDown: onToolbarMouseDown },
403
- React.createElement(ToolbarGroup, { className: "richtext-toolbar-left-section" },
404
- React.createElement(Button, { variant: ButtonVariant.plain, isClicked: !!activeFormat.bold, isDisabled: disabled, onClick: onBoldClick, "aria-label": "Bold", "aria-pressed": !!activeFormat.bold, className: "richtext-toolbar-btn" },
405
- React.createElement("strong", null, "B")),
406
- React.createElement(Button, { variant: ButtonVariant.plain, isClicked: !!activeFormat.italic, isDisabled: disabled, onClick: onItalicClick, "aria-label": "Italic", "aria-pressed": !!activeFormat.italic, className: "richtext-toolbar-btn" },
407
- React.createElement("em", null, "I")),
408
- React.createElement(Button, { variant: ButtonVariant.plain, isClicked: !!activeFormat.underline, isDisabled: disabled, onClick: onUnderlineClick, "aria-label": "Underline", "aria-pressed": !!activeFormat.underline, className: "richtext-toolbar-btn" },
409
- React.createElement("u", null, "U")),
410
- React.createElement(Button, { icon: React.createElement(StrikethroughIcon, null), variant: ButtonVariant.plain, isClicked: !!activeFormat.strike, isDisabled: disabled, onClick: onStrikethroughClick, "aria-label": "Strikethrough", "aria-pressed": !!activeFormat.strike, className: "richtext-toolbar-btn" }),
411
- React.createElement("div", { className: "btn-group-separator" }),
412
- React.createElement(Dropdown, { isOpen: isHeadingDropdownOpen, onSelect: onHeadingSelect, onOpenChange: setIsHeadingDropdownOpen, toggle: headingToggleRenderer },
413
- React.createElement(DropdownList, null,
414
- React.createElement(DropdownItem, { key: "h1", onClick: onHeading1Click }, "Heading 1"),
415
- React.createElement(DropdownItem, { key: "h2", onClick: onHeading2Click }, "Heading 2"),
416
- React.createElement(DropdownItem, { key: "h3", onClick: onHeading3Click }, "Heading 3"),
417
- React.createElement(DropdownItem, { key: "normal", onClick: onHeadingNormalClick }, "Normal"))),
418
- React.createElement("div", { className: "btn-group-separator" }),
419
- React.createElement(Button, { icon: React.createElement(ListUlIcon, null), variant: ButtonVariant.plain, isClicked: activeFormat.list === 'bullet', isDisabled: disabled, onClick: onBulletListClick, "aria-label": "Bullet List", "aria-pressed": activeFormat.list === 'bullet', className: "richtext-toolbar-btn" }),
420
- React.createElement(Button, { icon: React.createElement(ListOlIcon, null), variant: ButtonVariant.plain, isClicked: activeFormat.list === 'ordered', isDisabled: disabled, onClick: onOrderedListClick, "aria-label": "Ordered List", "aria-pressed": activeFormat.list === 'ordered', className: "richtext-toolbar-btn" }),
421
- React.createElement(Button, { icon: React.createElement(IndentIcon, null), variant: ButtonVariant.plain, isDisabled: disabled, onClick: onIndentClick, "aria-label": "Indent", className: "richtext-toolbar-btn" }),
422
- React.createElement(Button, { icon: React.createElement(OutdentIcon, null), variant: ButtonVariant.plain, isDisabled: disabled, onClick: onOutdentClick, "aria-label": "Outdent", className: "richtext-toolbar-btn" }),
423
- React.createElement("div", { className: "btn-group-separator" }),
424
- React.createElement(Button, { icon: React.createElement(AlignLeftIcon, null), variant: ButtonVariant.plain, isClicked: !activeFormat.align, isDisabled: disabled, onClick: onAlignLeftClick, "aria-label": "Align Left", "aria-pressed": !activeFormat.align, className: "richtext-toolbar-btn" }),
425
- React.createElement(Button, { icon: React.createElement(AlignCenterIcon, null), variant: ButtonVariant.plain, isClicked: activeFormat.align === 'center', isDisabled: disabled, onClick: onAlignCenterClick, "aria-label": "Align Center", "aria-pressed": activeFormat.align === 'center', className: "richtext-toolbar-btn" }),
426
- React.createElement(Button, { icon: React.createElement(AlignRightIcon, null), variant: ButtonVariant.plain, isClicked: activeFormat.align === 'right', isDisabled: disabled, onClick: onAlignRightClick, "aria-label": "Align Right", "aria-pressed": activeFormat.align === 'right', className: "richtext-toolbar-btn" }),
427
- React.createElement(Button, { icon: React.createElement(AlignJustifyIcon, null), variant: ButtonVariant.plain, isClicked: activeFormat.align === 'justify', isDisabled: disabled, onClick: onAlignJustifyClick, "aria-label": "Justify", "aria-pressed": activeFormat.align === 'justify', className: "richtext-toolbar-btn" }),
428
- React.createElement("div", { className: "btn-group-separator" }),
429
- React.createElement(Button, { icon: React.createElement(LinkIcon, null), variant: ButtonVariant.plain, isClicked: !!activeFormat.link, isDisabled: disabled, onClick: onLinkClick, "aria-label": "Link", "aria-pressed": !!activeFormat.link, className: "richtext-toolbar-btn" }),
430
- React.createElement(Button, { icon: React.createElement(RemoveFormatIcon, null), variant: ButtonVariant.plain, isDisabled: disabled, onClick: onRemoveFormatClick, "aria-label": "Remove Format", className: "richtext-toolbar-btn" })))),
431
- React.createElement("div", { ref: editorRef, role: "textbox", className: "richtext-editor-content", style: editorStyle, "aria-label": ariaLabel, tabIndex: -1, onClick: () => { var _a, _b; return (_b = (_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('[contenteditable="true"]')) === null || _b === void 0 ? void 0 : _b.focus(); }, onKeyDown: (e) => {
432
- var _a, _b;
433
- if (e.key === 'Enter' || e.key === ' ') {
434
- (_b = (_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('[contenteditable="true"]')) === null || _b === void 0 ? void 0 : _b.focus();
435
- }
436
- } }),
437
- showCounter && (React.createElement("div", { className: `richtext-char-counter ${isOverLimit ? 'richtext-char-counter--exceeded' : ''}` },
438
- charCount,
439
- "/",
440
- charLimit)),
441
- React.createElement(Modal, { variant: ModalVariant.small, isOpen: isLinkModalOpen, onClose: onLinkCancel, "aria-labelledby": "insert-link-title" },
442
- React.createElement(ModalHeader, { title: "Insert link", labelId: "insert-link-title" }),
443
- React.createElement(ModalBody, null,
444
- React.createElement(FormGroup, { label: "Display text", fieldId: "link-text-input" },
445
- React.createElement(TextInput, { id: "link-text-input", value: linkText, onChange: onLinkTextChange, placeholder: "Link text (defaults to URL)" })),
446
- React.createElement(FormGroup, { label: "URL", isRequired: true, fieldId: "link-url-input" },
447
- React.createElement(TextInput, { id: "link-url-input", type: "url", value: linkUrl, onChange: onLinkUrlChange, placeholder: "https://", onKeyDown: onLinkUrlKeyDown }))),
448
- React.createElement(ModalFooter, null,
449
- React.createElement(Button, { variant: ButtonVariant.primary, onClick: onLinkInsert, isDisabled: !linkUrl.trim() }, "Insert"),
450
- React.createElement(Button, { variant: ButtonVariant.link, onClick: onLinkCancel }, "Cancel"))),
451
- React.createElement("input", { ref: fileInputRef, type: "file", accept: "image/jpeg,image/png,image/gif,image/svg+xml", style: { display: 'none' }, onChange: handleFileInputChange, tabIndex: -1 }),
452
- !onImageUpload && (React.createElement(Modal, { variant: ModalVariant.small, isOpen: isImageModalOpen, onClose: onImageCancel, "aria-labelledby": "insert-image-title" },
453
- React.createElement(ModalHeader, { title: "Insert image", labelId: "insert-image-title" }),
454
- React.createElement(ModalBody, null,
455
- React.createElement(FormGroup, { label: "Image URL", isRequired: true, fieldId: "image-url-input" },
456
- React.createElement(TextInput, { id: "image-url-input", type: "url", value: imageUrl, validated: imageUrlError ? 'error' : 'default', onChange: onImageUrlChange, placeholder: "https://example.redhat.com/image.png", onKeyDown: onImageUrlKeyDown }),
457
- imageUrlError && (React.createElement(FormGroup, null,
458
- React.createElement("span", { className: "pf-v6-u-danger-color-100 pf-v6-u-font-size-sm" }, imageUrlError))))),
459
- React.createElement(ModalFooter, null,
460
- React.createElement(Button, { variant: ButtonVariant.primary, onClick: onImageInsert, isDisabled: !imageUrl.trim() || !!imageUrlError }, "Insert"),
461
- React.createElement(Button, { variant: ButtonVariant.link, onClick: onImageCancel }, "Cancel"))))));
462
- }
463
- export default RichTextEditor;
@@ -1,4 +0,0 @@
1
- export * from './RichTextEditor';
2
- export { useQuillEditor } from './useQuillEditor';
3
- export type { UseQuillEditorOptions } from './useQuillEditor';
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/RichTextEditor/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './RichTextEditor';
2
- export { useQuillEditor } from './useQuillEditor';