diff --git a/package-lock.json b/package-lock.json index 38a2fb88..c01c94a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,7 +86,6 @@ "react-icons": "4.7.1", "react-markdown": "8.0.5", "react-syntax-highlighter": "15.5.0", - "react-use-event-hook": "0.9.3", "rehype-raw": "6.1.1", "remark-gfm": "3.0.1", "rimraf": "3.0.2", @@ -30399,15 +30398,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/react-use-event-hook": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/react-use-event-hook/-/react-use-event-hook-0.9.3.tgz", - "integrity": "sha512-8edWglTZ9Z5kfl31EuRjr4MDkTcEczHvrbo2EG1WVrX/a1B2sP3S9RCXjtSwrEnYRw29ldErlvDQNbTOxHNcmQ==", - "dev": true, - "peerDependencies": { - "react": ">=16.8.0" - } - }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -59889,13 +59879,6 @@ } } }, - "react-use-event-hook": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/react-use-event-hook/-/react-use-event-hook-0.9.3.tgz", - "integrity": "sha512-8edWglTZ9Z5kfl31EuRjr4MDkTcEczHvrbo2EG1WVrX/a1B2sP3S9RCXjtSwrEnYRw29ldErlvDQNbTOxHNcmQ==", - "dev": true, - "requires": {} - }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", diff --git a/package.json b/package.json index ea09850c..b105ce8d 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,6 @@ "react-icons": "4.7.1", "react-markdown": "8.0.5", "react-syntax-highlighter": "15.5.0", - "react-use-event-hook": "0.9.3", "rehype-raw": "6.1.1", "remark-gfm": "3.0.1", "rimraf": "3.0.2", diff --git a/stories/documentation/tips-and-tricks/performance.md b/stories/documentation/tips-and-tricks/performance.md index 0abb4893..3d0bbb6f 100644 --- a/stories/documentation/tips-and-tricks/performance.md +++ b/stories/documentation/tips-and-tricks/performance.md @@ -35,5 +35,3 @@ function PlainTextEditorContainer({ content }) { return } ``` - -The same is true for event handler properties, such as the `onUpdate`, `onTransaction`, and all others. For these, you may consider wrapping them with `useEvent` from the third-party [`react-use-event-hook`](https://github.com/scottrippey/react-use-event-hook) package, which keeps the callback reference more stable than `useCallback` while invoking the callback with always up-to-date properties and state. Please refer to [Usage → Helpers](/?path=/docs/documentation-usage-helpers--page) for a `useEvent` example. diff --git a/stories/documentation/usage/helpers.md b/stories/documentation/usage/helpers.md index b3f0247d..0b83a99e 100644 --- a/stories/documentation/usage/helpers.md +++ b/stories/documentation/usage/helpers.md @@ -7,8 +7,7 @@ Passing down a `ref` to the `TypistEditor` component gives us access to some hel - `getAllNodesAttributesByType(nodeType)`: Returns the attributes of a given node type for all the nodes in the editor document. ```tsx -import { useRef } from 'react' -import { useEvent } from 'react-use-event-hook' +import { useCallback, useRef } from 'react' import { TypistEditor, RichTextKit } from '@doist/typist' @@ -17,9 +16,9 @@ import type { TypistEditorRef } from '@doist/typist' function TypistEditorContainer({ content }) { const typistEditorRef = useRef(null) - const handleUpdate = useEvent(function handleUpdate() { + const handleUpdate = useCallback(function handleUpdate() { console.log(typistEditorRef.current?.getMarkdown() || '') - }) + }, []) return ( { + const handleUpdate = useCallback((props: UpdateProps) => { setMarkdownOutput(props.getMarkdown()) - }) + }, []) useEffect( function updateMarkdownOutputOnContentControlChange() { diff --git a/stories/typist-editor/decorators/typist-editor-decorator/typist-editor-toolbar.tsx b/stories/typist-editor/decorators/typist-editor-decorator/typist-editor-toolbar.tsx index eddba9a4..80400fae 100644 --- a/stories/typist-editor/decorators/typist-editor-decorator/typist-editor-toolbar.tsx +++ b/stories/typist-editor/decorators/typist-editor-decorator/typist-editor-toolbar.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useCallback, useEffect } from 'react' import { RiArrowGoBackLine, RiArrowGoForwardLine, @@ -25,7 +25,6 @@ import { RiStrikethrough, RiTextWrap, } from 'react-icons/ri' -import { useEvent } from 'react-use-event-hook' import { Box, Button } from '@doist/reactist' @@ -61,7 +60,7 @@ function TypistEditorToolbar({ editor }: TypistEditorToolbarProps) { [editor, forceRerender], ) - const handleLinkButtonClick = useEvent(() => { + const handleLinkButtonClick = useCallback(() => { const previousUrl = String(editor.getAttributes('link').href || '') const newUrl = window.prompt('Link URL', previousUrl) @@ -71,9 +70,9 @@ function TypistEditorToolbar({ editor }: TypistEditorToolbarProps) { } editor.chain().focus().extendMarkRange('link').setLink({ href: newUrl }).run() - }) + }, [editor]) - const handleImageButtonClick = useEvent(() => { + const handleImageButtonClick = useCallback(() => { const newUrl = window.prompt('Image URL') if (newUrl === null) { @@ -82,7 +81,7 @@ function TypistEditorToolbar({ editor }: TypistEditorToolbarProps) { } editor.chain().focus().insertImage({ src: newUrl }).run() - }) + }, [editor]) return ( ({ const areSuggestionsLoading = items.length === 1 && 'isLoading' in items[0] const areSuggestionsEmpty = items.length === 0 - const handleItemSelect = useEvent((index: number) => { - const item = items[index] + const handleItemSelect = useCallback( + (index: number) => { + const item = items[index] - if (item) { - onItemSelect(item) - } - }) + if (item) { + onItemSelect(item) + } + }, + [items, onItemSelect], + ) useEffect( function scrollSelectedItemIntoView() { diff --git a/stories/typist-editor/plain-text-functions.stories.tsx b/stories/typist-editor/plain-text-functions.stories.tsx index 0448634b..11f5ce32 100644 --- a/stories/typist-editor/plain-text-functions.stories.tsx +++ b/stories/typist-editor/plain-text-functions.stories.tsx @@ -1,5 +1,4 @@ -import { useRef } from 'react' -import { useEvent } from 'react-use-event-hook' +import { useCallback, useRef } from 'react' import { Button } from '@doist/reactist' @@ -29,18 +28,18 @@ export const Commands: ComponentStoryObj = { (Story, context) => { const typistEditorRef = useRef(null) - const handleExtendWordRangeClick = useEvent(() => { + const handleExtendWordRangeClick = useCallback(() => { typistEditorRef.current?.getEditor().chain().focus().extendWordRange().run() - }) + }, []) - const handleInsertMarkdownContentClick = useEvent(() => { + const handleInsertMarkdownContentClick = useCallback(() => { typistEditorRef.current ?.getEditor() .chain() .focus() .insertMarkdownContent(MARKDOWN_PLACEHOLDER) .run() - }) + }, []) return ( = { (Story, context) => { const typistEditorRef = useRef(null) - const handleGetEditorClick = useEvent(() => { + const handleGetEditorClick = useCallback(() => { action('getEditor')(typistEditorRef.current?.getEditor()) - }) + }, []) - const handleGetMarkdownClick = useEvent(() => { + const handleGetMarkdownClick = useCallback(() => { action('getMarkdown')(typistEditorRef.current?.getMarkdown() || '') - }) + }, []) - const handleGetAllNodesAttributesByTypeClick = useEvent(() => { + const handleGetAllNodesAttributesByTypeClick = useCallback(() => { action('getAllNodesAttributesByType')( typistEditorRef.current?.getAllNodesAttributesByType('mentionSuggestion'), ) - }) + }, []) return ( = { }, decorators: [ (Story, context) => { - const handleKeyDown = useEvent((event: KeyboardEvent, view: EditorView) => { + const handleKeyDown = useCallback((event: KeyboardEvent, view: EditorView) => { if (event.key === 'Enter') { action('onEnterPressed')({ event, @@ -65,7 +65,7 @@ export const Singleline: ComponentStoryObj = { }) return true } - }) + }, []) return ( = { (Story, context) => { const typistEditorRef = useRef(null) - const handleExtendWordRangeClick = useEvent(() => { + const handleExtendWordRangeClick = useCallback(() => { typistEditorRef.current?.getEditor().chain().focus().extendWordRange().run() - }) + }, []) - const handleInsertMarkdownContentClick = useEvent(() => { + const handleInsertMarkdownContentClick = useCallback(() => { typistEditorRef.current ?.getEditor() .chain() .focus() .insertMarkdownContent(MARKDOWN_PLACEHOLDER) .run() - }) + }, []) return ( = { (Story, context) => { const typistEditorRef = useRef(null) - const handleGetEditorClick = useEvent(() => { + const handleGetEditorClick = useCallback(() => { action('getEditor')(typistEditorRef.current?.getEditor()) - }) + }, []) - const handleGetMarkdownClick = useEvent(() => { + const handleGetMarkdownClick = useCallback(() => { action('getMarkdown')(typistEditorRef.current?.getMarkdown() || '') - }) + }, []) - const handleGetAllNodesAttributesByTypeClick = useEvent(() => { + const handleGetAllNodesAttributesByTypeClick = useCallback(() => { action('getAllNodesAttributesByType')( typistEditorRef.current?.getAllNodesAttributesByType('mentionSuggestion'), ) - }) + }, []) return ( = { [imageAttachmentsProgress], ) - const handleImageFilePaste = useEvent((file: File) => { + const handleImageFilePaste = useCallback((file: File) => { const attachmentId = Math.random().toString(16).slice(2, 10) setImageAttachmentsProgress((prevState) => ({ ...prevState, [attachmentId]: 0 })) @@ -107,7 +106,7 @@ export const Default: ComponentStoryObj = { } fileReader.readAsDataURL(file) - }) + }, []) const extensions = useMemo( function configureExtensions() { @@ -162,7 +161,7 @@ export const Singleline: ComponentStoryObj = { }, decorators: [ (Story, context) => { - const handleKeyDown = useEvent((event: KeyboardEvent, view: EditorView) => { + const handleKeyDown = useCallback((event: KeyboardEvent, view: EditorView) => { if (event.key === 'Enter') { action('onEnterPressed')({ event, @@ -170,7 +169,7 @@ export const Singleline: ComponentStoryObj = { }) return true } - }) + }, []) return (