@momoi-labs/kiso 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 +21 -0
- package/README.md +63 -0
- package/kiso/AGENTS.md +50 -0
- package/kiso/README.md +62 -0
- package/kiso/docs/accessibility.md +87 -0
- package/kiso/docs/brand.md +95 -0
- package/kiso/docs/components/README.md +58 -0
- package/kiso/docs/components/alert.md +158 -0
- package/kiso/docs/components/badge.md +135 -0
- package/kiso/docs/components/breadcrumb.md +66 -0
- package/kiso/docs/components/button.md +168 -0
- package/kiso/docs/components/card.md +154 -0
- package/kiso/docs/components/checkbox.md +91 -0
- package/kiso/docs/components/command-palette.md +165 -0
- package/kiso/docs/components/drawer.md +79 -0
- package/kiso/docs/components/dropdown-menu.md +178 -0
- package/kiso/docs/components/empty-state.md +142 -0
- package/kiso/docs/components/form-field.md +115 -0
- package/kiso/docs/components/header.md +79 -0
- package/kiso/docs/components/helper-text.md +86 -0
- package/kiso/docs/components/icon-button.md +161 -0
- package/kiso/docs/components/input.md +99 -0
- package/kiso/docs/components/label.md +88 -0
- package/kiso/docs/components/link.md +152 -0
- package/kiso/docs/components/modal-dialog.md +82 -0
- package/kiso/docs/components/navigation.md +68 -0
- package/kiso/docs/components/page-header.md +70 -0
- package/kiso/docs/components/pagination.md +129 -0
- package/kiso/docs/components/popover.md +74 -0
- package/kiso/docs/components/search.md +147 -0
- package/kiso/docs/components/select.md +105 -0
- package/kiso/docs/components/sidebar.md +74 -0
- package/kiso/docs/components/skeleton.md +140 -0
- package/kiso/docs/components/spinner.md +125 -0
- package/kiso/docs/components/switch.md +92 -0
- package/kiso/docs/components/table.md +255 -0
- package/kiso/docs/components/tabs.md +69 -0
- package/kiso/docs/components/textarea.md +91 -0
- package/kiso/docs/components/toast.md +80 -0
- package/kiso/docs/components/tooltip.md +162 -0
- package/kiso/docs/components/validation-message.md +96 -0
- package/kiso/docs/data-interfaces.md +309 -0
- package/kiso/docs/evolution.md +35 -0
- package/kiso/docs/patterns/README.md +40 -0
- package/kiso/docs/patterns/application-shell.md +106 -0
- package/kiso/docs/patterns/command-palette.md +142 -0
- package/kiso/docs/patterns/confirmations.md +158 -0
- package/kiso/docs/patterns/crud.md +139 -0
- package/kiso/docs/patterns/dashboard.md +102 -0
- package/kiso/docs/patterns/destructive-actions.md +137 -0
- package/kiso/docs/patterns/developer-oriented-interfaces.md +162 -0
- package/kiso/docs/patterns/empty-states.md +76 -0
- package/kiso/docs/patterns/errors.md +93 -0
- package/kiso/docs/patterns/filtering.md +147 -0
- package/kiso/docs/patterns/keyboard-shortcuts.md +155 -0
- package/kiso/docs/patterns/large-data-tables.md +182 -0
- package/kiso/docs/patterns/list-detail.md +118 -0
- package/kiso/docs/patterns/loading.md +80 -0
- package/kiso/docs/patterns/login-authentication.md +101 -0
- package/kiso/docs/patterns/onboarding.md +94 -0
- package/kiso/docs/patterns/pagination.md +121 -0
- package/kiso/docs/patterns/permission-denied.md +84 -0
- package/kiso/docs/patterns/search.md +150 -0
- package/kiso/docs/patterns/settings.md +100 -0
- package/kiso/docs/patterns/sorting.md +121 -0
- package/kiso/docs/principles.md +122 -0
- package/kiso/docs/tokens.md +95 -0
- package/kiso/docs/voice-and-tone.md +154 -0
- package/package.json +42 -0
- package/tokens/build/tokens.css +143 -0
- package/tokens/build/tokens.d.ts +160 -0
- package/tokens/build/tokens.json +88 -0
- package/tokens/build/tokens.scss +89 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# CommandPalette
|
|
2
|
+
|
|
3
|
+
A global, keyboard-first overlay for running actions and navigating the
|
|
4
|
+
product by searching commands and destinations.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
CommandPalette is the "do or go anywhere" surface: open a query editor, jump
|
|
9
|
+
to a replica, switch project, run a frequent action — without hunting through
|
|
10
|
+
menus. It is invoked by a documented shortcut, filters a command list as the
|
|
11
|
+
person types, and is fully operable from the keyboard.
|
|
12
|
+
|
|
13
|
+
User stories #5, #19, and #20.
|
|
14
|
+
|
|
15
|
+
### Choose the right command surface
|
|
16
|
+
|
|
17
|
+
| Need | Control | Why |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Global actions and navigation | **CommandPalette** | App-scoped; search-as-you-type commands. |
|
|
20
|
+
| Filter items in a visible list/table | **[Search](search.md)** | Scoped to that collection; not an overlay of commands. |
|
|
21
|
+
| Actions on one specific element | **[DropdownMenu](dropdown-menu.md)** | Anchored to that control; contextual, not global. |
|
|
22
|
+
|
|
23
|
+
Search vs CommandPalette (user story #19): Search filters *content already
|
|
24
|
+
in view*. CommandPalette finds *actions and destinations* across the app.
|
|
25
|
+
|
|
26
|
+
DropdownMenu vs CommandPalette (user story #20): DropdownMenu is
|
|
27
|
+
*contextual* to a trigger. CommandPalette is *global*.
|
|
28
|
+
|
|
29
|
+
## Anatomy
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
CommandPalette
|
|
33
|
+
├── Overlay / dialog surface (modal or non-modal per product; usually modal)
|
|
34
|
+
├── Input (command filter; autofocused on open)
|
|
35
|
+
├── List
|
|
36
|
+
│ ├── Group (optional) × N
|
|
37
|
+
│ │ ├── Group heading
|
|
38
|
+
│ │ └── Item × N
|
|
39
|
+
│ │ ├── Icon (optional)
|
|
40
|
+
│ │ ├── Label (required)
|
|
41
|
+
│ │ ├── Shortcut hint (optional; visual only if not a real keybinding)
|
|
42
|
+
│ │ └── Description (optional)
|
|
43
|
+
│ └── Empty message (no matching commands)
|
|
44
|
+
└── Footer hints (optional; keyboard legend)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- **Input.** Filters commands; not a general document Search. Placeholder
|
|
48
|
+
like "Type a command or destination…".
|
|
49
|
+
- **Item.** One command or destination. Activating runs the action or
|
|
50
|
+
navigates.
|
|
51
|
+
- **Group.** Optional categories ("Navigation", "Replicas", "Settings").
|
|
52
|
+
- **Empty.** In-palette message when the filter matches nothing — not the
|
|
53
|
+
page-level [EmptyState](empty-state.md).
|
|
54
|
+
|
|
55
|
+
## Variants
|
|
56
|
+
|
|
57
|
+
| Variant | Behavior |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `commands` (default) | Mixed actions and destinations in one palette. |
|
|
60
|
+
| `navigation` | Destinations only (rare; prefer one palette with groups). |
|
|
61
|
+
|
|
62
|
+
Do not ship separate palettes per page unless the product truly scopes
|
|
63
|
+
commands; default is one app-level palette.
|
|
64
|
+
|
|
65
|
+
Surface: `--color-elevated-surface`, border `--color-border`, shadow
|
|
66
|
+
`--shadow-sm`, radius `--radius-lg`. Input and items use foreground /
|
|
67
|
+
muted-foreground roles. Active (highlighted) item uses `--color-surface` or
|
|
68
|
+
a quiet `--color-primary` indicator without filling the row in primary ink.
|
|
69
|
+
|
|
70
|
+
## Sizes
|
|
71
|
+
|
|
72
|
+
One size. The palette is a centered (or top-anchored) elevated panel with
|
|
73
|
+
max width from layout tokens / spacing rhythm — not Button `sm|md|lg`.
|
|
74
|
+
Item row padding `--spacing-sm` block, `--spacing-md` inline. Type:
|
|
75
|
+
the five body typography properties for items; the five label typography
|
|
76
|
+
properties for group headings.
|
|
77
|
+
|
|
78
|
+
## States
|
|
79
|
+
|
|
80
|
+
| State | Behavior |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| default (closed) | Not in the tree, or inert. Shortcut available. |
|
|
83
|
+
| open | Input focused; list visible; focus trapped within the palette while open (if modal). |
|
|
84
|
+
| hover | Item under pointer highlighted; keyboard highlight is source of truth when last input was keyboard. |
|
|
85
|
+
| focus | Input focus ring `--color-focus`. Highlighted item is the active descendant, not a second tab stop per row. |
|
|
86
|
+
| active | Item activation (Enter / click) runs the command and usually closes the palette. |
|
|
87
|
+
| disabled | Individual items may be disabled with `--color-disabled` and an explanation in description; prefer omitting unavailable commands. |
|
|
88
|
+
| loading | Optional: Spinner in the list while command providers resolve. Keep the input usable. `aria-busy` on the list region. |
|
|
89
|
+
| error | Provider failure: short in-palette message or Alert pattern inside the panel; do not fail silently to an empty list that looks like "no matches". |
|
|
90
|
+
|
|
91
|
+
### Invocation (user story #5)
|
|
92
|
+
|
|
93
|
+
| Mechanism | Behavior |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| Shortcut | Default recommendation: `⌘K` (macOS) / `Ctrl+K` (Windows/Linux), documented in product chrome. Do not bind Search fields to this shortcut. |
|
|
96
|
+
| Explicit trigger | Optional Button/IconButton in the Header ("Search commands…") that opens the same palette. |
|
|
97
|
+
| Search-as-you-type | Filter updates the list as the person types. |
|
|
98
|
+
| Keyboard navigation | Arrow keys move the highlight; Enter activates; Escape closes. |
|
|
99
|
+
|
|
100
|
+
## Accessibility
|
|
101
|
+
|
|
102
|
+
- Prefer a modal dialog pattern (`role="dialog"`, `aria-modal="true"`) with
|
|
103
|
+
an accessible name ("Command palette" / product-specific).
|
|
104
|
+
- Input has a visible or programmatically associated label.
|
|
105
|
+
- List uses `role="listbox"` (or cmdk's list semantics) with items as options;
|
|
106
|
+
the active item is exposed via `aria-activedescendant` on the input **or**
|
|
107
|
+
an equivalent pattern preserved from the reference library — do not invent
|
|
108
|
+
a broken tab-per-item list.
|
|
109
|
+
- Focus moves to the Input on open; on close, focus returns to the previously
|
|
110
|
+
focused element (or the trigger).
|
|
111
|
+
- Shortcut hints in items are decorative unless they document real bindings;
|
|
112
|
+
real bindings must work even when the palette is closed (where claimed).
|
|
113
|
+
- `Escape` closes without running a command.
|
|
114
|
+
- Reduced motion: no gratuitous entrance animation beyond token durations.
|
|
115
|
+
|
|
116
|
+
### Keyboard
|
|
117
|
+
|
|
118
|
+
| Key | Action |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `⌘K` / `Ctrl+K` | Toggle open/close (product default). |
|
|
121
|
+
| Printable keys | Filter commands (input focused). |
|
|
122
|
+
| `ArrowDown` / `ArrowUp` | Move highlight through items (and across groups). |
|
|
123
|
+
| `Enter` | Activate highlighted item. |
|
|
124
|
+
| `Escape` | Close without activating. |
|
|
125
|
+
| `Tab` | Generally stays within the palette (focus trap) while open; do not tab into the page behind a modal palette. |
|
|
126
|
+
|
|
127
|
+
## When to use
|
|
128
|
+
|
|
129
|
+
- App-wide command and navigation entry (user stories #5, #19, #20).
|
|
130
|
+
- Power-user shortcuts to frequent destinations in data tools.
|
|
131
|
+
- Discoverability for actions that would otherwise hide in nested menus.
|
|
132
|
+
|
|
133
|
+
## When NOT to use
|
|
134
|
+
|
|
135
|
+
- **Filtering a table or list in place.** [Search](search.md).
|
|
136
|
+
- **Actions on one row/button/avatar.** [DropdownMenu](dropdown-menu.md).
|
|
137
|
+
- **Confirming a destructive action.** Modal/Dialog (overlay slice) after
|
|
138
|
+
the command is chosen, if confirmation is required.
|
|
139
|
+
- **Form data entry.** Inputs and FormField — the palette is not a form.
|
|
140
|
+
- **Teaching the only path to a critical action.** Palette is acceleration;
|
|
141
|
+
critical actions still need a visible control somewhere.
|
|
142
|
+
|
|
143
|
+
## Tokens
|
|
144
|
+
|
|
145
|
+
`--color-elevated-surface`, `--color-surface`, `--color-foreground`,
|
|
146
|
+
`--color-muted-foreground`, `--color-subtle-foreground`, `--color-border`,
|
|
147
|
+
`--color-primary` (highlight affordance only), `--color-focus`,
|
|
148
|
+
`--color-disabled`, `--shadow-sm`, `--spacing-sm` / `--spacing-md`,
|
|
149
|
+
`--radius-lg`, `--motion-duration-fast`, and `--motion-easing-standard`.
|
|
150
|
+
Items use `--type-role-body-font-family`, `--type-role-body-font-size`,
|
|
151
|
+
`--type-role-body-font-weight`, `--type-role-body-letter-spacing`, and
|
|
152
|
+
`--type-role-body-line-height`; group headings use the equivalent five
|
|
153
|
+
property-qualified label tokens. No raw hex/px.
|
|
154
|
+
|
|
155
|
+
## Radix/shadcn mapping
|
|
156
|
+
|
|
157
|
+
| Kiso | Reference |
|
|
158
|
+
| --- | --- |
|
|
159
|
+
| Behavior | [cmdk](https://cmdk.paco.me/) via shadcn [Command](https://ui.shadcn.com/docs/components/command) |
|
|
160
|
+
| Dialog shell | shadcn Command Dialog example (Radix Dialog) for modal presentation |
|
|
161
|
+
| Input + list + groups + items | `Command`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandShortcut` |
|
|
162
|
+
|
|
163
|
+
Preserve cmdk keyboard and filter behavior. Restyle surfaces and text to Kiso
|
|
164
|
+
semantic tokens. Do not treat Command as Search, and do not use Command as a
|
|
165
|
+
DropdownMenu replacement for row actions.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Drawer
|
|
2
|
+
|
|
3
|
+
A viewport-adaptive overlay that enters from an edge and can replace a Modal
|
|
4
|
+
when a small viewport needs a more usable layout.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Drawer preserves context while giving forms, details, or focused tasks more
|
|
9
|
+
vertical room. Use it as the small-viewport presentation of the same task that
|
|
10
|
+
may appear in [Modal/Dialog](modal-dialog.md) on larger viewports; behavior and
|
|
11
|
+
accessible name stay consistent across the switch.
|
|
12
|
+
|
|
13
|
+
## Anatomy
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Drawer Root
|
|
17
|
+
├── Trigger
|
|
18
|
+
├── Overlay
|
|
19
|
+
└── Content
|
|
20
|
+
├── handle (optional, decorative)
|
|
21
|
+
├── Title
|
|
22
|
+
├── Description (optional)
|
|
23
|
+
├── body
|
|
24
|
+
├── actions
|
|
25
|
+
└── Close control
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Content uses `--color-elevated-surface`, `--color-foreground`,
|
|
29
|
+
`--color-border`, `--spacing-lg` padding, `--radius-lg`, and `--shadow-md`.
|
|
30
|
+
Entry/exit uses `--motion-duration-normal` and `--motion-easing-standard`, with
|
|
31
|
+
no travel under reduced motion.
|
|
32
|
+
|
|
33
|
+
## Variants
|
|
34
|
+
|
|
35
|
+
Two placements: bottom (default for small-viewport task adaptation) and side
|
|
36
|
+
for contextual detail or editing. Placement must not change Dialog semantics or
|
|
37
|
+
the task's accessible name.
|
|
38
|
+
|
|
39
|
+
## Sizes
|
|
40
|
+
|
|
41
|
+
One responsive size per placement. Content is bounded by the viewport and the
|
|
42
|
+
host layout; do not introduce `sm` / `md` / `lg` Drawer widths.
|
|
43
|
+
|
|
44
|
+
## States
|
|
45
|
+
|
|
46
|
+
| State | Behavior |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| closed (default) | Content is absent; trigger remains available. |
|
|
49
|
+
| hover | Trigger and child controls own hover. |
|
|
50
|
+
| focus | Opening moves focus inside; focused controls show `--color-focus`. |
|
|
51
|
+
| active/open | Page behind is inert and focus is trapped. |
|
|
52
|
+
| disabled | Disabled trigger does not open; Drawer itself is not disabled. |
|
|
53
|
+
| dragging | Optional touch dismissal follows the pointer and cancels below the component's deliberate threshold. |
|
|
54
|
+
| loading/error | Same task behavior as Modal/Dialog; do not dismiss on failure. |
|
|
55
|
+
|
|
56
|
+
## Accessibility
|
|
57
|
+
|
|
58
|
+
Use Dialog semantics (`role="dialog"`, `aria-modal="true"`, labelled title),
|
|
59
|
+
focus trap, background inertness, and focus return. `Escape` closes when safe;
|
|
60
|
+
`Tab` stays inside. Swipe/drag dismissal must have an equivalent Close Button,
|
|
61
|
+
must not be the only way out, and must not discard work accidentally.
|
|
62
|
+
|
|
63
|
+
## When to use
|
|
64
|
+
|
|
65
|
+
- A Modal task that needs a small-viewport, edge-to-edge presentation.
|
|
66
|
+
- Contextual detail or editing where retaining the underlying page matters.
|
|
67
|
+
|
|
68
|
+
## When NOT to use
|
|
69
|
+
|
|
70
|
+
- Merely because the design wants animation from an edge.
|
|
71
|
+
- Primary application navigation that should remain persistent; use Sidebar.
|
|
72
|
+
- A short anchored choice; use Popover or DropdownMenu.
|
|
73
|
+
- A full workflow that deserves its own route.
|
|
74
|
+
|
|
75
|
+
## Radix/shadcn mapping
|
|
76
|
+
|
|
77
|
+
Maps behavior to Radix Dialog and presentation to shadcn Sheet. Keep Dialog
|
|
78
|
+
focus management. A gesture-oriented drawer library may supply drag behavior,
|
|
79
|
+
but it must preserve these semantics and semantic tokens.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# DropdownMenu
|
|
2
|
+
|
|
3
|
+
A contextual menu of actions anchored to a specific control. It opens on
|
|
4
|
+
demand, stays near its trigger, and closes after a choice or dismissal.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
DropdownMenu offers actions *about this thing*: a row, an avatar, a kebab in
|
|
9
|
+
a Card header, a column of overflow actions. The trigger owns the context;
|
|
10
|
+
the menu does not search the whole app.
|
|
11
|
+
|
|
12
|
+
User story #20.
|
|
13
|
+
|
|
14
|
+
### Choose the right action menu
|
|
15
|
+
|
|
16
|
+
| Need | Control | Why |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| Actions on a specific element | **DropdownMenu** | Anchored; contextual. |
|
|
19
|
+
| Global actions / navigation by query | **[CommandPalette](command-palette.md)** | Not anchored to one element. |
|
|
20
|
+
| Single choice that sets a value | **[Select](select.md)** | Value selection, not a list of verbs. |
|
|
21
|
+
| Navigate to a URL as primary affordance | **[Link](link.md)** | Real navigation; menu items may still contain links when appropriate. |
|
|
22
|
+
|
|
23
|
+
DropdownMenu vs CommandPalette (user story #20): if the person must first
|
|
24
|
+
find the object, then open its menu, use DropdownMenu. If they are running
|
|
25
|
+
a global command without a local trigger, use CommandPalette.
|
|
26
|
+
|
|
27
|
+
Header (navigation slice) may compose DropdownMenu for account or overflow
|
|
28
|
+
actions. [Table / DataTable](table.md) uses it for row actions.
|
|
29
|
+
|
|
30
|
+
## Anatomy
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
DropdownMenu
|
|
34
|
+
├── Trigger (Button, IconButton, or other focusable control)
|
|
35
|
+
└── Content (portaled elevated surface)
|
|
36
|
+
├── Label (optional section label)
|
|
37
|
+
├── Item × N
|
|
38
|
+
│ ├── leading icon (optional)
|
|
39
|
+
│ ├── label (required)
|
|
40
|
+
│ ├── shortcut hint (optional)
|
|
41
|
+
│ └── destructive styling (optional)
|
|
42
|
+
├── Separator (optional)
|
|
43
|
+
├── Checkbox item (optional; rare)
|
|
44
|
+
├── Radio group (optional; rare)
|
|
45
|
+
└── Submenu (optional)
|
|
46
|
+
├── Sub-trigger
|
|
47
|
+
└── Sub-content
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- **Trigger.** Usually [IconButton](icon-button.md) (`ghost` `sm`) with an
|
|
51
|
+
accessible name ("Actions for {row}", "Open account menu"). Never an
|
|
52
|
+
unnamed icon.
|
|
53
|
+
- **Item.** A verb or destination ("Edit", "Duplicate", "Delete", "View
|
|
54
|
+
logs"). Prefer verbs for actions.
|
|
55
|
+
- **Separator.** Groups related items; decorative.
|
|
56
|
+
- **Destructive item.** Irreversible actions; use danger treatment on the
|
|
57
|
+
item label/icon, not a filled danger panel. Confirm with Modal when stakes
|
|
58
|
+
are high (overlay slice).
|
|
59
|
+
|
|
60
|
+
## Variants
|
|
61
|
+
|
|
62
|
+
Presentation is one menu system; item *kinds* vary:
|
|
63
|
+
|
|
64
|
+
| Kind | When |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `action` (default) | Runs a command or opens a follow-on UI. |
|
|
67
|
+
| `link` | Navigates; implement as a real link item when the reference supports it so open-in-new-tab works. |
|
|
68
|
+
| `destructive` | Destructive/irreversible action. |
|
|
69
|
+
| `checkbox` / `radio` | Rare in Kiso v1; only when the menu is the established pattern for a compact multi/one option set. Prefer Select/Checkbox in forms. |
|
|
70
|
+
|
|
71
|
+
Trigger variants come from Button/IconButton — DropdownMenu does not define
|
|
72
|
+
a parallel size/color system for the trigger.
|
|
73
|
+
|
|
74
|
+
Content tokens: background `--color-elevated-surface`, border
|
|
75
|
+
`--color-border`, text `--color-foreground`, muted hints
|
|
76
|
+
`--color-muted-foreground`, destructive `--color-danger`, focus/highlight
|
|
77
|
+
`--color-focus` / quiet `--color-surface` for the highlighted item. Radius
|
|
78
|
+
`--radius-md`. Padding `--spacing-xs` around the list; item padding
|
|
79
|
+
`--spacing-sm` / `--spacing-md`.
|
|
80
|
+
|
|
81
|
+
## Sizes
|
|
82
|
+
|
|
83
|
+
| Axis | Rule |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| Trigger | IconButton/Button `sm` in tables and dense chrome; `md` in headers. |
|
|
86
|
+
| Content | Min width fits labels; match trigger width only when it helps. No raw px: measure from the body/label typography properties and add the `--spacing-md` inline item padding. |
|
|
87
|
+
| Items | One density; do not ship `sm`/`lg` item scales. |
|
|
88
|
+
|
|
89
|
+
## States
|
|
90
|
+
|
|
91
|
+
| State | Behavior |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| default (closed) | Trigger at rest; content unmounted or hidden. |
|
|
94
|
+
| hover | Trigger and highlighted item show quiet emphasis. |
|
|
95
|
+
| focus | Trigger shows `--color-focus` when focused. Open content uses highlighted item semantics. |
|
|
96
|
+
| open / active | `data-state="open"` on trigger; content visible; focus moves into the menu per Radix model. |
|
|
97
|
+
| disabled | Trigger cannot open, or individual items disabled with `--color-disabled`. Prefer omitting unavailable items when absence is clear. |
|
|
98
|
+
| loading | Rare on the menu itself. A trigger IconButton may show loading after an item was chosen and the menu has closed. Do not leave a stuck open menu in a loading limbo. |
|
|
99
|
+
| error | Not a menu chrome state. Failures after an action use Alert/Toast (as appropriate) on the page. |
|
|
100
|
+
|
|
101
|
+
### Open / close
|
|
102
|
+
|
|
103
|
+
- Open on click / Enter / Space / ArrowDown on the trigger (per Radix).
|
|
104
|
+
- Close on item select, `Escape`, focus loss outside, or opening another
|
|
105
|
+
overlay — preserve Radix dismiss behavior.
|
|
106
|
+
- Pointer: hover may highlight items; selection commits on click, not merely
|
|
107
|
+
on hover.
|
|
108
|
+
|
|
109
|
+
## Accessibility
|
|
110
|
+
|
|
111
|
+
- Trigger must have an accessible name. Icon-only triggers use `aria-label`
|
|
112
|
+
or `aria-labelledby`.
|
|
113
|
+
- Use Radix Dropdown Menu roles (`menu`, `menuitem`, etc.) — do not fake a
|
|
114
|
+
menu with a div list lacking keyboard support.
|
|
115
|
+
- `aria-expanded` / `aria-controls` (or the library equivalents) reflect open
|
|
116
|
+
state.
|
|
117
|
+
- Destructive items must not rely on color alone; include clear labeling
|
|
118
|
+
("Delete replica").
|
|
119
|
+
- Submenus: follow Radix focus movement; do not invent a second Escape
|
|
120
|
+
model.
|
|
121
|
+
- Do not place essential instructions only inside a closed menu.
|
|
122
|
+
|
|
123
|
+
### Keyboard
|
|
124
|
+
|
|
125
|
+
| Key | Action |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `Enter` / `Space` | Open from trigger; activate focused item when open. |
|
|
128
|
+
| `ArrowDown` / `ArrowUp` | Open from trigger (where supported) or move between items. |
|
|
129
|
+
| `Home` / `End` | Move to first / last item when supported. |
|
|
130
|
+
| `ArrowRight` / `ArrowLeft` | Open / close submenu when present. |
|
|
131
|
+
| `Escape` | Close menu; return focus to trigger. |
|
|
132
|
+
| Typeahead | Focus the item matching typed characters when supported. |
|
|
133
|
+
|
|
134
|
+
## When to use
|
|
135
|
+
|
|
136
|
+
- Overflow / kebab actions on a table row, Card, or list item.
|
|
137
|
+
- Account or session menus in Header chrome.
|
|
138
|
+
- A small set of contextual verbs that would clutter the layout if always
|
|
139
|
+
visible (user story #20).
|
|
140
|
+
|
|
141
|
+
## When NOT to use
|
|
142
|
+
|
|
143
|
+
- **Global command search.** [CommandPalette](command-palette.md).
|
|
144
|
+
- **Filtering visible content.** [Search](search.md).
|
|
145
|
+
- **Primary page actions.** Prefer visible [Button](button.md)s in
|
|
146
|
+
PageHeader; menus are secondary/overflow.
|
|
147
|
+
- **Choosing a single form value from many.** [Select](select.md).
|
|
148
|
+
- **Navigation that should look like a menu of destinations as the main IA.**
|
|
149
|
+
Prefer Sidebar / Navigation (navigation slice); a DropdownMenu of links is
|
|
150
|
+
fine for compact account/overflow only.
|
|
151
|
+
- **Tooltips.** Tooltips are non-essential hints ([Tooltip](tooltip.md));
|
|
152
|
+
menus are actionable.
|
|
153
|
+
|
|
154
|
+
## Tokens
|
|
155
|
+
|
|
156
|
+
`--color-elevated-surface`, `--color-surface`, `--color-foreground`,
|
|
157
|
+
`--color-muted-foreground`, `--color-border`, `--color-danger`,
|
|
158
|
+
`--color-focus`, `--color-disabled`, `--spacing-xs` list padding,
|
|
159
|
+
`--spacing-sm` / `--spacing-md` item padding, `--radius-md`, `--shadow-sm`,
|
|
160
|
+
the five property-qualified body typography tokens for items, the five label
|
|
161
|
+
typography tokens for group labels, `--motion-duration-fast`, and
|
|
162
|
+
`--motion-easing-standard`. Trigger consumes Button/IconButton tokens. No raw
|
|
163
|
+
hex/px.
|
|
164
|
+
|
|
165
|
+
## Radix/shadcn mapping
|
|
166
|
+
|
|
167
|
+
| Kiso | Reference |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| Behavior | Radix [Dropdown Menu](https://www.radix-ui.com/primitives/docs/components/dropdown-menu) |
|
|
170
|
+
| Styling / composition | shadcn [Dropdown Menu](https://ui.shadcn.com/docs/components/dropdown-menu) |
|
|
171
|
+
| Trigger | Kiso [Button](button.md) / [IconButton](icon-button.md) via `asChild` / Slot when needed |
|
|
172
|
+
| Destructive item | shadcn `destructive` item class → `--color-danger` text/icon, not filled |
|
|
173
|
+
|
|
174
|
+
Preserve Radix focus management, typeahead, submenu behavior, and portal
|
|
175
|
+
positioning. Restyle with Kiso semantic tokens only.
|
|
176
|
+
|
|
177
|
+
Do **not** map row actions to Command/cmdk. Do **not** use Select to fake an
|
|
178
|
+
action menu.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# EmptyState
|
|
2
|
+
|
|
3
|
+
A deliberate placeholder when a region has nothing to show. It explains
|
|
4
|
+
why the space is empty and may offer a next action.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
EmptyState replaces an expected list, table body, or collection when there
|
|
9
|
+
are zero items — either because the person has never created any, or because
|
|
10
|
+
filters/search matched none.
|
|
11
|
+
|
|
12
|
+
User story #13: the action is **optional**. Informational-only EmptyStates are
|
|
13
|
+
valid when there is nothing useful to do yet.
|
|
14
|
+
|
|
15
|
+
### Choose the right empty
|
|
16
|
+
|
|
17
|
+
| Situation | Control | Why |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| Zero items in a collection / table body | **EmptyState** | Explains emptiness; optional create/clear action. |
|
|
20
|
+
| Still loading | [Skeleton](skeleton.md) | Not empty — pending. |
|
|
21
|
+
| Failed to load | [Alert](alert.md) | Error, not emptiness. |
|
|
22
|
+
| A single field with no value | Placeholder / HelperText | Not a page-level empty. |
|
|
23
|
+
|
|
24
|
+
[Table / DataTable](table.md) composes EmptyState for its empty data state.
|
|
25
|
+
|
|
26
|
+
## Anatomy
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
EmptyState
|
|
30
|
+
├── Illustration / icon (optional)
|
|
31
|
+
├── Title (required)
|
|
32
|
+
├── Description (optional; recommended when the title is not enough)
|
|
33
|
+
└── Action (optional: Button or Link)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **Illustration / icon.** Optional. Decorative (`aria-hidden`) when Title
|
|
37
|
+
carries the meaning. Prefer a simple icon over a large marketing
|
|
38
|
+
illustration in product UI.
|
|
39
|
+
- **Title.** What is empty, in product language ("No replicas yet", "No
|
|
40
|
+
queries match"). Follow [voice-and-tone](../voice-and-tone.md).
|
|
41
|
+
- **Description.** One or two short sentences: why, and what to do if there
|
|
42
|
+
is no Action control.
|
|
43
|
+
- **Action.** Optional [Button](button.md) (create, import, clear filters)
|
|
44
|
+
or [Link](link.md) when the next step is navigation. Never required.
|
|
45
|
+
|
|
46
|
+
## Variants
|
|
47
|
+
|
|
48
|
+
| Variant | When | Action |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `first-run` | The collection has never had items. | Usually a primary Button ("Create replica"). |
|
|
51
|
+
| `no-results` | Filters or Search exclude everything. | Often "Clear filters" (default/ghost) or adjust Search; not "Create". |
|
|
52
|
+
| `informational` | Empty is expected and there is no useful action. | No Action. Title + Description only. |
|
|
53
|
+
|
|
54
|
+
Do not add severity variants (info/warning/error). Emptiness is not an
|
|
55
|
+
error — errors are Alert. Do not color the whole EmptyState with status
|
|
56
|
+
tokens.
|
|
57
|
+
|
|
58
|
+
Surface tokens: text `--color-foreground` / `--color-muted-foreground` on
|
|
59
|
+
the surrounding `--color-surface` or `--color-background`. Icon uses
|
|
60
|
+
`--color-muted-foreground` unless it is purely decorative brand chrome.
|
|
61
|
+
|
|
62
|
+
## Sizes
|
|
63
|
+
|
|
64
|
+
| Size | Use | Tokens |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| `md` (default) | Table bodies, Card content, list panels. | Title uses the five heading typography properties, or the five label typography properties for label emphasis; description uses the five body typography properties; padding `--spacing-lg`; gap `--spacing-sm`. |
|
|
67
|
+
| `sm` | Narrow side panels or compact nested regions. | Tighter padding `--spacing-md`; smaller icon; same type roles if readable. |
|
|
68
|
+
|
|
69
|
+
Action Buttons use Button `md` by default; `sm` only inside `sm` EmptyState
|
|
70
|
+
in dense chrome. Do not invent an `lg` EmptyState that competes with
|
|
71
|
+
PageHeader.
|
|
72
|
+
|
|
73
|
+
## States
|
|
74
|
+
|
|
75
|
+
| State | Behavior |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| default | Visible empty region. |
|
|
78
|
+
| hover / focus / active | EmptyState itself is not a control. Focus goes to Action if present. |
|
|
79
|
+
| disabled | N/A. Hide the region or show a different state. |
|
|
80
|
+
| loading | Do not show EmptyState while loading — use Skeleton. If the Action triggers creation, that Button may enter loading. |
|
|
81
|
+
| error | Not an EmptyState state. Switch to Alert. |
|
|
82
|
+
|
|
83
|
+
## Accessibility
|
|
84
|
+
|
|
85
|
+
- EmptyState is a region with an accessible name from Title
|
|
86
|
+
(`aria-labelledby`) and optional `aria-describedby` for Description.
|
|
87
|
+
- Prefer landmark/region semantics only when the empty area is a major
|
|
88
|
+
page section; inside a table body, keep table structure and place
|
|
89
|
+
EmptyState content in a single full-width cell or a documented
|
|
90
|
+
replacement region announced as the table's status.
|
|
91
|
+
- Icon/illustration: `aria-hidden="true"` when Title is present.
|
|
92
|
+
- Action is a real Button or Link with its own accessible name. Do not make
|
|
93
|
+
the entire EmptyState clickable.
|
|
94
|
+
- When EmptyState appears because Search filtered everything, ensure the
|
|
95
|
+
Search field remains reachable and that the empty message is findable
|
|
96
|
+
by screen reader users (polite live update only if the change is not
|
|
97
|
+
obvious from focus).
|
|
98
|
+
|
|
99
|
+
### Keyboard
|
|
100
|
+
|
|
101
|
+
| Key | Action |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| `Tab` / `Shift+Tab` | Reach the Action if present. |
|
|
104
|
+
| `Enter` / `Space` | Activate the focused Action. |
|
|
105
|
+
|
|
106
|
+
## When to use
|
|
107
|
+
|
|
108
|
+
- A list, table body, or collection has zero items to show.
|
|
109
|
+
- First-run onboarding for a createable resource (with Action).
|
|
110
|
+
- No Search/filter matches (with copy that reflects filters).
|
|
111
|
+
- Informational empty when no action exists (user story #13).
|
|
112
|
+
|
|
113
|
+
## When NOT to use
|
|
114
|
+
|
|
115
|
+
- **Loading.** Skeleton (or Spinner for indeterminate non-layout waits).
|
|
116
|
+
- **Errors.** Alert with retry.
|
|
117
|
+
- **Permission denied.** Alert or a dedicated locked state — not "No items".
|
|
118
|
+
- **Marketing empty.** Product EmptyState is operational, not a billboard.
|
|
119
|
+
- **Replacing a whole app shell.** Page-level emptiness still sits inside the
|
|
120
|
+
shell; do not delete navigation to show EmptyState.
|
|
121
|
+
|
|
122
|
+
## Tokens
|
|
123
|
+
|
|
124
|
+
`--color-foreground`, `--color-muted-foreground`, `--color-surface` /
|
|
125
|
+
`--color-background`, optional icon `--color-muted-foreground`, `--spacing-lg`
|
|
126
|
+
padding (`--spacing-md` for `sm`), `--spacing-sm` gap, `--radius-md`, and
|
|
127
|
+
`--motion-duration-fast` / `--motion-easing-standard`. Typography uses every
|
|
128
|
+
property of the selected heading, label, and body roles named above. Action consumes Button/Link
|
|
129
|
+
tokens. No raw hex/px.
|
|
130
|
+
|
|
131
|
+
## Radix/shadcn mapping
|
|
132
|
+
|
|
133
|
+
No Radix EmptyState primitive.
|
|
134
|
+
|
|
135
|
+
| Kiso | Reference |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| Composition pattern | shadcn has no dedicated Empty component in core; compose layout + typography + [Button](button.md) like common "empty" blocks in shadcn Data Table examples |
|
|
138
|
+
| Action | shadcn / Kiso [Button](button.md) or [Link](link.md) |
|
|
139
|
+
| Inside tables | shadcn Data Table empty row patterns → replace with this anatomy |
|
|
140
|
+
|
|
141
|
+
Do not copy illustration-heavy marketing empties. Keep Kiso EmptyState
|
|
142
|
+
quiet and actionable.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# FormField
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
FormField is the standard composition for one labeled form control. It aligns
|
|
6
|
+
identification, entry, guidance, and field-level feedback so their visual and
|
|
7
|
+
accessible relationships remain intact. FormField is not a primitive and does
|
|
8
|
+
not replace the semantics of its children.
|
|
9
|
+
|
|
10
|
+
## Anatomy
|
|
11
|
+
|
|
12
|
+
The canonical composition is:
|
|
13
|
+
|
|
14
|
+
1. **Label** — required; names the control through matching `for`/`id`.
|
|
15
|
+
2. **Input** — the default control in this composition. Textarea, Select,
|
|
16
|
+
Checkbox, or Switch may occupy the control slot when appropriate.
|
|
17
|
+
3. **HelperText** — optional; provides persistent context, format, or scope.
|
|
18
|
+
4. **ValidationMessage** — optional until invalid; explains a field-level error
|
|
19
|
+
and recovery.
|
|
20
|
+
|
|
21
|
+
For the issue's foundational chain, read this literally as **Label + Input +
|
|
22
|
+
HelperText + ValidationMessage**. FormField owns layout and ID wiring; each
|
|
23
|
+
child retains its own behavior.
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
Label
|
|
27
|
+
Input
|
|
28
|
+
HelperText
|
|
29
|
+
ValidationMessage
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Variants
|
|
33
|
+
|
|
34
|
+
- **Standard** — Label above Input, supporting text below.
|
|
35
|
+
- **Required** — control exposes required semantics and the visible convention
|
|
36
|
+
is consistent across the form.
|
|
37
|
+
- **Optional** — Label carries an “Optional” qualifier when useful.
|
|
38
|
+
- **Horizontal** — Label and control columns for wide, dense settings pages;
|
|
39
|
+
collapses without changing reading order.
|
|
40
|
+
- **Control substitution** — replaces Input with another Kiso form primitive
|
|
41
|
+
while preserving Label and description/error wiring.
|
|
42
|
+
|
|
43
|
+
## Sizes
|
|
44
|
+
|
|
45
|
+
- **Small** — inherits the small size of its control and compact semantic gaps.
|
|
46
|
+
- **Medium** — default.
|
|
47
|
+
- **Large** — inherits the large control size where that control supports it.
|
|
48
|
+
|
|
49
|
+
FormField does not scale text independently. Label uses the five
|
|
50
|
+
property-qualified label typography tokens; supporting text uses the five
|
|
51
|
+
property-qualified metadata typography tokens. Use `--spacing-xs` between a
|
|
52
|
+
control and supporting text and `--spacing-sm` between the label and control.
|
|
53
|
+
|
|
54
|
+
## States
|
|
55
|
+
|
|
56
|
+
| State | Behavior |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| Default | Label, control, and optional HelperText form one readable group. |
|
|
59
|
+
| Hover | Delegated to the interactive control; layout does not change. |
|
|
60
|
+
| Focus | Control owns the visible focus ring; supporting content remains stable. |
|
|
61
|
+
| Active | Delegated to the control. |
|
|
62
|
+
| Disabled | Control is disabled; Label and supporting text communicate unavailability without hiding context. |
|
|
63
|
+
| Loading | Control exposes busy status and loading affordance while Label/help remain readable. |
|
|
64
|
+
| Error | Control has `aria-invalid="true"`; ValidationMessage appears without removing useful HelperText. |
|
|
65
|
+
|
|
66
|
+
Disabled and loading remain distinct at composition level. Loading is a live
|
|
67
|
+
process; disabled is unavailable. Showing ValidationMessage must not cause the
|
|
68
|
+
control, Label, or existing help to lose their associations.
|
|
69
|
+
|
|
70
|
+
## Accessibility
|
|
71
|
+
|
|
72
|
+
- Generate stable, collision-free IDs. Label `for` points to the control `id`.
|
|
73
|
+
- HelperText and ValidationMessage each have an ID. The control's
|
|
74
|
+
`aria-describedby` contains the IDs of every present description, separated
|
|
75
|
+
by spaces; preserve HelperText when an error appears if it is still useful.
|
|
76
|
+
- Invalid controls set `aria-invalid="true"`. ValidationMessage may use a live
|
|
77
|
+
region for errors introduced after interaction, but avoid duplicate
|
|
78
|
+
announcements caused by simultaneous alert and description behavior.
|
|
79
|
+
- Required, disabled, read-only, and busy semantics belong on the control.
|
|
80
|
+
- DOM reading order follows Label → control → HelperText → ValidationMessage,
|
|
81
|
+
even in a horizontal visual layout.
|
|
82
|
+
- FormField adds no keyboard interaction. The contained control keeps its native
|
|
83
|
+
or Radix keyboard contract, and clicking Label targets that control.
|
|
84
|
+
|
|
85
|
+
## When to use
|
|
86
|
+
|
|
87
|
+
- For nearly every standalone labeled form control.
|
|
88
|
+
- To make accessible ID wiring and vertical rhythm consistent.
|
|
89
|
+
- When a control needs help, validation, required/optional status, or all three.
|
|
90
|
+
|
|
91
|
+
## When NOT to use
|
|
92
|
+
|
|
93
|
+
- Do not use as a generic layout wrapper or fieldset for unrelated controls.
|
|
94
|
+
- Do not duplicate a Label or description already supplied by a composite
|
|
95
|
+
control.
|
|
96
|
+
- Do not render an empty ValidationMessage merely to reserve space unless the
|
|
97
|
+
product has measured layout-stability needs.
|
|
98
|
+
- Do not put form-level or page-level errors here; ValidationMessage is
|
|
99
|
+
field-level feedback.
|
|
100
|
+
|
|
101
|
+
## Tokens
|
|
102
|
+
|
|
103
|
+
FormField consumes `--spacing-xs`, `--spacing-sm`, and the label and metadata
|
|
104
|
+
typography properties named above for layout. Its
|
|
105
|
+
children own colors: foreground/muted text, surface/border, focus, disabled,
|
|
106
|
+
and danger. The composition introduces no primitive token or raw value.
|
|
107
|
+
|
|
108
|
+
## Radix/shadcn mapping
|
|
109
|
+
|
|
110
|
+
There is no single Radix FormField primitive. The composition uses Radix Label
|
|
111
|
+
and the relevant Radix control when one exists. It maps behaviorally to the
|
|
112
|
+
[shadcn/ui Field](https://ui.shadcn.com/docs/components/field) composition and
|
|
113
|
+
the form patterns documented by shadcn, while Kiso's explicit contract remains
|
|
114
|
+
Label + Input + HelperText + ValidationMessage with deterministic IDs and ARIA
|
|
115
|
+
wiring.
|