@twoux/ui 0.0.0-stage → 0.1.0
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.
- package/LICENSE.md +61 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/NOTICE.md +64 -0
- package/SHADCN-DIFF.md +228 -0
- package/agent/AGENTS.md +358 -0
- package/agent/docs-md/accessibility.md +49 -0
- package/agent/docs-md/action-catalogue.md +81 -0
- package/agent/docs-md/actions.md +74 -0
- package/agent/docs-md/agent-activity-log.md +70 -0
- package/agent/docs-md/agent-permissions.md +82 -0
- package/agent/docs-md/agent-run.md +90 -0
- package/agent/docs-md/agents-on-behalf.md +74 -0
- package/agent/docs-md/ai-column.md +85 -0
- package/agent/docs-md/ai-origin-label.md +70 -0
- package/agent/docs-md/announcing-features.md +73 -0
- package/agent/docs-md/answer-actions.md +81 -0
- package/agent/docs-md/app-shell.md +114 -0
- package/agent/docs-md/artifact-card.md +89 -0
- package/agent/docs-md/ask-on-screen.md +72 -0
- package/agent/docs-md/assistant-page.md +100 -0
- package/agent/docs-md/assistant-panel.md +142 -0
- package/agent/docs-md/avatar.md +82 -0
- package/agent/docs-md/banner.md +106 -0
- package/agent/docs-md/board.md +163 -0
- package/agent/docs-md/breadcrumb.md +89 -0
- package/agent/docs-md/breakdown-table.md +97 -0
- package/agent/docs-md/bulk-action-bar.md +112 -0
- package/agent/docs-md/button.md +293 -0
- package/agent/docs-md/card.md +115 -0
- package/agent/docs-md/change-list.md +99 -0
- package/agent/docs-md/change-request.md +166 -0
- package/agent/docs-md/chart-area.md +87 -0
- package/agent/docs-md/chart-bar.md +100 -0
- package/agent/docs-md/chart-box-plot.md +88 -0
- package/agent/docs-md/chart-bullet.md +89 -0
- package/agent/docs-md/chart-candlestick.md +112 -0
- package/agent/docs-md/chart-card-line.md +120 -0
- package/agent/docs-md/chart-donut.md +90 -0
- package/agent/docs-md/chart-drill-down.md +72 -0
- package/agent/docs-md/chart-funnel.md +71 -0
- package/agent/docs-md/chart-heatmap.md +76 -0
- package/agent/docs-md/chart-histogram.md +81 -0
- package/agent/docs-md/chart-map.md +165 -0
- package/agent/docs-md/chart-mixed.md +88 -0
- package/agent/docs-md/chart-price.md +92 -0
- package/agent/docs-md/chart-radial-bars.md +109 -0
- package/agent/docs-md/chart-radial-lines.md +111 -0
- package/agent/docs-md/chart-sankey.md +104 -0
- package/agent/docs-md/chart-scatter.md +87 -0
- package/agent/docs-md/chart-share-bar.md +89 -0
- package/agent/docs-md/chart-treemap.md +98 -0
- package/agent/docs-md/chart-waterfall.md +93 -0
- package/agent/docs-md/checkbox.md +131 -0
- package/agent/docs-md/choosing-selection-control.md +71 -0
- package/agent/docs-md/citations-sources.md +79 -0
- package/agent/docs-md/citing-sources.md +63 -0
- package/agent/docs-md/clarify-before-acting.md +69 -0
- package/agent/docs-md/clarifying-question.md +92 -0
- package/agent/docs-md/code-block.md +174 -0
- package/agent/docs-md/colours.md +87 -0
- package/agent/docs-md/columns-menu.md +140 -0
- package/agent/docs-md/combobox.md +161 -0
- package/agent/docs-md/command-palette.md +126 -0
- package/agent/docs-md/confidence-note.md +87 -0
- package/agent/docs-md/configurable-dashboard.md +76 -0
- package/agent/docs-md/confirmation-dialog.md +93 -0
- package/agent/docs-md/connected-tools.md +80 -0
- package/agent/docs-md/connector-picker.md +127 -0
- package/agent/docs-md/consistency.md +53 -0
- package/agent/docs-md/content-density.md +61 -0
- package/agent/docs-md/conversation-history.md +78 -0
- package/agent/docs-md/create-record.md +80 -0
- package/agent/docs-md/csv-import.md +88 -0
- package/agent/docs-md/dashboard-items.md +78 -0
- package/agent/docs-md/data-export.md +61 -0
- package/agent/docs-md/data-grid.md +137 -0
- package/agent/docs-md/data-vis-colours.md +76 -0
- package/agent/docs-md/data-visualisation.md +76 -0
- package/agent/docs-md/date-picker.md +178 -0
- package/agent/docs-md/delete-record.md +75 -0
- package/agent/docs-md/dense-table.md +495 -0
- package/agent/docs-md/design-tokens.md +53 -0
- package/agent/docs-md/disabled-read-only.md +75 -0
- package/agent/docs-md/drag-and-drop.md +74 -0
- package/agent/docs-md/dropdown-menu.md +137 -0
- package/agent/docs-md/edit-record.md +73 -0
- package/agent/docs-md/empty-loading-error.md +78 -0
- package/agent/docs-md/empty-state.md +128 -0
- package/agent/docs-md/error-messages.md +75 -0
- package/agent/docs-md/error-state.md +123 -0
- package/agent/docs-md/export-menu.md +86 -0
- package/agent/docs-md/feedback-prompt.md +88 -0
- package/agent/docs-md/field-mapping.md +78 -0
- package/agent/docs-md/file-drop.md +110 -0
- package/agent/docs-md/filter-bar.md +138 -0
- package/agent/docs-md/filter-panel.md +103 -0
- package/agent/docs-md/filtering-search.md +79 -0
- package/agent/docs-md/follow-ups-starters.md +79 -0
- package/agent/docs-md/form-validation.md +95 -0
- package/agent/docs-md/generated-columns.md +65 -0
- package/agent/docs-md/generated-drafts-files.md +71 -0
- package/agent/docs-md/grouped-list.md +89 -0
- package/agent/docs-md/guide-cue.md +170 -0
- package/agent/docs-md/help-panel.md +103 -0
- package/agent/docs-md/help-system.md +74 -0
- package/agent/docs-md/iconography.md +49 -0
- package/agent/docs-md/inbox.md +108 -0
- package/agent/docs-md/inline-editing-validation.md +80 -0
- package/agent/docs-md/inline-input-in-answer.md +70 -0
- package/agent/docs-md/items-palette.md +116 -0
- package/agent/docs-md/keyboard-model.md +47 -0
- package/agent/docs-md/keyboard-navigation.md +68 -0
- package/agent/docs-md/keyboard-shortcut-hint.md +87 -0
- package/agent/docs-md/keyboard-shortcut-sheet.md +90 -0
- package/agent/docs-md/labelling-ai-output.md +66 -0
- package/agent/docs-md/layout.md +47 -0
- package/agent/docs-md/list-table.md +254 -0
- package/agent/docs-md/loading-skeleton.md +91 -0
- package/agent/docs-md/managing-agents.md +71 -0
- package/agent/docs-md/message-composer.md +105 -0
- package/agent/docs-md/migrating.md +49 -0
- package/agent/docs-md/motion.md +93 -0
- package/agent/docs-md/navigation.md +76 -0
- package/agent/docs-md/notification-channels.md +65 -0
- package/agent/docs-md/notifications-decision.md +100 -0
- package/agent/docs-md/onboarding-step.md +114 -0
- package/agent/docs-md/order-book.md +108 -0
- package/agent/docs-md/page-header.md +96 -0
- package/agent/docs-md/pagination.md +88 -0
- package/agent/docs-md/pane-layout.md +105 -0
- package/agent/docs-md/period-comparison.md +66 -0
- package/agent/docs-md/plan-card.md +120 -0
- package/agent/docs-md/popover-rules.md +88 -0
- package/agent/docs-md/prompt-editor.md +90 -0
- package/agent/docs-md/propose-apply.md +65 -0
- package/agent/docs-md/provider-logo.md +97 -0
- package/agent/docs-md/radio.md +83 -0
- package/agent/docs-md/ranked-list.md +102 -0
- package/agent/docs-md/reasoning-progress.md +72 -0
- package/agent/docs-md/record-detail.md +71 -0
- package/agent/docs-md/regenerating-answers.md +70 -0
- package/agent/docs-md/run-status-bar.md +94 -0
- package/agent/docs-md/saved-tasks-schedules.md +63 -0
- package/agent/docs-md/saved-views.md +149 -0
- package/agent/docs-md/saving-views.md +68 -0
- package/agent/docs-md/scheduler.md +258 -0
- package/agent/docs-md/secondary-panels.md +72 -0
- package/agent/docs-md/segmented-control.md +88 -0
- package/agent/docs-md/selection-bulk-actions.md +70 -0
- package/agent/docs-md/separator.md +75 -0
- package/agent/docs-md/setup-checklist.md +92 -0
- package/agent/docs-md/shape-elevation.md +55 -0
- package/agent/docs-md/sheet-grid.md +211 -0
- package/agent/docs-md/side-panel.md +134 -0
- package/agent/docs-md/sign-in.md +114 -0
- package/agent/docs-md/spacing.md +55 -0
- package/agent/docs-md/split-button.md +100 -0
- package/agent/docs-md/stat-compare.md +82 -0
- package/agent/docs-md/static-dashboard.md +75 -0
- package/agent/docs-md/status-badge.md +140 -0
- package/agent/docs-md/step-card.md +75 -0
- package/agent/docs-md/stepper.md +92 -0
- package/agent/docs-md/suggested-changes.md +91 -0
- package/agent/docs-md/switch.md +78 -0
- package/agent/docs-md/table-settings.md +81 -0
- package/agent/docs-md/tabs.md +85 -0
- package/agent/docs-md/tag-input.md +108 -0
- package/agent/docs-md/tag.md +79 -0
- package/agent/docs-md/task-builder.md +87 -0
- package/agent/docs-md/team-instructions.md +72 -0
- package/agent/docs-md/templates-gallery.md +85 -0
- package/agent/docs-md/text-input.md +160 -0
- package/agent/docs-md/thinking-steps.md +89 -0
- package/agent/docs-md/timeline.md +189 -0
- package/agent/docs-md/timestamp.md +84 -0
- package/agent/docs-md/timestamps.md +70 -0
- package/agent/docs-md/toast.md +117 -0
- package/agent/docs-md/tooltip.md +90 -0
- package/agent/docs-md/typography.md +62 -0
- package/agent/docs-md/undo-destructive.md +66 -0
- package/agent/docs-md/unsaved-changes.md +71 -0
- package/agent/docs-md/usage-meter.md +80 -0
- package/agent/docs-md/user-feedback.md +71 -0
- package/agent/docs-md/voice-and-tone.md +60 -0
- package/agent/docs-md/why-choice.md +93 -0
- package/agent/docs-md/workspace-onboarding.md +74 -0
- package/agent/docs-md/writing.md +48 -0
- package/agent/llms-full.txt +18369 -0
- package/agent/llms.txt +198 -0
- package/agent/skills/twoux-audit/SKILL.md +49 -0
- package/agent/skills/twoux-build/SKILL.md +39 -0
- package/agent/skills/twoux-design/SKILL.md +54 -0
- package/agent/skills/twoux-write/SKILL.md +32 -0
- package/bin/check.mjs +123 -0
- package/bin/docs.mjs +24 -0
- package/bin/guard.mjs +27 -0
- package/bin/init.mjs +113 -0
- package/bin/knowledge.mjs +87 -0
- package/bin/mcp.mjs +116 -0
- package/bin/theme.mjs +168 -0
- package/bin/twoux.mjs +25 -0
- package/package.json +80 -3
- package/registry/jobs.json +1028 -0
- package/registry/palette.json +770 -0
- package/registry/rules.json +913 -0
- package/src/components/agent-review.tsx +364 -0
- package/src/components/ai-basics.tsx +212 -0
- package/src/components/ai-work.tsx +304 -0
- package/src/components/ai.tsx +227 -0
- package/src/components/alert-dialog.tsx +203 -0
- package/src/components/alert.tsx +86 -0
- package/src/components/avatar.tsx +114 -0
- package/src/components/badge.tsx +59 -0
- package/src/components/board.tsx +397 -0
- package/src/components/breadcrumb.tsx +114 -0
- package/src/components/button-group.tsx +90 -0
- package/src/components/button.tsx +109 -0
- package/src/components/calendar.tsx +247 -0
- package/src/components/card.tsx +102 -0
- package/src/components/chart-map.tsx +336 -0
- package/src/components/charts-more.tsx +1331 -0
- package/src/components/charts-radial.tsx +328 -0
- package/src/components/charts.tsx +390 -0
- package/src/components/checkbox.tsx +40 -0
- package/src/components/code.tsx +139 -0
- package/src/components/collapsible.tsx +37 -0
- package/src/components/combobox.tsx +339 -0
- package/src/components/command-extras.tsx +11 -0
- package/src/components/command.tsx +196 -0
- package/src/components/data-grid.tsx +213 -0
- package/src/components/data-table.tsx +334 -0
- package/src/components/data-views.tsx +740 -0
- package/src/components/date-picker.tsx +686 -0
- package/src/components/dense-table.tsx +207 -0
- package/src/components/dialog.tsx +162 -0
- package/src/components/dropdown-menu.tsx +264 -0
- package/src/components/empty.tsx +114 -0
- package/src/components/feedback-prompt.tsx +80 -0
- package/src/components/field.tsx +254 -0
- package/src/components/fields.tsx +112 -0
- package/src/components/flow.tsx +840 -0
- package/src/components/guide-cue.tsx +273 -0
- package/src/components/inbox.tsx +113 -0
- package/src/components/input-group.tsx +176 -0
- package/src/components/input.tsx +26 -0
- package/src/components/kbd.tsx +34 -0
- package/src/components/label.tsx +27 -0
- package/src/components/labels.tsx +176 -0
- package/src/components/motion.tsx +136 -0
- package/src/components/onboarding.tsx +454 -0
- package/src/components/order-book.tsx +185 -0
- package/src/components/pane-layout.tsx +417 -0
- package/src/components/popover.tsx +96 -0
- package/src/components/provider-logos.data.ts +49 -0
- package/src/components/radio-group.tsx +52 -0
- package/src/components/scheduler.tsx +997 -0
- package/src/components/segmented-control.tsx +28 -0
- package/src/components/select.tsx +195 -0
- package/src/components/separator.tsx +31 -0
- package/src/components/sheet.tsx +148 -0
- package/src/components/shell.tsx +426 -0
- package/src/components/shortcut-sheet.tsx +83 -0
- package/src/components/skeleton.tsx +18 -0
- package/src/components/sonner.tsx +107 -0
- package/src/components/spinner.tsx +13 -0
- package/src/components/split-button.tsx +58 -0
- package/src/components/stepper.tsx +78 -0
- package/src/components/switch.tsx +43 -0
- package/src/components/table.tsx +126 -0
- package/src/components/tabs.tsx +118 -0
- package/src/components/tag-input.tsx +253 -0
- package/src/components/textarea.tsx +21 -0
- package/src/components/theme.tsx +80 -0
- package/src/components/timeline.tsx +408 -0
- package/src/components/toggle-group.tsx +87 -0
- package/src/components/toggle.tsx +54 -0
- package/src/components/tooltip.tsx +65 -0
- package/src/components/workspace-actions.tsx +294 -0
- package/src/components/workspace-import.tsx +465 -0
- package/src/components/workspace.tsx +1884 -0
- package/src/index.ts +80 -0
- package/src/lib/active-indicator.tsx +53 -0
- package/src/lib/chart-kit.tsx +72 -0
- package/src/lib/cn.ts +6 -0
- package/src/lib/shortcuts.tsx +61 -0
- package/src/lib/workspace.tsx +10 -0
- package/src/shadcn/alert-dialog.tsx +196 -0
- package/src/shadcn/alert.tsx +65 -0
- package/src/shadcn/avatar.tsx +108 -0
- package/src/shadcn/badge.tsx +47 -0
- package/src/shadcn/breadcrumb.tsx +108 -0
- package/src/shadcn/button-group.tsx +83 -0
- package/src/shadcn/button.tsx +63 -0
- package/src/shadcn/calendar.tsx +220 -0
- package/src/shadcn/card.tsx +91 -0
- package/src/shadcn/checkbox.tsx +31 -0
- package/src/shadcn/collapsible.tsx +33 -0
- package/src/shadcn/command.tsx +184 -0
- package/src/shadcn/dialog.tsx +158 -0
- package/src/shadcn/dropdown-menu.tsx +256 -0
- package/src/shadcn/empty.tsx +103 -0
- package/src/shadcn/field.tsx +248 -0
- package/src/shadcn/input-group.tsx +170 -0
- package/src/shadcn/input.tsx +20 -0
- package/src/shadcn/kbd.tsx +28 -0
- package/src/shadcn/label.tsx +23 -0
- package/src/shadcn/popover.tsx +88 -0
- package/src/shadcn/radio-group.tsx +44 -0
- package/src/shadcn/select.tsx +189 -0
- package/src/shadcn/separator.tsx +27 -0
- package/src/shadcn/sheet.tsx +142 -0
- package/src/shadcn/skeleton.tsx +13 -0
- package/src/shadcn/sonner.tsx +40 -0
- package/src/shadcn/switch.tsx +34 -0
- package/src/shadcn/table.tsx +115 -0
- package/src/shadcn/tabs.tsx +90 -0
- package/src/shadcn/textarea.tsx +17 -0
- package/src/shadcn/toggle-group.tsx +83 -0
- package/src/shadcn/toggle.tsx +46 -0
- package/src/shadcn/tooltip.tsx +56 -0
- package/src/styles/palette.css +127 -0
- package/src/styles/theme.css +35 -0
- package/src/styles/twoux.css +236 -0
- package/theme.json +14 -0
- package/README.md +0 -3
|
@@ -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
|