altitude-design 0.4.0 → 0.4.2

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 (280) hide show
  1. package/README.md +1 -0
  2. package/dist/guidance/components/AILabel/README.md +35 -0
  3. package/dist/guidance/components/Accordion/README.md +25 -0
  4. package/dist/guidance/components/AgentFleet/README.md +48 -1
  5. package/dist/guidance/components/AgentLanes/README.md +32 -0
  6. package/dist/guidance/components/AgentRequests/README.md +47 -0
  7. package/dist/guidance/components/Alert/README.md +49 -0
  8. package/dist/guidance/components/AltitudeProvider/README.md +63 -0
  9. package/dist/guidance/components/AppShell/README.md +70 -0
  10. package/dist/guidance/components/AreaChart/README.md +58 -0
  11. package/dist/guidance/components/Artifact/README.md +69 -0
  12. package/dist/guidance/components/Avatar/README.md +41 -0
  13. package/dist/guidance/components/Await/README.md +48 -0
  14. package/dist/guidance/components/Badge/README.md +44 -0
  15. package/dist/guidance/components/BarChart/README.md +62 -0
  16. package/dist/guidance/components/BarList/README.md +58 -0
  17. package/dist/guidance/components/Board/README.md +67 -0
  18. package/dist/guidance/components/Breadcrumb/README.md +31 -0
  19. package/dist/guidance/components/Button/README.md +41 -0
  20. package/dist/guidance/components/Card/README.md +38 -0
  21. package/dist/guidance/components/ChartBrush/README.md +57 -0
  22. package/dist/guidance/components/ChartContainer/README.md +77 -0
  23. package/dist/guidance/components/ChartLegend/README.md +43 -0
  24. package/dist/guidance/components/ChartReference/README.md +74 -0
  25. package/dist/guidance/components/ChartTooltip/README.md +63 -0
  26. package/dist/guidance/components/Checkbox/README.md +35 -0
  27. package/dist/guidance/components/Checklist/README.md +66 -0
  28. package/dist/guidance/components/CodeBlock/README.md +44 -0
  29. package/dist/guidance/components/ColorPicker/README.md +39 -0
  30. package/dist/guidance/components/Combobox/README.md +35 -0
  31. package/dist/guidance/components/CommandPalette/README.md +177 -0
  32. package/dist/guidance/components/CommentThread/README.md +51 -0
  33. package/dist/guidance/components/Confirmation/README.md +60 -0
  34. package/dist/guidance/components/ContextMenu/README.md +51 -0
  35. package/dist/guidance/components/Conversation/README.md +124 -0
  36. package/dist/guidance/components/CopyButton/README.md +31 -0
  37. package/dist/guidance/components/DataGrid/README.md +75 -0
  38. package/dist/guidance/components/DatePicker/README.md +49 -0
  39. package/dist/guidance/components/Dialog/README.md +175 -0
  40. package/dist/guidance/components/DiffView/README.md +77 -0
  41. package/dist/guidance/components/DotPlot/README.md +44 -0
  42. package/dist/guidance/components/Drilldown/README.md +28 -0
  43. package/dist/guidance/components/DropZone/README.md +50 -0
  44. package/dist/guidance/components/DropdownMenu/README.md +44 -0
  45. package/dist/guidance/components/EditRegion/README.md +159 -0
  46. package/dist/guidance/components/EmptyState/README.md +49 -0
  47. package/dist/guidance/components/FeatureGate/README.md +39 -0
  48. package/dist/guidance/components/Field/README.md +36 -0
  49. package/dist/guidance/components/FilterBar/README.md +63 -0
  50. package/dist/guidance/components/FormattedNumber/README.md +44 -0
  51. package/dist/guidance/components/Heatmap/README.md +71 -0
  52. package/dist/guidance/components/HoldButton/README.md +32 -0
  53. package/dist/guidance/components/HoverCard/README.md +53 -0
  54. package/dist/guidance/components/InlineCitation/README.md +32 -0
  55. package/dist/guidance/components/InlineEdit/README.md +247 -1
  56. package/dist/guidance/components/Input/README.md +36 -0
  57. package/dist/guidance/components/InputOTP/README.md +46 -0
  58. package/dist/guidance/components/ItemGroup/README.md +100 -0
  59. package/dist/guidance/components/Kbd/README.md +27 -0
  60. package/dist/guidance/components/LineChart/README.md +62 -0
  61. package/dist/guidance/components/Link/README.md +41 -0
  62. package/dist/guidance/components/Markdown/README.md +81 -0
  63. package/dist/guidance/components/Meter/README.md +52 -0
  64. package/dist/guidance/components/NotificationCenter/README.md +39 -0
  65. package/dist/guidance/components/NumberInput/README.md +37 -0
  66. package/dist/guidance/components/PageHeader/README.md +45 -0
  67. package/dist/guidance/components/Pagination/README.md +33 -0
  68. package/dist/guidance/components/PasswordInput/README.md +36 -0
  69. package/dist/guidance/components/PermissionMatrix/README.md +40 -0
  70. package/dist/guidance/components/Pile/README.md +42 -0
  71. package/dist/guidance/components/PlanPicker/README.md +37 -0
  72. package/dist/guidance/components/Popover/README.md +36 -0
  73. package/dist/guidance/components/Progress/README.md +31 -0
  74. package/dist/guidance/components/PromptInput/README.md +98 -0
  75. package/dist/guidance/components/PropertyList/README.md +80 -0
  76. package/dist/guidance/components/Question/README.md +54 -0
  77. package/dist/guidance/components/RadioGroup/README.md +37 -0
  78. package/dist/guidance/components/RelativeTime/README.md +47 -0
  79. package/dist/guidance/components/RemovalReceipt/README.md +77 -0
  80. package/dist/guidance/components/Resizable/README.md +29 -0
  81. package/dist/guidance/components/SaveBar/README.md +38 -0
  82. package/dist/guidance/components/SavedViews/README.md +58 -0
  83. package/dist/guidance/components/ScatterChart/README.md +63 -0
  84. package/dist/guidance/components/Schedule/README.md +66 -0
  85. package/dist/guidance/components/ScrollArea/README.md +28 -0
  86. package/dist/guidance/components/SecretField/README.md +46 -0
  87. package/dist/guidance/components/Select/README.md +70 -0
  88. package/dist/guidance/components/Separator/README.md +44 -0
  89. package/dist/guidance/components/Sheet/README.md +94 -0
  90. package/dist/guidance/components/Skeleton/README.md +36 -0
  91. package/dist/guidance/components/Slider/README.md +35 -0
  92. package/dist/guidance/components/SortableList/README.md +34 -0
  93. package/dist/guidance/components/Sparkline/README.md +58 -0
  94. package/dist/guidance/components/SplitButton/README.md +39 -0
  95. package/dist/guidance/components/Stat/README.md +61 -0
  96. package/dist/guidance/components/Stepper/README.md +61 -0
  97. package/dist/guidance/components/Suggestions/README.md +58 -0
  98. package/dist/guidance/components/Surface/README.md +28 -0
  99. package/dist/guidance/components/Switch/README.md +29 -0
  100. package/dist/guidance/components/SyncIndicator/README.md +54 -0
  101. package/dist/guidance/components/Table/README.md +62 -0
  102. package/dist/guidance/components/Tabs/README.md +55 -0
  103. package/dist/guidance/components/TagInput/README.md +50 -0
  104. package/dist/guidance/components/Terminal/README.md +42 -0
  105. package/dist/guidance/components/ThreadList/README.md +73 -0
  106. package/dist/guidance/components/TimeInput/README.md +37 -0
  107. package/dist/guidance/components/Timeline/README.md +55 -0
  108. package/dist/guidance/components/Toaster/README.md +38 -0
  109. package/dist/guidance/components/Toggle/README.md +52 -0
  110. package/dist/guidance/components/Toolbar/README.md +69 -0
  111. package/dist/guidance/components/Tooltip/README.md +29 -0
  112. package/dist/guidance/components/Tour/README.md +44 -0
  113. package/dist/guidance/components/Trace/README.md +92 -0
  114. package/dist/guidance/components/Tree/README.md +85 -0
  115. package/dist/guidance/index.json +117 -117
  116. package/dist/guidance/llms.txt +1 -1
  117. package/dist/guidance/manifest.json +120 -120
  118. package/dist/guidance/visual/ActionsInPlace.md +5 -5
  119. package/dist/guidance/visual/Distinctiveness.md +6 -2
  120. package/dist/guidance/visual/Research.md +14 -2
  121. package/dist/guidance/visual/Theming.md +1 -1
  122. package/dist/types/agent-fleet.d.ts +28 -0
  123. package/dist/types/ai-label.d.ts +7 -0
  124. package/dist/types/app-shell.d.ts +23 -0
  125. package/dist/types/area-chart.d.ts +8 -0
  126. package/dist/types/artifact.d.ts +14 -0
  127. package/dist/types/bar-chart.d.ts +6 -0
  128. package/dist/types/bar-list.d.ts +6 -0
  129. package/dist/types/breadcrumb.d.ts +6 -0
  130. package/dist/types/chart-brush.d.ts +6 -0
  131. package/dist/types/chart.d.ts +29 -1
  132. package/dist/types/checklist.d.ts +6 -0
  133. package/dist/types/code-block.d.ts +6 -0
  134. package/dist/types/collections.d.ts +15 -0
  135. package/dist/types/color-picker.d.ts +6 -0
  136. package/dist/types/command.d.ts +13 -0
  137. package/dist/types/comment-thread.d.ts +11 -0
  138. package/dist/types/confirmation.d.ts +8 -0
  139. package/dist/types/context-menu.d.ts +11 -0
  140. package/dist/types/controls.d.ts +174 -10
  141. package/dist/types/conversation.d.ts +21 -0
  142. package/dist/types/copy-button.d.ts +6 -0
  143. package/dist/types/core.d.ts +31 -0
  144. package/dist/types/data-grid.d.ts +25 -0
  145. package/dist/types/date-picker.d.ts +6 -0
  146. package/dist/types/diff-view.d.ts +8 -0
  147. package/dist/types/dot-plot.d.ts +6 -0
  148. package/dist/types/edit-region.d.ts +23 -0
  149. package/dist/types/empty.d.ts +9 -0
  150. package/dist/types/feature-gate.d.ts +8 -0
  151. package/dist/types/filter-bar.d.ts +8 -0
  152. package/dist/types/formatted-number.d.ts +6 -0
  153. package/dist/types/heatmap.d.ts +6 -0
  154. package/dist/types/inline-citation.d.ts +6 -0
  155. package/dist/types/inline-edit.d.ts +7 -0
  156. package/dist/types/input-otp.d.ts +11 -0
  157. package/dist/types/item-group.d.ts +29 -0
  158. package/dist/types/line-chart.d.ts +6 -0
  159. package/dist/types/link.d.ts +8 -1
  160. package/dist/types/markdown.d.ts +6 -0
  161. package/dist/types/meter.d.ts +6 -0
  162. package/dist/types/nav.d.ts +6 -0
  163. package/dist/types/notifications.d.ts +6 -0
  164. package/dist/types/number-input.d.ts +6 -0
  165. package/dist/types/overlays.d.ts +61 -0
  166. package/dist/types/page-header.d.ts +14 -0
  167. package/dist/types/pagination.d.ts +6 -0
  168. package/dist/types/password-input.d.ts +6 -0
  169. package/dist/types/permission-matrix.d.ts +7 -0
  170. package/dist/types/pile.d.ts +6 -0
  171. package/dist/types/plan-picker.d.ts +6 -0
  172. package/dist/types/prompt-input.d.ts +11 -0
  173. package/dist/types/property-list.d.ts +17 -0
  174. package/dist/types/question.d.ts +11 -0
  175. package/dist/types/relative-time.d.ts +8 -1
  176. package/dist/types/removal-receipt.d.ts +18 -1
  177. package/dist/types/save-bar.d.ts +6 -0
  178. package/dist/types/saved-views.d.ts +12 -0
  179. package/dist/types/scatter-chart.d.ts +8 -0
  180. package/dist/types/schedule.d.ts +21 -0
  181. package/dist/types/secret-field.d.ts +6 -0
  182. package/dist/types/select.d.ts +12 -0
  183. package/dist/types/separator.d.ts +8 -1
  184. package/dist/types/sheet.d.ts +19 -0
  185. package/dist/types/sparkline.d.ts +6 -0
  186. package/dist/types/split-button.d.ts +7 -0
  187. package/dist/types/stat.d.ts +7 -0
  188. package/dist/types/stepper.d.ts +12 -0
  189. package/dist/types/suggestions.d.ts +10 -0
  190. package/dist/types/sync-indicator.d.ts +8 -0
  191. package/dist/types/tag-input.d.ts +8 -0
  192. package/dist/types/terminal.d.ts +6 -0
  193. package/dist/types/thread-list.d.ts +16 -0
  194. package/dist/types/time-input.d.ts +6 -0
  195. package/dist/types/timeline.d.ts +9 -0
  196. package/dist/types/toggle.d.ts +6 -0
  197. package/dist/types/toolbar.d.ts +20 -0
  198. package/dist/types/tour.d.ts +10 -0
  199. package/dist/types/trace.d.ts +16 -0
  200. package/dist/types/tree.d.ts +21 -0
  201. package/dist/types-cjs/agent-fleet.d.cts +28 -0
  202. package/dist/types-cjs/ai-label.d.cts +7 -0
  203. package/dist/types-cjs/app-shell.d.cts +23 -0
  204. package/dist/types-cjs/area-chart.d.cts +8 -0
  205. package/dist/types-cjs/artifact.d.cts +14 -0
  206. package/dist/types-cjs/bar-chart.d.cts +6 -0
  207. package/dist/types-cjs/bar-list.d.cts +6 -0
  208. package/dist/types-cjs/breadcrumb.d.cts +6 -0
  209. package/dist/types-cjs/chart-brush.d.cts +6 -0
  210. package/dist/types-cjs/chart.d.cts +29 -1
  211. package/dist/types-cjs/checklist.d.cts +6 -0
  212. package/dist/types-cjs/code-block.d.cts +6 -0
  213. package/dist/types-cjs/collections.d.cts +15 -0
  214. package/dist/types-cjs/color-picker.d.cts +6 -0
  215. package/dist/types-cjs/command.d.cts +13 -0
  216. package/dist/types-cjs/comment-thread.d.cts +11 -0
  217. package/dist/types-cjs/confirmation.d.cts +8 -0
  218. package/dist/types-cjs/context-menu.d.cts +11 -0
  219. package/dist/types-cjs/controls.d.cts +174 -10
  220. package/dist/types-cjs/conversation.d.cts +21 -0
  221. package/dist/types-cjs/copy-button.d.cts +6 -0
  222. package/dist/types-cjs/core.d.cts +31 -0
  223. package/dist/types-cjs/data-grid.d.cts +25 -0
  224. package/dist/types-cjs/date-picker.d.cts +6 -0
  225. package/dist/types-cjs/diff-view.d.cts +8 -0
  226. package/dist/types-cjs/dot-plot.d.cts +6 -0
  227. package/dist/types-cjs/edit-region.d.cts +23 -0
  228. package/dist/types-cjs/empty.d.cts +9 -0
  229. package/dist/types-cjs/feature-gate.d.cts +8 -0
  230. package/dist/types-cjs/filter-bar.d.cts +8 -0
  231. package/dist/types-cjs/formatted-number.d.cts +6 -0
  232. package/dist/types-cjs/heatmap.d.cts +6 -0
  233. package/dist/types-cjs/inline-citation.d.cts +6 -0
  234. package/dist/types-cjs/inline-edit.d.cts +7 -0
  235. package/dist/types-cjs/input-otp.d.cts +11 -0
  236. package/dist/types-cjs/item-group.d.cts +29 -0
  237. package/dist/types-cjs/line-chart.d.cts +6 -0
  238. package/dist/types-cjs/link.d.cts +8 -1
  239. package/dist/types-cjs/markdown.d.cts +6 -0
  240. package/dist/types-cjs/meter.d.cts +6 -0
  241. package/dist/types-cjs/nav.d.cts +6 -0
  242. package/dist/types-cjs/notifications.d.cts +6 -0
  243. package/dist/types-cjs/number-input.d.cts +6 -0
  244. package/dist/types-cjs/overlays.d.cts +61 -0
  245. package/dist/types-cjs/page-header.d.cts +14 -0
  246. package/dist/types-cjs/pagination.d.cts +6 -0
  247. package/dist/types-cjs/password-input.d.cts +6 -0
  248. package/dist/types-cjs/permission-matrix.d.cts +7 -0
  249. package/dist/types-cjs/pile.d.cts +6 -0
  250. package/dist/types-cjs/plan-picker.d.cts +6 -0
  251. package/dist/types-cjs/prompt-input.d.cts +11 -0
  252. package/dist/types-cjs/property-list.d.cts +17 -0
  253. package/dist/types-cjs/question.d.cts +11 -0
  254. package/dist/types-cjs/relative-time.d.cts +8 -1
  255. package/dist/types-cjs/removal-receipt.d.cts +18 -1
  256. package/dist/types-cjs/save-bar.d.cts +6 -0
  257. package/dist/types-cjs/saved-views.d.cts +12 -0
  258. package/dist/types-cjs/scatter-chart.d.cts +8 -0
  259. package/dist/types-cjs/schedule.d.cts +21 -0
  260. package/dist/types-cjs/secret-field.d.cts +6 -0
  261. package/dist/types-cjs/select.d.cts +12 -0
  262. package/dist/types-cjs/separator.d.cts +8 -1
  263. package/dist/types-cjs/sheet.d.cts +19 -0
  264. package/dist/types-cjs/sparkline.d.cts +6 -0
  265. package/dist/types-cjs/split-button.d.cts +7 -0
  266. package/dist/types-cjs/stat.d.cts +7 -0
  267. package/dist/types-cjs/stepper.d.cts +12 -0
  268. package/dist/types-cjs/suggestions.d.cts +10 -0
  269. package/dist/types-cjs/sync-indicator.d.cts +8 -0
  270. package/dist/types-cjs/tag-input.d.cts +8 -0
  271. package/dist/types-cjs/terminal.d.cts +6 -0
  272. package/dist/types-cjs/thread-list.d.cts +16 -0
  273. package/dist/types-cjs/time-input.d.cts +6 -0
  274. package/dist/types-cjs/timeline.d.cts +9 -0
  275. package/dist/types-cjs/toggle.d.cts +6 -0
  276. package/dist/types-cjs/toolbar.d.cts +20 -0
  277. package/dist/types-cjs/tour.d.cts +10 -0
  278. package/dist/types-cjs/trace.d.cts +16 -0
  279. package/dist/types-cjs/tree.d.cts +21 -0
  280. package/package.json +1 -1
