variable-picker-plugin.tsx
Overview
The variable-picker-plugin.tsx file implements a React component plugin for the Lexical rich text editor. This plugin enables a typeahead (autocomplete) menu that allows users to quickly insert predefined variables into the editor content by typing a trigger character (/). It supports filtering and selecting variables grouped under categories and converts matching text patterns into specialized variable nodes inside the editor.
Main functionalities include:
Displaying a categorized dropdown list of variable options when triggered.
Filtering variable options based on user input.
Inserting selected variable nodes into the Lexical editor content.
Parsing an initial string value to convert embedded variable placeholders into variable nodes programmatically.
This plugin is designed to integrate seamlessly with Lexical's typeahead and node APIs, providing an intuitive UI for variable insertion within rich text.
Detailed Explanation
Classes
VariableInnerOption
Extends MenuOption from Lexical's typeahead plugin to represent an individual variable option.
Properties:
label: string- Display text for the option.value: string- Internal value/key for the variable.parentLabel: string | JSX.Element- The category or group label this variable belongs to.icon?: ReactNode- Optional icon displayed alongside the label.
Constructor:
constructor( label: string, value: string, parentLabel: string | JSX.Element, icon?: ReactNode, )Initializes the option with label, value, parent category, and optional icon.
Usage:
Represents a selectable variable in the dropdown menu.
VariableOption
Extends MenuOption to represent a grouped variable category containing multiple VariableInnerOptions.
Properties:
label: ReactElement | string- Display label for the group.title: string- Title of the group.options: VariableInnerOption[]- List of variables under this group.
Constructor:
constructor( label: ReactElement | string, title: string, options: VariableInnerOption[], )Initializes a grouped option with a label, title, and options.
Usage:
Used to organize variable options into categories for display.
Functional Components and Functions
VariablePickerMenuItem
A React component rendering a single grouped variable option and its inner variable items.
Props:
{ index: number; option: VariableOption; selectOptionAndCleanUp: (option: VariableOption | VariableInnerOption) => void; }index: Index of the option in the list.option: TheVariableOptiongroup to render.selectOptionAndCleanUp: Callback to invoke when an inner option is selected.
Functionality:
Renders the group title and a nested list of clickable variable options.
On clicking an inner option, calls
selectOptionAndCleanUpwith the selected variable.
Usage Example:
Used internally by the main plugin component to render each group option.
VariablePickerMenuPlugin
The main exported React component providing the typeahead variable picker plugin.
Props:
{ value?: string; // Optional initial text containing variable placeholders. }State:
queryString: string | null- The current query string typed after the trigger.isFirstRender: React.RefObject<boolean>- Tracks if this is the first render to parse initial value.
Hooks and Utilities Used:
useLexicalComposerContext()- Accesses the Lexical editor instance.useBasicTypeaheadTriggerMatch('/')- Detects the/trigger for opening the typeahead menu.useBuildQueryVariableOptions()- Custom hook to get variable option groups from external source.Lexical APIs for node creation, selection, and editor updates.
Key Methods:
buildNextOptions: Filters and builds the variable options list based on the current query string.Filters inner options by matching label or value with a case-insensitive search of
queryString.Returns an array of
VariableOptioninstances with filteredVariableInnerOptions.
findItemByValue: Finds a variable option by its value string.Flattens all inner options and returns the first matching item.
onSelectOption: Handles selection of a variable option from the typeahead menu.Removes the matched text node if any.
Creates a new variable node using
$createVariableNodewith selected option data.Inserts the variable node at the current selection.
Closes the typeahead menu.
parseTextToVariableNodes: Parses an initial string to convert{variable}placeholders into variable nodes.Uses regex to find
{...}patterns.For each match, either inserts a variable node if it matches a known variable or inserts the raw text.
Clears the editor root and appends a new paragraph node with text and variable nodes.
Effect:
On first render, if an initial
valueprop is provided, parses and inserts variable nodes programmatically into the editor content.
Render:
Returns a
<LexicalTypeaheadMenuPlugin>component configured with:triggerFn: Detects/trigger.options: Current filtered options.onQueryChange: UpdatesqueryString.onSelectOption: Handles option selection.menuRenderFn: Renders the dropdown menu portal near the trigger element, usingVariablePickerMenuItemcomponents.
Important Implementation Details and Algorithms
Typeahead Triggering: Uses Lexical's
useBasicTypeaheadTriggerMatchhook configured for the/character with zero minimum length, enabling the menu to appear immediately after typing/.Dynamic Filtering: Implements client-side filtering of nested variable options based on user query, supporting partial and case-insensitive matching against both label and value.
Variable Node Creation: On selection, the plugin inserts a custom
VariableNode(defined externally) representing the variable, encapsulating the value, label, and icon for rich rendering.Initial Text Parsing: Supports programmatically converting a string containing
{variable}placeholders into editor content with variable nodes, enabling seamless initialization from serialized content.React Portals for Menu: Uses React portals to render the dropdown menu in a floating container anchored to the editor's UI, ensuring proper layering and positioning.
Performance Considerations: Memoizes filtering and lookup functions with
useCallbackto avoid unnecessary recalculations during typing.
Interaction with Other Parts of the System
Lexical Editor Integration: Tightly coupled with Lexical React and core APIs, this plugin acts as an extension to provide variable insertion capabilities.
Variable Node (
variable-node.ts): Relies on$createVariableNodeto instantiate custom variable nodes within the editor state.Data Source Hook (
useBuildQueryVariableOptions): Retrieves the list of available variable groups and variables, presumably fetching or computing from a higher-level data context (e.g., an agent or query builder page).Constants (
constant.ts): UsesProgrammaticTagfor Lexical update tagging to differentiate programmatic updates from user inputs.Styling (
index.css): Uses scoped CSS classes for styling the typeahead dropdown and menu items.
Usage Example
import VariablePickerMenuPlugin from './variable-picker-plugin';
function EditorWrapper() {
const initialValue = "Calculate sum of {totalAmount} and {tax}";
return (
<LexicalComposer initialConfig={{ /* editor config */ }}>
{/* Other plugins */}
<VariablePickerMenuPlugin value={initialValue} />
</LexicalComposer>
);
}
Typing / inside the editor will trigger the variable picker menu, allowing users to select and insert variables. The initial value string will be parsed and rendered with variable nodes on first render.
Visual Diagram
classDiagram
VariableInnerOption <|-- VariableOption
VariableOption o-- VariableInnerOption : contains
VariablePickerMenuPlugin ..> VariableOption : uses
VariablePickerMenuPlugin ..> VariableInnerOption : uses
VariablePickerMenuPlugin ..> LexicalTypeaheadMenuPlugin : composes
VariablePickerMenuItem --> VariableOption : renders
VariablePickerMenuItem --> VariableInnerOption : renders inner options
Summary
The variable-picker-plugin.tsx file provides a Lexical editor plugin that enhances user experience by enabling quick insertion of categorized variables via a / triggered typeahead menu. It supports filtering, selection, and programmatic initialization, integrating custom variable nodes seamlessly with the editor content. This plugin interacts with external hooks for options data, custom node creation, and editor state management, making it a reusable and extensible component within a Lexical-based rich text editing system.