Make MentionNode a DecoratorNode instead of a TextNode
This commit is contained in:
parent
1ba1584da8
commit
964ba8c758
4 changed files with 105 additions and 75 deletions
|
@ -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',
|
||||
|
|
|
@ -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 };
|
103
src/features/compose/editor/nodes/mention-node.tsx
Normal file
103
src/features/compose/editor/nodes/mention-node.tsx
Normal 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 };
|
|
@ -328,7 +328,7 @@ const AutosuggestPlugin = ({
|
|||
node.select();
|
||||
} else {
|
||||
const acct = selectAccount(getState(), suggestion)!.acct;
|
||||
replaceMatch($createMentionNode(`@${acct}`));
|
||||
replaceMatch($createMentionNode(acct));
|
||||
}
|
||||
|
||||
dispatch(clearComposeSuggestions(composeId));
|
||||
|
|
Loading…
Reference in a new issue