@malva-ui/editor 0.1.15 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -3
- package/fesm2022/malva-ui-editor.mjs +1619 -257
- package/fesm2022/malva-ui-editor.mjs.map +1 -1
- package/package.json +18 -16
- package/types/malva-ui-editor.d.ts +264 -17
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, signal, Injectable, inject,
|
|
2
|
+
import { InjectionToken, signal, Injectable, computed, inject, DestroyRef, ElementRef, Directive, input, viewChild, effect, ChangeDetectionStrategy, ViewEncapsulation, Component, TemplateRef, ViewContainerRef, PLATFORM_ID, afterNextRender, untracked, afterRenderEffect, Injector, viewChildren, model, output, contentChildren, forwardRef } from '@angular/core';
|
|
3
3
|
import { LiveAnnouncer } from '@angular/cdk/a11y';
|
|
4
4
|
import { MLV_EDITOR_I18N, MlvI18nResolverService, MLV_FILE_UPLOAD_I18N } from '@malva-ui/i18n';
|
|
5
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
+
import { Subscription, fromEvent, merge, take, delay } from 'rxjs';
|
|
5
7
|
import { closeHistory } from '@tiptap/pm/history';
|
|
6
8
|
import { Node as Node$1, Slice, Fragment } from '@tiptap/pm/model';
|
|
7
9
|
import { PluginKey, Plugin, TextSelection, NodeSelection } from '@tiptap/pm/state';
|
|
@@ -16,12 +18,14 @@ import { MlvMenuTrigger, MlvMenu, MlvMenuItem } from '@malva-ui/core/menu';
|
|
|
16
18
|
import { MlvPopup, MlvPopupContainer, MlvPopupContent, MlvPopupTrigger } from '@malva-ui/core/popup';
|
|
17
19
|
import { MlvRadio, MlvRadioGroup } from '@malva-ui/core/radio';
|
|
18
20
|
import { MlvTooltip } from '@malva-ui/core/tooltip';
|
|
19
|
-
import { getExtensionField, flattenExtensions, findDuplicates, Extension, generateHTML, getMarkRange, Editor } from '@tiptap/core';
|
|
20
|
-
import { MlvRtlService, MlvResizeObserverService, mlvNextId, MlvFade, MlvSpacer } from '@malva-ui/cdk/utils';
|
|
21
|
+
import { getExtensionField, flattenExtensions, findDuplicates, posToDOMRect, Extension, generateHTML, getMarkRange, Editor } from '@tiptap/core';
|
|
22
|
+
import { MlvRtlService, MlvResizeObserverService, mlvMirrorInlineOffsets, mlvNextId, MlvFade, MlvSpacer } from '@malva-ui/cdk/utils';
|
|
21
23
|
import { MlvSelectionService, MlvSignalFormControlBase, MlvFormControlWrapper, MlvFormControlWrapperControl, MlvHint, MlvLabel, MlvMessage, MLV_FORM_CONTROL } from '@malva-ui/core/form-utils';
|
|
22
24
|
import { MlvToolbar } from '@malva-ui/core/toolbar';
|
|
23
25
|
import { MlvDivider } from '@malva-ui/core/divider';
|
|
24
26
|
import { Markdown } from '@tiptap/markdown';
|
|
27
|
+
import { Overlay } from '@angular/cdk/overlay';
|
|
28
|
+
import { TemplatePortal } from '@angular/cdk/portal';
|
|
25
29
|
import { FileHandlePlugin } from '@tiptap/extension-file-handler';
|
|
26
30
|
import Image from '@tiptap/extension-image';
|
|
27
31
|
import { TaskList, TaskItem } from '@tiptap/extension-list';
|
|
@@ -37,7 +41,6 @@ import { MlvDialogRef, MlvDialog, MlvDialogBody, MlvDialogFooter, MlvDialogHeade
|
|
|
37
41
|
import { MlvProgress } from '@malva-ui/core/progress';
|
|
38
42
|
import { MlvFileUpload } from '@malva-ui/core/file-upload';
|
|
39
43
|
import { DOWN_ARROW, UP_ARROW, RIGHT_ARROW, LEFT_ARROW } from '@angular/cdk/keycodes';
|
|
40
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
41
44
|
import { MlvDropdownPanel } from '@malva-ui/core/dropdown';
|
|
42
45
|
|
|
43
46
|
/** Optional dependency-injection token for a host-provided image uploader. */
|
|
@@ -173,10 +176,10 @@ class MlvEditorToolbarRevision {
|
|
|
173
176
|
/** @internal Increments after every Tiptap transaction or selection update. */
|
|
174
177
|
revision = signal(0, /* @ts-ignore */
|
|
175
178
|
...(ngDevMode ? [{ debugName: "revision" }] : /* istanbul ignore next */ []));
|
|
176
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
177
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.
|
|
179
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRevision, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
180
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRevision });
|
|
178
181
|
}
|
|
179
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
182
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRevision, decorators: [{
|
|
180
183
|
type: Injectable
|
|
181
184
|
}] });
|
|
182
185
|
/** @internal Supplies the built-in toolbar's per-editor invalidation signal. */
|
|
@@ -212,15 +215,41 @@ class MlvEditorToolbarRovingRegistry {
|
|
|
212
215
|
this._disconnectObserver();
|
|
213
216
|
};
|
|
214
217
|
}
|
|
215
|
-
/**
|
|
218
|
+
/**
|
|
219
|
+
* @internal Resolves the single effective tab stop, even during DOM mutations.
|
|
220
|
+
*
|
|
221
|
+
* Called once per registered widget on every invalidation, so it does no DOM
|
|
222
|
+
* work of its own: the enabled set and its order come from
|
|
223
|
+
* `_enabledWidgets()`, which is derived once per generation and carries the
|
|
224
|
+
* `_domStateRevision` dependency that keeps this reactive.
|
|
225
|
+
*/
|
|
216
226
|
isActive(widget) {
|
|
217
|
-
this.
|
|
227
|
+
const enabled = this._enabledWidgets();
|
|
218
228
|
const active = this._active();
|
|
219
|
-
const effectiveActive = active &&
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
229
|
+
const effectiveActive = active && enabled.includes(active) ? active : (enabled[0] ?? null);
|
|
230
|
+
return (!this._disabled() &&
|
|
231
|
+
effectiveActive === widget &&
|
|
232
|
+
enabled.includes(widget));
|
|
223
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* @internal Promotes a widget to the tab stop, gated on a **live** DOM read
|
|
236
|
+
* rather than on `_enabledWidgets()`.
|
|
237
|
+
*
|
|
238
|
+
* Deliberate, and the only place the two readings differ. `activate()` runs
|
|
239
|
+
* from a `focus` / `pointerdown` handler, so the question it has to answer is
|
|
240
|
+
* "is this widget interactive at this instant" — the live read is that
|
|
241
|
+
* question, and it is never wrong. The memo can only lag the DOM inside the
|
|
242
|
+
* window between a DOM write and the observer's microtask, and no input event
|
|
243
|
+
* is dispatched in that window, so the two agree today; keeping the live read
|
|
244
|
+
* means they still agree if some future code writes an attribute and calls
|
|
245
|
+
* `activate()` in the same turn, where the memo would be a generation behind
|
|
246
|
+
* and would refuse a widget the user can see is enabled.
|
|
247
|
+
*
|
|
248
|
+
* `move()` and `focusBoundary()` take the memo instead because they need the
|
|
249
|
+
* *order* of the enabled set, and an order assembled from N independent live
|
|
250
|
+
* reads is exactly what the memo exists to prevent. Do not "harmonise" the
|
|
251
|
+
* two: they are asking different questions.
|
|
252
|
+
*/
|
|
224
253
|
activate(widget) {
|
|
225
254
|
if (this._widgets().includes(widget) && this._enabled(widget)) {
|
|
226
255
|
this._hasInteracted = true;
|
|
@@ -273,14 +302,42 @@ class MlvEditorToolbarRovingRegistry {
|
|
|
273
302
|
!widget.hasAttribute('disabled') &&
|
|
274
303
|
widget.getAttribute('aria-disabled') !== 'true');
|
|
275
304
|
}
|
|
276
|
-
|
|
305
|
+
/**
|
|
306
|
+
* @private Registered widgets that are currently interactive, in DOM order.
|
|
307
|
+
*
|
|
308
|
+
* Derived once per invalidation generation rather than once per widget.
|
|
309
|
+
* `isActive()` runs for every registered widget — 21 on the built-in
|
|
310
|
+
* toolbar — and Angular settles one `disabled` transition in about two
|
|
311
|
+
* change-detection passes, so the enabled order was assembled roughly
|
|
312
|
+
* `2N + 2` times, each assembly walking the DOM with `closest('[hidden]')`
|
|
313
|
+
* once per widget. The shape is therefore `(≈2N + c) derivations × N walks`,
|
|
314
|
+
* not the plain `N^2` an earlier draft of this comment claimed — `N^2` at
|
|
315
|
+
* N=21 is 441, and the measured cost is about twice that.
|
|
316
|
+
*
|
|
317
|
+
* Measured on the built-in toolbar at N=21, over `disabled` false → true:
|
|
318
|
+
* the code this replaced took 39 derivations / 841 walks; this file with only
|
|
319
|
+
* the `computed()` removed takes 44 / 924; as written it takes 1 / 21. The
|
|
320
|
+
* two pre-fix figures differ because the old `isActive()` short-circuited on
|
|
321
|
+
* a still-enabled `_active` and paid single `_enabled()` reads outside the
|
|
322
|
+
* derivations. 924 is the one the spec's guard is written against, since that
|
|
323
|
+
* ablation isolates this `computed()` and changes nothing else.
|
|
324
|
+
*
|
|
325
|
+
* `_domStateRevision` is what makes the memo correct. The enabled set is a
|
|
326
|
+
* DOM read, and the `MutationObserver` that bumps that signal is the only
|
|
327
|
+
* thing that tells the graph the DOM moved — the same dependency `isActive()`
|
|
328
|
+
* already relied on. Every consumer now shares one snapshot per generation
|
|
329
|
+
* instead of each re-reading the DOM at a different point in the same pass.
|
|
330
|
+
*/
|
|
331
|
+
_enabledWidgets = computed(() => {
|
|
332
|
+
this._domStateRevision();
|
|
277
333
|
return this._widgets()
|
|
278
334
|
.filter((widget) => this._enabled(widget))
|
|
279
335
|
.sort((left, right) => {
|
|
280
336
|
const position = left.compareDocumentPosition(right);
|
|
281
337
|
return position & 4 ? -1 : position & 2 ? 1 : 0;
|
|
282
338
|
});
|
|
283
|
-
}
|
|
339
|
+
}, /* @ts-ignore */
|
|
340
|
+
...(ngDevMode ? [{ debugName: "_enabledWidgets" }] : /* istanbul ignore next */ []));
|
|
284
341
|
_observeStateChanges() {
|
|
285
342
|
if (this._observer ||
|
|
286
343
|
typeof MutationObserver === 'undefined' ||
|
|
@@ -289,6 +346,21 @@ class MlvEditorToolbarRovingRegistry {
|
|
|
289
346
|
!(this._root instanceof Node)) {
|
|
290
347
|
return;
|
|
291
348
|
}
|
|
349
|
+
// No debounce, deliberately, and the durable reason is the memo below, not
|
|
350
|
+
// the batching: after it, a redundant invalidation costs exactly one
|
|
351
|
+
// derivation — 21 `closest('[hidden]')` walks on the built-in toolbar — so
|
|
352
|
+
// even a coalescer that did merge something would be buying ~nothing, and
|
|
353
|
+
// would pay for it by leaving the tab stop a turn stale.
|
|
354
|
+
//
|
|
355
|
+
// A `queueMicrotask` coalescer also merges nothing here, in either
|
|
356
|
+
// direction. Mutations written in one turn are already one callback:
|
|
357
|
+
// `MutationObserver` delivers once per microtask checkpoint carrying every
|
|
358
|
+
// record accumulated since the last delivery, so disabling the editor
|
|
359
|
+
// writes 22 attributes and lands here once ("coalesces a whole batch of
|
|
360
|
+
// observed mutations into one invalidation" pins that). Mutations spread
|
|
361
|
+
// across separate microtasks are not merged either — each already lands in
|
|
362
|
+
// its own turn, which is precisely where a per-turn debounce flushes.
|
|
363
|
+
// The cost that was worth removing was the fan-out below.
|
|
292
364
|
this._observer = new MutationObserver(() => {
|
|
293
365
|
this._domStateRevision.update((revision) => revision + 1);
|
|
294
366
|
this._synchronizeActiveWidget();
|
|
@@ -300,9 +372,23 @@ class MlvEditorToolbarRovingRegistry {
|
|
|
300
372
|
subtree: true,
|
|
301
373
|
});
|
|
302
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* @private Re-resolves `_active` when the widget holding the tab stop is no
|
|
377
|
+
* longer part of the enabled set.
|
|
378
|
+
*
|
|
379
|
+
* Reactive-graph note: this reads `_enabledWidgets()`, where it used to read
|
|
380
|
+
* a non-reactive `_enabled(active)`, so `MlvEditorToolbarRoot`'s effect —
|
|
381
|
+
* which reaches here through `setDisabled()` — now tracks `_widgets` and
|
|
382
|
+
* `_domStateRevision` on *both* branches, not just on the fall-through into
|
|
383
|
+
* `_focusFirstWidget()`. The effect therefore re-runs on every widget
|
|
384
|
+
* registration and every observed mutation. That is deliberate and cheap
|
|
385
|
+
* post-memo (a re-run costs one cached memo read), and it does not loop:
|
|
386
|
+
* `_active` converges in at most two runs, and the effect already both read
|
|
387
|
+
* and wrote `_active` before this change.
|
|
388
|
+
*/
|
|
303
389
|
_synchronizeActiveWidget() {
|
|
304
390
|
const active = this._active();
|
|
305
|
-
if (active && this.
|
|
391
|
+
if (active && this._enabledWidgets().includes(active))
|
|
306
392
|
return;
|
|
307
393
|
this._focusFirstWidget();
|
|
308
394
|
}
|
|
@@ -313,14 +399,28 @@ class MlvEditorToolbarRovingRegistry {
|
|
|
313
399
|
this._observer?.disconnect();
|
|
314
400
|
this._observer = undefined;
|
|
315
401
|
}
|
|
316
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
317
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.
|
|
402
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRovingRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
403
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRovingRegistry });
|
|
318
404
|
}
|
|
319
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
405
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRovingRegistry, decorators: [{
|
|
320
406
|
type: Injectable
|
|
321
407
|
}] });
|
|
322
408
|
/** @internal Resolves the nearest editor's projected-toolbar roving registry. */
|
|
323
409
|
const MLV_EDITOR_TOOLBAR_ROVING = new InjectionToken('MLV_EDITOR_TOOLBAR_ROVING');
|
|
410
|
+
/**
|
|
411
|
+
* @internal Focuses the editor content with its selection. `view.focus()`
|
|
412
|
+
* alone moves no DOM focus while the view is not editable (`readonly`), so the
|
|
413
|
+
* contenteditable root is focused first; ProseMirror then writes the selection
|
|
414
|
+
* back to the DOM.
|
|
415
|
+
*/
|
|
416
|
+
function mlvEditorFocusContent(editor) {
|
|
417
|
+
if (editor.isDestroyed)
|
|
418
|
+
return;
|
|
419
|
+
if (!editor.view.editable) {
|
|
420
|
+
editor.view.dom.focus({ preventScroll: true });
|
|
421
|
+
}
|
|
422
|
+
editor.view.focus();
|
|
423
|
+
}
|
|
324
424
|
/**
|
|
325
425
|
* Internal per-editor registry for CDK overlay roots owned by toolbar controls.
|
|
326
426
|
* It is intentionally excluded from the public barrel: public controls use it
|
|
@@ -330,6 +430,14 @@ class MlvEditorOverlayRegistry {
|
|
|
330
430
|
_entries = new Map();
|
|
331
431
|
_onFocusIn;
|
|
332
432
|
_onFocusOut;
|
|
433
|
+
/**
|
|
434
|
+
* @private Net for the whole registry. Each entry is released the moment its
|
|
435
|
+
* overlay is removed — a destroy-scoped lifetime alone would hold every
|
|
436
|
+
* overlay ever opened — but this guarantees release even if a consumer never
|
|
437
|
+
* calls `destroy()` or `closeAll()`. The registry is provided by the editor
|
|
438
|
+
* component, so this ref is the editor's.
|
|
439
|
+
*/
|
|
440
|
+
_destroyRef = inject(DestroyRef);
|
|
333
441
|
/** @internal Wires the nearest editor's composite focus handlers. */
|
|
334
442
|
setFocusHandlers(onFocusIn, onFocusOut) {
|
|
335
443
|
this._onFocusIn = onFocusIn;
|
|
@@ -342,12 +450,17 @@ class MlvEditorOverlayRegistry {
|
|
|
342
450
|
existing.close = close;
|
|
343
451
|
return () => this._remove(root);
|
|
344
452
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
453
|
+
// Capture phase, matching the editor host's own boundary listeners: an
|
|
454
|
+
// overlay's content may stop focus events on its way back up, and the
|
|
455
|
+
// composite has to see the crossing regardless.
|
|
456
|
+
const listeners = new Subscription();
|
|
457
|
+
listeners.add(fromEvent(root, 'focusin', { capture: true })
|
|
458
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
459
|
+
.subscribe((event) => this._onFocusIn?.(event)));
|
|
460
|
+
listeners.add(fromEvent(root, 'focusout', { capture: true })
|
|
461
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
462
|
+
.subscribe((event) => this._onFocusOut?.(event)));
|
|
463
|
+
this._entries.set(root, { root, close, listeners });
|
|
351
464
|
return () => this._remove(root);
|
|
352
465
|
}
|
|
353
466
|
/** @internal Whether a node is rendered in an editor-owned overlay. */
|
|
@@ -370,6 +483,45 @@ class MlvEditorOverlayRegistry {
|
|
|
370
483
|
}
|
|
371
484
|
}
|
|
372
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* @internal Asks every owned overlay except `keep` to close and leaves each
|
|
488
|
+
* entry for its owner to release, unlike `closeAll()`: an entry with nothing
|
|
489
|
+
* to close (the AI review bar) keeps its focus listeners.
|
|
490
|
+
*/
|
|
491
|
+
closeOthers(keep) {
|
|
492
|
+
for (const entry of [...this._entries.values()]) {
|
|
493
|
+
if (entry.root === keep)
|
|
494
|
+
continue;
|
|
495
|
+
try {
|
|
496
|
+
entry.close();
|
|
497
|
+
}
|
|
498
|
+
catch {
|
|
499
|
+
// A third-party overlay must not keep the others open.
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* @internal A toolbar surface is going away because the editor turned
|
|
505
|
+
* `readonly` (#498): the docked band, which the next render removes, or the
|
|
506
|
+
* selection bubble's pane, which it hides. Asks every owned overlay except
|
|
507
|
+
* `surface` to close, like `closeOthers()`, and keeps focus in the editor:
|
|
508
|
+
* focus in `surface`, or in a popup (a registered root portaled into an
|
|
509
|
+
* overlay pane that `content` does not share; inside a dialog it does), moves
|
|
510
|
+
* to the content through `focusContent` first, while both still exist, so a
|
|
511
|
+
* closing popup finds focus outside its pane and hands nothing back to a
|
|
512
|
+
* trigger in `surface`. Focus anywhere else (the content, the status row,
|
|
513
|
+
* the AI review bar) stays where it is.
|
|
514
|
+
*/
|
|
515
|
+
closeForReadonly(surface, content, focusContent) {
|
|
516
|
+
const active = surface.ownerDocument.activeElement;
|
|
517
|
+
if (active &&
|
|
518
|
+
(surface.contains(active) ||
|
|
519
|
+
(this.contains(active) &&
|
|
520
|
+
!(active.closest('.cdk-overlay-pane')?.contains(content) ?? true)))) {
|
|
521
|
+
focusContent();
|
|
522
|
+
}
|
|
523
|
+
this.closeOthers(surface);
|
|
524
|
+
}
|
|
373
525
|
/** @internal Removes listener resources without invoking overlay close callbacks. */
|
|
374
526
|
destroy() {
|
|
375
527
|
for (const entry of [...this._entries.values()])
|
|
@@ -380,13 +532,12 @@ class MlvEditorOverlayRegistry {
|
|
|
380
532
|
if (!entry)
|
|
381
533
|
return;
|
|
382
534
|
this._entries.delete(root);
|
|
383
|
-
entry.
|
|
384
|
-
entry.root.removeEventListener('focusout', entry.onFocusOut, true);
|
|
535
|
+
entry.listeners.unsubscribe();
|
|
385
536
|
}
|
|
386
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
387
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.
|
|
537
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorOverlayRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
538
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorOverlayRegistry });
|
|
388
539
|
}
|
|
389
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
540
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorOverlayRegistry, decorators: [{
|
|
390
541
|
type: Injectable
|
|
391
542
|
}] });
|
|
392
543
|
/** @internal Injection token for editor-owned overlay registration. */
|
|
@@ -414,10 +565,10 @@ class MlvEditorUploadAbortRegistry {
|
|
|
414
565
|
}
|
|
415
566
|
}
|
|
416
567
|
}
|
|
417
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
418
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.
|
|
568
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorUploadAbortRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
569
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorUploadAbortRegistry });
|
|
419
570
|
}
|
|
420
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
571
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorUploadAbortRegistry, decorators: [{
|
|
421
572
|
type: Injectable
|
|
422
573
|
}] });
|
|
423
574
|
/** @internal Injection token for the editor-owned upload abort registry. */
|
|
@@ -2472,10 +2623,10 @@ class MlvEditorAiContext {
|
|
|
2472
2623
|
const text = editor.getText();
|
|
2473
2624
|
return text.length > 0 ? text : null;
|
|
2474
2625
|
}
|
|
2475
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
2476
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.
|
|
2626
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAiContext, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2627
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAiContext });
|
|
2477
2628
|
}
|
|
2478
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
2629
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAiContext, decorators: [{
|
|
2479
2630
|
type: Injectable
|
|
2480
2631
|
}] });
|
|
2481
2632
|
/** Injects the AI command state belonging to the nearest `mlv-editor`. */
|
|
@@ -2504,10 +2655,10 @@ class MlvEditorToolbarWidget {
|
|
|
2504
2655
|
_activateOnPointerDown() {
|
|
2505
2656
|
this._registry.activate(this._element);
|
|
2506
2657
|
}
|
|
2507
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
2508
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
2658
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarWidget, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2659
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorToolbarWidget, isStandalone: true, selector: "[mlvEditorToolbarWidget]", host: { listeners: { "focus": "_activate()", "pointerdown": "_activateOnPointerDown()" }, properties: { "attr.tabindex": "_tabIndex()" } }, ngImport: i0 });
|
|
2509
2660
|
}
|
|
2510
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
2661
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarWidget, decorators: [{
|
|
2511
2662
|
type: Directive,
|
|
2512
2663
|
args: [{
|
|
2513
2664
|
selector: '[mlvEditorToolbarWidget]',
|
|
@@ -2540,6 +2691,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2540
2691
|
* resolves no provider (presence), and its actions disable — without hiding —
|
|
2541
2692
|
* while the editor is readonly or disabled or a transform is already running
|
|
2542
2693
|
* (executability), matching the toolbar's presence-vs-executability rule.
|
|
2694
|
+
* Projected into `mlv-editor`'s toolbar it is not rendered at all while the
|
|
2695
|
+
* editor is `readonly`, which renders no toolbar (#498).
|
|
2543
2696
|
*/
|
|
2544
2697
|
class MlvEditorAiMenu {
|
|
2545
2698
|
/**
|
|
@@ -2759,10 +2912,10 @@ class MlvEditorAiMenu {
|
|
|
2759
2912
|
this._unregisterMenu?.();
|
|
2760
2913
|
this._unregisterMenu = undefined;
|
|
2761
2914
|
}
|
|
2762
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
2763
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
2915
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAiMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2916
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorAiMenu, isStandalone: true, selector: "mlv-editor-ai-menu", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, showCustomPrompt: { classPropertyName: "showCustomPrompt", publicName: "showCustomPrompt", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "hidden": "!_hasProvider()" }, classAttribute: "mlv-editor-ai-menu" }, viewQueries: [{ propertyName: "_menu", first: true, predicate: ["_menu"], descendants: true, isSignal: true }, { propertyName: "_menuTrigger", first: true, predicate: MlvMenuTrigger, descendants: true, isSignal: true }, { propertyName: "_popup", first: true, predicate: ["_popup"], descendants: true, isSignal: true }, { propertyName: "_triggerElement", first: true, predicate: ["_triggerElement"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_instructionInput", first: true, predicate: ["_instructionInput"], descendants: true, isSignal: true }, { propertyName: "_panel", first: true, predicate: ["_panel"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- The trigger is declared once and rendered by whichever branch applies:\n `mlv-popup-container` requires a popup content child, so it cannot wrap the\n trigger when the custom prompt is dropped. -->\n<ng-template #_trigger>\n <button\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvMenuTrigger]=\"_menu\"\n [menuTriggerDisabled]=\"_disabled() || _running()\"\n [attr.aria-label]=\"_running() ? _copy().aiCancel : _copy().aiMenu\"\n [mlvTooltip]=\"_running() ? _copy().aiCancel : _copy().aiMenu\"\n (click)=\"_onTriggerClick()\"\n (menuOpened)=\"_registerMenuOverlay()\"\n (menuClosed)=\"_unregisterMenuOverlay()\"\n >\n @if (_running()) {\n <svg mlvButtonIcon lucideCircleStop aria-hidden=\"true\" />\n } @else {\n <svg mlvButtonIcon lucideSparkles aria-hidden=\"true\" />\n }\n </button>\n</ng-template>\n\n@if (showCustomPrompt()) {\n <mlv-popup-container class=\"mlv-editor-ai-menu__anchor\">\n <ng-container [ngTemplateOutlet]=\"_trigger\" />\n\n <mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [position]=\"['bottom-start', 'top-start', 'bottom-end', 'top-end']\"\n [ariaLabel]=\"_copy().aiCustom\"\n (afterOpened)=\"_onPromptOpened()\"\n (afterClosed)=\"_onPromptClosed()\"\n >\n <ng-template mlvPopupContent>\n <div #_panel class=\"mlv-editor-ai-menu__panel\">\n <mlv-input\n #_instructionInput\n [label]=\"_copy().aiCustom\"\n [placeholder]=\"_copy().aiPromptPlaceholder\"\n [disabled]=\"_disabled()\"\n [value]=\"_instruction()\"\n (valueChange)=\"_instruction.set($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-radio-group\n class=\"mlv-editor-ai-menu__output\"\n [label]=\"_copy().aiOutputMode\"\n [value]=\"_output()\"\n (valueChange)=\"_onOutputChange($event)\"\n >\n <mlv-radio value=\"replace-selection\" [disabled]=\"_disabled()\">\n {{ _copy().aiReplaceSelection }}\n </mlv-radio>\n <mlv-radio value=\"insert-below\" [disabled]=\"_disabled()\">\n {{ _copy().aiInsertBelow }}\n </mlv-radio>\n <mlv-radio value=\"review\" [disabled]=\"_disabled()\">\n {{ _copy().aiReviewChanges }}\n </mlv-radio>\n </mlv-radio-group>\n <div class=\"mlv-editor-ai-menu__actions\">\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [disabled]=\"_applyDisabled()\"\n (click)=\"_apply()\"\n >\n {{ _copy().aiApply }}\n </button>\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n (click)=\"_closePrompt()\"\n >\n {{ _copy().aiCancel }}\n </button>\n </div>\n </div>\n </ng-template>\n </mlv-popup>\n </mlv-popup-container>\n} @else {\n <ng-container [ngTemplateOutlet]=\"_trigger\" />\n}\n\n<mlv-menu #_menu [label]=\"_copy().aiMenu\">\n <!-- Tracked by index: a host-authored list may repeat a kind, so the kind\n is not an identity. -->\n @for (action of _actions(); track $index) {\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_itemsDisabled()\"\n (itemClick)=\"_runAction(action)\"\n >\n {{ action.label }}\n </mlv-list-item>\n }\n @if (showCustomPrompt()) {\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_itemsDisabled()\"\n (itemClick)=\"_openPrompt()\"\n >\n {{ _copy().aiCustom }}\n </mlv-list-item>\n }\n</mlv-menu>\n", styles: ["@layer mlv.components{.mlv-editor-ai-menu{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-ai-menu *{box-sizing:border-box}.mlv-editor-ai-menu,.mlv-editor-ai-menu__anchor{display:inline-flex}.mlv-editor-ai-menu__panel{display:grid;width:min(22rem,100vw - 3.5rem);gap:var(--mlv-spacing-1-5);padding:var(--mlv-spacing-2)}.mlv-editor-ai-menu__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--mlv-spacing-3)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideCircleStop, selector: "svg[lucideCircleStop], svg[lucideStopCircle]" }, { kind: "component", type: LucideSparkles, selector: "svg[lucideSparkles], svg[lucideStars]" }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }, { kind: "component", type: MlvInput, selector: "mlv-input", inputs: ["type", "placeholder", "autocomplete", "inputMode", "maxLength", "minLength", "pattern", "name", "autofocus", "min", "max", "step", "bare", "projectControl", "role", "ariaExpanded", "ariaHasPopup", "ariaAutocomplete", "ariaControls", "ariaActiveDescendant", "ariaDescribedBy", "value"], outputs: ["valueChange", "inputFocus", "inputBlur"] }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }, { kind: "component", type: MlvPopup, selector: "mlv-popup", inputs: ["position", "positions", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "hasArrow", "hasShadow", "class", "mlvDensity", "flexibleDimensions", "scrollStrategy", "hasBackdrop", "restrictPosition", "panelRole", "modal", "ariaLabel", "dismissExcludeElements", "mobileMode", "mobileBreakpoint", "mobileTitle", "mobileCloseLabel", "opened"], outputs: ["openedChange", "afterOpened", "afterClosed"] }, { kind: "component", type: MlvPopupContainer, selector: "mlv-popup-container" }, { kind: "directive", type: MlvPopupContent, selector: "[mlvPopupContent]" }, { kind: "component", type: MlvRadio, selector: "mlv-radio", inputs: ["ariaLabel", "ariaLabelledBy", "value", "disabled"] }, { kind: "component", type: MlvRadioGroup, selector: "mlv-radio-group", inputs: ["value", "name"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
2764
2917
|
}
|
|
2765
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
2918
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAiMenu, decorators: [{
|
|
2766
2919
|
type: Component,
|
|
2767
2920
|
args: [{ selector: 'mlv-editor-ai-menu', imports: [
|
|
2768
2921
|
NgTemplateOutlet,
|
|
@@ -2785,7 +2938,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
2785
2938
|
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
2786
2939
|
class: 'mlv-editor-ai-menu',
|
|
2787
2940
|
'[hidden]': '!_hasProvider()',
|
|
2788
|
-
}, template: "<!-- The trigger is declared once and rendered by whichever branch applies:\n `mlv-popup-container` requires a popup content child, so it cannot wrap the\n trigger when the custom prompt is dropped. -->\n<ng-template #_trigger>\n <button\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvMenuTrigger]=\"_menu\"\n [menuTriggerDisabled]=\"_disabled() || _running()\"\n [attr.aria-label]=\"_running() ? _copy().aiCancel : _copy().aiMenu\"\n [mlvTooltip]=\"_running() ? _copy().aiCancel : _copy().aiMenu\"\n (click)=\"_onTriggerClick()\"\n (menuOpened)=\"_registerMenuOverlay()\"\n (menuClosed)=\"_unregisterMenuOverlay()\"\n >\n @if (_running()) {\n
|
|
2941
|
+
}, template: "<!-- The trigger is declared once and rendered by whichever branch applies:\n `mlv-popup-container` requires a popup content child, so it cannot wrap the\n trigger when the custom prompt is dropped. -->\n<ng-template #_trigger>\n <button\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvMenuTrigger]=\"_menu\"\n [menuTriggerDisabled]=\"_disabled() || _running()\"\n [attr.aria-label]=\"_running() ? _copy().aiCancel : _copy().aiMenu\"\n [mlvTooltip]=\"_running() ? _copy().aiCancel : _copy().aiMenu\"\n (click)=\"_onTriggerClick()\"\n (menuOpened)=\"_registerMenuOverlay()\"\n (menuClosed)=\"_unregisterMenuOverlay()\"\n >\n @if (_running()) {\n <svg mlvButtonIcon lucideCircleStop aria-hidden=\"true\" />\n } @else {\n <svg mlvButtonIcon lucideSparkles aria-hidden=\"true\" />\n }\n </button>\n</ng-template>\n\n@if (showCustomPrompt()) {\n <mlv-popup-container class=\"mlv-editor-ai-menu__anchor\">\n <ng-container [ngTemplateOutlet]=\"_trigger\" />\n\n <mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [position]=\"['bottom-start', 'top-start', 'bottom-end', 'top-end']\"\n [ariaLabel]=\"_copy().aiCustom\"\n (afterOpened)=\"_onPromptOpened()\"\n (afterClosed)=\"_onPromptClosed()\"\n >\n <ng-template mlvPopupContent>\n <div #_panel class=\"mlv-editor-ai-menu__panel\">\n <mlv-input\n #_instructionInput\n [label]=\"_copy().aiCustom\"\n [placeholder]=\"_copy().aiPromptPlaceholder\"\n [disabled]=\"_disabled()\"\n [value]=\"_instruction()\"\n (valueChange)=\"_instruction.set($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-radio-group\n class=\"mlv-editor-ai-menu__output\"\n [label]=\"_copy().aiOutputMode\"\n [value]=\"_output()\"\n (valueChange)=\"_onOutputChange($event)\"\n >\n <mlv-radio value=\"replace-selection\" [disabled]=\"_disabled()\">\n {{ _copy().aiReplaceSelection }}\n </mlv-radio>\n <mlv-radio value=\"insert-below\" [disabled]=\"_disabled()\">\n {{ _copy().aiInsertBelow }}\n </mlv-radio>\n <mlv-radio value=\"review\" [disabled]=\"_disabled()\">\n {{ _copy().aiReviewChanges }}\n </mlv-radio>\n </mlv-radio-group>\n <div class=\"mlv-editor-ai-menu__actions\">\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [disabled]=\"_applyDisabled()\"\n (click)=\"_apply()\"\n >\n {{ _copy().aiApply }}\n </button>\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n (click)=\"_closePrompt()\"\n >\n {{ _copy().aiCancel }}\n </button>\n </div>\n </div>\n </ng-template>\n </mlv-popup>\n </mlv-popup-container>\n} @else {\n <ng-container [ngTemplateOutlet]=\"_trigger\" />\n}\n\n<mlv-menu #_menu [label]=\"_copy().aiMenu\">\n <!-- Tracked by index: a host-authored list may repeat a kind, so the kind\n is not an identity. -->\n @for (action of _actions(); track $index) {\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_itemsDisabled()\"\n (itemClick)=\"_runAction(action)\"\n >\n {{ action.label }}\n </mlv-list-item>\n }\n @if (showCustomPrompt()) {\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_itemsDisabled()\"\n (itemClick)=\"_openPrompt()\"\n >\n {{ _copy().aiCustom }}\n </mlv-list-item>\n }\n</mlv-menu>\n", styles: ["@layer mlv.components{.mlv-editor-ai-menu{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-ai-menu *{box-sizing:border-box}.mlv-editor-ai-menu,.mlv-editor-ai-menu__anchor{display:inline-flex}.mlv-editor-ai-menu__panel{display:grid;width:min(22rem,100vw - 3.5rem);gap:var(--mlv-spacing-1-5);padding:var(--mlv-spacing-2)}.mlv-editor-ai-menu__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--mlv-spacing-3)}}\n"] }]
|
|
2789
2942
|
}], ctorParameters: () => [], propDecorators: { actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], showCustomPrompt: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCustomPrompt", required: false }] }], _menu: [{ type: i0.ViewChild, args: ['_menu', { isSignal: true }] }], _menuTrigger: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MlvMenuTrigger), { isSignal: true }] }], _popup: [{ type: i0.ViewChild, args: ['_popup', { isSignal: true }] }], _triggerElement: [{ type: i0.ViewChild, args: ['_triggerElement', { ...{
|
|
2790
2943
|
read: ElementRef,
|
|
2791
2944
|
}, isSignal: true }] }], _instructionInput: [{ type: i0.ViewChild, args: ['_instructionInput', { isSignal: true }] }], _panel: [{ type: i0.ViewChild, args: ['_panel', { isSignal: true }] }] } });
|
|
@@ -2983,10 +3136,10 @@ class MlvEditorAiReviewBar {
|
|
|
2983
3136
|
_rejectAll() {
|
|
2984
3137
|
this._ai?.rejectAll();
|
|
2985
3138
|
}
|
|
2986
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
2987
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
3139
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAiReviewBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3140
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorAiReviewBar, isStandalone: true, selector: "mlv-editor-ai-review-bar", host: { attributes: { "role": "group" }, properties: { "attr.aria-label": "_copy().aiReviewBar", "hidden": "!_visible()" }, classAttribute: "mlv-editor-ai-review-bar" }, ngImport: i0, template: "@if (_running()) {\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n mlvDensity=\"tight\"\n class=\"mlv-editor-ai-review-bar__stop\"\n [disabled]=\"_disabled()\"\n (click)=\"_stop()\"\n >\n <svg mlvButtonIcon lucideCircleStop aria-hidden=\"true\" />\n {{ _copy().aiStopGeneration }}\n </button>\n}\n@if (_reviewing()) {\n <span class=\"mlv-editor-ai-review-bar__count\">{{ _countText() }}</span>\n <!-- Screen-reader-only description of the current suggestion: the removed\n text exists only in the aria-hidden strikethrough widget, so the\n accept/reject buttons point here via aria-describedby. -->\n <span\n class=\"mlv-editor-ai-review-bar__current-description\"\n [id]=\"_descriptionId\"\n >{{ _currentDescription() }}</span\n >\n <div class=\"mlv-editor-ai-review-bar__group\">\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiPreviousSuggestion\"\n [mlvTooltip]=\"_copy().aiPreviousSuggestion\"\n (click)=\"_previous()\"\n >\n <svg mlvButtonIcon lucideChevronLeft aria-hidden=\"true\" />\n </button>\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiNextSuggestion\"\n [mlvTooltip]=\"_copy().aiNextSuggestion\"\n (click)=\"_next()\"\n >\n <svg mlvButtonIcon lucideChevronRight aria-hidden=\"true\" />\n </button>\n </div>\n <div class=\"mlv-editor-ai-review-bar__group\">\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiAcceptSuggestion\"\n [attr.aria-describedby]=\"_descriptionId\"\n [mlvTooltip]=\"_copy().aiAcceptSuggestion\"\n (click)=\"_acceptCurrent()\"\n >\n <svg mlvButtonIcon lucideCheck aria-hidden=\"true\" />\n </button>\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiRejectSuggestion\"\n [attr.aria-describedby]=\"_descriptionId\"\n [mlvTooltip]=\"_copy().aiRejectSuggestion\"\n (click)=\"_rejectCurrent()\"\n >\n <svg mlvButtonIcon lucideX aria-hidden=\"true\" />\n </button>\n </div>\n <div class=\"mlv-editor-ai-review-bar__group\">\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n (click)=\"_acceptAll()\"\n >\n {{ _copy().aiAcceptAll }}\n </button>\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n (click)=\"_rejectAll()\"\n >\n {{ _copy().aiRejectAll }}\n </button>\n </div>\n}\n", styles: ["@layer mlv.components{.mlv-editor-ai-review-bar{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-ai-review-bar *{box-sizing:border-box}.mlv-editor-ai-review-bar{display:inline-flex;flex-wrap:wrap;align-items:center;gap:var(--mlv-spacing-2);font-size:var(--mlv-typography-body-s-size)}.mlv-editor-ai-review-bar[hidden]{display:none}.mlv-editor-ai-review-bar__count{color:var(--mlv-text-secondary);white-space:nowrap}.mlv-editor-ai-review-bar__group{display:inline-flex;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor-ai-review-bar__stop{white-space:nowrap}.mlv-editor-ai-review-bar__current-description{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;padding:0;margin:-1px}}\n"], dependencies: [{ kind: "component", type: LucideCheck, selector: "svg[lucideCheck]" }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "component", type: LucideCircleStop, selector: "svg[lucideCircleStop], svg[lucideStopCircle]" }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
2988
3141
|
}
|
|
2989
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
3142
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAiReviewBar, decorators: [{
|
|
2990
3143
|
type: Component,
|
|
2991
3144
|
args: [{ selector: 'mlv-editor-ai-review-bar', imports: [
|
|
2992
3145
|
LucideCheck,
|
|
@@ -3002,7 +3155,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
3002
3155
|
role: 'group',
|
|
3003
3156
|
'[attr.aria-label]': '_copy().aiReviewBar',
|
|
3004
3157
|
'[hidden]': '!_visible()',
|
|
3005
|
-
}, template: "@if (_running()) {\n<button\n
|
|
3158
|
+
}, template: "@if (_running()) {\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n mlvDensity=\"tight\"\n class=\"mlv-editor-ai-review-bar__stop\"\n [disabled]=\"_disabled()\"\n (click)=\"_stop()\"\n >\n <svg mlvButtonIcon lucideCircleStop aria-hidden=\"true\" />\n {{ _copy().aiStopGeneration }}\n </button>\n}\n@if (_reviewing()) {\n <span class=\"mlv-editor-ai-review-bar__count\">{{ _countText() }}</span>\n <!-- Screen-reader-only description of the current suggestion: the removed\n text exists only in the aria-hidden strikethrough widget, so the\n accept/reject buttons point here via aria-describedby. -->\n <span\n class=\"mlv-editor-ai-review-bar__current-description\"\n [id]=\"_descriptionId\"\n >{{ _currentDescription() }}</span\n >\n <div class=\"mlv-editor-ai-review-bar__group\">\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiPreviousSuggestion\"\n [mlvTooltip]=\"_copy().aiPreviousSuggestion\"\n (click)=\"_previous()\"\n >\n <svg mlvButtonIcon lucideChevronLeft aria-hidden=\"true\" />\n </button>\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiNextSuggestion\"\n [mlvTooltip]=\"_copy().aiNextSuggestion\"\n (click)=\"_next()\"\n >\n <svg mlvButtonIcon lucideChevronRight aria-hidden=\"true\" />\n </button>\n </div>\n <div class=\"mlv-editor-ai-review-bar__group\">\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiAcceptSuggestion\"\n [attr.aria-describedby]=\"_descriptionId\"\n [mlvTooltip]=\"_copy().aiAcceptSuggestion\"\n (click)=\"_acceptCurrent()\"\n >\n <svg mlvButtonIcon lucideCheck aria-hidden=\"true\" />\n </button>\n <button\n mlvButton\n type=\"button\"\n shape=\"square\"\n variant=\"transparent\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().aiRejectSuggestion\"\n [attr.aria-describedby]=\"_descriptionId\"\n [mlvTooltip]=\"_copy().aiRejectSuggestion\"\n (click)=\"_rejectCurrent()\"\n >\n <svg mlvButtonIcon lucideX aria-hidden=\"true\" />\n </button>\n </div>\n <div class=\"mlv-editor-ai-review-bar__group\">\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n (click)=\"_acceptAll()\"\n >\n {{ _copy().aiAcceptAll }}\n </button>\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n mlvDensity=\"tight\"\n [disabled]=\"_disabled()\"\n (click)=\"_rejectAll()\"\n >\n {{ _copy().aiRejectAll }}\n </button>\n </div>\n}\n", styles: ["@layer mlv.components{.mlv-editor-ai-review-bar{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-ai-review-bar *{box-sizing:border-box}.mlv-editor-ai-review-bar{display:inline-flex;flex-wrap:wrap;align-items:center;gap:var(--mlv-spacing-2);font-size:var(--mlv-typography-body-s-size)}.mlv-editor-ai-review-bar[hidden]{display:none}.mlv-editor-ai-review-bar__count{color:var(--mlv-text-secondary);white-space:nowrap}.mlv-editor-ai-review-bar__group{display:inline-flex;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor-ai-review-bar__stop{white-space:nowrap}.mlv-editor-ai-review-bar__current-description{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0;padding:0;margin:-1px}}\n"] }]
|
|
3006
3159
|
}], ctorParameters: () => [] });
|
|
3007
3160
|
|
|
3008
3161
|
/**
|
|
@@ -3238,18 +3391,793 @@ function preflightMlvEditorExtensions(extensions, initialFormat) {
|
|
|
3238
3391
|
}
|
|
3239
3392
|
}
|
|
3240
3393
|
|
|
3394
|
+
/**
|
|
3395
|
+
* @internal Resolves an `MlvEditor` sizing input to the value its custom
|
|
3396
|
+
* property receives, or `null` to write nothing.
|
|
3397
|
+
*
|
|
3398
|
+
* A finite number is px, matching `mlv-popup`. A string passes through
|
|
3399
|
+
* verbatim once trimmed, so any CSS length, `calc()`, `min()` or viewport unit
|
|
3400
|
+
* works. `undefined`, `null`, a blank string and a non-finite number all
|
|
3401
|
+
* resolve to `null`, so the host binding removes the property and the
|
|
3402
|
+
* stylesheet's `var()` fallback applies.
|
|
3403
|
+
*/
|
|
3404
|
+
function mlvEditorCssLength(value) {
|
|
3405
|
+
if (typeof value === 'number') {
|
|
3406
|
+
return Number.isFinite(value) ? `${value}px` : null;
|
|
3407
|
+
}
|
|
3408
|
+
if (typeof value === 'string') {
|
|
3409
|
+
const trimmed = value.trim();
|
|
3410
|
+
return trimmed === '' ? null : trimmed;
|
|
3411
|
+
}
|
|
3412
|
+
return null;
|
|
3413
|
+
}
|
|
3414
|
+
/** @internal ProseMirror's own default `scrollMargin`, in px (prosemirror-view `scrollRectIntoView`). */
|
|
3415
|
+
const MLV_EDITOR_SCROLL_MARGIN = 5;
|
|
3416
|
+
/**
|
|
3417
|
+
* @internal ProseMirror `scrollMargin` / `scrollThreshold` for a toolbar that
|
|
3418
|
+
* obscures `obscured` px on its own side (WCAG 2.2 SC 2.4.11). The threshold is
|
|
3419
|
+
* the obscured extent: ProseMirror scrolls only once the caret enters it. The
|
|
3420
|
+
* margin leaves the default 5px beyond it. Every other side keeps
|
|
3421
|
+
* ProseMirror's defaults.
|
|
3422
|
+
*/
|
|
3423
|
+
function mlvEditorScrollSides(kind, position, obscured) {
|
|
3424
|
+
const base = kind === 'margin' ? MLV_EDITOR_SCROLL_MARGIN : 0;
|
|
3425
|
+
const edge = base + Math.max(0, Math.ceil(obscured));
|
|
3426
|
+
return {
|
|
3427
|
+
top: position === 'top' ? edge : base,
|
|
3428
|
+
right: base,
|
|
3429
|
+
bottom: position === 'bottom' ? edge : base,
|
|
3430
|
+
left: base,
|
|
3431
|
+
};
|
|
3432
|
+
}
|
|
3433
|
+
/**
|
|
3434
|
+
* @internal A scroll-prop object whose sides re-resolve on every read.
|
|
3435
|
+
* ProseMirror reads `value[side]` lazily each time it scrolls a rect into view
|
|
3436
|
+
* (`getSide()` in prosemirror-view), so one stable object follows density,
|
|
3437
|
+
* configuration and consumer CSS offsets without `setProps` churn. Only the
|
|
3438
|
+
* toolbar's side measures anything.
|
|
3439
|
+
*/
|
|
3440
|
+
function createMlvEditorLiveScrollSides(kind, position, obscured) {
|
|
3441
|
+
const base = kind === 'margin' ? MLV_EDITOR_SCROLL_MARGIN : 0;
|
|
3442
|
+
const side = (which) => position() === which
|
|
3443
|
+
? mlvEditorScrollSides(kind, which, obscured())[which]
|
|
3444
|
+
: base;
|
|
3445
|
+
return {
|
|
3446
|
+
get top() {
|
|
3447
|
+
return side('top');
|
|
3448
|
+
},
|
|
3449
|
+
get right() {
|
|
3450
|
+
return base;
|
|
3451
|
+
},
|
|
3452
|
+
get bottom() {
|
|
3453
|
+
return side('bottom');
|
|
3454
|
+
},
|
|
3455
|
+
get left() {
|
|
3456
|
+
return base;
|
|
3457
|
+
},
|
|
3458
|
+
};
|
|
3459
|
+
}
|
|
3460
|
+
/**
|
|
3461
|
+
* @internal The part of `rect` inside `boundary`, or `null` once none of it
|
|
3462
|
+
* is. Edges count as inside, so a zero-size caret lying on the boundary is
|
|
3463
|
+
* still visible.
|
|
3464
|
+
*
|
|
3465
|
+
* The selection bubble anchors on this: while a capped viewport scrolls, it
|
|
3466
|
+
* follows the visible part of the selection, and when the selection has left
|
|
3467
|
+
* the viewport (or the window) it hides instead of floating over content the
|
|
3468
|
+
* selection is no longer in.
|
|
3469
|
+
*/
|
|
3470
|
+
function mlvEditorVisibleRect(rect, boundary) {
|
|
3471
|
+
const top = Math.max(rect.top, boundary.top);
|
|
3472
|
+
const bottom = Math.min(rect.bottom, boundary.bottom);
|
|
3473
|
+
const left = Math.max(rect.left, boundary.left);
|
|
3474
|
+
const right = Math.min(rect.right, boundary.right);
|
|
3475
|
+
return top <= bottom && left <= right ? { top, bottom, left, right } : null;
|
|
3476
|
+
}
|
|
3477
|
+
/**
|
|
3478
|
+
* @internal Which side of `anchor` the selection bubble opens on: above,
|
|
3479
|
+
* unless a bubble `height` px tall, `gap` px from the anchor, would cross the
|
|
3480
|
+
* boundary's top edge (the window, or a capped scroller's edge).
|
|
3481
|
+
*
|
|
3482
|
+
* CDK's own fallback flips only on the window's edges; a capped viewport's top
|
|
3483
|
+
* edge is not one it knows about, so the preference is decided here and CDK
|
|
3484
|
+
* keeps the other side as its fallback.
|
|
3485
|
+
*/
|
|
3486
|
+
function mlvEditorBubblePlacement(anchor, boundary, height, gap) {
|
|
3487
|
+
return anchor.top - gap - height >= boundary.top ? 'above' : 'below';
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
/** @internal Gap between the selection and the bubble, in px. */
|
|
3491
|
+
const MLV_EDITOR_BUBBLE_GAP = 8;
|
|
3492
|
+
/** @internal Closest the bubble comes to a window edge, in px. */
|
|
3493
|
+
const MLV_EDITOR_BUBBLE_VIEWPORT_MARGIN = 8;
|
|
3494
|
+
/** @internal Pane class; the bubble's BEM block. */
|
|
3495
|
+
const MLV_EDITOR_BUBBLE_CLASS = 'mlv-editor-bubble';
|
|
3496
|
+
/** @internal Pane modifier while the bubble is off screen. */
|
|
3497
|
+
const MLV_EDITOR_BUBBLE_HIDDEN_CLASS = 'mlv-editor-bubble--hidden';
|
|
3498
|
+
/** @internal Pane modifier while CDK resolved the below position. */
|
|
3499
|
+
const MLV_EDITOR_BUBBLE_BELOW_CLASS = 'mlv-editor-bubble--below';
|
|
3500
|
+
/** @internal Centred above the selection. */
|
|
3501
|
+
const MLV_EDITOR_BUBBLE_ABOVE = {
|
|
3502
|
+
originX: 'center',
|
|
3503
|
+
originY: 'top',
|
|
3504
|
+
overlayX: 'center',
|
|
3505
|
+
overlayY: 'bottom',
|
|
3506
|
+
offsetY: -MLV_EDITOR_BUBBLE_GAP,
|
|
3507
|
+
};
|
|
3508
|
+
/** @internal Centred below the selection. */
|
|
3509
|
+
const MLV_EDITOR_BUBBLE_BELOW = {
|
|
3510
|
+
originX: 'center',
|
|
3511
|
+
originY: 'bottom',
|
|
3512
|
+
overlayX: 'center',
|
|
3513
|
+
overlayY: 'top',
|
|
3514
|
+
offsetY: MLV_EDITOR_BUBBLE_GAP,
|
|
3515
|
+
};
|
|
3516
|
+
/** @internal Above first; CDK falls back below on a window edge. */
|
|
3517
|
+
const MLV_EDITOR_BUBBLE_ABOVE_FIRST = [
|
|
3518
|
+
MLV_EDITOR_BUBBLE_ABOVE,
|
|
3519
|
+
MLV_EDITOR_BUBBLE_BELOW,
|
|
3520
|
+
];
|
|
3521
|
+
/** @internal Below first, once above would cross the boundary. */
|
|
3522
|
+
const MLV_EDITOR_BUBBLE_BELOW_FIRST = [
|
|
3523
|
+
MLV_EDITOR_BUBBLE_BELOW,
|
|
3524
|
+
MLV_EDITOR_BUBBLE_ABOVE,
|
|
3525
|
+
];
|
|
3526
|
+
/** @internal Elements a press may focus; a press anywhere else keeps the caret. */
|
|
3527
|
+
const MLV_EDITOR_BUBBLE_FOCUSABLE = 'button, a[href], input, select, textarea, [tabindex], [contenteditable="true"]';
|
|
3528
|
+
/**
|
|
3529
|
+
* @internal Renders its template in a CDK overlay that floats over the
|
|
3530
|
+
* nearest `mlv-editor`'s selection: `toolbarAppearance="floating"`.
|
|
3531
|
+
*
|
|
3532
|
+
* The contents are whatever the template holds, so the same host can carry a
|
|
3533
|
+
* different set of controls later; `MlvEditor` stamps its toolbar template.
|
|
3534
|
+
* The overlay is created once and kept attached, hidden by a pane modifier,
|
|
3535
|
+
* so the controls keep their state and their narrow-mode measurement between
|
|
3536
|
+
* appearances instead of being re-created per selection. The one exception is
|
|
3537
|
+
* a `readonly` flip: `MlvEditor` stamps no toolbar into the template while
|
|
3538
|
+
* `readonly` (#498), so the pane is empty then and the controls are
|
|
3539
|
+
* re-created on the way back.
|
|
3540
|
+
*
|
|
3541
|
+
* Shown only while all of these hold: focus is in the editor composite, the
|
|
3542
|
+
* selection is non-empty (or Alt+F10 summoned it at the caret), no pointer is
|
|
3543
|
+
* still selecting, no drag or IME composition is in progress, the editor is
|
|
3544
|
+
* enabled and not `readonly`, and the selection is visible inside the window
|
|
3545
|
+
* and, for a capped editor, inside its scrolling viewport. It prefers above
|
|
3546
|
+
* the selection and flips below only when above would cross that boundary's
|
|
3547
|
+
* top edge. Turning `readonly` on while it is shown hides it and closes every
|
|
3548
|
+
* popup the editor owns; focus inside either returns to the content.
|
|
3549
|
+
*
|
|
3550
|
+
* Keyboard: Alt+F10 in the content shows it and moves focus to its first
|
|
3551
|
+
* control through the toolbar's roving registry; Escape dismisses it and
|
|
3552
|
+
* returns focus to the content with the selection intact; Tab leaves it back
|
|
3553
|
+
* into the content rather than for the end of the document, where the portal
|
|
3554
|
+
* sits. Appearing never moves focus.
|
|
3555
|
+
*
|
|
3556
|
+
* Escape and Alt+F10 in the content go through a ProseMirror plugin, not a DOM
|
|
3557
|
+
* listener: ProseMirror cancels every Escape it sees, so a listener behind it
|
|
3558
|
+
* would find each one already `defaultPrevented`, and one in front of it
|
|
3559
|
+
* would take Escape from a content popup. The plugin offers both keys to
|
|
3560
|
+
* every plugin registered after it and acts only when none claims them, so a
|
|
3561
|
+
* consumer's `@tiptap/suggestion` list or an AI stream still gets Escape
|
|
3562
|
+
* first. A dismissing Escape stops propagating, so a dialog or drawer around
|
|
3563
|
+
* the editor stays open; the next one reaches it. While `readonly` the bubble
|
|
3564
|
+
* claims neither key.
|
|
3565
|
+
*/
|
|
3566
|
+
class MlvEditorBubble {
|
|
3567
|
+
/** The editor's content viewport: the listener scope and the capped boundary. */
|
|
3568
|
+
viewport = input.required(/* @ts-ignore */
|
|
3569
|
+
...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
|
|
3570
|
+
/** Whether the viewport is the editor's scroll container, bounding where the selection counts as visible. */
|
|
3571
|
+
capped = input(false, { ...(ngDevMode ? { debugName: "capped" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
3572
|
+
/** @private Template rendered into the overlay pane. */
|
|
3573
|
+
_templateRef = inject(TemplateRef);
|
|
3574
|
+
/** @private Container the template view is created in, so it keeps the editor's injector. */
|
|
3575
|
+
_viewContainerRef = inject(ViewContainerRef);
|
|
3576
|
+
/** @private CDK overlay factory. */
|
|
3577
|
+
_overlay = inject(Overlay);
|
|
3578
|
+
/** @private Injected document; never the ambient global. */
|
|
3579
|
+
_document = inject(DOCUMENT);
|
|
3580
|
+
/** @private Directive lifetime; owns every listener below. */
|
|
3581
|
+
_destroyRef = inject(DestroyRef);
|
|
3582
|
+
/** @private Editor state: instance, focus, disabled and zoom. */
|
|
3583
|
+
_context = inject(MLV_EDITOR_TOOLBAR_CONTEXT);
|
|
3584
|
+
/** @private Bumped after every Tiptap transaction or selection update. */
|
|
3585
|
+
_revision = inject(MLV_EDITOR_TOOLBAR_REVISION, {
|
|
3586
|
+
optional: true,
|
|
3587
|
+
});
|
|
3588
|
+
/** @private The toolbar's roving focus; Alt+F10 enters through it. */
|
|
3589
|
+
_roving = inject(MLV_EDITOR_TOOLBAR_ROVING);
|
|
3590
|
+
/** @private Makes the pane part of the editor's composite focus while shown. */
|
|
3591
|
+
_overlays = inject(MLV_EDITOR_OVERLAY_REGISTRY);
|
|
3592
|
+
/** @private Scoped direction for the pane. */
|
|
3593
|
+
_rtl = inject(MlvRtlService);
|
|
3594
|
+
/** @private Pane size changes reposition the bubble. */
|
|
3595
|
+
_resizeObserver = inject(MlvResizeObserverService);
|
|
3596
|
+
/** @private Invalidates the render effect from DOM events. */
|
|
3597
|
+
_tick = signal(0, /* @ts-ignore */
|
|
3598
|
+
...(ngDevMode ? [{ debugName: "_tick" }] : /* istanbul ignore next */ []));
|
|
3599
|
+
/** @private Identifies this instance's content-key plugin in the editor state. */
|
|
3600
|
+
_keyPluginKey = new PluginKey('mlvEditorBubbleKeys');
|
|
3601
|
+
/** @private The overlay, created after the first render in the browser. */
|
|
3602
|
+
_overlayRef = null;
|
|
3603
|
+
/** @private The overlay's position strategy, re-pointed at the selection. */
|
|
3604
|
+
_strategy = null;
|
|
3605
|
+
/** @private The position list last handed to the strategy. */
|
|
3606
|
+
_positions = null;
|
|
3607
|
+
/** @private Whether the bubble is on screen. */
|
|
3608
|
+
_shown = false;
|
|
3609
|
+
/** @private Releases the pane's composite-focus registration. */
|
|
3610
|
+
_unregister = null;
|
|
3611
|
+
/** @private Alt+F10 showed it at a bare caret; cleared when focus returns to the content. */
|
|
3612
|
+
_summoned = false;
|
|
3613
|
+
/** @private Escape dismissed it for this selection; any other selection clears it. */
|
|
3614
|
+
_dismissed = null;
|
|
3615
|
+
/** @private A primary pointer is down in the content, still selecting. */
|
|
3616
|
+
_pointerSelecting = false;
|
|
3617
|
+
/** @private A pointer is down on the bubble; covers browsers that blur on a button press. */
|
|
3618
|
+
_pressing = false;
|
|
3619
|
+
/** @private A native drag (block handle or text) is in progress. */
|
|
3620
|
+
_dragging = false;
|
|
3621
|
+
/** @private An IME composition is in progress. */
|
|
3622
|
+
_composing = false;
|
|
3623
|
+
/** @private Per-gesture listeners, replaced by the next gesture of the same kind. */
|
|
3624
|
+
_gestures = { select: null, press: null, drag: null };
|
|
3625
|
+
constructor() {
|
|
3626
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID)))
|
|
3627
|
+
return;
|
|
3628
|
+
afterNextRender(() => this._create());
|
|
3629
|
+
// Registered once per editor instance and removed with this directive,
|
|
3630
|
+
// e.g. when `toolbarAppearance` returns to `'bar'`: left behind, it would
|
|
3631
|
+
// keep claiming Escape and Alt+F10 for a bubble that no longer exists.
|
|
3632
|
+
effect((onCleanup) => {
|
|
3633
|
+
const editor = this._context.editor();
|
|
3634
|
+
if (!editor || editor.isDestroyed)
|
|
3635
|
+
return;
|
|
3636
|
+
untracked(() => editor.registerPlugin(this._createKeyPlugin()));
|
|
3637
|
+
onCleanup(() => {
|
|
3638
|
+
if (!editor.isDestroyed)
|
|
3639
|
+
editor.unregisterPlugin(this._keyPluginKey);
|
|
3640
|
+
});
|
|
3641
|
+
});
|
|
3642
|
+
// Before the render effect below would hide the bubble, so focus in a
|
|
3643
|
+
// popup moves to the content while that popup still exists.
|
|
3644
|
+
effect(() => {
|
|
3645
|
+
if (!this._context.readonly())
|
|
3646
|
+
return;
|
|
3647
|
+
untracked(() => this._closeForReadonly());
|
|
3648
|
+
});
|
|
3649
|
+
afterRenderEffect(() => {
|
|
3650
|
+
this._tick();
|
|
3651
|
+
this._context.editor();
|
|
3652
|
+
this._context.disabled();
|
|
3653
|
+
this._context.readonly();
|
|
3654
|
+
this._context.focused();
|
|
3655
|
+
this._context.zoom();
|
|
3656
|
+
this._revision?.();
|
|
3657
|
+
this.capped();
|
|
3658
|
+
untracked(() => this._sync());
|
|
3659
|
+
});
|
|
3660
|
+
this._destroyRef.onDestroy(() => {
|
|
3661
|
+
for (const gesture of Object.values(this._gestures)) {
|
|
3662
|
+
gesture?.unsubscribe();
|
|
3663
|
+
}
|
|
3664
|
+
// Nothing is on screen once the overlay is gone.
|
|
3665
|
+
this._shown = false;
|
|
3666
|
+
this._unregister?.();
|
|
3667
|
+
this._unregister = null;
|
|
3668
|
+
this._overlayRef?.dispose();
|
|
3669
|
+
this._overlayRef = null;
|
|
3670
|
+
});
|
|
3671
|
+
}
|
|
3672
|
+
/** @private Creates the overlay and binds every listener, once. */
|
|
3673
|
+
_create() {
|
|
3674
|
+
const viewport = this.viewport();
|
|
3675
|
+
const direction = this._rtl.resolveDirection(viewport);
|
|
3676
|
+
const strategy = this._overlay
|
|
3677
|
+
.position()
|
|
3678
|
+
.flexibleConnectedTo({ x: 0, y: 0 })
|
|
3679
|
+
.withPositions(mlvMirrorInlineOffsets(MLV_EDITOR_BUBBLE_ABOVE_FIRST, direction))
|
|
3680
|
+
.withFlexibleDimensions(false)
|
|
3681
|
+
.withPush(true)
|
|
3682
|
+
.withViewportMargin(MLV_EDITOR_BUBBLE_VIEWPORT_MARGIN);
|
|
3683
|
+
const ref = this._overlay.create({
|
|
3684
|
+
positionStrategy: strategy,
|
|
3685
|
+
// Repositioned by `_sync()` from a document-level scroll listener, which
|
|
3686
|
+
// also sees the capped viewport's own scrolling; CDK's reposition
|
|
3687
|
+
// strategy only knows registered `cdkScrollable`s.
|
|
3688
|
+
scrollStrategy: this._overlay.scrollStrategies.noop(),
|
|
3689
|
+
direction,
|
|
3690
|
+
panelClass: [MLV_EDITOR_BUBBLE_CLASS, MLV_EDITOR_BUBBLE_HIDDEN_CLASS],
|
|
3691
|
+
hasBackdrop: false,
|
|
3692
|
+
});
|
|
3693
|
+
ref.attach(new TemplatePortal(this._templateRef, this._viewContainerRef));
|
|
3694
|
+
this._overlayRef = ref;
|
|
3695
|
+
this._strategy = strategy;
|
|
3696
|
+
this._positions = MLV_EDITOR_BUBBLE_ABOVE_FIRST;
|
|
3697
|
+
const pane = ref.overlayElement;
|
|
3698
|
+
strategy.positionChanges
|
|
3699
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3700
|
+
.subscribe((change) => pane.classList.toggle(MLV_EDITOR_BUBBLE_BELOW_CLASS, change.connectionPair.overlayY === 'top'));
|
|
3701
|
+
// Nothing re-parents an open pane, so a `[dir]` flip above the editor
|
|
3702
|
+
// re-mirrors it here.
|
|
3703
|
+
this._destroyRef.onDestroy(this._rtl.watchDirection(viewport, (next) => {
|
|
3704
|
+
ref.setDirection(next);
|
|
3705
|
+
this._positions = null;
|
|
3706
|
+
this._invalidate();
|
|
3707
|
+
}));
|
|
3708
|
+
this._resizeObserver
|
|
3709
|
+
.observe(pane)
|
|
3710
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3711
|
+
.subscribe(() => this._invalidate());
|
|
3712
|
+
this._bindViewportListeners(viewport);
|
|
3713
|
+
this._bindPaneListeners(pane);
|
|
3714
|
+
const window = this._document.defaultView;
|
|
3715
|
+
// Passive and capture: every scroll container's `scroll` reaches the
|
|
3716
|
+
// document in the capture phase, the capped viewport's included.
|
|
3717
|
+
fromEvent(this._document, 'scroll', { capture: true, passive: true })
|
|
3718
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3719
|
+
.subscribe(() => this._invalidateOnLayout());
|
|
3720
|
+
if (window) {
|
|
3721
|
+
fromEvent(window, 'resize', { passive: true })
|
|
3722
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3723
|
+
.subscribe(() => this._invalidateOnLayout());
|
|
3724
|
+
}
|
|
3725
|
+
this._sync();
|
|
3726
|
+
}
|
|
3727
|
+
/** @private Content-side gestures and keys. */
|
|
3728
|
+
_bindViewportListeners(viewport) {
|
|
3729
|
+
// Fallback behind the key plugin for ProseMirror's composition window: it
|
|
3730
|
+
// skips every key handler while it still counts as composing, and in
|
|
3731
|
+
// Safari for 500ms after `compositionend`, by when the bubble may already
|
|
3732
|
+
// be back. It cancels every key it does handle, so only a key it never
|
|
3733
|
+
// processed arrives here uncancelled. (A read-only view also skips them,
|
|
3734
|
+
// but the bubble claims no key there.)
|
|
3735
|
+
fromEvent(viewport, 'keydown')
|
|
3736
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3737
|
+
.subscribe((event) => {
|
|
3738
|
+
if (event.defaultPrevented)
|
|
3739
|
+
return;
|
|
3740
|
+
if (this._onContentKey(event))
|
|
3741
|
+
event.preventDefault();
|
|
3742
|
+
});
|
|
3743
|
+
fromEvent(viewport, 'focusin')
|
|
3744
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3745
|
+
.subscribe((event) => {
|
|
3746
|
+
if (!this._inContent(event.target))
|
|
3747
|
+
return;
|
|
3748
|
+
this._summoned = false;
|
|
3749
|
+
this._invalidate();
|
|
3750
|
+
});
|
|
3751
|
+
fromEvent(viewport, 'pointerdown')
|
|
3752
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3753
|
+
.subscribe((event) => {
|
|
3754
|
+
if (event.button !== 0 ||
|
|
3755
|
+
event.isPrimary === false ||
|
|
3756
|
+
!this._inContent(event.target)) {
|
|
3757
|
+
return;
|
|
3758
|
+
}
|
|
3759
|
+
this._pointerSelecting = true;
|
|
3760
|
+
this._summoned = false;
|
|
3761
|
+
this._invalidate();
|
|
3762
|
+
this._gesture('select', merge(fromEvent(this._document, 'pointerup', { capture: true }), fromEvent(this._document, 'pointercancel', { capture: true })).pipe(take(1)), () => {
|
|
3763
|
+
this._pointerSelecting = false;
|
|
3764
|
+
this._invalidate();
|
|
3765
|
+
});
|
|
3766
|
+
});
|
|
3767
|
+
fromEvent(viewport, 'compositionstart')
|
|
3768
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3769
|
+
.subscribe(() => {
|
|
3770
|
+
this._composing = true;
|
|
3771
|
+
this._invalidate();
|
|
3772
|
+
});
|
|
3773
|
+
fromEvent(viewport, 'compositionend')
|
|
3774
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3775
|
+
.subscribe(() => {
|
|
3776
|
+
this._composing = false;
|
|
3777
|
+
this._invalidate();
|
|
3778
|
+
});
|
|
3779
|
+
// Capture, so a drag source that stops `dragstart` still counts.
|
|
3780
|
+
fromEvent(viewport, 'dragstart', { capture: true })
|
|
3781
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3782
|
+
.subscribe(() => {
|
|
3783
|
+
this._dragging = true;
|
|
3784
|
+
this._invalidate();
|
|
3785
|
+
// `dragend` never reaches the document when the source left the DOM
|
|
3786
|
+
// mid-drag; the next press ends the wait instead.
|
|
3787
|
+
this._gesture('drag', merge(fromEvent(this._document, 'dragend', { capture: true }), fromEvent(this._document, 'drop', { capture: true }), fromEvent(this._document, 'pointerdown', { capture: true })).pipe(take(1)), () => {
|
|
3788
|
+
this._dragging = false;
|
|
3789
|
+
this._invalidate();
|
|
3790
|
+
});
|
|
3791
|
+
});
|
|
3792
|
+
}
|
|
3793
|
+
/** @private Bubble-side keys and presses. */
|
|
3794
|
+
_bindPaneListeners(pane) {
|
|
3795
|
+
fromEvent(pane, 'keydown')
|
|
3796
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3797
|
+
.subscribe((event) => {
|
|
3798
|
+
if (event.defaultPrevented)
|
|
3799
|
+
return;
|
|
3800
|
+
if (event.key === 'Escape') {
|
|
3801
|
+
event.preventDefault();
|
|
3802
|
+
// Kept from the page and any dialog around the editor: this Escape
|
|
3803
|
+
// belongs to the bubble.
|
|
3804
|
+
event.stopPropagation();
|
|
3805
|
+
this._dismiss();
|
|
3806
|
+
}
|
|
3807
|
+
else if (event.key === 'Tab') {
|
|
3808
|
+
// The pane is portaled to the end of the document; the next tab
|
|
3809
|
+
// stop after it is not the editor's.
|
|
3810
|
+
event.preventDefault();
|
|
3811
|
+
this._context.editor()?.view.focus();
|
|
3812
|
+
}
|
|
3813
|
+
});
|
|
3814
|
+
fromEvent(pane, 'pointerdown', { capture: true })
|
|
3815
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3816
|
+
.subscribe(() => {
|
|
3817
|
+
this._pressing = true;
|
|
3818
|
+
// Released a task after `pointerup`, so the `click` that follows
|
|
3819
|
+
// still finds the bubble on screen.
|
|
3820
|
+
this._gesture('press', merge(fromEvent(this._document, 'pointerup', { capture: true }), fromEvent(this._document, 'pointercancel', { capture: true })).pipe(take(1), delay(0)), () => {
|
|
3821
|
+
this._pressing = false;
|
|
3822
|
+
this._invalidate();
|
|
3823
|
+
});
|
|
3824
|
+
});
|
|
3825
|
+
// A press on the bubble's own padding keeps the caret and the selection
|
|
3826
|
+
// in the content; controls still take focus as usual.
|
|
3827
|
+
fromEvent(pane, 'mousedown')
|
|
3828
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
3829
|
+
.subscribe((event) => {
|
|
3830
|
+
const target = event.target;
|
|
3831
|
+
if (target instanceof Element &&
|
|
3832
|
+
target.closest(MLV_EDITOR_BUBBLE_FOCUSABLE)) {
|
|
3833
|
+
return;
|
|
3834
|
+
}
|
|
3835
|
+
event.preventDefault();
|
|
3836
|
+
});
|
|
3837
|
+
}
|
|
3838
|
+
/**
|
|
3839
|
+
* @private The plugin carrying content-side Escape and Alt+F10. The loop is
|
|
3840
|
+
* what makes it the lowest-priority key handler, not its place in the list:
|
|
3841
|
+
* plugins before it run first anyway, and it offers each of those keys to
|
|
3842
|
+
* every plugin after it (an AI stream session registers its Escape claim
|
|
3843
|
+
* later) before acting. Once it has offered the key it acts and returns
|
|
3844
|
+
* `true` unconditionally, even if a declining later handler changed the
|
|
3845
|
+
* bubble's state meanwhile; returning `false` there would make ProseMirror
|
|
3846
|
+
* run those handlers a second time. Returning `true` makes ProseMirror
|
|
3847
|
+
* cancel the event.
|
|
3848
|
+
*/
|
|
3849
|
+
_createKeyPlugin() {
|
|
3850
|
+
const key = this._keyPluginKey;
|
|
3851
|
+
return new Plugin({
|
|
3852
|
+
key,
|
|
3853
|
+
props: {
|
|
3854
|
+
handleKeyDown: (view, event) => {
|
|
3855
|
+
if (!this._ownsContentKey(event))
|
|
3856
|
+
return false;
|
|
3857
|
+
const plugins = view.state.plugins;
|
|
3858
|
+
const own = key.get(view.state);
|
|
3859
|
+
for (let index = own ? plugins.indexOf(own) + 1 : plugins.length; index < plugins.length; index++) {
|
|
3860
|
+
const plugin = plugins[index];
|
|
3861
|
+
if (plugin.props.handleKeyDown?.call(plugin, view, event)) {
|
|
3862
|
+
return true;
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
this._act(event);
|
|
3866
|
+
return true;
|
|
3867
|
+
},
|
|
3868
|
+
},
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3871
|
+
/**
|
|
3872
|
+
* @private Whether `event` is a key the bubble acts on right now: never
|
|
3873
|
+
* while disabled or `readonly`, where it cannot show.
|
|
3874
|
+
*/
|
|
3875
|
+
_ownsContentKey(event) {
|
|
3876
|
+
if (this._context.disabled() || this._context.readonly())
|
|
3877
|
+
return false;
|
|
3878
|
+
return ((event.key === 'Escape' && this._shown) ||
|
|
3879
|
+
(event.key === 'F10' &&
|
|
3880
|
+
event.altKey &&
|
|
3881
|
+
!event.ctrlKey &&
|
|
3882
|
+
!event.metaKey &&
|
|
3883
|
+
!event.shiftKey));
|
|
3884
|
+
}
|
|
3885
|
+
/**
|
|
3886
|
+
* @private The DOM fallback's entry: acts only on a key the bubble owns.
|
|
3887
|
+
* Returns whether it acted; the caller cancels the event.
|
|
3888
|
+
*/
|
|
3889
|
+
_onContentKey(event) {
|
|
3890
|
+
if (!this._ownsContentKey(event))
|
|
3891
|
+
return false;
|
|
3892
|
+
this._act(event);
|
|
3893
|
+
return true;
|
|
3894
|
+
}
|
|
3895
|
+
/**
|
|
3896
|
+
* @private Alt+F10 summons; Escape dismisses and stops there, so a dialog or
|
|
3897
|
+
* drawer around the editor does not close with it. Unchecked: callers
|
|
3898
|
+
* establish that the bubble owns the key.
|
|
3899
|
+
*/
|
|
3900
|
+
_act(event) {
|
|
3901
|
+
if (event.key === 'Escape') {
|
|
3902
|
+
event.stopPropagation();
|
|
3903
|
+
this._dismiss();
|
|
3904
|
+
}
|
|
3905
|
+
else {
|
|
3906
|
+
this._summon();
|
|
3907
|
+
}
|
|
3908
|
+
}
|
|
3909
|
+
/** @private Shows the bubble at the caret or selection and focuses its first control. */
|
|
3910
|
+
_summon() {
|
|
3911
|
+
const ref = this._overlayRef;
|
|
3912
|
+
if (!ref || this._context.disabled() || !this._context.editor())
|
|
3913
|
+
return;
|
|
3914
|
+
this._summoned = true;
|
|
3915
|
+
this._dismissed = null;
|
|
3916
|
+
this._sync();
|
|
3917
|
+
if (!this._shown) {
|
|
3918
|
+
this._summoned = false;
|
|
3919
|
+
return;
|
|
3920
|
+
}
|
|
3921
|
+
this._roving.focusBoundary('start');
|
|
3922
|
+
if (!ref.overlayElement.contains(this._document.activeElement)) {
|
|
3923
|
+
this._summoned = false;
|
|
3924
|
+
this._sync();
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
/** @private Hides the bubble for the current selection; focus returns to the content. */
|
|
3928
|
+
_dismiss() {
|
|
3929
|
+
this._dismissed = this._context.editor()?.state.selection ?? null;
|
|
3930
|
+
this._summoned = false;
|
|
3931
|
+
this._sync();
|
|
3932
|
+
}
|
|
3933
|
+
/** @private Shows, repositions or hides the bubble for the current state. */
|
|
3934
|
+
_sync() {
|
|
3935
|
+
const ref = this._overlayRef;
|
|
3936
|
+
const editor = this._context.editor();
|
|
3937
|
+
if (!ref || !editor || editor.isDestroyed || !this._wanted(editor)) {
|
|
3938
|
+
this._hide();
|
|
3939
|
+
return;
|
|
3940
|
+
}
|
|
3941
|
+
const windowRect = this._windowRect();
|
|
3942
|
+
const boundary = this.capped()
|
|
3943
|
+
? mlvEditorVisibleRect(this.viewport().getBoundingClientRect(), windowRect)
|
|
3944
|
+
: windowRect;
|
|
3945
|
+
const selection = this._selectionRect(editor);
|
|
3946
|
+
const visible = boundary ? mlvEditorVisibleRect(selection, boundary) : null;
|
|
3947
|
+
// Focus in the bubble (or a popup it opened) keeps it on screen when the
|
|
3948
|
+
// selection scrolls away, pushed to the window edge; hiding it would drop
|
|
3949
|
+
// that focus.
|
|
3950
|
+
const pinned = this._summoned || !editor.view.hasFocus();
|
|
3951
|
+
const anchor = visible ?? (pinned ? selection : null);
|
|
3952
|
+
if (!anchor) {
|
|
3953
|
+
this._hide();
|
|
3954
|
+
return;
|
|
3955
|
+
}
|
|
3956
|
+
this._show(ref, anchor, boundary ?? windowRect);
|
|
3957
|
+
}
|
|
3958
|
+
/** @private Whether every visibility condition except the anchor holds. */
|
|
3959
|
+
_wanted(editor) {
|
|
3960
|
+
if (this._context.disabled() || this._context.readonly())
|
|
3961
|
+
return false;
|
|
3962
|
+
if (!this._context.focused() && !this._pressing)
|
|
3963
|
+
return false;
|
|
3964
|
+
if (this._pointerSelecting || this._dragging || this._composing) {
|
|
3965
|
+
return false;
|
|
3966
|
+
}
|
|
3967
|
+
const selection = editor.state.selection;
|
|
3968
|
+
if (this._dismissed) {
|
|
3969
|
+
if (selection.eq(this._dismissed))
|
|
3970
|
+
return false;
|
|
3971
|
+
this._dismissed = null;
|
|
3972
|
+
}
|
|
3973
|
+
return this._summoned || !selection.empty;
|
|
3974
|
+
}
|
|
3975
|
+
/** @private Places and reveals the bubble at `anchor`. */
|
|
3976
|
+
_show(ref, anchor, boundary) {
|
|
3977
|
+
const strategy = this._strategy;
|
|
3978
|
+
if (!strategy)
|
|
3979
|
+
return;
|
|
3980
|
+
const pane = ref.overlayElement;
|
|
3981
|
+
const positions = mlvEditorBubblePlacement(anchor, boundary, pane.getBoundingClientRect().height, MLV_EDITOR_BUBBLE_GAP) === 'above'
|
|
3982
|
+
? MLV_EDITOR_BUBBLE_ABOVE_FIRST
|
|
3983
|
+
: MLV_EDITOR_BUBBLE_BELOW_FIRST;
|
|
3984
|
+
if (positions !== this._positions) {
|
|
3985
|
+
this._positions = positions;
|
|
3986
|
+
strategy.withPositions(mlvMirrorInlineOffsets(positions, ref.getDirection()));
|
|
3987
|
+
}
|
|
3988
|
+
strategy.setOrigin({
|
|
3989
|
+
x: anchor.left,
|
|
3990
|
+
y: anchor.top,
|
|
3991
|
+
width: anchor.right - anchor.left,
|
|
3992
|
+
height: anchor.bottom - anchor.top,
|
|
3993
|
+
});
|
|
3994
|
+
if (!this._shown) {
|
|
3995
|
+
this._shown = true;
|
|
3996
|
+
pane.classList.remove(MLV_EDITOR_BUBBLE_HIDDEN_CLASS);
|
|
3997
|
+
this._unregister = this._overlays.register(pane, () => {
|
|
3998
|
+
// The registry drops the entry itself after calling this.
|
|
3999
|
+
this._unregister = null;
|
|
4000
|
+
this._hide();
|
|
4001
|
+
});
|
|
4002
|
+
}
|
|
4003
|
+
ref.updatePosition();
|
|
4004
|
+
}
|
|
4005
|
+
/** @private Takes the bubble off screen, handing focus back to the content first. */
|
|
4006
|
+
_hide() {
|
|
4007
|
+
const ref = this._overlayRef;
|
|
4008
|
+
if (!ref || !this._shown)
|
|
4009
|
+
return;
|
|
4010
|
+
this._shown = false;
|
|
4011
|
+
const pane = ref.overlayElement;
|
|
4012
|
+
if (pane.contains(this._document.activeElement))
|
|
4013
|
+
this._focusContent();
|
|
4014
|
+
pane.classList.add(MLV_EDITOR_BUBBLE_HIDDEN_CLASS);
|
|
4015
|
+
this._unregister?.();
|
|
4016
|
+
this._unregister = null;
|
|
4017
|
+
}
|
|
4018
|
+
/**
|
|
4019
|
+
* @private `readonly` just turned on. While the bubble is shown, every popup
|
|
4020
|
+
* the editor owns closes (their controls no longer apply, and the ones the
|
|
4021
|
+
* bubble opened would float beside a hidden pane), and focus in the bubble
|
|
4022
|
+
* or in such a popup returns to the content before either goes away. The
|
|
4023
|
+
* docked bar goes through the same registry call (#498).
|
|
4024
|
+
*/
|
|
4025
|
+
_closeForReadonly() {
|
|
4026
|
+
const ref = this._overlayRef;
|
|
4027
|
+
const editor = this._context.editor();
|
|
4028
|
+
if (!ref || !this._shown || !editor || editor.isDestroyed)
|
|
4029
|
+
return;
|
|
4030
|
+
this._overlays.closeForReadonly(ref.overlayElement, editor.view.dom, () => this._focusContent());
|
|
4031
|
+
this._sync();
|
|
4032
|
+
}
|
|
4033
|
+
/** @private Focuses the content with its selection, unless disabled. */
|
|
4034
|
+
_focusContent() {
|
|
4035
|
+
const editor = this._context.editor();
|
|
4036
|
+
if (!editor || editor.isDestroyed || this._context.disabled())
|
|
4037
|
+
return;
|
|
4038
|
+
mlvEditorFocusContent(editor);
|
|
4039
|
+
}
|
|
4040
|
+
/** @private The selection's client rect; a caret is zero-width. */
|
|
4041
|
+
_selectionRect(editor) {
|
|
4042
|
+
const { from, to } = editor.state.selection;
|
|
4043
|
+
try {
|
|
4044
|
+
const { top, bottom, left, right } = posToDOMRect(editor.view, from, to);
|
|
4045
|
+
return { top, bottom, left, right };
|
|
4046
|
+
}
|
|
4047
|
+
catch {
|
|
4048
|
+
// `coordsAtPos` throws where nothing is laid out; fall back to the
|
|
4049
|
+
// content's top edge.
|
|
4050
|
+
const rect = editor.view.dom.getBoundingClientRect();
|
|
4051
|
+
return {
|
|
4052
|
+
top: rect.top,
|
|
4053
|
+
bottom: rect.top,
|
|
4054
|
+
left: rect.left,
|
|
4055
|
+
right: rect.right,
|
|
4056
|
+
};
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
/** @private The window's client rect. */
|
|
4060
|
+
_windowRect() {
|
|
4061
|
+
const window = this._document.defaultView;
|
|
4062
|
+
return {
|
|
4063
|
+
top: 0,
|
|
4064
|
+
left: 0,
|
|
4065
|
+
bottom: window?.innerHeight ?? 0,
|
|
4066
|
+
right: window?.innerWidth ?? 0,
|
|
4067
|
+
};
|
|
4068
|
+
}
|
|
4069
|
+
/** @private Whether `target` is inside the ProseMirror content. */
|
|
4070
|
+
_inContent(target) {
|
|
4071
|
+
const dom = this._context.editor()?.view.dom;
|
|
4072
|
+
return !!dom && target instanceof Node && dom.contains(target);
|
|
4073
|
+
}
|
|
4074
|
+
/**
|
|
4075
|
+
* @private Runs `done` on the first emission of `end`, replacing any wait
|
|
4076
|
+
* of the same kind still open. Per gesture, so released here and at
|
|
4077
|
+
* destroy rather than by `takeUntilDestroyed`, which would keep every
|
|
4078
|
+
* earlier generation alive.
|
|
4079
|
+
*/
|
|
4080
|
+
_gesture(kind, end, done) {
|
|
4081
|
+
this._gestures[kind]?.unsubscribe();
|
|
4082
|
+
this._gestures[kind] = end.subscribe(() => {
|
|
4083
|
+
this._gestures[kind] = null;
|
|
4084
|
+
done();
|
|
4085
|
+
});
|
|
4086
|
+
}
|
|
4087
|
+
/** @private Schedules `_sync()` for the next render. */
|
|
4088
|
+
_invalidate() {
|
|
4089
|
+
this._tick.update((tick) => tick + 1);
|
|
4090
|
+
}
|
|
4091
|
+
/**
|
|
4092
|
+
* @private Scroll and resize only matter while the bubble is shown or could
|
|
4093
|
+
* show: summoned, or a non-empty selection that may scroll back into view.
|
|
4094
|
+
* A focused bare caret, and a disabled or `readonly` editor, skip the render
|
|
4095
|
+
* these events would schedule.
|
|
4096
|
+
*/
|
|
4097
|
+
_invalidateOnLayout() {
|
|
4098
|
+
if (this._shown) {
|
|
4099
|
+
this._invalidate();
|
|
4100
|
+
return;
|
|
4101
|
+
}
|
|
4102
|
+
if (!untracked(this._context.focused) ||
|
|
4103
|
+
untracked(this._context.disabled) ||
|
|
4104
|
+
untracked(this._context.readonly)) {
|
|
4105
|
+
return;
|
|
4106
|
+
}
|
|
4107
|
+
const editor = untracked(this._context.editor);
|
|
4108
|
+
if (this._summoned ||
|
|
4109
|
+
(editor && !editor.isDestroyed && !editor.state.selection.empty)) {
|
|
4110
|
+
this._invalidate();
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorBubble, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4114
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: MlvEditorBubble, isStandalone: true, selector: "ng-template[mlvEditorBubble]", inputs: { viewport: { classPropertyName: "viewport", publicName: "viewport", isSignal: true, isRequired: true, transformFunction: null }, capped: { classPropertyName: "capped", publicName: "capped", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
4115
|
+
}
|
|
4116
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorBubble, decorators: [{
|
|
4117
|
+
type: Directive,
|
|
4118
|
+
args: [{
|
|
4119
|
+
selector: 'ng-template[mlvEditorBubble]',
|
|
4120
|
+
}]
|
|
4121
|
+
}], ctorParameters: () => [], propDecorators: { viewport: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewport", required: true }] }], capped: [{ type: i0.Input, args: [{ isSignal: true, alias: "capped", required: false }] }] } });
|
|
4122
|
+
|
|
3241
4123
|
/** @internal Class of the floating drop indicator. */
|
|
3242
4124
|
const MLV_EDITOR_DROP_INDICATOR_CLASS = 'mlv-editor__drop-indicator';
|
|
3243
4125
|
/** @internal Class of the off-screen wrapper handed to `setDragImage`. */
|
|
3244
4126
|
const MLV_EDITOR_DRAG_GHOST_CLASS = 'mlv-editor__drag-ghost';
|
|
3245
4127
|
/**
|
|
3246
|
-
* @internal Marks the
|
|
3247
|
-
*
|
|
3248
|
-
*
|
|
4128
|
+
* @internal Marks the block currently on the cursor, dimmed in place. Applied
|
|
4129
|
+
* as a node decoration, never written onto the element — see
|
|
4130
|
+
* `MLV_EDITOR_DRAG_SOURCE_KEY`.
|
|
3249
4131
|
*/
|
|
3250
|
-
const MLV_EDITOR_DRAGGING_CLASS = 'ProseMirror--block-dragging';
|
|
3251
|
-
/** @internal Marks the block currently on the cursor, dimmed in place. */
|
|
3252
4132
|
const MLV_EDITOR_DRAG_SOURCE_CLASS = 'mlv-editor__block--dragging';
|
|
4133
|
+
/**
|
|
4134
|
+
* @internal Plugin state holding the dimmed source's node decoration: empty
|
|
4135
|
+
* while no block drag is in flight, one `Decoration.node` while one is.
|
|
4136
|
+
*
|
|
4137
|
+
* The dim has to travel through ProseMirror's own render path because nothing
|
|
4138
|
+
* written directly onto a block's element survives a drag. ProseMirror's
|
|
4139
|
+
* `DOMObserver` treats an attribute mutation on any node it rendered — a class,
|
|
4140
|
+
* an inline style — as an external DOM change, marks that node dirty and
|
|
4141
|
+
* redraws it, **replacing** the element. Measured in Chromium, 22 of 25
|
|
4142
|
+
* top-level elements were replaced by the first `dragover`: the dim class and
|
|
4143
|
+
* the old partition's transforms all ended up on detached nodes, so none of it
|
|
4144
|
+
* was ever visible. A decoration is part of the view description instead, so a
|
|
4145
|
+
* redraw re-applies it rather than discarding it.
|
|
4146
|
+
*/
|
|
4147
|
+
const MLV_EDITOR_DRAG_SOURCE_KEY = new PluginKey('mlvEditorBlockDragSource');
|
|
4148
|
+
/**
|
|
4149
|
+
* @internal Clears a source dim a freshly built plugin view inherited rather
|
|
4150
|
+
* than published.
|
|
4151
|
+
*
|
|
4152
|
+
* Plugin state outlives the plugin view. `EditorState.reconfigure` — what
|
|
4153
|
+
* Tiptap's `registerPlugin` / `unregisterPlugin` call, e.g. when an AI stream
|
|
4154
|
+
* or suggestion session settles — keeps every state field but destroys and
|
|
4155
|
+
* rebuilds every plugin view. A reconfigure mid-drag therefore takes the view
|
|
4156
|
+
* that owned the drag, and its `dragend` listener, while the dim stays in
|
|
4157
|
+
* state; the replacing view never saw the drag, so without this the block
|
|
4158
|
+
* would stay dimmed until the next document change.
|
|
4159
|
+
*
|
|
4160
|
+
* Deferred to a microtask because this runs from the view factory, inside
|
|
4161
|
+
* ProseMirror's `updatePluginViews`, where a dispatch would re-enter
|
|
4162
|
+
* `updateState` while the views are still being built. The old view's
|
|
4163
|
+
* `destroy` cannot clear it either: it runs inside that same update, or inside
|
|
4164
|
+
* `EditorView.destroy()` before `isDestroyed` turns true. Every other teardown
|
|
4165
|
+
* discards the state (a destroyed editor) or the field (the plugin removed)
|
|
4166
|
+
* along with the dim. The clear only drops the exact set inherited, so it can
|
|
4167
|
+
* never undo a newer drag's dim.
|
|
4168
|
+
*/
|
|
4169
|
+
function clearInheritedDragSource(view) {
|
|
4170
|
+
const inherited = MLV_EDITOR_DRAG_SOURCE_KEY.getState(view.state);
|
|
4171
|
+
if (inherited === undefined || inherited === DecorationSet.empty)
|
|
4172
|
+
return;
|
|
4173
|
+
queueMicrotask(() => {
|
|
4174
|
+
if (view.isDestroyed)
|
|
4175
|
+
return;
|
|
4176
|
+
if (MLV_EDITOR_DRAG_SOURCE_KEY.getState(view.state) !== inherited)
|
|
4177
|
+
return;
|
|
4178
|
+
view.dispatch(view.state.tr.setMeta(MLV_EDITOR_DRAG_SOURCE_KEY, DecorationSet.empty));
|
|
4179
|
+
});
|
|
4180
|
+
}
|
|
3253
4181
|
/** @internal Duration of the post-drop settle, matching `--mlv-duration-normal`. */
|
|
3254
4182
|
const MLV_EDITOR_SETTLE_DURATION = 200;
|
|
3255
4183
|
/** @internal Sub-pixel movement not worth animating after a drop. */
|
|
@@ -3470,19 +4398,20 @@ function dropTargetIndex(hit, clientY, from) {
|
|
|
3470
4398
|
/**
|
|
3471
4399
|
* @internal Measures every top-level block once, in the mount's unscaled space.
|
|
3472
4400
|
*
|
|
3473
|
-
* Taken at `dragstart` and read by everything downstream
|
|
3474
|
-
*
|
|
3475
|
-
*
|
|
3476
|
-
*
|
|
3477
|
-
*
|
|
3478
|
-
* the
|
|
3479
|
-
*
|
|
4401
|
+
* Taken at `dragstart` and read by everything downstream — target resolution,
|
|
4402
|
+
* the indicator's `top` and the settle's "before" — so no pointer event during
|
|
4403
|
+
* the drag reads a block's rect. Mount-relative rather than viewport-relative
|
|
4404
|
+
* so drag-autoscroll cannot invalidate it: only the mount's own rect is re-read
|
|
4405
|
+
* per event, one layout read instead of one per block. Unscaled for the same
|
|
4406
|
+
* reason the handle's `top` is: a CSS length on a child of the zoom layer
|
|
4407
|
+
* applies in that layer's space, while `getBoundingClientRect()` reports scaled
|
|
4408
|
+
* screen pixels.
|
|
3480
4409
|
*
|
|
3481
|
-
*
|
|
3482
|
-
*
|
|
3483
|
-
*
|
|
3484
|
-
*
|
|
3485
|
-
*
|
|
4410
|
+
* Boxes only, deliberately **no element**. ProseMirror replaces top-level
|
|
4411
|
+
* elements during a drag (see `MLV_EDITOR_DRAG_SOURCE_KEY`), so an element
|
|
4412
|
+
* captured here is detached by the first `dragover`, and anything written to it
|
|
4413
|
+
* afterwards is written to nothing. Everything after `dragstart` that needs a
|
|
4414
|
+
* live element resolves it from a document position instead.
|
|
3486
4415
|
*/
|
|
3487
4416
|
function snapshotBlocks(view, mount) {
|
|
3488
4417
|
const { top: mountTop, scale } = mountFrame(mount);
|
|
@@ -3491,10 +4420,10 @@ function snapshotBlocks(view, mount) {
|
|
|
3491
4420
|
for (let i = 0; i < children.length; i += 1) {
|
|
3492
4421
|
const element = children[i];
|
|
3493
4422
|
// Same category check the hover path uses: a widget decoration owns no
|
|
3494
|
-
// top-level node and must not occupy a slot, or
|
|
3495
|
-
//
|
|
4423
|
+
// top-level node and must not occupy a slot, or its sliver of a box would
|
|
4424
|
+
// decide a neighbour's drop side. Mapping every child once here is what the
|
|
3496
4425
|
// drag pays instead of the hover path's deferred single mapping — the
|
|
3497
|
-
//
|
|
4426
|
+
// settle needs a box per block regardless.
|
|
3498
4427
|
const index = topLevelIndexOfDom(view, element);
|
|
3499
4428
|
if (index === null)
|
|
3500
4429
|
continue;
|
|
@@ -3503,7 +4432,6 @@ function snapshotBlocks(view, mount) {
|
|
|
3503
4432
|
index,
|
|
3504
4433
|
top: (rect.top - mountTop) / scale,
|
|
3505
4434
|
bottom: (rect.bottom - mountTop) / scale,
|
|
3506
|
-
element: element,
|
|
3507
4435
|
});
|
|
3508
4436
|
}
|
|
3509
4437
|
return slots;
|
|
@@ -3541,9 +4469,12 @@ function slotAt(slots, y) {
|
|
|
3541
4469
|
* @internal Mount-space y of the boundary the given gap sits on, where `gap`
|
|
3542
4470
|
* counts the `slots.length + 1` positions a block can be inserted at.
|
|
3543
4471
|
*
|
|
3544
|
-
*
|
|
3545
|
-
*
|
|
3546
|
-
*
|
|
4472
|
+
* An interior gap is the middle of the **natural** space between two blocks —
|
|
4473
|
+
* the midpoint of the previous block's bottom and the next block's top — since
|
|
4474
|
+
* nothing parts the blocks to preview a drop. The outer two sit on the first
|
|
4475
|
+
* block's top and the last block's bottom. The stylesheet centres the line on
|
|
4476
|
+
* this y (`translateY(-50%)`), so its own thickness never has to be resolved
|
|
4477
|
+
* here.
|
|
3547
4478
|
*/
|
|
3548
4479
|
function gapOffset(slots, gap) {
|
|
3549
4480
|
if (gap <= 0)
|
|
@@ -3561,9 +4492,9 @@ function gapOffset(slots, gap) {
|
|
|
3561
4492
|
* an ancestor class chain that would have to track whichever selectors happen
|
|
3562
4493
|
* to exist. Adapted from `@tiptap/extension-drag-handle`'s `cloneElement`.
|
|
3563
4494
|
*
|
|
3564
|
-
* Note what this cannot carry: computed styles are
|
|
3565
|
-
*
|
|
3566
|
-
*
|
|
4495
|
+
* Note what this cannot carry: computed styles are the element's own values
|
|
4496
|
+
* and never carry an ancestor's `zoom`. The editor's zoom is applied to the
|
|
4497
|
+
* wrapper instead — see `createGhostElement`.
|
|
3567
4498
|
*/
|
|
3568
4499
|
function cloneWithComputedStyles(source) {
|
|
3569
4500
|
const clone = source.cloneNode(true);
|
|
@@ -3598,7 +4529,8 @@ function cloneWithComputedStyles(source) {
|
|
|
3598
4529
|
* requires — without ever being seen. `zoom` rather than `transform` carries
|
|
3599
4530
|
* the editor's scale because it affects layout, so the wrapper's own box
|
|
3600
4531
|
* reflects it before the browser rasterizes; a `transform` is honoured
|
|
3601
|
-
* inconsistently across engines for drag images
|
|
4532
|
+
* inconsistently across engines for drag images, and the source's computed
|
|
4533
|
+
* styles carry no ancestor `zoom`.
|
|
3602
4534
|
*/
|
|
3603
4535
|
function createGhostElement(source, scale) {
|
|
3604
4536
|
const wrapper = document.createElement('div');
|
|
@@ -3744,7 +4676,26 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
3744
4676
|
const editor = this.editor;
|
|
3745
4677
|
return [
|
|
3746
4678
|
new Plugin({
|
|
4679
|
+
key: MLV_EDITOR_DRAG_SOURCE_KEY,
|
|
4680
|
+
state: {
|
|
4681
|
+
init: () => DecorationSet.empty,
|
|
4682
|
+
// Set and cleared only through a meta, from the plugin view (and
|
|
4683
|
+
// `clearInheritedDragSource`). A document change also ends the
|
|
4684
|
+
// drag (see `update` below), so the decoration is dropped in that
|
|
4685
|
+
// same transaction rather than mapped onto a block that may no
|
|
4686
|
+
// longer be the one on the pointer. That transaction therefore
|
|
4687
|
+
// never renders a set built against the previous document, and
|
|
4688
|
+
// `update`'s `endDrag` finds nothing left to dispatch.
|
|
4689
|
+
apply: (tr, decorations) => tr.getMeta(MLV_EDITOR_DRAG_SOURCE_KEY) ??
|
|
4690
|
+
(tr.docChanged ? DecorationSet.empty : decorations),
|
|
4691
|
+
},
|
|
4692
|
+
props: {
|
|
4693
|
+
decorations: (state) => MLV_EDITOR_DRAG_SOURCE_KEY.getState(state),
|
|
4694
|
+
},
|
|
3747
4695
|
view: (view) => {
|
|
4696
|
+
// First, before the mount check: a rebuilt view with no mount
|
|
4697
|
+
// still inherits whatever dim its predecessor left in state.
|
|
4698
|
+
clearInheritedDragSource(view);
|
|
3748
4699
|
const mount = options.mount();
|
|
3749
4700
|
if (!mount)
|
|
3750
4701
|
return { destroy: () => undefined };
|
|
@@ -3789,9 +4740,9 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
3789
4740
|
const hit = blockAtPoint(view, event.clientY);
|
|
3790
4741
|
if (!hit)
|
|
3791
4742
|
return hide();
|
|
3792
|
-
// `getBoundingClientRect()` reports
|
|
3793
|
-
// CSS `top` on a child of the
|
|
3794
|
-
// layer's own
|
|
4743
|
+
// `getBoundingClientRect()` reports zoomed screen pixels, but a
|
|
4744
|
+
// CSS `top` on a child of the zoomed layer is applied in the
|
|
4745
|
+
// layer's own unzoomed space. Convert once, off one rect read of
|
|
3795
4746
|
// the mount.
|
|
3796
4747
|
const { top: mountTop, scale } = mountFrame(mount);
|
|
3797
4748
|
const top = `${(hit.top - mountTop) / scale}px`;
|
|
@@ -3811,13 +4762,11 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
3811
4762
|
};
|
|
3812
4763
|
/** Top-level index being dragged, or null when no drag is active. */
|
|
3813
4764
|
let source = null;
|
|
3814
|
-
/** The dimmed element the drag started from. */
|
|
3815
|
-
let sourceElement = null;
|
|
3816
4765
|
/** Geometry measured once at `dragstart`; empty while no drag runs. */
|
|
3817
4766
|
let slots = [];
|
|
3818
4767
|
/** The off-screen element handed to `setDragImage`. */
|
|
3819
4768
|
let ghost = null;
|
|
3820
|
-
/** Gap the
|
|
4769
|
+
/** Gap the indicator currently marks, or null while it is retracted. */
|
|
3821
4770
|
let gap = null;
|
|
3822
4771
|
/**
|
|
3823
4772
|
* Converts a viewport y into the mount's own unscaled space, off
|
|
@@ -3831,45 +4780,61 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
3831
4780
|
* Gap a resolved target index sits on. `dropTargetIndex` folds the
|
|
3832
4781
|
* `slots.length + 1` gaps onto `moveBlock`'s pre-move convention,
|
|
3833
4782
|
* where `to` names the block the moved one ends up after when
|
|
3834
|
-
* moving down; this is that fold inverted, so the previewed
|
|
4783
|
+
* moving down; this is that fold inverted, so the previewed line
|
|
3835
4784
|
* and the committed move come from one resolved index.
|
|
3836
4785
|
*/
|
|
3837
4786
|
const gapForTarget = (to, from) => to <= from ? to : to + 1;
|
|
3838
|
-
/**
|
|
4787
|
+
/**
|
|
4788
|
+
* Moves the indicator to `next`, or retracts it when null. Only
|
|
4789
|
+
* the mount-owned line is written: nothing parts the blocks, so no
|
|
4790
|
+
* element ProseMirror rendered is touched during a drag.
|
|
4791
|
+
*/
|
|
3839
4792
|
const setGap = (next) => {
|
|
3840
4793
|
if (gap === next)
|
|
3841
4794
|
return;
|
|
3842
4795
|
gap = next;
|
|
3843
|
-
for (const slot of slots) {
|
|
3844
|
-
// The gap is a token rather than a number here, so the size
|
|
3845
|
-
// stays owned by the stylesheet.
|
|
3846
|
-
slot.element.style.transform =
|
|
3847
|
-
next !== null && slot.index >= next
|
|
3848
|
-
? 'translateY(var(--mlv-editor-drop-gap))'
|
|
3849
|
-
: '';
|
|
3850
|
-
}
|
|
3851
4796
|
if (next === null) {
|
|
3852
4797
|
indicator.setAttribute('data-visible', 'false');
|
|
3853
4798
|
return;
|
|
3854
4799
|
}
|
|
3855
|
-
// The *pre-partition* boundary: the stylesheet offsets the line
|
|
3856
|
-
// into the opened space by half the gap, so this never has to
|
|
3857
|
-
// resolve the token into pixels.
|
|
3858
4800
|
indicator.style.top = `${gapOffset(slots, next)}px`;
|
|
3859
4801
|
indicator.setAttribute('data-visible', 'true');
|
|
3860
4802
|
};
|
|
4803
|
+
/**
|
|
4804
|
+
* Publishes the source's dim, or clears it with `null`, through
|
|
4805
|
+
* plugin state. Skipped when nothing would change, so the several
|
|
4806
|
+
* paths that end one drag (`drop`, then `dragend`) dispatch once.
|
|
4807
|
+
*/
|
|
4808
|
+
const setSourceDecoration = (from) => {
|
|
4809
|
+
const current = MLV_EDITOR_DRAG_SOURCE_KEY.getState(view.state);
|
|
4810
|
+
if (from === null && current === DecorationSet.empty)
|
|
4811
|
+
return;
|
|
4812
|
+
const node = from === null ? null : view.state.doc.nodeAt(from);
|
|
4813
|
+
const next = from === null || node === null
|
|
4814
|
+
? DecorationSet.empty
|
|
4815
|
+
: DecorationSet.create(view.state.doc, [
|
|
4816
|
+
Decoration.node(from, from + node.nodeSize, {
|
|
4817
|
+
class: MLV_EDITOR_DRAG_SOURCE_CLASS,
|
|
4818
|
+
}),
|
|
4819
|
+
]);
|
|
4820
|
+
// A meta-only transaction: no step, so nothing for history to
|
|
4821
|
+
// record (prosemirror-history returns its state unchanged for a
|
|
4822
|
+
// step-less transaction, so no `addToHistory` flag is needed)
|
|
4823
|
+
// and no model emission. `update` below compares documents by
|
|
4824
|
+
// identity, so this does not read as a document change and end
|
|
4825
|
+
// the drag.
|
|
4826
|
+
view.dispatch(view.state.tr.setMeta(MLV_EDITOR_DRAG_SOURCE_KEY, next));
|
|
4827
|
+
};
|
|
3861
4828
|
const endDrag = () => {
|
|
3862
|
-
for (const slot of slots)
|
|
3863
|
-
slot.element.style.transform = '';
|
|
3864
4829
|
indicator.setAttribute('data-visible', 'false');
|
|
3865
|
-
view.dom.classList.remove(MLV_EDITOR_DRAGGING_CLASS);
|
|
3866
|
-
sourceElement?.classList.remove(MLV_EDITOR_DRAG_SOURCE_CLASS);
|
|
3867
4830
|
ghost?.remove();
|
|
3868
4831
|
slots = [];
|
|
3869
4832
|
gap = null;
|
|
3870
4833
|
source = null;
|
|
3871
|
-
sourceElement = null;
|
|
3872
4834
|
ghost = null;
|
|
4835
|
+
// Last, once the closure no longer records a drag: the dispatch
|
|
4836
|
+
// re-enters `update`, which must not see one still in flight.
|
|
4837
|
+
setSourceDecoration(null);
|
|
3873
4838
|
};
|
|
3874
4839
|
/** Target index for the pointer, or null when the drop is a no-op. */
|
|
3875
4840
|
const targetAt = (clientY) => {
|
|
@@ -3894,11 +4859,15 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
3894
4859
|
*
|
|
3895
4860
|
* Only the span between the two indices moved, so the walk is
|
|
3896
4861
|
* bounded by the distance dragged rather than by document length.
|
|
4862
|
+
* Each element is resolved live through `nodeDOM` after the move,
|
|
4863
|
+
* never taken from the snapshot: ProseMirror has replaced most of
|
|
4864
|
+
* the elements measured at `dragstart` by now.
|
|
3897
4865
|
*
|
|
3898
|
-
* Uses the Web Animations API rather than a transition
|
|
3899
|
-
* to force a reflow between setting and
|
|
3900
|
-
* animation cleans itself up, and it
|
|
3901
|
-
*
|
|
4866
|
+
* Uses the Web Animations API rather than a transition or an inline
|
|
4867
|
+
* `transform`: nothing has to force a reflow between setting and
|
|
4868
|
+
* clearing the offset, the animation cleans itself up, and it
|
|
4869
|
+
* writes no attribute — an inline style is a DOM mutation
|
|
4870
|
+
* ProseMirror would answer by redrawing the block mid-animation.
|
|
3902
4871
|
*/
|
|
3903
4872
|
const settle = (tops, from, to) => {
|
|
3904
4873
|
if (prefersReducedMotion())
|
|
@@ -3945,11 +4914,18 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
3945
4914
|
return;
|
|
3946
4915
|
}
|
|
3947
4916
|
const measured = snapshotBlocks(view, mount);
|
|
3948
|
-
const
|
|
4917
|
+
const from = index < view.state.doc.childCount
|
|
4918
|
+
? childStart(view.state.doc, index)
|
|
4919
|
+
: null;
|
|
4920
|
+
// Resolved now, from the document position, and used only in
|
|
4921
|
+
// this handler — see `snapshotBlocks` for why no element is kept.
|
|
4922
|
+
const element = from === null ? null : view.nodeDOM(from);
|
|
3949
4923
|
// The hovered index outliving its block means the snapshot and
|
|
3950
4924
|
// `data-index` disagree; refusing is the same answer as a drag
|
|
3951
4925
|
// that never hovered.
|
|
3952
|
-
if (
|
|
4926
|
+
if (from === null ||
|
|
4927
|
+
!(element instanceof HTMLElement) ||
|
|
4928
|
+
!measured.some((candidate) => candidate.index === index)) {
|
|
3953
4929
|
event.preventDefault();
|
|
3954
4930
|
return;
|
|
3955
4931
|
}
|
|
@@ -3970,13 +4946,17 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
3970
4946
|
// Cloned *before* the source is dimmed: the clone carries
|
|
3971
4947
|
// resolved computed styles, so dimming first would bake the
|
|
3972
4948
|
// reduced opacity into the drag image.
|
|
3973
|
-
ghost = createGhostElement(
|
|
4949
|
+
ghost = createGhostElement(element, mountFrame(mount).scale);
|
|
4950
|
+
// The pointer rides the image's inline-start edge: its right
|
|
4951
|
+
// edge in RTL. The offset is in CSS pixels against the image as
|
|
4952
|
+
// painted, and the wrapper carries the editor zoom as CSS
|
|
4953
|
+
// `zoom`, which `offsetWidth` leaves out (measured 475 against
|
|
4954
|
+
// 594 at 125%): only the rendered width puts the pointer on
|
|
4955
|
+
// that edge.
|
|
3974
4956
|
event.dataTransfer?.setDragImage(ghost, getComputedStyle(view.dom).direction === 'rtl'
|
|
3975
|
-
? ghost.
|
|
4957
|
+
? Math.round(ghost.getBoundingClientRect().width)
|
|
3976
4958
|
: 0, 0);
|
|
3977
|
-
|
|
3978
|
-
sourceElement.classList.add(MLV_EDITOR_DRAG_SOURCE_CLASS);
|
|
3979
|
-
view.dom.classList.add(MLV_EDITOR_DRAGGING_CLASS);
|
|
4959
|
+
setSourceDecoration(from);
|
|
3980
4960
|
};
|
|
3981
4961
|
const onDragOver = (event) => {
|
|
3982
4962
|
if (source === null)
|
|
@@ -4014,8 +4994,8 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
4014
4994
|
event.clientY > rect.bottom);
|
|
4015
4995
|
};
|
|
4016
4996
|
const onDragLeave = (event) => {
|
|
4017
|
-
// Only the
|
|
4018
|
-
//
|
|
4997
|
+
// Only the line retracts; the source stays dimmed. The drag
|
|
4998
|
+
// itself is still in flight, and re-entering
|
|
4019
4999
|
// the editor must resolve a target again rather than leave the
|
|
4020
5000
|
// user dragging something that can no longer be dropped.
|
|
4021
5001
|
if (source !== null && leavesMount(event))
|
|
@@ -4030,10 +5010,9 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
4030
5010
|
// Resolved from the drop's own coordinates rather than the last
|
|
4031
5011
|
// `dragover`, so the release position always wins.
|
|
4032
5012
|
const to = targetAt(event.clientY);
|
|
4033
|
-
// Captured before `endDrag` discards the snapshot.
|
|
4034
|
-
//
|
|
4035
|
-
//
|
|
4036
|
-
// turn, so nothing the user saw shifted is measured as movement.
|
|
5013
|
+
// Captured before `endDrag` discards the snapshot. Nothing moves
|
|
5014
|
+
// a block during the drag, so the `dragstart` tops are exactly
|
|
5015
|
+
// the FLIP's "before".
|
|
4037
5016
|
const tops = slots.map((slot) => slot.top);
|
|
4038
5017
|
endDrag();
|
|
4039
5018
|
if (to === null)
|
|
@@ -4045,6 +5024,27 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
4045
5024
|
if (event.key === 'Escape' && source !== null)
|
|
4046
5025
|
endDrag();
|
|
4047
5026
|
};
|
|
5027
|
+
// These eight stay raw `addEventListener`s rather than becoming
|
|
5028
|
+
// `fromEvent` + `takeUntilDestroyed`, deliberately and for two
|
|
5029
|
+
// reasons.
|
|
5030
|
+
//
|
|
5031
|
+
// There is no `DestroyRef` to take. This file is a plain
|
|
5032
|
+
// ProseMirror plugin with no Angular import at all, constructed by
|
|
5033
|
+
// Tiptap outside any injection context, so `inject()` would throw.
|
|
5034
|
+
// The lifetime that matters here is not the editor component's
|
|
5035
|
+
// either: it is this plugin *view's*, which is torn down and
|
|
5036
|
+
// rebuilt whenever the editor is recreated (a format switch, an
|
|
5037
|
+
// extension-set change). `destroy()` below is that boundary, and it
|
|
5038
|
+
// unbinds all eight with the capture flags they were bound with.
|
|
5039
|
+
//
|
|
5040
|
+
// And the three capture-phase drag listeners are protocol-sensitive.
|
|
5041
|
+
// ProseMirror installs its own `dragover`/`drop` handlers on
|
|
5042
|
+
// `view.dom`, a descendant of `mount`; capturing on the ancestor is
|
|
5043
|
+
// what lets `onDrop` claim the drop and `stopPropagation()` before
|
|
5044
|
+
// ProseMirror inserts the dragged slice itself. Nothing in the unit
|
|
5045
|
+
// suite can drive a native HTML5 drag, so that ordering cannot be
|
|
5046
|
+
// pinned by a test here — and an unprovable reordering of block
|
|
5047
|
+
// drag-and-drop is not worth a stylistic conversion.
|
|
4048
5048
|
mount.addEventListener('mousemove', onMouseMove);
|
|
4049
5049
|
mount.addEventListener('mouseleave', hide);
|
|
4050
5050
|
handle.addEventListener('dragstart', onDragStart);
|
|
@@ -4081,6 +5081,8 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
4081
5081
|
// selection-only transaction carries the same reference — so
|
|
4082
5082
|
// this is exactly `docChanged` at O(1), where a structural
|
|
4083
5083
|
// compare would walk the whole document on every keystroke.
|
|
5084
|
+
// The same change has already emptied the source decoration in
|
|
5085
|
+
// plugin state (`apply`), so this `endDrag` dispatches nothing.
|
|
4084
5086
|
if (previous.doc !== updated.state.doc && source !== null) {
|
|
4085
5087
|
endDrag();
|
|
4086
5088
|
}
|
|
@@ -4091,7 +5093,9 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
4091
5093
|
// releasing the button after the revocation cannot reorder
|
|
4092
5094
|
// anything. Previously the line went through `decorations`,
|
|
4093
5095
|
// which read `enabled()` itself; a mount-owned element has to
|
|
4094
|
-
// be told.
|
|
5096
|
+
// be told. Clearing the dim dispatches from inside `update`;
|
|
5097
|
+
// that re-entry finds no drag recorded and returns, so it runs
|
|
5098
|
+
// once.
|
|
4095
5099
|
if (source !== null)
|
|
4096
5100
|
endDrag();
|
|
4097
5101
|
},
|
|
@@ -4109,6 +5113,8 @@ const MlvEditorBlockHandle = Extension.create({
|
|
|
4109
5113
|
// A drag interrupted by teardown leaves its drag image on
|
|
4110
5114
|
// `document.body`, outside everything else this removes.
|
|
4111
5115
|
ghost?.remove();
|
|
5116
|
+
// The dim stays in plugin state, where this cannot dispatch;
|
|
5117
|
+
// see `clearInheritedDragSource`.
|
|
4112
5118
|
},
|
|
4113
5119
|
};
|
|
4114
5120
|
},
|
|
@@ -5055,8 +6061,16 @@ class EditorImageUploadCoordinator extends MlvEditorImageUploadControl {
|
|
|
5055
6061
|
catch {
|
|
5056
6062
|
return undefined;
|
|
5057
6063
|
}
|
|
5058
|
-
|
|
5059
|
-
|
|
6064
|
+
// The author's metadata states intent and wins; the adapter's only fills
|
|
6065
|
+
// what the author left out. An author `alt: ''` marks the image
|
|
6066
|
+
// decorative: the alt stays empty (WCAG 1.1.1) and no title is kept,
|
|
6067
|
+
// the author's or the adapter's, because an `alt=""` image with a title
|
|
6068
|
+
// is exposed as an unnamed image described by it (WCAG H67). Otherwise
|
|
6069
|
+
// an empty author title means no title, so the adapter's may fill it.
|
|
6070
|
+
const adapterAlt = typeof value['alt'] === 'string' ? value['alt'] : undefined;
|
|
6071
|
+
const adapterTitle = typeof value['title'] === 'string' ? value['title'] : undefined;
|
|
6072
|
+
const alt = state.alt ?? adapterAlt;
|
|
6073
|
+
const title = state.alt === '' ? undefined : state.title || adapterTitle;
|
|
5060
6074
|
return {
|
|
5061
6075
|
src,
|
|
5062
6076
|
...(alt === undefined ? {} : { alt }),
|
|
@@ -5317,8 +6331,8 @@ class MlvEditorAlignment {
|
|
|
5317
6331
|
this._unregister?.();
|
|
5318
6332
|
this._unregister = undefined;
|
|
5319
6333
|
}
|
|
5320
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
5321
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
6334
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAlignment, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6335
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorAlignment, isStandalone: true, selector: "mlv-editor-alignment", host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-alignment" }, viewQueries: [{ propertyName: "_menu", first: true, predicate: ["_menu"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: MlvMenuTrigger, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
5322
6336
|
<button
|
|
5323
6337
|
mlvButton
|
|
5324
6338
|
mlvEditorToolbarWidget
|
|
@@ -5350,7 +6364,7 @@ class MlvEditorAlignment {
|
|
|
5350
6364
|
</mlv-menu>
|
|
5351
6365
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideAlignLeft, selector: "svg[lucideTextAlignStart], svg[lucideText], svg[lucideAlignLeft]" }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5352
6366
|
}
|
|
5353
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
6367
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorAlignment, decorators: [{
|
|
5354
6368
|
type: Component,
|
|
5355
6369
|
args: [{
|
|
5356
6370
|
selector: 'mlv-editor-alignment',
|
|
@@ -5460,8 +6474,8 @@ class MlvEditorCommandButton {
|
|
|
5460
6474
|
return;
|
|
5461
6475
|
this._context.run(this.command());
|
|
5462
6476
|
}
|
|
5463
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
5464
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.
|
|
6477
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorCommandButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6478
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: MlvEditorCommandButton, isStandalone: true, selector: "mlv-editor-command-button", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, supports: { classPropertyName: "supports", publicName: "supports", isSignal: true, isRequired: true, transformFunction: null }, command: { classPropertyName: "command", publicName: "command", isSignal: true, isRequired: true, transformFunction: null }, canCommand: { classPropertyName: "canCommand", publicName: "canCommand", isSignal: true, isRequired: false, transformFunction: null }, pressed: { classPropertyName: "pressed", publicName: "pressed", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "hidden": "!supported()" }, classAttribute: "mlv-editor-command-button" }, ngImport: i0, template: `
|
|
5465
6479
|
<button
|
|
5466
6480
|
mlvButton
|
|
5467
6481
|
mlvEditorToolbarWidget
|
|
@@ -5481,7 +6495,7 @@ class MlvEditorCommandButton {
|
|
|
5481
6495
|
</button>
|
|
5482
6496
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5483
6497
|
}
|
|
5484
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
6498
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorCommandButton, decorators: [{
|
|
5485
6499
|
type: Component,
|
|
5486
6500
|
args: [{
|
|
5487
6501
|
selector: 'mlv-editor-command-button',
|
|
@@ -5539,8 +6553,8 @@ class MlvEditorBlockInsert {
|
|
|
5539
6553
|
this._revision();
|
|
5540
6554
|
return this._context.isActive(name);
|
|
5541
6555
|
};
|
|
5542
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
5543
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.
|
|
6556
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorBlockInsert, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6557
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorBlockInsert, isStandalone: true, selector: "mlv-editor-block-insert", host: { attributes: { "role": "group" }, classAttribute: "mlv-editor-block-insert" }, ngImport: i0, template: `
|
|
5544
6558
|
<mlv-editor-command-button
|
|
5545
6559
|
[label]="_copy().blockquote"
|
|
5546
6560
|
[pressed]="_isActive('blockquote')"
|
|
@@ -5566,7 +6580,7 @@ class MlvEditorBlockInsert {
|
|
|
5566
6580
|
/></mlv-editor-command-button>
|
|
5567
6581
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvEditorCommandButton, selector: "mlv-editor-command-button", inputs: ["label", "supports", "command", "canCommand", "pressed"] }, { kind: "component", type: LucideCode2, selector: "svg[lucideCodeXml], svg[lucideCode2]" }, { kind: "component", type: LucideMinus, selector: "svg[lucideMinus]" }, { kind: "component", type: LucideTextQuote, selector: "svg[lucideTextQuote]" }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5568
6582
|
}
|
|
5569
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
6583
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorBlockInsert, decorators: [{
|
|
5570
6584
|
type: Component,
|
|
5571
6585
|
args: [{
|
|
5572
6586
|
selector: 'mlv-editor-block-insert',
|
|
@@ -5763,8 +6777,8 @@ class MlvEditorHeading {
|
|
|
5763
6777
|
this._unregister?.();
|
|
5764
6778
|
this._unregister = undefined;
|
|
5765
6779
|
}
|
|
5766
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
5767
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
6780
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorHeading, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6781
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorHeading, isStandalone: true, selector: "mlv-editor-heading", inputs: { levels: { classPropertyName: "levels", publicName: "levels", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-heading" }, viewQueries: [{ propertyName: "_menu", first: true, predicate: ["_menu"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: MlvMenuTrigger, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
5768
6782
|
<button
|
|
5769
6783
|
mlvButton
|
|
5770
6784
|
mlvEditorToolbarWidget
|
|
@@ -5833,7 +6847,7 @@ class MlvEditorHeading {
|
|
|
5833
6847
|
</mlv-menu>
|
|
5834
6848
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideHeading, selector: "svg[lucideHeading]" }, { kind: "component", type: LucideHeading1, selector: "svg[lucideHeading1]" }, { kind: "component", type: LucideHeading2, selector: "svg[lucideHeading2]" }, { kind: "component", type: LucideHeading3, selector: "svg[lucideHeading3]" }, { kind: "component", type: LucideHeading4, selector: "svg[lucideHeading4]" }, { kind: "component", type: LucideHeading5, selector: "svg[lucideHeading5]" }, { kind: "component", type: LucideHeading6, selector: "svg[lucideHeading6]" }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5835
6849
|
}
|
|
5836
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
6850
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorHeading, decorators: [{
|
|
5837
6851
|
type: Component,
|
|
5838
6852
|
args: [{
|
|
5839
6853
|
selector: 'mlv-editor-heading',
|
|
@@ -5953,14 +6967,18 @@ class MlvEditorColorControl {
|
|
|
5953
6967
|
const trigger = this._picker().triggerElement();
|
|
5954
6968
|
if (!trigger)
|
|
5955
6969
|
return;
|
|
6970
|
+
// Released from `onCleanup`, not `takeUntilDestroyed`: this effect
|
|
6971
|
+
// re-runs whenever the picker publishes a different trigger element, and
|
|
6972
|
+
// a destroy-scoped teardown would leave every superseded generation
|
|
6973
|
+
// subscribed for the rest of the control's life.
|
|
6974
|
+
const listeners = new Subscription();
|
|
5956
6975
|
const activate = () => this._roving.activate(trigger);
|
|
5957
|
-
|
|
5958
|
-
|
|
6976
|
+
listeners.add(fromEvent(trigger, 'focus').subscribe(activate));
|
|
6977
|
+
listeners.add(fromEvent(trigger, 'pointerdown').subscribe(activate));
|
|
5959
6978
|
const unregister = untracked(() => this._roving.register(trigger));
|
|
5960
6979
|
onCleanup(() => {
|
|
5961
6980
|
unregister();
|
|
5962
|
-
|
|
5963
|
-
trigger.removeEventListener('pointerdown', activate);
|
|
6981
|
+
listeners.unsubscribe();
|
|
5964
6982
|
});
|
|
5965
6983
|
});
|
|
5966
6984
|
effect(() => {
|
|
@@ -5992,10 +7010,10 @@ class MlvEditorColorControl {
|
|
|
5992
7010
|
return;
|
|
5993
7011
|
this._context.run((editor) => this._run(editor, selection, color));
|
|
5994
7012
|
}
|
|
5995
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
5996
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.
|
|
7013
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorColorControl, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7014
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.1.7", type: MlvEditorColorControl, isStandalone: true, viewQueries: [{ propertyName: "_picker", first: true, predicate: ["picker"], descendants: true, isSignal: true }], ngImport: i0 });
|
|
5997
7015
|
}
|
|
5998
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
7016
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorColorControl, decorators: [{
|
|
5999
7017
|
type: Directive
|
|
6000
7018
|
}], ctorParameters: () => [], propDecorators: { _picker: [{ type: i0.ViewChild, args: ['picker', { isSignal: true }] }] } });
|
|
6001
7019
|
|
|
@@ -6028,8 +7046,8 @@ class MlvEditorHighlight extends MlvEditorColorControl {
|
|
|
6028
7046
|
? chain.toggleHighlight({ color }).run()
|
|
6029
7047
|
: chain.unsetHighlight().run();
|
|
6030
7048
|
}
|
|
6031
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
6032
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.
|
|
7049
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorHighlight, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
7050
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorHighlight, isStandalone: true, selector: "mlv-editor-highlight", host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-highlight" }, usesInheritance: true, ngImport: i0, template: `
|
|
6033
7051
|
<mlv-color-picker-popup
|
|
6034
7052
|
#picker
|
|
6035
7053
|
presentation="icon"
|
|
@@ -6046,7 +7064,7 @@ class MlvEditorHighlight extends MlvEditorColorControl {
|
|
|
6046
7064
|
</mlv-color-picker-popup>
|
|
6047
7065
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvColorPickerPopup, selector: "mlv-color-picker-popup", inputs: ["value", "presentation", "opened", "showOpacity", "defaultMode", "supportedFormats", "live"], outputs: ["valueChange", "openedChange", "afterOpened", "afterClosed", "colorChange"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "component", type: LucideHighlighter, selector: "svg[lucideHighlighter]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6048
7066
|
}
|
|
6049
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
7067
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorHighlight, decorators: [{
|
|
6050
7068
|
type: Component,
|
|
6051
7069
|
args: [{
|
|
6052
7070
|
selector: 'mlv-editor-highlight',
|
|
@@ -6105,8 +7123,8 @@ class MlvEditorInlineMarks {
|
|
|
6105
7123
|
/** @protected Italic command. */ _italic = (editor) => editor.chain().focus().toggleItalic().run();
|
|
6106
7124
|
/** @protected Strike command. */ _strike = (editor) => editor.chain().focus().toggleStrike().run();
|
|
6107
7125
|
/** @protected Underline command. */ _underline = (editor) => editor.chain().focus().toggleUnderline().run();
|
|
6108
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
6109
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.
|
|
7126
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorInlineMarks, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7127
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorInlineMarks, isStandalone: true, selector: "mlv-editor-inline-marks", host: { attributes: { "role": "group" }, classAttribute: "mlv-editor-inline-marks" }, ngImport: i0, template: `
|
|
6110
7128
|
<mlv-editor-command-button
|
|
6111
7129
|
[label]="_copy().bold"
|
|
6112
7130
|
[pressed]="_isActive('bold')"
|
|
@@ -6141,7 +7159,7 @@ class MlvEditorInlineMarks {
|
|
|
6141
7159
|
/></mlv-editor-command-button>
|
|
6142
7160
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvEditorCommandButton, selector: "mlv-editor-command-button", inputs: ["label", "supports", "command", "canCommand", "pressed"] }, { kind: "component", type: LucideBold, selector: "svg[lucideBold]" }, { kind: "component", type: LucideItalic, selector: "svg[lucideItalic]" }, { kind: "component", type: LucideStrikethrough, selector: "svg[lucideStrikethrough]" }, { kind: "component", type: LucideUnderline, selector: "svg[lucideUnderline]" }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6143
7161
|
}
|
|
6144
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
7162
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorInlineMarks, decorators: [{
|
|
6145
7163
|
type: Component,
|
|
6146
7164
|
args: [{
|
|
6147
7165
|
selector: 'mlv-editor-inline-marks',
|
|
@@ -6303,8 +7321,8 @@ class MlvEditorList {
|
|
|
6303
7321
|
this._unregister?.();
|
|
6304
7322
|
this._unregister = undefined;
|
|
6305
7323
|
}
|
|
6306
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
6307
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
7324
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorList, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7325
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorList, isStandalone: true, selector: "mlv-editor-list", host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-list" }, viewQueries: [{ propertyName: "_menu", first: true, predicate: ["_menu"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: MlvMenuTrigger, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
6308
7326
|
<button
|
|
6309
7327
|
mlvButton
|
|
6310
7328
|
mlvEditorToolbarWidget
|
|
@@ -6356,7 +7374,7 @@ class MlvEditorList {
|
|
|
6356
7374
|
</mlv-menu>
|
|
6357
7375
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideList, selector: "svg[lucideList]" }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6358
7376
|
}
|
|
6359
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
7377
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorList, decorators: [{
|
|
6360
7378
|
type: Component,
|
|
6361
7379
|
args: [{
|
|
6362
7380
|
selector: 'mlv-editor-list',
|
|
@@ -6659,15 +7677,14 @@ class MlvEditorLink {
|
|
|
6659
7677
|
.map((protocol) => protocol.trim().toLowerCase().replace(/:+$/, ''))
|
|
6660
7678
|
.filter(Boolean));
|
|
6661
7679
|
}
|
|
6662
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
6663
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
7680
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorLink, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7681
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorLink, isStandalone: true, selector: "mlv-editor-link", inputs: { allowedProtocols: { classPropertyName: "allowedProtocols", publicName: "allowedProtocols", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-link" }, viewQueries: [{ propertyName: "_popup", first: true, predicate: ["_popup"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: ["_trigger"], descendants: true, isSignal: true }, { propertyName: "_triggerElement", first: true, predicate: ["_triggerElement"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_urlInput", first: true, predicate: ["_urlInput"], descendants: true, isSignal: true }, { propertyName: "_panel", first: true, predicate: ["_panel"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n #_trigger=\"mlvPopupTrigger\"\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvPopupTrigger]=\"_popup\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_copy().link\"\n [attr.aria-pressed]=\"_active()\"\n [mlvTooltip]=\"_copy().link\"\n>\n <svg mlvButtonIcon lucideLink aria-hidden=\"true\" />\n</button>\n\n<mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [ariaLabel]=\"_copy().link\"\n (afterOpened)=\"_onOpened()\"\n (afterClosed)=\"_onClosed()\"\n>\n <ng-template mlvPopupContent>\n <div #_panel class=\"mlv-editor-link__panel\">\n <mlv-input\n #_urlInput\n type=\"url\"\n [label]=\"_copy().linkUrl\"\n [value]=\"_urlDraft()\"\n [disabled]=\"_disabled()\"\n [state]=\"_invalid() ? 'error' : 'default'\"\n [message]=\"_invalid() ? _copy().invalidLink : ''\"\n (valueChange)=\"_onUrlChange($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-input\n [label]=\"_copy().linkText\"\n [value]=\"_textDraft()\"\n [disabled]=\"_disabled()\"\n (valueChange)=\"_textDraft.set($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-switch [label]=\"_copy().openInNewTab\" [(checked)]=\"_newTab\">{{\n _copy().openInNewTab\n }}</mlv-switch>\n <div class=\"mlv-editor-link__actions\">\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [disabled]=\"_disabled()\"\n (click)=\"_apply()\"\n >\n {{ _copy().applyLink }}\n </button>\n @if (_canRemove()) {\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n [disabled]=\"_disabled()\"\n (click)=\"_remove()\"\n >\n {{ _copy().removeLink }}\n </button>\n }\n </div>\n </div>\n </ng-template>\n</mlv-popup>\n", styles: ["@layer mlv.components{.mlv-editor-link{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-link *{box-sizing:border-box}.mlv-editor-link{display:inline-flex}.mlv-editor-link__panel{display:grid;width:min(22rem,100vw - 3.5rem);gap:var(--mlv-spacing-1-5);padding:var(--mlv-spacing-2)}.mlv-editor-link__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--mlv-spacing-3)}}\n"], dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideLink, selector: "svg[lucideLink]" }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }, { kind: "component", type: MlvInput, selector: "mlv-input", inputs: ["type", "placeholder", "autocomplete", "inputMode", "maxLength", "minLength", "pattern", "name", "autofocus", "min", "max", "step", "bare", "projectControl", "role", "ariaExpanded", "ariaHasPopup", "ariaAutocomplete", "ariaControls", "ariaActiveDescendant", "ariaDescribedBy", "value"], outputs: ["valueChange", "inputFocus", "inputBlur"] }, { kind: "component", type: MlvPopup, selector: "mlv-popup", inputs: ["position", "positions", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "hasArrow", "hasShadow", "class", "mlvDensity", "flexibleDimensions", "scrollStrategy", "hasBackdrop", "restrictPosition", "panelRole", "modal", "ariaLabel", "dismissExcludeElements", "mobileMode", "mobileBreakpoint", "mobileTitle", "mobileCloseLabel", "opened"], outputs: ["openedChange", "afterOpened", "afterClosed"] }, { kind: "directive", type: MlvPopupContent, selector: "[mlvPopupContent]" }, { kind: "directive", type: MlvPopupTrigger, selector: "[mlvPopupTrigger]", inputs: ["mlvPopupTrigger", "triggerOn", "ariaHasPopup"], exportAs: ["mlvPopupTrigger"] }, { kind: "component", type: MlvSwitch, selector: "mlv-switch", inputs: ["ariaLabelledBy", "checked"], outputs: ["checkedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6664
7682
|
}
|
|
6665
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
7683
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorLink, decorators: [{
|
|
6666
7684
|
type: Component,
|
|
6667
7685
|
args: [{ selector: 'mlv-editor-link', imports: [
|
|
6668
7686
|
MlvButton,
|
|
6669
7687
|
MlvButtonIcon,
|
|
6670
|
-
MlvButtonToggle,
|
|
6671
7688
|
MlvTooltip,
|
|
6672
7689
|
LucideLink,
|
|
6673
7690
|
MlvEditorToolbarWidget,
|
|
@@ -6679,7 +7696,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
6679
7696
|
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
6680
7697
|
class: 'mlv-editor-link',
|
|
6681
7698
|
'[hidden]': '!_supported()',
|
|
6682
|
-
}, template: "<button\n #_trigger=\"mlvPopupTrigger\"\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvPopupTrigger]=\"_popup\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_copy().link\"\n [attr.aria-pressed]=\"_active()\"\n [mlvTooltip]=\"_copy().link\"\n>\n <svg mlvButtonIcon lucideLink aria-hidden=\"true\" />\n</button>\n\n<mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [ariaLabel]=\"_copy().link\"\n (afterOpened)=\"_onOpened()\"\n (afterClosed)=\"_onClosed()\"\n>\n <ng-template mlvPopupContent>\n <div #_panel class=\"mlv-editor-link__panel\">\n <mlv-input\n #_urlInput\n type=\"url\"\n [label]=\"_copy().linkUrl\"\n [value]=\"_urlDraft()\"\n [disabled]=\"_disabled()\"\n [state]=\"_invalid() ? 'error' : 'default'\"\n [message]=\"_invalid() ? _copy().invalidLink : ''\"\n (valueChange)=\"_onUrlChange($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-input\n [label]=\"_copy().linkText\"\n [value]=\"_textDraft()\"\n [disabled]=\"_disabled()\"\n (valueChange)=\"_textDraft.set($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-switch [label]=\"_copy().openInNewTab\" [(checked)]=\"_newTab\"\n
|
|
7699
|
+
}, template: "<button\n #_trigger=\"mlvPopupTrigger\"\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvPopupTrigger]=\"_popup\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_copy().link\"\n [attr.aria-pressed]=\"_active()\"\n [mlvTooltip]=\"_copy().link\"\n>\n <svg mlvButtonIcon lucideLink aria-hidden=\"true\" />\n</button>\n\n<mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [ariaLabel]=\"_copy().link\"\n (afterOpened)=\"_onOpened()\"\n (afterClosed)=\"_onClosed()\"\n>\n <ng-template mlvPopupContent>\n <div #_panel class=\"mlv-editor-link__panel\">\n <mlv-input\n #_urlInput\n type=\"url\"\n [label]=\"_copy().linkUrl\"\n [value]=\"_urlDraft()\"\n [disabled]=\"_disabled()\"\n [state]=\"_invalid() ? 'error' : 'default'\"\n [message]=\"_invalid() ? _copy().invalidLink : ''\"\n (valueChange)=\"_onUrlChange($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-input\n [label]=\"_copy().linkText\"\n [value]=\"_textDraft()\"\n [disabled]=\"_disabled()\"\n (valueChange)=\"_textDraft.set($event)\"\n (keydown.enter)=\"_apply()\"\n />\n <mlv-switch [label]=\"_copy().openInNewTab\" [(checked)]=\"_newTab\">{{\n _copy().openInNewTab\n }}</mlv-switch>\n <div class=\"mlv-editor-link__actions\">\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [disabled]=\"_disabled()\"\n (click)=\"_apply()\"\n >\n {{ _copy().applyLink }}\n </button>\n @if (_canRemove()) {\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n [disabled]=\"_disabled()\"\n (click)=\"_remove()\"\n >\n {{ _copy().removeLink }}\n </button>\n }\n </div>\n </div>\n </ng-template>\n</mlv-popup>\n", styles: ["@layer mlv.components{.mlv-editor-link{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-link *{box-sizing:border-box}.mlv-editor-link{display:inline-flex}.mlv-editor-link__panel{display:grid;width:min(22rem,100vw - 3.5rem);gap:var(--mlv-spacing-1-5);padding:var(--mlv-spacing-2)}.mlv-editor-link__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--mlv-spacing-3)}}\n"] }]
|
|
6683
7700
|
}], ctorParameters: () => [], propDecorators: { allowedProtocols: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowedProtocols", required: false }] }], _popup: [{ type: i0.ViewChild, args: ['_popup', { isSignal: true }] }], _trigger: [{ type: i0.ViewChild, args: ['_trigger', { isSignal: true }] }], _triggerElement: [{ type: i0.ViewChild, args: ['_triggerElement', { ...{
|
|
6684
7701
|
read: ElementRef,
|
|
6685
7702
|
}, isSignal: true }] }], _urlInput: [{ type: i0.ViewChild, args: ['_urlInput', { isSignal: true }] }], _panel: [{ type: i0.ViewChild, args: ['_panel', { isSignal: true }] }] } });
|
|
@@ -6832,6 +7849,8 @@ class MlvEditorImageUploadDialog {
|
|
|
6832
7849
|
this._dialogRef.close();
|
|
6833
7850
|
return;
|
|
6834
7851
|
}
|
|
7852
|
+
// A removed failure: its "failed" text must not outlive it.
|
|
7853
|
+
this._announcement.set('');
|
|
6835
7854
|
this._reset();
|
|
6836
7855
|
});
|
|
6837
7856
|
this._dialogRef.beforeClose().subscribe(() => {
|
|
@@ -6905,6 +7924,16 @@ class MlvEditorImageUploadDialog {
|
|
|
6905
7924
|
this._progressBucket = -1;
|
|
6906
7925
|
this._coordinator.retry(id);
|
|
6907
7926
|
}
|
|
7927
|
+
/**
|
|
7928
|
+
* @protected Toggles Decorative. Turning it on clears the title draft: a
|
|
7929
|
+
* decorative image carries an empty alt and no title (WCAG H67), and the
|
|
7930
|
+
* title field stays disabled until it is turned off.
|
|
7931
|
+
*/
|
|
7932
|
+
_onDecorativeChange(decorative) {
|
|
7933
|
+
this._decorative.set(decorative);
|
|
7934
|
+
if (decorative)
|
|
7935
|
+
this._title.set('');
|
|
7936
|
+
}
|
|
6908
7937
|
/** @protected Removes the failed item and clears the draft. */
|
|
6909
7938
|
_remove() {
|
|
6910
7939
|
const id = this._activeId();
|
|
@@ -6943,10 +7972,10 @@ class MlvEditorImageUploadDialog {
|
|
|
6943
7972
|
if (url)
|
|
6944
7973
|
URL.revokeObjectURL(url);
|
|
6945
7974
|
}
|
|
6946
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
6947
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
7975
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorImageUploadDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7976
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorImageUploadDialog, isStandalone: true, selector: "mlv-editor-image-upload-dialog", host: { classAttribute: "mlv-editor-image-upload-dialog" }, ngImport: i0, template: "<mlv-dialog>\n <mlv-dialog-header />\n <mlv-dialog-body>\n <div class=\"mlv-editor-image-upload-dialog__body\">\n <mlv-file-upload\n [accept]=\"_accept()\"\n [maxSize]=\"_maxSize()\"\n [multiple]=\"false\"\n [disabled]=\"_disabled() || !!_activeId()\"\n [value]=\"_files()\"\n (filesChange)=\"_onFilesChange($event)\"\n />\n\n @if (_file(); as selected) {\n @if (selected.previewUrl) {\n <img\n class=\"mlv-editor-image-upload-dialog__preview\"\n [src]=\"selected.previewUrl\"\n [alt]=\"_previewAlt()\"\n />\n }\n @if (_item(); as item) {\n @if (item.status === 'uploading') {\n <mlv-progress\n [value]=\"item.progress\"\n [showPercentage]=\"true\"\n [ariaLabel]=\"_progressLabel(item.progress)\"\n />\n } @else {\n <p\n class=\"mlv-editor-image-upload-dialog__error\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {{ _copy().failed }}\n </p>\n }\n }\n }\n\n <mlv-input\n [label]=\"_copy().alt\"\n [ariaLabel]=\"_copy().alt\"\n [value]=\"_alt()\"\n [disabled]=\"_disabled() || !!_activeId() || _decorative()\"\n [state]=\"_altInvalid() ? 'error' : 'default'\"\n [message]=\"_altInvalid() ? _copy().altRequired : ''\"\n (valueChange)=\"_alt.set($event)\"\n />\n <mlv-input\n [label]=\"_copy().imageTitle\"\n [ariaLabel]=\"_copy().imageTitle\"\n [value]=\"_title()\"\n [disabled]=\"_disabled() || !!_activeId() || _decorative()\"\n (valueChange)=\"_title.set($event)\"\n />\n <mlv-switch\n [ariaLabel]=\"_copy().decorative\"\n [checked]=\"_decorative()\"\n [disabled]=\"_disabled() || !!_activeId()\"\n (checkedChange)=\"_onDecorativeChange($event)\"\n >\n {{ _copy().decorative }}\n </mlv-switch>\n\n <span\n class=\"mlv-editor-image-upload-dialog__live\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >{{ _announcement() }}</span\n >\n </div>\n </mlv-dialog-body>\n\n <mlv-dialog-footer>\n @if (_item()?.status === 'uploading') {\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"_copy().cancel\"\n (click)=\"_cancel()\"\n >\n {{ _copy().cancel }}\n </button>\n } @else if (_item()?.status === 'failed') {\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [attr.aria-label]=\"_copy().retry\"\n [disabled]=\"_disabled()\"\n (click)=\"_retry()\"\n >\n {{ _copy().retry }}\n </button>\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"_removeLabel()\"\n [disabled]=\"_disabled()\"\n (click)=\"_remove()\"\n >\n {{ _removeLabel() }}\n </button>\n } @else {\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [attr.aria-label]=\"_copy().title\"\n [disabled]=\"_submitDisabled()\"\n (click)=\"_submit()\"\n >\n {{ _copy().title }}\n </button>\n }\n </mlv-dialog-footer>\n</mlv-dialog>\n", styles: ["@layer mlv.components{.mlv-editor-image-upload-dialog{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-image-upload-dialog *{box-sizing:border-box}.mlv-editor-image-upload-dialog__body{display:grid;gap:var(--mlv-spacing-2)}.mlv-editor-image-upload-dialog__preview{display:block;max-block-size:12rem;max-inline-size:100%;margin-inline:auto;border-radius:var(--mlv-radius-card);object-fit:contain}.mlv-editor-image-upload-dialog__error{margin:0;color:var(--mlv-text-negative)}.mlv-editor-image-upload-dialog__live{position:absolute;width:.0625rem;height:.0625rem;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.mlv-editor-image-upload-status{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-image-upload-status *{box-sizing:border-box}.mlv-editor-image-upload-status{display:block;padding:0 var(--mlv-spacing-4) var(--mlv-spacing-2)}.mlv-editor-image-upload-status__list{display:grid;gap:var(--mlv-spacing-1-5);padding:0;margin:0;list-style:none}.mlv-editor-image-upload-status__item{display:grid;grid-template-columns:minmax(0,1fr) minmax(8rem,2fr) auto auto;align-items:center;gap:var(--mlv-spacing-3)}.mlv-editor-image-upload-status__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mlv-editor-image-upload-status__live{position:absolute;width:.0625rem;height:.0625rem;overflow:hidden;clip-path:inset(50%);white-space:nowrap}}\n"], dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "component", type: MlvDialog, selector: "mlv-dialog" }, { kind: "component", type: MlvDialogBody, selector: "mlv-dialog-body, [mlvDialogBody]" }, { kind: "component", type: MlvDialogFooter, selector: "mlv-dialog-footer, [mlvDialogFooter]", inputs: ["align"] }, { kind: "component", type: MlvDialogHeader, selector: "mlv-dialog-header, [mlvDialogHeader]", inputs: ["title", "closable"] }, { kind: "component", type: MlvFileUpload, selector: "mlv-file-upload", inputs: ["value", "accept", "maxSize", "multiple", "title", "subtitle", "actionLabel", "compact", "previewMode"], outputs: ["valueChange", "filesChange"] }, { kind: "component", type: MlvInput, selector: "mlv-input", inputs: ["type", "placeholder", "autocomplete", "inputMode", "maxLength", "minLength", "pattern", "name", "autofocus", "min", "max", "step", "bare", "projectControl", "role", "ariaExpanded", "ariaHasPopup", "ariaAutocomplete", "ariaControls", "ariaActiveDescendant", "ariaDescribedBy", "value"], outputs: ["valueChange", "inputFocus", "inputBlur"] }, { kind: "component", type: MlvProgress, selector: "mlv-progress", inputs: ["shape", "value", "size", "tone", "showPercentage", "ariaLabel"] }, { kind: "component", type: MlvSwitch, selector: "mlv-switch", inputs: ["ariaLabelledBy", "checked"], outputs: ["checkedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6948
7977
|
}
|
|
6949
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
7978
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorImageUploadDialog, decorators: [{
|
|
6950
7979
|
type: Component,
|
|
6951
7980
|
args: [{ selector: 'mlv-editor-image-upload-dialog', imports: [
|
|
6952
7981
|
MlvButton,
|
|
@@ -6958,7 +7987,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
6958
7987
|
MlvInput,
|
|
6959
7988
|
MlvProgress,
|
|
6960
7989
|
MlvSwitch,
|
|
6961
|
-
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'mlv-editor-image-upload-dialog' }, template: "<mlv-dialog>\n <mlv-dialog-header />\n <mlv-dialog-body>\n <div class=\"mlv-editor-image-upload-dialog__body\">\n <mlv-file-upload\n [accept]=\"_accept()\"\n [maxSize]=\"_maxSize()\"\n [multiple]=\"false\"\n [disabled]=\"_disabled() || !!_activeId()\"\n [value]=\"_files()\"\n (filesChange)=\"_onFilesChange($event)\"\n />\n\n @if (_file(); as selected) {
|
|
7990
|
+
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'mlv-editor-image-upload-dialog' }, template: "<mlv-dialog>\n <mlv-dialog-header />\n <mlv-dialog-body>\n <div class=\"mlv-editor-image-upload-dialog__body\">\n <mlv-file-upload\n [accept]=\"_accept()\"\n [maxSize]=\"_maxSize()\"\n [multiple]=\"false\"\n [disabled]=\"_disabled() || !!_activeId()\"\n [value]=\"_files()\"\n (filesChange)=\"_onFilesChange($event)\"\n />\n\n @if (_file(); as selected) {\n @if (selected.previewUrl) {\n <img\n class=\"mlv-editor-image-upload-dialog__preview\"\n [src]=\"selected.previewUrl\"\n [alt]=\"_previewAlt()\"\n />\n }\n @if (_item(); as item) {\n @if (item.status === 'uploading') {\n <mlv-progress\n [value]=\"item.progress\"\n [showPercentage]=\"true\"\n [ariaLabel]=\"_progressLabel(item.progress)\"\n />\n } @else {\n <p\n class=\"mlv-editor-image-upload-dialog__error\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {{ _copy().failed }}\n </p>\n }\n }\n }\n\n <mlv-input\n [label]=\"_copy().alt\"\n [ariaLabel]=\"_copy().alt\"\n [value]=\"_alt()\"\n [disabled]=\"_disabled() || !!_activeId() || _decorative()\"\n [state]=\"_altInvalid() ? 'error' : 'default'\"\n [message]=\"_altInvalid() ? _copy().altRequired : ''\"\n (valueChange)=\"_alt.set($event)\"\n />\n <mlv-input\n [label]=\"_copy().imageTitle\"\n [ariaLabel]=\"_copy().imageTitle\"\n [value]=\"_title()\"\n [disabled]=\"_disabled() || !!_activeId() || _decorative()\"\n (valueChange)=\"_title.set($event)\"\n />\n <mlv-switch\n [ariaLabel]=\"_copy().decorative\"\n [checked]=\"_decorative()\"\n [disabled]=\"_disabled() || !!_activeId()\"\n (checkedChange)=\"_onDecorativeChange($event)\"\n >\n {{ _copy().decorative }}\n </mlv-switch>\n\n <span\n class=\"mlv-editor-image-upload-dialog__live\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >{{ _announcement() }}</span\n >\n </div>\n </mlv-dialog-body>\n\n <mlv-dialog-footer>\n @if (_item()?.status === 'uploading') {\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"_copy().cancel\"\n (click)=\"_cancel()\"\n >\n {{ _copy().cancel }}\n </button>\n } @else if (_item()?.status === 'failed') {\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [attr.aria-label]=\"_copy().retry\"\n [disabled]=\"_disabled()\"\n (click)=\"_retry()\"\n >\n {{ _copy().retry }}\n </button>\n <button\n mlvButton\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"_removeLabel()\"\n [disabled]=\"_disabled()\"\n (click)=\"_remove()\"\n >\n {{ _removeLabel() }}\n </button>\n } @else {\n <button\n mlvButton\n type=\"button\"\n variant=\"primary\"\n [attr.aria-label]=\"_copy().title\"\n [disabled]=\"_submitDisabled()\"\n (click)=\"_submit()\"\n >\n {{ _copy().title }}\n </button>\n }\n </mlv-dialog-footer>\n</mlv-dialog>\n", styles: ["@layer mlv.components{.mlv-editor-image-upload-dialog{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-image-upload-dialog *{box-sizing:border-box}.mlv-editor-image-upload-dialog__body{display:grid;gap:var(--mlv-spacing-2)}.mlv-editor-image-upload-dialog__preview{display:block;max-block-size:12rem;max-inline-size:100%;margin-inline:auto;border-radius:var(--mlv-radius-card);object-fit:contain}.mlv-editor-image-upload-dialog__error{margin:0;color:var(--mlv-text-negative)}.mlv-editor-image-upload-dialog__live{position:absolute;width:.0625rem;height:.0625rem;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.mlv-editor-image-upload-status{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-image-upload-status *{box-sizing:border-box}.mlv-editor-image-upload-status{display:block;padding:0 var(--mlv-spacing-4) var(--mlv-spacing-2)}.mlv-editor-image-upload-status__list{display:grid;gap:var(--mlv-spacing-1-5);padding:0;margin:0;list-style:none}.mlv-editor-image-upload-status__item{display:grid;grid-template-columns:minmax(0,1fr) minmax(8rem,2fr) auto auto;align-items:center;gap:var(--mlv-spacing-3)}.mlv-editor-image-upload-status__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mlv-editor-image-upload-status__live{position:absolute;width:.0625rem;height:.0625rem;overflow:hidden;clip-path:inset(50%);white-space:nowrap}}\n"] }]
|
|
6962
7991
|
}], ctorParameters: () => [] });
|
|
6963
7992
|
|
|
6964
7993
|
/** Public toolbar entry point for the editor image-upload dialog. */
|
|
@@ -7052,10 +8081,10 @@ class MlvEditorImageUpload {
|
|
|
7052
8081
|
}
|
|
7053
8082
|
});
|
|
7054
8083
|
}
|
|
7055
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
7056
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.
|
|
8084
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorImageUpload, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8085
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.7", type: MlvEditorImageUpload, isStandalone: true, selector: "mlv-editor-image-upload", host: { properties: { "hidden": "!_visible()" }, classAttribute: "mlv-editor-image-upload" }, viewQueries: [{ propertyName: "_trigger", first: true, predicate: ["_trigger"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<button\n #_trigger\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy()\"\n [attr.aria-pressed]=\"false\"\n [mlvTooltip]=\"_copy()\"\n (click)=\"_open()\"\n>\n <svg mlvButtonIcon lucideImage aria-hidden=\"true\" />\n</button>\n", dependencies: [{ kind: "component", type: LucideImage, selector: "svg[lucideImage]" }, { kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
7057
8086
|
}
|
|
7058
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
8087
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorImageUpload, decorators: [{
|
|
7059
8088
|
type: Component,
|
|
7060
8089
|
args: [{ selector: 'mlv-editor-image-upload', imports: [
|
|
7061
8090
|
LucideImage,
|
|
@@ -7087,6 +8116,11 @@ class MlvEditorImageUploadStatus {
|
|
|
7087
8116
|
...(ngDevMode ? [{ debugName: "_announcement" }] : /* istanbul ignore next */ []));
|
|
7088
8117
|
/** @private Last announced progress bucket for each active item. */
|
|
7089
8118
|
_buckets = new Map();
|
|
8119
|
+
/**
|
|
8120
|
+
* @private Upload whose progress or failure the live region currently
|
|
8121
|
+
* reads, or `null` when it reads a terminal announcement (or nothing).
|
|
8122
|
+
*/
|
|
8123
|
+
_announcedId = null;
|
|
7090
8124
|
/** @protected Whether status actions are inert. */
|
|
7091
8125
|
_disabled = computed(() => this._context.disabled() || this._context.readonly(), /* @ts-ignore */
|
|
7092
8126
|
...(ngDevMode ? [{ debugName: "_disabled" }] : /* istanbul ignore next */ []));
|
|
@@ -7106,7 +8140,7 @@ class MlvEditorImageUploadStatus {
|
|
|
7106
8140
|
const pending = this._pending();
|
|
7107
8141
|
for (const item of pending) {
|
|
7108
8142
|
if (item.status === 'failed') {
|
|
7109
|
-
this.
|
|
8143
|
+
this._announce(this._copy().failed, item.id);
|
|
7110
8144
|
this._buckets.delete(item.id);
|
|
7111
8145
|
continue;
|
|
7112
8146
|
}
|
|
@@ -7114,16 +8148,22 @@ class MlvEditorImageUploadStatus {
|
|
|
7114
8148
|
if (this._buckets.get(item.id) === bucket)
|
|
7115
8149
|
continue;
|
|
7116
8150
|
this._buckets.set(item.id, bucket);
|
|
7117
|
-
this.
|
|
8151
|
+
this._announce(this._progressLabel(bucket), item.id);
|
|
7118
8152
|
}
|
|
7119
8153
|
});
|
|
7120
8154
|
const stopTerminalEvents = this._coordinator.onTerminal(({ id, reason }) => {
|
|
7121
8155
|
this._buckets.delete(id);
|
|
7122
8156
|
if (reason === 'success' && !this._coordinator.hasDialogOwner(id)) {
|
|
7123
|
-
this.
|
|
8157
|
+
this._announce(this._fileI18n().uploadComplete, null);
|
|
7124
8158
|
}
|
|
7125
8159
|
else if (reason === 'cancelled') {
|
|
7126
|
-
this.
|
|
8160
|
+
this._announce(this._copy().cancel, null);
|
|
8161
|
+
}
|
|
8162
|
+
else if (this._announcedId === id) {
|
|
8163
|
+
// A dialog-owned success (the dialog announces it), a lifecycle
|
|
8164
|
+
// abort or a removed failure: the ended upload's progress or
|
|
8165
|
+
// failure text must not outlive it. Another upload's text stays.
|
|
8166
|
+
this._announce('', null);
|
|
7127
8167
|
}
|
|
7128
8168
|
});
|
|
7129
8169
|
inject(DestroyRef).onDestroy(stopTerminalEvents);
|
|
@@ -7132,6 +8172,11 @@ class MlvEditorImageUploadStatus {
|
|
|
7132
8172
|
_progressLabel(progress) {
|
|
7133
8173
|
return this._copy().progress.replace('{progress}', String(Math.floor(progress / 10) * 10));
|
|
7134
8174
|
}
|
|
8175
|
+
/** @private Writes the live region and records which upload it describes. */
|
|
8176
|
+
_announce(text, id) {
|
|
8177
|
+
this._announcement.set(text);
|
|
8178
|
+
this._announcedId = id;
|
|
8179
|
+
}
|
|
7135
8180
|
/** @protected Labels a remove action without exposing a bare icon. */
|
|
7136
8181
|
_removeLabel(name) {
|
|
7137
8182
|
return this._fileI18n().removeFile.replace('{name}', name);
|
|
@@ -7140,8 +8185,8 @@ class MlvEditorImageUploadStatus {
|
|
|
7140
8185
|
_cancel(id) {
|
|
7141
8186
|
this._coordinator.cancel(id);
|
|
7142
8187
|
}
|
|
7143
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
7144
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
8188
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorImageUploadStatus, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8189
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorImageUploadStatus, isStandalone: true, selector: "mlv-editor-image-upload-status", host: { classAttribute: "mlv-editor-image-upload-status" }, ngImport: i0, template: `
|
|
7145
8190
|
@if (_pending().length) {
|
|
7146
8191
|
<ul class="mlv-editor-image-upload-status__list">
|
|
7147
8192
|
@for (item of _pending(); track item.id) {
|
|
@@ -7201,7 +8246,7 @@ class MlvEditorImageUploadStatus {
|
|
|
7201
8246
|
>
|
|
7202
8247
|
`, isInline: true, styles: ["@layer mlv.components{.mlv-editor-image-upload-dialog{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-image-upload-dialog *{box-sizing:border-box}.mlv-editor-image-upload-dialog__body{display:grid;gap:var(--mlv-spacing-2)}.mlv-editor-image-upload-dialog__preview{display:block;max-block-size:12rem;max-inline-size:100%;margin-inline:auto;border-radius:var(--mlv-radius-card);object-fit:contain}.mlv-editor-image-upload-dialog__error{margin:0;color:var(--mlv-text-negative)}.mlv-editor-image-upload-dialog__live{position:absolute;width:.0625rem;height:.0625rem;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.mlv-editor-image-upload-status{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-image-upload-status *{box-sizing:border-box}.mlv-editor-image-upload-status{display:block;padding:0 var(--mlv-spacing-4) var(--mlv-spacing-2)}.mlv-editor-image-upload-status__list{display:grid;gap:var(--mlv-spacing-1-5);padding:0;margin:0;list-style:none}.mlv-editor-image-upload-status__item{display:grid;grid-template-columns:minmax(0,1fr) minmax(8rem,2fr) auto auto;align-items:center;gap:var(--mlv-spacing-3)}.mlv-editor-image-upload-status__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mlv-editor-image-upload-status__live{position:absolute;width:.0625rem;height:.0625rem;overflow:hidden;clip-path:inset(50%);white-space:nowrap}}\n"], dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "component", type: MlvProgress, selector: "mlv-progress", inputs: ["shape", "value", "size", "tone", "showPercentage", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
7203
8248
|
}
|
|
7204
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
8249
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorImageUploadStatus, decorators: [{
|
|
7205
8250
|
type: Component,
|
|
7206
8251
|
args: [{ selector: 'mlv-editor-image-upload-status', imports: [MlvButton, MlvProgress], template: `
|
|
7207
8252
|
@if (_pending().length) {
|
|
@@ -7271,6 +8316,18 @@ class MlvEditorTable {
|
|
|
7271
8316
|
_context = inject(MLV_EDITOR_TOOLBAR_CONTEXT);
|
|
7272
8317
|
/** @private Normalizes horizontal grid movement for RTL. */
|
|
7273
8318
|
_rtlService = inject(MlvRtlService);
|
|
8319
|
+
/**
|
|
8320
|
+
* @private Host element; the scope horizontal arrow keys resolve their
|
|
8321
|
+
* direction against. The grid renders in a popup pane portaled out of this
|
|
8322
|
+
* subtree, so the handler speaks for the host, never for `event.target`.
|
|
8323
|
+
*/
|
|
8324
|
+
_elementRef = inject((ElementRef));
|
|
8325
|
+
/**
|
|
8326
|
+
* @private Direction applying to this control, resolved once and cached
|
|
8327
|
+
* behind the shared `dir` observer rather than re-walked on every arrow
|
|
8328
|
+
* keypress.
|
|
8329
|
+
*/
|
|
8330
|
+
_direction = this._rtlService.elementDirection(this._elementRef);
|
|
7274
8331
|
/** @private Transaction and selection invalidation bridge. */
|
|
7275
8332
|
_revision = inject(MLV_EDITOR_TOOLBAR_REVISION, {
|
|
7276
8333
|
optional: true,
|
|
@@ -7524,7 +8581,11 @@ class MlvEditorTable {
|
|
|
7524
8581
|
_onGridKeydown(event) {
|
|
7525
8582
|
const current = this._selectedSize();
|
|
7526
8583
|
let next = current;
|
|
7527
|
-
|
|
8584
|
+
// Columns run along the inline axis, resolved against this control's own
|
|
8585
|
+
// host rather than the document, so a scoped `dir` subtree — or a CDK
|
|
8586
|
+
// overlay pane, which carries its own `dir` — mirrors the pair correctly.
|
|
8587
|
+
switch (this._rtlService.normalizeArrowKey(event, this._direction()) ??
|
|
8588
|
+
event.key) {
|
|
7528
8589
|
case LEFT_ARROW:
|
|
7529
8590
|
next = { ...current, cols: Math.max(1, current.cols - 1) };
|
|
7530
8591
|
break;
|
|
@@ -7567,10 +8628,10 @@ class MlvEditorTable {
|
|
|
7567
8628
|
const index = (selected.rows - 1) * TABLE_GRID_BOUNDARY + (selected.cols - 1);
|
|
7568
8629
|
this._gridCells()[index]?.nativeElement.focus();
|
|
7569
8630
|
}
|
|
7570
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
7571
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: MlvEditorTable, isStandalone: true, selector: "mlv-editor-table", host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-table" }, viewQueries: [{ propertyName: "_popup", first: true, predicate: ["_popup"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: ["_trigger"], descendants: true, isSignal: true }, { propertyName: "_menu", first: true, predicate: ["_menu"], descendants: true, isSignal: true }, { propertyName: "_menuTrigger", first: true, predicate: MlvMenuTrigger, descendants: true, isSignal: true }, { propertyName: "_triggerElement", first: true, predicate: ["_triggerElement"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_panel", first: true, predicate: ["_panel"], descendants: true, isSignal: true }, { propertyName: "_firstAction", first: true, predicate: ["_firstAction"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_gridCells", predicate: ["_gridCell"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "@if (_active()) {\n <button\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n selected\n [disabled]=\"_disabled()\"\n [mlvMenuTrigger]=\"_menu\"\n [menuTriggerDisabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().table\"\n [mlvTooltip]=\"_copy().table\"\n (menuOpened)=\"_registerMenuOverlay()\"\n (menuClosed)=\"_unregisterMenuOverlay()\"\n >\n <svg mlvButtonIcon lucideTable2 aria-hidden=\"true\" />\n </button>\n\n <mlv-menu #_menu [label]=\"_copy().table\">\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddRowBefore)\"\n (itemClick)=\"_run(_addRowBefore)\"\n >\n {{ _copy().addRowBefore }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddRowAfter)\"\n (itemClick)=\"_run(_addRowAfter)\"\n >\n {{ _copy().addRowAfter }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canDeleteRow)\"\n (itemClick)=\"_run(_deleteRow)\"\n >\n {{ _copy().deleteRow }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddColumnBefore)\"\n (itemClick)=\"_run(_addColumnBefore)\"\n >\n {{ _copy().addColumnBefore }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddColumnAfter)\"\n (itemClick)=\"_run(_addColumnAfter)\"\n >\n {{ _copy().addColumnAfter }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canDeleteColumn)\"\n (itemClick)=\"_run(_deleteColumn)\"\n >\n {{ _copy().deleteColumn }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canMergeCells)\"\n (itemClick)=\"_run(_mergeCells)\"\n >\n {{ _copy().mergeCells }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canSplitCell)\"\n (itemClick)=\"_run(_splitCell)\"\n >\n {{ _copy().splitCell }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canToggleHeaderRow)\"\n (itemClick)=\"_run(_toggleHeaderRow)\"\n >\n {{ _copy().toggleHeaderRow }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canToggleHeaderColumn)\"\n (itemClick)=\"_run(_toggleHeaderColumn)\"\n >\n {{ _copy().toggleHeaderColumn }}\n </mlv-list-item>\n <!-- `aria-current` marks the state the caret's cell is already in; the row\n paints itself from the shared selected pair. -->\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canToggleHeaderCell)\"\n [attr.aria-current]=\"_isHeaderCell() ? 'true' : null\"\n (itemClick)=\"_run(_toggleHeaderCell)\"\n >\n {{ _copy().toggleHeaderCell }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canDeleteTable)\"\n (itemClick)=\"_run(_deleteTable, true)\"\n >\n {{ _copy().deleteTable }}\n </mlv-list-item>\n </mlv-menu>\n} @else {\n <button\n #_trigger=\"mlvPopupTrigger\"\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvPopupTrigger]=\"_popup\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_copy().table\"\n [mlvTooltip]=\"_copy().table\"\n >\n <svg mlvButtonIcon lucideTable2 aria-hidden=\"true\" />\n </button>\n\n <mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [ariaLabel]=\"_copy().table\"\n (afterOpened)=\"_onOpened()\"\n (afterClosed)=\"_onClosed()\"\n >\n <ng-template mlvPopupContent>\n <div #_panel class=\"mlv-editor-table__panel\">\n <div\n class=\"mlv-editor-table__grid\"\n role=\"grid\"\n tabindex=\"-1\"\n [attr.aria-label]=\"_copy().insertTable\"\n (keydown)=\"_onGridKeydown($event)\"\n >\n @for (row of _gridRows; track $index) {\n <div class=\"mlv-editor-table__grid-row\" role=\"row\">\n @for (size of row; track size.cols) {\n <button\n #_gridCell\n class=\"mlv-editor-table__grid-cell\"\n type=\"button\"\n role=\"gridcell\"\n [class.mlv-editor-table__grid-cell--selected]=\"\n _sizeSelected(size)\n \"\n [attr.aria-label]=\"_sizeLabel(size)\"\n [attr.aria-selected]=\"_sizeSelected(size)\"\n [attr.tabindex]=\"\n size.rows === _selectedSize().rows &&\n size.cols === _selectedSize().cols\n ? 0\n : -1\n \"\n [disabled]=\"_disabled()\"\n (focus)=\"_selectSize(size)\"\n (mouseenter)=\"_selectSize(size)\"\n (click)=\"_insertSize(size)\"\n ></button>\n }\n </div>\n }\n </div>\n\n <div class=\"mlv-editor-table__footer\">\n <span class=\"mlv-editor-table__size\" aria-hidden=\"true\">\n {{ _selectedSize().rows }} \u00D7 {{ _selectedSize().cols }}\n </span>\n <mlv-button-toggle\n [pressed]=\"_withHeaderRow()\"\n [disabled]=\"_disabled()\"\n (pressedChange)=\"_withHeaderRow.set($event)\"\n >\n {{ _copy().toggleHeaderRow }}\n </mlv-button-toggle>\n </div>\n </div>\n </ng-template>\n </mlv-popup>\n}\n", styles: ["@layer mlv.components{.mlv-editor-table{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-table *{box-sizing:border-box}.mlv-editor-table{display:inline-flex}.mlv-editor-table__panel{display:grid;width:max-content;max-width:calc(100vw - 3.5rem);padding:var(--mlv-popover-inset);gap:var(--mlv-spacing-2)}.mlv-editor-table__actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));width:min(24rem,100vw - 4rem);gap:var(--mlv-spacing-2)}.mlv-editor-table__grid{display:grid;grid-template-columns:1fr;gap:.125rem}.mlv-editor-table__grid-row{display:grid;grid-template-columns:repeat(10,1.25rem);gap:.125rem}.mlv-editor-table__grid-cell{appearance:none;box-sizing:border-box;inline-size:1.25rem;block-size:1.25rem;margin:0;padding:0;border:var(--mlv-stroke-width) solid var(--mlv-border-normal);border-radius:var(--mlv-radius-xs);background:var(--mlv-background-base);cursor:pointer;transition:background-color var(--mlv-duration-fast) var(--mlv-ease-default),border-color var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor-table__grid-cell--selected{border-color:var(--mlv-border-focus);background:var(--mlv-background-selected)}.mlv-editor-table__grid-cell:disabled{cursor:default;opacity:var(--mlv-disabled-opacity)}.mlv-editor-table__grid-cell:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-focus-ring-offset)}.mlv-editor-table__footer{display:flex;align-items:center;justify-content:space-between;gap:var(--mlv-spacing-3)}.mlv-editor-table__size{color:var(--mlv-text-secondary);font-size:var(--mlv-typography-body-s-size);font-variant-numeric:tabular-nums;white-space:nowrap}@media(prefers-reduced-motion:reduce){.mlv-editor-table,.mlv-editor-table *,.mlv-editor-table:before,.mlv-editor-table:after,[class^=mlv-editor-table__],[class*=\" mlv-editor-table__\"],[class^=mlv-editor-table--],[class*=\" mlv-editor-table--\"]{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:var(--mlv-duration-instant)!important}}}\n"], dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "component", type: MlvButtonToggle, selector: "mlv-button-toggle", inputs: ["pressed", "disabled", "variant", "shape", "mlvDensity", "ariaLabel", "ariaLabelledBy"], outputs: ["pressedChange"] }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideTable2, selector: "svg[lucideTable2]" }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }, { kind: "component", type: MlvPopup, selector: "mlv-popup", inputs: ["position", "positions", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "hasArrow", "hasShadow", "class", "mlvDensity", "flexibleDimensions", "scrollStrategy", "hasBackdrop", "restrictPosition", "panelRole", "modal", "ariaLabel", "dismissExcludeElements", "mobileMode", "mobileBreakpoint", "mobileTitle", "mobileCloseLabel", "opened"], outputs: ["openedChange", "afterOpened", "afterClosed"] }, { kind: "directive", type: MlvPopupContent, selector: "[mlvPopupContent]" }, { kind: "directive", type: MlvPopupTrigger, selector: "[mlvPopupTrigger]", inputs: ["mlvPopupTrigger", "triggerOn", "ariaHasPopup"], exportAs: ["mlvPopupTrigger"] }, { kind: "component", type: MlvDivider, selector: "mlv-divider", inputs: ["orientation", "dashed", "muted"] }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
8631
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8632
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorTable, isStandalone: true, selector: "mlv-editor-table", host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-table" }, viewQueries: [{ propertyName: "_popup", first: true, predicate: ["_popup"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: ["_trigger"], descendants: true, isSignal: true }, { propertyName: "_menu", first: true, predicate: ["_menu"], descendants: true, isSignal: true }, { propertyName: "_menuTrigger", first: true, predicate: MlvMenuTrigger, descendants: true, isSignal: true }, { propertyName: "_triggerElement", first: true, predicate: ["_triggerElement"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_panel", first: true, predicate: ["_panel"], descendants: true, isSignal: true }, { propertyName: "_firstAction", first: true, predicate: ["_firstAction"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "_gridCells", predicate: ["_gridCell"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "@if (_active()) {\n <button\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n selected\n [disabled]=\"_disabled()\"\n [mlvMenuTrigger]=\"_menu\"\n [menuTriggerDisabled]=\"_disabled()\"\n [attr.aria-label]=\"_copy().table\"\n [mlvTooltip]=\"_copy().table\"\n (menuOpened)=\"_registerMenuOverlay()\"\n (menuClosed)=\"_unregisterMenuOverlay()\"\n >\n <svg mlvButtonIcon lucideTable2 aria-hidden=\"true\" />\n </button>\n\n <mlv-menu #_menu [label]=\"_copy().table\">\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddRowBefore)\"\n (itemClick)=\"_run(_addRowBefore)\"\n >\n {{ _copy().addRowBefore }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddRowAfter)\"\n (itemClick)=\"_run(_addRowAfter)\"\n >\n {{ _copy().addRowAfter }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canDeleteRow)\"\n (itemClick)=\"_run(_deleteRow)\"\n >\n {{ _copy().deleteRow }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddColumnBefore)\"\n (itemClick)=\"_run(_addColumnBefore)\"\n >\n {{ _copy().addColumnBefore }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canAddColumnAfter)\"\n (itemClick)=\"_run(_addColumnAfter)\"\n >\n {{ _copy().addColumnAfter }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canDeleteColumn)\"\n (itemClick)=\"_run(_deleteColumn)\"\n >\n {{ _copy().deleteColumn }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canMergeCells)\"\n (itemClick)=\"_run(_mergeCells)\"\n >\n {{ _copy().mergeCells }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canSplitCell)\"\n (itemClick)=\"_run(_splitCell)\"\n >\n {{ _copy().splitCell }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canToggleHeaderRow)\"\n (itemClick)=\"_run(_toggleHeaderRow)\"\n >\n {{ _copy().toggleHeaderRow }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canToggleHeaderColumn)\"\n (itemClick)=\"_run(_toggleHeaderColumn)\"\n >\n {{ _copy().toggleHeaderColumn }}\n </mlv-list-item>\n <!-- `aria-current` marks the state the caret's cell is already in; the row\n paints itself from the shared selected pair. -->\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canToggleHeaderCell)\"\n [attr.aria-current]=\"_isHeaderCell() ? 'true' : null\"\n (itemClick)=\"_run(_toggleHeaderCell)\"\n >\n {{ _copy().toggleHeaderCell }}\n </mlv-list-item>\n\n <mlv-divider muted />\n\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_commandDisabled(_canDeleteTable)\"\n (itemClick)=\"_run(_deleteTable, true)\"\n >\n {{ _copy().deleteTable }}\n </mlv-list-item>\n </mlv-menu>\n} @else {\n <button\n #_trigger=\"mlvPopupTrigger\"\n #_triggerElement\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvPopupTrigger]=\"_popup\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_copy().table\"\n [mlvTooltip]=\"_copy().table\"\n >\n <svg mlvButtonIcon lucideTable2 aria-hidden=\"true\" />\n </button>\n\n <mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [ariaLabel]=\"_copy().table\"\n (afterOpened)=\"_onOpened()\"\n (afterClosed)=\"_onClosed()\"\n >\n <ng-template mlvPopupContent>\n <div #_panel class=\"mlv-editor-table__panel\">\n <div\n class=\"mlv-editor-table__grid\"\n role=\"grid\"\n tabindex=\"-1\"\n [attr.aria-label]=\"_copy().insertTable\"\n (keydown)=\"_onGridKeydown($event)\"\n >\n @for (row of _gridRows; track $index) {\n <div class=\"mlv-editor-table__grid-row\" role=\"row\">\n @for (size of row; track size.cols) {\n <button\n #_gridCell\n class=\"mlv-editor-table__grid-cell\"\n type=\"button\"\n role=\"gridcell\"\n [class.mlv-editor-table__grid-cell--selected]=\"\n _sizeSelected(size)\n \"\n [attr.aria-label]=\"_sizeLabel(size)\"\n [attr.aria-selected]=\"_sizeSelected(size)\"\n [attr.tabindex]=\"\n size.rows === _selectedSize().rows &&\n size.cols === _selectedSize().cols\n ? 0\n : -1\n \"\n [disabled]=\"_disabled()\"\n (focus)=\"_selectSize(size)\"\n (mouseenter)=\"_selectSize(size)\"\n (click)=\"_insertSize(size)\"\n ></button>\n }\n </div>\n }\n </div>\n\n <div class=\"mlv-editor-table__footer\">\n <span class=\"mlv-editor-table__size\" aria-hidden=\"true\">\n {{ _selectedSize().rows }} \u00D7 {{ _selectedSize().cols }}\n </span>\n <mlv-button-toggle\n [pressed]=\"_withHeaderRow()\"\n [disabled]=\"_disabled()\"\n (pressedChange)=\"_withHeaderRow.set($event)\"\n >\n {{ _copy().toggleHeaderRow }}\n </mlv-button-toggle>\n </div>\n </div>\n </ng-template>\n </mlv-popup>\n}\n", styles: ["@layer mlv.components{.mlv-editor-table{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-table *{box-sizing:border-box}.mlv-editor-table{display:inline-flex}.mlv-editor-table__panel{display:grid;width:max-content;max-width:calc(100vw - 3.5rem);padding:var(--mlv-popover-inset);gap:var(--mlv-spacing-2)}.mlv-editor-table__actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));width:min(24rem,100vw - 4rem);gap:var(--mlv-spacing-2)}.mlv-editor-table__grid{display:grid;grid-template-columns:1fr;gap:.125rem}.mlv-editor-table__grid-row{display:grid;grid-template-columns:repeat(10,1.25rem);gap:.125rem}.mlv-editor-table__grid-cell{appearance:none;box-sizing:border-box;inline-size:1.25rem;block-size:1.25rem;margin:0;padding:0;border:var(--mlv-stroke-width) solid var(--mlv-border-normal);border-radius:var(--mlv-radius-xs);background:var(--mlv-background-base);cursor:pointer;transition:background-color var(--mlv-duration-fast) var(--mlv-ease-default),border-color var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor-table__grid-cell--selected{border-color:var(--mlv-border-focus);background:var(--mlv-background-selected)}.mlv-editor-table__grid-cell:disabled{cursor:default;opacity:var(--mlv-disabled-opacity)}.mlv-editor-table__grid-cell:focus-visible{outline:var(--mlv-stroke-width-medium) solid var(--mlv-border-focus);outline-offset:var(--mlv-focus-ring-offset)}.mlv-editor-table__footer{display:flex;align-items:center;justify-content:space-between;gap:var(--mlv-spacing-3)}.mlv-editor-table__size{color:var(--mlv-text-secondary);font-size:var(--mlv-typography-body-s-size);font-variant-numeric:tabular-nums;white-space:nowrap}@media(prefers-reduced-motion:reduce){.mlv-editor-table,.mlv-editor-table *,.mlv-editor-table:before,.mlv-editor-table:after,[class^=mlv-editor-table__],[class*=\" mlv-editor-table__\"],[class^=mlv-editor-table--],[class*=\" mlv-editor-table--\"]{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:var(--mlv-duration-instant)!important}}}\n"], dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "component", type: MlvButtonToggle, selector: "mlv-button-toggle", inputs: ["pressed", "disabled", "variant", "shape", "mlvDensity", "ariaLabel", "ariaLabelledBy"], outputs: ["pressedChange"] }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideTable2, selector: "svg[lucideTable2]" }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }, { kind: "component", type: MlvPopup, selector: "mlv-popup", inputs: ["position", "positions", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "hasArrow", "hasShadow", "class", "mlvDensity", "flexibleDimensions", "scrollStrategy", "hasBackdrop", "restrictPosition", "panelRole", "modal", "ariaLabel", "dismissExcludeElements", "mobileMode", "mobileBreakpoint", "mobileTitle", "mobileCloseLabel", "opened"], outputs: ["openedChange", "afterOpened", "afterClosed"] }, { kind: "directive", type: MlvPopupContent, selector: "[mlvPopupContent]" }, { kind: "directive", type: MlvPopupTrigger, selector: "[mlvPopupTrigger]", inputs: ["mlvPopupTrigger", "triggerOn", "ariaHasPopup"], exportAs: ["mlvPopupTrigger"] }, { kind: "component", type: MlvDivider, selector: "mlv-divider", inputs: ["orientation", "dashed", "muted"] }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
7572
8633
|
}
|
|
7573
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
8634
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorTable, decorators: [{
|
|
7574
8635
|
type: Component,
|
|
7575
8636
|
args: [{ selector: 'mlv-editor-table', imports: [
|
|
7576
8637
|
MlvButton,
|
|
@@ -7753,21 +8814,24 @@ class MlvEditorTableControls {
|
|
|
7753
8814
|
...(ngDevMode ? [{ debugName: "_enabled" }] : /* istanbul ignore next */ []));
|
|
7754
8815
|
constructor() {
|
|
7755
8816
|
const destroyRef = inject(DestroyRef);
|
|
7756
|
-
|
|
7757
|
-
const onPointerLeave = () => this._release();
|
|
7758
|
-
// Registered on the document rather than on the editor DOM: the ProseMirror
|
|
8817
|
+
// Subscribed on the document rather than on the editor DOM: the ProseMirror
|
|
7759
8818
|
// element is replaced whenever the editor is recreated (a format switch, an
|
|
7760
8819
|
// extension-set change), and a listener bound to the old node would go
|
|
7761
|
-
// quiet without ever erroring. Capture is not needed — the events bubble
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
8820
|
+
// quiet without ever erroring. Capture is not needed — the events bubble,
|
|
8821
|
+
// and `passive` is carried through because neither handler calls
|
|
8822
|
+
// `preventDefault()`.
|
|
8823
|
+
//
|
|
8824
|
+
// The *injected* document, never the ambient global: this component is
|
|
8825
|
+
// constructed during server rendering too, where the two are different
|
|
8826
|
+
// objects, so the bare global would bind a per-render component to a
|
|
8827
|
+
// process-wide document that no teardown reaches.
|
|
8828
|
+
fromEvent(this._document, 'pointermove', { passive: true })
|
|
8829
|
+
.pipe(takeUntilDestroyed(destroyRef))
|
|
8830
|
+
.subscribe((event) => this._track(event));
|
|
8831
|
+
fromEvent(this._document, 'pointerleave', { passive: true })
|
|
8832
|
+
.pipe(takeUntilDestroyed(destroyRef))
|
|
8833
|
+
.subscribe(() => this._release());
|
|
8834
|
+
destroyRef.onDestroy(() => this._unregisterOverlay());
|
|
7771
8835
|
}
|
|
7772
8836
|
/** @protected Inline placement for one grip box. */
|
|
7773
8837
|
_style(box) {
|
|
@@ -7940,10 +9004,10 @@ class MlvEditorTableControls {
|
|
|
7940
9004
|
gripSize: GRIP_SIZE,
|
|
7941
9005
|
}));
|
|
7942
9006
|
}
|
|
7943
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
7944
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
9007
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorTableControls, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9008
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorTableControls, isStandalone: true, selector: "mlv-editor-table-controls", inputs: { layer: { classPropertyName: "layer", publicName: "layer", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, classAttribute: "mlv-editor-table-controls" }, ngImport: i0, template: "@if (_geometry(); as geometry) {\n <button\n class=\"mlv-editor-table-controls__grip mlv-editor-table-controls__grip--corner\"\n type=\"button\"\n tabindex=\"-1\"\n [style]=\"_style(geometry.corner)\"\n [mlvMenuTrigger]=\"_cornerMenu\"\n [attr.aria-label]=\"_copy().tableActions\"\n (menuOpened)=\"_openMenu(_cornerMenu)\"\n (menuClosed)=\"_closeMenu()\"\n >\n <svg lucideEllipsis [size]=\"10\" aria-hidden=\"true\" />\n </button>\n <mlv-menu #_cornerMenu [label]=\"_copy().tableActions\">\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canToggleHeaderRow)\"\n (itemClick)=\"_run(_toggleHeaderRow)\"\n >\n {{ _copy().toggleHeaderRow }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canToggleHeaderColumn)\"\n (itemClick)=\"_run(_toggleHeaderColumn)\"\n >\n {{ _copy().toggleHeaderColumn }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canToggleHeaderCell)\"\n (itemClick)=\"_run(_toggleHeaderCell)\"\n >\n {{ _copy().toggleHeaderCell }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canMergeCells)\"\n (itemClick)=\"_run(_mergeCells)\"\n >\n {{ _copy().mergeCells }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canSplitCell)\"\n (itemClick)=\"_run(_splitCell)\"\n >\n {{ _copy().splitCell }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canDeleteTable)\"\n (itemClick)=\"_run(_deleteTable)\"\n >\n {{ _copy().deleteTable }}\n </mlv-list-item>\n </mlv-menu>\n\n <button\n class=\"mlv-editor-table-controls__grip mlv-editor-table-controls__grip--column\"\n type=\"button\"\n tabindex=\"-1\"\n [style]=\"_style(geometry.column)\"\n [mlvMenuTrigger]=\"_columnMenu\"\n [attr.aria-label]=\"_copy().columnActions\"\n (menuOpened)=\"_openMenu(_columnMenu)\"\n (menuClosed)=\"_closeMenu()\"\n >\n <svg lucideGripHorizontal [size]=\"12\" aria-hidden=\"true\" />\n </button>\n <mlv-menu #_columnMenu [label]=\"_copy().columnActions\">\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canAddColumnBefore)\"\n (itemClick)=\"_run(_addColumnBefore)\"\n >\n {{ _copy().addColumnBefore }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canAddColumnAfter)\"\n (itemClick)=\"_run(_addColumnAfter)\"\n >\n {{ _copy().addColumnAfter }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canToggleHeaderColumn)\"\n (itemClick)=\"_run(_toggleHeaderColumn)\"\n >\n {{ _copy().toggleHeaderColumn }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canDeleteColumn)\"\n (itemClick)=\"_run(_deleteColumn)\"\n >\n {{ _copy().deleteColumn }}\n </mlv-list-item>\n </mlv-menu>\n\n <button\n class=\"mlv-editor-table-controls__grip mlv-editor-table-controls__grip--row\"\n type=\"button\"\n tabindex=\"-1\"\n [style]=\"_style(geometry.row)\"\n [mlvMenuTrigger]=\"_rowMenu\"\n [attr.aria-label]=\"_copy().rowActions\"\n (menuOpened)=\"_openMenu(_rowMenu)\"\n (menuClosed)=\"_closeMenu()\"\n >\n <svg lucideGripVertical [size]=\"12\" aria-hidden=\"true\" />\n </button>\n <mlv-menu #_rowMenu [label]=\"_copy().rowActions\">\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canAddRowBefore)\"\n (itemClick)=\"_run(_addRowBefore)\"\n >\n {{ _copy().addRowBefore }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canAddRowAfter)\"\n (itemClick)=\"_run(_addRowAfter)\"\n >\n {{ _copy().addRowAfter }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canToggleHeaderRow)\"\n (itemClick)=\"_run(_toggleHeaderRow)\"\n >\n {{ _copy().toggleHeaderRow }}\n </mlv-list-item>\n <mlv-list-item\n mlvMenuItem\n [disabled]=\"_disabled(_canDeleteRow)\"\n (itemClick)=\"_run(_deleteRow)\"\n >\n {{ _copy().deleteRow }}\n </mlv-list-item>\n </mlv-menu>\n}\n", styles: ["@layer mlv.components{.mlv-editor-table-controls{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-table-controls *{box-sizing:border-box}.mlv-editor-table-controls{display:contents;--mlv-editor-table-grip-size: 14px}.mlv-editor-table-controls__grip{position:absolute;display:flex;align-items:center;justify-content:center;padding:0;border:var(--mlv-stroke-width) solid var(--mlv-border-subtle);border-radius:var(--mlv-radius-xs);background:var(--mlv-background-neutral-1);color:var(--mlv-text-secondary);cursor:pointer;z-index:1;transition:background-color var(--mlv-duration-fast) var(--mlv-ease-default),color var(--mlv-duration-fast) var(--mlv-ease-default)}.mlv-editor-table-controls__grip:hover{background:var(--mlv-background-neutral-1-hover);color:var(--mlv-text-primary)}.mlv-editor-table-controls__grip[aria-expanded=true]{background:var(--mlv-background-selected);color:var(--mlv-text-on-selected)}.mlv-editor-table-controls__grip--corner svg{opacity:.75}@media(prefers-reduced-motion:reduce){.mlv-editor-table-controls,.mlv-editor-table-controls *,.mlv-editor-table-controls:before,.mlv-editor-table-controls:after,[class^=mlv-editor-table-controls__],[class*=\" mlv-editor-table-controls__\"],[class^=mlv-editor-table-controls--],[class*=\" mlv-editor-table-controls--\"]{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:var(--mlv-duration-instant)!important}}}\n"], dependencies: [{ kind: "component", type: LucideEllipsis, selector: "svg[lucideEllipsis], svg[lucideMoreHorizontal]" }, { kind: "component", type: LucideGripHorizontal, selector: "svg[lucideGripHorizontal]" }, { kind: "component", type: LucideGripVertical, selector: "svg[lucideGripVertical]" }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
7945
9009
|
}
|
|
7946
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9010
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorTableControls, decorators: [{
|
|
7947
9011
|
type: Component,
|
|
7948
9012
|
args: [{ selector: 'mlv-editor-table-controls', imports: [
|
|
7949
9013
|
LucideEllipsis,
|
|
@@ -7969,10 +9033,10 @@ class MlvEditorToolbarDef {
|
|
|
7969
9033
|
static ngTemplateContextGuard(_dir, _context) {
|
|
7970
9034
|
return true;
|
|
7971
9035
|
}
|
|
7972
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
7973
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
9036
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarDef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9037
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorToolbarDef, isStandalone: true, selector: "[mlvEditorToolbar]", ngImport: i0 });
|
|
7974
9038
|
}
|
|
7975
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9039
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarDef, decorators: [{
|
|
7976
9040
|
type: Directive,
|
|
7977
9041
|
args: [{
|
|
7978
9042
|
selector: '[mlvEditorToolbar]',
|
|
@@ -7988,10 +9052,10 @@ class MlvEditorToolbarStartDef {
|
|
|
7988
9052
|
static ngTemplateContextGuard(_dir, _context) {
|
|
7989
9053
|
return true;
|
|
7990
9054
|
}
|
|
7991
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
7992
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
9055
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarStartDef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9056
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorToolbarStartDef, isStandalone: true, selector: "[mlvEditorToolbarStart]", ngImport: i0 });
|
|
7993
9057
|
}
|
|
7994
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9058
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarStartDef, decorators: [{
|
|
7995
9059
|
type: Directive,
|
|
7996
9060
|
args: [{
|
|
7997
9061
|
selector: '[mlvEditorToolbarStart]',
|
|
@@ -8007,10 +9071,10 @@ class MlvEditorToolbarEndDef {
|
|
|
8007
9071
|
static ngTemplateContextGuard(_dir, _context) {
|
|
8008
9072
|
return true;
|
|
8009
9073
|
}
|
|
8010
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
8011
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.
|
|
9074
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarEndDef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9075
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorToolbarEndDef, isStandalone: true, selector: "[mlvEditorToolbarEnd]", ngImport: i0 });
|
|
8012
9076
|
}
|
|
8013
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9077
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarEndDef, decorators: [{
|
|
8014
9078
|
type: Directive,
|
|
8015
9079
|
args: [{
|
|
8016
9080
|
selector: '[mlvEditorToolbarEnd]',
|
|
@@ -8039,8 +9103,8 @@ class MlvEditorUndoRedo {
|
|
|
8039
9103
|
_undo = (editor) => editor.chain().focus().undo().run();
|
|
8040
9104
|
/** @protected Selection-restoring redo command. */
|
|
8041
9105
|
_redo = (editor) => editor.chain().focus().redo().run();
|
|
8042
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
8043
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.
|
|
9106
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorUndoRedo, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9107
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorUndoRedo, isStandalone: true, selector: "mlv-editor-undo-redo", host: { attributes: { "role": "group" }, classAttribute: "mlv-editor-undo-redo" }, ngImport: i0, template: `
|
|
8044
9108
|
<mlv-editor-command-button
|
|
8045
9109
|
[label]="_copy().undo"
|
|
8046
9110
|
[supports]="_canUndo"
|
|
@@ -8057,7 +9121,7 @@ class MlvEditorUndoRedo {
|
|
|
8057
9121
|
/></mlv-editor-command-button>
|
|
8058
9122
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvEditorCommandButton, selector: "mlv-editor-command-button", inputs: ["label", "supports", "command", "canCommand", "pressed"] }, { kind: "component", type: LucideRedo2, selector: "svg[lucideRedo2]" }, { kind: "component", type: LucideUndo2, selector: "svg[lucideUndo2]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
8059
9123
|
}
|
|
8060
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9124
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorUndoRedo, decorators: [{
|
|
8061
9125
|
type: Component,
|
|
8062
9126
|
args: [{
|
|
8063
9127
|
selector: 'mlv-editor-undo-redo',
|
|
@@ -8428,10 +9492,10 @@ class MlvEditorZoom {
|
|
|
8428
9492
|
const finite = Number.isFinite(value) ? value : DEFAULT_ZOOM;
|
|
8429
9493
|
return Math.min(Math.max(finite, min), max);
|
|
8430
9494
|
}
|
|
8431
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
8432
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.
|
|
9495
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorZoom, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9496
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.7", type: MlvEditorZoom, isStandalone: true, selector: "mlv-editor-zoom", inputs: { zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, zoomLevels: { classPropertyName: "zoomLevels", publicName: "zoomLevels", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, fitToContainer: { classPropertyName: "fitToContainer", publicName: "fitToContainer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zoom: "zoomChange" }, host: { classAttribute: "mlv-editor-zoom" }, providers: [MlvSelectionService], viewQueries: [{ propertyName: "_popup", first: true, predicate: ["_popup"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: ["_trigger"], descendants: true, isSignal: true }, { propertyName: "_input", first: true, predicate: ["_input"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<button\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_zoomOutDisabled()\"\n [attr.aria-label]=\"_copy().zoomOut\"\n [mlvTooltip]=\"_copy().zoomOut\"\n (click)=\"_zoomOut()\"\n>\n <svg mlvButtonIcon lucideZoomOut aria-hidden=\"true\" />\n</button>\n\n<button\n #_trigger=\"mlvPopupTrigger\"\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_disabled()\"\n [mlvPopupTrigger]=\"_popup\"\n [ariaHasPopup]=\"'dialog'\"\n [attr.aria-label]=\"_copy().zoom\"\n [mlvTooltip]=\"_copy().zoom\"\n>\n {{ zoom() }}%\n</button>\n\n<button\n mlvButton\n mlvEditorToolbarWidget\n type=\"button\"\n shape=\"square\"\n mlvDensity=\"tight\"\n variant=\"transparent\"\n [disabled]=\"_zoomInDisabled()\"\n [attr.aria-label]=\"_copy().zoomIn\"\n [mlvTooltip]=\"_copy().zoomIn\"\n (click)=\"_zoomIn()\"\n>\n <svg mlvButtonIcon lucideZoomIn aria-hidden=\"true\" />\n</button>\n\n<mlv-popup\n #_popup\n panelRole=\"dialog\"\n [modal]=\"true\"\n [ariaLabel]=\"_copy().zoom\"\n (afterOpened)=\"_onPopupOpened()\"\n (afterClosed)=\"_onPopupClosed()\"\n>\n <ng-template mlvPopupContent>\n <div [id]=\"_panelId\" class=\"mlv-editor-zoom__panel\">\n <div class=\"mlv-editor-zoom__field\">\n <mlv-input\n #_input\n type=\"number\"\n inputMode=\"numeric\"\n [ariaLabel]=\"_copy().zoom\"\n [min]=\"_bounds().min\"\n [max]=\"_bounds().max\"\n [disabled]=\"_disabled()\"\n [value]=\"_draft()\"\n (valueChange)=\"_draft.set($event)\"\n (keydown.enter)=\"_applyDraft($event)\"\n (inputBlur)=\"_applyDraft()\"\n />\n </div>\n <mlv-dropdown-panel\n class=\"mlv-editor-zoom__levels\"\n [options]=\"_levelOptions()\"\n [selectedValues]=\"_selectedLevels()\"\n [ariaLabel]=\"_copy().zoom\"\n [maxHeight]=\"_PANEL_MAX_HEIGHT\"\n (valueChange)=\"_selectLevel($event)\"\n />\n </div>\n </ng-template>\n</mlv-popup>\n", styles: ["@layer mlv.components{.mlv-editor-zoom{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-typography-body-m-size)}.mlv-editor-zoom *{box-sizing:border-box}.mlv-editor-zoom{display:inline-flex;align-items:center;gap:var(--mlv-spacing-1);white-space:nowrap}.mlv-editor-zoom__panel{display:grid;inline-size:11rem;padding:var(--mlv-popover-inset);gap:var(--mlv-spacing-1)}.mlv-editor-zoom__field,.mlv-editor-zoom__levels{display:block}.mlv-editor-zoom__levels.mlv-dropdown-panel .mlv-dropdown-panel__listbox{--mlv-list-padding-block: 0}}\n"], dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideZoomIn, selector: "svg[lucideZoomIn]" }, { kind: "component", type: LucideZoomOut, selector: "svg[lucideZoomOut]" }, { kind: "component", type: MlvDropdownPanel, selector: "mlv-dropdown-panel", inputs: ["scrollMode", "minHeight", "maxHeight", "options", "multiple", "selectedValues", "compareWith", "itemTemplate", "focusMode", "activeIndex", "listboxId", "ariaLabel", "highlightQuery", "loading", "loadingText", "loadingMore", "hasMore", "infiniteScrollThreshold"], outputs: ["loadMore", "valueChange"] }, { kind: "component", type: MlvInput, selector: "mlv-input", inputs: ["type", "placeholder", "autocomplete", "inputMode", "maxLength", "minLength", "pattern", "name", "autofocus", "min", "max", "step", "bare", "projectControl", "role", "ariaExpanded", "ariaHasPopup", "ariaAutocomplete", "ariaControls", "ariaActiveDescendant", "ariaDescribedBy", "value"], outputs: ["valueChange", "inputFocus", "inputBlur"] }, { kind: "component", type: MlvPopup, selector: "mlv-popup", inputs: ["position", "positions", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "hasArrow", "hasShadow", "class", "mlvDensity", "flexibleDimensions", "scrollStrategy", "hasBackdrop", "restrictPosition", "panelRole", "modal", "ariaLabel", "dismissExcludeElements", "mobileMode", "mobileBreakpoint", "mobileTitle", "mobileCloseLabel", "opened"], outputs: ["openedChange", "afterOpened", "afterClosed"] }, { kind: "directive", type: MlvPopupContent, selector: "[mlvPopupContent]" }, { kind: "directive", type: MlvPopupTrigger, selector: "[mlvPopupTrigger]", inputs: ["mlvPopupTrigger", "triggerOn", "ariaHasPopup"], exportAs: ["mlvPopupTrigger"] }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
8433
9497
|
}
|
|
8434
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9498
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorZoom, decorators: [{
|
|
8435
9499
|
type: Component,
|
|
8436
9500
|
args: [{ selector: 'mlv-editor-zoom', imports: [
|
|
8437
9501
|
MlvButton,
|
|
@@ -8477,8 +9541,8 @@ class MlvEditorTextColor extends MlvEditorColorControl {
|
|
|
8477
9541
|
const chain = editor.chain().setTextSelection(selection);
|
|
8478
9542
|
return color ? chain.setColor(color).run() : chain.unsetColor().run();
|
|
8479
9543
|
}
|
|
8480
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
8481
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.
|
|
9544
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorTextColor, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
9545
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: MlvEditorTextColor, isStandalone: true, selector: "mlv-editor-text-color", host: { properties: { "hidden": "!_supported()" }, classAttribute: "mlv-editor-text-color" }, usesInheritance: true, ngImport: i0, template: `
|
|
8482
9546
|
<mlv-color-picker-popup
|
|
8483
9547
|
#picker
|
|
8484
9548
|
presentation="icon"
|
|
@@ -8495,7 +9559,7 @@ class MlvEditorTextColor extends MlvEditorColorControl {
|
|
|
8495
9559
|
</mlv-color-picker-popup>
|
|
8496
9560
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvColorPickerPopup, selector: "mlv-color-picker-popup", inputs: ["value", "presentation", "opened", "showOpacity", "defaultMode", "supportedFormats", "live"], outputs: ["valueChange", "openedChange", "afterOpened", "afterClosed", "colorChange"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "component", type: LucideType, selector: "svg[lucideType]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
8497
9561
|
}
|
|
8498
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9562
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorTextColor, decorators: [{
|
|
8499
9563
|
type: Component,
|
|
8500
9564
|
args: [{
|
|
8501
9565
|
selector: 'mlv-editor-text-color',
|
|
@@ -8540,6 +9604,16 @@ class MlvEditorToolbarRoot {
|
|
|
8540
9604
|
...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
|
|
8541
9605
|
/** Whether arrow navigation wraps at the boundaries. */
|
|
8542
9606
|
wrap = input(true, { ...(ngDevMode ? { debugName: "wrap" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
9607
|
+
/**
|
|
9608
|
+
* @internal Element whose width decides narrow mode, instead of this root's
|
|
9609
|
+
* own. `MlvEditor` passes its `.mlv-editor__surface`, for the docked bar
|
|
9610
|
+
* and the selection bubble alike. The bubble hugs its controls, so measuring
|
|
9611
|
+
* itself would be circular: hiding groups shrinks the bubble, which
|
|
9612
|
+
* un-narrows it. `undefined` observes this root, which the standalone
|
|
9613
|
+
* `MlvEditorToolbar` shell keeps doing.
|
|
9614
|
+
*/
|
|
9615
|
+
measureTarget = input(undefined, /* @ts-ignore */
|
|
9616
|
+
...(ngDevMode ? [{ debugName: "measureTarget" }] : /* istanbul ignore next */ []));
|
|
8543
9617
|
/** @internal Editor-scoped focus registry. */
|
|
8544
9618
|
_registry = inject(MLV_EDITOR_TOOLBAR_ROVING);
|
|
8545
9619
|
/** @internal Transaction state that re-evaluates disabled toolbar widgets. */
|
|
@@ -8548,7 +9622,10 @@ class MlvEditorToolbarRoot {
|
|
|
8548
9622
|
});
|
|
8549
9623
|
/** @internal Optional localized defaults. */
|
|
8550
9624
|
_i18n = inject(MLV_EDITOR_I18N, { optional: true });
|
|
8551
|
-
/**
|
|
9625
|
+
/**
|
|
9626
|
+
* @internal Actual composite-root element. Also the scope the horizontal
|
|
9627
|
+
* roving arrows resolve their direction against.
|
|
9628
|
+
*/
|
|
8552
9629
|
_element = inject(ElementRef);
|
|
8553
9630
|
/** @internal Root teardown lifecycle. */
|
|
8554
9631
|
_destroyRef = inject(DestroyRef);
|
|
@@ -8558,6 +9635,12 @@ class MlvEditorToolbarRoot {
|
|
|
8558
9635
|
_resizeObserver = inject(MlvResizeObserverService);
|
|
8559
9636
|
/** @internal Normalizes horizontal arrow meaning for RTL toolbars. */
|
|
8560
9637
|
_rtlService = inject(MlvRtlService);
|
|
9638
|
+
/**
|
|
9639
|
+
* @internal Direction applying to this toolbar, resolved once and cached
|
|
9640
|
+
* behind the shared `dir` observer rather than re-walked on every arrow
|
|
9641
|
+
* keypress.
|
|
9642
|
+
*/
|
|
9643
|
+
_direction = this._rtlService.elementDirection(this._element);
|
|
8561
9644
|
constructor() {
|
|
8562
9645
|
effect(() => {
|
|
8563
9646
|
this._revision?.();
|
|
@@ -8565,15 +9648,23 @@ class MlvEditorToolbarRoot {
|
|
|
8565
9648
|
});
|
|
8566
9649
|
if (this._isBrowser) {
|
|
8567
9650
|
this._destroyRef.onDestroy(this._registry.connect(this._element.nativeElement));
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
9651
|
+
}
|
|
9652
|
+
effect((onCleanup) => {
|
|
9653
|
+
if (!this._isBrowser)
|
|
9654
|
+
return;
|
|
9655
|
+
const target = this.measureTarget() ?? this._element.nativeElement;
|
|
9656
|
+
// Re-created whenever the target changes, so it is released by this
|
|
9657
|
+
// effect's cleanup; `takeUntilDestroyed` would fire only at destroy and
|
|
9658
|
+
// leak every earlier generation (best-practices, "DOM Listeners").
|
|
9659
|
+
const subscription = this._resizeObserver
|
|
9660
|
+
.observe(target)
|
|
8571
9661
|
.subscribe((entries) => {
|
|
8572
9662
|
const width = entries[entries.length - 1]?.contentRect.width;
|
|
8573
9663
|
if (width !== undefined && width > 0)
|
|
8574
9664
|
this.narrow.set(width < 640);
|
|
8575
9665
|
});
|
|
8576
|
-
|
|
9666
|
+
onCleanup(() => subscription.unsubscribe());
|
|
9667
|
+
});
|
|
8577
9668
|
}
|
|
8578
9669
|
/** @internal Resolves the user or localized toolbar label. */
|
|
8579
9670
|
resolvedAriaLabel() {
|
|
@@ -8591,7 +9682,10 @@ class MlvEditorToolbarRoot {
|
|
|
8591
9682
|
this._registry.focusBoundary(event.key === 'Home' ? 'start' : 'end');
|
|
8592
9683
|
return;
|
|
8593
9684
|
}
|
|
8594
|
-
|
|
9685
|
+
// Resolved against the toolbar root, not the document: direction is scoped,
|
|
9686
|
+
// so a toolbar inside a `dir` subtree — or inside a CDK overlay pane, which
|
|
9687
|
+
// is stamped with its own `dir` — must mirror on its own reading.
|
|
9688
|
+
const key = this._rtlService.normalizeArrowKey(event, this._direction());
|
|
8595
9689
|
const direction = this.orientation() === 'vertical'
|
|
8596
9690
|
? key === UP_ARROW
|
|
8597
9691
|
? -1
|
|
@@ -8608,10 +9702,10 @@ class MlvEditorToolbarRoot {
|
|
|
8608
9702
|
event.preventDefault();
|
|
8609
9703
|
this._registry.move(target, direction, this.wrap());
|
|
8610
9704
|
}
|
|
8611
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
8612
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.
|
|
9705
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9706
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: MlvEditorToolbarRoot, isStandalone: true, selector: "[mlvEditorToolbarRoot]", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "wrap", isSignal: true, isRequired: false, transformFunction: null }, measureTarget: { classPropertyName: "measureTarget", publicName: "measureTarget", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "toolbar" }, listeners: { "keydown": "handleKeydown($event)" }, properties: { "class.mlv-editor-toolbar--narrow": "narrow()", "attr.aria-label": "resolvedAriaLabel()", "attr.aria-orientation": "orientation()", "attr.aria-disabled": "disabled() || null" }, classAttribute: "mlv-editor-toolbar" }, exportAs: ["mlvEditorToolbarRoot"], ngImport: i0 });
|
|
8613
9707
|
}
|
|
8614
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9708
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarRoot, decorators: [{
|
|
8615
9709
|
type: Directive,
|
|
8616
9710
|
args: [{
|
|
8617
9711
|
selector: '[mlvEditorToolbarRoot]',
|
|
@@ -8626,7 +9720,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
8626
9720
|
'(keydown)': 'handleKeydown($event)',
|
|
8627
9721
|
},
|
|
8628
9722
|
}]
|
|
8629
|
-
}], ctorParameters: () => [], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], wrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrap", required: false }] }] } });
|
|
9723
|
+
}], ctorParameters: () => [], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], wrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrap", required: false }] }], measureTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "measureTarget", required: false }] }] } });
|
|
8630
9724
|
/** @internal Responsive menu containing commands removed from the primary row. */
|
|
8631
9725
|
class MlvEditorToolbarOverflow {
|
|
8632
9726
|
/** @protected Responsive state owned by the enclosing toolbar root. */
|
|
@@ -8777,8 +9871,8 @@ class MlvEditorToolbarOverflow {
|
|
|
8777
9871
|
this._unregister?.();
|
|
8778
9872
|
this._unregister = undefined;
|
|
8779
9873
|
}
|
|
8780
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
8781
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
9874
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarOverflow, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9875
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorToolbarOverflow, isStandalone: true, selector: "mlv-editor-toolbar-overflow", host: { properties: { "hidden": "!_root.narrow()" }, classAttribute: "mlv-editor-toolbar__overflow" }, viewQueries: [{ propertyName: "_menu", first: true, predicate: ["_menu"], descendants: true, isSignal: true }, { propertyName: "_trigger", first: true, predicate: MlvMenuTrigger, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
8782
9876
|
<button
|
|
8783
9877
|
mlvButton
|
|
8784
9878
|
mlvEditorToolbarWidget
|
|
@@ -8876,7 +9970,7 @@ class MlvEditorToolbarOverflow {
|
|
|
8876
9970
|
</mlv-menu>
|
|
8877
9971
|
`, isInline: true, dependencies: [{ kind: "component", type: MlvButton, selector: "button[mlvButton], a[mlvButton]", inputs: ["variant", "shape", "disabled", "loading", "selected"] }, { kind: "directive", type: MlvButtonIcon, selector: "[mlvButtonIcon]" }, { kind: "directive", type: MlvTooltip, selector: "[mlvTooltip]", inputs: ["mlvTooltip", "tooltipPlacement", "tooltipTone", "tooltipDelay", "tooltipDisabled", "tooltipArrow"] }, { kind: "component", type: LucideEllipsis, selector: "svg[lucideEllipsis], svg[lucideMoreHorizontal]" }, { kind: "component", type: MlvListItem, selector: "mlv-list-item", inputs: ["itemRole", "unread", "accent"] }, { kind: "component", type: MlvMenu, selector: "mlv-menu", inputs: ["label", "mlvDensity", "dataSource"], outputs: ["closed"] }, { kind: "directive", type: MlvMenuItem, selector: "mlv-list-item[mlvMenuItem]", inputs: ["disabled"], outputs: ["itemClick"] }, { kind: "directive", type: MlvMenuTrigger, selector: "[mlvMenuTrigger]", inputs: ["mlvMenuTrigger", "isSubmenuTrigger", "menuTriggerDisabled"], outputs: ["menuOpened", "menuClosed"] }, { kind: "directive", type: MlvEditorToolbarWidget, selector: "[mlvEditorToolbarWidget]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
8878
9972
|
}
|
|
8879
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
9973
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarOverflow, decorators: [{
|
|
8880
9974
|
type: Component,
|
|
8881
9975
|
args: [{
|
|
8882
9976
|
selector: 'mlv-editor-toolbar-overflow',
|
|
@@ -9047,10 +10141,10 @@ class MlvEditorToolbarContextProxy {
|
|
|
9047
10141
|
reportError(error) {
|
|
9048
10142
|
this._toolbar.context().reportError(error);
|
|
9049
10143
|
}
|
|
9050
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
9051
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.
|
|
10144
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarContextProxy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10145
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarContextProxy });
|
|
9052
10146
|
}
|
|
9053
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
10147
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbarContextProxy, decorators: [{
|
|
9054
10148
|
type: Injectable
|
|
9055
10149
|
}] });
|
|
9056
10150
|
/** Public compatibility toolbar shell for standalone consumer use. */
|
|
@@ -9086,8 +10180,8 @@ class MlvEditorToolbar {
|
|
|
9086
10180
|
});
|
|
9087
10181
|
});
|
|
9088
10182
|
}
|
|
9089
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
9090
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
10183
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10184
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorToolbar, isStandalone: true, selector: "mlv-editor-toolbar", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, startTemplate: { classPropertyName: "startTemplate", publicName: "startTemplate", isSignal: true, isRequired: false, transformFunction: null }, endTemplate: { classPropertyName: "endTemplate", publicName: "endTemplate", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class.mlv-editor-toolbar--disabled": "disabled() || context().disabled()" }, classAttribute: "mlv-editor-toolbar" }, providers: [
|
|
9091
10185
|
MlvEditorOverlayRegistry,
|
|
9092
10186
|
MlvEditorToolbarRevision,
|
|
9093
10187
|
MlvEditorToolbarRovingRegistry,
|
|
@@ -9192,9 +10286,9 @@ class MlvEditorToolbar {
|
|
|
9192
10286
|
/>
|
|
9193
10287
|
}
|
|
9194
10288
|
<ng-content select="[mlvEditorToolbarEnd]" /><ng-content />
|
|
9195
|
-
</div>`, isInline: true, styles: ["@layer mlv.components{.mlv-editor-toolbar{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-typography-body-m-size)}.mlv-editor-toolbar *{box-sizing:border-box}.mlv-editor-toolbar{display:flex;align-items:center;min-width:0;overflow:hidden}.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-toolbar__separator{flex:0 0 auto;align-self:stretch;min-height:var(--mlv-height-s);margin-inline:var(--mlv-spacing-1)}.mlv-editor-toolbar__overflow,.mlv-editor-toolbar .mlv-editor-undo-redo,.mlv-editor-toolbar .mlv-editor-inline-marks,.mlv-editor-toolbar .mlv-editor-block-insert{display:inline-flex;flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor-toolbar mlv-editor-zoom,.mlv-editor-toolbar mlv-editor-heading,.mlv-editor-toolbar mlv-editor-list,.mlv-editor-toolbar mlv-editor-text-color,.mlv-editor-toolbar mlv-editor-highlight,.mlv-editor-toolbar mlv-editor-alignment,.mlv-editor-toolbar mlv-editor-link,.mlv-editor-toolbar mlv-editor-table,.mlv-editor-toolbar mlv-editor-image-upload{flex:0 0 auto}.mlv-editor-toolbar--disabled{opacity:var(--mlv-disabled-opacity)}}\n"], dependencies: [{ 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: 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: 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: 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: MlvEditorToolbarOverflow, selector: "mlv-editor-toolbar-overflow" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
10289
|
+
</div>`, isInline: true, styles: ["@layer mlv.components{.mlv-editor-toolbar{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-typography-body-m-size)}.mlv-editor-toolbar *{box-sizing:border-box}.mlv-editor-toolbar{display:flex;align-items:center;min-width:0;overflow:hidden}.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-toolbar__separator{flex:0 0 auto;align-self:stretch;min-height:var(--mlv-height-s);margin-inline:var(--mlv-spacing-1)}.mlv-editor-toolbar__overflow,.mlv-editor-toolbar .mlv-editor-undo-redo,.mlv-editor-toolbar .mlv-editor-inline-marks,.mlv-editor-toolbar .mlv-editor-block-insert{display:inline-flex;flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor-toolbar mlv-editor-zoom,.mlv-editor-toolbar mlv-editor-heading,.mlv-editor-toolbar mlv-editor-list,.mlv-editor-toolbar mlv-editor-text-color,.mlv-editor-toolbar mlv-editor-highlight,.mlv-editor-toolbar mlv-editor-alignment,.mlv-editor-toolbar mlv-editor-link,.mlv-editor-toolbar mlv-editor-table,.mlv-editor-toolbar mlv-editor-image-upload{flex:0 0 auto}.mlv-editor-toolbar--disabled{opacity:var(--mlv-disabled-opacity)}}\n"], dependencies: [{ 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", "measureTarget"], exportAs: ["mlvEditorToolbarRoot"] }, { 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: 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: 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: MlvEditorToolbarOverflow, selector: "mlv-editor-toolbar-overflow" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
9196
10290
|
}
|
|
9197
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
10291
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorToolbar, decorators: [{
|
|
9198
10292
|
type: Component,
|
|
9199
10293
|
args: [{ selector: 'mlv-editor-toolbar', host: {
|
|
9200
10294
|
class: 'mlv-editor-toolbar',
|
|
@@ -9375,15 +10469,15 @@ class MlvEditorStatus {
|
|
|
9375
10469
|
return typeof storage?.characters === 'function' ? storage : null;
|
|
9376
10470
|
}, /* @ts-ignore */
|
|
9377
10471
|
...(ngDevMode ? [{ debugName: "_storage" }] : /* istanbul ignore next */ []));
|
|
9378
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
9379
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
10472
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorStatus, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10473
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: MlvEditorStatus, isStandalone: true, selector: "mlv-editor-status", inputs: { characterLimit: { classPropertyName: "characterLimit", publicName: "characterLimit", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "hidden": "!available()" }, classAttribute: "mlv-editor-status" }, ngImport: i0, template: "@if (available()) {\n <span\n class=\"mlv-editor-status__summary\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"_ariaLabel()\"\n >\n @if (_limit(); as limit) {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }}/{{ limit }} characters</span\n >\n } @else {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }} characters</span\n >\n }\n <span aria-hidden=\"true\"> \u00B7 </span>\n <span class=\"mlv-editor-status__words\">{{ words() }} words</span>\n </span>\n}\n", styles: ["@layer mlv.components{.mlv-editor-status{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-status *{box-sizing:border-box}.mlv-editor-status{display:inline-flex;color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}.mlv-editor-status__summary{display:inline-flex;gap:var(--mlv-spacing-1)}.mlv-editor-status__summary *{color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
9380
10474
|
}
|
|
9381
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
10475
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditorStatus, decorators: [{
|
|
9382
10476
|
type: Component,
|
|
9383
10477
|
args: [{ selector: 'mlv-editor-status', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
9384
10478
|
class: 'mlv-editor-status',
|
|
9385
10479
|
'[hidden]': '!available()',
|
|
9386
|
-
}, template: "@if (available()) {\n<span\n
|
|
10480
|
+
}, template: "@if (available()) {\n <span\n class=\"mlv-editor-status__summary\"\n role=\"status\"\n aria-live=\"polite\"\n [attr.aria-label]=\"_ariaLabel()\"\n >\n @if (_limit(); as limit) {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }}/{{ limit }} characters</span\n >\n } @else {\n <span class=\"mlv-editor-status__characters\"\n >{{ characters() }} characters</span\n >\n }\n <span aria-hidden=\"true\"> \u00B7 </span>\n <span class=\"mlv-editor-status__words\">{{ words() }} words</span>\n </span>\n}\n", styles: ["@layer mlv.components{.mlv-editor-status{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-status *{box-sizing:border-box}.mlv-editor-status{display:inline-flex;color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}.mlv-editor-status__summary{display:inline-flex;gap:var(--mlv-spacing-1)}.mlv-editor-status__summary *{color:var(--mlv-text-secondary);font-size:var(--mlv-typography-caption-size);line-height:var(--mlv-typography-caption-line-height)}}\n"] }]
|
|
9387
10481
|
}], propDecorators: { characterLimit: [{ type: i0.Input, args: [{ isSignal: true, alias: "characterLimit", required: false }] }] } });
|
|
9388
10482
|
|
|
9389
10483
|
/**
|
|
@@ -9406,6 +10500,87 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9406
10500
|
/** Width of the centred content column; a gutter is reserved at every value. */
|
|
9407
10501
|
contentWidth = input('default', /* @ts-ignore */
|
|
9408
10502
|
...(ngDevMode ? [{ debugName: "contentWidth" }] : /* istanbul ignore next */ []));
|
|
10503
|
+
/**
|
|
10504
|
+
* Fixed block size of the editor surface (toolbar plus content viewport).
|
|
10505
|
+
* A number is px; a string is any CSS length, passed through verbatim.
|
|
10506
|
+
*
|
|
10507
|
+
* Setting it **caps** the editor: `.mlv-editor__viewport` becomes the only
|
|
10508
|
+
* scroll container. With neither `height` nor `maxHeight`, the editor grows
|
|
10509
|
+
* with its content, never shows a scrollbar, and never stops a scroll meant
|
|
10510
|
+
* for the page. Writing `--mlv-editor-height` in CSS alone does not cap.
|
|
10511
|
+
*/
|
|
10512
|
+
height = input(undefined, /* @ts-ignore */
|
|
10513
|
+
...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
|
|
10514
|
+
/**
|
|
10515
|
+
* Minimum block size of the editable content area; the viewport adds its
|
|
10516
|
+
* 1rem padding around it. A number is px; a string is any CSS length. `undefined` keeps the `8rem` floor. Setting only this input
|
|
10517
|
+
* leaves the editor in auto mode. `--mlv-editor-min-height` may also be set
|
|
10518
|
+
* in CSS.
|
|
10519
|
+
*
|
|
10520
|
+
* Under a cap (`height` / `maxHeight`) the cap wins, even over a larger
|
|
10521
|
+
* `minHeight`: the viewport shrinks to fit the surface, and the floor moves
|
|
10522
|
+
* to the content inside the scroller, at every zoom level. A `minHeight`
|
|
10523
|
+
* above what the cap leaves the content (the cap minus the toolbar band and
|
|
10524
|
+
* the viewport padding) scrolls an empty document; for a fixed size set
|
|
10525
|
+
* `height` rather than `minHeight` equal to `maxHeight`.
|
|
10526
|
+
*/
|
|
10527
|
+
minHeight = input(undefined, /* @ts-ignore */
|
|
10528
|
+
...(ngDevMode ? [{ debugName: "minHeight" }] : /* istanbul ignore next */ []));
|
|
10529
|
+
/**
|
|
10530
|
+
* Largest block size of the editor surface. The surface grows with its
|
|
10531
|
+
* content up to this cap, and then the viewport scrolls. A number is px; a
|
|
10532
|
+
* string is any CSS length. Like `height`, this caps the editor; writing
|
|
10533
|
+
* `--mlv-editor-max-height` in CSS alone does not.
|
|
10534
|
+
*/
|
|
10535
|
+
maxHeight = input(undefined, /* @ts-ignore */
|
|
10536
|
+
...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
|
|
10537
|
+
/**
|
|
10538
|
+
* Docked-bar placement. The DOM order follows it, so the Tab order matches
|
|
10539
|
+
* the visual order (WCAG 2.4.3). Changing it re-creates the toolbar view,
|
|
10540
|
+
* which closes any open toolbar popup. It does not move the floating
|
|
10541
|
+
* selection bubble, which always prefers above the selection. While
|
|
10542
|
+
* `readonly` no bar renders in either position (see `toolbarAppearance`).
|
|
10543
|
+
*/
|
|
10544
|
+
toolbarPosition = input('top', /* @ts-ignore */
|
|
10545
|
+
...(ngDevMode ? [{ debugName: "toolbarPosition" }] : /* istanbul ignore next */ []));
|
|
10546
|
+
/**
|
|
10547
|
+
* Toolbar drawing: `'bar'` is the docked row with a hairline; `'floating'` is
|
|
10548
|
+
* a selection bubble. The bubble is a CDK overlay (`.mlv-editor-bubble`)
|
|
10549
|
+
* shown only while focus is in the editor, the selection is non-empty and
|
|
10550
|
+
* the editor is neither disabled nor `readonly`; it prefers above the
|
|
10551
|
+
* selection and flips below at the window's or a capped viewport's edge.
|
|
10552
|
+
* Alt+F10 in the content summons it at the caret and focuses its first
|
|
10553
|
+
* control (the content carries `aria-keyshortcuts="Alt+F10"` while floating
|
|
10554
|
+
* and editable); Escape dismisses it and returns focus to the content with
|
|
10555
|
+
* the selection intact. A plugin that claims Escape itself (a consumer's
|
|
10556
|
+
* `@tiptap/suggestion` list, an AI stream) gets it first, and the Escape
|
|
10557
|
+
* that dismisses the bubble goes no further, so a dialog or drawer around
|
|
10558
|
+
* the editor closes only on the next one. Turning `readonly` on while the
|
|
10559
|
+
* bubble is shown hides it and closes its popups.
|
|
10560
|
+
*
|
|
10561
|
+
* A `readonly` editor renders **no toolbar in either appearance** (#498):
|
|
10562
|
+
* no `.mlv-editor__toolbar-band`, and no space kept for one. Turning
|
|
10563
|
+
* `readonly` on tears the bar down, closes every popup the editor owns and
|
|
10564
|
+
* returns focus from the bar or such a popup to the content, with the
|
|
10565
|
+
* selection intact; turning it off stamps the bar again in its position.
|
|
10566
|
+
* A consumer toolbar (`[mlvEditorToolbar]`, `[mlvEditorToolbarStart]`,
|
|
10567
|
+
* `[mlvEditorToolbarEnd]`) is stamped in the same band and goes with it.
|
|
10568
|
+
*/
|
|
10569
|
+
toolbarAppearance = input('bar', /* @ts-ignore */
|
|
10570
|
+
...(ngDevMode ? [{ debugName: "toolbarAppearance" }] : /* istanbul ignore next */ []));
|
|
10571
|
+
/**
|
|
10572
|
+
* Keeps the docked bar `position: sticky` against the page (or the nearest
|
|
10573
|
+
* consumer scroll container) while the surface is on screen, offset by
|
|
10574
|
+
* `--mlv-editor-toolbar-sticky-offset` (default `0`).
|
|
10575
|
+
*
|
|
10576
|
+
* It applies only to an **uncapped** **bar**. A capped editor
|
|
10577
|
+
* (`height` / `maxHeight`) scrolls inside its own viewport, and the bar
|
|
10578
|
+
* sits outside that scroller, so there is nothing for it to stick against;
|
|
10579
|
+
* the floating bubble follows the selection instead; and a `readonly`
|
|
10580
|
+
* editor renders no bar at all (#498). In each case the input is ignored
|
|
10581
|
+
* and `.mlv-editor--toolbar-sticky` is not stamped.
|
|
10582
|
+
*/
|
|
10583
|
+
toolbarSticky = input(false, { ...(ngDevMode ? { debugName: "toolbarSticky" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
9409
10584
|
/** Complete Tiptap extension replacement; omit it for Malva's fresh preset. */
|
|
9410
10585
|
extensions = input(undefined, /* @ts-ignore */
|
|
9411
10586
|
...(ngDevMode ? [{ debugName: "extensions" }] : /* istanbul ignore next */ []));
|
|
@@ -9443,6 +10618,57 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9443
10618
|
/** View-only zoom percentage shared with the nearest toolbar. */
|
|
9444
10619
|
zoom = signal(100, /* @ts-ignore */
|
|
9445
10620
|
...(ngDevMode ? [{ debugName: "zoom" }] : /* istanbul ignore next */ []));
|
|
10621
|
+
/** @protected Resolved `height`, written into `--mlv-editor-height`; `null` writes nothing. */
|
|
10622
|
+
_heightStyle = computed(() => mlvEditorCssLength(this.height()), /* @ts-ignore */
|
|
10623
|
+
...(ngDevMode ? [{ debugName: "_heightStyle" }] : /* istanbul ignore next */ []));
|
|
10624
|
+
/** @protected Resolved `minHeight`, written into `--mlv-editor-min-height`; `null` writes nothing. */
|
|
10625
|
+
_minHeightStyle = computed(() => mlvEditorCssLength(this.minHeight()), /* @ts-ignore */
|
|
10626
|
+
...(ngDevMode ? [{ debugName: "_minHeightStyle" }] : /* istanbul ignore next */ []));
|
|
10627
|
+
/** @protected Resolved `maxHeight`, written into `--mlv-editor-max-height`; `null` writes nothing. */
|
|
10628
|
+
_maxHeightStyle = computed(() => mlvEditorCssLength(this.maxHeight()), /* @ts-ignore */
|
|
10629
|
+
...(ngDevMode ? [{ debugName: "_maxHeightStyle" }] : /* istanbul ignore next */ []));
|
|
10630
|
+
/**
|
|
10631
|
+
* @protected Whether the editor is capped. Only `height` or `maxHeight`
|
|
10632
|
+
* switches it on; `minHeight` alone stays in auto mode. It is the one input
|
|
10633
|
+
* that turns `.mlv-editor__viewport` into a scroll container.
|
|
10634
|
+
*/
|
|
10635
|
+
_capped = computed(() => this._heightStyle() !== null || this._maxHeightStyle() !== null, /* @ts-ignore */
|
|
10636
|
+
...(ngDevMode ? [{ debugName: "_capped" }] : /* istanbul ignore next */ []));
|
|
10637
|
+
/**
|
|
10638
|
+
* @protected Whether the editor stamps its toolbar at all, in either
|
|
10639
|
+
* appearance: never while `readonly` (#498 owner ruling, "a readonly editor
|
|
10640
|
+
* renders no toolbar"). The docked bar is torn down and the selection
|
|
10641
|
+
* bubble's pane stays empty; both come back when `readonly` turns off.
|
|
10642
|
+
*
|
|
10643
|
+
* This is the one switch, and it covers a consumer toolbar too: a complete
|
|
10644
|
+
* `[mlvEditorToolbar]` replacement and the `[mlvEditorToolbarStart]` /
|
|
10645
|
+
* `[mlvEditorToolbarEnd]` slots are stamped inside the same band. That is
|
|
10646
|
+
* an assumption the owner may reverse. Keeping a complete replacement while
|
|
10647
|
+
* `readonly` is `!this.readonly() || this._hasToolbarDef()` here for the
|
|
10648
|
+
* bar, and the default groups inside the band then need their own readonly
|
|
10649
|
+
* hiding; `_closeBarForReadonly()`'s `_barRendered()` early return must
|
|
10650
|
+
* then key on the removed region, not the band, or focus on a removed
|
|
10651
|
+
* default control drops to `<body>`. The bubble also gates itself on
|
|
10652
|
+
* `readonly` in `MlvEditorBubble._wanted()` / `_ownsContentKey()`, and
|
|
10653
|
+
* `_editorAttributes()` drops `aria-keyshortcuts`.
|
|
10654
|
+
*/
|
|
10655
|
+
_toolbarRendered = computed(() => !this.readonly(), /* @ts-ignore */
|
|
10656
|
+
...(ngDevMode ? [{ debugName: "_toolbarRendered" }] : /* istanbul ignore next */ []));
|
|
10657
|
+
/**
|
|
10658
|
+
* @protected Whether the docked bar is stamped before or after the
|
|
10659
|
+
* viewport: the `'bar'` appearance while `_toolbarRendered()`. With it
|
|
10660
|
+
* false no band exists, so nothing reserves space for one and no sticky
|
|
10661
|
+
* extent is measured.
|
|
10662
|
+
*/
|
|
10663
|
+
_barRendered = computed(() => this.toolbarAppearance() === 'bar' && this._toolbarRendered(), /* @ts-ignore */
|
|
10664
|
+
...(ngDevMode ? [{ debugName: "_barRendered" }] : /* istanbul ignore next */ []));
|
|
10665
|
+
/**
|
|
10666
|
+
* @protected Whether the docked bar is actually sticky: `toolbarSticky` on an
|
|
10667
|
+
* uncapped bar that renders (not while `readonly`). Drives
|
|
10668
|
+
* `.mlv-editor--toolbar-sticky` and the caret scroll margin.
|
|
10669
|
+
*/
|
|
10670
|
+
_stickyToolbar = computed(() => this.toolbarSticky() && this._barRendered() && !this._capped(), /* @ts-ignore */
|
|
10671
|
+
...(ngDevMode ? [{ debugName: "_stickyToolbar" }] : /* istanbul ignore next */ []));
|
|
9446
10672
|
/** Whether the mounted editor currently accepts document mutations. */
|
|
9447
10673
|
editable = computed(() => this._editor() !== null && !this.computedDisabled() && !this.readonly(), /* @ts-ignore */
|
|
9448
10674
|
...(ngDevMode ? [{ debugName: "editable" }] : /* istanbul ignore next */ []));
|
|
@@ -9475,7 +10701,7 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9475
10701
|
_content = viewChild.required('content', /* @ts-ignore */
|
|
9476
10702
|
...(ngDevMode ? [{ debugName: "_content" }] : /* istanbul ignore next */ []));
|
|
9477
10703
|
/**
|
|
9478
|
-
* @private
|
|
10704
|
+
* @private Zoomed layer (CSS `zoom`) the floating block handle is mounted into.
|
|
9479
10705
|
*
|
|
9480
10706
|
* Deliberately optional rather than `viewChild.required`: the block-handle
|
|
9481
10707
|
* `mount` capability is typed `() => HTMLElement | null`, and the extension
|
|
@@ -9485,6 +10711,12 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9485
10711
|
*/
|
|
9486
10712
|
_view = viewChild('view', /* @ts-ignore */
|
|
9487
10713
|
...(ngDevMode ? [{ debugName: "_view" }] : /* istanbul ignore next */ []));
|
|
10714
|
+
/**
|
|
10715
|
+
* @private Toolbar band currently stamped before or after the viewport.
|
|
10716
|
+
* Queried by declaration, so it follows the band across position changes.
|
|
10717
|
+
*/
|
|
10718
|
+
_toolbarBand = viewChild('toolbarBand', /* @ts-ignore */
|
|
10719
|
+
...(ngDevMode ? [{ debugName: "_toolbarBand" }] : /* istanbul ignore next */ []));
|
|
9488
10720
|
/** @protected Complete projected toolbar replacement, if the consumer provides one. */
|
|
9489
10721
|
_toolbarDefs = contentChildren(MlvEditorToolbarDef, /* @ts-ignore */
|
|
9490
10722
|
...(ngDevMode ? [{ debugName: "_toolbarDefs" }] : /* istanbul ignore next */ []));
|
|
@@ -9513,6 +10745,16 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9513
10745
|
_uploadAbortRegistry = inject(MlvEditorUploadAbortRegistry);
|
|
9514
10746
|
/** @private Physical host used to determine the composite focus boundary. */
|
|
9515
10747
|
_host = inject(ElementRef);
|
|
10748
|
+
/**
|
|
10749
|
+
* @private Live ProseMirror `scrollMargin` (WCAG 2.2 SC 2.4.11). One stable
|
|
10750
|
+
* object passed on every `editorProps` write; its sides re-measure per read.
|
|
10751
|
+
* Read untracked: ProseMirror scrolls synchronously inside `updateState`,
|
|
10752
|
+
* which can run within `_synchronizeEditor`'s effect, and that effect must
|
|
10753
|
+
* not start depending on the toolbar inputs.
|
|
10754
|
+
*/
|
|
10755
|
+
_scrollMargin = createMlvEditorLiveScrollSides('margin', () => untracked(this.toolbarPosition), () => untracked(() => this._obscuredToolbarExtent()));
|
|
10756
|
+
/** @private Live ProseMirror `scrollThreshold`, paired with `_scrollMargin`. */
|
|
10757
|
+
_scrollThreshold = createMlvEditorLiveScrollSides('threshold', () => untracked(this.toolbarPosition), () => untracked(() => this._obscuredToolbarExtent()));
|
|
9516
10758
|
/** @private Optional translated accessible defaults. */
|
|
9517
10759
|
_i18n = inject(MLV_EDITOR_I18N, { optional: true });
|
|
9518
10760
|
/** @private Announces block moves politely; the editor content itself is not a live region. */
|
|
@@ -9539,13 +10781,7 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9539
10781
|
_blurCheckQueued = false;
|
|
9540
10782
|
/** @private The last boundary event, retained until the microtask resolves focus ownership. */
|
|
9541
10783
|
_pendingBlurEvent;
|
|
9542
|
-
/** @private
|
|
9543
|
-
_onHostFocusIn = (event) => this._handleCompositeFocusIn(event);
|
|
9544
|
-
/** @private Stable capture listener for focus leaving the physical host. */
|
|
9545
|
-
_onHostFocusOut = (event) => this._handleCompositeFocusOut(event);
|
|
9546
|
-
/** @private Stable capture listener that blocks disabled projected controls. */
|
|
9547
|
-
_onDisabledPointerOrClick = (event) => this._blockDisabledInteraction(event);
|
|
9548
|
-
/** @private Stable capture listener that blocks disabled keyboard activation. */
|
|
10784
|
+
/** @private Blocks disabled keyboard activation; the other three subscribe to their handler directly. */
|
|
9549
10785
|
_onDisabledKeydown = (event) => {
|
|
9550
10786
|
if (event.key !== 'Enter' &&
|
|
9551
10787
|
event.key !== ' ' &&
|
|
@@ -9588,6 +10824,10 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9588
10824
|
this._wasDisabled = disabled;
|
|
9589
10825
|
if (readonly && !this._wasReadonly) {
|
|
9590
10826
|
this._abortInFlightUploads();
|
|
10827
|
+
// Constructor effect: registered on the parent view, so it runs
|
|
10828
|
+
// before this component's template (and the wrapper-stamped band
|
|
10829
|
+
// `@if`) refreshes; focus in the band or its popups can still move.
|
|
10830
|
+
untracked(() => this._closeBarForReadonly());
|
|
9591
10831
|
}
|
|
9592
10832
|
this._wasReadonly = readonly;
|
|
9593
10833
|
if (!editor)
|
|
@@ -9681,7 +10921,11 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9681
10921
|
extensions: selectedExtensions,
|
|
9682
10922
|
editable: !this.computedDisabled() && !this.readonly(),
|
|
9683
10923
|
enableContentCheck: true,
|
|
9684
|
-
editorProps: {
|
|
10924
|
+
editorProps: {
|
|
10925
|
+
attributes: this._editorAttributes(),
|
|
10926
|
+
scrollMargin: this._scrollMargin,
|
|
10927
|
+
scrollThreshold: this._scrollThreshold,
|
|
10928
|
+
},
|
|
9685
10929
|
onTransaction: ({ editor: changedEditor, transaction }) => {
|
|
9686
10930
|
if (this._destroyed)
|
|
9687
10931
|
return;
|
|
@@ -9725,6 +10969,23 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9725
10969
|
});
|
|
9726
10970
|
}
|
|
9727
10971
|
}
|
|
10972
|
+
/**
|
|
10973
|
+
* @protected Focuses the editable content when the control's own
|
|
10974
|
+
* `<mlv-label>` is clicked.
|
|
10975
|
+
*
|
|
10976
|
+
* ProseMirror's contenteditable root is focusable but not HTML-labelable, so
|
|
10977
|
+
* `<label for>` can never name it and the native click-to-focus a field
|
|
10978
|
+
* label owes its control never ran — the visible label was inert (#216), the
|
|
10979
|
+
* same gap the three date/time pickers close. `readonly` still focuses (a
|
|
10980
|
+
* read-only `<textarea>` does), `disabled` returns early (the host is
|
|
10981
|
+
* `inert` anyway), and Tiptap's `focus` command restores the stored
|
|
10982
|
+
* selection rather than dropping the caret at the document start.
|
|
10983
|
+
*/
|
|
10984
|
+
_onLabelClick() {
|
|
10985
|
+
if (this.computedDisabled())
|
|
10986
|
+
return;
|
|
10987
|
+
this._editor()?.commands.focus();
|
|
10988
|
+
}
|
|
9728
10989
|
/** Clears the document through Tiptap when the shared form wrapper is clearable. */
|
|
9729
10990
|
clearValue() {
|
|
9730
10991
|
if (this.computedDisabled() || this.readonly())
|
|
@@ -9811,7 +11072,15 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
9811
11072
|
return;
|
|
9812
11073
|
const requestedFormat = this.format();
|
|
9813
11074
|
editor.setOptions({
|
|
9814
|
-
|
|
11075
|
+
// `setOptions` replaces Tiptap's stored `editorProps` wholesale. The
|
|
11076
|
+
// live view keeps its props (ProseMirror's `setProps` merges), but a
|
|
11077
|
+
// later `mount()` rebuilds the view from the stored copy, so the scroll
|
|
11078
|
+
// props travel with every call.
|
|
11079
|
+
editorProps: {
|
|
11080
|
+
attributes: this._editorAttributes(),
|
|
11081
|
+
scrollMargin: this._scrollMargin,
|
|
11082
|
+
scrollThreshold: this._scrollThreshold,
|
|
11083
|
+
},
|
|
9815
11084
|
});
|
|
9816
11085
|
this._synchronizeContentSurfaceState(editor);
|
|
9817
11086
|
const rawIncoming = this.value();
|
|
@@ -10020,6 +11289,39 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
10020
11289
|
recoverable: true,
|
|
10021
11290
|
});
|
|
10022
11291
|
}
|
|
11292
|
+
/**
|
|
11293
|
+
* @private Block extent the toolbar hides on its own side, in px.
|
|
11294
|
+
*
|
|
11295
|
+
* Only a sticky bar hides anything: its height plus its offset, at its
|
|
11296
|
+
* nearest scroll container. A docked bar sits outside the content, and the
|
|
11297
|
+
* floating bubble is an overlay that follows the selection, clear of it by
|
|
11298
|
+
* construction.
|
|
11299
|
+
* Sticky applies only to an uncapped bar (`_stickyToolbar`), so the margin
|
|
11300
|
+
* never lands on a capped viewport's own edge.
|
|
11301
|
+
*
|
|
11302
|
+
* Read by ProseMirror at scroll time, never for layout. ProseMirror applies
|
|
11303
|
+
* one margin at every scroll ancestor. For an uncapped editor the page is
|
|
11304
|
+
* usually the only one. With a consumer scroll container in between, the
|
|
11305
|
+
* band sticks to that container, where the margin is right; the page, one
|
|
11306
|
+
* scroll ancestor further out, also keeps the caret that far from its edge
|
|
11307
|
+
* although no band is there, which errs toward visibility.
|
|
11308
|
+
*/
|
|
11309
|
+
_obscuredToolbarExtent() {
|
|
11310
|
+
if (!this._stickyToolbar())
|
|
11311
|
+
return 0;
|
|
11312
|
+
const band = this._toolbarBand()?.nativeElement;
|
|
11313
|
+
if (!band)
|
|
11314
|
+
return 0;
|
|
11315
|
+
const side = this.toolbarPosition() === 'top'
|
|
11316
|
+
? 'inset-block-start'
|
|
11317
|
+
: 'inset-block-end';
|
|
11318
|
+
const view = band.ownerDocument.defaultView;
|
|
11319
|
+
const offset = view
|
|
11320
|
+
? Number.parseFloat(view.getComputedStyle(band).getPropertyValue(side)) ||
|
|
11321
|
+
0
|
|
11322
|
+
: 0;
|
|
11323
|
+
return band.getBoundingClientRect().height + offset;
|
|
11324
|
+
}
|
|
10023
11325
|
/** @private Builds the exact accessible attributes assigned to Tiptap's contenteditable root. */
|
|
10024
11326
|
_editorAttributes() {
|
|
10025
11327
|
const attributes = {
|
|
@@ -10057,6 +11359,14 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
10057
11359
|
if (this.readonly()) {
|
|
10058
11360
|
attributes['aria-readonly'] = 'true';
|
|
10059
11361
|
}
|
|
11362
|
+
// The selection bubble stays hidden until a selection exists, so the key
|
|
11363
|
+
// that reaches it is the only hint assistive technology gets. Disabled or
|
|
11364
|
+
// `readonly`, the bubble never shows and the key does nothing.
|
|
11365
|
+
if (this.toolbarAppearance() === 'floating' &&
|
|
11366
|
+
!this.computedDisabled() &&
|
|
11367
|
+
!this.readonly()) {
|
|
11368
|
+
attributes['aria-keyshortcuts'] = 'Alt+F10';
|
|
11369
|
+
}
|
|
10060
11370
|
return attributes;
|
|
10061
11371
|
}
|
|
10062
11372
|
/** @internal Capture handler for focus entering the host or an owned overlay root. */
|
|
@@ -10109,21 +11419,39 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
10109
11419
|
(this._host.nativeElement.contains(node) ||
|
|
10110
11420
|
this._overlayRegistry.contains(node)));
|
|
10111
11421
|
}
|
|
10112
|
-
/**
|
|
11422
|
+
/**
|
|
11423
|
+
* @private Subscribes the composite's host listeners, because overlay focus
|
|
11424
|
+
* happens outside Angular's view tree.
|
|
11425
|
+
*
|
|
11426
|
+
* Every one is registered in the **capture** phase, which is load-bearing
|
|
11427
|
+
* rather than incidental: ProseMirror binds its own handlers to `view.dom`,
|
|
11428
|
+
* a descendant of this host, so only a capture-phase listener on the host
|
|
11429
|
+
* runs ahead of them. The disabled handlers depend on that to call
|
|
11430
|
+
* `stopImmediatePropagation()` while the event is still travelling down —
|
|
11431
|
+
* from the bubble phase ProseMirror would already have acted on it. Capture
|
|
11432
|
+
* is carried through `fromEvent`'s third argument, and `editor-focus.spec.ts`
|
|
11433
|
+
* pins the ordering against descendant listeners.
|
|
11434
|
+
*
|
|
11435
|
+
* Called from `ngAfterViewInit`, which is not an injection context, so
|
|
11436
|
+
* `takeUntilDestroyed` is given the ref explicitly.
|
|
11437
|
+
*/
|
|
10113
11438
|
_bindCompositeFocusEvents() {
|
|
10114
11439
|
const host = this._host.nativeElement;
|
|
10115
|
-
host
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
host
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
11440
|
+
fromEvent(host, 'focusin', { capture: true })
|
|
11441
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
11442
|
+
.subscribe((event) => this._handleCompositeFocusIn(event));
|
|
11443
|
+
fromEvent(host, 'focusout', { capture: true })
|
|
11444
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
11445
|
+
.subscribe((event) => this._handleCompositeFocusOut(event));
|
|
11446
|
+
fromEvent(host, 'pointerdown', { capture: true })
|
|
11447
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
11448
|
+
.subscribe((event) => this._blockDisabledInteraction(event));
|
|
11449
|
+
fromEvent(host, 'click', { capture: true })
|
|
11450
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
11451
|
+
.subscribe((event) => this._blockDisabledInteraction(event));
|
|
11452
|
+
fromEvent(host, 'keydown', { capture: true })
|
|
11453
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
11454
|
+
.subscribe((event) => this._onDisabledKeydown(event));
|
|
10127
11455
|
}
|
|
10128
11456
|
/** @private Stops all pointer/click/activation-key command surfaces while disabled. */
|
|
10129
11457
|
_blockDisabledInteraction(event) {
|
|
@@ -10154,6 +11482,7 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
10154
11482
|
'aria-readonly',
|
|
10155
11483
|
'tabindex',
|
|
10156
11484
|
'aria-invalid',
|
|
11485
|
+
'aria-keyshortcuts',
|
|
10157
11486
|
];
|
|
10158
11487
|
for (const name of managedAttributes) {
|
|
10159
11488
|
const value = attributes[name];
|
|
@@ -10165,6 +11494,29 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
10165
11494
|
}
|
|
10166
11495
|
}
|
|
10167
11496
|
}
|
|
11497
|
+
/**
|
|
11498
|
+
* @private `readonly` just turned on over a docked bar, which this render
|
|
11499
|
+
* tears down (#498). Every popup the editor owns closes, and focus in the
|
|
11500
|
+
* band or in such a popup returns to the content first, through the same
|
|
11501
|
+
* registry call the selection bubble makes. Called from the constructor
|
|
11502
|
+
* effect, which is registered on the parent view, so it runs before this
|
|
11503
|
+
* component's template (and the wrapper-stamped band `@if`) refreshes: the
|
|
11504
|
+
* band and its focus are still there. A disabled editor is left alone, like
|
|
11505
|
+
* the bubble's own focus return: it takes no focus, even from a projected
|
|
11506
|
+
* consumer control, which the editor does not disable and which can hold
|
|
11507
|
+
* focus in the band of a disabled editor.
|
|
11508
|
+
*/
|
|
11509
|
+
_closeBarForReadonly() {
|
|
11510
|
+
if (this.toolbarAppearance() !== 'bar' || this._barRendered())
|
|
11511
|
+
return;
|
|
11512
|
+
if (this.computedDisabled())
|
|
11513
|
+
return;
|
|
11514
|
+
const band = this._toolbarBand()?.nativeElement;
|
|
11515
|
+
const editor = this._editor();
|
|
11516
|
+
if (!band || !editor || editor.isDestroyed)
|
|
11517
|
+
return;
|
|
11518
|
+
this._overlayRegistry.closeForReadonly(band, editor.view.dom, () => mlvEditorFocusContent(editor));
|
|
11519
|
+
}
|
|
10168
11520
|
/** @private Aborts registered upload work while preserving the document/editor instance. */
|
|
10169
11521
|
_abortInFlightUploads() {
|
|
10170
11522
|
this._uploadAbortRegistry.abortAll();
|
|
@@ -10177,8 +11529,8 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
10177
11529
|
this._editor.set(null);
|
|
10178
11530
|
editor?.destroy();
|
|
10179
11531
|
}
|
|
10180
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
10181
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
11532
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11533
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.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 }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, toolbarPosition: { classPropertyName: "toolbarPosition", publicName: "toolbarPosition", isSignal: true, isRequired: false, transformFunction: null }, toolbarAppearance: { classPropertyName: "toolbarAppearance", publicName: "toolbarAppearance", isSignal: true, isRequired: false, transformFunction: null }, toolbarSticky: { classPropertyName: "toolbarSticky", publicName: "toolbarSticky", 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()", "class.mlv-editor--capped": "_capped()", "class.mlv-editor--toolbar-top": "toolbarPosition() === \"top\"", "class.mlv-editor--toolbar-bottom": "toolbarPosition() === \"bottom\"", "class.mlv-editor--toolbar-bar": "toolbarAppearance() === \"bar\"", "class.mlv-editor--toolbar-floating": "toolbarAppearance() === \"floating\"", "class.mlv-editor--toolbar-sticky": "_stickyToolbar()", "attr.aria-disabled": "computedDisabled() || null", "attr.inert": "computedDisabled() ? \"\" : null", "style.--mlv-editor-zoom": "zoom() / 100", "style.--mlv-editor-height": "_heightStyle()", "style.--mlv-editor-min-height": "_minHeightStyle()", "style.--mlv-editor-max-height": "_maxHeightStyle()" }, classAttribute: "mlv-editor" }, providers: [
|
|
10182
11534
|
MlvEditorOverlayRegistry,
|
|
10183
11535
|
MlvEditorToolbarRevision,
|
|
10184
11536
|
MlvEditorToolbarRovingRegistry,
|
|
@@ -10237,9 +11589,9 @@ class MlvEditor extends MlvSignalFormControlBase {
|
|
|
10237
11589
|
}, inject(MLV_EDITOR_IMAGE_UPLOADER, { optional: true }) ?? undefined, inject(MLV_EDITOR_UPLOAD_ABORT_REGISTRY));
|
|
10238
11590
|
},
|
|
10239
11591
|
},
|
|
10240
|
-
], 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 <mlv-editor-table-controls [layer]=\"view\" />\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: ["@layer mlv.components{.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:var(--mlv-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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: MlvEditorTableControls, selector: "mlv-editor-table-controls", inputs: ["layer"] }, { 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 });
|
|
11592
|
+
], 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 }, { propertyName: "_toolbarBand", first: true, predicate: ["toolbarBand"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<mlv-form-control-wrapper (clear)=\"clearValue()\">\n @if (label() || hint()) {\n <mlv-label\n [for]=\"_ownLabelFor()\"\n [id]=\"_labelId()\"\n (click)=\"_onLabelClick()\"\n >\n {{ label() }}\n @if (hint()) {\n <mlv-hint>{{ hint() }}</mlv-hint>\n }\n </mlv-label>\n }\n\n <ng-template mlvFormControlWrapperControl>\n <div #surface class=\"mlv-editor__surface\">\n <!--\n Declared once and stamped by one outlet: before or after the viewport\n for the docked bar (#416), so the DOM order is always the visual\n order, with no CSS `order`; into the selection bubble's overlay for\n the floating appearance (#483). Re-stamping re-creates the view, which\n closes an open toolbar popup; projected slot content is re-attached.\n Neither stamps anything while `readonly` (#498): no band, no reserved\n space; `_toolbarRendered()` is the one switch.\n -->\n <ng-template #toolbarTemplate>\n <div #toolbarBand class=\"mlv-editor__toolbar-band\">\n <div\n mlvEditorToolbarRoot\n #toolbarRoot=\"mlvEditorToolbarRoot\"\n class=\"mlv-editor__toolbar\"\n [ariaLabel]=\"_toolbarAriaLabel()\"\n [disabled]=\"computedDisabled()\"\n [measureTarget]=\"surface\"\n >\n @if (_hasToolbarDef()) {\n <ng-content select=\"[mlvEditorToolbar]\" />\n @for (definition of _toolbarDefs(); track definition) {\n @if (definition.templateRef; as toolbarTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"toolbarTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n }\n }\n } @else {\n <ng-content select=\"[mlvEditorToolbarStart]\" />\n @for (definition of _toolbarStartDefs(); track definition) {\n @if (definition.templateRef; as startTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"startTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\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) {\n @if (definition.templateRef; as endTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"endTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n }\n }\n <ng-content select=\"[mlvEditorToolbarEnd]\" />\n }\n </div>\n </div>\n </ng-template>\n\n @if (_barRendered() && toolbarPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"toolbarTemplate\" />\n }\n\n <div #viewport class=\"mlv-editor__viewport\">\n <div #view class=\"mlv-editor__view\">\n <div #content class=\"mlv-editor__content\"></div>\n <mlv-editor-table-controls [layer]=\"view\" />\n </div>\n </div>\n @if (_barRendered() && toolbarPosition() === 'bottom') {\n <ng-container [ngTemplateOutlet]=\"toolbarTemplate\" />\n }\n @if (toolbarAppearance() === 'floating') {\n <ng-template mlvEditorBubble [viewport]=\"viewport\" [capped]=\"_capped()\">\n @if (_toolbarRendered()) {\n <ng-container [ngTemplateOutlet]=\"toolbarTemplate\" />\n }\n </ng-template>\n }\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: ["@layer mlv.components{.mlv-editor{--mlv-editor-gutter: var(--mlv-spacing-6);--mlv-editor-measure: 45rem;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:clip;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-block-end:var(--mlv-stroke-width) solid var(--mlv-border-normal);background:var(--mlv-elevation-bg-3)}.mlv-editor__toolbar-band{display:flex;flex:0 0 auto;flex-direction:column;min-inline-size:0}.mlv-editor--toolbar-bottom .mlv-editor__toolbar{border-block-start:var(--mlv-stroke-width) solid var(--mlv-border-normal);border-block-end:0}.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{flex:1 1 auto;min-block-size:var(--mlv-editor-min-height, 8rem)}.mlv-editor--capped .mlv-editor__surface{block-size:var(--mlv-editor-height, auto);max-block-size:var(--mlv-editor-max-height, none)}.mlv-editor--capped .mlv-editor__viewport{min-block-size:0;overflow:auto;overscroll-behavior:contain}.mlv-editor__view{position:relative;isolation:isolate;min-inline-size:100%;zoom:var(--mlv-editor-zoom, 1)}.mlv-editor--capped .mlv-editor__view{min-inline-size:0;inline-size:calc(100% * var(--mlv-editor-zoom, 1))}.mlv-editor__content{min-block-size:var(--mlv-editor-min-height, 8rem);padding-block:var(--mlv-spacing-2);padding-inline:var(--mlv-editor-gutter);border:0;outline:none}.mlv-editor--capped .mlv-editor__content{min-block-size:calc(var(--mlv-editor-min-height, 8rem) / var(--mlv-editor-zoom, 1))}.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(-50%);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__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:var(--mlv-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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}}.mlv-editor--toolbar-sticky.mlv-editor--toolbar-top .mlv-editor__toolbar-band{position:sticky;inset-block-start:var(--mlv-editor-toolbar-sticky-offset, 0);z-index:var(--mlv-z-raised)}.mlv-editor--toolbar-sticky.mlv-editor--toolbar-bottom .mlv-editor__toolbar-band{position:sticky;inset-block-end:var(--mlv-editor-toolbar-sticky-offset, 0);z-index:var(--mlv-z-raised)}.mlv-editor-bubble{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-bubble *{box-sizing:border-box}.mlv-editor-bubble .mlv-editor-toolbar__separator{flex:0 0 auto;min-height:var(--mlv-height-s);margin-inline:var(--mlv-spacing-1)}.mlv-editor-bubble .mlv-editor-toolbar__overflow,.mlv-editor-bubble .mlv-editor-undo-redo,.mlv-editor-bubble .mlv-editor-inline-marks,.mlv-editor-bubble .mlv-editor-block-insert{display:inline-flex;flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor-bubble mlv-editor-zoom,.mlv-editor-bubble mlv-editor-heading,.mlv-editor-bubble mlv-editor-list,.mlv-editor-bubble mlv-editor-text-color,.mlv-editor-bubble mlv-editor-highlight,.mlv-editor-bubble mlv-editor-alignment,.mlv-editor-bubble mlv-editor-link,.mlv-editor-bubble mlv-editor-table,.mlv-editor-bubble mlv-editor-image-upload{flex:0 0 auto}.mlv-editor-bubble{max-inline-size:calc(100vw - 2 * var(--mlv-spacing-2));border-radius:var(--mlv-radius-panel);background:var(--mlv-elevation-bg-4);box-shadow:var(--mlv-shadow-floating);color:var(--mlv-text-primary);animation:mlv-editor-bubble-enter var(--mlv-duration-fast) var(--mlv-ease-out)}.mlv-editor-bubble--hidden{visibility:hidden;animation:none}.mlv-editor-bubble .mlv-editor__toolbar-band{flex:1 1 auto;min-inline-size:0}.mlv-editor-bubble .mlv-editor__toolbar{border:0;border-radius:inherit;background:transparent}@keyframes mlv-editor-bubble-enter{0%{opacity:0}}@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-band,.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,.mlv-editor--capped .mlv-editor__viewport{overflow:visible;padding-block:0}.mlv-editor--capped .mlv-editor__surface{block-size:auto;max-block-size:none}.mlv-editor__view,.mlv-editor--capped .mlv-editor__view{zoom:1;inline-size:auto;min-inline-size:0}.mlv-editor__content,.mlv-editor--capped .mlv-editor__content,.mlv-editor .ProseMirror{min-block-size:0;padding:0}.mlv-editor table{break-inside:avoid}}@media print{.mlv-editor-bubble{display:none}}@media(hover:none){.mlv-editor__block-handle{display:none}}@media(prefers-reduced-motion:reduce){.mlv-editor .mlv-form-control-wrapper__control-container,.mlv-editor__block-handle,.mlv-editor__drop-indicator,.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-bubble{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-accent-1-pale);opacity:.9;-webkit-mask-image:linear-gradient(to bottom,black 70%,transparent 100%);mask-image:linear-gradient(to bottom,black 70%,transparent 100%)}}\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", "measureTarget"], 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: MlvEditorTableControls, selector: "mlv-editor-table-controls", inputs: ["layer"] }, { kind: "component", type: MlvEditorAlignment, selector: "mlv-editor-alignment" }, { kind: "component", type: MlvEditorBlockInsert, selector: "mlv-editor-block-insert" }, { kind: "directive", type: MlvEditorBubble, selector: "ng-template[mlvEditorBubble]", inputs: ["viewport", "capped"] }, { kind: "component", type: MlvSpacer, selector: "mlv-spacer" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
10241
11593
|
}
|
|
10242
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
11594
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: MlvEditor, decorators: [{
|
|
10243
11595
|
type: Component,
|
|
10244
11596
|
args: [{ selector: 'mlv-editor', imports: [
|
|
10245
11597
|
MlvFormControlWrapper,
|
|
@@ -10268,6 +11620,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
10268
11620
|
MlvEditorTableControls,
|
|
10269
11621
|
MlvEditorAlignment,
|
|
10270
11622
|
MlvEditorBlockInsert,
|
|
11623
|
+
MlvEditorBubble,
|
|
10271
11624
|
MlvSpacer,
|
|
10272
11625
|
], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
10273
11626
|
MlvEditorOverlayRegistry,
|
|
@@ -10334,11 +11687,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
10334
11687
|
'[class.mlv-editor--disabled]': 'computedDisabled()',
|
|
10335
11688
|
'[class.mlv-editor--readonly]': 'readonly()',
|
|
10336
11689
|
'[class.mlv-editor--focused]': 'focused()',
|
|
11690
|
+
'[class.mlv-editor--capped]': '_capped()',
|
|
11691
|
+
'[class.mlv-editor--toolbar-top]': 'toolbarPosition() === "top"',
|
|
11692
|
+
'[class.mlv-editor--toolbar-bottom]': 'toolbarPosition() === "bottom"',
|
|
11693
|
+
'[class.mlv-editor--toolbar-bar]': 'toolbarAppearance() === "bar"',
|
|
11694
|
+
'[class.mlv-editor--toolbar-floating]': 'toolbarAppearance() === "floating"',
|
|
11695
|
+
'[class.mlv-editor--toolbar-sticky]': '_stickyToolbar()',
|
|
10337
11696
|
'[attr.aria-disabled]': 'computedDisabled() || null',
|
|
10338
11697
|
'[attr.inert]': 'computedDisabled() ? "" : null',
|
|
10339
11698
|
'[style.--mlv-editor-zoom]': 'zoom() / 100',
|
|
10340
|
-
}, 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 <mlv-editor-table-controls [layer]=\"view\" />\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: ["@layer mlv.components{.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:var(--mlv-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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"] }]
|
|
10341
|
-
|
|
11699
|
+
'[style.--mlv-editor-height]': '_heightStyle()',
|
|
11700
|
+
'[style.--mlv-editor-min-height]': '_minHeightStyle()',
|
|
11701
|
+
'[style.--mlv-editor-max-height]': '_maxHeightStyle()',
|
|
11702
|
+
}, template: "<mlv-form-control-wrapper (clear)=\"clearValue()\">\n @if (label() || hint()) {\n <mlv-label\n [for]=\"_ownLabelFor()\"\n [id]=\"_labelId()\"\n (click)=\"_onLabelClick()\"\n >\n {{ label() }}\n @if (hint()) {\n <mlv-hint>{{ hint() }}</mlv-hint>\n }\n </mlv-label>\n }\n\n <ng-template mlvFormControlWrapperControl>\n <div #surface class=\"mlv-editor__surface\">\n <!--\n Declared once and stamped by one outlet: before or after the viewport\n for the docked bar (#416), so the DOM order is always the visual\n order, with no CSS `order`; into the selection bubble's overlay for\n the floating appearance (#483). Re-stamping re-creates the view, which\n closes an open toolbar popup; projected slot content is re-attached.\n Neither stamps anything while `readonly` (#498): no band, no reserved\n space; `_toolbarRendered()` is the one switch.\n -->\n <ng-template #toolbarTemplate>\n <div #toolbarBand class=\"mlv-editor__toolbar-band\">\n <div\n mlvEditorToolbarRoot\n #toolbarRoot=\"mlvEditorToolbarRoot\"\n class=\"mlv-editor__toolbar\"\n [ariaLabel]=\"_toolbarAriaLabel()\"\n [disabled]=\"computedDisabled()\"\n [measureTarget]=\"surface\"\n >\n @if (_hasToolbarDef()) {\n <ng-content select=\"[mlvEditorToolbar]\" />\n @for (definition of _toolbarDefs(); track definition) {\n @if (definition.templateRef; as toolbarTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"toolbarTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n }\n }\n } @else {\n <ng-content select=\"[mlvEditorToolbarStart]\" />\n @for (definition of _toolbarStartDefs(); track definition) {\n @if (definition.templateRef; as startTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"startTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\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) {\n @if (definition.templateRef; as endTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"endTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: _toolbarContext }\"\n />\n }\n }\n <ng-content select=\"[mlvEditorToolbarEnd]\" />\n }\n </div>\n </div>\n </ng-template>\n\n @if (_barRendered() && toolbarPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"toolbarTemplate\" />\n }\n\n <div #viewport class=\"mlv-editor__viewport\">\n <div #view class=\"mlv-editor__view\">\n <div #content class=\"mlv-editor__content\"></div>\n <mlv-editor-table-controls [layer]=\"view\" />\n </div>\n </div>\n @if (_barRendered() && toolbarPosition() === 'bottom') {\n <ng-container [ngTemplateOutlet]=\"toolbarTemplate\" />\n }\n @if (toolbarAppearance() === 'floating') {\n <ng-template mlvEditorBubble [viewport]=\"viewport\" [capped]=\"_capped()\">\n @if (_toolbarRendered()) {\n <ng-container [ngTemplateOutlet]=\"toolbarTemplate\" />\n }\n </ng-template>\n }\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: ["@layer mlv.components{.mlv-editor{--mlv-editor-gutter: var(--mlv-spacing-6);--mlv-editor-measure: 45rem;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:clip;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-block-end:var(--mlv-stroke-width) solid var(--mlv-border-normal);background:var(--mlv-elevation-bg-3)}.mlv-editor__toolbar-band{display:flex;flex:0 0 auto;flex-direction:column;min-inline-size:0}.mlv-editor--toolbar-bottom .mlv-editor__toolbar{border-block-start:var(--mlv-stroke-width) solid var(--mlv-border-normal);border-block-end:0}.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{flex:1 1 auto;min-block-size:var(--mlv-editor-min-height, 8rem)}.mlv-editor--capped .mlv-editor__surface{block-size:var(--mlv-editor-height, auto);max-block-size:var(--mlv-editor-max-height, none)}.mlv-editor--capped .mlv-editor__viewport{min-block-size:0;overflow:auto;overscroll-behavior:contain}.mlv-editor__view{position:relative;isolation:isolate;min-inline-size:100%;zoom:var(--mlv-editor-zoom, 1)}.mlv-editor--capped .mlv-editor__view{min-inline-size:0;inline-size:calc(100% * var(--mlv-editor-zoom, 1))}.mlv-editor__content{min-block-size:var(--mlv-editor-min-height, 8rem);padding-block:var(--mlv-spacing-2);padding-inline:var(--mlv-editor-gutter);border:0;outline:none}.mlv-editor--capped .mlv-editor__content{min-block-size:calc(var(--mlv-editor-min-height, 8rem) / var(--mlv-editor-zoom, 1))}.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(-50%);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__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:var(--mlv-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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-focus-ring-offset)}.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}}.mlv-editor--toolbar-sticky.mlv-editor--toolbar-top .mlv-editor__toolbar-band{position:sticky;inset-block-start:var(--mlv-editor-toolbar-sticky-offset, 0);z-index:var(--mlv-z-raised)}.mlv-editor--toolbar-sticky.mlv-editor--toolbar-bottom .mlv-editor__toolbar-band{position:sticky;inset-block-end:var(--mlv-editor-toolbar-sticky-offset, 0);z-index:var(--mlv-z-raised)}.mlv-editor-bubble{box-sizing:border-box;padding:0;margin:0;font-family:var(--mlv-typography-family-text);font-size:var(--mlv-font-size-m)}.mlv-editor-bubble *{box-sizing:border-box}.mlv-editor-bubble .mlv-editor-toolbar__separator{flex:0 0 auto;min-height:var(--mlv-height-s);margin-inline:var(--mlv-spacing-1)}.mlv-editor-bubble .mlv-editor-toolbar__overflow,.mlv-editor-bubble .mlv-editor-undo-redo,.mlv-editor-bubble .mlv-editor-inline-marks,.mlv-editor-bubble .mlv-editor-block-insert{display:inline-flex;flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--mlv-spacing-1)}.mlv-editor-bubble mlv-editor-zoom,.mlv-editor-bubble mlv-editor-heading,.mlv-editor-bubble mlv-editor-list,.mlv-editor-bubble mlv-editor-text-color,.mlv-editor-bubble mlv-editor-highlight,.mlv-editor-bubble mlv-editor-alignment,.mlv-editor-bubble mlv-editor-link,.mlv-editor-bubble mlv-editor-table,.mlv-editor-bubble mlv-editor-image-upload{flex:0 0 auto}.mlv-editor-bubble{max-inline-size:calc(100vw - 2 * var(--mlv-spacing-2));border-radius:var(--mlv-radius-panel);background:var(--mlv-elevation-bg-4);box-shadow:var(--mlv-shadow-floating);color:var(--mlv-text-primary);animation:mlv-editor-bubble-enter var(--mlv-duration-fast) var(--mlv-ease-out)}.mlv-editor-bubble--hidden{visibility:hidden;animation:none}.mlv-editor-bubble .mlv-editor__toolbar-band{flex:1 1 auto;min-inline-size:0}.mlv-editor-bubble .mlv-editor__toolbar{border:0;border-radius:inherit;background:transparent}@keyframes mlv-editor-bubble-enter{0%{opacity:0}}@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-band,.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,.mlv-editor--capped .mlv-editor__viewport{overflow:visible;padding-block:0}.mlv-editor--capped .mlv-editor__surface{block-size:auto;max-block-size:none}.mlv-editor__view,.mlv-editor--capped .mlv-editor__view{zoom:1;inline-size:auto;min-inline-size:0}.mlv-editor__content,.mlv-editor--capped .mlv-editor__content,.mlv-editor .ProseMirror{min-block-size:0;padding:0}.mlv-editor table{break-inside:avoid}}@media print{.mlv-editor-bubble{display:none}}@media(hover:none){.mlv-editor__block-handle{display:none}}@media(prefers-reduced-motion:reduce){.mlv-editor .mlv-form-control-wrapper__control-container,.mlv-editor__block-handle,.mlv-editor__drop-indicator,.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-bubble{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-accent-1-pale);opacity:.9;-webkit-mask-image:linear-gradient(to bottom,black 70%,transparent 100%);mask-image:linear-gradient(to bottom,black 70%,transparent 100%)}}\n"] }]
|
|
11703
|
+
}], 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 }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], toolbarPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarPosition", required: false }] }], toolbarAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarAppearance", required: false }] }], toolbarSticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarSticky", 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 }] }], _toolbarBand: [{ type: i0.ViewChild, args: ['toolbarBand', { 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 }] }] } });
|
|
10342
11704
|
|
|
10343
11705
|
/**
|
|
10344
11706
|
* Generated bundle index. Do not edit.
|