@blocknote/react
Version:
A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.
1 lines • 42.3 kB
Source Map (JSON)
{"version":3,"file":"defaultCommentEditorSchema-Cow33c_f.cjs","names":[],"sources":["../src/editor/BlockNoteContext.ts","../src/hooks/useBlockNoteEditor.ts","../src/hooks/useExtension.ts","../src/components/Popovers/GenericPopover.tsx","../src/editor/ComponentsContext.tsx","../src/i18n/dictionary.ts","../src/hooks/useEditorState.ts","../src/hooks/useEditorDomElement.ts","../src/components/Popovers/PositionPopover.tsx","../src/hooks/useCreateBlockNote.tsx","../src/components/Comments/CommentEditor.tsx","../src/components/Comments/defaultCommentEditorSchema.ts"],"sourcesContent":["import {\n BlockNoteEditor,\n BlockNoteSchema,\n BlockSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"@blocknote/core\";\nimport { createContext, useContext, useState } from \"react\";\n\nexport type BlockNoteContextValue<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n> = {\n setContentEditableProps?: ReturnType<typeof useState<Record<string, any>>>[1]; // copy type of setXXX from useState\n editor?: BlockNoteEditor<BSchema, ISchema, SSchema>;\n colorSchemePreference?: \"light\" | \"dark\";\n};\n\nexport const BlockNoteContext = createContext<\n BlockNoteContextValue | undefined\n>(undefined);\n\n/**\n * Get the BlockNoteContext instance from the nearest BlockNoteContext provider\n * @param _schema: optional, pass in the schema to return type-safe Context if you're using a custom schema\n */\nexport function useBlockNoteContext<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n>(\n _schema?: BlockNoteSchema<BSchema, ISchema, SSchema>,\n): BlockNoteContextValue<BSchema, ISchema, SSchema> | undefined {\n const context = useContext(BlockNoteContext) as any;\n\n return context;\n}\n","import {\n BlockNoteEditor,\n BlockNoteSchema,\n BlockSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n InlineContentSchema,\n StyleSchema,\n} from \"@blocknote/core\";\n\nimport { useBlockNoteContext } from \"../editor/BlockNoteContext.js\";\n\n/**\n * Get the BlockNoteEditor instance from the nearest BlockNoteContext provider\n * @param _schema: optional, pass in the schema to return type-safe BlockNoteEditor if you're using a custom schema\n */\nexport function useBlockNoteEditor<\n BSchema extends BlockSchema = DefaultBlockSchema,\n ISchema extends InlineContentSchema = DefaultInlineContentSchema,\n SSchema extends StyleSchema = DefaultStyleSchema,\n>(\n _schema?: BlockNoteSchema<BSchema, ISchema, SSchema>,\n): BlockNoteEditor<BSchema, ISchema, SSchema> {\n const context = useBlockNoteContext(_schema);\n\n if (!context?.editor) {\n throw new Error(\n \"useBlockNoteEditor was called outside of a BlockNoteContext provider or BlockNoteView component\",\n );\n }\n\n return context.editor;\n}\n","import {\n BlockNoteEditor,\n createStore,\n Extension,\n ExtensionFactory,\n} from \"@blocknote/core\";\nimport { useStore } from \"@tanstack/react-store\";\nimport { useBlockNoteEditor } from \"./useBlockNoteEditor.js\";\n\ntype Store<T> = ReturnType<typeof createStore<T>>;\n\n/**\n * Use an extension instance\n */\nexport function useExtension<\n const T extends ExtensionFactory | Extension | string,\n>(\n plugin: T,\n ctx?: { editor?: BlockNoteEditor<any, any, any> },\n): T extends ExtensionFactory\n ? NonNullable<ReturnType<ReturnType<T>>>\n : T extends string\n ? Extension\n : T extends Extension\n ? T\n : never {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const editor = ctx?.editor ?? useBlockNoteEditor();\n\n const instance = editor.getExtension(plugin as any);\n\n if (!instance) {\n throw new Error(\"Extension not found\", { cause: { plugin } });\n }\n\n return instance;\n}\n\ntype ExtractStore<T> = T extends Store<infer U> ? U : never;\n\n/**\n * Use the state of an extension\n */\nexport function useExtensionState<\n T extends ExtensionFactory | Extension,\n TExtension = T extends ExtensionFactory ? ReturnType<ReturnType<T>> : T,\n TStore = TExtension extends { store: Store<any> }\n ? TExtension[\"store\"]\n : never,\n TSelected = NoInfer<ExtractStore<TStore>>,\n>(\n plugin: T,\n ctx?: {\n editor?: BlockNoteEditor<any, any, any>;\n selector?: (state: NoInfer<ExtractStore<TStore>>) => TSelected;\n },\n): TSelected {\n const { store } = useExtension(plugin, ctx);\n if (!store) {\n throw new Error(\"Store not found on plugin\", { cause: { plugin } });\n }\n return useStore<ExtractStore<TStore>, TSelected>(store, ctx?.selector as any);\n}\n","import {\n autoUpdate,\n FloatingFocusManager,\n FloatingPortal,\n useDismiss,\n useFloating,\n UseFloatingOptions,\n useHover,\n useInteractions,\n useMergeRefs,\n useTransitionStatus,\n useTransitionStyles,\n} from \"@floating-ui/react\";\nimport { HTMLAttributes, ReactNode, useEffect, useRef } from \"react\";\n\nimport { useBlockNoteEditor } from \"../../hooks/useBlockNoteEditor.js\";\nimport { FloatingUIOptions } from \"./FloatingUIOptions.js\";\n\nexport type GenericPopoverReference =\n | {\n // A DOM element to use as the reference element for the popover.\n element: Element;\n // To update the popover position, `element.getReferenceBoundingRect`\n // is called. This flag caches the last result of the call while the\n // element is mounted to the DOM, so it doesn't update while the\n // popover is closing and transitioning out. Useful for if the\n // reference element unmounts, as `element.getReferenceBoundingRect`\n // would return a `DOMRect` with x, y, width, and height of 0.\n // Defaults to `true`.\n cacheMountedBoundingClientRect?: boolean;\n }\n | {\n element: undefined;\n // When no reference element is provided, this can be provided as an\n // alternative \"virtual\" element to position the popover around.\n getBoundingClientRect: () => DOMRect;\n }\n | {\n element: Element;\n cacheMountedBoundingClientRect?: boolean;\n // If both `element` and `getBoundingClientRect` are provided, uses\n // `getBoundingClientRect` to position the popover, but still treats\n // `element` as the reference element for all other purposes. When\n // `cacheMountedBoundingClientRect` is `true` or unspecified, this\n // function is not called while the reference element is not mounted.\n getBoundingClientRect: () => DOMRect;\n };\n\n// Returns a modified version of `getBoundingClientRect`, if\n// `reference.element` is passed and `reference.cacheMountedBoundingClientRect`\n// is `true` or `undefined`. In the modified version, each new result is cached\n// and returned while `reference.element` is connected to the DOM. If it is no\n// longer connected, the cache is no longer updated and the last cached result\n// is used.\n//\n// In all other cases, just returns `reference.getBoundingClientRect`, or\n// `reference.element.getBoundingClientRect` if it's not defined.\nexport function getMountedBoundingClientRectCache(\n reference: GenericPopoverReference,\n) {\n let lastBoundingClientRect = new DOMRect();\n const getBoundingClientRect =\n \"getBoundingClientRect\" in reference\n ? () => reference.getBoundingClientRect()\n : () => reference.element.getBoundingClientRect();\n\n return () => {\n if (\n reference.element &&\n (reference.cacheMountedBoundingClientRect ?? true)\n ) {\n if (reference.element.isConnected) {\n lastBoundingClientRect = getBoundingClientRect();\n }\n\n return lastBoundingClientRect;\n }\n\n return getBoundingClientRect();\n };\n}\n\n/**\n * Merges two `whileElementsMounted` handlers into one. Both run when elements\n * mount, and both cleanup functions are called on unmount.\n */\nfunction mergeWhileElementsMounted(\n a: UseFloatingOptions[\"whileElementsMounted\"],\n b: UseFloatingOptions[\"whileElementsMounted\"],\n): UseFloatingOptions[\"whileElementsMounted\"] {\n if (!a) {\n return b;\n }\n if (!b) {\n return a;\n }\n\n return (reference, floating, update) => {\n const cleanupA = a(reference, floating, update);\n const cleanupB = b(reference, floating, update);\n return () => {\n cleanupA?.();\n cleanupB?.();\n };\n };\n}\n\nexport const GenericPopover = (\n props: FloatingUIOptions & {\n reference?: GenericPopoverReference;\n children: ReactNode;\n /**\n * Override the DOM node this popover portals into. If omitted, falls back\n * to `editor.portalElement`.\n */\n portalElement?: HTMLElement | null;\n },\n) => {\n const editor = useBlockNoteEditor();\n const portalRoot =\n props.portalElement === null\n ? typeof document !== \"undefined\"\n ? document.body\n : undefined\n : (props.portalElement ?? editor?.portalElement);\n if (!portalRoot) {\n throw new Error(\"Portal element not found\");\n }\n const {\n whileElementsMounted: _whileElementsMounted,\n ...restFloatingOptions\n } = props.useFloatingOptions ?? {};\n\n const { refs, floatingStyles, context } = useFloating<HTMLDivElement>({\n whileElementsMounted: mergeWhileElementsMounted(\n autoUpdate,\n props.useFloatingOptions?.whileElementsMounted,\n ),\n ...restFloatingOptions,\n });\n\n const { isMounted, styles } = useTransitionStyles(\n context,\n props.useTransitionStylesProps,\n );\n const { status } = useTransitionStatus(\n context,\n props.useTransitionStatusProps,\n );\n\n const dismiss = useDismiss(context, props.useDismissProps);\n const hover = useHover(context, { enabled: false, ...props.useHoverProps });\n // Also returns `getReferenceProps` but unused as the reference element may\n // not even be managed by React, so we may be unable to set them. Seems like\n // `refs.setReferences` attaches most of the same listeners anyway, but\n // possible both are needed.\n const { getFloatingProps } = useInteractions([dismiss, hover]);\n\n const innerHTML = useRef<string>(\"\");\n const ref = useRef<HTMLDivElement>(null);\n const mergedRefs = useMergeRefs([ref, refs.setFloating]);\n\n useEffect(() => {\n if (props.reference) {\n const element =\n \"element\" in props.reference ? props.reference.element : undefined;\n\n if (\n element !== undefined &&\n (props.focusManagerProps?.disabled ||\n !editor.isWithinEditor(element))\n ) {\n // Only set domReference when FloatingFocusManager is disabled.\n // When FloatingFocusManager is active (disabled !== false) and the\n // reference is inside the ProseMirror editor, setting domReference\n // causes floating-ui to call insertAdjacentElement on the reference,\n // inserting a focus-return <span> into the PM contenteditable. This\n // triggers PM's MutationObserver and resets the editor selection.\n // (issue #2525)\n refs.setReference(element);\n }\n\n refs.setPositionReference({\n getBoundingClientRect: getMountedBoundingClientRectCache(\n props.reference,\n ),\n contextElement: element,\n });\n }\n }, [props.reference, refs, props.focusManagerProps?.disabled, editor]);\n\n // Stores the last rendered `innerHTML` of the popover while it was open. The\n // `innerHTML` is used while the popover is closing, as the React children\n // may rerender during this time, causing unwanted behaviour.\n useEffect(\n () => {\n if (status === \"initial\" || status === \"open\") {\n if (ref.current?.innerHTML) {\n innerHTML.current = ref.current.innerHTML;\n }\n }\n },\n // `props.children` is added to the deps, since it's ultimately the HTML of\n // the children that we're storing.\n [status, props.reference, props.children],\n );\n\n if (!isMounted) {\n return false;\n }\n\n const mergedProps: HTMLAttributes<HTMLDivElement> = {\n ...props.elementProps,\n style: {\n display: \"flex\",\n ...props.elementProps?.style,\n zIndex: `calc(var(--bn-ui-base-z-index, 0) + ${props.elementProps?.style?.zIndex || 0})`,\n ...floatingStyles,\n ...styles,\n },\n ...getFloatingProps(),\n };\n\n if (status === \"close\") {\n // While the popover is closing, shows its last rendered `innerHTML` while\n // it was open, instead of the React children. This is because they may\n // rerender during this time, causing unwanted behaviour.\n //\n // When we use the `GenericPopover` for BlockNote's internal UI elements\n // this isn't a huge deal, as we only pass child components if the popover\n // should be open. So without this fix, the popover just won't transition\n // out and will instead appear to hide instantly.\n return (\n <FloatingPortal root={portalRoot}>\n <div\n ref={mergedRefs}\n {...mergedProps}\n dangerouslySetInnerHTML={{ __html: innerHTML.current }}\n />\n </FloatingPortal>\n );\n }\n\n if (!props.focusManagerProps?.disabled) {\n return (\n <FloatingPortal root={portalRoot}>\n <FloatingFocusManager {...props.focusManagerProps} context={context}>\n <div ref={mergedRefs} {...mergedProps}>\n {props.children}\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n );\n }\n\n return (\n <FloatingPortal root={portalRoot}>\n <div ref={mergedRefs} {...mergedProps}>\n {props.children}\n </div>\n </FloatingPortal>\n );\n};\n","import {\n ChangeEvent,\n ComponentType,\n createContext,\n CSSProperties,\n ForwardedRef,\n HTMLInputAutoCompleteAttribute,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n useContext,\n} from \"react\";\n\nimport { BlockNoteEditor } from \"@blocknote/core\";\nimport { User } from \"@blocknote/core/comments\";\nimport { DefaultReactGridSuggestionItem } from \"../components/SuggestionMenu/GridSuggestionMenu/types.js\";\nimport { DefaultReactSuggestionItem } from \"../components/SuggestionMenu/types.js\";\n\ntype ToolbarRootType = {\n className?: string;\n children?: ReactNode;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n variant?: \"default\" | \"action-toolbar\";\n};\n\ntype ToolbarButtonType = {\n className?: string;\n mainTooltip?: string;\n secondaryTooltip?: string;\n icon?: ReactNode;\n onClick?: (e: MouseEvent) => void;\n isSelected?: boolean;\n isDisabled?: boolean;\n variant?: \"default\" | \"compact\";\n} & (\n | { children: ReactNode; label?: string }\n | { children?: undefined; label: string }\n);\n\ntype ToolbarSelectType = {\n className?: string;\n items: {\n text: string;\n icon: ReactNode;\n onClick: () => void;\n isSelected: boolean;\n isDisabled?: boolean;\n }[];\n isDisabled?: boolean;\n};\n\ntype MenuButtonType = {\n className?: string;\n onClick?: (e: MouseEvent) => void;\n icon?: ReactNode;\n onDragStart?: (e: React.DragEvent) => void;\n onDragEnd?: (e: React.DragEvent) => void;\n draggable?: boolean;\n} & (\n | { children: ReactNode; label?: string }\n | { children?: undefined; label: string }\n);\n\nexport type ComponentProps = {\n FormattingToolbar: {\n Root: ToolbarRootType;\n Button: ToolbarButtonType;\n Select: ToolbarSelectType;\n };\n FilePanel: {\n Root: {\n className?: string;\n tabs: {\n name: string;\n tabPanel: ReactNode;\n }[];\n openTab: string;\n setOpenTab: (name: string) => void;\n defaultOpenTab: string;\n loading: boolean;\n };\n Button: {\n className?: string;\n onClick: () => void;\n } & (\n | { children: ReactNode; label?: string }\n | { children?: undefined; label: string }\n );\n FileInput: {\n className?: string;\n accept: string;\n value: File | null;\n placeholder: string;\n onChange: (payload: File | null) => void;\n };\n TabPanel: {\n className?: string;\n children?: ReactNode;\n };\n TextInput: {\n className?: string;\n value: string;\n placeholder: string;\n onChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onKeyDown: (event: KeyboardEvent) => void;\n };\n };\n LinkToolbar: {\n Root: ToolbarRootType;\n Button: ToolbarButtonType;\n Select: ToolbarSelectType;\n };\n SideMenu: {\n Root: {\n className?: string;\n children?: ReactNode;\n };\n Button: {\n className?: string;\n onClick?: (e: MouseEvent) => void;\n icon?: ReactNode;\n onDragStart?: (e: React.DragEvent) => void;\n onDragEnd?: (e: React.DragEvent) => void;\n draggable?: boolean;\n } & (\n | { children: ReactNode; label?: string }\n | { children?: undefined; label: string }\n );\n };\n SuggestionMenu: {\n Root: {\n id: string;\n className?: string;\n children?: ReactNode;\n };\n EmptyItem: {\n className?: string;\n children?: ReactNode;\n };\n Item: {\n className?: string;\n id: string;\n isSelected: boolean;\n onClick: () => void;\n item: Omit<DefaultReactSuggestionItem, \"onItemClick\">;\n };\n Label: {\n className?: string;\n children?: ReactNode;\n };\n Loader: {\n className?: string;\n };\n };\n GridSuggestionMenu: {\n Root: {\n id: string;\n columns: number;\n className?: string;\n children?: ReactNode;\n };\n EmptyItem: {\n columns: number;\n className?: string;\n children?: ReactNode;\n };\n Item: {\n className?: string;\n id: string;\n isSelected: boolean;\n onClick: () => void;\n item: DefaultReactGridSuggestionItem;\n };\n // Label: {\n // className?: string;\n // children?: ReactNode;\n // };\n Loader: {\n columns: number;\n className?: string;\n children?: ReactNode;\n };\n };\n TableHandle: {\n Root: {\n className?: string;\n draggable: boolean;\n onDragStart: (e: React.DragEvent) => void;\n onDragEnd: () => void;\n style?: CSSProperties;\n } & (\n | { children: ReactNode; label?: string }\n | { children?: undefined; label: string }\n );\n ExtendButton: {\n className?: string;\n onClick: (e: React.MouseEvent) => void;\n onMouseDown: (e: React.MouseEvent) => void;\n children: ReactNode;\n };\n };\n Comments: {\n Card: {\n className?: string;\n headerText?: string;\n selected?: boolean;\n onFocus?: (event: React.FocusEvent) => void;\n onBlur?: (event: React.FocusEvent) => void;\n tabIndex?: number;\n children?: ReactNode;\n };\n CardSection: {\n className?: string;\n children?: ReactNode;\n };\n ExpandSectionsPrompt: {\n className?: string;\n children?: ReactNode;\n };\n Editor: {\n className?: string;\n autoFocus?: boolean;\n editable: boolean;\n editor: BlockNoteEditor<any, any, any>;\n onFocus?: () => void;\n onBlur?: () => void;\n };\n Comment: {\n className?: string;\n children?: ReactNode;\n authorInfo: \"loading\" | User;\n timeString: string;\n edited: boolean;\n actions?: ReactNode;\n showActions?: boolean | \"hover\";\n emojiPickerOpen?: boolean;\n };\n };\n // TODO: We should try to make everything as generic as we can\n Generic: {\n Badge: {\n Root: {\n className?: string;\n text: string;\n icon?: ReactNode;\n isSelected?: boolean;\n mainTooltip?: string;\n secondaryTooltip?: string;\n onClick?: (event: React.MouseEvent) => void;\n onMouseEnter?: () => void;\n };\n Group: {\n className?: string;\n children: ReactNode;\n };\n };\n Form: {\n Root: {\n children?: ReactNode;\n };\n TextInput: {\n className?: string;\n name: string;\n label?: string;\n variant?: \"default\" | \"large\";\n icon: ReactNode;\n rightSection?: ReactNode;\n autoFocus?: boolean;\n placeholder?: string;\n disabled?: boolean;\n value: string;\n onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => void;\n onChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onSubmit?: () => void;\n autoComplete?: HTMLInputAutoCompleteAttribute;\n \"aria-activedescendant\"?: string;\n ref?: ForwardedRef<HTMLInputElement>;\n };\n };\n Menu: {\n Root: {\n sub?: boolean;\n onOpenChange?: (open: boolean) => void;\n position?:\n | \"top\"\n | \"right\"\n | \"bottom\"\n | \"left\"\n | `${\"top\" | \"right\" | \"bottom\" | \"left\"}-${\"start\" | \"end\"}`;\n children?: ReactNode;\n };\n Divider: {\n className?: string;\n };\n Dropdown: {\n className?: string;\n children?: ReactNode;\n sub?: boolean;\n };\n Item: {\n className?: string;\n children?: ReactNode;\n\n subTrigger?: boolean;\n icon?: ReactNode;\n checked?: boolean;\n onClick?: () => void;\n };\n Label: {\n className?: string;\n children?: ReactNode;\n };\n Trigger: {\n children?: ReactNode;\n sub?: boolean;\n };\n Button: MenuButtonType;\n };\n Popover: {\n Root: {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n position?:\n | \"top\"\n | \"right\"\n | \"bottom\"\n | \"left\"\n | `${\"top\" | \"right\" | \"bottom\" | \"left\"}-${\"start\" | \"end\"}`;\n portalRoot?: HTMLElement | null;\n children?: ReactNode;\n };\n Content: {\n className?: string;\n variant: \"form-popover\" | \"panel-popover\";\n children?: ReactNode;\n };\n Trigger: {\n children?: ReactNode;\n };\n };\n Toolbar: {\n Root: ToolbarRootType;\n Button: ToolbarButtonType;\n Select: ToolbarSelectType;\n };\n };\n};\n\nexport type Components = {\n [Components in keyof Omit<ComponentProps, \"Generic\">]: {\n [Component in keyof ComponentProps[Components]]: ComponentType<\n ComponentProps[Components][Component]\n >;\n };\n} & {\n // only needed as Generic Root/etc elements are 1 level of nesting deeper\n Generic: {\n [GenericComponents in keyof ComponentProps[\"Generic\"]]: {\n [Component in keyof ComponentProps[\"Generic\"][GenericComponents]]: ComponentType<\n ComponentProps[\"Generic\"][GenericComponents][Component]\n >;\n };\n };\n};\n\nexport const ComponentsContext = createContext<Components | undefined>(\n undefined,\n);\n\nexport function useComponentsContext(): Components | undefined {\n return useContext(ComponentsContext)!;\n}\n","import { Dictionary } from \"@blocknote/core\";\nimport { useBlockNoteContext } from \"../editor/BlockNoteContext.js\";\n\nexport function useDictionary(): Dictionary {\n const ctx = useBlockNoteContext();\n return ctx!.editor!.dictionary;\n}\n","import type { BlockNoteEditor } from \"@blocknote/core\";\nimport deepEqual from \"fast-deep-equal/es6/react.js\";\nimport { useDebugValue, useEffect, useLayoutEffect, useState } from \"react\";\nimport { useSyncExternalStoreWithSelector } from \"use-sync-external-store/shim/with-selector\";\nimport { useBlockNoteContext } from \"../editor/BlockNoteContext.js\";\n\nconst useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\nexport type EditorStateSnapshot<\n TEditor extends BlockNoteEditor<any, any, any> | null = BlockNoteEditor<\n any,\n any,\n any\n > | null,\n> = {\n editor: TEditor;\n transactionNumber: number;\n};\n\nexport type UseEditorStateOptions<\n TSelectorResult,\n TEditor extends BlockNoteEditor<any, any, any> | null = BlockNoteEditor<\n any,\n any,\n any\n > | null,\n> = {\n /**\n * The editor instance. If not provided, will use the editor from BlockNoteContext.\n */\n editor?: TEditor;\n\n /**\n * A selector function to determine the value to compare for re-rendering.\n */\n selector: (context: EditorStateSnapshot<TEditor>) => TSelectorResult;\n\n /**\n * A custom equality function to determine if the editor should re-render.\n * @default `deepEqual` from `fast-deep-equal`\n */\n equalityFn?: (a: TSelectorResult, b: TSelectorResult | null) => boolean;\n\n /**\n * The event to subscribe to.\n * @default \"all\"\n */\n on?: \"all\" | \"mount\" | \"selection\" | \"change\";\n};\n\n/**\n * To synchronize the editor instance with the component state,\n * we need to create a separate instance that is not affected by the component re-renders.\n */\nclass EditorStateManager<\n TEditor extends BlockNoteEditor<any, any, any> | null = BlockNoteEditor<\n any,\n any,\n any\n > | null,\n> {\n private transactionNumber = 0;\n\n private lastTransactionNumber = 0;\n\n private lastSnapshot: EditorStateSnapshot<TEditor>;\n\n private editor: TEditor;\n\n private subscribers = new Set<() => void>();\n\n constructor(initialEditor: TEditor) {\n this.editor = initialEditor;\n this.lastSnapshot = { editor: initialEditor, transactionNumber: 0 };\n\n this.getSnapshot = this.getSnapshot.bind(this);\n this.getServerSnapshot = this.getServerSnapshot.bind(this);\n this.watch = this.watch.bind(this);\n this.subscribe = this.subscribe.bind(this);\n }\n\n /**\n * Get the current editor instance.\n */\n getSnapshot(): EditorStateSnapshot<TEditor> {\n if (this.transactionNumber === this.lastTransactionNumber) {\n return this.lastSnapshot;\n }\n this.lastTransactionNumber = this.transactionNumber;\n this.lastSnapshot = {\n editor: this.editor,\n transactionNumber: this.transactionNumber,\n };\n return this.lastSnapshot;\n }\n\n /**\n * Always disable the editor on the server-side.\n */\n getServerSnapshot(): EditorStateSnapshot<null> {\n return { editor: null, transactionNumber: 0 };\n }\n\n /**\n * Subscribe to the editor instance's changes.\n */\n subscribe(callback: () => void): () => void {\n this.subscribers.add(callback);\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n /**\n * Watch the editor instance for changes.\n */\n watch(\n nextEditor: BlockNoteEditor<any, any, any> | null,\n on: \"all\" | \"mount\" | \"selection\" | \"change\",\n ): undefined | (() => void) {\n this.editor = nextEditor as TEditor;\n\n if (this.editor) {\n /**\n * This will force a re-render when the editor state changes.\n * This is to support things like `editor.can().toggleBold()` in components that `useEditor`.\n * This could be more efficient, but it's a good trade-off for now.\n */\n const fn = () => {\n this.transactionNumber += 1;\n this.subscribers.forEach((callback) => callback());\n };\n\n const currentTiptapEditor = this.editor._tiptapEditor;\n\n const EVENT_TYPES = {\n all: [\"transaction\", \"create\", \"mount\", \"unmount\"],\n // Listen for \"create\" as \"mount\" may fire before the hook is run.\n mount: [\"create\", \"mount\", \"unmount\"],\n selection: [\"selectionUpdate\"],\n change: [\"update\"],\n } as const;\n\n for (const eventType of EVENT_TYPES[on]) {\n currentTiptapEditor.on(eventType, fn);\n }\n\n return () => {\n for (const eventType of EVENT_TYPES[on]) {\n currentTiptapEditor.off(eventType, fn);\n }\n };\n }\n\n return undefined;\n }\n}\n\n/**\n * This hook allows you to watch for changes on the editor instance.\n * It will allow you to select a part of the editor state and re-render the component when it changes.\n * @example\n * ```tsx\n * const { currentSelection } = useEditorState({\n * selector: snapshot => ({ currentSelection: snapshot.editor?._tiptapEditor.state.selection }),\n * })\n * ```\n */\nexport function useEditorState<TSelectorResult>(\n options: UseEditorStateOptions<\n TSelectorResult,\n BlockNoteEditor<any, any, any>\n >,\n): TSelectorResult;\n/**\n * This hook allows you to watch for changes on the editor instance.\n * It will allow you to select a part of the editor state and re-render the component when it changes.\n * @example\n * ```tsx\n * const { currentSelection } = useEditorState({\n * selector: snapshot => ({ currentSelection: snapshot.editor?._tiptapEditor.state.selection }),\n * })\n * ```\n */\nexport function useEditorState<TSelectorResult>(\n options: UseEditorStateOptions<\n TSelectorResult,\n BlockNoteEditor<any, any, any> | null\n >,\n): TSelectorResult | null;\n\n/**\n * This hook allows you to watch for changes on the editor instance.\n * It will allow you to select a part of the editor state and re-render the component when it changes.\n * @example\n * ```tsx\n * const { currentSelection } = useEditorState({\n * selector: snapshot => ({ currentSelection: snapshot.editor?._tiptapEditor.state.selection }),\n * })\n * ```\n */\nexport function useEditorState<TSelectorResult>(\n options:\n | UseEditorStateOptions<TSelectorResult, BlockNoteEditor<any, any, any>>\n | UseEditorStateOptions<\n TSelectorResult,\n BlockNoteEditor<any, any, any> | null\n >,\n): TSelectorResult | null {\n const editorContext = useBlockNoteContext();\n const editor = options.editor || editorContext?.editor || null;\n const on = options.on || \"all\";\n\n const [editorStateManager] = useState(() => new EditorStateManager(editor));\n\n // Using the `useSyncExternalStore` hook to sync the editor instance with the component state\n const selectedState = useSyncExternalStoreWithSelector(\n editorStateManager.subscribe,\n editorStateManager.getSnapshot,\n editorStateManager.getServerSnapshot,\n options.selector as UseEditorStateOptions<\n TSelectorResult,\n BlockNoteEditor<any, any, any> | null\n >[\"selector\"],\n options.equalityFn ?? deepEqual,\n );\n\n useIsomorphicLayoutEffect(() => {\n return editorStateManager.watch(editor, on);\n }, [editor, editorStateManager, on]);\n\n useDebugValue(selectedState);\n\n return selectedState;\n}\n","import { BlockNoteEditor } from \"@blocknote/core\";\n\nimport { useBlockNoteContext } from \"../editor/BlockNoteContext.js\";\nimport { useEditorState } from \"./useEditorState.js\";\n\n// Returns the editor's DOM element reactively.\nexport function useEditorDOMElement(editor?: BlockNoteEditor<any, any, any>) {\n const editorContext = useBlockNoteContext();\n if (!editor) {\n editor = editorContext?.editor;\n }\n\n return useEditorState({\n editor,\n selector: (ctx) => ctx.editor?.domElement,\n equalityFn: (a, b) => a === b,\n on: \"mount\",\n });\n}\n","import { posToDOMRect } from \"@tiptap/core\";\nimport { ReactNode, useMemo } from \"react\";\n\nimport { useBlockNoteEditor } from \"../../hooks/useBlockNoteEditor.js\";\nimport { useEditorDOMElement } from \"../../hooks/useEditorDomElement.js\";\nimport { FloatingUIOptions } from \"./FloatingUIOptions.js\";\nimport { GenericPopover, GenericPopoverReference } from \"./GenericPopover.js\";\n\nexport const PositionPopover = (\n props: FloatingUIOptions & {\n position: { from: number; to?: number } | undefined;\n children: ReactNode;\n portalElement?: HTMLElement | null;\n },\n) => {\n const { position, children, portalElement, ...floatingUIOptions } = props;\n const { from, to } = position || {};\n\n const editor = useBlockNoteEditor<any, any, any>();\n const editorDOMElement = useEditorDOMElement();\n\n const reference = useMemo<GenericPopoverReference | undefined>(() => {\n if (from === undefined || to === undefined) {\n return undefined;\n }\n\n return {\n // Use first child as the editor DOM element may itself be scrollable.\n // For FloatingUI to auto-update the position during scrolling, the\n // `contextElement` must be a descendant of the scroll container.\n element: editorDOMElement?.firstElementChild || undefined,\n getBoundingClientRect: () =>\n posToDOMRect(editor.prosemirrorView, from, to ?? from),\n };\n }, [editor, editorDOMElement, from, to]);\n\n return (\n <GenericPopover\n reference={reference}\n portalElement={portalElement}\n {...floatingUIOptions}\n >\n {position !== undefined && children}\n </GenericPopover>\n );\n};\n","import {\n BlockNoteEditor,\n BlockNoteEditorOptions,\n CustomBlockNoteSchema,\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema,\n} from \"@blocknote/core\";\nimport { DependencyList, useMemo } from \"react\";\n\n/**\n * Hook to instantiate a BlockNote Editor instance in React\n */\nexport const useCreateBlockNote = <\n Options extends Partial<BlockNoteEditorOptions<any, any, any>> | undefined,\n>(\n options: Options = {} as Options,\n deps: DependencyList = [],\n): Options extends {\n schema: CustomBlockNoteSchema<infer BSchema, infer ISchema, infer SSchema>;\n}\n ? BlockNoteEditor<BSchema, ISchema, SSchema>\n : BlockNoteEditor<\n DefaultBlockSchema,\n DefaultInlineContentSchema,\n DefaultStyleSchema\n > => {\n return useMemo(() => {\n const editor = BlockNoteEditor.create(options) as any;\n if (window) {\n // for testing / dev purposes\n (window as any).ProseMirror = editor._tiptapEditor;\n }\n return editor;\n }, deps); //eslint-disable-line react-hooks/exhaustive-deps\n};\n","import { BlockNoteEditor } from \"@blocknote/core\";\nimport { ReactNode, useCallback, useEffect, useState } from \"react\";\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useEditorState } from \"../../hooks/useEditorState.js\";\n\n/**\n * The CommentEditor component displays an editor for creating or editing a comment.\n * Currently, we also use the non-editable version for displaying a comment.\n *\n * It's used:\n * - to create a new comment (FloatingComposer.tsx)\n * - As the last item in a Thread, to compose a reply (Thread.tsx)\n * - To edit or display an existing comment (Comment.tsx)\n *\n */\nexport const CommentEditor = (props: {\n autoFocus?: boolean;\n editable: boolean;\n actions?: (args: { isFocused: boolean; isEmpty: boolean }) => ReactNode;\n editor: BlockNoteEditor<any, any, any>;\n}) => {\n const [isFocused, setIsFocused] = useState(false);\n const isEmpty = useEditorState({\n editor: props.editor,\n selector: ({ editor }) => editor.isEmpty,\n });\n\n const components = useComponentsContext()!;\n\n const onFocus = useCallback(() => {\n setIsFocused(true);\n }, []);\n\n const onBlur = useCallback(() => {\n setIsFocused(false);\n }, []);\n\n // When we click the edit button on a comment, we also want to focus the\n // comment editor\n useEffect(() => {\n if (props.editable && props.autoFocus) {\n props.editor.focus();\n }\n }, [props.autoFocus, props.editable, props.editor]);\n\n return (\n <>\n <components.Comments.Editor\n autoFocus={props.autoFocus}\n className=\"bn-comment-editor\"\n editor={props.editor}\n onFocus={onFocus}\n onBlur={onBlur}\n editable={props.editable}\n />\n {props.actions && (\n <div className={\"bn-comment-actions-wrapper\"}>\n {props.actions({ isFocused, isEmpty })}\n </div>\n )}\n </>\n );\n};\n","import { BlockNoteSchema, defaultStyleSpecs } from \"@blocknote/core\";\nimport { createParagraphBlockSpec } from \"@blocknote/core\";\n\n// this is quite convoluted. we'll clean this up when we make\n// it easier to extend / customize the default blocks\n\n// remove textColor, backgroundColor from styleSpecs\nconst { textColor, backgroundColor, ...styleSpecs } = defaultStyleSpecs;\n\n// the schema to use for comments\nexport const defaultCommentEditorSchema = BlockNoteSchema.create({\n blockSpecs: {\n paragraph: createParagraphBlockSpec(),\n },\n styleSpecs,\n});\n"],"mappings":"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"}