@flogeez/angular-tiptap-editor 0.3.2 → 0.3.4

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.
@@ -535,60 +535,60 @@ class TiptapButtonComponent {
535
535
  event.preventDefault();
536
536
  }
537
537
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
538
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.0", type: TiptapButtonComponent, isStandalone: true, selector: "tiptap-button", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, iconSize: { classPropertyName: "iconSize", publicName: "iconSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, ngImport: i0, template: `
539
- <button
540
- class="tiptap-button"
541
- [class.is-active]="active()"
542
- [class.is-disabled]="disabled()"
543
- [class.text-button]="variant() === 'text'"
544
- [class.danger]="variant() === 'danger'"
545
- [class.small]="size() === 'small'"
546
- [class.medium]="size() === 'medium'"
547
- [class.large]="size() === 'large'"
548
- [disabled]="disabled()"
549
- [attr.title]="title()"
550
- (mousedown)="onMouseDown($event)"
551
- (click)="onClick.emit($event)"
552
- type="button"
553
- >
554
- <span
555
- class="material-symbols-outlined"
556
- [class.icon-small]="iconSize() === 'small'"
557
- [class.icon-medium]="iconSize() === 'medium'"
558
- [class.icon-large]="iconSize() === 'large'"
559
- >{{ icon() }}</span
560
- >
561
- <ng-content></ng-content>
562
- </button>
538
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.0", type: TiptapButtonComponent, isStandalone: true, selector: "tiptap-button", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, iconSize: { classPropertyName: "iconSize", publicName: "iconSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, ngImport: i0, template: `
539
+ <button
540
+ class="tiptap-button"
541
+ [class.is-active]="active()"
542
+ [class.is-disabled]="disabled()"
543
+ [class.text-button]="variant() === 'text'"
544
+ [class.danger]="variant() === 'danger'"
545
+ [class.small]="size() === 'small'"
546
+ [class.medium]="size() === 'medium'"
547
+ [class.large]="size() === 'large'"
548
+ [disabled]="disabled()"
549
+ [attr.title]="title()"
550
+ (mousedown)="onMouseDown($event)"
551
+ (click)="onClick.emit($event)"
552
+ type="button"
553
+ >
554
+ <span
555
+ class="material-symbols-outlined"
556
+ [class.icon-small]="iconSize() === 'small'"
557
+ [class.icon-medium]="iconSize() === 'medium'"
558
+ [class.icon-large]="iconSize() === 'large'"
559
+ >{{ icon() }}</span
560
+ >
561
+ <ng-content></ng-content>
562
+ </button>
563
563
  `, isInline: true, styles: [".tiptap-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:8px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);color:#64748b;position:relative;overflow:hidden}.tiptap-button:before{content:\"\";position:absolute;inset:0;background:linear-gradient(135deg,#6366f1,#8b5cf6);opacity:0;transition:opacity .2s ease;border-radius:8px}.tiptap-button:hover{color:#6366f1;transform:translateY(-1px)}.tiptap-button:hover:before{opacity:.1}.tiptap-button:active{transform:translateY(0)}.tiptap-button.is-active{color:#6366f1;background:#6366f11a}.tiptap-button.is-active:before{opacity:.15}.tiptap-button.is-active:hover{background:#6366f126}.tiptap-button:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tiptap-button:disabled:hover{transform:none;color:#64748b}.tiptap-button:disabled:before{opacity:0}.tiptap-button .material-symbols-outlined{font-size:20px;position:relative;z-index:1}.tiptap-button .material-symbols-outlined.icon-small{font-size:16px}.tiptap-button .material-symbols-outlined.icon-medium{font-size:20px}.tiptap-button .material-symbols-outlined.icon-large{font-size:24px}.tiptap-button.text-button{width:auto;padding:0 12px;font-size:14px;font-weight:500}.tiptap-button.color-button{width:28px;height:28px;border-radius:50%;border:2px solid transparent;transition:all .2s ease}.tiptap-button.color-button:hover{border-color:#e2e8f0;transform:scale(1.1)}.tiptap-button.color-button.is-active{border-color:#6366f1;box-shadow:0 0 0 2px #6366f133}.tiptap-button.primary{background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff}.tiptap-button.primary:hover{background:linear-gradient(135deg,#5b21b6,#7c3aed);color:#fff}.tiptap-button.secondary{background:#f1f5f9;color:#64748b}.tiptap-button.secondary:hover{background:#e2e8f0;color:#475569}.tiptap-button.danger{color:#ef4444}.tiptap-button.danger:hover{color:#dc2626;background:#ef44441a}.tiptap-button.danger:before{background:linear-gradient(135deg,#ef4444,#dc2626)}.tiptap-button.small{width:24px;height:24px}.tiptap-button.medium{width:32px;height:32px}.tiptap-button.large{width:40px;height:40px}.tiptap-button.has-badge{position:relative}.tiptap-button .badge{position:absolute;top:-4px;right:-4px;background:#ef4444;color:#fff;font-size:10px;padding:2px 4px;border-radius:8px;min-width:16px;text-align:center;line-height:1}.tiptap-button.has-tooltip{position:relative}.tiptap-button .tooltip{position:absolute;bottom:-30px;left:50%;transform:translate(-50%);background:#000c;color:#fff;padding:4px 8px;border-radius:4px;font-size:12px;white-space:nowrap;opacity:0;visibility:hidden;transition:all .2s ease;z-index:1000}.tiptap-button:hover .tooltip{opacity:1;visibility:visible}@keyframes pulse{0%,to{box-shadow:0 0 #6366f166}50%{box-shadow:0 0 0 4px #6366f100}}.tiptap-button.is-active.pulse{animation:pulse 2s infinite}@media (max-width: 768px){.tiptap-button{width:32px;height:32px}.tiptap-button .material-symbols-outlined{font-size:18px}.tiptap-button.text-button{padding:0 8px;font-size:13px}}\n"] }); }
564
564
  }
565
565
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapButtonComponent, decorators: [{
566
566
  type: Component,
567
- args: [{ selector: "tiptap-button", standalone: true, template: `
568
- <button
569
- class="tiptap-button"
570
- [class.is-active]="active()"
571
- [class.is-disabled]="disabled()"
572
- [class.text-button]="variant() === 'text'"
573
- [class.danger]="variant() === 'danger'"
574
- [class.small]="size() === 'small'"
575
- [class.medium]="size() === 'medium'"
576
- [class.large]="size() === 'large'"
577
- [disabled]="disabled()"
578
- [attr.title]="title()"
579
- (mousedown)="onMouseDown($event)"
580
- (click)="onClick.emit($event)"
581
- type="button"
582
- >
583
- <span
584
- class="material-symbols-outlined"
585
- [class.icon-small]="iconSize() === 'small'"
586
- [class.icon-medium]="iconSize() === 'medium'"
587
- [class.icon-large]="iconSize() === 'large'"
588
- >{{ icon() }}</span
589
- >
590
- <ng-content></ng-content>
591
- </button>
567
+ args: [{ selector: "tiptap-button", standalone: true, template: `
568
+ <button
569
+ class="tiptap-button"
570
+ [class.is-active]="active()"
571
+ [class.is-disabled]="disabled()"
572
+ [class.text-button]="variant() === 'text'"
573
+ [class.danger]="variant() === 'danger'"
574
+ [class.small]="size() === 'small'"
575
+ [class.medium]="size() === 'medium'"
576
+ [class.large]="size() === 'large'"
577
+ [disabled]="disabled()"
578
+ [attr.title]="title()"
579
+ (mousedown)="onMouseDown($event)"
580
+ (click)="onClick.emit($event)"
581
+ type="button"
582
+ >
583
+ <span
584
+ class="material-symbols-outlined"
585
+ [class.icon-small]="iconSize() === 'small'"
586
+ [class.icon-medium]="iconSize() === 'medium'"
587
+ [class.icon-large]="iconSize() === 'large'"
588
+ >{{ icon() }}</span
589
+ >
590
+ <ng-content></ng-content>
591
+ </button>
592
592
  `, styles: [".tiptap-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:8px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);color:#64748b;position:relative;overflow:hidden}.tiptap-button:before{content:\"\";position:absolute;inset:0;background:linear-gradient(135deg,#6366f1,#8b5cf6);opacity:0;transition:opacity .2s ease;border-radius:8px}.tiptap-button:hover{color:#6366f1;transform:translateY(-1px)}.tiptap-button:hover:before{opacity:.1}.tiptap-button:active{transform:translateY(0)}.tiptap-button.is-active{color:#6366f1;background:#6366f11a}.tiptap-button.is-active:before{opacity:.15}.tiptap-button.is-active:hover{background:#6366f126}.tiptap-button:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tiptap-button:disabled:hover{transform:none;color:#64748b}.tiptap-button:disabled:before{opacity:0}.tiptap-button .material-symbols-outlined{font-size:20px;position:relative;z-index:1}.tiptap-button .material-symbols-outlined.icon-small{font-size:16px}.tiptap-button .material-symbols-outlined.icon-medium{font-size:20px}.tiptap-button .material-symbols-outlined.icon-large{font-size:24px}.tiptap-button.text-button{width:auto;padding:0 12px;font-size:14px;font-weight:500}.tiptap-button.color-button{width:28px;height:28px;border-radius:50%;border:2px solid transparent;transition:all .2s ease}.tiptap-button.color-button:hover{border-color:#e2e8f0;transform:scale(1.1)}.tiptap-button.color-button.is-active{border-color:#6366f1;box-shadow:0 0 0 2px #6366f133}.tiptap-button.primary{background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff}.tiptap-button.primary:hover{background:linear-gradient(135deg,#5b21b6,#7c3aed);color:#fff}.tiptap-button.secondary{background:#f1f5f9;color:#64748b}.tiptap-button.secondary:hover{background:#e2e8f0;color:#475569}.tiptap-button.danger{color:#ef4444}.tiptap-button.danger:hover{color:#dc2626;background:#ef44441a}.tiptap-button.danger:before{background:linear-gradient(135deg,#ef4444,#dc2626)}.tiptap-button.small{width:24px;height:24px}.tiptap-button.medium{width:32px;height:32px}.tiptap-button.large{width:40px;height:40px}.tiptap-button.has-badge{position:relative}.tiptap-button .badge{position:absolute;top:-4px;right:-4px;background:#ef4444;color:#fff;font-size:10px;padding:2px 4px;border-radius:8px;min-width:16px;text-align:center;line-height:1}.tiptap-button.has-tooltip{position:relative}.tiptap-button .tooltip{position:absolute;bottom:-30px;left:50%;transform:translate(-50%);background:#000c;color:#fff;padding:4px 8px;border-radius:4px;font-size:12px;white-space:nowrap;opacity:0;visibility:hidden;transition:all .2s ease;z-index:1000}.tiptap-button:hover .tooltip{opacity:1;visibility:visible}@keyframes pulse{0%,to{box-shadow:0 0 #6366f166}50%{box-shadow:0 0 0 4px #6366f100}}.tiptap-button.is-active.pulse{animation:pulse 2s infinite}@media (max-width: 768px){.tiptap-button{width:32px;height:32px}.tiptap-button .material-symbols-outlined{font-size:18px}.tiptap-button.text-button{padding:0 8px;font-size:13px}}\n"] }]
593
593
  }] });
594
594
 
