Skip to Content
MavKitOne is in beta. @mav-labs-inc/mavkit-react is not public packages yet.
Utilities

Utilities

Hooks and helper functions exported from @mav-labs-inc/mavkit-react alongside the components. Most re-export behavior from @mav-labs-inc/core-js/primitives so vanilla, Angular, and React stay in sync.

cx

Join truthy class names with a space.

function cx(...parts: (string | false | null | undefined)[]): string
cx('btn', isActive && 'btn-active', className) // 'btn btn-active custom'

useControllableState

Controlled/uncontrolled state helper — the pattern every form-like MavKit component (TextField, Select, InputStepper, …) uses internally to support both value/onChange and defaultValue usage. When controlled is defined the returned state mirrors it and only reports changes via onChange; otherwise it owns the state internally (seeded from defaultValue) and still reports.

function useControllableState<T>( controlled: T | undefined, defaultValue: T, onChange?: (value: T) => void, ): [T, (next: T) => void]
const [open, setOpen] = useControllableState(props.open, false, props.onOpenChange)

useDeviceInfo

Reports the current device tier and orientation, updating on resize/orientation change. SSR-safe — everything is null on the server and on the client’s first render (to avoid a hydration mismatch), then resolves to the real viewport immediately after mount.

interface UseDeviceInfoResult { deviceType: 'mobile' | 'tablet' | 'desktop' | null orientation: 'portrait' | 'landscape' | null width: number | null height: number | null isMobile: boolean isTablet: boolean isDesktop: boolean isPortrait: boolean isLandscape: boolean } function useDeviceInfo(): UseDeviceInfoResult
const { isMobile, orientation } = useDeviceInfo()

Focus management

const FOCUSABLE_SELECTOR: string /** All focusable descendants of `container`, in DOM order. */ function getFocusable(container: HTMLElement): HTMLElement[] /** * Keeps Tab/Shift+Tab cycling within `container`. Call from a keydown * handler scoped to the container; no-ops for any key other than Tab. */ function trapFocus(container: HTMLElement, event: KeyboardEvent): void

Motion

/** True when the user has requested reduced motion at the OS level. */ function prefersReducedMotion(): boolean /** * Reads a duration off a CSS custom property (e.g. "180ms") and returns * milliseconds, falling back to `fallbackMs` if unset or unparsable. */ function readDurationVar(el: HTMLElement, varName: string, fallbackMs: number): number

Overlay registry

One registry is shared across vanilla, Angular, and React overlays, so opening any of them (a Modal, Dropdown, Menu, …) closes the others.

interface Overlay { close(): void } /** Register `instance` as open, closing every other registered overlay. */ function registerOverlay(instance: Overlay): void /** Unregister `instance` (call on close and on teardown). */ function unregisterOverlay(instance: Overlay): void

resolveSnap

The drag-release snap resolution BottomSheet uses to decide which snap point (or dismissal) a gesture lands on.

interface ResolveSnapOptions { /** Ascending px heights, one per snap point (length >= 1). */ heights: number[] /** Current dragged height, in px. */ current: number /** Release velocity in px/ms. Positive = moving down (shrinking). Default 0. */ velocity?: number /** Whether a downward gesture may dismiss (index: null). Default true. */ dismissible?: boolean /** px/ms above which a flick wins over nearest-snap. Default 0.5. */ velocityThreshold?: number /** Fraction of the lowest snap height below which a slow drag still dismisses. Default 0.5. */ dismissRatio?: number } /** Resolve a drag-release gesture to a snap index, or `null` to dismiss. */ function resolveSnap(options: ResolveSnapOptions): { index: number | null }
Last updated on