@lyfie/luthor 2.0.1 → 2.2.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/README.md CHANGED
@@ -1,48 +1,567 @@
1
1
  # Luthor Presets
2
2
 
3
- Presets and plug-and-play configurations for the Luthor headless editor.
3
+ **Batteries-included presets and plug-and-play configurations for the Luthor editor**
4
4
 
5
- ## Install
5
+ This package provides ready-to-use editor presets built on top of [@lyfie/luthor-headless](../headless/README.md). All Lexical dependencies are included - no additional installations required.
6
+
7
+ [![npm version](https://badge.fury.io/js/%40lyfie%2Fluthor.svg)](https://badge.fury.io/js/%40lyfie%2Fluthor)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ---
11
+
12
+ ## Why Use This Package?
13
+
14
+ ### ✅ Zero Configuration Hassle
15
+ - All Lexical packages bundled as dependencies
16
+ - No peer dependency warnings
17
+ - No version conflicts to resolve
18
+
19
+ ### 🎮 Ready-to-Use Editors
20
+ - Multiple presets for different use cases
21
+ - Pre-built toolbar components
22
+ - Styled and themed out of the box
23
+
24
+ ### 🔧 Still Fully Customizable
25
+ - Extend or modify any preset
26
+ - Access all luthor-headless features
27
+ - Build on top of presets with your own extensions
28
+
29
+ ---
30
+
31
+ ## Installation
32
+
33
+ Install both the headless package and this preset package:
6
34
 
7
35
  ```bash
8
- npm install @lyfie/luthor @lyfie/luthor-headless
36
+ # npm
37
+ npm install @lyfie/luthor-headless @lyfie/luthor
38
+
39
+ # pnpm
40
+ pnpm add @lyfie/luthor-headless @lyfie/luthor
9
41
  ```
10
42
 
11
- Install the Lexical peer dependencies:
43
+ **That's it!** All required Lexical packages are automatically installed as dependencies of `@lyfie/luthor`.
12
44
 
13
- ```bash
14
- npm install lexical @lexical/react @lexical/html @lexical/markdown @lexical/list @lexical/rich-text @lexical/selection @lexical/utils
45
+ ### What Gets Installed
46
+
47
+ When you install `@lyfie/luthor`, your package manager (npm/pnpm) automatically installs:
48
+ - `@lyfie/luthor-headless` (the core editor)
49
+ - `lexical` (the Lexical framework)
50
+ - All `@lexical/*` packages (code, html, link, list, markdown, react, rich-text, selection, table, utils)
51
+
52
+ These satisfy the peer dependencies of luthor-headless, so you don't need to install anything else.
53
+
54
+ ### Peer Dependencies
55
+
56
+ Only React remains as a peer dependency (which you already have in your project):
57
+ - `react` (^18.0.0 or ^19.0.0)
58
+ - `react-dom` (^18.0.0 or ^19.0.0)
59
+
60
+ ---
61
+
62
+ ## Quick Start
63
+
64
+ ### Using the Extensive Editor (Recommended)
65
+
66
+ The fastest way to get a full-featured editor:
67
+
68
+ ```tsx
69
+ import { ExtensiveEditor } from "@lyfie/luthor";
70
+ import type { ExtensiveEditorRef } from "@lyfie/luthor";
71
+ import { useRef } from "react";
72
+
73
+ function App() {
74
+ const editorRef = useRef<ExtensiveEditorRef>(null);
75
+
76
+ const handleSave = () => {
77
+ const html = editorRef.current?.getHTML();
78
+ const markdown = editorRef.current?.getMarkdown();
79
+ console.log({ html, markdown });
80
+ };
81
+
82
+ return (
83
+ <div>
84
+ <ExtensiveEditor
85
+ ref={editorRef}
86
+ placeholder="Start writing..."
87
+ onReady={(methods) => {
88
+ console.log("Editor ready!", methods);
89
+ }}
90
+ />
91
+ <button onClick={handleSave}>Save Content</button>
92
+ </div>
93
+ );
94
+ }
15
95
  ```
16
96
 
17
- ## Usage
97
+ This gives you:
98
+ - ✅ Full-featured toolbar
99
+ - ✅ All formatting options (bold, italic, underline, etc.)
100
+ - ✅ Lists, tables, images, links
101
+ - ✅ Code blocks with syntax highlighting
102
+ - ✅ HTML/Markdown export
103
+ - ✅ Dark mode support
104
+ - ✅ Command palette (Cmd+K / Ctrl+K)
105
+
106
+ ### Using Preset Definitions
107
+
108
+ For more control over the editor setup:
18
109
 
19
110
  ```tsx
20
- import { presetRegistry, defaultPreset } from "@lyfie/luthor";
111
+ import { createEditorSystem, RichText } from "@lyfie/luthor-headless";
112
+ import { extensiveExtensions } from "@lyfie/luthor";
21
113
 
22
- // Get a preset by id
23
- const preset = presetRegistry.default;
114
+ const { Provider, useEditor } = createEditorSystem<typeof extensiveExtensions>();
24
115
 
25
- // Or use a named preset directly
26
- const explicit = defaultPreset;
116
+ function MyToolbar() {
117
+ const { commands, activeStates } = useEditor();
118
+
119
+ return (
120
+ <div className="my-custom-toolbar">
121
+ <button onClick={() => commands.toggleBold()}>
122
+ Bold
123
+ </button>
124
+ {/* Add your custom UI */}
125
+ </div>
126
+ );
127
+ }
128
+
129
+ function App() {
130
+ return (
131
+ <Provider extensions={extensiveExtensions}>
132
+ <MyToolbar />
133
+ <RichText placeholder="Start writing..." />
134
+ </Provider>
135
+ );
136
+ }
27
137
  ```
28
138
 
29
- ## What is included
139
+ ---
140
+
141
+ ## Available Presets
142
+
143
+ All presets are exported with their configurations and can be used as starting points:
144
+
145
+ ### 1. **Minimal** - `minimalPreset`
146
+ Lightweight editor for short text and basic formatting.
147
+ - Bold, italic, link
148
+ - Perfect for comments or short descriptions
149
+
150
+ ### 2. **Classic** - `classicPreset`
151
+ Traditional rich text editor feel.
152
+ - Standard formatting toolbar
153
+ - Good for general content editing
154
+
155
+ ### 3. **Blog** - `blogPreset`
156
+ Optimized for blog post writing.
157
+ - Headings, images, quotes
158
+ - Clean reading experience
159
+
160
+ ### 4. **CMS** - `cmsPreset`
161
+ Content management system focused.
162
+ - Advanced formatting options
163
+ - Image handling with alignment
164
+ - Tables for structured content
165
+
166
+ ### 5. **Docs** - `docsPreset`
167
+ Documentation and technical writing.
168
+ - Code blocks with syntax highlighting
169
+ - Tables and lists
170
+ - Markdown export
171
+
172
+ ### 6. **Chat** - `chatPreset`
173
+ Lightweight for messaging interfaces.
174
+ - Minimal formatting
175
+ - Emoji and mentions (with custom extensions)
176
+
177
+ ### 7. **Email** - `emailPreset`
178
+ Email composition focused.
179
+ - Safe HTML output
180
+ - Link handling
181
+ - Simple formatting
182
+
183
+ ### 8. **Markdown** - `markdownPreset`
184
+ Markdown-first editing.
185
+ - Markdown shortcuts
186
+ - Preview mode
187
+ - Clean export
30
188
 
31
- - Preset definitions (toolbar, config, optional theme)
32
- - Registry lookup by id
33
- - Readme files describing each preset
189
+ ### 9. **Code** - `codePreset`
190
+ Code snippet editor.
191
+ - Syntax highlighting
192
+ - Multiple language support
193
+ - Line numbers
34
194
 
35
- ## Customization
195
+ ### 10. **Default** - `defaultPreset`
196
+ Balanced general-purpose editor.
197
+ - Good starting point for customization
36
198
 
37
- Presets are data objects. You can clone and override any field:
199
+ ### 11. **Extensive** - `extensivePreset` + `ExtensiveEditor`
200
+ Full-featured editor with everything.
201
+ - All extensions included
202
+ - Complete toolbar
203
+ - Pre-built component
204
+
205
+ ---
206
+
207
+ ## Usage Examples
208
+
209
+ ### Example 1: Using Preset Registry
210
+
211
+ ```tsx
212
+ import { presetRegistry } from "@lyfie/luthor";
213
+
214
+ // Get a preset by ID
215
+ const blogPreset = presetRegistry.blog;
216
+ const minimalPreset = presetRegistry.minimal;
217
+
218
+ console.log(blogPreset.label); // "Blog"
219
+ console.log(blogPreset.toolbar); // ["heading", "bold", "italic", ...]
220
+ ```
221
+
222
+ ### Example 2: Customizing a Preset
38
223
 
39
224
  ```tsx
40
225
  import { defaultPreset } from "@lyfie/luthor";
226
+ import { createEditorSystem } from "@lyfie/luthor-headless";
41
227
 
228
+ // Clone and customize
42
229
  const myPreset = {
43
230
  ...defaultPreset,
44
- id: "my-default",
45
- label: "My Default",
231
+ id: "my-custom",
232
+ label: "My Custom Editor",
233
+ toolbar: ["bold", "italic", "link"], // Override toolbar
234
+ config: {
235
+ ...defaultPreset.config,
236
+ placeholder: "Write your story...",
237
+ },
238
+ };
239
+ ```
240
+
241
+ ### Example 3: Building with Extensions
242
+
243
+ ```tsx
244
+ import { extensiveExtensions } from "@lyfie/luthor";
245
+ import { createEditorSystem, RichText } from "@lyfie/luthor-headless";
246
+
247
+ const { Provider, useEditor } = createEditorSystem<typeof extensiveExtensions>();
248
+
249
+ function Editor() {
250
+ const { commands } = useEditor();
251
+
252
+ return (
253
+ <div>
254
+ <button onClick={() => commands.toggleBold()}>Bold</button>
255
+ <button onClick={() => commands.insertTable({ rows: 3, cols: 3 })}>
256
+ Insert Table
257
+ </button>
258
+ <RichText />
259
+ </div>
260
+ );
261
+ }
262
+
263
+ function App() {
264
+ return (
265
+ <Provider extensions={extensiveExtensions}>
266
+ <Editor />
267
+ </Provider>
268
+ );
269
+ }
270
+ ```
271
+
272
+ ### Example 4: Export/Import Content
273
+
274
+ ```tsx
275
+ import { ExtensiveEditor } from "@lyfie/luthor";
276
+ import type { ExtensiveEditorRef } from "@lyfie/luthor";
277
+ import { useRef, useState } from "react";
278
+
279
+ function App() {
280
+ const editorRef = useRef<ExtensiveEditorRef>(null);
281
+ const [savedContent, setSavedContent] = useState("");
282
+
283
+ const handleExport = () => {
284
+ const html = editorRef.current?.getHTML();
285
+ const markdown = editorRef.current?.getMarkdown();
286
+ setSavedContent(html || "");
287
+ console.log({ html, markdown });
288
+ };
289
+
290
+ const handleImport = () => {
291
+ editorRef.current?.injectHTML(savedContent);
292
+ // or
293
+ editorRef.current?.injectMarkdown("# Hello\n\nMarkdown content");
294
+ };
295
+
296
+ return (
297
+ <div>
298
+ <ExtensiveEditor ref={editorRef} />
299
+ <button onClick={handleExport}>Export</button>
300
+ <button onClick={handleImport}>Import</button>
301
+ </div>
302
+ );
303
+ }
304
+ ```
305
+
306
+ ---
307
+
308
+ ## API Reference
309
+
310
+ ### ExtensiveEditor Component
311
+
312
+ ```tsx
313
+ import { ExtensiveEditor } from "@lyfie/luthor";
314
+ import type { ExtensiveEditorRef, ExtensiveEditorProps } from "@lyfie/luthor";
315
+ ```
316
+
317
+ **Props:**
318
+ ```typescript
319
+ interface ExtensiveEditorProps {
320
+ placeholder?: string; // Placeholder text
321
+ className?: string; // CSS class for container
322
+ onReady?: (ref: ExtensiveEditorRef) => void; // Called when editor is ready
323
+ }
324
+ ```
325
+
326
+ **Ref Methods:**
327
+ ```typescript
328
+ interface ExtensiveEditorRef {
329
+ injectMarkdown: (content: string) => void; // Import markdown
330
+ injectHTML: (content: string) => void; // Import HTML
331
+ getMarkdown: () => string; // Export as markdown
332
+ getHTML: () => string; // Export as HTML
333
+ }
334
+ ```
335
+
336
+ ### Preset Registry
337
+
338
+ ```tsx
339
+ import { presetRegistry } from "@lyfie/luthor";
340
+ import type { EditorPreset } from "@lyfie/luthor";
341
+ ```
342
+
343
+ **Type:**
344
+ ```typescript
345
+ interface EditorPreset {
346
+ id: string; // Unique preset ID
347
+ label: string; // Display name
348
+ description?: string; // Preset description
349
+ extensions?: Extension[]; // Included extensions
350
+ config?: EditorConfig; // Editor configuration
351
+ theme?: LuthorTheme; // Custom theme
352
+ toolbar?: string[]; // Toolbar items
353
+ components?: Record<string, unknown>; // Custom components
354
+ css?: string; // CSS file path
355
+ }
356
+ ```
357
+
358
+ **Available Presets:**
359
+ - `presetRegistry.minimal`
360
+ - `presetRegistry.classic`
361
+ - `presetRegistry.blog`
362
+ - `presetRegistry.cms`
363
+ - `presetRegistry.docs`
364
+ - `presetRegistry.chat`
365
+ - `presetRegistry.email`
366
+ - `presetRegistry.markdown`
367
+ - `presetRegistry.code`
368
+ - `presetRegistry.default`
369
+ - `presetRegistry.extensive`
370
+
371
+ ### Extension Sets
372
+
373
+ ```tsx
374
+ import { extensiveExtensions } from "@lyfie/luthor";
375
+ ```
376
+
377
+ Pre-configured extension arrays that can be used with luthor-headless:
378
+
379
+ ```typescript
380
+ const extensions = extensiveExtensions as const;
381
+ const { Provider } = createEditorSystem<typeof extensions>();
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Comparison: Headless vs Luthor
387
+
388
+ | Feature | @lyfie/luthor-headless | @lyfie/luthor |
389
+ |---------|----------------------|---------------|
390
+ | **Installation** | Manual Lexical deps | Zero additional deps |
391
+ | **Bundle Size** | Minimal | Includes all Lexical |
392
+ | **Setup Time** | More configuration | Instant |
393
+ | **Flexibility** | Maximum control | Pre-configured |
394
+ | **Use Case** | Custom editors | Quick implementation |
395
+ | **UI Components** | Build your own | ExtensiveEditor included |
396
+ | **Presets** | None | 11 ready-to-use |
397
+ | **Dependencies** | Peer deps | Bundled deps |
398
+
399
+ **Choose luthor-headless when:**
400
+ - Building completely custom UI
401
+ - Need minimal bundle size
402
+ - Want control over Lexical versions
403
+ - Have specific dependency requirements
404
+
405
+ **Choose @lyfie/luthor when:**
406
+ - Want to start quickly
407
+ - Need a working editor ASAP
408
+ - Don't want to manage dependencies
409
+ - Want ready-to-use components
410
+
411
+ [📖 Learn more about luthor-headless](../headless/README.md)
412
+
413
+ ---
414
+
415
+ ## Advanced Usage
416
+
417
+ ### Creating Custom Presets
418
+
419
+ ```tsx
420
+ import type { EditorPreset } from "@lyfie/luthor";
421
+ import {
422
+ boldExtension,
423
+ italicExtension,
424
+ linkExtension
425
+ } from "@lyfie/luthor-headless";
426
+
427
+ const myCustomPreset: EditorPreset = {
428
+ id: "my-custom",
429
+ label: "My Custom Editor",
430
+ description: "A tailored editor for my use case",
431
+ extensions: [boldExtension, italicExtension, linkExtension],
432
+ config: {
433
+ placeholder: "Start typing...",
434
+ editable: true,
435
+ },
46
436
  toolbar: ["bold", "italic", "link"],
47
437
  };
48
438
  ```