@@ -64,3 +64,53 @@ The set, its policy (what's allowed, the limit, normalizing), and any persistenc
64
64
  ## Demo and verification
65
65
 
66
66
  The `TagInput` section of `build/previews.txt` shows labels (suggestions, a limit of 6, coloured dots), recipients persisted one at a time (a fictional invite service rejects other domains), a disabled set and standalone `Tag`s. `node checks/tag-input.mjs` (from `build/`; `ALT_FIXTURE_ROOT` selects React 19 fixtures) covers adding, suggestions, duplicates, double Backspace, focus after removal, editing, paste splitting, the limit, IME, pending and rejected adds, removal, and 320/960px layouts in both schemes under reduced motion, forced colours and `contrast="more"`.
67
+
68
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
69
+ ## Example
70
+
71
+ `TagInput` as first used in its preview:
72
+
73
+ ```tsx
74
+ import { TagInput } from 'altitude-design';
75
+
76
+ <TagInput value={labels} onValueChange={setLabels} suggestions={TAG_LABELS} max={6} noun={['label', 'labels']}
77
+ placeholder="Add a label" normalize={tag => tag.trim().toLowerCase()} validate={tag => tag.length <= 24 ? undefined : 'Use 24 characters or fewer.'}
78
+ renderTag={tag => <>{TAG_DOTS[tag] && <span className="tags-dot" style={{ '--dot': TAG_DOTS[tag] }} aria-hidden="true" />}{tag}</>} />
79
+ ```
80
+
81
+ The full preview, as rendered in Storybook and checked in CI (`tags-demo`, `tags-dot`, `tags-caption`, `tags-row` are the preview page's own layout classes, not Altitude's):
82
+
83
+ ```tsx
84
+ import * as React from 'react';
85
+ import { Field, Tag, TagInput } from 'altitude-design';
86
+
87
+ const TAG_LABELS = ['bug', 'design', 'docs', 'performance', 'accessibility', 'onboarding', 'billing', 'mobile'];
88
+ const TAG_DOTS = { bug: 'var(--critical)', design: 'var(--accent)', accessibility: 'var(--positive)', performance: 'var(--caution)' };
89
+ const tagWait = ms => new Promise(resolve => setTimeout(resolve, ms));
90
+ export default function App() {
91
+ const [labels, setLabels] = React.useState(['design', 'accessibility']);
92
+ const [recipients, setRecipients] = React.useState(['mara@northwind.example']);
93
+ const [skills, setSkills] = React.useState(['Figma', 'Research', 'Writing']);
94
+ return <div className="tags-demo">
95
+ <Field label="Labels">
96
+ <TagInput value={labels} onValueChange={setLabels} suggestions={TAG_LABELS} max={6} noun={['label', 'labels']}
97
+ placeholder="Add a label" normalize={tag => tag.trim().toLowerCase()} validate={tag => tag.length <= 24 ? undefined : 'Use 24 characters or fewer.'}
98
+ renderTag={tag => <>{TAG_DOTS[tag] && <span className="tags-dot" style={{ '--dot': TAG_DOTS[tag] }} aria-hidden="true" />}{tag}</>} />
99
+ </Field>
100
+ <Field label="Share with">
101
+ <TagInput value={recipients} onValueChange={setRecipients} noun={['person', 'people']} placeholder="name@northwind.example"
102
+ validate={tag => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(tag) ? undefined : `${tag} isn’t an email address.`}
103
+ onAdd={async tag => { await tagWait(500); return tag.endsWith('@northwind.example') ? { ok: true, value: tag.toLowerCase() } : { ok: false, error: `Only people at northwind.example can be invited. ${tag} wasn’t added.` }; }}
104
+ onRemove={async () => { await tagWait(300); return { ok: true }; }} />
105
+ </Field>
106
+ <Field label="Skills">
107
+ <TagInput value={skills} onValueChange={setSkills} noun={['skill', 'skills']} disabled />
108
+ </Field>
109
+ <div>
110
+ <p className="tags-caption">Standalone tags</p>
111
+ <div className="tags-row"><Tag>Figma</Tag><Tag>Research</Tag><Tag onRemove={() => {}}>Writing</Tag></div>
112
+ </div>
113
+ </div>;
114
+ }
115
+ ```
116
+ <!-- /example -->
@@ -25,3 +25,45 @@ A command's output as it runs, with how it ended. Coding agents run `npm test`,
25
25
  - Do keep stderr marked as stderr; it's how a failing line is found.
26
26
  - Do say the exit, even when it's 0.
27
27
  - Don't use it for code the agent is writing (that's `CodeBlock streaming`).
