@gilav21/shadcn-angular-rte 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/README.md +43 -27
  2. package/fesm2022/{gilav21-shadcn-angular-rte-docx-parser-B8BeJWtY.mjs → gilav21-shadcn-angular-rte-docx-parser-DiBPweI4.mjs} +63 -38
  3. package/fesm2022/gilav21-shadcn-angular-rte-docx-parser-DiBPweI4.mjs.map +1 -0
  4. package/fesm2022/{gilav21-shadcn-angular-rte-docx-to-editor-html-Cl9eIhkC.mjs → gilav21-shadcn-angular-rte-docx-to-editor-html-BreagmS_.mjs} +43 -33
  5. package/fesm2022/gilav21-shadcn-angular-rte-docx-to-editor-html-BreagmS_.mjs.map +1 -0
  6. package/fesm2022/{gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CfjU_y-y.mjs → gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BnEAQOuU.mjs} +3561 -1901
  7. package/fesm2022/gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-BnEAQOuU.mjs.map +1 -0
  8. package/fesm2022/gilav21-shadcn-angular-rte-markup-safety-qJk8EoPk.mjs +69 -0
  9. package/fesm2022/gilav21-shadcn-angular-rte-markup-safety-qJk8EoPk.mjs.map +1 -0
  10. package/fesm2022/{gilav21-shadcn-angular-rte-pdf-readable-DmE-CIxv.mjs → gilav21-shadcn-angular-rte-pdf-readable-JvCpuNQH.mjs} +445 -124
  11. package/fesm2022/gilav21-shadcn-angular-rte-pdf-readable-JvCpuNQH.mjs.map +1 -0
  12. package/fesm2022/gilav21-shadcn-angular-rte.mjs +1 -1
  13. package/package.json +6 -2
  14. package/schematics/collection.json +10 -0
  15. package/schematics/ng-add/index.cjs +169 -0
  16. package/schematics/ng-add/schema.json +13 -0
  17. package/styles.css +2 -0
  18. package/types/gilav21-shadcn-angular-rte.d.ts +365 -114
  19. package/types/gilav21-shadcn-angular-rte.d.ts.map +1 -1
  20. package/fesm2022/gilav21-shadcn-angular-rte-docx-parser-B8BeJWtY.mjs.map +0 -1
  21. package/fesm2022/gilav21-shadcn-angular-rte-docx-to-editor-html-Cl9eIhkC.mjs.map +0 -1
  22. package/fesm2022/gilav21-shadcn-angular-rte-gilav21-shadcn-angular-rte-CfjU_y-y.mjs.map +0 -1
  23. package/fesm2022/gilav21-shadcn-angular-rte-pdf-readable-DmE-CIxv.mjs.map +0 -1
  24. package/theme.css +0 -159
@@ -795,7 +795,9 @@ declare abstract class RichTextEditorAddonHost {
795
795
  /**
796
796
  * Apply a built-in toolbar command to a specific block (its block-transform
797
797
  * engine): re-tag/list-wrap the block or run the formatting command, place
798
- * the caret, and record one history entry.
798
+ * the caret, and record one history entry. `null` runs the command at the
799
+ * current selection; a block no longer inside the editor (detached by an
800
+ * undo since it was captured) is ignored and nothing changes.
799
801
  */
800
802
  abstract executeToolbarCommandOnBlock(command: string, anchorBlock: HTMLElement | null): void;
801
803
  /**
@@ -1506,6 +1508,11 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
1506
1508
  tableContextMenuRef?: ElementRef<HTMLDivElement>;
1507
1509
  /** Output format: `'markdown'` converts to/from Markdown; `'html'` works with raw HTML. */
1508
1510
  readonly mode: _angular_core.InputSignal<EditorMode>;
1511
+ /**
1512
+ * Colour preset for this editor and its overlays — the names `change-theme`
1513
+ * accepts. Unset, the editor follows the app's global tokens.
1514
+ */
1515
+ readonly theme: _angular_core.InputSignal<"zinc" | "slate" | "stone" | "gray" | "neutral" | "red" | "rose" | "orange" | "green" | "blue" | "yellow" | "violet" | "amber" | undefined>;
1509
1516
  /** Visual border/focus style. See {@link EditorVariant}. */
1510
1517
  readonly variant: _angular_core.InputSignal<"default" | "ghost" | null | undefined>;
1511
1518
  /** Text size preset for the editor content. See {@link EditorSize}. */
@@ -1809,6 +1816,13 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
1809
1816
  }>;
1810
1817
  private tableContextMenuTarget;
1811
1818
  private tableContextMenuCloseHandler;
1819
+ /**
1820
+ * A running column resize: the first-row cells sizing the columns before
1821
+ * and after the dragged border (`after` is null at the table's end edge,
1822
+ * where the table itself grows), their widths when the drag began, and
1823
+ * `direction` 1 in LTR or -1 in RTL, where the column before the border
1824
+ * is the one on the right.
1825
+ */
1812
1826
  private tableResizeState;
1813
1827
  private readonly tableResizeCursor;
1814
1828
  private readonly onTableResizeMoveBound;
@@ -2068,8 +2082,9 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2068
2082
  * Insert plain text at the restored caret as one history entry, then focus
2069
2083
  * the editor — the method a page button next to the editor calls.
2070
2084
  *
2071
- * No-op while readonly or disabled, and for the empty string (an empty
2072
- * insert would otherwise record a history entry that undoes nothing).
2085
+ * No-op while readonly or disabled, when the text would take the document
2086
+ * past {@link maxLength}, and for the empty string (an empty insert would
2087
+ * otherwise record a history entry that undoes nothing).
2073
2088
  *
2074
2089
  * @publicApi
2075
2090
  */
@@ -2079,7 +2094,8 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2079
2094
  * editor. The markup goes through the editor's allow-list sanitizer, so a
2080
2095
  * `<script>` is dropped rather than inserted.
2081
2096
  *
2082
- * No-op while readonly or disabled, and when nothing survives sanitization.
2097
+ * No-op while readonly or disabled, when nothing survives sanitization, and
2098
+ * when its text would take the document past {@link maxLength}.
2083
2099
  * The single sanitize pass both answers that question and supplies the
2084
2100
  * markup that is inserted — deciding and inserting must not disagree.
2085
2101
  *
@@ -2391,7 +2407,6 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2391
2407
  * into a single text node, collapsing the block's lines into one.
2392
2408
  */
2393
2409
  private trailingBreakIn;
2394
- private insertNewlineInCodeBlock;
2395
2410
  private findAncestorByTag;
2396
2411
  private setSelectionRange;
2397
2412
  /**
@@ -2403,6 +2418,11 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2403
2418
  * down. Pasting is budgeted separately inside {@link onPaste}.
2404
2419
  */
2405
2420
  onBeforeInput(event: Event): void;
2421
+ /**
2422
+ * The text a drop or a paste would add, from the flavour that is inserted:
2423
+ * the HTML when there is some, else the plain text.
2424
+ */
2425
+ private transferredText;
2406
2426
  /**
2407
2427
  * Template-bound `paste` handler. The native paste is ALWAYS cancelled first
2408
2428
  * — nothing reaches the DOM unfiltered — and any pending debounced history
@@ -2418,9 +2438,9 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2418
2438
  onPaste(event: ClipboardEvent): void;
2419
2439
  /**
2420
2440
  * Enforce `maxLength` on a paste, returning `true` when the paste was fully
2421
- * handled here. Measures against the plain-text (`text/plain`) clipboard
2422
- * value rather than parsing the untrusted HTML — the over-limit path inserts
2423
- * plain text anyway, so the HTML length would be the wrong budget.
2441
+ * handled here. `text` is the visible text of what the paste inserts -- the
2442
+ * normalized HTML flavour when there is one -- and the over-limit path
2443
+ * inserts it, truncated, as plain text.
2424
2444
  */
2425
2445
  /**
2426
2446
  * The visible text an HTML fragment contributes, for budgeting against
@@ -2489,6 +2509,12 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2489
2509
  */
2490
2510
  private sweepSpentCaretAnchors;
2491
2511
  private perceivedText;
2512
+ /**
2513
+ * Whether adding `text` beside the document, replacing nothing, would take
2514
+ * it past {@link maxLength}: an insert that lands after the caret's line
2515
+ * frees none of the selection, which counted as freed let a block through.
2516
+ */
2517
+ private exceedsMaxLengthBeside;
2492
2518
  private exceedsMaxLength;
2493
2519
  private handlePasteMaxLength;
