@flogeez/angular-tiptap-editor 0.5.4 → 2.0.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/CHANGELOG.md CHANGED
@@ -5,6 +5,67 @@ All notable changes to `@flogeez/angular-tiptap-editor` will be documented in th
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.0] - 2026-01-17
9
+
10
+ ### Added
11
+ - **Extensible I18n**: The translation system is now open. You can add any language (e.g., `es`, `it`) via `addTranslations()`, and the `SupportedLocale` type now accepts any string with autocomplete for default languages.
12
+ - **Per-Instance I18n Override**: Added ability to define a specific language for a given editor instance via the `[locale]` input, without affecting the global language of other editors.
13
+ - **Global I18n Singleton**: The translation service is now a global singleton (`providedIn: 'root'`), allowing for application-wide language switching with a single call.
14
+ - **Seamless Mode**: Added `[seamless]` input to remove borders, backgrounds, and paddings.
15
+ - **Floating Toolbar**: Added `[floatingToolbar]` option for a sticky, auto-hiding toolbar with glassmorphism that only appears on focus or hover.
16
+ - **Improved Read-Only**: Refined the `[editable]="false"` behavior. Clicking in the empty space of a read-only editor no longer forces focus or moves the cursor. The toolbar and footer now correctly reflect the read-only state.
17
+ - **Code Block Support**: Added dedicated `CodeBlock` button to the toolbar and slash commands.
18
+ - **Precise Inline Code**: Separated "Inline Code" and "Code Block" in menus and translations for better clarity.
19
+
20
+ ### Fixed
21
+ - **Inline Code Toggle**: Fixed a reactivity bug where the "Code" button in the toolbar became disabled when already inside a code mark, preventing it from being toggled off.
22
+
23
+ ### Changed
24
+ - **Service Isolation**: `EditorCommandsService`, `LinkService`, `ColorPickerService`, and `ImageService` are no longer global (`root`). They are now provided at the component level for each editor instance, ensuring perfect isolation in multi-editor scenarios.
25
+ - **Internal Refactoring**: Systemic use of `currentTranslations` (computed signal) across all internal components for perfect reactivity to language changes.
26
+
27
+ ### Breaking Changes
28
+ - **Service Injection**: If you were injecting `EditorCommandsService` (or other internal services) directly into your own global services/components, it will no longer work. You must now interact with the editor via its public API (`@ViewChild`).
29
+
30
+ ## [0.6.0] - 2026-01-14
31
+
32
+ ### Added
33
+ - **Reactive State Management**: New "Snapshot & Signal" architecture with optimized change detection (OnPush).
34
+ - **Custom Extension Tracking**: Automatic state tracking for custom Tiptap Marks and Nodes (zero-config).
35
+ - **Extensible State**: New `stateCalculators` input to inject custom logic into the reactive editor state.
36
+ - **Intelligent Color Detection**: The editor state now computes the actual visible text and background colors by inspecting the DOM (computed styles). This ensures the color picker accurately reflects the current formatting even when derived from CSS themes or inherited from parent elements.
37
+ - **Link & Color Bubble Menus**: Completely refactored management with dedicated bubble menus.
38
+ - **LinkService**: New dedicated service to manage link state and lifecycle independently.
39
+ - **Improved Visual Feedback**: Menus now preserve the editor's blue selection highlight while choosing colors or preparing to type a link.
40
+ - **Improved Image Selection**: Automatic node selection after insertion or replacement, ensuring resize handles and bubble menus appear instantly.
41
+ - **Danger Button Variant**: New `danger` variant for actions like "Reset Color" or "Remove Link", providing clear visual feedback for destructive operations.
42
+
43
+ ### Fixed
44
+ - **Multi-instance Support**: Full service isolation, allowing multiple editors on the same page without shared state.
45
+ - **Bubble Menu Conflicts**: Fixed overlapping menus by implementing a strict priority system (specialized menus now hide the main text menu).
46
+ - **Image Bubble Menu Persistence**: Corrected Tippy.js behavior to prevent menus from disappearing when re-clicking an already-selected image.
47
+ - **Toolbar-Menu Harmony**: Bubbles now reactively hide when interacting with the main toolbar via a centralized signal.
48
+ - **Anti-Echo Loop**: Implemented a robust "lastEmittedHtml" logic combined with `untracked()` to prevent infinite loops and cursor reset when using two-way binding or FormControls.
49
+ - **Atomic Image Replacement**: Refactored image service to perform atomic updates, fixing the "extra space" bug and preventing layout shifts during asynchronous uploads.
50
+
51
+ ### Changed
52
+ - **Architectural Refactoring**: `EditorCommandsService` is now a clean facade/proxy for specialized services (`ImageService`, `ColorPickerService`, `LinkService`).
53
+ - **Optimized State Performance**: Refactored state calculators (notably `MarksCalculator`) to minimize DOM access and avoid unnecessary layout recalculations (reflow).
54
+ - **Centralized Color Utilities**: Consolidated color normalization, luminance, and contrast calculations into a shared utility for perfect consistency.
55
+ - **Public API Cleanup**: Exported all modular calculators, services, and models for better extensibility.
56
+ - **Color Picker Stability**: Integrated selection capture and locked modes to ensure 100% reliability in color application.
57
+
58
+ ## [0.5.5] - 2026-01-09
59
+
60
+ ### Added
61
+ - **Bubble Menus Confinement**: Menus now properly respect the editor's boundaries and are clipped by the container when scrolling, specifically optimized for `fillContainer` mode.
62
+ - **Unified Command Execution**: Centralized all editor operations within `EditorCommandsService`, ensuring consistent behavior between the toolbar and bubble menus.
63
+
64
+ ### Fixed
65
+ - **Bubble Menus Positionning**: Refactored positioning logic for all bubble menus (Text, Image, Table, Cell, Slash) using Tippy's `sticky` plugin for real-time tracking during resizing and scrolling.
66
+ - **Bubble Menus Performances**: Significant performance boost in `getImageRect` and `getTableRect` using direct ProseMirror DOM lookups.
67
+ - **Performance Optimization**: Implemented `ChangeDetectionStrategy.OnPush` across all library components to minimize change detection cycles. Improved resource management by enabling Tippy's sticky polling only while menus are visible.
68
+
8
69
  ## [0.5.4] - 2026-01-08
