@sableui/react 0.3.1 → 0.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.
Files changed (58) hide show
  1. package/AGENTS.md +8 -4
  2. package/CHANGELOG.md +60 -0
  3. package/CONTRIBUTING.md +2 -2
  4. package/DESIGN.md +7 -7
  5. package/README.md +7 -3
  6. package/bin/sable-lint.mjs +0 -0
  7. package/bin/sable.mjs +10 -5
  8. package/dist/{_contract-o3tUc8Ig.d.ts → _contract-Cn3lUpih.d.ts} +10 -5
  9. package/dist/blocks/index.js +2 -2
  10. package/dist/{chunk-YXBOYWBN.js → chunk-C4Z3CF54.js} +1 -1
  11. package/dist/{chunk-CKNM7KSB.js → chunk-CCUDFLU3.js} +23 -6
  12. package/dist/{chunk-6LCIBMMG.js → chunk-D2ETQBHV.js} +1 -1
  13. package/dist/{chunk-MXJX3NZI.js → chunk-EFLC4NA3.js} +4 -4
  14. package/dist/{chunk-EP55KSYA.js → chunk-EHH4MHO6.js} +6 -6
  15. package/dist/{chunk-WCFLQVK5.js → chunk-FBSL2LZQ.js} +1 -1
  16. package/dist/{chunk-X276MF2W.js → chunk-OQACYT2D.js} +2 -0
  17. package/dist/index.d.ts +8 -8
  18. package/dist/index.js +13 -13
  19. package/dist/patterns/index.js +2 -2
  20. package/dist/presets/index.d.ts +1 -1
  21. package/dist/presets/index.js +2 -2
  22. package/dist/styles.css +16 -6
  23. package/dist/{theme-provider-BE-KqUG-.d.ts → theme-provider-CGeiusgu.d.ts} +3 -3
  24. package/dist/themes/atelier/index.d.ts +1 -1
  25. package/dist/themes/atelier/index.js +1 -1
  26. package/dist/themes/ember/ember.css +8 -5
  27. package/dist/themes/ember/index.d.ts +1 -1
  28. package/dist/themes/index.d.ts +3 -3
  29. package/dist/themes/index.js +3 -3
  30. package/dist/themes/meridian/index.d.ts +1 -1
  31. package/dist/themes/poppy/index.d.ts +1 -1
  32. package/dist/themes/poppy/poppy.css +1 -1
  33. package/dist/themes/prism/index.d.ts +1 -1
  34. package/dist/themes/sable/index.d.ts +9 -0
  35. package/dist/themes/sable/index.js +1 -0
  36. package/dist/themes/{base/base.css → sable/sable.css} +6 -6
  37. package/dist/themes/verdant/index.d.ts +1 -1
  38. package/dist/themes.css +3 -3
  39. package/llms/components/button.md +15 -3
  40. package/llms/components/input.md +1 -1
  41. package/llms/components/scrub-field.md +1 -1
  42. package/llms/components/select.md +1 -1
  43. package/llms/components/theme-selector.md +1 -1
  44. package/llms/reference/token-intent.md +5 -1
  45. package/llms/tasks/building-a-page.md +1 -1
  46. package/llms/tasks/creating-a-preset.md +1 -1
  47. package/llms/tasks/designing-a-surface.md +1 -1
  48. package/llms/tasks/getting-started.md +4 -0
  49. package/llms-full.txt +32 -12
  50. package/llms.txt +1 -1
  51. package/package.json +5 -5
  52. package/registry.json +2456 -18
  53. package/scripts/agent-setup.mjs +34 -7
  54. package/scripts/design-presets.mjs +1 -1
  55. package/scripts/grade.mjs +50 -11
  56. package/scripts/lint-rules.mjs +20 -1
  57. package/dist/themes/base/index.d.ts +0 -9
  58. package/dist/themes/base/index.js +0 -1
@@ -62,7 +62,7 @@ chosen by what the surface *does*:
62
62
  - `secondary` — a control fill (something you can press)
63
63
  - `accent` — a transient state (hover, selected, current)
64
64
 
