carbon-react 153.3.1 → 153.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.
Files changed (45) hide show
  1. package/esm/components/note/note.component.js +1 -2
  2. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.d.ts +3 -5
  3. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.js +8 -11
  4. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.d.ts +1 -0
  5. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.js +8 -14
  6. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.d.ts +3 -9
  7. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.js +3 -15
  8. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.d.ts +1 -5
  9. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.js +3 -26
  10. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.d.ts +3 -1
  11. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.js +2 -0
  12. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.d.ts +3 -1
  13. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.js +9 -5
  14. package/esm/components/text-editor/text-editor.component.d.ts +5 -1
  15. package/esm/components/text-editor/text-editor.component.js +34 -10
  16. package/esm/components/text-editor/text-editor.context.d.ts +0 -1
  17. package/esm/components/text-editor/text-editor.style.d.ts +3 -0
  18. package/esm/components/text-editor/text-editor.style.js +10 -6
  19. package/esm/locales/de-de.js +18 -0
  20. package/esm/locales/es-es.js +18 -0
  21. package/esm/locales/fr-ca.js +18 -0
  22. package/esm/locales/fr-fr.js +18 -0
  23. package/lib/components/note/note.component.js +1 -2
  24. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.d.ts +3 -5
  25. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.js +10 -11
  26. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.d.ts +1 -0
  27. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.js +8 -14
  28. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.d.ts +3 -9
  29. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.js +3 -17
  30. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.d.ts +1 -5
  31. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.js +4 -28
  32. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.d.ts +3 -1
  33. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.js +2 -0
  34. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.d.ts +3 -1
  35. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.js +9 -5
  36. package/lib/components/text-editor/text-editor.component.d.ts +5 -1
  37. package/lib/components/text-editor/text-editor.component.js +33 -9
  38. package/lib/components/text-editor/text-editor.context.d.ts +0 -1
  39. package/lib/components/text-editor/text-editor.style.d.ts +3 -0
  40. package/lib/components/text-editor/text-editor.style.js +11 -7
  41. package/lib/locales/de-de.js +18 -0
  42. package/lib/locales/es-es.js +18 -0
  43. package/lib/locales/fr-ca.js +18 -0
  44. package/lib/locales/fr-fr.js +18 -0
  45. package/package.json +1 -1
