@sableui/react 0.17.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.
Files changed (154) hide show
  1. package/AGENTS.md +10 -3
  2. package/CHANGELOG.md +235 -0
  3. package/README.md +11 -4
  4. package/bin/sable.mjs +266 -30
  5. package/dist/{_contract-CDa9-NdB.d.ts → _contract-DlklV0Im.d.ts} +2 -2
  6. package/dist/activity-DT8VK9fx.d.ts +25 -0
  7. package/dist/adapters/github.d.ts +41 -0
  8. package/dist/adapters/github.js +24 -0
  9. package/dist/blocks/index.d.ts +1 -1
  10. package/dist/components/activity-heatmap/activity-heatmap.js +420 -0
  11. package/dist/components/activity-heatmap/activity-heatmap.meta.js +142 -0
  12. package/dist/components/activity-heatmap/index.js +9 -0
  13. package/dist/components/avatar/avatar.js +16 -7
  14. package/dist/components/avatar/avatar.meta.js +43 -10
  15. package/dist/components/avatar/avatar.variants.js +26 -2
  16. package/dist/components/code-block/code-block.js +5 -3
  17. package/dist/components/code-block/code-block.meta.js +6 -0
  18. package/dist/components/collapsible/collapsible.js +6 -5
  19. package/dist/components/collapsible/collapsible.meta.js +14 -5
  20. package/dist/components/data-table/data-table.js +132 -45
  21. package/dist/components/data-table/data-table.meta.js +63 -4
  22. package/dist/components/date-picker/date-picker.js +13 -6
  23. package/dist/components/date-picker/date-picker.meta.js +22 -0
  24. package/dist/components/dialog/dialog.js +25 -5
  25. package/dist/components/dialog/dialog.meta.js +26 -5
  26. package/dist/components/media-image/media-image.js +3 -1
  27. package/dist/components/media-image/media-image.meta.js +15 -1
  28. package/dist/components/media-tile/media-tile.js +13 -1
  29. package/dist/components/media-tile/media-tile.meta.js +10 -0
  30. package/dist/components/menu/menu.js +2 -0
  31. package/dist/components/menu/menu.meta.js +2 -2
  32. package/dist/components/page-header/page-header.js +9 -4
  33. package/dist/components/page-header/page-header.meta.js +26 -1
  34. package/dist/components/panel-group/panel-group.js +17 -1
  35. package/dist/components/panel-group/panel-group.meta.js +43 -3
  36. package/dist/components/pill/pill.meta.js +15 -6
  37. package/dist/components/pill/pill.variants.js +1 -0
  38. package/dist/components/search-input/search-input.js +30 -5
  39. package/dist/components/search-input/search-input.meta.js +29 -4
  40. package/dist/components/section-header/section-header.js +27 -17
  41. package/dist/components/section-header/section-header.meta.js +27 -5
  42. package/dist/components/sheet/sheet.js +15 -3
  43. package/dist/components/sheet/sheet.meta.js +2 -2
  44. package/dist/components/side-nav/side-nav.variants.js +8 -3
  45. package/dist/components/sidebar/index.js +4 -0
  46. package/dist/components/sidebar/sidebar.js +90 -11
  47. package/dist/components/sidebar/sidebar.meta.js +38 -4
  48. package/dist/components/table/table.js +7 -3
  49. package/dist/components/tabs/tabs.js +10 -2
  50. package/dist/components/tabs/tabs.meta.js +4 -0
  51. package/dist/components/workspace/workspace.js +13 -3
  52. package/dist/components/workspace/workspace.meta.js +109 -1
  53. package/dist/file-hashes.json +94 -80
  54. package/dist/foundations/typography.js +13 -0
  55. package/dist/icon/Icon.js +21 -2
  56. package/dist/icon/index.d.ts +36 -1
  57. package/dist/icon/index.js +5 -0
  58. package/dist/icon/names.js +240 -0
  59. package/dist/icon-sets/reicon.js +41 -1
  60. package/dist/index.d.ts +540 -75
  61. package/dist/index.js +18 -1
  62. package/dist/layout/AspectBox.js +2 -5
  63. package/dist/layout/Bleed.js +10 -6
  64. package/dist/layout/Center.js +11 -3
  65. package/dist/layout/Columns.js +6 -3
  66. package/dist/layout/Grid.js +14 -6
  67. package/dist/layout/GridOverlay.js +7 -7
  68. package/dist/layout/Region.js +18 -3
  69. package/dist/layout/Row.js +27 -20
  70. package/dist/layout/Spacer.js +13 -2
  71. package/dist/layout/SplitPane.js +1 -1
  72. package/dist/layout/Stack.js +25 -18
  73. package/dist/layout/index.d.ts +57 -6
  74. package/dist/lib/chart/activity.js +32 -0
  75. package/dist/lib/chart/calendar.js +67 -0
  76. package/dist/lib/chart/chart-tooltip.js +2 -2
  77. package/dist/lib/chart/heat.js +55 -0
  78. package/dist/lib/cn.js +1 -0
  79. package/dist/lib/focus-return.js +53 -0
  80. package/dist/lib/taxonomy.js +1 -0
  81. package/dist/lib/use-media-query.js +41 -0
  82. package/dist/{meta-DX5r5wQL.d.ts → meta-Dfm9AExe.d.ts} +6 -0
  83. package/dist/patterns/dashboard-page.js +23 -17
  84. package/dist/patterns/index.d.ts +7 -2
  85. package/dist/patterns/index.js +5 -1
  86. package/dist/patterns/tracker-page.js +392 -0
  87. package/dist/patterns/tracker-page.meta.js +40 -0
  88. package/dist/presets/index.d.ts +1 -1
  89. package/dist/styles.css +301 -188
  90. package/dist/{theme-provider-BydfM5Z0.d.ts → theme-provider-BUBealk_.d.ts} +1 -1
  91. package/dist/themes/_contract.js +9 -1
  92. package/dist/themes/atelier/index.d.ts +1 -1
  93. package/dist/themes/ember/index.d.ts +1 -1
  94. package/dist/themes/index.d.ts +2 -2
  95. package/dist/themes/meridian/index.d.ts +1 -1
  96. package/dist/themes/poppy/index.d.ts +1 -1
  97. package/dist/themes/prism/index.d.ts +1 -1
  98. package/dist/themes/sable/index.d.ts +1 -1
  99. package/dist/themes/verdant/index.d.ts +1 -1
  100. package/llms/components/activity-heatmap.md +133 -0
  101. package/llms/components/avatar.md +32 -9
  102. package/llms/components/code-block.md +1 -0
  103. package/llms/components/collapsible.md +12 -4
  104. package/llms/components/data-table.md +40 -3
  105. package/llms/components/date-picker.md +15 -1
  106. package/llms/components/dialog.md +34 -3
  107. package/llms/components/media-image.md +12 -0
  108. package/llms/components/media-tile.md +21 -0
  109. package/llms/components/menu.md +1 -1
  110. package/llms/components/page-header.md +16 -1
  111. package/llms/components/panel-group.md +34 -2
  112. package/llms/components/pill.md +24 -5
  113. package/llms/components/search-input.md +37 -4
  114. package/llms/components/section-header.md +28 -4
  115. package/llms/components/sheet.md +2 -2
  116. package/llms/components/sidebar.md +17 -4
  117. package/llms/components/tabs.md +1 -0
  118. package/llms/components/workspace.md +81 -1
  119. package/llms/foundations/typography.md +4 -1
  120. package/llms/layout/aspect-box.md +1 -1
  121. package/llms/layout/bleed.md +1 -1
  122. package/llms/layout/center.md +1 -1
  123. package/llms/layout/columns.md +1 -1
  124. package/llms/layout/grid.md +1 -1
  125. package/llms/layout/region.md +1 -1
  126. package/llms/layout/row.md +9 -1
  127. package/llms/layout/spacer.md +1 -1
  128. package/llms/layout/split-pane.md +1 -1
  129. package/llms/layout/stack.md +1 -1
  130. package/llms/patterns/dashboard-page.md +18 -15
  131. package/llms/patterns/tracker-page.md +450 -0
  132. package/llms/reference/token-intent.md +3 -1
  133. package/llms/reference/utilities.md +4 -1
  134. package/llms/tasks/auditing-an-app.md +35 -1
  135. package/llms/tasks/building-a-page.md +3 -2
  136. package/llms/tasks/building-a-tool.md +101 -5
  137. package/llms/tasks/building-with-sable.md +11 -3
  138. package/llms/tasks/creating-a-preset.md +9 -0
  139. package/llms/tasks/getting-started.md +10 -3
  140. package/llms/tasks/using-presets.md +1 -2
  141. package/llms-full.txt +1215 -89
  142. package/llms.txt +11 -9
  143. package/package.json +7 -1
  144. package/registry.json +1021 -70
  145. package/scripts/adoption.mjs +252 -0
  146. package/scripts/agent-setup.mjs +110 -18
  147. package/scripts/app-css.mjs +129 -0
  148. package/scripts/grade.mjs +178 -2
  149. package/scripts/lint-rules.mjs +126 -0
  150. package/scripts/wiring.mjs +2 -1
  151. package/skills/entry/SKILL.md +1 -1
  152. package/skills/sable/SKILL.md +64 -6
  153. package/skills/sable/agents/openai.yaml +1 -1
  154. package/targets/ios.json +9 -0
