@lyfie/luthor 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,2311 +1,56 @@
1
- import * as lexical from 'lexical';
2
- import { TextFormatType, LexicalEditor, EditorThemeClasses, ParagraphNode, DecoratorNode, DOMConversionMap, NodeKey, EditorConfig as EditorConfig$1, DOMExportOutput, Spread, SerializedLexicalNode, LexicalNode, ElementNode, RangeSelection } from 'lexical';
3
- import React$1, { ReactNode, ComponentType, CSSProperties } from 'react';
4
- import * as react_jsx_runtime from 'react/jsx-runtime';
5
- import { Transformer } from '@lexical/markdown';
6
- import { CodeNode } from '@lexical/code';
7
- import { HeadingTagType, HeadingNode, QuoteNode } from '@lexical/rich-text';
8
- import * as _lexical_table from '@lexical/table';
9
- import * as _lexical_react_LexicalHorizontalRuleNode from '@lexical/react/LexicalHorizontalRuleNode';
1
+ import * as _lyfie_luthor_headless from '@lyfie/luthor-headless';
2
+ import { LinkExtension, TableExtension, ImageExtension, MarkdownExtension, HTMLEmbedExtension, FloatingToolbarExtension, ContextMenuExtension, CommandPaletteExtension, DraggableBlockExtension, Extension, EditorConfig, LuthorTheme } from '@lyfie/luthor-headless';
3
+ import React from 'react';
10
4
 
11
- /** Extension category buckets */
12
- declare enum ExtensionCategory {
13
- Toolbar = "toolbar",
14
- Sidebar = "sidebar",
15
- ContextMenu = "contextmenu",
16
- Floating = "floating"
17
- }
18
- /** Shared base config for extensions */
19
- interface BaseExtensionConfig {
20
- showInToolbar?: boolean;
21
- category?: ExtensionCategory[];
22
- position?: "before" | "after";
23
- /** Initialization priority; higher registers first (default: 0) */
24
- initPriority?: number;
25
- [key: string]: any;
26
- }
27
- /** Toolbar item configuration */
28
- interface ToolbarItem {
29
- label: string;
30
- onClick: () => void;
31
- isActive?: () => boolean;
32
- component?: React.ComponentType<any>;
33
- }
34
- /**
35
- * Core extension contract implemented by all extensions.
36
- * Defines the required API surface for Luthor extensions.
37
- *
38
- * @template Name - Exact literal type of the extension name
39
- * @template Config - Extension configuration type
40
- * @template Commands - Command map exposed by the extension
41
- * @template StateQueries - State query function map
42
- * @template Plugins - React plugins exposed by the extension
43
- */
44
- interface Extension<Name extends string = string, Config extends BaseExtensionConfig = BaseExtensionConfig, Commands extends Record<string, any> = {}, StateQueries extends Record<string, () => Promise<boolean>> = {}, Plugins extends ReactNode[] = ReactNode[]> {
45
- /** Unique identifier for this extension */
46
- name: Name;
47
- /** Category groups for this extension */
48
- category: ExtensionCategory[];
49
- /** Extension configuration */
50
- config: Config;
51
- /** Supported text formats */
52
- supportedFormats?: readonly TextFormatType[];
53
- /** Update extension settings */
54
- configure?: (config: Partial<Config>) => Extension<Name, Config, Commands, StateQueries, Plugins>;
55
- /** Register the extension with Lexical */
56
- register: (editor: LexicalEditor) => () => void;
57
- /** Override the extension UI component */
58
- overrideUI?: (CustomUI: ComponentType<{
59
- selected?: boolean;
60
- className?: string;
61
- style?: CSSProperties;
62
- [key: string]: any;
63
- }>) => Extension<Name, Config, Commands, StateQueries, Plugins>;
64
- /** Override node rendering logic */
65
- overrideNodeRender?: (overrides: {
66
- createDOM?: (config: any) => HTMLElement;
67
- updateDOM?: (prev: any, next: any, dom: HTMLElement) => boolean;
68
- }) => Extension<Name, Config, Commands, StateQueries, Plugins>;
69
- /** Return custom Lexical nodes */
70
- getNodes?: () => any[];
71
- /** Return React plugins */
72
- getPlugins: () => Plugins;
73
- /** Provide commands exposed by the extension */
74
- getCommands: (editor: LexicalEditor) => Commands;
75
- /** Return state query functions */
76
- getStateQueries?: (editor: LexicalEditor) => StateQueries;
77
- }
78
- type MergeCommands<T> = {
79
- [K in UnionKeys<T>]: T extends {
80
- [P in K]: infer V;
81
- } ? V : never;
82
- };
83
- type MergeStateQueries<T> = {
84
- [K in UnionKeys<T>]: boolean;
85
- };
86
- type ExtractNames<Exts extends readonly Extension[]> = Exts[number]["name"];
87
- type ExtractCommands<Exts extends readonly Extension[]> = MergeCommands<ReturnType<Exts[number]["getCommands"]>>;
88
- type ExtractPlugins<Exts extends readonly Extension[]> = ReturnType<Exts[number]["getPlugins"]>[number];
89
- type UnionKeys<T> = T extends unknown ? keyof T : never;
90
- type ExtractStateQueries<Exts extends readonly Extension[]> = MergeStateQueries<ReturnType<NonNullable<Exts[number]["getStateQueries"]>>>;
91
- interface BaseCommands {
92
- formatText: (format: TextFormatType, value?: boolean | string) => void;
93
- }
94
- /**
95
- * Editor system context type, parameterized by the extensions array.
96
- * Exposes typed commands, state, and utilities.
97
- *
98
- * @template Exts - Extensions array that defines available functionality
99
- */
100
- interface EditorContextType<Exts extends readonly Extension[]> {
101
- /** Underlying Lexical editor instance */
102
- editor: LexicalEditor | null;
103
- /** Editor settings */
104
- config?: EditorConfig;
105
- /** Loaded extensions list */
106
- extensions: Exts;
107
- /** Commands available from all extensions */
108
- commands: BaseCommands & ExtractCommands<Exts>;
109
- /** Current state for all extensions */
110
- activeStates: ExtractStateQueries<Exts>;
111
- /** State query functions from extensions */
112
- stateQueries: Record<string, () => Promise<any>>;
113
- /** Event listener registration */
114
- listeners: {
115
- registerUpdate: (listener: (state: any) => void) => (() => void) | undefined;
116
- registerPaste: (listener: (event: ClipboardEvent) => boolean) => (() => void) | undefined;
117
- };
118
- /** Export helpers for formats */
119
- export: {
120
- toHTML: () => Promise<string>;
121
- toMarkdown: () => Promise<string>;
122
- toJSON: () => any;
123
- };
124
- /** Import helpers for formats */
125
- import: {
126
- fromHTML: (html: string) => Promise<void>;
127
- fromMarkdown: (md: string) => Promise<void>;
128
- fromJSON: (json: any) => void;
129
- };
130
- /** Alias of the raw Lexical editor */
131
- lexical: LexicalEditor | null;
132
- /** Dynamic extensions API */
133
- extensionsAPI: {
134
- add: (ext: Extension) => void;
135
- remove: (name: string) => void;
136
- reorder: (names: string[]) => void;
137
- };
138
- /** React plugins collected from extensions */
139
- plugins: ExtractPlugins<Exts>[];
140
- /** Check whether a specific extension is loaded */
141
- hasExtension: (name: ExtractNames<Exts>) => boolean;
142
- }
143
- interface EditorConfig {
144
- theme?: EditorThemeClasses;
145
- [key: string]: any;
146
- }
5
+ declare const blogPreset: EditorPreset;
147
6
 
148
- interface ProviderProps<Exts extends readonly Extension[]> {
149
- children: ReactNode;
150
- config?: EditorConfig;
151
- extensions: Exts;
152
- }
153
- /**
154
- * Creates a typed editor system based on the provided extensions array.
155
- * This factory function generates a Provider component and useEditor hook
156
- * that are strongly typed based on the extensions passed to it.
157
- *
158
- * @template Exts - Array of extensions that define the editor's capabilities
159
- * @returns Object containing Provider component and useEditor hook
160
- *
161
- * @example
162
- * ```tsx
163
- * const extensions = [boldExtension, italicExtension] as const;
164
- * const { Provider, useEditor } = createEditorSystem<typeof extensions>();
165
- * ```
166
- */
167
- declare function createEditorSystem<Exts extends readonly Extension[]>(): {
168
- Provider: (props: ProviderProps<Exts>) => react_jsx_runtime.JSX.Element;
169
- useEditor: () => EditorContextType<Exts>;
170
- };
171
- declare const BaseProvider: (props: ProviderProps<readonly Extension<string, BaseExtensionConfig, {}, {}, React$1.ReactNode[]>[]>) => react_jsx_runtime.JSX.Element;
172
- declare const useBaseEditor: () => EditorContextType<any>;
7
+ declare const chatPreset: EditorPreset;
173
8
 
174
- /**
175
- * Abstract base class for all Luthor extensions.
176
- * Provides default implementations and shared extension behavior.
177
- *
178
- * @template Name - Literal extension name
179
- * @template Config - Configuration object type
180
- * @template Commands - Commands exposed by this extension
181
- * @template StateQueries - State query functions exposed by this extension
182
- * @template Plugins - React plugins/components exposed by this extension
183
- */
184
- declare abstract class BaseExtension<Name extends string = string, Config extends BaseExtensionConfig = BaseExtensionConfig, Commands extends Record<string, any> = {}, StateQueries extends Record<string, () => Promise<boolean>> = {}, Plugins extends ReactNode[] = ReactNode[]> implements Extension<Name, Config, Commands, StateQueries, Plugins> {
185
- /** Unique name identifier for this extension */
186
- name: Name;
187
- /** Categories this extension belongs to (toolbar, sidebar, etc.) */
188
- category: ExtensionCategory[];
189
- /** Configuration for this extension */
190
- config: Config;
191
- /** Text formats supported by this extension */
192
- supportedFormats: readonly TextFormatType[];
193
- /** Node rendering overrides */
194
- nodeOverrides: {
195
- createDOM?: (config: any) => HTMLElement;
196
- updateDOM?: (prev: any, next: any, dom: HTMLElement) => boolean;
197
- };
198
- /**
199
- * Creates a new extension instance.
200
- *
201
- * @param name - Unique name for this extension
202
- * @param category - Categories this extension belongs to
203
- */
204
- constructor(name: Name, category?: ExtensionCategory[]);
205
- /**
206
- * Configures the extension with new settings.
207
- * Returns the instance with updated configuration.
208
- *
209
- * @param config - Partial configuration to merge into existing config
210
- * @returns Extension instance with updated config
211
- */
212
- configure(config: Partial<Config>): Extension<Name, Config, Commands, StateQueries, Plugins>;
213
- /**
214
- * Registers the extension with the Lexical editor.
215
- * Override to set up event listeners, commands, etc.
216
- *
217
- * @param editor - Lexical editor instance
218
- * @returns Cleanup function to unregister the extension
219
- */
220
- abstract register(editor: LexicalEditor): () => void;
221
- /**
222
- * Returns custom Lexical nodes exposed by this extension.
223
- *
224
- * @returns Array of Lexical node classes
225
- */
226
- getNodes(): any[];
227
- /**
228
- * Allows overriding the UI component used for this extension.
229
- *
230
- * @param CustomUI - Custom React component to render
231
- * @returns Extension instance for chaining
232
- */
233
- overrideUI(CustomUI: ComponentType<{
234
- selected?: boolean;
235
- className?: string;
236
- style?: CSSProperties;
237
- [key: string]: any;
238
- }>): Extension<Name, Config, Commands, StateQueries, Plugins>;
239
- /**
240
- * Overrides node rendering behavior.
241
- *
242
- * @param overrides - DOM creation and update handlers
243
- * @returns Extension instance for chaining
244
- */
245
- overrideNodeRender(overrides: {
246
- createDOM?: (config: any) => HTMLElement;
247
- updateDOM?: (prev: any, next: any, dom: HTMLElement) => boolean;
248
- }): Extension<Name, Config, Commands, StateQueries, Plugins>;
249
- /**
250
- * Returns React plugins/components exposed by this extension.
251
- *
252
- * @returns Array of React nodes to render
253
- */
254
- getPlugins(): Plugins;
255
- /**
256
- * Returns commands exposed by this extension.
257
- *
258
- * @param editor - Lexical editor instance
259
- * @returns Object containing command functions
260
- */
261
- getCommands(editor: LexicalEditor): Commands;
262
- /**
263
- * Returns state query functions exposed by this extension.
264
- *
265
- * @param editor - Lexical editor instance
266
- * @returns Object containing state query functions
267
- */
268
- getStateQueries(editor: LexicalEditor): StateQueries;
269
- /**
270
- * Returns toolbar items contributed by this extension.
271
- *
272
- * @param commands - Available commands from all extensions
273
- * @returns Array of toolbar item configurations
274
- */
275
- getToolbarItems(commands: any): ToolbarItem[];
276
- }
9
+ declare const classicPreset: EditorPreset;
277
10
 
