@inkami/blx 0.17.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.
Files changed (114) hide show
  1. package/README.md +98 -0
  2. package/dist/attributed-string/attributed-string.d.ts +37 -0
  3. package/dist/attributed-string/index.d.ts +2 -0
  4. package/dist/attributed-string/types.d.ts +13 -0
  5. package/dist/autocomplete/autocomplete-menu.d.ts +24 -0
  6. package/dist/autocomplete/index.d.ts +2 -0
  7. package/dist/autocomplete/types.d.ts +29 -0
  8. package/dist/blob-store/index.d.ts +32 -0
  9. package/dist/blob-store/types.d.ts +24 -0
  10. package/dist/block/block-controller.d.ts +205 -0
  11. package/dist/block/index.d.ts +2 -0
  12. package/dist/block/types.d.ts +15 -0
  13. package/dist/block-action-menu/block-action-menu.d.ts +62 -0
  14. package/dist/block-action-menu/index.d.ts +2 -0
  15. package/dist/block-context-menu/block-context-menu.d.ts +33 -0
  16. package/dist/block-context-menu/index.d.ts +2 -0
  17. package/dist/blx.js +16245 -0
  18. package/dist/blx.js.map +1 -0
  19. package/dist/caret/custom-caret.d.ts +30 -0
  20. package/dist/clipboard/clipboard-manager.d.ts +28 -0
  21. package/dist/clipboard/index.d.ts +2 -0
  22. package/dist/clipboard/paste-parser.d.ts +30 -0
  23. package/dist/commands/command-registry.d.ts +26 -0
  24. package/dist/commands/index.d.ts +2 -0
  25. package/dist/crdt/automerge-sync.d.ts +157 -0
  26. package/dist/crdt/crdt-log.d.ts +57 -0
  27. package/dist/crdt/index.d.ts +8 -0
  28. package/dist/crdt/remote-cursor-renderer.d.ts +28 -0
  29. package/dist/crdt/replay-ui.d.ts +34 -0
  30. package/dist/crdt/types.d.ts +47 -0
  31. package/dist/date-picker/agenda-utils.d.ts +37 -0
  32. package/dist/date-picker/date-parser.d.ts +25 -0
  33. package/dist/date-picker/date-picker.d.ts +115 -0
  34. package/dist/date-picker/index.d.ts +6 -0
  35. package/dist/drag-handle/drag-handle.d.ts +105 -0
  36. package/dist/drag-handle/index.d.ts +1 -0
  37. package/dist/editor.d.ts +864 -0
  38. package/dist/emoji-picker/emoji-data.d.ts +22 -0
  39. package/dist/emoji-picker/emoji-picker.d.ts +43 -0
  40. package/dist/emoji-picker/index.d.ts +3 -0
  41. package/dist/event-bus/event-bus.d.ts +14 -0
  42. package/dist/event-bus/index.d.ts +2 -0
  43. package/dist/event-bus/types.d.ts +320 -0
  44. package/dist/fold/fold-manager.d.ts +27 -0
  45. package/dist/fold/index.d.ts +2 -0
  46. package/dist/grapheme.d.ts +28 -0
  47. package/dist/index.d.ts +62 -0
  48. package/dist/inline-toolbar/highlight-picker.d.ts +41 -0
  49. package/dist/inline-toolbar/index.d.ts +5 -0
  50. package/dist/inline-toolbar/inline-toolbar.d.ts +97 -0
  51. package/dist/inline-toolbar/link-popover.d.ts +24 -0
  52. package/dist/keybindings/defaults.d.ts +2 -0
  53. package/dist/keybindings/index.d.ts +4 -0
  54. package/dist/keybindings/key-matcher.d.ts +41 -0
  55. package/dist/keybindings/types.d.ts +6 -0
  56. package/dist/keybindings/vim.d.ts +2 -0
  57. package/dist/markdown/block-shortcuts.d.ts +35 -0
  58. package/dist/markdown/emoticon-substitutions.d.ts +22 -0
  59. package/dist/markdown/export.d.ts +5 -0
  60. package/dist/markdown/index.d.ts +4 -0
  61. package/dist/markdown/inline-shortcuts.d.ts +13 -0
  62. package/dist/markdown/types.d.ts +29 -0
  63. package/dist/plugins/blockquote.d.ts +6 -0
  64. package/dist/plugins/checklist.d.ts +18 -0
  65. package/dist/plugins/code.d.ts +50 -0
  66. package/dist/plugins/excalidraw.d.ts +26 -0
  67. package/dist/plugins/heading.d.ts +20 -0
  68. package/dist/plugins/horizontal-rule.d.ts +5 -0
  69. package/dist/plugins/image.d.ts +19 -0
  70. package/dist/plugins/index.d.ts +28 -0
  71. package/dist/plugins/list.d.ts +18 -0
  72. package/dist/plugins/mermaid.d.ts +11 -0
  73. package/dist/plugins/paragraph.d.ts +18 -0
  74. package/dist/plugins/prism-loader.d.ts +16 -0
  75. package/dist/plugins/render-utils.d.ts +43 -0
  76. package/dist/plugins/table.d.ts +22 -0
  77. package/dist/plugins/youtube.d.ts +21 -0
  78. package/dist/schema/index.d.ts +2 -0
  79. package/dist/schema/schema-registry.d.ts +35 -0
  80. package/dist/schema/types.d.ts +67 -0
  81. package/dist/search/index.d.ts +4 -0
  82. package/dist/search/search-engine.d.ts +39 -0
  83. package/dist/search/search-ui.d.ts +59 -0
  84. package/dist/selection/index.d.ts +3 -0
  85. package/dist/selection/selection-manager.d.ts +41 -0
  86. package/dist/selection/types.d.ts +20 -0
  87. package/dist/slash-menu/index.d.ts +2 -0
  88. package/dist/slash-menu/slash-menu.d.ts +27 -0
  89. package/dist/table-of-contents/index.d.ts +1 -0
  90. package/dist/table-of-contents/table-of-contents.d.ts +74 -0
  91. package/dist/transaction/index.d.ts +2 -0
  92. package/dist/transaction/transaction.d.ts +29 -0
  93. package/dist/transaction/types.d.ts +40 -0
  94. package/dist/types.d.ts +21 -0
  95. package/dist/ui/context-menu.d.ts +103 -0
  96. package/dist/ui/dismiss.d.ts +33 -0
  97. package/dist/ui/dropdown.d.ts +81 -0
  98. package/dist/ui/floating-scroll-manager.d.ts +50 -0
  99. package/dist/ui/index.d.ts +18 -0
  100. package/dist/ui/modal.d.ts +109 -0
  101. package/dist/ui/popover.d.ts +59 -0
  102. package/dist/ui/position-fixed.d.ts +35 -0
  103. package/dist/ui/toast.d.ts +60 -0
  104. package/dist/ui/tooltip.d.ts +64 -0
  105. package/dist/undo/index.d.ts +5 -0
  106. package/dist/undo/jump-list.d.ts +37 -0
  107. package/dist/undo/types.d.ts +49 -0
  108. package/dist/undo/undo-manager.d.ts +47 -0
  109. package/dist/util/icons.d.ts +13 -0
  110. package/dist/util/id.d.ts +10 -0
  111. package/dist/viewport/block-viewport.d.ts +106 -0
  112. package/dist/viewport/index.d.ts +2 -0
  113. package/package.json +66 -0
  114. package/style.css +4670 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Small floating input for entering/editing link URLs.
