@flogeez/angular-tiptap-editor 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +132 -93
- package/esm2022/flogeez-angular-tiptap-editor.mjs +5 -0
- package/esm2022/lib/ate-editor.provider.mjs +38 -0
- package/esm2022/lib/components/bubble-menus/base/ate-base-bubble-menu.mjs +207 -0
- package/esm2022/lib/components/bubble-menus/base/ate-base-sub-bubble-menu.mjs +133 -0
- package/esm2022/lib/components/bubble-menus/color/ate-color-bubble-menu.component.mjs +365 -0
- package/esm2022/lib/components/bubble-menus/image/ate-image-bubble-menu.component.mjs +226 -0
- package/esm2022/lib/components/bubble-menus/link/ate-link-bubble-menu.component.mjs +247 -0
- package/esm2022/lib/components/bubble-menus/table/ate-cell-bubble-menu.component.mjs +121 -0
- package/esm2022/lib/components/bubble-menus/table/ate-table-bubble-menu.component.mjs +266 -0
- package/esm2022/lib/components/bubble-menus/text/ate-bubble-menu.component.mjs +294 -0
- package/esm2022/lib/components/color-picker/ate-color-picker.component.mjs +122 -0
- package/esm2022/lib/components/edit-toggle/ate-edit-toggle.component.mjs +42 -0
- package/esm2022/lib/components/editor/angular-tiptap-editor.component.mjs +953 -0
- package/esm2022/lib/components/slash-commands/ate-slash-commands.component.mjs +329 -0
- package/esm2022/lib/components/toolbar/ate-toolbar.component.mjs +531 -0
- package/esm2022/lib/components/ui/ate-button.component.mjs +90 -0
- package/esm2022/lib/components/ui/ate-separator.component.mjs +31 -0
- package/esm2022/lib/config/ate-editor.config.mjs +76 -0
- package/esm2022/lib/config/ate-global-config.token.mjs +6 -0
- package/esm2022/lib/config/ate-slash-commands.config.mjs +130 -0
- package/esm2022/lib/directives/ate-noop-value-accessor.directive.mjs +40 -0
- package/esm2022/lib/extensions/ate-link-click-behavior.extension.mjs +32 -0
- package/esm2022/lib/extensions/ate-resizable-image.extension.mjs +270 -0
- package/esm2022/lib/extensions/ate-table.extension.mjs +29 -0
- package/esm2022/lib/extensions/ate-tiptap-state.extension.mjs +85 -0
- package/esm2022/lib/extensions/ate-upload-progress.extension.mjs +195 -0
- package/esm2022/lib/extensions/calculators/ate-discovery.calculator.mjs +62 -0
- package/esm2022/lib/extensions/calculators/ate-image.calculator.mjs +8 -0
- package/esm2022/lib/extensions/calculators/ate-marks.calculator.mjs +75 -0
- package/esm2022/lib/extensions/calculators/ate-selection.calculator.mjs +35 -0
- package/esm2022/lib/extensions/calculators/ate-structure.calculator.mjs +34 -0
- package/esm2022/lib/extensions/calculators/ate-table.calculator.mjs +38 -0
- package/esm2022/lib/models/ate-bubble-menu.model.mjs +49 -0
- package/esm2022/lib/models/ate-editor-config.model.mjs +2 -0
- package/esm2022/lib/models/ate-editor-state.model.mjs +90 -0
- package/esm2022/lib/models/ate-image.model.mjs +2 -0
- package/esm2022/lib/models/ate-toolbar.model.mjs +35 -0
- package/esm2022/lib/node-view/ate-angular-node-view.mjs +97 -0
- package/esm2022/lib/node-view/ate-injector.registry.mjs +16 -0
- package/esm2022/lib/node-view/ate-node-view.factory.mjs +125 -0
- package/esm2022/lib/node-view/ate-node-view.models.mjs +2 -0
- package/esm2022/lib/node-view/ate-node-view.renderer.mjs +154 -0
- package/esm2022/lib/node-view/ate-register-angular-component.mjs +49 -0
- package/esm2022/lib/services/ate-color-picker.service.mjs +193 -0
- package/esm2022/lib/services/ate-editor-commands.service.mjs +465 -0
- package/esm2022/lib/services/ate-i18n.service.mjs +410 -0
- package/esm2022/lib/services/ate-image.service.mjs +368 -0
- package/esm2022/lib/services/ate-link.service.mjs +97 -0
- package/esm2022/lib/utils/ate-color.utils.mjs +60 -0
- package/esm2022/public-api.mjs +93 -0
- package/fesm2022/flogeez-angular-tiptap-editor.mjs +1178 -1100
- package/fesm2022/flogeez-angular-tiptap-editor.mjs.map +1 -1
- package/index.d.ts +3 -1562
- package/lib/ate-editor.provider.d.ts +21 -0
- package/lib/components/bubble-menus/base/ate-base-bubble-menu.d.ts +71 -0
- package/lib/components/bubble-menus/base/ate-base-sub-bubble-menu.d.ts +60 -0
- package/lib/components/bubble-menus/color/ate-color-bubble-menu.component.d.ts +77 -0
- package/lib/components/bubble-menus/image/ate-image-bubble-menu.component.d.ts +52 -0
- package/lib/components/bubble-menus/link/ate-link-bubble-menu.component.d.ts +55 -0
- package/lib/components/bubble-menus/table/ate-cell-bubble-menu.component.d.ts +12 -0
- package/lib/components/bubble-menus/table/ate-table-bubble-menu.component.d.ts +24 -0
- package/lib/components/bubble-menus/text/ate-bubble-menu.component.d.ts +53 -0
- package/lib/components/color-picker/ate-color-picker.component.d.ts +54 -0
- package/lib/components/edit-toggle/ate-edit-toggle.component.d.ts +13 -0
- package/lib/components/editor/angular-tiptap-editor.component.d.ts +235 -0
- package/lib/components/slash-commands/ate-slash-commands.component.d.ts +43 -0
- package/lib/components/toolbar/ate-toolbar.component.d.ts +47 -0
- package/lib/components/ui/ate-button.component.d.ts +25 -0
- package/lib/components/ui/ate-separator.component.d.ts +7 -0
- package/lib/config/ate-editor.config.d.ts +7 -0
- package/lib/config/ate-global-config.token.d.ts +6 -0
- package/lib/config/ate-slash-commands.config.d.ts +41 -0
- package/lib/directives/ate-noop-value-accessor.directive.d.ts +13 -0
- package/lib/extensions/ate-link-click-behavior.extension.d.ts +2 -0
- package/lib/extensions/ate-resizable-image.extension.d.ts +27 -0
- package/lib/extensions/ate-table.extension.d.ts +2 -0
- package/lib/extensions/ate-tiptap-state.extension.d.ts +7 -0
- package/lib/extensions/ate-upload-progress.extension.d.ts +7 -0
- package/lib/extensions/calculators/ate-discovery.calculator.d.ts +7 -0
- package/lib/extensions/calculators/ate-image.calculator.d.ts +2 -0
- package/lib/extensions/calculators/ate-marks.calculator.d.ts +2 -0
- package/lib/extensions/calculators/ate-selection.calculator.d.ts +2 -0
- package/lib/extensions/calculators/ate-structure.calculator.d.ts +2 -0
- package/lib/extensions/calculators/ate-table.calculator.d.ts +2 -0
- package/lib/models/ate-bubble-menu.model.d.ts +33 -0
- package/lib/models/ate-editor-config.model.d.ts +100 -0
- package/lib/models/ate-editor-state.model.d.ts +109 -0
- package/lib/models/ate-image.model.d.ts +104 -0
- package/lib/models/ate-toolbar.model.d.ts +18 -0
- package/lib/node-view/ate-angular-node-view.d.ts +115 -0
- package/lib/node-view/ate-injector.registry.d.ts +3 -0
- package/lib/node-view/ate-node-view.factory.d.ts +10 -0
- package/lib/node-view/ate-node-view.models.d.ts +138 -0
- package/lib/node-view/ate-node-view.renderer.d.ts +23 -0
- package/lib/node-view/ate-register-angular-component.d.ts +35 -0
- package/lib/services/ate-color-picker.service.d.ts +65 -0
- package/lib/services/ate-editor-commands.service.d.ts +72 -0
- package/lib/services/ate-i18n.service.d.ts +394 -0
- package/lib/services/ate-image.service.d.ts +71 -0
- package/lib/services/ate-link.service.d.ts +42 -0
- package/lib/utils/ate-color.utils.d.ts +12 -0
- package/package.json +3 -1
- package/public-api.d.ts +112 -0
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, ChangeDetectionStrategy, Component, signal, computed, Injectable, inject, viewChild, effect, Directive, DestroyRef,
|
|
2
|
+
import { input, output, ChangeDetectionStrategy, Component, signal, computed, Injectable, inject, viewChild, effect, Directive, ApplicationRef, EnvironmentInjector, createComponent, InjectionToken, DestroyRef, Injector, untracked, makeEnvironmentProviders, APP_INITIALIZER } 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
|
-
import StarterKit from '@tiptap/starter-kit';
|
|
6
|
-
import Placeholder from '@tiptap/extension-placeholder';
|
|
7
|
-
import CharacterCount from '@tiptap/extension-character-count';
|
|
8
|
-
import Underline from '@tiptap/extension-underline';
|
|
9
|
-
import Superscript from '@tiptap/extension-superscript';
|
|
10
|
-
import Subscript from '@tiptap/extension-subscript';
|
|
11
|
-
import TextAlign from '@tiptap/extension-text-align';
|
|
12
|
-
import Link from '@tiptap/extension-link';
|
|
13
|
-
import Highlight from '@tiptap/extension-highlight';
|
|
14
|
-
import TextStyle from '@tiptap/extension-text-style';
|
|
15
|
-
import Color from '@tiptap/extension-color';
|
|
5
|
+
import { StarterKit } from '@tiptap/starter-kit';
|
|
6
|
+
import { Placeholder } from '@tiptap/extension-placeholder';
|
|
7
|
+
import { CharacterCount } from '@tiptap/extension-character-count';
|
|
8
|
+
import { Underline } from '@tiptap/extension-underline';
|
|
9
|
+
import { Superscript } from '@tiptap/extension-superscript';
|
|
10
|
+
import { Subscript } from '@tiptap/extension-subscript';
|
|
11
|
+
import { TextAlign } from '@tiptap/extension-text-align';
|
|
12
|
+
import { Link } from '@tiptap/extension-link';
|
|
13
|
+
import { Highlight } from '@tiptap/extension-highlight';
|
|
14
|
+
import { TextStyle } from '@tiptap/extension-text-style';
|
|
15
|
+
import { Color } from '@tiptap/extension-color';
|
|
16
16
|
import OfficePaste from '@intevation/tiptap-extension-office-paste';
|
|
17
17
|
import { Plugin, PluginKey, TextSelection, NodeSelection } from '@tiptap/pm/state';
|
|
18
18
|
import { DecorationSet, Decoration } from '@tiptap/pm/view';
|
|
19
|
-
import Table from '@tiptap/extension-table';
|
|
20
|
-
import TableRow from '@tiptap/extension-table-row';
|
|
21
|
-
import TableCell from '@tiptap/extension-table-cell';
|
|
22
|
-
import TableHeader from '@tiptap/extension-table-header';
|
|
23
|
-
import { isObservable, firstValueFrom, concat, defer, of, tap
|
|
19
|
+
import { Table } from '@tiptap/extension-table';
|
|
20
|
+
import { TableRow } from '@tiptap/extension-table-row';
|
|
21
|
+
import { TableCell } from '@tiptap/extension-table-cell';
|
|
22
|
+
import { TableHeader } from '@tiptap/extension-table-header';
|
|
23
|
+
import { isObservable, firstValueFrom, Subscription, concat, defer, of, tap } from 'rxjs';
|
|
24
24
|
import { CommonModule } from '@angular/common';
|
|
25
25
|
import tippy, { sticky } from 'tippy.js';
|
|
26
26
|
import * as i1 from '@angular/forms';
|
|
@@ -687,23 +687,23 @@ const AteTiptapStateExtension = Extension.create({
|
|
|
687
687
|
class AteButtonComponent {
|
|
688
688
|
constructor() {
|
|
689
689
|
// Inputs
|
|
690
|
-
this.icon = input(""
|
|
691
|
-
this.title = input.required(
|
|
692
|
-
this.active = input(false
|
|
693
|
-
this.disabled = input(false
|
|
694
|
-
this.color = input(
|
|
695
|
-
this.backgroundColor = input(
|
|
696
|
-
this.variant = input("default"
|
|
697
|
-
this.size = input("medium"
|
|
698
|
-
this.iconSize = input("medium"
|
|
690
|
+
this.icon = input("");
|
|
691
|
+
this.title = input.required();
|
|
692
|
+
this.active = input(false);
|
|
693
|
+
this.disabled = input(false);
|
|
694
|
+
this.color = input();
|
|
695
|
+
this.backgroundColor = input();
|
|
696
|
+
this.variant = input("default");
|
|
697
|
+
this.size = input("medium");
|
|
698
|
+
this.iconSize = input("medium");
|
|
699
699
|
// Outputs
|
|
700
700
|
this.buttonClick = output();
|
|
701
701
|
}
|
|
702
702
|
onMouseDown(event) {
|
|
703
703
|
event.preventDefault();
|
|
704
704
|
}
|
|
705
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
706
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
705
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
706
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AteButtonComponent, isStandalone: true, selector: "ate-button", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, backgroundColor: { classPropertyName: "backgroundColor", publicName: "backgroundColor", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, iconSize: { classPropertyName: "iconSize", publicName: "iconSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { buttonClick: "buttonClick" }, ngImport: i0, template: `
|
|
707
707
|
<button
|
|
708
708
|
class="ate-button"
|
|
709
709
|
[class.is-active]="active()"
|
|
@@ -736,7 +736,7 @@ class AteButtonComponent {
|
|
|
736
736
|
</button>
|
|
737
737
|
`, isInline: true, styles: [".ate-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:var(--ate-sub-border-radius, 8px);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);color:var(--ate-toolbar-button-color, var(--ate-text-secondary));position:relative;overflow:hidden}.ate-button:before{content:\"\";position:absolute;inset:0;background:var(--ate-primary);opacity:0;transition:opacity .2s ease;border-radius:var(--ate-sub-border-radius, 8px)}.ate-button:hover:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.ate-button.has-custom-color:hover:not(.has-custom-bg){background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.ate-button.has-custom-bg:hover{transform:translateY(-1px);filter:brightness(.9)}.ate-button:hover:before{opacity:.1}.ate-button:active{transform:translateY(0)}.ate-button.is-active:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.ate-button.is-active.has-custom-color{background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.ate-button:disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ate-button .material-symbols-outlined{font-size:20px;position:relative;z-index:1}.ate-button .material-symbols-outlined.icon-small{font-size:16px}.ate-button .material-symbols-outlined.icon-medium{font-size:20px}.ate-button .material-symbols-outlined.icon-large{font-size:24px}.ate-button.text-button{width:auto;padding:0 12px;font-size:14px;font-weight:500;gap:8px}.ate-button.color-button{width:28px;height:28px;border-radius:50%;border:2px solid transparent;transition:all .2s ease}.ate-button.color-button:hover{border-color:var(--ate-border);transform:scale(1.1)}.ate-button.color-button.is-active{border-color:var(--ate-primary);box-shadow:0 0 0 2px var(--ate-primary-light)}.ate-button.danger{color:var(--ate-error-color, #ef4444)}.ate-button.danger:hover{color:var(--ate-error-color, #ef4444);background:var(--ate-error-bg, rgba(239, 68, 68, .1))}.ate-button.danger:before{background:var(--ate-error-color, #ef4444)}.ate-button.small{width:24px;height:24px}.ate-button.medium{width:32px;height:32px}.ate-button.large{width:40px;height:40px}@keyframes pulse{0%,to{box-shadow:0 0 0 0 var(--ate-primary-light-alpha)}50%{box-shadow:0 0 0 4px transparent}}.ate-button.is-active.pulse{animation:pulse 2s infinite}@media (max-width: 768px){.ate-button{width:32px;height:32px}.ate-button .material-symbols-outlined{font-size:18px}.ate-button.text-button{padding:0 8px;font-size:13px}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
738
738
|
}
|
|
739
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
739
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteButtonComponent, decorators: [{
|
|
740
740
|
type: Component,
|
|
741
741
|
args: [{ selector: "ate-button", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
742
742
|
<button
|
|
@@ -770,15 +770,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
770
770
|
<ng-content></ng-content>
|
|
771
771
|
</button>
|
|
772
772
|
`, styles: [".ate-button{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:var(--ate-sub-border-radius, 8px);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);color:var(--ate-toolbar-button-color, var(--ate-text-secondary));position:relative;overflow:hidden}.ate-button:before{content:\"\";position:absolute;inset:0;background:var(--ate-primary);opacity:0;transition:opacity .2s ease;border-radius:var(--ate-sub-border-radius, 8px)}.ate-button:hover:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.ate-button.has-custom-color:hover:not(.has-custom-bg){background:var(--ate-toolbar-button-hover-background, transparent);transform:translateY(-1px)}.ate-button.has-custom-bg:hover{transform:translateY(-1px);filter:brightness(.9)}.ate-button:hover:before{opacity:.1}.ate-button:active{transform:translateY(0)}.ate-button.is-active:not(.has-custom-color){color:var(--ate-toolbar-button-active-color, var(--ate-primary));background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.ate-button.is-active.has-custom-color{background:var(--ate-toolbar-button-active-background, var(--ate-primary-light))}.ate-button:disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ate-button .material-symbols-outlined{font-size:20px;position:relative;z-index:1}.ate-button .material-symbols-outlined.icon-small{font-size:16px}.ate-button .material-symbols-outlined.icon-medium{font-size:20px}.ate-button .material-symbols-outlined.icon-large{font-size:24px}.ate-button.text-button{width:auto;padding:0 12px;font-size:14px;font-weight:500;gap:8px}.ate-button.color-button{width:28px;height:28px;border-radius:50%;border:2px solid transparent;transition:all .2s ease}.ate-button.color-button:hover{border-color:var(--ate-border);transform:scale(1.1)}.ate-button.color-button.is-active{border-color:var(--ate-primary);box-shadow:0 0 0 2px var(--ate-primary-light)}.ate-button.danger{color:var(--ate-error-color, #ef4444)}.ate-button.danger:hover{color:var(--ate-error-color, #ef4444);background:var(--ate-error-bg, rgba(239, 68, 68, .1))}.ate-button.danger:before{background:var(--ate-error-color, #ef4444)}.ate-button.small{width:24px;height:24px}.ate-button.medium{width:32px;height:32px}.ate-button.large{width:40px;height:40px}@keyframes pulse{0%,to{box-shadow:0 0 0 0 var(--ate-primary-light-alpha)}50%{box-shadow:0 0 0 4px transparent}}.ate-button.is-active.pulse{animation:pulse 2s infinite}@media (max-width: 768px){.ate-button{width:32px;height:32px}.ate-button .material-symbols-outlined{font-size:18px}.ate-button.text-button{padding:0 8px;font-size:13px}}\n"] }]
|
|
773
|
-
}]
|
|
773
|
+
}] });
|
|
774
774
|
|
|
775
775
|
class AteSeparatorComponent {
|
|
776
776
|
constructor() {
|
|
777
|
-
this.orientation = input("vertical"
|
|
778
|
-
this.size = input("medium"
|
|
777
|
+
this.orientation = input("vertical");
|
|
778
|
+
this.size = input("medium");
|
|
779
779
|
}
|
|
780
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
781
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
780
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteSeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
781
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.14", type: AteSeparatorComponent, isStandalone: true, selector: "ate-separator", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
782
782
|
<div
|
|
783
783
|
class="ate-separator"
|
|
784
784
|
[class.vertical]="orientation() === 'vertical'"
|
|
@@ -788,7 +788,7 @@ class AteSeparatorComponent {
|
|
|
788
788
|
[class.large]="size() === 'large'"></div>
|
|
789
789
|
`, isInline: true, styles: [".ate-separator{background-color:var(--ate-border, #e2e8f0);margin:0}.ate-separator.vertical{width:1px;height:24px;margin:0 8px}.ate-separator.horizontal{height:1px;width:100%;margin:8px 0}.ate-separator.small.vertical{height:16px;margin:0 4px}.ate-separator.small.horizontal{margin:4px 0}.ate-separator.medium.vertical{height:24px;margin:0 8px}.ate-separator.medium.horizontal{margin:8px 0}.ate-separator.large.vertical{height:32px;margin:0 12px}.ate-separator.large.horizontal{margin:12px 0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
790
790
|
}
|
|
791
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
791
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteSeparatorComponent, decorators: [{
|
|
792
792
|
type: Component,
|
|
793
793
|
args: [{ selector: "ate-separator", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
794
794
|
<div
|
|
@@ -799,7 +799,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
799
799
|
[class.medium]="size() === 'medium'"
|
|
800
800
|
[class.large]="size() === 'large'"></div>
|
|
801
801
|
`, styles: [".ate-separator{background-color:var(--ate-border, #e2e8f0);margin:0}.ate-separator.vertical{width:1px;height:24px;margin:0 8px}.ate-separator.horizontal{height:1px;width:100%;margin:8px 0}.ate-separator.small.vertical{height:16px;margin:0 4px}.ate-separator.small.horizontal{margin:4px 0}.ate-separator.medium.vertical{height:24px;margin:0 8px}.ate-separator.medium.horizontal{margin:8px 0}.ate-separator.large.vertical{height:32px;margin:0 12px}.ate-separator.large.horizontal{margin:12px 0}\n"] }]
|
|
802
|
-
}]
|
|
802
|
+
}] });
|
|
803
803
|
|
|
804
804
|
const ENGLISH_TRANSLATIONS = {
|
|
805
805
|
toolbar: {
|
|
@@ -1137,25 +1137,25 @@ const FRENCH_TRANSLATIONS = {
|
|
|
1137
1137
|
};
|
|
1138
1138
|
class AteI18nService {
|
|
1139
1139
|
constructor() {
|
|
1140
|
-
this._currentLocale = signal("en"
|
|
1140
|
+
this._currentLocale = signal("en");
|
|
1141
1141
|
this._translations = signal({
|
|
1142
1142
|
en: ENGLISH_TRANSLATIONS,
|
|
1143
1143
|
fr: FRENCH_TRANSLATIONS,
|
|
1144
|
-
}
|
|
1144
|
+
});
|
|
1145
1145
|
// Public signals
|
|
1146
1146
|
this.currentLocale = this._currentLocale.asReadonly();
|
|
1147
1147
|
/** All loaded translations (useful for dynamic key access) */
|
|
1148
1148
|
this.allTranslations = this._translations.asReadonly();
|
|
1149
|
-
this.translations = computed(() => this._translations()[this._currentLocale()]
|
|
1149
|
+
this.translations = computed(() => this._translations()[this._currentLocale()]);
|
|
1150
1150
|
// Fast translation methods
|
|
1151
|
-
this.t = computed(() => this.translations()
|
|
1152
|
-
this.toolbar = computed(() => this.translations().toolbar
|
|
1153
|
-
this.bubbleMenu = computed(() => this.translations().bubbleMenu
|
|
1154
|
-
this.slashCommands = computed(() => this.translations().slashCommands
|
|
1155
|
-
this.table = computed(() => this.translations().table
|
|
1156
|
-
this.imageUpload = computed(() => this.translations().imageUpload
|
|
1157
|
-
this.editor = computed(() => this.translations().editor
|
|
1158
|
-
this.common = computed(() => this.translations().common
|
|
1151
|
+
this.t = computed(() => this.translations());
|
|
1152
|
+
this.toolbar = computed(() => this.translations().toolbar);
|
|
1153
|
+
this.bubbleMenu = computed(() => this.translations().bubbleMenu);
|
|
1154
|
+
this.slashCommands = computed(() => this.translations().slashCommands);
|
|
1155
|
+
this.table = computed(() => this.translations().table);
|
|
1156
|
+
this.imageUpload = computed(() => this.translations().imageUpload);
|
|
1157
|
+
this.editor = computed(() => this.translations().editor);
|
|
1158
|
+
this.common = computed(() => this.translations().common);
|
|
1159
1159
|
// Automatically detect browser language
|
|
1160
1160
|
this.detectBrowserLanguage();
|
|
1161
1161
|
}
|
|
@@ -1199,10 +1199,10 @@ class AteI18nService {
|
|
|
1199
1199
|
getSlashCommand(key) {
|
|
1200
1200
|
return this.translations().slashCommands[key];
|
|
1201
1201
|
}
|
|
1202
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1203
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1202
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteI18nService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1203
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteI18nService, providedIn: "root" }); }
|
|
1204
1204
|
}
|
|
1205
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1205
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteI18nService, decorators: [{
|
|
1206
1206
|
type: Injectable,
|
|
1207
1207
|
args: [{
|
|
1208
1208
|
providedIn: "root",
|
|
@@ -1212,16 +1212,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1212
1212
|
class AteImageService {
|
|
1213
1213
|
constructor() {
|
|
1214
1214
|
/** Signals for image state */
|
|
1215
|
-
this.selectedImage = signal(null
|
|
1216
|
-
this.isImageSelected = computed(() => this.selectedImage() !== null
|
|
1215
|
+
this.selectedImage = signal(null);
|
|
1216
|
+
this.isImageSelected = computed(() => this.selectedImage() !== null);
|
|
1217
1217
|
/** Resizing state */
|
|
1218
|
-
this.isResizing = signal(false
|
|
1218
|
+
this.isResizing = signal(false);
|
|
1219
1219
|
this.i18n = inject(AteI18nService);
|
|
1220
1220
|
this.t = this.i18n.imageUpload;
|
|
1221
1221
|
/** Upload state signals */
|
|
1222
|
-
this.isUploading = signal(false
|
|
1223
|
-
this.uploadProgress = signal(0
|
|
1224
|
-
this.uploadMessage = signal(""
|
|
1222
|
+
this.isUploading = signal(false);
|
|
1223
|
+
this.uploadProgress = signal(0);
|
|
1224
|
+
this.uploadMessage = signal("");
|
|
1225
1225
|
/**
|
|
1226
1226
|
* Custom upload handler.
|
|
1227
1227
|
* If set, this handler replaces the default base64 conversion.
|
|
@@ -1566,10 +1566,10 @@ class AteImageService {
|
|
|
1566
1566
|
this.selectImage(ed);
|
|
1567
1567
|
}, this.t().replacingImage, options);
|
|
1568
1568
|
}
|
|
1569
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1570
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1569
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1570
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageService }); }
|
|
1571
1571
|
}
|
|
1572
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1572
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageService, decorators: [{
|
|
1573
1573
|
type: Injectable
|
|
1574
1574
|
}] });
|
|
1575
1575
|
|
|
@@ -1640,11 +1640,11 @@ class AteColorPickerService {
|
|
|
1640
1640
|
// State Signals (owned by this service)
|
|
1641
1641
|
// ============================================
|
|
1642
1642
|
/** Current edit mode: null when closed, 'text' or 'highlight' when open */
|
|
1643
|
-
this.editMode = signal(null
|
|
1643
|
+
this.editMode = signal(null);
|
|
1644
1644
|
/** Reference to the element that triggered the menu (for anchoring) */
|
|
1645
|
-
this.menuTrigger = signal(null
|
|
1645
|
+
this.menuTrigger = signal(null);
|
|
1646
1646
|
/** Whether the user is currently interacting with the picker UI (e.g. typing) */
|
|
1647
|
-
this.isInteracting = signal(false
|
|
1647
|
+
this.isInteracting = signal(false);
|
|
1648
1648
|
}
|
|
1649
1649
|
// ============================================
|
|
1650
1650
|
// Menu Lifecycle Methods
|
|
@@ -1816,10 +1816,10 @@ class AteColorPickerService {
|
|
|
1816
1816
|
getContrastColor(color) {
|
|
1817
1817
|
return getContrastColor(color);
|
|
1818
1818
|
}
|
|
1819
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1820
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1819
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteColorPickerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1820
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteColorPickerService }); }
|
|
1821
1821
|
}
|
|
1822
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1822
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteColorPickerService, decorators: [{
|
|
1823
1823
|
type: Injectable
|
|
1824
1824
|
}] });
|
|
1825
1825
|
|
|
@@ -1829,11 +1829,11 @@ class AteLinkService {
|
|
|
1829
1829
|
// State Signals (owned by this service)
|
|
1830
1830
|
// ============================================
|
|
1831
1831
|
/** Whether link edit mode is active */
|
|
1832
|
-
this.editMode = signal(false
|
|
1832
|
+
this.editMode = signal(false);
|
|
1833
1833
|
/** Reference to the element that triggered the menu (for anchoring) */
|
|
1834
|
-
this.menuTrigger = signal(null
|
|
1834
|
+
this.menuTrigger = signal(null);
|
|
1835
1835
|
/** Whether the user is currently interacting with the link UI (input focus) */
|
|
1836
|
-
this.isInteracting = signal(false
|
|
1836
|
+
this.isInteracting = signal(false);
|
|
1837
1837
|
}
|
|
1838
1838
|
// ============================================
|
|
1839
1839
|
// Menu Lifecycle Methods
|
|
@@ -1911,10 +1911,10 @@ class AteLinkService {
|
|
|
1911
1911
|
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
1912
1912
|
this.close();
|
|
1913
1913
|
}
|
|
1914
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1915
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1914
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1915
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkService }); }
|
|
1916
1916
|
}
|
|
1917
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1917
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkService, decorators: [{
|
|
1918
1918
|
type: Injectable
|
|
1919
1919
|
}] });
|
|
1920
1920
|
|
|
@@ -1923,90 +1923,53 @@ class AteEditorCommandsService {
|
|
|
1923
1923
|
this.imageService = inject(AteImageService);
|
|
1924
1924
|
this.colorPickerSvc = inject(AteColorPickerService);
|
|
1925
1925
|
this.linkSvc = inject(AteLinkService);
|
|
1926
|
-
this._editorState = signal(ATE_INITIAL_EDITOR_STATE,
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
}
|
|
1946
|
-
return keysA.every(key => objA[key] === objB[key]);
|
|
1947
|
-
};
|
|
1948
|
-
// 3. Compare sub-states (marks, can, nodes)
|
|
1949
|
-
if (!isRecordEqual(a.marks, b.marks)) {
|
|
1950
|
-
return false;
|
|
1951
|
-
}
|
|
1952
|
-
if (!isRecordEqual(a.can, b.can)) {
|
|
1953
|
-
return false;
|
|
1954
|
-
}
|
|
1955
|
-
if (!isRecordEqual(a.nodes, b.nodes)) {
|
|
1956
|
-
return false;
|
|
1957
|
-
}
|
|
1958
|
-
// 4. Compare custom extension states
|
|
1959
|
-
if (!isRecordEqual(a.custom, b.custom)) {
|
|
1960
|
-
return false;
|
|
1961
|
-
}
|
|
1962
|
-
return true;
|
|
1963
|
-
} }] : [{
|
|
1964
|
-
equal: (a, b) => {
|
|
1965
|
-
// 1. Primitive global states
|
|
1966
|
-
if (a.isFocused !== b.isFocused || a.isEditable !== b.isEditable) {
|
|
1967
|
-
return false;
|
|
1968
|
-
}
|
|
1969
|
-
// 2. Detailed selection comparison
|
|
1970
|
-
if (a.selection.from !== b.selection.from ||
|
|
1971
|
-
a.selection.to !== b.selection.to ||
|
|
1972
|
-
a.selection.type !== b.selection.type ||
|
|
1973
|
-
a.selection.empty !== b.selection.empty ||
|
|
1974
|
-
a.selection.isSingleCell !== b.selection.isSingleCell) {
|
|
1975
|
-
return false;
|
|
1976
|
-
}
|
|
1977
|
-
// Helper for object comparison
|
|
1978
|
-
const isRecordEqual = (objA, objB) => {
|
|
1979
|
-
const keysA = Object.keys(objA);
|
|
1980
|
-
const keysB = Object.keys(objB);
|
|
1981
|
-
if (keysA.length !== keysB.length) {
|
|
1982
|
-
return false;
|
|
1983
|
-
}
|
|
1984
|
-
return keysA.every(key => objA[key] === objB[key]);
|
|
1985
|
-
};
|
|
1986
|
-
// 3. Compare sub-states (marks, can, nodes)
|
|
1987
|
-
if (!isRecordEqual(a.marks, b.marks)) {
|
|
1988
|
-
return false;
|
|
1989
|
-
}
|
|
1990
|
-
if (!isRecordEqual(a.can, b.can)) {
|
|
1991
|
-
return false;
|
|
1992
|
-
}
|
|
1993
|
-
if (!isRecordEqual(a.nodes, b.nodes)) {
|
|
1994
|
-
return false;
|
|
1995
|
-
}
|
|
1996
|
-
// 4. Compare custom extension states
|
|
1997
|
-
if (!isRecordEqual(a.custom, b.custom)) {
|
|
1926
|
+
this._editorState = signal(ATE_INITIAL_EDITOR_STATE, {
|
|
1927
|
+
equal: (a, b) => {
|
|
1928
|
+
// 1. Primitive global states
|
|
1929
|
+
if (a.isFocused !== b.isFocused || a.isEditable !== b.isEditable) {
|
|
1930
|
+
return false;
|
|
1931
|
+
}
|
|
1932
|
+
// 2. Detailed selection comparison
|
|
1933
|
+
if (a.selection.from !== b.selection.from ||
|
|
1934
|
+
a.selection.to !== b.selection.to ||
|
|
1935
|
+
a.selection.type !== b.selection.type ||
|
|
1936
|
+
a.selection.empty !== b.selection.empty ||
|
|
1937
|
+
a.selection.isSingleCell !== b.selection.isSingleCell) {
|
|
1938
|
+
return false;
|
|
1939
|
+
}
|
|
1940
|
+
// Helper for object comparison
|
|
1941
|
+
const isRecordEqual = (objA, objB) => {
|
|
1942
|
+
const keysA = Object.keys(objA);
|
|
1943
|
+
const keysB = Object.keys(objB);
|
|
1944
|
+
if (keysA.length !== keysB.length) {
|
|
1998
1945
|
return false;
|
|
1999
1946
|
}
|
|
2000
|
-
return
|
|
2001
|
-
}
|
|
2002
|
-
|
|
1947
|
+
return keysA.every(key => objA[key] === objB[key]);
|
|
1948
|
+
};
|
|
1949
|
+
// 3. Compare sub-states (marks, can, nodes)
|
|
1950
|
+
if (!isRecordEqual(a.marks, b.marks)) {
|
|
1951
|
+
return false;
|
|
1952
|
+
}
|
|
1953
|
+
if (!isRecordEqual(a.can, b.can)) {
|
|
1954
|
+
return false;
|
|
1955
|
+
}
|
|
1956
|
+
if (!isRecordEqual(a.nodes, b.nodes)) {
|
|
1957
|
+
return false;
|
|
1958
|
+
}
|
|
1959
|
+
// 4. Compare custom extension states
|
|
1960
|
+
if (!isRecordEqual(a.custom, b.custom)) {
|
|
1961
|
+
return false;
|
|
1962
|
+
}
|
|
1963
|
+
return true;
|
|
1964
|
+
},
|
|
1965
|
+
});
|
|
2003
1966
|
/** Exposed editor state as a readonly signal */
|
|
2004
1967
|
this.editorState = this._editorState.asReadonly();
|
|
2005
1968
|
// ============================================
|
|
2006
1969
|
// Toolbar Interaction State
|
|
2007
1970
|
// ============================================
|
|
2008
1971
|
/** Signal to track when the toolbar is being hovered/interacted with */
|
|
2009
|
-
this._isToolbarInteracting = signal(false
|
|
1972
|
+
this._isToolbarInteracting = signal(false);
|
|
2010
1973
|
this.isToolbarInteracting = this._isToolbarInteracting.asReadonly();
|
|
2011
1974
|
// Access to ImageService states as readonly signals for UI binding
|
|
2012
1975
|
this.isUploading = this.imageService.isUploading.asReadonly();
|
|
@@ -2407,19 +2370,19 @@ class AteEditorCommandsService {
|
|
|
2407
2370
|
throw error;
|
|
2408
2371
|
}
|
|
2409
2372
|
}
|
|
2410
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2411
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2373
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteEditorCommandsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2374
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteEditorCommandsService }); }
|
|
2412
2375
|
}
|
|
2413
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2376
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteEditorCommandsService, decorators: [{
|
|
2414
2377
|
type: Injectable
|
|
2415
2378
|
}] });
|
|
2416
2379
|
|
|
2417
2380
|
class AteColorPickerComponent {
|
|
2418
2381
|
constructor() {
|
|
2419
|
-
this.editor = input.required(
|
|
2420
|
-
this.mode = input("text"
|
|
2421
|
-
this.disabled = input(false
|
|
2422
|
-
this.anchorToText = input(false
|
|
2382
|
+
this.editor = input.required();
|
|
2383
|
+
this.mode = input("text");
|
|
2384
|
+
this.disabled = input(false);
|
|
2385
|
+
this.anchorToText = input(false);
|
|
2423
2386
|
this.colorPickerSvc = inject(AteColorPickerService);
|
|
2424
2387
|
this.i18nService = inject(AteI18nService);
|
|
2425
2388
|
this.editorCommands = inject(AteEditorCommandsService);
|
|
@@ -2429,14 +2392,14 @@ class AteColorPickerComponent {
|
|
|
2429
2392
|
const marks = this.state().marks;
|
|
2430
2393
|
const color = this.mode() === "text" ? marks.computedColor : marks.computedBackground;
|
|
2431
2394
|
return color || (this.mode() === "text" ? "#000000" : "#ffff00");
|
|
2432
|
-
}
|
|
2395
|
+
});
|
|
2433
2396
|
this.hasColorApplied = computed(() => {
|
|
2434
2397
|
const marks = this.state().marks;
|
|
2435
2398
|
return (this.mode() === "text" ? marks.color : marks.background) !== null;
|
|
2436
|
-
}
|
|
2399
|
+
});
|
|
2437
2400
|
this.buttonIcon = computed(() => {
|
|
2438
2401
|
return this.mode() === "text" ? "format_color_text" : "format_color_fill";
|
|
2439
|
-
}
|
|
2402
|
+
});
|
|
2440
2403
|
this.buttonBgColor = computed(() => {
|
|
2441
2404
|
const color = this.currentColor();
|
|
2442
2405
|
if (this.mode() === "highlight") {
|
|
@@ -2447,7 +2410,7 @@ class AteColorPickerComponent {
|
|
|
2447
2410
|
return "#030617";
|
|
2448
2411
|
}
|
|
2449
2412
|
return "";
|
|
2450
|
-
}
|
|
2413
|
+
});
|
|
2451
2414
|
this.buttonTextColor = computed(() => {
|
|
2452
2415
|
const color = this.currentColor();
|
|
2453
2416
|
if (this.mode() === "text") {
|
|
@@ -2457,7 +2420,7 @@ class AteColorPickerComponent {
|
|
|
2457
2420
|
return this.colorPickerSvc.getLuminance(color) > 128 ? "#000000" : "#ffffff";
|
|
2458
2421
|
}
|
|
2459
2422
|
return "var(--ate-text-secondary)";
|
|
2460
|
-
}
|
|
2423
|
+
});
|
|
2461
2424
|
}
|
|
2462
2425
|
onToggle(event) {
|
|
2463
2426
|
// If anchorToText is true, we don't pass the event so it defaults to text selection anchoring
|
|
@@ -2475,8 +2438,8 @@ class AteColorPickerComponent {
|
|
|
2475
2438
|
}
|
|
2476
2439
|
this.colorPickerSvc.close();
|
|
2477
2440
|
}
|
|
2478
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2479
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2441
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteColorPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2442
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AteColorPickerComponent, isStandalone: true, selector: "ate-color-picker", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, anchorToText: { classPropertyName: "anchorToText", publicName: "anchorToText", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2480
2443
|
<div class="color-picker-wrapper">
|
|
2481
2444
|
<div class="color-picker-container" [class.is-highlight]="mode() === 'highlight'">
|
|
2482
2445
|
<ate-button
|
|
@@ -2501,7 +2464,7 @@ class AteColorPickerComponent {
|
|
|
2501
2464
|
</div>
|
|
2502
2465
|
`, isInline: true, styles: [".color-picker-wrapper{position:relative;display:inline-block}.color-picker-container{position:relative;display:inline-flex;align-items:center}.btn-clear-badge{position:absolute;top:-4px;right:-4px;width:14px;height:14px;padding:0;border:none;border-radius:999px;background:#0f172abf;color:#fff;display:flex;align-items:center;justify-content:center;z-index:10;opacity:0;pointer-events:none;transition:opacity .12s ease}.color-picker-container:hover .btn-clear-badge{opacity:1;pointer-events:auto}.btn-clear-badge .material-symbols-outlined{font-size:10px;line-height:1}\n"], dependencies: [{ kind: "component", type: AteButtonComponent, selector: "ate-button", inputs: ["icon", "title", "active", "disabled", "color", "backgroundColor", "variant", "size", "iconSize"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2503
2466
|
}
|
|
2504
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2467
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteColorPickerComponent, decorators: [{
|
|
2505
2468
|
type: Component,
|
|
2506
2469
|
args: [{ selector: "ate-color-picker", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [AteButtonComponent, CommonModule], template: `
|
|
2507
2470
|
<div class="color-picker-wrapper">
|
|
@@ -2527,14 +2490,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
2527
2490
|
</div>
|
|
2528
2491
|
</div>
|
|
2529
2492
|
`, styles: [".color-picker-wrapper{position:relative;display:inline-block}.color-picker-container{position:relative;display:inline-flex;align-items:center}.btn-clear-badge{position:absolute;top:-4px;right:-4px;width:14px;height:14px;padding:0;border:none;border-radius:999px;background:#0f172abf;color:#fff;display:flex;align-items:center;justify-content:center;z-index:10;opacity:0;pointer-events:none;transition:opacity .12s ease}.color-picker-container:hover .btn-clear-badge{opacity:1;pointer-events:auto}.btn-clear-badge .material-symbols-outlined{font-size:10px;line-height:1}\n"] }]
|
|
2530
|
-
}]
|
|
2493
|
+
}] });
|
|
2531
2494
|
|
|
2532
2495
|
class AteToolbarComponent {
|
|
2533
2496
|
constructor() {
|
|
2534
|
-
this.editor = input.required(
|
|
2535
|
-
this.config = input.required(
|
|
2536
|
-
this.imageUpload = input({}
|
|
2537
|
-
this.floating = input(false
|
|
2497
|
+
this.editor = input.required();
|
|
2498
|
+
this.config = input.required();
|
|
2499
|
+
this.imageUpload = input({});
|
|
2500
|
+
this.floating = input(false);
|
|
2538
2501
|
this.i18nService = inject(AteI18nService);
|
|
2539
2502
|
this.editorCommands = inject(AteEditorCommandsService);
|
|
2540
2503
|
this.t = this.i18nService.toolbar;
|
|
@@ -2547,8 +2510,8 @@ class AteToolbarComponent {
|
|
|
2547
2510
|
}
|
|
2548
2511
|
this.editorCommands.execute(editor, command, ...args);
|
|
2549
2512
|
}
|
|
2550
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2551
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
2513
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2514
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AteToolbarComponent, isStandalone: true, selector: "ate-toolbar", inputs: { editor: { classPropertyName: "editor", publicName: "editor", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null }, floating: { classPropertyName: "floating", publicName: "floating", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2552
2515
|
<div class="ate-toolbar" [class.floating]="floating()">
|
|
2553
2516
|
@if (config().bold) {
|
|
2554
2517
|
<ate-button
|
|
@@ -2799,7 +2762,7 @@ class AteToolbarComponent {
|
|
|
2799
2762
|
</div>
|
|
2800
2763
|
`, 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 }); }
|
|
2801
2764
|
}
|
|
2802
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2765
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteToolbarComponent, decorators: [{
|
|
2803
2766
|
type: Component,
|
|
2804
2767
|
args: [{ selector: "ate-toolbar", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [AteButtonComponent, AteSeparatorComponent, AteColorPickerComponent], template: `
|
|
2805
2768
|
<div class="ate-toolbar" [class.floating]="floating()">
|
|
@@ -3051,7 +3014,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3051
3014
|
}
|
|
3052
3015
|
</div>
|
|
3053
3016
|
`, 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"] }]
|
|
3054
|
-
}]
|
|
3017
|
+
}] });
|
|
3055
3018
|
|
|
3056
3019
|
/**
|
|
3057
3020
|
* Base abstract class for all Bubble Menus (Text, Image, Table, Cell).
|
|
@@ -3062,7 +3025,7 @@ class AteBaseBubbleMenu {
|
|
|
3062
3025
|
this.i18nService = inject(AteI18nService);
|
|
3063
3026
|
this.editorCommands = inject(AteEditorCommandsService);
|
|
3064
3027
|
// Core Inputs
|
|
3065
|
-
this.editor = input.required(
|
|
3028
|
+
this.editor = input.required();
|
|
3066
3029
|
// Required viewChild for the menu container
|
|
3067
3030
|
this.menuRef = viewChild.required("menuRef");
|
|
3068
3031
|
// Internal State
|
|
@@ -3106,7 +3069,7 @@ class AteBaseBubbleMenu {
|
|
|
3106
3069
|
this.editorCommands.linkEditMode();
|
|
3107
3070
|
this.editorCommands.colorEditMode();
|
|
3108
3071
|
this.updateMenu();
|
|
3109
|
-
});
|
|
3072
|
+
}, { allowSignalWrites: true });
|
|
3110
3073
|
}
|
|
3111
3074
|
ngOnInit() {
|
|
3112
3075
|
this.initTippy();
|
|
@@ -3248,12 +3211,12 @@ class AteBaseBubbleMenu {
|
|
|
3248
3211
|
onTippyHide(_instance) {
|
|
3249
3212
|
/* empty */
|
|
3250
3213
|
}
|
|
3251
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3252
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "
|
|
3214
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteBaseBubbleMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3215
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "18.2.14", type: AteBaseBubbleMenu, 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 }); }
|
|
3253
3216
|
}
|
|
3254
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3217
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteBaseBubbleMenu, decorators: [{
|
|
3255
3218
|
type: Directive
|
|
3256
|
-
}], ctorParameters: () => []
|
|
3219
|
+
}], ctorParameters: () => [] });
|
|
3257
3220
|
|
|
3258
3221
|
class AteBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
3259
3222
|
constructor() {
|
|
@@ -3274,7 +3237,7 @@ class AteBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3274
3237
|
textColor: false,
|
|
3275
3238
|
link: true,
|
|
3276
3239
|
separator: true,
|
|
3277
|
-
}
|
|
3240
|
+
});
|
|
3278
3241
|
this.bubbleMenuConfig = computed(() => ({
|
|
3279
3242
|
bold: true,
|
|
3280
3243
|
italic: true,
|
|
@@ -3288,7 +3251,7 @@ class AteBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3288
3251
|
link: true,
|
|
3289
3252
|
separator: true,
|
|
3290
3253
|
...this.config(),
|
|
3291
|
-
})
|
|
3254
|
+
}));
|
|
3292
3255
|
}
|
|
3293
3256
|
ngOnInit() {
|
|
3294
3257
|
super.ngOnInit();
|
|
@@ -3336,8 +3299,8 @@ class AteBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3336
3299
|
// Sub-menus now manage their own state. Clearing them here causes
|
|
3337
3300
|
// premature closing when clicking between 'sibling' menu instances.
|
|
3338
3301
|
}
|
|
3339
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3340
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
3302
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteBubbleMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
3303
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AteBubbleMenuComponent, isStandalone: true, selector: "ate-bubble-menu", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
|
|
3341
3304
|
<div #menuRef class="bubble-menu" (mousedown)="$event.preventDefault()">
|
|
3342
3305
|
@if (bubbleMenuConfig().bold) {
|
|
3343
3306
|
<ate-button
|
|
@@ -3436,7 +3399,7 @@ class AteBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3436
3399
|
</div>
|
|
3437
3400
|
`, 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 }); }
|
|
3438
3401
|
}
|
|
3439
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3402
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteBubbleMenuComponent, decorators: [{
|
|
3440
3403
|
type: Component,
|
|
3441
3404
|
args: [{
|
|
3442
3405
|
selector: "ate-bubble-menu",
|
|
@@ -3542,7 +3505,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3542
3505
|
</div>
|
|
3543
3506
|
`,
|
|
3544
3507
|
}]
|
|
3545
|
-
}]
|
|
3508
|
+
}] });
|
|
3546
3509
|
|
|
3547
3510
|
class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
3548
3511
|
constructor() {
|
|
@@ -3557,8 +3520,8 @@ class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3557
3520
|
resizeOriginal: true,
|
|
3558
3521
|
deleteImage: true,
|
|
3559
3522
|
separator: true,
|
|
3560
|
-
}
|
|
3561
|
-
this.imageUpload = input({}
|
|
3523
|
+
});
|
|
3524
|
+
this.imageUpload = input({});
|
|
3562
3525
|
this.imageBubbleMenuConfig = computed(() => ({
|
|
3563
3526
|
changeImage: this.config().changeImage ?? true,
|
|
3564
3527
|
resizeSmall: this.config().resizeSmall ?? true,
|
|
@@ -3567,11 +3530,11 @@ class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3567
3530
|
resizeOriginal: this.config().resizeOriginal ?? true,
|
|
3568
3531
|
deleteImage: this.config().deleteImage ?? true,
|
|
3569
3532
|
separator: this.config().separator ?? true,
|
|
3570
|
-
})
|
|
3533
|
+
}));
|
|
3571
3534
|
this.hasResizeButtons = computed(() => {
|
|
3572
3535
|
const c = this.imageBubbleMenuConfig();
|
|
3573
3536
|
return c.resizeSmall || c.resizeMedium || c.resizeLarge || c.resizeOriginal;
|
|
3574
|
-
}
|
|
3537
|
+
});
|
|
3575
3538
|
}
|
|
3576
3539
|
shouldShow() {
|
|
3577
3540
|
const { nodes, isEditable, isFocused } = this.state();
|
|
@@ -3652,8 +3615,8 @@ class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3652
3615
|
ed.chain().focus().deleteSelection().run();
|
|
3653
3616
|
}
|
|
3654
3617
|
}
|
|
3655
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3656
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
3618
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageBubbleMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
3619
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AteImageBubbleMenuComponent, isStandalone: true, selector: "ate-image-bubble-menu", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
|
|
3657
3620
|
<div #menuRef class="bubble-menu" (mousedown)="$event.preventDefault()">
|
|
3658
3621
|
@if (imageBubbleMenuConfig().changeImage) {
|
|
3659
3622
|
<ate-button
|
|
@@ -3704,7 +3667,7 @@ class AteImageBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3704
3667
|
</div>
|
|
3705
3668
|
`, 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: AteSeparatorComponent, selector: "ate-separator", inputs: ["orientation", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3706
3669
|
}
|
|
3707
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3670
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageBubbleMenuComponent, decorators: [{
|
|
3708
3671
|
type: Component,
|
|
3709
3672
|
args: [{
|
|
3710
3673
|
selector: "ate-image-bubble-menu",
|
|
@@ -3762,7 +3725,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
3762
3725
|
</div>
|
|
3763
3726
|
`,
|
|
3764
3727
|
}]
|
|
3765
|
-
}]
|
|
3728
|
+
}] });
|
|
3766
3729
|
|
|
3767
3730
|
class AteTableBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
3768
3731
|
constructor() {
|
|
@@ -3780,7 +3743,7 @@ class AteTableBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3780
3743
|
toggleHeaderRow: true,
|
|
3781
3744
|
toggleHeaderColumn: true,
|
|
3782
3745
|
separator: true,
|
|
3783
|
-
}
|
|
3746
|
+
});
|
|
3784
3747
|
}
|
|
3785
3748
|
shouldShow() {
|
|
3786
3749
|
const { selection, nodes, isEditable, isFocused } = this.state();
|
|
@@ -3836,8 +3799,8 @@ class AteTableBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3836
3799
|
executeCommand(editor, command, ...args) {
|
|
3837
3800
|
this.editorCommands.execute(editor, command, ...args);
|
|
3838
3801
|
}
|
|
3839
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3840
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
3802
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteTableBubbleMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
3803
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AteTableBubbleMenuComponent, isStandalone: true, selector: "ate-table-bubble-menu", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
|
|
3841
3804
|
<div #menuRef class="bubble-menu" (mousedown)="$event.preventDefault()">
|
|
3842
3805
|
<!-- Row actions -->
|
|
3843
3806
|
@if (config().addRowBefore !== false) {
|
|
@@ -3926,7 +3889,7 @@ class AteTableBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
3926
3889
|
</div>
|
|
3927
3890
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3928
3891
|
}
|
|
3929
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3892
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteTableBubbleMenuComponent, decorators: [{
|
|
3930
3893
|
type: Component,
|
|
3931
3894
|
args: [{
|
|
3932
3895
|
selector: "ate-table-bubble-menu",
|
|
@@ -4022,13 +3985,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4022
3985
|
</div>
|
|
4023
3986
|
`,
|
|
4024
3987
|
}]
|
|
4025
|
-
}]
|
|
3988
|
+
}] });
|
|
4026
3989
|
|
|
4027
3990
|
class AteCellBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
4028
3991
|
constructor() {
|
|
4029
3992
|
super(...arguments);
|
|
4030
3993
|
// Inputs
|
|
4031
|
-
this.config = input({}
|
|
3994
|
+
this.config = input({});
|
|
4032
3995
|
// Signals
|
|
4033
3996
|
this.i18n = () => this.i18nService;
|
|
4034
3997
|
}
|
|
@@ -4090,8 +4053,8 @@ class AteCellBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
4090
4053
|
executeCommand(editor, command, ...args) {
|
|
4091
4054
|
this.editorCommands.execute(editor, command, ...args);
|
|
4092
4055
|
}
|
|
4093
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4094
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
4056
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteCellBubbleMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
4057
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AteCellBubbleMenuComponent, isStandalone: true, selector: "ate-cell-bubble-menu", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
|
|
4095
4058
|
<div #menuRef class="bubble-menu" (mousedown)="$event.preventDefault()">
|
|
4096
4059
|
<!-- Cell specific actions -->
|
|
4097
4060
|
@if (config().mergeCells !== false && !state().selection.isSingleCell) {
|
|
@@ -4111,7 +4074,7 @@ class AteCellBubbleMenuComponent extends AteBaseBubbleMenu {
|
|
|
4111
4074
|
</div>
|
|
4112
4075
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AteButtonComponent, selector: "ate-button", inputs: ["icon", "title", "active", "disabled", "color", "backgroundColor", "variant", "size", "iconSize"], outputs: ["buttonClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4113
4076
|
}
|
|
4114
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4077
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteCellBubbleMenuComponent, decorators: [{
|
|
4115
4078
|
type: Component,
|
|
4116
4079
|
args: [{
|
|
4117
4080
|
selector: "ate-cell-bubble-menu",
|
|
@@ -4138,7 +4101,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4138
4101
|
</div>
|
|
4139
4102
|
`,
|
|
4140
4103
|
}]
|
|
4141
|
-
}]
|
|
4104
|
+
}] });
|
|
4142
4105
|
|
|
4143
4106
|
/**
|
|
4144
4107
|
* Base abstract class for Sub-Bubble Menus (Link, Color).
|
|
@@ -4149,7 +4112,7 @@ class AteBaseSubBubbleMenu {
|
|
|
4149
4112
|
this.i18nService = inject(AteI18nService);
|
|
4150
4113
|
this.editorCommands = inject(AteEditorCommandsService);
|
|
4151
4114
|
// Core Inputs
|
|
4152
|
-
this.editor = input.required(
|
|
4115
|
+
this.editor = input.required();
|
|
4153
4116
|
// Required viewChild for the menu container
|
|
4154
4117
|
this.menuRef = viewChild.required("menuRef");
|
|
4155
4118
|
// Internal State
|
|
@@ -4179,7 +4142,7 @@ class AteBaseSubBubbleMenu {
|
|
|
4179
4142
|
this.state();
|
|
4180
4143
|
this.onStateChange();
|
|
4181
4144
|
this.updateMenu();
|
|
4182
|
-
});
|
|
4145
|
+
}, { allowSignalWrites: true });
|
|
4183
4146
|
}
|
|
4184
4147
|
ngOnInit() {
|
|
4185
4148
|
this.initTippy();
|
|
@@ -4261,12 +4224,12 @@ class AteBaseSubBubbleMenu {
|
|
|
4261
4224
|
onTippyHide(_instance) {
|
|
4262
4225
|
/* empty */
|
|
4263
4226
|
}
|
|
4264
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4265
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "
|
|
4227
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteBaseSubBubbleMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
4228
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "18.2.14", type: AteBaseSubBubbleMenu, 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
4229
|
}
|
|
4267
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4230
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteBaseSubBubbleMenu, decorators: [{
|
|
4268
4231
|
type: Directive
|
|
4269
|
-
}], ctorParameters: () => []
|
|
4232
|
+
}], ctorParameters: () => [] });
|
|
4270
4233
|
|
|
4271
4234
|
class AteLinkBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
4272
4235
|
constructor() {
|
|
@@ -4274,8 +4237,8 @@ class AteLinkBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
4274
4237
|
this.linkSvc = inject(AteLinkService);
|
|
4275
4238
|
this.t = this.i18nService.bubbleMenu;
|
|
4276
4239
|
this.common = this.i18nService.common;
|
|
4277
|
-
this.linkInput = viewChild("linkInput"
|
|
4278
|
-
this.editUrl = signal(""
|
|
4240
|
+
this.linkInput = viewChild("linkInput");
|
|
4241
|
+
this.editUrl = signal("");
|
|
4279
4242
|
// Reactive effect for URL sync
|
|
4280
4243
|
effect(() => {
|
|
4281
4244
|
const state = this.state();
|
|
@@ -4287,7 +4250,7 @@ class AteLinkBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
4287
4250
|
if (!isInteracting) {
|
|
4288
4251
|
this.editUrl.set(currentLinkHref);
|
|
4289
4252
|
}
|
|
4290
|
-
});
|
|
4253
|
+
}, { allowSignalWrites: true });
|
|
4291
4254
|
}
|
|
4292
4255
|
onStateChange() {
|
|
4293
4256
|
this.linkSvc.editMode();
|
|
@@ -4403,8 +4366,8 @@ class AteLinkBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
4403
4366
|
this.linkSvc.close();
|
|
4404
4367
|
this.hideTippy();
|
|
4405
4368
|
}
|
|
4406
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4407
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "
|
|
4369
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkBubbleMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4370
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "18.2.14", 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: `
|
|
4408
4371
|
<div
|
|
4409
4372
|
#menuRef
|
|
4410
4373
|
class="bubble-menu"
|
|
@@ -4454,7 +4417,7 @@ class AteLinkBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
4454
4417
|
</div>
|
|
4455
4418
|
`, isInline: true, 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"], 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: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4456
4419
|
}
|
|
4457
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4420
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkBubbleMenuComponent, decorators: [{
|
|
4458
4421
|
type: Component,
|
|
4459
4422
|
args: [{ selector: "ate-link-bubble-menu", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [AteButtonComponent, AteSeparatorComponent, FormsModule], template: `
|
|
4460
4423
|
<div
|
|
@@ -4505,7 +4468,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4505
4468
|
</div>
|
|
4506
4469
|
</div>
|
|
4507
4470
|
`, 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"] }]
|
|
4508
|
-
}], ctorParameters: () => []
|
|
4471
|
+
}], ctorParameters: () => [] });
|
|
4509
4472
|
|
|
4510
4473
|
const PRESET_COLORS = [
|
|
4511
4474
|
"#000000",
|
|
@@ -4528,21 +4491,21 @@ class AteColorBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
4528
4491
|
this.t = this.i18nService.toolbar;
|
|
4529
4492
|
this.common = this.i18nService.common;
|
|
4530
4493
|
this.presets = PRESET_COLORS;
|
|
4531
|
-
this.colorInputRef = viewChild("colorInput"
|
|
4494
|
+
this.colorInputRef = viewChild("colorInput");
|
|
4532
4495
|
/**
|
|
4533
4496
|
* LOCAL MODE: We lock the mode when the menu is shown to avoid race conditions
|
|
4534
4497
|
* where the parent (bubble menu) clears the global signal before we apply the color.
|
|
4535
4498
|
*/
|
|
4536
|
-
this.activeMode = signal("text"
|
|
4499
|
+
this.activeMode = signal("text");
|
|
4537
4500
|
this.currentColor = computed(() => {
|
|
4538
4501
|
const marks = this.state().marks;
|
|
4539
4502
|
const color = this.activeMode() === "text" ? marks.computedColor : marks.computedBackground;
|
|
4540
4503
|
return color || (this.activeMode() === "text" ? "#000000" : "#ffff00");
|
|
4541
|
-
}
|
|
4504
|
+
});
|
|
4542
4505
|
this.hexValue = computed(() => {
|
|
4543
4506
|
const color = this.currentColor();
|
|
4544
4507
|
return color.replace("#", "").toUpperCase();
|
|
4545
|
-
}
|
|
4508
|
+
});
|
|
4546
4509
|
}
|
|
4547
4510
|
onStateChange() {
|
|
4548
4511
|
this.colorPickerSvc.editMode();
|
|
@@ -4700,8 +4663,8 @@ class AteColorBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
4700
4663
|
this.updateMenu();
|
|
4701
4664
|
}, 150);
|
|
4702
4665
|
}
|
|
4703
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
4704
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
4666
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteColorBubbleMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
4667
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", 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: `
|
|
4705
4668
|
<div
|
|
4706
4669
|
#menuRef
|
|
4707
4670
|
class="bubble-menu color-bubble-menu"
|
|
@@ -4781,7 +4744,7 @@ class AteColorBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
4781
4744
|
</div>
|
|
4782
4745
|
`, isInline: true, 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"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4783
4746
|
}
|
|
4784
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4747
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteColorBubbleMenuComponent, decorators: [{
|
|
4785
4748
|
type: Component,
|
|
4786
4749
|
args: [{ selector: "ate-color-bubble-menu", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, AteButtonComponent, AteSeparatorComponent], template: `
|
|
4787
4750
|
<div
|
|
@@ -4862,7 +4825,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
4862
4825
|
</div>
|
|
4863
4826
|
</div>
|
|
4864
4827
|
`, 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"] }]
|
|
4865
|
-
}]
|
|
4828
|
+
}] });
|
|
4866
4829
|
|
|
4867
4830
|
/**
|
|
4868
4831
|
* Clés des commandes natives dans l'ordre d'affichage
|
|
@@ -4998,17 +4961,17 @@ function filterSlashCommands(config, i18n, commands, imageOptions) {
|
|
|
4998
4961
|
class AteSlashCommandsComponent {
|
|
4999
4962
|
constructor() {
|
|
5000
4963
|
this.i18nService = inject(AteI18nService);
|
|
5001
|
-
this.editor = input.required(
|
|
5002
|
-
this.config = input(undefined
|
|
4964
|
+
this.editor = input.required();
|
|
4965
|
+
this.config = input(undefined);
|
|
5003
4966
|
this.menuRef = viewChild.required("menuRef");
|
|
5004
4967
|
this.tippyInstance = null;
|
|
5005
4968
|
this.editorCommands = inject(AteEditorCommandsService);
|
|
5006
4969
|
// Local state
|
|
5007
4970
|
this.isActive = false;
|
|
5008
|
-
this.currentQuery = signal(""
|
|
4971
|
+
this.currentQuery = signal("");
|
|
5009
4972
|
this.slashRange = null;
|
|
5010
4973
|
// Signal for selected index
|
|
5011
|
-
this.selectedIndex = signal(0
|
|
4974
|
+
this.selectedIndex = signal(0);
|
|
5012
4975
|
// Toolbar interaction state (from centralized service)
|
|
5013
4976
|
this.isToolbarInteracting = this.editorCommands.isToolbarInteracting;
|
|
5014
4977
|
this.commands = computed(() => {
|
|
@@ -5018,7 +4981,7 @@ class AteSlashCommandsComponent {
|
|
|
5018
4981
|
}
|
|
5019
4982
|
// Fallback to default native commands
|
|
5020
4983
|
return createDefaultSlashCommands(this.i18nService, this.editorCommands);
|
|
5021
|
-
}
|
|
4984
|
+
});
|
|
5022
4985
|
this.filteredCommands = computed(() => {
|
|
5023
4986
|
const query = this.currentQuery().toLowerCase();
|
|
5024
4987
|
const commands = this.commands();
|
|
@@ -5028,7 +4991,7 @@ class AteSlashCommandsComponent {
|
|
|
5028
4991
|
return commands.filter(command => command.title.toLowerCase().includes(query) ||
|
|
5029
4992
|
command.description.toLowerCase().includes(query) ||
|
|
5030
4993
|
command.keywords.some(keyword => keyword.toLowerCase().includes(query)));
|
|
5031
|
-
}
|
|
4994
|
+
});
|
|
5032
4995
|
this.updateMenu = () => {
|
|
5033
4996
|
const ed = this.editor();
|
|
5034
4997
|
if (!ed) {
|
|
@@ -5084,7 +5047,7 @@ class AteSlashCommandsComponent {
|
|
|
5084
5047
|
// Use ProseMirror plugin system to intercept keys
|
|
5085
5048
|
this.addKeyboardPlugin(ed);
|
|
5086
5049
|
// updateMenu() will be called automatically when editor is ready
|
|
5087
|
-
});
|
|
5050
|
+
}, { allowSignalWrites: true });
|
|
5088
5051
|
}
|
|
5089
5052
|
ngOnInit() {
|
|
5090
5053
|
this.initTippy();
|
|
@@ -5272,8 +5235,8 @@ class AteSlashCommandsComponent {
|
|
|
5272
5235
|
plugins: [keyboardPlugin, ...ed.view.state.plugins],
|
|
5273
5236
|
}));
|
|
5274
5237
|
}
|
|
5275
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5276
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
5238
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteSlashCommandsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5239
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", 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: `
|
|
5277
5240
|
<div #menuRef class="slash-commands-menu">
|
|
5278
5241
|
@for (command of filteredCommands(); track command.title) {
|
|
5279
5242
|
<div
|
|
@@ -5293,7 +5256,7 @@ class AteSlashCommandsComponent {
|
|
|
5293
5256
|
</div>
|
|
5294
5257
|
`, isInline: true, 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"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
5295
5258
|
}
|
|
5296
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5259
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteSlashCommandsComponent, decorators: [{
|
|
5297
5260
|
type: Component,
|
|
5298
5261
|
args: [{ selector: "ate-slash-commands", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
5299
5262
|
<div #menuRef class="slash-commands-menu">
|
|
@@ -5314,7 +5277,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5314
5277
|
}
|
|
5315
5278
|
</div>
|
|
5316
5279
|
`, 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"] }]
|
|
5317
|
-
}], ctorParameters: () => []
|
|
5280
|
+
}], ctorParameters: () => [] });
|
|
5318
5281
|
|
|
5319
5282
|
/**
|
|
5320
5283
|
* Edit Toggle Component
|
|
@@ -5322,12 +5285,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5322
5285
|
*/
|
|
5323
5286
|
class AteEditToggleComponent {
|
|
5324
5287
|
constructor() {
|
|
5325
|
-
this.editable = input.required(
|
|
5326
|
-
this.translations = input.required(
|
|
5288
|
+
this.editable = input.required();
|
|
5289
|
+
this.translations = input.required();
|
|
5327
5290
|
this.editToggle = output();
|
|
5328
5291
|
}
|
|
5329
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5330
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "
|
|
5292
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteEditToggleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5293
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.14", type: AteEditToggleComponent, isStandalone: true, selector: "ate-edit-toggle", inputs: { editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: true, transformFunction: null }, translations: { classPropertyName: "translations", publicName: "translations", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { editToggle: "editToggle" }, ngImport: i0, template: `
|
|
5331
5294
|
<div class="ate-edit-toggle-container" [class.is-editable]="editable()">
|
|
5332
5295
|
<ate-button
|
|
5333
5296
|
[icon]="editable() ? 'visibility' : 'edit'"
|
|
@@ -5339,7 +5302,7 @@ class AteEditToggleComponent {
|
|
|
5339
5302
|
</div>
|
|
5340
5303
|
`, isInline: true, styles: [".ate-edit-toggle-container{position:absolute;margin-top:16px;right:16px;z-index:50}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AteButtonComponent, selector: "ate-button", inputs: ["icon", "title", "active", "disabled", "color", "backgroundColor", "variant", "size", "iconSize"], outputs: ["buttonClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
5341
5304
|
}
|
|
5342
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5305
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteEditToggleComponent, decorators: [{
|
|
5343
5306
|
type: Component,
|
|
5344
5307
|
args: [{ selector: "ate-edit-toggle", standalone: true, imports: [CommonModule, AteButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
5345
5308
|
<div class="ate-edit-toggle-container" [class.is-editable]="editable()">
|
|
@@ -5352,7 +5315,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5352
5315
|
backgroundColor="var(--ate-primary-lighter)" />
|
|
5353
5316
|
</div>
|
|
5354
5317
|
`, styles: [".ate-edit-toggle-container{position:absolute;margin-top:16px;right:16px;z-index:50}\n"] }]
|
|
5355
|
-
}]
|
|
5318
|
+
}] });
|
|
5356
5319
|
|
|
5357
5320
|
/**
|
|
5358
5321
|
* Noop Value Accessor Directive
|
|
@@ -5368,8 +5331,8 @@ class AteNoopValueAccessorDirective {
|
|
|
5368
5331
|
registerOnTouched(_fn) {
|
|
5369
5332
|
/* empty */
|
|
5370
5333
|
}
|
|
5371
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
5372
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
5334
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteNoopValueAccessorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
5335
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: AteNoopValueAccessorDirective, isStandalone: true, providers: [
|
|
5373
5336
|
{
|
|
5374
5337
|
provide: NG_VALUE_ACCESSOR,
|
|
5375
5338
|
multi: true,
|
|
@@ -5377,7 +5340,7 @@ class AteNoopValueAccessorDirective {
|
|
|
5377
5340
|
},
|
|
5378
5341
|
], ngImport: i0 }); }
|
|
5379
5342
|
}
|
|
5380
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
5343
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteNoopValueAccessorDirective, decorators: [{
|
|
5381
5344
|
type: Directive,
|
|
5382
5345
|
args: [{
|
|
5383
5346
|
standalone: true,
|
|
@@ -5391,271 +5354,707 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
5391
5354
|
}]
|
|
5392
5355
|
}] });
|
|
5393
5356
|
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5357
|
+
/**
|
|
5358
|
+
* Base abstract class for custom 'Angular Nodes'.
|
|
5359
|
+
*
|
|
5360
|
+
* Extend this class in your custom components to automatically receive TipTap editor
|
|
5361
|
+
* properties (node attributes, selection state, etc.) as reactive Signals.
|
|
5362
|
+
*
|
|
5363
|
+
* @example
|
|
5364
|
+
* ```typescript
|
|
5365
|
+
* @Component({
|
|
5366
|
+
* selector: 'app-counter',
|
|
5367
|
+
* template: `
|
|
5368
|
+
* <div>
|
|
5369
|
+
* <button (click)="increment()">Count: {{ node().attrs['count'] }}</button>
|
|
5370
|
+
* </div>
|
|
5371
|
+
* `
|
|
5372
|
+
* })
|
|
5373
|
+
* export class CounterComponent extends AteAngularNodeView {
|
|
5374
|
+
* increment() {
|
|
5375
|
+
* const count = this.node().attrs['count'] || 0;
|
|
5376
|
+
* this.updateAttributes({ count: count + 1 });
|
|
5377
|
+
* }
|
|
5378
|
+
* }
|
|
5379
|
+
* ```
|
|
5380
|
+
*/
|
|
5381
|
+
class AteAngularNodeView {
|
|
5382
|
+
/**
|
|
5383
|
+
* Internal method to initialize the component with NodeView props.
|
|
5384
|
+
* This is called by the AngularNodeViewRenderer.
|
|
5385
|
+
*
|
|
5386
|
+
* @internal
|
|
5387
|
+
*/
|
|
5388
|
+
_initNodeView(props) {
|
|
5389
|
+
// Create signals from the props
|
|
5390
|
+
const editorSignal = signal(props.editor);
|
|
5391
|
+
const nodeSignal = signal(props.node);
|
|
5392
|
+
const decorationsSignal = signal(props.decorations);
|
|
5393
|
+
const selectedSignal = signal(props.selected);
|
|
5394
|
+
const extensionSignal = signal(props.extension);
|
|
5395
|
+
// Assign to the component
|
|
5396
|
+
this.editor = editorSignal.asReadonly();
|
|
5397
|
+
this.node = nodeSignal.asReadonly();
|
|
5398
|
+
this.decorations = decorationsSignal.asReadonly();
|
|
5399
|
+
this.selected = selectedSignal.asReadonly();
|
|
5400
|
+
this.extension = extensionSignal.asReadonly();
|
|
5401
|
+
this.getPos = props.getPos;
|
|
5402
|
+
this.updateAttributes = props.updateAttributes;
|
|
5403
|
+
this.deleteNode = props.deleteNode;
|
|
5404
|
+
// Store writable signals for updates
|
|
5405
|
+
this._writableSignals = {
|
|
5406
|
+
node: nodeSignal,
|
|
5407
|
+
decorations: decorationsSignal,
|
|
5408
|
+
selected: selectedSignal,
|
|
5409
|
+
};
|
|
5400
5410
|
}
|
|
5401
|
-
|
|
5402
|
-
|
|
5411
|
+
/**
|
|
5412
|
+
* Internal method to update the component when the node changes.
|
|
5413
|
+
* This is called by the AngularNodeViewRenderer.
|
|
5414
|
+
*
|
|
5415
|
+
* @internal
|
|
5416
|
+
*/
|
|
5417
|
+
_updateNodeView(node, decorations) {
|
|
5418
|
+
if (this._writableSignals) {
|
|
5419
|
+
this._writableSignals.node.set(node);
|
|
5420
|
+
this._writableSignals.decorations.set(decorations);
|
|
5421
|
+
}
|
|
5403
5422
|
}
|
|
5404
|
-
|
|
5405
|
-
|
|
5423
|
+
/**
|
|
5424
|
+
* Internal method to update the selection state.
|
|
5425
|
+
* This is called by the AngularNodeViewRenderer.
|
|
5426
|
+
*
|
|
5427
|
+
* @internal
|
|
5428
|
+
*/
|
|
5429
|
+
_selectNodeView() {
|
|
5430
|
+
if (this._writableSignals) {
|
|
5431
|
+
this._writableSignals.selected.set(true);
|
|
5432
|
+
}
|
|
5406
5433
|
}
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5434
|
+
/**
|
|
5435
|
+
* Internal method to update the deselection state.
|
|
5436
|
+
* This is called by the AngularNodeViewRenderer.
|
|
5437
|
+
*
|
|
5438
|
+
* @internal
|
|
5439
|
+
*/
|
|
5440
|
+
_deselectNodeView() {
|
|
5441
|
+
if (this._writableSignals) {
|
|
5442
|
+
this._writableSignals.selected.set(false);
|
|
5443
|
+
}
|
|
5410
5444
|
}
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
type:
|
|
5416
|
-
|
|
5417
|
-
to,
|
|
5418
|
-
empty: selection.empty || (selectionType === "text" && from === to),
|
|
5419
|
-
isSingleCell: isSingleCell,
|
|
5420
|
-
},
|
|
5421
|
-
nodes: {
|
|
5422
|
-
activeNodeName: editor.state.doc.nodeAt(editor.state.selection.$head.pos)?.type.name || null,
|
|
5423
|
-
},
|
|
5424
|
-
};
|
|
5425
|
-
};
|
|
5445
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteAngularNodeView, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
5446
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: AteAngularNodeView, ngImport: i0 }); }
|
|
5447
|
+
}
|
|
5448
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteAngularNodeView, decorators: [{
|
|
5449
|
+
type: Directive
|
|
5450
|
+
}] });
|
|
5426
5451
|
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
}
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
return node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
|
|
5445
|
-
}
|
|
5446
|
-
catch (_e) {
|
|
5447
|
-
return null;
|
|
5452
|
+
/**
|
|
5453
|
+
* Universal Renderer for Angular Components as TipTap NodeViews.
|
|
5454
|
+
*
|
|
5455
|
+
* Supports:
|
|
5456
|
+
* - TipTap-Aware components (extending AteAngularNodeView)
|
|
5457
|
+
* - Standard library components (automatic @Input() sync)
|
|
5458
|
+
* - Signal-based inputs and outputs (Angular 18+)
|
|
5459
|
+
* - Content projection (editableContent)
|
|
5460
|
+
* - Unified lifecycle and event management
|
|
5461
|
+
*/
|
|
5462
|
+
function AteNodeViewRenderer(component, options) {
|
|
5463
|
+
return props => {
|
|
5464
|
+
const { node, view: _view, getPos, decorations, editor, extension } = props;
|
|
5465
|
+
const { injector, inputs = {}, wrapperTag = "div", wrapperClass, editableContent = false, contentSelector, onOutput, ignoreMutation = true, } = options;
|
|
5466
|
+
const dom = document.createElement(wrapperTag);
|
|
5467
|
+
if (wrapperClass) {
|
|
5468
|
+
dom.className = wrapperClass;
|
|
5448
5469
|
}
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
if (!
|
|
5455
|
-
|
|
5470
|
+
const applicationRef = injector.get(ApplicationRef);
|
|
5471
|
+
const environmentInjector = injector.get(EnvironmentInjector);
|
|
5472
|
+
// 1. Setup Content Projection (ng-content)
|
|
5473
|
+
let initialNodes = [];
|
|
5474
|
+
let contentDOM = null;
|
|
5475
|
+
if (editableContent && !contentSelector) {
|
|
5476
|
+
contentDOM = document.createElement("div");
|
|
5477
|
+
contentDOM.setAttribute("data-node-view-content", "");
|
|
5478
|
+
initialNodes = [[contentDOM]];
|
|
5456
5479
|
}
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
}
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5480
|
+
// 2. Create the Angular Component
|
|
5481
|
+
const componentRef = createComponent(component, {
|
|
5482
|
+
environmentInjector,
|
|
5483
|
+
elementInjector: injector,
|
|
5484
|
+
projectableNodes: initialNodes,
|
|
5485
|
+
});
|
|
5486
|
+
const instance = componentRef.instance;
|
|
5487
|
+
const subscriptions = [];
|
|
5488
|
+
// 3. Initialize TipTap-Aware instances
|
|
5489
|
+
if (instance instanceof AteAngularNodeView) {
|
|
5490
|
+
instance._initNodeView({
|
|
5491
|
+
editor,
|
|
5492
|
+
node,
|
|
5493
|
+
decorations,
|
|
5494
|
+
selected: false,
|
|
5495
|
+
extension,
|
|
5496
|
+
getPos,
|
|
5497
|
+
updateAttributes: attrs => editor.commands.updateAttributes(node.type.name, attrs),
|
|
5498
|
+
deleteNode: () => {
|
|
5499
|
+
const pos = getPos();
|
|
5500
|
+
if (pos !== undefined) {
|
|
5501
|
+
editor.commands.deleteRange({ from: pos, to: pos + node.nodeSize });
|
|
5502
|
+
}
|
|
5503
|
+
},
|
|
5504
|
+
});
|
|
5505
|
+
}
|
|
5506
|
+
// 4. Synchronize Inputs (Handles standard @Input and Signal-based inputs)
|
|
5507
|
+
const syncInputs = (nodeToSync) => {
|
|
5508
|
+
// Combine base inputs from options with dynamic node attributes
|
|
5509
|
+
const mergedInputs = { ...inputs, ...nodeToSync.attrs };
|
|
5510
|
+
Object.entries(mergedInputs).forEach(([key, value]) => {
|
|
5511
|
+
if (key !== "id" && value !== null && value !== undefined) {
|
|
5512
|
+
try {
|
|
5513
|
+
componentRef.setInput(key, value);
|
|
5514
|
+
}
|
|
5515
|
+
catch {
|
|
5516
|
+
// Silently ignore inputs that don't exist on the component
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5519
|
+
});
|
|
5520
|
+
};
|
|
5521
|
+
syncInputs(node);
|
|
5522
|
+
// 5. Setup Outputs (Handles EventEmitter and OutputRef)
|
|
5523
|
+
if (onOutput) {
|
|
5524
|
+
Object.entries(instance).forEach(([key, potentialOutput]) => {
|
|
5525
|
+
if (potentialOutput &&
|
|
5526
|
+
typeof potentialOutput
|
|
5527
|
+
.subscribe === "function") {
|
|
5528
|
+
const sub = potentialOutput.subscribe((value) => {
|
|
5529
|
+
onOutput(key, value);
|
|
5530
|
+
});
|
|
5531
|
+
if (sub instanceof Subscription) {
|
|
5532
|
+
subscriptions.push(sub);
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5535
|
+
});
|
|
5536
|
+
}
|
|
5537
|
+
// 6. Attach to DOM and ApplicationRef
|
|
5538
|
+
applicationRef.attachView(componentRef.hostView);
|
|
5539
|
+
const componentElement = componentRef.location.nativeElement;
|
|
5540
|
+
// Target specific element for content if selector provided
|
|
5541
|
+
if (editableContent && contentSelector) {
|
|
5542
|
+
contentDOM = componentElement.querySelector(contentSelector);
|
|
5543
|
+
}
|
|
5544
|
+
dom.appendChild(componentElement);
|
|
5545
|
+
// Initial detection to ensure the component is rendered
|
|
5546
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
5547
|
+
// 7. Return the TipTap NodeView Interface
|
|
5504
5548
|
return {
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5549
|
+
dom,
|
|
5550
|
+
contentDOM,
|
|
5551
|
+
update: (updatedNode, updatedDecorations) => {
|
|
5552
|
+
if (updatedNode.type !== node.type) {
|
|
5553
|
+
return false;
|
|
5554
|
+
}
|
|
5555
|
+
// Update Aware component signals
|
|
5556
|
+
if (instance instanceof AteAngularNodeView) {
|
|
5557
|
+
instance._updateNodeView(updatedNode, updatedDecorations);
|
|
5558
|
+
}
|
|
5559
|
+
// Update inputs
|
|
5560
|
+
syncInputs(updatedNode);
|
|
5561
|
+
// Notify and Detect changes
|
|
5562
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
5563
|
+
if (options.onUpdate) {
|
|
5564
|
+
options.onUpdate(updatedNode);
|
|
5565
|
+
}
|
|
5566
|
+
return true;
|
|
5567
|
+
},
|
|
5568
|
+
selectNode: () => {
|
|
5569
|
+
if (instance instanceof AteAngularNodeView) {
|
|
5570
|
+
instance._selectNodeView();
|
|
5571
|
+
}
|
|
5572
|
+
dom.classList.add("ProseMirror-selectednode");
|
|
5573
|
+
},
|
|
5574
|
+
deselectNode: () => {
|
|
5575
|
+
if (instance instanceof AteAngularNodeView) {
|
|
5576
|
+
instance._deselectNodeView();
|
|
5577
|
+
}
|
|
5578
|
+
dom.classList.remove("ProseMirror-selectednode");
|
|
5579
|
+
},
|
|
5580
|
+
destroy: () => {
|
|
5581
|
+
if (options.onDestroy) {
|
|
5582
|
+
options.onDestroy();
|
|
5583
|
+
}
|
|
5584
|
+
subscriptions.forEach(s => s.unsubscribe());
|
|
5585
|
+
applicationRef.detachView(componentRef.hostView);
|
|
5586
|
+
componentRef.destroy();
|
|
5587
|
+
},
|
|
5588
|
+
stopEvent: event => {
|
|
5589
|
+
const target = event.target;
|
|
5590
|
+
const isEditable = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
|
|
5591
|
+
return isEditable;
|
|
5592
|
+
},
|
|
5593
|
+
ignoreMutation: mutation => {
|
|
5594
|
+
if (typeof ignoreMutation === "function") {
|
|
5595
|
+
return ignoreMutation(mutation);
|
|
5596
|
+
}
|
|
5597
|
+
return ignoreMutation;
|
|
5510
5598
|
},
|
|
5511
5599
|
};
|
|
5512
|
-
}
|
|
5513
|
-
const { selection } = editor.state;
|
|
5514
|
-
return {
|
|
5515
|
-
nodes: {
|
|
5516
|
-
isTable: true,
|
|
5517
|
-
isTableNodeSelected: selection instanceof NodeSelection && selection.node.type.name === "table",
|
|
5518
|
-
isTableCell: editor.isActive("tableCell") || editor.isActive("tableHeader"),
|
|
5519
|
-
isTableHeaderRow: editor.isActive("tableHeader", { row: true }),
|
|
5520
|
-
isTableHeaderColumn: editor.isActive("tableHeader", { column: true }),
|
|
5521
|
-
},
|
|
5522
|
-
can: {
|
|
5523
|
-
addRowBefore: editor.can().addRowBefore(),
|
|
5524
|
-
addRowAfter: editor.can().addRowAfter(),
|
|
5525
|
-
deleteRow: editor.can().deleteRow(),
|
|
5526
|
-
addColumnBefore: editor.can().addColumnBefore(),
|
|
5527
|
-
addColumnAfter: editor.can().addColumnAfter(),
|
|
5528
|
-
deleteColumn: editor.can().deleteColumn(),
|
|
5529
|
-
deleteTable: editor.can().deleteTable(),
|
|
5530
|
-
mergeCells: editor.can().mergeCells(),
|
|
5531
|
-
splitCell: editor.can().splitCell(),
|
|
5532
|
-
toggleHeaderRow: editor.can().toggleHeaderRow(),
|
|
5533
|
-
toggleHeaderColumn: editor.can().toggleHeaderColumn(),
|
|
5534
|
-
},
|
|
5535
|
-
};
|
|
5536
|
-
};
|
|
5537
|
-
|
|
5538
|
-
const AteImageCalculator = editor => {
|
|
5539
|
-
return {
|
|
5540
|
-
nodes: {
|
|
5541
|
-
isImage: editor.isActive("image") || editor.isActive("resizableImage"),
|
|
5542
|
-
},
|
|
5543
|
-
};
|
|
5544
|
-
};
|
|
5545
|
-
|
|
5546
|
-
const AteStructureCalculator = editor => {
|
|
5547
|
-
return {
|
|
5548
|
-
nodes: {
|
|
5549
|
-
isBlockquote: editor.isActive("blockquote"),
|
|
5550
|
-
isCodeBlock: editor.isActive("codeBlock"),
|
|
5551
|
-
isBulletList: editor.isActive("bulletList"),
|
|
5552
|
-
isOrderedList: editor.isActive("orderedList"),
|
|
5553
|
-
h1: editor.isActive("heading", { level: 1 }),
|
|
5554
|
-
h2: editor.isActive("heading", { level: 2 }),
|
|
5555
|
-
h3: editor.isActive("heading", { level: 3 }),
|
|
5556
|
-
alignLeft: editor.isActive({ textAlign: "left" }),
|
|
5557
|
-
alignCenter: editor.isActive({ textAlign: "center" }),
|
|
5558
|
-
alignRight: editor.isActive({ textAlign: "right" }),
|
|
5559
|
-
alignJustify: editor.isActive({ textAlign: "justify" }),
|
|
5560
|
-
},
|
|
5561
|
-
can: {
|
|
5562
|
-
toggleHeading1: editor.can().toggleHeading({ level: 1 }),
|
|
5563
|
-
toggleHeading2: editor.can().toggleHeading({ level: 2 }),
|
|
5564
|
-
toggleHeading3: editor.can().toggleHeading({ level: 3 }),
|
|
5565
|
-
toggleBulletList: editor.can().toggleBulletList(),
|
|
5566
|
-
toggleOrderedList: editor.can().toggleOrderedList(),
|
|
5567
|
-
toggleBlockquote: editor.can().toggleBlockquote(),
|
|
5568
|
-
toggleCodeBlock: editor.can().toggleCodeBlock(),
|
|
5569
|
-
setTextAlignLeft: editor.can().setTextAlign("left"),
|
|
5570
|
-
setTextAlignCenter: editor.can().setTextAlign("center"),
|
|
5571
|
-
setTextAlignRight: editor.can().setTextAlign("right"),
|
|
5572
|
-
setTextAlignJustify: editor.can().setTextAlign("justify"),
|
|
5573
|
-
insertHorizontalRule: editor.can().setHorizontalRule(),
|
|
5574
|
-
insertTable: editor.can().insertTable(),
|
|
5575
|
-
insertImage: editor.can().setResizableImage({ src: "" }),
|
|
5576
|
-
},
|
|
5577
5600
|
};
|
|
5578
|
-
}
|
|
5601
|
+
}
|
|
5579
5602
|
|
|
5603
|
+
const RESERVED_NAMES = [
|
|
5604
|
+
"doc",
|
|
5605
|
+
"paragraph",
|
|
5606
|
+
"text",
|
|
5607
|
+
"hardBreak",
|
|
5608
|
+
"bulletList",
|
|
5609
|
+
"orderedList",
|
|
5610
|
+
"listItem",
|
|
5611
|
+
"blockquote",
|
|
5612
|
+
"codeBlock",
|
|
5613
|
+
"heading",
|
|
5614
|
+
"horizontalRule",
|
|
5615
|
+
];
|
|
5580
5616
|
/**
|
|
5581
|
-
*
|
|
5582
|
-
* It provides a "fallback" reactive state for any mark or node not explicitly handled
|
|
5583
|
-
* by specialized calculators.
|
|
5617
|
+
* Derives the TipTap node name and HTML tag from a component class.
|
|
5584
5618
|
*/
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5619
|
+
function deriveMetadata(component, customName) {
|
|
5620
|
+
let nodeName = customName;
|
|
5621
|
+
if (!nodeName) {
|
|
5622
|
+
nodeName = component.name
|
|
5623
|
+
.replace(/Component$/, "")
|
|
5624
|
+
.replace(/Node$/, "")
|
|
5625
|
+
.replace(/^([A-Z])/, m => m.toLowerCase());
|
|
5626
|
+
console.warn(`[ATE] Auto-deriving node name '${nodeName}' for component ${component.name}. ` +
|
|
5627
|
+
`Provide an explicit 'name' in options to avoid potential naming collisions.`);
|
|
5628
|
+
}
|
|
5629
|
+
if (RESERVED_NAMES.includes(nodeName)) {
|
|
5630
|
+
throw new Error(`[ATE] The name '${nodeName}' is a reserved TipTap node name. ` +
|
|
5631
|
+
`Please provide a unique name for your custom component.`);
|
|
5632
|
+
}
|
|
5633
|
+
const tag = nodeName.toLowerCase().replace(/([A-Z])/g, "-$1");
|
|
5634
|
+
return { nodeName, tag };
|
|
5635
|
+
}
|
|
5636
|
+
/**
|
|
5637
|
+
* Creates TipTap attributes from component inputs (Standard Mode).
|
|
5638
|
+
*/
|
|
5639
|
+
function createStandardAttributes(defaultInputs = {}) {
|
|
5640
|
+
const tiptapAttributes = {};
|
|
5641
|
+
Object.entries(defaultInputs).forEach(([key, defaultValue]) => {
|
|
5642
|
+
tiptapAttributes[key] = {
|
|
5643
|
+
default: defaultValue,
|
|
5644
|
+
parseHTML: (element) => {
|
|
5645
|
+
const attr = element.getAttribute(`data-${key}`);
|
|
5646
|
+
if (attr === null) {
|
|
5647
|
+
return defaultValue;
|
|
5648
|
+
}
|
|
5649
|
+
try {
|
|
5650
|
+
return JSON.parse(attr);
|
|
5651
|
+
}
|
|
5652
|
+
catch {
|
|
5653
|
+
return attr;
|
|
5654
|
+
}
|
|
5655
|
+
},
|
|
5656
|
+
renderHTML: (attrs) => {
|
|
5657
|
+
const value = attrs[key];
|
|
5658
|
+
if (value === undefined || value === null) {
|
|
5659
|
+
return {};
|
|
5660
|
+
}
|
|
5661
|
+
const serialized = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
5662
|
+
return { [`data-${key}`]: serialized };
|
|
5663
|
+
},
|
|
5664
|
+
};
|
|
5665
|
+
});
|
|
5666
|
+
return tiptapAttributes;
|
|
5667
|
+
}
|
|
5668
|
+
/**
|
|
5669
|
+
* Factory to transform an Angular component into a TipTap Node extension.
|
|
5670
|
+
* Supports both "TipTap-Aware" and "Standard" modes.
|
|
5671
|
+
*
|
|
5672
|
+
* @internal
|
|
5673
|
+
*/
|
|
5674
|
+
function createAngularComponentExtension(injector, options) {
|
|
5675
|
+
const { component, name: customName, attributes, defaultInputs, contentSelector, contentMode = "block", editableContent = false, group = "block", draggable = true, ignoreMutation = true, onOutput, HTMLAttributes = {}, parseHTML: customParseHTML, renderHTML: customRenderHTML, } = options;
|
|
5676
|
+
const { nodeName, tag } = deriveMetadata(component, customName);
|
|
5677
|
+
const isTipTapAware = Object.prototype.isPrototypeOf.call(AteAngularNodeView, component);
|
|
5678
|
+
const atom = !editableContent;
|
|
5679
|
+
// 1. Prepare Attributes
|
|
5680
|
+
const tiptapAttributes = isTipTapAware
|
|
5681
|
+
? attributes || {}
|
|
5682
|
+
: createStandardAttributes(defaultInputs);
|
|
5683
|
+
// 2. Create Node Extension
|
|
5684
|
+
return Node$1.create({
|
|
5685
|
+
name: nodeName,
|
|
5686
|
+
group,
|
|
5687
|
+
inline: group === "inline",
|
|
5688
|
+
atom,
|
|
5689
|
+
draggable,
|
|
5690
|
+
content: editableContent ? (contentMode === "inline" ? "inline*" : "block*") : undefined,
|
|
5691
|
+
addAttributes() {
|
|
5692
|
+
return tiptapAttributes;
|
|
5693
|
+
},
|
|
5694
|
+
parseHTML() {
|
|
5695
|
+
if (customParseHTML) {
|
|
5696
|
+
return customParseHTML.call(this);
|
|
5697
|
+
}
|
|
5698
|
+
return [{ tag }, { tag: `div[data-component="${nodeName}"]` }];
|
|
5699
|
+
},
|
|
5700
|
+
renderHTML({ node, HTMLAttributes: attrs }) {
|
|
5701
|
+
if (customRenderHTML) {
|
|
5702
|
+
return customRenderHTML.call(this, { node, HTMLAttributes: attrs });
|
|
5703
|
+
}
|
|
5704
|
+
return [tag, mergeAttributes(HTMLAttributes, attrs, { "data-component": nodeName })];
|
|
5705
|
+
},
|
|
5706
|
+
addNodeView() {
|
|
5707
|
+
return AteNodeViewRenderer(component, {
|
|
5708
|
+
injector,
|
|
5709
|
+
inputs: defaultInputs,
|
|
5710
|
+
wrapperTag: group === "inline" ? "span" : "div",
|
|
5711
|
+
wrapperClass: isTipTapAware
|
|
5712
|
+
? `ate-node-${nodeName}`
|
|
5713
|
+
: `embedded-component embedded-${nodeName}`,
|
|
5714
|
+
atom,
|
|
5715
|
+
editableContent,
|
|
5716
|
+
contentSelector,
|
|
5717
|
+
contentMode,
|
|
5718
|
+
onOutput,
|
|
5719
|
+
ignoreMutation,
|
|
5720
|
+
});
|
|
5721
|
+
},
|
|
5722
|
+
});
|
|
5723
|
+
}
|
|
5724
|
+
|
|
5725
|
+
/**
|
|
5726
|
+
* Internal registry to store the root injector for the editor.
|
|
5727
|
+
* This allows registerAngularComponent to work without explicitly passing the injector.
|
|
5728
|
+
* @internal
|
|
5729
|
+
*/
|
|
5730
|
+
let globalInjector = null;
|
|
5731
|
+
function setGlobalInjector(injector) {
|
|
5732
|
+
globalInjector = injector;
|
|
5733
|
+
}
|
|
5734
|
+
function getGlobalInjector() {
|
|
5735
|
+
if (!globalInjector) {
|
|
5736
|
+
throw new Error("[ATE] Global Injector not found. Make sure to call provideAteEditor() in your app.config.ts or main.ts.");
|
|
5737
|
+
}
|
|
5738
|
+
return globalInjector;
|
|
5739
|
+
}
|
|
5740
|
+
|
|
5741
|
+
/**
|
|
5742
|
+
* Registers ANY Angular component as a TipTap node extension.
|
|
5743
|
+
*
|
|
5744
|
+
* This function is the single public entry point for adding custom components.
|
|
5745
|
+
* It supports two distinct modes:
|
|
5746
|
+
*
|
|
5747
|
+
* 1. **TipTap-Aware Mode** (the component extends `AteAngularNodeView`):
|
|
5748
|
+
* Grants direct access to the TipTap API (`editor`, `node`, `updateAttributes`, etc.) within the component.
|
|
5749
|
+
*
|
|
5750
|
+
* 2. **Standard Mode** (library or legacy components):
|
|
5751
|
+
* Allows using any existing Angular component. Its `@Input()` properties are automatically
|
|
5752
|
+
* synchronized with TipTap node attributes.
|
|
5753
|
+
*
|
|
5754
|
+
* @param injectorOrOptions - The Angular Injector OR the configuration options
|
|
5755
|
+
* @param maybeOptions - Configuration options (if the first param was an injector)
|
|
5756
|
+
* @returns A TipTap Node extension ready to be used
|
|
5757
|
+
*
|
|
5758
|
+
* @example
|
|
5759
|
+
* ```typescript
|
|
5760
|
+
* // Modern way (requires provideAteEditor())
|
|
5761
|
+
* registerAngularComponent({
|
|
5762
|
+
* component: MyComponent,
|
|
5763
|
+
* name: 'myComponent'
|
|
5764
|
+
* });
|
|
5765
|
+
*
|
|
5766
|
+
* // Classic way
|
|
5767
|
+
* registerAngularComponent(injector, {
|
|
5768
|
+
* component: MyComponent
|
|
5769
|
+
* });
|
|
5770
|
+
* ```
|
|
5771
|
+
*/
|
|
5772
|
+
function registerAngularComponent(injectorOrOptions, maybeOptions) {
|
|
5773
|
+
let injector;
|
|
5774
|
+
let options;
|
|
5775
|
+
// Duck-typing check: Injectors have a 'get' method
|
|
5776
|
+
const isInjector = (obj) => obj !== null && typeof obj === "object" && typeof obj.get === "function";
|
|
5777
|
+
if (isInjector(injectorOrOptions)) {
|
|
5778
|
+
injector = injectorOrOptions;
|
|
5779
|
+
options = maybeOptions;
|
|
5780
|
+
}
|
|
5781
|
+
else {
|
|
5782
|
+
injector = getGlobalInjector();
|
|
5783
|
+
options = injectorOrOptions;
|
|
5784
|
+
}
|
|
5785
|
+
return createAngularComponentExtension(injector, options);
|
|
5786
|
+
}
|
|
5787
|
+
|
|
5788
|
+
/**
|
|
5789
|
+
* Injection Token for global editor configuration.
|
|
5790
|
+
*/
|
|
5791
|
+
const ATE_GLOBAL_CONFIG = new InjectionToken("ATE_GLOBAL_CONFIG");
|
|
5792
|
+
|
|
5793
|
+
const AteSelectionCalculator = editor => {
|
|
5794
|
+
const { selection } = editor.state;
|
|
5795
|
+
const { from, to } = selection;
|
|
5796
|
+
let selectionType = "none";
|
|
5797
|
+
if (selection instanceof TextSelection) {
|
|
5798
|
+
selectionType = "text";
|
|
5799
|
+
}
|
|
5800
|
+
else if (selection instanceof NodeSelection) {
|
|
5801
|
+
selectionType = "node";
|
|
5802
|
+
}
|
|
5803
|
+
else if (selection instanceof CellSelection) {
|
|
5804
|
+
selectionType = "cell";
|
|
5805
|
+
}
|
|
5806
|
+
let isSingleCell = false;
|
|
5807
|
+
if (selection instanceof CellSelection) {
|
|
5808
|
+
isSingleCell = selection.$anchorCell.pos === selection.$headCell.pos;
|
|
5809
|
+
}
|
|
5810
|
+
return {
|
|
5811
|
+
isFocused: editor.view.hasFocus(),
|
|
5812
|
+
isEditable: editor.isEditable,
|
|
5813
|
+
selection: {
|
|
5814
|
+
type: selectionType,
|
|
5815
|
+
from,
|
|
5816
|
+
to,
|
|
5817
|
+
empty: selection.empty || (selectionType === "text" && from === to),
|
|
5818
|
+
isSingleCell: isSingleCell,
|
|
5819
|
+
},
|
|
5820
|
+
nodes: {
|
|
5821
|
+
activeNodeName: editor.state.doc.nodeAt(editor.state.selection.$head.pos)?.type.name || null,
|
|
5822
|
+
},
|
|
5823
|
+
};
|
|
5824
|
+
};
|
|
5825
|
+
|
|
5826
|
+
const AteMarksCalculator = editor => {
|
|
5827
|
+
const isCodeBlock = editor.isActive("codeBlock");
|
|
5828
|
+
const isCode = editor.isActive("code"); // Inline code mark
|
|
5829
|
+
const isImage = editor.isActive("image") || editor.isActive("resizableImage");
|
|
5830
|
+
// Check if marks are generally allowed based on context
|
|
5831
|
+
const marksAllowed = !isCodeBlock && !isImage;
|
|
5832
|
+
// For inline code specifically, we don't allow nesting OTHER marks inside it,
|
|
5833
|
+
// but the code mark ITSELF must be togglable to be removed.
|
|
5834
|
+
const isInsideInlineCode = isCode;
|
|
5835
|
+
// 1. Resolve target element once for this calculation
|
|
5836
|
+
const getTargetElement = () => {
|
|
5837
|
+
if (typeof window === "undefined" || !editor.view?.dom) {
|
|
5838
|
+
return null;
|
|
5628
5839
|
}
|
|
5629
|
-
|
|
5630
|
-
|
|
5840
|
+
try {
|
|
5841
|
+
const { from } = editor.state.selection;
|
|
5842
|
+
const { node } = editor.view.domAtPos(from);
|
|
5843
|
+
return node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
|
|
5631
5844
|
}
|
|
5632
|
-
|
|
5633
|
-
|
|
5845
|
+
catch (_e) {
|
|
5846
|
+
return null;
|
|
5634
5847
|
}
|
|
5635
|
-
|
|
5636
|
-
|
|
5848
|
+
};
|
|
5849
|
+
const targetEl = getTargetElement() || (typeof window !== "undefined" ? editor.view?.dom : null);
|
|
5850
|
+
const computedStyle = targetEl && typeof window !== "undefined" ? window.getComputedStyle(targetEl) : null;
|
|
5851
|
+
// 2. Lightweight helper to extract properties from the pre-calculated style object
|
|
5852
|
+
const getStyle = (prop) => {
|
|
5853
|
+
if (!computedStyle) {
|
|
5854
|
+
return null;
|
|
5637
5855
|
}
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
};
|
|
5641
|
-
|
|
5642
|
-
const
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5856
|
+
const val = computedStyle.getPropertyValue(prop);
|
|
5857
|
+
return normalizeColor(val);
|
|
5858
|
+
};
|
|
5859
|
+
const colorMark = editor.getAttributes("textStyle")["color"] || null;
|
|
5860
|
+
const backgroundMark = editor.getAttributes("highlight")["color"] || null;
|
|
5861
|
+
return {
|
|
5862
|
+
marks: {
|
|
5863
|
+
bold: editor.isActive("bold"),
|
|
5864
|
+
italic: editor.isActive("italic"),
|
|
5865
|
+
underline: editor.isActive("underline"),
|
|
5866
|
+
strike: editor.isActive("strike"),
|
|
5867
|
+
code: isCode,
|
|
5868
|
+
superscript: editor.isActive("superscript"),
|
|
5869
|
+
subscript: editor.isActive("subscript"),
|
|
5870
|
+
highlight: editor.isActive("highlight"),
|
|
5871
|
+
link: editor.isActive("link"),
|
|
5872
|
+
linkHref: editor.getAttributes("link")["href"] || null,
|
|
5873
|
+
color: colorMark,
|
|
5874
|
+
computedColor: colorMark || getStyle("color"),
|
|
5875
|
+
background: backgroundMark,
|
|
5876
|
+
computedBackground: backgroundMark || getStyle("background-color"),
|
|
5877
|
+
linkOpenOnClick: editor.extensionManager.extensions.find(ext => ext.name === "link")?.options?.openOnClick ??
|
|
5878
|
+
false,
|
|
5879
|
+
},
|
|
5880
|
+
can: {
|
|
5881
|
+
toggleBold: marksAllowed && !isInsideInlineCode && editor.can().toggleBold(),
|
|
5882
|
+
toggleItalic: marksAllowed && !isInsideInlineCode && editor.can().toggleItalic(),
|
|
5883
|
+
toggleUnderline: marksAllowed && !isInsideInlineCode && editor.can().toggleUnderline(),
|
|
5884
|
+
toggleStrike: marksAllowed && !isInsideInlineCode && editor.can().toggleStrike(),
|
|
5885
|
+
toggleCode: marksAllowed && editor.can().toggleCode(),
|
|
5886
|
+
toggleHighlight: marksAllowed && !isInsideInlineCode && editor.can().toggleHighlight(),
|
|
5887
|
+
toggleLink: marksAllowed &&
|
|
5888
|
+
!isInsideInlineCode &&
|
|
5889
|
+
(editor.can().setLink({ href: "" }) || editor.can().unsetLink()),
|
|
5890
|
+
toggleSuperscript: marksAllowed && !isInsideInlineCode && editor.can().toggleSuperscript(),
|
|
5891
|
+
toggleSubscript: marksAllowed && !isInsideInlineCode && editor.can().toggleSubscript(),
|
|
5892
|
+
setColor: marksAllowed && !isInsideInlineCode && editor.can().setColor(""),
|
|
5893
|
+
setHighlight: marksAllowed && !isInsideInlineCode && editor.can().setHighlight(),
|
|
5894
|
+
undo: editor.can().undo(),
|
|
5895
|
+
redo: editor.can().redo(),
|
|
5896
|
+
},
|
|
5897
|
+
};
|
|
5898
|
+
};
|
|
5899
|
+
|
|
5900
|
+
const AteTableCalculator = editor => {
|
|
5901
|
+
const isTable = editor.isActive("table");
|
|
5902
|
+
if (!isTable) {
|
|
5903
|
+
return {
|
|
5904
|
+
nodes: {
|
|
5905
|
+
isTable: false,
|
|
5906
|
+
isTableCell: false,
|
|
5907
|
+
isTableHeaderRow: false,
|
|
5908
|
+
isTableHeaderColumn: false,
|
|
5909
|
+
},
|
|
5910
|
+
};
|
|
5911
|
+
}
|
|
5912
|
+
const { selection } = editor.state;
|
|
5913
|
+
return {
|
|
5914
|
+
nodes: {
|
|
5915
|
+
isTable: true,
|
|
5916
|
+
isTableNodeSelected: selection instanceof NodeSelection && selection.node.type.name === "table",
|
|
5917
|
+
isTableCell: editor.isActive("tableCell") || editor.isActive("tableHeader"),
|
|
5918
|
+
isTableHeaderRow: editor.isActive("tableHeader", { row: true }),
|
|
5919
|
+
isTableHeaderColumn: editor.isActive("tableHeader", { column: true }),
|
|
5920
|
+
},
|
|
5921
|
+
can: {
|
|
5922
|
+
addRowBefore: editor.can().addRowBefore(),
|
|
5923
|
+
addRowAfter: editor.can().addRowAfter(),
|
|
5924
|
+
deleteRow: editor.can().deleteRow(),
|
|
5925
|
+
addColumnBefore: editor.can().addColumnBefore(),
|
|
5926
|
+
addColumnAfter: editor.can().addColumnAfter(),
|
|
5927
|
+
deleteColumn: editor.can().deleteColumn(),
|
|
5928
|
+
deleteTable: editor.can().deleteTable(),
|
|
5929
|
+
mergeCells: editor.can().mergeCells(),
|
|
5930
|
+
splitCell: editor.can().splitCell(),
|
|
5931
|
+
toggleHeaderRow: editor.can().toggleHeaderRow(),
|
|
5932
|
+
toggleHeaderColumn: editor.can().toggleHeaderColumn(),
|
|
5933
|
+
},
|
|
5934
|
+
};
|
|
5935
|
+
};
|
|
5936
|
+
|
|
5937
|
+
const AteImageCalculator = editor => {
|
|
5938
|
+
return {
|
|
5939
|
+
nodes: {
|
|
5940
|
+
isImage: editor.isActive("image") || editor.isActive("resizableImage"),
|
|
5941
|
+
},
|
|
5942
|
+
};
|
|
5943
|
+
};
|
|
5944
|
+
|
|
5945
|
+
const AteStructureCalculator = editor => {
|
|
5946
|
+
return {
|
|
5947
|
+
nodes: {
|
|
5948
|
+
isBlockquote: editor.isActive("blockquote"),
|
|
5949
|
+
isCodeBlock: editor.isActive("codeBlock"),
|
|
5950
|
+
isBulletList: editor.isActive("bulletList"),
|
|
5951
|
+
isOrderedList: editor.isActive("orderedList"),
|
|
5952
|
+
h1: editor.isActive("heading", { level: 1 }),
|
|
5953
|
+
h2: editor.isActive("heading", { level: 2 }),
|
|
5954
|
+
h3: editor.isActive("heading", { level: 3 }),
|
|
5955
|
+
alignLeft: editor.isActive({ textAlign: "left" }),
|
|
5956
|
+
alignCenter: editor.isActive({ textAlign: "center" }),
|
|
5957
|
+
alignRight: editor.isActive({ textAlign: "right" }),
|
|
5958
|
+
alignJustify: editor.isActive({ textAlign: "justify" }),
|
|
5959
|
+
},
|
|
5960
|
+
can: {
|
|
5961
|
+
toggleHeading1: editor.can().toggleHeading({ level: 1 }),
|
|
5962
|
+
toggleHeading2: editor.can().toggleHeading({ level: 2 }),
|
|
5963
|
+
toggleHeading3: editor.can().toggleHeading({ level: 3 }),
|
|
5964
|
+
toggleBulletList: editor.can().toggleBulletList(),
|
|
5965
|
+
toggleOrderedList: editor.can().toggleOrderedList(),
|
|
5966
|
+
toggleBlockquote: editor.can().toggleBlockquote(),
|
|
5967
|
+
toggleCodeBlock: editor.can().toggleCodeBlock(),
|
|
5968
|
+
setTextAlignLeft: editor.can().setTextAlign("left"),
|
|
5969
|
+
setTextAlignCenter: editor.can().setTextAlign("center"),
|
|
5970
|
+
setTextAlignRight: editor.can().setTextAlign("right"),
|
|
5971
|
+
setTextAlignJustify: editor.can().setTextAlign("justify"),
|
|
5972
|
+
insertHorizontalRule: editor.can().setHorizontalRule(),
|
|
5973
|
+
insertTable: editor.can().insertTable(),
|
|
5974
|
+
insertImage: editor.can().setResizableImage({ src: "" }),
|
|
5975
|
+
},
|
|
5976
|
+
};
|
|
5977
|
+
};
|
|
5978
|
+
|
|
5979
|
+
/**
|
|
5980
|
+
* DiscoveryCalculator automatically detects and tracks the state of any TipTap extension.
|
|
5981
|
+
* It provides a "fallback" reactive state for any mark or node not explicitly handled
|
|
5982
|
+
* by specialized calculators.
|
|
5983
|
+
*/
|
|
5984
|
+
const AteDiscoveryCalculator = (editor) => {
|
|
5985
|
+
const state = {
|
|
5986
|
+
marks: {},
|
|
5987
|
+
nodes: {},
|
|
5988
|
+
};
|
|
5989
|
+
// We skip core extensions that are already handled by specialized calculators
|
|
5990
|
+
// to avoid redundant calculations and maintain precise attribute tracking.
|
|
5991
|
+
const handled = [
|
|
5992
|
+
"bold",
|
|
5993
|
+
"italic",
|
|
5994
|
+
"underline",
|
|
5995
|
+
"strike",
|
|
5996
|
+
"code",
|
|
5997
|
+
"link",
|
|
5998
|
+
"highlight",
|
|
5999
|
+
"superscript",
|
|
6000
|
+
"subscript",
|
|
6001
|
+
"table",
|
|
6002
|
+
"image",
|
|
6003
|
+
"resizableImage",
|
|
6004
|
+
"heading",
|
|
6005
|
+
"bulletList",
|
|
6006
|
+
"orderedList",
|
|
6007
|
+
"blockquote",
|
|
6008
|
+
"textAlign",
|
|
6009
|
+
"textStyle",
|
|
6010
|
+
"color",
|
|
6011
|
+
];
|
|
6012
|
+
editor.extensionManager.extensions.forEach(extension => {
|
|
6013
|
+
const name = extension.name;
|
|
6014
|
+
const type = extension.type;
|
|
6015
|
+
// Skip internal/core extensions or already handled ones
|
|
6016
|
+
if ([
|
|
6017
|
+
"selection",
|
|
6018
|
+
"editable",
|
|
6019
|
+
"focus",
|
|
6020
|
+
"undo",
|
|
6021
|
+
"redo",
|
|
6022
|
+
"history",
|
|
6023
|
+
"placeholder",
|
|
6024
|
+
"characterCount",
|
|
6025
|
+
].includes(name)) {
|
|
6026
|
+
return;
|
|
6027
|
+
}
|
|
6028
|
+
if (handled.includes(name)) {
|
|
6029
|
+
return;
|
|
6030
|
+
}
|
|
6031
|
+
if (type === "mark") {
|
|
6032
|
+
state.marks[name] = editor.isActive(name);
|
|
6033
|
+
}
|
|
6034
|
+
else if (type === "node") {
|
|
6035
|
+
state.nodes[name] = editor.isActive(name);
|
|
6036
|
+
}
|
|
6037
|
+
});
|
|
6038
|
+
return state;
|
|
6039
|
+
};
|
|
6040
|
+
|
|
6041
|
+
const AteLinkClickBehavior = Extension.create({
|
|
6042
|
+
name: "linkClickBehavior",
|
|
6043
|
+
addProseMirrorPlugins() {
|
|
6044
|
+
return [
|
|
6045
|
+
new Plugin({
|
|
6046
|
+
key: new PluginKey("linkClickBehavior"),
|
|
6047
|
+
props: {
|
|
6048
|
+
handleClick(view, _pos, event) {
|
|
6049
|
+
// handleClick only runs in the browser, but we guard it for absolute SSR safety
|
|
6050
|
+
if (typeof window === "undefined") {
|
|
6051
|
+
return false;
|
|
6052
|
+
}
|
|
6053
|
+
const isModKey = event.ctrlKey || event.metaKey;
|
|
6054
|
+
// If editor is editable, only proceed if Ctrl/Cmd is pressed
|
|
6055
|
+
if (view.editable && !isModKey) {
|
|
6056
|
+
return false;
|
|
6057
|
+
}
|
|
5659
6058
|
const attrs = getAttributes(view.state, "link");
|
|
5660
6059
|
if (attrs["href"]) {
|
|
5661
6060
|
window.open(attrs["href"], "_blank", "noopener,noreferrer");
|
|
@@ -5746,6 +6145,14 @@ const ATE_DEFAULT_CELL_MENU_CONFIG = {
|
|
|
5746
6145
|
};
|
|
5747
6146
|
|
|
5748
6147
|
// Slash commands configuration is handled dynamically via slashCommandsConfigComputed
|
|
6148
|
+
/**
|
|
6149
|
+
* The main rich-text editor component for Angular.
|
|
6150
|
+
*
|
|
6151
|
+
* Powered by Tiptap and built with a native Signal-based architecture, it provides
|
|
6152
|
+
* a seamless, high-performance editing experience. Supports automatic registration
|
|
6153
|
+
* of Angular components as interactive nodes ('Angular Nodes'), full Reactive Forms
|
|
6154
|
+
* integration, and extensive customization via the AteEditorConfig.
|
|
6155
|
+
*/
|
|
5749
6156
|
class AngularTiptapEditorComponent {
|
|
5750
6157
|
// ============================================
|
|
5751
6158
|
// Toolbar / Bubble Menu Coordination
|
|
@@ -5758,50 +6165,50 @@ class AngularTiptapEditorComponent {
|
|
|
5758
6165
|
}
|
|
5759
6166
|
constructor() {
|
|
5760
6167
|
/** Configuration globale de l'éditeur */
|
|
5761
|
-
this.config = input({}
|
|
5762
|
-
this.content = input(""
|
|
5763
|
-
this.placeholder = input(""
|
|
5764
|
-
this.editable = input(true
|
|
5765
|
-
this.disabled = input(false
|
|
5766
|
-
this.minHeight = input(200
|
|
5767
|
-
this.height = input(undefined
|
|
5768
|
-
this.maxHeight = input(undefined
|
|
5769
|
-
this.fillContainer = input(false
|
|
5770
|
-
this.showToolbar = input(true
|
|
5771
|
-
this.showFooter = input(true
|
|
5772
|
-
this.showCharacterCount = input(true
|
|
5773
|
-
this.showWordCount = input(true
|
|
5774
|
-
this.maxCharacters = input(undefined
|
|
5775
|
-
this.enableOfficePaste = input(true
|
|
5776
|
-
this.enableSlashCommands = input(true
|
|
5777
|
-
this.slashCommands = input({}
|
|
5778
|
-
this.customSlashCommands = input(undefined
|
|
5779
|
-
this.locale = input(undefined
|
|
5780
|
-
this.autofocus = input(false
|
|
5781
|
-
this.seamless = input(false
|
|
5782
|
-
this.floatingToolbar = input(false
|
|
5783
|
-
this.showEditToggle = input(false
|
|
5784
|
-
this.spellcheck = input(true
|
|
5785
|
-
this.tiptapExtensions = input([]
|
|
5786
|
-
this.tiptapOptions = input({}
|
|
6168
|
+
this.config = input({});
|
|
6169
|
+
this.content = input("");
|
|
6170
|
+
this.placeholder = input("");
|
|
6171
|
+
this.editable = input(true);
|
|
6172
|
+
this.disabled = input(false);
|
|
6173
|
+
this.minHeight = input(200);
|
|
6174
|
+
this.height = input(undefined);
|
|
6175
|
+
this.maxHeight = input(undefined);
|
|
6176
|
+
this.fillContainer = input(false);
|
|
6177
|
+
this.showToolbar = input(true);
|
|
6178
|
+
this.showFooter = input(true);
|
|
6179
|
+
this.showCharacterCount = input(true);
|
|
6180
|
+
this.showWordCount = input(true);
|
|
6181
|
+
this.maxCharacters = input(undefined);
|
|
6182
|
+
this.enableOfficePaste = input(true);
|
|
6183
|
+
this.enableSlashCommands = input(true);
|
|
6184
|
+
this.slashCommands = input({});
|
|
6185
|
+
this.customSlashCommands = input(undefined);
|
|
6186
|
+
this.locale = input(undefined);
|
|
6187
|
+
this.autofocus = input(false);
|
|
6188
|
+
this.seamless = input(false);
|
|
6189
|
+
this.floatingToolbar = input(false);
|
|
6190
|
+
this.showEditToggle = input(false);
|
|
6191
|
+
this.spellcheck = input(true);
|
|
6192
|
+
this.tiptapExtensions = input([]);
|
|
6193
|
+
this.tiptapOptions = input({});
|
|
5787
6194
|
// Nouveaux inputs pour les bubble menus
|
|
5788
|
-
this.showBubbleMenu = input(true
|
|
5789
|
-
this.bubbleMenu = input(ATE_DEFAULT_BUBBLE_MENU_CONFIG
|
|
5790
|
-
this.showImageBubbleMenu = input(true
|
|
5791
|
-
this.imageBubbleMenu = input(ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG
|
|
6195
|
+
this.showBubbleMenu = input(true);
|
|
6196
|
+
this.bubbleMenu = input(ATE_DEFAULT_BUBBLE_MENU_CONFIG);
|
|
6197
|
+
this.showImageBubbleMenu = input(true);
|
|
6198
|
+
this.imageBubbleMenu = input(ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG);
|
|
5792
6199
|
// Configuration de la toolbar
|
|
5793
|
-
this.toolbar = input({}
|
|
6200
|
+
this.toolbar = input({});
|
|
5794
6201
|
// Configuration des menus de table
|
|
5795
|
-
this.showTableBubbleMenu = input(true
|
|
5796
|
-
this.tableBubbleMenu = input(ATE_DEFAULT_TABLE_MENU_CONFIG
|
|
5797
|
-
this.showCellBubbleMenu = input(true
|
|
5798
|
-
this.cellBubbleMenu = input(ATE_DEFAULT_CELL_MENU_CONFIG
|
|
6202
|
+
this.showTableBubbleMenu = input(true);
|
|
6203
|
+
this.tableBubbleMenu = input(ATE_DEFAULT_TABLE_MENU_CONFIG);
|
|
6204
|
+
this.showCellBubbleMenu = input(true);
|
|
6205
|
+
this.cellBubbleMenu = input(ATE_DEFAULT_CELL_MENU_CONFIG);
|
|
5799
6206
|
/**
|
|
5800
6207
|
* Additionnal state calculators to extend the reactive editor state.
|
|
5801
6208
|
*/
|
|
5802
|
-
this.stateCalculators = input([]
|
|
6209
|
+
this.stateCalculators = input([]);
|
|
5803
6210
|
// Nouveau input pour la configuration de l'upload d'images
|
|
5804
|
-
this.imageUpload = input({}
|
|
6211
|
+
this.imageUpload = input({});
|
|
5805
6212
|
/**
|
|
5806
6213
|
* Custom handler for image uploads.
|
|
5807
6214
|
* When provided, images will be processed through this handler instead of being converted to base64.
|
|
@@ -5821,7 +6228,7 @@ class AngularTiptapEditorComponent {
|
|
|
5821
6228
|
* // <angular-tiptap-editor [imageUploadHandler]="myUploadHandler" />
|
|
5822
6229
|
* ```
|
|
5823
6230
|
*/
|
|
5824
|
-
this.imageUploadHandler = input(undefined
|
|
6231
|
+
this.imageUploadHandler = input(undefined);
|
|
5825
6232
|
// Nouveaux outputs
|
|
5826
6233
|
this.contentChange = output();
|
|
5827
6234
|
this.editorCreated = output();
|
|
@@ -5832,11 +6239,11 @@ class AngularTiptapEditorComponent {
|
|
|
5832
6239
|
// ViewChild with signal
|
|
5833
6240
|
this.editorElement = viewChild.required("editorElement");
|
|
5834
6241
|
// Private signals for internal state
|
|
5835
|
-
this._editor = signal(null
|
|
5836
|
-
this._characterCount = signal(0
|
|
5837
|
-
this._wordCount = signal(0
|
|
5838
|
-
this._isDragOver = signal(false
|
|
5839
|
-
this._editorFullyInitialized = signal(false
|
|
6242
|
+
this._editor = signal(null);
|
|
6243
|
+
this._characterCount = signal(0);
|
|
6244
|
+
this._wordCount = signal(0);
|
|
6245
|
+
this._isDragOver = signal(false);
|
|
6246
|
+
this._editorFullyInitialized = signal(false);
|
|
5840
6247
|
// Anti-echo: track last emitted HTML to prevent cursor reset on parent echo
|
|
5841
6248
|
this.lastEmittedHtml = null;
|
|
5842
6249
|
// Read-only access to signals
|
|
@@ -5845,58 +6252,58 @@ class AngularTiptapEditorComponent {
|
|
|
5845
6252
|
this.wordCount = this._wordCount.asReadonly();
|
|
5846
6253
|
this.isDragOver = this._isDragOver.asReadonly();
|
|
5847
6254
|
this.editorFullyInitialized = this._editorFullyInitialized.asReadonly();
|
|
5848
|
-
this._isFormControlDisabled = signal(false
|
|
6255
|
+
this._isFormControlDisabled = signal(false);
|
|
5849
6256
|
this.isFormControlDisabled = this._isFormControlDisabled.asReadonly();
|
|
5850
6257
|
// Combined disabled state (Input + FormControl)
|
|
5851
|
-
this.mergedDisabled = computed(() => (this.
|
|
6258
|
+
this.mergedDisabled = computed(() => (this.effectiveConfig().disabled ?? this.disabled()) || this.isFormControlDisabled());
|
|
5852
6259
|
// Computed for editor states
|
|
5853
|
-
this.isEditorReady = computed(() => this.editor() !== null
|
|
6260
|
+
this.isEditorReady = computed(() => this.editor() !== null);
|
|
5854
6261
|
// ============================================
|
|
5855
6262
|
// UNIFIED CONFIGURATION COMPUTED PROPERTIES
|
|
5856
6263
|
// ============================================
|
|
5857
6264
|
// Appearance & Fundamentals
|
|
5858
6265
|
this.finalSeamless = computed(() => {
|
|
5859
|
-
const fromConfig = this.
|
|
6266
|
+
const fromConfig = this.effectiveConfig().mode;
|
|
5860
6267
|
if (fromConfig !== undefined) {
|
|
5861
6268
|
return fromConfig === "seamless";
|
|
5862
6269
|
}
|
|
5863
6270
|
return this.seamless();
|
|
5864
|
-
}
|
|
5865
|
-
this.finalEditable = computed(() => this.
|
|
5866
|
-
this.finalPlaceholder = computed(() => this.
|
|
5867
|
-
(this.placeholder() || this.currentTranslations().editor.placeholder)
|
|
5868
|
-
this.finalFillContainer = computed(() => this.
|
|
5869
|
-
this.finalShowFooter = computed(() => this.
|
|
5870
|
-
this.finalShowEditToggle = computed(() => this.
|
|
5871
|
-
this.finalHeight = computed(() => this.
|
|
5872
|
-
this.finalMinHeight = computed(() => this.
|
|
5873
|
-
this.finalMaxHeight = computed(() => this.
|
|
5874
|
-
this.finalSpellcheck = computed(() => this.
|
|
5875
|
-
this.finalEnableOfficePaste = computed(() => this.
|
|
6271
|
+
});
|
|
6272
|
+
this.finalEditable = computed(() => this.effectiveConfig().editable ?? this.editable());
|
|
6273
|
+
this.finalPlaceholder = computed(() => this.effectiveConfig().placeholder ??
|
|
6274
|
+
(this.placeholder() || this.currentTranslations().editor.placeholder));
|
|
6275
|
+
this.finalFillContainer = computed(() => this.effectiveConfig().fillContainer ?? this.fillContainer());
|
|
6276
|
+
this.finalShowFooter = computed(() => this.effectiveConfig().showFooter ?? this.showFooter());
|
|
6277
|
+
this.finalShowEditToggle = computed(() => this.effectiveConfig().showEditToggle ?? this.showEditToggle());
|
|
6278
|
+
this.finalHeight = computed(() => this.effectiveConfig().height ?? (this.height() ? `${this.height()}px` : undefined));
|
|
6279
|
+
this.finalMinHeight = computed(() => this.effectiveConfig().minHeight ?? (this.minHeight() ? `${this.minHeight()}px` : undefined));
|
|
6280
|
+
this.finalMaxHeight = computed(() => this.effectiveConfig().maxHeight ?? (this.maxHeight() ? `${this.maxHeight()}px` : undefined));
|
|
6281
|
+
this.finalSpellcheck = computed(() => this.effectiveConfig().spellcheck ?? this.spellcheck());
|
|
6282
|
+
this.finalEnableOfficePaste = computed(() => this.effectiveConfig().enableOfficePaste ?? this.enableOfficePaste());
|
|
5876
6283
|
// Features
|
|
5877
|
-
this.finalShowToolbar = computed(() => this.
|
|
6284
|
+
this.finalShowToolbar = computed(() => this.effectiveConfig().showToolbar ?? this.showToolbar());
|
|
5878
6285
|
this.finalToolbarConfig = computed(() => {
|
|
5879
|
-
const fromConfig = this.
|
|
6286
|
+
const fromConfig = this.effectiveConfig().toolbar;
|
|
5880
6287
|
const base = ATE_DEFAULT_TOOLBAR_CONFIG;
|
|
5881
6288
|
if (fromConfig) {
|
|
5882
6289
|
return { ...base, ...fromConfig };
|
|
5883
6290
|
}
|
|
5884
6291
|
const fromInput = this.toolbar();
|
|
5885
6292
|
return Object.keys(fromInput).length === 0 ? base : { ...base, ...fromInput };
|
|
5886
|
-
}
|
|
5887
|
-
this.finalFloatingToolbar = computed(() => this.
|
|
5888
|
-
this.finalShowBubbleMenu = computed(() => this.
|
|
6293
|
+
});
|
|
6294
|
+
this.finalFloatingToolbar = computed(() => this.effectiveConfig().floatingToolbar ?? this.floatingToolbar());
|
|
6295
|
+
this.finalShowBubbleMenu = computed(() => this.effectiveConfig().showBubbleMenu ?? this.showBubbleMenu());
|
|
5889
6296
|
this.finalBubbleMenuConfig = computed(() => {
|
|
5890
|
-
const fromConfig = this.
|
|
6297
|
+
const fromConfig = this.effectiveConfig().bubbleMenu;
|
|
5891
6298
|
const base = ATE_DEFAULT_BUBBLE_MENU_CONFIG;
|
|
5892
6299
|
if (fromConfig) {
|
|
5893
6300
|
return { ...base, ...fromConfig };
|
|
5894
6301
|
}
|
|
5895
6302
|
return Object.keys(this.bubbleMenu()).length === 0 ? base : { ...base, ...this.bubbleMenu() };
|
|
5896
|
-
}
|
|
5897
|
-
this.finalShowImageBubbleMenu = computed(() => this.
|
|
6303
|
+
});
|
|
6304
|
+
this.finalShowImageBubbleMenu = computed(() => this.effectiveConfig().showImageBubbleMenu ?? this.showImageBubbleMenu());
|
|
5898
6305
|
this.finalImageBubbleMenuConfig = computed(() => {
|
|
5899
|
-
const fromConfig = this.
|
|
6306
|
+
const fromConfig = this.effectiveConfig().imageBubbleMenu;
|
|
5900
6307
|
const base = ATE_DEFAULT_IMAGE_BUBBLE_MENU_CONFIG;
|
|
5901
6308
|
if (fromConfig) {
|
|
5902
6309
|
return { ...base, ...fromConfig };
|
|
@@ -5904,10 +6311,10 @@ class AngularTiptapEditorComponent {
|
|
|
5904
6311
|
return Object.keys(this.imageBubbleMenu()).length === 0
|
|
5905
6312
|
? base
|
|
5906
6313
|
: { ...base, ...this.imageBubbleMenu() };
|
|
5907
|
-
}
|
|
5908
|
-
this.finalShowTableBubbleMenu = computed(() => this.
|
|
6314
|
+
});
|
|
6315
|
+
this.finalShowTableBubbleMenu = computed(() => this.effectiveConfig().showTableMenu ?? this.showTableBubbleMenu());
|
|
5909
6316
|
this.finalTableBubbleMenuConfig = computed(() => {
|
|
5910
|
-
const fromConfig = this.
|
|
6317
|
+
const fromConfig = this.effectiveConfig().tableBubbleMenu;
|
|
5911
6318
|
const base = ATE_DEFAULT_TABLE_MENU_CONFIG;
|
|
5912
6319
|
if (fromConfig) {
|
|
5913
6320
|
return { ...base, ...fromConfig };
|
|
@@ -5915,10 +6322,10 @@ class AngularTiptapEditorComponent {
|
|
|
5915
6322
|
return Object.keys(this.tableBubbleMenu()).length === 0
|
|
5916
6323
|
? base
|
|
5917
6324
|
: { ...base, ...this.tableBubbleMenu() };
|
|
5918
|
-
}
|
|
5919
|
-
this.finalShowCellBubbleMenu = computed(() => this.
|
|
6325
|
+
});
|
|
6326
|
+
this.finalShowCellBubbleMenu = computed(() => this.effectiveConfig().showCellMenu ?? this.showCellBubbleMenu());
|
|
5920
6327
|
this.finalCellBubbleMenuConfig = computed(() => {
|
|
5921
|
-
const fromConfig = this.
|
|
6328
|
+
const fromConfig = this.effectiveConfig().cellBubbleMenu;
|
|
5922
6329
|
const base = ATE_DEFAULT_CELL_MENU_CONFIG;
|
|
5923
6330
|
if (fromConfig) {
|
|
5924
6331
|
return { ...base, ...fromConfig };
|
|
@@ -5926,11 +6333,13 @@ class AngularTiptapEditorComponent {
|
|
|
5926
6333
|
return Object.keys(this.cellBubbleMenu()).length === 0
|
|
5927
6334
|
? base
|
|
5928
6335
|
: { ...base, ...this.cellBubbleMenu() };
|
|
5929
|
-
}
|
|
5930
|
-
this.finalEnableSlashCommands = computed(() => this.
|
|
6336
|
+
});
|
|
6337
|
+
this.finalEnableSlashCommands = computed(() => this.effectiveConfig().enableSlashCommands ?? this.enableSlashCommands());
|
|
5931
6338
|
this.finalSlashCommandsConfig = computed(() => {
|
|
5932
|
-
const fromConfig = this.
|
|
5933
|
-
const
|
|
6339
|
+
const fromConfig = this.effectiveConfig().slashCommands;
|
|
6340
|
+
const fromGlobalCustom = this.effectiveConfig().customSlashCommands;
|
|
6341
|
+
const fromInputCustom = this.customSlashCommands();
|
|
6342
|
+
const customConfig = fromInputCustom ?? fromGlobalCustom;
|
|
5934
6343
|
if (customConfig) {
|
|
5935
6344
|
return customConfig;
|
|
5936
6345
|
}
|
|
@@ -5941,16 +6350,21 @@ class AngularTiptapEditorComponent {
|
|
|
5941
6350
|
return {
|
|
5942
6351
|
commands: filterSlashCommands(baseConfig, this.i18nService, this.editorCommandsService, this.finalImageUploadConfig()),
|
|
5943
6352
|
};
|
|
5944
|
-
}
|
|
6353
|
+
});
|
|
5945
6354
|
// Behavior
|
|
5946
|
-
this.finalAutofocus = computed(() => this.
|
|
5947
|
-
this.finalMaxCharacters = computed(() => this.
|
|
5948
|
-
this.finalShowCharacterCount = computed(() => this.
|
|
5949
|
-
this.finalShowWordCount = computed(() => this.
|
|
5950
|
-
this.finalLocale = computed(() => this.
|
|
6355
|
+
this.finalAutofocus = computed(() => this.effectiveConfig().autofocus ?? this.autofocus());
|
|
6356
|
+
this.finalMaxCharacters = computed(() => this.effectiveConfig().maxCharacters ?? this.maxCharacters());
|
|
6357
|
+
this.finalShowCharacterCount = computed(() => this.effectiveConfig().showCharacterCount ?? this.showCharacterCount());
|
|
6358
|
+
this.finalShowWordCount = computed(() => this.effectiveConfig().showWordCount ?? this.showWordCount());
|
|
6359
|
+
this.finalLocale = computed(() => this.effectiveConfig().locale ?? this.locale());
|
|
6360
|
+
// Extensions & Options
|
|
6361
|
+
this.finalTiptapExtensions = computed(() => this.effectiveConfig().tiptapExtensions ?? this.tiptapExtensions() ?? []);
|
|
6362
|
+
this.finalTiptapOptions = computed(() => this.effectiveConfig().tiptapOptions ?? this.tiptapOptions() ?? {});
|
|
6363
|
+
this.finalStateCalculators = computed(() => this.effectiveConfig().stateCalculators ?? this.stateCalculators() ?? []);
|
|
6364
|
+
this.finalAngularNodesConfig = computed(() => this.effectiveConfig().angularNodes ?? []);
|
|
5951
6365
|
// Image Upload
|
|
5952
6366
|
this.finalImageUploadConfig = computed(() => {
|
|
5953
|
-
const fromConfig = this.
|
|
6367
|
+
const fromConfig = this.effectiveConfig().imageUpload;
|
|
5954
6368
|
const fromInput = this.imageUpload();
|
|
5955
6369
|
const merged = {
|
|
5956
6370
|
maxSize: 5, // Default 5MB
|
|
@@ -5969,8 +6383,8 @@ class AngularTiptapEditorComponent {
|
|
|
5969
6383
|
...merged,
|
|
5970
6384
|
maxSize: merged.maxSize * 1024 * 1024, // Convert MB to bytes for internal service
|
|
5971
6385
|
};
|
|
5972
|
-
}
|
|
5973
|
-
this.finalImageUploadHandler = computed(() => this.
|
|
6386
|
+
});
|
|
6387
|
+
this.finalImageUploadHandler = computed(() => this.effectiveConfig().imageUpload?.handler ?? this.imageUploadHandler());
|
|
5974
6388
|
// Computed for current translations (allows per-instance override via config or input)
|
|
5975
6389
|
this.currentTranslations = computed(() => {
|
|
5976
6390
|
const localeOverride = this.finalLocale();
|
|
@@ -5979,7 +6393,7 @@ class AngularTiptapEditorComponent {
|
|
|
5979
6393
|
return allTranslations[localeOverride] || this.i18nService.translations();
|
|
5980
6394
|
}
|
|
5981
6395
|
return this.i18nService.translations();
|
|
5982
|
-
}
|
|
6396
|
+
});
|
|
5983
6397
|
this._destroyRef = inject(DestroyRef);
|
|
5984
6398
|
// NgControl for management of FormControls
|
|
5985
6399
|
this.ngControl = inject(NgControl, { self: true, optional: true });
|
|
@@ -5987,6 +6401,17 @@ class AngularTiptapEditorComponent {
|
|
|
5987
6401
|
this.editorCommandsService = inject(AteEditorCommandsService);
|
|
5988
6402
|
// Access editor state via service
|
|
5989
6403
|
this.editorState = this.editorCommandsService.editorState;
|
|
6404
|
+
this.injector = inject(Injector);
|
|
6405
|
+
this.globalConfig = inject(ATE_GLOBAL_CONFIG, { optional: true });
|
|
6406
|
+
/**
|
|
6407
|
+
* Final merged configuration.
|
|
6408
|
+
* Priority: Input [config] > Global config via provideAteEditor()
|
|
6409
|
+
*/
|
|
6410
|
+
this.effectiveConfig = computed(() => {
|
|
6411
|
+
const fromInput = this.config();
|
|
6412
|
+
const fromGlobal = this.globalConfig || {};
|
|
6413
|
+
return { ...fromGlobal, ...fromInput };
|
|
6414
|
+
});
|
|
5990
6415
|
// Effect to update editor content (with anti-echo)
|
|
5991
6416
|
effect(() => {
|
|
5992
6417
|
const content = this.content(); // Sole reactive dependency
|
|
@@ -6010,7 +6435,7 @@ class AngularTiptapEditorComponent {
|
|
|
6010
6435
|
}
|
|
6011
6436
|
editor.commands.setContent(content, false);
|
|
6012
6437
|
});
|
|
6013
|
-
});
|
|
6438
|
+
}, { allowSignalWrites: true });
|
|
6014
6439
|
// Effect to update height properties
|
|
6015
6440
|
effect(() => {
|
|
6016
6441
|
const minHeight = this.finalMinHeight();
|
|
@@ -6025,7 +6450,7 @@ class AngularTiptapEditorComponent {
|
|
|
6025
6450
|
element.style.setProperty("--editor-max-height", maxHeight ?? "none");
|
|
6026
6451
|
element.style.setProperty("--editor-overflow", needsScroll ? "auto" : "visible");
|
|
6027
6452
|
}
|
|
6028
|
-
});
|
|
6453
|
+
}, { allowSignalWrites: true });
|
|
6029
6454
|
// Effect to monitor editability changes
|
|
6030
6455
|
effect(() => {
|
|
6031
6456
|
const currentEditor = this.editor();
|
|
@@ -6036,12 +6461,12 @@ class AngularTiptapEditorComponent {
|
|
|
6036
6461
|
if (currentEditor) {
|
|
6037
6462
|
this.editorCommandsService.setEditable(currentEditor, isEditable);
|
|
6038
6463
|
}
|
|
6039
|
-
});
|
|
6464
|
+
}, { allowSignalWrites: true });
|
|
6040
6465
|
// Effect to synchronize image upload handler with the service
|
|
6041
6466
|
effect(() => {
|
|
6042
6467
|
const handler = this.finalImageUploadHandler();
|
|
6043
6468
|
this.editorCommandsService.uploadHandler = handler || null;
|
|
6044
|
-
});
|
|
6469
|
+
}, { allowSignalWrites: true });
|
|
6045
6470
|
// Effect to update character count limit dynamically
|
|
6046
6471
|
effect(() => {
|
|
6047
6472
|
const editor = this.editor();
|
|
@@ -6052,12 +6477,13 @@ class AngularTiptapEditorComponent {
|
|
|
6052
6477
|
characterCountExtension.options.limit = limit;
|
|
6053
6478
|
}
|
|
6054
6479
|
}
|
|
6055
|
-
});
|
|
6056
|
-
// Effect to re-initialize editor when
|
|
6480
|
+
}, { allowSignalWrites: true });
|
|
6481
|
+
// Effect to re-initialize editor when technical configuration changes
|
|
6057
6482
|
effect(() => {
|
|
6058
|
-
// Monitor
|
|
6059
|
-
this.
|
|
6060
|
-
this.
|
|
6483
|
+
// Monitor technical dependencies
|
|
6484
|
+
this.finalTiptapExtensions();
|
|
6485
|
+
this.finalTiptapOptions();
|
|
6486
|
+
this.finalAngularNodesConfig();
|
|
6061
6487
|
untracked(() => {
|
|
6062
6488
|
// Only if already initialized (post AfterViewInit)
|
|
6063
6489
|
if (this.editorFullyInitialized()) {
|
|
@@ -6069,7 +6495,7 @@ class AngularTiptapEditorComponent {
|
|
|
6069
6495
|
}
|
|
6070
6496
|
}
|
|
6071
6497
|
});
|
|
6072
|
-
});
|
|
6498
|
+
}, { allowSignalWrites: true });
|
|
6073
6499
|
}
|
|
6074
6500
|
ngAfterViewInit() {
|
|
6075
6501
|
// La vue est déjà complètement initialisée dans ngAfterViewInit
|
|
@@ -6136,7 +6562,7 @@ class AngularTiptapEditorComponent {
|
|
|
6136
6562
|
AteImageCalculator,
|
|
6137
6563
|
AteStructureCalculator,
|
|
6138
6564
|
AteDiscoveryCalculator,
|
|
6139
|
-
...this.
|
|
6565
|
+
...this.finalStateCalculators(),
|
|
6140
6566
|
],
|
|
6141
6567
|
}),
|
|
6142
6568
|
];
|
|
@@ -6153,8 +6579,22 @@ class AngularTiptapEditorComponent {
|
|
|
6153
6579
|
limit: this.finalMaxCharacters(),
|
|
6154
6580
|
}));
|
|
6155
6581
|
}
|
|
6582
|
+
// Register automatic node views from config
|
|
6583
|
+
const autoNodeViews = this.finalAngularNodesConfig();
|
|
6584
|
+
autoNodeViews.forEach(reg => {
|
|
6585
|
+
const options = typeof reg === "function"
|
|
6586
|
+
? { component: reg }
|
|
6587
|
+
: reg;
|
|
6588
|
+
try {
|
|
6589
|
+
const extension = registerAngularComponent(this.injector, options);
|
|
6590
|
+
extensions.push(extension);
|
|
6591
|
+
}
|
|
6592
|
+
catch (e) {
|
|
6593
|
+
console.error("[ATE] Failed to auto-register node view:", e);
|
|
6594
|
+
}
|
|
6595
|
+
});
|
|
6156
6596
|
// Allow addition of custom extensions, but avoid duplicates by filtering by name
|
|
6157
|
-
const customExtensions = this.
|
|
6597
|
+
const customExtensions = this.finalTiptapExtensions();
|
|
6158
6598
|
if (customExtensions.length > 0) {
|
|
6159
6599
|
const existingNames = new Set(extensions
|
|
6160
6600
|
.map(ext => ext?.name)
|
|
@@ -6166,7 +6606,7 @@ class AngularTiptapEditorComponent {
|
|
|
6166
6606
|
extensions.push(...toAdd);
|
|
6167
6607
|
}
|
|
6168
6608
|
// Also allow any tiptap user options
|
|
6169
|
-
const userOptions = this.
|
|
6609
|
+
const userOptions = this.finalTiptapOptions();
|
|
6170
6610
|
const newEditor = new Editor({
|
|
6171
6611
|
...userOptions,
|
|
6172
6612
|
element: this.editorElement().nativeElement,
|
|
@@ -6341,8 +6781,8 @@ class AngularTiptapEditorComponent {
|
|
|
6341
6781
|
}, 0);
|
|
6342
6782
|
}
|
|
6343
6783
|
}
|
|
6344
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
6345
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "
|
|
6784
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AngularTiptapEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6785
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AngularTiptapEditorComponent, isStandalone: true, selector: "angular-tiptap-editor", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, fillContainer: { classPropertyName: "fillContainer", publicName: "fillContainer", isSignal: true, isRequired: false, transformFunction: null }, showToolbar: { classPropertyName: "showToolbar", publicName: "showToolbar", isSignal: true, isRequired: false, transformFunction: null }, showFooter: { classPropertyName: "showFooter", publicName: "showFooter", isSignal: true, isRequired: false, transformFunction: null }, showCharacterCount: { classPropertyName: "showCharacterCount", publicName: "showCharacterCount", isSignal: true, isRequired: false, transformFunction: null }, showWordCount: { classPropertyName: "showWordCount", publicName: "showWordCount", isSignal: true, isRequired: false, transformFunction: null }, maxCharacters: { classPropertyName: "maxCharacters", publicName: "maxCharacters", isSignal: true, isRequired: false, transformFunction: null }, enableOfficePaste: { classPropertyName: "enableOfficePaste", publicName: "enableOfficePaste", isSignal: true, isRequired: false, transformFunction: null }, enableSlashCommands: { classPropertyName: "enableSlashCommands", publicName: "enableSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, slashCommands: { classPropertyName: "slashCommands", publicName: "slashCommands", isSignal: true, isRequired: false, transformFunction: null }, customSlashCommands: { classPropertyName: "customSlashCommands", publicName: "customSlashCommands", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, seamless: { classPropertyName: "seamless", publicName: "seamless", isSignal: true, isRequired: false, transformFunction: null }, floatingToolbar: { classPropertyName: "floatingToolbar", publicName: "floatingToolbar", isSignal: true, isRequired: false, transformFunction: null }, showEditToggle: { classPropertyName: "showEditToggle", publicName: "showEditToggle", isSignal: true, isRequired: false, transformFunction: null }, spellcheck: { classPropertyName: "spellcheck", publicName: "spellcheck", isSignal: true, isRequired: false, transformFunction: null }, tiptapExtensions: { classPropertyName: "tiptapExtensions", publicName: "tiptapExtensions", isSignal: true, isRequired: false, transformFunction: null }, tiptapOptions: { classPropertyName: "tiptapOptions", publicName: "tiptapOptions", isSignal: true, isRequired: false, transformFunction: null }, showBubbleMenu: { classPropertyName: "showBubbleMenu", publicName: "showBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, bubbleMenu: { classPropertyName: "bubbleMenu", publicName: "bubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showImageBubbleMenu: { classPropertyName: "showImageBubbleMenu", publicName: "showImageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, imageBubbleMenu: { classPropertyName: "imageBubbleMenu", publicName: "imageBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, toolbar: { classPropertyName: "toolbar", publicName: "toolbar", isSignal: true, isRequired: false, transformFunction: null }, showTableBubbleMenu: { classPropertyName: "showTableBubbleMenu", publicName: "showTableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, tableBubbleMenu: { classPropertyName: "tableBubbleMenu", publicName: "tableBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, showCellBubbleMenu: { classPropertyName: "showCellBubbleMenu", publicName: "showCellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, cellBubbleMenu: { classPropertyName: "cellBubbleMenu", publicName: "cellBubbleMenu", isSignal: true, isRequired: false, transformFunction: null }, stateCalculators: { classPropertyName: "stateCalculators", publicName: "stateCalculators", isSignal: true, isRequired: false, transformFunction: null }, imageUpload: { classPropertyName: "imageUpload", publicName: "imageUpload", isSignal: true, isRequired: false, transformFunction: null }, imageUploadHandler: { classPropertyName: "imageUploadHandler", publicName: "imageUploadHandler", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { contentChange: "contentChange", editorCreated: "editorCreated", editorUpdate: "editorUpdate", editorFocus: "editorFocus", editorBlur: "editorBlur", editableChange: "editableChange" }, host: { properties: { "class.fill-container": "finalFillContainer()", "class.floating-toolbar": "finalFloatingToolbar()", "class.is-readonly": "!finalEditable() && !mergedDisabled()", "class.is-disabled": "mergedDisabled()", "style.--ate-border-width": "finalSeamless() || mergedDisabled() ? '0' : null", "style.--ate-background": "finalSeamless() ? 'transparent' : (mergedDisabled() ? 'var(--ate-surface-tertiary)' : null)", "style.--ate-toolbar-border-color": "finalSeamless() ? 'transparent' : null", "style.--ate-counter-background": "finalSeamless() ? 'transparent' : null", "style.--ate-counter-border-color": "finalSeamless() ? 'transparent' : null", "class.dark": "config().theme === 'dark'", "attr.data-theme": "config().theme" } }, providers: [AteEditorCommandsService, AteImageService, AteColorPickerService, AteLinkService], viewQueries: [{ propertyName: "editorElement", first: true, predicate: ["editorElement"], descendants: true, isSignal: true }], hostDirectives: [{ directive: AteNoopValueAccessorDirective }], ngImport: i0, template: `
|
|
6346
6786
|
<div class="ate-editor">
|
|
6347
6787
|
<!-- Toolbar -->
|
|
6348
6788
|
@if (finalEditable() && !mergedDisabled() && finalShowToolbar() && editor()) {
|
|
@@ -6462,7 +6902,7 @@ class AngularTiptapEditorComponent {
|
|
|
6462
6902
|
</div>
|
|
6463
6903
|
`, 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 }); }
|
|
6464
6904
|
}
|
|
6465
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
6905
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AngularTiptapEditorComponent, decorators: [{
|
|
6466
6906
|
type: Component,
|
|
6467
6907
|
args: [{ selector: "angular-tiptap-editor", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [AteNoopValueAccessorDirective], host: {
|
|
6468
6908
|
"[class.fill-container]": "finalFillContainer()",
|
|
@@ -6566,532 +7006,170 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
6566
7006
|
[config]="finalTableBubbleMenuConfig()"
|
|
6567
7007
|
[style.display]="editorFullyInitialized() ? 'block' : 'none'"></ate-table-bubble-menu>
|
|
6568
7008
|
}
|
|
6569
|
-
|
|
6570
|
-
<!-- Cell Menu -->
|
|
6571
|
-
@if (finalEditable() && finalShowCellBubbleMenu() && editor()) {
|
|
6572
|
-
<ate-cell-bubble-menu
|
|
6573
|
-
[editor]="editor()!"
|
|
6574
|
-
[config]="finalCellBubbleMenuConfig()"
|
|
6575
|
-
[style.display]="editorFullyInitialized() ? 'block' : 'none'"></ate-cell-bubble-menu>
|
|
6576
|
-
}
|
|
6577
|
-
|
|
6578
|
-
<!-- Counters -->
|
|
6579
|
-
@if (
|
|
6580
|
-
finalEditable() &&
|
|
6581
|
-
!mergedDisabled() &&
|
|
6582
|
-
finalShowFooter() &&
|
|
6583
|
-
(finalShowCharacterCount() || finalShowWordCount())
|
|
6584
|
-
) {
|
|
6585
|
-
<div
|
|
6586
|
-
class="character-count"
|
|
6587
|
-
[class.limit-reached]="finalMaxCharacters() && characterCount() >= finalMaxCharacters()!">
|
|
6588
|
-
@if (finalShowCharacterCount()) {
|
|
6589
|
-
{{ characterCount() }}
|
|
6590
|
-
{{ currentTranslations().editor.character }}{{ characterCount() > 1 ? "s" : "" }}
|
|
6591
|
-
@if (finalMaxCharacters()) {
|
|
6592
|
-
/ {{ finalMaxCharacters() }}
|
|
6593
|
-
}
|
|
6594
|
-
}
|
|
6595
|
-
|
|
6596
|
-
@if (finalShowCharacterCount() && finalShowWordCount()) {
|
|
6597
|
-
,
|
|
6598
|
-
}
|
|
6599
|
-
|
|
6600
|
-
@if (finalShowWordCount()) {
|
|
6601
|
-
{{ wordCount() }}
|
|
6602
|
-
{{ currentTranslations().editor.word }}{{ wordCount() > 1 ? "s" : "" }}
|
|
6603
|
-
}
|
|
6604
|
-
</div>
|
|
6605
|
-
}
|
|
6606
|
-
</div>
|
|
6607
|
-
`, 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"] }]
|
|
6608
|
-
}], ctorParameters: () => []
|
|
6609
|
-
|
|
6610
|
-
/**
|
|
6611
|
-
*
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
"undo",
|
|
6639
|
-
"redo",
|
|
6640
|
-
"clear",
|
|
6641
|
-
"textColor",
|
|
6642
|
-
"separator",
|
|
6643
|
-
];
|
|
6644
|
-
|
|
6645
|
-
/**
|
|
6646
|
-
* Clés des options du menu bulle de texte
|
|
6647
|
-
*/
|
|
6648
|
-
const ATE_BUBBLE_MENU_KEYS = [
|
|
6649
|
-
"bold",
|
|
6650
|
-
"italic",
|
|
6651
|
-
"underline",
|
|
6652
|
-
"strike",
|
|
6653
|
-
"code",
|
|
6654
|
-
"superscript",
|
|
6655
|
-
"subscript",
|
|
6656
|
-
"highlight",
|
|
6657
|
-
"highlightPicker",
|
|
6658
|
-
"textColor",
|
|
6659
|
-
"link",
|
|
6660
|
-
"separator",
|
|
6661
|
-
];
|
|
6662
|
-
/**
|
|
6663
|
-
* Clés des options du menu bulle d'image
|
|
6664
|
-
*/
|
|
6665
|
-
const ATE_IMAGE_BUBBLE_MENU_KEYS = [
|
|
6666
|
-
"changeImage",
|
|
6667
|
-
"resizeSmall",
|
|
6668
|
-
"resizeMedium",
|
|
6669
|
-
"resizeLarge",
|
|
6670
|
-
"resizeOriginal",
|
|
6671
|
-
"deleteImage",
|
|
6672
|
-
"separator",
|
|
6673
|
-
];
|
|
6674
|
-
/**
|
|
6675
|
-
* Clés des options du menu de table
|
|
6676
|
-
*/
|
|
6677
|
-
const ATE_TABLE_BUBBLE_MENU_KEYS = [
|
|
6678
|
-
"addRowBefore",
|
|
6679
|
-
"addRowAfter",
|
|
6680
|
-
"deleteRow",
|
|
6681
|
-
"addColumnBefore",
|
|
6682
|
-
"addColumnAfter",
|
|
6683
|
-
"deleteColumn",
|
|
6684
|
-
"deleteTable",
|
|
6685
|
-
"toggleHeaderRow",
|
|
6686
|
-
"toggleHeaderColumn",
|
|
6687
|
-
"separator",
|
|
6688
|
-
];
|
|
6689
|
-
/**
|
|
6690
|
-
* Clés des options du menu de cellule
|
|
6691
|
-
*/
|
|
6692
|
-
const ATE_CELL_BUBBLE_MENU_KEYS = ["mergeCells", "splitCell"];
|
|
6693
|
-
|
|
6694
|
-
/**
|
|
6695
|
-
* Base abstract class for Angular components used as TipTap NodeViews.
|
|
6696
|
-
*
|
|
6697
|
-
* Extend this class in your custom components to get access to the TipTap node properties.
|
|
6698
|
-
*
|
|
6699
|
-
* @example
|
|
6700
|
-
* ```typescript
|
|
6701
|
-
* @Component({
|
|
6702
|
-
* selector: 'app-counter',
|
|
6703
|
-
* template: `
|
|
6704
|
-
* <div>
|
|
6705
|
-
* <button (click)="increment()">Count: {{ node().attrs['count'] }}</button>
|
|
6706
|
-
* </div>
|
|
6707
|
-
* `
|
|
6708
|
-
* })
|
|
6709
|
-
* export class CounterComponent extends AteAngularNodeView {
|
|
6710
|
-
* increment() {
|
|
6711
|
-
* const count = this.node().attrs['count'] || 0;
|
|
6712
|
-
* this.updateAttributes({ count: count + 1 });
|
|
6713
|
-
* }
|
|
6714
|
-
* }
|
|
6715
|
-
* ```
|
|
6716
|
-
*/
|
|
6717
|
-
class AteAngularNodeView {
|
|
6718
|
-
/**
|
|
6719
|
-
* Internal method to initialize the component with NodeView props.
|
|
6720
|
-
* This is called by the AngularNodeViewRenderer.
|
|
6721
|
-
*
|
|
6722
|
-
* @internal
|
|
6723
|
-
*/
|
|
6724
|
-
_initNodeView(props) {
|
|
6725
|
-
// Create signals from the props
|
|
6726
|
-
const editorSignal = signal(props.editor, ...(ngDevMode ? [{ debugName: "editorSignal" }] : []));
|
|
6727
|
-
const nodeSignal = signal(props.node, ...(ngDevMode ? [{ debugName: "nodeSignal" }] : []));
|
|
6728
|
-
const decorationsSignal = signal(props.decorations, ...(ngDevMode ? [{ debugName: "decorationsSignal" }] : []));
|
|
6729
|
-
const selectedSignal = signal(props.selected, ...(ngDevMode ? [{ debugName: "selectedSignal" }] : []));
|
|
6730
|
-
const extensionSignal = signal(props.extension, ...(ngDevMode ? [{ debugName: "extensionSignal" }] : []));
|
|
6731
|
-
// Assign to the component
|
|
6732
|
-
this.editor = editorSignal.asReadonly();
|
|
6733
|
-
this.node = nodeSignal.asReadonly();
|
|
6734
|
-
this.decorations = decorationsSignal.asReadonly();
|
|
6735
|
-
this.selected = selectedSignal.asReadonly();
|
|
6736
|
-
this.extension = extensionSignal.asReadonly();
|
|
6737
|
-
this.getPos = props.getPos;
|
|
6738
|
-
this.updateAttributes = props.updateAttributes;
|
|
6739
|
-
this.deleteNode = props.deleteNode;
|
|
6740
|
-
// Store writable signals for updates
|
|
6741
|
-
this._writableSignals = {
|
|
6742
|
-
node: nodeSignal,
|
|
6743
|
-
decorations: decorationsSignal,
|
|
6744
|
-
selected: selectedSignal,
|
|
6745
|
-
};
|
|
6746
|
-
}
|
|
6747
|
-
/**
|
|
6748
|
-
* Internal method to update the component when the node changes.
|
|
6749
|
-
* This is called by the AngularNodeViewRenderer.
|
|
6750
|
-
*
|
|
6751
|
-
* @internal
|
|
6752
|
-
*/
|
|
6753
|
-
_updateNodeView(node, decorations) {
|
|
6754
|
-
if (this._writableSignals) {
|
|
6755
|
-
this._writableSignals.node.set(node);
|
|
6756
|
-
this._writableSignals.decorations.set(decorations);
|
|
6757
|
-
}
|
|
6758
|
-
}
|
|
6759
|
-
/**
|
|
6760
|
-
* Internal method to update the selection state.
|
|
6761
|
-
* This is called by the AngularNodeViewRenderer.
|
|
6762
|
-
*
|
|
6763
|
-
* @internal
|
|
6764
|
-
*/
|
|
6765
|
-
_selectNodeView() {
|
|
6766
|
-
if (this._writableSignals) {
|
|
6767
|
-
this._writableSignals.selected.set(true);
|
|
6768
|
-
}
|
|
6769
|
-
}
|
|
6770
|
-
/**
|
|
6771
|
-
* Internal method to update the deselection state.
|
|
6772
|
-
* This is called by the AngularNodeViewRenderer.
|
|
6773
|
-
*
|
|
6774
|
-
* @internal
|
|
6775
|
-
*/
|
|
6776
|
-
_deselectNodeView() {
|
|
6777
|
-
if (this._writableSignals) {
|
|
6778
|
-
this._writableSignals.selected.set(false);
|
|
6779
|
-
}
|
|
6780
|
-
}
|
|
6781
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteAngularNodeView, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
6782
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: AteAngularNodeView, isStandalone: true, ngImport: i0 }); }
|
|
6783
|
-
}
|
|
6784
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AteAngularNodeView, decorators: [{
|
|
6785
|
-
type: Directive
|
|
6786
|
-
}] });
|
|
6787
|
-
|
|
6788
|
-
/**
|
|
6789
|
-
* Universal Renderer for Angular Components as TipTap NodeViews.
|
|
6790
|
-
*
|
|
6791
|
-
* Supports:
|
|
6792
|
-
* - TipTap-Aware components (extending AteAngularNodeView)
|
|
6793
|
-
* - Standard library components (automatic @Input() sync)
|
|
6794
|
-
* - Signal-based inputs and outputs (Angular 18+)
|
|
6795
|
-
* - Content projection (editableContent)
|
|
6796
|
-
* - Unified lifecycle and event management
|
|
6797
|
-
*/
|
|
6798
|
-
function AteNodeViewRenderer(component, options) {
|
|
6799
|
-
return props => {
|
|
6800
|
-
const { node, view: _view, getPos, decorations, editor, extension } = props;
|
|
6801
|
-
const { injector, inputs = {}, wrapperTag = "div", wrapperClass, editableContent = false, contentSelector, onOutput, ignoreMutation = true, } = options;
|
|
6802
|
-
const dom = document.createElement(wrapperTag);
|
|
6803
|
-
if (wrapperClass) {
|
|
6804
|
-
dom.className = wrapperClass;
|
|
6805
|
-
}
|
|
6806
|
-
const applicationRef = injector.get(ApplicationRef);
|
|
6807
|
-
const environmentInjector = injector.get(EnvironmentInjector);
|
|
6808
|
-
// 1. Setup Content Projection (ng-content)
|
|
6809
|
-
let initialNodes = [];
|
|
6810
|
-
let contentDOM = null;
|
|
6811
|
-
if (editableContent && !contentSelector) {
|
|
6812
|
-
contentDOM = document.createElement("div");
|
|
6813
|
-
contentDOM.setAttribute("data-node-view-content", "");
|
|
6814
|
-
initialNodes = [[contentDOM]];
|
|
6815
|
-
}
|
|
6816
|
-
// 2. Create the Angular Component
|
|
6817
|
-
const componentRef = createComponent(component, {
|
|
6818
|
-
environmentInjector,
|
|
6819
|
-
elementInjector: injector,
|
|
6820
|
-
projectableNodes: initialNodes,
|
|
6821
|
-
});
|
|
6822
|
-
const instance = componentRef.instance;
|
|
6823
|
-
const subscriptions = [];
|
|
6824
|
-
// 3. Initialize TipTap-Aware instances
|
|
6825
|
-
if (instance instanceof AteAngularNodeView) {
|
|
6826
|
-
instance._initNodeView({
|
|
6827
|
-
editor,
|
|
6828
|
-
node,
|
|
6829
|
-
decorations,
|
|
6830
|
-
selected: false,
|
|
6831
|
-
extension,
|
|
6832
|
-
getPos,
|
|
6833
|
-
updateAttributes: attrs => editor.commands.updateAttributes(node.type.name, attrs),
|
|
6834
|
-
deleteNode: () => {
|
|
6835
|
-
const pos = getPos();
|
|
6836
|
-
if (pos !== undefined) {
|
|
6837
|
-
editor.commands.deleteRange({ from: pos, to: pos + node.nodeSize });
|
|
6838
|
-
}
|
|
6839
|
-
},
|
|
6840
|
-
});
|
|
6841
|
-
}
|
|
6842
|
-
// 4. Synchronize Inputs (Handles standard @Input and Signal-based inputs)
|
|
6843
|
-
const syncInputs = (nodeToSync) => {
|
|
6844
|
-
// Combine base inputs from options with dynamic node attributes
|
|
6845
|
-
const mergedInputs = { ...inputs, ...nodeToSync.attrs };
|
|
6846
|
-
Object.entries(mergedInputs).forEach(([key, value]) => {
|
|
6847
|
-
if (key !== "id" && value !== null && value !== undefined) {
|
|
6848
|
-
try {
|
|
6849
|
-
componentRef.setInput(key, value);
|
|
6850
|
-
}
|
|
6851
|
-
catch {
|
|
6852
|
-
// Silently ignore inputs that don't exist on the component
|
|
6853
|
-
}
|
|
6854
|
-
}
|
|
6855
|
-
});
|
|
6856
|
-
};
|
|
6857
|
-
syncInputs(node);
|
|
6858
|
-
// 5. Setup Outputs (Handles EventEmitter and OutputRef)
|
|
6859
|
-
if (onOutput) {
|
|
6860
|
-
Object.entries(instance).forEach(([key, potentialOutput]) => {
|
|
6861
|
-
if (potentialOutput &&
|
|
6862
|
-
typeof potentialOutput
|
|
6863
|
-
.subscribe === "function") {
|
|
6864
|
-
const sub = potentialOutput.subscribe((value) => {
|
|
6865
|
-
onOutput(key, value);
|
|
6866
|
-
});
|
|
6867
|
-
if (sub instanceof Subscription) {
|
|
6868
|
-
subscriptions.push(sub);
|
|
6869
|
-
}
|
|
6870
|
-
}
|
|
6871
|
-
});
|
|
6872
|
-
}
|
|
6873
|
-
// 6. Attach to DOM and ApplicationRef
|
|
6874
|
-
applicationRef.attachView(componentRef.hostView);
|
|
6875
|
-
const componentElement = componentRef.location.nativeElement;
|
|
6876
|
-
// Target specific element for content if selector provided
|
|
6877
|
-
if (editableContent && contentSelector) {
|
|
6878
|
-
contentDOM = componentElement.querySelector(contentSelector);
|
|
6879
|
-
}
|
|
6880
|
-
dom.appendChild(componentElement);
|
|
6881
|
-
// Initial detection to ensure the component is rendered
|
|
6882
|
-
componentRef.changeDetectorRef.detectChanges();
|
|
6883
|
-
// 7. Return the TipTap NodeView Interface
|
|
6884
|
-
return {
|
|
6885
|
-
dom,
|
|
6886
|
-
contentDOM,
|
|
6887
|
-
update: (updatedNode, updatedDecorations) => {
|
|
6888
|
-
if (updatedNode.type !== node.type) {
|
|
6889
|
-
return false;
|
|
6890
|
-
}
|
|
6891
|
-
// Update Aware component signals
|
|
6892
|
-
if (instance instanceof AteAngularNodeView) {
|
|
6893
|
-
instance._updateNodeView(updatedNode, updatedDecorations);
|
|
6894
|
-
}
|
|
6895
|
-
// Update inputs
|
|
6896
|
-
syncInputs(updatedNode);
|
|
6897
|
-
// Notify and Detect changes
|
|
6898
|
-
componentRef.changeDetectorRef.detectChanges();
|
|
6899
|
-
if (options.onUpdate) {
|
|
6900
|
-
options.onUpdate(updatedNode);
|
|
6901
|
-
}
|
|
6902
|
-
return true;
|
|
6903
|
-
},
|
|
6904
|
-
selectNode: () => {
|
|
6905
|
-
if (instance instanceof AteAngularNodeView) {
|
|
6906
|
-
instance._selectNodeView();
|
|
6907
|
-
}
|
|
6908
|
-
dom.classList.add("ProseMirror-selectednode");
|
|
6909
|
-
},
|
|
6910
|
-
deselectNode: () => {
|
|
6911
|
-
if (instance instanceof AteAngularNodeView) {
|
|
6912
|
-
instance._deselectNodeView();
|
|
6913
|
-
}
|
|
6914
|
-
dom.classList.remove("ProseMirror-selectednode");
|
|
6915
|
-
},
|
|
6916
|
-
destroy: () => {
|
|
6917
|
-
if (options.onDestroy) {
|
|
6918
|
-
options.onDestroy();
|
|
6919
|
-
}
|
|
6920
|
-
subscriptions.forEach(s => s.unsubscribe());
|
|
6921
|
-
applicationRef.detachView(componentRef.hostView);
|
|
6922
|
-
componentRef.destroy();
|
|
6923
|
-
},
|
|
6924
|
-
stopEvent: event => {
|
|
6925
|
-
const target = event.target;
|
|
6926
|
-
const isEditable = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
|
|
6927
|
-
return isEditable;
|
|
6928
|
-
},
|
|
6929
|
-
ignoreMutation: mutation => {
|
|
6930
|
-
if (typeof ignoreMutation === "function") {
|
|
6931
|
-
return ignoreMutation(mutation);
|
|
6932
|
-
}
|
|
6933
|
-
return ignoreMutation;
|
|
7009
|
+
|
|
7010
|
+
<!-- Cell Menu -->
|
|
7011
|
+
@if (finalEditable() && finalShowCellBubbleMenu() && editor()) {
|
|
7012
|
+
<ate-cell-bubble-menu
|
|
7013
|
+
[editor]="editor()!"
|
|
7014
|
+
[config]="finalCellBubbleMenuConfig()"
|
|
7015
|
+
[style.display]="editorFullyInitialized() ? 'block' : 'none'"></ate-cell-bubble-menu>
|
|
7016
|
+
}
|
|
7017
|
+
|
|
7018
|
+
<!-- Counters -->
|
|
7019
|
+
@if (
|
|
7020
|
+
finalEditable() &&
|
|
7021
|
+
!mergedDisabled() &&
|
|
7022
|
+
finalShowFooter() &&
|
|
7023
|
+
(finalShowCharacterCount() || finalShowWordCount())
|
|
7024
|
+
) {
|
|
7025
|
+
<div
|
|
7026
|
+
class="character-count"
|
|
7027
|
+
[class.limit-reached]="finalMaxCharacters() && characterCount() >= finalMaxCharacters()!">
|
|
7028
|
+
@if (finalShowCharacterCount()) {
|
|
7029
|
+
{{ characterCount() }}
|
|
7030
|
+
{{ currentTranslations().editor.character }}{{ characterCount() > 1 ? "s" : "" }}
|
|
7031
|
+
@if (finalMaxCharacters()) {
|
|
7032
|
+
/ {{ finalMaxCharacters() }}
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
|
|
7036
|
+
@if (finalShowCharacterCount() && finalShowWordCount()) {
|
|
7037
|
+
,
|
|
7038
|
+
}
|
|
7039
|
+
|
|
7040
|
+
@if (finalShowWordCount()) {
|
|
7041
|
+
{{ wordCount() }}
|
|
7042
|
+
{{ currentTranslations().editor.word }}{{ wordCount() > 1 ? "s" : "" }}
|
|
7043
|
+
}
|
|
7044
|
+
</div>
|
|
7045
|
+
}
|
|
7046
|
+
</div>
|
|
7047
|
+
`, 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"] }]
|
|
7048
|
+
}], ctorParameters: () => [] });
|
|
7049
|
+
|
|
7050
|
+
/**
|
|
7051
|
+
* Provides the necessary configuration and initialization for the Angular TipTap Editor.
|
|
7052
|
+
* This should be called in your app.config.ts (for standalone) or main.ts.
|
|
7053
|
+
*
|
|
7054
|
+
* This provider is essential for 'Angular Nodes' to work correctly, as it captures the
|
|
7055
|
+
* root Injector required to instantiate custom Angular components within the editor.
|
|
7056
|
+
* @example
|
|
7057
|
+
* ```ts
|
|
7058
|
+
* bootstrapApplication(AppComponent, {
|
|
7059
|
+
* providers: [
|
|
7060
|
+
* provideAteEditor({
|
|
7061
|
+
* theme: 'dark',
|
|
7062
|
+
* mode: 'seamless'
|
|
7063
|
+
* })
|
|
7064
|
+
* ]
|
|
7065
|
+
* });
|
|
7066
|
+
* ```
|
|
7067
|
+
*/
|
|
7068
|
+
function provideAteEditor(config) {
|
|
7069
|
+
return makeEnvironmentProviders([
|
|
7070
|
+
{
|
|
7071
|
+
provide: ATE_GLOBAL_CONFIG,
|
|
7072
|
+
useValue: config || {},
|
|
7073
|
+
},
|
|
7074
|
+
{
|
|
7075
|
+
provide: APP_INITIALIZER,
|
|
7076
|
+
useFactory: (injector) => () => {
|
|
7077
|
+
setGlobalInjector(injector);
|
|
6934
7078
|
},
|
|
6935
|
-
|
|
6936
|
-
|
|
7079
|
+
deps: [Injector],
|
|
7080
|
+
multi: true,
|
|
7081
|
+
},
|
|
7082
|
+
]);
|
|
6937
7083
|
}
|
|
6938
7084
|
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
"
|
|
7085
|
+
/**
|
|
7086
|
+
* Clés des boutons de la barre d'outils native
|
|
7087
|
+
*/
|
|
7088
|
+
const ATE_TOOLBAR_KEYS = [
|
|
7089
|
+
"bold",
|
|
7090
|
+
"italic",
|
|
7091
|
+
"underline",
|
|
7092
|
+
"strike",
|
|
7093
|
+
"code",
|
|
7094
|
+
"codeBlock",
|
|
7095
|
+
"superscript",
|
|
7096
|
+
"subscript",
|
|
7097
|
+
"highlight",
|
|
7098
|
+
"highlightPicker",
|
|
7099
|
+
"heading1",
|
|
7100
|
+
"heading2",
|
|
7101
|
+
"heading3",
|
|
6944
7102
|
"bulletList",
|
|
6945
7103
|
"orderedList",
|
|
6946
|
-
"listItem",
|
|
6947
7104
|
"blockquote",
|
|
6948
|
-
"
|
|
6949
|
-
"
|
|
7105
|
+
"alignLeft",
|
|
7106
|
+
"alignCenter",
|
|
7107
|
+
"alignRight",
|
|
7108
|
+
"alignJustify",
|
|
7109
|
+
"link",
|
|
7110
|
+
"image",
|
|
6950
7111
|
"horizontalRule",
|
|
7112
|
+
"table",
|
|
7113
|
+
"undo",
|
|
7114
|
+
"redo",
|
|
7115
|
+
"clear",
|
|
7116
|
+
"textColor",
|
|
7117
|
+
"separator",
|
|
6951
7118
|
];
|
|
7119
|
+
|
|
6952
7120
|
/**
|
|
6953
|
-
*
|
|
7121
|
+
* Clés des options du menu bulle de texte
|
|
6954
7122
|
*/
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
const tag = nodeName.toLowerCase().replace(/([A-Z])/g, "-$1");
|
|
6970
|
-
return { nodeName, tag };
|
|
6971
|
-
}
|
|
7123
|
+
const ATE_BUBBLE_MENU_KEYS = [
|
|
7124
|
+
"bold",
|
|
7125
|
+
"italic",
|
|
7126
|
+
"underline",
|
|
7127
|
+
"strike",
|
|
7128
|
+
"code",
|
|
7129
|
+
"superscript",
|
|
7130
|
+
"subscript",
|
|
7131
|
+
"highlight",
|
|
7132
|
+
"highlightPicker",
|
|
7133
|
+
"textColor",
|
|
7134
|
+
"link",
|
|
7135
|
+
"separator",
|
|
7136
|
+
];
|
|
6972
7137
|
/**
|
|
6973
|
-
*
|
|
7138
|
+
* Clés des options du menu bulle d'image
|
|
6974
7139
|
*/
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
}
|
|
6985
|
-
try {
|
|
6986
|
-
return JSON.parse(attr);
|
|
6987
|
-
}
|
|
6988
|
-
catch {
|
|
6989
|
-
return attr;
|
|
6990
|
-
}
|
|
6991
|
-
},
|
|
6992
|
-
renderHTML: (attrs) => {
|
|
6993
|
-
const value = attrs[key];
|
|
6994
|
-
if (value === undefined || value === null) {
|
|
6995
|
-
return {};
|
|
6996
|
-
}
|
|
6997
|
-
const serialized = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
6998
|
-
return { [`data-${key}`]: serialized };
|
|
6999
|
-
},
|
|
7000
|
-
};
|
|
7001
|
-
});
|
|
7002
|
-
return tiptapAttributes;
|
|
7003
|
-
}
|
|
7140
|
+
const ATE_IMAGE_BUBBLE_MENU_KEYS = [
|
|
7141
|
+
"changeImage",
|
|
7142
|
+
"resizeSmall",
|
|
7143
|
+
"resizeMedium",
|
|
7144
|
+
"resizeLarge",
|
|
7145
|
+
"resizeOriginal",
|
|
7146
|
+
"deleteImage",
|
|
7147
|
+
"separator",
|
|
7148
|
+
];
|
|
7004
7149
|
/**
|
|
7005
|
-
*
|
|
7006
|
-
* Supports both "TipTap-Aware" and "Standard" modes.
|
|
7007
|
-
*
|
|
7008
|
-
* @internal
|
|
7150
|
+
* Clés des options du menu de table
|
|
7009
7151
|
*/
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
group,
|
|
7023
|
-
inline: group === "inline",
|
|
7024
|
-
atom,
|
|
7025
|
-
draggable,
|
|
7026
|
-
content: editableContent ? (contentMode === "inline" ? "inline*" : "block*") : undefined,
|
|
7027
|
-
addAttributes() {
|
|
7028
|
-
return tiptapAttributes;
|
|
7029
|
-
},
|
|
7030
|
-
parseHTML() {
|
|
7031
|
-
if (customParseHTML) {
|
|
7032
|
-
return customParseHTML.call(this);
|
|
7033
|
-
}
|
|
7034
|
-
return [{ tag }, { tag: `div[data-component="${nodeName}"]` }];
|
|
7035
|
-
},
|
|
7036
|
-
renderHTML({ node, HTMLAttributes: attrs }) {
|
|
7037
|
-
if (customRenderHTML) {
|
|
7038
|
-
return customRenderHTML.call(this, { node, HTMLAttributes: attrs });
|
|
7039
|
-
}
|
|
7040
|
-
return [tag, mergeAttributes(HTMLAttributes, attrs, { "data-component": nodeName })];
|
|
7041
|
-
},
|
|
7042
|
-
addNodeView() {
|
|
7043
|
-
return AteNodeViewRenderer(component, {
|
|
7044
|
-
injector,
|
|
7045
|
-
inputs: defaultInputs,
|
|
7046
|
-
wrapperTag: group === "inline" ? "span" : "div",
|
|
7047
|
-
wrapperClass: isTipTapAware
|
|
7048
|
-
? `ate-node-${nodeName}`
|
|
7049
|
-
: `embedded-component embedded-${nodeName}`,
|
|
7050
|
-
atom,
|
|
7051
|
-
editableContent,
|
|
7052
|
-
contentSelector,
|
|
7053
|
-
contentMode,
|
|
7054
|
-
onOutput,
|
|
7055
|
-
ignoreMutation,
|
|
7056
|
-
});
|
|
7057
|
-
},
|
|
7058
|
-
});
|
|
7059
|
-
}
|
|
7060
|
-
|
|
7152
|
+
const ATE_TABLE_BUBBLE_MENU_KEYS = [
|
|
7153
|
+
"addRowBefore",
|
|
7154
|
+
"addRowAfter",
|
|
7155
|
+
"deleteRow",
|
|
7156
|
+
"addColumnBefore",
|
|
7157
|
+
"addColumnAfter",
|
|
7158
|
+
"deleteColumn",
|
|
7159
|
+
"deleteTable",
|
|
7160
|
+
"toggleHeaderRow",
|
|
7161
|
+
"toggleHeaderColumn",
|
|
7162
|
+
"separator",
|
|
7163
|
+
];
|
|
7061
7164
|
/**
|
|
7062
|
-
*
|
|
7063
|
-
*
|
|
7064
|
-
* This function is the single public entry point for adding custom components.
|
|
7065
|
-
* It supports two distinct modes:
|
|
7066
|
-
*
|
|
7067
|
-
* 1. **TipTap-Aware Mode** (the component extends `AteAngularNodeView`):
|
|
7068
|
-
* Grants direct access to the TipTap API (`editor`, `node`, `updateAttributes`, etc.) within the component.
|
|
7069
|
-
*
|
|
7070
|
-
* 2. **Standard Mode** (library or legacy components):
|
|
7071
|
-
* Allows using any existing Angular component. Its `@Input()` properties are automatically
|
|
7072
|
-
* synchronized with TipTap node attributes.
|
|
7073
|
-
*
|
|
7074
|
-
* @param injector - The Angular Injector (obtained via `inject(Injector)`)
|
|
7075
|
-
* @param options - Configuration options for the component extension
|
|
7076
|
-
* @returns A TipTap Node extension ready to be used
|
|
7077
|
-
*
|
|
7078
|
-
* @example
|
|
7079
|
-
* ```typescript
|
|
7080
|
-
* registerAngularComponent(injector, {
|
|
7081
|
-
* component: MyComponent,
|
|
7082
|
-
* name: 'myComponent',
|
|
7083
|
-
* defaultInputs: { color: 'blue' }
|
|
7084
|
-
* });
|
|
7085
|
-
* ```
|
|
7165
|
+
* Clés des options du menu de cellule
|
|
7086
7166
|
*/
|
|
7087
|
-
|
|
7088
|
-
return createAngularComponentExtension(injector, options);
|
|
7089
|
-
}
|
|
7167
|
+
const ATE_CELL_BUBBLE_MENU_KEYS = ["mergeCells", "splitCell"];
|
|
7090
7168
|
|
|
7091
7169
|
/*
|
|
7092
7170
|
* Public API Surface of tiptap-editor
|
|
7093
7171
|
*/
|
|
7094
|
-
// Main component
|
|
7172
|
+
// Main component & Provider
|
|
7095
7173
|
/** @deprecated Renamed to `ATE_INITIAL_EDITOR_STATE`. This alias will be removed in v3.0.0. */
|
|
7096
7174
|
const INITIAL_EDITOR_STATE = ATE_INITIAL_EDITOR_STATE;
|
|
7097
7175
|
/** @deprecated Renamed to `ATE_SLASH_COMMAND_KEYS`. This alias will be removed in v3.0.0. */
|
|
@@ -7125,5 +7203,5 @@ const DEFAULT_CELL_MENU_CONFIG = ATE_DEFAULT_CELL_MENU_CONFIG;
|
|
|
7125
7203
|
* Generated bundle index. Do not edit.
|
|
7126
7204
|
*/
|
|
7127
7205
|
|
|
7128
|
-
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, AteAngularNodeView, AteColorPickerService, AteDiscoveryCalculator, AteEditorCommandsService, AteI18nService, AteImageCalculator, AteImageService, AteLinkService, AteMarksCalculator, AteNodeViewRenderer, 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, createAngularComponentExtension, createDefaultSlashCommands, filterSlashCommands, registerAngularComponent };
|
|
7206
|
+
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_GLOBAL_CONFIG, ATE_IMAGE_BUBBLE_MENU_KEYS, ATE_INITIAL_EDITOR_STATE, ATE_SLASH_COMMAND_KEYS, ATE_TABLE_BUBBLE_MENU_KEYS, ATE_TOOLBAR_KEYS, AngularTiptapEditorComponent, AteAngularNodeView, AteColorPickerService, AteDiscoveryCalculator, AteEditorCommandsService, AteI18nService, AteImageCalculator, AteImageService, AteLinkService, AteMarksCalculator, AteNodeViewRenderer, 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, createAngularComponentExtension, createDefaultSlashCommands, filterSlashCommands, provideAteEditor, registerAngularComponent };
|
|
7129
7207
|
//# sourceMappingURL=flogeez-angular-tiptap-editor.mjs.map
|