@lyfie/luthor-headless 2.3.1 → 2.3.3

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/README.md CHANGED
@@ -1,671 +1,20 @@
1
1
  # @lyfie/luthor-headless
2
2
 
3
- Type-safe, headless rich text editor system for React, built on Lexical.
3
+ Headless, extension-first rich text editor runtime for React on top of Lexical.
4
4
 
5
- ## Package responsibility
6
-
7
- - Owns Lexical-derived behavior and extension runtime semantics.
8
- - Designed to stay lightweight with optional integrations that degrade gracefully.
9
- - Preset UX belongs in `@lyfie/luthor`.
10
-
11
- ## Installation
12
-
13
- ```bash
14
- pnpm add @lyfie/luthor-headless lexical @lexical/code @lexical/html @lexical/link @lexical/list @lexical/markdown @lexical/react @lexical/rich-text @lexical/selection @lexical/table @lexical/utils react react-dom
15
- ```
16
-
17
- Optional syntax highlighting provider:
5
+ ## Install
18
6
 
19
7
  ```bash
20
- pnpm add highlight.js
8
+ pnpm add @lyfie/luthor-headless lexical @lexical/code @lexical/link @lexical/list @lexical/markdown @lexical/react @lexical/rich-text @lexical/selection @lexical/table @lexical/utils react react-dom
21
9
  ```
22
10
 
23
- Optional emoji catalog provider:
11
+ Optional:
24
12
 
25
13
  ```bash
26
- pnpm add @emoji-mart/data
27
- ```
28
-
29
- Optional package behavior:
30
-
31
- - Without `highlight.js`, code blocks use built-in fallback token styling.
32
- - Without `@emoji-mart/data`, emoji features use the built-in lightweight catalog.
33
- - Both optional packages are fail-safe and do not block editor startup.
34
-
35
- ## Quick Start
36
-
37
- ```tsx
38
- import {
39
- createEditorSystem,
40
- RichText,
41
- richTextExtension,
42
- boldExtension,
43
- italicExtension,
44
- } from "@lyfie/luthor-headless";
45
-
46
- const extensions = [richTextExtension, boldExtension, italicExtension] as const;
47
- const { Provider, useEditor } = createEditorSystem<typeof extensions>();
48
-
49
- function Toolbar() {
50
- const { commands, activeStates } = useEditor();
51
-
52
- return (
53
- <div>
54
- <button onClick={() => commands.toggleBold()} aria-pressed={activeStates.bold}>
55
- Bold
56
- </button>
57
- <button onClick={() => commands.toggleItalic()} aria-pressed={activeStates.italic}>
58
- Italic
59
- </button>
60
- </div>
61
- );
62
- }
63
-
64
- export function Editor() {
65
- return (
66
- <Provider extensions={extensions}>
67
- <Toolbar />
68
- <RichText placeholder="Write here..." />
69
- </Provider>
70
- );
71
- }
14
+ pnpm add highlight.js @emoji-mart/data
72
15
  ```
73
16
 
