From d87aed4cad4a503554b674da9dda584ce8ebbcfe Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Fri, 24 May 2024 15:14:24 +0100 Subject: [PATCH 1/8] Make placeholder accessible --- examples/react-rich/src/App.tsx | 15 +- packages/lexical-playground/src/Editor.tsx | 10 +- .../src/nodes/ImageComponent.tsx | 12 +- .../InlineImageNode/InlineImageComponent.tsx | 12 +- .../src/nodes/StickyComponent.tsx | 12 +- .../src/plugins/CommentPlugin/index.tsx | 6 +- .../src/ui/ContentEditable.css | 21 +++ .../src/ui/ContentEditable.tsx | 24 ++- .../lexical-playground/src/ui/Placeholder.css | 28 ---- .../lexical-playground/src/ui/Placeholder.tsx | 22 --- .../flow/LexicalContentEditable.js.flow | 8 +- .../src/LexicalContentEditable.tsx | 138 ++++++------------ .../src/LexicalPlainTextPlugin.tsx | 6 +- .../src/LexicalRichTextPlugin.tsx | 6 +- .../shared/LexicalContentEditableElement.tsx | 107 ++++++++++++++ 15 files changed, 241 insertions(+), 186 deletions(-) delete mode 100644 packages/lexical-playground/src/ui/Placeholder.css delete mode 100644 packages/lexical-playground/src/ui/Placeholder.tsx create mode 100644 packages/lexical-react/src/shared/LexicalContentEditableElement.tsx diff --git a/examples/react-rich/src/App.tsx b/examples/react-rich/src/App.tsx index 665d654054b..de1b5d4e1e4 100644 --- a/examples/react-rich/src/App.tsx +++ b/examples/react-rich/src/App.tsx @@ -16,9 +16,7 @@ import ExampleTheme from './ExampleTheme'; import ToolbarPlugin from './plugins/ToolbarPlugin'; import TreeViewPlugin from './plugins/TreeViewPlugin'; -function Placeholder() { - return
Enter some rich text...
; -} +const placeholder = 'Enter some rich text...'; const editorConfig = { namespace: 'React.js Demo', @@ -38,8 +36,15 @@ export default function App() {
} - placeholder={} + contentEditable={ + {placeholder}
+ } + aria-placeholder={placeholder} + /> + } ErrorBoundary={LexicalErrorBoundary} /> diff --git a/packages/lexical-playground/src/Editor.tsx b/packages/lexical-playground/src/Editor.tsx index 096770f184e..af2b07c74e2 100644 --- a/packages/lexical-playground/src/Editor.tsx +++ b/packages/lexical-playground/src/Editor.tsx @@ -69,7 +69,6 @@ import TreeViewPlugin from './plugins/TreeViewPlugin'; import TwitterPlugin from './plugins/TwitterPlugin'; import YouTubePlugin from './plugins/YouTubePlugin'; import ContentEditable from './ui/ContentEditable'; -import Placeholder from './ui/Placeholder'; const skipCollaborationInit = // @ts-expect-error @@ -94,12 +93,11 @@ export default function Editor(): JSX.Element { }, } = useSettings(); const isEditable = useLexicalEditable(); - const text = isCollab + const placeholder = isCollab ? 'Enter some collaborative rich text...' : isRichText ? 'Enter some rich text...' : 'Enter some plain text...'; - const placeholder = {text}; const [floatingAnchorElem, setFloatingAnchorElem] = useState(null); const [isSmallWidthViewport, setIsSmallWidthViewport] = @@ -168,11 +166,10 @@ export default function Editor(): JSX.Element { contentEditable={
- +
} - placeholder={placeholder} ErrorBoundary={LexicalErrorBoundary} /> @@ -224,8 +221,7 @@ export default function Editor(): JSX.Element { ) : ( <> } - placeholder={placeholder} + contentEditable={} ErrorBoundary={LexicalErrorBoundary} /> diff --git a/packages/lexical-playground/src/nodes/ImageComponent.tsx b/packages/lexical-playground/src/nodes/ImageComponent.tsx index 23c891e12d4..d53eb30db33 100644 --- a/packages/lexical-playground/src/nodes/ImageComponent.tsx +++ b/packages/lexical-playground/src/nodes/ImageComponent.tsx @@ -62,7 +62,6 @@ import MentionsPlugin from '../plugins/MentionsPlugin'; import TreeViewPlugin from '../plugins/TreeViewPlugin'; import ContentEditable from '../ui/ContentEditable'; import ImageResizer from '../ui/ImageResizer'; -import Placeholder from '../ui/Placeholder'; import {EmojiNode} from './EmojiNode'; import {$isImageNode} from './ImageNode'; import {KeywordNode} from './KeywordNode'; @@ -452,12 +451,11 @@ export default function ImageComponent({ )} - } - placeholder={ - - Enter a caption... - + } ErrorBoundary={LexicalErrorBoundary} /> diff --git a/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx b/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx index 7cc9428f465..ad2861ba3d0 100644 --- a/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx +++ b/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx @@ -39,7 +39,6 @@ import LinkPlugin from '../../plugins/LinkPlugin'; import Button from '../../ui/Button'; import ContentEditable from '../../ui/ContentEditable'; import {DialogActions} from '../../ui/Dialog'; -import Placeholder from '../../ui/Placeholder'; import Select from '../../ui/Select'; import TextInput from '../../ui/TextInput'; import {$isInlineImageNode, InlineImageNode} from './InlineImageNode'; @@ -388,12 +387,11 @@ export default function InlineImageComponent({ - } - placeholder={ - - Enter a caption... - + } ErrorBoundary={LexicalErrorBoundary} /> diff --git a/packages/lexical-playground/src/nodes/StickyComponent.tsx b/packages/lexical-playground/src/nodes/StickyComponent.tsx index ec3ebf6fa6b..469ac869457 100644 --- a/packages/lexical-playground/src/nodes/StickyComponent.tsx +++ b/packages/lexical-playground/src/nodes/StickyComponent.tsx @@ -27,7 +27,6 @@ import {createWebsocketProvider} from '../collaboration'; import {useSharedHistoryContext} from '../context/SharedHistoryContext'; import StickyEditorTheme from '../themes/StickyEditorTheme'; import ContentEditable from '../ui/ContentEditable'; -import Placeholder from '../ui/Placeholder'; import {$isStickyNode} from './StickyNode'; type Positioning = { @@ -254,12 +253,11 @@ export default function StickyComponent({ )} - } - placeholder={ - - What's up? - + } ErrorBoundary={LexicalErrorBoundary} /> diff --git a/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx b/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx index 1d446889f5d..66915aacf01 100644 --- a/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx @@ -67,7 +67,6 @@ import useModal from '../../hooks/useModal'; import CommentEditorTheme from '../../themes/CommentEditorTheme'; import Button from '../../ui/Button'; import ContentEditable from '../../ui/ContentEditable'; -import Placeholder from '../../ui/Placeholder'; export const INSERT_INLINE_COMMAND: LexicalCommand = createCommand( 'INSERT_INLINE_COMMAND', @@ -168,8 +167,9 @@ function PlainTextEditor({
} - placeholder={{placeholder}} + contentEditable={ + + } ErrorBoundary={LexicalErrorBoundary} /> diff --git a/packages/lexical-playground/src/ui/ContentEditable.css b/packages/lexical-playground/src/ui/ContentEditable.css index 319b2ca1839..66ec2b92a17 100644 --- a/packages/lexical-playground/src/ui/ContentEditable.css +++ b/packages/lexical-playground/src/ui/ContentEditable.css @@ -21,3 +21,24 @@ padding-right: 8px; } } + +.ContentEditable__placeholder { + font-size: 15px; + color: #999; + overflow: hidden; + position: absolute; + text-overflow: ellipsis; + top: 8px; + left: 8px; + right: 8px; + user-select: none; + white-space: nowrap; + display: inline-block; + pointer-events: none; +} +@media (max-width: 1025px) { + .Placeholder__root { + left: 8px; + right: 8px; + } +} diff --git a/packages/lexical-playground/src/ui/ContentEditable.tsx b/packages/lexical-playground/src/ui/ContentEditable.tsx index 9301f5f0c2c..b1ee20b2103 100644 --- a/packages/lexical-playground/src/ui/ContentEditable.tsx +++ b/packages/lexical-playground/src/ui/ContentEditable.tsx @@ -11,10 +11,26 @@ import './ContentEditable.css'; import {ContentEditable} from '@lexical/react/LexicalContentEditable'; import * as React from 'react'; +type Props = { + className?: string; + placeholderClassName?: string; + placeholder: string; +}; + export default function LexicalContentEditable({ className, -}: { - className?: string; -}): JSX.Element { - return ; + placeholder, + placeholderClassName, +}: Props): JSX.Element { + return ( + + {placeholder} +
+ } + /> + ); } diff --git a/packages/lexical-playground/src/ui/Placeholder.css b/packages/lexical-playground/src/ui/Placeholder.css deleted file mode 100644 index 61e3df765fb..00000000000 --- a/packages/lexical-playground/src/ui/Placeholder.css +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * - */ - -.Placeholder__root { - font-size: 15px; - color: #999; - overflow: hidden; - position: absolute; - text-overflow: ellipsis; - top: 8px; - left: 28px; - right: 28px; - user-select: none; - white-space: nowrap; - display: inline-block; - pointer-events: none; -} -@media (max-width: 1025px) { - .Placeholder__root { - left: 8px; - } -} diff --git a/packages/lexical-playground/src/ui/Placeholder.tsx b/packages/lexical-playground/src/ui/Placeholder.tsx deleted file mode 100644 index 67677688683..00000000000 --- a/packages/lexical-playground/src/ui/Placeholder.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - */ - -import './Placeholder.css'; - -import * as React from 'react'; -import {ReactNode} from 'react'; - -export default function Placeholder({ - children, - className, -}: { - children: ReactNode; - className?: string; -}): JSX.Element { - return
{children}
; -} diff --git a/packages/lexical-react/flow/LexicalContentEditable.js.flow b/packages/lexical-react/flow/LexicalContentEditable.js.flow index b6b63a4f2cc..ff45922df9a 100644 --- a/packages/lexical-react/flow/LexicalContentEditable.js.flow +++ b/packages/lexical-react/flow/LexicalContentEditable.js.flow @@ -9,7 +9,13 @@ import * as React from 'react'; -export type Props = $ReadOnly<{ +export type Props = ({} | $ReadOnly<{ + 'aria-placeholder': string; + placeholder: + | ((isEditable: boolean) => null | React$Node) + | null + | React$Node; +}>) & $ReadOnly<{ ...Partial, ariaActiveDescendant?: string, ariaAutoComplete?: string, diff --git a/packages/lexical-react/src/LexicalContentEditable.tsx b/packages/lexical-react/src/LexicalContentEditable.tsx index 1dbfe1201b0..a7097a0e1c9 100644 --- a/packages/lexical-react/src/LexicalContentEditable.tsx +++ b/packages/lexical-react/src/LexicalContentEditable.tsx @@ -6,102 +6,58 @@ * */ -import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import * as React from 'react'; -import {useCallback, useState} from 'react'; -import useLayoutEffect from 'shared/useLayoutEffect'; +import type {Props as ElementProps} from './shared/LexicalContentEditableElement'; -export type Props = { - ariaActiveDescendant?: React.AriaAttributes['aria-activedescendant']; - ariaAutoComplete?: React.AriaAttributes['aria-autocomplete']; - ariaControls?: React.AriaAttributes['aria-controls']; - ariaDescribedBy?: React.AriaAttributes['aria-describedby']; - ariaExpanded?: React.AriaAttributes['aria-expanded']; - ariaLabel?: React.AriaAttributes['aria-label']; - ariaLabelledBy?: React.AriaAttributes['aria-labelledby']; - ariaMultiline?: React.AriaAttributes['aria-multiline']; - ariaOwns?: React.AriaAttributes['aria-owns']; - ariaRequired?: React.AriaAttributes['aria-required']; - autoCapitalize?: HTMLDivElement['autocapitalize']; - 'data-testid'?: string | null | undefined; -} & React.AllHTMLAttributes; +import {useLexicalEditable} from '@lexical/react/useLexicalEditable'; -export function ContentEditable({ - ariaActiveDescendant, - ariaAutoComplete, - ariaControls, - ariaDescribedBy, - ariaExpanded, - ariaLabel, - ariaLabelledBy, - ariaMultiline, - ariaOwns, - ariaRequired, - autoCapitalize, - className, - id, - role = 'textbox', - spellCheck = true, - style, - tabIndex, - 'data-testid': testid, - ...rest -}: Props): JSX.Element { - const [editor] = useLexicalComposerContext(); - const [isEditable, setEditable] = useState(false); +import {useLexicalComposerContext} from './LexicalComposerContext'; +import {ContentEditableElement} from './shared/LexicalContentEditableElement'; +import {useCanShowPlaceholder} from './shared/useCanShowPlaceholder'; - const ref = useCallback( - (rootElement: null | HTMLElement) => { - // defaultView is required for a root element. - // In multi-window setups, the defaultView may not exist at certain points. - if ( - rootElement && - rootElement.ownerDocument && - rootElement.ownerDocument.defaultView - ) { - editor.setRootElement(rootElement); - } - }, - [editor], - ); +/* eslint-disable @typescript-eslint/ban-types */ +export type Props = ( + | {} + | { + 'aria-placeholder': string; + placeholder: + | ((isEditable: boolean) => null | JSX.Element) + | null + | JSX.Element; + } +) & + ElementProps; +/* eslint-enable @typescript-eslint/ban-types */ - useLayoutEffect(() => { - setEditable(editor.isEditable()); - return editor.registerEditableListener((currentIsEditable) => { - setEditable(currentIsEditable); - }); - }, [editor]); +export function ContentEditable(props: Props): JSX.Element { + let placeholder = null; + if ('placeholder' in props) { + placeholder = props.placeholder; + } return ( -
+ <> + + + ); } + +function Placeholder({ + content, +}: { + content: ((isEditable: boolean) => null | JSX.Element) | null | JSX.Element; +}): null | JSX.Element { + const [editor] = useLexicalComposerContext(); + const showPlaceholder = useCanShowPlaceholder(editor); + const editable = useLexicalEditable(); + + if (!showPlaceholder) { + return null; + } + + if (typeof content === 'function') { + return content(editable); + } else { + return content; + } +} diff --git a/packages/lexical-react/src/LexicalPlainTextPlugin.tsx b/packages/lexical-react/src/LexicalPlainTextPlugin.tsx index 3a13ca672eb..108e6aa1914 100644 --- a/packages/lexical-react/src/LexicalPlainTextPlugin.tsx +++ b/packages/lexical-react/src/LexicalPlainTextPlugin.tsx @@ -16,11 +16,12 @@ import {usePlainTextSetup} from './shared/usePlainTextSetup'; export function PlainTextPlugin({ contentEditable, - placeholder, + // TODO Remove. This property is now part of ContentEditable + placeholder = null, ErrorBoundary, }: { contentEditable: JSX.Element; - placeholder: + placeholder?: | ((isEditable: boolean) => null | JSX.Element) | null | JSX.Element; @@ -39,6 +40,7 @@ export function PlainTextPlugin({ ); } +// TODO Remove function Placeholder({ content, }: { diff --git a/packages/lexical-react/src/LexicalRichTextPlugin.tsx b/packages/lexical-react/src/LexicalRichTextPlugin.tsx index abc46555749..40ce57544d5 100644 --- a/packages/lexical-react/src/LexicalRichTextPlugin.tsx +++ b/packages/lexical-react/src/LexicalRichTextPlugin.tsx @@ -16,11 +16,12 @@ import {useRichTextSetup} from './shared/useRichTextSetup'; export function RichTextPlugin({ contentEditable, - placeholder, + // TODO Remove. This property is now part of ContentEditable + placeholder = null, ErrorBoundary, }: { contentEditable: JSX.Element; - placeholder: + placeholder?: | ((isEditable: boolean) => null | JSX.Element) | null | JSX.Element; @@ -39,6 +40,7 @@ export function RichTextPlugin({ ); } +// TODO remove function Placeholder({ content, }: { diff --git a/packages/lexical-react/src/shared/LexicalContentEditableElement.tsx b/packages/lexical-react/src/shared/LexicalContentEditableElement.tsx new file mode 100644 index 00000000000..25ab75abc26 --- /dev/null +++ b/packages/lexical-react/src/shared/LexicalContentEditableElement.tsx @@ -0,0 +1,107 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; +import * as React from 'react'; +import {useCallback, useState} from 'react'; +import useLayoutEffect from 'shared/useLayoutEffect'; + +export type Props = { + ariaActiveDescendant?: React.AriaAttributes['aria-activedescendant']; + ariaAutoComplete?: React.AriaAttributes['aria-autocomplete']; + ariaControls?: React.AriaAttributes['aria-controls']; + ariaDescribedBy?: React.AriaAttributes['aria-describedby']; + ariaExpanded?: React.AriaAttributes['aria-expanded']; + ariaLabel?: React.AriaAttributes['aria-label']; + ariaLabelledBy?: React.AriaAttributes['aria-labelledby']; + ariaMultiline?: React.AriaAttributes['aria-multiline']; + ariaOwns?: React.AriaAttributes['aria-owns']; + ariaRequired?: React.AriaAttributes['aria-required']; + autoCapitalize?: HTMLDivElement['autocapitalize']; + 'data-testid'?: string | null | undefined; +} & Omit, 'placeholder'>; + +export function ContentEditableElement({ + ariaActiveDescendant, + ariaAutoComplete, + ariaControls, + ariaDescribedBy, + ariaExpanded, + ariaLabel, + ariaLabelledBy, + ariaMultiline, + ariaOwns, + ariaRequired, + autoCapitalize, + className, + id, + role = 'textbox', + spellCheck = true, + style, + tabIndex, + 'data-testid': testid, + ...rest +}: Props): JSX.Element { + const [editor] = useLexicalComposerContext(); + const [isEditable, setEditable] = useState(false); + + const ref = useCallback( + (rootElement: null | HTMLElement) => { + // defaultView is required for a root element. + // In multi-window setups, the defaultView may not exist at certain points. + if ( + rootElement && + rootElement.ownerDocument && + rootElement.ownerDocument.defaultView + ) { + editor.setRootElement(rootElement); + } + }, + [editor], + ); + + useLayoutEffect(() => { + setEditable(editor.isEditable()); + return editor.registerEditableListener((currentIsEditable) => { + setEditable(currentIsEditable); + }); + }, [editor]); + + return ( +
+ ); +} From f4b1d3e5c064c90a2c073e7b3fcfe7fe0556de10 Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Fri, 24 May 2024 15:20:35 +0100 Subject: [PATCH 2/8] . --- packages/lexical-playground/src/ui/ContentEditable.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/lexical-playground/src/ui/ContentEditable.css b/packages/lexical-playground/src/ui/ContentEditable.css index 66ec2b92a17..efced7fc1bc 100644 --- a/packages/lexical-playground/src/ui/ContentEditable.css +++ b/packages/lexical-playground/src/ui/ContentEditable.css @@ -29,15 +29,15 @@ position: absolute; text-overflow: ellipsis; top: 8px; - left: 8px; - right: 8px; + left: 28px; + right: 28px; user-select: none; white-space: nowrap; display: inline-block; pointer-events: none; } @media (max-width: 1025px) { - .Placeholder__root { + .ContentEditable__placeholder { left: 8px; right: 8px; } From 3e20a043bc30c3b2706158fa29f0c06593a1031f Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Fri, 24 May 2024 15:29:39 +0100 Subject: [PATCH 3/8] hidden --- .../lexical-react/src/LexicalContentEditable.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/lexical-react/src/LexicalContentEditable.tsx b/packages/lexical-react/src/LexicalContentEditable.tsx index a7097a0e1c9..461a2309f40 100644 --- a/packages/lexical-react/src/LexicalContentEditable.tsx +++ b/packages/lexical-react/src/LexicalContentEditable.tsx @@ -55,9 +55,15 @@ function Placeholder({ return null; } + let placeholder = null; if (typeof content === 'function') { - return content(editable); - } else { - return content; + placeholder = content(editable); + } else if (content !== null) { + placeholder = content; + } + + if (placeholder === null) { + return null; } + return
{placeholder}
; } From 1db8c31c426a1edd96d375c72de5a36857041686 Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Mon, 27 May 2024 15:34:51 -0400 Subject: [PATCH 4/8] remove --no-save --no-package-lock --- scripts/__tests__/integration/utils.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/__tests__/integration/utils.js b/scripts/__tests__/integration/utils.js index 452c5dedbc8..3267c4cba9f 100644 --- a/scripts/__tests__/integration/utils.js +++ b/scripts/__tests__/integration/utils.js @@ -88,11 +88,7 @@ async function buildExample({packageJson, exampleDir}) { (cleanDir) => fs.removeSync(path.resolve(exampleDir, cleanDir)), ); await withCwd(exampleDir, async () => { - await exec( - `npm install --no-save --no-package-lock ${installDeps - .map((fn) => `'${fn}'`) - .join(' ')}`, - ); + await exec(`npm install ${installDeps.map((fn) => `'${fn}'`).join(' ')}`); await exec('npm run build'); if (hasPlaywright) { await exec('npx playwright install'); From 9dd45a3c35dcd9f9b76dbe6fc95f03cd691f9da8 Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Tue, 18 Jun 2024 15:11:53 -0400 Subject: [PATCH 5/8] . --- scripts/__tests__/integration/utils.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/__tests__/integration/utils.js b/scripts/__tests__/integration/utils.js index 3267c4cba9f..452c5dedbc8 100644 --- a/scripts/__tests__/integration/utils.js +++ b/scripts/__tests__/integration/utils.js @@ -88,7 +88,11 @@ async function buildExample({packageJson, exampleDir}) { (cleanDir) => fs.removeSync(path.resolve(exampleDir, cleanDir)), ); await withCwd(exampleDir, async () => { - await exec(`npm install ${installDeps.map((fn) => `'${fn}'`).join(' ')}`); + await exec( + `npm install --no-save --no-package-lock ${installDeps + .map((fn) => `'${fn}'`) + .join(' ')}`, + ); await exec('npm run build'); if (hasPlaywright) { await exec('npx playwright install'); From 5e26f7c5baa5fa6e27e2fce54413f148433d5cca Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Tue, 18 Jun 2024 16:50:25 -0400 Subject: [PATCH 6/8] modernize integration test --- .../lexical-esm-nextjs/app/EditorUseClient.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx index 7d626911e23..d2cc4610028 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx +++ b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx @@ -28,10 +28,6 @@ import { useEffect } from "react"; import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"; import { $getRoot } from "lexical"; -function Placeholder() { - return
Enter some rich text...
; -} - const editorConfig = { namespace: "React.js Demo", nodes: [CodeNode, CodeHighlightNode], @@ -64,8 +60,10 @@ export default function App() {
} - placeholder={} + contentEditable={} ErrorBoundary={LexicalErrorBoundary} /> From c39cbcb22dfdd79f2f2a977fe87646177c98b57d Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Wed, 3 Jul 2024 16:39:44 -0400 Subject: [PATCH 7/8] never give up --- examples/react-rich/src/App.tsx | 2 +- .../lexical-react/src/LexicalContentEditable.tsx | 2 +- .../src/components/App.tsx | 15 ++++++++++----- .../lexical-esm-nextjs/app/EditorUseClient.tsx | 15 +++++++++++---- scripts/error-codes/codes.json | 3 ++- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/examples/react-rich/src/App.tsx b/examples/react-rich/src/App.tsx index de1b5d4e1e4..1686f3b1d52 100644 --- a/examples/react-rich/src/App.tsx +++ b/examples/react-rich/src/App.tsx @@ -39,10 +39,10 @@ export default function App() { contentEditable={ {placeholder}
} - aria-placeholder={placeholder} /> } ErrorBoundary={LexicalErrorBoundary} diff --git a/packages/lexical-react/src/LexicalContentEditable.tsx b/packages/lexical-react/src/LexicalContentEditable.tsx index 461a2309f40..776c90b0c2b 100644 --- a/packages/lexical-react/src/LexicalContentEditable.tsx +++ b/packages/lexical-react/src/LexicalContentEditable.tsx @@ -8,9 +8,9 @@ import type {Props as ElementProps} from './shared/LexicalContentEditableElement'; +import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable'; -import {useLexicalComposerContext} from './LexicalComposerContext'; import {ContentEditableElement} from './shared/LexicalContentEditableElement'; import {useCanShowPlaceholder} from './shared/useCanShowPlaceholder'; diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/App.tsx b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/App.tsx index 46c35127143..8150efce6c2 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/App.tsx +++ b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/App.tsx @@ -27,9 +27,7 @@ import { useEffect } from "react"; import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"; import { $getRoot } from "lexical"; -function Placeholder() { - return
Enter some rich text...
; -} +const placeholder = 'Enter some rich text...'; const editorConfig = { namespace: "React.js Demo", @@ -63,8 +61,15 @@ export default function App() {
} - placeholder={} + contentEditable={ + {placeholder}
+ } + /> + } ErrorBoundary={LexicalErrorBoundary} /> diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx index d2cc4610028..11cb9015058 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx +++ b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/EditorUseClient.tsx @@ -39,6 +39,8 @@ const editorConfig = { theme: ExampleTheme, }; +const placeholder = 'Enter some rich text...'; + function CodeHighlightingPlugin() { const [editor] = useLexicalComposerContext(); useEffect(() => { @@ -60,10 +62,15 @@ export default function App() {
} + contentEditable={ + {placeholder}
+ } + /> + } ErrorBoundary={LexicalErrorBoundary} /> diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index 0d90d5e1a65..9663b42e464 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -186,5 +186,6 @@ "184": "Element point must be an element node", "185": "%s doesn't extend the %s", "186": "Lexical node with constructor %s attempted to re-use key from node in active editor state with constructor %s. Keys must not be re-used when the type is changed.", - "187": "Lexical node with constructor %s attempted to re-use key from node in active editor state with different constructor with the same name (possibly due to invalid Hot Module Replacement). Keys must not be re-used when the type is changed." + "187": "Lexical node with constructor %s attempted to re-use key from node in active editor state with different constructor with the same name (possibly due to invalid Hot Module Replacement). Keys must not be re-used when the type is changed.", + "188": "Expected a RangeSelection or TableSelection" } From 5b03be3ed57f1ed4cc6ecbc7684b09e6d0bb4278 Mon Sep 17 00:00:00 2001 From: Gerard Rovira Date: Wed, 3 Jul 2024 18:45:51 -0400 Subject: [PATCH 8/8] i can sense success --- .../lexical-playground/__tests__/e2e/Placeholder.spec.mjs | 2 +- packages/lexical-playground/__tests__/e2e/Toolbar.spec.mjs | 1 + packages/lexical-react/src/LexicalContentEditable.tsx | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/lexical-playground/__tests__/e2e/Placeholder.spec.mjs b/packages/lexical-playground/__tests__/e2e/Placeholder.spec.mjs index 3df7624f30c..40882785499 100644 --- a/packages/lexical-playground/__tests__/e2e/Placeholder.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Placeholder.spec.mjs @@ -25,7 +25,7 @@ test.describe('Placeholder', () => { isCollab, }) => { await focusEditor(page); - const content = await textContent(page, '.Placeholder__root'); + const content = await textContent(page, '.ContentEditable__placeholder'); if (isCollab) { expect(content).toBe('Enter some collaborative rich text...'); } else if (isRichText) { diff --git a/packages/lexical-playground/__tests__/e2e/Toolbar.spec.mjs b/packages/lexical-playground/__tests__/e2e/Toolbar.spec.mjs index 0eab008b6c0..39c2795c5d9 100644 --- a/packages/lexical-playground/__tests__/e2e/Toolbar.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Toolbar.spec.mjs @@ -79,6 +79,7 @@ test.describe('Toolbar', () => {
- + );