28
+
29
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
30
+ ## Example
31
+
32
+ `Terminal` as first used in its preview:
33
+
34
+ ```tsx
35
+ import { Terminal } from 'altitude-design';
36
+
37
+ <Terminal command="npm test" output={testRun} status="exited" exitCode={1} duration={4200} />
38
+ ```
39
+
40
+ The full preview, as rendered in Storybook and checked in CI (`tm` is the preview page's own layout class, not Altitude's):
41
+
42
+ ```tsx
43
+ import * as React from 'react';
44
+ import { Terminal } from 'altitude-design';
45
+
46
+ const E = String.fromCharCode(27);
47
+ const testRun = [
48
+ { text: '> altitude@0.2.1 test\n> vitest run\n\n' },
49
+ { text: E + '[32m ✓' + E + '[0m src/format.test.ts ' + E + '[2m(12 tests)' + E + '[0m\n' },
50
+ { text: E + '[32m ✓' + E + '[0m src/tokens.test.ts ' + E + '[2m(31 tests)' + E + '[0m\n' },
51
+ { text: E + '[31m ✗' + E + '[0m src/billing.test.ts > refunds an annual plan\n' },
52
+ { text: ' AssertionError: expected 240 to equal 200\n', stream: 'stderr' },
53
+ { text: '\n' + E + '[1m Tests' + E + '[0m ' + E + '[31m1 failed' + E + '[0m | ' + E + '[32m43 passed' + E + '[0m (44)\n' },
54
+ ];
55
+ export default function App() {
56
+ const [n, setN] = React.useState(0);
57
+ const [stopped, setStopped] = React.useState(false);
58
+ React.useEffect(() => { if (stopped || n >= 30) return; const t = setTimeout(() => setN(n + 1), 140); return () => clearTimeout(t); }, [n, stopped]);
59
+ const lines = Array.from({ length: n }, (_, i) => `[migrate] applying 2026_10_${String(i + 1).padStart(2, '0')}_add_index.sql … ok\n`).join('');
60
+ return (
61
+ <div className="tm">
62
+ <Terminal command="npm test" output={testRun} status="exited" exitCode={1} duration={4200} />
63
+ <Terminal command="npm run migrate" output={lines} status={stopped ? 'stopped' : n >= 30 ? 'exited' : 'running'} exitCode={0} duration={n * 140}
64
+ onStop={() => setStopped(true)} stopOnEscape />
65
+ </div>
66
+ );
67
+ }
68
+ ```
69
+ <!-- /example -->
@@ -35,3 +35,76 @@ Conversations with an assistant, beside the thread: new conversation, grouped by
35
35
  - Do say every state in words; the lamp only repeats it.