package/AGENTS.md CHANGED
@@ -153,6 +153,11 @@ In a monorepo where Sable belongs to one workspace package, run setup in that
153
153
  package with `--root` naming the repository root (for example
154
154
  `pnpm --filter web exec sable setup --agent --root ../..`); the entries go
155
155
  there and resolve Sable through the package.
156
+ Setup also adds a short managed block to the project's `AGENTS.md` and
157
+ `CLAUDE.md`, the instructions an agent reads on every task, so a UI request
158
+ goes through the skill even when it doesn't mention Sable. Only the text between
159
+ its `<!-- sable:begin -->` and `<!-- sable:end -->` markers is Sable's;
160
+ `--no-instructions` skips it.
156
161
  Each entry resolves `skills/sable/SKILL.md` from the installed package, so package
157
162
  upgrades also update the workflow. Other agents can read that file directly.
158
163
  Use `$sable build <idea>`, `inspire <references>`, `audit <target>`,
@@ -160,9 +165,11 @@ Use `$sable build <idea>`, `inspire <references>`, `audit <target>`,
160
165
  Claude Code or Cursor. `create` is a build alias. `fix` takes the short path for
161
166
  one scoped defect and escalates to `polish` when the change grows. These are agent modes, not shell commands.
162
167
 
163
- Upgrade with `pnpm update @sableui/react --latest`, then
164
- `pnpm exec sable setup --agent --update`. Setup only replaces managed files
165
- that have not been locally edited; `--dry-run` checks without writing. Keep
168
+ Upgrade with `pnpm exec sable upgrade`: it updates the package, then runs the
169
+ new version's `init`, which refreshes the skill entries and the instructions
170
+ block and checks the wiring. From 0.17 or earlier, which has no `upgrade`, run
171
+ `pnpm update @sableui/react --latest` and then `pnpm exec sable init` once.
172
+ Setup only replaces managed files that have not been locally edited; `--dry-run` checks without writing. Keep
166
173
  project preferences in project instructions. Package installation alone does not