65
- Pick by appearance and it works in Base and breaks in Meridian. Every token's
65
+ Pick by appearance and it works in the Sable theme and breaks in Meridian. Every token's
66
66
  intent, and what it gets confused with, is in
67
67
  `llms/reference/token-intent.md`.
68
68
 
@@ -21,7 +21,7 @@ pnpm exec sable preset --check .sable/presets/clay.json --json
21
21
  pnpm exec sable preset --css .sable/presets/clay.json
22
22
  ```
23
23
 
24
- The template starts from a complete Base theme snapshot. Give it a unique ID and
24
+ The template starts from a complete Sable theme snapshot. Give it a unique ID and
25
25
  label; author its tokens, direction, and reference observations. Avoid IDs of
26
26
  bundled themes. Save the record at `.sable/presets/<id>.json`. Advance `revision`
27
27
  when changing a shared record; keep earlier revisions when reproducibility matters.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Tokens make decisions consistent; they do not decide what deserves attention.
4
4
  Start with the user's task and content, then choose a visual direction. Sable's
5
- default Base identity is a starting point. A consumer can be light-first,
5
+ default Sable identity is a starting point. A consumer can be light-first,
6
6
  photographic, editorial, playful, or quiet while retaining semantic tokens,
7
7
  accessible behavior, and a coherent interaction policy.
8
8
 
@@ -48,6 +48,10 @@ pnpm exec sable doctor
48
48
  After installing Sable, run `pnpm exec sable setup --agent` in the target
49
49
  project. It installs discoverable entry files in `.agents/skills/sable` for
50
50
  Codex/Cursor and `.claude/skills/sable` for Claude Code; `--target` selects a host.
51
+ In a monorepo where Sable belongs to one workspace package, run setup in that
52
+ package with `--root` naming the repository root (for example
53
+ `pnpm --filter web exec sable setup --agent --root ../..`); the entries go
54
+ there and resolve Sable through the package.
51
55
  Each entry resolves `skills/sable/SKILL.md` from the installed package, so package
52
56
  upgrades also update the workflow. Other agents can read that file directly.
53
57
  Use `$sable build <idea>`, `inspire <references>`, `audit <target>`, or
package/llms-full.txt CHANGED
@@ -243,7 +243,7 @@ On npm as `@sableui/react`. The structured recipe is the `consume` block in `reg
243
243
  @source "<path-to>/@sableui/react/dist/**/*.{js,mjs}"; /* workspace: packages/sable/src; published: node_modules/@sableui/react/dist */
244
244
  ```
245
245
 
246
- 4. **Fonts:** the theme declares the stacks; the host loads the files (every featured primary is available through Google Fonts). Per theme — base: Figtree + DM Mono · meridian: Instrument Sans + Geist Mono · prism: Outfit + Roboto Mono + Playfair Display (display) · verdant: Inter + IBM Plex Mono + Instrument Serif (display) · ember: Work Sans + DM Mono · poppy: Albert Sans + Red Hat Mono + Unbounded (display). The machine-readable list is `registry.json → themes.available[].fonts`.
246
+ 4. **Fonts:** the theme declares the stacks; the host loads the files (every featured primary is available through Google Fonts). Per theme — sable: Figtree + DM Mono · meridian: Instrument Sans + Geist Mono · prism: Outfit + Roboto Mono + Playfair Display (display) · verdant: Inter + IBM Plex Mono + Instrument Serif (display) · ember: Work Sans + DM Mono · poppy: Albert Sans + Red Hat Mono + Unbounded (display). The machine-readable list is `registry.json → themes.available[].fonts`.
247
247
  5. **Providers + theme switching:**
248
248
 
249
249
  ```tsx
@@ -653,7 +653,7 @@ chosen by what the surface *does*:
653
653
  - `secondary` — a control fill (something you can press)
654
654
  - `accent` — a transient state (hover, selected, current)
655
655
 
656
- Pick by appearance and it works in Base and breaks in Meridian. Every token's
656
+ Pick by appearance and it works in the Sable theme and breaks in Meridian. Every token's
657
657
  intent, and what it gets confused with, is in