9
70
 
10
71
  ### Added
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 FloGeez
3
+ Copyright (c) 2026 FloGeez
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -6,19 +6,35 @@ A modern, customizable rich-text editor for Angular applications, built with Tip
6
6
 
7
7
  ## 🚀 Features
8
8
 
9
- - **Modern Angular**: Built with Angular 18+ with Signals and modern patterns
10
- - **Rich Text Editing**: Powered by Tiptap v2 with extensive formatting options
11
- - **Table Support**: Full table management with bubble menus and cell selection
12
- - **Slash Commands**: Intuitive slash commands for quick content insertion
13
- - **Internationalization**: Full i18n support (English & French) with auto-detection
14
- - **Customizable**: Highly configurable toolbar, bubble menus, and slash commands
15
- - **Image Support**: Advanced image handling with resizing, compression, and bubble menus
16
- - **Height Control**: Configurable editor height with scrolling
17
- - **Word/Character Count**: Real-time word and character counting with proper pluralization
18
- - **Office Paste**: Clean pasting from Microsoft Office applications
19
- - **TypeScript**: Full TypeScript support with strict typing
20
- - **Accessibility**: Built with accessibility best practices
21
- - **Service Architecture**: Clean service-based architecture with `EditorCommandsService`
9
+ - **Modern Angular**: Built with Angular 18+ using Signals and modern patterns for peak performance.
10
+ - **Full Rich Text Power**: Powered by Tiptap v2 with extensive formatting and block capabilities.
11
+ - **Modern UX (Notion-like)**: Intuitive slash commands and bubble menus for a keyboard-first experience.
12
+ - **Highly Customizable**: Easily configure toolbars, bubble menus, and slash command items.
13
+ - **Signal-Based Reactivity**: Pure Signal architecture natively compatible with `ChangeDetectionStrategy.OnPush`.
14
+ - **Advanced Table Support**: Full table management with cell selection and context-aware bubble menus.
15
+ - **Professional Media**: Advanced image handling with resizing, auto-compression, and custom uploaders.
16
+ - **Built-in i18n**: English & French support with a reactive, extensible locale system.
17
+ - **Word/Character Count**: Real-time statistics with proper pluralization support.
18
+ - **Office-Ready**: Cleaned-up pasting from Microsoft Word and Excel to maintain layout integrity.
19
+ - **Service Driven**: Deep programmatic control via `EditorCommandsService` and isolated instances.
20
+ - **A11y First**: Built with accessibility best practices and full keyboard navigation.
21
+
22
+ ## 💎 Why this editor?
23
+
24
+ Most Angular wrappers for Tiptap provide a basic component but leave the heavy lifting to you. **Angular Tiptap Editor** is built to solve common production hurdles:
25
+
26
+ - **True Scalability**: Thanks to **isolated services** provided at the component level, you can host multiple independent editors with different configurations and languages on the same page without a single state leak.
27
+ - **OnPush by Default**: The entire UI (toolbar, menus) is powered by **Angular Signals**. The `editorState` snapshot logic ensures that your components only re-render when necessary, even in complex `OnPush` applications.
28
+ - **Deep i18n & Extensibility**: Not just English/French — you can inject **custom translations** and **custom Tiptap extensions**. Our `DiscoveryCalculator` automatically tracks any new mark or node you add, making them reactive without extra code.
29
+ - **Clean Office UX**: Professional-grade pasting from **Word and Excel** plus smart image handling (auto-compression, resizing handles) ensures a polished experience for end-users.
30
+
31
+ ## 🛠️ Extensions included
32
+
33
+ The library comes with a pre-configured set of standard and custom extensions:
34
+
35
+ - **Nodes**: `StarterKit`, `Heading`, `Table`, `Image`, `HorizontalRule`, `CodeBlock`.
36
+ - **Marks**: `Bold`, `Italic`, `Underline`, `Strike`, `Code`, `Link`, `Highlight`, `TextStyle`, `Color`, `Superscript`, `Subscript`.
37
+ - **Utilities**: `Placeholder`, `CharacterCount`, `Typography`, `Focus`, `BubbleMenu`, `Gapcursor`, `Dropcursor`, `ResizableImage` (Custom).
22
38
 