167
174
  change agent settings. See [building-with-sable.md](./llms/tasks/building-with-sable.md),
168
175
  [creating-a-preset.md](./llms/tasks/creating-a-preset.md), and
package/CHANGELOG.md CHANGED
@@ -1,5 +1,240 @@
1
1
  # What's new
2
2
 
3
+ ## 0.19.0
4
+
5
+ A compact work tracker, built on Sable by an agent, rebuilt about thirty parts
6
+ Sable already ships. Every gap behind those rebuilds is fixed here: a lookup
7
+ that couldn't find parts, checks that couldn't see the app's own CSS, and
8
+ components that had no variant for a dense layout.
9
+
10
+ - **`--type-base` rebuilds the type scale at another base size.** Set
11
+ `--type-base: 14` (a unitless px number; the default is 16) on `:root`, a
12
+ `[data-sable-theme]` scope or in a preset's `tokens.shared`, and every page
13
+ tier scales by `base / 16`, including each theme's own tier values and any
14
+ per-tier override. Spacing follows, because the baseline step is derived from
15
+ body size. The workspace `ui-*` tiers stay absolute px, and compact still only
16
+ ever shrinks text. Don't change the root font-size to get a denser UI: it
17
+ scales every rem in the app, not just the type.
18
+ - **New `text-ui-title`** (14px / 600 / 20px leading, tokens
19
+ `--type-ui-title-*`). Inside a compact scope `text-title-lg` maps to it. It
20
+ used to collapse to 12px, the same size as the description under it.
21
+ - **A comfortable scope inside a compact one gets page type back.**
22
+ `<Density value="comfortable">` around a reading view (an overview, notes,
23
+ docs) in a Workspace used to reset the control sizes but not the text, which
24
+ stayed at 11px.
25
+ - **Tables follow density.** TableHead's height, TableCell's padding and the
26
+ table's text tier read density tokens. In a compact Workspace that is a 28px
27
+ head, 32px rows and `text-ui-body`, with no consumer CSS.
28
+ - **Compact on a touch screen uses the comfortable control ladder.** Under
29
+ `pointer: coarse` the 24/28/32 ladder, measured from mouse-driven editors,
30
+ becomes 28/32/40.
31
+ - **Workspace's body is its only stretching row.** The grid always assumed a
32
+ toolbar, so a Workspace without one put the body in the auto track and
33
+ clipped the status bar. The root is now a flex column, which holds for every
34
+ combination of slots. Migration: drop any `grid-template-rows` override on
35
+ the Workspace root.
36
+ - **Workspace and Panel on small screens.** Workspace takes `bottomNav`, a row
37
+ shown below `lg`. Panel takes `narrow="sheet" | "hidden"` with `open`,
38
+ `onOpenChange`, `side` and `below`: below the breakpoint an inspector becomes
39
+ a Sheet and its content renders once. A Sidebar moved into that sheet fills
40
+ it. New `useMediaQuery` and
41
+ `useBelowBreakpoint` hooks are exported. A WorkspaceBar can also sit at the
42
+ top of one column, so the inspector runs the full height beside it, as in
43
+ Linear.
44
+ - **DataTable groups rows.** `groupBy`, `groups` (each with an icon, an action
45
+ and `defaultExpanded`), `collapsible` and controlled `expandedGroups` give
46
+ one table with one header and a header row per group that carries a toggle,
47
+ a count and an add action. Sorting applies within each group, and select-all
48
+ acts on the visible rows.
49
+ - **The Sidebar rail is one grid, at either density.** New `SidebarGroup`
50
+ labels a run of items, so a rail no longer has to borrow SideNav for its
51
+ groups. New `SidebarAccount` is the account row: the avatar in the icon slot,
52
+ the label and one detail line on the label column, and an up-down chevron.
53
+ Make it the account Menu's trigger and put Settings, appearance and sign-out
54
+ in the menu. Inside a compact scope such as a Workspace, the whole rail takes
55
+ 32px rows and 20px icons, and the header matches the chrome bar's height.
56
+ Before this, a tool's footer mixed a ghost Button, an Entity patched with
57
+ `[--entity-py:0]` and a Badge, and the rail's icons and labels landed on four
58
+ columns. DashboardPage uses the new parts.
59
+ - **Underline tabs in a WorkspaceBar sit on the bar's hairline.** They used to
60
+ draw a second, shorter rule that stopped after the last tab, with the mark
61
+ floating above the bar's edge. Tabs guidance now steers a view switch in tool
62
+ chrome to `variant="pill"`.
63
+ - **`MenuSubmenuTrigger` takes `icon`**, as MenuItem does, so a submenu row
64
+ lines up with the icon rows around it.
65
+ - New icon `chevron-up-down` (Lucide's `chevrons-up-down` resolves to it).
66
+ - **Avatar:** `2xs` (20px) and `xs` (24px), `shape="square"` for a workspace,
67
+ project or org mark, and a palette `tone` for the initials fallback.
68
+ - **DatePicker:** `size="xs"` for a property row, and `formatOptions`
69
+ (`Intl.DateTimeFormatOptions`) for the trigger text.
70
+ - **CollapsibleIndicator needs no setup.** It no longer needs the
71
+ `group/collapsible` class on its trigger. New `direction="end"` gives a side
72
+ caret that turns down on open, mirrored in RTL.
73
+ - **Icons:** new `users`, `archive`, `kanban`, `sliders`, `help` and `sidebar`.
74
+ About 90 Lucide and Heroicons names now resolve to Sable's (`settings` →
75
+ `gear`, `menu` → `bars`, `check-circle` → `circle-check`). A development
76
+ build warns once for a name the set can't draw, and names the nearest ones.
77
+ - **A toast clears an open side sheet on a phone.** It used to move to the
78
+ top, over the sheet's close button. It now sits below the sheet's header
79
+ inset, tunable with `--sable-sheet-top-inset`.
80
+ - **Workspace surfaces derive in oklab.** The canvas, panel, field, hairline
81
+ and shell-ground mixes used `color-mix(in oklch, …)`. On hex colours Chrome
82
+ resolves that to a colour with no hue, painted as 0°: a brown cast on a cool
83
+ graphite preset's canvas. Bundled themes write oklch and never showed it, but
84
+ presets and apps write hex. The heatmap's empty cell moves to oklab too.
85
+ - **`--nav-height` is defined** (56px). AppShell's bottom padding read it with
86
+ no fallback, so the padding was dropped.
87
+ - **Agent tooling finds parts.** `sable component PropertyRow` (or `Panel`,
88
+ `WorkspaceBar`, `CollapsibleTrigger`) answers with the parent component;
89
+ it used to be ERR_UNKNOWN_COMPONENT. Search indexes parts, and an exact name
90
+ ranks first. New `sable icon [name]` lists the drawable names and resolves
91
+ aliases.
92
+ - **`sable check` sees rebuilt parts.** A new "Rebuilt parts" block reads class
93
+ names in the app's markup and the app's own CSS. It flags a breadcrumb, top
94
+ bar, property row, status dot or avatar stack built by hand; fixed bar and row
95
+ heights; selectors reaching into Sable's components; and a chevron rotated on
96
+ `aria-expanded`. Icon names passed through an app's own wrapper are checked
97
+ too. These are notes, and the skill asks the agent to answer each one.
98
+ - **`sable check` warns on one-mode colour.** Colour tokens set for light with
99
+ no dark value now produce a warning, and an app with no ThemeSwitcher gets a
100
+ note. The skill now ships both modes, as a preset with a ThemeSwitcher under
101
+ SableThemeProvider, unless the brief rules one out.
102
+ - **New pattern: `TrackerPage`.** A records workspace in the tool register,
103
+ the reference shape for an issue tracker, a support queue or a pipeline. It
104
+ has a Sidebar rail of grouped views ending in an account menu (with
105
+ appearance), Breadcrumbs and pill Tabs in WorkspaceBars, a filter row, one
106
+ grouped DataTable, a docked inspector of PanelSection property rows with a
107
+ pinned comment form, and a comfortable reading tab. Below lg the rail and the
108
+ inspector become sheets and BottomNav takes the last row. `sable pattern
109
+ TrackerPage --skeleton` has the tree. Pattern metadata takes `keywords` now,
110
+ so "issue tracker", "like Linear" or "support queue" lands on the shell first.
111
+ - **Guidance for a records workspace.** `building-a-tool` now covers the
112
+ shape of an issue tracker, a support queue or a pipeline: the shell, the
113
+ decisions that keep it one system (one rail grid, the account as a row and a
114
+ menu, one grouped table, an inspector that renders once, page-sized reading
115
+ tabs, pill tabs in chrome, both modes, `type-base` for "compact") and a
116
+ "you want / use / not" table built from what a real build rebuilt. The skill
117
+ routes a tool, tracker or "like Linear" brief there; `building-a-page` points
118
+ trackers to it; `creating-a-preset` explains `type-base`.
119
+ - **`sable check` notes compositions another part does better:** SideNav
120
+ inside a Sidebar, an Entity or Badge in the rail's footer, a DataTable per
121
+ group inside Collapsibles, underline tabs in a WorkspaceBar, and a native
122
+ date input. Notes, never failures. On the build that prompted this release
123
+ they flag four drifts, each at its line.
124
+ - **The skill searches before it builds.** It looks up a part by its plain name
125
+ and role before writing any class or component for it. A style or layout
126
+ disagreement means using the variant or prop, or reporting the missing
127
+ variant, never rebuilding the part.
128
+ - Migration: run `sable sources --write` after upgrading. Panel now imports
129
+ Sheet, so the generated sources file is stale until it is rewritten, and
130
+ doctor says so.
131
+
132
+ ## 0.18.0
133
+
134
+ A year at a glance: the contribution graph, built so a phone, a keyboard and a
135
+ screen reader can all read it.
136
+
137
+ - **New: `ActivityHeatmap`.** A calendar heatmap: one value per day as a grid
138
+ of weeks by weekdays — the GitHub contribution graph, for any daily measure.
139
+ Pass days as `"YYYY-MM-DD"` with a value (or a date-to-value map); levels
140
+ come by quartile, as GitHub's do, unless a day brings its own. `categories`
141
+ colour days by source instead of intensity, and `mergeActivity` tags each day
142
+ with its source or `both`. The grid is a real `role="grid"` table with one
143
+ tab stop: arrows step a day or a week, each cell is named with its date and
144
+ value, and the tooltip shows on hover, focus and tap. It fills the width down
145
+ to `size`; narrower, the weeks scroll sideways and open on the latest, while
146
+ the weekday labels stay outside the scroller. Days are read as calendar days,
147
+ never instants, so no time zone shifts one. Prompted by a consumer site that
148
+ hand-built one from 371 buttons and broke on phones.
149
+ - **New: `@sableui/react/adapters/github`.** `fromGitHubGraphQL` and
150
+ `fromGitHubContributionsApi` turn GitHub's contribution data into heatmap
151
+ days. Pure transforms: fetch on your server and pass the result in.
152
+ - **New: `activityLevels` and `activityGrid`.** The level scale and the week
153
+ grid behind the heatmap, exported for a custom legend, a summary stat or
154
+ another layout.
155
+ - **`ChartTooltipContent` with no rows** draws just its label, so a caller's
156
+ own content sits on the standard tooltip card.
157
+ - **Layout primitives take `className` over their own layout.** Row, Stack,
158
+ Grid, Columns, Col, Center, Region, Page, Bleed, AspectBox, Spacer, SplitPane
159
+ and GridOverlay set `display`, direction, alignment, gap, inset, cap, ratio and
160
+ size inline, and an inline declaration beats every utility, so
161
+ `<Row className="max-lg:hidden">` or `hidden md:flex` silently did nothing.
162
+ The grid and split rules in `styles.css` were unlayered too, so `hidden` lost
163
+ to them whatever its specificity. Layout now lives in classes merged through
164
+ `cn()`, with prop values passed as CSS variables those classes read, and the
165
+ layout rules sit in `@layer components`. A utility in `className` wins at any
166
+ breakpoint (`max-md:flex-col`, `md:gap-6`, `lg:grid-cols-3`); the props work
167
+ as before. Migration: a `className` that used to be ignored on a primitive now
168
+ applies, and a test reading `style.gap` or `style.maxWidth` reads
169
+ `--sable-row-gap`, `--sable-region-max` and the like instead.
170
+ - **`PageHeader size="lg"`.** A display-size page title for an editorial page
171
+ (a personal site, a marketing page, an article index): `text-display-lg` over
172
+ a `text-body-lg` lede capped at the prose measure. `md`, the default, is
173
+ unchanged. Keep `lg` off app routes: display type stays out of product chrome.
174
+ - **`SectionHeader size="lg"`.** The major-section tier, `text-heading-2` over a
175
+ `text-body-md` description, for an editorial page's sections under a
176
+ `PageHeader size="lg"`. It stops at heading-2 because heading-1 is the page
177
+ title's, one per route. Actions stay centred on the title's first line at
178
+ every size.
179
+ - **`SearchInput` takes `size`** (`md` | `sm` | `xs`), on the same ladder as
180
+ Input, Select and Combobox. `sm` is the toolbar field on `--control-sm`, `xs`
181
+ the inset tool-panel field; the magnifier, padding and clear button scale with
182
+ it and stay centred. Before, it was fixed at 40px and matched nothing in a
183
+ toolbar.
184
+ - **`Pill size="lg"`.** A 32px chip on `--control-sm`, the toolbar height Button
185
+ `sm` and SearchInput `sm` share, so a filter row beside a search field is one
186
+ height in either density.
187
+ - **`MediaImage` and `MediaTile` take a crop focus.** `position` sets where the
188
+ image sits in its frame and takes any CSS `object-position` value
189
+ (`"35% 50%"`, `"top"`), beside `fit`. MediaTile forwards it to its cover.
190
+ - **Dialogs return focus to whatever opened them.** `Dialog`, `AlertDialog` and
191
+ `Sheet` record the element focused when `open` turns true and send focus back
192
+ to it on close, with or without a trigger. Before, a dialog opened from your
193
+ own button lost focus to the page whenever a field inside autofocused,
194
+ CommandMenu's included. An explicit `finalFocus` still wins.
195
+ - **`DialogContent keepMounted`.** Keeps a closed dialog's content mounted and
196
+ hidden, so a half-written draft survives Esc or a stray click and is still
197
+ there on reopen. Opt in for drafts the user may come back to.
198
+ - **Eight more icon names.** `briefcase`, `layers`, `microphone`, `video`,
199
+ `broadcast`, `newspaper`, `palette` and `gamepad` join the contract, mapped
200
+ in the Reicon set, for a portfolio that imported reicon-react directly for
201
+ its work, audio, video, live, press, design and games sections.
202
+ - **Setup writes the skill into the instructions every task reads.** A skill
203
+ loads only when a request names it, so "add a pricing page" in a wired app
204
+ could skip it: the agent saw Tailwind and a stylesheet, wrote its own Button
205
+ and Modal, and put Sable's tokens on them. `sable setup --agent` (and `sable
206
+ init`) now also writes a short managed block into `AGENTS.md` and
207
+ `CLAUDE.md` that sends every UI request through the skill. Only the text
208
+ between its `<!-- sable:begin -->` and `<!-- sable:end -->` markers is
209
+ Sable's; `--no-instructions` skips it. **Migration:** from 0.17, run
210
+ `pnpm update @sableui/react --latest` then `pnpm exec sable init` once; after
211
+ that, `sable upgrade` does both.
212
+ - **New: `sable upgrade`.** One command to update: installs the latest
213
+ `@sableui/react` with the project's package manager, then runs the new
214
+ version's `init`, so the skill entries, the instructions block and the
215
+ checks are the new release's. Safe on an app that already works.
216
+ - **"Move this app onto Sable" is a request the skill understands.** It checks
217
+ the app, shows the swaps once, asks, and moves them a screen at a time; it
218
+ never starts a new build. `init` says so when an app's UI barely uses Sable,
219
+ and its next step for a ready app is now a plain request, not mode syntax.
220
+ - **Adoption, in `sable check`, `sable grade` and `sable doctor`.** How much of
221
+ the UI composes Sable, which app-built components do by hand what a Sable
222
+ component already does (a `Modal` → Dialog, a `SearchBar` → SearchInput,
223
+ behaviour first), and what the app already stands on: nothing, its own
224
+ primitives, or another library. Never a failure. `check` lists the swaps and,
225
+ when adoption is low, makes "ask the user about moving onto Sable" the first
226
+ review step; `doctor` warns. The skill and `sable docs auditing-an-app` say
227
+ how to put the choice to the user, more firmly when the app has no
228
+ foundation of its own.
229
+ - **The skill triggers on any UI work in a Sable app.** Its description now
230
+ says so, even when the request doesn't mention Sable.
231
+ - **`sable init --hook`.** Adds the Claude Code Stop hook that runs `sable
232
+ check` before a task can end. Run in a terminal, init asks; `--no-hook`
233
+ doesn't.
234
+ - **`CodeBlock wrap`.** Wraps long lines instead of scrolling them, for prose
235
+ in a code face: a prompt to paste into an agent, a log line. Code keeps
236
+ scrolling.
237
+
3
238
  ## 0.17.0
4
239
 
5
240
  Knowing where you are: a rail that follows a long read, and an approval
package/README.md CHANGED
@@ -69,7 +69,7 @@ pnpm add @sableui/react
69
69
  pnpm exec sable init # or: npx sable init — once the package is installed
70
70
  ```
