Make MentionNode a DecoratorNode instead of a TextNode

This commit is contained in:
Alex Gleason 2023-10-13 17:19:55 -05:00
parent 1ba1584da8
commit 964ba8c758
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
4 changed files with 105 additions and 75 deletions

View file

@ -52,7 +52,7 @@ interface IComposeEditor {
const theme: InitialConfigType['theme'] = {
emoji: 'select-none',
hashtag: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
mention: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
mention: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue select-none',
link: 'hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue',
text: {
bold: 'font-bold',

View file

@ -1,73 +0,0 @@
/**
* This source code is derived from code from Meta Platforms, Inc.
* and affiliates, licensed under the MIT license located in the
* LICENSE file in the /src/features/compose/editor directory.
*/
import { addClassNamesToElement } from '@lexical/utils';
import { $applyNodeReplacement, TextNode } from 'lexical';
import type {
EditorConfig,
LexicalNode,
NodeKey,
SerializedTextNode,
} from 'lexical';
class MentionNode extends TextNode {
static getType(): string {
return 'mention';
}
static clone(node: MentionNode): MentionNode {
return new MentionNode(node.__text, node.__key);
}
constructor(text: string, key?: NodeKey) {
super(text, key);
}
createDOM(config: EditorConfig): HTMLElement {
const element = super.createDOM(config);
addClassNamesToElement(element, config.theme.mention);
return element;
}
static importJSON(serializedNode: SerializedTextNode): MentionNode {
const node = $createMentionNode(serializedNode.text);
node.setFormat(serializedNode.format);
node.setDetail(serializedNode.detail);
node.setMode(serializedNode.mode);
node.setStyle(serializedNode.style);
return node;
}
exportJSON(): SerializedTextNode {
return {
...super.exportJSON(),
type: 'mention',
};
}
canInsertTextBefore(): boolean {
return false;
}
isTextEntity(): true {
return true;
}
}
function $createMentionNode(text: string): MentionNode {
const node = new MentionNode(text);
node.setMode('segmented').toggleDirectionless();
return $applyNodeReplacement(node);
}
const $isMentionNode = (
node: LexicalNode | null | undefined,
): node is MentionNode => node instanceof MentionNode;
export { MentionNode, $createMentionNode, $isMentionNode };

View file

@ -0,0 +1,103 @@
/**
* This source code is derived from code from Meta Platforms, Inc.
* and affiliates, licensed under the MIT license located in the
* LICENSE file in the /src/features/compose/editor directory.
*/
import { addClassNamesToElement } from '@lexical/utils';
import { $applyNodeReplacement, DecoratorNode } from 'lexical';
import React from 'react';
import type {
EditorConfig,
LexicalNode,
NodeKey,
SerializedLexicalNode,
Spread,
} from 'lexical';
type SerializedMentionNode = Spread<{
acct: string;
type: 'mention';
version: 1;
}, SerializedLexicalNode>;
class MentionNode extends DecoratorNode<JSX.Element> {
__acct: string;
static getType(): string {
return 'mention';
}
static clone(node: MentionNode): MentionNode {
return new MentionNode(node.__acct, node.__key);
}
constructor(acct: string, key?: NodeKey) {
super(key);
this.__acct = acct;
}
createDOM(config: EditorConfig): HTMLElement {
const span = document.createElement('span');
addClassNamesToElement(span, config.theme.mention);
return span;
}
updateDOM(): false {
return false;
}
static importJSON(serializedNode: SerializedMentionNode): MentionNode {
const node = $createMentionNode(serializedNode.acct);
return node;
}
exportJSON(): SerializedMentionNode {
return {
type: 'mention',
acct: this.__acct,
version: 1,
};
}
getTextContent(): string {
return `@${this.__acct}`;
}
canInsertTextBefore(): boolean {
return false;
}
isTextEntity(): true {
return true;
}
decorate(): JSX.Element {
const acct = this.__acct;
return (
<button
className='text-accent-blue'
type='button'
title={`@${acct}`}
dir='ltr'
>
@{acct}
</button>
);
}
}
function $createMentionNode(acct: string): MentionNode {
const node = new MentionNode(acct);
return $applyNodeReplacement(node);
}
const $isMentionNode = (
node: LexicalNode | null | undefined,
): node is MentionNode => node instanceof MentionNode;
export { MentionNode, $createMentionNode, $isMentionNode };

View file

@ -328,7 +328,7 @@ const AutosuggestPlugin = ({
node.select();
} else {
const acct = selectAccount(getState(), suggestion)!.acct;
replaceMatch($createMentionNode(`@${acct}`));
replaceMatch($createMentionNode(acct));
}
dispatch(clearComposeSuggestions(composeId));