@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,92 @@
1
+ # Price chart
2
+
3
+ One price over a session: a line with a light wash, the last value tagged on the right axis, the previous close as a dashed reference, a live dot, and an axis that says when it does not start at zero.
4
+
5
+ Kind: component · Group: Data visualisation · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - A price or rate that moves within a narrow band, where the movement is the point, such as a share price today.
10
+ - A live value where people need the latest level and where it stands against a reference.
11
+
12
+ ## When not to use
13
+
14
+ - For amounts that should be compared from zero, such as revenue. Use the TwoUX Line chart card, which always starts at zero.
15
+ - For open, high, low and close per day. Use the TwoUX Candlestick chart.
16
+
17
+ ## Structure
18
+
19
+ 1. Title and subtitle (unit, delay)
20
+ 2. Plot: line with a 10% wash down to the axis floor
21
+ 3. Right axis with ticks and the last-value tag
22
+ 4. Dashed reference line with label (previous close)
23
+ 5. Live dot at the last point
24
+ 6. Time axis across the whole session
25
+ 7. Note under the axis when it does not start at zero
26
+ 8. Crosshair tooltip: time, price, change against the reference
27
+
28
+ ## Guidelines
29
+
30
+ - Start the axis at zero unless the range is narrow; when it does not, say so under the axis.
31
+ - Lay out the whole session on the time axis so the empty part of the day stays visible.
32
+ - Tag the last value on the right axis and hide ticks that would collide with it.
33
+ - Draw the reference as a dashed grey line with a text label, never a series.
34
+ - Fill under the line with a light wash of the series colour, not a solid block.
35
+ - The live dot pulses only while the market is open, and never under reduced motion.
36
+ - 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.
37
+
38
+ ## Content
39
+
40
+ - Put the unit and delay in the subtitle, such as In pence, 15 minutes delayed.
41
+ - Label the reference by what it is (Previous close), with its value.
42
+
43
+ ## Accessibility
44
+
45
+ - 1.1.1 and WAI complex images: the chart has a short generated summary as its accessible name and a Table view with every value.
46
+ - 2.1.1 Keyboard: the chart is one tab stop; arrow keys move between marks and show the same tooltip as hover.
47
+ - 1.4.13 Content on Hover or Focus: the tooltip never covers the mark it describes, stays while the pointer is over the chart and closes with Esc.
48
+ - Accessible description: "Line chart showing Ashdown plc share price today in pence."
49
+ - 2.2.2 and 2.3.3: the pulsing dot is under five seconds per cycle and stops under prefers-reduced-motion.
50
+
51
+ ## Keyboard
52
+
53
+ | Keys | Action |
54
+ |---|---|
55
+ | Tab | Focus the chart |
56
+ | ← → ↑ ↓ | Move to the previous or next mark and show its values |
57
+ | Home End | Jump to the first or last mark |
58
+ | Esc | Hide the tooltip |
59
+
60
+ ## Examples
61
+
62
+ ### intraday
63
+
64
+ ```tsx
65
+ import { ChartFrame, PriceChart } from "@twoux/ui";
66
+
67
+ export const meta = { title: "Share price today", description: "Ten-minute prices from the open, the session's remaining slots left empty, the last price tagged on the right axis and the previous close as a dashed reference. The axis starts above zero and says so.", order: 1 };
68
+
69
+ const TIMES = ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50", "09:00", "09:10", "09:20", "09:30", "09:40", "09:50", "10:00", "10:10", "10:20", "10:30", "10:40", "10:50", "11:00", "11:10", "11:20", "11:30", "11:40", "11:50", "12:00", "12:10", "12:20", "12:30", "12:40", "12:50", "13:00", "13:10", "13:20", "13:30", "13:40", "13:50", "14:00", "14:10", "14:20", "14:30", "14:40", "14:50", "15:00", "15:10", "15:20", "15:30", "15:40", "15:50", "16:00", "16:10", "16:20", "16:30"];
70
+ const TRADED = [741.8, 742.7, 742.5, 742.2, 741.0, 740.9, 742.6, 743.3, 745.0, 745.5, 746.2, 746.6, 744.4, 745.7, 746.6, 747.4, 745.2, 742.9, 741.8, 741.3, 741.9, 742.0, 742.9, 742.1, 742.7, 743.4, 742.6, 745.2, 746.1, 747.9, 747.2, 746.3, 746.0, 746.0, 747.0, 747.5, 747.1, 745.9, 745.3];
71
+ const PRICES = TIMES.map((_, i) => TRADED[i] ?? null);
72
+ const pence = (n: number) => `${n.toLocaleString("en-GB", { minimumFractionDigits: 1, maximumFractionDigits: 1 })}p`;
73
+
74
+ export default function Example() {
75
+ return (
76
+ <ChartFrame
77
+ className="w-full"
78
+ title="Ashdown plc share price"
79
+ description="Today, in pence, 15 minutes delayed"
80
+ table={{ columns: ["Time", "Price"], rows: TIMES.slice(0, TRADED.length).map((t, i) => [t, pence(TRADED[i])]) }}
81
+ >
82
+ <PriceChart x={TIMES} data={PRICES} format={pence} reference={{ value: 741.2, label: "Previous close" }} live aria-label="Ashdown plc share price today" />
83
+ </ChartFrame>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ## Related
89
+
90
+ - Line chart card
91
+ - Candlestick chart
92
+ - Change list
@@ -0,0 +1,109 @@
1
+ # Radial bars
2
+
3
+ One to four small concentric rings, each the share of a fixed limit such as seats, credits or storage, with used of limit always written beside them. Never actual against target: that stays the bullet chart.
4
+
5
+ Kind: component · Group: Data visualisation · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - Showing two to four limits of a plan together in the space of a stat card, such as seats, assistant credits and storage this month.
10
+ - One budget that resets, such as an SLA error budget, where a ring with the share in the centre fits a small tile.
11
+
12
+ ## When not to use
13
+
14
+ - For actual against a target, such as bookings against plan. Use the TwoUX Bullet chart: angles are read less exactly than lengths.
15
+ - For a single limit with a reset date and what stops at the limit. Use the TwoUX Usage meter.
16
+ - To compare amounts across categories around a circle. Use a Bar chart: outer rings look longer than inner ones for the same value.
17
+ - For parts of one total. Use a Donut chart or Share bar.
18
+ - For a value with no fixed maximum, or for the progress of a task. A ring needs a real limit.
19
+
20
+ ## Structure
21
+
22
+ 1. Rings, outermost first: grey track and an arc from 12 o'clock clockwise
23
+ 2. Zero tick at 12 o'clock
24
+ 3. Share in the centre when there is one ring
25
+ 4. List: colour key, measure name, used of limit and share
26
+ 5. Status badge when a ring is at or over its limit
27
+ 6. Tooltip under the rings on hover or focus
28
+
29
+ ## Guidelines
30
+
31
+ - Use radial bars only for share of a fixed limit, 0 to 100% of capacity, quota or budget.
32
+ - Show at most four rings, at 96 to 160px. Extra items are not drawn.
33
+ - Write used of limit and the share as text beside the rings; the ring only repeats it.
34
+ - Start every ring at 12 o'clock and run clockwise from zero. A value over the limit fills the ring; it never wraps round twice.
35
+ - Colour rings in series order. A ring at or over its limit adds At limit or Over limit as a badge; never recolour a ring as the only cue.
36
+ - No needle, no half-circle dial and no thresholds on the ring.
37
+ - 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.
38
+
39
+ ## Content
40
+
41
+ - Name each ring by what it measures, as a noun: Seats, Assistant credits, Storage.
42
+ - Write used of limit with the unit, then the share: 38 of 50 seats · 76%.
43
+ - Put the plan and reset date in the chart description: Growth plan · resets 1 Dec.
44
+
45
+ ## Accessibility
46
+
47
+ - 1.1.1 and WAI complex images: the chart's accessible name lists each measure as used of limit, share and status.
48
+ - 1.4.1 Use of Color: every value and status is printed in the list; colour only links a ring to its row.
49
+ - 1.4.11 Non-text Contrast: arcs meet 3:1 against the grey track.
50
+ - 2.1.1 Keyboard: one tab stop, arrow keys move between rings and show the same tooltip as hover.
51
+ - 1.4.10 Reflow: the list moves under the rings on narrow screens.
52
+
53
+ ## Keyboard
54
+
55
+ | Keys | Action |
56
+ |---|---|
57
+ | Tab | Focus the chart |
58
+ | ← → ↑ ↓ | Move to the previous or next ring |
59
+ | Home End | Go to the outer or inner ring |
60
+ | Esc | Hide the tooltip |
61
+
62
+ ## Examples
63
+
64
+ ### error-budget
65
+
66
+ ```tsx
67
+ import { ChartFrame, RadialBars, radialBarsTable } from "@twoux/ui";
68
+
69
+ export const meta = { title: "One ring: SLA error budget", description: "A single ring shows its share in the centre. The budget is a fixed limit for the month, so the ring fits; progress against a target would be a bullet chart.", order: 2 };
70
+
71
+ const ITEMS = [{ id: "budget", label: "Error budget used", value: 26, limit: 43, unit: "min" }];
72
+
73
+ export default function Example() {
74
+ return (
75
+ <ChartFrame className="w-full max-w-sm" title="Checkout API error budget" description="99.9% availability · November" table={radialBarsTable(ITEMS)} height={120}>
76
+ <RadialBars items={ITEMS} size={104} aria-label="Checkout API error budget used in November" />
77
+ </ChartFrame>
78
+ );
79
+ }
80
+ ```
81
+
82
+ ### workspace-usage
83
+
84
+ ```tsx
85
+ import { ChartFrame, RadialBars, radialBarsTable } from "@twoux/ui";
86
+
87
+ export const meta = { title: "Workspace usage this month", description: "Seats, assistant credits and storage, each as a share of the plan's limit. The list says every value in words; the rings only repeat it. Seats at the limit add a status badge.", order: 1 };
88
+
89
+ const ITEMS = [
90
+ { id: "seats", label: "Seats", value: 50, limit: 50, unit: "seats" },
91
+ { id: "credits", label: "Assistant credits", value: 13_200, limit: 20_000, unit: "credits" },
92
+ { id: "storage", label: "Storage", value: 38, limit: 100, unit: "GB" },
93
+ ];
94
+
95
+ export default function Example() {
96
+ return (
97
+ <ChartFrame className="w-full max-w-md" title="Plan usage" description="Growth plan · resets 1 Dec" table={radialBarsTable(ITEMS)} height={140}>
98
+ <RadialBars items={ITEMS} aria-label="Plan usage this month" />
99
+ </ChartFrame>
100
+ );
101
+ }
102
+ ```
103
+
104
+ ## Related
105
+
106
+ - Usage meter
107
+ - Bullet chart
108
+ - Donut chart
109
+ - Stat card with comparison
@@ -0,0 +1,111 @@
1
+ # Radial lines
2
+
3
+ A line chart wrapped round a circle for cyclical periods (hour of day, day of week, month), so the last period runs into the first. One to three series, values from zero, gaps for missing data.
4
+
5
+ Kind: component · Group: Data visualisation · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - Showing how a measure rises and falls through a repeating cycle where the wrap-around matters, such as support tickets by hour of day across two queues.
10
+ - Daily or weekly rhythms, such as sign-ins by day of week, where Sunday into Monday should read as one stretch.
11
+
12
+ ## When not to use
13
+
14
+ - For time that does not repeat, such as revenue by month over two years. Use the TwoUX Line chart card.
15
+ - For exact comparisons between periods. Use a Bar chart: values near the centre are hard to compare.
16
+ - For a cycle against a second dimension, such as hour by weekday. Use the TwoUX Heatmap.
17
+ - For more than three series. Split them into small charts side by side.
18
+
19
+ ## Structure
20
+
21
+ 1. Title and subtitle with the period averaged and time zone
22
+ 2. Value rings from zero, three or four, labelled along the top spoke
23
+ 3. One spoke per period, labels round the outside
24
+ 4. Lines in series colours, joined from the last period to the first
25
+ 5. Gaps for missing data
26
+ 6. Legend for two or more series
27
+ 7. Tooltip for the nearest period on hover or focus
28
+
29
+ ## Guidelines
30
+
31
+ - Use radial lines only for cyclical periods: hour of day, day of week, month of year.
32
+ - Start the first period at 12 o'clock and run clockwise.
33
+ - Start the value axis at zero with three or four labelled rings; never crop the centre.
34
+ - Draw missing data as a gap, never as zero. Join the last period to the first only when both have values.
35
+ - Show one to three series as lines; no area fill.
36
+ - Show a legend only for two or more series; legend keys hide series without changing colours.
37
+ - 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.
38
+
39
+ ## Content
40
+
41
+ - Name the measure and the cycle in the title: Tickets opened by hour.
42
+ - Say what was averaged and the time zone in the description: Average per day, last 30 days, UK time.
43
+ - Write periods as people read them: 00:00 to 23:00, Mon to Sun, Jan to Dec.
44
+
45
+ ## Accessibility
46
+
47
+ - 1.1.1 and WAI complex images: the accessible name gives the cycle, where it starts, and each series' highest and lowest period and gaps.
48
+ - 2.1.1 Keyboard: one tab stop; arrow keys move round the cycle and wrap, showing the same tooltip as hover.
49
+ - 1.4.13 Content on Hover or Focus: the tooltip stays while the period is active and Esc hides it.
50
+ - 1.4.11 Non-text Contrast: lines meet 3:1 against the surface.
51
+ - 1.4.10 Reflow: the chart shrinks to its container and the table view lists every value.
52
+
53
+ ## Keyboard
54
+
55
+ | Keys | Action |
56
+ |---|---|
57
+ | Tab | Focus the chart |
58
+ | → ↓ | Next period, clockwise; wraps from the last to the first |
59
+ | ← ↑ | Previous period, anticlockwise |
60
+ | Home End | Go to the first or last period |
61
+ | Esc | Hide the tooltip |
62
+
63
+ ## Examples
64
+
65
+ ### logins-by-weekday
66
+
67
+ ```tsx
68
+ import { ChartFrame, RadialLines, radialLinesTable } from "@twoux/ui";
69
+
70
+ export const meta = { title: "One series: sign-ins by day of week", description: "One series needs no legend. Sunday meets Monday, so the weekend dip reads as one shape.", order: 2 };
71
+
72
+ const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
73
+ const SERIES = [{ id: "signins", label: "Sign-ins", data: [4_820, 5_130, 5_060, 4_910, 3_980, 820, 640] }];
74
+
75
+ export default function Example() {
76
+ return (
77
+ <ChartFrame className="w-full max-w-md" title="Sign-ins by day of week" description="Average per day, last 12 weeks" table={radialLinesTable(DAYS, SERIES, undefined, "Day")} height={260}>
78
+ <RadialLines periods={DAYS} series={SERIES} periodLabel="Day" maxSize={260} aria-label="Sign-ins by day of week, last 12 weeks" />
79
+ </ChartFrame>
80
+ );
81
+ }
82
+ ```
83
+
84
+ ### tickets-by-hour
85
+
86
+ ```tsx
87
+ import { ChartFrame, RadialLines, radialLinesTable } from "@twoux/ui";
88
+
89
+ export const meta = { title: "Support tickets by hour of day", description: "Two queues over 24 hours. Midnight sits at the top, so the overnight hours read as one stretch. 04:00 has no data after a logging outage and shows as a gap.", order: 1 };
90
+
91
+ const HOURS = Array.from({ length: 24 }, (_, h) => `${String(h).padStart(2, "0")}:00`);
92
+ const SERIES = [
93
+ { id: "billing", label: "Billing", data: [6, 4, 3, 2, null, 3, 8, 18, 34, 52, 61, 58, 49, 55, 60, 54, 44, 31, 22, 17, 14, 12, 10, 8] },
94
+ { id: "technical", label: "Technical", data: [14, 12, 10, 9, null, 11, 16, 24, 31, 38, 42, 40, 36, 39, 43, 41, 37, 33, 29, 27, 24, 21, 18, 16] },
95
+ ];
96
+
97
+ export default function Example() {
98
+ return (
99
+ <ChartFrame className="w-full" title="Tickets opened by hour" description="Average per day, last 30 days, UK time" table={radialLinesTable(HOURS, SERIES, undefined, "Hour")} height={320}>
100
+ <RadialLines periods={HOURS} series={SERIES} periodLabel="Hour" aria-label="Support tickets opened by hour of day, last 30 days" />
101
+ </ChartFrame>
102
+ );
103
+ }
104
+ ```
105
+
106
+ ## Related
107
+
108
+ - Line chart card
109
+ - Heatmap
110
+ - Bar chart
111
+ - Data visualisation
@@ -0,0 +1,104 @@
1
+ # Sankey chart
2
+
3
+ Flows from left to right across two or three columns, such as traffic sources to pages to outcomes. Link width shows value; hover or focus highlights a path.
4
+
5
+ Kind: component · Group: Data visualisation · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - Showing how a quantity splits and recombines across stages, such as visits from sources to pages to outcomes.
10
+ - Finding the largest flows into a loss, such as where people leave.
11
+
12
+ ## When not to use
13
+
14
+ - For ordered stages where each is a subset of the last. Use the TwoUX Funnel.
15
+ - For more than three columns or about 12 nodes; split it or use a table.
16
+
17
+ ## Structure
18
+
19
+ 1. Title and subtitle
20
+ 2. Columns of nodes
21
+ 3. Links, width by value
22
+ 4. Labels: name, value and share of column
23
+ 5. Highlighted path on hover or focus
24
+ 6. Tooltip: from, to, value, share of source
25
+
26
+ ## Guidelines
27
+
28
+ - Keep to two or three columns and about 12 nodes.
29
+ - Link width is proportional to value; links use one hue at low opacity so overlaps stay readable.
30
+ - Hovering a node lights every flow through it; hovering a link lights that link.
31
+ - Labels give name, value and share of the column when there is room; on narrow screens names only.
32
+ - The Table view lists every flow as from, to and value.
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 the last column by outcome (Started trial, Left), not by page.
38
+ - Shares are of the column, so each column adds to 100%.
39
+
40
+ ## Accessibility
41
+
42
+ - 1.1.1 and WAI complex images: the chart has a short generated summary as its accessible name and a Table view with every value.
43
+ - 2.1.1 Keyboard: the chart is one tab stop; arrow keys move between marks and show the same tooltip as hover.
44
+ - 1.4.13 Content on Hover or Focus: the tooltip never covers the mark it describes, stays while the pointer is over the chart and closes with Esc.
45
+ - Accessible description: "Sankey chart showing visits from source to page to outcome, last 30 days."
46
+ - 1.4.1 Use of Color: links are one hue; their values are in labels, tooltips and the table.
47
+
48
+ ## Keyboard
49
+
50
+ | Keys | Action |
51
+ |---|---|
52
+ | Tab | Focus the chart |
53
+ | ← → ↑ ↓ | Move to the previous or next mark and show its values |
54
+ | Home End | Jump to the first or last mark |
55
+ | Esc | Hide the tooltip |
56
+
57
+ ## Examples
58
+
59
+ ### pricing-traffic
60
+
61
+ ```tsx
62
+ import { ChartFrame, SankeyChart, sankeyTable } from "@twoux/ui";
63
+
64
+ export const meta = { title: "Visits to the pricing page", description: "Where visits came from, which page they reached, and what they did next. Hover a node to light every flow through it.", order: 1 };
65
+
66
+ const NODES = [
67
+ { id: "organic", label: "Organic search" },
68
+ { id: "paid", label: "Paid search" },
69
+ { id: "direct", label: "Direct" },
70
+ { id: "referral", label: "Referral" },
71
+ { id: "pricing", label: "Pricing page" },
72
+ { id: "docs", label: "Docs" },
73
+ { id: "trial", label: "Started trial" },
74
+ { id: "demo", label: "Booked demo" },
75
+ { id: "left", label: "Left" },
76
+ ];
77
+ const LINKS = [
78
+ { source: "organic", target: "pricing", value: 8_200 },
79
+ { source: "organic", target: "docs", value: 4_100 },
80
+ { source: "paid", target: "pricing", value: 5_600 },
81
+ { source: "direct", target: "pricing", value: 3_900 },
82
+ { source: "direct", target: "docs", value: 2_300 },
83
+ { source: "referral", target: "pricing", value: 1_800 },
84
+ { source: "pricing", target: "trial", value: 2_900 },
85
+ { source: "pricing", target: "demo", value: 1_100 },
86
+ { source: "pricing", target: "left", value: 15_500 },
87
+ { source: "docs", target: "trial", value: 1_200 },
88
+ { source: "docs", target: "left", value: 5_200 },
89
+ ];
90
+
91
+ export default function Example() {
92
+ return (
93
+ <ChartFrame className="w-full" title="Visits to pricing and docs" description="Last 30 days" table={sankeyTable(NODES, LINKS)} height={280}>
94
+ <SankeyChart nodes={NODES} links={LINKS} aria-label="Visits from source to page to outcome, last 30 days" />
95
+ </ChartFrame>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ## Related
101
+
102
+ - Funnel
103
+ - Bar chart
104
+ - Breakdown table
@@ -0,0 +1,87 @@
1
+ # Scatter chart
2
+
3
+ One dot per record placed by two measures, such as each live listing by advertised salary and applications, for spotting relationships and outliers.
4
+
5
+ Kind: component · Group: Data visualisation · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - When the question is whether two measures move together across records: salary and applications per listing, or days open and applications.
10
+ - When outliers matter: a listing with a high salary and few applications is worth opening.
11
+
12
+ ## When not to use
13
+
14
+ - For change over time. Use the Line chart card.
15
+ - For fewer than about ten records. Use a Breakdown table; a scatter of five dots shows no pattern.
16
+ - To compare candidates. Plotting people by scores invites ranking them; candidate decisions stay with the hiring team and are never made from a chart.
17
+ - To encode a third measure as dot size. Use a second scatter or a table instead.
18
+
19
+ ## Structure
20
+
21
+ 1. Title and subtitle
22
+ 2. Plot: x-axis and y-axis, each with a title and unit
23
+ 3. Dots, one per record (up to three groups by colour and shape)
24
+ 4. Optional threshold lines with text labels
25
+ 5. Legend when there are two or more groups
26
+ 6. Details popover: the record's name and both values, with a link to it
27
+
28
+ ## Guidelines
29
+
30
+ - Each axis has a title with its unit; axes may start above zero if the axis says so, because position, not length, carries the value.
31
+ - Use at most three groups, coloured with categorical colours 1 to 3 and each with its own marker shape (circle, square, triangle), since any dot can touch any other.
32
+ - Keep dots small (6px) with a 1px surface-colour outline so overlapping dots stay visible.
33
+ - Selecting a dot opens the details popover with the listing's name, both values and a link to the record.
34
+ - Do not draw a trend line unless the team asked for one and its method is named in the footer.
35
+
36
+ ## Content
37
+
38
+ - Title names both measures: "Salary and applications by listing". Subtitle gives the scope: "Live listings, last 30 days".
39
+ - Axis titles are short with units: "Salary (£k)", "Applications".
40
+ - Popover reads as key and value pairs: "Junior Product Designer, Leeds", "Salary £32k", "Applications 46".
41
+
42
+ ## Accessibility
43
+
44
+ - Description: "Scatter chart showing salary and applications for 38 live listings, last 30 days." The Table view lists every record with both values.
45
+ - Groups differ by marker shape as well as colour.
46
+ - Arrow keys move from dot to dot in x order and open each popover; a pinned popover stays until Esc.
47
+
48
+ ## Keyboard
49
+
50
+ | Keys | Action |
51
+ |---|---|
52
+ | Tab | Focus the plot, then the legend |
53
+ | ← → | Move to the previous or next dot along the x-axis |
54
+ | Enter | Pin the popover and reach its link |
55
+ | Esc | Close the popover |
56
+
57
+ ## Examples
58
+
59
+ ### salary-applicants
60
+
61
+ ```tsx
62
+ import { ChartFrame, ScatterChart } from "@twoux/ui";
63
+
64
+ export const meta = { title: "Salary against applicants", description: "One dot per listing, up to three teams, each with its own colour and shape. Arrow keys move along the x axis; Enter pins the details with a link to the listing.", order: 1 };
65
+
66
+ const P = [
67
+ ["Junior Product Designer", 30, 38, "Design"], ["Senior Product Designer", 58, 37, "Design"], ["Content Designer", 42, 21, "Design"],
68
+ ["Frontend Engineer", 52, 112, "Engineering"], ["Backend Engineer", 60, 64, "Engineering"], ["QA Engineer", 40, 47, "Engineering"], ["Platform Engineer", 68, 29, "Engineering"],
69
+ ["Data Analyst", 41, 64, "Data"], ["Analytics Engineer", 55, 33, "Data"], ["Data Scientist", 62, 41, "Data"],
70
+ ] as const;
71
+
72
+ export default function Example() {
73
+ return (
74
+ <ChartFrame className="w-full" title="Salary and applicants" description="Open listings, salary from in £000s">
75
+ <ScatterChart aria-label="Salary against applicants by team" xTitle="Salary from (£000s)" yTitle="Applicants" points={P.map(([label, x, y, group], i) => ({ id: String(i), label, x, y, group, href: "#listing" }))} />
76
+ </ChartFrame>
77
+ );
78
+ }
79
+ ```
80
+
81
+ ## Related
82
+
83
+ - Line chart card
84
+ - Breakdown table
85
+ - Data visualisation colours
86
+ - Chart drill-down
87
+ - Data visualisation
@@ -0,0 +1,89 @@
1
+ # Share bar
2
+
3
+ One whole split into up to six parts in a single horizontal bar, with each part's name and share in a legend above. Smaller parts fold into a grey Other.
4
+
5
+ Kind: component · Group: Data visualisation · Status: built, import from @twoux/ui
6
+
7
+ ## When to use
8
+
9
+ - Showing how one total splits at one moment, read at a glance, such as recurring revenue by plan.
10
+ - A card or table header has room for a line, not a chart: a thin bar takes 8px and the legend carries the numbers.
11
+
12
+ ## When not to use
13
+
14
+ - To compare parts precisely or rank more than six of them. Use the TwoUX Bar chart, because bars on one baseline compare more exactly than segments end to end.
15
+ - To show the split changing over time. Use the TwoUX Area chart.
16
+
17
+ ## Structure
18
+
19
+ 1. Title and subtitle
20
+ 2. Legend above the bar: swatch, name and share for each part
21
+ 3. Bar: one block per part with a 2px surface gap
22
+ 4. Other: the folded tail, in grey
23
+ 5. Tooltip: name, share and amount
24
+
25
+ ## Guidelines
26
+
27
+ - Keep to six parts; the smallest fold into Other, which is always grey and always last.
28
+ - Separate parts with a 2px gap in the surface colour, never a border.
29
+ - Colours follow the order you pass, c1 first. Pass parts in a stable order so a part keeps its colour from one period to the next.
30
+ - Thin bar: shares go in the legend above, not on the bar. Tall bar: the share prints inside each block only when it fits, and the legend gives names.
31
+ - Use a share bar instead of a donut when space is a line, not a square.
32
+ - 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.
33
+
34
+ ## Content
35
+
36
+ - Shares to one decimal place in the legend, whole percentages inside a tall bar.
37
+ - Name the part people know (Business, Team), not an internal code.
38
+
39
+ ## Accessibility
40
+
41
+ - 1.4.1 Use of Color: every part is named in the legend and in the generated summary, so colour is not the only way to tell parts apart.
42
+ - 1.1.1 and WAI complex images: the chart has a short generated summary as its accessible name and a Table view with every value.
43
+ - 2.1.1 Keyboard: the chart is one tab stop; arrow keys move between marks and show the same tooltip as hover.
44
+ - 1.4.13 Content on Hover or Focus: the tooltip never covers the mark it describes, stays while the pointer is over the chart and closes with Esc.
45
+
46
+ ## Keyboard
47
+
48
+ | Keys | Action |
49
+ |---|---|
50
+ | Tab | Focus the chart |
51
+ | ← → ↑ ↓ | Move to the previous or next mark and show its values |
52
+ | Home End | Jump to the first or last mark |
53
+ | Esc | Hide the tooltip |
54
+
55
+ ## Examples
56
+
57
+ ### plan-revenue
58
+
59
+ ```tsx
60
+ import { ChartFrame, ShareBar, shareTable } from "@twoux/ui";
61
+
62
+ export const meta = { title: "Recurring revenue by plan", description: "A thin bar under a legend that already gives each share. Eight plans arrive; the two smallest fold into Other so the bar keeps six parts.", order: 1 };
63
+
64
+ const PLANS = [
65
+ { id: "business", label: "Business", value: 1_284_000 },
66
+ { id: "team", label: "Team", value: 612_000 },
67
+ { id: "enterprise", label: "Enterprise", value: 498_000 },
68
+ { id: "starter", label: "Starter", value: 231_000 },
69
+ { id: "agency", label: "Agency", value: 104_000 },
70
+ { id: "education", label: "Education", value: 46_000 },
71
+ { id: "charity", label: "Charity", value: 21_000 },
72
+ { id: "legacy", label: "Legacy", value: 9_000 },
73
+ ];
74
+ const gbp = (n: number) => `£${(n / 1000).toLocaleString("en-GB", { maximumFractionDigits: 0 })}k`;
75
+
76
+ export default function Example() {
77
+ return (
78
+ <ChartFrame className="w-full" title="Recurring revenue by plan" description="Annual run rate, 5 November 2026" table={shareTable(PLANS, gbp, "Plan")} height={60}>
79
+ <ShareBar parts={PLANS} format={gbp} aria-label="Recurring revenue by plan" />
80
+ </ChartFrame>
81
+ );
82
+ }
83
+ ```
84
+
85
+ ## Related
86
+
87
+ - Donut chart
88
+ - Bar chart
89
+ - Treemap