creo-edit 0.1.0

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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/dist/clipboard/drop.d.ts +17 -0
  4. package/dist/clipboard/htmlParser.d.ts +18 -0
  5. package/dist/clipboard/htmlSerializer.d.ts +9 -0
  6. package/dist/commands/imageCommands.d.ts +32 -0
  7. package/dist/commands/insertCommands.d.ts +33 -0
  8. package/dist/commands/listCommands.d.ts +19 -0
  9. package/dist/commands/markCommands.d.ts +21 -0
  10. package/dist/commands/navigationCommands.d.ts +27 -0
  11. package/dist/commands/structuralCommands.d.ts +22 -0
  12. package/dist/commands/textCommands.d.ts +18 -0
  13. package/dist/controller/history.d.ts +31 -0
  14. package/dist/controller/navigation.d.ts +18 -0
  15. package/dist/controller/selection.d.ts +25 -0
  16. package/dist/controller/wordBoundary.d.ts +25 -0
  17. package/dist/createEditor.d.ts +252 -0
  18. package/dist/dom/anchorMap.d.ts +27 -0
  19. package/dist/index.d.ts +34 -0
  20. package/dist/index.js +7833 -0
  21. package/dist/index.js.map +72 -0
  22. package/dist/input/keymap.d.ts +47 -0
  23. package/dist/input/mobile.d.ts +13 -0
  24. package/dist/input/nativeInput.d.ts +27 -0
  25. package/dist/markdown/serialize.d.ts +2 -0
  26. package/dist/model/blockText.d.ts +42 -0
  27. package/dist/model/cellAccess.d.ts +2 -0
  28. package/dist/model/doc.d.ts +45 -0
  29. package/dist/model/fractional.d.ts +57 -0
  30. package/dist/model/rebalance.d.ts +12 -0
  31. package/dist/model/types.d.ts +133 -0
  32. package/dist/plugin/anchorCodec.d.ts +18 -0
  33. package/dist/plugin/atomic.d.ts +2 -0
  34. package/dist/plugin/builtin.d.ts +10 -0
  35. package/dist/plugin/decorations.d.ts +35 -0
  36. package/dist/plugin/htmlCodec.d.ts +8 -0
  37. package/dist/plugin/keymapMatch.d.ts +2 -0
  38. package/dist/plugin/registry.d.ts +29 -0
  39. package/dist/plugin/runsAt.d.ts +9 -0
  40. package/dist/plugin/serializeCodec.d.ts +6 -0
  41. package/dist/plugin/triggers.d.ts +33 -0
  42. package/dist/plugin/types.d.ts +188 -0
  43. package/dist/plugins/add-block/index.d.ts +17 -0
  44. package/dist/plugins/calendar/index.d.ts +7 -0
  45. package/dist/plugins/calendar/view.d.ts +29 -0
  46. package/dist/plugins/cells/codecs.d.ts +6 -0
  47. package/dist/plugins/cells/commands.d.ts +5 -0
  48. package/dist/plugins/cells/controls.d.ts +3 -0
  49. package/dist/plugins/cells/htmlCodec.d.ts +6 -0
  50. package/dist/plugins/cells/index.d.ts +3 -0
  51. package/dist/plugins/cells/views.d.ts +27 -0
  52. package/dist/plugins/drag-handle/index.d.ts +6 -0
  53. package/dist/plugins/infinite-scroll/index.d.ts +44 -0
  54. package/dist/plugins/md-shortcuts/index.d.ts +2 -0
  55. package/dist/plugins/search/engine.d.ts +33 -0
  56. package/dist/plugins/search/highlight.d.ts +13 -0
  57. package/dist/plugins/search/index.d.ts +5 -0
  58. package/dist/plugins/search/navigate.d.ts +15 -0
  59. package/dist/plugins/search/styles.d.ts +1 -0
  60. package/dist/plugins/search/types.d.ts +73 -0
  61. package/dist/plugins/search/ui.d.ts +2 -0
  62. package/dist/plugins/slash/index.d.ts +12 -0
  63. package/dist/plugins/slash/items.d.ts +21 -0
  64. package/dist/plugins/slash/menu.d.ts +17 -0
  65. package/dist/plugins/styles.css +233 -0
  66. package/dist/render/DocView.d.ts +7 -0
  67. package/dist/render/InlineRunsView.d.ts +7 -0
  68. package/dist/render/blocks/CodeBlockView.d.ts +7 -0
  69. package/dist/render/blocks/HeadingView.d.ts +7 -0
  70. package/dist/render/blocks/ImageView.d.ts +8 -0
  71. package/dist/render/blocks/ListItemView.d.ts +7 -0
  72. package/dist/render/blocks/ParagraphView.d.ts +7 -0
  73. package/dist/virtual/VirtualDoc.d.ts +28 -0
  74. package/dist/virtual/heightIndex.d.ts +36 -0
  75. package/package.json +53 -0
