UNPKG

@senyao-design-system/magic-tree

Version:

A tree component implemented with Konva for handling large datasets.

179 lines (177 loc) 7.85 kB
import { default as Konva } from 'konva'; /** * Unique identifier for a tree node. */ export type TreeNodeId = string | number; /** * Represents a single item in the action menu for a tree node. */ export interface NodeActionMenuItem<T = Record<string, unknown>> { /** Unique key for the menu item. */ readonly key: string; /** Text label to display for the menu item. */ readonly label: string; /** Optional Konva shape or ReactNode to display as an icon. */ readonly icon?: React.ReactNode; /** Callback executed when the menu item is clicked. */ readonly onClick: (node: TreeNodeData<T>) => void; /** Optional: Indicates if the menu item should be disabled. */ readonly disabled?: boolean; } /** * Defines the structure for a node icon. */ export type NodeIconType = 'image' | 'html' | 'konva'; export interface NodeIcon { readonly type: NodeIconType; readonly content: any; readonly width?: number; readonly height?: number; } /** * Represents the data structure for a single node in the tree. * @template T - The type of custom data associated with the node. */ export interface TreeNodeData<T = Record<string, unknown>> { /** Unique ID of the node. */ readonly id: TreeNodeId; /** Label or text to display for the node. */ readonly label: string; /** Child nodes. */ readonly children?: ReadonlyArray<TreeNodeData<T>>; /** Custom data associated with the node. */ readonly data?: T; /** Indicates if this node can load children asynchronously. */ readonly hasAsyncChildren?: boolean; /** Optional: Icon to display for the node. */ readonly icon?: NodeIcon; } /** * Props for the main MagicTree component. * @template T - The type of custom data associated with each tree node. */ export interface MagicTreeProps<T = Record<string, unknown>> { /** The array of tree node data to render. */ readonly data: ReadonlyArray<TreeNodeData<T>>; /** Set of IDs for currently expanded nodes. */ readonly expandedKeys: ReadonlyArray<TreeNodeId>; /** Callback function invoked when a node's expanded state is toggled. */ readonly onExpand: (nodeIdList: ReadonlyArray<TreeNodeId>) => void; /** Height of each node in pixels. Essential for virtualization. */ readonly nodeHeight: number; /** Width of the tree container. */ readonly width?: number; /** Height of the tree container. */ readonly height?: number; /** * Optional custom render function for a node's content (excluding expand/collapse icon and indentation). * If not provided, a default renderer will be used. */ readonly renderNodeContent?: (props: NodeContentRenderProps<T>) => React.ReactNode; readonly icon?: (props: FlattenedTreeNode<T>) => React.ReactNode; /** Callback function when a node is clicked. */ readonly onNodeClick?: (node: TreeNodeData<T>, event: Konva.KonvaEventObject<MouseEvent>) => void; /** Callback function when a node is hovered. */ readonly onNodeHover?: (node: TreeNodeData<T> | null, event: Konva.KonvaEventObject<MouseEvent> | null) => void; /** * Callback function to load children for a node asynchronously. * The parent component is responsible for fetching the data and updating the main 'data' prop. * The MagicTree component will manage the loading state internally based on this promise. */ readonly onLoadData?: (node: TreeNodeData<T>) => Promise<void>; /** * Optional function to provide action menu items for a given node. * Return an array of MenuItem objects or null/undefined to show no menu. */ readonly renderRowActionMenu?: (node: TreeNodeData<T>) => ReadonlyArray<NodeActionMenuItem<T>> | null | undefined; /** Optional: Callback when a drag gesture is initiated on a node. */ readonly onNodeDragStart?: (event: NodeDragStartEvent<T>) => void; /** Optional: Callback when a node is being dragged. */ readonly onNodeDragMove?: (event: NodeDragMoveEvent<T>) => void; /** Optional: Callback when a drag gesture ends for a node. */ readonly onNodeDragEnd?: (event: NodeDragEndEvent<T>) => void; /** * Optional configuration for displaying tooltips on node hover. * - If `true`, a default tooltip showing the node label will be used. * - If a function, it will be called with the node data and should return the tooltip content (string or ReactNode). * - If `false` or undefined, no tooltip will be shown. */ readonly showNodeTooltip?: boolean | ((node: TreeNodeData<T>) => React.ReactNode | string); readonly iconSize?: number; } /** Defines the event payload for onNodeDragStart. */ export interface NodeDragStartEvent<T = Record<string, unknown>> { /** The node data being dragged. */ readonly node: TreeNodeData<T>; /** The pointer position relative to the Konva stage at the start of the drag. */ readonly pointerPosition: { readonly x: number; readonly y: number; }; /** The raw mouse event that initiated the drag. */ readonly rawEvent: MouseEvent; } /** Defines the event payload for onNodeDragMove. */ export interface NodeDragMoveEvent<T = Record<string, unknown>> { /** The node data being dragged. */ readonly node: TreeNodeData<T>; /** The current pointer position relative to the Konva stage. */ readonly pointerPosition: { readonly x: number; readonly y: number; }; /** The change in pointer position from the start of the drag. */ readonly delta: { readonly x: number; readonly y: number; }; /** The raw mouse event. */ readonly rawEvent: MouseEvent; } /** Defines the event payload for onNodeDragEnd. */ export interface NodeDragEndEvent<T = Record<string, unknown>> { /** The node data that was being dragged. */ readonly node: TreeNodeData<T>; /** The raw mouse event that ended the drag. */ readonly rawEvent: MouseEvent; } /** * Props passed to the custom `renderNodeContent` function. * @template T - The type of custom data associated with the tree node. */ export interface NodeContentRenderProps<T = Record<string, unknown>> { /** The data for the node being rendered (original TreeNodeData). */ readonly node: TreeNodeData<T>; /** Current depth of the node in the tree (0-indexed). */ readonly depth: number; /** Indicates if the node is currently expanded. */ readonly isExpanded: boolean; /** Indicates if the node has children (either already loaded or loadable). */ readonly hasChildren: boolean; /** Indicates if the node is currently hovered. */ readonly isHovered: boolean; /** Indicates if the node is currently loading children (managed by MagicTree). */ readonly isLoading: boolean; /** Default x offset for the content (after icon and indentation). */ readonly contentX: number; /** Default y offset for the content. */ readonly contentY: number; /** Available width for the content area. */ readonly contentWidth: number; /** Available height for the content area. */ readonly contentHeight: number; } /** * Internal representation of a flattened node, used for rendering and virtualization. * @template T - The type of custom data associated with the tree node. */ export interface FlattenedTreeNode<T = Record<string, unknown>> extends Omit<TreeNodeData<T>, 'isLoading'> { /** Depth of the node in the tree (0-indexed). */ readonly depth: number; /** Y position of the node in the virtualized list. */ readonly y: number; /** Original parent ID (if any) */ readonly parentId?: TreeNodeId; /** Indicates if the node is currently expanded (if it has children). This is always defined for a flattened node. */ readonly isExpanded: boolean; }