36
36
  - Do keep deleted threads until the receipt closes.
37
37
  - Don't show a spinner or make a working row hover.
38
+
39
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
40
+ ## Example
41
+
42
+ `ThreadList` as first used in its preview:
43
+
44
+ ```tsx
45
+ import { ThreadList, ThreadListGroup, ThreadListItem, groupByDate } from 'altitude-design';
46
+
47
+ <ThreadList searchable onSearch={setQ}>
48
+ {groupByDate(shown, (t) => t.at, now).map((g) => (
49
+ <ThreadListGroup key={g.label} label={g.label}>
50
+ {g.threads.map((t) => (
51
+ <ThreadListItem key={t.id} href={'#/c/' + t.id} title={t.title} updatedAt={t.at} status={t.status} needs={t.needs} unread={t.unread} current={t.id === at}
52
+ onSelect={(e) => { e.preventDefault(); setAt(t.id); set(t.id, { unread: false }); }}
53
+ onRename={(title) => set(t.id, { title })} onDelete={() => {}} onUndoDelete={() => {}} onDeleted={() => setThreads((ts) => ts.filter((x) => x.id !== t.id))} />
54
+ ))}
55
+ </ThreadListGroup>
56
+ ))}
57
+ </ThreadList>
58
+ ```
59
+
60
+ The full preview, as rendered in Storybook and checked in CI (`tl`, `page` are the preview page's own layout classes, not Altitude's):
61
+
62
+ ```tsx
63
+ import * as React from 'react';
64
+ import { AppShell, Sidebar, SidebarContent, SidebarHeader, ThreadList, ThreadListGroup, ThreadListItem, ThreadListNew, groupByDate } from 'altitude-design';
65
+
66
+ const now = Date.now(), min = 60000, hour = 3600000, day = 86400000;
67
+ // Earlier threads hang off the start of today, not off now, so each stays in its group just after midnight.
68
+ const today = new Date(now).setHours(0, 0, 0, 0);
69
+ const seed = [
70
+ { id: 'a', title: 'Q3 pricing comparison', at: now - 2 * min, status: 'needs-input', needs: 'approval' },
71
+ { id: 'b', title: 'Refactor the billing module', at: Math.max(now - 9 * min, today), status: 'working' },
72
+ { id: 'c', title: 'Summarise incident #4821', at: Math.max(now - 40 * min, today), unread: true },
73
+ { id: 'd', title: 'Draft the release note', at: today - 9 * hour },
74
+ { id: 'e', title: 'Migrate the users table', at: today - 11 * hour, status: 'failed' },
75
+ { id: 'f', title: 'Onboarding email ideas', at: today - 3 * day - 12 * hour },
76
+ { id: 'g', title: 'Competitor research', at: today - 11 * day - 12 * hour, status: 'stopped' },
77
+ ];
78
+ export default function App() {
79
+ const [threads, setThreads] = React.useState(seed);
80
+ const [at, setAt] = React.useState('b');
81
+ const [q, setQ] = React.useState('');
82
+ const shown = threads.filter((t) => t.title.toLowerCase().includes(q.toLowerCase()));
83
+ const set = (id, patch) => setThreads((ts) => ts.map((t) => (t.id === id ? { ...t, ...patch } : t)));
84
+ return (
85
+ <div className="tl">
86
+ <AppShell sidebar={
87
+ <Sidebar aria-label="Conversations">
88
+ <SidebarHeader><ThreadListNew onClick={() => { const id = String(Date.now()); setThreads((ts) => [{ id, title: 'New conversation', at: Date.now() }, ...ts]); setAt(id); }} /></SidebarHeader>
89
+ <SidebarContent>
90
+ <ThreadList searchable onSearch={setQ}>
91
+ {groupByDate(shown, (t) => t.at, now).map((g) => (
92
+ <ThreadListGroup key={g.label} label={g.label}>
93
+ {g.threads.map((t) => (
94
+ <ThreadListItem key={t.id} href={'#/c/' + t.id} title={t.title} updatedAt={t.at} status={t.status} needs={t.needs} unread={t.unread} current={t.id === at}
95
+ onSelect={(e) => { e.preventDefault(); setAt(t.id); set(t.id, { unread: false }); }}
96
+ onRename={(title) => set(t.id, { title })} onDelete={() => {}} onUndoDelete={() => {}} onDeleted={() => setThreads((ts) => ts.filter((x) => x.id !== t.id))} />
97
+ ))}
98
+ </ThreadListGroup>
99
+ ))}
100
+ </ThreadList>
101
+ </SidebarContent>
102
+ </Sidebar>
103
+ }>
104
+ <div className="page">The conversation “{threads.find((t) => t.id === at)?.title}” is open here.</div>
105
+ </AppShell>
106
+ </div>
107
+ );
108
+ }
109
+ ```
110
+ <!-- /example -->
@@ -24,3 +24,40 @@ A time of day: when a scheduled report is sent, quiet hours, business hours, a m
24
24
  - Do set `step` to the granularity you actually schedule at (15 minutes, not 1).