74
- ## Core API
75
-
76
- ### `createEditorSystem<Exts>()`
77
-
78
- Returns:
79
-
80
- - `Provider(props)`
81
- - `useEditor()`
82
-
83
- `Provider` props:
84
-
85
- - `extensions: Exts` (required)
86
- - `children: ReactNode` (required)
87
- - `config?: EditorConfig`
88
-
89
- `EditorConfig`:
90
-
91
- - `theme?: EditorThemeClasses`
92
- - any additional keys are allowed and can be consumed by extensions/components
93
-
94
- ### `useEditor()` context
95
-
96
- Returns strongly typed surface based on `extensions`:
97
-
98
- - `commands`
99
- - `activeStates`
100
- - `stateQueries`
101
- - `hasExtension(name)`
102
- - `export.toJSON()`
103
- - `import.fromJSON(json)`
104
- - `lexical` / `editor`
105
- - `plugins`
106
- - listener helpers (`registerUpdate`, `registerPaste`)
107
-
108
- ## RichText Component API
109
-
110
- `RichText` and `RichTextExtension` use the same prop shape:
111
-
112
- - `contentEditable?: ReactElement`
113
- - `placeholder?: ReactElement | string`
114
- - `className?: string`
115
- - `classNames?: { container?: string; contentEditable?: string; placeholder?: string }`
116
- - `styles?: { container?: CSSProperties; contentEditable?: CSSProperties; placeholder?: CSSProperties }`
117
- - `errorBoundary?: ComponentType<{ children: JSX.Element; onError: (error: Error) => void }>`
118
-
119
- ## Theme Utilities
120
-
121
- - `defaultLuthorTheme`
122
- - `mergeThemes(baseTheme, overrideTheme)`
123
- - `isLuthorTheme(value)`
124
- - `LUTHOR_EDITOR_THEME_TOKENS`
125
- - `createEditorThemeStyleVars(overrides)`
126
-
127
- `LuthorEditorThemeOverrides` is a token map with keys from `LUTHOR_EDITOR_THEME_TOKENS` and string values.
128
-
129
- ## Markdown Bridge API
130
-
131
- Headless now exposes lightweight markdown bridge helpers:
132
-
133
- - `markdownToJSONB(markdown: string): JsonbDocument`
134
- - `jsonbToMarkdown(input: unknown): string`
135
-
136
- These are intended as conversion primitives for preset mode-switch UIs (for example `MDTextEditor` in `@lyfie/luthor`).
137
-
138
- ## Base Extension Config
139
-
140
- All extension configs support `BaseExtensionConfig`:
141
-
142
- - `showInToolbar?: boolean`
143
- - `category?: ExtensionCategory[]`
144
- - `position?: "before" | "after"`
145
- - `initPriority?: number`
146
-
147
- ## Built-in Extensions
148
-
149
- ### Text Formatting
150
-
151
- - `boldExtension`
152
- - `italicExtension`
153
- - `underlineExtension`
154
- - `strikethroughExtension`
155
- - `subscriptExtension`
156
- - `superscriptExtension`
157
- - `codeFormatExtension` (inline code mark)
158
-
159
- These are toggle-style text-format extensions and do not require custom config.
160
-
161
- ### Link Extension (`LinkExtension`, `linkExtension`)
162
-
163
- `LinkConfig`:
164
-
165
- - `autoLinkText?: boolean`
166
- - `autoLinkUrls?: boolean`
167
- - `linkSelectedTextOnPaste?: boolean`
168
- - `validateUrl?: (url: string) => boolean`
169
- - `clickableLinks?: boolean`
170
- - `openLinksInNewTab?: boolean`
171
-
172
- Commands:
173
-
174
- - `insertLink(url?, text?)`
175
- - `updateLink(url, rel?, target?)`
176
- - `removeLink()`
177
- - `getCurrentLink()`
178
- - `getLinkByKey(linkNodeKey)`
179
- - `updateLinkByKey(linkNodeKey, url, rel?, target?)`
180
- - `removeLinkByKey(linkNodeKey)`
181
-
182
- Note: set `autoLinkUrls` explicitly in your config for unambiguous paste-link behavior.
183
-
184
- ### Typography Selectors
185
-
186
- #### `FontFamilyExtension`
187
-
188
- `FontFamilyOption`:
189
-
190
- - `value: string`
191
- - `label: string`
192
- - `fontFamily: string`
193
- - `cssImportUrl?: string`
194
-
195
- `FontFamilyConfig`:
196
-
197
- - `options: readonly FontFamilyOption[]`
198
- - `cssLoadStrategy: "none" | "preload-all" | "on-demand"`
199
-
200
- Nuances:
201
-
202
- - Invalid/duplicate option values are sanitized out.
203
- - `default` option is auto-inserted when omitted.
204
-
205
- #### `FontSizeExtension`
206
-
207
- `FontSizeOption`:
208
-
209
- - `value: string`
210
- - `label: string`
211
- - `fontSize: string`
212
-
213
- `FontSizeConfig`:
214
-
215
- - `options: readonly FontSizeOption[]`
216
-
217
- Nuances:
218
-
219
- - Invalid/duplicate option values are sanitized out.
220
- - `default` option is auto-inserted when omitted.
221
-
222
- #### `LineHeightExtension`
223
-
224
- `LineHeightOption`:
225
-
226
- - `value: string`
227
- - `label: string`
228
- - `lineHeight: string`
229
-
230
- `LineHeightConfig`:
231
-
232
- - `options: readonly LineHeightOption[]`
233
- - `defaultLineHeight?: string` (default `"1.5"`)
234
-
235
- Nuances:
236
-
237
- - `value: "default"` maps to `defaultLineHeight` (or `"1.5"` when not configured).
238
- - Non-default entries should use numeric ratios `>= 1.0` (`"1"`, `"1.5"`, `"2"`).
239
- - Line height is applied at block level (TinyMCE-style): selecting text inside a block updates that whole block.
240
-
241
- #### `TextColorExtension`
242
-
243
- `TextColorOption`:
244
-
245
- - `value: string`
246
- - `label: string`
247
- - `color: string`
248
-
249
- `TextColorConfig`:
250
-
251
- - `options: readonly TextColorOption[]`
252
-
253
- Nuances:
254
-
255
- - `setTextColor` accepts configured option values and valid CSS colors.
256
-
257
- #### `TextHighlightExtension`
258
-
259
- `TextHighlightOption`:
260
-
261
- - `value: string`
262
- - `label: string`
263
- - `backgroundColor: string`
264
-
265
- `TextHighlightConfig`:
266
-
267
- - `options: readonly TextHighlightOption[]`
268
-
269
- Nuances:
270
-
271
- - `setTextHighlight` accepts configured option values and valid CSS colors.
272
- - Highlight styling also patches padding/box-decoration style helpers for clean rendering.
273
-
274
- ### Block/Structure Extensions
275
-
276
- #### `blockFormatExtension`
277
-
278
- Commands include paragraph/heading/quote toggles and alignment helpers. No custom config required.
279
-
280
- #### `listExtension`
281
-
282
- Commands include unordered/ordered/check list toggles and indentation commands. No custom config required.
283
-
284
- #### `horizontalRuleExtension`
285
-
286
- Commands include horizontal rule insertion. No custom config required.
287
-
288
- ### Code Extensions
289
-
290
- #### `CodeExtension`
291
-
292
- `CodeExtensionConfig`:
293
-
294
- - `syntaxHighlighting?: "auto" | "disabled"`
295
- - `tokenizer?: CodeTokenizer | null`
296
- - `provider?: CodeHighlightProvider | null`
297
- - `loadProvider?: () => Promise<CodeHighlightProvider | null>`
17
+ ## Docs
298
18
 
