{"version":3,"file":"BlockNoteExtension-M0znTzxP.cjs","names":[],"sources":["../src/schema/markGroups.ts","../src/editor/managers/ExtensionManager/symbol.ts","../src/editor/BlockNoteExtension.ts"],"sourcesContent":["import { Editor, getExtensionField } from \"@tiptap/core\";\n\n/**\n * ProseMirror mark group for \"non-formatting\" marks: comments and the\n * suggestion/diff marks (the AI `insertion`/`deletion`/`modification` marks and\n * the Yjs `y-attributed-*` marks). These annotate content without representing\n * inline formatting and are ignored by BlockNote's content model\n * (`blocknoteIgnore`).\n *\n * They are the only marks allowed on `\"plain\"` blocks (e.g. code blocks), which\n * otherwise disallow all formatting marks. A block references this group rather\n * than the individual marks because each of them comes from an optional\n * extension (comments, AI suggestions, Yjs attribution) and so is only present\n * when that extension is configured.\n */\nexport const NON_FORMATTING_MARK_GROUP = \"annotation\";\n\n/**\n * The `marks` field value for `\"plain\"` blocks (e.g. code blocks), which hold\n * unstyled text and so disallow formatting marks but still allow the\n * non-formatting ones.\n *\n * Every mark in {@link NON_FORMATTING_MARK_GROUP} comes from an optional\n * extension, so a node spec that referenced the group unconditionally would make\n * ProseMirror throw \"Unknown mark type: 'annotation'\" while building the schema\n * of an editor that has none of them registered — an empty mark group is an\n * unknown reference just like a missing mark is. (This mirrors `suggestionMarks`\n * for the block-level suggestion group.)\n *\n * Returns the group name (which ProseMirror expands to every mark in it) when at\n * least one such mark is registered, or `\"\"` otherwise. Evaluated at\n * schema-build time, where the tiptap editor's fully-flattened extension list is\n * available on `this.editor`.\n */\nexport function nonFormattingMarks(editor: Editor | undefined): string {\n  if (!editor) {\n    return \"\";\n  }\n  const hasNonFormattingMark = editor.options.extensions.some((extension) => {\n    if (extension.type !== \"mark\") {\n      return false;\n    }\n    const group = getExtensionField(extension, \"group\") as string | undefined;\n    return (\n      typeof group === \"string\" &&\n      group.split(\" \").includes(NON_FORMATTING_MARK_GROUP)\n    );\n  });\n  return hasNonFormattingMark ? NON_FORMATTING_MARK_GROUP : \"\";\n}\n","/**\n * Symbol used to track the original factory function for extensions.\n * This allows us to retrieve the original factory for comparison and other operations.\n */\nexport const originalFactorySymbol = Symbol(\"originalFactory\");\n","import { Store, StoreOptions } from \"@tanstack/store\";\nimport { type AnyExtension } from \"@tiptap/core\";\nimport type { Plugin as ProsemirrorPlugin } from \"prosemirror-state\";\nimport type { PartialBlockNoDefaults } from \"../schema/index.js\";\nimport type { BlockNoteEditor } from \"./BlockNoteEditor.js\";\nimport { originalFactorySymbol } from \"./managers/ExtensionManager/symbol.js\";\n\n/**\n * This function is called when the extension is destroyed.\n */\ntype OnDestroy = () => void;\n\n/**\n * Describes a BlockNote extension.\n */\nexport interface Extension<State = any, Key extends string = string> {\n  /**\n   * The unique identifier for the extension.\n   */\n  readonly key: Key;\n\n  /**\n   * Triggered when the extension is mounted to the editor.\n   */\n  readonly mount?: (ctx: {\n    /**\n     * The DOM element that the editor is mounted to.\n     */\n    dom: HTMLElement;\n    /**\n     * The root document of the {@link document} that the editor is mounted to.\n     */\n    root: Document | ShadowRoot;\n    /**\n     * An {@link AbortSignal} that will be aborted when the extension is destroyed.\n     */\n    signal: AbortSignal;\n  }) => void | OnDestroy;\n\n  /**\n   * The store for the extension.\n   */\n  readonly store?: Store<State>;\n\n  /**\n   * Declares what {@link Extension}s that this extension depends on.\n   */\n  readonly runsBefore?: ReadonlyArray<string>;\n\n  /**\n   * Input rules for a block: An input rule is what is used to replace text in a block when a regular expression match is found.\n   * As an example, typing `#` in a paragraph block will trigger an input rule to replace the text with a heading block.\n   */\n  readonly inputRules?: ReadonlyArray<InputRule>;\n\n  /**\n   * A mapping of a keyboard shortcut to a function that will be called when the shortcut is pressed\n   *\n   * The keys are in the format:\n   * - Key names may be strings like `Shift-Ctrl-Enter`—a key identifier prefixed with zero or more modifiers\n   * - Key identifiers are based on the strings that can appear in KeyEvent.key\n   * - Use lowercase letters to refer to letter keys (or uppercase letters if you want shift to be held)\n   * - You may use `Space` as an alias for the \" \" name\n   * - Modifiers can be given in any order: `Shift-` (or `s-`), `Alt-` (or `a-`), `Ctrl-` (or `c-` or `Control-`) and `Cmd-` (or `m-` or `Meta-`)\n   * - For characters that are created by holding shift, the Shift- prefix is implied, and should not be added explicitly\n   * - You can use Mod- as a shorthand for Cmd- on Mac and Ctrl- on other platforms\n   *\n   * @example\n   * ```typescript\n   * keyboardShortcuts: {\n   *   \"Mod-Enter\": (ctx) => {  return true; },\n   *   \"Shift-Ctrl-Space\": (ctx) => { return true; },\n   *   \"a\": (ctx) => { return true; },\n   *   \"Space\": (ctx) => { return true; }\n   * }\n   * ```\n   */\n  readonly keyboardShortcuts?: Record<\n    string,\n    (ctx: { editor: BlockNoteEditor<any, any, any> }) => boolean\n  >;\n\n  /**\n   * Add additional prosemirror plugins to the editor.\n   */\n  readonly prosemirrorPlugins?: ReadonlyArray<ProsemirrorPlugin>;\n\n  /**\n   * Add additional tiptap extensions to the editor.\n   */\n  readonly tiptapExtensions?: ReadonlyArray<AnyExtension>;\n\n  /**\n   * Add additional BlockNote extensions to the editor.\n   */\n  readonly blockNoteExtensions?: ReadonlyArray<ExtensionFactoryInstance>;\n}\n\n/**\n * An input rule is what is used to replace text in a block when a regular expression match is found.\n * As an example, typing `#` in a paragraph block will trigger an input rule to replace the text with a heading block.\n */\ntype InputRule = {\n  /**\n   * The regex to match when to trigger the input rule\n   */\n  find: RegExp;\n  /**\n   * The function to call when the input rule is matched\n   * @returns undefined if the input rule should not be triggered, or an object with the type and props to update the block\n   */\n  replace: (props: {\n    /**\n     * The result of the regex match\n     */\n    match: RegExpMatchArray;\n    // TODO this will be a Point, when we have the Location API\n    /**\n     * The range of the text that was matched\n     */\n    range: { from: number; to: number };\n    /**\n     * The editor instance\n     */\n    editor: BlockNoteEditor<any, any, any>;\n  }) => undefined | PartialBlockNoDefaults<any, any, any>;\n};\n\n/**\n * These are the arguments that are passed to an {@link ExtensionFactoryInstance}.\n */\nexport interface ExtensionOptions<\n  Options extends Record<string, any> | undefined =\n    | Record<string, any>\n    | undefined,\n> {\n  options: Options;\n  editor: BlockNoteEditor<any, any, any>;\n}\n\n// a type that maps the extension key to the return type of the extension factory\nexport type ExtensionMap<T extends ReadonlyArray<ExtensionFactoryInstance>> = {\n  [K in T[number] extends ExtensionFactoryInstance<infer Ext>\n    ? Ext[\"key\"]\n    : never]: T[number] extends ExtensionFactoryInstance<infer Ext>\n    ? Ext\n    : never;\n};\n\n/**\n * This is a type that represents the function which will actually create the extension.\n * It requires the editor instance to be passed in, but will already have the options applied automatically.\n *\n * @note Only the BlockNoteEditor should instantiate this function, not the user. Look at {@link createExtension} for user-facing functions.\n */\nexport type ExtensionFactoryInstance<\n  Ext extends Extension<any, any> = Extension<any, any>,\n> = (ctx: Omit<ExtensionOptions<any>, \"options\">) => Ext;\n\n/**\n * This is the return type of the {@link createExtension} function.\n * It is a function that can be invoked with the extension's options to create a new extension factory.\n */\nexport type ExtensionFactory<\n  State = any,\n  Key extends string = string,\n  Factory extends (ctx: any) => Extension<State, Key> = (\n    ctx: ExtensionOptions<any>,\n  ) => Extension<State, Key>,\n> =\n  Parameters<Factory>[0] extends ExtensionOptions<infer Options>\n    ? undefined extends Options\n      ? (\n          options?: Exclude<Options, undefined>,\n        ) => ExtensionFactoryInstance<ReturnType<Factory>>\n      : (options: Options) => ExtensionFactoryInstance<ReturnType<Factory>>\n    : () => ExtensionFactoryInstance<ReturnType<Factory>>;\n\n/**\n * Constructs a BlockNote {@link ExtensionFactory} from a factory function or object\n */\n// This overload is for `createExtension({ key: \"test\", ... })`\nexport function createExtension<\n  const State = any,\n  const Key extends string = string,\n  const Ext extends Extension<State, Key> = Extension<State, Key>,\n>(factory: Ext): ExtensionFactoryInstance<Ext>;\n// This overload is for `createExtension(({editor, options}) => ({ key: \"test\", ... }))`\nexport function createExtension<\n  const State = any,\n  const Options extends Record<string, any> | undefined = any,\n  const Key extends string = string,\n  const Factory extends (ctx: any) => Extension<State, Key> = (\n    ctx: ExtensionOptions<Options>,\n  ) => Extension<State, Key>,\n>(factory: Factory): ExtensionFactory<State, Key, Factory>;\n// This overload is for both of the above overloads as it is the implementation of the function\nexport function createExtension<\n  const State = any,\n  const Options extends Record<string, any> | undefined = any,\n  const Key extends string = string,\n  const Factory extends\n    | Extension<State, Key>\n    | ((ctx: any) => Extension<State, Key>) = (\n    ctx: ExtensionOptions<Options>,\n  ) => Extension<State, Key>,\n>(\n  factory: Factory,\n): Factory extends Extension<State, Key>\n  ? ExtensionFactoryInstance<Factory>\n  : Factory extends (ctx: any) => Extension<State, Key>\n    ? ExtensionFactory<State, Key, Factory>\n    : never {\n  if (typeof factory === \"object\" && \"key\" in factory) {\n    return function factoryFn() {\n      (factory as any)[originalFactorySymbol] = factoryFn;\n      return factory;\n    } as any;\n  }\n\n  if (typeof factory !== \"function\") {\n    throw new Error(\"factory must be a function\");\n  }\n\n  return function factoryFn(options: Options) {\n    return (ctx: { editor: BlockNoteEditor<any, any, any> }) => {\n      const extension = factory({ editor: ctx.editor, options });\n      // We stick a symbol onto the extension to allow us to retrieve the original factory for comparison later.\n      // This enables us to do things like: `editor.getExtension(YSync).prosemirrorPlugins`\n      (extension as any)[originalFactorySymbol] = factoryFn;\n      return extension;\n    };\n  } as any;\n}\n\nexport function createStore<T = any>(\n  initialState: T,\n  options?: StoreOptions<T>,\n): Store<T> {\n  return new Store(initialState, options);\n}\n"],"mappings":"2DAeA,IAAa,EAA4B,aAmBzC,SAAgB,EAAmB,EAAoC,CAcrE,OAbK,GAGwB,EAAO,QAAQ,WAAW,KAAM,GAAc,CACzE,GAAI,EAAU,OAAS,OACrB,MAAO,GAET,IAAM,GAAA,EAAA,EAAA,mBAA0B,EAAW,OAAO,EAClD,OACE,OAAO,GAAU,UACjB,EAAM,MAAM,GAAG,EAAE,SAAA,YAAkC,CAEvD,CACO,EAAuB,EAA4B,EAC5D,CC7CA,IAAa,EAAwB,OAAO,iBAAiB,ECiM7D,SAAgB,EAUd,EAKU,CACV,GAAI,OAAO,GAAY,UAAY,QAAS,EAC1C,OAAO,SAAS,GAAY,CAE1B,MADA,GAAiB,GAAyB,EACnC,CACT,EAGF,GAAI,OAAO,GAAY,WACrB,MAAU,MAAM,4BAA4B,EAG9C,OAAO,SAAS,EAAU,EAAkB,CAC1C,MAAQ,IAAoD,CAC1D,IAAM,EAAY,EAAQ,CAAE,OAAQ,EAAI,OAAQ,SAAQ,CAAC,EAIzD,MADA,GAAmB,GAAyB,EACrC,CACT,CACF,CACF,CAEA,SAAgB,EACd,EACA,EACU,CACV,OAAO,IAAI,EAAA,MAAM,EAAc,CAAO,CACxC"}