2494
2520
  /**
@@ -2635,6 +2661,13 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2635
2661
  * pinned to `'none'` for ~100ms while focus returns, which stops the mobile
2636
2662
  * software keyboard from flashing open. The caret is re-saved afterwards so
2637
2663
  * consecutive inserts append instead of stacking at the same spot.
2664
+ *
2665
+ * The guards every such insert shares come first: nothing is inserted while
2666
+ * the editor is read-only or disabled, and `plainText` -- what the insert
2667
+ * adds -- must fit {@link maxLength}. The limit is measured once the
2668
+ * editor's caret is restored, against what the insert will replace:
2669
+ * measured before, a selection elsewhere on the page was subtracted from
2670
+ * the document as if the insert would replace it, and the limit gave way.
2638
2671
  */
2639
2672
  private insertAtRestoredCaret;
2640
2673
  /** Commit addon DOM edits to the model + flush pending history (addon host surface). */
@@ -2848,6 +2881,12 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2848
2881
  y: number;
2849
2882
  }) => void): () => void;
2850
2883
  private getSelectedTextLength;
2884
+ /**
2885
+ * The selected text when the selection lies in the editor, else nothing:
2886
+ * only that is what an insert replaces. Text selected elsewhere on the page
2887
+ * freed budget it does not occupy, so an insert got past maxLength.
2888
+ */
2889
+ private selectedTextInEditor;
2851
2890
  private closeTableContextMenu;
2852
2891
  private setupTableContextMenuCloseHandlers;
2853
2892
  private adjustTableContextMenuPosition;
@@ -2871,8 +2910,9 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2871
2910
  onEditorContextMenu(event: MouseEvent): void;
2872
2911
  /**
2873
2912
  * Template-bound `mousemove` handler; its only job is the column-resize
2874
- * affordance. Within 4px of a cell's right edge — or its left edge, for any
2875
- * column but the first — it switches the editable area's cursor to
2913
+ * affordance. Within 4px of a column border that can be dragged (see
2914
+ * `resolveResizeBorder`: a cell's end or start edge, mirrored in RTL, never
2915
+ * the table's start edge) it switches the editable area's cursor to
2876
2916
  * `col-resize` and arms the flag {@link onEditorMouseDown} checks to start a
2877
2917
  * drag. Idle while a resize is already running, or when disabled/readonly.
2878
2918
  */
@@ -2914,7 +2954,7 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2914
2954
  private startTableResize;
2915
2955
  /**
2916
2956
  * Whether a pointer at `clientX` is within the column-resize hotspot of a
2917
- * cell's left or right edge.
2957
+ * border {@link resolveResizeBorder} can move.
2918
2958
  *
2919
2959
  * Shared by the mouse and touch paths. The mouse path also uses it to set
2920
2960
  * the `col-resize` cursor on hover; touch has no hover, so the touch path
@@ -2922,7 +2962,24 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2922
2962
  * being shared, a column simply could not be resized on a touch device.
2923
2963
  */
2924
2964
  private isNearResizeBorder;
2925
- private getResizeColumnIndex;
2965
+ /**
2966
+ * The column border a pointer at `clientX` grabs on `cell`, as the
2967
+ * first-row cells that size the rendered columns either side of it.
2968
+ *
2969
+ * Within 4px of the cell's end edge (right, or left in RTL) it is the
2970
+ * border after the cell's last column; within 4px of its start edge, the
2971
+ * border before its first column — none before the table's first column.
2972
+ * Columns come from the cell grid, not the cell's index in its row, which a
2973
+ * rowspan from above shifts. A fixed-layout table takes its column widths
2974
+ * from the first row alone, so the border is only resizable when each
2975
+ * column beside it has a first-row cell of its own (no colspan over it);
2976
+ * `after` is null for the table's end edge, which resizes the table.
2977
+ */
2978
+ private resolveResizeBorder;
2979
+ /** Which of the cell's inline edges `clientX` is on, if either. */
2980
+ private resizeEdgeAt;
2981
+ /** The cell covering `column` of a grid row, when it covers that column alone. */
2982
+ private singleColumnCell;
2926
2983
  private onTableResizeMove;
2927
2984
  /**
2928
2985
  * Touch equivalent of {@link onTableResizeMove}. Registered non-passive so
@@ -2946,12 +3003,17 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
2946
3003
  private onTableCellTouchMove;
2947
3004
  private onTableCellTouchEnd;
2948
3005
  private clearCellSelection;
3006
+ /**
3007
+ * The table as the browser lays it out: one slot per rendered row and
3008
+ * column, each holding the cell that covers it (`null` for a hole in a
3009
+ * ragged table). A cell starts at the first column its row has free after
3010
+ * the rowspans reaching down from above, so the grid is as wide as the
3011
+ * widest row *including* those carried-over columns — a row's own colspan
3012
+ * sum undercounts it and leaves the pushed-right cells out of the grid.
3013
+ */
2949
3014
  private buildCellGrid;
2950
- private getTotalRowColSpan;
2951
3015
  private fillCellGridRow;
2952
- private findNextAvailableColumn;
2953
3016
  private placeCellInGrid;
2954
- private isGridPositionInBounds;
2955
3017
  private getCellGridBounds;
2956
3018
  private findCellInRow;
2957
3019
  private updateCellSelection;
@@ -3125,7 +3187,19 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
3125
3187
  * own outer border must be left alone. */
3126
3188
  private clearTableBorders;
3127
3189
  private setBorderStyleNone;
3190
+ /**
3191
+ * The cells of `table` itself — not those of a table nested in one of
3192
+ * them, which `querySelectorAll('td, th')` would also return.
3193
+ */
3194
+ private ownTableCells;
3195
+ /**
3196
+ * Frame the table: a cell gets a border on each side that lies on the
3197
+ * table's edge as rendered — from its grid position, so a cell pushed
3198
+ * right by a rowspan is not taken for the first column, and with the
3199
+ * first column on the right in RTL.
3200
+ */
3128
3201
  private applyOuterTableBorders;
3202
+ /** Rules over the top and between rows; a cell reaching the last row gets none below. */
3129
3203
  private applyHorizontalTableBorders;
3130
3204
  /**
3131
3205
  * Set `text-align` on the single cell the table context menu targets — not
@@ -3685,7 +3759,10 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
3685
3759
  private setSelectionAtNodeEnd;
3686
3760
  /**
3687
3761
  * Apply a built-in toolbar command to a specific block (addon host surface):
3688
- * the block-transform engine used by the slash-commands addon.
3762
+ * the block-transform engine used by the slash-commands addon. With `null`
3763
+ * the command runs at the current selection. A block that is no longer
3764
+ * inside the editor — one an addon captured before an undo or `writeValue`
3765
+ * rewrote the content — is ignored and nothing changes.
3689
3766
  */
3690
3767
  executeToolbarCommandOnBlock(command: string, anchorBlock: HTMLElement | null): void;
3691
3768
  private insertInlineCodeFromSlash;
@@ -4109,6 +4186,13 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
4109
4186
  private lastReconstructedHtml;
4110
4187
  private reconstructHtmlCached;
4111
4188
  private pushHistory;
