carbon-react 153.3.1 → 153.5.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 (67) hide show
  1. package/esm/__internal__/fieldset/fieldset.component.js +4 -0
  2. package/esm/__internal__/fieldset/fieldset.style.d.ts +1 -0
  3. package/esm/__internal__/fieldset/fieldset.style.js +3 -2
  4. package/esm/__internal__/label/label.component.js +5 -1
  5. package/esm/__internal__/label/label.style.d.ts +2 -0
  6. package/esm/__internal__/label/label.style.js +3 -2
  7. package/esm/components/fieldset/fieldset.component.js +5 -1
  8. package/esm/components/fieldset/fieldset.style.d.ts +2 -0
  9. package/esm/components/fieldset/fieldset.style.js +3 -2
  10. package/esm/components/note/note.component.js +1 -2
  11. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.d.ts +3 -5
  12. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.js +8 -11
  13. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.d.ts +1 -0
  14. package/esm/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.js +8 -14
  15. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.d.ts +3 -9
  16. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.js +3 -15
  17. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.d.ts +1 -5
  18. package/esm/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.js +3 -26
  19. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.d.ts +3 -1
  20. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.js +2 -0
  21. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.d.ts +3 -1
  22. package/esm/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.js +9 -5
  23. package/esm/components/text-editor/text-editor.component.d.ts +5 -1
  24. package/esm/components/text-editor/text-editor.component.js +34 -10
  25. package/esm/components/text-editor/text-editor.context.d.ts +0 -1
  26. package/esm/components/text-editor/text-editor.style.d.ts +3 -0
  27. package/esm/components/text-editor/text-editor.style.js +10 -6
  28. package/esm/locales/de-de.js +21 -0
  29. package/esm/locales/en-gb.js +3 -0
  30. package/esm/locales/es-es.js +21 -0
  31. package/esm/locales/fr-ca.js +21 -0
  32. package/esm/locales/fr-fr.js +21 -0
  33. package/esm/locales/locale.d.ts +3 -0
  34. package/lib/__internal__/fieldset/fieldset.component.js +4 -0
  35. package/lib/__internal__/fieldset/fieldset.style.d.ts +1 -0
  36. package/lib/__internal__/fieldset/fieldset.style.js +3 -2
  37. package/lib/__internal__/label/label.component.js +5 -1
  38. package/lib/__internal__/label/label.style.d.ts +2 -0
  39. package/lib/__internal__/label/label.style.js +3 -2
  40. package/lib/components/fieldset/fieldset.component.js +5 -1
  41. package/lib/components/fieldset/fieldset.style.d.ts +2 -0
  42. package/lib/components/fieldset/fieldset.style.js +3 -2
  43. package/lib/components/note/note.component.js +1 -2
  44. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.d.ts +3 -5
  45. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.component.js +10 -11
  46. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.d.ts +1 -0
  47. package/lib/components/text-editor/__internal__/plugins/ContentEditor/content-editor.style.js +8 -14
  48. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.d.ts +3 -9
  49. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.component.js +3 -17
  50. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.d.ts +1 -5
  51. package/lib/components/text-editor/__internal__/plugins/LinkPreviewer/link-previewer.style.js +4 -28
  52. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.d.ts +3 -1
  53. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.component.js +2 -0
  54. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.d.ts +3 -1
  55. package/lib/components/text-editor/__internal__/plugins/Toolbar/toolbar.style.js +9 -5
  56. package/lib/components/text-editor/text-editor.component.d.ts +5 -1
  57. package/lib/components/text-editor/text-editor.component.js +33 -9
  58. package/lib/components/text-editor/text-editor.context.d.ts +0 -1
  59. package/lib/components/text-editor/text-editor.style.d.ts +3 -0
  60. package/lib/components/text-editor/text-editor.style.js +11 -7
  61. package/lib/locales/de-de.js +21 -0
  62. package/lib/locales/en-gb.js +3 -0
  63. package/lib/locales/es-es.js +21 -0
  64. package/lib/locales/fr-ca.js +21 -0
  65. package/lib/locales/fr-fr.js +21 -0
  66. package/lib/locales/locale.d.ts +3 -0
  67. package/package.json +1 -1
@@ -7,6 +7,7 @@ import { InputGroupBehaviour, InputGroupContext } from "../input-behaviour";
7
7
  import Help from "../../components/help";
8
8
  import Typography from "../../components/typography";
