@twoux/ui 0.0.0-stage → 0.1.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 (325) hide show
  1. package/LICENSE.md +61 -0
  2. package/LICENSES/Apache-2.0.txt +202 -0
  3. package/NOTICE.md +64 -0
  4. package/README.md +211 -2
  5. package/SHADCN-DIFF.md +228 -0
  6. package/agent/AGENTS.md +358 -0
  7. package/agent/docs-md/accessibility.md +49 -0
  8. package/agent/docs-md/action-catalogue.md +81 -0
  9. package/agent/docs-md/actions.md +74 -0
  10. package/agent/docs-md/agent-activity-log.md +70 -0
  11. package/agent/docs-md/agent-permissions.md +82 -0
  12. package/agent/docs-md/agent-run.md +90 -0
  13. package/agent/docs-md/agents-on-behalf.md +74 -0
  14. package/agent/docs-md/ai-column.md +85 -0
  15. package/agent/docs-md/ai-origin-label.md +70 -0
  16. package/agent/docs-md/announcing-features.md +73 -0
  17. package/agent/docs-md/answer-actions.md +81 -0
  18. package/agent/docs-md/app-shell.md +114 -0
  19. package/agent/docs-md/artifact-card.md +89 -0
  20. package/agent/docs-md/ask-on-screen.md +72 -0
  21. package/agent/docs-md/assistant-page.md +100 -0
  22. package/agent/docs-md/assistant-panel.md +142 -0
  23. package/agent/docs-md/avatar.md +82 -0
  24. package/agent/docs-md/banner.md +106 -0
  25. package/agent/docs-md/board.md +163 -0
  26. package/agent/docs-md/breadcrumb.md +89 -0
  27. package/agent/docs-md/breakdown-table.md +97 -0
  28. package/agent/docs-md/bulk-action-bar.md +112 -0
  29. package/agent/docs-md/button.md +293 -0
  30. package/agent/docs-md/card.md +115 -0
  31. package/agent/docs-md/change-list.md +99 -0
  32. package/agent/docs-md/change-request.md +166 -0
  33. package/agent/docs-md/chart-area.md +87 -0
  34. package/agent/docs-md/chart-bar.md +100 -0
  35. package/agent/docs-md/chart-box-plot.md +88 -0
  36. package/agent/docs-md/chart-bullet.md +89 -0
  37. package/agent/docs-md/chart-candlestick.md +112 -0
  38. package/agent/docs-md/chart-card-line.md +120 -0
  39. package/agent/docs-md/chart-donut.md +90 -0
  40. package/agent/docs-md/chart-drill-down.md +72 -0
  41. package/agent/docs-md/chart-funnel.md +71 -0
  42. package/agent/docs-md/chart-heatmap.md +76 -0
  43. package/agent/docs-md/chart-histogram.md +81 -0
  44. package/agent/docs-md/chart-map.md +165 -0
  45. package/agent/docs-md/chart-mixed.md +88 -0
  46. package/agent/docs-md/chart-price.md +92 -0
  47. package/agent/docs-md/chart-radial-bars.md +109 -0
  48. package/agent/docs-md/chart-radial-lines.md +111 -0
  49. package/agent/docs-md/chart-sankey.md +104 -0
  50. package/agent/docs-md/chart-scatter.md +87 -0
  51. package/agent/docs-md/chart-share-bar.md +89 -0
  52. package/agent/docs-md/chart-treemap.md +98 -0
  53. package/agent/docs-md/chart-waterfall.md +93 -0
  54. package/agent/docs-md/checkbox.md +131 -0
  55. package/agent/docs-md/choosing-selection-control.md +71 -0
  56. package/agent/docs-md/citations-sources.md +79 -0
  57. package/agent/docs-md/citing-sources.md +63 -0
  58. package/agent/docs-md/clarify-before-acting.md +69 -0
  59. package/agent/docs-md/clarifying-question.md +92 -0
  60. package/agent/docs-md/code-block.md +174 -0
  61. package/agent/docs-md/colours.md +87 -0
  62. package/agent/docs-md/columns-menu.md +140 -0
  63. package/agent/docs-md/combobox.md +161 -0
  64. package/agent/docs-md/command-palette.md +126 -0
  65. package/agent/docs-md/confidence-note.md +87 -0
  66. package/agent/docs-md/configurable-dashboard.md +76 -0
  67. package/agent/docs-md/confirmation-dialog.md +93 -0
  68. package/agent/docs-md/connected-tools.md +80 -0
  69. package/agent/docs-md/connector-picker.md +127 -0
  70. package/agent/docs-md/consistency.md +53 -0
  71. package/agent/docs-md/content-density.md +61 -0
  72. package/agent/docs-md/conversation-history.md +78 -0
  73. package/agent/docs-md/create-record.md +80 -0
  74. package/agent/docs-md/csv-import.md +88 -0
  75. package/agent/docs-md/dashboard-items.md +78 -0
  76. package/agent/docs-md/data-export.md +61 -0
  77. package/agent/docs-md/data-grid.md +137 -0
  78. package/agent/docs-md/data-vis-colours.md +76 -0
  79. package/agent/docs-md/data-visualisation.md +76 -0
  80. package/agent/docs-md/date-picker.md +178 -0
  81. package/agent/docs-md/delete-record.md +75 -0
  82. package/agent/docs-md/dense-table.md +495 -0
  83. package/agent/docs-md/design-tokens.md +53 -0
  84. package/agent/docs-md/disabled-read-only.md +75 -0
  85. package/agent/docs-md/drag-and-drop.md +74 -0
  86. package/agent/docs-md/dropdown-menu.md +137 -0
  87. package/agent/docs-md/edit-record.md +73 -0
  88. package/agent/docs-md/empty-loading-error.md +78 -0
  89. package/agent/docs-md/empty-state.md +128 -0
  90. package/agent/docs-md/error-messages.md +75 -0
  91. package/agent/docs-md/error-state.md +123 -0
  92. package/agent/docs-md/export-menu.md +86 -0
  93. package/agent/docs-md/feedback-prompt.md +88 -0
  94. package/agent/docs-md/field-mapping.md +78 -0
  95. package/agent/docs-md/file-drop.md +110 -0
  96. package/agent/docs-md/filter-bar.md +138 -0
  97. package/agent/docs-md/filter-panel.md +103 -0
  98. package/agent/docs-md/filtering-search.md +79 -0
  99. package/agent/docs-md/follow-ups-starters.md +79 -0
  100. package/agent/docs-md/form-validation.md +95 -0
  101. package/agent/docs-md/generated-columns.md +65 -0
  102. package/agent/docs-md/generated-drafts-files.md +71 -0
  103. package/agent/docs-md/grouped-list.md +89 -0
  104. package/agent/docs-md/guide-cue.md +170 -0
  105. package/agent/docs-md/help-panel.md +103 -0
  106. package/agent/docs-md/help-system.md +74 -0
  107. package/agent/docs-md/iconography.md +49 -0
  108. package/agent/docs-md/inbox.md +108 -0
  109. package/agent/docs-md/inline-editing-validation.md +80 -0
  110. package/agent/docs-md/inline-input-in-answer.md +70 -0
  111. package/agent/docs-md/items-palette.md +116 -0
  112. package/agent/docs-md/keyboard-model.md +47 -0
  113. package/agent/docs-md/keyboard-navigation.md +68 -0
  114. package/agent/docs-md/keyboard-shortcut-hint.md +87 -0
  115. package/agent/docs-md/keyboard-shortcut-sheet.md +90 -0
  116. package/agent/docs-md/labelling-ai-output.md +66 -0
  117. package/agent/docs-md/layout.md +47 -0
  118. package/agent/docs-md/list-table.md +254 -0
  119. package/agent/docs-md/loading-skeleton.md +91 -0
  120. package/agent/docs-md/managing-agents.md +71 -0
  121. package/agent/docs-md/message-composer.md +105 -0
  122. package/agent/docs-md/migrating.md +49 -0
  123. package/agent/docs-md/motion.md +93 -0
  124. package/agent/docs-md/navigation.md +76 -0
  125. package/agent/docs-md/notification-channels.md +65 -0
  126. package/agent/docs-md/notifications-decision.md +100 -0
  127. package/agent/docs-md/onboarding-step.md +114 -0
  128. package/agent/docs-md/order-book.md +108 -0
  129. package/agent/docs-md/page-header.md +96 -0
  130. package/agent/docs-md/pagination.md +88 -0
  131. package/agent/docs-md/pane-layout.md +105 -0
  132. package/agent/docs-md/period-comparison.md +66 -0
  133. package/agent/docs-md/plan-card.md +120 -0
  134. package/agent/docs-md/popover-rules.md +88 -0
  135. package/agent/docs-md/prompt-editor.md +90 -0
  136. package/agent/docs-md/propose-apply.md +65 -0
  137. package/agent/docs-md/provider-logo.md +97 -0
  138. package/agent/docs-md/radio.md +83 -0
  139. package/agent/docs-md/ranked-list.md +102 -0
  140. package/agent/docs-md/reasoning-progress.md +72 -0
  141. package/agent/docs-md/record-detail.md +71 -0
  142. package/agent/docs-md/regenerating-answers.md +70 -0
  143. package/agent/docs-md/run-status-bar.md +94 -0
  144. package/agent/docs-md/saved-tasks-schedules.md +63 -0
  145. package/agent/docs-md/saved-views.md +149 -0
  146. package/agent/docs-md/saving-views.md +68 -0
  147. package/agent/docs-md/scheduler.md +258 -0
  148. package/agent/docs-md/secondary-panels.md +72 -0
  149. package/agent/docs-md/segmented-control.md +88 -0
  150. package/agent/docs-md/selection-bulk-actions.md +70 -0
  151. package/agent/docs-md/separator.md +75 -0
  152. package/agent/docs-md/setup-checklist.md +92 -0
  153. package/agent/docs-md/shape-elevation.md +55 -0
  154. package/agent/docs-md/sheet-grid.md +211 -0
  155. package/agent/docs-md/side-panel.md +134 -0
  156. package/agent/docs-md/sign-in.md +114 -0
  157. package/agent/docs-md/spacing.md +55 -0
  158. package/agent/docs-md/split-button.md +100 -0
  159. package/agent/docs-md/stat-compare.md +82 -0
  160. package/agent/docs-md/static-dashboard.md +75 -0
  161. package/agent/docs-md/status-badge.md +140 -0
  162. package/agent/docs-md/step-card.md +75 -0
  163. package/agent/docs-md/stepper.md +92 -0
  164. package/agent/docs-md/suggested-changes.md +91 -0
  165. package/agent/docs-md/switch.md +78 -0
  166. package/agent/docs-md/table-settings.md +81 -0
  167. package/agent/docs-md/tabs.md +85 -0
  168. package/agent/docs-md/tag-input.md +108 -0
  169. package/agent/docs-md/tag.md +79 -0
  170. package/agent/docs-md/task-builder.md +87 -0
  171. package/agent/docs-md/team-instructions.md +72 -0
  172. package/agent/docs-md/templates-gallery.md +85 -0
  173. package/agent/docs-md/text-input.md +160 -0
  174. package/agent/docs-md/thinking-steps.md +89 -0
  175. package/agent/docs-md/timeline.md +189 -0
  176. package/agent/docs-md/timestamp.md +84 -0
  177. package/agent/docs-md/timestamps.md +70 -0
  178. package/agent/docs-md/toast.md +117 -0
  179. package/agent/docs-md/tooltip.md +90 -0
  180. package/agent/docs-md/typography.md +62 -0
  181. package/agent/docs-md/undo-destructive.md +66 -0
  182. package/agent/docs-md/unsaved-changes.md +71 -0
  183. package/agent/docs-md/usage-meter.md +80 -0
  184. package/agent/docs-md/user-feedback.md +71 -0
  185. package/agent/docs-md/voice-and-tone.md +60 -0
  186. package/agent/docs-md/why-choice.md +93 -0
  187. package/agent/docs-md/workspace-onboarding.md +74 -0
  188. package/agent/docs-md/writing.md +48 -0
  189. package/agent/llms-full.txt +18369 -0
  190. package/agent/llms.txt +198 -0
  191. package/agent/skills/twoux-audit/SKILL.md +49 -0
  192. package/agent/skills/twoux-build/SKILL.md +39 -0
  193. package/agent/skills/twoux-design/SKILL.md +54 -0
  194. package/agent/skills/twoux-write/SKILL.md +32 -0
  195. package/bin/check.mjs +123 -0
  196. package/bin/docs.mjs +24 -0
  197. package/bin/guard.mjs +27 -0
  198. package/bin/init.mjs +113 -0
  199. package/bin/knowledge.mjs +87 -0
  200. package/bin/mcp.mjs +116 -0
  201. package/bin/theme.mjs +168 -0
  202. package/bin/twoux.mjs +25 -0
  203. package/package.json +80 -3
  204. package/registry/jobs.json +1028 -0
  205. package/registry/palette.json +770 -0
  206. package/registry/rules.json +913 -0
  207. package/src/components/agent-review.tsx +364 -0
  208. package/src/components/ai-basics.tsx +212 -0
  209. package/src/components/ai-work.tsx +304 -0
  210. package/src/components/ai.tsx +227 -0
  211. package/src/components/alert-dialog.tsx +203 -0
  212. package/src/components/alert.tsx +86 -0
  213. package/src/components/avatar.tsx +114 -0
  214. package/src/components/badge.tsx +59 -0
  215. package/src/components/board.tsx +397 -0
  216. package/src/components/breadcrumb.tsx +114 -0
  217. package/src/components/button-group.tsx +90 -0
  218. package/src/components/button.tsx +109 -0
  219. package/src/components/calendar.tsx +247 -0
  220. package/src/components/card.tsx +102 -0
  221. package/src/components/chart-map.tsx +336 -0
  222. package/src/components/charts-more.tsx +1331 -0
  223. package/src/components/charts-radial.tsx +328 -0
  224. package/src/components/charts.tsx +390 -0
  225. package/src/components/checkbox.tsx +40 -0
  226. package/src/components/code.tsx +139 -0
  227. package/src/components/collapsible.tsx +37 -0
  228. package/src/components/combobox.tsx +339 -0
  229. package/src/components/command-extras.tsx +11 -0
  230. package/src/components/command.tsx +196 -0
  231. package/src/components/data-grid.tsx +213 -0
  232. package/src/components/data-table.tsx +334 -0
  233. package/src/components/data-views.tsx +740 -0
  234. package/src/components/date-picker.tsx +686 -0
  235. package/src/components/dense-table.tsx +207 -0
  236. package/src/components/dialog.tsx +162 -0
  237. package/src/components/dropdown-menu.tsx +264 -0
  238. package/src/components/empty.tsx +114 -0
  239. package/src/components/feedback-prompt.tsx +80 -0
  240. package/src/components/field.tsx +254 -0
  241. package/src/components/fields.tsx +112 -0
  242. package/src/components/flow.tsx +840 -0
  243. package/src/components/guide-cue.tsx +273 -0
  244. package/src/components/inbox.tsx +113 -0
  245. package/src/components/input-group.tsx +176 -0
  246. package/src/components/input.tsx +26 -0
  247. package/src/components/kbd.tsx +34 -0
  248. package/src/components/label.tsx +27 -0
  249. package/src/components/labels.tsx +176 -0
  250. package/src/components/motion.tsx +136 -0
  251. package/src/components/onboarding.tsx +454 -0
  252. package/src/components/order-book.tsx +185 -0
  253. package/src/components/pane-layout.tsx +417 -0
  254. package/src/components/popover.tsx +96 -0
  255. package/src/components/provider-logos.data.ts +49 -0
  256. package/src/components/radio-group.tsx +52 -0
  257. package/src/components/scheduler.tsx +997 -0
  258. package/src/components/segmented-control.tsx +28 -0
  259. package/src/components/select.tsx +195 -0
  260. package/src/components/separator.tsx +31 -0
  261. package/src/components/sheet.tsx +148 -0
  262. package/src/components/shell.tsx +426 -0
  263. package/src/components/shortcut-sheet.tsx +83 -0
  264. package/src/components/skeleton.tsx +18 -0
  265. package/src/components/sonner.tsx +107 -0
  266. package/src/components/spinner.tsx +13 -0
  267. package/src/components/split-button.tsx +58 -0
  268. package/src/components/stepper.tsx +78 -0
  269. package/src/components/switch.tsx +43 -0
  270. package/src/components/table.tsx +126 -0
  271. package/src/components/tabs.tsx +118 -0
  272. package/src/components/tag-input.tsx +253 -0
  273. package/src/components/textarea.tsx +21 -0
  274. package/src/components/theme.tsx +80 -0
  275. package/src/components/timeline.tsx +408 -0
  276. package/src/components/toggle-group.tsx +87 -0
  277. package/src/components/toggle.tsx +54 -0
  278. package/src/components/tooltip.tsx +65 -0
  279. package/src/components/workspace-actions.tsx +294 -0
  280. package/src/components/workspace-import.tsx +465 -0
  281. package/src/components/workspace.tsx +1884 -0
  282. package/src/index.ts +80 -0
  283. package/src/lib/active-indicator.tsx +53 -0
  284. package/src/lib/chart-kit.tsx +72 -0
  285. package/src/lib/cn.ts +6 -0
  286. package/src/lib/shortcuts.tsx +61 -0
  287. package/src/lib/workspace.tsx +10 -0
  288. package/src/shadcn/alert-dialog.tsx +196 -0
  289. package/src/shadcn/alert.tsx +65 -0
  290. package/src/shadcn/avatar.tsx +108 -0
  291. package/src/shadcn/badge.tsx +47 -0
  292. package/src/shadcn/breadcrumb.tsx +108 -0
  293. package/src/shadcn/button-group.tsx +83 -0
  294. package/src/shadcn/button.tsx +63 -0
  295. package/src/shadcn/calendar.tsx +220 -0
  296. package/src/shadcn/card.tsx +91 -0
  297. package/src/shadcn/checkbox.tsx +31 -0
  298. package/src/shadcn/collapsible.tsx +33 -0
  299. package/src/shadcn/command.tsx +184 -0
  300. package/src/shadcn/dialog.tsx +158 -0
  301. package/src/shadcn/dropdown-menu.tsx +256 -0
  302. package/src/shadcn/empty.tsx +103 -0
  303. package/src/shadcn/field.tsx +248 -0
  304. package/src/shadcn/input-group.tsx +170 -0
  305. package/src/shadcn/input.tsx +20 -0
  306. package/src/shadcn/kbd.tsx +28 -0
  307. package/src/shadcn/label.tsx +23 -0
  308. package/src/shadcn/popover.tsx +88 -0
  309. package/src/shadcn/radio-group.tsx +44 -0
  310. package/src/shadcn/select.tsx +189 -0
  311. package/src/shadcn/separator.tsx +27 -0
  312. package/src/shadcn/sheet.tsx +142 -0
  313. package/src/shadcn/skeleton.tsx +13 -0
  314. package/src/shadcn/sonner.tsx +40 -0
  315. package/src/shadcn/switch.tsx +34 -0
  316. package/src/shadcn/table.tsx +115 -0
  317. package/src/shadcn/tabs.tsx +90 -0
  318. package/src/shadcn/textarea.tsx +17 -0
  319. package/src/shadcn/toggle-group.tsx +83 -0
  320. package/src/shadcn/toggle.tsx +46 -0
  321. package/src/shadcn/tooltip.tsx +56 -0
  322. package/src/styles/palette.css +127 -0
  323. package/src/styles/theme.css +35 -0
  324. package/src/styles/twoux.css +236 -0
  325. package/theme.json +14 -0
