@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.
- package/CHANGELOG.md +13 -1
- package/README.md +63 -46
- package/fesm2022/flogeez-angular-tiptap-editor.mjs +619 -384
- package/fesm2022/flogeez-angular-tiptap-editor.mjs.map +1 -1
- package/index.d.ts +59 -80
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, ChangeDetectionStrategy, Component, signal, computed, Injectable, inject,
|
|
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
|
-
|
|
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 =
|
|
177
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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()
|
|
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
|
-
|
|
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
|
|
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;
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
1951
|
+
}
|
|
1952
|
+
if (!isRecordEqual(a.can, b.can)) {
|
|
1905
1953
|
return false;
|
|
1906
|
-
|
|
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
|
-
|
|
1989
|
+
}
|
|
1990
|
+
if (!isRecordEqual(a.can, b.can)) {
|
|
1936
1991
|
return false;
|
|
1937
|
-
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4252
|
+
/**
|
|
4253
|
+
* Optional hook called when Tippy is about to be shown.
|
|
4254
|
+
*/
|
|
4255
|
+
onTippyShow(_instance) {
|
|
4256
|
+
/* empty */
|
|
4085
4257
|
}
|
|
4086
|
-
|
|
4087
|
-
|
|
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.
|
|
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: {
|
|
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
|
-
|
|
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
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
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()) ===
|
|
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:
|
|
4554
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: AteColorBubbleMenuComponent, isStandalone: true, selector: "ate-color-bubble-menu",
|
|
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
|
-
}],
|
|
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
|
-
|
|
5077
|
-
|
|
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
|
|
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
|
-
|
|
5400
|
+
}
|
|
5401
|
+
else if (selection instanceof NodeSelection) {
|
|
5297
5402
|
selectionType = "node";
|
|
5298
|
-
|
|
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 ??
|
|
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 &&
|
|
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 ([
|
|
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 ??
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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()) &&
|
|
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() &&
|
|
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() &&
|
|
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
|