@domternal/core 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -10
- package/dist/index.cjs +1428 -221
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1835 -1360
- package/dist/index.d.ts +1835 -1360
- package/dist/index.js +1399 -214
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Schema, Node as Node$1, DOMOutputSpec, NodeType, Mark as Mark$1, MarkType, Attrs,
|
|
1
|
+
import { Schema, Node as Node$1, DOMOutputSpec, NodeType, Mark as Mark$1, MarkType, Attrs, ResolvedPos, DOMParser, ContentMatch, NodeSpec, MarkSpec } from '@domternal/pm/model';
|
|
2
2
|
import { Transaction, EditorState, Plugin, PluginKey, Selection as Selection$1 } from '@domternal/pm/state';
|
|
3
3
|
export { PluginKey } from '@domternal/pm/state';
|
|
4
4
|
import { InputRule } from '@domternal/pm/inputrules';
|
|
5
|
-
import {
|
|
5
|
+
import { NodeViewConstructor, EditorView } from '@domternal/pm/view';
|
|
6
6
|
import { Placement } from '@floating-ui/dom';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -131,8 +131,7 @@ interface ErrorEventProps$1 {
|
|
|
131
131
|
context: string;
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
|
-
* All editor events with their payload types
|
|
135
|
-
* Used by EventEmitter for type-safe event handling
|
|
134
|
+
* All editor events with their payload types.
|
|
136
135
|
*/
|
|
137
136
|
interface EditorEvents {
|
|
138
137
|
/** Fired before editor is created - can modify options */
|
|
@@ -169,6 +168,10 @@ interface EditorEvents {
|
|
|
169
168
|
linkEdit: {
|
|
170
169
|
anchorElement?: HTMLElement;
|
|
171
170
|
};
|
|
171
|
+
/** Fired when the Notion color picker should open, with the trigger as anchor. */
|
|
172
|
+
notionColorOpen: {
|
|
173
|
+
anchorElement?: HTMLElement | null;
|
|
174
|
+
};
|
|
172
175
|
}
|
|
173
176
|
/**
|
|
174
177
|
* Event names as a type
|
|
@@ -212,11 +215,9 @@ type FocusPosition = boolean | 'start' | 'end' | 'all' | number | null;
|
|
|
212
215
|
*/
|
|
213
216
|
interface EditorOptions {
|
|
214
217
|
/**
|
|
215
|
-
* ProseMirror Schema for the editor
|
|
216
|
-
*
|
|
217
|
-
* Step 1.3: Required (no extensions system yet)
|
|
218
|
-
* Step 2+: Optional if extensions are provided (schema built from extensions)
|
|
218
|
+
* ProseMirror Schema for the editor.
|
|
219
219
|
*
|
|
220
|
+
* Optional when `extensions` is provided (schema is built from them).
|
|
220
221
|
* The schema must contain at least 'doc' and 'text' nodes.
|
|
221
222
|
*/
|
|
222
223
|
schema?: Schema;
|
|
@@ -354,12 +355,12 @@ type Command = (props: CommandProps) => boolean;
|
|
|
354
355
|
* return true;
|
|
355
356
|
* };
|
|
356
357
|
*/
|
|
357
|
-
type CommandSpec
|
|
358
|
+
type CommandSpec<Args extends unknown[] = []> = (...args: Args) => Command;
|
|
358
359
|
/**
|
|
359
360
|
* Internal command storage used by CommandManager and ExtensionManager.
|
|
360
361
|
* Holds commands as a generic record for dynamic runtime collection.
|
|
361
362
|
*/
|
|
362
|
-
type CommandMap = Record<string, CommandSpec
|
|
363
|
+
type CommandMap = Record<string, CommandSpec<unknown[]>>;
|
|
363
364
|
/**
|
|
364
365
|
* Typed command interface for the public API.
|
|
365
366
|
*
|
|
@@ -384,7 +385,7 @@ interface RawCommands {
|
|
|
384
385
|
* These are accessed via editor.commands.commandName()
|
|
385
386
|
*/
|
|
386
387
|
type SingleCommands = {
|
|
387
|
-
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec
|
|
388
|
+
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec<infer Args> ? (...args: Args) => boolean : never;
|
|
388
389
|
};
|
|
389
390
|
/**
|
|
390
391
|
* Information about a command chain failure
|
|
@@ -402,7 +403,7 @@ interface ChainFailure {
|
|
|
402
403
|
* These are accessed via editor.chain().commandName().run()
|
|
403
404
|
*/
|
|
404
405
|
type ChainedCommands = {
|
|
405
|
-
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec
|
|
406
|
+
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec<infer Args> ? (...args: Args) => ChainedCommands : never;
|
|
406
407
|
} & {
|
|
407
408
|
/** Execute the command chain */
|
|
408
409
|
run: () => boolean;
|
|
@@ -414,7 +415,7 @@ type ChainedCommands = {
|
|
|
414
415
|
* These are accessed via editor.can().commandName()
|
|
415
416
|
*/
|
|
416
417
|
type CanCommands = {
|
|
417
|
-
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec
|
|
418
|
+
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec<infer Args> ? (...args: Args) => boolean : never;
|
|
418
419
|
} & {
|
|
419
420
|
/** Start a chain check */
|
|
420
421
|
chain: () => CanChainedCommands;
|
|
@@ -423,7 +424,7 @@ type CanCommands = {
|
|
|
423
424
|
* Chained commands for dry-run checking
|
|
424
425
|
*/
|
|
425
426
|
type CanChainedCommands = {
|
|
426
|
-
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec
|
|
427
|
+
[K in keyof RawCommands]: RawCommands[K] extends CommandSpec<infer Args> ? (...args: Args) => CanChainedCommands : never;
|
|
427
428
|
} & {
|
|
428
429
|
/** Check if the entire chain can be executed */
|
|
429
430
|
run: () => boolean;
|
|
@@ -480,7 +481,7 @@ interface ToolbarButton {
|
|
|
480
481
|
* How to check if this button is active.
|
|
481
482
|
* - string: extension name passed to `editor.isActive(name)`
|
|
482
483
|
* - object: `{ name, attributes }` passed to `editor.isActive(name, attributes)`
|
|
483
|
-
* - array: OR-check
|
|
484
|
+
* - array: OR-check - active if ANY entry matches (useful for attributes on multiple node types)
|
|
484
485
|
* - undefined: button has no active state (e.g. undo/redo)
|
|
485
486
|
*/
|
|
486
487
|
isActive?: string | {
|
|
@@ -602,1485 +603,1600 @@ interface ToolbarLayoutDropdown {
|
|
|
602
603
|
/**
|
|
603
604
|
* A single entry in a toolbar layout array.
|
|
604
605
|
*
|
|
605
|
-
* - `string`
|
|
606
|
-
* - `ToolbarLayoutDropdown`
|
|
606
|
+
* - `string` - item name (e.g. `'bold'`) or separator (`'|'`)
|
|
607
|
+
* - `ToolbarLayoutDropdown` - custom dropdown grouping
|
|
607
608
|
*/
|
|
608
609
|
type ToolbarLayoutEntry = string | ToolbarLayoutDropdown;
|
|
609
610
|
|
|
610
611
|
/**
|
|
611
|
-
*
|
|
612
|
+
* Callback type for event handlers
|
|
613
|
+
* - Events with payload: (data: T) => void
|
|
614
|
+
* - Events without payload (undefined): () => void
|
|
615
|
+
*/
|
|
616
|
+
type EventCallback<T> = T extends undefined ? () => void : (data: T) => void;
|
|
617
|
+
/**
|
|
618
|
+
* Generic, type-safe event emitter
|
|
612
619
|
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
620
|
+
* @example
|
|
621
|
+
* ```typescript
|
|
622
|
+
* interface MyEvents {
|
|
623
|
+
* update: { value: number };
|
|
624
|
+
* destroy: undefined;
|
|
625
|
+
* }
|
|
626
|
+
*
|
|
627
|
+
* const emitter = new EventEmitter<MyEvents>();
|
|
628
|
+
* emitter.on('update', ({ value }) => console.log(value));
|
|
629
|
+
* emitter.on('destroy', () => console.log('destroyed'));
|
|
630
|
+
* ```
|
|
615
631
|
*/
|
|
632
|
+
declare class EventEmitter<Events extends {
|
|
633
|
+
[K in keyof Events]: unknown;
|
|
634
|
+
} = Record<string, never>> {
|
|
635
|
+
protected callbacks: Map<keyof Events, Set<(data: unknown) => void>>;
|
|
636
|
+
/**
|
|
637
|
+
* Register an event listener
|
|
638
|
+
*/
|
|
639
|
+
on<E extends keyof Events>(event: E, callback: EventCallback<Events[E]>): this;
|
|
640
|
+
/**
|
|
641
|
+
* Remove an event listener, or all listeners for an event if no callback specified
|
|
642
|
+
*/
|
|
643
|
+
off<E extends keyof Events>(event: E, callback?: EventCallback<Events[E]>): this;
|
|
644
|
+
/**
|
|
645
|
+
* Emit an event to all registered listeners
|
|
646
|
+
* Uses .call(this) to preserve context for callbacks
|
|
647
|
+
*/
|
|
648
|
+
emit<E extends keyof Events>(event: E, ...args: Events[E] extends undefined ? [] : [Events[E]]): this;
|
|
649
|
+
/**
|
|
650
|
+
* Register an event listener that fires only once
|
|
651
|
+
*/
|
|
652
|
+
once<E extends keyof Events>(event: E, callback: EventCallback<Events[E]>): this;
|
|
653
|
+
/**
|
|
654
|
+
* Remove all listeners for a specific event, or all events if no event specified
|
|
655
|
+
*/
|
|
656
|
+
removeAllListeners(event?: keyof Events): this;
|
|
657
|
+
/**
|
|
658
|
+
* Get the number of listeners for a specific event
|
|
659
|
+
*/
|
|
660
|
+
listenerCount(event: keyof Events): number;
|
|
661
|
+
/**
|
|
662
|
+
* Get all event names that have listeners
|
|
663
|
+
*/
|
|
664
|
+
eventNames(): (keyof Events)[];
|
|
665
|
+
}
|
|
616
666
|
|
|
617
667
|
/**
|
|
618
|
-
*
|
|
668
|
+
* ExtensionManager - manages extensions and schema.
|
|
669
|
+
*
|
|
670
|
+
* Handles:
|
|
671
|
+
* - Extension lifecycle (flatten, resolve, bind)
|
|
672
|
+
* - Schema building from Node/Mark extensions
|
|
673
|
+
* - Plugin collection from all extensions
|
|
674
|
+
* - Extension storage management
|
|
675
|
+
* - Conflict detection (duplicate extension names)
|
|
619
676
|
*/
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Error event props for safeCall
|
|
680
|
+
*/
|
|
681
|
+
interface ErrorEventProps {
|
|
682
|
+
error: Error;
|
|
683
|
+
context: string;
|
|
625
684
|
}
|
|
626
685
|
/**
|
|
627
|
-
*
|
|
686
|
+
* Editor interface for ExtensionManager
|
|
687
|
+
* Forward declaration to avoid circular dependency
|
|
628
688
|
*/
|
|
629
|
-
interface
|
|
630
|
-
|
|
631
|
-
|
|
689
|
+
interface ExtensionManagerEditor {
|
|
690
|
+
readonly schema: Schema;
|
|
691
|
+
emit?(event: 'error', props: ErrorEventProps): void;
|
|
632
692
|
}
|
|
633
693
|
/**
|
|
634
|
-
*
|
|
635
|
-
*
|
|
694
|
+
* Context attached to node view constructors for framework wrappers.
|
|
695
|
+
* Accessible via `(constructor as any).__domternalContext`.
|
|
636
696
|
*/
|
|
637
|
-
interface
|
|
697
|
+
interface NodeViewContext {
|
|
698
|
+
editor: ExtensionManagerEditor;
|
|
699
|
+
extension: {
|
|
700
|
+
name: string;
|
|
701
|
+
options: Record<string, unknown>;
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Options for ExtensionManager constructor
|
|
706
|
+
*/
|
|
707
|
+
interface ExtensionManagerOptions {
|
|
638
708
|
/**
|
|
639
|
-
*
|
|
709
|
+
* Extensions to process
|
|
710
|
+
* If provided, schema is built from extensions
|
|
640
711
|
*/
|
|
641
|
-
|
|
712
|
+
extensions?: AnyExtension[] | undefined;
|
|
642
713
|
/**
|
|
643
|
-
*
|
|
644
|
-
* @param element - The DOM element to parse from
|
|
645
|
-
* @returns The parsed attribute value
|
|
714
|
+
* Direct schema. If provided, extensions are ignored for schema building.
|
|
646
715
|
*/
|
|
647
|
-
|
|
716
|
+
schema?: Schema | undefined;
|
|
717
|
+
}
|
|
718
|
+
declare class ExtensionManager {
|
|
648
719
|
/**
|
|
649
|
-
*
|
|
650
|
-
* @param attributes - The node/mark attributes
|
|
651
|
-
* @returns Object of HTML attributes to set, or null/empty to skip
|
|
720
|
+
* Processed extensions (flattened, sorted by priority)
|
|
652
721
|
*/
|
|
653
|
-
|
|
654
|
-
}
|
|
655
|
-
/**
|
|
656
|
-
* Global attributes definition for injecting into node/mark types.
|
|
657
|
-
*/
|
|
658
|
-
interface GlobalAttributes {
|
|
722
|
+
private readonly _extensions;
|
|
659
723
|
/**
|
|
660
|
-
*
|
|
661
|
-
* @example ['heading', 'paragraph']
|
|
724
|
+
* ProseMirror schema (built from extensions or passed directly)
|
|
662
725
|
*/
|
|
663
|
-
|
|
726
|
+
private readonly _schema;
|
|
664
727
|
/**
|
|
665
|
-
*
|
|
666
|
-
* @example { textAlign: { default: 'left', parseHTML: (el) => el.style.textAlign } }
|
|
728
|
+
* Reference to the editor instance
|
|
667
729
|
*/
|
|
668
|
-
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* Context interface that describes what `this` will be in config methods.
|
|
672
|
-
* This enables proper typing of `this.options`, `this.editor`, etc.
|
|
673
|
-
* without creating circular dependencies.
|
|
674
|
-
*
|
|
675
|
-
* @typeParam Options - Extension options type
|
|
676
|
-
* @typeParam Storage - Extension storage type
|
|
677
|
-
*/
|
|
678
|
-
interface ExtensionContext<Options = unknown, Storage = unknown> {
|
|
679
|
-
/** Extension type identifier */
|
|
680
|
-
readonly type: 'extension' | 'node' | 'mark';
|
|
681
|
-
/** Unique extension name */
|
|
682
|
-
readonly name: string;
|
|
683
|
-
/** Extension options (immutable after creation) */
|
|
684
|
-
readonly options: Options;
|
|
685
|
-
/** Extension storage (mutable state) */
|
|
686
|
-
storage: Storage;
|
|
687
|
-
/** Editor instance (null until bound by ExtensionManager) */
|
|
688
|
-
editor: ExtensionEditor | null;
|
|
730
|
+
readonly editor: ExtensionManagerEditor;
|
|
689
731
|
/**
|
|
690
|
-
*
|
|
691
|
-
* Available only inside overridden config methods.
|
|
692
|
-
* Use `this.parent?.()` to call the parent's version of the current method.
|
|
732
|
+
* Extension storage (keyed by extension name)
|
|
693
733
|
*/
|
|
694
|
-
|
|
695
|
-
}
|
|
696
|
-
/**
|
|
697
|
-
* Base configuration properties for all extension types.
|
|
698
|
-
* This interface contains just the properties without ThisType,
|
|
699
|
-
* allowing Node and Mark configs to use their own context types.
|
|
700
|
-
*
|
|
701
|
-
* @typeParam Options - Extension options type
|
|
702
|
-
* @typeParam Storage - Extension storage type
|
|
703
|
-
*/
|
|
704
|
-
interface ExtensionConfigBase<Options = unknown, Storage = unknown> {
|
|
734
|
+
private readonly _storage;
|
|
705
735
|
/**
|
|
706
|
-
*
|
|
707
|
-
* Used for identification, storage access, and error messages
|
|
736
|
+
* Whether the manager has been destroyed
|
|
708
737
|
*/
|
|
709
|
-
|
|
738
|
+
private isDestroyed;
|
|
710
739
|
/**
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
* Reserved ranges:
|
|
714
|
-
* - 900-1000: Core nodes (Document, Text, Paragraph)
|
|
715
|
-
* - 500-899: Standard extensions (Heading, Bold, etc.)
|
|
716
|
-
* - 100-499: Default range for user extensions
|
|
717
|
-
* - 0-99: Low priority extensions (run after everything)
|
|
718
|
-
*
|
|
719
|
-
* @default 100
|
|
740
|
+
* Cached plugins (built lazily)
|
|
720
741
|
*/
|
|
721
|
-
|
|
742
|
+
private _plugins;
|
|
722
743
|
/**
|
|
723
|
-
*
|
|
724
|
-
* ExtensionManager throws if any dependency is missing
|
|
725
|
-
*
|
|
726
|
-
* @example
|
|
727
|
-
* dependencies: ['bulletList', 'orderedList']
|
|
744
|
+
* Cached commands (collected lazily)
|
|
728
745
|
*/
|
|
729
|
-
|
|
746
|
+
private _commands;
|
|
730
747
|
/**
|
|
731
|
-
*
|
|
732
|
-
* Called during extension creation with `this` bound to the extension
|
|
748
|
+
* Cached toolbar items (collected lazily)
|
|
733
749
|
*/
|
|
734
|
-
|
|
750
|
+
private _toolbarItems;
|
|
735
751
|
/**
|
|
736
|
-
*
|
|
737
|
-
* Storage is mutable and accessible via editor.storage[extensionName]
|
|
752
|
+
* Cached floating-menu items (collected lazily)
|
|
738
753
|
*/
|
|
739
|
-
|
|
754
|
+
private _floatingMenuItems;
|
|
740
755
|
/**
|
|
741
|
-
*
|
|
742
|
-
* Commands are accessible via editor.commands.commandName()
|
|
743
|
-
*
|
|
744
|
-
* @example
|
|
745
|
-
* addCommands() {
|
|
746
|
-
* return {
|
|
747
|
-
* toggleBold: () => ({ commands }) => commands.toggleMark('bold'),
|
|
748
|
-
* };
|
|
749
|
-
* }
|
|
756
|
+
* Cached node views (collected lazily)
|
|
750
757
|
*/
|
|
751
|
-
|
|
758
|
+
private _nodeViews;
|
|
752
759
|
/**
|
|
753
|
-
*
|
|
754
|
-
* Keys are shortcut strings (e.g., 'Mod-b'), values are handler functions
|
|
760
|
+
* Creates a new ExtensionManager
|
|
755
761
|
*
|
|
756
|
-
* @
|
|
757
|
-
*
|
|
758
|
-
* return {
|
|
759
|
-
* 'Mod-b': () => this.editor.commands.toggleBold(),
|
|
760
|
-
* };
|
|
761
|
-
* }
|
|
762
|
+
* @param options - Extensions or direct schema
|
|
763
|
+
* @param editor - Editor instance
|
|
762
764
|
*/
|
|
763
|
-
|
|
765
|
+
constructor(options: ExtensionManagerOptions, editor: ExtensionManagerEditor);
|
|
764
766
|
/**
|
|
765
|
-
*
|
|
766
|
-
* Triggered when user types matching patterns
|
|
767
|
-
*
|
|
768
|
-
* @example
|
|
769
|
-
* addInputRules() {
|
|
770
|
-
* return [
|
|
771
|
-
* textblockTypeInputRule(/^## $/, this.type),
|
|
772
|
-
* ];
|
|
773
|
-
* }
|
|
767
|
+
* Gets the processed extensions array
|
|
774
768
|
*/
|
|
775
|
-
|
|
769
|
+
get extensions(): readonly AnyExtension[];
|
|
776
770
|
/**
|
|
777
|
-
*
|
|
771
|
+
* Gets the ProseMirror schema
|
|
778
772
|
*/
|
|
779
|
-
|
|
773
|
+
get schema(): Schema;
|
|
780
774
|
/**
|
|
781
|
-
*
|
|
782
|
-
* These extensions are flattened and processed like top-level extensions
|
|
775
|
+
* Gets extension storage (accessed via editor.storage)
|
|
783
776
|
*/
|
|
784
|
-
|
|
777
|
+
get storage(): Record<string, unknown>;
|
|
785
778
|
/**
|
|
786
|
-
*
|
|
787
|
-
*
|
|
788
|
-
* to several nodes (heading, paragraph, etc.) without modifying each.
|
|
789
|
-
*
|
|
790
|
-
* @example
|
|
791
|
-
* addGlobalAttributes() {
|
|
792
|
-
* return [{
|
|
793
|
-
* types: ['heading', 'paragraph'],
|
|
794
|
-
* attributes: {
|
|
795
|
-
* textAlign: {
|
|
796
|
-
* default: 'left',
|
|
797
|
-
* parseHTML: (element) => element.style.textAlign || 'left',
|
|
798
|
-
* renderHTML: (attrs) => attrs.textAlign !== 'left'
|
|
799
|
-
* ? { style: `text-align: ${attrs.textAlign}` }
|
|
800
|
-
* : null,
|
|
801
|
-
* },
|
|
802
|
-
* },
|
|
803
|
-
* }];
|
|
804
|
-
* }
|
|
805
|
-
*/
|
|
806
|
-
addGlobalAttributes?: () => GlobalAttributes[];
|
|
807
|
-
/**
|
|
808
|
-
* Toolbar items this extension contributes.
|
|
809
|
-
* Framework toolbar components read these to auto-generate buttons.
|
|
810
|
-
*
|
|
811
|
-
* @example
|
|
812
|
-
* addToolbarItems() {
|
|
813
|
-
* return [{
|
|
814
|
-
* type: 'button',
|
|
815
|
-
* name: 'bold',
|
|
816
|
-
* command: 'toggleBold',
|
|
817
|
-
* isActive: 'bold',
|
|
818
|
-
* icon: 'textB',
|
|
819
|
-
* label: 'Bold',
|
|
820
|
-
* shortcut: 'Mod-b',
|
|
821
|
-
* group: 'format',
|
|
822
|
-
* }];
|
|
823
|
-
* }
|
|
779
|
+
* Gets plugins from all extensions
|
|
780
|
+
* Cached after first call
|
|
824
781
|
*/
|
|
825
|
-
|
|
782
|
+
get plugins(): Plugin[];
|
|
826
783
|
/**
|
|
827
|
-
*
|
|
828
|
-
* Can be used to modify editor options
|
|
784
|
+
* Gets commands from all extensions
|
|
829
785
|
*/
|
|
830
|
-
|
|
786
|
+
get commands(): CommandMap;
|
|
831
787
|
/**
|
|
832
|
-
*
|
|
788
|
+
* Gets toolbar items from all extensions
|
|
789
|
+
* Cached after first call
|
|
833
790
|
*/
|
|
834
|
-
|
|
791
|
+
get toolbarItems(): ToolbarItem[];
|
|
835
792
|
/**
|
|
836
|
-
*
|
|
793
|
+
* Gets floating-menu items from all extensions
|
|
794
|
+
* Cached after first call
|
|
837
795
|
*/
|
|
838
|
-
|
|
796
|
+
get floatingMenuItems(): FloatingMenuItem[];
|
|
839
797
|
/**
|
|
840
|
-
*
|
|
798
|
+
* Gets node views from all Node extensions that define addNodeView
|
|
841
799
|
*/
|
|
842
|
-
|
|
800
|
+
get nodeViews(): Record<string, NodeViewConstructor>;
|
|
843
801
|
/**
|
|
844
|
-
*
|
|
845
|
-
*
|
|
802
|
+
* Clears all caches (plugins, commands)
|
|
803
|
+
* Call when extensions change dynamically
|
|
846
804
|
*/
|
|
847
|
-
|
|
848
|
-
transaction: Transaction;
|
|
849
|
-
}) => void;
|
|
805
|
+
clearAllCaches(): void;
|
|
850
806
|
/**
|
|
851
|
-
*
|
|
807
|
+
* Recursively flattens extensions by expanding addExtensions()
|
|
808
|
+
* This allows extension bundles like StarterKit to work
|
|
852
809
|
*/
|
|
853
|
-
|
|
854
|
-
event: FocusEvent;
|
|
855
|
-
}) => void;
|
|
810
|
+
private flattenExtensions;
|
|
856
811
|
/**
|
|
857
|
-
*
|
|
812
|
+
* Removes duplicate extensions by name, keeping the last occurrence.
|
|
813
|
+
* This allows parent extensions to auto-include children via addExtensions()
|
|
814
|
+
* while letting users override with explicitly configured versions.
|
|
858
815
|
*/
|
|
859
|
-
|
|
860
|
-
event: FocusEvent;
|
|
861
|
-
}) => void;
|
|
816
|
+
private deduplicateExtensions;
|
|
862
817
|
/**
|
|
863
|
-
*
|
|
864
|
-
*
|
|
818
|
+
* Sorts extensions by priority (higher priority first)
|
|
819
|
+
* Default priority is 100
|
|
865
820
|
*/
|
|
866
|
-
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* Full configuration type for Extension.create()
|
|
870
|
-
* Combines base properties with ThisType for proper `this` typing.
|
|
871
|
-
*
|
|
872
|
-
* @typeParam Options - Extension options type
|
|
873
|
-
* @typeParam Storage - Extension storage type
|
|
874
|
-
*/
|
|
875
|
-
type ExtensionConfig<Options = unknown, Storage = unknown> = ExtensionConfigBase<Options, Storage> & ThisType<ExtensionContext<Options, Storage>>;
|
|
876
|
-
|
|
877
|
-
/**
|
|
878
|
-
* Attribute specification for Node and Mark extensions
|
|
879
|
-
*
|
|
880
|
-
* Used by addAttributes() to define node/mark attributes
|
|
881
|
-
* with parsing, rendering, and validation rules.
|
|
882
|
-
*
|
|
883
|
-
* @example
|
|
884
|
-
* addAttributes() {
|
|
885
|
-
* return {
|
|
886
|
-
* level: {
|
|
887
|
-
* default: 1,
|
|
888
|
-
* parseHTML: (element) => parseInt(element.tagName.charAt(1), 10),
|
|
889
|
-
* renderHTML: (attributes) => ({ 'data-level': attributes.level }),
|
|
890
|
-
* },
|
|
891
|
-
* };
|
|
892
|
-
* }
|
|
893
|
-
*/
|
|
894
|
-
/**
|
|
895
|
-
* Specification for a single attribute
|
|
896
|
-
*/
|
|
897
|
-
interface AttributeSpec {
|
|
821
|
+
private resolveExtensions;
|
|
898
822
|
/**
|
|
899
|
-
*
|
|
900
|
-
*
|
|
823
|
+
* Detects duplicate extension names.
|
|
824
|
+
* @throws Error if duplicate names found
|
|
901
825
|
*/
|
|
902
|
-
|
|
826
|
+
private detectConflicts;
|
|
903
827
|
/**
|
|
904
|
-
*
|
|
905
|
-
* @
|
|
828
|
+
* Validates that all extension dependencies are present
|
|
829
|
+
* @throws Error if required dependency is missing
|
|
906
830
|
*/
|
|
907
|
-
|
|
831
|
+
private checkDependencies;
|
|
908
832
|
/**
|
|
909
|
-
*
|
|
910
|
-
* For example, heading level should be kept when pressing Enter
|
|
911
|
-
* @default true
|
|
833
|
+
* Sets editor reference on all extensions
|
|
912
834
|
*/
|
|
913
|
-
|
|
835
|
+
private bindEditorToExtensions;
|
|
914
836
|
/**
|
|
915
|
-
*
|
|
916
|
-
*
|
|
917
|
-
* (`"number"`, `"string"`, `"boolean"`, `"null"`, `"undefined"`).
|
|
918
|
-
* When a function, it should throw if the value is invalid.
|
|
919
|
-
*
|
|
920
|
-
* @example
|
|
921
|
-
* validate: 'number'
|
|
922
|
-
* validate: 'string|null'
|
|
923
|
-
* validate: (value) => { if (typeof value !== 'number') throw new Error('expected number'); }
|
|
837
|
+
* Collects global attributes from all extensions.
|
|
838
|
+
* Returns a map of type name -> attribute specs to merge.
|
|
924
839
|
*/
|
|
925
|
-
|
|
840
|
+
private collectGlobalAttributes;
|
|
926
841
|
/**
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
*
|
|
931
|
-
* @returns The attribute value
|
|
932
|
-
*
|
|
933
|
-
* @example
|
|
934
|
-
* parseHTML: (element) => element.getAttribute('data-level')
|
|
842
|
+
* Applies global attributes to a node or mark spec.
|
|
843
|
+
* Merges extra attrs into spec.attrs, wraps parseDOM getAttrs to parse
|
|
844
|
+
* global attributes from DOM elements, and wraps toDOM to inject rendered
|
|
845
|
+
* global HTML attributes into the output.
|
|
935
846
|
*/
|
|
936
|
-
|
|
847
|
+
private applyGlobalAttributes;
|
|
937
848
|
/**
|
|
938
|
-
*
|
|
939
|
-
* Called during HTML serialization
|
|
940
|
-
*
|
|
941
|
-
* @param attributes - All attributes of the node/mark
|
|
942
|
-
* @returns HTML attributes object or null to skip
|
|
943
|
-
*
|
|
944
|
-
* @example
|
|
945
|
-
* renderHTML: (attributes) => ({ 'data-level': attributes.level })
|
|
849
|
+
* Builds ProseMirror Schema from Node and Mark extensions
|
|
946
850
|
*/
|
|
947
|
-
|
|
948
|
-
}
|
|
949
|
-
/**
|
|
950
|
-
* Collection of attribute specifications
|
|
951
|
-
* Keyed by attribute name
|
|
952
|
-
*/
|
|
953
|
-
type AttributeSpecs = Record<string, AttributeSpec>;
|
|
954
|
-
|
|
955
|
-
/**
|
|
956
|
-
* Node configuration types
|
|
957
|
-
*
|
|
958
|
-
* These types define the configuration object passed to Node.create()
|
|
959
|
-
* for creating ProseMirror node extensions.
|
|
960
|
-
*/
|
|
961
|
-
|
|
962
|
-
/**
|
|
963
|
-
* Editor interface for Node context
|
|
964
|
-
* Includes schema with nodes for NodeType getter
|
|
965
|
-
*/
|
|
966
|
-
interface NodeEditorContext {
|
|
967
|
-
readonly state: EditorState;
|
|
968
|
-
readonly view: EditorView;
|
|
969
|
-
readonly schema: {
|
|
970
|
-
nodes: Record<string, NodeType>;
|
|
971
|
-
};
|
|
972
|
-
readonly commands: Record<string, (...args: unknown[]) => boolean>;
|
|
973
|
-
}
|
|
974
|
-
/**
|
|
975
|
-
* Context interface for Node config methods.
|
|
976
|
-
* Extends ExtensionContext with node-specific properties.
|
|
977
|
-
* This enables proper typing of `this.options`, `this.nodeType`, etc.
|
|
978
|
-
*
|
|
979
|
-
* @typeParam Options - Node options type
|
|
980
|
-
* @typeParam Storage - Node storage type
|
|
981
|
-
*/
|
|
982
|
-
interface NodeContext<Options = unknown, Storage = unknown> extends Omit<ExtensionContext<Options, Storage>, 'editor' | 'type'> {
|
|
983
|
-
/** Node type identifier */
|
|
984
|
-
readonly type: 'node';
|
|
985
|
-
/** Editor instance with schema access */
|
|
986
|
-
editor: NodeEditorContext | null;
|
|
987
|
-
/** ProseMirror NodeType (null until editor is initialized) */
|
|
988
|
-
readonly nodeType: NodeType | null;
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Parse rule for converting HTML to ProseMirror node
|
|
992
|
-
* Simplified version of ProseMirror's ParseRule
|
|
993
|
-
*/
|
|
994
|
-
interface NodeParseRule {
|
|
851
|
+
private buildSchema;
|
|
995
852
|
/**
|
|
996
|
-
*
|
|
997
|
-
* @example 'p', 'h1', 'div.my-class'
|
|
853
|
+
* Initializes storage for all extensions
|
|
998
854
|
*/
|
|
999
|
-
|
|
855
|
+
private initializeStorage;
|
|
1000
856
|
/**
|
|
1001
|
-
*
|
|
1002
|
-
* @example 'font-weight'
|
|
857
|
+
* Builds all ProseMirror plugins from extensions
|
|
1003
858
|
*/
|
|
1004
|
-
|
|
859
|
+
private buildPlugins;
|
|
1005
860
|
/**
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
861
|
+
* Collects keyboard shortcuts from all extensions
|
|
862
|
+
* Returns ProseMirror-compatible commands for keymap plugin
|
|
863
|
+
*
|
|
864
|
+
* Note: Extensions should return PM-compatible commands from addKeyboardShortcuts()
|
|
1008
865
|
*/
|
|
1009
|
-
|
|
866
|
+
private collectKeyboardShortcuts;
|
|
1010
867
|
/**
|
|
1011
|
-
*
|
|
1012
|
-
* @default true
|
|
868
|
+
* Collects input rules from all extensions
|
|
1013
869
|
*/
|
|
1014
|
-
|
|
870
|
+
private collectInputRules;
|
|
1015
871
|
/**
|
|
1016
|
-
*
|
|
1017
|
-
*
|
|
872
|
+
* Collects commands from all extensions
|
|
873
|
+
*
|
|
874
|
+
* Note: Commands with the same name will be overwritten by later extensions
|
|
875
|
+
* (lower priority extensions override higher priority). This is intentional
|
|
876
|
+
* to allow customization of built-in commands.
|
|
1018
877
|
*/
|
|
1019
|
-
|
|
878
|
+
private collectCommands;
|
|
1020
879
|
/**
|
|
1021
|
-
*
|
|
1022
|
-
* Return null/undefined to skip this rule
|
|
880
|
+
* Collects toolbar items from all extensions
|
|
1023
881
|
*/
|
|
1024
|
-
|
|
882
|
+
private collectToolbarItems;
|
|
1025
883
|
/**
|
|
1026
|
-
*
|
|
1027
|
-
* Return false to use default content parsing
|
|
884
|
+
* Collects floating-menu items from all extensions via `addFloatingMenuItems()`.
|
|
1028
885
|
*/
|
|
1029
|
-
|
|
886
|
+
private collectFloatingMenuItems;
|
|
1030
887
|
/**
|
|
1031
|
-
*
|
|
1032
|
-
|
|
1033
|
-
preserveWhitespace?: boolean | 'full';
|
|
1034
|
-
}
|
|
1035
|
-
/**
|
|
1036
|
-
* Props passed to renderHTML function
|
|
1037
|
-
*/
|
|
1038
|
-
interface NodeRenderHTMLProps {
|
|
1039
|
-
/**
|
|
1040
|
-
* The ProseMirror node being rendered
|
|
1041
|
-
*/
|
|
1042
|
-
node: Node$1;
|
|
1043
|
-
/**
|
|
1044
|
-
* Merged HTML attributes from all sources
|
|
1045
|
-
*/
|
|
1046
|
-
HTMLAttributes: Record<string, unknown>;
|
|
1047
|
-
}
|
|
1048
|
-
/**
|
|
1049
|
-
* Node-specific configuration properties (schema-related)
|
|
1050
|
-
*/
|
|
1051
|
-
interface NodeSchemaProperties {
|
|
1052
|
-
/**
|
|
1053
|
-
* Node group(s) this node belongs to
|
|
1054
|
-
* Used in content expressions
|
|
888
|
+
* Collects node views from all Node extensions.
|
|
889
|
+
* Returns a map of node name to NodeViewConstructor for EditorView.
|
|
1055
890
|
*
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
891
|
+
* Each constructor is annotated with `__domternalContext` containing
|
|
892
|
+
* the editor and extension metadata so framework wrappers (React, Vue)
|
|
893
|
+
* can access them without changing the ProseMirror calling convention.
|
|
1058
894
|
*/
|
|
1059
|
-
|
|
895
|
+
private collectNodeViews;
|
|
1060
896
|
/**
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
* @example 'inline*', 'block+', 'paragraph block*'
|
|
897
|
+
* Validates that the schema has required nodes
|
|
898
|
+
* @throws Error if schema is missing 'doc' or 'text' nodes
|
|
1065
899
|
*/
|
|
1066
|
-
|
|
900
|
+
validateSchema(): void;
|
|
1067
901
|
/**
|
|
1068
|
-
*
|
|
1069
|
-
*
|
|
1070
|
-
* @default false
|
|
902
|
+
* Cleans up the extension manager
|
|
903
|
+
* Calls onDestroy on all extensions and clears all caches
|
|
1071
904
|
*/
|
|
1072
|
-
|
|
905
|
+
destroy(): void;
|
|
1073
906
|
/**
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
907
|
+
* Safely executes a function, catching and reporting errors
|
|
908
|
+
* Prevents a single extension error from crashing the entire editor
|
|
1076
909
|
*
|
|
1077
|
-
*
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
*
|
|
1082
|
-
* @default true for leaf nodes, false for others
|
|
1083
|
-
*/
|
|
1084
|
-
selectable?: boolean;
|
|
1085
|
-
/**
|
|
1086
|
-
* Whether the node can be dragged
|
|
1087
|
-
* @default false
|
|
1088
|
-
*/
|
|
1089
|
-
draggable?: boolean;
|
|
1090
|
-
/**
|
|
1091
|
-
* Whether this node represents code
|
|
1092
|
-
* Affects text input handling (disables smart quotes, etc.)
|
|
1093
|
-
*/
|
|
1094
|
-
code?: boolean;
|
|
1095
|
-
/**
|
|
1096
|
-
* How whitespace is handled in this node
|
|
1097
|
-
* - 'pre': preserve whitespace (like <pre>)
|
|
1098
|
-
* - 'normal': collapse whitespace (default)
|
|
910
|
+
* Handles both synchronous errors and async promise rejections.
|
|
911
|
+
*
|
|
912
|
+
* @param fn - Function to execute
|
|
913
|
+
* @param context - Context for error reporting (e.g., 'Bold.onUpdate')
|
|
914
|
+
* @returns The function result, or undefined if an error occurred
|
|
1099
915
|
*/
|
|
1100
|
-
|
|
916
|
+
safeCall<T>(fn: () => T, context: string): T | undefined;
|
|
1101
917
|
/**
|
|
1102
|
-
*
|
|
1103
|
-
* Marks don't extend across isolating boundaries
|
|
918
|
+
* Calls onBeforeCreate on all extensions
|
|
1104
919
|
*/
|
|
1105
|
-
|
|
920
|
+
callOnBeforeCreate(): void;
|
|
1106
921
|
/**
|
|
1107
|
-
*
|
|
1108
|
-
* Set to false to prevent gapcursor from appearing inside this node.
|
|
1109
|
-
* Set to true to force gapcursor even if the default heuristic disallows it.
|
|
1110
|
-
* When undefined, uses ProseMirror's default heuristic.
|
|
922
|
+
* Calls onCreate on all extensions
|
|
1111
923
|
*/
|
|
1112
|
-
|
|
924
|
+
callOnCreate(): void;
|
|
1113
925
|
/**
|
|
1114
|
-
*
|
|
1115
|
-
* Nodes with a tableRole are discovered by prosemirror-tables via spec.tableRole.
|
|
1116
|
-
* One of: 'table', 'row', 'cell', 'header_cell'
|
|
926
|
+
* Calls onUpdate on all extensions
|
|
1117
927
|
*/
|
|
1118
|
-
|
|
928
|
+
callOnUpdate(): void;
|
|
1119
929
|
/**
|
|
1120
|
-
*
|
|
1121
|
-
* Only one node should have this set to true
|
|
930
|
+
* Calls onSelectionUpdate on all extensions
|
|
1122
931
|
*/
|
|
1123
|
-
|
|
932
|
+
callOnSelectionUpdate(): void;
|
|
1124
933
|
/**
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
934
|
+
* Calls onTransaction on all extensions
|
|
935
|
+
* @param props - Transaction props
|
|
1127
936
|
*/
|
|
1128
|
-
|
|
937
|
+
callOnTransaction(props: {
|
|
938
|
+
transaction: Transaction;
|
|
939
|
+
}): void;
|
|
1129
940
|
/**
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
* @example '', '_', 'bold italic'
|
|
941
|
+
* Calls onFocus on all extensions
|
|
942
|
+
* @param props - Focus event props
|
|
1134
943
|
*/
|
|
1135
|
-
|
|
944
|
+
callOnFocus(props: {
|
|
945
|
+
event: FocusEvent;
|
|
946
|
+
}): void;
|
|
1136
947
|
/**
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
* @example '\n' for hard break
|
|
948
|
+
* Calls onBlur on all extensions
|
|
949
|
+
* @param props - Blur event props
|
|
1141
950
|
*/
|
|
1142
|
-
|
|
951
|
+
callOnBlur(props: {
|
|
952
|
+
event: FocusEvent;
|
|
953
|
+
}): void;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Inline Styles Utility
|
|
958
|
+
*
|
|
959
|
+
* Applies inline CSS styles to serialized HTML so it renders correctly
|
|
960
|
+
* when pasted outside the editor (email clients, CMS, Google Docs, etc.).
|
|
961
|
+
*
|
|
962
|
+
* Uses hardcoded light-theme defaults (same approach as Google Docs, Notion,
|
|
963
|
+
* TinyMCE). Optionally accepts overrides for custom styling.
|
|
964
|
+
*
|
|
965
|
+
* Only structural styles are inlined (borders, padding, margins, fonts).
|
|
966
|
+
* Colors are NOT inlined - explicit colors (TextColor, Highlight, cell bg)
|
|
967
|
+
* are already inline from renderHTML, and default text color is browser default.
|
|
968
|
+
*/
|
|
969
|
+
interface InlineStyleOverrides {
|
|
970
|
+
blockquoteBorder?: string;
|
|
971
|
+
blockquoteColor?: string;
|
|
972
|
+
tableBorder?: string;
|
|
973
|
+
tableHeaderBg?: string;
|
|
974
|
+
codeBg?: string;
|
|
975
|
+
codeFont?: string;
|
|
976
|
+
codeBorder?: string;
|
|
977
|
+
codeBlockBg?: string;
|
|
978
|
+
codeBlockFont?: string;
|
|
979
|
+
hrBorder?: string;
|
|
980
|
+
linkColor?: string;
|
|
981
|
+
detailsBorder?: string;
|
|
982
|
+
detailsBg?: string;
|
|
1143
983
|
/**
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
1146
|
-
*
|
|
1147
|
-
*
|
|
1148
|
-
* addAttributes() {
|
|
1149
|
-
* return {
|
|
1150
|
-
* level: { default: 1 },
|
|
1151
|
-
* };
|
|
1152
|
-
* }
|
|
984
|
+
* How to export table column widths from `data-colwidth` attributes.
|
|
985
|
+
* - `'percent'` (default): convert to percentage widths on first-row cells
|
|
986
|
+
* - `'pixel'`: convert to pixel widths on first-row cells, table gets fixed width
|
|
987
|
+
* - `'none'`: leave `data-colwidth` as-is, no width styles applied
|
|
1153
988
|
*/
|
|
1154
|
-
|
|
989
|
+
tableColumnWidths?: 'percent' | 'pixel' | 'none';
|
|
1155
990
|
/**
|
|
1156
|
-
*
|
|
1157
|
-
*
|
|
991
|
+
* Optional callback to syntax-highlight code blocks.
|
|
992
|
+
* Receives the raw text content and optional language, returns highlighted HTML
|
|
993
|
+
* with `<span class="hljs-*">` markup (or any spans with inline styles).
|
|
1158
994
|
*
|
|
1159
995
|
* @example
|
|
1160
|
-
*
|
|
1161
|
-
*
|
|
1162
|
-
*
|
|
1163
|
-
*
|
|
1164
|
-
* ];
|
|
1165
|
-
* }
|
|
1166
|
-
*/
|
|
1167
|
-
parseHTML?: () => NodeParseRule[];
|
|
1168
|
-
/**
|
|
1169
|
-
* Render this node to DOM
|
|
1170
|
-
* Returns DOMOutputSpec (tag, attributes, children)
|
|
996
|
+
* ```ts
|
|
997
|
+
* import { createLowlight, common } from 'lowlight';
|
|
998
|
+
* import { toHtml } from 'hast-util-to-html';
|
|
999
|
+
* const lowlight = createLowlight(common);
|
|
1171
1000
|
*
|
|
1172
|
-
*
|
|
1173
|
-
*
|
|
1174
|
-
*
|
|
1175
|
-
*
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
*
|
|
1180
|
-
*
|
|
1181
|
-
*/
|
|
1182
|
-
addNodeView?: () => NodeViewConstructor;
|
|
1183
|
-
/**
|
|
1184
|
-
* Additional ProseMirror plugins for this node
|
|
1185
|
-
* Called during plugin collection
|
|
1001
|
+
* inlineStyles(html, {
|
|
1002
|
+
* codeHighlighter: (code, language) => {
|
|
1003
|
+
* if (language && lowlight.registered(language)) {
|
|
1004
|
+
* return toHtml(lowlight.highlight(language, code));
|
|
1005
|
+
* }
|
|
1006
|
+
* return null; // no highlighting
|
|
1007
|
+
* },
|
|
1008
|
+
* });
|
|
1009
|
+
* ```
|
|
1186
1010
|
*/
|
|
1187
|
-
|
|
1011
|
+
codeHighlighter?: (code: string, language: string | null) => string | null;
|
|
1188
1012
|
}
|
|
1189
1013
|
/**
|
|
1190
|
-
*
|
|
1191
|
-
*
|
|
1192
|
-
|
|
1014
|
+
* Applies inline styles to all elements in a container.
|
|
1015
|
+
* Exported for use in clipboardSerializer (operates on DOM directly).
|
|
1016
|
+
*/
|
|
1017
|
+
declare function applyInlineStyles(container: HTMLElement, overrides?: InlineStyleOverrides): void;
|
|
1018
|
+
/**
|
|
1019
|
+
* Takes an HTML string and returns it with inline CSS styles applied
|
|
1020
|
+
* to all elements, so it renders correctly outside the editor.
|
|
1193
1021
|
*
|
|
1194
|
-
* @
|
|
1195
|
-
* @
|
|
1022
|
+
* @param html - Serialized HTML string from editor.getHTML()
|
|
1023
|
+
* @param overrides - Optional style overrides for custom theming
|
|
1196
1024
|
*
|
|
1197
1025
|
* @example
|
|
1198
|
-
*
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
1205
|
-
*
|
|
1206
|
-
* renderHTML({ HTMLAttributes }) {
|
|
1207
|
-
* return ['p', HTMLAttributes, 0];
|
|
1208
|
-
* },
|
|
1026
|
+
* ```ts
|
|
1027
|
+
* // Default light-theme styles
|
|
1028
|
+
* const styled = inlineStyles(editor.getHTML());
|
|
1029
|
+
*
|
|
1030
|
+
* // With custom overrides
|
|
1031
|
+
* const styled = inlineStyles(editor.getHTML(), {
|
|
1032
|
+
* blockquoteBorder: '5px solid red',
|
|
1033
|
+
* linkColor: '#ff6600',
|
|
1209
1034
|
* });
|
|
1035
|
+
* ```
|
|
1210
1036
|
*/
|
|
1211
|
-
|
|
1037
|
+
declare function inlineStyles(html: string, overrides?: InlineStyleOverrides): string;
|
|
1212
1038
|
|
|
1213
1039
|
/**
|
|
1214
|
-
*
|
|
1040
|
+
* Editor - Main editor class wrapping ProseMirror
|
|
1215
1041
|
*
|
|
1216
|
-
*
|
|
1217
|
-
* for creating ProseMirror mark extensions.
|
|
1042
|
+
* Manages extensions, schema, commands, and the ProseMirror EditorView/State.
|
|
1218
1043
|
*/
|
|
1219
1044
|
|
|
1220
1045
|
/**
|
|
1221
|
-
*
|
|
1222
|
-
* Includes schema with marks for MarkType getter
|
|
1223
|
-
*/
|
|
1224
|
-
interface MarkEditorContext {
|
|
1225
|
-
readonly state: EditorState;
|
|
1226
|
-
readonly view: EditorView;
|
|
1227
|
-
readonly schema: {
|
|
1228
|
-
marks: Record<string, MarkType>;
|
|
1229
|
-
};
|
|
1230
|
-
readonly commands: Record<string, (...args: unknown[]) => boolean>;
|
|
1231
|
-
}
|
|
1232
|
-
/**
|
|
1233
|
-
* Context interface for Mark config methods.
|
|
1234
|
-
* Extends ExtensionContext with mark-specific properties.
|
|
1235
|
-
* This enables proper typing of `this.options`, `this.markType`, etc.
|
|
1046
|
+
* Main editor class
|
|
1236
1047
|
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1048
|
+
* Wraps ProseMirror's EditorView and EditorState with a cleaner API.
|
|
1049
|
+
*
|
|
1050
|
+
* @example
|
|
1051
|
+
* ```ts
|
|
1052
|
+
* import { Editor } from '@domternal/core';
|
|
1053
|
+
* import { Schema } from '@domternal/pm/model';
|
|
1054
|
+
*
|
|
1055
|
+
* const schema = new Schema({
|
|
1056
|
+
* nodes: { doc: { content: 'paragraph+' }, paragraph: { content: 'text*' }, text: {} }
|
|
1057
|
+
* });
|
|
1058
|
+
*
|
|
1059
|
+
* const editor = new Editor({
|
|
1060
|
+
* schema,
|
|
1061
|
+
* element: document.getElementById('editor'),
|
|
1062
|
+
* content: '<p>Hello world</p>',
|
|
1063
|
+
* });
|
|
1064
|
+
*
|
|
1065
|
+
* // Get content
|
|
1066
|
+
* const json = editor.getJSON();
|
|
1067
|
+
* const html = editor.getHTML();
|
|
1068
|
+
*
|
|
1069
|
+
* // Set content
|
|
1070
|
+
* editor.commands.setContent('<p>New content</p>');
|
|
1071
|
+
*
|
|
1072
|
+
* // Cleanup
|
|
1073
|
+
* editor.destroy();
|
|
1074
|
+
* ```
|
|
1251
1075
|
*/
|
|
1252
|
-
|
|
1076
|
+
declare class Editor extends EventEmitter<EditorEvents> {
|
|
1253
1077
|
/**
|
|
1254
|
-
*
|
|
1255
|
-
* @example 'strong', 'b', 'span.bold'
|
|
1078
|
+
* Editor configuration options
|
|
1256
1079
|
*/
|
|
1257
|
-
|
|
1080
|
+
private options;
|
|
1258
1081
|
/**
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1261
|
-
* @example 'font-weight', 'font-weight=bold'
|
|
1082
|
+
* Manages extensions and schema
|
|
1083
|
+
* @internal Exposed for CommandManager, not for public use
|
|
1262
1084
|
*/
|
|
1263
|
-
|
|
1085
|
+
private _extensionManager;
|
|
1264
1086
|
/**
|
|
1265
|
-
*
|
|
1266
|
-
* @
|
|
1087
|
+
* Gets the extension manager
|
|
1088
|
+
* @internal For CommandManager use only
|
|
1267
1089
|
*/
|
|
1268
|
-
|
|
1090
|
+
get extensionManager(): ExtensionManager;
|
|
1269
1091
|
/**
|
|
1270
|
-
*
|
|
1271
|
-
* @default true
|
|
1092
|
+
* Manages commands
|
|
1272
1093
|
*/
|
|
1273
|
-
|
|
1094
|
+
private commandManager;
|
|
1274
1095
|
/**
|
|
1275
|
-
*
|
|
1276
|
-
* Return null/undefined to skip this rule
|
|
1277
|
-
* Return false to explicitly not match
|
|
1278
|
-
*
|
|
1279
|
-
* For style rules, receives the style value as string
|
|
1096
|
+
* ProseMirror EditorView instance
|
|
1280
1097
|
*/
|
|
1281
|
-
|
|
1282
|
-
}
|
|
1283
|
-
/**
|
|
1284
|
-
* Props passed to renderHTML function for marks
|
|
1285
|
-
*/
|
|
1286
|
-
interface MarkRenderHTMLProps {
|
|
1098
|
+
view: EditorView;
|
|
1287
1099
|
/**
|
|
1288
|
-
*
|
|
1100
|
+
* Whether the editor has been destroyed
|
|
1289
1101
|
*/
|
|
1290
|
-
|
|
1102
|
+
private _isDestroyed;
|
|
1291
1103
|
/**
|
|
1292
|
-
*
|
|
1104
|
+
* Timer for autofocus (cleared on destroy to prevent memory leaks)
|
|
1293
1105
|
*/
|
|
1294
|
-
|
|
1295
|
-
}
|
|
1296
|
-
/**
|
|
1297
|
-
* Mark-specific configuration properties (schema-related)
|
|
1298
|
-
*/
|
|
1299
|
-
interface MarkSchemaProperties {
|
|
1106
|
+
private _autofocusTimer;
|
|
1300
1107
|
/**
|
|
1301
|
-
*
|
|
1302
|
-
* is at its end (or beginning for marks that open).
|
|
1303
|
-
*
|
|
1304
|
-
* When true, typing at the mark's boundary continues the mark.
|
|
1305
|
-
* When false, typing creates unmarked content.
|
|
1108
|
+
* Creates a new Editor instance
|
|
1306
1109
|
*
|
|
1307
|
-
* @
|
|
1110
|
+
* @param options - Editor configuration
|
|
1111
|
+
* @throws Error if running in SSR environment (no window)
|
|
1112
|
+
* @throws Error if schema is not provided
|
|
1308
1113
|
*/
|
|
1309
|
-
|
|
1114
|
+
constructor(options: EditorOptions);
|
|
1310
1115
|
/**
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1313
|
-
* - '_' excludes all marks
|
|
1314
|
-
* - Space-separated mark names exclude specific marks
|
|
1315
|
-
* - Empty string or undefined means no exclusions
|
|
1316
|
-
*
|
|
1317
|
-
* @example 'code' - excludes code mark
|
|
1318
|
-
* @example 'bold italic' - excludes bold and italic
|
|
1319
|
-
* @example '_' - excludes all other marks
|
|
1116
|
+
* Gets the current EditorState
|
|
1320
1117
|
*/
|
|
1321
|
-
|
|
1118
|
+
get state(): EditorState;
|
|
1322
1119
|
/**
|
|
1323
|
-
*
|
|
1324
|
-
* Used in node's marks property
|
|
1325
|
-
*
|
|
1326
|
-
* @example 'formatting', 'inline'
|
|
1120
|
+
* Gets the ProseMirror schema
|
|
1327
1121
|
*/
|
|
1328
|
-
|
|
1122
|
+
get schema(): Schema;
|
|
1329
1123
|
/**
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
* When true (default), the mark persists across inline nodes.
|
|
1333
|
-
* When false, the mark only applies within a single text node.
|
|
1334
|
-
*
|
|
1335
|
-
* @default true
|
|
1124
|
+
* Checks if the editor is editable
|
|
1336
1125
|
*/
|
|
1337
|
-
|
|
1126
|
+
get isEditable(): boolean;
|
|
1338
1127
|
/**
|
|
1339
|
-
*
|
|
1128
|
+
* Checks if the editor content is empty
|
|
1129
|
+
*/
|
|
1130
|
+
get isEmpty(): boolean;
|
|
1131
|
+
/**
|
|
1132
|
+
* Checks if the editor has focus
|
|
1133
|
+
*/
|
|
1134
|
+
get isFocused(): boolean;
|
|
1135
|
+
/**
|
|
1136
|
+
* Checks if the editor has been destroyed
|
|
1137
|
+
*/
|
|
1138
|
+
get isDestroyed(): boolean;
|
|
1139
|
+
/**
|
|
1140
|
+
* Gets single commands for immediate execution
|
|
1141
|
+
* @example editor.commands.focus('end')
|
|
1142
|
+
*/
|
|
1143
|
+
get commands(): SingleCommands;
|
|
1144
|
+
/**
|
|
1145
|
+
* Creates a command chain for batched execution
|
|
1146
|
+
* @example editor.chain().focus().insertText('Hello').run()
|
|
1147
|
+
*/
|
|
1148
|
+
chain(): ChainedCommands;
|
|
1149
|
+
/**
|
|
1150
|
+
* Checks if commands can be executed (dry-run)
|
|
1151
|
+
* @example if (editor.can().toggleBold()) { ... }
|
|
1152
|
+
*/
|
|
1153
|
+
can(): CanCommands;
|
|
1154
|
+
/**
|
|
1155
|
+
* Gets extension storage
|
|
1156
|
+
* Access via: editor.storage.extensionName.propertyName
|
|
1157
|
+
*/
|
|
1158
|
+
get storage(): Record<string, unknown>;
|
|
1159
|
+
/**
|
|
1160
|
+
* Toolbar items registered by all extensions.
|
|
1161
|
+
*/
|
|
1162
|
+
get toolbarItems(): ToolbarItem[];
|
|
1163
|
+
/**
|
|
1164
|
+
* Floating-menu items registered by all extensions, rendered as the
|
|
1165
|
+
* block-insert menu shown on empty paragraphs.
|
|
1166
|
+
*/
|
|
1167
|
+
get floatingMenuItems(): FloatingMenuItem[];
|
|
1168
|
+
/**
|
|
1169
|
+
* Checks if a node or mark is currently active
|
|
1340
1170
|
*
|
|
1341
|
-
*
|
|
1342
|
-
*
|
|
1343
|
-
*
|
|
1171
|
+
* For toolbar button states - returns true if:
|
|
1172
|
+
* - For marks: the current selection has the mark applied
|
|
1173
|
+
* - For nodes: the cursor is inside that node type
|
|
1344
1174
|
*
|
|
1345
|
-
*
|
|
1346
|
-
*
|
|
1347
|
-
* Link.configure({ isFormatting: true }) // make links clearable
|
|
1348
|
-
* ```
|
|
1175
|
+
* @param nameOrAttributes - Extension name, or object with name and attributes
|
|
1176
|
+
* @param attributes - Optional attributes to match (for node/mark specific states)
|
|
1349
1177
|
*
|
|
1350
|
-
* @
|
|
1178
|
+
* @example
|
|
1179
|
+
* editor.isActive('bold') // → true if bold mark is active
|
|
1180
|
+
* editor.isActive('heading', { level: 2 }) // → true if in h2
|
|
1181
|
+
* editor.isActive({ name: 'textAlign', attributes: { align: 'center' } })
|
|
1351
1182
|
*/
|
|
1352
|
-
|
|
1183
|
+
isActive(nameOrAttributes: string | {
|
|
1184
|
+
name: string;
|
|
1185
|
+
attributes?: Record<string, unknown>;
|
|
1186
|
+
}, attributes?: Record<string, unknown>): boolean;
|
|
1353
1187
|
/**
|
|
1354
|
-
*
|
|
1355
|
-
*
|
|
1188
|
+
* Gets attributes of the currently active node or mark
|
|
1189
|
+
*
|
|
1190
|
+
* Returns empty object if the node/mark is not found or not active.
|
|
1191
|
+
*
|
|
1192
|
+
* @param name - Extension name (node or mark)
|
|
1356
1193
|
*
|
|
1357
1194
|
* @example
|
|
1358
|
-
*
|
|
1359
|
-
*
|
|
1360
|
-
* color: { default: null },
|
|
1361
|
-
* };
|
|
1362
|
-
* }
|
|
1195
|
+
* editor.getAttributes('heading') // → { level: 2 }
|
|
1196
|
+
* editor.getAttributes('link') // → { href: 'https://...', target: '_blank' }
|
|
1363
1197
|
*/
|
|
1364
|
-
|
|
1198
|
+
getAttributes(name: string): Record<string, unknown>;
|
|
1365
1199
|
/**
|
|
1366
|
-
*
|
|
1367
|
-
*
|
|
1200
|
+
* Helper to match attributes
|
|
1201
|
+
* Returns true if target contains all key/value pairs from source
|
|
1202
|
+
*/
|
|
1203
|
+
private matchAttributes;
|
|
1204
|
+
/**
|
|
1205
|
+
* Gets the document content as JSON
|
|
1206
|
+
*/
|
|
1207
|
+
getJSON(): JSONContent;
|
|
1208
|
+
/**
|
|
1209
|
+
* Gets the document content as HTML string
|
|
1368
1210
|
*
|
|
1369
|
-
* @
|
|
1370
|
-
*
|
|
1371
|
-
*
|
|
1372
|
-
* { tag: 'strong' },
|
|
1373
|
-
* { tag: 'b' },
|
|
1374
|
-
* { style: 'font-weight', getAttrs: (value) => /bold|[5-9]\d{2}/.test(value) && null },
|
|
1375
|
-
* ];
|
|
1376
|
-
* }
|
|
1211
|
+
* @param options - Optional settings
|
|
1212
|
+
* @param options.styled - When true (or an override object), applies inline CSS
|
|
1213
|
+
* styles so the HTML renders correctly outside the editor (email, CMS, etc.)
|
|
1377
1214
|
*/
|
|
1378
|
-
|
|
1215
|
+
getHTML(options?: {
|
|
1216
|
+
styled?: boolean | InlineStyleOverrides;
|
|
1217
|
+
}): string;
|
|
1379
1218
|
/**
|
|
1380
|
-
*
|
|
1381
|
-
* Returns DOMOutputSpec (tag, attributes, hole)
|
|
1219
|
+
* Gets the document content as plain text
|
|
1382
1220
|
*
|
|
1383
|
-
*
|
|
1221
|
+
* @param options - Options for text extraction
|
|
1222
|
+
* @param options.blockSeparator - String to insert between blocks (default: '\n\n')
|
|
1223
|
+
*/
|
|
1224
|
+
getText(options?: {
|
|
1225
|
+
blockSeparator?: string;
|
|
1226
|
+
}): string;
|
|
1227
|
+
/**
|
|
1228
|
+
* Executes a command with proper CommandProps
|
|
1229
|
+
* @internal
|
|
1230
|
+
*/
|
|
1231
|
+
private runCommand;
|
|
1232
|
+
/**
|
|
1233
|
+
* Sets the editor content
|
|
1384
1234
|
*
|
|
1385
|
-
* @
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1388
|
-
* }
|
|
1235
|
+
* @param content - JSON or HTML content
|
|
1236
|
+
* @param emitUpdate - Whether to emit update event (default: true)
|
|
1237
|
+
* @returns true if content was set successfully, false if content was invalid
|
|
1389
1238
|
*/
|
|
1390
|
-
|
|
1239
|
+
setContent(content: Content, emitUpdate?: boolean): boolean;
|
|
1240
|
+
/**
|
|
1241
|
+
* Clears the editor content
|
|
1242
|
+
*
|
|
1243
|
+
* @param emitUpdate - Whether to emit update event (default: true)
|
|
1244
|
+
* @returns true if content was cleared successfully
|
|
1245
|
+
*/
|
|
1246
|
+
clearContent(emitUpdate?: boolean): boolean;
|
|
1247
|
+
/**
|
|
1248
|
+
* Sets whether the editor is editable
|
|
1249
|
+
*
|
|
1250
|
+
* @param editable - Whether the editor should be editable
|
|
1251
|
+
*/
|
|
1252
|
+
setEditable(editable: boolean): this;
|
|
1253
|
+
/**
|
|
1254
|
+
* Focuses the editor
|
|
1255
|
+
*
|
|
1256
|
+
* @param position - Where to place cursor (default: null = just focus)
|
|
1257
|
+
*/
|
|
1258
|
+
focus(position?: FocusPosition): this;
|
|
1259
|
+
/**
|
|
1260
|
+
* Removes focus from the editor
|
|
1261
|
+
*/
|
|
1262
|
+
blur(): this;
|
|
1263
|
+
/**
|
|
1264
|
+
* Registers a ProseMirror plugin dynamically at runtime, after the editor
|
|
1265
|
+
* has been created. Safe to call repeatedly with the same plugin key.
|
|
1266
|
+
*/
|
|
1267
|
+
registerPlugin(plugin: Plugin): void;
|
|
1268
|
+
/**
|
|
1269
|
+
* Unregisters a ProseMirror plugin by its PluginKey.
|
|
1270
|
+
* Uses PluginKey.get() to identify the plugin to remove.
|
|
1271
|
+
*/
|
|
1272
|
+
unregisterPlugin(key: PluginKey): void;
|
|
1273
|
+
/**
|
|
1274
|
+
* Destroys the editor and cleans up resources
|
|
1275
|
+
*
|
|
1276
|
+
* After calling destroy(), the editor instance should not be used.
|
|
1277
|
+
*/
|
|
1278
|
+
destroy(): void;
|
|
1279
|
+
/**
|
|
1280
|
+
* Builds a clipboardSerializer that applies a transform function to HTML on copy/cut.
|
|
1281
|
+
*/
|
|
1282
|
+
private buildClipboardSerializer;
|
|
1283
|
+
/**
|
|
1284
|
+
* Creates the editor instance
|
|
1285
|
+
*/
|
|
1286
|
+
private createEditor;
|
|
1287
|
+
/**
|
|
1288
|
+
* Handles ProseMirror transactions
|
|
1289
|
+
*/
|
|
1290
|
+
private dispatchTransaction;
|
|
1291
|
+
/**
|
|
1292
|
+
* Emit method - needed for CommandManager interface
|
|
1293
|
+
*/
|
|
1294
|
+
emit<E extends keyof EditorEvents>(event: E, ...args: EditorEvents[E] extends undefined ? [] : [EditorEvents[E]]): this;
|
|
1391
1295
|
}
|
|
1296
|
+
|
|
1392
1297
|
/**
|
|
1393
|
-
*
|
|
1394
|
-
* Combines ExtensionConfigBase with mark-specific schema properties.
|
|
1395
|
-
* Uses ThisType<MarkContext> to provide proper typing for `this` in config methods.
|
|
1298
|
+
* FloatingMenu configuration types
|
|
1396
1299
|
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1399
|
-
*
|
|
1400
|
-
* @example
|
|
1401
|
-
* const Bold = Mark.create({
|
|
1402
|
-
* name: 'bold',
|
|
1403
|
-
* parseHTML() {
|
|
1404
|
-
* // `this` is properly typed here!
|
|
1405
|
-
* return [{ tag: 'strong' }, { tag: 'b' }];
|
|
1406
|
-
* },
|
|
1407
|
-
* renderHTML({ HTMLAttributes }) {
|
|
1408
|
-
* return ['strong', HTMLAttributes, 0];
|
|
1409
|
-
* },
|
|
1410
|
-
* });
|
|
1300
|
+
* Types for block-insert items contributed by extensions via the
|
|
1301
|
+
* `addFloatingMenuItems()` hook. Framework wrappers read these items
|
|
1302
|
+
* and render a WAI-ARIA menu shown on empty paragraphs.
|
|
1411
1303
|
*/
|
|
1412
|
-
type MarkConfig<Options = unknown, Storage = unknown> = ExtensionConfigBase<Options, Storage> & MarkSchemaProperties & ThisType<MarkContext<Options, Storage>>;
|
|
1413
1304
|
|
|
1414
1305
|
/**
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
1417
|
-
*
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
* Generic, type-safe event emitter
|
|
1306
|
+
* A single entry in the floating menu.
|
|
1307
|
+
*
|
|
1308
|
+
* Unlike `ToolbarButton`, floating-menu items represent one-shot insert
|
|
1309
|
+
* actions (no toggle / active state), carry an optional `description` for
|
|
1310
|
+
* Notion-style two-line rendering, and expose `keywords` for future
|
|
1311
|
+
* slash-command filtering.
|
|
1422
1312
|
*
|
|
1423
1313
|
* @example
|
|
1424
|
-
*
|
|
1425
|
-
*
|
|
1426
|
-
*
|
|
1427
|
-
*
|
|
1314
|
+
* {
|
|
1315
|
+
* name: 'heading-1',
|
|
1316
|
+
* label: 'Heading 1',
|
|
1317
|
+
* description: 'Big section heading',
|
|
1318
|
+
* icon: 'textHOne',
|
|
1319
|
+
* group: 'Basic',
|
|
1320
|
+
* shortcut: '# ',
|
|
1321
|
+
* command: 'toggleHeading',
|
|
1322
|
+
* commandArgs: [{ level: 1 }],
|
|
1428
1323
|
* }
|
|
1429
|
-
*
|
|
1430
|
-
* const emitter = new EventEmitter<MyEvents>();
|
|
1431
|
-
* emitter.on('update', ({ value }) => console.log(value));
|
|
1432
|
-
* emitter.on('destroy', () => console.log('destroyed'));
|
|
1433
|
-
* ```
|
|
1434
1324
|
*/
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
* Remove an event listener, or all listeners for an event if no callback specified
|
|
1445
|
-
*/
|
|
1446
|
-
off<E extends keyof Events>(event: E, callback?: EventCallback<Events[E]>): this;
|
|
1447
|
-
/**
|
|
1448
|
-
* Emit an event to all registered listeners
|
|
1449
|
-
* Uses .call(this) to preserve context for callbacks
|
|
1450
|
-
*/
|
|
1451
|
-
emit<E extends keyof Events>(event: E, ...args: Events[E] extends undefined ? [] : [Events[E]]): this;
|
|
1325
|
+
interface FloatingMenuItem {
|
|
1326
|
+
/** Unique identifier (used as React key, aria id, and dedup key when merging). */
|
|
1327
|
+
name: string;
|
|
1328
|
+
/** Primary label shown to the user. */
|
|
1329
|
+
label: string;
|
|
1330
|
+
/** Optional secondary line shown under the label. */
|
|
1331
|
+
description?: string;
|
|
1332
|
+
/** Icon key resolved against the editor's IconSet. Optional. */
|
|
1333
|
+
icon?: string;
|
|
1452
1334
|
/**
|
|
1453
|
-
*
|
|
1335
|
+
* Group heading. Items with the same group render under a shared
|
|
1336
|
+
* `<div role="group" aria-label={group}>` section.
|
|
1337
|
+
* @default '' (no group heading)
|
|
1454
1338
|
*/
|
|
1455
|
-
|
|
1339
|
+
group?: string;
|
|
1340
|
+
/** Sort order within group (higher first). @default 100 */
|
|
1341
|
+
priority?: number;
|
|
1342
|
+
/** Keywords for future slash-command fuzzy filtering. */
|
|
1343
|
+
keywords?: string[];
|
|
1344
|
+
/** Visible keyboard-shortcut hint (e.g. `# `, `Mod-Alt-1`). */
|
|
1345
|
+
shortcut?: string;
|
|
1456
1346
|
/**
|
|
1457
|
-
*
|
|
1347
|
+
* Command to execute on activation.
|
|
1348
|
+
*
|
|
1349
|
+
* - String: key of `editor.commands`; invoked with `commandArgs`.
|
|
1350
|
+
* - Function: arbitrary callback receiving the editor. Use when the
|
|
1351
|
+
* action is not a registered command (e.g. opening a popover).
|
|
1458
1352
|
*/
|
|
1459
|
-
|
|
1353
|
+
command: string | ((editor: Editor) => void);
|
|
1354
|
+
/** Arguments for string commands. Ignored when `command` is a function. */
|
|
1355
|
+
commandArgs?: unknown[];
|
|
1460
1356
|
/**
|
|
1461
|
-
*
|
|
1357
|
+
* Custom disabled predicate. When omitted, the controller dry-runs the
|
|
1358
|
+
* command via `editor.can()` (string commands only) to detect availability.
|
|
1462
1359
|
*/
|
|
1463
|
-
|
|
1360
|
+
isDisabled?: (editor: Editor) => boolean;
|
|
1464
1361
|
/**
|
|
1465
|
-
*
|
|
1362
|
+
* Node-type names that, when present as ancestors of the cursor, cause
|
|
1363
|
+
* the slash menu to hide this item. Useful for list/task-list entries:
|
|
1364
|
+
* e.g. `['bulletList']` removes "Bulleted list" from the menu while the
|
|
1365
|
+
* cursor is already inside a bullet list, so picking it doesn't lift
|
|
1366
|
+
* the user out of the list unexpectedly.
|
|
1466
1367
|
*/
|
|
1467
|
-
|
|
1368
|
+
hideWhenInside?: string[];
|
|
1468
1369
|
}
|
|
1469
|
-
|
|
1470
1370
|
/**
|
|
1471
|
-
*
|
|
1371
|
+
* Override form accepted by `FloatingMenu.configure({ items })`.
|
|
1472
1372
|
*
|
|
1473
|
-
*
|
|
1474
|
-
* -
|
|
1475
|
-
* - Schema building from Node/Mark extensions
|
|
1476
|
-
* - Plugin collection from all extensions
|
|
1477
|
-
* - Extension storage management
|
|
1478
|
-
* - Conflict detection (AD-7)
|
|
1373
|
+
* - Array: replaces the collected defaults entirely.
|
|
1374
|
+
* - Function: transforms the defaults (filter / reorder / extend).
|
|
1479
1375
|
*/
|
|
1376
|
+
type FloatingMenuItemsOverride = FloatingMenuItem[] | ((defaults: FloatingMenuItem[], editor: Editor) => FloatingMenuItem[]);
|
|
1480
1377
|
|
|
1481
1378
|
/**
|
|
1482
|
-
*
|
|
1379
|
+
* Extension configuration types
|
|
1380
|
+
*
|
|
1381
|
+
* These types define the configuration object passed to Extension.create(),
|
|
1382
|
+
* Node.create(), and Mark.create() factory methods.
|
|
1483
1383
|
*/
|
|
1484
|
-
|
|
1485
|
-
error: Error;
|
|
1486
|
-
context: string;
|
|
1487
|
-
}
|
|
1384
|
+
|
|
1488
1385
|
/**
|
|
1489
|
-
* Editor
|
|
1490
|
-
* Forward declaration to avoid circular dependency
|
|
1386
|
+
* Editor instance type (forward declaration)
|
|
1491
1387
|
*/
|
|
1492
|
-
interface
|
|
1493
|
-
readonly
|
|
1494
|
-
|
|
1388
|
+
interface ExtensionEditor {
|
|
1389
|
+
readonly state: EditorState;
|
|
1390
|
+
readonly view: EditorView;
|
|
1391
|
+
readonly schema: unknown;
|
|
1392
|
+
readonly commands: SingleCommands;
|
|
1495
1393
|
}
|
|
1496
1394
|
/**
|
|
1497
|
-
*
|
|
1498
|
-
* Accessible via `(constructor as any).__domternalContext`.
|
|
1395
|
+
* Any extension type (forward declaration)
|
|
1499
1396
|
*/
|
|
1500
|
-
interface
|
|
1501
|
-
|
|
1502
|
-
extension
|
|
1503
|
-
name: string;
|
|
1504
|
-
options: Record<string, unknown>;
|
|
1505
|
-
};
|
|
1397
|
+
interface AnyExtensionConfig {
|
|
1398
|
+
name: string;
|
|
1399
|
+
type?: 'extension' | 'node' | 'mark';
|
|
1506
1400
|
}
|
|
1507
1401
|
/**
|
|
1508
|
-
*
|
|
1402
|
+
* Global attribute specification for injecting attributes into multiple node/mark types.
|
|
1403
|
+
* Used by extensions like TextAlign to add alignment to heading, paragraph, etc.
|
|
1509
1404
|
*/
|
|
1510
|
-
interface
|
|
1511
|
-
/**
|
|
1512
|
-
* Extensions to process
|
|
1513
|
-
* If provided, schema is built from extensions
|
|
1514
|
-
*/
|
|
1515
|
-
extensions?: AnyExtension[] | undefined;
|
|
1516
|
-
/**
|
|
1517
|
-
* Direct schema (backward compatibility with Step 1.3)
|
|
1518
|
-
* If provided, extensions are ignored for schema building
|
|
1519
|
-
*/
|
|
1520
|
-
schema?: Schema | undefined;
|
|
1521
|
-
}
|
|
1522
|
-
declare class ExtensionManager {
|
|
1405
|
+
interface GlobalAttributeSpec {
|
|
1523
1406
|
/**
|
|
1524
|
-
*
|
|
1407
|
+
* Default value for the attribute.
|
|
1525
1408
|
*/
|
|
1526
|
-
|
|
1409
|
+
default?: unknown;
|
|
1527
1410
|
/**
|
|
1528
|
-
*
|
|
1411
|
+
* Parse attribute value from HTML element.
|
|
1412
|
+
* @param element - The DOM element to parse from
|
|
1413
|
+
* @returns The parsed attribute value
|
|
1529
1414
|
*/
|
|
1530
|
-
|
|
1415
|
+
parseHTML?: (element: HTMLElement) => unknown;
|
|
1531
1416
|
/**
|
|
1532
|
-
*
|
|
1417
|
+
* Render attribute value to HTML attributes.
|
|
1418
|
+
* @param attributes - The node/mark attributes
|
|
1419
|
+
* @returns Object of HTML attributes to set, or null/empty to skip
|
|
1533
1420
|
*/
|
|
1534
|
-
|
|
1421
|
+
renderHTML?: (attributes: Record<string, unknown>) => Record<string, string> | null;
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Global attributes definition for injecting into node/mark types.
|
|
1425
|
+
*/
|
|
1426
|
+
interface GlobalAttributes {
|
|
1535
1427
|
/**
|
|
1536
|
-
*
|
|
1428
|
+
* Node or mark type names to add these attributes to.
|
|
1429
|
+
* @example ['heading', 'paragraph']
|
|
1537
1430
|
*/
|
|
1538
|
-
|
|
1431
|
+
types: string[];
|
|
1539
1432
|
/**
|
|
1540
|
-
*
|
|
1433
|
+
* Attribute specifications to add.
|
|
1434
|
+
* @example { textAlign: { default: 'left', parseHTML: (el) => el.style.textAlign } }
|
|
1541
1435
|
*/
|
|
1542
|
-
|
|
1436
|
+
attributes: Record<string, GlobalAttributeSpec>;
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Context interface that describes what `this` will be in config methods.
|
|
1440
|
+
* This enables proper typing of `this.options`, `this.editor`, etc.
|
|
1441
|
+
* without creating circular dependencies.
|
|
1442
|
+
*
|
|
1443
|
+
* @typeParam Options - Extension options type
|
|
1444
|
+
* @typeParam Storage - Extension storage type
|
|
1445
|
+
*/
|
|
1446
|
+
interface ExtensionContext<Options = unknown, Storage = unknown> {
|
|
1447
|
+
/** Extension type identifier */
|
|
1448
|
+
readonly type: 'extension' | 'node' | 'mark';
|
|
1449
|
+
/** Unique extension name */
|
|
1450
|
+
readonly name: string;
|
|
1451
|
+
/** Extension options (immutable after creation) */
|
|
1452
|
+
readonly options: Options;
|
|
1453
|
+
/** Extension storage (mutable state) */
|
|
1454
|
+
storage: Storage;
|
|
1455
|
+
/** Editor instance (null until bound by ExtensionManager) */
|
|
1456
|
+
editor: ExtensionEditor | null;
|
|
1543
1457
|
/**
|
|
1544
|
-
*
|
|
1458
|
+
* Reference to the parent config method when using extend().
|
|
1459
|
+
* Available only inside overridden config methods.
|
|
1460
|
+
* Use `this.parent?.()` to call the parent's version of the current method.
|
|
1545
1461
|
*/
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1462
|
+
parent?: ((...args: unknown[]) => unknown) | undefined;
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Base configuration properties for all extension types.
|
|
1466
|
+
* This interface contains just the properties without ThisType,
|
|
1467
|
+
* allowing Node and Mark configs to use their own context types.
|
|
1468
|
+
*
|
|
1469
|
+
* @typeParam Options - Extension options type
|
|
1470
|
+
* @typeParam Storage - Extension storage type
|
|
1471
|
+
*/
|
|
1472
|
+
interface ExtensionConfigBase<Options = unknown, Storage = unknown> {
|
|
1551
1473
|
/**
|
|
1552
|
-
*
|
|
1474
|
+
* Unique extension name
|
|
1475
|
+
* Used for identification, storage access, and error messages
|
|
1553
1476
|
*/
|
|
1554
|
-
|
|
1477
|
+
name: string;
|
|
1555
1478
|
/**
|
|
1556
|
-
*
|
|
1479
|
+
* Extension priority (higher = loaded first)
|
|
1480
|
+
*
|
|
1481
|
+
* Reserved ranges:
|
|
1482
|
+
* - 900-1000: Core nodes (Document, Text, Paragraph)
|
|
1483
|
+
* - 500-899: Standard extensions (Heading, Bold, etc.)
|
|
1484
|
+
* - 100-499: Default range for user extensions
|
|
1485
|
+
* - 0-99: Low priority extensions (run after everything)
|
|
1486
|
+
*
|
|
1487
|
+
* @default 100
|
|
1557
1488
|
*/
|
|
1558
|
-
|
|
1489
|
+
priority?: number;
|
|
1559
1490
|
/**
|
|
1560
|
-
*
|
|
1491
|
+
* Required extensions that must be present
|
|
1492
|
+
* ExtensionManager throws if any dependency is missing
|
|
1561
1493
|
*
|
|
1562
|
-
* @
|
|
1563
|
-
*
|
|
1494
|
+
* @example
|
|
1495
|
+
* dependencies: ['bulletList', 'orderedList']
|
|
1564
1496
|
*/
|
|
1565
|
-
|
|
1497
|
+
dependencies?: string[];
|
|
1566
1498
|
/**
|
|
1567
|
-
*
|
|
1499
|
+
* Default options for this extension
|
|
1500
|
+
* Called during extension creation with `this` bound to the extension
|
|
1568
1501
|
*/
|
|
1569
|
-
|
|
1502
|
+
addOptions?: () => Options;
|
|
1570
1503
|
/**
|
|
1571
|
-
*
|
|
1504
|
+
* Initial storage state for this extension
|
|
1505
|
+
* Storage is mutable and accessible via editor.storage[extensionName]
|
|
1572
1506
|
*/
|
|
1573
|
-
|
|
1507
|
+
addStorage?: () => Storage;
|
|
1574
1508
|
/**
|
|
1575
|
-
*
|
|
1509
|
+
* Commands this extension provides
|
|
1510
|
+
* Commands are accessible via editor.commands.commandName()
|
|
1511
|
+
*
|
|
1512
|
+
* @example
|
|
1513
|
+
* addCommands() {
|
|
1514
|
+
* return {
|
|
1515
|
+
* toggleBold: () => ({ commands }) => commands.toggleMark('bold'),
|
|
1516
|
+
* };
|
|
1517
|
+
* }
|
|
1576
1518
|
*/
|
|
1577
|
-
|
|
1519
|
+
addCommands?: () => Record<string, (...args: never[]) => Command>;
|
|
1578
1520
|
/**
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1521
|
+
* Keyboard shortcuts for this extension
|
|
1522
|
+
* Keys are shortcut strings (e.g., 'Mod-b'), values are handler functions
|
|
1523
|
+
*
|
|
1524
|
+
* @example
|
|
1525
|
+
* addKeyboardShortcuts() {
|
|
1526
|
+
* return {
|
|
1527
|
+
* 'Mod-b': () => this.editor.commands.toggleBold(),
|
|
1528
|
+
* };
|
|
1529
|
+
* }
|
|
1581
1530
|
*/
|
|
1582
|
-
|
|
1531
|
+
addKeyboardShortcuts?: () => Record<string, KeyboardShortcutCommand>;
|
|
1583
1532
|
/**
|
|
1584
|
-
*
|
|
1533
|
+
* Input rules (markdown-style shortcuts)
|
|
1534
|
+
* Triggered when user types matching patterns
|
|
1535
|
+
*
|
|
1536
|
+
* @example
|
|
1537
|
+
* addInputRules() {
|
|
1538
|
+
* return [
|
|
1539
|
+
* textblockTypeInputRule(/^## $/, this.type),
|
|
1540
|
+
* ];
|
|
1541
|
+
* }
|
|
1585
1542
|
*/
|
|
1586
|
-
|
|
1543
|
+
addInputRules?: () => InputRule[];
|
|
1587
1544
|
/**
|
|
1588
|
-
*
|
|
1589
|
-
* Cached after first call
|
|
1545
|
+
* ProseMirror plugins for this extension
|
|
1590
1546
|
*/
|
|
1591
|
-
|
|
1547
|
+
addProseMirrorPlugins?: () => Plugin[];
|
|
1592
1548
|
/**
|
|
1593
|
-
*
|
|
1549
|
+
* Nested extensions (for extension bundles like StarterKit)
|
|
1550
|
+
* These extensions are flattened and processed like top-level extensions
|
|
1594
1551
|
*/
|
|
1595
|
-
|
|
1552
|
+
addExtensions?: () => AnyExtensionConfig[];
|
|
1596
1553
|
/**
|
|
1597
|
-
*
|
|
1598
|
-
*
|
|
1554
|
+
* Global attributes to add to multiple node/mark types.
|
|
1555
|
+
* Useful for extensions like TextAlign that need to add attributes
|
|
1556
|
+
* to several nodes (heading, paragraph, etc.) without modifying each.
|
|
1557
|
+
*
|
|
1558
|
+
* @example
|
|
1559
|
+
* addGlobalAttributes() {
|
|
1560
|
+
* return [{
|
|
1561
|
+
* types: ['heading', 'paragraph'],
|
|
1562
|
+
* attributes: {
|
|
1563
|
+
* textAlign: {
|
|
1564
|
+
* default: 'left',
|
|
1565
|
+
* parseHTML: (element) => element.style.textAlign || 'left',
|
|
1566
|
+
* renderHTML: (attrs) => attrs.textAlign !== 'left'
|
|
1567
|
+
* ? { style: `text-align: ${attrs.textAlign}` }
|
|
1568
|
+
* : null,
|
|
1569
|
+
* },
|
|
1570
|
+
* },
|
|
1571
|
+
* }];
|
|
1572
|
+
* }
|
|
1599
1573
|
*/
|
|
1600
|
-
|
|
1574
|
+
addGlobalAttributes?: () => GlobalAttributes[];
|
|
1601
1575
|
/**
|
|
1602
|
-
*
|
|
1603
|
-
*
|
|
1576
|
+
* Toolbar items this extension contributes.
|
|
1577
|
+
* Framework toolbar components read these to auto-generate buttons.
|
|
1578
|
+
*
|
|
1579
|
+
* @example
|
|
1580
|
+
* addToolbarItems() {
|
|
1581
|
+
* return [{
|
|
1582
|
+
* type: 'button',
|
|
1583
|
+
* name: 'bold',
|
|
1584
|
+
* command: 'toggleBold',
|
|
1585
|
+
* isActive: 'bold',
|
|
1586
|
+
* icon: 'textB',
|
|
1587
|
+
* label: 'Bold',
|
|
1588
|
+
* shortcut: 'Mod-b',
|
|
1589
|
+
* group: 'format',
|
|
1590
|
+
* }];
|
|
1591
|
+
* }
|
|
1604
1592
|
*/
|
|
1605
|
-
|
|
1593
|
+
addToolbarItems?: () => ToolbarItem[];
|
|
1606
1594
|
/**
|
|
1607
|
-
*
|
|
1608
|
-
*
|
|
1609
|
-
*
|
|
1595
|
+
* Floating-menu items this extension contributes.
|
|
1596
|
+
* Block-insert menu shown on empty paragraphs aggregates these items
|
|
1597
|
+
* across all extensions. Framework wrappers render them as a WAI-ARIA
|
|
1598
|
+
* menu with groups, arrow-key navigation, and Enter to execute.
|
|
1599
|
+
*
|
|
1600
|
+
* @example
|
|
1601
|
+
* addFloatingMenuItems() {
|
|
1602
|
+
* return [{
|
|
1603
|
+
* name: 'heading-1',
|
|
1604
|
+
* label: 'Heading 1',
|
|
1605
|
+
* description: 'Big section heading',
|
|
1606
|
+
* icon: 'textHOne',
|
|
1607
|
+
* group: 'Basic',
|
|
1608
|
+
* command: 'toggleHeading',
|
|
1609
|
+
* commandArgs: [{ level: 1 }],
|
|
1610
|
+
* }];
|
|
1611
|
+
* }
|
|
1610
1612
|
*/
|
|
1611
|
-
|
|
1613
|
+
addFloatingMenuItems?: () => FloatingMenuItem[];
|
|
1612
1614
|
/**
|
|
1613
|
-
*
|
|
1614
|
-
*
|
|
1615
|
+
* Called before editor is created
|
|
1616
|
+
* Can be used to modify editor options
|
|
1615
1617
|
*/
|
|
1616
|
-
|
|
1618
|
+
onBeforeCreate?: () => void;
|
|
1617
1619
|
/**
|
|
1618
|
-
*
|
|
1619
|
-
* @throws Error if duplicate names found
|
|
1620
|
+
* Called when editor is fully initialized and ready
|
|
1620
1621
|
*/
|
|
1621
|
-
|
|
1622
|
+
onCreate?: () => void;
|
|
1622
1623
|
/**
|
|
1623
|
-
*
|
|
1624
|
-
* @throws Error if required dependency is missing
|
|
1624
|
+
* Called when document content changes
|
|
1625
1625
|
*/
|
|
1626
|
-
|
|
1626
|
+
onUpdate?: () => void;
|
|
1627
1627
|
/**
|
|
1628
|
-
*
|
|
1628
|
+
* Called when selection changes (without content change)
|
|
1629
1629
|
*/
|
|
1630
|
-
|
|
1630
|
+
onSelectionUpdate?: () => void;
|
|
1631
1631
|
/**
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1632
|
+
* Called on every transaction
|
|
1633
|
+
* Can be used to intercept or modify transactions
|
|
1634
1634
|
*/
|
|
1635
|
-
|
|
1635
|
+
onTransaction?: (props: {
|
|
1636
|
+
transaction: Transaction;
|
|
1637
|
+
}) => void;
|
|
1636
1638
|
/**
|
|
1637
|
-
*
|
|
1638
|
-
* Merges extra attrs into spec.attrs, wraps parseDOM getAttrs to parse
|
|
1639
|
-
* global attributes from DOM elements, and wraps toDOM to inject rendered
|
|
1640
|
-
* global HTML attributes into the output.
|
|
1639
|
+
* Called when editor receives focus
|
|
1641
1640
|
*/
|
|
1642
|
-
|
|
1641
|
+
onFocus?: (props: {
|
|
1642
|
+
event: FocusEvent;
|
|
1643
|
+
}) => void;
|
|
1643
1644
|
/**
|
|
1644
|
-
*
|
|
1645
|
+
* Called when editor loses focus
|
|
1645
1646
|
*/
|
|
1646
|
-
|
|
1647
|
+
onBlur?: (props: {
|
|
1648
|
+
event: FocusEvent;
|
|
1649
|
+
}) => void;
|
|
1647
1650
|
/**
|
|
1648
|
-
*
|
|
1651
|
+
* Called when editor is being destroyed
|
|
1652
|
+
* Use for cleanup (remove event listeners, etc.)
|
|
1649
1653
|
*/
|
|
1650
|
-
|
|
1654
|
+
onDestroy?: () => void;
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Full configuration type for Extension.create()
|
|
1658
|
+
* Combines base properties with ThisType for proper `this` typing.
|
|
1659
|
+
*
|
|
1660
|
+
* @typeParam Options - Extension options type
|
|
1661
|
+
* @typeParam Storage - Extension storage type
|
|
1662
|
+
*/
|
|
1663
|
+
type ExtensionConfig<Options = unknown, Storage = unknown> = ExtensionConfigBase<Options, Storage> & ThisType<ExtensionContext<Options, Storage>>;
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* Attribute specification for Node and Mark extensions
|
|
1667
|
+
*
|
|
1668
|
+
* Used by addAttributes() to define node/mark attributes
|
|
1669
|
+
* with parsing, rendering, and validation rules.
|
|
1670
|
+
*
|
|
1671
|
+
* @example
|
|
1672
|
+
* addAttributes() {
|
|
1673
|
+
* return {
|
|
1674
|
+
* level: {
|
|
1675
|
+
* default: 1,
|
|
1676
|
+
* parseHTML: (element) => parseInt(element.tagName.charAt(1), 10),
|
|
1677
|
+
* renderHTML: (attributes) => ({ 'data-level': attributes.level }),
|
|
1678
|
+
* },
|
|
1679
|
+
* };
|
|
1680
|
+
* }
|
|
1681
|
+
*/
|
|
1682
|
+
/**
|
|
1683
|
+
* Specification for a single attribute
|
|
1684
|
+
*/
|
|
1685
|
+
interface AttributeSpec {
|
|
1651
1686
|
/**
|
|
1652
|
-
*
|
|
1687
|
+
* Default value for the attribute
|
|
1688
|
+
* Used when the attribute is not explicitly set
|
|
1653
1689
|
*/
|
|
1654
|
-
|
|
1690
|
+
default?: unknown;
|
|
1655
1691
|
/**
|
|
1656
|
-
*
|
|
1657
|
-
*
|
|
1658
|
-
*
|
|
1659
|
-
* Note: Extensions should return PM-compatible commands from addKeyboardShortcuts()
|
|
1692
|
+
* Whether this attribute is rendered to the DOM
|
|
1693
|
+
* @default true
|
|
1660
1694
|
*/
|
|
1661
|
-
|
|
1695
|
+
rendered?: boolean;
|
|
1662
1696
|
/**
|
|
1663
|
-
*
|
|
1697
|
+
* Keep this attribute when splitting the node
|
|
1698
|
+
* For example, heading level should be kept when pressing Enter
|
|
1699
|
+
* @default true
|
|
1664
1700
|
*/
|
|
1665
|
-
|
|
1701
|
+
keepOnSplit?: boolean;
|
|
1666
1702
|
/**
|
|
1667
|
-
*
|
|
1703
|
+
* Validate attribute value (ProseMirror 1.22.0+).
|
|
1704
|
+
* When a string, a `|`-separated list of primitive types
|
|
1705
|
+
* (`"number"`, `"string"`, `"boolean"`, `"null"`, `"undefined"`).
|
|
1706
|
+
* When a function, it should throw if the value is invalid.
|
|
1668
1707
|
*
|
|
1669
|
-
*
|
|
1670
|
-
*
|
|
1671
|
-
*
|
|
1672
|
-
|
|
1673
|
-
private collectCommands;
|
|
1674
|
-
/**
|
|
1675
|
-
* Collects toolbar items from all extensions
|
|
1708
|
+
* @example
|
|
1709
|
+
* validate: 'number'
|
|
1710
|
+
* validate: 'string|null'
|
|
1711
|
+
* validate: (value) => { if (typeof value !== 'number') throw new Error('expected number'); }
|
|
1676
1712
|
*/
|
|
1677
|
-
|
|
1713
|
+
validate?: string | ((value: unknown) => void);
|
|
1678
1714
|
/**
|
|
1679
|
-
*
|
|
1680
|
-
*
|
|
1715
|
+
* Parse attribute value from HTML element
|
|
1716
|
+
* Called during HTML parsing to extract attribute value
|
|
1681
1717
|
*
|
|
1682
|
-
*
|
|
1683
|
-
*
|
|
1684
|
-
*
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
/**
|
|
1688
|
-
* Validates that the schema has required nodes
|
|
1689
|
-
* @throws Error if schema is missing 'doc' or 'text' nodes
|
|
1690
|
-
*/
|
|
1691
|
-
validateSchema(): void;
|
|
1692
|
-
/**
|
|
1693
|
-
* Cleans up the extension manager
|
|
1694
|
-
* Calls onDestroy on all extensions and clears all caches
|
|
1718
|
+
* @param element - The HTML element being parsed
|
|
1719
|
+
* @returns The attribute value
|
|
1720
|
+
*
|
|
1721
|
+
* @example
|
|
1722
|
+
* parseHTML: (element) => element.getAttribute('data-level')
|
|
1695
1723
|
*/
|
|
1696
|
-
|
|
1724
|
+
parseHTML?: (element: HTMLElement) => unknown;
|
|
1697
1725
|
/**
|
|
1698
|
-
*
|
|
1699
|
-
*
|
|
1726
|
+
* Render attribute to HTML attributes object
|
|
1727
|
+
* Called during HTML serialization
|
|
1700
1728
|
*
|
|
1701
|
-
*
|
|
1729
|
+
* @param attributes - All attributes of the node/mark
|
|
1730
|
+
* @returns HTML attributes object or null to skip
|
|
1702
1731
|
*
|
|
1703
|
-
* @
|
|
1704
|
-
*
|
|
1705
|
-
* @returns The function result, or undefined if an error occurred
|
|
1706
|
-
*/
|
|
1707
|
-
safeCall<T>(fn: () => T, context: string): T | undefined;
|
|
1708
|
-
/**
|
|
1709
|
-
* Calls onBeforeCreate on all extensions
|
|
1732
|
+
* @example
|
|
1733
|
+
* renderHTML: (attributes) => ({ 'data-level': attributes.level })
|
|
1710
1734
|
*/
|
|
1711
|
-
|
|
1735
|
+
renderHTML?: (attributes: Record<string, unknown>) => Record<string, string | number | boolean | null | undefined> | null;
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Collection of attribute specifications
|
|
1739
|
+
* Keyed by attribute name
|
|
1740
|
+
*/
|
|
1741
|
+
type AttributeSpecs = Record<string, AttributeSpec>;
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Node configuration types
|
|
1745
|
+
*
|
|
1746
|
+
* These types define the configuration object passed to Node.create()
|
|
1747
|
+
* for creating ProseMirror node extensions.
|
|
1748
|
+
*/
|
|
1749
|
+
|
|
1750
|
+
/**
|
|
1751
|
+
* Editor interface for Node context
|
|
1752
|
+
* Includes schema with nodes for NodeType getter
|
|
1753
|
+
*/
|
|
1754
|
+
interface NodeEditorContext {
|
|
1755
|
+
readonly state: EditorState;
|
|
1756
|
+
readonly view: EditorView;
|
|
1757
|
+
readonly schema: {
|
|
1758
|
+
nodes: Record<string, NodeType>;
|
|
1759
|
+
};
|
|
1760
|
+
readonly commands: Record<string, (...args: unknown[]) => boolean>;
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Context interface for Node config methods.
|
|
1764
|
+
* Extends ExtensionContext with node-specific properties.
|
|
1765
|
+
* This enables proper typing of `this.options`, `this.nodeType`, etc.
|
|
1766
|
+
*
|
|
1767
|
+
* @typeParam Options - Node options type
|
|
1768
|
+
* @typeParam Storage - Node storage type
|
|
1769
|
+
*/
|
|
1770
|
+
interface NodeContext<Options = unknown, Storage = unknown> extends Omit<ExtensionContext<Options, Storage>, 'editor' | 'type'> {
|
|
1771
|
+
/** Node type identifier */
|
|
1772
|
+
readonly type: 'node';
|
|
1773
|
+
/** Editor instance with schema access */
|
|
1774
|
+
editor: NodeEditorContext | null;
|
|
1775
|
+
/** ProseMirror NodeType (null until editor is initialized) */
|
|
1776
|
+
readonly nodeType: NodeType | null;
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Parse rule for converting HTML to ProseMirror node
|
|
1780
|
+
* Simplified version of ProseMirror's ParseRule
|
|
1781
|
+
*/
|
|
1782
|
+
interface NodeParseRule {
|
|
1712
1783
|
/**
|
|
1713
|
-
*
|
|
1784
|
+
* CSS selector or tag name to match
|
|
1785
|
+
* @example 'p', 'h1', 'div.my-class'
|
|
1714
1786
|
*/
|
|
1715
|
-
|
|
1787
|
+
tag?: string;
|
|
1716
1788
|
/**
|
|
1717
|
-
*
|
|
1789
|
+
* Match by CSS style
|
|
1790
|
+
* @example 'font-weight'
|
|
1718
1791
|
*/
|
|
1719
|
-
|
|
1792
|
+
style?: string;
|
|
1720
1793
|
/**
|
|
1721
|
-
*
|
|
1794
|
+
* Priority for this rule (higher = checked first)
|
|
1795
|
+
* @default 50
|
|
1722
1796
|
*/
|
|
1723
|
-
|
|
1797
|
+
priority?: number;
|
|
1724
1798
|
/**
|
|
1725
|
-
*
|
|
1726
|
-
* @
|
|
1799
|
+
* Whether to consume the matched element
|
|
1800
|
+
* @default true
|
|
1727
1801
|
*/
|
|
1728
|
-
|
|
1729
|
-
transaction: Transaction;
|
|
1730
|
-
}): void;
|
|
1802
|
+
consuming?: boolean;
|
|
1731
1803
|
/**
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1804
|
+
* Context required for this rule to match
|
|
1805
|
+
* ProseMirror content expression
|
|
1734
1806
|
*/
|
|
1735
|
-
|
|
1736
|
-
event: FocusEvent;
|
|
1737
|
-
}): void;
|
|
1807
|
+
context?: string;
|
|
1738
1808
|
/**
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1809
|
+
* Get attributes from the matched element
|
|
1810
|
+
* Return null/undefined to skip this rule
|
|
1741
1811
|
*/
|
|
1742
|
-
|
|
1743
|
-
event: FocusEvent;
|
|
1744
|
-
}): void;
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
/**
|
|
1748
|
-
* Inline Styles Utility
|
|
1749
|
-
*
|
|
1750
|
-
* Applies inline CSS styles to serialized HTML so it renders correctly
|
|
1751
|
-
* when pasted outside the editor (email clients, CMS, Google Docs, etc.).
|
|
1752
|
-
*
|
|
1753
|
-
* Uses hardcoded light-theme defaults (same approach as Google Docs, Notion,
|
|
1754
|
-
* TinyMCE). Optionally accepts overrides for custom styling.
|
|
1755
|
-
*
|
|
1756
|
-
* Only structural styles are inlined (borders, padding, margins, fonts).
|
|
1757
|
-
* Colors are NOT inlined — explicit colors (TextColor, Highlight, cell bg)
|
|
1758
|
-
* are already inline from renderHTML, and default text color is browser default.
|
|
1759
|
-
*/
|
|
1760
|
-
interface InlineStyleOverrides {
|
|
1761
|
-
blockquoteBorder?: string;
|
|
1762
|
-
blockquoteColor?: string;
|
|
1763
|
-
tableBorder?: string;
|
|
1764
|
-
tableHeaderBg?: string;
|
|
1765
|
-
codeBg?: string;
|
|
1766
|
-
codeFont?: string;
|
|
1767
|
-
codeBorder?: string;
|
|
1768
|
-
codeBlockBg?: string;
|
|
1769
|
-
codeBlockFont?: string;
|
|
1770
|
-
hrBorder?: string;
|
|
1771
|
-
linkColor?: string;
|
|
1772
|
-
detailsBorder?: string;
|
|
1773
|
-
detailsBg?: string;
|
|
1812
|
+
getAttrs?: ((node: HTMLElement) => Record<string, unknown> | null | undefined) | null;
|
|
1774
1813
|
/**
|
|
1775
|
-
*
|
|
1776
|
-
*
|
|
1777
|
-
* - `'pixel'`: convert to pixel widths on first-row cells, table gets fixed width
|
|
1778
|
-
* - `'none'`: leave `data-colwidth` as-is, no width styles applied
|
|
1814
|
+
* Get content from the matched element
|
|
1815
|
+
* Return false to use default content parsing
|
|
1779
1816
|
*/
|
|
1780
|
-
|
|
1817
|
+
getContent?: (node: HTMLElement, schema: unknown) => unknown;
|
|
1781
1818
|
/**
|
|
1782
|
-
*
|
|
1783
|
-
* Receives the raw text content and optional language, returns highlighted HTML
|
|
1784
|
-
* with `<span class="hljs-*">` markup (or any spans with inline styles).
|
|
1785
|
-
*
|
|
1786
|
-
* @example
|
|
1787
|
-
* ```ts
|
|
1788
|
-
* import { createLowlight, common } from 'lowlight';
|
|
1789
|
-
* import { toHtml } from 'hast-util-to-html';
|
|
1790
|
-
* const lowlight = createLowlight(common);
|
|
1791
|
-
*
|
|
1792
|
-
* inlineStyles(html, {
|
|
1793
|
-
* codeHighlighter: (code, language) => {
|
|
1794
|
-
* if (language && lowlight.registered(language)) {
|
|
1795
|
-
* return toHtml(lowlight.highlight(language, code));
|
|
1796
|
-
* }
|
|
1797
|
-
* return null; // no highlighting
|
|
1798
|
-
* },
|
|
1799
|
-
* });
|
|
1800
|
-
* ```
|
|
1819
|
+
* How to preserve whitespace
|
|
1801
1820
|
*/
|
|
1802
|
-
|
|
1821
|
+
preserveWhitespace?: boolean | 'full';
|
|
1803
1822
|
}
|
|
1804
1823
|
/**
|
|
1805
|
-
*
|
|
1806
|
-
* Exported for use in clipboardSerializer (operates on DOM directly).
|
|
1807
|
-
*/
|
|
1808
|
-
declare function applyInlineStyles(container: HTMLElement, overrides?: InlineStyleOverrides): void;
|
|
1809
|
-
/**
|
|
1810
|
-
* Takes an HTML string and returns it with inline CSS styles applied
|
|
1811
|
-
* to all elements, so it renders correctly outside the editor.
|
|
1812
|
-
*
|
|
1813
|
-
* @param html - Serialized HTML string from editor.getHTML()
|
|
1814
|
-
* @param overrides - Optional style overrides for custom theming
|
|
1815
|
-
*
|
|
1816
|
-
* @example
|
|
1817
|
-
* ```ts
|
|
1818
|
-
* // Default light-theme styles
|
|
1819
|
-
* const styled = inlineStyles(editor.getHTML());
|
|
1820
|
-
*
|
|
1821
|
-
* // With custom overrides
|
|
1822
|
-
* const styled = inlineStyles(editor.getHTML(), {
|
|
1823
|
-
* blockquoteBorder: '5px solid red',
|
|
1824
|
-
* linkColor: '#ff6600',
|
|
1825
|
-
* });
|
|
1826
|
-
* ```
|
|
1827
|
-
*/
|
|
1828
|
-
declare function inlineStyles(html: string, overrides?: InlineStyleOverrides): string;
|
|
1829
|
-
|
|
1830
|
-
/**
|
|
1831
|
-
* Editor - Main editor class wrapping ProseMirror
|
|
1832
|
-
*
|
|
1833
|
-
* Manages extensions, schema, commands, and the ProseMirror EditorView/State.
|
|
1834
|
-
*/
|
|
1835
|
-
|
|
1836
|
-
/**
|
|
1837
|
-
* Main editor class
|
|
1838
|
-
*
|
|
1839
|
-
* Wraps ProseMirror's EditorView and EditorState with a cleaner API.
|
|
1840
|
-
*
|
|
1841
|
-
* @example
|
|
1842
|
-
* ```ts
|
|
1843
|
-
* import { Editor } from '@domternal/core';
|
|
1844
|
-
* import { Schema } from '@domternal/pm/model';
|
|
1845
|
-
*
|
|
1846
|
-
* const schema = new Schema({
|
|
1847
|
-
* nodes: { doc: { content: 'paragraph+' }, paragraph: { content: 'text*' }, text: {} }
|
|
1848
|
-
* });
|
|
1849
|
-
*
|
|
1850
|
-
* const editor = new Editor({
|
|
1851
|
-
* schema,
|
|
1852
|
-
* element: document.getElementById('editor'),
|
|
1853
|
-
* content: '<p>Hello world</p>',
|
|
1854
|
-
* });
|
|
1855
|
-
*
|
|
1856
|
-
* // Get content
|
|
1857
|
-
* const json = editor.getJSON();
|
|
1858
|
-
* const html = editor.getHTML();
|
|
1859
|
-
*
|
|
1860
|
-
* // Set content
|
|
1861
|
-
* editor.commands.setContent('<p>New content</p>');
|
|
1862
|
-
*
|
|
1863
|
-
* // Cleanup
|
|
1864
|
-
* editor.destroy();
|
|
1865
|
-
* ```
|
|
1824
|
+
* Props passed to renderHTML function
|
|
1866
1825
|
*/
|
|
1867
|
-
|
|
1868
|
-
/**
|
|
1869
|
-
* Editor configuration options
|
|
1870
|
-
*/
|
|
1871
|
-
private options;
|
|
1872
|
-
/**
|
|
1873
|
-
* Manages extensions and schema
|
|
1874
|
-
* @internal Exposed for CommandManager, not for public use
|
|
1875
|
-
*/
|
|
1876
|
-
private _extensionManager;
|
|
1826
|
+
interface NodeRenderHTMLProps {
|
|
1877
1827
|
/**
|
|
1878
|
-
*
|
|
1879
|
-
* @internal For CommandManager use only
|
|
1828
|
+
* The ProseMirror node being rendered
|
|
1880
1829
|
*/
|
|
1881
|
-
|
|
1830
|
+
node: Node$1;
|
|
1882
1831
|
/**
|
|
1883
|
-
*
|
|
1832
|
+
* Merged HTML attributes from all sources
|
|
1884
1833
|
*/
|
|
1885
|
-
|
|
1834
|
+
HTMLAttributes: Record<string, unknown>;
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Node-specific configuration properties (schema-related)
|
|
1838
|
+
*/
|
|
1839
|
+
interface NodeSchemaProperties {
|
|
1886
1840
|
/**
|
|
1887
|
-
*
|
|
1841
|
+
* Node group(s) this node belongs to
|
|
1842
|
+
* Used in content expressions
|
|
1843
|
+
*
|
|
1844
|
+
* @example 'block', 'inline', 'block list'
|
|
1845
|
+
* Can be a function that returns the group string (useful for dynamic group based on options)
|
|
1888
1846
|
*/
|
|
1889
|
-
|
|
1847
|
+
group?: string | (() => string);
|
|
1890
1848
|
/**
|
|
1891
|
-
*
|
|
1849
|
+
* Content expression defining allowed children
|
|
1850
|
+
* Uses ProseMirror content expression syntax
|
|
1851
|
+
*
|
|
1852
|
+
* @example 'inline*', 'block+', 'paragraph block*'
|
|
1892
1853
|
*/
|
|
1893
|
-
|
|
1854
|
+
content?: string;
|
|
1894
1855
|
/**
|
|
1895
|
-
*
|
|
1856
|
+
* Whether this is an inline node
|
|
1857
|
+
* Can be a function for dynamic inline based on options
|
|
1858
|
+
* @default false
|
|
1896
1859
|
*/
|
|
1897
|
-
|
|
1860
|
+
inline?: boolean | (() => boolean);
|
|
1898
1861
|
/**
|
|
1899
|
-
*
|
|
1862
|
+
* Whether this node is an atom (no direct content editing)
|
|
1863
|
+
* Cursor moves around atoms, not into them
|
|
1900
1864
|
*
|
|
1901
|
-
* @
|
|
1902
|
-
* @throws Error if running in SSR environment (no window)
|
|
1903
|
-
* @throws Error if schema is not provided
|
|
1865
|
+
* @example true for images, mentions, emoji
|
|
1904
1866
|
*/
|
|
1905
|
-
|
|
1867
|
+
atom?: boolean;
|
|
1906
1868
|
/**
|
|
1907
|
-
*
|
|
1869
|
+
* Whether the node can be selected as a whole
|
|
1870
|
+
* @default true for leaf nodes, false for others
|
|
1908
1871
|
*/
|
|
1909
|
-
|
|
1872
|
+
selectable?: boolean;
|
|
1910
1873
|
/**
|
|
1911
|
-
*
|
|
1874
|
+
* Whether the node can be dragged
|
|
1875
|
+
* @default false
|
|
1912
1876
|
*/
|
|
1913
|
-
|
|
1877
|
+
draggable?: boolean;
|
|
1914
1878
|
/**
|
|
1915
|
-
*
|
|
1879
|
+
* Whether this node represents code
|
|
1880
|
+
* Affects text input handling (disables smart quotes, etc.)
|
|
1916
1881
|
*/
|
|
1917
|
-
|
|
1882
|
+
code?: boolean;
|
|
1918
1883
|
/**
|
|
1919
|
-
*
|
|
1884
|
+
* How whitespace is handled in this node
|
|
1885
|
+
* - 'pre': preserve whitespace (like <pre>)
|
|
1886
|
+
* - 'normal': collapse whitespace (default)
|
|
1920
1887
|
*/
|
|
1921
|
-
|
|
1888
|
+
whitespace?: 'pre' | 'normal';
|
|
1922
1889
|
/**
|
|
1923
|
-
*
|
|
1890
|
+
* Whether this node isolates marks at its boundaries
|
|
1891
|
+
* Marks don't extend across isolating boundaries
|
|
1924
1892
|
*/
|
|
1925
|
-
|
|
1893
|
+
isolating?: boolean;
|
|
1926
1894
|
/**
|
|
1927
|
-
*
|
|
1895
|
+
* Whether a gap cursor is allowed inside this node.
|
|
1896
|
+
* Set to false to prevent gapcursor from appearing inside this node.
|
|
1897
|
+
* Set to true to force gapcursor even if the default heuristic disallows it.
|
|
1898
|
+
* When undefined, uses ProseMirror's default heuristic.
|
|
1928
1899
|
*/
|
|
1929
|
-
|
|
1900
|
+
allowGapCursor?: boolean;
|
|
1930
1901
|
/**
|
|
1931
|
-
*
|
|
1932
|
-
*
|
|
1902
|
+
* Table role for prosemirror-tables integration.
|
|
1903
|
+
* Nodes with a tableRole are discovered by prosemirror-tables via spec.tableRole.
|
|
1904
|
+
* One of: 'table', 'row', 'cell', 'header_cell'
|
|
1933
1905
|
*/
|
|
1934
|
-
|
|
1906
|
+
tableRole?: 'table' | 'row' | 'cell' | 'header_cell';
|
|
1935
1907
|
/**
|
|
1936
|
-
*
|
|
1937
|
-
*
|
|
1908
|
+
* Whether this is a top-level node (document root)
|
|
1909
|
+
* Only one node should have this set to true
|
|
1938
1910
|
*/
|
|
1939
|
-
|
|
1911
|
+
topNode?: boolean;
|
|
1940
1912
|
/**
|
|
1941
|
-
*
|
|
1942
|
-
*
|
|
1913
|
+
* Whether this node defines its own scope
|
|
1914
|
+
* Content and marks don't leak out of defining nodes
|
|
1943
1915
|
*/
|
|
1944
|
-
|
|
1916
|
+
defining?: boolean;
|
|
1945
1917
|
/**
|
|
1946
|
-
*
|
|
1947
|
-
*
|
|
1918
|
+
* Which marks are allowed in this node
|
|
1919
|
+
* Empty string means no marks allowed
|
|
1920
|
+
*
|
|
1921
|
+
* @example '', '_', 'bold italic'
|
|
1948
1922
|
*/
|
|
1949
|
-
|
|
1923
|
+
marks?: string;
|
|
1950
1924
|
/**
|
|
1951
|
-
*
|
|
1952
|
-
*
|
|
1925
|
+
* Custom text for leaf nodes returned by `getText()` / `textContent`.
|
|
1926
|
+
*
|
|
1927
|
+
* @example '\n' for hard break
|
|
1953
1928
|
*/
|
|
1954
|
-
|
|
1929
|
+
leafText?: string | ((node: Node$1) => string);
|
|
1955
1930
|
/**
|
|
1956
|
-
*
|
|
1957
|
-
*
|
|
1958
|
-
* For toolbar button states - returns true if:
|
|
1959
|
-
* - For marks: the current selection has the mark applied
|
|
1960
|
-
* - For nodes: the cursor is inside that node type
|
|
1961
|
-
*
|
|
1962
|
-
* @param nameOrAttributes - Extension name, or object with name and attributes
|
|
1963
|
-
* @param attributes - Optional attributes to match (for node/mark specific states)
|
|
1931
|
+
* Define node attributes
|
|
1932
|
+
* Returns attribute specifications
|
|
1964
1933
|
*
|
|
1965
1934
|
* @example
|
|
1966
|
-
*
|
|
1967
|
-
*
|
|
1968
|
-
*
|
|
1935
|
+
* addAttributes() {
|
|
1936
|
+
* return {
|
|
1937
|
+
* level: { default: 1 },
|
|
1938
|
+
* };
|
|
1939
|
+
* }
|
|
1969
1940
|
*/
|
|
1970
|
-
|
|
1971
|
-
name: string;
|
|
1972
|
-
attributes?: Record<string, unknown>;
|
|
1973
|
-
}, attributes?: Record<string, unknown>): boolean;
|
|
1941
|
+
addAttributes?: () => AttributeSpecs;
|
|
1974
1942
|
/**
|
|
1975
|
-
*
|
|
1976
|
-
*
|
|
1977
|
-
* Returns empty object if the node/mark is not found or not active.
|
|
1943
|
+
* Parse rules for converting HTML to this node
|
|
1944
|
+
* Each rule defines how to match and parse HTML elements
|
|
1978
1945
|
*
|
|
1979
|
-
* @
|
|
1946
|
+
* @example
|
|
1947
|
+
* parseHTML() {
|
|
1948
|
+
* return [
|
|
1949
|
+
* { tag: 'p' },
|
|
1950
|
+
* { tag: 'div', priority: 10 },
|
|
1951
|
+
* ];
|
|
1952
|
+
* }
|
|
1953
|
+
*/
|
|
1954
|
+
parseHTML?: () => NodeParseRule[];
|
|
1955
|
+
/**
|
|
1956
|
+
* Render this node to DOM
|
|
1957
|
+
* Returns DOMOutputSpec (tag, attributes, children)
|
|
1980
1958
|
*
|
|
1981
1959
|
* @example
|
|
1982
|
-
*
|
|
1983
|
-
*
|
|
1960
|
+
* renderHTML({ node, HTMLAttributes }) {
|
|
1961
|
+
* return ['p', HTMLAttributes, 0];
|
|
1962
|
+
* }
|
|
1984
1963
|
*/
|
|
1985
|
-
|
|
1964
|
+
renderHTML?: (props: NodeRenderHTMLProps) => DOMOutputSpec;
|
|
1986
1965
|
/**
|
|
1987
|
-
*
|
|
1988
|
-
*
|
|
1966
|
+
* Custom node view constructor
|
|
1967
|
+
* For complex interactive nodes
|
|
1989
1968
|
*/
|
|
1990
|
-
|
|
1969
|
+
addNodeView?: () => NodeViewConstructor;
|
|
1991
1970
|
/**
|
|
1992
|
-
*
|
|
1971
|
+
* Additional ProseMirror plugins for this node
|
|
1972
|
+
* Called during plugin collection
|
|
1993
1973
|
*/
|
|
1994
|
-
|
|
1974
|
+
addProseMirrorPlugins?: () => Plugin[];
|
|
1975
|
+
}
|
|
1976
|
+
/**
|
|
1977
|
+
* Configuration for Node extensions
|
|
1978
|
+
* Combines ExtensionConfig base with node-specific schema properties.
|
|
1979
|
+
* Uses ThisType<NodeContext> to provide proper typing for `this` in config methods.
|
|
1980
|
+
*
|
|
1981
|
+
* @typeParam Options - Node options type
|
|
1982
|
+
* @typeParam Storage - Node storage type
|
|
1983
|
+
*
|
|
1984
|
+
* @example
|
|
1985
|
+
* const Paragraph = Node.create({
|
|
1986
|
+
* name: 'paragraph',
|
|
1987
|
+
* group: 'block',
|
|
1988
|
+
* content: 'inline*',
|
|
1989
|
+
* parseHTML() {
|
|
1990
|
+
* // `this` is properly typed here!
|
|
1991
|
+
* return [{ tag: 'p' }];
|
|
1992
|
+
* },
|
|
1993
|
+
* renderHTML({ HTMLAttributes }) {
|
|
1994
|
+
* return ['p', HTMLAttributes, 0];
|
|
1995
|
+
* },
|
|
1996
|
+
* });
|
|
1997
|
+
*/
|
|
1998
|
+
type NodeConfig<Options = unknown, Storage = unknown> = ExtensionConfigBase<Options, Storage> & NodeSchemaProperties & ThisType<NodeContext<Options, Storage>>;
|
|
1999
|
+
|
|
2000
|
+
/**
|
|
2001
|
+
* Mark configuration types
|
|
2002
|
+
*
|
|
2003
|
+
* These types define the configuration object passed to Mark.create()
|
|
2004
|
+
* for creating ProseMirror mark extensions.
|
|
2005
|
+
*/
|
|
2006
|
+
|
|
2007
|
+
/**
|
|
2008
|
+
* Editor interface for Mark context
|
|
2009
|
+
* Includes schema with marks for MarkType getter
|
|
2010
|
+
*/
|
|
2011
|
+
interface MarkEditorContext {
|
|
2012
|
+
readonly state: EditorState;
|
|
2013
|
+
readonly view: EditorView;
|
|
2014
|
+
readonly schema: {
|
|
2015
|
+
marks: Record<string, MarkType>;
|
|
2016
|
+
};
|
|
2017
|
+
readonly commands: Record<string, (...args: unknown[]) => boolean>;
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* Context interface for Mark config methods.
|
|
2021
|
+
* Extends ExtensionContext with mark-specific properties.
|
|
2022
|
+
* This enables proper typing of `this.options`, `this.markType`, etc.
|
|
2023
|
+
*
|
|
2024
|
+
* @typeParam Options - Mark options type
|
|
2025
|
+
* @typeParam Storage - Mark storage type
|
|
2026
|
+
*/
|
|
2027
|
+
interface MarkContext<Options = unknown, Storage = unknown> extends Omit<ExtensionContext<Options, Storage>, 'editor' | 'type'> {
|
|
2028
|
+
/** Mark type identifier */
|
|
2029
|
+
readonly type: 'mark';
|
|
2030
|
+
/** Editor instance with schema access */
|
|
2031
|
+
editor: MarkEditorContext | null;
|
|
2032
|
+
/** ProseMirror MarkType (null until editor is initialized) */
|
|
2033
|
+
readonly markType: MarkType | null;
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Parse rule for converting HTML to ProseMirror mark
|
|
2037
|
+
* Simplified version of ProseMirror's ParseRule for marks
|
|
2038
|
+
*/
|
|
2039
|
+
interface MarkParseRule {
|
|
1995
2040
|
/**
|
|
1996
|
-
*
|
|
1997
|
-
*
|
|
1998
|
-
* @param options - Optional settings
|
|
1999
|
-
* @param options.styled - When true (or an override object), applies inline CSS
|
|
2000
|
-
* styles so the HTML renders correctly outside the editor (email, CMS, etc.)
|
|
2041
|
+
* CSS selector or tag name to match
|
|
2042
|
+
* @example 'strong', 'b', 'span.bold'
|
|
2001
2043
|
*/
|
|
2002
|
-
|
|
2003
|
-
styled?: boolean | InlineStyleOverrides;
|
|
2004
|
-
}): string;
|
|
2044
|
+
tag?: string;
|
|
2005
2045
|
/**
|
|
2006
|
-
*
|
|
2007
|
-
*
|
|
2008
|
-
* @
|
|
2009
|
-
* @param options.blockSeparator - String to insert between blocks (default: '\n\n')
|
|
2046
|
+
* Match by CSS style property
|
|
2047
|
+
* Can include expected value after '='
|
|
2048
|
+
* @example 'font-weight', 'font-weight=bold'
|
|
2010
2049
|
*/
|
|
2011
|
-
|
|
2012
|
-
blockSeparator?: string;
|
|
2013
|
-
}): string;
|
|
2050
|
+
style?: string;
|
|
2014
2051
|
/**
|
|
2015
|
-
*
|
|
2016
|
-
* @
|
|
2052
|
+
* Priority for this rule (higher = checked first)
|
|
2053
|
+
* @default 50
|
|
2017
2054
|
*/
|
|
2018
|
-
|
|
2055
|
+
priority?: number;
|
|
2019
2056
|
/**
|
|
2020
|
-
*
|
|
2021
|
-
*
|
|
2022
|
-
* @param content - JSON or HTML content
|
|
2023
|
-
* @param emitUpdate - Whether to emit update event (default: true)
|
|
2024
|
-
* @returns true if content was set successfully, false if content was invalid
|
|
2057
|
+
* Whether to consume the matched element
|
|
2058
|
+
* @default true
|
|
2025
2059
|
*/
|
|
2026
|
-
|
|
2060
|
+
consuming?: boolean;
|
|
2027
2061
|
/**
|
|
2028
|
-
*
|
|
2062
|
+
* Get attributes from the matched element
|
|
2063
|
+
* Return null/undefined to skip this rule
|
|
2064
|
+
* Return false to explicitly not match
|
|
2029
2065
|
*
|
|
2030
|
-
*
|
|
2031
|
-
* @returns true if content was cleared successfully
|
|
2066
|
+
* For style rules, receives the style value as string
|
|
2032
2067
|
*/
|
|
2033
|
-
|
|
2068
|
+
getAttrs?: ((node: HTMLElement | string) => Record<string, unknown> | false | null) | null;
|
|
2069
|
+
}
|
|
2070
|
+
/**
|
|
2071
|
+
* Props passed to renderHTML function for marks
|
|
2072
|
+
*/
|
|
2073
|
+
interface MarkRenderHTMLProps {
|
|
2034
2074
|
/**
|
|
2035
|
-
*
|
|
2036
|
-
*
|
|
2037
|
-
* @param editable - Whether the editor should be editable
|
|
2075
|
+
* The ProseMirror mark being rendered
|
|
2038
2076
|
*/
|
|
2039
|
-
|
|
2077
|
+
mark: Mark$1;
|
|
2040
2078
|
/**
|
|
2041
|
-
*
|
|
2042
|
-
*
|
|
2043
|
-
* @param position - Where to place cursor (default: null = just focus)
|
|
2079
|
+
* Merged HTML attributes from all sources
|
|
2044
2080
|
*/
|
|
2045
|
-
|
|
2081
|
+
HTMLAttributes: Record<string, unknown>;
|
|
2082
|
+
}
|
|
2083
|
+
/**
|
|
2084
|
+
* Mark-specific configuration properties (schema-related)
|
|
2085
|
+
*/
|
|
2086
|
+
interface MarkSchemaProperties {
|
|
2046
2087
|
/**
|
|
2047
|
-
*
|
|
2088
|
+
* Whether this mark should be active when the cursor
|
|
2089
|
+
* is at its end (or beginning for marks that open).
|
|
2090
|
+
*
|
|
2091
|
+
* When true, typing at the mark's boundary continues the mark.
|
|
2092
|
+
* When false, typing creates unmarked content.
|
|
2093
|
+
*
|
|
2094
|
+
* @default true
|
|
2048
2095
|
*/
|
|
2049
|
-
|
|
2096
|
+
inclusive?: boolean | (() => boolean);
|
|
2050
2097
|
/**
|
|
2051
|
-
*
|
|
2052
|
-
*
|
|
2053
|
-
*
|
|
2098
|
+
* Marks that this mark excludes (cannot coexist with)
|
|
2099
|
+
*
|
|
2100
|
+
* - '_' excludes all marks
|
|
2101
|
+
* - Space-separated mark names exclude specific marks
|
|
2102
|
+
* - Empty string or undefined means no exclusions
|
|
2103
|
+
*
|
|
2104
|
+
* @example 'code' - excludes code mark
|
|
2105
|
+
* @example 'bold italic' - excludes bold and italic
|
|
2106
|
+
* @example '_' - excludes all other marks
|
|
2054
2107
|
*/
|
|
2055
|
-
|
|
2108
|
+
excludes?: string;
|
|
2056
2109
|
/**
|
|
2057
|
-
*
|
|
2058
|
-
*
|
|
2110
|
+
* Mark group(s) this mark belongs to
|
|
2111
|
+
* Used in node's marks property
|
|
2112
|
+
*
|
|
2113
|
+
* @example 'formatting', 'inline'
|
|
2059
2114
|
*/
|
|
2060
|
-
|
|
2115
|
+
group?: string;
|
|
2061
2116
|
/**
|
|
2062
|
-
*
|
|
2117
|
+
* Whether this mark can span multiple nodes
|
|
2063
2118
|
*
|
|
2064
|
-
*
|
|
2119
|
+
* When true (default), the mark persists across inline nodes.
|
|
2120
|
+
* When false, the mark only applies within a single text node.
|
|
2121
|
+
*
|
|
2122
|
+
* @default true
|
|
2065
2123
|
*/
|
|
2066
|
-
|
|
2124
|
+
spanning?: boolean;
|
|
2067
2125
|
/**
|
|
2068
|
-
*
|
|
2126
|
+
* Whether this mark represents visual formatting.
|
|
2127
|
+
*
|
|
2128
|
+
* Used by `unsetAllMarks` to decide which marks to remove.
|
|
2129
|
+
* Marks with `isFormatting: false` survive clear formatting
|
|
2130
|
+
* (e.g., links, comments, annotations).
|
|
2131
|
+
*
|
|
2132
|
+
* Can be overridden via `.configure()`:
|
|
2133
|
+
* ```ts
|
|
2134
|
+
* Link.configure({ isFormatting: true }) // make links clearable
|
|
2135
|
+
* ```
|
|
2136
|
+
*
|
|
2137
|
+
* @default true
|
|
2069
2138
|
*/
|
|
2070
|
-
|
|
2139
|
+
isFormatting?: boolean;
|
|
2071
2140
|
/**
|
|
2072
|
-
*
|
|
2141
|
+
* Define mark attributes
|
|
2142
|
+
* Returns attribute specifications
|
|
2143
|
+
*
|
|
2144
|
+
* @example
|
|
2145
|
+
* addAttributes() {
|
|
2146
|
+
* return {
|
|
2147
|
+
* color: { default: null },
|
|
2148
|
+
* };
|
|
2149
|
+
* }
|
|
2073
2150
|
*/
|
|
2074
|
-
|
|
2151
|
+
addAttributes?: () => AttributeSpecs;
|
|
2075
2152
|
/**
|
|
2076
|
-
*
|
|
2153
|
+
* Parse rules for converting HTML to this mark
|
|
2154
|
+
* Each rule defines how to match and parse HTML elements
|
|
2155
|
+
*
|
|
2156
|
+
* @example
|
|
2157
|
+
* parseHTML() {
|
|
2158
|
+
* return [
|
|
2159
|
+
* { tag: 'strong' },
|
|
2160
|
+
* { tag: 'b' },
|
|
2161
|
+
* { style: 'font-weight', getAttrs: (value) => /bold|[5-9]\d{2}/.test(value) && null },
|
|
2162
|
+
* ];
|
|
2163
|
+
* }
|
|
2077
2164
|
*/
|
|
2078
|
-
|
|
2165
|
+
parseHTML?: () => MarkParseRule[];
|
|
2079
2166
|
/**
|
|
2080
|
-
*
|
|
2167
|
+
* Render this mark to DOM
|
|
2168
|
+
* Returns DOMOutputSpec (tag, attributes, hole)
|
|
2169
|
+
*
|
|
2170
|
+
* The 0 in the return array indicates where child content goes.
|
|
2171
|
+
*
|
|
2172
|
+
* @example
|
|
2173
|
+
* renderHTML({ mark, HTMLAttributes }) {
|
|
2174
|
+
* return ['strong', HTMLAttributes, 0];
|
|
2175
|
+
* }
|
|
2081
2176
|
*/
|
|
2082
|
-
|
|
2177
|
+
renderHTML?: (props: MarkRenderHTMLProps) => DOMOutputSpec;
|
|
2083
2178
|
}
|
|
2179
|
+
/**
|
|
2180
|
+
* Configuration for Mark extensions
|
|
2181
|
+
* Combines ExtensionConfigBase with mark-specific schema properties.
|
|
2182
|
+
* Uses ThisType<MarkContext> to provide proper typing for `this` in config methods.
|
|
2183
|
+
*
|
|
2184
|
+
* @typeParam Options - Mark options type
|
|
2185
|
+
* @typeParam Storage - Mark storage type
|
|
2186
|
+
*
|
|
2187
|
+
* @example
|
|
2188
|
+
* const Bold = Mark.create({
|
|
2189
|
+
* name: 'bold',
|
|
2190
|
+
* parseHTML() {
|
|
2191
|
+
* // `this` is properly typed here!
|
|
2192
|
+
* return [{ tag: 'strong' }, { tag: 'b' }];
|
|
2193
|
+
* },
|
|
2194
|
+
* renderHTML({ HTMLAttributes }) {
|
|
2195
|
+
* return ['strong', HTMLAttributes, 0];
|
|
2196
|
+
* },
|
|
2197
|
+
* });
|
|
2198
|
+
*/
|
|
2199
|
+
type MarkConfig<Options = unknown, Storage = unknown> = ExtensionConfigBase<Options, Storage> & MarkSchemaProperties & ThisType<MarkContext<Options, Storage>>;
|
|
2084
2200
|
|
|
2085
2201
|
/**
|
|
2086
2202
|
* Focus command - focuses the editor at the specified position
|
|
@@ -2092,30 +2208,30 @@ declare class Editor extends EventEmitter<EditorEvents> {
|
|
|
2092
2208
|
* - number: Specific position
|
|
2093
2209
|
* - null/false: Just focus without changing selection
|
|
2094
2210
|
*/
|
|
2095
|
-
declare const focus: CommandSpec
|
|
2211
|
+
declare const focus: CommandSpec<[position?: FocusPosition]>;
|
|
2096
2212
|
/**
|
|
2097
2213
|
* Blur command - removes focus from the editor
|
|
2098
2214
|
*/
|
|
2099
|
-
declare const blur: CommandSpec
|
|
2215
|
+
declare const blur: CommandSpec;
|
|
2100
2216
|
/**
|
|
2101
2217
|
* SelectAll command - selects all content in the editor
|
|
2102
2218
|
*
|
|
2103
2219
|
* Uses AllSelection to select the entire document.
|
|
2104
2220
|
* Uses tr.doc to support chain context.
|
|
2105
2221
|
*/
|
|
2106
|
-
declare const selectAll: CommandSpec
|
|
2222
|
+
declare const selectAll: CommandSpec;
|
|
2107
2223
|
/**
|
|
2108
2224
|
* SelectNodeBackward command - selects the node before the cursor
|
|
2109
2225
|
*
|
|
2110
2226
|
* When the cursor is at the start of a textblock, this selects the node before it.
|
|
2111
2227
|
*/
|
|
2112
|
-
declare const selectNodeBackward: CommandSpec
|
|
2228
|
+
declare const selectNodeBackward: CommandSpec;
|
|
2113
2229
|
/**
|
|
2114
2230
|
* DeleteSelection command - deletes the current selection
|
|
2115
2231
|
*
|
|
2116
2232
|
* Uses tr.selection to support chain context.
|
|
2117
2233
|
*/
|
|
2118
|
-
declare const deleteSelection: CommandSpec
|
|
2234
|
+
declare const deleteSelection: CommandSpec;
|
|
2119
2235
|
|
|
2120
2236
|
/**
|
|
2121
2237
|
* Options for setContent command
|
|
@@ -2147,28 +2263,28 @@ interface ClearContentOptions {
|
|
|
2147
2263
|
* @param content - JSON or HTML content
|
|
2148
2264
|
* @param options - Options for setting content
|
|
2149
2265
|
*/
|
|
2150
|
-
declare const setContent: CommandSpec
|
|
2266
|
+
declare const setContent: CommandSpec<[content: Content, options?: SetContentOptions]>;
|
|
2151
2267
|
/**
|
|
2152
2268
|
* ClearContent command - clears the editor content to empty state
|
|
2153
2269
|
*
|
|
2154
2270
|
* @param options - Options for clearing content
|
|
2155
2271
|
*/
|
|
2156
|
-
declare const clearContent: CommandSpec
|
|
2272
|
+
declare const clearContent: CommandSpec<[options?: ClearContentOptions]>;
|
|
2157
2273
|
/**
|
|
2158
2274
|
* InsertText command - inserts text at the current selection
|
|
2159
2275
|
*
|
|
2160
2276
|
* @param text - Text to insert
|
|
2161
2277
|
*/
|
|
2162
|
-
declare const insertText: CommandSpec
|
|
2278
|
+
declare const insertText: CommandSpec<[text: string]>;
|
|
2163
2279
|
/**
|
|
2164
2280
|
* InsertContent command - inserts content at the current selection
|
|
2165
2281
|
*
|
|
2166
2282
|
* @param content - The content to insert (JSON object, array, or HTML string)
|
|
2167
2283
|
*/
|
|
2168
|
-
declare const insertContent: CommandSpec
|
|
2284
|
+
declare const insertContent: CommandSpec<[content: Content]>;
|
|
2169
2285
|
|
|
2170
2286
|
/**
|
|
2171
|
-
* Mark commands
|
|
2287
|
+
* Mark commands - toggleMark, setMark, unsetMark, unsetAllMarks
|
|
2172
2288
|
*/
|
|
2173
2289
|
|
|
2174
2290
|
/**
|
|
@@ -2181,20 +2297,20 @@ declare const insertContent: CommandSpec$1<[content: Content]>;
|
|
|
2181
2297
|
* @param markName - The name of the mark to toggle
|
|
2182
2298
|
* @param attributes - Optional attributes for the mark
|
|
2183
2299
|
*/
|
|
2184
|
-
declare const toggleMark: CommandSpec
|
|
2300
|
+
declare const toggleMark: CommandSpec<[markName: string, attributes?: Attrs]>;
|
|
2185
2301
|
/**
|
|
2186
2302
|
* SetMark command - adds a mark to the current selection
|
|
2187
2303
|
*
|
|
2188
2304
|
* @param markName - The name of the mark to set
|
|
2189
2305
|
* @param attributes - Optional attributes for the mark
|
|
2190
2306
|
*/
|
|
2191
|
-
declare const setMark: CommandSpec
|
|
2307
|
+
declare const setMark: CommandSpec<[markName: string, attributes?: Attrs]>;
|
|
2192
2308
|
/**
|
|
2193
2309
|
* UnsetMark command - removes a mark from the current selection
|
|
2194
2310
|
*
|
|
2195
2311
|
* @param markName - The name of the mark to remove
|
|
2196
2312
|
*/
|
|
2197
|
-
declare const unsetMark: CommandSpec
|
|
2313
|
+
declare const unsetMark: CommandSpec<[markName: string]>;
|
|
2198
2314
|
/**
|
|
2199
2315
|
* UnsetAllMarks command - removes all formatting marks from the current selection
|
|
2200
2316
|
*
|
|
@@ -2204,7 +2320,7 @@ declare const unsetMark: CommandSpec$1<[markName: string]>;
|
|
|
2204
2320
|
*
|
|
2205
2321
|
* Returns false for empty selections (no range to clear).
|
|
2206
2322
|
*/
|
|
2207
|
-
declare const unsetAllMarks: CommandSpec
|
|
2323
|
+
declare const unsetAllMarks: CommandSpec;
|
|
2208
2324
|
|
|
2209
2325
|
/**
|
|
2210
2326
|
* SetBlockType command - changes the block type of the selection
|
|
@@ -2216,7 +2332,7 @@ declare const unsetAllMarks: CommandSpec$1;
|
|
|
2216
2332
|
* @param nodeName - The name of the node type to set
|
|
2217
2333
|
* @param attributes - Optional attributes for the node
|
|
2218
2334
|
*/
|
|
2219
|
-
declare const setBlockType: CommandSpec
|
|
2335
|
+
declare const setBlockType: CommandSpec<[nodeName: string, attributes?: Attrs]>;
|
|
2220
2336
|
/**
|
|
2221
2337
|
* ToggleBlockType command - toggles between a block type and a default type
|
|
2222
2338
|
*
|
|
@@ -2228,7 +2344,7 @@ declare const setBlockType: CommandSpec$1<[nodeName: string, attributes?: Attrs]
|
|
|
2228
2344
|
* @param defaultNodeName - The name of the default node type (usually 'paragraph')
|
|
2229
2345
|
* @param attributes - Optional attributes for the node
|
|
2230
2346
|
*/
|
|
2231
|
-
declare const toggleBlockType: CommandSpec
|
|
2347
|
+
declare const toggleBlockType: CommandSpec<[nodeName: string, defaultNodeName: string, attributes?: Attrs]>;
|
|
2232
2348
|
/**
|
|
2233
2349
|
* WrapIn command - wraps the selection in a node type
|
|
2234
2350
|
*
|
|
@@ -2237,7 +2353,7 @@ declare const toggleBlockType: CommandSpec$1<[nodeName: string, defaultNodeName:
|
|
|
2237
2353
|
* @param nodeName - The name of the wrapping node type
|
|
2238
2354
|
* @param attributes - Optional attributes for the node
|
|
2239
2355
|
*/
|
|
2240
|
-
declare const wrapIn: CommandSpec
|
|
2356
|
+
declare const wrapIn: CommandSpec<[nodeName: string, attributes?: Attrs]>;
|
|
2241
2357
|
/**
|
|
2242
2358
|
* ToggleWrap command - toggles wrapping of the selection in a node type
|
|
2243
2359
|
*
|
|
@@ -2248,14 +2364,14 @@ declare const wrapIn: CommandSpec$1<[nodeName: string, attributes?: Attrs]>;
|
|
|
2248
2364
|
* @param nodeName - The name of the wrapping node type
|
|
2249
2365
|
* @param attributes - Optional attributes for the node
|
|
2250
2366
|
*/
|
|
2251
|
-
declare const toggleWrap: CommandSpec
|
|
2367
|
+
declare const toggleWrap: CommandSpec<[nodeName: string, attributes?: Attrs]>;
|
|
2252
2368
|
/**
|
|
2253
2369
|
* Lift command - lifts the current block out of its parent wrapper
|
|
2254
2370
|
*
|
|
2255
2371
|
* Uses tr.doc/tr.selection for chain compatibility.
|
|
2256
2372
|
* For example, lifts a paragraph out of a blockquote.
|
|
2257
2373
|
*/
|
|
2258
|
-
declare const lift: CommandSpec
|
|
2374
|
+
declare const lift: CommandSpec;
|
|
2259
2375
|
|
|
2260
2376
|
/**
|
|
2261
2377
|
* ToggleList command - toggles a list type on the current selection
|
|
@@ -2268,10 +2384,10 @@ declare const lift: CommandSpec$1;
|
|
|
2268
2384
|
* @param listItemNodeName - The name of the list item node type (usually 'listItem')
|
|
2269
2385
|
* @param attributes - Optional attributes for the list node
|
|
2270
2386
|
*/
|
|
2271
|
-
declare const toggleList: CommandSpec
|
|
2387
|
+
declare const toggleList: CommandSpec<[listNodeName: string, listItemNodeName: string, attributes?: Attrs]>;
|
|
2272
2388
|
|
|
2273
2389
|
/**
|
|
2274
|
-
* Attribute commands
|
|
2390
|
+
* Attribute commands - updateAttributes, resetAttributes
|
|
2275
2391
|
*/
|
|
2276
2392
|
|
|
2277
2393
|
/**
|
|
@@ -2282,7 +2398,7 @@ declare const toggleList: CommandSpec$1<[listNodeName: string, listItemNodeName:
|
|
|
2282
2398
|
* @param typeOrName - The node type name or NodeType to update
|
|
2283
2399
|
* @param attributes - The attributes to merge into existing attributes
|
|
2284
2400
|
*/
|
|
2285
|
-
declare const updateAttributes: CommandSpec
|
|
2401
|
+
declare const updateAttributes: CommandSpec<[typeOrName: string, attributes: Record<string, unknown>]>;
|
|
2286
2402
|
/**
|
|
2287
2403
|
* ResetAttributes command - resets an attribute to its default value
|
|
2288
2404
|
*
|
|
@@ -2292,7 +2408,7 @@ declare const updateAttributes: CommandSpec$1<[typeOrName: string, attributes: R
|
|
|
2292
2408
|
* @param typeOrName - The node type name to update
|
|
2293
2409
|
* @param attributeName - The name of the attribute to reset
|
|
2294
2410
|
*/
|
|
2295
|
-
declare const resetAttributes: CommandSpec
|
|
2411
|
+
declare const resetAttributes: CommandSpec<[typeOrName: string, attributeName: string]>;
|
|
2296
2412
|
|
|
2297
2413
|
/**
|
|
2298
2414
|
* Built-in commands for @domternal/core
|
|
@@ -2370,8 +2486,8 @@ declare class CommandManager {
|
|
|
2370
2486
|
*/
|
|
2371
2487
|
private buildCommandProps;
|
|
2372
2488
|
/**
|
|
2373
|
-
* Single commands that execute immediately
|
|
2374
|
-
* Uses Proxy to dynamically generate command methods
|
|
2489
|
+
* Single commands that execute immediately.
|
|
2490
|
+
* Uses a Proxy to dynamically generate command methods.
|
|
2375
2491
|
*
|
|
2376
2492
|
* @example
|
|
2377
2493
|
* editor.commands.focus('end');
|
|
@@ -2430,61 +2546,252 @@ interface PositionFloatingOptions {
|
|
|
2430
2546
|
trackScroll?: boolean;
|
|
2431
2547
|
}
|
|
2432
2548
|
/**
|
|
2433
|
-
* Positions a floating element relative to a reference element or virtual rect,
|
|
2434
|
-
* and keeps it positioned on scroll, resize, and layout shifts.
|
|
2435
|
-
*
|
|
2436
|
-
* Uses `autoUpdate` from floating-ui with `animationFrame` polling for
|
|
2437
|
-
* jitter-free scroll tracking (rAF syncs with browser paint).
|
|
2438
|
-
*
|
|
2439
|
-
* Includes `hide` middleware
|
|
2440
|
-
* view, the floating element is hidden via `visibility: hidden`.
|
|
2441
|
-
*
|
|
2442
|
-
* The floating element must have `position: fixed`.
|
|
2443
|
-
*
|
|
2444
|
-
* Returns a cleanup function. **Always call it** when hiding or destroying
|
|
2445
|
-
* the floating element to stop listeners and prevent memory leaks.
|
|
2446
|
-
*
|
|
2447
|
-
* @example
|
|
2448
|
-
* ```ts
|
|
2449
|
-
* // Start auto-positioning (follows scroll/resize)
|
|
2450
|
-
* const cleanup = positionFloating(buttonEl, dropdownEl, {
|
|
2451
|
-
* placement: 'bottom-start',
|
|
2452
|
-
* });
|
|
2453
|
-
*
|
|
2454
|
-
* // Virtual reference (e.g. cursor position
|
|
2455
|
-
* const virtualEl = {
|
|
2456
|
-
* getBoundingClientRect: () => {
|
|
2457
|
-
* const coords = view.coordsAtPos(pos);
|
|
2458
|
-
* return new DOMRect(coords.left, coords.top, 0, coords.bottom - coords.top);
|
|
2459
|
-
* },
|
|
2460
|
-
* };
|
|
2461
|
-
* const cleanup = positionFloating(virtualEl, tooltipEl, { placement: 'top' });
|
|
2549
|
+
* Positions a floating element relative to a reference element or virtual rect,
|
|
2550
|
+
* and keeps it positioned on scroll, resize, and layout shifts.
|
|
2551
|
+
*
|
|
2552
|
+
* Uses `autoUpdate` from floating-ui with `animationFrame` polling for
|
|
2553
|
+
* jitter-free scroll tracking (rAF syncs with browser paint).
|
|
2554
|
+
*
|
|
2555
|
+
* Includes `hide` middleware - when the reference element is scrolled out of
|
|
2556
|
+
* view, the floating element is hidden via `visibility: hidden`.
|
|
2557
|
+
*
|
|
2558
|
+
* The floating element must have `position: fixed`.
|
|
2559
|
+
*
|
|
2560
|
+
* Returns a cleanup function. **Always call it** when hiding or destroying
|
|
2561
|
+
* the floating element to stop listeners and prevent memory leaks.
|
|
2562
|
+
*
|
|
2563
|
+
* @example
|
|
2564
|
+
* ```ts
|
|
2565
|
+
* // Start auto-positioning (follows scroll/resize)
|
|
2566
|
+
* const cleanup = positionFloating(buttonEl, dropdownEl, {
|
|
2567
|
+
* placement: 'bottom-start',
|
|
2568
|
+
* });
|
|
2569
|
+
*
|
|
2570
|
+
* // Virtual reference (e.g. cursor position - must return fresh coords)
|
|
2571
|
+
* const virtualEl = {
|
|
2572
|
+
* getBoundingClientRect: () => {
|
|
2573
|
+
* const coords = view.coordsAtPos(pos);
|
|
2574
|
+
* return new DOMRect(coords.left, coords.top, 0, coords.bottom - coords.top);
|
|
2575
|
+
* },
|
|
2576
|
+
* };
|
|
2577
|
+
* const cleanup = positionFloating(virtualEl, tooltipEl, { placement: 'top' });
|
|
2578
|
+
*
|
|
2579
|
+
* // Stop when done
|
|
2580
|
+
* cleanup();
|
|
2581
|
+
* ```
|
|
2582
|
+
*/
|
|
2583
|
+
declare function positionFloating(reference: Element | {
|
|
2584
|
+
getBoundingClientRect: () => DOMRect;
|
|
2585
|
+
}, floating: HTMLElement, options?: PositionFloatingOptions): () => void;
|
|
2586
|
+
/**
|
|
2587
|
+
* Positions a floating element using `strategy: 'absolute'` so it scrolls
|
|
2588
|
+
* together with its offsetParent - zero jitter by design.
|
|
2589
|
+
*
|
|
2590
|
+
* Ideal for dropdowns inside scroll containers (e.g. emoji suggestion inside
|
|
2591
|
+
* `.dm-editor`) and toolbar dropdowns. The absolute coordinates are stable
|
|
2592
|
+
* across scrolls - only `flip`/`shift` decisions change on scroll, producing
|
|
2593
|
+
* a discrete jump rather than continuous jitter.
|
|
2594
|
+
*
|
|
2595
|
+
* The floating element must have `position: absolute` and its offsetParent
|
|
2596
|
+
* must have `position: relative`.
|
|
2597
|
+
*
|
|
2598
|
+
* Returns a cleanup function - call it when hiding or destroying the
|
|
2599
|
+
* floating element.
|
|
2600
|
+
*/
|
|
2601
|
+
declare function positionFloatingOnce(reference: Element | {
|
|
2602
|
+
getBoundingClientRect: () => DOMRect;
|
|
2603
|
+
}, floating: HTMLElement, options?: PositionFloatingOptions): () => void;
|
|
2604
|
+
|
|
2605
|
+
/**
|
|
2606
|
+
* Clipboard helper - writes plain text to the system clipboard.
|
|
2607
|
+
*
|
|
2608
|
+
* Tries the modern async Clipboard API first; if unavailable or denied
|
|
2609
|
+
* (Safari private mode, insecure context, missing user gesture), falls
|
|
2610
|
+
* back to a hidden textarea + `document.execCommand('copy')`.
|
|
2611
|
+
*
|
|
2612
|
+
* Returns `true` on success, `false` on failure. Never throws - callers
|
|
2613
|
+
* decide how to surface failure (toast, re-throw, silent).
|
|
2614
|
+
*
|
|
2615
|
+
* @example
|
|
2616
|
+
* ```ts
|
|
2617
|
+
* const ok = await writeToClipboard('https://example.com#block-abc123');
|
|
2618
|
+
* if (!ok) showError('Copy failed');
|
|
2619
|
+
* ```
|
|
2620
|
+
*/
|
|
2621
|
+
declare function writeToClipboard(text: string): Promise<boolean>;
|
|
2622
|
+
|
|
2623
|
+
/**
|
|
2624
|
+
* Copies `dm-theme-*` classes from the editor's host element onto a
|
|
2625
|
+
* floating element that lives OUTSIDE `.dm-editor` (typically portaled
|
|
2626
|
+
* to `document.body` to escape `overflow: hidden`). Without the copy
|
|
2627
|
+
* the `.dm-theme-dark` cascade does not reach the floating element and
|
|
2628
|
+
* it renders with light-theme defaults on a dark page.
|
|
2629
|
+
*
|
|
2630
|
+
* Call this whenever the floating element is shown - cheap and
|
|
2631
|
+
* idempotent. Removes stale theme classes from the target first so
|
|
2632
|
+
* runtime theme toggles propagate on the next show.
|
|
2633
|
+
*/
|
|
2634
|
+
declare function copyThemeClass(view: {
|
|
2635
|
+
dom: Element;
|
|
2636
|
+
}, target: Element): void;
|
|
2637
|
+
|
|
2638
|
+
/**
|
|
2639
|
+
* Default `contexts` map for a bubble menu when the consumer has not
|
|
2640
|
+
* supplied one. Returns a richer item set when the editor (or any
|
|
2641
|
+
* ancestor) carries the `.dm-notion-mode` class - that class is the
|
|
2642
|
+
* project-wide signal that the host is rendering Notion-style UX, so
|
|
2643
|
+
* the bubble menu mirrors it by including `link` and `textAlign`.
|
|
2644
|
+
*
|
|
2645
|
+
* Consumers can always override by passing their own `contexts` prop.
|
|
2646
|
+
*/
|
|
2647
|
+
declare function defaultBubbleContexts(editor: Editor): Record<string, string[]>;
|
|
2648
|
+
|
|
2649
|
+
interface InsertAsListItemChildArgs {
|
|
2650
|
+
/** Existing transaction to mutate. Caller dispatches. */
|
|
2651
|
+
tr: Transaction;
|
|
2652
|
+
/** Position of the list wrapper node (bulletList / orderedList / taskList) in `tr.doc`. */
|
|
2653
|
+
wrapperPos: number;
|
|
2654
|
+
/**
|
|
2655
|
+
* Position of the target list item node (= position right BEFORE the
|
|
2656
|
+
* item) in `tr.doc`. When omitted, the wrapper's LAST child is used,
|
|
2657
|
+
* matching the Tab keyboard behaviour ("indent into last item").
|
|
2658
|
+
*/
|
|
2659
|
+
targetItemPos?: number;
|
|
2660
|
+
/** Block node to append as the LAST child of the target item. */
|
|
2661
|
+
blockNode: Node$1;
|
|
2662
|
+
/**
|
|
2663
|
+
* Optional source range to delete in the SAME transaction (when
|
|
2664
|
+
* MOVING an existing block instead of creating a new one). Position
|
|
2665
|
+
* math handles source-before-vs-after-target ordering automatically.
|
|
2666
|
+
*/
|
|
2667
|
+
sourceRange?: {
|
|
2668
|
+
from: number;
|
|
2669
|
+
to: number;
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2672
|
+
interface InsertAsListItemChildResult {
|
|
2673
|
+
/** True when schema accepted the insertion and `tr` was mutated. */
|
|
2674
|
+
ok: boolean;
|
|
2675
|
+
/**
|
|
2676
|
+
* Position right BEFORE the inserted block in the resulting doc.
|
|
2677
|
+
* Caller can resolve `insertedAt + 1` to place the caret inside the
|
|
2678
|
+
* inserted block. Only present when `ok === true`.
|
|
2679
|
+
*/
|
|
2680
|
+
insertedAt?: number;
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* Insert `blockNode` as the LAST child of a list item (target item or, when
|
|
2684
|
+
* omitted, the wrapper's last item). When `sourceRange` is set, the source
|
|
2685
|
+
* range is removed in the same transaction so the op is a clean MOVE.
|
|
2686
|
+
* Returns `{ ok: false }` WITHOUT mutating `tr` on schema reject so callers
|
|
2687
|
+
* can fall through to a sibling-mode fallback.
|
|
2688
|
+
*/
|
|
2689
|
+
declare function insertAsListItemChild(args: InsertAsListItemChildArgs): InsertAsListItemChildResult;
|
|
2690
|
+
|
|
2691
|
+
/**
|
|
2692
|
+
* Cursor context relative to the INNERMOST containing list/task item,
|
|
2693
|
+
* resolved only when the cursor's parent paragraph is a DIRECT child of
|
|
2694
|
+
* that item. Innermost so nested lists hand control to the deepest item;
|
|
2695
|
+
* direct-child so paragraphs inside blockquote/table-cell/etc. inside a
|
|
2696
|
+
* list item fall through to the container's own Enter/Backspace.
|
|
2697
|
+
*/
|
|
2698
|
+
interface ListItemCursorContext {
|
|
2699
|
+
/** Depth of the containing list item ancestor in the resolved pos. */
|
|
2700
|
+
itemDepth: number;
|
|
2701
|
+
/** Position right BEFORE the containing list item in the doc. */
|
|
2702
|
+
itemPos: number;
|
|
2703
|
+
/** Position right BEFORE the containing list wrapper (one depth above the item). */
|
|
2704
|
+
wrapperPos: number;
|
|
2705
|
+
/** `true` when the parent paragraph is not the first child of the list item. */
|
|
2706
|
+
isInChildrenZone: boolean;
|
|
2707
|
+
/** `true` when the parent paragraph has no inline content. */
|
|
2708
|
+
paragraphIsEmpty: boolean;
|
|
2709
|
+
/** `true` when the parent paragraph is the LAST child of the list item. */
|
|
2710
|
+
isLastChild: boolean;
|
|
2711
|
+
/** Index of the parent paragraph within the list item (0 = label). */
|
|
2712
|
+
childIndex: number;
|
|
2713
|
+
/** Index of the containing list item within its wrapper. */
|
|
2714
|
+
itemIndexInWrapper: number;
|
|
2715
|
+
}
|
|
2716
|
+
/**
|
|
2717
|
+
* Resolve list-item cursor context. Returns `null` when the cursor's
|
|
2718
|
+
* shape does not match `(wrapper > item > paragraph)`; callers should
|
|
2719
|
+
* fall through to default Enter/Backspace in that case.
|
|
2720
|
+
*/
|
|
2721
|
+
declare function getListItemCursorContext($from: ResolvedPos): ListItemCursorContext | null;
|
|
2722
|
+
|
|
2723
|
+
/**
|
|
2724
|
+
* Lift an empty children-zone paragraph out of its list/task item as a
|
|
2725
|
+
* top-level sibling. PM's `liftTarget` covers the common case; we fall
|
|
2726
|
+
* back to manual delete-and-insert when it returns null (empty p sandwiched
|
|
2727
|
+
* before a non-paragraph would leave the after-cut half violating the
|
|
2728
|
+
* `paragraph block*` schema).
|
|
2729
|
+
*/
|
|
2730
|
+
declare function liftEmptyChildrenZoneParagraph(state: EditorState, dispatch: ((tr: Transaction) => void) | undefined, ctx: ListItemCursorContext): boolean;
|
|
2731
|
+
|
|
2732
|
+
/**
|
|
2733
|
+
* Insert an empty paragraph as next sibling inside the same list/task item,
|
|
2734
|
+
* keeping the cursor in the children-zone so Enter accumulates blocks at the
|
|
2735
|
+
* same nesting level (Notion semantics). Exit paths are Backspace on empty,
|
|
2736
|
+
* Shift+Tab, or Enter on the empty label paragraph.
|
|
2737
|
+
*/
|
|
2738
|
+
declare function insertChildrenZoneSibling(state: EditorState, dispatch: ((tr: Transaction) => void) | undefined, ctx: ListItemCursorContext): boolean;
|
|
2739
|
+
|
|
2740
|
+
/**
|
|
2741
|
+
* Activation conditions (single-cursor only):
|
|
2742
|
+
* - selection is empty (single caret)
|
|
2743
|
+
* - cursor's nearest list-item ancestor exists
|
|
2744
|
+
* - cursor's containing block is at index 0 (label slot) of that item
|
|
2745
|
+
* - `tr` has no prior steps (lift steps captured from a fresh state must
|
|
2746
|
+
* replay against the same starting state as `tr`)
|
|
2747
|
+
*
|
|
2748
|
+
* Returns true if the lift was applied to `tr`. The caller can keep
|
|
2749
|
+
* chaining work on `tr` (e.g. `setBlockType`, `wrapIn`) on the new
|
|
2750
|
+
* top-level paragraph.
|
|
2751
|
+
*/
|
|
2752
|
+
declare function liftCurrentListItem(state: EditorState, tr: Transaction): boolean;
|
|
2753
|
+
|
|
2754
|
+
interface SplitListForInsertRange {
|
|
2755
|
+
from: number;
|
|
2756
|
+
to: number;
|
|
2757
|
+
}
|
|
2758
|
+
/**
|
|
2759
|
+
* Activation conditions (single-cursor only):
|
|
2760
|
+
* - selection is empty
|
|
2761
|
+
* - cursor's nearest list-item ancestor exists
|
|
2762
|
+
* - cursor's containing block is at index 0 (label slot) of that item
|
|
2763
|
+
* - `tr` has no prior steps
|
|
2462
2764
|
*
|
|
2463
|
-
*
|
|
2464
|
-
*
|
|
2465
|
-
*
|
|
2765
|
+
* @returns A range where the caller should call `tr.replaceWith(from, to,
|
|
2766
|
+
* [block, optionalTrailingParagraph])`, or `null` if the cursor isn't
|
|
2767
|
+
* in a list-item label.
|
|
2466
2768
|
*/
|
|
2467
|
-
declare function
|
|
2468
|
-
|
|
2469
|
-
}, floating: HTMLElement, options?: PositionFloatingOptions): () => void;
|
|
2769
|
+
declare function splitListForInsert(state: EditorState, tr: Transaction): SplitListForInsertRange | null;
|
|
2770
|
+
|
|
2470
2771
|
/**
|
|
2471
|
-
*
|
|
2472
|
-
*
|
|
2473
|
-
*
|
|
2474
|
-
*
|
|
2475
|
-
*
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
*
|
|
2772
|
+
* Shared helpers for locating a list/task item ancestor of a resolved
|
|
2773
|
+
* position. Centralises the `LIST_ITEM_TYPE_NAMES` constant + ancestor
|
|
2774
|
+
* walk so the four+ consumers (liftCurrentListItem, splitListForInsert,
|
|
2775
|
+
* TaskItem keymap, Details proactive lift, slash menu filtering) stay
|
|
2776
|
+
* in sync.
|
|
2777
|
+
*/
|
|
2778
|
+
|
|
2779
|
+
declare const LIST_ITEM_TYPE_NAMES: Set<string>;
|
|
2780
|
+
/**
|
|
2781
|
+
* Returns the depth at which the nearest list/task item ancestor sits,
|
|
2782
|
+
* or -1 if none.
|
|
2481
2783
|
*
|
|
2482
|
-
*
|
|
2483
|
-
* floating element.
|
|
2784
|
+
* Walks UP from `$pos.depth` toward 1 (we skip depth 0 = doc itself).
|
|
2484
2785
|
*/
|
|
2485
|
-
declare function
|
|
2486
|
-
|
|
2487
|
-
|
|
2786
|
+
declare function findListItemAncestorDepth($pos: ResolvedPos): number;
|
|
2787
|
+
/** Convenience: true when the cursor has a list/task item ancestor. */
|
|
2788
|
+
declare function isInsideListItem($pos: ResolvedPos): boolean;
|
|
2789
|
+
/**
|
|
2790
|
+
* True when the cursor sits in the LABEL paragraph (index 0) of its
|
|
2791
|
+
* nearest list/task item ancestor. Used to gate Notion-style "operate
|
|
2792
|
+
* on the label" commands (slash menu CONVERT, INSERT, etc.).
|
|
2793
|
+
*/
|
|
2794
|
+
declare function isInListItemLabel($pos: ResolvedPos): boolean;
|
|
2488
2795
|
|
|
2489
2796
|
/**
|
|
2490
2797
|
* Create a ProseMirror document from content
|
|
@@ -3160,7 +3467,7 @@ declare class Extension<Options = unknown, Storage = unknown> {
|
|
|
3160
3467
|
* // Shallow merge behavior with nested objects:
|
|
3161
3468
|
* // Given: options = { nested: { a: 1, b: 2 } }
|
|
3162
3469
|
* // configure({ nested: { b: 3 } })
|
|
3163
|
-
* // Result: { nested: { b: 3 } }
|
|
3470
|
+
* // Result: { nested: { b: 3 } } - 'a' is lost!
|
|
3164
3471
|
* // To preserve nested values, spread manually:
|
|
3165
3472
|
* // configure({ nested: { ...original.options.nested, b: 3 } })
|
|
3166
3473
|
*/
|
|
@@ -3289,25 +3596,12 @@ declare class Node<Options = unknown, Storage = unknown> extends Extension<Optio
|
|
|
3289
3596
|
*/
|
|
3290
3597
|
static create<O = unknown, S = unknown>(config: NodeConfig<O, S>): Node<O, S>;
|
|
3291
3598
|
/**
|
|
3292
|
-
* Creates a new node with merged options
|
|
3293
|
-
*
|
|
3294
|
-
*
|
|
3295
|
-
* **Note:** Options are merged shallowly using object spread (`...`).
|
|
3296
|
-
* Nested objects are replaced entirely, not deeply merged.
|
|
3297
|
-
*
|
|
3298
|
-
* @param options - Options to merge with existing options
|
|
3299
|
-
* @returns New node instance with merged options
|
|
3599
|
+
* Creates a new node with merged options. Original node is not modified.
|
|
3600
|
+
* Options merge shallowly (object spread); see {@link Extension.configure}
|
|
3601
|
+
* for the nested-object gotcha and a workaround.
|
|
3300
3602
|
*
|
|
3301
3603
|
* @example
|
|
3302
3604
|
* const CustomParagraph = Paragraph.configure({ HTMLAttributes: { class: 'custom' } });
|
|
3303
|
-
*
|
|
3304
|
-
* @example
|
|
3305
|
-
* // Shallow merge behavior with nested objects:
|
|
3306
|
-
* // Given: options = { HTMLAttributes: { class: 'a', id: 'b' } }
|
|
3307
|
-
* // configure({ HTMLAttributes: { class: 'c' } })
|
|
3308
|
-
* // Result: { HTMLAttributes: { class: 'c' } } — 'id' is lost!
|
|
3309
|
-
* // To preserve nested values, spread manually:
|
|
3310
|
-
* // configure({ HTMLAttributes: { ...original.options.HTMLAttributes, class: 'c' } })
|
|
3311
3605
|
*/
|
|
3312
3606
|
configure(options: Partial<Options>): Node<Options, Storage>;
|
|
3313
3607
|
/**
|
|
@@ -3351,7 +3645,7 @@ declare class Node<Options = unknown, Storage = unknown> extends Extension<Optio
|
|
|
3351
3645
|
}
|
|
3352
3646
|
|
|
3353
3647
|
/**
|
|
3354
|
-
* ToolbarController
|
|
3648
|
+
* ToolbarController - Headless, framework-agnostic toolbar state machine
|
|
3355
3649
|
*
|
|
3356
3650
|
* Manages toolbar item collection, grouping, active state tracking,
|
|
3357
3651
|
* dropdown state, and keyboard navigation. Framework wrappers (Angular,
|
|
@@ -3359,7 +3653,7 @@ declare class Node<Options = unknown, Storage = unknown> extends Extension<Optio
|
|
|
3359
3653
|
*
|
|
3360
3654
|
* @example
|
|
3361
3655
|
* const controller = new ToolbarController(editor, () => {
|
|
3362
|
-
* // Called on every state change
|
|
3656
|
+
* // Called on every state change - trigger framework re-render
|
|
3363
3657
|
* });
|
|
3364
3658
|
* controller.subscribe();
|
|
3365
3659
|
* // ... use controller.groups, controller.activeMap, etc.
|
|
@@ -3419,7 +3713,7 @@ declare class ToolbarController {
|
|
|
3419
3713
|
private _activeMap;
|
|
3420
3714
|
/** Disabled state for each button (keyed by item.name) */
|
|
3421
3715
|
private _disabledMap;
|
|
3422
|
-
/** Expanded state for emitEvent buttons
|
|
3716
|
+
/** Expanded state for emitEvent buttons - true when their panel is open */
|
|
3423
3717
|
private _expandedMap;
|
|
3424
3718
|
/** Currently open dropdown name (null = none) */
|
|
3425
3719
|
private _openDropdown;
|
|
@@ -3518,6 +3812,124 @@ declare class ToolbarController {
|
|
|
3518
3812
|
private checkButtonExpanded;
|
|
3519
3813
|
}
|
|
3520
3814
|
|
|
3815
|
+
/**
|
|
3816
|
+
* A group of floating-menu items sharing the same `group` value.
|
|
3817
|
+
*/
|
|
3818
|
+
interface FloatingMenuGroup {
|
|
3819
|
+
name: string;
|
|
3820
|
+
items: FloatingMenuItem[];
|
|
3821
|
+
}
|
|
3822
|
+
/**
|
|
3823
|
+
* Groups items by their `group` property, preserving extension insertion
|
|
3824
|
+
* order of groups. Within each group, items are sorted by `priority`
|
|
3825
|
+
* descending (higher first, default 100).
|
|
3826
|
+
*
|
|
3827
|
+
* Shared between `FloatingMenuController` (which renders grouped item lists
|
|
3828
|
+
* for FloatingMenu + framework wrappers) and `createSlashSuggestionRenderer`
|
|
3829
|
+
* (the popup shown by SlashCommand). Having one implementation keeps visual
|
|
3830
|
+
* grouping consistent across every trigger mechanism.
|
|
3831
|
+
*/
|
|
3832
|
+
declare function groupFloatingMenuItems(items: FloatingMenuItem[]): FloatingMenuGroup[];
|
|
3833
|
+
|
|
3834
|
+
/**
|
|
3835
|
+
* FloatingMenuController - Headless, framework-agnostic state machine for the
|
|
3836
|
+
* block-insert floating menu.
|
|
3837
|
+
*
|
|
3838
|
+
* Mirrors the shape of ToolbarController: collects items from extensions,
|
|
3839
|
+
* groups them, tracks focused index for roving-tabindex keyboard navigation,
|
|
3840
|
+
* and executes commands. Framework wrappers (Angular, React, Vue) bind their
|
|
3841
|
+
* templates to this controller.
|
|
3842
|
+
*
|
|
3843
|
+
* @example
|
|
3844
|
+
* const controller = new FloatingMenuController(editor, () => {
|
|
3845
|
+
* // onChange - re-render
|
|
3846
|
+
* });
|
|
3847
|
+
* controller.subscribe();
|
|
3848
|
+
* // ... controller.groups, controller.focusedIndex, controller.execute(item)
|
|
3849
|
+
* controller.destroy();
|
|
3850
|
+
*/
|
|
3851
|
+
|
|
3852
|
+
/** -1 means no item is focused (menu not entered via keyboard). */
|
|
3853
|
+
declare const FLOATING_MENU_NO_FOCUS = -1;
|
|
3854
|
+
declare class FloatingMenuController {
|
|
3855
|
+
/**
|
|
3856
|
+
* Resolves an `items` option (array | function) against the editor's
|
|
3857
|
+
* default floating-menu items. Exposed as static so the plugin can
|
|
3858
|
+
* resolve once at init without constructing a controller.
|
|
3859
|
+
*/
|
|
3860
|
+
static resolveItems(editor: Editor, override?: FloatingMenuItemsOverride): FloatingMenuItem[];
|
|
3861
|
+
/**
|
|
3862
|
+
* Executes a floating-menu item's command on the editor.
|
|
3863
|
+
* String commands are dispatched via `editor.commands[name](...args)`;
|
|
3864
|
+
* function commands are called directly.
|
|
3865
|
+
*/
|
|
3866
|
+
static executeItem(editor: Editor, item: FloatingMenuItem): void;
|
|
3867
|
+
private editor;
|
|
3868
|
+
private onChange;
|
|
3869
|
+
private override;
|
|
3870
|
+
private transactionHandler;
|
|
3871
|
+
private _groups;
|
|
3872
|
+
private _flatItems;
|
|
3873
|
+
private _disabledMap;
|
|
3874
|
+
private _focusedIndex;
|
|
3875
|
+
constructor(editor: Editor, onChange: () => void, override?: FloatingMenuItemsOverride);
|
|
3876
|
+
get groups(): FloatingMenuGroup[];
|
|
3877
|
+
get flatItems(): FloatingMenuItem[];
|
|
3878
|
+
get disabledMap(): ReadonlyMap<string, boolean>;
|
|
3879
|
+
get focusedIndex(): number;
|
|
3880
|
+
/** True when keyboard focus is inside the menu (at least one item focused). */
|
|
3881
|
+
get isEntered(): boolean;
|
|
3882
|
+
get itemCount(): number;
|
|
3883
|
+
isDisabled(item: FloatingMenuItem): boolean;
|
|
3884
|
+
/**
|
|
3885
|
+
* Executes an item's command, then closes the menu keyboard focus.
|
|
3886
|
+
* Callers should refocus the editor after calling this.
|
|
3887
|
+
*/
|
|
3888
|
+
execute(item: FloatingMenuItem): void;
|
|
3889
|
+
/**
|
|
3890
|
+
* Rebuilds items from the editor. Call when the editor's extensions
|
|
3891
|
+
* change (rare) or on explicit refresh. Notification is delegated to
|
|
3892
|
+
* `updateDisabledStates` which fires `onChange` only when a disabled
|
|
3893
|
+
* state flipped - wrappers that need to react to pure group-structure
|
|
3894
|
+
* changes do so by bumping their own render signal after constructing
|
|
3895
|
+
* / re-using the controller (see framework wrapper usage).
|
|
3896
|
+
*/
|
|
3897
|
+
rebuild(): void;
|
|
3898
|
+
/** Enter keyboard focus on the menu (first item). Called by the plugin's keymap. */
|
|
3899
|
+
enterMenu(): number;
|
|
3900
|
+
/** Leave keyboard focus (Escape). Refocus of the editor is the caller's job. */
|
|
3901
|
+
leaveMenu(): void;
|
|
3902
|
+
/** ArrowDown - wrap to first at end. */
|
|
3903
|
+
next(): number;
|
|
3904
|
+
/** ArrowUp - wrap to last at start. */
|
|
3905
|
+
prev(): number;
|
|
3906
|
+
first(): number;
|
|
3907
|
+
last(): number;
|
|
3908
|
+
/** Set focused index directly (e.g. on pointer hover). */
|
|
3909
|
+
setFocusedIndex(index: number): void;
|
|
3910
|
+
/** Get focused item (or null). */
|
|
3911
|
+
focusedItem(): FloatingMenuItem | null;
|
|
3912
|
+
/** Get flat index of item by name (for wrappers binding roving tabindex). */
|
|
3913
|
+
getFlatIndex(name: string): number;
|
|
3914
|
+
/** Subscribes to editor transactions for disabled-state tracking. */
|
|
3915
|
+
subscribe(): void;
|
|
3916
|
+
/** Unsubscribes and clears internal state. */
|
|
3917
|
+
destroy(): void;
|
|
3918
|
+
/**
|
|
3919
|
+
* Groups items by `group` preserving insertion order, then sorts by
|
|
3920
|
+
* priority (higher first) within each group. Delegates to the shared
|
|
3921
|
+
* utility so `SlashCommand`'s renderer and this controller always
|
|
3922
|
+
* produce identical ordering.
|
|
3923
|
+
*/
|
|
3924
|
+
private groupItems;
|
|
3925
|
+
/**
|
|
3926
|
+
* Updates disabled state for each item. Uses custom predicate when
|
|
3927
|
+
* provided; otherwise tries a dry-run against `editor.can()[command]`.
|
|
3928
|
+
* Only notifies on change to avoid noisy re-renders.
|
|
3929
|
+
*/
|
|
3930
|
+
private updateDisabledStates;
|
|
3931
|
+
}
|
|
3932
|
+
|
|
3521
3933
|
declare const defaultIcons: IconSet;
|
|
3522
3934
|
|
|
3523
3935
|
/**
|
|
@@ -3619,25 +4031,12 @@ declare class Mark<Options = unknown, Storage = unknown> extends Extension<Optio
|
|
|
3619
4031
|
*/
|
|
3620
4032
|
static create<O = unknown, S = unknown>(config: MarkConfig<O, S>): Mark<O, S>;
|
|
3621
4033
|
/**
|
|
3622
|
-
* Creates a new mark with merged options
|
|
3623
|
-
*
|
|
3624
|
-
*
|
|
3625
|
-
* **Note:** Options are merged shallowly using object spread (`...`).
|
|
3626
|
-
* Nested objects are replaced entirely, not deeply merged.
|
|
3627
|
-
*
|
|
3628
|
-
* @param options - Options to merge with existing options
|
|
3629
|
-
* @returns New mark instance with merged options
|
|
4034
|
+
* Creates a new mark with merged options. Original mark is not modified.
|
|
4035
|
+
* Options merge shallowly (object spread); see {@link Extension.configure}
|
|
4036
|
+
* for the nested-object gotcha and a workaround.
|
|
3630
4037
|
*
|
|
3631
4038
|
* @example
|
|
3632
4039
|
* const CustomBold = Bold.configure({ HTMLAttributes: { class: 'custom-bold' } });
|
|
3633
|
-
*
|
|
3634
|
-
* @example
|
|
3635
|
-
* // Shallow merge behavior with nested objects:
|
|
3636
|
-
* // Given: options = { HTMLAttributes: { class: 'a', id: 'b' } }
|
|
3637
|
-
* // configure({ HTMLAttributes: { class: 'c' } })
|
|
3638
|
-
* // Result: { HTMLAttributes: { class: 'c' } } — 'id' is lost!
|
|
3639
|
-
* // To preserve nested values, spread manually:
|
|
3640
|
-
* // configure({ HTMLAttributes: { ...original.options.HTMLAttributes, class: 'c' } })
|
|
3641
4040
|
*/
|
|
3642
4041
|
configure(options: Partial<Options> & {
|
|
3643
4042
|
isFormatting?: boolean;
|
|
@@ -4086,14 +4485,19 @@ interface OrderedListOptions {
|
|
|
4086
4485
|
declare const OrderedList: Node<OrderedListOptions, unknown>;
|
|
4087
4486
|
|
|
4088
4487
|
/**
|
|
4089
|
-
*
|
|
4488
|
+
* Enter / Backspace state machine for listItem (cursor's parent must be a paragraph):
|
|
4090
4489
|
*
|
|
4091
|
-
*
|
|
4092
|
-
*
|
|
4490
|
+
* LABEL paragraph (childIndex 0):
|
|
4491
|
+
* Enter, empty -> liftListItem (exit empty bullet)
|
|
4492
|
+
* Enter, non-empty -> splitListItem (new sibling listItem)
|
|
4493
|
+
* Backspace, empty -> falls through to ListKeymap (liftListItem)
|
|
4093
4494
|
*
|
|
4094
|
-
*
|
|
4095
|
-
*
|
|
4096
|
-
* -
|
|
4495
|
+
* CHILDREN-ZONE paragraph (childIndex > 0):
|
|
4496
|
+
* Enter, empty -> insertChildrenZoneSibling (accumulate inside the item)
|
|
4497
|
+
* Enter, non-empty -> splitBlock (both halves stay inside the same item)
|
|
4498
|
+
* Backspace, empty -> liftEmptyChildrenZoneParagraph (exit as top-level)
|
|
4499
|
+
*
|
|
4500
|
+
* Tab / Shift-Tab handled by the ListKeymap extension.
|
|
4097
4501
|
*/
|
|
4098
4502
|
|
|
4099
4503
|
interface ListItemOptions {
|
|
@@ -4155,17 +4559,21 @@ interface TaskListOptions {
|
|
|
4155
4559
|
declare const TaskList: Node<TaskListOptions, unknown>;
|
|
4156
4560
|
|
|
4157
4561
|
/**
|
|
4158
|
-
*
|
|
4562
|
+
* Enter / Backspace state machine for taskItem (cursor's parent must be a paragraph):
|
|
4159
4563
|
*
|
|
4160
|
-
*
|
|
4161
|
-
*
|
|
4564
|
+
* LABEL paragraph (childIndex 0):
|
|
4565
|
+
* Enter, empty -> splitListItem fall-through, then taskItem-in-listItem
|
|
4566
|
+
* promotion (nested orderedList > listItem > taskList > taskItem
|
|
4567
|
+
* context), else liftListItem.
|
|
4568
|
+
* Enter, non-empty -> splitListItem (new sibling taskItem)
|
|
4569
|
+
* Backspace, empty -> liftListItem (exit empty checkbox)
|
|
4162
4570
|
*
|
|
4163
|
-
*
|
|
4164
|
-
*
|
|
4165
|
-
* -
|
|
4166
|
-
*
|
|
4167
|
-
*
|
|
4168
|
-
* - Mod-Enter
|
|
4571
|
+
* CHILDREN-ZONE paragraph (childIndex > 0):
|
|
4572
|
+
* Enter, empty -> insertChildrenZoneSibling (accumulate inside the item)
|
|
4573
|
+
* Enter, non-empty -> splitBlock (both halves stay inside the same item)
|
|
4574
|
+
* Backspace, empty -> liftEmptyChildrenZoneParagraph (exit as top-level)
|
|
4575
|
+
*
|
|
4576
|
+
* Tab / Shift-Tab sink / lift the item; Mod-Enter toggles checked state.
|
|
4169
4577
|
*/
|
|
4170
4578
|
|
|
4171
4579
|
declare module '@domternal/core' {
|
|
@@ -4376,9 +4784,6 @@ declare module '@domternal/core' {
|
|
|
4376
4784
|
}
|
|
4377
4785
|
}
|
|
4378
4786
|
|
|
4379
|
-
/**
|
|
4380
|
-
* Options for the Link mark
|
|
4381
|
-
*/
|
|
4382
4787
|
interface LinkOptions {
|
|
4383
4788
|
/**
|
|
4384
4789
|
* HTML attributes to add to the rendered element
|
|
@@ -4882,6 +5287,61 @@ interface ListKeymapOptions {
|
|
|
4882
5287
|
}
|
|
4883
5288
|
declare const ListKeymap: Extension<ListKeymapOptions, unknown>;
|
|
4884
5289
|
|
|
5290
|
+
/**
|
|
5291
|
+
* Keyboard indent across list boundaries. `Tab` on a top-level block whose
|
|
5292
|
+
* previous sibling is a list moves the block INTO the last item as a nested
|
|
5293
|
+
* child; `Shift-Tab` reverses for a block sitting as the last child of the
|
|
5294
|
+
* last item.
|
|
5295
|
+
*
|
|
5296
|
+
* Trigger is intentionally narrow so ListKeymap retains in-list Tab/Shift-Tab
|
|
5297
|
+
* (`sinkListItem` / `liftListItem`). Schema is validated via `canReplaceWith`;
|
|
5298
|
+
* invalid placements are a clean no-op so the keymap chain falls through.
|
|
5299
|
+
*
|
|
5300
|
+
* Intentional design restrictions (NOT bugs to "fix"):
|
|
5301
|
+
* - Tab indents into the IMMEDIATE last item only, not recursively into a
|
|
5302
|
+
* deeper "deepest last item". Users get deeper nesting via repeated Tab
|
|
5303
|
+
* inside the now-nested context (then ListKeymap takes over).
|
|
5304
|
+
* - Tab only fires for cursors in TOP-LEVEL blocks (depth === 1). Cursors
|
|
5305
|
+
* inside other containers (blockquote, table cell) fall through.
|
|
5306
|
+
* - Shift-Tab only fires when the block is BOTH the last child of its
|
|
5307
|
+
* item AND the item is the last in its wrapper. Mid-position outdent
|
|
5308
|
+
* would require splitting the list item, which is deferred.
|
|
5309
|
+
*
|
|
5310
|
+
* Registration order: must come AFTER ListKeymap so this extension's keymap
|
|
5311
|
+
* runs FIRST and can defer to ListKeymap for in-list flows.
|
|
5312
|
+
*/
|
|
5313
|
+
|
|
5314
|
+
/**
|
|
5315
|
+
* `Tab` handler: indent a top-level block as the last child of the
|
|
5316
|
+
* last item of the immediately-preceding list wrapper. Returns true
|
|
5317
|
+
* when the operation succeeded (and dispatched, if `dispatch` is
|
|
5318
|
+
* provided), false when any precondition fails so the keymap chain
|
|
5319
|
+
* can fall through to the next handler.
|
|
5320
|
+
*/
|
|
5321
|
+
declare function indentBlockAsListChild(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;
|
|
5322
|
+
/**
|
|
5323
|
+
* `Shift-Tab` handler: lift a non-label nested block out of its list
|
|
5324
|
+
* item to become a top-level sibling AFTER the list wrapper. Only
|
|
5325
|
+
* fires for the strict end-of-end case (last child of last item) so
|
|
5326
|
+
* the lift is deterministic and never needs to split a list item.
|
|
5327
|
+
*
|
|
5328
|
+
* Precondition table:
|
|
5329
|
+
* - cursor empty
|
|
5330
|
+
* - cursor textblock parent is NOT a paragraph (so we never
|
|
5331
|
+
* accidentally outdent the label; ListKeymap.Shift-Tab handles
|
|
5332
|
+
* in-label cases via liftListItem)
|
|
5333
|
+
* - the cursor's enclosing list item exists in the ancestry
|
|
5334
|
+
* - the cursor's containing block is a DIRECT child of the list
|
|
5335
|
+
* item (depth = listItemDepth + 1) - keeps the math local to
|
|
5336
|
+
* immediate li children rather than reaching deeper into nested
|
|
5337
|
+
* containers
|
|
5338
|
+
* - the block is the LAST child of the list item
|
|
5339
|
+
* - the list item is the LAST child of its wrapper
|
|
5340
|
+
* - the wrapper's parent accepts the block as a sibling (schema)
|
|
5341
|
+
*/
|
|
5342
|
+
declare function outdentBlockFromListItem(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;
|
|
5343
|
+
declare const ListIndent: Extension<unknown, unknown>;
|
|
5344
|
+
|
|
4885
5345
|
/**
|
|
4886
5346
|
* CharacterCount Extension
|
|
4887
5347
|
*
|
|
@@ -5113,25 +5573,8 @@ interface LineHeightOptions {
|
|
|
5113
5573
|
declare const LineHeight: Extension<LineHeightOptions, unknown>;
|
|
5114
5574
|
|
|
5115
5575
|
/**
|
|
5116
|
-
*
|
|
5117
|
-
*
|
|
5118
|
-
* Automatically assigns unique IDs to specified node types.
|
|
5119
|
-
* Useful for collaborative editing, linking, and history tracking.
|
|
5120
|
-
*
|
|
5121
|
-
* @example
|
|
5122
|
-
* ```ts
|
|
5123
|
-
* import { UniqueID } from '@domternal/core';
|
|
5124
|
-
*
|
|
5125
|
-
* const editor = new Editor({
|
|
5126
|
-
* extensions: [
|
|
5127
|
-
* // ... other extensions
|
|
5128
|
-
* UniqueID.configure({
|
|
5129
|
-
* types: ['paragraph', 'heading'],
|
|
5130
|
-
* attributeName: 'id',
|
|
5131
|
-
* }),
|
|
5132
|
-
* ],
|
|
5133
|
-
* });
|
|
5134
|
-
* ```
|
|
5576
|
+
* Canonical block-id system. Assigns ids to configured node types and is
|
|
5577
|
+
* read by TableOfContents and BlockContextMenu.
|
|
5135
5578
|
*/
|
|
5136
5579
|
|
|
5137
5580
|
declare const uniqueIDPluginKey: PluginKey<any>;
|
|
@@ -5159,6 +5602,70 @@ interface UniqueIDOptions {
|
|
|
5159
5602
|
}
|
|
5160
5603
|
declare const UniqueID: Extension<UniqueIDOptions, unknown>;
|
|
5161
5604
|
|
|
5605
|
+
/**
|
|
5606
|
+
* Tints whole blocks via `bgColor` / `textColor` attributes rendered as
|
|
5607
|
+
* `data-bg-color` / `data-text-color`. Theme's `_block-colors.scss` maps
|
|
5608
|
+
* names to CSS custom properties with light/dark variants. `null` clears
|
|
5609
|
+
* the attribute; unknown palette names are rejected by commands.
|
|
5610
|
+
*/
|
|
5611
|
+
|
|
5612
|
+
declare module '@domternal/core' {
|
|
5613
|
+
interface RawCommands {
|
|
5614
|
+
setBlockBgColor: CommandSpec<[color: string | null]>;
|
|
5615
|
+
setBlockTextColor: CommandSpec<[color: string | null]>;
|
|
5616
|
+
unsetBlockColors: CommandSpec;
|
|
5617
|
+
}
|
|
5618
|
+
}
|
|
5619
|
+
/**
|
|
5620
|
+
* Notion's public palette. Names are semantic (not tied to specific hex);
|
|
5621
|
+
* the stylesheet owns the actual colors so themes can customize them.
|
|
5622
|
+
* `'default'` is implicit - represented by `null` (no data attribute).
|
|
5623
|
+
*/
|
|
5624
|
+
declare const DEFAULT_BLOCK_COLORS: string[];
|
|
5625
|
+
/**
|
|
5626
|
+
* Default set of block types that receive the color attributes. `codeBlock`
|
|
5627
|
+
* is intentionally excluded - `<pre><code>` already has its own background
|
|
5628
|
+
* that would conflict visually. Similarly, details-content blocks have
|
|
5629
|
+
* their own affordance. Callers can extend via `types` option.
|
|
5630
|
+
*/
|
|
5631
|
+
declare const DEFAULT_BLOCK_COLOR_TYPES: string[];
|
|
5632
|
+
interface BlockColorOptions {
|
|
5633
|
+
/**
|
|
5634
|
+
* Node types that receive `bgColor` / `textColor` attributes.
|
|
5635
|
+
* @default DEFAULT_BLOCK_COLOR_TYPES
|
|
5636
|
+
*/
|
|
5637
|
+
types: string[];
|
|
5638
|
+
/**
|
|
5639
|
+
* Palette used by the `setBlockBgColor` command. Commands reject values
|
|
5640
|
+
* outside this list (no-op + false return) so host apps can curate
|
|
5641
|
+
* what's selectable.
|
|
5642
|
+
* @default DEFAULT_BLOCK_COLORS
|
|
5643
|
+
*/
|
|
5644
|
+
bgColors: string[];
|
|
5645
|
+
/**
|
|
5646
|
+
* Palette used by the `setBlockTextColor` command.
|
|
5647
|
+
* @default DEFAULT_BLOCK_COLORS
|
|
5648
|
+
*/
|
|
5649
|
+
textColors: string[];
|
|
5650
|
+
}
|
|
5651
|
+
/**
|
|
5652
|
+
* Strip any inline `textStyle` marks inside [from, to] that carry the inline
|
|
5653
|
+
* counterpart of a block-level color attribute. Mutates the transaction in
|
|
5654
|
+
* place. This makes "last action wins": applying a block color erases
|
|
5655
|
+
* conflicting inline colors so the new block tint isn't visually hidden by
|
|
5656
|
+
* old span overrides.
|
|
5657
|
+
*
|
|
5658
|
+
* `which` may be 'text', 'bg', or 'both' - 'both' handles the unset case
|
|
5659
|
+
* in a single pass so the two strip operations don't step on each other's
|
|
5660
|
+
* replaced mark instances.
|
|
5661
|
+
*
|
|
5662
|
+
* Exported so `BlockContextMenu` (which writes node attrs directly via
|
|
5663
|
+
* `setNodeMarkup` instead of going through `setBlockBgColor` /
|
|
5664
|
+
* `setBlockTextColor`) shares the same conflict-stripping behavior.
|
|
5665
|
+
*/
|
|
5666
|
+
declare function stripInlineColorConflicts(tr: Transaction, state: EditorState, from: number, to: number, which: 'text' | 'bg' | 'both'): void;
|
|
5667
|
+
declare const BlockColor: Extension<BlockColorOptions, unknown>;
|
|
5668
|
+
|
|
5162
5669
|
/**
|
|
5163
5670
|
* Selection Extension
|
|
5164
5671
|
*
|
|
@@ -5237,7 +5744,7 @@ declare const Selection: Extension<SelectionOptions, SelectionStorage>;
|
|
|
5237
5744
|
* clicks outside the editor (approach A - same as Google Docs / Notion).
|
|
5238
5745
|
*
|
|
5239
5746
|
* Toolbar and bubble-menu buttons call `event.preventDefault()` on
|
|
5240
|
-
* `mousedown`, so they never trigger blur
|
|
5747
|
+
* `mousedown`, so they never trigger blur - the selection stays intact
|
|
5241
5748
|
* while the user interacts with editor UI.
|
|
5242
5749
|
*/
|
|
5243
5750
|
|
|
@@ -5358,6 +5865,8 @@ declare module '@domternal/core' {
|
|
|
5358
5865
|
interface RawCommands {
|
|
5359
5866
|
setTextColor: CommandSpec<[color: string]>;
|
|
5360
5867
|
unsetTextColor: CommandSpec;
|
|
5868
|
+
setTextColorToken: CommandSpec<[token: string | null]>;
|
|
5869
|
+
unsetTextColorToken: CommandSpec;
|
|
5361
5870
|
}
|
|
5362
5871
|
}
|
|
5363
5872
|
/**
|
|
@@ -5419,6 +5928,8 @@ declare module '@domternal/core' {
|
|
|
5419
5928
|
toggleHighlight: CommandSpec<[attributes?: {
|
|
5420
5929
|
color?: string;
|
|
5421
5930
|
}]>;
|
|
5931
|
+
setBackgroundColorToken: CommandSpec<[token: string | null]>;
|
|
5932
|
+
unsetBackgroundColorToken: CommandSpec;
|
|
5422
5933
|
}
|
|
5423
5934
|
}
|
|
5424
5935
|
/**
|
|
@@ -5534,6 +6045,59 @@ interface FontSizeOptions {
|
|
|
5534
6045
|
}
|
|
5535
6046
|
declare const FontSize: Extension<FontSizeOptions, unknown>;
|
|
5536
6047
|
|
|
6048
|
+
/**
|
|
6049
|
+
* NotionColorPicker Extension
|
|
6050
|
+
*
|
|
6051
|
+
* Provides toolbar registration for a Notion-style inline color picker that
|
|
6052
|
+
* drives the `colorToken` / `backgroundColorToken` attributes on the textStyle
|
|
6053
|
+
* mark (added by TextColor and Highlight).
|
|
6054
|
+
*
|
|
6055
|
+
* Owns:
|
|
6056
|
+
* - The shared named-token palette (default: 9 Notion-style colors).
|
|
6057
|
+
* - A bubble-menu-only toolbar item (`notionColor`) that emits a custom
|
|
6058
|
+
* `notionColorOpen` event when clicked. Framework wrappers listen for the
|
|
6059
|
+
* event and render the actual picker panel.
|
|
6060
|
+
*
|
|
6061
|
+
* The panel renders the full palette every time it opens; no MRU/recent
|
|
6062
|
+
* tracking is kept because all 18 swatches (9 text + 9 bg) fit in one view.
|
|
6063
|
+
*
|
|
6064
|
+
* @example
|
|
6065
|
+
* ```ts
|
|
6066
|
+
* import { TextStyle, TextColor, Highlight, NotionColorPicker } from '@domternal/core';
|
|
6067
|
+
*
|
|
6068
|
+
* const editor = new Editor({
|
|
6069
|
+
* extensions: [
|
|
6070
|
+
* TextStyle,
|
|
6071
|
+
* TextColor,
|
|
6072
|
+
* Highlight,
|
|
6073
|
+
* NotionColorPicker,
|
|
6074
|
+
* ],
|
|
6075
|
+
* });
|
|
6076
|
+
* ```
|
|
6077
|
+
*/
|
|
6078
|
+
|
|
6079
|
+
/**
|
|
6080
|
+
* Default named tokens. Match the BlockColor palette + theme tokens
|
|
6081
|
+
* (`--dm-block-text-<token>`, `--dm-block-bg-<token>`) so light and dark
|
|
6082
|
+
* themes render the right hex without any extra CSS work.
|
|
6083
|
+
*/
|
|
6084
|
+
declare const DEFAULT_NOTION_COLOR_PALETTE: readonly string[];
|
|
6085
|
+
interface NotionColorPickerOptions {
|
|
6086
|
+
/**
|
|
6087
|
+
* Named tokens shown in the picker. Each token must have matching
|
|
6088
|
+
* `--dm-block-text-<token>` and `--dm-block-bg-<token>` CSS variables in
|
|
6089
|
+
* the active theme; tokens with no theme support render as transparent
|
|
6090
|
+
* swatches.
|
|
6091
|
+
* @default DEFAULT_NOTION_COLOR_PALETTE
|
|
6092
|
+
*/
|
|
6093
|
+
palette: readonly string[];
|
|
6094
|
+
}
|
|
6095
|
+
interface NotionColorPickerStorage {
|
|
6096
|
+
/** Whether the picker panel is currently open. UI sets this. */
|
|
6097
|
+
isOpen: boolean;
|
|
6098
|
+
}
|
|
6099
|
+
declare const NotionColorPicker: Extension<NotionColorPickerOptions, NotionColorPickerStorage>;
|
|
6100
|
+
|
|
5537
6101
|
/**
|
|
5538
6102
|
* ClearFormatting Extension
|
|
5539
6103
|
*
|
|
@@ -5569,33 +6133,7 @@ interface LinkPopoverOptions {
|
|
|
5569
6133
|
declare const LinkPopover: Extension<LinkPopoverOptions, unknown>;
|
|
5570
6134
|
|
|
5571
6135
|
/**
|
|
5572
|
-
*
|
|
5573
|
-
*
|
|
5574
|
-
* Shows a floating menu when text is selected in the editor.
|
|
5575
|
-
* Useful for formatting toolbars that appear contextually.
|
|
5576
|
-
*
|
|
5577
|
-
* Styles are included automatically via `@domternal/theme` (`_bubble-menu.scss`).
|
|
5578
|
-
*
|
|
5579
|
-
* @example
|
|
5580
|
-
* ```ts
|
|
5581
|
-
* import { BubbleMenu } from '@domternal/core';
|
|
5582
|
-
*
|
|
5583
|
-
* // Create menu element
|
|
5584
|
-
* const menuElement = document.getElementById('bubble-menu');
|
|
5585
|
-
*
|
|
5586
|
-
* const editor = new Editor({
|
|
5587
|
-
* extensions: [
|
|
5588
|
-
* // ... other extensions
|
|
5589
|
-
* BubbleMenu.configure({
|
|
5590
|
-
* element: menuElement,
|
|
5591
|
-
* shouldShow: ({ editor, state, from, to }) => {
|
|
5592
|
-
* // Only show for text selections
|
|
5593
|
-
* return !state.selection.empty;
|
|
5594
|
-
* },
|
|
5595
|
-
* }),
|
|
5596
|
-
* ],
|
|
5597
|
-
* });
|
|
5598
|
-
* ```
|
|
6136
|
+
* Floating menu shown when text is selected. Contextual formatting toolbar.
|
|
5599
6137
|
*/
|
|
5600
6138
|
|
|
5601
6139
|
declare const bubbleMenuPluginKey: PluginKey<any>;
|
|
@@ -5649,76 +6187,6 @@ interface CreateBubbleMenuPluginOptions {
|
|
|
5649
6187
|
declare function createBubbleMenuPlugin(options: CreateBubbleMenuPluginOptions): Plugin;
|
|
5650
6188
|
declare const BubbleMenu: Extension<BubbleMenuOptions, unknown>;
|
|
5651
6189
|
|
|
5652
|
-
/**
|
|
5653
|
-
* FloatingMenu Extension
|
|
5654
|
-
*
|
|
5655
|
-
* Shows a floating menu when the cursor is in an empty paragraph.
|
|
5656
|
-
* Useful for showing block-level insertion options.
|
|
5657
|
-
*
|
|
5658
|
-
* @example
|
|
5659
|
-
* ```ts
|
|
5660
|
-
* import { FloatingMenu } from '@domternal/core';
|
|
5661
|
-
*
|
|
5662
|
-
* // Create menu element
|
|
5663
|
-
* const menuElement = document.getElementById('floating-menu');
|
|
5664
|
-
*
|
|
5665
|
-
* const editor = new Editor({
|
|
5666
|
-
* extensions: [
|
|
5667
|
-
* // ... other extensions
|
|
5668
|
-
* FloatingMenu.configure({
|
|
5669
|
-
* element: menuElement,
|
|
5670
|
-
* shouldShow: ({ editor, state }) => {
|
|
5671
|
-
* const { $from, empty } = state.selection;
|
|
5672
|
-
* // Show in empty paragraphs
|
|
5673
|
-
* return empty &&
|
|
5674
|
-
* $from.parent.type.name === 'paragraph' &&
|
|
5675
|
-
* $from.parent.content.size === 0;
|
|
5676
|
-
* },
|
|
5677
|
-
* }),
|
|
5678
|
-
* ],
|
|
5679
|
-
* });
|
|
5680
|
-
* ```
|
|
5681
|
-
*
|
|
5682
|
-
* Styles are included automatically via `@domternal/theme` (`_floating-menu.scss`).
|
|
5683
|
-
*/
|
|
5684
|
-
|
|
5685
|
-
declare const floatingMenuPluginKey: PluginKey<any>;
|
|
5686
|
-
interface FloatingMenuOptions {
|
|
5687
|
-
/**
|
|
5688
|
-
* The HTML element that contains the menu.
|
|
5689
|
-
* Must be provided by the user.
|
|
5690
|
-
*/
|
|
5691
|
-
element: HTMLElement | null;
|
|
5692
|
-
/**
|
|
5693
|
-
* Function to determine if the menu should be shown.
|
|
5694
|
-
* By default, shows when the cursor is in an empty paragraph.
|
|
5695
|
-
*/
|
|
5696
|
-
shouldShow: (props: {
|
|
5697
|
-
editor: Editor;
|
|
5698
|
-
view: EditorView;
|
|
5699
|
-
state: EditorState;
|
|
5700
|
-
}) => boolean;
|
|
5701
|
-
/**
|
|
5702
|
-
* Offset in pixels from the cursor position.
|
|
5703
|
-
* @default 0
|
|
5704
|
-
*/
|
|
5705
|
-
offset: number;
|
|
5706
|
-
}
|
|
5707
|
-
interface CreateFloatingMenuPluginOptions {
|
|
5708
|
-
pluginKey: PluginKey;
|
|
5709
|
-
editor: Editor;
|
|
5710
|
-
element: HTMLElement;
|
|
5711
|
-
shouldShow?: FloatingMenuOptions['shouldShow'];
|
|
5712
|
-
offset?: number;
|
|
5713
|
-
}
|
|
5714
|
-
/**
|
|
5715
|
-
* Creates a standalone FloatingMenu ProseMirror plugin.
|
|
5716
|
-
* Can be used by framework wrappers (Angular, React, Vue) to create the plugin
|
|
5717
|
-
* independently of the extension system.
|
|
5718
|
-
*/
|
|
5719
|
-
declare function createFloatingMenuPlugin(options: CreateFloatingMenuPluginOptions): Plugin;
|
|
5720
|
-
declare const FloatingMenu: Extension<FloatingMenuOptions, unknown>;
|
|
5721
|
-
|
|
5722
6190
|
/**
|
|
5723
6191
|
* StarterKit Extension
|
|
5724
6192
|
*
|
|
@@ -5827,6 +6295,13 @@ interface StarterKitOptions {
|
|
|
5827
6295
|
* Set to false to disable the ListKeymap extension, or pass options to configure it.
|
|
5828
6296
|
*/
|
|
5829
6297
|
listKeymap?: false | Partial<ListKeymapOptions>;
|
|
6298
|
+
/**
|
|
6299
|
+
* Set to false to disable the ListIndent extension. ListIndent adds
|
|
6300
|
+
* Tab / Shift-Tab keymap that indents a top-level block under the
|
|
6301
|
+
* previous list (and outdents back). Registered AFTER ListKeymap so
|
|
6302
|
+
* the in-list-item Tab/Shift-Tab keep priority.
|
|
6303
|
+
*/
|
|
6304
|
+
listIndent?: false;
|
|
5830
6305
|
/**
|
|
5831
6306
|
* Set to false to disable the LinkPopover extension, or pass options to configure it.
|
|
5832
6307
|
*/
|
|
@@ -5846,4 +6321,4 @@ declare const StarterKit: Extension<StarterKitOptions, unknown>;
|
|
|
5846
6321
|
*/
|
|
5847
6322
|
declare const VERSION = "0.1.0";
|
|
5848
6323
|
|
|
5849
|
-
export { type AnyExtension, type AnyExtensionConfig, type AttributeSpec, type AttributeSpecs, type AutolinkPluginOptions, BaseKeymap, type BaseKeymapOptions, Blockquote, type BlockquoteOptions, Bold, type BoldOptions, BubbleMenu, type BubbleMenuOptions, type BuildCommandPropsOptions, BulletList, type BulletListOptions, type CanChainedCommands, CanChecker, type CanCheckerEditor, type CanCheckerOptions, type CanCommands, ChainBuilder, type ChainBuilderEditor, type ChainBuilderOptions, type ChainFailure, type ChainedCommands, CharacterCount, type CharacterCountOptions, type CharacterCountStorage, type ClearContentOptions, ClearFormatting, Code, CodeBlock, type CodeBlockOptions, type CodeOptions, type Command, type CommandEditor, CommandManager, type CommandManagerEditor, type CommandMap, type CommandProps, type CommandPropsEditor, type CommandSpec
|
|
6324
|
+
export { type AnyExtension, type AnyExtensionConfig, type AttributeSpec, type AttributeSpecs, type AutolinkPluginOptions, BaseKeymap, type BaseKeymapOptions, BlockColor, type BlockColorOptions, Blockquote, type BlockquoteOptions, Bold, type BoldOptions, BubbleMenu, type BubbleMenuOptions, type BuildCommandPropsOptions, BulletList, type BulletListOptions, type CanChainedCommands, CanChecker, type CanCheckerEditor, type CanCheckerOptions, type CanCommands, ChainBuilder, type ChainBuilderEditor, type ChainBuilderOptions, type ChainFailure, type ChainedCommands, CharacterCount, type CharacterCountOptions, type CharacterCountStorage, type ClearContentOptions, ClearFormatting, Code, CodeBlock, type CodeBlockOptions, type CodeOptions, type Command, type CommandEditor, CommandManager, type CommandManagerEditor, type CommandMap, type CommandProps, type CommandPropsEditor, type CommandSpec, type Content, type ContentErrorProps, type CreateBubbleMenuPluginOptions, type CreateDocumentOptions, type CreateEventProps, DEFAULT_BLOCK_COLORS, DEFAULT_BLOCK_COLOR_TYPES, DEFAULT_HIGHLIGHT_COLORS, DEFAULT_NOTION_COLOR_PALETTE, DEFAULT_TEXT_COLORS, type DeleteEventProps, Document$1 as Document, type DropEventProps, Dropcursor, type DropcursorOptions, Editor, type EditorEventName, type EditorEvents, type EditorInstance, type EditorOptions, EventEmitter, Extension, type ExtensionConfig, type ExtensionEditor, ExtensionManager, type ExtensionManagerEditor, type ExtensionManagerOptions, FLOATING_MENU_NO_FOCUS, type FindChildResult, type FindParentNodeResult, FloatingMenuController, type FloatingMenuGroup, type FloatingMenuItem, type FloatingMenuItemsOverride, Focus, type FocusEventProps, type FocusOptions, type FocusPosition, FontFamily, type FontFamilyOptions, FontSize, type FontSizeOptions, Gapcursor, type GenerateHTMLOptions, type GenerateJSONOptions, type GenerateTextOptions, type GlobalAttributeSpec, type GlobalAttributes, HardBreak, type HardBreakOptions, Heading, type HeadingOptions, Highlight, type HighlightOptions, History, type HistoryOptions, HorizontalRule, type HorizontalRuleOptions, type IconSet, type InlineStyleOverrides, type InsertAsListItemChildArgs, type InsertAsListItemChildResult, InvisibleChars, type InvisibleCharsOptions, type InvisibleCharsStorage, type IsNodeEmptyOptions, type IsValidUrlOptions, Italic, type ItalicOptions, type JSONAttribute, type JSONContent, type JSONMark, type KeyboardShortcutCommand, LIST_ITEM_TYPE_NAMES, LineHeight, type LineHeightOptions, Link, type LinkAttributes, type LinkClickPluginOptions, type LinkExitPluginOptions, type LinkOptions, type LinkPastePluginOptions, LinkPopover, type LinkPopoverOptions, ListIndent, ListItem, type ListItemCursorContext, type ListItemOptions, ListKeymap, type ListKeymapOptions, Mark, type MarkConfig, type MarkInputRuleOptions, type MarkParseRule, type MarkRange, type MarkRenderHTMLProps, type MountEventProps, Node, type NodeConfig, type NodeInputRuleOptions, type NodeParseRule, type NodeRenderHTMLProps, type NodeViewContext, NotionColorPicker, type NotionColorPickerOptions, type NotionColorPickerStorage, OrderedList, type OrderedListOptions, Paragraph, type ParagraphOptions, type PasteEventProps, Placeholder, type PlaceholderOptions, type PositionFloatingOptions, type Range, type RawCommands, Selection, SelectionDecoration, type SelectionDecorationOptions, type SelectionOptions, type SelectionStorage, type SetContentOptions, type SingleCommands, type SplitListForInsertRange, StarterKit, type StarterKitOptions, Strike, type StrikeOptions, Subscript, type SubscriptOptions, Superscript, type SuperscriptOptions, TaskItem, type TaskItemOptions, TaskList, type TaskListOptions, Text, TextAlign, type TextAlignOptions, TextColor, type TextColorOptions, type TextInputRuleOptions, TextStyle, type TextStyleOptions, type TextblockTypeInputRuleOptions, type ToolbarButton, ToolbarController, type ToolbarControllerEditor, type ToolbarDropdown, type ToolbarGroup, type ToolbarItem, type ToolbarLayoutDropdown, type ToolbarLayoutEntry, type ToolbarSeparator, TrailingNode, type TrailingNodeOptions, type TransactionEventProps, Typography, type TypographyOptions, Underline, type UnderlineOptions, UniqueID, type UniqueIDOptions, VERSION, type WrappingInputRuleOptions, applyInlineStyles, autolinkPlugin, autolinkPluginKey, blur, bubbleMenuPluginKey, buildCommandProps, builtInCommands, callOrReturn, characterCountPluginKey, clearContent, copyThemeClass, createAccumulatingDispatch, createBubbleMenuPlugin, createCanChecker, createChainBuilder, createDocument, defaultBlockAt, defaultBubbleContexts, defaultIcons, deleteSelection, findChildren, findListItemAncestorDepth, findParentNode, focus, focusPluginKey, generateHTML, generateJSON, generateText, getListItemCursorContext, getMarkRange, groupFloatingMenuItems, indentBlockAsListChild, inlineStyles, insertAsListItemChild, insertChildrenZoneSibling, insertContent, insertText, invisibleCharsPluginKey, isDocumentEmpty, isInListItemLabel, isInsideListItem, isNodeEmpty, isValidUrl, lift, liftCurrentListItem, liftEmptyChildrenZoneParagraph, linkClickPlugin, linkClickPluginKey, linkExitPlugin, linkExitPluginKey, linkPastePlugin, linkPastePluginKey, markInputRule, markInputRulePatterns, nodeInputRule, outdentBlockFromListItem, placeholderPluginKey, positionFloating, positionFloatingOnce, resetAttributes, selectAll, selectNodeBackward, selectionDecorationPluginKey, setBlockType, setContent, setMark, splitListForInsert, stripInlineColorConflicts, textInputRule, textblockTypeInputRule, toggleBlockType, toggleList, toggleMark, toggleWrap, uniqueIDPluginKey, unsetAllMarks, unsetMark, updateAttributes, wrapIn, wrappingInputRule, writeToClipboard };
|