Skip to content

Commit 97d7563

Browse files
authored
Update RichTextEditor to be a forwardRef and expose setContent through useImperativeHandle (#1173)
1 parent d213c7c commit 97d7563

File tree

3 files changed

+57
-19
lines changed

3 files changed

+57
-19
lines changed

src/RichTextEditor/RichTextEditor.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as ComponentStories from './RichTextEditor.stories';
1010

1111
<Canvas of={ComponentStories.Default} />
1212

13-
### When to use
13+
### When to use
1414
To allow users to edit text where formatting is important, such as messages to be sent via email.
1515

1616
### When to not use
@@ -45,3 +45,7 @@ RichTextEditor also has an error state to display that the input is invalid. The
4545
but by setting `hasErrors` via your provided `onChange` callback you can check the HTML produced by the RichTextEditor for any requirements that you have.
4646

4747
<Canvas of={ComponentStories.Error} />
48+
49+
RichTextEditor can optionally take in a forwardedRef to allow content to be programmatically manipulated.
50+
51+
<Canvas of={ComponentStories.SetContent} />

src/RichTextEditor/RichTextEditor.stories.jsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React from 'react';
1+
import React, { useRef } from 'react';
22

3+
import Button from 'src/Button';
34
import { RichTextEditor, RichTextEditorActions } from 'src/RichTextEditor';
45

56
import mdx from './RichTextEditor.mdx';
@@ -60,3 +61,22 @@ export const Error = () => (
6061
onChange={() => null}
6162
/>
6263
);
64+
65+
export const SetContent = () => {
66+
const ref = useRef(null);
67+
68+
const handleClick = () => {
69+
ref.current.setContent('Oh hey');
70+
};
71+
72+
return (
73+
<>
74+
<Button onClick={handleClick}>Set content to "Oh hey"</Button>
75+
<RichTextEditor
76+
id="text-editor"
77+
ref={ref}
78+
onChange={() => null}
79+
/>
80+
</>
81+
);
82+
};

src/RichTextEditor/RichTextEditor.tsx

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Extension, Node as TipTapNode, Mark } from '@tiptap/core';
44

55
import './RichTextEditor.scss';
66

7-
import React from 'react';
7+
import React, { forwardRef, type ForwardedRef, useImperativeHandle } from 'react';
88

99
import classNames from 'classnames';
1010

@@ -94,21 +94,28 @@ export type RichTextEditorProps = {
9494
onChange: (arg0: string) => void;
9595
}
9696

97-
function RichTextEditor({
98-
allowedAttributes,
99-
allowedTags,
100-
ariaAttributes,
101-
availableActions = RichTextEditorDefaultActionsArray,
102-
characterLimit,
103-
className,
104-
hasErrors,
105-
id,
106-
initialValue,
107-
isOneLine,
108-
onChange,
109-
placeholder,
110-
customExtensions = [],
111-
}: RichTextEditorProps) {
97+
export type RichTextEditorRef = {
98+
setContent: (content: string) => void;
99+
}
100+
101+
const RichTextEditor = forwardRef((
102+
{
103+
allowedAttributes,
104+
allowedTags,
105+
ariaAttributes,
106+
availableActions = RichTextEditorDefaultActionsArray,
107+
characterLimit,
108+
className,
109+
hasErrors,
110+
id,
111+
initialValue,
112+
isOneLine,
113+
onChange,
114+
placeholder,
115+
customExtensions = [],
116+
}: RichTextEditorProps,
117+
ref: ForwardedRef<RichTextEditorRef> = null,
118+
) => {
112119
const oneLineExtension = isOneLine ? [OneLineLimit] : [];
113120

114121
const requiredExtensions = [
@@ -183,6 +190,13 @@ function RichTextEditor({
183190
},
184191
});
185192

193+
useImperativeHandle(ref, () => ({
194+
setContent: (content: string) => {
195+
editor?.commands.setContent(content);
196+
onChange(content);
197+
},
198+
}));
199+
186200
return (
187201
editor ? (
188202
<div
@@ -221,7 +235,7 @@ function RichTextEditor({
221235
</>
222236
)
223237
);
224-
}
238+
});
225239

226240
// eslint-disable-next-line import/no-default-export
227241
export default RichTextEditor;

0 commit comments

Comments
 (0)