@malva-ui/editor 0.1.13 → 0.1.14

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.
Files changed (134) hide show
  1. package/README.md +5 -5
  2. package/fesm2022/malva-ui-editor-ai.mjs +17 -0
  3. package/fesm2022/malva-ui-editor-ai.mjs.map +1 -0
  4. package/fesm2022/malva-ui-editor.mjs +10227 -0
  5. package/fesm2022/malva-ui-editor.mjs.map +1 -0
  6. package/package.json +35 -26
  7. package/types/malva-ui-editor-ai.d.ts +1 -0
  8. package/types/malva-ui-editor.d.ts +2995 -0
  9. package/ai/index.d.ts +0 -12
  10. package/ai/malva-ui-editor-ai.d.ts +0 -5
  11. package/esm2022/ai/index.js +0 -12
  12. package/esm2022/ai/index.js.map +0 -1
  13. package/esm2022/ai/malva-ui-editor-ai.js +0 -5
  14. package/esm2022/ai/malva-ui-editor-ai.js.map +0 -1
  15. package/esm2022/index.js +0 -37
  16. package/esm2022/index.js.map +0 -1
  17. package/esm2022/lib/ai/editor-ai-actions.js +0 -69
  18. package/esm2022/lib/ai/editor-ai-actions.js.map +0 -1
  19. package/esm2022/lib/ai/editor-ai-context.js +0 -612
  20. package/esm2022/lib/ai/editor-ai-context.js.map +0 -1
  21. package/esm2022/lib/ai/editor-ai-menu.js +0 -288
  22. package/esm2022/lib/ai/editor-ai-menu.js.map +0 -1
  23. package/esm2022/lib/ai/editor-ai-review-bar.js +0 -223
  24. package/esm2022/lib/ai/editor-ai-review-bar.js.map +0 -1
  25. package/esm2022/lib/ai/editor-ai-stream.js +0 -677
  26. package/esm2022/lib/ai/editor-ai-stream.js.map +0 -1
  27. package/esm2022/lib/ai/editor-ai-suggestions.js +0 -751
  28. package/esm2022/lib/ai/editor-ai-suggestions.js.map +0 -1
  29. package/esm2022/lib/ai/editor-ai.tokens.js +0 -10
  30. package/esm2022/lib/ai/editor-ai.tokens.js.map +0 -1
  31. package/esm2022/lib/ai/editor-ai.types.js +0 -1
  32. package/esm2022/lib/ai/editor-ai.types.js.map +0 -1
  33. package/esm2022/lib/editor/editor.js +0 -985
  34. package/esm2022/lib/editor/editor.js.map +0 -1
  35. package/esm2022/lib/editor-extension-preflight.js +0 -83
  36. package/esm2022/lib/editor-extension-preflight.js.map +0 -1
  37. package/esm2022/lib/editor-serialization.js +0 -152
  38. package/esm2022/lib/editor-serialization.js.map +0 -1
  39. package/esm2022/lib/editor-toolbar-context.js +0 -259
  40. package/esm2022/lib/editor-toolbar-context.js.map +0 -1
  41. package/esm2022/lib/editor.tokens.js +0 -10
  42. package/esm2022/lib/editor.tokens.js.map +0 -1
  43. package/esm2022/lib/editor.types.js +0 -48
  44. package/esm2022/lib/editor.types.js.map +0 -1
  45. package/esm2022/lib/extensions/editor-block-handle.js +0 -760
  46. package/esm2022/lib/extensions/editor-block-handle.js.map +0 -1
  47. package/esm2022/lib/extensions/editor-extensions.js +0 -321
  48. package/esm2022/lib/extensions/editor-extensions.js.map +0 -1
  49. package/esm2022/lib/extensions/editor-markdown-compatibility.js +0 -162
  50. package/esm2022/lib/extensions/editor-markdown-compatibility.js.map +0 -1
  51. package/esm2022/lib/extensions/editor-upload-placeholder.js +0 -156
  52. package/esm2022/lib/extensions/editor-upload-placeholder.js.map +0 -1
  53. package/esm2022/lib/status/editor-status.js +0 -64
  54. package/esm2022/lib/status/editor-status.js.map +0 -1
  55. package/esm2022/lib/toolbar/editor-alignment.js +0 -203
  56. package/esm2022/lib/toolbar/editor-alignment.js.map +0 -1
  57. package/esm2022/lib/toolbar/editor-block-insert.js +0 -101
  58. package/esm2022/lib/toolbar/editor-block-insert.js.map +0 -1
  59. package/esm2022/lib/toolbar/editor-color-control.js +0 -71
  60. package/esm2022/lib/toolbar/editor-color-control.js.map +0 -1
  61. package/esm2022/lib/toolbar/editor-command-button.js +0 -115
  62. package/esm2022/lib/toolbar/editor-command-button.js.map +0 -1
  63. package/esm2022/lib/toolbar/editor-heading.js +0 -266
  64. package/esm2022/lib/toolbar/editor-heading.js.map +0 -1
  65. package/esm2022/lib/toolbar/editor-highlight.js +0 -84
  66. package/esm2022/lib/toolbar/editor-highlight.js.map +0 -1
  67. package/esm2022/lib/toolbar/editor-image-upload-dialog.js +0 -289
  68. package/esm2022/lib/toolbar/editor-image-upload-dialog.js.map +0 -1
  69. package/esm2022/lib/toolbar/editor-image-upload.js +0 -315
  70. package/esm2022/lib/toolbar/editor-image-upload.js.map +0 -1
  71. package/esm2022/lib/toolbar/editor-inline-marks.js +0 -124
  72. package/esm2022/lib/toolbar/editor-inline-marks.js.map +0 -1
  73. package/esm2022/lib/toolbar/editor-link.js +0 -265
  74. package/esm2022/lib/toolbar/editor-link.js.map +0 -1
  75. package/esm2022/lib/toolbar/editor-list.js +0 -249
  76. package/esm2022/lib/toolbar/editor-list.js.map +0 -1
  77. package/esm2022/lib/toolbar/editor-table.js +0 -292
  78. package/esm2022/lib/toolbar/editor-table.js.map +0 -1
  79. package/esm2022/lib/toolbar/editor-text-color.js +0 -82
  80. package/esm2022/lib/toolbar/editor-text-color.js.map +0 -1
  81. package/esm2022/lib/toolbar/editor-toolbar-widget.js +0 -41
  82. package/esm2022/lib/toolbar/editor-toolbar-widget.js.map +0 -1
  83. package/esm2022/lib/toolbar/editor-toolbar.defs.js +0 -60
  84. package/esm2022/lib/toolbar/editor-toolbar.defs.js.map +0 -1
  85. package/esm2022/lib/toolbar/editor-toolbar.js +0 -826
  86. package/esm2022/lib/toolbar/editor-toolbar.js.map +0 -1
  87. package/esm2022/lib/toolbar/editor-undo-redo.js +0 -72
  88. package/esm2022/lib/toolbar/editor-undo-redo.js.map +0 -1
  89. package/esm2022/lib/toolbar/editor-zoom.js +0 -330
  90. package/esm2022/lib/toolbar/editor-zoom.js.map +0 -1
  91. package/esm2022/lib/upload/editor-image-upload-coordinator.js +0 -480
  92. package/esm2022/lib/upload/editor-image-upload-coordinator.js.map +0 -1
  93. package/esm2022/malva-ui-editor.js +0 -5
  94. package/esm2022/malva-ui-editor.js.map +0 -1
  95. package/index.d.ts +0 -35
  96. package/lib/ai/editor-ai-actions.d.ts +0 -27
  97. package/lib/ai/editor-ai-context.d.ts +0 -307
  98. package/lib/ai/editor-ai-menu.d.ts +0 -142
  99. package/lib/ai/editor-ai-review-bar.d.ts +0 -116
  100. package/lib/ai/editor-ai-stream.d.ts +0 -207
  101. package/lib/ai/editor-ai-suggestions.d.ts +0 -219
  102. package/lib/ai/editor-ai.tokens.d.ts +0 -10
  103. package/lib/ai/editor-ai.types.d.ts +0 -176
  104. package/lib/editor/editor.d.ts +0 -243
  105. package/lib/editor-extension-preflight.d.ts +0 -23
  106. package/lib/editor-serialization.d.ts +0 -74
  107. package/lib/editor-toolbar-context.d.ts +0 -116
  108. package/lib/editor.tokens.d.ts +0 -6
  109. package/lib/editor.types.d.ts +0 -194
  110. package/lib/extensions/editor-block-handle.d.ts +0 -59
  111. package/lib/extensions/editor-extensions.d.ts +0 -165
  112. package/lib/extensions/editor-markdown-compatibility.d.ts +0 -11
  113. package/lib/extensions/editor-upload-placeholder.d.ts +0 -75
  114. package/lib/status/editor-status.d.ts +0 -24
  115. package/lib/toolbar/editor-alignment.d.ts +0 -61
  116. package/lib/toolbar/editor-block-insert.d.ts +0 -26
  117. package/lib/toolbar/editor-color-control.d.ts +0 -32
  118. package/lib/toolbar/editor-command-button.d.ts +0 -29
  119. package/lib/toolbar/editor-heading.d.ts +0 -68
  120. package/lib/toolbar/editor-highlight.d.ts +0 -21
  121. package/lib/toolbar/editor-image-upload-dialog.d.ts +0 -96
  122. package/lib/toolbar/editor-image-upload.d.ts +0 -71
  123. package/lib/toolbar/editor-inline-marks.d.ts +0 -30
  124. package/lib/toolbar/editor-link.d.ts +0 -78
  125. package/lib/toolbar/editor-list.d.ts +0 -67
  126. package/lib/toolbar/editor-table.d.ts +0 -133
  127. package/lib/toolbar/editor-text-color.d.ts +0 -21
  128. package/lib/toolbar/editor-toolbar-widget.d.ts +0 -19
  129. package/lib/toolbar/editor-toolbar.d.ts +0 -157
  130. package/lib/toolbar/editor-toolbar.defs.d.ts +0 -35
  131. package/lib/toolbar/editor-undo-redo.d.ts +0 -26
  132. package/lib/toolbar/editor-zoom.d.ts +0 -108
  133. package/lib/upload/editor-image-upload-coordinator.d.ts +0 -55
  134. package/malva-ui-editor.d.ts +0 -5