@@ -43,8 +43,7 @@ export const Note = ({
43
43
  };
44
44
  return /*#__PURE__*/React.createElement(TextEditorContext.Provider, {
45
45
  value: {
46
- onLinkAdded,
47
- readOnly: true
46
+ onLinkAdded
48
47
  }
49
48
  }, /*#__PURE__*/React.createElement(StyledNote, _extends({
50
49
  width: width
@@ -1,7 +1,5 @@
1
1
  import React from "react";
2
2
  export interface ContentEditorProps {
3
- /** The active error message of the editor */
4
- error?: string;
5
3
  /** A hint string rendered before the editor but after the label. Intended to describe the purpose or content of the input. */
6
4
  inputHint?: string;
7
5
  /** The namespace of the editor that this content editor belongs to */
@@ -10,8 +8,8 @@ export interface ContentEditorProps {
10
8
  previews?: React.JSX.Element[];
11
9
  /** The number of rows to render in the editor */
12
10
  rows?: number;
13
- /** The active warning message of the editor */
14
- warning?: string;
11
+ /** Whether the editor is read-only */
12
+ readOnly?: boolean;
15
13
  }
16
- declare const ContentEditor: ({ error, inputHint, namespace, previews, rows, warning, }: ContentEditorProps) => React.JSX.Element;
14
+ declare const ContentEditor: React.ForwardRefExoticComponent<ContentEditorProps & React.RefAttributes<HTMLDivElement>>;
17
15
  export default ContentEditor;
@@ -3,25 +3,24 @@
3
3
  * as per their documentation. It also uses the `LinkPreviewerPlugin` to render link previews.
4
4
  */
5
5
  import { ContentEditable } from "@lexical/react/LexicalContentEditable";
6
- import React from "react";
6
+ import React, { forwardRef } from "react";
7
7
  import StyledContentEditable from "./content-editor.style";
8
8
  import { LinkPreviewerPlugin, useCursorAtEnd } from "..";
9
- const ContentEditor = ({
10
- error,
9
+ const ContentEditor = /*#__PURE__*/forwardRef(({
11
10
  inputHint,
12
11
  namespace,
13
12
  previews = [],
14
13
  rows,
15
- warning
16
- }) => {
14
+ readOnly
15
+ }, ref) => {
17
16
  const focusAtEnd = useCursorAtEnd();
18
17
  return /*#__PURE__*/React.createElement(StyledContentEditable, {
19
18
  "data-role": `${namespace}-content-editable`,
20
- error: error,
21
19
  namespace: namespace,
22
20
  rows: rows,
23
- warning: warning
21
+ readOnly: readOnly
24
22
  }, /*#__PURE__*/React.createElement(ContentEditable, {
23
+ ref: ref,
25
24
  "aria-describedby": inputHint && `${namespace}-input-hint`,
26
25
  "aria-labelledby": `${namespace}-label`,
27
26
  className: `${namespace}-editable`,
@@ -37,9 +36,7 @@ const ContentEditor = ({
37
36
  "aria-autocomplete": undefined,
38
37
  "aria-readonly": undefined
39
38
  }), /*#__PURE__*/React.createElement(LinkPreviewerPlugin, {
40
- error: error,
41
- previews: previews,
42
- warning: warning
39
+ previews: previews
43
40
  }));
44
- };
41
+ });
45
42
  export default ContentEditor;
@@ -1,6 +1,7 @@
1
1
  import { ContentEditorProps } from "./content-editor.component";
2
2
  interface StyledContentEditableProps extends ContentEditorProps {
3
3
  showBorders?: boolean;
4
+ readOnly?: boolean;
4
5
  }
5
6
  declare const StyledContentEditable: import("styled-components").StyledComponent<"div", any, StyledContentEditableProps, never>;
6
7
  export default StyledContentEditable;
@@ -3,28 +3,22 @@ const DEFAULT_EDITOR_HEIGHT = 210;
3
3
  const FIXED_LINE_HEIGHT = 21;
4
4
  const StyledContentEditable = styled.div`
5
5
  ${({
6
- error,
7
6
  namespace,
8
7
  rows,
9
- warning
8
+ readOnly
10
9
  }) => css`
11
10
  .${namespace}-editable {
12
11
  min-height: ${rows && rows > 2 ? rows * FIXED_LINE_HEIGHT : DEFAULT_EDITOR_HEIGHT}px;
13
12
  background-color: var(--colorsUtilityYang100);
14
- border-top: 1px solid var(--colorsUtilityMajor200);
15
- border-left: 1px solid var(--colorsUtilityMajor200);
16
- border-right: 1px solid var(--colorsUtilityMajor200);
13
+ ${!readOnly && "border-top: 1px solid var(--colorsUtilityMajor200);"}
14
+ ${readOnly && `
15
+ border-top-left-radius: var(--borderRadius100);
16
+ border-top-right-radius: var(--borderRadius100);
17
+ `}
17
18
  margin: 0;
18
19
  padding: 2px 8px;
19
- border-top-left-radius: var(--borderWidth600);
20
- border-top-right-radius: var(--borderWidth600);
21
- border-bottom-left-radius: 0;
22
- border-bottom-right-radius: 0;
23
-
24
- ${(error || warning) && css`
25
- border: none;
26
- `}
27
-
20
+ border-bottom-right-radius: var(--borderRadius100);
21
+ border-bottom-left-radius: var(--borderRadius100);
28
22
  :focus {
29
23
  outline: none;
30
24
  }
@@ -1,11 +1,5 @@
1
1
  import React from "react";
2
- export interface LinkPreviewerProps {
3
- /** The active error message of the editor */
4
- error?: string;
5
- /** The link previews to render at the foot of the editor */
6
- previews?: React.JSX.Element[];
7
- /** The active warning message of the editor */
8
- warning?: string;
9
- }
10
- declare const LinkPreviewer: ({ error, previews, warning, }: LinkPreviewerProps) => React.JSX.Element;
2
+ declare const LinkPreviewer: ({ previews, }: {
3
+ previews?: React.JSX.Element[] | undefined;
4
+ }) => React.JSX.Element;
11
5
  export default LinkPreviewer;
@@ -1,18 +1,6 @@
1
- import React, { useContext } from "react";
2
- import TextEditorContext from "../../../text-editor.context";
1
+ import React from "react";
3
2
  import StyledLinkPreviewer from "./link-previewer.style";
4
3
  const LinkPreviewer = ({
5
- error,
6
- previews = [],
7
- warning
8
- }) => {
9
- const {
10
- readOnly
11
- } = useContext(TextEditorContext);
12
- return /*#__PURE__*/React.createElement(StyledLinkPreviewer, {
13
- error: error,
14
- readOnly: readOnly,
15
- warning: warning
16
- }, previews);
17
- };
4
+ previews = []
5
+ }) => /*#__PURE__*/React.createElement(StyledLinkPreviewer, null, previews);
18
6
  export default LinkPreviewer;
@@ -1,6 +1,2 @@
1
- import { LinkPreviewerProps } from "./link-previewer.component";
2
- interface StyledLinkPreviewerProps extends LinkPreviewerProps {
3
- readOnly?: boolean;
4
- }
5
- declare const StyledLinkPreviewer: import("styled-components").StyledComponent<"div", any, StyledLinkPreviewerProps, never>;
1
+ declare const StyledLinkPreviewer: import("styled-components").StyledComponent<"div", any, {}, never>;
6
2
  export default StyledLinkPreviewer;
@@ -1,29 +1,6 @@
1
- import styled, { css } from "styled-components";
1
+ import styled from "styled-components";
2
2
  const StyledLinkPreviewer = styled.div`
3
- ${({
4
- error,
5
- readOnly,
6
- warning
7
- }) => css`
8
- border-bottom-left-radius: 0;
9
- border-bottom-right-radius: 0;
10
- background-color: var(--colorsUtilityYang100);
11
- border-bottom: 1px solid var(--colorsUtilityMajor200);
12
- border-left: 1px solid var(--colorsUtilityMajor200);
13
- border-right: 1px solid var(--colorsUtilityMajor200);
14
- margin: 0;
15
- padding: 2px 8px;
16
-
17
- ${(error || warning) && css`
18
- border-left: none;
19
- border-right: none;
20
- border-bottom: none;
21
- `}
22
-
23
- ${readOnly && css`
24
- border-bottom-left-radius: var(--borderWidth600);
25
- border-bottom-right-radius: var(--borderWidth600);
26
- `}
27
- `}
3
+ margin: 0;
4
+ padding: 2px 8px;
28
5
  `;
29
6
  export default StyledLinkPreviewer;
@@ -3,10 +3,12 @@ import { EditorFormattedValues } from "./buttons/save.component";
3
3
  interface ToolbarProps {
4
4
  /** The namespace of the editor that this toolbar belongs to */
5
5
  namespace: string;
6
+ /** Determines if the Text Editor has a header */
7
+ hasHeader?: boolean;
6
8
  /** The callback to call when the cancel button is clicked */
7
9
  onCancel?: () => void;
8
10
  /** The callback to call when the save button is clicked */
9
11
  onSave?: (value: EditorFormattedValues) => void;
10
12
  }
11
- declare const Toolbar: ({ namespace, onCancel, onSave }: ToolbarProps) => React.JSX.Element;
13
+ declare const Toolbar: ({ namespace, hasHeader, onCancel, onSave }: ToolbarProps) => React.JSX.Element;
12
14
  export default Toolbar;
@@ -10,6 +10,7 @@ import { BoldButton, ItalicButton, ListControls } from "./buttons";
10
10
  import SaveButton from "./buttons/save.component";
11
11
  const Toolbar = ({
12
12
  namespace,
13
+ hasHeader,
13
14
  onCancel,
14
15
  onSave
15
16
  }) => {
@@ -80,6 +81,7 @@ const Toolbar = ({
80
81
  }, [buttons]);
81
82
  return /*#__PURE__*/React.createElement(StyledToolbar, {
82
83
  role: "toolbar",
84
+ hasHeader: hasHeader,
83
85
  "aria-label": locale.textEditor.toolbarAriaLabel(),
84
86
  "data-role": `${namespace}-toolbar`,
85
87
  id: `${namespace}-toolbar`,
@@ -4,7 +4,9 @@ interface FormattingButtonProps extends ButtonProps {
4
4
  tabIndex?: number;
5
5
  isActive?: boolean;
6
6
  }
7
- declare const StyledToolbar: import("styled-components").StyledComponent<"div", any, {}, never>;
7
+ declare const StyledToolbar: import("styled-components").StyledComponent<"div", any, {
8
+ hasHeader?: boolean | undefined;
9
+ }, never>;
8
10
  declare const FormattingButtons: import("styled-components").StyledComponent<"div", any, {}, never>;
9
11
  declare const CommandButtons: import("styled-components").StyledComponent<"div", any, {}, never>;
10
12
  declare const FormattingButton: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLAnchorElement | HTMLButtonElement>>, any, FormattingButtonProps, never>;
@@ -4,12 +4,16 @@ const StyledToolbar = styled.div`
4
4
  display: flex;
5
5
  flex-direction: row;
6
6
  gap: 8px;
7
- background-color: var(--colorsUtilityMajor025);
8
- outline: 1px solid var(--colorsUtilityMajor200);
7
+ background-color: var(--colorsActionMajorYang100);
9
8
  padding: 12px;
10
- border-radius: var(--borderRadius100);
11
- border-top-left-radius: 0;
12
- border-top-right-radius: 0;
9
+ border-top-left-radius: ${({
10
+ hasHeader
11
+ }) => hasHeader ? "0" : "var(--borderRadius100)"};
12
+ border-top-right-radius: ${({
13
+ hasHeader
14
+ }) => hasHeader ? "0" : "var(--borderRadius100)"};
15
+ border-bottom-left-radius: 0;
16
+ border-bottom-right-radius: 0;
13
17
  justify-content: space-between;
14
18
  align-items: center;
15
19
  margin-left: 1px;
@@ -8,6 +8,10 @@ export interface TextEditorProps extends MarginProps, TagProps {
8
8
  characterLimit?: number;
9
9
  /** The message to be shown when the editor is in an error state */
10
10
  error?: string;
11
+ /** Custom footer content to be displayed below the editor */
12
+ footer?: React.ReactNode;
13
+ /** Custom header content to be displayed above the editor */
14
+ header?: React.ReactNode;
11
15
  /** A hint string rendered before the editor but after the label. Intended to describe the purpose or content of the input. */
12
16
  inputHint?: string;
13
17
  /** Whether the content of the editor can be empty */
@@ -39,5 +43,5 @@ export interface TextEditorProps extends MarginProps, TagProps {
39
43
  /** The initial value of the editor, as a HTML string, or JSON */
40
44
  value?: string | undefined;
41
45
  }
42
- export declare const TextEditor: ({ characterLimit, error, inputHint, isOptional, labelText, namespace, onCancel, onChange, onLinkAdded, onSave, placeholder, previews, readOnly, required, rows, warning, value, ...rest }: TextEditorProps) => React.JSX.Element;
46
+ 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;
43
47
  export default TextEditor;
@@ -18,7 +18,7 @@ import useLocale from "../../hooks/__internal__/useLocale";
18
18
  import { COMPONENT_PREFIX, markdownNodes, theme } from "./__internal__/constants";
19
19
  import { AutoLinkerPlugin, CharacterCounterPlugin, ContentEditor, LinkMonitorPlugin, OnChangePlugin, Placeholder, ToolbarPlugin } from "./__internal__/plugins";
20
20
  import TextEditorContext from "./text-editor.context";
21
- import StyledTextEditor, { StyledEditorToolbarWrapper, StyledTextEditorWrapper, StyledValidationMessage, StyledWrapper } from "./text-editor.style";
21
+ import StyledTextEditor, { StyledEditorToolbarWrapper, StyledHeaderWrapper, StyledFooterWrapper, StyledTextEditorWrapper, StyledValidationMessage, StyledWrapper } from "./text-editor.style";
22
22
  import { createEmpty } from "./utils";
23
23
  import HintText from "../../__internal__/hint-text";
24
24
  import { filterStyledSystemMarginProps } from "../../style/utils";
@@ -26,6 +26,8 @@ import tagComponent from "../../__internal__/utils/helpers/tags";
26
26
  export const TextEditor = ({
27
27
  characterLimit = 3000,
28
28
  error,
29
+ footer,
30
+ header,
29
31
  inputHint,
30
32
  isOptional = false,
31
33
  labelText,
@@ -46,7 +48,25 @@ export const TextEditor = ({
46
48
  const editorRef = useRef(undefined);
47
49
  const locale = useLocale();
48
50
  const [characterLimitWarning, setCharacterLimitWarning] = useState(undefined);
51
+ const hasWarningOrError = Boolean(error || characterLimitWarning || warning);
52
+ const contentEditorRef = useRef(null);
49
53
  const [isFocused, setIsFocused] = useState(false);
54
+ useEffect(() => {
55
+ const editorElement = contentEditorRef?.current;
56
+ const handleFocus = () => {
57
+ setIsFocused(true);
58
+ };
59
+ const handleBlur = () => {
60
+ setIsFocused(false);
61
+ };
62
+ editorElement?.addEventListener("focus", handleFocus);
63
+ editorElement?.addEventListener("blur", handleBlur);
64
+ const cleanup = () => {
65
+ editorElement?.removeEventListener("focus", handleFocus);
66
+ editorElement?.removeEventListener("blur", handleBlur);
67
+ };
68
+ return cleanup;
69
+ }, [contentEditorRef]);
50
70
  const [cancelTrigger, setCancelTrigger] = useState(false);
51
71
  const debounceWaitTime = 500;
52
72
  const initialConfig = useMemo(() => {
@@ -110,8 +130,7 @@ export const TextEditor = ({
110
130
  "data-role": `${namespace}-editor-wrapper`
111
131
  }, filterStyledSystemMarginProps(rest), tagComponent("text-editor", rest)), /*#__PURE__*/React.createElement(TextEditorContext.Provider, {
112
132
  value: {
113
- onLinkAdded,
114
- readOnly
133
+ onLinkAdded
115
134
  }
116
135
  }, /*#__PURE__*/React.createElement(Label, {
117
136
  isRequired: required,
@@ -135,19 +154,22 @@ export const TextEditor = ({
135
154
  }, error || characterLimitWarning || warning), /*#__PURE__*/React.createElement(StyledEditorToolbarWrapper, {
136
155
  "data-role": `${namespace}-editor-toolbar-wrapper`,
137
156
  id: `${namespace}-editor-toolbar-wrapper`,
138
- onBlur: () => setIsFocused(false),
139
- onFocus: () => setIsFocused(true),
140
- focused: isFocused
141
- }, /*#__PURE__*/React.createElement(StyledTextEditor, {
157
+ focused: isFocused,
158
+ hasWarningOrError: hasWarningOrError
159
+ }, header && /*#__PURE__*/React.createElement(StyledHeaderWrapper, {
160
+ "data-role": `${namespace}-header-wrapper`
161
+ }, header), !readOnly && /*#__PURE__*/React.createElement(ToolbarPlugin, _extends({
162
+ hasHeader: Boolean(header)
163
+ }, toolbarProps)), /*#__PURE__*/React.createElement(StyledTextEditor, {
142
164
  "data-role": `${namespace}-editor`
143
165
  }, /*#__PURE__*/React.createElement(RichTextPlugin, {
144
166
  contentEditable: /*#__PURE__*/React.createElement(ContentEditor, {
145
- error: error,
167
+ ref: contentEditorRef,
146
168
  inputHint: inputHint,
147
169
  namespace: namespace,
148
170
  previews: previews,
149
171
  rows: rows,
150
- warning: warning
172
+ readOnly: readOnly
151
173
  }),
152
174
  placeholder: /*#__PURE__*/React.createElement(Placeholder, {
153
175
  namespace: namespace,
@@ -160,7 +182,9 @@ export const TextEditor = ({
160
182
  validateUrl: validateUrl
161
183
  }), /*#__PURE__*/React.createElement(ClickableLinkPlugin, {
162
184
  newTab: true
163
- }), /*#__PURE__*/React.createElement(AutoLinkerPlugin, null)), !readOnly && /*#__PURE__*/React.createElement(ToolbarPlugin, toolbarProps), /*#__PURE__*/React.createElement(LinkMonitorPlugin, null)), characterLimit > 0 && !readOnly && /*#__PURE__*/React.createElement(CharacterCounterPlugin, {
185
+ }), /*#__PURE__*/React.createElement(AutoLinkerPlugin, null)), footer && /*#__PURE__*/React.createElement(StyledFooterWrapper, {
186
+ "data-role": `${namespace}-footer-wrapper`
187
+ }, footer), /*#__PURE__*/React.createElement(LinkMonitorPlugin, null)), characterLimit > 0 && !readOnly && /*#__PURE__*/React.createElement(CharacterCounterPlugin, {
164
188
  maxChars: characterLimit,
165
189
  namespace: namespace
166
190
  })))));
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  declare const _default: React.Context<{
3
3
  onLinkAdded?: ((link: string, state: string) => void) | undefined;
4
- readOnly?: boolean | undefined;
5
4
  }>;
6
5
  export default _default;
@@ -11,10 +11,13 @@ interface StyledValidationMessageProps {
11
11
  }
12
12
  interface StyledEditorToolbarWrapperProps {
13
13
  focused?: boolean;
14
+ hasWarningOrError?: boolean;
14
15
  }
15
16
  export declare const StyledTextEditor: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../box").BoxProps & import("react").RefAttributes<HTMLDivElement>>, any, {}, never>;
16
17
  export declare const StyledTextEditorWrapper: import("styled-components").StyledComponent<"div", any, StyledTextEditorWrapperProps, never>;
17
18
  export declare const StyledWrapper: import("styled-components").StyledComponent<"div", any, StyledWrapperProps, never>;
18
19
  export declare const StyledEditorToolbarWrapper: import("styled-components").StyledComponent<"div", any, StyledEditorToolbarWrapperProps, never>;
20
+ export declare const StyledHeaderWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
21
+ export declare const StyledFooterWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
19
22
  export declare const StyledValidationMessage: import("styled-components").StyledComponent<"div", any, StyledValidationMessageProps, never>;
20
23
  export default StyledTextEditor;
@@ -35,24 +35,28 @@ export const StyledWrapper = styled.div`
35
35
  .${namespace}-editable, #${namespace}-toolbar {
36
36
  outline: none;
37
37
  }
38
-
39
- #${namespace}-toolbar {
40
- border-top: 1px solid var(--colorsUtilityMajor200);
41
- }
42
38
  }
43
39
  `}
44
40
  `};
45
41
  `;
46
42
  export const StyledEditorToolbarWrapper = styled.div`
47
43
  ${({
48
- focused
44
+ focused,
45
+ hasWarningOrError
49
46
  }) => css`
50
47
  border-radius: var(--borderRadius100);
51
- outline: none;
48
+ outline: ${hasWarningOrError ? "none" : "1px solid var(--colorsUtilityMajor200)"};
52
49
 
53
50
  ${focused && addFocusStyling()}
54
51
  `}
55
52
  `;
53
+ export const StyledHeaderWrapper = styled.div`
54
+ padding: var(--spacing200);
55
+ `;
56
+ export const StyledFooterWrapper = styled.div`
57
+ border-top: 1px solid var(--colorsUtilityMajor200);
58
+ padding: var(--spacing200);
59
+ `;
56
60
  export const StyledValidationMessage = styled.div`
57
61
  ${({
58
62
  error
@@ -148,6 +148,24 @@ const deDE = {
148
148
  pod: {
149
149
  undo: () => "Rückgängig"
150
150
  },
151
+ textEditor: {
152
+ boldAria: () => "Fett",
153
+ cancelButton: () => "Abbrechen",
154
+ cancelButtonAria: () => "Abbrechen",
155
+ characterCounter(count) {
156
+ return `Noch ${typeof count === "number" ? count.toString() : count} Zeichen`;
157
+ },
158
+ characterLimit(count) {
159
+ return `Sie sind ${count} Zeichen über dem Zeichenlimit`;
160
+ },
161
+ contentEditorAria: () => "Editor für Rich-Text-Inhalte",
162
+ italicAria: () => "Kursiv",
163
+ orderedListAria: () => "Sortierte Liste",
164
+ saveButton: () => "Speichern",
165
+ saveButtonAria: () => "Speichern",
166
+ toolbarAriaLabel: () => "Formatierung",
167
+ unorderedListAria: () => "Unsortierte Liste"
168
+ },
151
169
  search: {
152
170
  searchButtonText: () => "Suchen"
153
171
  },
@@ -149,6 +149,24 @@ const esES = {
149
149
  pod: {
150
150
  undo: () => "Deshacer"
151
151
  },
152
+ textEditor: {
153
+ boldAria: () => "Negrita",
154
+ cancelButton: () => "Cancelar",
155
+ cancelButtonAria: () => "Cancelar",
156
+ characterCounter(count) {
157
+ return `Quedan ${typeof count === "number" ? count.toString() : count} caracteres`;
158
+ },
159
+ characterLimit(count) {
160
+ return `El límite de ${count} caracteres se ha superado.`;
161
+ },
162
+ contentEditorAria: () => "Editor de contenidos de texto enriquecido",
163
+ italicAria: () => "Cursiva",
164
+ orderedListAria: () => "Lista ordenada",
165
+ saveButton: () => "Guardar",
166
+ saveButtonAria: () => "Guardar",
167
+ toolbarAriaLabel: () => "Formato",
168
+ unorderedListAria: () => "Lista no ordenada"
169
+ },
152
170
  search: {
153
171
  searchButtonText: () => "Buscar"
154
172
  },
@@ -149,6 +149,24 @@ const frCA = {
149
149
  pod: {
150
150
  undo: () => "Annuler"
151
151
  },
152
+ textEditor: {
153
+ boldAria: () => "Gras",
154
+ cancelButton: () => "Annuler",
155
+ cancelButtonAria: () => "Annuler",
156
+ characterCounter(count) {
157
+ return `${typeof count === "number" ? count.toString() : count} caractères restants`;
158
+ },
159
+ characterLimit(count) {
160
+ return `Vous avez dépassé de ${count} caractères la limite autorisée`;
161
+ },
162
+ contentEditorAria: () => "Éditeur de texte enrichi",
163
+ italicAria: () => "Italique",
164
+ orderedListAria: () => "Liste ordonnée",
165
+ saveButton: () => "Enregistrer",
166
+ saveButtonAria: () => "Enregistrer",
167
+ toolbarAriaLabel: () => "Mise en forme",
168
+ unorderedListAria: () => "Liste non ordonnée"
169
+ },
152
170
  search: {
153
171
  searchButtonText: () => "Chercher"
154
172
  },
@@ -149,6 +149,24 @@ const frFR = {
149
149
  pod: {
150
150
  undo: () => "Annuler"
151
151
  },
152
+ textEditor: {
153
+ boldAria: () => "Gras",
154
+ cancelButton: () => "Annuler",
155
+ cancelButtonAria: () => "Annuler",
156
+ characterCounter(count) {
157
+ return `${typeof count === "number" ? count.toString() : count} caractères restants`;
158
+ },
159
+ characterLimit(count) {
160
+ return `Vous avez dépassé de ${count} caractères la limite autorisée`;
161
+ },
162
+ contentEditorAria: () => "Éditeur de texte enrichi",
163
+ italicAria: () => "Italique",
164
+ orderedListAria: () => "Liste ordonnée",
165
+ saveButton: () => "Enregistrer",
166
+ saveButtonAria: () => "Enregistrer",
167
+ toolbarAriaLabel: () => "Mise en forme",
168
+ unorderedListAria: () => "Liste non ordonnée"
169
+ },
152
170
  search: {
153
171
  searchButtonText: () => "Rechercher"
154
172
  },
@@ -50,8 +50,7 @@ const Note = ({
50
50
  };
51
51
  return /*#__PURE__*/_react.default.createElement(_textEditor.default.Provider, {
52
52
  value: {
53
- onLinkAdded,
54
- readOnly: true
53
+ onLinkAdded
55
54
  }
56
55
  }, /*#__PURE__*/_react.default.createElement(_note.StyledNote, _extends({
57
56
  width: width
@@ -1,7 +1,5 @@
1
1
  import React from "react";
2
2
  export interface ContentEditorProps {
3
- /** The active error message of the editor */
4
- error?: string;
5
3
  /** A hint string rendered before the editor but after the label. Intended to describe the purpose or content of the input. */
6
4
  inputHint?: string;
7
5
  /** The namespace of the editor that this content editor belongs to */
@@ -10,8 +8,8 @@ export interface ContentEditorProps {
10
8
  previews?: React.JSX.Element[];
11
9
  /** The number of rows to render in the editor */
12
10
  rows?: number;
13
- /** The active warning message of the editor */
14
- warning?: string;
11
+ /** Whether the editor is read-only */
12
+ readOnly?: boolean;
15
13
  }
16
- declare const ContentEditor: ({ error, inputHint, namespace, previews, rows, warning, }: ContentEditorProps) => React.JSX.Element;
14
+ declare const ContentEditor: React.ForwardRefExoticComponent<ContentEditorProps & React.RefAttributes<HTMLDivElement>>;
17
15
  export default ContentEditor;
@@ -5,31 +5,32 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _LexicalContentEditable = require("@lexical/react/LexicalContentEditable");
8
- var _react = _interopRequireDefault(require("react"));
8
+ var _react = _interopRequireWildcard(require("react"));
9
9
  var _contentEditor = _interopRequireDefault(require("./content-editor.style"));
10
10
  var _ = require("..");
11
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
13
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
12
14
  /**
13
15
  * This is where the actual content editor is rendered. It uses the `ContentEditable` component from the `@lexical/react` package
14
16
  * as per their documentation. It also uses the `LinkPreviewerPlugin` to render link previews.
15
17
  */
16
18
 
17
- const ContentEditor = ({
18
- error,
19
+ const ContentEditor = /*#__PURE__*/(0, _react.forwardRef)(({
19
20
  inputHint,
20
21
  namespace,
21
22
  previews = [],
22
23
  rows,
23
- warning
24
- }) => {
24
+ readOnly
25
+ }, ref) => {
25
26
  const focusAtEnd = (0, _.useCursorAtEnd)();
26
27
  return /*#__PURE__*/_react.default.createElement(_contentEditor.default, {
27
28
  "data-role": `${namespace}-content-editable`,
28
- error: error,
29
29
  namespace: namespace,
30
30
  rows: rows,
31
- warning: warning
31
+ readOnly: readOnly
32
32
  }, /*#__PURE__*/_react.default.createElement(_LexicalContentEditable.ContentEditable, {
33
+ ref: ref,
33
34
  "aria-describedby": inputHint && `${namespace}-input-hint`,
34
35
  "aria-labelledby": `${namespace}-label`,
35
36
  className: `${namespace}-editable`,
@@ -45,9 +46,7 @@ const ContentEditor = ({
45
46
  "aria-autocomplete": undefined,
46
47
  "aria-readonly": undefined
47
48
  }), /*#__PURE__*/_react.default.createElement(_.LinkPreviewerPlugin, {
48
- error: error,
49
- previews: previews,
50
- warning: warning
49
+ previews: previews
51
50
  }));
52
- };
51
+ });
53
52
  var _default = exports.default = ContentEditor;
@@ -1,6 +1,7 @@
1
1
  import { ContentEditorProps } from "./content-editor.component";
2
2
  interface StyledContentEditableProps extends ContentEditorProps {
3
3
  showBorders?: boolean;
4
+ readOnly?: boolean;
4
5
  }
5
6
  declare const StyledContentEditable: import("styled-components").StyledComponent<"div", any, StyledContentEditableProps, never>;
6
7
  export default StyledContentEditable;
@@ -11,28 +11,22 @@ const DEFAULT_EDITOR_HEIGHT = 210;
11
11
  const FIXED_LINE_HEIGHT = 21;
12
12
  const StyledContentEditable = _styledComponents.default.div`
13
13
  ${({
14
- error,
15
14
  namespace,
16
15
  rows,
17
- warning
16
+ readOnly
18
17
  }) => (0, _styledComponents.css)`
19
18
  .${namespace}-editable {
20
19
  min-height: ${rows && rows > 2 ? rows * FIXED_LINE_HEIGHT : DEFAULT_EDITOR_HEIGHT}px;
21
20
  background-color: var(--colorsUtilityYang100);
22
- border-top: 1px solid var(--colorsUtilityMajor200);
23
- border-left: 1px solid var(--colorsUtilityMajor200);
24
- border-right: 1px solid var(--colorsUtilityMajor200);
21
+ ${!readOnly && "border-top: 1px solid var(--colorsUtilityMajor200);"}
22
+ ${readOnly && `
23
+ border-top-left-radius: var(--borderRadius100);
24
+ border-top-right-radius: var(--borderRadius100);
25
+ `}
25
26
  margin: 0;
26
27
  padding: 2px 8px;
27
- border-top-left-radius: var(--borderWidth600);
28
- border-top-right-radius: var(--borderWidth600);
29
- border-bottom-left-radius: 0;
30
- border-bottom-right-radius: 0;
31
-
32
- ${(error || warning) && (0, _styledComponents.css)`
33
- border: none;
34
- `}
35
-
28
+ border-bottom-right-radius: var(--borderRadius100);
29
+ border-bottom-left-radius: var(--borderRadius100);
36
30
  :focus {
37
31
  outline: none;
38
32
  }
@@ -1,11 +1,5 @@
1
1
  import React from "react";
2
- export interface LinkPreviewerProps {
3
- /** The active error message of the editor */
4
- error?: string;
5
- /** The link previews to render at the foot of the editor */
6
- previews?: React.JSX.Element[];
7
- /** The active warning message of the editor */
8
- warning?: string;
9
- }
10
- declare const LinkPreviewer: ({ error, previews, warning, }: LinkPreviewerProps) => React.JSX.Element;
2
+ declare const LinkPreviewer: ({ previews, }: {
3
+ previews?: React.JSX.Element[] | undefined;
4
+ }) => React.JSX.Element;
11
5
  export default LinkPreviewer;
@@ -4,24 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireWildcard(require("react"));
8
- var _textEditor = _interopRequireDefault(require("../../../text-editor.context"));
7
+ var _react = _interopRequireDefault(require("react"));
9
8
  var _linkPreviewer = _interopRequireDefault(require("./link-previewer.style"));
10
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
12
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
13
10
  const LinkPreviewer = ({
14
- error,
15
- previews = [],
16
- warning
17
- }) => {
18
- const {
19
- readOnly
20
- } = (0, _react.useContext)(_textEditor.default);
21
- return /*#__PURE__*/_react.default.createElement(_linkPreviewer.default, {
22
- error: error,
23
- readOnly: readOnly,
24
- warning: warning
25
- }, previews);
26
- };
11
+ previews = []
12
+ }) => /*#__PURE__*/_react.default.createElement(_linkPreviewer.default, null, previews);
27
13
  var _default = exports.default = LinkPreviewer;
@@ -1,6 +1,2 @@
1
- import { LinkPreviewerProps } from "./link-previewer.component";
2
- interface StyledLinkPreviewerProps extends LinkPreviewerProps {
3
- readOnly?: boolean;
4
- }
5
- declare const StyledLinkPreviewer: import("styled-components").StyledComponent<"div", any, StyledLinkPreviewerProps, never>;
1
+ declare const StyledLinkPreviewer: import("styled-components").StyledComponent<"div", any, {}, never>;
6
2
  export default StyledLinkPreviewer;
@@ -4,34 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _styledComponents = _interopRequireWildcard(require("styled-components"));
8
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
9
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
7
+ var _styledComponents = _interopRequireDefault(require("styled-components"));
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
9
  const StyledLinkPreviewer = _styledComponents.default.div`
11
- ${({
12
- error,
13
- readOnly,
14
- warning
15
- }) => (0, _styledComponents.css)`
16
- border-bottom-left-radius: 0;
17
- border-bottom-right-radius: 0;
18
- background-color: var(--colorsUtilityYang100);
19
- border-bottom: 1px solid var(--colorsUtilityMajor200);
20
- border-left: 1px solid var(--colorsUtilityMajor200);
21
- border-right: 1px solid var(--colorsUtilityMajor200);
22
- margin: 0;
23
- padding: 2px 8px;
24
-
25
- ${(error || warning) && (0, _styledComponents.css)`
26
- border-left: none;
27
- border-right: none;
28
- border-bottom: none;
29
- `}
30
-
31
- ${readOnly && (0, _styledComponents.css)`
32
- border-bottom-left-radius: var(--borderWidth600);
33
- border-bottom-right-radius: var(--borderWidth600);
34
- `}
35
- `}
10
+ margin: 0;
11
+ padding: 2px 8px;
36
12
  `;
37
13
  var _default = exports.default = StyledLinkPreviewer;
@@ -3,10 +3,12 @@ import { EditorFormattedValues } from "./buttons/save.component";
3
3
  interface ToolbarProps {
4
4
  /** The namespace of the editor that this toolbar belongs to */
5
5
  namespace: string;
6
+ /** Determines if the Text Editor has a header */
7
+ hasHeader?: boolean;
6
8
  /** The callback to call when the cancel button is clicked */
7
9
  onCancel?: () => void;
8
10
  /** The callback to call when the save button is clicked */
9
11
  onSave?: (value: EditorFormattedValues) => void;
10
12
  }
11
- declare const Toolbar: ({ namespace, onCancel, onSave }: ToolbarProps) => React.JSX.Element;
13
+ declare const Toolbar: ({ namespace, hasHeader, onCancel, onSave }: ToolbarProps) => React.JSX.Element;
12
14
  export default Toolbar;
@@ -19,6 +19,7 @@ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return
19
19
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
20
20
  const Toolbar = ({
21
21
  namespace,
22
+ hasHeader,
22
23
  onCancel,
23
24
  onSave
24
25
  }) => {
@@ -89,6 +90,7 @@ const Toolbar = ({
89
90
  }, [buttons]);
90
91
  return /*#__PURE__*/_react.default.createElement(_toolbar.StyledToolbar, {
91
92
  role: "toolbar",
93
+ hasHeader: hasHeader,
92
94
  "aria-label": locale.textEditor.toolbarAriaLabel(),
93
95
  "data-role": `${namespace}-toolbar`,
94
96
  id: `${namespace}-toolbar`,
@@ -4,7 +4,9 @@ interface FormattingButtonProps extends ButtonProps {
4
4
  tabIndex?: number;
5
5
  isActive?: boolean;
6
6
  }
7
- declare const StyledToolbar: import("styled-components").StyledComponent<"div", any, {}, never>;
7
+ declare const StyledToolbar: import("styled-components").StyledComponent<"div", any, {
8
+ hasHeader?: boolean | undefined;
9
+ }, never>;
8
10
  declare const FormattingButtons: import("styled-components").StyledComponent<"div", any, {}, never>;
9
11
  declare const CommandButtons: import("styled-components").StyledComponent<"div", any, {}, never>;
10
12
  declare const FormattingButton: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLAnchorElement | HTMLButtonElement>>, any, FormattingButtonProps, never>;
@@ -13,12 +13,16 @@ const StyledToolbar = exports.StyledToolbar = _styledComponents.default.div`
13
13
  display: flex;
14
14
  flex-direction: row;
15
15
  gap: 8px;
16
- background-color: var(--colorsUtilityMajor025);
17
- outline: 1px solid var(--colorsUtilityMajor200);
16
+ background-color: var(--colorsActionMajorYang100);
18
17
  padding: 12px;
19
- border-radius: var(--borderRadius100);
20
- border-top-left-radius: 0;
21
- border-top-right-radius: 0;
18
+ border-top-left-radius: ${({
19
+ hasHeader
20
+ }) => hasHeader ? "0" : "var(--borderRadius100)"};
21
+ border-top-right-radius: ${({
22
+ hasHeader
23
+ }) => hasHeader ? "0" : "var(--borderRadius100)"};
24
+ border-bottom-left-radius: 0;
25
+ border-bottom-right-radius: 0;
22
26
  justify-content: space-between;
23
27
  align-items: center;
24
28
  margin-left: 1px;
@@ -8,6 +8,10 @@ export interface TextEditorProps extends MarginProps, TagProps {
8
8
  characterLimit?: number;
9
9
  /** The message to be shown when the editor is in an error state */
10
10
  error?: string;
11
+ /** Custom footer content to be displayed below the editor */
12
+ footer?: React.ReactNode;
13
+ /** Custom header content to be displayed above the editor */
14
+ header?: React.ReactNode;
11
15
  /** A hint string rendered before the editor but after the label. Intended to describe the purpose or content of the input. */
12
16
  inputHint?: string;
13
17
  /** Whether the content of the editor can be empty */
@@ -39,5 +43,5 @@ export interface TextEditorProps extends MarginProps, TagProps {
39
43
  /** The initial value of the editor, as a HTML string, or JSON */
40
44
  value?: string | undefined;
41
45
  }
42
- export declare const TextEditor: ({ characterLimit, error, inputHint, isOptional, labelText, namespace, onCancel, onChange, onLinkAdded, onSave, placeholder, previews, readOnly, required, rows, warning, value, ...rest }: TextEditorProps) => React.JSX.Element;
46
+ 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;
43
47
  export default TextEditor;
@@ -34,6 +34,8 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
34
34
  const TextEditor = ({
35
35
  characterLimit = 3000,
36
36
  error,
37
+ footer,
38
+ header,
37
39
  inputHint,
38
40
  isOptional = false,
39
41
  labelText,
@@ -54,7 +56,25 @@ const TextEditor = ({
54
56
  const editorRef = (0, _react.useRef)(undefined);
55
57
  const locale = (0, _useLocale.default)();
56
58
  const [characterLimitWarning, setCharacterLimitWarning] = (0, _react.useState)(undefined);
59
+ const hasWarningOrError = Boolean(error || characterLimitWarning || warning);
60
+ const contentEditorRef = (0, _react.useRef)(null);
57
61
  const [isFocused, setIsFocused] = (0, _react.useState)(false);
62
+ (0, _react.useEffect)(() => {
63
+ const editorElement = contentEditorRef?.current;
64
+ const handleFocus = () => {
65
+ setIsFocused(true);
66
+ };
67
+ const handleBlur = () => {
68
+ setIsFocused(false);
69
+ };
70
+ editorElement?.addEventListener("focus", handleFocus);
71
+ editorElement?.addEventListener("blur", handleBlur);
72
+ const cleanup = () => {
73
+ editorElement?.removeEventListener("focus", handleFocus);
74
+ editorElement?.removeEventListener("blur", handleBlur);
75
+ };
76
+ return cleanup;
77
+ }, [contentEditorRef]);
58
78
  const [cancelTrigger, setCancelTrigger] = (0, _react.useState)(false);
59
79
  const debounceWaitTime = 500;
60
80
  const initialConfig = (0, _react.useMemo)(() => {
@@ -118,8 +138,7 @@ const TextEditor = ({
118
138
  "data-role": `${namespace}-editor-wrapper`
119
139
  }, (0, _utils2.filterStyledSystemMarginProps)(rest), (0, _tags.default)("text-editor", rest)), /*#__PURE__*/_react.default.createElement(_textEditor.default.Provider, {
120
140
  value: {
121
- onLinkAdded,
122
- readOnly
141
+ onLinkAdded
123
142
  }
124
143
  }, /*#__PURE__*/_react.default.createElement(_label.default, {
125
144
  isRequired: required,
@@ -143,19 +162,22 @@ const TextEditor = ({
143
162
  }, error || characterLimitWarning || warning), /*#__PURE__*/_react.default.createElement(_textEditor2.StyledEditorToolbarWrapper, {
144
163
  "data-role": `${namespace}-editor-toolbar-wrapper`,
145
164
  id: `${namespace}-editor-toolbar-wrapper`,
146
- onBlur: () => setIsFocused(false),
147
- onFocus: () => setIsFocused(true),
148
- focused: isFocused
149
- }, /*#__PURE__*/_react.default.createElement(_textEditor2.default, {
165
+ focused: isFocused,
166
+ hasWarningOrError: hasWarningOrError
167
+ }, header && /*#__PURE__*/_react.default.createElement(_textEditor2.StyledHeaderWrapper, {
168
+ "data-role": `${namespace}-header-wrapper`
169
+ }, header), !readOnly && /*#__PURE__*/_react.default.createElement(_plugins.ToolbarPlugin, _extends({
170
+ hasHeader: Boolean(header)
171
+ }, toolbarProps)), /*#__PURE__*/_react.default.createElement(_textEditor2.default, {
150
172
  "data-role": `${namespace}-editor`
151
173
  }, /*#__PURE__*/_react.default.createElement(_LexicalRichTextPlugin.RichTextPlugin, {
152
174
  contentEditable: /*#__PURE__*/_react.default.createElement(_plugins.ContentEditor, {
153
- error: error,
175
+ ref: contentEditorRef,
154
176
  inputHint: inputHint,
155
177
  namespace: namespace,
156
178
  previews: previews,
157
179
  rows: rows,
158
- warning: warning
180
+ readOnly: readOnly
159
181
  }),
160
182
  placeholder: /*#__PURE__*/_react.default.createElement(_plugins.Placeholder, {
161
183
  namespace: namespace,
@@ -168,7 +190,9 @@ const TextEditor = ({
168
190
  validateUrl: _helpers.validateUrl
169
191
  }), /*#__PURE__*/_react.default.createElement(_LexicalClickableLinkPlugin.ClickableLinkPlugin, {
170
192
  newTab: true
171
- }), /*#__PURE__*/_react.default.createElement(_plugins.AutoLinkerPlugin, null)), !readOnly && /*#__PURE__*/_react.default.createElement(_plugins.ToolbarPlugin, toolbarProps), /*#__PURE__*/_react.default.createElement(_plugins.LinkMonitorPlugin, null)), characterLimit > 0 && !readOnly && /*#__PURE__*/_react.default.createElement(_plugins.CharacterCounterPlugin, {
193
+ }), /*#__PURE__*/_react.default.createElement(_plugins.AutoLinkerPlugin, null)), footer && /*#__PURE__*/_react.default.createElement(_textEditor2.StyledFooterWrapper, {
194
+ "data-role": `${namespace}-footer-wrapper`
195
+ }, footer), /*#__PURE__*/_react.default.createElement(_plugins.LinkMonitorPlugin, null)), characterLimit > 0 && !readOnly && /*#__PURE__*/_react.default.createElement(_plugins.CharacterCounterPlugin, {
172
196
  maxChars: characterLimit,
173
197
  namespace: namespace
174
198
  })))));
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  declare const _default: React.Context<{
3
3
  onLinkAdded?: ((link: string, state: string) => void) | undefined;
4
- readOnly?: boolean | undefined;
5
4
  }>;
6
5
  export default _default;
@@ -11,10 +11,13 @@ interface StyledValidationMessageProps {
11
11
  }
12
12
  interface StyledEditorToolbarWrapperProps {
13
13
  focused?: boolean;
14
+ hasWarningOrError?: boolean;
14
15
  }
15
16
  export declare const StyledTextEditor: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("../box").BoxProps & import("react").RefAttributes<HTMLDivElement>>, any, {}, never>;
16
17
  export declare const StyledTextEditorWrapper: import("styled-components").StyledComponent<"div", any, StyledTextEditorWrapperProps, never>;
17
18
  export declare const StyledWrapper: import("styled-components").StyledComponent<"div", any, StyledWrapperProps, never>;
18
19
  export declare const StyledEditorToolbarWrapper: import("styled-components").StyledComponent<"div", any, StyledEditorToolbarWrapperProps, never>;
20
+ export declare const StyledHeaderWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
21
+ export declare const StyledFooterWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
19
22
  export declare const StyledValidationMessage: import("styled-components").StyledComponent<"div", any, StyledValidationMessageProps, never>;
20
23
  export default StyledTextEditor;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = exports.StyledWrapper = exports.StyledValidationMessage = exports.StyledTextEditorWrapper = exports.StyledTextEditor = exports.StyledEditorToolbarWrapper = void 0;
6
+ exports.default = exports.StyledWrapper = exports.StyledValidationMessage = exports.StyledTextEditorWrapper = exports.StyledTextEditor = exports.StyledHeaderWrapper = exports.StyledFooterWrapper = exports.StyledEditorToolbarWrapper = void 0;
7
7
  var _styledComponents = _interopRequireWildcard(require("styled-components"));
8
8
  var _styledSystem = require("styled-system");
9
9
  var _box = _interopRequireDefault(require("../box"));
@@ -44,24 +44,28 @@ const StyledWrapper = exports.StyledWrapper = _styledComponents.default.div`
44
44
  .${namespace}-editable, #${namespace}-toolbar {
45
45
  outline: none;
46
46
  }
47
-
48
- #${namespace}-toolbar {
49
- border-top: 1px solid var(--colorsUtilityMajor200);
50
- }
51
47
  }
52
48
  `}
53
49
  `};
54
50
  `;
55
51
  const StyledEditorToolbarWrapper = exports.StyledEditorToolbarWrapper = _styledComponents.default.div`
56
52
  ${({
57
- focused
53
+ focused,
54
+ hasWarningOrError
58
55
  }) => (0, _styledComponents.css)`
59
56
  border-radius: var(--borderRadius100);
60
- outline: none;
57
+ outline: ${hasWarningOrError ? "none" : "1px solid var(--colorsUtilityMajor200)"};
61
58
 
62
59
  ${focused && (0, _addFocusStyling.default)()}
63
60
  `}
64
61
  `;
62
+ const StyledHeaderWrapper = exports.StyledHeaderWrapper = _styledComponents.default.div`
63
+ padding: var(--spacing200);
64
+ `;
65
+ const StyledFooterWrapper = exports.StyledFooterWrapper = _styledComponents.default.div`
66
+ border-top: 1px solid var(--colorsUtilityMajor200);
67
+ padding: var(--spacing200);
68
+ `;
65
69
  const StyledValidationMessage = exports.StyledValidationMessage = _styledComponents.default.div`
66
70
  ${({
67
71
  error
@@ -154,6 +154,24 @@ const deDE = {
154
154
  pod: {
155
155
  undo: () => "Rückgängig"
156
156
  },
157
+ textEditor: {
158
+ boldAria: () => "Fett",
159
+ cancelButton: () => "Abbrechen",
160
+ cancelButtonAria: () => "Abbrechen",
161
+ characterCounter(count) {
162
+ return `Noch ${typeof count === "number" ? count.toString() : count} Zeichen`;
163
+ },
164
+ characterLimit(count) {
165
+ return `Sie sind ${count} Zeichen über dem Zeichenlimit`;
166
+ },
167
+ contentEditorAria: () => "Editor für Rich-Text-Inhalte",
168
+ italicAria: () => "Kursiv",
169
+ orderedListAria: () => "Sortierte Liste",
170
+ saveButton: () => "Speichern",
171
+ saveButtonAria: () => "Speichern",
172
+ toolbarAriaLabel: () => "Formatierung",
173
+ unorderedListAria: () => "Unsortierte Liste"
174
+ },
157
175
  search: {
158
176
  searchButtonText: () => "Suchen"
159
177
  },
@@ -155,6 +155,24 @@ const esES = {
155
155
  pod: {
156
156
  undo: () => "Deshacer"
157
157
  },
158
+ textEditor: {
159
+ boldAria: () => "Negrita",
160
+ cancelButton: () => "Cancelar",
161
+ cancelButtonAria: () => "Cancelar",
162
+ characterCounter(count) {
163
+ return `Quedan ${typeof count === "number" ? count.toString() : count} caracteres`;
164
+ },
165
+ characterLimit(count) {
166
+ return `El límite de ${count} caracteres se ha superado.`;
167
+ },
168
+ contentEditorAria: () => "Editor de contenidos de texto enriquecido",
169
+ italicAria: () => "Cursiva",
170
+ orderedListAria: () => "Lista ordenada",
171
+ saveButton: () => "Guardar",
172
+ saveButtonAria: () => "Guardar",
173
+ toolbarAriaLabel: () => "Formato",
174
+ unorderedListAria: () => "Lista no ordenada"
175
+ },
158
176
  search: {
159
177
  searchButtonText: () => "Buscar"
160
178
  },
@@ -155,6 +155,24 @@ const frCA = {
155
155
  pod: {
156
156
  undo: () => "Annuler"
157
157
  },
158
+ textEditor: {
159
+ boldAria: () => "Gras",
160
+ cancelButton: () => "Annuler",
161
+ cancelButtonAria: () => "Annuler",
162
+ characterCounter(count) {
163
+ return `${typeof count === "number" ? count.toString() : count} caractères restants`;
164
+ },
165
+ characterLimit(count) {
166
+ return `Vous avez dépassé de ${count} caractères la limite autorisée`;
167
+ },
168
+ contentEditorAria: () => "Éditeur de texte enrichi",
169
+ italicAria: () => "Italique",
170
+ orderedListAria: () => "Liste ordonnée",
171
+ saveButton: () => "Enregistrer",
172
+ saveButtonAria: () => "Enregistrer",
173
+ toolbarAriaLabel: () => "Mise en forme",
174
+ unorderedListAria: () => "Liste non ordonnée"
175
+ },
158
176
  search: {
159
177
  searchButtonText: () => "Chercher"
160
178
  },
@@ -155,6 +155,24 @@ const frFR = {
155
155
  pod: {
156
156
  undo: () => "Annuler"
157
157
  },
158
+ textEditor: {
159
+ boldAria: () => "Gras",
160
+ cancelButton: () => "Annuler",
161
+ cancelButtonAria: () => "Annuler",
162
+ characterCounter(count) {
163
+ return `${typeof count === "number" ? count.toString() : count} caractères restants`;
164
+ },
165
+ characterLimit(count) {
166
+ return `Vous avez dépassé de ${count} caractères la limite autorisée`;
167
+ },
168
+ contentEditorAria: () => "Éditeur de texte enrichi",
169
+ italicAria: () => "Italique",
170
+ orderedListAria: () => "Liste ordonnée",
171
+ saveButton: () => "Enregistrer",
172
+ saveButtonAria: () => "Enregistrer",
173
+ toolbarAriaLabel: () => "Mise en forme",
174
+ unorderedListAria: () => "Liste non ordonnée"
175
+ },
158
176
  search: {
159
177
  searchButtonText: () => "Rechercher"
160
178
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "153.3.1",
3
+ "version": "153.4.0",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",