@@ -0,0 +1,358 @@
1
+ # TwoUX: rules for AI coding agents
2
+
3
+ <!-- Generated by scripts/build-llm.mjs from packages/ui/registry/jobs.json and apps/docs/src/content. Do not edit by hand. -->
4
+
5
+ TwoUX is an engineering-first, compact, keyboard-first design system for complex, data-intensive B2B applications (SaaS platforms, BI tools, fintech consoles, CRMs, ERPs): information-dense interfaces, complex data tables, advanced visualisations, drill-down workflows and command-centre dashboards, in light and dark. This file is TwoUX AI Knowledge: it tells you which component and pattern fits each job and why, so you never have to guess or invent UX. Every component, token and pattern is grounded in WCAG 2.2, WAI-ARIA and the design systems of major SaaS products. Its first rule is consistency: the same job always uses the same component, the same tokens and the same behaviour. Follow these rules for every UI change, without exception. Never invent a rule, component or source that isn't in these files.
6
+
7
+ ## Before writing any UI
8
+
9
+ 1. Find the job in the job table. Use the component it names, and read that component's page, including “When not to use”.
10
+ 2. If a pattern covers the flow (filtering, bulk actions, propose then apply, record detail…), follow its steps in order.
11
+ 3. If the component is planned or missing, do not build a local version, a lookalike or a partial one. Use the closest existing TwoUX component and tell the person what is missing.
12
+ 4. When you suggest a new component, layout or flow, base it on the patterns here, WAI-ARIA APG and WCAG 2.2. Use the closest existing component meanwhile.
13
+ 5. Before you finish, run `npx twoux check` and fix every error it reports.
14
+
15
+ Rules marked **TwoUX only** are about the @twoux/ui package, its tokens and its theme. Every other rule is a principle: it also holds in an app not built with TwoUX, where the component it names is the TwoUX way of meeting it.
16
+
17
+ ## Code
18
+
19
+ - **TwoUX only.** Import components from the TwoUX package. Never copy, restyle or rebuild a primitive locally. Package: `@twoux/ui`. Why: One implementation means one behaviour and one accessibility fix for everyone.
20
+ - **TwoUX only.** Use shadcn's component names and props exactly. TwoUX only adds a few props, such as loading and shortcut on Button, and the warning variant. Button variants: `default`, `outline`, `secondary`, `ghost`, `warning`, `destructive`, `link`. Button sizes: `xs`, `sm`, `default`, `lg`, `icon`, `icon-sm`, `icon-xs`. Why: TwoUX is generated from shadcn's source, so shadcn knowledge applies directly and agents do not invent variants.
21
+ - **TwoUX only.** Support light and dark by using role tokens only (bg-surface, text-ink-2, border-line, bg-ok-bg…). Never write dark: variants, a second set of classes, or a colour that only works on white. Light is the default; offer ThemeSwitcher (Light, Dark, Match system) in the header or account menu, and add THEME_SCRIPT to <head> so the page doesn't flash. Switch: `ThemeSwitcher`, `useTheme`, `setTheme`, `THEME_SCRIPT`. Root attribute: `<html data-theme="dark">`, `<html data-theme="system">`. Why: Each role holds a light and a dark value (CSS light-dark()), chosen and contrast-checked per theme, so code written once works in both. Charts use their own dark selection, not an inverted one.
22
+ - **TwoUX only.** Keep shadcn's own motion for overlays (dialogs, sheets, menus, popovers, tooltips, toasts); never retime it. For changes inside a screen use TwoUX's motion helpers, never a hand-written animation: Swap for an icon or label that changes state (Copy → Copied, Save → Saved), Count for a number that changes, RollingNumber for a figure on a stat card, ShimmerText for a working status line, StreamingText for AI text as it arrives, AnimateHeight for a card that changes size. Helpers: `Swap`, `Count`, `RollingNumber`, `ShimmerText`, `StreamingText`, `AnimateHeight`. Easing: `--ease-standard`, `--ease-entrance`, `--ease-move`, `--ease-exit`, `--ease-pop (pops only)`. Why: shadcn's timing is tuned and familiar, and one set of helpers keeps motion consistent, short and off under reduced motion. Motion confirms a change; it never decorates.
23
+ - **TwoUX only.** Never import Radix or a shadcn file directly in app code. Import from @twoux/ui, where the tailored versions live. Why: TwoUX wraps them with its tokens and restrictions; going around it bypasses both.
24
+ - **TwoUX only.** Style only with TwoUX role tokens and the utilities they generate. Examples: `bg-surface`, `text-ink-2`, `border-control`, `h-control`, `rounded-md`. Why: Roles can be re-pointed in one place; raw values cannot.
25
+ - **TwoUX only.** No hex colours, pixel values, inline styles or arbitrary Tailwind values. Blocked: `#5753E0`, `w-[37px]`, `style={…}`, `bg-slate-500`. Why: Every raw value is a decision nobody reviewed. Tailwind's default palette is switched off, so bg-slate-500 fails to build.
26
+ - **TwoUX only.** Use range tokens only in charts and reviewed illustrations, never in components. Range token: `--color-indigo-600`. Why: Components say what a colour is for, not which colour it is.
27
+ - Show third-party services with ProviderLogo: official marks only for services people sign in with or connect (Google, Microsoft, Slack…), unaltered and beside the service's name. Never draw, recolour or crop a mark, and never use the marks of reference or competing products. New providers are added in scripts/provider-logos.mjs. Component: `ProviderLogo`, `PROVIDERS`. Why: Brand guidelines allow a mark only to identify that service, unchanged; one generated source keeps licences and versions traceable.
28
+
29
+ ## Changing TwoUX
30
+
31
+ - **TwoUX only.** Never edit TwoUX itself during app work: nothing under `packages/ui/src`, `packages/ui/registry` or `node_modules/@twoux`. Protected: `packages/ui/src/components`, `packages/ui/src/shadcn`, `packages/ui/src/styles`. Instead: `props` (on the component), `composition` (in app code), `request` (ask the person to request it). Why: TwoUX components are generated from shadcn source by a script; a hand edit is lost on the next run and silently forks behaviour for everyone.
32
+ - **TwoUX only.** To change how the whole product looks (brand colour, corners, button shape, font, motion tempo), edit `twoux.theme.json` (in the TwoUX repo, `packages/ui/theme.json`) and run `npx twoux theme`. Never restyle or retime a component on one page, not even with valid tokens such as `px-3` or `rounded-full` on a Button or menu item. File: `twoux.theme.json`. Fields: `primary` (palette name or #RRGGBB), `radius` (xs, sm, md in px), `radius.button` (px or "pill"), `font`, `motion.tempo` (0.75 to 1.25), `motion.character` (standard or crisp). Command: `npx twoux theme`. Why: One theme file keeps every screen consistent, and the generator refuses colours that would fail WCAG contrast.
33
+ - **TwoUX only.** If a component needs a behaviour it lacks, first look for a prop or composition (for example onSelect with preventDefault to keep a menu open). If there is none, use the component as it is and tell the person what is missing; don't patch the component. Why: Props and composition keep the shared behaviour intact; patches fork it.
34
+
35
+ ## Layout and density
36
+
37
+ - **TwoUX only.** Compact density only. No other sizes, except size="dense" on tables and sheets for spreadsheet-like data. Controls: `input` (32px), `row` (36px). Buttons: `xs` (24px), `sm` (28px), `md` (32px), `lg` (36px). Dense tables and sheets: `row` (28px, spreadsheet-like data only). Why: Power users scan dense data; a fixed set of sizes keeps every screen aligned.
38
+ - **TwoUX only.** Use workspace density only on tool pages that pass all three tests: people watch and act on several regions at once, experts work in it for long repeated sessions, and the content is mostly numbers or tables scanned across many rows (trading, operations consoles, data workspaces, editors). Workspace density removes chrome and gaps, never size: AppShell frame="flush" with the sidebar as a rail, regions in PaneLayout divided by 1px lines, panes padded 8px, charts flush, size="dense" for spreadsheet-like tables. Forms, settings, onboarding, record detail, list pages and glance dashboards keep the inset canvas. Shell: `AppShell frame="flush"`, `sidebarRail`. Regions: `PaneLayout`, `usePaneSize`. Inside a pane: `ChartFrame frame="flush" (default in a flush shell)`, `Table size="dense" for spreadsheet-like data`. Why: Removing gaps and frames is what puts every region in view on a trading or operations screen; shrinking text or targets would make the same screen slower and fail WCAG 2.5.8. Text stays on TwoUX's type scale (13px body, 12px meta, never smaller), targets at 24px or more, and alerts, validation and empty states keep their size.
39
+ - One primary button per view. Why: The next step is obvious when only one action is primary.
40
+ - Show record detail in the side panel (push by default), not a modal or a new page. Why: People keep their place in the list.
41
+ - Animate only to show what changed, such as panels, tabs, menus and content swaps. Never animate decoration or row hover. Pick the duration by job and the easing by role: arrivals decelerate, movement eases both ends, exits are shorter and accelerate. Durations: `duration-fast` (120ms), `duration-base` (180ms), `duration-move` (200ms), `duration-slow` (260ms), `duration-long` (480ms (rolling figures only)), `duration-exit` (120ms). Easing: `ease-standard`, `ease-entrance`, `ease-move`, `ease-exit`. Utilities: `animate-fade-in`, `animate-rise-in`, `animate-pop-in`, `animate-fade-out`. Why: Short, consistent motion helps people follow a change; anything longer slows power users down. Everything stops when the system asks for reduced motion (WCAG 2.3.3).
42
+ - Every screen reflows down to 320px wide without sideways scrolling. Wide tables, code and charts scroll inside their own box; navigation collapses behind a menu button. Breakpoints: `md` (768px), `lg` (1024px), `xl` (1280px). Why: People zoom, split screens and use phones. WCAG 1.4.10 Reflow.
43
+ - **TwoUX only.** Icons stay smaller than the text they sit beside and are muted: 14px in menus, lists and small controls, 16px in buttons and default fields. Menus and lists: `size-3.5`, `text-ink-3`. Buttons and fields: `size-4`. Why: Icons support the label; at full size and full contrast they compete with it.
44
+ - Open at most one right-hand panel at a time; opening record detail, the assistant or help replaces the open one, and closing restores it. Workspace pages built with PaneLayout keep their regions as panes instead, and still open at most one right-hand panel. Why: Two side panels leave the table too narrow to use; a workspace gives each region its own pane that people size and arrange.
45
+
46
+ ## Separation and hierarchy
47
+
48
+ - **TwoUX only.** Use three elevations, each a light border plus a shadow: flat for tables and previews, card for things on the page, float for things above it. Flat: `border-line`. Card: `border-line`, `shadow-card`. Float: `shadow-pop`. Why: The border gives a crisp edge, the soft shadow gives lift. Together they separate without heavy lines.
49
+ - **TwoUX only.** Use a grey fill for quiet, supporting groups such as summaries, anatomy and sources. Not for primary content, and never with a shadow. Fill: `bg-surface-2`. Why: Fills recede, so the page reads primary content first.
50
+ - Use a tint only when it carries meaning: green for do, red for don't, primary for selection or the recommended path. Why: Colour that always means something is colour people learn.
51
+ - Selected items get a fill, not a heavier border. Fill: `bg-selected`. Why: A fill reads as state at a glance and keeps edges aligned.
52
+ - Text fields and selects use a light edge with a hairline shadow, and always have a visible label. Checkboxes, radios and switches keep the stronger edge, because nothing else marks them. Fields: `border-input`, `shadow-xs`, `hover:border-input-hover`. Focus: `border-primary`, `ring-3 ring-primary/20`. Small controls: `border-control` (3.59:1). Why: WCAG 1.4.11 needs 3:1 for the visual that identifies a control. A field is identified by its label and shadow; a checkbox only by its edge.
53
+ - **TwoUX only.** Corners are tight and follow role: 4px inside a control, 6px for controls and cards, 8px for what floats. Inner radius is the outer radius minus the padding. Inside: `rounded-xs` (badge, checkbox, menu item, segment). Controls: `rounded-sm` (button, input, toggle, banner, card). Floating: `rounded-md` (menu, popover, palette, toast, dialog). Why: Tight corners read as precise in a dense tool; matched nested corners make an element read as one object.
54
+
55
+ ## Content
56
+
57
+ - UK English, sentence case, verb-first labels: Publish listing, Export 2 rows. Why: Labels that say what happens are faster to act on.
58
+ - Before writing any label, message, empty state or assistant text, read docs-md/writing.md and docs-md/voice-and-tone.md (in Claude Code, /twoux-write); they override any general UX writing or design skill where the two differ. One voice everywhere, product and assistant alike: precise, calm, candid, respectful of expertise. The tone follows the moment (inform by default, empower at decisions, encourage when stuck, motivate only when starting, satisfy on routine work). Never humour, exclamation marks, celebration, "we", or effort words such as just, simply or easy. Why: Trust drives recommendation far more than friendliness, and power users see the same message hundreds of times; what amuses once annoys by the tenth.
59
+ - Say what happened and what to do next. No apologies, no vague errors. Why: People recover faster from errors that explain the fix.
60
+ - Never write “AI-powered”, “magic” or “smart”. Say what the assistant did. Why: Plain words build trust; hype erodes it.
61
+ - Status is always a word in a Badge; colour is never the only cue. Why: WCAG 1.4.1 Use of colour.
62
+ - Write every error as what happened plus what to do next, with raw codes only in a collapsed Details section. Why: Raw API text gives people nothing to act on.
63
+ - Render every date and time with the Timestamp component: relative in lists, absolute UK format with zone in details and deadlines, ISO 8601 in exports, always labelled. Why: Hand-formatted dates drift in format and leave out the zone and the event they refer to.
64
+ - If an action can't be undone, say so before it runs, in the button's confirmation or next to it, never only afterwards. Why: People decide differently when they know there is no way back.
65
+
66
+ ## Keyboard and accessibility
67
+
68
+ - Every action is reachable by keyboard, and shows its shortcut on the button. A button that opens a menu shows its shortcut inside the menu instead, beside the menu's heading. Prop: `shortcut="C"`. Why: Keyboard-first users learn shortcuts by seeing them. On a menu button the hint competes with the label and the menu's own options, so it moves to where people look once the menu is open.
69
+ - Single-key shortcuts must respect the setting that turns them off. Why: WCAG 2.1.4 Character key shortcuts.
70
+ - Meet WCAG 2.2 AA: 4.5:1 text, 3:1 control edges and icons, 24px minimum targets, visible focus. Why: The baseline TwoUX is tested against.
71
+ - Only one popover open at a time, and never cut off by its container. Why: Stacked or clipped popovers hide information and trap focus.
72
+ - When an action is unavailable but could become available, use aria-disabled and give a one-sentence reason in a tooltip; hide actions the person's role can never use. Why: A natively disabled button can't take focus, so keyboard users never see why.
73
+ - Ship every drag-and-drop with a keyboard path (pick up, arrows, drop, Esc) and a menu or button alternative that does the same move. Why: WCAG 2.2 requires a way to complete dragging tasks without dragging.
74
+
75
+ ## AI and agents
76
+
77
+ - The assistant changes data only through a proposal the person applies, with Undo. Why: People stay in control of what changes.
78
+ - Decisions about candidates are never set to Allow, and are reviewed one at a time with a recorded reason. Why: UK GDPR Article 22 and ICO guidance: rubber-stamped AI decisions about people count as solely automated.
79
+ - Mark AI-written content with the origin label and cite the records it used. Why: People can check where an answer came from.
80
+ - Every run can be stopped, and shows what it is doing. Why: Visible progress and a way out keep people in charge.
81
+ - Never give AI features their own colour, gradient, glow or sparkle icon; mark generated output only with `AiOrigin` ("Assistant · from …"). Why: A separate AI style competes with status colours and labels the feature instead of telling people where the output came from.
82
+ - Show Regenerate only on the latest answer, keep the previous version reachable with a version switch, and never let it undo or repeat changes already applied. Why: Regenerating an earlier answer silently drops later turns, and applied changes are reversed only through Undo.
83
+ - Route any generated draft that would change a record through `SuggestedChanges`; a generated file card may offer Open, Copy, Download or Suggest, never Save. Why: TwoUX's only path for the assistant to change data is a proposal the person applies, with Undo.
84
+ - Collect values needed to act in an inline input card with at most five required, prefilled fields that produces a proposal; use `ClarifyingQuestion` only to settle intent. Why: Mixing the two makes people type values into free text or answer forms about what they meant.
85
+ - After every approval request, leave a resolved line in the thread (Approved, Rejected, Approved automatically, Expired) and have the assistant acknowledge a rejection. Why: The decision is part of the record, and a closed card with no trace leaves people unsure what ran.
86
+ - Never offer Always allow, or the Allow level, for actions that decide on candidates or that reach people outside the workspace. Why: Candidate decisions stay with a person under UK GDPR Article 22, and outside contact can't be undone.
87
+ - Show no loading state for waits under one second, stream only prose, and render tables, record lists and files as a skeleton until they arrive whole. Why: Flicker and half-built tables mislead more than a short wait does.
88
+ - Never count failed or stopped steps as done, and end a summary that didn't finish with the reason: "2 of 5 steps · stopped". Why: A bare percentage reads as work still in progress and contradicts the list under it.
89
+ - Keep the composer pinned and never auto-scroll the thread or an activity log while the person is reading earlier content. Why: Jumping to new output loses the person's place and breaks copying.
90
+ - Never switch off or delete an agent automatically; mark it Needs attention and send its owner an Inbox item. Why: Agents that vanish silently break schedules and trust.
91
+ - Before a multi-step or costly run, show the plan with PlanCard: steps people can remove, steps that reach people outside the workspace or can't be undone marked, nothing running until approved and never on a timeout. If the plan changes mid-run, add a PlanChange line saying what changed and why. Why: Agreeing the plan first is cheaper than undoing the work, and a silent reroute breaks trust.
92
+ - Approvals for steps that send to people outside the workspace or move money show Approve and Cancel at equal weight (both outline). This is the only exception to one primary action per view. Why: A highlighted Approve nudges people to rubber-stamp the actions that are hardest to take back.
93
+ - Any change an agent proposes to records, procedures, prompts, tools or another agent arrives as a ChangeRequest: the reason in plain words, its origin, the diff (DiffView) and simulation results (SimulationResults). Nothing goes live until a person approves; rejecting asks for a reason; every decision leaves who and when. Why: Agents can change faster than people can read; review, test evidence and an attributable log keep a person accountable.
94
+ - When the agent is unsure, say so in words with ConfidenceNote, never as a percentage: what caused it and a safer option or a way to check. If it's unclear whether a change applies to one item, all items or future items, ask before acting. Why: People misread probabilities; a named cause and an alternative tell them what to do.
95
+ - Offer WhyChoice next to a choice the agent made on someone's behalf: the deciding factors, the options that lost, any requirement it couldn't meet, then Change this or Keep it. Explain on demand, not by default. Why: An explanation is only useful if it can be acted on and still matches the choice later.
96
+ - Cite every key claim next to the claim. Say when an answer rests on one source and how fresh time-sensitive facts are, keep what came from a source, from the person's own data and what was inferred apart, and label promoted or partner options every time. Why: Polished output hides weak evidence; people need to see how much to trust each part.
97
+ - Write the assistant's caveat as one specific limit and one thing to check, shown in the flow (AssistantPanel caveat), never a generic "can make mistakes". Why: A generic disclaimer is ignored; a specific limit tells people where to look.
98
+ - Decline out-of-scope requests in one sentence that names the boundary, then offer what the agent can do or where to get help. Why: A short, specific decline keeps people moving without making them feel they asked something wrong.
99
+ - Use one set of words for agent work everywhere: agent (the thing that acts), run (one piece of work), step (part of a run), plan (steps agreed before a run), proposal (changes waiting to be applied), change request (a proposed change to how something works), handoff (passing to a person), instructions (standing guidance people write), memory (facts the agent kept). Never task, job or workflow for a run. Why: Mixed words for the same thing make people think there are two features.
100
+ - Show the cost of a computed column before it runs and the running total while it runs; Stop is always available, and paid columns test on a few rows before running on all of them. Why: People decide differently when they see the price, and a run they can't stop spends credits they never agreed to.
101
+
102
+ ## Data and charts
103
+
104
+ - Choose the chart from the question: change over time is a line, amounts are bars, parts of a total over time are a stacked area, two to five parts at one moment are a donut, ordered stages are a funnel, two measures across records are a scatter. Why: A fixed mapping stops agents picking charts for looks and keeps every dashboard readable the same way.
105
+ - Never add a second y-axis; put a measure with a different unit in its own chart beside the first. Why: Dual scales make the relationship between series depend on the chosen scales and mislead readers.
106
+ - Build all four states for every chart (loading, empty, no match with Clear filters, error with Try again) inside the chart card, using TwoUX's state copy. Why: A blank or zeroed plot is read as real data.
107
+ - Plot missing data as a gap, never as zero, and start bars and areas at zero. Why: Both errors invent drops or exaggerate change that the data does not show.
108
+ - Give each chart an accessible name equal to its visible title, a description "[Chart type] showing [data], [period].", and a Table view. Why: Screen reader users and anyone who reads numbers better than shapes get the same information.
109
+ - Show a legend only for two or more series and a series filter only for three or more; legend items toggle series without changing any colour. Why: Extra controls on simple charts add noise, and repainting series on toggle breaks recognition.
110
+ - Make chart popovers pin on select or Enter, close on Esc, hold at most seven breakdown items and two buttons, and link a row's name or value, never both. Why: Hover-only popovers fail keyboard and touch, and crowded popovers hide the point.
111
+ - Use either chart drill-down or page drill-down on a page, never both, and show every drill-down filter as a removable pill in the filter bar. Why: Two levels of filters conflict, and hidden filters make people trust numbers that are narrowed without them knowing.
112
+ - Draw targets and limits as a dashed threshold line with a text label, not as a series and not in a status colour alone. Why: A threshold is a reference, and status colours are reserved for status meaning.
113
+ - Never plot individual candidates against each other on a chart, and never put candidate actions in a chart popover. Why: Charts of people read as rankings, and candidate decisions must stay with a person reviewing each record.
114
+ - Use a bullet chart for actual against target, never a gauge or dial. Use RadialBars only for share of a fixed limit (seats, credits, storage, a budget), with one to four rings at small size and used of limit written beside them. Why: Gauges spend a large area on one number and angles are read less exactly than lengths; a ring is acceptable only when the value is already in words and the limit is real.
115
+ - In a waterfall, draw increases and decreases in two categorical colours with + and − labels, and totals in neutral grey from zero. Why: Green and red would claim a judgement the chart cannot make, and the signs keep direction readable without colour.
116
+ - Fold parts past six in a share bar, or past twelve in a treemap, into a grey Other; never add colours to fit more. Why: Past that, parts cannot be told apart, and a colour on Other would make it read as one more series.
117
+ - When a price or candlestick axis does not start at zero, say so under the axis; every other chart starts at zero. Why: A cropped axis exaggerates change unless the reader is told.
118
+ - Give every sheet column a type shown by its icon, and show computed columns' state in words: in each cell (Waiting, Writing, Failed with the reason, Not found) and in a status row under the header. Why: People recognise a column by its type at a glance, and a word tells them what to do where a colour or spinner can't.
119
+ - **TwoUX only.** Use size="dense" (28px rows) on Table or SheetGrid only for spreadsheet-like data people scan many rows of: inventories, ledgers, bills of materials, imports and field mappings. Everything else keeps 36px rows. Why: Dense rows put more of a sheet in view where people compare many rows; elsewhere they only cost readability.
120
+ - An in-cell button (TableCellAction, or SheetGrid's Open) shows on row hover and keyboard focus, always on touch screens, and repeats an action that is also in the row's ⋮ menu. It is never the only way to do the action. Why: Hover-revealed controls are missed by some people and can't be hovered on touch; the menu is the dependable path.
121
+ - Spreadsheet keys follow Excel and Google Sheets: Shift+arrows extend the selection, ⌘ or Ctrl+arrows jump to the edge of the data, ⌘C and ⌘V copy and paste tab-separated values, ⌘D and ⌘R fill, Delete clears, ⌘Z and ⌘⇧Z (or Ctrl+Y) undo and redo. Use SheetGrid for this; never write another keyboard handler for these actions. Why: People bring years of spreadsheet habits, and copy and paste must work across the tools they already use.
122
+ - A paste checks every value against its column. Rejected cells keep their value, are marked on the cell with the reason, and the status line says how many were left and why; a value is never dropped silently or written in part. Why: Pastes from other tools often carry text into number or date columns; people can only fix what they are told about.
123
+ - **TwoUX only.** Use SplitButton when one action is the usual choice and a few close variants exist (Import data, then Import all and Import selection). Never join a Button and a menu trigger by hand. Why: One component keeps the parts, divider, names and menu the same everywhere.
124
+ - Use a map only when location itself is the question; to compare amounts use a bar chart or ranked list. Shade regions only by a rate or per-head figure, put raw counts on sized markers, and draw regions with no data hatched and labelled No data, never as zero. Why: Large regions draw the eye whatever their value, and shading raw counts mostly maps where people live; a missing value painted as zero invents a result.
125
+ - Use RadialLines only for cyclical periods (hour of day, day of week, month of year) where the last period runs into the first: one to three series, values from zero, missing data as a gap. For any other time use a line chart. Why: Polar coordinates help only when the end of the scale meets the start; elsewhere angles and a crowded centre read less exactly than a line.
126
+ - Show records people book or rearrange in time (interviews, shifts, rooms) in Scheduler: Day, Week and Month in its segmented control, open events in the side panel, create in a dialog, and move with drag, keyboard (Space, arrows, Enter) or the event menu, each with Undo. Never build a calendar grid by hand. Why: One scheduler keeps the keyboard and menu paths every drag needs (WCAG 2.5.7), UK 24-hour times and the agenda that reflows to 320px.
127
+
128
+ ## Patterns
129
+
130
+ - Before adding anything to a dashboard, pick one item type from Dashboard items (key metrics, chart, list, status and alerts, quick links, getting started, feature news) and give it one job. Why: A fixed catalogue stops items growing into mini reports with their own filters and tables.
131
+ - Make a dashboard either fully static or fully configurable; never mix fixed and movable items on one page. Why: Mixed layouts confuse people about what they can change.
132
+ - Keep a dashboard to about seven items and link every chart or list item to the page with the full data. Why: The page must answer its questions in seconds; detail belongs on report and list pages.
133
+ - Give a board item at most one header action and put the rest in its more menu, ordered Preferences first and Remove from dashboard last. Why: Consistent menus let people find Remove and settings in the same place on every item.
134
+ - Provide a keyboard and single-click alternative for every drag on a board or items palette: menu moves, step resizes and an Add to dashboard button. Why: WCAG 2.2 2.5.7 requires it and TwoUX is keyboard-first.
135
+ - Remove dashboard items and reset layouts at once with an Undo toast, never with a confirmation dialog. Why: Both are reversible, so TwoUX's Undo rule applies.
136
+ - Save configurable dashboard layouts on the server per person, never only in localStorage, and never change another person's layout or the workspace default. Why: People expect their layout on every device, and a personal change must not move a colleague's dashboard.
137
+ - Give each dashboard item its own loading, empty and error state inside its frame instead of one page-level spinner or error. Why: One failing source must not hide the numbers that did load.
138
+ - Never disable a form's submit button; keep it enabled and run validation when it is pressed. Why: A disabled submit hides which field is wrong and leaves people stuck.
139
+ - Show every error at the smallest scope that contains it (field, form banner, region error state, page) and never in a toast. Why: Errors far from their cause are missed, and TwoUX toasts disappear after 6 seconds.
140
+ - Ask before discarding unsaved changes only while the form is dirty, register beforeunload only while it is dirty, and autosave drafts of long text instead of asking. Why: Prompts that appear when nothing changed train people to click through the one that matters.
141
+ - Keep every row action also reachable from a selection (bulk bar) and ⌘K, and show at most two quick actions plus a More actions menu on each row. Why: Actions that exist only on one row's hover are missed and can't be applied in bulk.
142
+ - Choose selection controls by rule: up to seven options shown as radios or checkboxes, eight or more in a select, switch only for changes that apply at once. Why: Agents otherwise default to dropdowns everywhere, which hides short option sets.
143
+ - Choose the create surface by size: a dialog for up to three short fields, one page for most records, the Stepper only for more than about 15 main fields or steps that depend on each other. Why: Wizards slow short tasks down and dialogs cannot hold long ones.
144
+ - Never disable a Create or Save changes button for an incomplete form; validate on submit and focus the first error. Why: A disabled button gives no reason and hides what is missing.
145
+ - Put only required fields without a good default, and fields most people need, in the main section; put the rest under a collapsed Additional settings with their defaults filled in. Why: Short forms are finished faster and visible defaults let people create in one step.
146
+ - Build the edit page from the create form component, with the same fields, order and headings. Why: Two forms for one record drift apart and confuse people.
147
+ - Make delete move records to Deleted with Undo; use a confirmation dialog only for permanent deletes, and a typed name only when the permanent delete also removes other records. Why: Friction must match severity or people click through every warning.
148
+ - Never add a sidebar item for a single record, a create page or an edit page; keep the record's type active instead. Why: The sidebar shows where people can go, not where they have been.
149
+ - Put global destinations and utilities in the sidebar and keep the top bar for the breadcrumb and page-level controls. Why: Splitting the same kind of thing across two places makes both harder to find.
150
+ - Announce features only with a New or Beta text label (FeatureLabel: plain in the sidebar via SidebarItem tag, a popover on request after the page title via PageHeader titleAddon), removed after 30 days for New; never with a toast, banner or auto-opening popover. A feature that spans several controls may offer Show me in its popover, which starts a GuideCue of at most three steps. Why: Announcements must not compete with status messages people need to act on; a guide the person starts shows where the feature lives without interrupting anyone else.
151
+ - Never use a hero header, gradient banner or marketing-style title block inside the product. Why: It pushes the work below the fold and draws attention away from the task.
152
+ - **TwoUX only.** TwoUX has one density for the app: never build a density setting, comfortable mode or row height preference. Tables and sheets also offer size="dense" (28px rows) only for spreadsheet-like data (inventories, ledgers, imports, mapping), never as a user preference or app-wide switch. Why: One density keeps every screen consistent; dense rows exist only where people scan many rows of tabular data, as in a spreadsheet.
153
+ - Sign in with SignInOptions: provider buttons first, then a work email that switches to single sign-on when the domain requires it, otherwise sends an email link. Errors go under the field and say what to do next. Why: People pick the method they already use; SSO detection saves a failed attempt; a specific error gets them in.
154
+ - First-run setup is three to five OnboardingStep screens on a plain page: each says why it asks, optional steps say Optional and offer Skip, Continue is never disabled, progress is written as "Step 2 of 5", and Back keeps what was entered. No tours, auto-playing videos or gradient backgrounds; the only in-product guide is GuideCue, one to three steps, started by the person. Why: Short, explained steps get finished; skippable questions respect people's time; text progress is read out by screen readers. Guides people ask for get followed; tours that start on their own get skipped.
155
+ - Connect services with ConnectorPicker and ConnectDialog: say what each connection lets the product do and who it is shared with before connecting, open OAuth in a new window, test API keys before saving and never show them again, and mark expired connections Needs attention with Reconnect. Why: People grant access they understand; a tested key fails at setup, not in the middle of a run.
156
+ - After onboarding, keep a SetupChecklist of three to five useful tasks in the sidebar until done or dismissed, never as a modal. Why: A checklist people can return to finishes setup without interrupting work.
157
+ - Show credits, seats or storage with UsageMeter: used of limit, when it resets and what used it. Warn from 80% and say what stops at the limit; show the upgrade link only then, never a permanent bright button. Show the cost of an action before it runs. Why: People manage what they can see; surprise limits and constant upsell erode trust.
158
+ - Announce what changed on a What's new page or panel opened from the Help menu, with a FeatureLabel on the changed item. Never open it, a changelog modal or a video on load. Why: Updates people ask for get read; ones that interrupt get dismissed unread.
159
+ - Imports show problems before importing and say what happens to bad rows (skipped, or imported with the cell left empty), and the Import button states how many rows it will add. Why: Finding bad rows after an import means cleaning up data that is already in use.
160
+ - Show people where a task's controls are only with GuideCue, opened from something they pressed (SetupChecklist Start, Help menu, HelpPanel link, FeatureLabel Show me), never on load, a timer or hover: one to three steps on real targets, missing targets skipped, no overlay or beacon, Esc closes and focus returns. Why: Pulled guidance is followed and remembered; pushed tours interrupt (WCAG 2.2.4) and are dismissed unread.
161
+
162
+ ## Which component for which job
163
+
164
+ | Job | Use | How | Not this |
165
+ |---|---|---|---|
166
+ | Run the main action of a page or panel | **Button** | `variant="default"`, once per view | a second primary button, a link styled as a button |
167
+ | Run any other action | **Button** | `variant="outline"`, or `"ghost"` in toolbars, rows and bars | primary, link variant |
168
+ | Go to another page | **Button** | `variant="link"` or a plain link | secondary button |
169
+ | Show a keyboard shortcut | **Keyboard shortcut hint** | Button `shortcut` prop, or one `<Kbd>` per key | plain text in brackets |
170
+ | Show code, a command or log output to copy | **Code block** | `<Code>` inside sentences, `<CodeBlock>` for anything longer | Text input |
171
+ | Show the status of a record | **Status badge** | always a word, tone by meaning | a coloured dot alone, Tag, chart colours |
172
+ | Label or categorise a record | **Tag** | | Status badge |
173
+ | Switch between sections of a page | **Tabs (underline)** | | Segmented control |
174
+ | Switch between 2 or 3 views of the same data | **Segmented control** | | Tabs (underline), Dropdown menu |
175
+ | Offer several actions on one record | **Dropdown menu** | | a row of many buttons |
176
+ | Turn a setting on or off, applied immediately | **Switch** | | Checkbox |
177
+ | Pick options in a form that is submitted later | **Checkbox** | | Switch |
178
+ | Explain an icon-only button | **Tooltip** | | title attribute alone, popover |
179
+ | Confirm an action the person just took | **Toast** | with Undo when reversible | Banner (inline alert), Confirmation dialog, Inbox (triage) |
180
+ | Something on the page needs attention | **Banner (inline alert)** | | Toast, Confirmation dialog |
181
+ | Something needs a person to act, later | **Inbox (triage)** | | notification bell list, Toast, email only |
182
+ | Stop before an irreversible action | **Confirmation dialog** | states the consequence, safe option first | Toast, browser confirm() |
183
+ | Show or edit one record next to the list | **Side panel (drawer)** | `mode="push"` by default, `"overlay"` below 1100px | Confirmation dialog, a new page |
184
+ | Show nothing yet, or no results | **Empty state** | | an empty table with no message |
185
+ | Show content while it loads | **Loading skeleton** | | a full-page spinner |
186
+ | Something failed to load | **Error state (failed to load)** | say what failed, keep filters, offer Try again | Toast, Empty state |
187
+ | Find anything or run a command | **Command palette (⌘K)** | `⌘K` | |
188
+ | Scan and triage records | **List table** | | Data grid |
189
+ | Edit, enrich or export many columns | **Data grid** | | List table |
190
+ | Show spreadsheet-like data people scan many rows of, such as an inventory, a ledger or a bill of materials | **Dense table** | `Table size="dense"` with `TableGroupRow`, `TableRowNumber`, frozen columns (`data-pinned`) and `TableFilterRow` | list-table at 36px rows, a density setting |
191
+ | Group a table's rows into sections, such as Inputs, Wastes and emissions and Products | **Dense table** | One `TableBody` per group with `TableGroupRow` (label, info tooltip, count, collapsible); in a sheet, `SheetGrid groupBy` | grouped-list for tabular data |
192
+ | Offer a shortcut button inside a table row, such as Open or Share | **Dense table** | `TableCellAction` with an aria-label naming the row, and the same action in the `TableRowNumber` menu | a hover-only action with no menu item |
193
+ | Let people select ranges, paste from Excel or Google Sheets, fill down and undo cell edits | **Sheet grid** | `SheetGrid` (`size="dense"` for spreadsheet-like data) with `onCellsChange`; `ShortcutSheet` groups from `sheetGridShortcuts()` | Data grid, a custom keyboard handler |
194
+ | Run the usual action with a few variants, such as Import data with Import all and Import selection | **Split button** | `SplitButton` with `menuLabel="More import options"` and `DropdownMenuItem` variants | a Button beside a hand-made menu trigger, two separate buttons |
195
+ | Filter a list by a few fields | **Filter pills and filter bar** | pills: field, operator, value; apply on tick | Filter panel, a filter row under each column |
196
+ | Search with many fields | **Filter panel** | | Filter pills and filter bar |
197
+ | Save a combination of filters, columns and sort | **Saved views** | | |
198
+ | Act on several selected rows | **Bulk action bar** | | a toolbar that replaces the filters |
199
+ | Show one number that matters | **Stat card with comparison** | number, change with arrow and sign, what it compares to | a chart |
200
+ | Show change over time | **Line chart card** | | bar chart for long series, two y-axes |
201
+ | Compare amounts across categories | **Bar chart** | | |
202
+ | Ask the assistant about what is on screen | **Assistant side panel** | `⌘J`; selection and filters become context chips | a floating chat bubble |
203
+ | Have the AI change data | **Suggested changes** | proposal with checkboxes, Apply, then Undo | applying directly, batch Apply for decisions about people |
204
+ | Mark content written by AI | **AI origin label** | | an AI colour, sparkles on every button |
205
+ | Let an agent act on someone's behalf | **Agent permissions** | Off / Ask first / Allow; decisions about candidates are capped at Ask first | Allow on decisions with legal or similar effects on people |
206
+ | Group one settings section or form | **Card** | `Card` with header, content, footer actions on the right; `CardFooter band` for one secondary line | Banner (inline alert) |
207
+ | Divide two ways of doing the same thing | **Separator** | `FieldSeparator` with “or”; plain `Separator` between groups | |
208
+ | Guide a task done in steps, in order | **Stepper** | `Stepper steps current onStepSelect`; 3 to 6 steps | Tabs (underline) |
209
+ | Show how a total splits over time, such as applications by source per week | **Stacked area chart** | `ChartArea` with 2 to 5 `series` stacked from zero, legend toggles, `Table` view | Donut chart, Line chart card |
210
+ | Show a count against its plan or average in the same unit | **Bar and line chart** | `ChartMixed` with one `bar` series and up to three `line` series on one y-axis | Line chart card |
211
+ | Show how one total splits at a single moment into a few parts | **Donut chart** | `ChartDonut` with 2 to 5 `segments`, centre `total` and `unit`, labels as count and share | Stacked area chart, Funnel |
212
+ | See whether two measures move together across listings and spot outliers | **Scatter chart** | `ChartScatter` with up to 3 `groups` (colour plus marker shape), axis titles with units, popover linking to the record | Line chart card |
213
+ | Pick the right chart for a question on a dashboard | **Data visualisation** | Tag the question (trend, anomaly, comparison, investigation), then use the chart-choice step; finish with title, units, `Table` view and four states | |
214
+ | Find out why a chart spiked or dropped on a given day | **Chart drill-down** | Pin the `ChartPopover` on the point, read the breakdown, then "Filter chart" or "Filter page" to add pills to the `FilterBar` | Breakdown table |
215
+ | Mark a target or limit on a chart | **Bar chart** | Add a `threshold` (dashed, neutral, with a text `label`) instead of an extra series | Bar and line chart |
216
+ | Build the team's weekly hiring overview that everyone reads the same way | **Static dashboard** | 12-column grid: `stat-compare` row at full width, then `chart-card-line` and short `list-table` items at 6 columns, getting started and links at the bottom | Configurable dashboard, Board and board item |
217
+ | Let each recruiter choose and arrange what they see on their home page | **Configurable dashboard** | `Board` with `BoardItem`s, Add items in `page-header` opening `items-palette` in `side-panel`, layout saved per person, Reset to default layout in the more menu | Static dashboard |
218
+ | Decide what to put inside a new dashboard tile | **Dashboard items** | Pick one type (key metrics, chart, list, status and alerts, quick links, getting started, feature news); one header action, `dropdown-menu` for the rest, footer "View all N" link | List table |
219
+ | Let someone add a chart back to their dashboard after removing it | **Items palette** | Open Add items; the removed item is listed again; drag it or press its `Add to dashboard` button | Templates gallery, Command palette (⌘K) |
220
+ | Give people a way back after rearranging their dashboard badly | **Configurable dashboard** | `Reset to default layout` in the page header more menu, applied at once with a `toast` offering Undo | Confirmation dialog |
221
+ | Get a different version of the assistant's last answer | **Regenerating an answer** | `AnswerActions` Regenerate on the latest answer; version switch `2 / 2`; Stop replaces Send while writing | Clarifying before acting, Generated table columns and enrichment |
222
+ | Give the person a job description or CSV the assistant made | **Generated drafts and files** | `ArtifactCard` under the answer with `Open`/`Download`; record-bound drafts use `Suggest for LST-…` into `SuggestedChanges` | Data export, Propose, then apply |
223
+ | Collect a closing date and salary band before preparing a new listing | **Asking for details inside the answer** | Inline `Card` with up to five required, prefilled fields and `Continue`, which produces `SuggestedChanges` | Clarifying before acting, Onboarding to an empty workspace |
224
+ | See what an agent did last week and which run changed a listing | **Agent activity log** | `GroupedList` by day with time, `StatusBadge` outcome and past-tense label linking to the `AgentRun` step; `FilterBar` by agent and outcome | Showing reasoning and progress |
225
+ | Turn an agent on or off and limit which listings it touches | **Managing agents** | Agents page `ListTable` with `Switch` (Undo toast) and row detail in `SidePanel` showing `AgentPermissions` and scope | Agents acting on your behalf, Connected tools |
226
+ | Let a person approve a tool call the agent needs mid-conversation | **Agents acting on your behalf** | Approval card above `MessageComposer`: `Allow once` / `Allow in this conversation` / `Always allow`, focus on heading, resolved line afterwards | Confirmation dialog, Propose, then apply |
227
+ | Explain why an action can't be used right now | **Disabled and read-only states** | `Button aria-disabled` with `Tooltip` reason "Available when the listing is Live."; hide it if the role can never use it | Contextual help |
228
+ | Let people reorder pipeline stages or columns | **Drag and drop** | Grip handle plus keyboard pick-up (Enter, arrows, Enter) and `DropdownMenu` items Move up / Move down | Board and board item |
229
+ | Tell people a save, load or action failed | **Error messages** | Field: `FormField error`; form: `Banner variant="error"` above actions; region: `ErrorState` with Try again | Toast, Empty state |
230
+ | Explain a field or concept that needs more than a label | **Contextual help** | Info link beside the label opens `HelpPanel topic="visa-sponsorship"` in the right slot | Tooltip, Assistant side panel |
231
+ | Decide which right-hand panel to use | **Secondary panels: which right-hand panel** | Record: `SidePanel`; questions about data: `AssistantPanel`; guidance: `HelpPanel`; one open at a time | Confirmation dialog |
232
+ | Ask people whether a help topic or report was useful | **Collecting product feedback** | `FeedbackPrompt question="Was this helpful?"` at the end of the content, follow-up revealed after the vote | Labelling AI output |
233
+ | Stop people losing a half-written listing | **Unsaved changes** | Autosave drafts with `Timestamp` "Draft saved"; `ConfirmationDialog` "Discard changes?" only when dirty; `beforeunload` while dirty | Undo and destructive actions |
234
+ | Show when something happened or is due | **Timestamps** | `Timestamp format="relative"` in tables, `format="absolute"` in details and deadlines, `by` for the source | |
235
+ | Place actions for a page, a selection and a single row | **Page actions and row actions** | `PageHeader actions` (one primary, last), `BulkActionBar` for selections, row icon buttons plus `DropdownMenu` More actions | Selection and bulk actions |
236
+ | Pick between radio, checkbox, switch and select | **Choosing a selection control** | Up to 7 options: `RadioGroup` or `Checkbox` group; 8+: select; immediate on/off: `Switch` | Segmented control |
237
+ | Add a new job listing | **Creating a record: dialog, single page or steps** | `Create listing` in the `page-header` opens a single page with `card` sections, defaults filled in and `Additional settings` collapsed; never disable the submit `button`. | Stepper, Confirmation dialog |
238
+ | Publish a listing to external job boards | **Creating a record: dialog, single page or steps** | Use the `stepper` with 3 to 5 steps ending in a Review step whose `Edit` links return to each step. | Side panel (drawer) |
239
+ | Add a location that does not exist yet while creating a listing | **Creating a record: dialog, single page or steps** | Offer `Create "Leeds office"` in the select, or open an overlay `side-panel`; select the new item and return focus to the field. | Confirmation dialog |
240
+ | Change the salary and location of a listing | **Editing a record: inline, section or whole page** | Section `Edit` in the `card` header turns the section into a form with `Save` and `Cancel`; `toast` "Listing updated. Undo". | Inline editing and validation |
241
+ | Change the stage of many candidates | **Inline editing and validation** | Edit the cell in the `data-grid` or use the `bulk-action-bar`; Undo in the `toast`. | Editing a record: inline, section or whole page |
242
+ | Delete a duplicate candidate record | **Deleting records** | Move to Deleted at once with `toast` "Candidate deleted. Undo" and ⌘Z; no dialog. | Confirmation dialog |
243
+ | Erase a candidate's data on request | **Deleting records** | `confirmation-dialog` with role `alertdialog`, the name in bold, what is erased and what stays, buttons `Keep candidate` and `Delete permanently`. | Toast |
244
+ | Delete a whole workspace or a team with live listings | **Deleting records** | `confirmation-dialog` plus a warning `banner` listing what else goes and a `text-input` where the person types the name. | Undo and destructive actions |
245
+ | Decide where a new area of the product goes in the navigation | **Navigation: what goes in the sidebar and the top bar** | Add an item to the `app-shell` sidebar only if people go there directly; keep the `breadcrumb` and sidebar labels identical. | Page header |
246
+ | Tell people about a new Reports page | **Announcing new and beta features** | `New` text label after the sidebar item, opening a popover with two sentences and Learn more; remove after 30 days. | Toast, Banner (inline alert), Status badge |
247
+ | Mark an AI feature as beta | **Announcing new and beta features** | `FeatureLabel kind="Beta"` in the sidebar (`SidebarItem tag`) and after the page title (`PageHeader titleAddon`), popover saying results may change, plus Send feedback; still label output per `labelling-ai-output`. | Tag, Status badge |
248
+ | Agree a multi-step or costly run before it starts | **Plan preview** | `PlanCard` with removable steps and risk marks; approval starts the `AgentRun`; a mid-run change adds `PlanChange`. | Suggested changes, Confirmation dialog |
249
+ | Review a change an agent proposes to procedures, prompts, tools or another agent | **Change review** | `ChangeRequest` with reason, `AiOrigin`, `DiffView` and `SimulationResults`; Approve, or Reject with a reason; list open ones in the Inbox. | Suggested changes, alert-dialog |
250
+ | Tell people the agent is unsure | **Confidence note** | `ConfidenceNote` with the cause in words and a safer option or a way to check; ask first when the scope of a change is unclear. | alert, Toast, badge |
251
+ | Explain why the agent chose something | **Why this choice** | `WhyChoice` next to the choice: factors, options that lost, anything it couldn't meet, then Change this or Keep it. | Tooltip, Help panel |
252
+ | Let people sign in with Google, Microsoft, SSO or email | **Sign in** | `SignInOptions` with `providers` and `ssoDomains`; errors under the email field. | Confirmation dialog, text-field |
253
+ | Set up a new account in a few steps | **Onboarding step** | Three to five `OnboardingStep`s; optional ones with Skip; then a `SetupChecklist` in the sidebar. | Stepper, Confirmation dialog |
254
+ | Upload a profile picture, logo or document | **File drop** | `FileDrop` with `accept`, `hint` and `maxBytes`; preview once chosen. | Empty state |
255
+ | Connect Google, Slack, a CRM or another service | **Connector picker** | `ConnectorPicker` with what each connection can do; `ConnectDialog` for OAuth or an API key test. | Connected tools, Agent permissions |
256
+ | Show credits, seats or storage against a limit | **Usage meter** | `UsageMeter` with used, limit, unit and reset date; upgrade link appears from 80%. | Stat card with comparison, badge |
257
+ | Show a third-party service's logo | **Provider logo** | `ProviderLogo provider="google"` beside its name; add new ones in scripts/provider-logos.mjs. | Avatar and avatar stack, Tag |
258
+ | Show how one total splits at one moment, in a line of space | **Share bar** | `ShareBar` with up to 6 `parts`; the rest fold into grey Other; `shareTable` for the table view | Donut chart, a pie chart |
259
+ | Rank items by one measure beside a stacked chart, as its legend | **Ranked list** | `RankedList` with `colorIndex` matching the chart's series, change with arrow and sign | ChartLegend plus a second list, List table |
260
+ | List prices, indices or rates with today's change | **Change list** | `ChangeList` with name, code, value and unit, change, optional `spark`, and `seeAll` | a stat tile per instrument, colour without arrow and sign |
261
+ | Show a price moving within a narrow range today | **Price chart** | `PriceChart` over the whole session with `reference` (previous close) and `live`; the axis says when it does not start at zero | Line chart card, a line chart cropped without saying so |
262
+ | Explain how an opening amount became a closing amount | **Waterfall chart** | `Waterfall` with `total` steps in grey and changes in c1 and c2 with + and − labels | green and red bars, stacked bar |
263
+ | Show actual against target for a few measures | **Bullet chart** | `BulletChart` rows with `value`, `target` and neutral `bands` | a gauge, a dial, a donut |
264
+ | Show which of many items make up most of a total | **Treemap** | `Treemap` with up to 12 `items`, optional `group` for colour and legend | chart-donut with many slices, colour by value |
265
+ | Show how a quantity flows across two or three stages | **Sankey chart** | `SankeyChart` with `nodes` and `links`; `sankeyTable` for the table view | Funnel, more than three columns |
266
+ | Show how one set of values is spread | **Histogram** | `Histogram` with `binValues(values, { binWidth })` and an optional median `marker` | an average alone, chart-bar of categories |
267
+ | Compare how spread out several groups are | **Box plot** | `BoxPlot` with raw `values` per group on one shared axis | averages in a bar chart, one histogram per group |
268
+ | Show daily open, high, low and close for a traded price | **Candlestick chart** | `CandlestickChart` with up hollow and down filled; volume as its own panel; `colors="market"` and `showLast` on trading screens | colour as the only sign of direction, volume on a second y axis |
269
+ | Show the prices people are offering to buy and sell at, and let them pick one | **Order book** | `OrderBook` with `asks`, `bids`, `steps` and `onSelectPrice` filling the order form's limit price | a list table of orders, colour as the only sign of side |
270
+ | Build a table whose columns are looked up, calculated or written per row | **Sheet grid** | `SheetGrid` with typed `columns` and computed cells in `rows[].computed`; `RunStatusBar` under it | Data grid, List table |
271
+ | Show, hide or reorder the columns of a sheet or list table | **Columns menu** | `ColumnsMenu` in the table toolbar; applies at once, with keyboard and Move buttons for reordering; on list tables add `onWrapChange` and `onPageSizeChange` | Confirmation dialog |
272
+ | Show what a sheet is running, how far it is and what it costs | **Run status bar** | `RunStatusBar` with done, total, creditsUsed, costPerRow and onStop; Auto-run states its cost per row | Usage meter, Agent run timeline |
273
+ | Import rows from a CSV file | **CSV import** | `CsvImport` with the table's `targets`: map, read the problem summary, then Import with the row count | File drop |
274
+ | Match fields from a file, form or service to a table's fields | **Field mapping** | `FieldMapping` with `targets`, `sources` and `autoMapFields`; required marked, type mismatches warned | Columns menu |
275
+ | Add a looked-up, AI, formula or export column to a sheet | **Action catalogue** | `ActionCatalogue` in a `SidePanel` titled Add column; cost per row, then the total before adding, test on 10 rows by default | Items palette, Templates gallery |
276
+ | Set how a table handles duplicates, empty rows and template sharing | **Table settings** | `TableSettings` in the side panel slot, saved with Save; asks before discarding only when changed | Confirmation dialog |
277
+ | Show where something happens when location itself matters, such as conversion rate by country or ARR by city | **Map chart** | `MapChart` with your TopoJSON and `values` as a rate (five steps, No data hatched), or `markers` for raw amounts; `mapTable` for the Table view | Bar chart or Ranked list to compare amounts, raw counts as shading |
278
+ | Show someone where the controls for a task are, after they ask | **Guide cue** | `GuideCue` with 1 to 3 `steps` (target ref or data attribute, title, body), opened from a `SetupChecklist` Start, Help menu, `HelpPanel` link or a `FeatureLabel` Show me via `useGuide().start` | a product tour on load, an auto-opening popover, a dimmed spotlight overlay |
279
+ | See releases, maintenance windows or campaign phases across services or teams on one time scale | **Timeline** | `Timeline` with `tracks`, `start`, `end` and `now` inside `ChartFrame` with `timelineTable`; `onSelect` opens the record in `SidePanel` | List table, Line chart card, Agent activity log |
280
+ | Show how much of a few fixed limits is used, such as seats, credits and storage, in a small card | **Radial bars** | `RadialBars` with 1 to 4 `items` ({ label, value, limit, unit }), used of limit written beside the rings, `radialBarsTable` for the table view | Bullet chart for actual against target, a gauge or dial, Donut chart for parts of one total |
281
+ | Show how a measure rises and falls through a repeating cycle, such as support tickets by hour of day | **Radial lines** | `RadialLines` with `periods` for one full cycle and 1 to 3 `series` (null for gaps), `periodLabel`, `radialLinesTable` for the table view | Line chart card for time that does not repeat, Heatmap for a cycle against a second dimension, an area fill that paints gaps as zero |
282
+ | Book and rearrange interviews, shifts or rooms across a few people on a calendar | **Scheduler** | `Scheduler` with `resources`, `view`/`onViewChange` and `date`/`onDateChange`; `onSelectEvent` opens `SidePanel`, `onCreate` opens a dialog of up to three fields, `onMove` applies with an Undo `toast` | List table, Timeline, Board and board item |
283
+ | Set a date on a record, such as a closing date or start date | **Date picker** | `DatePicker` with `label`, ISO `value` and `onValueChange`; typing dd/mm/yyyy is the main path, Alt+↓ or the calendar button the second; `min`, `isDateUnavailable` and `unavailableReason` say which dates can't be chosen | Text input, Scheduler |
284
+ | Filter a list or chart to a period, such as the last 30 days or last quarter | **Date picker** | In a filter bar, `DateFilterPill` beside `FilterPill` ("Applied is in Last 30 days"); in a form or chart header, `DateRangePicker` with `presets`. Store the value with `dateFilterToValues` in the URL and saved views, and get the dates with `resolveDateRange` | Segmented control, Text input |
285
+ | Pick one or several values from a list of eight or more, such as a location or skills | **Combobox** | `Combobox` with `options` (add `multiple` for several); `onCreate` offers Create "Leeds office"; server search with `filter={null}`, `onSearch`, `loading` and `loadError` | Radio, Checkbox, Filter pills and filter bar, Command palette (⌘K) |
286
+ | Enter several free values that don't come from a list, such as email addresses to invite | **Tag input** | `TagInput` with `validateValue` and `noun`; pasted lists are split, duplicates are reported and invalid values stay marked with their reason | Combobox, Text input, Tag |
287
+ | Keep several regions of a tool page in view and let people resize and rearrange them, such as a trading screen | **Pane layout** | `PaneLayout` with `value`, `onValueChange`, `panes` and `onReset` inside `AppShell frame="flush"`; `usePaneSize` sizes charts and lists to their pane | a page that scrolls past regions people need together, a hand-built grid of fixed cards |
288
+
289
+ ## Patterns: how whole flows work
290
+
291
+ Read the pattern page before building any of these flows, and follow its steps in order.
292
+
293
+ - **Filtering and search** (`docs-md/filtering-search.md`): Narrow a list to the rows that matter with filter pills that apply as you tick, show counts, and live in the URL.
294
+ - **Saved views** (`docs-md/saving-views.md`): Store a filtered, sorted, column-chosen list under a name so people and teams return to it in one click.
295
+ - **Selection and bulk actions** (`docs-md/selection-bulk-actions.md`): Pick rows with X or checkboxes, then act on all of them from one bar above the table that says how many rows it will touch.
296
+ - **Inline editing and validation** (`docs-md/inline-editing-validation.md`): Edit values where they are shown, check each field when the person leaves it, and summarise every problem on submit.
297
+ - **Empty, loading and error states** (`docs-md/empty-loading-error.md`): One rule set for the three states every view has before or instead of data: loading, nothing to show, and failed.
298
+ - **Undo and destructive actions** (`docs-md/undo-destructive.md`): Decide between Undo after the fact and a confirmation before it, using one test: can the action be reversed, and who else does it reach?
299
+ - **Notifications: inbox, bell, toast or email digest** (`docs-md/notification-channels.md`): Route every message by one question: does it need this person to act? Things that need you go to the Inbox; your own results go in a toast; nothing gets a separate bell list.
300
+ - **Record detail: side panel, overlay or full page** (`docs-md/record-detail.md`): Open a record in a side panel that pushes the list by default, overlay it on narrow or wide-content pages, and go to the full page for deep work.
301
+ - **Keyboard-first navigation** (`docs-md/keyboard-navigation.md`): Every action has a key shown on its button. J/K move, Enter opens, Esc steps back one layer at a time, ⌘K runs anything, ⌘J asks the assistant.
302
+ - **Data export** (`docs-md/data-export.md`): One Export menu on every table: choose what to include first, then the format, then copy instead of download if you want.
303
+ - **Comparison over time** (`docs-md/period-comparison.md`): Every headline number says what it compares against: this period vs the previous period of the same length, with arrow, sign and colour.
304
+ - **Onboarding to an empty workspace** (`docs-md/workspace-onboarding.md`): A new workspace shows a short setup checklist in the sidebar and empty states that each offer one way in: create, import or start from a template.
305
+ - **Ask about what's on screen** (`docs-md/ask-on-screen.md`): ⌘J or Ask opens the assistant beside the data with the current selection and filters as removable context chips, so the scope of every answer is visible.
306
+ - **Propose, then apply** (`docs-md/propose-apply.md`): The assistant never edits on its own: it lists suggested changes with checkboxes, the person applies them in one step, each change shows its progress, and Undo reverses all of it.
307
+ - **Showing reasoning and progress** (`docs-md/reasoning-progress.md`): While working, say the current step in words with a running timer and a Stop; when done, collapse to "Thought for 2.1s · 4 steps" that opens on request.
308
+ - **Clarifying before acting** (`docs-md/clarify-before-acting.md`): When the answer would change the result, ask with a question card above the composer: options with a recommended default, number keys, Skip and Next.
309
+ - **Citing sources** (`docs-md/citing-sources.md`): Every claim in an answer links to the record it came from by ID; clicking opens the record in the side panel, and the full page lists every record used.
310
+ - **Labelling AI output** (`docs-md/labelling-ai-output.md`): Mark generated content with one small origin mark next to it. No AI colour, no sparkle on every button, no "AI-powered" copy.
311
+ - **Agents acting on your behalf** (`docs-md/agents-on-behalf.md`): Agents work within permissions set per action (Off, Ask first, Allow), show every run as a list of steps, stop to wait for you through the Inbox, and can always be stopped.
312
+ - **Generated table columns and enrichment** (`docs-md/generated-columns.md`): Add an AI column, test it on three rows, see the cost per row, then run it with progress and Stop. Each cell shows its own state and cites its record.
313
+ - **Saved tasks and schedules** (`docs-md/saved-tasks-schedules.md`): Turn repeated requests into a task sentence with editable slots, test it once, then save it and optionally run it on a schedule.
314
+ - **Data visualisation** (`docs-md/data-visualisation.md`): Start from the question the person is asking, pick the one chart that answers it, give it a noun title, units and a period, and ship it with a table view and its four states.
315
+ - **Chart drill-down** (`docs-md/chart-drill-down.md`): Select a point on a chart to see what makes it up, then narrow the chart or the whole page to that point, with every applied filter shown as a pill you can remove.
316
+ - **Static dashboard** (`docs-md/static-dashboard.md`): A fixed overview page where the team sees the same items in the same order, most important first, answering the day's questions at a glance.
317
+ - **Configurable dashboard** (`docs-md/configurable-dashboard.md`): A personal overview where each person adds, removes, moves and resizes items on a board, with an items palette to add from, a saved layout and a reset to the default.
318
+ - **Dashboard items** (`docs-md/dashboard-items.md`): The catalogue of item types a dashboard is built from, such as key metrics, charts, short lists, alerts, quick links, getting started and feature news, and what each one should contain.
319
+ - **Regenerating an answer** (`docs-md/regenerating-answers.md`): Regenerate reruns the same question with the same context and replaces the latest answer, keeping the earlier version one step away. It never touches changes already applied.
320
+ - **Generated drafts and files** (`docs-md/generated-drafts-files.md`): Show what the assistant makes (a job description, a CSV, a chart) as a card under the answer. Short things are read and copied in place; long drafts open on the assistant page. Anything that would change a record goes through Suggested changes.
321
+ - **Asking for details inside the answer** (`docs-md/inline-input-in-answer.md`): When the assistant knows what to do but needs a few values to do it, it asks with a short form card in the thread, prefilled from context. Submitting the form produces a proposal, not a change.
322
+ - **Agent activity log** (`docs-md/agent-activity-log.md`): A chronological list of what agents and the assistant did across runs: time, an icon with a word for the outcome, a past-tense label that links to the run or message, grouped by day.
323
+ - **Managing agents** (`docs-md/managing-agents.md`): One Agents page lists every agent with its source, what it does, whether it is on and where it may act. People turn agents on and off with Undo, edit scope in the side panel, and agents are never switched off or deleted without someone choosing to.
324
+ - **Disabled and read-only states** (`docs-md/disabled-read-only.md`): Show an action as unavailable only when the person can do something about it, say why in one sentence, and show values they can't change as read-only rather than greyed out.
325
+ - **Drag and drop** (`docs-md/drag-and-drop.md`): Dragging is a shortcut, never the only way: every drag in TwoUX has a keyboard path and a menu path that do the same thing.
326
+ - **Error messages** (`docs-md/error-messages.md`): Put every error where it happened, at the smallest scope that contains it, and say what went wrong and what to do next in plain words.
327
+ - **Contextual help** (`docs-md/help-system.md`): Answer "what is this, why does it matter, how do I choose" in three steps of depth: the words on the screen, a help panel opened from an Info link, and a help centre article in a new tab.
328
+ - **Secondary panels: which right-hand panel** (`docs-md/secondary-panels.md`): TwoUX has one right-hand panel slot. Record detail, the assistant, help and filters each have a clear job, only one is open at a time, and none is ever required to finish a task.
329
+ - **Collecting product feedback** (`docs-md/user-feedback.md`): Ask "Was this helpful?" in a quiet spot after people have read or used something, record the Yes or No straight away, then offer one short optional question.
330
+ - **Unsaved changes** (`docs-md/unsaved-changes.md`): Don't let people lose work by accident: save drafts of long text automatically, and ask before discarding a changed form only when there really are changes.
331
+ - **Timestamps** (`docs-md/timestamps.md`): Show when things happened as relative time in lists ("3 hours ago"), the exact date and time on hover and in record details, and always say what the time refers to and who caused it.
332
+ - **Page actions and row actions** (`docs-md/actions.md`): Actions that affect the page or many records sit in the page header or the bulk action bar; one or two frequent actions also sit on each row, and every row action is reachable from the selection too.
333
+ - **Choosing a selection control** (`docs-md/choosing-selection-control.md`): Pick the control from three questions: one choice or many, how many options, and does it apply at once or on Save.
334
+ - **Creating a record: dialog, single page or steps** (`docs-md/create-record.md`): Pick the creation surface by how much people must decide: a small dialog for a name or two, one page for most records, steps only for long or high-stakes set-ups. Fill everything else with visible defaults.
335
+ - **Editing a record: inline, section or whole page** (`docs-md/edit-record.md`): Change one value where it is shown, one section in place, or many linked settings on an edit page that mirrors the create form. Every saved edit can be undone.
336
+ - **Deleting records** (`docs-md/delete-record.md`): Deleting moves records to Deleted with Undo. Only permanent or cascading deletes ask first, and only the rare, severe ones ask people to type the name.
337
+ - **Navigation: what goes in the sidebar and the top bar** (`docs-md/navigation.md`): The sidebar holds where you can go and the few things you always need; the top bar holds where you are and what this page does. Records never become sidebar items.
338
+ - **Announcing new and beta features** (`docs-md/announcing-features.md`): Mark new or beta things where people meet them, with a small text label that opens a short explanation. Keep a What's new list for the rest. Never use toasts or banners for announcements.
339
+
340
+ ## Tasks
341
+
342
+ These are the things you'll be asked to do. Claude Code has them as skills (/twoux-build, /twoux-design, /twoux-write, /twoux-audit); in other tools, follow the steps here.
343
+
344
+ - **Build** a page, feature or interaction: restate the request as jobs; find the pattern, then the component for each job (job table above); read each page (When not to use, Behaviour, Accessibility, Keyboard, API); plan regions, states (loading, empty, no results, error, disabled or read-only) and shortcuts; write the copy from `docs-md/writing.md` and `docs-md/voice-and-tone.md`; build with `@twoux/ui` only; then lay out and finish it as good UI (/twoux-design): reading order from the job, hierarchy from TwoUX type, spacing and elevation, no lazy defaults (nested cards, card grids as structure, eyebrow labels, decoration), rendered and checked at 1280, 768 and 320px in light and dark; run `npx twoux check`.
345
+ - **Audit** existing UI: run `npx twoux check`; for each region check the job, the pattern steps, the states, actions (one primary, Undo vs confirm), content against writing and voice-and-tone, AI rules and WCAG 2.2 AA; report by severity (blocks people, drift, polish) with the TwoUX page behind each fix.
346
+ - **Improve** (audit, then fix): fix in app code with TwoUX components and props, never by editing TwoUX; re-run the check.
347
+ - **Audit an app not built with TwoUX** (`twoux init --principles`): apply only rules not marked TwoUX only, fix with the app's own components, tokens and brand, change behaviour, structure and words but not the look of anything you rebuild, never import TwoUX components piecemeal; run `npx twoux check --principles`, type-check and render each changed screen before reporting.
348
+ - **Migrate** an app onto TwoUX: follow `docs-md/migrating.md` in order (platform, init, theme, token owners, raw colours, adapters, codemod, screen by screen, CI); propose each step and apply only what the team approves.
349
+ - **Missing something?** Use the closest existing component and ask for the addition; don't build a local one-off.
350
+
351
+ ## Files
352
+
353
+ - `llms.txt`: index of every page.
354
+ - `llms-full.txt`: every page in one file.
355
+ - `docs-md/<id>.md`: one page per foundation, component and pattern, with guidance and real example code.
356
+ - `packages/ui/src/styles/twoux.css`: all tokens (installed: `node_modules/@twoux/ui/src/styles/twoux.css`).
357
+ - `twoux.theme.json`: the one place to change brand colour, corners and font (TwoUX repo: `packages/ui/theme.json`).
358
+ - `npx twoux find "<job>"` and `npx twoux docs <id>`: the job table and any page from the terminal. The same lookups are MCP tools (`find_component`, `get_doc`, `list_docs`, `get_rules`, `check`) when the `twoux` MCP server is connected.
@@ -0,0 +1,49 @@
1
+ # Accessibility
2
+
3
+ TwoUX targets WCAG 2.2 level AA on every component and view. Keyboard is a first-class input, focus is always visible and always managed, and single-key shortcuts can be turned off.
4
+
5
+ Kind: foundation · Group: Key principles
6
+
7
+ ## Principles
8
+
9
+ - Everything works from the keyboard. All functionality is operable through a keyboard interface.
10
+ - Focus is never lost and never hidden. It is always visible, moves in a logical order, and returns where it came from.
11
+ - Colour is never the only cue.
12
+ - Accessibility lives in components. Teams get it by using components and following their guidance: semantic markup and appropriate ARIA attributes.
13
+
14
+ ## Guidelines
15
+
16
+ - Focus ring: every focusable element uses :focus-visible with --ring (a 2px --surface gap and a 2px accent ring). Removing focus indicators is catastrophic for keyboard users.
17
+ - Dialogs: focus moves into the dialog, Tab stays inside, Esc closes, focus returns to the element that opened it.
18
+ - Side panel and popovers: focus moves to the first useful control on open and back to the row or trigger on close. If the trigger is gone, focus moves somewhere logical, such as the next row.
19
+ - After deleting or closing rows, focus goes to the next row, so screen reader users notice the list changed.
20
+ - Lists and grids use one tab stop with arrow keys or J and K inside (roving tabindex or aria-activedescendant).
21
+ - Status messages (saved, closed 3 listings, AI finished) are announced through role=status without moving focus.
22
+ - Sticky headers, the bulk bar and the overlay side panel must not fully cover the focused element.
23
+ - Targets are at least 24 by 24 CSS px or spaced so they do not crowd.
24
+ - Errors say what is wrong and how to fix it.
25
+
26
+ ## Accessibility
27
+
28
+ - Single-character shortcuts (J, K, X, C, E, F, T, D) can be turned off in the shortcut sheet; ⌘ shortcuts stay on. This meets 2.1.4, which requires that character-only shortcuts can be turned off, remapped or limited to focus.
29
+ - Text contrast 4.5:1, large text and non-text 3:1.
30
+ - Reflow at 320 CSS px; tables scroll in their own container.
31
+ - Reduced motion removes all animation.
32
+
33
+ ## Do
34
+
35
+ - Test every new component with keyboard only before review.
36
+ - Return focus to the triggering row when the side panel closes.
37
+
38
+ ## Don't
39
+
40
+ - Do not remove outlines without replacing them with --ring.
41
+ - Do not move focus for info messages; announce them.
42
+ - Do not ship a shortcut that only works with a mouse nearby.
43
+
44
+ ## Related
45
+
46
+ - Keyboard model
47
+ - Colours
48
+ - Motion
49
+ - Writing
@@ -0,0 +1,81 @@
1
+ # Action catalogue
2
+
3
+ A searchable list, in the side panel, of actions that add a column: look-ups from other services, AI, formulas and exports, each with a one-line description and its cost per row. Choosing one opens a short set-up with the estimated total.
4
+
5
+ Kind: component · Group: Data · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - To add a computed column to a sheet.
10
+
11
+ ## When not to use
12
+
13
+ - For adding a dashboard item. Use the Items palette.
14
+ - For templates of whole tables. Use the Templates gallery.
15
+
16
+ ## Structure
17
+
18
+ 1. Search
19
+ 2. Tabs: Suggested, Enrichment, AI, Formulas, Exports, with counts
20
+ 3. Action: logo or icon, name, description, cost per row
21
+ 4. Set-up: column name, inputs, Run after adding (test, all, not yet), estimated total, Add column
22
+
23
+ ## Guidelines
24
+
25
+ - State the cost per row on every action, and the total for the current rows before adding.
26
+ - Default to testing on the first 10 rows when an action costs credits.
27
+ - Show the service's logo with ProviderLogo when an action uses one; otherwise a plain icon.
28
+ - Search covers every category; tabs group the rest.
29
+
30
+ ## Content
31
+
32
+ - Cost: "≈ 0.5 credits / row"; total: "About 1,000 credits for 2,000 rows".
33
+ - The button says what happens: "Add column and test on 10 rows".
34
+
35
+ ## Accessibility
36
+
37
+ - Each action is a button whose name includes its cost.
38
+ - Back to the list returns focus to the action chosen.
39
+
40
+ ## Keyboard
41
+
42
+ | Keys | Action |
43
+ |---|---|
44
+ | Tab | Move through actions |
45
+ | Enter | Open an action's set-up |
46
+
47
+ ## Examples
48
+
49
+ ### add-column
50
+
51
+ ```tsx
52
+ import { ActionCatalogue, type CatalogueAction, toast } from "@twoux/ui";
53
+ import { AtSign, PenLine, Sigma, Tags } from "lucide-react";
54
+
55
+ export const meta = { title: "Add a column to 2,000 rows", description: "Search or pick a category, choose an action, then set it up. Paid actions test on 10 rows by default; the total for every row is shown before you add.", order: 1 };
56
+
57
+ const ACTIONS: CatalogueAction[] = [
58
+ { id: "email", name: "Find work email", description: "Looks up the person's work email in HubSpot from their name and company domain.", category: "Enrichment", suggested: true, provider: "hubspot", costPerRow: 0.5, inputs: [{ id: "domain", label: "Company domain column", options: ["Company domain", "Company"] }] },
59
+ { id: "account", name: "Company details from Salesforce", description: "Industry, headcount and account owner from the matching account.", category: "Enrichment", provider: "salesforce", costPerRow: 0.5 },
60
+ { id: "summary", name: "Summarise role", description: "One sentence on what the person does and whether they buy tools.", category: "AI", suggested: true, icon: <PenLine />, costPerRow: 1 },
61
+ { id: "industry", name: "Classify industry", description: "Puts each company into one of your industries, with the reason.", category: "AI", icon: <Tags />, costPerRow: 0.5 },
62
+ { id: "combine", name: "Combine columns", description: "Joins two or more columns with a separator you choose.", category: "Formulas", suggested: true, icon: <Sigma />, costPerRow: 0 },
63
+ { id: "domain", name: "Domain from email", description: "Takes the part after @ from an email column.", category: "Formulas", icon: <AtSign />, costPerRow: 0 },
64
+ { id: "sheet", name: "Add to a Google Sheet", description: "Appends each row to a sheet you choose and keeps it in step.", category: "Exports", provider: "google-sheets", costPerRow: 0 },
65
+ ];
66
+
67
+ export default function Example() {
68
+ return (
69
+ <div className="w-full max-w-md rounded-sm border border-line p-4">
70
+ <ActionCatalogue actions={ACTIONS} rowCount={2000} onAdd={(c) => toast.success(`Added “${c.columnName}”`, { description: c.run === "test" ? "Testing on 10 rows." : c.run === "all" ? "Running on 2,000 rows." : "Not run yet." })} />
71
+ </div>
72
+ );
73
+ }
74
+ ```
75
+
76
+ ## Related
77
+
78
+ - Sheet grid
79
+ - Run status bar
80
+ - Items palette
81
+ - Prompt editor with fields