@flogeez/angular-tiptap-editor 3.5.2 → 3.5.3

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.
@@ -9,7 +9,7 @@ import { AteSlashCommandsConfig } from "../../config/ate-slash-commands.config";
9
9
  import { AteToolbarConfig } from "../../models/ate-toolbar.model";
10
10
  import { AteBubbleMenuConfig } from "../../models/ate-bubble-menu.model";
11
11
  import { AteEditorConfig, AteAngularNode, AteBlockControlsMode, AteAutofocusMode } from "../../models/ate-editor-config.model";
12
- import { AteImageUploadHandler, AteImageUploadOptions, AteImageUploadResult } from "../../models/ate-image.model";
12
+ import { AteImageUploadHandler, AteImageUploadOptions, AteImageUploadResult, AtePastedImageRejection } from "../../models/ate-image.model";
13
13
  import { SupportedLocale } from "../../i18n/ateTranslationsModel";
14
14
  import * as i0 from "@angular/core";
15
15
  import * as i1 from "../../directives/ate-noop-value-accessor.directive";
@@ -106,6 +106,8 @@ export declare class AngularTiptapEditorComponent implements AfterViewInit, OnDe
106
106
  }>;
107
107
  editableChange: import("@angular/core").OutputEmitterRef<boolean>;
108
108
  imageUploaded: import("@angular/core").OutputEmitterRef<AteImageUploadResult>;
109
+ /** Emitted when an image from pasted HTML is dropped (unreachable source or failed upload) */
110
+ pastedImageRejected: import("@angular/core").OutputEmitterRef<AtePastedImageRejection>;
109
111
  editorElement: import("@angular/core").Signal<ElementRef<any>>;
110
112
  hideBubbleMenus(): void;
111
113
  showBubbleMenus(): void;
@@ -251,5 +253,5 @@ export declare class AngularTiptapEditorComponent implements AfterViewInit, OnDe
251
253
  private setupFormControlSubscription;
252
254
  onEditorClick(event: Event): void;
253
255
  static ɵfac: i0.ɵɵFactoryDeclaration<AngularTiptapEditorComponent, never>;