299
- Usage (manual language selection + plaintext fallback):
300
-
301
- ```tsx
302
- import {
303
- codeExtension,
304
- codeIntelligenceExtension,
305
- } from "@lyfie/luthor-headless";
306
-
307
- const extensions = [
308
- codeExtension.configure({
309
- syntaxHighlighting: "auto", // default
310
- }),
311
- codeIntelligenceExtension,
312
- ] as const;
313
- ```
314
-
315
- - `CodeIntelligenceExtension` no longer auto-detects code languages.
316
- - Selecting `plaintext` keeps code tokens in the plaintext fallback theme (`plain`).
317
- - Selecting any non-plaintext language switches token classes to the `hljs-*` namespace.
318
- - Language values are alias-normalized (`md` -> `markdown`, `ts` -> `typescript`, `js` -> `javascript` family).
319
- - Only Prism-supported loaded languages are accepted. Unsupported values are treated as plaintext.
320
- - If your app loads a highlight.js stylesheet, those `hljs-*` token colors are applied automatically.
321
- - Without a highlight.js stylesheet, code remains muted/plain fallback.
322
-
323
- `CodeHighlightProvider` shape:
324
-
325
- - `highlightAuto?(code, languageSubset?)`
326
- - `tokenizer?: CodeTokenizer | null`
327
- - `getTokenizer?: () => CodeTokenizer | null | Promise<CodeTokenizer | null>`
328
-
329
- #### `CodeIntelligenceExtension`
330
-
331
- `CodeLanguageOptionsConfig`:
332
-
333
- - `mode?: "append" | "replace"`
334
- - `values: readonly string[]`
335
-
336
- `CodeIntelligenceConfig`:
337
-
338
- - `provider?: CodeHighlightProvider | null`
339
- - `loadProvider?: () => Promise<CodeHighlightProvider | null>`
340
- - `maxAutoDetectLength?: number` (default `12000`)
341
- - `isCopyAllowed?: boolean` (default `true`)
342
- - `languageOptions?: readonly string[] | CodeLanguageOptionsConfig`
343
-
344
- Commands:
345
-
346
- - `setCodeLanguage(language)`
347
- - `autoDetectCodeLanguage()`
348
- - `getCurrentCodeLanguage()`
349
- - `getCodeLanguageOptions()`
350
- - `copySelectedCodeBlock()`
351
-
352
- Nuances:
353
-
354
- - Array form for `languageOptions` is equivalent to `{ mode: "append", values }`.
355
- - Aliases are normalized.
356
- - Duplicate normalized languages throw.
357
-
358
- ### History and Input Behavior
359
-
360
- - `historyExtension`: undo/redo commands and canUndo/canRedo state.
361
- - `tabIndentExtension`: tab/shift-tab indent behavior.
362
- - `enterKeyBehaviorExtension`: enter behavior normalization (quotes/code/table transitions). No extra config.
363
-
364
- ### Table Extension (`TableExtension`, `tableExtension`)
365
-
366
- `TableConfig`:
367
-
368
- - `rows?: number`
369
- - `columns?: number`
370
- - `includeHeaders?: boolean`
371
- - `enableContextMenu?: boolean`
372
- - `contextMenuItems?: ContextMenuItem[] | ((commands: TableCommands) => ContextMenuItem[])`
373
- - `contextMenuRenderer?: ContextMenuRenderer`
374
- - `contextMenuExtension?: typeof contextMenuExtension`
375
- - `tableBubbleRenderer?: (props: TableBubbleRenderProps) => ReactNode`
376
-
377
- `TableBubbleRenderProps`:
378
-
379
- - `headersEnabled: boolean`
380
- - `setHeadersEnabled(enabled)`
381
- - `actions`: row/column insert/delete + delete table actions
382
-
383
- Defaults:
384
-
385
- - `rows: 3`
386
- - `columns: 3`
387
- - `includeHeaders: false`
388
- - `enableContextMenu: true`
389
-
390
- ### Media Extensions
391
-
392
- #### Image (`ImageExtension`, `imageExtension`)
393
-
394
- `ImageExtensionConfig`:
395
-
396
- - `uploadHandler?: (file: File) => Promise<string>`
397
- - `defaultAlignment?: "left" | "right" | "center" | "none"`
398
- - `classNames?: Partial<Record<Alignment | "wrapper" | "caption", string>>`
399
- - `styles?: Partial<Record<Alignment | "wrapper" | "caption", CSSProperties>>`
400
- - `customRenderer?: ComponentType<ImageComponentProps>`
401
- - `resizable?: boolean` (default `true`)
402
- - `scaleByRatio?: boolean` (default `false`)
403
- - `pasteListener?: { insert: boolean; replace: boolean }` (default both `true`)
404
- - `debug?: boolean` (default `false`)
405
- - `forceUpload?: boolean` (default `false`)
406
-
407
- #### Iframe (`IframeEmbedExtension`, `iframeEmbedExtension`)
408
-
409
- `IframeEmbedConfig`:
410
-
411
- - `defaultWidth?: number` (default `640`)
412
- - `defaultHeight?: number` (default `360`)
413
- - `defaultAlignment?: "left" | "center" | "right"` (default `"center"`)
414
-
415
- #### YouTube (`YouTubeEmbedExtension`, `youTubeEmbedExtension`)
416
-
417
- `YouTubeEmbedConfig`:
418
-
419
- - `defaultWidth?: number` (default `640`)
420
- - `defaultHeight?: number` (default `480`)
421
- - `defaultAlignment?: "left" | "center" | "right"` (default `"center"`)
422
- - `allowFullscreen?: boolean` (default `true`)
423
- - `autoplay?: boolean` (default `false`)
424
- - `controls?: boolean` (default `true`)
425
- - `nocookie?: boolean` (default `true`)
426
- - `rel?: number` (default `1`)
427
-
428
- ### Command UI Extensions
429
-
430
- #### Slash Command (`SlashCommandExtension`, `slashCommandExtension`)
431
-
432
- `SlashCommandItem`:
433
-
434
- - `id`, `label`, `action`
435
- - optional: `description`, `keywords`, `category`, `icon`, `shortcut`
436
-
437
- `SlashCommandConfig`:
438
-
439
- - `trigger?: string` (default `"/"`)
440
- - `offset?: { x: number; y: number }` (default `{ x: 0, y: 8 }`)
441
- - `items?: readonly SlashCommandItem[]`
442
-
443
- Commands:
444
-
445
- - `registerSlashCommand(item)`
446
- - `unregisterSlashCommand(id)`
447
- - `setSlashCommands(items)`
448
- - `closeSlashMenu()`
449
- - `executeSlashCommand(id)`
450
-
451
- #### Command Palette (`CommandPaletteExtension`, `commandPaletteExtension`)
452
-
453
- `CommandPaletteItem`:
454
-
455
- - `id`, `label`, `action`
456
- - optional: `description`, `keywords`, `category`, `icon`, `shortcut`
457
-
458
- Commands:
459
-
460
- - `showCommandPalette()`
461
- - `hideCommandPalette()`
462
- - `registerCommand(item)`
463
- - `unregisterCommand(id)`
464
-
465
- #### Emoji (`EmojiExtension`, `emojiExtension`)
466
-
467
- `EmojiCatalogItem`:
468
-
469
- - `emoji`, `label`, `shortcodes`
470
- - optional `keywords`
471
-
472
- `EmojiConfig`:
473
-
474
- - `trigger?: string` (default `":"`)
475
- - `maxSuggestions?: number` (default `8`)
476
- - `maxQueryLength?: number` (default `32`)
477
- - `autoReplaceSymbols?: boolean` (default `true`)
478
- - `symbolReplacements?: Record<string, string>`
479
- - `catalog?: EmojiCatalogItem[]`
480
- - `catalogAdapter?: { search(query, options?), resolveShortcode(shortcode), getAll() }`
481
- - `autoDetectExternalCatalog?: boolean` (default `true`, auto-detects emoji-mart data if available)
482
- - `offset?: { x: number; y: number }` (default `{ x: 0, y: 8 }`)
483
-
484
- Commands:
485
-
486
- - `insertEmoji(emoji)`
487
- - `executeEmojiSuggestion(emoji)`
488
- - `closeEmojiSuggestions()`
489
- - `getEmojiSuggestions(query?)`
490
- - `getEmojiCatalog()`
491
- - `resolveEmojiShortcode(shortcode)`
492
- - `setEmojiCatalog(catalog)`
493
- - `setEmojiCatalogAdapter(adapter)`
494
- - `getEmojiCatalogAdapter()`
495
-
496
- Behavior:
497
-
498
- - If no custom catalog/adapter is provided, emoji will auto-detect emoji-mart data when available.
499
- - If nothing is detected, it falls back to the built-in lightweight catalog.
500
-
501
- Usage (including `apps/demo`):
502
-
503
- ```bash
504
- pnpm add -F demo @emoji-mart/data
505
- ```
506
-
507
- - No editor config changes are required.
508
- - After install, typing `:shortcode` and opening the emoji toolbar picker will use the detected emoji-mart catalog.
509
- - If `@emoji-mart/data` is not installed (or not available globally), behavior stays on the built-in fallback catalog.
510
-
511
- ### Context/Overlay Extensions
512
-
513
- #### Context Menu (`ContextMenuExtension`, `contextMenuExtension`)
514
-
515
- `ContextMenuConfig`:
516
-
517
- - `defaultRenderer?: ContextMenuRenderer`
518
- - `preventDefault?: boolean`
519
- - `theme?: { container?: string; item?: string; itemDisabled?: string }`
520
- - `styles?: { container?: CSSProperties; item?: CSSProperties; itemDisabled?: CSSProperties }`
521
-
522
- Commands:
523
-
524
- - `registerProvider(provider)`
525
- - `unregisterProvider(id)`
526
- - `showContextMenu({ items, position, renderer? })`
527
- - `hideContextMenu()`
528
-
529
- `ContextMenuProvider`:
530
-
531
- - `id`
532
- - `priority?`
533
- - `canHandle(context)`
534
- - `getItems(context)`
535
- - `renderer?`
536
-
537
- #### Floating Toolbar (`FloatingToolbarExtension`, `floatingToolbarExtension`)
538
-
539
- `FloatingConfig<TCommands, TStates>`:
540
-
541
- - `render(props)`
542
- - `getCommands?(): TCommands`
543
- - `getActiveStates?(): TStates`
544
- - `anchorElem?: HTMLElement`
545
- - `debounceMs?: number` (default `100`)
546
- - `offset?: { x: number; y: number }` (default `{ x: 0, y: 8 }`)
547
- - `positionStrategy?: "above" | "below" | "auto"` (default `"below"`)
548
- - `theme?: { container?: string; button?: string; buttonActive?: string }`
549
- - `toolbarDimensions?: { width: number; height: number }`
550
-
551
- #### Draggable Blocks (`DraggableBlockExtension`, `draggableBlockExtension`)
552
-
553
- `DraggableConfig`:
554
-
555
- - `anchorElem?: HTMLElement`
556
- - `showAddButton?: boolean`
557
- - `buttonStackPosition?: "left" | "right"`
558
- - `enableTextSelectionDrag?: boolean`
559
- - `offsetLeft?: number`
560
- - `offsetRight?: number`
561
- - `theme?: { handle?, handleActive?, blockDragging?, dropIndicator?, addButton?, buttonStack? }`
562
- - `styles?: { handle?, handleActive?, blockDragging?, dropIndicator?, addButton?, buttonStack? }`
563
- - `handleRenderer?(props)`
564
- - `buttonsRenderer?(props)`
565
- - `dropIndicatorRenderer?(props)`
566
-
567
- Default behavior includes draggable handle, add button, and left-side controls.
568
-
569
- ### Custom Nodes
570
-
571
- `createCustomNodeExtension(config)` lets you define a full custom node extension.
572
-
573
- `CustomNodeConfig` includes:
574
-
575
- - `nodeType: string`
576
- - `isContainer?: boolean`
577
- - `defaultPayload?: Record<string, any>`
578
- - `initialChildren?: () => SerializedLexicalNode[]`
579
- - `render?` or `jsx?`
580
- - DOM import/export hooks (`createDOM`, `updateDOM`, `importDOM`, `exportDOM`)
581
- - `commands?(editor)`
582
- - `stateQueries?(editor)`
583
-
584
- Returns:
585
-
586
- - `extension`
587
- - `$createCustomNode(payload?)`
588
- - `jsxToDOM(jsxElement)`
589
-
590
- ## Complete Extension Example
591
-
592
- ```tsx
593
- import {
594
- createEditorSystem,
595
- RichText,
596
- richTextExtension,
597
- historyExtension,
598
- boldExtension,
599
- italicExtension,
600
- linkExtension,
601
- listExtension,
602
- blockFormatExtension,
603
- tableExtension,
604
- imageExtension,
605
- slashCommandExtension,
606
- commandPaletteExtension,
607
- codeExtension,
608
- codeIntelligenceExtension,
609
- } from "@lyfie/luthor-headless";
610
-
611
- const extensions = [
612
- richTextExtension,
613
- historyExtension,
614
- boldExtension,
615
- italicExtension,
616
- linkExtension.configure({
617
- autoLinkText: true,
618
- autoLinkUrls: true,
619
- linkSelectedTextOnPaste: true,
620
- }),
621
- listExtension,
622
- blockFormatExtension,
623
- tableExtension.configure({
624
- rows: 3,
625
- columns: 4,
626
- includeHeaders: true,
627
- }),
628
- imageExtension.configure({
629
- resizable: true,
630
- scaleByRatio: true,
631
- }),
632
- codeExtension.configure({
633
- syntaxHighlighting: "auto",
634
- }),
635
- codeIntelligenceExtension.configure({
636
- maxAutoDetectLength: 12000,
637
- isCopyAllowed: true,
638
- languageOptions: {
639
- mode: "append",
640
- values: ["sql", "yaml"],
641
- },
642
- }),
643
- slashCommandExtension,
644
- commandPaletteExtension,
645
- ] as const;
646
-
647
- const { Provider } = createEditorSystem<typeof extensions>();
648
-
649
- export function Editor() {
650
- return (
651
- <Provider extensions={extensions}>
652
- <RichText placeholder="Write here..." />
653
- </Provider>
654
- );
655
- }
656
- ```
657
-
658
- ## Documentation
659
-
660
- - Monorepo docs index: [../../documentation/index.md](../../documentation/index.md)
661
- - User docs: [../../documentation/user/headless/getting-started.md](../../documentation/user/headless/getting-started.md)
662
- - Developer docs: [../../documentation/developer/headless/architecture.md](../../documentation/developer/headless/architecture.md)
663
- - Luthor preset package README: [../luthor/README.md](../luthor/README.md)
664
-
665
- ## Workspace Development
666
-
667
- ```bash
668
- pnpm --filter @lyfie/luthor-headless dev
669
- pnpm --filter @lyfie/luthor-headless build
670
- pnpm --filter @lyfie/luthor-headless lint
671
- ```
19
+ - https://luthor-editor.vercel.app/docs/getting-started/luthor-headless/
20
+ - https://luthor-editor.vercel.app/docs/luthor-headless/features/
package/package.json CHANGED
@@ -1,21 +1,20 @@
1
1
  {
2
2
  "name": "@lyfie/luthor-headless",
3
- "version": "2.3.1",
3
+ "version": "2.3.3",
4
4
  "description": "Luthor Editor - A headless, extensible rich text editor built on Lexical",
5
5
  "type": "module",
6
6
  "private": false,
7
- "main": "./dist/index.cjs",
7
+ "main": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "files": [
10
- "dist",
11
- "README.md"
10
+ "dist/**/*.js",
11
+ "dist/**/*.d.ts"
12
12
  ],
13
13
  "sideEffects": false,
14
14
  "exports": {
15
15
  ".": {
16
16
  "types": "./dist/index.d.ts",
17
17
  "import": "./dist/index.js",
18
- "require": "./dist/index.cjs",
19
18
  "default": "./dist/index.js"
20
19
  }
21
20
  },