278
- /**
279
- * Configuration options for creating a custom extension
280
- */
281
- interface CreateExtensionConfig<Name extends string, Config extends BaseExtensionConfig = BaseExtensionConfig, Commands extends Record<string, any> = {}, StateQueries extends Record<string, () => Promise<boolean>> = {}, Plugins extends ReactNode[] = ReactNode[]> {
282
- /** Unique name for the extension */
283
- name: Name;
284
- /** Categories this extension belongs to */
285
- category?: ExtensionCategory[];
286
- /** Default configuration */
287
- config?: Partial<Config>;
288
- /** Commands provided by this extension */
289
- commands?: (editor: LexicalEditor) => Commands;
290
- /** State query functions */
291
- stateQueries?: (editor: LexicalEditor) => StateQueries;
292
- /** React plugins/components */
293
- plugins?: Plugins;
294
- /** Initialization function called when extension is registered */
295
- initialize?: (editor: LexicalEditor) => (() => void) | void;
296
- /** Custom Lexical nodes */
297
- nodes?: any[];
298
- /** Text formats supported by this extension */
299
- supportedFormats?: readonly any[];
300
- }
301
- /**
302
- * Factory function to create a type-safe extension that extends BaseExtension.
303
- * Provides a simpler API for creating extensions while maintaining full type safety.
304
- *
305
- * @template Name - Literal type for the extension name
306
- * @template Config - Configuration object type
307
- * @template Commands - Commands provided by the extension
308
- * @template StateQueries - State query functions
309
- * @template Plugins - React plugins provided by the extension
310
- *
311
- * @param config - Configuration object for the extension
312
- * @returns A fully typed extension instance
313
- *
314
- * @example
315
- * ```tsx
316
- * const myExtension = createExtension({
317
- * name: 'my-extension',
318
- * commands: (editor) => ({
319
- * myCommand: () => console.log('Hello!')
320
- * }),
321
- * stateQueries: (editor) => ({
322
- * isActive: async () => true
323
- * }),
324
- * initialize: (editor) => {
325
- * // Custom initialization
326
- * return () => {
327
- * // Cleanup function
328
- * };
329
- * }
330
- * });
331
- * ```
332
- */
333
- declare function createExtension<Name extends string, Config extends BaseExtensionConfig = BaseExtensionConfig, Commands extends Record<string, any> = {}, StateQueries extends Record<string, () => Promise<boolean>> = {}, Plugins extends ReactNode[] = ReactNode[]>(config: CreateExtensionConfig<Name, Config, Commands, StateQueries, Plugins>): BaseExtension<Name, Config, Commands, StateQueries, Plugins>;
11
+ declare const cmsPreset: EditorPreset;
334
12
 
335
- /**
336
- * Enhanced theme type that extends Lexical's EditorThemeClasses
337
- * with better TypeScript support and additional properties
338
- */
339
- interface LuthorTheme extends EditorThemeClasses {
340
- toolbar?: {
341
- button?: string;
342
- buttonActive?: string;
343
- buttonDisabled?: string;
344
- group?: string;
345
- };
346
- container?: string;
347
- wrapper?: string;
348
- contextMenu?: {
349
- container?: string;
350
- item?: string;
351
- itemDisabled?: string;
352
- };
353
- draggable?: {
354
- handle?: string;
355
- handleActive?: string;
356
- handleHover?: string;
357
- handleDragging?: string;
358
- blockDragging?: string;
359
- dropIndicator?: string;
360
- upButton?: string;
361
- downButton?: string;
362
- blockIsDragging?: string;
363
- buttonStack?: string;
364
- styles?: {
365
- handle?: React$1.CSSProperties;
366
- handleActive?: React$1.CSSProperties;
367
- handleHover?: React$1.CSSProperties;
368
- handleDragging?: React$1.CSSProperties;
369
- blockDragging?: React$1.CSSProperties;
370
- dropIndicator?: React$1.CSSProperties;
371
- upButton?: React$1.CSSProperties;
372
- downButton?: React$1.CSSProperties;
373
- blockIsDragging?: React$1.CSSProperties;
374
- buttonStack?: React$1.CSSProperties;
375
- };
376
- };
377
- floatingToolbar?: {
378
- container?: string;
379
- button?: string;
380
- buttonActive?: string;
381
- styles?: {
382
- container?: React$1.CSSProperties;
383
- button?: React$1.CSSProperties;
384
- buttonActive?: React$1.CSSProperties;
385
- };
386
- };
387
- htmlEmbed?: {
388
- container?: string;
389
- preview?: string;
390
- editor?: string;
391
- textarea?: string;
392
- toggle?: string;
393
- content?: string;
394
- styles?: {
395
- container?: React$1.CSSProperties;
396
- preview?: React$1.CSSProperties;
397
- editor?: React$1.CSSProperties;
398
- textarea?: React$1.CSSProperties;
399
- toggle?: React$1.CSSProperties;
400
- content?: React$1.CSSProperties;
401
- };
402
- };
403
- styles?: {
404
- toolbar?: {
405
- button?: React$1.CSSProperties;
406
- buttonActive?: React$1.CSSProperties;
407
- buttonDisabled?: React$1.CSSProperties;
408
- group?: React$1.CSSProperties;
409
- };
410
- container?: React$1.CSSProperties;
411
- wrapper?: React$1.CSSProperties;
412
- draggable?: {
413
- handle?: React$1.CSSProperties;
414
- handleHover?: React$1.CSSProperties;
415
- handleDragging?: React$1.CSSProperties;
416
- blockDragging?: React$1.CSSProperties;
417
- dropIndicator?: React$1.CSSProperties;
418
- upButton?: React$1.CSSProperties;
419
- downButton?: React$1.CSSProperties;
420
- blockIsDragging?: React$1.CSSProperties;
421
- buttonStack?: React$1.CSSProperties;
422
- };
423
- floatingToolbar?: {
424
- container?: React$1.CSSProperties;
425
- button?: React$1.CSSProperties;
426
- buttonActive?: React$1.CSSProperties;
427
- };
428
- htmlEmbed?: {
429
- container?: React$1.CSSProperties;
430
- preview?: React$1.CSSProperties;
431
- editor?: React$1.CSSProperties;
432
- textarea?: React$1.CSSProperties;
433
- toggle?: React$1.CSSProperties;
434
- content?: React$1.CSSProperties;
435
- };
436
- };
437
- }
438
- /**
439
- * Default Luthor theme with sensible defaults
440
- */
441
- declare const defaultLuthorTheme: LuthorTheme;
442
- /**
443
- * Helper function to merge themes
444
- */
445
- declare function mergeThemes(baseTheme: LuthorTheme, overrideTheme: Partial<LuthorTheme>): LuthorTheme;
446
- /**
447
- * Type guard to check if a theme is a LuthorTheme
448
- */
449
- declare function isLuthorTheme(theme: any): theme is LuthorTheme;
13
+ declare const codePreset: EditorPreset;
450
14
 
451
- /**
452
- * Commands exposed by text format extensions.
453
- * Generates toggle commands for text formatting (e.g., toggleBold, toggleItalic).
454
- */
455
- type TextFormatCommands<Name extends TextFormatType> = {
456
- [Key in `toggle${Capitalize<Name>}`]: () => void;
457
- };
458
- /**
459
- * Base extension for text formatting (bold, italic, underline, etc.).
460
- * Provides shared functionality for text format extensions.
461
- *
462
- * @template Name - Text format name (e.g., 'bold', 'italic')
463
- */
464
- declare abstract class TextFormatExtension<Name extends TextFormatType> extends BaseExtension<Name, any, TextFormatCommands<Name>, Record<Name, () => Promise<boolean>>, ReactNode[]> {
465
- /**
466
- * Creates a new text format extension instance.
467
- *
468
- * @param name - Text format name
469
- */
470
- constructor(name: Name);
471
- /**
472
- * Registers the extension with the editor.
473
- * Text format extensions register listeners for INSERT_PARAGRAPH_COMMAND and INSERT_LINE_BREAK_COMMAND
474
- * to handle formatting behavior when Enter/Shift+Enter is pressed.
475
- *
476
- * @param editor - Lexical editor instance
477
- * @returns Cleanup function
478
- */
479
- register(editor: LexicalEditor): () => void;
480
- /**
481
- * Returns the toggle command for this text format.
482
- *
483
- * @param editor - Lexical editor instance
484
- * @returns Object with toggle command function
485
- */
486
- getCommands(editor: LexicalEditor): TextFormatCommands<Name>;
487
- /**
488
- * Returns a state query to check if the selection has this format applied.
489
- *
490
- * @param editor - Lexical editor instance
491
- * @returns Object with format state query function
492
- */
493
- getStateQueries(editor: LexicalEditor): Record<Name, () => Promise<boolean>>;
494
- }
15
+ declare const defaultPreset: EditorPreset;
495
16
 
496
- /**
497
- * Bold text formatting extension.
498
- * Provides bold text formatting functionality with toggle command and state tracking.
499
- *
500
- * @example
501
- * ```tsx
502
- * const extensions = [boldExtension] as const;
503
- * const { Provider, useEditor } = createEditorSystem<typeof extensions>();
504
- *
505
- * function MyEditor() {
506
- * const { commands, activeStates } = useEditor();
507
- * return (
508
- * <button
509
- * onClick={() => commands.toggleBold()}
510
- * className={activeStates.bold ? 'active' : ''}
511
- * >
512
- * Bold
513
- * </button>
514
- * );
515
- * }
516
- * ```
517
- */
518
- declare class BoldExtension extends TextFormatExtension<"bold"> {
519
- /**
520
- * Creates a new bold extension instance.
521
- */
522
- constructor();
523
- }
524
- /**
525
- * Pre-configured bold extension instance.
526
- * Ready to use in extension arrays.
527
- */
528
- declare const boldExtension: BoldExtension;
17
+ declare const docsPreset: EditorPreset;
529
18
 
530
- /**
531
- * Italic text formatting extension.
532
- * Provides italic formatting with toggle command and state tracking.
533
- */
534
- declare class ItalicExtension extends TextFormatExtension<"italic"> {
535
- /**
536
- * Creates a new italic extension.
537
- */
538
- constructor();
539
- }
540
- /**
541
- * Preconfigured italic extension instance.
542
- * Ready for use in extension arrays.
543
- */
544
- declare const italicExtension: ItalicExtension;
19
+ declare const emailPreset: EditorPreset;
545
20
 
