@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malva-ui/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "SSR-safe Angular rich-text editor for Malva UI — a Tiptap shell with HTML/Markdown/JSON values, image uploads and block reordering.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -31,21 +31,23 @@
|
|
|
31
31
|
"@angular/core": "^22.0.0",
|
|
32
32
|
"@angular/forms": "^22.0.0",
|
|
33
33
|
"@lucide/angular": "^1.25.0",
|
|
34
|
-
"@malva-ui/cdk": "0.
|
|
35
|
-
"@malva-ui/core": "0.
|
|
36
|
-
"@malva-ui/i18n": "0.
|
|
37
|
-
"@tiptap/core": "^3.
|
|
38
|
-
"@tiptap/extension-file-handler": "^3.
|
|
39
|
-
"@tiptap/extension-highlight": "^3.
|
|
40
|
-
"@tiptap/extension-image": "^3.
|
|
41
|
-
"@tiptap/extension-list": "^3.
|
|
42
|
-
"@tiptap/extension-table": "^3.
|
|
43
|
-
"@tiptap/extension-text-align": "^3.
|
|
44
|
-
"@tiptap/extension-text-style": "^3.
|
|
45
|
-
"@tiptap/extensions": "^3.
|
|
46
|
-
"@tiptap/markdown": "^3.
|
|
47
|
-
"@tiptap/pm": "^3.
|
|
48
|
-
"@tiptap/starter-kit": "^3.
|
|
34
|
+
"@malva-ui/cdk": "0.2.0",
|
|
35
|
+
"@malva-ui/core": "0.2.0",
|
|
36
|
+
"@malva-ui/i18n": "0.2.0",
|
|
37
|
+
"@tiptap/core": "^3.31.0",
|
|
38
|
+
"@tiptap/extension-file-handler": "^3.31.0",
|
|
39
|
+
"@tiptap/extension-highlight": "^3.31.0",
|
|
40
|
+
"@tiptap/extension-image": "^3.31.0",
|
|
41
|
+
"@tiptap/extension-list": "^3.31.0",
|
|
42
|
+
"@tiptap/extension-table": "^3.31.0",
|
|
43
|
+
"@tiptap/extension-text-align": "^3.31.0",
|
|
44
|
+
"@tiptap/extension-text-style": "^3.31.0",
|
|
45
|
+
"@tiptap/extensions": "^3.31.0",
|
|
46
|
+
"@tiptap/markdown": "^3.31.0",
|
|
47
|
+
"@tiptap/pm": "^3.31.0",
|
|
48
|
+
"@tiptap/starter-kit": "^3.31.0",
|
|
49
|
+
"prosemirror-model": "^1.25.12",
|
|
50
|
+
"prosemirror-view": "^1.42.5",
|
|
49
51
|
"rxjs": "~7.8.0"
|
|
50
52
|
},
|
|
51
53
|
"sideEffects": false,
|
|
@@ -33,6 +33,25 @@ type MlvEditorFormat = 'html' | 'markdown' | 'json';
|
|
|
33
33
|
* reserved at every value, so block affordances never overlap text.
|
|
34
34
|
*/
|
|
35
35
|
type MlvEditorContentWidth = 'default' | 'wide' | 'full';
|
|
36
|
+
/**
|
|
37
|
+
* Where `mlv-editor` places its toolbar relative to the content viewport.
|
|
38
|
+
*
|
|
39
|
+
* The DOM order follows the value, so the Tab order always matches the visual
|
|
40
|
+
* order: `'top'` renders toolbar → content and `'bottom'` renders content →
|
|
41
|
+
* toolbar. Both are block-axis positions and do not change in RTL.
|
|
42
|
+
*/
|
|
43
|
+
type MlvEditorToolbarPosition = 'top' | 'bottom';
|
|
44
|
+
/**
|
|
45
|
+
* How `mlv-editor` draws its toolbar.
|
|
46
|
+
*
|
|
47
|
+
* `'bar'` is the docked full-width row with a hairline toward the content.
|
|
48
|
+
* `'floating'` is a selection bubble: an overlay hugging its controls, shown
|
|
49
|
+
* only while focus is in the editor, the selection is non-empty (Alt+F10
|
|
50
|
+
* summons it at the caret) and the editor is neither disabled nor `readonly`.
|
|
51
|
+
* It prefers above the selection and flips below at the window's or a capped
|
|
52
|
+
* viewport's edge. `toolbarPosition` and `toolbarSticky` do not apply to it.
|
|
53
|
+
*/
|
|
54
|
+
type MlvEditorToolbarAppearance = 'bar' | 'floating';
|
|
36
55
|
/** Origin of an image file supplied to the editor. */
|
|
37
56
|
type MlvEditorImageUploadSource = 'button' | 'paste' | 'drop';
|
|
38
57
|
/** Decides whether an uploaded image URL is safe to insert into the editor. */
|
|
@@ -82,9 +101,24 @@ interface MlvEditorImageUploadContext {
|
|
|
82
101
|
interface MlvEditorImageUploadResult {
|
|
83
102
|
/** URL used in the inserted image node. */
|
|
84
103
|
readonly src: string;
|
|
85
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* Optional alternative text for the image.
|
|
106
|
+
*
|
|
107
|
+
* Returned by an uploader, it is a **fallback**: alternative text the
|
|
108
|
+
* author supplied — typed in the upload dialog, or the empty alt of an
|
|
109
|
+
* image marked decorative — wins, because the author states what the image
|
|
110
|
+
* means and a file name rarely describes it (WCAG 1.1.1). Pasted and
|
|
111
|
+
* dropped images carry no author alt, so this value applies to them.
|
|
112
|
+
*/
|
|
86
113
|
readonly alt?: string;
|
|
87
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Optional image title. Returned by an uploader, it is a fallback: a
|
|
116
|
+
* non-empty title the author typed in the upload dialog wins. An image the
|
|
117
|
+
* author marked decorative gets no title at all — an `alt=""` image with a
|
|
118
|
+
* title is exposed as an unnamed image described by it (WCAG H67). An
|
|
119
|
+
* uploader's own `alt: ''` is inserted as returned, title included — return
|
|
120
|
+
* no `title` for an image you mean to be decorative (WCAG H67).
|
|
121
|
+
*/
|
|
88
122
|
readonly title?: string;
|
|
89
123
|
/** Optional rendered image width. */
|
|
90
124
|
readonly width?: number;
|
|
@@ -148,7 +182,15 @@ declare abstract class MlvEditorImageUploadControl {
|
|
|
148
182
|
abstract readonly options: Signal<MlvEditorImageUploadOptions>;
|
|
149
183
|
/** Active and retryable uploads owned by this editor. */
|
|
150
184
|
abstract readonly pending: Signal<readonly MlvEditorPendingUpload[]>;
|
|
151
|
-
/**
|
|
185
|
+
/**
|
|
186
|
+
* Starts validated uploads in the owning editor.
|
|
187
|
+
*
|
|
188
|
+
* `metadata.alt` and `metadata.title` are the author's and win over the
|
|
189
|
+
* uploader's result. Omit `alt` when the author supplied none — `''` marks
|
|
190
|
+
* the image decorative, keeps it empty and drops every title, the
|
|
191
|
+
* author's and the uploader's; otherwise an empty `title` lets the
|
|
192
|
+
* uploader's apply.
|
|
193
|
+
*/
|
|
152
194
|
abstract start(files: readonly File[], source: MlvEditorImageUploadSource, metadata?: {
|
|
153
195
|
readonly position?: number;
|
|
154
196
|
readonly alt?: string;
|
|
@@ -167,7 +209,10 @@ interface MlvEditorImageUploadSuccess {
|
|
|
167
209
|
readonly file: File;
|
|
168
210
|
/** Origin of the image file. */
|
|
169
211
|
readonly source: MlvEditorImageUploadSource;
|
|
170
|
-
/**
|
|
212
|
+
/**
|
|
213
|
+
* Metadata inserted into the document: the uploader's validated result
|
|
214
|
+
* with the author's alt and title applied over the uploader's.
|
|
215
|
+
*/
|
|
171
216
|
readonly result: MlvEditorImageUploadResult;
|
|
172
217
|
}
|
|
173
218
|
/** Details emitted when an image upload fails. */
|
|
@@ -504,7 +549,7 @@ declare class MlvEditorAiContext {
|
|
|
504
549
|
*/
|
|
505
550
|
private _serializeDocument;
|
|
506
551
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MlvEditorAiContext, never>;
|
|
507
|
-
static ɵprov: _angular_core.ɵɵInjectableDeclaration<
|
|
552
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<any>;
|
|
508
553
|
}
|
|
509
554
|
/** Injects the AI command state belonging to the nearest `mlv-editor`. */
|
|
510
555
|
declare const MLV_EDITOR_AI_CONTEXT: InjectionToken<MlvEditorAiContext>;
|
|
@@ -920,6 +965,8 @@ declare function mlvEditorAiDefaultActions(copy: MlvEditorI18n | null | undefine
|
|
|
920
965
|
* resolves no provider (presence), and its actions disable — without hiding —
|
|
921
966
|
* while the editor is readonly or disabled or a transform is already running
|
|
922
967
|
* (executability), matching the toolbar's presence-vs-executability rule.
|
|
968
|
+
* Projected into `mlv-editor`'s toolbar it is not rendered at all while the
|
|
969
|
+
* editor is `readonly`, which renders no toolbar (#498).
|
|
923
970
|
*/
|
|
924
971
|
declare class MlvEditorAiMenu {
|
|
925
972
|
/**
|
|
@@ -1464,6 +1511,82 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1464
1511
|
readonly format: _angular_core.InputSignal<MlvEditorFormat>;
|
|
1465
1512
|
/** Width of the centred content column; a gutter is reserved at every value. */
|
|
1466
1513
|
readonly contentWidth: _angular_core.InputSignal<MlvEditorContentWidth>;
|
|
1514
|
+
/**
|
|
1515
|
+
* Fixed block size of the editor surface (toolbar plus content viewport).
|
|
1516
|
+
* A number is px; a string is any CSS length, passed through verbatim.
|
|
1517
|
+
*
|
|
1518
|
+
* Setting it **caps** the editor: `.mlv-editor__viewport` becomes the only
|
|
1519
|
+
* scroll container. With neither `height` nor `maxHeight`, the editor grows
|
|
1520
|
+
* with its content, never shows a scrollbar, and never stops a scroll meant
|
|
1521
|
+
* for the page. Writing `--mlv-editor-height` in CSS alone does not cap.
|
|
1522
|
+
*/
|
|
1523
|
+
readonly height: _angular_core.InputSignal<string | number | undefined>;
|
|
1524
|
+
/**
|
|
1525
|
+
* Minimum block size of the editable content area; the viewport adds its
|
|
1526
|
+
* 1rem padding around it. A number is px; a string is any CSS length. `undefined` keeps the `8rem` floor. Setting only this input
|
|
1527
|
+
* leaves the editor in auto mode. `--mlv-editor-min-height` may also be set
|
|
1528
|
+
* in CSS.
|
|
1529
|
+
*
|
|
1530
|
+
* Under a cap (`height` / `maxHeight`) the cap wins, even over a larger
|
|
1531
|
+
* `minHeight`: the viewport shrinks to fit the surface, and the floor moves
|
|
1532
|
+
* to the content inside the scroller, at every zoom level. A `minHeight`
|
|
1533
|
+
* above what the cap leaves the content (the cap minus the toolbar band and
|
|
1534
|
+
* the viewport padding) scrolls an empty document; for a fixed size set
|
|
1535
|
+
* `height` rather than `minHeight` equal to `maxHeight`.
|
|
1536
|
+
*/
|
|
1537
|
+
readonly minHeight: _angular_core.InputSignal<string | number | undefined>;
|
|
1538
|
+
/**
|
|
1539
|
+
* Largest block size of the editor surface. The surface grows with its
|
|
1540
|
+
* content up to this cap, and then the viewport scrolls. A number is px; a
|
|
1541
|
+
* string is any CSS length. Like `height`, this caps the editor; writing
|
|
1542
|
+
* `--mlv-editor-max-height` in CSS alone does not.
|
|
1543
|
+
*/
|
|
1544
|
+
readonly maxHeight: _angular_core.InputSignal<string | number | undefined>;
|
|
1545
|
+
/**
|
|
1546
|
+
* Docked-bar placement. The DOM order follows it, so the Tab order matches
|
|
1547
|
+
* the visual order (WCAG 2.4.3). Changing it re-creates the toolbar view,
|
|
1548
|
+
* which closes any open toolbar popup. It does not move the floating
|
|
1549
|
+
* selection bubble, which always prefers above the selection. While
|
|
1550
|
+
* `readonly` no bar renders in either position (see `toolbarAppearance`).
|
|
1551
|
+
*/
|
|
1552
|
+
readonly toolbarPosition: _angular_core.InputSignal<MlvEditorToolbarPosition>;
|
|
1553
|
+
/**
|
|
1554
|
+
* Toolbar drawing: `'bar'` is the docked row with a hairline; `'floating'` is
|
|
1555
|
+
* a selection bubble. The bubble is a CDK overlay (`.mlv-editor-bubble`)
|
|
1556
|
+
* shown only while focus is in the editor, the selection is non-empty and
|
|
1557
|
+
* the editor is neither disabled nor `readonly`; it prefers above the
|
|
1558
|
+
* selection and flips below at the window's or a capped viewport's edge.
|
|
1559
|
+
* Alt+F10 in the content summons it at the caret and focuses its first
|
|
1560
|
+
* control (the content carries `aria-keyshortcuts="Alt+F10"` while floating
|
|
1561
|
+
* and editable); Escape dismisses it and returns focus to the content with
|
|
1562
|
+
* the selection intact. A plugin that claims Escape itself (a consumer's
|
|
1563
|
+
* `@tiptap/suggestion` list, an AI stream) gets it first, and the Escape
|
|
1564
|
+
* that dismisses the bubble goes no further, so a dialog or drawer around
|
|
1565
|
+
* the editor closes only on the next one. Turning `readonly` on while the
|
|
1566
|
+
* bubble is shown hides it and closes its popups.
|
|
1567
|
+
*
|
|
1568
|
+
* A `readonly` editor renders **no toolbar in either appearance** (#498):
|
|
1569
|
+
* no `.mlv-editor__toolbar-band`, and no space kept for one. Turning
|
|
1570
|
+
* `readonly` on tears the bar down, closes every popup the editor owns and
|
|
1571
|
+
* returns focus from the bar or such a popup to the content, with the
|
|
1572
|
+
* selection intact; turning it off stamps the bar again in its position.
|
|
1573
|
+
* A consumer toolbar (`[mlvEditorToolbar]`, `[mlvEditorToolbarStart]`,
|
|
1574
|
+
* `[mlvEditorToolbarEnd]`) is stamped in the same band and goes with it.
|
|
1575
|
+
*/
|
|
1576
|
+
readonly toolbarAppearance: _angular_core.InputSignal<MlvEditorToolbarAppearance>;
|
|
1577
|
+
/**
|
|
1578
|
+
* Keeps the docked bar `position: sticky` against the page (or the nearest
|
|
1579
|
+
* consumer scroll container) while the surface is on screen, offset by
|
|
1580
|
+
* `--mlv-editor-toolbar-sticky-offset` (default `0`).
|
|
1581
|
+
*
|
|
1582
|
+
* It applies only to an **uncapped** **bar**. A capped editor
|
|
1583
|
+
* (`height` / `maxHeight`) scrolls inside its own viewport, and the bar
|
|
1584
|
+
* sits outside that scroller, so there is nothing for it to stick against;
|
|
1585
|
+
* the floating bubble follows the selection instead; and a `readonly`
|
|
1586
|
+
* editor renders no bar at all (#498). In each case the input is ignored
|
|
1587
|
+
* and `.mlv-editor--toolbar-sticky` is not stamped.
|
|
1588
|
+
*/
|
|
1589
|
+
readonly toolbarSticky: _angular_core.InputSignalWithTransform<boolean, BooleanInput>;
|
|
1467
1590
|
/** Complete Tiptap extension replacement; omit it for Malva's fresh preset. */
|
|
1468
1591
|
readonly extensions: _angular_core.InputSignal<Extensions | undefined>;
|
|
1469
1592
|
/** Placeholder displayed by the default extension preset. */
|
|
@@ -1490,6 +1613,50 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1490
1613
|
get imageUpload(): MlvEditorImageUploadControl;
|
|
1491
1614
|
/** View-only zoom percentage shared with the nearest toolbar. */
|
|
1492
1615
|
readonly zoom: _angular_core.WritableSignal<number>;
|
|
1616
|
+
/** @protected Resolved `height`, written into `--mlv-editor-height`; `null` writes nothing. */
|
|
1617
|
+
protected readonly _heightStyle: _angular_core.Signal<string | null>;
|
|
1618
|
+
/** @protected Resolved `minHeight`, written into `--mlv-editor-min-height`; `null` writes nothing. */
|
|
1619
|
+
protected readonly _minHeightStyle: _angular_core.Signal<string | null>;
|
|
1620
|
+
/** @protected Resolved `maxHeight`, written into `--mlv-editor-max-height`; `null` writes nothing. */
|
|
1621
|
+
protected readonly _maxHeightStyle: _angular_core.Signal<string | null>;
|
|
1622
|
+
/**
|
|
1623
|
+
* @protected Whether the editor is capped. Only `height` or `maxHeight`
|
|
1624
|
+
* switches it on; `minHeight` alone stays in auto mode. It is the one input
|
|
1625
|
+
* that turns `.mlv-editor__viewport` into a scroll container.
|
|
1626
|
+
*/
|
|
1627
|
+
protected readonly _capped: _angular_core.Signal<boolean>;
|
|
1628
|
+
/**
|
|
1629
|
+
* @protected Whether the editor stamps its toolbar at all, in either
|
|
1630
|
+
* appearance: never while `readonly` (#498 owner ruling, "a readonly editor
|
|
1631
|
+
* renders no toolbar"). The docked bar is torn down and the selection
|
|
1632
|
+
* bubble's pane stays empty; both come back when `readonly` turns off.
|
|
1633
|
+
*
|
|
1634
|
+
* This is the one switch, and it covers a consumer toolbar too: a complete
|
|
1635
|
+
* `[mlvEditorToolbar]` replacement and the `[mlvEditorToolbarStart]` /
|
|
1636
|
+
* `[mlvEditorToolbarEnd]` slots are stamped inside the same band. That is
|
|
1637
|
+
* an assumption the owner may reverse. Keeping a complete replacement while
|
|
1638
|
+
* `readonly` is `!this.readonly() || this._hasToolbarDef()` here for the
|
|
1639
|
+
* bar, and the default groups inside the band then need their own readonly
|
|
1640
|
+
* hiding; `_closeBarForReadonly()`'s `_barRendered()` early return must
|
|
1641
|
+
* then key on the removed region, not the band, or focus on a removed
|
|
1642
|
+
* default control drops to `<body>`. The bubble also gates itself on
|
|
1643
|
+
* `readonly` in `MlvEditorBubble._wanted()` / `_ownsContentKey()`, and
|
|
1644
|
+
* `_editorAttributes()` drops `aria-keyshortcuts`.
|
|
1645
|
+
*/
|
|
1646
|
+
protected readonly _toolbarRendered: _angular_core.Signal<boolean>;
|
|
1647
|
+
/**
|
|
1648
|
+
* @protected Whether the docked bar is stamped before or after the
|
|
1649
|
+
* viewport: the `'bar'` appearance while `_toolbarRendered()`. With it
|
|
1650
|
+
* false no band exists, so nothing reserves space for one and no sticky
|
|
1651
|
+
* extent is measured.
|
|
1652
|
+
*/
|
|
1653
|
+
protected readonly _barRendered: _angular_core.Signal<boolean>;
|
|
1654
|
+
/**
|
|
1655
|
+
* @protected Whether the docked bar is actually sticky: `toolbarSticky` on an
|
|
1656
|
+
* uncapped bar that renders (not while `readonly`). Drives
|
|
1657
|
+
* `.mlv-editor--toolbar-sticky` and the caret scroll margin.
|
|
1658
|
+
*/
|
|
1659
|
+
protected readonly _stickyToolbar: _angular_core.Signal<boolean>;
|
|
1493
1660
|
/** Whether the mounted editor currently accepts document mutations. */
|
|
1494
1661
|
readonly editable: _angular_core.Signal<boolean>;
|
|
1495
1662
|
/** Emits after the browser-only Tiptap editor has been created. */
|
|
@@ -1515,7 +1682,7 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1515
1682
|
/** @private Browser-only mount element for Tiptap's ProseMirror DOM. */
|
|
1516
1683
|
private readonly _content;
|
|
1517
1684
|
/**
|
|
1518
|
-
* @private
|
|
1685
|
+
* @private Zoomed layer (CSS `zoom`) the floating block handle is mounted into.
|
|
1519
1686
|
*
|
|
1520
1687
|
* Deliberately optional rather than `viewChild.required`: the block-handle
|
|
1521
1688
|
* `mount` capability is typed `() => HTMLElement | null`, and the extension
|
|
@@ -1524,6 +1691,11 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1524
1691
|
* uncaught error rather than the absent mount the contract already allows.
|
|
1525
1692
|
*/
|
|
1526
1693
|
private readonly _view;
|
|
1694
|
+
/**
|
|
1695
|
+
* @private Toolbar band currently stamped before or after the viewport.
|
|
1696
|
+
* Queried by declaration, so it follows the band across position changes.
|
|
1697
|
+
*/
|
|
1698
|
+
private readonly _toolbarBand;
|
|
1527
1699
|
/** @protected Complete projected toolbar replacement, if the consumer provides one. */
|
|
1528
1700
|
protected readonly _toolbarDefs: _angular_core.Signal<readonly MlvEditorToolbarDef[]>;
|
|
1529
1701
|
/** @protected Projected controls displayed before the built-in toolbar groups. */
|
|
@@ -1548,6 +1720,16 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1548
1720
|
private readonly _uploadAbortRegistry;
|
|
1549
1721
|
/** @private Physical host used to determine the composite focus boundary. */
|
|
1550
1722
|
private readonly _host;
|
|
1723
|
+
/**
|
|
1724
|
+
* @private Live ProseMirror `scrollMargin` (WCAG 2.2 SC 2.4.11). One stable
|
|
1725
|
+
* object passed on every `editorProps` write; its sides re-measure per read.
|
|
1726
|
+
* Read untracked: ProseMirror scrolls synchronously inside `updateState`,
|
|
1727
|
+
* which can run within `_synchronizeEditor`'s effect, and that effect must
|
|
1728
|
+
* not start depending on the toolbar inputs.
|
|
1729
|
+
*/
|
|
1730
|
+
private readonly _scrollMargin;
|
|
1731
|
+
/** @private Live ProseMirror `scrollThreshold`, paired with `_scrollMargin`. */
|
|
1732
|
+
private readonly _scrollThreshold;
|
|
1551
1733
|
/** @private Optional translated accessible defaults. */
|
|
1552
1734
|
private readonly _i18n;
|
|
1553
1735
|
/** @private Announces block moves politely; the editor content itself is not a live region. */
|
|
@@ -1574,13 +1756,7 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1574
1756
|
private _blurCheckQueued;
|
|
1575
1757
|
/** @private The last boundary event, retained until the microtask resolves focus ownership. */
|
|
1576
1758
|
private _pendingBlurEvent;
|
|
1577
|
-
/** @private
|
|
1578
|
-
private readonly _onHostFocusIn;
|
|
1579
|
-
/** @private Stable capture listener for focus leaving the physical host. */
|
|
1580
|
-
private readonly _onHostFocusOut;
|
|
1581
|
-
/** @private Stable capture listener that blocks disabled projected controls. */
|
|
1582
|
-
private readonly _onDisabledPointerOrClick;
|
|
1583
|
-
/** @private Stable capture listener that blocks disabled keyboard activation. */
|
|
1759
|
+
/** @private Blocks disabled keyboard activation; the other three subscribe to their handler directly. */
|
|
1584
1760
|
private readonly _onDisabledKeydown;
|
|
1585
1761
|
/** @protected Fallback-accessible name when no visible label is supplied. */
|
|
1586
1762
|
protected readonly _resolvedAriaLabel: _angular_core.Signal<string>;
|
|
@@ -1593,6 +1769,19 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1593
1769
|
constructor();
|
|
1594
1770
|
/** Creates the one Tiptap editor after Angular has rendered the mount element. */
|
|
1595
1771
|
ngAfterViewInit(): void;
|
|
1772
|
+
/**
|
|
1773
|
+
* @protected Focuses the editable content when the control's own
|
|
1774
|
+
* `<mlv-label>` is clicked.
|
|
1775
|
+
*
|
|
1776
|
+
* ProseMirror's contenteditable root is focusable but not HTML-labelable, so
|
|
1777
|
+
* `<label for>` can never name it and the native click-to-focus a field
|
|
1778
|
+
* label owes its control never ran — the visible label was inert (#216), the
|
|
1779
|
+
* same gap the three date/time pickers close. `readonly` still focuses (a
|
|
1780
|
+
* read-only `<textarea>` does), `disabled` returns early (the host is
|
|
1781
|
+
* `inert` anyway), and Tiptap's `focus` command restores the stored
|
|
1782
|
+
* selection rather than dropping the caret at the document start.
|
|
1783
|
+
*/
|
|
1784
|
+
protected _onLabelClick(): void;
|
|
1596
1785
|
/** Clears the document through Tiptap when the shared form wrapper is clearable. */
|
|
1597
1786
|
clearValue(): void;
|
|
1598
1787
|
/** @private Formats a completed block move and announces it politely. */
|
|
@@ -1656,6 +1845,24 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1656
1845
|
private _supportsMarkdown;
|
|
1657
1846
|
/** @private Emits the stable unsupported-Markdown error without throwing through Angular. */
|
|
1658
1847
|
private _emitUnsupportedMarkdownError;
|
|
1848
|
+
/**
|
|
1849
|
+
* @private Block extent the toolbar hides on its own side, in px.
|
|
1850
|
+
*
|
|
1851
|
+
* Only a sticky bar hides anything: its height plus its offset, at its
|
|
1852
|
+
* nearest scroll container. A docked bar sits outside the content, and the
|
|
1853
|
+
* floating bubble is an overlay that follows the selection, clear of it by
|
|
1854
|
+
* construction.
|
|
1855
|
+
* Sticky applies only to an uncapped bar (`_stickyToolbar`), so the margin
|
|
1856
|
+
* never lands on a capped viewport's own edge.
|
|
1857
|
+
*
|
|
1858
|
+
* Read by ProseMirror at scroll time, never for layout. ProseMirror applies
|
|
1859
|
+
* one margin at every scroll ancestor. For an uncapped editor the page is
|
|
1860
|
+
* usually the only one. With a consumer scroll container in between, the
|
|
1861
|
+
* band sticks to that container, where the margin is right; the page, one
|
|
1862
|
+
* scroll ancestor further out, also keeps the caret that far from its edge
|
|
1863
|
+
* although no band is there, which errs toward visibility.
|
|
1864
|
+
*/
|
|
1865
|
+
private _obscuredToolbarExtent;
|
|
1659
1866
|
/** @private Builds the exact accessible attributes assigned to Tiptap's contenteditable root. */
|
|
1660
1867
|
private _editorAttributes;
|
|
1661
1868
|
/** @internal Capture handler for focus entering the host or an owned overlay root. */
|
|
@@ -1666,7 +1873,22 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1666
1873
|
private _isFocusInsideComposite;
|
|
1667
1874
|
/** @private Whether a node belongs to the physical shell or an owned overlay. */
|
|
1668
1875
|
private _isOwnedFocusNode;
|
|
1669
|
-
/**
|
|
1876
|
+
/**
|
|
1877
|
+
* @private Subscribes the composite's host listeners, because overlay focus
|
|
1878
|
+
* happens outside Angular's view tree.
|
|
1879
|
+
*
|
|
1880
|
+
* Every one is registered in the **capture** phase, which is load-bearing
|
|
1881
|
+
* rather than incidental: ProseMirror binds its own handlers to `view.dom`,
|
|
1882
|
+
* a descendant of this host, so only a capture-phase listener on the host
|
|
1883
|
+
* runs ahead of them. The disabled handlers depend on that to call
|
|
1884
|
+
* `stopImmediatePropagation()` while the event is still travelling down —
|
|
1885
|
+
* from the bubble phase ProseMirror would already have acted on it. Capture
|
|
1886
|
+
* is carried through `fromEvent`'s third argument, and `editor-focus.spec.ts`
|
|
1887
|
+
* pins the ordering against descendant listeners.
|
|
1888
|
+
*
|
|
1889
|
+
* Called from `ngAfterViewInit`, which is not an injection context, so
|
|
1890
|
+
* `takeUntilDestroyed` is given the ref explicitly.
|
|
1891
|
+
*/
|
|
1670
1892
|
private _bindCompositeFocusEvents;
|
|
1671
1893
|
/** @private Stops all pointer/click/activation-key command surfaces while disabled. */
|
|
1672
1894
|
private _blockDisabledInteraction;
|
|
@@ -1674,12 +1896,25 @@ declare class MlvEditor extends MlvSignalFormControlBase<string | null> implemen
|
|
|
1674
1896
|
private _removeCompositeFocusForDisabledState;
|
|
1675
1897
|
/** @private Keeps the real ProseMirror root in sync with dynamic ARIA/tabindex state. */
|
|
1676
1898
|
private _synchronizeContentSurfaceState;
|
|
1899
|
+
/**
|
|
1900
|
+
* @private `readonly` just turned on over a docked bar, which this render
|
|
1901
|
+
* tears down (#498). Every popup the editor owns closes, and focus in the
|
|
1902
|
+
* band or in such a popup returns to the content first, through the same
|
|
1903
|
+
* registry call the selection bubble makes. Called from the constructor
|
|
1904
|
+
* effect, which is registered on the parent view, so it runs before this
|
|
1905
|
+
* component's template (and the wrapper-stamped band `@if`) refreshes: the
|
|
1906
|
+
* band and its focus are still there. A disabled editor is left alone, like
|
|
1907
|
+
* the bubble's own focus return: it takes no focus, even from a projected
|
|
1908
|
+
* consumer control, which the editor does not disable and which can hold
|
|
1909
|
+
* focus in the band of a disabled editor.
|
|
1910
|
+
*/
|
|
1911
|
+
private _closeBarForReadonly;
|
|
1677
1912
|
/** @private Aborts registered upload work while preserving the document/editor instance. */
|
|
1678
1913
|
private _abortInFlightUploads;
|
|
1679
1914
|
/** @private Destroys the owned Tiptap editor exactly once. */
|
|
1680
1915
|
private _destroyEditor;
|
|
1681
1916
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MlvEditor, never>;
|
|
1682
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MlvEditor, "mlv-editor", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "contentWidth": { "alias": "contentWidth"; "required": false; "isSignal": true; }; "extensions": { "alias": "extensions"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "characterLimit": { "alias": "characterLimit"; "required": false; "isSignal": true; }; "ariaLabelledBy": { "alias": "ariaLabelledBy"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "imageUploader": { "alias": "imageUploader"; "required": false; "isSignal": true; }; "imageUploadOptions": { "alias": "imageUploadOptions"; "required": false; "isSignal": true; }; "aiProvider": { "alias": "aiProvider"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "editorReady": "editorReady"; "focus": "focus"; "blur": "blur"; "selectionChange": "selectionChange"; "transaction": "transaction"; "editorError": "editorError"; "imageUploadSuccess": "imageUploadSuccess"; "imageUploadFailure": "imageUploadFailure"; "imageUploadCancelled": "imageUploadCancelled"; }, ["_toolbarDefs", "_toolbarStartDefs", "_toolbarEndDefs"], ["[mlvEditorToolbar]", "[mlvEditorToolbarStart]", "[mlvEditorToolbarEnd]", "[mlvEditorStatus]"], true, never>;
|
|
1917
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MlvEditor, "mlv-editor", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "contentWidth": { "alias": "contentWidth"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "toolbarPosition": { "alias": "toolbarPosition"; "required": false; "isSignal": true; }; "toolbarAppearance": { "alias": "toolbarAppearance"; "required": false; "isSignal": true; }; "toolbarSticky": { "alias": "toolbarSticky"; "required": false; "isSignal": true; }; "extensions": { "alias": "extensions"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "characterLimit": { "alias": "characterLimit"; "required": false; "isSignal": true; }; "ariaLabelledBy": { "alias": "ariaLabelledBy"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "imageUploader": { "alias": "imageUploader"; "required": false; "isSignal": true; }; "imageUploadOptions": { "alias": "imageUploadOptions"; "required": false; "isSignal": true; }; "aiProvider": { "alias": "aiProvider"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "editorReady": "editorReady"; "focus": "focus"; "blur": "blur"; "selectionChange": "selectionChange"; "transaction": "transaction"; "editorError": "editorError"; "imageUploadSuccess": "imageUploadSuccess"; "imageUploadFailure": "imageUploadFailure"; "imageUploadCancelled": "imageUploadCancelled"; }, ["_toolbarDefs", "_toolbarStartDefs", "_toolbarEndDefs"], ["[mlvEditorToolbar]", "[mlvEditorToolbarStart]", "[mlvEditorToolbarEnd]", "[mlvEditorStatus]"], true, never>;
|
|
1683
1918
|
}
|
|
1684
1919
|
|
|
1685
1920
|
/** A completed block move, reported so the host can announce it. */
|
|
@@ -1702,7 +1937,7 @@ interface MlvEditorBlockMove {
|
|
|
1702
1937
|
interface MlvEditorBlockHandleOptions {
|
|
1703
1938
|
/**
|
|
1704
1939
|
* Container the floating handle is appended to. Must be the layer carrying the
|
|
1705
|
-
* editor zoom
|
|
1940
|
+
* editor zoom (CSS `zoom`) so the handle shares its coordinate space.
|
|
1706
1941
|
*/
|
|
1707
1942
|
readonly mount: () => HTMLElement | null;
|
|
1708
1943
|
/** Accessible label for the handle, read live so locale changes apply. */
|
|
@@ -2439,6 +2674,18 @@ declare class MlvEditorTable {
|
|
|
2439
2674
|
protected readonly _context: _malva_ui_editor.MlvEditorToolbarContext;
|
|
2440
2675
|
/** @private Normalizes horizontal grid movement for RTL. */
|
|
2441
2676
|
private readonly _rtlService;
|
|
2677
|
+
/**
|
|
2678
|
+
* @private Host element; the scope horizontal arrow keys resolve their
|
|
2679
|
+
* direction against. The grid renders in a popup pane portaled out of this
|
|
2680
|
+
* subtree, so the handler speaks for the host, never for `event.target`.
|
|
2681
|
+
*/
|
|
2682
|
+
private readonly _elementRef;
|
|
2683
|
+
/**
|
|
2684
|
+
* @private Direction applying to this control, resolved once and cached
|
|
2685
|
+
* behind the shared `dir` observer rather than re-walked on every arrow
|
|
2686
|
+
* keypress.
|
|
2687
|
+
*/
|
|
2688
|
+
private readonly _direction;
|
|
2442
2689
|
/** @private Transaction and selection invalidation bridge. */
|
|
2443
2690
|
private readonly _revision;
|
|
2444
2691
|
/** @private Detached popup ownership for composite editor focus. */
|
|
@@ -2992,4 +3239,4 @@ declare class MlvEditorTextColor extends MlvEditorColorControl {
|
|
|
2992
3239
|
}
|
|
2993
3240
|
|
|
2994
3241
|
export { MLV_EDITOR_AI_CARET_CLASS, MLV_EDITOR_AI_CONTEXT, MLV_EDITOR_AI_PROVIDER, MLV_EDITOR_AI_STREAMING_CHUNK_CLASS, MLV_EDITOR_AI_STREAMING_CLASS, MLV_EDITOR_AI_SUGGESTION_CURRENT_CLASS, MLV_EDITOR_AI_SUGGESTION_DELETE_CLASS, MLV_EDITOR_AI_SUGGESTION_INSERT_CLASS, MLV_EDITOR_DEFAULT_IMAGE_UPLOAD_OPTIONS, MLV_EDITOR_IMAGE_UPLOADER, MLV_EDITOR_TOOLBAR_CONTEXT, MlvEditor, MlvEditorAiContext, MlvEditorAiMenu, MlvEditorAiReviewBar, MlvEditorAlignment, MlvEditorBlockHandle, MlvEditorBlockInsert, MlvEditorFileHandler, MlvEditorHeading, MlvEditorHighlight, MlvEditorImageUpload, MlvEditorImageUploadControl, MlvEditorInlineMarks, MlvEditorLink, MlvEditorList, MlvEditorStatus, MlvEditorTable, MlvEditorTableControls, MlvEditorTextColor, MlvEditorToolbar, MlvEditorToolbarDef, MlvEditorToolbarEndDef, MlvEditorToolbarStartDef, MlvEditorToolbarWidget, MlvEditorUndoRedo, MlvEditorUploadPlaceholder, MlvEditorZoom, applyMlvEditorAiSuggestions, countMlvEditorWords, mlvEditorAiDefaultActions, mlvEditorAiReplaceRange, mlvEditorBlockHandleExtensions, mlvEditorDefaultExtensions, mlvEditorDefaultImageUrlPolicy, mlvEditorFormattingExtensions, mlvEditorImageExtensions, mlvEditorListExtensions, mlvEditorMarkdownExtensions, mlvEditorTableExtensions, mlvEditorTableGeometry, mlvEditorUtilityExtensions, normalizeMlvEditorCharacterLimit, runMlvEditorAiStream };
|
|
2995
|
-
export type { MlvEditorAiAction, MlvEditorAiBuiltInTransformKind, MlvEditorAiFrameScheduler, MlvEditorAiOutputMode, MlvEditorAiProvider, MlvEditorAiRequest, MlvEditorAiReviewSuggestion, MlvEditorAiStatus, MlvEditorAiStreamErrorCode, MlvEditorAiStreamHandle, MlvEditorAiStreamOptions, MlvEditorAiStreamOutputMode, MlvEditorAiStreamResult, MlvEditorAiStreamStatus, MlvEditorAiSuggestion, MlvEditorAiSuggestionKind, MlvEditorAiSuggestionRange, MlvEditorAiSuggestionsOptions, MlvEditorAiSuggestionsSession, MlvEditorAiTransformKind, MlvEditorAiTransformOptions, MlvEditorBlockHandleOptions, MlvEditorBlockMove, MlvEditorContentWidth, MlvEditorDefaultExtensionOptions, MlvEditorError, MlvEditorErrorCode, MlvEditorFileHandlerEvent, MlvEditorFocusEvent, MlvEditorFormat, MlvEditorFormattingExtensionOptions, MlvEditorHeadingLevel, MlvEditorImageExtensionOptions, MlvEditorImageUploadCancelled, MlvEditorImageUploadContext, MlvEditorImageUploadFailure, MlvEditorImageUploadOptions, MlvEditorImageUploadResult, MlvEditorImageUploadSource, MlvEditorImageUploadSuccess, MlvEditorImageUploader, MlvEditorImageUrlPolicy, MlvEditorInsertUploadPlaceholderOptions, MlvEditorListExtensionOptions, MlvEditorMarkdownExtensionOptions, MlvEditorPendingUpload, MlvEditorRemoveUploadPlaceholderOptions, MlvEditorReplaceUploadPlaceholderOptions, MlvEditorSelectionChange, MlvEditorTableBox, MlvEditorTableExtensionOptions, MlvEditorTableGeometry, MlvEditorTableGeometryInput, MlvEditorToolbarContext, MlvEditorTransactionEvent, MlvEditorUpdateUploadPlaceholderOptions, MlvEditorUploadPlaceholderItem, MlvEditorUploadPlaceholderStorage, MlvEditorUtilityExtensionOptions };
|
|
3242
|
+
export type { MlvEditorAiAction, MlvEditorAiBuiltInTransformKind, MlvEditorAiFrameScheduler, MlvEditorAiOutputMode, MlvEditorAiProvider, MlvEditorAiRequest, MlvEditorAiReviewSuggestion, MlvEditorAiStatus, MlvEditorAiStreamErrorCode, MlvEditorAiStreamHandle, MlvEditorAiStreamOptions, MlvEditorAiStreamOutputMode, MlvEditorAiStreamResult, MlvEditorAiStreamStatus, MlvEditorAiSuggestion, MlvEditorAiSuggestionKind, MlvEditorAiSuggestionRange, MlvEditorAiSuggestionsOptions, MlvEditorAiSuggestionsSession, MlvEditorAiTransformKind, MlvEditorAiTransformOptions, MlvEditorBlockHandleOptions, MlvEditorBlockMove, MlvEditorContentWidth, MlvEditorDefaultExtensionOptions, MlvEditorError, MlvEditorErrorCode, MlvEditorFileHandlerEvent, MlvEditorFocusEvent, MlvEditorFormat, MlvEditorFormattingExtensionOptions, MlvEditorHeadingLevel, MlvEditorImageExtensionOptions, MlvEditorImageUploadCancelled, MlvEditorImageUploadContext, MlvEditorImageUploadFailure, MlvEditorImageUploadOptions, MlvEditorImageUploadResult, MlvEditorImageUploadSource, MlvEditorImageUploadSuccess, MlvEditorImageUploader, MlvEditorImageUrlPolicy, MlvEditorInsertUploadPlaceholderOptions, MlvEditorListExtensionOptions, MlvEditorMarkdownExtensionOptions, MlvEditorPendingUpload, MlvEditorRemoveUploadPlaceholderOptions, MlvEditorReplaceUploadPlaceholderOptions, MlvEditorSelectionChange, MlvEditorTableBox, MlvEditorTableExtensionOptions, MlvEditorTableGeometry, MlvEditorTableGeometryInput, MlvEditorToolbarAppearance, MlvEditorToolbarContext, MlvEditorToolbarPosition, MlvEditorTransactionEvent, MlvEditorUpdateUploadPlaceholderOptions, MlvEditorUploadPlaceholderItem, MlvEditorUploadPlaceholderStorage, MlvEditorUtilityExtensionOptions };
|