@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,293 @@
1
+ # Button
2
+
3
+ Starts an action on the current page, such as saving, exporting or opening a menu.
4
+
5
+ Kind: component · Group: Actions and inputs · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - To start an action on the current page: New listing, Export, Save view.
10
+ - To open a menu or popover of more actions, with a chevron on the right.
11
+ - For the one step most people take next in a view, using the primary style.
12
+ - As an icon-only ghost button for frequent, well-known row actions where space is tight.
13
+
14
+ ## When not to use
15
+
16
+ - To go to another page or URL. Use a link (button-link style) instead.
17
+ - To switch between views of the same data. Use the Segmented control.
18
+ - To turn a setting on or off. Use a Switch, not a button whose label flips.
19
+ - For a long set of secondary actions on one object. Group them in a Dropdown menu.
20
+
21
+ ## Structure
22
+
23
+ 1. Container
24
+ 2. Icon (optional)
25
+ 3. Label
26
+ 4. Shortcut hint (optional)
27
+ 5. Chevron (menu buttons only)
28
+
29
+ ## Guidelines
30
+
31
+ - Seven variants, using shadcn names: default (the primary), outline (white with a light border), secondary (grey fill), ghost (no fill until hover), warning (risky but reversible, a TwoUX addition), destructive (red, inside a confirmation) and link. Pick by importance in the view, not by looks.
32
+ - Only one primary button per view. In a dialog or side panel with its own task, that container may have its own primary.
33
+ - Four sizes: 24px inside rows, 28px in toolbars and filter bars, 32px by default, 36px only for the single action of an empty state or sign-in page. Icon-only buttons are square at the same height.
34
+ - States: default, hover, focus (2px primary ring with a 2px white gap), pressed, disabled (45% opacity), loading.
35
+ - Avoid disabled buttons in forms. Keep Publish pressable and show what is missing through validation.
36
+ - When a button must be disabled, give the reason in a tooltip or nearby text.
37
+ - While an action runs, use loading: the spinner replaces the leading icon, the button ignores clicks and stays focusable, so it cannot be pressed twice and keyboard users keep their place.
38
+
39
+ ## Content
40
+
41
+ - Start with a verb and say what happens: Publish listing, Export 2 rows, Close listings.
42
+ - Sentence case, no full stop, no articles: Save view, not Save The View.
43
+ - Two to four words. Add the object for destructive actions: Delete listing, not Delete.
44
+ - Add an ellipsis when the action needs more input before it runs: Extend to a date…
45
+ - Never OK or Yes in a dialog. Name both outcomes: Close listings and Keep open.
46
+
47
+ ## Accessibility
48
+
49
+ - Use a native button element. Enter and Space activate it.
50
+ - Icon-only buttons need an aria-label naming the action, plus a tooltip showing the same words.
51
+ - The accessible name must contain the visible label so voice users can say what they see.
52
+ - Focus ring and secondary border need at least 3:1 against the background; label text at least 4.5:1, white on primary included.
53
+ - The 28px small button meets the 24px minimum target. Do not shrink icon buttons below 24px.
54
+ - Menu buttons set aria-haspopup and aria-expanded.
55
+
56
+ ## Keyboard
57
+
58
+ | Keys | Action |
59
+ |---|---|
60
+ | Enter / Space | Activate the focused button |
61
+ | Shortcut shown on the button | Run the action from anywhere in the view |
62
+
63
+ ## Examples
64
+
65
+ ### disabled
66
+
67
+ ```tsx
68
+ import { Button } from "@twoux/ui";
69
+
70
+ export const meta = {
71
+ title: "Disabled",
72
+ description: "Prefer leaving the button enabled and explaining what is missing when pressed. Disable only when the reason is visible next to it.",
73
+ order: 6,
74
+ };
75
+
76
+ export default function Example() {
77
+ return (
78
+ <div className="flex flex-col items-start gap-1.5">
79
+ <Button variant="default" disabled>
80
+ Run task
81
+ </Button>
82
+ <span className="text-sm text-bad">Choose who gets the titles before you run this.</span>
83
+ </div>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ### icon-only
89
+
90
+ ```tsx
91
+ import { Button } from "@twoux/ui";
92
+ import { MoreHorizontal, Pencil, X } from "lucide-react";
93
+
94
+ export const meta = {
95
+ title: "Icon only",
96
+ description: "For well-known actions in dense places. The aria-label names the action and its target, not the icon, and a tooltip shows the same words.",
97
+ order: 7,
98
+ };
99
+
100
+ export default function Example() {
101
+ return (
102
+ <div className="flex items-center gap-4">
103
+ <Button variant="ghost" size="icon-xs" aria-label="Edit Junior Product Designer" title="Edit"><Pencil /></Button>
104
+ <Button variant="ghost" size="icon-sm" aria-label="More actions for this listing" title="More actions"><MoreHorizontal /></Button>
105
+ <Button variant="ghost" size="icon" aria-label="Close details" title="Close (Esc)"><X /></Button>
106
+ </div>
107
+ );
108
+ }
109
+ ```
110
+
111
+ ### icons
112
+
113
+ ```tsx
114
+ import { Button } from "@twoux/ui";
115
+ import { ChevronDown, ExternalLink, Plus } from "lucide-react";
116
+
117
+ export const meta = {
118
+ title: "With icons",
119
+ description: "An icon before the label clarifies the action. An icon after it says what happens next: a chevron opens a menu, an arrow leaves the app.",
120
+ order: 4,
121
+ };
122
+
123
+ export default function Example() {
124
+ return (
125
+ <div className="flex flex-wrap items-center gap-2">
126
+ <Button variant="default"><Plus />New listing</Button>
127
+ <Button variant="outline">Status<ChevronDown /></Button>
128
+ <Button variant="ghost">View public page<ExternalLink /></Button>
129
+ </div>
130
+ );
131
+ }
132
+ ```
133
+
134
+ ### loading
135
+
136
+ ```tsx
137
+ import { Button } from "@twoux/ui";
138
+ import { useState } from "react";
139
+
140
+ export const meta = {
141
+ title: "Loading",
142
+ description: "While an action runs, the button shows a spinner and ignores clicks but stays focusable, so keyboard users keep their place. Press it to try.",
143
+ order: 6,
144
+ };
145
+
146
+ export default function Example() {
147
+ const [busy, setBusy] = useState(false);
148
+ return (
149
+ <div className="flex items-center gap-2">
150
+ <Button variant="default" loading={busy} onClick={() => { setBusy(true); setTimeout(() => setBusy(false), 1800); }}>
151
+ {busy ? "Publishing…" : "Publish listing"}
152
+ </Button>
153
+ <Button variant="outline" size="sm" loading>Saving…</Button>
154
+ </div>
155
+ );
156
+ }
157
+ ```
158
+
159
+ ### matrix
160
+
161
+ ```tsx
162
+ import { Button } from "@twoux/ui";
163
+
164
+ export const meta = { title: "All sizes and variants", description: "Every combination, for checking alignment. Rows share a baseline at each size.", order: 9 };
165
+
166
+ const variants = ["default", "outline", "secondary", "ghost", "warning", "destructive"] as const;
167
+ const sizes = ["xs", "sm", "default", "lg"] as const;
168
+
169
+ export default function Example() {
170
+ return (
171
+ <div className="grid grid-cols-[auto_repeat(6,auto)] items-center gap-x-3 gap-y-3">
172
+ <span />
173
+ {variants.map((v) => (
174
+ <span key={v} className="text-sm text-ink-3">{v}</span>
175
+ ))}
176
+ {sizes.map((s) => (
177
+ <div key={s} className="contents">
178
+ <span className="font-mono text-sm text-ink-3">{s}</span>
179
+ {variants.map((v) => (
180
+ <Button key={v} size={s} variant={v}>Button</Button>
181
+ ))}
182
+ </div>
183
+ ))}
184
+ </div>
185
+ );
186
+ }
187
+ ```
188
+
189
+ ### primary
190
+
191
+ ```tsx
192
+ import { Button } from "@twoux/ui";
193
+ import { Plus } from "lucide-react";
194
+
195
+ export const meta = {
196
+ title: "One primary action per view",
197
+ description: "The main action of the page is the only indigo button. Everything else is secondary or ghost.",
198
+ order: 1,
199
+ };
200
+
201
+ export default function Example() {
202
+ return (
203
+ <div className="flex items-center gap-2">
204
+ <Button variant="outline">Export</Button>
205
+ <Button variant="default" shortcut="C"><Plus />
206
+ New listing
207
+ </Button>
208
+ </div>
209
+ );
210
+ }
211
+ ```
212
+
213
+ ### shortcut
214
+
215
+ ```tsx
216
+ import { Button } from "@twoux/ui";
217
+ import { Clock, Copy } from "lucide-react";
218
+
219
+ export const meta = {
220
+ title: "With keyboard shortcut",
221
+ description: "Every frequent action shows its key, so people learn it by using it. The key is also in the tooltip for screen readers.",
222
+ order: 4,
223
+ };
224
+
225
+ export default function Example() {
226
+ return (
227
+ <div className="flex items-center gap-1 rounded-sm bg-surface p-1 shadow-pop">
228
+ <Button variant="ghost" size="sm" shortcut="T" title="Extend 30 days (T)"><Clock />
229
+ Extend 30 days
230
+ </Button>
231
+ <Button variant="ghost" size="sm" shortcut="D" title="Duplicate (D)"><Copy />
232
+ Duplicate
233
+ </Button>
234
+ </div>
235
+ );
236
+ }
237
+ ```
238
+
239
+ ### sizes
240
+
241
+ ```tsx
242
+ import { Button } from "@twoux/ui";
243
+ import { Download } from "lucide-react";
244
+
245
+ export const meta = {
246
+ title: "Sizes",
247
+ description: "Four compact sizes. 32px is the default. 28px in toolbars and filter bars, 24px inside table rows, 36px only for the single action of an empty state or sign-in page.",
248
+ order: 3,
249
+ };
250
+
251
+ export default function Example() {
252
+ return (
253
+ <div className="flex flex-wrap items-center gap-2">
254
+ <Button size="xs" variant="outline"><Download />Export</Button>
255
+ <Button size="sm" variant="outline"><Download />Export</Button>
256
+ <Button variant="outline"><Download />Export</Button>
257
+ <Button size="lg" variant="outline"><Download />Export</Button>
258
+ </div>
259
+ );
260
+ }
261
+ ```
262
+
263
+ ### variants
264
+
265
+ ```tsx
266
+ import { Button } from "@twoux/ui";
267
+
268
+ export const meta = {
269
+ title: "Variants",
270
+ description: "Primary for the one main action, secondary for supporting actions, tertiary in toolbars and rows, warning for risky but reversible actions, destructive only inside a confirmation, link for navigation.",
271
+ order: 2,
272
+ };
273
+
274
+ export default function Example() {
275
+ return (
276
+ <div className="flex flex-wrap items-center gap-2">
277
+ <Button variant="default">Publish listing</Button>
278
+ <Button variant="outline">Save draft</Button>
279
+ <Button variant="ghost">Cancel</Button>
280
+ <Button variant="warning">Close early</Button>
281
+ <Button variant="destructive">Delete listing</Button>
282
+ <Button variant="link">View all listings</Button>
283
+ </div>
284
+ );
285
+ }
286
+ ```
287
+
288
+ ## Related
289
+
290
+ - Keyboard shortcut hint
291
+ - Dropdown menu
292
+ - Tooltip
293
+ - Form validation
@@ -0,0 +1,115 @@
1
+ # Card
2
+
3
+ A white container that groups one object or one task, such as a settings section, a sign-in form or a summary, with an optional header, actions and footer.
4
+
5
+ Kind: component · Group: Content · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - To group the fields and actions of one settings section or one form, so it reads as one unit.
10
+ - To show one summary of an object, such as a listing's status and owner, on a page that holds several.
11
+
12
+ ## When not to use
13
+
14
+ - For rows of a list or table. Use the List table; cards break scanning and comparison across rows.
15
+ - Inside another card. Use a Separator or a heading to divide the content instead.
16
+ - To make text stand out. Use a Banner for a condition, or plain hierarchy.
17
+
18
+ ## Structure
19
+
20
+ 1. Container: white, light edge, 6px corners, resting shadow
21
+ 2. Header: title and optional description
22
+ 3. Action (optional): one button or menu, top right
23
+ 4. Content
24
+ 5. Footer (optional): actions on the right, or a tinted band with one secondary line
25
+
26
+ ## Guidelines
27
+
28
+ - One card is one object or one task. If the content splits into two jobs, use two cards.
29
+ - Keep the header short: a title, an optional one-line description, and at most one action on the right.
30
+ - Put primary actions in the footer, right-aligned, with the main action last.
31
+ - Use the footer band for a single secondary line, such as “Already have an account? Sign in”.
32
+ - Cards on a white page keep their edge; cards on the grey app background can drop the shadow but keep the edge.
33
+
34
+ ## Content
35
+
36
+ - Title in sentence case naming the object or task: “Notifications”, “Salary bands”.
37
+ - The description says what the section controls, not how to use the card.
38
+
39
+ ## Accessibility
40
+
41
+ - When a card holds a section, give the title a real heading element at the right level, so it appears in the heading list.
42
+ - Do not make the whole card clickable when it contains other controls; link the title instead, so each target has one purpose.
43
+ - The card edge is decorative; the content does not rely on it to be understood.
44
+
45
+ ## Keyboard
46
+
47
+ | Keys | Action |
48
+ |---|---|
49
+ | Tab | Moves through the card's own controls in reading order; the card itself is not a stop |
50
+
51
+ ## Examples
52
+
53
+ ### settings
54
+
55
+ ```tsx
56
+ import { Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, SwitchField } from "@twoux/ui";
57
+
58
+ export const meta = { title: "Settings section", description: "One card, one task. The title names it, the description says what it controls, and the footer holds the save action on the right.", order: 1 };
59
+
60
+ export default function Example() {
61
+ return (
62
+ <Card className="w-full max-w-md">
63
+ <CardHeader>
64
+ <CardTitle>Applicant emails</CardTitle>
65
+ <CardDescription>Choose when hiring managers hear about new applicants.</CardDescription>
66
+ <CardAction>
67
+ <Button variant="ghost" size="sm">Reset</Button>
68
+ </CardAction>
69
+ </CardHeader>
70
+ <CardContent className="grid gap-3">
71
+ <SwitchField id="email-each" label="Each new applicant" defaultChecked />
72
+ <SwitchField id="email-digest" label="Daily digest at 9:00" />
73
+ </CardContent>
74
+ <CardFooter className="justify-end gap-2 border-t pt-4">
75
+ <Button variant="outline" size="sm">Cancel</Button>
76
+ <Button size="sm">Save</Button>
77
+ </CardFooter>
78
+ </Card>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ### sign-in
84
+
85
+ ```tsx
86
+ import { Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, FieldSeparator, TextField } from "@twoux/ui";
87
+
88
+ export const meta = { title: "Sign in, with a footer band", description: "The band holds one secondary line, apart from the main action. The labelled separator divides the two ways in.", order: 2 };
89
+
90
+ export default function Example() {
91
+ return (
92
+ <Card className="w-full max-w-sm">
93
+ <CardHeader className="text-center">
94
+ <CardTitle>Sign in to TwoUX Hiring</CardTitle>
95
+ <CardDescription>Welcome back. Sign in to continue.</CardDescription>
96
+ </CardHeader>
97
+ <CardContent className="grid gap-4">
98
+ <Button variant="outline" className="w-full">Continue with Google</Button>
99
+ <FieldSeparator>or</FieldSeparator>
100
+ <TextField id="signin-email" label="Work email" type="email" placeholder="name@company.co.uk" />
101
+ <Button className="w-full">Continue</Button>
102
+ </CardContent>
103
+ <CardFooter band>
104
+ Don't have an account?&nbsp;<a href="#signup" className="font-medium text-primary-ink hover:underline">Sign up</a>
105
+ </CardFooter>
106
+ </Card>
107
+ );
108
+ }
109
+ ```
110
+
111
+ ## Related
112
+
113
+ - Banner (inline alert)
114
+ - Separator
115
+ - Empty state
@@ -0,0 +1,99 @@
1
+ # Change list
2
+
3
+ Ticker rows for indices, prices or rates: name and code, value with unit, change by arrow, sign and colour, an optional sparkline, and a See all link.
4
+
5
+ Kind: component · Group: Data visualisation · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - A short dashboard list of instruments or metrics where today's level and change matter most.
10
+ - Several numbers that move together, each too small for its own stat tile.
11
+
12
+ ## When not to use
13
+
14
+ - For one headline number. Use the TwoUX Stat compare.
15
+ - To rank items by a share of a total. Use the TwoUX Ranked list.
16
+
17
+ ## Structure
18
+
19
+ 1. Title and subtitle (period, delay)
20
+ 2. Row: name and code
21
+ 3. Optional sparkline of the period
22
+ 4. Value with unit, tabular
23
+ 5. Change: arrow, sign and percentage
24
+ 6. Footer: See all link
25
+
26
+ ## Guidelines
27
+
28
+ - Keep to about five to seven rows and link to the full list with See all.
29
+ - Change shows an arrow, a sign and a colour; colour alone is never the signal.
30
+ - Values align in tabular figures with their unit after the number.
31
+ - Sparklines use one colour and no axis; they show shape, the number gives the level.
32
+ - Say how fresh the data is in the subtitle, such as 15 minutes delayed.
33
+ - Use ChartFrame for the four states: loading keeps the frame, an error says what failed with Try again, an empty period says so, and no match offers Clear filters.
34
+
35
+ ## Content
36
+
37
+ - Name first, code second in smaller text: people scan names, specialists scan codes.
38
+ - Use a real minus sign for falls and two decimals for percentage change.
39
+
40
+ ## Accessibility
41
+
42
+ - 1.4.1 Use of Color: arrow and sign carry direction; screen readers hear up or down with the value.
43
+ - 1.4.11 Non-text Contrast: arrows use the status text colours, which meet 4.5:1.
44
+ - 4.1.2 Name, Role, Value: each row is one link named by its whole content.
45
+
46
+ ## Keyboard
47
+
48
+ | Keys | Action |
49
+ |---|---|
50
+ | Tab | Move to the next row, then See all |
51
+ | Enter | Open the row |
52
+
53
+ ## Examples
54
+
55
+ ### indices
56
+
57
+ ```tsx
58
+ import { ChangeList } from "@twoux/ui";
59
+
60
+ export const meta = { title: "Market indices", description: "Name and code, value with unit, change by arrow, sign and colour, and today's line. The footer links to the full list.", order: 1 };
61
+
62
+ // Intraday path: 48 five-minute points from a seeded walk that ends at today's change, so each line has real ups and downs.
63
+ function intraday(value: number, changePct: number, volatility: number, seed: number) {
64
+ const rand = () => ((seed = (seed * 16807) % 2147483647) / 2147483647);
65
+ const open = value / (1 + changePct / 100);
66
+ const n = 48;
67
+ const walk = [0];
68
+ for (let i = 1; i < n; i++) walk.push(walk[i - 1] + (rand() - 0.5) * 2);
69
+ const end = walk[n - 1];
70
+ return walk.map((w, i) => open + (w - (end * i) / (n - 1)) * open * volatility + ((value - open) * i) / (n - 1));
71
+ }
72
+
73
+ const ROWS = [
74
+ { id: "uk100", name: "UK 100", symbol: "UKX", value: 8412.36, unit: "pts", change: 0.42, spark: intraday(8412.36, 0.42, 0.0011, 11) },
75
+ { id: "uk250", name: "UK 250", symbol: "MCX", value: 20184.9, unit: "pts", change: -0.31, spark: intraday(20184.9, -0.31, 0.001, 23) },
76
+ { id: "eu600", name: "Europe 600", symbol: "SXXP", value: 512.07, unit: "pts", change: 0.18, spark: intraday(512.07, 0.18, 0.0009, 37) },
77
+ { id: "gilt10", name: "UK gilt, 10 year", symbol: "GUKG10", value: 4.12, unit: "%", change: 0.0, spark: intraday(4.12, 0.0, 0.0016, 53) },
78
+ { id: "gbpusd", name: "Pound to dollar", symbol: "GBP/USD", value: 1.2846, unit: "USD", change: -0.12, spark: intraday(1.2846, -0.12, 0.0004, 71) },
79
+ ];
80
+
81
+ export default function Example() {
82
+ return (
83
+ <ChangeList
84
+ className="w-full max-w-md"
85
+ title="Major indices"
86
+ description="Today, 15 minutes delayed"
87
+ items={ROWS.map((r) => ({ ...r, href: `#${r.id}` }))}
88
+ format={(n) => n.toLocaleString("en-GB", { minimumFractionDigits: 2, maximumFractionDigits: n < 10 ? 4 : 2 })}
89
+ seeAll={{ href: "#markets", label: "See all markets" }}
90
+ />
91
+ );
92
+ }
93
+ ```
94
+
95
+ ## Related
96
+
97
+ - Ranked list
98
+ - Stat card with comparison
99
+ - Price chart
@@ -0,0 +1,166 @@
1
+ # Change review
2
+
3
+ The review queue for changes an agent proposes to records, procedures, prompts, tools or another agent: the reason, the diff, and test results, approved or rejected by a person.
4
+
5
+ Kind: component · Group: AI and agents · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - When an agent proposes to change how something works: a procedure, a prompt, a tool, a rule, or another agent's instructions.
10
+ - When a change can be tested against a set of known cases (a regression set) before it goes live.
11
+ - When many agent changes arrive together and a person has to work through them in order.
12
+
13
+ ## When not to use
14
+
15
+ - Changes to a few records a person asked for. Use Suggested changes (suggested-changes).
16
+ - Plans for work that has not started. Use the Plan preview (plan-card).
17
+ - Actions set to Allow in Agent permissions (agent-permissions). Those run and appear in the Activity log with Undo.
18
+
19
+ ## Structure
20
+
21
+ 1. Header (title, status badge, origin label, reason in plain words)
22
+ 2. Diff view (files changed, +/− counts, unified diff)
23
+ 3. Simulation results ("228 of 240 pass", failures first, newly failing called out)
24
+ 4. Footer (note, Reject, Approve change) or the Reject reason field
25
+ 5. Resolved line (who decided and when)
26
+
27
+ ## Guidelines
28
+
29
+ - Nothing goes live until a person approves. Say so in the footer.
30
+ - State the reason in plain words and what the proposal is based on (the origin label), for example "14 conversations this week".
31
+ - Show the diff and the simulation results in the same card, so the person can decide without opening anything else.
32
+ - Run the change against a regression set. Failures come first, and a case that passed before and fails now is called out in words ("Newly failing"), with a count in the footer.
33
+ - Rejecting needs a reason the agent can learn from. If the box is empty, say why it is needed, next to the field.
34
+ - Every decision leaves a resolved line with who decided and when. Changes are logged and attributable to the agent that proposed them and the person who approved.
35
+ - A change one agent proposes to another agent's procedures is reviewed in the same way, with the proposing agent named as the origin.
36
+ - Group many changes by batch, each batch with a stated rationale. Stage risky ones with a traffic split or a gradual ramp, not all at once.
37
+
38
+ ## Content
39
+
40
+ - Title the change by what it does: "Reply in the applicant's language", not "Update prompt v14".
41
+ - Write the reason as cause and effect: "Applicants wrote in Welsh in 6 of 14 conversations and the assistant replied in English."
42
+ - Name failures in words: "2 conversations that passed before now fail." Do not rely on a coloured count.
43
+ - Resolved line: "Approved by Imogen Hart · 10:42" or "Rejected by Imogen Hart · 10:42", with the reason kept in the log.
44
+
45
+ ## Accessibility
46
+
47
+ - Each card is an article labelled with the change title, so people can move through a queue of changes by heading (SC 1.3.1).
48
+ - Added and removed lines carry a + or − marker and a hidden word ("Added", "Removed"), not colour alone (SC 1.4.1).
49
+ - File rows are disclosure buttons with aria-expanded (SC 4.1.2).
50
+ - The Reject reason field has a visible label, and a missing reason is an error shown beside it as text (SC 3.3.1, 3.3.2).
51
+ - Approving puts a change live, so the review step, the simulation results and the logged decision satisfy error prevention (SC 3.3.4). The resolved line is a role="status" message (SC 4.1.3).
52
+
53
+ ## Keyboard
54
+
55
+ | Keys | Action |
56
+ |---|---|
57
+ | Tab | Move through file rows, then Reject and Approve change |
58
+ | Enter / Space | Open or close a file's diff, or press the focused button |
59
+ | Enter (in Reject) | New line in the reason field; Tab to Reject change to send it |
60
+
61
+ ## Examples
62
+
63
+ ### agent-to-agent
64
+
65
+ ```tsx
66
+ import { ChangeRequest, toast } from "@twoux/ui";
67
+ import { useState } from "react";
68
+
69
+ export const meta = { title: "One agent changes another's procedure", description: "A reviewing agent proposes an edit to the Listing checker's steps. It is reviewed like any change, with the proposing agent named and a staged ramp.", order: 2 };
70
+
71
+ export default function Example() {
72
+ const [state, setState] = useState<"open" | "approved" | "rejected">("open");
73
+ return (
74
+ <div className="w-full max-w-2xl">
75
+ <ChangeRequest
76
+ title="Listing checker: ask before closing a listing with applicants"
77
+ from="9 listings closed with active applicants last month, found by the Quality reviewer agent"
78
+ reason="The Listing checker closed 3 listings that still had active applicants. This adds a step to ask for approval first. It would start with 10% of runs, then ramp up over a week."
79
+ files={[
80
+ {
81
+ path: "agents/listing-checker/steps.md",
82
+ lines: [
83
+ { type: "ctx", text: "1. Find listings past their closing date." },
84
+ { type: "add", text: "2. If a listing has active applicants, ask for approval." },
85
+ { type: "del", text: "2. Close the listing." },
86
+ { type: "add", text: "3. Close the listing." },
87
+ ],
88
+ },
89
+ ]}
90
+ simulation={{
91
+ suite: "Regression set, 60 listings",
92
+ cases: [
93
+ { name: "Listing with 12 active applicants", status: "fixed" },
94
+ { name: "Listing with no applicants", status: "pass" },
95
+ { name: "Listing closed by a person yesterday", status: "pass" },
96
+ ],
97
+ }}
98
+ state={state}
99
+ decidedBy={state === "approved" ? "Approved by Imogen Hart · 14:05 · ramping from 10%" : "Rejected by Imogen Hart · 14:05"}
100
+ onApprove={() => { setState("approved"); toast.success("Approved. Starting with 10% of runs."); }}
101
+ onReject={(why) => { setState("rejected"); toast("Rejected", { description: why }); }}
102
+ />
103
+ </div>
104
+ );
105
+ }
106
+ ```
107
+
108
+ ### review
109
+
110
+ ```tsx
111
+ import { ChangeRequest, toast } from "@twoux/ui";
112
+ import { useState } from "react";
113
+
114
+ export const meta = { title: "Review a change to a prompt", description: "The reason, the diff and the test results in one card. Two cases that passed before now fail, so the footer says so. Reject asks for a reason.", order: 1 };
115
+
116
+ export default function Example() {
117
+ const [state, setState] = useState<"open" | "approved" | "rejected">("open");
118
+ const [by, setBy] = useState<string>();
119
+ return (
120
+ <div className="w-full max-w-2xl">
121
+ <ChangeRequest
122
+ title="Reply in the applicant's language"
123
+ from="14 conversations this week"
124
+ reason="Applicants wrote in Welsh in 6 of 14 conversations and the assistant replied in English. This adds a line telling it to reply in the language the applicant used."
125
+ files={[
126
+ {
127
+ path: "prompts/applicant-reply.md",
128
+ lines: [
129
+ { type: "ctx", text: "You answer applicants for Harbour Recruitment." },
130
+ { type: "del", text: "Always reply in English." },
131
+ { type: "add", text: "Reply in the language the applicant wrote in." },
132
+ { type: "add", text: "If you are unsure of the language, reply in English." },
133
+ { type: "ctx", text: "Never promise an interview date." },
134
+ ],
135
+ },
136
+ { path: "prompts/shortlist-summary.md", lines: [{ type: "add", text: "Summaries stay in English for the hiring team." }] },
137
+ ]}
138
+ simulation={{
139
+ suite: "Golden set, 240 conversations",
140
+ cases: [
141
+ { name: "Applicant asks about the closing date, in Welsh", status: "fixed" },
142
+ { name: "Applicant asks about visa support, in Polish", status: "fixed" },
143
+ { name: "Applicant mixes English and Welsh", status: "new-fail", detail: "Replied in Welsh only. Passed before this change." },
144
+ { name: "Applicant writes only 'hi'", status: "new-fail", detail: "Replied in Welsh. Passed before this change." },
145
+ { name: "Applicant asks for a call back", status: "fail", detail: "Still promises a date." },
146
+ { name: "Applicant withdraws", status: "pass" },
147
+ { name: "Applicant asks about pay", status: "pass" },
148
+ ]}}
149
+ state={state}
150
+ decidedBy={by}
151
+ onApprove={() => { setState("approved"); setBy("Approved by Imogen Hart · 10:42"); toast.success("Approved. The change is live."); }}
152
+ onReject={(why) => { setState("rejected"); setBy("Rejected by Imogen Hart · 10:42"); toast("Rejected", { description: why }); }}
153
+ />
154
+ </div>
155
+ );
156
+ }
157
+ ```
158
+
159
+ ## Related
160
+
161
+ - Suggested changes
162
+ - Agent permissions
163
+ - Agent run timeline
164
+ - Confidence note
165
+ - Plan preview
166
+ - Prompt editor with fields