UNPKG

24.2 kBTypeScriptView Raw
1import { __INTERNAL_REMIRROR_IDENTIFIER_KEY__, ExtensionPriority, RemirrorIdentifier } from '@remirror/core-constants';
2import type { ApplySchemaAttributes, Dispose, EditorState, EditorView, EmptyShape, MarkExtensionSpec, MarkSpecOverride, MarkType, NodeExtensionSpec, NodeSpecOverride, NodeType, Replace, Shape, ValidOptions } from '@remirror/core-types';
3import type { AppendLifecycleProps, ApplyStateLifecycleProps, BaseExtensionOptions, ExtensionCommandReturn, ExtensionHelperReturn, StateUpdateLifecycleProps } from '../types';
4import { AnyBaseClassOverrides, BaseClass, BaseClassConstructor, ConstructorProps, DefaultOptions } from './base-class';
5/**
6 * Auto infers the parameter for the constructor. If there is a required static
7 * option then the TypeScript compiler will error if nothing is passed in.
8 */
9export type ExtensionConstructorProps<Options extends ValidOptions> = ConstructorProps<Options, BaseExtensionOptions>;
10/**
11 * Extensions are fundamental to the way that Remirror works by grouping
12 * together the functionality and handling the management of similar concerns.
13 *
14 * @remarks
15 *
16 * Extension can adjust editor functionality in any way. Here are some
17 * examples.
18 *
19 * - How the editor displays certain content, i.e. **bold**, _italic_,
20 * **underline**.
21 * - Which commands should be made available e.g. `commands.toggleBold()` to
22 * toggle the weight of the selected text.
23 * - Check if a command is currently enabled (i.e a successful dry run) e.g.
24 * `commands.toggleBold.isEnabled()`.
25 * - Register Prosemirror `Plugin`s, `keymap`s, `InputRule`s `PasteRule`s,
26 * `Suggestions`, and custom `nodeViews` which affect the behavior of the
27 * editor.
28 *
29 * There are three types of `Extension`.
30 *
31 * - `NodeExtension` - For creating Prosemirror nodes in the editor. See
32 * {@link NodeExtension}
33 * - `MarkExtension` - For creating Prosemirror marks in the editor. See
34 * {@link MarkExtension}
35 * - `PlainExtension` - For behavior which doesn't map to a `ProsemirrorNode` or
36 * `Mark` and as a result doesn't directly affect the Prosemirror `Schema` or
37 * content. See {@link PlainExtension}.
38 *
39 * This `Extension` is an abstract class that should not be used directly but
40 * rather extended to add the intended functionality.
41 *
42 * ```ts
43 * import { PlainExtension, Static } from 'remirror';
44 *
45 * interface AwesomeExtensionOptions {
46 * isAwesome?: Static<boolean>;
47 * id?: string;
48 * }
49 *
50 * class AwesomeExtension extends PlainExtension<AwesomeExtensionOptions> {
51 * static defaultOptions: DefaultExtensionOptions<AwesomeExtensionOptions> = {
52 * isAwesome: true,
53 * id: '',
54 * }
55 *
56 * get name() {
57 * return 'awesome' as const;
58 * }
59 * }
60 * ```
61 */
62declare abstract class Extension<Options extends ValidOptions = EmptyShape> extends BaseClass<Options, BaseExtensionOptions> {
63 /**
64 * The default priority for this family of extensions.
65 */
66 static readonly defaultPriority: ExtensionPriority;
67 /**
68 * Allows for the `RemirrorManager` or `Preset`'s to override the priority of
69 * an extension.
70 */
71 private priorityOverride?;
72 /**
73 * The priority level for this instance of the extension. A higher value
74 * corresponds to a higher priority extension
75 */
76 get priority(): ExtensionPriority;
77 /**
78 * The name that the constructor should have, which doesn't get mangled in
79 * production.
80 */
81 get constructorName(): string;
82 /**
83 * The store is a shared object that's internal to each extension. It includes
84 * often used items like the `view` and `schema` that are added by the
85 * extension manager and also the lifecycle extension methods.
86 *
87 * **NOTE** - The store is not available until the manager has been created
88 * and received the extension. As a result trying to access the store during
89 * `init` and `constructor` will result in a runtime error.
90 *
91 * Some properties of the store are available at different phases. You should
92 * check the inline documentation to know when a certain property is useable
93 * in your extension.
94 */
95 protected get store(): Remirror.ExtensionStore;
96 /**
97 * The list of extensions added to the editor by this `Preset`.
98 */
99 get extensions(): Array<this['~E']>;
100 /**
101 * Private list of extension stored within this [[`Preset`]].
102 */
103 private _extensions;
104 /**
105 * An extension mapping of the extensions and their constructors.
106 */
107 private readonly extensionMap;
108 /**
109 * This store is can be modified by the extension manager with and lifecycle
110 * extension methods.
111 *
112 * Different properties are added at different times so it's important to
113 * check the documentation for each property to know what phase is being
114 * added.
115 */
116 private _store?;
117 constructor(...args: ExtensionConstructorProps<Options>);
118 /**
119 * When there are duplicate extensions used within the editor the extension
120 * manager will call this method and make sure all extension holders are using
121 * the same instance of the `ExtensionConstructor`.
122 *
123 * @internal
124 */
125 replaceChildExtension(constructor: AnyExtensionConstructor, extension: this['~E']): void;
126 /**
127 * Not for usage. This is purely for types to make it easier to infer
128 * available sub extension types.
129 *
130 * @internal
131 */
132 ['~E']: ReturnType<this['createExtensions']>[number];
133 /**
134 * Create the extensions which will be consumed by the preset. Override this
135 * if you would like to make your extension a parent to other (holder)
136 * extensions which don't make sense existing outside of the context of this
137 * extension.
138 *
139 * @remarks
140 *
141 * Since this method is called in the constructor it should always be created
142 * as an instance method and not a property. Properties aren't available for
143 * the call to the parent class.
144 *
145 * ```ts
146 * class HolderExtension extends PlainExtension {
147 * get name() {
148 * return 'holder'
149 * }
150 *
151 * // GOOD ✅
152 * createExtensions() {
153 * return [];
154 * }
155 *
156 * // BAD ❌
157 * createExtensions = () => {
158 * return [];
159 * }
160 * }
161 * ```
162 */
163 createExtensions(): AnyExtension[];
164 /**
165 * Get an extension from this holder extension by providing the desired
166 * `Constructor`.
167 *
168 * @param Constructor - the extension constructor to find in the editor.
169 *
170 * @remarks
171 *
172 * This method will throw an error if the constructor doesn't exist within the
173 * extension created by this extension.
174 *
175 * It can be used to forward options and attach handlers to the children
176 * extensions. It is the spiritual replacement of the `Preset` extension.
177 *
178 * ```ts
179 * import { PlainExtension, OnSetOptionsProps } from 'remirror';
180 *
181 * interface ParentOptions { weight?: string }
182 *
183 * class ParentExtension extends PlainExtension<ParentOptions> {
184 * get name() {
185 * return 'parent' as const;
186 * }
187 *
188 * createExtensions() {
189 * return [new BoldExtension()]
190 * }
191 *
192 * onSetOptions(options: OnSetOptionsProps<ParentOptions>): void {
193 * if (options.changes.weight.changed) {
194 * // Update the value of the provided extension.
195 * this.getExtension(BoldExtension).setOption({ weight: options.changes.weight.value });
196 * }
197 * }
198 * }
199 * ```
200 */
201 getExtension<Type extends this['~E']['constructor']>(Constructor: Type): InstanceType<Type>;
202 /**
203 * Check if the type of this extension's constructor matches the type of the
204 * provided constructor.
205 */
206 isOfType<Type extends AnyExtensionConstructor>(Constructor: Type): this is InstanceType<Type>;
207 /**
208 * Pass a reference to the globally shared `ExtensionStore` for this
209 * extension.
210 *
211 * @remarks
212 *
213 * The extension store allows extensions to access important variables without
214 * complicating their creator methods.
215 *
216 * ```ts
217 * import { PlainExtension } from 'remirror';
218 *
219 * class Awesome extends PlainExtension {
220 * customMethod() {
221 * if (this.store.view.hasFocus()) {
222 * log('dance dance dance');
223 * }
224 * }
225 * }
226 * ```
227 *
228 * This should only be called by the `RemirrorManager`.
229 *
230 * @internal
231 * @nonVirtual
232 */
233 setStore(store: Remirror.ExtensionStore): void;
234 /**
235 * Clone an extension.
236 */
237 clone(...args: ExtensionConstructorProps<Options>): Extension<Options>;
238 /**
239 * Set the priority override for this extension. This is used in the
240 * `RemirrorManager` in order to override the priority of an extension.
241 *
242 * If you set the first parameter to `undefined` it will remove the priority
243 * override.
244 *
245 * @internal
246 */
247 setPriority(priority: undefined | ExtensionPriority): void;
248 /**
249 * This handler is called when the `RemirrorManager` is first created.
250 *
251 * @remarks
252 *
253 * Since it is called as soon as the manager is some methods may not be
254 * available in the extension store. When accessing methods on `this.store` be
255 * shore to check when they become available in the lifecycle.
256 *
257 * You can return a `Dispose` function which will automatically be called when
258 * the extension is destroyed.
259 *
260 * This handler is called before the `onView` handler.
261 *
262 * @category Lifecycle Methods
263 */
264 onCreate?(): Dispose | void;
265 /**
266 * This event happens when the view is first received from the view layer
267 * (e.g. React).
268 *
269 * Return a dispose function which will be called when the extension is
270 * destroyed.
271 *
272 * This handler is called after the `onCreate` handler.
273 *
274 * @category Lifecycle Methods
275 */
276 onView?(view: EditorView): Dispose | void;
277 /**
278 * This can be used by the `Extension` to append a transaction to the latest
279 * update.
280 *
281 * This is shorthand for the `ProsemirrorPlugin.spec.appendTransaction`.
282 *
283 * @category Lifecycle Methods
284 */
285 onAppendTransaction?(props: AppendLifecycleProps): void;
286 /**
287 * This is called when the prosemirror editor state is first attached to the
288 * editor. It can be useful for doing some preparation work.
289 *
290 * This is a shorthand for creating a plugin and adding the
291 * [[`Plugin.spec.state.init`]].
292 *
293 * @category Lifecycle Methods
294 */
295 onInitState?(state: EditorState): void;
296 /**
297 * This is called when the state is being applied to the editor. This can be
298 * used as a shorthand for the [[`Plugin.spec.state.apply`]] method.
299 *
300 * For example, when using [[`createDecorations`]] you can respond to editor
301 * updates within this callback.
302 *
303 * @category Lifecycle Methods
304 */
305 onApplyState?(props: ApplyStateLifecycleProps): void;
306 /**
307 * This handler is called after a transaction successfully updates the editor
308 * state. It is called asynchronously after the [[`onApplyState`]] hook has
309 * been run run.
310 *
311 * @category Lifecycle Methods
312 */
313 onStateUpdate?(props: StateUpdateLifecycleProps): void;
314 /**
315 * Called when the extension is being destroyed.
316 *
317 * @category Lifecycle Methods
318 */
319 onDestroy?(): void;
320}
321/**
322 * Declaration merging since the constructor property can't be defined on the
323 * actual class.
324 */
325interface Extension<Options extends ValidOptions = EmptyShape> extends Remirror.BaseExtension {
326 /**
327 * The type of the constructor for the extension.
328 */
329 constructor: ExtensionConstructor<Options>;
330 /**
331 * An extension can declare the extensions it requires.
332 *
333 * @remarks
334 *
335 * When creating the extension manager the extension will be checked for
336 * required extension as well as a quick check to see if the required
337 * extension is already included. If not present a descriptive error will be
338 * thrown.
339 */
340 requiredExtensions?: AnyExtensionConstructor[];
341}
342/**
343 * Get the expected type signature for the `defaultOptions`. Requires that every
344 * optional setting key (except for keys which are defined on the
345 * `BaseExtensionOptions`) has a value assigned.
346 */
347export type DefaultExtensionOptions<Options extends ValidOptions> = DefaultOptions<Options, BaseExtensionOptions>;
348/**
349 * Create a plain extension which doesn't directly map to Prosemirror nodes or
350 * marks.
351 *
352 * Plain extensions are a great way to add custom behavior to your editor.
353 */
354export declare abstract class PlainExtension<Options extends ValidOptions = EmptyShape> extends Extension<Options> {
355 /** @internal */
356 static get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.PlainExtensionConstructor;
357 /** @internal */
358 get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.PlainExtension;
359}
360/**
361 * A mark extension is based on the `Mark` concept from from within prosemirror
362 * {@link https://prosemirror.net/docs/guide/#schema.marks}
363 *
364 * @remarks
365 *
366 * Marks are used to add extra styling or other information to inline content.
367 * Mark types are objects much like node types, used to tag mark objects and
368 * provide additional information about them.
369 */
370export declare abstract class MarkExtension<Options extends ValidOptions = EmptyShape> extends Extension<Options> {
371 /** @internal */
372 static get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.MarkExtensionConstructor;
373 /**
374 * Whether to disable extra attributes for this extension.
375 */
376 static readonly disableExtraAttributes: boolean;
377 /** @internal */
378 get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.MarkExtension;
379 /**
380 * Provides access to the mark type from the schema.
381 *
382 * @remarks
383 *
384 * The type is available as soon as the schema is created by the
385 * `SchemaExtension` which has the priority `Highest`. It should be safe to
386 * access in any of the lifecycle methods.
387 */
388 get type(): MarkType;
389 constructor(...args: ExtensionConstructorProps<Options>);
390 /**
391 * Provide a method for creating the schema. This is required in order to
392 * create a `MarkExtension`.
393 *
394 * @remarks
395 *
396 * The main difference between the return value of this method and Prosemirror
397 * `MarkSpec` is that that the `toDOM` method doesn't allow dom manipulation.
398 * You can only return an array or string.
399 *
400 * For more advanced requirements, it may be possible to create a `nodeView`
401 * to manage the dom interactions.
402 */
403 abstract createMarkSpec(extra: ApplySchemaAttributes, override: MarkSpecOverride): MarkExtensionSpec;
404}
405export interface MarkExtension<Options extends ValidOptions = EmptyShape> extends Extension<Options>, Remirror.MarkExtension {
406}
407/**
408 * Defines the abstract class for extensions which can place nodes into the
409 * prosemirror state.
410 *
411 * @remarks
412 *
413 * For more information see {@link https://prosemirror.net/docs/ref/#model.Node}
414 */
415export declare abstract class NodeExtension<Options extends ValidOptions = EmptyShape> extends Extension<Options> {
416 static get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.NodeExtensionConstructor;
417 /**
418 * Whether to disable extra attributes for this extension.
419 */
420 static readonly disableExtraAttributes: boolean;
421 /** @internal */
422 get [__INTERNAL_REMIRROR_IDENTIFIER_KEY__](): RemirrorIdentifier.NodeExtension;
423 /**
424 * Provides access to the node type from the schema.
425 */
426 get type(): NodeType;
427 constructor(...args: ExtensionConstructorProps<Options>);
428 /**
429 * Provide a method for creating the schema. This is required in order to
430 * create a `NodeExtension`.
431 *
432 * @remarks
433 *
434 * A node schema defines the behavior of the content within the editor. This
435 * is very tied to the prosemirror implementation and the best place to learn
436 * more about it is in the
437 * {@link https://prosemirror.net/docs/guide/#schema docs}.
438 *
439 * @params hole - a method that is meant to indicate where extra attributes
440 * should be placed (if they exist).
441 *
442 * The `hole` is a function that augments the passed object adding a special
443 * `secret` key which is used to insert the extra attributes setter.
444 *
445 * ```ts
446 * import { NodeExtension, SpecHole } from 'remirror';
447 *
448 * class AwesomeExtension extends NodeExtension {
449 * get name() { return 'awesome' as const'; }
450 *
451 * createNodeSpec() {
452 * return {
453 * toDOM: (node) => {
454 * return ['p', hole(), 0]
455 * }
456 * }
457 * }
458 * }
459 * ```
460 *
461 * The above example will have the `hole()` method call replaced with the
462 * extra attributes.
463 */
464 abstract createNodeSpec(extra: ApplySchemaAttributes, override: NodeSpecOverride): NodeExtensionSpec;
465}
466export interface NodeExtension<Options extends ValidOptions = EmptyShape> extends Extension<Options>, Remirror.NodeExtension {
467}
468/**
469 * The type which is applicable to any extension instance.
470 *
471 * **NOTE** `& object` forces VSCode to use the name `AnyExtension` rather than
472 * print out `Replace<Extension<Shape>, Remirror.AnyExtensionOverrides>`
473 */
474export type AnyExtension = Replace<Extension<Shape>, Remirror.AnyExtensionOverrides> & object;
475/**
476 * The type which is applicable to any extension instance.
477 */
478export type AnyExtensionConstructor = Replace<ExtensionConstructor<any>, {
479 new (...args: any[]): AnyExtension;
480}>;
481/**
482 * The type for any potential PlainExtension.
483 */
484export type AnyPlainExtension = Replace<PlainExtension<Shape>, Remirror.AnyExtensionOverrides> & object;
485/**
486 * The type for any potential NodeExtension.
487 */
488export type AnyNodeExtension = Replace<NodeExtension<Shape>, Remirror.AnyExtensionOverrides> & object;
489/**
490 * The type for any potential MarkExtension.
491 */
492export type AnyMarkExtension = Replace<MarkExtension<Shape>, Remirror.AnyExtensionOverrides> & object;
493/**
494 * Mutate the default extension options.
495 *
496 * @remarks
497 *
498 * This is a dangerous method since it allows you to mutate the received object.
499 * Don't use it unless you absolutely have to.
500 *
501 * A potential use case is for adding a new default option to all extensions. It
502 * shows an example of how to accomplish this in a typesafe way.
503 *
504 * ```ts
505 * import { mutateDefaultExtensionOptions } from 'remirror';
506 *
507 * mutateDefaultExtensionOptions((settings) => {
508 * // Set the default value of all extensions to have a property `customSetting` with value `false`.
509 * settings.customSetting = false;
510 * })
511 *
512 * declare global {
513 * namespace Remirror {
514 * interface BaseExtensionOptions {
515 * customSetting?: boolean;
516 * }
517 * }
518 * }
519 *```
520 *
521 * The mutation must happen before any extension have been instantiated.
522 */
523export declare function mutateDefaultExtensionOptions(mutatorMethod: (defaultOptions: BaseExtensionOptions) => void): void;
524/**
525 * Determines if the passed value is an extension.
526 *
527 * @param value - the value to test
528 */
529export declare function isExtension<Type extends AnyExtension = AnyExtension>(value: unknown): value is Type;
530/**
531 * Determines if the passed value is an extension constructor.
532 *
533 * @param value - the value to test
534 */
535export declare function isExtensionConstructor<Type extends AnyExtensionConstructor = AnyExtensionConstructor>(value: unknown): value is Type;
536/**
537 * Checks whether the provided value is a plain extension.
538 *
539 * @param value - the extension to check
540 */
541export declare function isPlainExtension<Type extends AnyPlainExtension = AnyPlainExtension>(value: unknown): value is Type;
542/**
543 * Determines if the passed in extension is a node extension. Useful as a type
544 * guard where a particular type of extension is needed.
545 *
546 * @param value - the extension to check
547 */
548export declare function isNodeExtension<Type extends AnyNodeExtension = AnyNodeExtension>(value: unknown): value is Type;
549/**
550 * Determines if the passed in extension is a mark extension. Useful as a type
551 * guard where a particular type of extension is needed.
552 *
553 * @param value - the extension to check
554 */
555export declare function isMarkExtension<Type extends AnyMarkExtension = AnyMarkExtension>(value: unknown): value is Type;
556export interface ExtensionConstructor<Options extends ValidOptions = EmptyShape> extends BaseClassConstructor<Options, BaseExtensionOptions>, Partial<Remirror.StaticExtensionOptions> {
557 new (...args: ExtensionConstructorProps<Options>): Extension<Options>;
558 /**
559 * The default priority level for all instance of this extension.
560 *
561 * @defaultValue ExtensionPriority.Default
562 */
563 readonly defaultPriority: ExtensionPriority;
564}
565export type AnyManagerStore = Remirror.ManagerStore<any>;
566export type ManagerStoreKeys = keyof Remirror.ManagerStore<any>;
567declare global {
568 /**
569 * This namespace is global and you can use declaration merging to extend and
570 * create new types used by the `remirror` project.
571 *
572 * @remarks
573 *
574 * The following would add `MyCustomType` to the `Remirror` namespace. Please
575 * note that this can only be used for types and interfaces.
576 *
577 * ```ts
578 * declare global {
579 * namespace Remirror {
580 * type MyCustomType = 'look-at-me';
581 * }
582 * }
583 * ```
584 */
585 namespace Remirror {
586 /**
587 * This interface stores all the currently installed extensions. As a result
588 * it can be used to set the default loaded extensions to include all
589 * available within `node_modules`. By extending this extension in the
590 * global `Remirror` namespace the key is ignored but the value is used to
591 * form the union type in the `chain`, `commands`, `helpers` properties on
592 * the `Remirror.ExtensionStore` interface.
593 *
594 * This is useful for extensions being able to reuse the work of other
595 * extension.
596 */
597 interface AllExtensions {
598 }
599 /**
600 * This is the global interface for adding extra methods and properties to
601 * all [[`Extension`]]s using declaration merging.
602 *
603 * @remarks
604 *
605 * The following will add `newOption` to the expected options. This is the
606 * way that extensions which add new functionality to the editor can request
607 * configuration options.
608 *
609 * ```ts
610 * declare global {
611 * namespace Remirror {
612 * interface ExtensionFactoryProps {
613 * newOption?: string;
614 * }
615 * }
616 * }
617 * ```
618 */
619 interface BaseExtension {
620 }
621 interface NodeExtension {
622 }
623 interface MarkExtension {
624 }
625 /**
626 * An override to for the `AnyExtension` type. If you're extension adds a
627 * new property to the `Extension` that is deeply nested or very complex it
628 * can break the `AnyExtension` implementation from being compatible with
629 * all valid extensions.
630 *
631 * The keys you provide on this override replace the default `AnyExtension`
632 * types include unsafe properties that need to be simplified.
633 *
634 * An example is the `constructor` property which makes it impossible to
635 * find a common interface between extensions with different settings and
636 * properties. By setting the `constructor` to a much simpler override all
637 * `Extension`'s are now assignable to the `AnyExtension type again.`
638 */
639 interface AnyExtensionOverrides extends AnyBaseClassOverrides {
640 constructor: AnyExtensionConstructor;
641 ['~C']: ExtensionCommandReturn;
642 ['~H']: ExtensionHelperReturn;
643 ['~E']: AnyExtension;
644 }
645 }
646}
647export type { Extension };