One kit. Every Versable screen.
The component kit, the design language it obeys, and the patterns proven in Speedway and Walmart, browsable in one place. Corrections caught on a shipping screen flow back here as law; nothing flows the other way.
SEE IT LIVE
See it live
The strip below is not a screenshot: every tile is the real, interactive component.
Identity
Components
Every export, all states, both themes, the tsx source beside each render.
Patterns
App-level composites proven on a shipping screen, rebuilt from kit parts on fixture data.
Agent docs
The scripture, the design language, the app patterns, and every kit contract, read in place.
The intent layer: why this project exists, what it must achieve, how it works.
- Abstractions are born from evidence, never ahead of it: a hack lives in an app until it earns graduation, two or more real consumers.
- Do not invent exceptions to the ground rules. Stop and flag instead.
The twelve traits, the layer-relation table, and the pin caveat.
- The canon says what a surface should be and why; what props a component takes lives in the kit docs, never restated here.
- Deviation is legitimate and never free: a surface that deviates records the reason in its own doc, never silently.
Every banned combination and canon do-not in one place, regenerated from source.
- A rule filed under one component's contract is invisible to a builder who never opens that doc; check here before shipping.
- A button that cannot act is hidden or explains itself, never silently disabled.
How to set up, run, and extend this repo: a component, a pattern, a doc.
- A component is never one file: source, contract doc, showcase page, registry entry and the do-nots regen travel together.
- Never publish the kit by hand from a laptop; it races the workflow, which then finds the version present and skips.
Admin demo
The operator console one level above the workspace: every team on the installation, the machinery under them, and the controls that reach across all of them.
PACKAGES
Packages
Two more layers under the kit, both real, working code: framework-free utilities and the URL half of the table sync seam.
date · download · event · file · iter · number · object · promise · random · result · sampling · security · string · text · types · url · validation
import { listToMap, getHumanReadableNumber, truncateMiddle, getRelativeTime } from "@versable-git/toolkit";const rows = [{ id: "x", n: 1 }, { id: "y", n: 2 }];// Build an id-lookup map from a list (the default key)listToMap(rows);// { x: { id: "x", n: 1 }, y: { id: "y", n: 2 } }// Key by any other field on the rowlistToMap(rows, "n");// { 1: { id: "x", n: 1 }, 2: { id: "y", n: 2 } }// Shape each value with a transform, not just the keylistToMap(rows, "id", (r) => r.n);// { x: 1, y: 2 }// Compact a raw count for a stat tile or a table cellgetHumanReadableNumber(1500);// "1.5K"getHumanReadableNumber(2340000);// "2.3M"// Keep a long filename recognizable at a fixed widthtruncateMiddle("a-very-long-generated-filename-from-the-pipeline.csv", 24);// "a-very-long...peline.csv"// "5 minutes ago", not a raw timestampconst fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);getRelativeTime(fiveMinutesAgo);// "5 minutes ago"applyOps · createUrlSyncAdapter · createHistorySyncAdapter
import { applyOps, createUrlSyncAdapter } from "@versable-git/qsync";const base = new URLSearchParams("a=1&b=2");// Delete a key by writing nullapplyOps(base, new Map([["a", null]]));// "b=2" (base itself is untouched: applyOps returns a copy)// Add a brand-new keyapplyOps(base, new Map([["c", "3"]]));// "a=1&b=2&c=3"// Delete and add in the same batchapplyOps(base, new Map([["a", null], ["c", "3"]]));// "b=2&c=3"// createUrlSyncAdapter owns the batching: writes made in the same// tick coalesce into ONE commit, never one per writeconst adapter = createUrlSyncAdapter({ read: () => "sort=name", commit: (next) => console.log("commit:", next.toString()),});adapter.write("dir", "asc");adapter.write("dir", "desc"); // last write to a key winsadapter.read("dir");// "desc" (a read before the flush still sees the pending value)await Promise.resolve(); // one microtask later, the batch flushes// commit: "sort=name&dir=desc", a single commit call, not two