{"version":3,"file":"BlockNoteExtension-BJCLnwrE.cjs","names":[],"sources":["../src/schema/markGroups.ts","../src/util/Store.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","// Vendored from https://github.com/TanStack/store/blob/main/packages/store/src/store.ts (MIT)\n//\n// BlockNote only ever used `Store` — never the `Derived`/`Effect` reactive graph that\n// makes up the rest of `@tanstack/store`, and that graph isn't tree-shakeable because\n// `setState` reaches into the scheduler. Since the `Store` type is part of BlockNote's\n// public API (every extension exposes one), owning these ~40 lines lets us keep that\n// surface stable instead of tracking a 0.x dependency's breaking changes.\n//\n// Behaviour matches `@tanstack/store@0.7.7`, minus the dependency graph and the\n// `updateFn`/`onSubscribe` options, which nothing used. `onUpdate` additionally receives\n// the new and previous state rather than requiring callers to close over the store.\n\n/**\n * The value a {@link Listener} is called with when a {@link Store} updates.\n */\nexport interface ListenerValue<T> {\n  readonly prevVal: T;\n  readonly currentVal: T;\n}\n\n/**\n * A callback invoked when a {@link Store}'s state changes.\n */\nexport type Listener<T> = (value: ListenerValue<T>) => void;\n\n/**\n * A new state, or a function deriving it from the previous state.\n */\nexport type Updater<T> = T | ((prev: T) => T);\n\nexport interface StoreOptions<TState> {\n  /**\n   * Called after the state has been updated, before listeners are notified.\n   */\n  onUpdate?: (state: TState, prevState: TState) => void;\n}\n\n/**\n * A minimal observable state container.\n *\n * Extensions expose one of these as their `store` so that both React (via\n * `useExtensionState`) and vanilla consumers can read and subscribe to their state.\n */\nexport class Store<TState> {\n  listeners = new Set<Listener<TState>>();\n  state: TState;\n  prevState: TState;\n  options?: StoreOptions<TState>;\n\n  constructor(initialState: TState, options?: StoreOptions<TState>) {\n    this.prevState = initialState;\n    this.state = initialState;\n    this.options = options;\n  }\n\n  subscribe = (listener: Listener<TState>) => {\n    this.listeners.add(listener);\n\n    return () => {\n      this.listeners.delete(listener);\n    };\n  };\n\n  /**\n   * Update the store state, either with a new state or a function deriving it from the\n   * previous one.\n   */\n  setState(updater: (prevState: TState) => TState): void;\n  setState(updater: TState): void;\n  setState(updater: Updater<TState>): void {\n    this.prevState = this.state;\n    this.state = isUpdaterFunction(updater) ? updater(this.prevState) : updater;\n\n    flush(this);\n  }\n\n  /**\n   * @internal Only to be called by {@link flush}.\n   */\n  _notify() {\n    const value: ListenerValue<TState> = {\n      prevVal: this.prevState,\n      currentVal: this.state,\n    };\n    for (const listener of this.listeners) {\n      listener(value);\n    }\n  }\n}\n\nfunction isUpdaterFunction<T>(updater: Updater<T>): updater is (prev: T) => T {\n  return typeof updater === \"function\";\n}\n\n// Both `onUpdate` and listener notification can synchronously trigger further `setState`\n// calls — a callback that dispatches a ProseMirror transaction, for example. Rather than\n// recursing, re-entrant writes are queued and drained by the outermost flush, so a write\n// made during a callback still reaches every listener but the stack stays flat and\n// subscribers see the settled state once.\n//\n// `onUpdate` therefore runs *inside* the flush transaction: the store is queued and the\n// flush is marked in progress before the callback fires, so a nested write it makes is\n// coalesced into this drain rather than starting its own.\nlet isFlushing = false;\nconst pendingUpdates = new Set<Store<any>>();\n\nfunction flush(store: Store<any>) {\n  pendingUpdates.add(store);\n\n  const isOutermost = !isFlushing;\n  isFlushing = true;\n\n  try {\n    store.options?.onUpdate?.(store.state, store.prevState);\n\n    if (!isOutermost) {\n      return;\n    }\n\n    while (pendingUpdates.size > 0) {\n      const stores = Array.from(pendingUpdates);\n      pendingUpdates.clear();\n      for (const pendingStore of stores) {\n        pendingStore._notify();\n      }\n    }\n  } finally {\n    if (isOutermost) {\n      isFlushing = false;\n      // A throwing callback would otherwise strand queued stores, letting them notify\n      // during an unrelated store's next flush.\n      pendingUpdates.clear();\n    }\n  }\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 { type AnyExtension } from \"@tiptap/core\";\nimport type { Plugin as ProsemirrorPlugin } from \"prosemirror-state\";\nimport type { PartialBlockNoDefaults } from \"../schema/index.js\";\nimport { Store, StoreOptions } from \"../util/Store.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":"8BAeA,IAAa,EAA4B,aAmBzC,SAAgB,EAAmB,EAAoC,CAcrE,OAbK,GAGwB,EAAO,QAAQ,WAAW,KAAM,GAAc,CACzE,GAAI,EAAU,OAAS,OACrB,MAAO,GAET,IAAM,GAAA,EAAQ,EAAA,kBAAA,CAAkB,EAAW,OAAO,EAClD,OACE,OAAO,GAAU,UACjB,EAAM,MAAM,GAAG,CAAC,CAAC,SAAA,YAAkC,CAEvD,CACO,EAAuB,EAA4B,EAC5D,CCNA,IAAa,EAAb,KAA2B,CACzB,UAAY,IAAI,IAChB,MACA,UACA,QAEA,YAAY,EAAsB,EAAgC,CAChE,KAAK,UAAY,EACjB,KAAK,MAAQ,EACb,KAAK,QAAU,CACjB,CAEA,UAAa,IACX,KAAK,UAAU,IAAI,CAAQ,MAEd,CACX,KAAK,UAAU,OAAO,CAAQ,CAChC,GASF,SAAS,EAAgC,CACvC,KAAK,UAAY,KAAK,MACtB,KAAK,MAAQ,EAAkB,CAAO,EAAI,EAAQ,KAAK,SAAS,EAAI,EAEpE,EAAM,IAAI,CACZ,CAKA,SAAU,CACR,IAAM,EAA+B,CACnC,QAAS,KAAK,UACd,WAAY,KAAK,KACnB,EACA,IAAK,IAAM,KAAY,KAAK,UAC1B,EAAS,CAAK,CAElB,CACF,EAEA,SAAS,EAAqB,EAAgD,CAC5E,OAAO,OAAO,GAAY,UAC5B,CAWA,IAAI,EAAa,GACX,EAAiB,IAAI,IAE3B,SAAS,EAAM,EAAmB,CAChC,EAAe,IAAI,CAAK,EAExB,IAAM,EAAc,CAAC,EACrB,EAAa,GAEb,GAAI,CAGF,GAFA,EAAM,SAAS,WAAW,EAAM,MAAO,EAAM,SAAS,EAElD,CAAC,EACH,OAGF,KAAO,EAAe,KAAO,GAAG,CAC9B,IAAM,EAAS,MAAM,KAAK,CAAc,EACxC,EAAe,MAAM,EACrB,IAAK,IAAM,KAAgB,EACzB,EAAa,QAAQ,CAEzB,CACF,QAAU,CACJ,IACF,EAAa,GAGb,EAAe,MAAM,EAEzB,CACF,CClIA,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,EAAM,EAAc,CAAO,CACxC"}