carbon-react 153.8.0 → 154.0.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/esm/components/text-editor/__internal__/helpers.js +1 -1
- package/esm/components/text-editor/__internal__/plugins/EditorRef/editor-ref.plugin.d.ts +5 -0
- package/esm/components/text-editor/__internal__/plugins/EditorRef/editor-ref.plugin.js +17 -0
- package/esm/components/text-editor/__internal__/plugins/EditorRef/index.d.ts +1 -0
- package/esm/components/text-editor/__internal__/plugins/EditorRef/index.js +1 -0
- package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.js +0 -1
- package/esm/components/text-editor/text-editor.component.d.ts +5 -1
- package/esm/components/text-editor/text-editor.component.js +19 -11
- package/lib/components/text-editor/__internal__/helpers.js +1 -1
- package/lib/components/text-editor/__internal__/plugins/EditorRef/editor-ref.plugin.d.ts +5 -0
- package/lib/components/text-editor/__internal__/plugins/EditorRef/editor-ref.plugin.js +24 -0
- package/lib/components/text-editor/__internal__/plugins/EditorRef/index.d.ts +1 -0
- package/lib/components/text-editor/__internal__/plugins/EditorRef/index.js +13 -0
- package/lib/components/text-editor/__internal__/plugins/EditorRef/package.json +6 -0
- package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.js +0 -1
- package/lib/components/text-editor/text-editor.component.d.ts +5 -1
- package/lib/components/text-editor/text-editor.component.js +19 -11
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ import { markdownNodes, theme } from "./constants";
|
|
|
14
14
|
const SerializeLexical = editor => {
|
|
15
15
|
let htmlString;
|
|
16
16
|
let json;
|
|
17
|
-
editor.
|
|
17
|
+
editor.read(() => {
|
|
18
18
|
// Get the current editor state
|
|
19
19
|
const editorState = editor.getEditorState();
|
|
20
20
|
// Serialize the editor state to JSON
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This plugin allows retrieval of a reference to the current editor. It's useful
|
|
3
|
+
* for testing purposes, where tests might need to directly interact with the editor to
|
|
4
|
+
* emulate e.g. blurring.
|
|
5
|
+
*/
|
|
6
|
+
import { useEffect } from "react";
|
|
7
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
8
|
+
const EditorRefPlugin = ({
|
|
9
|
+
setEditorRef
|
|
10
|
+
}) => {
|
|
11
|
+
const [editor] = useLexicalComposerContext();
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
setEditorRef(editor);
|
|
14
|
+
}, [editor, setEditorRef]);
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
export default EditorRefPlugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./editor-ref.plugin";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./editor-ref.plugin";
|
|
@@ -85,7 +85,6 @@ const Toolbar = ({
|
|
|
85
85
|
"aria-label": locale.textEditor.toolbarAriaLabel(),
|
|
86
86
|
"data-role": `${namespace}-toolbar`,
|
|
87
87
|
id: `${namespace}-toolbar`,
|
|
88
|
-
onFocus: e => e.stopPropagation(),
|
|
89
88
|
ref: toolbarRef
|
|
90
89
|
}, /*#__PURE__*/React.createElement(FormattingButtons, {
|
|
91
90
|
"data-role": `${namespace}-formatting-buttons`
|
|
@@ -23,10 +23,14 @@ export interface TextEditorProps extends MarginProps, TagProps {
|
|
|
23
23
|
labelText: string;
|
|
24
24
|
/** The identifier for the Text Editor. This allows for the using of multiple Text Editors on a screen */
|
|
25
25
|
namespace?: string;
|
|
26
|
+
/** The callback to fire when the editor loses focus */
|
|
27
|
+
onBlur?: (ev: React.FocusEvent<HTMLElement>) => void;
|
|
26
28
|
/** The callback to fire when the Cancel button within the editor is pressed */
|
|
27
29
|
onCancel?: () => void;
|
|
28
30
|
/** The callback to fire when a change is registered within the editor */
|
|
29
31
|
onChange?: (value: string, formattedValues: EditorFormattedValues) => void;
|
|
32
|
+
/** The callback to fire when the editor gains focus */
|
|
33
|
+
onFocus?: (ev: React.FocusEvent<HTMLElement>) => void;
|
|
30
34
|
/** The callback to fire when a link is added into the editor */
|
|
31
35
|
onLinkAdded?: (link: string, state: string) => void;
|
|
32
36
|
/** The callback to fire when the Save button within the editor is pressed */
|
|
@@ -46,5 +50,5 @@ export interface TextEditorProps extends MarginProps, TagProps {
|
|
|
46
50
|
/** The initial value of the editor, as a HTML string, or JSON */
|
|
47
51
|
value?: string | undefined;
|
|
48
52
|
}
|
|
49
|
-
export declare const TextEditor: ({ characterLimit, error, footer, header, inputHint, isOptional, labelText, namespace, onCancel, onChange, onLinkAdded, onSave, placeholder, previews, readOnly, required, rows, warning, value, ...rest }: TextEditorProps) => React.JSX.Element;
|
|
53
|
+
export declare const TextEditor: ({ characterLimit, error, footer, header, inputHint, isOptional, labelText, namespace, onBlur, onCancel, onChange, onFocus, onLinkAdded, onSave, placeholder, previews, readOnly, required, rows, warning, value, ...rest }: TextEditorProps) => React.JSX.Element;
|
|
50
54
|
export default TextEditor;
|
|
@@ -13,7 +13,6 @@ import { $getRoot } from "lexical";
|
|
|
13
13
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
14
14
|
import { SerializeLexical, validateUrl } from "./__internal__/helpers";
|
|
15
15
|
import Label from "../../__internal__/label";
|
|
16
|
-
import useDebounce from "../../hooks/__internal__/useDebounce";
|
|
17
16
|
import useLocale from "../../hooks/__internal__/useLocale";
|
|
18
17
|
import Logger from "../../__internal__/utils/logger";
|
|
19
18
|
import { COMPONENT_PREFIX, markdownNodes, theme } from "./__internal__/constants";
|
|
@@ -34,8 +33,10 @@ export const TextEditor = ({
|
|
|
34
33
|
isOptional = false,
|
|
35
34
|
labelText,
|
|
36
35
|
namespace = COMPONENT_PREFIX,
|
|
36
|
+
onBlur,
|
|
37
37
|
onCancel,
|
|
38
38
|
onChange,
|
|
39
|
+
onFocus,
|
|
39
40
|
onLinkAdded,
|
|
40
41
|
onSave,
|
|
41
42
|
placeholder,
|
|
@@ -74,7 +75,6 @@ export const TextEditor = ({
|
|
|
74
75
|
return cleanup;
|
|
75
76
|
}, [contentEditorRef]);
|
|
76
77
|
const [cancelTrigger, setCancelTrigger] = useState(false);
|
|
77
|
-
const debounceWaitTime = 500;
|
|
78
78
|
const initialConfig = useMemo(() => {
|
|
79
79
|
return {
|
|
80
80
|
namespace,
|
|
@@ -88,7 +88,7 @@ export const TextEditor = ({
|
|
|
88
88
|
|
|
89
89
|
// OnChangePlugin is tested separately
|
|
90
90
|
/* istanbul ignore next */
|
|
91
|
-
const handleChange =
|
|
91
|
+
const handleChange = useCallback(newState => {
|
|
92
92
|
const currentTextContent = newState.read(() => $getRoot().getTextContent());
|
|
93
93
|
if (onChange) {
|
|
94
94
|
const formattedValues = editorRef.current ? SerializeLexical(editorRef.current) : {};
|
|
@@ -101,11 +101,10 @@ export const TextEditor = ({
|
|
|
101
101
|
// If the character limit has been exceeded, show the character limit warning
|
|
102
102
|
setCharacterLimitWarning(currentDiff < 0 ? locale.textEditor.characterLimit(Math.abs(currentDiff)) : undefined);
|
|
103
103
|
}
|
|
104
|
-
},
|
|
104
|
+
}, [characterLimit, locale.textEditor, onChange]);
|
|
105
105
|
const handleCancel = useCallback(() => {
|
|
106
|
-
const editor = editorRef.current;
|
|
107
106
|
/* istanbul ignore next */
|
|
108
|
-
const isEditable =
|
|
107
|
+
const isEditable = editorRef.current?.isEditable() || false;
|
|
109
108
|
/* istanbul ignore if */
|
|
110
109
|
if (!isEditable) return;
|
|
111
110
|
|
|
@@ -118,13 +117,12 @@ export const TextEditor = ({
|
|
|
118
117
|
|
|
119
118
|
// Reset the value of the editor when the cancel trigger is updated (implements reset on cancel)
|
|
120
119
|
useEffect(() => {
|
|
121
|
-
const editor = editorRef.current;
|
|
122
120
|
const safeValue = value || createEmpty();
|
|
123
121
|
|
|
124
122
|
/* istanbul ignore else */
|
|
125
|
-
if (
|
|
126
|
-
const newEditorState =
|
|
127
|
-
|
|
123
|
+
if (editorRef.current) {
|
|
124
|
+
const newEditorState = editorRef.current.parseEditorState(safeValue);
|
|
125
|
+
editorRef.current.setEditorState(newEditorState);
|
|
128
126
|
}
|
|
129
127
|
}, [cancelTrigger, value]);
|
|
130
128
|
const toolbarProps = useMemo(() => ({
|
|
@@ -133,7 +131,17 @@ export const TextEditor = ({
|
|
|
133
131
|
onSave
|
|
134
132
|
}), [handleCancel, namespace, onCancel, onSave]);
|
|
135
133
|
return /*#__PURE__*/React.createElement(StyledTextEditorWrapper, _extends({
|
|
136
|
-
"data-role": `${namespace}-editor-wrapper
|
|
134
|
+
"data-role": `${namespace}-editor-wrapper`,
|
|
135
|
+
onBlur: ev => {
|
|
136
|
+
if (!ev.currentTarget.contains(ev.relatedTarget)) {
|
|
137
|
+
onBlur?.(ev);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
onFocus: ev => {
|
|
141
|
+
if (!ev.currentTarget.contains(ev.relatedTarget)) {
|
|
142
|
+
onFocus?.(ev);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
137
145
|
}, filterStyledSystemMarginProps(rest), tagComponent("text-editor", rest)), /*#__PURE__*/React.createElement(TextEditorContext.Provider, {
|
|
138
146
|
value: {
|
|
139
147
|
onLinkAdded
|
|
@@ -20,7 +20,7 @@ var _constants = require("./constants");
|
|
|
20
20
|
const SerializeLexical = editor => {
|
|
21
21
|
let htmlString;
|
|
22
22
|
let json;
|
|
23
|
-
editor.
|
|
23
|
+
editor.read(() => {
|
|
24
24
|
// Get the current editor state
|
|
25
25
|
const editorState = editor.getEditorState();
|
|
26
26
|
// Serialize the editor state to JSON
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _LexicalComposerContext = require("@lexical/react/LexicalComposerContext");
|
|
9
|
+
/**
|
|
10
|
+
* This plugin allows retrieval of a reference to the current editor. It's useful
|
|
11
|
+
* for testing purposes, where tests might need to directly interact with the editor to
|
|
12
|
+
* emulate e.g. blurring.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const EditorRefPlugin = ({
|
|
16
|
+
setEditorRef
|
|
17
|
+
}) => {
|
|
18
|
+
const [editor] = (0, _LexicalComposerContext.useLexicalComposerContext)();
|
|
19
|
+
(0, _react.useEffect)(() => {
|
|
20
|
+
setEditorRef(editor);
|
|
21
|
+
}, [editor, setEditorRef]);
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
var _default = exports.default = EditorRefPlugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./editor-ref.plugin";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "default", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _editorRef.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _editorRef = _interopRequireDefault(require("./editor-ref.plugin"));
|
|
13
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -94,7 +94,6 @@ const Toolbar = ({
|
|
|
94
94
|
"aria-label": locale.textEditor.toolbarAriaLabel(),
|
|
95
95
|
"data-role": `${namespace}-toolbar`,
|
|
96
96
|
id: `${namespace}-toolbar`,
|
|
97
|
-
onFocus: e => e.stopPropagation(),
|
|
98
97
|
ref: toolbarRef
|
|
99
98
|
}, /*#__PURE__*/_react.default.createElement(_toolbar.FormattingButtons, {
|
|
100
99
|
"data-role": `${namespace}-formatting-buttons`
|
|
@@ -23,10 +23,14 @@ export interface TextEditorProps extends MarginProps, TagProps {
|
|
|
23
23
|
labelText: string;
|
|
24
24
|
/** The identifier for the Text Editor. This allows for the using of multiple Text Editors on a screen */
|
|
25
25
|
namespace?: string;
|
|
26
|
+
/** The callback to fire when the editor loses focus */
|
|
27
|
+
onBlur?: (ev: React.FocusEvent<HTMLElement>) => void;
|
|
26
28
|
/** The callback to fire when the Cancel button within the editor is pressed */
|
|
27
29
|
onCancel?: () => void;
|
|
28
30
|
/** The callback to fire when a change is registered within the editor */
|
|
29
31
|
onChange?: (value: string, formattedValues: EditorFormattedValues) => void;
|
|
32
|
+
/** The callback to fire when the editor gains focus */
|
|
33
|
+
onFocus?: (ev: React.FocusEvent<HTMLElement>) => void;
|
|
30
34
|
/** The callback to fire when a link is added into the editor */
|
|
31
35
|
onLinkAdded?: (link: string, state: string) => void;
|
|
32
36
|
/** The callback to fire when the Save button within the editor is pressed */
|
|
@@ -46,5 +50,5 @@ export interface TextEditorProps extends MarginProps, TagProps {
|
|
|
46
50
|
/** The initial value of the editor, as a HTML string, or JSON */
|
|
47
51
|
value?: string | undefined;
|
|
48
52
|
}
|
|
49
|
-
export declare const TextEditor: ({ characterLimit, error, footer, header, inputHint, isOptional, labelText, namespace, onCancel, onChange, onLinkAdded, onSave, placeholder, previews, readOnly, required, rows, warning, value, ...rest }: TextEditorProps) => React.JSX.Element;
|
|
53
|
+
export declare const TextEditor: ({ characterLimit, error, footer, header, inputHint, isOptional, labelText, namespace, onBlur, onCancel, onChange, onFocus, onLinkAdded, onSave, placeholder, previews, readOnly, required, rows, warning, value, ...rest }: TextEditorProps) => React.JSX.Element;
|
|
50
54
|
export default TextEditor;
|
|
@@ -17,7 +17,6 @@ var _lexical = require("lexical");
|
|
|
17
17
|
var _react = _interopRequireWildcard(require("react"));
|
|
18
18
|
var _helpers = require("./__internal__/helpers");
|
|
19
19
|
var _label = _interopRequireDefault(require("../../__internal__/label"));
|
|
20
|
-
var _useDebounce = _interopRequireDefault(require("../../hooks/__internal__/useDebounce"));
|
|
21
20
|
var _useLocale = _interopRequireDefault(require("../../hooks/__internal__/useLocale"));
|
|
22
21
|
var _logger = _interopRequireDefault(require("../../__internal__/utils/logger"));
|
|
23
22
|
var _constants = require("./__internal__/constants");
|
|
@@ -42,8 +41,10 @@ const TextEditor = ({
|
|
|
42
41
|
isOptional = false,
|
|
43
42
|
labelText,
|
|
44
43
|
namespace = _constants.COMPONENT_PREFIX,
|
|
44
|
+
onBlur,
|
|
45
45
|
onCancel,
|
|
46
46
|
onChange,
|
|
47
|
+
onFocus,
|
|
47
48
|
onLinkAdded,
|
|
48
49
|
onSave,
|
|
49
50
|
placeholder,
|
|
@@ -82,7 +83,6 @@ const TextEditor = ({
|
|
|
82
83
|
return cleanup;
|
|
83
84
|
}, [contentEditorRef]);
|
|
84
85
|
const [cancelTrigger, setCancelTrigger] = (0, _react.useState)(false);
|
|
85
|
-
const debounceWaitTime = 500;
|
|
86
86
|
const initialConfig = (0, _react.useMemo)(() => {
|
|
87
87
|
return {
|
|
88
88
|
namespace,
|
|
@@ -96,7 +96,7 @@ const TextEditor = ({
|
|
|
96
96
|
|
|
97
97
|
// OnChangePlugin is tested separately
|
|
98
98
|
/* istanbul ignore next */
|
|
99
|
-
const handleChange = (0,
|
|
99
|
+
const handleChange = (0, _react.useCallback)(newState => {
|
|
100
100
|
const currentTextContent = newState.read(() => (0, _lexical.$getRoot)().getTextContent());
|
|
101
101
|
if (onChange) {
|
|
102
102
|
const formattedValues = editorRef.current ? (0, _helpers.SerializeLexical)(editorRef.current) : {};
|
|
@@ -109,11 +109,10 @@ const TextEditor = ({
|
|
|
109
109
|
// If the character limit has been exceeded, show the character limit warning
|
|
110
110
|
setCharacterLimitWarning(currentDiff < 0 ? locale.textEditor.characterLimit(Math.abs(currentDiff)) : undefined);
|
|
111
111
|
}
|
|
112
|
-
},
|
|
112
|
+
}, [characterLimit, locale.textEditor, onChange]);
|
|
113
113
|
const handleCancel = (0, _react.useCallback)(() => {
|
|
114
|
-
const editor = editorRef.current;
|
|
115
114
|
/* istanbul ignore next */
|
|
116
|
-
const isEditable =
|
|
115
|
+
const isEditable = editorRef.current?.isEditable() || false;
|
|
117
116
|
/* istanbul ignore if */
|
|
118
117
|
if (!isEditable) return;
|
|
119
118
|
|
|
@@ -126,13 +125,12 @@ const TextEditor = ({
|
|
|
126
125
|
|
|
127
126
|
// Reset the value of the editor when the cancel trigger is updated (implements reset on cancel)
|
|
128
127
|
(0, _react.useEffect)(() => {
|
|
129
|
-
const editor = editorRef.current;
|
|
130
128
|
const safeValue = value || (0, _utils.createEmpty)();
|
|
131
129
|
|
|
132
130
|
/* istanbul ignore else */
|
|
133
|
-
if (
|
|
134
|
-
const newEditorState =
|
|
135
|
-
|
|
131
|
+
if (editorRef.current) {
|
|
132
|
+
const newEditorState = editorRef.current.parseEditorState(safeValue);
|
|
133
|
+
editorRef.current.setEditorState(newEditorState);
|
|
136
134
|
}
|
|
137
135
|
}, [cancelTrigger, value]);
|
|
138
136
|
const toolbarProps = (0, _react.useMemo)(() => ({
|
|
@@ -141,7 +139,17 @@ const TextEditor = ({
|
|
|
141
139
|
onSave
|
|
142
140
|
}), [handleCancel, namespace, onCancel, onSave]);
|
|
143
141
|
return /*#__PURE__*/_react.default.createElement(_textEditor2.StyledTextEditorWrapper, _extends({
|
|
144
|
-
"data-role": `${namespace}-editor-wrapper
|
|
142
|
+
"data-role": `${namespace}-editor-wrapper`,
|
|
143
|
+
onBlur: ev => {
|
|
144
|
+
if (!ev.currentTarget.contains(ev.relatedTarget)) {
|
|
145
|
+
onBlur?.(ev);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
onFocus: ev => {
|
|
149
|
+
if (!ev.currentTarget.contains(ev.relatedTarget)) {
|
|
150
|
+
onFocus?.(ev);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
145
153
|
}, (0, _utils2.filterStyledSystemMarginProps)(rest), (0, _tags.default)("text-editor", rest)), /*#__PURE__*/_react.default.createElement(_textEditor.default.Provider, {
|
|
146
154
|
value: {
|
|
147
155
|
onLinkAdded
|