71
71
 
72
- `init` reads your package manager from the lockfile and your framework from the project. It installs what is missing (React, Tailwind and its build plugin), puts the CSS imports below in order, adds React dedupe and the Tailwind plugin to a Vite config, loads the fonts, mounts `IconProvider` in a Vite starter's entry, installs the agent skill (`sable setup --agent`), then runs `sable doctor`. Anything it cannot change safely — an unfamiliar config, a Next.js layout — it prints as the exact snippet and the file it belongs in. Vite and Next.js (App Router) get every step; other setups get the packages and the stylesheet. `--dry-run` shows every change first; `--no-agent` skips the skill. Already set up? `sable doctor --fix` applies the same fixes to whatever doctor flags.
72
+ `init` reads your package manager from the lockfile and your framework from the project. It installs what is missing (React, Tailwind and its build plugin), puts the CSS imports below in order, adds React dedupe and the Tailwind plugin to a Vite config, loads the fonts, mounts `IconProvider` in a Vite starter's entry, installs the agent skill and its block in `AGENTS.md` / `CLAUDE.md` (`sable setup --agent`), offers the Claude Code Stop hook when you run it in a terminal, then runs `sable doctor`. Anything it cannot change safely — an unfamiliar config, a Next.js layout — it prints as the exact snippet and the file it belongs in. Vite and Next.js (App Router) get every step; other setups get the packages and the stylesheet. `--dry-run` shows every change first; `--no-agent` skips the skill. Already set up? `sable doctor --fix` applies the same fixes to whatever doctor flags.
73
73
 