254
- static ɵcmp: i0.ɵɵComponentDeclaration<AngularTiptapEditorComponent, "angular-tiptap-editor", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "content": { "alias": "content"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "fillContainer": { "alias": "fillContainer"; "required": false; "isSignal": true; }; "showToolbar": { "alias": "showToolbar"; "required": false; "isSignal": true; }; "showFooter": { "alias": "showFooter"; "required": false; "isSignal": true; }; "showCharacterCount": { "alias": "showCharacterCount"; "required": false; "isSignal": true; }; "showWordCount": { "alias": "showWordCount"; "required": false; "isSignal": true; }; "maxCharacters": { "alias": "maxCharacters"; "required": false; "isSignal": true; }; "enableOfficePaste": { "alias": "enableOfficePaste"; "required": false; "isSignal": true; }; "enableSlashCommands": { "alias": "enableSlashCommands"; "required": false; "isSignal": true; }; "slashCommands": { "alias": "slashCommands"; "required": false; "isSignal": true; }; "customSlashCommands": { "alias": "customSlashCommands"; "required": false; "isSignal": true; }; "blockControls": { "alias": "blockControls"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "seamless": { "alias": "seamless"; "required": false; "isSignal": true; }; "floatingToolbar": { "alias": "floatingToolbar"; "required": false; "isSignal": true; }; "showEditToggle": { "alias": "showEditToggle"; "required": false; "isSignal": true; }; "spellcheck": { "alias": "spellcheck"; "required": false; "isSignal": true; }; "tiptapExtensions": { "alias": "tiptapExtensions"; "required": false; "isSignal": true; }; "tiptapOptions": { "alias": "tiptapOptions"; "required": false; "isSignal": true; }; "showBubbleMenu": { "alias": "showBubbleMenu"; "required": false; "isSignal": true; }; "bubbleMenu": { "alias": "bubbleMenu"; "required": false; "isSignal": true; }; "showImageBubbleMenu": { "alias": "showImageBubbleMenu"; "required": false; "isSignal": true; }; "imageBubbleMenu": { "alias": "imageBubbleMenu"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "showTableBubbleMenu": { "alias": "showTableBubbleMenu"; "required": false; "isSignal": true; }; "tableBubbleMenu": { "alias": "tableBubbleMenu"; "required": false; "isSignal": true; }; "showCellBubbleMenu": { "alias": "showCellBubbleMenu"; "required": false; "isSignal": true; }; "cellBubbleMenu": { "alias": "cellBubbleMenu"; "required": false; "isSignal": true; }; "stateCalculators": { "alias": "stateCalculators"; "required": false; "isSignal": true; }; "imageUpload": { "alias": "imageUpload"; "required": false; "isSignal": true; }; "imageUploadHandler": { "alias": "imageUploadHandler"; "required": false; "isSignal": true; }; "editorId": { "alias": "editorId"; "required": false; "isSignal": true; }; }, { "contentChange": "contentChange"; "editorCreated": "editorCreated"; "editorUpdate": "editorUpdate"; "editorFocus": "editorFocus"; "editorBlur": "editorBlur"; "editableChange": "editableChange"; "imageUploaded": "imageUploaded"; }, never, never, true, [{ directive: typeof i1.AteNoopValueAccessorDirective; inputs: {}; outputs: {}; }]>;
256
+ static ɵcmp: i0.ɵɵComponentDeclaration<AngularTiptapEditorComponent, "angular-tiptap-editor", never, { "config": { "alias": "config"; "required": false; "isSignal": true; }; "content": { "alias": "content"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "minHeight": { "alias": "minHeight"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "fillContainer": { "alias": "fillContainer"; "required": false; "isSignal": true; }; "showToolbar": { "alias": "showToolbar"; "required": false; "isSignal": true; }; "showFooter": { "alias": "showFooter"; "required": false; "isSignal": true; }; "showCharacterCount": { "alias": "showCharacterCount"; "required": false; "isSignal": true; }; "showWordCount": { "alias": "showWordCount"; "required": false; "isSignal": true; }; "maxCharacters": { "alias": "maxCharacters"; "required": false; "isSignal": true; }; "enableOfficePaste": { "alias": "enableOfficePaste"; "required": false; "isSignal": true; }; "enableSlashCommands": { "alias": "enableSlashCommands"; "required": false; "isSignal": true; }; "slashCommands": { "alias": "slashCommands"; "required": false; "isSignal": true; }; "customSlashCommands": { "alias": "customSlashCommands"; "required": false; "isSignal": true; }; "blockControls": { "alias": "blockControls"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "seamless": { "alias": "seamless"; "required": false; "isSignal": true; }; "floatingToolbar": { "alias": "floatingToolbar"; "required": false; "isSignal": true; }; "showEditToggle": { "alias": "showEditToggle"; "required": false; "isSignal": true; }; "spellcheck": { "alias": "spellcheck"; "required": false; "isSignal": true; }; "tiptapExtensions": { "alias": "tiptapExtensions"; "required": false; "isSignal": true; }; "tiptapOptions": { "alias": "tiptapOptions"; "required": false; "isSignal": true; }; "showBubbleMenu": { "alias": "showBubbleMenu"; "required": false; "isSignal": true; }; "bubbleMenu": { "alias": "bubbleMenu"; "required": false; "isSignal": true; }; "showImageBubbleMenu": { "alias": "showImageBubbleMenu"; "required": false; "isSignal": true; }; "imageBubbleMenu": { "alias": "imageBubbleMenu"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "showTableBubbleMenu": { "alias": "showTableBubbleMenu"; "required": false; "isSignal": true; }; "tableBubbleMenu": { "alias": "tableBubbleMenu"; "required": false; "isSignal": true; }; "showCellBubbleMenu": { "alias": "showCellBubbleMenu"; "required": false; "isSignal": true; }; "cellBubbleMenu": { "alias": "cellBubbleMenu"; "required": false; "isSignal": true; }; "stateCalculators": { "alias": "stateCalculators"; "required": false; "isSignal": true; }; "imageUpload": { "alias": "imageUpload"; "required": false; "isSignal": true; }; "imageUploadHandler": { "alias": "imageUploadHandler"; "required": false; "isSignal": true; }; "editorId": { "alias": "editorId"; "required": false; "isSignal": true; }; }, { "contentChange": "contentChange"; "editorCreated": "editorCreated"; "editorUpdate": "editorUpdate"; "editorFocus": "editorFocus"; "editorBlur": "editorBlur"; "editableChange": "editableChange"; "imageUploaded": "imageUploaded"; "pastedImageRejected": "pastedImageRejected"; }, never, never, true, [{ directive: typeof i1.AteNoopValueAccessorDirective; inputs: {}; outputs: {}; }]>;
255
257
  }
@@ -0,0 +1,33 @@
1
+ import { Extension } from "@tiptap/core";
2
+ import { Slice } from "@tiptap/pm/model";
3
+ import { AtePastedImageRejection } from "../models/ate-image.model";
4
+ export type AtePastedImageSource = "remote" | "inline" | "unreachable";
5
+ export interface AtePastedImageOptions {
6
+ /** Whether pasted base64 images should be sent to the upload handler */
7
+ shouldRehost: () => boolean;
8
+ /** Uploads a pasted base64 image and resolves to its hosted URL */
9
+ rehost: (file: File) => Promise<string>;
10
+ /** Called for every pasted image that could not be kept */
11
+ onRejected: (rejection: AtePastedImageRejection) => void;
12
+ }
13
+ /**
14
+ * Classifies the `src` of an image found in pasted HTML.
15
+ * `unreachable` sources (e.g. `attachment:`, `file:`, `cid:`, foreign `blob:`) cannot be fetched by the page.
16
+ */
17
+ export declare function classifyPastedImageSrc(src: string | null | undefined, origin?: string): AtePastedImageSource;
18
+ /** Decodes a base64 image data URI into a `File`, or returns `null` when it is malformed */
19
+ export declare function dataUriToFile(src: string): File | null;
20
+ /** Removes unreachable images from a pasted slice and lists the base64 sources it keeps */
21
+ export declare function sanitizePastedImages(slice: Slice): {
22
+ slice: Slice;
23
+ inlineSources: string[];
24
+ droppedSources: string[];
25
+ };
26
+ /**
27
+ * Cleans images coming from pasted HTML (e.g. Notion, Google Docs, Office):
28
+ * - drops images whose source the page cannot load, instead of inserting broken images;
29
+ * - sends base64 images through the upload handler (when one is configured) and swaps in the hosted URL.
30
+ *
31
+ * File-based clipboard images keep going through the regular paste upload flow.
32
+ */
33
+ export declare const AtePastedImage: Extension<AtePastedImageOptions, any>;
@@ -15,6 +15,15 @@ export interface AteImageUploadResult {
15
15
  height?: number;
16
16
  originalSize?: number;
17
17
  }
18
+ /**
19
+ * Emitted when an image found in pasted HTML cannot be kept.
20
+ * - `unreachable`: the page cannot load its source (e.g. `attachment:`, `file:`, `cid:`, foreign `blob:`, malformed base64)
21
+ * - `upload-failed`: a pasted base64 image was rejected by validation or by the upload handler
22
+ */
23
+ export interface AtePastedImageRejection {
24
+ reason: "unreachable" | "upload-failed";
25
+ src: string;
26
+ }
18
27
  export interface AteResizeOptions {
19
28
  width?: number;
20
29
  height?: number;
@@ -85,6 +85,8 @@ export declare class AteEditorCommandsService {
85
85
  downloadImage(editor: Editor): void;
86
86
  handleImageDrop(editor: Editor, event: DragEvent, options?: AteImageUploadOptions): boolean;
87
87
  handleImagePaste(editor: Editor, event: ClipboardEvent, options?: AteImageUploadOptions): boolean;
88
+ rehostImage(file: File, options?: AteImageUploadOptions): Promise<string>;
89
+ get hasUploadHandler(): boolean;
88
90
  static ɵfac: i0.ɵɵFactoryDeclaration<AteEditorCommandsService, never>;
89
91
  static ɵprov: i0.ɵɵInjectableDeclaration<AteEditorCommandsService>;
90
92
  }
@@ -56,6 +56,13 @@ export declare class AteImageService {
56
56
  compressImage(file: File, quality?: number, maxWidth?: number, maxHeight?: number): Promise<AteImageUploadResult>;
57
57
  /** Core upload logic with progress tracking */
58
58
  private uploadImageWithProgress;
59
+ /** Validate, compress and (when configured) send an image to the upload handler */
60
+ private processImage;
61
+ /**
62
+ * Run an image that is already in the document (e.g. base64 from pasted HTML)
63
+ * through validation, compression and the upload handler, and resolve to its new `src`.
64
+ */
65
+ rehostImage(file: File, options?: AteImageUploadOptions): Promise<string>;
59
66
  private resetUploadState;
60
67
  /** Main entry point for file upload and insertion */
61
68
  uploadAndInsertImage(editor: Editor, file: File, options?: AteImageUploadOptions): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flogeez/angular-tiptap-editor",
3
- "version": "3.5.2",
3
+ "version": "3.5.3",
4
4
  "description": "A modern, customizable rich-text editor for Angular (18+), built with Tiptap and featuring complete internationalization support",
5
5
  "keywords": [
6
6
  "angular",
package/public-api.d.ts CHANGED
@@ -23,6 +23,7 @@ export * from "./lib/extensions/calculators/ate-marks.calculator";
23
23
  export * from "./lib/extensions/calculators/ate-selection.calculator";
24
24
  export * from "./lib/extensions/calculators/ate-structure.calculator";
25
25
  export * from "./lib/extensions/calculators/ate-table.calculator";
26
+ export { AtePastedImage, classifyPastedImageSrc, dataUriToFile, sanitizePastedImages, type AtePastedImageOptions, type AtePastedImageSource, } from "./lib/extensions/ate-pasted-image.extension";
26
27
  export * from "./lib/models/ate-toolbar.model";
27
28
  export * from "./lib/models/ate-image.model";
28
29
  export * from "./lib/models/ate-bubble-menu.model";