@@ -1,985 +0,0 @@
1
- import { LiveAnnouncer } from '@angular/cdk/a11y';
2
- import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
3
- import { ChangeDetectionStrategy, Component, computed, contentChildren, DestroyRef, ElementRef, effect, forwardRef, inject, Injector, input, model, output, PLATFORM_ID, signal, viewChild, ViewEncapsulation, } from '@angular/core';
4
- import { Editor } from '@tiptap/core';
5
- import { MlvFade, MlvSpacer } from '@malva-ui/cdk/utils';
6
- import { MlvFormControlWrapper, MlvFormControlWrapperControl, MlvHint, MlvLabel, MlvMessage, MlvSignalFormControlBase, MLV_FORM_CONTROL, } from '@malva-ui/core/form-utils';
7
- import { MlvToolbar } from '@malva-ui/core/toolbar';
8
- import { MlvDivider } from '@malva-ui/core/divider';
9
- import { MLV_EDITOR_I18N } from '@malva-ui/i18n';
10
- import { MLV_EDITOR_OVERLAY_REGISTRY, MLV_EDITOR_TOOLBAR_CONTEXT, MLV_EDITOR_TOOLBAR_ROVING, MLV_EDITOR_TOOLBAR_REVISION, MLV_EDITOR_UPLOAD_ABORT_REGISTRY, MlvEditorOverlayRegistry, MlvEditorToolbarRevision, MlvEditorToolbarRovingRegistry, MlvEditorUploadAbortRegistry, } from '../editor-toolbar-context';
11
- import { MLV_EDITOR_DEFAULT_IMAGE_UPLOAD_OPTIONS, MLV_EDITOR_IMAGE_UPLOADER, } from '../editor.tokens';
12
- import { MLV_EDITOR_AI_CONTEXT, MLV_EDITOR_AI_INPUT_PROVIDER, MlvEditorAiContext, } from '../ai/editor-ai-context';
13
- import { editorValuesAreEquivalent, normalizeEditorValue, parseEditorJsonDocument, serializeEditorValue, } from '../editor-serialization';
14
- import { preflightMlvEditorExtensions } from '../editor-extension-preflight';
15
- import { mlvEditorDefaultExtensions } from '../extensions/editor-extensions';
16
- import { createMlvEditorImageUploadCoordinator, MLV_EDITOR_IMAGE_UPLOAD_COORDINATOR, } from '../upload/editor-image-upload-coordinator';
17
- import { MlvEditorAlignment } from '../toolbar/editor-alignment';
18
- import { MlvEditorBlockInsert } from '../toolbar/editor-block-insert';
19
- import { MlvEditorHeading } from '../toolbar/editor-heading';
20
- import { MlvEditorHighlight } from '../toolbar/editor-highlight';
21
- import { MlvEditorInlineMarks } from '../toolbar/editor-inline-marks';
22
- import { MlvEditorList } from '../toolbar/editor-list';
23
- import { MlvEditorLink } from '../toolbar/editor-link';
24
- import { MlvEditorImageUpload, MlvEditorImageUploadStatus, } from '../toolbar/editor-image-upload';
25
- import { MlvEditorTable } from '../toolbar/editor-table';
26
- import { MlvEditorToolbarDef, MlvEditorToolbarEndDef, MlvEditorToolbarStartDef, } from '../toolbar/editor-toolbar.defs';
27
- import { MlvEditorToolbarOverflow, MlvEditorToolbarRoot, } from '../toolbar/editor-toolbar';
28
- import { MlvEditorUndoRedo } from '../toolbar/editor-undo-redo';
29
- import { MlvEditorZoom } from '../toolbar/editor-zoom';
30
- import { MlvEditorTextColor } from '../toolbar/editor-text-color';
31
- import { MlvEditorStatus } from '../status/editor-status';
32
- import * as i0 from "@angular/core";
33
- /**
34
- * Browser-only Tiptap form control with nullable HTML, Markdown, or JSON
35
- * values.
36
- *
37
- * The component is a pure Angular `FormValueControl`; it deliberately does
38
- * not implement a `ControlValueAccessor` or provide `NG_VALUE_ACCESSOR`.
39
- */
40
- export class MlvEditor extends MlvSignalFormControlBase {
41
- /** @private Tiptap instance owned exclusively by this component. */
42
- _editor = signal(null, /* @ts-ignore */
43
- ...(ngDevMode ? [{ debugName: "_editor" }] : /* istanbul ignore next */ []));
44
- /** Nullable editor model used by direct, reactive, template, and signal forms. */
45
- value = model(null, /* @ts-ignore */
46
- ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
47
- /** Serialization format for the visual editor. */
48
- format = input('html', /* @ts-ignore */
49
- ...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
50
- /** Width of the centred content column; a gutter is reserved at every value. */
51
- contentWidth = input('default', /* @ts-ignore */
52
- ...(ngDevMode ? [{ debugName: "contentWidth" }] : /* istanbul ignore next */ []));
53
- /** Complete Tiptap extension replacement; omit it for Malva's fresh preset. */
54
- extensions = input(undefined, /* @ts-ignore */
55
- ...(ngDevMode ? [{ debugName: "extensions" }] : /* istanbul ignore next */ []));
56
- /** Placeholder displayed by the default extension preset. */
57
- placeholder = input('Write something…', /* @ts-ignore */
58
- ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
59
- /** Maximum character count for Malva's default extension preset. */
60
- characterLimit = input(null, /* @ts-ignore */
61
- ...(ngDevMode ? [{ debugName: "characterLimit" }] : /* istanbul ignore next */ []));
62
- /** IDREF(s) naming the editable content region. */
63
- ariaLabelledBy = input(undefined, /* @ts-ignore */
64
- ...(ngDevMode ? [{ debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ []));
65
- /** IDREF(s) describing the editable content region. */
66
- ariaDescribedBy = input(undefined, /* @ts-ignore */
67
- ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : /* istanbul ignore next */ []));
68
- /** Per-editor image upload adapter, taking precedence over an injected adapter. */
69
- imageUploader = input(undefined, /* @ts-ignore */
70
- ...(ngDevMode ? [{ debugName: "imageUploader" }] : /* istanbul ignore next */ []));
71
- /** Image upload restrictions used by the later upload controls. */
72
- imageUploadOptions = input(MLV_EDITOR_DEFAULT_IMAGE_UPLOAD_OPTIONS, /* @ts-ignore */
73
- ...(ngDevMode ? [{ debugName: "imageUploadOptions" }] : /* istanbul ignore next */ []));
74
- /**
75
- * Per-editor AI transport, taking precedence over an injected
76
- * `MLV_EDITOR_AI_PROVIDER`. Without either, AI UI modules hide and AI
77
- * commands report a recoverable `configuration` error.
78
- */
79
- aiProvider = input(undefined, /* @ts-ignore */
80
- ...(ngDevMode ? [{ debugName: "aiProvider" }] : /* istanbul ignore next */ []));
81
- /** Read-only signal exposing the one Tiptap editor instance after browser mount. */
82
- editor = this._editor.asReadonly();
83
- /** Exact editor-owned image upload capability forwarded to public toolbars. */
84
- get imageUpload() {
85
- return this._injector.get(MLV_EDITOR_IMAGE_UPLOAD_COORDINATOR);
86
- }
87
- /** View-only zoom percentage shared with the nearest toolbar. */
88
- zoom = signal(100, /* @ts-ignore */
89
- ...(ngDevMode ? [{ debugName: "zoom" }] : /* istanbul ignore next */ []));
90
- /** Whether the mounted editor currently accepts document mutations. */
91
- editable = computed(() => this._editor() !== null && !this.computedDisabled() && !this.readonly(), /* @ts-ignore */
92
- ...(ngDevMode ? [{ debugName: "editable" }] : /* istanbul ignore next */ []));
93
- /** Emits after the browser-only Tiptap editor has been created. */
94
- editorReady = output();
95
- /** Emits when focus enters the editable Tiptap content. */
96
- // The public API deliberately mirrors the documented editor focus event.
97
- // eslint-disable-next-line @angular-eslint/no-output-native
98
- focus = output();
99
- /** Emits when focus leaves the editor composite. */
100
- // The public API deliberately mirrors the documented editor blur event.
101
- // eslint-disable-next-line @angular-eslint/no-output-native
102
- blur = output();
103
- /** Emits Tiptap selection updates. */
104
- selectionChange = output();
105
- /** Emits every Tiptap transaction. */
106
- transaction = output();
107
- /** Emits recoverable construction, parsing, and serialization errors. */
108
- editorError = output();
109
- /** Emits after an image upload succeeds. */
110
- imageUploadSuccess = output();
111
- /** Emits after an image upload fails. */
112
- imageUploadFailure = output();
113
- /** Emits after an image upload is cancelled. */
114
- imageUploadCancelled = output();
115
- /** Whether the nullable model contains meaningful serialized content. */
116
- hasValue = computed(() => this.value() !== null, /* @ts-ignore */
117
- ...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
118
- /** @private Browser-only mount element for Tiptap's ProseMirror DOM. */
119
- _content = viewChild.required('content', /* @ts-ignore */
120
- ...(ngDevMode ? [{ debugName: "_content" }] : /* istanbul ignore next */ []));
121
- /**
122
- * @private Zoom-transformed layer the floating block handle is mounted into.
123
- *
124
- * Deliberately optional rather than `viewChild.required`: the block-handle
125
- * `mount` capability is typed `() => HTMLElement | null`, and the extension
126
- * may call it from a ProseMirror plugin view during a user interaction. A
127
- * required query throws `NG0951` while unresolved, which would surface as an
128
- * uncaught error rather than the absent mount the contract already allows.
129
- */
130
- _view = viewChild('view', /* @ts-ignore */
131
- ...(ngDevMode ? [{ debugName: "_view" }] : /* istanbul ignore next */ []));
132
- /** @protected Complete projected toolbar replacement, if the consumer provides one. */
133
- _toolbarDefs = contentChildren(MlvEditorToolbarDef, /* @ts-ignore */
134
- ...(ngDevMode ? [{ debugName: "_toolbarDefs" }] : /* istanbul ignore next */ []));
135
- /** @protected Projected controls displayed before the built-in toolbar groups. */
136
- _toolbarStartDefs = contentChildren(MlvEditorToolbarStartDef, /* @ts-ignore */
137
- ...(ngDevMode ? [{ debugName: "_toolbarStartDefs" }] : /* istanbul ignore next */ []));
138
- /** @protected Projected controls displayed after the built-in toolbar groups. */
139
- _toolbarEndDefs = contentChildren(MlvEditorToolbarEndDef, /* @ts-ignore */
140
- ...(ngDevMode ? [{ debugName: "_toolbarEndDefs" }] : /* istanbul ignore next */ []));
141
- /** @protected Whether a consumer declared a complete toolbar replacement. */
142
- _hasToolbarDef = computed(() => this._toolbarDefs().length > 0, /* @ts-ignore */
143
- ...(ngDevMode ? [{ debugName: "_hasToolbarDef" }] : /* istanbul ignore next */ []));
144
- /** @protected Context supplied as the implicit value of projected toolbar templates. */
145
- _toolbarContext = this;
146
- /** @private Platform marker used to keep all editor construction out of SSR. */
147
- _isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
148
- /** @private Teardown registration for the browser editor instance. */
149
- _destroyRef = inject(DestroyRef);
150
- /** @private Registry for overlay roots logically owned by this composite control. */
151
- _overlayRegistry = inject(MlvEditorOverlayRegistry);
152
- /** @private Injector used after construction to resolve the editor coordinator safely. */
153
- _injector = inject(Injector);
154
- /** @private Invalidates built-in command state after Tiptap state changes. */
155
- _toolbarRevision = inject(MlvEditorToolbarRevision);
156
- /** @private Registry of in-flight upload abort callbacks. */
157
- _uploadAbortRegistry = inject(MlvEditorUploadAbortRegistry);
158
- /** @private Physical host used to determine the composite focus boundary. */
159
- _host = inject(ElementRef);
160
- /** @private Optional translated accessible defaults. */
161
- _i18n = inject(MLV_EDITOR_I18N, { optional: true });
162
- /** @private Announces block moves politely; the editor content itself is not a live region. */
163
- _liveAnnouncer = inject(LiveAnnouncer);
164
- /** @private Last external value applied to Tiptap without an update event. */
165
- _lastAppliedValue;
166
- /** @private Last value emitted from a user transaction or format conversion. */
167
- _lastEmittedValue;
168
- /** @private Active serialization mode for the current editor document. */
169
- _activeFormat;
170
- /** @private Guards against duplicate Tiptap teardown. */
171
- _destroyed = false;
172
- /** @private Suppresses document-transaction serialization while applying an external value. */
173
- _applyingExternalValue = false;
174
- /** @private Tracks the disabled edge so overlays/uploads close once per transition. */
175
- _wasDisabled = false;
176
- /** @private Tracks the readonly edge so uploads stop before they can mutate content. */
177
- _wasReadonly = false;
178
- /** @private Text selection retained while ProseMirror is made non-editable. */
179
- _disabledSelection;
180
- /** @private Stored marks retained with a collapsed selection while disabled. */
181
- _disabledStoredMarks;
182
- /** @private Avoids duplicate queued focus-leave checks. */
183
- _blurCheckQueued = false;
184
- /** @private The last boundary event, retained until the microtask resolves focus ownership. */
185
- _pendingBlurEvent;
186
- /** @private Stable capture listener for focus entering the physical host. */
187
- _onHostFocusIn = (event) => this._handleCompositeFocusIn(event);
188
- /** @private Stable capture listener for focus leaving the physical host. */
189
- _onHostFocusOut = (event) => this._handleCompositeFocusOut(event);
190
- /** @private Stable capture listener that blocks disabled projected controls. */
191
- _onDisabledPointerOrClick = (event) => this._blockDisabledInteraction(event);
192
- /** @private Stable capture listener that blocks disabled keyboard activation. */
193
- _onDisabledKeydown = (event) => {
194
- if (event.key !== 'Enter' &&
195
- event.key !== ' ' &&
196
- event.key !== 'Spacebar') {
197
- return;
198
- }
199
- this._blockDisabledInteraction(event);
200
- };
201
- /** @protected Fallback-accessible name when no visible label is supplied. */
202
- _resolvedAriaLabel = computed(() => this.ariaLabel() ?? this._i18n?.().editorLabel ?? 'Rich text editor', /* @ts-ignore */
203
- ...(ngDevMode ? [{ debugName: "_resolvedAriaLabel" }] : /* istanbul ignore next */ []));
204
- /** @protected Descriptions supplied explicitly or by the inherited validation message. */
205
- _resolvedAriaDescribedBy = computed(() => this.ariaDescribedBy() ??
206
- (this.message() ? `${this.id()}-message` : undefined), /* @ts-ignore */
207
- ...(ngDevMode ? [{ debugName: "_resolvedAriaDescribedBy" }] : /* istanbul ignore next */ []));
208
- /** @protected ID used to connect a visible inherited label to ProseMirror. */
209
- _labelId = computed(() => `${this.id()}-label`, /* @ts-ignore */
210
- ...(ngDevMode ? [{ debugName: "_labelId" }] : /* istanbul ignore next */ []));
211
- /** @protected Accessible label for the projected toolbar region. */
212
- _toolbarAriaLabel = computed(() => this._i18n?.().toolbarLabel ?? 'Editor toolbar', /* @ts-ignore */
213
- ...(ngDevMode ? [{ debugName: "_toolbarAriaLabel" }] : /* istanbul ignore next */ []));
214
- constructor() {
215
- super();
216
- effect(() => {
217
- const editor = this._editor();
218
- const disabled = this.computedDisabled();
219
- const readonly = this.readonly();
220
- const wasDisabled = this._wasDisabled;
221
- if (disabled && !wasDisabled) {
222
- this._disabledSelection = editor
223
- ? { from: editor.state.selection.from, to: editor.state.selection.to }
224
- : undefined;
225
- this._disabledStoredMarks = editor
226
- ? (editor.state.storedMarks ?? editor.state.selection.$from.marks())
227
- : undefined;
228
- this._removeCompositeFocusForDisabledState();
229
- this._overlayRegistry.closeAll();
230
- this._abortInFlightUploads();
231
- }
232
- this._wasDisabled = disabled;
233
- if (readonly && !this._wasReadonly) {
234
- this._abortInFlightUploads();
235
- }
236
- this._wasReadonly = readonly;
237
- if (!editor)
238
- return;
239
- editor.setEditable(!disabled && !readonly);
240
- if (!disabled && wasDisabled && this._disabledSelection) {
241
- editor.commands.setTextSelection(this._disabledSelection);
242
- if (this._disabledStoredMarks) {
243
- editor.view.dispatch(editor.state.tr.setStoredMarks(this._disabledStoredMarks));
244
- }
245
- this._disabledSelection = undefined;
246
- this._disabledStoredMarks = undefined;
247
- }
248
- this._synchronizeContentSurfaceState(editor);
249
- });
250
- effect(() => this._synchronizeEditor());
251
- this._overlayRegistry.setFocusHandlers((event) => this._handleCompositeFocusIn(event), (event) => this._handleCompositeFocusOut(event));
252
- this._destroyRef.onDestroy(() => {
253
- this._destroyed = true;
254
- this._removeCompositeFocusForDisabledState();
255
- this._overlayRegistry.closeAll();
256
- this._abortInFlightUploads();
257
- this._overlayRegistry.destroy();
258
- this._destroyEditor();
259
- });
260
- }
261
- /** Creates the one Tiptap editor after Angular has rendered the mount element. */
262
- ngAfterViewInit() {
263
- if (!this._isBrowser || this._editor() || this._destroyed)
264
- return;
265
- this._bindCompositeFocusEvents();
266
- const initialFormat = this.format();
267
- const initialRawValue = this.value();
268
- const initialValue = normalizeEditorValue(initialRawValue);
269
- if (initialRawValue !== initialValue) {
270
- this._lastEmittedValue = initialValue;
271
- this.value.set(initialValue);
272
- }
273
- try {
274
- // A consumer array remains a literal replacement. Defaults are selected
275
- // once so preflight and Tiptap receive the identical extension objects.
276
- const selectedExtensions = this.extensions() ??
277
- mlvEditorDefaultExtensions({
278
- format: 'markdown',
279
- placeholder: this.placeholder(),
280
- characterLimit: this.characterLimit(),
281
- allowedMimeTypes: ['image/*'],
282
- fileHandlingEnabled: () => {
283
- if (this._destroyed || this.computedDisabled() || this.readonly()) {
284
- return false;
285
- }
286
- return this._injector
287
- .get(MLV_EDITOR_IMAGE_UPLOAD_COORDINATOR)
288
- .available();
289
- },
290
- acceptsMimeType: (mimeType) => this._acceptsImageMimeType(mimeType),
291
- onFiles: ({ files, source, position }) => {
292
- if (this._destroyed || this.computedDisabled() || this.readonly()) {
293
- return;
294
- }
295
- const acceptedImages = files.filter((file) => file.type.startsWith('image/') &&
296
- this._acceptsImageMimeType(file.type));
297
- if (!acceptedImages.length)
298
- return;
299
- this._injector
300
- .get(MLV_EDITOR_IMAGE_UPLOAD_COORDINATOR)
301
- .start(acceptedImages, source, {
302
- ...(position === undefined ? {} : { position }),
303
- });
304
- },
305
- blockHandle: {
306
- mount: () => this._view()?.nativeElement ?? null,
307
- label: () => this._i18n?.().dragBlock ?? 'Drag block',
308
- enabled: () => !this._destroyed && !this.computedDisabled() && !this.readonly(),
309
- announceMove: (move) => this._announceBlockMove(move),
310
- },
311
- });
312
- const preflight = preflightMlvEditorExtensions(selectedExtensions, initialFormat);
313
- if (!preflight.ok) {
314
- this.editorError.emit(preflight.error);
315
- return;
316
- }
317
- const editor = new Editor({
318
- element: this._content().nativeElement,
319
- ...this._emptyDocumentOptions(initialFormat),
320
- // The factory itself deliberately adds Markdown only for `format:
321
- // 'markdown'`. The shell always keeps that capability so an in-place
322
- // switch between any two formats can serialize the existing document
323
- // without constructing a second editor. A supplied array remains
324
- // literal.
325
- extensions: selectedExtensions,
326
- editable: !this.computedDisabled() && !this.readonly(),
327
- enableContentCheck: true,
328
- editorProps: { attributes: this._editorAttributes() },
329
- onTransaction: ({ editor: changedEditor, transaction }) => {
330
- if (this._destroyed)
331
- return;
332
- this.transaction.emit({ editor: changedEditor, transaction });
333
- this._toolbarRevision.revision.update((revision) => revision + 1);
334
- if (transaction.docChanged && !this._applyingExternalValue) {
335
- this._serializeAndWrite(changedEditor, this.format());
336
- }
337
- },
338
- onSelectionUpdate: ({ editor: changedEditor, transaction }) => {
339
- if (this._destroyed)
340
- return;
341
- this.selectionChange.emit({ editor: changedEditor, transaction });
342
- this._toolbarRevision.revision.update((revision) => revision + 1);
343
- },
344
- onContentError: ({ error }) => {
345
- if (this._destroyed)
346
- return;
347
- this.editorError.emit({
348
- code: 'parse',
349
- message: 'Unable to parse the editor value with the configured extensions.',
350
- recoverable: true,
351
- cause: error,
352
- });
353
- },
354
- });
355
- this._activeFormat = initialFormat;
356
- this._lastAppliedValue = null;
357
- this._editor.set(editor);
358
- this._applyInitialValue(editor, initialValue, initialFormat);
359
- // Consumers may immediately issue commands from `editorReady`; emit only
360
- // after the initial model has either been applied or recovered from.
361
- this.editorReady.emit(editor);
362
- }
363
- catch (cause) {
364
- this.editorError.emit({
365
- code: 'configuration',
366
- message: 'Unable to create the editor with the configured extensions.',
367
- recoverable: true,
368
- cause,
369
- });
370
- }
371
- }
372
- /** Clears the document through Tiptap when the shared form wrapper is clearable. */
373
- clearValue() {
374
- if (this.computedDisabled() || this.readonly())
375
- return;
376
- this._editor()?.commands.clearContent();
377
- }
378
- /** @private Formats a completed block move and announces it politely. */
379
- _announceBlockMove(move) {
380
- if (this._destroyed)
381
- return;
382
- const template = this._i18n?.().blockMoved;
383
- const message = template
384
- ? template
385
- .replace('{type}', move.type)
386
- .replace('{position}', String(move.position))
387
- .replace('{total}', String(move.total))
388
- : `Moved ${move.type} to position ${move.position} of ${move.total}`;
389
- this._liveAnnouncer.announce(message, 'polite');
390
- }
391
- /** @private Whether a browser MIME type matches the current coordinator options. */
392
- _acceptsImageMimeType(mimeType) {
393
- const normalizedMimeType = mimeType.trim().toLowerCase();
394
- if (!normalizedMimeType.startsWith('image/'))
395
- return false;
396
- return this.imageUploadOptions().accept.some((pattern) => {
397
- const normalizedPattern = pattern.trim().toLowerCase();
398
- if (normalizedPattern === '*/*')
399
- return true;
400
- if (normalizedPattern.endsWith('/*')) {
401
- return normalizedMimeType.startsWith(normalizedPattern.slice(0, -1));
402
- }
403
- return normalizedMimeType === normalizedPattern;
404
- });
405
- }
406
- /** Runs a Tiptap mutation command when the editor is available and editable. */
407
- run(command) {
408
- if (this.computedDisabled() || this.readonly())
409
- return false;
410
- const editor = this._editor();
411
- if (!editor)
412
- return false;
413
- try {
414
- return command(editor) === true;
415
- }
416
- catch {
417
- return false;
418
- }
419
- }
420
- /** Checks a Tiptap command when the editor is available and editable. */
421
- can(command) {
422
- if (this.computedDisabled() || this.readonly())
423
- return false;
424
- const editor = this._editor();
425
- if (!editor)
426
- return false;
427
- try {
428
- return command(editor) === true;
429
- }
430
- catch {
431
- return false;
432
- }
433
- }
434
- /** Safely reads a Tiptap active state without requiring a particular extension. */
435
- isActive(name, attributes) {
436
- this._toolbarRevision.revision();
437
- const editor = this._editor();
438
- if (!editor)
439
- return false;
440
- try {
441
- return editor.isActive(name, attributes);
442
- }
443
- catch {
444
- return false;
445
- }
446
- }
447
- /** Reports a typed recoverable error through the owning editor output. */
448
- reportError(error) {
449
- this.editorError.emit(error);
450
- }
451
- /** @private Applies the current inputs to the already-created editor instance. */
452
- _synchronizeEditor() {
453
- const editor = this._editor();
454
- if (!editor)
455
- return;
456
- const requestedFormat = this.format();
457
- editor.setOptions({
458
- editorProps: { attributes: this._editorAttributes() },
459
- });
460
- this._synchronizeContentSurfaceState(editor);
461
- const rawIncoming = this.value();
462
- const incoming = normalizeEditorValue(rawIncoming);
463
- // Tracked values were produced under the currently active format, so the
464
- // comparison runs in that format rather than the requested one. JSON is
465
- // compared structurally there; a host value that only reorders keys or
466
- // reflows whitespace describes the mounted document and is not an
467
- // external change.
468
- const trackedFormat = this._activeFormat ?? requestedFormat;
469
- const hasExternalValue = !editorValuesAreEquivalent(incoming, this._lastAppliedValue, trackedFormat) &&
470
- !editorValuesAreEquivalent(incoming, this._lastEmittedValue, trackedFormat);
471
- if (this._activeFormat !== requestedFormat) {
472
- if (hasExternalValue) {
473
- if (requestedFormat === 'markdown' && !this._supportsMarkdown(editor)) {
474
- this._emitUnsupportedMarkdownError('configuration');
475
- return;
476
- }
477
- this._activeFormat = requestedFormat;
478
- this._applyExternalValue(editor, incoming, requestedFormat);
479
- return;
480
- }
481
- if (this._activeFormat !== undefined) {
482
- if (!this._supportsMarkdown(editor) && requestedFormat === 'markdown') {
483
- this._emitUnsupportedMarkdownError('configuration');
484
- return;
485
- }
486
- if (!this._serializeAndWrite(editor, requestedFormat))
487
- return;
488
- }
489
- this._activeFormat = requestedFormat;
490
- }
491
- if (rawIncoming !== incoming) {
492
- this._lastEmittedValue = incoming;
493
- this.value.set(incoming);
494
- }
495
- if (!hasExternalValue) {
496
- this._lastAppliedValue = incoming;
497
- return;
498
- }
499
- this._applyExternalValue(editor, incoming, requestedFormat);
500
- }
501
- /** @private Applies an external value without reflecting it back through `onUpdate`. */
502
- _applyExternalValue(editor, value, format) {
503
- const prepared = value === null ? null : this._prepareContent(editor, value, format);
504
- if (prepared !== null && !prepared.ok) {
505
- this._recoverFromInvalidValue(prepared.cause);
506
- return;
507
- }
508
- try {
509
- this._applyingExternalValue = true;
510
- // External applications must stay invisible to user undo history:
511
- // Tiptap's setContent/clearContent never set `addToHistory`, so a bare
512
- // command would land the initial or programmatic document as an undoable
513
- // step whose undo empties the editor. The chain shares one transaction,
514
- // so the meta covers the whole application.
515
- if (prepared === null) {
516
- editor.chain().setMeta('addToHistory', false).clearContent(false).run();
517
- }
518
- else {
519
- editor
520
- .chain()
521
- .setMeta('addToHistory', false)
522
- .setContent(prepared.content, prepared.options)
523
- .run();
524
- }
525
- this._lastAppliedValue = value;
526
- this._lastEmittedValue = undefined;
527
- }
528
- catch (cause) {
529
- this._recoverFromInvalidValue(cause);
530
- }
531
- finally {
532
- this._applyingExternalValue = false;
533
- }
534
- }
535
- /**
536
- * @private Converts one nonempty external value into Tiptap content and
537
- * options.
538
- *
539
- * The branch is exhaustive over every format rather than special-casing one:
540
- * HTML is parsed from its own markup, Markdown declares its content type so
541
- * the Markdown manager parses it, and JSON is handed over as an
542
- * already-parsed document node because Tiptap reads any string argument as
543
- * HTML. A rejected JSON value carries its cause instead of a document.
544
- */
545
- _prepareContent(editor, value, format) {
546
- switch (format) {
547
- case 'html':
548
- return {
549
- ok: true,
550
- content: value,
551
- options: { emitUpdate: false, errorOnInvalidContent: true },
552
- };
553
- case 'markdown':
554
- return {
555
- ok: true,
556
- content: value,
557
- options: {
558
- emitUpdate: false,
559
- errorOnInvalidContent: true,
560
- contentType: 'markdown',
561
- },
562
- };
563
- case 'json': {
564
- const parsed = parseEditorJsonDocument(value, editor.schema.topNodeType.name);
565
- return parsed.ok
566
- ? {
567
- ok: true,
568
- content: parsed.document,
569
- options: { emitUpdate: false, errorOnInvalidContent: true },
570
- }
571
- : { ok: false, cause: parsed.cause };
572
- }
573
- }
574
- }
575
- /**
576
- * @private Construction options mounting an empty document for one format.
577
- *
578
- * Tiptap is always constructed against an empty document so every real
579
- * value travels the same strict parsing path. Markdown still declares its
580
- * content type here because the Markdown manager validates that declaration
581
- * against the supplied content before the first document is published. HTML
582
- * needs no declaration, and JSON never reaches Tiptap as a string at all.
583
- */
584
- _emptyDocumentOptions(format) {
585
- switch (format) {
586
- case 'html':
587
- return { content: '' };
588
- case 'markdown':
589
- return { content: '', contentType: 'markdown' };
590
- case 'json':
591
- return { content: '' };
592
- }
593
- }
594
- /** @private Restores the last valid value and reports a recoverable parse failure. */
595
- _recoverFromInvalidValue(cause) {
596
- const lastValidValue = this._lastAppliedValue ?? null;
597
- this._lastEmittedValue = lastValidValue;
598
- if (this.value() !== lastValidValue) {
599
- this.value.set(lastValidValue);
600
- }
601
- this.editorError.emit({
602
- code: 'parse',
603
- message: 'Unable to parse the editor value with the configured extensions.',
604
- recoverable: true,
605
- cause,
606
- });
607
- }
608
- /**
609
- * @private Serializes an editor transaction and writes only valid distinct
610
- * values.
611
- *
612
- * The distinctness check runs in the serialized format, so a JSON document
613
- * that differs from the model only by key order or whitespace is not
614
- * re-emitted. An emission therefore follows only a real user transaction or
615
- * an explicit format conversion.
616
- */
617
- _serializeAndWrite(editor, format) {
618
- const result = serializeEditorValue(editor, format);
619
- if (!result.ok) {
620
- this.editorError.emit(result.error);
621
- return false;
622
- }
623
- this._lastAppliedValue = result.value;
624
- this._lastEmittedValue = result.value;
625
- if (!editorValuesAreEquivalent(this.value(), result.value, format)) {
626
- this.value.set(result.value);
627
- }
628
- return true;
629
- }
630
- /**
631
- * @private Applies the initial model through the same strict parsing path as
632
- * later updates.
633
- *
634
- * Only Markdown has a capability requirement; HTML and JSON mount against
635
- * any valid extension set.
636
- */
637
- _applyInitialValue(editor, value, format) {
638
- switch (format) {
639
- case 'markdown':
640
- if (!this._supportsMarkdown(editor)) {
641
- this._emitUnsupportedMarkdownError('configuration');
642
- this._lastAppliedValue = null;
643
- this._lastEmittedValue = null;
644
- if (this.value() !== null)
645
- this.value.set(null);
646
- return;
647
- }
648
- break;
649
- case 'html':
650
- case 'json':
651
- break;
652
- }
653
- this._applyExternalValue(editor, value, format);
654
- }
655
- /** @private Whether the runtime editor exposes Tiptap Markdown serialization. */
656
- _supportsMarkdown(editor) {
657
- return typeof editor.getMarkdown === 'function';
658
- }
659
- /** @private Emits the stable unsupported-Markdown error without throwing through Angular. */
660
- _emitUnsupportedMarkdownError(code) {
661
- this.editorError.emit({
662
- code,
663
- message: 'Markdown requires the configured extensions to include Tiptap Markdown.',
664
- recoverable: true,
665
- });
666
- }
667
- /** @private Builds the exact accessible attributes assigned to Tiptap's contenteditable root. */
668
- _editorAttributes() {
669
- const attributes = {
670
- id: this.id(),
671
- role: 'textbox',
672
- 'aria-multiline': 'true',
673
- };
674
- const labelledBy = this.ariaLabelledBy();
675
- if (labelledBy) {
676
- attributes['aria-labelledby'] = labelledBy;
677
- }
678
- else if (this.ariaLabel()) {
679
- attributes['aria-label'] = this._resolvedAriaLabel();
680
- }
681
- else if (this.label()) {
682
- attributes['aria-labelledby'] = this._labelId();
683
- }
684
- else {
685
- attributes['aria-label'] = this._resolvedAriaLabel();
686
- }
687
- const describedBy = this._resolvedAriaDescribedBy();
688
- if (describedBy) {
689
- attributes['aria-describedby'] = describedBy;
690
- }
691
- if (this.resolvedState() === 'error') {
692
- attributes['aria-invalid'] = 'true';
693
- }
694
- if (this.computedDisabled()) {
695
- attributes['aria-disabled'] = 'true';
696
- attributes['tabindex'] = '-1';
697
- }
698
- else {
699
- attributes['tabindex'] = '0';
700
- }
701
- if (this.readonly()) {
702
- attributes['aria-readonly'] = 'true';
703
- }
704
- return attributes;
705
- }
706
- /** @internal Capture handler for focus entering the host or an owned overlay root. */
707
- _handleCompositeFocusIn(event) {
708
- if (this._destroyed || this.computedDisabled() || this.focused())
709
- return;
710
- const editor = this._editor();
711
- if (!editor)
712
- return;
713
- this.setFocused(true);
714
- this.focus.emit({ editor, event });
715
- }
716
- /** @internal Capture handler for focus leaving the host or an owned overlay root. */
717
- _handleCompositeFocusOut(event) {
718
- if (this._destroyed || !this.focused())
719
- return;
720
- this._pendingBlurEvent = event;
721
- if (this._blurCheckQueued)
722
- return;
723
- this._blurCheckQueued = true;
724
- queueMicrotask(() => {
725
- this._blurCheckQueued = false;
726
- const pendingEvent = this._pendingBlurEvent;
727
- this._pendingBlurEvent = undefined;
728
- if (!pendingEvent ||
729
- this._destroyed ||
730
- this._isFocusInsideComposite(pendingEvent.relatedTarget)) {
731
- return;
732
- }
733
- const editor = this._editor();
734
- if (!editor)
735
- return;
736
- this.setFocused(false);
737
- this._markTouched();
738
- this.blur.emit({ editor, event: pendingEvent });
739
- });
740
- }
741
- /** @private Whether the browser's current focus remains in the host or an owned overlay. */
742
- _isFocusInsideComposite(relatedTarget) {
743
- if (typeof Node !== 'undefined' && relatedTarget instanceof Node) {
744
- return this._isOwnedFocusNode(relatedTarget);
745
- }
746
- if (typeof document === 'undefined')
747
- return false;
748
- return this._isOwnedFocusNode(document.activeElement);
749
- }
750
- /** @private Whether a node belongs to the physical shell or an owned overlay. */
751
- _isOwnedFocusNode(node) {
752
- return (node !== null &&
753
- (this._host.nativeElement.contains(node) ||
754
- this._overlayRegistry.contains(node)));
755
- }
756
- /** @private Installs native capture listeners because overlay focus is outside Angular's view tree. */
757
- _bindCompositeFocusEvents() {
758
- const host = this._host.nativeElement;
759
- host.addEventListener('focusin', this._onHostFocusIn, true);
760
- host.addEventListener('focusout', this._onHostFocusOut, true);
761
- host.addEventListener('pointerdown', this._onDisabledPointerOrClick, true);
762
- host.addEventListener('click', this._onDisabledPointerOrClick, true);
763
- host.addEventListener('keydown', this._onDisabledKeydown, true);
764
- this._destroyRef.onDestroy(() => {
765
- host.removeEventListener('focusin', this._onHostFocusIn, true);
766
- host.removeEventListener('focusout', this._onHostFocusOut, true);
767
- host.removeEventListener('pointerdown', this._onDisabledPointerOrClick, true);
768
- host.removeEventListener('click', this._onDisabledPointerOrClick, true);
769
- host.removeEventListener('keydown', this._onDisabledKeydown, true);
770
- });
771
- }
772
- /** @private Stops all pointer/click/activation-key command surfaces while disabled. */
773
- _blockDisabledInteraction(event) {
774
- if (!this.computedDisabled())
775
- return;
776
- event.preventDefault();
777
- event.stopImmediatePropagation();
778
- }
779
- /** @private Removes browser focus when the composite becomes disabled without marking it touched. */
780
- _removeCompositeFocusForDisabledState() {
781
- if (typeof document === 'undefined' || typeof HTMLElement === 'undefined') {
782
- return;
783
- }
784
- const activeElement = document.activeElement;
785
- if (!(activeElement instanceof HTMLElement) ||
786
- !this._isOwnedFocusNode(activeElement)) {
787
- return;
788
- }
789
- this.setFocused(false);
790
- activeElement.blur();
791
- }
792
- /** @private Keeps the real ProseMirror root in sync with dynamic ARIA/tabindex state. */
793
- _synchronizeContentSurfaceState(editor) {
794
- const element = editor.view.dom;
795
- const attributes = this._editorAttributes();
796
- const managedAttributes = [
797
- 'aria-disabled',
798
- 'aria-readonly',
799
- 'tabindex',
800
- 'aria-invalid',
801
- ];
802
- for (const name of managedAttributes) {
803
- const value = attributes[name];
804
- if (value === undefined) {
805
- element.removeAttribute(name);
806
- }
807
- else {
808
- element.setAttribute(name, value);
809
- }
810
- }
811
- }
812
- /** @private Aborts registered upload work while preserving the document/editor instance. */
813
- _abortInFlightUploads() {
814
- this._uploadAbortRegistry.abortAll();
815
- }
816
- /** @private Destroys the owned Tiptap editor exactly once. */
817
- _destroyEditor() {
818
- const editor = this._editor();
819
- if (!editor)
820
- return;
821
- this._editor.set(null);
822
- editor?.destroy();
823
- }
824
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
825
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MlvEditor, isStandalone: true, selector: "mlv-editor", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, contentWidth: { classPropertyName: "contentWidth", publicName: "contentWidth", isSignal: true, isRequired: false, transformFunction: null }, extensions: { classPropertyName: "extensions", publicName: "extensions", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, characterLimit: { classPropertyName: "characterLimit", publicName: "characterLimit", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, imageUploader: { classPropertyName: "imageUploader", publicName: "imageUploader", isSignal: true, isRequired: false, transformFunction: null }, imageUploadOptions: { classPropertyName: "imageUploadOptions", publicName: "imageUploadOptions", isSignal: true, isRequired: false, transformFunction: null }, aiProvider: { classPropertyName: "aiProvider", publicName: "aiProvider", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", editorReady: "editorReady", focus: "focus", blur: "blur", selectionChange: "selectionChange", transaction: "transaction", editorError: "editorError", imageUploadSuccess: "imageUploadSuccess", imageUploadFailure: "imageUploadFailure", imageUploadCancelled: "imageUploadCancelled" }, host: { properties: { "class": "\"mlv-editor--content-width-\" + contentWidth()", "class.mlv-editor--disabled": "computedDisabled()", "class.mlv-editor--readonly": "readonly()", "class.mlv-editor--focused": "focused()", "attr.aria-disabled": "computedDisabled() || null", "attr.inert": "computedDisabled() ? \"\" : null", "style.--mlv-editor-zoom": "zoom() / 100" }, classAttribute: "mlv-editor" }, providers: [
826
- MlvEditorOverlayRegistry,
827
- MlvEditorToolbarRevision,
828
- MlvEditorToolbarRovingRegistry,
829
- MlvEditorUploadAbortRegistry,
830
- {
831
- provide: MLV_FORM_CONTROL,
832
- useExisting: forwardRef(() => MlvEditor),
833
- },
834
- {
835
- provide: MLV_EDITOR_TOOLBAR_CONTEXT,
836
- useExisting: forwardRef(() => MlvEditor),
837
- },
838
- {
839
- provide: MLV_EDITOR_TOOLBAR_REVISION,
840
- useFactory: (state) => state.revision,
841
- deps: [MlvEditorToolbarRevision],
842
- },
843
- {
844
- provide: MLV_EDITOR_TOOLBAR_ROVING,
845
- useExisting: MlvEditorToolbarRovingRegistry,
846
- },
847
- {
848
- provide: MLV_EDITOR_OVERLAY_REGISTRY,
849
- useExisting: MlvEditorOverlayRegistry,
850
- },
851
- {
852
- provide: MLV_EDITOR_UPLOAD_ABORT_REGISTRY,
853
- useExisting: MlvEditorUploadAbortRegistry,
854
- },
855
- MlvEditorAiContext,
856
- {
857
- provide: MLV_EDITOR_AI_CONTEXT,
858
- useExisting: MlvEditorAiContext,
859
- },
860
- {
861
- provide: MLV_EDITOR_AI_INPUT_PROVIDER,
862
- useFactory: () => {
863
- const owner = inject(forwardRef(() => MlvEditor));
864
- return owner.aiProvider;
865
- },
866
- },
867
- {
868
- provide: MLV_EDITOR_IMAGE_UPLOAD_COORDINATOR,
869
- useFactory: () => {
870
- const owner = inject(forwardRef(() => MlvEditor));
871
- return createMlvEditorImageUploadCoordinator({
872
- editor: owner.editor,
873
- imageUploader: owner.imageUploader,
874
- imageUploadOptions: owner.imageUploadOptions,
875
- disabled: () => owner.computedDisabled(),
876
- readonly: () => owner.readonly(),
877
- emitSuccess: (event) => owner.imageUploadSuccess.emit(event),
878
- emitFailure: (event) => owner.imageUploadFailure.emit(event),
879
- emitCancelled: (event) => owner.imageUploadCancelled.emit(event),
880
- emitError: (error) => owner.editorError.emit(error),
881
- }, inject(MLV_EDITOR_IMAGE_UPLOADER, { optional: true }) ?? undefined, inject(MLV_EDITOR_UPLOAD_ABORT_REGISTRY));
882
- },
883
- },
884
- ], queries: [{ propertyName: "_toolbarDefs", predicate: MlvEditorToolbarDef, isSignal: true }, { propertyName: "_toolbarStartDefs", predicate: MlvEditorToolbarStartDef, isSignal: true }, { propertyName: "_toolbarEndDefs", predicate: MlvEditorToolbarEndDef, isSignal: true }], viewQueries: [{ propertyName: "_content", first: true, predicate: ["content"], descendants: true, isSignal: true }, { propertyName: "_view", first: true, predicate: ["view"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<mlv-form-control-wrapper (clear)=\"clearValue()\">\n @if (label() || hint()) {\n <mlv-label [for]=\"id()\" [id]=\"_labelId()\">\n {{ label() }} @if (hint()) {\n <mlv-hint>{{ hint() }}</mlv-hint>\n }\n </mlv-label>\n }\n\n <ng-template mlvFormControlWrapperControl>\n <div class=\"mlv-editor__surface\">\n <div\n mlvEditorToolbarRoot\n #toolbarRoot=\"mlvEditorToolbarRoot\"\n class=\"mlv-editor__toolbar\"\n [ariaLabel]=\"_toolbarAriaLabel()\"\n [disabled]=\"computedDisabled()\"\n >\n @if (_hasToolbarDef()) {\n <ng-content select=\"[mlvEditorToolbar]\" />\n @for (definition of _toolbarDefs(); track definition) { @if\n (definition.templateRef; as toolbarTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"toolbarTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n } } } @else {\n <ng-content select=\"[mlvEditorToolbarStart]\" />\n @for (definition of _toolbarStartDefs(); track definition) { @if\n (definition.templateRef; as startTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"startTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n } }\n <div mlvFade class=\"mlv-editor__toolbar-scroll\">\n <mlv-toolbar>\n <mlv-editor-undo-redo />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n />\n <mlv-editor-zoom />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n />\n <mlv-editor-heading />\n <mlv-editor-list />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-inline-marks [hidden]=\"toolbarRoot.narrow()\" />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-text-color />\n <mlv-editor-highlight />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-alignment [hidden]=\"toolbarRoot.narrow()\" />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-link />\n <mlv-editor-table />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-block-insert [hidden]=\"toolbarRoot.narrow()\" />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-image-upload />\n </mlv-toolbar>\n </div>\n <mlv-editor-toolbar-overflow />\n @for (definition of _toolbarEndDefs(); track definition) { @if\n (definition.templateRef; as endTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"endTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n } }\n <ng-content select=\"[mlvEditorToolbarEnd]\" />\n }\n </div>\n\n <div class=\"mlv-editor__viewport\">\n <div #view class=\"mlv-editor__view\">\n <div #content class=\"mlv-editor__content\"></div>\n </div>\n </div>\n <mlv-editor-image-upload-status />\n </div>\n </ng-template>\n\n @if (message()) {\n <mlv-message [state]=\"resolvedState()\" [id]=\"id() + '-message'\">\n {{ message() }}\n </mlv-message>\n }\n</mlv-form-control-wrapper>\n\n<div\n class=\"mlv-editor__status\"\n [attr.aria-disabled]=\"computedDisabled() || null\"\n>\n <ng-content select=\"[mlvEditorStatus]\" />\n <mlv-spacer />\n <mlv-editor-status [characterLimit]=\"characterLimit()\" />\n</div>\n", styles: [".mlv-editor{--mlv-editor-gutter: var(--mlv-spacing-6);--mlv-editor-measure: 45rem;--mlv-editor-drop-gap: 1.5rem;box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor *{box-sizing:border-box}.mlv-editor{display:block;color:var(--mlv-text-primary)}.mlv-editor .mlv-form-control-wrapper__control-container{height:auto;min-height:var(--form-ctrl-height);padding:0;overflow:hidden;background:var(--mlv-background-base);transition:border-color var(--mlv-duration-fast) var(--mlv-ease-default),box-shadow var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor .mlv-form-control-wrapper__control-row{align-items:stretch}.mlv-form-control-wrapper--state-error .mlv-editor__surface{box-shadow:inset 0 0 0 var(--mlv-stroke-width) var(--mlv-border-error)}.mlv-editor__surface{display:flex;flex:1 1 auto;flex-direction:column;min-width:0;width:100%;background:var(--mlv-elevation-bg-3)}.mlv-editor__toolbar{display:flex;flex-wrap:nowrap;align-items:center;gap:var(--mlv-spacing-1);min-width:0;padding:var(--mlv-padding-xs);overflow:hidden;border-bottom:var(--mlv-stroke-width) solid var(--mlv-border-normal);background:var(--mlv-elevation-bg-3)}.mlv-editor__toolbar [hidden]{display:none!important}.mlv-editor__toolbar-scroll{flex:1 1 auto;min-width:0}.mlv-editor__toolbar-scroll>.mlv-toolbar{width:max-content;min-width:100%;flex-wrap:nowrap}.mlv-editor .mlv-editor-toolbar__separator{flex:0 0 auto;min-height:var(--mlv-height-s);margin-inline:var(--mlv-spacing-1)}.mlv-editor .mlv-editor-toolbar__overflow,.mlv-editor .mlv-editor-undo-redo,.mlv-editor .mlv-editor-inline-marks,.mlv-editor .mlv-editor-block-insert{display:inline-flex;flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor mlv-editor-zoom,.mlv-editor mlv-editor-heading,.mlv-editor mlv-editor-list,.mlv-editor mlv-editor-text-color,.mlv-editor mlv-editor-highlight,.mlv-editor mlv-editor-alignment,.mlv-editor mlv-editor-link,.mlv-editor mlv-editor-table,.mlv-editor mlv-editor-image-upload{flex:0 0 auto}.mlv-editor__viewport{min-block-size:8rem;overflow:auto;overscroll-behavior:contain}.mlv-editor__view{position:relative;min-inline-size:100%;transform:scale(var(--mlv-editor-zoom, 1));transform-origin:left top;transition:transform var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor__content{min-block-size:8rem;padding-block:var(--mlv-spacing-2);padding-inline:var(--mlv-editor-gutter);border:0;outline:none}.mlv-editor__block-handle{position:absolute;inset-inline-start:max(0rem,(100% - 2 * var(--mlv-editor-gutter) - var(--mlv-editor-measure)) / 2);display:inline-flex;align-items:center;justify-content:center;inline-size:var(--mlv-editor-gutter);block-size:var(--mlv-height-xs);border-radius:var(--mlv-radius-s);color:var(--mlv-text-tertiary);cursor:grab;opacity:0;pointer-events:none;transition:opacity var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor__block-handle svg{inline-size:var(--mlv-spacing-4);block-size:var(--mlv-spacing-4);fill:currentcolor}.mlv-editor__block-handle:hover{background-color:var(--mlv-background-neutral-1-hover);color:var(--mlv-text-secondary)}.mlv-editor__block-handle[data-visible=true]{opacity:1;pointer-events:auto}.mlv-editor__drop-indicator{position:absolute;inset-inline:calc(max(0rem,(100% - 2 * var(--mlv-editor-gutter) - var(--mlv-editor-measure)) / 2) + var(--mlv-editor-gutter));block-size:var(--mlv-stroke-width-medium);border-radius:var(--mlv-radius-full);background-color:var(--mlv-border-focus);opacity:0;pointer-events:none;transform:translateY(calc(var(--mlv-editor-drop-gap) / 2 - var(--mlv-stroke-width-medium) / 2));transition:top var(--mlv-duration-normal) var(--mlv-ease-out),opacity var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor__drop-indicator[data-visible=true]{opacity:1}.mlv-editor .mlv-editor__block--dragging{opacity:var(--mlv-disabled-opacity)}.mlv-editor .ProseMirror--block-dragging>*{transition:transform var(--mlv-duration-normal) var(--mlv-ease-out)}.mlv-editor__status{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--mlv-spacing-2);min-block-size:var(--mlv-spacing-4);margin-block-start:var(--mlv-spacing-1)}.mlv-editor__upload-placeholder{position:relative;display:inline-block;inline-size:var(--mlv-height-l);block-size:var(--mlv-height-l);margin-inline:var(--mlv-spacing-1);border:var(--mlv-stroke-width) dashed var(--mlv-border-focus);border-radius:var(--mlv-radius-m);background:var(--mlv-background-accent-1-pale);vertical-align:middle}.mlv-editor__upload-placeholder:after{position:absolute;inset:var(--mlv-spacing-2);border:var(--mlv-stroke-width-medium) solid var(--mlv-border-normal);border-block-start-color:var(--mlv-border-focus);border-radius:var(--mlv-radius-full);animation:mlv-editor-upload-spin var(--mlv-duration-slower) var(--mlv-ease-linear) infinite;content:\"\"}.mlv-editor__ai-streaming{border-radius:var(--mlv-radius-xs);background-color:var(--mlv-background-accent-1-pale)}.mlv-editor__ai-streaming-chunk{animation:mlv-editor-ai-chunk-in var(--mlv-duration-normal) var(--mlv-ease-out)}.mlv-editor__ai-caret{position:relative;display:inline-block;inline-size:0;block-size:1em;pointer-events:none}.mlv-editor__ai-caret:after{position:absolute;inset-block:0;inset-inline-start:.0625rem;inline-size:.35em;border-radius:var(--mlv-radius-xs);background:linear-gradient(to bottom,var(--mlv-background-accent-1),var(--mlv-background-accent-2));content:\"\";animation:mlv-editor-ai-caret-pulse var(--mlv-duration-sluggish) var(--mlv-ease-in-out) infinite}.mlv-editor__ai-suggestion-insert{border-radius:var(--mlv-radius-xs);background-color:var(--mlv-background-success-pale)}.mlv-editor__ai-suggestion-delete{border-radius:var(--mlv-radius-xs);background-color:var(--mlv-background-danger-1-pale);color:var(--mlv-text-negative);text-decoration-line:line-through}.mlv-editor__ai-suggestion-current{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:.125rem}.mlv-editor--content-width-default{--mlv-editor-measure: 45rem}.mlv-editor--content-width-wide{--mlv-editor-measure: 60rem}.mlv-editor--content-width-full{--mlv-editor-measure: 100%}.mlv-editor--focused .mlv-form-control-wrapper__control-container{border-color:var(--mlv-border-focus);box-shadow:var(--mlv-focus-ring)}.mlv-editor--readonly .ProseMirror{cursor:text}.mlv-editor--readonly .ProseMirror ::selection{background:var(--mlv-background-accent-1-pale)}.mlv-editor--disabled{opacity:var(--mlv-disabled-opacity)}.mlv-editor--disabled .mlv-editor__surface,.mlv-editor--disabled .mlv-editor__status{pointer-events:none}.mlv-editor--disabled .mlv-editor__content,.mlv-editor--disabled .ProseMirror{cursor:default;-webkit-user-select:none;user-select:none}.mlv-editor .ProseMirror{min-block-size:inherit;max-inline-size:var(--mlv-editor-measure);margin-inline:auto;color:var(--mlv-text-primary);font-family:var(--mlv-typography-family-text);font-size:var(--mlv-typography-body-m-size);font-weight:var(--mlv-typography-body-m-weight);line-height:var(--mlv-typography-body-m-line-height);overflow-wrap:anywhere;white-space:pre-wrap}.mlv-editor .ProseMirror:focus-visible{outline:none}.mlv-editor .ProseMirror>*:first-child{margin-block-start:0}.mlv-editor .ProseMirror>*:last-child{margin-block-end:0}.mlv-editor .ProseMirror p{margin-block:0 var(--mlv-spacing-3)}.mlv-editor .ProseMirror h1,.mlv-editor .ProseMirror h2,.mlv-editor .ProseMirror h3,.mlv-editor .ProseMirror h4,.mlv-editor .ProseMirror h5,.mlv-editor .ProseMirror h6{margin-block:var(--mlv-spacing-6) var(--mlv-spacing-3);color:var(--mlv-text-heading);font-family:var(--mlv-typography-family-heading)}.mlv-editor .ProseMirror h1{font-size:var(--mlv-typography-heading-h1-size);font-weight:var(--mlv-typography-heading-h1-weight);line-height:var(--mlv-typography-heading-h1-line-height)}.mlv-editor .ProseMirror h2{font-size:var(--mlv-typography-heading-h2-size);font-weight:var(--mlv-typography-heading-h2-weight);line-height:var(--mlv-typography-heading-h2-line-height)}.mlv-editor .ProseMirror h3{font-size:var(--mlv-typography-heading-h3-size);font-weight:var(--mlv-typography-heading-h3-weight);line-height:var(--mlv-typography-heading-h3-line-height)}.mlv-editor .ProseMirror h4{font-size:var(--mlv-typography-heading-h4-size);font-weight:var(--mlv-typography-heading-h4-weight);line-height:var(--mlv-typography-heading-h4-line-height)}.mlv-editor .ProseMirror h5{font-size:var(--mlv-typography-heading-h5-size);font-weight:var(--mlv-typography-heading-h5-weight);line-height:var(--mlv-typography-heading-h5-line-height)}.mlv-editor .ProseMirror h6{font-size:var(--mlv-typography-heading-h6-size);font-weight:var(--mlv-typography-heading-h6-weight);line-height:var(--mlv-typography-heading-h6-line-height)}.mlv-editor .ProseMirror h1{letter-spacing:var(--mlv-typography-heading-h1-letter-spacing)}.mlv-editor .ProseMirror h2{letter-spacing:var(--mlv-typography-heading-h2-letter-spacing)}.mlv-editor .ProseMirror h3,.mlv-editor .ProseMirror h4,.mlv-editor .ProseMirror h5,.mlv-editor .ProseMirror h6{letter-spacing:var(--mlv-letter-spacing-normal)}.mlv-editor .ProseMirror strong{font-weight:var(--mlv-font-weight-bold)}.mlv-editor .ProseMirror em{font-style:italic}.mlv-editor .ProseMirror s{text-decoration:line-through}.mlv-editor .ProseMirror u{text-underline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror a{color:var(--mlv-text-action);text-decoration:underline;text-underline-offset:var(--mlv-spacing-0-5);transition:color var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor .ProseMirror a:visited{color:var(--mlv-text-action)}.mlv-editor .ProseMirror a:hover{color:var(--mlv-text-action-hover)}.mlv-editor .ProseMirror a:focus-visible{border-radius:var(--mlv-radius-xs);outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror ul,.mlv-editor .ProseMirror ol{padding-inline-start:var(--mlv-spacing-6);margin-block:0 var(--mlv-spacing-3)}.mlv-editor .ProseMirror ul ul,.mlv-editor .ProseMirror ul ol,.mlv-editor .ProseMirror ol ul,.mlv-editor .ProseMirror ol ol{margin-block:var(--mlv-spacing-1) 0}.mlv-editor .ProseMirror ul{list-style:disc}.mlv-editor .ProseMirror ul ul{list-style:circle}.mlv-editor .ProseMirror ol{list-style:decimal}.mlv-editor .ProseMirror li{margin-block:var(--mlv-spacing-1)}.mlv-editor .ProseMirror li>p{margin:0}.mlv-editor .ProseMirror ul[data-type=taskList]{padding:0;list-style:none}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]{display:flex;align-items:flex-start;gap:var(--mlv-spacing-2)}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>label{display:inline-flex;align-items:center;min-block-size:var(--mlv-height-xs);cursor:pointer;-webkit-user-select:none;user-select:none}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>label input{accent-color:var(--mlv-background-accent-1)}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>label input:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>div{flex:1 1 auto;min-width:0}.mlv-editor .ProseMirror blockquote{padding-inline-start:var(--mlv-spacing-4);margin:var(--mlv-spacing-4) 0;border-inline-start:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);color:var(--mlv-text-secondary)}.mlv-editor .ProseMirror code{padding:var(--mlv-spacing-0-5) var(--mlv-spacing-1);border-radius:var(--mlv-radius-s);background:var(--mlv-background-neutral-1);color:var(--mlv-text-primary);font-family:var(--mlv-typography-family-code);font-size:var(--mlv-typography-code-size)}.mlv-editor .ProseMirror pre{padding:var(--mlv-padding-m);margin-block:var(--mlv-spacing-4);overflow:auto;border:var(--mlv-stroke-width) solid var(--mlv-border-normal);border-radius:var(--mlv-radius-m);background:var(--mlv-background-sunken);color:var(--mlv-text-primary);font-family:var(--mlv-typography-family-code);font-size:var(--mlv-typography-code-size);line-height:var(--mlv-typography-body-m-line-height);tab-size:2}.mlv-editor .ProseMirror pre code{padding:0;background:transparent;color:inherit;font-size:inherit}.mlv-editor .ProseMirror hr{height:var(--mlv-stroke-width);margin-block:var(--mlv-spacing-6);border:0;background:var(--mlv-border-normal)}.mlv-editor .ProseMirror img{display:block;max-inline-size:100%;block-size:auto;margin-block:var(--mlv-spacing-4);border-radius:var(--mlv-radius-m)}.mlv-editor .ProseMirror img.ProseMirror-selectednode{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:0}.mlv-editor .ProseMirror .ProseMirror-selectednode,.mlv-editor .ProseMirror [data-resize-state=true]{border-radius:var(--mlv-radius-s);outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-1)}.mlv-editor .ProseMirror [data-resize-container]{margin-block:var(--mlv-spacing-4)}.mlv-editor .ProseMirror [data-resize-container] img{margin-block:0}.mlv-editor .ProseMirror [data-resize-container].ProseMirror-selectednode,.mlv-editor .ProseMirror [data-resize-container][data-resize-state=true]{outline:none}.mlv-editor .ProseMirror [data-resize-container].ProseMirror-selectednode>[data-resize-wrapper],.mlv-editor .ProseMirror [data-resize-container][data-resize-state=true]>[data-resize-wrapper]{border-radius:var(--mlv-radius-m);outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:0}.mlv-editor .ProseMirror [data-resize-handle],.mlv-editor .ProseMirror .resize-handle{inline-size:var(--mlv-spacing-3);block-size:var(--mlv-spacing-3);border:var(--mlv-stroke-width) solid var(--mlv-background-base);border-radius:var(--mlv-radius-full);background:var(--mlv-background-accent-1);box-shadow:var(--mlv-shadow-raised)}.mlv-editor .ProseMirror [data-resize-handle]:focus-visible,.mlv-editor .ProseMirror .resize-handle:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror .is-editor-empty:first-child:before{float:left;height:0;color:var(--mlv-text-placeholder);content:attr(data-placeholder);pointer-events:none}.mlv-editor .tableWrapper{margin-block:var(--mlv-spacing-3);overflow-x:auto}.mlv-editor table{width:100%;border-collapse:collapse;table-layout:fixed}.mlv-editor th,.mlv-editor td{position:relative;min-width:3rem;padding:var(--mlv-spacing-2) var(--mlv-spacing-3);border:var(--mlv-stroke-width) solid var(--mlv-border-normal);vertical-align:top}.mlv-editor th{background:var(--mlv-background-neutral-1);font-weight:var(--mlv-font-weight-semibold)}.mlv-editor .selectedCell:after{position:absolute;inset:0;z-index:1;background:var(--mlv-background-accent-1-pale);content:\"\";opacity:.55;pointer-events:none}.mlv-editor .ProseMirror-focused .selectedCell:after{box-shadow:inset 0 0 0 var(--mlv-stroke-width-medium) var(--mlv-border-focus)}.mlv-editor .column-resize-handle{position:absolute;inset-block:0;inset-inline-end:calc(var(--mlv-stroke-width) * -1);z-index:2;width:calc(var(--mlv-stroke-width) * 2);background:var(--mlv-border-focus);pointer-events:none}.mlv-editor .resize-cursor{cursor:col-resize}@keyframes mlv-editor-upload-spin{to{transform:rotate(1turn)}}@keyframes mlv-editor-ai-chunk-in{0%{opacity:0;filter:blur(.125rem)}to{opacity:1;filter:blur(0)}}@keyframes mlv-editor-ai-caret-pulse{0%,to{opacity:1}50%{opacity:.35}}@media(max-width:40rem){.mlv-editor{--mlv-editor-gutter: var(--mlv-spacing-3)}.mlv-editor__toolbar{flex-wrap:nowrap;overflow-x:auto}.mlv-editor__content{padding-block:var(--mlv-spacing-1-5)}.mlv-editor__status{justify-content:flex-start}.mlv-editor .ProseMirror h1{font-size:var(--mlv-typography-heading-h2-size)}.mlv-editor .ProseMirror h2{font-size:var(--mlv-typography-heading-h3-size)}}@media print{.mlv-editor__toolbar,.mlv-editor__status,.mlv-editor__block-handle,.mlv-editor__drop-indicator,.mlv-editor .mlv-editor-image-upload-status,.mlv-editor__upload-placeholder,.mlv-editor__ai-suggestion-delete,.mlv-editor__ai-caret{display:none}.mlv-editor__ai-suggestion-current{outline:none}.mlv-editor__ai-streaming-chunk{animation:none}.mlv-editor__viewport{overflow:visible}.mlv-editor__view{transform:none}.mlv-editor__content,.mlv-editor .ProseMirror{min-block-size:0;padding:0}.mlv-editor table{break-inside:avoid}}@media(hover:none){.mlv-editor__block-handle{display:none}}@media(prefers-reduced-motion:reduce){.mlv-editor .mlv-form-control-wrapper__control-container,.mlv-editor__view,.mlv-editor__block-handle,.mlv-editor__drop-indicator,.mlv-editor .ProseMirror--block-dragging>*,.mlv-editor .ProseMirror a{transition-duration:var(--mlv-duration-instant)}.mlv-editor__upload-placeholder:after,.mlv-editor__ai-streaming-chunk,.mlv-editor__ai-caret:after{animation:none}}.mlv-editor__drag-ghost{max-block-size:12rem;padding:var(--mlv-spacing-2);overflow:hidden;border-radius:var(--mlv-radius-m);background-color:var(--mlv-background-raised);box-shadow:var(--mlv-shadow-floating);opacity:.9;-webkit-mask-image:linear-gradient(to bottom,black 70%,transparent 100%);mask-image:linear-gradient(to bottom,black 70%,transparent 100%);scale:.85;transform-origin:top left}\n"], dependencies: [{ kind: "component", type: MlvFormControlWrapper, selector: "mlv-form-control-wrapper", outputs: ["clear"] }, { kind: "directive", type: MlvFormControlWrapperControl, selector: "[mlvFormControlWrapperControl]" }, { kind: "component", type: MlvHint, selector: "mlv-hint" }, { kind: "component", type: MlvLabel, selector: "mlv-label", inputs: ["for", "required"] }, { kind: "component", type: MlvMessage, selector: "mlv-message", inputs: ["state"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: MlvFade, selector: "[mlvFade]", inputs: ["mlvFadeHeight", "mlvFadeSize", "mlvFadeOffset", "mlvFade"] }, { kind: "component", type: MlvToolbar, selector: "mlv-toolbar", inputs: ["gap", "equalSize"] }, { kind: "component", type: MlvDivider, selector: "mlv-divider", inputs: ["orientation", "dashed", "muted"] }, { kind: "directive", type: MlvEditorToolbarRoot, selector: "[mlvEditorToolbarRoot]", inputs: ["ariaLabel", "disabled", "orientation", "wrap"], exportAs: ["mlvEditorToolbarRoot"] }, { kind: "component", type: MlvEditorToolbarOverflow, selector: "mlv-editor-toolbar-overflow" }, { kind: "component", type: MlvEditorUndoRedo, selector: "mlv-editor-undo-redo" }, { kind: "component", type: MlvEditorZoom, selector: "mlv-editor-zoom", inputs: ["zoom", "zoomLevels", "min", "max", "fitToContainer"], outputs: ["zoomChange"] }, { kind: "component", type: MlvEditorHeading, selector: "mlv-editor-heading", inputs: ["levels"] }, { kind: "component", type: MlvEditorList, selector: "mlv-editor-list" }, { kind: "component", type: MlvEditorInlineMarks, selector: "mlv-editor-inline-marks" }, { kind: "component", type: MlvEditorTextColor, selector: "mlv-editor-text-color" }, { kind: "component", type: MlvEditorStatus, selector: "mlv-editor-status", inputs: ["characterLimit"] }, { kind: "component", type: MlvEditorHighlight, selector: "mlv-editor-highlight" }, { kind: "component", type: MlvEditorLink, selector: "mlv-editor-link", inputs: ["allowedProtocols"] }, { kind: "component", type: MlvEditorImageUpload, selector: "mlv-editor-image-upload" }, { kind: "component", type: MlvEditorImageUploadStatus, selector: "mlv-editor-image-upload-status" }, { kind: "component", type: MlvEditorTable, selector: "mlv-editor-table" }, { kind: "component", type: MlvEditorAlignment, selector: "mlv-editor-alignment" }, { kind: "component", type: MlvEditorBlockInsert, selector: "mlv-editor-block-insert" }, { kind: "component", type: MlvSpacer, selector: "mlv-spacer" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
885
- }
886
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MlvEditor, decorators: [{
887
- type: Component,
888
- args: [{ selector: 'mlv-editor', imports: [
889
- MlvFormControlWrapper,
890
- MlvFormControlWrapperControl,
891
- MlvHint,
892
- MlvLabel,
893
- MlvMessage,
894
- NgTemplateOutlet,
895
- MlvFade,
896
- MlvToolbar,
897
- MlvDivider,
898
- MlvEditorToolbarRoot,
899
- MlvEditorToolbarOverflow,
900
- MlvEditorUndoRedo,
901
- MlvEditorZoom,
902
- MlvEditorHeading,
903
- MlvEditorList,
904
- MlvEditorInlineMarks,
905
- MlvEditorTextColor,
906
- MlvEditorStatus,
907
- MlvEditorHighlight,
908
- MlvEditorLink,
909
- MlvEditorImageUpload,
910
- MlvEditorImageUploadStatus,
911
- MlvEditorTable,
912
- MlvEditorAlignment,
913
- MlvEditorBlockInsert,
914
- MlvSpacer,
915
- ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
916
- MlvEditorOverlayRegistry,
917
- MlvEditorToolbarRevision,
918
- MlvEditorToolbarRovingRegistry,
919
- MlvEditorUploadAbortRegistry,
920
- {
921
- provide: MLV_FORM_CONTROL,
922
- useExisting: forwardRef(() => MlvEditor),
923
- },
924
- {
925
- provide: MLV_EDITOR_TOOLBAR_CONTEXT,
926
- useExisting: forwardRef(() => MlvEditor),
927
- },
928
- {
929
- provide: MLV_EDITOR_TOOLBAR_REVISION,
930
- useFactory: (state) => state.revision,
931
- deps: [MlvEditorToolbarRevision],
932
- },
933
- {
934
- provide: MLV_EDITOR_TOOLBAR_ROVING,
935
- useExisting: MlvEditorToolbarRovingRegistry,
936
- },
937
- {
938
- provide: MLV_EDITOR_OVERLAY_REGISTRY,
939
- useExisting: MlvEditorOverlayRegistry,
940
- },
941
- {
942
- provide: MLV_EDITOR_UPLOAD_ABORT_REGISTRY,
943
- useExisting: MlvEditorUploadAbortRegistry,
944
- },
945
- MlvEditorAiContext,
946
- {
947
- provide: MLV_EDITOR_AI_CONTEXT,
948
- useExisting: MlvEditorAiContext,
949
- },
950
- {
951
- provide: MLV_EDITOR_AI_INPUT_PROVIDER,
952
- useFactory: () => {
953
- const owner = inject(forwardRef(() => MlvEditor));
954
- return owner.aiProvider;
955
- },
956
- },
957
- {
958
- provide: MLV_EDITOR_IMAGE_UPLOAD_COORDINATOR,
959
- useFactory: () => {
960
- const owner = inject(forwardRef(() => MlvEditor));
961
- return createMlvEditorImageUploadCoordinator({
962
- editor: owner.editor,
963
- imageUploader: owner.imageUploader,
964
- imageUploadOptions: owner.imageUploadOptions,
965
- disabled: () => owner.computedDisabled(),
966
- readonly: () => owner.readonly(),
967
- emitSuccess: (event) => owner.imageUploadSuccess.emit(event),
968
- emitFailure: (event) => owner.imageUploadFailure.emit(event),
969
- emitCancelled: (event) => owner.imageUploadCancelled.emit(event),
970
- emitError: (error) => owner.editorError.emit(error),
971
- }, inject(MLV_EDITOR_IMAGE_UPLOADER, { optional: true }) ?? undefined, inject(MLV_EDITOR_UPLOAD_ABORT_REGISTRY));
972
- },
973
- },
974
- ], host: {
975
- class: 'mlv-editor',
976
- '[class]': '"mlv-editor--content-width-" + contentWidth()',
977
- '[class.mlv-editor--disabled]': 'computedDisabled()',
978
- '[class.mlv-editor--readonly]': 'readonly()',
979
- '[class.mlv-editor--focused]': 'focused()',
980
- '[attr.aria-disabled]': 'computedDisabled() || null',
981
- '[attr.inert]': 'computedDisabled() ? "" : null',
982
- '[style.--mlv-editor-zoom]': 'zoom() / 100',
983
- }, template: "<mlv-form-control-wrapper (clear)=\"clearValue()\">\n @if (label() || hint()) {\n <mlv-label [for]=\"id()\" [id]=\"_labelId()\">\n {{ label() }} @if (hint()) {\n <mlv-hint>{{ hint() }}</mlv-hint>\n }\n </mlv-label>\n }\n\n <ng-template mlvFormControlWrapperControl>\n <div class=\"mlv-editor__surface\">\n <div\n mlvEditorToolbarRoot\n #toolbarRoot=\"mlvEditorToolbarRoot\"\n class=\"mlv-editor__toolbar\"\n [ariaLabel]=\"_toolbarAriaLabel()\"\n [disabled]=\"computedDisabled()\"\n >\n @if (_hasToolbarDef()) {\n <ng-content select=\"[mlvEditorToolbar]\" />\n @for (definition of _toolbarDefs(); track definition) { @if\n (definition.templateRef; as toolbarTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"toolbarTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n } } } @else {\n <ng-content select=\"[mlvEditorToolbarStart]\" />\n @for (definition of _toolbarStartDefs(); track definition) { @if\n (definition.templateRef; as startTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"startTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n } }\n <div mlvFade class=\"mlv-editor__toolbar-scroll\">\n <mlv-toolbar>\n <mlv-editor-undo-redo />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n />\n <mlv-editor-zoom />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n />\n <mlv-editor-heading />\n <mlv-editor-list />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-inline-marks [hidden]=\"toolbarRoot.narrow()\" />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-text-color />\n <mlv-editor-highlight />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-alignment [hidden]=\"toolbarRoot.narrow()\" />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-link />\n <mlv-editor-table />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-block-insert [hidden]=\"toolbarRoot.narrow()\" />\n <mlv-divider\n class=\"mlv-editor-toolbar__separator\"\n orientation=\"vertical\"\n muted\n [hidden]=\"toolbarRoot.narrow()\"\n />\n <mlv-editor-image-upload />\n </mlv-toolbar>\n </div>\n <mlv-editor-toolbar-overflow />\n @for (definition of _toolbarEndDefs(); track definition) { @if\n (definition.templateRef; as endTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"endTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n } }\n <ng-content select=\"[mlvEditorToolbarEnd]\" />\n }\n </div>\n\n <div class=\"mlv-editor__viewport\">\n <div #view class=\"mlv-editor__view\">\n <div #content class=\"mlv-editor__content\"></div>\n </div>\n </div>\n <mlv-editor-image-upload-status />\n </div>\n </ng-template>\n\n @if (message()) {\n <mlv-message [state]=\"resolvedState()\" [id]=\"id() + '-message'\">\n {{ message() }}\n </mlv-message>\n }\n</mlv-form-control-wrapper>\n\n<div\n class=\"mlv-editor__status\"\n [attr.aria-disabled]=\"computedDisabled() || null\"\n>\n <ng-content select=\"[mlvEditorStatus]\" />\n <mlv-spacer />\n <mlv-editor-status [characterLimit]=\"characterLimit()\" />\n</div>\n", styles: [".mlv-editor{--mlv-editor-gutter: var(--mlv-spacing-6);--mlv-editor-measure: 45rem;--mlv-editor-drop-gap: 1.5rem;box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor *{box-sizing:border-box}.mlv-editor{display:block;color:var(--mlv-text-primary)}.mlv-editor .mlv-form-control-wrapper__control-container{height:auto;min-height:var(--form-ctrl-height);padding:0;overflow:hidden;background:var(--mlv-background-base);transition:border-color var(--mlv-duration-fast) var(--mlv-ease-default),box-shadow var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor .mlv-form-control-wrapper__control-row{align-items:stretch}.mlv-form-control-wrapper--state-error .mlv-editor__surface{box-shadow:inset 0 0 0 var(--mlv-stroke-width) var(--mlv-border-error)}.mlv-editor__surface{display:flex;flex:1 1 auto;flex-direction:column;min-width:0;width:100%;background:var(--mlv-elevation-bg-3)}.mlv-editor__toolbar{display:flex;flex-wrap:nowrap;align-items:center;gap:var(--mlv-spacing-1);min-width:0;padding:var(--mlv-padding-xs);overflow:hidden;border-bottom:var(--mlv-stroke-width) solid var(--mlv-border-normal);background:var(--mlv-elevation-bg-3)}.mlv-editor__toolbar [hidden]{display:none!important}.mlv-editor__toolbar-scroll{flex:1 1 auto;min-width:0}.mlv-editor__toolbar-scroll>.mlv-toolbar{width:max-content;min-width:100%;flex-wrap:nowrap}.mlv-editor .mlv-editor-toolbar__separator{flex:0 0 auto;min-height:var(--mlv-height-s);margin-inline:var(--mlv-spacing-1)}.mlv-editor .mlv-editor-toolbar__overflow,.mlv-editor .mlv-editor-undo-redo,.mlv-editor .mlv-editor-inline-marks,.mlv-editor .mlv-editor-block-insert{display:inline-flex;flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor mlv-editor-zoom,.mlv-editor mlv-editor-heading,.mlv-editor mlv-editor-list,.mlv-editor mlv-editor-text-color,.mlv-editor mlv-editor-highlight,.mlv-editor mlv-editor-alignment,.mlv-editor mlv-editor-link,.mlv-editor mlv-editor-table,.mlv-editor mlv-editor-image-upload{flex:0 0 auto}.mlv-editor__viewport{min-block-size:8rem;overflow:auto;overscroll-behavior:contain}.mlv-editor__view{position:relative;min-inline-size:100%;transform:scale(var(--mlv-editor-zoom, 1));transform-origin:left top;transition:transform var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor__content{min-block-size:8rem;padding-block:var(--mlv-spacing-2);padding-inline:var(--mlv-editor-gutter);border:0;outline:none}.mlv-editor__block-handle{position:absolute;inset-inline-start:max(0rem,(100% - 2 * var(--mlv-editor-gutter) - var(--mlv-editor-measure)) / 2);display:inline-flex;align-items:center;justify-content:center;inline-size:var(--mlv-editor-gutter);block-size:var(--mlv-height-xs);border-radius:var(--mlv-radius-s);color:var(--mlv-text-tertiary);cursor:grab;opacity:0;pointer-events:none;transition:opacity var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor__block-handle svg{inline-size:var(--mlv-spacing-4);block-size:var(--mlv-spacing-4);fill:currentcolor}.mlv-editor__block-handle:hover{background-color:var(--mlv-background-neutral-1-hover);color:var(--mlv-text-secondary)}.mlv-editor__block-handle[data-visible=true]{opacity:1;pointer-events:auto}.mlv-editor__drop-indicator{position:absolute;inset-inline:calc(max(0rem,(100% - 2 * var(--mlv-editor-gutter) - var(--mlv-editor-measure)) / 2) + var(--mlv-editor-gutter));block-size:var(--mlv-stroke-width-medium);border-radius:var(--mlv-radius-full);background-color:var(--mlv-border-focus);opacity:0;pointer-events:none;transform:translateY(calc(var(--mlv-editor-drop-gap) / 2 - var(--mlv-stroke-width-medium) / 2));transition:top var(--mlv-duration-normal) var(--mlv-ease-out),opacity var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor__drop-indicator[data-visible=true]{opacity:1}.mlv-editor .mlv-editor__block--dragging{opacity:var(--mlv-disabled-opacity)}.mlv-editor .ProseMirror--block-dragging>*{transition:transform var(--mlv-duration-normal) var(--mlv-ease-out)}.mlv-editor__status{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--mlv-spacing-2);min-block-size:var(--mlv-spacing-4);margin-block-start:var(--mlv-spacing-1)}.mlv-editor__upload-placeholder{position:relative;display:inline-block;inline-size:var(--mlv-height-l);block-size:var(--mlv-height-l);margin-inline:var(--mlv-spacing-1);border:var(--mlv-stroke-width) dashed var(--mlv-border-focus);border-radius:var(--mlv-radius-m);background:var(--mlv-background-accent-1-pale);vertical-align:middle}.mlv-editor__upload-placeholder:after{position:absolute;inset:var(--mlv-spacing-2);border:var(--mlv-stroke-width-medium) solid var(--mlv-border-normal);border-block-start-color:var(--mlv-border-focus);border-radius:var(--mlv-radius-full);animation:mlv-editor-upload-spin var(--mlv-duration-slower) var(--mlv-ease-linear) infinite;content:\"\"}.mlv-editor__ai-streaming{border-radius:var(--mlv-radius-xs);background-color:var(--mlv-background-accent-1-pale)}.mlv-editor__ai-streaming-chunk{animation:mlv-editor-ai-chunk-in var(--mlv-duration-normal) var(--mlv-ease-out)}.mlv-editor__ai-caret{position:relative;display:inline-block;inline-size:0;block-size:1em;pointer-events:none}.mlv-editor__ai-caret:after{position:absolute;inset-block:0;inset-inline-start:.0625rem;inline-size:.35em;border-radius:var(--mlv-radius-xs);background:linear-gradient(to bottom,var(--mlv-background-accent-1),var(--mlv-background-accent-2));content:\"\";animation:mlv-editor-ai-caret-pulse var(--mlv-duration-sluggish) var(--mlv-ease-in-out) infinite}.mlv-editor__ai-suggestion-insert{border-radius:var(--mlv-radius-xs);background-color:var(--mlv-background-success-pale)}.mlv-editor__ai-suggestion-delete{border-radius:var(--mlv-radius-xs);background-color:var(--mlv-background-danger-1-pale);color:var(--mlv-text-negative);text-decoration-line:line-through}.mlv-editor__ai-suggestion-current{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:.125rem}.mlv-editor--content-width-default{--mlv-editor-measure: 45rem}.mlv-editor--content-width-wide{--mlv-editor-measure: 60rem}.mlv-editor--content-width-full{--mlv-editor-measure: 100%}.mlv-editor--focused .mlv-form-control-wrapper__control-container{border-color:var(--mlv-border-focus);box-shadow:var(--mlv-focus-ring)}.mlv-editor--readonly .ProseMirror{cursor:text}.mlv-editor--readonly .ProseMirror ::selection{background:var(--mlv-background-accent-1-pale)}.mlv-editor--disabled{opacity:var(--mlv-disabled-opacity)}.mlv-editor--disabled .mlv-editor__surface,.mlv-editor--disabled .mlv-editor__status{pointer-events:none}.mlv-editor--disabled .mlv-editor__content,.mlv-editor--disabled .ProseMirror{cursor:default;-webkit-user-select:none;user-select:none}.mlv-editor .ProseMirror{min-block-size:inherit;max-inline-size:var(--mlv-editor-measure);margin-inline:auto;color:var(--mlv-text-primary);font-family:var(--mlv-typography-family-text);font-size:var(--mlv-typography-body-m-size);font-weight:var(--mlv-typography-body-m-weight);line-height:var(--mlv-typography-body-m-line-height);overflow-wrap:anywhere;white-space:pre-wrap}.mlv-editor .ProseMirror:focus-visible{outline:none}.mlv-editor .ProseMirror>*:first-child{margin-block-start:0}.mlv-editor .ProseMirror>*:last-child{margin-block-end:0}.mlv-editor .ProseMirror p{margin-block:0 var(--mlv-spacing-3)}.mlv-editor .ProseMirror h1,.mlv-editor .ProseMirror h2,.mlv-editor .ProseMirror h3,.mlv-editor .ProseMirror h4,.mlv-editor .ProseMirror h5,.mlv-editor .ProseMirror h6{margin-block:var(--mlv-spacing-6) var(--mlv-spacing-3);color:var(--mlv-text-heading);font-family:var(--mlv-typography-family-heading)}.mlv-editor .ProseMirror h1{font-size:var(--mlv-typography-heading-h1-size);font-weight:var(--mlv-typography-heading-h1-weight);line-height:var(--mlv-typography-heading-h1-line-height)}.mlv-editor .ProseMirror h2{font-size:var(--mlv-typography-heading-h2-size);font-weight:var(--mlv-typography-heading-h2-weight);line-height:var(--mlv-typography-heading-h2-line-height)}.mlv-editor .ProseMirror h3{font-size:var(--mlv-typography-heading-h3-size);font-weight:var(--mlv-typography-heading-h3-weight);line-height:var(--mlv-typography-heading-h3-line-height)}.mlv-editor .ProseMirror h4{font-size:var(--mlv-typography-heading-h4-size);font-weight:var(--mlv-typography-heading-h4-weight);line-height:var(--mlv-typography-heading-h4-line-height)}.mlv-editor .ProseMirror h5{font-size:var(--mlv-typography-heading-h5-size);font-weight:var(--mlv-typography-heading-h5-weight);line-height:var(--mlv-typography-heading-h5-line-height)}.mlv-editor .ProseMirror h6{font-size:var(--mlv-typography-heading-h6-size);font-weight:var(--mlv-typography-heading-h6-weight);line-height:var(--mlv-typography-heading-h6-line-height)}.mlv-editor .ProseMirror h1{letter-spacing:var(--mlv-typography-heading-h1-letter-spacing)}.mlv-editor .ProseMirror h2{letter-spacing:var(--mlv-typography-heading-h2-letter-spacing)}.mlv-editor .ProseMirror h3,.mlv-editor .ProseMirror h4,.mlv-editor .ProseMirror h5,.mlv-editor .ProseMirror h6{letter-spacing:var(--mlv-letter-spacing-normal)}.mlv-editor .ProseMirror strong{font-weight:var(--mlv-font-weight-bold)}.mlv-editor .ProseMirror em{font-style:italic}.mlv-editor .ProseMirror s{text-decoration:line-through}.mlv-editor .ProseMirror u{text-underline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror a{color:var(--mlv-text-action);text-decoration:underline;text-underline-offset:var(--mlv-spacing-0-5);transition:color var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor .ProseMirror a:visited{color:var(--mlv-text-action)}.mlv-editor .ProseMirror a:hover{color:var(--mlv-text-action-hover)}.mlv-editor .ProseMirror a:focus-visible{border-radius:var(--mlv-radius-xs);outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror ul,.mlv-editor .ProseMirror ol{padding-inline-start:var(--mlv-spacing-6);margin-block:0 var(--mlv-spacing-3)}.mlv-editor .ProseMirror ul ul,.mlv-editor .ProseMirror ul ol,.mlv-editor .ProseMirror ol ul,.mlv-editor .ProseMirror ol ol{margin-block:var(--mlv-spacing-1) 0}.mlv-editor .ProseMirror ul{list-style:disc}.mlv-editor .ProseMirror ul ul{list-style:circle}.mlv-editor .ProseMirror ol{list-style:decimal}.mlv-editor .ProseMirror li{margin-block:var(--mlv-spacing-1)}.mlv-editor .ProseMirror li>p{margin:0}.mlv-editor .ProseMirror ul[data-type=taskList]{padding:0;list-style:none}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]{display:flex;align-items:flex-start;gap:var(--mlv-spacing-2)}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>label{display:inline-flex;align-items:center;min-block-size:var(--mlv-height-xs);cursor:pointer;-webkit-user-select:none;user-select:none}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>label input{accent-color:var(--mlv-background-accent-1)}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>label input:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror ul[data-type=taskList] li[data-type=taskItem]>div{flex:1 1 auto;min-width:0}.mlv-editor .ProseMirror blockquote{padding-inline-start:var(--mlv-spacing-4);margin:var(--mlv-spacing-4) 0;border-inline-start:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);color:var(--mlv-text-secondary)}.mlv-editor .ProseMirror code{padding:var(--mlv-spacing-0-5) var(--mlv-spacing-1);border-radius:var(--mlv-radius-s);background:var(--mlv-background-neutral-1);color:var(--mlv-text-primary);font-family:var(--mlv-typography-family-code);font-size:var(--mlv-typography-code-size)}.mlv-editor .ProseMirror pre{padding:var(--mlv-padding-m);margin-block:var(--mlv-spacing-4);overflow:auto;border:var(--mlv-stroke-width) solid var(--mlv-border-normal);border-radius:var(--mlv-radius-m);background:var(--mlv-background-sunken);color:var(--mlv-text-primary);font-family:var(--mlv-typography-family-code);font-size:var(--mlv-typography-code-size);line-height:var(--mlv-typography-body-m-line-height);tab-size:2}.mlv-editor .ProseMirror pre code{padding:0;background:transparent;color:inherit;font-size:inherit}.mlv-editor .ProseMirror hr{height:var(--mlv-stroke-width);margin-block:var(--mlv-spacing-6);border:0;background:var(--mlv-border-normal)}.mlv-editor .ProseMirror img{display:block;max-inline-size:100%;block-size:auto;margin-block:var(--mlv-spacing-4);border-radius:var(--mlv-radius-m)}.mlv-editor .ProseMirror img.ProseMirror-selectednode{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:0}.mlv-editor .ProseMirror .ProseMirror-selectednode,.mlv-editor .ProseMirror [data-resize-state=true]{border-radius:var(--mlv-radius-s);outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-1)}.mlv-editor .ProseMirror [data-resize-container]{margin-block:var(--mlv-spacing-4)}.mlv-editor .ProseMirror [data-resize-container] img{margin-block:0}.mlv-editor .ProseMirror [data-resize-container].ProseMirror-selectednode,.mlv-editor .ProseMirror [data-resize-container][data-resize-state=true]{outline:none}.mlv-editor .ProseMirror [data-resize-container].ProseMirror-selectednode>[data-resize-wrapper],.mlv-editor .ProseMirror [data-resize-container][data-resize-state=true]>[data-resize-wrapper]{border-radius:var(--mlv-radius-m);outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:0}.mlv-editor .ProseMirror [data-resize-handle],.mlv-editor .ProseMirror .resize-handle{inline-size:var(--mlv-spacing-3);block-size:var(--mlv-spacing-3);border:var(--mlv-stroke-width) solid var(--mlv-background-base);border-radius:var(--mlv-radius-full);background:var(--mlv-background-accent-1);box-shadow:var(--mlv-shadow-raised)}.mlv-editor .ProseMirror [data-resize-handle]:focus-visible,.mlv-editor .ProseMirror .resize-handle:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-spacing-0-5)}.mlv-editor .ProseMirror .is-editor-empty:first-child:before{float:left;height:0;color:var(--mlv-text-placeholder);content:attr(data-placeholder);pointer-events:none}.mlv-editor .tableWrapper{margin-block:var(--mlv-spacing-3);overflow-x:auto}.mlv-editor table{width:100%;border-collapse:collapse;table-layout:fixed}.mlv-editor th,.mlv-editor td{position:relative;min-width:3rem;padding:var(--mlv-spacing-2) var(--mlv-spacing-3);border:var(--mlv-stroke-width) solid var(--mlv-border-normal);vertical-align:top}.mlv-editor th{background:var(--mlv-background-neutral-1);font-weight:var(--mlv-font-weight-semibold)}.mlv-editor .selectedCell:after{position:absolute;inset:0;z-index:1;background:var(--mlv-background-accent-1-pale);content:\"\";opacity:.55;pointer-events:none}.mlv-editor .ProseMirror-focused .selectedCell:after{box-shadow:inset 0 0 0 var(--mlv-stroke-width-medium) var(--mlv-border-focus)}.mlv-editor .column-resize-handle{position:absolute;inset-block:0;inset-inline-end:calc(var(--mlv-stroke-width) * -1);z-index:2;width:calc(var(--mlv-stroke-width) * 2);background:var(--mlv-border-focus);pointer-events:none}.mlv-editor .resize-cursor{cursor:col-resize}@keyframes mlv-editor-upload-spin{to{transform:rotate(1turn)}}@keyframes mlv-editor-ai-chunk-in{0%{opacity:0;filter:blur(.125rem)}to{opacity:1;filter:blur(0)}}@keyframes mlv-editor-ai-caret-pulse{0%,to{opacity:1}50%{opacity:.35}}@media(max-width:40rem){.mlv-editor{--mlv-editor-gutter: var(--mlv-spacing-3)}.mlv-editor__toolbar{flex-wrap:nowrap;overflow-x:auto}.mlv-editor__content{padding-block:var(--mlv-spacing-1-5)}.mlv-editor__status{justify-content:flex-start}.mlv-editor .ProseMirror h1{font-size:var(--mlv-typography-heading-h2-size)}.mlv-editor .ProseMirror h2{font-size:var(--mlv-typography-heading-h3-size)}}@media print{.mlv-editor__toolbar,.mlv-editor__status,.mlv-editor__block-handle,.mlv-editor__drop-indicator,.mlv-editor .mlv-editor-image-upload-status,.mlv-editor__upload-placeholder,.mlv-editor__ai-suggestion-delete,.mlv-editor__ai-caret{display:none}.mlv-editor__ai-suggestion-current{outline:none}.mlv-editor__ai-streaming-chunk{animation:none}.mlv-editor__viewport{overflow:visible}.mlv-editor__view{transform:none}.mlv-editor__content,.mlv-editor .ProseMirror{min-block-size:0;padding:0}.mlv-editor table{break-inside:avoid}}@media(hover:none){.mlv-editor__block-handle{display:none}}@media(prefers-reduced-motion:reduce){.mlv-editor .mlv-form-control-wrapper__control-container,.mlv-editor__view,.mlv-editor__block-handle,.mlv-editor__drop-indicator,.mlv-editor .ProseMirror--block-dragging>*,.mlv-editor .ProseMirror a{transition-duration:var(--mlv-duration-instant)}.mlv-editor__upload-placeholder:after,.mlv-editor__ai-streaming-chunk,.mlv-editor__ai-caret:after{animation:none}}.mlv-editor__drag-ghost{max-block-size:12rem;padding:var(--mlv-spacing-2);overflow:hidden;border-radius:var(--mlv-radius-m);background-color:var(--mlv-background-raised);box-shadow:var(--mlv-shadow-floating);opacity:.9;-webkit-mask-image:linear-gradient(to bottom,black 70%,transparent 100%);mask-image:linear-gradient(to bottom,black 70%,transparent 100%);scale:.85;transform-origin:top left}\n"] }]
984
- }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], contentWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentWidth", required: false }] }], extensions: [{ type: i0.Input, args: [{ isSignal: true, alias: "extensions", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], characterLimit: [{ type: i0.Input, args: [{ isSignal: true, alias: "characterLimit", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledBy", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], imageUploader: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageUploader", required: false }] }], imageUploadOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageUploadOptions", required: false }] }], aiProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiProvider", required: false }] }], editorReady: [{ type: i0.Output, args: ["editorReady"] }], focus: [{ type: i0.Output, args: ["focus"] }], blur: [{ type: i0.Output, args: ["blur"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], transaction: [{ type: i0.Output, args: ["transaction"] }], editorError: [{ type: i0.Output, args: ["editorError"] }], imageUploadSuccess: [{ type: i0.Output, args: ["imageUploadSuccess"] }], imageUploadFailure: [{ type: i0.Output, args: ["imageUploadFailure"] }], imageUploadCancelled: [{ type: i0.Output, args: ["imageUploadCancelled"] }], _content: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }], _view: [{ type: i0.ViewChild, args: ['view', { isSignal: true }] }], _toolbarDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvEditorToolbarDef), { isSignal: true }] }], _toolbarStartDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvEditorToolbarStartDef), { isSignal: true }] }], _toolbarEndDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => MlvEditorToolbarEndDef), { isSignal: true }] }] } });
985
- //# sourceMappingURL=editor.js.map