@flogeez/angular-tiptap-editor 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +107 -16
- package/fesm2022/flogeez-angular-tiptap-editor.mjs +346 -878
- package/fesm2022/flogeez-angular-tiptap-editor.mjs.map +1 -1
- package/index.d.ts +72 -27
- package/package.json +1 -1
- package/src/lib/styles/bubble-menu.global.css +11 -10
- package/src/lib/styles/index.css +4 -4
|
@@ -361,9 +361,9 @@ const UploadProgress = Extension.create({
|
|
|
361
361
|
max-width: 400px;
|
|
362
362
|
}
|
|
363
363
|
.upload-skeleton {
|
|
364
|
-
background:
|
|
365
|
-
border: 2px dashed
|
|
366
|
-
border-radius:
|
|
364
|
+
background: var(--ate-surface-secondary);
|
|
365
|
+
border: 2px dashed var(--ate-border-color);
|
|
366
|
+
border-radius: var(--ate-border-radius);
|
|
367
367
|
padding: 16px;
|
|
368
368
|
display: flex;
|
|
369
369
|
align-items: center;
|
|
@@ -372,8 +372,8 @@ const UploadProgress = Extension.create({
|
|
|
372
372
|
animation: pulse 2s infinite;
|
|
373
373
|
}
|
|
374
374
|
@keyframes pulse {
|
|
375
|
-
0%, 100% { background-color:
|
|
376
|
-
50% { background-color:
|
|
375
|
+
0%, 100% { background-color: var(--ate-surface-secondary); }
|
|
376
|
+
50% { background-color: var(--ate-surface-tertiary); }
|
|
377
377
|
}
|
|
378
378
|
.upload-content {
|
|
379
379
|
display: flex;
|
|
@@ -388,9 +388,9 @@ const UploadProgress = Extension.create({
|
|
|
388
388
|
justify-content: center;
|
|
389
389
|
width: 48px;
|
|
390
390
|
height: 48px;
|
|
391
|
-
background:
|
|
391
|
+
background: var(--ate-primary-light);
|
|
392
392
|
border-radius: 50%;
|
|
393
|
-
color:
|
|
393
|
+
color: var(--ate-primary);
|
|
394
394
|
}
|
|
395
395
|
.upload-icon .material-symbols-outlined {
|
|
396
396
|
font-size: 24px;
|
|
@@ -411,25 +411,25 @@ const UploadProgress = Extension.create({
|
|
|
411
411
|
}
|
|
412
412
|
.upload-message {
|
|
413
413
|
font-size: 14px;
|
|
414
|
-
color:
|
|
414
|
+
color: var(--ate-text);
|
|
415
415
|
font-weight: 500;
|
|
416
416
|
}
|
|
417
417
|
.progress-bar {
|
|
418
418
|
width: 100%;
|
|
419
419
|
height: 6px;
|
|
420
|
-
background:
|
|
420
|
+
background: var(--ate-border-color);
|
|
421
421
|
border-radius: 3px;
|
|
422
422
|
overflow: hidden;
|
|
423
423
|
}
|
|
424
424
|
.progress-fill {
|
|
425
425
|
height: 100%;
|
|
426
|
-
background:
|
|
426
|
+
background: var(--ate-primary);
|
|
427
427
|
border-radius: 3px;
|
|
428
428
|
transition: width 0.3s ease;
|
|
429
429
|
}
|
|
430
430
|
.progress-text {
|
|
431
431
|
font-size: 12px;
|
|
432
|
-
color:
|
|
432
|
+
color: var(--ate-text-secondary);
|
|
433
433
|
font-weight: 500;
|
|
434
434
|
}
|
|
435
435
|
`;
|
|
@@ -548,6 +548,7 @@ class TiptapButtonComponent {
|
|
|
548
548
|
[class.small]="size() === 'small'"
|
|
549
549
|
[class.medium]="size() === 'medium'"
|
|
550
550
|
[class.large]="size() === 'large'"
|
|
551
|
+
[class.has-custom-color]="!!color()"
|
|
551
552
|
[disabled]="disabled()"
|
|
552
553
|
[style.color]="color()"
|
|
553
554
|
[attr.title]="title()"
|
|
@@ -564,7 +565,7 @@ class TiptapButtonComponent {
|
|
|
564
565
|
>
|
|
565
566
|
<ng-content></ng-content>
|
|
566
567
|
</button>
|
|
567
|
-
`, 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
|
|
568
|
+
`, isInline: true, styles: [".tiptap-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:var(--ate-border-radius, 8px);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);color:var(--ate-toolbar-button-color, var(--ate-text-secondary));position:relative;overflow:hidden}.tiptap-button:before{content:\"\";position:absolute;inset:0;background:var(--ate-primary);opacity:0;transition:opacity .2s ease;border-radius:var(--ate-border-radius, 8px)}.tiptap-button:hover:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button.has-custom-color:hover{background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button:hover:before{opacity:.1}.tiptap-button:active{transform:translateY(0)}.tiptap-button.is-active:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.tiptap-button.is-active.has-custom-color{background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.tiptap-button:disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.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;gap:8px}.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:var(--ate-border);transform:scale(1.1)}.tiptap-button.color-button.is-active{border-color:var(--ate-primary);box-shadow:0 0 0 2px var(--ate-primary-light)}.tiptap-button.danger{color:var(--ate-error-color, #ef4444)}.tiptap-button.danger:hover{background:var(--ate-error-bg, rgba(239, 68, 68, .1))}.tiptap-button.danger:before{background:var(--ate-error-color, #ef4444)}.tiptap-button.small{width:24px;height:24px}.tiptap-button.medium{width:32px;height:32px}.tiptap-button.large{width:40px;height:40px}@keyframes pulse{0%,to{box-shadow:0 0 0 0 var(--ate-primary-light-alpha)}50%{box-shadow:0 0 0 4px transparent}}.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"] }); }
|
|
568
569
|
}
|
|
569
570
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapButtonComponent, decorators: [{
|
|
570
571
|
type: Component,
|
|
@@ -578,6 +579,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
578
579
|
[class.small]="size() === 'small'"
|
|
579
580
|
[class.medium]="size() === 'medium'"
|
|
580
581
|
[class.large]="size() === 'large'"
|
|
582
|
+
[class.has-custom-color]="!!color()"
|
|
581
583
|
[disabled]="disabled()"
|
|
582
584
|
[style.color]="color()"
|
|
583
585
|
[attr.title]="title()"
|
|
@@ -594,7 +596,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
594
596
|
>
|
|
595
597
|
<ng-content></ng-content>
|
|
596
598
|
</button>
|
|
597
|
-
`, 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
|
|
599
|
+
`, styles: [".tiptap-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:var(--ate-border-radius, 8px);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);color:var(--ate-toolbar-button-color, var(--ate-text-secondary));position:relative;overflow:hidden}.tiptap-button:before{content:\"\";position:absolute;inset:0;background:var(--ate-primary);opacity:0;transition:opacity .2s ease;border-radius:var(--ate-border-radius, 8px)}.tiptap-button:hover:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button.has-custom-color:hover{background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button:hover:before{opacity:.1}.tiptap-button:active{transform:translateY(0)}.tiptap-button.is-active:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.tiptap-button.is-active.has-custom-color{background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.tiptap-button:disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.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;gap:8px}.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:var(--ate-border);transform:scale(1.1)}.tiptap-button.color-button.is-active{border-color:var(--ate-primary);box-shadow:0 0 0 2px var(--ate-primary-light)}.tiptap-button.danger{color:var(--ate-error-color, #ef4444)}.tiptap-button.danger:hover{background:var(--ate-error-bg, rgba(239, 68, 68, .1))}.tiptap-button.danger:before{background:var(--ate-error-color, #ef4444)}.tiptap-button.small{width:24px;height:24px}.tiptap-button.medium{width:32px;height:32px}.tiptap-button.large{width:40px;height:40px}@keyframes pulse{0%,to{box-shadow:0 0 0 0 var(--ate-primary-light-alpha)}50%{box-shadow:0 0 0 4px transparent}}.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"] }]
|
|
598
600
|
}] });
|
|
599
601
|
|
|
600
602
|
class ColorPickerService {
|
|
@@ -658,7 +660,19 @@ class ColorPickerService {
|
|
|
658
660
|
if (found)
|
|
659
661
|
return found;
|
|
660
662
|
const attrs = editor.getAttributes("textStyle") || {};
|
|
661
|
-
|
|
663
|
+
if (attrs.color)
|
|
664
|
+
return this.normalizeColor(attrs.color);
|
|
665
|
+
// Dynamic fallback: get current computed text color from editor's DOM
|
|
666
|
+
try {
|
|
667
|
+
if (typeof window !== "undefined" && editor.view?.dom) {
|
|
668
|
+
const computedColor = window.getComputedStyle(editor.view.dom).color;
|
|
669
|
+
return this.normalizeColor(computedColor);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
catch (e) {
|
|
673
|
+
// Fail silently and use basic fallback
|
|
674
|
+
}
|
|
675
|
+
return "#000000";
|
|
662
676
|
}
|
|
663
677
|
/**
|
|
664
678
|
* Check if a color is explicitly applied on the selection.
|
|
@@ -856,6 +870,7 @@ const ENGLISH_TRANSLATIONS = {
|
|
|
856
870
|
},
|
|
857
871
|
imageUpload: {
|
|
858
872
|
selectImage: "Select Image",
|
|
873
|
+
loadError: "Error loading image",
|
|
859
874
|
uploadingImage: "Uploading image...",
|
|
860
875
|
uploadProgress: "Upload Progress",
|
|
861
876
|
uploadError: "Upload Error",
|
|
@@ -869,12 +884,20 @@ const ENGLISH_TRANSLATIONS = {
|
|
|
869
884
|
resizeMedium: "Medium",
|
|
870
885
|
resizeLarge: "Large",
|
|
871
886
|
resizeOriginal: "Original",
|
|
887
|
+
resizing: "Resizing...",
|
|
888
|
+
compressing: "Compressing...",
|
|
889
|
+
compressionError: "Error during compression",
|
|
890
|
+
validating: "Validating file...",
|
|
891
|
+
uploadingToServer: "Uploading to server...",
|
|
892
|
+
replacingImage: "Replacing image...",
|
|
893
|
+
insertingImage: "Inserting into editor...",
|
|
894
|
+
noFileSelected: "No image file selected",
|
|
895
|
+
selectionCancelled: "Selection cancelled",
|
|
872
896
|
},
|
|
873
897
|
editor: {
|
|
874
898
|
placeholder: "Start typing...",
|
|
875
899
|
character: "character",
|
|
876
900
|
word: "word",
|
|
877
|
-
imageLoadError: "Error loading image",
|
|
878
901
|
linkPrompt: "Enter link URL",
|
|
879
902
|
linkUrlPrompt: "Enter URL",
|
|
880
903
|
confirmDelete: "Are you sure you want to delete this?",
|
|
@@ -1014,6 +1037,7 @@ const FRENCH_TRANSLATIONS = {
|
|
|
1014
1037
|
},
|
|
1015
1038
|
imageUpload: {
|
|
1016
1039
|
selectImage: "Sélectionner une image",
|
|
1040
|
+
loadError: "Erreur de chargement de l'image",
|
|
1017
1041
|
uploadingImage: "Téléchargement de l'image...",
|
|
1018
1042
|
uploadProgress: "Progression du téléchargement",
|
|
1019
1043
|
uploadError: "Erreur de téléchargement",
|
|
@@ -1027,12 +1051,20 @@ const FRENCH_TRANSLATIONS = {
|
|
|
1027
1051
|
resizeMedium: "Moyen",
|
|
1028
1052
|
resizeLarge: "Grand",
|
|
1029
1053
|
resizeOriginal: "Original",
|
|
1054
|
+
resizing: "Redimensionnement...",
|
|
1055
|
+
compressing: "Compression...",
|
|
1056
|
+
compressionError: "Erreur lors de la compression",
|
|
1057
|
+
validating: "Validation du fichier...",
|
|
1058
|
+
uploadingToServer: "Upload vers le serveur...",
|
|
1059
|
+
replacingImage: "Remplacement de l'image...",
|
|
1060
|
+
insertingImage: "Insertion dans l'éditeur...",
|
|
1061
|
+
noFileSelected: "Aucun fichier image sélectionné",
|
|
1062
|
+
selectionCancelled: "Sélection annulée",
|
|
1030
1063
|
},
|
|
1031
1064
|
editor: {
|
|
1032
1065
|
placeholder: "Commencez à écrire...",
|
|
1033
1066
|
character: "caractère",
|
|
1034
1067
|
word: "mot",
|
|
1035
|
-
imageLoadError: "Erreur de chargement de l'image",
|
|
1036
1068
|
linkPrompt: "Entrez l'URL du lien",
|
|
1037
1069
|
linkUrlPrompt: "Entrez l'URL",
|
|
1038
1070
|
confirmDelete: "Êtes-vous sûr de vouloir supprimer ceci ?",
|
|
@@ -1132,7 +1164,9 @@ class TiptapTextColorPickerComponent {
|
|
|
1132
1164
|
this.editorChange = signal(0);
|
|
1133
1165
|
this.currentColor = computed(() => {
|
|
1134
1166
|
this.editorChange();
|
|
1135
|
-
|
|
1167
|
+
if (this.previewColor())
|
|
1168
|
+
return this.previewColor();
|
|
1169
|
+
return this.colorPickerSvc.getCurrentColor(this.editor());
|
|
1136
1170
|
});
|
|
1137
1171
|
this.hasColorApplied = computed(() => {
|
|
1138
1172
|
this.editorChange();
|
|
@@ -1252,7 +1286,7 @@ class TiptapTextColorPickerComponent {
|
|
|
1252
1286
|
<tiptap-button
|
|
1253
1287
|
icon="format_color_text"
|
|
1254
1288
|
[title]="t().textColor"
|
|
1255
|
-
[color]="hasColorApplied() ? currentColor() :
|
|
1289
|
+
[color]="hasColorApplied() ? currentColor() : 'var(--ate-text)'"
|
|
1256
1290
|
(onClick)="triggerPicker()"
|
|
1257
1291
|
>
|
|
1258
1292
|
<input
|
|
@@ -1287,7 +1321,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
1287
1321
|
<tiptap-button
|
|
1288
1322
|
icon="format_color_text"
|
|
1289
1323
|
[title]="t().textColor"
|
|
1290
|
-
[color]="hasColorApplied() ? currentColor() :
|
|
1324
|
+
[color]="hasColorApplied() ? currentColor() : 'var(--ate-text)'"
|
|
1291
1325
|
(onClick)="triggerPicker()"
|
|
1292
1326
|
>
|
|
1293
1327
|
<input
|
|
@@ -1325,6 +1359,8 @@ class TiptapBubbleMenuComponent {
|
|
|
1325
1359
|
}
|
|
1326
1360
|
// Effect comme propriété de classe pour éviter l'erreur d'injection context
|
|
1327
1361
|
constructor() {
|
|
1362
|
+
this.i18nService = inject(TiptapI18nService);
|
|
1363
|
+
this.t = this.i18nService.bubbleMenu;
|
|
1328
1364
|
this.editor = input.required();
|
|
1329
1365
|
this.config = input({
|
|
1330
1366
|
bold: true,
|
|
@@ -1356,8 +1392,6 @@ class TiptapBubbleMenuComponent {
|
|
|
1356
1392
|
separator: true,
|
|
1357
1393
|
...this.config(),
|
|
1358
1394
|
}));
|
|
1359
|
-
this.i18nService = inject(TiptapI18nService);
|
|
1360
|
-
this.t = this.i18nService.bubbleMenu;
|
|
1361
1395
|
this.updateMenu = () => {
|
|
1362
1396
|
// Debounce pour éviter les appels trop fréquents
|
|
1363
1397
|
if (this.updateTimeout) {
|
|
@@ -1461,7 +1495,10 @@ class TiptapBubbleMenuComponent {
|
|
|
1461
1495
|
content: menuElement,
|
|
1462
1496
|
trigger: "manual",
|
|
1463
1497
|
placement: "top-start",
|
|
1464
|
-
appendTo: () =>
|
|
1498
|
+
appendTo: (ref) => {
|
|
1499
|
+
const host = this.editor().options.element.closest("angular-tiptap-editor");
|
|
1500
|
+
return host || document.body;
|
|
1501
|
+
},
|
|
1465
1502
|
interactive: true,
|
|
1466
1503
|
arrow: false,
|
|
1467
1504
|
offset: [0, 8],
|
|
@@ -1573,7 +1610,7 @@ class TiptapBubbleMenuComponent {
|
|
|
1573
1610
|
ed.chain().focus().toggleHighlight().run();
|
|
1574
1611
|
break;
|
|
1575
1612
|
case "link":
|
|
1576
|
-
const href = window.prompt(
|
|
1613
|
+
const href = window.prompt(this.i18nService.editor().linkPrompt);
|
|
1577
1614
|
if (href) {
|
|
1578
1615
|
ed.chain().focus().toggleLink({ href }).run();
|
|
1579
1616
|
}
|
|
@@ -1768,7 +1805,7 @@ class TiptapSeparatorComponent {
|
|
|
1768
1805
|
[class.medium]="size() === 'medium'"
|
|
1769
1806
|
[class.large]="size() === 'large'"
|
|
1770
1807
|
></div>
|
|
1771
|
-
`, isInline: true, styles: [".tiptap-separator{background-color
|
|
1808
|
+
`, isInline: true, styles: [".tiptap-separator{background-color:var(--ate-border, #e2e8f0);margin:0}.tiptap-separator.vertical{width:1px;height:24px;margin:0 8px}.tiptap-separator.horizontal{height:1px;width:100%;margin:8px 0}.tiptap-separator.small.vertical{height:16px;margin:0 4px}.tiptap-separator.small.horizontal{margin:4px 0}.tiptap-separator.medium.vertical{height:24px;margin:0 8px}.tiptap-separator.medium.horizontal{margin:8px 0}.tiptap-separator.large.vertical{height:32px;margin:0 12px}.tiptap-separator.large.horizontal{margin:12px 0}\n"] }); }
|
|
1772
1809
|
}
|
|
1773
1810
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapSeparatorComponent, decorators: [{
|
|
1774
1811
|
type: Component,
|
|
@@ -1781,7 +1818,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
1781
1818
|
[class.medium]="size() === 'medium'"
|
|
1782
1819
|
[class.large]="size() === 'large'"
|
|
1783
1820
|
></div>
|
|
1784
|
-
`, styles: [".tiptap-separator{background-color
|
|
1821
|
+
`, styles: [".tiptap-separator{background-color:var(--ate-border, #e2e8f0);margin:0}.tiptap-separator.vertical{width:1px;height:24px;margin:0 8px}.tiptap-separator.horizontal{height:1px;width:100%;margin:8px 0}.tiptap-separator.small.vertical{height:16px;margin:0 4px}.tiptap-separator.small.horizontal{margin:4px 0}.tiptap-separator.medium.vertical{height:24px;margin:0 8px}.tiptap-separator.medium.horizontal{margin:8px 0}.tiptap-separator.large.vertical{height:32px;margin:0 12px}.tiptap-separator.large.horizontal{margin:12px 0}\n"] }]
|
|
1785
1822
|
}] });
|
|
1786
1823
|
|
|
1787
1824
|
class ImageService {
|
|
@@ -1789,7 +1826,10 @@ class ImageService {
|
|
|
1789
1826
|
// Signals pour l'état des images
|
|
1790
1827
|
this.selectedImage = signal(null);
|
|
1791
1828
|
this.isImageSelected = computed(() => this.selectedImage() !== null);
|
|
1829
|
+
// Resizing signals
|
|
1792
1830
|
this.isResizing = signal(false);
|
|
1831
|
+
this.i18n = inject(TiptapI18nService);
|
|
1832
|
+
this.t = this.i18n.imageUpload;
|
|
1793
1833
|
// Signaux pour l'upload
|
|
1794
1834
|
this.isUploading = signal(false);
|
|
1795
1835
|
this.uploadProgress = signal(0);
|
|
@@ -1947,7 +1987,7 @@ class ImageService {
|
|
|
1947
1987
|
resolve({ width: img.naturalWidth, height: img.naturalHeight });
|
|
1948
1988
|
};
|
|
1949
1989
|
img.onerror = () => {
|
|
1950
|
-
reject(new Error(
|
|
1990
|
+
reject(new Error(this.t().loadError));
|
|
1951
1991
|
};
|
|
1952
1992
|
img.src = src;
|
|
1953
1993
|
});
|
|
@@ -1968,12 +2008,12 @@ class ImageService {
|
|
|
1968
2008
|
// Validation des images
|
|
1969
2009
|
validateImage(file, maxSize = 5 * 1024 * 1024) {
|
|
1970
2010
|
if (!file.type.startsWith("image/")) {
|
|
1971
|
-
return { valid: false, error:
|
|
2011
|
+
return { valid: false, error: this.t().invalidFileType };
|
|
1972
2012
|
}
|
|
1973
2013
|
if (file.size > maxSize) {
|
|
1974
2014
|
return {
|
|
1975
2015
|
valid: false,
|
|
1976
|
-
error:
|
|
2016
|
+
error: `${this.t().imageTooLarge} (max ${maxSize / 1024 / 1024}MB)`,
|
|
1977
2017
|
};
|
|
1978
2018
|
}
|
|
1979
2019
|
return { valid: true };
|
|
@@ -1988,7 +2028,7 @@ class ImageService {
|
|
|
1988
2028
|
// Mise à jour du progrès
|
|
1989
2029
|
if (this.isUploading()) {
|
|
1990
2030
|
this.uploadProgress.set(40);
|
|
1991
|
-
this.uploadMessage.set(
|
|
2031
|
+
this.uploadMessage.set(this.t().resizing);
|
|
1992
2032
|
this.forceEditorUpdate();
|
|
1993
2033
|
}
|
|
1994
2034
|
let { width, height } = img;
|
|
@@ -2005,7 +2045,7 @@ class ImageService {
|
|
|
2005
2045
|
// Mise à jour du progrès
|
|
2006
2046
|
if (this.isUploading()) {
|
|
2007
2047
|
this.uploadProgress.set(60);
|
|
2008
|
-
this.uploadMessage.set(
|
|
2048
|
+
this.uploadMessage.set(this.t().compressing);
|
|
2009
2049
|
this.forceEditorUpdate();
|
|
2010
2050
|
}
|
|
2011
2051
|
// Convertir en base64 avec compression
|
|
@@ -2027,17 +2067,17 @@ class ImageService {
|
|
|
2027
2067
|
resolve(result);
|
|
2028
2068
|
}
|
|
2029
2069
|
else {
|
|
2030
|
-
reject(new Error(
|
|
2070
|
+
reject(new Error(this.t().compressionError));
|
|
2031
2071
|
}
|
|
2032
2072
|
};
|
|
2033
2073
|
reader.readAsDataURL(blob);
|
|
2034
2074
|
}
|
|
2035
2075
|
else {
|
|
2036
|
-
reject(new Error(
|
|
2076
|
+
reject(new Error(this.t().compressionError));
|
|
2037
2077
|
}
|
|
2038
2078
|
}, file.type, quality);
|
|
2039
2079
|
};
|
|
2040
|
-
img.onerror = () => reject(new Error(
|
|
2080
|
+
img.onerror = () => reject(new Error(this.t().loadError));
|
|
2041
2081
|
img.src = URL.createObjectURL(file);
|
|
2042
2082
|
});
|
|
2043
2083
|
}
|
|
@@ -2048,7 +2088,7 @@ class ImageService {
|
|
|
2048
2088
|
this.currentEditor = editor;
|
|
2049
2089
|
this.isUploading.set(true);
|
|
2050
2090
|
this.uploadProgress.set(0);
|
|
2051
|
-
this.uploadMessage.set(
|
|
2091
|
+
this.uploadMessage.set(this.t().validating);
|
|
2052
2092
|
this.forceEditorUpdate();
|
|
2053
2093
|
// Validation
|
|
2054
2094
|
const validation = this.validateImage(file);
|
|
@@ -2056,7 +2096,7 @@ class ImageService {
|
|
|
2056
2096
|
throw new Error(validation.error);
|
|
2057
2097
|
}
|
|
2058
2098
|
this.uploadProgress.set(20);
|
|
2059
|
-
this.uploadMessage.set(
|
|
2099
|
+
this.uploadMessage.set(this.t().compressing);
|
|
2060
2100
|
this.forceEditorUpdate();
|
|
2061
2101
|
// Petit délai pour permettre à l'utilisateur de voir la progression
|
|
2062
2102
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
@@ -2064,7 +2104,7 @@ class ImageService {
|
|
|
2064
2104
|
this.uploadProgress.set(80);
|
|
2065
2105
|
// Si un handler personnalisé est défini, l'utiliser pour l'upload
|
|
2066
2106
|
if (this.uploadHandler) {
|
|
2067
|
-
this.uploadMessage.set(
|
|
2107
|
+
this.uploadMessage.set(this.t().uploadingToServer);
|
|
2068
2108
|
this.forceEditorUpdate();
|
|
2069
2109
|
try {
|
|
2070
2110
|
const handlerResponse = this.uploadHandler({
|
|
@@ -2086,7 +2126,7 @@ class ImageService {
|
|
|
2086
2126
|
}
|
|
2087
2127
|
}
|
|
2088
2128
|
catch (handlerError) {
|
|
2089
|
-
console.error(
|
|
2129
|
+
console.error(this.t().uploadError, handlerError);
|
|
2090
2130
|
throw handlerError;
|
|
2091
2131
|
}
|
|
2092
2132
|
}
|
|
@@ -2109,7 +2149,7 @@ class ImageService {
|
|
|
2109
2149
|
this.uploadMessage.set("");
|
|
2110
2150
|
this.forceEditorUpdate();
|
|
2111
2151
|
this.currentEditor = null;
|
|
2112
|
-
console.error(
|
|
2152
|
+
console.error(this.t().uploadError, error);
|
|
2113
2153
|
throw error;
|
|
2114
2154
|
}
|
|
2115
2155
|
}
|
|
@@ -2123,7 +2163,7 @@ class ImageService {
|
|
|
2123
2163
|
width: result.width,
|
|
2124
2164
|
height: result.height,
|
|
2125
2165
|
});
|
|
2126
|
-
},
|
|
2166
|
+
}, this.t().insertingImage, options);
|
|
2127
2167
|
}
|
|
2128
2168
|
// Méthode pour forcer la mise à jour de l'éditeur
|
|
2129
2169
|
forceEditorUpdate() {
|
|
@@ -2152,13 +2192,13 @@ class ImageService {
|
|
|
2152
2192
|
}
|
|
2153
2193
|
}
|
|
2154
2194
|
else {
|
|
2155
|
-
reject(new Error(
|
|
2195
|
+
reject(new Error(this.t().noFileSelected));
|
|
2156
2196
|
}
|
|
2157
2197
|
document.body.removeChild(input);
|
|
2158
2198
|
});
|
|
2159
2199
|
input.addEventListener("cancel", () => {
|
|
2160
2200
|
document.body.removeChild(input);
|
|
2161
|
-
reject(new Error(
|
|
2201
|
+
reject(new Error(this.t().selectionCancelled));
|
|
2162
2202
|
});
|
|
2163
2203
|
document.body.appendChild(input);
|
|
2164
2204
|
input.click();
|
|
@@ -2180,60 +2220,28 @@ class ImageService {
|
|
|
2180
2220
|
try {
|
|
2181
2221
|
// Supprimer visuellement l'ancienne image immédiatement
|
|
2182
2222
|
editor.chain().focus().deleteSelection().run();
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
throw new Error(validation.error);
|
|
2193
|
-
}
|
|
2194
|
-
this.uploadProgress.set(20);
|
|
2195
|
-
this.uploadMessage.set("Compression en cours...");
|
|
2196
|
-
this.forceEditorUpdate();
|
|
2197
|
-
// Petit délai pour permettre à l'utilisateur de voir la progression
|
|
2198
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
2199
|
-
const result = await this.compressImage(file, options?.quality || 0.8, options?.maxWidth || 1920, options?.maxHeight || 1080);
|
|
2200
|
-
this.uploadProgress.set(80);
|
|
2201
|
-
this.uploadMessage.set("Remplacement de l'image...");
|
|
2202
|
-
this.forceEditorUpdate();
|
|
2203
|
-
// Petit délai pour le remplacement
|
|
2204
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2205
|
-
// Insérer la nouvelle image à la position actuelle
|
|
2206
|
-
this.insertImage(editor, {
|
|
2207
|
-
src: result.src,
|
|
2208
|
-
alt: result.name,
|
|
2209
|
-
title: `${result.name} (${result.width}×${result.height})`,
|
|
2210
|
-
width: result.width,
|
|
2211
|
-
height: result.height,
|
|
2212
|
-
});
|
|
2213
|
-
// L'image est remplacée, maintenant on peut cacher l'indicateur
|
|
2214
|
-
this.isUploading.set(false);
|
|
2215
|
-
this.uploadProgress.set(0);
|
|
2216
|
-
this.uploadMessage.set("");
|
|
2217
|
-
this.forceEditorUpdate();
|
|
2218
|
-
this.currentEditor = null;
|
|
2223
|
+
await this.uploadImageWithProgress(editor, file, (editor, result) => {
|
|
2224
|
+
this.insertImage(editor, {
|
|
2225
|
+
src: result.src,
|
|
2226
|
+
alt: result.name,
|
|
2227
|
+
title: `${result.name} (${result.width}×${result.height})`,
|
|
2228
|
+
width: result.width,
|
|
2229
|
+
height: result.height,
|
|
2230
|
+
});
|
|
2231
|
+
}, this.t().replacingImage, options);
|
|
2219
2232
|
}
|
|
2220
2233
|
catch (error) {
|
|
2221
|
-
// En cas d'erreur, restaurer l'image originale
|
|
2234
|
+
// En cas d'erreur, restaurer l'image originale si elle existait
|
|
2222
2235
|
if (backupImage["src"]) {
|
|
2223
2236
|
this.insertImage(editor, {
|
|
2224
2237
|
src: backupImage["src"],
|
|
2225
|
-
alt: backupImage["alt"],
|
|
2226
|
-
title: backupImage["title"],
|
|
2238
|
+
alt: backupImage["alt"] || "",
|
|
2239
|
+
title: backupImage["title"] || "",
|
|
2227
2240
|
width: backupImage["width"],
|
|
2228
2241
|
height: backupImage["height"],
|
|
2229
2242
|
});
|
|
2230
2243
|
}
|
|
2231
|
-
|
|
2232
|
-
this.uploadProgress.set(0);
|
|
2233
|
-
this.uploadMessage.set("");
|
|
2234
|
-
this.forceEditorUpdate();
|
|
2235
|
-
this.currentEditor = null;
|
|
2236
|
-
console.error("Erreur lors du remplacement d'image:", error);
|
|
2244
|
+
console.error("Error during image replacement:", error);
|
|
2237
2245
|
throw error;
|
|
2238
2246
|
}
|
|
2239
2247
|
}
|
|
@@ -2249,6 +2257,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
2249
2257
|
|
|
2250
2258
|
class TiptapImageBubbleMenuComponent {
|
|
2251
2259
|
constructor() {
|
|
2260
|
+
this.i18nService = inject(TiptapI18nService);
|
|
2261
|
+
this.t = this.i18nService.imageUpload;
|
|
2252
2262
|
this.editor = input.required();
|
|
2253
2263
|
this.config = input({
|
|
2254
2264
|
changeImage: true,
|
|
@@ -2289,8 +2299,6 @@ class TiptapImageBubbleMenuComponent {
|
|
|
2289
2299
|
if (!ed)
|
|
2290
2300
|
return;
|
|
2291
2301
|
const isImageSelected = ed.isActive("resizableImage") || ed.isActive("image");
|
|
2292
|
-
const { from, to } = ed.state.selection;
|
|
2293
|
-
const hasTextSelection = from !== to;
|
|
2294
2302
|
// Ne montrer le menu image que si :
|
|
2295
2303
|
// - Une image est sélectionnée
|
|
2296
2304
|
// - L'éditeur est éditable
|
|
@@ -2365,7 +2373,10 @@ class TiptapImageBubbleMenuComponent {
|
|
|
2365
2373
|
content: menuElement,
|
|
2366
2374
|
trigger: "manual",
|
|
2367
2375
|
placement: "top-start",
|
|
2368
|
-
appendTo: () =>
|
|
2376
|
+
appendTo: (ref) => {
|
|
2377
|
+
const host = this.editor().options.element.closest("angular-tiptap-editor");
|
|
2378
|
+
return host || document.body;
|
|
2379
|
+
},
|
|
2369
2380
|
interactive: true,
|
|
2370
2381
|
arrow: false,
|
|
2371
2382
|
offset: [0, 8],
|
|
@@ -2492,7 +2503,7 @@ class TiptapImageBubbleMenuComponent {
|
|
|
2492
2503
|
});
|
|
2493
2504
|
}
|
|
2494
2505
|
catch (error) {
|
|
2495
|
-
console.error(
|
|
2506
|
+
console.error(this.i18nService.imageUpload().uploadError, error);
|
|
2496
2507
|
}
|
|
2497
2508
|
}
|
|
2498
2509
|
deleteImage() {
|
|
@@ -2507,7 +2518,7 @@ class TiptapImageBubbleMenuComponent {
|
|
|
2507
2518
|
@if (imageBubbleMenuConfig().changeImage) {
|
|
2508
2519
|
<tiptap-button
|
|
2509
2520
|
icon="drive_file_rename_outline"
|
|
2510
|
-
title="
|
|
2521
|
+
[title]="t().changeImage"
|
|
2511
2522
|
(click)="onCommand('changeImage', $event)"
|
|
2512
2523
|
></tiptap-button>
|
|
2513
2524
|
} @if (imageBubbleMenuConfig().separator && hasResizeButtons()) {
|
|
@@ -2516,27 +2527,27 @@ class TiptapImageBubbleMenuComponent {
|
|
|
2516
2527
|
<tiptap-button
|
|
2517
2528
|
icon="crop_square"
|
|
2518
2529
|
iconSize="small"
|
|
2519
|
-
title="
|
|
2530
|
+
[title]="t().resizeSmall"
|
|
2520
2531
|
(click)="onCommand('resizeSmall', $event)"
|
|
2521
2532
|
></tiptap-button>
|
|
2522
2533
|
} @if (imageBubbleMenuConfig().resizeMedium) {
|
|
2523
2534
|
<tiptap-button
|
|
2524
2535
|
icon="crop_square"
|
|
2525
2536
|
iconSize="medium"
|
|
2526
|
-
title="
|
|
2537
|
+
[title]="t().resizeMedium"
|
|
2527
2538
|
(click)="onCommand('resizeMedium', $event)"
|
|
2528
2539
|
></tiptap-button>
|
|
2529
2540
|
} @if (imageBubbleMenuConfig().resizeLarge) {
|
|
2530
2541
|
<tiptap-button
|
|
2531
2542
|
icon="crop_square"
|
|
2532
2543
|
iconSize="large"
|
|
2533
|
-
title="
|
|
2544
|
+
[title]="t().resizeLarge"
|
|
2534
2545
|
(click)="onCommand('resizeLarge', $event)"
|
|
2535
2546
|
></tiptap-button>
|
|
2536
2547
|
} @if (imageBubbleMenuConfig().resizeOriginal) {
|
|
2537
2548
|
<tiptap-button
|
|
2538
2549
|
icon="photo_size_select_actual"
|
|
2539
|
-
title="
|
|
2550
|
+
[title]="t().resizeOriginal"
|
|
2540
2551
|
(click)="onCommand('resizeOriginal', $event)"
|
|
2541
2552
|
></tiptap-button>
|
|
2542
2553
|
} @if (imageBubbleMenuConfig().separator &&
|
|
@@ -2545,7 +2556,7 @@ class TiptapImageBubbleMenuComponent {
|
|
|
2545
2556
|
} @if (imageBubbleMenuConfig().deleteImage) {
|
|
2546
2557
|
<tiptap-button
|
|
2547
2558
|
icon="delete"
|
|
2548
|
-
title="
|
|
2559
|
+
[title]="t().deleteImage"
|
|
2549
2560
|
variant="danger"
|
|
2550
2561
|
(click)="onCommand('deleteImage', $event)"
|
|
2551
2562
|
></tiptap-button>
|
|
@@ -2560,7 +2571,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
2560
2571
|
@if (imageBubbleMenuConfig().changeImage) {
|
|
2561
2572
|
<tiptap-button
|
|
2562
2573
|
icon="drive_file_rename_outline"
|
|
2563
|
-
title="
|
|
2574
|
+
[title]="t().changeImage"
|
|
2564
2575
|
(click)="onCommand('changeImage', $event)"
|
|
2565
2576
|
></tiptap-button>
|
|
2566
2577
|
} @if (imageBubbleMenuConfig().separator && hasResizeButtons()) {
|
|
@@ -2569,27 +2580,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
2569
2580
|
<tiptap-button
|
|
2570
2581
|
icon="crop_square"
|
|
2571
2582
|
iconSize="small"
|
|
2572
|
-
title="
|
|
2583
|
+
[title]="t().resizeSmall"
|
|
2573
2584
|
(click)="onCommand('resizeSmall', $event)"
|
|
2574
2585
|
></tiptap-button>
|
|
2575
2586
|
} @if (imageBubbleMenuConfig().resizeMedium) {
|
|
2576
2587
|
<tiptap-button
|
|
2577
2588
|
icon="crop_square"
|
|
2578
2589
|
iconSize="medium"
|
|
2579
|
-
title="
|
|
2590
|
+
[title]="t().resizeMedium"
|
|
2580
2591
|
(click)="onCommand('resizeMedium', $event)"
|
|
2581
2592
|
></tiptap-button>
|
|
2582
2593
|
} @if (imageBubbleMenuConfig().resizeLarge) {
|
|
2583
2594
|
<tiptap-button
|
|
2584
2595
|
icon="crop_square"
|
|
2585
2596
|
iconSize="large"
|
|
2586
|
-
title="
|
|
2597
|
+
[title]="t().resizeLarge"
|
|
2587
2598
|
(click)="onCommand('resizeLarge', $event)"
|
|
2588
2599
|
></tiptap-button>
|
|
2589
2600
|
} @if (imageBubbleMenuConfig().resizeOriginal) {
|
|
2590
2601
|
<tiptap-button
|
|
2591
2602
|
icon="photo_size_select_actual"
|
|
2592
|
-
title="
|
|
2603
|
+
[title]="t().resizeOriginal"
|
|
2593
2604
|
(click)="onCommand('resizeOriginal', $event)"
|
|
2594
2605
|
></tiptap-button>
|
|
2595
2606
|
} @if (imageBubbleMenuConfig().separator &&
|
|
@@ -2598,7 +2609,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
2598
2609
|
} @if (imageBubbleMenuConfig().deleteImage) {
|
|
2599
2610
|
<tiptap-button
|
|
2600
2611
|
icon="delete"
|
|
2601
|
-
title="
|
|
2612
|
+
[title]="t().deleteImage"
|
|
2602
2613
|
variant="danger"
|
|
2603
2614
|
(click)="onCommand('deleteImage', $event)"
|
|
2604
2615
|
></tiptap-button>
|
|
@@ -2785,7 +2796,7 @@ class EditorCommandsService {
|
|
|
2785
2796
|
}
|
|
2786
2797
|
// Méthode pour vider le contenu
|
|
2787
2798
|
clearContent(editor) {
|
|
2788
|
-
editor.
|
|
2799
|
+
editor.commands.setContent("", true);
|
|
2789
2800
|
}
|
|
2790
2801
|
// Méthodes de base de l'éditeur
|
|
2791
2802
|
focus(editor) {
|
|
@@ -2795,11 +2806,14 @@ class EditorCommandsService {
|
|
|
2795
2806
|
editor.chain().blur().run();
|
|
2796
2807
|
}
|
|
2797
2808
|
setContent(editor, content, emitUpdate = true) {
|
|
2798
|
-
editor.
|
|
2809
|
+
editor.commands.setContent(content, emitUpdate);
|
|
2799
2810
|
}
|
|
2800
2811
|
setEditable(editor, editable) {
|
|
2801
2812
|
editor.setEditable(editable);
|
|
2802
2813
|
}
|
|
2814
|
+
insertContent(editor, content) {
|
|
2815
|
+
editor.chain().focus().insertContent(content).run();
|
|
2816
|
+
}
|
|
2803
2817
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2804
2818
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService, providedIn: "root" }); }
|
|
2805
2819
|
}
|
|
@@ -2822,7 +2836,7 @@ class TiptapTableBubbleMenuComponent {
|
|
|
2822
2836
|
this.tippyInstance = null;
|
|
2823
2837
|
this.updateTimeout = null;
|
|
2824
2838
|
// Signaux
|
|
2825
|
-
this.
|
|
2839
|
+
this.t = this.i18nService.table;
|
|
2826
2840
|
this.updateMenu = () => {
|
|
2827
2841
|
// Debounce pour éviter les appels trop fréquents
|
|
2828
2842
|
if (this.updateTimeout) {
|
|
@@ -2904,8 +2918,11 @@ class TiptapTableBubbleMenuComponent {
|
|
|
2904
2918
|
this.tippyInstance = tippy(document.body, {
|
|
2905
2919
|
content: menuElement,
|
|
2906
2920
|
trigger: "manual",
|
|
2907
|
-
placement: "
|
|
2908
|
-
appendTo: () =>
|
|
2921
|
+
placement: "bottom-start",
|
|
2922
|
+
appendTo: (ref) => {
|
|
2923
|
+
const host = this.editor().options.element.closest("angular-tiptap-editor");
|
|
2924
|
+
return host || document.body;
|
|
2925
|
+
},
|
|
2909
2926
|
interactive: true,
|
|
2910
2927
|
arrow: false,
|
|
2911
2928
|
offset: [0, 8],
|
|
@@ -3034,19 +3051,19 @@ class TiptapTableBubbleMenuComponent {
|
|
|
3034
3051
|
@if (config().addRowBefore !== false) {
|
|
3035
3052
|
<tiptap-button
|
|
3036
3053
|
icon="add_row_above"
|
|
3037
|
-
title="{{
|
|
3054
|
+
title="{{ t().addRowBefore }}"
|
|
3038
3055
|
(click)="addRowBefore()"
|
|
3039
3056
|
></tiptap-button>
|
|
3040
3057
|
} @if (config().addRowAfter !== false) {
|
|
3041
3058
|
<tiptap-button
|
|
3042
3059
|
icon="add_row_below"
|
|
3043
|
-
title="{{
|
|
3060
|
+
title="{{ t().addRowAfter }}"
|
|
3044
3061
|
(click)="addRowAfter()"
|
|
3045
3062
|
></tiptap-button>
|
|
3046
3063
|
} @if (config().deleteRow !== false) {
|
|
3047
3064
|
<tiptap-button
|
|
3048
3065
|
icon="delete"
|
|
3049
|
-
title="{{
|
|
3066
|
+
title="{{ t().deleteRow }}"
|
|
3050
3067
|
variant="danger"
|
|
3051
3068
|
(click)="deleteRow()"
|
|
3052
3069
|
></tiptap-button>
|
|
@@ -3058,19 +3075,19 @@ class TiptapTableBubbleMenuComponent {
|
|
|
3058
3075
|
@if (config().addColumnBefore !== false) {
|
|
3059
3076
|
<tiptap-button
|
|
3060
3077
|
icon="add_column_left"
|
|
3061
|
-
title="{{
|
|
3078
|
+
title="{{ t().addColumnBefore }}"
|
|
3062
3079
|
(click)="addColumnBefore()"
|
|
3063
3080
|
></tiptap-button>
|
|
3064
3081
|
} @if (config().addColumnAfter !== false) {
|
|
3065
3082
|
<tiptap-button
|
|
3066
3083
|
icon="add_column_right"
|
|
3067
|
-
title="{{
|
|
3084
|
+
title="{{ t().addColumnAfter }}"
|
|
3068
3085
|
(click)="addColumnAfter()"
|
|
3069
3086
|
></tiptap-button>
|
|
3070
3087
|
} @if (config().deleteColumn !== false) {
|
|
3071
3088
|
<tiptap-button
|
|
3072
3089
|
icon="delete"
|
|
3073
|
-
title="{{
|
|
3090
|
+
title="{{ t().deleteColumn }}"
|
|
3074
3091
|
variant="danger"
|
|
3075
3092
|
(click)="deleteColumn()"
|
|
3076
3093
|
></tiptap-button>
|
|
@@ -3082,13 +3099,13 @@ class TiptapTableBubbleMenuComponent {
|
|
|
3082
3099
|
@if (config().toggleHeaderRow !== false) {
|
|
3083
3100
|
<tiptap-button
|
|
3084
3101
|
icon="toolbar"
|
|
3085
|
-
title="{{
|
|
3102
|
+
title="{{ t().toggleHeaderRow }}"
|
|
3086
3103
|
(click)="toggleHeaderRow()"
|
|
3087
3104
|
></tiptap-button>
|
|
3088
3105
|
} @if (config().toggleHeaderColumn !== false) {
|
|
3089
3106
|
<tiptap-button
|
|
3090
3107
|
icon="dock_to_right"
|
|
3091
|
-
title="{{
|
|
3108
|
+
title="{{ t().toggleHeaderColumn }}"
|
|
3092
3109
|
(click)="toggleHeaderColumn()"
|
|
3093
3110
|
></tiptap-button>
|
|
3094
3111
|
} @if (config().separator !== false && config().deleteTable !== false) {
|
|
@@ -3099,7 +3116,7 @@ class TiptapTableBubbleMenuComponent {
|
|
|
3099
3116
|
@if (config().deleteTable !== false) {
|
|
3100
3117
|
<tiptap-button
|
|
3101
3118
|
icon="delete_forever"
|
|
3102
|
-
title="{{
|
|
3119
|
+
title="{{ t().deleteTable }}"
|
|
3103
3120
|
variant="danger"
|
|
3104
3121
|
(click)="deleteTable()"
|
|
3105
3122
|
></tiptap-button>
|
|
@@ -3115,19 +3132,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3115
3132
|
@if (config().addRowBefore !== false) {
|
|
3116
3133
|
<tiptap-button
|
|
3117
3134
|
icon="add_row_above"
|
|
3118
|
-
title="{{
|
|
3135
|
+
title="{{ t().addRowBefore }}"
|
|
3119
3136
|
(click)="addRowBefore()"
|
|
3120
3137
|
></tiptap-button>
|
|
3121
3138
|
} @if (config().addRowAfter !== false) {
|
|
3122
3139
|
<tiptap-button
|
|
3123
3140
|
icon="add_row_below"
|
|
3124
|
-
title="{{
|
|
3141
|
+
title="{{ t().addRowAfter }}"
|
|
3125
3142
|
(click)="addRowAfter()"
|
|
3126
3143
|
></tiptap-button>
|
|
3127
3144
|
} @if (config().deleteRow !== false) {
|
|
3128
3145
|
<tiptap-button
|
|
3129
3146
|
icon="delete"
|
|
3130
|
-
title="{{
|
|
3147
|
+
title="{{ t().deleteRow }}"
|
|
3131
3148
|
variant="danger"
|
|
3132
3149
|
(click)="deleteRow()"
|
|
3133
3150
|
></tiptap-button>
|
|
@@ -3139,19 +3156,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3139
3156
|
@if (config().addColumnBefore !== false) {
|
|
3140
3157
|
<tiptap-button
|
|
3141
3158
|
icon="add_column_left"
|
|
3142
|
-
title="{{
|
|
3159
|
+
title="{{ t().addColumnBefore }}"
|
|
3143
3160
|
(click)="addColumnBefore()"
|
|
3144
3161
|
></tiptap-button>
|
|
3145
3162
|
} @if (config().addColumnAfter !== false) {
|
|
3146
3163
|
<tiptap-button
|
|
3147
3164
|
icon="add_column_right"
|
|
3148
|
-
title="{{
|
|
3165
|
+
title="{{ t().addColumnAfter }}"
|
|
3149
3166
|
(click)="addColumnAfter()"
|
|
3150
3167
|
></tiptap-button>
|
|
3151
3168
|
} @if (config().deleteColumn !== false) {
|
|
3152
3169
|
<tiptap-button
|
|
3153
3170
|
icon="delete"
|
|
3154
|
-
title="{{
|
|
3171
|
+
title="{{ t().deleteColumn }}"
|
|
3155
3172
|
variant="danger"
|
|
3156
3173
|
(click)="deleteColumn()"
|
|
3157
3174
|
></tiptap-button>
|
|
@@ -3163,13 +3180,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3163
3180
|
@if (config().toggleHeaderRow !== false) {
|
|
3164
3181
|
<tiptap-button
|
|
3165
3182
|
icon="toolbar"
|
|
3166
|
-
title="{{
|
|
3183
|
+
title="{{ t().toggleHeaderRow }}"
|
|
3167
3184
|
(click)="toggleHeaderRow()"
|
|
3168
3185
|
></tiptap-button>
|
|
3169
3186
|
} @if (config().toggleHeaderColumn !== false) {
|
|
3170
3187
|
<tiptap-button
|
|
3171
3188
|
icon="dock_to_right"
|
|
3172
|
-
title="{{
|
|
3189
|
+
title="{{ t().toggleHeaderColumn }}"
|
|
3173
3190
|
(click)="toggleHeaderColumn()"
|
|
3174
3191
|
></tiptap-button>
|
|
3175
3192
|
} @if (config().separator !== false && config().deleteTable !== false) {
|
|
@@ -3180,7 +3197,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3180
3197
|
@if (config().deleteTable !== false) {
|
|
3181
3198
|
<tiptap-button
|
|
3182
3199
|
icon="delete_forever"
|
|
3183
|
-
title="{{
|
|
3200
|
+
title="{{ t().deleteTable }}"
|
|
3184
3201
|
variant="danger"
|
|
3185
3202
|
(click)="deleteTable()"
|
|
3186
3203
|
></tiptap-button>
|
|
@@ -3283,7 +3300,10 @@ class TiptapCellBubbleMenuComponent {
|
|
|
3283
3300
|
content: menuElement,
|
|
3284
3301
|
trigger: "manual",
|
|
3285
3302
|
placement: "top-start",
|
|
3286
|
-
appendTo: () =>
|
|
3303
|
+
appendTo: (ref) => {
|
|
3304
|
+
const host = this.editor().options.element.closest("angular-tiptap-editor");
|
|
3305
|
+
return host || document.body;
|
|
3306
|
+
},
|
|
3287
3307
|
interactive: true,
|
|
3288
3308
|
arrow: false,
|
|
3289
3309
|
offset: [0, 8],
|
|
@@ -3440,6 +3460,7 @@ class TiptapToolbarComponent {
|
|
|
3440
3460
|
this.editorCommands = editorCommands;
|
|
3441
3461
|
this.editor = input.required();
|
|
3442
3462
|
this.config = input.required();
|
|
3463
|
+
this.imageUpload = input({});
|
|
3443
3464
|
// Outputs pour les événements d'image
|
|
3444
3465
|
this.imageUploaded = output();
|
|
3445
3466
|
this.imageError = output();
|
|
@@ -3513,11 +3534,17 @@ class TiptapToolbarComponent {
|
|
|
3513
3534
|
// Méthode pour insérer une image
|
|
3514
3535
|
async insertImage() {
|
|
3515
3536
|
try {
|
|
3516
|
-
|
|
3537
|
+
const config = this.imageUpload() || {};
|
|
3538
|
+
await this.imageService.selectAndUploadImage(this.editor(), {
|
|
3539
|
+
quality: config.quality,
|
|
3540
|
+
maxWidth: config.maxWidth,
|
|
3541
|
+
maxHeight: config.maxHeight,
|
|
3542
|
+
accept: config.allowedTypes?.join(',')
|
|
3543
|
+
});
|
|
3517
3544
|
}
|
|
3518
3545
|
catch (error) {
|
|
3519
|
-
console.error(
|
|
3520
|
-
this.imageError.emit(
|
|
3546
|
+
console.error(this.i18nService.imageUpload().uploadError, error);
|
|
3547
|
+
this.imageError.emit(this.i18nService.imageUpload().uploadError);
|
|
3521
3548
|
}
|
|
3522
3549
|
}
|
|
3523
3550
|
// Méthode pour vider le contenu
|
|
@@ -3532,7 +3559,7 @@ class TiptapToolbarComponent {
|
|
|
3532
3559
|
this.imageError.emit(error);
|
|
3533
3560
|
}
|
|
3534
3561
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapToolbarComponent, deps: [{ token: EditorCommandsService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3535
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: TiptapToolbarComponent, isStandalone: true, selector: "tiptap-toolbar", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", imageError: "imageError" }, ngImport: i0, template: `
|
|
3562
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: TiptapToolbarComponent, isStandalone: true, selector: "tiptap-toolbar", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageUploaded: "imageUploaded", imageError: "imageError" }, ngImport: i0, template: `
|
|
3536
3563
|
<div class="tiptap-toolbar">
|
|
3537
3564
|
@if (config().bold) {
|
|
3538
3565
|
<tiptap-button
|
|
@@ -3607,7 +3634,6 @@ class TiptapToolbarComponent {
|
|
|
3607
3634
|
<tiptap-button
|
|
3608
3635
|
icon="format_h1"
|
|
3609
3636
|
[title]="t().heading1"
|
|
3610
|
-
variant="text"
|
|
3611
3637
|
[active]="isActive('heading', { level: 1 })"
|
|
3612
3638
|
(onClick)="toggleHeading(1)"
|
|
3613
3639
|
/>
|
|
@@ -3615,7 +3641,6 @@ class TiptapToolbarComponent {
|
|
|
3615
3641
|
<tiptap-button
|
|
3616
3642
|
icon="format_h2"
|
|
3617
3643
|
[title]="t().heading2"
|
|
3618
|
-
variant="text"
|
|
3619
3644
|
[active]="isActive('heading', { level: 2 })"
|
|
3620
3645
|
(onClick)="toggleHeading(2)"
|
|
3621
3646
|
/>
|
|
@@ -3623,7 +3648,6 @@ class TiptapToolbarComponent {
|
|
|
3623
3648
|
<tiptap-button
|
|
3624
3649
|
icon="format_h3"
|
|
3625
3650
|
[title]="t().heading3"
|
|
3626
|
-
variant="text"
|
|
3627
3651
|
[active]="isActive('heading', { level: 3 })"
|
|
3628
3652
|
(onClick)="toggleHeading(3)"
|
|
3629
3653
|
/>
|
|
@@ -3737,7 +3761,7 @@ class TiptapToolbarComponent {
|
|
|
3737
3761
|
/>
|
|
3738
3762
|
}
|
|
3739
3763
|
</div>
|
|
3740
|
-
`, isInline: true, styles: [".tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:4px 8px;background
|
|
3764
|
+
`, isInline: true, styles: [".tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:4px 8px;background:var(--ate-toolbar-background);border-bottom:1px solid var(--ate-toolbar-border-color);flex-wrap:wrap;min-height:32px;position:relative;-webkit-backdrop-filter:blur(var(--ate-menu-blur, 16px));backdrop-filter:blur(var(--ate-menu-blur, 16px))}.toolbar-group{display:flex;align-items:center;gap:2px;padding:0 4px}.toolbar-separator{width:1px;height:24px;background:var(--ate-toolbar-border-color);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"], dependencies: [{ kind: "component", type: TiptapButtonComponent, selector: "tiptap-button", inputs: ["icon", "title", "active", "disabled", "color", "variant", "size", "iconSize"], outputs: ["onClick"] }, { kind: "component", type: TiptapSeparatorComponent, selector: "tiptap-separator", inputs: ["orientation", "size"] }, { kind: "component", type: TiptapTextColorPickerComponent, selector: "tiptap-text-color-picker", inputs: ["editor"], outputs: ["interactionChange", "requestUpdate"] }] }); }
|
|
3741
3765
|
}
|
|
3742
3766
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapToolbarComponent, decorators: [{
|
|
3743
3767
|
type: Component,
|
|
@@ -3820,7 +3844,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3820
3844
|
<tiptap-button
|
|
3821
3845
|
icon="format_h1"
|
|
3822
3846
|
[title]="t().heading1"
|
|
3823
|
-
variant="text"
|
|
3824
3847
|
[active]="isActive('heading', { level: 1 })"
|
|
3825
3848
|
(onClick)="toggleHeading(1)"
|
|
3826
3849
|
/>
|
|
@@ -3828,7 +3851,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3828
3851
|
<tiptap-button
|
|
3829
3852
|
icon="format_h2"
|
|
3830
3853
|
[title]="t().heading2"
|
|
3831
|
-
variant="text"
|
|
3832
3854
|
[active]="isActive('heading', { level: 2 })"
|
|
3833
3855
|
(onClick)="toggleHeading(2)"
|
|
3834
3856
|
/>
|
|
@@ -3836,7 +3858,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3836
3858
|
<tiptap-button
|
|
3837
3859
|
icon="format_h3"
|
|
3838
3860
|
[title]="t().heading3"
|
|
3839
|
-
variant="text"
|
|
3840
3861
|
[active]="isActive('heading', { level: 3 })"
|
|
3841
3862
|
(onClick)="toggleHeading(3)"
|
|
3842
3863
|
/>
|
|
@@ -3950,152 +3971,150 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
3950
3971
|
/>
|
|
3951
3972
|
}
|
|
3952
3973
|
</div>
|
|
3953
|
-
`, styles: [".tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:4px 8px;background
|
|
3974
|
+
`, styles: [".tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:4px 8px;background:var(--ate-toolbar-background);border-bottom:1px solid var(--ate-toolbar-border-color);flex-wrap:wrap;min-height:32px;position:relative;-webkit-backdrop-filter:blur(var(--ate-menu-blur, 16px));backdrop-filter:blur(var(--ate-menu-blur, 16px))}.toolbar-group{display:flex;align-items:center;gap:2px;padding:0 4px}.toolbar-separator{width:1px;height:24px;background:var(--ate-toolbar-border-color);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"] }]
|
|
3954
3975
|
}], ctorParameters: () => [{ type: EditorCommandsService }] });
|
|
3955
3976
|
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
},
|
|
3971
|
-
{
|
|
3972
|
-
title: "Titre 3",
|
|
3973
|
-
description: "Petit titre",
|
|
3974
|
-
icon: "format_h3",
|
|
3975
|
-
keywords: ["heading", "h3", "titre", "title", "3"],
|
|
3976
|
-
command: (editor) => editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
3977
|
-
},
|
|
3978
|
-
{
|
|
3979
|
-
title: "Liste à puces",
|
|
3980
|
-
description: "Créer une liste à puces",
|
|
3981
|
-
icon: "format_list_bulleted",
|
|
3982
|
-
keywords: ["bullet", "list", "liste", "puces", "ul"],
|
|
3983
|
-
command: (editor) => editor.chain().focus().toggleBulletList().run(),
|
|
3984
|
-
},
|
|
3985
|
-
{
|
|
3986
|
-
title: "Liste numérotée",
|
|
3987
|
-
description: "Créer une liste numérotée",
|
|
3988
|
-
icon: "format_list_numbered",
|
|
3989
|
-
keywords: ["numbered", "list", "liste", "numérotée", "ol", "ordered"],
|
|
3990
|
-
command: (editor) => editor.chain().focus().toggleOrderedList().run(),
|
|
3991
|
-
},
|
|
3992
|
-
{
|
|
3993
|
-
title: "Citation",
|
|
3994
|
-
description: "Ajouter une citation",
|
|
3995
|
-
icon: "format_quote",
|
|
3996
|
-
keywords: ["quote", "blockquote", "citation"],
|
|
3997
|
-
command: (editor) => editor.chain().focus().toggleBlockquote().run(),
|
|
3998
|
-
},
|
|
3999
|
-
{
|
|
4000
|
-
title: "Code",
|
|
4001
|
-
description: "Bloc de code",
|
|
4002
|
-
icon: "code",
|
|
4003
|
-
keywords: ["code", "codeblock", "pre"],
|
|
4004
|
-
command: (editor) => editor.chain().focus().toggleCodeBlock().run(),
|
|
4005
|
-
},
|
|
4006
|
-
{
|
|
4007
|
-
title: "Image",
|
|
4008
|
-
description: "Insérer une image",
|
|
4009
|
-
icon: "image",
|
|
4010
|
-
keywords: ["image", "photo", "picture", "img"],
|
|
4011
|
-
command: (editor) => {
|
|
4012
|
-
// Créer un input file temporaire pour sélectionner une image
|
|
4013
|
-
const input = document.createElement("input");
|
|
4014
|
-
input.type = "file";
|
|
4015
|
-
input.accept = "image/*";
|
|
4016
|
-
input.style.display = "none";
|
|
4017
|
-
input.addEventListener("change", async (e) => {
|
|
4018
|
-
const file = e.target.files?.[0];
|
|
4019
|
-
if (file && file.type.startsWith("image/")) {
|
|
4020
|
-
try {
|
|
4021
|
-
// Utiliser la méthode de compression unifiée
|
|
4022
|
-
const canvas = document.createElement("canvas");
|
|
4023
|
-
const ctx = canvas.getContext("2d");
|
|
4024
|
-
const img = new Image();
|
|
4025
|
-
img.onload = () => {
|
|
4026
|
-
// Vérifier les dimensions (max 1920x1080)
|
|
4027
|
-
const maxWidth = 1920;
|
|
4028
|
-
const maxHeight = 1080;
|
|
4029
|
-
let { width, height } = img;
|
|
4030
|
-
// Redimensionner si nécessaire
|
|
4031
|
-
if (width > maxWidth || height > maxHeight) {
|
|
4032
|
-
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
4033
|
-
width *= ratio;
|
|
4034
|
-
height *= ratio;
|
|
4035
|
-
}
|
|
4036
|
-
canvas.width = width;
|
|
4037
|
-
canvas.height = height;
|
|
4038
|
-
// Dessiner l'image redimensionnée
|
|
4039
|
-
ctx?.drawImage(img, 0, 0, width, height);
|
|
4040
|
-
// Convertir en base64 avec compression
|
|
4041
|
-
canvas.toBlob((blob) => {
|
|
4042
|
-
if (blob) {
|
|
4043
|
-
const reader = new FileReader();
|
|
4044
|
-
reader.onload = (e) => {
|
|
4045
|
-
const base64 = e.target?.result;
|
|
4046
|
-
if (base64) {
|
|
4047
|
-
// Utiliser setResizableImage avec toutes les propriétés
|
|
4048
|
-
editor
|
|
4049
|
-
.chain()
|
|
4050
|
-
.focus()
|
|
4051
|
-
.setResizableImage({
|
|
4052
|
-
src: base64,
|
|
4053
|
-
alt: file.name,
|
|
4054
|
-
title: `${file.name} (${Math.round(width)}×${Math.round(height)})`,
|
|
4055
|
-
width: Math.round(width),
|
|
4056
|
-
height: Math.round(height),
|
|
4057
|
-
})
|
|
4058
|
-
.run();
|
|
4059
|
-
}
|
|
4060
|
-
};
|
|
4061
|
-
reader.readAsDataURL(blob);
|
|
4062
|
-
}
|
|
4063
|
-
}, file.type, 0.8 // qualité de compression
|
|
4064
|
-
);
|
|
4065
|
-
};
|
|
4066
|
-
img.onerror = () => {
|
|
4067
|
-
console.error("Erreur lors du chargement de l'image");
|
|
4068
|
-
};
|
|
4069
|
-
img.src = URL.createObjectURL(file);
|
|
4070
|
-
}
|
|
4071
|
-
catch (error) {
|
|
4072
|
-
console.error("Erreur lors de l'upload:", error);
|
|
4073
|
-
}
|
|
4074
|
-
}
|
|
4075
|
-
document.body.removeChild(input);
|
|
4076
|
-
});
|
|
4077
|
-
document.body.appendChild(input);
|
|
4078
|
-
input.click();
|
|
4079
|
-
},
|
|
4080
|
-
},
|
|
4081
|
-
{
|
|
4082
|
-
title: "Ligne horizontale",
|
|
4083
|
-
description: "Ajouter une ligne de séparation",
|
|
4084
|
-
icon: "horizontal_rule",
|
|
4085
|
-
keywords: ["hr", "horizontal", "rule", "ligne", "séparation"],
|
|
4086
|
-
command: (editor) => editor.chain().focus().setHorizontalRule().run(),
|
|
4087
|
-
},
|
|
3977
|
+
/**
|
|
3978
|
+
* Clés des commandes natives dans l'ordre d'affichage
|
|
3979
|
+
*/
|
|
3980
|
+
const SLASH_COMMAND_KEYS = [
|
|
3981
|
+
"heading1",
|
|
3982
|
+
"heading2",
|
|
3983
|
+
"heading3",
|
|
3984
|
+
"bulletList",
|
|
3985
|
+
"orderedList",
|
|
3986
|
+
"blockquote",
|
|
3987
|
+
"code",
|
|
3988
|
+
"image",
|
|
3989
|
+
"horizontalRule",
|
|
3990
|
+
"table",
|
|
4088
3991
|
];
|
|
3992
|
+
/**
|
|
3993
|
+
* Configuration par défaut : toutes les commandes natives sont activées
|
|
3994
|
+
*/
|
|
3995
|
+
const DEFAULT_SLASH_COMMANDS_CONFIG = {
|
|
3996
|
+
heading1: true,
|
|
3997
|
+
heading2: true,
|
|
3998
|
+
heading3: true,
|
|
3999
|
+
bulletList: true,
|
|
4000
|
+
orderedList: true,
|
|
4001
|
+
blockquote: true,
|
|
4002
|
+
code: true,
|
|
4003
|
+
image: true,
|
|
4004
|
+
horizontalRule: true,
|
|
4005
|
+
table: true,
|
|
4006
|
+
};
|
|
4007
|
+
/**
|
|
4008
|
+
* Factory pour créer les commandes natives avec leurs traductions et leur logique d'exécution.
|
|
4009
|
+
* Utilise les services de l'éditeur pour garantir une cohérence de comportement.
|
|
4010
|
+
*/
|
|
4011
|
+
function createDefaultSlashCommands(i18n, commands, images, imageOptions) {
|
|
4012
|
+
const t = i18n.slashCommands();
|
|
4013
|
+
return [
|
|
4014
|
+
{
|
|
4015
|
+
title: t.heading1.title,
|
|
4016
|
+
description: t.heading1.description,
|
|
4017
|
+
icon: "format_h1",
|
|
4018
|
+
keywords: t.heading1.keywords,
|
|
4019
|
+
command: (editor) => commands.toggleHeading(editor, 1),
|
|
4020
|
+
},
|
|
4021
|
+
{
|
|
4022
|
+
title: t.heading2.title,
|
|
4023
|
+
description: t.heading2.description,
|
|
4024
|
+
icon: "format_h2",
|
|
4025
|
+
keywords: t.heading2.keywords,
|
|
4026
|
+
command: (editor) => commands.toggleHeading(editor, 2),
|
|
4027
|
+
},
|
|
4028
|
+
{
|
|
4029
|
+
title: t.heading3.title,
|
|
4030
|
+
description: t.heading3.description,
|
|
4031
|
+
icon: "format_h3",
|
|
4032
|
+
keywords: t.heading3.keywords,
|
|
4033
|
+
command: (editor) => commands.toggleHeading(editor, 3),
|
|
4034
|
+
},
|
|
4035
|
+
{
|
|
4036
|
+
title: t.bulletList.title,
|
|
4037
|
+
description: t.bulletList.description,
|
|
4038
|
+
icon: "format_list_bulleted",
|
|
4039
|
+
keywords: t.bulletList.keywords,
|
|
4040
|
+
command: (editor) => commands.toggleBulletList(editor),
|
|
4041
|
+
},
|
|
4042
|
+
{
|
|
4043
|
+
title: t.orderedList.title,
|
|
4044
|
+
description: t.orderedList.description,
|
|
4045
|
+
icon: "format_list_numbered",
|
|
4046
|
+
keywords: t.orderedList.keywords,
|
|
4047
|
+
command: (editor) => commands.toggleOrderedList(editor),
|
|
4048
|
+
},
|
|
4049
|
+
{
|
|
4050
|
+
title: t.blockquote.title,
|
|
4051
|
+
description: t.blockquote.description,
|
|
4052
|
+
icon: "format_quote",
|
|
4053
|
+
keywords: t.blockquote.keywords,
|
|
4054
|
+
command: (editor) => commands.toggleBlockquote(editor),
|
|
4055
|
+
},
|
|
4056
|
+
{
|
|
4057
|
+
title: t.code.title,
|
|
4058
|
+
description: t.code.description,
|
|
4059
|
+
icon: "code",
|
|
4060
|
+
keywords: t.code.keywords,
|
|
4061
|
+
command: (editor) => commands.toggleCode(editor),
|
|
4062
|
+
},
|
|
4063
|
+
{
|
|
4064
|
+
title: t.image.title,
|
|
4065
|
+
description: t.image.description,
|
|
4066
|
+
icon: "image",
|
|
4067
|
+
keywords: t.image.keywords,
|
|
4068
|
+
command: (editor) => images.selectAndUploadImage(editor, {
|
|
4069
|
+
quality: imageOptions?.quality,
|
|
4070
|
+
maxWidth: imageOptions?.maxWidth,
|
|
4071
|
+
maxHeight: imageOptions?.maxHeight,
|
|
4072
|
+
accept: imageOptions?.allowedTypes?.join(',')
|
|
4073
|
+
}),
|
|
4074
|
+
},
|
|
4075
|
+
{
|
|
4076
|
+
title: t.horizontalRule.title,
|
|
4077
|
+
description: t.horizontalRule.description,
|
|
4078
|
+
icon: "horizontal_rule",
|
|
4079
|
+
keywords: t.horizontalRule.keywords,
|
|
4080
|
+
command: (editor) => commands.insertHorizontalRule(editor),
|
|
4081
|
+
},
|
|
4082
|
+
{
|
|
4083
|
+
title: t.table.title,
|
|
4084
|
+
description: t.table.description,
|
|
4085
|
+
icon: "table_view",
|
|
4086
|
+
keywords: t.table.keywords,
|
|
4087
|
+
command: (editor) => commands.insertTable(editor),
|
|
4088
|
+
},
|
|
4089
|
+
];
|
|
4090
|
+
}
|
|
4091
|
+
/**
|
|
4092
|
+
* Filtre et assemble les commandes selon la configuration fournie.
|
|
4093
|
+
*/
|
|
4094
|
+
function filterSlashCommands(config, i18n, commands, images, imageOptions) {
|
|
4095
|
+
const allNatives = createDefaultSlashCommands(i18n, commands, images, imageOptions);
|
|
4096
|
+
const activeConfig = { ...DEFAULT_SLASH_COMMANDS_CONFIG, ...config };
|
|
4097
|
+
const filtered = allNatives.filter((_, index) => {
|
|
4098
|
+
const key = SLASH_COMMAND_KEYS[index];
|
|
4099
|
+
return key && activeConfig[key] !== false;
|
|
4100
|
+
});
|
|
4101
|
+
if (config.custom && Array.isArray(config.custom)) {
|
|
4102
|
+
return [...filtered, ...config.custom];
|
|
4103
|
+
}
|
|
4104
|
+
return filtered;
|
|
4105
|
+
}
|
|
4106
|
+
|
|
4107
|
+
// La définition des commandes par défaut est maintenant centralisée dans src/lib/config/i18n-slash-commands.ts
|
|
4089
4108
|
class TiptapSlashCommandsComponent {
|
|
4090
4109
|
constructor() {
|
|
4110
|
+
this.i18nService = inject(TiptapI18nService);
|
|
4091
4111
|
this.editor = input.required();
|
|
4092
|
-
this.config = input(
|
|
4093
|
-
commands: DEFAULT_SLASH_COMMANDS$1,
|
|
4094
|
-
});
|
|
4112
|
+
this.config = input(undefined);
|
|
4095
4113
|
// Output pour l'upload d'image
|
|
4096
4114
|
this.imageUploadRequested = output();
|
|
4097
4115
|
this.tippyInstance = null;
|
|
4098
4116
|
this.imageService = inject(ImageService);
|
|
4117
|
+
this.editorCommands = inject(EditorCommandsService);
|
|
4099
4118
|
// État local
|
|
4100
4119
|
this.isActive = false;
|
|
4101
4120
|
this.currentQuery = signal("");
|
|
@@ -4103,32 +4122,12 @@ class TiptapSlashCommandsComponent {
|
|
|
4103
4122
|
// Signal pour l'index sélectionné
|
|
4104
4123
|
this.selectedIndex = signal(0);
|
|
4105
4124
|
this.commands = computed(() => {
|
|
4106
|
-
const
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
command: (editor) => {
|
|
4113
|
-
// Créer un input file temporaire
|
|
4114
|
-
const input = document.createElement("input");
|
|
4115
|
-
input.type = "file";
|
|
4116
|
-
input.accept = "image/*";
|
|
4117
|
-
input.style.display = "none";
|
|
4118
|
-
input.addEventListener("change", (e) => {
|
|
4119
|
-
const file = e.target.files?.[0];
|
|
4120
|
-
if (file && file.type.startsWith("image/")) {
|
|
4121
|
-
this.imageUploadRequested.emit(file);
|
|
4122
|
-
}
|
|
4123
|
-
document.body.removeChild(input);
|
|
4124
|
-
});
|
|
4125
|
-
document.body.appendChild(input);
|
|
4126
|
-
input.click();
|
|
4127
|
-
},
|
|
4128
|
-
};
|
|
4129
|
-
}
|
|
4130
|
-
return command;
|
|
4131
|
-
});
|
|
4125
|
+
const config = this.config();
|
|
4126
|
+
if (config && config.commands) {
|
|
4127
|
+
return config.commands;
|
|
4128
|
+
}
|
|
4129
|
+
// Fallback vers les commandes natives par défaut
|
|
4130
|
+
return createDefaultSlashCommands(this.i18nService, this.editorCommands, this.imageService);
|
|
4132
4131
|
});
|
|
4133
4132
|
this.filteredCommands = computed(() => {
|
|
4134
4133
|
const query = this.currentQuery().toLowerCase();
|
|
@@ -4265,7 +4264,11 @@ class TiptapSlashCommandsComponent {
|
|
|
4265
4264
|
content: menuElement,
|
|
4266
4265
|
trigger: "manual",
|
|
4267
4266
|
placement: "bottom-start",
|
|
4268
|
-
appendTo: () =>
|
|
4267
|
+
appendTo: (ref) => {
|
|
4268
|
+
// Toujours essayer de remonter jusqu'au host de l'éditeur pour hériter des variables CSS
|
|
4269
|
+
const host = this.editor().options.element.closest("angular-tiptap-editor");
|
|
4270
|
+
return host || document.body;
|
|
4271
|
+
},
|
|
4269
4272
|
interactive: true,
|
|
4270
4273
|
arrow: false,
|
|
4271
4274
|
offset: [0, 8],
|
|
@@ -4304,7 +4307,7 @@ class TiptapSlashCommandsComponent {
|
|
|
4304
4307
|
return new DOMRect(coords.left, coords.top, 0, coords.bottom - coords.top);
|
|
4305
4308
|
}
|
|
4306
4309
|
catch (error) {
|
|
4307
|
-
console.warn("
|
|
4310
|
+
console.warn("Error calculating coordinates:", error);
|
|
4308
4311
|
// Fallback sur window.getSelection
|
|
4309
4312
|
const selection = window.getSelection();
|
|
4310
4313
|
if (!selection || selection.rangeCount === 0) {
|
|
@@ -4337,14 +4340,18 @@ class TiptapSlashCommandsComponent {
|
|
|
4337
4340
|
const ed = this.editor();
|
|
4338
4341
|
if (!ed || !this.slashRange)
|
|
4339
4342
|
return;
|
|
4340
|
-
// Supprimer le texte slash
|
|
4343
|
+
// Supprimer le texte slash ("/")
|
|
4341
4344
|
const { tr } = ed.state;
|
|
4342
4345
|
tr.delete(this.slashRange.from, this.slashRange.to);
|
|
4343
4346
|
ed.view.dispatch(tr);
|
|
4344
|
-
// Cacher le menu
|
|
4347
|
+
// Cacher le menu immédiatement
|
|
4345
4348
|
this.hideTippy();
|
|
4346
|
-
|
|
4349
|
+
this.isActive = false;
|
|
4350
|
+
// Redonner le focus à l'éditeur et exécuter la commande
|
|
4351
|
+
// On utilise un micro-délai pour s'assurer que le DOM ProseMirror est stable
|
|
4352
|
+
// après la suppression du texte "/"
|
|
4347
4353
|
setTimeout(() => {
|
|
4354
|
+
ed.commands.focus();
|
|
4348
4355
|
command.command(ed);
|
|
4349
4356
|
}, 10);
|
|
4350
4357
|
}
|
|
@@ -4408,7 +4415,7 @@ class TiptapSlashCommandsComponent {
|
|
|
4408
4415
|
<div
|
|
4409
4416
|
class="slash-command-item"
|
|
4410
4417
|
[class.selected]="$index === selectedIndex()"
|
|
4411
|
-
(
|
|
4418
|
+
(mousedown)="executeCommand(command); $event.preventDefault(); $event.stopPropagation()"
|
|
4412
4419
|
(mouseenter)="selectedIndex.set($index)"
|
|
4413
4420
|
>
|
|
4414
4421
|
<div class="slash-command-icon">
|
|
@@ -4421,7 +4428,7 @@ class TiptapSlashCommandsComponent {
|
|
|
4421
4428
|
</div>
|
|
4422
4429
|
}
|
|
4423
4430
|
</div>
|
|
4424
|
-
`, isInline: true, styles: [".slash-commands-menu{background
|
|
4431
|
+
`, isInline: true, styles: [".slash-commands-menu{background:var(--ate-menu-bg);-webkit-backdrop-filter:blur(var(--ate-menu-blur, 16px));backdrop-filter:blur(var(--ate-menu-blur, 16px));border:1px solid var(--ate-menu-border);border-radius:var(--ate-border-radius, 12px);box-shadow:var(--ate-menu-shadow);padding:6px;max-height:320px;overflow-y:auto;min-width:280px;outline:none;animation:slashMenuFadeIn .2s cubic-bezier(0,0,.2,1);scrollbar-width:thin;scrollbar-color:var(--ate-scrollbar-thumb) var(--ate-scrollbar-track)}.slash-commands-menu::-webkit-scrollbar{width:var(--ate-scrollbar-width)}.slash-commands-menu::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.slash-commands-menu::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.slash-commands-menu::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}@keyframes slashMenuFadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.slash-command-item{display:flex;align-items:center;gap:12px;padding:8px 12px;border-radius:var(--ate-border-radius, 8px);cursor:pointer;transition:all .15s ease;border:var(--ate-border-width, 1px) solid transparent;outline:none;margin-bottom:2px}.slash-command-item:last-child{margin-bottom:0}.slash-command-item:hover{background:var(--ate-surface-secondary)}.slash-command-item.selected{background:var(--ate-primary-light);border-color:var(--ate-primary-light-alpha)}.slash-command-icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;background:var(--ate-surface-tertiary);border-radius:var(--ate-border-radius, 8px);color:var(--ate-primary);flex-shrink:0;transition:all .15s ease}.slash-command-item.selected .slash-command-icon{background:var(--ate-primary);color:var(--ate-primary-contrast, #ffffff)}.slash-command-icon .material-symbols-outlined{font-size:18px}.slash-command-content{flex:1;min-width:0}.slash-command-title{font-weight:500;color:var(--ate-text);font-size:14px;margin-bottom:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.slash-command-description{color:var(--ate-text-secondary);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }); }
|
|
4425
4432
|
}
|
|
4426
4433
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapSlashCommandsComponent, decorators: [{
|
|
4427
4434
|
type: Component,
|
|
@@ -4431,7 +4438,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
4431
4438
|
<div
|
|
4432
4439
|
class="slash-command-item"
|
|
4433
4440
|
[class.selected]="$index === selectedIndex()"
|
|
4434
|
-
(
|
|
4441
|
+
(mousedown)="executeCommand(command); $event.preventDefault(); $event.stopPropagation()"
|
|
4435
4442
|
(mouseenter)="selectedIndex.set($index)"
|
|
4436
4443
|
>
|
|
4437
4444
|
<div class="slash-command-icon">
|
|
@@ -4444,7 +4451,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
4444
4451
|
</div>
|
|
4445
4452
|
}
|
|
4446
4453
|
</div>
|
|
4447
|
-
`, styles: [".slash-commands-menu{background
|
|
4454
|
+
`, styles: [".slash-commands-menu{background:var(--ate-menu-bg);-webkit-backdrop-filter:blur(var(--ate-menu-blur, 16px));backdrop-filter:blur(var(--ate-menu-blur, 16px));border:1px solid var(--ate-menu-border);border-radius:var(--ate-border-radius, 12px);box-shadow:var(--ate-menu-shadow);padding:6px;max-height:320px;overflow-y:auto;min-width:280px;outline:none;animation:slashMenuFadeIn .2s cubic-bezier(0,0,.2,1);scrollbar-width:thin;scrollbar-color:var(--ate-scrollbar-thumb) var(--ate-scrollbar-track)}.slash-commands-menu::-webkit-scrollbar{width:var(--ate-scrollbar-width)}.slash-commands-menu::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.slash-commands-menu::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.slash-commands-menu::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}@keyframes slashMenuFadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.slash-command-item{display:flex;align-items:center;gap:12px;padding:8px 12px;border-radius:var(--ate-border-radius, 8px);cursor:pointer;transition:all .15s ease;border:var(--ate-border-width, 1px) solid transparent;outline:none;margin-bottom:2px}.slash-command-item:last-child{margin-bottom:0}.slash-command-item:hover{background:var(--ate-surface-secondary)}.slash-command-item.selected{background:var(--ate-primary-light);border-color:var(--ate-primary-light-alpha)}.slash-command-icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;background:var(--ate-surface-tertiary);border-radius:var(--ate-border-radius, 8px);color:var(--ate-primary);flex-shrink:0;transition:all .15s ease}.slash-command-item.selected .slash-command-icon{background:var(--ate-primary);color:var(--ate-primary-contrast, #ffffff)}.slash-command-icon .material-symbols-outlined{font-size:18px}.slash-command-content{flex:1;min-width:0}.slash-command-title{font-weight:500;color:var(--ate-text);font-size:14px;margin-bottom:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.slash-command-description{color:var(--ate-text-secondary);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
|
|
4448
4455
|
}], ctorParameters: () => [], propDecorators: { menuRef: [{
|
|
4449
4456
|
type: ViewChild,
|
|
4450
4457
|
args: ["menuRef", { static: false }]
|
|
@@ -4452,350 +4459,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
4452
4459
|
|
|
4453
4460
|
// Main component
|
|
4454
4461
|
|
|
4455
|
-
class TiptapImageUploadComponent {
|
|
4456
|
-
constructor() {
|
|
4457
|
-
// Inputs
|
|
4458
|
-
this.config = input({
|
|
4459
|
-
maxSize: 5, // 5MB par défaut
|
|
4460
|
-
maxWidth: 1920, // largeur max par défaut
|
|
4461
|
-
maxHeight: 1080, // hauteur max par défaut
|
|
4462
|
-
allowedTypes: ["image/jpeg", "image/png", "image/gif", "image/webp"],
|
|
4463
|
-
enableDragDrop: true,
|
|
4464
|
-
showPreview: true,
|
|
4465
|
-
multiple: false,
|
|
4466
|
-
compressImages: true,
|
|
4467
|
-
quality: 0.8,
|
|
4468
|
-
});
|
|
4469
|
-
// Outputs
|
|
4470
|
-
this.imageSelected = output();
|
|
4471
|
-
this.error = output();
|
|
4472
|
-
// Signals internes
|
|
4473
|
-
this.isDragOver = signal(false);
|
|
4474
|
-
this.isUploading = signal(false);
|
|
4475
|
-
this.uploadProgress = signal(0);
|
|
4476
|
-
this.previewImage = signal(null);
|
|
4477
|
-
this.previewInfo = signal("");
|
|
4478
|
-
this.errorMessage = signal(null);
|
|
4479
|
-
// Computed
|
|
4480
|
-
this.acceptedTypes = computed(() => {
|
|
4481
|
-
const types = this.config().allowedTypes || ["image/*"];
|
|
4482
|
-
return types.join(",");
|
|
4483
|
-
});
|
|
4484
|
-
}
|
|
4485
|
-
triggerFileInput() {
|
|
4486
|
-
const input = document.querySelector('input[type="file"]');
|
|
4487
|
-
if (input) {
|
|
4488
|
-
input.click();
|
|
4489
|
-
}
|
|
4490
|
-
}
|
|
4491
|
-
onFileSelected(event) {
|
|
4492
|
-
const input = event.target;
|
|
4493
|
-
const files = input.files;
|
|
4494
|
-
if (files && files.length > 0) {
|
|
4495
|
-
this.processFiles(Array.from(files));
|
|
4496
|
-
}
|
|
4497
|
-
// Reset input
|
|
4498
|
-
input.value = "";
|
|
4499
|
-
}
|
|
4500
|
-
onDragOver(event) {
|
|
4501
|
-
event.preventDefault();
|
|
4502
|
-
event.stopPropagation();
|
|
4503
|
-
this.isDragOver.set(true);
|
|
4504
|
-
}
|
|
4505
|
-
onDrop(event) {
|
|
4506
|
-
event.preventDefault();
|
|
4507
|
-
event.stopPropagation();
|
|
4508
|
-
this.isDragOver.set(false);
|
|
4509
|
-
const files = event.dataTransfer?.files;
|
|
4510
|
-
if (files && files.length > 0) {
|
|
4511
|
-
this.processFiles(Array.from(files));
|
|
4512
|
-
}
|
|
4513
|
-
}
|
|
4514
|
-
onDragLeave(event) {
|
|
4515
|
-
event.preventDefault();
|
|
4516
|
-
event.stopPropagation();
|
|
4517
|
-
this.isDragOver.set(false);
|
|
4518
|
-
}
|
|
4519
|
-
processFiles(files) {
|
|
4520
|
-
const config = this.config();
|
|
4521
|
-
const maxSize = (config.maxSize || 5) * 1024 * 1024; // Convertir en bytes
|
|
4522
|
-
const allowedTypes = config.allowedTypes || ["image/*"];
|
|
4523
|
-
// Vérifier le nombre de fichiers
|
|
4524
|
-
if (!config.multiple && files.length > 1) {
|
|
4525
|
-
this.showError("Veuillez sélectionner une seule image");
|
|
4526
|
-
return;
|
|
4527
|
-
}
|
|
4528
|
-
// Traiter chaque fichier
|
|
4529
|
-
files.forEach((file) => {
|
|
4530
|
-
// Vérifier le type
|
|
4531
|
-
if (!this.isValidFileType(file, allowedTypes)) {
|
|
4532
|
-
this.showError(`Type de fichier non supporté: ${file.name}`);
|
|
4533
|
-
return;
|
|
4534
|
-
}
|
|
4535
|
-
// Vérifier la taille
|
|
4536
|
-
if (file.size > maxSize) {
|
|
4537
|
-
this.showError(`Fichier trop volumineux: ${file.name} (max ${config.maxSize}MB)`);
|
|
4538
|
-
return;
|
|
4539
|
-
}
|
|
4540
|
-
// Traiter l'image avec compression si nécessaire
|
|
4541
|
-
this.processImage(file);
|
|
4542
|
-
});
|
|
4543
|
-
}
|
|
4544
|
-
isValidFileType(file, allowedTypes) {
|
|
4545
|
-
if (allowedTypes.includes("image/*")) {
|
|
4546
|
-
return file.type.startsWith("image/");
|
|
4547
|
-
}
|
|
4548
|
-
return allowedTypes.includes(file.type);
|
|
4549
|
-
}
|
|
4550
|
-
processImage(file) {
|
|
4551
|
-
this.isUploading.set(true);
|
|
4552
|
-
this.uploadProgress.set(10);
|
|
4553
|
-
const config = this.config();
|
|
4554
|
-
const originalSize = file.size;
|
|
4555
|
-
// Créer un canvas pour la compression
|
|
4556
|
-
const canvas = document.createElement("canvas");
|
|
4557
|
-
const ctx = canvas.getContext("2d");
|
|
4558
|
-
const img = new Image();
|
|
4559
|
-
img.onload = () => {
|
|
4560
|
-
this.uploadProgress.set(30);
|
|
4561
|
-
// Vérifier les dimensions
|
|
4562
|
-
const maxWidth = config.maxWidth || 1920;
|
|
4563
|
-
const maxHeight = config.maxHeight || 1080;
|
|
4564
|
-
let { width, height } = img;
|
|
4565
|
-
// Redimensionner si nécessaire
|
|
4566
|
-
if (width > maxWidth || height > maxHeight) {
|
|
4567
|
-
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
4568
|
-
width *= ratio;
|
|
4569
|
-
height *= ratio;
|
|
4570
|
-
}
|
|
4571
|
-
canvas.width = width;
|
|
4572
|
-
canvas.height = height;
|
|
4573
|
-
// Dessiner l'image redimensionnée
|
|
4574
|
-
ctx?.drawImage(img, 0, 0, width, height);
|
|
4575
|
-
this.uploadProgress.set(70);
|
|
4576
|
-
// Convertir en base64 avec compression
|
|
4577
|
-
const quality = config.quality || 0.8;
|
|
4578
|
-
const mimeType = file.type;
|
|
4579
|
-
canvas.toBlob((blob) => {
|
|
4580
|
-
this.uploadProgress.set(90);
|
|
4581
|
-
if (blob) {
|
|
4582
|
-
const reader = new FileReader();
|
|
4583
|
-
reader.onload = (e) => {
|
|
4584
|
-
const base64 = e.target?.result;
|
|
4585
|
-
if (base64) {
|
|
4586
|
-
const result = {
|
|
4587
|
-
src: base64,
|
|
4588
|
-
name: file.name,
|
|
4589
|
-
size: blob.size,
|
|
4590
|
-
type: file.type,
|
|
4591
|
-
width: Math.round(width),
|
|
4592
|
-
height: Math.round(height),
|
|
4593
|
-
originalSize: originalSize,
|
|
4594
|
-
};
|
|
4595
|
-
// Afficher la prévisualisation si activée
|
|
4596
|
-
if (config.showPreview) {
|
|
4597
|
-
this.previewImage.set(base64);
|
|
4598
|
-
this.previewInfo.set(`${result.width}×${result.height} • ${this.formatFileSize(blob.size)}`);
|
|
4599
|
-
}
|
|
4600
|
-
// Émettre l'événement
|
|
4601
|
-
this.imageSelected.emit(result);
|
|
4602
|
-
this.clearError();
|
|
4603
|
-
}
|
|
4604
|
-
this.uploadProgress.set(100);
|
|
4605
|
-
setTimeout(() => {
|
|
4606
|
-
this.isUploading.set(false);
|
|
4607
|
-
this.uploadProgress.set(0);
|
|
4608
|
-
}, 500);
|
|
4609
|
-
};
|
|
4610
|
-
reader.readAsDataURL(blob);
|
|
4611
|
-
}
|
|
4612
|
-
else {
|
|
4613
|
-
this.showError("Erreur lors de la compression de l'image");
|
|
4614
|
-
this.isUploading.set(false);
|
|
4615
|
-
this.uploadProgress.set(0);
|
|
4616
|
-
}
|
|
4617
|
-
}, mimeType, quality);
|
|
4618
|
-
};
|
|
4619
|
-
img.onerror = () => {
|
|
4620
|
-
this.showError("Erreur lors du chargement de l'image");
|
|
4621
|
-
this.isUploading.set(false);
|
|
4622
|
-
this.uploadProgress.set(0);
|
|
4623
|
-
};
|
|
4624
|
-
img.src = URL.createObjectURL(file);
|
|
4625
|
-
}
|
|
4626
|
-
formatFileSize(bytes) {
|
|
4627
|
-
if (bytes === 0)
|
|
4628
|
-
return "0 B";
|
|
4629
|
-
const k = 1024;
|
|
4630
|
-
const sizes = ["B", "KB", "MB", "GB"];
|
|
4631
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
4632
|
-
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
|
|
4633
|
-
}
|
|
4634
|
-
showError(message) {
|
|
4635
|
-
this.errorMessage.set(message);
|
|
4636
|
-
this.error.emit(message);
|
|
4637
|
-
this.isUploading.set(false);
|
|
4638
|
-
this.uploadProgress.set(0);
|
|
4639
|
-
// Auto-clear après 5 secondes
|
|
4640
|
-
setTimeout(() => {
|
|
4641
|
-
this.clearError();
|
|
4642
|
-
}, 5000);
|
|
4643
|
-
}
|
|
4644
|
-
clearError() {
|
|
4645
|
-
this.errorMessage.set(null);
|
|
4646
|
-
}
|
|
4647
|
-
clearPreview() {
|
|
4648
|
-
this.previewImage.set(null);
|
|
4649
|
-
this.previewInfo.set("");
|
|
4650
|
-
}
|
|
4651
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapImageUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4652
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.0", type: TiptapImageUploadComponent, isStandalone: true, selector: "tiptap-image-upload", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageSelected: "imageSelected", error: "error" }, ngImport: i0, template: `
|
|
4653
|
-
<div class="image-upload-container">
|
|
4654
|
-
<!-- Bouton d'upload -->
|
|
4655
|
-
<tiptap-button
|
|
4656
|
-
icon="image"
|
|
4657
|
-
title="Ajouter une image"
|
|
4658
|
-
[disabled]="isUploading()"
|
|
4659
|
-
(onClick)="triggerFileInput()"
|
|
4660
|
-
/>
|
|
4661
|
-
|
|
4662
|
-
<!-- Input file caché -->
|
|
4663
|
-
<input
|
|
4664
|
-
#fileInput
|
|
4665
|
-
type="file"
|
|
4666
|
-
[accept]="acceptedTypes()"
|
|
4667
|
-
[multiple]="config().multiple"
|
|
4668
|
-
(change)="onFileSelected($event)"
|
|
4669
|
-
style="display: none;"
|
|
4670
|
-
/>
|
|
4671
|
-
|
|
4672
|
-
<!-- Zone de drag & drop -->
|
|
4673
|
-
@if (config().enableDragDrop && isDragOver()) {
|
|
4674
|
-
<div
|
|
4675
|
-
class="drag-overlay"
|
|
4676
|
-
(dragover)="onDragOver($event)"
|
|
4677
|
-
(drop)="onDrop($event)"
|
|
4678
|
-
(dragleave)="onDragLeave($event)"
|
|
4679
|
-
>
|
|
4680
|
-
<div class="drag-content">
|
|
4681
|
-
<span class="material-symbols-outlined">cloud_upload</span>
|
|
4682
|
-
<p>Déposez votre image ici</p>
|
|
4683
|
-
</div>
|
|
4684
|
-
</div>
|
|
4685
|
-
}
|
|
4686
|
-
|
|
4687
|
-
<!-- Barre de progression -->
|
|
4688
|
-
@if (isUploading() && uploadProgress() > 0) {
|
|
4689
|
-
<div class="upload-progress">
|
|
4690
|
-
<div class="progress-bar">
|
|
4691
|
-
<div class="progress-fill" [style.width.%]="uploadProgress()"></div>
|
|
4692
|
-
</div>
|
|
4693
|
-
<div class="progress-text">{{ uploadProgress() }}%</div>
|
|
4694
|
-
</div>
|
|
4695
|
-
}
|
|
4696
|
-
|
|
4697
|
-
<!-- Prévisualisation -->
|
|
4698
|
-
@if (config().showPreview && previewImage()) {
|
|
4699
|
-
<div class="image-preview">
|
|
4700
|
-
<img [src]="previewImage()" alt="Prévisualisation" />
|
|
4701
|
-
<div class="preview-info">
|
|
4702
|
-
<span>{{ previewInfo() }}</span>
|
|
4703
|
-
</div>
|
|
4704
|
-
<button
|
|
4705
|
-
class="preview-close"
|
|
4706
|
-
(click)="clearPreview()"
|
|
4707
|
-
title="Fermer la prévisualisation"
|
|
4708
|
-
>
|
|
4709
|
-
<span class="material-symbols-outlined">close</span>
|
|
4710
|
-
</button>
|
|
4711
|
-
</div>
|
|
4712
|
-
}
|
|
4713
|
-
|
|
4714
|
-
<!-- Messages d'erreur -->
|
|
4715
|
-
@if (errorMessage()) {
|
|
4716
|
-
<div class="error-message">
|
|
4717
|
-
<span class="material-symbols-outlined">error</span>
|
|
4718
|
-
{{ errorMessage() }}
|
|
4719
|
-
</div>
|
|
4720
|
-
}
|
|
4721
|
-
</div>
|
|
4722
|
-
`, isInline: true, styles: [".image-upload-container{position:relative;display:inline-block}.drag-overlay{position:fixed;inset:0;background:#3182ce1a;border:2px dashed #3182ce;border-radius:6px;display:flex;align-items:center;justify-content:center;z-index:1000;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.drag-content{text-align:center;color:#3182ce;font-weight:600}.drag-content .material-symbols-outlined{font-size:48px;margin-bottom:16px}.drag-content p{margin:0;font-size:18px}.upload-progress{position:absolute;top:100%;left:0;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:12px;margin-top:8px;z-index:100;min-width:200px;box-shadow:0 4px 12px #00000026}.progress-bar{width:100%;height:6px;background:#e2e8f0;border-radius:3px;overflow:hidden;margin-bottom:8px}.progress-fill{height:100%;background:#3182ce;border-radius:3px;transition:width .3s ease}.progress-text{font-size:12px;color:#4a5568;text-align:center}.image-preview{position:absolute;top:100%;left:0;background:#fff;border:1px solid #e2e8f0;border-radius:8px;box-shadow:0 4px 12px #00000026;padding:8px;margin-top:8px;z-index:100;min-width:200px}.image-preview img{max-width:200px;max-height:150px;border-radius:4px;display:block}.preview-info{margin-top:8px;font-size:11px;color:#718096;text-align:center}.preview-close{position:absolute;top:4px;right:4px;background:#000000b3;color:#fff;border:none;border-radius:50%;width:24px;height:24px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px}.preview-close:hover{background:#000000e6}.error-message{position:absolute;top:100%;left:0;background:#fed7d7;color:#c53030;border:1px solid #feb2b2;border-radius:6px;padding:8px 12px;margin-top:8px;font-size:12px;display:flex;align-items:center;gap:6px;z-index:100;min-width:200px}.error-message .material-symbols-outlined{font-size:16px}\n"], dependencies: [{ kind: "component", type: TiptapButtonComponent, selector: "tiptap-button", inputs: ["icon", "title", "active", "disabled", "color", "variant", "size", "iconSize"], outputs: ["onClick"] }] }); }
|
|
4723
|
-
}
|
|
4724
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapImageUploadComponent, decorators: [{
|
|
4725
|
-
type: Component,
|
|
4726
|
-
args: [{ selector: "tiptap-image-upload", standalone: true, imports: [TiptapButtonComponent], template: `
|
|
4727
|
-
<div class="image-upload-container">
|
|
4728
|
-
<!-- Bouton d'upload -->
|
|
4729
|
-
<tiptap-button
|
|
4730
|
-
icon="image"
|
|
4731
|
-
title="Ajouter une image"
|
|
4732
|
-
[disabled]="isUploading()"
|
|
4733
|
-
(onClick)="triggerFileInput()"
|
|
4734
|
-
/>
|
|
4735
|
-
|
|
4736
|
-
<!-- Input file caché -->
|
|
4737
|
-
<input
|
|
4738
|
-
#fileInput
|
|
4739
|
-
type="file"
|
|
4740
|
-
[accept]="acceptedTypes()"
|
|
4741
|
-
[multiple]="config().multiple"
|
|
4742
|
-
(change)="onFileSelected($event)"
|
|
4743
|
-
style="display: none;"
|
|
4744
|
-
/>
|
|
4745
|
-
|
|
4746
|
-
<!-- Zone de drag & drop -->
|
|
4747
|
-
@if (config().enableDragDrop && isDragOver()) {
|
|
4748
|
-
<div
|
|
4749
|
-
class="drag-overlay"
|
|
4750
|
-
(dragover)="onDragOver($event)"
|
|
4751
|
-
(drop)="onDrop($event)"
|
|
4752
|
-
(dragleave)="onDragLeave($event)"
|
|
4753
|
-
>
|
|
4754
|
-
<div class="drag-content">
|
|
4755
|
-
<span class="material-symbols-outlined">cloud_upload</span>
|
|
4756
|
-
<p>Déposez votre image ici</p>
|
|
4757
|
-
</div>
|
|
4758
|
-
</div>
|
|
4759
|
-
}
|
|
4760
|
-
|
|
4761
|
-
<!-- Barre de progression -->
|
|
4762
|
-
@if (isUploading() && uploadProgress() > 0) {
|
|
4763
|
-
<div class="upload-progress">
|
|
4764
|
-
<div class="progress-bar">
|
|
4765
|
-
<div class="progress-fill" [style.width.%]="uploadProgress()"></div>
|
|
4766
|
-
</div>
|
|
4767
|
-
<div class="progress-text">{{ uploadProgress() }}%</div>
|
|
4768
|
-
</div>
|
|
4769
|
-
}
|
|
4770
|
-
|
|
4771
|
-
<!-- Prévisualisation -->
|
|
4772
|
-
@if (config().showPreview && previewImage()) {
|
|
4773
|
-
<div class="image-preview">
|
|
4774
|
-
<img [src]="previewImage()" alt="Prévisualisation" />
|
|
4775
|
-
<div class="preview-info">
|
|
4776
|
-
<span>{{ previewInfo() }}</span>
|
|
4777
|
-
</div>
|
|
4778
|
-
<button
|
|
4779
|
-
class="preview-close"
|
|
4780
|
-
(click)="clearPreview()"
|
|
4781
|
-
title="Fermer la prévisualisation"
|
|
4782
|
-
>
|
|
4783
|
-
<span class="material-symbols-outlined">close</span>
|
|
4784
|
-
</button>
|
|
4785
|
-
</div>
|
|
4786
|
-
}
|
|
4787
|
-
|
|
4788
|
-
<!-- Messages d'erreur -->
|
|
4789
|
-
@if (errorMessage()) {
|
|
4790
|
-
<div class="error-message">
|
|
4791
|
-
<span class="material-symbols-outlined">error</span>
|
|
4792
|
-
{{ errorMessage() }}
|
|
4793
|
-
</div>
|
|
4794
|
-
}
|
|
4795
|
-
</div>
|
|
4796
|
-
`, styles: [".image-upload-container{position:relative;display:inline-block}.drag-overlay{position:fixed;inset:0;background:#3182ce1a;border:2px dashed #3182ce;border-radius:6px;display:flex;align-items:center;justify-content:center;z-index:1000;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.drag-content{text-align:center;color:#3182ce;font-weight:600}.drag-content .material-symbols-outlined{font-size:48px;margin-bottom:16px}.drag-content p{margin:0;font-size:18px}.upload-progress{position:absolute;top:100%;left:0;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:12px;margin-top:8px;z-index:100;min-width:200px;box-shadow:0 4px 12px #00000026}.progress-bar{width:100%;height:6px;background:#e2e8f0;border-radius:3px;overflow:hidden;margin-bottom:8px}.progress-fill{height:100%;background:#3182ce;border-radius:3px;transition:width .3s ease}.progress-text{font-size:12px;color:#4a5568;text-align:center}.image-preview{position:absolute;top:100%;left:0;background:#fff;border:1px solid #e2e8f0;border-radius:8px;box-shadow:0 4px 12px #00000026;padding:8px;margin-top:8px;z-index:100;min-width:200px}.image-preview img{max-width:200px;max-height:150px;border-radius:4px;display:block}.preview-info{margin-top:8px;font-size:11px;color:#718096;text-align:center}.preview-close{position:absolute;top:4px;right:4px;background:#000000b3;color:#fff;border:none;border-radius:50%;width:24px;height:24px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px}.preview-close:hover{background:#000000e6}.error-message{position:absolute;top:100%;left:0;background:#fed7d7;color:#c53030;border:1px solid #feb2b2;border-radius:6px;padding:8px 12px;margin-top:8px;font-size:12px;display:flex;align-items:center;gap:6px;z-index:100;min-width:200px}.error-message .material-symbols-outlined{font-size:16px}\n"] }]
|
|
4797
|
-
}] });
|
|
4798
|
-
|
|
4799
4462
|
class NoopValueAccessorDirective {
|
|
4800
4463
|
writeValue(obj) { }
|
|
4801
4464
|
registerOnChange(fn) { }
|
|
@@ -4823,178 +4486,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
4823
4486
|
}]
|
|
4824
4487
|
}] });
|
|
4825
4488
|
|
|
4826
|
-
/**
|
|
4827
|
-
* Clés des commandes dans l'ordre de création
|
|
4828
|
-
*/
|
|
4829
|
-
const SLASH_COMMAND_KEYS = [
|
|
4830
|
-
"heading1",
|
|
4831
|
-
"heading2",
|
|
4832
|
-
"heading3",
|
|
4833
|
-
"bulletList",
|
|
4834
|
-
"orderedList",
|
|
4835
|
-
"blockquote",
|
|
4836
|
-
"code",
|
|
4837
|
-
"image",
|
|
4838
|
-
"horizontalRule",
|
|
4839
|
-
"table",
|
|
4840
|
-
];
|
|
4841
|
-
/**
|
|
4842
|
-
* Factory function pour créer les slash commands traduits
|
|
4843
|
-
*/
|
|
4844
|
-
function createI18nSlashCommands(i18nService) {
|
|
4845
|
-
const slashCommands = i18nService.slashCommands();
|
|
4846
|
-
return [
|
|
4847
|
-
{
|
|
4848
|
-
title: slashCommands.heading1.title,
|
|
4849
|
-
description: slashCommands.heading1.description,
|
|
4850
|
-
icon: "format_h1",
|
|
4851
|
-
keywords: slashCommands.heading1.keywords,
|
|
4852
|
-
command: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run(),
|
|
4853
|
-
},
|
|
4854
|
-
{
|
|
4855
|
-
title: slashCommands.heading2.title,
|
|
4856
|
-
description: slashCommands.heading2.description,
|
|
4857
|
-
icon: "format_h2",
|
|
4858
|
-
keywords: slashCommands.heading2.keywords,
|
|
4859
|
-
command: (editor) => editor.chain().focus().toggleHeading({ level: 2 }).run(),
|
|
4860
|
-
},
|
|
4861
|
-
{
|
|
4862
|
-
title: slashCommands.heading3.title,
|
|
4863
|
-
description: slashCommands.heading3.description,
|
|
4864
|
-
icon: "format_h3",
|
|
4865
|
-
keywords: slashCommands.heading3.keywords,
|
|
4866
|
-
command: (editor) => editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
4867
|
-
},
|
|
4868
|
-
{
|
|
4869
|
-
title: slashCommands.bulletList.title,
|
|
4870
|
-
description: slashCommands.bulletList.description,
|
|
4871
|
-
icon: "format_list_bulleted",
|
|
4872
|
-
keywords: slashCommands.bulletList.keywords,
|
|
4873
|
-
command: (editor) => editor.chain().focus().toggleBulletList().run(),
|
|
4874
|
-
},
|
|
4875
|
-
{
|
|
4876
|
-
title: slashCommands.orderedList.title,
|
|
4877
|
-
description: slashCommands.orderedList.description,
|
|
4878
|
-
icon: "format_list_numbered",
|
|
4879
|
-
keywords: slashCommands.orderedList.keywords,
|
|
4880
|
-
command: (editor) => editor.chain().focus().toggleOrderedList().run(),
|
|
4881
|
-
},
|
|
4882
|
-
{
|
|
4883
|
-
title: slashCommands.blockquote.title,
|
|
4884
|
-
description: slashCommands.blockquote.description,
|
|
4885
|
-
icon: "format_quote",
|
|
4886
|
-
keywords: slashCommands.blockquote.keywords,
|
|
4887
|
-
command: (editor) => editor.chain().focus().toggleBlockquote().run(),
|
|
4888
|
-
},
|
|
4889
|
-
{
|
|
4890
|
-
title: slashCommands.code.title,
|
|
4891
|
-
description: slashCommands.code.description,
|
|
4892
|
-
icon: "code",
|
|
4893
|
-
keywords: slashCommands.code.keywords,
|
|
4894
|
-
command: (editor) => editor.chain().focus().toggleCodeBlock().run(),
|
|
4895
|
-
},
|
|
4896
|
-
{
|
|
4897
|
-
title: slashCommands.image.title,
|
|
4898
|
-
description: slashCommands.image.description,
|
|
4899
|
-
icon: "image",
|
|
4900
|
-
keywords: slashCommands.image.keywords,
|
|
4901
|
-
command: (editor) => {
|
|
4902
|
-
// Créer un input file temporaire pour sélectionner une image
|
|
4903
|
-
const input = document.createElement("input");
|
|
4904
|
-
input.type = "file";
|
|
4905
|
-
input.accept = "image/*";
|
|
4906
|
-
input.style.display = "none";
|
|
4907
|
-
input.addEventListener("change", async (e) => {
|
|
4908
|
-
const file = e.target.files?.[0];
|
|
4909
|
-
if (file && file.type.startsWith("image/")) {
|
|
4910
|
-
try {
|
|
4911
|
-
// Utiliser la méthode de compression unifiée
|
|
4912
|
-
const canvas = document.createElement("canvas");
|
|
4913
|
-
const ctx = canvas.getContext("2d");
|
|
4914
|
-
const img = new Image();
|
|
4915
|
-
img.onload = () => {
|
|
4916
|
-
// Vérifier les dimensions (max 1920x1080)
|
|
4917
|
-
const maxWidth = 1920;
|
|
4918
|
-
const maxHeight = 1080;
|
|
4919
|
-
let { width, height } = img;
|
|
4920
|
-
// Redimensionner si nécessaire
|
|
4921
|
-
if (width > maxWidth || height > maxHeight) {
|
|
4922
|
-
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
|
4923
|
-
width *= ratio;
|
|
4924
|
-
height *= ratio;
|
|
4925
|
-
}
|
|
4926
|
-
canvas.width = width;
|
|
4927
|
-
canvas.height = height;
|
|
4928
|
-
// Dessiner l'image redimensionnée
|
|
4929
|
-
ctx?.drawImage(img, 0, 0, width, height);
|
|
4930
|
-
// Convertir en base64 avec compression
|
|
4931
|
-
canvas.toBlob((blob) => {
|
|
4932
|
-
if (blob) {
|
|
4933
|
-
const reader = new FileReader();
|
|
4934
|
-
reader.onload = (e) => {
|
|
4935
|
-
const base64 = e.target?.result;
|
|
4936
|
-
if (base64) {
|
|
4937
|
-
// Utiliser setResizableImage avec toutes les propriétés
|
|
4938
|
-
editor
|
|
4939
|
-
.chain()
|
|
4940
|
-
.focus()
|
|
4941
|
-
.setResizableImage({
|
|
4942
|
-
src: base64,
|
|
4943
|
-
alt: file.name,
|
|
4944
|
-
title: `${file.name} (${Math.round(width)}×${Math.round(height)})`,
|
|
4945
|
-
width: Math.round(width),
|
|
4946
|
-
height: Math.round(height),
|
|
4947
|
-
})
|
|
4948
|
-
.run();
|
|
4949
|
-
}
|
|
4950
|
-
};
|
|
4951
|
-
reader.readAsDataURL(blob);
|
|
4952
|
-
}
|
|
4953
|
-
}, file.type, 0.8 // qualité de compression
|
|
4954
|
-
);
|
|
4955
|
-
};
|
|
4956
|
-
img.onerror = () => {
|
|
4957
|
-
console.error(i18nService.editor().imageLoadError);
|
|
4958
|
-
};
|
|
4959
|
-
img.src = URL.createObjectURL(file);
|
|
4960
|
-
}
|
|
4961
|
-
catch (error) {
|
|
4962
|
-
console.error("Error uploading image:", error);
|
|
4963
|
-
}
|
|
4964
|
-
}
|
|
4965
|
-
document.body.removeChild(input);
|
|
4966
|
-
});
|
|
4967
|
-
document.body.appendChild(input);
|
|
4968
|
-
input.click();
|
|
4969
|
-
},
|
|
4970
|
-
},
|
|
4971
|
-
{
|
|
4972
|
-
title: slashCommands.horizontalRule.title,
|
|
4973
|
-
description: slashCommands.horizontalRule.description,
|
|
4974
|
-
icon: "horizontal_rule",
|
|
4975
|
-
keywords: slashCommands.horizontalRule.keywords,
|
|
4976
|
-
command: (editor) => editor.chain().focus().setHorizontalRule().run(),
|
|
4977
|
-
},
|
|
4978
|
-
{
|
|
4979
|
-
title: slashCommands.table.title,
|
|
4980
|
-
description: slashCommands.table.description,
|
|
4981
|
-
icon: "table_view",
|
|
4982
|
-
keywords: slashCommands.table.keywords,
|
|
4983
|
-
command: (editor) => editor.chain().focus().insertTable({ rows: 3, cols: 3 }).run(),
|
|
4984
|
-
},
|
|
4985
|
-
];
|
|
4986
|
-
}
|
|
4987
|
-
/**
|
|
4988
|
-
* Fonction utilitaire pour filtrer les slash commands selon les commandes actives
|
|
4989
|
-
*/
|
|
4990
|
-
function filterSlashCommands(activeCommands, i18nService) {
|
|
4991
|
-
const allCommands = createI18nSlashCommands(i18nService);
|
|
4992
|
-
return allCommands.filter((command, index) => {
|
|
4993
|
-
const commandKey = SLASH_COMMAND_KEYS[index];
|
|
4994
|
-
return commandKey && activeCommands.has(commandKey);
|
|
4995
|
-
});
|
|
4996
|
-
}
|
|
4997
|
-
|
|
4998
4489
|
// Configuration par défaut de la toolbar
|
|
4999
4490
|
const DEFAULT_TOOLBAR_CONFIG = {
|
|
5000
4491
|
bold: true,
|
|
@@ -5066,9 +4557,7 @@ const DEFAULT_CELL_MENU_CONFIG = {
|
|
|
5066
4557
|
mergeCells: true,
|
|
5067
4558
|
splitCell: true,
|
|
5068
4559
|
};
|
|
5069
|
-
|
|
5070
|
-
commands: [], // Sera rempli par filterSlashCommands
|
|
5071
|
-
};
|
|
4560
|
+
// La configuration des slash commands est gérée dynamiquement via slashCommandsConfigComputed
|
|
5072
4561
|
class AngularTiptapEditorComponent {
|
|
5073
4562
|
constructor() {
|
|
5074
4563
|
this.content = input("");
|
|
@@ -5083,7 +4572,8 @@ class AngularTiptapEditorComponent {
|
|
|
5083
4572
|
this.maxCharacters = input(undefined);
|
|
5084
4573
|
this.enableOfficePaste = input(true);
|
|
5085
4574
|
this.enableSlashCommands = input(true);
|
|
5086
|
-
this.
|
|
4575
|
+
this.slashCommands = input({});
|
|
4576
|
+
this.customSlashCommands = input(undefined);
|
|
5087
4577
|
this.locale = input(undefined);
|
|
5088
4578
|
this.autofocus = input(false);
|
|
5089
4579
|
this.tiptapExtensions = input([]);
|
|
@@ -5183,13 +4673,15 @@ class AngularTiptapEditorComponent {
|
|
|
5183
4673
|
}));
|
|
5184
4674
|
// Computed pour la configuration des slash commands
|
|
5185
4675
|
this.slashCommandsConfigComputed = computed(() => {
|
|
5186
|
-
const
|
|
5187
|
-
if (
|
|
5188
|
-
return
|
|
4676
|
+
const customConfig = this.customSlashCommands();
|
|
4677
|
+
if (customConfig) {
|
|
4678
|
+
return customConfig;
|
|
5189
4679
|
}
|
|
5190
|
-
//
|
|
5191
|
-
|
|
5192
|
-
return {
|
|
4680
|
+
// Utilise l'utilitaire filterSlashCommands qui gère maintenant
|
|
4681
|
+
// les défauts, le filtrage et l'ajout de commandes personnalisées
|
|
4682
|
+
return {
|
|
4683
|
+
commands: filterSlashCommands(this.slashCommands(), this.i18nService, this.editorCommandsService, this.imageService, this.imageUploadConfig()),
|
|
4684
|
+
};
|
|
5193
4685
|
});
|
|
5194
4686
|
this._destroyRef = inject(DestroyRef);
|
|
5195
4687
|
// NgControl pour gérer les FormControls
|
|
@@ -5386,22 +4878,6 @@ class AngularTiptapEditorComponent {
|
|
|
5386
4878
|
this._wordCount.set(storage.words());
|
|
5387
4879
|
}
|
|
5388
4880
|
}
|
|
5389
|
-
// Méthodes pour l'upload d'images
|
|
5390
|
-
onImageUploaded(result) {
|
|
5391
|
-
const currentEditor = this.editor();
|
|
5392
|
-
if (currentEditor) {
|
|
5393
|
-
this.imageService.insertImage(currentEditor, {
|
|
5394
|
-
src: result.src,
|
|
5395
|
-
alt: result.name,
|
|
5396
|
-
title: `${result.name} (${result.width}×${result.height})`,
|
|
5397
|
-
width: result.width,
|
|
5398
|
-
height: result.height,
|
|
5399
|
-
});
|
|
5400
|
-
}
|
|
5401
|
-
}
|
|
5402
|
-
onImageUploadError(error) {
|
|
5403
|
-
// Ici vous pourriez afficher une notification à l'utilisateur
|
|
5404
|
-
}
|
|
5405
4881
|
// Gestion de l'upload d'image depuis les slash commands
|
|
5406
4882
|
async onSlashCommandImageUpload(file) {
|
|
5407
4883
|
const currentEditor = this.editor();
|
|
@@ -5435,7 +4911,12 @@ class AngularTiptapEditorComponent {
|
|
|
5435
4911
|
const currentEditor = this.editor();
|
|
5436
4912
|
if (currentEditor) {
|
|
5437
4913
|
try {
|
|
5438
|
-
|
|
4914
|
+
const config = this.imageUploadConfig();
|
|
4915
|
+
await this.imageService.uploadAndInsertImage(currentEditor, file, {
|
|
4916
|
+
quality: config.quality,
|
|
4917
|
+
maxWidth: config.maxWidth,
|
|
4918
|
+
maxHeight: config.maxHeight
|
|
4919
|
+
});
|
|
5439
4920
|
}
|
|
5440
4921
|
catch (error) {
|
|
5441
4922
|
// Gérer l'erreur silencieusement ou afficher une notification
|
|
@@ -5520,19 +5001,15 @@ class AngularTiptapEditorComponent {
|
|
|
5520
5001
|
}
|
|
5521
5002
|
}
|
|
5522
5003
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: AngularTiptapEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5523
|
-
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 }, fillContainer: { classPropertyName: "fillContainer", publicName: "fillContainer", 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 },
|
|
5004
|
+
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 }, fillContainer: { classPropertyName: "fillContainer", publicName: "fillContainer", 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 }, slashCommands: { classPropertyName: "slashCommands", publicName: "slashCommands", isSignal: true, isRequired: false, transformFunction: null }, customSlashCommands: { classPropertyName: "customSlashCommands", publicName: "customSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, tiptapExtensions: { classPropertyName: "tiptapExtensions", publicName: "tiptapExtensions", isSignal: true, isRequired: false, transformFunction: null }, tiptapOptions: { classPropertyName: "tiptapOptions", publicName: "tiptapOptions", 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 }, imageUploadHandler: { classPropertyName: "imageUploadHandler", publicName: "imageUploadHandler", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange", editorCreated: "editorCreated", editorUpdate: "editorUpdate", editorFocus: "editorFocus", editorBlur: "editorBlur" }, host: { properties: { "class.fill-container": "fillContainer()" } }, viewQueries: [{ propertyName: "editorElement", first: true, predicate: ["editorElement"], descendants: true, isSignal: true }], hostDirectives: [{ directive: NoopValueAccessorDirective }], ngImport: i0, template: `
|
|
5524
5005
|
<div class="tiptap-editor" [class.fill-container]="fillContainer()">
|
|
5525
5006
|
<!-- Toolbar -->
|
|
5526
5007
|
@if (showToolbar() && editor()) {
|
|
5527
|
-
<tiptap-toolbar
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
(error)="onImageUploadError($event)"
|
|
5533
|
-
/>
|
|
5534
|
-
</div>
|
|
5535
|
-
</tiptap-toolbar>
|
|
5008
|
+
<tiptap-toolbar
|
|
5009
|
+
[editor]="editor()!"
|
|
5010
|
+
[config]="toolbarConfig()"
|
|
5011
|
+
[imageUpload]="imageUploadConfig()"
|
|
5012
|
+
/>
|
|
5536
5013
|
}
|
|
5537
5014
|
|
|
5538
5015
|
<!-- Contenu de l'éditeur -->
|
|
@@ -5591,8 +5068,6 @@ class AngularTiptapEditorComponent {
|
|
|
5591
5068
|
></tiptap-cell-bubble-menu>
|
|
5592
5069
|
}
|
|
5593
5070
|
|
|
5594
|
-
<!-- Table Edit Button - Supprimé car remplacé par le menu bubble -->
|
|
5595
|
-
|
|
5596
5071
|
<!-- Compteur de caractères -->
|
|
5597
5072
|
@if (showCharacterCount()) {
|
|
5598
5073
|
<div class="character-count">
|
|
@@ -5606,7 +5081,7 @@ class AngularTiptapEditorComponent {
|
|
|
5606
5081
|
</div>
|
|
5607
5082
|
}
|
|
5608
5083
|
</div>
|
|
5609
|
-
`, isInline: true, styles: [":host(.fill-container){display:block;height:100%}.tiptap-editor{border:2px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;transition:border-color .2s ease}.tiptap-editor.fill-container{display:flex;flex-direction:column;height:100%}.tiptap-editor.fill-container .tiptap-content{flex:1;min-height:0;overflow-y:auto}.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"] }] }); }
|
|
5084
|
+
`, isInline: true, styles: [":host{--ate-primary: #2563eb;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 90%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 95%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-surface: #ffffff;--ate-surface-secondary: #f8f9fa;--ate-surface-tertiary: #f1f5f9;--ate-text: #2d3748;--ate-text-secondary: #64748b;--ate-text-muted: #a0aec0;--ate-border: #e2e8f0;--ate-highlight-bg: #fef08a;--ate-highlight-color: #854d0e;--ate-button-hover: #f1f5f9;--ate-button-active: #e2e8f0;--ate-menu-bg: rgba(255, 255, 255, .98);--ate-menu-border: var(--ate-border);--ate-menu-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--ate-menu-blur: 16px;--ate-error-color: #c53030;--ate-error-bg: #fed7d7;--ate-error-border: #feb2b2;--ate-border-color: var(--ate-border);--ate-border-width: 2px;--ate-border-radius: 8px;--ate-focus-color: var(--ate-primary);--ate-background: var(--ate-surface);--ate-text-color: var(--ate-text);--ate-placeholder-color: var(--ate-text-muted);--ate-line-height: 1.6;--ate-content-padding: 16px;--ate-toolbar-background: var(--ate-surface-secondary);--ate-toolbar-border-color: var(--ate-border);--ate-toolbar-button-color: var(--ate-text-secondary);--ate-toolbar-button-hover-background: transparent;--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-counter-color: var(--ate-text-secondary);--ate-counter-background: var(--ate-surface-secondary);--ate-counter-border-color: var(--ate-border);--ate-drag-background: #f0f8ff;--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-border);--ate-blockquote-background: var(--ate-surface-secondary);--ate-code-background: var(--ate-surface-secondary);--ate-code-color: var(--ate-text);--ate-code-block-background: #181825;--ate-code-block-color: #e2e8f0;--ate-code-border-color: var(--ate-border);--ate-code-block-border-color: var(--ate-border);--ate-image-border-radius: 8px;--ate-image-selected-color: var(--ate-primary);--ate-scrollbar-width: 10px;--ate-scrollbar-thumb: var(--ate-border);--ate-scrollbar-thumb-hover: var(--ate-text-muted);--ate-scrollbar-track: transparent;--ate-table-border-color: var(--ate-border);--ate-table-header-background: var(--ate-surface-secondary);--ate-table-header-color: var(--ate-text);--ate-table-cell-background: var(--ate-surface);--ate-table-cell-selected-background: var(--ate-primary-light);--ate-table-resize-handle-color: var(--ate-primary);--ate-table-row-hover-background: var(--ate-primary-lighter)}:host(.dark),:host([data-theme=\"dark\"]){--ate-primary: #3b82f6;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 92%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 80%);--ate-surface: #020617;--ate-surface-secondary: #0f172a;--ate-surface-tertiary: #1e293b;--ate-text: #f8fafc;--ate-text-secondary: #94a3b8;--ate-text-muted: #64748b;--ate-border: #1e293b;--ate-highlight-bg: #854d0e;--ate-highlight-color: #fef08a;--ate-button-hover: #1e293b;--ate-button-active: #0f172a;--ate-menu-bg: rgba(15, 23, 42, .95);--ate-menu-border: rgba(255, 255, 255, .1);--ate-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .3), 0 10px 10px -5px rgba(0, 0, 0, .2);--ate-menu-blur: 16px;--ate-error-color: #f87171;--ate-error-bg: #450a0a;--ate-error-border: #7f1d1d;--ate-drag-background: var(--ate-surface-tertiary);--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-primary);--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-button-hover: var(--ate-surface-tertiary);--ate-button-active: var(--ate-surface-secondary);--ate-scrollbar-thumb: var(--ate-surface-tertiary);--ate-scrollbar-thumb-hover: var(--ate-text-muted)}:host(.fill-container){display:block;height:100%}.tiptap-editor{border:var(--ate-border-width) solid var(--ate-border-color);border-radius:var(--ate-border-radius);background:var(--ate-background);overflow:hidden;transition:border-color .2s ease}.tiptap-editor.fill-container{display:flex;flex-direction:column;height:100%}.tiptap-editor.fill-container .tiptap-content{flex:1;min-height:0;overflow-y:auto}.tiptap-editor:focus-within{border-color:var(--ate-focus-color)}.tiptap-content{padding:var(--ate-content-padding);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;scrollbar-width:thin;scrollbar-color:var(--ate-scrollbar-thumb) var(--ate-scrollbar-track)}.tiptap-content::-webkit-scrollbar{width:var(--ate-scrollbar-width);height:var(--ate-scrollbar-width)}.tiptap-content::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.tiptap-content::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.tiptap-content::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}.tiptap-content.drag-over{background:var(--ate-drag-background);border:2px dashed var(--ate-drag-border-color)}.character-count{padding:8px var(--ate-content-padding);font-size:12px;color:var(--ate-counter-color);text-align:right;border-top:1px solid var(--ate-counter-border-color);background:var(--ate-counter-background)}:host ::ng-deep .ProseMirror{outline:none;line-height:var(--ate-line-height);color:var(--ate-text-color);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 var(--ate-blockquote-border-color);margin:1em 0;font-style:italic;background:var(--ate-blockquote-background);padding:.5em 1em;border-radius:0 4px 4px 0}:host ::ng-deep .ProseMirror code{background:var(--ate-code-background);color:var(--ate-code-color);border:1px solid var(--ate-code-border-color);padding:.2em .4em;border-radius:3px;font-family:Monaco,Consolas,monospace;font-size:.9em}:host ::ng-deep .ProseMirror pre{background:var(--ate-code-block-background);color:var(--ate-code-block-color);border:1px solid var(--ate-code-block-border-color);padding:1em;border-radius:6px;overflow-x:auto;margin:1em 0}:host ::ng-deep .ProseMirror pre code{background:none;color:inherit;border:none;padding:0}:host ::ng-deep .ProseMirror p.is-editor-empty:first-child:before{content:attr(data-placeholder);color:var(--ate-placeholder-color);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:var(--ate-image-border-radius)}:host ::ng-deep .ProseMirror img:hover{border-color:var(--ate-border-color);box-shadow:0 2px 4px #0000001a}:host ::ng-deep .ProseMirror img.ProseMirror-selectednode{border-color:var(--ate-image-selected-color);box-shadow:0 0 0 3px var(--ate-primary-light-alpha);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 var(--ate-primary);outline-offset:2px;border-radius:16px;box-shadow:0 0 0 4px var(--ate-primary-light-alpha)}: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:var(--ate-primary);border:2px solid var(--ate-surface);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:var(--ate-primary);box-shadow:0 3px 8px #0000004d}:host ::ng-deep .resize-handle:active{background:var(--ate-primary)}: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 var(--ate-table-border-color);border-bottom:1px solid var(--ate-table-border-color);box-sizing:border-box;min-width:1em;padding:8px 12px;position:relative;vertical-align:top;text-align:left}:host ::ng-deep .ProseMirror table td{background:var(--ate-table-cell-background)}:host ::ng-deep .ProseMirror table td:first-child,:host ::ng-deep .ProseMirror table th:first-child{border-left:1px solid var(--ate-table-border-color)}:host ::ng-deep .ProseMirror table tr:first-child td,:host ::ng-deep .ProseMirror table tr:first-child th{border-top:1px solid var(--ate-table-border-color)}: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:var(--ate-table-header-background);font-weight:600;color:var(--ate-table-header-color)}:host ::ng-deep .ProseMirror table .selectedCell:after{background:var(--ate-table-cell-selected-background);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:var(--ate-table-resize-handle-color);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:var(--ate-focus-color)}: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 tbody tr:hover td{background-color:var(--ate-table-row-hover-background)}\n"], dependencies: [{ kind: "component", type: TiptapToolbarComponent, selector: "tiptap-toolbar", inputs: ["editor", "config", "imageUpload"], outputs: ["imageUploaded", "imageError"] }, { 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"] }] }); }
|
|
5610
5085
|
}
|
|
5611
5086
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: AngularTiptapEditorComponent, decorators: [{
|
|
5612
5087
|
type: Component,
|
|
@@ -5614,7 +5089,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
5614
5089
|
'[class.fill-container]': 'fillContainer()',
|
|
5615
5090
|
}, imports: [
|
|
5616
5091
|
TiptapToolbarComponent,
|
|
5617
|
-
TiptapImageUploadComponent,
|
|
5618
5092
|
TiptapBubbleMenuComponent,
|
|
5619
5093
|
TiptapImageBubbleMenuComponent,
|
|
5620
5094
|
TiptapTableBubbleMenuComponent,
|
|
@@ -5624,15 +5098,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
5624
5098
|
<div class="tiptap-editor" [class.fill-container]="fillContainer()">
|
|
5625
5099
|
<!-- Toolbar -->
|
|
5626
5100
|
@if (showToolbar() && editor()) {
|
|
5627
|
-
<tiptap-toolbar
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
(error)="onImageUploadError($event)"
|
|
5633
|
-
/>
|
|
5634
|
-
</div>
|
|
5635
|
-
</tiptap-toolbar>
|
|
5101
|
+
<tiptap-toolbar
|
|
5102
|
+
[editor]="editor()!"
|
|
5103
|
+
[config]="toolbarConfig()"
|
|
5104
|
+
[imageUpload]="imageUploadConfig()"
|
|
5105
|
+
/>
|
|
5636
5106
|
}
|
|
5637
5107
|
|
|
5638
5108
|
<!-- Contenu de l'éditeur -->
|
|
@@ -5691,8 +5161,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
5691
5161
|
></tiptap-cell-bubble-menu>
|
|
5692
5162
|
}
|
|
5693
5163
|
|
|
5694
|
-
<!-- Table Edit Button - Supprimé car remplacé par le menu bubble -->
|
|
5695
|
-
|
|
5696
5164
|
<!-- Compteur de caractères -->
|
|
5697
5165
|
@if (showCharacterCount()) {
|
|
5698
5166
|
<div class="character-count">
|
|
@@ -5706,7 +5174,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
5706
5174
|
</div>
|
|
5707
5175
|
}
|
|
5708
5176
|
</div>
|
|
5709
|
-
`, styles: [":host(.fill-container){display:block;height:100%}.tiptap-editor{border:2px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;transition:border-color .2s ease}.tiptap-editor.fill-container{display:flex;flex-direction:column;height:100%}.tiptap-editor.fill-container .tiptap-content{flex:1;min-height:0;overflow-y:auto}.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"] }]
|
|
5177
|
+
`, styles: [":host{--ate-primary: #2563eb;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 90%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 95%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-surface: #ffffff;--ate-surface-secondary: #f8f9fa;--ate-surface-tertiary: #f1f5f9;--ate-text: #2d3748;--ate-text-secondary: #64748b;--ate-text-muted: #a0aec0;--ate-border: #e2e8f0;--ate-highlight-bg: #fef08a;--ate-highlight-color: #854d0e;--ate-button-hover: #f1f5f9;--ate-button-active: #e2e8f0;--ate-menu-bg: rgba(255, 255, 255, .98);--ate-menu-border: var(--ate-border);--ate-menu-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--ate-menu-blur: 16px;--ate-error-color: #c53030;--ate-error-bg: #fed7d7;--ate-error-border: #feb2b2;--ate-border-color: var(--ate-border);--ate-border-width: 2px;--ate-border-radius: 8px;--ate-focus-color: var(--ate-primary);--ate-background: var(--ate-surface);--ate-text-color: var(--ate-text);--ate-placeholder-color: var(--ate-text-muted);--ate-line-height: 1.6;--ate-content-padding: 16px;--ate-toolbar-background: var(--ate-surface-secondary);--ate-toolbar-border-color: var(--ate-border);--ate-toolbar-button-color: var(--ate-text-secondary);--ate-toolbar-button-hover-background: transparent;--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-counter-color: var(--ate-text-secondary);--ate-counter-background: var(--ate-surface-secondary);--ate-counter-border-color: var(--ate-border);--ate-drag-background: #f0f8ff;--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-border);--ate-blockquote-background: var(--ate-surface-secondary);--ate-code-background: var(--ate-surface-secondary);--ate-code-color: var(--ate-text);--ate-code-block-background: #181825;--ate-code-block-color: #e2e8f0;--ate-code-border-color: var(--ate-border);--ate-code-block-border-color: var(--ate-border);--ate-image-border-radius: 8px;--ate-image-selected-color: var(--ate-primary);--ate-scrollbar-width: 10px;--ate-scrollbar-thumb: var(--ate-border);--ate-scrollbar-thumb-hover: var(--ate-text-muted);--ate-scrollbar-track: transparent;--ate-table-border-color: var(--ate-border);--ate-table-header-background: var(--ate-surface-secondary);--ate-table-header-color: var(--ate-text);--ate-table-cell-background: var(--ate-surface);--ate-table-cell-selected-background: var(--ate-primary-light);--ate-table-resize-handle-color: var(--ate-primary);--ate-table-row-hover-background: var(--ate-primary-lighter)}:host(.dark),:host([data-theme=\"dark\"]){--ate-primary: #3b82f6;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 92%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 80%);--ate-surface: #020617;--ate-surface-secondary: #0f172a;--ate-surface-tertiary: #1e293b;--ate-text: #f8fafc;--ate-text-secondary: #94a3b8;--ate-text-muted: #64748b;--ate-border: #1e293b;--ate-highlight-bg: #854d0e;--ate-highlight-color: #fef08a;--ate-button-hover: #1e293b;--ate-button-active: #0f172a;--ate-menu-bg: rgba(15, 23, 42, .95);--ate-menu-border: rgba(255, 255, 255, .1);--ate-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .3), 0 10px 10px -5px rgba(0, 0, 0, .2);--ate-menu-blur: 16px;--ate-error-color: #f87171;--ate-error-bg: #450a0a;--ate-error-border: #7f1d1d;--ate-drag-background: var(--ate-surface-tertiary);--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-primary);--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-button-hover: var(--ate-surface-tertiary);--ate-button-active: var(--ate-surface-secondary);--ate-scrollbar-thumb: var(--ate-surface-tertiary);--ate-scrollbar-thumb-hover: var(--ate-text-muted)}:host(.fill-container){display:block;height:100%}.tiptap-editor{border:var(--ate-border-width) solid var(--ate-border-color);border-radius:var(--ate-border-radius);background:var(--ate-background);overflow:hidden;transition:border-color .2s ease}.tiptap-editor.fill-container{display:flex;flex-direction:column;height:100%}.tiptap-editor.fill-container .tiptap-content{flex:1;min-height:0;overflow-y:auto}.tiptap-editor:focus-within{border-color:var(--ate-focus-color)}.tiptap-content{padding:var(--ate-content-padding);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;scrollbar-width:thin;scrollbar-color:var(--ate-scrollbar-thumb) var(--ate-scrollbar-track)}.tiptap-content::-webkit-scrollbar{width:var(--ate-scrollbar-width);height:var(--ate-scrollbar-width)}.tiptap-content::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.tiptap-content::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.tiptap-content::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}.tiptap-content.drag-over{background:var(--ate-drag-background);border:2px dashed var(--ate-drag-border-color)}.character-count{padding:8px var(--ate-content-padding);font-size:12px;color:var(--ate-counter-color);text-align:right;border-top:1px solid var(--ate-counter-border-color);background:var(--ate-counter-background)}:host ::ng-deep .ProseMirror{outline:none;line-height:var(--ate-line-height);color:var(--ate-text-color);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 var(--ate-blockquote-border-color);margin:1em 0;font-style:italic;background:var(--ate-blockquote-background);padding:.5em 1em;border-radius:0 4px 4px 0}:host ::ng-deep .ProseMirror code{background:var(--ate-code-background);color:var(--ate-code-color);border:1px solid var(--ate-code-border-color);padding:.2em .4em;border-radius:3px;font-family:Monaco,Consolas,monospace;font-size:.9em}:host ::ng-deep .ProseMirror pre{background:var(--ate-code-block-background);color:var(--ate-code-block-color);border:1px solid var(--ate-code-block-border-color);padding:1em;border-radius:6px;overflow-x:auto;margin:1em 0}:host ::ng-deep .ProseMirror pre code{background:none;color:inherit;border:none;padding:0}:host ::ng-deep .ProseMirror p.is-editor-empty:first-child:before{content:attr(data-placeholder);color:var(--ate-placeholder-color);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:var(--ate-image-border-radius)}:host ::ng-deep .ProseMirror img:hover{border-color:var(--ate-border-color);box-shadow:0 2px 4px #0000001a}:host ::ng-deep .ProseMirror img.ProseMirror-selectednode{border-color:var(--ate-image-selected-color);box-shadow:0 0 0 3px var(--ate-primary-light-alpha);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 var(--ate-primary);outline-offset:2px;border-radius:16px;box-shadow:0 0 0 4px var(--ate-primary-light-alpha)}: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:var(--ate-primary);border:2px solid var(--ate-surface);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:var(--ate-primary);box-shadow:0 3px 8px #0000004d}:host ::ng-deep .resize-handle:active{background:var(--ate-primary)}: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 var(--ate-table-border-color);border-bottom:1px solid var(--ate-table-border-color);box-sizing:border-box;min-width:1em;padding:8px 12px;position:relative;vertical-align:top;text-align:left}:host ::ng-deep .ProseMirror table td{background:var(--ate-table-cell-background)}:host ::ng-deep .ProseMirror table td:first-child,:host ::ng-deep .ProseMirror table th:first-child{border-left:1px solid var(--ate-table-border-color)}:host ::ng-deep .ProseMirror table tr:first-child td,:host ::ng-deep .ProseMirror table tr:first-child th{border-top:1px solid var(--ate-table-border-color)}: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:var(--ate-table-header-background);font-weight:600;color:var(--ate-table-header-color)}:host ::ng-deep .ProseMirror table .selectedCell:after{background:var(--ate-table-cell-selected-background);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:var(--ate-table-resize-handle-color);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:var(--ate-focus-color)}: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 tbody tr:hover td{background-color:var(--ate-table-row-hover-background)}\n"] }]
|
|
5710
5178
|
}], ctorParameters: () => [] });
|
|
5711
5179
|
|
|
5712
5180
|
/*
|
|
@@ -5718,5 +5186,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
|
|
|
5718
5186
|
* Generated bundle index. Do not edit.
|
|
5719
5187
|
*/
|
|
5720
5188
|
|
|
5721
|
-
export { AngularTiptapEditorComponent, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG,
|
|
5189
|
+
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 };
|
|
5722
5190
|
//# sourceMappingURL=flogeez-angular-tiptap-editor.mjs.map
|