@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 +539 -20
- package/dist/index.css +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +16 -1
- package/package.json +18 -16
package/README.md
CHANGED
|
@@ -1,48 +1,567 @@
|
|
|
1
1
|
# Luthor Presets
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Batteries-included presets and plug-and-play configurations for the Luthor editor**
|
|
4
4
|
|
|
5
|
-
|
|
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
|
+
[](https://badge.fury.io/js/%40lyfie%2Fluthor)
|
|
8
|
+
[](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
|
|
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
|
-
|
|
43
|
+
**That's it!** All required Lexical packages are automatically installed as dependencies of `@lyfie/luthor`.
|
|
12
44
|
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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 {
|
|
111
|
+
import { createEditorSystem, RichText } from "@lyfie/luthor-headless";
|
|
112
|
+
import { extensiveExtensions } from "@lyfie/luthor";
|
|
21
113
|
|
|
22
|
-
|
|
23
|
-
const preset = presetRegistry.default;
|
|
114
|
+
const { Provider, useEditor } = createEditorSystem<typeof extensiveExtensions>();
|
|
24
115
|
|
|
25
|
-
|
|
26
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
189
|
+
### 9. **Code** - `codePreset`
|
|
190
|
+
Code snippet editor.
|
|
191
|
+
- Syntax highlighting
|
|
192
|
+
- Multiple language support
|
|
193
|
+
- Line numbers
|
|
34
194
|
|
|
35
|
-
|
|
195
|
+
### 10. **Default** - `defaultPreset`
|
|
196
|
+
Balanced general-purpose editor.
|
|
197
|
+
- Good starting point for customization
|
|
36
198
|
|
|
37
|
-
|
|
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-
|
|
45
|
-
label: "My
|
|
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,
|
|
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
|
|
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.
|
|
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/
|
|
47
|
-
"@repo/
|
|
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
|
},
|