23
39
  ## 📦 Installation
24
40
 
@@ -114,20 +130,24 @@ export class AdvancedComponent {
114
130
  };
115
131
 
116
132
  // No config needed if you want all commands enabled
117
- slashCommands = {
133
+ slashCommandsConfig = {
118
134
  image: true,
119
135
  table: true,
120
136
  heading1: true
121
137
  };
122
138
 
139
+ // Available keys: "heading1", "heading2", "heading3", "bulletList",
140
+ // "orderedList", "blockquote", "code", "image", "horizontalRule", "table"
141
+
123
142
  onContentChange(newContent: string) {
124
143
  this.content = newContent;
125
144
  }
126
145
  }
127
146
  ```
128
147
 
129
- You can also pass additional TipTap extensions (including custom marks)
130
- via the `tiptapExtensions` input.
148
+ ### 3. Registering Custom Extensions
149
+
150
+ Easily extend the editor with any standard Tiptap extension or your own custom marks/nodes via the `tiptapExtensions` input.
131
151
 
132
152
  ```typescript
133
153
  import { Component } from "@angular/core";
@@ -156,7 +176,7 @@ export class CustomExtensionsComponent {
156
176
  }
157
177
  ```
158
178
 
159
- ### 3. With Form Integration
179
+ ### 4. With Form Integration
160
180
 
161
181
  ```typescript
162
182
  import { Component } from "@angular/core";
@@ -184,7 +204,7 @@ export class FormComponent {
184
204
  }
185
205
  ```
186
206
 
187
- ### 4. Using EditorCommandsService
207
+ ### 5. Using EditorCommandsService
188
208
 
189
209
  ```typescript
190
210
  import { Component, inject } from "@angular/core";
@@ -195,9 +215,15 @@ import { EditorCommandsService } from "@flogeez/angular-tiptap-editor";
195
215
  standalone: true,
