@flogeez/angular-tiptap-editor 0.3.4 → 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;
@@ -592,12 +668,33 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
592
668
  enableSlashCommands: _angular_core.InputSignal<boolean>;
593
669
  slashCommandsConfig: _angular_core.InputSignal<SlashCommandsConfig | undefined>;
594
670
  locale: _angular_core.InputSignal<SupportedLocale | undefined>;
671
+ autofocus: _angular_core.InputSignal<number | boolean | "end" | "start" | "all">;
595
672
  showBubbleMenu: _angular_core.InputSignal<boolean>;
596
673
  bubbleMenu: _angular_core.InputSignal<Partial<BubbleMenuConfig>>;
597
674
  showImageBubbleMenu: _angular_core.InputSignal<boolean>;
598
675
  imageBubbleMenu: _angular_core.InputSignal<Partial<ImageBubbleMenuConfig>>;
599
676
  toolbar: _angular_core.InputSignal<Partial<ToolbarConfig>>;
600
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>;
601
698
  contentChange: _angular_core.OutputEmitterRef<string>;
602
699
  editorCreated: _angular_core.OutputEmitterRef<Editor>;
603
700
  editorUpdate: _angular_core.OutputEmitterRef<{
@@ -682,7 +779,7 @@ declare class AngularTiptapEditorComponent implements AfterViewInit, OnDestroy {
682
779
  setDisabledState(isDisabled: boolean): void;
683
780
  onEditorClick(event: MouseEvent): void;
684
781
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AngularTiptapEditorComponent, never>;
685
- 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; }; "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: {}; }]>;
686
783
  }
687
784
 
688
785
  /**
@@ -705,4 +802,4 @@ type HeightConfig = {
705
802
  };
706
803
 
707
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 };
708
- 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.4",
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",