import type { Renderable, Signal, TNode, Value } from '@tempots/dom'; import type { Merge } from '@tempots/std'; import type { LexicalEditor, LexicalNode, Klass } from 'lexical'; import type { InputOptions } from '../components/form/input/input-options'; import type { ControlSize } from '../components/theme'; /** * Content format types supported by the editor */ export type ContentFormatType = 'markdown' | 'json' | 'html'; /** * JSON-based content (Lexical's serialized state) */ export type JsonContent = Record; /** * Plugin definition for Lexical editor */ export interface LexicalPluginDefinition { /** * Unique name for the plugin */ name: string; /** * Custom Lexical nodes this plugin provides */ nodes?: Klass[]; /** * Registration function called when plugin is initialized * @param editor - The Lexical editor instance * @returns Optional cleanup function */ register: (editor: LexicalEditor) => (() => void) | void; } /** * Configuration for built-in editor plugins */ export interface PluginConfig { /** * Enable rich text features (bold, italic, etc.) */ richText?: boolean; /** * Enable plain text mode (no formatting) */ plainText?: boolean; /** * Enable undo/redo history */ history?: boolean | HistoryPluginOptions; /** * Enable list support (ul, ol) */ list?: boolean; /** * Enable table support */ table?: boolean | TablePluginOptions; /** * Enable link support */ link?: boolean; /** * Enable automatic link detection */ autoLink?: boolean | AutoLinkPluginOptions; /** * Enable code block support */ code?: boolean | CodePluginOptions; /** * Enable Shiki syntax highlighting for code blocks */ codeShiki?: boolean; /** * Enable hashtag support */ hashtag?: boolean | HashtagPluginOptions; /** * Enable mark/annotation support */ mark?: boolean; /** * Enable overflow detection */ overflow?: boolean | OverflowPluginOptions; /** * Enable clipboard handling */ clipboard?: boolean; /** * Enable dragon drop support */ dragon?: boolean; /** * Enable slash commands */ slashCommands?: boolean | SlashCommandPluginOptions; /** * Enable markdown import/export */ markdownIO?: boolean; /** * Enable HTML import/export */ htmlIO?: boolean; /** * Enable file operations */ fileIO?: boolean; /** * Enable Yjs collaborative editing */ yjs?: CollaborationConfig; } /** * Options for the history plugin */ export interface HistoryPluginOptions { /** * Delay before creating a new history entry (ms) * @default 300 */ delay?: number; /** * Maximum number of history entries to keep * @default 100 */ maxDepth?: number; } /** * Options for the table plugin */ export interface TablePluginOptions { /** * Allow nested tables * @default false */ allowNesting?: boolean; /** * Default number of rows for new tables * @default 3 */ defaultRows?: number; /** * Default number of columns for new tables * @default 3 */ defaultColumns?: number; } /** * Options for the auto-link plugin */ export interface AutoLinkPluginOptions { /** * Custom matchers for auto-linking */ matchers?: AutoLinkMatcher[]; } /** * Auto-link matcher definition */ export interface AutoLinkMatcher { /** * Regular expression pattern to match */ pattern: RegExp; /** * Transform matched text into a URL * @param match - The matched text * @returns The URL to link to */ urlTransformer: (match: string) => string; } /** * Options for the code plugin */ export interface CodePluginOptions { /** * Supported programming languages */ languages?: string[]; /** * Use Shiki for syntax highlighting * @default false */ useShiki?: boolean; } /** * Options for the hashtag plugin */ export interface HashtagPluginOptions { /** * Callback when a hashtag is clicked * @param hashtag - The hashtag text (without #) */ onHashtagClick?: (hashtag: string) => void; } /** * Options for the overflow plugin */ export interface OverflowPluginOptions { /** * Maximum character length */ maxLength: number; /** * Callback when overflow state changes * @param isOverflowing - Whether content exceeds the limit * @param currentLength - Current character count */ onOverflow?: (isOverflowing: boolean, currentLength: number) => void; } /** * Options for the slash commands plugin */ export interface SlashCommandPluginOptions { /** * Custom slash commands */ commands?: SlashCommandDefinition[]; /** * Replace default commands instead of extending * @default false */ replaceDefaults?: boolean; /** * Trigger character for commands * @default '/' */ trigger?: string; } /** * Slash command definition */ export interface SlashCommandDefinition { /** * Unique identifier for the command */ id: string; /** * Display label */ label: string; /** * Optional description */ description?: string; /** * Optional icon (emoji or HTML) */ icon?: string | TNode; /** * Keywords for searching */ keywords?: string[]; /** * Category for grouping */ category?: string; /** * Handler function when command is executed * @param editor - The Lexical editor instance */ handler: (editor: LexicalEditor) => void; } /** * Font option for toolbar dropdowns */ export interface FontOption { /** * CSS value (e.g. 'Arial', '14px'). Empty string means default/inherit. */ value: string; /** * Display label shown in the dropdown */ label: string; } /** * Toolbar group identifiers */ export type ToolbarGroupId = 'text-formatting' | 'headings' | 'lists' | 'indent' | 'blocks' | 'tables' | 'links' | 'history' | 'clipboard' | 'font' | 'color' | 'clear-formatting'; /** * Stable identifiers for individual toolbar buttons/controls. * Each ID corresponds to a single button or widget within a toolbar group. */ export type ToolbarButtonId = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'code' | 'clear-formatting' | 'paragraph' | 'heading-1' | 'heading-2' | 'heading-3' | 'heading-4' | 'heading-5' | 'heading-6' | 'bullet-list' | 'ordered-list' | 'check-list' | 'indent' | 'outdent' | 'blockquote' | 'code-block' | 'horizontal-rule' | 'insert-table' | 'link' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'font-family' | 'font-size' | 'line-height' | 'font-color' | 'highlight-color' | 'background-color'; /** * Context passed to custom toolbar items, providing access to editor state, * reactive signals, and the built-in button factory. */ export interface ToolbarItemContext { /** Editor signal (guaranteed non-null inside the toolbar) */ editor: Signal; /** Incremented on every editor state update — use in `.map()` for reactive queries */ stateUpdate: Signal; /** Whether the editor is read-only */ readOnly: Signal; /** Control size */ size: Value; /** Create a toolbar button matching built-in styling */ button: (opts: { active?: Signal; onClick: () => void; label: Value; icon: string; }) => TNode; } /** * A custom icon button toolbar item, rendered identically to built-in buttons. */ export interface ToolbarButtonItem { type: 'button'; /** Unique id (must not collide with built-in ToolbarButtonId values) */ id: string; /** Accessible tooltip label */ label: string; /** Iconify icon identifier (e.g. 'mdi:variable') */ icon: string; /** Called when the button is clicked */ onClick: (editor: LexicalEditor) => void; /** Optional reactive active state. Return a signal that tracks whether this button is "on". */ active?: (ctx: ToolbarItemContext) => Signal; } /** * A single option in a select dropdown toolbar item. */ export interface ToolbarSelectOption { /** Value passed to onSelect when this option is chosen */ value: string; /** Display label in the dropdown */ label: string; } /** * A select dropdown toolbar item: renders a `