@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/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- import { Editor, Node, Extension, Mark, EditorOptions } from '@tiptap/core';
1
+ import * as _flogeez_angular_tiptap_editor from '@flogeez/angular-tiptap-editor';
2
2
  import * as _angular_core from '@angular/core';
3
3
  import { AfterViewInit, OnDestroy, ElementRef } from '@angular/core';
4
+ import { Editor, Node, Mark, Extension, EditorOptions } from '@tiptap/core';
4
5
  import { Observable } from 'rxjs';
5
6
  import { ControlValueAccessor } from '@angular/forms';
6
7
 
7
- type SupportedLocale = "en" | "fr";
8
+ type SupportedLocale = "en" | "fr" | (string & {});
8
9
  interface TiptapTranslations {
9
10
  toolbar: {
10
11
  bold: string;
@@ -12,6 +13,7 @@ interface TiptapTranslations {
12
13
  underline: string;
13
14
  strike: string;
14
15
  code: string;
16
+ codeBlock: string;
15
17
  superscript: string;
16
18
  subscript: string;
17
19
  highlight: string;
@@ -173,6 +175,8 @@ declare class TiptapI18nService {
173
175
  private _currentLocale;
174
176
  private _translations;
175
177
  readonly currentLocale: _angular_core.Signal<SupportedLocale>;
178
+ /** All loaded translations (useful for dynamic key access) */
179
+ readonly allTranslations: _angular_core.Signal<Record<SupportedLocale, TiptapTranslations>>;
176
180
  readonly translations: _angular_core.Signal<TiptapTranslations>;
177
181
  readonly t: _angular_core.Signal<TiptapTranslations>;
178
182
  readonly toolbar: _angular_core.Signal<{
@@ -181,6 +185,7 @@ declare class TiptapI18nService {
181
185
  underline: string;
182
186
  strike: string;
183
187
  code: string;
188
+ codeBlock: string;
184
189
  superscript: string;
185
190
  subscript: string;
186
191
  highlight: string;
@@ -341,7 +346,7 @@ declare class TiptapI18nService {
341
346
  setLocale(locale: SupportedLocale): void;
342
347
  autoDetectLocale(): void;
343
348
  getSupportedLocales(): SupportedLocale[];
344
- addTranslations(locale: SupportedLocale, translations: Partial<TiptapTranslations>): void;
349
+ addTranslations(locale: string, translations: TiptapTranslations | Partial<TiptapTranslations>): void;
345
350
  private detectBrowserLanguage;
346
351
  getToolbarTitle(key: keyof TiptapTranslations["toolbar"]): string;
347
352
  getBubbleMenuTitle(key: keyof TiptapTranslations["bubbleMenu"]): string;
@@ -390,11 +395,6 @@ declare class TiptapI18nService {
390
395
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<TiptapI18nService>;
391
396
  }
392
397
 
393
- interface CellBubbleMenuConfig$1 {
394
- mergeCells?: boolean;
395
- splitCell?: boolean;
396
- }
397
-
398
398
  interface SlashCommandItem {
399
399
  title: string;
400
400
  description: string;
@@ -486,107 +486,225 @@ interface ImageUploadHandlerResult {
486
486
  */
487
487
  type ImageUploadHandler = (context: ImageUploadContext) => Promise<ImageUploadHandlerResult> | Observable<ImageUploadHandlerResult>;
488
488
  declare class ImageService {
489
+ /** Signals for image state */
489
490
  selectedImage: _angular_core.WritableSignal<ImageData | null>;
490
491
  isImageSelected: _angular_core.Signal<boolean>;
492
+ /** Resizing state */
491
493
  isResizing: _angular_core.WritableSignal<boolean>;
492
494
  private i18n;
493
495
  private readonly t;
496
+ /** Upload state signals */
494
497
  isUploading: _angular_core.WritableSignal<boolean>;
495
498
  uploadProgress: _angular_core.WritableSignal<number>;
496
499
  uploadMessage: _angular_core.WritableSignal<string>;
497
500
  /**
498
- * Custom upload handler for images.
499
- * When set, this handler will be called instead of the default base64 conversion.
500
- * This allows users to implement their own image storage logic.
501
- *
502
- * @example
503
- * ```typescript
504
- * imageService.uploadHandler = async (context) => {
505
- * const formData = new FormData();
506
- * formData.append('image', context.file);
507
- * const response = await fetch('/api/upload', { method: 'POST', body: formData });
508
- * const data = await response.json();
509
- * return { src: data.url };
510
- * };
511
- * ```
501
+ * Custom upload handler.
502
+ * If set, this handler replaces the default base64 conversion.
512
503
  */
513
504
  uploadHandler: ImageUploadHandler | null;
514
505
  private currentEditor;
506
+ /** Select and track an image from the editor */
515
507
  selectImage(editor: Editor): void;
516
508
  clearSelection(): void;
509
+ /** Insert a new image and ensure it's selected */
517
510
  insertImage(editor: Editor, imageData: ImageData): void;
511
+ /** Update attributes of the currently active image */
518
512
  updateImageAttributes(editor: Editor, attributes: Partial<ImageData>): void;
513
+ /** Resize image with optional aspect ratio maintenance */
519
514
  resizeImage(editor: Editor, options: ResizeOptions): void;
520
- resizeImageByPercentage(editor: Editor, percentage: number): void;
515
+ /** Predetermined resize helpers used by UI */
521
516
  resizeImageToSmall(editor: Editor): void;
522
517
  resizeImageToMedium(editor: Editor): void;
523
518
  resizeImageToLarge(editor: Editor): void;
524
519
  resizeImageToOriginal(editor: Editor): void;
525
- resizeImageFreely(editor: Editor, width: number, height: number): void;
520
+ /** Get current image dimensions */
526
521
  getImageDimensions(editor: Editor): {
527
522
  width: number;
528
523
  height: number;
529
524
  } | null;
530
- getNaturalImageDimensions(src: string): Promise<{
531
- width: number;
532
- height: number;
533
- }>;
525
+ /** Remove the selected image */
534
526
  deleteImage(editor: Editor): void;
535
527
  private updateSelectedImage;
528
+ /** Validate file type and size */
536
529
  validateImage(file: File, maxSize?: number): {
537
530
  valid: boolean;
538
531
  error?: string;
539
532
  };
533
+ /** Compress and process image on client side */
540
534
  compressImage(file: File, quality?: number, maxWidth?: number, maxHeight?: number): Promise<ImageUploadResult>;
535
+ /** Core upload logic with progress tracking */
541
536
  private uploadImageWithProgress;
542
- uploadAndInsertImage(editor: Editor, file: File, options?: {
543
- quality?: number;
544
- maxWidth?: number;
545
- maxHeight?: number;
546
- }): Promise<void>;
537
+ private resetUploadState;
538
+ /** Main entry point for file upload and insertion */
539
+ uploadAndInsertImage(editor: Editor, file: File, options?: Record<string, any>): Promise<void>;
540
+ /** Trigger an editor transaction to force decoration update */
547
541
  private forceEditorUpdate;
542
+ /** Generic helper to open file picker and process selection */
548
543
  private selectFileAndProcess;
549
- selectAndUploadImage(editor: Editor, options?: {
550
- quality?: number;
551
- maxWidth?: number;
552
- maxHeight?: number;
553
- accept?: string;
554
- }): Promise<void>;
555
- selectAndReplaceImage(editor: Editor, options?: {
556
- quality?: number;
557
- maxWidth?: number;
558
- maxHeight?: number;
559
- accept?: string;
560
- }): Promise<void>;
561
- uploadAndReplaceImage(editor: Editor, file: File, options?: {
562
- quality?: number;
563
- maxWidth?: number;
564
- maxHeight?: number;
565
- }): Promise<void>;
544
+ /** Select file and upload as new image */
545
+ selectAndUploadImage(editor: Editor, options?: Record<string, any>): Promise<void>;
546
+ /** Select file and replace currently selected image */
547
+ selectAndReplaceImage(editor: Editor, options?: Record<string, any>): Promise<void>;
548
+ /** Internal helper used by replacement logic */
549
+ uploadAndReplaceImage(editor: Editor, file: File, options?: Record<string, any>): Promise<void>;
566
550
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ImageService, never>;
567
551
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<ImageService>;
568
552
  }
569
553
 
554
+ type StateCalculator = (editor: Editor) => Partial<{
555
+ [K in keyof EditorStateSnapshot]: EditorStateSnapshot[K] extends object ? Partial<EditorStateSnapshot[K]> : EditorStateSnapshot[K];
556
+ }>;
557
+ interface EditorStateSnapshot {
558
+ /** Global editor states */
559
+ isFocused: boolean;
560
+ isEditable: boolean;
561
+ /**
562
+ * Detailed selection information to avoid overlap between menus
563
+ */
564
+ selection: {
565
+ type: 'text' | 'node' | 'cell' | 'none';
566
+ from: number;
567
+ to: number;
568
+ empty: boolean;
569
+ /** Specific for CellSelection */
570
+ isSingleCell: boolean;
571
+ };
572
+ /** Text formatting states (Marks) */
573
+ marks: {
574
+ bold: boolean;
575
+ italic: boolean;
576
+ underline: boolean;
577
+ strike: boolean;
578
+ code: boolean;
579
+ superscript: boolean;
580
+ subscript: boolean;
581
+ highlight: boolean;
582
+ link: boolean;
583
+ linkHref: string | null;
584
+ color: string | null;
585
+ computedColor: string | null;
586
+ background: string | null;
587
+ computedBackground: string | null;
588
+ linkOpenOnClick: boolean;
589
+ };
590
+ /** Capability states (canExecute) */
591
+ can: {
592
+ toggleBold: boolean;
593
+ toggleItalic: boolean;
594
+ toggleUnderline: boolean;
595
+ toggleStrike: boolean;
596
+ toggleCode: boolean;
597
+ toggleHighlight: boolean;
598
+ toggleLink: boolean;
599
+ toggleSuperscript: boolean;
600
+ toggleSubscript: boolean;
601
+ setColor: boolean;
602
+ setHighlight: boolean;
603
+ undo: boolean;
604
+ redo: boolean;
605
+ /** Table specific capabilities */
606
+ addRowBefore: boolean;
607
+ addRowAfter: boolean;
608
+ deleteRow: boolean;
609
+ addColumnBefore: boolean;
610
+ addColumnAfter: boolean;
611
+ deleteColumn: boolean;
612
+ deleteTable: boolean;
613
+ mergeCells: boolean;
614
+ splitCell: boolean;
615
+ toggleHeaderRow: boolean;
616
+ toggleHeaderColumn: boolean;
617
+ /** Structure/Node capabilities */
618
+ toggleHeading1: boolean;
619
+ toggleHeading2: boolean;
620
+ toggleHeading3: boolean;
621
+ toggleBulletList: boolean;
622
+ toggleOrderedList: boolean;
623
+ toggleBlockquote: boolean;
624
+ toggleCodeBlock: boolean;
625
+ setTextAlignLeft: boolean;
626
+ setTextAlignCenter: boolean;
627
+ setTextAlignRight: boolean;
628
+ setTextAlignJustify: boolean;
629
+ insertHorizontalRule: boolean;
630
+ insertTable: boolean;
631
+ insertImage: boolean;
632
+ };
633
+ /** Current node context */
634
+ nodes: {
635
+ isTable: boolean;
636
+ isTableNodeSelected: boolean;
637
+ isTableCell: boolean;
638
+ isImage: boolean;
639
+ isBlockquote: boolean;
640
+ isCodeBlock: boolean;
641
+ isBulletList: boolean;
642
+ isOrderedList: boolean;
643
+ /** Headings */
644
+ h1: boolean;
645
+ h2: boolean;
646
+ h3: boolean;
647
+ /** Alignment */
648
+ alignLeft: boolean;
649
+ alignCenter: boolean;
650
+ alignRight: boolean;
651
+ alignJustify: boolean;
652
+ /** Table specific */
653
+ isTableHeaderRow: boolean;
654
+ isTableHeaderColumn: boolean;
655
+ /** Name of the active node at selection head */
656
+ activeNodeName: string | null;
657
+ };
658
+ /** Placeholder for custom extension states */
659
+ custom: Record<string, any>;
660
+ }
661
+ declare const INITIAL_EDITOR_STATE: EditorStateSnapshot;
662
+
570
663
  declare class EditorCommandsService {
571
- isActive(editor: Editor, name: string, attributes?: Record<string, any>): boolean;
572
- canExecute(editor: Editor, command: string): boolean;
664
+ private imageService;
665
+ private colorPickerSvc;
666
+ private linkSvc;
667
+ private readonly _editorState;
668
+ /** Exposed editor state as a readonly signal */
669
+ readonly editorState: _angular_core.Signal<EditorStateSnapshot>;
670
+ /** Signal to track when the toolbar is being hovered/interacted with */
671
+ private readonly _isToolbarInteracting;
672
+ readonly isToolbarInteracting: _angular_core.Signal<boolean>;
673
+ /** Set toolbar interaction state (called by editor component) */
674
+ setToolbarInteracting(value: boolean): void;
675
+ readonly isUploading: _angular_core.Signal<boolean>;
676
+ readonly uploadProgress: _angular_core.Signal<number>;
677
+ readonly uploadMessage: _angular_core.Signal<string>;
678
+ set uploadHandler(handler: ImageUploadHandler | null);
679
+ /** Update state (called by TiptapStateExtension) */
680
+ updateState(state: EditorStateSnapshot): void;
681
+ /** Signal to toggle link edit mode from UI (Toolbar) - Immediate response */
682
+ readonly linkEditMode: _angular_core.Signal<boolean>;
683
+ /** Reference to the element that triggered the link menu (for anchoring) */
684
+ readonly linkMenuTrigger: _angular_core.Signal<HTMLElement | null>;
685
+ /** Signal to toggle color picker mode from UI (text or highlight) */
686
+ readonly colorEditMode: _angular_core.Signal<_flogeez_angular_tiptap_editor.ColorEditMode | null>;
687
+ /** Reference to the element that triggered the color menu (for anchoring) */
688
+ readonly colorMenuTrigger: _angular_core.Signal<HTMLElement | null>;
689
+ /** Generic method to execute any command by name */
690
+ execute(editor: Editor, command: string, ...args: any[]): void;
573
691
  toggleBold(editor: Editor): void;
574
692
  toggleItalic(editor: Editor): void;
575
693
  toggleStrike(editor: Editor): void;
576
694
  toggleCode(editor: Editor): void;
695
+ toggleCodeBlock(editor: Editor): void;
696
+ toggleUnderline(editor: Editor): void;
697
+ toggleSuperscript(editor: Editor): void;
698
+ toggleSubscript(editor: Editor): void;
577
699
  toggleHeading(editor: Editor, level: 1 | 2 | 3): void;
700
+ toggleHighlight(editor: Editor, color?: string): void;
578
701
  toggleBulletList(editor: Editor): void;
579
702
  toggleOrderedList(editor: Editor): void;
580
703
  toggleBlockquote(editor: Editor): void;
581
- undo(editor: Editor): void;
582
- redo(editor: Editor): void;
583
- toggleUnderline(editor: Editor): void;
584
- toggleSuperscript(editor: Editor): void;
585
- toggleSubscript(editor: Editor): void;
586
704
  setTextAlign(editor: Editor, alignment: "left" | "center" | "right" | "justify"): void;
587
- toggleLink(editor: Editor, url?: string): void;
588
705
  insertHorizontalRule(editor: Editor): void;
589
- toggleHighlight(editor: Editor, color?: string): void;
706
+ undo(editor: Editor): void;
707
+ redo(editor: Editor): void;
590
708
  insertTable(editor: Editor, rows?: number, cols?: number): void;
591
709
  addColumnBefore(editor: Editor): void;
592
710
  addColumnAfter(editor: Editor): void;
@@ -599,13 +717,23 @@ declare class EditorCommandsService {
599
717
  splitCell(editor: Editor): void;
600
718
  toggleHeaderColumn(editor: Editor): void;
601
719
  toggleHeaderRow(editor: Editor): void;
602
- toggleHeaderCell(editor: Editor): void;
603
720
  clearContent(editor: Editor): void;
604
721
  focus(editor: Editor): void;
605
722
  blur(editor: Editor): void;
606
723
  setContent(editor: Editor, content: string, emitUpdate?: boolean): void;
607
724
  setEditable(editor: Editor, editable: boolean): void;
608
725
  insertContent(editor: Editor, content: string): void;
726
+ insertImage(editor: Editor, options?: {
727
+ quality?: number;
728
+ maxWidth?: number;
729
+ maxHeight?: number;
730
+ accept?: string;
731
+ }): Promise<void>;
732
+ uploadImage(editor: Editor, file: File, options?: {
733
+ quality?: number;
734
+ maxWidth?: number;
735
+ maxHeight?: number;
736
+ }): Promise<void>;
609
737
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EditorCommandsService, never>;
610
738
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<EditorCommandsService>;
611
739
  }
@@ -633,7 +761,7 @@ declare const DEFAULT_SLASH_COMMANDS_CONFIG: Record<SlashCommandKey, boolean>;
633
761
  * Factory pour créer les commandes natives avec leurs traductions et leur logique d'exécution.
634
762
  * Utilise les services de l'éditeur pour garantir une cohérence de comportement.
635
763
  */
636
- declare function createDefaultSlashCommands(i18n: TiptapI18nService, commands: EditorCommandsService, images: ImageService, imageOptions?: {
764
+ declare function createDefaultSlashCommands(i18n: TiptapI18nService, commands: EditorCommandsService, imageOptions?: {
637
765
  quality?: number;
638
766
  maxWidth?: number;
639
767
  maxHeight?: number;
@@ -642,7 +770,7 @@ declare function createDefaultSlashCommands(i18n: TiptapI18nService, commands: E
642
770
  /**
643
771
  * Filtre et assemble les commandes selon la configuration fournie.
644
772
  */
645
- declare function filterSlashCommands(config: SlashCommandsConfig, i18n: TiptapI18nService, commands: EditorCommandsService, images: ImageService, imageOptions?: {
773
+ declare function filterSlashCommands(config: SlashCommandsConfig, i18n: TiptapI18nService, commands: EditorCommandsService, imageOptions?: {
646
774
  quality?: number;
647
775
  maxWidth?: number;
648
776
  maxHeight?: number;
@@ -655,6 +783,7 @@ interface ToolbarConfig {
655
783
  underline?: boolean;
656
784
  strike?: boolean;
657
785
  code?: boolean;
786
+ codeBlock?: boolean;
658
787
  superscript?: boolean;
659
788
  subscript?: boolean;
660
789
  highlight?: boolean;
@@ -728,15 +857,11 @@ declare class NoopValueAccessorDirective implements ControlValueAccessor {
728
857
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NoopValueAccessorDirective, never, never, {}, {}, never, never, true, never>;
729
858
  }
730
859
 
731
- declare const DEFAULT_TOOLBAR_CONFIG: ToolbarConfig;
732
- declare const DEFAULT_BUBBLE_MENU_CONFIG: BubbleMenuConfig;
733
- declare const DEFAULT_IMAGE_BUBBLE_MENU_CONFIG: ImageBubbleMenuConfig;
734
- declare const DEFAULT_TABLE_MENU_CONFIG: TableBubbleMenuConfig;
735
- declare const DEFAULT_CELL_MENU_CONFIG: CellBubbleMenuConfig$1;
736
860
  declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
737
861
  content: _angular_core.InputSignal<string>;
738
862
  placeholder: _angular_core.InputSignal<string>;
739
863
  editable: _angular_core.InputSignal<boolean>;
864
+ disabled: _angular_core.InputSignal<boolean>;
740
865
  minHeight: _angular_core.InputSignal<number>;
741
866
  height: _angular_core.InputSignal<number | undefined>;
742
867
  maxHeight: _angular_core.InputSignal<number | undefined>;
@@ -750,14 +875,24 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
750
875
  slashCommands: _angular_core.InputSignal<SlashCommandsConfig>;
751
876
  customSlashCommands: _angular_core.InputSignal<CustomSlashCommands | undefined>;
752
877
  locale: _angular_core.InputSignal<SupportedLocale | undefined>;
753
- autofocus: _angular_core.InputSignal<number | boolean | "end" | "start" | "all">;
754
- tiptapExtensions: _angular_core.InputSignal<(Node<any, any> | Extension<any, any> | Mark<any, any>)[]>;
878
+ autofocus: _angular_core.InputSignal<number | boolean | "start" | "end" | "all">;
879
+ seamless: _angular_core.InputSignal<boolean>;
880
+ floatingToolbar: _angular_core.InputSignal<boolean>;
881
+ tiptapExtensions: _angular_core.InputSignal<(Node<any, any> | Mark<any, any> | Extension<any, any>)[]>;
755
882
  tiptapOptions: _angular_core.InputSignal<Partial<EditorOptions>>;
756
883
  showBubbleMenu: _angular_core.InputSignal<boolean>;
757
884
  bubbleMenu: _angular_core.InputSignal<Partial<BubbleMenuConfig>>;
758
885
  showImageBubbleMenu: _angular_core.InputSignal<boolean>;
759
886
  imageBubbleMenu: _angular_core.InputSignal<Partial<ImageBubbleMenuConfig>>;
760
887
  toolbar: _angular_core.InputSignal<Partial<ToolbarConfig>>;
888
+ showTableBubbleMenu: _angular_core.InputSignal<boolean>;
889
+ tableBubbleMenu: _angular_core.InputSignal<Partial<TableBubbleMenuConfig>>;
890
+ showCellBubbleMenu: _angular_core.InputSignal<boolean>;
891
+ cellBubbleMenu: _angular_core.InputSignal<Partial<CellBubbleMenuConfig>>;
892
+ /**
893
+ * Additionnal state calculators to extend the reactive editor state.
894
+ */
895
+ stateCalculators: _angular_core.InputSignal<StateCalculator[]>;
761
896
  imageUpload: _angular_core.InputSignal<Partial<any>>;
762
897
  /**
763
898
  * Custom handler for image uploads.
@@ -794,10 +929,6 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
794
929
  event: FocusEvent;
795
930
  }>;
796
931
  editorElement: _angular_core.Signal<ElementRef<any>>;
797
- private textMenuComp;
798
- private imageMenuComp;
799
- private tableMenuComp;
800
- private cellMenuComp;
801
932
  hideBubbleMenus(): void;
802
933
  showBubbleMenus(): void;
803
934
  private _editor;
@@ -805,30 +936,21 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
805
936
  private _wordCount;
806
937
  private _isDragOver;
807
938
  private _editorFullyInitialized;
939
+ private lastEmittedHtml;
808
940
  readonly editor: _angular_core.Signal<Editor | null>;
809
941
  readonly characterCount: _angular_core.Signal<number>;
810
942
  readonly wordCount: _angular_core.Signal<number>;
811
943
  readonly isDragOver: _angular_core.Signal<boolean>;
812
944
  readonly editorFullyInitialized: _angular_core.Signal<boolean>;
945
+ private _isFormControlDisabled;
946
+ readonly isFormControlDisabled: _angular_core.Signal<boolean>;
947
+ readonly mergedDisabled: _angular_core.Signal<boolean>;
813
948
  isEditorReady: _angular_core.Signal<boolean>;
814
949
  toolbarConfig: _angular_core.Signal<ToolbarConfig>;
815
950
  bubbleMenuConfig: _angular_core.Signal<BubbleMenuConfig>;
816
951
  imageBubbleMenuConfig: _angular_core.Signal<ImageBubbleMenuConfig>;
817
- tableBubbleMenuConfig: _angular_core.Signal<{
818
- addRowBefore: boolean;
819
- addRowAfter: boolean;
820
- deleteRow: boolean;
821
- addColumnBefore: boolean;
822
- addColumnAfter: boolean;
823
- deleteColumn: boolean;
824
- deleteTable: boolean;
825
- toggleHeaderRow: boolean;
826
- toggleHeaderColumn: boolean;
827
- }>;
828
- cellBubbleMenuConfig: _angular_core.Signal<{
829
- mergeCells: boolean;
830
- splitCell: boolean;
831
- }>;
952
+ tableBubbleMenuConfig: _angular_core.Signal<TableBubbleMenuConfig>;
953
+ cellBubbleMenuConfig: _angular_core.Signal<CellBubbleMenuConfig>;
832
954
  imageUploadConfig: _angular_core.Signal<{
833
955
  maxSize: number;
834
956
  maxWidth: number;
@@ -841,17 +963,17 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
841
963
  quality: number;
842
964
  }>;
843
965
  slashCommandsConfigComputed: _angular_core.Signal<CustomSlashCommands>;
966
+ readonly currentTranslations: _angular_core.Signal<_flogeez_angular_tiptap_editor.TiptapTranslations>;
844
967
  private _destroyRef;
845
968
  private ngControl;
846
969
  readonly i18nService: TiptapI18nService;
847
- readonly imageService: ImageService;
848
970
  readonly editorCommandsService: EditorCommandsService;
971
+ readonly editorState: _angular_core.Signal<_flogeez_angular_tiptap_editor.EditorStateSnapshot>;
849
972
  constructor();
850
973
  ngAfterViewInit(): void;
851
974
  ngOnDestroy(): void;
852
975
  private initEditor;
853
976
  private updateCharacterCount;
854
- onSlashCommandImageUpload(file: File): Promise<void>;
855
977
  onDragOver(event: DragEvent): void;
856
978
  onDrop(event: DragEvent): void;
857
979
  private insertImageFromFile;
@@ -864,17 +986,138 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
864
986
  clearContent(): void;
865
987
  getEditor(): Editor | null;
866
988
  private setupFormControlSubscription;
867
- setDisabledState(isDisabled: boolean): void;
868
989
  onEditorClick(event: MouseEvent): void;
869
990
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AngularTiptapEditorComponent, never>;
870
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AngularTiptapEditorComponent, "angular-tiptap-editor", never, { "content": { "alias": "content"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "fillContainer": { "alias": "fillContainer"; "required": false; "isSignal": true; }; "showToolbar": { "alias": "showToolbar"; "required": false; "isSignal": true; }; "showCharacterCount": { "alias": "showCharacterCount"; "required": false; "isSignal": true; }; "showWordCount": { "alias": "showWordCount"; "required": false; "isSignal": true; }; "maxCharacters": { "alias": "maxCharacters"; "required": false; "isSignal": true; }; "enableOfficePaste": { "alias": "enableOfficePaste"; "required": false; "isSignal": true; }; "enableSlashCommands": { "alias": "enableSlashCommands"; "required": false; "isSignal": true; }; "slashCommands": { "alias": "slashCommands"; "required": false; "isSignal": true; }; "customSlashCommands": { "alias": "customSlashCommands"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; "tiptapExtensions": { "alias": "tiptapExtensions"; "required": false; "isSignal": true; }; "tiptapOptions": { "alias": "tiptapOptions"; "required": false; "isSignal": true; }; "showBubbleMenu": { "alias": "showBubbleMenu"; "required": false; "isSignal": true; }; "bubbleMenu": { "alias": "bubbleMenu"; "required": false; "isSignal": true; }; "showImageBubbleMenu": { "alias": "showImageBubbleMenu"; "required": false; "isSignal": true; }; "imageBubbleMenu": { "alias": "imageBubbleMenu"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "imageUpload": { "alias": "imageUpload"; "required": false; "isSignal": true; }; "imageUploadHandler": { "alias": "imageUploadHandler"; "required": false; "isSignal": true; }; }, { "contentChange": "contentChange"; "editorCreated": "editorCreated"; "editorUpdate": "editorUpdate"; "editorFocus": "editorFocus"; "editorBlur": "editorBlur"; }, never, never, true, [{ directive: typeof NoopValueAccessorDirective; inputs: {}; outputs: {}; }]>;
991
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AngularTiptapEditorComponent, "angular-tiptap-editor", never, { "content": { "alias": "content"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "fillContainer": { "alias": "fillContainer"; "required": false; "isSignal": true; }; "showToolbar": { "alias": "showToolbar"; "required": false; "isSignal": true; }; "showCharacterCount": { "alias": "showCharacterCount"; "required": false; "isSignal": true; }; "showWordCount": { "alias": "showWordCount"; "required": false; "isSignal": true; }; "maxCharacters": { "alias": "maxCharacters"; "required": false; "isSignal": true; }; "enableOfficePaste": { "alias": "enableOfficePaste"; "required": false; "isSignal": true; }; "enableSlashCommands": { "alias": "enableSlashCommands"; "required": false; "isSignal": true; }; "slashCommands": { "alias": "slashCommands"; "required": false; "isSignal": true; }; "customSlashCommands": { "alias": "customSlashCommands"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; "seamless": { "alias": "seamless"; "required": false; "isSignal": true; }; "floatingToolbar": { "alias": "floatingToolbar"; "required": false; "isSignal": true; }; "tiptapExtensions": { "alias": "tiptapExtensions"; "required": false; "isSignal": true; }; "tiptapOptions": { "alias": "tiptapOptions"; "required": false; "isSignal": true; }; "showBubbleMenu": { "alias": "showBubbleMenu"; "required": false; "isSignal": true; }; "bubbleMenu": { "alias": "bubbleMenu"; "required": false; "isSignal": true; }; "showImageBubbleMenu": { "alias": "showImageBubbleMenu"; "required": false; "isSignal": true; }; "imageBubbleMenu": { "alias": "imageBubbleMenu"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "showTableBubbleMenu": { "alias": "showTableBubbleMenu"; "required": false; "isSignal": true; }; "tableBubbleMenu": { "alias": "tableBubbleMenu"; "required": false; "isSignal": true; }; "showCellBubbleMenu": { "alias": "showCellBubbleMenu"; "required": false; "isSignal": true; }; "cellBubbleMenu": { "alias": "cellBubbleMenu"; "required": false; "isSignal": true; }; "stateCalculators": { "alias": "stateCalculators"; "required": false; "isSignal": true; }; "imageUpload": { "alias": "imageUpload"; "required": false; "isSignal": true; }; "imageUploadHandler": { "alias": "imageUploadHandler"; "required": false; "isSignal": true; }; }, { "contentChange": "contentChange"; "editorCreated": "editorCreated"; "editorUpdate": "editorUpdate"; "editorFocus": "editorFocus"; "editorBlur": "editorBlur"; }, never, never, true, [{ directive: typeof NoopValueAccessorDirective; inputs: {}; outputs: {}; }]>;
871
992
  }
872
993
 
873
- type HeightConfig = {
874
- minHeight?: number;
875
- height?: number;
876
- maxHeight?: number;
877
- };
994
+ interface ColorPickerSelection {
995
+ from: number;
996
+ to: number;
997
+ }
998
+ type ColorEditMode = 'text' | 'highlight';
999
+ declare class ColorPickerService {
1000
+ private storedSelection;
1001
+ /** Current edit mode: null when closed, 'text' or 'highlight' when open */
1002
+ readonly editMode: _angular_core.WritableSignal<ColorEditMode | null>;
1003
+ /** Reference to the element that triggered the menu (for anchoring) */
1004
+ readonly menuTrigger: _angular_core.WritableSignal<HTMLElement | null>;
1005
+ /** Whether the user is currently interacting with the picker UI (e.g. typing) */
1006
+ readonly isInteracting: _angular_core.WritableSignal<boolean>;
1007
+ /**
1008
+ * Open the color picker menu in the specified mode.
1009
+ */
1010
+ open(mode: ColorEditMode, trigger?: HTMLElement): void;
1011
+ /**
1012
+ * Close the color picker menu.
1013
+ */
1014
+ close(): void;
1015
+ /**
1016
+ * Set interaction state (prevents premature closing when blurring editor)
1017
+ */
1018
+ setInteracting(value: boolean): void;
1019
+ /**
1020
+ * Toggle color picker from UI (extracts trigger from event).
1021
+ */
1022
+ toggle(editor: Editor, mode: ColorEditMode, event?: Event): void;
1023
+ /**
1024
+ * Capture current editor selection.
1025
+ */
1026
+ captureSelection(editor: Editor): void;
1027
+ /**
1028
+ * Get last captured selection.
1029
+ */
1030
+ getStoredSelection(): ColorPickerSelection | null;
1031
+ /**
1032
+ * Clear captured selection.
1033
+ */
1034
+ done(): void;
1035
+ /**
1036
+ * Apply text color to selection.
1037
+ */
1038
+ applyColor(editor: Editor, color: string, addToHistory?: boolean, focus?: boolean): void;
1039
+ /**
1040
+ * Remove text color from selection.
1041
+ */
1042
+ unsetColor(editor: Editor, focus?: boolean): void;
1043
+ /**
1044
+ * Apply highlight color to selection.
1045
+ */
1046
+ applyHighlight(editor: Editor, color: string, addToHistory?: boolean, focus?: boolean): void;
1047
+ /**
1048
+ * Remove highlight from selection.
1049
+ */
1050
+ unsetHighlight(editor: Editor, focus?: boolean): void;
1051
+ normalizeColor(color: string | null | undefined): string;
1052
+ getLuminance(color: string): number;
1053
+ getContrastColor(color: string): "black" | "white";
1054
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ColorPickerService, never>;
1055
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<ColorPickerService>;
1056
+ }
1057
+
1058
+ declare class LinkService {
1059
+ /** Whether link edit mode is active */
1060
+ readonly editMode: _angular_core.WritableSignal<boolean>;
1061
+ /** Reference to the element that triggered the menu (for anchoring) */
1062
+ readonly menuTrigger: _angular_core.WritableSignal<HTMLElement | null>;
1063
+ /** Whether the user is currently interacting with the link UI (input focus) */
1064
+ readonly isInteracting: _angular_core.WritableSignal<boolean>;
1065
+ /**
1066
+ * Open the link edit menu.
1067
+ */
1068
+ open(trigger?: HTMLElement): void;
1069
+ /**
1070
+ * Close the link edit menu.
1071
+ */
1072
+ close(): void;
1073
+ /**
1074
+ * Final cleanup (called after UI is hidden)
1075
+ */
1076
+ done(): void;
1077
+ /**
1078
+ * Set interaction state
1079
+ */
1080
+ setInteracting(value: boolean): void;
1081
+ /**
1082
+ * Toggle link mode from UI.
1083
+ * If a URL string is provided, applies the link and closes.
1084
+ * If an Event is provided, extracts the trigger for anchoring.
1085
+ */
1086
+ toggle(editor: Editor, urlOrEvent?: string | Event): void;
1087
+ /**
1088
+ * Apply a link to the current selection.
1089
+ */
1090
+ setLink(editor: Editor, url: string): void;
1091
+ /**
1092
+ * Remove link from the current selection.
1093
+ */
1094
+ unsetLink(editor: Editor): void;
1095
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<LinkService, never>;
1096
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<LinkService>;
1097
+ }
1098
+
1099
+ /**
1100
+ * DiscoveryCalculator automatically detects and tracks the state of any TipTap extension.
1101
+ * It provides a "fallback" reactive state for any mark or node not explicitly handled
1102
+ * by specialized calculators.
1103
+ */
1104
+ declare const DiscoveryCalculator: StateCalculator;
1105
+
1106
+ declare const ImageCalculator: StateCalculator;
1107
+
1108
+ declare const MarksCalculator: StateCalculator;
1109
+
1110
+ declare const SelectionCalculator: StateCalculator;
1111
+
1112
+ declare const StructureCalculator: StateCalculator;
1113
+
1114
+ declare const TableCalculator: StateCalculator;
1115
+
1116
+ declare const DEFAULT_TOOLBAR_CONFIG: ToolbarConfig;
1117
+ declare const DEFAULT_BUBBLE_MENU_CONFIG: BubbleMenuConfig;
1118
+ declare const DEFAULT_IMAGE_BUBBLE_MENU_CONFIG: ImageBubbleMenuConfig;
1119
+ declare const DEFAULT_TABLE_MENU_CONFIG: TableBubbleMenuConfig;
1120
+ declare const DEFAULT_CELL_MENU_CONFIG: CellBubbleMenuConfig;
878
1121
 
879
- export { AngularTiptapEditorComponent, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS_CONFIG, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, EditorCommandsService, ImageService, NoopValueAccessorDirective, SLASH_COMMAND_KEYS, TiptapI18nService, createDefaultSlashCommands, filterSlashCommands };
880
- export type { BubbleMenuConfig, CellBubbleMenuConfig, CustomSlashCommands, HeightConfig, ImageBubbleMenuConfig, ImageData, ImageUploadContext, ImageUploadHandler, ImageUploadHandlerResult, ImageUploadResult, ResizeOptions, SlashCommandItem, SlashCommandKey, SlashCommandsConfig, SupportedLocale, TableBubbleMenuConfig, TiptapTranslations, ToolbarConfig };
1122
+ export { AngularTiptapEditorComponent, ColorPickerService, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS_CONFIG, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, DiscoveryCalculator, EditorCommandsService, INITIAL_EDITOR_STATE, ImageCalculator, ImageService, LinkService, MarksCalculator, NoopValueAccessorDirective, SLASH_COMMAND_KEYS, SelectionCalculator, StructureCalculator, TableCalculator, TiptapI18nService, createDefaultSlashCommands, filterSlashCommands };
1123
+ export type { BubbleMenuConfig, CellBubbleMenuConfig, ColorEditMode, ColorPickerSelection, CustomSlashCommands, EditorStateSnapshot, ImageBubbleMenuConfig, ImageData, ImageUploadContext, ImageUploadHandler, ImageUploadHandlerResult, ImageUploadResult, ResizeOptions, SlashCommandItem, SlashCommandKey, SlashCommandsConfig, StateCalculator, SupportedLocale, TableBubbleMenuConfig, TiptapTranslations, ToolbarConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flogeez/angular-tiptap-editor",
3
- "version": "0.5.4",
3
+ "version": "2.0.0",
4
4
  "description": "A modern, customizable rich-text editor for Angular (18+), built with Tiptap and featuring complete internationalization support",
5
5
  "keywords": [
6
6
  "angular",