658
658
  `llms/reference/token-intent.md`.
659
659
 
@@ -1309,7 +1309,7 @@ pnpm exec sable preset --check .sable/presets/clay.json --json
1309
1309
  pnpm exec sable preset --css .sable/presets/clay.json
1310
1310
  ```
1311
1311
 
1312
- The template starts from a complete Base theme snapshot. Give it a unique ID and
1312
+ The template starts from a complete Sable theme snapshot. Give it a unique ID and
1313
1313
  label; author its tokens, direction, and reference observations. Avoid IDs of
1314
1314
  bundled themes. Save the record at `.sable/presets/<id>.json`. Advance `revision`
1315
1315
  when changing a shared record; keep earlier revisions when reproducibility matters.
@@ -1435,7 +1435,7 @@ requirement that every future brand use the same illustration or font pairing.
1435
1435
 
1436
1436
  Tokens make decisions consistent; they do not decide what deserves attention.
1437
1437
  Start with the user's task and content, then choose a visual direction. Sable's
1438
- default Base identity is a starting point. A consumer can be light-first,
1438
+ default Sable identity is a starting point. A consumer can be light-first,
1439
1439
  photographic, editorial, playful, or quiet while retaining semantic tokens,
1440
1440
  accessible behavior, and a coherent interaction policy.
1441
1441
 
@@ -1759,6 +1759,10 @@ pnpm exec sable doctor
1759
1759
  After installing Sable, run `pnpm exec sable setup --agent` in the target
1760
1760
  project. It installs discoverable entry files in `.agents/skills/sable` for
1761
1761
  Codex/Cursor and `.claude/skills/sable` for Claude Code; `--target` selects a host.
1762
+ In a monorepo where Sable belongs to one workspace package, run setup in that
1763
+ package with `--root` naming the repository root (for example
1764
+ `pnpm --filter web exec sable setup --agent --root ../..`); the entries go
1765
+ there and resolve Sable through the package.
1762
1766
  Each entry resolves `skills/sable/SKILL.md` from the installed package, so package
1763
1767
  upgrades also update the workflow. Other agents can read that file directly.
1764
1768
  Use `$sable build <idea>`, `inspire <references>`, `audit <target>`, or
@@ -10885,7 +10889,7 @@ Use Button when the user commits an action, submits a form, opens UI, or confirm
10885
10889
 
10886
10890
  | Name | Type | Default | Description |
10887
10891
  | --- | --- | --- | --- |
10888
- | variant | "primary" \| "secondary" \| "ghost" \| "outline" \| "destructive" \| "link" \| "floating" \| "on-color" \| "on-color-outline" \| "on-color-ghost" | "primary" | Visual emphasis tier. One primary per screen. The on-color tiers are for buttons ON a coloured fill: they paint with the inherited text colour (the fill's ink) — on-color is solid (ink background, fill-coloured label via the optional --on-color-fill var, else black/white), on-color-outline and on-color-ghost are transparent with an ink label. Never use them on page or card surfaces. floating is for a control that sits OVER content (carousel arrows, a marquee pause, a jump-to-latest over a conversation): its own edge, lift and translucent popover fill, so it reads on arbitrary content beneath. |
10892
+ | variant | "primary" \| "secondary" \| "ghost" \| "outline" \| "destructive" \| "link" \| "floating" \| "field" \| "on-color" \| "on-color-outline" \| "on-color-ghost" | "primary" | Visual emphasis tier. One primary per screen. The on-color tiers are for buttons ON a coloured fill: they paint with the inherited text colour (the fill's ink) — on-color is solid (ink background, fill-coloured label via the optional --on-color-fill var, else black/white), on-color-outline and on-color-ghost are transparent with an ink label. Never use them on page or card surfaces. floating is for a control that sits OVER content (carousel arrows, a marquee pause, a jump-to-latest over a conversation): its own edge, lift and translucent popover fill, so it reads on arbitrary content beneath. field is for a button docked in a workspace panel among xs fields: the inset panel-field fill and the field's corner, so a picker trigger or an add action reads as one of the row's controls; pair it with size xs or icon-xs. |
10889
10893
  | size | "xs" \| "sm" \| "md" \| "cta" \| "icon" \| "icon-sm" \| "icon-xs" | "md" | Reads the density ladder, so every value differs by register: page 28/32/40/44, workspace 24/28/32/36. xs and icon-xs were added in 0.31.0 for the workspace control floor and are the sizes tool chrome wants; md is the default everywhere. icon/icon-sm/icon-xs are square. |
10890
10894
  | render | ReactElement \| (props, state) => ReactElement | — | Compose with another element/component through the Base UI render prop. |
10891
10895
  | loading | boolean | false | Disable the button and show a leading Spinner while an action is in flight. Sets aria-busy; a native button is disabled, a render element (e.g. an <a>) gets aria-disabled. |
@@ -10896,12 +10900,12 @@ Use Button when the user commits an action, submits a form, opens UI, or confirm
10896
10900
 
10897
10901
  ## Variants
10898
10902
 
10899
- - **variant**: primary, secondary, ghost, outline, destructive, link, floating, on-color, on-color-outline, on-color-ghost
10903
+ - **variant**: primary, secondary, ghost, outline, destructive, link, floating, field, on-color, on-color-outline, on-color-ghost
10900
10904
  - **size**: xs, sm, md, cta, icon, icon-sm, icon-xs
10901
10905
 
10902
10906
  ## Tokens used
10903
10907
 
10904
- `primary`, `primary-foreground`, `secondary`, `secondary-foreground`, `accent`, `accent-foreground`, `input`, `destructive`, `destructive-foreground`, `ring`
10908
+ `primary`, `primary-foreground`, `secondary`, `secondary-foreground`, `accent`, `accent-foreground`, `input`, `destructive`, `destructive-foreground`, `ring`, `panel-field`, `panel-field-hover`, `panel-foreground`
10905
10909
 
10906
10910
  ## Motion
10907
10911
 
@@ -11032,6 +11036,18 @@ import { Button, Icon, NotificationBadge } from "@sableui/react"
11032
11036
  <Button size="icon" variant="ghost" aria-label="Notifications" badge={<NotificationBadge dot />}><Icon name="bell" /></Button>
11033
11037
  ```
