@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,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.