@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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/kiso/AGENTS.md +50 -0
  4. package/kiso/README.md +62 -0
  5. package/kiso/docs/accessibility.md +87 -0
  6. package/kiso/docs/brand.md +95 -0
  7. package/kiso/docs/components/README.md +58 -0
  8. package/kiso/docs/components/alert.md +158 -0
  9. package/kiso/docs/components/badge.md +135 -0
  10. package/kiso/docs/components/breadcrumb.md +66 -0
  11. package/kiso/docs/components/button.md +168 -0
  12. package/kiso/docs/components/card.md +154 -0
  13. package/kiso/docs/components/checkbox.md +91 -0
  14. package/kiso/docs/components/command-palette.md +165 -0
  15. package/kiso/docs/components/drawer.md +79 -0
  16. package/kiso/docs/components/dropdown-menu.md +178 -0
  17. package/kiso/docs/components/empty-state.md +142 -0
  18. package/kiso/docs/components/form-field.md +115 -0
  19. package/kiso/docs/components/header.md +79 -0
  20. package/kiso/docs/components/helper-text.md +86 -0
  21. package/kiso/docs/components/icon-button.md +161 -0
  22. package/kiso/docs/components/input.md +99 -0
  23. package/kiso/docs/components/label.md +88 -0
  24. package/kiso/docs/components/link.md +152 -0
  25. package/kiso/docs/components/modal-dialog.md +82 -0
  26. package/kiso/docs/components/navigation.md +68 -0
  27. package/kiso/docs/components/page-header.md +70 -0
  28. package/kiso/docs/components/pagination.md +129 -0
  29. package/kiso/docs/components/popover.md +74 -0
  30. package/kiso/docs/components/search.md +147 -0
  31. package/kiso/docs/components/select.md +105 -0
  32. package/kiso/docs/components/sidebar.md +74 -0
  33. package/kiso/docs/components/skeleton.md +140 -0
  34. package/kiso/docs/components/spinner.md +125 -0
  35. package/kiso/docs/components/switch.md +92 -0
  36. package/kiso/docs/components/table.md +255 -0
  37. package/kiso/docs/components/tabs.md +69 -0
  38. package/kiso/docs/components/textarea.md +91 -0
  39. package/kiso/docs/components/toast.md +80 -0
  40. package/kiso/docs/components/tooltip.md +162 -0
  41. package/kiso/docs/components/validation-message.md +96 -0
  42. package/kiso/docs/data-interfaces.md +309 -0
  43. package/kiso/docs/evolution.md +35 -0
  44. package/kiso/docs/patterns/README.md +40 -0
  45. package/kiso/docs/patterns/application-shell.md +106 -0
  46. package/kiso/docs/patterns/command-palette.md +142 -0
  47. package/kiso/docs/patterns/confirmations.md +158 -0
  48. package/kiso/docs/patterns/crud.md +139 -0
  49. package/kiso/docs/patterns/dashboard.md +102 -0
  50. package/kiso/docs/patterns/destructive-actions.md +137 -0
  51. package/kiso/docs/patterns/developer-oriented-interfaces.md +162 -0
  52. package/kiso/docs/patterns/empty-states.md +76 -0
  53. package/kiso/docs/patterns/errors.md +93 -0
  54. package/kiso/docs/patterns/filtering.md +147 -0
  55. package/kiso/docs/patterns/keyboard-shortcuts.md +155 -0
  56. package/kiso/docs/patterns/large-data-tables.md +182 -0
  57. package/kiso/docs/patterns/list-detail.md +118 -0
  58. package/kiso/docs/patterns/loading.md +80 -0
  59. package/kiso/docs/patterns/login-authentication.md +101 -0
  60. package/kiso/docs/patterns/onboarding.md +94 -0
  61. package/kiso/docs/patterns/pagination.md +121 -0
  62. package/kiso/docs/patterns/permission-denied.md +84 -0
  63. package/kiso/docs/patterns/search.md +150 -0
  64. package/kiso/docs/patterns/settings.md +100 -0
  65. package/kiso/docs/patterns/sorting.md +121 -0
  66. package/kiso/docs/principles.md +122 -0
  67. package/kiso/docs/tokens.md +95 -0
  68. package/kiso/docs/voice-and-tone.md +154 -0
  69. package/package.json +42 -0
  70. package/tokens/build/tokens.css +143 -0
  71. package/tokens/build/tokens.d.ts +160 -0
  72. package/tokens/build/tokens.json +88 -0
  73. 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.