@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,135 @@
|
|
|
1
|
+
# Badge
|
|
2
|
+
|
|
3
|
+
A small inline status label. Not a button, not a card, not a count of
|
|
4
|
+
notifications by itself.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Badge names a state or classification next to something else: "New",
|
|
9
|
+
"Beta", "live", "primary", "read replica". It is read, not clicked.
|
|
10
|
+
|
|
11
|
+
User story #18: Badge is for status labels; [Card](card.md) is for grouping
|
|
12
|
+
related content.
|
|
13
|
+
|
|
14
|
+
If the person must act on the status, pair the Badge with a
|
|
15
|
+
[Button](button.md) / [Link](link.md). Do not make the Badge the control.
|
|
16
|
+
|
|
17
|
+
## Anatomy
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Badge
|
|
21
|
+
├── leading icon or dot (optional)
|
|
22
|
+
├── label (required)
|
|
23
|
+
└── trailing icon (optional; rarely needed)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Label.** One or two words. Lowercase product nouns are fine ("live",
|
|
27
|
+
"beta"); proper names keep their form. Follow
|
|
28
|
+
[voice-and-tone](../voice-and-tone.md): direct, no filler.
|
|
29
|
+
- **Dot / icon.** Optional severity or category cue. Decorative
|
|
30
|
+
(`aria-hidden="true"`) when the label already says the state. If the Badge
|
|
31
|
+
is icon-only (avoid this), it needs `aria-label`.
|
|
32
|
+
- **No dismiss control.** A dismissible status is an [Alert](alert.md) or a
|
|
33
|
+
filter chip (not in this slice). Badge is not closable.
|
|
34
|
+
|
|
35
|
+
## Variants
|
|
36
|
+
|
|
37
|
+
Variants encode *meaning*, using status and foreground roles. Do not invent
|
|
38
|
+
ad-hoc colors.
|
|
39
|
+
|
|
40
|
+
| Variant | Meaning | Tokens |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `neutral` (default) | Classification without severity: "Beta", "read", "v2". | Text `--color-foreground`, background `--color-surface`, border `--color-border`. |
|
|
43
|
+
| `info` | Informational state: "New", "preview". | Text `--color-info`, border `--color-info`, background `--color-surface`. |
|
|
44
|
+
| `success` | Healthy / complete: "live", "connected", "healthy". | Text `--color-success`, border `--color-success`, background `--color-surface`. |
|
|
45
|
+
| `warning` | Needs attention: "degraded", "stale". | Text `--color-warning`, border `--color-warning`, background `--color-surface`. |
|
|
46
|
+
| `danger` | Failed / blocked: "down", "unhealthy". | Text `--color-danger`, border `--color-danger`, background `--color-surface`. |
|
|
47
|
+
|
|
48
|
+
Fill stays `--color-surface` so the status color is the text and border.
|
|
49
|
+
That keeps contrast on the AA gate (status roles are checked against
|
|
50
|
+
`surface`). Do not paint the whole Badge `--color-danger` and then guess a
|
|
51
|
+
foreground.
|
|
52
|
+
|
|
53
|
+
Do not add a `primary` Badge to shout marketing emphasis. If the thing is
|
|
54
|
+
the main object, that is typography and hierarchy, not a Badge.
|
|
55
|
+
|
|
56
|
+
An optional `outline` look is `neutral` with transparent background — still
|
|
57
|
+
`--color-border`, not a new variant.
|
|
58
|
+
|
|
59
|
+
## Sizes
|
|
60
|
+
|
|
61
|
+
| Size | Type role | Padding | Radius |
|
|
62
|
+
| --- | --- | --- | --- |
|
|
63
|
+
| `sm` (default) | Metadata properties (`--type-role-metadata-font-family`, `--type-role-metadata-font-size`, `--type-role-metadata-font-weight`, `--type-role-metadata-letter-spacing`, `--type-role-metadata-line-height`) | `--spacing-xs` | `--radius-sm` |
|
|
64
|
+
| `md` | Label properties (`--type-role-label-font-family`, `--type-role-label-font-size`, `--type-role-label-font-weight`, `--type-role-label-letter-spacing`, `--type-role-label-line-height`) | `--spacing-xs` block, `--spacing-sm` inline | `--radius-sm` |
|
|
65
|
+
|
|
66
|
+
Do not use `--radius-full` (pill). Badges are compact labels, not tags in
|
|
67
|
+
a marketing cluster.
|
|
68
|
+
|
|
69
|
+
## States
|
|
70
|
+
|
|
71
|
+
Badge is not interactive by default.
|
|
72
|
+
|
|
73
|
+
| State | Behavior |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| default | Static label. |
|
|
76
|
+
| hover / focus / active | None, unless the Badge is wrapped by a Link (see below). |
|
|
77
|
+
| disabled | N/A. Hide a Badge that no longer applies; do not grey it. |
|
|
78
|
+
| loading | Optional: replace the label with a tiny [Spinner](spinner.md) plus a word ("syncing"). Prefer Skeleton on the parent region if the whole status is unknown. |
|
|
79
|
+
| error | Use `danger` as the *meaning*, not a separate error state. |
|
|
80
|
+
|
|
81
|
+
If a Badge is a Link (filter that navigates to a tagged view), the Link is
|
|
82
|
+
the interactive element: Badge provides appearance only. Focus ring
|
|
83
|
+
`--color-focus` on the Link. Do not put `onClick` on a `span` Badge.
|
|
84
|
+
|
|
85
|
+
## Accessibility
|
|
86
|
+
|
|
87
|
+
- Default element: `<span>`. No `role="status"` on every Badge — that would
|
|
88
|
+
shout every "Beta" as a live region. The surrounding content already
|
|
89
|
+
includes the object; the Badge is extra words in that name.
|
|
90
|
+
- If the Badge is the only indication of a *changing* live state that the
|
|
91
|
+
person must notice (connection dropped), the *region* should update via
|
|
92
|
+
[Alert](alert.md) or `aria-live`, not a silent Badge swap.
|
|
93
|
+
- Color is not the only cue: the label text carries the meaning. A red
|
|
94
|
+
empty Badge is a fail.
|
|
95
|
+
- Icon-only: `aria-label` required. Prefer text.
|
|
96
|
+
|
|
97
|
+
### Keyboard
|
|
98
|
+
|
|
99
|
+
No keymap. A Badge that is a Link follows [Link](link.md) keyboard rules.
|
|
100
|
+
|
|
101
|
+
## When to use
|
|
102
|
+
|
|
103
|
+
- A short status or classification next to a title, table cell, or Card
|
|
104
|
+
title: "New", "Beta", "live", "primary".
|
|
105
|
+
- Several orthogonal labels ("live" + "read replica") — each is its own
|
|
106
|
+
Badge, not one concatenated string.
|
|
107
|
+
|
|
108
|
+
## When NOT to use
|
|
109
|
+
|
|
110
|
+
- **Grouping content.** [Card](card.md).
|
|
111
|
+
- **In-page warnings with explanation and recovery.** [Alert](alert.md).
|
|
112
|
+
- **Actions.** Buttons, IconButtons, and Links. A "Delete" Badge is a
|
|
113
|
+
mistake.
|
|
114
|
+
- **Counts, notifications, or numeric attention dots.** If Kiso needs a
|
|
115
|
+
notification count later, that is not this component. A numeric "3" Badge
|
|
116
|
+
on an icon is chrome, not a status label.
|
|
117
|
+
- **Section headings or filters that look like a pile of pills.** Filters
|
|
118
|
+
are Controls; they belong with Input/Select or a later pattern.
|
|
119
|
+
- **Long sentences.** If it needs punctuation, it is copy, not a Badge.
|
|
120
|
+
|
|
121
|
+
## Radix/shadcn mapping
|
|
122
|
+
|
|
123
|
+
No Radix Badge primitive. Visual reference: shadcn
|
|
124
|
+
[Badge](https://ui.shadcn.com/docs/components/badge).
|
|
125
|
+
|
|
126
|
+
| Kiso | shadcn |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| `neutral` | `secondary` or `outline` restyled to `--color-surface` / `--color-border` / `--color-foreground` |
|
|
129
|
+
| `info` / `success` / `warning` / `danger` | Do not use arbitrary `bg-green-*` utilities from the shadcn "Custom Colors" example. Map respectively to `--color-info`, `--color-success`, `--color-warning`, or `--color-danger`. |
|
|
130
|
+
| shadcn `destructive` | Closest to Kiso `danger` |
|
|
131
|
+
| shadcn `default` (accent fill) | Do not use as a status; it competes with primary actions |
|
|
132
|
+
| shadcn `variant="link"` | Do not use; navigation is [Link](link.md) |
|
|
133
|
+
|
|
134
|
+
If the Badge navigates, compose shadcn Badge visuals on an `<a>` the same
|
|
135
|
+
way Button-look Links do — do not use a Button.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Breadcrumb
|
|
2
|
+
|
|
3
|
+
Shows the current page's position in a hierarchy and links to its ancestors.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Breadcrumb answers “where am I?” across nested routes. Unlike [Tabs](tabs.md),
|
|
8
|
+
it does not switch peer content within the current page.
|
|
9
|
+
|
|
10
|
+
## Anatomy
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Breadcrumb navigation
|
|
14
|
+
└── ordered list
|
|
15
|
+
├── ancestor Link
|
|
16
|
+
├── separator (decorative)
|
|
17
|
+
└── current page (text)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use `--color-muted-foreground` for ancestors, `--color-foreground` for the
|
|
21
|
+
current page, `--color-primary` for Link interaction, and `--color-focus` for
|
|
22
|
+
focus. Separators use the muted role and are hidden from assistive technology.
|
|
23
|
+
|
|
24
|
+
## Variants
|
|
25
|
+
|
|
26
|
+
No visual variants. Breadcrumb always represents one hierarchy; overflow is a
|
|
27
|
+
state that collapses middle ancestors, not a separate variant.
|
|
28
|
+
|
|
29
|
+
## Sizes
|
|
30
|
+
|
|
31
|
+
One size. Use the standard body/link treatment and semantic spacing; do not
|
|
32
|
+
create compact or large breadcrumb scales.
|
|
33
|
+
|
|
34
|
+
## States
|
|
35
|
+
|
|
36
|
+
| State | Behavior |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| default | Ancestors are Links; the current page is plain text. |
|
|
39
|
+
| hover | Ancestor Link shows its Link hover treatment. |
|
|
40
|
+
| focus | Focused ancestor shows `--color-focus`. |
|
|
41
|
+
| active | Pressing an ancestor follows its URL. Current page carries `aria-current="page"`. |
|
|
42
|
+
| disabled | N/A. Do not render a disabled breadcrumb Link. |
|
|
43
|
+
| overflow | Collapse middle ancestors into an accessible menu; keep the root and current page visible. |
|
|
44
|
+
|
|
45
|
+
## Accessibility
|
|
46
|
+
|
|
47
|
+
Use `<nav aria-label="Breadcrumb">` with an `<ol>`. Separators are CSS or
|
|
48
|
+
`aria-hidden="true"`. Do not make the current page a self-link. Keyboard
|
|
49
|
+
behavior is native Link/menu behavior; `Tab` visits Links, not separators.
|
|
50
|
+
|
|
51
|
+
## When to use
|
|
52
|
+
|
|
53
|
+
- Routes at least two meaningful levels deep.
|
|
54
|
+
- Technical products where parent context is useful for returning upward.
|
|
55
|
+
|
|
56
|
+
## When NOT to use
|
|
57
|
+
|
|
58
|
+
- Switching panels on one page; use Tabs.
|
|
59
|
+
- A flat product with no hierarchy.
|
|
60
|
+
- As a substitute for the page title or browser history.
|
|
61
|
+
|
|
62
|
+
## Radix/shadcn mapping
|
|
63
|
+
|
|
64
|
+
Radix has no Breadcrumb primitive. Map structure to shadcn Breadcrumb while
|
|
65
|
+
preserving native `<nav>`, ordered-list, and Link semantics. Use DropdownMenu
|
|
66
|
+
for collapsed middle items.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Button
|
|
2
|
+
|
|
3
|
+
Triggers an in-page action. It does not change the URL.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Button is the control for *doing something*: submit a form, run a query, open
|
|
8
|
+
a dialog, save, delete. The person activates it; the application performs
|
|
9
|
+
behavior.
|
|
10
|
+
|
|
11
|
+
If the destination is a URL, use [Link](link.md). If the action is an icon
|
|
12
|
+
with no visible text, use [IconButton](icon-button.md).
|
|
13
|
+
|
|
14
|
+
### Choose the right control
|
|
15
|
+
|
|
16
|
+
| Need | Control | Why |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| Trigger behavior (submit, save, delete, open) | **Button** | Action; URL does not change. |
|
|
19
|
+
| Icon-only action (toolbar, compact chrome) | **[IconButton](icon-button.md)** | Same as Button, but the accessible name is not visible text. |
|
|
20
|
+
| Go to a URL (in-app or external) | **[Link](link.md)** | Navigation; must remain a real link (open in new tab, copy URL). |
|
|
21
|
+
|
|
22
|
+
A Button that looks like a link is still a Button and is the wrong control for
|
|
23
|
+
navigation. A Link that looks like a Button is still a Link: visual style does
|
|
24
|
+
not change the semantics.
|
|
25
|
+
|
|
26
|
+
A Button may include an icon *plus* a text label. That is still Button, not
|
|
27
|
+
IconButton.
|
|
28
|
+
|
|
29
|
+
## Anatomy
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Button
|
|
33
|
+
├── leading icon (optional)
|
|
34
|
+
├── label (required visible text)
|
|
35
|
+
├── trailing icon (optional)
|
|
36
|
+
└── Spinner (loading state only; replaces or precedes the label)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- **Label.** Direct verb phrase. Follow
|
|
40
|
+
[voice-and-tone](../voice-and-tone.md): "Save query", "Delete replica",
|
|
41
|
+
"Run". Not "Click here", not "Submit" when a specific verb exists.
|
|
42
|
+
- **Icon.** Optional reinforcement of the label. Never the only name — that
|
|
43
|
+
is IconButton.
|
|
44
|
+
- **Spinner.** Only while the action is pending. See
|
|
45
|
+
[Spinner](spinner.md).
|
|
46
|
+
|
|
47
|
+
## Variants
|
|
48
|
+
|
|
49
|
+
Four variants. Do not add a "link" variant; navigation is [Link](link.md).
|
|
50
|
+
|
|
51
|
+
| Variant | When | Tokens |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `default` | Secondary action on the current task. Most buttons. | Background `--color-surface`, text `--color-foreground`, border `--color-border`. Hover background `--color-elevated-surface`. |
|
|
54
|
+
| `primary` | The one action that advances the current task. At most one primary Button per region. | Background `--color-surface`, text and border `--color-primary`, label `--type-weight-semibold`. Hover background `--color-elevated-surface`. |
|
|
55
|
+
| `destructive` | Irreversible or destructive action (delete, drop, disconnect). User story #4. | Background `--color-surface`, text and border `--color-danger`. Hover background `--color-elevated-surface`. Match confirmation weight to stakes; see voice-and-tone. |
|
|
56
|
+
| `ghost` | Low-emphasis action in chrome, toolbars, or inside a Card. | Transparent background and border. Text `--color-foreground`. Hover background `--color-surface`. |
|
|
57
|
+
|
|
58
|
+
`primary` and `danger` are text roles (checked against surfaces in the AA
|
|
59
|
+
gate). `--color-background` is canvas and is never text, so these variants
|
|
60
|
+
are **not** filled inversions. A filled "on-primary" treatment would need a
|
|
61
|
+
new semantic role; do not invent one here and do not borrow the canvas
|
|
62
|
+
role as ink.
|
|
63
|
+
|
|
64
|
+
If a destructive action is not irreversible (archive, disable, hide), use
|
|
65
|
+
`default` or `ghost`, not `destructive`.
|
|
66
|
+
|
|
67
|
+
## Sizes
|
|
68
|
+
|
|
69
|
+
| Size | Type role | Padding | Radius | Use |
|
|
70
|
+
| --- | --- | --- | --- | --- |
|
|
71
|
+
| `sm` | Label properties (`--type-role-label-font-family`, `--type-role-label-font-size`, `--type-role-label-font-weight`, `--type-role-label-letter-spacing`, `--type-role-label-line-height`) | `--spacing-xs` block, `--spacing-sm` inline | `--radius-sm` | Dense tables, Card footers, compact filters. |
|
|
72
|
+
| `md` (default) | Same label properties | `--spacing-sm` block, `--spacing-md` inline | `--radius-md` | Forms, page actions, dialogs. |
|
|
73
|
+
| `lg` | Same label properties | `--spacing-md` block, `--spacing-lg` inline | `--radius-md` | Rare; empty-state or onboarding primary actions. |
|
|
74
|
+
|
|
75
|
+
Do not invent a fourth size. Page-level calls to action still use `md` or
|
|
76
|
+
`lg`. PageHeader (navigation slice) composes Buttons; it is not a Button
|
|
77
|
+
size.
|
|
78
|
+
|
|
79
|
+
## States
|
|
80
|
+
|
|
81
|
+
| State | Behavior | Tokens / notes |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| default | Interactive. | Variant tokens above. |
|
|
84
|
+
| hover | Pointer over the control. | See variant hover. Cursor indicates affordance. Transition: `--motion-duration-fast` / `--motion-easing-standard`. |
|
|
85
|
+
| focus | Keyboard focus. | Visible ring using `--color-focus`. Never remove the ring without an equivalent. |
|
|
86
|
+
| active | Pointer down / activation. | Slightly pressed; keep the same semantic colors. |
|
|
87
|
+
| disabled | Interaction blocked. The person must see *that* it is blocked. User story #12. | Text and chrome `--color-disabled`. Not in the tab order (`disabled` on `<button>`). If the reason is not obvious from context, state it in adjacent copy — not inside a Tooltip. |
|
|
88
|
+
| loading | Interaction pending. User story #12. | `aria-busy="true"`. Show [Spinner](spinner.md); keep the original label or replace with a specific loading verb ("Saving…"). Ignore further activations. Do not swap loading for disabled: disabled means "cannot", loading means "working". |
|
|
89
|
+
| error | Not a Button state. | Failure belongs on [Alert](alert.md) or a field ValidationMessage, not on the Button. After failure, return the Button to default so the person can retry. |
|
|
90
|
+
|
|
91
|
+
Disabled is exempt from the AA text-contrast gate (`--color-disabled` is
|
|
92
|
+
intentionally outside it). Loading is not exempt: Spinner and remaining text
|
|
93
|
+
must still meet contrast.
|
|
94
|
+
|
|
95
|
+
## Accessibility
|
|
96
|
+
|
|
97
|
+
- Native `<button>` (or a component that renders one). Do not put
|
|
98
|
+
`role="button"` on a link or a `div`.
|
|
99
|
+
- `type="button"` unless the Button submits a form (`type="submit"`) or
|
|
100
|
+
resets it (`type="reset"`). A Button inside a form without an explicit
|
|
101
|
+
type is a silent submit — that is a bug.
|
|
102
|
+
- Accessible name is the visible label. Do not override it with a different
|
|
103
|
+
`aria-label`.
|
|
104
|
+
- Focus visible at all times using `--color-focus`.
|
|
105
|
+
- Disabled uses the native `disabled` attribute (removed from tab order).
|
|
106
|
+
Loading may also set `disabled` to prevent double-submit; keep `aria-busy`
|
|
107
|
+
so the pending state is announced.
|
|
108
|
+
- Icon + text: the icon is decorative (`aria-hidden="true"`); the text is the
|
|
109
|
+
name.
|
|
110
|
+
|
|
111
|
+
### Keyboard
|
|
112
|
+
|
|
113
|
+
| Key | Action |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `Enter` | Activate. |
|
|
116
|
+
| `Space` | Activate. |
|
|
117
|
+
| `Tab` / `Shift+Tab` | Move focus to the next / previous control. |
|
|
118
|
+
|
|
119
|
+
## When to use
|
|
120
|
+
|
|
121
|
+
- The person is causing an action: save, run, create, delete, confirm, retry.
|
|
122
|
+
- The action stays on this URL (including opening a dialog or drawer).
|
|
123
|
+
- Form submit and form-reset controls.
|
|
124
|
+
- PageHeader actions (title + subtitle + Buttons — composition lands in a
|
|
125
|
+
later slice).
|
|
126
|
+
|
|
127
|
+
## When NOT to use
|
|
128
|
+
|
|
129
|
+
- **Navigation.** Anything that should change the URL, support open-in-new-tab,
|
|
130
|
+
or be copyable as a link — use [Link](link.md), even if it is styled to look
|
|
131
|
+
like a Button.
|
|
132
|
+
- **Icon with no text.** Use [IconButton](icon-button.md).
|
|
133
|
+
- **A row of mutually exclusive choices.** That is Tabs or a Select, not a
|
|
134
|
+
Button group pretending to be navigation.
|
|
135
|
+
- **Toggling a boolean.** Use Switch or Checkbox (form primitives), not a
|
|
136
|
+
Button whose label flips.
|
|
137
|
+
- **In-page warnings.** Use [Alert](alert.md) for the message; the Alert may
|
|
138
|
+
*contain* a Button for recovery.
|
|
139
|
+
|
|
140
|
+
## Radix/shadcn mapping
|
|
141
|
+
|
|
142
|
+
There is no Radix Button primitive. Behavior is the native `<button>`.
|
|
143
|
+
|
|
144
|
+
| Kiso | Reference |
|
|
145
|
+
| --- | --- |
|
|
146
|
+
| Composition onto a child (rare; prefer a real `<button>`) | Radix [Slot](https://www.radix-ui.com/primitives/docs/utilities/slot) (`asChild`) |
|
|
147
|
+
| Visual system, sizes, variants | shadcn [Button](https://ui.shadcn.com/docs/components/button) |
|
|
148
|
+
|
|
149
|
+
Map Kiso variants onto shadcn *by intent*, not by name:
|
|
150
|
+
|
|
151
|
+
| Kiso variant | shadcn `variant` |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `primary` | `outline`, restyled: `--color-primary` text and border, `--type-weight-semibold`. Do not use shadcn's filled `default` — that needs an on-primary text role Kiso does not have. |
|
|
154
|
+
| `default` | `outline` with `--color-foreground` / `--color-border` |
|
|
155
|
+
| `destructive` | `outline` restyled with `--color-danger` text and border, not filled `destructive` |
|
|
156
|
+
| `ghost` | `ghost` |
|
|
157
|
+
|
|
158
|
+
Do **not** use shadcn `variant="link"`. That style is [Link](link.md).
|
|
159
|
+
|
|
160
|
+
Do **not** use shadcn `size="icon"` here. That is [IconButton](icon-button.md).
|
|
161
|
+
|
|
162
|
+
shadcn's "As Link" / `buttonVariants` helper is valid when a *navigation*
|
|
163
|
+
control must *look* like a Button: apply the visual classes to a
|
|
164
|
+
[Link](link.md) (`<a>` / router link). Do not render `<button>` or a
|
|
165
|
+
component that forces `role="button"` for navigation.
|
|
166
|
+
|
|
167
|
+
Loading: compose shadcn Button with shadcn/Kiso [Spinner](spinner.md), as in
|
|
168
|
+
the shadcn Button "Spinner" example. Keep `aria-busy`.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Card
|
|
2
|
+
|
|
3
|
+
Groups related content with visual separation from the surrounding canvas.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Card is a surface for one unit of related content: a cluster of fields, a
|
|
8
|
+
summary of a replica, a setting group, a login form. It creates hierarchy by
|
|
9
|
+
sitting on `--color-surface` against `--color-background`.
|
|
10
|
+
|
|
11
|
+
It is not a status label ([Badge](badge.md)), not an in-page warning
|
|
12
|
+
([Alert](alert.md)), and not a layout primitive for the whole app (Header,
|
|
13
|
+
Sidebar, PageHeader belong to a later slice).
|
|
14
|
+
|
|
15
|
+
User story #18: Badge labels status; Card groups content.
|
|
16
|
+
|
|
17
|
+
## Anatomy
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Card
|
|
21
|
+
├── media (optional, edge-to-edge at the start)
|
|
22
|
+
├── Header (optional)
|
|
23
|
+
│ ├── Title
|
|
24
|
+
│ ├── Description
|
|
25
|
+
│ └── Action (optional: Button, IconButton, Badge, or Link)
|
|
26
|
+
├── Content (optional if Header/Footer already carry the payload)
|
|
27
|
+
└── Footer (optional: actions or supporting meta)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Every part except the root is optional, but a Card with no content is
|
|
31
|
+
decorative and does not belong. Prefer Title + Content as the minimum useful
|
|
32
|
+
shape.
|
|
33
|
+
|
|
34
|
+
- **Title.** Use the heading typography properties (`--type-role-heading-font-family`,
|
|
35
|
+
`--type-role-heading-font-size`, `--type-role-heading-font-weight`,
|
|
36
|
+
`--type-role-heading-letter-spacing`, `--type-role-heading-line-height`) only
|
|
37
|
+
when the Card is a true section; otherwise use the equivalent five
|
|
38
|
+
`--type-role-label-font-family`, `--type-role-label-font-size`,
|
|
39
|
+
`--type-role-label-font-weight`, `--type-role-label-letter-spacing`, and
|
|
40
|
+
`--type-role-label-line-height` properties. One title.
|
|
41
|
+
- **Description.** Use the five body typography properties or the five metadata
|
|
42
|
+
typography properties listed in `tokens/build/tokens.css`. Secondary;
|
|
43
|
+
`--color-muted-foreground`.
|
|
44
|
+
- **Action.** One compact control aligned with the title — not a toolbar.
|
|
45
|
+
- **Content.** The payload. Default type uses `--type-role-body-font-family`,
|
|
46
|
+
`--type-role-body-font-size`, `--type-role-body-font-weight`,
|
|
47
|
+
`--type-role-body-letter-spacing`, and `--type-role-body-line-height`; color
|
|
48
|
+
uses `--color-foreground`.
|
|
49
|
+
- **Footer.** Actions that apply to the whole Card, typically
|
|
50
|
+
[Button](button.md) `sm` / `md`.
|
|
51
|
+
|
|
52
|
+
## Variants
|
|
53
|
+
|
|
54
|
+
| Variant | When | Tokens |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `plain` (default) | Grouping on the page canvas. | Background `--color-surface`, border `--color-border`, radius `--radius-lg`, padding `--spacing-lg`. No shadow. |
|
|
57
|
+
| `elevated` | The grouping must lift above nearby surfaces (a floating picker, a featured summary). | Background `--color-elevated-surface`, border `--color-border`, shadow `--shadow-sm`. Same radius and padding. |
|
|
58
|
+
|
|
59
|
+
Default is `plain`. Tokens.md assigns `--color-surface` to "cards, panels,
|
|
60
|
+
and table rows" and `--color-elevated-surface` to "menus, popovers, and
|
|
61
|
+
dialogs". Use `elevated` only when the Card is competing with other surfaces
|
|
62
|
+
and needs that lift — not on every tile.
|
|
63
|
+
|
|
64
|
+
Do not add outline/ghost Card variants. If the grouping needs no surface,
|
|
65
|
+
it is a section with a heading, not a Card.
|
|
66
|
+
|
|
67
|
+
## Sizes
|
|
68
|
+
|
|
69
|
+
Size changes padding and gap, not type roles.
|
|
70
|
+
|
|
71
|
+
| Size | Padding / gap | Use |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `sm` | `--spacing-md` | Dense dashboards, nested grouping inside a larger region. |
|
|
74
|
+
| `md` (default) | `--spacing-lg` | Standard product Cards. |
|
|
75
|
+
| `lg` | `--spacing-xl` | Rare; a single featured group on an otherwise empty view. |
|
|
76
|
+
|
|
77
|
+
Media that bleeds to the edges still uses the size token for the remaining
|
|
78
|
+
sections, not for the image itself.
|
|
79
|
+
|
|
80
|
+
## States
|
|
81
|
+
|
|
82
|
+
Card is a container. It does not have hover/active/disabled of its own
|
|
83
|
+
unless the *entire Card* is a single destination or action — which is
|
|
84
|
+
usually the wrong pattern (put a Link or Button inside).
|
|
85
|
+
|
|
86
|
+
| State | Behavior |
|
|
87
|
+
| --- | --- |
|
|
88
|
+
| default | Static grouping. |
|
|
89
|
+
| hover | No chrome change for static Cards. If the whole Card is a Link (rare), use `--color-elevated-surface` on hover and a `--color-focus` ring on focus; the Card *is* the Link, not a Button. |
|
|
90
|
+
| focus | Focus lives on interactive children, not the Card. |
|
|
91
|
+
| active | N/A for static Cards. |
|
|
92
|
+
| disabled | Disable the controls inside; do not grey the whole Card unless every action is unavailable — and then explain why in the Content. |
|
|
93
|
+
| loading | Replace Content with [Skeleton](skeleton.md) shaped like the loaded layout, or set `aria-busy="true"` on the Card. Do not cover a Card with a disconnected [Spinner](spinner.md) if the structure is known. |
|
|
94
|
+
| error | Keep the Card; put an [Alert](alert.md) in Content (or replace Content with the Alert). Do not turn the Card border `--color-danger` as the only error cue. |
|
|
95
|
+
|
|
96
|
+
## Accessibility
|
|
97
|
+
|
|
98
|
+
- The Card root is a generic grouping (`<section>` or `<article>` when it is
|
|
99
|
+
a self-contained unit; `<div>` when it is only visual). Do not set
|
|
100
|
+
`role="group"` unless the Card is a true composite widget with its own
|
|
101
|
+
name.
|
|
102
|
+
- If the Card has a Title, point the grouping at it:
|
|
103
|
+
`aria-labelledby` on the section.
|
|
104
|
+
- Interactive children keep their own roles (Button, Link, IconButton).
|
|
105
|
+
Do not make the Card clickable *and* nest Buttons — nested interactive
|
|
106
|
+
elements.
|
|
107
|
+
- Keyboard: no Card-level keymap. Tab moves through the children.
|
|
108
|
+
|
|
109
|
+
### Keyboard
|
|
110
|
+
|
|
111
|
+
| Key | Action |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `Tab` / `Shift+Tab` | Move between interactive children. |
|
|
114
|
+
|
|
115
|
+
## When to use
|
|
116
|
+
|
|
117
|
+
- A bounded cluster of related content that should read as one unit against
|
|
118
|
+
the canvas.
|
|
119
|
+
- A form or setting group that is one task.
|
|
120
|
+
- A summary tile that still contains structure (title, meta, actions) —
|
|
121
|
+
not a single status word.
|
|
122
|
+
|
|
123
|
+
## When NOT to use
|
|
124
|
+
|
|
125
|
+
- **Status labels** ("Beta", "live"). Use [Badge](badge.md).
|
|
126
|
+
- **Warnings and errors about the page or a section.** Use [Alert](alert.md).
|
|
127
|
+
An Alert may sit *inside* a Card; it is not a Card variant.
|
|
128
|
+
- **Every block on the page.** If removing the surface, border, and radius
|
|
129
|
+
does not hurt understanding, it should not be a Card.
|
|
130
|
+
- **Application chrome.** Header, Sidebar, PageHeader, and tables are their
|
|
131
|
+
own components. A data table does not sit in a Card unless the table is a
|
|
132
|
+
small embedded summary.
|
|
133
|
+
- **Clickable marketing tiles with overlay badges.** Product Cards contain
|
|
134
|
+
controls; they are not posters.
|
|
135
|
+
|
|
136
|
+
## Radix/shadcn mapping
|
|
137
|
+
|
|
138
|
+
No Radix Card primitive. Structure follows shadcn
|
|
139
|
+
[Card](https://ui.shadcn.com/docs/components/card):
|
|
140
|
+
|
|
141
|
+
| Kiso | shadcn |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| Card | `Card` |
|
|
144
|
+
| Header | `CardHeader` |
|
|
145
|
+
| Title | `CardTitle` |
|
|
146
|
+
| Description | `CardDescription` |
|
|
147
|
+
| Action | `CardAction` |
|
|
148
|
+
| Content | `CardContent` |
|
|
149
|
+
| Footer | `CardFooter` |
|
|
150
|
+
| `sm` / `md` | `size="sm"` / default; map padding to `--spacing-md` / `--spacing-lg`, not raw values |
|
|
151
|
+
| `plain` / `elevated` | Default shadcn Card uses its `bg-card` token — restyle to `--color-surface` or `--color-elevated-surface` |
|
|
152
|
+
|
|
153
|
+
Ignore shadcn's invitation to hard-code spacing utilities. Card spacing
|
|
154
|
+
consumes `--spacing-md`, `--spacing-lg`, or `--spacing-xl` only.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Checkbox
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Checkbox represents an independent boolean choice or membership in a list of
|
|
6
|
+
multiple choices. More than one checkbox in a group may be selected.
|
|
7
|
+
|
|
8
|
+
## Anatomy
|
|
9
|
+
|
|
10
|
+
1. **Root** — focusable checkbox control and checked-state owner.
|
|
11
|
+
2. **Indicator** — check mark or indeterminate mark.
|
|
12
|
+
3. **Label** — names the choice and enlarges the activation target.
|
|
13
|
+
4. **Description (optional)** — HelperText for consequences or context.
|
|
14
|
+
|
|
15
|
+
## Variants
|
|
16
|
+
|
|
17
|
+
- **Unchecked / checked** — independent false/true choice.
|
|
18
|
+
- **Indeterminate** — summarizes mixed child selections; it is a visual and
|
|
19
|
+
programmatic third presentation, not a submitted business value by itself.
|
|
20
|
+
- **Checkbox group** — multiple related values within `fieldset` and `legend`.
|
|
21
|
+
- **Required acknowledgment** — use sparingly for a genuinely required consent;
|
|
22
|
+
validation must explain what is needed.
|
|
23
|
+
|
|
24
|
+
Checkbox is for independent or multiple selections. Switch is for one setting
|
|
25
|
+
that takes effect as on/off; Select is for exactly one value from many.
|
|
26
|
+
|
|
27
|
+
## Sizes
|
|
28
|
+
|
|
29
|
+
- **Small** — dense data and compact lists while retaining an adequate combined
|
|
30
|
+
Label activation target.
|
|
31
|
+
- **Medium** — default.
|
|
32
|
+
|
|
33
|
+
Indicator follows `--type-role-label-font-size`; its label gap is
|
|
34
|
+
`--spacing-sm`. Avoid a
|
|
35
|
+
large decorative variant; hierarchy belongs in the text and layout.
|
|
36
|
+
|
|
37
|
+
## States
|
|
38
|
+
|
|
39
|
+
| State | Behavior |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| Default | Unchecked outline uses `--color-border`; checked state uses the semantic primary treatment. |
|
|
42
|
+
| Hover | Root/label pair shows subtle interactive emphasis. |
|
|
43
|
+
| Focus | Visible `--color-focus` ring on the root. |
|
|
44
|
+
| Active | Pressed feedback is brief and does not obscure the checked value. |
|
|
45
|
+
| Disabled | Cannot toggle, uses `--color-disabled`, and the Label reflects disabled state. |
|
|
46
|
+
| Loading | Rare; keep the current value visible and announce pending persistence instead of replacing the indicator. |
|
|
47
|
+
| Error | Group or control is invalid, uses `--color-danger`, and references ValidationMessage. |
|
|
48
|
+
|
|
49
|
+
Loading does not mean unchecked or disabled. For optimistic updates, retain the
|
|
50
|
+
new checked value and expose pending status; on failure, restore or explain the
|
|
51
|
+
actual value with a recovery action.
|
|
52
|
+
|
|
53
|
+
## Accessibility
|
|
54
|
+
|
|
55
|
+
- Radix supplies `role="checkbox"`, checked/indeterminate state, and hidden
|
|
56
|
+
native form participation. Preserve those semantics.
|
|
57
|
+
- Associate Label with the root ID. A group uses `fieldset`/`legend` or an
|
|
58
|
+
equivalent named group.
|
|
59
|
+
- Use `aria-checked="mixed"` for indeterminate state where not supplied by the
|
|
60
|
+
primitive. Expose required, invalid, disabled, and busy states.
|
|
61
|
+
- Link HelperText and ValidationMessage through `aria-describedby`.
|
|
62
|
+
- Keyboard: `Tab` focuses each enabled checkbox; `Space` toggles it. Do not add
|
|
63
|
+
arrow-key exclusivity—that belongs to radio-group behavior.
|
|
64
|
+
|
|
65
|
+
## When to use
|
|
66
|
+
|
|
67
|
+
- For independent opt-in/opt-out choices submitted with a form.
|
|
68
|
+
- For selecting zero, one, or many items from a visible list.
|
|
69
|
+
- For a parent “select all” control with a mixed state.
|
|
70
|
+
|
|
71
|
+
## When NOT to use
|
|
72
|
+
|
|
73
|
+
- Do not use for an immediate single on/off setting; use Switch.
|
|
74
|
+
- Do not use for exactly one mutually exclusive choice from many; use Select
|
|
75
|
+
(or a future RadioGroup).
|
|
76
|
+
- Do not make the check mark the only indication of a consequential choice;
|
|
77
|
+
provide a clear Label and context.
|
|
78
|
+
|
|
79
|
+
## Tokens
|
|
80
|
+
|
|
81
|
+
Use `--color-border`, `--color-surface`, `--color-foreground`,
|
|
82
|
+
`--color-primary`, `--color-focus`, `--color-disabled`, and `--color-danger`,
|
|
83
|
+
plus `--spacing-sm`, `--radius-sm`, the five property-qualified label
|
|
84
|
+
typography tokens, `--motion-duration-fast`, and `--motion-easing-standard`.
|
|
85
|
+
|
|
86
|
+
## Radix/shadcn mapping
|
|
87
|
+
|
|
88
|
+
Maps to [Radix Checkbox](https://www.radix-ui.com/primitives/docs/components/checkbox)
|
|
89
|
+
and [shadcn/ui Checkbox](https://ui.shadcn.com/docs/components/checkbox).
|
|
90
|
+
Preserve Radix's controlled/uncontrolled and indeterminate behavior, keyboard
|
|
91
|
+
contract, and form participation.
|