xiaodao-editor 0.1.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.
Files changed (72) hide show
  1. package/README.md +306 -0
  2. package/dist/block-editor.js +23254 -0
  3. package/dist/block-editor.umd.cjs +26 -0
  4. package/dist/core/Editor.d.ts +83 -0
  5. package/dist/core/command/Command.d.ts +32 -0
  6. package/dist/core/command/InputRule.d.ts +21 -0
  7. package/dist/core/command/Keymap.d.ts +42 -0
  8. package/dist/core/command/SlashCommand.d.ts +24 -0
  9. package/dist/core/command/primitiveCommands.d.ts +97 -0
  10. package/dist/core/extension/Extension.d.ts +52 -0
  11. package/dist/core/extension/Registry.d.ts +46 -0
  12. package/dist/core/history/HistoryManager.d.ts +37 -0
  13. package/dist/core/ids.d.ts +5 -0
  14. package/dist/core/index.d.ts +35 -0
  15. package/dist/core/plugin/Plugin.d.ts +26 -0
  16. package/dist/core/schema/BlockSchema.d.ts +70 -0
  17. package/dist/core/schema/SchemaRegistry.d.ts +22 -0
  18. package/dist/core/selection/Selection.d.ts +25 -0
  19. package/dist/core/serialize/Serializer.d.ts +31 -0
  20. package/dist/core/state/EditorState.d.ts +26 -0
  21. package/dist/core/state/Step.d.ts +39 -0
  22. package/dist/core/state/Transaction.d.ts +52 -0
  23. package/dist/core/state/invert.d.ts +19 -0
  24. package/dist/core/state/store.d.ts +78 -0
  25. package/dist/core/types.d.ts +105 -0
  26. package/dist/extensions/BulletList.d.ts +2 -0
  27. package/dist/extensions/CodeBlock.d.ts +2 -0
  28. package/dist/extensions/Divider.d.ts +2 -0
  29. package/dist/extensions/Heading.d.ts +2 -0
  30. package/dist/extensions/History.d.ts +2 -0
  31. package/dist/extensions/Image.d.ts +34 -0
  32. package/dist/extensions/Keymap.d.ts +2 -0
  33. package/dist/extensions/OrderedList.d.ts +18 -0
  34. package/dist/extensions/Paragraph.d.ts +5 -0
  35. package/dist/extensions/Quote.d.ts +2 -0
  36. package/dist/extensions/Table.d.ts +74 -0
  37. package/dist/extensions/TableOfContents.d.ts +18 -0
  38. package/dist/extensions/TodoList.d.ts +2 -0
  39. package/dist/extensions/_commonAttrs.d.ts +84 -0
  40. package/dist/extensions/builtin.d.ts +15 -0
  41. package/dist/extensions/tableModel.d.ts +199 -0
  42. package/dist/i18n.d.ts +31 -0
  43. package/dist/index.d.ts +30 -0
  44. package/dist/style.css +1 -0
  45. package/dist/test-img.png +0 -0
  46. package/dist/view/BlockContent.vue.d.ts +21 -0
  47. package/dist/view/BlockEditor.vue.d.ts +67 -0
  48. package/dist/view/BlockHost.vue.d.ts +51 -0
  49. package/dist/view/BlockList.vue.d.ts +64 -0
  50. package/dist/view/clipboard.d.ts +11 -0
  51. package/dist/view/context.d.ts +116 -0
  52. package/dist/view/domSelection.d.ts +65 -0
  53. package/dist/view/imageUpload.d.ts +130 -0
  54. package/dist/view/inlineDom.d.ts +23 -0
  55. package/dist/view/keymapHandler.d.ts +7 -0
  56. package/dist/view/ui/BlockHandle.vue.d.ts +33 -0
  57. package/dist/view/ui/BlockSettingsMenu.vue.d.ts +32 -0
  58. package/dist/view/ui/CodeLangPicker.vue.d.ts +20 -0
  59. package/dist/view/ui/HoverToolbar.vue.d.ts +81 -0
  60. package/dist/view/ui/LinkPopover.vue.d.ts +62 -0
  61. package/dist/view/ui/MobileToolbar.vue.d.ts +29 -0
  62. package/dist/view/ui/NumberPicker.vue.d.ts +20 -0
  63. package/dist/view/ui/OrderedListMenu.vue.d.ts +37 -0
  64. package/dist/view/ui/PlusMenu.vue.d.ts +29 -0
  65. package/dist/view/ui/SafeHtml.vue.d.ts +8 -0
  66. package/dist/view/ui/icons.d.ts +51 -0
  67. package/dist/view/ui/inputRulesEngine.d.ts +33 -0
  68. package/dist/view/ui/popup.d.ts +75 -0
  69. package/dist/view/ui/useMenuDismiss.d.ts +9 -0
  70. package/dist/view/ui/useMenuScroll.d.ts +2 -0
  71. package/dist/view/urlUtils.d.ts +39 -0
  72. package/package.json +73 -0
