@flogeez/angular-tiptap-editor 0.6.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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-button-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-button-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-button-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-button-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: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 }); }
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: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"] }]
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,6 +5604,7 @@ 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);
@@ -5557,6 +5619,8 @@ class AngularTiptapEditorComponent {
5557
5619
  this.customSlashCommands = input(undefined);
5558
5620
  this.locale = input(undefined);
5559
5621
  this.autofocus = input(false);
5622
+ this.seamless = input(false);
5623
+ this.floatingToolbar = input(false);
5560
5624
  this.tiptapExtensions = input([]);
5561
5625
  this.tiptapOptions = input({});
5562
5626
  // Nouveaux inputs pour les bubble menus
@@ -5564,8 +5628,13 @@ class AngularTiptapEditorComponent {
5564
5628
  this.bubbleMenu = input(DEFAULT_BUBBLE_MENU_CONFIG);
5565
5629
  this.showImageBubbleMenu = input(true);
5566
5630
  this.imageBubbleMenu = input(DEFAULT_IMAGE_BUBBLE_MENU_CONFIG);
5567
- // Nouveau input pour la configuration de la toolbar
5631
+ // Configuration de la toolbar
5568
5632
  this.toolbar = input({});
5633
+ // Configuration des menus de table
5634
+ this.showTableBubbleMenu = input(true);
5635
+ this.tableBubbleMenu = input(DEFAULT_TABLE_MENU_CONFIG);
5636
+ this.showCellBubbleMenu = input(true);
5637
+ this.cellBubbleMenu = input(DEFAULT_CELL_MENU_CONFIG);
5569
5638
  /**
5570
5639
  * Additionnal state calculators to extend the reactive editor state.
5571
5640
  */
@@ -5598,9 +5667,9 @@ class AngularTiptapEditorComponent {
5598
5667
  this.editorUpdate = output();
5599
5668
  this.editorFocus = output();
5600
5669
  this.editorBlur = output();
5601
- // ViewChild avec signal
5670
+ // ViewChild with signal
5602
5671
  this.editorElement = viewChild.required("editorElement");
5603
- // Signals privés pour l'état interne
5672
+ // Private signals for internal state
5604
5673
  this._editor = signal(null);
5605
5674
  this._characterCount = signal(0);
5606
5675
  this._wordCount = signal(0);
@@ -5608,44 +5677,39 @@ class AngularTiptapEditorComponent {
5608
5677
  this._editorFullyInitialized = signal(false);
5609
5678
  // Anti-echo: track last emitted HTML to prevent cursor reset on parent echo
5610
5679
  this.lastEmittedHtml = null;
5611
- // Accès en lecture seule aux signaux
5680
+ // Read-only access to signals
5612
5681
  this.editor = this._editor.asReadonly();
5613
5682
  this.characterCount = this._characterCount.asReadonly();
5614
5683
  this.wordCount = this._wordCount.asReadonly();
5615
5684
  this.isDragOver = this._isDragOver.asReadonly();
5616
5685
  this.editorFullyInitialized = this._editorFullyInitialized.asReadonly();
5617
- // Computed pour les états de l'éditeur
5686
+ this._isFormControlDisabled = signal(false);
5687
+ this.isFormControlDisabled = this._isFormControlDisabled.asReadonly();
5688
+ // Combined disabled state (Input + FormControl)
5689
+ this.mergedDisabled = computed(() => this.disabled() || this.isFormControlDisabled());
5690
+ // Computed for editor states
5618
5691
  this.isEditorReady = computed(() => this.editor() !== null);
5619
- // Computed pour la configuration de la toolbar
5692
+ // Computed for toolbar configuration
5620
5693
  this.toolbarConfig = computed(() => Object.keys(this.toolbar()).length === 0
5621
5694
  ? DEFAULT_TOOLBAR_CONFIG
5622
5695
  : this.toolbar());
5623
- // Computed pour la configuration du bubble menu
5696
+ // Computed for bubble menu configuration
5624
5697
  this.bubbleMenuConfig = computed(() => Object.keys(this.bubbleMenu()).length === 0
5625
5698
  ? DEFAULT_BUBBLE_MENU_CONFIG
5626
5699
  : { ...DEFAULT_BUBBLE_MENU_CONFIG, ...this.bubbleMenu() });
5627
- // Computed pour la configuration du bubble menu image
5700
+ // Computed for image bubble menu configuration
5628
5701
  this.imageBubbleMenuConfig = computed(() => Object.keys(this.imageBubbleMenu()).length === 0
5629
5702
  ? DEFAULT_IMAGE_BUBBLE_MENU_CONFIG
5630
5703
  : { ...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
5704
+ // Computed for table bubble menu configuration
5705
+ this.tableBubbleMenuConfig = computed(() => Object.keys(this.tableBubbleMenu()).length === 0
5706
+ ? DEFAULT_TABLE_MENU_CONFIG
5707
+ : { ...DEFAULT_TABLE_MENU_CONFIG, ...this.tableBubbleMenu() });
5708
+ // Computed for cell bubble menu configuration
5709
+ this.cellBubbleMenuConfig = computed(() => Object.keys(this.cellBubbleMenu()).length === 0
5710
+ ? DEFAULT_CELL_MENU_CONFIG
5711
+ : { ...DEFAULT_CELL_MENU_CONFIG, ...this.cellBubbleMenu() });
5712
+ // Computed for image upload configuration
5649
5713
  this.imageUploadConfig = computed(() => ({
5650
5714
  maxSize: 5,
5651
5715
  maxWidth: 1920,
@@ -5658,7 +5722,7 @@ class AngularTiptapEditorComponent {
5658
5722
  quality: 0.8,
5659
5723
  ...this.imageUpload(),
5660
5724
  }));
5661
- // Computed pour la configuration des slash commands
5725
+ // Computed for slash commands configuration
5662
5726
  this.slashCommandsConfigComputed = computed(() => {
5663
5727
  const customConfig = this.customSlashCommands();
5664
5728
  if (customConfig) {
@@ -5670,22 +5734,27 @@ class AngularTiptapEditorComponent {
5670
5734
  commands: filterSlashCommands(this.slashCommands(), this.i18nService, this.editorCommandsService, this.imageUploadConfig()),
5671
5735
  };
5672
5736
  });
5737
+ // Computed for current translations (allows per-instance override via [locale] input)
5738
+ this.currentTranslations = computed(() => {
5739
+ const localeOverride = this.locale();
5740
+ if (localeOverride) {
5741
+ // If a specific language is provided to this instance, try to retrieve it
5742
+ const allTranslations = this.i18nService.allTranslations();
5743
+ return allTranslations[localeOverride] || this.i18nService.translations();
5744
+ }
5745
+ // Otherwise, follow the global service language
5746
+ return this.i18nService.translations();
5747
+ });
5673
5748
  this._destroyRef = inject(DestroyRef);
5674
- // NgControl pour gérer les FormControls
5749
+ // NgControl for management of FormControls
5675
5750
  this.ngControl = inject(NgControl, { self: true, optional: true });
5676
5751
  this.i18nService = inject(TiptapI18nService);
5677
5752
  this.editorCommandsService = inject(EditorCommandsService);
5753
+ // Access editor state via service
5678
5754
  this.editorState = this.editorCommandsService.editorState;
5679
- // Effet pour gérer le changement de langue
5755
+ // Effect to update editor content (with anti-echo)
5680
5756
  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
5757
+ const content = this.content(); // Sole reactive dependency
5689
5758
  untracked(() => {
5690
5759
  const editor = this.editor();
5691
5760
  const hasFormControl = !!this.ngControl?.control;
@@ -5697,19 +5766,19 @@ class AngularTiptapEditorComponent {
5697
5766
  // Double sécurité : on vérifie le contenu actuel de l'éditeur
5698
5767
  if (content === editor.getHTML())
5699
5768
  return;
5700
- // Ne pas écraser le contenu si on a un FormControl et que le content est vide
5769
+ // Do not overwrite content if we have a FormControl and content is empty
5701
5770
  if (hasFormControl && !content)
5702
5771
  return;
5703
5772
  editor.commands.setContent(content, false);
5704
5773
  });
5705
5774
  });
5706
- // Effet pour mettre à jour les propriétés de hauteur
5775
+ // Effect to update height properties
5707
5776
  effect(() => {
5708
5777
  const minHeight = this.minHeight();
5709
5778
  const height = this.height();
5710
5779
  const maxHeight = this.maxHeight();
5711
5780
  const element = this.editorElement()?.nativeElement;
5712
- // Calculer automatiquement si le scroll est nécessaire
5781
+ // Automatically calculate if scroll is needed
5713
5782
  const needsScroll = height !== undefined || maxHeight !== undefined;
5714
5783
  if (element) {
5715
5784
  element.style.setProperty("--editor-min-height", `${minHeight}px`);
@@ -5721,7 +5790,10 @@ class AngularTiptapEditorComponent {
5721
5790
  // Effect to monitor editability changes
5722
5791
  effect(() => {
5723
5792
  const currentEditor = this.editor();
5724
- const isEditable = this.editable();
5793
+ // An editor is "editable" if it's not disabled and editable mode is ON
5794
+ const isEditable = this.editable() && !this.mergedDisabled();
5795
+ // An editor is "readonly" if it's explicitly non-editable and not disabled
5796
+ const isReadOnly = !this.editable() && !this.mergedDisabled();
5725
5797
  if (currentEditor) {
5726
5798
  this.editorCommandsService.setEditable(currentEditor, isEditable);
5727
5799
  }
@@ -5731,13 +5803,6 @@ class AngularTiptapEditorComponent {
5731
5803
  const handler = this.imageUploadHandler();
5732
5804
  this.editorCommandsService.uploadHandler = handler || null;
5733
5805
  });
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
5806
  // Effect to update character count limit dynamically
5742
5807
  effect(() => {
5743
5808
  const editor = this.editor();
@@ -5789,6 +5854,7 @@ class AngularTiptapEditorComponent {
5789
5854
  class: "tiptap-link",
5790
5855
  },
5791
5856
  }),
5857
+ LinkClickBehavior,
5792
5858
  Highlight.configure({
5793
5859
  multicolor: true,
5794
5860
  HTMLAttributes: {
@@ -5853,7 +5919,7 @@ class AngularTiptapEditorComponent {
5853
5919
  element: this.editorElement().nativeElement,
5854
5920
  extensions,
5855
5921
  content: this.content(),
5856
- editable: this.editable(),
5922
+ editable: this.editable() && !this.mergedDisabled(),
5857
5923
  autofocus: this.autofocus(),
5858
5924
  onUpdate: ({ editor, transaction }) => {
5859
5925
  const html = editor.getHTML();
@@ -5973,6 +6039,7 @@ class AngularTiptapEditorComponent {
5973
6039
  setupFormControlSubscription() {
5974
6040
  const control = this.ngControl?.control;
5975
6041
  if (control) {
6042
+ // Synchronize form control value with editor content
5976
6043
  const formValue$ = concat(defer(() => of(control.value)), control.valueChanges);
5977
6044
  formValue$
5978
6045
  .pipe(tap((value) => {
@@ -5982,25 +6049,25 @@ class AngularTiptapEditorComponent {
5982
6049
  }
5983
6050
  }), takeUntilDestroyed(this._destroyRef))
5984
6051
  .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);
6052
+ // Synchronize form control status with editor disabled state
6053
+ const formStatus$ = concat(defer(() => of(control.status)), control.statusChanges);
6054
+ formStatus$
6055
+ .pipe(tap((status) => {
6056
+ this._isFormControlDisabled.set(status === 'DISABLED');
6057
+ }), takeUntilDestroyed(this._destroyRef))
6058
+ .subscribe();
5992
6059
  }
5993
6060
  }
5994
6061
  onEditorClick(event) {
5995
6062
  const editor = this.editor();
5996
- if (!editor)
6063
+ if (!editor || !this.editable())
5997
6064
  return;
5998
- // Vérifier si on clique sur l'élément conteneur et non sur le contenu
6065
+ // Verify if click is on the container element and not on the content
5999
6066
  const target = event.target;
6000
6067
  const editorElement = this.editorElement()?.nativeElement;
6001
6068
  if (target === editorElement ||
6002
6069
  target.classList.contains("tiptap-content")) {
6003
- // On clique dans l'espace vide, positionner le curseur à la fin
6070
+ // Click in the empty space, position the cursor at the end
6004
6071
  setTimeout(() => {
6005
6072
  const { doc } = editor.state;
6006
6073
  const endPos = doc.content.size;
@@ -6010,20 +6077,20 @@ class AngularTiptapEditorComponent {
6010
6077
  }
6011
6078
  }
6012
6079
  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: [
6080
+ 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 }, 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
6081
  EditorCommandsService,
6015
6082
  ImageService,
6016
- TiptapI18nService,
6017
6083
  ColorPickerService,
6018
6084
  LinkService,
6019
6085
  ], 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()">
6086
+ <div class="tiptap-editor">
6021
6087
  <!-- Toolbar -->
6022
- @if (showToolbar() && editor()) {
6088
+ @if (editable() && !mergedDisabled() && showToolbar() && editor()) {
6023
6089
  <tiptap-toolbar
6024
6090
  [editor]="editor()!"
6025
6091
  [config]="toolbarConfig()"
6026
6092
  [imageUpload]="imageUploadConfig()"
6093
+ [floating]="floatingToolbar()"
6027
6094
  (mouseenter)="hideBubbleMenus()"
6028
6095
  (mouseleave)="showBubbleMenus()"
6029
6096
  />
@@ -6040,7 +6107,7 @@ class AngularTiptapEditorComponent {
6040
6107
  ></div>
6041
6108
 
6042
6109
  <!-- Text Bubble Menu -->
6043
- @if (showBubbleMenu() && editor()) {
6110
+ @if (editable() && showBubbleMenu() && editor()) {
6044
6111
  <tiptap-bubble-menu
6045
6112
  [editor]="editor()!"
6046
6113
  [config]="bubbleMenuConfig()"
@@ -6049,7 +6116,7 @@ class AngularTiptapEditorComponent {
6049
6116
  }
6050
6117
 
6051
6118
  <!-- Image Bubble Menu -->
6052
- @if (showImageBubbleMenu() && editor()) {
6119
+ @if (editable() && showImageBubbleMenu() && editor()) {
6053
6120
  <tiptap-image-bubble-menu
6054
6121
  [editor]="editor()!"
6055
6122
  [config]="imageBubbleMenuConfig()"
@@ -6058,7 +6125,7 @@ class AngularTiptapEditorComponent {
6058
6125
  }
6059
6126
 
6060
6127
  <!-- Link Bubble Menu -->
6061
- @if (editor()) {
6128
+ @if (editable() && editor()) {
6062
6129
  <tiptap-link-bubble-menu
6063
6130
  [editor]="editor()!"
6064
6131
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6066,7 +6133,7 @@ class AngularTiptapEditorComponent {
6066
6133
  }
6067
6134
 
6068
6135
  <!-- Color Bubble Menu -->
6069
- @if (editor()) {
6136
+ @if (editable() && editor()) {
6070
6137
  <tiptap-color-bubble-menu
6071
6138
  [editor]="editor()!"
6072
6139
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6074,7 +6141,7 @@ class AngularTiptapEditorComponent {
6074
6141
  }
6075
6142
 
6076
6143
  <!-- Slash Commands -->
6077
- @if (enableSlashCommands() && editor()) {
6144
+ @if (editable() && enableSlashCommands() && editor()) {
6078
6145
  <tiptap-slash-commands
6079
6146
  [editor]="editor()!"
6080
6147
  [config]="slashCommandsConfigComputed()"
@@ -6083,7 +6150,7 @@ class AngularTiptapEditorComponent {
6083
6150
  }
6084
6151
 
6085
6152
  <!-- Table Menu -->
6086
- @if (editor()) {
6153
+ @if (editable() && editor()) {
6087
6154
  <tiptap-table-bubble-menu
6088
6155
  [editor]="editor()!"
6089
6156
  [config]="tableBubbleMenuConfig()"
@@ -6092,7 +6159,7 @@ class AngularTiptapEditorComponent {
6092
6159
  }
6093
6160
 
6094
6161
  <!-- Cell Menu -->
6095
- @if (editor()) {
6162
+ @if (editable() && editor()) {
6096
6163
  <tiptap-cell-bubble-menu
6097
6164
  [editor]="editor()!"
6098
6165
  [config]="cellBubbleMenuConfig()"
@@ -6101,11 +6168,11 @@ class AngularTiptapEditorComponent {
6101
6168
  }
6102
6169
 
6103
6170
  <!-- Counters -->
6104
- @if (showCharacterCount() || showWordCount()) {
6171
+ @if (editable() && !mergedDisabled() && (showCharacterCount() || showWordCount())) {
6105
6172
  <div class="character-count" [class.limit-reached]="maxCharacters() && characterCount() >= maxCharacters()!">
6106
6173
  @if (showCharacterCount()) {
6107
6174
  {{ characterCount() }}
6108
- {{ i18nService.editor().character }}{{ characterCount() > 1 ? "s" : "" }}
6175
+ {{ currentTranslations().editor.character }}{{ characterCount() > 1 ? "s" : "" }}
6109
6176
  @if (maxCharacters()) {
6110
6177
  / {{ maxCharacters() }}
6111
6178
  }
@@ -6117,17 +6184,25 @@ class AngularTiptapEditorComponent {
6117
6184
 
6118
6185
  @if (showWordCount()) {
6119
6186
  {{ wordCount() }}
6120
- {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
6187
+ {{ currentTranslations().editor.word }}{{ wordCount() > 1 ? "s" : "" }}
6121
6188
  }
6122
6189
  </div>
6123
6190
  }
6124
6191
  </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 }); }
6192
+ `, 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-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-border-radius: var(--ate-border-radius, 8px);--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: 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);--ate-button-border-radius: 8px}: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
6193
  }
6127
6194
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: AngularTiptapEditorComponent, decorators: [{
6128
6195
  type: Component,
6129
6196
  args: [{ selector: "angular-tiptap-editor", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [NoopValueAccessorDirective], host: {
6130
6197
  '[class.fill-container]': 'fillContainer()',
6198
+ '[class.floating-toolbar]': 'floatingToolbar()',
6199
+ '[class.is-readonly]': '!editable() && !mergedDisabled()',
6200
+ '[class.is-disabled]': 'mergedDisabled()',
6201
+ '[style.--ate-border-width]': "seamless() || mergedDisabled() ? '0' : null",
6202
+ '[style.--ate-background]': "seamless() ? 'transparent' : (mergedDisabled() ? 'var(--ate-surface-tertiary)' : null)",
6203
+ '[style.--ate-toolbar-border-color]': "seamless() ? 'transparent' : null",
6204
+ '[style.--ate-counter-background]': "seamless() ? 'transparent' : null",
6205
+ '[style.--ate-counter-border-color]': "seamless() ? 'transparent' : null",
6131
6206
  }, imports: [
6132
6207
  TiptapToolbarComponent,
6133
6208
  TiptapBubbleMenuComponent,
@@ -6140,17 +6215,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6140
6215
  ], providers: [
6141
6216
  EditorCommandsService,
6142
6217
  ImageService,
6143
- TiptapI18nService,
6144
6218
  ColorPickerService,
6145
6219
  LinkService,
6146
6220
  ], template: `
6147
- <div class="tiptap-editor" [class.fill-container]="fillContainer()">
6221
+ <div class="tiptap-editor">
6148
6222
  <!-- Toolbar -->
6149
- @if (showToolbar() && editor()) {
6223
+ @if (editable() && !mergedDisabled() && showToolbar() && editor()) {
6150
6224
  <tiptap-toolbar
6151
6225
  [editor]="editor()!"
6152
6226
  [config]="toolbarConfig()"
6153
6227
  [imageUpload]="imageUploadConfig()"
6228
+ [floating]="floatingToolbar()"
6154
6229
  (mouseenter)="hideBubbleMenus()"
6155
6230
  (mouseleave)="showBubbleMenus()"
6156
6231
  />
@@ -6167,7 +6242,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6167
6242
  ></div>
6168
6243
 
6169
6244
  <!-- Text Bubble Menu -->
6170
- @if (showBubbleMenu() && editor()) {
6245
+ @if (editable() && showBubbleMenu() && editor()) {
6171
6246
  <tiptap-bubble-menu
6172
6247
  [editor]="editor()!"
6173
6248
  [config]="bubbleMenuConfig()"
@@ -6176,7 +6251,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6176
6251
  }
6177
6252
 
6178
6253
  <!-- Image Bubble Menu -->
6179
- @if (showImageBubbleMenu() && editor()) {
6254
+ @if (editable() && showImageBubbleMenu() && editor()) {
6180
6255
  <tiptap-image-bubble-menu
6181
6256
  [editor]="editor()!"
6182
6257
  [config]="imageBubbleMenuConfig()"
@@ -6185,7 +6260,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6185
6260
  }
6186
6261
 
6187
6262
  <!-- Link Bubble Menu -->
6188
- @if (editor()) {
6263
+ @if (editable() && editor()) {
6189
6264
  <tiptap-link-bubble-menu
6190
6265
  [editor]="editor()!"
6191
6266
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6193,7 +6268,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6193
6268
  }
6194
6269
 
6195
6270
  <!-- Color Bubble Menu -->
6196
- @if (editor()) {
6271
+ @if (editable() && editor()) {
6197
6272
  <tiptap-color-bubble-menu
6198
6273
  [editor]="editor()!"
6199
6274
  [style.display]="editorFullyInitialized() ? 'block' : 'none'"
@@ -6201,7 +6276,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6201
6276
  }
6202
6277
 
6203
6278
  <!-- Slash Commands -->
6204
- @if (enableSlashCommands() && editor()) {
6279
+ @if (editable() && enableSlashCommands() && editor()) {
6205
6280
  <tiptap-slash-commands
6206
6281
  [editor]="editor()!"
6207
6282
  [config]="slashCommandsConfigComputed()"
@@ -6210,7 +6285,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6210
6285
  }
6211
6286
 
6212
6287
  <!-- Table Menu -->
6213
- @if (editor()) {
6288
+ @if (editable() && editor()) {
6214
6289
  <tiptap-table-bubble-menu
6215
6290
  [editor]="editor()!"
6216
6291
  [config]="tableBubbleMenuConfig()"
@@ -6219,7 +6294,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6219
6294
  }
6220
6295
 
6221
6296
  <!-- Cell Menu -->
6222
- @if (editor()) {
6297
+ @if (editable() && editor()) {
6223
6298
  <tiptap-cell-bubble-menu
6224
6299
  [editor]="editor()!"
6225
6300
  [config]="cellBubbleMenuConfig()"
@@ -6228,11 +6303,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6228
6303
  }
6229
6304
 
6230
6305
  <!-- Counters -->
6231
- @if (showCharacterCount() || showWordCount()) {
6306
+ @if (editable() && !mergedDisabled() && (showCharacterCount() || showWordCount())) {
6232
6307
  <div class="character-count" [class.limit-reached]="maxCharacters() && characterCount() >= maxCharacters()!">
6233
6308
  @if (showCharacterCount()) {
6234
6309
  {{ characterCount() }}
6235
- {{ i18nService.editor().character }}{{ characterCount() > 1 ? "s" : "" }}
6310
+ {{ currentTranslations().editor.character }}{{ characterCount() > 1 ? "s" : "" }}
6236
6311
  @if (maxCharacters()) {
6237
6312
  / {{ maxCharacters() }}
6238
6313
  }
@@ -6244,12 +6319,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImpor
6244
6319
 
6245
6320
  @if (showWordCount()) {
6246
6321
  {{ wordCount() }}
6247
- {{ i18nService.editor().word }}{{ wordCount() > 1 ? "s" : "" }}
6322
+ {{ currentTranslations().editor.word }}{{ wordCount() > 1 ? "s" : "" }}
6248
6323
  }
6249
6324
  </div>
6250
6325
  }
6251
6326
  </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"] }]
6327
+ `, 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-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-border-radius: var(--ate-border-radius, 8px);--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: 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);--ate-button-border-radius: 8px}: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
6328
  }], ctorParameters: () => [] });
6254
6329
 
6255
6330
  /*