4189
+ /**
4190
+ * Drop the oldest entries past the history limit. Every entry must still
4191
+ * reconstruct the HTML it was pushed with, so the head is always a
4192
+ * keyframe: a delta about to become the head is rebuilt into a full
4193
+ * snapshot while the base it depends on is still in the stack.
4194
+ */
4195
+ private trimHistoryToLimit;
4112
4196
  /**
4113
4197
  * Undo one step — mirrors `Ctrl`/`Cmd`+`Z`. Flushes a pending typing burst
4114
4198
  * first, so one call takes back the whole burst rather than half of it.
@@ -4197,7 +4281,7 @@ declare class RichTextEditorComponent extends RichTextEditorAddonHost implements
4197
4281
  private highlightCaretCodeBlock;
4198
4282
  ngOnDestroy(): void;
4199
4283
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<RichTextEditorComponent, never>;
4200
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<RichTextEditorComponent, "ui-rich-text-editor", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "toolbarItems": { "alias": "toolbarItems"; "required": false; "isSignal": true; }; "customToolbarItems": { "alias": "customToolbarItems"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "markdownShortcuts": { "alias": "markdownShortcuts"; "required": false; "isSignal": true; }; "counter": { "alias": "counter"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "history": { "alias": "history"; "required": false; "isSignal": true; }; "findDebounceMs": { "alias": "findDebounceMs"; "required": false; "isSignal": true; }; "codeHighlightDebounceMs": { "alias": "codeHighlightDebounceMs"; "required": false; "isSignal": true; }; "allowedImageHosts": { "alias": "allowedImageHosts"; "required": false; "isSignal": true; }; "allowedLinkSchemes": { "alias": "allowedLinkSchemes"; "required": false; "isSignal": true; }; "blockedImageMessage": { "alias": "blockedImageMessage"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "dir": { "alias": "dir"; "required": false; "isSignal": true; }; }, { "customToolbarAction": "customToolbarAction"; "htmlChange": "htmlChange"; "markdownChange": "markdownChange"; "wordCountChange": "wordCountChange"; "historyChange": "historyChange"; "imageBlocked": "imageBlocked"; "focused": "focused"; "blurred": "blurred"; }, never, never, true, never>;
4284
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<RichTextEditorComponent, "ui-rich-text-editor", never, { "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "theme": { "alias": "theme"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "toolbarItems": { "alias": "toolbarItems"; "required": false; "isSignal": true; }; "customToolbarItems": { "alias": "customToolbarItems"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "markdownShortcuts": { "alias": "markdownShortcuts"; "required": false; "isSignal": true; }; "counter": { "alias": "counter"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "history": { "alias": "history"; "required": false; "isSignal": true; }; "findDebounceMs": { "alias": "findDebounceMs"; "required": false; "isSignal": true; }; "codeHighlightDebounceMs": { "alias": "codeHighlightDebounceMs"; "required": false; "isSignal": true; }; "allowedImageHosts": { "alias": "allowedImageHosts"; "required": false; "isSignal": true; }; "allowedLinkSchemes": { "alias": "allowedLinkSchemes"; "required": false; "isSignal": true; }; "blockedImageMessage": { "alias": "blockedImageMessage"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "class": { "alias": "class"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "ariaDescribedBy": { "alias": "ariaDescribedBy"; "required": false; "isSignal": true; }; "dir": { "alias": "dir"; "required": false; "isSignal": true; }; }, { "customToolbarAction": "customToolbarAction"; "htmlChange": "htmlChange"; "markdownChange": "markdownChange"; "wordCountChange": "wordCountChange"; "historyChange": "historyChange"; "imageBlocked": "imageBlocked"; "focused": "focused"; "blurred": "blurred"; }, never, never, true, never>;
4201
4285
  }
4202
4286
 
4203
4287
  /**
@@ -4237,12 +4321,6 @@ declare const DEFAULT_LINK_SCHEMES: readonly string[];
4237
4321
  declare class RichTextSanitizerService {
4238
4322
  private readonly document;
4239
4323
  /** Allowlisted elements - only these can appear in sanitized output */
4240
- /**
4241
- * Whether `tagName` survives {@link sanitize}. The markdown service asks so
4242
- * it can decide whether a `<` in the source opens a real tag or is just a
4243
- * less-than sign the author typed.
4244
- */
4245
- isAllowedTag(tagName: string): boolean;
4246
4324
  private readonly ALLOWED_TAGS;
4247
4325
  /** Allowlisted attributes per element */
4248
4326
  private readonly ALLOWED_ATTRS;