439
+
440
+ ### Extending Existing Presets
441
+
442
+ ```tsx
443
+ import { defaultPreset } from "@lyfie/luthor";
444
+ import { myCustomExtension } from "./my-extension";
445
+
446
+ const enhancedPreset: EditorPreset = {
447
+ ...defaultPreset,
448
+ id: "enhanced-default",
449
+ extensions: [
450
+ ...(defaultPreset.extensions || []),
451
+ myCustomExtension,
452
+ ],
453
+ toolbar: [
454
+ ...(defaultPreset.toolbar || []),
455
+ "myCustomCommand",
456
+ ],
457
+ };
458
+ ```
459
+
460
+ ### Accessing Luthor-Headless Features
461
+
462
+ Since `@lyfie/luthor` depends on `@lyfie/luthor-headless`, you have access to all headless features:
463
+
464
+ ```tsx
465
+ import { createEditorSystem, RichText } from "@lyfie/luthor-headless";
466
+ import { extensiveExtensions } from "@lyfie/luthor";
467
+
468
+ const { Provider, useEditor } = createEditorSystem<typeof extensiveExtensions>();
469
+
470
+ // Use all luthor-headless APIs
471
+ function MyEditor() {
472
+ const { commands, activeStates, lexical } = useEditor();
473
+
474
+ // Access Lexical editor instance
475
+ lexical?.update(() => {
476
+ // Direct Lexical operations
477
+ });
478
+
479
+ return <RichText />;
480
+ }
481
+ ```
482
+
483
+ ---
484
+
485
+ ## TypeScript Support
486
+
487
+ Fully typed with TypeScript. All exports include type definitions:
488
+
489
+ ```typescript
490
+ import type {
491
+ EditorPreset,
492
+ ExtensiveEditorRef,
493
+ ExtensiveEditorProps,
494
+ ExtensiveEditorMode,
495
+ } from "@lyfie/luthor";
496
+ ```
497
+
498
+ ---
499
+
500
+ ## Styling
501
+
502
+ The `ExtensiveEditor` component includes default styles. To customize:
503
+
504
+ ```tsx
505
+ import { ExtensiveEditor } from "@lyfie/luthor";
506
+
507
+ // Add custom class
508
+ <ExtensiveEditor className="my-editor" />
509
+ ```
510
+
511
+ ```css
512
+ /* Override default styles */
513
+ .my-editor {
514
+ --luthor-bg: #ffffff;
515
+ --luthor-text: #000000;
516
+ --luthor-border: #e5e5e5;
517
+ }
518
+
519
+ /* Dark mode */
520
+ .my-editor.dark {
521
+ --luthor-bg: #1a1a1a;
522
+ --luthor-text: #ffffff;
523
+ --luthor-border: #333333;
524
+ }
525
+ ```
526
+
527
+ ---
528
+
529
+ ## Migration from Headless
530
+
531
+ If you're using luthor-headless and want to switch:
532
+
533
+ **Before:**
534
+ ```bash
535
+ # npm
536
+ npm install @lyfie/luthor-headless
537
+ npm install lexical @lexical/react @lexical/html # ... many packages
538
+
539
+ # pnpm
540
+ pnpm add @lyfie/luthor-headless
541
+ pnpm add lexical @lexical/react @lexical/html # ... many packages
542
+ ```
543
+
544
+ **After:**
545
+ ```bash
546
+ # npm
547
+ npm install @lyfie/luthor-headless @lyfie/luthor
548
+
549
+ # pnpm
550
+ pnpm add @lyfie/luthor-headless @lyfie/luthor
551
+
552
+ # Remove individual @lexical/* packages if desired
553
+ ```
554
+
555
+ Your code doesn't need to change! All luthor-headless APIs work the same way.
556
+
557
+ ---
558
+
559
+ ## Examples
560
+
561
+ Check out the [demo site](https://luthor.lyfie.app/demo) for live examples of all presets.
562
+
563
+ ---
564
+
565
+ **Built with ❤️ by the Luthor Team**
566
+
567
+ MIT License - Use it however you want.
package/dist/index.css CHANGED
@@ -1 +1 @@
1
- :root,.luthor-editor-wrapper[data-editor-theme=light]{--luthor-bg: #ffffff;--luthor-fg: #0f172a;--luthor-border: #e2e8f0;--luthor-border-hover: #cbd5e1;--luthor-border-active: #94a3b8;--luthor-accent: #0f172a;--luthor-accent-hover: #1e293b;--luthor-shadow: rgba(0, 0, 0, .08);--luthor-muted: #f8fafc;--luthor-muted-fg: #64748b}.luthor-editor-wrapper[data-editor-theme=dark]{--luthor-bg: #0b0b0b;--luthor-fg: #f5f5f5;--luthor-border: #2b2b2b;--luthor-border-hover: #3f3f3f;--luthor-border-active: #525252;--luthor-accent: #f5f5f5;--luthor-accent-hover: #d4d4d8;--luthor-shadow: rgba(0, 0, 0, .5);--luthor-muted: #171717;--luthor-muted-fg: #a3a3a3}.luthor-editor-wrapper{border:1px solid var(--luthor-border);border-radius:10px;background-color:var(--luthor-bg);overflow:hidden;display:flex;flex-direction:column}.luthor-editor-header{background-color:var(--luthor-muted);border-bottom:1px solid var(--luthor-border)}.luthor-mode-tabs{display:flex;border-bottom:1px solid var(--luthor-border)}.luthor-mode-tab{padding:10px 16px;background:none;border:none;cursor:pointer;color:var(--luthor-muted-fg);font-size:14px;font-weight:600;border-bottom:2px solid transparent;transition:color .2s ease,border-color .2s ease}.luthor-mode-tab:hover{color:var(--luthor-fg)}.luthor-mode-tab.active{color:var(--luthor-accent);border-bottom-color:var(--luthor-accent)}.luthor-toolbar{display:flex;align-items:center;gap:6px;padding:8px 10px;flex-wrap:wrap;min-height:52px}.luthor-toolbar-section{display:flex;align-items:center;gap:4px;padding:0 6px}.luthor-toolbar-section:not(:last-child){border-right:1px solid var(--luthor-border);margin-right:8px;padding-right:8px}.luthor-toolbar-button{display:inline-flex;align-items:center;justify-content:center;min-width:34px;height:34px;padding:0 6px;border:1px solid transparent;border-radius:6px;background-color:transparent;color:var(--luthor-fg);cursor:pointer;transition:all .2s ease}.luthor-toolbar-button:hover{background-color:var(--luthor-muted);border-color:var(--luthor-border-hover)}.luthor-toolbar-button.active{background-color:var(--luthor-accent);border-color:var(--luthor-accent);color:var(--luthor-bg)}.luthor-toolbar-button:disabled{opacity:.5;cursor:not-allowed}.luthor-select{position:relative;display:inline-block}.luthor-select-trigger{display:flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid var(--luthor-border);border-radius:6px;background-color:var(--luthor-bg);color:var(--luthor-fg);cursor:pointer;font-size:13px;min-width:140px;height:34px}.luthor-select-trigger.open{border-color:var(--luthor-accent)}.luthor-select-dropdown{position:absolute;top:100%;left:0;right:0;z-index:50;background-color:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:6px;margin-top:4px;box-shadow:0 6px 20px var(--luthor-shadow)}.luthor-select-option{width:100%;text-align:left;padding:8px 10px;background:none;border:none;cursor:pointer;color:var(--luthor-fg);font-size:13px}.luthor-select-option:hover{background-color:var(--luthor-muted)}.luthor-select-option.selected{background-color:var(--luthor-accent);color:var(--luthor-bg)}.luthor-dropdown{position:relative;display:inline-flex}.luthor-dropdown-content{position:absolute;top:calc(100% + 6px);left:0;z-index:60;min-width:180px;background-color:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:8px;box-shadow:0 12px 24px var(--luthor-shadow);padding:6px}.luthor-dropdown-item{width:100%;display:flex;align-items:center;gap:8px;padding:8px 10px;border:none;background:none;color:var(--luthor-fg);cursor:pointer;border-radius:6px}.luthor-dropdown-item:hover{background-color:var(--luthor-muted)}.luthor-file-input{display:none}.luthor-editor{min-height:320px;background-color:var(--luthor-bg)}.luthor-richtext-container{position:relative}.luthor-content-editable{min-height:300px;padding:18px;font-size:15px;line-height:1.6;color:var(--luthor-fg);outline:none}.luthor-placeholder{position:absolute;top:18px;left:18px;color:var(--luthor-muted-fg);pointer-events:none}.luthor-source-panel{padding:18px}.luthor-source-view{width:100%;min-height:280px;padding:12px;border:1px solid var(--luthor-border);border-radius:8px;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:13px;background-color:var(--luthor-bg);color:var(--luthor-fg)}.luthor-command-palette-overlay{position:fixed;inset:0;background:#0006;display:flex;align-items:flex-start;justify-content:center;padding-top:10vh;z-index:1000}.luthor-command-palette{width:min(640px,92vw);background:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:12px;overflow:hidden;box-shadow:0 20px 40px var(--luthor-shadow)}.luthor-command-palette-header{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--luthor-border)}.luthor-command-palette-icon{color:var(--luthor-muted-fg)}.luthor-command-palette-input{flex:1;border:none;outline:none;font-size:14px;background:transparent;color:var(--luthor-fg)}.luthor-command-palette-kbd{font-size:11px;padding:3px 6px;border-radius:4px;border:1px solid var(--luthor-border);color:var(--luthor-muted-fg);background:var(--luthor-muted)}.luthor-command-palette-list{max-height:320px;overflow-y:auto;padding:6px 0}.luthor-command-palette-group{padding:6px 16px}.luthor-command-palette-group-title{font-size:12px;color:var(--luthor-muted-fg);margin-bottom:4px}.luthor-command-palette-item{display:flex;align-items:center;justify-content:space-between;padding:8px 10px;border-radius:8px;cursor:pointer}.luthor-command-palette-item-content{display:flex;flex-direction:column;gap:2px}.luthor-command-palette-item:hover,.luthor-command-palette-item.selected{background:var(--luthor-muted)}.luthor-command-palette-item-title{font-size:14px;color:var(--luthor-fg)}.luthor-command-palette-item-description{font-size:12px;color:var(--luthor-muted-fg)}.luthor-command-palette-item-shortcut{font-size:11px;padding:2px 6px;border-radius:4px;border:1px solid var(--luthor-border);background:var(--luthor-muted);color:var(--luthor-muted-fg)}.luthor-command-palette-footer{border-top:1px solid var(--luthor-border);padding:10px 16px}.luthor-command-palette-hint{display:inline-flex;align-items:center;gap:8px;font-size:12px;color:var(--luthor-muted-fg)}.luthor-command-palette-empty{padding:20px;text-align:center;color:var(--luthor-muted-fg)}.luthor-dialog-overlay{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000}.luthor-dialog{background-color:var(--luthor-bg);border-radius:10px;box-shadow:0 20px 30px var(--luthor-shadow);min-width:360px;max-width:520px;max-height:90vh;overflow:hidden}.luthor-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--luthor-border)}.luthor-dialog-title{margin:0;font-size:16px;font-weight:600;color:var(--luthor-fg)}.luthor-dialog-close{background:none;border:none;color:var(--luthor-muted-fg);cursor:pointer;padding:4px;border-radius:6px}.luthor-dialog-close:hover{background-color:var(--luthor-muted);color:var(--luthor-fg)}.luthor-dialog-content{padding:18px 20px}.luthor-table-dialog{display:flex;flex-direction:column;gap:14px}.luthor-form-group{display:flex;flex-direction:column;gap:6px}.luthor-form-group label{font-size:13px;font-weight:600;color:var(--luthor-fg)}.luthor-input{padding:8px 12px;border:1px solid var(--luthor-border);border-radius:6px;background-color:var(--luthor-bg);color:var(--luthor-fg);font-size:13px}.luthor-input:focus{outline:none;border-color:var(--luthor-accent);box-shadow:0 0 0 3px #3b82f61f}.luthor-checkbox-label{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--luthor-fg)}.luthor-checkbox{width:16px;height:16px;accent-color:var(--luthor-accent)}.luthor-dialog-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}.luthor-button-primary,.luthor-button-secondary{padding:8px 14px;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid}.luthor-button-primary{background-color:var(--luthor-accent);border-color:var(--luthor-accent);color:var(--luthor-bg)}.luthor-button-primary:hover{background-color:var(--luthor-accent-hover);border-color:var(--luthor-accent-hover)}.luthor-button-secondary{background-color:transparent;border-color:var(--luthor-border);color:var(--luthor-fg)}.luthor-button-secondary:hover{background-color:var(--luthor-muted);border-color:var(--luthor-border-hover)}.luthor-text-bold{font-weight:700}.luthor-text-italic{font-style:italic}.luthor-text-underline{text-decoration:underline}.luthor-text-strikethrough{text-decoration:line-through}.luthor-text-code,.luthor-code-block{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;background-color:var(--luthor-muted);border:1px solid var(--luthor-border);padding:2px 6px;border-radius:4px}.luthor-code-block{display:block;padding:12px;margin:12px 0}.luthor-paragraph{margin:8px 0}.luthor-heading-h1,.luthor-heading-h2,.luthor-heading-h3,.luthor-heading-h4,.luthor-heading-h5,.luthor-heading-h6{margin:16px 0 8px;font-weight:700}.luthor-heading-h1{font-size:28px}.luthor-heading-h2{font-size:24px}.luthor-heading-h3{font-size:20px}.luthor-heading-h4{font-size:18px}.luthor-heading-h5{font-size:16px}.luthor-heading-h6{font-size:14px}.luthor-list-ul,.luthor-list-ol{margin:10px 0 10px 20px}.luthor-list-li{margin:4px 0}.luthor-quote{border-left:4px solid var(--luthor-accent);background-color:var(--luthor-muted);padding:10px 14px;margin:12px 0;color:var(--luthor-fg)}.luthor-link{color:var(--luthor-accent);text-decoration:underline}.luthor-link:hover{color:var(--luthor-accent-hover)}.luthor-hr{margin:16px 0;border:none;border-top:1px solid var(--luthor-border);height:1px}.lexical-image{margin:1em 0;display:block;position:relative}.lexical-image img{max-width:100%;height:auto;border-radius:6px;display:block}.lexical-image.align-left{float:left;margin-right:1em;margin-bottom:1em}.lexical-image.align-right{float:right;margin-left:1em;margin-bottom:1em}.lexical-image.align-center{text-align:center;margin:1em auto}.lexical-image.align-center img{margin:0 auto}.lexical-image figcaption{margin-top:.5em;font-size:12px;color:var(--luthor-muted-fg);text-align:center;font-style:italic}.lexical-image.selected{outline:2px solid var(--luthor-accent);outline-offset:2px}.resizer{position:absolute;width:8px;height:8px;background:var(--luthor-accent);border:1px solid white;border-radius:50%}.resizer.ne{top:-4px;right:-4px;cursor:nesw-resize}.resizer.nw{top:-4px;left:-4px;cursor:nwse-resize}.resizer.se{bottom:-4px;right:-4px;cursor:nwse-resize}.resizer.sw{bottom:-4px;left:-4px;cursor:nesw-resize}.luthor-table{border-collapse:collapse;width:100%;margin:16px 0;border:1px solid var(--luthor-border)}.luthor-table-cell,.luthor-table-cell-header{border:1px solid var(--luthor-border);padding:8px 12px;text-align:left;min-width:80px;background-color:var(--luthor-bg)}.luthor-table-cell-header{background-color:var(--luthor-muted);font-weight:600}table[data-lexical-table-selection]{box-shadow:0 0 0 2px var(--luthor-accent)}table td[data-lexical-table-cell-selection]{background-color:#3b82f61a}.luthor-context-menu{position:fixed;background:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:8px;box-shadow:0 10px 30px var(--luthor-shadow);z-index:1000;min-width:160px;padding:6px 0;font-size:13px}.luthor-context-menu-item{padding:8px 14px;cursor:pointer;user-select:none}.luthor-context-menu-item:hover{background-color:var(--luthor-muted)}.luthor-context-menu-item-disabled{opacity:.5;cursor:not-allowed}.luthor-floating-toolbar{display:flex;align-items:center;gap:4px;padding:6px;background-color:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:8px;box-shadow:0 8px 24px var(--luthor-shadow)}.luthor-floating-toolbar-separator{width:1px;height:18px;background-color:var(--luthor-border);margin:0 4px}.luthor-html-embed-container{border:1px solid var(--luthor-border);border-radius:8px;padding:12px;margin:14px 0;background:var(--luthor-muted)}.luthor-html-embed-preview{padding:10px;border-radius:6px;background:var(--luthor-bg);border:1px solid var(--luthor-border)}.luthor-html-embed-editor{display:flex;flex-direction:column;gap:10px}.luthor-html-embed-textarea{width:100%;min-height:120px;padding:10px;border-radius:6px;border:1px solid var(--luthor-border);background:var(--luthor-bg);color:var(--luthor-fg);font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace}.luthor-html-embed-toggle{align-self:flex-end;background:var(--luthor-accent);color:var(--luthor-bg);border:none;border-radius:6px;padding:6px 10px;cursor:pointer;font-size:12px;font-weight:600}.luthor-draggable-handle,.luthor-draggable-up-button,.luthor-draggable-down-button{width:24px;height:24px;border-radius:6px;border:1px solid var(--luthor-border);background:var(--luthor-bg);color:var(--luthor-muted-fg);display:flex;align-items:center;justify-content:center;cursor:pointer}.luthor-draggable-button-stack{display:flex;flex-direction:column;gap:6px;align-items:center}.luthor-draggable-drop-indicator{height:3px;background:var(--luthor-accent);border-radius:999px}.luthor-draggable-block-dragging,.luthor-draggable-block-is-dragging{opacity:.6}@media(max-width:768px){.luthor-toolbar{padding:6px}.luthor-toolbar-button{min-width:30px;height:30px}.luthor-content-editable{padding:14px;font-size:16px}.luthor-placeholder{top:14px;left:14px}}
1
+ .luthor-preset-extensive.luthor-editor-wrapper[data-editor-theme=light]{--luthor-bg: #ffffff;--luthor-fg: #0f172a;--luthor-border: #e2e8f0;--luthor-border-hover: #cbd5e1;--luthor-border-active: #94a3b8;--luthor-accent: #0f172a;--luthor-accent-hover: #1e293b;--luthor-shadow: rgba(0, 0, 0, .08);--luthor-muted: #f8fafc;--luthor-muted-fg: #64748b}.luthor-preset-extensive.luthor-editor-wrapper[data-editor-theme=dark]{--luthor-bg: #0a0a0a;--luthor-fg: #ededed;--luthor-border: #262626;--luthor-border-hover: #404040;--luthor-border-active: #525252;--luthor-accent: #ededed;--luthor-accent-hover: #d4d4d8;--luthor-shadow: rgba(0, 0, 0, .5);--luthor-muted: #171717;--luthor-muted-fg: #a3a3a3}.luthor-preset-extensive.luthor-editor-wrapper{border:1px solid var(--luthor-border);border-radius:8px;background-color:var(--luthor-bg);overflow:hidden;display:flex;flex-direction:column;width:100%;max-width:100%;min-height:500px;height:auto}.luthor-editor-header{background-color:var(--luthor-muted);border-bottom:1px solid var(--luthor-border)}.luthor-mode-tabs{display:flex;border-bottom:1px solid var(--luthor-border)}.luthor-mode-tab{padding:10px 20px;background:none;border:none;cursor:pointer;color:var(--luthor-muted-fg);font-size:14px;font-weight:500;transition:all .2s cubic-bezier(.4,0,.2,1);border-bottom:2px solid transparent;position:relative}.luthor-mode-tab:hover{color:var(--luthor-fg);background-color:var(--luthor-muted)}.luthor-mode-tab.active{color:var(--luthor-accent);border-bottom-color:var(--luthor-accent);background-color:#0f172a0d}.luthor-toolbar{display:flex;align-items:center;gap:4px;padding:8px;flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;min-height:48px}.luthor-toolbar-section{display:flex;align-items:center;gap:2px;padding:0 4px}.luthor-toolbar-section:not(:last-child){border-right:1px solid var(--luthor-border);margin-right:8px;padding-right:8px}.luthor-toolbar-button{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid transparent;border-radius:6px;background-color:transparent;color:var(--luthor-fg);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);font-size:16px;position:relative;overflow:hidden}.luthor-toolbar-button:before{content:"";position:absolute;inset:0;background:linear-gradient(135deg,#ffffff1a,#ffffff0d);opacity:0;transition:opacity .2s ease}.luthor-toolbar-button:hover{background-color:var(--luthor-muted);border-color:var(--luthor-border-hover);transform:translateY(-1px);box-shadow:0 4px 12px #00000026}.luthor-toolbar-button:hover:before{opacity:1}.luthor-toolbar-button:active{transform:translateY(0) scale(.98);box-shadow:0 2px 8px #0000001a}.luthor-toolbar-button.active{background-color:var(--luthor-accent);border-color:var(--luthor-accent);color:var(--luthor-bg);box-shadow:0 2px 8px #0003}.luthor-toolbar-button.active:before{background:linear-gradient(135deg,#fff3,#ffffff1a);opacity:1}.luthor-toolbar-button:disabled{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none}.luthor-toolbar-button:disabled:hover{background-color:transparent;border-color:transparent;transform:none;box-shadow:none}.luthor-toolbar-button:disabled:before{opacity:0}.luthor-select{position:relative;display:inline-block}.luthor-select-trigger{display:flex;align-items:center;gap:6px;padding:8px 12px;border:1px solid var(--luthor-border);border-radius:6px;background-color:var(--luthor-bg);color:var(--luthor-fg);cursor:pointer;font-size:14px;min-width:120px;height:36px;transition:all .2s cubic-bezier(.4,0,.2,1);box-shadow:0 1px 3px #0000001a}.luthor-select-trigger:hover{border-color:var(--luthor-border-hover);box-shadow:0 2px 8px #00000026}.luthor-select-trigger.open{border-color:var(--luthor-accent);box-shadow:0 0 0 3px #0f172a1a}.luthor-select-dropdown{position:absolute;top:100%;left:0;right:0;z-index:50;background-color:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:6px;box-shadow:0 8px 32px #0000001f;margin-top:4px;max-height:200px;overflow-y:auto}.luthor-select-option{display:block;width:100%;padding:10px 14px;border:none;background:none;color:var(--luthor-fg);cursor:pointer;font-size:14px;text-align:left;transition:all .15s ease}.luthor-select-option:hover{background-color:var(--luthor-muted)}.luthor-select-option.selected{background-color:var(--luthor-accent);color:var(--luthor-bg);font-weight:500}.luthor-dropdown{position:relative;display:inline-flex}.luthor-dropdown-content{position:absolute;top:100%;left:0;z-index:50;background-color:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:4px;box-shadow:0 4px 6px -1px var(--luthor-shadow);margin-top:2px;min-width:160px;padding:4px 0}.luthor-dropdown-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;border:none;background:none;color:var(--luthor-fg);cursor:pointer;font-size:14px;text-align:left;transition:background-color .15s}.luthor-dropdown-item:hover{background-color:var(--luthor-muted)}.luthor-file-input{display:none}.luthor-editor{flex:1;display:flex;flex-direction:column;min-height:400px;position:relative}.luthor-richtext-container{position:relative;flex:1;display:flex;flex-direction:column}.luthor-content-editable{flex:1;padding:20px;outline:none;color:var(--luthor-fg);line-height:1.7;font-size:16px;background-color:var(--luthor-bg);transition:background-color .2s ease}.luthor-content-editable:focus{outline:none;background-color:var(--luthor-bg)}.luthor-placeholder{color:var(--luthor-muted-fg);pointer-events:none;position:absolute;top:20px;left:20px;font-size:16px;line-height:1.7;z-index:1}.luthor-source-panel{padding:20px;flex:1;overflow-y:auto}.luthor-source-view{width:100%;min-height:280px;padding:12px;border:1px solid var(--luthor-border);font-family:SF Mono,Monaco,Inconsolata,Roboto Mono,Consolas,Courier New,monospace;font-size:14px;line-height:1.6;background-color:var(--luthor-bg);color:var(--luthor-fg);border-radius:0;transition:background-color .2s ease}.luthor-command-palette-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:flex-start;justify-content:center;padding-top:20vh;z-index:9999}.luthor-command-palette{background:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:12px;box-shadow:0 12px 48px #0000001f;width:640px;max-width:90vw;max-height:60vh;display:flex;flex-direction:column;overflow:hidden}.luthor-command-palette-header{display:flex;align-items:center;padding:16px 20px;border-bottom:1px solid var(--luthor-border);gap:12px}.luthor-command-palette-icon{color:var(--luthor-muted-fg);flex-shrink:0}.luthor-command-palette-input{flex:1;background:transparent;border:none;outline:none;font-size:16px;color:var(--luthor-fg);font-family:inherit}.luthor-command-palette-input::placeholder{color:var(--luthor-muted-fg)}.luthor-command-palette-kbd{background:var(--luthor-muted);border:1px solid var(--luthor-border);border-radius:4px;padding:2px 6px;font-size:11px;color:var(--luthor-muted-fg);font-family:monospace}.luthor-command-palette-list{flex:1;overflow-y:auto;padding:8px 0}.luthor-command-palette-group{margin-bottom:8px}.luthor-command-palette-group-title{padding:8px 20px 4px;font-size:11px;font-weight:600;color:var(--luthor-muted-fg);text-transform:uppercase;letter-spacing:.5px}.luthor-command-palette-item{display:flex;align-items:center;padding:12px 20px;cursor:pointer;border:none;background:none;width:100%;text-align:left;transition:background-color .1s}.luthor-command-palette-item:hover,.luthor-command-palette-item.selected{background:var(--luthor-muted)}.luthor-command-palette-item-content{flex:1;min-width:0}.luthor-command-palette-item-title{font-size:14px;color:var(--luthor-fg);font-weight:500;margin-bottom:2px}.luthor-command-palette-item-description{font-size:12px;color:var(--luthor-muted-fg);line-height:1.4}.luthor-command-palette-item-shortcut{background:var(--luthor-muted);border:1px solid var(--luthor-border);border-radius:4px;padding:2px 6px;font-size:10px;color:var(--luthor-muted-fg);font-family:monospace;margin-left:12px;flex-shrink:0}.luthor-command-palette-footer{padding:12px 20px;border-top:1px solid var(--luthor-border);background:var(--luthor-muted)}.luthor-command-palette-hint{font-size:11px;color:var(--luthor-muted-fg);display:flex;align-items:center;gap:8px}.luthor-command-palette-hint kbd{background:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:3px;padding:1px 4px;font-size:10px;font-family:monospace}.luthor-command-palette-empty{padding:40px 20px;text-align:center;color:var(--luthor-muted-fg);font-size:14px}.luthor-dialog-overlay{position:fixed;inset:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000}.luthor-dialog{background-color:var(--luthor-bg);border-radius:10px;box-shadow:0 20px 30px var(--luthor-shadow);min-width:360px;max-width:520px;max-height:90vh;overflow:hidden}.luthor-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--luthor-border)}.luthor-dialog-title{margin:0;font-size:16px;font-weight:600;color:var(--luthor-fg)}.luthor-dialog-close{background:none;border:none;color:var(--luthor-muted-fg);cursor:pointer;padding:4px;border-radius:6px}.luthor-dialog-close:hover{background-color:var(--luthor-muted);color:var(--luthor-fg)}.luthor-dialog-content{padding:18px 20px}.luthor-table-dialog{display:flex;flex-direction:column;gap:14px}.luthor-form-group{display:flex;flex-direction:column;gap:6px}.luthor-form-group label{font-size:13px;font-weight:600;color:var(--luthor-fg)}.luthor-input{padding:8px 12px;border:1px solid var(--luthor-border);border-radius:6px;background-color:var(--luthor-bg);color:var(--luthor-fg);font-size:13px}.luthor-input:focus{outline:none;border-color:var(--luthor-accent);box-shadow:0 0 0 3px #3b82f61f}.luthor-checkbox-label{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--luthor-fg)}.luthor-checkbox{width:16px;height:16px;accent-color:var(--luthor-accent)}.luthor-dialog-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}.luthor-button-primary,.luthor-button-secondary{padding:8px 14px;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid}.luthor-button-primary{background-color:var(--luthor-accent);border-color:var(--luthor-accent);color:var(--luthor-bg)}.luthor-button-primary:hover{background-color:var(--luthor-accent-hover);border-color:var(--luthor-accent-hover)}.luthor-button-secondary{background-color:transparent;border-color:var(--luthor-border);color:var(--luthor-fg)}.luthor-button-secondary:hover{background-color:var(--luthor-muted);border-color:var(--luthor-border-hover)}.luthor-text-bold{font-weight:700}.luthor-text-italic{font-style:italic}.luthor-text-underline{text-decoration:underline}.luthor-text-strikethrough{text-decoration:line-through}.luthor-text-code,.luthor-code-block{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;background-color:var(--luthor-muted);border:1px solid var(--luthor-border);padding:2px 6px;border-radius:4px}.luthor-code-block{display:block;padding:12px;margin:12px 0}.luthor-paragraph{margin:8px 0}.luthor-heading-h1,.luthor-heading-h2,.luthor-heading-h3,.luthor-heading-h4,.luthor-heading-h5,.luthor-heading-h6{margin:16px 0 8px;font-weight:700}.luthor-heading-h1{font-size:28px}.luthor-heading-h2{font-size:24px}.luthor-heading-h3{font-size:20px}.luthor-heading-h4{font-size:18px}.luthor-heading-h5{font-size:16px}.luthor-heading-h6{font-size:14px}.luthor-list-ul,.luthor-list-ol{margin:10px 0 10px 20px}.luthor-list-li{margin:4px 0}.luthor-quote{border-left:4px solid var(--luthor-accent);background-color:var(--luthor-muted);padding:10px 14px;margin:12px 0;color:var(--luthor-fg)}.luthor-link{color:var(--luthor-accent);text-decoration:underline}.luthor-link:hover{color:var(--luthor-accent-hover)}.luthor-hr{margin:16px 0;border:none;border-top:1px solid var(--luthor-border);height:1px}.luthor-preset-extensive .lexical-image{margin:1em 0;display:block;position:relative}.luthor-preset-extensive .lexical-image img{max-width:100%;height:auto;border-radius:6px;display:block}.luthor-preset-extensive .lexical-image.align-left{float:left;margin-right:1em;margin-bottom:1em}.luthor-preset-extensive .lexical-image.align-right{float:right;margin-left:1em;margin-bottom:1em}.luthor-preset-extensive .lexical-image.align-center{text-align:center;margin:1em auto}.luthor-preset-extensive .lexical-image.align-center img{margin:0 auto}.luthor-preset-extensive .lexical-image figcaption{margin-top:.5em;font-size:12px;color:var(--luthor-muted-fg);text-align:center;font-style:italic}.luthor-preset-extensive .lexical-image.selected{outline:2px solid var(--luthor-accent);outline-offset:2px}.luthor-preset-extensive .resizer{position:absolute;width:8px;height:8px;background:var(--luthor-accent);border:1px solid white;border-radius:50%}.luthor-preset-extensive .resizer.ne{top:-4px;right:-4px;cursor:nesw-resize}.luthor-preset-extensive .resizer.nw{top:-4px;left:-4px;cursor:nwse-resize}.luthor-preset-extensive .resizer.se{bottom:-4px;right:-4px;cursor:nwse-resize}.luthor-preset-extensive .resizer.sw{bottom:-4px;left:-4px;cursor:nesw-resize}.luthor-table{border-collapse:collapse;width:100%;margin:16px 0;border:1px solid var(--luthor-border)}.luthor-table-cell,.luthor-table-cell-header{border:1px solid var(--luthor-border);padding:8px 12px;text-align:left;min-width:80px;background-color:var(--luthor-bg)}.luthor-table-cell-header{background-color:var(--luthor-muted);font-weight:600}.luthor-preset-extensive table[data-lexical-table-selection]{box-shadow:0 0 0 2px var(--luthor-accent)}.luthor-preset-extensive table td[data-lexical-table-cell-selection]{background-color:#3b82f61a}.luthor-context-menu{position:fixed;background:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:8px;box-shadow:0 10px 30px var(--luthor-shadow);z-index:1000;min-width:160px;padding:6px 0;font-size:13px}.luthor-context-menu-item{padding:8px 14px;cursor:pointer;user-select:none}.luthor-context-menu-item:hover{background-color:var(--luthor-muted)}.luthor-context-menu-item-disabled{opacity:.5;cursor:not-allowed}.luthor-floating-toolbar{display:flex;align-items:center;gap:4px;padding:6px;background-color:var(--luthor-bg);border:1px solid var(--luthor-border);border-radius:8px;box-shadow:0 8px 24px var(--luthor-shadow)}.luthor-floating-toolbar-separator{width:1px;height:18px;background-color:var(--luthor-border);margin:0 4px}.luthor-html-embed-container{border:1px solid var(--luthor-border);border-radius:8px;padding:12px;margin:14px 0;background:var(--luthor-muted)}.luthor-html-embed-preview{padding:10px;border-radius:6px;background:var(--luthor-bg);border:1px solid var(--luthor-border)}.luthor-html-embed-editor{display:flex;flex-direction:column;gap:10px}.luthor-html-embed-textarea{width:100%;min-height:120px;padding:10px;border-radius:6px;border:1px solid var(--luthor-border);background:var(--luthor-bg);color:var(--luthor-fg);font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace}.luthor-html-embed-toggle{align-self:flex-end;background:var(--luthor-accent);color:var(--luthor-bg);border:none;border-radius:6px;padding:6px 10px;cursor:pointer;font-size:12px;font-weight:600}.luthor-draggable-handle,.luthor-draggable-up-button,.luthor-draggable-down-button{width:24px;height:24px;border-radius:6px;border:1px solid var(--luthor-border);background:var(--luthor-bg);color:var(--luthor-muted-fg);display:flex;align-items:center;justify-content:center;cursor:pointer}.luthor-draggable-button-stack{display:flex;flex-direction:column;gap:6px;align-items:center}.luthor-draggable-drop-indicator{height:3px;background:var(--luthor-accent);border-radius:999px}.luthor-draggable-block-dragging,.luthor-draggable-block-is-dragging{opacity:.6}@media(max-width:768px){.luthor-preset-extensive.luthor-editor-wrapper{min-height:400px}.luthor-toolbar{padding:6px}.luthor-toolbar-button{width:32px;height:32px;font-size:14px}.luthor-toolbar-section{padding:0 2px}.luthor-toolbar-section:not(:last-child){margin-right:6px;padding-right:6px}.luthor-content-editable{padding:16px;font-size:16px}.luthor-placeholder{top:16px;left:16px}.luthor-select-trigger{min-width:100px;font-size:13px}.luthor-mode-tab{padding:8px 12px;font-size:13px}}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
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';
2
+ import { LinkExtension, TableExtension, ImageExtension, MarkdownExtension, HTMLEmbedExtension, FloatingToolbarExtension, ContextMenuExtension, CommandPaletteExtension, DraggableBlockExtension, EditorConfig, Extension, LuthorTheme } from '@lyfie/luthor-headless';
3
3
  import React from 'react';
4
4
 
5
5
  declare const blogPreset: EditorPreset;
@@ -32,6 +32,8 @@ interface ExtensiveEditorProps {
32
32
  className?: string;
33
33
  onReady?: (methods: ExtensiveEditorRef) => void;
34
34
  initialTheme?: "light" | "dark";
35
+ defaultContent?: string;
36
+ showDefaultContent?: boolean;
35
37
  }
36
38
  declare const ExtensiveEditor: React.ForwardRefExoticComponent<ExtensiveEditorProps & React.RefAttributes<ExtensiveEditorRef>>;
37
39
 
@@ -39,6 +41,8 @@ declare const markdownPreset: EditorPreset;
39
41
 
40
42
  declare const minimalPreset: EditorPreset;
41
43
 
44
+ declare function createPresetEditorConfig(presetId: string, placeholder: string): EditorConfig;
45
+
42
46
  interface EditorPreset {
43
47
  id: string;
44
48
  label: string;
@@ -53,4 +57,4 @@ interface EditorPreset {
53
57
 
54
58
  declare const presetRegistry: Record<string, EditorPreset>;
55
59
 
56
- export { type EditorPreset, ExtensiveEditor, blogPreset, chatPreset, classicPreset, cmsPreset, codePreset, defaultPreset, docsPreset, emailPreset, extensiveExtensions, extensivePreset, markdownPreset, minimalPreset, presetRegistry };
60
+ export { type EditorPreset, ExtensiveEditor, blogPreset, chatPreset, classicPreset, cmsPreset, codePreset, createPresetEditorConfig, defaultPreset, docsPreset, emailPreset, extensiveExtensions, extensivePreset, markdownPreset, minimalPreset, presetRegistry };
package/dist/index.js CHANGED
@@ -1 +1,16 @@
1
- import {MarkdownExtension,ALL_MARKDOWN_TRANSFORMERS,ImageExtension,TableExtension,HTMLEmbedExtension,FloatingToolbarExtension,ContextMenuExtension,CommandPaletteExtension,DraggableBlockExtension,LinkExtension,createEditorSystem,boldExtension,italicExtension,underlineExtension,strikethroughExtension,horizontalRuleExtension,listExtension,historyExtension,blockFormatExtension,htmlExtension,codeExtension,codeFormatExtension,RichText}from'@lyfie/luthor-headless';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import Rt,{forwardRef,useState,useRef,useEffect,useMemo}from'react';var te={id:"blog",label:"Blog",description:"Long form publishing with media and quotes.",toolbar:["heading","bold","italic","link","image","blockquote","bulletedList","numberedList"],config:{placeholder:"Tell your story..."},css:"blog/styles.css"};var oe={id:"chat",label:"Chat",description:"Compact composer with mentions and quick formatting.",toolbar:["bold","italic","link","emoji","mention"],config:{placeholder:"Write a message..."},css:"chat/styles.css"};var re={id:"classic",label:"Classic",description:"Full featured WYSIWYG default.",toolbar:["undo","redo","bold","italic","underline","link","image","table","bulletedList","numberedList"],config:{placeholder:"Start writing..."},css:"classic/styles.css"};var ne={id:"cms",label:"CMS",description:"Structured content with validation and schema rules.",toolbar:["heading","bold","italic","link","image"],config:{placeholder:"Compose structured content..."},css:"cms/styles.css"};var ie={id:"code",label:"Code",description:"Developer focused editing with code as a first class block.",toolbar:["code","codeBlock","copy","link"],config:{placeholder:"Paste or write code..."},css:"code/styles.css"};var ae={id:"default",label:"Default",description:"Balanced general purpose editor preset.",toolbar:["heading","bold","italic","link","image","table"],config:{placeholder:"Start writing..."},css:"default/styles.css"};var le={id:"docs",label:"Docs",description:"Documentation focused with code and callouts.",toolbar:["heading","bold","italic","code","codeBlock","link"],config:{placeholder:"Write documentation..."},css:"docs/styles.css"};var se={id:"email",label:"Email",description:"Email safe markup with stricter rules.",toolbar:["bold","italic","link","button","table"],config:{placeholder:"Write an email..."},css:"email/styles.css"};function u({size:e=16,className:n,children:i}){return jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:n,"aria-hidden":"true",children:i})}function O(e){return jsxs(u,{...e,children:[jsx("path",{d:"M7 5h6a3 3 0 0 1 0 6H7z"}),jsx("path",{d:"M7 11h7a3 3 0 0 1 0 6H7z"})]})}function $(e){return jsxs(u,{...e,children:[jsx("path",{d:"M11 5h6"}),jsx("path",{d:"M7 19h6"}),jsx("path",{d:"M14 5l-4 14"})]})}function q(e){return jsxs(u,{...e,children:[jsx("path",{d:"M6 4v6a6 6 0 0 0 12 0V4"}),jsx("path",{d:"M4 20h16"})]})}function j(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 12h16"}),jsx("path",{d:"M7 5h7a3 3 0 0 1 0 6H7"}),jsx("path",{d:"M7 19h10"})]})}function Q(e){return jsxs(u,{...e,children:[jsx("path",{d:"M8 7l-4 5 4 5"}),jsx("path",{d:"M16 7l4 5-4 5"})]})}function Ee(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 6h16"}),jsx("path",{d:"M4 18h16"}),jsx("path",{d:"M9 9l-3 3 3 3"}),jsx("path",{d:"M15 9l3 3-3 3"})]})}function R(e){return jsxs(u,{...e,children:[jsx("path",{d:"M10 13a5 5 0 0 1 0-7l2-2a5 5 0 1 1 7 7l-2 2"}),jsx("path",{d:"M14 11a5 5 0 0 1 0 7l-2 2a5 5 0 1 1-7-7l2-2"})]})}function W(e){return jsxs(u,{...e,children:[jsx("path",{d:"M8 8l8 8"}),jsx("path",{d:"M10 13a5 5 0 0 1 0-7l2-2a5 5 0 0 1 7 7l-1 1"}),jsx("path",{d:"M14 11a5 5 0 0 1 0 7l-2 2a5 5 0 0 1-7-7l1-1"})]})}function V(e){return jsxs(u,{...e,children:[jsx("path",{d:"M8 6h12"}),jsx("path",{d:"M8 12h12"}),jsx("path",{d:"M8 18h12"}),jsx("circle",{cx:"4",cy:"6",r:"1"}),jsx("circle",{cx:"4",cy:"12",r:"1"}),jsx("circle",{cx:"4",cy:"18",r:"1"})]})}function Y(e){return jsxs(u,{...e,children:[jsx("path",{d:"M9 6h11"}),jsx("path",{d:"M9 12h11"}),jsx("path",{d:"M9 18h11"}),jsx("path",{d:"M4 6h1"}),jsx("path",{d:"M4 12h1"}),jsx("path",{d:"M4 18h1"})]})}function Ce(e){return jsxs(u,{...e,children:[jsx("path",{d:"M3 7v6h6"}),jsx("path",{d:"M21 17a9 9 0 0 0-9-9H3"})]})}function Me(e){return jsxs(u,{...e,children:[jsx("path",{d:"M21 7v6h-6"}),jsx("path",{d:"M3 17a9 9 0 0 1 9-9h9"})]})}function Pe(e){return jsxs(u,{...e,children:[jsx("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),jsx("circle",{cx:"8",cy:"10",r:"2"}),jsx("path",{d:"M21 16l-5-5-4 4-2-2-5 5"})]})}function _(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 6h16"}),jsx("path",{d:"M4 12h10"}),jsx("path",{d:"M4 18h12"})]})}function N(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 6h16"}),jsx("path",{d:"M7 12h10"}),jsx("path",{d:"M6 18h12"})]})}function G(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 6h16"}),jsx("path",{d:"M10 12h10"}),jsx("path",{d:"M8 18h12"})]})}function Le(e){return jsxs(u,{...e,children:[jsx("path",{d:"M12 16V6"}),jsx("path",{d:"M8 10l4-4 4 4"}),jsx("path",{d:"M4 18h16"})]})}function Be(e){return jsx(u,{...e,children:jsx("path",{d:"M5 12h14"})})}function ze(e){return jsxs(u,{...e,children:[jsx("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"}),jsx("path",{d:"M3 10h18"}),jsx("path",{d:"M9 4v16"}),jsx("path",{d:"M15 4v16"})]})}function Te(e){return jsxs(u,{...e,children:[jsx("path",{d:"M14 2H7a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7z"}),jsx("path",{d:"M14 2v5h5"}),jsx("path",{d:"M9 13l-2 2 2 2"}),jsx("path",{d:"M15 13l2 2-2 2"})]})}function Re(e){return jsxs(u,{...e,children:[jsx("path",{d:"M2 12s4-6 10-6 10 6 10 6-4 6-10 6-10-6-10-6"}),jsx("circle",{cx:"12",cy:"12",r:"3"})]})}function Ne(e){return jsxs(u,{...e,children:[jsx("path",{d:"M3 17l4 4"}),jsx("path",{d:"M14 3l7 7"}),jsx("path",{d:"M7 21l10-10"})]})}function Z(e){return jsxs(u,{...e,children:[jsx("path",{d:"M7 7h10v10H7z"}),jsx("path",{d:"M7 7v-2a2 2 0 1 1 4 0v2"}),jsx("path",{d:"M13 7v-2a2 2 0 1 1 4 0v2"}),jsx("path",{d:"M7 17v2a2 2 0 1 0 4 0v-2"}),jsx("path",{d:"M13 17v2a2 2 0 1 0 4 0v-2"})]})}function He(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 6h16"}),jsx("path",{d:"M12 6v12"})]})}function Ke(e){return jsxs(u,{...e,children:[jsx("path",{d:"M6 8h4v8H6z"}),jsx("path",{d:"M14 8h4v8h-4z"})]})}function Fe(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 6h16"}),jsx("path",{d:"M4 12h10"}),jsx("path",{d:"M4 18h16"}),jsx("path",{d:"M14 9l4 3-4 3"})]})}function Se(e){return jsxs(u,{...e,children:[jsx("path",{d:"M4 6h16"}),jsx("path",{d:"M4 12h10"}),jsx("path",{d:"M4 18h16"}),jsx("path",{d:"M18 9l-4 3 4 3"})]})}function Ae(e){return jsxs(u,{...e,children:[jsx("circle",{cx:"12",cy:"12",r:"4"}),jsx("path",{d:"M12 2v3"}),jsx("path",{d:"M12 19v3"}),jsx("path",{d:"M4.9 4.9l2.1 2.1"}),jsx("path",{d:"M17 17l2.1 2.1"}),jsx("path",{d:"M2 12h3"}),jsx("path",{d:"M19 12h3"}),jsx("path",{d:"M4.9 19.1L7 17"}),jsx("path",{d:"M17 7l2.1-2.1"})]})}function Ue(e){return jsx(u,{...e,children:jsx("path",{d:"M21 12.8A8 8 0 1 1 11.2 3a6 6 0 0 0 9.8 9.8z"})})}function De(e){return jsxs(u,{...e,children:[jsx("circle",{cx:"11",cy:"11",r:"7"}),jsx("path",{d:"M20 20l-3-3"})]})}function Oe(e){return jsx(u,{...e,children:jsx("path",{d:"M6 9l6 6 6-6"})})}function $e(e){return jsxs(u,{...e,children:[jsx("path",{d:"M6 6l12 12"}),jsx("path",{d:"M18 6l-12 12"})]})}function c({children:e,onClick:n,title:i,active:l,disabled:r,className:a,type:s="button"}){return jsx("button",{type:s,className:`luthor-toolbar-button${l?" active":""}${a?` ${a}`:""}`,onClick:n,title:i,disabled:r,children:e})}function ue({children:e,onClick:n,variant:i="primary",type:l="button",className:r}){return jsx("button",{type:l,onClick:n,className:`${i==="primary"?"luthor-button-primary":"luthor-button-secondary"}${r?` ${r}`:""}`,children:e})}function qe({value:e,onValueChange:n,options:i,placeholder:l="Select..."}){let[r,a]=useState(false),s=useRef(null);useEffect(()=>{function v(y){s.current&&!s.current.contains(y.target)&&a(false);}return document.addEventListener("mousedown",v),()=>document.removeEventListener("mousedown",v)},[]);let d=i.find(v=>v.value===e);return jsxs("div",{className:"luthor-select",ref:s,children:[jsxs("button",{className:`luthor-select-trigger ${r?"open":""}`,onClick:()=>a(!r),type:"button",children:[jsx("span",{children:d?.label||l}),jsx(Oe,{size:14})]}),r&&jsx("div",{className:"luthor-select-dropdown",children:i.map(v=>jsx("button",{className:`luthor-select-option ${e===v.value?"selected":""}`,onClick:()=>{n(v.value),a(false);},type:"button",children:v.label},v.value))})]})}function pe({trigger:e,children:n,isOpen:i,onOpenChange:l}){let r=useRef(null);return useEffect(()=>{function a(s){r.current&&!r.current.contains(s.target)&&l(false);}return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[l]),jsxs("div",{className:"luthor-dropdown",ref:r,children:[jsx("div",{onClick:()=>l(!i),children:e}),i&&jsx("div",{className:"luthor-dropdown-content",children:n})]})}function je({isOpen:e,onClose:n,title:i,children:l}){let r=useRef(null);return useEffect(()=>{function a(d){r.current&&!r.current.contains(d.target)&&n();}function s(d){d.key==="Escape"&&n();}return e&&(document.addEventListener("mousedown",a),document.addEventListener("keydown",s),document.body.style.overflow="hidden"),()=>{document.removeEventListener("mousedown",a),document.removeEventListener("keydown",s),document.body.style.overflow="unset";}},[e,n]),e?jsx("div",{className:"luthor-dialog-overlay",children:jsxs("div",{className:"luthor-dialog",ref:r,children:[jsxs("div",{className:"luthor-dialog-header",children:[jsx("h3",{className:"luthor-dialog-title",children:i}),jsx("button",{className:"luthor-dialog-close",onClick:n,type:"button",children:jsx($e,{size:16})})]}),jsx("div",{className:"luthor-dialog-content",children:l})]})}):null}function We(e){let{isVisible:n,selectionRect:i,commands:l,activeStates:r}=e;if(!n||!i)return null;let a={position:"absolute",top:i.y,left:i.positionFromRight?"auto":i.x,right:i.positionFromRight?10:"auto",zIndex:9999,pointerEvents:"auto"};return r?.imageSelected?jsxs("div",{className:"luthor-floating-toolbar",style:a,children:[jsx(c,{onClick:()=>l.setImageAlignment("left"),active:r.isImageAlignedLeft,title:"Align Left",children:jsx(_,{size:14})}),jsx(c,{onClick:()=>l.setImageAlignment("center"),active:r.isImageAlignedCenter,title:"Align Center",children:jsx(N,{size:14})}),jsx(c,{onClick:()=>l.setImageAlignment("right"),active:r.isImageAlignedRight,title:"Align Right",children:jsx(G,{size:14})}),jsx("div",{className:"luthor-floating-toolbar-separator"}),jsx(c,{onClick:()=>l.setImageCaption(prompt("Enter caption:")||""),title:"Edit Caption",children:jsx(Ke,{size:14})})]}):jsxs("div",{className:"luthor-floating-toolbar",style:a,children:[jsx(c,{onClick:()=>l.toggleBold(),active:r.bold,title:"Bold",children:jsx(O,{size:14})}),jsx(c,{onClick:()=>l.toggleItalic(),active:r.italic,title:"Italic",children:jsx($,{size:14})}),jsx(c,{onClick:()=>l.toggleUnderline(),active:r.underline,title:"Underline",children:jsx(q,{size:14})}),jsx(c,{onClick:()=>l.toggleStrikethrough(),active:r.strikethrough,title:"Strikethrough",children:jsx(j,{size:14})}),jsx("div",{className:"luthor-floating-toolbar-separator"}),jsx(c,{onClick:()=>l.formatText("code"),active:r.code,title:"Inline Code",children:jsx(Q,{size:14})}),jsx(c,{onClick:()=>r.isLink?l.removeLink():l.insertLink(),active:r.isLink,title:r.isLink?"Remove Link":"Insert Link",children:r.isLink?jsx(W,{size:14}):jsx(R,{size:14})}),jsx("div",{className:"luthor-floating-toolbar-separator"}),jsx(c,{onClick:()=>l.toggleUnorderedList(),active:r.unorderedList,title:"Bullet List",children:jsx(V,{size:14})}),jsx(c,{onClick:()=>l.toggleOrderedList(),active:r.orderedList,title:"Numbered List",children:jsx(Y,{size:14})})]})}var K=new MarkdownExtension;K.config={...K.config,customTransformers:ALL_MARKDOWN_TRANSFORMERS};var F=new ImageExtension;F.config={...F.config,uploadHandler:async e=>URL.createObjectURL(e),defaultAlignment:"center",resizable:true,pasteListener:{insert:true,replace:true},debug:false};var he=new TableExtension;he.config={...he.config,enableContextMenu:true,markdownExtension:K};var me=new HTMLEmbedExtension;me.config={...me.config,markdownExtension:K};var J={commands:{},activeStates:{}};function Ve(e,n){J.commands=e,J.activeStates=n;}var ge=new FloatingToolbarExtension;ge.config={...ge.config,render:e=>jsx(We,{...e}),getCommands:()=>J.commands,getActiveStates:()=>J.activeStates};var be=new ContextMenuExtension;be.config={...be.config,preventDefault:true};var Ct=new CommandPaletteExtension,fe=new DraggableBlockExtension;fe.config={...fe.config,showMoveButtons:true,showUpButton:true,showDownButton:true,buttonStackPosition:"left"};var xe=new LinkExtension;xe.config={...xe.config,linkSelectedTextOnPaste:true,autoLinkText:true,autoLinkUrls:true};var z=[boldExtension,italicExtension,underlineExtension,strikethroughExtension,xe,horizontalRuleExtension,he,listExtension,historyExtension,F,blockFormatExtension,htmlExtension,K,codeExtension,codeFormatExtension,me,ge,be,Ct,fe];function Ye(){return [{id:"format.bold",label:"Toggle Bold",description:"Make text bold or remove bold formatting",category:"Format",action:e=>e.toggleBold(),shortcuts:[{key:"b",ctrlKey:true}],keywords:["bold","strong","format"]},{id:"format.italic",label:"Toggle Italic",description:"Make text italic or remove italic formatting",category:"Format",action:e=>e.toggleItalic(),shortcuts:[{key:"i",ctrlKey:true}],keywords:["italic","emphasis","format"]},{id:"format.underline",label:"Toggle Underline",description:"Add or remove underline formatting",category:"Format",action:e=>e.toggleUnderline(),shortcuts:[{key:"u",ctrlKey:true}],keywords:["underline","format"]},{id:"format.strikethrough",label:"Toggle Strikethrough",description:"Add or remove strikethrough formatting",category:"Format",action:e=>e.toggleStrikethrough(),keywords:["strikethrough","format"]},{id:"format.code",label:"Toggle Inline Code",description:"Format text as inline code",category:"Format",action:e=>e.formatText("code"),shortcuts:[{key:"`",ctrlKey:true}],keywords:["code","inline","format"]},{id:"block.heading1",label:"Heading 1",description:"Convert to large heading",category:"Block",action:e=>e.toggleHeading("h1"),shortcuts:[{key:"1",ctrlKey:true,altKey:true}],keywords:["heading","h1"]},{id:"block.heading2",label:"Heading 2",description:"Convert to medium heading",category:"Block",action:e=>e.toggleHeading("h2"),shortcuts:[{key:"2",ctrlKey:true,altKey:true}],keywords:["heading","h2"]},{id:"block.heading3",label:"Heading 3",description:"Convert to small heading",category:"Block",action:e=>e.toggleHeading("h3"),shortcuts:[{key:"3",ctrlKey:true,altKey:true}],keywords:["heading","h3"]},{id:"block.paragraph",label:"Paragraph",description:"Convert to paragraph",category:"Block",action:e=>e.toggleParagraph(),shortcuts:[{key:"0",ctrlKey:true,altKey:true}],keywords:["paragraph","text"]},{id:"block.quote",label:"Quote",description:"Convert to blockquote",category:"Block",action:e=>e.toggleQuote(),keywords:["quote","blockquote"]},{id:"block.codeblock",label:"Code Block",description:"Convert to code block",category:"Block",action:e=>e.toggleCodeBlock(),shortcuts:[{key:"`",ctrlKey:true,shiftKey:true}],keywords:["code","block"]},{id:"list.bullet",label:"Bullet List",description:"Create or toggle bullet list",category:"List",action:e=>e.toggleUnorderedList(),shortcuts:[{key:"l",ctrlKey:true,shiftKey:true}],keywords:["list","bullet"]},{id:"list.numbered",label:"Numbered List",description:"Create or toggle numbered list",category:"List",action:e=>e.toggleOrderedList(),shortcuts:[{key:"l",ctrlKey:true,altKey:true}],keywords:["list","numbered"]},{id:"link.insert",label:"Insert Link",description:"Insert or edit a link",category:"Insert",action:e=>e.insertLink(),shortcuts:[{key:"k",ctrlKey:true}],keywords:["link","url"]},{id:"link.remove",label:"Remove Link",description:"Remove link formatting",category:"Format",action:e=>e.removeLink(),shortcuts:[{key:"k",ctrlKey:true,shiftKey:true}],keywords:["unlink","remove","link"]},{id:"insert.horizontal-rule",label:"Insert Horizontal Rule",description:"Insert a horizontal line separator",category:"Insert",action:e=>e.insertHorizontalRule(),keywords:["horizontal","rule"]},{id:"insert.image",label:"Insert Image",description:"Insert an image from URL",category:"Insert",action:e=>{let n=prompt("Enter image URL:");if(n){let i=prompt("Enter alt text:")||"";e.insertImage({src:n,alt:i});}},keywords:["image","photo"]},{id:"insert.table",label:"Insert Table",description:"Insert a 3x3 table",category:"Insert",action:e=>e.insertTable({rows:3,columns:3,includeHeaders:true}),keywords:["table","grid"]},{id:"insert.html-embed",label:"Insert HTML Embed",description:"Insert a custom HTML block",category:"Insert",action:e=>e.insertHTMLEmbed(),keywords:["html","embed"]},{id:"edit.undo",label:"Undo",description:"Undo the last action",category:"Edit",action:e=>e.undo(),shortcuts:[{key:"z",ctrlKey:true}],keywords:["undo","revert"]},{id:"edit.redo",label:"Redo",description:"Redo the last undone action",category:"Edit",action:e=>e.redo(),shortcuts:[{key:"y",ctrlKey:true},{key:"z",ctrlKey:true,shiftKey:true}],keywords:["redo","repeat"]},{id:"palette.show",label:"Show Command Palette",description:"Open the command palette",category:"View",action:e=>e.showCommandPalette(),shortcuts:[{key:"p",ctrlKey:true,shiftKey:true}],keywords:["command","palette"]}]}function _e(e){return Ye().map(n=>({id:n.id,label:n.label,description:n.description,category:n.category,action:()=>n.action(e),keywords:n.keywords,shortcut:n.shortcuts?.[0]?Pt(n.shortcuts[0]):void 0}))}function Pt(e){let n=[];return e.ctrlKey&&n.push("Ctrl"),e.metaKey&&n.push("Cmd"),e.altKey&&n.push("Alt"),e.shiftKey&&n.push("Shift"),n.push(e.key.toUpperCase()),n.join("+")}function Ge(e,n=document.body){let i=Ye(),l=r=>{for(let a of i)if(a.shortcuts){for(let s of a.shortcuts)if(r.key.toLowerCase()===s.key.toLowerCase()&&!!r.ctrlKey==!!s.ctrlKey&&!!r.metaKey==!!s.metaKey&&!!r.shiftKey==!!s.shiftKey&&!!r.altKey==!!s.altKey){s.preventDefault!==false&&r.preventDefault(),(!a.condition||a.condition(e))&&a.action(e);return}}};return n.addEventListener("keydown",l),()=>n.removeEventListener("keydown",l)}function zt(e,n){let i=useRef(null),l=F.config;return {handlers:useMemo(()=>({insertFromUrl:()=>{let a=prompt("Enter image URL:");if(!a)return;let s=prompt("Enter alt text:")||"",d=prompt("Enter caption (optional):")||void 0;e.insertImage({src:a,alt:s,caption:d});},insertFromFile:()=>i.current?.click(),handleUpload:async a=>{let s=a.target.files?.[0];if(!s)return;let d;if(l.uploadHandler)try{d=await l.uploadHandler(s);}catch{alert("Failed to upload image");return}else d=URL.createObjectURL(s);e.insertImage({src:d,alt:s.name,file:s}),a.target.value="";},setAlignment:a=>{e.setImageAlignment(a);},setCaption:()=>{let a=prompt("Enter caption:")||"";e.setImageCaption(a);}}),[e,l]),fileInputRef:i}}function Je({commands:e,hasExtension:n,activeStates:i,isDark:l,toggleTheme:r,onCommandPaletteOpen:a,editor:s}){let{handlers:d,fileInputRef:v}=zt(e),[y,w]=useState(false),[h,f]=useState(false),[k,L]=useState(false),[P,B]=useState({rows:3,columns:3,includeHeaders:false}),D=[{value:"p",label:"Paragraph"},{value:"h1",label:"Heading 1"},{value:"h2",label:"Heading 2"},{value:"h3",label:"Heading 3"},{value:"h4",label:"Heading 4"},{value:"h5",label:"Heading 5"},{value:"h6",label:"Heading 6"},{value:"quote",label:"Quote"}],we=i.isH1?"h1":i.isH2?"h2":i.isH3?"h3":i.isH4?"h4":i.isH5?"h5":i.isH6?"h6":i.isQuote?"quote":"p",b=m=>{m==="p"?e.toggleParagraph():m.startsWith("h")?e.toggleHeading(m):m==="quote"&&e.toggleQuote();};return jsxs(Fragment,{children:[jsxs("div",{className:"luthor-toolbar",children:[jsxs("div",{className:"luthor-toolbar-section",children:[jsx(c,{onClick:()=>e.toggleBold(),active:i.bold,title:"Bold (Ctrl+B)",children:jsx(O,{size:16})}),jsx(c,{onClick:()=>e.toggleItalic(),active:i.italic,title:"Italic (Ctrl+I)",children:jsx($,{size:16})}),jsx(c,{onClick:()=>e.toggleUnderline(),active:i.underline,title:"Underline (Ctrl+U)",children:jsx(q,{size:16})}),jsx(c,{onClick:()=>e.toggleStrikethrough(),active:i.strikethrough,title:"Strikethrough",children:jsx(j,{size:16})}),jsx(c,{onClick:()=>e.formatText("code"),active:i.code,title:"Inline Code",children:jsx(Q,{size:16})}),jsx(c,{onClick:()=>i.isLink?e.removeLink():e.insertLink(),active:i.isLink,title:i.isLink?"Remove Link":"Insert Link",children:i.isLink?jsx(W,{size:16}):jsx(R,{size:16})})]}),n("blockFormat")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(qe,{value:we,onValueChange:b,options:D,placeholder:"Format"}),n("code")&&jsx(c,{onClick:()=>e.toggleCodeBlock(),active:i.isInCodeBlock,title:"Code Block",children:jsx(Ee,{size:16})})]}),n("list")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(c,{onClick:()=>e.toggleUnorderedList(),active:i.unorderedList,title:"Bullet List",children:jsx(V,{size:16})}),jsx(c,{onClick:()=>e.toggleOrderedList(),active:i.orderedList,title:"Numbered List",children:jsx(Y,{size:16})}),(i.unorderedList||i.orderedList)&&jsxs(Fragment,{children:[jsx(c,{onClick:()=>e.indentList(),title:"Indent List",children:jsx(Fe,{size:14})}),jsx(c,{onClick:()=>e.outdentList(),title:"Outdent List",children:jsx(Se,{size:14})})]})]}),n("horizontalRule")&&jsx("div",{className:"luthor-toolbar-section",children:jsx(c,{onClick:()=>e.insertHorizontalRule(),title:"Insert Horizontal Rule",children:jsx(Be,{size:16})})}),n("table")&&jsx("div",{className:"luthor-toolbar-section",children:jsx(c,{onClick:()=>L(true),title:"Insert Table",children:jsx(ze,{size:16})})}),n("image")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsxs(pe,{trigger:jsx("button",{className:`luthor-toolbar-button ${i.imageSelected?"active":""}`,title:"Insert Image",children:jsx(Pe,{size:16})}),isOpen:y,onOpenChange:w,children:[jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{d.insertFromUrl(),w(false);},children:[jsx(R,{size:16}),jsx("span",{children:"From URL"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{d.insertFromFile(),w(false);},children:[jsx(Le,{size:16}),jsx("span",{children:"Upload File"})]})]}),i.imageSelected&&jsxs(pe,{trigger:jsx("button",{className:"luthor-toolbar-button",title:"Align Image",children:jsx(N,{size:16})}),isOpen:h,onOpenChange:f,children:[jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{d.setAlignment("left"),f(false);},children:[jsx(_,{size:16}),jsx("span",{children:"Align Left"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{d.setAlignment("center"),f(false);},children:[jsx(N,{size:16}),jsx("span",{children:"Align Center"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{d.setAlignment("right"),f(false);},children:[jsx(G,{size:16}),jsx("span",{children:"Align Right"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{d.setCaption(),f(false);},children:[jsx(He,{size:16}),jsx("span",{children:"Set Caption"})]})]}),jsx("input",{ref:v,type:"file",accept:"image/*",onChange:d.handleUpload,className:"luthor-file-input"})]}),n("htmlEmbed")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(c,{onClick:()=>e.insertHTMLEmbed(),active:i.isHTMLEmbedSelected,title:"Insert HTML Embed",children:jsx(Te,{size:16})}),i.isHTMLEmbedSelected&&jsx(c,{onClick:()=>e.toggleHTMLPreview(),title:"Toggle Preview/Edit",children:i.isHTMLPreviewMode?jsx(Re,{size:16}):jsx(Ne,{size:16})})]}),n("history")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(c,{onClick:()=>e.undo(),disabled:!i.canUndo,title:"Undo (Ctrl+Z)",children:jsx(Ce,{size:16})}),jsx(c,{onClick:()=>e.redo(),disabled:!i.canRedo,title:"Redo (Ctrl+Y)",children:jsx(Me,{size:16})})]}),jsx("div",{className:"luthor-toolbar-section",children:jsx(c,{onClick:a,title:"Command Palette (Ctrl+Shift+P)",children:jsx(Z,{size:16})})}),jsx("div",{className:"luthor-toolbar-section",children:jsx(c,{onClick:r,title:l?"Light Mode":"Dark Mode",children:l?jsx(Ae,{size:16}):jsx(Ue,{size:16})})})]}),jsx(je,{isOpen:k,onClose:()=>L(false),title:"Insert Table",children:jsxs("div",{className:"luthor-table-dialog",children:[jsxs("div",{className:"luthor-form-group",children:[jsx("label",{htmlFor:"table-rows",children:"Rows:"}),jsx("input",{id:"table-rows",type:"number",min:"1",max:"20",value:P.rows,onChange:m=>B(I=>({...I,rows:parseInt(m.target.value)||1})),className:"luthor-input"})]}),jsxs("div",{className:"luthor-form-group",children:[jsx("label",{htmlFor:"table-columns",children:"Columns:"}),jsx("input",{id:"table-columns",type:"number",min:"1",max:"20",value:P.columns,onChange:m=>B(I=>({...I,columns:parseInt(m.target.value)||1})),className:"luthor-input"})]}),jsx("div",{className:"luthor-form-group",children:jsxs("label",{className:"luthor-checkbox-label",children:[jsx("input",{type:"checkbox",checked:P.includeHeaders||false,onChange:m=>B(I=>({...I,includeHeaders:m.target.checked})),className:"luthor-checkbox"}),"Include headers"]})}),jsxs("div",{className:"luthor-dialog-actions",children:[jsx(ue,{variant:"secondary",onClick:()=>L(false),children:"Cancel"}),jsx(ue,{variant:"primary",onClick:()=>{e.insertTable(P),L(false);},children:"Insert Table"})]})]})})]})}function et({isOpen:e,onClose:n,commands:i}){let[l,r]=useState(""),[a,s]=useState(0),d=useRef(null),v=i.filter(h=>`${h.label} ${h.description||""} ${h.keywords?.join(" ")||""}`.toLowerCase().includes(l.toLowerCase())),y=v.reduce((h,f)=>{let k=f.category||"Other";return h[k]||(h[k]=[]),h[k].push(f),h},{}),w=v;return useEffect(()=>{s(0);},[l]),useEffect(()=>{e&&d.current&&(d.current.focus(),r(""),s(0));},[e]),useEffect(()=>{let h=f=>{if(e)switch(f.key){case "Escape":f.preventDefault(),n();break;case "ArrowDown":f.preventDefault(),s(k=>Math.min(k+1,w.length-1));break;case "ArrowUp":f.preventDefault(),s(k=>Math.max(k-1,0));break;case "Enter":f.preventDefault(),w[a]&&(w[a].action(),n());break}};return document.addEventListener("keydown",h),()=>document.removeEventListener("keydown",h)},[e,a,w,n]),e?jsx("div",{className:"luthor-command-palette-overlay",onClick:n,children:jsxs("div",{className:"luthor-command-palette",onClick:h=>h.stopPropagation(),children:[jsxs("div",{className:"luthor-command-palette-header",children:[jsx(De,{size:16,className:"luthor-command-palette-icon"}),jsx("input",{ref:d,type:"text",placeholder:"Type a command or search...",value:l,onChange:h=>r(h.target.value),className:"luthor-command-palette-input"}),jsx("kbd",{className:"luthor-command-palette-kbd",children:"ESC"})]}),jsx("div",{className:"luthor-command-palette-list",children:Object.keys(y).length===0?jsx("div",{className:"luthor-command-palette-empty",children:"No commands found"}):Object.entries(y).map(([h,f])=>jsxs("div",{className:"luthor-command-palette-group",children:[jsx("div",{className:"luthor-command-palette-group-title",children:h}),f.map(k=>{let L=w.indexOf(k);return jsxs("div",{className:`luthor-command-palette-item ${L===a?"selected":""}`,onClick:()=>{k.action(),n();},onMouseEnter:()=>s(L),children:[jsxs("div",{className:"luthor-command-palette-item-content",children:[jsx("div",{className:"luthor-command-palette-item-title",children:k.label}),k.description&&jsx("div",{className:"luthor-command-palette-item-description",children:k.description})]}),k.shortcut&&jsx("kbd",{className:"luthor-command-palette-item-shortcut",children:k.shortcut})]},k.id)})]},h))}),jsx("div",{className:"luthor-command-palette-footer",children:jsxs("span",{className:"luthor-command-palette-hint",children:[jsx(Z,{size:14}),jsx("span",{children:"Use arrow keys, Enter, ESC"})]})})]})}):null}var{Provider:St,useEditor:At}=createEditorSystem();function Ut({mode:e,onModeChange:n}){return jsxs("div",{className:"luthor-mode-tabs",children:[jsx("button",{className:`luthor-mode-tab ${e==="visual"?"active":""}`,onClick:()=>n("visual"),children:"Visual"}),jsx("button",{className:`luthor-mode-tab ${e==="html"?"active":""}`,onClick:()=>n("html"),children:"HTML"}),jsx("button",{className:`luthor-mode-tab ${e==="markdown"?"active":""}`,onClick:()=>n("markdown"),children:"Markdown"})]})}function ot({value:e,onChange:n,placeholder:i}){return jsx("textarea",{className:"luthor-source-view",value:e,onChange:l=>n(l.target.value),placeholder:i,spellCheck:false})}function Dt({className:e,isDark:n,toggleTheme:i,onReady:l}){let{commands:r,hasExtension:a,activeStates:s,lexical:d,extensions:v}=At(),[y,w]=useState("visual"),[h,f]=useState({html:"",markdown:""}),[k,L]=useState({isOpen:false,commands:[]}),P=useRef(r),B=useRef(false);useEffect(()=>{P.current=r;},[r]),useEffect(()=>{Ve(r,s);},[r,s]);let D=useMemo(()=>({injectMarkdown:b=>{setTimeout(()=>{d&&d.update(()=>{P.current.importFromMarkdown(b,{immediate:true,preventFocus:true});});},100);},injectHTML:b=>{setTimeout(()=>{d&&d.update(()=>{P.current.importFromHTML(b,{preventFocus:true});});},100);},getMarkdown:()=>P.current.exportToMarkdown(),getHTML:()=>P.current.exportToHTML()}),[d]);return useEffect(()=>{if(!d||!r)return;let b=_e(r);b.forEach(I=>r.registerCommand(I));let m=Ge(r,document.body);return B.current||(B.current=true,l?.(D)),()=>{m(),b.forEach(I=>r.unregisterCommand(I.id));}},[d,r,D,l]),useEffect(()=>{let b=v.find(m=>m.name==="commandPalette");if(!(!b||!b.subscribe))return b.subscribe((m,I)=>{L({isOpen:m,commands:I});})},[v]),jsxs(Fragment,{children:[jsxs("div",{className:"luthor-editor-header",children:[jsx(Ut,{mode:y,onModeChange:async b=>{if(y==="markdown"&&b!=="markdown"&&a("markdown")&&(await r.importFromMarkdown(h.markdown,{immediate:true}),await new Promise(m=>setTimeout(m,50))),y==="html"&&b!=="html"&&a("html")&&(await r.importFromHTML(h.html),await new Promise(m=>setTimeout(m,50))),b==="markdown"&&y!=="markdown"&&a("markdown")){await new Promise(I=>setTimeout(I,50));let m=r.exportToMarkdown();f(I=>({...I,markdown:m}));}if(b==="html"&&y!=="html"&&a("html")){await new Promise(I=>setTimeout(I,50));let m=r.exportToHTML();f(I=>({...I,html:m}));}w(b),b==="visual"&&setTimeout(()=>d?.focus(),100);}}),y==="visual"&&jsx(Je,{commands:r,hasExtension:a,activeStates:s,isDark:n,toggleTheme:i,onCommandPaletteOpen:()=>r.showCommandPalette(),editor:d})]}),jsxs("div",{className:"luthor-editor","data-mode":y,children:[y==="visual"&&jsx(RichText,{placeholder:"Write anything...",classNames:{container:"luthor-richtext-container",contentEditable:"luthor-content-editable",placeholder:"luthor-placeholder"}}),y!=="visual"&&jsxs("div",{className:"luthor-source-panel",children:[y==="html"&&jsx(ot,{value:h.html,onChange:b=>f(m=>({...m,html:b})),placeholder:"Enter HTML content..."}),y==="markdown"&&jsx(ot,{value:h.markdown,onChange:b=>f(m=>({...m,markdown:b})),placeholder:"Enter Markdown content..."})]})]}),jsx(et,{isOpen:k.isOpen,onClose:()=>r.hideCommandPalette(),commands:k.commands})]})}var U=forwardRef(({className:e,onReady:n,initialTheme:i="light"},l)=>{let[r,a]=useState(i),s=r==="dark",d=()=>a(s?"light":"dark"),[v,y]=useState(null);Rt.useImperativeHandle(l,()=>v,[v]);let w=h=>{y(h),n?.(h);};return jsx("div",{className:`luthor-editor-wrapper ${e||""}`,"data-editor-theme":r,children:jsx(St,{extensions:z,children:jsx(Dt,{className:e,isDark:s,toggleTheme:d,onReady:w})})})});U.displayName="ExtensiveEditor";var ke={id:"extensive",label:"Extensive",description:"All features enabled for power users.",extensions:[...z],components:{Editor:U},toolbar:["undo","redo","heading","bold","italic","underline","strikethrough","link","image","table","blockquote","code","codeBlock","bulletedList","numberedList"],config:{placeholder:"Write anything..."},css:"extensive/styles.css"};var ye={id:"markdown",label:"Markdown",description:"Markdown first editing with predictable output.",toolbar:["bold","italic","link","code","codeBlock"],config:{placeholder:"Write in markdown..."},css:"markdown/styles.css"};var Ie={id:"minimal",label:"Minimal",description:"Lightweight editor for short text and embeds.",toolbar:["bold","italic","link"],config:{placeholder:"Write something..."},css:"minimal/styles.css"};var wr={minimal:Ie,classic:re,docs:le,blog:te,cms:ne,chat:oe,email:se,markdown:ye,code:ie,default:ae,extensive:ke};export{U as ExtensiveEditor,te as blogPreset,oe as chatPreset,re as classicPreset,ne as cmsPreset,ie as codePreset,ae as defaultPreset,le as docsPreset,se as emailPreset,z as extensiveExtensions,ke as extensivePreset,ye as markdownPreset,Ie as minimalPreset,wr as presetRegistry};
1
+ import {MarkdownExtension,ALL_MARKDOWN_TRANSFORMERS,ImageExtension,TableExtension,HTMLEmbedExtension,FloatingToolbarExtension,ContextMenuExtension,CommandPaletteExtension,DraggableBlockExtension,LinkExtension,createEditorSystem,boldExtension,italicExtension,underlineExtension,strikethroughExtension,horizontalRuleExtension,listExtension,historyExtension,blockFormatExtension,htmlExtension,codeExtension,codeFormatExtension,RichText}from'@lyfie/luthor-headless';import {AlignLeft,AlignCenter,AlignRight,Quote,Bold,Italic,Underline,Strikethrough,Code,Unlink,Link,List,ListOrdered,Code2,IndentIncrease,IndentDecrease,Minus,Table,Upload,Image,Type,FileCode,Eye,Pencil,Undo2,Redo2,Command,Sun,Moon,Search,ChevronDown,X}from'lucide-react';import so,{forwardRef,useState,useRef,useEffect,useMemo}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';function b(e,o){let r=`luthor-preset-${e}`;return {placeholder:o,classNames:{container:`luthor-preset ${r} ${r}__container`,contentEditable:`luthor-content-editable ${r}__content`,placeholder:`luthor-placeholder ${r}__placeholder`}}}var J={id:"blog",label:"Blog",description:"Long form publishing with media and quotes.",toolbar:["heading","bold","italic","link","image","blockquote","bulletedList","numberedList"],config:b("blog","Tell your story..."),css:"blog/styles.css"};var ee={id:"chat",label:"Chat",description:"Compact composer with mentions and quick formatting.",toolbar:["bold","italic","link","emoji","mention"],config:b("chat","Write a message..."),css:"chat/styles.css"};var te={id:"classic",label:"Classic",description:"Full featured WYSIWYG default.",toolbar:["undo","redo","bold","italic","underline","link","image","table","bulletedList","numberedList"],config:b("classic","Start writing..."),css:"classic/styles.css"};var oe={id:"cms",label:"CMS",description:"Structured content with validation and schema rules.",toolbar:["heading","bold","italic","link","image"],config:b("cms","Compose structured content..."),css:"cms/styles.css"};var re={id:"code",label:"Code",description:"Developer focused editing with code as a first class block.",toolbar:["code","codeBlock","copy","link"],config:b("code","Paste or write code..."),css:"code/styles.css"};var ne={id:"default",label:"Default",description:"Balanced general purpose editor preset.",toolbar:["heading","bold","italic","link","image","table"],config:b("default","Start writing..."),css:"default/styles.css"};var ie={id:"docs",label:"Docs",description:"Documentation focused with code and callouts.",toolbar:["heading","bold","italic","code","codeBlock","link"],config:b("docs","Write documentation..."),css:"docs/styles.css"};var le={id:"email",label:"Email",description:"Email safe markup with stricter rules.",toolbar:["bold","italic","link","button","table"],config:b("email","Write an email..."),css:"email/styles.css"};var U=Bold,A=Italic,O=Underline,$=Strikethrough,j=Code,we=Code2,R=Link,Q=Unlink,_=List,q=ListOrdered,Ce=Undo2,Ee=Redo2,Ie=Image,W=AlignLeft,N=AlignCenter,V=AlignRight,Le=Upload,Pe=Minus,ze=Table,Te=FileCode,Re=Eye,Ne=Pencil,Y=Command,Me=Type,Be=Quote,He=IndentIncrease,Ke=IndentDecrease,Se=Sun,Fe=Moon,De=Search,Ue=ChevronDown,Ae=X;function d({children:e,onClick:o,title:r,active:i,disabled:n,className:l,type:a="button"}){return jsx("button",{type:a,className:`luthor-toolbar-button${i?" active":""}${l?` ${l}`:""}`,onClick:o,title:r,disabled:n,children:e})}function de({children:e,onClick:o,variant:r="primary",type:i="button",className:n}){return jsx("button",{type:i,onClick:o,className:`${r==="primary"?"luthor-button-primary":"luthor-button-secondary"}${n?` ${n}`:""}`,children:e})}function Oe({value:e,onValueChange:o,options:r,placeholder:i="Select..."}){let[n,l]=useState(false),a=useRef(null);useEffect(()=>{function f(v){a.current&&!a.current.contains(v.target)&&l(false);}return document.addEventListener("mousedown",f),()=>document.removeEventListener("mousedown",f)},[]);let s=r.find(f=>f.value===e);return jsxs("div",{className:"luthor-select",ref:a,children:[jsxs("button",{className:`luthor-select-trigger ${n?"open":""}`,onClick:()=>l(!n),type:"button",children:[jsx("span",{children:s?.label||i}),jsx(Ue,{size:14})]}),n&&jsx("div",{className:"luthor-select-dropdown",children:r.map(f=>jsx("button",{className:`luthor-select-option ${e===f.value?"selected":""}`,onClick:()=>{o(f.value),l(false);},type:"button",children:f.label},f.value))})]})}function ce({trigger:e,children:o,isOpen:r,onOpenChange:i}){let n=useRef(null);return useEffect(()=>{function l(a){n.current&&!n.current.contains(a.target)&&i(false);}return document.addEventListener("mousedown",l),()=>document.removeEventListener("mousedown",l)},[i]),jsxs("div",{className:"luthor-dropdown",ref:n,children:[jsx("div",{onClick:()=>i(!r),children:e}),r&&jsx("div",{className:"luthor-dropdown-content",children:o})]})}function $e({isOpen:e,onClose:o,title:r,children:i}){let n=useRef(null);return useEffect(()=>{function l(s){n.current&&!n.current.contains(s.target)&&o();}function a(s){s.key==="Escape"&&o();}return e&&(document.addEventListener("mousedown",l),document.addEventListener("keydown",a),document.body.style.overflow="hidden"),()=>{document.removeEventListener("mousedown",l),document.removeEventListener("keydown",a),document.body.style.overflow="unset";}},[e,o]),e?jsx("div",{className:"luthor-dialog-overlay",children:jsxs("div",{className:"luthor-dialog",ref:n,children:[jsxs("div",{className:"luthor-dialog-header",children:[jsx("h3",{className:"luthor-dialog-title",children:r}),jsx("button",{className:"luthor-dialog-close",onClick:o,type:"button",children:jsx(Ae,{size:16})})]}),jsx("div",{className:"luthor-dialog-content",children:i})]})}):null}function Qe(e){let{isVisible:o,selectionRect:r,commands:i,activeStates:n}=e;if(!o||!r)return null;let l={position:"absolute",top:r.y,left:r.positionFromRight?"auto":r.x,right:r.positionFromRight?10:"auto",zIndex:9999,pointerEvents:"auto"};return n?.imageSelected?jsxs("div",{className:"luthor-floating-toolbar",style:l,children:[jsx(d,{onClick:()=>i.setImageAlignment("left"),active:n.isImageAlignedLeft,title:"Align Left",children:jsx(W,{size:14})}),jsx(d,{onClick:()=>i.setImageAlignment("center"),active:n.isImageAlignedCenter,title:"Align Center",children:jsx(N,{size:14})}),jsx(d,{onClick:()=>i.setImageAlignment("right"),active:n.isImageAlignedRight,title:"Align Right",children:jsx(V,{size:14})}),jsx("div",{className:"luthor-floating-toolbar-separator"}),jsx(d,{onClick:()=>i.setImageCaption(prompt("Enter caption:")||""),title:"Edit Caption",children:jsx(Be,{size:14})})]}):jsxs("div",{className:"luthor-floating-toolbar",style:l,children:[jsx(d,{onClick:()=>i.toggleBold(),active:n.bold,title:"Bold",children:jsx(U,{size:14})}),jsx(d,{onClick:()=>i.toggleItalic(),active:n.italic,title:"Italic",children:jsx(A,{size:14})}),jsx(d,{onClick:()=>i.toggleUnderline(),active:n.underline,title:"Underline",children:jsx(O,{size:14})}),jsx(d,{onClick:()=>i.toggleStrikethrough(),active:n.strikethrough,title:"Strikethrough",children:jsx($,{size:14})}),jsx("div",{className:"luthor-floating-toolbar-separator"}),jsx(d,{onClick:()=>i.formatText("code"),active:n.code,title:"Inline Code",children:jsx(j,{size:14})}),jsx(d,{onClick:()=>n.isLink?i.removeLink():i.insertLink(),active:n.isLink,title:n.isLink?"Remove Link":"Insert Link",children:n.isLink?jsx(Q,{size:14}):jsx(R,{size:14})}),jsx("div",{className:"luthor-floating-toolbar-separator"}),jsx(d,{onClick:()=>i.toggleUnorderedList(),active:n.unorderedList,title:"Bullet List",children:jsx(_,{size:14})}),jsx(d,{onClick:()=>i.toggleOrderedList(),active:n.orderedList,title:"Numbered List",children:jsx(q,{size:14})})]})}var B=new MarkdownExtension;B.config={...B.config,customTransformers:ALL_MARKDOWN_TRANSFORMERS};var H=new ImageExtension;H.config={...H.config,uploadHandler:async e=>URL.createObjectURL(e),defaultAlignment:"center",resizable:true,pasteListener:{insert:true,replace:true},debug:false};var ue=new TableExtension;ue.config={...ue.config,enableContextMenu:true,markdownExtension:B};var pe=new HTMLEmbedExtension;pe.config={...pe.config,markdownExtension:B};var G={commands:{},activeStates:{}};function _e(e,o){G.commands=e,G.activeStates=o;}var me=new FloatingToolbarExtension;me.config={...me.config,render:e=>jsx(Qe,{...e}),getCommands:()=>G.commands,getActiveStates:()=>G.activeStates};var he=new ContextMenuExtension;he.config={...he.config,preventDefault:true};var to=new CommandPaletteExtension,ge=new DraggableBlockExtension;ge.config={...ge.config,showMoveButtons:true,showUpButton:true,showDownButton:true,buttonStackPosition:"left"};var be=new LinkExtension;be.config={...be.config,linkSelectedTextOnPaste:true,autoLinkText:true,autoLinkUrls:true};var z=[boldExtension,italicExtension,underlineExtension,strikethroughExtension,be,horizontalRuleExtension,ue,listExtension,historyExtension,H,blockFormatExtension,htmlExtension,B,codeExtension,codeFormatExtension,pe,me,he,to,ge];function qe(){return [{id:"format.bold",label:"Toggle Bold",description:"Make text bold or remove bold formatting",category:"Format",action:e=>e.toggleBold(),shortcuts:[{key:"b",ctrlKey:true}],keywords:["bold","strong","format"]},{id:"format.italic",label:"Toggle Italic",description:"Make text italic or remove italic formatting",category:"Format",action:e=>e.toggleItalic(),shortcuts:[{key:"i",ctrlKey:true}],keywords:["italic","emphasis","format"]},{id:"format.underline",label:"Toggle Underline",description:"Add or remove underline formatting",category:"Format",action:e=>e.toggleUnderline(),shortcuts:[{key:"u",ctrlKey:true}],keywords:["underline","format"]},{id:"format.strikethrough",label:"Toggle Strikethrough",description:"Add or remove strikethrough formatting",category:"Format",action:e=>e.toggleStrikethrough(),keywords:["strikethrough","format"]},{id:"format.code",label:"Toggle Inline Code",description:"Format text as inline code",category:"Format",action:e=>e.formatText("code"),shortcuts:[{key:"`",ctrlKey:true}],keywords:["code","inline","format"]},{id:"block.heading1",label:"Heading 1",description:"Convert to large heading",category:"Block",action:e=>e.toggleHeading("h1"),shortcuts:[{key:"1",ctrlKey:true,altKey:true}],keywords:["heading","h1"]},{id:"block.heading2",label:"Heading 2",description:"Convert to medium heading",category:"Block",action:e=>e.toggleHeading("h2"),shortcuts:[{key:"2",ctrlKey:true,altKey:true}],keywords:["heading","h2"]},{id:"block.heading3",label:"Heading 3",description:"Convert to small heading",category:"Block",action:e=>e.toggleHeading("h3"),shortcuts:[{key:"3",ctrlKey:true,altKey:true}],keywords:["heading","h3"]},{id:"block.paragraph",label:"Paragraph",description:"Convert to paragraph",category:"Block",action:e=>e.toggleParagraph(),shortcuts:[{key:"0",ctrlKey:true,altKey:true}],keywords:["paragraph","text"]},{id:"block.quote",label:"Quote",description:"Convert to blockquote",category:"Block",action:e=>e.toggleQuote(),keywords:["quote","blockquote"]},{id:"block.codeblock",label:"Code Block",description:"Convert to code block",category:"Block",action:e=>e.toggleCodeBlock(),shortcuts:[{key:"`",ctrlKey:true,shiftKey:true}],keywords:["code","block"]},{id:"list.bullet",label:"Bullet List",description:"Create or toggle bullet list",category:"List",action:e=>e.toggleUnorderedList(),shortcuts:[{key:"l",ctrlKey:true,shiftKey:true}],keywords:["list","bullet"]},{id:"list.numbered",label:"Numbered List",description:"Create or toggle numbered list",category:"List",action:e=>e.toggleOrderedList(),shortcuts:[{key:"l",ctrlKey:true,altKey:true}],keywords:["list","numbered"]},{id:"link.insert",label:"Insert Link",description:"Insert or edit a link",category:"Insert",action:e=>e.insertLink(),shortcuts:[{key:"k",ctrlKey:true}],keywords:["link","url"]},{id:"link.remove",label:"Remove Link",description:"Remove link formatting",category:"Format",action:e=>e.removeLink(),shortcuts:[{key:"k",ctrlKey:true,shiftKey:true}],keywords:["unlink","remove","link"]},{id:"insert.horizontal-rule",label:"Insert Horizontal Rule",description:"Insert a horizontal line separator",category:"Insert",action:e=>e.insertHorizontalRule(),keywords:["horizontal","rule"]},{id:"insert.image",label:"Insert Image",description:"Insert an image from URL",category:"Insert",action:e=>{let o=prompt("Enter image URL:");if(o){let r=prompt("Enter alt text:")||"";e.insertImage({src:o,alt:r});}},keywords:["image","photo"]},{id:"insert.table",label:"Insert Table",description:"Insert a 3x3 table",category:"Insert",action:e=>e.insertTable({rows:3,columns:3,includeHeaders:true}),keywords:["table","grid"]},{id:"insert.html-embed",label:"Insert HTML Embed",description:"Insert a custom HTML block",category:"Insert",action:e=>e.insertHTMLEmbed(),keywords:["html","embed"]},{id:"edit.undo",label:"Undo",description:"Undo the last action",category:"Edit",action:e=>e.undo(),shortcuts:[{key:"z",ctrlKey:true}],keywords:["undo","revert"]},{id:"edit.redo",label:"Redo",description:"Redo the last undone action",category:"Edit",action:e=>e.redo(),shortcuts:[{key:"y",ctrlKey:true},{key:"z",ctrlKey:true,shiftKey:true}],keywords:["redo","repeat"]},{id:"palette.show",label:"Show Command Palette",description:"Open the command palette",category:"View",action:e=>e.showCommandPalette(),shortcuts:[{key:"p",ctrlKey:true,shiftKey:true}],keywords:["command","palette"]}]}function We(e){return qe().map(o=>({id:o.id,label:o.label,description:o.description,category:o.category,action:()=>o.action(e),keywords:o.keywords,shortcut:o.shortcuts?.[0]?ro(o.shortcuts[0]):void 0}))}function ro(e){let o=[];return e.ctrlKey&&o.push("Ctrl"),e.metaKey&&o.push("Cmd"),e.altKey&&o.push("Alt"),e.shiftKey&&o.push("Shift"),o.push(e.key.toUpperCase()),o.join("+")}function Ve(e,o=document.body){let r=qe(),i=n=>{for(let l of r)if(l.shortcuts){for(let a of l.shortcuts)if(n.key.toLowerCase()===a.key.toLowerCase()&&!!n.ctrlKey==!!a.ctrlKey&&!!n.metaKey==!!a.metaKey&&!!n.shiftKey==!!a.shiftKey&&!!n.altKey==!!a.altKey){a.preventDefault!==false&&n.preventDefault(),(!l.condition||l.condition(e))&&l.action(e);return}}};return o.addEventListener("keydown",i),()=>o.removeEventListener("keydown",i)}function lo(e,o){let r=useRef(null),i=H.config;return {handlers:useMemo(()=>({insertFromUrl:()=>{let l=prompt("Enter image URL:");if(!l)return;let a=prompt("Enter alt text:")||"",s=prompt("Enter caption (optional):")||void 0;e.insertImage({src:l,alt:a,caption:s});},insertFromFile:()=>r.current?.click(),handleUpload:async l=>{let a=l.target.files?.[0];if(!a)return;let s;if(i.uploadHandler)try{s=await i.uploadHandler(a);}catch{alert("Failed to upload image");return}else s=URL.createObjectURL(a);e.insertImage({src:s,alt:a.name,file:a}),l.target.value="";},setAlignment:l=>{e.setImageAlignment(l);},setCaption:()=>{let l=prompt("Enter caption:")||"";e.setImageCaption(l);}}),[e,i]),fileInputRef:r}}function Ge({commands:e,hasExtension:o,activeStates:r,isDark:i,toggleTheme:n,onCommandPaletteOpen:l,editor:a}){let{handlers:s,fileInputRef:f}=lo(e),[v,y]=useState(false),[p,h]=useState(false),[g,w]=useState(false),[L,P]=useState({rows:3,columns:3,includeHeaders:false}),D=[{value:"p",label:"Paragraph"},{value:"h1",label:"Heading 1"},{value:"h2",label:"Heading 2"},{value:"h3",label:"Heading 3"},{value:"h4",label:"Heading 4"},{value:"h5",label:"Heading 5"},{value:"h6",label:"Heading 6"},{value:"quote",label:"Quote"}],ye=r.isH1?"h1":r.isH2?"h2":r.isH3?"h3":r.isH4?"h4":r.isH5?"h5":r.isH6?"h6":r.isQuote?"quote":"p",m=c=>{c==="p"?e.toggleParagraph():c.startsWith("h")?e.toggleHeading(c):c==="quote"&&e.toggleQuote();};return jsxs(Fragment,{children:[jsxs("div",{className:"luthor-toolbar",children:[jsxs("div",{className:"luthor-toolbar-section",children:[jsx(d,{onClick:()=>e.toggleBold(),active:r.bold,title:"Bold (Ctrl+B)",children:jsx(U,{size:16})}),jsx(d,{onClick:()=>e.toggleItalic(),active:r.italic,title:"Italic (Ctrl+I)",children:jsx(A,{size:16})}),jsx(d,{onClick:()=>e.toggleUnderline(),active:r.underline,title:"Underline (Ctrl+U)",children:jsx(O,{size:16})}),jsx(d,{onClick:()=>e.toggleStrikethrough(),active:r.strikethrough,title:"Strikethrough",children:jsx($,{size:16})}),jsx(d,{onClick:()=>e.formatText("code"),active:r.code,title:"Inline Code",children:jsx(j,{size:16})}),jsx(d,{onClick:()=>r.isLink?e.removeLink():e.insertLink(),active:r.isLink,title:r.isLink?"Remove Link":"Insert Link",children:r.isLink?jsx(Q,{size:16}):jsx(R,{size:16})})]}),o("blockFormat")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(Oe,{value:ye,onValueChange:m,options:D,placeholder:"Format"}),o("code")&&jsx(d,{onClick:()=>e.toggleCodeBlock(),active:r.isInCodeBlock,title:"Code Block",children:jsx(we,{size:16})})]}),o("list")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(d,{onClick:()=>e.toggleUnorderedList(),active:r.unorderedList,title:"Bullet List",children:jsx(_,{size:16})}),jsx(d,{onClick:()=>e.toggleOrderedList(),active:r.orderedList,title:"Numbered List",children:jsx(q,{size:16})}),(r.unorderedList||r.orderedList)&&jsxs(Fragment,{children:[jsx(d,{onClick:()=>e.indentList(),title:"Indent List",children:jsx(He,{size:14})}),jsx(d,{onClick:()=>e.outdentList(),title:"Outdent List",children:jsx(Ke,{size:14})})]})]}),o("horizontalRule")&&jsx("div",{className:"luthor-toolbar-section",children:jsx(d,{onClick:()=>e.insertHorizontalRule(),title:"Insert Horizontal Rule",children:jsx(Pe,{size:16})})}),o("table")&&jsx("div",{className:"luthor-toolbar-section",children:jsx(d,{onClick:()=>w(true),title:"Insert Table",children:jsx(ze,{size:16})})}),o("image")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsxs(ce,{trigger:jsx("button",{className:`luthor-toolbar-button ${r.imageSelected?"active":""}`,title:"Insert Image",children:jsx(Ie,{size:16})}),isOpen:v,onOpenChange:y,children:[jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{s.insertFromUrl(),y(false);},children:[jsx(R,{size:16}),jsx("span",{children:"From URL"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{s.insertFromFile(),y(false);},children:[jsx(Le,{size:16}),jsx("span",{children:"Upload File"})]})]}),r.imageSelected&&jsxs(ce,{trigger:jsx("button",{className:"luthor-toolbar-button",title:"Align Image",children:jsx(N,{size:16})}),isOpen:p,onOpenChange:h,children:[jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{s.setAlignment("left"),h(false);},children:[jsx(W,{size:16}),jsx("span",{children:"Align Left"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{s.setAlignment("center"),h(false);},children:[jsx(N,{size:16}),jsx("span",{children:"Align Center"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{s.setAlignment("right"),h(false);},children:[jsx(V,{size:16}),jsx("span",{children:"Align Right"})]}),jsxs("button",{className:"luthor-dropdown-item",onClick:()=>{s.setCaption(),h(false);},children:[jsx(Me,{size:16}),jsx("span",{children:"Set Caption"})]})]}),jsx("input",{ref:f,type:"file",accept:"image/*",onChange:s.handleUpload,className:"luthor-file-input"})]}),o("htmlEmbed")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(d,{onClick:()=>e.insertHTMLEmbed(),active:r.isHTMLEmbedSelected,title:"Insert HTML Embed",children:jsx(Te,{size:16})}),r.isHTMLEmbedSelected&&jsx(d,{onClick:()=>e.toggleHTMLPreview(),title:"Toggle Preview/Edit",children:r.isHTMLPreviewMode?jsx(Re,{size:16}):jsx(Ne,{size:16})})]}),o("history")&&jsxs("div",{className:"luthor-toolbar-section",children:[jsx(d,{onClick:()=>e.undo(),disabled:!r.canUndo,title:"Undo (Ctrl+Z)",children:jsx(Ce,{size:16})}),jsx(d,{onClick:()=>e.redo(),disabled:!r.canRedo,title:"Redo (Ctrl+Y)",children:jsx(Ee,{size:16})})]}),jsx("div",{className:"luthor-toolbar-section",children:jsx(d,{onClick:l,title:"Command Palette (Ctrl+Shift+P)",children:jsx(Y,{size:16})})}),jsx("div",{className:"luthor-toolbar-section",children:jsx(d,{onClick:n,title:i?"Light Mode":"Dark Mode",children:i?jsx(Se,{size:16}):jsx(Fe,{size:16})})})]}),jsx($e,{isOpen:g,onClose:()=>w(false),title:"Insert Table",children:jsxs("div",{className:"luthor-table-dialog",children:[jsxs("div",{className:"luthor-form-group",children:[jsx("label",{htmlFor:"table-rows",children:"Rows:"}),jsx("input",{id:"table-rows",type:"number",min:"1",max:"20",value:L.rows,onChange:c=>P(k=>({...k,rows:parseInt(c.target.value)||1})),className:"luthor-input"})]}),jsxs("div",{className:"luthor-form-group",children:[jsx("label",{htmlFor:"table-columns",children:"Columns:"}),jsx("input",{id:"table-columns",type:"number",min:"1",max:"20",value:L.columns,onChange:c=>P(k=>({...k,columns:parseInt(c.target.value)||1})),className:"luthor-input"})]}),jsx("div",{className:"luthor-form-group",children:jsxs("label",{className:"luthor-checkbox-label",children:[jsx("input",{type:"checkbox",checked:L.includeHeaders||false,onChange:c=>P(k=>({...k,includeHeaders:c.target.checked})),className:"luthor-checkbox"}),"Include headers"]})}),jsxs("div",{className:"luthor-dialog-actions",children:[jsx(de,{variant:"secondary",onClick:()=>w(false),children:"Cancel"}),jsx(de,{variant:"primary",onClick:()=>{e.insertTable(L),w(false);},children:"Insert Table"})]})]})})]})}function Ze({isOpen:e,onClose:o,commands:r}){let[i,n]=useState(""),[l,a]=useState(0),s=useRef(null),f=r.filter(p=>`${p.label} ${p.description||""} ${p.keywords?.join(" ")||""}`.toLowerCase().includes(i.toLowerCase())),v=f.reduce((p,h)=>{let g=h.category||"Other";return p[g]||(p[g]=[]),p[g].push(h),p},{}),y=f;return useEffect(()=>{a(0);},[i]),useEffect(()=>{e&&s.current&&(s.current.focus(),n(""),a(0));},[e]),useEffect(()=>{let p=h=>{if(e)switch(h.key){case "Escape":h.preventDefault(),o();break;case "ArrowDown":h.preventDefault(),a(g=>Math.min(g+1,y.length-1));break;case "ArrowUp":h.preventDefault(),a(g=>Math.max(g-1,0));break;case "Enter":h.preventDefault(),y[l]&&(y[l].action(),o());break}};return document.addEventListener("keydown",p),()=>document.removeEventListener("keydown",p)},[e,l,y,o]),e?jsx("div",{className:"luthor-command-palette-overlay",onClick:o,children:jsxs("div",{className:"luthor-command-palette",onClick:p=>p.stopPropagation(),children:[jsxs("div",{className:"luthor-command-palette-header",children:[jsx(De,{size:16,className:"luthor-command-palette-icon"}),jsx("input",{ref:s,type:"text",placeholder:"Type a command or search...",value:i,onChange:p=>n(p.target.value),className:"luthor-command-palette-input"}),jsx("kbd",{className:"luthor-command-palette-kbd",children:"ESC"})]}),jsx("div",{className:"luthor-command-palette-list",children:Object.keys(v).length===0?jsx("div",{className:"luthor-command-palette-empty",children:"No commands found"}):Object.entries(v).map(([p,h])=>jsxs("div",{className:"luthor-command-palette-group",children:[jsx("div",{className:"luthor-command-palette-group-title",children:p}),h.map(g=>{let w=y.indexOf(g);return jsxs("div",{className:`luthor-command-palette-item ${w===l?"selected":""}`,onClick:()=>{g.action(),o();},onMouseEnter:()=>a(w),children:[jsxs("div",{className:"luthor-command-palette-item-content",children:[jsx("div",{className:"luthor-command-palette-item-title",children:g.label}),g.description&&jsx("div",{className:"luthor-command-palette-item-description",children:g.description})]}),g.shortcut&&jsx("kbd",{className:"luthor-command-palette-item-shortcut",children:g.shortcut})]},g.id)})]},p))}),jsx("div",{className:"luthor-command-palette-footer",children:jsxs("span",{className:"luthor-command-palette-hint",children:[jsx(Y,{size:14}),jsx("span",{children:"Use arrow keys, Enter, ESC"})]})})]})}):null}var{Provider:ho,useEditor:go}=createEditorSystem();function bo({mode:e,onModeChange:o}){return jsxs("div",{className:"luthor-mode-tabs",children:[jsx("button",{className:`luthor-mode-tab ${e==="visual"?"active":""}`,onClick:()=>o("visual"),children:"Visual"}),jsx("button",{className:`luthor-mode-tab ${e==="html"?"active":""}`,onClick:()=>o("html"),children:"HTML"}),jsx("button",{className:`luthor-mode-tab ${e==="markdown"?"active":""}`,onClick:()=>o("markdown"),children:"Markdown"})]})}function et({value:e,onChange:o,placeholder:r}){return jsx("textarea",{className:"luthor-source-view",value:e,onChange:i=>o(i.target.value),placeholder:r,spellCheck:false})}function xo({className:e,isDark:o,toggleTheme:r,onReady:i}){let{commands:n,hasExtension:l,activeStates:a,lexical:s,extensions:f}=go(),[v,y]=useState("visual"),[p,h]=useState({html:"",markdown:""}),[g,w]=useState({isOpen:false,commands:[]}),L=useRef(n),P=useRef(false);useEffect(()=>{L.current=n;},[n]),useEffect(()=>{_e(n,a);},[n,a]);let D=useMemo(()=>({injectMarkdown:m=>{setTimeout(()=>{s&&s.update(()=>{L.current.importFromMarkdown(m,{immediate:true,preventFocus:true});});},100);},injectHTML:m=>{setTimeout(()=>{s&&s.update(()=>{L.current.importFromHTML(m,{preventFocus:true});});},100);},getMarkdown:()=>L.current.exportToMarkdown(),getHTML:()=>L.current.exportToHTML()}),[s]);return useEffect(()=>{if(!s||!n)return;let m=We(n);m.forEach(k=>n.registerCommand(k));let c=Ve(n,document.body);return P.current||(P.current=true,i?.(D)),()=>{c(),m.forEach(k=>n.unregisterCommand(k.id));}},[s,n,D,i]),useEffect(()=>{let m=f.find(c=>c.name==="commandPalette");if(!(!m||!m.subscribe))return m.subscribe((c,k)=>{w({isOpen:c,commands:k});})},[f]),jsxs(Fragment,{children:[jsxs("div",{className:"luthor-editor-header",children:[jsx(bo,{mode:v,onModeChange:async m=>{if(v==="markdown"&&m!=="markdown"&&l("markdown")&&(await n.importFromMarkdown(p.markdown,{immediate:true}),await new Promise(c=>setTimeout(c,50))),v==="html"&&m!=="html"&&l("html")&&(await n.importFromHTML(p.html),await new Promise(c=>setTimeout(c,50))),m==="markdown"&&v!=="markdown"&&l("markdown")){await new Promise(k=>setTimeout(k,50));let c=n.exportToMarkdown();h(k=>({...k,markdown:c}));}if(m==="html"&&v!=="html"&&l("html")){await new Promise(k=>setTimeout(k,50));let c=n.exportToHTML();h(k=>({...k,html:c}));}y(m),m==="visual"&&setTimeout(()=>s?.focus(),100);}}),v==="visual"&&jsx(Ge,{commands:n,hasExtension:m=>l(m),activeStates:a,isDark:o,toggleTheme:r,onCommandPaletteOpen:()=>n.showCommandPalette(),editor:s})]}),jsxs("div",{className:"luthor-editor","data-mode":v,children:[v==="visual"&&jsx(RichText,{placeholder:"Write anything...",classNames:{container:"luthor-richtext-container luthor-preset-extensive__container",contentEditable:"luthor-content-editable luthor-preset-extensive__content",placeholder:"luthor-placeholder luthor-preset-extensive__placeholder"}}),v!=="visual"&&jsxs("div",{className:"luthor-source-panel",children:[v==="html"&&jsx(et,{value:p.html,onChange:m=>h(c=>({...c,html:m})),placeholder:"Enter HTML content..."}),v==="markdown"&&jsx(et,{value:p.markdown,onChange:m=>h(c=>({...c,markdown:m})),placeholder:"Enter Markdown content..."})]})]}),jsx(Ze,{isOpen:g.isOpen,onClose:()=>n.hideCommandPalette(),commands:g.commands})]})}var F=forwardRef(({className:e,onReady:o,initialTheme:r="light",defaultContent:i,showDefaultContent:n=true},l)=>{let[a,s]=useState(r),f=a==="dark",v=()=>s(f?"light":"dark"),[y,p]=useState(null);so.useImperativeHandle(l,()=>y,[y]);let h=`# (Default Content) Welcome to Luthor Editor
2
+
3
+ **Build amazing React-based rich text editors with ease**
4
+
5
+ Luthor is a modern, type-safe React framework built on top of Meta's Lexical that makes creating powerful text editors simple and enjoyable.
6
+
7
+ ## \u2728 Quick Start
8
+
9
+ - \u{1F680} Lightning Fast - Optimized performance with minimal bundle size
10
+ - \u{1F6E1}\uFE0F Type-Safe - Full TypeScript support with auto-completion
11
+ - \u{1F9E9} Extensible - 25+ built-in extensions for common features
12
+ - \u{1F3A8} Customizable - Framework-agnostic styling with CSS custom properties
13
+
14
+ ## \u{1F4DD} Try It Out
15
+
16
+ Start typing or use the toolbar above to format your text. Press \`Cmd+K\` (Mac) or \`Ctrl+K\` (Windows/Linux) to open the command palette.`,g=w=>{p(w),n&&i===void 0?w.injectMarkdown(h):i&&w.injectMarkdown(i),o?.(w);};return jsx("div",{className:`luthor-preset luthor-preset-extensive luthor-editor-wrapper ${e||""}`,"data-editor-theme":a,children:jsx(ho,{extensions:z,children:jsx(xo,{className:e,isDark:f,toggleTheme:v,onReady:g})})})});F.displayName="ExtensiveEditor";var fe={id:"extensive",label:"Extensive",description:"All features enabled for power users.",extensions:[...z],components:{Editor:F},toolbar:["undo","redo","heading","bold","italic","underline","strikethrough","link","image","table","blockquote","code","codeBlock","bulletedList","numberedList"],config:b("extensive","Write anything..."),css:"extensive/styles.css"};var ve={id:"markdown",label:"Markdown",description:"Markdown first editing with predictable output.",toolbar:["bold","italic","link","code","codeBlock"],config:b("markdown","Write in markdown..."),css:"markdown/styles.css"};var ke={id:"minimal",label:"Minimal",description:"Lightweight editor for short text and embeds.",toolbar:["bold","italic","link"],config:b("minimal","Write something..."),css:"minimal/styles.css"};var pn={minimal:ke,classic:te,docs:ie,blog:J,cms:oe,chat:ee,email:le,markdown:ve,code:re,default:ne,extensive:fe};export{F as ExtensiveEditor,J as blogPreset,ee as chatPreset,te as classicPreset,oe as cmsPreset,re as codePreset,b as createPresetEditorConfig,ne as defaultPreset,ie as docsPreset,le as emailPreset,z as extensiveExtensions,fe as extensivePreset,ve as markdownPreset,ke as minimalPreset,pn as presetRegistry};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyfie/luthor",
3
- "version": "2.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "Luthor presets and plug-and-play configuration for the headless editor",
5
5
  "type": "module",
