@phuong-tran-redoc/document-engine-angular 0.0.41 → 0.1.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/LICENSE.md +19 -0
- package/README.md +95 -233
- package/THIRD-PARTY-NOTICES.txt +67 -0
- package/fesm2022/phuong-tran-redoc-document-engine-angular.mjs +241 -130
- package/fesm2022/phuong-tran-redoc-document-engine-angular.mjs.map +1 -1
- package/index.d.ts +284 -224
- package/package.json +47 -38
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import * as i1 from '@angular/common';
|
|
2
|
+
import { DOCUMENT, CommonModule } from '@angular/common';
|
|
1
3
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, Input, Directive, Injectable, ApplicationRef, createComponent, HostBinding, InjectionToken, Renderer2, ChangeDetectorRef, forwardRef,
|
|
4
|
+
import { inject, ElementRef, Input, Directive, Injectable, ApplicationRef, createComponent, HostBinding, InjectionToken, Renderer2, ChangeDetectorRef, forwardRef, ChangeDetectionStrategy, Component, ViewEncapsulation, EventEmitter, Output, HostListener, ContentChildren, ViewChild, ViewChildren, NgZone, ViewContainerRef, EnvironmentInjector, NgModule } from '@angular/core';
|
|
3
5
|
import { Extension, Editor } from '@tiptap/core';
|
|
4
6
|
import Blockquote from '@tiptap/extension-blockquote';
|
|
5
7
|
import Bold from '@tiptap/extension-bold';
|
|
@@ -21,10 +23,8 @@ import { TextAlign } from '@tiptap/extension-text-align';
|
|
|
21
23
|
import { TextStyleKit } from '@tiptap/extension-text-style';
|
|
22
24
|
import Underline from '@tiptap/extension-underline';
|
|
23
25
|
import { Dropcursor, Gapcursor, TrailingNode, UndoRedo, CharacterCount, Placeholder } from '@tiptap/extensions';
|
|
24
|
-
import { ResetOnEnter, EditableRegion, RestrictedEditing, CustomOrderedList, StyledTableKit, PageBreak, ResetFormat, Indent, ClearContent, TextCase, NotumHeading, DynamicField, Color, normalizeColor, getActiveMarkRange, getSelectedCells, getCombinedCellAttributeValue, TableDefaultAttributes, getCursorCellInfo, getClosestDomElement } from '@phuong-tran-redoc/document-engine-core';
|
|
26
|
+
import { ResetOnEnter, EditableRegion, RestrictedEditing, CustomOrderedList, StyledTableKit, ImageRef, PageBreak, ResetFormat, Indent, ClearContent, TextCase, NotumHeading, DynamicField, Color, normalizeColor, getActiveMarkRange, getSelectedCells, getCombinedCellAttributeValue, TableDefaultAttributes, getCursorCellInfo, getClosestDomElement } from '@phuong-tran-redoc/document-engine-core';
|
|
25
27
|
import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu';
|
|
26
|
-
import * as i1 from '@angular/common';
|
|
27
|
-
import { DOCUMENT, CommonModule } from '@angular/common';
|
|
28
28
|
import * as i2 from '@angular/forms';
|
|
29
29
|
import { NG_VALUE_ACCESSOR, FormsModule, FormControl, ReactiveFormsModule, FormBuilder, Validators, NonNullableFormBuilder } from '@angular/forms';
|
|
30
30
|
import { FloatingMenuPlugin } from '@tiptap/extension-floating-menu';
|
|
@@ -104,6 +104,7 @@ const DocumentEngineKit = Extension.create({
|
|
|
104
104
|
add(options.superscript, Superscript);
|
|
105
105
|
add(options.textAlign, TextAlign, DEFAULT_TEXT_ALIGN);
|
|
106
106
|
add(options.image, Image);
|
|
107
|
+
add(options.imageRef, ImageRef);
|
|
107
108
|
add(options.placeholder, Placeholder, DEFAULT_PLACEHOLDER);
|
|
108
109
|
add(options.pageBreak, PageBreak);
|
|
109
110
|
add(options.resetFormat, ResetFormat);
|
|
@@ -1033,6 +1034,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
|
|
|
1033
1034
|
type: Input
|
|
1034
1035
|
}] } });
|
|
1035
1036
|
|
|
1037
|
+
/**
|
|
1038
|
+
* Character Count component for document editor footer
|
|
1039
|
+
* Displays character/word count with optional limit and color coding
|
|
1040
|
+
*/
|
|
1041
|
+
class CharacterCountComponent {
|
|
1042
|
+
cdr = inject(ChangeDetectorRef);
|
|
1043
|
+
editor;
|
|
1044
|
+
config;
|
|
1045
|
+
mode = 'characters';
|
|
1046
|
+
count = 0;
|
|
1047
|
+
limit = null;
|
|
1048
|
+
updateCount = () => {
|
|
1049
|
+
if (!this.editor) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
// Get count from editor storage if available
|
|
1053
|
+
const characterCountStorage = this.editor.storage.characterCount;
|
|
1054
|
+
if (characterCountStorage) {
|
|
1055
|
+
if (this.mode === 'characters') {
|
|
1056
|
+
this.count = characterCountStorage.characters?.() || 0;
|
|
1057
|
+
}
|
|
1058
|
+
else {
|
|
1059
|
+
this.count = characterCountStorage.words?.() || 0;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
// Fallback: calculate from text
|
|
1064
|
+
const text = this.editor.getText();
|
|
1065
|
+
if (this.mode === 'characters') {
|
|
1066
|
+
this.count = text.length;
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
this.count = text.trim() ? text.trim().split(/\s+/).length : 0;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
// Get limit from config
|
|
1073
|
+
const characterCountConfig = this.config?.characterCount;
|
|
1074
|
+
if (characterCountConfig && typeof characterCountConfig === 'object') {
|
|
1075
|
+
this.limit = characterCountConfig.limit || null;
|
|
1076
|
+
}
|
|
1077
|
+
else {
|
|
1078
|
+
this.limit = null;
|
|
1079
|
+
}
|
|
1080
|
+
this.cdr.markForCheck();
|
|
1081
|
+
};
|
|
1082
|
+
ngOnInit() {
|
|
1083
|
+
if (!this.editor) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
// Subscribe to update events to keep count in sync
|
|
1087
|
+
this.editor.on('update', this.updateCount);
|
|
1088
|
+
this.editor.on('transaction', this.updateCount);
|
|
1089
|
+
// Initialize count once
|
|
1090
|
+
this.updateCount();
|
|
1091
|
+
}
|
|
1092
|
+
ngOnDestroy() {
|
|
1093
|
+
if (this.editor) {
|
|
1094
|
+
this.editor.off('update', this.updateCount);
|
|
1095
|
+
this.editor.off('transaction', this.updateCount);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
isNearLimit() {
|
|
1099
|
+
if (!this.limit) {
|
|
1100
|
+
return false;
|
|
1101
|
+
}
|
|
1102
|
+
// Consider near limit when >= 90% of limit
|
|
1103
|
+
return this.count >= this.limit * 0.9 && this.count < this.limit;
|
|
1104
|
+
}
|
|
1105
|
+
isOverLimit() {
|
|
1106
|
+
if (!this.limit) {
|
|
1107
|
+
return false;
|
|
1108
|
+
}
|
|
1109
|
+
return this.count > this.limit;
|
|
1110
|
+
}
|
|
1111
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: CharacterCountComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1112
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: CharacterCountComponent, isStandalone: true, selector: "document-engine-character-count", inputs: { editor: "editor", config: "config", mode: "mode" }, ngImport: i0, template: "<div class=\"document-engine-character-count\">\n <span\n class=\"document-engine-character-count__text\"\n [class.document-engine-character-count__text--muted]=\"!isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--warning]=\"isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--error]=\"isOverLimit()\"\n >\n <ng-container *ngIf=\"mode === 'characters'\">\n <ng-container *ngIf=\"limit; else noLimit\"> {{ count }} / {{ limit }} characters. </ng-container>\n <ng-template #noLimit> {{ count }} {{ count === 1 ? 'character' : 'characters' }}. </ng-template>\n </ng-container>\n <ng-container *ngIf=\"mode === 'words'\"> {{ count }} {{ count === 1 ? 'word' : 'words' }}. </ng-container>\n </span>\n</div>\n", styles: [".document-engine-character-count{display:flex;justify-content:flex-end}.document-engine-character-count__text{font-size:.875rem;transition:color .2s ease-in-out}.document-engine-character-count__text--muted{color:var(--muted-foreground, #6b7280)}.document-engine-character-count__text--warning{color:var(--warning, #d97706)}.document-engine-character-count__text--error{color:var(--destructive, #dc2626)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1113
|
+
}
|
|
1114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: CharacterCountComponent, decorators: [{
|
|
1115
|
+
type: Component,
|
|
1116
|
+
args: [{ selector: 'document-engine-character-count', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"document-engine-character-count\">\n <span\n class=\"document-engine-character-count__text\"\n [class.document-engine-character-count__text--muted]=\"!isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--warning]=\"isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--error]=\"isOverLimit()\"\n >\n <ng-container *ngIf=\"mode === 'characters'\">\n <ng-container *ngIf=\"limit; else noLimit\"> {{ count }} / {{ limit }} characters. </ng-container>\n <ng-template #noLimit> {{ count }} {{ count === 1 ? 'character' : 'characters' }}. </ng-template>\n </ng-container>\n <ng-container *ngIf=\"mode === 'words'\"> {{ count }} {{ count === 1 ? 'word' : 'words' }}. </ng-container>\n </span>\n</div>\n", styles: [".document-engine-character-count{display:flex;justify-content:flex-end}.document-engine-character-count__text{font-size:.875rem;transition:color .2s ease-in-out}.document-engine-character-count__text--muted{color:var(--muted-foreground, #6b7280)}.document-engine-character-count__text--warning{color:var(--warning, #d97706)}.document-engine-character-count__text--error{color:var(--destructive, #dc2626)}\n"] }]
|
|
1117
|
+
}], propDecorators: { editor: [{
|
|
1118
|
+
type: Input
|
|
1119
|
+
}], config: [{
|
|
1120
|
+
type: Input
|
|
1121
|
+
}], mode: [{
|
|
1122
|
+
type: Input
|
|
1123
|
+
}] } });
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Footer component for document editor
|
|
1127
|
+
* Container for footer components like character count
|
|
1128
|
+
*/
|
|
1129
|
+
class FooterComponent {
|
|
1130
|
+
editor;
|
|
1131
|
+
config;
|
|
1132
|
+
// @Input() editable = true;
|
|
1133
|
+
hasCharacterCount() {
|
|
1134
|
+
const config = this.config ?? {};
|
|
1135
|
+
return config.characterCount !== false;
|
|
1136
|
+
}
|
|
1137
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: FooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1138
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: FooterComponent, isStandalone: true, selector: "document-engine-footer", inputs: { editor: "editor", config: "config" }, ngImport: i0, template: "<div class=\"document-engine-document-editor__footer\">\n <div class=\"document-engine-document-editor__footer-content\">\n <div class=\"document-engine-document-editor__footer-left\">\n <!-- Additional footer components can be added here -->\n </div>\n\n <div class=\"document-engine-document-editor__footer-right\">\n <document-engine-character-count\n *ngIf=\"hasCharacterCount()\"\n [editor]=\"editor\"\n [config]=\"config\"\n mode=\"characters\"\n ></document-engine-character-count>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CharacterCountComponent, selector: "document-engine-character-count", inputs: ["editor", "config", "mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1139
|
+
}
|
|
1140
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: FooterComponent, decorators: [{
|
|
1141
|
+
type: Component,
|
|
1142
|
+
args: [{ selector: 'document-engine-footer', standalone: true, imports: [CommonModule, CharacterCountComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"document-engine-document-editor__footer\">\n <div class=\"document-engine-document-editor__footer-content\">\n <div class=\"document-engine-document-editor__footer-left\">\n <!-- Additional footer components can be added here -->\n </div>\n\n <div class=\"document-engine-document-editor__footer-right\">\n <document-engine-character-count\n *ngIf=\"hasCharacterCount()\"\n [editor]=\"editor\"\n [config]=\"config\"\n mode=\"characters\"\n ></document-engine-character-count>\n </div>\n </div>\n</div>\n" }]
|
|
1143
|
+
}], propDecorators: { editor: [{
|
|
1144
|
+
type: Input
|
|
1145
|
+
}], config: [{
|
|
1146
|
+
type: Input
|
|
1147
|
+
}] } });
|
|
1148
|
+
|
|
1036
1149
|
const COLORS = Color.fromArray([
|
|
1037
1150
|
{ name: 'Black', value: '#000000', type: 'hex' },
|
|
1038
1151
|
{ name: 'Dim gray', value: '#696969', type: 'hex' },
|
|
@@ -1920,6 +2033,39 @@ const DynamicFieldsBubbleConfig = {
|
|
|
1920
2033
|
],
|
|
1921
2034
|
};
|
|
1922
2035
|
|
|
2036
|
+
/**
|
|
2037
|
+
* Whether a picker result is worth inserting. A `null`/`undefined` result (or one
|
|
2038
|
+
* with neither an `id` nor a `url`) is treated as a cancel — insert nothing.
|
|
2039
|
+
*/
|
|
2040
|
+
function isInsertableResult(result) {
|
|
2041
|
+
return !!result && (!!result.id || !!result.url);
|
|
2042
|
+
}
|
|
2043
|
+
/** Read the consumer's `onPick` media hook off the `image` extension options, if any. */
|
|
2044
|
+
function getImagePickHook(editor) {
|
|
2045
|
+
const ext = editor.extensionManager.extensions.find((e) => e.name === 'image');
|
|
2046
|
+
return ext?.options?.onPick;
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Insert a picked media result: an `image-ref` node when that node is enabled
|
|
2050
|
+
* (preferred — URL-free), otherwise a plain image from the resolved URL. Returns
|
|
2051
|
+
* `true` when something was actually inserted, `false` when the result had
|
|
2052
|
+
* nothing usable (id-only with no `imageRef` node, and no url) — so the caller can
|
|
2053
|
+
* avoid closing the view as if an insert had happened.
|
|
2054
|
+
*/
|
|
2055
|
+
function insertMediaResult(editor, result) {
|
|
2056
|
+
const hasImageRef = editor.extensionManager.extensions.some((e) => e.name === 'imageRef');
|
|
2057
|
+
const chain = editor.chain().focus();
|
|
2058
|
+
if (hasImageRef && result.id) {
|
|
2059
|
+
chain.insertImageRef({ imageId: result.id, caption: result.alt ?? null }).run();
|
|
2060
|
+
return true;
|
|
2061
|
+
}
|
|
2062
|
+
if (result.url) {
|
|
2063
|
+
chain.setImage({ src: result.url, alt: result.alt ?? '' }).run();
|
|
2064
|
+
return true;
|
|
2065
|
+
}
|
|
2066
|
+
return false;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
1923
2069
|
const urlValidator = (control) => {
|
|
1924
2070
|
const value = (control.value ?? '').trim();
|
|
1925
2071
|
if (!value)
|
|
@@ -1968,9 +2114,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
|
|
|
1968
2114
|
}] } });
|
|
1969
2115
|
|
|
1970
2116
|
/**
|
|
1971
|
-
*
|
|
1972
|
-
*
|
|
1973
|
-
*
|
|
2117
|
+
* Image insert view for the bubble menu.
|
|
2118
|
+
*
|
|
2119
|
+
* Two modes:
|
|
2120
|
+
* - When the editor's `image` config supplies an async `onPick` hook, the view
|
|
2121
|
+
* delegates selection to the consumer's media picker and inserts the result
|
|
2122
|
+
* (an `image-ref` node when that node is enabled, else a plain image).
|
|
2123
|
+
* - Otherwise it falls back to the built-in raw-URL input form.
|
|
1974
2124
|
*/
|
|
1975
2125
|
class ImageInsertViewComponent {
|
|
1976
2126
|
fb = inject(FormBuilder);
|
|
@@ -1978,11 +2128,22 @@ class ImageInsertViewComponent {
|
|
|
1978
2128
|
editor;
|
|
1979
2129
|
close;
|
|
1980
2130
|
goBack;
|
|
2131
|
+
/** True while the consumer's `onPick` promise is in flight. */
|
|
2132
|
+
loading = false;
|
|
1981
2133
|
imageForm = this.fb.nonNullable.group({
|
|
1982
2134
|
url: this.fb.control('', [Validators.required, urlValidator]),
|
|
1983
2135
|
alt: this.fb.control(''),
|
|
1984
2136
|
});
|
|
2137
|
+
/** The consumer's media picker, read off the `image` extension options (if any). */
|
|
2138
|
+
get onPick() {
|
|
2139
|
+
return this.editor ? getImagePickHook(this.editor) : undefined;
|
|
2140
|
+
}
|
|
2141
|
+
/** Whether to show the picker mode (vs the raw-URL fallback form). */
|
|
2142
|
+
get hasPicker() {
|
|
2143
|
+
return typeof this.onPick === 'function';
|
|
2144
|
+
}
|
|
1985
2145
|
onActivate() {
|
|
2146
|
+
this.loading = false;
|
|
1986
2147
|
this.imageForm.reset();
|
|
1987
2148
|
this.imageForm.controls.url.markAsUntouched();
|
|
1988
2149
|
this.cdr.markForCheck();
|
|
@@ -1999,6 +2160,30 @@ class ImageInsertViewComponent {
|
|
|
1999
2160
|
this.editor.chain().focus().setImage({ src: url, alt }).run();
|
|
2000
2161
|
this.close?.();
|
|
2001
2162
|
}
|
|
2163
|
+
/** Delegate selection to the consumer's media picker, then insert the result. */
|
|
2164
|
+
async pickImage() {
|
|
2165
|
+
const onPick = this.onPick;
|
|
2166
|
+
if (!onPick || !this.editor || this.loading)
|
|
2167
|
+
return;
|
|
2168
|
+
this.loading = true;
|
|
2169
|
+
this.cdr.markForCheck();
|
|
2170
|
+
try {
|
|
2171
|
+
const result = await onPick();
|
|
2172
|
+
// Reject / resolve-nothing is a deliberate no-op (consumer cancelled). Only
|
|
2173
|
+
// close when something was actually inserted — an id-only result with no
|
|
2174
|
+
// `image-ref` node inserts nothing and must leave the view open.
|
|
2175
|
+
if (this.editor && isInsertableResult(result) && insertMediaResult(this.editor, result)) {
|
|
2176
|
+
this.close?.();
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
catch {
|
|
2180
|
+
// Swallow: a rejected picker (e.g. dialog dismissed) must not crash the editor.
|
|
2181
|
+
}
|
|
2182
|
+
finally {
|
|
2183
|
+
this.loading = false;
|
|
2184
|
+
this.cdr.markForCheck();
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2002
2187
|
cancel() {
|
|
2003
2188
|
this.close?.();
|
|
2004
2189
|
}
|
|
@@ -2008,7 +2193,23 @@ class ImageInsertViewComponent {
|
|
|
2008
2193
|
<!-- Title -->
|
|
2009
2194
|
<div class="image-insert-view__header">Insert Image</div>
|
|
2010
2195
|
|
|
2011
|
-
<!--
|
|
2196
|
+
<!-- Picker mode: delegate selection to the consumer's media library -->
|
|
2197
|
+
<ng-container *ngIf="hasPicker; else urlForm">
|
|
2198
|
+
<div class="image-insert-view__content">
|
|
2199
|
+
<p class="image-insert-view__hint">Choose an image from your media library.</p>
|
|
2200
|
+
</div>
|
|
2201
|
+
<div class="image-insert-view__actions">
|
|
2202
|
+
<button type="button" documentEngineButton variant="ghost" [disabled]="loading" (click)="cancel()">
|
|
2203
|
+
Cancel
|
|
2204
|
+
</button>
|
|
2205
|
+
<button type="button" documentEngineButton variant="default" [disabled]="loading" (click)="pickImage()">
|
|
2206
|
+
{{ loading ? 'Loading…' : 'Choose from library' }}
|
|
2207
|
+
</button>
|
|
2208
|
+
</div>
|
|
2209
|
+
</ng-container>
|
|
2210
|
+
|
|
2211
|
+
<!-- Fallback: built-in raw-URL input form -->
|
|
2212
|
+
<ng-template #urlForm>
|
|
2012
2213
|
<form [formGroup]="imageForm" (ngSubmit)="insertImage()">
|
|
2013
2214
|
<div class="image-insert-view__content">
|
|
2014
2215
|
<!-- Image URL input -->
|
|
@@ -2048,8 +2249,9 @@ class ImageInsertViewComponent {
|
|
|
2048
2249
|
<button type="submit" documentEngineButton variant="default" [disabled]="!canInsert()">Insert Image</button>
|
|
2049
2250
|
</div>
|
|
2050
2251
|
</form>
|
|
2252
|
+
</ng-template>
|
|
2051
2253
|
</div>
|
|
2052
|
-
`, isInline: true, styles: [".image-insert-view{display:flex;flex-direction:column;min-width:320px}.image-insert-view__header{padding:.5rem 1rem;border-bottom:1px solid var(--border);font-weight:500;font-size:.875rem}.image-insert-view__content{display:flex;flex-direction:column;gap:.75rem;padding:1rem .5rem}.image-insert-view__field{display:flex;flex-direction:column;gap:.25rem;width:100%}.image-insert-view__actions{display:flex;gap:.5rem;justify-content:flex-end;padding:.5rem;border-top:1px solid var(--border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: ButtonDirective, selector: "button[documentEngineButton]", inputs: ["variant", "size"] }, { kind: "directive", type: InputDirective, selector: "input[documentEngineInput]", inputs: ["class"] }, { kind: "directive", type: LabelDirective, selector: "label[documentEngineLabel]", inputs: ["class"] }, { kind: "component", type: ErrorMessageComponent, selector: "document-engine-error-message", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2254
|
+
`, isInline: true, styles: [".image-insert-view{display:flex;flex-direction:column;min-width:320px}.image-insert-view__header{padding:.5rem 1rem;border-bottom:1px solid var(--border);font-weight:500;font-size:.875rem}.image-insert-view__content{display:flex;flex-direction:column;gap:.75rem;padding:1rem .5rem}.image-insert-view__hint{margin:0;font-size:.8125rem;color:var(--muted-foreground)}.image-insert-view__field{display:flex;flex-direction:column;gap:.25rem;width:100%}.image-insert-view__actions{display:flex;gap:.5rem;justify-content:flex-end;padding:.5rem;border-top:1px solid var(--border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: ButtonDirective, selector: "button[documentEngineButton]", inputs: ["variant", "size"] }, { kind: "directive", type: InputDirective, selector: "input[documentEngineInput]", inputs: ["class"] }, { kind: "directive", type: LabelDirective, selector: "label[documentEngineLabel]", inputs: ["class"] }, { kind: "component", type: ErrorMessageComponent, selector: "document-engine-error-message", inputs: ["class"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2053
2255
|
}
|
|
2054
2256
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ImageInsertViewComponent, decorators: [{
|
|
2055
2257
|
type: Component,
|
|
@@ -2058,7 +2260,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
|
|
|
2058
2260
|
<!-- Title -->
|
|
2059
2261
|
<div class="image-insert-view__header">Insert Image</div>
|
|
2060
2262
|
|
|
2061
|
-
<!--
|
|
2263
|
+
<!-- Picker mode: delegate selection to the consumer's media library -->
|
|
2264
|
+
<ng-container *ngIf="hasPicker; else urlForm">
|
|
2265
|
+
<div class="image-insert-view__content">
|
|
2266
|
+
<p class="image-insert-view__hint">Choose an image from your media library.</p>
|
|
2267
|
+
</div>
|
|
2268
|
+
<div class="image-insert-view__actions">
|
|
2269
|
+
<button type="button" documentEngineButton variant="ghost" [disabled]="loading" (click)="cancel()">
|
|
2270
|
+
Cancel
|
|
2271
|
+
</button>
|
|
2272
|
+
<button type="button" documentEngineButton variant="default" [disabled]="loading" (click)="pickImage()">
|
|
2273
|
+
{{ loading ? 'Loading…' : 'Choose from library' }}
|
|
2274
|
+
</button>
|
|
2275
|
+
</div>
|
|
2276
|
+
</ng-container>
|
|
2277
|
+
|
|
2278
|
+
<!-- Fallback: built-in raw-URL input form -->
|
|
2279
|
+
<ng-template #urlForm>
|
|
2062
2280
|
<form [formGroup]="imageForm" (ngSubmit)="insertImage()">
|
|
2063
2281
|
<div class="image-insert-view__content">
|
|
2064
2282
|
<!-- Image URL input -->
|
|
@@ -2098,8 +2316,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
|
|
|
2098
2316
|
<button type="submit" documentEngineButton variant="default" [disabled]="!canInsert()">Insert Image</button>
|
|
2099
2317
|
</div>
|
|
2100
2318
|
</form>
|
|
2319
|
+
</ng-template>
|
|
2101
2320
|
</div>
|
|
2102
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".image-insert-view{display:flex;flex-direction:column;min-width:320px}.image-insert-view__header{padding:.5rem 1rem;border-bottom:1px solid var(--border);font-weight:500;font-size:.875rem}.image-insert-view__content{display:flex;flex-direction:column;gap:.75rem;padding:1rem .5rem}.image-insert-view__field{display:flex;flex-direction:column;gap:.25rem;width:100%}.image-insert-view__actions{display:flex;gap:.5rem;justify-content:flex-end;padding:.5rem;border-top:1px solid var(--border)}\n"] }]
|
|
2321
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".image-insert-view{display:flex;flex-direction:column;min-width:320px}.image-insert-view__header{padding:.5rem 1rem;border-bottom:1px solid var(--border);font-weight:500;font-size:.875rem}.image-insert-view__content{display:flex;flex-direction:column;gap:.75rem;padding:1rem .5rem}.image-insert-view__hint{margin:0;font-size:.8125rem;color:var(--muted-foreground)}.image-insert-view__field{display:flex;flex-direction:column;gap:.25rem;width:100%}.image-insert-view__actions{display:flex;gap:.5rem;justify-content:flex-end;padding:.5rem;border-top:1px solid var(--border)}\n"] }]
|
|
2103
2322
|
}] });
|
|
2104
2323
|
|
|
2105
2324
|
const ImageBubbleConfig = {
|
|
@@ -5340,7 +5559,7 @@ class EditorBubbleMenuComponent {
|
|
|
5340
5559
|
// Activate new view
|
|
5341
5560
|
this.activateView(this.currentViewRef);
|
|
5342
5561
|
// Trigger change detection for the child component to render immediately
|
|
5343
|
-
//
|
|
5562
|
+
// (the view is created imperatively, so it is outside Angular's normal CD pass)
|
|
5344
5563
|
this.cdr.markForCheck();
|
|
5345
5564
|
// Mark bubble as visible for transition handling
|
|
5346
5565
|
const bubbleElement = this.bubbleElement?.nativeElement;
|
|
@@ -6099,118 +6318,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
|
|
|
6099
6318
|
args: ['tableCreateBubbleMenu']
|
|
6100
6319
|
}] } });
|
|
6101
6320
|
|
|
6102
|
-
/**
|
|
6103
|
-
* Character Count component for document editor footer
|
|
6104
|
-
* Displays character/word count with optional limit and color coding
|
|
6105
|
-
*/
|
|
6106
|
-
class CharacterCountComponent {
|
|
6107
|
-
cdr = inject(ChangeDetectorRef);
|
|
6108
|
-
editor;
|
|
6109
|
-
config;
|
|
6110
|
-
mode = 'characters';
|
|
6111
|
-
count = 0;
|
|
6112
|
-
limit = null;
|
|
6113
|
-
updateCount = () => {
|
|
6114
|
-
if (!this.editor) {
|
|
6115
|
-
return;
|
|
6116
|
-
}
|
|
6117
|
-
// Get count from editor storage if available
|
|
6118
|
-
const characterCountStorage = this.editor.storage.characterCount;
|
|
6119
|
-
if (characterCountStorage) {
|
|
6120
|
-
if (this.mode === 'characters') {
|
|
6121
|
-
this.count = characterCountStorage.characters?.() || 0;
|
|
6122
|
-
}
|
|
6123
|
-
else {
|
|
6124
|
-
this.count = characterCountStorage.words?.() || 0;
|
|
6125
|
-
}
|
|
6126
|
-
}
|
|
6127
|
-
else {
|
|
6128
|
-
// Fallback: calculate from text
|
|
6129
|
-
const text = this.editor.getText();
|
|
6130
|
-
if (this.mode === 'characters') {
|
|
6131
|
-
this.count = text.length;
|
|
6132
|
-
}
|
|
6133
|
-
else {
|
|
6134
|
-
this.count = text.trim() ? text.trim().split(/\s+/).length : 0;
|
|
6135
|
-
}
|
|
6136
|
-
}
|
|
6137
|
-
// Get limit from config
|
|
6138
|
-
const characterCountConfig = this.config?.characterCount;
|
|
6139
|
-
if (characterCountConfig && typeof characterCountConfig === 'object') {
|
|
6140
|
-
this.limit = characterCountConfig.limit || null;
|
|
6141
|
-
}
|
|
6142
|
-
else {
|
|
6143
|
-
this.limit = null;
|
|
6144
|
-
}
|
|
6145
|
-
this.cdr.markForCheck();
|
|
6146
|
-
};
|
|
6147
|
-
ngOnInit() {
|
|
6148
|
-
if (!this.editor) {
|
|
6149
|
-
return;
|
|
6150
|
-
}
|
|
6151
|
-
// Subscribe to update events to keep count in sync
|
|
6152
|
-
this.editor.on('update', this.updateCount);
|
|
6153
|
-
this.editor.on('transaction', this.updateCount);
|
|
6154
|
-
// Initialize count once
|
|
6155
|
-
this.updateCount();
|
|
6156
|
-
}
|
|
6157
|
-
ngOnDestroy() {
|
|
6158
|
-
if (this.editor) {
|
|
6159
|
-
this.editor.off('update', this.updateCount);
|
|
6160
|
-
this.editor.off('transaction', this.updateCount);
|
|
6161
|
-
}
|
|
6162
|
-
}
|
|
6163
|
-
isNearLimit() {
|
|
6164
|
-
if (!this.limit) {
|
|
6165
|
-
return false;
|
|
6166
|
-
}
|
|
6167
|
-
// Consider near limit when >= 90% of limit
|
|
6168
|
-
return this.count >= this.limit * 0.9 && this.count < this.limit;
|
|
6169
|
-
}
|
|
6170
|
-
isOverLimit() {
|
|
6171
|
-
if (!this.limit) {
|
|
6172
|
-
return false;
|
|
6173
|
-
}
|
|
6174
|
-
return this.count > this.limit;
|
|
6175
|
-
}
|
|
6176
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: CharacterCountComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6177
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: CharacterCountComponent, isStandalone: true, selector: "document-engine-character-count", inputs: { editor: "editor", config: "config", mode: "mode" }, ngImport: i0, template: "<div class=\"document-engine-character-count\">\n <span\n class=\"document-engine-character-count__text\"\n [class.document-engine-character-count__text--muted]=\"!isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--warning]=\"isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--error]=\"isOverLimit()\"\n >\n <ng-container *ngIf=\"mode === 'characters'\">\n <ng-container *ngIf=\"limit; else noLimit\"> {{ count }} / {{ limit }} characters. </ng-container>\n <ng-template #noLimit> {{ count }} {{ count === 1 ? 'character' : 'characters' }}. </ng-template>\n </ng-container>\n <ng-container *ngIf=\"mode === 'words'\"> {{ count }} {{ count === 1 ? 'word' : 'words' }}. </ng-container>\n </span>\n</div>\n", styles: [".document-engine-character-count{display:flex;justify-content:flex-end}.document-engine-character-count__text{font-size:.875rem;transition:color .2s ease-in-out}.document-engine-character-count__text--muted{color:var(--muted-foreground, #6b7280)}.document-engine-character-count__text--warning{color:var(--warning, #d97706)}.document-engine-character-count__text--error{color:var(--destructive, #dc2626)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6178
|
-
}
|
|
6179
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: CharacterCountComponent, decorators: [{
|
|
6180
|
-
type: Component,
|
|
6181
|
-
args: [{ selector: 'document-engine-character-count', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"document-engine-character-count\">\n <span\n class=\"document-engine-character-count__text\"\n [class.document-engine-character-count__text--muted]=\"!isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--warning]=\"isNearLimit() && !isOverLimit()\"\n [class.document-engine-character-count__text--error]=\"isOverLimit()\"\n >\n <ng-container *ngIf=\"mode === 'characters'\">\n <ng-container *ngIf=\"limit; else noLimit\"> {{ count }} / {{ limit }} characters. </ng-container>\n <ng-template #noLimit> {{ count }} {{ count === 1 ? 'character' : 'characters' }}. </ng-template>\n </ng-container>\n <ng-container *ngIf=\"mode === 'words'\"> {{ count }} {{ count === 1 ? 'word' : 'words' }}. </ng-container>\n </span>\n</div>\n", styles: [".document-engine-character-count{display:flex;justify-content:flex-end}.document-engine-character-count__text{font-size:.875rem;transition:color .2s ease-in-out}.document-engine-character-count__text--muted{color:var(--muted-foreground, #6b7280)}.document-engine-character-count__text--warning{color:var(--warning, #d97706)}.document-engine-character-count__text--error{color:var(--destructive, #dc2626)}\n"] }]
|
|
6182
|
-
}], propDecorators: { editor: [{
|
|
6183
|
-
type: Input
|
|
6184
|
-
}], config: [{
|
|
6185
|
-
type: Input
|
|
6186
|
-
}], mode: [{
|
|
6187
|
-
type: Input
|
|
6188
|
-
}] } });
|
|
6189
|
-
|
|
6190
|
-
/**
|
|
6191
|
-
* Footer component for document editor
|
|
6192
|
-
* Container for footer components like character count
|
|
6193
|
-
*/
|
|
6194
|
-
class FooterComponent {
|
|
6195
|
-
editor;
|
|
6196
|
-
config;
|
|
6197
|
-
// @Input() editable = true;
|
|
6198
|
-
hasCharacterCount() {
|
|
6199
|
-
const config = this.config ?? {};
|
|
6200
|
-
return config.characterCount !== false;
|
|
6201
|
-
}
|
|
6202
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: FooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6203
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: FooterComponent, isStandalone: true, selector: "document-engine-footer", inputs: { editor: "editor", config: "config" }, ngImport: i0, template: "<div class=\"document-engine-document-editor__footer\">\n <div class=\"document-engine-document-editor__footer-content\">\n <div class=\"document-engine-document-editor__footer-left\">\n <!-- Additional footer components can be added here -->\n </div>\n\n <div class=\"document-engine-document-editor__footer-right\">\n <document-engine-character-count\n *ngIf=\"hasCharacterCount()\"\n [editor]=\"editor\"\n [config]=\"config\"\n mode=\"characters\"\n ></document-engine-character-count>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CharacterCountComponent, selector: "document-engine-character-count", inputs: ["editor", "config", "mode"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6204
|
-
}
|
|
6205
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: FooterComponent, decorators: [{
|
|
6206
|
-
type: Component,
|
|
6207
|
-
args: [{ selector: 'document-engine-footer', standalone: true, imports: [CommonModule, CharacterCountComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"document-engine-document-editor__footer\">\n <div class=\"document-engine-document-editor__footer-content\">\n <div class=\"document-engine-document-editor__footer-left\">\n <!-- Additional footer components can be added here -->\n </div>\n\n <div class=\"document-engine-document-editor__footer-right\">\n <document-engine-character-count\n *ngIf=\"hasCharacterCount()\"\n [editor]=\"editor\"\n [config]=\"config\"\n mode=\"characters\"\n ></document-engine-character-count>\n </div>\n </div>\n</div>\n" }]
|
|
6208
|
-
}], propDecorators: { editor: [{
|
|
6209
|
-
type: Input
|
|
6210
|
-
}], config: [{
|
|
6211
|
-
type: Input
|
|
6212
|
-
}] } });
|
|
6213
|
-
|
|
6214
6321
|
/**
|
|
6215
6322
|
* Document Editor Component
|
|
6216
6323
|
* High-level wrapper that encapsulates TiptapEditor and DocumentEngineKit
|
|
@@ -6308,11 +6415,11 @@ class DocumentEditorComponent {
|
|
|
6308
6415
|
return merged;
|
|
6309
6416
|
}
|
|
6310
6417
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6311
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: DocumentEditorComponent, isStandalone:
|
|
6418
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: DocumentEditorComponent, isStandalone: true, selector: "document-engine-editor", inputs: { config: "config" }, outputs: { editorReady: "editorReady" }, host: { classAttribute: "no-twp" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"document-engine-document-editor\">\n <document-engine-toolbar\n *ngIf=\"mergedConfig.showToolbar\"\n [editor]=\"editor\"\n [capabilities]=\"capabilities\"\n [config]=\"mergedConfig\"\n ></document-engine-toolbar>\n\n <div class=\"document-engine-document-editor__content\">\n <ng-content></ng-content>\n </div>\n\n <document-engine-footer\n *ngIf=\"editor && mergedConfig.showFooter\"\n [editor]=\"editor\"\n [config]=\"mergedConfig\"\n ></document-engine-footer>\n</div>\n", styles: [":is() *,:is() *:before,:is() *:after{box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ToolbarComponent, selector: "document-engine-toolbar", inputs: ["editor", "capabilities", "config"], outputs: ["action"] }, { kind: "component", type: FooterComponent, selector: "document-engine-footer", inputs: ["editor", "config"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6312
6419
|
}
|
|
6313
6420
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorComponent, decorators: [{
|
|
6314
6421
|
type: Component,
|
|
6315
|
-
args: [{ selector: 'document-engine-editor',
|
|
6422
|
+
args: [{ selector: 'document-engine-editor', imports: [CommonModule, ToolbarComponent, FooterComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
6316
6423
|
class: 'no-twp',
|
|
6317
6424
|
}, template: "<div class=\"document-engine-document-editor\">\n <document-engine-toolbar\n *ngIf=\"mergedConfig.showToolbar\"\n [editor]=\"editor\"\n [capabilities]=\"capabilities\"\n [config]=\"mergedConfig\"\n ></document-engine-toolbar>\n\n <div class=\"document-engine-document-editor__content\">\n <ng-content></ng-content>\n </div>\n\n <document-engine-footer\n *ngIf=\"editor && mergedConfig.showFooter\"\n [editor]=\"editor\"\n [config]=\"mergedConfig\"\n ></document-engine-footer>\n</div>\n", styles: [":is() *,:is() *:before,:is() *:after{box-sizing:border-box}\n"] }]
|
|
6318
6425
|
}], propDecorators: { config: [{
|
|
@@ -6321,16 +6428,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
|
|
|
6321
6428
|
type: Output
|
|
6322
6429
|
}] } });
|
|
6323
6430
|
|
|
6431
|
+
/**
|
|
6432
|
+
* Back-compat shim for NgModule-based consumers. `DocumentEditorComponent` is now
|
|
6433
|
+
* standalone (and `@defer`-friendly); standalone consumers should import it (and
|
|
6434
|
+
* `TiptapEditorDirective`) directly instead of this module.
|
|
6435
|
+
*/
|
|
6324
6436
|
class DocumentEditorModule {
|
|
6325
6437
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
6326
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorModule,
|
|
6327
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorModule, imports: [
|
|
6438
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorModule, imports: [DocumentEditorComponent, TiptapEditorDirective], exports: [DocumentEditorComponent, TiptapEditorDirective] });
|
|
6439
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorModule, imports: [DocumentEditorComponent] });
|
|
6328
6440
|
}
|
|
6329
6441
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: DocumentEditorModule, decorators: [{
|
|
6330
6442
|
type: NgModule,
|
|
6331
6443
|
args: [{
|
|
6332
|
-
|
|
6333
|
-
imports: [CommonModule, ToolbarComponent, FooterComponent, TiptapEditorDirective],
|
|
6444
|
+
imports: [DocumentEditorComponent, TiptapEditorDirective],
|
|
6334
6445
|
exports: [DocumentEditorComponent, TiptapEditorDirective],
|
|
6335
6446
|
}]
|
|
6336
6447
|
}] });
|