196
216
  template: `
197
217
  <div>
198
- <button (click)="clearContent()">Clear Content</button>
199
- <button (click)="focusEditor()">Focus Editor</button>
200
- <button (click)="setContent()">Set Content</button>
218
+ <div class="controls">
219
+ <button (click)="clearContent()">Clear Content</button>
220
+ <button (click)="focusEditor()">Focus Editor</button>
221
+ <button (click)="setContent()">Set Content</button>
222
+ </div>
223
+
224
+ <angular-tiptap-editor
225
+ (editorCreated)="onEditorCreated($event)"
226
+ />
201
227
  </div>
202
228
  `,
203
229
  })
@@ -232,6 +258,55 @@ export class CommandsComponent {
232
258
  }
233
259
  ```
234
260
 
261
+ ### 6. Extending Reactive Editor State
262
+
263
+ The editor features a dual-layer state architecture: **Automatic Tracking** for simple extensions and **Custom Calculators** for advanced needs.
264
+
265
+ #### A. Automatic Extension Tracking (Zero Config)
266
+
267
+ Any TipTap **Mark** or **Node** you add to `tiptapExtensions` is automatically tracked by our `DiscoveryCalculator`. You don't need to write any extra code to make them reactive.
268
+
269
+ * **For Marks**: `state().marks.yourExtensionName` (boolean) and `state().can.toggleYourExtensionName` (boolean).
270
+ * **For Nodes**: `state().nodes.yourExtensionName` (boolean).
271
+
272
+ #### B. Custom State Calculators (Advanced)
273
+
274
+ If you need to extract complex data (like attributes, depth, or custom logic), you can provide a custom `StateCalculator`.
275
+
276
+ 1. **Define a Calculator**:
277
+ ```typescript
278
+ import { StateCalculator } from "@flogeez/angular-tiptap-editor";
279
+
280
+ // This function will be called on every editor update
281
+ export const MyCustomCalculator: StateCalculator = (editor) => {
282
+ return {
283
+ custom: {
284
+ hasHighPriority: editor.isActive('priority'),
285
+ selectionDepth: editor.state.selection.$from.depth,
286
+ // Any data you need...
287
+ }
288
+ };
289
+ };
290
+ ```
291
+
292
+ 2. **Register it in the Template**:
293
+ ```html
294
+ <angular-tiptap-editor
295
+ [stateCalculators]="[MyCustomCalculator]"
296
+ />
297
+ ```
298
+
299
+ 3. **Consume it anywhere**:
300
+ ```typescript
301
+ @Component({ ... })
302
+ export class MyToolbarComponent {
303
+ private editorCommands = inject(EditorCommandsService);
304
+
305
+ // Access your custom data reactively!
306
+ isHighPriority = computed(() => this.editorCommands.editorState().custom?.hasHighPriority);
307
+ }
308
+ ```
309
+
235
310
  ## ✨ Key Features
236
311
 
237
312
  ### 📊 Table Management
@@ -254,6 +329,30 @@ Quick content insertion with slash commands:
254
329
  - **Media**: `/image`, `/table`
255
330
  - **Fully Internationalized**: All commands translated
256
331
 
332
+ #### Custom Slash Commands
333
+
334
+ The `slashCommands` object also allows you to add completely custom command items:
335
+
336
+ ```typescript
337
+ import { SlashCommandsConfig } from "@flogeez/angular-tiptap-editor";
338
+
339
+ slashCommands: SlashCommandsConfig = {
340
+ // Toggle native commands
341
+ heading1: true,
342
+ image: false,
343
+ // Add custom ones
344
+ custom: [
345
+ {
346
+ title: 'Magic Action',
347
+ description: 'Insert some AI magic',
348
+ icon: 'auto_fix',
349
+ keywords: ['magic', 'ai'],
350
+ command: (editor) => editor.commands.insertContent('✨ Magic happened!')
351
+ }
352
+ ]
353
+ };
354
+ ```
355
+
257
356
  ### 🖼️ Advanced Image Handling
258
357
 
259
358
  Professional image management:
@@ -337,6 +436,8 @@ The `ImageUploadContext` provides:
337
436
 
338
437
  The handler must return an `ImageUploadHandlerResult` with at least a `src` property containing the image URL.
339
438
 
439
+ ---
440
+
340
441
 
341
442
  ### 📝 Word & Character Counting
342
443
 
@@ -379,127 +480,77 @@ Open [http://localhost:4200](http://localhost:4200) to view the demo.
379
480
  | `height` | `number` | `undefined` | Fixed height in pixels |
380
481
  | `maxHeight` | `number` | `undefined` | Maximum height in pixels |
381
482
  | `minHeight` | `number` | `200` | Minimum height in pixels |
483
+ | `maxCharacters` | `number` | `undefined` | Character limit |
382
484
  | `fillContainer` | `boolean` | `false` | Fill parent container height |
383
485
  | `autofocus` | `boolean \| 'start' \| 'end' \| 'all'` | `false` | Auto-focus behavior |
384
486
  | `showToolbar` | `boolean` | `true` | Show toolbar |
385
- | `showBubbleMenu` | `boolean` | `true` | Show bubble menu |
487
+ | `showBubbleMenu` | `boolean` | `true` | Show text bubble menu |
488
+ | `showImageBubbleMenu`| `boolean` | `true` | Show image bubble menu |
489
+ | `showTableBubbleMenu`| `boolean` | `true` | Show table bubble menu |
490
+ | `showCellBubbleMenu` | `boolean` | `true` | Show cell bubble menu |
491
+ | `enableSlashCommands`| `boolean` | `true` | Enable slash commands functionality|
492
+ | `enableOfficePaste` | `boolean` | `true` | Enable smart Office pasting |
386
493
  | `showCharacterCount` | `boolean` | `true` | Show character counter |
387
494
  | `showWordCount` | `boolean` | `true` | Show word counter |
388
495
  | `toolbar` | `ToolbarConfig` | All enabled | Toolbar configuration |
389
496
  | `bubbleMenu` | `BubbleMenuConfig` | All enabled | Bubble menu configuration |
497
+ | `imageBubbleMenu` | `ImageBubbleMenuConfig` | All enabled | Image bubble menu config |
498
+ | `tableBubbleMenu` | `TableBubbleMenuConfig` | All enabled | Table bubble menu config |
499
+ | `cellBubbleMenu` | `CellBubbleMenuConfig` | All enabled | Cell bubble menu config |
390
500
  | `slashCommands` | `SlashCommandsConfig` | All enabled | Slash commands configuration |
391
501
  | `imageUploadHandler` | `ImageUploadHandler` | `undefined` | Custom image upload function |
502
+ | `stateCalculators` | `StateCalculator[]` | `[]` | Custom reactive state logic |
392
503
  | `tiptapExtensions` | `(Extension \| Node \| Mark)[]` | `[]` | Additional Tiptap extensions |
393
504
  | `tiptapOptions` | `Partial<EditorOptions>` | `{}` | Additional Tiptap editor options |
394
505
 
395
506
 
396
-
397
507
  #### Outputs
398
508
 
399
509
  | Output | Type | Description |
400
510
  | --------------- | ----------------- | ------------------------------- |
401
511
  | `contentChange` | `string` | Emitted when content changes |
402
512
  | `editorCreated` | `Editor` | Emitted when editor is created |
513
+ | `editorUpdate` | `{editor, trans}` | Emitted on every editor update |
403
514
  | `editorFocus` | `{editor, event}` | Emitted when editor gains focus |
404
515
  | `editorBlur` | `{editor, event}` | Emitted when editor loses focus |
405
516
 
406
- ### Configuration Examples
407
-
408
- ```typescript
409
- import {
410
- DEFAULT_TOOLBAR_CONFIG,
411
- DEFAULT_BUBBLE_MENU_CONFIG,
412
- SLASH_COMMAND_KEYS,
413
- } from "@flogeez/angular-tiptap-editor";
414
-
415
- // Minimal toolbar
416
- const minimalToolbar = {
417
- bold: true,
418
- italic: true,
419
- bulletList: true,
420
- };
421
-
422
- // Full toolbar with clear button
423
- const fullToolbar = {
424
- ...DEFAULT_TOOLBAR_CONFIG,
425
- clear: true, // Add clear button
426
- };
427
-
428
- // Bubble menu with table support
429
- const bubbleMenuWithTable = {
430
- ...DEFAULT_BUBBLE_MENU_CONFIG,
431
- table: true, // Enable table bubble menu
432
- };
433
-
434
- // Slash commands configuration (simple toggle)
435
- // By default, all commands are enabled and localized.
436
- const slashCommands = {
437
- heading1: true,
438
- heading2: true,
439
- image: false, // Disable image command
440
- };
441
-
442
- // Available keys: "heading1", "heading2", "heading3", "bulletList",
443
- // "orderedList", "blockquote", "code", "image", "horizontalRule", "table"
444
- ```
445
517
 
446
518
  ## 🌍 Internationalization
447
519
 
448
- The editor supports English and French with automatic browser language detection:
520
+ The editor comes with built-in support for **English (en)** and **French (fr)**, featuring automatic browser language detection.
449
521
 
450
- ```typescript
451
- // Force English
452
- <angular-tiptap-editor [locale]="'en'" />
522
+ ### Basic Usage
453
523
 
