@runstack/ui
Version:
React UI components library for runstack
211 lines (200 loc) • 8.91 kB
TypeScript
import * as react_jsx_runtime from 'react/jsx-runtime';
import * as React from 'react';
import { ReactNode } from 'react';
import { ClassValue } from 'clsx';
type DraggableItem = {
sync_id: string;
rank: bigint;
title: string;
parent_id?: string | null | undefined;
};
/**
* Gets all direct children of a specific item.
* Returns children sorted by rank in ascending order.
*/
declare function getChildren<Item extends DraggableItem>(id: string, items: Item[]): Item[];
/**
* Gets all siblings of a specific item (items with the same parent).
* Returns siblings sorted by rank in ascending order.
*/
declare function getSiblings<Item extends DraggableItem>(id: string | "root", items: Item[]): Item[];
/**
* Gets the previous sibling of an item.
* Returns undefined if the item is the first sibling.
*/
declare function getPreviousSibling(id: string, items: DraggableItem[]): DraggableItem | undefined;
/**
* Gets all descendants (children, grandchildren, etc.) of a specific item.
* Returns all descendants in depth-first order.
*/
declare function getAllDescendants(id: string, items: DraggableItem[]): DraggableItem[];
/**
* Gets all root items (items with no parent).
* Returns all root items in depth-first order.
*/
declare function getRootItems<Item extends DraggableItem>(items: Item[]): Item[];
/**
* Calculates the updates needed to increase an item's indentation level.
* Makes the item a child of its previous sibling and recalculates ranks for all affected items.
*
* @param item - The item to increase indentation for
* @param items - Array of all items in the tree
* @returns Array of items that need to be updated with new ranks and parent relationships
*
* @example
* ```typescript
* // Before: [A, B, C] -> After: [A, B -> C]
* const updates = calculateIndentIncrease(itemC, allItems);
* // Returns updates for itemC with new parent_id = itemB._id
* ```
*
* Algorithm:
* 1. Finds the previous sibling of the target item
* 2. If no previous sibling exists, returns empty array (can't indent)
* 3. Makes the target item a child of the previous sibling
* 4. Recalculates ranks for all children of the previous sibling (including new child)
* 5. Uses ENTRY_GAP (100,000) spacing between ranks for efficient insertion
*/
declare function calculateIndentIncrease<Item extends DraggableItem>(item: Item, items?: Item[]): Item[];
/**
* Calculates the updates needed to decrease an item's indentation level.
* Promotes the item to be a sibling of its current parent and recalculates ranks for all affected items.
*
* @param item - The item to decrease indentation for
* @param items - Array of all items in the tree
* @returns Array of items that need to be updated with new ranks and parent relationships
*
* @example
* ```typescript
* // Before: [A -> B -> C] -> After: [A -> B, C]
* const updates = calculateIndentDecrease(itemC, allItems);
* // Returns updates for itemC with parent_id = itemA._id (same as itemB's parent)
* ```
*
* Algorithm:
* 1. Finds the parent of the target item
* 2. If no parent exists, returns empty array (already at root level)
* 3. Promotes the item to be a sibling of its current parent
* 4. Places the item immediately after its parent in the sibling order
* 5. Recalculates ranks for all siblings at the parent's level
* 6. Uses ENTRY_GAP (100,000) spacing between ranks for efficient insertion
*/
declare function calculateIndentDecrease<Item extends DraggableItem>(item: Item, items?: Item[]): Item[];
/**
* Flattens a tree structure into a pre-order traversal mapping.
* Used for calculating animation delays and determining render order.
*
* @param tree - Array of all items in the tree
* @returns Record mapping item IDs to their flat index position
*
* @example
* ```typescript
* // Tree structure: A -> [B, C], D -> [E]
* const flattened = flattenTreePreorder(items);
* // Returns: { A: 0, B: 1, C: 2, D: 3, E: 4 }
* ```
*
* Algorithm:
* 1. Sorts all items by rank to ensure consistent ordering
* 2. Performs pre-order traversal (parent first, then children)
* 3. Assigns incremental indices to each item in traversal order
* 4. Returns mapping of item ID to flat index for animation calculations
*/
declare function flattenTreePreorder<Item extends DraggableItem>(tree: Item[]): Record<string, number>;
/**
* Gap between consecutive item ranks in the tree structure.
*
* This large gap (100,000) allows for efficient insertion of new items
* between existing ones without requiring rank recalculation of many items.
*
* Example rank sequence: 0, 100000, 200000, 300000...
* To insert between ranks 100000 and 200000, we can use 150000.
*/
declare const ENTRY_GAP = 100000;
type DraggableListState = {
index: number;
level: number;
focusItemId: string;
updateFocusItemId: (value: string) => void;
};
type AddEntryPayload<Item extends DraggableItem> = {
rank: bigint;
parent_id: Item["parent_id"] | null;
title: string;
};
type AddEntryFn<Item extends DraggableItem> = (payload: AddEntryPayload<Item>, item: Item, context: DraggableListContextType<Item>) => void;
type DraggableListContextType<Item extends DraggableItem = DraggableItem> = {
items: Item[];
renderProps: (item: Item, state: DraggableListState) => React.ReactNode;
currentItem?: Item;
hasAnimated: boolean;
updateHasAnimated: (value: boolean) => void;
updateTitle: (id: Item["sync_id"], title: string) => void;
updateTree: (updates: DraggableItem[]) => void;
onAddEntry: AddEntryFn<Item>;
} & DraggableListState;
declare const useDraggableListContext: <Item extends DraggableItem>() => DraggableListContextType<Item>;
type DraggableListProviderProps<Item extends DraggableItem> = {
children: (item: Item, state: DraggableListState, context: DraggableListContextType<Item>) => React.ReactNode;
data: Item[];
onDrop?: (updates: Item[]) => void;
onTitleChange?: (id: Item["sync_id"], title: string) => void;
onTreeChange?: (updates: Item[]) => void;
/**
* onAddEntry is called with the payload and the current item being added.
* This allows for more granular control over the payload and item being added.
* @param payload - The payload object passed to the mutation
* @param item - The current item the addEntry was triggered on
* */
onAddEntry?: AddEntryFn<Item>;
_animationKey?: string;
};
declare const DraggableListProvider: <Item extends DraggableItem>(props: DraggableListProviderProps<Item>) => react_jsx_runtime.JSX.Element;
type DraggableListMainProps = {
children: React.ReactNode;
className?: string;
};
declare const DraggableListMain: (props: DraggableListMainProps) => react_jsx_runtime.JSX.Element;
type DraggableListItemProps = {
children: React.ReactNode;
className?: string;
};
declare const DraggableListItem: (props: DraggableListItemProps) => react_jsx_runtime.JSX.Element;
type DraggableListItemStartProps = {
children: React.ReactNode;
className?: string;
};
declare const DraggableListItemStart: (props: DraggableListItemStartProps) => react_jsx_runtime.JSX.Element;
type DraggableListItemContentProps = {
children: React.ReactNode;
className?: string;
};
declare const DraggableListItemContent: (props: DraggableListItemContentProps) => react_jsx_runtime.JSX.Element;
type DraggableListItemBottomProps = {
children: React.ReactNode;
className?: string;
};
declare const DraggableListItemBottom: (props: DraggableListItemBottomProps) => react_jsx_runtime.JSX.Element;
type DraggableListItemEndProps = {
children: React.ReactNode;
className?: string;
};
declare const DraggableListItemEnd: (props: DraggableListItemEndProps) => react_jsx_runtime.JSX.Element;
type DragHandleProps = {
children: React.ReactNode;
};
declare const DragHandle: (props: DragHandleProps) => react_jsx_runtime.JSX.Element;
type DraggableListEditableTextProps = {
className?: string;
placeholder?: string;
placeholderBehaviour?: "showOnHover" | "alwaysShow";
};
declare const DraggableListEditableText: (props: DraggableListEditableTextProps) => react_jsx_runtime.JSX.Element;
interface ButtonProps {
children: ReactNode;
className?: string;
appName: string;
}
declare const Button: ({ children, className, appName }: ButtonProps) => react_jsx_runtime.JSX.Element;
declare function cn(...inputs: ClassValue[]): string;
export { type AddEntryPayload, Button, DragHandle, type DraggableItem, type DraggableListContextType, DraggableListEditableText, DraggableListItem, DraggableListItemBottom, DraggableListItemContent, DraggableListItemEnd, DraggableListItemStart, DraggableListMain, DraggableListProvider, ENTRY_GAP, calculateIndentDecrease, calculateIndentIncrease, cn, flattenTreePreorder, getAllDescendants, getChildren, getPreviousSibling, getRootItems, getSiblings, useDraggableListContext };