{"version":3,"file":"taiga-ui-editor-extensions-tiptap-node-view.mjs","sources":["../../../projects/editor/extensions/tiptap-node-view/index.ts","../../../projects/editor/extensions/tiptap-node-view/taiga-ui-editor-extensions-tiptap-node-view.ts"],"sourcesContent":["import {DOCUMENT} from '@angular/common';\nimport {\n    ApplicationRef,\n    ComponentFactoryResolver,\n    type ComponentRef,\n    ElementRef,\n    type Injector,\n    type Type,\n} from '@angular/core';\nimport {TUI_EDITOR_PM_SELECTED_NODE} from '@taiga-ui/editor/common';\nimport {\n    type DecorationWithType,\n    type Editor,\n    NodeView,\n    type NodeViewProps,\n    type NodeViewRendererOptions,\n    type NodeViewRendererProps,\n} from '@tiptap/core';\nimport {type Node as ProseMirrorNode} from '@tiptap/pm/model';\nimport {type Decoration, type DecorationSource, type EditorView} from '@tiptap/pm/view';\n\n/**\n * Copied from\n * {@link https://github.com/sibiraj-s/ngx-tiptap/blob/master/projects/ngx-tiptap/src/lib/AngularRenderer.ts ngx-tiptap}\n */\nexport class TuiComponentRenderer<C, P> {\n    private readonly componentRef: ComponentRef<C>;\n\n    constructor(component: Type<C>, injector: Injector, props: Partial<P>) {\n        const applicationRef = injector.get(ApplicationRef);\n\n        const componentFactoryResolver = injector.get(ComponentFactoryResolver);\n        const factory = componentFactoryResolver.resolveComponentFactory(component);\n\n        this.componentRef = factory.create(injector, []);\n\n        // set input props to the component\n        this.updateProps(props);\n\n        // Attach to the view so that the change detector knows to run\n        applicationRef.attachView(this.componentRef.hostView);\n    }\n\n    public get el(): ElementRef {\n        return this.componentRef.injector.get(ElementRef);\n    }\n\n    public get dom(): HTMLElement {\n        return this.el.nativeElement;\n    }\n\n    public updateProps<T extends P>(props: Partial<T>): void {\n        Object.entries(props).forEach(([key, value]) => {\n            this.instance[key as keyof C] = value as C[keyof C];\n        });\n    }\n\n    public detectChanges(): void {\n        this.componentRef.changeDetectorRef.detectChanges();\n    }\n\n    public destroy(): void {\n        this.componentRef.destroy();\n    }\n\n    protected get instance(): C {\n        return this.componentRef.instance;\n    }\n}\n\n/**\n * You should extend this class to create custom\n * Tiptap's {@link https://tiptap.dev/guide/node-views NodeView} from angular component.\n * It contains compulsory properties which component will get externally while NodeView's rendering.\n */\nexport abstract class TuiNodeViewNg implements NodeViewProps {\n    declare public editor: NodeViewProps['editor'];\n    declare public decorations: NodeViewProps['decorations'];\n    declare public selected: NodeViewProps['selected'];\n    declare public extension: NodeViewProps['extension'];\n    declare public getPos: NodeViewProps['getPos'];\n    declare public updateAttributes: NodeViewProps['updateAttributes'];\n    declare public deleteNode: NodeViewProps['deleteNode'];\n    // eslint-disable-next-line @typescript-eslint/naming-convention\n    declare public HTMLAttributes: Record<string, any>;\n    declare public innerDecorations: DecorationSource;\n    declare public view: EditorView;\n\n    public abstract get node(): NodeViewProps['node'];\n    public abstract set node(value: NodeViewProps['node']);\n}\n\nexport interface TuiNodeViewRendererOptions extends NodeViewRendererOptions {\n    injector: Injector;\n    update?(node: ProseMirrorNode, decorations: Decoration[]): boolean;\n}\n\n/**\n * Tiptap editor proposes concept of interactive {@link https://tiptap.dev/guide/node-views NodeViews}.\n * It gives you opportunity to create custom complex Node inside editor. And it will look like native Tiptap's Node.\n * Regard it like angular component inside editor.\n *\n * This solution is adaptation of official React implementation of NodeViews.\n * It was copied from\n * {@link https://github.com/sibiraj-s/ngx-tiptap/blob/master/projects/ngx-tiptap/src/lib/NodeViewRenderer.ts ngx-tiptap}\n */\nexport class TuiNodeView extends NodeView<\n    Type<TuiNodeViewNg>,\n    Editor,\n    TuiNodeViewRendererOptions\n> {\n    declare protected renderer: TuiComponentRenderer<TuiNodeViewNg, NodeViewProps>;\n    protected contentDOMElement: HTMLElement | null = null;\n\n    /**\n     * @caretaker note:\n     * Class constructor NodeView cannot be invoked without 'new'\n     */\n    // eslint-disable-next-line @typescript-eslint/no-useless-constructor\n    constructor(\n        component: Type<TuiNodeViewNg>,\n        props: NodeViewRendererProps,\n        options?: Partial<TuiNodeViewRendererOptions>,\n    ) {\n        super(component, props, options);\n    }\n\n    public override get dom(): HTMLElement {\n        return this.renderer.dom;\n    }\n\n    public override get contentDOM(): HTMLElement | null {\n        if (this.node.isLeaf) {\n            return null;\n        }\n\n        return this.contentDOMElement;\n    }\n\n    public override mount(): void {\n        const injector = this.options.injector;\n        const doc = injector.get(DOCUMENT);\n\n        const props: NodeViewProps = {\n            editor: this.editor,\n            node: this.node,\n            decorations: this.decorations as readonly DecorationWithType[],\n            selected: false,\n            extension: this.extension,\n            getPos: () => this.getPos(),\n            updateAttributes: (attributes) => this.updateAttributes(attributes),\n            deleteNode: () => this.deleteNode(),\n            view: this.view,\n            innerDecorations: this.innerDecorations,\n            HTMLAttributes: this.HTMLAttributes,\n        };\n\n        this.editor.on('selectionUpdate', this.handleSelectionUpdate.bind(this));\n\n        // create renderer\n        this.renderer = new TuiComponentRenderer(this.component, injector, props);\n\n        // Register drag handler\n        if (this.extension.config.draggable !== undefined) {\n            this.renderer.el.nativeElement.ondragstart = (e: DragEvent) => {\n                this.onDragStart(e);\n            };\n        }\n\n        const inline = this.node.isInline ? 'span' : 'div';\n\n        this.contentDOMElement = this.node.isLeaf ? null : doc.createElement(inline);\n\n        if (this.contentDOMElement) {\n            // For some reason the whiteSpace prop is not inherited properly in Chrome and Safari\n            // With this fix it seems to work fine\n            // See: https://github.com/ueberdosis/tiptap/issues/1197\n            this.contentDOMElement.style.whiteSpace = 'inherit';\n            this.renderer.detectChanges();\n        }\n\n        this.appendContendDom();\n    }\n\n    protected update(node: ProseMirrorNode, decorations: DecorationWithType[]): boolean {\n        if (this.options.update) {\n            return this.options.update(node, decorations);\n        }\n\n        if (node.type !== this.node.type) {\n            return false;\n        }\n\n        if (node === this.node && this.decorations === decorations) {\n            return true;\n        }\n\n        this.node = node;\n        this.decorations = decorations;\n        this.renderer.updateProps({node, decorations});\n        this.appendContendDom();\n\n        return true;\n    }\n\n    protected handleSelectionUpdate(): void {\n        const {from, to} = this.editor.state.selection;\n\n        if (from <= this.getPos() && to >= this.getPos() + this.node.nodeSize) {\n            this.selectNode();\n        } else {\n            this.deselectNode();\n        }\n    }\n\n    protected selectNode(): void {\n        this.renderer.updateProps({selected: true});\n        this.renderer.dom.classList.add(TUI_EDITOR_PM_SELECTED_NODE);\n    }\n\n    protected deselectNode(): void {\n        this.renderer.updateProps({selected: false});\n        this.renderer.dom.classList.remove(TUI_EDITOR_PM_SELECTED_NODE);\n    }\n\n    protected destroy(): void {\n        this.renderer.destroy();\n        this.editor.off('selectionUpdate', this.handleSelectionUpdate.bind(this));\n        this.contentDOMElement = null;\n    }\n\n    private appendContendDom(): void {\n        const contentElement = this.dom.querySelector('[data-node-view-content]');\n\n        if (\n            this.contentDOMElement &&\n            contentElement &&\n            !contentElement.contains(this.contentDOMElement)\n        ) {\n            contentElement.appendChild(this.contentDOMElement);\n        }\n    }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}