import Big from "big.js"; export type PixelUnit = `${number}px`; export type PercentUnit = `${number}%`; export type Unit = PixelUnit | PercentUnit; export type Orientation = "horizontal" | "vertical"; export interface ParsedPercentUnit { type: "percent"; value: Big.Big; } export interface ParsedPixelUnit { type: "pixel"; value: Big.Big; } export type ParsedUnit = ParsedPercentUnit | ParsedPixelUnit; export declare function makePercentUnit(value: number): ParsedPercentUnit; export declare function makePixelUnit(value: number): ParsedPixelUnit; interface MoveMoveEvent { shiftKey: boolean; ctrlKey: boolean; metaKey: boolean; altKey: boolean; deltaX: number; deltaY: number; } export interface Constraints { /** The minimum size of the panel */ min?: T; /** The maximum size of the panel */ max?: T; /** The default size of the panel */ default?: T; /** Whether the panel is collapsible */ collapsible?: boolean; /** Whether the panel should initially render as collapsed */ defaultCollapsed?: boolean; /** The size of the panel once collapsed */ collapsedSize?: T; /** * By default the layout will be stored in percentage values while at rest. * This makes scaling the layout easier when the container is resized. * However you might have a panel you want to stay at a static size when * the container is resized. */ isStaticAtRest?: boolean; } interface Order { /** * When dynamically rendering panels/handles you need to add the order prop. * This tells the component what place the items should be in once rendered. */ order?: number; } export interface PanelData extends Omit, Required>, Order { max: ParsedUnit | "1fr"; type: "panel"; id: string; /** Whether the collapsed state is controlled by the consumer or not */ collapseIsControlled?: boolean; /** A ref to the latest "collapseChange" function provided by the user */ onCollapseChange?: { current: ((isCollapsed: boolean) => void) | null | undefined; }; /** A ref to the latest "onResize" function provided by the user */ onResize?: { current: OnResizeCallback | null | undefined; }; /** * The current value for the item in the grid */ currentValue: ParsedUnit; /** Whether the panel is currently collapsed */ collapsed: boolean | undefined; /** * The size the panel was before being collapsed. * This is used to re-open the panel at the same size. * If the panel starts out collapsed it will use the `min`. */ sizeBeforeCollapse: number | undefined; /** Animate the collapse/expand */ collapseAnimation?: CollapseAnimation | { duration: number; easing: CollapseAnimation | ((t: number) => number); }; lastKnownSize?: Rect; } /** Copied from https://github.com/d3/d3-ease */ declare const collapseAnimations: { "ease-in-out": (t: number) => number; bounce: (t: number) => number; linear: (t: number) => number; }; type CollapseAnimation = keyof typeof collapseAnimations; export interface PanelHandleData extends Order { type: "handle"; id: string; /** * The size of the panel handle. * Needed to correctly calculate the percentage of modified panels. */ size: ParsedPixelUnit; } export type Item = PanelData | PanelHandleData; interface RegisterPanelEvent { /** Register a new panel with the state machine */ type: "registerPanel"; data: Omit; } interface RebindPanelCallbacksEvent { /** Rebind the panel callbacks */ type: "rebindPanelCallbacks"; data: Pick; } interface UpdateConstraintsEvent { /** Update the constraints of a panel */ type: "updateConstraints"; data: Pick | Pick; } interface RegisterDynamicPanelEvent extends Omit { /** Register a new panel with the state machine */ type: "registerDynamicPanel"; } interface UnregisterPanelEvent { /** Remove a panel from the state machine */ type: "unregisterPanel"; id: string; } export type InitializePanelHandleData = Omit & { size: PixelUnit; }; interface RegisterPanelHandleEvent { /** Register a new panel handle with the state machine */ type: "registerPanelHandle"; data: PanelHandleData; } interface UnregisterPanelHandleEvent { /** Remove a panel handle from the state machine */ type: "unregisterPanelHandle"; id: string; } interface DragHandleStartEvent { /** Start a drag interaction */ type: "dragHandleStart"; /** The handle being interacted with */ handleId: string; } interface DragHandleEvent { /** Update the layout according to how the handle moved */ type: "dragHandle"; /** The handle being interacted with */ handleId: string; value: MoveMoveEvent; } interface DragHandleEndEvent { /** End a drag interaction */ type: "dragHandleEnd"; /** The handle being interacted with */ handleId: string; } export interface Rect { width: number; height: number; } interface SetSizeEvent { /** Set the size of the whole group */ type: "setSize"; size: Rect; } interface SetActualItemsSizeEvent { /** Set the size of the whole group */ type: "setActualItemsSize"; childrenSizes: Record; } interface ApplyDeltaEvent { type: "applyDelta"; delta: number; handleId: string; panelId: string; } interface SetOrientationEvent { /** Set the orientation of the group */ type: "setOrientation"; orientation: Orientation; } interface ControlledCollapseToggle { /** * This is used to react to the controlled panel "collapse" prop updating. * This will force an update to be applied and skip calling the user's `onCollapseChanged` */ controlled?: boolean; } interface CollapsePanelEvent extends ControlledCollapseToggle { /** Collapse a panel */ type: "collapsePanel"; /** The panel to collapse */ panelId: string; resolve?: () => void; } interface ExpandPanelEvent extends ControlledCollapseToggle { /** Expand a panel */ type: "expandPanel"; /** The panel to expand */ panelId: string; resolve?: () => void; } interface UpdateItemIndexEvent { /** Update the index of a panel */ type: "updateItemIndex"; /** The panel to update */ itemId: string; /** The new index of the panel */ index: number; } interface SetPanelPixelSizeEvent { /** * This event is used by the imperative panel API. * With this the user can set the panel's size to an explicit value. * This is done by faking interaction with the handles so min/max will still * be respected. */ type: "setPanelPixelSize"; /** The panel to apply the size to */ panelId: string; /** The size to apply to the panel */ size: Unit; } export interface GroupMachineContextValue { /** The items in the group */ items: Array; /** The available space in the group */ size: Rect; /** The orientation of the grid */ orientation: Orientation; /** How much the drag has overshot the handle */ dragOvershoot: Big.Big; /** The id of the handle that is currently being dragged */ activeDragHandleId?: string; groupId: string; /** * How to save the persisted state */ autosaveStrategy?: "localStorage" | "cookie"; /** * The amount to move the drag handle when shift is held down. * @default 15px */ shiftAmount?: number; } interface LockGroupEvent { type: "lockGroup"; } interface UnlockGroupEvent { type: "unlockGroup"; } export type GroupMachineEvent = RegisterPanelEvent | RegisterDynamicPanelEvent | UnregisterPanelEvent | RegisterPanelHandleEvent | UnregisterPanelHandleEvent | DragHandleEvent | SetSizeEvent | SetOrientationEvent | DragHandleStartEvent | DragHandleEndEvent | CollapsePanelEvent | ExpandPanelEvent | SetPanelPixelSizeEvent | ApplyDeltaEvent | SetActualItemsSizeEvent | RebindPanelCallbacksEvent | UpdateConstraintsEvent | LockGroupEvent | UnlockGroupEvent | UpdateItemIndexEvent; export declare function getCursor(context: Pick): "w-resize" | "e-resize" | "ew-resize" | "n-resize" | "s-resize" | "ns-resize"; export declare function prepareSnapshot(snapshot: GroupMachineContextValue): GroupMachineContextValue | undefined; /** Determine if an item is a panel */ export declare function isPanelData(value: unknown): value is PanelData; /** Determine if an item is a panel handle */ export declare function isPanelHandle(value: unknown): value is PanelHandleData; type OnResizeSize = { pixel: number; percentage: number; }; export type OnResizeCallback = (size: OnResizeSize) => void; type InitializePanelOptions = { min?: Unit; max?: Unit; default?: Unit; collapsedSize?: Unit; id?: string; } & Partial>; type InitializePanelOptionsWithId = InitializePanelOptions & { id: string; }; export declare function initializePanel(item: InitializePanelOptionsWithId): PanelData; export declare function initializePanel(item: InitializePanelOptions): Omit; export declare function haveConstraintsChangedForPanel(a: Omit, b?: Omit): boolean; export declare function haveConstraintsChangedForPanelHandle(a: Omit, b?: Omit): boolean; export declare function initializePanelHandleData(item: InitializePanelHandleData): { size: ParsedPixelUnit; id: string; order?: number | undefined; type: "handle"; }; /** Parse a `Unit` string or `clamp` value */ export declare function parseUnit(unit: Unit | "1fr"): ParsedUnit; /** Convert a `Unit` to a percentage of the group size */ export declare function getUnitPercentageValue(groupsSize: number, unit: ParsedUnit): number; export declare function getGroupSize(context: GroupMachineContextValue): number; /** Get a panel with a particular ID. */ export declare function getPanelWithId(context: GroupMachineContextValue, panelId: string): PanelData; /** * Get the panel that's collapsible next to a resize handle. * Will first check the left panel then the right. */ export declare function getCollapsiblePanelForHandleId(context: GroupMachineContextValue, handleId: string): PanelData; export declare function formatUnit(unit: ParsedUnit): Unit; export declare function getPanelGroupPixelSizes(context: GroupMachineContextValue): number[]; export declare function getPanelPixelSize(context: GroupMachineContextValue, panelId: string): number; export declare function getPanelGroupPercentageSizes(context: GroupMachineContextValue): number[]; export declare function getPanelPercentageSize(context: GroupMachineContextValue, panelId: string): number; /** Build the grid template from the item values. */ export declare function buildTemplate(context: GroupMachineContextValue): string; /** * This is the main meat of the layout logic. * It's responsible for figuring out how to distribute the space * amongst the panels. * * It's built around applying small deltas to panels relative to their * the resize handles. * * As much as possible we try to rely on the browser to do the layout. * During the initial layout we rely on CSS grid and a group might be * defined like this: * * ```css * grid-template-columns: minmax(100px, 1fr) 1px minmax(100px, 300px); * ``` * * Without any resizing this is nice and simple and the components don't do much. * * Once the user starts resizing the layout will be more complex. * * It's broken down into 3 phases: * * 1. `prepareItems` - The size of the group has been measure and we * can convert all the panel sizes into pixels. Converting into pixels * makes doing the math for the updates easier. * * ```css * grid-template-columns: 500px 1px 300px; * ``` * * 2. `updateLayout` - This is where the actual updates are applied. * This is where the user's drag interactions are applied. We also * use this to collapse/expand panels by simulating a drag interaction. * * ```css * grid-template-columns: 490px 1px 310px; * ``` * * 3. `commitLayout` - Once the updates have been applied we convert the * updated sizes back into a format that allows for easy resizing without * lots of updates. * * ```css * grid-template-columns: minmax(100px, min(calc(0.06117 * (100% - 1px)), 100%)) 1px minmax(100px, min(calc(0.0387 * (100% - 1px)), 300px)); * ``` * * When another update loop is triggered the above template will be converted back to pixels. */ /** Converts the items to pixels */ export declare function prepareItems(context: GroupMachineContextValue): Item[]; export declare function dragHandlePayload({ delta, orientation, shiftKey, }: { delta: number; orientation?: Orientation; shiftKey?: boolean; }): { readonly type: "move"; readonly pointerType: "keyboard"; readonly shiftKey: boolean; readonly ctrlKey: false; readonly altKey: false; readonly metaKey: false; readonly deltaX: number; readonly deltaY: number; }; export interface GroupMachineInput { orientation?: Orientation; groupId: string; items?: Item[]; autosaveStrategy?: "localStorage" | "cookie"; shiftAmount?: number; } export type State = "idle" | "dragging" | "togglingCollapse"; export declare function groupMachine(input: Partial, onUpdate?: (context: GroupMachineContextValue) => void, /** * A lazy getter for the group's DOM element. When provided and it returns * an element, `applyDelta` frames during collapse/expand animations write * the grid template directly to the DOM and skip `onUpdate` — avoiding a * full reactive re-render per animation frame. Other events still call * `onUpdate` as usual. */ getGroupElement?: () => HTMLElement | null): readonly [GroupMachineContextValue, (event: GroupMachineEvent) => void, { current: State; }]; export type SendFn = ReturnType[1]; export {}; //# sourceMappingURL=index.d.ts.map