altitude-design 0.3.2 → 0.4.1

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 (294) hide show
  1. package/README.md +2 -0
  2. package/dist/cli/altitude.mjs +120 -20
  3. package/dist/guidance/README.md +4 -0
  4. package/dist/guidance/agent-setup.md +3 -2
  5. package/dist/guidance/components/AILabel/README.md +60 -0
  6. package/dist/guidance/components/Accordion/README.md +32 -0
  7. package/dist/guidance/components/AgentFleet/README.md +81 -0
  8. package/dist/guidance/components/AgentLanes/README.md +53 -0
  9. package/dist/guidance/components/AgentRequests/README.md +76 -0
  10. package/dist/guidance/components/Alert/README.md +71 -0
  11. package/dist/guidance/components/AltitudeProvider/README.md +111 -0
  12. package/dist/guidance/components/AppShell/README.md +121 -0
  13. package/dist/guidance/components/AreaChart/README.md +101 -0
  14. package/dist/guidance/components/Artifact/README.md +99 -0
  15. package/dist/guidance/components/Avatar/README.md +75 -0
  16. package/dist/guidance/components/Await/README.md +128 -0
  17. package/dist/guidance/components/Badge/README.md +66 -0
  18. package/dist/guidance/components/BarChart/README.md +109 -0
  19. package/dist/guidance/components/BarList/README.md +87 -0
  20. package/dist/guidance/components/Board/README.md +98 -0
  21. package/dist/guidance/components/Breadcrumb/README.md +66 -0
  22. package/dist/guidance/components/Button/README.md +58 -0
  23. package/dist/guidance/components/Card/README.md +52 -0
  24. package/dist/guidance/components/ChartBrush/README.md +98 -0
  25. package/dist/guidance/components/ChartContainer/README.md +229 -0
  26. package/dist/guidance/components/ChartLegend/README.md +78 -0
  27. package/dist/guidance/components/ChartReference/README.md +115 -0
  28. package/dist/guidance/components/ChartTooltip/README.md +101 -0
  29. package/dist/guidance/components/Checkbox/README.md +46 -0
  30. package/dist/guidance/components/Checklist/README.md +137 -0
  31. package/dist/guidance/components/CodeBlock/README.md +72 -0
  32. package/dist/guidance/components/ColorPicker/README.md +69 -0
  33. package/dist/guidance/components/Combobox/README.md +51 -0
  34. package/dist/guidance/components/CommandPalette/README.md +204 -0
  35. package/dist/guidance/components/CommentThread/README.md +81 -0
  36. package/dist/guidance/components/Confirmation/README.md +94 -0
  37. package/dist/guidance/components/ContextMenu/README.md +81 -0
  38. package/dist/guidance/components/Conversation/README.md +169 -0
  39. package/dist/guidance/components/CopyButton/README.md +54 -0
  40. package/dist/guidance/components/DataGrid/README.md +157 -0
  41. package/dist/guidance/components/DatePicker/README.md +116 -0
  42. package/dist/guidance/components/Dialog/README.md +204 -0
  43. package/dist/guidance/components/DiffView/README.md +107 -0
  44. package/dist/guidance/components/DotPlot/README.md +82 -0
  45. package/dist/guidance/components/Drilldown/README.md +43 -0
  46. package/dist/guidance/components/DropZone/README.md +71 -0
  47. package/dist/guidance/components/DropdownMenu/README.md +63 -0
  48. package/dist/guidance/components/EditRegion/README.md +263 -0
  49. package/dist/guidance/components/EmptyState/README.md +66 -0
  50. package/dist/guidance/components/FeatureGate/README.md +67 -0
  51. package/dist/guidance/components/Field/README.md +46 -0
  52. package/dist/guidance/components/FilterBar/README.md +132 -0
  53. package/dist/guidance/components/FormattedNumber/README.md +81 -0
  54. package/dist/guidance/components/Heatmap/README.md +116 -0
  55. package/dist/guidance/components/HoldButton/README.md +48 -0
  56. package/dist/guidance/components/HoverCard/README.md +71 -0
  57. package/dist/guidance/components/InlineCitation/README.md +56 -0
  58. package/dist/guidance/components/InlineEdit/README.md +379 -0
  59. package/dist/guidance/components/Input/README.md +63 -0
  60. package/dist/guidance/components/InputOTP/README.md +76 -0
  61. package/dist/guidance/components/ItemGroup/README.md +193 -0
  62. package/dist/guidance/components/Kbd/README.md +36 -0
  63. package/dist/guidance/components/LineChart/README.md +109 -0
  64. package/dist/guidance/components/Link/README.md +69 -0
  65. package/dist/guidance/components/Markdown/README.md +113 -0
  66. package/dist/guidance/components/Meter/README.md +81 -0
  67. package/dist/guidance/components/NotificationCenter/README.md +67 -0
  68. package/dist/guidance/components/NumberInput/README.md +66 -0
  69. package/dist/guidance/components/PageHeader/README.md +74 -0
  70. package/dist/guidance/components/Pagination/README.md +58 -0
  71. package/dist/guidance/components/PasswordInput/README.md +70 -0
  72. package/dist/guidance/components/PermissionMatrix/README.md +68 -0
  73. package/dist/guidance/components/Pile/README.md +54 -0
  74. package/dist/guidance/components/PlanPicker/README.md +62 -0
  75. package/dist/guidance/components/Popover/README.md +48 -0
  76. package/dist/guidance/components/Progress/README.md +41 -0
  77. package/dist/guidance/components/PromptInput/README.md +138 -0
  78. package/dist/guidance/components/PropertyList/README.md +137 -0
  79. package/dist/guidance/components/Question/README.md +81 -0
  80. package/dist/guidance/components/RadioGroup/README.md +47 -0
  81. package/dist/guidance/components/RelativeTime/README.md +73 -0
  82. package/dist/guidance/components/RemovalReceipt/README.md +111 -0
  83. package/dist/guidance/components/Resizable/README.md +65 -0
  84. package/dist/guidance/components/SaveBar/README.md +65 -0
  85. package/dist/guidance/components/SavedViews/README.md +82 -0
  86. package/dist/guidance/components/ScatterChart/README.md +104 -0
  87. package/dist/guidance/components/Schedule/README.md +142 -0
  88. package/dist/guidance/components/ScrollArea/README.md +35 -0
  89. package/dist/guidance/components/SecretField/README.md +74 -0
  90. package/dist/guidance/components/Select/README.md +97 -0
  91. package/dist/guidance/components/Separator/README.md +70 -0
  92. package/dist/guidance/components/Sheet/README.md +126 -0
  93. package/dist/guidance/components/Skeleton/README.md +50 -0
  94. package/dist/guidance/components/Slider/README.md +60 -0
  95. package/dist/guidance/components/SortableList/README.md +45 -0
  96. package/dist/guidance/components/Sparkline/README.md +87 -0
  97. package/dist/guidance/components/SplitButton/README.md +65 -0
  98. package/dist/guidance/components/Stat/README.md +92 -0
  99. package/dist/guidance/components/Stepper/README.md +90 -0
  100. package/dist/guidance/components/Suggestions/README.md +87 -0
  101. package/dist/guidance/components/Surface/README.md +48 -0
  102. package/dist/guidance/components/Switch/README.md +38 -0
  103. package/dist/guidance/components/SyncIndicator/README.md +78 -0
  104. package/dist/guidance/components/Table/README.md +138 -0
  105. package/dist/guidance/components/Tabs/README.md +73 -0
  106. package/dist/guidance/components/TagInput/README.md +116 -0
  107. package/dist/guidance/components/Terminal/README.md +69 -0
  108. package/dist/guidance/components/ThreadList/README.md +110 -0
  109. package/dist/guidance/components/TimeInput/README.md +63 -0
  110. package/dist/guidance/components/Timeline/README.md +87 -0
  111. package/dist/guidance/components/Toaster/README.md +54 -0
  112. package/dist/guidance/components/Toggle/README.md +85 -0
  113. package/dist/guidance/components/Toolbar/README.md +106 -0
  114. package/dist/guidance/components/Tooltip/README.md +41 -0
  115. package/dist/guidance/components/Tour/README.md +73 -0
  116. package/dist/guidance/components/Trace/README.md +129 -0
  117. package/dist/guidance/components/Tree/README.md +171 -0
  118. package/dist/guidance/evidence.json +18 -0
  119. package/dist/guidance/index.json +811 -7
  120. package/dist/guidance/llms.txt +153 -2
  121. package/dist/guidance/manifest.json +133 -12
  122. package/dist/guidance/patterns/screen-layout.md +1 -1
  123. package/dist/guidance/references/build/checks/agent-setup.mjs +7 -0
  124. package/dist/guidance/references/build/checks/guidance.mjs +8 -2
  125. package/dist/guidance/references/build/checks/source-check.mjs +101 -0
  126. package/dist/guidance/rules.json +155 -0
  127. package/dist/guidance/visual/ActionsInPlace.md +463 -0
  128. package/dist/guidance/visual/Charts.md +119 -0
  129. package/dist/guidance/visual/Distinctiveness.md +106 -0
  130. package/dist/guidance/visual/Elevation.md +1 -1
  131. package/dist/guidance/visual/Mobile.md +64 -0
  132. package/dist/guidance/visual/Motion.md +225 -0
  133. package/dist/guidance/visual/README.md +98 -0
  134. package/dist/guidance/visual/Research.md +1 -1
  135. package/dist/guidance/visual/Theming.md +349 -0
  136. package/dist/types/agent-fleet.d.ts +28 -0
  137. package/dist/types/ai-label.d.ts +7 -0
  138. package/dist/types/app-shell.d.ts +23 -0
  139. package/dist/types/area-chart.d.ts +8 -0
  140. package/dist/types/artifact.d.ts +14 -0
  141. package/dist/types/bar-chart.d.ts +6 -0
  142. package/dist/types/bar-list.d.ts +6 -0
  143. package/dist/types/breadcrumb.d.ts +6 -0
  144. package/dist/types/chart-brush.d.ts +6 -0
  145. package/dist/types/chart.d.ts +29 -1
  146. package/dist/types/checklist.d.ts +6 -0
  147. package/dist/types/code-block.d.ts +6 -0
  148. package/dist/types/collections.d.ts +15 -0
  149. package/dist/types/color-picker.d.ts +6 -0
  150. package/dist/types/command.d.ts +13 -0
  151. package/dist/types/comment-thread.d.ts +11 -0
  152. package/dist/types/confirmation.d.ts +8 -0
  153. package/dist/types/context-menu.d.ts +11 -0
  154. package/dist/types/controls.d.ts +174 -10
  155. package/dist/types/conversation.d.ts +21 -0
  156. package/dist/types/copy-button.d.ts +6 -0
  157. package/dist/types/core.d.ts +31 -0
  158. package/dist/types/data-grid.d.ts +25 -0
  159. package/dist/types/date-picker.d.ts +6 -0
  160. package/dist/types/diff-view.d.ts +8 -0
  161. package/dist/types/dot-plot.d.ts +6 -0
  162. package/dist/types/edit-region.d.ts +23 -0
  163. package/dist/types/empty.d.ts +9 -0
  164. package/dist/types/feature-gate.d.ts +8 -0
  165. package/dist/types/filter-bar.d.ts +8 -0
  166. package/dist/types/formatted-number.d.ts +6 -0
  167. package/dist/types/heatmap.d.ts +6 -0
  168. package/dist/types/inline-citation.d.ts +6 -0
  169. package/dist/types/inline-edit.d.ts +7 -0
  170. package/dist/types/input-otp.d.ts +11 -0
  171. package/dist/types/item-group.d.ts +29 -0
  172. package/dist/types/line-chart.d.ts +6 -0
  173. package/dist/types/link.d.ts +8 -1
  174. package/dist/types/markdown.d.ts +6 -0
  175. package/dist/types/meter.d.ts +6 -0
  176. package/dist/types/nav.d.ts +6 -0
  177. package/dist/types/notifications.d.ts +6 -0
  178. package/dist/types/number-input.d.ts +6 -0
  179. package/dist/types/overlays.d.ts +61 -0
  180. package/dist/types/page-header.d.ts +14 -0
  181. package/dist/types/pagination.d.ts +6 -0
  182. package/dist/types/password-input.d.ts +6 -0
  183. package/dist/types/permission-matrix.d.ts +7 -0
  184. package/dist/types/pile.d.ts +6 -0
  185. package/dist/types/plan-picker.d.ts +6 -0
  186. package/dist/types/prompt-input.d.ts +11 -0
  187. package/dist/types/property-list.d.ts +17 -0
  188. package/dist/types/question.d.ts +11 -0
  189. package/dist/types/relative-time.d.ts +8 -1
  190. package/dist/types/removal-receipt.d.ts +18 -1
  191. package/dist/types/save-bar.d.ts +6 -0
  192. package/dist/types/saved-views.d.ts +12 -0
  193. package/dist/types/scatter-chart.d.ts +8 -0
  194. package/dist/types/schedule.d.ts +21 -0
  195. package/dist/types/secret-field.d.ts +6 -0
  196. package/dist/types/select.d.ts +12 -0
  197. package/dist/types/separator.d.ts +8 -1
  198. package/dist/types/sheet.d.ts +19 -0
  199. package/dist/types/sparkline.d.ts +6 -0
  200. package/dist/types/split-button.d.ts +7 -0
  201. package/dist/types/stat.d.ts +7 -0
  202. package/dist/types/stepper.d.ts +12 -0
  203. package/dist/types/suggestions.d.ts +10 -0
  204. package/dist/types/sync-indicator.d.ts +8 -0
  205. package/dist/types/tag-input.d.ts +8 -0
  206. package/dist/types/terminal.d.ts +6 -0
  207. package/dist/types/thread-list.d.ts +16 -0
  208. package/dist/types/time-input.d.ts +6 -0
  209. package/dist/types/timeline.d.ts +9 -0
  210. package/dist/types/toggle.d.ts +6 -0
  211. package/dist/types/toolbar.d.ts +20 -0
  212. package/dist/types/tour.d.ts +10 -0
  213. package/dist/types/trace.d.ts +16 -0
  214. package/dist/types/tree.d.ts +21 -0
  215. package/dist/types-cjs/agent-fleet.d.cts +28 -0
  216. package/dist/types-cjs/ai-label.d.cts +7 -0
  217. package/dist/types-cjs/app-shell.d.cts +23 -0
  218. package/dist/types-cjs/area-chart.d.cts +8 -0
  219. package/dist/types-cjs/artifact.d.cts +14 -0
  220. package/dist/types-cjs/bar-chart.d.cts +6 -0
  221. package/dist/types-cjs/bar-list.d.cts +6 -0
  222. package/dist/types-cjs/breadcrumb.d.cts +6 -0
  223. package/dist/types-cjs/chart-brush.d.cts +6 -0
  224. package/dist/types-cjs/chart.d.cts +29 -1
  225. package/dist/types-cjs/checklist.d.cts +6 -0
  226. package/dist/types-cjs/code-block.d.cts +6 -0
  227. package/dist/types-cjs/collections.d.cts +15 -0
  228. package/dist/types-cjs/color-picker.d.cts +6 -0
  229. package/dist/types-cjs/command.d.cts +13 -0
  230. package/dist/types-cjs/comment-thread.d.cts +11 -0
  231. package/dist/types-cjs/confirmation.d.cts +8 -0
  232. package/dist/types-cjs/context-menu.d.cts +11 -0
  233. package/dist/types-cjs/controls.d.cts +174 -10
  234. package/dist/types-cjs/conversation.d.cts +21 -0
  235. package/dist/types-cjs/copy-button.d.cts +6 -0
  236. package/dist/types-cjs/core.d.cts +31 -0
  237. package/dist/types-cjs/data-grid.d.cts +25 -0
  238. package/dist/types-cjs/date-picker.d.cts +6 -0
  239. package/dist/types-cjs/diff-view.d.cts +8 -0
  240. package/dist/types-cjs/dot-plot.d.cts +6 -0
  241. package/dist/types-cjs/edit-region.d.cts +23 -0
  242. package/dist/types-cjs/empty.d.cts +9 -0
  243. package/dist/types-cjs/feature-gate.d.cts +8 -0
  244. package/dist/types-cjs/filter-bar.d.cts +8 -0
  245. package/dist/types-cjs/formatted-number.d.cts +6 -0
  246. package/dist/types-cjs/heatmap.d.cts +6 -0
  247. package/dist/types-cjs/inline-citation.d.cts +6 -0
  248. package/dist/types-cjs/inline-edit.d.cts +7 -0
  249. package/dist/types-cjs/input-otp.d.cts +11 -0
  250. package/dist/types-cjs/item-group.d.cts +29 -0
  251. package/dist/types-cjs/line-chart.d.cts +6 -0
  252. package/dist/types-cjs/link.d.cts +8 -1
  253. package/dist/types-cjs/markdown.d.cts +6 -0
  254. package/dist/types-cjs/meter.d.cts +6 -0
  255. package/dist/types-cjs/nav.d.cts +6 -0
  256. package/dist/types-cjs/notifications.d.cts +6 -0
  257. package/dist/types-cjs/number-input.d.cts +6 -0
  258. package/dist/types-cjs/overlays.d.cts +61 -0
  259. package/dist/types-cjs/page-header.d.cts +14 -0
  260. package/dist/types-cjs/pagination.d.cts +6 -0
  261. package/dist/types-cjs/password-input.d.cts +6 -0
  262. package/dist/types-cjs/permission-matrix.d.cts +7 -0
  263. package/dist/types-cjs/pile.d.cts +6 -0
  264. package/dist/types-cjs/plan-picker.d.cts +6 -0
  265. package/dist/types-cjs/prompt-input.d.cts +11 -0
  266. package/dist/types-cjs/property-list.d.cts +17 -0
  267. package/dist/types-cjs/question.d.cts +11 -0
  268. package/dist/types-cjs/relative-time.d.cts +8 -1
  269. package/dist/types-cjs/removal-receipt.d.cts +18 -1
  270. package/dist/types-cjs/save-bar.d.cts +6 -0
  271. package/dist/types-cjs/saved-views.d.cts +12 -0
  272. package/dist/types-cjs/scatter-chart.d.cts +8 -0
  273. package/dist/types-cjs/schedule.d.cts +21 -0
  274. package/dist/types-cjs/secret-field.d.cts +6 -0
  275. package/dist/types-cjs/select.d.cts +12 -0
  276. package/dist/types-cjs/separator.d.cts +8 -1
  277. package/dist/types-cjs/sheet.d.cts +19 -0
  278. package/dist/types-cjs/sparkline.d.cts +6 -0
  279. package/dist/types-cjs/split-button.d.cts +7 -0
  280. package/dist/types-cjs/stat.d.cts +7 -0
  281. package/dist/types-cjs/stepper.d.cts +12 -0
  282. package/dist/types-cjs/suggestions.d.cts +10 -0
  283. package/dist/types-cjs/sync-indicator.d.cts +8 -0
  284. package/dist/types-cjs/tag-input.d.cts +8 -0
  285. package/dist/types-cjs/terminal.d.cts +6 -0
  286. package/dist/types-cjs/thread-list.d.cts +16 -0
  287. package/dist/types-cjs/time-input.d.cts +6 -0
  288. package/dist/types-cjs/timeline.d.cts +9 -0
  289. package/dist/types-cjs/toggle.d.cts +6 -0
  290. package/dist/types-cjs/toolbar.d.cts +20 -0
  291. package/dist/types-cjs/tour.d.cts +10 -0
  292. package/dist/types-cjs/trace.d.cts +16 -0
  293. package/dist/types-cjs/tree.d.cts +21 -0
  294. package/package.json +1 -1