546
- /**
547
- * UnderlineExtension - Adds underline text formatting
548
- *
549
- * Extends TextFormatExtension to add underline formatting for selected text in
550
- * the Lexical editor. Integrates with the toolbar system and exposes commands
551
- * and state queries for underline actions.
552
- *
553
- * Supports Markdown syntax: ++underline++
554
- *
555
- * @example
556
- * ```tsx
557
- * import { underlineExtension } from '@lyfie/luthor/extensions/formatting/UnderlineExtension';
558
- *
559
- * const extensions = [underlineExtension];
560
- * const editor = createEditorSystem(extensions);
561
- * ```
562
- */
563
- declare class UnderlineExtension extends TextFormatExtension<"underline"> {
564
- constructor();
565
- /**
566
- * Returns Markdown transformers for underline formatting.
567
- *
568
- * @returns An array containing the underline transformer
569
- */
570
- getMarkdownTransformers(): any[];
571
- }
572
- declare const underlineExtension: UnderlineExtension;
21
+ declare const extensivePreset: EditorPreset;
573
22
 
574
- /**
575
- * StrikethroughExtension - Adds strikethrough text formatting
576
- *
577
- * Extends TextFormatExtension to add strikethrough formatting for selected
578
- * text in the Lexical editor. Integrates with the toolbar system and exposes
579
- * commands and state queries for strikethrough actions.
580
- *
581
- * @example
582
- * ```tsx
583
- * import { strikethroughExtension } from '@lyfie/luthor/extensions/formatting/StrikethroughExtension';
584
- *
585
- * const extensions = [strikethroughExtension];
586
- * const editor = createEditorSystem(extensions);
587
- * ```
588
- */
589
- declare class StrikethroughExtension extends TextFormatExtension<"strikethrough"> {
590
- constructor();
591
- }
592
- declare const strikethroughExtension: StrikethroughExtension;
23
+ declare const extensiveExtensions: readonly [_lyfie_luthor_headless.BoldExtension, _lyfie_luthor_headless.ItalicExtension, _lyfie_luthor_headless.UnderlineExtension, _lyfie_luthor_headless.StrikethroughExtension, LinkExtension, _lyfie_luthor_headless.HorizontalRuleExtension, TableExtension, _lyfie_luthor_headless.ListExtension, _lyfie_luthor_headless.HistoryExtension, ImageExtension, _lyfie_luthor_headless.BlockFormatExtension, _lyfie_luthor_headless.HTMLExtension, MarkdownExtension, _lyfie_luthor_headless.CodeExtension, _lyfie_luthor_headless.CodeFormatExtension, HTMLEmbedExtension, FloatingToolbarExtension<any, any>, ContextMenuExtension, CommandPaletteExtension, DraggableBlockExtension];
593
24
 
