Skip to content

Commit

Permalink
Make placeholder accessible
Browse files Browse the repository at this point in the history
  • Loading branch information
zurfyx committed May 25, 2024
1 parent 8a57b66 commit 24b9118
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 186 deletions.
15 changes: 10 additions & 5 deletions examples/react-rich/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import ExampleTheme from './ExampleTheme';
import ToolbarPlugin from './plugins/ToolbarPlugin';
import TreeViewPlugin from './plugins/TreeViewPlugin';

function Placeholder() {
return <div className="editor-placeholder">Enter some rich text...</div>;
}
const placeholder = 'Enter some rich text...';

const editorConfig = {
namespace: 'React.js Demo',
Expand All @@ -38,8 +36,15 @@ export default function App() {
<ToolbarPlugin />
<div className="editor-inner">
<RichTextPlugin
contentEditable={<ContentEditable className="editor-input" />}
placeholder={<Placeholder />}
contentEditable={
<ContentEditable
className="editor-input"
placeholder={
<div className="editor-placeholder">{placeholder}</div>
}
aria-placeholder={placeholder}
/>
}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin />
Expand Down
10 changes: 3 additions & 7 deletions packages/lexical-playground/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 = <Placeholder>{text}</Placeholder>;
const [floatingAnchorElem, setFloatingAnchorElem] =
useState<HTMLDivElement | null>(null);
const [isSmallWidthViewport, setIsSmallWidthViewport] =
Expand Down Expand Up @@ -168,11 +166,10 @@ export default function Editor(): JSX.Element {
contentEditable={
<div className="editor-scroller">
<div className="editor" ref={onRef}>
<ContentEditable />
<ContentEditable placeholder={placeholder} />
</div>
</div>
}
placeholder={placeholder}
ErrorBoundary={LexicalErrorBoundary}
/>
<MarkdownShortcutPlugin />
Expand Down Expand Up @@ -224,8 +221,7 @@ export default function Editor(): JSX.Element {
) : (
<>
<PlainTextPlugin
contentEditable={<ContentEditable />}
placeholder={placeholder}
contentEditable={<ContentEditable placeholder={placeholder} />}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin externalHistoryState={historyState} />
Expand Down
12 changes: 5 additions & 7 deletions packages/lexical-playground/src/nodes/ImageComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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 {$isImageNode} from './ImageNode';

const imageCache = new Set();
Expand Down Expand Up @@ -433,12 +432,11 @@ export default function ImageComponent({
)}
<RichTextPlugin
contentEditable={
<ContentEditable className="ImageNode__contentEditable" />
}
placeholder={
<Placeholder className="ImageNode__placeholder">
Enter a caption...
</Placeholder>
<ContentEditable
placeholder="Enter a caption..."
placeholderClassName="ImageNode__placeholder"
className="ImageNode__contentEditable"
/>
}
ErrorBoundary={LexicalErrorBoundary}
/>
Expand Down
12 changes: 5 additions & 7 deletions packages/lexical-playground/src/nodes/InlineImageComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -388,12 +387,11 @@ export default function InlineImageComponent({
<LinkPlugin />
<RichTextPlugin
contentEditable={
<ContentEditable className="InlineImageNode__contentEditable" />
}
placeholder={
<Placeholder className="InlineImageNode__placeholder">
Enter a caption...
</Placeholder>
<ContentEditable
placeholder="Enter a caption..."
placeholderClassName="InlineImageNode__placeholder"
className="InlineImageNode__contentEditable"
/>
}
ErrorBoundary={LexicalErrorBoundary}
/>
Expand Down
12 changes: 5 additions & 7 deletions packages/lexical-playground/src/nodes/StickyComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -254,12 +253,11 @@ export default function StickyComponent({
)}
<PlainTextPlugin
contentEditable={
<ContentEditable className="StickyNode__contentEditable" />
}
placeholder={
<Placeholder className="StickyNode__placeholder">
What's up?
</Placeholder>
<ContentEditable
placeholder="What's up?"
placeholderClassName="StickyNode__placeholder"
className="StickyNode__contentEditable"
/>
}
ErrorBoundary={LexicalErrorBoundary}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> = createCommand(
'INSERT_INLINE_COMMAND',
Expand Down Expand Up @@ -168,8 +167,9 @@ function PlainTextEditor({
<LexicalComposer initialConfig={initialConfig}>
<div className="CommentPlugin_CommentInputBox_EditorContainer">
<PlainTextPlugin
contentEditable={<ContentEditable className={className} />}
placeholder={<Placeholder>{placeholder}</Placeholder>}
contentEditable={
<ContentEditable placeholder={placeholder} className={className} />
}
ErrorBoundary={LexicalErrorBoundary}
/>
<OnChangePlugin onChange={onChange} />
Expand Down
21 changes: 21 additions & 0 deletions packages/lexical-playground/src/ui/ContentEditable.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
24 changes: 20 additions & 4 deletions packages/lexical-playground/src/ui/ContentEditable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <ContentEditable className={className || 'ContentEditable__root'} />;
placeholder,
placeholderClassName,
}: Props): JSX.Element {
return (
<ContentEditable
className={className ?? 'ContentEditable__root'}
aria-placeholder={placeholder}
placeholder={
<div className={placeholderClassName ?? 'ContentEditable__placeholder'}>
{placeholder}
</div>
}
/>
);
}
28 changes: 0 additions & 28 deletions packages/lexical-playground/src/ui/Placeholder.css

This file was deleted.

22 changes: 0 additions & 22 deletions packages/lexical-playground/src/ui/Placeholder.tsx

This file was deleted.

8 changes: 7 additions & 1 deletion packages/lexical-react/flow/LexicalContentEditable.js.flow
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement>,
ariaActiveDescendant?: string,
ariaAutoComplete?: string,
Expand Down
Loading

0 comments on commit 24b9118

Please sign in to comment.