454
- // Force French
524
+ ```typescript
525
+ // Force a specific language
455
526
  <angular-tiptap-editor [locale]="'fr'" />
456
527
 
457
528
  // Auto-detect (default)
458
529
  <angular-tiptap-editor />
459
530
  ```
460
531
 
461
- ### Available Translations
532
+ ### Adding Custom Languages
462
533
 
463
- - **English (en)**: Default language with complete translations
464
- - **French (fr)**: Full French translation including:
465
- - Toolbar buttons
466
- - Bubble menu items
467
- - Slash commands
468
- - Placeholder text
469
- - Error messages
470
- - Word/character count (with proper pluralization)
471
-
472
- ### Custom Slash Commands
473
-
474
- For advanced usage, you can provide entirely custom command items (titles, icons, logic):
534
+ You can easily extend the editor with new languages or override existing labels using the `TiptapI18nService`:
475
535
 
476
536
  ```typescript
477
- import {
478
- CustomSlashCommands,
479
- SlashCommandItem
480
- } from "@flogeez/angular-tiptap-editor";
481
-
482
- // Define your custom items
483
- const myCommands: SlashCommandItem[] = [
484
- {
485
- title: 'My Action',
486
- description: 'Do something cool',
487
- icon: 'star',
488
- keywords: ['custom', 'cool'],
489
- command: (editor) => { /* logic */ }
537
+ import { TiptapI18nService } from "@flogeez/angular-tiptap-editor";
538
+
539
+ @Component({ ... })
540
+ export class MyComponent {
541
+ constructor(private i18nService: TiptapI18nService) {
542
+ // Add Spanish support
543
+ this.i18nService.addTranslations('es', {
544
+ toolbar: { bold: 'Negrita', italic: 'Cursiva', ... },
545
+ editor: { placeholder: 'Empieza a escribir...' }
546
+ });
547
+
548
+ // Switch to Spanish
549
+ this.i18nService.setLocale('es');
490
550
  }
491
- ];
492
-
493
- // Use in template
494
- customSlashCommands = {
495
- commands: myCommands,
496
- };
551
+ }
497
552
  ```
