@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,255 @@
|
|
|
1
|
+
# Table / DataTable
|
|
2
|
+
|
|
3
|
+
A dense, scannable grid of records. Rows are entities; columns are
|
|
4
|
+
comparable fields. DataTable is the same component with sorting, filtering
|
|
5
|
+
composition, pagination, and row selection switched on.
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
Table is the primary surface for Momoi's data-heavy products: replicas,
|
|
10
|
+
queries, metrics series, config keys, log lines. The person scans, compares,
|
|
11
|
+
sorts, selects, and acts on many similar items.
|
|
12
|
+
|
|
13
|
+
User stories #3 and #21.
|
|
14
|
+
|
|
15
|
+
**Table** is the structural grid (header, body, optional footer).
|
|
16
|
+
**DataTable** is Table plus the interactive behaviors listed below. Prefer the
|
|
17
|
+
name DataTable in product UI copy when those behaviors are present; the
|
|
18
|
+
spec is one component.
|
|
19
|
+
|
|
20
|
+
### Composition
|
|
21
|
+
|
|
22
|
+
| Concern | Compose with | Notes |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| Loading rows | [Skeleton](skeleton.md) | Skeleton *text* cells inside rows; keep chrome. |
|
|
25
|
+
| Empty dataset | [EmptyState](empty-state.md) | Replaces the body; keep column headers when helpful. |
|
|
26
|
+
| Error loading | [Alert](alert.md) | Above or in place of the body; retry via Button. |
|
|
27
|
+
| Filter visible rows | [Search](search.md) | Standalone; not built into Table. User story #9. |
|
|
28
|
+
| Page through known sets | [Pagination](pagination.md) | Known total / page size. User story #11. |
|
|
29
|
+
| Row actions | [DropdownMenu](dropdown-menu.md) or [IconButton](icon-button.md) | Per-row contextual actions. |
|
|
30
|
+
| Bulk actions | [Button](button.md) in a selection toolbar | Appear when one or more rows are selected. |
|
|
31
|
+
|
|
32
|
+
Do not invent a second "table kit". Loading, empty, and error are *states of
|
|
33
|
+
this component*, expressed by composing the pieces above.
|
|
34
|
+
|
|
35
|
+
## Anatomy
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
DataTable
|
|
39
|
+
├── Toolbar (optional)
|
|
40
|
+
│ ├── Search (filter; optional)
|
|
41
|
+
│ ├── Filters / view controls (optional)
|
|
42
|
+
│ └── Bulk action Buttons (when rows selected)
|
|
43
|
+
├── Table
|
|
44
|
+
│ ├── Caption (optional; accessible name for the table)
|
|
45
|
+
│ ├── Header (thead)
|
|
46
|
+
│ │ └── HeaderRow
|
|
47
|
+
│ │ ├── SelectionHeaderCell (optional checkbox)
|
|
48
|
+
│ │ └── ColumnHeaderCell × N
|
|
49
|
+
│ │ ├── Sort control (optional)
|
|
50
|
+
│ │ └── Resize handle (optional)
|
|
51
|
+
│ ├── Body (tbody)
|
|
52
|
+
│ │ ├── DataRow × N
|
|
53
|
+
│ │ │ ├── SelectionCell (optional checkbox)
|
|
54
|
+
│ │ │ ├── DataCell × N
|
|
55
|
+
│ │ │ └── RowActionsCell (optional)
|
|
56
|
+
│ │ ├── SkeletonRow × N (loading only)
|
|
57
|
+
│ │ └── Empty / Error region (replaces DataRows)
|
|
58
|
+
│ └── Footer (tfoot; optional totals / summary)
|
|
59
|
+
└── Pagination (optional; below the table)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **Caption.** Visible or visually hidden. Required accessible name for the
|
|
63
|
+
table (`<caption>` or `aria-labelledby`).
|
|
64
|
+
- **ColumnHeaderCell.** Column title. Sortable headers are buttons (or have a
|
|
65
|
+
nested button), not plain text.
|
|
66
|
+
- **DataCell.** One value. Prefer plain text; [Badge](badge.md) for status;
|
|
67
|
+
[Link](link.md) only when the cell navigates.
|
|
68
|
+
- **SelectionCell.** [Checkbox](checkbox.md) for multi-select membership.
|
|
69
|
+
- **RowActionsCell.** Usually a DropdownMenu trigger (kebab / more), not a
|
|
70
|
+
pile of Buttons.
|
|
71
|
+
- **Toolbar.** Outside the `<table>`. Owns Search, filters, and bulk actions.
|
|
72
|
+
- **Pagination.** Sibling below the table, not a table row (navigation slice).
|
|
73
|
+
|
|
74
|
+
## Variants
|
|
75
|
+
|
|
76
|
+
| Variant | Behavior |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `plain` | Structural table only: no sort, selection, or pagination. Rare; prefer DataTable. |
|
|
79
|
+
| `data` (default) | Sort, optional row selection, Search composition, Pagination when the set is paged. |
|
|
80
|
+
|
|
81
|
+
Density is a presentation choice, not a named color variant:
|
|
82
|
+
|
|
83
|
+
| Density | Use | Tokens |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `comfortable` | Default for most product tables. | Cell padding `--spacing-sm` block, `--spacing-md` inline. All five body typography properties. |
|
|
86
|
+
| `compact` | Ops dashboards, wide schemas, log-like grids. | Cell padding `--spacing-xs` block, `--spacing-sm` inline. Same five body typography properties (do not shrink below readable). |
|
|
87
|
+
|
|
88
|
+
Header background `--color-surface`. Body rows `--color-surface` on
|
|
89
|
+
`--color-background` page canvas, or zebra with alternating
|
|
90
|
+
`--color-elevated-surface` / `--color-surface` when it aids scanning — never
|
|
91
|
+
raw stripes. Borders `--color-border`. Text `--color-foreground`; secondary
|
|
92
|
+
cell metadata `--color-muted-foreground`.
|
|
93
|
+
|
|
94
|
+
### Column behaviors
|
|
95
|
+
|
|
96
|
+
| Behavior | Spec |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| **Sortable** | Header exposes sort control. One primary sort column at a time unless the product explicitly supports multi-sort (rare; document in the screen). Cycle: unsorted → ascending → descending → unsorted (or omit unsorted if a default sort is required). |
|
|
99
|
+
| **Sticky header** | Header stays visible while the body scrolls inside a scrollport. Use when the table is taller than the viewport. Sticky uses the same `--color-surface` as the header so rows do not show through. |
|
|
100
|
+
| **Column resize** | Optional. Drag handle on the header edge. Persist width in product state when useful. Minimum width must keep the header label readable; do not specify px — use ch, the label typography properties, and `--spacing-sm`. |
|
|
101
|
+
| **Virtualization** | Guidance, not a separate variant. For large client-side sets (thousands of rows), virtualize the body so only visible rows mount. Keep header, selection model, and keyboard navigation correct. Prefer server-side Pagination when the dataset is known and paged; virtualize when scrolling one large loaded set. |
|
|
102
|
+
|
|
103
|
+
Filtering is **not** a Table variant. [Search](search.md) (and optional
|
|
104
|
+
filter chips) live in the Toolbar and feed the data query or client filter.
|
|
105
|
+
|
|
106
|
+
## Sizes
|
|
107
|
+
|
|
108
|
+
Table has no `sm` / `md` / `lg` control scale like Button. Size comes from:
|
|
109
|
+
|
|
110
|
+
| Axis | Token / rule |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| Type | All five property-qualified body typography tokens for cells; all five property-qualified label typography tokens for headers. |
|
|
113
|
+
| Cell padding | Density table above (`--spacing-xs`, `--spacing-sm`, and `--spacing-md`). |
|
|
114
|
+
| Radius | Outer wrapper `--radius-md` when the table sits in a framed panel; internal cells are square. |
|
|
115
|
+
| Checkbox / IconButton in cells | `sm` controls so row height stays dense. |
|
|
116
|
+
|
|
117
|
+
Do not invent a fourth density. Do not set row height in raw pixels.
|
|
118
|
+
|
|
119
|
+
## States
|
|
120
|
+
|
|
121
|
+
The table as a whole has mutually exclusive *data* states. Interactive
|
|
122
|
+
chrome (headers, checkboxes, row actions) still has control states.
|
|
123
|
+
|
|
124
|
+
### Data states (user story #3)
|
|
125
|
+
|
|
126
|
+
| State | Presentation | Behavior |
|
|
127
|
+
| --- | --- | --- |
|
|
128
|
+
| **Loading** | Keep header (and toolbar if already meaningful). Body shows Skeleton rows matching column count and approximate page size. Region `aria-busy="true"` with a polite status ("Loading replicas"). | Do not show EmptyState or stale rows next to Skeletons. Do not disable the whole page. |
|
|
129
|
+
| **Empty** | Body replaced by [EmptyState](empty-state.md). Headers may remain so column meaning is clear. | Empty means *zero matching records*, not "still loading". If Search/filters are active, EmptyState copy should say no matches and offer clear-filters when applicable. |
|
|
130
|
+
| **Error** | Remove Skeletons. Show [Alert](alert.md) `error` with retry. Optionally keep headers. | Do not leave an empty table that looks like success. After retry, return to loading then populated/empty. |
|
|
131
|
+
| **Populated** | DataRows + optional Pagination. | Default happy path. |
|
|
132
|
+
|
|
133
|
+
Loading vs empty vs error must never be ambiguous: Skeleton ≠ EmptyState ≠
|
|
134
|
+
Alert.
|
|
135
|
+
|
|
136
|
+
### Interaction states
|
|
137
|
+
|
|
138
|
+
| State | Where | Behavior |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| default | Rows, headers, cells | Interactive affordances at rest. |
|
|
141
|
+
| hover | DataRow, sortable header, resize handle | Quiet emphasis (`--color-elevated-surface` or border). Cursor indicates affordance. Transition `--motion-duration-fast` / `--motion-easing-standard`. |
|
|
142
|
+
| focus | Sort button, Checkbox, row action, Pagination | Visible `--color-focus` ring. Row focus for roving tabindex patterns follows the keyboard model below. |
|
|
143
|
+
| active | Sort control, Checkbox, menu trigger | Pressed / open as for those controls. |
|
|
144
|
+
| disabled | Individual Checkbox, sort, or action | Native/disabled semantics with `--color-disabled`. Prefer hiding irrelevant actions over a sea of disabled controls. |
|
|
145
|
+
| loading | Whole table data state, or a single row action | Table-level: Skeleton rows. Row action: Button/IconButton loading ([Spinner](spinner.md)). |
|
|
146
|
+
| selected | DataRow | One or more rows selected. Background `--color-elevated-surface` or a left accent border using `--color-primary` (not a filled primary row — primary is a text/action role). Selection Header Checkbox reflects none / some / all. |
|
|
147
|
+
| sorted | ColumnHeaderCell | `aria-sort="ascending"` \| `"descending"` \| `"none"`. Visible sort indicator (icon); do not rely on color alone. |
|
|
148
|
+
|
|
149
|
+
### Sorting
|
|
150
|
+
|
|
151
|
+
- Sort changes the **order of the current result set** (client) or the
|
|
152
|
+
**query** (server). Document which on the screen.
|
|
153
|
+
- Announce sort changes politely when they are not obvious from focus
|
|
154
|
+
("Sorted by name, ascending").
|
|
155
|
+
- Unsortable columns have no sort control and no `aria-sort`.
|
|
156
|
+
|
|
157
|
+
### Pagination
|
|
158
|
+
|
|
159
|
+
- Use Pagination when the dataset size is known or page-shaped (user story
|
|
160
|
+
#11). Infinite scroll is a pattern (Epic #4), not a Table state — and is
|
|
161
|
+
usually wrong for ops tables where "page 7 of 40" matters.
|
|
162
|
+
- Changing page keeps selection policy explicit: either clear selection or
|
|
163
|
+
keep a cross-page selection model — pick one per product surface and say so.
|
|
164
|
+
- While a page fetch runs, prefer Skeleton rows inside the body over blanking
|
|
165
|
+
the chrome.
|
|
166
|
+
|
|
167
|
+
### Row selection
|
|
168
|
+
|
|
169
|
+
- Multi-select via Checkbox in the leading column. Header Checkbox toggles
|
|
170
|
+
all rows **on the current page** (or all loaded rows if virtualized without
|
|
171
|
+
pages) unless the product defines "select all matching query" — that needs
|
|
172
|
+
explicit copy and a confirmation.
|
|
173
|
+
- Selected count appears in the Toolbar ("3 selected") with bulk actions.
|
|
174
|
+
- Single-select (radio-like) is rare; if needed, one selected row at a time
|
|
175
|
+
and no Header Checkbox.
|
|
176
|
+
- Do not use row click alone for selection when the row also navigates; keep
|
|
177
|
+
Checkbox as the selection affordance and Link/Button for navigation/actions.
|
|
178
|
+
|
|
179
|
+
## Accessibility
|
|
180
|
+
|
|
181
|
+
- Use a real `<table>` with `<thead>`, `<tbody>`, and `<th scope="col">`
|
|
182
|
+
(and `scope="row"` when row headers exist). Do not fake a table with CSS
|
|
183
|
+
grids for tabular data.
|
|
184
|
+
- Accessible name via `<caption>` or `aria-labelledby`.
|
|
185
|
+
- Sortable headers: the sort control is a button; set `aria-sort` on the
|
|
186
|
+
`<th>`.
|
|
187
|
+
- Selection Checkboxes: each has an accessible name ("Select row {name}" /
|
|
188
|
+
"Select all rows on this page"). Indeterminate Header Checkbox uses the
|
|
189
|
+
Checkbox indeterminate state.
|
|
190
|
+
- Loading: `aria-busy="true"` on the table region; Skeletons `aria-hidden`.
|
|
191
|
+
See [Skeleton](skeleton.md).
|
|
192
|
+
- Empty: EmptyState is the content; do not leave an empty `<tbody>` with no
|
|
193
|
+
explanation.
|
|
194
|
+
- Error Alert: follow [Alert](alert.md) focus guidance on failure after a
|
|
195
|
+
user-initiated refresh.
|
|
196
|
+
- Do not put essential meaning in zebra color alone.
|
|
197
|
+
- Sticky header: ensure focus order still follows visual order; do not trap
|
|
198
|
+
focus under a sticky layer.
|
|
199
|
+
|
|
200
|
+
### Keyboard
|
|
201
|
+
|
|
202
|
+
| Key | Action |
|
|
203
|
+
| --- | --- |
|
|
204
|
+
| `Tab` / `Shift+Tab` | Move through interactive controls: toolbar, sort buttons, Checkboxes, row actions, Pagination. |
|
|
205
|
+
| `Enter` / `Space` | Activate the focused control (sort, Checkbox, menu trigger, Button). |
|
|
206
|
+
| Arrow keys | Within DropdownMenu / composite widgets per those specs. Optional grid navigation inside the table body is allowed when implemented as a composite; if so, document `aria-activedescendant` or roving tabindex and keep one tab stop into the grid. |
|
|
207
|
+
| `Escape` | Closes an open row DropdownMenu; does not clear selection unless the product defines that. |
|
|
208
|
+
|
|
209
|
+
## When to use
|
|
210
|
+
|
|
211
|
+
- Many similar records with comparable fields (user story #21).
|
|
212
|
+
- The person needs to sort, page, select, or scan columns.
|
|
213
|
+
- Ops and data tools: databases, jobs, configs, metrics inventories.
|
|
214
|
+
|
|
215
|
+
## When NOT to use
|
|
216
|
+
|
|
217
|
+
- **One or two fields about a single entity.** Use a definition list, Card,
|
|
218
|
+
or PageHeader — not a one-row table.
|
|
219
|
+
- **Hierarchical location.** Breadcrumb (navigation slice).
|
|
220
|
+
- **Free-form layout.** Cards or a custom panel; tables imply comparison.
|
|
221
|
+
- **Charts.** Deferred to v2; do not stretch Table into a graph.
|
|
222
|
+
- **Global actions / jump-to.** [CommandPalette](command-palette.md), not a
|
|
223
|
+
table of commands.
|
|
224
|
+
- **Filtering UI embedded as magic columns.** Use Search + filters in the
|
|
225
|
+
Toolbar.
|
|
226
|
+
|
|
227
|
+
## Tokens
|
|
228
|
+
|
|
229
|
+
Consume only semantic roles: `--color-background`, `--color-surface`,
|
|
230
|
+
`--color-elevated-surface`, `--color-foreground`, `--color-muted-foreground`,
|
|
231
|
+
`--color-border`, `--color-primary`, `--color-focus`, `--color-disabled`,
|
|
232
|
+
`--color-danger` (via Alert on error); the five property-qualified body and
|
|
233
|
+
label typography tokens; `--spacing-xs`, `--spacing-sm`, `--spacing-md`;
|
|
234
|
+
`--radius-md`; `--motion-duration-fast`; and `--motion-easing-standard`. No
|
|
235
|
+
palette primitives, no raw hex/px.
|
|
236
|
+
|
|
237
|
+
## Radix/shadcn mapping
|
|
238
|
+
|
|
239
|
+
There is no Radix Table primitive for the grid itself. Behavior for menus and
|
|
240
|
+
checkboxes comes from those primitives; the table is semantic HTML.
|
|
241
|
+
|
|
242
|
+
| Kiso | Reference |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| Markup and structure | shadcn [Table](https://ui.shadcn.com/docs/components/table) (`Table`, `TableHeader`, `TableBody`, `TableRow`, `TableHead`, `TableCell`, `TableCaption`, `TableFooter`) |
|
|
245
|
+
| DataTable patterns (sort, selection, toolbar) | shadcn [Data Table](https://ui.shadcn.com/docs/components/data-table) (TanStack Table examples) — adopt interaction patterns; restyle with Kiso tokens |
|
|
246
|
+
| Row / header Checkbox | Radix / shadcn Checkbox → Kiso [Checkbox](checkbox.md) |
|
|
247
|
+
| Row actions menu | Radix / shadcn Dropdown Menu → Kiso [DropdownMenu](dropdown-menu.md) |
|
|
248
|
+
| Loading rows | shadcn Skeleton "Table" example → Kiso [Skeleton](skeleton.md) |
|
|
249
|
+
| Empty | Compose [EmptyState](empty-state.md); do not use a blank shadcn row |
|
|
250
|
+
| Pagination | Kiso [Pagination](pagination.md), using shadcn Pagination as its structural reference |
|
|
251
|
+
|
|
252
|
+
Map shadcn Data Table examples by *intent*: sorting state, row selection,
|
|
253
|
+
toolbar bulk actions. Replace every utility color and pixel size with Kiso
|
|
254
|
+
semantic tokens. Do not copy example row heights or `h-10` / `w-[100px]`
|
|
255
|
+
literals.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Tabs
|
|
2
|
+
|
|
3
|
+
Switches between related panels within the same page.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Tabs organize peer views without changing the person's hierarchical location.
|
|
8
|
+
They answer “which view of this page?”; [Breadcrumb](breadcrumb.md) answers
|
|
9
|
+
“where am I in the product?”
|
|
10
|
+
|
|
11
|
+
## Anatomy
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Tabs
|
|
15
|
+
├── TabList
|
|
16
|
+
│ └── Tab (one or more)
|
|
17
|
+
└── TabPanel (one per Tab)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Tabs use `--color-foreground`, `--color-muted-foreground`,
|
|
21
|
+
`--color-primary`, `--color-border`, and `--color-focus`; `--spacing-sm` block
|
|
22
|
+
and `--spacing-md` inline tab padding; the five property-qualified label
|
|
23
|
+
typography tokens; `--motion-duration-fast`; and `--motion-easing-standard`.
|
|
24
|
+
|
|
25
|
+
## Variants
|
|
26
|
+
|
|
27
|
+
Two orientations: horizontal (default) and vertical. Orientation changes the
|
|
28
|
+
TabList layout and arrow-key axis, not the selection or panel semantics.
|
|
29
|
+
|
|
30
|
+
## Sizes
|
|
31
|
+
|
|
32
|
+
One size. Tabs use a single label and spacing treatment; do not add compact or
|
|
33
|
+
large scales. The host layout controls available panel width.
|
|
34
|
+
|
|
35
|
+
## States
|
|
36
|
+
|
|
37
|
+
| State | Behavior |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| default | One Tab is selected and its panel is visible. |
|
|
40
|
+
| hover | An enabled Tab signals selection availability. |
|
|
41
|
+
| focus | Focused Tab shows `--color-focus`; focus and selection may differ during keyboard movement. |
|
|
42
|
+
| active | Selected Tab has `aria-selected="true"` and controls the visible panel. |
|
|
43
|
+
| disabled | Tab remains identifiable with `aria-disabled="true"` and `--color-disabled`, but cannot be selected. |
|
|
44
|
+
|
|
45
|
+
## Accessibility
|
|
46
|
+
|
|
47
|
+
Use `tablist`, `tab`, and `tabpanel` roles with `aria-controls` /
|
|
48
|
+
`aria-labelledby`. One Tab is in the tab sequence. Arrow keys move between
|
|
49
|
+
Tabs; `Home`/`End` move to the first/last; `Tab` enters the active panel.
|
|
50
|
+
Prefer automatic activation when panel changes are immediate; use
|
|
51
|
+
`Enter`/`Space` for manual activation when loading is costly. Orientation
|
|
52
|
+
determines the arrow-key axis.
|
|
53
|
+
|
|
54
|
+
## When to use
|
|
55
|
+
|
|
56
|
+
- Two or more peer panels within one page or object.
|
|
57
|
+
- Content where switching is frequent and labels are short.
|
|
58
|
+
|
|
59
|
+
## When NOT to use
|
|
60
|
+
|
|
61
|
+
- Product hierarchy or ancestors; use Breadcrumb.
|
|
62
|
+
- Routes that need independent history/bookmarking unless the selected Tab is
|
|
63
|
+
encoded in the URL without losing tab semantics.
|
|
64
|
+
- A sequential workflow; use explicit steps instead.
|
|
65
|
+
|
|
66
|
+
## Radix/shadcn mapping
|
|
67
|
+
|
|
68
|
+
Maps to Radix Tabs / shadcn Tabs (`Root`, `List`, `Trigger`, `Content`). Keep
|
|
69
|
+
Radix keyboard behavior and restyle only with Kiso semantic tokens.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Textarea
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Textarea collects multi-line free-form text. It is for content whose line
|
|
6
|
+
breaks or length make a single-line Input inappropriate.
|
|
7
|
+
|
|
8
|
+
## Anatomy
|
|
9
|
+
|
|
10
|
+
1. **Native textarea** — editable multi-line value.
|
|
11
|
+
2. **Resize affordance (optional)** — browser-provided, usually vertical only.
|
|
12
|
+
3. **Character count (optional)** — supporting status when a meaningful limit
|
|
13
|
+
exists; it does not replace validation.
|
|
14
|
+
4. **Loading affordance (optional)** — Spinner that does not cover the value.
|
|
15
|
+
|
|
16
|
+
Label, HelperText, and ValidationMessage are composed by FormField.
|
|
17
|
+
|
|
18
|
+
## Variants
|
|
19
|
+
|
|
20
|
+
- **Default** — multi-line entry with a useful initial row count.
|
|
21
|
+
- **Auto-growing** — expands to content up to a documented maximum, without
|
|
22
|
+
causing uncontrolled page jumps.
|
|
23
|
+
- **Fixed-height** — scrolls internally when layout stability is essential.
|
|
24
|
+
- **Read-only** — focusable and selectable, but not editable.
|
|
25
|
+
|
|
26
|
+
## Sizes
|
|
27
|
+
|
|
28
|
+
- **Small** — compact notes with a small expected amount of text.
|
|
29
|
+
- **Medium** — default.
|
|
30
|
+
- **Large** — longer authored content.
|
|
31
|
+
|
|
32
|
+
Size controls minimum block size and padding through semantic tokens. Authors
|
|
33
|
+
may set a content-driven `rows` value; do not encode raw dimensions in the
|
|
34
|
+
component contract.
|
|
35
|
+
|
|
36
|
+
## States
|
|
37
|
+
|
|
38
|
+
| State | Behavior |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| Default | Surface, text, border, and placeholder use their semantic color roles. |
|
|
41
|
+
| Hover | Border emphasis may increase without moving content. |
|
|
42
|
+
| Focus | Visible `--color-focus` ring around the whole control. |
|
|
43
|
+
| Active | Native editing, selection, scrolling, and resize behavior. |
|
|
44
|
+
| Disabled | Native `disabled`; unavailable and uses `--color-disabled`. |
|
|
45
|
+
| Loading | Value remains legible; shows status and avoids resize/layout shifts. |
|
|
46
|
+
| Error | `aria-invalid="true"`, `--color-danger` treatment, and linked ValidationMessage. |
|
|
47
|
+
|
|
48
|
+
Loading communicates ongoing work; disabled communicates unavailability. Use
|
|
49
|
+
both only when the control truly cannot accept edits during that work, and keep
|
|
50
|
+
the loading status independently perceivable.
|
|
51
|
+
|
|
52
|
+
## Accessibility
|
|
53
|
+
|
|
54
|
+
- Associate Label using matching `for` and `id`.
|
|
55
|
+
- Use native `textarea` behavior and appropriate `name`, `autocomplete`,
|
|
56
|
+
`required`, `minlength`, and `maxlength` attributes.
|
|
57
|
+
- Link HelperText, character-count guidance, and ValidationMessage with
|
|
58
|
+
`aria-describedby`; add `aria-invalid` only for an invalid value.
|
|
59
|
+
- Announce a changing character count only near a limit and without noisy
|
|
60
|
+
updates on every keystroke.
|
|
61
|
+
- Preserve standard keyboard editing, selection, undo, paste, scrolling, and
|
|
62
|
+
platform shortcuts. `Enter` inserts a line break; do not submit implicitly.
|
|
63
|
+
|
|
64
|
+
## When to use
|
|
65
|
+
|
|
66
|
+
- For descriptions, notes, queries, or other multi-line text.
|
|
67
|
+
- When line breaks are meaningful or expected.
|
|
68
|
+
- In FormField when contextual help or validation is present.
|
|
69
|
+
|
|
70
|
+
## When NOT to use
|
|
71
|
+
|
|
72
|
+
- Do not use for a single short value; use Input.
|
|
73
|
+
- Do not use as a code editor when syntax, line numbers, or editor commands are
|
|
74
|
+
required; that needs a specialized component.
|
|
75
|
+
- Do not prevent paste or ordinary keyboard editing.
|
|
76
|
+
- Do not use placeholder text as the only label or instruction.
|
|
77
|
+
|
|
78
|
+
## Tokens
|
|
79
|
+
|
|
80
|
+
Use the same exact mapping as Input: `--color-surface`, `--color-foreground`,
|
|
81
|
+
`--color-subtle-foreground`, `--color-border`, `--color-focus`,
|
|
82
|
+
`--color-disabled`, `--color-danger`; all five body typography properties;
|
|
83
|
+
`--spacing-sm` block and `--spacing-md` inline padding; `--radius-md`;
|
|
84
|
+
`--motion-duration-fast`; and `--motion-easing-standard`. No primitive colors
|
|
85
|
+
or raw values.
|
|
86
|
+
|
|
87
|
+
## Radix/shadcn mapping
|
|
88
|
+
|
|
89
|
+
Maps to [shadcn/ui Textarea](https://ui.shadcn.com/docs/components/textarea),
|
|
90
|
+
which styles native `textarea`. Radix has no Textarea primitive; Kiso preserves
|
|
91
|
+
the native element's interaction and accessibility model.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Toast
|
|
2
|
+
|
|
3
|
+
A transient system notification that confirms an outcome without blocking the
|
|
4
|
+
current task.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Toast reports brief, non-essential outcomes such as “Copied” or “Saved”. It is
|
|
9
|
+
time-limited and appears outside page flow. [Alert](alert.md) is persistent,
|
|
10
|
+
in-page, and appropriate when the condition or recovery must remain visible.
|
|
11
|
+
|
|
12
|
+
## Anatomy
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Toast Provider
|
|
16
|
+
├── Viewport
|
|
17
|
+
└── Toast
|
|
18
|
+
├── Title (required)
|
|
19
|
+
├── Description (optional)
|
|
20
|
+
├── Action (optional)
|
|
21
|
+
└── Dismiss (optional IconButton)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Use `--color-elevated-surface`, `--color-foreground`,
|
|
25
|
+
`--color-muted-foreground`, `--color-border`, `--color-info`, `--color-success`,
|
|
26
|
+
`--color-warning`, or `--color-danger` where severity must be shown;
|
|
27
|
+
`--spacing-md` padding; `--spacing-sm` gap; `--radius-md`; and `--shadow-md`.
|
|
28
|
+
|
|
29
|
+
## Variants
|
|
30
|
+
|
|
31
|
+
Four semantic variants: `neutral` (default), `success`, `warning`, and `error`.
|
|
32
|
+
Status variants change the announcement urgency and semantic accent only; they
|
|
33
|
+
do not turn the whole Toast into a status-colored surface.
|
|
34
|
+
|
|
35
|
+
## Sizes
|
|
36
|
+
|
|
37
|
+
One compact size. Toast has no `sm` / `lg` scales; title, optional description,
|
|
38
|
+
and at most one Action must remain brief enough for the standard treatment.
|
|
39
|
+
|
|
40
|
+
## States
|
|
41
|
+
|
|
42
|
+
| State | Behavior |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| closed (default) | Not present in the viewport. |
|
|
45
|
+
| open | Visible long enough to read; polite announcement for normal notices. |
|
|
46
|
+
| hover/focus | Pause auto-dismiss while pointer or keyboard focus is within. |
|
|
47
|
+
| active | Action runs once; dismiss follows when appropriate. |
|
|
48
|
+
| disabled | Toast is never disabled; an unavailable Action follows Button rules. |
|
|
49
|
+
| loading | Do not toast indefinite progress; show progress in the initiating region. |
|
|
50
|
+
| error | Only for brief, already recoverable failures; persistent/blocking errors are Alert. |
|
|
51
|
+
|
|
52
|
+
## Accessibility
|
|
53
|
+
|
|
54
|
+
Use a managed live region: `role="status"` / polite for ordinary outcomes and
|
|
55
|
+
assertive announcement only for urgent errors. Do not move focus to a newly
|
|
56
|
+
appearing Toast. `F8` may move focus to the Toast viewport (Radix convention);
|
|
57
|
+
`Tab` reaches Action/Dismiss after focus enters it; `Escape` dismisses. Pause
|
|
58
|
+
the timer on hover, focus, and page blur. Never make Toast the only copy of an
|
|
59
|
+
essential error, completed record, or required recovery step.
|
|
60
|
+
|
|
61
|
+
## When to use
|
|
62
|
+
|
|
63
|
+
- Brief confirmation of a completed, non-blocking action.
|
|
64
|
+
- A background event whose details remain available elsewhere.
|
|
65
|
+
- An optional undo action that is also recoverable through normal product UI.
|
|
66
|
+
|
|
67
|
+
## When NOT to use
|
|
68
|
+
|
|
69
|
+
- A condition that must remain visible or blocks progress; use Alert.
|
|
70
|
+
- Field validation; use ValidationMessage.
|
|
71
|
+
- A confirmation that requires a decision; use Modal/Dialog.
|
|
72
|
+
- Long content, multiple actions, or ongoing progress.
|
|
73
|
+
|
|
74
|
+
## Radix/shadcn mapping
|
|
75
|
+
|
|
76
|
+
Behavior maps to Radix Toast (`Provider`, `Viewport`, `Root`, `Title`,
|
|
77
|
+
`Description`, `Action`, `Close`). shadcn currently recommends Sonner; it is
|
|
78
|
+
acceptable when configured to preserve the live-region, pause, keyboard, and
|
|
79
|
+
semantic-token rules above. Do not copy library hard-coded colors or timing
|
|
80
|
+
values.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Tooltip
|
|
2
|
+
|
|
3
|
+
A short, non-essential hint on hover or keyboard focus. Progressive
|
|
4
|
+
enhancement only.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Tooltip clarifies a control the person can already use: the accessible name
|
|
9
|
+
of an [IconButton](icon-button.md), a keyboard shortcut, an abbreviated
|
|
10
|
+
column header. If the person cannot succeed without the Tooltip, the UI is
|
|
11
|
+
wrong — put the information on the screen.
|
|
12
|
+
|
|
13
|
+
User story #10: **do not use Tooltip on touch**, and **never put essential
|
|
14
|
+
information in a Tooltip**.
|
|
15
|
+
|
|
16
|
+
Tooltip is not [Alert](alert.md), not field help (HelperText), and not a
|
|
17
|
+
rich overlay (Popover, later slice).
|
|
18
|
+
|
|
19
|
+
## Anatomy
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Tooltip.Provider (once per app)
|
|
23
|
+
└── Tooltip
|
|
24
|
+
├── Trigger (the existing control: usually IconButton, sometimes a
|
|
25
|
+
│ truncated string)
|
|
26
|
+
└── Content (short text; optional keyboard hint)
|
|
27
|
+
└── Arrow (optional; skip if it adds noise)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- **Trigger.** Almost always an existing control that already has a name.
|
|
31
|
+
Tooltip does not *become* the name.
|
|
32
|
+
- **Content.** A few words that match or slightly expand the name. Optional
|
|
33
|
+
shortcut, written as the keys themselves ("⌘K"), not as a sentence.
|
|
34
|
+
- **Arrow.** Optional. Prefer none; alignment and `--spacing-xs` offset are
|
|
35
|
+
enough.
|
|
36
|
+
|
|
37
|
+
## Variants
|
|
38
|
+
|
|
39
|
+
One variant. No color-coded "error tooltips". Errors are ValidationMessage
|
|
40
|
+
or Alert, and they are essential — they cannot live in a Tooltip.
|
|
41
|
+
|
|
42
|
+
| Treatment | Tokens |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| Default | Background `--color-elevated-surface`, text `--color-foreground`, border `--color-border`, radius `--radius-sm`, padding `--spacing-xs` `--spacing-sm`, all five property-qualified metadata typography tokens, shadow `--shadow-sm`. |
|
|
45
|
+
|
|
46
|
+
Keyboard shortcut inside Content uses `--type-role-code-font-family`,
|
|
47
|
+
`--type-role-code-font-size`, `--type-role-code-font-weight`,
|
|
48
|
+
`--type-role-code-letter-spacing`, and `--type-role-code-line-height`.
|
|
49
|
+
|
|
50
|
+
Placement: `top` by default, flip on collision (`side` + `align` from the
|
|
51
|
+
Radix reference). Offset `--spacing-xs` from the trigger. Do not specify
|
|
52
|
+
the offset in raw pixels.
|
|
53
|
+
|
|
54
|
+
## Sizes
|
|
55
|
+
|
|
56
|
+
One size: `--type-role-metadata-font-family`, `--type-role-metadata-font-size`,
|
|
57
|
+
`--type-role-metadata-font-weight`, `--type-role-metadata-letter-spacing`, and
|
|
58
|
+
`--type-role-metadata-line-height`. Content wraps; max width is a reading
|
|
59
|
+
measure of a short phrase (about three or four words per line, a couple of
|
|
60
|
+
lines). If you need a paragraph, you need HelperText, Alert, or Popover.
|
|
61
|
+
|
|
62
|
+
## States
|
|
63
|
+
|
|
64
|
+
| State | Behavior |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| closed (default) | Content not shown. Trigger is usable. |
|
|
67
|
+
| delayed-open | Pointer hover still; waiting the delay. |
|
|
68
|
+
| open | Content visible. |
|
|
69
|
+
| hover (trigger) | Starts the open delay. |
|
|
70
|
+
| focus (trigger) | Opens without the pointer delay (keyboard). |
|
|
71
|
+
| active (trigger) | Activation **closes** the Tooltip and runs the control. |
|
|
72
|
+
| disabled trigger | Native disabled controls do not hover. If a disabled [Button](button.md) must explain *why*, that explanation is adjacent copy or HelperText — **not** a Tooltip on a wrapper span. Disabled-why is essential, so Tooltip is the wrong place. |
|
|
73
|
+
| loading | N/A for Tooltip itself. |
|
|
74
|
+
| error | N/A. |
|
|
75
|
+
|
|
76
|
+
**Touch / coarse pointer:** do not open. `pointer: coarse` (and the absence
|
|
77
|
+
of hover) means the Content never appears. The trigger must remain fully
|
|
78
|
+
usable. This is a hard rule, not a nice-to-have.
|
|
79
|
+
|
|
80
|
+
**Delay:** follow the Radix Provider default (open delay, skip-delay when
|
|
81
|
+
moving between triggers). Do not open instantly on pointer hover — that
|
|
82
|
+
flickers. Keyboard focus opens without the pointer delay.
|
|
83
|
+
|
|
84
|
+
Motion: fade/scale with `--motion-duration-fast` and
|
|
85
|
+
`--motion-easing-standard`. Reduced motion: show and hide with no travel.
|
|
86
|
+
|
|
87
|
+
## Accessibility
|
|
88
|
+
|
|
89
|
+
- Content has `role="tooltip"` and is referenced from the trigger with
|
|
90
|
+
`aria-describedby` when open (Radix does this).
|
|
91
|
+
- The trigger's **accessible name** stays on the trigger (`aria-label` on
|
|
92
|
+
IconButton, visible text on Button). Tooltip is a description, not a
|
|
93
|
+
name. If the Tooltip text *is* the name, it must duplicate `aria-label`,
|
|
94
|
+
not replace it.
|
|
95
|
+
- Content is plain text. No Buttons, no Links, no inputs. Interactive
|
|
96
|
+
content is Popover.
|
|
97
|
+
- Do not set `aria-hidden` on Content while it is shown.
|
|
98
|
+
- Never the only path to a label, an error, a shortcut that is required,
|
|
99
|
+
or a destructive-consequence warning.
|
|
100
|
+
- Touch: because Content does not open, anything that was only in the
|
|
101
|
+
Tooltip is unavailable — another reason it cannot be essential.
|
|
102
|
+
|
|
103
|
+
### Keyboard
|
|
104
|
+
|
|
105
|
+
From Radix Tooltip:
|
|
106
|
+
|
|
107
|
+
| Key | Action |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `Tab` | Focus on the trigger opens the Tooltip without delay; focus away closes it. |
|
|
110
|
+
| `Escape` | Closes without delay. |
|
|
111
|
+
| `Enter` / `Space` | Activate the trigger; Tooltip closes. |
|
|
112
|
+
|
|
113
|
+
There is no Tooltip-specific tab stop. Content is not focused.
|
|
114
|
+
|
|
115
|
+
## When to use
|
|
116
|
+
|
|
117
|
+
- Repeating an IconButton's `aria-label` for pointer users.
|
|
118
|
+
- Showing a keyboard shortcut next to a named control.
|
|
119
|
+
- Expanding a truncated string (filename, query) where the full value is
|
|
120
|
+
also available by expanding the row or focusing a cell — the Tooltip is a
|
|
121
|
+
shortcut to read it, not the only copy.
|
|
122
|
+
|
|
123
|
+
## When NOT to use
|
|
124
|
+
|
|
125
|
+
- **Touch as a primary environment for that control.** If the product's
|
|
126
|
+
use of the control is touch-first, put a visible label on the screen.
|
|
127
|
+
- **Essential information.** Errors, permissions, destructive consequences,
|
|
128
|
+
how to complete the task. User story #10.
|
|
129
|
+
- **Field help.** HelperText, always visible or available next to the
|
|
130
|
+
field.
|
|
131
|
+
- **In-page conditions.** [Alert](alert.md).
|
|
132
|
+
- **Rich or interactive content.** Popover (overlay slice).
|
|
133
|
+
- **Disabled-button explanations.** Visible copy; see States.
|
|
134
|
+
- **A substitute for `aria-label`.** IconButton already requires a name.
|
|
135
|
+
- **Delaying first-time discovery of a primary action.** If people need a
|
|
136
|
+
Tooltip to find "Save", the label is missing.
|
|
137
|
+
|
|
138
|
+
## Radix/shadcn mapping
|
|
139
|
+
|
|
140
|
+
This is the component with a real Radix primitive. Implement against it.
|
|
141
|
+
|
|
142
|
+
| Kiso | Reference |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| Behavior, delay, keyboard, `role="tooltip"` | Radix [Tooltip](https://www.radix-ui.com/primitives/docs/components/tooltip) (`Provider`, `Root`, `Trigger`, `Portal`, `Content`) |
|
|
145
|
+
| Styling conventions | shadcn [Tooltip](https://ui.shadcn.com/docs/components/tooltip) restyled to the tokens above |
|
|
146
|
+
|
|
147
|
+
Provider wraps the app once. Do not nest Providers per control.
|
|
148
|
+
|
|
149
|
+
shadcn's "Disabled Button" example wraps a disabled Button in a span to
|
|
150
|
+
force a Tooltip. **Do not use that pattern in Kiso.** A disabled-why
|
|
151
|
+
message is essential and must be visible without hover.
|
|
152
|
+
|
|
153
|
+
shadcn (and newer Base UI ports) may differ in API names (`TooltipTrigger`,
|
|
154
|
+
`TooltipContent`). Map parts 1:1 to Radix anatomy; keep Radix keyboard and
|
|
155
|
+
delay behavior as the behavioral source of truth.
|
|
156
|
+
|
|
157
|
+
Skip the arrow if the shadcn default includes one and it adds decoration
|
|
158
|
+
without helping placement.
|
|
159
|
+
|
|
160
|
+
On coarse pointers, do not mount/open Content. Radix will still open on
|
|
161
|
+
long-press in some browsers — suppress that. Long-press is not a Tooltip
|
|
162
|
+
affordance in Kiso; it is a platform selection gesture.
|