Component gallery

Interaction hooks

The five framework-free interaction hooks the apps lean on, keyboard shortcuts, debounced input, hydration-safe storage, link interception and disabled reasons, and the one rule each carries.

useKeyPress

Key name, array, or a predicate for modifier combos: callback held in a ref
Press ↑ / ↓ anywhere: 0
Predicate combo Ctrl+Shift+K: off

useDebounce

Follows a value but only settles after it stops changing
Debounced (300ms): -

useLocalStorage

Reload-safe state; the key-name union is the consumer's to own
Component A
Component B
Both fields are separate components bound to playground.note: typing in one updates the other (same tab via a sync event, other tabs via the native storage event), and either clear resets both. Reload the page: the value is read synchronously, no default-value flash.

useLocalStorage, raw

encoding: "raw" stores a string as given, for a key older code wrote without quotes
Stored as the bare text prod under playground.env, not as "prod".

useSessionStorage

The per-tab sibling: same API over sessionStorage
Same contract as useLocalStorage, scoped to this tab: reload keeps it, a new tab starts clean.

useAction

Pending, a success or error toast, and a Retry; run never throws
Each press shows a spinner toast, then a success or an error toast that replaces it. The error toast has a Retry button that runs the same call again.

ThemeToggle

Light by default, the choice stored by name, applied before paint by themeBootScript
Writes versable-light or versable-dark under pg-theme, the key the playground's own boot script reads.

useDisabledReason

Priority-ordered checks → { disabled, reason }; spread buttonProps to get a bricked Button that explains itself on hover
blocked: No template selected

useNavHijack

Match a URL pattern and run a callback instead of navigating
@versable-git/ui · all states, both themes