9
9
  import { filterStyledSystemMarginProps } from "../../style/utils";
10
+ import useLocale from "../../hooks/__internal__/useLocale";
10
11
  const Fieldset = ({
11
12
  legend,
12
13
  children,
@@ -32,6 +33,8 @@ const Fieldset = ({
32
33
  const marginProps = filterStyledSystemMarginProps(rest);
33
34
  const [ref, setRef] = useState(null);
34
35
  const [isFocused, setFocus] = useState(false);
36
+ const locale = useLocale();
37
+ const optionalLabel = locale.label.optional();
35
38
  useEffect(() => {
36
39
  if (ref && isRequired) {
37
40
  Array.from(ref.querySelectorAll("input") || /* istanbul ignore next */[]).forEach(el => {
@@ -90,6 +93,7 @@ const Fieldset = ({
90
93
  }), /*#__PURE__*/React.createElement(StyledLegendContent, {
91
94
  isRequired: isRequired,
92
95
  isOptional: isOptional,
96
+ optionalLabel: optionalLabel,
93
97
  isDisabled: isDisabled
94
98
  }, legend, !validationRedesignOptIn && tooltipIcon()))), !validationRedesignOptIn && /*#__PURE__*/React.createElement(Typography, {
95
99
  screenReaderOnly: true,
@@ -6,6 +6,7 @@ type StyledLegendContentProps = {
6
6
  isRequired?: boolean;
7
7
  isOptional?: boolean;
8
8
  isDisabled?: boolean;
9
+ optionalLabel?: string;
9
10
  };
10
11
  declare const StyledLegendContent: import("styled-components").StyledComponent<"span", any, StyledLegendContentProps, never>;
11
12
  export type StyledLegendProps = {
@@ -35,10 +35,11 @@ const StyledLegendContent = styled.span`
35
35
  `}
36
36
 
37
37
  ${({
38
- isOptional
38
+ isOptional,
39
+ optionalLabel
39
40
  }) => isOptional && css`
40
41
  ::after {
41
- content: "(optional)";
42
+ content: "(${optionalLabel})";
42
43
  color: var(--colorsUtilityYin055);
43
44
  font-weight: var(--fontWeights400);
44
45
  margin-left: var(--spacing050);
@@ -6,6 +6,7 @@ import ValidationIcon from "../validations/validation-icon.component";
6
6
  import StyledIconWrapper from "./icon-wrapper.style";
7
7
  import { InputContext, InputGroupContext } from "../input-behaviour";
8
8
  import createGuid from "../../__internal__/utils/helpers/guid";
9
+ import useLocale from "../../hooks/__internal__/useLocale";
9
10
  const shouldDisplayValidationIcon = ({
10
11
  error,
11
12
  warning,
@@ -58,6 +59,8 @@ export const Label = ({
58
59
  onMouseLeave: onGroupMouseLeave
59
60
  } = useContext(InputGroupContext);
60
61
  const guid = useRef(createGuid());
62
+ const locale = useLocale();
63
+ const optionalLabel = locale.label.optional();
61
64
  const handleMouseEnter = () => {
62
65
  if (onMouseEnter) onMouseEnter();
63
66
  if (onGroupMouseEnter) onGroupMouseEnter();
@@ -115,7 +118,8 @@ export const Label = ({
115
118
  optional: optional,
116
119
  pr: pr,
117
120
  pl: pl,
118
- className: className
121
+ className: className,
122
+ optionalLabel: optionalLabel
119
123
  }, /*#__PURE__*/React.createElement(StyledLabel, _extends({
120
124
  "data-element": "label",
121
125
  disabled: disabled,
@@ -20,6 +20,8 @@ export interface StyledLabelContainerProps {
20
20
  pl?: 1 | 2;
21
21
  /** Label width */
22
22
  width?: number;
23
+ /** Text used for the optional label */
24
+ optionalLabel?: string;
23
25
  }
24
26
  export declare const StyledLabelContainer: import("styled-components").StyledComponent<"div", any, StyledLabelContainerProps, never>;
25
27
  export default StyledLabel;
@@ -54,10 +54,11 @@ export const StyledLabelContainer = styled.div`
54
54
  `}
55
55
 
56
56
  ${({
57
- optional
57
+ optional,
58
+ optionalLabel
58
59
  }) => optional && css`
59
60
  ::after {
60
- content: "(optional)";
61
+ content: "(${optionalLabel})";
61
62
  font-weight: var(--fontWeights400);
62
63
  margin-left: var(--spacing050);
63
64
  color: var(--colorsUtilityYin055);
@@ -4,6 +4,7 @@ import tagComponent from "../../__internal__/utils/helpers/tags";
4
4
  import { FieldsetStyle, StyledLegend } from "./fieldset.style";
5
5
  import NewValidationContext from "../carbon-provider/__internal__/new-validation.context";
6
6
  import { filterStyledSystemMarginProps } from "../../style/utils";
7
+ import useLocale from "../../hooks/__internal__/useLocale";
7
8
  export const Fieldset = ({
8
9
  children,
9
10
  legend,
@@ -16,6 +17,8 @@ export const Fieldset = ({
16
17
  const {
17
18
  validationRedesignOptIn
18
19
  } = useContext(NewValidationContext);
20
+ const locale = useLocale();
21
+ const optionalLabel = locale.label.optional();
19
22
  useEffect(() => {
20
23
  if (ref && required) {
21
24
  Array.from(ref.querySelectorAll("input") || /* istanbul ignore next */[]).forEach(el => {
@@ -29,7 +32,8 @@ export const Fieldset = ({
29
32
  }, rest, marginProps, tagComponent("fieldset", rest)), legend && /*#__PURE__*/React.createElement(StyledLegend, {
30
33
  "data-element": "legend",
31
34
  isRequired: required,
32
- isOptional: isOptional
35
+ isOptional: isOptional,
36
+ optionalLabel: optionalLabel
33
37
  }, legend), children);
34
38
  };
35
39
  Fieldset.displayName = "Fieldset";
@@ -7,6 +7,8 @@ export interface StyledLegendProps {
7
7
  isRequired?: boolean;
8
8
  /** Flag to configure fields as optional. */
9
9
  isOptional?: boolean;
10
+ /** Text used for the optional label */
11
+ optionalLabel?: string;
10
12
  }
11
13
  declare const StyledLegend: import("styled-components").StyledComponent<"legend", any, StyledLegendProps, never>;
12
14
  export { FieldsetStyle, StyledLegend };
@@ -56,10 +56,11 @@ const StyledLegend = styled.legend`
56
56
  `}
57
57
 
58
58
  ${({
59
- isOptional
59
+ isOptional,
60
+ optionalLabel
60
61
  }) => isOptional && css`
61
62
  ::after {
62
- content: "(optional)";
63
+ content: "(${optionalLabel})";
63
64
  color: var(--colorsUtilityYin055);
64
65
  font-weight: var(--fontWeights400);
65
66
  margin-left: var(--spacing050);
@@ -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
@@ -82,6 +82,9 @@ const deDE = {
82
82
  heading: {
83
83
  backLinkAriaLabel: () => "Zurück"
84
84
  },
85
+ label: {
86
+ optional: () => "optional"
87
+ },
85
88
  link: {
86
89
  skipLinkLabel: () => "Zum Hauptinhalt springen"
87
90
  },
@@ -148,6 +151,24 @@ const deDE = {
148
151
  pod: {
149
152
  undo: () => "Rückgängig"
150
153
  },
154
+ textEditor: {
155
+ boldAria: () => "Fett",
156
+ cancelButton: () => "Abbrechen",
157
+ cancelButtonAria: () => "Abbrechen",
158
+ characterCounter(count) {
159
+ return `Noch ${typeof count === "number" ? count.toString() : count} Zeichen`;
160
+ },
161
+ characterLimit(count) {
162
+ return `Sie sind ${count} Zeichen über dem Zeichenlimit`;
163
+ },
164
+ contentEditorAria: () => "Editor für Rich-Text-Inhalte",
165
+ italicAria: () => "Kursiv",
166
+ orderedListAria: () => "Sortierte Liste",
167
+ saveButton: () => "Speichern",
168
+ saveButtonAria: () => "Speichern",
169
+ toolbarAriaLabel: () => "Formatierung",
170
+ unorderedListAria: () => "Unsortierte Liste"
171
+ },
151
172
  search: {
152
173
  searchButtonText: () => "Suchen"
153
174
  },
@@ -86,6 +86,9 @@ const enGB = {
86
86
  heading: {
87
87
  backLinkAriaLabel: () => "Back"
88
88
  },
89
+ label: {
90
+ optional: () => "optional"
91
+ },
89
92
  link: {
90
93
  skipLinkLabel: () => "Skip to main content"
91
94
  },