@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.
- package/README.md +98 -0
- package/dist/attributed-string/attributed-string.d.ts +37 -0
- package/dist/attributed-string/index.d.ts +2 -0
- package/dist/attributed-string/types.d.ts +13 -0
- package/dist/autocomplete/autocomplete-menu.d.ts +24 -0
- package/dist/autocomplete/index.d.ts +2 -0
- package/dist/autocomplete/types.d.ts +29 -0
- package/dist/blob-store/index.d.ts +32 -0
- package/dist/blob-store/types.d.ts +24 -0
- package/dist/block/block-controller.d.ts +205 -0
- package/dist/block/index.d.ts +2 -0
- package/dist/block/types.d.ts +15 -0
- package/dist/block-action-menu/block-action-menu.d.ts +62 -0
- package/dist/block-action-menu/index.d.ts +2 -0
- package/dist/block-context-menu/block-context-menu.d.ts +33 -0
- package/dist/block-context-menu/index.d.ts +2 -0
- package/dist/blx.js +16245 -0
- package/dist/blx.js.map +1 -0
- package/dist/caret/custom-caret.d.ts +30 -0
- package/dist/clipboard/clipboard-manager.d.ts +28 -0
- package/dist/clipboard/index.d.ts +2 -0
- package/dist/clipboard/paste-parser.d.ts +30 -0
- package/dist/commands/command-registry.d.ts +26 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/crdt/automerge-sync.d.ts +157 -0
- package/dist/crdt/crdt-log.d.ts +57 -0
- package/dist/crdt/index.d.ts +8 -0
- package/dist/crdt/remote-cursor-renderer.d.ts +28 -0
- package/dist/crdt/replay-ui.d.ts +34 -0
- package/dist/crdt/types.d.ts +47 -0
- package/dist/date-picker/agenda-utils.d.ts +37 -0
- package/dist/date-picker/date-parser.d.ts +25 -0
- package/dist/date-picker/date-picker.d.ts +115 -0
- package/dist/date-picker/index.d.ts +6 -0
- package/dist/drag-handle/drag-handle.d.ts +105 -0
- package/dist/drag-handle/index.d.ts +1 -0
- package/dist/editor.d.ts +864 -0
- package/dist/emoji-picker/emoji-data.d.ts +22 -0
- package/dist/emoji-picker/emoji-picker.d.ts +43 -0
- package/dist/emoji-picker/index.d.ts +3 -0
- package/dist/event-bus/event-bus.d.ts +14 -0
- package/dist/event-bus/index.d.ts +2 -0
- package/dist/event-bus/types.d.ts +320 -0
- package/dist/fold/fold-manager.d.ts +27 -0
- package/dist/fold/index.d.ts +2 -0
- package/dist/grapheme.d.ts +28 -0
- package/dist/index.d.ts +62 -0
- package/dist/inline-toolbar/highlight-picker.d.ts +41 -0
- package/dist/inline-toolbar/index.d.ts +5 -0
- package/dist/inline-toolbar/inline-toolbar.d.ts +97 -0
- package/dist/inline-toolbar/link-popover.d.ts +24 -0
- package/dist/keybindings/defaults.d.ts +2 -0
- package/dist/keybindings/index.d.ts +4 -0
- package/dist/keybindings/key-matcher.d.ts +41 -0
- package/dist/keybindings/types.d.ts +6 -0
- package/dist/keybindings/vim.d.ts +2 -0
- package/dist/markdown/block-shortcuts.d.ts +35 -0
- package/dist/markdown/emoticon-substitutions.d.ts +22 -0
- package/dist/markdown/export.d.ts +5 -0
- package/dist/markdown/index.d.ts +4 -0
- package/dist/markdown/inline-shortcuts.d.ts +13 -0
- package/dist/markdown/types.d.ts +29 -0
- package/dist/plugins/blockquote.d.ts +6 -0
- package/dist/plugins/checklist.d.ts +18 -0
- package/dist/plugins/code.d.ts +50 -0
- package/dist/plugins/excalidraw.d.ts +26 -0
- package/dist/plugins/heading.d.ts +20 -0
- package/dist/plugins/horizontal-rule.d.ts +5 -0
- package/dist/plugins/image.d.ts +19 -0
- package/dist/plugins/index.d.ts +28 -0
- package/dist/plugins/list.d.ts +18 -0
- package/dist/plugins/mermaid.d.ts +11 -0
- package/dist/plugins/paragraph.d.ts +18 -0
- package/dist/plugins/prism-loader.d.ts +16 -0
- package/dist/plugins/render-utils.d.ts +43 -0
- package/dist/plugins/table.d.ts +22 -0
- package/dist/plugins/youtube.d.ts +21 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/schema-registry.d.ts +35 -0
- package/dist/schema/types.d.ts +67 -0
- package/dist/search/index.d.ts +4 -0
- package/dist/search/search-engine.d.ts +39 -0
- package/dist/search/search-ui.d.ts +59 -0
- package/dist/selection/index.d.ts +3 -0
- package/dist/selection/selection-manager.d.ts +41 -0
- package/dist/selection/types.d.ts +20 -0
- package/dist/slash-menu/index.d.ts +2 -0
- package/dist/slash-menu/slash-menu.d.ts +27 -0
- package/dist/table-of-contents/index.d.ts +1 -0
- package/dist/table-of-contents/table-of-contents.d.ts +74 -0
- package/dist/transaction/index.d.ts +2 -0
- package/dist/transaction/transaction.d.ts +29 -0
- package/dist/transaction/types.d.ts +40 -0
- package/dist/types.d.ts +21 -0
- package/dist/ui/context-menu.d.ts +103 -0
- package/dist/ui/dismiss.d.ts +33 -0
- package/dist/ui/dropdown.d.ts +81 -0
- package/dist/ui/floating-scroll-manager.d.ts +50 -0
- package/dist/ui/index.d.ts +18 -0
- package/dist/ui/modal.d.ts +109 -0
- package/dist/ui/popover.d.ts +59 -0
- package/dist/ui/position-fixed.d.ts +35 -0
- package/dist/ui/toast.d.ts +60 -0
- package/dist/ui/tooltip.d.ts +64 -0
- package/dist/undo/index.d.ts +5 -0
- package/dist/undo/jump-list.d.ts +37 -0
- package/dist/undo/types.d.ts +49 -0
- package/dist/undo/undo-manager.d.ts +47 -0
- package/dist/util/icons.d.ts +13 -0
- package/dist/util/id.d.ts +10 -0
- package/dist/viewport/block-viewport.d.ts +106 -0
- package/dist/viewport/index.d.ts +2 -0
- package/package.json +66 -0
- package/style.css +4670 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modal dialog widget.
|
|
3
|
+
*
|
|
4
|
+
* Provides both static factory helpers (Modal.confirm, Modal.alert) and an
|
|
5
|
+
* instance-based API (new Modal()) for custom content dialogs.
|
|
6
|
+
*
|
|
7
|
+
* Uses the native `<dialog>` element with `showModal()` for:
|
|
8
|
+
* - Built-in focus trap (browser-managed)
|
|
9
|
+
* - Top-layer rendering (above all other content)
|
|
10
|
+
* - Native Escape key handling
|
|
11
|
+
*
|
|
12
|
+
* Accessibility:
|
|
13
|
+
* - `role="dialog"` + `aria-modal="true"` on the dialog element
|
|
14
|
+
* - `aria-labelledby` points to the title element when a title is provided
|
|
15
|
+
* - Scroll lock applied to body while dialog is open
|
|
16
|
+
* - Focus returned to triggering element on close
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Confirm dialog
|
|
20
|
+
* const confirmed = await Modal.confirm("Delete this block?", { title: "Confirm Delete" });
|
|
21
|
+
*
|
|
22
|
+
* // Alert dialog
|
|
23
|
+
* await Modal.alert("Your changes have been saved.");
|
|
24
|
+
*
|
|
25
|
+
* // Custom content modal
|
|
26
|
+
* const modal = new Modal({ title: "Settings" });
|
|
27
|
+
* modal.contentEl.appendChild(myForm);
|
|
28
|
+
* modal.open();
|
|
29
|
+
*/
|
|
30
|
+
/** Construction / configuration options for Modal instances and static helpers. */
|
|
31
|
+
export interface ModalOptions {
|
|
32
|
+
/** Dialog title displayed in a header `<h3>`. Used for `aria-labelledby`. */
|
|
33
|
+
title?: string;
|
|
34
|
+
/** Additional CSS class for the dialog element. */
|
|
35
|
+
className?: string;
|
|
36
|
+
/** Whether a click on the backdrop area closes the dialog (default: true). */
|
|
37
|
+
closeOnBackdropClick?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare class Modal {
|
|
40
|
+
/** The native `<dialog>` element. */
|
|
41
|
+
readonly dialogEl: HTMLDialogElement;
|
|
42
|
+
/**
|
|
43
|
+
* Container element for custom content.
|
|
44
|
+
* Append child elements here when using the instance API.
|
|
45
|
+
*/
|
|
46
|
+
readonly contentEl: HTMLElement;
|
|
47
|
+
private opts;
|
|
48
|
+
private previousFocus;
|
|
49
|
+
/**
|
|
50
|
+
* Create a new Modal instance for custom content dialogs.
|
|
51
|
+
* The dialog is NOT appended to the DOM until `.open()` is called.
|
|
52
|
+
*
|
|
53
|
+
* @param options - Modal configuration.
|
|
54
|
+
*/
|
|
55
|
+
constructor(options?: ModalOptions);
|
|
56
|
+
/**
|
|
57
|
+
* Open the modal: append to DOM, apply scroll lock, call showModal().
|
|
58
|
+
* Records the currently focused element to restore focus on close.
|
|
59
|
+
*/
|
|
60
|
+
open(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Close the modal programmatically.
|
|
63
|
+
* Calls `dialog.close()` which fires the "close" event and removes scroll lock.
|
|
64
|
+
*/
|
|
65
|
+
close(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Remove the dialog element from the DOM.
|
|
68
|
+
* Should be called when you no longer need the modal instance.
|
|
69
|
+
*/
|
|
70
|
+
destroy(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Show a confirmation dialog.
|
|
73
|
+
*
|
|
74
|
+
* @param message - Body text for the dialog.
|
|
75
|
+
* @param opts - Optional title and configuration.
|
|
76
|
+
* @returns Promise that resolves to `true` (confirmed) or `false` (cancelled).
|
|
77
|
+
*/
|
|
78
|
+
static confirm(message: string, opts?: Pick<ModalOptions, "title" | "closeOnBackdropClick">): Promise<boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* Show an informational alert dialog with a single OK button.
|
|
81
|
+
*
|
|
82
|
+
* @param message - Body text for the dialog.
|
|
83
|
+
* @param opts - Optional title.
|
|
84
|
+
* @returns Promise that resolves when the dialog is dismissed.
|
|
85
|
+
*/
|
|
86
|
+
static alert(message: string, opts?: Pick<ModalOptions, "title">): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Build a `<dialog>` element with the standard modal structure:
|
|
89
|
+
* optional header (if title provided), body div, footer div.
|
|
90
|
+
* Sets ARIA attributes: role, aria-modal, aria-labelledby.
|
|
91
|
+
*/
|
|
92
|
+
private static buildDialog;
|
|
93
|
+
/**
|
|
94
|
+
* Attach a backdrop click listener to a dialog.
|
|
95
|
+
* Backdrop clicks are detected by checking if the click target is the dialog
|
|
96
|
+
* element itself (not a child — those have a different target).
|
|
97
|
+
*/
|
|
98
|
+
private static attachBackdropListener;
|
|
99
|
+
/**
|
|
100
|
+
* Apply scroll lock: hide body overflow and compensate for scrollbar width
|
|
101
|
+
* to prevent layout shift.
|
|
102
|
+
*/
|
|
103
|
+
private static applyScrollLock;
|
|
104
|
+
/**
|
|
105
|
+
* Remove scroll lock previously applied by applyScrollLock().
|
|
106
|
+
*/
|
|
107
|
+
private static removeScrollLock;
|
|
108
|
+
}
|
|
109
|
+
export type { ModalOptions as ModalConfirmOptions };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable floating container with positioning and dismiss logic.
|
|
3
|
+
* Content is appended by the consumer via `popover.el`.
|
|
4
|
+
*
|
|
5
|
+
* Used internally by LinkPopover, HighlightPicker, and InlineToolbar.
|
|
6
|
+
*/
|
|
7
|
+
/** Construction options for {@link Popover}. */
|
|
8
|
+
export interface PopoverOptions {
|
|
9
|
+
/** Additional CSS class (e.g. "blx-link-popover") */
|
|
10
|
+
className?: string;
|
|
11
|
+
/** CSS display value when shown (default: "flex") */
|
|
12
|
+
displayMode?: string;
|
|
13
|
+
/** Pixel gap between anchor and popover (default: 6) */
|
|
14
|
+
gap?: number;
|
|
15
|
+
/** Horizontal alignment (default: "center") */
|
|
16
|
+
align?: "start" | "center";
|
|
17
|
+
/** Preferred vertical placement (default: "below") */
|
|
18
|
+
placement?: "above" | "below";
|
|
19
|
+
/** Dismiss on click outside (default: true) */
|
|
20
|
+
dismissOnClickOutside?: boolean;
|
|
21
|
+
/** Dismiss on Escape key (default: true) */
|
|
22
|
+
dismissOnEscape?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare class Popover {
|
|
25
|
+
/** The root DOM element of the popover. Append to document before calling {@link show}. */
|
|
26
|
+
readonly el: HTMLElement;
|
|
27
|
+
private _visible;
|
|
28
|
+
private opts;
|
|
29
|
+
private dismissHandle;
|
|
30
|
+
/** Called after the popover is hidden (by any means). */
|
|
31
|
+
onHide: (() => void) | null;
|
|
32
|
+
/**
|
|
33
|
+
* Create a new Popover.
|
|
34
|
+
* @param options - Optional configuration overrides.
|
|
35
|
+
*/
|
|
36
|
+
constructor(options?: PopoverOptions);
|
|
37
|
+
/** Whether the popover is currently visible. */
|
|
38
|
+
get visible(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Show the popover anchored to `anchorRect`.
|
|
41
|
+
* Installs click-outside and/or Escape-key dismiss handlers as configured.
|
|
42
|
+
* @param anchorRect - Bounding rect of the element to anchor to.
|
|
43
|
+
*/
|
|
44
|
+
show(anchorRect: DOMRect): void;
|
|
45
|
+
/**
|
|
46
|
+
* Reposition to a new anchor rect without toggling visibility or dismiss handlers.
|
|
47
|
+
* No-op if the popover is not currently visible.
|
|
48
|
+
* @param anchorRect - New bounding rect to anchor to.
|
|
49
|
+
*/
|
|
50
|
+
reposition(anchorRect: DOMRect): void;
|
|
51
|
+
private positionTo;
|
|
52
|
+
/**
|
|
53
|
+
* Hide the popover and remove all dismiss handlers.
|
|
54
|
+
* Fires {@link onHide} if it was previously visible.
|
|
55
|
+
*/
|
|
56
|
+
hide(): void;
|
|
57
|
+
/** Hide the popover and remove its element from the DOM. */
|
|
58
|
+
destroy(): void;
|
|
59
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared positioning utility for floating UI elements.
|
|
3
|
+
* Sets `position: fixed` and places the element relative to an anchor rect,
|
|
4
|
+
* flipping vertically if it overflows and clamping horizontally.
|
|
5
|
+
* Constrains max-height to available viewport space so menus scroll
|
|
6
|
+
* instead of bleeding outside the viewport.
|
|
7
|
+
*/
|
|
8
|
+
/** Options for {@link positionFixed}. */
|
|
9
|
+
export interface PositionFixedOptions {
|
|
10
|
+
/** Pixel gap between anchor and element (default: 4) */
|
|
11
|
+
gap?: number;
|
|
12
|
+
/** Horizontal alignment relative to anchor (default: "start") */
|
|
13
|
+
align?: "start" | "center";
|
|
14
|
+
/** Preferred vertical placement (default: "below") */
|
|
15
|
+
placement?: "above" | "below";
|
|
16
|
+
/** Viewport edge padding in px (default: 4) */
|
|
17
|
+
viewportPadding?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Called after final placement is determined.
|
|
20
|
+
* Receives the actual placement used (`"above"` or `"below"`), which may
|
|
21
|
+
* differ from `options.placement` if a flip was necessary.
|
|
22
|
+
*/
|
|
23
|
+
onPlaced?: (placement: "above" | "below") => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Position `el` with `position: fixed` relative to `anchor`.
|
|
27
|
+
*
|
|
28
|
+
* Measures the element and places it in a single synchronous pass so the
|
|
29
|
+
* final position is painted on the first frame (no flash/jump).
|
|
30
|
+
*
|
|
31
|
+
* @param el - The floating element to position (must be in the DOM and visible).
|
|
32
|
+
* @param anchor - The anchor bounding rect (e.g. from `getBoundingClientRect()`).
|
|
33
|
+
* @param options - Placement preferences and callbacks.
|
|
34
|
+
*/
|
|
35
|
+
export declare function positionFixed(el: HTMLElement, anchor: DOMRect, options?: PositionFixedOptions): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toast notification widget.
|
|
3
|
+
*
|
|
4
|
+
* Displays brief, auto-dismissing notifications at the bottom-center of the
|
|
5
|
+
* viewport. Uses static factory methods — callers never manage instances.
|
|
6
|
+
*
|
|
7
|
+
* Two aria-live containers are maintained:
|
|
8
|
+
* - Polite container (info/success): does not interrupt screen readers
|
|
9
|
+
* - Assertive container (error): interrupts screen readers immediately
|
|
10
|
+
*
|
|
11
|
+
* Both containers are created lazily on first use and persist indefinitely
|
|
12
|
+
* so that aria-live regions are pre-registered before content is injected
|
|
13
|
+
* (which is required for reliable screen reader announcements).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* Toast.show("File saved");
|
|
17
|
+
* Toast.show("Connection failed", { type: "error" });
|
|
18
|
+
* Toast.show("Copied!", { type: "success", duration: 2000 });
|
|
19
|
+
*/
|
|
20
|
+
/** Visual variant of a toast notification. */
|
|
21
|
+
export type ToastType = "info" | "error" | "success";
|
|
22
|
+
/** Options for {@link Toast.show}. */
|
|
23
|
+
export interface ToastShowOptions {
|
|
24
|
+
/** Toast variant (default: "info"). */
|
|
25
|
+
type?: ToastType;
|
|
26
|
+
/** Auto-dismiss duration in milliseconds (default: 4000). */
|
|
27
|
+
duration?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare class Toast {
|
|
30
|
+
/** Polite aria-live container (info / success toasts). Created on first use. */
|
|
31
|
+
private static container;
|
|
32
|
+
/** Assertive aria-live container (error toasts). Created on first use. */
|
|
33
|
+
private static assertiveContainer;
|
|
34
|
+
private constructor();
|
|
35
|
+
/**
|
|
36
|
+
* Display a toast notification.
|
|
37
|
+
*
|
|
38
|
+
* @param message - Text content to show in the toast.
|
|
39
|
+
* @param opts - Optional configuration.
|
|
40
|
+
*/
|
|
41
|
+
static show(message: string, opts?: ToastShowOptions): void;
|
|
42
|
+
/**
|
|
43
|
+
* Return the appropriate aria-live container for the given toast type,
|
|
44
|
+
* creating and appending it to document.body if it doesn't exist yet.
|
|
45
|
+
*
|
|
46
|
+
* The container is created BEFORE any toast is appended so that
|
|
47
|
+
* screen readers register the live region in advance.
|
|
48
|
+
*/
|
|
49
|
+
private static getOrCreateContainer;
|
|
50
|
+
/**
|
|
51
|
+
* Create a new toast container element and append it to document.body.
|
|
52
|
+
*/
|
|
53
|
+
private static createContainer;
|
|
54
|
+
/**
|
|
55
|
+
* Dismiss a toast element with an exit animation.
|
|
56
|
+
* Removes the element from DOM after the animation completes.
|
|
57
|
+
* If prefers-reduced-motion is set, removes immediately.
|
|
58
|
+
*/
|
|
59
|
+
private static dismiss;
|
|
60
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessible Tooltip widget.
|
|
3
|
+
*
|
|
4
|
+
* Shows a short text label near a trigger element on hover (with configurable
|
|
5
|
+
* delay) or focus (immediately). Uses `positionFixed` for viewport-aware placement.
|
|
6
|
+
*
|
|
7
|
+
* Follows WAI-ARIA Tooltip pattern: the trigger gets `aria-describedby` pointing
|
|
8
|
+
* to the tooltip element which has `role="tooltip"`. The tooltip element itself
|
|
9
|
+
* is never focusable (`pointer-events: none` set in CSS).
|
|
10
|
+
*/
|
|
11
|
+
/** Construction options for {@link Tooltip}. */
|
|
12
|
+
export interface TooltipOptions {
|
|
13
|
+
/** Tooltip text content. */
|
|
14
|
+
content: string;
|
|
15
|
+
/** Preferred placement relative to trigger (default: "above"). */
|
|
16
|
+
placement?: "above" | "below";
|
|
17
|
+
/** Show delay in ms on mouseenter (default: 350). Focus always shows instantly. */
|
|
18
|
+
delay?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class Tooltip {
|
|
21
|
+
/** The tooltip DOM element. Has `role="tooltip"` and class `blx-tooltip`. */
|
|
22
|
+
readonly el: HTMLElement;
|
|
23
|
+
private opts;
|
|
24
|
+
private _visible;
|
|
25
|
+
private trigger;
|
|
26
|
+
private showTimer;
|
|
27
|
+
private onMouseEnter;
|
|
28
|
+
private onMouseLeave;
|
|
29
|
+
private onFocus;
|
|
30
|
+
private onBlur;
|
|
31
|
+
private onKeyDown;
|
|
32
|
+
private onVisibilityChange;
|
|
33
|
+
/**
|
|
34
|
+
* Create a new Tooltip.
|
|
35
|
+
* The element is appended to `document.body` immediately so it is available
|
|
36
|
+
* for positioning. It starts hidden (`display: none`).
|
|
37
|
+
* @param options - Tooltip configuration.
|
|
38
|
+
*/
|
|
39
|
+
constructor(options: TooltipOptions);
|
|
40
|
+
/**
|
|
41
|
+
* Attach the tooltip to a trigger element.
|
|
42
|
+
* Sets `aria-describedby` on the trigger and installs event listeners.
|
|
43
|
+
* Call at most once per Tooltip instance — create a new Tooltip to re-attach.
|
|
44
|
+
* @param trigger - The element that triggers the tooltip.
|
|
45
|
+
*/
|
|
46
|
+
attachTo(trigger: HTMLElement): void;
|
|
47
|
+
/**
|
|
48
|
+
* Update the tooltip's text content.
|
|
49
|
+
* Can be called at any time, including while the tooltip is visible.
|
|
50
|
+
* @param content - New text content.
|
|
51
|
+
*/
|
|
52
|
+
updateContent(content: string): void;
|
|
53
|
+
/**
|
|
54
|
+
* Remove the tooltip element from the DOM and clean up all event listeners
|
|
55
|
+
* and timers. Removes `aria-describedby` from the trigger.
|
|
56
|
+
* After calling destroy, do not use this Tooltip instance.
|
|
57
|
+
*/
|
|
58
|
+
destroy(): void;
|
|
59
|
+
private startShowTimer;
|
|
60
|
+
private cancelAndHide;
|
|
61
|
+
private cancelTimer;
|
|
62
|
+
private showNow;
|
|
63
|
+
private hide;
|
|
64
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { UndoManager } from "./undo-manager";
|
|
2
|
+
export type { UndoManagerOptions } from "./undo-manager";
|
|
3
|
+
export { JumpList } from "./jump-list";
|
|
4
|
+
export type { JumpEntry, JumpListOptions } from "./jump-list";
|
|
5
|
+
export type { UndoAction, UndoEntry, CursorState, BlockSnapshot } from "./types";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** A position in the editor (block + cursor offset) */
|
|
2
|
+
export interface JumpEntry {
|
|
3
|
+
blockId: string;
|
|
4
|
+
offset: number;
|
|
5
|
+
}
|
|
6
|
+
export interface JumpListOptions {
|
|
7
|
+
/** Maximum number of entries (default 100) */
|
|
8
|
+
maxSize?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Vim-style navigation history (jumplist).
|
|
12
|
+
*
|
|
13
|
+
* Records cursor positions before "jumps" — significant position changes
|
|
14
|
+
* such as search navigation, internal link clicks, or scrollToBlock calls.
|
|
15
|
+
* Navigate with Ctrl-O (back) and Ctrl-I (forward).
|
|
16
|
+
*/
|
|
17
|
+
export declare class JumpList {
|
|
18
|
+
private entries;
|
|
19
|
+
private index;
|
|
20
|
+
private readonly maxSize;
|
|
21
|
+
constructor(options?: JumpListOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Record the current position before jumping away.
|
|
24
|
+
* Discards forward history (like vim's jumplist).
|
|
25
|
+
*/
|
|
26
|
+
push(entry: JumpEntry): void;
|
|
27
|
+
/** Go back (Ctrl-O). Returns the position to jump to, or null. */
|
|
28
|
+
back(): JumpEntry | null;
|
|
29
|
+
/** Go forward (Ctrl-I). Returns the position to jump to, or null. */
|
|
30
|
+
forward(): JumpEntry | null;
|
|
31
|
+
/** Current position in the jump list */
|
|
32
|
+
current(): JumpEntry | null;
|
|
33
|
+
canGoBack(): boolean;
|
|
34
|
+
canGoForward(): boolean;
|
|
35
|
+
clear(): void;
|
|
36
|
+
get size(): number;
|
|
37
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AttributedString } from "../attributed-string";
|
|
2
|
+
import type { BlockMetadata } from "../schema";
|
|
3
|
+
/** Snapshot of a block's full state for undo/redo */
|
|
4
|
+
export interface BlockSnapshot {
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
content: AttributedString;
|
|
8
|
+
metadata: BlockMetadata;
|
|
9
|
+
}
|
|
10
|
+
/** Cursor position within the editor */
|
|
11
|
+
export interface CursorState {
|
|
12
|
+
blockId: string;
|
|
13
|
+
offset: number;
|
|
14
|
+
}
|
|
15
|
+
/** A single reversible action within an undo entry */
|
|
16
|
+
export type UndoAction = {
|
|
17
|
+
type: "contentChange";
|
|
18
|
+
blockId: string;
|
|
19
|
+
before: {
|
|
20
|
+
content: AttributedString;
|
|
21
|
+
metadata: BlockMetadata;
|
|
22
|
+
blockType: string;
|
|
23
|
+
};
|
|
24
|
+
after: {
|
|
25
|
+
content: AttributedString;
|
|
26
|
+
metadata: BlockMetadata;
|
|
27
|
+
blockType: string;
|
|
28
|
+
};
|
|
29
|
+
} | {
|
|
30
|
+
type: "addBlock";
|
|
31
|
+
block: BlockSnapshot;
|
|
32
|
+
index: number;
|
|
33
|
+
} | {
|
|
34
|
+
type: "removeBlock";
|
|
35
|
+
block: BlockSnapshot;
|
|
36
|
+
index: number;
|
|
37
|
+
} | {
|
|
38
|
+
type: "moveBlock";
|
|
39
|
+
blockId: string;
|
|
40
|
+
fromIndex: number;
|
|
41
|
+
toIndex: number;
|
|
42
|
+
};
|
|
43
|
+
/** A group of actions that form a single undoable unit */
|
|
44
|
+
export interface UndoEntry {
|
|
45
|
+
actions: UndoAction[];
|
|
46
|
+
beforeCursor: CursorState | null;
|
|
47
|
+
afterCursor: CursorState | null;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { UndoAction, UndoEntry, CursorState } from "./types";
|
|
2
|
+
export interface UndoManagerOptions {
|
|
3
|
+
/** Maximum entries in the undo stack (default 200) */
|
|
4
|
+
maxEntries?: number;
|
|
5
|
+
/** Max ms between content changes on the same block to merge them (default 500) */
|
|
6
|
+
mergeWindow?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Transaction-aware undo/redo history manager.
|
|
10
|
+
*
|
|
11
|
+
* Records individual actions or compound groups (e.g., block split = content
|
|
12
|
+
* change + block add). Consecutive content changes on the same block within
|
|
13
|
+
* `mergeWindow` ms are automatically coalesced into a single entry.
|
|
14
|
+
*/
|
|
15
|
+
export declare class UndoManager {
|
|
16
|
+
private undoStack;
|
|
17
|
+
private redoStack;
|
|
18
|
+
private readonly maxEntries;
|
|
19
|
+
private readonly mergeWindow;
|
|
20
|
+
private compoundActions;
|
|
21
|
+
private compoundBeforeCursor;
|
|
22
|
+
constructor(options?: UndoManagerOptions);
|
|
23
|
+
/** Start grouping actions into a single compound entry */
|
|
24
|
+
beginGroup(beforeCursor: CursorState | null): void;
|
|
25
|
+
/** Whether a compound group is currently active */
|
|
26
|
+
get isGrouping(): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Record an undoable action.
|
|
29
|
+
*
|
|
30
|
+
* If a compound group is active, the action is appended to the group.
|
|
31
|
+
* Otherwise, consecutive content changes on the same block within
|
|
32
|
+
* `mergeWindow` are merged into the last entry.
|
|
33
|
+
*/
|
|
34
|
+
record(action: UndoAction, beforeCursor: CursorState | null, afterCursor: CursorState | null): void;
|
|
35
|
+
/** End compound group and push as a single entry */
|
|
36
|
+
endGroup(afterCursor: CursorState | null): void;
|
|
37
|
+
private pushEntry;
|
|
38
|
+
/** Pop the last undo entry. Returns null if nothing to undo. */
|
|
39
|
+
popUndo(): UndoEntry | null;
|
|
40
|
+
/** Pop the last redo entry. Returns null if nothing to redo. */
|
|
41
|
+
popRedo(): UndoEntry | null;
|
|
42
|
+
canUndo(): boolean;
|
|
43
|
+
canRedo(): boolean;
|
|
44
|
+
clear(): void;
|
|
45
|
+
get undoSize(): number;
|
|
46
|
+
get redoSize(): number;
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon utilities — thin wrapper around lucide icon definitions.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { iconHtml, X, Plus } from "../util/icons";
|
|
6
|
+
* el.innerHTML = iconHtml(X, 14);
|
|
7
|
+
*/
|
|
8
|
+
import type { IconNode } from "lucide";
|
|
9
|
+
export { Check, ChevronDown, CircleCheckBig, ChevronsLeft, ChevronsRight, Clipboard, ClipboardPaste, ClockFading, ClockPlus, Code, Copy, GripVertical, Heading1, Heading2, Heading3, Heading4, History, Image, Link, List, ListChecks, ListOrdered, Pause, Pencil, Pilcrow, Play, Plus, Repeat2, Scissors, Sparkles, TextQuote, Trash2, Ban, X, } from "lucide";
|
|
10
|
+
/**
|
|
11
|
+
* Return an HTML string for a lucide icon (for innerHTML contexts).
|
|
12
|
+
*/
|
|
13
|
+
export declare function iconHtml(def: IconNode, size?: number, attrs?: Record<string, string>): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a unique block ID using UUID v4.
|
|
3
|
+
*
|
|
4
|
+
* Uses `crypto.randomUUID()` when available (all modern browsers and
|
|
5
|
+
* Node 19+). Falls back to a manual implementation for older runtimes
|
|
6
|
+
* (e.g. jsdom in tests).
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateId(): string;
|
|
9
|
+
/** Validate whether a string is a valid UUID v4 */
|
|
10
|
+
export declare function isUUID(id: string): boolean;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { BlockController } from "../block";
|
|
2
|
+
export interface BlockViewportOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Number of pixels above/below the viewport to keep blocks fully active
|
|
5
|
+
* (listeners attached, content visible). Defaults to 1x viewport height,
|
|
6
|
+
* giving a total active zone of ~3x the viewport (1 above + visible + 1 below).
|
|
7
|
+
*
|
|
8
|
+
* Blocks outside this zone are *ejected*: listeners detached and the
|
|
9
|
+
* browser skips painting via `content-visibility: hidden`. The DOM stays
|
|
10
|
+
* intact so the container height is perfectly preserved — zero layout shift.
|
|
11
|
+
*/
|
|
12
|
+
bufferPx?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Estimated height in px for blocks whose content has not yet been
|
|
15
|
+
* rendered. Used as `minHeight` on the container to maintain scroll
|
|
16
|
+
* position stability. Default: 32
|
|
17
|
+
*/
|
|
18
|
+
estimatedBlockHeight?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Manages virtual rendering of blocks using IntersectionObserver.
|
|
22
|
+
*
|
|
23
|
+
* Two-tier lifecycle:
|
|
24
|
+
*
|
|
25
|
+
* 1. **First mount** — Block has never been rendered. When it enters the
|
|
26
|
+
* buffer zone, `mountContent()` is called to run the plugin's `render()`
|
|
27
|
+
* and attach listeners. This is the only transition that may cause a
|
|
28
|
+
* layout shift (estimated height → real height); it is compensated
|
|
29
|
+
* with a scroll anchor.
|
|
30
|
+
*
|
|
31
|
+
* 2. **Eject / Restore** — Once rendered, blocks are never unmounted.
|
|
32
|
+
* When they leave the buffer, `ejectContent()` detaches listeners and
|
|
33
|
+
* sets `content-visibility: hidden` (browser skips painting but
|
|
34
|
+
* remembers the size). When they re-enter, `restoreContent()` reverses
|
|
35
|
+
* this. Because the DOM is untouched, there is zero layout shift.
|
|
36
|
+
*
|
|
37
|
+
* When IntersectionObserver is unavailable (e.g. jsdom in tests), all blocks
|
|
38
|
+
* are mounted immediately, preserving existing behavior.
|
|
39
|
+
*/
|
|
40
|
+
export declare class BlockViewport {
|
|
41
|
+
private observer;
|
|
42
|
+
private controllers;
|
|
43
|
+
private forceMounted;
|
|
44
|
+
/** Measured content heights — used as `minHeight` for blocks that have
|
|
45
|
+
* never been rendered, so first-mount layout shifts are minimized. */
|
|
46
|
+
private heightCache;
|
|
47
|
+
private readonly blocksContainer;
|
|
48
|
+
private readonly estimatedHeight;
|
|
49
|
+
private readonly hasIO;
|
|
50
|
+
/** Guard against re-entrant intersection callbacks caused by scrollBy */
|
|
51
|
+
private handlingIntersection;
|
|
52
|
+
/** Callback invoked after a batch of blocks is mounted by the viewport */
|
|
53
|
+
onContentMounted: ((blockId: string) => void) | null;
|
|
54
|
+
constructor(container: HTMLElement, options?: BlockViewportOptions);
|
|
55
|
+
/**
|
|
56
|
+
* Register a block controller with the viewport manager.
|
|
57
|
+
* If IntersectionObserver is available, the block is observed and content
|
|
58
|
+
* is mounted lazily. Otherwise, content is mounted immediately.
|
|
59
|
+
*/
|
|
60
|
+
register(controller: BlockController): void;
|
|
61
|
+
/**
|
|
62
|
+
* Register multiple block controllers in a single batch.
|
|
63
|
+
* More efficient than individual register() calls during initial load.
|
|
64
|
+
*/
|
|
65
|
+
registerBatch(controllers: BlockController[]): void;
|
|
66
|
+
/** Unregister a block and stop observing it */
|
|
67
|
+
unregister(blockId: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* Ensure a block's content is mounted and active (e.g., before focusing
|
|
70
|
+
* or searching). The block is also marked as force-mounted so it won't
|
|
71
|
+
* be ejected when scrolling away.
|
|
72
|
+
*/
|
|
73
|
+
ensureMounted(blockId: string): void;
|
|
74
|
+
/**
|
|
75
|
+
* Remove the force-mount flag from a block. If the block is outside the
|
|
76
|
+
* viewport buffer, it may be ejected on the next intersection check.
|
|
77
|
+
*/
|
|
78
|
+
releaseForceMounted(blockId: string): void;
|
|
79
|
+
/** Whether a block is currently content-mounted */
|
|
80
|
+
isContentMounted(blockId: string): boolean;
|
|
81
|
+
/** Whether a block is force-mounted (won't be ejected by intersection) */
|
|
82
|
+
isForceMounted(blockId: string): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Synchronously mount content for all blocks currently visible in the
|
|
85
|
+
* viewport. Call this after the initial block load to avoid a flash of
|
|
86
|
+
* empty containers.
|
|
87
|
+
*/
|
|
88
|
+
mountInitialViewport(): void;
|
|
89
|
+
/**
|
|
90
|
+
* Ensure a block is mounted, then scroll its container into view.
|
|
91
|
+
*/
|
|
92
|
+
scrollIntoView(blockId: string, behavior?: ScrollBehavior): void;
|
|
93
|
+
/**
|
|
94
|
+
* Recalculate the average height from measured blocks and apply it to
|
|
95
|
+
* all never-rendered block placeholders.
|
|
96
|
+
*/
|
|
97
|
+
private updateEstimatedHeights;
|
|
98
|
+
destroy(): void;
|
|
99
|
+
/** Check if an element is within the viewport (synchronous fallback) */
|
|
100
|
+
private isInViewport;
|
|
101
|
+
private handleIntersection;
|
|
102
|
+
/**
|
|
103
|
+
* Find a block container visible in the viewport to use as a scroll anchor.
|
|
104
|
+
*/
|
|
105
|
+
private pickScrollAnchor;
|
|
106
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inkami/blx",
|
|
3
|
+
"version": "0.17.3",
|
|
4
|
+
"description": "A block-based editor library",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"style.css"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/blx.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/blx.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./style.css": "./style.css"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"registry": "https://registry.npmjs.org",
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"lucide": "^0.575.0",
|
|
26
|
+
"prismjs": "^1.30.0"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@automerge/automerge": "^3.0.0",
|
|
30
|
+
"mermaid": "^11.0.0",
|
|
31
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
32
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
33
|
+
"@excalidraw/excalidraw": ">=0.18.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependenciesMeta": {
|
|
36
|
+
"@automerge/automerge": {
|
|
37
|
+
"optional": true
|
|
38
|
+
},
|
|
39
|
+
"mermaid": {
|
|
40
|
+
"optional": true
|
|
41
|
+
},
|
|
42
|
+
"react": {
|
|
43
|
+
"optional": true
|
|
44
|
+
},
|
|
45
|
+
"react-dom": {
|
|
46
|
+
"optional": true
|
|
47
|
+
},
|
|
48
|
+
"@excalidraw/excalidraw": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/prismjs": "^1.26.5",
|
|
54
|
+
"jsdom": "^28.0.0",
|
|
55
|
+
"typescript": "^5.9.3",
|
|
56
|
+
"vite": "^7.3.1",
|
|
57
|
+
"vite-plugin-wasm": "^3.5.0",
|
|
58
|
+
"vitest": "^4.0.18"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "vite build && pnpm run build:types",
|
|
62
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
63
|
+
"test": "vitest run",
|
|
64
|
+
"test:watch": "vitest"
|
|
65
|
+
}
|
|
66
|
+
}
|