@flogeez/angular-tiptap-editor 0.3.5 → 0.3.6

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/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Editor } from '@tiptap/core';
2
2
  import * as _angular_core from '@angular/core';
3
3
  import { AfterViewInit, OnDestroy, ElementRef } from '@angular/core';
4
+ import { Observable } from 'rxjs';
4
5
  import { ControlValueAccessor } from '@angular/forms';
5
6
 
6
7
  type SupportedLocale = "en" | "fr";
@@ -393,6 +394,64 @@ interface ResizeOptions {
393
394
  height?: number;
394
395
  maintainAspectRatio?: boolean;
395
396
  }
397
+ /**
398
+ * Context passed to the image upload handler containing information about the image
399
+ */
400
+ interface ImageUploadContext {
401
+ /** Original file being uploaded */
402
+ file: File;
403
+ /** Width of the processed image */
404
+ width: number;
405
+ /** Height of the processed image */
406
+ height: number;
407
+ /** MIME type of the image */
408
+ type: string;
409
+ /** Base64 data URL of the processed image (after compression/resize) */
410
+ base64: string;
411
+ }
412
+ /**
413
+ * Result expected from a custom image upload handler.
414
+ * Must contain at least the `src` property with the image URL.
415
+ */
416
+ interface ImageUploadHandlerResult {
417
+ /** URL of the uploaded image (can be a remote URL or any string) */
418
+ src: string;
419
+ /** Optional custom alt text */
420
+ alt?: string;
421
+ /** Optional custom title */
422
+ title?: string;
423
+ }
424
+ /**
425
+ * Custom handler function for image uploads.
426
+ * Allows users to implement their own image storage logic (e.g., upload to S3, Cloudinary, etc.)
427
+ *
428
+ * Can return either a Promise or an Observable (Angular-friendly).
429
+ *
430
+ * @param context - Context containing the image file and metadata
431
+ * @returns Promise or Observable resolving to ImageUploadHandlerResult
432
+ *
433
+ * @example Using Promise (async/await)
434
+ * ```typescript
435
+ * uploadHandler: ImageUploadHandler = async (ctx) => {
436
+ * const formData = new FormData();
437
+ * formData.append('image', ctx.file);
438
+ * const result = await firstValueFrom(this.http.post<{url: string}>('/api/upload', formData));
439
+ * return { src: result.url };
440
+ * };
441
+ * ```
442
+ *
443
+ * @example Using Observable (Angular HttpClient)
444
+ * ```typescript
445
+ * uploadHandler: ImageUploadHandler = (ctx) => {
446
+ * const formData = new FormData();
447
+ * formData.append('image', ctx.file);
448
+ * return this.http.post<{url: string}>('/api/upload', formData).pipe(
449
+ * map(result => ({ src: result.url }))
450
+ * );
451
+ * };
452
+ * ```
453
+ */
454
+ type ImageUploadHandler = (context: ImageUploadContext) => Promise<ImageUploadHandlerResult> | Observable<ImageUploadHandlerResult>;
396
455
  declare class ImageService {
397
456
  selectedImage: _angular_core.WritableSignal<ImageData | null>;
398
457
  isImageSelected: _angular_core.Signal<boolean>;
@@ -400,6 +459,23 @@ declare class ImageService {
400
459
  isUploading: _angular_core.WritableSignal<boolean>;
401
460
  uploadProgress: _angular_core.WritableSignal<number>;
402
461
  uploadMessage: _angular_core.WritableSignal<string>;
462
+ /**
463
+ * Custom upload handler for images.
464
+ * When set, this handler will be called instead of the default base64 conversion.
465
+ * This allows users to implement their own image storage logic.
466
+ *
467
+ * @example
468
+ * ```typescript
469
+ * imageService.uploadHandler = async (context) => {
470
+ * const formData = new FormData();
471
+ * formData.append('image', context.file);
472
+ * const response = await fetch('/api/upload', { method: 'POST', body: formData });
473
+ * const data = await response.json();
474
+ * return { src: data.url };
475
+ * };
476
+ * ```
477
+ */
478
+ uploadHandler: ImageUploadHandler | null;
403
479
  private currentEditor;
404
480
  selectImage(editor: Editor): void;
405
481
  clearSelection(): void;
@@ -599,6 +675,26 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
599
675
  imageBubbleMenu: _angular_core.InputSignal<Partial<ImageBubbleMenuConfig>>;
600
676
  toolbar: _angular_core.InputSignal<Partial<ToolbarConfig>>;
601
677
  imageUpload: _angular_core.InputSignal<Partial<any>>;
678
+ /**
679
+ * Custom handler for image uploads.
680
+ * When provided, images will be processed through this handler instead of being converted to base64.
681
+ * This allows you to upload images to your own server/storage and use the returned URL.
682
+ *
683
+ * @example
684
+ * ```typescript
685
+ * myUploadHandler: ImageUploadHandler = async (context) => {
686
+ * const formData = new FormData();
687
+ * formData.append('image', context.file);
688
+ * const response = await fetch('/api/upload', { method: 'POST', body: formData });
689
+ * const data = await response.json();
690
+ * return { src: data.imageUrl };
691
+ * };
692
+ *
693
+ * // In template:
694
+ * // <angular-tiptap-editor [imageUploadHandler]="myUploadHandler" />
695
+ * ```
696
+ */
697
+ imageUploadHandler: _angular_core.InputSignal<ImageUploadHandler | undefined>;
602
698
  contentChange: _angular_core.OutputEmitterRef<string>;
603
699
  editorCreated: _angular_core.OutputEmitterRef<Editor>;
604
700
  editorUpdate: _angular_core.OutputEmitterRef<{
@@ -683,7 +779,7 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
683
779
  setDisabledState(isDisabled: boolean): void;
684
780
  onEditorClick(event: MouseEvent): void;
685
781
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AngularTiptapEditorComponent, never>;
686
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AngularTiptapEditorComponent, "angular-tiptap-editor", never, { "content": { "alias": "content"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "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; }; "showToolbar": { "alias": "showToolbar"; "required": false; "isSignal": true; }; "showCharacterCount": { "alias": "showCharacterCount"; "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; }; "slashCommandsConfig": { "alias": "slashCommandsConfig"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "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; }; "imageUpload": { "alias": "imageUpload"; "required": false; "isSignal": true; }; }, { "contentChange": "contentChange"; "editorCreated": "editorCreated"; "editorUpdate": "editorUpdate"; "editorFocus": "editorFocus"; "editorBlur": "editorBlur"; }, never, never, true, [{ directive: typeof NoopValueAccessorDirective; inputs: {}; outputs: {}; }]>;
782
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AngularTiptapEditorComponent, "angular-tiptap-editor", never, { "content": { "alias": "content"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "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; }; "showToolbar": { "alias": "showToolbar"; "required": false; "isSignal": true; }; "showCharacterCount": { "alias": "showCharacterCount"; "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; }; "slashCommandsConfig": { "alias": "slashCommandsConfig"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "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; }; "imageUpload": { "alias": "imageUpload"; "required": false; "isSignal": true; }; "imageUploadHandler": { "alias": "imageUploadHandler"; "required": false; "isSignal": true; }; }, { "contentChange": "contentChange"; "editorCreated": "editorCreated"; "editorUpdate": "editorUpdate"; "editorFocus": "editorFocus"; "editorBlur": "editorBlur"; }, never, never, true, [{ directive: typeof NoopValueAccessorDirective; inputs: {}; outputs: {}; }]>;
687
783
  }
688
784
 
689
785
  /**
@@ -706,4 +802,4 @@ type HeightConfig = {
706
802
  };
707
803
 
708
804
  export { AngularTiptapEditorComponent, DEFAULT_BUBBLE_MENU_CONFIG, DEFAULT_CELL_MENU_CONFIG, DEFAULT_IMAGE_BUBBLE_MENU_CONFIG, DEFAULT_SLASH_COMMANDS, DEFAULT_TABLE_MENU_CONFIG, DEFAULT_TOOLBAR_CONFIG, EditorCommandsService, ImageService, NoopValueAccessorDirective, SLASH_COMMAND_KEYS, TiptapI18nService, createI18nSlashCommands, filterSlashCommands };
709
- export type { BubbleMenuConfig, CellBubbleMenuConfig, HeightConfig, ImageBubbleMenuConfig, ImageData, ImageUploadResult, ResizeOptions, SlashCommandItem, SlashCommandsConfig, SupportedLocale, TableBubbleMenuConfig, TiptapTranslations, ToolbarConfig };
805
+ export type { BubbleMenuConfig, CellBubbleMenuConfig, HeightConfig, ImageBubbleMenuConfig, ImageData, ImageUploadContext, ImageUploadHandler, ImageUploadHandlerResult, ImageUploadResult, ResizeOptions, SlashCommandItem, SlashCommandsConfig, SupportedLocale, TableBubbleMenuConfig, TiptapTranslations, ToolbarConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flogeez/angular-tiptap-editor",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
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",