lexical-beautiful-mentions

repository·main·Indexed 43 days ago

https://github.com/sodenn/lexical-beautiful-mentions

An advanced mentions plugin for the Lexical text editor featuring multiple triggers, async querying, and deep UI customization. It provides the BeautifulMentionsPlugin and BeautifulMentionNode to implement robust mention functionality with support for custom metadata, programmatic control via the useBeautifulMentions hook, and flexible styling through BeautifulMentionsTheme.

Tokens
12.2K
Snippets
35
Records
53
Agent score
54%

What's inside lexical-beautiful-mentions

  1. Overview of lexical-beautiful-mentions features

    main

    lexical-beautiful-mentions is an advanced mentions plugin for the Lexical editor. Key features include:

    • Customizable triggers: Use characters, words, or regular expressions.
    • Multiple triggers: Support for multiple triggers like @ and # simultaneously.
    • Programmatic control: Use the useBeautifulMentions hook to insert, delete, or rename mentions.
    • Automatic spacing: Automatically manages spaces around mentions for better typing flow.
    • Creation support: Ability to allow users to create new mentions not present in the suggestion list.
    • Async support: Use async query functions for fetching suggestion lists.
    • Metadata support: Attach additional metadata to mention items that persists during serialization.
    • High customizability: Customize mention styles via editor themes, replace mention nodes/components, and customize the suggestion menu and menu items.
  2. Add additional metadata to mentions

    main

    To uniquely identify mentions (e.g., by an ID), pass objects instead of strings in the items configuration. The extra properties will be stored in the data field of the BeautifulMentionNode during serialization.

    Example item structure:

    { value: "Catherine", id: "1", email: "catherine.a@example.com" }

    This metadata is accessible in the BeautifulMentionsMenuItemProps via item.data.

    const mentionItems = {
      "@": [
        { value: "Catherine", id: "1", email: "catherine.a@example.com" },
        { value: "Catherine", id: "2", email: "catherine.b@example.com" },
      ],
    };
    
    // Accessing in a custom menu item
    const CustomMenuItem = forwardRef<HTMLLIElement, BeautifulMentionsMenuItemProps>(
      ({ item: { data: { id, email }}, ...props }, ref) => (
        <li {...props} ref={ref}> {id} - {email} </li>
      )
    );
  3. Customize mention detection (punctuation and preTriggerChars)

    main

    You can adjust how the plugin detects mentions using two properties:

    1. punctuation: Defines characters that can follow a mention without being part of it (e.g., a period in @Alice.).
    2. preTriggerChars: Defines characters that can appear immediately before a trigger (e.g., (@Alice)).
  4. Use the BeautifulMentionsPlugin in Lexical

    main

    To implement mentions in a Lexical editor, you must:

    1. Register the BeautifulMentionNode in your editorConfig.nodes array.
    2. Use RichTextPlugin to ensure clipboard support.
    3. Add the BeautifulMentionsPlugin to your LexicalComposer and provide an items object mapping triggers to suggestion arrays.

    Example triggers and items:

    const mentionItems = {
      "@": ["Anton", "Boris"],
      "#": ["Apple", "Banana"],
      "due:": ["Today", "Tomorrow"]
    };
    import { BeautifulMentionsPlugin, BeautifulMentionNode } from "lexical-beautiful-mentions";
    import { LexicalComposer } from "@lexical/react/LexicalComposer";
    import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
    
    const mentionItems = {
      "@": ["Anton", "Boris", "Catherine", "Dmitri", "Elena", "Felix", "Gina"],
      "#": ["Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig", "Grape"],
      "due:": ["Today", "Tomorrow", "01-01-2023"],
    };
    
    const editorConfig = {
      // ...
      nodes: [BeautifulMentionNode]
    };
    
    return (
      <LexicalComposer initialConfig={editorConfig}>
        <RichTextPlugin
          contentEditable={/* ... */}
          placeholder={/* ... */}
          ErrorBoundary={/* ... */}
        />
        <BeautifulMentionsPlugin items={mentionItems} />
      </LexicalComposer>
    );
  5. Define the structure of a mention item

    main

    A mention item can be a simple string or a complex object containing metadata.

    Type: BeautifulMentionsItem

    • string: A simple value (e.g., 'John').
    • object: { value: string; [key: string]: BeautifulMentionsItemData }. The value is the actual text inserted, and additional keys store metadata.

    Type: BeautifulMentionsItemData Metadata values must be one of: string | boolean | number | null.

    // Simple string item
    const item1: BeautifulMentionsItem = 'John';
    
    // Item with metadata
    const item2: BeautifulMentionsItem = {
      value: 'John',
      id: 123,
      isAdmin: true
    };
  6. How mention detection and triggers work

    main

    The plugin uses a regex-based strategy to detect when a user is typing a mention.

    1. Trigger Detection: It monitors text input for specific triggers (e.g., @).
    2. Regex Matching: The checkForMentions function uses a dynamically generated regex that accounts for preTriggerChars, punctuation, and whether allowSpaces is enabled.
    3. Match Result: When a match is found, it returns a MenuTextMatch containing the leadOffset (where the mention starts), the matchingString (the text to be replaced by the mention), and the replaceableString (the full text including the trigger).

    This mechanism ensures that mentions are only triggered when the character sequence follows valid word boundaries or punctuation rules defined in the plugin configuration.

  7. Customize mention style with BeautifulMentionsTheme

    main

    You can style mentions by defining a BeautifulMentionsTheme object and adding it to your Lexical editor's theme configuration.

    Keys in the theme object correspond to the trigger name (e.g., @). To style the focused state, append the Focused suffix (e.g., @Focused). For advanced styling, provide a configuration object containing trigger, value, container, and containerFocused classes.

    import { BeautifulMentionsTheme } from "lexical-beautiful-mentions";
    
    const beautifulMentionsTheme: BeautifulMentionsTheme = {
      "@": "px-1 mx-px ...",
      "@Focused": "outline-none shadow-md ...",
      "due:": {
        "trigger": "text-blue-400 ...",
        "value": "text-orange-400 ...",
        "container": "px-1 mx-px ...",
        "containerFocused": "outline-none shadow-md ...",
      },
    };
    
    const editorConfig = {
      // ...
      theme: {
        // ...
        beautifulMentions: beautifulMentionsTheme,
      },
    };
  8. Integrate BeautifulMentionsPlugin into Lexical

    main

    The BeautifulMentionsPlugin is the primary component used to add mention functionality to a Lexical editor. It handles trigger detection, menu rendering, and mention insertion.

    To use it, include it within your LexicalComposer context. You must ensure that BeautifulMentionNode is registered in your editor configuration, otherwise the plugin will throw an error.

    Key configuration options include:

    • items: An object containing available mention items.
    • onSearch: An async function to fetch results based on a query string.
    • triggers: An array of strings that act as mention triggers (e.g., ['@', '#']).
    • creatable: Allows users to create new mentions from the query string. Can be a boolean or a string template like "Add {{name}}".
    • menuComponent / menuItemComponent: Custom React components for rendering the menu and its items (defaults to ul and li).
    import { BeautifulMentionsPlugin } from 'lexical-beautiful-mentions';
    
    // Inside your Lexical editor setup:
    <BeautifulMentionsPlugin
      items={{
        '@': [
          { value: 'john', displayValue: 'John Doe', data: { id: '1' } },
        ]
      }}
      onSearch={async (query) => {
        // Fetch your data here
      }}
      triggers={['@']}
    />
  9. Implement async mention queries

    main

    To fetch mentions from an external API, use the onSearch and triggers props on BeautifulMentionsPlugin.

    • onSearch: An async function receiving (trigger, query) and returning an array of strings or objects.
    • triggers: An array of trigger characters (e.g., ['@', '#']) that tells the plugin when to invoke the search function.
    const queryMentions = async (trigger: string, query: string) => {
      const response = await fetch(`https://example.com/api/mentions?trigger=${trigger}&query=${query}`);
      const data = await response.json();
      return data as string[];
    };
    
    <BeautifulMentionsPlugin
      triggers={["@", "#"]}
      onSearch={queryMentions}
    />
  10. Programmatically manage mentions with useBeautifulMentions

    main

    Use the useBeautifulMentions hook to interact with mentions from outside the plugin (e.g., in a toolbar).

    Available methods:

    • insertMention({ trigger, value }): Inserts a new mention.
    • removeMentions({ trigger, value }): Removes a specific mention.
    import { useBeautifulMentions } from "lexical-beautiful-mentions";
    
    function MentionsToolbar() {
      const { removeMentions, insertMention } = useBeautifulMentions();
      return (
        <div className="grid gap-2 grid-cols-2">
          <Button onClick={() => removeMentions({ trigger: "#", value: "urgent" })}>Remove</Button>
          <Button onClick={() => insertMention({ trigger: "#", value: "work" })}>Insert</Button>
        </div>
      );
    }