11034
11038
 
11039
+ ### Field button in a panel row
11040
+
11041
+ ```tsx
11042
+ import { Button, Icon, PanelSection, PropertyRow } from "@sableui/react"
11043
+
11044
+ <PanelSection title="Text">
11045
+ <PropertyRow label="Font">
11046
+ <Button variant="field" size="xs" className="w-full justify-between" iconEnd={<Icon name="chevron-down" />}>Figtree</Button>
11047
+ </PropertyRow>
11048
+ </PanelSection>
11049
+ ```
11050
+
11035
11051
  ### On a coloured band
11036
11052
 
11037
11053
  ```tsx
@@ -13721,7 +13737,7 @@ Use Input for short freeform text, search, email, password, file, and native inp
13721
13737
 
13722
13738
  | Name | Type | Default | Description |
13723
13739
  | --- | --- | --- | --- |
13724
- | size | "md" \| "xs" | "md" | md is the form field. xs is the dense inset field of a tool panel (an inset canvas fill, no outline, tight padding) — the same ladder as Select and Combobox. Use it instead of overriding the height with className. |
13740
+ | size | "md" \| "xs" | "md" | md is the form field. xs is the dense inset field of a tool panel (an inset panel-field fill, no outline, tight padding) — the same ladder as Select and Combobox. Use it instead of overriding the height with className. |
13725
13741
  | type | string | "text" | Native input type (text, email, password, search, number, file, …). type="file" themes the native selector button via file: token utilities. |
13726
13742
  | disabled | boolean | false | Dims the control and blocks pointer interaction. |
13727
13743
  | aria-invalid | boolean | — | Surfaces the destructive border + ring. Base UI form fields set this automatically. |
@@ -16706,7 +16722,7 @@ Use ScrubField for numeric properties in tool chrome — an inspector, a propert
16706
16722
 
16707
16723
  ## Tokens used
16708
16724
 
16709
- `foreground`, `muted-foreground`, `ring`, `canvas`, `panel-raised`
16725
+ `foreground`, `muted-foreground`, `ring`, `panel-field`, `panel-field-hover`
16710
16726
 
16711
16727
  ## Accessibility
16712
16728
 
@@ -16991,7 +17007,7 @@ Use Select when users choose one value from a known, finite set. Use Combobox fo
16991
17007
 
16992
17008
  | Name | Type | Description |
16993
17009
  | --- | --- | --- |
16994
- | SelectTrigger | Base UI Trigger props + placeholder?: ReactNode + size?: "md" \| "xs" + className | The button. Composes Trigger + Value + a chevron Icon that flips on open (data-[popup-open]). `size="xs"` is the property-grid rung — height, padding, radius AND surface move together, which is why it is a prop and not a className: the xs trigger is an inset `bg-canvas` field with no border, matching ScrubField on the same row. A consumer overriding only the height gets an md-register 8px radius on a 24px box and a raised card sitting among inset fields; one inspector panel had eleven of those, and both tells are visible at a glance. |
17010
+ | SelectTrigger | Base UI Trigger props + placeholder?: ReactNode + size?: "md" \| "xs" + className | The button. Composes Trigger + Value + a chevron Icon that flips on open (data-[popup-open]). `size="xs"` is the property-grid rung — height, padding, radius AND surface move together, which is why it is a prop and not a className: the xs trigger is an inset `bg-panel-field` field with no border, matching ScrubField on the same row. A consumer overriding only the height gets an md-register 8px radius on a 24px box and a raised card sitting among inset fields; one inspector panel had eleven of those, and both tells are visible at a glance. |
16995
17011
  | SelectContent | Base UI Popup props + side, align, sideOffset + className | Portal + Positioner + Popup + List. side="bottom", align="start", sideOffset=6 by default; matches trigger width. |
16996
17012
  | SelectItem | { value: string; disabled?: boolean; label?: string } + className | An option. Composes Item + ItemText + a check ItemIndicator for the selected row. String children double as the item's `label`, so the closed trigger shows the display text — pass `label` explicitly only when children are richer than a string. |
16997
17013
  | SelectGroup | Base UI Group props + className | Optional grouping of related options. |
@@ -18827,7 +18843,7 @@ const { themeId, setThemeId, themes, mode } = useSableTheme()
18827
18843
  ```tsx
