import type { EditorOptions } from '@tiptap/core'; import { Editor } from '@tiptap/core'; import { createEffect, createSignal, onCleanup } from 'solid-js'; export type EditorRef = Editor | ((editor: Editor) => void); export type BaseEditorOptions = Omit, 'element'>; export interface UseEditorOptions extends BaseEditorOptions { element: T; } export function createEditorTransaction( instance: () => V, read: (value: V) => T, ): () => T { const [depend, update] = createSignal(undefined, { equals: false }); function forceUpdate() { update(); } createEffect(() => { const editor = instance(); if (editor) { editor.on('transaction', forceUpdate); onCleanup(() => { editor.off('transaction', forceUpdate); }); } }); return () => { depend(); return read(instance()); }; } export default function useEditor( props: () => UseEditorOptions, ): () => Editor | undefined { const [signal, setSignal] = createSignal(); createEffect(() => { const instance = new Editor({ ...props(), }); onCleanup(() => { instance.destroy(); }); setSignal(instance); }); return signal; } export function useEditorHTML( editor: () => V, ): () => string | undefined { return createEditorTransaction(editor, instance => instance?.getHTML()); } export function useEditorJSON< V extends Editor | undefined, R extends Record, >(editor: () => V): () => R | undefined { return createEditorTransaction(editor, instance => instance?.getJSON() as R | undefined); } export function useEditorIsActive< V extends Editor | undefined, R extends Record, >( editor: () => V, ...args: [name: () => string, options?: R] | [options: R] ): () => boolean | undefined { return createEditorTransaction(editor, instance => { if (args.length === 2) { return instance?.isActive(args[0](), args[1]); } return instance?.isActive(args[0]); }); } export function useEditorIsEmpty( editor: () => V, ): () => boolean | undefined { return createEditorTransaction(editor, instance => instance?.isEmpty); } export function useEditorIsEditable( editor: () => V, ): () => boolean | undefined { return createEditorTransaction(editor, instance => instance?.isEditable); } export function useEditorIsFocused( editor: () => V, ): () => boolean | undefined { return createEditorTransaction(editor, instance => instance?.isFocused); }