@tristan2828/ui-foundation 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ than installing this by hand:
19
19
  | Import | What |
20
20
  |---|---|
21
21
  | `@tristan2828/ui-foundation` | `AppShell`, `DataTable`, `EntityForm`, `ErrorState`, `MultiChoice`, `PasswordInput`, `RouteErrorBoundary`, `FoundationProviders`, `LoginRoute`, `RegisterRoute`, `useAuth`, `useTableUrlState`, `useDebouncedValue`, `createQueryClient`, `cn`; types `Page`, `AppError`, `QuerySpec` |
22
- | `@tristan2828/ui-foundation/ui/<name>` | shadcn primitives: badge, button, calendar, card, combobox, dialog, empty, field, input, input-group, label, popover, select, separator, sheet, sidebar, skeleton, sonner, spinner, table, textarea, tooltip |
22
+ | `@tristan2828/ui-foundation/ui/<name>` | shadcn primitives: badge, button, calendar, card, combobox, dialog, empty, field, input, input-group, label, popover, select, separator, sheet, sidebar, skeleton, sonner, spinner, switch, table, textarea, tooltip |
23
23
  | `@tristan2828/ui-foundation/gateway` | `safeFetch`, `toAppError`, `networkError` — for an app's `src/api/gateway/` only |
24
24
  | `@tristan2828/ui-foundation/mocks` | MSW: `authHandlers`, `resetMockAuth`, `getMockCurrentUser`, `MOCK_USER`, `exposeMswForE2E` |
25
25
  | `@tristan2828/ui-foundation/testing` | Playwright: `defineA11ySuite`, `defineMockModeBannerSuite`, `forceMswOverride`, `forceLoggedOut`, `waitForMswReady` |
@@ -76,7 +76,12 @@ is a filled-in example while the Widgets demo is still here).
76
76
  and labels from its field table, and field types by pattern (a
77
77
  `reference` field copies Category's searchable combobox, a
78
78
  `single choice` copies Status's select, a `date-time` copies
79
- Available From's date picker, a `multi choice` copies Tags — the
79
+ Available From's date picker, a `yes/no` copies In Stock — a `Switch`
80
+ (`@tristan2828/ui-foundation/ui/switch`) in a horizontal `Field` with
81
+ its label beside it on the form, cell pattern 12 (the word Yes/No) in
82
+ the table, and a three-way toolbar `Select` (either / yes / no) whose URL
83
+ value is `'true'`/`'false'` and whose `filters` value is a real boolean,
84
+ so `false` reaches the wire — and a `multi choice` copies Tags — the
80
85
  `<MultiChoice>` control from the foundation on the
81
86
  form and as a toolbar filter via `useTableUrlState`'s multi filters,
82
87
  badges in the table, and a `filters` array the gateway sends as a
@@ -7,7 +7,9 @@ per-entity, and only the shape is reusable. Copy the markup into your
7
7
 
8
8
  Patterns 1–10 were each chosen for a real column, from a page of
9
9
  alternatives ([`column-options.md`](column-options.md)), not designed in the abstract.
10
- Patterns from 11 on are marked **Unproven**: written ahead of a real
10
+ Pattern 12 (boolean) is the template's own reference: Widget's In Stock
11
+ column renders it and its specs pin it. The other patterns from 11 on are
12
+ marked **Unproven**: written ahead of a real
11
13
  column, so no app has tested them on real data yet. Prefer a proven
12
14
  pattern when one fits. When you use an unproven one, say so in the
13
15
  entity's plan, and raise what you learned for the foundation, so the
@@ -257,9 +259,11 @@ cell: ({ getValue }) => {
257
259
  template's `USD` is the demo's.
258
260
  - **Cost:** none to speak of. It's the plain-text pattern with formatting.
259
261
 
260
- ## 12. Boolean — *Unproven*
262
+ ## 12. Boolean
261
263
 
262
- A yes/no field.
264
+ A yes/no field. Widget's In Stock column (`src/routes/widgets/widgets-columns.tsx`)
265
+ is the reference; its value is never null, so it drops the `emptyCell`
266
+ branch below.
263
267
 
264
268
  ```tsx
265
269
  cell: ({ getValue }) => {
@@ -24,7 +24,9 @@ One or two sentences: what one record is, and who uses the screens.
24
24
  - **Type** — what the foundation supports today:
25
25
  - *Demonstrated by the Widget reference* (copied directly): `text` (one
26
26
  line), `long text`, `decimal` (fixed places — say how many),
27
- `date-time`, `email`, `single choice` (list the options, in display
27
+ `date-time`, `email`, `yes/no` (a boolean that is always yes or no:
28
+ say its default and the filter's three labels, e.g. Any stock /
29
+ In stock / Out of stock), `single choice` (list the options, in display
28
30
  order; see the note below if it is *optional*), `multi choice` (list
29
31
  the options; any number can be picked —
30
32
  chips on the form, badges in the table, an any-of filter), `reference`
@@ -32,7 +34,8 @@ One or two sentences: what one record is, and who uses the screens.
32
34
  - *Close variants* (built by a small, stated change to the nearest
33
35
  pattern): `integer` (from decimal), `url` (from email — a format
34
36
  check), `date` (from date-time — no time part).
35
- - *Not supported yet:* boolean, file, and anything else.
37
+ - *Not supported yet:* a yes/no that can also be unset (three states),
38
+ file, and anything else.
36
39
  Write it anyway with a note; the playbook will stop and raise it
37
40
  rather than improvise.
38
41
  - **Required**: `yes`, or `no` (then say whether empty means "unknown").
@@ -0,0 +1,5 @@
1
+ import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
2
+ declare function Switch({ className, size, ...props }: SwitchPrimitive.Root.Props & {
3
+ size?: "sm" | "default";
4
+ }): import("react").JSX.Element;
5
+ export { Switch };
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
3
+ import { cn } from "cn";
4
+ function Switch({ className, size = "default", ...props }) {
5
+ return (_jsx(SwitchPrimitive.Root, { "data-slot": "switch", "data-size": size, className: cn("peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none group-has-[:focus-visible]/field-label:border-transparent group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50", className), ...props, children: _jsx(SwitchPrimitive.Thumb, { "data-slot": "switch-thumb", className: "pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground" }) }));
6
+ }
7
+ export { Switch };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tristan2828/ui-foundation",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "Shared UI foundation for contract-first, database-backed React apps: shadcn primitives, DataTable/EntityForm composites, auth, the gateway error seam, design tokens, lint rules and the AI playbook.",
5
5
  "license": "MIT",
6
6
  "repository": {