@remirror/core
Version:
Where your quest to create a world class editing experience begins.
4 lines • 443 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/index.ts", "../src/builtins/attributes-extension.ts", "../src/extension/extension.ts", "../src/extension/base-class.ts", "../src/helpers.ts", "../src/extension/extension-decorator.ts", "../src/builtins/builtin-decorators.ts", "../src/builtins/builtin-preset.ts", "../src/builtins/commands-extension.ts", "../src/commands.ts", "../src/builtins/decorations-extension.ts", "../src/builtins/doc-changed-extension.ts", "../src/builtins/helpers-extension.ts", "../src/builtins/input-rules-extension.ts", "../src/builtins/keymap-extension.ts", "../src/builtins/node-views-extension.ts", "../src/builtins/paste-rules-extension.ts", "../src/builtins/plugins-extension.ts", "../src/builtins/schema-extension.ts", "../src/builtins/suggest-extension.ts", "../src/builtins/tags-extension.ts", "../src/builtins/upload-extension/file-placeholder-plugin.ts", "../src/builtins/upload-extension/file-upload.ts", "../src/builtins/upload-extension/upload-context.ts", "../src/builtins/upload-extension/upload-extension.ts", "../src/builtins/meta-extension.ts", "../src/framework/framework.ts", "../src/manager/remirror-manager.ts", "../src/manager/remirror-manager-helpers.ts"],
"sourcesContent": ["export * from './builtins';\nexport type { DelayedPromiseCreator, DelayedValue } from './commands';\nexport { DelayedCommand, delayedCommand, insertText, isDelayedValue, toggleMark } from './commands';\nexport * from './extension';\nexport type {\n AddCustomHandler,\n AddHandler,\n CustomHandlerMethod,\n HandlerKeyOptions,\n} from './extension/base-class';\nexport type {\n AttributePropFunction,\n BaseFramework,\n CreateStateFromContent,\n FrameworkOptions,\n FrameworkOutput,\n FrameworkProps,\n ListenerProps,\n PlaceholderConfig,\n RemirrorEventListener,\n RemirrorEventListenerProps,\n TriggerChangeProps,\n UpdateStateProps,\n} from './framework';\nexport { Framework } from './framework';\nexport type { AnyRemirrorManager, CreateEditorStateProps, ManagerEvents } from './manager';\nexport { isRemirrorManager, RemirrorManager } from './manager';\nexport type {\n AppendLifecycleProps,\n ApplyStateLifecycleProps,\n BaseExtensionOptions,\n ChangedOptions,\n CommandShape,\n CreateExtensionPlugin,\n DynamicOptionsOfConstructor,\n ExcludeOptions,\n ExtensionCommandFunction,\n ExtensionCommandReturn,\n ExtensionHelperReturn,\n ExtensionStore,\n FocusType,\n GetChangeOptionsReturn,\n GetCommands,\n GetConstructor,\n GetHelpers,\n GetOptions,\n OnSetOptionsProps,\n OptionsOfConstructor,\n PickChanged,\n StateUpdateLifecycleProps,\n TypedPropertyDescriptor,\n UpdateReason,\n UpdateReasonProps,\n} from './types';\nexport * from '@remirror/core-constants';\nexport * from '@remirror/core-helpers';\nexport * from '@remirror/core-types';\nexport * from '@remirror/core-utils';\nexport type { CoreIcon } from '@remirror/icons';\n", "import type { ClassName } from '@linaria/core/types/cx';\nimport { cx, object } from '@remirror/core-helpers';\nimport type { ProsemirrorAttributes } from '@remirror/core-types';\n\nimport { AnyExtension, PlainExtension } from '../extension';\n\n/**\n * This extension allows others extension to add the `createAttributes` method\n * for adding attributes to the prosemirror dom element.\n *\n * @remarks\n *\n * Use this to include all the dynamically generated attributes provided by each\n * extension. High priority extensions have preference over the lower priority\n * extensions.\n *\n * @category Builtin Extension\n */\nexport class AttributesExtension extends PlainExtension {\n get name() {\n return 'attributes' as const;\n }\n\n private attributeList: ProsemirrorAttributes[] = [];\n private attributeObject: ProsemirrorAttributes = object();\n\n /**\n * Create the attributes object on initialization.\n *\n * @internal\n */\n onCreate(): void {\n this.transformAttributes();\n this.store.setExtensionStore('updateAttributes', this.updateAttributes);\n }\n\n private readonly updateAttributes = (triggerUpdate = true) => {\n this.transformAttributes();\n\n if (triggerUpdate) {\n this.store.commands.forceUpdate('attributes');\n }\n };\n\n private transformAttributes() {\n this.attributeObject = object();\n\n // Exit early when the manager excludes these settings.\n if (this.store.managerSettings.exclude?.attributes) {\n this.store.setStoreKey('attributes', this.attributeObject);\n return;\n }\n\n // Reset this attributes\n this.attributeList = [];\n\n for (const extension of this.store.extensions) {\n if (extension.options.exclude?.attributes) {\n continue;\n }\n\n const createdAttributes = extension.createAttributes?.();\n const attributes = {\n ...createdAttributes,\n class: cx(...(extension.classNames ?? []), createdAttributes?.class),\n };\n\n // Inserted at the start of the list so that when combining the full\n // attribute object the higher priority extension attributes are\n // preferred to the lower priority since they merge with the object\n // later.\n this.attributeList.unshift(attributes);\n }\n\n for (const attributes of this.attributeList) {\n this.attributeObject = {\n ...this.attributeObject,\n ...attributes,\n class: cx(this.attributeObject.class, attributes.class),\n };\n }\n\n this.store.setStoreKey('attributes', this.attributeObject);\n }\n}\n\ndeclare global {\n namespace Remirror {\n interface ManagerStore<Extension extends AnyExtension> {\n /**\n * The attributes to be added to the prosemirror editor.\n */\n attributes: ProsemirrorAttributes;\n }\n\n interface ExtensionStore {\n /**\n * Triggers a recalculation of the `view.dom` attributes for each\n * extension and notifies the parent UI once done.\n *\n * This will also dispatch an update to the state automatically. However\n * you can disable this by setting `triggerUpdate` to `false`.\n *\n * By not triggering an update the new value may not be capture by the view layer, e.g. `React`.\n *\n * @param triggerUpdate - defaults to true\n */\n updateAttributes: (triggerUpdate?: boolean) => void;\n }\n\n interface ExcludeOptions {\n /**\n * Whether to use the attributes provided by this extension\n *\n * @defaultValue undefined\n */\n attributes?: boolean;\n }\n\n interface BaseExtension {\n /**\n * A list of class names to add to the main editor element.\n */\n classNames?: ClassName[];\n\n /**\n * Allows the extension to modify the attributes for the Prosemirror editor\n * dom element.\n *\n * @remarks\n *\n * Sometimes an extension will need to make a change to the attributes of the\n * editor itself. For example a placeholder may need to do some work to make\n * the editor more accessible by setting the `aria-placeholder` value to match\n * the value of the placeholder.\n *\n * @alpha\n */\n createAttributes?(): ProsemirrorAttributes;\n }\n\n interface AllExtensions {\n attributes: AttributesExtension;\n }\n }\n}\n", "/* eslint-disable @typescript-eslint/member-ordering */\n\nimport {\n __INTERNAL_REMIRROR_IDENTIFIER_KEY__,\n ErrorConstant,\n ExtensionPriority,\n RemirrorIdentifier,\n} from '@remirror/core-constants';\nimport { assertGet, freeze, invariant, pascalCase, uniqueBy } from '@remirror/core-helpers';\nimport type {\n ApplySchemaAttributes,\n Dispose,\n EditorState,\n EditorView,\n EmptyShape,\n MarkExtensionSpec,\n MarkSpecOverride,\n MarkType,\n NodeExtensionSpec,\n NodeSpecOverride,\n NodeType,\n Replace,\n Shape,\n ValidOptions,\n} from '@remirror/core-types';\nimport { isIdentifierOfType, isRemirrorType } from '@remirror/core-utils';\n\nimport type {\n AppendLifecycleProps,\n ApplyStateLifecycleProps,\n BaseExtensionOptions,\n ExtensionCommandReturn,\n ExtensionHelperReturn,\n StateUpdateLifecycleProps,\n} from '../types';\nimport {\n AnyBaseClassOverrides,\n BaseClass,\n BaseClassConstructor,\n ConstructorProps,\n DefaultOptions,\n} from './base-class';\n\n/**\n * Auto infers the parameter for the constructor. If there is a required static\n * option then the TypeScript compiler will error if nothing is passed in.\n */\nexport type ExtensionConstructorProps<Options extends ValidOptions> = ConstructorProps<\n Options,\n BaseExtensionOptions\n>;\n\n/**\n * Extensions are fundamental to the way that Remirror works by grouping\n * together the functionality and handling the management of similar concerns.\n *\n * @remarks\n *\n * Extension can adjust editor functionality in any way. Here are some\n * examples.\n *\n * - How the editor displays certain content, i.e. **bold**, _italic_,\n * **underline**.\n * - Which commands should be made available e.g. `commands.toggleBold()` to\n * toggle the weight of the selected text.\n * - Check if a command is currently enabled (i.e a successful dry run) e.g.\n * `commands.toggleBold.isEnabled()`.\n * - Register Prosemirror `Plugin`s, `keymap`s, `InputRule`s `PasteRule`s,\n * `Suggestions`, and custom `nodeViews` which affect the behavior of the\n * editor.\n *\n * There are three types of `Extension`.\n *\n * - `NodeExtension` - For creating Prosemirror nodes in the editor. See\n * {@link NodeExtension}\n * - `MarkExtension` - For creating Prosemirror marks in the editor. See\n * {@link MarkExtension}\n * - `PlainExtension` - For behavior which doesn't map to a `ProsemirrorNode` or\n * `Mark` and as a result doesn't directly affect the Prosemirror `Schema` or\n * content. See {@link PlainExtension}.\n *\n * This `Extension` is an abstract class that should not be used directly but\n * rather extended to add the intended functionality.\n *\n * ```ts\n * import { PlainExtension, Static } from 'remirror';\n *\n * interface AwesomeExtensionOptions {\n * isAwesome?: Static<boolean>;\n * id?: string;\n * }\n *\n * class AwesomeExtension extends PlainExtension<AwesomeExtensionOptions> {\n * static defaultOptions: DefaultExtensionOptions<AwesomeExtensionOptions> = {\n * isAwesome: true,\n * id: '',\n * }\n *\n * get name() {\n * return 'awesome' as const;\n * }\n * }\n * ```\n */\nabstract class Extension<Options extends ValidOptions = EmptyShape> extends BaseClass<\n Options,\n BaseExtensionOptions\n> {\n /**\n * The default priority for this family of extensions.\n */\n static readonly defaultPriority: ExtensionPriority = ExtensionPriority.Default;\n\n /**\n * Allows for the `RemirrorManager` or `Preset`'s to override the priority of\n * an extension.\n */\n private priorityOverride?: ExtensionPriority;\n\n /**\n * The priority level for this instance of the extension. A higher value\n * corresponds to a higher priority extension\n */\n get priority(): ExtensionPriority {\n return this.priorityOverride ?? this.options.priority ?? this.constructor.defaultPriority;\n }\n\n /**\n * The name that the constructor should have, which doesn't get mangled in\n * production.\n */\n get constructorName(): string {\n return `${pascalCase(this.name)}Extension`;\n }\n\n /**\n * The store is a shared object that's internal to each extension. It includes\n * often used items like the `view` and `schema` that are added by the\n * extension manager and also the lifecycle extension methods.\n *\n * **NOTE** - The store is not available until the manager has been created\n * and received the extension. As a result trying to access the store during\n * `init` and `constructor` will result in a runtime error.\n *\n * Some properties of the store are available at different phases. You should\n * check the inline documentation to know when a certain property is useable\n * in your extension.\n */\n protected get store(): Remirror.ExtensionStore {\n invariant(this._store, {\n code: ErrorConstant.MANAGER_PHASE_ERROR,\n message: `An error occurred while attempting to access the 'extension.store' when the Manager has not yet set created the lifecycle methods.`,\n });\n\n return freeze(this._store, { requireKeys: true });\n }\n\n /**\n * The list of extensions added to the editor by this `Preset`.\n */\n get extensions(): Array<this['~E']> {\n return this._extensions;\n }\n /**\n * Private list of extension stored within this [[`Preset`]].\n */\n private _extensions: Array<this['~E']>;\n\n /**\n * An extension mapping of the extensions and their constructors.\n */\n private readonly extensionMap: Map<this['~E']['constructor'], this['~E']>;\n\n /**\n * This store is can be modified by the extension manager with and lifecycle\n * extension methods.\n *\n * Different properties are added at different times so it's important to\n * check the documentation for each property to know what phase is being\n * added.\n */\n private _store?: Remirror.ExtensionStore;\n\n constructor(...args: ExtensionConstructorProps<Options>) {\n super(defaultOptions, ...args);\n\n // Create the extension list.\n this._extensions = uniqueBy(\n this.createExtensions() as any,\n // Ensure that all the provided extensions are unique.\n (extension) => extension.constructor,\n );\n\n this.extensionMap = new Map<this['~E']['constructor'], this['~E']>();\n\n // Create the extension map for retrieving extensions from the `Preset`\n for (const extension of this._extensions) {\n this.extensionMap.set(extension.constructor, extension);\n }\n }\n\n /**\n * When there are duplicate extensions used within the editor the extension\n * manager will call this method and make sure all extension holders are using\n * the same instance of the `ExtensionConstructor`.\n *\n * @internal\n */\n replaceChildExtension(constructor: AnyExtensionConstructor, extension: this['~E']): void {\n if (!this.extensionMap.has(constructor)) {\n return;\n }\n\n this.extensionMap.set(constructor, extension);\n this._extensions = this.extensions.map((currentExtension) =>\n extension.constructor === constructor ? extension : currentExtension,\n );\n }\n\n /**\n * Not for usage. This is purely for types to make it easier to infer\n * available sub extension types.\n *\n * @internal\n */\n ['~E']: ReturnType<this['createExtensions']>[number] = {} as ReturnType<\n this['createExtensions']\n >[number];\n\n /**\n * Create the extensions which will be consumed by the preset. Override this\n * if you would like to make your extension a parent to other (holder)\n * extensions which don't make sense existing outside of the context of this\n * extension.\n *\n * @remarks\n *\n * Since this method is called in the constructor it should always be created\n * as an instance method and not a property. Properties aren't available for\n * the call to the parent class.\n *\n * ```ts\n * class HolderExtension extends PlainExtension {\n * get name() {\n * return 'holder'\n * }\n *\n * // GOOD \u2705\n * createExtensions() {\n * return [];\n * }\n *\n * // BAD \u274C\n * createExtensions = () => {\n * return [];\n * }\n * }\n * ```\n */\n createExtensions(): AnyExtension[] {\n return [];\n }\n\n /**\n * Get an extension from this holder extension by providing the desired\n * `Constructor`.\n *\n * @param Constructor - the extension constructor to find in the editor.\n *\n * @remarks\n *\n * This method will throw an error if the constructor doesn't exist within the\n * extension created by this extension.\n *\n * It can be used to forward options and attach handlers to the children\n * extensions. It is the spiritual replacement of the `Preset` extension.\n *\n * ```ts\n * import { PlainExtension, OnSetOptionsProps } from 'remirror';\n *\n * interface ParentOptions { weight?: string }\n *\n * class ParentExtension extends PlainExtension<ParentOptions> {\n * get name() {\n * return 'parent' as const;\n * }\n *\n * createExtensions() {\n * return [new BoldExtension()]\n * }\n *\n * onSetOptions(options: OnSetOptionsProps<ParentOptions>): void {\n * if (options.changes.weight.changed) {\n * // Update the value of the provided extension.\n * this.getExtension(BoldExtension).setOption({ weight: options.changes.weight.value });\n * }\n * }\n * }\n * ```\n */\n getExtension<Type extends this['~E']['constructor']>(Constructor: Type): InstanceType<Type> {\n const extension = this.extensionMap.get(Constructor);\n\n // Throws an error if attempting to get an extension which is not available\n // in this preset.\n invariant(extension, {\n code: ErrorConstant.INVALID_GET_EXTENSION,\n message: `'${Constructor.name}' does not exist within the preset: '${this.name}'`,\n });\n\n return extension as InstanceType<Type>;\n }\n\n /**\n * Check if the type of this extension's constructor matches the type of the\n * provided constructor.\n */\n isOfType<Type extends AnyExtensionConstructor>(Constructor: Type): this is InstanceType<Type> {\n return this.constructor === (Constructor as unknown);\n }\n\n /**\n * Pass a reference to the globally shared `ExtensionStore` for this\n * extension.\n *\n * @remarks\n *\n * The extension store allows extensions to access important variables without\n * complicating their creator methods.\n *\n * ```ts\n * import { PlainExtension } from 'remirror';\n *\n * class Awesome extends PlainExtension {\n * customMethod() {\n * if (this.store.view.hasFocus()) {\n * log('dance dance dance');\n * }\n * }\n * }\n * ```\n *\n * This should only be called by the `RemirrorManager`.\n *\n * @internal\n * @nonVirtual\n */\n setStore(store: Remirror.ExtensionStore): void {\n if (this._store) {\n return;\n }\n\n this._store = store;\n }\n\n /**\n * Clone an extension.\n */\n clone(...args: ExtensionConstructorProps<Options>): Extension<Options> {\n return new this.constructor(...args);\n }\n\n /**\n * Set the priority override for this extension. This is used in the\n * `RemirrorManager` in order to override the priority of an extension.\n *\n * If you set the first parameter to `undefined` it will remove the priority\n * override.\n *\n * @internal\n */\n setPriority(priority: undefined | ExtensionPriority): void {\n this.priorityOverride = priority;\n }\n\n /**\n * This handler is called when the `RemirrorManager` is first created.\n *\n * @remarks\n *\n * Since it is called as soon as the manager is some methods may not be\n * available in the extension store. When accessing methods on `this.store` be\n * shore to check when they become available in the lifecycle.\n *\n * You can return a `Dispose` function which will automatically be called when\n * the extension is destroyed.\n *\n * This handler is called before the `onView` handler.\n *\n * @category Lifecycle Methods\n */\n onCreate?(): Dispose | void;\n\n /**\n * This event happens when the view is first received from the view layer\n * (e.g. React).\n *\n * Return a dispose function which will be called when the extension is\n * destroyed.\n *\n * This handler is called after the `onCreate` handler.\n *\n * @category Lifecycle Methods\n */\n onView?(view: EditorView): Dispose | void;\n\n /**\n * This can be used by the `Extension` to append a transaction to the latest\n * update.\n *\n * This is shorthand for the `ProsemirrorPlugin.spec.appendTransaction`.\n *\n * @category Lifecycle Methods\n */\n onAppendTransaction?(props: AppendLifecycleProps): void;\n\n /**\n * This is called when the prosemirror editor state is first attached to the\n * editor. It can be useful for doing some preparation work.\n *\n * This is a shorthand for creating a plugin and adding the\n * [[`Plugin.spec.state.init`]].\n *\n * @category Lifecycle Methods\n */\n onInitState?(state: EditorState): void;\n\n /**\n * This is called when the state is being applied to the editor. This can be\n * used as a shorthand for the [[`Plugin.spec.state.apply`]] method.\n *\n * For example, when using [[`createDecorations`]] you can respond to editor\n * updates within this callback.\n *\n * @category Lifecycle Methods\n */\n onApplyState?(props: ApplyStateLifecycleProps): void;\n\n /**\n * This handler is called after a transaction successfully updates the editor\n * state. It is called asynchronously after the [[`onApplyState`]] hook has\n * been run run.\n *\n * @category Lifecycle Methods\n */\n onStateUpdate?(props: StateUpdateLifecycleProps): void;\n\n /**\n * Called when the extension is being destroyed.\n *\n * @category Lifecycle Methods\n */\n onDestroy?(): void;\n}\n\n/**\n * Declaration merging since the constructor property can't be defined on the\n * actual class.\n */\ninterface Extension<Options extends ValidOptions = EmptyShape> extends Remirror.BaseExtension {\n /**\n * The type of the constructor for the extension.\n */\n constructor: ExtensionConstructor<Options>;\n\n /**\n * An extension can declare the extensions it requires.\n *\n * @remarks\n *\n * When creating the extension manager the extension will be checked for\n * required extension as well as a quick check to see if the required\n * extension is already included. If not present a descriptive error will be\n * thrown.\n */\n requiredExtensions?: AnyExtensionConstructor[];\n}\n\n/**\n * Get the expected type signature for the `defaultOptions`. Requires that every\n * optional setting key (except for keys which are defined on the\n * `BaseExtensionOptions`) has a value assigned.\n */\nexport type DefaultExtensionOptions<Options extends ValidOptions> = DefaultOptions<\n Options,\n BaseExtensionOptions\n>;\n\n/**\n * Create a plain extension which doesn't directly map to Prosemirror nodes or\n * marks.\n *\n * Plain extensions are a great way to add custom behavior to your editor.\n */\nexport abstract class PlainExtension<\n Options extends ValidOptions = EmptyShape,\n> extends Extension<Options> {\n /** @internal */\n static get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.PlainExtensionConstructor {\n return RemirrorIdentifier.PlainExtensionConstructor;\n }\n\n /** @internal */\n get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.PlainExtension {\n return RemirrorIdentifier.PlainExtension;\n }\n}\n\n/**\n * A mark extension is based on the `Mark` concept from from within prosemirror\n * {@link https://prosemirror.net/docs/guide/#schema.marks}\n *\n * @remarks\n *\n * Marks are used to add extra styling or other information to inline content.\n * Mark types are objects much like node types, used to tag mark objects and\n * provide additional information about them.\n */\nexport abstract class MarkExtension<\n Options extends ValidOptions = EmptyShape,\n> extends Extension<Options> {\n /** @internal */\n static get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.MarkExtensionConstructor {\n return RemirrorIdentifier.MarkExtensionConstructor;\n }\n\n /**\n * Whether to disable extra attributes for this extension.\n */\n static readonly disableExtraAttributes: boolean = false;\n\n /** @internal */\n get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.MarkExtension {\n return RemirrorIdentifier.MarkExtension;\n }\n\n /**\n * Provides access to the mark type from the schema.\n *\n * @remarks\n *\n * The type is available as soon as the schema is created by the\n * `SchemaExtension` which has the priority `Highest`. It should be safe to\n * access in any of the lifecycle methods.\n */\n get type(): MarkType {\n return assertGet(this.store.schema.marks, this.name);\n }\n\n constructor(...args: ExtensionConstructorProps<Options>) {\n super(...args);\n }\n\n /**\n * Provide a method for creating the schema. This is required in order to\n * create a `MarkExtension`.\n *\n * @remarks\n *\n * The main difference between the return value of this method and Prosemirror\n * `MarkSpec` is that that the `toDOM` method doesn't allow dom manipulation.\n * You can only return an array or string.\n *\n * For more advanced requirements, it may be possible to create a `nodeView`\n * to manage the dom interactions.\n */\n abstract createMarkSpec(\n extra: ApplySchemaAttributes,\n override: MarkSpecOverride,\n ): MarkExtensionSpec;\n}\n\nexport interface MarkExtension<Options extends ValidOptions = EmptyShape>\n extends Extension<Options>,\n Remirror.MarkExtension {}\n\n/**\n * Defines the abstract class for extensions which can place nodes into the\n * prosemirror state.\n *\n * @remarks\n *\n * For more information see {@link https://prosemirror.net/docs/ref/#model.Node}\n */\nexport abstract class NodeExtension<\n Options extends ValidOptions = EmptyShape,\n> extends Extension<Options> {\n static get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.NodeExtensionConstructor {\n return RemirrorIdentifier.NodeExtensionConstructor;\n }\n\n /**\n * Whether to disable extra attributes for this extension.\n */\n static readonly disableExtraAttributes: boolean = false;\n\n /** @internal */\n get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.NodeExtension {\n return RemirrorIdentifier.NodeExtension as const;\n }\n\n /**\n * Provides access to the node type from the schema.\n */\n get type(): NodeType {\n return assertGet(this.store.schema.nodes, this.name);\n }\n\n constructor(...args: ExtensionConstructorProps<Options>) {\n super(...args);\n }\n\n /**\n * Provide a method for creating the schema. This is required in order to\n * create a `NodeExtension`.\n *\n * @remarks\n *\n * A node schema defines the behavior of the content within the editor. This\n * is very tied to the prosemirror implementation and the best place to learn\n * more about it is in the\n * {@link https://prosemirror.net/docs/guide/#schema docs}.\n *\n * @params hole - a method that is meant to indicate where extra attributes\n * should be placed (if they exist).\n *\n * The `hole` is a function that augments the passed object adding a special\n * `secret` key which is used to insert the extra attributes setter.\n *\n * ```ts\n * import { NodeExtension, SpecHole } from 'remirror';\n *\n * class AwesomeExtension extends NodeExtension {\n * get name() { return 'awesome' as const'; }\n *\n * createNodeSpec() {\n * return {\n * toDOM: (node) => {\n * return ['p', hole(), 0]\n * }\n * }\n * }\n * }\n * ```\n *\n * The above example will have the `hole()` method call replaced with the\n * extra attributes.\n */\n abstract createNodeSpec(\n extra: ApplySchemaAttributes,\n override: NodeSpecOverride,\n ): NodeExtensionSpec;\n}\n\nexport interface NodeExtension<Options extends ValidOptions = EmptyShape>\n extends Extension<Options>,\n Remirror.NodeExtension {}\n\n/**\n * The type which is applicable to any extension instance.\n *\n * **NOTE** `& object` forces VSCode to use the name `AnyExtension` rather than\n * print out `Replace<Extension<Shape>, Remirror.AnyExtensionOverrides>`\n */\nexport type AnyExtension = Replace<Extension<Shape>, Remirror.AnyExtensionOverrides> & object;\n\n/**\n * The type which is applicable to any extension instance.\n */\nexport type AnyExtensionConstructor = Replace<\n ExtensionConstructor<any>,\n // eslint-disable-next-line @typescript-eslint/prefer-function-type\n { new (...args: any[]): AnyExtension }\n>;\n\n/**\n * The type for any potential PlainExtension.\n */\nexport type AnyPlainExtension = Replace<PlainExtension<Shape>, Remirror.AnyExtensionOverrides> &\n object;\n\n/**\n * The type for any potential NodeExtension.\n */\nexport type AnyNodeExtension = Replace<NodeExtension<Shape>, Remirror.AnyExtensionOverrides> &\n object;\n\n/**\n * The type for any potential MarkExtension.\n */\nexport type AnyMarkExtension = Replace<MarkExtension<Shape>, Remirror.AnyExtensionOverrides> &\n object;\n\n/**\n * These are the default options merged into every extension. They can be\n * overridden.\n */\nconst defaultOptions: BaseExtensionOptions = {\n priority: undefined,\n extraAttributes: {},\n disableExtraAttributes: false,\n exclude: {},\n} as BaseExtensionOptions;\n\n/**\n * Mutate the default extension options.\n *\n * @remarks\n *\n * This is a dangerous method since it allows you to mutate the received object.\n * Don't use it unless you absolutely have to.\n *\n * A potential use case is for adding a new default option to all extensions. It\n * shows an example of how to accomplish this in a typesafe way.\n *\n * ```ts\n * import { mutateDefaultExtensionOptions } from 'remirror';\n *\n * mutateDefaultExtensionOptions((settings) => {\n * // Set the default value of all extensions to have a property `customSetting` with value `false`.\n * settings.customSetting = false;\n * })\n *\n * declare global {\n * namespace Remirror {\n * interface BaseExtensionOptions {\n * customSetting?: boolean;\n * }\n * }\n * }\n *```\n *\n * The mutation must happen before any extension have been instantiated.\n */\nexport function mutateDefaultExtensionOptions(\n mutatorMethod: (defaultOptions: BaseExtensionOptions) => void,\n): void {\n mutatorMethod(defaultOptions);\n}\n\n/**\n * Determines if the passed value is an extension.\n *\n * @param value - the value to test\n */\nexport function isExtension<Type extends AnyExtension = AnyExtension>(\n value: unknown,\n): value is Type {\n return (\n isRemirrorType(value) &&\n isIdentifierOfType(value, [\n RemirrorIdentifier.PlainExtension,\n RemirrorIdentifier.MarkExtension,\n RemirrorIdentifier.NodeExtension,\n ])\n );\n}\n\n/**\n * Determines if the passed value is an extension constructor.\n *\n * @param value - the value to test\n */\nexport function isExtensionConstructor<\n Type extends AnyExtensionConstructor = AnyExtensionConstructor,\n>(value: unknown): value is Type {\n return (\n isRemirrorType(value) &&\n isIdentifierOfType(value, [\n RemirrorIdentifier.PlainExtensionConstructor,\n RemirrorIdentifier.MarkExtensionConstructor,\n RemirrorIdentifier.NodeExtensionConstructor,\n ])\n );\n}\n\n/**\n * Checks whether the provided value is a plain extension.\n *\n * @param value - the extension to check\n */\nexport function isPlainExtension<Type extends AnyPlainExtension = AnyPlainExtension>(\n value: unknown,\n): value is Type {\n return isRemirrorType(value) && isIdentifierOfType(value, RemirrorIdentifier.PlainExtension);\n}\n\n/**\n * Determines if the passed in extension is a node extension. Useful as a type\n * guard where a particular type of extension is needed.\n *\n * @param value - the extension to check\n */\nexport function isNodeExtension<Type extends AnyNodeExtension = AnyNodeExtension>(\n value: unknown,\n): value is Type {\n return isRemirrorType(value) && isIdentifierOfType(value, RemirrorIdentifier.NodeExtension);\n}\n\n/**\n * Determines if the passed in extension is a mark extension. Useful as a type\n * guard where a particular type of extension is needed.\n *\n * @param value - the extension to check\n */\nexport function isMarkExtension<Type extends AnyMarkExtension = AnyMarkExtension>(\n value: unknown,\n): value is Type {\n return isRemirrorType(value) && isIdentifierOfType(value, RemirrorIdentifier.MarkExtension);\n}\n\nexport interface ExtensionConstructor<Options extends ValidOptions = EmptyShape>\n extends BaseClassConstructor<Options, BaseExtensionOptions>,\n Partial<Remirror.StaticExtensionOptions> {\n new (...args: ExtensionConstructorProps<Options>): Extension<Options>;\n\n /**\n * The default priority level for all instance of this extension.\n *\n * @defaultValue ExtensionPriority.Default\n */\n readonly defaultPriority: ExtensionPriority;\n}\n\nexport type AnyManagerStore = Remirror.ManagerStore<any>;\nexport type ManagerStoreKeys = keyof Remirror.ManagerStore<any>;\n\ndeclare global {\n /**\n * This namespace is global and you can use declaration merging to extend and\n * create new types used by the `remirror` project.\n *\n * @remarks\n *\n * The following would add `MyCustomType` to the `Remirror` namespace. Please\n * note that this can only be used for types and interfaces.\n *\n * ```ts\n * declare global {\n * namespace Remirror {\n * type MyCustomType = 'look-at-me';\n * }\n * }\n * ```\n */\n namespace Remirror {\n /**\n * This interface stores all the currently installed extensions. As a result\n * it can be used to set the default loaded extensions to include all\n * available within `node_modules`. By extending this extension in the\n * global `Remirror` namespace the key is ignored but the value is used to\n * form the union type in the `chain`, `commands`, `helpers` properties on\n * the `Remirror.ExtensionStore` interface.\n *\n * This is useful for extensions being able to reuse the work of other\n * extension.\n */\n interface AllExtensions {}\n\n /**\n * This is the global interface for adding extra methods and properties to\n * all [[`Extension`]]s using declaration merging.\n *\n * @remarks\n *\n * The following will add `newOption` to the expected options. This is the\n * way that extensions which add new functionality to the editor can request\n * configuration options.\n *\n * ```ts\n * declare global {\n * namespace Remirror {\n * interface ExtensionFactoryProps {\n * newOption?: string;\n * }\n * }\n * }\n * ```\n */\n interface BaseExtension {}\n\n interface NodeExtension {}\n interface MarkExtension {}\n\n /**\n * An override to for the `AnyExtension` type. If you're extension adds a\n * new property to the `Extension` that is deeply nested or very complex it\n * can break the `AnyExtension` implementation from being compatible with\n * all valid extensions.\n *\n * The keys you provide on this override replace the default `AnyExtension`\n * types include unsafe properties that need to be simplified.\n *\n * An example is the `constructor` property which makes it impossible to\n * find a common interface between extensions with different settings and\n * properties. By setting the `constructor` to a much simpler override all\n * `Extension`'s are now assignable to the `AnyExtension type again.`\n */\n interface AnyExtensionOverrides extends AnyBaseClassOverrides {\n constructor: AnyExtensionConstructor;\n ['~C']: ExtensionCommandReturn;\n ['~H']: ExtensionHelperReturn;\n ['~E']: AnyExtension;\n }\n }\n}\n\n/* eslint-enable @typescript-eslint/member-ordering */\n\n// Make the abstract extension available but only as a type.\nexport type { Extension };\n", "/* eslint-disable @typescript-eslint/member-ordering */\n\nimport {\n __INTERNAL_REMIRROR_IDENTIFIER_KEY__,\n ErrorConstant,\n ExtensionPriority,\n RemirrorIdentifier,\n} from '@remirror/core-constants';\nimport {\n deepMerge,\n invariant,\n isEmptyArray,\n isFunction,\n keys,\n noop,\n object,\n omit,\n sort,\n} from '@remirror/core-helpers';\nimport type {\n AnyFunction,\n Dispose,\n EmptyShape,\n GetAcceptUndefined,\n GetConstructorProps,\n GetCustomHandler,\n GetFixed,\n GetFixedDynamic,\n GetHandler,\n GetMappedHandler,\n GetPartialDynamic,\n GetStatic,\n IfNoRequiredProperties,\n LiteralUnion,\n MakeUndefined,\n Primitive,\n RemoveAnnotations,\n Replace,\n Shape,\n StringKey,\n UndefinedFlipPartialAndRequired,\n ValidOptions,\n} from '@remirror/core-types';\nimport { environment } from '@remirror/core-utils';\n\nimport { getChangedOptions } from '../helpers';\nimport type { OnSetOptionsProps } from '../types';\n\nconst IGNORE = '__IGNORE__';\nconst GENERAL_OPTIONS = '__ALL__' as const;\n\nexport abstract class BaseClass<\n Options extends ValidOptions = EmptyShape,\n DefaultStaticOptions extends Shape = EmptyShape,\n> {\n /**\n * The default options for this extension.\n *\n * TODO see if this can be cast to something other than any and allow\n * composition.\n */\n static readonly defaultOptions: any = {};\n\n /**\n * The static keys for this class.\n */\n static readonly staticKeys: string[] = [];\n\n /**\n * The event handler keys.\n */\n static readonly handlerKeys: string[] = [];\n\n /**\n * Customize the way the handler should behave.\n */\n static handlerKeyOptions: Partial<\n Record<string, HandlerKeyOptions> & { [GENERAL_OPTIONS]?: HandlerKeyOptions }\n > = {};\n\n /**\n * The custom keys.\n */\n static readonly customHandlerKeys: string[] = [];\n\n /**\n * This is not for external use. It is purely here for TypeScript inference of\n * the generic `Options` type parameter.\n *\n * @internal\n */\n ['~O']: Options & DefaultStaticOptions = {} as Options & DefaultStaticOptions;\n\n /**\n * This identifies this as a `Remirror` object. .\n * @internal\n */\n abstract readonly [__INTERNAL_REMIRROR_IDENTIFIER_KEY__]: RemirrorIdentifier;\n\n /**\n * The unique name of this extension.\n *\n * @remarks\n *\n * Every extension **must** have a name. The name should have a distinct type\n * to allow for better type inference for end users. By convention the name\n * should be `camelCased` and unique within your editor instance.\n *\n * ```ts\n * class SimpleExtension extends Extension {\n * get name() {\n * return 'simple' as const;\n * }\n * }\n * ```\n */\n abstract get name(): string;\n\n /**\n * The options for this extension.\n *\n * @remarks\n *\n * Options are composed of Static, Dynamic, Handlers and ObjectHandlers.\n *\n * - `Static` - set at instantiation by the constructor.\n * - `Dynamic` - optionally set at instantiation by the constructor and also\n * set during the runtime.\n * - `Handlers` - can only be set during the runtime.\n * - `ObjectHandlers` - Can only be set during the runtime of the extension.\n */\n get options(): RemoveAnnotations<GetFixed<Options> & DefaultStaticOptions> {\n return this._options;\n }\n\n /**\n * Get the dynamic keys for this extension.\n */\n get dynamicKeys(): string[] {\n return this._dynamicKeys;\n }\n\n /**\n * The options that this instance was created with, merged with all the\n * default options.\n */\n get initialOptions(): RemoveAnnotations<GetFixed<Options> & DefaultStaticOptions> {\n return this._initialOptions;\n }\n\n /**\n * The initial options at creation (used to reset).\n */\n private readonly _initialOptions: RemoveAnnotations<GetFixed<Options> & DefaultStaticOptions>;\n\n /**\n * All the dynamic keys supported by this extension.\n */\n private readonly _dynamicKeys: string[];\n\n /**\n * Private instance of the extension options.\n */\n private _options: RemoveAnnotations<GetFixed<Options> & DefaultStaticOptions>;\n\n /**\n * The mapped function handlers.\n */\n private _mappedHandlers: GetMappedHandler<Options>;\n\n constructor(\n defaultOptions: DefaultStaticOptions,\n ...[options]: ConstructorProps<Options, DefaultStaticOptions>\n ) {\n this._mappedHandlers = object();\n this.populateMappedHandlers();\n\n this._options = this._initialOptions = deepMerge(\n defaultOptions,\n this.constructor.defaultOptions,\n options ?? object(),\n this.createDefaultHandlerOptions(),\n );\n\n this._dynamicKeys = this.getDynamicKeys();\n\n // Triggers the `init` options update for this extension.\n this.init();\n }\n\n /**\n * This method is called by the extension constructor. It is not strictly a\n * lifecycle method since at this point the manager has not yet been\n * instantiated.\n *\n * @remarks\n *\n * It should be used instead of overriding the constructor which is strongly\n * advised against.\n *\n * There are some limitations when using this method.\n *\n * - Accessing `this.store` will throw an error since the manager hasn't been\n * created and it hasn't yet been attached to the extensions.\n * - `this.type` in `NodeExtension` and `MarkExtension` will also throw an\n * error since the schema hasn't been created yet.\n *\n * You should use this to setup any instance properties with the options\n * provided to the extension.\n */\n protected init(): void {}\n\n /**\n * Clone the current instance with the provided options. If nothing is\n * provided it uses the same initial options as the current instance.\n */\n abstract clone(\n ...parameters: ConstructorProps<Options, DefaultStaticOptions>\n ): BaseClass<Options, DefaultStaticOptions>;\n\n /**\n * Get the dynamic keys for this extension.\n */\n private getDynamicKeys(): string[] {\n const dynamicKeys: string[] = [];\n const { customHandlerKeys, handlerKeys, staticKeys } = this.constructor;\n\n for (const key of keys(this._options)) {\n if (\n staticKeys.includes(key) ||\n handlerKeys.includes(key) ||\n customHandlerKeys.includes(key)\n ) {\n continue;\n }\n\n dynamicKeys.push(key);\n }\n\n return dynamicKeys;\n }\n\n /**\n * Throw an error if non dynamic keys are updated.\n */\n private ensureAllKeysAreDynamic(update: GetPartialDynamic<Options>) {\n if (environment.isProduction) {\n return;\n }\n\n const invalid: string[] = [];\n\n for (const key of keys(update)) {\n if (this._dynamicKeys.includes(key)) {\n continue;\n }\n\n invalid.push(key);\n }\n\n invariant(isEmptyArray(invalid), {\n code: ErrorConstant.INVALID_SET_EXTENSION_OPTIONS,\n message: `Invalid properties passed into the 'setOptions()' method: ${JSON.stringify(\n invalid,\n )}.`,\n });\n }\n\n /**\n * Update the properties with the provided partial value when changed.\n */\n setOptions(update: GetPartialDynamic<Options>): void {\n const previousOptions = this.getDynamicOptions();\n\n this.ensureAllKeysAreDynamic(update);\n\n const { changes, options, pickChanged } = getChangedOptions({\n previousOptions,\n update,\n });\n\n this.updateDynamicOptions(options);\n\n // Trigger the update handler so the extension can respond to any relevant\n // property updates.\n this.onSetOptions?.({\n reason: 'set',\n changes,\n options,\n pickChanged,\n initialOptions: this._initialOptions,\n });\n }\n\n /**\n * Reset the extension properties to their default values.\n *\n * @nonVirtual\n */\n resetOptions(): void {\n const previousOptions = this.getDynamicOptions();\n const { changes, options, pickChanged } = getChangedOptions<Options>({\n previousOptions,\n update: this._initialOptions,\n });\n\n this.updateDynamicOptions(options);\n\n // Trigger the update handler so that child extension properties can also be\n // updated.\n this.onSetOptions?.({\n reason: 'reset',\n options,\n changes,\n pickChanged,\n initialOptions: this._initialOptions,\n });\n }\n\n /**\n * Override this to receive updates whenever the options have been updated on\n * this instance. This method is called after the updates have already been\n * applied to the instance. If you need more control over exactly how the\n * option should be applied you should set the option to be `Custom`.\n *\n * **Please Note**:\n *\n * This must be defined as a instance method and not a property since it is\n * called in the constructor.\n *\n * ```ts\n * class ThisPreset extends Preset {\n * // GOOD \u2705\n * onSetOptions(props: OnSetOptionsProps<Options>) {}\n *\n * // BAD \u274C\n * onSetOptions = (props: OnSetOptionsProps<Options>) => {}\n * }\n * ```\n *\n * @abstract\n */\n protected onSetOptions?(props: OnSetOptionsProps<Options>): void;\n\n /**\n * Update the private options.\n */\n private getDynamicOptions(): GetFixedDynamic<Options> {\n return omit(this._options, [\n ...this.constructor.customHandlerKeys,\n ...this.constructor.handlerKeys,\n ]) as any;\n }\n\n /**\n * Update the dynamic options.\n */\n private updateDynamicOptions(options: GetFixedDynamic<Options>) {\n this._options = { ...this._options, ...options };\n }\n\n /**\n * Set up the mapped handlers object with default values (an empty array);\n */\n private populateMappedHandlers() {\n for (const key of this.constructor.handlerKeys) {\n this._mappedHandlers[key as keyof GetMappedHandler<Options>] = [];\n }\n }\n\n /**\n * This is currently fudged together, I'm not sure it will work.\n */\n private createDefaultHandlerOptions() {\n const methods = object<any>();\n\n for (const key of this.constructor.handlerKeys) {\n methods[key] = (...args: any[]) => {\n const { handlerKeyOptions } = this.constructor;\n const reducer = handlerKeyOptions[key]?.reducer;\n let returnValue: unknown = reducer?.getDefault(...args);\n\n for (const [, handler] of this._mappedHandlers[key as keyof GetMappedHandler<Options>]) {\n const value = (handler as unknown as AnyFunction)(...args);\n returnValue = reducer ? reducer.accumulator(returnValue, value, ...args) : value;\n\n // Check if the method should cause an early return, based on the\n // return value.\n if (shouldReturnEarly(handlerKeyOptions, returnValue, key)) {\n return returnValue;\n }\n }\n\n return returnValue;\n };\n }\n\n return methods;\n }\n\n /**\n * Add a handler to the event handlers so that it is called along with all the\n * other handler methods.\n *\n * This is helpful for integrating react hooks which can be used in multiple\n * places. The original problem with fixed properties is that you can only\n * assign to a method once and it overwrites any other methods. This pattern\n * for adding handlers allows for multiple usages of the same handler in the\n * most relevant part of the code.\n *\n * More to come on this pattern.\n *\n * @nonVirtual\n */\n addHandler<Key extends keyof GetHandler<Options>>(\n key: Key,\n method: GetHandler<Options>[Key],\n priority = ExtensionPriority.Default,\n ): Dispose {\n this._mappedHandlers[key].push([priority, method]);\n this.sortHandlers(key);\n\n // Return a method for disposing of the handler.\n return () =>\n (this._mappedHandlers[key] = this._mappedHandlers[key].filter(\n ([, handler]) => handler !== method,\n ));\n }\n\n /**\n * Determines if handlers exist for the given key.\n *\n * Checking the existence of a handler property directly gives wrong results.\n * `this.options.onHandlerName` is always truthy because it is a reference to\n * the wrapper function that calls each handler.\n *\n * ```ts\n *\n * // GOOD \u2705\n * if (!this.hasHandlers('onHandlerName')) {\n * return;\n * }\n *\n * // BAD \u274C\n * if (!this.options.onHandlerName) {\n * return;\n * }\n * ```\n *\n * @param key The handler to test\n */\n hasHandlers<Key extends keyof GetHandler<Options>>(key: Key): boolean {\n return (this._mappedHandlers[key] ?? []).length > 0;\n }\n\n private sortHandlers<Key extends keyof GetHandler<Options>>(key: Key) {\n this._mappedHandlers[key] = sort(\n this._mappedHandlers[key],\n // Sort from highest binding to the lowest.\n ([a], [z]) => z - a,\n );\n }\n\n /**\n * A method that can be used to add a custom handler. It is up to the\n * extension creator to manage the handlers and dispose methods.\n */\n addCustomHandler<Key extends keyof GetCustomHandler<Options>>(\n key: Key,\n value: Required<GetCustomHandler<Options>>[Key],\n ): Dispose {\n return this.onAddCustomHandler?.({ [key]: value } as any) ?? noop;\n }\n\n /**\n * Override this method if you want to set custom handlers on your extension.\n *\n * This must return a dispose function.\n */\n protected onAddCustomHandler?: AddCustomHandler<Options>;\n}\n\ntype HandlerKeyOptionsMap = Partial<\n Record<string, HandlerKeyOptions> & { [GENERAL_OPTIONS]?: HandlerKeyOptions }\n>;\n\n/**\n * A function used to determine whether the value provided by the handler\n * warrants an early return.\n */\nfunction shouldReturnEarly(\n handlerKeyOptions: HandlerKeyOptionsMap,\n returnValue: unknown,\n handlerKey: string,\n): boolean {\n const { [GENERAL_OPTIONS]: generalOptions } = handlerKeyOptions;\n const handlerOptions = handlerKeyOptions[handlerKey];\n\n if (!generalOptions && !handlerOptions) {\n return false;\n }\n\n // First check if there are options set for the provided handlerKey\n if (\n handlerOptions &&\n // Only proceed if the value should not be ignored.\n handlerOptions.earlyReturnValue !== IGNORE &&\n (isFunction(handlerOptions.earlyReturnValue)\n ? ha