74
74
  The steps below are what `init` does, for doing it by hand or checking its work.
75
75
 
@@ -213,6 +213,11 @@ In a monorepo where Sable belongs to one workspace package, run setup in that
213
213
  package with `--root` naming the repository root (for example
214
214
  `pnpm --filter web exec sable setup --agent --root ../..`); the entries go
215
215
  there and resolve Sable through the package.
216
+ Setup also adds a short managed block to the project's `AGENTS.md` and
217
+ `CLAUDE.md`, the instructions an agent reads on every task, so a UI request
218
+ goes through the skill even when it doesn't mention Sable. Only the text between
219
+ its `<!-- sable:begin -->` and `<!-- sable:end -->` markers is Sable's;
220
+ `--no-instructions` skips it.
216
221
  Each entry resolves `skills/sable/SKILL.md` from the installed package, so package
217
222
  upgrades also update the workflow. Other agents can read that file directly.
218
223
  Use `$sable build <idea>`, `inspire <references>`, `audit <target>`, or
@@ -225,9 +230,11 @@ server: `claude mcp add --transport http sable https://www.sableui.com/api/mcp`
225
230
  and `docs`, give the CLI's answers from the published package, at the version
226
231
  the agent passes or the latest. Once Sable is installed, the CLI is the default.
227
232
 
228
- Upgrade with `pnpm update @sableui/react --latest`, then
229
- `pnpm exec sable setup --agent --update`. Setup only replaces managed files
230
- that have not been locally edited; `--dry-run` checks without writing. Keep
233
+ Upgrade with `pnpm exec sable upgrade`: it updates the package, then runs the
234
+ new version's `init`, which refreshes the skill entries and the instructions
235
+ block and checks the wiring. From 0.17 or earlier, which has no `upgrade`, run
236
+ `pnpm update @sableui/react --latest` and then `pnpm exec sable init` once.
237
+ Setup only replaces managed files that have not been locally edited; `--dry-run` checks without writing. Keep
231
238
  project preferences in project instructions. Package installation alone does not
232
239
  change agent settings. See [building-with-sable.md](./llms/tasks/building-with-sable.md),
233
240
  [creating-a-preset.md](./llms/tasks/creating-a-preset.md), and