crucıble

Rigging

Settings page block: schema-driven sections with a sliding section nav (tabs or scroll-spy), validated inputs, a counted bio, avatar uploader, spring switches, theme radio cards and Quorum segmented controls. Any change slides up a dirty-state save bar — async onSave drives pending, error and a fading Saved chip; Reset springs every field back. Danger zone actions use Ratchet hold-to-confirm.

motionfree

Installation

CLI

npx shadcn@latest add @crucible/rigging

Manual — install dependencies, then copy the source

npm install motion

Props

PropTypeDefaultDescription
sectionsRiggingSection[]Profile, Account, Notifications, Appearance and Danger zone sample sectionsThe settings schema. Each section becomes a nav entry.
defaultValuesRiggingValuesseeded sample values when sections is omittedInitial (and "last saved") values. Missing keys fall back per field kind (empty string, false, first option, null).
valuesRiggingValuesControlled values. Omit for uncontrolled use.
onChange(values: RiggingValues, name: string) => voidFires on every edit with the full next values and the field that changed.
onSave(values: RiggingValues) => void | Promise<unknown>Called with all values when Save is pressed (or ⌘/Ctrl+S) and validation passes. Return a Promise to show the pending state; resolve shows the "Saved" chip and makes these the new baseline, reject shows its message in the bar. Note: navigating away with unsaved changes is NOT blocked — wire beforeunload / your router guard yourself if you need that.
onAction(name: string) => voidFires when a danger-zone (action) field's hold completes.
layout"tabs" | "stacked""tabs""tabs" swaps one section at a time; "stacked" shows every section in one scroll column with scroll-spy nav (give the block a bounded height, e.g. h-[640px], so the column scrolls inside it).
titleReact.ReactNode"Settings"Page heading.
descriptionReact.ReactNodeCopy under the heading.
accentColorstring"#93c5fd"Accent hex for the nav indicator, focus rings, switches and Save.
refReact.Ref<RiggingHandle>Imperative handle (reset(), replay(), save(), getValues()). React 19 ref-as-prop.
classNamestringExtra classes for the root. Set a height to make the content column scroll internally.
Also accepts all props of Omit<React.ComponentPropsWithoutRef<"section">, "children" | "title" | "onChange" | "defaultValue"> — they pass through to the underlying element.

Honors prefers-reduced-motion with a designed static fallback, and passes className through.