18828
18844
  import { ThemeSelector, type ThemeId } from "@sableui/react"
18829
18845
 
18830
- const [themeId, setThemeId] = useState<ThemeId>("base")
18846
+ const [themeId, setThemeId] = useState<ThemeId>("sable")
18831
18847
  <ThemeSelector value={themeId} onValueChange={setThemeId} />
18832
18848
  ```
18833
18849
 
@@ -20275,7 +20291,7 @@ Which token to reach for, and what it is most often confused with. Generated fro
20275
20291
  - **`type-mono-sm-tracking`** — The monospace family: mono-xl through mono-sm, plus mono-caption. *Use for:* Code, identifiers, hashes, keyboard keys, and any figure where digits must align in a column.
20276
20292
  - **Not** the sans tiers for numeric data. Proportional digits make a column of numbers ragged; that is what `text-ui-num` solves in chrome and mono solves on a page.
20277
20293
 
20278
- ### derived (8)
20294
+ ### derived (10)
20279
20295
 
20280
20296
  - **`canvas`** — The WORK surface — the artboard, the document being edited. *Use for:* Behind the thing the tool operates on. `WorkspaceCanvas` uses it.
20281
20297
  - **Not** `background`. The thing being edited is not the page behind the UI, and collapsing the two makes the document indistinguishable from its chrome.
@@ -20287,6 +20303,10 @@ Which token to reach for, and what it is most often confused with. Generated fro
20287
20303
  - **Not** `foreground`. That is the ink for `background` only; on any other surface it is a contrast gamble that happens to pass in the default theme and fails in another.
20288
20304
  - **`panel-raised`** — One step up from `panel`: a selected row, a hover fill, a nested well. *Use for:* Tree row selection, hovered panel rows, and the light square of a checkerboard.
20289
20305
  - **Not** `accent`. In a workspace the tonal band is only a few units wide; `accent` is a page-register step and reads as a shout in chrome.
20306
+ - **`panel-field`** — The inset fill of a compact control docked in a panel. *Use for:* The `size="xs"` field rung (Input, SelectTrigger, ScrubField share it) and `<Button variant="field">`. A panel control of your own that should sit among those fields.
20307
+ - **Not** `canvas`. `canvas` names the work surface, and its step off the panel is too faint to read as a field in dark mode. This one is mixed from the panel itself, so it follows a theme that retunes the panel. Tune it with `--theme-panel-field`.
20308
+ - **`panel-field-hover`** — The hover step of a `panel-field` control. *Use for:* `hover:bg-panel-field-hover` on anything filled with `panel-field`.
20309
+ - **Not** `hover:bg-panel-raised`. A fixed surface token as a hover is what the surface-hover lint rejects; this one is defined against the panel field it steps from.
20290
20310
  - **`hairline`** — The 1px structural line that carries all separation in tool chrome. *Use for:* Between panel sections, under a toolbar, above a status bar.
20291
20311
  - **Not** a bigger tonal step. This is one of the two rules the workspace register deliberately reverses: on a page prefer space or tone over a line, in chrome the hairline *is* the structure.
20292
20312
  - **`hairline-strong`** — A hairline that must be seen — an input edge, a swatch ring. *Use for:* Bounding a control whose fill is arbitrary (a colour swatch) or user content.
package/llms.txt CHANGED
@@ -243,7 +243,7 @@ On npm as `@sableui/react`. The structured recipe is the `consume` block in `reg
243
243
  @source "<path-to>/@sableui/react/dist/**/*.{js,mjs}"; /* workspace: packages/sable/src; published: node_modules/@sableui/react/dist */
