@festo-ui/react-extra 9.0.0-dev.691 → 9.0.0-dev.693

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.
@@ -1,28 +0,0 @@
1
- import './TextEditor.scss';
2
- export interface TextEditorConfiguration {
3
- toolbar?: {
4
- bold?: boolean;
5
- italic?: boolean;
6
- underline?: boolean;
7
- alignCenter?: boolean;
8
- alignRight?: boolean;
9
- bulletList?: boolean;
10
- orderedList?: boolean;
11
- image?: boolean;
12
- link?: boolean;
13
- };
14
- }
15
- export interface TextEditorProps {
16
- readonly disabled?: boolean;
17
- readonly label: string;
18
- readonly maxLength?: number;
19
- readonly value?: string;
20
- readonly defaultValue?: string;
21
- readonly hint?: string;
22
- readonly error?: string;
23
- readonly readOnly?: boolean;
24
- readonly onChange?: (value: string | null) => void;
25
- readonly className?: string;
26
- readonly config?: TextEditorConfiguration;
27
- }
28
- export declare function TextEditor({ disabled, defaultValue, label, maxLength, value, hint, error, readOnly, onChange, className, config: configProps, }: TextEditorProps): import("react/jsx-runtime").JSX.Element;
@@ -1,279 +0,0 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import classnames from "classnames";
3
- import { useCallback, useEffect, useRef, useState } from "react";
4
- import "./TextEditor.css";
5
- import { IconAlignCenter, IconAlignRight, IconEnumeration, IconImage, IconLink, IconListView } from "@festo-ui/react-icons";
6
- import { filterXSS, whiteList as external_xss_whiteList } from "xss";
7
- import useId from "../../utils/useId.js";
8
- import { TextEditorButton } from "./TextEditorButton.js";
9
- const defaultConfig = {
10
- toolbar: {
11
- bold: true,
12
- italic: true,
13
- underline: true,
14
- alignCenter: false,
15
- alignRight: false,
16
- bulletList: true,
17
- orderedList: true,
18
- image: true,
19
- link: true
20
- }
21
- };
22
- function postpone(fn) {
23
- Promise.resolve().then(fn);
24
- }
25
- function TextEditor({ disabled = false, defaultValue, label, maxLength, value, hint, error, readOnly = false, onChange, className, config: configProps }) {
26
- const editorRef = useRef(null);
27
- const [editor, setEditor] = useState(null);
28
- const id = useId();
29
- const [innerValue, setInnerValue] = useState(null);
30
- const config = {
31
- toolbar: {
32
- ...defaultConfig.toolbar,
33
- ...configProps?.toolbar
34
- }
35
- };
36
- const setEditorContents = useCallback((e, v)=>{
37
- if (e) {
38
- const whiteList = {
39
- ...external_xss_whiteList,
40
- p: [
41
- ...external_xss_whiteList?.p ?? [],
42
- 'class'
43
- ],
44
- li: [
45
- ...external_xss_whiteList?.li ?? [],
46
- 'class'
47
- ],
48
- a: [
49
- ...external_xss_whiteList?.a ?? [],
50
- 'rel',
51
- 'class'
52
- ]
53
- };
54
- const sanitizedValue = filterXSS(v, {
55
- whiteList
56
- });
57
- const content = e.clipboard.convert({
58
- html: sanitizedValue
59
- });
60
- const selection = e.getSelection();
61
- e.setContents(content, 'silent');
62
- setInnerValue(sanitizedValue);
63
- postpone(()=>e.setSelection(selection));
64
- }
65
- }, []);
66
- useEffect(()=>{
67
- const initializeQuill = async ()=>{
68
- let Quill;
69
- if ('undefined' != typeof globalThis) {
70
- const QuillModule = await import("quill");
71
- Quill = QuillModule.default;
72
- }
73
- if (editorRef.current && Quill && null === editor) {
74
- const newEditor = new Quill(editorRef.current, {
75
- modules: {
76
- toolbar: `#editor-toolbar-${CSS.escape(id ?? '')}`
77
- },
78
- theme: 'snow'
79
- });
80
- newEditor.root.setAttribute('role', 'textbox');
81
- newEditor.root.setAttribute('aria-labelledby', `editor-label-${id}`);
82
- newEditor.root.setAttribute('aria-multiline', 'true');
83
- newEditor.enable(!readOnly);
84
- if (disabled) newEditor.disable();
85
- else if (!readOnly) newEditor.enable();
86
- setEditor(newEditor);
87
- if (defaultValue) setEditorContents(newEditor, defaultValue);
88
- }
89
- };
90
- initializeQuill();
91
- }, [
92
- editor,
93
- disabled,
94
- readOnly,
95
- id,
96
- setEditorContents,
97
- defaultValue
98
- ]);
99
- useEffect(()=>{
100
- if (editor) editor.on('text-change', ()=>{
101
- let html = editor.getSemanticHTML();
102
- if ('<p><br></p>' === html || '<div><br></div>' === html || void 0 === html) html = null;
103
- if (null !== html) {
104
- const relativeLinkRegex = /href="(?!https?:\/\/|mailto:|tel:)([^"]+)"/g;
105
- html = html.replace(relativeLinkRegex, 'href="https://$1"');
106
- }
107
- if (onChange) onChange(html);
108
- setInnerValue(html);
109
- });
110
- }, [
111
- editor,
112
- onChange
113
- ]);
114
- useEffect(()=>{
115
- if (value !== innerValue && null != value) setEditorContents(editor, value);
116
- }, [
117
- editor,
118
- innerValue,
119
- setEditorContents,
120
- value
121
- ]);
122
- function currentLength() {
123
- return innerValue?.length || 0;
124
- }
125
- function hideDivider(name) {
126
- const linkOrImage = config.toolbar?.image || config.toolbar?.link;
127
- const lists = config.toolbar?.bulletList || config.toolbar?.orderedList;
128
- const typos = config.toolbar?.bold || config.toolbar?.italic || config.toolbar?.underline;
129
- const textAlign = config.toolbar?.alignCenter || config.toolbar?.alignRight;
130
- switch(name){
131
- case 'typo':
132
- return !typos || !textAlign && !linkOrImage && !lists;
133
- case 'text-align':
134
- return !textAlign || !linkOrImage && !lists;
135
- case 'lists':
136
- return !lists || !linkOrImage;
137
- case 'image':
138
- return !config.toolbar?.image || !config.toolbar.link;
139
- default:
140
- break;
141
- }
142
- return true;
143
- }
144
- return /*#__PURE__*/ jsxs("label", {
145
- className: classnames('fwe-input-text', {
146
- disabled
147
- }),
148
- htmlFor: `editor-label-${id}`,
149
- children: [
150
- /*#__PURE__*/ jsx("div", {
151
- className: classnames('fwe-editor-toolbar', {
152
- [`fwe-editor-toolbar-${className}`]: className
153
- }),
154
- id: `editor-toolbar-${id}`,
155
- children: /*#__PURE__*/ jsxs("span", {
156
- className: "ql-formats fwe-mr-3",
157
- children: [
158
- config?.toolbar?.bold && /*#__PURE__*/ jsx(TextEditorButton, {
159
- disabled: disabled,
160
- type: "bold",
161
- className: "fwe-mr-3",
162
- label: "B"
163
- }),
164
- config?.toolbar?.italic && /*#__PURE__*/ jsx(TextEditorButton, {
165
- disabled: disabled,
166
- type: "italic",
167
- className: "fwe-mr-3",
168
- label: "I"
169
- }),
170
- config?.toolbar?.underline && /*#__PURE__*/ jsx(TextEditorButton, {
171
- disabled: disabled,
172
- type: "underline",
173
- label: "U"
174
- }),
175
- !hideDivider('typo') && /*#__PURE__*/ jsx("div", {
176
- className: "fwe-divider-y fwe-d-inline-flex fwe-mx-4"
177
- }),
178
- config?.toolbar?.alignCenter && /*#__PURE__*/ jsx(TextEditorButton, {
179
- disabled: disabled,
180
- category: "align",
181
- type: "align-center",
182
- icon: /*#__PURE__*/ jsx(IconAlignCenter, {
183
- className: classnames({
184
- 'fwe-gray': disabled
185
- })
186
- }),
187
- value: "center",
188
- className: classnames({
189
- 'fwe-mr-3': config?.toolbar?.alignRight
190
- })
191
- }),
192
- config?.toolbar?.alignRight && /*#__PURE__*/ jsx(TextEditorButton, {
193
- disabled: disabled,
194
- category: "align",
195
- type: "align-right",
196
- icon: /*#__PURE__*/ jsx(IconAlignRight, {
197
- className: classnames({
198
- 'fwe-gray': disabled
199
- })
200
- }),
201
- value: "right"
202
- }),
203
- !hideDivider('text-align') && /*#__PURE__*/ jsx("div", {
204
- className: "fwe-divider-y fwe-d-inline-flex fwe-mx-4"
205
- }),
206
- config?.toolbar?.bulletList && /*#__PURE__*/ jsx(TextEditorButton, {
207
- disabled: disabled,
208
- className: "fwe-mr-3",
209
- type: "ul",
210
- list: true,
211
- icon: /*#__PURE__*/ jsx(IconListView, {}),
212
- value: "bullet"
213
- }),
214
- config?.toolbar?.orderedList && /*#__PURE__*/ jsx(TextEditorButton, {
215
- disabled: disabled,
216
- type: "ol",
217
- list: true,
218
- icon: /*#__PURE__*/ jsx(IconEnumeration, {}),
219
- value: "ordered"
220
- }),
221
- config?.toolbar?.image && /*#__PURE__*/ jsxs(Fragment, {
222
- children: [
223
- /*#__PURE__*/ jsx("div", {
224
- className: "fwe-divider-y fwe-d-inline-flex fwe-mx-4"
225
- }),
226
- /*#__PURE__*/ jsx(TextEditorButton, {
227
- disabled: disabled,
228
- type: "image",
229
- icon: /*#__PURE__*/ jsx(IconImage, {}),
230
- noAction: true
231
- })
232
- ]
233
- }),
234
- config?.toolbar?.link && /*#__PURE__*/ jsxs(Fragment, {
235
- children: [
236
- /*#__PURE__*/ jsx("div", {
237
- className: "fwe-divider-y fwe-d-inline-flex fwe-mx-4"
238
- }),
239
- /*#__PURE__*/ jsx(TextEditorButton, {
240
- disabled: disabled,
241
- type: "link",
242
- icon: /*#__PURE__*/ jsx(IconLink, {}),
243
- noAction: true
244
- })
245
- ]
246
- })
247
- ]
248
- })
249
- }),
250
- /*#__PURE__*/ jsx("div", {
251
- className: classnames('fwe-editor-container', {
252
- 'fwe-editor-container--error': error
253
- }),
254
- id: `editor-container-${id}`,
255
- children: /*#__PURE__*/ jsx("div", {
256
- className: "fwe-editor",
257
- ref: editorRef
258
- })
259
- }),
260
- /*#__PURE__*/ jsx("span", {
261
- className: "fwe-input-text-label",
262
- children: label
263
- }),
264
- error && /*#__PURE__*/ jsx("span", {
265
- className: "fwe-text-editor-invalid",
266
- children: error
267
- }),
268
- hint && /*#__PURE__*/ jsx("span", {
269
- className: "fwe-text-editor-info",
270
- children: hint
271
- }),
272
- maxLength && maxLength > 0 && null != value && /*#__PURE__*/ jsx("span", {
273
- className: "fwe-input-text-count",
274
- children: `${currentLength()} / ${maxLength}`
275
- })
276
- ]
277
- });
278
- }
279
- export { TextEditor };
@@ -1,14 +0,0 @@
1
- import { type ReactElement } from 'react';
2
- export interface TextEditorButtonProps {
3
- type: string;
4
- label?: string;
5
- icon?: ReactElement;
6
- disabled: boolean;
7
- className?: string;
8
- list?: boolean;
9
- value?: string;
10
- noAction?: boolean;
11
- category?: string;
12
- }
13
- export declare function TextEditorButton({ disabled, label, type, className, icon, list, value, noAction, category, }: Readonly<TextEditorButtonProps>): import("react/jsx-runtime").JSX.Element;
14
- export default TextEditorButton;
@@ -1,73 +0,0 @@
1
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import classnames from "classnames";
3
- import { useEffect, useRef, useState } from "react";
4
- function TextEditorButton({ disabled, label, type, className, icon, list, value, noAction, category }) {
5
- const [active, setActive] = useState(false);
6
- const btnRef = useRef(null);
7
- function handleClick() {
8
- const btn = btnRef.current;
9
- setActive((prevActive)=>!prevActive);
10
- btn?.click();
11
- }
12
- useEffect(()=>{
13
- function callback(mutationRecords) {
14
- for (const mutationRecord of mutationRecords){
15
- const { classList } = mutationRecord.target;
16
- const { oldValue } = mutationRecord;
17
- if (classList.contains('ql-active')) setActive(true);
18
- if (!classList.contains('ql-active') && oldValue?.includes('ql-active')) setActive(false);
19
- }
20
- }
21
- if (btnRef.current && !noAction) {
22
- const observer = new MutationObserver(callback);
23
- observer.observe(btnRef.current, {
24
- attributes: true,
25
- attributeFilter: [
26
- 'class'
27
- ],
28
- attributeOldValue: true
29
- });
30
- }
31
- }, [
32
- noAction
33
- ]);
34
- return /*#__PURE__*/ jsxs(Fragment, {
35
- children: [
36
- /*#__PURE__*/ jsx("button", {
37
- ref: btnRef,
38
- type: "button",
39
- className: classnames('fwe-d-none', {
40
- 'ql-list': list
41
- }, {
42
- [`ql-${category || type}`]: !list
43
- }, {
44
- [`action-${type}`]: !noAction
45
- }),
46
- "aria-hidden": "true",
47
- tabIndex: -1,
48
- value: value
49
- }),
50
- /*#__PURE__*/ jsxs("button", {
51
- type: "button",
52
- className: classnames({
53
- 'fr-icon-button': !!icon
54
- }, 'fr-button', className, {
55
- 'fwe-active': active && !noAction
56
- }),
57
- onClick: ()=>handleClick(),
58
- disabled: disabled,
59
- children: [
60
- label && /*#__PURE__*/ jsx("div", {
61
- className: `fr-button-text fwe-text-${type}`,
62
- children: label
63
- }),
64
- /*#__PURE__*/ jsx("div", {
65
- children: icon
66
- })
67
- ]
68
- })
69
- ]
70
- });
71
- }
72
- const text_editor_TextEditorButton = TextEditorButton;
73
- export { TextEditorButton, text_editor_TextEditorButton as default };
package/dist/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export { ColorIndicator, type ColorIndicatorProps, } from './forms/color-indicator/ColorIndicator';
2
- export { ColorPicker, type ColorPickerProps, } from './forms/color-picker/ColorPicker';
3
- export { DatePicker, type DatePickerOptions, type DatePickerProps, } from './forms/date-picker/DatePicker';
4
- export { DateRangePicker, type DateRangePickerOptions, type DateRangePickerProps, } from './forms/date-range-picker/DateRangePicker';
5
- export { TextEditor, type TextEditorConfiguration, type TextEditorProps, } from './forms/text-editor/TextEditor';
package/dist/index.js DELETED
@@ -1,6 +0,0 @@
1
- import { ColorIndicator } from "./forms/color-indicator/ColorIndicator.js";
2
- import { ColorPicker } from "./forms/color-picker/ColorPicker.js";
3
- import { DatePicker } from "./forms/date-picker/DatePicker.js";
4
- import { DateRangePicker } from "./forms/date-range-picker/DateRangePicker.js";
5
- import { TextEditor } from "./forms/text-editor/TextEditor.js";
6
- export { ColorIndicator, ColorPicker, DatePicker, DateRangePicker, TextEditor };
@@ -1 +0,0 @@
1
- export default function useId(idInput?: string): string | undefined;
@@ -1,20 +0,0 @@
1
- import react from "react";
2
- const maybeReactUseId = react["useId"];
3
- let nextId = 0;
4
- function useLegacyId() {
5
- const [id, setId] = react.useState(void 0);
6
- react.useEffect(()=>{
7
- if (null == id) {
8
- nextId += 1;
9
- setId(`fr-${nextId}`);
10
- }
11
- }, [
12
- id
13
- ]);
14
- return id;
15
- }
16
- function useId(idInput) {
17
- if (null != idInput) return idInput;
18
- return maybeReactUseId ? maybeReactUseId() : useLegacyId();
19
- }
20
- export { useId as default };