@flogeez/angular-tiptap-editor 0.6.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { input, output, ChangeDetectionStrategy, Component, signal, computed, Injectable, inject, effect, ViewChild, Directive, viewChild, DestroyRef, untracked } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
- import { Node as Node$1, nodeInputRule, mergeAttributes, Extension, Editor } from '@tiptap/core';
4
+ import { Node as Node$1, nodeInputRule, mergeAttributes, Extension, getAttributes, Editor } from '@tiptap/core';
5
5
  import StarterKit from '@tiptap/starter-kit';
6
6
  import Placeholder from '@tiptap/extension-placeholder';
7
7
  import CharacterCount from '@tiptap/extension-character-count';
@@ -144,11 +144,11 @@ const ResizableImage = Node$1.create({
144
144
  img.height = node.attrs["height"];
145
145
  img.parentNode?.insertBefore(container, img);
146
146
  container.appendChild(img);
147
- // Ajouter les contrôles de redimensionnement modernes
147
+ // Add modern resize controls
148
148
  const resizeControls = document.createElement("div");
149
149
  resizeControls.className = "resize-controls";
150
150
  resizeControls.style.display = "none";
151
- // Créer les 8 poignées pour un redimensionnement complet
151
+ // Create 8 handles for full resizing capability
152
152
  const handles = ["nw", "n", "ne", "w", "e", "sw", "s", "se"];
153
153
  handles.forEach((direction) => {
154
154
  const handle = document.createElement("div");
@@ -156,27 +156,27 @@ const ResizableImage = Node$1.create({
156
156
  handle.setAttribute("data-direction", direction);
157
157
  resizeControls.appendChild(handle);
158
158
  });
159
- // Attacher les contrôles au conteneur
159
+ // Attach controls to container
160
160
  container.appendChild(resizeControls);
161
- // Variables pour le redimensionnement
161
+ // Variables for resizing
162
162
  let isResizing = false;
163
163
  let startX = 0;
164
164
  let startY = 0;
165
165
  let startWidth = 0;
166
166
  let startHeight = 0;
167
167
  let aspectRatio = 1;
168
- // Calculer le ratio d'aspect
168
+ // Calculate aspect ratio
169
169
  img.onload = () => {
170
170
  aspectRatio = img.naturalWidth / img.naturalHeight;
171
171
  };
172
- // Gestion du redimensionnement
172
+ // Resizing logic
173
173
  const handleMouseDown = (e, direction) => {
174
174
  e.preventDefault();
175
175
  e.stopPropagation();
176
176
  isResizing = true;
177
177
  startX = e.clientX;
178
178
  startY = e.clientY;
179
- // Utiliser les dimensions actuelles de l'image au lieu des dimensions initiales
179
+ // Use current image dimensions instead of initial ones
180
180
  startWidth =
181
181
  parseInt(img.getAttribute("width") || "0") ||
182
182
  node.attrs["width"] ||
@@ -185,7 +185,7 @@ const ResizableImage = Node$1.create({
185
185
  parseInt(img.getAttribute("height") || "0") ||
186
186
  node.attrs["height"] ||
187
187
  img.naturalHeight;
188
- // Ajouter la classe de redimensionnement au body
188
+ // Add resizing class to body
189
189
  document.body.classList.add("resizing");
190
190
  const handleMouseMove = (e) => {
191
191
  if (!isResizing)
@@ -194,7 +194,7 @@ const ResizableImage = Node$1.create({
194
194
  const deltaY = e.clientY - startY;
195
195
  let newWidth = startWidth;
196
196
  let newHeight = startHeight;
197
- // Redimensionnement selon la direction
197
+ // Resize according to direction
198
198
  switch (direction) {
199
199
  case "e":
200
200
  newWidth = startWidth + deltaX;
@@ -229,17 +229,17 @@ const ResizableImage = Node$1.create({
229
229
  newHeight = startHeight - deltaY;
230
230
  break;
231
231
  }
232
- // Limites
232
+ // Limits
233
233
  newWidth = Math.max(50, Math.min(2000, newWidth));
234
234
  newHeight = Math.max(50, Math.min(2000, newHeight));
235
- // Mettre à jour directement les attributs de l'image
235
+ // Update image attributes directly
236
236
  img.setAttribute("width", Math.round(newWidth).toString());
237
237
  img.setAttribute("height", Math.round(newHeight).toString());
238
238
  };
239
239
  const handleMouseUp = () => {
240
240
  isResizing = false;
241
241
  document.body.classList.remove("resizing");
242
- // Mettre à jour le nœud Tiptap avec les nouvelles dimensions
242
+ // Update Tiptap node with new dimensions
243
243
  if (typeof getPos === "function") {
244
244
  const finalWidth = parseInt(img.getAttribute("width") || "0");
245
245
  const finalHeight = parseInt(img.getAttribute("height") || "0");
@@ -256,7 +256,7 @@ const ResizableImage = Node$1.create({
256
256
  document.addEventListener("mousemove", handleMouseMove);
257
257
  document.addEventListener("mouseup", handleMouseUp);
258
258
  };
259
- // Ajouter les événements aux poignées
259
+ // Add events to handles
260
260
  resizeControls.addEventListener("mousedown", (e) => {
261
261
  const target = e.target;
262
262
  if (target.classList.contains("resize-handle")) {
@@ -541,6 +541,7 @@ const INITIAL_EDITOR_STATE = {
541
541
  computedColor: null,
542
542
  background: null,
543
543
  computedBackground: null,
544
+ linkOpenOnClick: false,
544
545
  },
545
546
  can: {
546
547
  toggleBold: false,
@@ -573,6 +574,7 @@ const INITIAL_EDITOR_STATE = {
573
574
  toggleBulletList: false,
574
575
  toggleOrderedList: false,
575
576
  toggleBlockquote: false,
577
+ toggleCodeBlock: false,
576
578
  setTextAlignLeft: false,
577
579
  setTextAlignCenter: false,
578
580
  setTextAlignRight: false,
@@ -605,22 +607,22 @@ const INITIAL_EDITOR_STATE = {
605
607
  };
606
608
 
607
609
  /**
608
- * Mergeur de propriétés à plat, ultra-performant.
609
- * Traite les sous-objets (marks, can, nodes) propriété par propriété.
610
+ * High-performance flat property merger.
611
+ * Processes sub-objects (marks, can, nodes) property by property.
610
612
  */
611
613
  function fastMerge(target, source) {
612
614
  if (!source)
613
615
  return;
614
616
  for (const key in source) {
615
617
  const sourceVal = source[key];
616
- // Si la valeur est un objet (marks, can, nodes, selection)
618
+ // If the value is an object (marks, can, nodes, selection)
617
619
  if (sourceVal !== null && typeof sourceVal === 'object' && !Array.isArray(sourceVal)) {
618
620
  if (!target[key])
619
621
  target[key] = {};
620
- // Fusionner les propriétés internes
622
+ // Merge internal properties
621
623
  for (const subKey in sourceVal) {
622
624
  const subVal = sourceVal[subKey];
623
- // Règle de priorité TRUE pour les booléens de catégories d'état
625
+ // TRUE priority rule for boolean state categories
624
626
  if (typeof subVal === 'boolean' && (key === 'marks' || key === 'can' || key === 'nodes')) {
625
627
  target[key][subKey] = target[key][subKey] || subVal;
626
628
  }
@@ -630,7 +632,7 @@ function fastMerge(target, source) {
630
632
  }
631
633
  }
632
634
  else {
633
- // Valeur simple (isFocused, isEditable)
635
+ // Simple value (isFocused, isEditable)
634
636
  target[key] = sourceVal;
635
637
  }
636
638
  }
@@ -718,6 +720,7 @@ class TiptapButtonComponent {
718
720
  [style.color]="color()"
719
721
  [style.background-color]="backgroundColor()"
720
722
  [attr.title]="title()"
723
+ [attr.aria-label]="title()"
721
724
  (mousedown)="onMouseDown($event)"
722
725
  (click)="onClick.emit($event)"
723
726
  type="button"
@@ -732,7 +735,7 @@ class TiptapButtonComponent {
732
735
  }
733
736
  <ng-content></ng-content>
734
737
  </button>
735
- `, 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:not(.has-custom-bg){background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button.has-custom-bg:hover{transform:translateY(-1px);filter:brightness(.9)}.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{color:var(--ate-error-color, #ef4444);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"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
738
+ `, 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-sub-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-sub-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:not(.has-custom-bg){background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button.has-custom-bg:hover{transform:translateY(-1px);filter:brightness(.9)}.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{color:var(--ate-error-color, #ef4444);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"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
736
739
  }
737
740
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapButtonComponent, decorators: [{
738
741
  type: Component,
@@ -752,6 +755,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
752
755
  [style.color]="color()"
753
756
  [style.background-color]="backgroundColor()"
754
757
  [attr.title]="title()"
758
+ [attr.aria-label]="title()"
755
759
  (mousedown)="onMouseDown($event)"
756
760
  (click)="onClick.emit($event)"
757
761
  type="button"
@@ -766,7 +770,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
766
770
  }
767
771
  <ng-content></ng-content>
768
772
  </button>
769
- `, 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:not(.has-custom-bg){background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button.has-custom-bg:hover{transform:translateY(-1px);filter:brightness(.9)}.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{color:var(--ate-error-color, #ef4444);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"] }]
773
+ `, styles: [".tiptap-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:var(--ate-sub-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-sub-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:not(.has-custom-bg){background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.tiptap-button.has-custom-bg:hover{transform:translateY(-1px);filter:brightness(.9)}.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{color:var(--ate-error-color, #ef4444);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"] }]
770
774
  }] });
771
775
 
772
776
  class TiptapSeparatorComponent {
@@ -806,7 +810,8 @@ const ENGLISH_TRANSLATIONS = {
806
810
  italic: "Italic",
807
811
  underline: "Underline",
808
812
  strike: "Strikethrough",
809
- code: "Code",
813
+ code: "Inline Code",
814
+ codeBlock: "Code Block",
810
815
  superscript: "Superscript",
811
816
  subscript: "Subscript",
812
817
  highlight: "Highlight",
@@ -970,7 +975,8 @@ const FRENCH_TRANSLATIONS = {
970
975
  italic: "Italique",
971
976
  underline: "Souligné",
972
977
  strike: "Barré",
973
- code: "Code",
978
+ code: "Code en ligne",
979
+ codeBlock: "Bloc de code",
974
980
  superscript: "Exposant",
975
981
  subscript: "Indice",
976
982
  highlight: "Surligner",
@@ -1144,10 +1150,12 @@ class TiptapI18nService {
1144
1150
  en: ENGLISH_TRANSLATIONS,
1145
1151
  fr: FRENCH_TRANSLATIONS,
1146
1152
  });
1147
- // Signaux publics
1153
+ // Public signals
1148
1154
  this.currentLocale = this._currentLocale.asReadonly();
1155
+ /** All loaded translations (useful for dynamic key access) */
1156
+ this.allTranslations = this._translations.asReadonly();
1149
1157
  this.translations = computed(() => this._translations()[this._currentLocale()]);
1150
- // Méthodes de traduction rapides
1158
+ // Fast translation methods
1151
1159
  this.t = computed(() => this.translations());
1152
1160
  this.toolbar = computed(() => this.translations().toolbar);
1153
1161
  this.bubbleMenu = computed(() => this.translations().bubbleMenu);
@@ -1156,7 +1164,7 @@ class TiptapI18nService {
1156
1164
  this.imageUpload = computed(() => this.translations().imageUpload);
1157
1165
  this.editor = computed(() => this.translations().editor);
1158
1166
  this.common = computed(() => this.translations().common);
1159
- // Détecter automatiquement la langue du navigateur
1167
+ // Automatically detect browser language
1160
1168
  this.detectBrowserLanguage();
1161
1169
  }
1162
1170
  setLocale(locale) {
@@ -1169,13 +1177,16 @@ class TiptapI18nService {
1169
1177
  return Object.keys(this._translations());
1170
1178
  }
1171
1179
  addTranslations(locale, translations) {
1172
- this._translations.update((current) => ({
1173
- ...current,
1174
- [locale]: {
1175
- ...current[locale],
1176
- ...translations,
1177
- },
1178
- }));
1180
+ this._translations.update((current) => {
1181
+ const existing = current[locale] || ENGLISH_TRANSLATIONS;
1182
+ return {
1183
+ ...current,
1184
+ [locale]: {
1185
+ ...existing,
1186
+ ...translations,
1187
+ },
1188
+ };
1189
+ });
1179
1190
  }
1180
1191
  detectBrowserLanguage() {
1181
1192
  const browserLang = navigator.language.toLowerCase();
@@ -1186,7 +1197,7 @@ class TiptapI18nService {
1186
1197
  this._currentLocale.set("en");
1187
1198
  }
1188
1199
  }
1189
- // Méthodes utilitaires pour les composants
1200
+ // Utility methods for components
1190
1201
  getToolbarTitle(key) {
1191
1202
  return this.translations().toolbar[key];
1192
1203
  }
@@ -1552,13 +1563,10 @@ class ImageService {
1552
1563
  }, this.t().replacingImage, options);
1553
1564
  }
1554
1565
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1555
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ImageService, providedIn: "root" }); }
1566
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ImageService }); }
1556
1567
  }
1557
1568
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ImageService, decorators: [{
1558
- type: Injectable,
1559
- args: [{
1560
- providedIn: "root",
1561
- }]
1569
+ type: Injectable
1562
1570
  }] });
1563
1571
 
1564
1572
  /**
@@ -1788,13 +1796,10 @@ class ColorPickerService {
1788
1796
  return getContrastColor(color);
1789
1797
  }
1790
1798
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ColorPickerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1791
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ColorPickerService, providedIn: "root" }); }
1799
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ColorPickerService }); }
1792
1800
  }
1793
1801
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: ColorPickerService, decorators: [{
1794
- type: Injectable,
1795
- args: [{
1796
- providedIn: "root",
1797
- }]
1802
+ type: Injectable
1798
1803
  }] });
1799
1804
 
1800
1805
  class LinkService {
@@ -1882,13 +1887,10 @@ class LinkService {
1882
1887
  this.close();
1883
1888
  }
1884
1889
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: LinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1885
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: LinkService, providedIn: "root" }); }
1890
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: LinkService }); }
1886
1891
  }
1887
1892
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: LinkService, decorators: [{
1888
- type: Injectable,
1889
- args: [{
1890
- providedIn: "root",
1891
- }]
1893
+ type: Injectable
1892
1894
  }] });
1893
1895
 
1894
1896
  class EditorCommandsService {
@@ -1988,6 +1990,9 @@ class EditorCommandsService {
1988
1990
  case "toggleCode":
1989
1991
  this.toggleCode(editor);
1990
1992
  break;
1993
+ case "toggleCodeBlock":
1994
+ this.toggleCodeBlock(editor);
1995
+ break;
1991
1996
  case "toggleUnderline":
1992
1997
  this.toggleUnderline(editor);
1993
1998
  break;
@@ -2113,6 +2118,11 @@ class EditorCommandsService {
2113
2118
  return;
2114
2119
  editor.chain().focus().toggleCode().run();
2115
2120
  }
2121
+ toggleCodeBlock(editor) {
2122
+ if (!editor)
2123
+ return;
2124
+ editor.chain().focus().toggleCodeBlock().run();
2125
+ }
2116
2126
  toggleUnderline(editor) {
2117
2127
  if (!editor)
2118
2128
  return;
@@ -2291,13 +2301,10 @@ class EditorCommandsService {
2291
2301
  }
2292
2302
  }
2293
2303
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2294
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService, providedIn: "root" }); }
2304
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService }); }
2295
2305
  }
2296
2306
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: EditorCommandsService, decorators: [{
2297
- type: Injectable,
2298
- args: [{
2299
- providedIn: "root",
2300
- }]
2307
+ type: Injectable
2301
2308
  }] });
2302
2309
 
2303
2310
  class TiptapColorPickerComponent {
@@ -2330,7 +2337,7 @@ class TiptapColorPickerComponent {
2330
2337
  }
2331
2338
  // For text mode, add contrast background if current color is too light
2332
2339
  if (this.colorPickerSvc.getLuminance(color) > 200) {
2333
- return "#333333";
2340
+ return "#030617";
2334
2341
  }
2335
2342
  return "";
2336
2343
  });
@@ -2379,6 +2386,7 @@ class TiptapColorPickerComponent {
2379
2386
  class="btn-clear-badge"
2380
2387
  type="button"
2381
2388
  [title]="t().clear"
2389
+ [attr.aria-label]="t().clear"
2382
2390
  (click)="onClear($event)"
2383
2391
  >
2384
2392
  <span class="material-symbols-outlined">close</span>
@@ -2407,6 +2415,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
2407
2415
  class="btn-clear-badge"
2408
2416
  type="button"
2409
2417
  [title]="t().clear"
2418
+ [attr.aria-label]="t().clear"
2410
2419
  (click)="onClear($event)"
2411
2420
  >
2412
2421
  <span class="material-symbols-outlined">close</span>
@@ -2422,6 +2431,7 @@ class TiptapToolbarComponent {
2422
2431
  this.editor = input.required();
2423
2432
  this.config = input.required();
2424
2433
  this.imageUpload = input({});
2434
+ this.floating = input(false);
2425
2435
  this.i18nService = inject(TiptapI18nService);
2426
2436
  this.editorCommands = inject(EditorCommandsService);
2427
2437
  this.t = this.i18nService.toolbar;
@@ -2434,8 +2444,8 @@ class TiptapToolbarComponent {
2434
2444
  this.editorCommands.execute(editor, command, ...args);
2435
2445
  }
2436
2446
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2437
- 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 } }, ngImport: i0, template: `
2438
- <div class="tiptap-toolbar">
2447
+ 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 }, floating: { classPropertyName: "floating", publicName: "floating", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
2448
+ <div class="tiptap-toolbar" [class.floating]="floating()">
2439
2449
  @if (config().bold) {
2440
2450
  <tiptap-button
2441
2451
  icon="format_bold"
@@ -2476,6 +2486,14 @@ class TiptapToolbarComponent {
2476
2486
  [disabled]="!state().can.toggleCode"
2477
2487
  (onClick)="onCommand('toggleCode')"
2478
2488
  />
2489
+ } @if (config().codeBlock) {
2490
+ <tiptap-button
2491
+ icon="terminal"
2492
+ [title]="t().codeBlock"
2493
+ [active]="state().nodes.isCodeBlock"
2494
+ [disabled]="!state().can.toggleCodeBlock"
2495
+ (onClick)="onCommand('toggleCodeBlock')"
2496
+ />
2479
2497
  } @if (config().superscript) {
2480
2498
  <tiptap-button
2481
2499
  icon="superscript"
@@ -2660,7 +2678,7 @@ class TiptapToolbarComponent {
2660
2678
  />
2661
2679
  }
2662
2680
  </div>
2663
- `, 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;z-index:50;-webkit-backdrop-filter:blur(var(--ate-menu-blur, 16px));backdrop-filter:blur(var(--ate-menu-blur, 16px));border-top-left-radius:calc(var(--ate-border-radius, 8px) - var(--ate-border-width, 2px));border-top-right-radius:calc(var(--ate-border-radius, 8px) - var(--ate-border-width, 2px))}@media (max-width: 768px){.tiptap-toolbar{padding:6px 8px;gap:2px}}@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", "backgroundColor", "variant", "size", "iconSize"], outputs: ["onClick"] }, { kind: "component", type: TiptapSeparatorComponent, selector: "tiptap-separator", inputs: ["orientation", "size"] }, { kind: "component", type: TiptapColorPickerComponent, selector: "tiptap-color-picker", inputs: ["editor", "mode", "disabled", "anchorToText"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2681
+ `, isInline: true, styles: [":host{display:block;transition:opacity .3s ease}:host-context(.floating-toolbar){position:sticky;top:3rem;left:0;right:0;z-index:100;display:flex;height:0;overflow:visible;pointer-events:none;opacity:0}:host-context(.floating-toolbar:focus-within),:host-context(.floating-toolbar:hover){opacity:1}.tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:var(--ate-toolbar-padding);background:var(--ate-toolbar-background);border-bottom:1px solid var(--ate-toolbar-border-color);flex-wrap:wrap;min-height:32px;position:relative;z-index:50;border-top-left-radius:calc(var(--ate-menu-border-radius, 8px) - var(--ate-border-width, 2px));border-top-right-radius:calc(var(--ate-menu-border-radius, 8px) - var(--ate-border-width, 2px))}.tiptap-toolbar.floating{pointer-events:auto;border-radius:var(--ate-menu-border-radius, 8px);border:1px solid var(--ate-menu-border)!important;box-shadow:var(--ate-menu-shadow)!important;background:var(--ate-menu-bg)!important;padding:var(--ate-menu-padding)!important;flex-wrap:nowrap;overflow-x:auto;max-width:95vw;scrollbar-width:none;transform:translateY(0);transition:transform .3s cubic-bezier(.4,0,.2,1)}.tiptap-toolbar.floating::-webkit-scrollbar{display:none}:host-context(.floating-toolbar:focus-within) .tiptap-toolbar.floating,:host-context(.floating-toolbar:hover) .tiptap-toolbar.floating{transform:translateY(-2rem)}@media (max-width: 768px){.tiptap-toolbar{padding:6px 8px;gap:2px}}@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", "backgroundColor", "variant", "size", "iconSize"], outputs: ["onClick"] }, { kind: "component", type: TiptapSeparatorComponent, selector: "tiptap-separator", inputs: ["orientation", "size"] }, { kind: "component", type: TiptapColorPickerComponent, selector: "tiptap-color-picker", inputs: ["editor", "mode", "disabled", "anchorToText"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2664
2682
  }
2665
2683
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapToolbarComponent, decorators: [{
2666
2684
  type: Component,
@@ -2669,7 +2687,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
2669
2687
  TiptapSeparatorComponent,
2670
2688
  TiptapColorPickerComponent,
2671
2689
  ], template: `
2672
- <div class="tiptap-toolbar">
2690
+ <div class="tiptap-toolbar" [class.floating]="floating()">
2673
2691
  @if (config().bold) {
2674
2692
  <tiptap-button
2675
2693
  icon="format_bold"
@@ -2710,6 +2728,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
2710
2728
  [disabled]="!state().can.toggleCode"
2711
2729
  (onClick)="onCommand('toggleCode')"
2712
2730
  />
2731
+ } @if (config().codeBlock) {
2732
+ <tiptap-button
2733
+ icon="terminal"
2734
+ [title]="t().codeBlock"
2735
+ [active]="state().nodes.isCodeBlock"
2736
+ [disabled]="!state().can.toggleCodeBlock"
2737
+ (onClick)="onCommand('toggleCodeBlock')"
2738
+ />
2713
2739
  } @if (config().superscript) {
2714
2740
  <tiptap-button
2715
2741
  icon="superscript"
@@ -2894,7 +2920,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
2894
2920
  />
2895
2921
  }
2896
2922
  </div>
2897
- `, 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;z-index:50;-webkit-backdrop-filter:blur(var(--ate-menu-blur, 16px));backdrop-filter:blur(var(--ate-menu-blur, 16px));border-top-left-radius:calc(var(--ate-border-radius, 8px) - var(--ate-border-width, 2px));border-top-right-radius:calc(var(--ate-border-radius, 8px) - var(--ate-border-width, 2px))}@media (max-width: 768px){.tiptap-toolbar{padding:6px 8px;gap:2px}}@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"] }]
2923
+ `, styles: [":host{display:block;transition:opacity .3s ease}:host-context(.floating-toolbar){position:sticky;top:3rem;left:0;right:0;z-index:100;display:flex;height:0;overflow:visible;pointer-events:none;opacity:0}:host-context(.floating-toolbar:focus-within),:host-context(.floating-toolbar:hover){opacity:1}.tiptap-toolbar{display:flex;align-items:center;gap:4px;padding:var(--ate-toolbar-padding);background:var(--ate-toolbar-background);border-bottom:1px solid var(--ate-toolbar-border-color);flex-wrap:wrap;min-height:32px;position:relative;z-index:50;border-top-left-radius:calc(var(--ate-menu-border-radius, 8px) - var(--ate-border-width, 2px));border-top-right-radius:calc(var(--ate-menu-border-radius, 8px) - var(--ate-border-width, 2px))}.tiptap-toolbar.floating{pointer-events:auto;border-radius:var(--ate-menu-border-radius, 8px);border:1px solid var(--ate-menu-border)!important;box-shadow:var(--ate-menu-shadow)!important;background:var(--ate-menu-bg)!important;padding:var(--ate-menu-padding)!important;flex-wrap:nowrap;overflow-x:auto;max-width:95vw;scrollbar-width:none;transform:translateY(0);transition:transform .3s cubic-bezier(.4,0,.2,1)}.tiptap-toolbar.floating::-webkit-scrollbar{display:none}:host-context(.floating-toolbar:focus-within) .tiptap-toolbar.floating,:host-context(.floating-toolbar:hover) .tiptap-toolbar.floating{transform:translateY(-2rem)}@media (max-width: 768px){.tiptap-toolbar{padding:6px 8px;gap:2px}}@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"] }]
2898
2924
  }] });
2899
2925
 
2900
2926
  /**
@@ -3467,7 +3493,7 @@ class TiptapImageBubbleMenuComponent extends TiptapBaseBubbleMenu {
3467
3493
  if (!ed)
3468
3494
  return;
3469
3495
  try {
3470
- // Utiliser la méthode spécifique pour remplacer une image existante
3496
+ // Use dedicated method to replace an existing image
3471
3497
  await this.imageService.selectAndReplaceImage(ed, {
3472
3498
  quality: 0.8,
3473
3499
  maxWidth: 1920,
@@ -4582,6 +4608,7 @@ class TiptapColorBubbleMenuComponent {
4582
4608
  type="text"
4583
4609
  class="hex-input"
4584
4610
  [value]="hexValue()"
4611
+ [attr.aria-label]="t().customColor"
4585
4612
  (input)="onHexInput($event)"
4586
4613
  (change)="onHexChange($event)"
4587
4614
  (keydown.enter)="onApply($event)"
@@ -4605,6 +4632,7 @@ class TiptapColorBubbleMenuComponent {
4605
4632
  type="color"
4606
4633
  class="hidden-native-input"
4607
4634
  [value]="currentColor()"
4635
+ [attr.aria-label]="t().customColor"
4608
4636
  (input)="onNativeInput($event)"
4609
4637
  (change)="onNativeChange($event)"
4610
4638
  (focus)="onFocus()"
@@ -4666,6 +4694,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
4666
4694
  type="text"
4667
4695
  class="hex-input"
4668
4696
  [value]="hexValue()"
4697
+ [attr.aria-label]="t().customColor"
4669
4698
  (input)="onHexInput($event)"
4670
4699
  (change)="onHexChange($event)"
4671
4700
  (keydown.enter)="onApply($event)"
@@ -4689,6 +4718,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
4689
4718
  type="color"
4690
4719
  class="hidden-native-input"
4691
4720
  [value]="currentColor()"
4721
+ [attr.aria-label]="t().customColor"
4692
4722
  (input)="onNativeInput($event)"
4693
4723
  (change)="onNativeChange($event)"
4694
4724
  (focus)="onFocus()"
@@ -4805,7 +4835,7 @@ function createDefaultSlashCommands(i18n, commands, imageOptions) {
4805
4835
  description: t.code.description,
4806
4836
  icon: "code",
4807
4837
  keywords: t.code.keywords,
4808
- command: (editor) => commands.toggleCode(editor),
4838
+ command: (editor) => commands.toggleCodeBlock(editor),
4809
4839
  },
4810
4840
  {
4811
4841
  title: t.image.title,
@@ -4851,7 +4881,7 @@ function filterSlashCommands(config, i18n, commands, imageOptions) {
4851
4881
  return filtered;
4852
4882
  }
4853
4883
 
4854
- // La définition des commandes par défaut est maintenant centralisée dans src/lib/config/i18n-slash-commands.ts
4884
+ // Default command definitions are now centralized in src/lib/config/slash-commands.config.ts
4855
4885
  class TiptapSlashCommandsComponent {
4856
4886
  constructor() {
4857
4887
  this.i18nService = inject(TiptapI18nService);
@@ -4859,11 +4889,11 @@ class TiptapSlashCommandsComponent {
4859
4889
  this.config = input(undefined);
4860
4890
  this.tippyInstance = null;
4861
4891
  this.editorCommands = inject(EditorCommandsService);
4862
- // État local
4892
+ // Local state
4863
4893
  this.isActive = false;
4864
4894
  this.currentQuery = signal("");
4865
4895
  this.slashRange = null;
4866
- // Signal pour l'index sélectionné
4896
+ // Signal for selected index
4867
4897
  this.selectedIndex = signal(0);
4868
4898
  // Toolbar interaction state (from centralized service)
4869
4899
  this.isToolbarInteracting = this.editorCommands.isToolbarInteracting;
@@ -4872,7 +4902,7 @@ class TiptapSlashCommandsComponent {
4872
4902
  if (config && config.commands) {
4873
4903
  return config.commands;
4874
4904
  }
4875
- // Fallback vers les commandes natives par défaut
4905
+ // Fallback to default native commands
4876
4906
  return createDefaultSlashCommands(this.i18nService, this.editorCommands);
4877
4907
  });
4878
4908
  this.filteredCommands = computed(() => {
@@ -4890,7 +4920,7 @@ class TiptapSlashCommandsComponent {
4890
4920
  if (!ed)
4891
4921
  return;
4892
4922
  const { from } = ed.state.selection;
4893
- // Vérifier si on a tapé '/' au début d'une ligne ou après un espace
4923
+ // Check if '/' was typed at the beginning of a line or after a space
4894
4924
  const textBefore = ed.state.doc.textBetween(Math.max(0, from - 20), from, "\n");
4895
4925
  const slashMatch = textBefore.match(/(?:^|\s)\/([^\/\s]*)$/);
4896
4926
  if (slashMatch) {
@@ -4901,7 +4931,7 @@ class TiptapSlashCommandsComponent {
4901
4931
  from: from - slashMatch[0].length + slashMatch[0].indexOf("/"),
4902
4932
  to: from,
4903
4933
  };
4904
- // Si le menu vient de devenir actif, réinitialiser l'index
4934
+ // Reset index if menu just became active
4905
4935
  if (!wasActive) {
4906
4936
  this.selectedIndex.set(0);
4907
4937
  }
@@ -4922,7 +4952,7 @@ class TiptapSlashCommandsComponent {
4922
4952
  setTimeout(() => this.hideTippy(), 100);
4923
4953
  };
4924
4954
  this.handleKeyDown = (event) => {
4925
- // Ne gérer les touches que si le menu est actif
4955
+ // Only handle keys if menu is active
4926
4956
  if (!this.isActive || this.filteredCommands().length === 0) {
4927
4957
  return;
4928
4958
  }
@@ -4956,7 +4986,7 @@ class TiptapSlashCommandsComponent {
4956
4986
  event.stopPropagation();
4957
4987
  this.isActive = false;
4958
4988
  this.hideTippy();
4959
- // Optionnel : supprimer le "/" tapé
4989
+ // Optional: remove the typed "/"
4960
4990
  const ed = this.editor();
4961
4991
  if (ed && this.slashRange) {
4962
4992
  const { tr } = ed.state;
@@ -4970,20 +5000,19 @@ class TiptapSlashCommandsComponent {
4970
5000
  const ed = this.editor();
4971
5001
  if (!ed)
4972
5002
  return;
4973
- // Nettoyer les anciens listeners
5003
+ // Clean up old listeners
4974
5004
  ed.off("selectionUpdate", this.updateMenu);
4975
5005
  ed.off("transaction", this.updateMenu);
4976
5006
  ed.off("focus", this.updateMenu);
4977
5007
  ed.off("blur", this.handleBlur);
4978
- // Ajouter les nouveaux listeners
5008
+ // Add new listeners
4979
5009
  ed.on("selectionUpdate", this.updateMenu);
4980
5010
  ed.on("transaction", this.updateMenu);
4981
5011
  ed.on("focus", this.updateMenu);
4982
5012
  ed.on("blur", this.handleBlur);
4983
- // Utiliser le système de plugins ProseMirror pour intercepter les touches
5013
+ // Use ProseMirror plugin system to intercept keys
4984
5014
  this.addKeyboardPlugin(ed);
4985
- // Ne pas appeler updateMenu() ici pour éviter l'affichage prématuré
4986
- // Il sera appelé automatiquement quand l'éditeur sera prêt
5015
+ // updateMenu() will be called automatically when editor is ready
4987
5016
  });
4988
5017
  }
4989
5018
  ngOnInit() {
@@ -5017,7 +5046,7 @@ class TiptapSlashCommandsComponent {
5017
5046
  placement: "bottom-start",
5018
5047
  theme: "slash-menu",
5019
5048
  appendTo: (ref) => {
5020
- // Toujours essayer de remonter jusqu'au host de l'éditeur pour hériter des variables CSS
5049
+ // Always try to climb up to editor host to inherit CSS variables
5021
5050
  const host = this.editor().options.element.closest("angular-tiptap-editor");
5022
5051
  return host || document.body;
5023
5052
  },
@@ -5028,7 +5057,7 @@ class TiptapSlashCommandsComponent {
5028
5057
  plugins: [sticky],
5029
5058
  sticky: false,
5030
5059
  getReferenceClientRect: () => this.getSlashRect(),
5031
- // Améliorer le positionnement avec scroll
5060
+ // Improve positioning with scroll
5032
5061
  popperOptions: {
5033
5062
  modifiers: [
5034
5063
  {
@@ -5050,7 +5079,7 @@ class TiptapSlashCommandsComponent {
5050
5079
  ],
5051
5080
  },
5052
5081
  });
5053
- // Maintenant que Tippy est initialisé, faire un premier check
5082
+ // Initial check after Tippy is initialized
5054
5083
  this.updateMenu();
5055
5084
  }
5056
5085
  getSlashRect() {
@@ -5059,13 +5088,13 @@ class TiptapSlashCommandsComponent {
5059
5088
  return new DOMRect(-9999, -9999, 0, 0);
5060
5089
  }
5061
5090
  try {
5062
- // Utiliser les coordonnées ProseMirror pour plus de précision
5091
+ // Use ProseMirror coordinates for better precision
5063
5092
  const coords = ed.view.coordsAtPos(this.slashRange.from);
5064
5093
  return new DOMRect(coords.left, coords.top, 0, coords.bottom - coords.top);
5065
5094
  }
5066
5095
  catch (error) {
5067
5096
  console.warn("Error calculating coordinates:", error);
5068
- // Fallback sur window.getSelection
5097
+ // Fallback to window.getSelection
5069
5098
  const selection = window.getSelection();
5070
5099
  if (!selection || selection.rangeCount === 0) {
5071
5100
  return new DOMRect(-9999, -9999, 0, 0);
@@ -5075,7 +5104,7 @@ class TiptapSlashCommandsComponent {
5075
5104
  }
5076
5105
  }
5077
5106
  scrollToSelected() {
5078
- // Faire défiler vers l'élément sélectionné
5107
+ // Scroll to the selected element
5079
5108
  if (this.menuRef?.nativeElement) {
5080
5109
  const selectedItem = this.menuRef.nativeElement.querySelector(".slash-command-item.selected");
5081
5110
  if (selectedItem) {
@@ -5099,28 +5128,27 @@ class TiptapSlashCommandsComponent {
5099
5128
  const ed = this.editor();
5100
5129
  if (!ed || !this.slashRange)
5101
5130
  return;
5102
- // Supprimer le texte slash ("/")
5131
+ // Remove slash text ("/")
5103
5132
  const { tr } = ed.state;
5104
5133
  tr.delete(this.slashRange.from, this.slashRange.to);
5105
5134
  ed.view.dispatch(tr);
5106
- // Cacher le menu immédiatement
5135
+ // Hide menu immediately
5107
5136
  this.hideTippy();
5108
5137
  this.isActive = false;
5109
- // Redonner le focus à l'éditeur et exécuter la commande
5110
- // On utilise un micro-délai pour s'assurer que le DOM ProseMirror est stable
5111
- // après la suppression du texte "/"
5138
+ // Give focus back to editor and execute command
5139
+ // Use a micro-delay to ensure ProseMirror DOM is stable after removing "/"
5112
5140
  setTimeout(() => {
5113
5141
  ed.commands.focus();
5114
5142
  command.command(ed);
5115
5143
  }, 10);
5116
5144
  }
5117
5145
  addKeyboardPlugin(ed) {
5118
- // Ajouter un plugin ProseMirror pour intercepter les événements clavier
5146
+ // Add a ProseMirror plugin to intercept keyboard events
5119
5147
  const keyboardPlugin = new Plugin$1({
5120
5148
  key: new PluginKey$1("slash-commands-keyboard"),
5121
5149
  props: {
5122
5150
  handleKeyDown: (view, event) => {
5123
- // Ne gérer que si le menu est actif
5151
+ // Only handle if menu is active
5124
5152
  if (!this.isActive || this.filteredCommands().length === 0) {
5125
5153
  return false;
5126
5154
  }
@@ -5150,7 +5178,7 @@ class TiptapSlashCommandsComponent {
5150
5178
  event.preventDefault();
5151
5179
  this.isActive = false;
5152
5180
  this.hideTippy();
5153
- // Supprimer le "/" tapé
5181
+ // Remove typed "/"
5154
5182
  if (this.slashRange) {
5155
5183
  const { tr } = view.state;
5156
5184
  tr.delete(this.slashRange.from, this.slashRange.to);
@@ -5162,7 +5190,7 @@ class TiptapSlashCommandsComponent {
5162
5190
  },
5163
5191
  },
5164
5192
  });
5165
- // Ajouter le plugin à l'éditeur
5193
+ // Add plugin to editor
5166
5194
  ed.view.updateState(ed.view.state.reconfigure({
5167
5195
  plugins: [keyboardPlugin, ...ed.view.state.plugins],
5168
5196
  }));
@@ -5187,7 +5215,7 @@ class TiptapSlashCommandsComponent {
5187
5215
  </div>
5188
5216
  }
5189
5217
  </div>
5190
- `, 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"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5218
+ `, isInline: true, styles: [".slash-commands-menu{background:var(--ate-menu-bg);border:1px solid var(--ate-menu-border);border-radius:var(--ate-border-radius, 12px);box-shadow:var(--ate-menu-shadow);padding:var(--ate-menu-padding);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:var(--ate-menu-padding);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-sub-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"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5191
5219
  }
5192
5220
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: TiptapSlashCommandsComponent, decorators: [{
5193
5221
  type: Component,
@@ -5210,7 +5238,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
5210
5238
  </div>
5211
5239
  }
5212
5240
  </div>
5213
- `, 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"] }]
5241
+ `, styles: [".slash-commands-menu{background:var(--ate-menu-bg);border:1px solid var(--ate-menu-border);border-radius:var(--ate-border-radius, 12px);box-shadow:var(--ate-menu-shadow);padding:var(--ate-menu-padding);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:var(--ate-menu-padding);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-sub-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"] }]
5214
5242
  }], ctorParameters: () => [], propDecorators: { menuRef: [{
5215
5243
  type: ViewChild,
5216
5244
  args: ["menuRef", { static: false }]
@@ -5278,8 +5306,10 @@ const MarksCalculator = (editor) => {
5278
5306
  const isCode = editor.isActive('code'); // Inline code mark
5279
5307
  const isImage = editor.isActive('image') || editor.isActive('resizableImage');
5280
5308
  // Check if marks are generally allowed based on context
5281
- // Marks are NOT allowed inside code blocks, inline code, or on images
5282
- const marksAllowed = !isCodeBlock && !isCode && !isImage;
5309
+ const marksAllowed = !isCodeBlock && !isImage;
5310
+ // For inline code specifically, we don't allow nesting OTHER marks inside it,
5311
+ // but the code mark ITSELF must be togglable to be removed.
5312
+ const isInsideInlineCode = isCode;
5283
5313
  // 1. Resolve target element once for this calculation
5284
5314
  const getTargetElement = () => {
5285
5315
  if (typeof window === 'undefined' || !editor.view?.dom)
@@ -5312,7 +5342,7 @@ const MarksCalculator = (editor) => {
5312
5342
  italic: editor.isActive('italic'),
5313
5343
  underline: editor.isActive('underline'),
5314
5344
  strike: editor.isActive('strike'),
5315
- code: editor.isActive('code'),
5345
+ code: isCode,
5316
5346
  superscript: editor.isActive('superscript'),
5317
5347
  subscript: editor.isActive('subscript'),
5318
5348
  highlight: editor.isActive('highlight'),
@@ -5322,19 +5352,20 @@ const MarksCalculator = (editor) => {
5322
5352
  computedColor: colorMark || getStyle('color'),
5323
5353
  background: backgroundMark,
5324
5354
  computedBackground: backgroundMark || getStyle('background-color'),
5355
+ linkOpenOnClick: editor.extensionManager.extensions.find(ext => ext.name === 'link')?.options?.openOnClick ?? false,
5325
5356
  },
5326
5357
  can: {
5327
- toggleBold: marksAllowed && editor.can().toggleBold(),
5328
- toggleItalic: marksAllowed && editor.can().toggleItalic(),
5329
- toggleUnderline: marksAllowed && editor.can().toggleUnderline(),
5330
- toggleStrike: marksAllowed && editor.can().toggleStrike(),
5358
+ toggleBold: marksAllowed && !isInsideInlineCode && editor.can().toggleBold(),
5359
+ toggleItalic: marksAllowed && !isInsideInlineCode && editor.can().toggleItalic(),
5360
+ toggleUnderline: marksAllowed && !isInsideInlineCode && editor.can().toggleUnderline(),
5361
+ toggleStrike: marksAllowed && !isInsideInlineCode && editor.can().toggleStrike(),
5331
5362
  toggleCode: marksAllowed && editor.can().toggleCode(),
5332
- toggleHighlight: marksAllowed && editor.can().toggleHighlight(),
5333
- toggleLink: marksAllowed && (editor.can().setLink({ href: '' }) || editor.can().unsetLink()),
5334
- toggleSuperscript: marksAllowed && editor.can().toggleSuperscript(),
5335
- toggleSubscript: marksAllowed && editor.can().toggleSubscript(),
5336
- setColor: marksAllowed && editor.can().setColor(''),
5337
- setHighlight: marksAllowed && editor.can().setHighlight(),
5363
+ toggleHighlight: marksAllowed && !isInsideInlineCode && editor.can().toggleHighlight(),
5364
+ toggleLink: marksAllowed && !isInsideInlineCode && (editor.can().setLink({ href: '' }) || editor.can().unsetLink()),
5365
+ toggleSuperscript: marksAllowed && !isInsideInlineCode && editor.can().toggleSuperscript(),
5366
+ toggleSubscript: marksAllowed && !isInsideInlineCode && editor.can().toggleSubscript(),
5367
+ setColor: marksAllowed && !isInsideInlineCode && editor.can().setColor(''),
5368
+ setHighlight: marksAllowed && !isInsideInlineCode && editor.can().setHighlight(),
5338
5369
  undo: editor.can().undo(),
5339
5370
  redo: editor.can().redo(),
5340
5371
  }
@@ -5408,6 +5439,7 @@ const StructureCalculator = (editor) => {
5408
5439
  toggleBulletList: editor.can().toggleBulletList(),
5409
5440
  toggleOrderedList: editor.can().toggleOrderedList(),
5410
5441
  toggleBlockquote: editor.can().toggleBlockquote(),
5442
+ toggleCodeBlock: editor.can().toggleCodeBlock(),
5411
5443
  setTextAlignLeft: editor.can().setTextAlign('left'),
5412
5444
  setTextAlignCenter: editor.can().setTextAlign('center'),
5413
5445
  setTextAlignRight: editor.can().setTextAlign('right'),
@@ -5454,16 +5486,44 @@ const DiscoveryCalculator = (editor) => {
5454
5486
  return state;
5455
5487
  };
5456
5488
 
5457
- // Configuration par défaut de la toolbar
5489
+ const LinkClickBehavior = Extension.create({
5490
+ name: 'linkClickBehavior',
5491
+ addProseMirrorPlugins() {
5492
+ return [
5493
+ new Plugin({
5494
+ key: new PluginKey('linkClickBehavior'),
5495
+ props: {
5496
+ handleClick(view, pos, event) {
5497
+ // handleClick only runs in the browser, but we guard it for absolute SSR safety
5498
+ if (typeof window === 'undefined')
5499
+ return false;
5500
+ // If editor is editable, let TipTap/BubbleMenu handle it
5501
+ if (view.editable)
5502
+ return false;
5503
+ const attrs = getAttributes(view.state, 'link');
5504
+ if (attrs['href']) {
5505
+ window.open(attrs['href'], '_blank', 'noopener,noreferrer');
5506
+ return true;
5507
+ }
5508
+ return false;
5509
+ }
5510
+ }
5511
+ })
5512
+ ];
5513
+ }
5514
+ });
5515
+
5516
+ // Default toolbar configuration
5458
5517
  const DEFAULT_TOOLBAR_CONFIG = {
5459
5518
  bold: true,
5460
5519
  italic: true,
5461
5520
  underline: true,
5462
5521
  strike: true,
5463
5522
  code: true,
5464
- superscript: false,
5465
- subscript: false,
5466
- highlight: false,
5523
+ codeBlock: true,
5524
+ superscript: false, // Disabled by default (opt-in)
5525
+ subscript: false, // Disabled by default (opt-in)
5526
+ highlight: false, // Disabled by default (opt-in)
5467
5527
  highlightPicker: true,
5468
5528
  heading1: true,
5469
5529
  heading2: true,
@@ -5471,21 +5531,21 @@ const DEFAULT_TOOLBAR_CONFIG = {
5471
5531
  bulletList: true,
5472
5532
  orderedList: true,
5473
5533
  blockquote: true,
5474
- alignLeft: false,
5475
- alignCenter: false,
5476
- alignRight: false,
5477
- alignJustify: false,
5534
+ alignLeft: false, // Disabled by default (opt-in)
5535
+ alignCenter: false, // Disabled by default (opt-in)
5536
+ alignRight: false, // Disabled by default (opt-in)
5537
+ alignJustify: false, // Disabled by default (opt-in)
5478
5538
  link: true,
5479
5539
  image: true,
5480
- horizontalRule: true,
5540
+ horizontalRule: false, // Disabled by default (opt-in)
5481
5541
  table: true,
5482
5542
  undo: true,
5483
5543
  redo: true,
5484
- clear: false, // Désactivé par défaut (opt-in)
5544
+ clear: false, // Disabled by default (opt-in)
5485
5545
  textColor: true,
5486
5546
  separator: true,
5487
5547
  };
5488
- // Configuration par défaut du bubble menu
5548
+ // Default bubble menu configuration
5489
5549
  const DEFAULT_BUBBLE_MENU_CONFIG = {
5490
5550
  bold: true,
5491
5551
  italic: true,
@@ -5500,7 +5560,7 @@ const DEFAULT_BUBBLE_MENU_CONFIG = {
5500
5560
  link: true,
5501
5561
  separator: true,
5502
5562
  };
5503
- // Configuration par défaut du bubble menu image
5563
+ // Default image bubble menu configuration
5504
5564
  const DEFAULT_IMAGE_BUBBLE_MENU_CONFIG = {
5505
5565
  changeImage: true,
5506
5566
  resizeSmall: true,
@@ -5510,7 +5570,7 @@ const DEFAULT_IMAGE_BUBBLE_MENU_CONFIG = {
5510
5570
  deleteImage: true,
5511
5571
  separator: true,
5512
5572
  };
5513
- // Configuration par défaut du menu de table
5573
+ // Default table bubble menu configuration
5514
5574
  const DEFAULT_TABLE_MENU_CONFIG = {
5515
5575
  addRowBefore: true,
5516
5576
  addRowAfter: true,
@@ -5523,6 +5583,7 @@ const DEFAULT_TABLE_MENU_CONFIG = {
5523
5583
  deleteTable: true,
5524
5584
  separator: true,
5525
5585
  };
5586
+ // Default cell bubble menu configuration
5526
5587
  const DEFAULT_CELL_MENU_CONFIG = {
5527
5588
  mergeCells: true,
5528
5589
  splitCell: true,
@@ -5543,11 +5604,13 @@ class AngularTiptapEditorComponent {
5543
5604
  this.content = input("");
5544
5605
  this.placeholder = input("");
5545
5606
  this.editable = input(true);
5607
+ this.disabled = input(false);
5546
5608
  this.minHeight = input(200);
5547
5609
  this.height = input(undefined);
5548
5610
  this.maxHeight = input(undefined);
5549
5611
  this.fillContainer = input(false);
5550
5612
  this.showToolbar = input(true);
5613
+ this.showFooter = input(true);
5551
5614
  this.showCharacterCount = input(true);
5552
5615
  this.showWordCount = input(true);
5553
5616
  this.maxCharacters = input(undefined);
@@ -5557,6 +5620,8 @@ class AngularTiptapEditorComponent {
5557
5620
  this.customSlashCommands = input(undefined);
5558
5621
  this.locale = input(undefined);
5559
5622
  this.autofocus = input(false);
5623
+ this.seamless = input(false);
5624
+ this.floatingToolbar = input(false);
5560
5625
  this.tiptapExtensions = input([]);
5561
5626
  this.tiptapOptions = input({});
5562
5627
  // Nouveaux inputs pour les bubble menus
@@ -5564,8 +5629,13 @@ class AngularTiptapEditorComponent {
5564
5629
  this.bubbleMenu = input(DEFAULT_BUBBLE_MENU_CONFIG);
5565
5630
  this.showImageBubbleMenu = input(true);
5566
5631
  this.imageBubbleMenu = input(DEFAULT_IMAGE_BUBBLE_MENU_CONFIG);
5567
- // Nouveau input pour la configuration de la toolbar
5632
+ // Configuration de la toolbar
5568
5633
  this.toolbar = input({});
5634
+ // Configuration des menus de table
5635
+ this.showTableBubbleMenu = input(true);
5636
+ this.tableBubbleMenu = input(DEFAULT_TABLE_MENU_CONFIG);
5637
+ this.showCellBubbleMenu = input(true);
5638
+ this.cellBubbleMenu = input(DEFAULT_CELL_MENU_CONFIG);
5569
5639
  /**
5570
5640
  * Additionnal state calculators to extend the reactive editor state.
5571
5641
  */
@@ -5598,9 +5668,9 @@ class AngularTiptapEditorComponent {
5598
5668
  this.editorUpdate = output();
5599
5669
  this.editorFocus = output();
5600
5670
  this.editorBlur = output();
5601
- // ViewChild avec signal
5671
+ // ViewChild with signal
5602
5672
  this.editorElement = viewChild.required("editorElement");
5603
- // Signals privés pour l'état interne
5673
+ // Private signals for internal state
5604
5674
  this._editor = signal(null);
5605
5675
  this._characterCount = signal(0);
5606
5676
  this._wordCount = signal(0);
@@ -5608,44 +5678,39 @@ class AngularTiptapEditorComponent {
5608
5678
  this._editorFullyInitialized = signal(false);
5609
5679
  // Anti-echo: track last emitted HTML to prevent cursor reset on parent echo
5610
5680
  this.lastEmittedHtml = null;
5611
- // Accès en lecture seule aux signaux
5681
+ // Read-only access to signals
5612
5682
  this.editor = this._editor.asReadonly();
5613
5683
  this.characterCount = this._characterCount.asReadonly();
5614
5684
  this.wordCount = this._wordCount.asReadonly();
5615
5685
  this.isDragOver = this._isDragOver.asReadonly();
5616
5686
  this.editorFullyInitialized = this._editorFullyInitialized.asReadonly();
5617
- // Computed pour les états de l'éditeur
5687
+ this._isFormControlDisabled = signal(false);
5688
+ this.isFormControlDisabled = this._isFormControlDisabled.asReadonly();
5689
+ // Combined disabled state (Input + FormControl)
5690
+ this.mergedDisabled = computed(() => this.disabled() || this.isFormControlDisabled());
5691
+ // Computed for editor states
5618
5692
  this.isEditorReady = computed(() => this.editor() !== null);
5619
- // Computed pour la configuration de la toolbar
5693
+ // Computed for toolbar configuration
5620
5694
  this.toolbarConfig = computed(() => Object.keys(this.toolbar()).length === 0
5621
5695
  ? DEFAULT_TOOLBAR_CONFIG
5622
5696
  : this.toolbar());
5623
- // Computed pour la configuration du bubble menu
5697
+ // Computed for bubble menu configuration
5624
5698
  this.bubbleMenuConfig = computed(() => Object.keys(this.bubbleMenu()).length === 0
5625
5699
  ? DEFAULT_BUBBLE_MENU_CONFIG
5626
5700
  : { ...DEFAULT_BUBBLE_MENU_CONFIG, ...this.bubbleMenu() });
5627
- // Computed pour la configuration du bubble menu image
5701
+ // Computed for image bubble menu configuration
5628
5702
  this.imageBubbleMenuConfig = computed(() => Object.keys(this.imageBubbleMenu()).length === 0
5629
5703
  ? DEFAULT_IMAGE_BUBBLE_MENU_CONFIG
5630
5704
  : { ...DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, ...this.imageBubbleMenu() });
5631
- // Computed pour la configuration du bubble menu table
5632
- this.tableBubbleMenuConfig = computed(() => ({
5633
- addRowBefore: true,
5634
- addRowAfter: true,
5635
- deleteRow: true,
5636
- addColumnBefore: true,
5637
- addColumnAfter: true,
5638
- deleteColumn: true,
5639
- deleteTable: true,
5640
- toggleHeaderRow: true,
5641
- toggleHeaderColumn: true,
5642
- }));
5643
- // Computed pour la configuration du menu de cellules
5644
- this.cellBubbleMenuConfig = computed(() => ({
5645
- mergeCells: true,
5646
- splitCell: true,
5647
- }));
5648
- // Computed pour la configuration de l'upload d'images
5705
+ // Computed for table bubble menu configuration
5706
+ this.tableBubbleMenuConfig = computed(() => Object.keys(this.tableBubbleMenu()).length === 0
5707
+ ? DEFAULT_TABLE_MENU_CONFIG
5708
+ : { ...DEFAULT_TABLE_MENU_CONFIG, ...this.tableBubbleMenu() });
5709
+ // Computed for cell bubble menu configuration
5710
+ this.cellBubbleMenuConfig = computed(() => Object.keys(this.cellBubbleMenu()).length === 0
5711
+ ? DEFAULT_CELL_MENU_CONFIG
5712
+ : { ...DEFAULT_CELL_MENU_CONFIG, ...this.cellBubbleMenu() });
5713
+ // Computed for image upload configuration
5649
5714
  this.imageUploadConfig = computed(() => ({
5650
5715
  maxSize: 5,
5651
5716
  maxWidth: 1920,
@@ -5658,7 +5723,7 @@ class AngularTiptapEditorComponent {
5658
5723
  quality: 0.8,
5659
5724
  ...this.imageUpload(),
5660
5725
  }));
5661
- // Computed pour la configuration des slash commands
5726
+ // Computed for slash commands configuration
5662
5727
  this.slashCommandsConfigComputed = computed(() => {
5663
5728
  const customConfig = this.customSlashCommands();
5664
5729
  if (customConfig) {
@@ -5670,22 +5735,27 @@ class AngularTiptapEditorComponent {
5670
5735
  commands: filterSlashCommands(this.slashCommands(), this.i18nService, this.editorCommandsService, this.imageUploadConfig()),
5671
5736
  };
5672
5737
  });
5738
+ // Computed for current translations (allows per-instance override via [locale] input)
5739
+ this.currentTranslations = computed(() => {
5740
+ const localeOverride = this.locale();
5741
+ if (localeOverride) {
5742
+ // If a specific language is provided to this instance, try to retrieve it
5743
+ const allTranslations = this.i18nService.allTranslations();
5744
+ return allTranslations[localeOverride] || this.i18nService.translations();
5745
+ }
5746
+ // Otherwise, follow the global service language
5747
+ return this.i18nService.translations();
5748
+ });
5673
5749
  this._destroyRef = inject(DestroyRef);
5674
- // NgControl pour gérer les FormControls
5750
+ // NgControl for management of FormControls
5675
5751
  this.ngControl = inject(NgControl, { self: true, optional: true });
5676
5752
  this.i18nService = inject(TiptapI18nService);
5677
5753
  this.editorCommandsService = inject(EditorCommandsService);
5754
+ // Access editor state via service
5678
5755
  this.editorState = this.editorCommandsService.editorState;
5679
- // Effet pour gérer le changement de langue
5756
+ // Effect to update editor content (with anti-echo)
5680
5757
  effect(() => {
5681
- const locale = this.locale();
5682
- if (locale) {
5683
- this.i18nService.setLocale(locale);
5684
- }
5685
- });
5686
- // Effet pour mettre à jour le contenu de l'éditeur (avec anti-écho)
5687
- effect(() => {
5688
- const content = this.content(); // Seule dépendance réactive
5758
+ const content = this.content(); // Sole reactive dependency
5689
5759
  untracked(() => {
5690
5760
  const editor = this.editor();
5691
5761
  const hasFormControl = !!this.ngControl?.control;
@@ -5697,19 +5767,19 @@ class AngularTiptapEditorComponent {
5697
5767
  // Double sécurité : on vérifie le contenu actuel de l'éditeur
5698
5768
  if (content === editor.getHTML())
5699
5769
  return;
5700
- // Ne pas écraser le contenu si on a un FormControl et que le content est vide
5770
+ // Do not overwrite content if we have a FormControl and content is empty
5701
5771
  if (hasFormControl && !content)
5702
5772
  return;
5703
5773
  editor.commands.setContent(content, false);
5704
5774
  });
5705
5775
  });
5706
- // Effet pour mettre à jour les propriétés de hauteur
5776
+ // Effect to update height properties
5707
5777
  effect(() => {
5708
5778
  const minHeight = this.minHeight();
5709
5779
  const height = this.height();
5710
5780
  const maxHeight = this.maxHeight();
5711
5781
  const element = this.editorElement()?.nativeElement;
5712
- // Calculer automatiquement si le scroll est nécessaire
5782
+ // Automatically calculate if scroll is needed
5713
5783
  const needsScroll = height !== undefined || maxHeight !== undefined;
5714
5784
  if (element) {
5715
5785
  element.style.setProperty("--editor-min-height", `${minHeight}px`);
@@ -5721,7 +5791,10 @@ class AngularTiptapEditorComponent {
5721
5791
  // Effect to monitor editability changes
5722
5792
  effect(() => {
5723
5793
  const currentEditor = this.editor();
5724
- const isEditable = this.editable();
5794
+ // An editor is "editable" if it's not disabled and editable mode is ON
5795
+ const isEditable = this.editable() && !this.mergedDisabled();
5796
+ // An editor is "readonly" if it's explicitly non-editable and not disabled
5797
+ const isReadOnly = !this.editable() && !this.mergedDisabled();
5725
5798
  if (currentEditor) {
5726
5799
  this.editorCommandsService.setEditable(currentEditor, isEditable);
5727
5800
  }
@@ -5731,13 +5804,6 @@ class AngularTiptapEditorComponent {
5731
5804
  const handler = this.imageUploadHandler();
5732
5805
  this.editorCommandsService.uploadHandler = handler || null;
5733
5806
  });
5734
- // Effect for table hover detection
5735
- effect(() => {
5736
- const currentEditor = this.editor();
5737
- if (!currentEditor)
5738
- return;
5739
- // Table hover detection removed (replaced by bubble menu)
5740
- });
5741
5807
  // Effect to update character count limit dynamically
5742
5808
  effect(() => {
5743
5809
  const editor = this.editor();
@@ -5789,6 +5855,7 @@ class AngularTiptapEditorComponent {
5789
5855
  class: "tiptap-link",
5790
5856
  },
5791
5857
  }),
5858
+ LinkClickBehavior,
5792
5859
  Highlight.configure({
5793
5860
  multicolor: true,
5794
5861
  HTMLAttributes: {
@@ -5853,7 +5920,7 @@ class AngularTiptapEditorComponent {
5853
5920
  element: this.editorElement().nativeElement,
5854
5921
  extensions,
5855
5922
  content: this.content(),
5856
- editable: this.editable(),
5923
+ editable: this.editable() && !this.mergedDisabled(),
5857
5924
  autofocus: this.autofocus(),
5858
5925
  onUpdate: ({ editor, transaction }) => {
5859
5926
  const html = editor.getHTML();
@@ -5973,6 +6040,7 @@ class AngularTiptapEditorComponent {
5973
6040
  setupFormControlSubscription() {
5974
6041
  const control = this.ngControl?.control;
5975
6042
  if (control) {
6043
+ // Synchronize form control value with editor content
5976
6044
  const formValue$ = concat(defer(() => of(control.value)), control.valueChanges);
5977
6045
  formValue$
5978
6046
  .pipe(tap((value) => {
@@ -5982,25 +6050,25 @@ class AngularTiptapEditorComponent {
5982
6050
  }
5983
6051
  }), takeUntilDestroyed(this._destroyRef))
5984
6052
  .subscribe();
5985
- }
5986
- }
5987
- // Méthode pour gérer l'état disabled
5988
- setDisabledState(isDisabled) {
5989
- const currentEditor = this.editor();
5990
- if (currentEditor) {
5991
- this.editorCommandsService.setEditable(currentEditor, !isDisabled);
6053
+ // Synchronize form control status with editor disabled state
6054
+ const formStatus$ = concat(defer(() => of(control.status)), control.statusChanges);
6055
+ formStatus$
6056
+ .pipe(tap((status) => {
6057
+ this._isFormControlDisabled.set(status === 'DISABLED');
6058
+ }), takeUntilDestroyed(this._destroyRef))
6059
+ .subscribe();
5992
6060
  }
5993
6061
  }
5994
6062
  onEditorClick(event) {
5995
6063
  const editor = this.editor();
5996
- if (!editor)
6064
+ if (!editor || !this.editable())
5997
6065
  return;
5998
- // Vérifier si on clique sur l'élément conteneur et non sur le contenu
6066
+ // Verify if click is on the container element and not on the content
5999
6067
  const target = event.target;
6000
6068
  const editorElement = this.editorElement()?.nativeElement;
6001
6069
  if (target === editorElement ||
6002
6070
  target.classList.contains("tiptap-content")) {
6003
- // On clique dans l'espace vide, positionner le curseur à la fin
6071
+ // Click in the empty space, position the cursor at the end
6004
6072
  setTimeout(() => {
6005
6073
  const { doc } = editor.state;
6006
6074
  const endPos = doc.content.size;
@@ -6010,20 +6078,20 @@ class AngularTiptapEditorComponent {
6010
6078
  }
6011
6079
  }
6012
6080
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: AngularTiptapEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6013
- 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 }, showWordCount: { classPropertyName: "showWordCount", publicName: "showWordCount", 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 }, stateCalculators: { classPropertyName: "stateCalculators", publicName: "stateCalculators", 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()" } }, providers: [
6081
+ 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", 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 }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCharacterCount: { classPropertyName: "showCharacterCount", publicName: "showCharacterCount", isSignal: true, isRequired: false, transformFunction: null }, showWordCount: { classPropertyName: "showWordCount", publicName: "showWordCount", 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 }, seamless: { classPropertyName: "seamless", publicName: "seamless", isSignal: true, isRequired: false, transformFunction: null }, floatingToolbar: { classPropertyName: "floatingToolbar", publicName: "floatingToolbar", 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 }, showTableBubbleMenu: { classPropertyName: "showTableBubbleMenu", publicName: "showTableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, tableBubbleMenu: { classPropertyName: "tableBubbleMenu", publicName: "tableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showCellBubbleMenu: { classPropertyName: "showCellBubbleMenu", publicName: "showCellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, cellBubbleMenu: { classPropertyName: "cellBubbleMenu", publicName: "cellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, stateCalculators: { classPropertyName: "stateCalculators", publicName: "stateCalculators", 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()", "class.floating-toolbar": "floatingToolbar()", "class.is-readonly": "!editable() && !mergedDisabled()", "class.is-disabled": "mergedDisabled()", "style.--ate-border-width": "seamless() || mergedDisabled() ? '0' : null", "style.--ate-background": "seamless() ? 'transparent' : (mergedDisabled() ? 'var(--ate-surface-tertiary)' : null)", "style.--ate-toolbar-border-color": "seamless() ? 'transparent' : null", "style.--ate-counter-background": "seamless() ? 'transparent' : null", "style.--ate-counter-border-color": "seamless() ? 'transparent' : null" } }, providers: [
6014
6082
  EditorCommandsService,
6015
6083
  ImageService,
6016
- TiptapI18nService,
6017
6084
  ColorPickerService,
6018
6085
  LinkService,
6019
6086
  ], viewQueries: [{ propertyName: "editorElement", first: true, predicate: ["editorElement"], descendants: true, isSignal: true }], hostDirectives: [{ directive: NoopValueAccessorDirective }], ngImport: i0, template: `
6020
- <div class="tiptap-editor" [class.fill-container]="fillContainer()">
6087
+ <div class="tiptap-editor">
6021
6088
  <!-- Toolbar -->
6022
- @if (showToolbar() && editor()) {
6089
+ @if (editable() && !mergedDisabled() && showToolbar() && editor()) {
6023
6090
  <tiptap-toolbar
6024
6091
  [editor]="editor()!"
6025
6092
  [config]="toolbarConfig()"
6026
6093
  [imageUpload]="imageUploadConfig()"
6094
+ [floating]="floatingToolbar()"
6027
6095
  (mouseenter)="hideBubbleMenus()"
6028
6096
  (mouseleave)="showBubbleMenus()"
6029
6097
  />
@@ -6040,7 +6108,7 @@ class AngularTiptapEditorComponent {
6040
6108
  ></div>
6041
6109
 
6042
6110
  <!-- Text Bubble Menu -->
6043
- @if (showBubbleMenu() && editor()) {
6111
+ @if (editable() && showBubbleMenu() && editor()) {
6044
6112
  <tiptap-bubble-menu
6045
6113
  [editor]="editor()!"
6046
6114
  [config]="bubbleMenuConfig()"
@@ -6049,7 +6117,7 @@ class AngularTiptapEditorComponent {
6049
6117
  }
6050
6118
 
6051
6119
  <!-- Image Bubble Menu -->
6052
- @if (showImageBubbleMenu() && editor()) {
6120
+ @if (editable() && showImageBubbleMenu() && editor()) {
6053
6121
  <tiptap-image-bubble-menu
6054
6122
  [editor]="editor()!"
6055
6123
  [config]="imageBubbleMenuConfig()"
@@ -6058,7 +6126,7 @@ class AngularTiptapEditorComponent {
6058
6126
  }
6059
6127
 
6060
6128
  <!-- Link Bubble Menu -->
6061
- @if (editor()) {
6129
+ @if (editable() && editor()) {
6062
6130
  <tiptap-link-bubble-menu
6063
6131
  [editor]="editor()!"
6064
6132
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6066,7 +6134,7 @@ class AngularTiptapEditorComponent {
6066
6134
  }
6067
6135
 
6068
6136
  <!-- Color Bubble Menu -->
6069
- @if (editor()) {
6137
+ @if (editable() && editor()) {
6070
6138
  <tiptap-color-bubble-menu
6071
6139
  [editor]="editor()!"
6072
6140
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6074,7 +6142,7 @@ class AngularTiptapEditorComponent {
6074
6142
  }
6075
6143
 
6076
6144
  <!-- Slash Commands -->
6077
- @if (enableSlashCommands() && editor()) {
6145
+ @if (editable() && enableSlashCommands() && editor()) {
6078
6146
  <tiptap-slash-commands
6079
6147
  [editor]="editor()!"
6080
6148
  [config]="slashCommandsConfigComputed()"
@@ -6083,7 +6151,7 @@ class AngularTiptapEditorComponent {
6083
6151
  }
6084
6152
 
6085
6153
  <!-- Table Menu -->
6086
- @if (editor()) {
6154
+ @if (editable() && editor()) {
6087
6155
  <tiptap-table-bubble-menu
6088
6156
  [editor]="editor()!"
6089
6157
  [config]="tableBubbleMenuConfig()"
@@ -6092,7 +6160,7 @@ class AngularTiptapEditorComponent {
6092
6160
  }
6093
6161
 
6094
6162
  <!-- Cell Menu -->
6095
- @if (editor()) {
6163
+ @if (editable() && editor()) {
6096
6164
  <tiptap-cell-bubble-menu
6097
6165
  [editor]="editor()!"
6098
6166
  [config]="cellBubbleMenuConfig()"
@@ -6101,11 +6169,11 @@ class AngularTiptapEditorComponent {
6101
6169
  }
6102
6170
 
6103
6171
  <!-- Counters -->
6104
- @if (showCharacterCount() || showWordCount()) {
6172
+ @if (editable() && !mergedDisabled() && showFooter() && (showCharacterCount() || showWordCount())) {
6105
6173
  <div class="character-count" [class.limit-reached]="maxCharacters() && characterCount() >= maxCharacters()!">
6106
6174
  @if (showCharacterCount()) {
6107
6175
  {{ characterCount() }}
6108
- {{ i18nService.editor().character }}{{ characterCount() > 1 ? "s" : "" }}
6176
+ {{ currentTranslations().editor.character }}{{ characterCount() > 1 ? "s" : "" }}
6109
6177
  @if (maxCharacters()) {
6110
6178
  / {{ maxCharacters() }}
6111
6179
  }
@@ -6117,17 +6185,25 @@ class AngularTiptapEditorComponent {
6117
6185
 
6118
6186
  @if (showWordCount()) {
6119
6187
  {{ wordCount() }}
6120
- {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
6188
+ {{ currentTranslations().editor.word }}{{ wordCount() > 1 ? "s" : "" }}
6121
6189
  }
6122
6190
  </div>
6123
6191
  }
6124
6192
  </div>
6125
- `, 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;position:relative}.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);transition:color .2s ease;border-bottom-left-radius:calc(var(--ate-border-radius) - var(--ate-border-width));border-bottom-right-radius:calc(var(--ate-border-radius) - var(--ate-border-width))}.character-count.limit-reached{color:var(--ate-error-color, #ef4444);font-weight:600}: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;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"] }, { kind: "component", type: TiptapBubbleMenuComponent, selector: "tiptap-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapImageBubbleMenuComponent, selector: "tiptap-image-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapTableBubbleMenuComponent, selector: "tiptap-table-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapCellBubbleMenuComponent, selector: "tiptap-cell-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapSlashCommandsComponent, selector: "tiptap-slash-commands", inputs: ["editor", "config"] }, { kind: "component", type: TiptapLinkBubbleMenuComponent, selector: "tiptap-link-bubble-menu", inputs: ["editor"] }, { kind: "component", type: TiptapColorBubbleMenuComponent, selector: "tiptap-color-bubble-menu", inputs: ["editor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6193
+ `, 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-error-color: #c53030;--ate-error-bg: #fed7d7;--ate-error-border: #feb2b2;--ate-border-color: var(--ate-border);--ate-border-width: 2px;--ate-border-radius: 12px;--ate-focus-color: var(--ate-primary);--ate-background: var(--ate-surface);--ate-sub-border-radius: 8px;--ate-text-color: var(--ate-text);--ate-placeholder-color: var(--ate-text-muted);--ate-line-height: 1.6;--ate-content-padding: 16px;--ate-menu-bg: var(--ate-surface-secondary);--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-padding: 6px;--ate-toolbar-padding: var(--ate-menu-padding);--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-secondary);--ate-code-border-color: var(--ate-border);--ate-code-block-background: #0f172a;--ate-code-block-color: #e2e8f0;--ate-code-block-border-color: var(--ate-border);--ate-image-border-radius: var(--ate-sub-border-radius);--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-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-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;position:relative}:host(.floating-toolbar) .tiptap-editor{overflow:visible}:host(.fill-container) .tiptap-editor{display:flex;flex-direction:column;height:100%}:host(.fill-container) .tiptap-content{flex:1;min-height:0;overflow-y:auto}.tiptap-editor:focus-within{border-color:var(--ate-focus-color)}.tiptap-content{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)}:host(.is-disabled) .tiptap-content{cursor:not-allowed;opacity:.7;-webkit-user-select:none;user-select:none;pointer-events:none;background-color:var(--ate-surface-tertiary)}:host(.is-readonly) .tiptap-content{cursor:default;-webkit-user-select:text;user-select:text}:host(.is-readonly) .tiptap-content ::ng-deep .tiptap-link{cursor:pointer;pointer-events:auto}.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);transition:color .2s ease;border-bottom-left-radius:calc(var(--ate-border-radius) - var(--ate-border-width));border-bottom-right-radius:calc(var(--ate-border-radius) - var(--ate-border-width))}.character-count.limit-reached{color:var(--ate-error-color, #ef4444);font-weight:600}:host ::ng-deep .ProseMirror{padding:var(--ate-content-padding);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;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:.15em .4em;border-radius:4px;font-family:JetBrains Mono,Fira Code,Monaco,Consolas,monospace;font-size:.85em;font-weight:500}: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:var(--ate-border-radius);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", "floating"] }, { kind: "component", type: TiptapBubbleMenuComponent, selector: "tiptap-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapImageBubbleMenuComponent, selector: "tiptap-image-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapTableBubbleMenuComponent, selector: "tiptap-table-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapCellBubbleMenuComponent, selector: "tiptap-cell-bubble-menu", inputs: ["config"] }, { kind: "component", type: TiptapSlashCommandsComponent, selector: "tiptap-slash-commands", inputs: ["editor", "config"] }, { kind: "component", type: TiptapLinkBubbleMenuComponent, selector: "tiptap-link-bubble-menu", inputs: ["editor"] }, { kind: "component", type: TiptapColorBubbleMenuComponent, selector: "tiptap-color-bubble-menu", inputs: ["editor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6126
6194
  }
6127
6195
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: AngularTiptapEditorComponent, decorators: [{
6128
6196
  type: Component,
6129
6197
  args: [{ selector: "angular-tiptap-editor", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [NoopValueAccessorDirective], host: {
6130
6198
  '[class.fill-container]': 'fillContainer()',
6199
+ '[class.floating-toolbar]': 'floatingToolbar()',
6200
+ '[class.is-readonly]': '!editable() && !mergedDisabled()',
6201
+ '[class.is-disabled]': 'mergedDisabled()',
6202
+ '[style.--ate-border-width]': "seamless() || mergedDisabled() ? '0' : null",
6203
+ '[style.--ate-background]': "seamless() ? 'transparent' : (mergedDisabled() ? 'var(--ate-surface-tertiary)' : null)",
6204
+ '[style.--ate-toolbar-border-color]': "seamless() ? 'transparent' : null",
6205
+ '[style.--ate-counter-background]': "seamless() ? 'transparent' : null",
6206
+ '[style.--ate-counter-border-color]': "seamless() ? 'transparent' : null",
6131
6207
  }, imports: [
6132
6208
  TiptapToolbarComponent,
6133
6209
  TiptapBubbleMenuComponent,
@@ -6140,17 +6216,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6140
6216
  ], providers: [
6141
6217
  EditorCommandsService,
6142
6218
  ImageService,
6143
- TiptapI18nService,
6144
6219
  ColorPickerService,
6145
6220
  LinkService,
6146
6221
  ], template: `
6147
- <div class="tiptap-editor" [class.fill-container]="fillContainer()">
6222
+ <div class="tiptap-editor">
6148
6223
  <!-- Toolbar -->
6149
- @if (showToolbar() && editor()) {
6224
+ @if (editable() && !mergedDisabled() && showToolbar() && editor()) {
6150
6225
  <tiptap-toolbar
6151
6226
  [editor]="editor()!"
6152
6227
  [config]="toolbarConfig()"
6153
6228
  [imageUpload]="imageUploadConfig()"
6229
+ [floating]="floatingToolbar()"
6154
6230
  (mouseenter)="hideBubbleMenus()"
6155
6231
  (mouseleave)="showBubbleMenus()"
6156
6232
  />
@@ -6167,7 +6243,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6167
6243
  ></div>
6168
6244
 
6169
6245
  <!-- Text Bubble Menu -->
6170
- @if (showBubbleMenu() && editor()) {
6246
+ @if (editable() && showBubbleMenu() && editor()) {
6171
6247
  <tiptap-bubble-menu
6172
6248
  [editor]="editor()!"
6173
6249
  [config]="bubbleMenuConfig()"
@@ -6176,7 +6252,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6176
6252
  }
6177
6253
 
6178
6254
  <!-- Image Bubble Menu -->
6179
- @if (showImageBubbleMenu() && editor()) {
6255
+ @if (editable() && showImageBubbleMenu() && editor()) {
6180
6256
  <tiptap-image-bubble-menu
6181
6257
  [editor]="editor()!"
6182
6258
  [config]="imageBubbleMenuConfig()"
@@ -6185,7 +6261,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6185
6261
  }
6186
6262
 
6187
6263
  <!-- Link Bubble Menu -->
6188
- @if (editor()) {
6264
+ @if (editable() && editor()) {
6189
6265
  <tiptap-link-bubble-menu
6190
6266
  [editor]="editor()!"
6191
6267
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6193,7 +6269,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6193
6269
  }
6194
6270
 
6195
6271
  <!-- Color Bubble Menu -->
6196
- @if (editor()) {
6272
+ @if (editable() && editor()) {
6197
6273
  <tiptap-color-bubble-menu
6198
6274
  [editor]="editor()!"
6199
6275
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6201,7 +6277,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6201
6277
  }
6202
6278
 
6203
6279
  <!-- Slash Commands -->
6204
- @if (enableSlashCommands() && editor()) {
6280
+ @if (editable() && enableSlashCommands() && editor()) {
6205
6281
  <tiptap-slash-commands
6206
6282
  [editor]="editor()!"
6207
6283
  [config]="slashCommandsConfigComputed()"
@@ -6210,7 +6286,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6210
6286
  }
6211
6287
 
6212
6288
  <!-- Table Menu -->
6213
- @if (editor()) {
6289
+ @if (editable() && editor()) {
6214
6290
  <tiptap-table-bubble-menu
6215
6291
  [editor]="editor()!"
6216
6292
  [config]="tableBubbleMenuConfig()"
@@ -6219,7 +6295,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6219
6295
  }
6220
6296
 
6221
6297
  <!-- Cell Menu -->
6222
- @if (editor()) {
6298
+ @if (editable() && editor()) {
6223
6299
  <tiptap-cell-bubble-menu
6224
6300
  [editor]="editor()!"
6225
6301
  [config]="cellBubbleMenuConfig()"
@@ -6228,11 +6304,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6228
6304
  }
6229
6305
 
6230
6306
  <!-- Counters -->
6231
- @if (showCharacterCount() || showWordCount()) {
6307
+ @if (editable() && !mergedDisabled() && showFooter() && (showCharacterCount() || showWordCount())) {
6232
6308
  <div class="character-count" [class.limit-reached]="maxCharacters() && characterCount() >= maxCharacters()!">
6233
6309
  @if (showCharacterCount()) {
6234
6310
  {{ characterCount() }}
6235
- {{ i18nService.editor().character }}{{ characterCount() > 1 ? "s" : "" }}
6311
+ {{ currentTranslations().editor.character }}{{ characterCount() > 1 ? "s" : "" }}
6236
6312
  @if (maxCharacters()) {
6237
6313
  / {{ maxCharacters() }}
6238
6314
  }
@@ -6244,12 +6320,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6244
6320
 
6245
6321
  @if (showWordCount()) {
6246
6322
  {{ wordCount() }}
6247
- {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
6323
+ {{ currentTranslations().editor.word }}{{ wordCount() > 1 ? "s" : "" }}
6248
6324
  }
6249
6325
  </div>
6250
6326
  }
6251
6327
  </div>
6252
- `, 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;position:relative}.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);transition:color .2s ease;border-bottom-left-radius:calc(var(--ate-border-radius) - var(--ate-border-width));border-bottom-right-radius:calc(var(--ate-border-radius) - var(--ate-border-width))}.character-count.limit-reached{color:var(--ate-error-color, #ef4444);font-weight:600}: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;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"] }]
6328
+ `, 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-error-color: #c53030;--ate-error-bg: #fed7d7;--ate-error-border: #feb2b2;--ate-border-color: var(--ate-border);--ate-border-width: 2px;--ate-border-radius: 12px;--ate-focus-color: var(--ate-primary);--ate-background: var(--ate-surface);--ate-sub-border-radius: 8px;--ate-text-color: var(--ate-text);--ate-placeholder-color: var(--ate-text-muted);--ate-line-height: 1.6;--ate-content-padding: 16px;--ate-menu-bg: var(--ate-surface-secondary);--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-padding: 6px;--ate-toolbar-padding: var(--ate-menu-padding);--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-secondary);--ate-code-border-color: var(--ate-border);--ate-code-block-background: #0f172a;--ate-code-block-color: #e2e8f0;--ate-code-block-border-color: var(--ate-border);--ate-image-border-radius: var(--ate-sub-border-radius);--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-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-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;position:relative}:host(.floating-toolbar) .tiptap-editor{overflow:visible}:host(.fill-container) .tiptap-editor{display:flex;flex-direction:column;height:100%}:host(.fill-container) .tiptap-content{flex:1;min-height:0;overflow-y:auto}.tiptap-editor:focus-within{border-color:var(--ate-focus-color)}.tiptap-content{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)}:host(.is-disabled) .tiptap-content{cursor:not-allowed;opacity:.7;-webkit-user-select:none;user-select:none;pointer-events:none;background-color:var(--ate-surface-tertiary)}:host(.is-readonly) .tiptap-content{cursor:default;-webkit-user-select:text;user-select:text}:host(.is-readonly) .tiptap-content ::ng-deep .tiptap-link{cursor:pointer;pointer-events:auto}.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);transition:color .2s ease;border-bottom-left-radius:calc(var(--ate-border-radius) - var(--ate-border-width));border-bottom-right-radius:calc(var(--ate-border-radius) - var(--ate-border-width))}.character-count.limit-reached{color:var(--ate-error-color, #ef4444);font-weight:600}:host ::ng-deep .ProseMirror{padding:var(--ate-content-padding);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;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:.15em .4em;border-radius:4px;font-family:JetBrains Mono,Fira Code,Monaco,Consolas,monospace;font-size:.85em;font-weight:500}: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:var(--ate-border-radius);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"] }]
6253
6329
  }], ctorParameters: () => [] });
6254
6330
 
6255
6331
  /*