244
244
  ```
245
245
 
246
- 4. **Fonts:** the theme declares the stacks; the host loads the files (every featured primary is available through Google Fonts). Per theme — base: Figtree + DM Mono · meridian: Instrument Sans + Geist Mono · prism: Outfit + Roboto Mono + Playfair Display (display) · verdant: Inter + IBM Plex Mono + Instrument Serif (display) · ember: Work Sans + DM Mono · poppy: Albert Sans + Red Hat Mono + Unbounded (display). The machine-readable list is `registry.json → themes.available[].fonts`.
246
+ 4. **Fonts:** the theme declares the stacks; the host loads the files (every featured primary is available through Google Fonts). Per theme — sable: Figtree + DM Mono · meridian: Instrument Sans + Geist Mono · prism: Outfit + Roboto Mono + Playfair Display (display) · verdant: Inter + IBM Plex Mono + Instrument Serif (display) · ember: Work Sans + DM Mono · poppy: Albert Sans + Red Hat Mono + Unbounded (display). The machine-readable list is `registry.json → themes.available[].fonts`.
247
247
  5. **Providers + theme switching:**
248
248
 
249
249
  ```tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sableui/react",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Sable: themeable React components, layout patterns, and tools for coding agents.",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -71,11 +71,11 @@
71
71
  "default": "./dist/themes/ember/index.js"
72
72
  },
73
73
  "./theme/ember.css": "./dist/themes/ember/ember.css",
74
- "./theme/base": {
75
- "types": "./dist/themes/base/index.d.ts",
76
- "default": "./dist/themes/base/index.js"
74
+ "./theme/sable": {
75
+ "types": "./dist/themes/sable/index.d.ts",
76
+ "default": "./dist/themes/sable/index.js"
77
77
  },
78
- "./theme/base.css": "./dist/themes/base/base.css",
78
+ "./theme/sable.css": "./dist/themes/sable/sable.css",
79
79
  "./theme/poppy": {
80
80
  "types": "./dist/themes/poppy/index.d.ts",
81
81
  "default": "./dist/themes/poppy/index.js"