@sableui/react 0.18.0 → 0.19.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/CHANGELOG.md +129 -0
- package/bin/sable.mjs +108 -14
- package/dist/{_contract-CDa9-NdB.d.ts → _contract-DlklV0Im.d.ts} +2 -2
- package/dist/blocks/index.d.ts +1 -1
- package/dist/components/avatar/avatar.js +16 -7
- package/dist/components/avatar/avatar.meta.js +43 -10
- package/dist/components/avatar/avatar.variants.js +26 -2
- package/dist/components/collapsible/collapsible.js +6 -5
- package/dist/components/collapsible/collapsible.meta.js +14 -5
- package/dist/components/data-table/data-table.js +132 -45
- package/dist/components/data-table/data-table.meta.js +63 -4
- package/dist/components/date-picker/date-picker.js +13 -6
- package/dist/components/date-picker/date-picker.meta.js +22 -0
- package/dist/components/menu/menu.js +2 -0
- package/dist/components/menu/menu.meta.js +2 -2
- package/dist/components/panel-group/panel-group.js +17 -1
- package/dist/components/panel-group/panel-group.meta.js +43 -3
- package/dist/components/side-nav/side-nav.variants.js +8 -3
- package/dist/components/sidebar/index.js +4 -0
- package/dist/components/sidebar/sidebar.js +90 -11
- package/dist/components/sidebar/sidebar.meta.js +38 -4
- package/dist/components/table/table.js +7 -3
- package/dist/components/tabs/tabs.js +10 -2
- package/dist/components/tabs/tabs.meta.js +4 -0
- package/dist/components/workspace/workspace.js +13 -3
- package/dist/components/workspace/workspace.meta.js +109 -1
- package/dist/file-hashes.json +53 -49
- package/dist/foundations/typography.js +13 -0
- package/dist/icon/Icon.js +21 -2
- package/dist/icon/index.d.ts +36 -1
- package/dist/icon/index.js +5 -0
- package/dist/icon/names.js +240 -0
- package/dist/icon-sets/reicon.js +19 -1
- package/dist/index.d.ts +272 -50
- package/dist/index.js +11 -1
- package/dist/lib/chart/heat.js +1 -1
- package/dist/lib/cn.js +1 -0
- package/dist/lib/use-media-query.js +41 -0
- package/dist/{meta-DX5r5wQL.d.ts → meta-Dfm9AExe.d.ts} +6 -0
- package/dist/patterns/dashboard-page.js +23 -17
- package/dist/patterns/index.d.ts +7 -2
- package/dist/patterns/index.js +5 -1
- package/dist/patterns/tracker-page.js +392 -0
- package/dist/patterns/tracker-page.meta.js +40 -0
- package/dist/presets/index.d.ts +1 -1
- package/dist/styles.css +179 -74
- package/dist/{theme-provider-BydfM5Z0.d.ts → theme-provider-BUBealk_.d.ts} +1 -1
- package/dist/themes/_contract.js +9 -1
- package/dist/themes/atelier/index.d.ts +1 -1
- package/dist/themes/ember/index.d.ts +1 -1
- package/dist/themes/index.d.ts +2 -2
- package/dist/themes/meridian/index.d.ts +1 -1
- package/dist/themes/poppy/index.d.ts +1 -1
- package/dist/themes/prism/index.d.ts +1 -1
- package/dist/themes/sable/index.d.ts +1 -1
- package/dist/themes/verdant/index.d.ts +1 -1
- package/llms/components/avatar.md +32 -9
- package/llms/components/collapsible.md +12 -4
- package/llms/components/data-table.md +40 -3
- package/llms/components/date-picker.md +15 -1
- package/llms/components/menu.md +1 -1
- package/llms/components/panel-group.md +34 -2
- package/llms/components/sidebar.md +17 -4
- package/llms/components/tabs.md +1 -0
- package/llms/components/workspace.md +81 -1
- package/llms/foundations/typography.md +4 -1
- package/llms/patterns/dashboard-page.md +18 -15
- package/llms/patterns/tracker-page.md +450 -0
- package/llms/reference/token-intent.md +3 -1
- package/llms/reference/utilities.md +4 -1
- package/llms/tasks/auditing-an-app.md +4 -1
- package/llms/tasks/building-a-page.md +3 -2
- package/llms/tasks/building-a-tool.md +101 -5
- package/llms/tasks/building-with-sable.md +11 -3
- package/llms/tasks/creating-a-preset.md +9 -0
- package/llms-full.txt +843 -54
- package/llms.txt +8 -7
- package/package.json +2 -1
- package/registry.json +491 -36
- package/scripts/adoption.mjs +15 -2
- package/scripts/app-css.mjs +129 -0
- package/scripts/grade.mjs +161 -2
- package/scripts/lint-rules.mjs +126 -0
- package/skills/sable/SKILL.md +33 -4
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# Task: building a tool (workspace register)
|
|
2
2
|
|
|
3
|
-
An editor, a canvas app, a console
|
|
4
|
-
|
|
3
|
+
An editor, a canvas app, a console, or a records workspace (an issue tracker, a
|
|
4
|
+
support queue, a pipeline): anything whose primary interaction is *operating on
|
|
5
|
+
something* rather than reading and navigating.
|
|
5
6
|
|
|
6
7
|
If the primary interaction is reading down a page, stop: you want
|
|
7
8
|
[building-a-page.md](./building-a-page.md). A dashboard that scrolls is a page
|
|
8
|
-
with dense content, not a workspace.
|
|
9
|
+
with dense content, not a workspace. A tracker or inbox where people work
|
|
10
|
+
through records one at a time, with the selected one open beside the list, is a
|
|
11
|
+
workspace. Start that one from the `TrackerPage` pattern
|
|
12
|
+
(`sable pattern TrackerPage --skeleton`) and read "A records workspace" below.
|
|
9
13
|
|
|
10
14
|
## The shell
|
|
11
15
|
|
|
@@ -29,12 +33,88 @@ hierarchy do not automatically transfer to dense operating surfaces.
|
|
|
29
33
|
</Workspace>
|
|
30
34
|
```
|
|
31
35
|
|
|
36
|
+
Every slot is optional; the body is always the one growing row. A bar that
|
|
37
|
+
belongs to one column (a list's breadcrumbs and view switch, with the inspector
|
|
38
|
+
running the full height beside it, as in Linear) is a `WorkspaceBar` placed first
|
|
39
|
+
inside that column, not the `toolbar` slot.
|
|
40
|
+
|
|
32
41
|
`Workspace` sets the compact density scope for its whole subtree. Nothing
|
|
33
42
|
hardcodes a height: every control reads `--control-*`, so the same
|
|
34
43
|
`<Button size="md">` is 40px on a page and 32px here. A `Dialog` opened from
|
|
35
44
|
inside resets to comfortable, because a modal is a page-register surface even
|
|
36
45
|
when a tool launched it.
|
|
37
46
|
|
|
47
|
+
## A records workspace
|
|
48
|
+
|
|
49
|
+
The shape of an issue tracker, a support queue or a CRM pipeline. Every piece
|
|
50
|
+
below exists, so the build is composition; `sable pattern TrackerPage
|
|
51
|
+
--skeleton` has the whole tree.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<Workspace statusBar={<StatusBar>…</StatusBar>} bottomNav={<BottomNav>…</BottomNav>}>
|
|
55
|
+
<PanelGroup>
|
|
56
|
+
<Panel label="Navigation" width={220} narrow="sheet" side="left"
|
|
57
|
+
open={narrow ? navOpen : true} onOpenChange={setNavOpen} scroll={false}>
|
|
58
|
+
<Sidebar variant="inline">
|
|
59
|
+
<SidebarHeader><SidebarBrand mark={…} label="Studio" />{search}</SidebarHeader>
|
|
60
|
+
<SidebarNav>
|
|
61
|
+
<SidebarItem icon={…} label="Inbox" badge={…} />
|
|
62
|
+
<SidebarGroup label="Workspace">{items}</SidebarGroup>
|
|
63
|
+
</SidebarNav>
|
|
64
|
+
<SidebarFooter>
|
|
65
|
+
<Menu>
|
|
66
|
+
<MenuTrigger render={<SidebarAccount avatar={<Avatar size="2xs" … />} label="Emma Lee" detail="Studio" />} />
|
|
67
|
+
<MenuContent side="top" align="start">{settings, appearance, sign out}</MenuContent>
|
|
68
|
+
</Menu>
|
|
69
|
+
</SidebarFooter>
|
|
70
|
+
</Sidebar>
|
|
71
|
+
</Panel>
|
|
72
|
+
<WorkspaceCanvas className="flex flex-col">
|
|
73
|
+
<WorkspaceBar><Breadcrumbs>…</Breadcrumbs></WorkspaceBar>
|
|
74
|
+
<WorkspaceBar><Tabs><TabsList variant="pill">…</TabsList></Tabs></WorkspaceBar>
|
|
75
|
+
{filters}
|
|
76
|
+
<DataTable groupBy={(r) => r.status} groups={…} isRowSelected={…} onRowClick={…} />
|
|
77
|
+
</WorkspaceCanvas>
|
|
78
|
+
<Panel label="Details" width={320} narrow="sheet" open={selected != null}
|
|
79
|
+
onOpenChange={(o) => !o && setSelected(null)} scroll={false}>
|
|
80
|
+
<PanelSection title="Properties"><PropertyRow label="Status">…</PropertyRow></PanelSection>
|
|
81
|
+
</Panel>
|
|
82
|
+
</PanelGroup>
|
|
83
|
+
</Workspace>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The decisions that keep it one system:
|
|
87
|
+
|
|
88
|
+
- **One grid down the rail.** SidebarBrand, SidebarItem, SidebarGroup and
|
|
89
|
+
SidebarAccount share the icon and label columns, and inside the compact scope
|
|
90
|
+
they take 32px rows on their own. Do not drop SideNav, an Entity or a stack of
|
|
91
|
+
ghost Buttons into the rail: each brings its own insets.
|
|
92
|
+
- **The account is one row and a menu.** Settings, appearance (light, dark,
|
|
93
|
+
system) and sign-out go in the SidebarAccount's menu, not in a Settings button
|
|
94
|
+
above it or a badge beside it. Its detail line ("Studio · Demo") carries what a
|
|
95
|
+
badge would.
|
|
96
|
+
- **One table, grouped.** Rows grouped by state are one `DataTable` with
|
|
97
|
+
`groupBy`: one header, columns that line up, a count and an add action per
|
|
98
|
+
group. Not one table per group inside Collapsibles.
|
|
99
|
+
- **The inspector renders once.** `Panel narrow="sheet"` docks it on a desktop
|
|
100
|
+
and makes it a Sheet below `lg`. Not a media-query hook plus a second copy in a
|
|
101
|
+
Sheet. The nav rail does the same from the left, and fills its sheet.
|
|
102
|
+
- **Reading inside the tool is page-sized.** An overview, a description, notes or
|
|
103
|
+
a docs tab goes in `<Density value="comfortable">`, or its prose renders at the
|
|
104
|
+
11px chrome tier.
|
|
105
|
+
- **A view switch in chrome is a pill.** `TabsList variant="pill"`: its fill takes
|
|
106
|
+
the compact `--button-radius`, about 5px, so it reads as a segment. Underline
|
|
107
|
+
tabs are the page-section idiom.
|
|
108
|
+
- **Ship both modes, and a way to switch.** The look is a preset with light and
|
|
109
|
+
dark; SableThemeProvider applies it, and the account menu or a Settings dialog
|
|
110
|
+
holds the mode switch. A tool asked to be compact and technical takes
|
|
111
|
+
`type-base` (13 or 14) in the preset, which rebuilds the whole type scale,
|
|
112
|
+
instead of per-tier overrides.
|
|
113
|
+
- **State has a shape.** A status with more than on and off (partly done, in
|
|
114
|
+
review) can be an app-owned glyph, but give it a label (`role="img"`,
|
|
115
|
+
`aria-label`) and colour it from the palette (`var(--yellow-500)`) so it
|
|
116
|
+
follows the mode.
|
|
117
|
+
|
|
38
118
|
## What you will need, and what to avoid reaching for
|
|
39
119
|
|
|
40
120
|
| you want | use | NOT |
|
|
@@ -46,6 +126,17 @@ when a tool launched it.
|
|
|
46
126
|
| a colour property | `ColorField` | `<input type="color">` — OS dialog, ignores the theme, wrong size |
|
|
47
127
|
| ambient document facts | `StatusBar` | a toolbar — status is glanced at, not operated |
|
|
48
128
|
| chrome typography | `text-ui-md` / `-sm` / `-body` / `-section` / `-micro` / `-num` | `text-body-*` — page tiers, ~1/3 too large here |
|
|
129
|
+
| a title in a panel | `text-title-lg` (14px `text-ui-title` in compact) | a heading tier, or a page-tier override on `:root` |
|
|
130
|
+
| a top bar over one column | `WorkspaceBar` first in the column, with `Breadcrumbs` | a hand-built `<header>` with `/` spans |
|
|
131
|
+
| nav groups in a rail | `SidebarGroup` | `SideNav` + `SideNavGroup` — another set of columns |
|
|
132
|
+
| the account at the foot of a rail | `SidebarAccount` as a `MenuTrigger` | an Entity + a Settings Button + a Badge |
|
|
133
|
+
| a view switch in a bar | `TabsList variant="pill"` | underline tabs (page idiom), a hand-built segmented row |
|
|
134
|
+
| rows grouped by state | `DataTable groupBy` + `groups` | a DataTable per group in Collapsibles |
|
|
135
|
+
| a date property | `DatePicker size="xs"` | `<input type="date">` — OS format, wrong size |
|
|
136
|
+
| a person in a row | `Avatar size="2xs"` / `"xs"`, `AvatarGroup` for several | a class on Avatar to shrink it |
|
|
137
|
+
| a project or workspace mark | `Avatar shape="square" tone="…"` | a tinted `<span>` |
|
|
138
|
+
| an inspector on a phone | `Panel narrow="sheet"` | a media-query hook and a second render in a Sheet |
|
|
139
|
+
| a reading tab | `<Density value="comfortable">` | prose in chrome tiers |
|
|
49
140
|
|
|
50
141
|
## Menus, selects and popovers adapt on their own
|
|
51
142
|
|
|
@@ -104,9 +195,12 @@ a modal is its own surface rather than part of the control that opened it.
|
|
|
104
195
|
the nesting reads inverted. Use `treeIndent(depth)`; never hand-write an inset.
|
|
105
196
|
- **No pills in chrome.** The compact scope flattens `--button-radius` to ~5px —
|
|
106
197
|
one of two page-register rules the workspace register deliberately reverses.
|
|
198
|
+
`TabsList variant="pill"` takes that radius too, so in a bar it is a segment.
|
|
107
199
|
- **Drag with window listeners, not `setPointerCapture`.** Capture throws for an
|
|
108
200
|
inactive pointer id and the throw aborts the handler mid-gesture, silently.
|
|
109
|
-
- **An unmapped `<Icon name>` renders nothing.**
|
|
201
|
+
- **An unmapped `<Icon name>` renders nothing.** A development build warns and
|
|
202
|
+
names the nearest names, and Lucide or Heroicons spellings resolve, but check
|
|
203
|
+
with `sable icon <name>` before you write one, through a wrapper too.
|
|
110
204
|
|
|
111
205
|
## Verify
|
|
112
206
|
|
|
@@ -136,6 +230,8 @@ and distinguish observed behavior from untested claims.
|
|
|
136
230
|
## Read next
|
|
137
231
|
|
|
138
232
|
- `DESIGN.md → Registers` — doctrine, measured numbers, the two reversals
|
|
233
|
+
- `sable pattern TrackerPage --skeleton` — the records workspace, whole
|
|
139
234
|
- `llms/components/workspace.md`, `panel-group.md`, `panel-section.md`,
|
|
140
|
-
`
|
|
235
|
+
`sidebar.md`, `data-table.md`, `tree.md`, `scrub-field.md`, `status-bar.md`,
|
|
236
|
+
`color-field.md`
|
|
141
237
|
- `llms/reference/token-intent.md` — which token to reach for
|
|
@@ -46,7 +46,13 @@ for each recognizable element with `sable search "<need>" --json`; inspect the
|
|
|
46
46
|
matching `component <Name> --props` and `--examples` before implementation.
|
|
47
47
|
Use Sable's composed anatomy and supported variants. A hand-built button, field,
|
|
48
48
|
menu, dialog, table, or card that imitates a shipped component violates the contract.
|
|
49
|
-
That binds behaviour and parts, not layouts.
|
|
49
|
+
That binds behaviour and parts, not layouts. Search a part by its plain name and
|
|
50
|
+
its role before writing a class or component for it (`sable search breadcrumb`,
|
|
51
|
+
`sable search "top bar"`); exported parts such as `PropertyRow` and `WorkspaceBar`
|
|
52
|
+
are listed by name, and `sable component <Part>` answers with their entry. When a
|
|
53
|
+
part's look or size disagrees with the design, use its variant or prop, or report
|
|
54
|
+
the missing variant; never rebuild it. `sable icon <name>` says whether an icon
|
|
55
|
+
exists. Results marked ◇ (patterns, blocks,
|
|
50
56
|
and compositions such as MediaTile) are references: use one when its layout fits
|
|
51
57
|
the brief, otherwise compose your own from Sable's parts. The brief's signature
|
|
52
58
|
surfaces, where the product's identity lives, are designed from its direction.
|
|
@@ -65,8 +71,10 @@ implement genuinely app-specific structure without creating parallel controls.
|
|
|
65
71
|
|
|
66
72
|
## Finish the working product
|
|
67
73
|
|
|
68
|
-
Run `sable
|
|
69
|
-
checks.
|
|
74
|
+
Run `sable check <source paths>` (doctor, lint and grade) and the project's
|
|
75
|
+
build/type checks. Answer each Rebuilt parts note in the reuse inventory, and fix
|
|
76
|
+
a colour-modes warning: app colours live in a preset with both modes, and a
|
|
77
|
+
`ThemeSwitcher` under `SableThemeProvider` lets the user review each. Inspect desktop/mobile layouts, operate the primary task and recovery
|
|
70
78
|
path, and check keyboard focus, fonts, reduced motion, and meaningful states.
|
|
71
79
|
Use [reviewing-a-design.md](./reviewing-a-design.md),
|
|
72
80
|
[reviewing-a-journey.md](./reviewing-a-journey.md), and
|
|
@@ -21,6 +21,15 @@ are optional: set `page-inset` and the `region-*` caps (`form`, `feed`, `content
|
|
|
21
21
|
`wide`, `full`) in `tokens.shared` only when the direction calls for a different
|
|
22
22
|
page proportion, and keep each cap's role.
|
|
23
23
|
|
|
24
|
+
Overall type size is one token. Sable's scale is built on a 16px base;
|
|
25
|
+
`"type-base": "14"` (or 13) in `tokens.shared` rebuilds every page tier at that
|
|
26
|
+
base, keeping their ratios, and spacing follows because the rhythm is derived
|
|
27
|
+
from body size. Use it when the direction is denser or more technical than the
|
|
28
|
+
bundled presets (a tracker, a console, "like Linear"). Don't rescale the root
|
|
29
|
+
font-size, and don't override tiers one by one to the same end. Retune a single
|
|
30
|
+
tier only when that tier's role changes. Inside a Workspace the chrome already
|
|
31
|
+
uses its own compact `ui-*` tiers.
|
|
32
|
+
|
|
24
33
|
```bash
|
|
25
34
|
pnpm exec sable preset --template
|
|
26
35
|
pnpm exec sable preset --check .sable/presets/clay.json --json
|