@@ -4250,8 +4328,6 @@ declare class RichTextSanitizerService {
4250
4328
  private readonly ALLOWED_STYLE_PROPERTIES;
4251
4329
  /** Allowed class patterns (for syntax highlighting) */
4252
4330
  private readonly ALLOWED_CLASS_PATTERNS;
4253
- /** Dangerous URL protocols to block */
4254
- private readonly DANGEROUS_PROTOCOLS;
4255
4331
  /** Event handler attributes pattern */
4256
4332
  private readonly EVENT_HANDLER_PATTERN;
4257
4333
  /** Attributes an addon rule may never target — the security boundary stays here. */
@@ -4296,6 +4372,20 @@ declare class RichTextSanitizerService {
4296
4372
  * the next read took apart, so the document gained an empty paragraph on
4297
4373
  * every pass. The wrapper moves inside instead, around each inline run, so
4298
4374
  * its formatting survives: `<b><p>x</p></b>` becomes `<p><b>x</b></p>`.
4375
+ *
4376
+ * Innermost wrapper first, so each one finds the ones inside it already
4377
+ * pushed down and descends only to the runs, never through them again:
4378
+ * outermost first re-walked every wrapper nested below, and unclosed inline
4379
+ * tags nest thousands deep. It also keeps the wrappers in their written
4380
+ * order around each run. The moves keep every holder in the tree, and
4381
+ * holding its block, so the holders are found once, up front.
4382
+ *
4383
+ * Each run takes each wrapper around it once, so the output is the runs
4384
+ * times the wrappers -- quadratic when a wrapper is left open around every
4385
+ * block. It is bounded, block by block: a block is not walked again for a
4386
+ * copy of a wrapper already walked through it, which adds nothing, nor past
4387
+ * MAX_NESTING_DEPTH wrappers, as every nested construct is capped. A copy of
4388
+ * the very wrapper already around a run is skipped for the same reason.
4299
4389
  */
4300
4390
  private pushInlineWrappersIntoBlocks;
4301
4391
  /** Wrap each inline piece of `node` in a copy of `wrapper`, descending through blocks. */
@@ -4371,14 +4461,15 @@ declare class RichTextSanitizerService {
4371
4461
  */
4372
4462
  private normalizeStrayLines;
4373
4463
  /**
4374
- * Runs of inline content between the block children of `el`.
4464
+ * `children` with each run of inline content between the blocks in a
4465
+ * paragraph of its own, everything else in place.
4375
4466
  *
4376
4467
  * A block ENDS a run and is never part of one. Letting a nested list stay
4377
4468
  * in the run — because the sub-list exception says it does not make its
4378
4469
  * item a container — moved the list into the new paragraph, producing a
4379
4470
  * `<ul>` inside a `<p>` and one more empty paragraph on every save.
4380
4471
  */
4381
- private strayRunsOf;
4472
+ private withStrayRunsWrapped;
4382
4473
  /**
4383
4474
  * Whether a block child means its host's own text needs a line of its own.
4384
4475
  *
@@ -4571,9 +4662,45 @@ declare class RichTextSanitizerService {
4571
4662
  stripTags(html: string): string;
4572
4663
  /** Tags that should be removed entirely (including content) */
4573
4664
  private readonly TAGS_TO_REMOVE;
4665
+ /**
4666
+ * Elements that change how the markup INSIDE them is parsed: MathML and SVG
4667
+ * are foreign content, and the rest are scope boundaries a `<table>` does
4668
+ * not close a paragraph across. Unwrapped, their content kept a shape the
4669
+ * parser never builds -- `<p>a <math><mtext><table>` left a table inside a
4670
+ * paragraph -- so the output read back as a different document, the
4671
+ * instability mutation XSS is built on. Removed whole, the author's text
4672
+ * went with them: "Click <button>Save</button> to continue" lost a word.
4673
+ * They become their text alone, which keeps the words and none of the
4674
+ * structure.
4675
+ */
4676
+ private readonly TAGS_TO_FLATTEN;
4677
+ /**
4678
+ * Copy one element, or what of it is safe, into `target`. Returns whether
4679
+ * anything in it was removed rather than copied, so a paragraph can tell an
4680
+ * emptiness sanitising caused from one the author wrote.
4681
+ */
4574
4682
  private processElementNode;
4683
+ /**
4684
+ * Copy `element` into `target` as one text node of the text it shows --
4685
+ * without the script or style text a removed tag holds. Walked with a
4686
+ * stack: foreign content nests as deep as the parser allows.
4687
+ *
4688
+ * The element was a box of its own, so its text is set apart from text
4689
+ * right before it: two buttons side by side read "Accept Decline", not
4690
+ * one fused word.
4691
+ */
4692
+ private flattenToText;
4693
+ /** Whether an image that named a source was left with neither a `src` nor a blocked-source marker. */
4694
+ private lostItsSource;
4695
+ /**
4696
+ * Whether a block renders nothing: no element that draws, and no text but
4697
+ * collapsible whitespace. A non-breaking space is the author's blank line
4698
+ * and counts as content.
4699
+ */
4700
+ private showsNothingAtAll;
4575
4701
  /**
4576
4702
  * Process nodes recursively, copying safe content to clean container.
4703
+ * Returns whether any of them was removed rather than copied.
4577
4704
  */
4578
4705
  private processNodes;
4579
4706
  /**
@@ -4680,6 +4807,11 @@ declare class RichTextPasteNormalizerService {
4680
4807
  private parseWordListItem;
4681
4808
  private convertWordLists;
4682
4809
  private stripListBulletSpan;
4810
+ /**
4811
+ * Nest a run of Word list paragraphs by their mso-list level: consecutive
4812
+ * items at one level share one list under the same parent item, and an item
4813
+ * at a shallower level closes every deeper list.
4814
+ */
4683
4815
  private buildNestedList;
4684
4816
  private ensureNestedListParent;
4685
4817
  private readonly systemColorMap;
@@ -4740,7 +4872,27 @@ declare class RichTextPasteNormalizerService {
4740
4872
  private removeMetaTags;
4741
4873
  private stripClassAndIdAttributes;
4742
4874
  private isEffectivelyEmpty;
4875
+ /**
4876
+ * Drop wrappers that carry nothing: an attribute-less span with no visible
4877
+ * content and a whitespace-only paragraph that has siblings.
4878
+ *
4879
+ * A span holding only whitespace is unwrapped, never deleted -- that
4880
+ * whitespace is often the only thing separating two words
4881
+ * (`<b>a</b><span> </span><i>b</i>`, or a Word spacerun), and deleting it
4882
+ * glued them together.
4883
+ */
4743
4884
  private removeEmptyElements;
4885
+ /**
4886
+ * The text nodes inside Word's `mso-spacerun:yes` runs: spaces the author
4887
+ * typed, written as nbsp so they keep their width. Collected as nodes rather
4888
+ * than elements because removeEmptyElements unwraps the whitespace-only run
4889
+ * span, while the text node itself survives.
4890
+ */
4891
+ private collectSpacerunText;
4892
+ /**
4893
+ * Collapse each run of two or more nbsp into one space, leaving code and
4894
+ * spacerun text (see {@link collectSpacerunText}) as written.
4895
+ */
4744
4896
  private normalizeWhitespace;
4745
4897
  private readonly SEMANTIC_TAGS;
4746
4898
  private applySemanticStyleToElement;
@@ -4765,6 +4917,15 @@ interface MarkdownSpanSerializer {
4765
4917
  declare class RichTextMarkdownService {
4766
4918
  private readonly sanitizer;
4767
4919
  private readonly spanSerializers;
4920
+ /** A code tag form the inline passes read back: their syntax escaped, an image as markdown. */
4921
+ private readonly inlineCodeTag;
4922
+ /**
4923
+ * A code tag form that opens a raw HTML block, read back verbatim: nothing
4924
+ * in it is markdown, so its text is only HTML-escaped and an image is its tag.
4925
+ * Written as markdown there, the image came back as the characters of its
4926
+ * syntax, and every escaped asterisk as a visible backslash.
4927
+ */
4928
+ private readonly rawCodeTag;
4768
4929
  /**
4769
4930
  * Register a span serializer consulted before the built-in mention/tag
4770
4931
  * handling in {@link toMarkdown}. Returns a teardown that unregisters it.
@@ -4773,27 +4934,17 @@ declare class RichTextMarkdownService {
4773
4934
  /**
4774
4935
  * Convert Markdown to sanitized HTML. Block constructs are parsed before
4775
4936
  * inline ones — the order of the passes below is load-bearing.
4776
- */
4777
- toHtml(markdown: string): string;
4778
- /**
4779
- * Replace every raw `<span …>` / `</span>` tag and `data-action-*` image
4780
- * tag with a placeholder token the markdown pipeline treats as opaque
4781
- * text, so escaping and block parsing leave the tag intact while its inner
4782
- * content is still processed. The restored tags are re-sanitized, so
4783
- * protecting non-action spans (rare in markdown) is harmless. Any private-
4784
- * use delimiter chars already in the input are stripped first so user
4785
- * content can never spoof a token.
4786
- */
4787
- /**
4788
- * Whether a tag written in the source is markup or prose about markup.
4789
4937
  *
4790
- * An author writing "the <table> element has <tr> children" means those as
4791
- * words; treating them as markup turned the sentence into a real table with
4792
- * the prose swallowed into a cell. Real markup comes in matched pairs, so an
4793
- * unpaired non-void tag is text.
4938
+ * Raw HTML follows CommonMark 0.31.2. A raw HTML block (§4.6), at the top
4939
+ * level or inside a quote, a list item or a details body, passes through
4940
+ * verbatim to its end condition -- a blank line after a block tag or a lone
4941
+ * tag, the closing tag of `<pre>`/`<script>`/`<style>`/`<textarea>`, the end
4942
+ * of a comment -- so `<details>`, a blank line, markdown, a blank line and
4943
+ * `</details>` renders the markdown inside the element. Inside a paragraph
4944
+ * every well-formed tag, comment or declaration is raw HTML (§6.6), paired
4945
+ * or not. The sanitizer still judges the whole output.
4794
4946
  */
4795
- private isMarkupTag;
4796
- private protectRawTags;
4947
+ toHtml(markdown: string): string;
4797
4948
  /**
4798
4949
  * Lift fenced code bodies out of the source before anything else touches
4799
4950
  * them, already converted to their final `<pre><code>` form. Restored after
@@ -4801,17 +4952,39 @@ declare class RichTextMarkdownService {
4801
4952
  * with no markup smuggled through it into the live document.
4802
4953
  */
4803
4954
  private protectCodeFences;
4955
+ /**
4956
+ * Park every top-level raw HTML block (CommonMark 0.31.2 §4.6) whole: like a
4957
+ * fence it is one opaque block that no markdown pass may rewrite, restored
4958
+ * verbatim for the sanitizer to judge.
4959
+ *
4960
+ * Every pass's delimiters are stripped from the block, not only this pass's
4961
+ * own: it runs before the others strip theirs, and a restored block is
4962
+ * scanned again by the restores after it, so a delimiter typed inside it
4963
+ * would forge another pass's token.
4964
+ */
4965
+ private protectHtmlBlocks;
4804
4966
  /**
4805
4967
  * Park a backslash-escaped punctuation character so no later pass reads it
4806
- * as syntax.
4968
+ * as syntax, and every inline raw HTML construct of CommonMark 0.31.2 §6.6
4969
+ * -- an open or closing tag, a comment, a processing instruction, a
4970
+ * declaration, a CDATA section -- in `tagStore`.
4807
4971
  *
4808
4972
  * CommonMark: a backslash before any ASCII punctuation makes that character
4809
4973
  * literal. Neither half of that worked -- "2 \\* 3 \\* 4" came out as
4810
4974
  * "2 \\ 3 \\ 4" in italics, so the escape was ignored AND the backslash
4811
4975
  * rendered. Others (\\#, \\-, \\[) left a visible backslash.
4812
4976
  *
4813
- * Runs after protectInlineCode, so a backslash inside `code` stays literal
4814
- * as the spec requires, and before every syntax pass.
4977
+ * One left-to-right scan, because escapes, code spans and raw HTML take
4978
+ * precedence by position: a backslash inside `code` or inside a tag stays
4979
+ * literal (example 631), and a backtick inside a tag opens no code span.
4980
+ *
4981
+ * Raw HTML is any well-formed construct, paired or not, known or not; the
4982
+ * sanitizer, not this reader, decides what survives. Text that only mentions
4983
+ * a tag is written with its "<" escaped, as toMarkdown does for every
4984
+ * tag-shaped "<" in prose. Closing tags are parked like opening ones:
4985
+ * escaping "</u>" but not "<u>" appended another visible "</u>" on every
4986
+ * save. Every pass's delimiters are stripped first, so user content can
4987
+ * never spoof a token.
4815
4988
  */
4816
4989
  private protectEscapes;
4817
4990
  /** Put escaped characters back as literal text, HTML-escaped. */
@@ -4828,8 +5001,9 @@ declare class RichTextMarkdownService {
4828
5001
  private restoreCodeFences;
4829
5002
  private restoreRawTags;
4830
5003
  /**
4831
- * Escape HTML entities but preserve Markdown syntax. Only `<`/`>` that look
4832
- * like HTML tags are escaped, so characters carrying Markdown meaning survive.
5004
+ * Escape the angle brackets left in the text. Every raw HTML construct is
5005
+ * parked by now (see protectEscapes), so a "<" left is text; a ">" is kept
5006
+ * where it can be a quote marker.
4833
5007
  */
4834
5008
  private escapeHtmlInContent;
4835
5009
  /**
@@ -4897,7 +5071,11 @@ declare class RichTextMarkdownService {
4897
5071
  private isTableRow;
4898
5072
  /** The `| --- | :--: |` row that makes the line above it a header. */
4899
5073
  private isTableSeparator;
4900
- /** Cells of one row, honouring `\\|` escapes inside cell text. */
5074
+ /**
5075
+ * Cells of one row. Every pipe here is a cell boundary: an escaped `\|` in
5076
+ * cell text never reaches this pass, because protectEscapes parks it before
5077
+ * any block is parsed.
5078
+ */
4901
5079
  private splitTableRow;
4902
5080
  /**
4903
5081
  * Parse horizontal rules (---, ***, ___).
@@ -4948,12 +5126,6 @@ declare class RichTextMarkdownService {
4948
5126
  * attribute of its own.
4949
5127
  */
4950
5128
  private attr;
4951
- /**
4952
- * An attribute value made of document text, which escapeHtmlInContent has
4953
- * already escaped: only a quote is escaped here. Escaped again, a "<" in alt
4954
- * text came back as the characters "&lt;", one more layer on every save.
4955
- */
4956
- private textAttr;
4957
5129
  /** Restore the characters {@link shieldUrl} hid, once those passes are done. */
4958
5130
  private unshieldUrls;
4959
5131
  /**
@@ -4976,6 +5148,9 @@ declare class RichTextMarkdownService {
4976
5148
  * parenthesis the target grammar cannot carry (see markdownTarget): the real
4977
5149
  * character reaches the sanitizer and the attribute, rather than the parked
4978
5150
  * token, which sanitizeImageSrc percent-encoded into the address.
5151
+ *
5152
+ * A title after the destination is split off and returned apart, typed the
5153
+ * same way.
4979
5154
  */
4980
5155
  private targetSource;
4981
5156
  /**
@@ -5017,6 +5192,20 @@ declare class RichTextMarkdownService {
5017
5192
  * Parse links [text](url).
5018
5193
  */
5019
5194
  private parseLinks;
5195
+ /**
5196
+ * Remove a paragraph whose only content the media passes rejected.
5197
+ *
5198
+ * parseParagraphs must wrap lines before parseImages runs (the order is
5199
+ * load-bearing), so a line holding only an unsafe image was wrapped first
5200
+ * and then emptied, leaving a `<p></p>` the author never wrote -- visible
5201
+ * spacing under prose margins. A paragraph is the parser's wrapper for
5202
+ * content, so with its content gone it goes too; a heading or list item the
5203
+ * author marked keeps its structure. Only parser-written `<p>` is literal at
5204
+ * this point: an author's raw `<p></p>` is still parked and survives. One
5205
+ * separating newline goes with the paragraph, so its neighbours keep the
5206
+ * single newline between them.
5207
+ */
5208
+ private dropEmptiedParagraphs;
5020
5209
  /**
5021
5210
  * Parse bold and italic, in this order so the longer delimiters win:
5022
5211
  *
@@ -5076,10 +5265,10 @@ declare class RichTextMarkdownService {
5076
5265
  */
5077
5266
  private handleCodeTag;
5078
5267
  /**
5079
- * A code element's content for its tag form: its text escaped, each break as
5080
- * the tag, each image as markdown, and newlines as character references -- a
5081
- * raw one ended a heading or a task row the tag sat in, a blank line split the
5082
- * tag pair, and the break rewrite changed the code's own spaces.
5268
+ * A code element's content for its tag form: its text and images as `writer`
5269
+ * writes them, each break as the tag, and newlines as character references --
5270
+ * a raw one ended a heading or a task row the tag sat in, a blank line split
5271
+ * the tag pair, and the break rewrite changed the code's own spaces.
5083
5272
  */
5084
5273
  private codeTagContent;
5085
5274
  private handleAnchorTag;
@@ -5117,11 +5306,13 @@ declare class RichTextMarkdownService {
5117
5306
  /**
5118
5307
  * A code block as its tag pair, on one markdown line.
5119
5308
  *
5120
- * One line, with every newline written as a character reference, because a
5121
- * raw newline inside the pair would let the block passes split it: the
5122
- * `<pre>` and `</pre>` are parked separately and the lines between them are
5123
- * read as markdown. The reference decodes to the newline when the sanitizer
5124
- * parses the restored tag, so the code keeps its own line breaks.
5309
+ * One line, with every newline written as a character reference. At the
5310
+ * margin the pair opens a raw HTML block and is read back verbatim; inside a
5311
+ * list item or a quote it is read inline, where a raw newline would let the
5312
+ * block passes split it: the `<pre>` and `</pre>` are parked separately and
5313
+ * the lines between them are read as markdown. The reference decodes to the
5314
+ * newline when the sanitizer parses the restored tag, so the code keeps its
5315
+ * own line breaks.
5125
5316
  */
5126
5317
  private preTagForm;
5127
5318
  private handleUlTag;
@@ -5312,11 +5503,14 @@ declare function richTextRequired(): ValidatorFn;
5312
5503
  /**
5313
5504
  * Cap the number of *visible* characters, so `<strong>` tags and `**` markers
5314
5505
  * do not eat a 280-character budget. Line breaks and block boundaries are not
5315
- * characters. Emoji count in UTF-16 units, matching Angular's `maxLength` and
5316
- * the editor's own character counter.
5506
+ * characters. A character is what a reader sees as one (a grapheme cluster),
5507
+ * counted by the same helper as the editor's own counter, so an emoji is one
5508
+ * character here and there — unlike Angular's `maxLength`, which counts UTF-16
5509
+ * units.
5317
5510
  *
5318
5511
  * @returns Angular's `{ maxlength: { requiredLength, actualLength } }`, so
5319
5512
  * `ui-field-auto-errors` renders its existing message with no configuration.
5513
+ * `actualLength` is in the same characters.
5320
5514
  */
5321
5515
  declare function richTextMaxLength(max: number): ValidatorFn;
5322
5516
  /**
@@ -5507,8 +5701,28 @@ declare function isNestedList(node: Node): boolean;
5507
5701
  * empty paragraph on every pass.
5508
5702
  */
5509
5703
  declare function isPhrasing(node: Node): boolean;
5510
- /** An inline element that wraps a block: a shape the parser keeps and nothing downstream can hold. */
5511
- declare function isInlineHoldingBlock(node: Node): boolean;
5704
+ /**
5705
+ * `node`'s children, walked by sibling rather than read from `childNodes`.
5706
+ *
5707
+ * Reading `childNodes` makes some DOM implementations keep that live list up to
5708
+ * date on every later change to the node, a walk of every child per insert or
5709
+ * removal: a pass that read a host holding thousands of lines, and then wrapped
5710
+ * them, took time quadratic in the host.
5711
+ */
5712
+ declare function childList(node: Node): ChildNode[];
5713
+ /**
5714
+ * Every inline element under `root` that wraps a block -- a shape the parser
5715
+ * keeps and nothing downstream can hold -- innermost first, with
5716
+ * {@link isPhrasing} answered for the whole tree from the same single pass.
5717
+ *
5718
+ * Found from the leaves up in one pass. Asking isPhrasing of each element walks
5719
+ * its whole subtree again, which is quadratic in the nesting depth, and unclosed
5720
+ * inline tags nest thousands deep: three thousand `<b>` took eight seconds.
5721
+ */
5722
+ declare function inlineElementsHoldingBlocks(root: Element): {
5723
+ holders: Element[];
5724
+ phrasing: (node: Node) => boolean;
5725
+ };
5512
5726
  /** A task row's content and the nested lists under it; see rowRunsOf. */
5513
5727
  interface RowRun {
5514
5728
  readonly content: Node[];
@@ -5799,7 +6013,7 @@ interface RichTextActionDefinition {
5799
6013
  id: string;
5800
6014
  label: string;
5801
6015
  description?: string;
5802
- /** Lucide icon name shown in the picker. */
6016
+ /** Icon name shown in the picker. */
5803
6017
  icon?: string;
5804
6018
  triggers: RichTextActionTrigger[];
5805
6019
  /** Which targets the action may attach to. Default: both. */
@@ -5923,8 +6137,10 @@ declare class RichTextActionsDirective {
5923
6137
  /**
5924
6138
  * An action was written to the document (attach or edit). A combined
5925
6139
  * action emits twice — once for `'click'`, once for `'hover'` — with the
5926
- * params each trigger received. Not emitted when the flow aborts because
5927
- * the target selection was lost.
6140
+ * params each trigger received. Not emitted when the target was lost —
6141
+ * the text selection could not be restored, or the captured image or
6142
+ * action element left the editor while the dialog was open (setContent,
6143
+ * undo): nothing is written and a dialog awaiting confirm stays open.
5928
6144
  */
5929
6145
  readonly actionAttached: _angular_core.OutputEmitterRef<{
5930
6146
  actionId: string;
@@ -5989,6 +6205,15 @@ declare class RichTextActionsDirective {
5989
6205
  */
5990
6206
  private injectVisualizationStyles;
5991
6207
  private releaseVisualizationStyles;
6208
+ /**
6209
+ * Whether the element the flow captured can no longer take the action,
6210
+ * logging when so. An image flow always captures its image, and any
6211
+ * captured element must still be inside the editor: setContent, undo or
6212
+ * writeValue can replace the content while the dialog is open, and an
6213
+ * action written onto the detached node would be reported as attached
6214
+ * although the document never changed.
6215
+ */
6216
+ private targetLost;
5992
6217
  private applyAction;
5993
6218
  private applyCombined;
5994
6219
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<RichTextActionsDirective, never>;
@@ -6871,6 +7096,7 @@ declare const RICH_TEXT_FILE_IMPORT_LOCALES: Record<string, RichTextFileImportLo
6871
7096
 
6872
7097
  declare class RichTextFileImportDirective {
6873
7098
  private readonly host;
7099
+ private readonly sanitizer;
6874
7100
  private readonly injector;
6875
7101
  private readonly vcr;
6876
7102
  /** Locale for the addon UI: a registry key (`'en'`/`'he'`/…) or a full dictionary. */
@@ -6891,7 +7117,7 @@ declare class RichTextFileImportDirective {
6891
7117
  readonly uiRteFileImportAccept: _angular_core.InputSignal<string | undefined>;
6892
7118
  /** Emits the `File` when an import begins. */
6893
7119
  readonly fileImportStart: _angular_core.OutputEmitterRef<File>;
6894
- /** Emits the inserted HTML when an import completes. */
7120
+ /** Emits the sanitized HTML that was inserted when an import completes — the same markup the editor now holds. */
6895
7121
  readonly fileImportComplete: _angular_core.OutputEmitterRef<string>;
6896
7122
  /** Emits an error message when an import fails. */
6897
7123
  readonly fileImportError: _angular_core.OutputEmitterRef<string>;
@@ -7403,6 +7629,7 @@ declare class RichTextImagesDirective {
7403
7629
  private readonly injector;
7404
7630
  private readonly vcr;
7405
7631
  private readonly document;
7632
+ private readonly destroyRef;
7406
7633
  /** Locale for the addon UI: a registry key (`'en'`/`'he'`/…) or a full dictionary. */
7407
7634
  readonly uiRteImagesLocale: _angular_core.InputSignal<LocaleInput<RichTextImagesLocale> | undefined>;
7408
7635
  /**
@@ -7441,18 +7668,26 @@ declare class RichTextImagesDirective {
7441
7668
  private readonly uploading;
7442
7669
  private readonly autoUploadErrors;
7443
7670
  private readonly autoUploadMap;
7671
+ /**
7672
+ * The src this directive last wrote to each image (placeholder or upload
7673
+ * result). An image whose src is still that value is never auto-uploaded.
7674
+ * The observer sees the directive's own edits too -- its records arrive as a
7675
+ * microtask, after any flag set around the edit is cleared -- so eligibility,
7676
+ * not timing, keeps a placeholder or a data-URL result from being sent.
7677
+ */
7678
+ private readonly writtenSources;
7444
7679
  private autoUploadCounter;
7445
- private autoUploadMutating;
7446
7680
  private autoUploadObserver;
7447
7681
  private overlayRef?;
7448
7682
  /**
7449
7683
  * Whether this directive has been torn down.
7450
7684
  *
7451
7685
  * An upload is a network round-trip the user can easily outlive — routing
7452
- * away, closing a dialog, toggling a tab. The auto-upload path already
7453
- * unsubscribes on destroy, but the manual insert/drop/paste path awaited its
7454
- * promise with nothing watching, then committed into a dead editor and
7455
- * emitted outputs whose owning directive no longer exists (NG0953).
7686
+ * away, closing a dialog, toggling a tab. Teardown cancels every in-flight
7687
+ * upload, which settles the manual insert/drop/paste promise; this flag
7688
+ * stops that settled promise, and a file read still in progress, from
7689
+ * committing into a dead editor or emitting outputs whose owning directive
7690
+ * no longer exists (NG0953).
7456
7691
  */
7457
7692
  private destroyed;
7458
7693
  private readonly resizerLabels;
@@ -7498,6 +7733,21 @@ declare class RichTextImagesDirective {
7498
7733
  private injectAutoUploadStyles;
7499
7734
  private releaseAutoUploadStyles;
7500
7735
  private scanForBase64Images;
7736
+ /**
7737
+ * A base64 image that is not already uploading and whose src this directive
7738
+ * did not write. The placeholder pixel is also refused by value, because
7739
+ * undo or setContent restore a rejected image as a new element that
7740
+ * {@link writtenSources} has never seen.
7741
+ */
7742
+ private isAutoUploadCandidate;
7743
+ /**
7744
+ * Cancel every upload whose image has left the editor -- deleted, inside a
7745
+ * removed subtree, or replaced by undo/setContent. Checked against the
7746
+ * document when the records arrive, so an image moved within the editor
7747
+ * (removed and re-added in one batch) keeps its upload.
7748
+ */
7749
+ private cancelDetachedUploads;
7750
+ private writeSrc;
7501
7751
  private processAutoUploadImage;
7502
7752
  private markImageAsUploading;
7503
7753
  private revertInvalidUploadImage;
@@ -7624,6 +7874,12 @@ declare class RichTextImageResizerComponent implements OnDestroy {
7624
7874
  readonly deleteIconHtml: SafeHtml;
7625
7875
  private rafId;
7626
7876
  private resizeObserver;
7877
+ /**
7878
+ * The element the scroll listener was added to. Kept because
7879
+ * {@link container} may have changed by the time tracking stops, and the
7880
+ * listener must come off the element it went on.
7881
+ */
7882
+ private scrollListenerTarget;
7627
7883
  private readonly onContainerScrollBound;
7628
7884
  private readonly onWindowResizeBound;
7629
7885
  private resizeState;
@@ -7682,6 +7938,15 @@ declare class RichTextImageResizerComponent implements OnDestroy {
7682
7938
  */
7683
7939
  startResize(event: MouseEvent | TouchEvent, handle: ResizeHandle): void;
7684
7940
  private onPointerMove;
7941
+ /**
7942
+ * Accessible name for one resize handle.
7943
+ *
7944
+ * The handles were bare divs -- no tabindex, no role, no name -- so image
7945
+ * resizing was strictly pointer-only. They are buttons now, and each says
7946
+ * which corner or edge it drags. The compass point is spelled out rather
7947
+ * than left as "nw" so it is pronounceable.
7948
+ */
7949
+ handleLabel(handle: ResizeHandle): string;
7685
7950
  /**
7686
7951
  * Resize the image from the keyboard.
7687
7952
  *
@@ -7692,15 +7957,6 @@ declare class RichTextImageResizerComponent implements OnDestroy {
7692
7957
  * the image with the arrow keys, holding the aspect ratio when
7693
7958
  * {@link lockAspectRatio} asks for it. Shift moves in larger steps.
7694
7959
  */
7695
- /**
7696
- * Accessible name for one resize handle.
7697
- *
7698
- * The handles were bare divs -- no tabindex, no role, no name -- so image
7699
- * resizing was strictly pointer-only. They are buttons now, and each says
7700
- * which corner or edge it drags. The compass point is spelled out rather
7701
- * than left as "nw" so it is pronounceable.
7702
- */
7703
- handleLabel(handle: ResizeHandle): string;
7704
7960
  onResizeKeydown(event: KeyboardEvent, handle: ResizeHandle): void;
7705
7961
  /**
7706
7962
  * Emit one {@link resizeEnd} for a run of keypresses.
@@ -7721,31 +7977,18 @@ declare class RichTextImageResizerComponent implements OnDestroy {
7721
7977
  * the default.
7722
7978
  */
7723
7979
  private clampWidth;
7980
+ /** The width bound: {@link maxWidth} when set, never above the absolute cap. */
7981
+ private widthCeiling;
7724
7982
  /**
7725
- * Size with the aspect ratio held. BOTH axes are bounded here.
7726
- *
7727
- * Clamping width and then deriving height by division skipped the height
7728
- * bound entirely: a 20x10000 image dragged out reached 5,000,000px. And
7729
- * because `lockAspectRatio` defaults to true, that is the path most users
7730
- * are on -- the earlier bounds fix, and both of its tests, only exercised
7731
- * `freeSize`, the ratio-unlocked function.
7983
+ * Fit a ratio-locked size inside the bounds by scaling both axes by one
7984
+ * factor, so the image keeps its shape and the drag stays responsive.
7732
7985
  *
7733
- * The ratio is preserved while clamping, so the image stays the shape it
7734
- * was. Only the ceiling is enforced here; the floor belongs to
7735
- * onPointerMove, which rejects an undersized drag rather than snapping it.
7736
- */
7737
- /**
7738
- * Fit a ratio-locked size inside the bounds, scaling rather than overriding.
7739
- *
7740
- * The earlier version enforced the floor on the DERIVED axis and then
7741
- * back-projected it onto the axis the user was dragging, which pinned the
7742
- * width: a 2000x40 banner returned 1000px for a 500px request and for a
7743
- * 100px request alike, so the drag was unresponsive below 1000px -- the
7744
- * frozen drag relocated, not removed. It could also return a dimension under
7745
- * the very floor it exists to enforce.
7746
- *
7747
- * Scaling both axes by one factor keeps the ratio, keeps the drag
7748
- * responsive, and cannot produce a dimension outside the bounds.
7986
+ * The floor is applied first and the ceiling last, so the ceiling always
7987
+ * holds: {@link minWidth} on both axes, {@link maxWidth} (or the absolute
7988
+ * cap) on width and the absolute cap on height. When the ratio is so extreme
7989
+ * that no size satisfies floor and ceiling together (past cap:floor, 500:1 by
7990
+ * default), the ceiling wins and the short side may end under the floor --
7991
+ * the ratio is never bent to rescue it.
7749
7992
  */
7750
7993
  private ratioBoundedSize;
7751
7994
  private lockedSize;
@@ -8299,6 +8542,7 @@ declare class RichTextMentionsDirective {
8299
8542
  constructor();
8300
8543
  private get doc();
8301
8544
  private setupSearch;
8545
+ private runSearch;
8302
8546
  private onInput;
8303
8547
  private onKeydown;
8304
8548
  private onSelect;
@@ -8391,7 +8635,7 @@ declare class RichTextMentionPopoverComponent implements AfterViewInit, OnDestro
8391
8635
  readonly itemSelect: _angular_core.OutputEmitterRef<MentionItem | TagItem>;
8392
8636
  /**
8393
8637
  * The user dismissed the list: `Escape`/`Tab`, or a click anywhere outside
8394
- * the `ui-rich-text-mention-popover` element. The host owns the teardown;
8638
+ * this popover (whatever its host tag). The host owns the teardown;
8395
8639
  * this component stays rendered until it is destroyed.
8396
8640
  */
8397
8641
  readonly closed: _angular_core.OutputEmitterRef<void>;
@@ -8404,6 +8648,13 @@ declare class RichTextMentionPopoverComponent implements AfterViewInit, OnDestro
8404
8648
  readonly listboxId: string;
8405
8649
  optionId(index: number): string;
8406
8650
  readonly selectedIndex: _angular_core.WritableSignal<number>;
8651
+ private readonly host;
8652
+ /**
8653
+ * Dismisses on a click outside THIS popover. Containment is the host's DOM
8654
+ * subtree, never a selector string: a `--prefix` install or a selector
8655
+ * rename changes the tag, and a tag query also treated a click inside a
8656
+ * second, sibling popover as "inside" this one.
8657
+ */
8407
8658
  private readonly clickListener;
8408
8659
  readonly containerClasses: _angular_core.Signal<string>;
8409
8660
  /**
@@ -9053,6 +9304,6 @@ declare const RICH_TEXT_TYPOGRAPHY_BUTTON_CONTEXT: InjectionToken<RichTextTypogr
9053
9304
 
9054
9305
  declare const RTE_FULL: readonly [typeof RichTextActionsDirective, typeof RichTextAiDirective, typeof RichTextColorsDirective, typeof RichTextEmojiDirective, typeof RichTextFileImportDirective, typeof RichTextHistoryDirective, typeof RichTextImagesDirective, typeof RichTextLinksDirective, typeof RichTextMentionsDirective, typeof RichTextOutlineDirective, typeof RichTextSlashCommandsDirective, typeof RichTextTablesDirective, typeof RichTextTypographyDirective];
9055
9306
 
9056
- export { ACTION_ATTRS, ACTION_PARAMS, AddonSlotRegistry, DEFAULT_COLOR_PALETTE, DEFAULT_FONT_FAMILIES, DEFAULT_HIGHLIGHT_PALETTE, DEFAULT_LINK_SCHEMES, DEFAULT_TOOLBAR_ITEMS, DOCUMENT_IMPORT_ACCEPT, DOCX_MIME, EMPTINESS_FIXTURES, FIND_MAX_PAINTED_RECTS, FIND_MAX_QUERY_LENGTH, HEADER_BYTES, IMAGE_IMPORT_ACCEPT, INLINE_RULE_LOOKBEHIND, MAX_NESTING_DEPTH, PDF_MIME, PresetDialogComponent, PresetHoverCardComponent, RICH_TEXT_ACTIONS_SANITIZER_RULES, RICH_TEXT_AI_CONTEXT, RICH_TEXT_AI_LOCALES, RICH_TEXT_COLORS_LOCALES, RICH_TEXT_COLOR_BUTTON_CONTEXT, RICH_TEXT_EMOJI_CONTEXT, RICH_TEXT_EMOJI_LOCALES, RICH_TEXT_FILE_IMPORT_BUTTON_CONTEXT, RICH_TEXT_FILE_IMPORT_LOCALES, RICH_TEXT_HISTORY_LOCALES, RICH_TEXT_IMAGES_BUTTON_CONTEXT, RICH_TEXT_IMAGES_LOCALES, RICH_TEXT_LINKS_BUTTON_CONTEXT, RICH_TEXT_LINKS_LOCALES, RICH_TEXT_LOCALES, RICH_TEXT_MENTIONS_LOCALES, RICH_TEXT_OUTLINE_CONTEXT, RICH_TEXT_OUTLINE_LOCALES, RICH_TEXT_PROSE_CLASSES, RICH_TEXT_SHORTCUT_DEFINITIONS, RICH_TEXT_SLASH_COMMANDS_LOCALES, RICH_TEXT_TABLES_BUTTON_CONTEXT, RICH_TEXT_TABLES_LOCALES, RICH_TEXT_TYPOGRAPHY_BUTTON_CONTEXT, RICH_TEXT_TYPOGRAPHY_LOCALES, RTE_FULL, RichTextActionsBindDirective, RichTextActionsDirective, RichTextAiChipComponent, RichTextAiDirective, RichTextAiPanelComponent, RichTextAllowDirective, RichTextAllowHost, RichTextColorsButtonComponent, RichTextColorsDirective, RichTextCommandRegistry, RichTextEditorAddonHost, RichTextEditorComponent, RichTextEmojiButtonComponent, RichTextEmojiDirective, RichTextFileImportButtonComponent, RichTextFileImportDirective, RichTextFileImportOverlayComponent, RichTextHistoryDirective, RichTextHistoryPanelComponent, RichTextImageResizerComponent, RichTextImagesButtonComponent, RichTextImagesDirective, RichTextImagesOverlayComponent, RichTextLinksButtonComponent, RichTextLinksDirective, RichTextLinksFormComponent, RichTextMarkdownService, RichTextMentionPopoverComponent, RichTextMentionsDirective, RichTextOutlineDirective, RichTextOutlinePanelComponent, RichTextPasteNormalizerService, RichTextSanitizerService, RichTextSlashCommandsDirective, RichTextSlashCommandsMenuComponent, RichTextTablesButtonComponent, RichTextTablesDirective, RichTextToolbarComponent, RichTextToolbarViewContext, RichTextTypographyButtonComponent, RichTextTypographyDirective, TEXT_STYLE_OPTIONS, TOOLBAR_BUTTONS, TRANSPARENT_PIXEL, addonSetting, anchorOverlay, applyImageAlignment, applyStarterStyle, assertFlatParams, bindRichTextActions, blockquoteDepthOf, buildDefaultSlashCommands, buildEntityInsertNode, buildEntityRenderContext, buildFindIndex, buildLineIndex, caretPosition, classifyImport, compileFindRegex, computeSeedStyleString, containsCssUrl, createImageElement, cssFunctionCalls, dataUrlToFile, decodeCssEscapes, detectTrigger, directionOf, dragHasSupportedDocument, extractCssUrls, flattenIntoRowText, hasUnsafeCssFunction, holdsNothing, hostOf, hoverCardAction, hoverCardHandlers, isCombinedOnElement, isHostAllowed, isHostBearingUrl, isInlineHoldingBlock, isLineOwner, isNestedList, isPdfHeader, isPhrasing, isRichTextEmpty, isSupportedDocumentFile, isZipHeader, labelBlockedImages, lastOwnInlineNode, lineAbove, lineBelow, lineIsEmpty, lineIsTextOnly, lineKeepsItsElement, lineOf, lineOwnNodes, lineTagIsFixed, lineText, linesBetween, linesMayJoin, linkedPreviewDialogAction, linkedPreviewDialogHandlers, matchBlockInputRule, matchInlineInputRule, mountTopLayer, nodeShowsNothing, normalizeHostEntry, offsetToPosition, openDialogAction, openDialogHandlers, parseImageSize, placeCaretIn, placeImageAtSelection, positionAfterLine, rangeShowsNothing, readActions, readFileAsDataUrl, remoteHostOf, removeAction, reportResourceDecisions, resolveFromPage, richTextHasMedia, richTextMaxLength, richTextMinWords, richTextRequired, richTextVisibleText, rowRunsOf, selectTriggerRange, separateListKinds, simpleHash, stripCssComments, stripStyleIfMatches, structureAround, validateActionId, validateActionParams, writeAction, writeCombined };
9307
+ export { ACTION_ATTRS, ACTION_PARAMS, AddonSlotRegistry, DEFAULT_COLOR_PALETTE, DEFAULT_FONT_FAMILIES, DEFAULT_HIGHLIGHT_PALETTE, DEFAULT_LINK_SCHEMES, DEFAULT_TOOLBAR_ITEMS, DOCUMENT_IMPORT_ACCEPT, DOCX_MIME, EMPTINESS_FIXTURES, FIND_MAX_PAINTED_RECTS, FIND_MAX_QUERY_LENGTH, HEADER_BYTES, IMAGE_IMPORT_ACCEPT, INLINE_RULE_LOOKBEHIND, MAX_NESTING_DEPTH, PDF_MIME, PresetDialogComponent, PresetHoverCardComponent, RICH_TEXT_ACTIONS_SANITIZER_RULES, RICH_TEXT_AI_CONTEXT, RICH_TEXT_AI_LOCALES, RICH_TEXT_COLORS_LOCALES, RICH_TEXT_COLOR_BUTTON_CONTEXT, RICH_TEXT_EMOJI_CONTEXT, RICH_TEXT_EMOJI_LOCALES, RICH_TEXT_FILE_IMPORT_BUTTON_CONTEXT, RICH_TEXT_FILE_IMPORT_LOCALES, RICH_TEXT_HISTORY_LOCALES, RICH_TEXT_IMAGES_BUTTON_CONTEXT, RICH_TEXT_IMAGES_LOCALES, RICH_TEXT_LINKS_BUTTON_CONTEXT, RICH_TEXT_LINKS_LOCALES, RICH_TEXT_LOCALES, RICH_TEXT_MENTIONS_LOCALES, RICH_TEXT_OUTLINE_CONTEXT, RICH_TEXT_OUTLINE_LOCALES, RICH_TEXT_PROSE_CLASSES, RICH_TEXT_SHORTCUT_DEFINITIONS, RICH_TEXT_SLASH_COMMANDS_LOCALES, RICH_TEXT_TABLES_BUTTON_CONTEXT, RICH_TEXT_TABLES_LOCALES, RICH_TEXT_TYPOGRAPHY_BUTTON_CONTEXT, RICH_TEXT_TYPOGRAPHY_LOCALES, RTE_FULL, RichTextActionsBindDirective, RichTextActionsDirective, RichTextAiChipComponent, RichTextAiDirective, RichTextAiPanelComponent, RichTextAllowDirective, RichTextAllowHost, RichTextColorsButtonComponent, RichTextColorsDirective, RichTextCommandRegistry, RichTextEditorAddonHost, RichTextEditorComponent, RichTextEmojiButtonComponent, RichTextEmojiDirective, RichTextFileImportButtonComponent, RichTextFileImportDirective, RichTextFileImportOverlayComponent, RichTextHistoryDirective, RichTextHistoryPanelComponent, RichTextImageResizerComponent, RichTextImagesButtonComponent, RichTextImagesDirective, RichTextImagesOverlayComponent, RichTextLinksButtonComponent, RichTextLinksDirective, RichTextLinksFormComponent, RichTextMarkdownService, RichTextMentionPopoverComponent, RichTextMentionsDirective, RichTextOutlineDirective, RichTextOutlinePanelComponent, RichTextPasteNormalizerService, RichTextSanitizerService, RichTextSlashCommandsDirective, RichTextSlashCommandsMenuComponent, RichTextTablesButtonComponent, RichTextTablesDirective, RichTextToolbarComponent, RichTextToolbarViewContext, RichTextTypographyButtonComponent, RichTextTypographyDirective, TEXT_STYLE_OPTIONS, TOOLBAR_BUTTONS, TRANSPARENT_PIXEL, addonSetting, anchorOverlay, applyImageAlignment, applyStarterStyle, assertFlatParams, bindRichTextActions, blockquoteDepthOf, buildDefaultSlashCommands, buildEntityInsertNode, buildEntityRenderContext, buildFindIndex, buildLineIndex, caretPosition, childList, classifyImport, compileFindRegex, computeSeedStyleString, containsCssUrl, createImageElement, cssFunctionCalls, dataUrlToFile, decodeCssEscapes, detectTrigger, directionOf, dragHasSupportedDocument, extractCssUrls, flattenIntoRowText, hasUnsafeCssFunction, holdsNothing, hostOf, hoverCardAction, hoverCardHandlers, inlineElementsHoldingBlocks, isCombinedOnElement, isHostAllowed, isHostBearingUrl, isLineOwner, isNestedList, isPdfHeader, isPhrasing, isRichTextEmpty, isSupportedDocumentFile, isZipHeader, labelBlockedImages, lastOwnInlineNode, lineAbove, lineBelow, lineIsEmpty, lineIsTextOnly, lineKeepsItsElement, lineOf, lineOwnNodes, lineTagIsFixed, lineText, linesBetween, linesMayJoin, linkedPreviewDialogAction, linkedPreviewDialogHandlers, matchBlockInputRule, matchInlineInputRule, mountTopLayer, nodeShowsNothing, normalizeHostEntry, offsetToPosition, openDialogAction, openDialogHandlers, parseImageSize, placeCaretIn, placeImageAtSelection, positionAfterLine, rangeShowsNothing, readActions, readFileAsDataUrl, remoteHostOf, removeAction, reportResourceDecisions, resolveFromPage, richTextHasMedia, richTextMaxLength, richTextMinWords, richTextRequired, richTextVisibleText, rowRunsOf, selectTriggerRange, separateListKinds, simpleHash, stripCssComments, stripStyleIfMatches, structureAround, validateActionId, validateActionParams, writeAction, writeCombined };
9057
9308
  export type { ActionParams, ActionParamsMode, ActionTargetKind, BindRichTextActionsOptions, BlockInputRuleKind, BlockInputRuleMatch, CounterMode, DocumentImportKind, EditorMode, EditorSize, EditorVariant, FindIndex, FindOptions, FindPosition, FindSegment, FontFamilyStrategy, HoverCardPresetOptions, ImageAlignment, ImageInsertDefaults, ImageUploadErrorEntry, ImportKind, InlineInputRuleKind, InlineInputRuleMatch, Line, LineIndex, LineKind, LinePosition, LinkedPreviewDialogOptions, MarkdownSpanSerializer, MentionItem, MountedOverlay, OpenDialogPresetOptions, OutlineHeading, PasteSource, ResourcePolicyDecision, RichTextActionDefinition, RichTextActionEvent, RichTextActionField, RichTextActionHandler, RichTextActionParamsContext, RichTextActionParamsForm, RichTextActionTrigger, RichTextAddonOptions, RichTextAddonSetting, RichTextAddonState, RichTextAiContext, RichTextAiLocale, RichTextAiPhase, RichTextAiPoint, RichTextAiTaskOption, RichTextAllow, RichTextColorButtonContext, RichTextColorChange, RichTextColorKind, RichTextColorsLocale, RichTextCustomToolbarItem, RichTextEditorApi, RichTextEditorRef, RichTextEmojiContext, RichTextEmojiLocale, RichTextEntityInsertEvent, RichTextEntityRenderContext, RichTextEntityRenderMode, RichTextEntityRenderOptions, RichTextEntitySearchFn, RichTextEntitySearchResult, RichTextEntityType, RichTextExclusivePopover, RichTextFileImportButtonContext, RichTextFileImportLocale, RichTextFormatCommand, RichTextHistoryEntrySnapshot, RichTextHistoryLocale, RichTextHistoryOptions, RichTextHistoryState, RichTextImageResizerLabels, RichTextImageSources, RichTextImagesButtonContext, RichTextImagesLayoutOptions, RichTextImagesLocale, RichTextImagesUploadOptions, RichTextInlineStyle, RichTextLinkSubmit, RichTextLinksButtonContext, RichTextLinksLocale, RichTextLocale, RichTextMentionsLocale, RichTextOutlineContext, RichTextOutlineLocale, RichTextSelectionInlineStyle, RichTextSelectionSnapshot, RichTextSetContentOptions, RichTextSlashCommand, RichTextSlashCommandAvailabilityContext, RichTextSlashCommandContext, RichTextSlashCommandsLocale, RichTextTablesButtonContext, RichTextTablesLocale, RichTextToolbarSlot, RichTextTypographyButtonContext, RichTextTypographyKind, RichTextTypographyLocale, RowRun, SanitizerAttributeRule, TagItem, TextDirection, TextStyleOption, ToolbarButton, ToolbarButtonItem, ToolbarItem, ToolbarPosition, TriggerMatch };
9058
9309
  //# sourceMappingURL=gilav21-shadcn-angular-rte.d.ts.map