@abduljebar/text-editor 2.3.2 → 2.4.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 CHANGED
@@ -1,8 +1,3 @@
1
- ```tsx
2
- import '@abduljebar/text-editor/dist/index.css';
3
- import { TextEditor } from "@abduljebar/text-editor";
4
- ```
5
-
6
1
  # @abduljebar/text-editor
7
2
 
8
3
  A modern, feature-rich React text editor component with beautiful styling and extensive customization options. Perfect for blogs, content management systems, and any application requiring rich text editing capabilities.
@@ -11,18 +6,27 @@ A modern, feature-rich React text editor component with beautiful styling and ex
11
6
 
12
7
  ### 🎨 Rich Text Editing
13
8
  - **Text Formatting**: Bold, italic, underline, strikethrough
14
- - **Color Support**: 20 text colors & 25 background colors with intuitive pickers
15
- - **Headings**: H1, H2, H3 with automatic styling
9
+ - **Headings**: H1, H2 with automatic styling
16
10
  - **Lists**: Bulleted and numbered lists
17
- - **Block Elements**: Quotes and code blocks with syntax styling
11
+ - **Alignment**: Left, center, right alignment
12
+ - **Block Elements**: Quotes and code blocks
18
13
  - **Undo/Redo**: Full history support
14
+ - **Additional Formatting**: Superscript, subscript, indentation
15
+
16
+ ### 📁 File Management
17
+ - **Image Upload**: Drag & drop, paste, or file picker
18
+ - **Image Validation**: File type and size validation
19
+ - **Pending Images**: Track and upload pending images
20
+ - **HTML Export**: Generate complete HTML documents with styling
21
+ - **Auto-save**: Debounced content changes with configurable delay
19
22
 
20
23
  ### 🎯 Smart UX
21
- - **Auto-styling**: Automatic application of beautiful Tailwind CSS styles
22
24
  - **Contextual Toolbar**: Appears only when focused and editable
23
25
  - **Real-time Stats**: Word and character count in status bar
24
26
  - **Smart Format Detection**: Visual indicators for active text formats
25
- - **Tab Support**: Indentation with Tab key
27
+ - **Keyboard Shortcuts**: Ctrl+S (save), Ctrl+E (export)
28
+ - **Auto-focus**: Automatic focus on load
29
+ - **Placeholder Support**: Visual placeholder when empty
26
30
 
27
31
  ### 🔧 Flexible Configuration
28
32
  - **Read-only Mode**: Display content without editing capabilities
@@ -30,13 +34,15 @@ A modern, feature-rich React text editor component with beautiful styling and ex
30
34
  - **Title Support**: Optional document title with real-time updates
31
35
  - **Action Buttons**: Built-in save and export functionality
32
36
  - **Event Handling**: Comprehensive callback system
37
+ - **Debounce Control**: Configurable change debouncing
33
38
 
34
39
  ### 🚀 Advanced Features
35
40
  - **React Hook**: `useTextEditor` for custom implementations
36
- - **HTML Export**: Generate complete HTML documents
37
- - **Validation**: Built-in content validation
38
- - **State Management**: Full control over editor state
41
+ - **Ref API**: Exposed methods for programmatic control
42
+ - **Selection Management**: Proper cursor and selection handling
43
+ - **Paste/Upload Handling**: Smart image and content paste handling
39
44
  - **TypeScript**: Fully typed for better development experience
45
+ - **Validation**: Built-in content validation
40
46
 
41
47
  ## 📦 Installation
42
48
 
