@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,4 @@
1
+ export { SearchEngine } from "./search-engine";
2
+ export type { SearchMatch, SearchOptions, ReplaceResult } from "./search-engine";
3
+ export { SearchUI } from "./search-ui";
4
+ export type { SearchUICallbacks } from "./search-ui";
@@ -0,0 +1,39 @@
1
+ import type { Block } from "../types";
2
+ export interface SearchOptions {
3
+ caseSensitive?: boolean;
4
+ regex?: boolean;
5
+ blockTypes?: string[];
6
+ }
7
+ export interface SearchMatch {
8
+ blockId: string;
9
+ blockType: string;
10
+ /** Character offset within the block's text content */
11
+ start: number;
12
+ /** Character offset (exclusive) within the block's text content */
13
+ end: number;
14
+ /** The matched text */
15
+ matchText: string;
16
+ /** Surrounding context text */
17
+ context: string;
18
+ }
19
+ export interface ReplaceResult {
20
+ blockId: string;
21
+ /** Number of replacements made in this block */
22
+ count: number;
23
+ }
24
+ /**
25
+ * Search engine that operates on the block model (not the DOM).
26
+ * Stateless — takes blocks as input and returns matches.
27
+ */
28
+ export declare class SearchEngine {
29
+ /**
30
+ * Search all blocks for a query string or regex pattern.
31
+ */
32
+ search(blocks: ReadonlyArray<Block>, query: string, options?: SearchOptions): SearchMatch[];
33
+ /**
34
+ * Count total matches across all blocks.
35
+ */
36
+ count(blocks: ReadonlyArray<Block>, query: string, options?: SearchOptions): number;
37
+ private buildPattern;
38
+ private extractContext;
39
+ }
@@ -0,0 +1,59 @@
1
+ import type { SearchMatch, SearchOptions } from "./search-engine";
2
+ export interface SearchUICallbacks {
3
+ /** Called when the query, options, or navigation changes. */
4
+ onSearch: (query: string, options: SearchOptions) => SearchMatch[];
5
+ /** Called to navigate to (highlight & scroll to) a specific match. */
6
+ onNavigate: (match: SearchMatch) => void;
7
+ /** Called to replace a single match with replacement text. */
8
+ onReplace: (match: SearchMatch, replacement: string) => void;
9
+ /** Called to replace all matches. */
10
+ onReplaceAll: (matches: SearchMatch[], replacement: string) => void;
11
+ /** Called when the panel is closed. */
12
+ onClose: () => void;
13
+ }
14
+ /**
15
+ * Search & Replace panel UI.
16
+ * Renders a fixed panel at the top-right of the editor.
17
+ * Replace row is collapsed by default with a toggle button.
18
+ */
19
+ export declare class SearchUI {
20
+ readonly element: HTMLElement;
21
+ private searchInput;
22
+ private replaceInput;
23
+ private countLabel;
24
+ private caseSensitiveBtn;
25
+ private regexBtn;
26
+ private replaceRow;
27
+ private expandBtn;
28
+ private replaceExpanded;
29
+ private callbacks;
30
+ private matches;
31
+ private currentIndex;
32
+ private caseSensitive;
33
+ private useRegex;
34
+ private debounceTimer;
35
+ constructor(callbacks: SearchUICallbacks);
36
+ show(): void;
37
+ hide(): void;
38
+ get visible(): boolean;
39
+ /** Focus the search input (e.g. when re-opening). */
40
+ focus(): void;
41
+ /** Navigate to the next search match. */
42
+ next(): void;
43
+ /** Navigate to the previous search match. */
44
+ prev(): void;
45
+ /** Handle keydown events. Returns true if consumed. */
46
+ handleKeyDown(e: KeyboardEvent): boolean;
47
+ destroy(): void;
48
+ /** Position the panel at the top-right of the nearest scrollable ancestor. */
49
+ private positionPanel;
50
+ private toggleReplace;
51
+ private build;
52
+ private onQueryChange;
53
+ private runSearch;
54
+ private navigateNext;
55
+ private navigatePrev;
56
+ private replaceCurrent;
57
+ private replaceAll;
58
+ private updateCount;
59
+ }
@@ -0,0 +1,3 @@
1
+ export { SelectionManager } from "./selection-manager";
2
+ export type { InlineSelection, MultiBlockSelection, SelectionState } from "./types";
3
+ export { isMultiBlockSelection, isInlineSelection } from "./types";
@@ -0,0 +1,41 @@
1
+ import type { Editor } from "../editor";
2
+ import type { MultiBlockSelection, SelectionState } from "./types";
3
+ import type { Attributes } from "../attributed-string";
4
+ /**
5
+ * Tracks the native browser selection and maps it to block-level selection state.
6
+ * Provides cross-block operations: deleteSelection(), formatSelection().
7
+ */
8
+ export declare class SelectionManager {
9
+ private editor;
10
+ private bus;
11
+ private current;
12
+ private blockSelectionActive;
13
+ private handleSelectionChange;
14
+ constructor(editor: Editor);
15
+ /** Whether the current selection is a programmatic block selection */
16
+ isBlockSelection(): boolean;
17
+ /** Set a programmatic block selection state */
18
+ setBlockSelection(state: MultiBlockSelection): void;
19
+ /** Clear the programmatic block selection */
20
+ clearBlockSelection(): void;
21
+ /** Get the current selection state */
22
+ getSelection(): SelectionState;
23
+ /**
24
+ * Delete the current selection.
25
+ * For multi-block: trim first block, remove middle blocks, trim last block,
26
+ * then merge first and last.
27
+ */
28
+ deleteSelection(): void;
29
+ /**
30
+ * Apply formatting attributes to the current selection.
31
+ */
32
+ formatSelection(attrs: Attributes): void;
33
+ /** Manually set selection (used by tests or programmatic control) */
34
+ setSelection(sel: SelectionState): void;
35
+ /** Clean up event listeners */
36
+ destroy(): void;
37
+ private syncFromDOM;
38
+ private findBlockFromNode;
39
+ private getOffsetInBlock;
40
+ private applyToBlock;
41
+ }
@@ -0,0 +1,20 @@
1
+ /** Selection within a single block */
2
+ export interface InlineSelection {
3
+ blockId: string;
4
+ start: number;
5
+ end: number;
6
+ }
7
+ /** Selection spanning multiple blocks */
8
+ export interface MultiBlockSelection {
9
+ anchorBlockId: string;
10
+ anchorOffset: number;
11
+ focusBlockId: string;
12
+ focusOffset: number;
13
+ selectedBlockIds: string[];
14
+ }
15
+ /** Current selection state — either inline, multi-block, or null */
16
+ export type SelectionState = InlineSelection | MultiBlockSelection | null;
17
+ /** Type guard for MultiBlockSelection */
18
+ export declare function isMultiBlockSelection(sel: SelectionState): sel is MultiBlockSelection;
19
+ /** Type guard for InlineSelection */
20
+ export declare function isInlineSelection(sel: SelectionState): sel is InlineSelection;
@@ -0,0 +1,2 @@
1
+ export { SlashMenu, SLASH_MENU_ITEMS } from "./slash-menu";
2
+ export type { SlashMenuItem } from "./slash-menu";
@@ -0,0 +1,27 @@
1
+ export interface SlashMenuItem {
2
+ type: string;
3
+ label: string;
4
+ description: string;
5
+ metadata?: Record<string, unknown>;
6
+ }
7
+ export declare const SLASH_MENU_ITEMS: SlashMenuItem[];
8
+ export declare class SlashMenu {
9
+ private menu;
10
+ private allItems;
11
+ private filteredItems;
12
+ private onSelectCb;
13
+ constructor(items: SlashMenuItem[], onSelect: (item: SlashMenuItem) => void, onClose: () => void);
14
+ get element(): HTMLElement;
15
+ get hasItems(): boolean;
16
+ show(anchorRect: DOMRect): void;
17
+ /** Reposition the menu relative to a new anchor rect (e.g. on scroll) */
18
+ reposition(anchorRect: DOMRect): void;
19
+ hide(): void;
20
+ get visible(): boolean;
21
+ /** Update the filter query. Filters allItems, resets selection, re-renders. */
22
+ updateFilter(query: string): void;
23
+ /** Handle keyboard events. Returns true if the event was consumed. */
24
+ handleKeyDown(e: KeyboardEvent): boolean;
25
+ destroy(): void;
26
+ private toMenuItems;
27
+ }
@@ -0,0 +1 @@
1
+ export { TableOfContents } from "./table-of-contents";
@@ -0,0 +1,74 @@
1
+ import type { Block } from "../types";
2
+ /**
3
+ * Table of Contents widget — a minimap-style navigation rail on the right
4
+ * side of the editor. Shows tiny right-aligned lines at rest. On hover,
5
+ * entries expand into labeled pills with genie magnification that pops
6
+ * the entry nearest to the cursor.
7
+ */
8
+ export declare class TableOfContents {
9
+ private readonly container;
10
+ private readonly track;
11
+ private readonly editorRoot;
12
+ private readonly getBlocks;
13
+ private readonly onNavigate;
14
+ private activeBlockId;
15
+ private entries;
16
+ private entryEls;
17
+ private updateTimer;
18
+ private scrollRaf;
19
+ private scrollParent;
20
+ private scrollHandler;
21
+ private moveRaf;
22
+ private lastMouseY;
23
+ /** Timestamp until which scroll-based active tracking is suppressed (after click nav) */
24
+ private scrollLockUntil;
25
+ /** Whether the mouse is currently over the TOC container */
26
+ private isHovered;
27
+ constructor(editorRoot: HTMLElement, getBlocks: () => ReadonlyArray<Block>, onNavigate: (blockId: string) => void);
28
+ /**
29
+ * Scan blocks for headings and rebuild the ToC entries.
30
+ * Debounced when called repeatedly (e.g. rapid typing).
31
+ */
32
+ update(): void;
33
+ /**
34
+ * Highlight a specific entry as the active heading.
35
+ */
36
+ setActiveHeading(blockId: string | null): void;
37
+ /**
38
+ * Hide the widget.
39
+ */
40
+ hide(): void;
41
+ /**
42
+ * Show the widget.
43
+ */
44
+ show(): void;
45
+ /**
46
+ * Clean up DOM and listeners.
47
+ */
48
+ destroy(): void;
49
+ private rebuild;
50
+ private applyActiveClass;
51
+ private handleClick;
52
+ /**
53
+ * Briefly pulse the background of a heading block to confirm navigation.
54
+ */
55
+ private pulseBlock;
56
+ private handleMouseEnter;
57
+ private handleMouseLeave;
58
+ private handleMouseMove;
59
+ private applyMagnification;
60
+ /**
61
+ * Set up scroll-based active heading tracking.
62
+ * Find the scroll parent and listen for scroll events.
63
+ */
64
+ private setupScrollTracking;
65
+ /**
66
+ * Find the nearest scrollable ancestor, or fall back to window.
67
+ */
68
+ private findScrollParent;
69
+ /**
70
+ * Determine which heading is currently "active" based on scroll position.
71
+ * Skipped briefly after click-navigation so the clicked heading stays active.
72
+ */
73
+ private computeActiveHeading;
74
+ }
@@ -0,0 +1,2 @@
1
+ export { Transaction } from "./transaction";
2
+ export type { Operation, InsertTextOp, DeleteRangeOp, ApplyAttributesOp, RemoveAttributesOp, SetMetadataOp, ReplaceContentOp, TransactionResult, } from "./types";
@@ -0,0 +1,29 @@
1
+ import type { AttributedString, Attributes } from "../attributed-string";
2
+ import type { BlockMetadata } from "../schema";
3
+ import type { Operation, TransactionResult } from "./types";
4
+ /**
5
+ * Transaction builder — accumulates operations via a builder pattern,
6
+ * then applies them all in order to produce new content and metadata.
7
+ *
8
+ * A transaction can only be applied once.
9
+ */
10
+ export declare class Transaction {
11
+ readonly blockId: string;
12
+ private ops;
13
+ private committed;
14
+ constructor(blockId: string);
15
+ get operations(): ReadonlyArray<Operation>;
16
+ get isEmpty(): boolean;
17
+ insertText(offset: number, text: string, attributes?: Attributes): this;
18
+ deleteRange(start: number, end: number): this;
19
+ applyAttributes(start: number, end: number, attributes: Attributes): this;
20
+ removeAttributes(start: number, end: number, keys: string[]): this;
21
+ setMetadata(key: string, value: unknown): this;
22
+ replaceContent(content: AttributedString): this;
23
+ /**
24
+ * Apply all operations in order. Returns new content and metadata.
25
+ * Marks the transaction as committed — cannot be applied again.
26
+ */
27
+ apply(content: AttributedString, metadata: BlockMetadata): TransactionResult;
28
+ private guardCommitted;
29
+ }
@@ -0,0 +1,40 @@
1
+ import type { Attributes } from "../attributed-string";
2
+ import type { BlockMetadata } from "../schema";
3
+ import type { AttributedString } from "../attributed-string";
4
+ export interface InsertTextOp {
5
+ type: "insertText";
6
+ offset: number;
7
+ text: string;
8
+ attributes?: Attributes;
9
+ }
10
+ export interface DeleteRangeOp {
11
+ type: "deleteRange";
12
+ start: number;
13
+ end: number;
14
+ }
15
+ export interface ApplyAttributesOp {
16
+ type: "applyAttributes";
17
+ start: number;
18
+ end: number;
19
+ attributes: Attributes;
20
+ }
21
+ export interface RemoveAttributesOp {
22
+ type: "removeAttributes";
23
+ start: number;
24
+ end: number;
25
+ keys: string[];
26
+ }
27
+ export interface SetMetadataOp {
28
+ type: "setMetadata";
29
+ key: string;
30
+ value: unknown;
31
+ }
32
+ export interface ReplaceContentOp {
33
+ type: "replaceContent";
34
+ content: AttributedString;
35
+ }
36
+ export type Operation = InsertTextOp | DeleteRangeOp | ApplyAttributesOp | RemoveAttributesOp | SetMetadataOp | ReplaceContentOp;
37
+ export interface TransactionResult {
38
+ content: AttributedString;
39
+ metadata: BlockMetadata;
40
+ }
@@ -0,0 +1,21 @@
1
+ import { AttributedString } from "./attributed-string";
2
+ import type { AttributedStringJSON } from "./attributed-string";
3
+ import type { BlockMetadata } from "./schema";
4
+ /** A block of content in the editor */
5
+ export interface Block {
6
+ id: string;
7
+ type: string;
8
+ content: AttributedString;
9
+ metadata: BlockMetadata;
10
+ }
11
+ /** JSON-serializable representation of a Block */
12
+ export interface BlockJSON {
13
+ id: string;
14
+ type: string;
15
+ content: AttributedStringJSON;
16
+ metadata: BlockMetadata;
17
+ }
18
+ /** Convert a Block to its JSON representation */
19
+ export declare function blockToJSON(block: Block): BlockJSON;
20
+ /** Restore a Block from its JSON representation */
21
+ export declare function blockFromJSON(json: BlockJSON): Block;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Reusable floating context menu component.
3
+ * Renders a list of selectable items with keyboard navigation,
4
+ * mouse interaction, sections, disabled/danger states, and viewport-aware positioning.
5
+ *
6
+ * Used internally by SlashMenu, AutoCompleteMenu, BlockActionMenu, and table context menu.
7
+ */
8
+ /** A single item in a {@link ContextMenu}. */
9
+ export interface MenuItem {
10
+ /** Unique identifier for this item — returned in {@link ContextMenu.onSelect}. */
11
+ id: string;
12
+ /** Human-readable display name. */
13
+ label: string;
14
+ /** Optional secondary description displayed below the label. */
15
+ description?: string;
16
+ /**
17
+ * Optional icon: either an HTML string or a render function.
18
+ * Render functions receive the icon container element and may append
19
+ * arbitrary DOM nodes (e.g. SVGs).
20
+ */
21
+ icon?: string | ((container: HTMLElement) => void);
22
+ /** Group key — separator inserted between different sections */
23
+ section?: string;
24
+ /** When true, the item is rendered dimmed and cannot be selected. */
25
+ disabled?: boolean;
26
+ /** When true, the label is rendered in danger (red) color. */
27
+ danger?: boolean;
28
+ /** Keyboard shortcut hint displayed right-aligned, e.g. "⌫" or "Del" */
29
+ hint?: string;
30
+ /** Arbitrary payload passed back in onSelect */
31
+ data?: unknown;
32
+ }
33
+ /** Construction options for {@link ContextMenu}. */
34
+ export interface ContextMenuOptions {
35
+ /** Additional CSS class on the container (e.g. "blx-slash-menu") */
36
+ className?: string;
37
+ /** If set, shows empty state when items is empty */
38
+ emptyText?: string;
39
+ /** Arrow nav skips disabled items (default: true) */
40
+ skipDisabled?: boolean;
41
+ /**
42
+ * ARIA role for the container and its items.
43
+ * - "menu" (default): container gets role="menu", items get implicit button role
44
+ * - "listbox": container gets role="listbox", items get role="option"
45
+ * Used by Dropdown widget for accessible select-like behavior.
46
+ */
47
+ role?: "menu" | "listbox";
48
+ }
49
+ export declare class ContextMenu {
50
+ /** The root DOM element of the menu. Append to the document before calling {@link show}. */
51
+ readonly el: HTMLElement;
52
+ private items;
53
+ private selectedIndex;
54
+ private _visible;
55
+ private opts;
56
+ /** Remembered placement so reposition() doesn't flicker */
57
+ private placement;
58
+ /** Stored anchor rect for repositioning after content changes */
59
+ private anchorRect;
60
+ /** Called when the user selects an item (click, Enter, or Tab). */
61
+ onSelect: ((item: MenuItem) => void) | null;
62
+ /** Called when Escape is pressed while the menu is visible. */
63
+ onClose: (() => void) | null;
64
+ constructor(options?: ContextMenuOptions);
65
+ /** Whether the menu is currently visible. */
66
+ get visible(): boolean;
67
+ /** Whether the menu has at least one item. */
68
+ get hasItems(): boolean;
69
+ /** The currently highlighted {@link MenuItem}, or `undefined` if empty. */
70
+ get selectedItem(): MenuItem | undefined;
71
+ /**
72
+ * Show the menu anchored to `anchorRect` and populate it with `items`.
73
+ * The menu is positioned below the anchor by default and flips above if
74
+ * it would overflow the viewport bottom.
75
+ * @param anchorRect - Bounding rect of the element to anchor to.
76
+ * @param items - List of items to render.
77
+ */
78
+ show(anchorRect: DOMRect, items: MenuItem[]): void;
79
+ /** Hide the menu. Does not remove it from the DOM. */
80
+ hide(): void;
81
+ /** Hide the menu and remove its element from the DOM. */
82
+ destroy(): void;
83
+ /** Replace items and reanchor when placed above (used for filter-as-you-type) */
84
+ setItems(items: MenuItem[]): void;
85
+ /** Reposition relative to a new anchor rect (e.g. caret moved or content resized) */
86
+ reposition(anchorRect: DOMRect): void;
87
+ /**
88
+ * Handle keyboard events for menu navigation.
89
+ * @param e - The keyboard event to process.
90
+ * @returns `true` if the event was consumed (ArrowUp, ArrowDown, Enter, Tab, Escape),
91
+ * `false` otherwise. When `true`, callers should stop further event processing.
92
+ */
93
+ handleKeyDown(e: KeyboardEvent): boolean;
94
+ /**
95
+ * Programmatically select item by index.
96
+ * Used by Dropdown type-ahead to highlight the matching item.
97
+ */
98
+ selectIndex(index: number): void;
99
+ private moveSelection;
100
+ private findFirstEnabled;
101
+ private renderItems;
102
+ private updateSelection;
103
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Shared dismiss utility: click-outside + optional Escape key.
3
+ * Used internally by Popover, and directly by BlockActionMenu.
4
+ */
5
+ /**
6
+ * Handle returned by {@link dismissOnClickOutside}.
7
+ * Call {@link remove} to cancel all installed listeners.
8
+ */
9
+ export interface DismissHandle {
10
+ /** Cancel all event listeners installed by {@link dismissOnClickOutside}. */
11
+ remove(): void;
12
+ }
13
+ /**
14
+ * Install click-outside and optional Escape-key dismiss handlers for a floating element.
15
+ *
16
+ * The click-outside listener is installed via a capture-phase `mousedown` + `touchstart`
17
+ * on `document`, so it fires before the element's own handlers. Use `defer: true`
18
+ * (the default) to skip the listener installation for one tick, preventing the same
19
+ * click that opened the element from immediately closing it.
20
+ *
21
+ * @param el - The floating element. Clicks inside it will NOT trigger dismiss.
22
+ * @param onDismiss - Callback invoked when a dismiss condition is met.
23
+ * @param options - Configuration options.
24
+ * @returns A {@link DismissHandle} whose {@link DismissHandle.remove} cancels all listeners.
25
+ */
26
+ export declare function dismissOnClickOutside(el: HTMLElement, onDismiss: () => void, options?: {
27
+ /** Listen for Escape key (default: true) */
28
+ escapeKey?: boolean;
29
+ /** setTimeout(0) guard to avoid instant dismiss from triggering click (default: true) */
30
+ defer?: boolean;
31
+ /** Extra elements that should not trigger dismiss */
32
+ ignoreElements?: HTMLElement[];
33
+ }): DismissHandle;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Dropdown widget — a select-like component composing ContextMenu.
3
+ *
4
+ * Features:
5
+ * - Keyboard navigation (Enter/Space/ArrowDown opens; ArrowUp/Down navigates; Enter selects; Escape closes)
6
+ * - Type-ahead filtering with 500ms buffer reset
7
+ * - ARIA: role="listbox" on menu, role="option" on items, aria-haspopup/aria-expanded on trigger
8
+ * - Programmatic value get/set
9
+ * - dismissOnClickOutside for click-outside handling
10
+ */
11
+ /** A single item in a {@link Dropdown}. */
12
+ export interface DropdownItem {
13
+ /** Unique identifier for this item. */
14
+ id: string;
15
+ /** Human-readable display name shown in trigger and menu. */
16
+ label: string;
17
+ /** Optional secondary description shown below the label. */
18
+ description?: string;
19
+ /**
20
+ * Optional icon: either an HTML string or a render function.
21
+ * Render functions receive the icon container element.
22
+ */
23
+ icon?: string | ((container: HTMLElement) => void);
24
+ /** Group key — separator inserted between different sections. */
25
+ section?: string;
26
+ /** When true, the item is rendered dimmed and cannot be selected. */
27
+ disabled?: boolean;
28
+ }
29
+ /** Construction options for {@link Dropdown}. */
30
+ export interface DropdownOptions {
31
+ /** Available items. */
32
+ items: DropdownItem[];
33
+ /** Called when an item is selected. */
34
+ onSelect?: (item: DropdownItem) => void;
35
+ /** Initially selected item id. */
36
+ value?: string;
37
+ /** Placeholder text when nothing selected (default: "Select..."). */
38
+ placeholder?: string;
39
+ /** Additional CSS class on the trigger button. */
40
+ className?: string;
41
+ }
42
+ export declare class Dropdown {
43
+ private triggerEl;
44
+ private menu;
45
+ private currentItems;
46
+ private selectedId;
47
+ private onSelectCallback;
48
+ private placeholder;
49
+ private dismissHandle;
50
+ private docKeyHandler;
51
+ /** Type-ahead state */
52
+ private typeAheadBuffer;
53
+ private typeAheadTimer;
54
+ constructor(options: DropdownOptions);
55
+ /**
56
+ * Append trigger button and menu to the given container.
57
+ * The menu element is appended to the nearest `.blx-editor` ancestor (for
58
+ * CSS variable inheritance) or document.body as a fallback.
59
+ * Call before interacting with the dropdown.
60
+ */
61
+ attachTo(container: HTMLElement): void;
62
+ /** Currently selected item id, or null if nothing is selected. */
63
+ get value(): string | null;
64
+ /**
65
+ * Programmatically set the selected item.
66
+ * Updates trigger label. Does not call onSelect.
67
+ */
68
+ setValue(id: string): void;
69
+ /** Open the dropdown menu. */
70
+ open(): void;
71
+ /** Close the dropdown menu and return focus to trigger. */
72
+ close(): void;
73
+ /**
74
+ * Clean up the dropdown: remove trigger from DOM, destroy menu, remove all listeners.
75
+ */
76
+ destroy(): void;
77
+ private updateTriggerLabel;
78
+ private readonly handleTriggerClick;
79
+ private readonly handleTriggerKeyDown;
80
+ private handleTypeAhead;
81
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Manages scroll-aware positioning for all floating UI elements.
3
+ *
4
+ * Each floating UI registers when it opens and unregisters when it
5
+ * closes. A single capture-phase scroll listener handles repositioning,
6
+ * hiding when the anchor scrolls off-screen, and re-showing when it
7
+ * scrolls back.
8
+ */
9
+ /**
10
+ * Registration record for a floating element managed by {@link FloatingScrollManager}.
11
+ *
12
+ * Register when the floating element becomes visible; unregister when it hides.
13
+ */
14
+ export interface FloatingRegistration {
15
+ /** Unique key (e.g. "inline-toolbar", "slash-menu") */
16
+ key: string;
17
+ /** Element whose viewport visibility determines show/hide */
18
+ anchorEl: HTMLElement;
19
+ /** Called on scroll when anchor is in viewport — receives fresh anchor rect */
20
+ onReposition: (anchorRect: DOMRect) => void;
21
+ /** Called when anchor scrolls out of viewport */
22
+ onScrollOut: () => void;
23
+ /** Called when anchor scrolls back into viewport */
24
+ onScrollIn: () => void;
25
+ }
26
+ export declare class FloatingScrollManager {
27
+ private registrations;
28
+ private scrollHandler;
29
+ /**
30
+ * Register a floating element for scroll-aware management.
31
+ * The element's visibility state is captured immediately; callbacks will fire
32
+ * on subsequent scroll events.
33
+ * @param reg - The registration record describing the floating element and its callbacks.
34
+ */
35
+ register(reg: FloatingRegistration): void;
36
+ /**
37
+ * Unregister a floating element by key.
38
+ * Removes the global scroll listener when no registrations remain.
39
+ * @param key - The key used when calling {@link register}.
40
+ */
41
+ unregister(key: string): void;
42
+ /**
43
+ * Unregister all floating elements and remove the scroll listener.
44
+ * Call when the editor or owning component is destroyed.
45
+ */
46
+ destroy(): void;
47
+ private ensureScrollListener;
48
+ private removeScrollListener;
49
+ private handleScroll;
50
+ }
@@ -0,0 +1,18 @@
1
+ export { positionFixed } from "./position-fixed";
2
+ export type { PositionFixedOptions } from "./position-fixed";
3
+ export { dismissOnClickOutside } from "./dismiss";
4
+ export type { DismissHandle } from "./dismiss";
5
+ export { ContextMenu } from "./context-menu";
6
+ export type { MenuItem, ContextMenuOptions } from "./context-menu";
7
+ export { Popover } from "./popover";
8
+ export type { PopoverOptions } from "./popover";
9
+ export { FloatingScrollManager } from "./floating-scroll-manager";
10
+ export type { FloatingRegistration } from "./floating-scroll-manager";
11
+ export { Tooltip } from "./tooltip";
12
+ export type { TooltipOptions } from "./tooltip";
13
+ export { Toast } from "./toast";
14
+ export type { ToastShowOptions, ToastType } from "./toast";
15
+ export { Modal } from "./modal";
16
+ export type { ModalOptions } from "./modal";
17
+ export { Dropdown } from "./dropdown";
18
+ export type { DropdownOptions, DropdownItem } from "./dropdown";