@@ -638,16 +638,6 @@ class TiptapBubbleMenuComponent {
638
638
  const isImageSelected = ed.isActive("image") || ed.isActive("resizableImage");
639
639
  const isTableCellSelected = ed.isActive("tableCell") || ed.isActive("tableHeader");
640
640
  const hasCellSelection = selection instanceof CellSelection;
641
- console.log("TextBubbleMenu - updateMenu:", {
642
- hasTextSelection,
643
- isImageSelected,
644
- isTableCellSelected,
645
- hasCellSelection,
646
- selectionType: selection.constructor.name,
647
- selectionEmpty: selection.empty,
648
- from,
649
- to,
650
- });
651
641
  // Ne montrer le menu texte que si :
652
642
  // - Il y a une sélection de texte (pas une sélection de cellules multiples)
653
643
  // - Aucune image n'est sélectionnée (priorité aux images)
@@ -829,150 +819,150 @@ class TiptapBubbleMenuComponent {
829
819
  }
830
820
  }
831
821
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapBubbleMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
832
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: TiptapBubbleMenuComponent, isStandalone: true, selector: "tiptap-bubble-menu", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true }], ngImport: i0, template: `
833
- <div #menuRef class="bubble-menu">
834
- @if (bubbleMenuConfig().bold) {
835
- <tiptap-button
836
- icon="format_bold"
837
- title="Gras"
838
- [active]="isActive('bold')"
839
- (click)="onCommand('bold', $event)"
840
- ></tiptap-button>
841
- } @if (bubbleMenuConfig().italic) {
842
- <tiptap-button
843
- icon="format_italic"
844
- title="Italique"
845
- [active]="isActive('italic')"
846
- (click)="onCommand('italic', $event)"
847
- ></tiptap-button>
848
- } @if (bubbleMenuConfig().underline) {
849
- <tiptap-button
850
- icon="format_underlined"
851
- title="Souligné"
852
- [active]="isActive('underline')"
853
- (click)="onCommand('underline', $event)"
854
- ></tiptap-button>
855
- } @if (bubbleMenuConfig().strike) {
856
- <tiptap-button
857
- icon="strikethrough_s"
858
- title="Barré"
859
- [active]="isActive('strike')"
860
- (click)="onCommand('strike', $event)"
861
- ></tiptap-button>
862
- } @if (bubbleMenuConfig().superscript) {
863
- <tiptap-button
864
- icon="superscript"
865
- title="Exposant"
866
- [active]="isActive('superscript')"
867
- (click)="onCommand('superscript', $event)"
868
- ></tiptap-button>
869
- } @if (bubbleMenuConfig().subscript) {
870
- <tiptap-button
871
- icon="subscript"
872
- title="Indice"
873
- [active]="isActive('subscript')"
874
- (click)="onCommand('subscript', $event)"
875
- ></tiptap-button>
876
- } @if (bubbleMenuConfig().highlight) {
877
- <tiptap-button
878
- icon="highlight"
879
- title="Surbrillance"
880
- [active]="isActive('highlight')"
881
- (click)="onCommand('highlight', $event)"
882
- ></tiptap-button>
883
- } @if (bubbleMenuConfig().separator && (bubbleMenuConfig().code ||
884
- bubbleMenuConfig().link)) {
885
- <div class="tiptap-separator"></div>
886
- } @if (bubbleMenuConfig().code) {
887
- <tiptap-button
888
- icon="code"
889
- title="Code"
890
- [active]="isActive('code')"
891
- (click)="onCommand('code', $event)"
892
- ></tiptap-button>
893
- } @if (bubbleMenuConfig().link) {
894
- <tiptap-button
895
- icon="link"
896
- title="Lien"
897
- [active]="isActive('link')"
898
- (click)="onCommand('link', $event)"
899
- ></tiptap-button>
900
- }
901
- </div>
822
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: TiptapBubbleMenuComponent, isStandalone: true, selector: "tiptap-bubble-menu", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true }], ngImport: i0, template: `
823
+ <div #menuRef class="bubble-menu">
824
+ @if (bubbleMenuConfig().bold) {
825
+ <tiptap-button
826
+ icon="format_bold"
827
+ title="Gras"
828
+ [active]="isActive('bold')"
829
+ (click)="onCommand('bold', $event)"
830
+ ></tiptap-button>
831
+ } @if (bubbleMenuConfig().italic) {
832
+ <tiptap-button
833
+ icon="format_italic"
834
+ title="Italique"
835
+ [active]="isActive('italic')"
836
+ (click)="onCommand('italic', $event)"
837
+ ></tiptap-button>
838
+ } @if (bubbleMenuConfig().underline) {
839
+ <tiptap-button
840
+ icon="format_underlined"
841
+ title="Souligné"
842
+ [active]="isActive('underline')"
843
+ (click)="onCommand('underline', $event)"
844
+ ></tiptap-button>
845
+ } @if (bubbleMenuConfig().strike) {
846
+ <tiptap-button
847
+ icon="strikethrough_s"
848
+ title="Barré"
849
+ [active]="isActive('strike')"
850
+ (click)="onCommand('strike', $event)"
851
+ ></tiptap-button>
852
+ } @if (bubbleMenuConfig().superscript) {
853
+ <tiptap-button
854
+ icon="superscript"
855
+ title="Exposant"
856
+ [active]="isActive('superscript')"
857
+ (click)="onCommand('superscript', $event)"
858
+ ></tiptap-button>
859
+ } @if (bubbleMenuConfig().subscript) {
860
+ <tiptap-button
861
+ icon="subscript"
862
+ title="Indice"
863
+ [active]="isActive('subscript')"
864
+ (click)="onCommand('subscript', $event)"
865
+ ></tiptap-button>
866
+ } @if (bubbleMenuConfig().highlight) {
867
+ <tiptap-button
868
+ icon="highlight"
869
+ title="Surbrillance"
870
+ [active]="isActive('highlight')"
871
+ (click)="onCommand('highlight', $event)"
872
+ ></tiptap-button>
873
+ } @if (bubbleMenuConfig().separator && (bubbleMenuConfig().code ||
874
+ bubbleMenuConfig().link)) {
875
+ <div class="tiptap-separator"></div>
876
+ } @if (bubbleMenuConfig().code) {
877
+ <tiptap-button
878
+ icon="code"
879
+ title="Code"
880
+ [active]="isActive('code')"
881
+ (click)="onCommand('code', $event)"
882
+ ></tiptap-button>
883
+ } @if (bubbleMenuConfig().link) {
884
+ <tiptap-button
885
+ icon="link"
886
+ title="Lien"
887
+ [active]="isActive('link')"
888
+ (click)="onCommand('link', $event)"
889
+ ></tiptap-button>
890
+ }
891
+ </div>
902
892
  `, isInline: true, dependencies: [{ kind: "component", type: TiptapButtonComponent, selector: "tiptap-button", inputs: ["icon", "title", "active", "disabled", "variant", "size", "iconSize"], outputs: ["onClick"] }] }); }
903
893
  }
904
894
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapBubbleMenuComponent, decorators: [{
905
895
  type: Component,
906
- args: [{ selector: "tiptap-bubble-menu", standalone: true, imports: [TiptapButtonComponent], template: `
907
- <div #menuRef class="bubble-menu">
908
- @if (bubbleMenuConfig().bold) {
909
- <tiptap-button
910
- icon="format_bold"
911
- title="Gras"
912
- [active]="isActive('bold')"
913
- (click)="onCommand('bold', $event)"
914
- ></tiptap-button>
915
- } @if (bubbleMenuConfig().italic) {
916
- <tiptap-button
917
- icon="format_italic"
918
- title="Italique"
919
- [active]="isActive('italic')"
920
- (click)="onCommand('italic', $event)"
921
- ></tiptap-button>
922
- } @if (bubbleMenuConfig().underline) {
923
- <tiptap-button
924
- icon="format_underlined"
925
- title="Souligné"
926
- [active]="isActive('underline')"
927
- (click)="onCommand('underline', $event)"
928
- ></tiptap-button>
929
- } @if (bubbleMenuConfig().strike) {
930
- <tiptap-button
931
- icon="strikethrough_s"
932
- title="Barré"
933
- [active]="isActive('strike')"
934
- (click)="onCommand('strike', $event)"
935
- ></tiptap-button>
936
- } @if (bubbleMenuConfig().superscript) {
937
- <tiptap-button
938
- icon="superscript"
939
- title="Exposant"
940
- [active]="isActive('superscript')"
941
- (click)="onCommand('superscript', $event)"
942
- ></tiptap-button>
943
- } @if (bubbleMenuConfig().subscript) {
944
- <tiptap-button
945
- icon="subscript"
946
- title="Indice"
947
- [active]="isActive('subscript')"
948
- (click)="onCommand('subscript', $event)"
949
- ></tiptap-button>
950
- } @if (bubbleMenuConfig().highlight) {
951
- <tiptap-button
952
- icon="highlight"
953
- title="Surbrillance"
954
- [active]="isActive('highlight')"
955
- (click)="onCommand('highlight', $event)"
956
- ></tiptap-button>
957
- } @if (bubbleMenuConfig().separator && (bubbleMenuConfig().code ||
958
- bubbleMenuConfig().link)) {
959
- <div class="tiptap-separator"></div>
960
- } @if (bubbleMenuConfig().code) {
961
- <tiptap-button
962
- icon="code"
963
- title="Code"
964
- [active]="isActive('code')"
965
- (click)="onCommand('code', $event)"
966
- ></tiptap-button>
967
- } @if (bubbleMenuConfig().link) {
968
- <tiptap-button
969
- icon="link"
970
- title="Lien"
971
- [active]="isActive('link')"
972
- (click)="onCommand('link', $event)"
973
- ></tiptap-button>
974
- }
975
- </div>
896
+ args: [{ selector: "tiptap-bubble-menu", standalone: true, imports: [TiptapButtonComponent], template: `
897
+ <div #menuRef class="bubble-menu">
898
+ @if (bubbleMenuConfig().bold) {
899
+ <tiptap-button
900
+ icon="format_bold"
901
+ title="Gras"
902
+ [active]="isActive('bold')"
903
+ (click)="onCommand('bold', $event)"
904
+ ></tiptap-button>
905
+ } @if (bubbleMenuConfig().italic) {
906
+ <tiptap-button
907
+ icon="format_italic"
908
+ title="Italique"
909
+ [active]="isActive('italic')"
910
+ (click)="onCommand('italic', $event)"
911
+ ></tiptap-button>
912
+ } @if (bubbleMenuConfig().underline) {
913
+ <tiptap-button
914
+ icon="format_underlined"
915
+ title="Souligné"
916
+ [active]="isActive('underline')"
917
+ (click)="onCommand('underline', $event)"
918
+ ></tiptap-button>
919
+ } @if (bubbleMenuConfig().strike) {
920
+ <tiptap-button
921
+ icon="strikethrough_s"
922
+ title="Barré"
923
+ [active]="isActive('strike')"
924
+ (click)="onCommand('strike', $event)"
925
+ ></tiptap-button>
926
+ } @if (bubbleMenuConfig().superscript) {
927
+ <tiptap-button
928
+ icon="superscript"
929
+ title="Exposant"
930
+ [active]="isActive('superscript')"
931
+ (click)="onCommand('superscript', $event)"
932
+ ></tiptap-button>
933
+ } @if (bubbleMenuConfig().subscript) {
934
+ <tiptap-button
935
+ icon="subscript"
936
+ title="Indice"
937
+ [active]="isActive('subscript')"
938
+ (click)="onCommand('subscript', $event)"
939
+ ></tiptap-button>
940
+ } @if (bubbleMenuConfig().highlight) {
941
+ <tiptap-button
942
+ icon="highlight"
943
+ title="Surbrillance"
944
+ [active]="isActive('highlight')"
945
+ (click)="onCommand('highlight', $event)"
946
+ ></tiptap-button>
947
+ } @if (bubbleMenuConfig().separator && (bubbleMenuConfig().code ||
948
+ bubbleMenuConfig().link)) {
949
+ <div class="tiptap-separator"></div>
950
+ } @if (bubbleMenuConfig().code) {
951
+ <tiptap-button
952
+ icon="code"
953
+ title="Code"
954
+ [active]="isActive('code')"
955
+ (click)="onCommand('code', $event)"
956
+ ></tiptap-button>
957
+ } @if (bubbleMenuConfig().link) {
958
+ <tiptap-button
959
+ icon="link"
960
+ title="Lien"
961
+ [active]="isActive('link')"
962
+ (click)="onCommand('link', $event)"
963
+ ></tiptap-button>
964
+ }
965
+ </div>
976
966
  ` }]
