@blankdotpage/cake 0.1.2 → 0.1.3

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.
@@ -10,6 +10,7 @@ export type OverlayExtensionContext = {
10
10
  start: number;
11
11
  end: number;
12
12
  } | null;
13
+ executeCommand: (command: EditCommand) => boolean;
13
14
  contentRoot?: HTMLElement;
14
15
  overlayRoot?: HTMLElement;
15
16
  toOverlayRect?: (rect: DOMRectReadOnly) => {
@@ -37,33 +38,46 @@ export type SerializeInlineResult = {
37
38
  source: string;
38
39
  map: CursorSourceMap;
39
40
  };
40
- export type EditCommand = {
41
+ /** Insert command */
42
+ export type InsertCommand = {
41
43
  type: "insert";
42
44
  text: string;
43
- } | {
45
+ };
46
+ /** Commands that can be applied directly by the engine */
47
+ export type ApplyEditCommand = InsertCommand | {
44
48
  type: "insert-line-break";
45
- } | {
46
- type: "exit-block-wrapper";
47
49
  } | {
48
50
  type: "delete-backward";
49
51
  } | {
50
52
  type: "delete-forward";
51
- } | {
53
+ };
54
+ /** Structural edit commands that modify document structure */
55
+ export type StructuralEditCommand = ApplyEditCommand | {
56
+ type: "exit-block-wrapper";
57
+ };
58
+ /** Core edit commands handled by the runtime */
59
+ export type CoreEditCommand = StructuralEditCommand | {
52
60
  type: "indent";
53
61
  } | {
54
62
  type: "outdent";
55
- } | {
56
- type: "toggle-bullet-list";
57
- } | {
58
- type: "toggle-numbered-list";
59
63
  } | {
60
64
  type: "toggle-inline";
61
65
  marker: string;
62
- } | {
63
- type: "wrap-link";
64
- url?: string;
65
- openPopover?: boolean;
66
66
  };
67
+ /** Base type for extension-defined commands */
68
+ export type ExtensionCommand = {
69
+ type: string;
70
+ [key: string]: any;
71
+ };
72
+ /**
73
+ * Edit commands can be core commands or extension-defined commands.
74
+ * Extensions handle their own commands in onEdit before the core processes them.
75
+ */
76
+ export type EditCommand = CoreEditCommand | ExtensionCommand;
77
+ /** Type guard to check if a command is a structural edit */
78
+ export declare function isStructuralEdit(command: EditCommand): command is StructuralEditCommand;
79
+ /** Type guard to check if a command can be applied directly by the engine */
80
+ export declare function isApplyEditCommand(command: EditCommand): command is ApplyEditCommand;
67
81
  export type EditResult = {
68
82
  source: string;
69
83
  selection: Selection;
@@ -114,6 +128,29 @@ export type CakeExtension = {
114
128
  renderBlock?: (block: Block, context: DomRenderContext) => Node | Node[] | null;
115
129
  renderOverlay?: (context: OverlayExtensionContext) => ReactElement | null;
116
130
  };
131
+ /**
132
+ * Extension config with typed custom commands.
133
+ */
134
+ export type ExtensionConfig<TCommand extends ExtensionCommand> = Omit<CakeExtension, "onEdit"> & {
135
+ onEdit?: (command: EditCommand | TCommand, state: RuntimeState) => EditResult | EditCommand | TCommand | null;
136
+ };
137
+ /**
138
+ * Define an extension with typed custom commands.
139
+ *
140
+ * @example
141
+ * type MyCommand = { type: "my-command"; value: number };
142
+ * export const myExtension = defineExtension<MyCommand>({
143
+ * name: "my-extension",
144
+ * onEdit(command, state) {
145
+ * if (command.type === "my-command") {
146
+ * // command is narrowed to MyCommand here
147
+ * console.log(command.value);
148
+ * }
149
+ * return null;
150
+ * },
151
+ * });
152
+ */
153
+ export declare function defineExtension<TCommand extends ExtensionCommand>(extension: ExtensionConfig<TCommand>): CakeExtension;
117
154
  export type RuntimeState = {
118
155
  source: string;
119
156
  selection: Selection;
@@ -11,6 +11,14 @@ type EngineOptions = {
11
11
  readOnly?: boolean;
12
12
  spellCheckEnabled?: boolean;
13
13
  };
14
+ export type RenderPerf = {
15
+ totalMs: number;
16
+ renderAndMapMs: number;
17
+ applySelectionMs: number;
18
+ didUpdateDom: boolean;
19
+ blockCount: number;
20
+ runCount: number;
21
+ };
14
22
  export declare class CakeEngine {
15
23
  private container;
16
24
  private runtime;
@@ -40,6 +48,8 @@ export declare class CakeEngine {
40
48
  private caretBlinkTimeoutId;
41
49
  private overlayUpdateId;
42
50
  private scrollCaretIntoViewId;
51
+ private selectionRectElements;
52
+ private lastSelectionRects;
43
53
  private onChange?;
44
54
  private onSelectionChange?;
45
55
  private readOnly;
@@ -48,8 +58,10 @@ export declare class CakeEngine {
48
58
  private placeholderRoot;
49
59
  private lastFocusRect;
50
60
  private verticalNavGoalX;
61
+ private lastRenderPerf;
51
62
  private history;
52
63
  private pendingClickHit;
64
+ getLastRenderPerf(): RenderPerf | null;
53
65
  private isEventTargetInContentRoot;
54
66
  private handleBeforeInputBound;
55
67
  private handleInputBound;
@@ -82,6 +94,7 @@ export declare class CakeEngine {
82
94
  setSpellCheckEnabled(enabled: boolean): void;
83
95
  getValue(): string;
84
96
  getSelection(): Selection;
97
+ getCursorLength(): number;
85
98
  getFocusRect(): SelectionRect | null;
86
99
  getContainer(): HTMLElement;
87
100
  getContentRoot(): HTMLElement | null;
@@ -179,6 +192,7 @@ export declare class CakeEngine {
179
192
  private scheduleOverlayUpdate;
180
193
  private flushOverlayUpdate;
181
194
  private ensureOverlayRoot;
195
+ private selectionRectsEqual;
182
196
  private ensureExtensionsRoot;
183
197
  private updateExtensionsOverlayPosition;
184
198
  private updateSelectionOverlay;
@@ -17,6 +17,13 @@ export declare function measureLayoutModelFromDom(params: {
17
17
  root: HTMLElement;
18
18
  container: HTMLElement;
19
19
  }): LayoutModel | null;
20
+ export declare function measureLayoutModelRangeFromDom(params: {
21
+ lines: LineInfo[];
22
+ root: HTMLElement;
23
+ container: HTMLElement;
24
+ startLineIndex: number;
25
+ endLineIndex: number;
26
+ }): LayoutModel | null;
20
27
  export declare function getLineElement(root: HTMLElement, lineIndex: number): HTMLElement | null;
21
28
  export declare function resolveDomPosition(lineElement: HTMLElement, offsetInLine: number): {
22
29
  node: Node;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const blockquoteExtension: CakeExtension;
1
+ export declare const blockquoteExtension: import("../../..").CakeExtension;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const boldExtension: CakeExtension;
1
+ export declare const boldExtension: import("../../..").CakeExtension;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const combinedEmphasisExtension: CakeExtension;
1
+ export declare const combinedEmphasisExtension: import("../../..").CakeExtension;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const headingExtension: CakeExtension;
1
+ export declare const headingExtension: import("../../..").CakeExtension;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const imageExtension: CakeExtension;
1
+ export declare const imageExtension: import("../../..").CakeExtension;
@@ -10,4 +10,5 @@ import { listExtension } from "./list/list";
10
10
  import { scrollbarExtension } from "./scrollbar";
11
11
  import { strikethroughExtension } from "./strikethrough/strikethrough";
12
12
  export { boldExtension, combinedEmphasisExtension, linkExtension, pipeLinkExtension, blockquoteExtension, italicExtension, headingExtension, imageExtension, listExtension, scrollbarExtension, strikethroughExtension, };
13
+ export declare const bundledExtensionsWithoutImage: import("../..").CakeExtension[];
13
14
  export declare const bundledExtensions: import("../..").CakeExtension[];
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const italicExtension: CakeExtension;
1
+ export declare const italicExtension: import("../../..").CakeExtension;
@@ -1,3 +1,4 @@
1
+ import type { EditCommand } from "../../core/runtime";
1
2
  export declare function CakeLinkPopover(params: {
2
3
  container: HTMLElement;
3
4
  contentRoot: HTMLElement;
@@ -7,4 +8,9 @@ export declare function CakeLinkPopover(params: {
7
8
  width: number;
8
9
  height: number;
9
10
  };
11
+ getSelection: () => {
12
+ start: number;
13
+ end: number;
14
+ } | null;
15
+ executeCommand: (command: EditCommand) => boolean;
10
16
  }): import("react/jsx-runtime").JSX.Element | null;
@@ -1,2 +1,15 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const linkExtension: CakeExtension;
1
+ /** Command to wrap selected text in a link */
2
+ export type WrapLinkCommand = {
3
+ type: "wrap-link";
4
+ url?: string;
5
+ openPopover?: boolean;
6
+ };
7
+ /** Command to remove link formatting */
8
+ export type UnlinkCommand = {
9
+ type: "unlink";
10
+ start: number;
11
+ end: number;
12
+ };
13
+ /** All link extension commands */
14
+ export type LinkCommand = WrapLinkCommand | UnlinkCommand;
15
+ export declare const linkExtension: import("../../..").CakeExtension;
@@ -1,2 +1,11 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const listExtension: CakeExtension;
1
+ /** Command to toggle bullet list formatting */
2
+ export type ToggleBulletListCommand = {
3
+ type: "toggle-bullet-list";
4
+ };
5
+ /** Command to toggle numbered list formatting */
6
+ export type ToggleNumberedListCommand = {
7
+ type: "toggle-numbered-list";
8
+ };
9
+ /** All list extension commands */
10
+ export type ListCommand = ToggleBulletListCommand | ToggleNumberedListCommand;
11
+ export declare const listExtension: import("../../..").CakeExtension;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const pipeLinkExtension: CakeExtension;
1
+ export declare const pipeLinkExtension: import("../../..").CakeExtension;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const scrollbarExtension: CakeExtension;
1
+ export declare const scrollbarExtension: import("../../..").CakeExtension;
@@ -1,2 +1 @@
1
- import type { CakeExtension } from "../../core/runtime";
2
- export declare const strikethroughExtension: CakeExtension;
1
+ export declare const strikethroughExtension: import("../../..").CakeExtension;
@@ -22,6 +22,7 @@ export interface CakeEditorProps {
22
22
  style?: React.CSSProperties;
23
23
  extensions?: CakeExtension[];
24
24
  onBlur?: (event?: FocusEvent) => void;
25
+ disableImageExtension?: boolean;
25
26
  }
26
27
  export interface CakeEditorRef {
27
28
  element: HTMLElement | null;
@@ -36,6 +37,7 @@ export interface CakeEditorRef {
36
37
  start: number;
37
38
  end: number;
38
39
  } | null;
40
+ getCursorLength: () => number;
39
41
  insertText: (text: string) => void;
40
42
  replaceText: (oldText: string, newText: string) => void;
41
43
  }
@@ -12,6 +12,14 @@ export interface CaretInfo {
12
12
  left: number;
13
13
  height: number;
14
14
  }
15
+ export interface VisualRowInfo {
16
+ startOffset: number;
17
+ endOffset: number;
18
+ top: number;
19
+ bottom: number;
20
+ left: number;
21
+ right: number;
22
+ }
15
23
  export interface TestHarness {
16
24
  container: HTMLDivElement;
17
25
  contentRoot: HTMLElement;
@@ -24,6 +32,7 @@ export interface TestHarness {
24
32
  getCharRect(offset: number, lineIndex?: number): DOMRect;
25
33
  getSelectionRects(): SelectionRectInfo[];
26
34
  getCaretRect(): CaretInfo | null;
35
+ getVisualRows(lineIndex?: number): VisualRowInfo[];
27
36
  clickLeftOf(offset: number, lineIndex?: number): Promise<void>;
28
37
  clickRightOf(offset: number, lineIndex?: number): Promise<void>;
29
38
  clickAt(offset: number, lineIndex?: number): Promise<void>;
@@ -42,6 +51,9 @@ export interface TestHarness {
42
51
  alt?: boolean;
43
52
  }): Promise<void>;
44
53
  focus(): Promise<void>;
54
+ assertCaretOnVisualRow(rowIndex: number, lineIndex?: number): void;
55
+ assertCaretAtEndOfVisualRow(rowIndex: number, lineIndex?: number): void;
56
+ assertCaretAtStartOfVisualRow(rowIndex: number, lineIndex?: number): void;
45
57
  destroy(): void;
46
58
  }
47
59
  export interface TestHarnessOptions {