{"version":3,"file":"BlockNoteExtension-ab0REuob.cjs","names":[],"sources":["../src/editor/managers/ExtensionManager/symbol.ts","../src/editor/BlockNoteExtension.ts"],"sourcesContent":["/**\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":"+fAIA,IAAa,EAAwB,OAAO,kBAAkB,CCiM9D,SAAgB,EAUd,EAKU,CACV,GAAI,OAAO,GAAY,UAAY,QAAS,EAC1C,OAAO,SAAS,GAAY,CAE1B,MADC,GAAgB,GAAyB,EACnC,GAIX,GAAI,OAAO,GAAY,WACrB,MAAU,MAAM,6BAA6B,CAG/C,OAAO,SAAS,EAAU,EAAkB,CAC1C,MAAQ,IAAoD,CAC1D,IAAM,EAAY,EAAQ,CAAE,OAAQ,EAAI,OAAQ,UAAS,CAAC,CAI1D,MADC,GAAkB,GAAyB,EACrC,IAKb,SAAgB,EACd,EACA,EACU,CACV,OAAO,IAAI,EAAA,MAAM,EAAc,EAAQ"}