@flogeez/angular-tiptap-editor 3.5.2 → 3.5.4
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/CHANGELOG.md +21 -0
- package/esm2022/lib/components/bubble-menus/link/ate-link-bubble-menu.component.mjs +22 -2
- package/esm2022/lib/components/editor/angular-tiptap-editor.component.mjs +15 -2
- package/esm2022/lib/extensions/ate-link-shortcut.extension.mjs +50 -0
- package/esm2022/lib/extensions/ate-pasted-image.extension.mjs +156 -0
- package/esm2022/lib/models/ate-image.model.mjs +1 -1
- package/esm2022/lib/services/ate-editor-commands.service.mjs +7 -1
- package/esm2022/lib/services/ate-image.service.mjs +63 -36
- package/esm2022/public-api.mjs +4 -1
- package/fesm2022/flogeez-angular-tiptap-editor.mjs +303 -37
- package/fesm2022/flogeez-angular-tiptap-editor.mjs.map +1 -1
- package/lib/components/bubble-menus/link/ate-link-bubble-menu.component.d.ts +1 -0
- package/lib/components/editor/angular-tiptap-editor.component.d.ts +4 -2
- package/lib/extensions/ate-link-shortcut.extension.d.ts +15 -0
- package/lib/extensions/ate-pasted-image.extension.d.ts +33 -0
- package/lib/models/ate-image.model.d.ts +9 -0
- package/lib/services/ate-editor-commands.service.d.ts +2 -0
- package/lib/services/ate-image.service.d.ts +7 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -38,6 +38,7 @@ export declare class AteLinkBubbleMenuComponent extends AteBaseSubBubbleMenu {
|
|
|
38
38
|
linkInput: import("@angular/core").Signal<ElementRef<HTMLInputElement> | undefined>;
|
|
39
39
|
editUrl: import("@angular/core").WritableSignal<string>;
|
|
40
40
|
constructor();
|
|
41
|
+
private focusInputWhenVisible;
|
|
41
42
|
protected onStateChange(): void;
|
|
42
43
|
shouldShow(): boolean;
|
|
43
44
|
getSelectionRect(): DOMRect;
|
|
@@ -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,15 @@
|
|
|
1
|
+
import { Editor, Extension } from "@tiptap/core";
|
|
2
|
+
export interface AteLinkShortcutOptions {
|
|
3
|
+
/** Whether a link can be set or edited at the current selection */
|
|
4
|
+
canOpen: () => boolean;
|
|
5
|
+
/** Opens the link editor */
|
|
6
|
+
open: (editor: Editor) => void;
|
|
7
|
+
}
|
|
8
|
+
/** Matches the bare `Mod+K` chord (`Cmd+K` on macOS, `Ctrl+K` elsewhere) */
|
|
9
|
+
export declare function isLinkShortcut(event: KeyboardEvent): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* `Mod+K` opens the link editor when text is selected or the cursor is on a link.
|
|
12
|
+
* With an empty selection outside a link the event is left alone, so host-level `Mod+K`
|
|
13
|
+
* shortcuts (search, command palettes) keep working.
|
|
14
|
+
*/
|
|
15
|
+
export declare const AteLinkShortcut: Extension<AteLinkShortcutOptions, any>;
|
|
@@ -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
package/public-api.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ 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";
|
|
27
|
+
export { AteLinkShortcut, isLinkShortcut, type AteLinkShortcutOptions, } from "./lib/extensions/ate-link-shortcut.extension";
|
|
26
28
|
export * from "./lib/models/ate-toolbar.model";
|
|
27
29
|
export * from "./lib/models/ate-image.model";
|
|
28
30
|
export * from "./lib/models/ate-bubble-menu.model";
|