498
553
 
499
- And in template:
500
- ```html
501
- <angular-tiptap-editor [customSlashCommands]="customSlashCommands" />
502
- ```
503
554
 
504
555
  ### 🎨 CSS Custom Properties
505
556
 
@@ -571,23 +622,56 @@ angular-tiptap-editor {
571
622
  ```
572
623
 
573
624
 
625
+ ### ⚡ Reactive State & OnPush
626
+
627
+ The library exposes a reactive `editorState` signal via the `EditorCommandsService`. This signal contains everything you need to build custom UIs around the editor:
628
+
629
+ - **Active State**: Check if `bold`, `italic`, or custom marks are active.
630
+ - **Commands Availability**: Check if `undo`, `redo`, or custom commands can be executed.
631
+ - **Structural Data**: Access table status, image attributes, or selection details.
632
+
633
+ Since it's built with Signals, your custom toolbar items or UI overlays will only re-render when the specific data they consume changes, making it extremely efficient for `OnPush` applications.
634
+
635
+ ---
636
+
637
+ ### 🧩 Custom Tiptap Extensions
638
+
639
+ You are not limited to the built-in extensions. Pass any Tiptap extension, mark, or node:
640
+
641
+ ```html
642
+ <angular-tiptap-editor [tiptapExtensions]="[MyCustomExtension]" />
643
+ ```
644
+
645
+ Any custom extension is automatically detected and its state (active/can) is added to the reactive `editorState` snapshot.
646
+
647
+ ---
648
+
574
649
  ## 🏗️ Architecture
575
650
 
576
- ### Service-Based Design
651
+ ### Reactive State Management
652
+
653
+ The library uses a **Snapshot & Signal** pattern to bridge Tiptap and Angular.
654
+
655
+ 1. **State Snapshot**: Every editor transaction triggers a set of "Calculators" that produce a single immutable state object.
656
+ 2. **Specialized Calculators**: Logic is modularized into specialized functions (Marks, Table, Image, etc.) and a **Discovery Calculator** for automatic extension detection.
657
+ 3. **Signals Integration**: This snapshot is stored in a single Angular Signal. Sub-components (toolbar, menus) consume this signal only where needed.
658
+ 4. **Change Detection Optimization**: A custom equality check on the signal prevents unnecessary re-renders when the visual state of the editor hasn't changed.
659
+
660
+ ### Core Services
661
+
662
+ - **`EditorCommandsService`**: Exposes the `editorState` signal and provides a centralized API for executing Tiptap commands.
663
+ - **`ImageService`**: Manages the image processing pipeline (selection, compression, and server-side upload handling).
664
+ - **`TiptapI18nService`**: Reactive translation service with support for browser locale auto-detection.
577
665
 
578
- The library follows a clean service-based architecture:
666
+ ### Isolated Instances
579
667
 
580
- - **`EditorCommandsService`**: Centralized service for all editor commands
581
- - **`TiptapI18nService`**: Internationalization service with automatic language detection
582
- - **`ImageService`**: Advanced image handling with compression and resizing
583
- - **`filterSlashCommands()`**: Utility function for managing slash commands
668
+ Each component instance provides its own set of services (`EditorCommandsService`, `ImageService`, etc.) at the component level. This ensures that multiple editors on the same page maintain independent states and configurations without interference.
584
669
 
585
- ### Modern Angular Patterns
670
+ ### Modern Angular Integration
586
671
 
587
- - **Signals**: Used throughout for reactive state management
588
- - **Dependency Injection**: Clean service injection with `inject()`
589
- - **Standalone Components**: All components are standalone for better tree-shaking
590
- - **TypeScript**: Strict typing with comprehensive interfaces
672
+ - **Signals**: Native reactivity for efficient UI updates.
673
+ - **OnPush**: Designed for `ChangeDetectionStrategy.OnPush` throughout.
674
+ - **Typed State**: Fully typed interfaces for the editor state and configurations.
591
675
 
592
676
  ### Default Configurations
593
677
 
@@ -649,14 +733,11 @@ Contributions are welcome! Please feel free to submit a Pull Request.
649
733
 
650
734
  ### Latest Updates
651
735
 
652
- - ✅ **Custom Image Upload Handler**: Upload images to your own server (S3, Cloudinary, etc.)
653
- - ✅ **Table Support**: Full table management with bubble menus
654
- - ✅ **Slash Commands**: Intuitive content insertion commands
655
- - ✅ **Word/Character Count**: Real-time counting with proper pluralization
656
- - ✅ **Service Architecture**: Clean `EditorCommandsService` for better maintainability
657
- - ✅ **Default Configurations**: Importable default configs for easy customization
658
- - ✅ **Office Paste**: Clean pasting from Microsoft Office applications
659
- - ✅ **Enhanced i18n**: Improved internationalization with better architecture
736
+ - ✅ **Reactive State & Signals**: Optimized state management for a faster, smoother experience.
737
+ - ✅ **Zero-Config Extensions**: Custom Tiptap Marks and Nodes are tracked automatically.
738
+ - ✅ **Multi-Instance Support**: Use multiple independent editors on the same page without state leaks.
739
+ - ✅ **Clean Service Architecture**: Decoupled configurations and isolated services for better stability.
740
+ - ✅ **Refactored Link Management**: Dedicated link bubble menu with smart UI anchoring and real-time URL sync.
660
741
 
661
742
  ---
662
743