25
25
  - Don't use `<input type="time">`; it looks different in every browser and ignores the scheme.
26
26
  - Don't offer a long Select of times when people know the time they want.
27
+
28
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
29
+ ## Example
30
+
31
+ `TimeInput` as first used in its preview:
32
+
33
+ ```tsx
34
+ import { TimeInput } from 'altitude-design';
35
+
36
+ <TimeInput value={report} onValueChange={setReport} step={15} hourCycle="h12" locale="en-US" timeZone="Europe/Berlin" />
37
+ ```
38
+
39
+ The full preview, as rendered in Storybook and checked in CI (`col`, `ti`, `cap` are the preview page's own layout classes, not Altitude's):
40
+
41
+ ```tsx
42
+ import * as React from 'react';
43
+ import { Field, TimeInput } from 'altitude-design';
44
+
45
+ export default function App() {
46
+ const [report, setReport] = React.useState('09:30');
47
+ const [quiet, setQuiet] = React.useState(null);
48
+ const [open, setOpen] = React.useState('08:00');
49
+ return (
50
+ <div className="col">
51
+ <div className="ti">
52
+ <Field label="Send the report at" hint={report ? `Stored as ${report}` : 'Not set'}><TimeInput value={report} onValueChange={setReport} step={15} hourCycle="h12" locale="en-US" timeZone="Europe/Berlin" /></Field>
53
+ <Field label="Quiet hours start" hint="24-hour clock"><TimeInput value={quiet} onValueChange={setQuiet} hourCycle="h23" /></Field>
54
+ <Field label="Opens at" hint="Between 06:00 and 12:00" error={open && (open < '06:00' || open > '12:00') ? 'Choose a time between 06:00 and 12:00.' : undefined}>
55
+ <TimeInput value={open} onValueChange={setOpen} min="06:00" max="12:00" hourCycle="h23" />
56
+ </Field>
57
+ </div>
58
+ <p className="cap">Type digits (they move on by themselves), or use Up and Down; minutes step by 15 in the first field. "a" or "p" sets AM or PM. The field fills only once the whole time is there.</p>
59
+ </div>
60
+ );
61
+ }
62
+ ```
63
+ <!-- /example -->
@@ -30,3 +30,58 @@ With `groupBy="day"` (the default), each day starts with a heading ("Today", "Ye
30
30
  - Do keep keys stable, so only new events glow.
31
31
  - Don't raise past events into cards.
32
32
  - Don't use it for steps still to come; that's a `Stepper`.
33
+
34
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
35
+ ## Example
36
+
37
+ `Timeline` as first used in its preview:
38
+
39
+ ```tsx
40
+ import { Timeline, TimelineItem } from 'altitude-design';
41
+
42
+ <Timeline aria-label="Activity">
43
+ {events.map((e) => <TimelineItem key={e.id} time={e.at} icon={<I d={icons[e.icon]} />} status={e.status} href={e.href} detail={e.detail}
44
+ onRetry={() => setEvents((xs) => xs.map((x) => (x.id === e.id ? { ...x, status: 'committed' } : x)))}>{e.text}</TimelineItem>)}
45
+ </Timeline>
46
+ ```
47
+
48
+ The full preview, as rendered in Storybook and checked in CI (`tl`, `col`, `row`, `cap` are the preview page's own layout classes, not Altitude's):
49
+
50
+ ```tsx
51
+ import * as React from 'react';
52
+ import { Badge, Button, Input, Timeline, TimelineItem } from 'altitude-design';
53
+
54
+ // Anchored to the calendar day, so "Today" and "Yesterday" hold at any hour (just after midnight too).
55
+ const ago = (m) => { const start = new Date(); start.setHours(0, 0, 0, 0); return new Date(Math.max(Date.now() - m * 60000, start.getTime() + 1000)); };
56
+ const yesterdayAt = (h) => { const d = new Date(); d.setDate(d.getDate() - 1); d.setHours(h, 0, 0, 0); return d; };
57
+ const I = ({ d }) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d={d} /></svg>;
58
+ const icons = { status: 'M5 12.5l4.5 4.5L19 7.5', comment: 'M4 5h16v11H8l-4 4z', assign: 'M16 19v-1a4 4 0 0 0-8 0v1M12 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6' };
59
+ export default function App() {
60
+ const [events, setEvents] = React.useState([
61
+ { id: 'e3', at: ago(14), icon: 'status', text: <><strong>Maya</strong> changed status to <Badge tone="positive">Done</Badge></> },
62
+ { id: 'e2', at: ago(95), icon: 'assign', text: <><strong>Theo</strong> assigned this to <strong>Maya</strong></>, href: '#/people/maya' },
63
+ { id: 'e1', at: yesterdayAt(12), icon: 'comment', text: <><strong>Ada</strong> commented</>, detail: <p style={{ margin: 0 }}>“Can we ship this before the release freeze on Friday?”</p> },
64
+ ]);
65
+ const [text, setText] = React.useState('');
66
+ const send = (fail) => {
67
+ const id = 'n' + Date.now();
68
+ setEvents((xs) => [{ id, at: new Date(), icon: 'comment', status: 'pending', text: <><strong>You</strong> commented “{text || 'Looks good'}”</> }, ...xs]);
69
+ setText('');
70
+ setTimeout(() => setEvents((xs) => xs.map((x) => (x.id === id ? { ...x, status: fail ? 'failed' : 'committed' } : x))), 1200);
71
+ };
72
+ return (
73
+ <div className="tl">
74
+ <Timeline aria-label="Activity">
75
+ {events.map((e) => <TimelineItem key={e.id} time={e.at} icon={<I d={icons[e.icon]} />} status={e.status} href={e.href} detail={e.detail}
76
+ onRetry={() => setEvents((xs) => xs.map((x) => (x.id === e.id ? { ...x, status: 'committed' } : x)))}>{e.text}</TimelineItem>)}
77
+ </Timeline>
78
+ <div className="col">
79
+ <Input value={text} onChange={(ev) => setText(ev.target.value)} placeholder="Add a comment" aria-label="Comment" />
80
+ <div className="row"><Button variant="primary" onClick={() => send(false)}>Comment</Button><Button onClick={() => send(true)}>Comment (fails)</Button></div>
81
+ <p className="cap">Your comment hovers until it lands, then settles into the record; one that fails drops to a trench with Retry.</p>
82
+ </div>
83
+ </div>
84
+ );
85
+ }
86
+ ```
87
+ <!-- /example -->
@@ -14,3 +14,41 @@ Call `toast()` from anywhere; render `Toaster` once inside `AltitudeProvider`. A
14
14
  While a modal owns the document, toasts retain their visual position above the scrim, but their controls are inert and expiry timers pause with their remaining lifetime intact. Notification text is routed to a noninteractive live region inside the active modal, and the external live region is suppressed to avoid duplicate announcements. Timers and controls resume after final release. Essential modal errors belong inside that modal.
15
15
 
16
16
  When an item leaves a list, its result is shown first in the item's own slot ([RemovalReceipt](../RemovalReceipt/README.md)); once that slot has closed, a toast carries Undo, as in the [Actions in place recipe](../../visual/ActionsInPlace.md). A timed toast may supplement recovery, but must never be its only route: keep a durable Archived/Restore path after a brief Undo opportunity expires. Withdraw a toast's Undo (`toast.dismiss(id)`) as soon as a newer revision makes it invalid.
17
+
18
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
19
+ ## Example
20
+
21
+ `Toaster` as first used in its preview:
22
+
23
+ ```tsx
24
+ import { Toaster } from 'altitude-design';
25
+
26
+ <Toaster />
27
+ ```
28
+
29
+ The full preview, as rendered in Storybook and checked in CI (`col`, `row`, `cap` are the preview page's own layout classes, not Altitude's):
30
+
31
+ ```tsx
32
+ import * as React from 'react';
33
+ import { Button, Toaster, toast } from 'altitude-design';
34
+
35
+ const msgs = [
36
+ { title: 'Deployment queued', description: 'northwind-web · main@8dc01b2' },
37
+ { title: 'Domain verified', description: 'acme.dev now points here.', tone: 'positive' },
38
+ { title: 'Build failed', description: 'Missing DATABASE_URL.', tone: 'critical', action: { label: 'Retry', onClick: () => {} } },
39
+ ];
40
+ export default function App() {
41
+ React.useEffect(() => { msgs.forEach((m, i) => setTimeout(() => toast({ ...m, duration: 60000 }), 300 + i * 450)); }, []);
42
+ return (
43
+ <div className="col">
44
+ <div className="row">
45
+ <Button onClick={() => toast({ title: 'Changes saved', tone: 'positive' })}>Toast</Button>
46
+ <Button variant="ghost" onClick={() => toast({ title: 'Running low on storage', description: '92% used', tone: 'caution' })}>Warning</Button>
47
+ </div>
48
+ <p className="cap" style={{ maxWidth: 300 }}>Hover or tap the stack to fan it out; timers pause while you read; swipe a toast away.</p>
49
+ <Toaster />
50
+ </div>
51
+ );
52
+ }
53
+ ```
54
+ <!-- /example -->
@@ -31,3 +31,55 @@ Either way the group is **one tab stop**, and returning to it lands on the item
31
31
  - Do use `type="single"` for mutually exclusive views; use `Tabs` when each option has its own panel.
32
32
  - Don't change a toggle's label when it turns on.
33
33
  - Don't use a Toggle for an action that happens once; that's a `Button`.
34
+
35
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
36
+ ## Example
37
+
38
+ `Toggle` as first used in its preview:
39
+
40
+ ```tsx
41
+ import { Toggle } from 'altitude-design';
42
+
43
+ <Toggle variant="secondary" pressed={archived} onPressedChange={setArchived}>Show archived</Toggle>
44
+ ```
45
+
46
+ The full preview, as rendered in Storybook and checked in CI (`tg`, `bar`, `cap` are the preview page's own layout classes, not Altitude's):
47
+
48
+ ```tsx
49
+ import * as React from 'react';
50
+ import { Toggle, ToggleGroup, ToggleGroupItem } from 'altitude-design';
51
+
52
+ const Thumb = ({ down }) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" style={down ? { transform: 'scaleY(-1)' } : undefined}><path d="M7 10v11H4V10zM7 10l4-7a2 2 0 0 1 3 2l-1 5h6a2 2 0 0 1 2 2.3l-1.5 7A2 2 0 0 1 17.5 21H7" /></svg>;
53
+ export default function App() {
54
+ const [view, setView] = React.useState('board');
55
+ const [marks, setMarks] = React.useState(['bold']);
56
+ const [archived, setArchived] = React.useState(false);
57
+ const [vote, setVote] = React.useState('');
58
+ return (
59
+ <div className="tg">
60
+ <div className="bar">
61
+ <ToggleGroup type="multiple" value={marks} onValueChange={setMarks} aria-label="Text style">
62
+ <ToggleGroupItem value="bold" aria-label="Bold" square><b>B</b></ToggleGroupItem>
63
+ <ToggleGroupItem value="italic" aria-label="Italic" square><i>I</i></ToggleGroupItem>
64
+ <ToggleGroupItem value="underline" aria-label="Underline" square><u>U</u></ToggleGroupItem>
65
+ </ToggleGroup>
66
+ <ToggleGroup type="single" value={view} onValueChange={setView} aria-label="View">
67
+ <ToggleGroupItem value="list">List</ToggleGroupItem>
68
+ <ToggleGroupItem value="board">Board</ToggleGroupItem>
69
+ <ToggleGroupItem value="calendar">Calendar</ToggleGroupItem>
70
+ </ToggleGroup>
71
+ <Toggle variant="secondary" pressed={archived} onPressedChange={setArchived}>Show archived</Toggle>
72
+ </div>
73
+ <div className="bar">
74
+ <span className="cap">Was this answer helpful?</span>
75
+ <ToggleGroup type="single" value={vote} onValueChange={setVote} aria-label="Rate this answer">
76
+ <ToggleGroupItem value="up" aria-label="Helpful"><Thumb /></ToggleGroupItem>
77
+ <ToggleGroupItem value="down" aria-label="Not helpful"><Thumb down /></ToggleGroupItem>
78
+ </ToggleGroup>
79
+ </div>
80
+ <p className="cap">On is a choice, built like the Switch: the face sinks into a well with the accent poured in. Pointing at an on toggle previews off. One choice (View) is segmented Tabs without panels. Each group is one tab stop; arrows move inside it.</p>
81
+ </div>
82
+ );
83
+ }
84
+ ```
85
+ <!-- /example -->
@@ -35,3 +35,72 @@ A row of small actions with one tab stop: a formatting bar, a table's tools, a c
35
35
  - Do use a Toolbar for a set of small, related tools; a page's main actions are separate `Button`s.
36
36
  - Don't put text fields inside a Toolbar: arrow keys would stop moving the caret.
37
37
  - Don't give tools a raised (`secondary` or `primary`) variant; in a toolbar they're ghosts.
38
+
39
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
40
+ ## Example
41
+
42
+ `Toolbar` as first used in its preview:
43
+
44
+ ```tsx
45
+ import { ToggleGroup, ToggleGroupItem, Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator, ToolbarToggle } from 'altitude-design';
46
+
47
+ <Toolbar aria-label="Formatting" overflow="menu" bordered className={className}>
48
+ <ToggleGroup type="multiple" value={marks} onValueChange={setMarks} aria-label="Text style">
49
+ <ToggleGroupItem value="bold" aria-label="Bold" square><b>B</b></ToggleGroupItem>
50
+ <ToggleGroupItem value="italic" aria-label="Italic" square><i>I</i></ToggleGroupItem>
51
+ <ToggleGroupItem value="underline" aria-label="Underline" square><u>U</u></ToggleGroupItem>
52
+ </ToggleGroup>
53
+ <ToolbarSeparator />
54
+ <ToolbarGroup aria-label="Blocks">
55
+ <ToolbarButton aria-label="Bulleted list" square><I d={list} /></ToolbarButton>
56
+ <ToolbarToggle aria-label="Quote" square pressed={quoted} onPressedChange={setQuoted}><I d={quote} /></ToolbarToggle>
57
+ <ToolbarButton aria-label="Code" square><I d={code} /></ToolbarButton>
58
+ </ToolbarGroup>
59
+ <ToolbarSeparator />
60
+ <ToolbarButton aria-label="Insert link" square><I d={link} /></ToolbarButton>
61
+ </Toolbar>
62
+ ```
63
+
64
+ The full preview, as rendered in Storybook and checked in CI (`tb`, `narrow`, `cap` are the preview page's own layout classes, not Altitude's):
65
+
66
+ ```tsx
67
+ import * as React from 'react';
68
+ import { ToggleGroup, ToggleGroupItem, Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator, ToolbarToggle } from 'altitude-design';
69
+
70
+ const I = ({ d }) => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d={d} /></svg>;
71
+ const link = 'M10 14a4 4 0 0 0 6 0l3-3a4 4 0 0 0-6-6l-1 1M14 10a4 4 0 0 0-6 0l-3 3a4 4 0 0 0 6 6l1-1';
72
+ const list = 'M9 6h11M9 12h11M9 18h11M4 6h.01M4 12h.01M4 18h.01';
73
+ const quote = 'M7 7h4v6H5V9zM15 7h4v6h-6V9zM9 13l-2 4M17 13l-2 4';
74
+ const code = 'M8 8l-4 4 4 4M16 8l4 4-4 4';
75
+ function Bar({ className }) {
76
+ const [marks, setMarks] = React.useState(['bold']);
77
+ const [quoted, setQuoted] = React.useState(false);
78
+ return (
79
+ <Toolbar aria-label="Formatting" overflow="menu" bordered className={className}>
80
+ <ToggleGroup type="multiple" value={marks} onValueChange={setMarks} aria-label="Text style">
81
+ <ToggleGroupItem value="bold" aria-label="Bold" square><b>B</b></ToggleGroupItem>
82
+ <ToggleGroupItem value="italic" aria-label="Italic" square><i>I</i></ToggleGroupItem>
83
+ <ToggleGroupItem value="underline" aria-label="Underline" square><u>U</u></ToggleGroupItem>
84
+ </ToggleGroup>
85
+ <ToolbarSeparator />
86
+ <ToolbarGroup aria-label="Blocks">
87
+ <ToolbarButton aria-label="Bulleted list" square><I d={list} /></ToolbarButton>
88
+ <ToolbarToggle aria-label="Quote" square pressed={quoted} onPressedChange={setQuoted}><I d={quote} /></ToolbarToggle>
89
+ <ToolbarButton aria-label="Code" square><I d={code} /></ToolbarButton>
90
+ </ToolbarGroup>
91
+ <ToolbarSeparator />
92
+ <ToolbarButton aria-label="Insert link" square><I d={link} /></ToolbarButton>
93
+ </Toolbar>
94
+ );
95
+ }
96
+ export default function App() {
97
+ return (
98
+ <div className="tb">
99
+ <Bar />
100
+ <Bar className="narrow" />
101
+ <p className="cap">One tab stop for the whole bar; arrows move between tools. The narrow bar moves what doesn't fit into "More tools", where Quote stays a checkable item.</p>
102
+ </div>
103
+ );
104
+ }
105
+ ```
106
+ <!-- /example -->
@@ -10,3 +10,32 @@ It opens after `delay` (450ms) on hover or immediately on keyboard focus, rising
10
10
 
11
11
  - Do use `side="right"` for a rail of icons (a collapsed `Sidebar`), where a tooltip above would cover the next icon.
12
12
  - Don't put anything interactive in a tooltip, and don't hide essential information in one.
13
+
14
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
15
+ ## Example
16
+
17
+ `Tooltip` as first used in its preview:
18
+
19
+ ```tsx
20
+ import { Button, Tooltip } from 'altitude-design';
21
+
22
+ <Tooltip content="Bold ⌘B" defaultOpen><Button square variant="ghost" aria-label="Bold"><b>B</b></Button></Tooltip>
23
+ ```
24
+
25
+ The full preview, as rendered in Storybook and checked in CI (`row`, `cap` are the preview page's own layout classes, not Altitude's):
26
+
27
+ ```tsx
28
+ import { Button, Tooltip } from 'altitude-design';
29
+
30
+ export default function App() {
31
+ return (
32
+ <div className="row">
33
+ <Tooltip content="Bold ⌘B" defaultOpen><Button square variant="ghost" aria-label="Bold"><b>B</b></Button></Tooltip>
34
+ <Tooltip content="Italic ⌘I"><Button square variant="ghost" aria-label="Italic"><i style={{ fontFamily: 'serif', fontSize: 17 }}>I</i></Button></Tooltip>
35
+ <Tooltip content="Underline ⌘U"><Button square variant="ghost" aria-label="Underline"><u>U</u></Button></Tooltip>
36
+ <span className="cap" style={{ marginLeft: 12 }}>Hover one, then slide to the next: no second delay.</span>
37
+ </div>
38
+ );
39
+ }
40
+ ```
41
+ <!-- /example -->
@@ -27,3 +27,47 @@ A few steps pointing at parts of the interface, for onboarding or a feature laun
27
27
  - Do remember when it's been finished or skipped.
28
28
  - Don't dim the page or block the target.
29
29
  - Don't use a tour to explain an interface that should explain itself.
30
+
31
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
32
+ ## Example
33
+
34
+ `Tour` as first used in its preview:
35
+
36
+ ```tsx
37
+ import { Tour } from 'altitude-design';
38
+
39
+ <Tour open={open} onOpenChange={setOpen} onFinish={(how) => setSaid(how === 'done' ? 'Tour finished.' : 'Tour skipped.')} steps={[
40
+ { target: '#tour-projects', title: 'Projects moved here', body: 'All your projects now live in one place.' },
41
+ { target: '[data-tour="owner"]', title: 'Filter by owner', body: 'Type a name to see only their projects.' },
42
+ { target: '[data-tour="new"]', title: 'Start something new', body: 'Projects can start from a template.' },
43
+ ]} />
44
+ ```
45
+
46
+ The full preview, as rendered in Storybook and checked in CI (`tr`, `bar`, `row`, `cap` are the preview page's own layout classes, not Altitude's):
47
+
48
+ ```tsx
49
+ import * as React from 'react';
50
+ import { Button, Input, Tour } from 'altitude-design';
51
+
52
+ export default function App() {
53
+ const [open, setOpen] = React.useState(false);
54
+ const [said, setSaid] = React.useState('');
55
+ return (
56
+ <div className="tr">
57
+ <div className="bar">
58
+ <Button variant="ghost" id="tour-projects">Projects</Button>
59
+ <Input size="sm" placeholder="Filter by owner" aria-label="Filter by owner" data-tour="owner" style={{ maxWidth: 220 }} />
60
+ <span style={{ marginLeft: 'auto' }}><Button variant="primary" data-tour="new">New project</Button></span>
61
+ </div>
62
+ <div className="row"><Button onClick={() => setOpen(true)}>Take the tour</Button></div>
63
+ <p className="cap">{said || 'The tour points at one thing at a time with a ring. The page isn\'t dimmed and stays usable: try typing in the filter while it\'s on that step.'}</p>
64
+ <Tour open={open} onOpenChange={setOpen} onFinish={(how) => setSaid(how === 'done' ? 'Tour finished.' : 'Tour skipped.')} steps={[
65
+ { target: '#tour-projects', title: 'Projects moved here', body: 'All your projects now live in one place.' },
66
+ { target: '[data-tour="owner"]', title: 'Filter by owner', body: 'Type a name to see only their projects.' },
67
+ { target: '[data-tour="new"]', title: 'Start something new', body: 'Projects can start from a template.' },
68
+ ]} />
69
+ </div>
70
+ );
71
+ }
72
+ ```
73
+ <!-- /example -->
@@ -35,3 +35,95 @@ The steps an agent takes (searching, calling tools, reasoning, waiting for appro
35
35
  - Do put an approval request in the step that's waiting.
36
36
  - Don't draw spinners or nested cards.
37
37
  - Don't invent planned steps the agent hasn't planned.
38
+
39
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
40
+ ## Example
41
+
42
+ `Trace` as first used in its preview:
43
+
44
+ ```tsx
45
+ import { Confirmation, Trace, TraceReasoning, TraceStep, TraceToolCall } from 'altitude-design';
46
+
47
+ <Trace aria-label="Agent run: answer refund question">
48
+ {plan.map((s, i) => (
49
+ <TraceStep key={s.id} title={s.title} status={status(i)} duration={i < at ? s.ms : undefined}
50
+ error={failed && i === at ? 'The billing service timed out.' : undefined} onRetry={failed && i === at ? () => { setRetried(true); setFailed(false); } : undefined}>
51
+ {s.tool && <TraceToolCall name={s.tool.name} input={s.tool.input} output={i < at ? s.tool.output ?? { plan: 'annual', startedDaysAgo: 20 } : undefined} />}
52
+ {s.reasoning && i < at && <TraceReasoning duration={s.ms}>{s.reasoning}</TraceReasoning>}
53
+ {s.approval && <Confirmation state={approval} title="Send reply to Jamie Lee" consequence="Jamie will get an email confirming a full refund of €240." approveLabel="Send reply" rejectLabel="Don't send" runningLabel="Sending…" doneLabel="Sent"
54
+ onApprove={() => { setApproval('running'); setTimeout(() => setApproval('done'), 1000); }} onReject={() => setApproval('rejected')} />}
55
+ </TraceStep>
56
+ ))}
57
+ </Trace>
58
+ ```
59
+
60
+ The full preview, as rendered in Storybook and checked in CI (`col`, `tc` are the preview page's own layout classes, not Altitude's):
61
+
62
+ ```tsx
63
+ import * as React from 'react';
64
+ import { Confirmation, Trace, TraceParallel, TraceReasoning, TraceStep, TraceToolCall } from 'altitude-design';
65
+
66
+ const plan = [
67
+ { id: 's1', title: 'Search the help centre', ms: 820, tool: { name: 'search_documents', input: { query: 'refund policy annual plans', limit: 5 }, output: { results: 3 } } },
68
+ { id: 's2', title: 'Read 3 articles', ms: 1400 },
69
+ { id: 's3', title: 'Check the customer’s plan', ms: 600, fails: true, tool: { name: 'get_subscription', input: { customer: 'cus_EXAMPLE42' } } },
70
+ { id: 's4', title: 'Draft a reply', ms: 2100, reasoning: 'The customer is 20 days into an annual plan, so the 30-day full refund applies. No proration needed.' },
71
+ { id: 's5', title: 'Send the reply', approval: true },
72
+ ];
73
+ export default function App() {
74
+ const [at, setAt] = React.useState(0);
75
+ const [failed, setFailed] = React.useState(false);
76
+ const [retried, setRetried] = React.useState(false);
77
+ const [approval, setApproval] = React.useState('requested');
78
+ React.useEffect(() => {
79
+ if (failed || at >= plan.length - 1) return;
80
+ const step = plan[at];
81
+ const t = setTimeout(() => { if (step.fails && !retried) setFailed(true); else setAt(at + 1); }, step.ms);
82
+ return () => clearTimeout(t);
83
+ }, [at, failed, retried]);
84
+ const status = (i) => (i < at ? 'done' : i > at ? 'planned' : failed ? 'failed' : plan[i].approval ? (approval === 'done' ? 'done' : 'awaiting-approval') : 'running');
85
+ return (
86
+ <div className="col tc">
87
+ <Trace aria-label="Agent run: answer refund question">
88
+ {plan.map((s, i) => (
89
+ <TraceStep key={s.id} title={s.title} status={status(i)} duration={i < at ? s.ms : undefined}
90
+ error={failed && i === at ? 'The billing service timed out.' : undefined} onRetry={failed && i === at ? () => { setRetried(true); setFailed(false); } : undefined}>
91
+ {s.tool && <TraceToolCall name={s.tool.name} input={s.tool.input} output={i < at ? s.tool.output ?? { plan: 'annual', startedDaysAgo: 20 } : undefined} />}
92
+ {s.reasoning && i < at && <TraceReasoning duration={s.ms}>{s.reasoning}</TraceReasoning>}
93
+ {s.approval && <Confirmation state={approval} title="Send reply to Jamie Lee" consequence="Jamie will get an email confirming a full refund of €240." approveLabel="Send reply" rejectLabel="Don't send" runningLabel="Sending…" doneLabel="Sent"
94
+ onApprove={() => { setApproval('running'); setTimeout(() => setApproval('done'), 1000); }} onReject={() => setApproval('rejected')} />}
95
+ </TraceStep>
96
+ ))}
97
+ </Trace>
98
+ <Trace aria-label="Agent run: compare billing providers">
99
+ <TraceStep title="Plan the comparison" status="done" duration={900} />
100
+ <TraceStep title="Research pricing pages" status="auto">
101
+ <TraceParallel label="Subagents">
102
+ <TraceStep title="Stripe" status="auto">
103
+ <Trace aria-label="Stripe subagent">
104
+ <TraceStep title="Open the pricing page" status="done" duration={1200} />
105
+ <TraceStep title="Extract the fees" status="done" duration={3400} />
106
+ </Trace>
107
+ </TraceStep>
108
+ <TraceStep title="Paddle" status="auto">
109
+ <Trace aria-label="Paddle subagent">
110
+ <TraceStep title="Open the pricing page" status="done" duration={1500} />
111
+ <TraceStep title="Extract the fees" status="running" />
112
+ </Trace>
113
+ </TraceStep>
114
+ <TraceStep title="Lemon Squeezy" status="failed" error="The pricing page returned 403." onRetry={() => {}} />
115
+ </TraceParallel>
116
+ </TraceStep>
117
+ <TraceStep title="Weigh the fees" status="running">
118
+ <TraceReasoning status="streaming">{'Stripe charges 2.9% + 30¢ per card payment. Paddle is a merchant of record, so its 5% + 50¢ includes sales tax handling, which'}</TraceReasoning>
119
+ </TraceStep>
120
+ <TraceStep title="Check the provider's notes" status="done" duration={2400}>
121
+ <TraceReasoning status="redacted" />
122
+ </TraceStep>
123
+ <TraceStep title="Write the comparison" status="planned" />
124
+ </Trace>
125
+ </div>
126
+ );
127
+ }
128
+ ```
129
+ <!-- /example -->