@@ -0,0 +1,107 @@
1
+ # DiffView
2
+
3
+ What changed between two versions: version history, audit-log detail ("Plan: Pro → Business"), config changes before a deploy, and edits an AI proposes to a document or record.
4
+
5
+ **Elevation.** Both versions are the record, so it lies flush on the ground with a `line` rim, as `CodeBlock` does. It has no height of its own. **Never colour alone.**
6
+ - **Additions** are `positive-soft`, with a `+` sign and "Added" in their name (`<ins>`).
7
+ - **Removals** are `critical-soft`, struck through, with a `−` sign and "Removed" (`<del>`).
8
+ - **Words that changed** inside a line take a stronger tint. A removal and the addition that replaces it are paired in order, within a block of changed lines.
9
+ - **Long unchanged runs** fold behind a lid ("6 unchanged lines"), keeping `context` lines around each change. A single unchanged line is never folded.
10
+ - **In `mode="properties"`**, each changed field shows its old value struck through beside the new.
11
+
12
+ **Restoring a version is a consequential action**, not something the diff does: follow the consequential-action pattern (a confirmation, then a receipt).
13
+
14
+ **Accessibility.** A `figure` named by its caption, with a summary first ("3 additions, 2 removals", "2 properties changed"). Previous change and Next change move focus from change to change, and so do the `n` and `p` keys while focus is inside. Signs are hidden; "Added" and "Removed" are read. Under forced colours the tints are dropped, and the signs and strike-through carry the meaning. Under `contrast="more"` each changed line gets a 2px edge in its tone.
15
+
16
+ **Props:** `mode` (`'text' | 'properties'`); `before`, `after` (texts, or records); `fields` (`{ key, label, format? }[]`, for properties); `context` (default 3); `caption`; `hunks` (precomputed line operations for large inputs; `diffLines(before, after)` makes them).
17
+
18
+ **Reviewing a proposed change.** With `review` (text mode), each change is a labelled group ("Change 3 of 7, lines 40 to 52") raised as a proposal, with Accept and Reject; the header counts "3 of 7 changes reviewed" and offers Accept all and Reject all; n and p (or ] and [) move between undecided changes. `decisions` is yours (by id, `change-1` in order; `diffChanges` lists them), as is applying them. Accepted lands flush with one afterglow; rejected is muted and collapses to "Rejected · show" after `dur-linger`. Decisions are announced ("Change 3 accepted. 4 left."). Property diffs aren't reviewable yet.
19
+
20
+ **You provide:** the two versions and a caption that names them.
21
+
22
+ ```tsx
23
+ <DiffView caption="Version 4 → 5" before={v4.body} after={v5.body} context={3} />
24
+ <DiffView mode="properties" caption="Subscription changed" before={prev} after={next} fields={[{ key: 'plan', label: 'Plan' }]} />
25
+ ```
26
+
27
+ - Do say which versions are compared in the caption.
28
+ - Do keep a little context around changes, so they can be read.
29
+ - Don't show a diff in red and green alone.
30
+ - Don't restore from inside the diff without a confirmation.
31
+
32
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
33
+ ## Example
34
+
35
+ `DiffView` as first used in its preview:
36
+
37
+ ```tsx
38
+ import { DiffView, diffChanges, diffLines } from 'altitude-design';
39
+
40
+ <DiffView caption="src/pricing.ts · proposed by the assistant" before={pricingBefore} after={pricingAfter} review decisions={decisions}
41
+ onDecide={(id, d) => setDecisions({ ...decisions, [id]: d })}
42
+ onDecideAll={(d) => setDecisions(Object.fromEntries(diffChanges(diffLines(pricingBefore, pricingAfter)).map((c) => [c.id, decisions[c.id] ?? d])))} />
43
+ ```
44
+
45
+ The full preview, as rendered in Storybook and checked in CI (`dv` is the preview page's own layout class, not Altitude's):
46
+
47
+ ```tsx
48
+ import * as React from 'react';
49
+ import { DiffView, diffChanges, diffLines } from 'altitude-design';
50
+
51
+ const v4 = `# Deploy settings
52
+ region: eu-central-1
53
+ replicas: 2
54
+ memory: 512Mi
55
+ timeout: 30s
56
+ retries: 3
57
+ logging: info
58
+ metrics: enabled
59
+ tracing: disabled
60
+ cache: 5m
61
+ health: /healthz
62
+ owner: platform-team`;
63
+ const v5 = `# Deploy settings
64
+ region: eu-central-1
65
+ replicas: 4
66
+ memory: 1Gi
67
+ timeout: 30s
68
+ retries: 3
69
+ logging: info
70
+ metrics: enabled
71
+ tracing: disabled
72
+ cache: 5m
73
+ health: /healthz
74
+ owner: platform-team
75
+ alerts: on-call`;
76
+ const pricingBefore = `export const plans = {
77
+ starter: { monthly: 9, seats: 1 },
78
+ pro: { monthly: 29, seats: 5 },
79
+ business: { monthly: 99, seats: 25 },
80
+ };
81
+ export const trialDays = 14;
82
+ export const currency = 'USD';`;
83
+ const pricingAfter = `export const plans = {
84
+ starter: { monthly: 9, seats: 1 },
85
+ pro: { monthly: 32, seats: 5 },
86
+ business: { monthly: 99, seats: 25, sso: true },
87
+ };
88
+ export const trialDays = 30;
89
+ export const currency = 'USD';`;
90
+ function Review() {
91
+ const [decisions, setDecisions] = React.useState({ 'change-2': 'accept' });
92
+ return <DiffView caption="src/pricing.ts · proposed by the assistant" before={pricingBefore} after={pricingAfter} review decisions={decisions}
93
+ onDecide={(id, d) => setDecisions({ ...decisions, [id]: d })}
94
+ onDecideAll={(d) => setDecisions(Object.fromEntries(diffChanges(diffLines(pricingBefore, pricingAfter)).map((c) => [c.id, decisions[c.id] ?? d])))} />;
95
+ }
96
+ export default function App() {
97
+ return (
98
+ <div className="dv">
99
+ <DiffView caption="deploy.yaml · version 4 → 5" before={v4} after={v5} context={1} />
100
+ <DiffView mode="properties" caption="Subscription changed by Maya" before={{ plan: 'Pro', seats: 12, billing: 'Monthly' }} after={{ plan: 'Business', seats: 25, billing: 'Monthly' }}
101
+ fields={[{ key: 'plan', label: 'Plan' }, { key: 'seats', label: 'Seats' }, { key: 'billing', label: 'Billing' }]} />
102
+ <Review />
103
+ </div>
104
+ );
105
+ }
106
+ ```
107
+ <!-- /example -->
@@ -0,0 +1,82 @@
1
+ # DotPlot
2
+
3
+ Values compared across categories where zero isn't part of the story: ten services' p95, all between 180 and 240 ms; scores by team with their spread; last quarter against this one. A `BarChart` must stand on zero, which squashes differences of a few percent into identical bars, and bars of averages carry a measured misreading: values inside the bar are judged likelier than values equally far outside it (Newman & Scholl, 2012), which dot plots reduce (Okan et al., 2018). Without this form people reach for bars and either squash the data or truncate the axis, which Altitude forbids.
4
+
5
+ **Why it's flat.** The values are the record, so the dots lie on the plot as a `ScatterChart`'s do: at least 8px, a `data-*` fill (a marker shape per series when there's more than one), and a 2px ring of the plot's own colour so neighbours stay apart. Never raised, never shaded. The value is position, never height, on an axis that needn't include zero; with no zero there's no ground line, only the plot's foot, as on a `LineChart` that leaves zero off.
6
+
7
+ **Rows.** Categories run down the side, as on a horizontal `BarChart`, with the same label budget. Each row has a 1px `line` guide from its label across the plot. `sort="desc"` orders the rows by value (the first series', or `to`'s), and re-sorted rows are carried to their places.
8
+
9
+ **A spread.** `range={['p10', 'p90']}` draws a flat band of the series colour at 16% behind the dot, with round ends: an uncertainty band, as on a `LineChart`, never error bars, which readers misjudge (Correll & Gleicher, 2014). `rangeLabel` says what it is ("10th–90th percentile"). It joins the axis, the readout, each point's name ("Billing, p95, 236 ms. 10th–90th percentile 190 ms to 320 ms.") and a column of the table.
10
+
11
+ **Before and after.** `from="q2" to="q3"` makes a dumbbell: the earlier dot hollow, the later filled, both in one colour because they're one entity at two times, joined by a 2px `ink-muted` link. The change is said in words, as `compare` says it: "Up 7.5% from Q2" in the later dot's name, a row in the readout, "Q2" and "vs Q2" columns in the table, and "Against Q2: 4 rose, 1 fell." in the summary.
12
+
13
+ **Without colour.** Under forced colours the dots are `CanvasText` ringed in `Canvas` (a hollow dot is a `CanvasText` ring on `Canvas`), the spread `GrayText`, the link `CanvasText`. With `contrast="more"` the row guides are `line-control`, as gridlines are.
14
+
15
+ **Motion.** The container's engine: a rescale first, then the dots, their spreads and their links glide to their new values on `ease-glide`; re-sorted rows are carried. Nothing grows in on first render. Under reduced motion values change in place.
16
+
17
+ **Accessibility.** The keyboard path is one Tab stop: the summary, then the series, then the points down the rows. The generated summary names the range, the lowest and highest, and the widest spread. The readout, each point's name and the table view carry the spread and the change.
18
+
19
+ **Props:** `data`, `x`; `sort`; `range`, `rangeLabel`, `rangeSeries`; `from` and `to`; `zero` (default false); `relevance` and `rescale`; `selected`, `onSelect`, `drill`; `focus`; `tooltip`; `empty`.
20
+
21
+ **Selecting, drilling and filtering** work as on every chart: a mark that acts gets a 2px `ink` outline round its dots under the pointer or keyboard, never a lift; misses recede to 35% where they stand.
22
+
23
+ **You provide:** a `ChartContainer` whose `config` names and formats the value (or `from` and `to`), the records, and usually a `summary` or a `takeaway` that says what the comparison means.
24
+
25
+ ```tsx
26
+ <ChartContainer config={{ p95: { label: 'p95', format: (v) => `${v} ms` } }}>
27
+ <DotPlot data={services} x="service" range={['p10', 'p90']} rangeLabel="10th–90th percentile" sort="desc" />
28
+ </ChartContainer>
29
+
30
+ <ChartContainer config={{ q2: { label: 'Q2' }, q3: { label: 'Q3' } }}>
31
+ <DotPlot data={teams} x="team" from="q2" to="q3" sort="desc" />
32
+ </ChartContainer>
33
+ ```
34
+
35
+ - Do use it when the differences are a few percent of the values, or when each value is an average with a spread.
36
+ - Do sort the rows unless their order means something.
37
+ - Don't use it for change over time; that's a `LineChart`, which implies continuity.
38
+ - Don't set `zero` just to have it: if zero matters, a `BarChart` is usually the better form.
39
+
40
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
41
+ ## Example
42
+
43
+ `DotPlot` as first used in its preview:
44
+
45
+ ```tsx
46
+ import { DotPlot } from 'altitude-design';
47
+
48
+ <DotPlot data={services} x="service" range={['p10', 'p90']} rangeLabel="10th–90th percentile" sort="desc" />
49
+ ```
50
+
51
+ The full preview, as rendered in Storybook and checked in CI (`dp` is the preview page's own layout class, not Altitude's):
52
+
53
+ ```tsx
54
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle, ChartContainer, DotPlot } from 'altitude-design';
55
+
56
+ const services = [['Checkout', 212, 180, 240], ['Search', 188, 170, 205], ['Billing', 236, 190, 320], ['Accounts', 199, 182, 214], ['Media', 228, 196, 268], ['Auth', 184, 176, 193], ['Exports', 221, 187, 262], ['Email', 193, 179, 209]]
57
+ .map(([service, p95, p10, p90]) => ({ service, p95, p10, p90 }));
58
+ const teams = [['Atlas', 71, 78], ['Birch', 64, 62], ['Cedar', 80, 86], ['Delta', 58, 69], ['Ember', 75, 77]].map(([team, q2, q3]) => ({ team, q2, q3 }));
59
+ export default function App() {
60
+ return (
61
+ <div className="dp">
62
+ <Card>
63
+ <CardHeader><CardTitle id="d1">p95 latency by service</CardTitle><CardDescription>All between 180 and 240 ms; the band is the 10th–90th percentile</CardDescription></CardHeader>
64
+ <CardContent>
65
+ <ChartContainer aria-labelledby="d1" aspect={1.5} config={{ p95: { label: 'p95', format: (v) => `${v} ms` } }}>
66
+ <DotPlot data={services} x="service" range={['p10', 'p90']} rangeLabel="10th–90th percentile" sort="desc" />
67
+ </ChartContainer>
68
+ </CardContent>
69
+ </Card>
70
+ <Card>
71
+ <CardHeader><CardTitle id="d2">Accessibility score, Q2 to Q3</CardTitle><CardDescription>A dumbbell: the hollow dot is Q2, the filled one Q3</CardDescription></CardHeader>
72
+ <CardContent>
73
+ <ChartContainer aria-labelledby="d2" aspect={1.5} config={{ q2: { label: 'Q2' }, q3: { label: 'Q3' } }}>
74
+ <DotPlot data={teams} x="team" from="q2" to="q3" sort="desc" />
75
+ </ChartContainer>
76
+ </CardContent>
77
+ </Card>
78
+ </div>
79
+ );
80
+ }
81
+ ```
82
+ <!-- /example -->
@@ -0,0 +1,43 @@
1
+ # Drilldown
2
+
3
+ Navigates a hierarchy as a **stack**. Each place you go into is laid on top of the one before it; going back lifts sheets off the top.
4
+
5
+ - Do use `Breadcrumb` for the same staircase in an app with routes; the two share one implementation.
6
+ - **The breadcrumb is a staircase.** Every crumb is a step standing on the same ground line, so all their contact shadows line up; a deeper place is a *taller* step (its wall is 3px longer), not one floating higher. Face and wall share one hairline (`--alt-ring`), so the top edge of a white step always reads against a light page, and every step casts its contact shadow at the same ground line. The root is the lowest step and where you are now is the tallest. Every step except the current one is a button: it rises 1px when pointed at and presses down to the ground when clicked, and choosing it climbs back to that place. When you go deeper, the new step rises up out of the ground.
7
+ - **The view sits on a pile.** One sheet shows beneath it for each level you've descended (up to three), the same language as `Pile`: depth you can see at rest.
8
+ - **Transitions follow the stack.** Going deeper, the child is laid on top while the parent is pressed beneath it; going back, the top sheet lifts off and the parent comes up from under it. Focus moves to each new view.
9
+
10
+ **You provide:** `root`, a tree of `{ id, title, description?, children?, content? }`. A node with children lists them; a leaf shows its `content`.
11
+
12
+ - Use it for nested places people move through (workspace → project → environment → build).
13
+ - Don't use it for steps in a process; a stack implies you can always lift back out.
14
+
15
+ **Charts that drill.** A node with both `content` and `children` shows its content, and the content opens the children itself: a chart's `drill={(d) => childId}`, or `useDrilldown().open(id)` from your own component. After a step, focus moves to the new view's own first stop when it names one (`data-drill-focus`, as a chart's summary does), otherwise to the view.
16
+
17
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
18
+ ## Example
19
+
20
+ `Drilldown` as first used in its preview:
21
+
22
+ ```tsx
23
+ import { Drilldown } from 'altitude-design';
24
+
25
+ <Drilldown root={tree} />
26
+ ```
27
+
28
+ The full preview, as rendered in Storybook and checked in CI (`wrap` is the preview page's own layout class, not Altitude's):
29
+
30
+ ```tsx
31
+ import { Drilldown } from 'altitude-design';
32
+
33
+ const tree = { id: 'ws', title: 'Workspace', children: [
34
+ { id: 'nw', title: 'Northwind', description: 'Marketing site', children: [
35
+ { id: 'prod', title: 'Production', description: 'acme.dev', children: [
36
+ { id: 'b42', title: 'Build #42', description: 'main@8dc01b2 · 2h ago', content: 'Deployed by Mara. 14 routes, 2.1 MB, healthy.' },
37
+ { id: 'b41', title: 'Build #41', description: 'main@51ac9e0 · yesterday', content: 'Rolled back after a cold-start regression.' } ] },
38
+ { id: 'prev', title: 'Preview', description: '3 branches', content: 'Preview deployments for open pull requests.' } ] },
39
+ { id: 'bc', title: 'Beacon', description: 'Internal dashboard', content: 'No deployments yet.' },
40
+ { id: 'st', title: 'Settings', description: 'Members, billing, domains', content: 'Workspace settings.' } ] };
41
+ export default function App() { return <div className="wrap"><Drilldown root={tree} /></div>; }
42
+ ```
43
+ <!-- /example -->
@@ -0,0 +1,71 @@
1
+ # DropZone
2
+
3
+ A receptacle that opens only when there's something to receive: flush at rest, sunk while a file is in flight, deeper under the pointer.
4
+
5
+ At rest it's a dashed outline on the ground. As soon as files are dragged anywhere over the page it sinks into a well (armed), so every place that can take the file announces itself. Hovering it deepens it to a trench with an `accent-ink` rim and `accent-soft` fill (over). Dropped files settle in with an afterglow. Clicking, Enter or Space opens the file picker.
6
+
7
+ **You provide:** `onFiles`, optional `accept` and `multiple`, the zone's content (an icon and "Drop files or browse"). `state` forces a visual state for documentation.
8
+
9
+ - Don't leave drop zones armed when nothing is being dragged; an always-open well stops meaning anything.
10
+
11
+ ## The queue
12
+
13
+ Pass `queue` and each file you're handling is a slat under the zone, named by its file and size:
14
+
15
+ - **uploading** is a task, so a `Progress` fill rises out of its trench ("Uploading, 40%"), with Cancel;
16
+ - **processing** is a write the server hasn't confirmed, so the slat **hovers as pending** ("Processing"), with Cancel;
17
+ - **done** lands and settles with the afterglow ("Uploaded"), with Remove;
18
+ - **failed** drops to a trench with its reason and **Retry**, and Remove.
19
+
20
+ `UploadItem` is `{ id, name, size?, state, progress?, error? }`. `onRetry`, `onCancel` and `onRemove` get the id, and their buttons name the file ("Retry upload of report.pdf"). Progress is announced at 25, 50, 75 and 100%, and on processing, finishing and failing, never continuously. Afterglows start at most four at once.
21
+
22
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
23
+ ## Example
24
+
25
+ `DropZone` as first used in its preview:
26
+
27
+ ```tsx
28
+ import { DropZone } from 'altitude-design';
29
+
30
+ <DropZone state="idle"><Body /></DropZone>
31
+ ```
32
+
33
+ The full preview, as rendered in Storybook and checked in CI (`three`, `lab` are the preview page's own layout classes, not Altitude's):
34
+
35
+ ```tsx
36
+ import * as React from 'react';
37
+ import { DropZone } from 'altitude-design';
38
+
39
+ const Body = () => <><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"><path d="M12 16V4M7 9l5-5 5 5M5 20h14" /></svg><span>Drop files or <u>browse</u></span></>;
40
+ export default function App() {
41
+ return (
42
+ <div className="three">
43
+ <div><div className="lab">idle · flush</div><DropZone state="idle"><Body /></DropZone></div>
44
+ <div><div className="lab">armed · a file is in flight</div><DropZone state="armed"><Body /></DropZone></div>
45
+ <div><div className="lab">over · ready to receive</div><DropZone state="over"><Body /></DropZone></div>
46
+ <div style={{ gridColumn: '1 / -1' }}><Queue /></div>
47
+ </div>
48
+ );
49
+ }
50
+ // A stand-in uploader: files upload in steps, then the server processes them; one fails until retried.
51
+ const start = [
52
+ { id: 'a', name: 'Q3 board deck.pdf', size: 2400000, state: 'uploading', progress: 0 },
53
+ { id: 'b', name: 'Customer list.csv', size: 480000, state: 'uploading', progress: 0 },
54
+ { id: 'c', name: 'Brand guidelines.pdf', size: 18200000, state: 'uploading', progress: 0, fails: true },
55
+ ];
56
+ function Queue() {
57
+ const [items, setItems] = React.useState(start);
58
+ React.useEffect(() => {
59
+ const t = setInterval(() => setItems((xs) => xs.map((x) => {
60
+ if (x.state === 'uploading') { const p = Math.min(100, x.progress + (x.id === 'b' ? 34 : 13)); if (x.fails && p > 40) return { ...x, state: 'failed', error: 'The connection dropped' }; return p >= 100 ? { ...x, state: 'processing', progress: 100 } : { ...x, progress: p }; }
61
+ if (x.state === 'processing') return Math.random() < 0.35 ? { ...x, state: 'done' } : x;
62
+ return x;
63
+ })), 450);
64
+ return () => clearInterval(t);
65
+ }, []);
66
+ return <DropZone multiple queue={items} onFiles={(fs) => setItems((xs) => [...xs, ...fs.map((f, i) => ({ id: f.name + Date.now() + i, name: f.name, size: f.size, state: 'uploading', progress: 0 }))])}
67
+ onRetry={(id) => setItems((xs) => xs.map((x) => (x.id === id ? { ...x, state: 'uploading', progress: 40, fails: false, error: undefined } : x)))}
68
+ onCancel={(id) => setItems((xs) => xs.filter((x) => x.id !== id))} onRemove={(id) => setItems((xs) => xs.filter((x) => x.id !== id))}><Body /></DropZone>;
69
+ }
70
+ ```
71
+ <!-- /example -->
@@ -0,0 +1,63 @@
1
+ # DropdownMenu
2
+
3
+ Lists actions for a trigger; one highlight glides between items, which arrive in quick sequence.
4
+
5
+ The menu rises like a Popover. Items stagger in at 16ms each. A single `accent-soft` highlight (`critical-soft` on a destructive item) follows the pointer or arrow keys on `ease-settle` instead of each row blinking on and off. Arrow keys, Home and End move; Enter selects; Escape and Tab close and return focus.
6
+
7
+ **On touch.** An item's `shortcut` is shown only where there's likely a keyboard: on a touch-only device it's hidden until a key is pressed in the session. The shortcut still works.
8
+
9
+ **On a narrow screen.** It opens where its `side` and `align` put it, then shifts sideways to stay 8px inside the screen, and it's never wider than the screen less 16px.
10
+
11
+ **As a sheet.** `presentation="auto"` (the default) opens the menu as a sheet at the bottom edge on a narrow touch screen (under 640px, with a coarse pointer), where the thumb is: full width less 8px, clear of the safe areas, a head with its `title` (default: the trigger's label) and Close, and 44px rows. It's still the menu, at level 3, with the same keyboard and roles. `"anchored"` or `"sheet"` forces one.
12
+
13
+ **You provide:** `trigger` (usually a Button with a `ChevronDown` trailing icon) and `items`: actions (`label`, optional `icon`, `shortcut`, `onSelect`, `tone: 'critical'`, `disabled`), `{ type: 'separator' }` and `{ type: 'label', label }`.
14
+
15
+ **Predicted items.** Mark items you expect the person to want with `predicted: true`. They appear at once; the others fade in over `dur-onset` (500ms). Nothing moves, so the menu stays learnable. In Findlater et al.'s studies this made selection faster than a static menu and than highlighting, but only when predictions were right about four times in five; misses cost a little time. Leave it off unless your predictions are that good.
16
+
17
+ - Do use `ContextMenu` for the same menu opened where something is right-clicked; the two share one implementation.
18
+ - Do use `checked` for an item that turns something on or off: it becomes a `menuitemcheckbox` with a check, and every item keeps a slot for the check so labels line up.
19
+ - Do put destructive actions last, after a separator, in `critical`.
20
+
21
+ <!-- example: generated from build/previews.txt by build/previews.mjs. Edit the preview, not this section. -->
22
+ ## Example
23
+
24
+ `DropdownMenu` as first used in its preview:
25
+
26
+ ```tsx
27
+ import { Button, DropdownMenu, Icons } from 'altitude-design';
28
+
29
+ <DropdownMenu defaultOpen items={items} trigger={<Button trailing={<Icons.ChevronDown />}>Actions</Button>} />
30
+ ```
31
+
32
+ The full preview, as rendered in Storybook and checked in CI (`pair` is the preview page's own layout class, not Altitude's):
33
+
34
+ ```tsx
35
+ import { Button, DropdownMenu, Icons } from 'altitude-design';
36
+
37
+ const items = [
38
+ { type: 'label', label: 'Project' },
39
+ { label: 'Rename', shortcut: 'R' },
40
+ { label: 'Duplicate', shortcut: '⌘D' },
41
+ { label: 'Move to…' },
42
+ { label: 'Archive', disabled: true },
43
+ { type: 'separator' },
44
+ { label: 'Delete project', tone: 'critical', shortcut: '⌫' },
45
+ ];
46
+ const predicted = [
47
+ { label: 'Copy link', shortcut: '⌘L', predicted: true },
48
+ { label: 'Share…', predicted: true },
49
+ { label: 'Rename', shortcut: 'R' },
50
+ { label: 'Duplicate', shortcut: '⌘D' },
51
+ { label: 'Export as PDF' },
52
+ { label: 'Version history' },
53
+ ];
54
+ export default function App() {
55
+ return (
56
+ <div className="pair">
57
+ <DropdownMenu defaultOpen items={items} trigger={<Button trailing={<Icons.ChevronDown />}>Actions</Button>} />
58
+ <DropdownMenu items={predicted} trigger={<Button trailing={<Icons.ChevronDown />}>Predicted</Button>} />
59
+ </div>
60
+ );
61
+ }
62
+ ```
63
+ <!-- /example -->