@@ -57,7 +63,7 @@ import { TextEditor } from "@abduljebar/text-editor";
57
63
  function App() {
58
64
  return (
59
65
  <TextEditor
60
- height="min-h-[400px]"
66
+ height="500px"
61
67
  onChange={(content, html, title) => {
62
68
  console.log("Content:", content);
63
69
  console.log("HTML:", html);
@@ -126,6 +132,38 @@ function ReadOnlyView() {
126
132
  }
127
133
  ```
128
134
 
135
+ ### With Image Upload
136
+
137
+ ```tsx
138
+ import '@abduljebar/text-editor/dist/index.css';
139
+ import { TextEditor } from "@abduljebar/text-editor";
140
+
141
+ function EditorWithImages() {
142
+ const handleImageUpload = async (file: File) => {
143
+ // Upload to your backend
144
+ const formData = new FormData();
145
+ formData.append('image', file);
146
+
147
+ const response = await fetch('/api/upload', {
148
+ method: 'POST',
149
+ body: formData,
150
+ });
151
+
152
+ const data = await response.json();
153
+ return data.url; // Return the uploaded image URL
154
+ };
155
+
156
+ return (
157
+ <TextEditor
158
+ showButtons={true}
159
+ onImageUpload={handleImageUpload}
160
+ allowedImageTypes={['image/jpeg', 'image/png', 'image/webp']}
161
+ maxImageSize={10 * 1024 * 1024} // 10MB
162
+ />
163
+ );
164
+ }
165
+ ```
166
+
129
167
  ## ⚙️ API Reference
130
168
 
131
169
  ### TextEditor Props
@@ -136,11 +174,62 @@ function ReadOnlyView() {
136
174
  | `onChange` | `(content: string, html: string, title?: string) => void` | `undefined` | Callback when content changes |
137
175
  | `onSave` | `(content: string, html: string) => void` | `undefined` | Callback when save is triggered |
138
176
  | `onExport` | `(html: string) => void` | `undefined` | Callback when export is triggered |
177
+ | `onImageUpload` | `(file: File) => Promise<string>` | `undefined` | Custom image upload handler |
178
+ | `imageUploadEndpoint` | `string` | `undefined` | Endpoint for default image upload |
139
179
  | `readOnly` | `boolean` | `false` | Disable editing when true |
140
180
  | `showButtons` | `boolean` | `false` | Show save/export buttons |
141
181
  | `showSaveTitle` | `boolean` | `false` | Show document title input |
142
182
  | `showStatusBar` | `boolean` | `false` | Show word/character count |
143
183
  | `height` | `string` | `"500px"` | Editor height (any CSS value) |
184
+ | `allowedImageTypes` | `string[]` | `["image/jpeg","image/png","image/gif","image/webp"]` | Allowed image MIME types |
185
+ | `maxImageSize` | `number` | `5242880` (5MB) | Maximum image size in bytes |
186
+ | `debounceDelay` | `number` | `300` | Debounce delay for onChange in ms |
187
+ | `className` | `string` | `""` | Additional CSS class name |
188
+ | `placeholder` | `string` | `"Start typing here..."` | Placeholder text when empty |
189
+ | `autoFocus` | `boolean` | `false` | Auto-focus editor on load |
190
+ | `onInit` | `(editor: HTMLDivElement) => void` | `undefined` | Callback after editor initialization |
191
+
192
+ ### TextEditor Ref API
193
+
194
+ The component exposes a ref with the following methods:
195
+
196
+ ```typescript
197
+ interface TextEditorRef {
198
+ getContent: () => string;
199
+ getHTML: () => string;
200
+ getTitle: () => string;
201
+ clear: () => void;
202
+ focus: () => void;
203
+ insertText: (text: string) => void;
204
+ insertHTML: (html: string) => void;
205
+ executeCommand: (command: string, value?: string) => void;
206
+ }
207
+ ```
208
+
209
+ Example usage:
210
+ ```tsx
211
+ import { useRef } from 'react';
212
+ import { TextEditor, TextEditorRef } from "@abduljebar/text-editor";
213
+
214
+ function EditorWithRef() {
215
+ const editorRef = useRef<TextEditorRef>(null);
216
+
217
+ const handleGetContent = () => {
218
+ if (editorRef.current) {
219
+ const content = editorRef.current.getContent();
220
+ const html = editorRef.current.getHTML();
221
+ console.log({ content, html });
222
+ }
223
+ };
224
+
225
+ return (
226
+ <>
227
+ <TextEditor ref={editorRef} />
228
+ <button onClick={handleGetContent}>Get Content</button>
229
+ </>
230
+ );
231
+ }
232
+ ```
144
233
 
145
234
  ### useTextEditor Hook
146
235
 
@@ -160,12 +249,20 @@ function CustomEditor() {
160
249
  getValidationResult,
161
250
  exportToHTML,
162
251
  clearEditor,
163
- resetToInitial,
164
- activeFormats,
165
- isLinkActive,
166
- } = useTextEditor("Initial content", false);
252
+ handlePaste,
253
+ handleDrop,
254
+ insertImage,
255
+ uploadPendingImages,
256
+ } = useTextEditor({
257
+ initialContent: "Initial content",
258
+ onImageUpload: async (file) => {
259
+ // Custom upload logic
260
+ return "https://example.com/image.jpg";
261
+ },
262
+ allowedImageTypes: ["image/jpeg", "image/png"],
263
+ maxImageSize: 10 * 1024 * 1024,
264
+ });
167
265
 
168
- // Use the state and methods to build custom UI
169
266
  return (
170
267
  <div>
171
268
  <div
@@ -173,43 +270,60 @@ function CustomEditor() {
173
270
  contentEditable
174
271
  onInput={(e) => updateContent(e.currentTarget.innerHTML)}
175
272
  className="border p-4 min-h-[200px]"
273
+ onPaste={handlePaste}
274
+ onDrop={handleDrop}
176
275
  />
177
276
  <button onClick={() => executeCommand('bold')}>
178
277
  Bold
179
278
  </button>
279
+ <button onClick={() => insertImage(someFile)}>
280
+ Insert Image
281
+ </button>
180
282
  </div>
181
283
  );
182
284
  }
183
285
  ```
184
286
 
287
+ #### Hook Parameters
288
+
289
+ | Parameter | Type | Default | Description |
290
+ |-----------|------|---------|-------------|
291
+ | `initialContent` | `string` | `""` | Initial HTML content |
292
+ | `onImageUpload` | `(file: File) => Promise<string>` | `undefined` | Custom image upload handler |
293
+ | `imageUploadEndpoint` | `string` | `undefined` | Endpoint for default image upload |
294
+ | `allowedImageTypes` | `string[]` | `["image/jpeg","image/png","image/gif","image/webp"]` | Allowed image types |
295
+ | `maxImageSize` | `number` | `5242880` | Max image size in bytes |
296
+
185
297
  #### Hook Return Values
186
298
 
187
299
  | Property | Type | Description |
188
300
  |----------|------|-------------|
189
- | `editorState` | `object` | Current editor state (content, title, counts) |
190
- | `editorRef` | `RefObject` | Reference to the editable element |
301
+ | `editorState` | `object` | Current editor state with content, title, counts, pending images |
302
+ | `editorRef` | `RefObject<HTMLDivElement>` | Reference to the editable element |
191
303
  | `updateContent` | `(content: string) => void` | Update editor content |
192
304
  | `updateTitle` | `(title: string) => void` | Update document title |
193
305
  | `executeCommand` | `(command: string, value?: string) => void` | Execute formatting commands |
194
306
  | `getValidationResult` | `() => ValidationResult` | Validate and get editor data |
195
307
  | `exportToHTML` | `(options?) => string` | Generate HTML export |
196
308
  | `clearEditor` | `() => void` | Clear all content |
197
- | `resetToInitial` | `() => void` | Reset to initial content |
198
- | `activeFormats` | `object` | Current active text formats |
199
- | `isLinkActive` | `boolean` | Whether a link is currently selected |
309
+ | `handlePaste` | `(e: React.ClipboardEvent) => void` | Handle paste events |
310
+ | `handleDrop` | `(e: React.DragEvent) => void` | Handle drop events |
311
+ | `insertImage` | `(file: File, atCursor?: boolean) => Promise<void>` | Insert image into editor |
312
+ | `uploadPendingImages` | `() => Promise<void>` | Upload all pending images |
200
313
 
201
314
  ## 🎨 Styling & Customization
202
315
 
203
316
  ### Default Styling
204
317
 
205
- The editor comes with beautiful default styling using Tailwind CSS classes:
318
+ The editor comes with beautiful default styling:
206
319
 
207
- - **Headings**: Proper hierarchy with borders and spacing
320
+ - **Headings**: Proper hierarchy with appropriate sizing
208
321
  - **Paragraphs**: Optimal line height and margins
209
322
  - **Lists**: Clean indentation and spacing
210
- - **Code Blocks**: Dark theme with proper monospace fonts
323
+ - **Code Blocks**: Proper monospace fonts
211
324
  - **Quotes**: Elegant bordered design
212
- - **Links**: Blue color with hover effects
325
+ - **Links**: Proper styling with hover effects
326
+ - **Images**: Responsive with rounded corners
213
327
 
214
328
  ### Custom Styling
215
329
 
@@ -220,18 +334,25 @@ import '@abduljebar/text-editor/dist/index.css';
220
334
  import { TextEditor } from "@abduljebar/text-editor";
221
335
 
222
336
  <TextEditor
223
- className="custom-editor-styles"
337
+ className="my-custom-editor"
224
338
  // ... other props
225
339
  />
226
340
  ```
227
341
 
228
342
  ```css
229
- .custom-editor-styles {
230
- /* Your custom styles */
343
+ .my-custom-editor {
344
+ border: 2px solid #4f46e5;
345
+ border-radius: 12px;
346
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
347
+ }
348
+
349
+ .my-custom-editor h1 {
350
+ color: #4f46e5;
351
+ border-bottom: 2px solid #e0e7ff;
231
352
  }
232
353
 
233
- .custom-editor-styles h1 {
234
- /* Custom heading styles */
354
+ .my-custom-editor .toolbar {
355
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
235
356
  }
236
357
  ```
237
358
 
@@ -275,24 +396,25 @@ import '@abduljebar/text-editor/dist/index.css';
275
396
  import { useTextEditor } from "@abduljebar/text-editor";
276
397
 
277
398
  function CustomToolbarEditor() {
278
- const { executeCommand, activeFormats, editorRef } = useTextEditor();
399
+ const { executeCommand, editorRef, insertImage } = useTextEditor({
400
+ initialContent: "Start typing...",
401
+ });
402
+
403
+ const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
404
+ const file = e.target.files?.[0];
405
+ if (file) {
406
+ insertImage(file);
407
+ }
408
+ };
279
409
 
280
410
  return (
281
411
  <div className="editor-container">
282
412
  <div className="custom-toolbar">
283
- <button
284
- onClick={() => executeCommand('bold')}
285
- className={activeFormats.bold ? 'active' : ''}
286
- >
287
- B
288
- </button>
289
- <button
290
- onClick={() => executeCommand('italic')}
291
- className={activeFormats.italic ? 'active' : ''}
292
- >
293
- I
294
- </button>
295
- {/* Add more custom buttons */}
413
+ <button onClick={() => executeCommand('bold')}>Bold</button>
414
+ <button onClick={() => executeCommand('italic')}>Italic</button>
415
+ <button onClick={() => executeCommand('formatBlock', 'h1')}>H1</button>
416
+ <button onClick={() => executeCommand('formatBlock', 'h2')}>H2</button>
417
+ <input type="file" accept="image/*" onChange={handleFileSelect} />
296
418
  </div>
297
419
  <div
298
420
  ref={editorRef}
@@ -304,17 +426,44 @@ function CustomToolbarEditor() {
304
426
  }
305
427
  ```
306
428
 
307
- ## 🌈 Color Palettes
429
+ ### Programmatic Control
308
430
 
309
- ### Text Colors (20 colors)
310
- - Basic: Black, White
311
- - Primary: Red, Green, Blue
312
- - Secondary: Yellow, Magenta, Cyan, Orange, Purple
313
- - Additional: Dark Green, Maroon, Teal, Navy, Gray, Brown, Pink, Gold, Light Green, Light Blue
431
+ ```tsx
432
+ import { useRef, useEffect } from 'react';
433
+ import { TextEditor, TextEditorRef } from "@abduljebar/text-editor";
434
+
435
+ function ProgrammaticEditor() {
436
+ const editorRef = useRef<TextEditorRef>(null);
437
+
438
+ useEffect(() => {
439
+ // Example: Auto-insert content after 2 seconds
440
+ const timer = setTimeout(() => {
441
+ if (editorRef.current) {
442
+ editorRef.current.insertText("Hello, world!");
443
+ editorRef.current.focus();
444
+ }
445
+ }, 2000);
446
+
447
+ return () => clearTimeout(timer);
448
+ }, []);
449
+
450
+ const handleCommand = (command: string) => {
451
+ if (editorRef.current) {
452
+ editorRef.current.executeCommand(command);
453
+ }
454
+ };
314
455
 
315
- ### Background Colors (25 colors)
316
- - Same as text colors plus light variants
317
- - Light variants: Misty Rose, Honeydew, Alice Blue, Lemon Chiffon, White Smoke, Lavender, and more
456
+ return (
457
+ <div>
458
+ <TextEditor ref={editorRef} />
459
+ <div className="mt-4">
460
+ <button onClick={() => handleCommand('bold')}>Make Selection Bold</button>
461
+ <button onClick={() => editorRef.current?.clear()}>Clear Editor</button>
462
+ </div>
463
+ </div>
464
+ );
465
+ }
466
+ ```
318
467
 
319
468
  ## 📋 Browser Support
320
469
 
@@ -322,6 +471,7 @@ function CustomToolbarEditor() {
322
471
  - Firefox 55+
323
472
  - Safari 12+
324
473
  - Edge 79+
474
+ - Opera 47+
325
475
 
326
476
  ## 🔒 Accessibility
327
477
 
@@ -329,25 +479,48 @@ function CustomToolbarEditor() {
329
479
  - ARIA labels for toolbar buttons
330
480
  - Focus management
331
481
  - Screen reader compatible
482
+ - Proper semantic HTML structure
332
483
 
333
484
  ## 🐛 Troubleshooting
334
485
 
335
486
  ### Common Issues
336
487
 
337
- 1. **Content not updating**: Ensure you're using the `onChange` callback properly
338
- 2. **Styles not applying**: Make sure Tailwind CSS is properly configured in your project
339
- 3. **Toolbar not appearing**: Check that `readOnly` is set to `false` and the editor is focused
488
+ 1. **Toolbar buttons not working**: Ensure the editor is focused and content is selected
489
+ 2. **Images not uploading**: Check CORS settings and upload endpoint configuration
490
+ 3. **Styles not appearing**: Import the CSS file: `import '@abduljebar/text-editor/dist/index.css';`
491
+ 4. **Content not saving**: Check `onSave` callback and validation messages
492
+ 5. **Formatting lost on paste**: Use the built-in `handlePaste` function
340
493
 
341
494
  ### Performance Tips
342
495
 
343
- - Use `React.memo` if embedding in frequently re-rendering components
344
- - Debounce `onChange` callbacks for heavy operations
345
- - Consider using the hook version for complex custom implementations
496
+ - Use appropriate `debounceDelay` for `onChange` to prevent excessive updates
497
+ - Implement proper image compression before upload
498
+ - Consider using `React.memo` if embedding in frequently re-rendering components
499
+ - Use the ref API for programmatic control instead of frequent state updates
500
+
501
+ ## 📄 Supported Commands
502
+
503
+ The editor supports standard `document.execCommand` APIs:
504
+
505
+ - **Formatting**: `bold`, `italic`, `underline`, `strikeThrough`
506
+ - **Headings**: `formatBlock` (with `h1`, `h2`, `h3`, `p` values)
507
+ - **Lists**: `insertUnorderedList`, `insertOrderedList`
508
+ - **Alignment**: `justifyLeft`, `justifyCenter`, `justifyRight`
509
+ - **Indentation**: `indent`, `outdent`
510
+ - **Links**: `createLink` (with URL value)
511
+ - **History**: `undo`, `redo`
512
+ - **Special**: `superscript`, `subscript`, `formatBlock` (with `blockquote`, `pre` values)
346
513
 
347
514
  ## 🤝 Contributing
348
515
 
349
516
  We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
350
517
 
518
+ 1. Fork the repository
519
+ 2. Create a feature branch
520
+ 3. Make your changes
521
+ 4. Add tests if applicable
522
+ 5. Submit a pull request
523
+
351
524
  ## 📄 License
352
525
 
353
526
  MIT License - see the [LICENSE](LICENSE) file for details.
@@ -356,18 +529,37 @@ MIT License - see the [LICENSE](LICENSE) file for details.
356
529
 
357
530
  If you encounter any issues or have questions:
358
531
 
359
- 1. Check the [documentation](#)
360
- 2. Search [existing issues](https://github.com/abduljebar/text-editor/issues)
361
- 3. Create a [new issue](https://github.com/abduljebar/text-editor/issues/new)
532
+ 1. Check the documentation above
533
+ 2. Search existing GitHub issues
534
+ 3. Create a new issue with:
535
+ - A clear description of the problem
536
+ - Steps to reproduce
537
+ - Expected vs actual behavior
538
+ - Code examples if applicable
362
539
 
363
540
  ## 🚀 Changelog
364
541
 
542
+ ### v1.1.0
543
+ - Added image upload support with drag & drop
544
+ - Improved toolbar with better selection tracking
545
+ - Added ref API for programmatic control
546
+ - Enhanced keyboard shortcuts
547
+ - Better validation and error handling
548
+ - Added pending images tracking
549
+
365
550
  ### v1.0.0
366
551
  - Initial release with core editing features
367
- - Comprehensive text formatting options
368
- - Color support and styling system
552
+ - Basic text formatting and styling
553
+ - HTML export functionality
369
554
  - React hook for advanced usage
370
555
 
371
556
  ---
372
557
 
373
- Built with ❤️ by [AbdulJebar Sani](https://github.com/abduljebar49)
558
+ Built with ❤️ by [AbdulJebar Sani](https://github.com/abduljebar49)
559
+
560
+ ## 🔗 Links
561
+
562
+ - [GitHub Repository](https://github.com/abduljebar/text-editor)
563
+ - [npm Package](https://www.npmjs.com/package/@abduljebar/text-editor)
564
+ - [Issue Tracker](https://github.com/abduljebar/text-editor/issues)
565
+ - [Documentation](https://github.com/abduljebar/text-editor#readme)
@@ -15,7 +15,20 @@ interface TextEditorProps {
15
15
  maxImageSize?: number;
16
16
  onInit?: (editor: HTMLDivElement) => void;
17
17
  debounceDelay?: number;
18
+ className?: string;
19
+ placeholder?: string;
20
+ autoFocus?: boolean;
18
21
  }
19
- export declare const TextEditor: React.ForwardRefExoticComponent<TextEditorProps & React.RefAttributes<HTMLDivElement>>;
22
+ export interface TextEditorRef {
23
+ getContent: () => string;
24
+ getHTML: () => string;
25
+ getTitle: () => string;
26
+ clear: () => void;
27
+ focus: () => void;
28
+ insertText: (text: string) => void;
29
+ insertHTML: (html: string) => void;
30
+ executeCommand: (command: string, value?: string) => void;
31
+ }
32
+ export declare const TextEditor: React.ForwardRefExoticComponent<TextEditorProps & React.RefAttributes<TextEditorRef>>;
20
33
  export default TextEditor;
21
34
  //# sourceMappingURL=TextEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextEditor.d.ts","sourceRoot":"","sources":["../../src/components/TextEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAMN,MAAM,OAAO,CAAC;AAQf,UAAU,eAAe;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,UAAU,wFAiQtB,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"TextEditor.d.ts","sourceRoot":"","sources":["../../src/components/TextEditor.tsx"],"names":[],"mappings":"AACA,OAAO,KAON,MAAM,OAAO,CAAC;AAQf,UAAU,eAAe;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED,eAAO,MAAM,UAAU,uFAqetB,CAAC;AAIF,eAAe,UAAU,CAAC"}
@@ -9,6 +9,23 @@ interface ToolbarProps {
9
9
  hasUnsavedChanges: boolean;
10
10
  pendingImagesCount?: number;
11
11
  }
12
+ interface ToolbarButtonBase {
13
+ id: string;
14
+ }
15
+ interface ToolbarActionButton extends ToolbarButtonBase {
16
+ separator?: false;
17
+ command?: string;
18
+ value?: string;
19
+ icon: React.ReactNode;
20
+ title: string;
21
+ onClick?: () => void;
22
+ isActive?: boolean;
23
+ disabled?: boolean;
24
+ }
25
+ interface ToolbarSeparator extends ToolbarButtonBase {
26
+ separator: true;
27
+ }
28
+ export type ToolbarButton = ToolbarActionButton | ToolbarSeparator;
12
29
  export declare const Toolbar: React.FC<ToolbarProps>;
13
30
  export {};
14
31
  //# sourceMappingURL=Toolbar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AACA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAqBnD,UAAU,YAAY;IACpB,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CA0Q1C,CAAC"}
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../src/components/Toolbar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAmD,MAAM,OAAO,CAAC;AA6BxE,UAAU,YAAY;IACpB,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,UAAU,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,mBAAoB,SAAQ,iBAAiB;IACrD,SAAS,CAAC,EAAE,KAAK,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,gBAAiB,SAAQ,iBAAiB;IAClD,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAEnE,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAgf1C,CAAC"}
@@ -15,21 +15,23 @@ interface EditorContent {
15
15
  characterCount: number;
16
16
  };
17
17
  }
18
+ interface PendingImage {
19
+ id: string;
20
+ file: File;
21
+ placeholderUrl: string;
22
+ status: 'pending' | 'uploading' | 'uploaded' | 'failed';
23
+ }
24
+ interface EditorState {
25
+ content: string;
26
+ title: string;
27
+ wordCount: number;
28
+ characterCount: number;
29
+ hasUnsavedChanges: boolean;
30
+ pendingImages: PendingImage[];
31
+ }
18
32
  export declare const useTextEditor: ({ initialContent, onImageUpload, imageUploadEndpoint, allowedImageTypes, maxImageSize, }: UseTextEditorProps) => {
19
- editorState: {
20
- content: string;
21
- title: string;
22
- wordCount: number;
23
- characterCount: number;
24
- hasUnsavedChanges: boolean;
25
- pendingImages: Array<{
26
- id: string;
27
- file: File;
28
- placeholderUrl: string;
29
- status: "pending" | "uploading" | "uploaded" | "failed";
30
- }>;
31
- };
32
- editorRef: any;
33
+ editorState: EditorState;
34
+ editorRef: import("react").RefObject<HTMLDivElement | null>;
33
35
  updateContent: (content: string) => void;
34
36
  updateTitle: (title: string) => void;
35
37
  executeCommand: (command: string, value?: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useTextEditor.d.ts","sourceRoot":"","sources":["../../src/hooks/useTextEditor.ts"],"names":[],"mappings":"AAGA,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,eAAO,MAAM,aAAa,GAAI,0FAM3B,kBAAkB;;;;;;;uBAOI,KAAK,CAAC;YACzB,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,EAAE,IAAI,CAAC;YACX,cAAc,EAAE,MAAM,CAAC;YACvB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;SACzD,CAAC;;;6BAiCwC,MAAM;yBAeV,MAAM;8BAQD,MAAM,UAAU,MAAM;+BA0OvB;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,aAAa,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;qBAlClE,KAAK,CAAC,cAAc;oBAuBrB,KAAK,CAAC,SAAS;wBAjML,IAAI,aAAY,OAAO;;CAsUrE,CAAC"}
1
+ {"version":3,"file":"useTextEditor.d.ts","sourceRoot":"","sources":["../../src/hooks/useTextEditor.ts"],"names":[],"mappings":"AAGA,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC;CACzD;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,eAAO,MAAM,aAAa,GAAI,0FAM3B,kBAAkB;;;6BAqFyB,MAAM;yBAeV,MAAM;8BAQD,MAAM,UAAU,MAAM;+BA6TvB;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,aAAa,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;qBA1DlE,KAAK,CAAC,cAAc;oBA4BrB,KAAK,CAAC,SAAS;wBAzML,IAAI,aAAY,OAAO;;CAyWrE,CAAC"}