594
- /**
595
- * Link extension configuration.
596
- */
597
- interface LinkConfig extends BaseExtensionConfig {
598
- /**
599
- * Automatically link URLs as you type in the editor.
600
- * Uses real-time pattern matching. Default: false
601
- */
602
- autoLinkText?: boolean;
603
- /**
604
- * Automatically link URLs when pasted into the editor.
605
- * When false, pasted URLs remain plain text. Default: true
606
- */
607
- autoLinkUrls?: boolean;
608
- /**
609
- * Link selected text when pasting URLs over it.
610
- * When true: selected text becomes a link with the pasted URL.
611
- * When false: selected text is replaced with the pasted URL and then linked. Default: true
612
- */
613
- linkSelectedTextOnPaste?: boolean;
614
- /** URL validation function (default: basic URL regex) */
615
- validateUrl?: (url: string) => boolean;
25
+ interface ExtensiveEditorRef {
26
+ injectMarkdown: (content: string) => void;
27
+ injectHTML: (content: string) => void;
28
+ getMarkdown: () => string;
29
+ getHTML: () => string;
616
30
  }
617
- /**
618
- * Commands exposed by the link extension.
619
- */
620
- type LinkCommands = {
621
- insertLink: (url?: string, text?: string) => void;
622
- removeLink: () => void;
623
- };
624
- /**
625
- * State queries exposed by the link extension.
626
- */
627
- type LinkStateQueries = {
628
- isLink: () => Promise<boolean>;
629
- isTextSelected: () => Promise<boolean>;
630
- };
631
- /**
632
- * Link extension for creating and managing hyperlinks.
633
- *
634
- * Features:
635
- * - Manual link creation via commands
636
- * - Built-in paste handling (creates links when pasting URLs)
637
- * - Optional auto-linking while typing
638
- * - Click to follow links, click again to edit
639
- *
640
- * Uses Lexical's built-in LinkPlugin which handles:
641
- * - Pasting URLs over selected text (converts selection to a link)
642
- * - Pasting URLs at the cursor (creates a new link)
643
- * - Link editing and validation
644
- *
645
- * @example
646
- * ```tsx
647
- * const extensions = [
648
- * linkExtension.configure({
649
- * autoLinkText: true, // Optional: auto-link while typing
650
- * autoLinkUrls: true, // Optional: auto-link pasted URLs
651
- * linkSelectedTextOnPaste: false // Optional: replace selected text rather than linking it
652
- * })
653
- * ] as const;
654
- *
655
- * function MyEditor() {
656
- * const { commands, activeStates } = useEditor();
657
- * return (
658
- * <button
659
- * onClick={() => commands.insertLink()}
660
- * className={activeStates.isLink ? 'active' : ''}
661
- * >
662
- * Link
663
- * </button>
664
- * );
665
- * }
666
- * ```
667
- */
668
- declare class LinkExtension extends BaseExtension<"link", LinkConfig, LinkCommands, LinkStateQueries, React$1.ReactElement[]> {
669
- /**
670
- * Creates a new link extension instance.
671
- */
672
- constructor();
673
- /**
674
- * Registers the extension with the editor.
675
- * Configures URL paste handling.
676
- */
677
- register(editor: LexicalEditor): () => void;
678
- /**
679
- * Returns Lexical nodes exposed by this extension.
680
- */
681
- getNodes(): any[];
682
- /**
683
- * Returns React plugins exposed by this extension.
684
- */
685
- getPlugins(): React$1.ReactElement[];
686
- /**
687
- * Returns command handlers exposed by this extension.
688
- */
689
- getCommands(editor: LexicalEditor): LinkCommands;
690
- /**
691
- * Returns state query functions exposed by this extension.
692
- */
693
- getStateQueries(editor: LexicalEditor): LinkStateQueries;
694
- }
695
- /**
696
- * Preconfigured link extension instance.
697
- * Ready for use in extension arrays.
698
- */
699
- declare const linkExtension: LinkExtension;
700
-
701
- /**
702
- * Commands exposed by the horizontal rule extension.
703
- */
704
- type HorizontalRuleCommands = {
705
- insertHorizontalRule: () => void;
706
- };
707
- /**
708
- * State queries exposed by the horizontal rule extension.
709
- */
710
- type HorizontalRuleStateQueries = {
711
- isHorizontalRuleSelected: () => Promise<boolean>;
712
- };
713
- /**
714
- * Horizontal rule extension for inserting dividers.
715
- * Provides commands to insert and manage horizontal rules in the editor.
716
- *
717
- * @example
718
- * ```tsx
719
- * const extensions = [horizontalRuleExtension] as const;
720
- * const { Provider, useEditor } = createEditorSystem<typeof extensions>();
721
- *
722
- * function MyEditor() {
723
- * const { commands } = useEditor();
724
- * return (
725
- * <button onClick={() => commands.insertHorizontalRule()}>
726
- * Insert HR
727
- * </button>
728
- * );
729
- * }
730
- * ```
731
- */
732
- declare class HorizontalRuleExtension extends BaseExtension<"horizontalRule", any, HorizontalRuleCommands, HorizontalRuleStateQueries, React$1.ReactElement[]> {
733
- /**
734
- * Creates a new horizontal rule extension.
735
- */
736
- constructor();
737
- /**
738
- * Registers the extension with the editor.
739
- * No special registration needed because Lexical handles HR commands.
740
- *
741
- * @param editor - Lexical editor instance
742
- * @returns Cleanup function
743
- */
744
- register(editor: LexicalEditor): () => void;
745
- /**
746
- * Returns Lexical nodes provided by this extension.
747
- *
748
- * @returns Array containing the HorizontalRuleNode
749
- */
750
- getNodes(): any[];
751
- /**
752
- * Returns React plugins provided by this extension.
753
- *
754
- * @returns Array containing the HorizontalRulePlugin
755
- */
756
- getPlugins(): React$1.ReactElement[];
757
- /**
758
- * Returns commands exposed by this extension.
759
- *
760
- * @param editor - Lexical editor instance
761
- * @returns Object with horizontal rule command functions
762
- */
763
- getCommands(editor: LexicalEditor): HorizontalRuleCommands;
764
- /**
765
- * Returns state query functions exposed by this extension.
766
- *
767
- * @param editor - Lexical editor instance
768
- * @returns Object with horizontal rule state query functions
769
- */
770
- getStateQueries(editor: LexicalEditor): HorizontalRuleStateQueries;
771
- }
772
- /**
773
- * Preconfigured horizontal rule extension instance.
774
- * Ready for use in extension arrays.
775
- */
776
- declare const horizontalRuleExtension: HorizontalRuleExtension;
777
-
778
- type MarkdownConfig = BaseExtensionConfig & {
779
- /** Optional debounce (ms) for programmatic markdown imports */
780
- importDebounce?: number;
781
- /** Pre-registered transformers */
782
- transformers?: Transformer[];
783
- /** Transformer alias for backward compatibility */
784
- customTransformers?: Transformer[];
785
- };
786
- type MarkdownCommands = {
787
- exportToMarkdown: () => string;
788
- importFromMarkdown: (markdown: string, opts?: {
789
- immediate?: boolean;
790
- preventFocus?: boolean;
791
- }) => Promise<void>;
792
- registerMarkdownTransformer: (transformer: Transformer) => void;
793
- };
794
- type MarkdownStateQueries = {};
795
- declare class MarkdownExtension extends BaseExtension<'markdown', MarkdownConfig, MarkdownCommands, MarkdownStateQueries, [
796
- ]> {
797
- private manager;
798
- private pendingTransformers;
799
- private importTimer;
800
- constructor();
801
- configure(config: Partial<MarkdownConfig>): this;
802
- /** Allow other extensions to register transformers before or after editor registration */
803
- registerTransformer: (transformer: Transformer) => void;
804
- register(editor: LexicalEditor): () => void;
805
- getCommands(editor: LexicalEditor): MarkdownCommands;
806
- getStateQueries(editor: LexicalEditor): MarkdownStateQueries;
807
- }
808
- declare const markdownExtension: MarkdownExtension;
809
-
810
- /**
811
- * Context menu item definition
812
- */
813
- type ContextMenuItem = {
814
- label: string;
815
- action: () => void;
816
- icon?: React$1.ComponentType<{
817
- size?: number;
818
- className?: string;
819
- }>;
820
- disabled?: boolean;
821
- separator?: boolean;
822
- };
823
- /**
824
- * Context menu provider registered by extensions
825
- */
826
- type ContextMenuProvider = {
827
- id: string;
828
- priority?: number;
829
- canHandle: (context: {
830
- editor: LexicalEditor;
831
- target: HTMLElement;
832
- selection: any;
833
- event: MouseEvent;
834
- }) => boolean;
835
- getItems: (context: {
836
- editor: LexicalEditor;
837
- target: HTMLElement;
838
- selection: any;
839
- event: MouseEvent;
840
- }) => ContextMenuItem[];
841
- renderer?: ContextMenuRenderer;
842
- };
843
- /**
844
- * Context menu renderer function type
845
- */
846
- type ContextMenuRenderer = (props: {
847
- items: ContextMenuItem[];
848
- position: {
849
- x: number;
850
- y: number;
851
- };
852
- onClose: () => void;
853
- className: string;
854
- style?: React$1.CSSProperties;
855
- itemClassName: string;
856
- itemStyle?: React$1.CSSProperties;
857
- disabledItemClassName: string;
858
- disabledItemStyle?: React$1.CSSProperties;
859
- }) => React$1.ReactElement;
860
- /**
861
- * Context menu configuration
862
- */
863
- interface ContextMenuConfig extends BaseExtensionConfig {
864
- defaultRenderer?: ContextMenuRenderer;
865
- preventDefault?: boolean;
866
- theme?: {
867
- container?: string;
868
- item?: string;
869
- itemDisabled?: string;
870
- };
871
- styles?: {
872
- container?: React$1.CSSProperties;
873
- item?: React$1.CSSProperties;
874
- itemDisabled?: React$1.CSSProperties;
875
- };
876
- }
877
- /**
878
- * Commands exposed by the context menu extension
879
- */
880
- type ContextMenuCommands = {
881
- registerProvider: (provider: ContextMenuProvider) => void;
882
- unregisterProvider: (id: string) => void;
883
- showContextMenu: (config: {
884
- items: ContextMenuItem[];
885
- position: {
886
- x: number;
887
- y: number;
888
- };
889
- renderer?: ContextMenuRenderer;
890
- }) => void;
891
- hideContextMenu: () => void;
892
- };
893
- /**
894
- * State queries for context menus
895
- */
896
- type ContextMenuStateQueries = {
897
- isContextMenuOpen: () => Promise<boolean>;
898
- };
899
- /**
900
- * Context menu manager - handles provider registry and menu display
901
- */
902
- declare class ContextMenuManager {
903
- private providers;
904
- private currentMenu;
905
- private listeners;
906
- private editor;
907
- private config;
908
- constructor(editor: LexicalEditor, config?: ContextMenuConfig);
909
- registerProvider(provider: ContextMenuProvider): void;
910
- unregisterProvider(id: string): void;
911
- handleContextMenu(event: MouseEvent): void;
912
- showMenu(config: {
913
- items: ContextMenuItem[];
914
- position: {
915
- x: number;
916
- y: number;
917
- };
918
- renderer?: ContextMenuRenderer;
919
- }): void;
920
- hideMenu(): void;
921
- getCurrentMenu(): {
922
- items: ContextMenuItem[];
923
- position: {
924
- x: number;
925
- y: number;
926
- };
927
- renderer?: ContextMenuRenderer;
928
- } | null;
929
- subscribe(listener: (menu: typeof this.currentMenu) => void): () => void;
930
- private notifyListeners;
931
- }
932
- /**
933
- * Context menu extension - provides a clean, registry-based context menu system
934
- */
935
- declare class ContextMenuExtension extends BaseExtension<"contextMenu", ContextMenuConfig, ContextMenuCommands, ContextMenuStateQueries, React$1.ReactElement[]> {
936
- manager: ContextMenuManager | null;
937
- private pendingListeners;
938
- constructor(config?: ContextMenuConfig);
939
- configure(config: Partial<ContextMenuConfig>): this;
940
- register(editor: LexicalEditor): () => void;
941
- getCommands(editor: LexicalEditor): ContextMenuCommands;
942
- getStateQueries(editor: LexicalEditor): ContextMenuStateQueries;
943
- getPlugins(): React$1.ReactElement[];
944
- subscribe(listener: (menu: any) => void): () => void;
945
- }
946
- declare const contextMenuExtension: ContextMenuExtension;
947
-
948
- /**
949
- * Table extension configuration options.
950
- */
951
- type TableConfig = BaseExtensionConfig & {
952
- rows?: number;
953
- columns?: number;
954
- includeHeaders?: boolean;
955
- /** Enable right-click context menu */
956
- enableContextMenu?: boolean;
957
- /** Custom context menu items - static list or a function that receives commands */
958
- contextMenuItems?: ContextMenuItem[] | ((commands: TableCommands) => ContextMenuItem[]);
959
- /** Custom context menu renderer for full headless control */
960
- contextMenuRenderer?: ContextMenuRenderer;
961
- /** Context menu extension used to register providers */
962
- contextMenuExtension?: typeof contextMenuExtension;
963
- /** Markdown extension used to register transformers */
964
- markdownExtension?: typeof markdownExtension;
965
- };
966
- /**
967
- * Commands exposed by the Table extension.
968
- */
969
- type TableCommands = {
970
- insertTable: (config: {
971
- rows?: number;
972
- columns?: number;
973
- includeHeaders?: boolean;
974
- }) => void;
975
- insertRowAbove: () => void;
976
- insertRowBelow: () => void;
977
- insertColumnLeft: () => void;
978
- insertColumnRight: () => void;
979
- deleteRow: () => void;
980
- deleteColumn: () => void;
981
- deleteTable: () => void;
982
- showTableContextMenu: (position: {
983
- x: number;
984
- y: number;
985
- }) => void;
986
- };
987
- /**
988
- * State queries exposed by the Table extension.
989
- */
990
- type TableStateQueries = {
991
- isTableSelected: () => Promise<boolean>;
992
- isInTableCell: () => Promise<boolean>;
993
- };
994
- /**
995
- * Table extension for table operations in the editor.
996
- * Provides commands for inserting and manipulating tables.
997
- */
998
- declare class TableExtension extends BaseExtension<"table", TableConfig, TableCommands, TableStateQueries, ReactNode[]> {
999
- getContextMenuItems(commands: TableCommands): ContextMenuItem[];
1000
- private defaultContextMenuItems;
1001
- constructor(config?: Partial<TableConfig>);
1002
- configure(config: Partial<TableConfig>): this;
1003
- register(editor: LexicalEditor): () => void;
1004
- getNodes(): any[];
1005
- getCommands(editor: LexicalEditor): TableCommands;
1006
- getStateQueries(editor: LexicalEditor): TableStateQueries;
1007
- getPlugins(): ReactNode[];
1008
- }
1009
- /**
1010
- * Preconfigured Table extension instance.
1011
- * Ready for use in extension arrays.
1012
- */
1013
- declare const tableExtension: TableExtension;
1014
-
1015
- /**
1016
- * Commands exposed by the list extension.
1017
- */
1018
- type ListCommands = {
1019
- /** Toggle a bullet list for the current selection */
1020
- toggleUnorderedList: () => void;
1021
- /** Toggle a numbered list for the current selection */
1022
- toggleOrderedList: () => void;
1023
- /** Indent the current list item (nest deeper) */
1024
- indentList: () => void;
1025
- /** Outdent the current list item (unnest) */
1026
- outdentList: () => void;
1027
- /** Create a nested bullet list at the current selection */
1028
- insertNestedUnorderedList: () => void;
1029
- /** Create a nested numbered list at the current selection */
1030
- insertNestedOrderedList: () => void;
1031
- };
1032
- /**
1033
- * List extension for managing ordered and unordered lists.
1034
- * Provides functionality to convert paragraphs to lists and vice versa.
1035
- *
1036
- * @example
1037
- * ```tsx
1038
- * const extensions = [listExtension] as const;
1039
- * const { Provider, useEditor } = createEditorSystem<typeof extensions>();
1040
- *
1041
- * function MyEditor() {
1042
- * const { commands, activeStates } = useEditor();
1043
- * return (
1044
- * <div>
1045
- * <button
1046
- * onClick={() => commands.toggleUnorderedList()}
1047
- * className={activeStates.unorderedList ? 'active' : ''}
1048
- * >
1049
- * Bullet List
1050
- * </button>
1051
- * <button
1052
- * onClick={() => commands.toggleOrderedList()}
1053
- * className={activeStates.orderedList ? 'active' : ''}
1054
- * >
1055
- * Numbered List
1056
- * </button>
1057
- * <button onClick={() => commands.indentList()}>Indent</button>
1058
- * <button onClick={() => commands.outdentList()}>Outdent</button>
1059
- * <button onClick={() => commands.insertNestedUnorderedList()}>Nested Bullet</button>
1060
- * <button onClick={() => commands.insertNestedOrderedList()}>Nested Numbered</button>
1061
- * </div>
1062
- * );
1063
- * }
1064
- * ```
1065
- */
1066
- declare class ListExtension extends BaseExtension<"list", any, ListCommands, {
1067
- unorderedList: () => Promise<boolean>;
1068
- orderedList: () => Promise<boolean>;
1069
- }, ReactNode[]> {
1070
- /**
1071
- * Creates a new list extension instance.
1072
- */
1073
- constructor();
1074
- /**
1075
- * Registers the extension with Lexical.
1076
- * No special registration needed because Lexical handles list commands.
1077
- *
1078
- * @param editor - Lexical editor instance
1079
- * @returns Cleanup function (no-op for lists)
1080
- */
1081
- register(editor: LexicalEditor): () => void;
1082
- /**
1083
- * Returns Lexical nodes needed for list functionality.
1084
- *
1085
- * @returns Array containing ListNode and ListItemNode
1086
- */
1087
- getNodes(): any[];
1088
- /**
1089
- * Returns React plugins needed for list functionality.
1090
- *
1091
- * @returns Array containing the ListPlugin component
1092
- */
1093
- getPlugins(): React$1.ReactNode[];
1094
- /**
1095
- * Returns command handlers exposed by this extension.
1096
- *
1097
- * @param editor - Lexical editor instance
1098
- * @returns Object containing list toggle commands
1099
- */
1100
- getCommands(editor: LexicalEditor): ListCommands;
1101
- /**
1102
- * Returns state query functions for list state.
1103
- *
1104
- * @param editor - Lexical editor instance
1105
- * @returns Object containing state query functions for list types
1106
- */
1107
- getStateQueries(editor: LexicalEditor): {
1108
- unorderedList: () => Promise<boolean>;
1109
- orderedList: () => Promise<boolean>;
1110
- };
1111
- }
1112
- /**
1113
- * Preconfigured list extension instance.
1114
- * Ready for use in extension arrays.
1115
- */
1116
- declare const listExtension: ListExtension;
1117
-
1118
- /**
1119
- * Commands exposed by the CodeExtension for toggling code blocks
1120
- */
1121
- type CodeCommands = {
1122
- /** Toggle code block vs paragraph for the current selection */
1123
- toggleCodeBlock: () => void;
1124
- };
1125
- /**
1126
- * State queries exposed by the CodeExtension for checking code block status
1127
- */
1128
- type CodeStateQueries = {
1129
- /** Check whether the current selection is within a code block */
1130
- isInCodeBlock: () => Promise<boolean>;
1131
- };
1132
- /**
1133
- * CodeExtension - Adds code block support for the Lexical editor
1134
- *
1135
- * Enables users to create and manage code blocks in the editor.
1136
- * Provides commands to toggle between code blocks and paragraphs,
1137
- * plus state queries to check whether the selection is in a code block.
1138
- *
1139
- * Integrates with Lexical's CodeNode and provides a clean API
1140
- * for toolbar integration and programmatic control.
1141
- *
1142
- * @example
1143
- * ```tsx
1144
- * import { codeExtension } from '@lyfie/luthor/extensions/formatting/CodeExtension';
1145
- *
1146
- * const extensions = [codeExtension];
1147
- * const editor = createEditorSystem(extensions);
1148
- *
1149
- * // Use in a component
1150
- * const { commands } = useEditor();
1151
- * commands.toggleCodeBlock(); // Toggle code block on or off
1152
- * ```
1153
- */
1154
- declare class CodeExtension extends BaseExtension<"code", {}, CodeCommands, CodeStateQueries, ReactNode[]> {
1155
- constructor();
1156
- /**
1157
- * Register the extension with Lexical
1158
- * @param editor - Lexical editor instance
1159
- * @returns Cleanup function
1160
- */
1161
- register(editor: LexicalEditor): () => void;
1162
- /**
1163
- * Get Lexical nodes required by this extension
1164
- * @returns Array of node classes
1165
- */
1166
- getNodes(): (typeof CodeNode)[];
1167
- /**
1168
- * Get commands exposed by this extension
1169
- * @param editor - Lexical editor instance
1170
- * @returns Object containing available commands
1171
- */
1172
- getCommands(editor: LexicalEditor): CodeCommands;
1173
- /**
1174
- * Toggle between code block and paragraph for the selection
1175
- * @param editor - Lexical editor instance
1176
- */
1177
- private toggleCodeBlock;
1178
- /**
1179
- * Get state queries exposed by this extension
1180
- * @param editor - Lexical editor instance
1181
- * @returns Object containing available state queries
1182
- */
1183
- getStateQueries(editor: LexicalEditor): CodeStateQueries;
1184
- /**
1185
- * Check whether the current selection matches the specified format
1186
- * @param format - Format to check for (currently only 'code')
1187
- * @param editor - Lexical editor instance
1188
- * @returns True if all selected nodes match the format
1189
- */
1190
- private isFormat;
1191
- /**
1192
- * Get the nearest block node from the given node
1193
- * @param node - Starting node
1194
- * @returns Nearest CodeNode or null
1195
- */
1196
- private getBlockNode;
1197
- /**
1198
- * Get the format type of a given node
1199
- * @param node - Node to check
1200
- * @returns Format type or null
1201
- */
1202
- private getNodeFormat;
1203
- /**
1204
- * Get the current format synchronously (for use inside editor.update())
1205
- * @returns Current format or null
1206
- */
1207
- private getCurrentFormatSync;
1208
- }
1209
- declare const codeExtension: CodeExtension;
1210
-
1211
- /**
1212
- * CodeFormatExtension - Provides inline code text formatting functionality
1213
- *
1214
- * This extension extends TextFormatExtension to provide inline code formatting
1215
- * for selected text in the Lexical editor. It integrates with the toolbar system
1216
- * and provides commands and state queries for inline code operations.
1217
- *
1218
- * @example
1219
- * ```tsx
1220
- * import { codeFormatExtension } from '@lyfie/luthor/extensions/formatting/CodeFormatExtension';
1221
- *
1222
- * const extensions = [codeFormatExtension];
1223
- * const editor = createEditorSystem(extensions);
1224
- * ```
1225
- */
1226
- declare class CodeFormatExtension extends TextFormatExtension<"code"> {
1227
- constructor();
1228
- }
1229
- declare const codeFormatExtension: CodeFormatExtension;
1230
-
1231
- /**
1232
- * Supported block formats for BlockFormatExtension
1233
- */
1234
- type BlockFormat = "p" | HeadingTagType | "quote";
1235
- /**
1236
- * Commands exposed by BlockFormatExtension for block-level formatting
1237
- */
1238
- type BlockFormatCommands = {
1239
- /** Switch to a specific block format */
1240
- toggleBlockFormat: (format: BlockFormat) => void;
1241
- /** Switch to paragraph format */
1242
- toggleParagraph: () => void;
1243
- /** Switch to a heading format */
1244
- toggleHeading: (tag: HeadingTagType) => void;
1245
- /** Switch to quote format */
1246
- toggleQuote: () => void;
1247
- /** Return the current block type as a string ('p', 'h1', 'h2', etc.) */
1248
- getCurrentBlockType: () => BlockFormat;
1249
- };
1250
- /**
1251
- * State queries exposed by BlockFormatExtension for checking block formats
1252
- */
1253
- type BlockFormatStateQueries = {
1254
- /** Check whether the selection is in a paragraph */
1255
- isParagraph: () => Promise<boolean>;
1256
- /** Check whether the selection is in an H1 heading */
1257
- isH1: () => Promise<boolean>;
1258
- /** Check whether the selection is in an H2 heading */
1259
- isH2: () => Promise<boolean>;
1260
- /** Check whether the selection is in an H3 heading */
1261
- isH3: () => Promise<boolean>;
1262
- /** Check whether the selection is in an H4 heading */
1263
- isH4: () => Promise<boolean>;
1264
- /** Check whether the selection is in an H5 heading */
1265
- isH5: () => Promise<boolean>;
1266
- /** Check whether the selection is in an H6 heading */
1267
- isH6: () => Promise<boolean>;
1268
- /** Check whether the selection is in a quote block */
1269
- isQuote: () => Promise<boolean>;
1270
- };
1271
- /**
1272
- * BlockFormatExtension - Provides block-level formatting
1273
- *
1274
- * Enables users to change block-level elements like paragraphs,
1275
- * headings (H1-H6), and quotes. Provides a comprehensive set of commands
1276
- * for switching between formats and state queries for checking
1277
- * the current block format.
1278
- *
1279
- * The extension supports true toggling - applying the same format
1280
- * again reverts to a paragraph.
1281
- *
1282
- * @example
1283
- * ```tsx
1284
- * import { blockFormatExtension } from '@lyfie/luthor/extensions/formatting/BlockTypeExtension';
1285
- *
1286
- * const extensions = [blockFormatExtension];
1287
- * const editor = createEditorSystem(extensions);
1288
- *
1289
- * // Use in a component
1290
- * const { commands } = useEditor();
1291
- * commands.toggleHeading('h1'); // Switch selection to H1
1292
- * commands.toggleQuote(); // Convert selection to a quote block
1293
- * ```
1294
- */
1295
- declare class BlockFormatExtension extends BaseExtension<"blockFormat", {}, // No extra config needed
1296
- BlockFormatCommands, BlockFormatStateQueries> {
1297
- constructor();
1298
- /**
1299
- * Register the extension with Lexical
1300
- * @param editor - Lexical editor instance
1301
- * @returns Cleanup function
1302
- */
1303
- register(editor: LexicalEditor): () => void;
1304
- /**
1305
- * Get Lexical nodes required by this extension
1306
- * @returns Array of node classes
1307
- */
1308
- getNodes(): (typeof ParagraphNode | typeof HeadingNode | typeof QuoteNode)[];
1309
- /**
1310
- * Get commands exposed by this extension
1311
- * @param editor - Lexical editor instance
1312
- * @returns Object containing available commands
1313
- */
1314
- getCommands(editor: LexicalEditor): BlockFormatCommands;
1315
- /**
1316
- * Toggle the block format for the current selection
1317
- * @param editor - Lexical editor instance
1318
- * @param format - Target block format
1319
- */
1320
- private toggleBlockFormat;
1321
- /**
1322
- * Get the state queries provided by this extension
1323
- * @param editor - Lexical editor instance
1324
- * @returns Object containing available state queries
1325
- */
1326
- getStateQueries(editor: LexicalEditor): BlockFormatStateQueries;
1327
- /**
1328
- * Get the nearest block node starting from the given node
1329
- * @param node - Starting node
1330
- * @returns Nearest block node or null
1331
- */
1332
- private getBlockNode;
1333
- /**
1334
- * Check whether all blocks in the current selection match the specified format
1335
- * @param format - Format to check for
1336
- * @param editor - Lexical editor instance
1337
- * @returns True if all selected blocks match the format
1338
- */
1339
- private isFormat;
1340
- /**
1341
- * Get the format type for a block node
1342
- * @param node - Block node to check
1343
- * @returns Format type or null
1344
- */
1345
- private getNodeFormat;
1346
- /**
1347
- * Get the current block format for the selection
1348
- * @param editor - Lexical editor instance
1349
- * @returns Current format or null
1350
- */
1351
- private getCurrentFormat;
1352
- /**
1353
- * Get the current block format synchronously (for use inside editor.update())
1354
- * @returns Current format or null
1355
- */
1356
- private getCurrentFormatSync;
1357
- }
1358
- declare const blockFormatExtension: BlockFormatExtension;
1359
-
1360
- /**
1361
- * Commands exposed by the history extension.
1362
- */
1363
- type HistoryCommands = {
1364
- /** Undo the most recent action */
1365
- undo: () => void;
1366
- /** Redo the most recently undone action */
1367
- redo: () => void;
1368
- /** Clear the full history stack */
1369
- clearHistory: () => void;
1370
- };
1371
- /**
1372
- * History extension that provides undo/redo functionality.
1373
- * Integrates with Lexical's built-in history system to offer
1374
- * undo and redo capabilities with state tracking.
1375
- *
1376
- * @example
1377
- * ```tsx
1378
- * const extensions = [historyExtension] as const;
1379
- * const { Provider, useEditor } = createEditorSystem<typeof extensions>();
1380
- *
1381
- * function MyEditor() {
1382
- * const { commands, activeStates } = useEditor();
1383
- * return (
1384
- * <div>
1385
- * <button
1386
- * onClick={() => commands.undo()}
1387
- * disabled={!activeStates.canUndo}
1388
- * >
1389
- * Undo
1390
- * </button>
1391
- * <button
1392
- * onClick={() => commands.redo()}
1393
- * disabled={!activeStates.canRedo}
1394
- * >
1395
- * Redo
1396
- * </button>
1397
- * </div>
1398
- * );
1399
- * }
1400
- * ```
1401
- */
1402
- declare class HistoryExtension extends BaseExtension<"history", any, HistoryCommands, {
1403
- canUndo: () => Promise<boolean>;
1404
- canRedo: () => Promise<boolean>;
1405
- }, ReactNode[]> {
1406
- private canUndoState;
1407
- private canRedoState;
1408
- /**
1409
- * Creates a new history extension.
1410
- */
1411
- constructor();
1412
- /**
1413
- * Registers the extension with the Lexical editor.
1414
- * Sets up listeners for undo/redo state changes.
1415
- *
1416
- * @param editor - Lexical editor instance
1417
- * @returns Cleanup function
1418
- */
1419
- register(editor: LexicalEditor): () => void;
1420
- /**
1421
- * Returns React plugins required for history support.
1422
- *
1423
- * @returns Array containing the HistoryPlugin component
1424
- */
1425
- getPlugins(): ReactNode[];
1426
- /**
1427
- * Returns commands exposed by this extension.
1428
- *
1429
- * @param editor - Lexical editor instance
1430
- * @returns Object containing history commands
1431
- */
1432
- getCommands(editor: LexicalEditor): HistoryCommands;
1433
- /**
1434
- * Returns state query functions for undo/redo availability.
1435
- *
1436
- * @param editor - Lexical editor instance
1437
- * @returns Object containing state query functions
1438
- */
1439
- getStateQueries(editor: LexicalEditor): {
1440
- canUndo: () => Promise<boolean>;
1441
- canRedo: () => Promise<boolean>;
1442
- };
1443
- }
1444
- /**
1445
- * Preconfigured history extension instance.
1446
- * Ready for use in extension arrays.
1447
- */
1448
- declare const historyExtension: HistoryExtension;
1449
-
1450
- /**
1451
- * DraggableBlockExtension configuration
1452
- */
1453
- interface DraggableConfig extends BaseExtensionConfig {
1454
- /** Portal anchor element (default: document.body) */
1455
- anchorElem?: HTMLElement;
1456
- /** Show move buttons */
1457
- showMoveButtons?: boolean;
1458
- /** Show the up button */
1459
- showUpButton?: boolean;
1460
- /** Show the down button */
1461
- showDownButton?: boolean;
1462
- /** Button stack position relative to blocks */
1463
- buttonStackPosition?: "left" | "right";
1464
- /** Allow drag via text selection (default: true) */
1465
- enableTextSelectionDrag?: boolean;
1466
- /** Left offset */
1467
- offsetLeft?: number;
1468
- /** Right offset */
1469
- offsetRight?: number;
1470
- /** Theme class names */
1471
- theme?: {
1472
- handle?: string;
1473
- handleActive?: string;
1474
- blockDragging?: string;
1475
- dropIndicator?: string;
1476
- upButton?: string;
1477
- downButton?: string;
1478
- buttonStack?: string;
1479
- };
1480
- /** Custom styles for UI elements */
1481
- styles?: {
1482
- handle?: React$1.CSSProperties;
1483
- handleActive?: React$1.CSSProperties;
1484
- blockDragging?: React$1.CSSProperties;
1485
- dropIndicator?: React$1.CSSProperties;
1486
- upButton?: React$1.CSSProperties;
1487
- downButton?: React$1.CSSProperties;
1488
- buttonStack?: React$1.CSSProperties;
1489
- };
1490
- /** Custom handle renderer for full headless control */
1491
- handleRenderer?: (props: {
1492
- rect: DOMRect;
1493
- isDragging: boolean;
1494
- onDragStart: (e: React$1.DragEvent) => void;
1495
- className: string;
1496
- }) => ReactNode;
1497
- /** Custom up/down button renderer */
1498
- buttonsRenderer?: (props: {
1499
- rect: DOMRect;
1500
- onMoveUp: () => void;
1501
- onMoveDown: () => void;
1502
- showUp: boolean;
1503
- showDown: boolean;
1504
- upClassName: string;
1505
- downClassName: string;
1506
- }) => ReactNode;
1507
- /** Custom drop indicator renderer */
1508
- dropIndicatorRenderer?: (props: {
1509
- top: number;
1510
- left: number;
1511
- width: number;
1512
- className: string;
1513
- }) => ReactNode;
1514
- }
1515
- /**
1516
- * Commands exposed by the draggable block extension
1517
- */
1518
- type DraggableCommands = {
1519
- moveBlock: (sourceKey: string, targetKey: string, insertAfter: boolean) => void;
1520
- moveCurrentBlockUp: () => void;
1521
- moveCurrentBlockDown: () => void;
1522
- };
1523
- /**
1524
- * State queries exposed by the draggable block extension
1525
- */
1526
- type DraggableStateQueries = {
1527
- isDragging: () => Promise<boolean>;
1528
- };
1529
- /**
1530
- * DraggableBlockExtension - Clean, headless drag-and-drop for blocks
1531
- */
1532
- declare class DraggableBlockExtension extends BaseExtension<"draggableBlock", DraggableConfig, DraggableCommands, DraggableStateQueries, ReactNode[]> {
1533
- private isDraggingState;
1534
- private stateChangeCallbacks;
1535
- constructor(config?: Partial<DraggableConfig>);
1536
- register(editor: LexicalEditor): () => void;
1537
- getPlugins(): ReactNode[];
1538
- getCommands(editor: LexicalEditor): DraggableCommands;
1539
- getStateQueries(editor: LexicalEditor): DraggableStateQueries;
1540
- setIsDragging(isDragging: boolean): void;
1541
- onStateChange(callback: () => void): () => void;
1542
- }
1543
- /**
1544
- * Preconfigured instance
1545
- */
1546
- declare const draggableBlockExtension: DraggableBlockExtension;
1547
-
1548
- /**
1549
- * Commands exposed by the HTML extension.
1550
- */
1551
- type HTMLCommands = {
1552
- /** Export current editor content as an HTML string */
1553
- exportToHTML: () => string;
1554
- /** Import HTML into the editor, replacing current content */
1555
- importFromHTML: (html: string, opts?: {
1556
- preventFocus?: boolean;
1557
- }) => Promise<void>;
1558
- };
1559
- /**
1560
- * State queries exposed by the HTML extension.
1561
- */
1562
- type HTMLStateQueries = {
1563
- /** Check whether HTML export is available (always true) */
1564
- canExportHTML: () => Promise<boolean>;
1565
- };
1566
- /**
1567
- * HTML extension for import/export of HTML content.
1568
- * Converts between Lexical editor state and HTML strings.
1569
- *
1570
- * @example
1571
- * ```tsx
1572
- * const extensions = [htmlExtension] as const;
1573
- * const { Provider, useEditor } = createEditorSystem<typeof extensions>();
1574
- *
1575
- * function MyEditor() {
1576
- * const { commands } = useEditor();
1577
- *
1578
- * const handleExport = () => {
1579
- * const html = commands.exportToHTML();
1580
- * console.log('Exported HTML:', html);
1581
- * };
1582
- *
1583
- * const handleImport = () => {
1584
- * const html = '<p>Hello <strong>world</strong>!</p>';
1585
- * commands.importFromHTML(html);
1586
- * };
1587
- *
1588
- * return (
1589
- * <div>
1590
- * <button onClick={handleExport}>Export HTML</button>
1591
- * <button onClick={handleImport}>Import HTML</button>
1592
- * </div>
1593
- * );
1594
- * }
1595
- * ```
1596
- */
1597
- declare class HTMLExtension extends BaseExtension<"html", {}, HTMLCommands, HTMLStateQueries, ReactNode[]> {
1598
- /**
1599
- * Creates a new HTML extension.
1600
- */
1601
- constructor();
1602
- /**
1603
- * Registers the extension with the Lexical editor.
1604
- * No special registration needed for HTML functionality.
1605
- *
1606
- * @param editor - Lexical editor instance
1607
- * @returns Cleanup function
1608
- */
1609
- register(editor: LexicalEditor): () => void;
1610
- /**
1611
- * Returns commands exposed by this extension.
1612
- *
1613
- * @param editor - Lexical editor instance
1614
- * @returns Object containing HTML import/export commands
1615
- */
1616
- getCommands(editor: LexicalEditor): HTMLCommands;
1617
- /**
1618
- * Returns state query functions for this extension.
1619
- *
1620
- * @param editor - Lexical editor instance
1621
- * @returns Object containing state query functions
1622
- */
1623
- getStateQueries(editor: LexicalEditor): HTMLStateQueries;
1624
- }
1625
- /**
1626
- * Preconfigured HTML extension instance.
1627
- * Ready for use in extension arrays.
1628
- */
1629
- declare const htmlExtension: HTMLExtension;
1630
-
1631
- /**
1632
- * Supported alignment options for media items
1633
- */
1634
- type Alignment = "left" | "right" | "center" | "none";
1635
- /**
1636
- * Payload interface for image insertion and updates
1637
- */
1638
- interface ImagePayload {
1639
- /** Source URL for the image */
1640
- src?: string;
1641
- /** Accessible alt text */
1642
- alt: string;
1643
- /** Optional caption */
1644
- caption?: string;
1645
- /** Alignment */
1646
- alignment?: Alignment;
1647
- /** CSS class name for styling */
1648
- className?: string;
1649
- /** Inline style overrides */
1650
- style?: CSSProperties;
1651
- /** File object for uploads */
1652
- file?: File;
1653
- /** Width in pixels */
1654
- width?: number;
1655
- /** Height in pixels */
1656
- height?: number;
1657
- }
1658
- /**
1659
- * Props for the Image component
1660
- */
1661
- interface ImageComponentProps extends ImagePayload {
1662
- /** Lexical node key */
1663
- nodeKey?: string;
1664
- /** Whether the image is resizable */
1665
- resizable?: boolean;
1666
- /** Whether the image is uploading */
1667
- uploading?: boolean;
1668
- }
1669
- /**
1670
- * Serialized ImageNode representation for persistence
1671
- */
1672
- interface SerializedImageNode {
1673
- /** Node type ID */
1674
- type: "image";
1675
- /** Version for migrations */
1676
- version: number;
1677
- /** Source URL for the image */
1678
- src: string;
1679
- /** Accessible alt text */
1680
- alt: string;
1681
- /** Optional caption */
1682
- caption?: string;
1683
- /** Alignment */
1684
- alignment: Alignment;
1685
- /** CSS class name */
31
+ interface ExtensiveEditorProps {
1686
32
  className?: string;
1687
- /** Inline styles as a string record */
1688
- style?: Record<string, string>;
1689
- /** Width in pixels */
1690
- width?: number;
1691
- /** Height in pixels */
1692
- height?: number;
1693
- }
1694
- /**
1695
- * ImageExtension configuration options
1696
- */
1697
- interface ImageExtensionConfig extends BaseExtensionConfig {
1698
- /** Upload handler that returns the image URL */
1699
- uploadHandler?: (file: File) => Promise<string>;
1700
- /** Default alignment for new images */
1701
- defaultAlignment?: Alignment;
1702
- /** Class names for alignments and elements */
1703
- classNames?: Partial<Record<Alignment | "wrapper" | "caption", string>>;
1704
- /** Styles for alignments and elements */
1705
- styles?: Partial<Record<Alignment | "wrapper" | "caption", CSSProperties>>;
1706
- /** Custom renderer component for images */
1707
- customRenderer?: ComponentType<ImageComponentProps>;
1708
- /** Enable image resizing (default: true) */
1709
- resizable?: boolean;
1710
- /** Paste behavior configuration */
1711
- pasteListener?: {
1712
- /** Insert a new image on paste when none is selected */
1713
- insert: boolean;
1714
- /** Replace selected image src on paste */
1715
- replace: boolean;
1716
- };
1717
- /** Enable debug logging */
1718
- debug?: boolean;
1719
- /** Force upload even for remote URLs (default: false) */
1720
- forceUpload?: boolean;
1721
- }
1722
- /**
1723
- * Commands exposed by the ImageExtension
1724
- */
1725
- type ImageCommands = {
1726
- /** Insert an image into the editor */
1727
- insertImage: (payload: ImagePayload) => void;
1728
- /** Set alignment for the selected image */
1729
- setImageAlignment: (alignment: Alignment) => void;
1730
- /** Set caption for the selected image */
1731
- setImageCaption: (caption: string) => void;
1732
- /** Set the CSS class name on the selected image */
1733
- setImageClassName: (className: string) => void;
1734
- /** Set inline styles on the selected image */
1735
- setImageStyle: (style: CSSProperties) => void;
1736
- };
1737
- /**
1738
- * State queries exposed by the ImageExtension
1739
- */
1740
- type ImageStateQueries = {
1741
- /** Check whether an image is selected */
1742
- imageSelected: () => Promise<boolean>;
1743
- /** Check whether the selected image is left-aligned */
1744
- isImageAlignedLeft: () => Promise<boolean>;
1745
- /** Check whether the selected image is center-aligned */
1746
- isImageAlignedCenter: () => Promise<boolean>;
1747
- /** Check whether the selected image is right-aligned */
1748
- isImageAlignedRight: () => Promise<boolean>;
1749
- /** Check whether the selected image has no special alignment */
1750
- isImageAlignedNone: () => Promise<boolean>;
1751
- };
1752
-
1753
- declare class ImageNode extends DecoratorNode<ReactNode> {
1754
- /** Source URL for the image */
1755
- __src: string;
1756
- /** Accessible alt text */
1757
- __alt: string;
1758
- /** Optional caption */
1759
- __caption?: string;
1760
- /** Alignment */
1761
- __alignment: Alignment;
1762
- /** CSS class name */
1763
- __className?: string;
1764
- /** Inline style overrides */
1765
- __style?: CSSProperties;
1766
- /** Width in pixels */
1767
- __width?: number;
1768
- /** Height in pixels */
1769
- __height?: number;
1770
- /** Whether the image is uploading */
1771
- __uploading?: boolean;
1772
- static getType(): string;
1773
- static clone(node: ImageNode): ImageNode;
1774
- static importDOM(): DOMConversionMap | null;
1775
- static importJSON(serializedNode: SerializedImageNode): ImageNode;
1776
- constructor(src?: string, alt?: string, caption?: string, alignment?: Alignment, className?: string, style?: CSSProperties, width?: number, height?: number, uploading?: boolean, key?: NodeKey);
1777
- createDOM(config: EditorConfig$1): HTMLElement;
1778
- updateDOM(prevNode: ImageNode, dom: HTMLElement, config: EditorConfig$1): boolean;
1779
- exportDOM(): DOMExportOutput;
1780
- exportJSON(): SerializedImageNode;
1781
- setSrc(src: string): void;
1782
- setAlt(alt: string): void;
1783
- setCaption(caption?: string): void;
1784
- setAlignment(alignment: Alignment): void;
1785
- setClassName(className?: string): void;
1786
- setStyle(style?: CSSProperties): void;
1787
- getWidth(): number | undefined;
1788
- getHeight(): number | undefined;
1789
- setWidthAndHeight(width: number, height: number): void;
1790
- isInline(): boolean;
1791
- isBlockElement(): boolean;
1792
- canBeEmpty(): boolean;
1793
- decorate(): ReactNode;
1794
- }
1795
- declare class ImageExtension extends BaseExtension<"image", ImageExtensionConfig, ImageCommands, ImageStateQueries, ReactNode[]> {
1796
- /** Track recent image sources to avoid duplicate inserts */
1797
- private recentImages;
1798
- constructor();
1799
- configure(config: Partial<ImageExtensionConfig>): this;
1800
- register(editor: LexicalEditor): () => void;
1801
- getNodes(): any[];
1802
- getCommands(editor: LexicalEditor): ImageCommands;
1803
- getStateQueries(editor: LexicalEditor): ImageStateQueries;
33
+ onReady?: (methods: ExtensiveEditorRef) => void;
34
+ initialTheme?: "light" | "dark";
1804
35
  }
1805
- declare const imageExtension: ImageExtension;
36
+ declare const ExtensiveEditor: React.ForwardRefExoticComponent<ExtensiveEditorProps & React.RefAttributes<ExtensiveEditorRef>>;
1806
37
 
1807
- /**
1808
- * Payload for HTML embed content
1809
- */
1810
- type HTMLEmbedPayload = {
1811
- /** HTML content to embed */
1812
- html: string;
1813
- /** Whether to show preview or edit mode */
1814
- preview: boolean;
1815
- };
1816
- /**
1817
- * HTMLEmbedExtension configuration
1818
- */
1819
- interface HTMLEmbedConfig extends BaseExtensionConfig {
1820
- /** Default HTML for new embeds */
1821
- defaultHtml?: string;
1822
- /** Default to preview mode */
1823
- defaultPreview?: boolean;
1824
- /** Theme class names */
1825
- theme?: {
1826
- container?: string;
1827
- preview?: string;
1828
- editor?: string;
1829
- textarea?: string;
1830
- toggle?: string;
1831
- content?: string;
1832
- };
1833
- /** Custom styles for UI elements */
1834
- styles?: {
1835
- container?: React$1.CSSProperties;
1836
- preview?: React$1.CSSProperties;
1837
- editor?: React$1.CSSProperties;
1838
- textarea?: React$1.CSSProperties;
1839
- toggle?: React$1.CSSProperties;
1840
- content?: React$1.CSSProperties;
1841
- };
1842
- /** Custom container renderer for full headless control */
1843
- containerRenderer?: (props: {
1844
- children: ReactNode;
1845
- className: string;
1846
- style?: React$1.CSSProperties;
1847
- }) => ReactNode;
1848
- /** Custom preview renderer component */
1849
- previewRenderer?: (props: {
1850
- html: string;
1851
- onToggleEdit: () => void;
1852
- className: string;
1853
- style?: React$1.CSSProperties;
1854
- toggleClassName: string;
1855
- toggleStyle?: React$1.CSSProperties;
1856
- }) => ReactNode;
1857
- /** Custom editor renderer component */
1858
- editorRenderer?: (props: {
1859
- html: string;
1860
- onTogglePreview: () => void;
1861
- onSave: () => void;
1862
- className: string;
1863
- style?: React$1.CSSProperties;
1864
- textareaClassName: string;
1865
- textareaStyle?: React$1.CSSProperties;
1866
- toggleClassName: string;
1867
- toggleStyle?: React$1.CSSProperties;
1868
- }) => ReactNode;
1869
- /** Custom toggle button renderer component */
1870
- toggleRenderer?: (props: {
1871
- isPreview: boolean;
1872
- onClick: () => void;
1873
- className: string;
1874
- style?: React$1.CSSProperties;
1875
- }) => ReactNode;
1876
- /** Markdown extension instance used to register transformers */
1877
- markdownExtension?: typeof markdownExtension;
1878
- }
1879
- /**
1880
- * Commands exposed by the HTMLEmbedExtension
1881
- */
1882
- type HTMLEmbedCommands = {
1883
- /** Insert an HTML embed with optional initial HTML */
1884
- insertHTMLEmbed: (html?: string) => void;
1885
- /** Toggle between preview and edit modes */
1886
- toggleHTMLPreview: () => void;
1887
- };
1888
- /**
1889
- * State queries exposed by the HTMLEmbedExtension
1890
- */
1891
- type HTMLEmbedQueries = {
1892
- /** Check whether an HTML embed is selected */
1893
- isHTMLEmbedSelected: () => Promise<boolean>;
1894
- /** Check whether HTML preview mode is active */
1895
- isHTMLPreviewMode: () => Promise<boolean>;
1896
- };
1897
- /**
1898
- * Serialized representation of an HTMLEmbedNode
1899
- */
1900
- type SerializedHTMLEmbedNode = Spread<{
1901
- /** HTML content */
1902
- html: string;
1903
- /** Preview mode state */
1904
- preview: boolean;
1905
- /** Node type ID */
1906
- type: "html-embed";
1907
- /** Version for migrations */
1908
- version: 1;
1909
- }, SerializedLexicalNode>;
1910
- /**
1911
- * HTMLEmbedNode - A Lexical DecoratorNode for custom HTML embeds
1912
- *
1913
- * Allows users to embed custom HTML content in the editor.
1914
- * Supports preview mode (rendered HTML) and edit mode
1915
- * (editable HTML source).
1916
- *
1917
- * @example
1918
- * ```typescript
1919
- * const node = new HTMLEmbedNode({
1920
- * html: '<div>Hello World</div>',
1921
- * preview: true
1922
- * });
1923
- * ```
1924
- */
1925
- declare class HTMLEmbedNode extends DecoratorNode<ReactNode> {
1926
- __payload: HTMLEmbedPayload;
1927
- /**
1928
- * Get the node type identifier
1929
- * @returns Node type string
1930
- */
1931
- static getType(): string;
1932
- /**
1933
- * Clone the node
1934
- * @param node - Node to clone
1935
- * @returns New cloned node instance
1936
- */
1937
- static clone(node: HTMLEmbedNode): HTMLEmbedNode;
1938
- /**
1939
- * Constructor for HTMLEmbedNode
1940
- * @param payload - HTML embed payload
1941
- * @param key - Optional node key
1942
- */
1943
- constructor(payload: HTMLEmbedPayload, key?: NodeKey);
1944
- /**
1945
- * Create the DOM element for this node
1946
- * @returns DOM element
1947
- */
1948
- createDOM(): HTMLElement;
1949
- /**
1950
- * Update the DOM element (unused with React rendering)
1951
- * @returns Always false to let React handle updates
1952
- */
1953
- updateDOM(): boolean;
1954
- /**
1955
- * Import node from JSON serialization
1956
- * @param serialized - Serialized node data
1957
- * @returns New HTMLEmbedNode instance
1958
- */
1959
- static importJSON(serialized: SerializedHTMLEmbedNode): HTMLEmbedNode;
1960
- /**
1961
- * Export node to JSON serialization
1962
- * @returns Serialized node data
1963
- */
1964
- exportJSON(): SerializedHTMLEmbedNode;
1965
- static importDOM(): DOMConversionMap | null;
1966
- exportDOM(): {
1967
- element: HTMLElement;
1968
- };
1969
- getPayload(): HTMLEmbedPayload;
1970
- setPayload(payload: Partial<HTMLEmbedPayload>): void;
1971
- decorate(editor: LexicalEditor): ReactNode;
1972
- isInline(): false;
1973
- isKeyboardSelectable(): boolean;
1974
- }
1975
- declare class HTMLEmbedExtension extends BaseExtension<"htmlEmbed", HTMLEmbedConfig, HTMLEmbedCommands, HTMLEmbedQueries, ReactNode[]> {
1976
- constructor(config?: Partial<HTMLEmbedConfig>);
1977
- register(editor: LexicalEditor): () => void;
1978
- getNodes(): any[];
1979
- getPlugins(): ReactNode[];
1980
- getCommands(editor: LexicalEditor): HTMLEmbedCommands;
1981
- getStateQueries(editor: LexicalEditor): HTMLEmbedQueries;
1982
- }
1983
- declare const htmlEmbedExtension: HTMLEmbedExtension;
1984
-
1985
- type CustomPayload = Record<string, any>;
1986
- interface CustomNodeConfig<CustomCommands, CustomStateQueries> {
1987
- nodeType: string;
1988
- isContainer?: boolean;
1989
- defaultPayload?: CustomPayload;
1990
- initialChildren?: () => SerializedLexicalNode[];
1991
- render?: (props: {
1992
- node: LexicalNode;
1993
- payload: CustomPayload;
1994
- children?: ReactNode;
1995
- nodeKey: string;
1996
- isSelected: boolean;
1997
- updatePayload: (newPayload: Partial<CustomPayload>) => void;
1998
- }) => ReactNode;
1999
- jsx?: (props: {
2000
- node: LexicalNode;
2001
- payload: CustomPayload;
2002
- nodeKey: string;
2003
- isSelected: boolean;
2004
- updatePayload: (newPayload: Partial<CustomPayload>) => void;
2005
- }) => React.ReactElement;
2006
- createDOM?: (config: EditorConfig$1, node: LexicalNode) => HTMLElement;
2007
- updateDOM?: (prevNode: LexicalNode, dom: HTMLElement, config: EditorConfig$1) => boolean;
2008
- importDOM?: () => DOMConversionMap;
2009
- exportDOM?: (editor: LexicalEditor, options: {
2010
- element: HTMLElement;
2011
- node: LexicalNode;
2012
- }) => DOMExportOutput;
2013
- commands?: (editor: LexicalEditor) => CustomCommands;
2014
- stateQueries?: (editor: LexicalEditor) => CustomStateQueries;
2015
- }
2016
- /**
2017
- * Creates a custom node extension for the Luthor editor system.
2018
- * This factory lets you define custom Lexical nodes with React rendering,
2019
- * commands, and state queries.
2020
- *
2021
- * @template Name - Literal name type for the extension
2022
- * @template Commands - Commands exposed by this custom extension
2023
- * @template StateQueries - State query functions exposed by this extension
2024
- * @param userConfig - Configuration object defining the custom node behavior
2025
- * @returns Object containing the extension and helper functions
2026
- *
2027
- * @example
2028
- * ```tsx
2029
- * const { extension, $createCustomNode } = createCustomNodeExtension({
2030
- * nodeType: 'myBlock',
2031
- * render: ({ payload, isSelected }) => (
2032
- * <div className={isSelected ? 'selected' : ''}>
2033
- * {payload.text}
2034
- * </div>
2035
- * ),
2036
- * commands: (editor) => ({
2037
- * insertMyBlock: (data) => {
2038
- * const node = $createCustomNode(data);
2039
- * editor.dispatchCommand(INSERT_CUSTOM_NODE, node);
2040
- * }
2041
- * })
2042
- * });
2043
- * ```
2044
- */
2045
- declare function createCustomNodeExtension<Name extends string, Commands extends Record<string, any> = {}, StateQueries extends Record<string, () => Promise<boolean>> = {}>(userConfig: CustomNodeConfig<Commands, StateQueries>): {
2046
- extension: BaseExtension<Name, BaseExtensionConfig, Commands, StateQueries>;
2047
- $createCustomNode: (payload?: CustomPayload) => ElementNode | DecoratorNode<ReactNode>;
2048
- jsxToDOM: (jsxElement: React.ReactElement) => HTMLElement;
2049
- };
2050
-
2051
- interface BaseRichTextProps {
2052
- contentEditable?: React$1.ReactElement;
2053
- placeholder?: React$1.ReactElement | string;
2054
- className?: string;
2055
- classNames?: {
2056
- container?: string;
2057
- contentEditable?: string;
2058
- placeholder?: string;
2059
- };
2060
- styles?: {
2061
- container?: React$1.CSSProperties;
2062
- contentEditable?: React$1.CSSProperties;
2063
- placeholder?: React$1.CSSProperties;
2064
- };
2065
- errorBoundary?: React$1.ComponentType<{
2066
- children: React$1.JSX.Element;
2067
- onError: (error: Error) => void;
2068
- }>;
2069
- }
2070
- interface SharedRichTextProps extends BaseRichTextProps {
2071
- }
2072
- interface RichTextConfig extends BaseExtensionConfig, BaseRichTextProps {
2073
- }
2074
- interface RichTextConfig extends BaseExtensionConfig, BaseRichTextProps {
2075
- }
2076
- /**
2077
- * RichTextExtension - Provides core rich text editing functionality
2078
- * Extends BaseExtension to stay consistent with other extensions
2079
- */
2080
- declare class RichTextExtension extends BaseExtension<"richText", RichTextConfig, {}, // No commands
2081
- {}, // No state queries
2082
- ReactNode[]> {
2083
- constructor(config?: RichTextConfig);
2084
- register(editor: LexicalEditor): () => void;
2085
- getPlugins(): ReactNode[];
2086
- }
2087
- declare const richTextExtension: RichTextExtension;
2088
- interface RichTextComponentProps extends SharedRichTextProps {
2089
- }
2090
- declare const RichText: React$1.FC<RichTextComponentProps>;
38
+ declare const markdownPreset: EditorPreset;
2091
39
 
2092
- /**
2093
- * Selection rectangle with position data.
2094
- */
2095
- interface SelectionRect {
2096
- x: number;
2097
- y: number;
2098
- width: number;
2099
- height: number;
2100
- top: number;
2101
- left: number;
2102
- bottom: number;
2103
- right: number;
2104
- positionFromRight?: boolean;
2105
- }
2106
- /**
2107
- * Floating toolbar render props (typed, headless).
2108
- */
2109
- interface FloatingToolbarRenderProps<TCommands = any, TStates = any> {
2110
- /** Whether the toolbar is visible. */
2111
- isVisible: boolean;
2112
- /** Selection rectangle used for positioning. */
2113
- selectionRect: SelectionRect | null;
2114
- /** Current selection reference. */
2115
- selection: RangeSelection | null;
2116
- /** Lexical editor reference. */
2117
- editor: LexicalEditor;
2118
- /** Typed commands from the editor system. */
2119
- commands: TCommands;
2120
- /** Active state map from the editor system. */
2121
- activeStates: TStates;
2122
- /** Callback to dismiss the toolbar. */
2123
- hide: () => void;
2124
- /** Theme class names for styling. */
2125
- theme: {
2126
- container?: string;
2127
- button?: string;
2128
- buttonActive?: string;
2129
- };
2130
- }
2131
- /**
2132
- * FloatingToolbarExtension configuration.
2133
- */
2134
- interface FloatingConfig<TCommands = any, TStates = any> extends BaseExtensionConfig {
2135
- /**
2136
- * Headless render function for full UI control.
2137
- */
2138
- render: (props: FloatingToolbarRenderProps<TCommands, TStates>) => ReactNode | null;
2139
- /**
2140
- * Function to retrieve typed commands from the editor system.
2141
- */
2142
- getCommands?: () => TCommands;
2143
- /**
2144
- * Function to retrieve active states from the editor system.
2145
- */
2146
- getActiveStates?: () => TStates;
2147
- /**
2148
- * Portal anchor element (defaults to document.body).
2149
- */
2150
- anchorElem?: HTMLElement;
2151
- /**
2152
- * Debounce delay for selection changes (default: 100ms).
2153
- */
2154
- debounceMs?: number;
2155
- /**
2156
- * Offset from the selection (default: { x: 0, y: 8 }).
2157
- */
2158
- offset?: {
2159
- x: number;
2160
- y: number;
2161
- };
2162
- /**
2163
- * Position strategy (default: 'below').
2164
- */
2165
- positionStrategy?: "above" | "below" | "auto";
2166
- /**
2167
- * Theme class names for styling.
2168
- */
2169
- theme?: {
2170
- container?: string;
2171
- button?: string;
2172
- buttonActive?: string;
2173
- };
2174
- /**
2175
- * Toolbar dimensions for positioning calculations (default: { width: 300, height: 40 }).
2176
- */
2177
- toolbarDimensions?: {
2178
- width: number;
2179
- height: number;
2180
- };
2181
- }
2182
- /**
2183
- * Commands exposed by the floating toolbar extension (none by default).
2184
- */
2185
- type FloatingCommands = {};
2186
- /**
2187
- * State queries exposed by the floating toolbar extension.
2188
- */
2189
- type FloatingStateQueries = {
2190
- isFloatingVisible: () => Promise<boolean>;
2191
- };
2192
- /**
2193
- * FloatingToolbarExtension - Headless toolbar that appears on selection.
2194
- */
2195
- declare class FloatingToolbarExtension<TCommands = any, TStates = any> extends BaseExtension<"floatingToolbar", FloatingConfig<TCommands, TStates>, FloatingCommands, FloatingStateQueries, ReactNode[]> {
2196
- private isVisible;
2197
- private selectionRect;
2198
- constructor();
2199
- register(editor: LexicalEditor): () => void;
2200
- getPlugins(): ReactNode[];
2201
- getCommands(editor: LexicalEditor): FloatingCommands;
2202
- getStateQueries(editor: LexicalEditor): FloatingStateQueries;
2203
- updateContext(commands: TCommands, activeStates: TStates): void;
2204
- getSelectionRect(): SelectionRect | null;
2205
- getIsVisible(): boolean;
2206
- setVisible(visible: boolean): void;
2207
- setSelectionRect(rect: SelectionRect | null): void;
2208
- }
2209
- /**
2210
- * Preconfigured instance.
2211
- */
2212
- declare const floatingToolbarExtension: FloatingToolbarExtension<any, any>;
40
+ declare const minimalPreset: EditorPreset;
2213
41
 
2214
- /**
2215
- * Command palette item definition
2216
- */
2217
- type CommandPaletteItem = {
42
+ interface EditorPreset {
2218
43
  id: string;
2219
44
  label: string;
2220
45
  description?: string;
2221
- action: () => void;
2222
- keywords?: string[];
2223
- category?: string;
2224
- icon?: React$1.ReactNode;
2225
- shortcut?: string;
2226
- };
2227
- /**
2228
- * Commands exposed by the command palette extension
2229
- */
2230
- type CommandPaletteCommands = {
2231
- showCommandPalette: () => void;
2232
- hideCommandPalette: () => void;
2233
- registerCommand: (item: CommandPaletteItem) => void;
2234
- unregisterCommand: (id: string) => void;
2235
- };
2236
- /**
2237
- * State queries exposed by the command palette extension
2238
- */
2239
- type CommandPaletteStateQueries = {
2240
- isCommandPaletteOpen: () => Promise<boolean>;
2241
- };
2242
- /**
2243
- * Command palette extension for quick access to editor commands.
2244
- * Provides a searchable command palette similar to VS Code.
2245
- */
2246
- declare class CommandPaletteExtension extends BaseExtension<"commandPalette", any, CommandPaletteCommands, CommandPaletteStateQueries, React$1.ReactElement[]> {
2247
- private isOpen;
2248
- private commands;
2249
- private listeners;
2250
- constructor();
2251
- register(editor: LexicalEditor): () => void;
2252
- getCommands(editor: LexicalEditor): CommandPaletteCommands;
2253
- getStateQueries(editor: LexicalEditor): CommandPaletteStateQueries;
2254
- private showCommandPalette;
2255
- private hideCommandPalette;
2256
- private toggleCommandPalette;
2257
- private registerCommand;
2258
- private unregisterCommand;
2259
- private registerTableCommands;
2260
- private notifyListeners;
2261
- /**
2262
- * Subscribe to command palette updates
2263
- */
2264
- subscribe(listener: (isOpen: boolean, commands: CommandPaletteItem[]) => void): () => void;
2265
- getAllCommands(): CommandPaletteItem[];
46
+ extensions?: Extension[];
47
+ config?: EditorConfig;
48
+ theme?: LuthorTheme;
49
+ toolbar?: string[];
50
+ components?: Record<string, unknown>;
51
+ css?: string;
2266
52
  }
2267
- declare const commandPaletteExtension: CommandPaletteExtension;
2268
53
 
2269
- /**
2270
- * All Markdown transformers collected in one place
2271
- * Import this array to get all available transformers
2272
- */
2273
- declare const ALL_MARKDOWN_TRANSFORMERS: ({
2274
- format: readonly ["underline"];
2275
- tag: string;
2276
- type: "text-format";
2277
- } | {
2278
- dependencies: typeof _lexical_react_LexicalHorizontalRuleNode.HorizontalRuleNode[];
2279
- export: (node: lexical.LexicalNode) => "---" | null;
2280
- regExp: RegExp;
2281
- replace: (parentNode: lexical.ElementNode, children: lexical.LexicalNode[], match: string[]) => void;
2282
- type: "element";
2283
- } | {
2284
- dependencies: (typeof _lexical_table.TableNode | typeof _lexical_table.TableRowNode | typeof _lexical_table.TableCellNode)[];
2285
- export: (node: any) => string | null;
2286
- regExpStart: RegExp;
2287
- regExpEnd: {
2288
- optional: true;
2289
- regExp: RegExp;
2290
- };
2291
- replace: (rootNode: any, children: any, startMatch: any, endMatch: any, linesInBetween: any, isImport: boolean) => void;
2292
- type: "multiline-element";
2293
- } | {
2294
- dependencies: typeof HTMLEmbedNode[];
2295
- export: (node: any) => string | null;
2296
- regExpStart: RegExp;
2297
- regExpEnd: {
2298
- optional: true;
2299
- regExp: RegExp;
2300
- };
2301
- replace: (rootNode: any, children: any, startMatch: any, endMatch: any, linesInBetween: any, isImport: boolean) => void;
2302
- type: "multiline-element";
2303
- } | {
2304
- dependencies: typeof ImageNode[];
2305
- export: (node: lexical.LexicalNode) => string | null;
2306
- regExp: RegExp;
2307
- replace: (parentNode: lexical.ElementNode, _children: lexical.LexicalNode[], match: string[], isImport: boolean) => void;
2308
- type: "element";
2309
- })[];
54
+ declare const presetRegistry: Record<string, EditorPreset>;
2310
55
 
2311
- export { ALL_MARKDOWN_TRANSFORMERS, type Alignment, type BaseCommands, BaseExtension, type BaseExtensionConfig, BaseProvider, BlockFormatExtension, BoldExtension, CodeExtension, CodeFormatExtension, type CommandPaletteCommands, CommandPaletteExtension, type CommandPaletteItem, type CommandPaletteStateQueries, type ContextMenuCommands, type ContextMenuConfig, ContextMenuExtension, type ContextMenuItem, type ContextMenuStateQueries, DraggableBlockExtension, type DraggableCommands, type DraggableConfig, type DraggableStateQueries, type EditorConfig, type EditorContextType, type Extension, ExtensionCategory, type ExtractCommands, type ExtractNames, type ExtractPlugins, type ExtractStateQueries, type FloatingCommands, type FloatingConfig, type FloatingStateQueries, FloatingToolbarExtension, HTMLEmbedExtension, HTMLExtension, HistoryExtension, HorizontalRuleExtension, type ImageCommands, type ImageComponentProps, ImageExtension, type ImageExtensionConfig, type ImagePayload, type ImageStateQueries, ItalicExtension, LinkExtension, ListExtension, type LuthorTheme, MarkdownExtension, RichText, type RichTextComponentProps, type RichTextConfig, type SerializedImageNode, StrikethroughExtension, type TableConfig, TableExtension, TextFormatExtension, type ToolbarItem, UnderlineExtension, blockFormatExtension, boldExtension, codeExtension, codeFormatExtension, commandPaletteExtension, contextMenuExtension, createCustomNodeExtension, createEditorSystem, createExtension, defaultLuthorTheme, draggableBlockExtension, floatingToolbarExtension, historyExtension, horizontalRuleExtension, htmlEmbedExtension, htmlExtension, imageExtension, isLuthorTheme, italicExtension, linkExtension, listExtension, markdownExtension, mergeThemes, richTextExtension, strikethroughExtension, tableExtension, underlineExtension, useBaseEditor };
56
+ export { type EditorPreset, ExtensiveEditor, blogPreset, chatPreset, classicPreset, cmsPreset, codePreset, defaultPreset, docsPreset, emailPreset, extensiveExtensions, extensivePreset, markdownPreset, minimalPreset, presetRegistry };