3
+ * Displayed below the inline toolbar or selection.
4
+ */
5
+ export declare class LinkPopover {
6
+ private popover;
7
+ private input;
8
+ private applyBtn;
9
+ private removeBtn;
10
+ private onApply;
11
+ private onRemove;
12
+ private onClose;
13
+ constructor(onApply: (url: string) => void, onRemove: () => void, onClose: () => void);
14
+ get element(): HTMLElement;
15
+ get visible(): boolean;
16
+ /**
17
+ * Show the popover at a position relative to a given rect.
18
+ * Pre-fills the URL if editing an existing link.
19
+ */
20
+ show(anchorRect: DOMRect, existingUrl?: string): void;
21
+ hide(): void;
22
+ destroy(): void;
23
+ private submit;
24
+ }
@@ -0,0 +1,2 @@
1
+ import type { KeybindingMap } from "./types";
2
+ export declare const DEFAULT_KEYBINDINGS: KeybindingMap;
@@ -0,0 +1,4 @@
1
+ export type { KeyDescriptor, KeybindingMap } from "./types";
2
+ export { eventToDescriptor, KeySequencer } from "./key-matcher";
3
+ export { DEFAULT_KEYBINDINGS } from "./defaults";
4
+ export { VIM_KEYBINDINGS } from "./vim";
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Convert a KeyboardEvent into a canonical descriptor string.
3
+ *
4
+ * Modifiers are prepended in order: ctrl+meta+alt+shift+key
5
+ *
6
+ * For single-char keys (e.key.length === 1): shift is implicit in the
7
+ * character casing ("G" not "shift+G"), so shift is not prepended.
8
+ *
9
+ * For non-char keys (ArrowDown, Home, Tab, etc.): shift is included
10
+ * when held.
11
+ */
12
+ export declare function eventToDescriptor(e: KeyboardEvent): string;
13
+ /**
14
+ * Handles multi-key sequences of arbitrary length (e.g. "g,g", "d,d",
15
+ * " ,g,a") and single-key lookups against a keybinding map.
16
+ *
17
+ * `resolve()` returns:
18
+ * - An action name string when matched
19
+ * - `"pending"` when waiting for the next key in a sequence
20
+ * - `null` when no match is found
21
+ *
22
+ * When an accumulated buffer has both an exact match AND is the prefix of
23
+ * a longer sequence, the sequencer returns "pending" and waits. If the
24
+ * timeout fires before the next key, the `onFallback` callback is invoked
25
+ * with the shorter match's action name.
26
+ */
27
+ export declare class KeySequencer {
28
+ private buffer;
29
+ private timer;
30
+ private sequenceTimeout;
31
+ /**
32
+ * Resolve a key descriptor against a binding map.
33
+ *
34
+ * @param onFallback — called when a pending sequence times out and had
35
+ * a shorter exact action. The caller should execute the action.
36
+ */
37
+ resolve(descriptor: string, bindings: Record<string, string>, onFallback?: (action: string) => void): string | "pending" | null;
38
+ private clearTimer;
39
+ private clearPending;
40
+ destroy(): void;
41
+ }
@@ -0,0 +1,6 @@
1
+ /** Key descriptor string, e.g. "shift+ArrowDown", "j", "G", "g,g" (sequence) */
2
+ export type KeyDescriptor = string;
3
+ export interface KeybindingMap {
4
+ normal: Record<KeyDescriptor, string>;
5
+ visualBlock: Record<KeyDescriptor, string>;
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { KeybindingMap } from "./types";
2
+ export declare const VIM_KEYBINDINGS: KeybindingMap;
@@ -0,0 +1,35 @@
1
+ import type { BlockShortcutMatch } from "./types";
2
+ /**
3
+ * Match a block shortcut pattern without checking the trigger character.
4
+ *
5
+ * Matches:
6
+ * - `#` → h1, `##` → h2, `###` → h3, `####` → h4
7
+ * - `-`, `*`, `+` → unordered list
8
+ * - `1.`, `1)` → ordered list
9
+ * - `[a-zA-Z][.)]` → ordered list (lettered)
10
+ * - `` ``` `` or `` ```lang `` → code block
11
+ * - `---` → horizontal rule
12
+ * - `>` → blockquote
13
+ */
14
+ export declare function matchBlockShortcutPattern(prefix: string): BlockShortcutMatch | null;
15
+ /**
16
+ * Detect a block-level markdown shortcut being completed by a space.
17
+ *
18
+ * Called BEFORE the character is inserted. Fires when:
19
+ * - `charBeingTyped === " "`
20
+ * - The text before the cursor matches a block shortcut pattern
21
+ *
22
+ * Works both on empty blocks (cursor at end) and blocks with existing
23
+ * text (e.g. typing `# ` at the beginning of "Hello" → heading).
24
+ */
25
+ export declare function detectBlockShortcut(existingText: string, cursorOffset: number, charBeingTyped: string): BlockShortcutMatch | null;
26
+ /**
27
+ * Detect a block shortcut that fires immediately when the pattern is complete
28
+ * and unambiguous (no possible extensions exist).
29
+ *
30
+ * Currently only `---` → horizontal rule qualifies: no `----` pattern exists,
31
+ * so the third dash completes the pattern.
32
+ *
33
+ * Called BEFORE the character is inserted.
34
+ */
35
+ export declare function detectImmediateBlockShortcut(existingText: string, cursorOffset: number, charBeingTyped: string): BlockShortcutMatch | null;
@@ -0,0 +1,22 @@
1
+ /** Map of emoticon text patterns to their emoji replacements */
2
+ export declare const EMOTICON_MAP: Record<string, string>;
3
+ export interface EmoticonMatch {
4
+ /** The emoji character to insert */
5
+ emoji: string;
6
+ /** Start offset in existingText where the emoticon prefix begins */
7
+ start: number;
8
+ /** End offset in existingText (exclusive) — the cursor position */
9
+ end: number;
10
+ }
11
+ /**
12
+ * Detect an emoticon being completed by the character about to be typed.
13
+ *
14
+ * Called BEFORE the character is inserted into the content (same convention
15
+ * as `detectInlineShortcut`). Builds a candidate string from the last
16
+ * N characters of `existingText` (up to `cursorOffset`) plus `charBeingTyped`,
17
+ * then checks longest-first against the emoticon map.
18
+ *
19
+ * Safety: only triggers when the emoticon is preceded by whitespace or
20
+ * is at the start of text, to avoid false positives like `http:/`.
21
+ */
22
+ export declare function detectEmoticon(existingText: string, cursorOffset: number, charBeingTyped: string): EmoticonMatch | null;
@@ -0,0 +1,5 @@
1
+ import type { BlockJSON } from "../types";
2
+ /**
3
+ * Convert an array of editor blocks to a Markdown string.
4
+ */
5
+ export declare function blocksToMarkdown(blocks: BlockJSON[]): string;
@@ -0,0 +1,4 @@
1
+ export { detectInlineShortcut } from "./inline-shortcuts";
2
+ export { detectBlockShortcut } from "./block-shortcuts";
3
+ export { blocksToMarkdown } from "./export";
4
+ export type { InlineShortcutMatch, BlockShortcutMatch } from "./types";
@@ -0,0 +1,13 @@
1
+ import type { InlineShortcutMatch } from "./types";
2
+ /**
3
+ * Detect an inline markdown shortcut being completed.
4
+ *
5
+ * Called BEFORE the character is inserted into the content.
6
+ * Scans backward for a matching opening marker:
7
+ * - `charBeingTyped === "*"` + `existingText[cursorOffset-1] === "*"` → bold (`**`)
8
+ * - `charBeingTyped === "_"` → italic (`_`)
9
+ * - `charBeingTyped === "\`"` → code (`` ` ``)
10
+ *
11
+ * There must be at least 1 character between the markers.
12
+ */
13
+ export declare function detectInlineShortcut(existingText: string, cursorOffset: number, charBeingTyped: string): InlineShortcutMatch | null;
@@ -0,0 +1,29 @@
1
+ import type { Attributes } from "../attributed-string";
2
+ /** Result of detecting an inline markdown shortcut (bold, italic, code, link) */
3
+ export interface InlineShortcutMatch {
4
+ /** The kind of shortcut detected */
5
+ kind: "bold" | "italic" | "code" | "strikethrough" | "link";
6
+ /** The attribute(s) to apply to the matched content */
7
+ attribute: Attributes;
8
+ /** Offset into existingText where the opening marker starts */
9
+ openMarkerStart: number;
10
+ /** Offset into existingText where the opening marker ends (exclusive) */
11
+ openMarkerEnd: number;
12
+ /** Offset into existingText where the content starts */
13
+ contentStart: number;
14
+ /** Offset into existingText where the content ends (exclusive) */
15
+ contentEnd: number;
16
+ /** Offset into existingText where the close marker ends (exclusive, includes the char being typed) */
17
+ closeMarkerEnd: number;
18
+ }
19
+ /** Result of detecting a block-level markdown shortcut (heading, list) */
20
+ export interface BlockShortcutMatch {
21
+ /** The kind of shortcut detected */
22
+ kind: "heading" | "unordered-list" | "ordered-list" | "checklist" | "code-block" | "horizontal-rule" | "blockquote";
23
+ /** The new block type to convert to */
24
+ newType: string;
25
+ /** Metadata for the new block type */
26
+ metadata: Record<string, unknown>;
27
+ /** Length of the prefix (including the space being typed) */
28
+ prefixLength: number;
29
+ }
@@ -0,0 +1,6 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface BlockquoteMetadata {
3
+ [key: string]: unknown;
4
+ dir?: "ltr" | "rtl" | "auto";
5
+ }
6
+ export declare const blockquotePlugin: BlockTypePlugin<BlockquoteMetadata>;
@@ -0,0 +1,18 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface ChecklistMetadata {
3
+ [key: string]: unknown;
4
+ checked: boolean;
5
+ dueDate?: string;
6
+ scheduledDate?: string;
7
+ eventDate?: string;
8
+ recurrence?: {
9
+ interval: number;
10
+ unit: "day" | "week" | "month" | "year";
11
+ anchor?: string;
12
+ fromCompletion?: boolean;
13
+ };
14
+ /** @deprecated — migrated to dueDate/scheduledDate/eventDate by deserializeMetadata */
15
+ agendaDate?: string;
16
+ dir?: "ltr" | "rtl" | "auto";
17
+ }
18
+ export declare const checklistPlugin: BlockTypePlugin<ChecklistMetadata>;
@@ -0,0 +1,50 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface CodeBlockMetadata {
3
+ [key: string]: unknown;
4
+ language: string;
5
+ agendaDate?: string;
6
+ }
7
+ export declare const CODE_LANGUAGES: readonly [{
8
+ readonly id: "plain";
9
+ readonly label: "Plain Text";
10
+ }, {
11
+ readonly id: "json";
12
+ readonly label: "JSON";
13
+ }, {
14
+ readonly id: "javascript";
15
+ readonly label: "JavaScript";
16
+ }, {
17
+ readonly id: "typescript";
18
+ readonly label: "TypeScript";
19
+ }, {
20
+ readonly id: "html";
21
+ readonly label: "HTML";
22
+ }, {
23
+ readonly id: "css";
24
+ readonly label: "CSS";
25
+ }, {
26
+ readonly id: "python";
27
+ readonly label: "Python";
28
+ }, {
29
+ readonly id: "java";
30
+ readonly label: "Java";
31
+ }, {
32
+ readonly id: "c";
33
+ readonly label: "C";
34
+ }, {
35
+ readonly id: "cpp";
36
+ readonly label: "C++";
37
+ }, {
38
+ readonly id: "go";
39
+ readonly label: "Go";
40
+ }, {
41
+ readonly id: "rust";
42
+ readonly label: "Rust";
43
+ }, {
44
+ readonly id: "sql";
45
+ readonly label: "SQL";
46
+ }, {
47
+ readonly id: "yaml";
48
+ readonly label: "YAML";
49
+ }];
50
+ export declare const codeBlockPlugin: BlockTypePlugin<CodeBlockMetadata>;
@@ -0,0 +1,26 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface ExcalidrawMetadata {
3
+ [key: string]: unknown;
4
+ /** Serialized Excalidraw scene data (JSON string of { elements, appState }) */
5
+ sceneData: string;
6
+ /** Cached SVG string for preview rendering without loading Excalidraw */
7
+ previewSvg?: string;
8
+ /** Display width in pixels (null = auto) */
9
+ width?: number;
10
+ }
11
+ export declare const excalidrawPlugin: BlockTypePlugin<ExcalidrawMetadata>;
12
+ /**
13
+ * Re-render an Excalidraw scene to SVG with a specific theme.
14
+ * Returns null if excalidraw is not available or the scene is invalid.
15
+ */
16
+ export declare function renderExcalidrawSvg(sceneData: string, theme?: "light" | "dark"): Promise<string | null>;
17
+ /**
18
+ * Opens the Excalidraw editor in a fullscreen modal overlay.
19
+ * Dynamically imports react, react-dom, and @excalidraw/excalidraw.
20
+ *
21
+ * Returns a cleanup function. Calls `onSave` with the scene data and SVG
22
+ * preview when the user closes the modal.
23
+ */
24
+ export declare function openExcalidrawModal(sceneData: string | null, onSave: (sceneData: string, previewSvg: string) => void, onClose: () => void, options?: {
25
+ theme?: "light" | "dark";
26
+ }): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export type TaskStatus = "todo" | "in-progress" | "done";
3
+ export interface HeadingMetadata {
4
+ [key: string]: unknown;
5
+ level: 1 | 2 | 3 | 4;
6
+ taskStatus?: TaskStatus;
7
+ dueDate?: string;
8
+ scheduledDate?: string;
9
+ eventDate?: string;
10
+ recurrence?: {
11
+ interval: number;
12
+ unit: "day" | "week" | "month" | "year";
13
+ anchor?: string;
14
+ fromCompletion?: boolean;
15
+ };
16
+ /** @deprecated — migrated to dueDate/scheduledDate/eventDate by deserializeMetadata */
17
+ agendaDate?: string;
18
+ dir?: "ltr" | "rtl" | "auto";
19
+ }
20
+ export declare const headingPlugin: BlockTypePlugin<HeadingMetadata>;
@@ -0,0 +1,5 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface HorizontalRuleMetadata {
3
+ [key: string]: unknown;
4
+ }
5
+ export declare const horizontalRulePlugin: BlockTypePlugin<HorizontalRuleMetadata>;
@@ -0,0 +1,19 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface ImageMetadata {
3
+ [key: string]: unknown;
4
+ /** Image source URL, data: URI, or blob-store reference (`blxblob:…`) */
5
+ src: string;
6
+ /** Alt text for accessibility */
7
+ alt?: string;
8
+ /** Caption text */
9
+ caption?: string;
10
+ /** Display width in pixels (null = auto) */
11
+ width?: number;
12
+ /** Intrinsic image width, captured on first load. Used with naturalHeight
13
+ * to set width/height attributes so the browser reserves correct aspect
14
+ * ratio space before the image loads, preventing layout shift. */
15
+ naturalWidth?: number;
16
+ /** Intrinsic image height, captured on first load. */
17
+ naturalHeight?: number;
18
+ }
19
+ export declare const imagePlugin: BlockTypePlugin<ImageMetadata>;
@@ -0,0 +1,28 @@
1
+ import type { SchemaRegistry } from "../schema";
2
+ export { paragraphPlugin } from "./paragraph";
3
+ export { headingPlugin } from "./heading";
4
+ export { listPlugin } from "./list";
5
+ export { codeBlockPlugin, CODE_LANGUAGES } from "./code";
6
+ export { horizontalRulePlugin } from "./horizontal-rule";
7
+ export { checklistPlugin } from "./checklist";
8
+ export { youtubePlugin, parseYouTubeUrl } from "./youtube";
9
+ export { imagePlugin } from "./image";
10
+ export { tablePlugin } from "./table";
11
+ export { blockquotePlugin } from "./blockquote";
12
+ export { mermaidPlugin, renderMermaidSvg } from "./mermaid";
13
+ export { excalidrawPlugin, openExcalidrawModal, renderExcalidrawSvg } from "./excalidraw";
14
+ export { renderAttributedString, setUrlResolver, resolveUrl, getBlockDir, setBlockRefRenderCallback } from "./render-utils";
15
+ export type { ParagraphMetadata } from "./paragraph";
16
+ export type { HeadingMetadata, TaskStatus } from "./heading";
17
+ export type { ListMetadata } from "./list";
18
+ export type { CodeBlockMetadata } from "./code";
19
+ export type { HorizontalRuleMetadata } from "./horizontal-rule";
20
+ export type { ChecklistMetadata } from "./checklist";
21
+ export type { YouTubeMetadata } from "./youtube";
22
+ export type { ImageMetadata } from "./image";
23
+ export type { TableMetadata } from "./table";
24
+ export type { BlockquoteMetadata } from "./blockquote";
25
+ export type { MermaidMetadata } from "./mermaid";
26
+ export type { ExcalidrawMetadata } from "./excalidraw";
27
+ /** Register the default set of block type plugins */
28
+ export declare function registerDefaultPlugins(registry: SchemaRegistry): void;
@@ -0,0 +1,18 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface ListMetadata {
3
+ [key: string]: unknown;
4
+ ordered: boolean;
5
+ dueDate?: string;
6
+ scheduledDate?: string;
7
+ eventDate?: string;
8
+ recurrence?: {
9
+ interval: number;
10
+ unit: "day" | "week" | "month" | "year";
11
+ anchor?: string;
12
+ fromCompletion?: boolean;
13
+ };
14
+ /** @deprecated — migrated to dueDate/scheduledDate/eventDate by deserializeMetadata */
15
+ agendaDate?: string;
16
+ dir?: "ltr" | "rtl" | "auto";
17
+ }
18
+ export declare const listPlugin: BlockTypePlugin<ListMetadata>;
@@ -0,0 +1,11 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface MermaidMetadata {
3
+ [key: string]: unknown;
4
+ }
5
+ /**
6
+ * Render mermaid source to an SVG string with a specific theme.
7
+ * Returns null if mermaid is not available or the source has invalid syntax.
8
+ * Serialized through the render queue to avoid mermaid concurrency issues.
9
+ */
10
+ export declare function renderMermaidSvg(source: string, theme?: "light" | "dark"): Promise<string | null>;
11
+ export declare const mermaidPlugin: BlockTypePlugin<MermaidMetadata>;
@@ -0,0 +1,18 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface ParagraphMetadata {
3
+ [key: string]: unknown;
4
+ align?: "left" | "center" | "right" | "start" | "end";
5
+ dueDate?: string;
6
+ scheduledDate?: string;
7
+ eventDate?: string;
8
+ recurrence?: {
9
+ interval: number;
10
+ unit: "day" | "week" | "month" | "year";
11
+ anchor?: string;
12
+ fromCompletion?: boolean;
13
+ };
14
+ /** @deprecated — migrated to dueDate/scheduledDate/eventDate by deserializeMetadata */
15
+ agendaDate?: string;
16
+ dir?: "ltr" | "rtl" | "auto";
17
+ }
18
+ export declare const paragraphPlugin: BlockTypePlugin<ParagraphMetadata>;
@@ -0,0 +1,16 @@
1
+ import Prism from "prismjs";
2
+ import "prismjs/components/prism-markup";
3
+ import "prismjs/components/prism-css";
4
+ import "prismjs/components/prism-clike";
5
+ import "prismjs/components/prism-javascript";
6
+ import "prismjs/components/prism-typescript";
7
+ import "prismjs/components/prism-python";
8
+ import "prismjs/components/prism-java";
9
+ import "prismjs/components/prism-c";
10
+ import "prismjs/components/prism-cpp";
11
+ import "prismjs/components/prism-go";
12
+ import "prismjs/components/prism-rust";
13
+ import "prismjs/components/prism-sql";
14
+ import "prismjs/components/prism-yaml";
15
+ import "prismjs/components/prism-json";
16
+ export { Prism };
@@ -0,0 +1,43 @@
1
+ import type { AttributedString } from "../attributed-string";
2
+ /**
3
+ * Override the URL resolver used when rendering link elements.
4
+ * The resolver receives the raw `href` string from the content model
5
+ * and should return a fully-qualified URL for the `<a>` element.
6
+ *
7
+ * Pass `undefined` to reset to the default resolver.
8
+ */
9
+ export declare function setUrlResolver(resolver: ((url: string) => string) | undefined): void;
10
+ /** Resolve a URL using the configured resolver. */
11
+ export declare function resolveUrl(url: string): string;
12
+ /**
13
+ * Set a callback that is invoked after each blockRef span is rendered.
14
+ * Use it to add CSS classes or data attributes for app-specific styling
15
+ * (e.g. broken-link indicators).
16
+ *
17
+ * Pass `undefined` to clear the callback.
18
+ */
19
+ export declare function setBlockRefRenderCallback(cb: ((element: HTMLElement, refId: string) => void) | undefined): void;
20
+ /**
21
+ * Returns the `dir` attribute value for a block's contenteditable element.
22
+ * Defaults to "auto" which lets the browser's Unicode Bidi Algorithm detect
23
+ * text direction from the first strong character.
24
+ */
25
+ export declare function getBlockDir(metadata: Record<string, unknown>): string;
26
+ /**
27
+ * Toggle the empty state class and placeholder attribute on an element.
28
+ * When the content is empty, adds `blx-empty` class and sets `data-placeholder`.
29
+ * When non-empty, removes both.
30
+ */
31
+ export declare function updateEmptyState(el: HTMLElement, content: AttributedString, placeholder?: string): void;
32
+ /**
33
+ * Check whether the block is rendered inside a read-only context.
34
+ * Returns true when the nearest editor root (or any ancestor) has the
35
+ * `.blx-readonly` or `.blx-replay-mode` CSS class.
36
+ */
37
+ export declare function isBlockReadOnly(container: HTMLElement): boolean;
38
+ /**
39
+ * Render an AttributedString into a target element.
40
+ * Clears existing content and creates inline spans for each attributed span.
41
+ * Emoji characters render natively via the platform's emoji font.
42
+ */
43
+ export declare function renderAttributedString(target: HTMLElement, content: AttributedString): void;
@@ -0,0 +1,22 @@
1
+ import { AttributedString } from "../attributed-string";
2
+ import type { BlockTypePlugin } from "../schema";
3
+ export interface TableMetadata {
4
+ [key: string]: unknown;
5
+ /** Header row cells (one AttributedString per column) */
6
+ header: AttributedString[];
7
+ /** Body rows (each row is one AttributedString per column) */
8
+ rows: AttributedString[][];
9
+ /** Column alignments: "left" | "center" | "right" | "none" */
10
+ columnAlignments?: string[];
11
+ /** Column widths as percentages */
12
+ columnWidths?: number[];
13
+ }
14
+ /** Unified selection state for the table */
15
+ export interface TableSelection {
16
+ type: "rect" | "row" | "col";
17
+ anchorRow: number;
18
+ anchorCol: number;
19
+ focusRow: number;
20
+ focusCol: number;
21
+ }
22
+ export declare const tablePlugin: BlockTypePlugin<TableMetadata>;
@@ -0,0 +1,21 @@
1
+ import type { BlockTypePlugin } from "../schema";
2
+ export interface YouTubeMetadata {
3
+ [key: string]: unknown;
4
+ videoId: string;
5
+ startTime?: number;
6
+ }
7
+ /**
8
+ * Extract a YouTube video ID from various URL formats:
9
+ * - https://www.youtube.com/watch?v=VIDEO_ID
10
+ * - https://youtu.be/VIDEO_ID
11
+ * - https://www.youtube.com/embed/VIDEO_ID
12
+ * - https://youtube.com/shorts/VIDEO_ID
13
+ * - https://www.youtube-nocookie.com/embed/VIDEO_ID
14
+ *
15
+ * Returns `{ videoId, startTime? }` or `null` if no match.
16
+ */
17
+ export declare function parseYouTubeUrl(raw: string): {
18
+ videoId: string;
19
+ startTime?: number;
20
+ } | null;
21
+ export declare const youtubePlugin: BlockTypePlugin<YouTubeMetadata>;
@@ -0,0 +1,2 @@
1
+ export { SchemaRegistry } from "./schema-registry";
2
+ export type { BlockTypePlugin, BlockMetadata, ConversionTarget } from "./types";
@@ -0,0 +1,35 @@
1
+ import type { BlockTypePlugin, BlockMetadata, ConversionTarget } from "./types";
2
+ import type { BlockJSON } from "../types";
3
+ /**
4
+ * Registry for block type plugins.
5
+ */
6
+ export declare class SchemaRegistry {
7
+ private plugins;
8
+ private aliases;
9
+ register(plugin: BlockTypePlugin<BlockMetadata>): void;
10
+ unregister(type: string): boolean;
11
+ /**
12
+ * Register an alias so that old/renamed block types resolve to a current plugin.
13
+ * When blocks are loaded with `oldType`, they will be treated as `newType`.
14
+ */
15
+ registerAlias(oldType: string, newType: string): void;
16
+ get(type: string): BlockTypePlugin | undefined;
17
+ has(type: string): boolean;
18
+ /**
19
+ * Resolve a block type through aliases. Returns the canonical type name.
20
+ */
21
+ resolveType(type: string): string;
22
+ /**
23
+ * Migrate an array of block JSON objects, rewriting any aliased types
24
+ * to their canonical names. Returns true if any blocks were modified.
25
+ */
26
+ migrateBlocks(blocks: BlockJSON[]): boolean;
27
+ getAll(): ReadonlyArray<BlockTypePlugin>;
28
+ getTypes(): ReadonlyArray<string>;
29
+ /**
30
+ * Get the conversion targets for a given block type.
31
+ * If the plugin defines `convertibleTo()`, use that.
32
+ * Otherwise, build a default list from all registered text-content plugins.
33
+ */
34
+ getConversionTargets(type: string): ConversionTarget[];
35
+ }
@@ -0,0 +1,67 @@
1
+ import type { AttributedString } from "../attributed-string";
2
+ /** Metadata can be any serializable record */
3
+ export interface BlockMetadata {
4
+ [key: string]: unknown;
5
+ }
6
+ /** Describes a block type that this block can be converted to */
7
+ export interface ConversionTarget {
8
+ /** Target block type */
9
+ type: string;
10
+ /** Display label (e.g. "Heading 2") */
11
+ label: string;
12
+ /** Description shown in Turn Into menu */
13
+ description?: string;
14
+ /** Metadata for the target block type */
15
+ metadata?: Record<string, unknown>;
16
+ /** Keyboard shortcut hint (e.g. "Ctrl+Shift+2") */
17
+ shortcutHint?: string;
18
+ }
19
+ /**
20
+ * Plugin that defines how a block type behaves and renders.
21
+ */
22
+ export interface BlockTypePlugin<M extends BlockMetadata = BlockMetadata> {
23
+ /** Unique type identifier, e.g. "paragraph", "heading" */
24
+ readonly type: string;
25
+ /** Human-readable label */
26
+ readonly label: string;
27
+ /** Whether this block type has editable text content */
28
+ readonly hasTextContent: boolean;
29
+ /** Create default content for a new block of this type */
30
+ defaultContent(): AttributedString;
31
+ /** Create default metadata for a new block of this type */
32
+ defaultMetadata(): M;
33
+ /**
34
+ * Render the block into the container.
35
+ * Returns the contenteditable element (if hasTextContent), or null.
36
+ */
37
+ render(container: HTMLElement, content: AttributedString, metadata: M): HTMLElement | null;
38
+ /**
39
+ * Update an existing render without full re-render (optional optimization).
40
+ */
41
+ update?(container: HTMLElement, contentEditable: HTMLElement | null, content: AttributedString, metadata: M): void;
42
+ /** Serialize metadata to JSON-safe form */
43
+ serializeMetadata?(metadata: M): Record<string, unknown>;
44
+ /** Deserialize metadata from JSON */
45
+ deserializeMetadata?(raw: Record<string, unknown>): M;
46
+ /** Attribute keys allowed for this block type. null = all allowed. */
47
+ allowedAttributes?: string[] | null;
48
+ /** If true, block cannot be moved, deleted, or reordered. */
49
+ immovable?: boolean;
50
+ /** If true, block cannot be converted to another type. */
51
+ inconvertible?: boolean;
52
+ /** Whether this block type supports nesting via indent/outdent (Tab/Shift+Tab). Defaults to true. */
53
+ indentable?: boolean;
54
+ /** Whether Tab inserts literal spaces instead of indenting (e.g. code blocks). Only applies when indentable is false. */
55
+ tabInsertsSpaces?: boolean;
56
+ /**
57
+ * What block types this block can be converted to.
58
+ * Return an empty array to prevent conversion.
59
+ * If not defined, the schema registry builds a default list from all text-content plugins.
60
+ */
61
+ convertibleTo?(): ConversionTarget[];
62
+ /**
63
+ * Build metadata when converting TO this type from another.
64
+ * Falls back to defaultMetadata() if not defined.
65
+ */
66
+ metadataFromConversion?(fromType: string, fromMetadata: BlockMetadata): M;
67
+ }