@@ -0,0 +1,83 @@
1
+ import { BlockId, DocumentData, Selection } from './types';
2
+ import { EditorState } from './state/EditorState';
3
+ import { Transaction } from './state/Transaction';
4
+ import { EditorRegistries } from './extension/Registry';
5
+ import { Extension } from './extension/Extension';
6
+ export interface EditorConfig {
7
+ readonly extensions: readonly Extension[];
8
+ readonly defaultBlockType?: string;
9
+ readonly initialDocument?: DocumentData;
10
+ readonly initialSelection?: Selection;
11
+ readonly editable?: boolean;
12
+ readonly historyLimit?: number;
13
+ }
14
+ export interface StateUpdate {
15
+ readonly state: EditorState;
16
+ readonly changed: ReadonlySet<BlockId>;
17
+ readonly removed: ReadonlySet<BlockId>;
18
+ }
19
+ export type EditorListener = (update: StateUpdate) => void;
20
+ /** Public read-only history API exposed by the Editor facade. */
21
+ export interface EditorHistory {
22
+ /** True if an undo entry exists. */
23
+ canUndo(): boolean;
24
+ /** True if a redo entry exists. */
25
+ canRedo(): boolean;
26
+ /**
27
+ * Open an explicit grouping scope. Any `dispatch` between `beginGroup()` and
28
+ * the matching `endGroup()` merges into one undo entry. Scopes nest; only
29
+ * the outermost close "commits". Prefer this over using the
30
+ * `meta.historyGroup` key manually.
31
+ */
32
+ beginGroup(): string;
33
+ /** Close an explicit grouping scope opened by `beginGroup()`. */
34
+ endGroup(): void;
35
+ }
36
+ export declare class Editor {
37
+ readonly registries: EditorRegistries;
38
+ private state;
39
+ private readonly listeners;
40
+ private readonly _history;
41
+ readonly commands: Record<string, (...args: unknown[]) => boolean>;
42
+ editable: boolean;
43
+ /** The block id currently owning the focused contenteditable (set by the view). */
44
+ focusBlockId: BlockId | null;
45
+ /** Public history API: canUndo/canRedo plus grouping helpers. */
46
+ readonly history: EditorHistory;
47
+ constructor(config: EditorConfig);
48
+ getState(): EditorState;
49
+ toData(): DocumentData;
50
+ /**
51
+ * Export the current document as a Markdown string. Serializes the editor's
52
+ * own live document state directly (see `docToMarkdown` below); no external
53
+ * converter or intermediate re-serialization is involved.
54
+ */
55
+ toMarkdown(): string;
56
+ /**
57
+ * Replace the whole document by parsing a Markdown string. Resets history.
58
+ * The Markdown is parsed natively by the editor (see `markdownToDoc` below)
59
+ * straight into its document state; no external converter and no
60
+ * intermediate `DocumentData` round-trip is involved.
61
+ */
62
+ setDocFromMarkdown(markdown: string): void;
63
+ /** Replace the whole document (e.g. on external `v-model` change). Resets history. */
64
+ setDocument(json: DocumentData): void;
65
+ /** Take ownership of a normalized document and reset the editor state. */
66
+ private adoptDoc;
67
+ dispatch(tr: Transaction): void;
68
+ undo(): boolean;
69
+ redo(): boolean;
70
+ canUndo(): boolean;
71
+ canRedo(): boolean;
72
+ subscribe(listener: EditorListener): () => void;
73
+ private notify;
74
+ private eventContext;
75
+ handleKeyDown(event: KeyboardEvent): boolean;
76
+ handleInput(event: InputEvent): boolean;
77
+ handleCompositionStart(event: CompositionEvent): void;
78
+ handleCompositionEnd(event: CompositionEvent): void;
79
+ destroy(): void;
80
+ private seedEmptyDocument;
81
+ }
82
+ /** Validate that a block id exists in the current state (debugging helper). */
83
+ export declare function hasBlock(editor: Editor, id: BlockId): boolean;
@@ -0,0 +1,32 @@
1
+ import { EditorState } from '../state/EditorState';
2
+ import { Transaction } from '../state/Transaction';
3
+ export type Dispatch = (tr: Transaction) => void;
4
+ export type CommandFn<TArgs = void> = (args: TArgs) => (state: EditorState, dispatch?: Dispatch) => boolean;
5
+ export interface CommandEntry<TArgs = void> {
6
+ readonly name: string;
7
+ readonly run: CommandFn<TArgs>;
8
+ }
9
+ /** A command contributed by an extension. */
10
+ export type CommandSpec<TArgs = void> = CommandEntry<TArgs>;
11
+ /**
12
+ * A command entry with type-erased arguments, as stored in the registry.
13
+ * The registry is fundamentally heterogeneous (each command has its own arg
14
+ * type), so the arg type is erased at registration. Type safety is preserved
15
+ * at definition sites (`CommandEntry<YourArgs>`) and at typed command proxies.
16
+ */
17
+ export type AnyCommandEntry = CommandEntry<any>;
18
+ /** Resolves a command name + args to a boolean (handled?), given live state. */
19
+ export type CommandDispatcher = (name: string, args: unknown) => boolean;
20
+ export declare class CommandRegistry {
21
+ private readonly entries;
22
+ register(spec: AnyCommandEntry): void;
23
+ /** Replace an existing command (used so extensions can override primitives). */
24
+ override(spec: AnyCommandEntry): void;
25
+ has(name: string): boolean;
26
+ get(name: string): AnyCommandEntry | undefined;
27
+ /**
28
+ * Build a proxy so callers can write `editor.commands.insertBlock({...})`.
29
+ * Each property access returns a function that dispatches the named command.
30
+ */
31
+ createProxy(dispatch: CommandDispatcher): Record<string, (...args: unknown[]) => boolean>;
32
+ }
@@ -0,0 +1,21 @@
1
+ import { BlockId } from '../types';
2
+ export interface InputRuleContext {
3
+ readonly blockId: BlockId;
4
+ /** Full block text up to and including the just-typed character. */
5
+ readonly textBeforeCaret: string;
6
+ }
7
+ export interface InputRuleSpec {
8
+ readonly name: string;
9
+ /** Tested against `textBeforeCaret`. Must be anchored (e.g. /^# $/). */
10
+ readonly pattern: RegExp;
11
+ /** Command to dispatch when the pattern matches. */
12
+ readonly command: string;
13
+ /** Build command args from the match (optional). */
14
+ readonly args?: (match: RegExpExecArray) => unknown;
15
+ }
16
+ export type InputRule = InputRuleSpec;
17
+ export declare class InputRuleRegistry {
18
+ private readonly rules;
19
+ register(spec: InputRuleSpec): void;
20
+ get all(): readonly InputRule[];
21
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Keymap: binds normalized keyboard shortcuts to commands. Bindings are
3
+ * ordered by priority; the first match wins and a handler returning `true`
4
+ * stops propagation. Key names follow ProseMirror conventions
5
+ * (e.g. "Mod-Enter", "Shift-ArrowUp", "Backspace").
6
+ *
7
+ * See docs/editor-architecture.md §11.1.
8
+ */
9
+ export interface KeymapBinding {
10
+ /** Normalized key, e.g. "Enter", "Shift-Tab", "Mod-B", "ArrowUp". */
11
+ readonly key: string;
12
+ /** Command name to dispatch when the key matches. */
13
+ readonly command: string;
14
+ /** Args passed to the command. */
15
+ readonly args?: unknown;
16
+ /** Lower numbers run first. Default 0. */
17
+ readonly priority?: number;
18
+ }
19
+ export type KeymapSpec = readonly KeymapBinding[];
20
+ /**
21
+ * Derive a normalized key name from a keyboard event. Produces the *actual*
22
+ * platform modifier (Ctrl or Cmd), not a generic "Mod" token. Binding keys
23
+ * use "Mod" as a placeholder; `keyMatches` resolves it to the same actual
24
+ * modifier before comparing.
25
+ *
26
+ * Example: Cmd+Shift+Z on Mac → "Cmd-Shift-Z".
27
+ */
28
+ export declare function keyNameFromEvent(event: KeyboardEvent): string;
29
+ /**
30
+ * Match a binding key (which may use "Mod" as a placeholder) against an
31
+ * event key (which uses the actual modifier: Ctrl or Cmd).
32
+ *
33
+ * Comparison is case-insensitive so that binding keys may use lowercase
34
+ * letters (e.g. "Mod-z") while event keys use uppercase ("Cmd-Z").
35
+ */
36
+ export declare function keyMatches(bindingKey: string, eventKey: string): boolean;
37
+ export declare class KeymapRegistry {
38
+ private readonly bindings;
39
+ register(spec: KeymapSpec): void;
40
+ /** Resolve the first matching binding for an event key. */
41
+ resolve(eventKey: string): KeymapBinding | undefined;
42
+ }
@@ -0,0 +1,24 @@
1
+ import { BlockType } from '../types';
2
+ export interface SlashCommandSpec {
3
+ readonly id: string;
4
+ readonly title: string;
5
+ readonly keywords?: readonly string[];
6
+ readonly description?: string;
7
+ /** Opaque icon token; the view layer interprets it. */
8
+ readonly icon?: unknown;
9
+ /** Command to dispatch when chosen. */
10
+ readonly command: string;
11
+ readonly args?: unknown;
12
+ /** If set, only show when the current block is one of these types. */
13
+ readonly applicableTo?: readonly BlockType[];
14
+ /** Optional category for visual grouping in the menu. */
15
+ readonly category?: string;
16
+ }
17
+ export type SlashCommand = SlashCommandSpec;
18
+ export declare class SlashCommandRegistry {
19
+ private readonly commands;
20
+ register(spec: SlashCommandSpec): void;
21
+ get all(): readonly SlashCommand[];
22
+ /** Naive substring search over title + keywords; refined in Phase 2. */
23
+ search(query: string): readonly SlashCommand[];
24
+ }
@@ -0,0 +1,97 @@
1
+ import { Attrs, BlockId, BlockType, InlineSeq, Selection } from '../types';
2
+ import { AnyCommandEntry, Dispatch } from './Command';
3
+ import { EditorRegistries } from '../extension/Registry';
4
+ export interface InsertBlockArgs {
5
+ readonly type: BlockType;
6
+ readonly attrs?: Attrs;
7
+ readonly content?: InlineSeq;
8
+ /** Insert after this block (resolves parent + index). */
9
+ readonly after?: BlockId;
10
+ /** Or insert at an explicit parent/index. */
11
+ readonly parent?: BlockId | null;
12
+ readonly index?: number;
13
+ }
14
+ export interface ReplaceBlockArgs {
15
+ readonly id: BlockId;
16
+ readonly type: BlockType;
17
+ readonly attrs?: Attrs;
18
+ }
19
+ export interface SetTextArgs {
20
+ readonly id: BlockId;
21
+ readonly content: InlineSeq;
22
+ readonly selectionAfter?: Selection;
23
+ }
24
+ export interface SplitBlockArgs {
25
+ readonly id: BlockId;
26
+ readonly offset: number;
27
+ /**
28
+ * Type for the newly-created block. Defaults to the editor's default block
29
+ * type (paragraph). Used by the Enter handler to continue a list: passing
30
+ * the current list type yields a new list item instead of a paragraph.
31
+ */
32
+ readonly asType?: BlockType;
33
+ /** Attrs for the new block; defaults to defaultAttrsFor(asType). */
34
+ readonly asAttrs?: Attrs;
35
+ }
36
+ export interface MoveCaretArgs {
37
+ readonly offset?: number;
38
+ }
39
+ export interface ConvertBlockArgs {
40
+ readonly id: BlockId;
41
+ readonly type: BlockType;
42
+ readonly attrs?: Attrs;
43
+ }
44
+ export interface SetBlockAlignArgs {
45
+ readonly id: BlockId;
46
+ readonly align: 'left' | 'center' | 'right' | 'justify';
47
+ }
48
+ export interface SetBlockColorArgs {
49
+ readonly id: BlockId;
50
+ /** Color preset key (e.g. 'blue'). Pass 'default' to reset. */
51
+ readonly color: string;
52
+ }
53
+ export interface SetBlockBgColorArgs {
54
+ readonly id: BlockId;
55
+ readonly bgColor: string;
56
+ }
57
+ export interface SetStartNumberArgs {
58
+ readonly id: BlockId;
59
+ /**
60
+ * The explicit starting number for this ordered-list item.
61
+ * Pass `null` / `undefined` to clear the override — the item will then
62
+ * follow the previous block's numbering (standard "continue" behavior).
63
+ */
64
+ readonly startNumber: number | null;
65
+ }
66
+ export interface IndentBlockArgs {
67
+ readonly id?: BlockId;
68
+ }
69
+ export interface ToggleMarkArgs {
70
+ readonly id: BlockId;
71
+ readonly markType: string;
72
+ readonly from: number;
73
+ readonly to: number;
74
+ }
75
+ export interface SetInlineMarkArgs {
76
+ readonly id: BlockId;
77
+ readonly markType: string;
78
+ readonly attrs: Attrs | null;
79
+ readonly from: number;
80
+ readonly to: number;
81
+ }
82
+ export interface SetLinkArgs {
83
+ readonly id: BlockId;
84
+ readonly href: string;
85
+ readonly from: number;
86
+ readonly to: number;
87
+ /** Optional new text for the linked range. If omitted, text is unchanged. */
88
+ readonly text?: string;
89
+ }
90
+ export interface UnsetLinkArgs {
91
+ readonly id: BlockId;
92
+ readonly from: number;
93
+ readonly to: number;
94
+ }
95
+ /** Build all primitive commands. Registered by the Editor at construction. */
96
+ export declare function createPrimitiveCommands(registries: EditorRegistries): AnyCommandEntry[];
97
+ export type { Dispatch };
@@ -0,0 +1,52 @@
1
+ import { BlockSchemaSpec } from '../schema/BlockSchema';
2
+ import { BlockType } from '../types';
3
+ import { AnyCommandEntry } from '../command/Command';
4
+ import { InputRuleSpec } from '../command/InputRule';
5
+ import { KeymapSpec } from '../command/Keymap';
6
+ import { Plugin } from '../plugin/Plugin';
7
+ import { SlashCommandSpec } from '../command/SlashCommand';
8
+ import { DeserializerSpec, SerializerSpec } from '../serialize/Serializer';
9
+ /**
10
+ * Framework-opaque renderer spec. `component` is a Vue component in practice
11
+ * but typed as `unknown` so the core stays framework-agnostic; the view layer
12
+ * (`BlockHost`) interprets it.
13
+ */
14
+ export interface BlockRendererSpec {
15
+ readonly component: unknown;
16
+ /** Does this block own a contenteditable text region? Default: from schema. */
17
+ readonly editable?: boolean;
18
+ }
19
+ export interface ToolbarActionSpec {
20
+ readonly id: string;
21
+ readonly label: string;
22
+ readonly command: string;
23
+ readonly args?: unknown;
24
+ readonly icon?: unknown;
25
+ }
26
+ export interface Extension {
27
+ readonly name: string;
28
+ /** Other extensions this one bundles. Flattened and de-duplicated by name. */
29
+ readonly uses?: readonly Extension[];
30
+ /** Declares a block type (schema). */
31
+ readonly schema?: BlockSchemaSpec;
32
+ /** Vue component that renders blocks of this type. */
33
+ readonly renderer?: BlockRendererSpec;
34
+ /** Commands contributed by this extension. */
35
+ readonly commands?: readonly AnyCommandEntry[];
36
+ /** Keyboard shortcut → command bindings. */
37
+ readonly keymap?: KeymapSpec;
38
+ /** Text patterns → command (activated in Phase 2). */
39
+ readonly inputRules?: readonly InputRuleSpec[];
40
+ /** Slash-menu / command-palette entries (activated in Phase 2). */
41
+ readonly slashCommands?: readonly SlashCommandSpec[];
42
+ /** Hover/insert toolbar actions (activated in Phase 4). */
43
+ readonly toolbar?: readonly ToolbarActionSpec[];
44
+ /** Per-block serialization (Markdown/HTML). */
45
+ readonly serialize?: SerializerSpec;
46
+ /** Per-block deserialization (Markdown/HTML). */
47
+ readonly deserialize?: DeserializerSpec;
48
+ /** Editor-level plugins (history, keymap, selection sync, …). */
49
+ readonly plugins?: readonly Plugin[];
50
+ }
51
+ /** A block type this extension declares (for convenience). */
52
+ export declare function extensionBlockType(ext: Extension): BlockType | null;
@@ -0,0 +1,46 @@
1
+ import { BlockType } from '../types';
2
+ import { AnyCommandEntry, CommandRegistry } from '../command/Command';
3
+ import { InputRuleRegistry } from '../command/InputRule';
4
+ import { KeymapRegistry } from '../command/Keymap';
5
+ import { SlashCommandRegistry } from '../command/SlashCommand';
6
+ import { BlockRendererSpec, Extension, ToolbarActionSpec } from './Extension';
7
+ import { Plugin } from '../plugin/Plugin';
8
+ import { SchemaRegistry } from '../schema/SchemaRegistry';
9
+ import { DeserializerRegistry, SerializerRegistry } from '../serialize/Serializer';
10
+ /** Opaque renderer registry: maps a block type to its renderer spec. */
11
+ export declare class RendererRegistry {
12
+ private readonly map;
13
+ register(type: BlockType, spec: BlockRendererSpec): void;
14
+ get(type: BlockType): BlockRendererSpec | undefined;
15
+ }
16
+ export declare class ToolbarRegistry {
17
+ private readonly map;
18
+ register(type: BlockType, actions: readonly ToolbarActionSpec[]): void;
19
+ get(type: BlockType): readonly ToolbarActionSpec[];
20
+ }
21
+ export interface EditorRegistries {
22
+ readonly schema: SchemaRegistry;
23
+ readonly renderers: RendererRegistry;
24
+ readonly commands: CommandRegistry;
25
+ readonly keymap: KeymapRegistry;
26
+ readonly inputRules: InputRuleRegistry;
27
+ readonly slash: SlashCommandRegistry;
28
+ readonly toolbar: ToolbarRegistry;
29
+ readonly serializers: SerializerRegistry;
30
+ readonly deserializers: DeserializerRegistry;
31
+ readonly plugins: readonly Plugin[];
32
+ /** Extension-contributed commands (registered after primitives so they can override). */
33
+ readonly extensionCommands: readonly AnyCommandEntry[];
34
+ /** The block type used by "empty Enter exits" (default: 'paragraph'). */
35
+ readonly defaultBlockType: BlockType;
36
+ }
37
+ export interface BuildRegistriesOptions {
38
+ readonly defaultBlockType?: BlockType;
39
+ }
40
+ /**
41
+ * Flatten an extension array: recursively expand `uses`, de-duplicate by name
42
+ * keeping the *last* occurrence (so user-provided extensions override
43
+ * built-ins with the same name).
44
+ */
45
+ export declare function flattenExtensions(extensions: readonly Extension[]): Extension[];
46
+ export declare function buildRegistries(extensions: readonly Extension[], options?: BuildRegistriesOptions): EditorRegistries;
@@ -0,0 +1,37 @@
1
+ import { DocState, Selection } from '../types';
2
+ import { Transaction } from '../state/Transaction';
3
+ export declare class HistoryManager {
4
+ private readonly undoStack;
5
+ private readonly redoStack;
6
+ private readonly limit;
7
+ /** Stack of explicit groups opened by `beginGroup`/`endGroup`. */
8
+ private manualGroupStack;
9
+ /** Monotonically increasing counter for unique group ids. */
10
+ private groupCounter;
11
+ constructor(limit?: number);
12
+ /**
13
+ * Begin a new explicit grouping scope. Any `record()` call made between
14
+ * `beginGroup()` and the matching `endGroup()` (even across nested scopes)
15
+ * will be assigned to the same generated `historyGroup` key, so they merge
16
+ * into a single undo entry. Scopes nest: the outermost `endGroup()` closes
17
+ * the group (subsequent records become their own entries again).
18
+ *
19
+ * Typical use: bracket a sequence of commands (e.g. `setText` + `convertBlock`)
20
+ * so the user can undo them as one step.
21
+ */
22
+ beginGroup(): string;
23
+ /** Close an explicit grouping scope opened by `beginGroup()`. */
24
+ endGroup(): void;
25
+ /** The currently-active manual group id, or null if none. */
26
+ get currentGroup(): string | null;
27
+ /** Record a transaction against the state that preceded it. */
28
+ record(tr: Transaction, prevSelection: Selection, prevDoc: DocState): void;
29
+ canUndo(): boolean;
30
+ canRedo(): boolean;
31
+ /** Clear all history (used when the document is replaced wholesale). */
32
+ reset(): void;
33
+ /** Build the transaction that undoes the last entry, or null if none. */
34
+ undo(): Transaction | null;
35
+ /** Build the transaction that redoes the last undone entry, or null if none. */
36
+ redo(): Transaction | null;
37
+ }
@@ -0,0 +1,5 @@
1
+ import { BlockId } from './types';
2
+ /** Generate a fresh, unique block id. */
3
+ export declare function createBlockId(): BlockId;
4
+ /** Coerce a string into a `BlockId` (use only when rehydrating trusted data). */
5
+ export declare function asBlockId(value: string): BlockId;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Public surface of the framework-agnostic editor core. The view layer and
3
+ * extensions import from here. Nothing in this barrel imports Vue.
4
+ */
5
+ export * from './types';
6
+ export { createBlockId, asBlockId } from './ids';
7
+ export type { BlockSchema, BlockSchemaSpec, AttrSpec, } from './schema/BlockSchema';
8
+ export { defineSchema, defaultAttrs, coerceAttrs, canContain, hasText, isIsolating, isEmpty, } from './schema/BlockSchema';
9
+ export { SchemaRegistry } from './schema/SchemaRegistry';
10
+ export * from './state/store';
11
+ export type { Step } from './state/Step';
12
+ export { applySteps, type ApplyResult } from './state/Step';
13
+ export { createState, applyTransaction, type EditorState, type ApplyTransactionResult } from './state/EditorState';
14
+ export { createTransaction, TransactionBuilder, type Transaction, type TransactionMeta, type InsertBlockParams, } from './state/Transaction';
15
+ export { invertSteps } from './state/invert';
16
+ export * from './selection/Selection';
17
+ export type { CommandFn, CommandEntry, CommandSpec, AnyCommandEntry, Dispatch, CommandDispatcher } from './command/Command';
18
+ export { CommandRegistry } from './command/Command';
19
+ export { createPrimitiveCommands } from './command/primitiveCommands';
20
+ export type { KeymapBinding, KeymapSpec } from './command/Keymap';
21
+ export { KeymapRegistry, keyNameFromEvent, keyMatches } from './command/Keymap';
22
+ export type { InputRuleSpec, InputRule } from './command/InputRule';
23
+ export { InputRuleRegistry } from './command/InputRule';
24
+ export type { SlashCommandSpec, SlashCommand } from './command/SlashCommand';
25
+ export { SlashCommandRegistry } from './command/SlashCommand';
26
+ export type { SerializerSpec, DeserializerSpec, SerializeResult } from './serialize/Serializer';
27
+ export { SerializerRegistry, DeserializerRegistry } from './serialize/Serializer';
28
+ export type { Plugin, PluginState, EventContext } from './plugin/Plugin';
29
+ export type { Extension, BlockRendererSpec, ToolbarActionSpec } from './extension/Extension';
30
+ export { extensionBlockType } from './extension/Extension';
31
+ export { flattenExtensions, buildRegistries } from './extension/Registry';
32
+ export type { EditorRegistries, RendererRegistry, ToolbarRegistry, BuildRegistriesOptions, } from './extension/Registry';
33
+ export { HistoryManager } from './history/HistoryManager';
34
+ export { Editor } from './Editor';
35
+ export type { EditorConfig, StateUpdate, EditorListener } from './Editor';
@@ -0,0 +1,26 @@
1
+ import { EditorState } from '../state/EditorState';
2
+ import { Transaction } from '../state/Transaction';
3
+ /** Opaque per-plugin state slice. Each plugin owns its concrete type. */
4
+ export type PluginState = unknown;
5
+ export interface EventContext {
6
+ readonly state: EditorState;
7
+ readonly dispatch: (tr: Transaction) => void;
8
+ /** The focused block id, if any (the block owning the active contenteditable). */
9
+ readonly focusBlockId: () => string | null;
10
+ }
11
+ export interface Plugin {
12
+ readonly name: string;
13
+ /** Called once when the editor is created. Returns the initial plugin state. */
14
+ init?(state: EditorState): PluginState;
15
+ /**
16
+ * Called for every applied transaction. Receives the transaction, the
17
+ * *previous* state, and the new (doc/selection) state being assembled.
18
+ * Returns the plugin's new state slice.
19
+ */
20
+ applyTransaction?(tr: Transaction, prevState: EditorState, nextDoc: EditorState['doc'], nextSelection: EditorState['selection']): PluginState;
21
+ onKeyDown?(event: KeyboardEvent, ctx: EventContext): boolean;
22
+ onInput?(event: InputEvent, ctx: EventContext): boolean;
23
+ onCompositionStart?(event: CompositionEvent, ctx: EventContext): void;
24
+ onCompositionEnd?(event: CompositionEvent, ctx: EventContext): void;
25
+ onDestroy?(): void;
26
+ }
@@ -0,0 +1,70 @@
1
+ import { Attrs, Block, BlockType, JSONValue } from '../types';
2
+ export interface AttrSpec {
3
+ /** Default value used when a block is created without this attr. */
4
+ readonly default: JSONValue;
5
+ /** Optional runtime validation; rejected attrs fall back to the default. */
6
+ readonly validate?: (value: unknown) => boolean;
7
+ }
8
+ export interface BlockSchemaSpec {
9
+ readonly type: BlockType;
10
+ readonly attrs?: Readonly<Record<string, AttrSpec>>;
11
+ /** Does this block own an editable inline text region? */
12
+ readonly content?: 'text' | 'none';
13
+ /** May this block contain child blocks? */
14
+ readonly nestable?: boolean;
15
+ /** Whitelist of allowed child types. Omit / '*' means any registered type. */
16
+ readonly allowedChildren?: readonly BlockType[] | '*';
17
+ /**
18
+ * If true, this block is a boundary for delete/merge: Backspace at its start
19
+ * will not merge it into the previous block (e.g. a code block).
20
+ */
21
+ readonly isolating?: boolean;
22
+ /**
23
+ * If true, this block is a list item (bullet / ordered / todo). Enter on a
24
+ * non-empty item continues the list by inserting a new item of the same
25
+ * type; Backspace at offset 0 converts it to a paragraph instead of
26
+ * merging into the previous block. The core uses this schema flag rather
27
+ * than switching on `block.type`.
28
+ */
29
+ readonly listLike?: boolean;
30
+ /**
31
+ * If false, inline marks (bold/italic/underline/strikethrough/code) and
32
+ * block-level color/bgColor are not allowed on this block. When a block
33
+ * is converted to a type with inlineMarks=false, all existing marks are
34
+ * stripped and color/bgColor are reset to defaults.
35
+ */
36
+ readonly inlineMarks?: boolean;
37
+ /**
38
+ * Inline mark types that are disallowed on this block type even though
39
+ * inlineMarks=true. Used when a block renders a mark globally (e.g. quote
40
+ * blocks render italic by default) so the corresponding inline mark would
41
+ * be redundant. The toggleMark command refuses to apply these; the UI
42
+ * should disable the matching buttons.
43
+ */
44
+ readonly disallowedMarks?: readonly string[];
45
+ /** Is this block "empty" (used for placeholder + "empty Enter exits")? */
46
+ readonly empty?: (block: Block) => boolean;
47
+ }
48
+ export interface BlockSchema {
49
+ readonly type: BlockType;
50
+ readonly attrs: Readonly<Record<string, AttrSpec>>;
51
+ readonly content: 'text' | 'none';
52
+ readonly nestable: boolean;
53
+ readonly allowedChildren: readonly BlockType[] | '*';
54
+ readonly isolating: boolean;
55
+ readonly listLike: boolean;
56
+ readonly inlineMarks: boolean;
57
+ readonly disallowedMarks: readonly string[];
58
+ readonly empty: (block: Block) => boolean;
59
+ }
60
+ /** Normalize a spec into a full schema with defaults applied. */
61
+ export declare function defineSchema(spec: BlockSchemaSpec): BlockSchema;
62
+ /** Compute the default attrs for a schema (used when creating a block). */
63
+ export declare function defaultAttrs(schema: BlockSchema): Attrs;
64
+ /** Coerce arbitrary attrs through a schema, validating and filling defaults. */
65
+ export declare function coerceAttrs(schema: BlockSchema, raw: Readonly<Record<string, unknown>>): Attrs;
66
+ /** Does the parent schema permit a child of the given type? */
67
+ export declare function canContain(parent: BlockSchema, childType: BlockType): boolean;
68
+ export declare function hasText(schema: BlockSchema): boolean;
69
+ export declare function isIsolating(schema: BlockSchema): boolean;
70
+ export declare function isEmpty(schema: BlockSchema, block: Block): boolean;
@@ -0,0 +1,22 @@
1
+ import { Block, BlockType } from '../types';
2
+ import { BlockSchema } from './BlockSchema';
3
+ export declare class SchemaRegistry {
4
+ private readonly schemas;
5
+ private readonly fallback;
6
+ constructor(schemas: ReadonlyMap<BlockType, BlockSchema>, fallback: BlockSchema);
7
+ /** Resolve a schema by type, falling back to the paragraph-like default. */
8
+ get(type: BlockType): BlockSchema;
9
+ has(type: BlockType): boolean;
10
+ /** Compute default attrs for a type (used when creating a block). */
11
+ defaultAttrsFor(type: BlockType): Readonly<Record<string, import('../types').JSONValue>>;
12
+ /** Coerce raw attrs through the type's schema. */
13
+ coerceAttrsFor(type: BlockType, raw: Readonly<Record<string, unknown>>): Readonly<Record<string, import('../types').JSONValue>>;
14
+ canContain(parentType: BlockType, childType: BlockType): boolean;
15
+ hasText(type: BlockType): boolean;
16
+ isIsolating(type: BlockType): boolean;
17
+ isListLike(type: BlockType): boolean;
18
+ hasInlineMarks(type: BlockType): boolean;
19
+ /** Is the given inline mark type disallowed on this block type? */
20
+ isMarkDisallowed(type: BlockType, markType: string): boolean;
21
+ isEmpty(block: Block): boolean;
22
+ }
@@ -0,0 +1,25 @@
1
+ import { Anchor, BlockId, Selection } from '../types';
2
+ export declare function caretSelection(blockId: BlockId, offset: number): Selection;
3
+ export declare function textSelection(anchor: Anchor, focus: Anchor): Selection;
4
+ export declare function blocksSelection(blockIds: readonly BlockId[]): Selection;
5
+ export declare function isCaret(sel: Selection): sel is Extract<Selection, {
6
+ kind: 'caret';
7
+ }>;
8
+ export declare function isText(sel: Selection): sel is Extract<Selection, {
9
+ kind: 'text';
10
+ }>;
11
+ export declare function isBlocks(sel: Selection): sel is Extract<Selection, {
12
+ kind: 'blocks';
13
+ }>;
14
+ /** A collapsed text/caret selection targets a single offset in a single block. */
15
+ export declare function isCollapsed(sel: Selection): boolean;
16
+ /** The "primary" block of a selection (where commands like Enter operate). */
17
+ export declare function primaryBlock(sel: Selection): BlockId | null;
18
+ /** The focus offset for a caret/text selection, or 0 for blocks selection. */
19
+ export declare function focusOffset(sel: Selection): number;
20
+ /**
21
+ * Normalize a selection so the anchor precedes (or equals) the focus in
22
+ * document order. Used when computing deletion ranges for Backspace/typing
23
+ * over a selection. Returns the [start, end] anchors in order.
24
+ */
25
+ export declare function orderedAnchors(sel: Selection, compare: (a: Anchor, b: Anchor) => number): readonly [Anchor, Anchor] | null;
@@ -0,0 +1,31 @@
1
+ import { Attrs, Block, BlockType, InlineSeq } from '../types';
2
+ export interface SerializeResult {
3
+ readonly type: BlockType;
4
+ readonly attrs?: Attrs;
5
+ readonly content?: InlineSeq;
6
+ }
7
+ export interface SerializerSpec {
8
+ /** Serialize a block to a Markdown line/representation. */
9
+ readonly toMarkdown?: (block: Block) => string;
10
+ /** Serialize a block to an HTML string. */
11
+ readonly toHTML?: (block: Block) => string;
12
+ }
13
+ export interface DeserializerSpec {
14
+ /**
15
+ * Attempt to parse a single Markdown line into a block descriptor, or return
16
+ * null if this deserializer does not match.
17
+ */
18
+ readonly fromMarkdown?: (line: string) => SerializeResult | null;
19
+ }
20
+ export declare class SerializerRegistry {
21
+ private readonly toMarkdown;
22
+ private readonly toHTML;
23
+ register(type: BlockType, spec: SerializerSpec): void;
24
+ markdownFor(block: Block): string | undefined;
25
+ htmlFor(block: Block): string | undefined;
26
+ }
27
+ export declare class DeserializerRegistry {
28
+ private readonly fromMarkdown;
29
+ register(spec: DeserializerSpec): void;
30
+ parseMarkdownLine(line: string): SerializeResult | null;
31
+ }