@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,155 @@
|
|
|
1
|
+
# Keyboard shortcuts
|
|
2
|
+
|
|
3
|
+
Discoverable keyboard shortcuts for frequent actions and navigation. This
|
|
4
|
+
pattern governs how shortcuts are defined, invoked, and — critically —
|
|
5
|
+
discovered, so that keyboard efficiency does not become hidden knowledge.
|
|
6
|
+
|
|
7
|
+
User story #24.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Keyboard shortcuts let a person who prefers the keyboard move faster: jump to
|
|
12
|
+
search, open the [command palette](command-palette.md), create a new record,
|
|
13
|
+
refresh, navigate rows. They are acceleration on top of visible controls, never
|
|
14
|
+
the only path to an action.
|
|
15
|
+
|
|
16
|
+
The central problem is **discoverability**. A shortcut that no one knows exists
|
|
17
|
+
does not exist. This pattern mandates a discoverability mechanism so shortcuts
|
|
18
|
+
are findable without reading documentation.
|
|
19
|
+
|
|
20
|
+
## Component composition
|
|
21
|
+
|
|
22
|
+
| Region | Compose with | Role |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| Shortcut hint | inline text or [Tooltip](../components/tooltip.md) near the control | Shows the binding next to the action it triggers |
|
|
25
|
+
| Shortcut legend | [Modal / Dialog](../components/modal-dialog.md) or [Popover](../components/popover.md) opened by `?` | Lists all shortcuts in one place |
|
|
26
|
+
| Command palette | [CommandPalette](../components/command-palette.md) items with shortcut hints | Shortcuts visible where commands live |
|
|
27
|
+
| Footer hints | palette / dialog footer | Reminds `Enter`, `↑↓`, `Esc` |
|
|
28
|
+
|
|
29
|
+
## Flow
|
|
30
|
+
|
|
31
|
+
1. Person works in the product with the keyboard.
|
|
32
|
+
2. Person presses `?` (or `Shift+/`) anywhere a shortcut legend is available.
|
|
33
|
+
3. A [Modal / Dialog](../components/modal-dialog.md) or
|
|
34
|
+
[Popover](../components/popover.md) opens listing shortcuts, grouped by
|
|
35
|
+
category (Navigation, Actions, Tables).
|
|
36
|
+
4. Person closes the legend (`Escape` or click) and uses a shortcut.
|
|
37
|
+
5. Shortcuts also appear as hints next to their controls (in
|
|
38
|
+
[DropdownMenu](../components/dropdown-menu.md) items, next to
|
|
39
|
+
[Button](../components/button.md)s, in the [command palette](command-palette.md)).
|
|
40
|
+
|
|
41
|
+
## States
|
|
42
|
+
|
|
43
|
+
| State | Behavior |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| idle | Shortcuts active but not shown. Person can invoke any binding. |
|
|
46
|
+
| legend open | Shortcut legend visible; focus trapped (if dialog) or moved to the legend. `Escape` closes. |
|
|
47
|
+
| conflict | Two actions claim the same binding. The product must resolve this — the legend shows the winner; the loser gets a different binding or no binding. |
|
|
48
|
+
|
|
49
|
+
## Layout sketch
|
|
50
|
+
|
|
51
|
+
### Shortcut legend (`?`)
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
┌──────────────────────────────────────────────┐
|
|
55
|
+
│ Keyboard shortcuts │
|
|
56
|
+
├──────────────────────────────────────────────┤
|
|
57
|
+
│ Navigation │
|
|
58
|
+
│ ⌘K Open command palette │
|
|
59
|
+
│ ⌘/ Focus search │
|
|
60
|
+
│ g r Go to Replicas │
|
|
61
|
+
│ g q Go to Queries │
|
|
62
|
+
│ g s Go to Settings │
|
|
63
|
+
│ │
|
|
64
|
+
│ Actions │
|
|
65
|
+
│ c Create new (context-aware) │
|
|
66
|
+
│ r Refresh current view │
|
|
67
|
+
│ ⌘S Save (in an editor) │
|
|
68
|
+
│ │
|
|
69
|
+
│ Tables │
|
|
70
|
+
│ ↑ ↓ Move between rows │
|
|
71
|
+
│ j k Move between rows (vim) │
|
|
72
|
+
│ x Select row │
|
|
73
|
+
│ ? Show this legend │
|
|
74
|
+
│ │
|
|
75
|
+
│ [Close] [Esc] │
|
|
76
|
+
└──────────────────────────────────────────────┘
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Inline hints
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
[DropdownMenu]
|
|
83
|
+
▸ New query ⌘N
|
|
84
|
+
▸ Duplicate ⌘D
|
|
85
|
+
▸ Delete ⌫
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Hints appear right-aligned in menu items, in `--color-muted-foreground`. They
|
|
89
|
+
are decorative; the accessible name of the item does not depend on them.
|
|
90
|
+
|
|
91
|
+
## Rules
|
|
92
|
+
|
|
93
|
+
### Discoverability (mandatory)
|
|
94
|
+
|
|
95
|
+
- **Provide a shortcut legend**, opened by `?` (or `Shift+/`). This is the
|
|
96
|
+
primary discoverability mechanism. Without it, shortcuts are hidden knowledge.
|
|
97
|
+
- **Show hints next to controls** where space allows: in
|
|
98
|
+
[DropdownMenu](../components/dropdown-menu.md) items, next to
|
|
99
|
+
[Button](../components/button.md)s in toolbars, and in
|
|
100
|
+
[command palette](command-palette.md) items.
|
|
101
|
+
- **Mention the legend in onboarding** or first-run help so a new person learns
|
|
102
|
+
that `?` exists.
|
|
103
|
+
- Do not rely on [Tooltip](../components/tooltip.md) as the only discoverability
|
|
104
|
+
path — Tooltip is not available on touch and is progressive enhancement.
|
|
105
|
+
|
|
106
|
+
### Defining shortcuts
|
|
107
|
+
|
|
108
|
+
- Use platform conventions: `⌘` on macOS, `Ctrl` on Windows/Linux. Single-key
|
|
109
|
+
shortcuts (no modifier) are allowed for context-specific actions (table row
|
|
110
|
+
navigation with `j`/`k`) but must not conflict with text entry — only active
|
|
111
|
+
when the focus is not in a text field.
|
|
112
|
+
- Reserve `⌘K` / `Ctrl+K` for the [command palette](command-palette.md). Do
|
|
113
|
+
not bind it to list [Search](search.md).
|
|
114
|
+
- Reserve `?` for the shortcut legend. Do not bind it to an action.
|
|
115
|
+
- Do not override browser or OS shortcuts (`⌘W`, `⌘R`, `⌘T`, etc.) unless the
|
|
116
|
+
product explicitly opts into a contained context (e.g. a code editor) and
|
|
117
|
+
documents the override.
|
|
118
|
+
- Two-key sequences (like `g` then `r`) are allowed for navigation but must
|
|
119
|
+
show a brief "waiting for second key" state and time out cleanly.
|
|
120
|
+
|
|
121
|
+
### Scope
|
|
122
|
+
|
|
123
|
+
- Global shortcuts (navigation, command palette, legend) work everywhere.
|
|
124
|
+
- Context shortcuts (table row navigation, editor commands) are active only in
|
|
125
|
+
their context. When the person leaves the context, the binding is released.
|
|
126
|
+
- A shortcut that is context-only should not appear in the global legend as if
|
|
127
|
+
it were global; group it under its context ("Tables", "Editor").
|
|
128
|
+
|
|
129
|
+
### Conflicts
|
|
130
|
+
|
|
131
|
+
- No two actions may share the same binding in the same scope. The product
|
|
132
|
+
resolves conflicts; the legend shows the winner.
|
|
133
|
+
- If a user-customizable shortcut system exists (future), the legend reflects
|
|
134
|
+
the current bindings, not the defaults.
|
|
135
|
+
|
|
136
|
+
## Accessibility
|
|
137
|
+
|
|
138
|
+
- Shortcuts are keyboard input; they are inherently accessible to keyboard
|
|
139
|
+
users. Ensure they do not trap focus or override assistive technology
|
|
140
|
+
behavior.
|
|
141
|
+
- The legend is a real dialog or popover with focus management: focus moves in
|
|
142
|
+
on open, `Escape` closes, focus returns to the trigger.
|
|
143
|
+
- Shortcut hints in menu items are decorative (`aria-hidden` on the hint text)
|
|
144
|
+
— the item's accessible name is the action label, not the key combination.
|
|
145
|
+
- Single-key shortcuts must be inert when focus is in a text field, so they do
|
|
146
|
+
not intercept typing. The exception is `Escape` (which may blur the field or
|
|
147
|
+
close an overlay).
|
|
148
|
+
- Do not make a shortcut the only way to perform an action. Every shortcut-
|
|
149
|
+
accessible action has a visible control (button, menu item, link) as well.
|
|
150
|
+
|
|
151
|
+
## Related patterns
|
|
152
|
+
|
|
153
|
+
- [Command palette](command-palette.md) — `⌘K` / `Ctrl+K` is the flagship
|
|
154
|
+
shortcut; the palette lists commands with their hints.
|
|
155
|
+
- [Search](search.md) — a shortcut (`⌘/` or `/`) may focus the Search field.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Large data tables
|
|
2
|
+
|
|
3
|
+
Tables with many rows — virtualization, sticky headers, column resize, and
|
|
4
|
+
responsive collapse. This pattern composes [Table / DataTable](../components/table.md)
|
|
5
|
+
for datasets that exceed a comfortable page or viewport, and references
|
|
6
|
+
[data-interfaces.md](../data-interfaces.md) for the data-rendering rules
|
|
7
|
+
(alignment, null/unknown, truncation, dangerous values) that every cell still
|
|
8
|
+
follows.
|
|
9
|
+
|
|
10
|
+
User story #3.
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
When a table holds hundreds or thousands of rows — replicas, query history,
|
|
15
|
+
metrics series, log lines — the interaction model shifts. The person scrolls
|
|
16
|
+
through a large loaded set, compares columns across a wide schema, and relies
|
|
17
|
+
on [Search](search.md) + [filtering](filtering.md) to narrow it. This pattern
|
|
18
|
+
governs the table behaviors that make that volume usable: virtualization,
|
|
19
|
+
sticky headers, column resize, and responsive column collapse.
|
|
20
|
+
|
|
21
|
+
It does **not** redefine how cells render. Numeric alignment, null ≠ 0 ≠
|
|
22
|
+
unknown, truncation with full-value access, and dangerous-value marking are
|
|
23
|
+
defined in [data-interfaces.md](../data-interfaces.md) and apply unchanged
|
|
24
|
+
here. This pattern composes those rules; it does not redefine or override them.
|
|
25
|
+
|
|
26
|
+
## Component composition
|
|
27
|
+
|
|
28
|
+
| Concern | Compose with | Role |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| Grid | [Table / DataTable](../components/table.md) | Structural table with sort, selection, toolbar |
|
|
31
|
+
| Volume | virtualized body (guidance, not a separate component) | Only visible rows mount; header, selection, keyboard stay correct |
|
|
32
|
+
| Sticky header | DataTable `sticky` header behavior | Header stays visible while the body scrolls |
|
|
33
|
+
| Column width | DataTable column resize handle | Person drags to resize; width persisted in product state |
|
|
34
|
+
| Narrowing | [Search](search.md) + [filtering](filtering.md) | Reduce the set the person scrolls through |
|
|
35
|
+
| Paging | [Pagination](pagination.md) or virtualization | Pick one model per surface (see Rules) |
|
|
36
|
+
| Cell rendering | [data-interfaces.md](../data-interfaces.md) rules | Alignment, null/unknown, truncation, dangerous values |
|
|
37
|
+
| Row actions | [DropdownMenu](../components/dropdown-menu.md) | Per-row actions; does not break virtualization |
|
|
38
|
+
| Empty / error | [EmptyState](../components/empty-state.md) / [Alert](../components/alert.md) | Standard states, not special large-table variants |
|
|
39
|
+
|
|
40
|
+
## Flow
|
|
41
|
+
|
|
42
|
+
1. Person opens a large table (e.g. 4,000 replicas). The first viewport of rows
|
|
43
|
+
loads and renders; the rest are virtualized.
|
|
44
|
+
2. The header is sticky: as the person scrolls, column titles remain visible.
|
|
45
|
+
3. The person uses [Search](search.md) and [filtering](filtering.md) to narrow
|
|
46
|
+
the set. The virtualized body re-renders only visible rows of the filtered
|
|
47
|
+
set.
|
|
48
|
+
4. The person sorts a column ([sorting](sorting.md)); the virtualized body
|
|
49
|
+
reorders.
|
|
50
|
+
5. For wide schemas, the person resizes columns or the table collapses
|
|
51
|
+
secondary columns responsively (see below).
|
|
52
|
+
6. Row actions, selection, and keyboard navigation remain correct throughout
|
|
53
|
+
scroll, sort, and filter changes.
|
|
54
|
+
|
|
55
|
+
## States
|
|
56
|
+
|
|
57
|
+
| State | Behavior |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| loading | [Skeleton](../components/skeleton.md) rows matching column count and approximate viewport size. `aria-busy` on the region. Keep header and toolbar chrome. |
|
|
60
|
+
| populated | Virtualized rows render; only visible rows (plus a small overscan buffer) are mounted. |
|
|
61
|
+
| empty | [EmptyState](../components/empty-state.md) `no-results` or `first-run` in the body. Keep headers. |
|
|
62
|
+
| error | [Alert](../components/alert.md) with retry; remove Skeletons. |
|
|
63
|
+
| scrolling | Sticky header stays aligned with the body. Roving tabindex / `aria-activedescendant` keeps one focused row as the person scrolls. |
|
|
64
|
+
| resizing | Column resize handle drags; minimum width keeps the header label readable. Other columns adjust or scroll. |
|
|
65
|
+
|
|
66
|
+
## Layout sketch
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
70
|
+
│ Toolbar │
|
|
71
|
+
│ [🔍 Search 4,000 replicas...] [Status▾] [Region▾] [Lag range▾] │
|
|
72
|
+
│ 247 replicas match · sorted by Lag ▼ │
|
|
73
|
+
├──────────────────────────────────────────────────────────────────────┤
|
|
74
|
+
│ ↓ sticky header │
|
|
75
|
+
│ ┌────────────────────────────────────────────────────────────────┐ │
|
|
76
|
+
│ │ Name Host Status Lag ▼ Conn Region Ver │ │
|
|
77
|
+
│ │ replica-1 db.eu.example ok 12 ms 42 eu 16 │ │
|
|
78
|
+
│ │ replica-2 db.eu.backup degraded 820 ms 18 eu 16 │ │
|
|
79
|
+
│ │ replica-3 db.eu.dr ok — 9 eu 16 │ │
|
|
80
|
+
│ │ replica-4 db.ap.example ok 4 ms 31 ap 15 │ │
|
|
81
|
+
│ │ ...virtualized... │ │
|
|
82
|
+
│ │ replica-N db.us.example warn 2.1 s 7 us 14 │ │
|
|
83
|
+
│ └────────────────────────────────────────────────────────────────┘ │
|
|
84
|
+
│ ↑ body scrolls independently; header stays │
|
|
85
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Responsive collapse
|
|
89
|
+
|
|
90
|
+
On narrow viewports, collapse columns in a documented priority order — do not
|
|
91
|
+
turn rows into cards. This follows the
|
|
92
|
+
[responsive tables](../data-interfaces.md) rules in data-interfaces.md:
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
Wide: Name | Host | Status | Lag | Conn | Region | Ver
|
|
96
|
+
Narrow: Name | Status | Lag | [Show details ▾]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`Name` (key identifier), `Status` (includes danger markers), `Lag` (comparison),
|
|
100
|
+
and the primary action stay visible. `Host`, `Conn`, `Region`, and `Ver` move
|
|
101
|
+
into row detail under "Show details for {replica}". A danger or warning marker
|
|
102
|
+
**never** moves out of the summary row.
|
|
103
|
+
|
|
104
|
+
## Rules
|
|
105
|
+
|
|
106
|
+
### Virtualization vs pagination
|
|
107
|
+
|
|
108
|
+
- **Virtualize** when the person scrolls one large loaded set (thousands of
|
|
109
|
+
client-side rows, or a server cursor that fetches as the person scrolls).
|
|
110
|
+
Keep header, selection model, and keyboard navigation correct.
|
|
111
|
+
- **Paginate** ([pagination](pagination.md)) when the dataset is known and
|
|
112
|
+
page-shaped and the person benefits from "page 7 of 40" position.
|
|
113
|
+
- Do **not** combine Pagination and infinite scroll / virtualized scroll on the
|
|
114
|
+
same table. Pick one model per surface and document it.
|
|
115
|
+
|
|
116
|
+
### Sticky header
|
|
117
|
+
|
|
118
|
+
- Use a sticky header when the table is taller than the viewport. The header
|
|
119
|
+
uses the same `--color-surface` as the header so rows do not show through.
|
|
120
|
+
- Ensure focus order still follows visual order; do not trap focus under the
|
|
121
|
+
sticky layer.
|
|
122
|
+
|
|
123
|
+
### Column resize
|
|
124
|
+
|
|
125
|
+
- Optional. Drag handle on the header edge. Persist width in product state
|
|
126
|
+
when useful.
|
|
127
|
+
- Minimum width must keep the header label readable. Use `ch` / type-role and
|
|
128
|
+
`--spacing-*`, not raw pixels.
|
|
129
|
+
- Resizing must not break virtualization, selection, or keyboard order.
|
|
130
|
+
|
|
131
|
+
### Cell rendering (references data-interfaces.md)
|
|
132
|
+
|
|
133
|
+
- Numeric columns are right-aligned with `--type-role-numeric` and
|
|
134
|
+
`--font-variant-numeric`; headers align to the same edge. See
|
|
135
|
+
[data-interfaces.md](../data-interfaces.md) → Numeric values.
|
|
136
|
+
- `NULL`, `0`, and unknown `—` are three distinct states. See
|
|
137
|
+
[data-interfaces.md](../data-interfaces.md) → Missing and indeterminate
|
|
138
|
+
values.
|
|
139
|
+
- Truncate only when a known width is necessary; keep the full value in the DOM
|
|
140
|
+
for copy, search, and accessibility. A truncated value needs visible ellipsis,
|
|
141
|
+
full value in [Tooltip](../components/tooltip.md), and a touch-safe full-value
|
|
142
|
+
path. See [data-interfaces.md](../data-interfaces.md) → Truncation.
|
|
143
|
+
- Dangerous values keep the raw value visible with a `Danger` marker; never
|
|
144
|
+
replace `fsync = off` with only "Dangerous". See
|
|
145
|
+
[data-interfaces.md](../data-interfaces.md) → Warnings and dangerous values.
|
|
146
|
+
|
|
147
|
+
### Selection and keyboard
|
|
148
|
+
|
|
149
|
+
- Multi-select via [Checkbox](../components/checkbox.md) in the leading column.
|
|
150
|
+
Header Checkbox toggles all rows **on the current page** (paged) or **all
|
|
151
|
+
loaded rows** (virtualized) unless the product defines "select all matching
|
|
152
|
+
query" with explicit copy and confirmation.
|
|
153
|
+
- Keyboard: `Tab` reaches interactive controls (toolbar, sort headers,
|
|
154
|
+
checkboxes, row actions). Optional grid navigation inside the body uses
|
|
155
|
+
`aria-activedescendant` or roving tabindex with one tab stop into the grid —
|
|
156
|
+
document it on the screen.
|
|
157
|
+
- Do not break keyboard order when virtualizing: the focused row must remain
|
|
158
|
+
in view, and scrolling must not strand focus on a row that unmounts.
|
|
159
|
+
|
|
160
|
+
## Accessibility
|
|
161
|
+
|
|
162
|
+
- Use a real `<table>` with `<thead>`, `<tbody>`, `<th scope="col">`.
|
|
163
|
+
Virtualization must not replace the table with non-semantic divs for
|
|
164
|
+
tabular data.
|
|
165
|
+
- Accessible name via `<caption>` or `aria-labelledby`.
|
|
166
|
+
- `aria-busy` on the region during load; Skeletons `aria-hidden`.
|
|
167
|
+
- Sticky header: focus order follows visual order; no focus trap under the
|
|
168
|
+
sticky layer.
|
|
169
|
+
- Responsive collapse: hidden fields are reachable through row expansion /
|
|
170
|
+
detail with a named control ("Show details for replica-01"). Tooltip is
|
|
171
|
+
never the only path to a hidden value.
|
|
172
|
+
|
|
173
|
+
## Related patterns
|
|
174
|
+
|
|
175
|
+
- [Search](search.md) — narrow the large set by query.
|
|
176
|
+
- [Filtering](filtering.md) — narrow the large set by facet.
|
|
177
|
+
- [Sorting](sorting.md) — order the large set.
|
|
178
|
+
- [Pagination](pagination.md) — the alternative model for known, page-shaped
|
|
179
|
+
sets.
|
|
180
|
+
- [data-interfaces.md](../data-interfaces.md) — prescriptive cell-rendering
|
|
181
|
+
rules (alignment, null/unknown, truncation, dangerous values) that this
|
|
182
|
+
pattern composes.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# List-detail
|
|
2
|
+
|
|
3
|
+
Master list plus a detail pane for one selected record. Navigation and context
|
|
4
|
+
stay consistent: the list remains visible (or recoverable), and the detail
|
|
5
|
+
shows the same entity the person selected.
|
|
6
|
+
|
|
7
|
+
User story #5.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Browse many similar entities, select one, and inspect or act on it without
|
|
12
|
+
losing list context. Typical Momoi uses: connections, instances, queries,
|
|
13
|
+
parameters.
|
|
14
|
+
|
|
15
|
+
**Canonical rule:** A list screen must not reinvent search, filters,
|
|
16
|
+
pagination, and empty state. Compose [Search](../components/search.md),
|
|
17
|
+
filtering controls, [Pagination](../components/pagination.md), and
|
|
18
|
+
[EmptyState](../components/empty-state.md) through
|
|
19
|
+
[Table / DataTable](../components/table.md) (and related components) — do not
|
|
20
|
+
invent a parallel list kit.
|
|
21
|
+
|
|
22
|
+
How Search, filters, sorting, and Pagination behave is specified elsewhere;
|
|
23
|
+
this layout pattern only places those controls consistently.
|
|
24
|
+
|
|
25
|
+
## Component composition
|
|
26
|
+
|
|
27
|
+
| Region | Compose with | Role |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| Page chrome | [PageHeader](../components/page-header.md) | Page title, subtitle, primary create/import [Button](../components/button.md) |
|
|
30
|
+
| List toolbar | [Search](../components/search.md); optional filters via [Select](../components/select.md), [DropdownMenu](../components/dropdown-menu.md), and/or [Popover](../components/popover.md); optional bulk [Button](../components/button.md)s | Narrows the collection; owned by the list, not reinvented per product |
|
|
31
|
+
| List body | [Table / DataTable](../components/table.md) or a selectable list of rows | Master collection; row selection drives the detail |
|
|
32
|
+
| List paging | [Pagination](../components/pagination.md) | Below the table when the set is paged |
|
|
33
|
+
| Detail pane | content region, often a [Card](../components/card.md) or definition stack | Selected entity; may include [Tabs](../components/tabs.md), [Badge](../components/badge.md), [DropdownMenu](../components/dropdown-menu.md) for entity actions |
|
|
34
|
+
| Location | optional [Breadcrumb](../components/breadcrumb.md) | When the entity sits in a hierarchy deeper than Sidebar alone |
|
|
35
|
+
| Shell | [Application shell](application-shell.md) | Header + Sidebar + main around this page |
|
|
36
|
+
|
|
37
|
+
Tokens: list and detail panels use `--color-surface` on `--color-background`,
|
|
38
|
+
dividers `--color-border`, primary text `--color-foreground`, secondary
|
|
39
|
+
`--color-muted-foreground`, selection/current `--color-primary`, focus
|
|
40
|
+
`--color-focus`.
|
|
41
|
+
|
|
42
|
+
## Flow
|
|
43
|
+
|
|
44
|
+
1. Person opens the list route inside the application shell.
|
|
45
|
+
2. List loads; Search / filters / Pagination appear in their standard places
|
|
46
|
+
when the collection supports them.
|
|
47
|
+
3. Selecting a row (or opening its Link) loads that entity in the detail pane
|
|
48
|
+
or detail route while preserving list context.
|
|
49
|
+
4. Detail actions (edit, delete, connect) follow [CRUD](crud.md) and action
|
|
50
|
+
patterns; they do not replace the list chrome.
|
|
51
|
+
5. Clearing selection returns focus to the list; changing Search/filters
|
|
52
|
+
updates the list and clears or reconciles an obsolete selection.
|
|
53
|
+
|
|
54
|
+
Split view (list | detail) is preferred on wide viewports. On narrow
|
|
55
|
+
viewports, push detail as a full main view with an explicit back control
|
|
56
|
+
(Link or Button) that restores the list — same pattern, stacked presentation.
|
|
57
|
+
|
|
58
|
+
## States
|
|
59
|
+
|
|
60
|
+
| State | Behavior |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| loading (list) | Keep PageHeader and toolbar chrome; show Skeleton rows inside the table body — not a lone Spinner replacing the list. |
|
|
63
|
+
| loading (detail) | Keep the selected row highlighted; detail pane shows Skeleton for known structure. |
|
|
64
|
+
| empty (no items) | EmptyState in the list body with optional create action; detail pane hidden or shows a neutral prompt to select an item once items exist. |
|
|
65
|
+
| empty (no matches) | EmptyState explaining no matches; offer clear-filters action. Do not pretend the collection was never populated. |
|
|
66
|
+
| error (list) | Alert above or in place of the list body (what / why / now); retry Button; shell navigation remains. |
|
|
67
|
+
| error (detail) | Alert inside the detail pane; list stays interactive so the person can pick another row. |
|
|
68
|
+
| no selection | List visible; detail shows a short prompt ("Select a connection") — not an error, not EmptyState for the whole page. |
|
|
69
|
+
|
|
70
|
+
## Layout sketch
|
|
71
|
+
|
|
72
|
+
Wide (split):
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
76
|
+
│ PageHeader: Connections [Create connection]│
|
|
77
|
+
├──────────────────────────────────┬──────────────────────────────────────┤
|
|
78
|
+
│ List │ Detail │
|
|
79
|
+
│ [Search..............] [Filter▾] │ Connection · prod-eu │
|
|
80
|
+
│ │ [Badge: healthy] [Actions ▾] │
|
|
81
|
+
│ ┌──────────────────────────────┐ │ │
|
|
82
|
+
│ │ Name Host Status│ │ Host db.example.com:5432 │
|
|
83
|
+
│ │ prod-eu ● db.eu… ok │ │ User app_readonly │
|
|
84
|
+
│ │ staging db.st… warn │ │ SSL required │
|
|
85
|
+
│ │ analytics db.an… ok │ │ │
|
|
86
|
+
│ └──────────────────────────────┘ │ [Edit] [Test connection] │
|
|
87
|
+
│ ← Pagination → │ │
|
|
88
|
+
└──────────────────────────────────┴──────────────────────────────────────┘
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Narrow (stacked detail):
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
┌──────────────────────────────────────┐
|
|
95
|
+
│ ← Connections │
|
|
96
|
+
│ PageHeader: prod-eu [Actions ▾] │
|
|
97
|
+
│ │
|
|
98
|
+
│ Host db.example.com:5432 │
|
|
99
|
+
│ User app_readonly │
|
|
100
|
+
│ ... │
|
|
101
|
+
└──────────────────────────────────────┘
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## When to use
|
|
105
|
+
|
|
106
|
+
- Collections where inspecting one item while keeping list context matters.
|
|
107
|
+
- Entities that share the same columns and detail shape.
|
|
108
|
+
|
|
109
|
+
## When NOT to use
|
|
110
|
+
|
|
111
|
+
- Single-record settings pages — use [Settings](settings.md).
|
|
112
|
+
- Dashboards of unrelated widgets — use [Dashboard](dashboard.md).
|
|
113
|
+
- Create/edit full-page forms with no master list — use [CRUD](crud.md).
|
|
114
|
+
|
|
115
|
+
## Related patterns
|
|
116
|
+
|
|
117
|
+
- [Application shell](application-shell.md) — outer frame.
|
|
118
|
+
- [CRUD](crud.md) — create/edit/delete of the selected entity.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Loading
|
|
2
|
+
|
|
3
|
+
Loading tells the person that requested work is in progress while preserving
|
|
4
|
+
context. Match the affordance to what is known: Skeleton for known structure,
|
|
5
|
+
Spinner only for indeterminate work whose result has no honest layout yet.
|
|
6
|
+
|
|
7
|
+
## Component composition
|
|
8
|
+
|
|
9
|
+
- [Skeleton](../components/skeleton.md) preserves known content geometry.
|
|
10
|
+
- [Table / DataTable](../components/table.md) composes Skeleton cells into
|
|
11
|
+
rows. **Lists and tables use Skeleton rows, never a centered Spinner.**
|
|
12
|
+
- [Card](../components/card.md) keeps its frame and replaces known content with
|
|
13
|
+
shaped Skeletons.
|
|
14
|
+
- [Spinner](../components/spinner.md) belongs in an indeterminate region or in
|
|
15
|
+
a loading [Button](../components/button.md), not over a list.
|
|
16
|
+
- Keep [Search](../components/search.md) and
|
|
17
|
+
[Pagination](../components/pagination.md) stable during a refetch when their
|
|
18
|
+
current values are still meaningful.
|
|
19
|
+
|
|
20
|
+
Loading surfaces use `--color-background` or `--color-surface`; Skeleton uses
|
|
21
|
+
`--color-border`, while Spinner uses `--color-primary` and `--color-border`.
|
|
22
|
+
Motion consumes `--motion-duration-normal` and
|
|
23
|
+
`--motion-easing-standard`. Never invent raw placeholder dimensions; match
|
|
24
|
+
semantic type and spacing tokens.
|
|
25
|
+
|
|
26
|
+
## Flow
|
|
27
|
+
|
|
28
|
+
1. Start the request and set `aria-busy="true"` on the affected region.
|
|
29
|
+
2. Preserve stable chrome, headings, controls, and known dimensions.
|
|
30
|
+
3. Render Skeletons matching the content that will arrive. For a list, repeat
|
|
31
|
+
a representative row rather than drawing one large block.
|
|
32
|
+
4. Announce one concise status such as “Loading queries…”, not one per row.
|
|
33
|
+
5. Swap placeholders for populated, empty, error, or permission-denied content
|
|
34
|
+
in one update and clear the busy state.
|
|
35
|
+
|
|
36
|
+
For a pagination or filter refetch, keep the person's query and page context.
|
|
37
|
+
Prevent duplicate requests without presenting loading as disabled. If existing
|
|
38
|
+
rows remain safe to read, they may stay visible with the region marked busy;
|
|
39
|
+
otherwise replace only the rows with Skeleton rows.
|
|
40
|
+
|
|
41
|
+
## States
|
|
42
|
+
|
|
43
|
+
| State | Treatment |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| Initial loading | Known layout uses Skeletons; unknown layout may use a labeled Spinner. |
|
|
46
|
+
| Refetching | Keep controls and current context; replace or mark only the results region busy. |
|
|
47
|
+
| Empty | Remove Skeletons and show EmptyState. Never let placeholders linger as an empty result. |
|
|
48
|
+
| Error | Remove Skeletons and show the errors pattern. Retry returns to loading. |
|
|
49
|
+
| Permission denied | Stop loading and use the permission-denied pattern; do not retry indefinitely. |
|
|
50
|
+
| Loaded | Replace the loading presentation with real content in the same geometry. |
|
|
51
|
+
|
|
52
|
+
## Layout sketch
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
PageHeader: Queries [Create query]
|
|
56
|
+
[Search queries________________] [Status v] 1–25 of 86
|
|
57
|
+
┌─────────────────────────────────────────────────────────┐
|
|
58
|
+
│ Name Owner Updated │
|
|
59
|
+
├─────────────────────────────────────────────────────────┤
|
|
60
|
+
│ ███████████████ ███████ ██████████ │
|
|
61
|
+
│ ██████████ ██████████ ███████ │
|
|
62
|
+
│ █████████████ ██████ █████████ │
|
|
63
|
+
│ █████████ ████████ ██████ │
|
|
64
|
+
└─────────────────────────────────────────────────────────┘
|
|
65
|
+
Status: Loading queries… [Previous] [Next]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The blocks are decorative Skeleton cells aligned to final columns. Do not
|
|
69
|
+
replace this table body with a centered Spinner or erase its headers.
|
|
70
|
+
|
|
71
|
+
## Accessibility and copy
|
|
72
|
+
|
|
73
|
+
- Skeleton graphics are `aria-hidden="true"`; the containing region carries
|
|
74
|
+
`aria-busy` and one polite status.
|
|
75
|
+
- Keep focus on the initiating control or stable page heading. Loading content
|
|
76
|
+
does not enter the tab order.
|
|
77
|
+
- Under reduced motion, Skeletons stay static and Spinner uses a static graphic
|
|
78
|
+
plus its label.
|
|
79
|
+
- State what is happening in direct language. Do not use chatty filler or
|
|
80
|
+
promise a duration the system does not know.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Login / authentication
|
|
2
|
+
|
|
3
|
+
Pre-authenticated entry: sign-in, and the minimal adjacent flows (sign-out
|
|
4
|
+
landing, session expired). No product Sidebar; focus on one credential task.
|
|
5
|
+
|
|
6
|
+
User story #29.
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Authenticate the person with a calm, single-purpose layout. Authentication is
|
|
11
|
+
a gate, not a product tour. After success, enter the
|
|
12
|
+
[application shell](application-shell.md).
|
|
13
|
+
|
|
14
|
+
## Component composition
|
|
15
|
+
|
|
16
|
+
| Region | Compose with | Role |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| Page canvas | centered content on `--color-background` | No Header/Sidebar product chrome |
|
|
19
|
+
| Brand | product name / home [Link](../components/link.md) or mark | Identity only; not a marketing hero |
|
|
20
|
+
| Form surface | [Card](../components/card.md) | Contains the auth form |
|
|
21
|
+
| Fields | [FormField](../components/form-field.md) | Email/username [Input](../components/input.md), password Input (`type="password"`), optional OTP Input |
|
|
22
|
+
| Submit | [Button](../components/button.md) | "Sign in" primary; full width of the Card content is acceptable |
|
|
23
|
+
| Errors | [Alert](../components/alert.md) and/or [ValidationMessage](../components/validation-message.md) | Auth failures use Alert (what / why / now); field format errors use ValidationMessage |
|
|
24
|
+
| Secondary nav | [Link](../components/link.md) | Forgot password, SSO, create account — text Links, not a Sidebar |
|
|
25
|
+
| Busy | Button loading Spinner; optional [Spinner](../components/spinner.md) only if no Button loading affordance | Prevent double submit |
|
|
26
|
+
|
|
27
|
+
Tokens: canvas `--color-background`, Card `--color-surface` / `--color-border`,
|
|
28
|
+
text `--color-foreground` / `--color-muted-foreground`, primary action
|
|
29
|
+
`--color-primary`, focus `--color-focus`. Keep flourish out of error copy
|
|
30
|
+
([voice-and-tone](../voice-and-tone.md)).
|
|
31
|
+
|
|
32
|
+
## Flow
|
|
33
|
+
|
|
34
|
+
1. Unauthenticated person hits a protected route or opens the login URL.
|
|
35
|
+
2. Show login Card; focus the first FormField.
|
|
36
|
+
3. Person submits credentials.
|
|
37
|
+
4. On success: establish session and route into the application shell (deep
|
|
38
|
+
link to the originally requested path when safe).
|
|
39
|
+
5. On failure: keep credentials where safe (usually clear password); show Alert
|
|
40
|
+
with recovery (retry, reset password, contact admin) — never a cryptic code
|
|
41
|
+
alone.
|
|
42
|
+
6. Sign-out returns to this pattern (or a signed-out confirmation that Links
|
|
43
|
+
back to Sign in).
|
|
44
|
+
7. Session expired: same layout with an Alert explaining the session ended and
|
|
45
|
+
that signing in continues to the previous destination when possible.
|
|
46
|
+
|
|
47
|
+
SSO: primary Button or Link "Continue with …" above or instead of password
|
|
48
|
+
fields; do not hide password auth without a documented product decision.
|
|
49
|
+
|
|
50
|
+
## States
|
|
51
|
+
|
|
52
|
+
| State | Behavior |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| default | Brand + Card + fields + Sign in. |
|
|
55
|
+
| loading (submit) | Primary Button loading; inputs read-only or inert; no full-page Spinner that hides the form. |
|
|
56
|
+
| invalid fields | ValidationMessage on email/password format; focus first invalid field. |
|
|
57
|
+
| error (auth) | Alert with what / why / now (for example wrong credentials, locked account, IdP failure); form remains. |
|
|
58
|
+
| empty | Not applicable as a collection; do not use EmptyState for "no session". |
|
|
59
|
+
| success | Brief transition into the shell; optional Toast is unnecessary if navigation is immediate. |
|
|
60
|
+
|
|
61
|
+
## Layout sketch
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
65
|
+
│ --color-background │
|
|
66
|
+
│ │
|
|
67
|
+
│ Momoi Product │
|
|
68
|
+
│ ┌────────────────────────┐ │
|
|
69
|
+
│ │ Card: Sign in │ │
|
|
70
|
+
│ │ │ │
|
|
71
|
+
│ │ Alert (auth error) │ │
|
|
72
|
+
│ │ │ │
|
|
73
|
+
│ │ FormField Email │ │
|
|
74
|
+
│ │ FormField Password │ │
|
|
75
|
+
│ │ │ │
|
|
76
|
+
│ │ [ Sign in ] │ │
|
|
77
|
+
│ │ │ │
|
|
78
|
+
│ │ Forgot password? │ │
|
|
79
|
+
│ │ Continue with SSO │ │
|
|
80
|
+
│ └────────────────────────┘ │
|
|
81
|
+
│ │
|
|
82
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## When to use
|
|
86
|
+
|
|
87
|
+
- Sign-in, session-expired re-auth, and post sign-out entry.
|
|
88
|
+
- Minimal invite-accept screens that only establish a session.
|
|
89
|
+
|
|
90
|
+
## When NOT to use
|
|
91
|
+
|
|
92
|
+
- Authenticated account preference editing — [Settings](settings.md).
|
|
93
|
+
- Product navigation or first-run feature tours after sign-in — use the
|
|
94
|
+
[application shell](application-shell.md), not this gate.
|
|
95
|
+
- Permission failures inside an authenticated session — explain the blocked
|
|
96
|
+
action in-product; do not reuse this login layout as a stand-in.
|
|
97
|
+
|
|
98
|
+
## Related patterns
|
|
99
|
+
|
|
100
|
+
- [Application shell](application-shell.md) — post-auth destination.
|
|
101
|
+
- [Settings](settings.md) — profile and security preferences after login.
|