@editora/react 1.0.1
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 +496 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.esm.js +1044 -0
- package/dist/react.css +1 -0
- package/package.json +76 -0
package/README.md
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
# @editora/react
|
|
2
|
+
|
|
3
|
+
React components for Editora Rich Text Editor - A modern, extensible WYSIWYG editor.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @editora/react @editora/core @editora/plugins @editora/themes
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 🎯 Overview
|
|
12
|
+
|
|
13
|
+
The React package provides ready-to-use React components for building rich text editing experiences. It includes hooks, components, and utilities specifically designed for React applications.
|
|
14
|
+
|
|
15
|
+
## ✨ Features
|
|
16
|
+
|
|
17
|
+
- **React Hooks**: Modern hooks-based API (`useEditor`, `useEditorState`)
|
|
18
|
+
- **TypeScript**: Full type safety and IntelliSense support
|
|
19
|
+
- **SSR Compatible**: Works with Next.js and server-side rendering
|
|
20
|
+
- **Tree Shakeable**: Optimized bundle sizes
|
|
21
|
+
- **Accessible**: WCAG 2.1 compliant
|
|
22
|
+
- **Multi-Instance**: Support for multiple editors on one page
|
|
23
|
+
|
|
24
|
+
## 🚀 Quick Start
|
|
25
|
+
|
|
26
|
+
### Basic Editor
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { EditoraEditor } from '@editora/react';
|
|
30
|
+
import { BoldPlugin, ItalicPlugin } from '@editora/plugins';
|
|
31
|
+
import '@editora/themes/styles';
|
|
32
|
+
|
|
33
|
+
function App() {
|
|
34
|
+
const [content, setContent] = useState('<p>Start writing...</p>');
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<EditoraEditor
|
|
38
|
+
value={content}
|
|
39
|
+
onChange={setContent}
|
|
40
|
+
plugins={[
|
|
41
|
+
BoldPlugin(),
|
|
42
|
+
ItalicPlugin()
|
|
43
|
+
]}
|
|
44
|
+
placeholder="Type something..."
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Full-Featured Editor
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { EditoraEditor } from '@editora/react';
|
|
54
|
+
import {
|
|
55
|
+
BoldPlugin,
|
|
56
|
+
ItalicPlugin,
|
|
57
|
+
UnderlinePlugin,
|
|
58
|
+
HeadingPlugin,
|
|
59
|
+
ParagraphPlugin,
|
|
60
|
+
ListPlugin,
|
|
61
|
+
LinkPlugin,
|
|
62
|
+
ImagePlugin,
|
|
63
|
+
TablePlugin,
|
|
64
|
+
CodeSamplePlugin,
|
|
65
|
+
HistoryPlugin
|
|
66
|
+
} from '@editora/plugins';
|
|
67
|
+
import '@editora/themes/styles';
|
|
68
|
+
|
|
69
|
+
function FullEditor() {
|
|
70
|
+
const [content, setContent] = useState('');
|
|
71
|
+
|
|
72
|
+
const plugins = [
|
|
73
|
+
BoldPlugin(),
|
|
74
|
+
ItalicPlugin(),
|
|
75
|
+
UnderlinePlugin(),
|
|
76
|
+
HeadingPlugin(),
|
|
77
|
+
ListPlugin(),
|
|
78
|
+
LinkPlugin({
|
|
79
|
+
onLinkClick: (url) => window.open(url, '_blank')
|
|
80
|
+
}),
|
|
81
|
+
createImagePlugin({
|
|
82
|
+
upload: async (file) => {
|
|
83
|
+
const formData = new FormData();
|
|
84
|
+
formData.append('image', file);
|
|
85
|
+
const response = await fetch('/api/upload', {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
body: formData
|
|
88
|
+
});
|
|
89
|
+
const data = await response.json();
|
|
90
|
+
return data.url;
|
|
91
|
+
}
|
|
92
|
+
}),
|
|
93
|
+
createTablePlugin(),
|
|
94
|
+
createCodeSamplePlugin(),
|
|
95
|
+
createHistoryPlugin()
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div className="editor-container">
|
|
100
|
+
<EditoraEditor
|
|
101
|
+
value={content}
|
|
102
|
+
onChange={setContent}
|
|
103
|
+
plugins={plugins}
|
|
104
|
+
placeholder="Start writing your document..."
|
|
105
|
+
autofocus
|
|
106
|
+
/>
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### With Custom Toolbar
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
import { EditoraEditor, Toolbar, ToolbarButton } from '@editora/react';
|
|
116
|
+
import { useEditor } from '@editora/react/hooks';
|
|
117
|
+
|
|
118
|
+
function EditorWithCustomToolbar() {
|
|
119
|
+
const { editor, html, setHtml } = useEditor({
|
|
120
|
+
plugins: [/* your plugins */],
|
|
121
|
+
content: '<p>Hello</p>'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div>
|
|
126
|
+
<Toolbar editor={editor}>
|
|
127
|
+
<ToolbarButton command="bold" icon="bold" />
|
|
128
|
+
<ToolbarButton command="italic" icon="italic" />
|
|
129
|
+
<ToolbarButton command="underline" icon="underline" />
|
|
130
|
+
<div className="separator" />
|
|
131
|
+
<ToolbarButton command="heading" level={1} icon="h1" />
|
|
132
|
+
<ToolbarButton command="heading" level={2} icon="h2" />
|
|
133
|
+
</Toolbar>
|
|
134
|
+
|
|
135
|
+
<div
|
|
136
|
+
ref={(el) => el && editor.mount(el)}
|
|
137
|
+
className="editor-content"
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 📖 API Reference
|
|
145
|
+
|
|
146
|
+
### Components
|
|
147
|
+
|
|
148
|
+
#### `<EditoraEditor />`
|
|
149
|
+
|
|
150
|
+
Main editor component with built-in toolbar.
|
|
151
|
+
|
|
152
|
+
**Props:**
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
interface EditoraEditorProps {
|
|
156
|
+
// Content
|
|
157
|
+
value?: string;
|
|
158
|
+
defaultValue?: string;
|
|
159
|
+
onChange?: (html: string) => void;
|
|
160
|
+
|
|
161
|
+
// Plugins
|
|
162
|
+
plugins?: Plugin[];
|
|
163
|
+
|
|
164
|
+
// Configuration
|
|
165
|
+
placeholder?: string;
|
|
166
|
+
readonly?: boolean;
|
|
167
|
+
autofocus?: boolean;
|
|
168
|
+
maxLength?: number;
|
|
169
|
+
|
|
170
|
+
// Styling
|
|
171
|
+
className?: string;
|
|
172
|
+
style?: React.CSSProperties;
|
|
173
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
174
|
+
|
|
175
|
+
// Toolbar
|
|
176
|
+
showToolbar?: boolean;
|
|
177
|
+
toolbarItems?: ToolbarItem[];
|
|
178
|
+
toolbarPosition?: 'top' | 'bottom' | 'floating';
|
|
179
|
+
|
|
180
|
+
// Events
|
|
181
|
+
onFocus?: () => void;
|
|
182
|
+
onBlur?: () => void;
|
|
183
|
+
onReady?: (editor: Editor) => void;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### `<Toolbar />`
|
|
188
|
+
|
|
189
|
+
Customizable toolbar component.
|
|
190
|
+
|
|
191
|
+
**Props:**
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
interface ToolbarProps {
|
|
195
|
+
editor: Editor;
|
|
196
|
+
items?: ToolbarItem[];
|
|
197
|
+
position?: 'top' | 'bottom' | 'floating';
|
|
198
|
+
className?: string;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### `<ToolbarButton />`
|
|
203
|
+
|
|
204
|
+
Individual toolbar button.
|
|
205
|
+
|
|
206
|
+
**Props:**
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
interface ToolbarButtonProps {
|
|
210
|
+
command: string;
|
|
211
|
+
icon?: React.ReactNode;
|
|
212
|
+
label?: string;
|
|
213
|
+
active?: boolean;
|
|
214
|
+
disabled?: boolean;
|
|
215
|
+
onClick?: () => void;
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Hooks
|
|
220
|
+
|
|
221
|
+
#### `useEditor(config)`
|
|
222
|
+
|
|
223
|
+
Main hook for editor management.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
const { editor, html, json, setHtml, setJson } = useEditor({
|
|
227
|
+
plugins: [...],
|
|
228
|
+
content: '<p>Initial content</p>',
|
|
229
|
+
onChange: (html) => console.log(html)
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Returns:**
|
|
234
|
+
- `editor`: Editor instance
|
|
235
|
+
- `html`: Current HTML content
|
|
236
|
+
- `json`: Current JSON content
|
|
237
|
+
- `setHtml`: Function to set HTML content
|
|
238
|
+
- `setJson`: Function to set JSON content
|
|
239
|
+
|
|
240
|
+
#### `useEditorState(editor)`
|
|
241
|
+
|
|
242
|
+
Hook for accessing editor state.
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
const {
|
|
246
|
+
isFocused,
|
|
247
|
+
isEmpty,
|
|
248
|
+
canUndo,
|
|
249
|
+
canRedo
|
|
250
|
+
} = useEditorState(editor);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### `useEditorCommands(editor)`
|
|
254
|
+
|
|
255
|
+
Hook for editor commands.
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const {
|
|
259
|
+
bold,
|
|
260
|
+
italic,
|
|
261
|
+
undo,
|
|
262
|
+
redo,
|
|
263
|
+
insertText,
|
|
264
|
+
insertImage
|
|
265
|
+
} = useEditorCommands(editor);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## 🎨 Theming
|
|
269
|
+
|
|
270
|
+
### Using Built-in Themes
|
|
271
|
+
|
|
272
|
+
```tsx
|
|
273
|
+
import '@editora/themes/styles';
|
|
274
|
+
|
|
275
|
+
<EditoraEditor theme="dark" />
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Custom Theme
|
|
279
|
+
|
|
280
|
+
```css
|
|
281
|
+
:root {
|
|
282
|
+
--editora-bg: #ffffff;
|
|
283
|
+
--editora-text: #000000;
|
|
284
|
+
--editora-border: #cccccc;
|
|
285
|
+
--editora-primary: #0066cc;
|
|
286
|
+
--editora-toolbar-bg: #f5f5f5;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
[data-theme="dark"] {
|
|
290
|
+
--editora-bg: #1e1e1e;
|
|
291
|
+
--editora-text: #ffffff;
|
|
292
|
+
--editora-border: #444444;
|
|
293
|
+
--editora-primary: #3399ff;
|
|
294
|
+
--editora-toolbar-bg: #2d2d2d;
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## 🔌 Plugin Configuration
|
|
299
|
+
|
|
300
|
+
### Bold Plugin
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
import { BoldPlugin } from '@editora/plugins';
|
|
304
|
+
|
|
305
|
+
const boldPlugin = BoldPlugin({
|
|
306
|
+
keyboard: 'Mod-b',
|
|
307
|
+
icon: <BoldIcon />
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Image Plugin with Upload
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
import { createImagePlugin } from '@editora/plugins';
|
|
315
|
+
|
|
316
|
+
const imagePlugin = createImagePlugin({
|
|
317
|
+
upload: async (file) => {
|
|
318
|
+
const url = await uploadToServer(file);
|
|
319
|
+
return url;
|
|
320
|
+
},
|
|
321
|
+
validate: (file) => {
|
|
322
|
+
return file.size < 5 * 1024 * 1024; // 5MB limit
|
|
323
|
+
},
|
|
324
|
+
resize: true,
|
|
325
|
+
maxWidth: 1200
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Link Plugin
|
|
330
|
+
|
|
331
|
+
```tsx
|
|
332
|
+
import { createLinkPlugin } from '@editora/plugins';
|
|
333
|
+
|
|
334
|
+
const linkPlugin = createLinkPlugin({
|
|
335
|
+
openOnClick: false,
|
|
336
|
+
validate: (url) => {
|
|
337
|
+
return url.startsWith('http') || url.startsWith('https');
|
|
338
|
+
},
|
|
339
|
+
onLinkClick: (url) => {
|
|
340
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## 💡 Examples
|
|
346
|
+
|
|
347
|
+
### Form Integration
|
|
348
|
+
|
|
349
|
+
```tsx
|
|
350
|
+
function BlogPostForm() {
|
|
351
|
+
const [formData, setFormData] = useState({
|
|
352
|
+
title: '',
|
|
353
|
+
content: ''
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const handleSubmit = async (e) => {
|
|
357
|
+
e.preventDefault();
|
|
358
|
+
await fetch('/api/posts', {
|
|
359
|
+
method: 'POST',
|
|
360
|
+
body: JSON.stringify(formData)
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
return (
|
|
365
|
+
<form onSubmit={handleSubmit}>
|
|
366
|
+
<input
|
|
367
|
+
type="text"
|
|
368
|
+
value={formData.title}
|
|
369
|
+
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
|
|
370
|
+
placeholder="Post title"
|
|
371
|
+
/>
|
|
372
|
+
|
|
373
|
+
<EditoraEditor
|
|
374
|
+
value={formData.content}
|
|
375
|
+
onChange={(content) => setFormData({ ...formData, content })}
|
|
376
|
+
plugins={[/* ... */]}
|
|
377
|
+
/>
|
|
378
|
+
|
|
379
|
+
<button type="submit">Publish</button>
|
|
380
|
+
</form>
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Controlled Editor with Save
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
function DocumentEditor() {
|
|
389
|
+
const [content, setContent] = useState('');
|
|
390
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
391
|
+
|
|
392
|
+
const handleSave = async () => {
|
|
393
|
+
setIsSaving(true);
|
|
394
|
+
try {
|
|
395
|
+
await fetch('/api/save', {
|
|
396
|
+
method: 'POST',
|
|
397
|
+
body: JSON.stringify({ content })
|
|
398
|
+
});
|
|
399
|
+
alert('Saved successfully!');
|
|
400
|
+
} catch (error) {
|
|
401
|
+
alert('Failed to save');
|
|
402
|
+
} finally {
|
|
403
|
+
setIsSaving(false);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
return (
|
|
408
|
+
<div>
|
|
409
|
+
<div className="toolbar-actions">
|
|
410
|
+
<button onClick={handleSave} disabled={isSaving}>
|
|
411
|
+
{isSaving ? 'Saving...' : 'Save'}
|
|
412
|
+
</button>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
<EditoraEditor
|
|
416
|
+
value={content}
|
|
417
|
+
onChange={setContent}
|
|
418
|
+
plugins={[/* ... */]}
|
|
419
|
+
/>
|
|
420
|
+
</div>
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Read-Only Mode
|
|
426
|
+
|
|
427
|
+
```tsx
|
|
428
|
+
function ArticlePreview({ html }) {
|
|
429
|
+
return (
|
|
430
|
+
<EditoraEditor
|
|
431
|
+
value={html}
|
|
432
|
+
readonly
|
|
433
|
+
showToolbar={false}
|
|
434
|
+
className="article-preview"
|
|
435
|
+
/>
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
## 🔧 TypeScript Support
|
|
441
|
+
|
|
442
|
+
The package is written in TypeScript and includes comprehensive type definitions.
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
import type {
|
|
446
|
+
Editor,
|
|
447
|
+
Plugin,
|
|
448
|
+
ToolbarItem,
|
|
449
|
+
EditorConfig
|
|
450
|
+
} from '@editora/react';
|
|
451
|
+
|
|
452
|
+
const config: EditorConfig = {
|
|
453
|
+
plugins: [],
|
|
454
|
+
onChange: (html: string) => {
|
|
455
|
+
// TypeScript knows html is a string
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## 📱 Responsive Design
|
|
461
|
+
|
|
462
|
+
The editor automatically adapts to different screen sizes:
|
|
463
|
+
|
|
464
|
+
```tsx
|
|
465
|
+
<EditoraEditor
|
|
466
|
+
// Toolbar collapses to hamburger menu on mobile
|
|
467
|
+
toolbarBreakpoint={768}
|
|
468
|
+
|
|
469
|
+
// Custom mobile configuration
|
|
470
|
+
mobileConfig={{
|
|
471
|
+
toolbarPosition: 'bottom',
|
|
472
|
+
compactMode: true
|
|
473
|
+
}}
|
|
474
|
+
/>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## ♿ Accessibility
|
|
478
|
+
|
|
479
|
+
The editor is fully accessible and follows WCAG 2.1 guidelines:
|
|
480
|
+
|
|
481
|
+
- Keyboard navigation support
|
|
482
|
+
- Screen reader announcements
|
|
483
|
+
- ARIA attributes
|
|
484
|
+
- Focus management
|
|
485
|
+
- High contrast mode support
|
|
486
|
+
|
|
487
|
+
## 📄 License
|
|
488
|
+
|
|
489
|
+
MIT © [Ajay Kumar](https://github.com/ajaykr089)
|
|
490
|
+
|
|
491
|
+
## 🔗 Links
|
|
492
|
+
|
|
493
|
+
- [Documentation](https://github.com/ajaykr089/Editora#readme)
|
|
494
|
+
- [GitHub Repository](https://github.com/ajaykr089/Editora)
|
|
495
|
+
- [Issue Tracker](https://github.com/ajaykr089/Editora/issues)
|
|
496
|
+
- [npm Package](https://www.npmjs.com/package/@editora/react)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),c=require("react"),I=require("@editora/core"),K=({isOpen:e,options:t,onSelect:u,onClose:s,anchorRef:i,className:a=""})=>{const g=c.useRef(null),[m,b]=c.useState({top:0,left:0});return c.useEffect(()=>{if(e&&i.current){const r=i.current.getBoundingClientRect(),d=120,w=t.length*36;let h=r.bottom+4,f=r.left;const p=window.innerWidth,x=window.innerHeight;f+d>p&&(f=p-d-8),h+w>x&&(h=r.top-w-4),b({top:h,left:f})}},[e,i,t.length]),c.useEffect(()=>{if(e&&i.current&&g.current){const r=i.current.getBoundingClientRect(),d=g.current.getBoundingClientRect();let w=r.bottom+4,h=r.left;const f=window.innerWidth,p=window.innerHeight;h+d.width>f&&(h=f-d.width-8),w+d.height>p&&(w=r.top-d.height-4),b({top:w,left:h})}},[e]),c.useEffect(()=>{const r=w=>{g.current&&!g.current.contains(w.target)&&i.current&&!i.current.contains(w.target)&&s()},d=w=>{w.key==="Escape"&&s()};return e&&(document.addEventListener("mousedown",r),document.addEventListener("keydown",d)),()=>{document.removeEventListener("mousedown",r),document.removeEventListener("keydown",d)}},[e,s,i]),e?o.jsx("div",{ref:g,className:`rte-inline-menu ${a}`,style:{position:"fixed",top:m.top,left:m.left,zIndex:1e3,background:"white",border:"1px solid #ccc",borderRadius:"4px",boxShadow:"0 2px 8px rgba(0, 0, 0, 0.15)",minWidth:"120px",maxWidth:"200px",pointerEvents:"auto"},children:t.map(r=>o.jsx("div",{className:"rte-inline-menu-item",onClick:()=>{u(r.value),s()},style:{padding:"8px 12px",cursor:"pointer",borderBottom:"1px solid #f0f0f0",fontSize:"14px",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},onMouseEnter:d=>{d.currentTarget.style.backgroundColor="#f5f5f5"},onMouseLeave:d=>{d.currentTarget.style.backgroundColor="transparent"},children:r.label},r.value))}):null},H=({editor:e,position:t="top",sticky:u=!1,floating:s=!1})=>{const[i,a]=c.useState(null),[g,m]=c.useState(null),[b,r]=c.useState(null),[d,w]=c.useState(null),[h,f]=c.useState(!1),p=c.useRef({}),x=c.useRef(null),y=c.useRef(null),C=c.useRef(null),v=e.pluginManager.getToolbarItems();c.useEffect(()=>{const n=()=>{if(!x.current||!y.current)return;const N=x.current.clientWidth,A=16,Q=40,F=4,Y=N-A-Q-F;let B=0,O=0;const U=y.current.children;for(let D=0;D<U.length;D++){const q=U[D].offsetWidth+F;if(B+q<=Y)B+=q,O++;else break}w(Math.max(1,O))},l=requestAnimationFrame(()=>{n()}),E=new ResizeObserver(()=>{n()});x.current&&E.observe(x.current);const k=new MutationObserver(()=>{n()});return y.current&&k.observe(y.current,{childList:!0,subtree:!0}),()=>{cancelAnimationFrame(l),E.disconnect(),k.disconnect()}},[v.length]);const T=n=>(p.current[n]||(p.current[n]=c.createRef()),p.current[n]),S=(n,l)=>{const E=x.current?.closest("[data-editora-editor]"),k=E?.querySelector(".rte-content");if(k&&k.focus(),b&&(n==="setTextAlignment"||n==="setFontFamily"||n==="setBlockType")){const A=window.getSelection();A&&(A.removeAllRanges(),A.addRange(b)),r(null)}typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(n,l),a(null);const N=E?.querySelector(".rte-content");N&&N.focus()},R=n=>{const l=window.getSelection();l&&l.rangeCount>0&&r(l.getRangeAt(0).cloneRange()),a(i===n?null:n)},j=n=>{const l=window.getSelection();l&&l.rangeCount>0&&r(l.getRangeAt(0).cloneRange()),m(g===n?null:n),a(null)},L=(n,l)=>{if(b){const E=window.getSelection();E&&(E.removeAllRanges(),E.addRange(b)),r(null)}S(n,l),m(null)},M=(n,l)=>n&&n.startsWith("<svg")&&n.endsWith("</svg>")?o.jsx("span",{dangerouslySetInnerHTML:{__html:n}}):n&&n.length===1&&/^[BIUSH]$/.test(n)?o.jsx("span",{style:{fontWeight:"bold",fontSize:"14px",lineHeight:"1"},children:n}):n||"⚪";if(s)return null;const J={...u&&{position:"sticky",top:0,zIndex:100,backgroundColor:"#fff",boxShadow:"0 2px 4px rgba(0,0,0,0.1)"},...t==="bottom"&&{order:2}},z=n=>n.map((l,E)=>o.jsx("div",{className:"rte-toolbar-item",style:{display:d!==null&&E>=d?"none":"flex"},children:l.type==="dropdown"?o.jsxs("div",{className:"rte-toolbar-dropdown",children:[o.jsxs("button",{className:"rte-toolbar-button","data-command":l.command,"data-active":"false",onClick:()=>R(l.command),children:[l.label," ▼"]}),i===l.command&&o.jsx("div",{className:"rte-toolbar-dropdown-menu",children:l.options?.map(k=>o.jsx("div",{className:"rte-toolbar-dropdown-item",onClick:()=>S(l.command,k.value),children:k.label},k.value))})]}):l.type==="inline-menu"?o.jsx("button",{ref:T(l.command),className:"rte-toolbar-button","data-command":l.command,"data-active":"false",onClick:()=>j(l.command),title:l.label,children:M(l.icon,l.command)}):l.type==="input"?o.jsx("input",{type:"text",className:`rte-toolbar-input ${l.label.toLowerCase().replace(/\s+/g,"-")}`,placeholder:l.placeholder,onChange:k=>S(l.command,k.target.value),onKeyDown:k=>{k.key==="Enter"&&S(l.command,k.target.value)},title:l.label}):l.type==="group"?o.jsx("div",{className:`rte-toolbar-group-button ${l.label.toLowerCase().replace(/\s+/g,"-")}`,title:`${l.label}`,children:o.jsx("div",{className:`rte-toolbar-group-items ${l.label.toLowerCase().replace(/\s+/g,"-")}`,children:z(l.items||[])})}):o.jsx("button",{className:"rte-toolbar-button","data-command":l.command,"data-active":"false",onClick:()=>S(l.command),title:l.label,children:M(l.icon,l.command)})},E));return o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"rte-toolbar-wrapper",style:J,children:[o.jsxs("div",{className:"rte-toolbar",ref:x,children:[o.jsx("div",{className:"rte-toolbar-items-container",ref:y,children:z(v)}),d!==null&&d<v.length&&o.jsx("button",{ref:C,className:`rte-toolbar-more-button ${h?"active":""}`,onClick:()=>f(!h),title:"Show more options","aria-label":"More toolbar options",children:"☰"})]}),d!==null&&d<v.length&&o.jsx("div",{className:`rte-toolbar-expanded-row ${h?"show":""}`,children:v.map((n,l)=>l>=(d||0)&&o.jsx("div",{className:"rte-toolbar-item",children:n.type==="dropdown"?o.jsxs("div",{className:"rte-toolbar-dropdown",children:[o.jsxs("button",{className:"rte-toolbar-button","data-command":n.command,"data-active":"false",onClick:()=>R(n.command),children:[n.label," ▼"]}),i===n.command&&o.jsx("div",{className:"rte-toolbar-dropdown-menu",children:n.options?.map(E=>o.jsx("div",{className:"rte-toolbar-dropdown-item",onClick:()=>S(n.command,E.value),children:E.label},E.value))})]}):n.type==="inline-menu"?o.jsx("button",{ref:T(n.command),className:"rte-toolbar-button","data-command":n.command,"data-active":"false",onClick:()=>j(n.command),title:n.label,children:M(n.icon,n.command)}):n.type==="input"?o.jsx("input",{type:"text",className:"rte-toolbar-input",placeholder:n.placeholder,onChange:E=>S(n.command,E.target.value),onKeyDown:E=>{E.key==="Enter"&&S(n.command,E.target.value)},title:n.label}):o.jsx("button",{className:"rte-toolbar-button","data-command":n.command,"data-active":"false",onClick:()=>S(n.command),title:n.label,children:M(n.icon,n.command)})},l))})]}),v.map(n=>n.type==="inline-menu"?o.jsx(K,{isOpen:g===n.command,options:n.options||[],onSelect:l=>L(n.command,l),onClose:()=>m(null),anchorRef:T(n.command)},`menu-${n.command}`):null)]})};function Z(e,t){const u=c.useRef(),s=c.useRef("");return c.useEffect(()=>{if(!t?.enabled)return;const a=t.intervalMs||3e4,g=t.storageKey||"rte-autosave",m=t.provider||"localStorage",b=async()=>{const r=e();if(r!==s.current){if(s.current=r,m==="localStorage")try{localStorage.setItem(g,r),localStorage.setItem(`${g}-timestamp`,Date.now().toString()),console.log("[Autosave] Content saved to localStorage")}catch(d){console.error("[Autosave] Failed to save to localStorage:",d)}else if(m==="api"&&t.apiUrl)try{await fetch(t.apiUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:r,timestamp:Date.now()})}),console.log("[Autosave] Content saved to API")}catch(d){console.error("[Autosave] Failed to save to API:",d)}}};return u.current=setInterval(b,a),()=>{u.current&&clearInterval(u.current)}},[t?.enabled,t?.intervalMs,t?.storageKey,t?.provider,t?.apiUrl,e]),{restore:()=>{if(!t?.enabled)return null;const a=t.storageKey||"rte-autosave";if((t.provider||"localStorage")==="localStorage")try{const m=localStorage.getItem(a),b=localStorage.getItem(`${a}-timestamp`);if(m&&b)return console.log("[Autosave] Restored from localStorage, saved at:",new Date(parseInt(b))),m}catch(m){console.error("[Autosave] Failed to restore from localStorage:",m)}return null}}}const ee=["p","br","strong","em","u","s","b","i","h1","h2","h3","h4","h5","h6","ul","ol","li","a","img","video","audio","table","thead","tbody","tr","th","td","blockquote","pre","code","span","div","sup","sub","hr"],te={"*":["class","style","id","data-*"],a:["href","target","rel","title"],img:["src","alt","width","height","loading"],video:["src","controls","width","height","autoplay","loop","muted"],audio:["src","controls","autoplay","loop","muted"],table:["border","cellpadding","cellspacing"],td:["colspan","rowspan","align","valign"],th:["colspan","rowspan","align","valign"]};function P(e,t,u){if(t?.sanitize===!1)return e;const s=t?.allowedTags&&t.allowedTags.length>0?t.allowedTags:ee,i=t?.allowedAttributes||te,a=document.createElement("div");return a.innerHTML=e,$(a,s,i),a.innerHTML}function $(e,t,u){const s=Array.from(e.childNodes);for(const i of s)if(i.nodeType===Node.ELEMENT_NODE){const a=i,g=a.tagName.toLowerCase();if(!t.includes(g)){for(;a.firstChild;)e.insertBefore(a.firstChild,a);e.removeChild(a);continue}ne(a,u),$(a,t,u)}else{if(i.nodeType===Node.TEXT_NODE)continue;e.removeChild(i)}}function ne(e,t){const u=e.tagName.toLowerCase(),s=Array.from(e.attributes),i=t[u]||[],a=t["*"]||[],g=[...i,...a];for(const m of s){const b=m.name.toLowerCase();let r=!1;g.includes(b)&&(r=!0);for(const d of g)if(d.endsWith("*")){const w=d.slice(0,-1);if(b.startsWith(w)){r=!0;break}}(b.startsWith("on")||b==="javascript:"||b==="href"&&m.value.trim().toLowerCase().startsWith("javascript:")||b==="src"&&m.value.trim().toLowerCase().startsWith("javascript:"))&&(r=!1),r||e.removeAttribute(m.name)}e.hasAttribute("href")&&(e.getAttribute("href")||"").trim().toLowerCase().startsWith("javascript:")&&e.removeAttribute("href"),e.hasAttribute("src")&&(e.getAttribute("src")||"").trim().toLowerCase().startsWith("javascript:")&&e.removeAttribute("src")}function oe(e,t,u){return u?.sanitizeOnPaste===!1?e:P(e,t)}function re(e,t,u){return u?.sanitizeOnInput===!1?e:P(e,t)}const V=({editor:e,defaultValue:t,value:u,onChange:s,pasteConfig:i,contentConfig:a,securityConfig:g,performanceConfig:m,autosaveConfig:b})=>{const r=c.useRef(null),d=u!==void 0,w=c.useRef(),{restore:h}=Z(()=>r.current?.innerHTML||"",b);return c.useEffect(()=>{if(!r.current)return;const f=h(),p=f||u||t;p&&r.current.innerHTML!==p&&(r.current.innerHTML=p,f&&s&&s(f))},[]),c.useEffect(()=>{!r.current||!d||u!==r.current.innerHTML&&(r.current.innerHTML=u)},[u,d]),c.useEffect(()=>{if(!r.current)return;const f=()=>{if(!r.current||!s)return;let C=r.current.innerHTML;if(g?.sanitizeOnInput!==!1&&a?.sanitize!==!1&&(C=re(C,a,g),C!==r.current.innerHTML)){const v=window.getSelection(),T=v&&v.rangeCount>0?v.getRangeAt(0):null;if(r.current.innerHTML=C,T&&v)try{v.removeAllRanges(),v.addRange(T)}catch{}}m?.debounceInputMs?(w.current&&clearTimeout(w.current),w.current=setTimeout(()=>{s(C)},m.debounceInputMs)):s(C)},p=C=>{C.preventDefault();let v=C.clipboardData?.getData("text/html");const T=C.clipboardData?.getData("text/plain");if(i?.clean||!i?.keepFormatting){T&&document.execCommand("insertText",!1,T);return}if(v){g?.sanitizeOnPaste!==!1&&a?.sanitize!==!1&&(v=oe(v,a,g));const S=window.getSelection();if(S&&S.rangeCount>0){const R=S.getRangeAt(0);R.deleteContents();const j=document.createElement("div");j.innerHTML=v;const L=document.createDocumentFragment();for(;j.firstChild;)L.appendChild(j.firstChild);R.insertNode(L),R.collapse(!1),S.removeAllRanges(),S.addRange(R)}}else T&&document.execCommand("insertText",!1,T)},x=C=>{const v=C.target;(v.tagName==="IMG"||v.tagName==="VIDEO")&&(v.style.resize="both",v.style.overflow="auto",v.style.display="inline-block")},y=r.current;return y.addEventListener("input",f),y.addEventListener("paste",p),y.addEventListener("click",x),y.focus(),()=>{w.current&&clearTimeout(w.current),y.removeEventListener("input",f),y.removeEventListener("paste",p),y.removeEventListener("click",x)}},[e,s,i,a,g,m]),c.useEffect(()=>{if(!r.current||typeof window>"u")return;const f=new I.KeyboardShortcutManager,p=r.current,x=y=>{f.handleKeyDown(y,(C,v)=>{typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(C,v)})};return p.addEventListener("keydown",x),()=>{p.removeEventListener("keydown",x)}},[]),o.jsx("div",{ref:r,contentEditable:!0,suppressContentEditableWarning:!0,className:"rte-content",style:{minHeight:"200px",maxHeight:"100%",padding:"16px",outline:"none",border:"1px solid #ddd",borderRadius:"4px",fontSize:"14px",lineHeight:"1.5",overflow:"auto",flex:1,boxSizing:"border-box",wordWrap:"break-word",overflowWrap:"break-word"},children:o.jsx("p",{children:o.jsx("br",{})})})},ae=({editor:e,isEnabled:t})=>{const[u,s]=c.useState(!1),[i,a]=c.useState({top:0,left:0}),g=c.useRef(null),m=c.useRef(null),b=c.useRef(null),r=c.useRef(null);c.useEffect(()=>{if(!t){s(!1);return}r.current=g.current?.closest("[data-editora-editor]");const w=()=>{b.current&&clearTimeout(b.current);const f=window.getSelection();if(!f||f.rangeCount===0){s(!1),m.current=null;return}const p=f.getRangeAt(0),x=f.toString().trim(),y=r.current?.querySelector(".rte-content");if(!y||!y.contains(p.commonAncestorContainer)){s(!1),m.current=null;return}if(x.length>0){const C=p.getBoundingClientRect(),v=y.getBoundingClientRect(),T=300;if(C&&v){const S=C.top-50;let R=C.left+C.width/2;const j=T/2,L=v.left,M=v.right;R-j<L&&(R=L+j+10),R+j>M&&(R=M-j-10),a({top:S,left:R}),b.current=setTimeout(()=>{s(!0),m.current=p.cloneRange()},300)}}else s(!1),m.current=null},h=f=>{g.current&&!g.current.contains(f.target)&&(window.getSelection(),r.current?.querySelector(".rte-content")?.contains(f.target)||(s(!1),m.current=null))};return document.addEventListener("selectionchange",w),document.addEventListener("mousedown",h),document.addEventListener("keydown",f=>{f.key==="Escape"&&(s(!1),m.current=null)}),()=>{document.removeEventListener("selectionchange",w),document.removeEventListener("mousedown",h),b.current&&clearTimeout(b.current)}},[t]);const d=(w,h)=>{if(!m.current)return;const f=r.current?.querySelector(".rte-content");f&&f.focus(),{toggleBold:()=>document.execCommand("bold",!1),toggleItalic:()=>document.execCommand("italic",!1),toggleUnderline:()=>document.execCommand("underline",!1),toggleStrikethrough:()=>document.execCommand("strikeThrough",!1),createLink:()=>{typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand("openLinkDialog")},clearFormatting:()=>{document.execCommand("removeFormat",!1),document.execCommand("unlink",!1)},toggleCode:()=>{const x=window.getSelection();if(x&&x.rangeCount>0){const y=x.getRangeAt(0),C=document.createElement("code");y.surroundContents(C)}},setBlockType:()=>{if(h==="blockquote"){const x=window.getSelection();if(x&&x.rangeCount>0){const y=x.getRangeAt(0);(y.commonAncestorContainer.nodeType===Node.TEXT_NODE?y.commonAncestorContainer.parentElement:y.commonAncestorContainer)?.closest?.("blockquote")?document.execCommand("formatBlock",!1,"p"):document.execCommand("formatBlock",!1,"blockquote")}}else h&&document.execCommand("formatBlock",!1,h)}}[w]?.(),s(!1),m.current=null,f&&f.focus()};return!t||!u?null:o.jsxs("div",{ref:g,className:"floating-toolbar",style:{position:"fixed",top:`${i.top}px`,left:`${i.left}px`,transform:"translateX(-50%)",zIndex:1e3,background:"white",border:"1px solid #e1e5e9",borderRadius:"6px",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.15)",padding:"6px",display:"flex",gap:"4px",alignItems:"center"},children:[o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("toggleBold"),title:"Bold (Ctrl+B)",children:o.jsx("strong",{children:"B"})}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("toggleItalic"),title:"Italic (Ctrl+I)",children:o.jsx("em",{children:"I"})}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("toggleUnderline"),title:"Underline (Ctrl+U)",children:o.jsx("u",{children:"U"})}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("toggleStrikethrough"),title:"Strikethrough",children:o.jsx("s",{children:"S"})}),o.jsx("div",{className:"floating-toolbar-separator"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("clearFormatting"),title:"Clear Formatting",children:"⌫"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("createLink"),title:"Insert Link",children:"🔗"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("toggleCode"),title:"Code",children:"Code"}),o.jsx("div",{className:"floating-toolbar-separator"}),o.jsx("button",{className:"floating-toolbar-btn",onClick:()=>d("setBlockType","blockquote"),title:"Quote",children:"❝"})]})},le=({plugins:e,children:t})=>{const u=e.filter(i=>i.context?.provider);return u.length===0?o.jsx(o.Fragment,{children:t}):u.reduce((i,a)=>{const g=a.context.provider;return o.jsx(g,{children:i},a.name)},o.jsx(o.Fragment,{children:t}))},ie={toolbar:{items:[],floating:!1,sticky:!1},menubar:{enabled:!1,items:[]},contextMenu:{enabled:!0},media:{uploadUrl:"",libraryUrl:"",maxFileSize:10*1024*1024,allowedTypes:["image/jpeg","image/png","image/gif","image/webp"],headers:{},withCredentials:!1},paste:{clean:!0,keepFormatting:!1,convertWord:!0},history:{maxSteps:100,debounceMs:300},language:{locale:"en",direction:"ltr"},spellcheck:{enabled:!1,provider:"browser",apiUrl:"",apiHeaders:{}},autosave:{enabled:!1,intervalMs:3e4,storageKey:"rte-autosave",provider:"localStorage",apiUrl:""},accessibility:{enableARIA:!0,keyboardNavigation:!0,checker:!1},performance:{debounceInputMs:100,viewportOnlyScan:!0},content:{allowedTags:[],allowedAttributes:{},sanitize:!0},security:{sanitizeOnPaste:!0,sanitizeOnInput:!0}};function _(e,t){const u={...e};for(const s in t){const i=t[s],a=u[s];i!==void 0&&(typeof i=="object"&&i!==null&&!Array.isArray(i)&&typeof a=="object"&&a!==null&&!Array.isArray(a)?u[s]=_(a,i):u[s]=i)}return u}function G(e){const t=_(ie,{toolbar:e.toolbar,menubar:e.menubar,contextMenu:e.contextMenu,media:e.media,paste:e.paste,history:e.history,language:e.language,spellcheck:e.spellcheck,autosave:e.autosave,accessibility:e.accessibility,performance:e.performance,content:e.content,security:e.security});return e.floatingToolbar!==void 0&&(t.toolbar={...t.toolbar,floating:e.floatingToolbar.enabled??t.toolbar.floating}),e.mediaConfig&&(t.media={...t.media,uploadUrl:e.mediaConfig.uploadUrl||t.media.uploadUrl,libraryUrl:e.mediaConfig.libraryUrl||t.media.libraryUrl,maxFileSize:e.mediaConfig.maxFileSize||t.media.maxFileSize,allowedTypes:e.mediaConfig.allowedTypes||t.media.allowedTypes}),{...t,id:e.id,className:e.className,value:e.value,defaultValue:e.defaultValue,onChange:e.onChange,onInit:e.onInit,onDestroy:e.onDestroy,plugins:Array.isArray(e.plugins)?e.plugins.filter(s=>typeof s!="string"):[],pluginConfig:e.pluginConfig||{}}}const W=new Map;typeof window<"u"&&(window.registerEditorCommand=(e,t)=>{W.set(e,t)},window.executeEditorCommand=(e,t)=>{const u=W.get(e);return u?u(t):(console.warn(`No handler registered for command: ${e}`),!1)});const se=e=>{const t=c.useMemo(()=>G(e),[e.id,e.className,e.value,e.defaultValue,e.plugins,e.toolbar,e.menubar,e.contextMenu,e.media,e.paste,e.history,e.language,e.spellcheck,e.autosave,e.accessibility,e.performance,e.content,e.security,e.floatingToolbar,e.mediaConfig]),u=c.useRef(null),s=c.useRef(null),i=c.useRef(e.onInit),a=c.useRef(e.onDestroy),g=c.useRef(null);c.useEffect(()=>{i.current=e.onInit,a.current=e.onDestroy});const m=c.useMemo(()=>{const w=new I.PluginManager;t.plugins.forEach(f=>{w.register(f),f.commands&&typeof window<"u"&&Object.entries(f.commands).forEach(([p,x])=>{W.set(p,x)})});const h=new I.Editor(w);return u.current=h,h},[t.plugins]);c.useEffect(()=>{const w={getHTML:()=>g.current?.querySelector(".rte-content")?.innerHTML||"",setHTML:h=>{const f=g.current?.querySelector(".rte-content");f&&(f.innerHTML=h)},execCommand:(h,f)=>{typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(h,f)},registerCommand:(h,f)=>{typeof window<"u"&&window.registerEditorCommand&&window.registerEditorCommand(h,f)},focus:()=>{g.current?.querySelector(".rte-content")?.focus()},blur:()=>{g.current?.querySelector(".rte-content")?.blur()},destroy:()=>{a.current&&a.current()},onChange:h=>()=>{},getState:()=>({plugins:t.plugins,config:t}),toolbar:{items:m.toolbar?.items||[]}};return s.current=w,i.current&&i.current(w),()=>{a.current&&a.current()}},[]);const b=t.toolbar.floating??!1,r=t.toolbar.position||"top",d=t.toolbar.sticky??!1;return o.jsx(le,{plugins:t.plugins,children:o.jsxs("div",{ref:g,id:t.id,"data-editora-editor":!0,className:`rte-editor ${t.className||""}`,dir:t.language.direction,style:{display:"flex",flexDirection:"column",height:"100%"},children:[r!=="bottom"&&o.jsx(H,{editor:m,position:r,sticky:d,floating:b}),o.jsx(V,{editor:m,defaultValue:t.defaultValue,value:t.value,onChange:t.onChange,pasteConfig:t.paste,contentConfig:t.content,securityConfig:t.security,performanceConfig:t.performance,autosaveConfig:t.autosave}),r==="bottom"&&o.jsx(H,{editor:m,position:r,sticky:d,floating:b}),o.jsx(ae,{editor:m,isEnabled:b})]})})},X=e=>o.jsx(se,{...e});function ce(e={}){const t=c.useRef(null),u=c.useRef(e.onCommand);return c.useEffect(()=>{u.current=e.onCommand}),c.useEffect(()=>{if(typeof window>"u"||e.enabled===!1)return;const s=new I.KeyboardShortcutManager(e);t.current=s;const i=g=>s.handleKeyDown(g,(b,r)=>{u.current&&u.current(b,r),typeof window<"u"&&window.executeEditorCommand&&window.executeEditorCommand(b,r)}),a=e.editorElement||document;return a&&a.addEventListener("keydown",i),()=>{a&&a.removeEventListener("keydown",i)}},[e.editorElement,e.enabled,e.shortcuts,e.customShortcuts]),{getShortcuts:()=>t.current?.getAllShortcuts()||[],getShortcutForCommand:s=>t.current?.getShortcutForCommand(s),getShortcutsHelp:()=>t.current?.getShortcutsHelp()||"",enable:()=>t.current?.enable(),disable:()=>t.current?.disable(),isEnabled:()=>t.current?.isEnabled()||!1}}exports.EditorContent=V;exports.EditoraEditor=X;exports.InlineMenu=K;exports.RichTextEditor=X;exports.Toolbar=H;exports.mergeConfig=G;exports.useKeyboardShortcuts=ce;
|