977
967
  }], ctorParameters: () => [], propDecorators: { menuRef: [{
978
968
  type: ViewChild,
@@ -2779,22 +2769,10 @@ class TiptapCellBubbleMenuComponent {
2779
2769
  selection.$headCell.pos;
2780
2770
  const hasTextSelection = !selection.empty && !(selection instanceof CellSelection);
2781
2771
  const isTableCell = ed.isActive("tableCell") || ed.isActive("tableHeader");
2782
- console.log("CellBubbleMenu - updateMenu:", {
2783
- hasCellSelection,
2784
- isSingleCellSelected: this.isSingleCellSelected,
2785
- hasTextSelection,
2786
- isTableCell,
2787
- selectionEmpty: selection.empty,
2788
- selectionType: selection.constructor.name,
2789
- from,
2790
- to,
2791
- isEditable: ed.isEditable,
2792
- });
2793
2772
  // Le menu de cellule ne s'affiche QUE pour les sélections de cellules multiples
2794
2773
  // (pas pour la sélection de texte dans une cellule)
2795
2774
  const shouldShow = hasCellSelection && isTableCell && ed.isEditable;
2796
2775
  if (shouldShow) {
2797
- console.log("CellBubbleMenu - Affichage du menu de cellules");
2798
2776
  this.showTippy();
2799
2777
  }
2800
2778
  else {
@@ -3510,7 +3488,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
3510
3488
  `, styles: [".tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:4px 8px;background:#f8f9fa;border-bottom:1px solid #e2e8f0;flex-wrap:wrap;min-height:32px;position:relative}.toolbar-group{display:flex;align-items:center;gap:2px;padding:0 4px}.toolbar-separator{width:1px;height:24px;background:#e2e8f0;margin:0 4px}@media (max-width: 768px){.tiptap-toolbar{padding:6px 8px;gap:2px}.toolbar-group{gap:1px}}@keyframes toolbarSlideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.tiptap-toolbar{animation:toolbarSlideIn .3s cubic-bezier(.4,0,.2,1)}\n"] }]
3511
3489
  }], ctorParameters: () => [{ type: EditorCommandsService }] });
3512
3490
 
3513
- const DEFAULT_SLASH_COMMANDS = [
3491
+ const DEFAULT_SLASH_COMMANDS$1 = [
3514
3492
  {
3515
3493
  title: "Titre 1",
3516
3494
  description: "Grand titre de section",
@@ -3647,7 +3625,7 @@ class TiptapSlashCommandsComponent {
3647
3625
  constructor() {
3648
3626
  this.editor = input.required();
3649
3627
  this.config = input({
3650
- commands: DEFAULT_SLASH_COMMANDS,
3628
+ commands: DEFAULT_SLASH_COMMANDS$1,
3651
3629
  });
3652
3630
  // Output pour l'upload d'image
3653
3631
  this.imageUploadRequested = output();
@@ -3660,7 +3638,7 @@ class TiptapSlashCommandsComponent {
3660
3638
  // Signal pour l'index sélectionné
3661
3639
  this.selectedIndex = signal(0);
3662
3640
  this.commands = computed(() => {
3663
- const configCommands = this.config().commands || DEFAULT_SLASH_COMMANDS;
3641
+ const configCommands = this.config().commands || DEFAULT_SLASH_COMMANDS$1;
3664
3642
  // Remplacer la commande image par une version qui utilise l'output
3665
3643
  return configCommands.map((command) => {
3666
3644
  if (command.icon === "image") {
@@ -4380,152 +4358,327 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
4380
4358
  }]
4381
4359
  }] });
4382
4360
 
4383
- // Configuration par défaut de la toolbar
4384
- const DEFAULT_TOOLBAR_CONFIG = {
4385
- bold: true,
4386
- italic: true,
4387
- underline: true,
4388
- strike: true,
4389
- code: true,
4390
- superscript: false,
4391
- subscript: false,
4392
- highlight: true,
4393
- heading1: true,
4394
- heading2: true,
4395
- heading3: true,
4396
- bulletList: true,
4397
- orderedList: true,
4398
- blockquote: true,
4399
- alignLeft: false,
4400
- alignCenter: false,
4401
- alignRight: false,
4402
- alignJustify: false,
4403
- link: true,
4404
- image: true,
4405
- horizontalRule: true,
4406
- table: true,
4407
- undo: true,
4408
- redo: true,
4409
- clear: false, // Désactivé par défaut (opt-in)
4410
- separator: true,
4411
- };
4412
- // Configuration par défaut du bubble menu
4413
- const DEFAULT_BUBBLE_MENU_CONFIG = {
4414
- bold: true,
4415
- italic: true,
4416
- underline: true,
4417
- strike: true,
4418
- code: true,
4419
- superscript: false,
4420
- subscript: false,
4421
- highlight: true,
4422
- link: true,
4423
- separator: true,
4424
- };
4425
- // Configuration par défaut du bubble menu image
4426
- const DEFAULT_IMAGE_BUBBLE_MENU_CONFIG = {
4427
- changeImage: true,
4428
- resizeSmall: true,
4429
- resizeMedium: true,
4430
- resizeLarge: true,
4431
- resizeOriginal: true,
4432
- deleteImage: true,
4433
- separator: true,
4434
- };
4435
- // Configuration par défaut du menu de table
4436
- const DEFAULT_TABLE_MENU_CONFIG = {
4437
- addRowBefore: true,
4438
- addRowAfter: true,
4439
- deleteRow: true,
4440
- addColumnBefore: true,
4441
- addColumnAfter: true,
4442
- deleteColumn: true,
4443
- toggleHeaderRow: true,
4444
- toggleHeaderColumn: true,
4445
- deleteTable: true,
4446
- separator: true,
4447
- };
4448
- const DEFAULT_CELL_MENU_CONFIG = {
4449
- mergeCells: true,
4450
- splitCell: true,
4451
- };
4452
- class AngularTiptapEditorComponent {
4453
- constructor() {
4454
- // Nouveaux inputs avec signal
4455
- this.content = input("");
4456
- this.placeholder = input("");
4457
- this.editable = input(true);
4458
- this.minHeight = input(200);
4459
- this.height = input(undefined);
4460
- this.maxHeight = input(undefined);
4461
- this.showToolbar = input(true);
4462
- this.showCharacterCount = input(true);
4463
- this.maxCharacters = input(undefined);
4464
- this.enableOfficePaste = input(true);
4465
- this.enableSlashCommands = input(true);
4466
- this.slashCommandsConfig = input(undefined);
4467
- this.locale = input(undefined);
4468
- // Nouveaux inputs pour les bubble menus
4469
- this.showBubbleMenu = input(true);
4470
- this.bubbleMenu = input(DEFAULT_BUBBLE_MENU_CONFIG);
4471
- this.showImageBubbleMenu = input(true);
4472
- this.imageBubbleMenu = input(DEFAULT_IMAGE_BUBBLE_MENU_CONFIG);
4473
- // Nouveau input pour la configuration de la toolbar
4474
- this.toolbar = input({});
4475
- // Nouveau input pour la configuration de l'upload d'images
4476
- this.imageUpload = input({});
4477
- // Nouveaux outputs
4478
- this.contentChange = output();
4479
- this.editorCreated = output();
4480
- this.editorUpdate = output();
4481
- this.editorFocus = output();
4482
- this.editorBlur = output();
4483
- // ViewChild avec signal
4484
- this.editorElement = viewChild.required("editorElement");
4485
- // Signals privés pour l'état interne
4486
- this._editor = signal(null);
4487
- this._characterCount = signal(0);
4488
- this._wordCount = signal(0);
4489
- this._isDragOver = signal(false);
4490
- this._editorFullyInitialized = signal(false);
4491
- // Accès en lecture seule aux signaux
4492
- this.editor = this._editor.asReadonly();
4493
- this.characterCount = this._characterCount.asReadonly();
4494
- this.wordCount = this._wordCount.asReadonly();
4495
- this.isDragOver = this._isDragOver.asReadonly();
4496
- this.editorFullyInitialized = this._editorFullyInitialized.asReadonly();
4497
- // Computed pour les états de l'éditeur
4498
- this.isEditorReady = computed(() => this.editor() !== null);
4499
- // Computed pour la configuration de la toolbar
4500
- this.toolbarConfig = computed(() => Object.keys(this.toolbar()).length === 0
4501
- ? DEFAULT_TOOLBAR_CONFIG
4502
- : this.toolbar());
4503
- // Computed pour la configuration du bubble menu
4504
- this.bubbleMenuConfig = computed(() => Object.keys(this.bubbleMenu()).length === 0
4505
- ? DEFAULT_BUBBLE_MENU_CONFIG
4506
- : { ...DEFAULT_BUBBLE_MENU_CONFIG, ...this.bubbleMenu() });
4507
- // Computed pour la configuration du bubble menu image
4508
- this.imageBubbleMenuConfig = computed(() => Object.keys(this.imageBubbleMenu()).length === 0
4509
- ? DEFAULT_IMAGE_BUBBLE_MENU_CONFIG
4510
- : { ...DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, ...this.imageBubbleMenu() });
4511
- // Computed pour la configuration du bubble menu table
4512
- this.tableBubbleMenuConfig = computed(() => ({
4513
- addRowBefore: true,
4514
- addRowAfter: true,
4515
- deleteRow: true,
4516
- addColumnBefore: true,
4517
- addColumnAfter: true,
4518
- deleteColumn: true,
4519
- deleteTable: true,
4520
- toggleHeaderRow: true,
4521
- toggleHeaderColumn: true,
4522
- }));
4523
- // Computed pour la configuration du menu de cellules
4524
- this.cellBubbleMenuConfig = computed(() => ({
4525
- mergeCells: true,
4526
- splitCell: true,
4527
- }));
4528
- // Computed pour la configuration de l'upload d'images
4361
+ /**
4362
+ * Clés des commandes dans l'ordre de création
4363
+ */
4364
+ const SLASH_COMMAND_KEYS = [
4365
+ "heading1",
4366
+ "heading2",
4367
+ "heading3",
4368
+ "bulletList",
4369
+ "orderedList",
4370
+ "blockquote",
4371
+ "code",
4372
+ "image",
4373
+ "horizontalRule",
4374
+ "table",
4375
+ ];
4376
+ /**
4377
+ * Factory function pour créer les slash commands traduits
4378
+ */
4379
+ function createI18nSlashCommands(i18nService) {
4380
+ const slashCommands = i18nService.slashCommands();
4381
+ return [
4382
+ {
4383
+ title: slashCommands.heading1.title,
4384
+ description: slashCommands.heading1.description,
4385
+ icon: "format_h1",
4386
+ keywords: slashCommands.heading1.keywords,
4387
+ command: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run(),
4388
+ },
4389
+ {
4390
+ title: slashCommands.heading2.title,
4391
+ description: slashCommands.heading2.description,
4392
+ icon: "format_h2",
4393
+ keywords: slashCommands.heading2.keywords,
4394
+ command: (editor) => editor.chain().focus().toggleHeading({ level: 2 }).run(),
4395
+ },
4396
+ {
4397
+ title: slashCommands.heading3.title,
4398
+ description: slashCommands.heading3.description,
4399
+ icon: "format_h3",
4400
+ keywords: slashCommands.heading3.keywords,
4401
+ command: (editor) => editor.chain().focus().toggleHeading({ level: 3 }).run(),
4402
+ },
4403
+ {
4404
+ title: slashCommands.bulletList.title,
4405
+ description: slashCommands.bulletList.description,
4406
+ icon: "format_list_bulleted",
4407
+ keywords: slashCommands.bulletList.keywords,
4408
+ command: (editor) => editor.chain().focus().toggleBulletList().run(),
4409
+ },
4410
+ {
4411
+ title: slashCommands.orderedList.title,
4412
+ description: slashCommands.orderedList.description,
4413
+ icon: "format_list_numbered",
4414
+ keywords: slashCommands.orderedList.keywords,
4415
+ command: (editor) => editor.chain().focus().toggleOrderedList().run(),
4416
+ },
4417
+ {
4418
+ title: slashCommands.blockquote.title,
4419
+ description: slashCommands.blockquote.description,
4420
+ icon: "format_quote",
4421
+ keywords: slashCommands.blockquote.keywords,
4422
+ command: (editor) => editor.chain().focus().toggleBlockquote().run(),
4423
+ },
4424
+ {
4425
+ title: slashCommands.code.title,
4426
+ description: slashCommands.code.description,
4427
+ icon: "code",
4428
+ keywords: slashCommands.code.keywords,
4429
+ command: (editor) => editor.chain().focus().toggleCodeBlock().run(),
4430
+ },
4431
+ {
4432
+ title: slashCommands.image.title,
4433
+ description: slashCommands.image.description,
4434
+ icon: "image",
4435
+ keywords: slashCommands.image.keywords,
4436
+ command: (editor) => {
4437
+ // Créer un input file temporaire pour sélectionner une image
4438
+ const input = document.createElement("input");
4439
+ input.type = "file";
4440
+ input.accept = "image/*";
4441
+ input.style.display = "none";
4442
+ input.addEventListener("change", async (e) => {
4443
+ const file = e.target.files?.[0];
4444
+ if (file && file.type.startsWith("image/")) {
4445
+ try {
4446
+ // Utiliser la méthode de compression unifiée
4447
+ const canvas = document.createElement("canvas");
4448
+ const ctx = canvas.getContext("2d");
4449
+ const img = new Image();
4450
+ img.onload = () => {
4451
+ // Vérifier les dimensions (max 1920x1080)
4452
+ const maxWidth = 1920;
4453
+ const maxHeight = 1080;
4454
+ let { width, height } = img;
4455
+ // Redimensionner si nécessaire
4456
+ if (width > maxWidth || height > maxHeight) {
4457
+ const ratio = Math.min(maxWidth / width, maxHeight / height);
4458
+ width *= ratio;
4459
+ height *= ratio;
4460
+ }
4461
+ canvas.width = width;
4462
+ canvas.height = height;
4463
+ // Dessiner l'image redimensionnée
4464
+ ctx?.drawImage(img, 0, 0, width, height);
4465
+ // Convertir en base64 avec compression
4466
+ canvas.toBlob((blob) => {
4467
+ if (blob) {
4468
+ const reader = new FileReader();
4469
+ reader.onload = (e) => {
4470
+ const base64 = e.target?.result;
4471
+ if (base64) {
4472
+ // Utiliser setResizableImage avec toutes les propriétés
4473
+ editor
4474
+ .chain()
4475
+ .focus()
4476
+ .setResizableImage({
4477
+ src: base64,
4478
+ alt: file.name,
4479
+ title: `${file.name} (${Math.round(width)}×${Math.round(height)})`,
4480
+ width: Math.round(width),
4481
+ height: Math.round(height),
4482
+ })
4483
+ .run();
4484
+ }
4485
+ };
4486
+ reader.readAsDataURL(blob);
4487
+ }
4488
+ }, file.type, 0.8 // qualité de compression
4489
+ );
4490
+ };
4491
+ img.onerror = () => {
4492
+ console.error(i18nService.editor().imageLoadError);
4493
+ };
4494
+ img.src = URL.createObjectURL(file);
4495
+ }
4496
+ catch (error) {
4497
+ console.error("Error uploading image:", error);
4498
+ }
4499
+ }
4500
+ document.body.removeChild(input);
4501
+ });
4502
+ document.body.appendChild(input);
4503
+ input.click();
4504
+ },
4505
+ },
4506
+ {
4507
+ title: slashCommands.horizontalRule.title,
4508
+ description: slashCommands.horizontalRule.description,
4509
+ icon: "horizontal_rule",
4510
+ keywords: slashCommands.horizontalRule.keywords,
4511
+ command: (editor) => editor.chain().focus().setHorizontalRule().run(),
4512
+ },
4513
+ {
4514
+ title: slashCommands.table.title,
4515
+ description: slashCommands.table.description,
4516
+ icon: "table_view",
4517
+ keywords: slashCommands.table.keywords,
4518
+ command: (editor) => editor.chain().focus().insertTable({ rows: 3, cols: 3 }).run(),
4519
+ },
4520
+ ];
4521
+ }
4522
+ /**
4523
+ * Fonction utilitaire pour filtrer les slash commands selon les commandes actives
4524
+ */
4525
+ function filterSlashCommands(activeCommands, i18nService) {
4526
+ const allCommands = createI18nSlashCommands(i18nService);
4527
+ return allCommands.filter((command, index) => {
4528
+ const commandKey = SLASH_COMMAND_KEYS[index];
4529
+ return commandKey && activeCommands.has(commandKey);
4530
+ });
4531
+ }
4532
+
4533
+ // Configuration par défaut de la toolbar
4534
+ const DEFAULT_TOOLBAR_CONFIG = {
4535
+ bold: true,
4536
+ italic: true,
4537
+ underline: true,
4538
+ strike: true,
4539
+ code: true,
4540
+ superscript: false,
4541
+ subscript: false,
4542
+ highlight: true,
4543
+ heading1: true,
4544
+ heading2: true,
4545
+ heading3: true,
4546
+ bulletList: true,
4547
+ orderedList: true,
4548
+ blockquote: true,
4549
+ alignLeft: false,
4550
+ alignCenter: false,
4551
+ alignRight: false,
4552
+ alignJustify: false,
4553
+ link: true,
4554
+ image: true,
4555
+ horizontalRule: true,
4556
+ table: true,
4557
+ undo: true,
4558
+ redo: true,
4559
+ clear: false, // Désactivé par défaut (opt-in)
4560
+ separator: true,
4561
+ };
4562
+ // Configuration par défaut du bubble menu
4563
+ const DEFAULT_BUBBLE_MENU_CONFIG = {
4564
+ bold: true,
4565
+ italic: true,
4566
+ underline: true,
4567
+ strike: true,
4568
+ code: true,
4569
+ superscript: false,
4570
+ subscript: false,
4571
+ highlight: true,
4572
+ link: true,
4573
+ separator: true,
4574
+ };
4575
+ // Configuration par défaut du bubble menu image
4576
+ const DEFAULT_IMAGE_BUBBLE_MENU_CONFIG = {
4577
+ changeImage: true,
4578
+ resizeSmall: true,
4579
+ resizeMedium: true,
4580
+ resizeLarge: true,
4581
+ resizeOriginal: true,
4582
+ deleteImage: true,
4583
+ separator: true,
4584
+ };
4585
+ // Configuration par défaut du menu de table
4586
+ const DEFAULT_TABLE_MENU_CONFIG = {
4587
+ addRowBefore: true,
4588
+ addRowAfter: true,
4589
+ deleteRow: true,
4590
+ addColumnBefore: true,
4591
+ addColumnAfter: true,
4592
+ deleteColumn: true,
4593
+ toggleHeaderRow: true,
4594
+ toggleHeaderColumn: true,
4595
+ deleteTable: true,
4596
+ separator: true,
4597
+ };
4598
+ const DEFAULT_CELL_MENU_CONFIG = {
4599
+ mergeCells: true,
4600
+ splitCell: true,
4601
+ };
4602
+ const DEFAULT_SLASH_COMMANDS = {
4603
+ commands: [], // Sera rempli par filterSlashCommands
4604
+ };
4605
+ class AngularTiptapEditorComponent {
4606
+ constructor() {
4607
+ // Nouveaux inputs avec signal
4608
+ this.content = input("");
4609
+ this.placeholder = input("");
4610
+ this.editable = input(true);
4611
+ this.minHeight = input(200);
4612
+ this.height = input(undefined);
4613
+ this.maxHeight = input(undefined);
4614
+ this.showToolbar = input(true);
4615
+ this.showCharacterCount = input(true);
4616
+ this.maxCharacters = input(undefined);
4617
+ this.enableOfficePaste = input(true);
4618
+ this.enableSlashCommands = input(true);
4619
+ this.slashCommandsConfig = input(undefined);
4620
+ this.locale = input(undefined);
4621
+ // Nouveaux inputs pour les bubble menus
4622
+ this.showBubbleMenu = input(true);
4623
+ this.bubbleMenu = input(DEFAULT_BUBBLE_MENU_CONFIG);
4624
+ this.showImageBubbleMenu = input(true);
4625
+ this.imageBubbleMenu = input(DEFAULT_IMAGE_BUBBLE_MENU_CONFIG);
4626
+ // Nouveau input pour la configuration de la toolbar
4627
+ this.toolbar = input({});
4628
+ // Nouveau input pour la configuration de l'upload d'images
4629
+ this.imageUpload = input({});
4630
+ // Nouveaux outputs
4631
+ this.contentChange = output();
4632
+ this.editorCreated = output();
4633
+ this.editorUpdate = output();
4634
+ this.editorFocus = output();
4635
+ this.editorBlur = output();
4636
+ // ViewChild avec signal
4637
+ this.editorElement = viewChild.required("editorElement");
4638
+ // Signals privés pour l'état interne
4639
+ this._editor = signal(null);
4640
+ this._characterCount = signal(0);
4641
+ this._wordCount = signal(0);
4642
+ this._isDragOver = signal(false);
4643
+ this._editorFullyInitialized = signal(false);
4644
+ // Accès en lecture seule aux signaux
4645
+ this.editor = this._editor.asReadonly();
4646
+ this.characterCount = this._characterCount.asReadonly();
4647
+ this.wordCount = this._wordCount.asReadonly();
4648
+ this.isDragOver = this._isDragOver.asReadonly();
4649
+ this.editorFullyInitialized = this._editorFullyInitialized.asReadonly();
4650
+ // Computed pour les états de l'éditeur
4651
+ this.isEditorReady = computed(() => this.editor() !== null);
4652
+ // Computed pour la configuration de la toolbar
4653
+ this.toolbarConfig = computed(() => Object.keys(this.toolbar()).length === 0
4654
+ ? DEFAULT_TOOLBAR_CONFIG
4655
+ : this.toolbar());
4656
+ // Computed pour la configuration du bubble menu
4657
+ this.bubbleMenuConfig = computed(() => Object.keys(this.bubbleMenu()).length === 0
4658
+ ? DEFAULT_BUBBLE_MENU_CONFIG
4659
+ : { ...DEFAULT_BUBBLE_MENU_CONFIG, ...this.bubbleMenu() });
4660
+ // Computed pour la configuration du bubble menu image
4661
+ this.imageBubbleMenuConfig = computed(() => Object.keys(this.imageBubbleMenu()).length === 0
4662
+ ? DEFAULT_IMAGE_BUBBLE_MENU_CONFIG
4663
+ : { ...DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, ...this.imageBubbleMenu() });
4664
+ // Computed pour la configuration du bubble menu table
4665
+ this.tableBubbleMenuConfig = computed(() => ({
4666
+ addRowBefore: true,
4667
+ addRowAfter: true,
4668
+ deleteRow: true,
4669
+ addColumnBefore: true,
4670
+ addColumnAfter: true,
4671
+ deleteColumn: true,
4672
+ deleteTable: true,
4673
+ toggleHeaderRow: true,
4674
+ toggleHeaderColumn: true,
4675
+ }));
4676
+ // Computed pour la configuration du menu de cellules
4677
+ this.cellBubbleMenuConfig = computed(() => ({
4678
+ mergeCells: true,
4679
+ splitCell: true,
4680
+ }));
4681
+ // Computed pour la configuration de l'upload d'images
4529
4682
  this.imageUploadConfig = computed(() => ({
4530
4683
  maxSize: 5,
4531
4684
  maxWidth: 1920,
@@ -4539,7 +4692,15 @@ class AngularTiptapEditorComponent {
4539
4692
  ...this.imageUpload(),
4540
4693
  }));
4541
4694
  // Computed pour la configuration des slash commands
4542
- this.slashCommandsConfigComputed = computed(() => this.slashCommandsConfig() ?? { commands: undefined });
4695
+ this.slashCommandsConfigComputed = computed(() => {
4696
+ const config = this.slashCommandsConfig();
4697
+ if (config) {
4698
+ return config;
4699
+ }
4700
+ // Configuration par défaut avec toutes les commandes
4701
+ const allCommands = filterSlashCommands(new Set(SLASH_COMMAND_KEYS), this.i18nService);
4702
+ return { commands: allCommands };
4703
+ });
4543
4704
  this._destroyRef = inject(DestroyRef);
4544
4705
  // NgControl pour gérer les FormControls
4545
4706
  this.ngControl = inject(NgControl, { self: true, optional: true });
@@ -4844,92 +5005,92 @@ class AngularTiptapEditorComponent {
4844
5005
  }
4845
5006
  }
4846
5007
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: AngularTiptapEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4847
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: AngularTiptapEditorComponent, isStandalone: true, selector: "angular-tiptap-editor", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, showCharacterCount: { classPropertyName: "showCharacterCount", publicName: "showCharacterCount", isSignal: true, isRequired: false, transformFunction: null }, maxCharacters: { classPropertyName: "maxCharacters", publicName: "maxCharacters", isSignal: true, isRequired: false, transformFunction: null }, enableOfficePaste: { classPropertyName: "enableOfficePaste", publicName: "enableOfficePaste", isSignal: true, isRequired: false, transformFunction: null }, enableSlashCommands: { classPropertyName: "enableSlashCommands", publicName: "enableSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, slashCommandsConfig: { classPropertyName: "slashCommandsConfig", publicName: "slashCommandsConfig", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, showBubbleMenu: { classPropertyName: "showBubbleMenu", publicName: "showBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, bubbleMenu: { classPropertyName: "bubbleMenu", publicName: "bubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showImageBubbleMenu: { classPropertyName: "showImageBubbleMenu", publicName: "showImageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, imageBubbleMenu: { classPropertyName: "imageBubbleMenu", publicName: "imageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange", editorCreated: "editorCreated", editorUpdate: "editorUpdate", editorFocus: "editorFocus", editorBlur: "editorBlur" }, viewQueries: [{ propertyName: "editorElement", first: true, predicate: ["editorElement"], descendants: true, isSignal: true }], hostDirectives: [{ directive: NoopValueAccessorDirective }], ngImport: i0, template: `
4848
- <div class="tiptap-editor">
4849
- <!-- Toolbar -->
4850
- @if (showToolbar() && editor()) {
4851
- <tiptap-toolbar [editor]="editor()!" [config]="toolbarConfig()">
4852
- <div image-upload class="image-upload-container">
4853
- <tiptap-image-upload
4854
- [config]="imageUploadConfig()"
4855
- (imageSelected)="onImageUploaded($event)"
4856
- (error)="onImageUploadError($event)"
4857
- />
4858
- </div>
4859
- </tiptap-toolbar>
4860
- }
4861
-
4862
- <!-- Contenu de l'éditeur -->
4863
- <div
4864
- #editorElement
4865
- class="tiptap-content"
4866
- [class.drag-over]="isDragOver()"
4867
- (dragover)="onDragOver($event)"
4868
- (drop)="onDrop($event)"
4869
- (click)="onEditorClick($event)"
4870
- ></div>
4871
-
4872
- <!-- Bubble Menu pour le texte -->
4873
- @if (showBubbleMenu() && editor()) {
4874
- <tiptap-bubble-menu
4875
- [editor]="editor()!"
4876
- [config]="bubbleMenuConfig()"
4877
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4878
- ></tiptap-bubble-menu>
4879
- }
4880
-
4881
- <!-- Bubble Menu pour les images -->
4882
- @if (showImageBubbleMenu() && editor()) {
4883
- <tiptap-image-bubble-menu
4884
- [editor]="editor()!"
4885
- [config]="imageBubbleMenuConfig()"
4886
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4887
- ></tiptap-image-bubble-menu>
4888
- }
4889
-
4890
- <!-- Slash Commands -->
4891
- @if (enableSlashCommands() && editor()) {
4892
- <tiptap-slash-commands
4893
- [editor]="editor()!"
4894
- [config]="slashCommandsConfigComputed()"
4895
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4896
- (imageUploadRequested)="onSlashCommandImageUpload($event)"
4897
- ></tiptap-slash-commands>
4898
- }
4899
-
4900
- <!-- Table Menu -->
4901
- @if (editor()) {
4902
- <tiptap-table-bubble-menu
4903
- [editor]="editor()!"
4904
- [config]="tableBubbleMenuConfig()"
4905
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4906
- ></tiptap-table-bubble-menu>
4907
- }
4908
-
4909
- <!-- Cell Menu -->
4910
- @if (editor()) {
4911
- <tiptap-cell-bubble-menu
4912
- [editor]="editor()!"
4913
- [config]="cellBubbleMenuConfig()"
4914
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4915
- ></tiptap-cell-bubble-menu>
4916
- }
4917
-
4918
- <!-- Table Edit Button - Supprimé car remplacé par le menu bubble -->
4919
-
4920
- <!-- Compteur de caractères -->
4921
- @if (showCharacterCount()) {
4922
- <div class="character-count">
4923
- {{ characterCount() }}
4924
- {{ i18nService.editor().character
4925
- }}{{ characterCount() > 1 ? "s" : "" }}, {{ wordCount() }}
4926
- {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
4927
- @if (maxCharacters()) { /
4928
- {{ maxCharacters() }}
4929
- }
4930
- </div>
4931
- }
4932
- </div>
5008
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: AngularTiptapEditorComponent, isStandalone: true, selector: "angular-tiptap-editor", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, showCharacterCount: { classPropertyName: "showCharacterCount", publicName: "showCharacterCount", isSignal: true, isRequired: false, transformFunction: null }, maxCharacters: { classPropertyName: "maxCharacters", publicName: "maxCharacters", isSignal: true, isRequired: false, transformFunction: null }, enableOfficePaste: { classPropertyName: "enableOfficePaste", publicName: "enableOfficePaste", isSignal: true, isRequired: false, transformFunction: null }, enableSlashCommands: { classPropertyName: "enableSlashCommands", publicName: "enableSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, slashCommandsConfig: { classPropertyName: "slashCommandsConfig", publicName: "slashCommandsConfig", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, showBubbleMenu: { classPropertyName: "showBubbleMenu", publicName: "showBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, bubbleMenu: { classPropertyName: "bubbleMenu", publicName: "bubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showImageBubbleMenu: { classPropertyName: "showImageBubbleMenu", publicName: "showImageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, imageBubbleMenu: { classPropertyName: "imageBubbleMenu", publicName: "imageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange", editorCreated: "editorCreated", editorUpdate: "editorUpdate", editorFocus: "editorFocus", editorBlur: "editorBlur" }, viewQueries: [{ propertyName: "editorElement", first: true, predicate: ["editorElement"], descendants: true, isSignal: true }], hostDirectives: [{ directive: NoopValueAccessorDirective }], ngImport: i0, template: `
5009
+ <div class="tiptap-editor">
5010
+ <!-- Toolbar -->
5011
+ @if (showToolbar() && editor()) {
5012
+ <tiptap-toolbar [editor]="editor()!" [config]="toolbarConfig()">
5013
+ <div image-upload class="image-upload-container">
5014
+ <tiptap-image-upload
5015
+ [config]="imageUploadConfig()"
5016
+ (imageSelected)="onImageUploaded($event)"
5017
+ (error)="onImageUploadError($event)"
5018
+ />
5019
+ </div>
5020
+ </tiptap-toolbar>
5021
+ }
5022
+
5023
+ <!-- Contenu de l'éditeur -->
5024
+ <div
5025
+ #editorElement
5026
+ class="tiptap-content"
5027
+ [class.drag-over]="isDragOver()"
5028
+ (dragover)="onDragOver($event)"
5029
+ (drop)="onDrop($event)"
5030
+ (click)="onEditorClick($event)"
5031
+ ></div>
5032
+
5033
+ <!-- Bubble Menu pour le texte -->
5034
+ @if (showBubbleMenu() && editor()) {
5035
+ <tiptap-bubble-menu
5036
+ [editor]="editor()!"
5037
+ [config]="bubbleMenuConfig()"
5038
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5039
+ ></tiptap-bubble-menu>
5040
+ }
5041
+
5042
+ <!-- Bubble Menu pour les images -->
5043
+ @if (showImageBubbleMenu() && editor()) {
5044
+ <tiptap-image-bubble-menu
5045
+ [editor]="editor()!"
5046
+ [config]="imageBubbleMenuConfig()"
5047
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5048
+ ></tiptap-image-bubble-menu>
5049
+ }
5050
+
5051
+ <!-- Slash Commands -->
5052
+ @if (enableSlashCommands() && editor()) {
5053
+ <tiptap-slash-commands
5054
+ [editor]="editor()!"
5055
+ [config]="slashCommandsConfigComputed()"
5056
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5057
+ (imageUploadRequested)="onSlashCommandImageUpload($event)"
5058
+ ></tiptap-slash-commands>
5059
+ }
5060
+
5061
+ <!-- Table Menu -->
5062
+ @if (editor()) {
5063
+ <tiptap-table-bubble-menu
5064
+ [editor]="editor()!"
5065
+ [config]="tableBubbleMenuConfig()"
5066
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5067
+ ></tiptap-table-bubble-menu>
5068
+ }
5069
+
5070
+ <!-- Cell Menu -->
5071
+ @if (editor()) {
5072
+ <tiptap-cell-bubble-menu
5073
+ [editor]="editor()!"
5074
+ [config]="cellBubbleMenuConfig()"
5075
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5076
+ ></tiptap-cell-bubble-menu>
5077
+ }
5078
+
5079
+ <!-- Table Edit Button - Supprimé car remplacé par le menu bubble -->
5080
+
5081
+ <!-- Compteur de caractères -->
5082
+ @if (showCharacterCount()) {
5083
+ <div class="character-count">
5084
+ {{ characterCount() }}
5085
+ {{ i18nService.editor().character
5086
+ }}{{ characterCount() > 1 ? "s" : "" }}, {{ wordCount() }}
5087
+ {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
5088
+ @if (maxCharacters()) { /
5089
+ {{ maxCharacters() }}
5090
+ }
5091
+ </div>
5092
+ }
5093
+ </div>
4933
5094
  `, isInline: true, styles: [".tiptap-editor{border:2px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;transition:border-color .2s ease}.tiptap-editor:focus-within{border-color:#3182ce}.tiptap-content{padding:16px;min-height:var(--editor-min-height, 200px);height:var(--editor-height, auto);max-height:var(--editor-max-height, none);overflow-y:var(--editor-overflow, visible);outline:none;position:relative}.tiptap-content.drag-over{background:#f0f8ff;border:2px dashed #3182ce}.character-count{padding:8px 16px;font-size:12px;color:#718096;text-align:right;border-top:1px solid #e2e8f0;background:#f8f9fa}.image-upload-container{position:relative;display:inline-block}:host ::ng-deep .ProseMirror{outline:none;line-height:1.6;color:#2d3748;min-height:100%;height:100%;word-wrap:break-word;overflow-wrap:break-word}:host ::ng-deep .ProseMirror h1{font-size:2em;font-weight:700;margin-top:0;margin-bottom:.5em}:host ::ng-deep .ProseMirror h2{font-size:1.5em;font-weight:700;margin-top:1em;margin-bottom:.5em}:host ::ng-deep .ProseMirror h3{font-size:1.25em;font-weight:700;margin-top:1em;margin-bottom:.5em}:host ::ng-deep .ProseMirror p{margin:.5em 0}:host ::ng-deep .ProseMirror ul,:host ::ng-deep .ProseMirror ol{padding-left:2em;margin:.5em 0}:host ::ng-deep .ProseMirror blockquote{border-left:4px solid #e2e8f0;margin:1em 0;font-style:italic;background:#f8f9fa;padding:.5em 1em;border-radius:0 4px 4px 0}:host ::ng-deep .ProseMirror code{background:#f1f5f9;padding:.2em .4em;border-radius:3px;font-family:Monaco,Consolas,monospace;font-size:.9em}:host ::ng-deep .ProseMirror pre{background:#1a202c;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;margin:1em 0}:host ::ng-deep .ProseMirror pre code{background:none;color:inherit;padding:0}:host ::ng-deep .ProseMirror p.is-editor-empty:first-child:before{content:attr(data-placeholder);color:#a0aec0;pointer-events:none;float:left;height:0}:host ::ng-deep .ProseMirror[contenteditable=false]{pointer-events:none}:host ::ng-deep .ProseMirror[contenteditable=false] img{cursor:default;pointer-events:none}:host ::ng-deep .ProseMirror[contenteditable=false] img:hover{transform:none;box-shadow:0 2px 8px #0000001a}:host ::ng-deep .ProseMirror[contenteditable=false] img.ProseMirror-selectednode{outline:none}:host ::ng-deep .ProseMirror img{position:relative;display:inline-block;max-width:100%;height:auto;cursor:pointer;transition:all .2s ease;border:2px solid transparent;border-radius:8px}:host ::ng-deep .ProseMirror img:hover{border-color:#e2e8f0;box-shadow:0 2px 4px #0000001a}:host ::ng-deep .ProseMirror img.ProseMirror-selectednode{border-color:#3182ce;box-shadow:0 0 0 3px #3182ce1a;transition:all .2s ease}:host ::ng-deep .ProseMirror .tiptap-image{max-width:100%;height:auto;border-radius:16px;box-shadow:0 4px 20px #00000014;margin:.5em 0;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:block;filter:brightness(1) contrast(1)}:host ::ng-deep .ProseMirror .tiptap-image:hover{box-shadow:0 8px 30px #0000001f;filter:brightness(1.02) contrast(1.02)}:host ::ng-deep .ProseMirror .tiptap-image.ProseMirror-selectednode{outline:2px solid #6366f1;outline-offset:2px;border-radius:16px;box-shadow:0 0 0 4px #6366f11a}:host ::ng-deep .image-container{margin:.5em 0;text-align:center;border-radius:16px;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1)}:host ::ng-deep .image-container.image-align-left{text-align:left}:host ::ng-deep .image-container.image-align-center{text-align:center}:host ::ng-deep .image-container.image-align-right{text-align:right}:host ::ng-deep .image-container img{display:inline-block;max-width:100%;height:auto;border-radius:16px}:host ::ng-deep .resizable-image-container{position:relative;display:inline-block;margin:.5em 0}:host ::ng-deep .resize-controls{position:absolute;inset:0;pointer-events:none;z-index:1000}:host ::ng-deep .resize-handle{position:absolute;width:12px;height:12px;background:#3b82f6;border:2px solid white;border-radius:50%;pointer-events:all;cursor:pointer;z-index:1001;transition:all .15s ease;box-shadow:0 2px 6px #0003}:host ::ng-deep .resize-handle:hover{background:#2563eb;box-shadow:0 3px 8px #0000004d}:host ::ng-deep .resize-handle:active{background:#1d4ed8}:host ::ng-deep .resize-handle-n:hover,:host ::ng-deep .resize-handle-s:hover{transform:translate(-50%) scale(1.2)}:host ::ng-deep .resize-handle-w:hover,:host ::ng-deep .resize-handle-e:hover{transform:translateY(-50%) scale(1.2)}:host ::ng-deep .resize-handle-n:active,:host ::ng-deep .resize-handle-s:active{transform:translate(-50%) scale(.9)}:host ::ng-deep .resize-handle-w:active,:host ::ng-deep .resize-handle-e:active{transform:translateY(-50%) scale(.9)}:host ::ng-deep .resize-handle-nw:hover,:host ::ng-deep .resize-handle-ne:hover,:host ::ng-deep .resize-handle-sw:hover,:host ::ng-deep .resize-handle-se:hover{transform:scale(1.2)}:host ::ng-deep .resize-handle-nw:active,:host ::ng-deep .resize-handle-ne:active,:host ::ng-deep .resize-handle-sw:active,:host ::ng-deep .resize-handle-se:active{transform:scale(.9)}:host ::ng-deep .resize-handle-nw{top:0;left:-6px;cursor:nw-resize}:host ::ng-deep .resize-handle-n{top:0;left:50%;transform:translate(-50%);cursor:n-resize}:host ::ng-deep .resize-handle-ne{top:0;right:-6px;cursor:ne-resize}:host ::ng-deep .resize-handle-w{top:50%;left:-6px;transform:translateY(-50%);cursor:w-resize}:host ::ng-deep .resize-handle-e{top:50%;right:-6px;transform:translateY(-50%);cursor:e-resize}:host ::ng-deep .resize-handle-sw{bottom:0;left:-6px;cursor:sw-resize}:host ::ng-deep .resize-handle-s{bottom:0;left:50%;transform:translate(-50%);cursor:s-resize}:host ::ng-deep .resize-handle-se{bottom:0;right:-6px;cursor:se-resize}:host ::ng-deep body.resizing{-webkit-user-select:none;user-select:none;cursor:crosshair}:host ::ng-deep body.resizing .ProseMirror{pointer-events:none}:host ::ng-deep body.resizing .ProseMirror .tiptap-image{pointer-events:none}:host ::ng-deep .image-size-info{position:absolute;bottom:-20px;left:50%;transform:translate(-50%);background:#000c;color:#fff;padding:2px 6px;border-radius:3px;font-size:11px;white-space:nowrap;opacity:0;transition:opacity .2s ease}:host ::ng-deep .image-container:hover .image-size-info{opacity:1}:host ::ng-deep .ProseMirror table{border-collapse:separate;border-spacing:0;margin:0;table-layout:fixed;width:100%;border-radius:8px;overflow:hidden}:host ::ng-deep .ProseMirror table td,:host ::ng-deep .ProseMirror table th{border:none;border-right:1px solid #e2e8f0;border-bottom:1px solid #e2e8f0;box-sizing:border-box;min-width:1em;padding:8px 12px;position:relative;vertical-align:top;background:#fff}:host ::ng-deep .ProseMirror table td:first-child,:host ::ng-deep .ProseMirror table th:first-child{border-left:1px solid #e2e8f0}:host ::ng-deep .ProseMirror table tr:first-child td,:host ::ng-deep .ProseMirror table tr:first-child th{border-top:1px solid #e2e8f0}:host ::ng-deep .ProseMirror table tr:first-child th:first-child{border-top-left-radius:8px}:host ::ng-deep .ProseMirror table tr:first-child th:last-child{border-top-right-radius:8px}:host ::ng-deep .ProseMirror table tr:last-child td:first-child{border-bottom-left-radius:8px}:host ::ng-deep .ProseMirror table tr:last-child td:last-child{border-bottom-right-radius:8px}:host ::ng-deep .ProseMirror table th{background:#f8f9fa;font-weight:600;color:#374151}:host ::ng-deep .ProseMirror table .selectedCell:after{background:#c8c8ff66;content:\"\";inset:0;pointer-events:none;position:absolute;z-index:2}:host ::ng-deep .ProseMirror table .column-resize-handle{position:absolute;right:-2px;top:0;bottom:0;width:4px;background-color:#6366f1;opacity:0;transition:opacity .2s ease}:host ::ng-deep .ProseMirror table:hover .column-resize-handle{opacity:1}:host ::ng-deep .ProseMirror table .column-resize-handle:hover{background-color:#4f46e5}:host ::ng-deep .ProseMirror .tableWrapper{overflow-x:auto;margin:1em 0;border-radius:8px}:host ::ng-deep .ProseMirror .tableWrapper table{margin:0;border-radius:8px;min-width:600px;overflow:hidden}:host ::ng-deep .ProseMirror table p{margin:0}:host ::ng-deep .ProseMirror table .selectedCell{background-color:#6366f11a}:host ::ng-deep .ProseMirror table th{background-color:#f8f9fa;font-weight:600;color:#374151;text-align:left}:host ::ng-deep .ProseMirror table tbody tr:nth-child(2n){background-color:#fafbfc}:host ::ng-deep .ProseMirror table tbody tr:hover{background-color:#f1f5f9}\n"], dependencies: [{ kind: "component", type: TiptapToolbarComponent, selector: "tiptap-toolbar", inputs: ["editor", "config"], outputs: ["imageUploaded", "imageError"] }, { kind: "component", type: TiptapImageUploadComponent, selector: "tiptap-image-upload", inputs: ["config"], outputs: ["imageSelected", "error"] }, { kind: "component", type: TiptapBubbleMenuComponent, selector: "tiptap-bubble-menu", inputs: ["editor", "config"] }, { kind: "component", type: TiptapImageBubbleMenuComponent, selector: "tiptap-image-bubble-menu", inputs: ["editor", "config"] }, { kind: "component", type: TiptapTableBubbleMenuComponent, selector: "tiptap-table-bubble-menu", inputs: ["editor", "config"] }, { kind: "component", type: TiptapCellBubbleMenuComponent, selector: "tiptap-cell-bubble-menu", inputs: ["editor", "config"] }, { kind: "component", type: TiptapSlashCommandsComponent, selector: "tiptap-slash-commands", inputs: ["editor", "config"], outputs: ["imageUploadRequested"] }] }); }
4934
5095
  }
4935
5096
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: AngularTiptapEditorComponent, decorators: [{
@@ -4942,270 +5103,95 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
4942
5103
  TiptapTableBubbleMenuComponent,
4943
5104
  TiptapCellBubbleMenuComponent,
4944
5105
  TiptapSlashCommandsComponent,
4945
- ], template: `
4946
- <div class="tiptap-editor">
4947
- <!-- Toolbar -->
4948
- @if (showToolbar() && editor()) {
4949
- <tiptap-toolbar [editor]="editor()!" [config]="toolbarConfig()">
4950
- <div image-upload class="image-upload-container">
4951
- <tiptap-image-upload
4952
- [config]="imageUploadConfig()"
4953
- (imageSelected)="onImageUploaded($event)"
4954
- (error)="onImageUploadError($event)"
4955
- />
4956
- </div>
4957
- </tiptap-toolbar>
4958
- }
4959
-
4960
- <!-- Contenu de l'éditeur -->
4961
- <div
4962
- #editorElement
4963
- class="tiptap-content"
4964
- [class.drag-over]="isDragOver()"
4965
- (dragover)="onDragOver($event)"
4966
- (drop)="onDrop($event)"
4967
- (click)="onEditorClick($event)"
4968
- ></div>
4969
-
4970
- <!-- Bubble Menu pour le texte -->
4971
- @if (showBubbleMenu() && editor()) {
4972
- <tiptap-bubble-menu
4973
- [editor]="editor()!"
4974
- [config]="bubbleMenuConfig()"
4975
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4976
- ></tiptap-bubble-menu>
4977
- }
4978
-
4979
- <!-- Bubble Menu pour les images -->
4980
- @if (showImageBubbleMenu() && editor()) {
4981
- <tiptap-image-bubble-menu
4982
- [editor]="editor()!"
4983
- [config]="imageBubbleMenuConfig()"
4984
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4985
- ></tiptap-image-bubble-menu>
4986
- }
4987
-
4988
- <!-- Slash Commands -->
4989
- @if (enableSlashCommands() && editor()) {
4990
- <tiptap-slash-commands
4991
- [editor]="editor()!"
4992
- [config]="slashCommandsConfigComputed()"
4993
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
4994
- (imageUploadRequested)="onSlashCommandImageUpload($event)"
4995
- ></tiptap-slash-commands>
4996
- }
4997
-
4998
- <!-- Table Menu -->
4999
- @if (editor()) {
5000
- <tiptap-table-bubble-menu
5001
- [editor]="editor()!"
5002
- [config]="tableBubbleMenuConfig()"
5003
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5004
- ></tiptap-table-bubble-menu>
5005
- }
5006
-
5007
- <!-- Cell Menu -->
5008
- @if (editor()) {
5009
- <tiptap-cell-bubble-menu
5010
- [editor]="editor()!"
5011
- [config]="cellBubbleMenuConfig()"
5012
- [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5013
- ></tiptap-cell-bubble-menu>
5014
- }
5015
-
5016
- <!-- Table Edit Button - Supprimé car remplacé par le menu bubble -->
5017
-
5018
- <!-- Compteur de caractères -->
5019
- @if (showCharacterCount()) {
5020
- <div class="character-count">
5021
- {{ characterCount() }}
5022
- {{ i18nService.editor().character
5023
- }}{{ characterCount() > 1 ? "s" : "" }}, {{ wordCount() }}
5024
- {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
5025
- @if (maxCharacters()) { /
5026
- {{ maxCharacters() }}
5027
- }
5028
- </div>
5029
- }
5030
- </div>
5106
+ ], template: `
5107
+ <div class="tiptap-editor">
5108
+ <!-- Toolbar -->
5109
+ @if (showToolbar() && editor()) {
5110
+ <tiptap-toolbar [editor]="editor()!" [config]="toolbarConfig()">
5111
+ <div image-upload class="image-upload-container">
5112
+ <tiptap-image-upload
5113
+ [config]="imageUploadConfig()"
5114
+ (imageSelected)="onImageUploaded($event)"
5115
+ (error)="onImageUploadError($event)"
5116
+ />
5117
+ </div>
5118
+ </tiptap-toolbar>
5119
+ }
5120
+
5121
+ <!-- Contenu de l'éditeur -->
5122
+ <div
5123
+ #editorElement
5124
+ class="tiptap-content"
5125
+ [class.drag-over]="isDragOver()"
5126
+ (dragover)="onDragOver($event)"
5127
+ (drop)="onDrop($event)"
5128
+ (click)="onEditorClick($event)"
5129
+ ></div>
5130
+
5131
+ <!-- Bubble Menu pour le texte -->
5132
+ @if (showBubbleMenu() && editor()) {
5133
+ <tiptap-bubble-menu
5134
+ [editor]="editor()!"
5135
+ [config]="bubbleMenuConfig()"
5136
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5137
+ ></tiptap-bubble-menu>
5138
+ }
5139
+
5140
+ <!-- Bubble Menu pour les images -->
5141
+ @if (showImageBubbleMenu() && editor()) {
5142
+ <tiptap-image-bubble-menu
5143
+ [editor]="editor()!"
5144
+ [config]="imageBubbleMenuConfig()"
5145
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5146
+ ></tiptap-image-bubble-menu>
5147
+ }
5148
+
5149
+ <!-- Slash Commands -->
5150
+ @if (enableSlashCommands() && editor()) {
5151
+ <tiptap-slash-commands
5152
+ [editor]="editor()!"
5153
+ [config]="slashCommandsConfigComputed()"
5154
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5155
+ (imageUploadRequested)="onSlashCommandImageUpload($event)"
5156
+ ></tiptap-slash-commands>
5157
+ }
5158
+
5159
+ <!-- Table Menu -->
5160
+ @if (editor()) {
5161
+ <tiptap-table-bubble-menu
5162
+ [editor]="editor()!"
5163
+ [config]="tableBubbleMenuConfig()"
5164
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5165
+ ></tiptap-table-bubble-menu>
5166
+ }
5167
+
5168
+ <!-- Cell Menu -->
5169
+ @if (editor()) {
5170
+ <tiptap-cell-bubble-menu
5171
+ [editor]="editor()!"
5172
+ [config]="cellBubbleMenuConfig()"
5173
+ [style.display]="editorFullyInitialized() ? 'block' : 'none'"
5174
+ ></tiptap-cell-bubble-menu>
5175
+ }
5176
+
5177
+ <!-- Table Edit Button - Supprimé car remplacé par le menu bubble -->
5178
+
5179
+ <!-- Compteur de caractères -->
5180
+ @if (showCharacterCount()) {
5181
+ <div class="character-count">
5182
+ {{ characterCount() }}
5183
+ {{ i18nService.editor().character
5184
+ }}{{ characterCount() > 1 ? "s" : "" }}, {{ wordCount() }}
5185
+ {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
5186
+ @if (maxCharacters()) { /
5187
+ {{ maxCharacters() }}
5188
+ }
5189
+ </div>
5190
+ }
5191
+ </div>
5031
5192
  `, styles: [".tiptap-editor{border:2px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;transition:border-color .2s ease}.tiptap-editor:focus-within{border-color:#3182ce}.tiptap-content{padding:16px;min-height:var(--editor-min-height, 200px);height:var(--editor-height, auto);max-height:var(--editor-max-height, none);overflow-y:var(--editor-overflow, visible);outline:none;position:relative}.tiptap-content.drag-over{background:#f0f8ff;border:2px dashed #3182ce}.character-count{padding:8px 16px;font-size:12px;color:#718096;text-align:right;border-top:1px solid #e2e8f0;background:#f8f9fa}.image-upload-container{position:relative;display:inline-block}:host ::ng-deep .ProseMirror{outline:none;line-height:1.6;color:#2d3748;min-height:100%;height:100%;word-wrap:break-word;overflow-wrap:break-word}:host ::ng-deep .ProseMirror h1{font-size:2em;font-weight:700;margin-top:0;margin-bottom:.5em}:host ::ng-deep .ProseMirror h2{font-size:1.5em;font-weight:700;margin-top:1em;margin-bottom:.5em}:host ::ng-deep .ProseMirror h3{font-size:1.25em;font-weight:700;margin-top:1em;margin-bottom:.5em}:host ::ng-deep .ProseMirror p{margin:.5em 0}:host ::ng-deep .ProseMirror ul,:host ::ng-deep .ProseMirror ol{padding-left:2em;margin:.5em 0}:host ::ng-deep .ProseMirror blockquote{border-left:4px solid #e2e8f0;margin:1em 0;font-style:italic;background:#f8f9fa;padding:.5em 1em;border-radius:0 4px 4px 0}:host ::ng-deep .ProseMirror code{background:#f1f5f9;padding:.2em .4em;border-radius:3px;font-family:Monaco,Consolas,monospace;font-size:.9em}:host ::ng-deep .ProseMirror pre{background:#1a202c;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;margin:1em 0}:host ::ng-deep .ProseMirror pre code{background:none;color:inherit;padding:0}:host ::ng-deep .ProseMirror p.is-editor-empty:first-child:before{content:attr(data-placeholder);color:#a0aec0;pointer-events:none;float:left;height:0}:host ::ng-deep .ProseMirror[contenteditable=false]{pointer-events:none}:host ::ng-deep .ProseMirror[contenteditable=false] img{cursor:default;pointer-events:none}:host ::ng-deep .ProseMirror[contenteditable=false] img:hover{transform:none;box-shadow:0 2px 8px #0000001a}:host ::ng-deep .ProseMirror[contenteditable=false] img.ProseMirror-selectednode{outline:none}:host ::ng-deep .ProseMirror img{position:relative;display:inline-block;max-width:100%;height:auto;cursor:pointer;transition:all .2s ease;border:2px solid transparent;border-radius:8px}:host ::ng-deep .ProseMirror img:hover{border-color:#e2e8f0;box-shadow:0 2px 4px #0000001a}:host ::ng-deep .ProseMirror img.ProseMirror-selectednode{border-color:#3182ce;box-shadow:0 0 0 3px #3182ce1a;transition:all .2s ease}:host ::ng-deep .ProseMirror .tiptap-image{max-width:100%;height:auto;border-radius:16px;box-shadow:0 4px 20px #00000014;margin:.5em 0;cursor:pointer;transition:all .3s cubic-bezier(.4,0,.2,1);display:block;filter:brightness(1) contrast(1)}:host ::ng-deep .ProseMirror .tiptap-image:hover{box-shadow:0 8px 30px #0000001f;filter:brightness(1.02) contrast(1.02)}:host ::ng-deep .ProseMirror .tiptap-image.ProseMirror-selectednode{outline:2px solid #6366f1;outline-offset:2px;border-radius:16px;box-shadow:0 0 0 4px #6366f11a}:host ::ng-deep .image-container{margin:.5em 0;text-align:center;border-radius:16px;overflow:hidden;transition:all .3s cubic-bezier(.4,0,.2,1)}:host ::ng-deep .image-container.image-align-left{text-align:left}:host ::ng-deep .image-container.image-align-center{text-align:center}:host ::ng-deep .image-container.image-align-right{text-align:right}:host ::ng-deep .image-container img{display:inline-block;max-width:100%;height:auto;border-radius:16px}:host ::ng-deep .resizable-image-container{position:relative;display:inline-block;margin:.5em 0}:host ::ng-deep .resize-controls{position:absolute;inset:0;pointer-events:none;z-index:1000}:host ::ng-deep .resize-handle{position:absolute;width:12px;height:12px;background:#3b82f6;border:2px solid white;border-radius:50%;pointer-events:all;cursor:pointer;z-index:1001;transition:all .15s ease;box-shadow:0 2px 6px #0003}:host ::ng-deep .resize-handle:hover{background:#2563eb;box-shadow:0 3px 8px #0000004d}:host ::ng-deep .resize-handle:active{background:#1d4ed8}:host ::ng-deep .resize-handle-n:hover,:host ::ng-deep .resize-handle-s:hover{transform:translate(-50%) scale(1.2)}:host ::ng-deep .resize-handle-w:hover,:host ::ng-deep .resize-handle-e:hover{transform:translateY(-50%) scale(1.2)}:host ::ng-deep .resize-handle-n:active,:host ::ng-deep .resize-handle-s:active{transform:translate(-50%) scale(.9)}:host ::ng-deep .resize-handle-w:active,:host ::ng-deep .resize-handle-e:active{transform:translateY(-50%) scale(.9)}:host ::ng-deep .resize-handle-nw:hover,:host ::ng-deep .resize-handle-ne:hover,:host ::ng-deep .resize-handle-sw:hover,:host ::ng-deep .resize-handle-se:hover{transform:scale(1.2)}:host ::ng-deep .resize-handle-nw:active,:host ::ng-deep .resize-handle-ne:active,:host ::ng-deep .resize-handle-sw:active,:host ::ng-deep .resize-handle-se:active{transform:scale(.9)}:host ::ng-deep .resize-handle-nw{top:0;left:-6px;cursor:nw-resize}:host ::ng-deep .resize-handle-n{top:0;left:50%;transform:translate(-50%);cursor:n-resize}:host ::ng-deep .resize-handle-ne{top:0;right:-6px;cursor:ne-resize}:host ::ng-deep .resize-handle-w{top:50%;left:-6px;transform:translateY(-50%);cursor:w-resize}:host ::ng-deep .resize-handle-e{top:50%;right:-6px;transform:translateY(-50%);cursor:e-resize}:host ::ng-deep .resize-handle-sw{bottom:0;left:-6px;cursor:sw-resize}:host ::ng-deep .resize-handle-s{bottom:0;left:50%;transform:translate(-50%);cursor:s-resize}:host ::ng-deep .resize-handle-se{bottom:0;right:-6px;cursor:se-resize}:host ::ng-deep body.resizing{-webkit-user-select:none;user-select:none;cursor:crosshair}:host ::ng-deep body.resizing .ProseMirror{pointer-events:none}:host ::ng-deep body.resizing .ProseMirror .tiptap-image{pointer-events:none}:host ::ng-deep .image-size-info{position:absolute;bottom:-20px;left:50%;transform:translate(-50%);background:#000c;color:#fff;padding:2px 6px;border-radius:3px;font-size:11px;white-space:nowrap;opacity:0;transition:opacity .2s ease}:host ::ng-deep .image-container:hover .image-size-info{opacity:1}:host ::ng-deep .ProseMirror table{border-collapse:separate;border-spacing:0;margin:0;table-layout:fixed;width:100%;border-radius:8px;overflow:hidden}:host ::ng-deep .ProseMirror table td,:host ::ng-deep .ProseMirror table th{border:none;border-right:1px solid #e2e8f0;border-bottom:1px solid #e2e8f0;box-sizing:border-box;min-width:1em;padding:8px 12px;position:relative;vertical-align:top;background:#fff}:host ::ng-deep .ProseMirror table td:first-child,:host ::ng-deep .ProseMirror table th:first-child{border-left:1px solid #e2e8f0}:host ::ng-deep .ProseMirror table tr:first-child td,:host ::ng-deep .ProseMirror table tr:first-child th{border-top:1px solid #e2e8f0}:host ::ng-deep .ProseMirror table tr:first-child th:first-child{border-top-left-radius:8px}:host ::ng-deep .ProseMirror table tr:first-child th:last-child{border-top-right-radius:8px}:host ::ng-deep .ProseMirror table tr:last-child td:first-child{border-bottom-left-radius:8px}:host ::ng-deep .ProseMirror table tr:last-child td:last-child{border-bottom-right-radius:8px}:host ::ng-deep .ProseMirror table th{background:#f8f9fa;font-weight:600;color:#374151}:host ::ng-deep .ProseMirror table .selectedCell:after{background:#c8c8ff66;content:\"\";inset:0;pointer-events:none;position:absolute;z-index:2}:host ::ng-deep .ProseMirror table .column-resize-handle{position:absolute;right:-2px;top:0;bottom:0;width:4px;background-color:#6366f1;opacity:0;transition:opacity .2s ease}:host ::ng-deep .ProseMirror table:hover .column-resize-handle{opacity:1}:host ::ng-deep .ProseMirror table .column-resize-handle:hover{background-color:#4f46e5}:host ::ng-deep .ProseMirror .tableWrapper{overflow-x:auto;margin:1em 0;border-radius:8px}:host ::ng-deep .ProseMirror .tableWrapper table{margin:0;border-radius:8px;min-width:600px;overflow:hidden}:host ::ng-deep .ProseMirror table p{margin:0}:host ::ng-deep .ProseMirror table .selectedCell{background-color:#6366f11a}:host ::ng-deep .ProseMirror table th{background-color:#f8f9fa;font-weight:600;color:#374151;text-align:left}:host ::ng-deep .ProseMirror table tbody tr:nth-child(2n){background-color:#fafbfc}:host ::ng-deep .ProseMirror table tbody tr:hover{background-color:#f1f5f9}\n"] }]
5032
5193
  }], ctorParameters: () => [] });
5033
5194
 
5034
- /**
5035
- * Clés des commandes dans l'ordre de création
5036
- */
5037
- const SLASH_COMMAND_KEYS = [
5038
- "heading1",
5039
- "heading2",
5040
- "heading3",
5041
- "bulletList",
5042
- "orderedList",
5043
- "blockquote",
5044
- "code",
5045
- "image",
5046
- "horizontalRule",
5047
- "table",
5048
- ];
5049
- /**
5050
- * Factory function pour créer les slash commands traduits
5051
- */
5052
- function createI18nSlashCommands(i18nService) {
5053
- const slashCommands = i18nService.slashCommands();
5054
- return [
5055
- {
5056
- title: slashCommands.heading1.title,
5057
- description: slashCommands.heading1.description,
5058
- icon: "format_h1",
5059
- keywords: slashCommands.heading1.keywords,
5060
- command: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run(),
5061
- },
5062
- {
5063
- title: slashCommands.heading2.title,
5064
- description: slashCommands.heading2.description,
5065
- icon: "format_h2",
5066
- keywords: slashCommands.heading2.keywords,
5067
- command: (editor) => editor.chain().focus().toggleHeading({ level: 2 }).run(),
5068
- },
5069
- {
5070
- title: slashCommands.heading3.title,
5071
- description: slashCommands.heading3.description,
5072
- icon: "format_h3",
5073
- keywords: slashCommands.heading3.keywords,
5074
- command: (editor) => editor.chain().focus().toggleHeading({ level: 3 }).run(),
5075
- },
5076
- {
5077
- title: slashCommands.bulletList.title,
5078
- description: slashCommands.bulletList.description,
5079
- icon: "format_list_bulleted",
5080
- keywords: slashCommands.bulletList.keywords,
5081
- command: (editor) => editor.chain().focus().toggleBulletList().run(),
5082
- },
5083
- {
5084
- title: slashCommands.orderedList.title,
5085
- description: slashCommands.orderedList.description,
5086
- icon: "format_list_numbered",
5087
- keywords: slashCommands.orderedList.keywords,
5088
- command: (editor) => editor.chain().focus().toggleOrderedList().run(),
5089
- },
5090
- {
5091
- title: slashCommands.blockquote.title,
5092
- description: slashCommands.blockquote.description,
5093
- icon: "format_quote",
5094
- keywords: slashCommands.blockquote.keywords,
5095
- command: (editor) => editor.chain().focus().toggleBlockquote().run(),
5096
- },
5097
- {
5098
- title: slashCommands.code.title,
5099
- description: slashCommands.code.description,
5100
- icon: "code",
5101
- keywords: slashCommands.code.keywords,
5102
- command: (editor) => editor.chain().focus().toggleCodeBlock().run(),
5103
- },
5104
- {
5105
- title: slashCommands.image.title,
5106
- description: slashCommands.image.description,
5107
- icon: "image",
5108
- keywords: slashCommands.image.keywords,
5109
- command: (editor) => {
5110
- // Créer un input file temporaire pour sélectionner une image
5111
- const input = document.createElement("input");
5112
- input.type = "file";
5113
- input.accept = "image/*";
5114
- input.style.display = "none";
5115
- input.addEventListener("change", async (e) => {
5116
- const file = e.target.files?.[0];
5117
- if (file && file.type.startsWith("image/")) {
5118
- try {
5119
- // Utiliser la méthode de compression unifiée
5120
- const canvas = document.createElement("canvas");
5121
- const ctx = canvas.getContext("2d");
5122
- const img = new Image();
5123
- img.onload = () => {
5124
- // Vérifier les dimensions (max 1920x1080)
5125
- const maxWidth = 1920;
5126
- const maxHeight = 1080;
5127
- let { width, height } = img;
5128
- // Redimensionner si nécessaire
5129
- if (width > maxWidth || height > maxHeight) {
5130
- const ratio = Math.min(maxWidth / width, maxHeight / height);
5131
- width *= ratio;
5132
- height *= ratio;
5133
- }
5134
- canvas.width = width;
5135
- canvas.height = height;
5136
- // Dessiner l'image redimensionnée
5137
- ctx?.drawImage(img, 0, 0, width, height);
5138
- // Convertir en base64 avec compression
5139
- canvas.toBlob((blob) => {
5140
- if (blob) {
5141
- const reader = new FileReader();
5142
- reader.onload = (e) => {
5143
- const base64 = e.target?.result;
5144
- if (base64) {
5145
- // Utiliser setResizableImage avec toutes les propriétés
5146
- editor
5147
- .chain()
5148
- .focus()
5149
- .setResizableImage({
5150
- src: base64,
5151
- alt: file.name,
5152
- title: `${file.name} (${Math.round(width)}×${Math.round(height)})`,
5153
- width: Math.round(width),
5154
- height: Math.round(height),
5155
- })
5156
- .run();
5157
- }
5158
- };
5159
- reader.readAsDataURL(blob);
5160
- }
5161
- }, file.type, 0.8 // qualité de compression
5162
- );
5163
- };
5164
- img.onerror = () => {
5165
- console.error(i18nService.editor().imageLoadError);
5166
- };
5167
- img.src = URL.createObjectURL(file);
5168
- }
5169
- catch (error) {
5170
- console.error("Error uploading image:", error);
5171
- }
5172
- }
5173
- document.body.removeChild(input);
5174
- });
5175
- document.body.appendChild(input);
5176
- input.click();
5177
- },
5178
- },
5179
- {
5180
- title: slashCommands.horizontalRule.title,
5181
- description: slashCommands.horizontalRule.description,
5182
- icon: "horizontal_rule",
5183
- keywords: slashCommands.horizontalRule.keywords,
5184
- command: (editor) => editor.chain().focus().setHorizontalRule().run(),
5185
- },
5186
- {
5187
- title: slashCommands.table.title,
5188
- description: slashCommands.table.description,
5189
- icon: "table_view",
5190
- keywords: slashCommands.table.keywords,
5191
- command: (editor) => editor.chain().focus().insertTable({ rows: 3, cols: 3 }).run(),
5192
- },
5193
- ];
5194
- }
5195
- /**
5196
- * Fonction utilitaire pour filtrer les slash commands selon les commandes actives
5197
- * Utilise le service i18n injecté en interne
5198
- */
5199
- function filterSlashCommands(activeCommands) {
5200
- // Injecter le service i18n en interne
5201
- const i18nService = inject(TiptapI18nService);
5202
- const allCommands = createI18nSlashCommands(i18nService);
5203
- return allCommands.filter((command, index) => {
5204
- const commandKey = SLASH_COMMAND_KEYS[index];
5205
- return commandKey && activeCommands.has(commandKey);
5206
- });
5207
- }
5208
-
5209
5195
  /*
5210
5196
  * Public API Surface of tiptap-editor
5211
5197
  */
@@ -5215,5 +5201,5 @@ function filterSlashCommands(activeCommands) {
5215
5201
  * Generated bundle index. Do not edit.
5216
5202
  */
5217
5203
 
5218
- export { AngularTiptapEditorComponent, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, EditorCommandsService, ImageService, NoopValueAccessorDirective, SLASH_COMMAND_KEYS, TiptapI18nService, createI18nSlashCommands, filterSlashCommands };
5204
+ export { AngularTiptapEditorComponent, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS$1 as DEFAULT_SLASH_COMMANDS, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, EditorCommandsService, ImageService, NoopValueAccessorDirective, SLASH_COMMAND_KEYS, TiptapI18nService, createI18nSlashCommands, filterSlashCommands };
5219
5205
  //# sourceMappingURL=flogeez-angular-tiptap-editor.mjs.map