6
6
  "private": false,
@@ -12,7 +12,8 @@
12
12
  "import": "./dist/index.js",
13
13
  "require": "./dist/index.js",
14
14
  "default": "./dist/index.js"
15
- }
15
+ },
16
+ "./styles.css": "./dist/index.css"
16
17
  },
17
18
  "keywords": [
18
19
  "editor",
@@ -34,7 +35,19 @@
34
35
  },
35
36
  "homepage": "https://github.com/lyfie-app/luthor#readme",
36
37
  "dependencies": {
37
- "@lyfie/luthor-headless": "2.0.0"
38
+ "@lyfie/luthor-headless": "^2.0.1",
39
+ "@lexical/code": "^0.34.0",
40
+ "@lexical/html": "^0.34.0",
41
+ "@lexical/link": "^0.34.0",
42
+ "@lexical/list": "^0.34.0",
43
+ "@lexical/markdown": "^0.34.0",
44
+ "@lexical/react": "^0.34.0",
45
+ "@lexical/rich-text": "^0.34.0",
46
+ "@lexical/selection": "^0.34.0",
47
+ "@lexical/table": "^0.34.0",
48
+ "@lexical/utils": "^0.34.0",
49
+ "lexical": "^0.34.0",
50
+ "lucide-react": "^0.475.0"
38
51
  },