@@ -0,0 +1,47 @@
1
+ import type { Mark } from "../model/types";
2
+ import type { SetBlockTypePayload } from "../commands/structuralCommands";
3
+ /**
4
+ * Cross-platform "mod" key — ⌘ on macOS, Ctrl elsewhere.
5
+ *
6
+ * The detection is conservative: we look at navigator.platform first; in
7
+ * test / SSR environments (no navigator) we default to non-mac.
8
+ */
9
+ export declare function isMac(): boolean;
10
+ export type KeymapHit = {
11
+ kind: "toggleMark";
12
+ mark: Mark;
13
+ } | {
14
+ kind: "setBlockType";
15
+ payload: SetBlockTypePayload;
16
+ } | {
17
+ kind: "indent";
18
+ } | {
19
+ kind: "outdent";
20
+ } | {
21
+ kind: "undo";
22
+ } | {
23
+ kind: "redo";
24
+ } | {
25
+ kind: "selectAll";
26
+ } | {
27
+ kind: "moveWord";
28
+ direction: -1 | 1;
29
+ extend: boolean;
30
+ } | {
31
+ kind: "moveLineEdge";
32
+ direction: -1 | 1;
33
+ extend: boolean;
34
+ } | {
35
+ kind: "moveDocEdge";
36
+ direction: -1 | 1;
37
+ extend: boolean;
38
+ };
39
+ /**
40
+ * Match a keyboard event against the default chord table. Returns the hit if
41
+ * the key is a known chord, else `null` so the caller can fall through to
42
+ * navigation / text editing.
43
+ *
44
+ * The matcher is intentionally event-oriented rather than string-oriented;
45
+ * it sidesteps the "Ctrl+Shift+K" parsing rabbit-hole.
46
+ */
47
+ export declare function matchKeymap(e: KeyboardEvent): KeymapHit | null;
@@ -0,0 +1,13 @@
1
+ import type { Store } from "creo";
2
+ import type { DocState, Selection } from "../model/types";
3
+ export declare function isCoarsePointer(): boolean;
4
+ /** Test-only override (clears the cache so the next read re-detects). */
5
+ export declare function __resetCoarsePointerCache(): void;
6
+ export type ViewportStores = {
7
+ selStore: Store<Selection>;
8
+ docStore: Store<DocState>;
9
+ };
10
+ export type ViewportHandle = {
11
+ destroy: () => void;
12
+ };
13
+ export declare function attachVisualViewport(root: HTMLElement, stores: ViewportStores): ViewportHandle;
@@ -0,0 +1,27 @@
1
+ import type { Store } from "creo";
2
+ import type { DocState, Selection } from "../model/types";
3
+ import type { DispatchableCommand } from "../createEditor";
4
+ import { type UploadFn } from "../commands/imageCommands";
5
+ import type { Registry } from "../plugin/registry";
6
+ import type { TriggerManager } from "../plugin/triggers";
7
+ export type NativeInputStores = {
8
+ docStore: Store<DocState>;
9
+ selStore: Store<Selection>;
10
+ };
11
+ export type NativeInputOptions = {
12
+ dispatch: (cmd: DispatchableCommand) => void;
13
+ undo: () => void;
14
+ redo: () => void;
15
+ selectAll: () => void;
16
+ /** Optional upload hook for pasted / dropped image files. */
17
+ uploadImage?: UploadFn;
18
+ /** Plugin registry — keymap matching, command dispatch for plugin chords. */
19
+ registry: Registry;
20
+ /** Trigger manager — watches text insertion + key events for plugin
21
+ * triggers (slash commands, mentions, etc.). */
22
+ triggers: TriggerManager;
23
+ };
24
+ export type NativeInputHandle = {
25
+ destroy: () => void;
26
+ };
27
+ export declare function attachNativeInput(root: HTMLElement, stores: NativeInputStores, options: NativeInputOptions): NativeInputHandle;
@@ -0,0 +1,2 @@
1
+ import type { SerializedDoc } from "../createEditor";
2
+ export declare function docToMarkdown(doc: SerializedDoc): string;
@@ -0,0 +1,42 @@
1
+ import type { Block, InlineRun, Mark } from "./types";
2
+ /** Blocks whose content is a single InlineRun[] (paragraphs, headings, list items). */
3
+ export type TextBearingBlock = Extract<Block, {
4
+ runs: InlineRun[];
5
+ }>;
6
+ export declare function isTextBearing(block: Block): block is TextBearingBlock;
7
+ /** Total length of plain text across all runs of a text-bearing block. */
8
+ export declare function runsLength(runs: InlineRun[]): number;
9
+ export declare function blockTextLength(block: TextBearingBlock): number;
10
+ /**
11
+ * Normalize: drop empty runs and merge adjacent runs with identical marks.
12
+ * Always returns a fresh array.
13
+ */
14
+ export declare function normalizeRuns(runs: InlineRun[]): InlineRun[];
15
+ /**
16
+ * Find the run + local offset that owns the given character position.
17
+ * `offset` is clamped to [0, runsLength].
18
+ *
19
+ * The "boundary" rule: if `offset` lands exactly between two runs, we report
20
+ * `runIndex` = the index of the run that *ends* at that boundary (so callers
21
+ * inserting text inherit the LEFT run's marks by default).
22
+ */
23
+ export type RunPos = {
24
+ runIndex: number;
25
+ localOffset: number;
26
+ /** Aggregate length of all runs strictly before runIndex. */
27
+ prefixLen: number;
28
+ };
29
+ export declare function locateRun(runs: InlineRun[], offset: number): RunPos;
30
+ /** Marks the next inserted character should inherit at `offset`. */
31
+ export declare function marksAt(runs: InlineRun[], offset: number): ReadonlySet<Mark> | undefined;
32
+ /**
33
+ * Insert `text` (with optional `marks`) at character `offset`.
34
+ * Returns a new runs array.
35
+ */
36
+ export declare function insertText(runs: InlineRun[], offset: number, text: string, marks?: ReadonlySet<Mark>): InlineRun[];
37
+ /** Delete characters in [start, end). Returns a new runs array. */
38
+ export declare function deleteRange(runs: InlineRun[], start: number, end: number): InlineRun[];
39
+ /** Split runs at offset into [left, right] arrays. */
40
+ export declare function splitRunsAt(runs: InlineRun[], offset: number): [InlineRun[], InlineRun[]];
41
+ /** Concatenate two runs arrays, normalizing the seam. */
42
+ export declare function concatRuns(a: InlineRun[], b: InlineRun[]): InlineRun[];
@@ -0,0 +1,2 @@
1
+ export type { RunsCtx } from "../plugin/types";
2
+ export { runsAt, runsLengthAt } from "../plugin/runsAt";
@@ -0,0 +1,45 @@
1
+ import type { Block, BlockId, BlockSpec, DocState, FracIndex } from "./types";
2
+ /** Cheap, monotonically increasing block id with a per-session prefix. */
3
+ export declare function newBlockId(): BlockId;
4
+ export declare function emptyDoc(): DocState;
5
+ /** Build a DocState from a list of blocks (will assign indices if missing). */
6
+ export declare function docFromBlocks(blocks: BlockSpec[]): DocState;
7
+ /**
8
+ * Returns the insertion index in `order` such that the new key sorts at that
9
+ * position. Pure binary search by `Block.index`.
10
+ */
11
+ export declare function findInsertionPos(doc: DocState, index: FracIndex): number;
12
+ /** Returns the position of `id` in `order`, or -1 if not found. */
13
+ export declare function findPos(doc: DocState, id: BlockId): number;
14
+ /**
15
+ * Insert `block` between the blocks at positions [pos-1] and [pos].
16
+ * The new block's `index` is overwritten with a fractional key in that gap.
17
+ */
18
+ export declare function insertAt(doc: DocState, pos: number, block: BlockSpec): DocState;
19
+ /** Insert a block whose `index` has already been assigned. */
20
+ export declare function insertWithIndex(doc: DocState, block: Block): DocState;
21
+ /** Insert `block` immediately after `afterId` (or at the start if null). */
22
+ export declare function insertAfter(doc: DocState, afterId: BlockId | null, block: BlockSpec): DocState;
23
+ /** Replace the block with the same id. */
24
+ export declare function updateBlock(doc: DocState, block: Block): DocState;
25
+ /** Remove a block. */
26
+ export declare function removeBlock(doc: DocState, id: BlockId): DocState;
27
+ /**
28
+ * Remove multiple blocks in one pass. Single allocation of the new order
29
+ * array — avoids the O(M*N) cost of calling removeBlock M times in a loop.
30
+ */
31
+ export declare function removeBlocks(doc: DocState, ids: Iterable<BlockId>): DocState;
32
+ /**
33
+ * Bulk-insert: drop `n` new blocks evenly spaced into the gap before `pos`.
34
+ * Faster than calling insertAt repeatedly because we compute all keys at once.
35
+ *
36
+ * Builds the new `order` array in a single pass (O(N + M) where N = current
37
+ * doc size, M = inserted block count) instead of splicing in a loop. Splicing
38
+ * inside a loop is O(N) per call → O(M*N) overall, which hurts catastrophically
39
+ * for large pastes (e.g. ~10k paragraphs from a long document).
40
+ */
41
+ export declare function insertManyAt(doc: DocState, pos: number, blocks: BlockSpec[]): DocState;
42
+ export declare function maybeRebalance(doc: DocState): DocState;
43
+ export declare function iterBlocks(doc: DocState): IterableIterator<Block>;
44
+ export declare function getBlock(doc: DocState, id: BlockId): Block | undefined;
45
+ export declare function blockAt(doc: DocState, pos: number): Block | undefined;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Fractional indexing over a base-62 alphabet.
3
+ *
4
+ * Alphabet ordering (string compare matches numeric order):
5
+ * '0'..'9' < 'A'..'Z' < 'a'..'z' → 62 symbols.
6
+ *
7
+ * A key is a non-empty string of alphabet characters; lexicographic comparison
8
+ * yields the same ordering as the rationals they represent. The first symbol's
9
+ * value is the most-significant fractional digit.
10
+ *
11
+ * `generateBetween(a, b)` returns a key strictly between `a` and `b`. `null`
12
+ * means "no bound" — use it for the document's first or last position.
13
+ *
14
+ * `generateN(a, b, n)` produces `n` evenly-spaced keys between `a` and `b` in
15
+ * O(n + log span); used by bulk-paste so we don't pay O(n²) re-midpointing.
16
+ */
17
+ declare function ord(c: string): number;
18
+ declare function chr(n: number): string;
19
+ /** Random base-62 character — used as a tail to keep keys distinct. */
20
+ declare function randomChar(): string;
21
+ /** Strip trailing MIN_CHAR ('0') noise from a key (those bits are zeros). */
22
+ declare function trimZeros(s: string): string;
23
+ /**
24
+ * Generate a key strictly between `a` and `b`.
25
+ * - If a==null, the new key is < b.
26
+ * - If b==null, the new key is > a.
27
+ * - Both null → returns "U" (mid-range).
28
+ */
29
+ export declare function generateBetween(a: string | null, b: string | null): string;
30
+ /**
31
+ * Generate `n` evenly-spaced keys strictly between `a` and `b`.
32
+ * Returns them in ascending order.
33
+ *
34
+ * O(n) total — far cheaper than calling generateBetween repeatedly with
35
+ * a moving cursor (which would degrade by binary descent each step).
36
+ */
37
+ export declare function generateN(a: string | null, b: string | null, n: number): string[];
38
+ /** Soft cap; once any key exceeds this length, schedule a rebalance. */
39
+ export declare const REBALANCE_THRESHOLD = 32;
40
+ /** Returns true if any key in the sorted list exceeds REBALANCE_THRESHOLD. */
41
+ export declare function needsRebalance(keys: string[]): boolean;
42
+ /**
43
+ * Produce a fresh, evenly-spaced sequence of N keys, replacing an existing
44
+ * sorted sequence. Used by the doc layer when keys grow past threshold.
45
+ */
46
+ export declare function rebalance(count: number): string[];
47
+ export declare const __internal: {
48
+ ALPHABET: string;
49
+ BASE: number;
50
+ MIN_CHAR: string;
51
+ MAX_CHAR: string;
52
+ ord: typeof ord;
53
+ chr: typeof chr;
54
+ randomChar: typeof randomChar;
55
+ trimZeros: typeof trimZeros;
56
+ };
57
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { Store } from "creo";
2
+ import type { DocState } from "./types";
3
+ /**
4
+ * Watch a docStore and schedule a microtask rebalance whenever any
5
+ * fractional index grows past the soft threshold.
6
+ *
7
+ * Rebalance assigns fresh, evenly-spaced indices to every block (preserving
8
+ * order). It's O(n) and runs at most once per microtask, so worst-case a
9
+ * 600k-block doc rebalances in ~50ms — and only ever triggers under
10
+ * adversarial insertion patterns.
11
+ */
12
+ export declare function attachAutoRebalance(docStore: Store<DocState>): () => void;
@@ -0,0 +1,133 @@
1
+ export type BlockId = string;
2
+ export type FracIndex = string;
3
+ export type Mark = "b" | "i" | "u" | "s" | "code";
4
+ export type InlineRun = {
5
+ text: string;
6
+ marks?: ReadonlySet<Mark>;
7
+ };
8
+ export type ParagraphBlock = {
9
+ id: BlockId;
10
+ index: FracIndex;
11
+ type: "p";
12
+ runs: InlineRun[];
13
+ };
14
+ /**
15
+ * Code-block — like a paragraph, but rendered monospaced inside a <pre>.
16
+ * Enter inside the block inserts a newline character (it does NOT split
17
+ * the block) — the editor treats the whole code block as a single
18
+ * multi-line region. `lang` is an optional language hint preserved across
19
+ * markdown / HTML round-trips; the editor itself doesn't syntax-highlight.
20
+ */
21
+ export type CodeBlock = {
22
+ id: BlockId;
23
+ index: FracIndex;
24
+ type: "code";
25
+ runs: InlineRun[];
26
+ lang?: string;
27
+ };
28
+ export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
29
+ export type HeadingBlock = {
30
+ id: BlockId;
31
+ index: FracIndex;
32
+ type: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
33
+ runs: InlineRun[];
34
+ };
35
+ export type ListItemBlock = {
36
+ id: BlockId;
37
+ index: FracIndex;
38
+ type: "li";
39
+ ordered: boolean;
40
+ depth: 0 | 1 | 2 | 3;
41
+ runs: InlineRun[];
42
+ };
43
+ export type ImageBlock = {
44
+ id: BlockId;
45
+ index: FracIndex;
46
+ type: "img";
47
+ src: string;
48
+ alt?: string;
49
+ width?: number;
50
+ height?: number;
51
+ };
52
+ export type TableBlock = {
53
+ id: BlockId;
54
+ index: FracIndex;
55
+ type: "table";
56
+ rows: number;
57
+ cols: number;
58
+ cells: InlineRun[][][];
59
+ };
60
+ /**
61
+ * Multi-column layout — N side-by-side columns of inline runs. Internal
62
+ * cursor path = [colIndex, charOffset]. Same model shape as a 1-row
63
+ * table but rendered as flex columns instead of an HTML <table>.
64
+ */
65
+ export type ColumnsBlock = {
66
+ id: BlockId;
67
+ index: FracIndex;
68
+ type: "columns";
69
+ cols: number;
70
+ /** cells[c] is the inline-runs sequence for column c. */
71
+ cells: InlineRun[][];
72
+ };
73
+ /**
74
+ * Calendar — non-editable atomic block. Renders one row per day starting
75
+ * at `date` for `days` consecutive days. Path encoding: `[side]` (0
76
+ * = before, 1 = after) like image. Built as a first-party demo of the
77
+ * `isAtomic` plugin contract — third-party plugins follow the same shape.
78
+ */
79
+ export type CalendarBlock = {
80
+ id: BlockId;
81
+ index: FracIndex;
82
+ type: "calendar";
83
+ /** Anchor date in ISO YYYY-MM-DD form. */
84
+ date: string;
85
+ /** Number of consecutive days to render starting at `date`. */
86
+ days: number;
87
+ };
88
+ /**
89
+ * DateMarker — slim non-editable atomic block. One line, e.g.
90
+ * "Wednesday, 2 Sep." Used to break up a journal-style document into
91
+ * day sections that the user can write between.
92
+ */
93
+ export type DateMarkerBlock = {
94
+ id: BlockId;
95
+ index: FracIndex;
96
+ type: "date-marker";
97
+ /** Anchor date in ISO YYYY-MM-DD form. */
98
+ date: string;
99
+ };
100
+ export type Block = ParagraphBlock | HeadingBlock | ListItemBlock | CodeBlock | ImageBlock | TableBlock | ColumnsBlock | CalendarBlock | DateMarkerBlock;
101
+ export type BlockType = Block["type"];
102
+ /**
103
+ * Distributive `Omit` — applies Omit to each member of a union.
104
+ * Plain `Omit<Union, K>` collapses the union into its intersection of fields,
105
+ * which loses the discriminated-union shape.
106
+ */
107
+ export type DistOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;
108
+ /** A block missing its fractional `index` — used by callers that hand the doc
109
+ * layer un-indexed blocks for insertion. */
110
+ export type BlockSpec = DistOmit<Block, "index">;
111
+ export type DocState = {
112
+ byId: Map<BlockId, Block>;
113
+ order: BlockId[];
114
+ };
115
+ /**
116
+ * Anchor — points to a position inside a block.
117
+ * - For text-bearing blocks (p / h1..h6 / li): path = [charOffset]
118
+ * - For tables: path = [row, col, charOffset]
119
+ * - For images: path = [side] side: 0 = before, 1 = after
120
+ */
121
+ export type Anchor = {
122
+ blockId: BlockId;
123
+ path: number[];
124
+ offset: number;
125
+ };
126
+ export type Selection = {
127
+ kind: "caret";
128
+ at: Anchor;
129
+ } | {
130
+ kind: "range";
131
+ anchor: Anchor;
132
+ focus: Anchor;
133
+ };
@@ -0,0 +1,18 @@
1
+ import type { AnchorCodec, DomPoint } from "./types";
2
+ export declare function registerAnchorCodec(type: string, codec: AnchorCodec): void;
3
+ export declare function getAnchorCodec(type: string): AnchorCodec | null;
4
+ /** Visible-character offset from start of `scopeEl` to (hitNode, localOffset). */
5
+ export declare function offsetWithinScope(scopeEl: HTMLElement, hitNode: Node, localOffset: number): number;
6
+ /** Walk descendant text nodes to find the (node, offset) at `charOffset`. */
7
+ export declare function findTextPoint(scopeEl: HTMLElement, charOffset: number): DomPoint;
8
+ /** Default codec — text-bearing blocks land here when they don't register
9
+ * their own. Path encoding: [charOffset]. */
10
+ export declare const defaultTextCodec: AnchorCodec;
11
+ export declare const codeBlockCodec: AnchorCodec;
12
+ export declare const atomicCodec: AnchorCodec;
13
+ export declare const imageCodec: AnchorCodec;
14
+ export declare function findOwningBlockEl(node: Node): HTMLElement | null;
15
+ /** Pluggable anchor → which is just looking up the registered codec.
16
+ * Centralized here so anchorMap.ts and other consumers share one path. */
17
+ export declare function lookupAnchorCodec(kind: string): AnchorCodec | null;
18
+ export type { DomPoint };
@@ -0,0 +1,2 @@
1
+ export declare function registerAtomic(type: string): void;
2
+ export declare function isAtomicBlockType(type: string): boolean;
@@ -0,0 +1,10 @@
1
+ import type { EditorPlugin } from "./types";
2
+ import { cellsPlugin } from "../plugins/cells";
3
+ export declare const paragraphPlugin: EditorPlugin;
4
+ export declare const headingPlugin: EditorPlugin;
5
+ export declare const listPlugin: EditorPlugin;
6
+ export declare const codeBlockPlugin: EditorPlugin;
7
+ export declare const imagePlugin: EditorPlugin;
8
+ export { cellsPlugin };
9
+ /** All built-in plugins, in registration order. */
10
+ export declare const defaultPlugins: EditorPlugin[];
@@ -0,0 +1,35 @@
1
+ import type { Store } from "creo";
2
+ import type { BlockId, DocState } from "../model/types";
3
+ import type { Registry } from "./registry";
4
+ export type DecorationManagerOptions = {
5
+ registry: Registry;
6
+ docStore: Store<DocState>;
7
+ /** Editor root (the contentEditable div). The decoration layer mounts as
8
+ * a sibling, positioned to overlay the same screen rect. */
9
+ editorRoot: HTMLElement;
10
+ };
11
+ export declare class DecorationManager {
12
+ private opts;
13
+ private layer;
14
+ private mounted;
15
+ private rafQueued;
16
+ private rafSyncRequested;
17
+ private unsub;
18
+ private resizeObserver;
19
+ /** Hovered block id — surfaced to decorations via dataset on the layer
20
+ * so they can style themselves with sibling CSS or read it directly. */
21
+ private hoveredBlockId;
22
+ constructor(opts: DecorationManagerOptions);
23
+ destroy(): void;
24
+ /** Currently hovered block id (or null). Decorations read this via
25
+ * `manager.hoveredBlock()` to decide their own visibility. */
26
+ hoveredBlock(): BlockId | null;
27
+ private scheduleSync;
28
+ private schedulePosition;
29
+ private queueFlush;
30
+ private sync;
31
+ private mountDecoration;
32
+ private position;
33
+ private onPointerMove;
34
+ private onPointerLeave;
35
+ }
@@ -0,0 +1,8 @@
1
+ import type { Block, BlockSpec } from "../model/types";
2
+ import type { HtmlBlockCodec, HtmlParseCtx } from "./types";
3
+ type ParserFn = (el: HTMLElement, ctx: HtmlParseCtx) => BlockSpec | null;
4
+ type SerializerFn = (b: Block) => string;
5
+ export declare function registerHtmlBlockCodec(type: string, codec: HtmlBlockCodec): void;
6
+ export declare function getHtmlParserForTag(tag: string): ParserFn | null;
7
+ export declare function getHtmlSerializer(type: string): SerializerFn | null;
8
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { CommandCtx, KeymapDef } from "./types";
2
+ export declare function matchPluginKeymap(e: KeyboardEvent, entries: KeymapDef[], ctx: CommandCtx): KeymapDef | null;
@@ -0,0 +1,29 @@
1
+ import type { CommandCtx, CommandDef, DecorationDef, EditorPlugin, KeymapDef, TriggerDef } from "./types";
2
+ export declare class Registry {
3
+ readonly commands: Map<string, CommandDef<unknown>>;
4
+ readonly keymap: KeymapDef[];
5
+ readonly triggers: TriggerDef[];
6
+ readonly decorations: DecorationDef[];
7
+ readonly coalescePrefixes: Set<string>;
8
+ /** Set of all known block type discriminators (for fast existence checks). */
9
+ readonly knownBlockTypes: Set<string>;
10
+ install(plugin: EditorPlugin): void;
11
+ /**
12
+ * Look up a command by t and run it; returns false if the command is
13
+ * unknown OR if the command itself returned false (signaling "did not
14
+ * apply"). Used by both the editor dispatch path and the keymap matcher.
15
+ */
16
+ runCommand(t: string, payload: unknown, ctx: CommandCtx): boolean;
17
+ /** Should the given history tag coalesce with prior matching tags? */
18
+ shouldCoalesce(tag: string): boolean;
19
+ }
20
+ import type { PublicView } from "creo";
21
+ import type { Block } from "../model/types";
22
+ export declare function registerView(type: string, v: PublicView<{
23
+ block: Block;
24
+ key?: string;
25
+ }, void>): void;
26
+ export declare function getView(type: string): PublicView<{
27
+ block: Block;
28
+ key?: string;
29
+ }, void> | null;
@@ -0,0 +1,9 @@
1
+ import type { Anchor, Block } from "../model/types";
2
+ import type { RunsCtx } from "./types";
3
+ type RunsAtFn = (b: Block, a: Anchor) => RunsCtx | null;
4
+ export declare function registerRunsAt(type: string, fn: RunsAtFn): void;
5
+ export declare function runsAt(block: Block, anchor: Anchor): RunsCtx | null;
6
+ /** Total length of the runs container at `anchor` — convenience helper used
7
+ * by both text commands and the IME composition diff. */
8
+ export declare function runsLengthAt(block: Block, anchor: Anchor): number;
9
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { Block, BlockId, BlockSpec } from "../model/types";
2
+ import type { SerializeCodec } from "./types";
3
+ export declare function registerSerializeCodec(type: string, codec: SerializeCodec): void;
4
+ export declare function getSerializeCodec(type: string): SerializeCodec | null;
5
+ export declare function serializeBlock(b: Block): unknown | null;
6
+ export declare function deserializeBlock(type: string, s: unknown, id: BlockId): BlockSpec | null;
@@ -0,0 +1,33 @@
1
+ import type { Store } from "creo";
2
+ import type { DocState, Selection } from "../model/types";
3
+ import type { DispatchableCommand } from "../createEditor";
4
+ import type { Registry } from "./registry";
5
+ export type TriggerManagerOptions = {
6
+ registry: Registry;
7
+ docStore: Store<DocState>;
8
+ selStore: Store<Selection>;
9
+ dispatch: (cmd: DispatchableCommand) => void;
10
+ };
11
+ export declare class TriggerManager {
12
+ private opts;
13
+ private active;
14
+ private unsubSel;
15
+ private unsubDoc;
16
+ constructor(opts: TriggerManagerOptions);
17
+ destroy(): void;
18
+ /**
19
+ * Re-derive the active trigger's state from the current doc + selection.
20
+ * Closes the menu if any of:
21
+ * - caret left the trigger's block
22
+ * - caret moved before the trigger char position
23
+ * - the trigger char at the start position is no longer there
24
+ * Otherwise, recomputes the live query string and notifies the controller.
25
+ */
26
+ private reconcile;
27
+ /** Called by nativeInput AFTER a successful insertText dispatch. */
28
+ onTextInserted(text: string): void;
29
+ /** Called by nativeInput at the top of onKeyDown. Returns true if consumed. */
30
+ handleKeyDown(e: KeyboardEvent): boolean;
31
+ isActive(): boolean;
32
+ close(): void;
33
+ }