ngx-tiptap

repository·master·Indexed 41 days ago

https://github.com/sibiraj-s/ngx-tiptap

Angular bindings for Tiptap 3 (version 14.0.1), enabling the integration of Tiptap's headless editor into Angular applications. It provides directives for the editor, bubble menus, and floating menus, as well as tools like AngularNodeViewRenderer and AngularNodeViewComponent to render Angular components as NodeViews.

Tokens
4.8K
Snippets
18
Records
21
Agent score
51%

What's inside ngx-tiptap

  1. Add editable content to a Node View

    master

    To allow users to edit content inside an Angular-based NodeView, use the TiptapNodeViewContentDirective. Apply the tiptapNodeViewContent directive to an element within your component template.

    <!-- editable.component.html -->
    <div class="angular-component-with-content">
      <p tiptapNodeViewContent></p>
    </div>
  2. Basic Usage of TiptapEditor

    master

    To use the editor, import TiptapEditorDirective into your standalone component. You must manually create an instance of the Tiptap Editor and ensure you call editor.destroy() when the component is destroyed to prevent memory leaks. Use [(ngModel)] for two-way data binding.

    import { Component, OnDestroy } from '@angular/core';
    import { Editor } from '@tiptap/core';
    import StarterKit from '@tiptap/starter-kit';
    import { TiptapEditorDirective } from 'ngx-tiptap';
    
    @Component({
      selector: 'app-root',
      template: `
        <tiptap-editor [editor]="editor" [(ngModel)]="value"></tiptap-editor>
      ',
      imports: [TiptapEditorDirective],
    })
    export class AppComponent implements OnDestroy {
      editor = new Editor({
        extensions: [StarterKit],
      });
    
      value = '<p>Hello, Tiptap!</p>';
    
      ngOnDestroy(): void {
        this.editor.destroy();
      }
    }
  3. Create an Angular Node Extension with AngularNodeViewRenderer

    master

    To render Angular components as Tiptap NodeViews, use AngularNodeViewRenderer. This requires a two-step process: creating a Node extension that uses the renderer and creating an Angular component that extends AngularNodeViewComponent.

    // 1. Create the Extension
    import { Injector } from '@angular/core';
    import { Node, mergeAttributes } from '@tiptap/core';
    import { AngularNodeViewRenderer } from 'ngx-tiptap';
    import { NodeviewCounterComponent } from './nodeview-counter/nodeview-counter.component';
    
    const CounterComponentExtension = (injector: Injector): Node => {
      return Node.create({
        name: 'counter',
        parseHTML() {
          return [{ tag: 'angular-component-counter' }];
        },
        renderHTML({ HTMLAttributes }) {
          return ['angular-component-counter', mergeAttributes(HTMLAttributes)];
        },
        addNodeView() {
          return AngularNodeViewRenderer(NodeviewCounterComponent, { injector });
        },
      });
    };
    
    // 2. Create the Component
    import { Component } from '@angular/core';
    import { AngularNodeViewComponent } from 'ngx-tiptap';
    
    @Component({
      selector: 'app-nodeview-counter',
      template: `<div>Count: {{ node.attrs.count }}</div>`,
    })
    export class NodeviewCounterComponent extends AngularNodeViewComponent {
      increment(): void {
        const updateAttributes = this.updateAttributes();
        updateAttributes({
          count: this.node.attrs.count + 1,
        });
      }
    }
  4. Make Node Views draggable

    master

    To enable dragging for your Angular NodeViews:

    1. Set draggable: true in your Tiptap extension configuration.
    2. Import TiptapDraggableDirective into your component.
    3. Apply the tiptapDraggable directive to the specific DOM element inside your component that should act as the drag handle.
  5. Use Floating Menu

    master

    The TiptapFloatingMenuDirective allows you to render a contextual menu that appears near a text selection. You must import the directive and provide the editor instance.

    <tiptap-editor [editor]="editor"></tiptap-editor>
    <tiptap-floating-menu [editor]="editor">
      <!-- Anything that should be rendered inside floating menu -->
    </tiptap-floating-menu>
  6. Use Bubble Menu

    master

    The TiptapBubbleMenuDirective allows you to render a contextual menu near a text selection, typically used for applying marks (like bold or italic) to selected text. You must import the directive and provide the editor instance.

    <tiptap-editor [editor]="editor"></tiptap-editor>
    <tiptap-bubble-menu [editor]="editor">
      <!-- Anything that should be rendered inside bubble menu -->
    </tiptap-bubble-menu>
  7. Manually render components with AngularRenderer

    master

    Use AngularRenderer to manually manage the lifecycle of an Angular component within the Tiptap environment.

    import { AngularRenderer } from 'ngx-tiptap';
    
    const renderer = new AngularRenderer(Component, injector, props);
    
    renderer.instance; // Access the component instance to update @Input properties
    renderer.dom;      // Access the HTMLElement for the component
    renderer.destroy(); // Destroy the component and its instance
  8. Configure AngularNodeViewRenderer options

    master

    When calling AngularNodeViewRenderer, you can provide several configuration options to control how the Angular component behaves and how it is rendered in the DOM.

    Options

    OptionTypeDescription
    injectorInjectorRequired. The Angular Injector used to instantiate the component.
    update((props: RendererUpdateProps) => boolean) | nullAn optional function to handle manual updates of the node view. It receives the old and new node states and decorations.
    attrsRecord<string, string> | ((props: { node: ProseMirrorNode; HTMLAttributes: Record<string, unknown>; }) => Record<string, string>)Defines the attributes applied to the top-level element of the component. Can be a static object or a function that computes attributes based on the node and its HTML attributes.
    contentDOMElementTagstring(Inherited from NodeViewRendererOptions) An optional tag name for the element that will contain the node's content.
  9. Configure the output format for TiptapEditorDirective

    master

    The TiptapEditorDirective provides an outputFormat input to control whether the content emitted to the Angular form control is HTML or JSON.

    • Set outputFormat to 'html' (default) to receive the editor content as an HTML string.
    • Set outputFormat to 'json' to receive the editor content as a JSON object (Tiptap Content format).
    <div tiptap [editor]="myEditor" [outputFormat]="'json'"></div>
  10. Customize component attributes with the `attrs` option

    master

    The attrs option in AngularNodeViewRenderer allows you to dynamically set attributes on the host element of your Angular component. This is useful for syncing Tiptap node attributes (like id, class, or custom data attributes) to the actual DOM element rendered by Angular.

    You can provide attrs as a static object or as a function for dynamic calculation.

    Static attributes:

    attrs: { class: 'my-custom-node' }

    Dynamic attributes (using node properties):

    attrs: ({ node, HTMLAttributes }) => ({
      'data-id': node.attrs.id,
      ...HTMLAttributes
    })
    AngularNodeViewRenderer(MyComponent, {
      injector: myInjector,
      attrs: ({ node, HTMLAttributes }) => ({
        'data-custom-attr': node.attrs.someValue,
        ...HTMLAttributes
      })
    });