@kitn.ai/ui
Version:
Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. Authored in SolidJS.
89 lines (88 loc) • 4.64 kB
TypeScript
import { JSX } from 'solid-js';
type Orientation = 'horizontal' | 'vertical';
/** A size value: a number (percent), `"25%"` (percent), or `"280px"` (pixels). */
export type SizeValue = number | string;
interface ResizableContextValue {
orientation: Orientation;
}
export declare const ResizableContext: import('solid-js').Context<ResizableContextValue | undefined>;
/**
* Normalize a px-or-% size into a CSS length string usable as `flex-basis`.
* - number → percent (`30` → `"30%"`)
* - `"25%"` → percent passthrough
* - `"280px"` → pixel passthrough
* Returns `undefined` for unset values (caller falls back to flexible `flex: 1`).
*/
export declare function normalizeSize(value: SizeValue | undefined): string | undefined;
/**
* Resolve a px-or-% size to pixels, given the container's main-axis size.
* Used to seed `data-min-size` / `data-max-size` (which the handle reads as px).
* Returns `undefined` when the value is unset.
*/
export declare function resolveToPx(value: SizeValue | undefined, containerPx: number): number | undefined;
/**
* Build a panel's INITIAL `flex-basis`, clamped into its `[min, max]` bounds so
* it never PAINTS past its max (or below its min). The drag handler already
* clamps, but only once a drag begins — without this, a percentage default on a
* wide container (e.g. `40%` against a `480px` max) renders wider than max and
* then SNAPS to max on the first resize. Uses CSS `clamp()`/`min()`/`max()` so
* the bound is enforced at layout time against the live container size, with
* MIXED units (a `%` default vs a `px` max) resolving correctly — no JS measure.
* `basis`/`min`/`max` are already-normalized CSS lengths (see `normalizeSize`);
* an undefined `basis` stays undefined → the caller falls back to flexible.
*/
export declare function clampBasis(basis: string | undefined, min: string | undefined, max: string | undefined): string | undefined;
export interface ResizablePanelGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {
orientation?: Orientation;
children: JSX.Element;
}
declare function ResizablePanelGroup(props: ResizablePanelGroupProps): JSX.Element;
export interface ResizablePanelProps extends JSX.HTMLAttributes<HTMLDivElement> {
/** Initial main-axis size: number/`"25%"` (percent) or `"280px"` (pixels). Omitted → flexible. */
defaultSize?: SizeValue;
/** Minimum size during resize (px or %). */
minSize?: SizeValue;
/** Maximum size during resize (px or %). */
maxSize?: SizeValue;
/** When true, the panel's size is fixed and adjacent handles are non-draggable. */
locked?: boolean;
/** When true, the panel is not visible (used by the `Resizable` convenience to drop dividers). */
hidden?: boolean;
children: JSX.Element;
}
declare function ResizablePanel(props: ResizablePanelProps): JSX.Element;
export interface ResizableHandleProps extends JSX.HTMLAttributes<HTMLDivElement> {
withHandle?: boolean;
onPanelResize?: (delta: number) => void;
/** Keyboard nudge step in pixels (default 16). Home/End jump to min/max. */
keyboardStep?: number;
/** Render as a static, non-interactive divider (e.g. between locked panels). */
static?: boolean;
/** Explicit axis; overrides `ResizableContext`. Needed by facades that render
* handles outside a context provider (e.g. `<kai-resizable>`). */
orientation?: Orientation;
}
declare function ResizableHandle(props: ResizableHandleProps): JSX.Element;
export interface ResizableProps {
orientation?: Orientation;
/** Fired on drag-end / keyboard resize / visibility change with the current panel sizes (percent). */
onChange?: (sizes: number[]) => void;
/** Show a visible grip on each interactive handle. */
withHandle?: boolean;
class?: string;
/** Which panel index is maximized (null = none). Hides the others. */
maximizedIndex?: number | null;
/** Fired when the maximized panel changes (index, or null on restore). */
onMaximizeChange?: (index: number | null) => void;
/** `ResizablePanel` children. */
children: JSX.Element;
}
/**
* Convenience group that takes `ResizablePanel` children and AUTO-INSERTS a
* `ResizableHandle` between each pair of visible (non-`hidden`) panels. A handle
* is interactive only between two unlocked neighbors; otherwise it renders as a
* static divider. Power users who need manual control can keep using
* `ResizablePanelGroup` + explicit `ResizableHandle`s.
*/
declare function Resizable(props: ResizableProps): JSX.Element;
export { ResizablePanelGroup, ResizablePanel, ResizableHandle, Resizable };