From 97d7563ed41b1c99ff7015616dcd762054a87399 Mon Sep 17 00:00:00 2001 From: Eric Xian Date: Wed, 27 Mar 2024 06:17:15 -0700 Subject: [PATCH] Update RichTextEditor to be a forwardRef and expose setContent through useImperativeHandle (#1173) --- src/RichTextEditor/RichTextEditor.mdx | 6 ++- src/RichTextEditor/RichTextEditor.stories.jsx | 22 ++++++++- src/RichTextEditor/RichTextEditor.tsx | 48 ++++++++++++------- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/RichTextEditor/RichTextEditor.mdx b/src/RichTextEditor/RichTextEditor.mdx index a1a74156..92459a8b 100644 --- a/src/RichTextEditor/RichTextEditor.mdx +++ b/src/RichTextEditor/RichTextEditor.mdx @@ -10,7 +10,7 @@ import * as ComponentStories from './RichTextEditor.stories'; -### When to use +### When to use To allow users to edit text where formatting is important, such as messages to be sent via email. ### When to not use @@ -45,3 +45,7 @@ RichTextEditor also has an error state to display that the input is invalid. The but by setting `hasErrors` via your provided `onChange` callback you can check the HTML produced by the RichTextEditor for any requirements that you have. + +RichTextEditor can optionally take in a forwardedRef to allow content to be programmatically manipulated. + + diff --git a/src/RichTextEditor/RichTextEditor.stories.jsx b/src/RichTextEditor/RichTextEditor.stories.jsx index 00defcd8..c169504e 100644 --- a/src/RichTextEditor/RichTextEditor.stories.jsx +++ b/src/RichTextEditor/RichTextEditor.stories.jsx @@ -1,5 +1,6 @@ -import React from 'react'; +import React, { useRef } from 'react'; +import Button from 'src/Button'; import { RichTextEditor, RichTextEditorActions } from 'src/RichTextEditor'; import mdx from './RichTextEditor.mdx'; @@ -60,3 +61,22 @@ export const Error = () => ( onChange={() => null} /> ); + +export const SetContent = () => { + const ref = useRef(null); + + const handleClick = () => { + ref.current.setContent('Oh hey'); + }; + + return ( + <> + + null} + /> + + ); +}; diff --git a/src/RichTextEditor/RichTextEditor.tsx b/src/RichTextEditor/RichTextEditor.tsx index c299a537..fba8c2c8 100644 --- a/src/RichTextEditor/RichTextEditor.tsx +++ b/src/RichTextEditor/RichTextEditor.tsx @@ -4,7 +4,7 @@ import type { Extension, Node as TipTapNode, Mark } from '@tiptap/core'; import './RichTextEditor.scss'; -import React from 'react'; +import React, { forwardRef, type ForwardedRef, useImperativeHandle } from 'react'; import classNames from 'classnames'; @@ -94,21 +94,28 @@ export type RichTextEditorProps = { onChange: (arg0: string) => void; } -function RichTextEditor({ - allowedAttributes, - allowedTags, - ariaAttributes, - availableActions = RichTextEditorDefaultActionsArray, - characterLimit, - className, - hasErrors, - id, - initialValue, - isOneLine, - onChange, - placeholder, - customExtensions = [], -}: RichTextEditorProps) { +export type RichTextEditorRef = { + setContent: (content: string) => void; +} + +const RichTextEditor = forwardRef(( + { + allowedAttributes, + allowedTags, + ariaAttributes, + availableActions = RichTextEditorDefaultActionsArray, + characterLimit, + className, + hasErrors, + id, + initialValue, + isOneLine, + onChange, + placeholder, + customExtensions = [], + }: RichTextEditorProps, + ref: ForwardedRef = null, +) => { const oneLineExtension = isOneLine ? [OneLineLimit] : []; const requiredExtensions = [ @@ -183,6 +190,13 @@ function RichTextEditor({ }, }); + useImperativeHandle(ref, () => ({ + setContent: (content: string) => { + editor?.commands.setContent(content); + onChange(content); + }, + })); + return ( editor ? (
) ); -} +}); // eslint-disable-next-line import/no-default-export export default RichTextEditor;