39
52
  "devDependencies": {
40
53
  "@types/node": "^20.19.9",
@@ -43,21 +56,10 @@
43
56
  "eslint": "^9.32.0",
44
57
  "tsup": "^8.0.0",
45
58
  "typescript": "^5.7.3",
46
- "@repo/typescript-config": "0.0.0",
47
- "@repo/eslint-config": "0.0.0"
59
+ "@repo/eslint-config": "0.0.0",
60
+ "@repo/typescript-config": "0.0.0"
48
61
  },
49
62
  "peerDependencies": {
50
- "@lexical/code": ">=0.34.0",
51
- "@lexical/html": ">=0.34.0",
52
- "@lexical/link": ">=0.34.0",
53
- "@lexical/list": ">=0.34.0",
54
- "@lexical/markdown": ">=0.34.0",
55
- "@lexical/react": ">=0.34.0",
56
- "@lexical/rich-text": ">=0.34.0",
57
- "@lexical/selection": ">=0.34.0",
58
- "@lexical/table": ">=0.34.0",
59
- "@lexical/utils": ">=0.34.0",
60
- "lexical": ">=0.34.0",
61
63
  "react": "^18.0.0 || ^19.0.0",
62
64
  "react-dom": "^18.0.0 || ^19.0.0"
63
65
  },