@flogeez/angular-tiptap-editor 2.2.0 → 2.2.2

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, ChangeDetectionStrategy, Component, signal, computed, Injectable, inject, effect, ViewChild, Directive, viewChild, DestroyRef, untracked } from '@angular/core';
2
+ import { input, output, ChangeDetectionStrategy, Component, signal, computed, Injectable, inject, viewChild, effect, Directive, DestroyRef, untracked } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { Node as Node$1, nodeInputRule, mergeAttributes, Extension, getAttributes, Editor } from '@tiptap/core';
5
5
  import StarterKit from '@tiptap/starter-kit';
@@ -134,10 +134,12 @@ const AteResizableImage = Node$1.create({
134
134
  img.alt = node.attrs["alt"] || "";
135
135
  img.title = node.attrs["title"] || "";
136
136
  img.className = "ate-image";
137
- if (node.attrs["width"])
137
+ if (node.attrs["width"]) {
138
138
  img.width = node.attrs["width"];
139
- if (node.attrs["height"])
139
+ }
140
+ if (node.attrs["height"]) {
140
141
  img.height = node.attrs["height"];
142
+ }
141
143
  img.parentNode?.insertBefore(container, img);
142
144
  container.appendChild(img);
143
145
  // Add modern resize controls
@@ -173,13 +175,16 @@ const AteResizableImage = Node$1.create({
173
175
  startX = e.clientX;
174
176
  startY = e.clientY;
175
177
  // Use current image dimensions instead of initial ones
176
- startWidth = parseInt(img.getAttribute("width") || "0") || node.attrs["width"] || img.naturalWidth;
177
- startHeight = parseInt(img.getAttribute("height") || "0") || node.attrs["height"] || img.naturalHeight;
178
+ startWidth =
179
+ parseInt(img.getAttribute("width") || "0") || node.attrs["width"] || img.naturalWidth;
180
+ startHeight =
181
+ parseInt(img.getAttribute("height") || "0") || node.attrs["height"] || img.naturalHeight;
178
182
  // Add resizing class to body
179
183
  document.body.classList.add("resizing");
180
184
  const handleMouseMove = (e) => {
181
- if (!isResizing)
185
+ if (!isResizing) {
182
186
  return;
187
+ }
183
188
  const deltaX = e.clientX - startX;
184
189
  const deltaY = e.clientY - startY;
185
190
  let newWidth = startWidth;
@@ -272,15 +277,18 @@ const AteResizableImage = Node$1.create({
272
277
  selectNode,
273
278
  deselectNode,
274
279
  update: updatedNode => {
275
- if (updatedNode.type.name !== "resizableImage")
280
+ if (updatedNode.type.name !== "resizableImage") {
276
281
  return false;
282
+ }
277
283
  img.src = updatedNode.attrs["src"];
278
284
  img.alt = updatedNode.attrs["alt"] || "";
279
285
  img.title = updatedNode.attrs["title"] || "";
280
- if (updatedNode.attrs["width"])
286
+ if (updatedNode.attrs["width"]) {
281
287
  img.width = updatedNode.attrs["width"];
282
- if (updatedNode.attrs["height"])
288
+ }
289
+ if (updatedNode.attrs["height"]) {
283
290
  img.height = updatedNode.attrs["height"];
291
+ }
284
292
  return true;
285
293
  },
286
294
  };
@@ -600,14 +608,16 @@ const ATE_INITIAL_EDITOR_STATE = {
600
608
  */
601
609
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
602
610
  function fastMerge(target, source) {
603
- if (!source)
611
+ if (!source) {
604
612
  return;
613
+ }
605
614
  for (const key in source) {
606
615
  const sourceVal = source[key];
607
616
  // If the value is an object (marks, can, nodes, selection)
608
617
  if (sourceVal !== null && typeof sourceVal === "object" && !Array.isArray(sourceVal)) {
609
- if (!target[key])
618
+ if (!target[key]) {
610
619
  target[key] = {};
620
+ }
611
621
  // Merge internal properties
612
622
  for (const subKey in sourceVal) {
613
623
  const subVal = sourceVal[subKey];
@@ -644,8 +654,9 @@ const AteTiptapStateExtension = Extension.create({
644
654
  view: () => ({
645
655
  update: _view => {
646
656
  const { editor } = this;
647
- if (!editor)
657
+ if (!editor) {
648
658
  return;
659
+ }
649
660
  const snapshot = createFreshSnapshot();
650
661
  const calcs = this.options.calculators;
651
662
  for (const calculator of calcs) {
@@ -1246,14 +1257,20 @@ class AteImageService {
1246
1257
  updateImageAttributes(editor, attributes) {
1247
1258
  if (editor.isActive("resizableImage")) {
1248
1259
  const pos = editor.state.selection.from;
1249
- editor.chain().focus().updateAttributes("resizableImage", attributes).setNodeSelection(pos).run();
1260
+ editor
1261
+ .chain()
1262
+ .focus()
1263
+ .updateAttributes("resizableImage", attributes)
1264
+ .setNodeSelection(pos)
1265
+ .run();
1250
1266
  this.updateSelectedImage(attributes);
1251
1267
  }
1252
1268
  }
1253
1269
  /** Resize image with optional aspect ratio maintenance */
1254
1270
  resizeImage(editor, options) {
1255
- if (!editor.isActive("resizableImage"))
1271
+ if (!editor.isActive("resizableImage")) {
1256
1272
  return;
1273
+ }
1257
1274
  const currentAttrs = editor.getAttributes("resizableImage");
1258
1275
  let newWidth = options.width;
1259
1276
  let newHeight = options.height;
@@ -1268,10 +1285,12 @@ class AteImageService {
1268
1285
  }
1269
1286
  }
1270
1287
  // Apply minimum limits
1271
- if (newWidth)
1288
+ if (newWidth) {
1272
1289
  newWidth = Math.max(50, newWidth);
1273
- if (newHeight)
1290
+ }
1291
+ if (newHeight) {
1274
1292
  newHeight = Math.max(50, newHeight);
1293
+ }
1275
1294
  this.updateImageAttributes(editor, {
1276
1295
  width: newWidth,
1277
1296
  height: newHeight,
@@ -1288,8 +1307,9 @@ class AteImageService {
1288
1307
  this.resizeImage(editor, { width: 800, height: 600, maintainAspectRatio: true });
1289
1308
  }
1290
1309
  resizeImageToOriginal(editor) {
1291
- if (!editor.isActive("resizableImage"))
1310
+ if (!editor.isActive("resizableImage")) {
1292
1311
  return;
1312
+ }
1293
1313
  const img = new Image();
1294
1314
  img.onload = () => {
1295
1315
  this.resizeImage(editor, { width: img.naturalWidth, height: img.naturalHeight });
@@ -1298,8 +1318,9 @@ class AteImageService {
1298
1318
  }
1299
1319
  /** Get current image dimensions */
1300
1320
  getImageDimensions(editor) {
1301
- if (!editor.isActive("resizableImage"))
1321
+ if (!editor.isActive("resizableImage")) {
1302
1322
  return null;
1323
+ }
1303
1324
  const attrs = editor.getAttributes("resizableImage");
1304
1325
  return {
1305
1326
  width: attrs["width"] || 0,
@@ -1396,8 +1417,9 @@ class AteImageService {
1396
1417
  maxSize: options?.maxSize,
1397
1418
  allowedTypes: options?.allowedTypes,
1398
1419
  });
1399
- if (!validation.valid)
1420
+ if (!validation.valid) {
1400
1421
  throw new Error(validation.error);
1422
+ }
1401
1423
  this.uploadProgress.set(30);
1402
1424
  this.uploadMessage.set(this.t().compressing);
1403
1425
  this.forceEditorUpdate();
@@ -1419,8 +1441,9 @@ class AteImageService {
1419
1441
  ? await firstValueFrom(handlerResponse)
1420
1442
  : await handlerResponse;
1421
1443
  result.src = handlerResult.src;
1422
- if (handlerResult.alt)
1444
+ if (handlerResult.alt) {
1423
1445
  result.name = handlerResult.alt;
1446
+ }
1424
1447
  }
1425
1448
  catch (handlerError) {
1426
1449
  console.error(this.t().uploadError, handlerError);
@@ -1528,7 +1551,11 @@ class AteImageService {
1528
1551
  };
1529
1552
  // If the image was active or is still active, update it atomically
1530
1553
  if (wasActive || ed.isActive("resizableImage")) {
1531
- ed.chain().focus().updateAttributes("resizableImage", imageData).setNodeSelection(pos).run();
1554
+ ed.chain()
1555
+ .focus()
1556
+ .updateAttributes("resizableImage", imageData)
1557
+ .setNodeSelection(pos)
1558
+ .run();
1532
1559
  this.updateSelectedImage(imageData);
1533
1560
  }
1534
1561
  else {
@@ -1550,20 +1577,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1550
1577
  * Normalizes color values (rgb/rgba to hex).
1551
1578
  */
1552
1579
  function normalizeColor(color) {
1553
- if (!color || color === "transparent" || color === "rgba(0, 0, 0, 0)")
1580
+ if (!color || color === "transparent" || color === "rgba(0, 0, 0, 0)") {
1554
1581
  return null;
1555
- if (color.startsWith("#"))
1582
+ }
1583
+ if (color.startsWith("#")) {
1556
1584
  return color;
1585
+ }
1557
1586
  // Support both comma-separated (legacy) and space-separated (modern) rgb/rgba
1558
- const rgbMatch = color.trim().match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:[,\s/]+([\d.]+))?\s*\)$/i);
1587
+ const rgbMatch = color
1588
+ .trim()
1589
+ .match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:[,\s/]+([\d.]+))?\s*\)$/i);
1559
1590
  // If it's a named color or something else we don't recognize,
1560
1591
  // we can't easily normalize it to hex without a heavy dictionary.
1561
1592
  // However, getComputedStyle usually returns rgb() which we handle above.
1562
1593
  if (!rgbMatch) {
1563
1594
  // Simple fallback for common named colors if getComputedStyle fails to return rgb
1564
1595
  const named = { black: "#000000", white: "#ffffff", red: "#ff0000" };
1565
- if (named[color.toLowerCase()])
1596
+ if (named[color.toLowerCase()]) {
1566
1597
  return named[color.toLowerCase()];
1598
+ }
1567
1599
  return null;
1568
1600
  }
1569
1601
  const r = Math.max(0, Math.min(255, Math.round(parseFloat(rgbMatch[1]))));
@@ -1571,8 +1603,9 @@ function normalizeColor(color) {
1571
1603
  const b = Math.max(0, Math.min(255, Math.round(parseFloat(rgbMatch[3]))));
1572
1604
  const a = rgbMatch[4] ? parseFloat(rgbMatch[4]) : 1;
1573
1605
  // If completely transparent, return null
1574
- if (a === 0)
1606
+ if (a === 0) {
1575
1607
  return null;
1608
+ }
1576
1609
  return ("#" +
1577
1610
  [r, g, b]
1578
1611
  .map(n => n.toString(16).padStart(2, "0"))
@@ -1584,8 +1617,9 @@ function normalizeColor(color) {
1584
1617
  */
1585
1618
  function getLuminance(color) {
1586
1619
  const normalized = normalizeColor(color);
1587
- if (!normalized)
1588
- return 0; // Default to dark (luminance 0) if no color
1620
+ if (!normalized) {
1621
+ return 0;
1622
+ } // Default to dark (luminance 0) if no color
1589
1623
  const hex = normalized.replace("#", "");
1590
1624
  const r = parseInt(hex.substring(0, 2), 16);
1591
1625
  const g = parseInt(hex.substring(2, 4), 16);
@@ -1639,8 +1673,9 @@ class AteColorPickerService {
1639
1673
  * Toggle color picker from UI (extracts trigger from event).
1640
1674
  */
1641
1675
  toggle(editor, mode, event) {
1642
- if (!editor)
1676
+ if (!editor) {
1643
1677
  return;
1678
+ }
1644
1679
  let trigger;
1645
1680
  if (event && typeof event !== "string") {
1646
1681
  const target = event.target;
@@ -1655,8 +1690,9 @@ class AteColorPickerService {
1655
1690
  * Capture current editor selection.
1656
1691
  */
1657
1692
  captureSelection(editor) {
1658
- if (!editor)
1693
+ if (!editor) {
1659
1694
  return;
1695
+ }
1660
1696
  this.storedSelection = {
1661
1697
  from: editor.state.selection.from,
1662
1698
  to: editor.state.selection.to,
@@ -1682,42 +1718,44 @@ class AteColorPickerService {
1682
1718
  * Apply text color to selection.
1683
1719
  */
1684
1720
  applyColor(editor, color, addToHistory = true, focus = true) {
1685
- if (!editor)
1721
+ if (!editor) {
1686
1722
  return;
1723
+ }
1687
1724
  const stored = this.storedSelection;
1688
1725
  let chain = editor.chain();
1689
- if (focus)
1726
+ if (focus) {
1690
1727
  chain = chain.focus();
1728
+ }
1691
1729
  if (stored && (editor.state.selection.empty || !editor.isFocused)) {
1692
1730
  chain = chain.setTextSelection(stored);
1693
1731
  }
1694
1732
  else if (editor.state.selection.empty && !stored) {
1695
1733
  chain = chain.extendMarkRange("textStyle");
1696
1734
  }
1697
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1698
1735
  chain.setColor(color);
1699
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1700
- if (addToHistory === false)
1736
+ if (addToHistory === false) {
1701
1737
  chain = chain.setMeta("addToHistory", false);
1738
+ }
1702
1739
  chain.run();
1703
1740
  }
1704
1741
  /**
1705
1742
  * Remove text color from selection.
1706
1743
  */
1707
1744
  unsetColor(editor, focus = true) {
1708
- if (!editor)
1745
+ if (!editor) {
1709
1746
  return;
1747
+ }
1710
1748
  const stored = this.storedSelection;
1711
1749
  let chain = editor.chain();
1712
- if (focus)
1750
+ if (focus) {
1713
1751
  chain = chain.focus();
1752
+ }
1714
1753
  if (stored) {
1715
1754
  chain = chain.setTextSelection(stored);
1716
1755
  }
1717
1756
  else if (editor.state.selection.empty) {
1718
1757
  chain = chain.extendMarkRange("textStyle");
1719
1758
  }
1720
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1721
1759
  chain.unsetColor();
1722
1760
  chain.run();
1723
1761
  }
@@ -1725,42 +1763,44 @@ class AteColorPickerService {
1725
1763
  * Apply highlight color to selection.
1726
1764
  */
1727
1765
  applyHighlight(editor, color, addToHistory = true, focus = true) {
1728
- if (!editor)
1766
+ if (!editor) {
1729
1767
  return;
1768
+ }
1730
1769
  const stored = this.storedSelection;
1731
1770
  let chain = editor.chain();
1732
- if (focus)
1771
+ if (focus) {
1733
1772
  chain = chain.focus();
1773
+ }
1734
1774
  if (stored && (editor.state.selection.empty || !editor.isFocused)) {
1735
1775
  chain = chain.setTextSelection(stored);
1736
1776
  }
1737
1777
  else if (editor.state.selection.empty && !stored) {
1738
1778
  chain = chain.extendMarkRange("highlight");
1739
1779
  }
1740
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1741
1780
  chain.setHighlight({ color });
1742
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1743
- if (addToHistory === false)
1781
+ if (addToHistory === false) {
1744
1782
  chain = chain.setMeta("addToHistory", false);
1783
+ }
1745
1784
  chain.run();
1746
1785
  }
1747
1786
  /**
1748
1787
  * Remove highlight from selection.
1749
1788
  */
1750
1789
  unsetHighlight(editor, focus = true) {
1751
- if (!editor)
1790
+ if (!editor) {
1752
1791
  return;
1792
+ }
1753
1793
  const stored = this.storedSelection;
1754
1794
  let chain = editor.chain();
1755
- if (focus)
1795
+ if (focus) {
1756
1796
  chain = chain.focus();
1797
+ }
1757
1798
  if (stored) {
1758
1799
  chain = chain.setTextSelection(stored);
1759
1800
  }
1760
1801
  else if (editor.state.selection.empty) {
1761
1802
  chain = chain.extendMarkRange("highlight");
1762
1803
  }
1763
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1764
1804
  chain.unsetHighlight();
1765
1805
  chain.run();
1766
1806
  }
@@ -1830,8 +1870,9 @@ class AteLinkService {
1830
1870
  * If an Event is provided, extracts the trigger for anchoring.
1831
1871
  */
1832
1872
  toggle(editor, urlOrEvent) {
1833
- if (!editor)
1873
+ if (!editor) {
1834
1874
  return;
1875
+ }
1835
1876
  // If a string URL is provided, set the link and close
1836
1877
  if (urlOrEvent && typeof urlOrEvent === "string") {
1837
1878
  this.setLink(editor, urlOrEvent);
@@ -1841,7 +1882,8 @@ class AteLinkService {
1841
1882
  let trigger;
1842
1883
  if (urlOrEvent && typeof urlOrEvent !== "string") {
1843
1884
  const target = urlOrEvent.target;
1844
- trigger = urlOrEvent.currentTarget || target?.closest("button") || target;
1885
+ trigger =
1886
+ urlOrEvent.currentTarget || target?.closest("button") || target;
1845
1887
  }
1846
1888
  // Open the edit menu
1847
1889
  this.open(trigger);
@@ -1853,8 +1895,9 @@ class AteLinkService {
1853
1895
  * Apply a link to the current selection.
1854
1896
  */
1855
1897
  setLink(editor, url) {
1856
- if (!editor)
1898
+ if (!editor) {
1857
1899
  return;
1900
+ }
1858
1901
  editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
1859
1902
  this.close();
1860
1903
  }
@@ -1862,8 +1905,9 @@ class AteLinkService {
1862
1905
  * Remove link from the current selection.
1863
1906
  */
1864
1907
  unsetLink(editor) {
1865
- if (!editor)
1908
+ if (!editor) {
1866
1909
  return;
1910
+ }
1867
1911
  editor.chain().focus().extendMarkRange("link").unsetLink().run();
1868
1912
  this.close();
1869
1913
  }
@@ -1881,64 +1925,78 @@ class AteEditorCommandsService {
1881
1925
  this.linkSvc = inject(AteLinkService);
1882
1926
  this._editorState = signal(ATE_INITIAL_EDITOR_STATE, ...(ngDevMode ? [{ debugName: "_editorState", equal: (a, b) => {
1883
1927
  // 1. Primitive global states
1884
- if (a.isFocused !== b.isFocused || a.isEditable !== b.isEditable)
1928
+ if (a.isFocused !== b.isFocused || a.isEditable !== b.isEditable) {
1885
1929
  return false;
1930
+ }
1886
1931
  // 2. Detailed selection comparison
1887
1932
  if (a.selection.from !== b.selection.from ||
1888
1933
  a.selection.to !== b.selection.to ||
1889
1934
  a.selection.type !== b.selection.type ||
1890
1935
  a.selection.empty !== b.selection.empty ||
1891
- a.selection.isSingleCell !== b.selection.isSingleCell)
1936
+ a.selection.isSingleCell !== b.selection.isSingleCell) {
1892
1937
  return false;
1938
+ }
1893
1939
  // Helper for object comparison
1894
1940
  const isRecordEqual = (objA, objB) => {
1895
1941
  const keysA = Object.keys(objA);
1896
1942
  const keysB = Object.keys(objB);
1897
- if (keysA.length !== keysB.length)
1943
+ if (keysA.length !== keysB.length) {
1898
1944
  return false;
1945
+ }
1899
1946
  return keysA.every(key => objA[key] === objB[key]);
1900
1947
  };
1901
1948
  // 3. Compare sub-states (marks, can, nodes)
1902
- if (!isRecordEqual(a.marks, b.marks))
1949
+ if (!isRecordEqual(a.marks, b.marks)) {
1903
1950
  return false;
1904
- if (!isRecordEqual(a.can, b.can))
1951
+ }
1952
+ if (!isRecordEqual(a.can, b.can)) {
1905
1953
  return false;
1906
- if (!isRecordEqual(a.nodes, b.nodes))
1954
+ }
1955
+ if (!isRecordEqual(a.nodes, b.nodes)) {
1907
1956
  return false;
1957
+ }
1908
1958
  // 4. Compare custom extension states
1909
- if (!isRecordEqual(a.custom, b.custom))
1959
+ if (!isRecordEqual(a.custom, b.custom)) {
1910
1960
  return false;
1961
+ }
1911
1962
  return true;
1912
1963
  } }] : [{
1913
1964
  equal: (a, b) => {
1914
1965
  // 1. Primitive global states
1915
- if (a.isFocused !== b.isFocused || a.isEditable !== b.isEditable)
1966
+ if (a.isFocused !== b.isFocused || a.isEditable !== b.isEditable) {
1916
1967
  return false;
1968
+ }
1917
1969
  // 2. Detailed selection comparison
1918
1970
  if (a.selection.from !== b.selection.from ||
1919
1971
  a.selection.to !== b.selection.to ||
1920
1972
  a.selection.type !== b.selection.type ||
1921
1973
  a.selection.empty !== b.selection.empty ||
1922
- a.selection.isSingleCell !== b.selection.isSingleCell)
1974
+ a.selection.isSingleCell !== b.selection.isSingleCell) {
1923
1975
  return false;
1976
+ }
1924
1977
  // Helper for object comparison
1925
1978
  const isRecordEqual = (objA, objB) => {
1926
1979
  const keysA = Object.keys(objA);
1927
1980
  const keysB = Object.keys(objB);
1928
- if (keysA.length !== keysB.length)
1981
+ if (keysA.length !== keysB.length) {
1929
1982
  return false;
1983
+ }
1930
1984
  return keysA.every(key => objA[key] === objB[key]);
1931
1985
  };
1932
1986
  // 3. Compare sub-states (marks, can, nodes)
1933
- if (!isRecordEqual(a.marks, b.marks))
1987
+ if (!isRecordEqual(a.marks, b.marks)) {
1934
1988
  return false;
1935
- if (!isRecordEqual(a.can, b.can))
1989
+ }
1990
+ if (!isRecordEqual(a.can, b.can)) {
1936
1991
  return false;
1937
- if (!isRecordEqual(a.nodes, b.nodes))
1992
+ }
1993
+ if (!isRecordEqual(a.nodes, b.nodes)) {
1938
1994
  return false;
1995
+ }
1939
1996
  // 4. Compare custom extension states
1940
- if (!isRecordEqual(a.custom, b.custom))
1997
+ if (!isRecordEqual(a.custom, b.custom)) {
1941
1998
  return false;
1999
+ }
1942
2000
  return true;
1943
2001
  },
1944
2002
  }]));
@@ -1988,8 +2046,9 @@ class AteEditorCommandsService {
1988
2046
  // ============================================
1989
2047
  /** Generic method to execute any command by name */
1990
2048
  execute(editor, command, ...args) {
1991
- if (!editor)
2049
+ if (!editor) {
1992
2050
  return;
2051
+ }
1993
2052
  switch (command) {
1994
2053
  case "toggleBold":
1995
2054
  this.toggleBold(editor);
@@ -2112,53 +2171,63 @@ class AteEditorCommandsService {
2112
2171
  }
2113
2172
  // --- Formatting Commands ---
2114
2173
  toggleBold(editor) {
2115
- if (!editor)
2174
+ if (!editor) {
2116
2175
  return;
2176
+ }
2117
2177
  editor.chain().focus().toggleBold().run();
2118
2178
  }
2119
2179
  toggleItalic(editor) {
2120
- if (!editor)
2180
+ if (!editor) {
2121
2181
  return;
2182
+ }
2122
2183
  editor.chain().focus().toggleItalic().run();
2123
2184
  }
2124
2185
  toggleStrike(editor) {
2125
- if (!editor)
2186
+ if (!editor) {
2126
2187
  return;
2188
+ }
2127
2189
  editor.chain().focus().toggleStrike().run();
2128
2190
  }
2129
2191
  toggleCode(editor) {
2130
- if (!editor)
2192
+ if (!editor) {
2131
2193
  return;
2194
+ }
2132
2195
  editor.chain().focus().toggleCode().run();
2133
2196
  }
2134
2197
  toggleCodeBlock(editor) {
2135
- if (!editor)
2198
+ if (!editor) {
2136
2199
  return;
2200
+ }
2137
2201
  editor.chain().focus().toggleCodeBlock().run();
2138
2202
  }
2139
2203
  toggleUnderline(editor) {
2140
- if (!editor)
2204
+ if (!editor) {
2141
2205
  return;
2206
+ }
2142
2207
  editor.chain().focus().toggleUnderline().run();
2143
2208
  }
2144
2209
  toggleSuperscript(editor) {
2145
- if (!editor)
2210
+ if (!editor) {
2146
2211
  return;
2212
+ }
2147
2213
  editor.chain().focus().toggleSuperscript().run();
2148
2214
  }
2149
2215
  toggleSubscript(editor) {
2150
- if (!editor)
2216
+ if (!editor) {
2151
2217
  return;
2218
+ }
2152
2219
  editor.chain().focus().toggleSubscript().run();
2153
2220
  }
2154
2221
  toggleHeading(editor, level) {
2155
- if (!editor)
2222
+ if (!editor) {
2156
2223
  return;
2224
+ }
2157
2225
  editor.chain().focus().toggleHeading({ level }).run();
2158
2226
  }
2159
2227
  toggleHighlight(editor, color) {
2160
- if (!editor)
2228
+ if (!editor) {
2161
2229
  return;
2230
+ }
2162
2231
  if (color) {
2163
2232
  editor.chain().focus().setHighlight({ color }).run();
2164
2233
  }
@@ -2168,131 +2237,156 @@ class AteEditorCommandsService {
2168
2237
  }
2169
2238
  // --- Structure Commands ---
2170
2239
  toggleBulletList(editor) {
2171
- if (!editor)
2240
+ if (!editor) {
2172
2241
  return;
2242
+ }
2173
2243
  editor.chain().focus().toggleBulletList().run();
2174
2244
  }
2175
2245
  toggleOrderedList(editor) {
2176
- if (!editor)
2246
+ if (!editor) {
2177
2247
  return;
2248
+ }
2178
2249
  editor.chain().focus().toggleOrderedList().run();
2179
2250
  }
2180
2251
  toggleBlockquote(editor) {
2181
- if (!editor)
2252
+ if (!editor) {
2182
2253
  return;
2254
+ }
2183
2255
  editor.chain().focus().toggleBlockquote().run();
2184
2256
  }
2185
2257
  setTextAlign(editor, alignment) {
2186
- if (!editor)
2258
+ if (!editor) {
2187
2259
  return;
2260
+ }
2188
2261
  editor.chain().focus().setTextAlign(alignment).run();
2189
2262
  }
2190
2263
  insertHorizontalRule(editor) {
2191
- if (!editor)
2264
+ if (!editor) {
2192
2265
  return;
2266
+ }
2193
2267
  editor.chain().focus().setHorizontalRule().run();
2194
2268
  }
2195
2269
  // --- History Commands ---
2196
2270
  undo(editor) {
2197
- if (!editor)
2271
+ if (!editor) {
2198
2272
  return;
2273
+ }
2199
2274
  editor.chain().focus().undo().run();
2200
2275
  }
2201
2276
  redo(editor) {
2202
- if (!editor)
2277
+ if (!editor) {
2203
2278
  return;
2279
+ }
2204
2280
  editor.chain().focus().redo().run();
2205
2281
  }
2206
2282
  // --- Table Commands ---
2207
2283
  insertTable(editor, rows = 3, cols = 3) {
2208
- if (!editor)
2284
+ if (!editor) {
2209
2285
  return;
2286
+ }
2210
2287
  editor.chain().focus().insertTable({ rows, cols }).run();
2211
2288
  }
2212
2289
  addColumnBefore(editor) {
2213
- if (!editor)
2290
+ if (!editor) {
2214
2291
  return;
2292
+ }
2215
2293
  editor.chain().focus().addColumnBefore().run();
2216
2294
  }
2217
2295
  addColumnAfter(editor) {
2218
- if (!editor)
2296
+ if (!editor) {
2219
2297
  return;
2298
+ }
2220
2299
  editor.chain().focus().addColumnAfter().run();
2221
2300
  }
2222
2301
  deleteColumn(editor) {
2223
- if (!editor)
2302
+ if (!editor) {
2224
2303
  return;
2304
+ }
2225
2305
  editor.chain().focus().deleteColumn().run();
2226
2306
  }
2227
2307
  addRowBefore(editor) {
2228
- if (!editor)
2308
+ if (!editor) {
2229
2309
  return;
2310
+ }
2230
2311
  editor.chain().focus().addRowBefore().run();
2231
2312
  }
2232
2313
  addRowAfter(editor) {
2233
- if (!editor)
2314
+ if (!editor) {
2234
2315
  return;
2316
+ }
2235
2317
  editor.chain().focus().addRowAfter().run();
2236
2318
  }
2237
2319
  deleteRow(editor) {
2238
- if (!editor)
2320
+ if (!editor) {
2239
2321
  return;
2322
+ }
2240
2323
  editor.chain().focus().deleteRow().run();
2241
2324
  }
2242
2325
  deleteTable(editor) {
2243
- if (!editor)
2326
+ if (!editor) {
2244
2327
  return;
2328
+ }
2245
2329
  editor.chain().focus().deleteTable().run();
2246
2330
  }
2247
2331
  mergeCells(editor) {
2248
- if (!editor)
2332
+ if (!editor) {
2249
2333
  return;
2334
+ }
2250
2335
  editor.chain().focus().mergeCells().run();
2251
2336
  }
2252
2337
  splitCell(editor) {
2253
- if (!editor)
2338
+ if (!editor) {
2254
2339
  return;
2340
+ }
2255
2341
  editor.chain().focus().splitCell().run();
2256
2342
  }
2257
2343
  toggleHeaderColumn(editor) {
2258
- if (!editor)
2344
+ if (!editor) {
2259
2345
  return;
2346
+ }
2260
2347
  editor.chain().focus().toggleHeaderColumn().run();
2261
2348
  }
2262
2349
  toggleHeaderRow(editor) {
2263
- if (!editor)
2350
+ if (!editor) {
2264
2351
  return;
2352
+ }
2265
2353
  editor.chain().focus().toggleHeaderRow().run();
2266
2354
  }
2267
2355
  // --- Utility Commands ---
2268
2356
  clearContent(editor) {
2269
- if (!editor)
2357
+ if (!editor) {
2270
2358
  return;
2359
+ }
2271
2360
  editor.commands.clearContent(true);
2272
2361
  }
2273
2362
  focus(editor) {
2274
- if (!editor)
2363
+ if (!editor) {
2275
2364
  return;
2365
+ }
2276
2366
  editor.chain().focus().run();
2277
2367
  }
2278
2368
  blur(editor) {
2279
- if (!editor)
2369
+ if (!editor) {
2280
2370
  return;
2371
+ }
2281
2372
  editor.chain().blur().run();
2282
2373
  }
2283
2374
  setContent(editor, content, emitUpdate = true) {
2284
- if (!editor)
2375
+ if (!editor) {
2285
2376
  return;
2377
+ }
2286
2378
  editor.commands.setContent(content, emitUpdate);
2287
2379
  }
2288
2380
  setEditable(editor, editable) {
2289
- if (!editor)
2381
+ if (!editor) {
2290
2382
  return;
2383
+ }
2291
2384
  editor.setEditable(editable);
2292
2385
  }
2293
2386
  insertContent(editor, content) {
2294
- if (!editor)
2387
+ if (!editor) {
2295
2388
  return;
2389
+ }
2296
2390
  editor.chain().focus().insertContent(content).run();
2297
2391
  }
2298
2392
  async insertImage(editor, options) {
@@ -2448,8 +2542,9 @@ class AteToolbarComponent {
2448
2542
  }
2449
2543
  onCommand(command, ...args) {
2450
2544
  const editor = this.editor();
2451
- if (!editor)
2545
+ if (!editor) {
2452
2546
  return;
2547
+ }
2453
2548
  this.editorCommands.execute(editor, command, ...args);
2454
2549
  }
2455
2550
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -2528,7 +2623,10 @@ class AteToolbarComponent {
2528
2623
  (buttonClick)="onCommand('toggleHighlight')" />
2529
2624
  }
2530
2625
  @if (config().highlightPicker) {
2531
- <ate-color-picker mode="highlight" [editor]="editor()" [disabled]="!state().can.setHighlight" />
2626
+ <ate-color-picker
2627
+ mode="highlight"
2628
+ [editor]="editor()"
2629
+ [disabled]="!state().can.setHighlight" />
2532
2630
  }
2533
2631
  @if (config().textColor) {
2534
2632
  <ate-color-picker mode="text" [editor]="editor()" [disabled]="!state().can.setColor" />
@@ -2561,7 +2659,9 @@ class AteToolbarComponent {
2561
2659
  [disabled]="!state().can.toggleHeading3"
2562
2660
  (buttonClick)="onCommand('toggleHeading', 3)" />
2563
2661
  }
2564
- @if (config().separator && (config().bulletList || config().orderedList || config().blockquote)) {
2662
+ @if (
2663
+ config().separator && (config().bulletList || config().orderedList || config().blockquote)
2664
+ ) {
2565
2665
  <ate-separator />
2566
2666
  }
2567
2667
  @if (config().bulletList) {
@@ -2665,10 +2765,18 @@ class AteToolbarComponent {
2665
2765
  <ate-separator />
2666
2766
  }
2667
2767
  @if (config().undo) {
2668
- <ate-button icon="undo" [title]="t().undo" [disabled]="!state().can.undo" (buttonClick)="onCommand('undo')" />
2768
+ <ate-button
2769
+ icon="undo"
2770
+ [title]="t().undo"
2771
+ [disabled]="!state().can.undo"
2772
+ (buttonClick)="onCommand('undo')" />
2669
2773
  }
2670
2774
  @if (config().redo) {
2671
- <ate-button icon="redo" [title]="t().redo" [disabled]="!state().can.redo" (buttonClick)="onCommand('redo')" />
2775
+ <ate-button
2776
+ icon="redo"
2777
+ [title]="t().redo"
2778
+ [disabled]="!state().can.redo"
2779
+ (buttonClick)="onCommand('redo')" />
2672
2780
  }
2673
2781
  @if (config().separator && config().clear) {
2674
2782
  <ate-separator />
@@ -2680,6 +2788,14 @@ class AteToolbarComponent {
2680
2788
  [disabled]="!state().isEditable"
2681
2789
  (buttonClick)="onCommand('clearContent')" />
2682
2790
  }
2791
+ @if (config().custom?.length) {
2792
+ @for (item of config().custom; track item.key) {
2793
+ <ate-button
2794
+ [icon]="item.icon"
2795
+ [title]="item.label"
2796
+ (buttonClick)="item.command(editor())"></ate-button>
2797
+ }
2798
+ }
2683
2799
  </div>
2684
2800
  `, 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}.ate-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, 12px) - var(--ate-border-width, 2px));border-top-right-radius:calc(var(--ate-menu-border-radius, 12px) - var(--ate-border-width, 2px))}.ate-toolbar.floating{pointer-events:auto;border-radius:var(--ate-menu-border-radius, 12px);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)}.ate-toolbar.floating::-webkit-scrollbar{display:none}:host-context(.floating-toolbar:focus-within) .ate-toolbar.floating,:host-context(.floating-toolbar:hover) .ate-toolbar.floating{transform:translateY(-2rem)}@media (max-width: 768px){.ate-toolbar{padding:6px 8px;gap:2px}}@keyframes toolbarSlideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.ate-toolbar{animation:toolbarSlideIn .3s cubic-bezier(.4,0,.2,1)}\n"], dependencies: [{ kind: "component", type: AteButtonComponent, selector: "ate-button", inputs: ["icon", "title", "active", "disabled", "color", "backgroundColor", "variant", "size", "iconSize"], outputs: ["buttonClick"] }, { kind: "component", type: AteSeparatorComponent, selector: "ate-separator", inputs: ["orientation", "size"] }, { kind: "component", type: AteColorPickerComponent, selector: "ate-color-picker", inputs: ["editor", "mode", "disabled", "anchorToText"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2685
2801
  }
@@ -2760,7 +2876,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2760
2876
  (buttonClick)="onCommand('toggleHighlight')" />
2761
2877
  }
2762
2878
  @if (config().highlightPicker) {
2763
- <ate-color-picker mode="highlight" [editor]="editor()" [disabled]="!state().can.setHighlight" />
2879
+ <ate-color-picker
2880
+ mode="highlight"
2881
+ [editor]="editor()"
2882
+ [disabled]="!state().can.setHighlight" />
2764
2883
  }
2765
2884
  @if (config().textColor) {
2766
2885
  <ate-color-picker mode="text" [editor]="editor()" [disabled]="!state().can.setColor" />
@@ -2793,7 +2912,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2793
2912
  [disabled]="!state().can.toggleHeading3"
2794
2913
  (buttonClick)="onCommand('toggleHeading', 3)" />
2795
2914
  }
2796
- @if (config().separator && (config().bulletList || config().orderedList || config().blockquote)) {
2915
+ @if (
2916
+ config().separator && (config().bulletList || config().orderedList || config().blockquote)
2917
+ ) {
2797
2918
  <ate-separator />
2798
2919
  }
2799
2920
  @if (config().bulletList) {
@@ -2897,10 +3018,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2897
3018
  <ate-separator />
2898
3019
  }
2899
3020
  @if (config().undo) {
2900
- <ate-button icon="undo" [title]="t().undo" [disabled]="!state().can.undo" (buttonClick)="onCommand('undo')" />
3021
+ <ate-button
3022
+ icon="undo"
3023
+ [title]="t().undo"
3024
+ [disabled]="!state().can.undo"
3025
+ (buttonClick)="onCommand('undo')" />
2901
3026
  }
2902
3027
  @if (config().redo) {
2903
- <ate-button icon="redo" [title]="t().redo" [disabled]="!state().can.redo" (buttonClick)="onCommand('redo')" />
3028
+ <ate-button
3029
+ icon="redo"
3030
+ [title]="t().redo"
3031
+ [disabled]="!state().can.redo"
3032
+ (buttonClick)="onCommand('redo')" />
2904
3033
  }
2905
3034
  @if (config().separator && config().clear) {
2906
3035
  <ate-separator />
@@ -2912,6 +3041,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2912
3041
  [disabled]="!state().isEditable"
2913
3042
  (buttonClick)="onCommand('clearContent')" />
2914
3043
  }
3044
+ @if (config().custom?.length) {
3045
+ @for (item of config().custom; track item.key) {
3046
+ <ate-button
3047
+ [icon]="item.icon"
3048
+ [title]="item.label"
3049
+ (buttonClick)="item.command(editor())"></ate-button>
3050
+ }
3051
+ }
2915
3052
  </div>
2916
3053
  `, 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}.ate-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, 12px) - var(--ate-border-width, 2px));border-top-right-radius:calc(var(--ate-menu-border-radius, 12px) - var(--ate-border-width, 2px))}.ate-toolbar.floating{pointer-events:auto;border-radius:var(--ate-menu-border-radius, 12px);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)}.ate-toolbar.floating::-webkit-scrollbar{display:none}:host-context(.floating-toolbar:focus-within) .ate-toolbar.floating,:host-context(.floating-toolbar:hover) .ate-toolbar.floating{transform:translateY(-2rem)}@media (max-width: 768px){.ate-toolbar{padding:6px 8px;gap:2px}}@keyframes toolbarSlideIn{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.ate-toolbar{animation:toolbarSlideIn .3s cubic-bezier(.4,0,.2,1)}\n"] }]
2917
3054
  }], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], imageUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageUpload", required: false }] }], floating: [{ type: i0.Input, args: [{ isSignal: true, alias: "floating", required: false }] }] } });
@@ -2926,6 +3063,8 @@ class AteBaseBubbleMenu {
2926
3063
  this.editorCommands = inject(AteEditorCommandsService);
2927
3064
  // Core Inputs
2928
3065
  this.editor = input.required(...(ngDevMode ? [{ debugName: "editor" }] : []));
3066
+ // Required viewChild for the menu container
3067
+ this.menuRef = viewChild.required("menuRef");
2929
3068
  // Internal State
2930
3069
  this.tippyInstance = null;
2931
3070
  this.updateTimeout = null;
@@ -2942,8 +3081,9 @@ class AteBaseBubbleMenu {
2942
3081
  }
2943
3082
  this.updateTimeout = window.setTimeout(() => {
2944
3083
  const ed = this.editor();
2945
- if (!ed)
3084
+ if (!ed) {
2946
3085
  return;
3086
+ }
2947
3087
  // Hide when interacting with the main toolbar
2948
3088
  if (this.isToolbarInteracting()) {
2949
3089
  this.hideTippy();
@@ -2985,7 +3125,7 @@ class AteBaseBubbleMenu {
2985
3125
  * Can be overridden for specific Tippy configurations.
2986
3126
  */
2987
3127
  initTippy() {
2988
- if (!this.menuRef?.nativeElement) {
3128
+ if (!this.menuRef()?.nativeElement) {
2989
3129
  // Re-try if the view child is not yet available
2990
3130
  setTimeout(() => this.initTippy(), 50);
2991
3131
  return;
@@ -2995,7 +3135,7 @@ class AteBaseBubbleMenu {
2995
3135
  this.tippyInstance.destroy();
2996
3136
  }
2997
3137
  this.tippyInstance = tippy(document.body, {
2998
- content: this.menuRef.nativeElement,
3138
+ content: this.menuRef().nativeElement,
2999
3139
  trigger: "manual",
3000
3140
  placement: "top-start",
3001
3141
  appendTo: () => (ed ? ed.options.element : document.body),
@@ -3032,8 +3172,9 @@ class AteBaseBubbleMenu {
3032
3172
  * Helper to show the Tippy instance with updated positioning.
3033
3173
  */
3034
3174
  showTippy() {
3035
- if (!this.tippyInstance)
3175
+ if (!this.tippyInstance) {
3036
3176
  return;
3177
+ }
3037
3178
  // Update position before showing
3038
3179
  this.tippyInstance.setProps({
3039
3180
  getReferenceClientRect: () => this.getSelectionRect(),
@@ -3069,11 +3210,13 @@ class AteBaseBubbleMenu {
3069
3210
  * Uses a combination of native selection and ProseMirror coordinates.
3070
3211
  */
3071
3212
  getRectForSelection(ed) {
3072
- if (!ed)
3213
+ if (!ed) {
3073
3214
  return new DOMRect(0, 0, 0, 0);
3215
+ }
3074
3216
  const { from, to, empty } = ed.state.selection;
3075
- if (empty)
3217
+ if (empty) {
3076
3218
  return new DOMRect(-9999, -9999, 0, 0);
3219
+ }
3077
3220
  // 1. Try native selection for multi-line accuracy
3078
3221
  const selection = window.getSelection();
3079
3222
  if (selection && selection.rangeCount > 0) {
@@ -3106,14 +3249,11 @@ class AteBaseBubbleMenu {
3106
3249
  /* empty */
3107
3250
  }
3108
3251
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteBaseBubbleMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3109
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.16", type: AteBaseBubbleMenu, isStandalone: true, inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true }], ngImport: i0 }); }
3252
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.3.16", type: AteBaseBubbleMenu, isStandalone: true, inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true, isSignal: true }], ngImport: i0 }); }
3110
3253
  }
3111
3254
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteBaseBubbleMenu, decorators: [{
3112
3255
  type: Directive
3113
- }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], menuRef: [{
3114
- type: ViewChild,
3115
- args: ["menuRef", { static: false }]
3116
- }] } });
3256
+ }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], menuRef: [{ type: i0.ViewChild, args: ["menuRef", { isSignal: true }] }] } });
3117
3257
 
3118
3258
  class AteBubbleMenuComponent extends AteBaseBubbleMenu {
3119
3259
  constructor() {
@@ -3184,7 +3324,7 @@ class AteBubbleMenuComponent extends AteBaseBubbleMenu {
3184
3324
  }
3185
3325
  // Only show text bubble menu if there is a non-empty text selection
3186
3326
  // and no higher-priority node (image, table) is selected.
3187
- return selection.type === "text" && !selection.empty && !nodes.isImage && !nodes.isTableNodeSelected;
3327
+ return (selection.type === "text" && !selection.empty && !nodes.isImage && !nodes.isTableNodeSelected);
3188
3328
  }
3189
3329
  getSelectionRect() {
3190
3330
  return this.getRectForSelection(this.editor());
@@ -3271,7 +3411,11 @@ class AteBubbleMenuComponent extends AteBaseBubbleMenu {
3271
3411
  [anchorToText]="true" />
3272
3412
  }
3273
3413
  @if (bubbleMenuConfig().textColor) {
3274
- <ate-color-picker mode="text" [editor]="editor()" [disabled]="!state().can.setColor" [anchorToText]="true" />
3414
+ <ate-color-picker
3415
+ mode="text"
3416
+ [editor]="editor()"
3417
+ [disabled]="!state().can.setColor"
3418
+ [anchorToText]="true" />
3275
3419
  }
3276
3420
  @if (bubbleMenuConfig().link) {
3277
3421
  <ate-button
@@ -3281,6 +3425,14 @@ class AteBubbleMenuComponent extends AteBaseBubbleMenu {
3281
3425
  [disabled]="!state().can.toggleLink"
3282
3426
  (buttonClick)="onCommand('toggleLink', $event)"></ate-button>
3283
3427
  }
3428
+ @if (bubbleMenuConfig().custom?.length) {
3429
+ @for (item of bubbleMenuConfig().custom; track item.key) {
3430
+ <ate-button
3431
+ [icon]="item.icon"
3432
+ [title]="item.label"
3433
+ (buttonClick)="item.command(editor())"></ate-button>
3434
+ }
3435
+ }
3284
3436
  </div>
3285
3437
  `, isInline: true, dependencies: [{ kind: "component", type: AteButtonComponent, selector: "ate-button", inputs: ["icon", "title", "active", "disabled", "color", "backgroundColor", "variant", "size", "iconSize"], outputs: ["buttonClick"] }, { kind: "component", type: AteColorPickerComponent, selector: "ate-color-picker", inputs: ["editor", "mode", "disabled", "anchorToText"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3286
3438
  }
@@ -3365,7 +3517,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3365
3517
  [anchorToText]="true" />
3366
3518
  }
3367
3519
  @if (bubbleMenuConfig().textColor) {
3368
- <ate-color-picker mode="text" [editor]="editor()" [disabled]="!state().can.setColor" [anchorToText]="true" />
3520
+ <ate-color-picker
3521
+ mode="text"
3522
+ [editor]="editor()"
3523
+ [disabled]="!state().can.setColor"
3524
+ [anchorToText]="true" />
3369
3525
  }
3370
3526
  @if (bubbleMenuConfig().link) {
3371
3527
  <ate-button
@@ -3375,6 +3531,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3375
3531
  [disabled]="!state().can.toggleLink"
3376
3532
  (buttonClick)="onCommand('toggleLink', $event)"></ate-button>
3377
3533
  }
3534
+ @if (bubbleMenuConfig().custom?.length) {
3535
+ @for (item of bubbleMenuConfig().custom; track item.key) {
3536
+ <ate-button
3537
+ [icon]="item.icon"
3538
+ [title]="item.label"
3539
+ (buttonClick)="item.command(editor())"></ate-button>
3540
+ }
3541
+ }
3378
3542
  </div>
3379
3543
  `,
3380
3544
  }]
@@ -3418,8 +3582,9 @@ class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
3418
3582
  }
3419
3583
  getSelectionRect() {
3420
3584
  const ed = this.editor();
3421
- if (!ed)
3585
+ if (!ed) {
3422
3586
  return new DOMRect(0, 0, 0, 0);
3587
+ }
3423
3588
  const { from } = ed.state.selection;
3424
3589
  try {
3425
3590
  // 1. Direct ProseMirror approach: get DOM node at position
@@ -3428,8 +3593,9 @@ class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
3428
3593
  // If it's a resizable container, look for the image inside
3429
3594
  if (dom.classList.contains("resizable-image-container")) {
3430
3595
  const img = dom.querySelector("img");
3431
- if (img)
3596
+ if (img) {
3432
3597
  return img.getBoundingClientRect();
3598
+ }
3433
3599
  }
3434
3600
  return dom.getBoundingClientRect();
3435
3601
  }
@@ -3469,8 +3635,9 @@ class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
3469
3635
  }
3470
3636
  async changeImage() {
3471
3637
  const ed = this.editor();
3472
- if (!ed)
3638
+ if (!ed) {
3473
3639
  return;
3640
+ }
3474
3641
  try {
3475
3642
  // Use dedicated method to replace an existing image
3476
3643
  await this.imageService.selectAndReplaceImage(ed, this.imageUpload());
@@ -3633,8 +3800,9 @@ class AteTableBubbleMenuComponent extends AteBaseBubbleMenu {
3633
3800
  }
3634
3801
  getSelectionRect() {
3635
3802
  const ed = this.editor();
3636
- if (!ed)
3803
+ if (!ed) {
3637
3804
  return new DOMRect(0, 0, 0, 0);
3805
+ }
3638
3806
  const { from } = ed.state.selection;
3639
3807
  try {
3640
3808
  // 1. Direct ProseMirror approach: get DOM node at position
@@ -3654,8 +3822,9 @@ class AteTableBubbleMenuComponent extends AteBaseBubbleMenu {
3654
3822
  // Search for table element at these coordinates
3655
3823
  const element = document.elementFromPoint(coords.left, coords.top);
3656
3824
  const table = element?.closest("table");
3657
- if (table)
3825
+ if (table) {
3658
3826
  return table.getBoundingClientRect();
3827
+ }
3659
3828
  }
3660
3829
  // 3. Ultimate fallback if selection is ambiguous
3661
3830
  const activeTable = ed.view.dom.querySelector("table.selected, table:has(.selected), table:has(.selected-cell), table:has(.selected-node)");
@@ -3873,8 +4042,9 @@ class AteCellBubbleMenuComponent extends AteBaseBubbleMenu {
3873
4042
  }
3874
4043
  getSelectionRect() {
3875
4044
  const ed = this.editor();
3876
- if (!ed)
4045
+ if (!ed) {
3877
4046
  return new DOMRect(0, 0, 0, 0);
4047
+ }
3878
4048
  // CellSelection
3879
4049
  const selection = ed.state.selection;
3880
4050
  // 1. Multiple cells selected
@@ -3882,8 +4052,9 @@ class AteCellBubbleMenuComponent extends AteBaseBubbleMenu {
3882
4052
  const cells = [];
3883
4053
  // Try to find all selected cell nodes
3884
4054
  ed.view.dom.querySelectorAll(".selectedCell").forEach(el => {
3885
- if (el instanceof HTMLElement)
4055
+ if (el instanceof HTMLElement) {
3886
4056
  cells.push(el);
4057
+ }
3887
4058
  });
3888
4059
  if (cells.length > 0) {
3889
4060
  let top = Infinity, bottom = -Infinity, left = Infinity, right = -Infinity;
@@ -3969,21 +4140,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3969
4140
  }]
3970
4141
  }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
3971
4142
 
3972
- class AteLinkBubbleMenuComponent {
4143
+ /**
4144
+ * Base abstract class for Sub-Bubble Menus (Link, Color).
4145
+ * These menus are "sub-menus" of the main bubble menu or triggered/anchored by specific UI elements.
4146
+ */
4147
+ class AteBaseSubBubbleMenu {
3973
4148
  constructor() {
3974
4149
  this.i18nService = inject(AteI18nService);
3975
4150
  this.editorCommands = inject(AteEditorCommandsService);
3976
- this.linkSvc = inject(AteLinkService);
3977
- this.t = this.i18nService.bubbleMenu;
3978
- this.common = this.i18nService.common;
3979
- this.state = this.editorCommands.editorState;
4151
+ // Core Inputs
3980
4152
  this.editor = input.required(...(ngDevMode ? [{ debugName: "editor" }] : []));
4153
+ // Required viewChild for the menu container
4154
+ this.menuRef = viewChild.required("menuRef");
4155
+ // Internal State
3981
4156
  this.tippyInstance = null;
3982
4157
  this.updateTimeout = null;
3983
- this.editUrl = signal("", ...(ngDevMode ? [{ debugName: "editUrl" }] : []));
4158
+ // Reactive state alias for templates
4159
+ this.state = this.editorCommands.editorState;
4160
+ /**
4161
+ * Core logic to decide whether to show or hide the menu.
4162
+ */
3984
4163
  this.updateMenu = () => {
3985
- if (this.updateTimeout)
4164
+ if (this.updateTimeout) {
3986
4165
  clearTimeout(this.updateTimeout);
4166
+ }
3987
4167
  this.updateTimeout = setTimeout(() => {
3988
4168
  if (this.shouldShow()) {
3989
4169
  this.showTippy();
@@ -3993,24 +4173,11 @@ class AteLinkBubbleMenuComponent {
3993
4173
  }
3994
4174
  }, 10);
3995
4175
  };
3996
- // Reactive effect for URL sync and focus
3997
- effect(() => {
3998
- const state = this.state();
3999
- const isInteracting = this.linkSvc.isInteracting();
4000
- const currentLinkHref = state.marks.linkHref || "";
4001
- // SYNC LOGIC:
4002
- // If we are NOT currently typing (interacting),
4003
- // always keep the input in sync with the current editor selection.
4004
- if (!isInteracting) {
4005
- this.editUrl.set(currentLinkHref);
4006
- }
4007
- });
4008
4176
  // Reactive effect for menu updates (re-positioning)
4009
4177
  effect(() => {
4178
+ // Monitor editor state and specific sub-menu states
4010
4179
  this.state();
4011
- this.linkSvc.editMode();
4012
- this.linkSvc.menuTrigger();
4013
- this.linkSvc.isInteracting();
4180
+ this.onStateChange();
4014
4181
  this.updateMenu();
4015
4182
  });
4016
4183
  }
@@ -4018,21 +4185,28 @@ class AteLinkBubbleMenuComponent {
4018
4185
  this.initTippy();
4019
4186
  }
4020
4187
  ngOnDestroy() {
4021
- if (this.updateTimeout)
4188
+ if (this.updateTimeout) {
4022
4189
  clearTimeout(this.updateTimeout);
4190
+ }
4023
4191
  if (this.tippyInstance) {
4024
4192
  this.tippyInstance.destroy();
4025
4193
  this.tippyInstance = null;
4026
4194
  }
4027
4195
  }
4196
+ /**
4197
+ * Initializes the Tippy instance with sub-menu defaults.
4198
+ */
4028
4199
  initTippy() {
4029
- if (!this.menuRef?.nativeElement) {
4200
+ if (!this.menuRef()?.nativeElement) {
4030
4201
  setTimeout(() => this.initTippy(), 50);
4031
4202
  return;
4032
4203
  }
4033
4204
  const ed = this.editor();
4205
+ if (this.tippyInstance) {
4206
+ this.tippyInstance.destroy();
4207
+ }
4034
4208
  this.tippyInstance = tippy(document.body, {
4035
- content: this.menuRef.nativeElement,
4209
+ content: this.menuRef().nativeElement,
4036
4210
  trigger: "manual",
4037
4211
  placement: "bottom-start",
4038
4212
  appendTo: () => ed.options.element,
@@ -4055,41 +4229,76 @@ class AteLinkBubbleMenuComponent {
4055
4229
  },
4056
4230
  ],
4057
4231
  },
4058
- onShow: () => {
4059
- // We no longer auto-focus the input here to keep the editor selection visible.
4060
- // The user can click the input if they want to type, but for swatches/preview,
4061
- // staying in the editor is better for UX.
4062
- },
4063
- onHide: () => {
4064
- // Clear trigger only AFTER the menu is hidden to maintain anchor stability during animation
4065
- this.linkSvc.done();
4066
- this.linkSvc.close();
4067
- },
4232
+ onShow: instance => this.onTippyShow(instance),
4233
+ onHide: instance => this.onTippyHide(instance),
4068
4234
  });
4069
4235
  this.updateMenu();
4070
4236
  }
4237
+ /**
4238
+ * Helper to show the Tippy instance with updated positioning.
4239
+ */
4071
4240
  showTippy() {
4072
4241
  if (this.tippyInstance) {
4073
4242
  this.tippyInstance.setProps({ getReferenceClientRect: () => this.getSelectionRect() });
4074
4243
  this.tippyInstance.show();
4075
4244
  }
4076
4245
  }
4246
+ /**
4247
+ * Helper to hide the Tippy instance.
4248
+ */
4077
4249
  hideTippy() {
4078
4250
  this.tippyInstance?.hide();
4079
4251
  }
4080
- focusInput() {
4081
- setTimeout(() => {
4082
- this.linkInput?.nativeElement?.focus();
4083
- this.linkInput?.nativeElement?.select();
4084
- }, 50);
4252
+ /**
4253
+ * Optional hook called when Tippy is about to be shown.
4254
+ */
4255
+ onTippyShow(_instance) {
4256
+ /* empty */
4085
4257
  }
4086
- currentUrl() {
4087
- return this.state().marks.linkHref || "";
4258
+ /**
4259
+ * Optional hook called when Tippy is about to be hidden.
4260
+ */
4261
+ onTippyHide(_instance) {
4262
+ /* empty */
4263
+ }
4264
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteBaseSubBubbleMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4265
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.3.16", type: AteBaseSubBubbleMenu, isStandalone: true, inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true, isSignal: true }], ngImport: i0 }); }
4266
+ }
4267
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteBaseSubBubbleMenu, decorators: [{
4268
+ type: Directive
4269
+ }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], menuRef: [{ type: i0.ViewChild, args: ["menuRef", { isSignal: true }] }] } });
4270
+
4271
+ class AteLinkBubbleMenuComponent extends AteBaseSubBubbleMenu {
4272
+ constructor() {
4273
+ super();
4274
+ this.linkSvc = inject(AteLinkService);
4275
+ this.t = this.i18nService.bubbleMenu;
4276
+ this.common = this.i18nService.common;
4277
+ this.linkInput = viewChild("linkInput", ...(ngDevMode ? [{ debugName: "linkInput" }] : []));
4278
+ this.editUrl = signal("", ...(ngDevMode ? [{ debugName: "editUrl" }] : []));
4279
+ // Reactive effect for URL sync
4280
+ effect(() => {
4281
+ const state = this.state();
4282
+ const isInteracting = this.linkSvc.isInteracting();
4283
+ const currentLinkHref = state.marks.linkHref || "";
4284
+ // SYNC LOGIC:
4285
+ // If we are NOT currently typing (interacting),
4286
+ // always keep the input in sync with the current editor selection.
4287
+ if (!isInteracting) {
4288
+ this.editUrl.set(currentLinkHref);
4289
+ }
4290
+ });
4291
+ }
4292
+ onStateChange() {
4293
+ this.linkSvc.editMode();
4294
+ this.linkSvc.menuTrigger();
4295
+ this.linkSvc.isInteracting();
4088
4296
  }
4089
4297
  shouldShow() {
4090
4298
  const { selection, marks, isEditable, isFocused } = this.state();
4091
- if (!isEditable)
4299
+ if (!isEditable) {
4092
4300
  return false;
4301
+ }
4093
4302
  // Show if explicitly in edit mode (from toolbar/bubble menu) or interacting with input
4094
4303
  if (this.linkSvc.editMode() || this.linkSvc.isInteracting()) {
4095
4304
  return true;
@@ -4100,14 +4309,16 @@ class AteLinkBubbleMenuComponent {
4100
4309
  getSelectionRect() {
4101
4310
  const trigger = this.linkSvc.menuTrigger();
4102
4311
  const ed = this.editor();
4103
- if (!ed)
4312
+ if (!ed) {
4104
4313
  return new DOMRect(0, 0, 0, 0);
4314
+ }
4105
4315
  // 1. If we have a stable trigger from service (toolbar or parent menu), anchor to it
4106
4316
  if (trigger) {
4107
4317
  const rect = trigger.getBoundingClientRect();
4108
4318
  // Only use if it's still visible/in DOM (width > 0)
4109
- if (rect.width > 0)
4319
+ if (rect.width > 0) {
4110
4320
  return rect;
4321
+ }
4111
4322
  }
4112
4323
  // 2. Otherwise (bubble menu / relay), anchor to text selection
4113
4324
  const { from } = ed.state.selection;
@@ -4115,8 +4326,9 @@ class AteLinkBubbleMenuComponent {
4115
4326
  const { node } = ed.view.domAtPos(from);
4116
4327
  const element = node instanceof Element ? node : node.parentElement;
4117
4328
  const linkElement = element?.closest("a");
4118
- if (linkElement)
4329
+ if (linkElement) {
4119
4330
  return linkElement.getBoundingClientRect();
4331
+ }
4120
4332
  }
4121
4333
  catch (_e) {
4122
4334
  /* ignore */
@@ -4126,13 +4338,22 @@ class AteLinkBubbleMenuComponent {
4126
4338
  if (selection && selection.rangeCount > 0) {
4127
4339
  const range = selection.getRangeAt(0);
4128
4340
  const rect = range.getBoundingClientRect();
4129
- if (rect.width > 0 && rect.height > 0)
4341
+ if (rect.width > 0 && rect.height > 0) {
4130
4342
  return rect;
4343
+ }
4131
4344
  }
4132
4345
  // Final fallback to coordinates at cursor
4133
4346
  const { top, bottom, left, right } = ed.view.coordsAtPos(from);
4134
4347
  return new DOMRect(left, top, right - left, bottom - top);
4135
4348
  }
4349
+ onTippyHide() {
4350
+ // Clear trigger only AFTER the menu is hidden to maintain anchor stability during animation
4351
+ this.linkSvc.done();
4352
+ this.linkSvc.close();
4353
+ }
4354
+ currentUrl() {
4355
+ return this.state().marks.linkHref || "";
4356
+ }
4136
4357
  onMouseDown(event) {
4137
4358
  event.stopPropagation();
4138
4359
  const target = event.target;
@@ -4153,8 +4374,9 @@ class AteLinkBubbleMenuComponent {
4153
4374
  event.preventDefault();
4154
4375
  event.stopPropagation();
4155
4376
  const url = this.currentUrl();
4156
- if (url)
4377
+ if (url) {
4157
4378
  window.open(url, "_blank", "noopener,noreferrer");
4379
+ }
4158
4380
  }
4159
4381
  onRemove(event) {
4160
4382
  event.preventDefault();
@@ -4182,7 +4404,7 @@ class AteLinkBubbleMenuComponent {
4182
4404
  this.hideTippy();
4183
4405
  }
4184
4406
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteLinkBubbleMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4185
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.16", type: AteLinkBubbleMenuComponent, isStandalone: true, selector: "ate-link-bubble-menu", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "linkInput", first: true, predicate: ["linkInput"], descendants: true }, { propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true }], ngImport: i0, template: `
4407
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.16", type: AteLinkBubbleMenuComponent, isStandalone: true, selector: "ate-link-bubble-menu", viewQueries: [{ propertyName: "linkInput", first: true, predicate: ["linkInput"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
4186
4408
  <div
4187
4409
  #menuRef
4188
4410
  class="bubble-menu"
@@ -4283,13 +4505,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4283
4505
  </div>
4284
4506
  </div>
4285
4507
  `, styles: [".link-input-row{display:flex;align-items:center;gap:6px}.url-input-container{flex:1;display:flex;align-items:center;background:var(--ate-surface-secondary, #f8fafc);border:1px solid var(--ate-border, #e2e8f0);border-radius:8px;padding:0 10px;height:32px;transition:all .15s ease}.url-input-container:focus-within{border-color:var(--ate-primary, #3b82f6);background:var(--ate-surface, #ffffff);box-shadow:0 0 0 2px var(--ate-primary-light, rgba(59, 130, 246, .1))}.icon-link{font-size:16px;color:var(--ate-text-muted, #94a3b8);margin-right:6px}.url-field{background:transparent;border:none;outline:none;color:var(--ate-text, #1e293b);font-size:13px;width:100%;font-family:inherit}.action-buttons{display:flex;align-items:center;gap:2px}\n"] }]
4286
- }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], linkInput: [{
4287
- type: ViewChild,
4288
- args: ["linkInput"]
4289
- }], menuRef: [{
4290
- type: ViewChild,
4291
- args: ["menuRef", { static: false }]
4292
- }] } });
4508
+ }], ctorParameters: () => [], propDecorators: { linkInput: [{ type: i0.ViewChild, args: ["linkInput", { isSignal: true }] }] } });
4293
4509
 
4294
4510
  const PRESET_COLORS = [
4295
4511
  "#000000",
@@ -4305,36 +4521,19 @@ const PRESET_COLORS = [
4305
4521
  "#9C27B0",
4306
4522
  "#E91E63",
4307
4523
  ];
4308
- class AteColorBubbleMenuComponent {
4524
+ class AteColorBubbleMenuComponent extends AteBaseSubBubbleMenu {
4309
4525
  constructor() {
4310
- this.i18nService = inject(AteI18nService);
4311
- this.editorCommands = inject(AteEditorCommandsService);
4526
+ super(...arguments);
4312
4527
  this.colorPickerSvc = inject(AteColorPickerService);
4313
4528
  this.t = this.i18nService.toolbar;
4314
4529
  this.common = this.i18nService.common;
4315
- this.state = this.editorCommands.editorState;
4316
4530
  this.presets = PRESET_COLORS;
4317
- this.editor = input.required(...(ngDevMode ? [{ debugName: "editor" }] : []));
4318
4531
  this.colorInputRef = viewChild("colorInput", ...(ngDevMode ? [{ debugName: "colorInputRef" }] : []));
4319
- this.tippyInstance = null;
4320
- this.updateTimeout = null;
4321
4532
  /**
4322
4533
  * LOCAL MODE: We lock the mode when the menu is shown to avoid race conditions
4323
4534
  * where the parent (bubble menu) clears the global signal before we apply the color.
4324
4535
  */
4325
4536
  this.activeMode = signal("text", ...(ngDevMode ? [{ debugName: "activeMode" }] : []));
4326
- this.updateMenu = () => {
4327
- if (this.updateTimeout)
4328
- clearTimeout(this.updateTimeout);
4329
- this.updateTimeout = setTimeout(() => {
4330
- if (this.shouldShow()) {
4331
- this.showTippy();
4332
- }
4333
- else {
4334
- this.hideTippy();
4335
- }
4336
- }, 10);
4337
- };
4338
4537
  this.currentColor = computed(() => {
4339
4538
  const marks = this.state().marks;
4340
4539
  const color = this.activeMode() === "text" ? marks.computedColor : marks.computedBackground;
@@ -4344,85 +4543,17 @@ class AteColorBubbleMenuComponent {
4344
4543
  const color = this.currentColor();
4345
4544
  return color.replace("#", "").toUpperCase();
4346
4545
  }, ...(ngDevMode ? [{ debugName: "hexValue" }] : []));
4347
- effect(() => {
4348
- this.state();
4349
- this.colorPickerSvc.editMode();
4350
- this.colorPickerSvc.menuTrigger();
4351
- this.colorPickerSvc.isInteracting();
4352
- this.updateMenu();
4353
- });
4354
- }
4355
- ngOnInit() {
4356
- this.initTippy();
4357
4546
  }
4358
- ngOnDestroy() {
4359
- if (this.updateTimeout)
4360
- clearTimeout(this.updateTimeout);
4361
- if (this.tippyInstance) {
4362
- this.tippyInstance.destroy();
4363
- this.tippyInstance = null;
4364
- }
4365
- }
4366
- initTippy() {
4367
- if (!this.menuRef?.nativeElement) {
4368
- setTimeout(() => this.initTippy(), 50);
4369
- return;
4370
- }
4371
- const ed = this.editor();
4372
- this.tippyInstance = tippy(document.body, {
4373
- content: this.menuRef.nativeElement,
4374
- trigger: "manual",
4375
- placement: "bottom-start",
4376
- appendTo: () => ed.options.element,
4377
- interactive: true,
4378
- arrow: false,
4379
- offset: [0, 8],
4380
- hideOnClick: true,
4381
- plugins: [sticky],
4382
- sticky: false,
4383
- getReferenceClientRect: () => this.getSelectionRect(),
4384
- popperOptions: {
4385
- modifiers: [
4386
- {
4387
- name: "preventOverflow",
4388
- options: { boundary: ed.options.element, padding: 8 },
4389
- },
4390
- {
4391
- name: "flip",
4392
- options: { fallbackPlacements: ["top-start", "bottom-end", "top-end"] },
4393
- },
4394
- ],
4395
- },
4396
- onShow: () => {
4397
- // 1. Lock the mode immediately to be immune to external signal changes
4398
- const currentMode = this.colorPickerSvc.editMode() || "text";
4399
- this.activeMode.set(currentMode);
4400
- // 2. Capture selection for the command fallback
4401
- this.colorPickerSvc.captureSelection(this.editor());
4402
- // Note: We don't auto-focus the Hex input anymore to keep the
4403
- // visual selection (blue highlight) active in the editor.
4404
- },
4405
- onHide: () => {
4406
- // Clear trigger only AFTER the menu is hidden to maintain anchor stability during animation
4407
- this.colorPickerSvc.done();
4408
- this.colorPickerSvc.close();
4409
- },
4410
- });
4411
- this.updateMenu();
4412
- }
4413
- showTippy() {
4414
- if (this.tippyInstance) {
4415
- this.tippyInstance.setProps({ getReferenceClientRect: () => this.getSelectionRect() });
4416
- this.tippyInstance.show();
4417
- }
4418
- }
4419
- hideTippy() {
4420
- this.tippyInstance?.hide();
4547
+ onStateChange() {
4548
+ this.colorPickerSvc.editMode();
4549
+ this.colorPickerSvc.menuTrigger();
4550
+ this.colorPickerSvc.isInteracting();
4421
4551
  }
4422
4552
  shouldShow() {
4423
4553
  const { isEditable } = this.state();
4424
- if (!isEditable)
4554
+ if (!isEditable) {
4425
4555
  return false;
4556
+ }
4426
4557
  if (this.colorPickerSvc.editMode() !== null || this.colorPickerSvc.isInteracting()) {
4427
4558
  return true;
4428
4559
  }
@@ -4431,14 +4562,16 @@ class AteColorBubbleMenuComponent {
4431
4562
  getSelectionRect() {
4432
4563
  const trigger = this.colorPickerSvc.menuTrigger();
4433
4564
  const ed = this.editor();
4434
- if (!ed)
4565
+ if (!ed) {
4435
4566
  return new DOMRect(0, 0, 0, 0);
4567
+ }
4436
4568
  // 1. If we have a stable trigger from service (toolbar or parent menu), anchor to it
4437
4569
  if (trigger) {
4438
4570
  const rect = trigger.getBoundingClientRect();
4439
4571
  // Only use if it's still visible/in DOM (width > 0)
4440
- if (rect.width > 0)
4572
+ if (rect.width > 0) {
4441
4573
  return rect;
4574
+ }
4442
4575
  }
4443
4576
  // 2. Otherwise (bubble menu / relay), anchor to text selection
4444
4577
  const { from } = ed.state.selection;
@@ -4446,8 +4579,9 @@ class AteColorBubbleMenuComponent {
4446
4579
  const { node } = ed.view.domAtPos(from);
4447
4580
  const element = node instanceof Element ? node : node.parentElement;
4448
4581
  const colorElement = element?.closest('[style*="color"], [style*="background"], mark');
4449
- if (colorElement)
4582
+ if (colorElement) {
4450
4583
  return colorElement.getBoundingClientRect();
4584
+ }
4451
4585
  }
4452
4586
  catch (_e) {
4453
4587
  /* ignore */
@@ -4457,15 +4591,29 @@ class AteColorBubbleMenuComponent {
4457
4591
  if (selection && selection.rangeCount > 0) {
4458
4592
  const range = selection.getRangeAt(0);
4459
4593
  const rect = range.getBoundingClientRect();
4460
- if (rect.width > 0 && rect.height > 0)
4594
+ if (rect.width > 0 && rect.height > 0) {
4461
4595
  return rect;
4596
+ }
4462
4597
  }
4463
4598
  // Final fallback to coordinates at cursor
4464
4599
  const { top, bottom, left, right } = ed.view.coordsAtPos(from);
4465
4600
  return new DOMRect(left, top, right - left, bottom - top);
4466
4601
  }
4602
+ onTippyShow(_instance) {
4603
+ // 1. Lock the mode immediately to be immune to external signal changes
4604
+ const currentMode = this.colorPickerSvc.editMode() || "text";
4605
+ this.activeMode.set(currentMode);
4606
+ // 2. Capture selection for the command fallback
4607
+ this.colorPickerSvc.captureSelection(this.editor());
4608
+ }
4609
+ onTippyHide(_instance) {
4610
+ // Clear trigger only AFTER the menu is hidden to maintain anchor stability during animation
4611
+ this.colorPickerSvc.done();
4612
+ this.colorPickerSvc.close();
4613
+ }
4467
4614
  isColorActive(color) {
4468
- return this.colorPickerSvc.normalizeColor(this.currentColor()) === this.colorPickerSvc.normalizeColor(color);
4615
+ return (this.colorPickerSvc.normalizeColor(this.currentColor()) ===
4616
+ this.colorPickerSvc.normalizeColor(color));
4469
4617
  }
4470
4618
  applyColor(color, addToHistory = true, event) {
4471
4619
  if (event) {
@@ -4493,8 +4641,9 @@ class AteColorBubbleMenuComponent {
4493
4641
  onHexInput(event) {
4494
4642
  const input = event.target;
4495
4643
  let value = input.value.trim();
4496
- if (!value.startsWith("#"))
4644
+ if (!value.startsWith("#")) {
4497
4645
  value = "#" + value;
4646
+ }
4498
4647
  if (/^#?[0-9A-Fa-f]{3,6}$/.test(value)) {
4499
4648
  this.applyColor(value, false);
4500
4649
  }
@@ -4502,8 +4651,9 @@ class AteColorBubbleMenuComponent {
4502
4651
  onHexChange(event) {
4503
4652
  const input = event.target;
4504
4653
  let value = input.value.trim();
4505
- if (!value.startsWith("#"))
4654
+ if (!value.startsWith("#")) {
4506
4655
  value = "#" + value;
4656
+ }
4507
4657
  if (/^#?[0-9A-Fa-f]{3,6}$/.test(value)) {
4508
4658
  this.applyColor(value, true, event);
4509
4659
  }
@@ -4550,8 +4700,8 @@ class AteColorBubbleMenuComponent {
4550
4700
  this.updateMenu();
4551
4701
  }, 150);
4552
4702
  }
4553
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteColorBubbleMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4554
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AteColorBubbleMenuComponent, isStandalone: true, selector: "ate-color-bubble-menu", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "colorInputRef", first: true, predicate: ["colorInput"], descendants: true, isSignal: true }, { propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true }], ngImport: i0, template: `
4703
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteColorBubbleMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4704
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AteColorBubbleMenuComponent, isStandalone: true, selector: "ate-color-bubble-menu", viewQueries: [{ propertyName: "colorInputRef", first: true, predicate: ["colorInput"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
4555
4705
  <div
4556
4706
  #menuRef
4557
4707
  class="bubble-menu color-bubble-menu"
@@ -4712,10 +4862,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
4712
4862
  </div>
4713
4863
  </div>
4714
4864
  `, styles: [".color-picker-container{display:flex;flex-direction:column;gap:8px}.dropdown-row{display:flex;align-items:center;width:100%}.dropdown-row.presets{justify-content:center}.dropdown-row.controls{gap:8px;justify-content:space-between;padding-top:4px;border-top:1px solid var(--ate-border, #e2e8f0)}.color-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:4px;width:100%}:host ::ng-deep .color-swatch-btn .ate-button{width:100%;aspect-ratio:1;height:auto;border-radius:4px;border:1px solid rgba(0,0,0,.1);padding:0}:host ::ng-deep .color-swatch-btn .ate-button.is-active{border-color:var(--ate-primary, #3b82f6);box-shadow:0 0 0 2px #3b82f64d}:host ::ng-deep .btn-native-picker-trigger .ate-button{color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2)}.divider-v{width:1px;height:24px;background:var(--ate-border, #e2e8f0)}.hex-input-wrapper{flex:1;display:flex;align-items:center;background:var(--ate-surface-secondary, #f8fafc);border:1px solid var(--ate-border, #e2e8f0);border-radius:8px;padding:0 10px;height:32px;transition:border-color .15s ease}.hex-input-wrapper:focus-within{border-color:var(--ate-primary, #3b82f6);background:var(--ate-menu-bg, #ffffff)}.hex-hash{color:var(--ate-text-muted, #94a3b8);font-family:monospace;font-size:.875rem}.hex-input{background:transparent;border:none;outline:none;color:var(--ate-text, #1e293b);font-family:monospace;font-size:.875rem;width:100%;padding-left:4px}.native-trigger-wrapper{position:relative;width:32px;height:32px}.hidden-native-input{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer}\n"] }]
4715
- }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], menuRef: [{
4716
- type: ViewChild,
4717
- args: ["menuRef", { static: false }]
4718
- }], colorInputRef: [{ type: i0.ViewChild, args: ["colorInput", { isSignal: true }] }] } });
4865
+ }], propDecorators: { colorInputRef: [{ type: i0.ViewChild, args: ["colorInput", { isSignal: true }] }] } });
4719
4866
 
4720
4867
  /**
4721
4868
  * Clés des commandes natives dans l'ordre d'affichage
@@ -4853,6 +5000,7 @@ class AteSlashCommandsComponent {
4853
5000
  this.i18nService = inject(AteI18nService);
4854
5001
  this.editor = input.required(...(ngDevMode ? [{ debugName: "editor" }] : []));
4855
5002
  this.config = input(undefined, ...(ngDevMode ? [{ debugName: "config" }] : []));
5003
+ this.menuRef = viewChild.required("menuRef");
4856
5004
  this.tippyInstance = null;
4857
5005
  this.editorCommands = inject(AteEditorCommandsService);
4858
5006
  // Local state
@@ -4883,8 +5031,9 @@ class AteSlashCommandsComponent {
4883
5031
  }, ...(ngDevMode ? [{ debugName: "filteredCommands" }] : []));
4884
5032
  this.updateMenu = () => {
4885
5033
  const ed = this.editor();
4886
- if (!ed)
5034
+ if (!ed) {
4887
5035
  return;
5036
+ }
4888
5037
  const { from } = ed.state.selection;
4889
5038
  // Check if '/' was typed at the beginning of a line or after a space
4890
5039
  const textBefore = ed.state.doc.textBetween(Math.max(0, from - 20), from, "\n");
@@ -4917,57 +5066,11 @@ class AteSlashCommandsComponent {
4917
5066
  this.handleBlur = () => {
4918
5067
  setTimeout(() => this.hideTippy(), 100);
4919
5068
  };
4920
- this.handleKeyDown = (event) => {
4921
- // Only handle keys if menu is active
4922
- if (!this.isActive || this.filteredCommands().length === 0) {
4923
- return;
4924
- }
4925
- switch (event.key) {
4926
- case "ArrowDown": {
4927
- event.preventDefault();
4928
- event.stopPropagation();
4929
- const nextIndex = (this.selectedIndex() + 1) % this.filteredCommands().length;
4930
- this.selectedIndex.set(nextIndex);
4931
- this.scrollToSelected();
4932
- break;
4933
- }
4934
- case "ArrowUp": {
4935
- event.preventDefault();
4936
- event.stopPropagation();
4937
- const prevIndex = this.selectedIndex() === 0 ? this.filteredCommands().length - 1 : this.selectedIndex() - 1;
4938
- this.selectedIndex.set(prevIndex);
4939
- this.scrollToSelected();
4940
- break;
4941
- }
4942
- case "Enter": {
4943
- event.preventDefault();
4944
- event.stopPropagation();
4945
- const selectedCommand = this.filteredCommands()[this.selectedIndex()];
4946
- if (selectedCommand) {
4947
- this.executeCommand(selectedCommand);
4948
- }
4949
- break;
4950
- }
4951
- case "Escape": {
4952
- event.preventDefault();
4953
- event.stopPropagation();
4954
- this.isActive = false;
4955
- this.hideTippy();
4956
- // Optional: remove the typed "/"
4957
- const ed = this.editor();
4958
- if (ed && this.slashRange) {
4959
- const { tr } = ed.state;
4960
- tr.delete(this.slashRange.from, this.slashRange.to);
4961
- ed.view.dispatch(tr);
4962
- }
4963
- break;
4964
- }
4965
- }
4966
- };
4967
5069
  effect(() => {
4968
5070
  const ed = this.editor();
4969
- if (!ed)
5071
+ if (!ed) {
4970
5072
  return;
5073
+ }
4971
5074
  // Clean up old listeners
4972
5075
  ed.off("selectionUpdate", this.updateMenu);
4973
5076
  ed.off("transaction", this.updateMenu);
@@ -5000,11 +5103,11 @@ class AteSlashCommandsComponent {
5000
5103
  }
5001
5104
  }
5002
5105
  initTippy() {
5003
- if (!this.menuRef?.nativeElement) {
5106
+ if (!this.menuRef()?.nativeElement) {
5004
5107
  setTimeout(() => this.initTippy(), 50);
5005
5108
  return;
5006
5109
  }
5007
- const menuElement = this.menuRef.nativeElement;
5110
+ const menuElement = this.menuRef().nativeElement;
5008
5111
  if (this.tippyInstance) {
5009
5112
  this.tippyInstance.destroy();
5010
5113
  }
@@ -5073,8 +5176,9 @@ class AteSlashCommandsComponent {
5073
5176
  }
5074
5177
  scrollToSelected() {
5075
5178
  // Scroll to the selected element
5076
- if (this.menuRef?.nativeElement) {
5077
- const selectedItem = this.menuRef.nativeElement.querySelector(".slash-command-item.selected");
5179
+ const menuEl = this.menuRef()?.nativeElement;
5180
+ if (menuEl) {
5181
+ const selectedItem = menuEl.querySelector(".slash-command-item.selected");
5078
5182
  if (selectedItem) {
5079
5183
  selectedItem.scrollIntoView({ block: "nearest", behavior: "smooth" });
5080
5184
  }
@@ -5094,8 +5198,9 @@ class AteSlashCommandsComponent {
5094
5198
  }
5095
5199
  executeCommand(command) {
5096
5200
  const ed = this.editor();
5097
- if (!ed || !this.slashRange)
5201
+ if (!ed || !this.slashRange) {
5098
5202
  return;
5203
+ }
5099
5204
  // Remove slash text ("/")
5100
5205
  const { tr } = ed.state;
5101
5206
  tr.delete(this.slashRange.from, this.slashRange.to);
@@ -5130,7 +5235,9 @@ class AteSlashCommandsComponent {
5130
5235
  }
5131
5236
  case "ArrowUp": {
5132
5237
  event.preventDefault();
5133
- const prevIndex = this.selectedIndex() === 0 ? this.filteredCommands().length - 1 : this.selectedIndex() - 1;
5238
+ const prevIndex = this.selectedIndex() === 0
5239
+ ? this.filteredCommands().length - 1
5240
+ : this.selectedIndex() - 1;
5134
5241
  this.selectedIndex.set(prevIndex);
5135
5242
  this.scrollToSelected();
5136
5243
  return true;
@@ -5166,7 +5273,7 @@ class AteSlashCommandsComponent {
5166
5273
  }));
5167
5274
  }
5168
5275
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteSlashCommandsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5169
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AteSlashCommandsComponent, isStandalone: true, selector: "ate-slash-commands", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true }], ngImport: i0, template: `
5276
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AteSlashCommandsComponent, isStandalone: true, selector: "ate-slash-commands", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "menuRef", first: true, predicate: ["menuRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
5170
5277
  <div #menuRef class="slash-commands-menu">
5171
5278
  @for (command of filteredCommands(); track command.title) {
5172
5279
  <div
@@ -5207,10 +5314,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5207
5314
  }
5208
5315
  </div>
5209
5316
  `, styles: [".slash-commands-menu{background:var(--ate-menu-bg);border:1px solid var(--ate-menu-border);border-radius:var(--ate-menu-border-radius, 12px);box-shadow:var(--ate-menu-shadow);padding:var(--ate-menu-padding);max-height:320px;overflow-y:auto;min-width:280px;outline:none;animation:slashMenuFadeIn .2s cubic-bezier(0,0,.2,1);scrollbar-width:thin;scrollbar-color:var(--ate-scrollbar-thumb) var(--ate-scrollbar-track)}.slash-commands-menu::-webkit-scrollbar{width:var(--ate-scrollbar-width)}.slash-commands-menu::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.slash-commands-menu::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.slash-commands-menu::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}@keyframes slashMenuFadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.slash-command-item{display:flex;align-items:center;gap:12px;padding:var(--ate-menu-padding);border-radius:var(--ate-menu-border-radius, 8px);cursor:pointer;transition:all .15s ease;border:var(--ate-border-width, 1px) solid transparent;outline:none;margin-bottom:2px}.slash-command-item:last-child{margin-bottom:0}.slash-command-item:hover{background:var(--ate-surface-secondary)}.slash-command-item.selected{background:var(--ate-primary-light);border-color:var(--ate-primary-light-alpha)}.slash-command-icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;background:var(--ate-surface-tertiary);border-radius:var(--ate-sub-border-radius, 8px);color:var(--ate-primary);flex-shrink:0;transition:all .15s ease}.slash-command-item.selected .slash-command-icon{background:var(--ate-primary);color:var(--ate-primary-contrast, #ffffff)}.slash-command-icon .material-symbols-outlined{font-size:18px}.slash-command-content{flex:1;min-width:0}.slash-command-title{font-weight:500;color:var(--ate-text);font-size:14px;margin-bottom:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.slash-command-description{color:var(--ate-text-secondary);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
5210
- }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], menuRef: [{
5211
- type: ViewChild,
5212
- args: ["menuRef", { static: false }]
5213
- }] } });
5317
+ }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.Input, args: [{ isSignal: true, alias: "editor", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], menuRef: [{ type: i0.ViewChild, args: ["menuRef", { isSignal: true }] }] } });
5214
5318
 
5215
5319
  /**
5216
5320
  * Edit Toggle Component
@@ -5291,12 +5395,15 @@ const AteSelectionCalculator = editor => {
5291
5395
  const { selection } = editor.state;
5292
5396
  const { from, to } = selection;
5293
5397
  let selectionType = "none";
5294
- if (selection instanceof TextSelection)
5398
+ if (selection instanceof TextSelection) {
5295
5399
  selectionType = "text";
5296
- else if (selection instanceof NodeSelection)
5400
+ }
5401
+ else if (selection instanceof NodeSelection) {
5297
5402
  selectionType = "node";
5298
- else if (selection instanceof CellSelection)
5403
+ }
5404
+ else if (selection instanceof CellSelection) {
5299
5405
  selectionType = "cell";
5406
+ }
5300
5407
  let isSingleCell = false;
5301
5408
  if (selection instanceof CellSelection) {
5302
5409
  isSingleCell = selection.$anchorCell.pos === selection.$headCell.pos;
@@ -5328,8 +5435,9 @@ const AteMarksCalculator = editor => {
5328
5435
  const isInsideInlineCode = isCode;
5329
5436
  // 1. Resolve target element once for this calculation
5330
5437
  const getTargetElement = () => {
5331
- if (typeof window === "undefined" || !editor.view?.dom)
5438
+ if (typeof window === "undefined" || !editor.view?.dom) {
5332
5439
  return null;
5440
+ }
5333
5441
  try {
5334
5442
  const { from } = editor.state.selection;
5335
5443
  const { node } = editor.view.domAtPos(from);
@@ -5343,8 +5451,9 @@ const AteMarksCalculator = editor => {
5343
5451
  const computedStyle = targetEl && typeof window !== "undefined" ? window.getComputedStyle(targetEl) : null;
5344
5452
  // 2. Lightweight helper to extract properties from the pre-calculated style object
5345
5453
  const getStyle = (prop) => {
5346
- if (!computedStyle)
5454
+ if (!computedStyle) {
5347
5455
  return null;
5456
+ }
5348
5457
  const val = computedStyle.getPropertyValue(prop);
5349
5458
  return normalizeColor(val);
5350
5459
  };
@@ -5366,7 +5475,8 @@ const AteMarksCalculator = editor => {
5366
5475
  computedColor: colorMark || getStyle("color"),
5367
5476
  background: backgroundMark,
5368
5477
  computedBackground: backgroundMark || getStyle("background-color"),
5369
- linkOpenOnClick: editor.extensionManager.extensions.find(ext => ext.name === "link")?.options?.openOnClick ?? false,
5478
+ linkOpenOnClick: editor.extensionManager.extensions.find(ext => ext.name === "link")?.options?.openOnClick ??
5479
+ false,
5370
5480
  },
5371
5481
  can: {
5372
5482
  toggleBold: marksAllowed && !isInsideInlineCode && editor.can().toggleBold(),
@@ -5375,7 +5485,9 @@ const AteMarksCalculator = editor => {
5375
5485
  toggleStrike: marksAllowed && !isInsideInlineCode && editor.can().toggleStrike(),
5376
5486
  toggleCode: marksAllowed && editor.can().toggleCode(),
5377
5487
  toggleHighlight: marksAllowed && !isInsideInlineCode && editor.can().toggleHighlight(),
5378
- toggleLink: marksAllowed && !isInsideInlineCode && (editor.can().setLink({ href: "" }) || editor.can().unsetLink()),
5488
+ toggleLink: marksAllowed &&
5489
+ !isInsideInlineCode &&
5490
+ (editor.can().setLink({ href: "" }) || editor.can().unsetLink()),
5379
5491
  toggleSuperscript: marksAllowed && !isInsideInlineCode && editor.can().toggleSuperscript(),
5380
5492
  toggleSubscript: marksAllowed && !isInsideInlineCode && editor.can().toggleSubscript(),
5381
5493
  setColor: marksAllowed && !isInsideInlineCode && editor.can().setColor(""),
@@ -5502,7 +5614,16 @@ const AteDiscoveryCalculator = (editor) => {
5502
5614
  const name = extension.name;
5503
5615
  const type = extension.type;
5504
5616
  // Skip internal/core extensions or already handled ones
5505
- if (["selection", "editable", "focus", "undo", "redo", "history", "placeholder", "characterCount"].includes(name)) {
5617
+ if ([
5618
+ "selection",
5619
+ "editable",
5620
+ "focus",
5621
+ "undo",
5622
+ "redo",
5623
+ "history",
5624
+ "placeholder",
5625
+ "characterCount",
5626
+ ].includes(name)) {
5506
5627
  return;
5507
5628
  }
5508
5629
  if (handled.includes(name)) {
@@ -5527,11 +5648,13 @@ const AteLinkClickBehavior = Extension.create({
5527
5648
  props: {
5528
5649
  handleClick(view, _pos, _event) {
5529
5650
  // handleClick only runs in the browser, but we guard it for absolute SSR safety
5530
- if (typeof window === "undefined")
5651
+ if (typeof window === "undefined") {
5531
5652
  return false;
5653
+ }
5532
5654
  // If editor is editable, let TipTap/BubbleMenu handle it
5533
- if (view.editable)
5655
+ if (view.editable) {
5534
5656
  return false;
5657
+ }
5535
5658
  const attrs = getAttributes(view.state, "link");
5536
5659
  if (attrs["href"]) {
5537
5660
  window.open(attrs["href"], "_blank", "noopener,noreferrer");
@@ -5733,12 +5856,14 @@ class AngularTiptapEditorComponent {
5733
5856
  // Appearance & Fundamentals
5734
5857
  this.finalSeamless = computed(() => {
5735
5858
  const fromConfig = this.config().mode;
5736
- if (fromConfig !== undefined)
5859
+ if (fromConfig !== undefined) {
5737
5860
  return fromConfig === "seamless";
5861
+ }
5738
5862
  return this.seamless();
5739
5863
  }, ...(ngDevMode ? [{ debugName: "finalSeamless" }] : []));
5740
5864
  this.finalEditable = computed(() => this.config().editable ?? this.editable(), ...(ngDevMode ? [{ debugName: "finalEditable" }] : []));
5741
- this.finalPlaceholder = computed(() => this.config().placeholder ?? (this.placeholder() || this.currentTranslations().editor.placeholder), ...(ngDevMode ? [{ debugName: "finalPlaceholder" }] : []));
5865
+ this.finalPlaceholder = computed(() => this.config().placeholder ??
5866
+ (this.placeholder() || this.currentTranslations().editor.placeholder), ...(ngDevMode ? [{ debugName: "finalPlaceholder" }] : []));
5742
5867
  this.finalFillContainer = computed(() => this.config().fillContainer ?? this.fillContainer(), ...(ngDevMode ? [{ debugName: "finalFillContainer" }] : []));
5743
5868
  this.finalShowFooter = computed(() => this.config().showFooter ?? this.showFooter(), ...(ngDevMode ? [{ debugName: "finalShowFooter" }] : []));
5744
5869
  this.finalShowEditToggle = computed(() => this.config().showEditToggle ?? this.showEditToggle(), ...(ngDevMode ? [{ debugName: "finalShowEditToggle" }] : []));
@@ -5752,8 +5877,9 @@ class AngularTiptapEditorComponent {
5752
5877
  this.finalToolbarConfig = computed(() => {
5753
5878
  const fromConfig = this.config().toolbar;
5754
5879
  const base = ATE_DEFAULT_TOOLBAR_CONFIG;
5755
- if (fromConfig)
5880
+ if (fromConfig) {
5756
5881
  return { ...base, ...fromConfig };
5882
+ }
5757
5883
  const fromInput = this.toolbar();
5758
5884
  return Object.keys(fromInput).length === 0 ? base : { ...base, ...fromInput };
5759
5885
  }, ...(ngDevMode ? [{ debugName: "finalToolbarConfig" }] : []));
@@ -5762,40 +5888,51 @@ class AngularTiptapEditorComponent {
5762
5888
  this.finalBubbleMenuConfig = computed(() => {
5763
5889
  const fromConfig = this.config().bubbleMenu;
5764
5890
  const base = ATE_DEFAULT_BUBBLE_MENU_CONFIG;
5765
- if (fromConfig)
5891
+ if (fromConfig) {
5766
5892
  return { ...base, ...fromConfig };
5893
+ }
5767
5894
  return Object.keys(this.bubbleMenu()).length === 0 ? base : { ...base, ...this.bubbleMenu() };
5768
5895
  }, ...(ngDevMode ? [{ debugName: "finalBubbleMenuConfig" }] : []));
5769
5896
  this.finalShowImageBubbleMenu = computed(() => this.config().showImageBubbleMenu ?? this.showImageBubbleMenu(), ...(ngDevMode ? [{ debugName: "finalShowImageBubbleMenu" }] : []));
5770
5897
  this.finalImageBubbleMenuConfig = computed(() => {
5771
5898
  const fromConfig = this.config().imageBubbleMenu;
5772
5899
  const base = ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG;
5773
- if (fromConfig)
5900
+ if (fromConfig) {
5774
5901
  return { ...base, ...fromConfig };
5775
- return Object.keys(this.imageBubbleMenu()).length === 0 ? base : { ...base, ...this.imageBubbleMenu() };
5902
+ }
5903
+ return Object.keys(this.imageBubbleMenu()).length === 0
5904
+ ? base
5905
+ : { ...base, ...this.imageBubbleMenu() };
5776
5906
  }, ...(ngDevMode ? [{ debugName: "finalImageBubbleMenuConfig" }] : []));
5777
5907
  this.finalShowTableBubbleMenu = computed(() => this.config().showTableMenu ?? this.showTableBubbleMenu(), ...(ngDevMode ? [{ debugName: "finalShowTableBubbleMenu" }] : []));
5778
5908
  this.finalTableBubbleMenuConfig = computed(() => {
5779
5909
  const fromConfig = this.config().tableBubbleMenu;
5780
5910
  const base = ATE_DEFAULT_TABLE_MENU_CONFIG;
5781
- if (fromConfig)
5911
+ if (fromConfig) {
5782
5912
  return { ...base, ...fromConfig };
5783
- return Object.keys(this.tableBubbleMenu()).length === 0 ? base : { ...base, ...this.tableBubbleMenu() };
5913
+ }
5914
+ return Object.keys(this.tableBubbleMenu()).length === 0
5915
+ ? base
5916
+ : { ...base, ...this.tableBubbleMenu() };
5784
5917
  }, ...(ngDevMode ? [{ debugName: "finalTableBubbleMenuConfig" }] : []));
5785
5918
  this.finalShowCellBubbleMenu = computed(() => this.config().showCellMenu ?? this.showCellBubbleMenu(), ...(ngDevMode ? [{ debugName: "finalShowCellBubbleMenu" }] : []));
5786
5919
  this.finalCellBubbleMenuConfig = computed(() => {
5787
5920
  const fromConfig = this.config().cellBubbleMenu;
5788
5921
  const base = ATE_DEFAULT_CELL_MENU_CONFIG;
5789
- if (fromConfig)
5922
+ if (fromConfig) {
5790
5923
  return { ...base, ...fromConfig };
5791
- return Object.keys(this.cellBubbleMenu()).length === 0 ? base : { ...base, ...this.cellBubbleMenu() };
5924
+ }
5925
+ return Object.keys(this.cellBubbleMenu()).length === 0
5926
+ ? base
5927
+ : { ...base, ...this.cellBubbleMenu() };
5792
5928
  }, ...(ngDevMode ? [{ debugName: "finalCellBubbleMenuConfig" }] : []));
5793
5929
  this.finalEnableSlashCommands = computed(() => this.config().enableSlashCommands ?? this.enableSlashCommands(), ...(ngDevMode ? [{ debugName: "finalEnableSlashCommands" }] : []));
5794
5930
  this.finalSlashCommandsConfig = computed(() => {
5795
5931
  const fromConfig = this.config().slashCommands;
5796
5932
  const customConfig = this.customSlashCommands();
5797
- if (customConfig)
5933
+ if (customConfig) {
5798
5934
  return customConfig;
5935
+ }
5799
5936
  let baseConfig = this.slashCommands();
5800
5937
  if (fromConfig) {
5801
5938
  baseConfig = fromConfig;
@@ -5855,17 +5992,21 @@ class AngularTiptapEditorComponent {
5855
5992
  untracked(() => {
5856
5993
  const editor = this.editor();
5857
5994
  const hasFormControl = !!this.ngControl?.control;
5858
- if (!editor || content === undefined)
5995
+ if (!editor || content === undefined) {
5859
5996
  return;
5997
+ }
5860
5998
  // Anti-écho : on ignore ce qu'on vient d'émettre nous-mêmes
5861
- if (content === this.lastEmittedHtml)
5999
+ if (content === this.lastEmittedHtml) {
5862
6000
  return;
6001
+ }
5863
6002
  // Double sécurité : on vérifie le contenu actuel de l'éditeur
5864
- if (content === editor.getHTML())
6003
+ if (content === editor.getHTML()) {
5865
6004
  return;
6005
+ }
5866
6006
  // Do not overwrite content if we have a FormControl and content is empty
5867
- if (hasFormControl && !content)
6007
+ if (hasFormControl && !content) {
5868
6008
  return;
6009
+ }
5869
6010
  editor.commands.setContent(content, false);
5870
6011
  });
5871
6012
  });
@@ -5997,7 +6138,9 @@ class AngularTiptapEditorComponent {
5997
6138
  // Allow addition of custom extensions, but avoid duplicates by filtering by name
5998
6139
  const customExtensions = this.tiptapExtensions();
5999
6140
  if (customExtensions.length > 0) {
6000
- const existingNames = new Set(extensions.map(ext => ext?.name).filter((name) => !!name));
6141
+ const existingNames = new Set(extensions
6142
+ .map(ext => ext?.name)
6143
+ .filter((name) => !!name));
6001
6144
  const toAdd = customExtensions.filter(ext => {
6002
6145
  const name = ext?.name;
6003
6146
  return !name || !existingNames.has(name);
@@ -6062,7 +6205,8 @@ class AngularTiptapEditorComponent {
6062
6205
  this.editableChange.emit(newEditable);
6063
6206
  }
6064
6207
  updateCharacterCount(editor) {
6065
- if ((this.finalShowCharacterCount() || this.finalShowWordCount()) && editor.storage["characterCount"]) {
6208
+ if ((this.finalShowCharacterCount() || this.finalShowWordCount()) &&
6209
+ editor.storage["characterCount"]) {
6066
6210
  const storage = editor.storage["characterCount"];
6067
6211
  this._characterCount.set(storage.characters());
6068
6212
  this._wordCount.set(storage.words());
@@ -6163,8 +6307,9 @@ class AngularTiptapEditorComponent {
6163
6307
  }
6164
6308
  onEditorClick(event) {
6165
6309
  const editor = this.editor();
6166
- if (!editor || !this.finalEditable())
6310
+ if (!editor || !this.finalEditable()) {
6167
6311
  return;
6312
+ }
6168
6313
  // Verify if interaction is on the container element and not on the content
6169
6314
  const target = event.target;
6170
6315
  const editorElement = this.editorElement()?.nativeElement;
@@ -6270,7 +6415,10 @@ class AngularTiptapEditorComponent {
6270
6415
 
6271
6416
  <!-- Counters -->
6272
6417
  @if (
6273
- finalEditable() && !mergedDisabled() && finalShowFooter() && (finalShowCharacterCount() || finalShowWordCount())
6418
+ finalEditable() &&
6419
+ !mergedDisabled() &&
6420
+ finalShowFooter() &&
6421
+ (finalShowCharacterCount() || finalShowWordCount())
6274
6422
  ) {
6275
6423
  <div
6276
6424
  class="character-count"
@@ -6294,7 +6442,7 @@ class AngularTiptapEditorComponent {
6294
6442
  </div>
6295
6443
  }
6296
6444
  </div>
6297
- `, isInline: true, styles: [":host{--ate-primary: #2563eb;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 90%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 95%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-surface: #ffffff;--ate-surface-secondary: #f8f9fa;--ate-surface-tertiary: #f1f5f9;--ate-text: #2d3748;--ate-text-secondary: #64748b;--ate-text-muted: #a0aec0;--ate-border: #e2e8f0;--ate-highlight-bg: #fef08a;--ate-highlight-color: #854d0e;--ate-button-hover: #f1f5f9;--ate-button-active: #e2e8f0;--ate-error-color: #c53030;--ate-error-bg: #fed7d7;--ate-error-border: #feb2b2;--ate-border-color: var(--ate-border);--ate-border-width: 2px;--ate-border-radius: 12px;--ate-focus-color: var(--ate-primary);--ate-background: var(--ate-surface);--ate-sub-border-radius: 8px;--ate-text-color: var(--ate-text);--ate-placeholder-color: var(--ate-text-muted);--ate-line-height: 1.6;--ate-content-padding: 16px;--ate-menu-bg: var(--ate-surface);--ate-menu-border-radius: var(--ate-border-radius);--ate-menu-border: var(--ate-border);--ate-menu-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--ate-menu-padding: 6px;--ate-toolbar-padding: var(--ate-menu-padding);--ate-toolbar-background: var(--ate-surface-secondary);--ate-toolbar-border-color: var(--ate-border);--ate-toolbar-button-color: var(--ate-text-secondary);--ate-toolbar-button-hover-background: transparent;--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-counter-color: var(--ate-text-secondary);--ate-counter-background: var(--ate-surface-secondary);--ate-counter-border-color: var(--ate-border);--ate-drag-background: #f0f8ff;--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-border);--ate-blockquote-background: var(--ate-surface-secondary);--ate-code-background: var(--ate-surface-secondary);--ate-code-color: var(--ate-code-color);--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: 16px;--ate-image-selected-color: var(--ate-primary);--ate-scrollbar-width: 10px;--ate-scrollbar-thumb: var(--ate-border);--ate-scrollbar-thumb-hover: var(--ate-text-muted);--ate-scrollbar-track: transparent;--ate-table-border-color: var(--ate-border);--ate-table-header-background: var(--ate-surface-secondary);--ate-table-header-color: var(--ate-text);--ate-table-cell-background: var(--ate-surface);--ate-table-cell-selected-background: var(--ate-primary-light);--ate-table-resize-handle-color: var(--ate-primary);--ate-table-row-hover-background: var(--ate-primary-lighter)}:host(.dark),:host([data-theme=\"dark\"]){--ate-primary: #3b82f6;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 92%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 80%);--ate-surface: #020617;--ate-surface-secondary: #0f172a;--ate-surface-tertiary: #1e293b;--ate-text: #f8fafc;--ate-text-secondary: #94a3b8;--ate-text-muted: #64748b;--ate-border: #1e293b;--ate-highlight-bg: #854d0e;--ate-highlight-color: #fef08a;--ate-button-hover: #1e293b;--ate-button-active: #0f172a;--ate-menu-border: rgba(255, 255, 255, .1);--ate-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .3), 0 10px 10px -5px rgba(0, 0, 0, .2);--ate-error-color: #f87171;--ate-error-bg: #450a0a;--ate-error-border: #7f1d1d;--ate-drag-background: var(--ate-surface-tertiary);--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-primary);--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-button-hover: var(--ate-surface-tertiary);--ate-button-active: var(--ate-surface-secondary);--ate-scrollbar-thumb: var(--ate-surface-tertiary);--ate-scrollbar-thumb-hover: var(--ate-text-muted)}:host(.fill-container){display:block;height:100%}.ate-editor{border:var(--ate-border-width) solid var(--ate-border-color);border-radius:var(--ate-border-radius);background:var(--ate-background);overflow:visible;transition:border-color .2s ease;position:relative}:host(.floating-toolbar) .ate-editor{overflow:visible}:host(.fill-container) .ate-editor{display:flex;flex-direction:column;height:100%}:host(.fill-container) .ate-content-wrapper{flex:1;min-height:0}:host(.fill-container) .ate-content{flex:1;min-height:0;overflow-y:auto}.ate-editor:focus-within{border-color:var(--ate-focus-color)}.ate-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) .ate-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) .ate-content{cursor:default;-webkit-user-select:text;user-select:text}:host(.is-readonly) .ate-content ::ng-deep .ate-link{cursor:pointer;pointer-events:auto}.ate-content::-webkit-scrollbar{width:var(--ate-scrollbar-width)}.ate-content-wrapper{position:relative;display:flex;flex-direction:column;min-height:0}.ate-content-wrapper .ate-content{flex:1}.ate-content::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.ate-content::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.ate-content::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}.ate-content.drag-over{background:var(--ate-drag-background);border:2px dashed var(--ate-drag-border-color)}.character-count{padding:6px 8px;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:var(--ate-image-border-radius);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:var(--ate-image-border-radius);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: AteToolbarComponent, selector: "ate-toolbar", inputs: ["editor", "config", "imageUpload", "floating"] }, { kind: "component", type: AteBubbleMenuComponent, selector: "ate-bubble-menu", inputs: ["config"] }, { kind: "component", type: AteImageBubbleMenuComponent, selector: "ate-image-bubble-menu", inputs: ["config", "imageUpload"] }, { kind: "component", type: AteTableBubbleMenuComponent, selector: "ate-table-bubble-menu", inputs: ["config"] }, { kind: "component", type: AteCellBubbleMenuComponent, selector: "ate-cell-bubble-menu", inputs: ["config"] }, { kind: "component", type: AteSlashCommandsComponent, selector: "ate-slash-commands", inputs: ["editor", "config"] }, { kind: "component", type: AteLinkBubbleMenuComponent, selector: "ate-link-bubble-menu", inputs: ["editor"] }, { kind: "component", type: AteColorBubbleMenuComponent, selector: "ate-color-bubble-menu", inputs: ["editor"] }, { kind: "component", type: AteEditToggleComponent, selector: "ate-edit-toggle", inputs: ["editable", "translations"], outputs: ["editToggle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6445
+ `, isInline: true, styles: [":host{--ate-primary: #2563eb;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 90%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 95%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-surface: #ffffff;--ate-surface-secondary: #f8f9fa;--ate-surface-tertiary: #f1f5f9;--ate-text: #2d3748;--ate-text-secondary: #64748b;--ate-text-muted: #a0aec0;--ate-border: #e2e8f0;--ate-highlight-bg: #fef08a;--ate-highlight-color: #854d0e;--ate-button-hover: #f1f5f9;--ate-button-active: #e2e8f0;--ate-error-color: #c53030;--ate-error-bg: #fed7d7;--ate-error-border: #feb2b2;--ate-border-color: var(--ate-border);--ate-border-width: 2px;--ate-border-radius: 12px;--ate-focus-color: var(--ate-primary);--ate-background: var(--ate-surface);--ate-sub-border-radius: 8px;--ate-text-color: var(--ate-text);--ate-placeholder-color: var(--ate-text-muted);--ate-line-height: 1.6;--ate-content-padding: 16px;--ate-menu-bg: var(--ate-surface);--ate-menu-border-radius: var(--ate-border-radius);--ate-menu-border: var(--ate-border);--ate-menu-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--ate-menu-padding: 6px;--ate-toolbar-padding: var(--ate-menu-padding);--ate-toolbar-background: var(--ate-surface-secondary);--ate-toolbar-border-color: var(--ate-border);--ate-toolbar-button-color: var(--ate-text-secondary);--ate-toolbar-button-hover-background: transparent;--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-counter-color: var(--ate-text-secondary);--ate-counter-background: var(--ate-surface-secondary);--ate-counter-border-color: var(--ate-border);--ate-drag-background: #f0f8ff;--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-border);--ate-blockquote-background: var(--ate-surface-secondary);--ate-code-background: var(--ate-surface-secondary);--ate-code-color: var(--ate-code-color);--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: 16px;--ate-image-selected-color: var(--ate-primary);--ate-scrollbar-width: 10px;--ate-scrollbar-thumb: var(--ate-border);--ate-scrollbar-thumb-hover: var(--ate-text-muted);--ate-scrollbar-track: transparent;--ate-table-border-color: var(--ate-border);--ate-table-header-background: var(--ate-surface-secondary);--ate-table-header-color: var(--ate-text);--ate-table-cell-background: var(--ate-surface);--ate-table-cell-selected-background: var(--ate-primary-light);--ate-table-resize-handle-color: var(--ate-primary);--ate-table-row-hover-background: var(--ate-primary-lighter)}:host(.dark),:host([data-theme=\"dark\"]){--ate-primary: #3b82f6;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 92%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 80%);--ate-surface: #020617;--ate-surface-secondary: #0f172a;--ate-surface-tertiary: #1e293b;--ate-text: #f8fafc;--ate-text-secondary: #94a3b8;--ate-text-muted: #64748b;--ate-border: #1e293b;--ate-highlight-bg: #854d0e;--ate-highlight-color: #fef08a;--ate-button-hover: #1e293b;--ate-button-active: #0f172a;--ate-menu-border: rgba(255, 255, 255, .1);--ate-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .3), 0 10px 10px -5px rgba(0, 0, 0, .2);--ate-error-color: #f87171;--ate-error-bg: #450a0a;--ate-error-border: #7f1d1d;--ate-drag-background: var(--ate-surface-tertiary);--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-primary);--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-button-hover: var(--ate-surface-tertiary);--ate-button-active: var(--ate-surface-secondary);--ate-scrollbar-thumb: var(--ate-surface-tertiary);--ate-scrollbar-thumb-hover: var(--ate-text-muted)}:host(.fill-container){display:block;height:100%}.ate-editor{border:var(--ate-border-width) solid var(--ate-border-color);border-radius:var(--ate-border-radius);background:var(--ate-background);overflow:visible;transition:border-color .2s ease;position:relative}:host(.floating-toolbar) .ate-editor{overflow:visible}:host(.fill-container) .ate-editor{display:flex;flex-direction:column;height:100%}:host(.fill-container) .ate-content-wrapper{flex:1;min-height:0}:host(.fill-container) .ate-content{flex:1;min-height:0;overflow-y:auto}.ate-editor:focus-within{border-color:var(--ate-focus-color)}.ate-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) .ate-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) .ate-content{cursor:default;-webkit-user-select:text;user-select:text}:host(.is-readonly) .ate-content ::ng-deep .ate-link{cursor:pointer;pointer-events:auto}.ate-content::-webkit-scrollbar{width:var(--ate-scrollbar-width)}.ate-content-wrapper{position:relative;display:flex;flex-direction:column;min-height:0}.ate-content-wrapper .ate-content{flex:1}.ate-content::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.ate-content::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.ate-content::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}.ate-content.drag-over{background:var(--ate-drag-background);border:2px dashed var(--ate-drag-border-color)}.character-count{padding:6px 8px;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:var(--ate-image-border-radius);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:var(--ate-image-border-radius);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: AteToolbarComponent, selector: "ate-toolbar", inputs: ["editor", "config", "imageUpload", "floating"] }, { kind: "component", type: AteBubbleMenuComponent, selector: "ate-bubble-menu", inputs: ["config"] }, { kind: "component", type: AteImageBubbleMenuComponent, selector: "ate-image-bubble-menu", inputs: ["config", "imageUpload"] }, { kind: "component", type: AteTableBubbleMenuComponent, selector: "ate-table-bubble-menu", inputs: ["config"] }, { kind: "component", type: AteCellBubbleMenuComponent, selector: "ate-cell-bubble-menu", inputs: ["config"] }, { kind: "component", type: AteSlashCommandsComponent, selector: "ate-slash-commands", inputs: ["editor", "config"] }, { kind: "component", type: AteLinkBubbleMenuComponent, selector: "ate-link-bubble-menu" }, { kind: "component", type: AteColorBubbleMenuComponent, selector: "ate-color-bubble-menu" }, { kind: "component", type: AteEditToggleComponent, selector: "ate-edit-toggle", inputs: ["editable", "translations"], outputs: ["editToggle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
6298
6446
  }
6299
6447
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AngularTiptapEditorComponent, decorators: [{
6300
6448
  type: Component,
@@ -6411,7 +6559,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6411
6559
 
6412
6560
  <!-- Counters -->
6413
6561
  @if (
6414
- finalEditable() && !mergedDisabled() && finalShowFooter() && (finalShowCharacterCount() || finalShowWordCount())
6562
+ finalEditable() &&
6563
+ !mergedDisabled() &&
6564
+ finalShowFooter() &&
6565
+ (finalShowCharacterCount() || finalShowWordCount())
6415
6566
  ) {
6416
6567
  <div
6417
6568
  class="character-count"
@@ -6438,6 +6589,90 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
6438
6589
  `, styles: [":host{--ate-primary: #2563eb;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 90%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 95%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-surface: #ffffff;--ate-surface-secondary: #f8f9fa;--ate-surface-tertiary: #f1f5f9;--ate-text: #2d3748;--ate-text-secondary: #64748b;--ate-text-muted: #a0aec0;--ate-border: #e2e8f0;--ate-highlight-bg: #fef08a;--ate-highlight-color: #854d0e;--ate-button-hover: #f1f5f9;--ate-button-active: #e2e8f0;--ate-error-color: #c53030;--ate-error-bg: #fed7d7;--ate-error-border: #feb2b2;--ate-border-color: var(--ate-border);--ate-border-width: 2px;--ate-border-radius: 12px;--ate-focus-color: var(--ate-primary);--ate-background: var(--ate-surface);--ate-sub-border-radius: 8px;--ate-text-color: var(--ate-text);--ate-placeholder-color: var(--ate-text-muted);--ate-line-height: 1.6;--ate-content-padding: 16px;--ate-menu-bg: var(--ate-surface);--ate-menu-border-radius: var(--ate-border-radius);--ate-menu-border: var(--ate-border);--ate-menu-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--ate-menu-padding: 6px;--ate-toolbar-padding: var(--ate-menu-padding);--ate-toolbar-background: var(--ate-surface-secondary);--ate-toolbar-border-color: var(--ate-border);--ate-toolbar-button-color: var(--ate-text-secondary);--ate-toolbar-button-hover-background: transparent;--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-counter-color: var(--ate-text-secondary);--ate-counter-background: var(--ate-surface-secondary);--ate-counter-border-color: var(--ate-border);--ate-drag-background: #f0f8ff;--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-border);--ate-blockquote-background: var(--ate-surface-secondary);--ate-code-background: var(--ate-surface-secondary);--ate-code-color: var(--ate-code-color);--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: 16px;--ate-image-selected-color: var(--ate-primary);--ate-scrollbar-width: 10px;--ate-scrollbar-thumb: var(--ate-border);--ate-scrollbar-thumb-hover: var(--ate-text-muted);--ate-scrollbar-track: transparent;--ate-table-border-color: var(--ate-border);--ate-table-header-background: var(--ate-surface-secondary);--ate-table-header-color: var(--ate-text);--ate-table-cell-background: var(--ate-surface);--ate-table-cell-selected-background: var(--ate-primary-light);--ate-table-resize-handle-color: var(--ate-primary);--ate-table-row-hover-background: var(--ate-primary-lighter)}:host(.dark),:host([data-theme=\"dark\"]){--ate-primary: #3b82f6;--ate-primary-contrast: #ffffff;--ate-primary-light: color-mix(in srgb, var(--ate-primary), transparent 85%);--ate-primary-lighter: color-mix(in srgb, var(--ate-primary), transparent 92%);--ate-primary-light-alpha: color-mix(in srgb, var(--ate-primary), transparent 80%);--ate-surface: #020617;--ate-surface-secondary: #0f172a;--ate-surface-tertiary: #1e293b;--ate-text: #f8fafc;--ate-text-secondary: #94a3b8;--ate-text-muted: #64748b;--ate-border: #1e293b;--ate-highlight-bg: #854d0e;--ate-highlight-color: #fef08a;--ate-button-hover: #1e293b;--ate-button-active: #0f172a;--ate-menu-border: rgba(255, 255, 255, .1);--ate-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .3), 0 10px 10px -5px rgba(0, 0, 0, .2);--ate-error-color: #f87171;--ate-error-bg: #450a0a;--ate-error-border: #7f1d1d;--ate-drag-background: var(--ate-surface-tertiary);--ate-drag-border-color: var(--ate-primary);--ate-blockquote-border-color: var(--ate-primary);--ate-toolbar-button-active-background: var(--ate-primary-light);--ate-toolbar-button-active-color: var(--ate-primary);--ate-button-hover: var(--ate-surface-tertiary);--ate-button-active: var(--ate-surface-secondary);--ate-scrollbar-thumb: var(--ate-surface-tertiary);--ate-scrollbar-thumb-hover: var(--ate-text-muted)}:host(.fill-container){display:block;height:100%}.ate-editor{border:var(--ate-border-width) solid var(--ate-border-color);border-radius:var(--ate-border-radius);background:var(--ate-background);overflow:visible;transition:border-color .2s ease;position:relative}:host(.floating-toolbar) .ate-editor{overflow:visible}:host(.fill-container) .ate-editor{display:flex;flex-direction:column;height:100%}:host(.fill-container) .ate-content-wrapper{flex:1;min-height:0}:host(.fill-container) .ate-content{flex:1;min-height:0;overflow-y:auto}.ate-editor:focus-within{border-color:var(--ate-focus-color)}.ate-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) .ate-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) .ate-content{cursor:default;-webkit-user-select:text;user-select:text}:host(.is-readonly) .ate-content ::ng-deep .ate-link{cursor:pointer;pointer-events:auto}.ate-content::-webkit-scrollbar{width:var(--ate-scrollbar-width)}.ate-content-wrapper{position:relative;display:flex;flex-direction:column;min-height:0}.ate-content-wrapper .ate-content{flex:1}.ate-content::-webkit-scrollbar-track{background:var(--ate-scrollbar-track)}.ate-content::-webkit-scrollbar-thumb{background:var(--ate-scrollbar-thumb);border:3px solid transparent;background-clip:content-box;border-radius:10px}.ate-content::-webkit-scrollbar-thumb:hover{background:var(--ate-scrollbar-thumb-hover);background-clip:content-box}.ate-content.drag-over{background:var(--ate-drag-background);border:2px dashed var(--ate-drag-border-color)}.character-count{padding:6px 8px;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:var(--ate-image-border-radius);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:var(--ate-image-border-radius);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"] }]
6439
6590
  }], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], fillContainer: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillContainer", required: false }] }], showToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToolbar", required: false }] }], showFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFooter", required: false }] }], showCharacterCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCharacterCount", required: false }] }], showWordCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWordCount", required: false }] }], maxCharacters: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxCharacters", required: false }] }], enableOfficePaste: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableOfficePaste", required: false }] }], enableSlashCommands: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSlashCommands", required: false }] }], slashCommands: [{ type: i0.Input, args: [{ isSignal: true, alias: "slashCommands", required: false }] }], customSlashCommands: [{ type: i0.Input, args: [{ isSignal: true, alias: "customSlashCommands", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], autofocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autofocus", required: false }] }], seamless: [{ type: i0.Input, args: [{ isSignal: true, alias: "seamless", required: false }] }], floatingToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingToolbar", required: false }] }], showEditToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEditToggle", required: false }] }], spellcheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "spellcheck", required: false }] }], tiptapExtensions: [{ type: i0.Input, args: [{ isSignal: true, alias: "tiptapExtensions", required: false }] }], tiptapOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "tiptapOptions", required: false }] }], showBubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBubbleMenu", required: false }] }], bubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "bubbleMenu", required: false }] }], showImageBubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "showImageBubbleMenu", required: false }] }], imageBubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageBubbleMenu", required: false }] }], toolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbar", required: false }] }], showTableBubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTableBubbleMenu", required: false }] }], tableBubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableBubbleMenu", required: false }] }], showCellBubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCellBubbleMenu", required: false }] }], cellBubbleMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellBubbleMenu", required: false }] }], stateCalculators: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateCalculators", required: false }] }], imageUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageUpload", required: false }] }], imageUploadHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageUploadHandler", required: false }] }], contentChange: [{ type: i0.Output, args: ["contentChange"] }], editorCreated: [{ type: i0.Output, args: ["editorCreated"] }], editorUpdate: [{ type: i0.Output, args: ["editorUpdate"] }], editorFocus: [{ type: i0.Output, args: ["editorFocus"] }], editorBlur: [{ type: i0.Output, args: ["editorBlur"] }], editableChange: [{ type: i0.Output, args: ["editableChange"] }], editorElement: [{ type: i0.ViewChild, args: ["editorElement", { isSignal: true }] }] } });
6440
6591
 
6592
+ /**
6593
+ * Clés des boutons de la barre d'outils native
6594
+ */
6595
+ const ATE_TOOLBAR_KEYS = [
6596
+ "bold",
6597
+ "italic",
6598
+ "underline",
6599
+ "strike",
6600
+ "code",
6601
+ "codeBlock",
6602
+ "superscript",
6603
+ "subscript",
6604
+ "highlight",
6605
+ "highlightPicker",
6606
+ "heading1",
6607
+ "heading2",
6608
+ "heading3",
6609
+ "bulletList",
6610
+ "orderedList",
6611
+ "blockquote",
6612
+ "alignLeft",
6613
+ "alignCenter",
6614
+ "alignRight",
6615
+ "alignJustify",
6616
+ "link",
6617
+ "image",
6618
+ "horizontalRule",
6619
+ "table",
6620
+ "undo",
6621
+ "redo",
6622
+ "clear",
6623
+ "textColor",
6624
+ "separator",
6625
+ ];
6626
+
6627
+ /**
6628
+ * Clés des options du menu bulle de texte
6629
+ */
6630
+ const ATE_BUBBLE_MENU_KEYS = [
6631
+ "bold",
6632
+ "italic",
6633
+ "underline",
6634
+ "strike",
6635
+ "code",
6636
+ "superscript",
6637
+ "subscript",
6638
+ "highlight",
6639
+ "highlightPicker",
6640
+ "textColor",
6641
+ "link",
6642
+ "separator",
6643
+ ];
6644
+ /**
6645
+ * Clés des options du menu bulle d'image
6646
+ */
6647
+ const ATE_IMAGE_BUBBLE_MENU_KEYS = [
6648
+ "changeImage",
6649
+ "resizeSmall",
6650
+ "resizeMedium",
6651
+ "resizeLarge",
6652
+ "resizeOriginal",
6653
+ "deleteImage",
6654
+ "separator",
6655
+ ];
6656
+ /**
6657
+ * Clés des options du menu de table
6658
+ */
6659
+ const ATE_TABLE_BUBBLE_MENU_KEYS = [
6660
+ "addRowBefore",
6661
+ "addRowAfter",
6662
+ "deleteRow",
6663
+ "addColumnBefore",
6664
+ "addColumnAfter",
6665
+ "deleteColumn",
6666
+ "deleteTable",
6667
+ "toggleHeaderRow",
6668
+ "toggleHeaderColumn",
6669
+ "separator",
6670
+ ];
6671
+ /**
6672
+ * Clés des options du menu de cellule
6673
+ */
6674
+ const ATE_CELL_BUBBLE_MENU_KEYS = ["mergeCells", "splitCell"];
6675
+
6441
6676
  /*
6442
6677
  * Public API Surface of tiptap-editor
6443
6678
  */
@@ -6475,5 +6710,5 @@ const DEFAULT_CELL_MENU_CONFIG = ATE_DEFAULT_CELL_MENU_CONFIG;
6475
6710
  * Generated bundle index. Do not edit.
6476
6711
  */
6477
6712
 
6478
- export { ATE_DEFAULT_BUBBLE_MENU_CONFIG, ATE_DEFAULT_CELL_MENU_CONFIG, ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, ATE_DEFAULT_SLASH_COMMANDS_CONFIG, ATE_DEFAULT_TABLE_MENU_CONFIG, ATE_DEFAULT_TOOLBAR_CONFIG, ATE_INITIAL_EDITOR_STATE, ATE_SLASH_COMMAND_KEYS, AngularTiptapEditorComponent, AteColorPickerService, AteDiscoveryCalculator, AteEditorCommandsService, AteI18nService, AteImageCalculator, AteImageService, AteLinkService, AteMarksCalculator, AteNoopValueAccessorDirective, AteSelectionCalculator, AteStructureCalculator, AteTableCalculator, AteColorPickerService as ColorPickerService, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS_CONFIG, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, DiscoveryCalculator, AteEditorCommandsService as EditorCommandsService, INITIAL_EDITOR_STATE, ImageCalculator, AteImageService as ImageService, AteLinkService as LinkService, MarksCalculator, SLASH_COMMAND_KEYS, SelectionCalculator, StructureCalculator, TableCalculator, AteI18nService as TiptapI18nService, createDefaultSlashCommands, filterSlashCommands };
6713
+ export { ATE_BUBBLE_MENU_KEYS, ATE_CELL_BUBBLE_MENU_KEYS, ATE_DEFAULT_BUBBLE_MENU_CONFIG, ATE_DEFAULT_CELL_MENU_CONFIG, ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, ATE_DEFAULT_SLASH_COMMANDS_CONFIG, ATE_DEFAULT_TABLE_MENU_CONFIG, ATE_DEFAULT_TOOLBAR_CONFIG, ATE_IMAGE_BUBBLE_MENU_KEYS, ATE_INITIAL_EDITOR_STATE, ATE_SLASH_COMMAND_KEYS, ATE_TABLE_BUBBLE_MENU_KEYS, ATE_TOOLBAR_KEYS, AngularTiptapEditorComponent, AteColorPickerService, AteDiscoveryCalculator, AteEditorCommandsService, AteI18nService, AteImageCalculator, AteImageService, AteLinkService, AteMarksCalculator, AteNoopValueAccessorDirective, AteSelectionCalculator, AteStructureCalculator, AteTableCalculator, AteColorPickerService as ColorPickerService, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS_CONFIG, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, DiscoveryCalculator, AteEditorCommandsService as EditorCommandsService, INITIAL_EDITOR_STATE, ImageCalculator, AteImageService as ImageService, AteLinkService as LinkService, MarksCalculator, SLASH_COMMAND_KEYS, SelectionCalculator, StructureCalculator, TableCalculator, AteI18nService as TiptapI18nService, createDefaultSlashCommands, filterSlashCommands };
6479
6714
  //# sourceMappingURL=flogeez-angular-tiptap-editor.mjs.map