UNPKG

@liveblocks/react-ui

Version:

A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.

1 lines 9.96 kB
{"version":3,"file":"mentions.cjs","sources":["../../../src/slate/plugins/mentions.ts"],"sourcesContent":["import type { Node as SlateNode } from \"slate\";\nimport {\n Editor as SlateEditor,\n Element as SlateElement,\n Range as SlateRange,\n Transforms as SlateTransforms,\n} from \"slate\";\n\nimport type { ComposerBodyMention } from \"../../types\";\nimport { getCharacterAfter, getCharacterBefore } from \"../utils/get-character\";\nimport { getMatchRange } from \"../utils/get-match-range\";\nimport { isEmptyString } from \"../utils/is-empty-string\";\nimport { isWhitespaceCharacter } from \"../utils/is-whitespace-character\";\n\nexport const MENTION_CHARACTER = \"@\";\n\nexport type MentionDraft = {\n range: SlateRange;\n text: string;\n};\n\nexport function getMentionDraftAtSelection(\n editor: SlateEditor\n): MentionDraft | undefined {\n const { selection } = editor;\n\n if (!selection || !SlateRange.isCollapsed(selection)) {\n return;\n }\n\n // Walk backwards from the selection until \"@\" is found, unless the character\n // before isn't whitespace (or \"@\" is the block's first character)\n const match = getMatchRange(editor, selection, [\"@\"], {\n include: true,\n allowConsecutiveWhitespace: false,\n ignoreTerminator: (_, point) => {\n const characterBefore = getCharacterBefore(editor, point);\n\n // Ignore \"@\" if it's preceded by a non-whitespace character\n if (characterBefore && !isWhitespaceCharacter(characterBefore.text)) {\n return true;\n }\n\n return false;\n },\n });\n\n if (!match) {\n return;\n }\n\n const matchText = SlateEditor.string(editor, match);\n\n // Check if the match starts with the mention character (not followed by a whitespace character)\n if (\n !matchText.startsWith(MENTION_CHARACTER) ||\n (matchText.length > 1 && isWhitespaceCharacter(matchText[1]))\n ) {\n return;\n }\n\n return {\n range: match,\n // Exclude the mention character from the text\n text: matchText.substring(1),\n };\n}\n\nexport function isComposerBodyMention(\n node: SlateNode\n): node is ComposerBodyMention {\n return SlateElement.isElement(node) && node.type === \"mention\";\n}\n\nexport function insertMention(editor: SlateEditor, userId: string) {\n const mention: ComposerBodyMention = {\n type: \"mention\",\n id: userId,\n children: [{ text: \"\" }],\n };\n\n // Insert the mention\n SlateTransforms.insertNodes(editor, mention);\n SlateTransforms.move(editor);\n\n const afterCharacter = editor.selection\n ? getCharacterAfter(editor, editor.selection)\n : undefined;\n\n if (!afterCharacter || afterCharacter.void) {\n // Insert a following space if needed\n SlateTransforms.insertText(editor, \" \");\n } else if (isEmptyString(afterCharacter.text)) {\n // Move the selection if it's already followed by a space\n SlateTransforms.move(editor);\n }\n}\n\nexport function insertMentionCharacter(editor: SlateEditor) {\n if (!editor.selection) {\n return;\n }\n\n // Check if the selection is preceded or followed by a non-whitespace character\n const beforeCharacter = getCharacterBefore(editor, editor.selection, {\n filterVoids: true,\n });\n const afterCharacter = getCharacterAfter(editor, editor.selection, {\n filterVoids: true,\n });\n const shouldInsertSpaceBefore =\n beforeCharacter && !isEmptyString(beforeCharacter.text);\n const shouldInsertSpaceAfter =\n afterCharacter && !isEmptyString(afterCharacter.text);\n\n if (!SlateRange.isCollapsed(editor.selection)) {\n const text =\n (shouldInsertSpaceBefore ? \" \" : \"\") +\n MENTION_CHARACTER +\n (shouldInsertSpaceAfter ? \" \" : \"\");\n\n // If the selection is collapsed, insert the mention character at the current selection\n editor.insertText(text);\n\n // If a following space was inserted, move the selection back by one\n if (shouldInsertSpaceAfter) {\n SlateTransforms.move(editor, {\n distance: 1,\n unit: \"character\",\n reverse: true,\n });\n }\n } else {\n const beforeText = (shouldInsertSpaceBefore ? \" \" : \"\") + MENTION_CHARACTER;\n\n // If the selection is not collapsed, insert the mention character before the selection\n editor.insertText(beforeText, { at: SlateRange.start(editor.selection) });\n\n if (shouldInsertSpaceAfter) {\n editor.insertText(\" \", { at: SlateRange.end(editor.selection) });\n }\n\n // Collapse the selection at its end\n SlateTransforms.collapse(editor, { edge: \"end\" });\n }\n}\n\nexport function withMentions<T extends SlateEditor>(editor: T): T {\n const { isInline, isVoid, markableVoid, deleteBackward } = editor;\n\n editor.isInline = (element) => {\n return isComposerBodyMention(element) || isInline(element);\n };\n\n editor.isVoid = (element) => {\n return isComposerBodyMention(element) || isVoid(element);\n };\n\n editor.markableVoid = (element) => {\n return isComposerBodyMention(element) || markableVoid(element);\n };\n\n editor.deleteBackward = (unit) => {\n const { selection } = editor;\n\n if (selection && SlateRange.isCollapsed(selection)) {\n const [mention] = SlateEditor.nodes(editor, {\n at:\n unit === \"character\"\n ? SlateEditor.before(editor, selection, { unit: \"character\" })\n : selection,\n match: isComposerBodyMention,\n });\n\n deleteBackward(unit);\n\n if (mention) {\n SlateTransforms.insertText(editor, MENTION_CHARACTER);\n }\n } else {\n deleteBackward(unit);\n }\n };\n\n return editor;\n}\n"],"names":["SlateRange","getMatchRange","getCharacterBefore","isWhitespaceCharacter","SlateEditor","SlateElement","SlateTransforms","getCharacterAfter","isEmptyString"],"mappings":"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"}