lexical
lexical copied to clipboard
Bug: Decorator nodes are not selectable with mouse
Unable to select decorator nodes with mouse in certain situations. For example when you place your selection focus at the start or end of line.
Lexical version: 0.24.0
Steps To Reproduce
- Insert one or more decorator nodes(An example of the node I use is shown below)
- Make sure there are no text nodes before and after decorator nodes
- Place selection at the start/end of the content
- Press mouse down and try to select the nodes
https://github.com/user-attachments/assets/744b5bcf-da16-43b5-84b4-5e312f9b21bd
Link to code example:
You can use React plain text example to reproduce the bug by adding the my decorator node
// TempNode.tsx
import {
DecoratorNode,
type EditorConfig,
type LexicalNode,
type NodeKey,
} from 'lexical';
import React, {Suspense} from 'react';
const TempComponent = React.lazy(() => import('./TempComponent'));
export class TempNode extends DecoratorNode<JSX.Element> {
static override getType(): string {
return 'temp';
}
static override clone(node: TempNode): TempNode {
return new TempNode(node.__key);
}
constructor(key?: NodeKey) {
super(key);
}
override createDOM(config: EditorConfig): HTMLElement {
const span = document.createElement('span');
const theme = config.theme;
const className = theme.temp;
if (className !== undefined) {
span.className = className;
}
return span;
}
override updateDOM(): false {
return false;
}
override getTextContent(): string {
return 'temp';
}
override isKeyboardSelectable(): boolean {
return false;
}
override isIsolated(): boolean {
return true;
}
override decorate(): JSX.Element {
return (
<Suspense fallback={null}>
<TempComponent />
</Suspense>
);
}
}
export function $createTempNode(): TempNode {
return new TempNode();
}
export function $isTempNode(
node: LexicalNode | null | undefined,
): node is TempNode {
return node instanceof TempNode;
}
// TempComponent.tsx
// Just inserts a square red image
export default function TempComponent(): JSX.Element {
return (
<img
style={{
cursor: 'text',
pointerEvents: 'none',
userSelect: 'text',
verticalAlign: 'bottom',
}}
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAH0lEQVR42mP8r8Dwn4GKgHHUwFEDRw0cNXDUwJFqIACVuiptCfasPAAAAABJRU5ErkJggg=="
/>
);
}
// TempPlugin.tsx
// Adds a button to insert TempNode
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {$getSelection, $isRangeSelection} from 'lexical';
import {$createTempNode} from './TempNode';
export function TempPlugin(): JSX.Element {
const [editor] = useLexicalComposerContext();
function handleClick() {
editor.update(() => {
const selection = $getSelection();
if (selection === null || !$isRangeSelection(selection)) {
return;
}
const tempNode = $createTempNode();
selection.insertNodes([tempNode]);
});
}
return <button onClick={handleClick}>Add Temp Node</button>;
}
The current behavior
Selection blinks and resets to initial position
The expected behavior
Decorator node becomes selected
My debugging
I'm not entirely sure if this is a bug. Maybe I'm doing something wrong. But my research led me to the file LexicalSelection.ts
https://github.com/facebook/lexical/blob/fcc374018043620ec025262b352baa91d9536b6e/packages/lexical/src/LexicalSelection.ts#L2359-L2370
Impact of fix
In the project I'm working on, the images inside the detector node are emoji images from Apple fonts. This way you can unify emoji on different OS. Or even display any custom ones, like in Telegram
P.S. Maybe there is a better way to create custom emojis in lexical. I would be very glad if someone could suggest a better way.
Here's a repro link with just playground nodes. You can create a RangeSelection around a subset of the decorator nodes with the keyboard but not by dragging the mouse.
On further investigation, it looks like the playground can only reproduce this because the editor-image class sets user-select: none which is why they are not selectable. If that's removed or changed to another value like text then the example in the playground works.
Hi! I'm facing the same issue, my decorator node has some static text and I'm unable to select it with mouse. It only works with arrow up/down keys and selects the whole label. Did you ever found a way to fix this?
Same here, clicking on it also results in a keyboard deadzone, you can't type anything to remove it.