@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.
- package/LICENSE.md +61 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/NOTICE.md +64 -0
- package/README.md +211 -2
- 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
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Command palette (⌘K)
|
|
2
|
+
|
|
3
|
+
A searchable list of actions and destinations, scoped to the current selection, opened with ⌘K from anywhere.
|
|
4
|
+
|
|
5
|
+
Kind: component · Group: Navigation · Status: built, import from @twoux/ui
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
- Run any action by name without hunting through menus, especially on a selection of rows.
|
|
10
|
+
- Jump to a record or page by typing part of its name.
|
|
11
|
+
- Learn shortcuts: every action shows its key, so the palette teaches the faster path.
|
|
12
|
+
|
|
13
|
+
## When not to use
|
|
14
|
+
|
|
15
|
+
- As the only way to reach an action. Every command also exists as a visible button or menu item.
|
|
16
|
+
- Filtering the table. Use Filter (F) and its type-ahead field list.
|
|
17
|
+
- Confirming irreversible actions. A destructive command picked in the palette still opens the Confirmation dialog.
|
|
18
|
+
|
|
19
|
+
## Structure
|
|
20
|
+
|
|
21
|
+
1. Search input with a scope chip ("2 listings") and Esc hint
|
|
22
|
+
2. Group: Actions on selection, each with its shortcut
|
|
23
|
+
3. Group: Go to (records and pages)
|
|
24
|
+
4. Footer hints: ↑ ↓ navigate, ↵ run, Tab change scope
|
|
25
|
+
|
|
26
|
+
## Guidelines
|
|
27
|
+
|
|
28
|
+
- Opens centred near the top, up to 560px wide, with focus in the search input.
|
|
29
|
+
- Scope defaults to the current selection and shows it as a chip; Tab switches to the whole workspace.
|
|
30
|
+
- Order results with actions on the selection first, then Go to; show the most used actions before typing.
|
|
31
|
+
- Results update with each keystroke, within 400 ms.
|
|
32
|
+
- Enter runs the highlighted item and closes the palette; reversible results offer Undo in a toast.
|
|
33
|
+
- Esc closes it and focus returns to where it was.
|
|
34
|
+
|
|
35
|
+
## Content
|
|
36
|
+
|
|
37
|
+
- Commands start with a verb and name the object: "Extend end by 30 days", "Export 2 rows as CSV".
|
|
38
|
+
- Commands that need more input end with an ellipsis: "Extend end to a date…".
|
|
39
|
+
- Use the same command names as the buttons and menus they mirror.
|
|
40
|
+
- Placeholder text says what can be typed: "Search or run a command".
|
|
41
|
+
|
|
42
|
+
## Accessibility
|
|
43
|
+
|
|
44
|
+
- Built as a modal dialog containing a combobox with a listbox popup; DOM focus stays in the input and aria-activedescendant points to the highlighted item.
|
|
45
|
+
- Group headings are exposed as group labels and each option's shortcut is part of its accessible description (1.3.1).
|
|
46
|
+
- ⌘K uses a modifier, so it stays on when single-key shortcuts are turned off (2.1.4).
|
|
47
|
+
- Announce the number of results through a polite live region as the person types (4.1.3).
|
|
48
|
+
- Esc always exits; there is no keyboard trap (2.1.2).
|
|
49
|
+
|
|
50
|
+
## Keyboard
|
|
51
|
+
|
|
52
|
+
| Keys | Action |
|
|
53
|
+
|---|---|
|
|
54
|
+
| ⌘K / Ctrl+K | Open or close the palette |
|
|
55
|
+
| ↑ / ↓ | Move through results |
|
|
56
|
+
| Enter | Run the highlighted command |
|
|
57
|
+
| Tab | Switch scope between selection and workspace |
|
|
58
|
+
| Esc | Close and return focus |
|
|
59
|
+
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
### dialog
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { Button, CommandDialog, CommandGroup, CommandInput, CommandItem, CommandList, CommandShortcut, Kbd } from "@twoux/ui";
|
|
66
|
+
import { Search, Settings, Users } from "lucide-react";
|
|
67
|
+
import { useState } from "react";
|
|
68
|
+
|
|
69
|
+
export const meta = { title: "As a dialog (⌘K)", description: "Opens over the page, traps focus, and returns it to where it came from on close (Radix Dialog). Press the button to try.", order: 2 };
|
|
70
|
+
|
|
71
|
+
export default function Example() {
|
|
72
|
+
const [open, setOpen] = useState(false);
|
|
73
|
+
return (
|
|
74
|
+
<>
|
|
75
|
+
<Button shortcut="⌘K" onClick={() => setOpen(true)} variant="outline"><Search />Search</Button>
|
|
76
|
+
<CommandDialog open={open} onOpenChange={setOpen}>
|
|
77
|
+
<CommandInput placeholder="Search or run a command…" />
|
|
78
|
+
<CommandList>
|
|
79
|
+
<CommandGroup heading="Go to">
|
|
80
|
+
<CommandItem onSelect={() => setOpen(false)}><Users />Members</CommandItem>
|
|
81
|
+
<CommandItem onSelect={() => setOpen(false)}><Settings />Settings<CommandShortcut><Kbd>G</Kbd><Kbd>S</Kbd></CommandShortcut></CommandItem>
|
|
82
|
+
</CommandGroup>
|
|
83
|
+
</CommandList>
|
|
84
|
+
</CommandDialog>
|
|
85
|
+
</>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### inline
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { Command, CommandEmpty, CommandFooter, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Kbd } from "@twoux/ui";
|
|
94
|
+
import { Briefcase, Clock, Copy, Plus, Users } from "lucide-react";
|
|
95
|
+
|
|
96
|
+
export const meta = { title: "Commands and pages", description: "One line per item: icon, label, shortcut on the right. Groups have quiet sentence-case labels. Type to filter; arrows and Enter to run.", order: 1 };
|
|
97
|
+
|
|
98
|
+
export default function Example() {
|
|
99
|
+
return (
|
|
100
|
+
<Command className="w-full max-w-md rounded-sm border border-line shadow-card">
|
|
101
|
+
<CommandInput placeholder="Search or run a command…" />
|
|
102
|
+
<CommandList>
|
|
103
|
+
<CommandEmpty>No results. Try “extend” or “listings”.</CommandEmpty>
|
|
104
|
+
<CommandGroup heading="Actions on 2 listings">
|
|
105
|
+
<CommandItem><Clock />Extend by 30 days<CommandShortcut><Kbd>T</Kbd></CommandShortcut></CommandItem>
|
|
106
|
+
<CommandItem><Copy />Duplicate<CommandShortcut><Kbd>D</Kbd></CommandShortcut></CommandItem>
|
|
107
|
+
</CommandGroup>
|
|
108
|
+
<CommandSeparator />
|
|
109
|
+
<CommandGroup heading="Go to">
|
|
110
|
+
<CommandItem><Briefcase />Listings<CommandShortcut><Kbd>G</Kbd><Kbd>L</Kbd></CommandShortcut></CommandItem>
|
|
111
|
+
<CommandItem><Users />Pipeline<CommandShortcut><Kbd>G</Kbd><Kbd>P</Kbd></CommandShortcut></CommandItem>
|
|
112
|
+
<CommandItem><Plus />New listing<CommandShortcut><Kbd>C</Kbd></CommandShortcut></CommandItem>
|
|
113
|
+
</CommandGroup>
|
|
114
|
+
</CommandList>
|
|
115
|
+
<CommandFooter><span className="flex items-center gap-1"><Kbd>↵</Kbd> run</span><span className="flex items-center gap-1"><Kbd>esc</Kbd> close</span></CommandFooter>
|
|
116
|
+
</Command>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Related
|
|
122
|
+
|
|
123
|
+
- Shortcut sheet (?)
|
|
124
|
+
- App shell and sidebar navigation
|
|
125
|
+
- Page header
|
|
126
|
+
- Toast
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Confidence note
|
|
2
|
+
|
|
3
|
+
A short note beside agent output that says, in words, what the agent is unsure about, why, and the safer option or the way to check.
|
|
4
|
+
|
|
5
|
+
Kind: component · Group: AI and agents · Status: built, import from @twoux/ui
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
- When the output affects other people, shared records or money and the agent has a real reason to be unsure.
|
|
10
|
+
- When the cause is specific: missing data, out-of-date data, or an ambiguous request.
|
|
11
|
+
- When the agent is unsure whether a change applies to one item, all items or future items. Ask before acting.
|
|
12
|
+
|
|
13
|
+
## When not to use
|
|
14
|
+
|
|
15
|
+
- As a standing disclaimer on every answer. Use the caveat line under the message box (assistant-panel).
|
|
16
|
+
- To report an error. Use an error message (error-messages) with the fix.
|
|
17
|
+
- Low-stakes output the person can see and change in a second. A note there is noise people learn to skip.
|
|
18
|
+
|
|
19
|
+
## Structure
|
|
20
|
+
|
|
21
|
+
1. Lead line ("Not sure:" and the cause)
|
|
22
|
+
2. Safer option or what to check
|
|
23
|
+
3. Optional actions (for example Check the source, Use the safer option)
|
|
24
|
+
|
|
25
|
+
## Guidelines
|
|
26
|
+
|
|
27
|
+
- Say uncertainty in words, never as a percentage. A figure like 72% looks exact and gives people nothing to do.
|
|
28
|
+
- Say what caused it: missing data, out of date, or an ambiguous request.
|
|
29
|
+
- Offer a safer alternative or a concrete way to check, such as the record to open or the filter to apply.
|
|
30
|
+
- Scale to the stakes: use it when the output affects other people, shared records or money, and leave it off elsewhere.
|
|
31
|
+
- When unsure whether a change applies to one item, all items or future items, ask before acting. Do not pick the widest.
|
|
32
|
+
- Place the note next to the output it is about, not in a corner, so it is read together with it.
|
|
33
|
+
|
|
34
|
+
## Content
|
|
35
|
+
|
|
36
|
+
- Start with "Not sure:" and the cause: "Not sure: the connection is 35 minutes, and the last export was in March."
|
|
37
|
+
- Follow with what to do, as an instruction: "Check the rail times before sending this to applicants."
|
|
38
|
+
- Avoid "might", "may" and "possibly" on their own. Say which part, and why.
|
|
39
|
+
- Do not apologise. State the cause and the next step.
|
|
40
|
+
|
|
41
|
+
## Accessibility
|
|
42
|
+
|
|
43
|
+
- The cause is text with an icon that is hidden from assistive technology, so meaning does not rely on colour or the icon (SC 1.4.1).
|
|
44
|
+
- The note sits next to the output in reading order so it is read with it (SC 1.3.1).
|
|
45
|
+
- Any action in the note is a real button with a visible name (SC 4.1.2).
|
|
46
|
+
- If a note appears after the output has loaded, put it in a role="status" region so it is announced (SC 4.1.3).
|
|
47
|
+
|
|
48
|
+
## Keyboard
|
|
49
|
+
|
|
50
|
+
| Keys | Action |
|
|
51
|
+
|---|---|
|
|
52
|
+
| Tab | Move to the note's actions, if it has any |
|
|
53
|
+
| Enter / Space | Press the focused action |
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### note
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { Button, ConfidenceNote, toast } from "@twoux/ui";
|
|
61
|
+
|
|
62
|
+
export const meta = { title: "Unsure, and why", description: "The cause in words, then the safer option and a way to check. Use it when the output reaches people, shared records or money.", order: 1 };
|
|
63
|
+
|
|
64
|
+
export default function Example() {
|
|
65
|
+
return (
|
|
66
|
+
<div className="grid w-full max-w-xl gap-3">
|
|
67
|
+
<ConfidenceNote
|
|
68
|
+
cause="the venue's opening hours are from March, so they may be out of date"
|
|
69
|
+
action={<><Button size="xs" variant="outline" onClick={() => toast("Opened the venue page")}>Check the venue page</Button><Button size="xs" variant="ghost" onClick={() => toast("Draft saved without a time")}>Send without a time</Button></>}
|
|
70
|
+
>
|
|
71
|
+
Check the hours before this goes to 14 applicants. If you cannot, send the invitation without a time and ask them to reply.
|
|
72
|
+
</ConfidenceNote>
|
|
73
|
+
<ConfidenceNote cause="your request does not say whether the new closing date applies to the 3 selected listings or to every listing in this view">
|
|
74
|
+
I have not changed anything. Tell me which, and whether future listings should follow it too.
|
|
75
|
+
</ConfidenceNote>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Related
|
|
82
|
+
|
|
83
|
+
- Citations and sources
|
|
84
|
+
- Clarifying question card
|
|
85
|
+
- AI origin label
|
|
86
|
+
- Suggested changes
|
|
87
|
+
- Change review
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Configurable dashboard
|
|
2
|
+
|
|
3
|
+
A personal overview where each person adds, removes, moves and resizes items on a board, with an items palette to add from, a saved layout and a reset to the default.
|
|
4
|
+
|
|
5
|
+
Kind: pattern · Group: Patterns: data and dashboards
|
|
6
|
+
|
|
7
|
+
**Problem:** Recruiters, hiring managers and the head of talent watch different things. One fixed overview is either too crowded for each of them or missing what one of them needs, so they build their own spreadsheets instead.
|
|
8
|
+
|
|
9
|
+
**Solution:** Start from the static dashboard layout as the default, then let each person change it on a Board. Add items opens the items palette in a side panel; items move by drag, keyboard or menu; Remove is undoable and puts the item back in the palette; the layout is saved per person and Reset to default layout brings back the original.
|
|
10
|
+
|
|
11
|
+
**Built from:** Board and board item, Items palette, Side panel (drawer), Page header, Dropdown menu, Toast, Empty state, Stat card with comparison, Line chart card
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
1. Build the default layout first with the static dashboard guidelines; this is what new people see and what Reset returns to.
|
|
16
|
+
2. Put Add items in the page header. It opens the items palette in a side panel that pushes the board, and closes with the same button or Esc.
|
|
17
|
+
3. People add an item by dragging it from the palette onto the board, or by choosing Add to dashboard on the palette item, which places it at the end of the board and moves focus to it.
|
|
18
|
+
4. People move and resize items by dragging the handles, by keyboard on the handle, or from the item menu (Move earlier, Move later, Wider, Narrower, Taller, Shorter).
|
|
19
|
+
5. Remove from dashboard is the last entry in the item menu. It removes at once, shows a toast with Undo, and the item reappears in the palette.
|
|
20
|
+
6. Save every change to the person's layout on the server as it happens; there is no Save button.
|
|
21
|
+
7. Reset to default layout sits in the page header's more menu. It applies at once and offers Undo in a toast.
|
|
22
|
+
|
|
23
|
+
## When to use
|
|
24
|
+
|
|
25
|
+
- For a personal home page where people in different roles need different items, such as "My open listings" for a recruiter and "Cost per hire" for the head of talent.
|
|
26
|
+
- When there are more useful items than fit on one screen, and each person only needs some of them.
|
|
27
|
+
- When people use the page for investigation and want related items side by side.
|
|
28
|
+
|
|
29
|
+
## When not to use
|
|
30
|
+
|
|
31
|
+
- For a shared report that must read the same for everyone. Use the static dashboard.
|
|
32
|
+
- When there are fewer than about six possible items. Rearranging adds work and little value; fix the layout instead.
|
|
33
|
+
- Inside a side panel or dialog. The board is the main content of its page.
|
|
34
|
+
|
|
35
|
+
## Guidelines
|
|
36
|
+
|
|
37
|
+
- Make the whole page configurable or none of it. Don't pin some items in place among movable ones.
|
|
38
|
+
- Moving an item keeps its size, its settings and what it shows, such as the period or the location it is set to.
|
|
39
|
+
- Show a drop preview the size and shape of the item while dragging. Items swap when there is room and push others along when there is not; a drop outside the board puts the item back.
|
|
40
|
+
- The board has 4 columns on wide screens, 2 on tablets and 1 on phones. Store one layout per column count, so a change on a laptop doesn't scramble the phone layout.
|
|
41
|
+
- Layouts are personal. Changing yours never changes a colleague's dashboard or the workspace default.
|
|
42
|
+
- When the board is empty, show an empty state with Add items and Reset to default layout.
|
|
43
|
+
|
|
44
|
+
## Content
|
|
45
|
+
|
|
46
|
+
- Header actions: "Add items" and, in the more menu, "Reset to default layout".
|
|
47
|
+
- Removal toast names the item: "Removed Applications this week. Undo".
|
|
48
|
+
- Reset toast: "Dashboard reset to the default layout. Undo".
|
|
49
|
+
- Empty board: "Your dashboard has no items" with "Add items to see your hiring numbers here."
|
|
50
|
+
|
|
51
|
+
## Accessibility
|
|
52
|
+
|
|
53
|
+
- Dragging is never the only way: every add, move and resize also works by keyboard and from a menu or button with a single pointer action.
|
|
54
|
+
- Announce each pick-up, move, resize, drop, add and removal in a polite live region, naming the item and its new position: "Applications this week moved to row 1, column 2".
|
|
55
|
+
- After Add to dashboard, move focus to the new item's handle; after Remove, move focus to the next item, or to Add items if the board is now empty.
|
|
56
|
+
- Drag and resize handles have names that include the item title: "Move Applications this week", "Resize Applications this week".
|
|
57
|
+
|
|
58
|
+
## Do
|
|
59
|
+
|
|
60
|
+
- Do return a removed item to the palette so it can be added again.
|
|
61
|
+
- Do keep Remove and Add items close in meaning and in place: one undoes the other.
|
|
62
|
+
- Do keep the layout the person made on their next visit and on any device with the same column count.
|
|
63
|
+
|
|
64
|
+
## Don't
|
|
65
|
+
|
|
66
|
+
- Don't ask for confirmation before removing an item; offer Undo.
|
|
67
|
+
- Don't show a banner inside the board after a removal. The toast is enough.
|
|
68
|
+
- Don't store the layout only in the browser; it is lost on another device or after clearing data.
|
|
69
|
+
|
|
70
|
+
## Related
|
|
71
|
+
|
|
72
|
+
- Static dashboard
|
|
73
|
+
- Dashboard items
|
|
74
|
+
- Board and board item
|
|
75
|
+
- Items palette
|
|
76
|
+
- Undo and destructive actions
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Confirmation dialog
|
|
2
|
+
|
|
3
|
+
A modal question before an irreversible or high-impact action, stating the consequence and offering the safe option first.
|
|
4
|
+
|
|
5
|
+
Kind: component · Group: Feedback and overlays · Status: built, import from @twoux/ui
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
- Before actions that cannot be undone or that affect other people, such as closing listings that stop taking applications.
|
|
10
|
+
- Bulk actions on many records where a mistake is costly to repair.
|
|
11
|
+
- When the person must read a consequence they could not otherwise see, such as what happens to existing applicants.
|
|
12
|
+
|
|
13
|
+
## When not to use
|
|
14
|
+
|
|
15
|
+
- Reversible actions. Do them at once and offer Undo in a Toast.
|
|
16
|
+
- Collecting lots of input or showing a record. Use the Side panel.
|
|
17
|
+
- Reporting an error. Use a Banner or the Error state in place.
|
|
18
|
+
- Low-risk actions that are easy to redo, which need no confirmation at all.
|
|
19
|
+
|
|
20
|
+
## Structure
|
|
21
|
+
|
|
22
|
+
1. Title: a question naming the action and count ("Close 2 listings?")
|
|
23
|
+
2. Body: the consequence, and what is kept
|
|
24
|
+
3. Footer: safe secondary button ("Keep open")
|
|
25
|
+
4. Footer: destructive button named after the action ("Close listings")
|
|
26
|
+
|
|
27
|
+
## Guidelines
|
|
28
|
+
|
|
29
|
+
- Width up to 420px, centred, with the page dimmed behind it. One dialog at a time; never open a dialog from a dialog.
|
|
30
|
+
- Footer buttons sit on the right: the safe option first, the destructive action last in the destructive colour.
|
|
31
|
+
- On open, focus goes to the safe button, so Enter cannot destroy anything by accident.
|
|
32
|
+
- Esc and the safe button both close it with no change. On close, focus returns to the control that opened it.
|
|
33
|
+
- For the most dangerous, rare actions, require an unusual step such as typing the listing name.
|
|
34
|
+
- After confirming, report the result with a Toast.
|
|
35
|
+
|
|
36
|
+
## Content
|
|
37
|
+
|
|
38
|
+
- Title as a specific question with the verb and the object: "Close 2 listings?", never "Are you sure?".
|
|
39
|
+
- Body states the consequence and what stays: "They stop taking applications now. The 140 people who already applied stay in your pipeline."
|
|
40
|
+
- Buttons name the outcome ("Keep open", "Close listings"), never Yes, No or OK.
|
|
41
|
+
- The confirm label matches the title's verb.
|
|
42
|
+
|
|
43
|
+
## Accessibility
|
|
44
|
+
|
|
45
|
+
- Use role="alertdialog" with aria-modal="true", aria-labelledby on the title and aria-describedby on the consequence.
|
|
46
|
+
- Tab and Shift+Tab cycle inside the dialog; Esc closes it, so focus is contained but never trapped (2.1.2).
|
|
47
|
+
- Focus returns to the opener on close, or to the next logical row if the opener was removed (2.4.3).
|
|
48
|
+
- Confirming before data changes is one of the three ways to meet 3.3.4 Error Prevention.
|
|
49
|
+
- The destructive button is identified by its label, not only its red colour (1.4.1).
|
|
50
|
+
|
|
51
|
+
## Keyboard
|
|
52
|
+
|
|
53
|
+
| Keys | Action |
|
|
54
|
+
|---|---|
|
|
55
|
+
| Tab / ⇧Tab | Move between the two buttons, wrapping inside the dialog |
|
|
56
|
+
| Enter | Activates the focused button (the safe one on open) |
|
|
57
|
+
| Esc | Closes without changing anything |
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
### close-listings
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Button, toast } from "@twoux/ui";
|
|
65
|
+
|
|
66
|
+
export const meta = { title: "Close listings", description: "Closing removes listings from job boards and cannot be undone. Focus starts on the safe button, so Enter keeps them open. Esc does the same.", order: 1 };
|
|
67
|
+
|
|
68
|
+
export default function Example() {
|
|
69
|
+
return (
|
|
70
|
+
<AlertDialog>
|
|
71
|
+
<AlertDialogTrigger asChild>
|
|
72
|
+
<Button variant="outline">Close 2 listings</Button>
|
|
73
|
+
</AlertDialogTrigger>
|
|
74
|
+
<AlertDialogContent>
|
|
75
|
+
<AlertDialogHeader>
|
|
76
|
+
<AlertDialogTitle>Close 2 listings?</AlertDialogTitle>
|
|
77
|
+
<AlertDialogDescription>They come off every job board today. Applicants and notes are kept, but the listings cannot be reopened.</AlertDialogDescription>
|
|
78
|
+
</AlertDialogHeader>
|
|
79
|
+
<AlertDialogFooter>
|
|
80
|
+
<AlertDialogCancel>Keep open</AlertDialogCancel>
|
|
81
|
+
<AlertDialogAction variant="destructive" onClick={() => toast.success("2 listings closed")}>Close listings</AlertDialogAction>
|
|
82
|
+
</AlertDialogFooter>
|
|
83
|
+
</AlertDialogContent>
|
|
84
|
+
</AlertDialog>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Related
|
|
90
|
+
|
|
91
|
+
- Toast
|
|
92
|
+
- Side panel (drawer)
|
|
93
|
+
- Shortcut sheet (?)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Connected tools
|
|
2
|
+
|
|
3
|
+
Outside tools listed in the + menu and settings, each with a detail card saying what it can read and change, where data is stored and who connected it.
|
|
4
|
+
|
|
5
|
+
Kind: component · Group: AI and agents · Status: built, import from @twoux/ui
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
- Connecting a tool at the moment it is needed, from the + menu.
|
|
10
|
+
- Reviewing what a connected tool can access.
|
|
11
|
+
|
|
12
|
+
## When not to use
|
|
13
|
+
|
|
14
|
+
- Setting what the agent may do with TwoUX data. Use Agent permissions (agent-permissions).
|
|
15
|
+
- Adding a single file. Use Attach a file in the Message composer (message-composer).
|
|
16
|
+
|
|
17
|
+
## Structure
|
|
18
|
+
|
|
19
|
+
1. Tools menu (tool, status, Connect, Browse tools)
|
|
20
|
+
2. Detail card (name, type, status badge, description, Can read, Can change, Data stored, Connected by, Privacy policy, Disconnect, Permissions)
|
|
21
|
+
|
|
22
|
+
## Guidelines
|
|
23
|
+
|
|
24
|
+
- Before and after connecting, say in plain words what it can read and change, where data is stored and who connected it.
|
|
25
|
+
- Let people scope a tool to what it needs.
|
|
26
|
+
- Give each tool a consistent icon and name across menus and answers.
|
|
27
|
+
- When a tool fails or is partly loaded, say so inline and offer reconnect or retry; avoid blank states that imply success.
|
|
28
|
+
- Show when data was last synced.
|
|
29
|
+
|
|
30
|
+
## Content
|
|
31
|
+
|
|
32
|
+
- "Brings candidates and pipeline stages into TwoUX so the assistant can compare them with your listings."
|
|
33
|
+
- Use "Nothing" rather than leaving Can change empty.
|
|
34
|
+
|
|
35
|
+
## Accessibility
|
|
36
|
+
|
|
37
|
+
- The tools list is a menu; each tool is a menuitemcheckbox when it toggles use, or a menuitem when it connects (APG menu).
|
|
38
|
+
- The detail card uses a description list for its fields (SC 1.3.1).
|
|
39
|
+
- Disconnect is a destructive action; confirm with the consequence and keep focus order (SC 2.4.3, 3.3.4).
|
|
40
|
+
|
|
41
|
+
## Keyboard
|
|
42
|
+
|
|
43
|
+
| Keys | Action |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Right arrow | Open the tools submenu from the + menu |
|
|
46
|
+
| Space | Turn a connected tool on or off for this conversation |
|
|
47
|
+
| Enter | Connect or open the tool |
|
|
48
|
+
| Esc | Close the menu |
|
|
49
|
+
|
|
50
|
+
## Examples
|
|
51
|
+
|
|
52
|
+
### tool
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { ConnectedToolCard, toast } from "@twoux/ui";
|
|
56
|
+
import { useState } from "react";
|
|
57
|
+
|
|
58
|
+
export const meta = { title: "Say what a tool can do", description: "Before and after connecting: what it can read, what it can change, where data is stored and who connected it.", order: 1 };
|
|
59
|
+
|
|
60
|
+
export default function Example() {
|
|
61
|
+
const [on, setOn] = useState(true);
|
|
62
|
+
return (
|
|
63
|
+
<div className="w-full max-w-md">
|
|
64
|
+
<ConnectedToolCard
|
|
65
|
+
tool={{ id: "cal", name: "Google Calendar", kind: "Calendar", connected: on, canRead: "Free and busy times of interviewers", canChange: "Nothing. It suggests interview slots only.", stored: "Not stored; read when you ask", connectedBy: on ? "Priya Shah on 3 Nov" : undefined, privacyHref: "#privacy" }}
|
|
66
|
+
onConnect={() => { setOn(true); toast.success("Connected Google Calendar"); }}
|
|
67
|
+
onDisconnect={() => { setOn(false); toast.success("Disconnected Google Calendar", { action: { label: "Undo", onClick: () => setOn(true) } }); }}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Related
|
|
75
|
+
|
|
76
|
+
- Agent permissions
|
|
77
|
+
- Message composer
|
|
78
|
+
- Team instructions and files
|
|
79
|
+
- Connector picker
|
|
80
|
+
- Provider logo
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Connector picker
|
|
2
|
+
|
|
3
|
+
Search and connect outside services. Each row says what connecting lets the product do, and a dialog explains the access before anything is shared.
|
|
4
|
+
|
|
5
|
+
Kind: component · Group: Actions and inputs · Status: built, import from @twoux/ui
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
- Connecting several outside services, from onboarding or from Settings.
|
|
10
|
+
- Showing what is connected and what needs attention in one place.
|
|
11
|
+
|
|
12
|
+
## When not to use
|
|
13
|
+
|
|
14
|
+
- Setting what an agent may do with a tool. Use Agent permissions (agent-permissions).
|
|
15
|
+
- Reviewing one tool in depth. Use the detail card in Connected tools (connected-tools).
|
|
16
|
+
|
|
17
|
+
## Structure
|
|
18
|
+
|
|
19
|
+
1. Search (with the number of services)
|
|
20
|
+
2. Connected group
|
|
21
|
+
3. All services group
|
|
22
|
+
4. Row (logo, name, what it lets the product do, Connect, Reconnect or Manage)
|
|
23
|
+
5. Connect dialog (access in plain words, who it is shared with, OAuth or API key, Cancel)
|
|
24
|
+
|
|
25
|
+
## Guidelines
|
|
26
|
+
|
|
27
|
+
- Add search with the count of services, and put Connected first.
|
|
28
|
+
- Say what connecting lets the product do, in plain words, before connecting: "Read and send email".
|
|
29
|
+
- Say who the connection is shared with, for example "Only you" or "Everyone in TwoUX".
|
|
30
|
+
- OAuth opens the provider in a new window. Say so on the button ("Continue to Slack") and bring people back with a status message.
|
|
31
|
+
- Test an API key before saving it, store it encrypted and never show it again. Say all three beside the field.
|
|
32
|
+
- When a connection expires, show Needs attention with the reason and a Reconnect button, never colour alone.
|
|
33
|
+
- Disconnecting lives in Settings and asks what stops working before it does.
|
|
34
|
+
|
|
35
|
+
## Content
|
|
36
|
+
|
|
37
|
+
- "Read your calendar to find free times. Cannot change events."
|
|
38
|
+
- "Slack needs you to sign in again. Reconnect to resume the daily summary."
|
|
39
|
+
|
|
40
|
+
## Accessibility
|
|
41
|
+
|
|
42
|
+
- Rows are a list under group headings; the group names are real headings (SC 1.3.1).
|
|
43
|
+
- Buttons repeat the service name for assistive technology: "Connect Slack" (SC 2.4.6, 4.1.2).
|
|
44
|
+
- The dialog traps focus, returns it to the button and announces success with role="status" (APG dialog, SC 4.1.3).
|
|
45
|
+
- Status is carried by words (Connected, Needs attention) as well as colour (SC 1.4.1).
|
|
46
|
+
|
|
47
|
+
## Keyboard
|
|
48
|
+
|
|
49
|
+
| Keys | Action |
|
|
50
|
+
|---|---|
|
|
51
|
+
| Tab | Move through the search, then each row's button |
|
|
52
|
+
| Enter or Space | Connect, Reconnect or Manage |
|
|
53
|
+
| Esc | Close the dialog without connecting |
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### api-key
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { Button, ConnectDialog, type Connector } from "@twoux/ui";
|
|
61
|
+
import { useState } from "react";
|
|
62
|
+
|
|
63
|
+
export const meta = { title: "Connect with an API key", description: "The key is tested before it is saved. Try any text to see the error, or \"nw-live-key\" to connect.", order: 2 };
|
|
64
|
+
|
|
65
|
+
const XERO: Connector = { id: "xero", provider: "xero", can: ["Read invoices and payments", "Cannot create or change anything"] };
|
|
66
|
+
|
|
67
|
+
export default function Example() {
|
|
68
|
+
const [open, setOpen] = useState(false);
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
<Button variant="outline" onClick={() => setOpen(true)}>Connect Xero</Button>
|
|
72
|
+
<ConnectDialog
|
|
73
|
+
connector={XERO}
|
|
74
|
+
open={open}
|
|
75
|
+
onOpenChange={setOpen}
|
|
76
|
+
method="apikey"
|
|
77
|
+
scope="Only you"
|
|
78
|
+
onTestKey={async (key) => { await new Promise((r) => setTimeout(r, 700)); return key === "nw-live-key" ? undefined : "Xero did not accept that key. Check you copied all of it from Settings, API keys."; }}
|
|
79
|
+
onDone={() => {}}
|
|
80
|
+
/>
|
|
81
|
+
</>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### connect-oauth
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { ConnectDialog, ConnectorPicker, toast, type Connector } from "@twoux/ui";
|
|
90
|
+
import { useState } from "react";
|
|
91
|
+
|
|
92
|
+
export const meta = { title: "Search, connect, reconnect", description: "Connected first, then everything else. Slack shows Needs attention with Reconnect. Connecting asks first, in plain words.", order: 1 };
|
|
93
|
+
|
|
94
|
+
const START: Connector[] = [
|
|
95
|
+
{ id: "gmail", provider: "gmail", can: ["Read and send email as you", "Find threads about a candidate"], connected: true },
|
|
96
|
+
{ id: "slack", provider: "slack", can: ["Post summaries to channels you pick", "Read messages in those channels"], connected: true, problem: "Your Slack sign-in expired. Reconnect to resume the daily summary." },
|
|
97
|
+
{ id: "calendar", provider: "google-calendar", can: ["Read free and busy times", "Create interview events"] },
|
|
98
|
+
{ id: "drive", provider: "google-drive", can: ["Read files you choose", "Never change or delete files"] },
|
|
99
|
+
{ id: "notion", provider: "notion", can: ["Read pages you share with it", "Add notes to a database"] },
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
export default function Example() {
|
|
103
|
+
const [list, setList] = useState(START);
|
|
104
|
+
const [open, setOpen] = useState<Connector | null>(null);
|
|
105
|
+
return (
|
|
106
|
+
<div className="w-full max-w-lg">
|
|
107
|
+
<ConnectorPicker connectors={list} onConnect={setOpen} onManage={() => toast("Manage opens Settings, Connections")} />
|
|
108
|
+
<ConnectDialog
|
|
109
|
+
connector={open}
|
|
110
|
+
open={!!open}
|
|
111
|
+
onOpenChange={(o) => !o && setOpen(null)}
|
|
112
|
+
scope="Everyone in TwoUX"
|
|
113
|
+
onAuthorise={() => new Promise((r) => setTimeout(r, 1000))}
|
|
114
|
+
onDone={() => open && setList((l) => l.map((c) => (c.id === open.id ? { ...c, connected: true, problem: undefined } : c)))}
|
|
115
|
+
/>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Related
|
|
122
|
+
|
|
123
|
+
- Connected tools
|
|
124
|
+
- Agent permissions
|
|
125
|
+
- Provider logo
|
|
126
|
+
- Empty state
|
|
127
|
+
- Confirmation dialog
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Consistency
|
|
2
|
+
|
|
3
|
+
TwoUX's first rule: the same job gets the same component, the same token and the same behaviour, on every screen, whether a designer, an engineer or a language model wrote the code. Consistency is what makes a dense product learnable.
|
|
4
|
+
|
|
5
|
+
Kind: foundation · Group: Key principles
|
|
6
|
+
|
|
7
|
+
## Principles
|
|
8
|
+
|
|
9
|
+
- Same job, same component. People should not have to wonder whether different words, situations or actions mean the same thing.
|
|
10
|
+
- Consistency is also a WCAG requirement. Components with the same function are identified the same way (3.2.4) and repeated navigation keeps its order (3.2.3).
|
|
11
|
+
- Learn once, use everywhere. People transfer expectations from what they already know, inside the product as much as between products.
|
|
12
|
+
- A design system manages design at scale with reusable components and patterns; its value is lost the first time someone rebuilds a component by hand.
|
|
13
|
+
|
|
14
|
+
## Guidelines
|
|
15
|
+
|
|
16
|
+
- The job to component registry is the source of truth. Each row names a job and the one component that does it. Examples: show a record's state = Badge; confirm a destructive action = Dialog; peek at a record from a list = Side panel; run any command = Command menu (⌘K); ask the assistant = Assistant (⌘J); act on many rows = Bulk bar; show a one-line result with undo = Toast; filter a list = Filter pill.
|
|
17
|
+
- If a job is not in the registry, do not improvise. Propose a new row, or extend an existing component, through design review. Always check for an existing component before building a custom one.
|
|
18
|
+
- No one-off styling. Product code sets no colours, font sizes, radii, shadows or spacing; those come from components and tokens.
|
|
19
|
+
- Same behaviour, too: Esc closes the innermost layer, J and K move through every list, ↵ opens, ⇧↵ opens full page. A component that behaves differently in one place is a different component.
|
|
20
|
+
- Same words: one term per concept (listing, not job post in one place and role in another), and the same button label for the same action.
|
|
21
|
+
|
|
22
|
+
## Content
|
|
23
|
+
|
|
24
|
+
- Rules for code written by language models: 1. Import components from the TwoUX package; never recreate a button, badge, menu or panel with raw HTML and CSS.
|
|
25
|
+
- 2. Look up the job in the registry before choosing a component. If two components could fit, the registry decides.
|
|
26
|
+
- 3. Use tokens only. No hex, rgb, raw px font sizes, raw radii, raw shadows or raw durations. Choose the token by its role, not its value.
|
|
27
|
+
- 4. Use the icon meaning table; never pick an icon because it looks right.
|
|
28
|
+
- 5. Copy follows the Writing page: UK English, sentence case, verb-first buttons.
|
|
29
|
+
- 6. Lint must pass. Stylelint and ESLint rules reject raw values and unknown tokens. A generated change that needs a lint exception goes to human review.
|
|
30
|
+
|
|
31
|
+
## Accessibility
|
|
32
|
+
|
|
33
|
+
- Predictable components are an accessibility feature: the same icon and the same accessible name for the same function.
|
|
34
|
+
- Navigation and the shell appear in the same order on every page.
|
|
35
|
+
- Reusing tested components carries their keyboard and focus behaviour; custom components lack built-in testing and accessibility.
|
|
36
|
+
|
|
37
|
+
## Do
|
|
38
|
+
|
|
39
|
+
- Use the Toast for every 'done, undo?' message, from bulk close to AI actions.
|
|
40
|
+
- Add to the registry when you add a component.
|
|
41
|
+
|
|
42
|
+
## Don't
|
|
43
|
+
|
|
44
|
+
- Do not make a 'special' button for one page.
|
|
45
|
+
- Do not copy a component's markup to tweak it; extend the component.
|
|
46
|
+
- Do not accept generated code that hard-codes visual values, even when it looks right.
|
|
47
|
+
|
|
48
|
+
## Related
|
|
49
|
+
|
|
50
|
+
- Design tokens
|
|
51
|
+
- Iconography
|
|
52
|
+
- Writing
|
|
53
|
+
- Keyboard model
|