flow-mindmap 0.1.0-beta.1

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.
@@ -0,0 +1,20 @@
1
+ import type { MindMapNode } from '../types';
2
+ type __VLS_Props = {
3
+ /** The currently selected node. `null` means nothing is
4
+ * selected; the panel renders an empty-state in that case. */
5
+ selectedNode: MindMapNode | null;
6
+ /** Disable all edit controls (read-only mode). */
7
+ readonly?: boolean;
8
+ /** Bumped by the parent (App.vue) on each select change. The
9
+ * panel uses this as a "focus the textarea" signal so the
10
+ * user can start typing immediately after picking a node. */
11
+ focusTick?: number;
12
+ };
13
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
14
+ apply: (text: string) => any;
15
+ remove: () => any;
16
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
17
+ onApply?: ((text: string) => any) | undefined;
18
+ onRemove?: (() => any) | undefined;
19
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
+ export default _default;
@@ -0,0 +1,45 @@
1
+ import type { MindMapNode } from '../types';
2
+ type __VLS_Props = {
3
+ /** Root of the mind map. */
4
+ data: MindMapNode;
5
+ /** Highlight the node with this id (the one selected on the main canvas). */
6
+ selectedId?: string | null;
7
+ /** When true, hide a node's children in the outline. */
8
+ collapsedIds?: Set<string>;
9
+ /** Read-only — disables editing / add / drag. Default false. */
10
+ readonly?: boolean;
11
+ };
12
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
13
+ select: (node: MindMapNode) => any;
14
+ edit: (payload: {
15
+ id: string;
16
+ text: string;
17
+ }) => any;
18
+ toggleCollapse: (id: string) => any;
19
+ addChild: (id: string) => any;
20
+ addSibling: (id: string) => any;
21
+ move: (payload: {
22
+ srcId: string;
23
+ targetId: string;
24
+ position: "before" | "after" | "child";
25
+ }) => any;
26
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
27
+ onSelect?: ((node: MindMapNode) => any) | undefined;
28
+ onEdit?: ((payload: {
29
+ id: string;
30
+ text: string;
31
+ }) => any) | undefined;
32
+ onToggleCollapse?: ((id: string) => any) | undefined;
33
+ onAddChild?: ((id: string) => any) | undefined;
34
+ onAddSibling?: ((id: string) => any) | undefined;
35
+ onMove?: ((payload: {
36
+ srcId: string;
37
+ targetId: string;
38
+ position: "before" | "after" | "child";
39
+ }) => any) | undefined;
40
+ }>, {
41
+ readonly: boolean;
42
+ selectedId: string | null;
43
+ collapsedIds: Set<string>;
44
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
45
+ export default _default;
@@ -0,0 +1,30 @@
1
+ import type { MindMapSettings } from '../types';
2
+ type __VLS_Props = {
3
+ settings: MindMapSettings;
4
+ /** true when a node is selected — the per-node panel is shown too. */
5
+ hasSelection: boolean;
6
+ selectedNodeText?: string;
7
+ };
8
+ /** Style overrides for a single node. Stored externally (App.vue
9
+ * holds the map) so the per-node state is preserved across
10
+ * selection changes. */
11
+ export interface NodeStyle {
12
+ /** Background colour. undefined = fall back to theme/branch. */
13
+ bg?: string;
14
+ /** Text colour. */
15
+ textColor?: string;
16
+ /** Border colour. */
17
+ borderColor?: string;
18
+ /** Font weight: 400 / 600. undefined = inherit. */
19
+ fontWeight?: 400 | 600;
20
+ }
21
+ declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
22
+ reset: () => any;
23
+ "update:settings": (s: Partial<MindMapSettings>) => any;
24
+ "update:nodeStyle": (s: Partial<NodeStyle>) => any;
25
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
26
+ onReset?: (() => any) | undefined;
27
+ "onUpdate:settings"?: ((s: Partial<MindMapSettings>) => any) | undefined;
28
+ "onUpdate:nodeStyle"?: ((s: Partial<NodeStyle>) => any) | undefined;
29
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import type { MindMapNode } from '../types';
2
+ /**
3
+ * Linear undo/redo history for the mind map.
4
+ *
5
+ * Each entry stores the data tree (full JSON snapshot).
6
+ * Snapshots are deep-cloned JSON strings (one string per state). The
7
+ * timeline is bounded so a long session doesn't grow without limit.
8
+ */
9
+ export interface HistoryState {
10
+ data: MindMapNode;
11
+ }
12
+ export declare function useHistory(maxSize?: number): {
13
+ canUndo: () => boolean;
14
+ canRedo: () => boolean;
15
+ record: (snapshot: HistoryState) => void;
16
+ undo: () => HistoryState | null;
17
+ redo: () => HistoryState | null;
18
+ reset: () => void;
19
+ };
@@ -0,0 +1,32 @@
1
+ export interface KeyboardOptions {
2
+ isEditing: () => boolean;
3
+ isReadonly: () => boolean;
4
+ getSelectedId: () => string | null;
5
+ getRootId: () => string;
6
+ /**
7
+ * Called when Tab/Enter fires and no node is selected — defaults the
8
+ * action to the root node so the user can build a tree from scratch
9
+ * without first clicking something.
10
+ */
11
+ defaultTargetId?: () => string;
12
+ onAddChild: (id: string) => void;
13
+ onAddSibling: (id: string) => void;
14
+ onAddSiblingBefore: (id: string) => void;
15
+ onRemove: (id: string) => void;
16
+ onStartEdit: (id: string) => void;
17
+ onClearSelection: () => void;
18
+ onDuplicate: (id: string) => void;
19
+ onUndo: () => void;
20
+ onRedo: () => void;
21
+ /**
22
+ * Move selection to a neighbour. Returns the new selected id (or null
23
+ * if no neighbour exists in that direction).
24
+ * dx = -1 → select first child
25
+ * dx = +1 → select parent
26
+ * dy = -1 → select previous sibling
27
+ * dy = +1 → select next sibling
28
+ */
29
+ onNavigate: (dx: number, dy: number) => void;
30
+ onSelectRoot: () => void;
31
+ }
32
+ export declare function useKeyboard(opts: KeyboardOptions): void;
@@ -0,0 +1,35 @@
1
+ import { type Ref } from 'vue';
2
+ export interface PanZoomOptions {
3
+ minScale?: number;
4
+ maxScale?: number;
5
+ step?: number;
6
+ getContainer: () => HTMLElement | null;
7
+ }
8
+ export interface MarqueeRect {
9
+ x: number;
10
+ y: number;
11
+ width: number;
12
+ height: number;
13
+ }
14
+ export declare function usePanZoom(opts: PanZoomOptions): {
15
+ scale: Ref<number, number>;
16
+ offsetX: Ref<number, number>;
17
+ offsetY: Ref<number, number>;
18
+ isPanning: Ref<boolean, boolean>;
19
+ onWheel: (e: WheelEvent) => void;
20
+ zoomIn: () => void;
21
+ zoomOut: () => void;
22
+ startPan: (e: PointerEvent | MouseEvent) => void;
23
+ startMarquee: (worldX: number, worldY: number) => void;
24
+ updateMarquee: (worldX: number, worldY: number) => void;
25
+ isMarquee: Ref<boolean, boolean>;
26
+ marquee: {
27
+ x: number;
28
+ y: number;
29
+ width: number;
30
+ height: number;
31
+ };
32
+ marqueeVersion: Ref<number, number>;
33
+ setOnMarqueeEnd: (cb: (() => void) | null) => void;
34
+ resetView: (layoutWidth: number, layoutHeight: number, rootY: number, padding?: number) => void;
35
+ };
@@ -0,0 +1,98 @@
1
+ export interface LayoutNode {
2
+ id: string;
3
+ text: string;
4
+ depth: number;
5
+ x: number;
6
+ y: number;
7
+ width: number;
8
+ height: number;
9
+ /** Font size to render this node's text at, in px. */
10
+ fontSize: number;
11
+ isRoot: boolean;
12
+ collapsed?: boolean;
13
+ side: 1 | -1;
14
+ /**
15
+ * Direction this node's children fan out in: 'right' (default for
16
+ * mindmap right side / tree), 'left' (mindmap left side), or 'down'
17
+ * (org mode).
18
+ */
19
+ _dir: 'right' | 'left' | 'down';
20
+ /** Direction this node's children fan out in, as a signed scalar
21
+ * (1 = right, -1 = left). Mirrors `_dir` for callers that need
22
+ * a number. Kept in sync by applyDoLayout and forceRight — when
23
+ * the height-based balancer moves a child to the opposite side,
24
+ * the whole subtree gets its `side` / `_dir` / `_dirRight`
25
+ * re-stamped so descendants fan the right way. */
26
+ _dirRight: 1 | -1;
27
+ /** Layout-only: vertical extent of this node's subtree (post-order
28
+ * walk result, read by layoutHorizontal). Not for public use. */
29
+ _subtreeH: number;
30
+ /** Layout-only: horizontal extent of this node's subtree (read by
31
+ * layoutVertical / org mode). Not for public use. */
32
+ _subtreeW: number;
33
+ /** Optional embedded image (mirrored from MindMapNode.image).
34
+ * The renderer uses src/width/height; naturalW/H lock the
35
+ * resize aspect ratio. */
36
+ image?: MindMapImage;
37
+ /** Mirrored from MindMapNode.link. Read by the renderer to
38
+ * show a link icon next to the text. */
39
+ link?: {
40
+ url: string;
41
+ };
42
+ /** Mirrored from MindMapNode.note. Read by the renderer to
43
+ * show a note icon next to the text. */
44
+ note?: {
45
+ text: string;
46
+ };
47
+ children: LayoutNode[];
48
+ parent: LayoutNode | null;
49
+ }
50
+ import type { MindMapNode, MindMapImage } from '../types';
51
+ declare function heightAt(depth: number): number;
52
+ declare function fontAt(depth: number): number;
53
+ export type LayoutMode = 'mindmap' | 'tree' | 'org';
54
+ export interface LayoutOptions {
55
+ mode?: LayoutMode;
56
+ /** @deprecated kept for API compat; ignored in 1.html-style layout. */
57
+ balanced?: boolean;
58
+ /**
59
+ * When true, layout() leaves each LayoutNode's existing x/y in
60
+ * place — it still does the doLayout split / redirect / stack
61
+ * walk, but skips writing to child.x / child.y. Used after a
62
+ * drag: we commit the offset into the data tree, clear the
63
+ * per-node offset map, then re-run layout with this flag so
64
+ * the dragged node (and its subtree) stay where the user put
65
+ * them. The root is still forced to (0, 0) — to put the
66
+ * dragged node at a new position, the surrounding tree moves
67
+ * relative to it. New nodes added later get the algorithmic
68
+ * position since their LayoutNode has x = 0, y = 0.
69
+ */
70
+ preservePositions?: boolean;
71
+ }
72
+ export declare function layout(root: MindMapNode, options?: LayoutOptions): {
73
+ root: LayoutNode;
74
+ width: number;
75
+ height: number;
76
+ vbX: number;
77
+ vbY: number;
78
+ vbW: number;
79
+ vbH: number;
80
+ };
81
+ export declare const LAYOUT: {
82
+ /** Legacy single-size values for callers that still expect them. */
83
+ NODE_W: number;
84
+ NODE_H: number;
85
+ NODE_FONTS: number[];
86
+ NODE_HEIGHTS: number[];
87
+ NODE_MIN_W: number[];
88
+ NODE_PAD_H: number[];
89
+ NODE_FONT_WEIGHTS: number[];
90
+ H_GAP: number;
91
+ V_GAP: number;
92
+ SIDE_PADDING: number;
93
+ heightAt: typeof heightAt;
94
+ fontAt: typeof fontAt;
95
+ /** Clear the text-measurement cache (call after font load). */
96
+ clearMeasureCache: () => void;
97
+ };
98
+ export {};
@@ -0,0 +1,43 @@
1
+ export interface BranchPalette {
2
+ id: string;
3
+ name: string;
4
+ /** Hex colors cycled across top-level branches, in display order. */
5
+ colors: string[];
6
+ }
7
+ export declare const BUILTIN_PALETTES: readonly BranchPalette[];
8
+ /**
9
+ * Resolve a palette by id from a combined list of built-ins and
10
+ * user-defined custom palettes. Falls back to the default palette
11
+ * if `id` is missing or points at a deleted custom palette. Pure
12
+ * — no DOM, no reactive deps — so it can be called from a computed
13
+ * or a watch.
14
+ */
15
+ export declare function resolvePalette(id: string, customPalettes?: readonly BranchPalette[]): BranchPalette;
16
+ /**
17
+ * Parse a free-form text blob into a cleaned color array. Accepts:
18
+ *
19
+ * 1. **Hex codes** — `#rgb` / `#rgba` / `#rrggbb` / `#rrggbbaa`,
20
+ * with or without the leading `#`. The alpha channel on
21
+ * 4- or 8-digit hex is silently dropped.
22
+ * 2. **`rgb()` / `rgba()` functions** — `rgb(255, 99, 71)`,
23
+ * `rgba(255,99,71,0.5)`. Whitespace and percentage values
24
+ * are both accepted (matches CSS rules). Alpha dropped.
25
+ * 3. **CSS named colors** — the 30 most common (`red`, `tomato`,
26
+ * `coral`, `teal`, …). A small curated set keeps the parser
27
+ * from silently accepting typos that look color-ish
28
+ * (`tan`, `peru` are in; `chartreuse1` is not).
29
+ * 4. **JSON / JS array** — `['#f87171', 'red']`,
30
+ * `["#f87171","rgb(0,0,255)"]`, even a single-line
31
+ * `["red","blue"]`. Bracket and quote chars are tolerated
32
+ * so a copy-pasted `[…]` round-trips cleanly.
33
+ * 5. **Any-delimiter blob** — the parser scans the raw text for
34
+ * color-shaped substrings rather than splitting on commas,
35
+ * so a user can paste `rgb(255, 0, 0), #0f0, blue` and every
36
+ * piece lands.
37
+ *
38
+ * Malformed tokens are dropped silently (consistent with the
39
+ * rest of the canvas's "paste messy text" UX). Returns at most
40
+ * `maxColors` entries; output is lowercased `#rrggbb` for stable
41
+ * dedup and direct comparison with `BUILTIN_PALETTES`.
42
+ */
43
+ export declare function parsePaletteInput(text: string, maxColors?: number): string[];
@@ -0,0 +1,11 @@
1
+ import MindMap from './components/MindMap.vue';
2
+ import type { App } from 'vue';
3
+ import type { MindMapNode, MindMapOptions, MindMapTheme, MindMapExpose } from './types';
4
+ import { uid, clone, findNode, findParent, removeNode, addChild, addSibling } from './tree';
5
+ export type { MindMapNode, MindMapOptions, MindMapTheme, MindMapExpose };
6
+ export { MindMap };
7
+ export { uid, clone, findNode, findParent, removeNode, addChild, addSibling };
8
+ declare const plugin: {
9
+ install(app: App): void;
10
+ };
11
+ export default plugin;