@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,137 @@
1
+ # Destructive actions
2
+
3
+ Require confirmation with clear consequences before an irreversible or
4
+ high-impact action. This pattern composes [Modal / Dialog](../components/modal-dialog.md)
5
+ and the destructive [Button](../components/button.md) variant, and governs when
6
+ confirmation is mandatory, what it must say, and how it behaves.
7
+
8
+ User stories #11, #12.
9
+
10
+ ## Purpose
11
+
12
+ A destructive action cannot be undone, or its undo is expensive, slow, or
13
+ hidden: delete a database, drop a table, disconnect a live connection, purge
14
+ logs, revoke a key. The person must understand the consequence **before** the
15
+ action commits, and must be able to cancel without penalty.
16
+
17
+ This pattern is the gate; [confirmations](confirmations.md) is the broader
18
+ dialog spec (risk explanation, acknowledgment, copy structure). A destructive
19
+ action always uses a confirmation; not every confirmation is destructive.
20
+
21
+ ## Component composition
22
+
23
+ | Region | Compose with | Role |
24
+ | --- | --- | --- |
25
+ | Trigger | [Button](../components/button.md) `destructive` or [IconButton](../components/icon-button.md) `destructive` | Opens the confirmation; does not commit directly |
26
+ | Confirmation dialog | [Modal / Dialog](../components/modal-dialog.md) | Blocks the page; requires explicit confirm or cancel |
27
+ | Confirm action | [Button](../components/button.md) `destructive` inside the dialog | Commits the destructive action; the only destructive control in the dialog |
28
+ | Cancel action | [Button](../components/button.md) `default` or `ghost` inside the dialog | Closes without committing; always available |
29
+ | Progress | [Spinner](../components/spinner.md) inside the confirm Button | While the action is in flight; `aria-busy` |
30
+ | Success / failure | [Toast](../components/toast.md) or [Alert](../components/alert.md) | After the dialog closes (see States) |
31
+
32
+ The destructive `Button` variant uses `--color-danger` for its border/text (not
33
+ a filled danger panel that shouts past contrast). The confirm Button inside the
34
+ dialog is the **only** destructive-styled control; the dialog surface itself
35
+ does not use danger color.
36
+
37
+ ## Flow
38
+
39
+ 1. Person activates a destructive trigger (e.g. "Delete replica").
40
+ 2. A [Modal / Dialog](../components/modal-dialog.md) opens with focus moved to
41
+ the first meaningful element (usually the cancel Button, to make the safe
42
+ path the default).
43
+ 3. The dialog names the action and its consequence in plain language (see
44
+ [confirmations](confirmations.md) for copy structure).
45
+ 4. Person confirms or cancels:
46
+ - **Cancel** (or `Escape`, or overlay click when safe): dialog closes, focus
47
+ returns to the trigger, nothing changes.
48
+ - **Confirm**: the confirm Button enters loading
49
+ ([Spinner](../components/spinner.md), `aria-busy`). Cancel stays available
50
+ while the action is in flight, unless the action cannot be safely
51
+ interrupted.
52
+ 5. On success, the dialog closes and a [Toast](../components/toast.md) confirms
53
+ the outcome ("Replica 'prod-eu' deleted"). On failure, an
54
+ [Alert](../components/alert.md) explains what/why/now and the dialog may stay
55
+ open with the error next to the confirm action.
56
+
57
+ ## States
58
+
59
+ | State | Behavior |
60
+ | --- | --- |
61
+ | closed | Trigger available; no dialog. |
62
+ | open | Page behind is inert; focus trapped in dialog. Cancel and confirm available. |
63
+ | submitting | Confirm Button shows [Spinner](../components/spinner.md), `aria-busy`. Duplicate submission prevented. Cancel stays available unless interruption is unsafe. |
64
+ | error | Recoverable error shown next to the confirm action or as an [Alert](../components/alert.md) inside the dialog. Dialog stays open. The destructive action did **not** commit. |
65
+ | success | Dialog closes; [Toast](../components/toast.md) confirms. If the deleted entity was the current view, navigate to the parent list. |
66
+
67
+ `Escape` closes the dialog **unless** the destructive operation is in flight
68
+ and cannot be safely interrupted — in that case, `Escape` is inert or shows a
69
+ brief "Action in progress" status. Document this per surface.
70
+
71
+ ## Layout sketch
72
+
73
+ ```text
74
+ ┌─────────────────────────────────────────────┐
75
+ │ │
76
+ │ ┌───────────────────────────────────────┐ │
77
+ │ │ Delete "prod-eu"? │ │
78
+ │ │ │ │
79
+ │ │ This replica will be removed from the │ │
80
+ │ │ workspace. Active queries to it will │ │
81
+ │ │ be terminated. This cannot be undone. │ │
82
+ │ │ │ │
83
+ │ │ [Cancel] [Delete replica] │ │
84
+ │ └───────────────────────────────────────┘ │
85
+ │ │
86
+ └─────────────────────────────────────────────┘
87
+ ```
88
+
89
+ `Delete replica` is the only destructive-styled control. `Cancel` is the
90
+ default focus target so the safe path is one `Enter` away.
91
+
92
+ ## Rules
93
+
94
+ - **Always confirm destructive actions.** Do not commit on the trigger alone.
95
+ A single-click delete with no confirmation is a spec violation, even if the
96
+ trigger has a destructive variant.
97
+ - Name the action and its consequence. "Delete 'prod-eu'?" with "This cannot
98
+ be undone" or "Active queries will be terminated." Follow
99
+ [voice-and-tone](../voice-and-tone.md): match the confirmation's weight to
100
+ the action's irreversibility — do not wrap a low-stakes action in danger
101
+ color, and do not under-state a high-stakes one.
102
+ - The confirm Button is the **only** destructive control in the dialog. Do not
103
+ style the dialog surface, title, or body with `--color-danger`.
104
+ - Cancel is always available and is the safe default. Prefer focusing Cancel on
105
+ open so a reflexive `Enter` does the safe thing.
106
+ - Do not use "Are you sure?" as the only confirmation. State what will happen:
107
+ "This replica will be removed. Active queries will be terminated."
108
+ - For type-to-confirm (delete a named resource by typing its name), require the
109
+ exact name. Use an [Input](../components/input.md) in the dialog; the confirm
110
+ Button stays disabled until the typed value matches. Reserve this for the
111
+ highest-stakes actions (drop database, delete workspace).
112
+ - After success, do not leave the person on a deleted entity. Navigate to the
113
+ parent list or a neutral state.
114
+ - A destructive action triggered from the [command palette](command-palette.md)
115
+ still opens a confirmation dialog — the palette is acceleration, not a bypass
116
+ for the gate.
117
+
118
+ ## Accessibility
119
+
120
+ - Dialog: `role="dialog"`, `aria-modal="true"`, `aria-labelledby` (title),
121
+ `aria-describedby` (consequence) when the description is not the title.
122
+ - Focus moves to the first meaningful element on open (usually Cancel). `Tab`
123
+ and `Shift+Tab` cycle inside; `Escape` closes unless the action is
124
+ uninterruptible.
125
+ - The confirm Button's accessible name includes the action: "Delete replica",
126
+ not "Confirm" or "OK".
127
+ - On error, move focus to the error [Alert](../components/alert.md) or the
128
+ confirm action so the person lands on the recovery path.
129
+ - Type-to-confirm: the [Input](../components/input.md) has a
130
+ [Label](../components/label.md) ("Type 'prod-eu' to confirm"); the disabled
131
+ confirm Button has an accessible explanation of why it is disabled.
132
+
133
+ ## Related patterns
134
+
135
+ - [Confirmations](confirmations.md) — the broader dialog spec: risk
136
+ explanation, acknowledgment, copy structure.
137
+ - [Command palette](command-palette.md) — destructive commands still confirm.
@@ -0,0 +1,162 @@
1
+ # Developer-oriented interfaces
2
+
3
+ Raw value vs friendly display toggling for technical data. This pattern governs
4
+ how a surface lets a developer switch between a human-friendly presentation and
5
+ the exact machine-readable value, and composes the
6
+ [data-interfaces.md](../data-interfaces.md) rules into an interaction.
7
+
8
+ User story #26.
9
+
10
+ ## Purpose
11
+
12
+ Developer tools show data that has both a friendly form and a raw form: a
13
+ timestamp as "2 minutes ago" vs `2026-08-19T02:54:26Z`, a byte count as
14
+ `1.50 GiB` vs `1610612736`, a connection string as `postgresql://analytics…`
15
+ vs the full URI, a config value as `on` vs `true`. Developers often need the
16
+ exact raw value — to paste into a script, compare against a source, or debug —
17
+ while scanning benefits from the friendly form.
18
+
19
+ This pattern gives the person a consistent way to toggle between the two,
20
+ without losing the [data-interfaces.md](../data-interfaces.md) rules that govern
21
+ each form.
22
+
23
+ ## Component composition
24
+
25
+ | Region | Compose with | Role |
26
+ | --- | --- | --- |
27
+ | Display cell | [Table / DataTable](../components/table.md) cell or definition value | Shows friendly or raw form per current mode |
28
+ | Toggle control | [Switch](../components/switch.md), [Button](../components/button.md), or [Tabs](../components/tabs.md) | Switches the region between friendly and raw |
29
+ | Copy action | [IconButton](../components/icon-button.md) "Copy {value type}" | Copies the exact source value regardless of display mode |
30
+ | Full-value access | [Tooltip](../components/tooltip.md) + row/detail | Full value on hover/focus/touch (per [data-interfaces.md](../data-interfaces.md)) |
31
+ | Code rendering | `--type-role-code` / `--font-mono` | Raw values use code type; friendly values use their normal role |
32
+
33
+ ## Flow
34
+
35
+ 1. Person views a data-heavy surface (table, detail panel) in friendly mode by
36
+ default. Timestamps are relative, byte counts are humanized, connection
37
+ strings are truncated with ellipsis.
38
+ 2. Person activates the toggle ("Show raw values" [Switch](../components/switch.md),
39
+ or a [Tabs](../components/tabs.md) "Friendly / Raw", or a per-cell
40
+ [IconButton](../components/icon-button.md)).
41
+ 3. The region re-renders in raw mode: absolute timestamps, exact byte counts,
42
+ full connection strings (or full where space allows; truncation rules still
43
+ apply per [data-interfaces.md](../data-interfaces.md)).
44
+ 4. Person can copy any value — [copy](../data-interfaces.md) always uses the
45
+ exact source value, not the displayed form.
46
+ 5. Toggling back restores friendly mode. The toggle preference may persist per
47
+ surface or per person (documented).
48
+
49
+ ## States
50
+
51
+ | State | Behavior |
52
+ | --- | --- |
53
+ | friendly (default) | Human-readable forms: relative time, humanized bytes, truncated long values with full-value access. |
54
+ | raw | Machine-readable forms: absolute time (ISO 8601), exact byte counts, full values where space allows. Numeric alignment and `--type-role-numeric` still apply. |
55
+ | mixed | Rare: some columns raw, others friendly. Use per-column toggles only when the product needs it; default is one region-wide toggle. |
56
+
57
+ ## Layout sketch
58
+
59
+ ### Region-wide toggle
60
+
61
+ ```text
62
+ ┌──────────────────────────────────────────────────────────────────────┐
63
+ │ Replicas [Friendly ● Raw] [Show raw values]│
64
+ ├──────────────────────────────────────────────────────────────────────┤
65
+ │ Table (raw mode) │
66
+ │ ┌────────────────────────────────────────────────────────────────┐ │
67
+ │ │ Name Created Memory Conn string │ │
68
+ │ │ replica-01 2026-08-19T02:54:26Z 1610612736 B postgresql://… │ │
69
+ │ │ replica-02 2026-08-19T01:12:08Z 2147483648 B postgresql://… │ │
70
+ │ └────────────────────────────────────────────────────────────────┘ │
71
+ └──────────────────────────────────────────────────────────────────────┘
72
+ ```
73
+
74
+ ### Friendly (default) mode
75
+
76
+ ```text
77
+ ┌──────────────────────────────────────────────────────────────────────┐
78
+ │ Replicas [Friendly ● Raw] │
79
+ ├──────────────────────────────────────────────────────────────────────┤
80
+ │ Table (friendly mode) │
81
+ │ ┌────────────────────────────────────────────────────────────────┐ │
82
+ │ │ Name Created Memory Conn string │ │
83
+ │ │ replica-01 2 minutes ago 1.50 GiB postgresql://analytics… │ │
84
+ │ │ replica-02 1 hour ago 2.00 GiB postgresql://analytics… │ │
85
+ │ └────────────────────────────────────────────────────────────────┘ │
86
+ └──────────────────────────────────────────────────────────────────────┘
87
+ ```
88
+
89
+ Copy (`[Copy]` [IconButton](../components/icon-button.md) adjacent to a value)
90
+ copies the exact source: `1610612736 B` even in friendly mode where the cell
91
+ shows `1.50 GiB`.
92
+
93
+ ## Rules
94
+
95
+ ### What changes between modes
96
+
97
+ | Value type | Friendly | Raw |
98
+ | --- | --- | --- |
99
+ | Timestamp | Relative ("2 minutes ago") or localized | ISO 8601 (`2026-08-19T02:54:26Z`) or source epoch |
100
+ | Byte count | Humanized (`1.50 GiB`) | Exact (`1610612736 B`) |
101
+ | Duration | Humanized (`820 ms`, `1.2 s`) | Exact source unit (ms, µs) |
102
+ | Connection string / URI | Truncated (`postgresql://analytics…`) | Full value, or full where space allows |
103
+ | Config value | Friendly (`on`, `enabled`) | Source (`true`, `1`) |
104
+ | Identifier | Same in both (identifiers are already raw) | Same |
105
+
106
+ ### What does not change
107
+
108
+ - **Numeric alignment.** Raw numeric columns are still right-aligned with
109
+ `--type-role-numeric` and `--font-variant-numeric`. See
110
+ [data-interfaces.md](../data-interfaces.md) → Numeric values.
111
+ - **null ≠ 0 ≠ unknown.** `NULL`, `0`, and `—` are distinct in both modes.
112
+ See [data-interfaces.md](../data-interfaces.md) → Missing and indeterminate
113
+ values.
114
+ - **Dangerous values.** A dangerous value (`fsync = off`) keeps its
115
+ `Danger` marker and raw visibility in both modes. The friendly form does not
116
+ soften danger. See [data-interfaces.md](../data-interfaces.md) → Warnings and
117
+ dangerous values.
118
+ - **Copy always uses the source value.** Whether the display is friendly or
119
+ raw, [copy](../data-interfaces.md) copies the exact source — not the rounded,
120
+ humanized, or truncated presentation.
121
+ - **Truncation rules.** In raw mode, long values may still truncate per the
122
+ [data-interfaces.md](../data-interfaces.md) truncation rules (visible
123
+ ellipsis, full value in [Tooltip](../components/tooltip.md), touch-safe
124
+ full-value path). Raw mode does not mean "ignore layout"; it means "show the
125
+ source form where space allows."
126
+
127
+ ### Toggle mechanics
128
+
129
+ - Default is **friendly**. Raw is opt-in.
130
+ - The toggle is region-wide by default (one [Switch](../components/switch.md)
131
+ or [Tabs](../components/tabs.md) "Friendly / Raw" above the table). Per-column
132
+ or per-cell toggles are allowed only when the product needs mixed mode and
133
+ the toggle is clearly scoped.
134
+ - The toggle preference may persist per surface or per person. Document which.
135
+ - Toggling does not reload data — the underlying values are the same; only
136
+ presentation changes. Do not show a loading state for a display-mode toggle.
137
+ - In raw mode, use `--type-role-code` / `--font-mono` for values that are
138
+ machine-readable (connection strings, config keys, timestamps in ISO). In
139
+ friendly mode, use the normal type role (numeric role for numbers, body for
140
+ prose timestamps).
141
+
142
+ ## Accessibility
143
+
144
+ - The toggle control has an accessible name ("Show raw values", "Display mode")
145
+ and its state is announced.
146
+ - When the display mode changes, the updated values are in the DOM; do not
147
+ require a live-region announcement for every cell. If the person is focused
148
+ on a cell, its new value is read on the next interaction.
149
+ - Copy [IconButton](../components/icon-button.md) accessible name includes the
150
+ value type: "Copy memory (raw)", "Copy connection string". The copied value
151
+ is always the source, regardless of mode.
152
+ - Full-value access ([Tooltip](../components/tooltip.md) + row/detail) must work
153
+ in both modes per [data-interfaces.md](../data-interfaces.md) truncation
154
+ rules.
155
+
156
+ ## Related patterns
157
+
158
+ - [Large data tables](large-data-tables.md) — tables where raw/friendly toggle
159
+ is most useful.
160
+ - [data-interfaces.md](../data-interfaces.md) — the prescriptive cell-rendering
161
+ rules (alignment, null/unknown, truncation, copy, dangerous values) that both
162
+ modes compose.
@@ -0,0 +1,76 @@
1
+ # Empty states
2
+
3
+ Use an empty state when a collection or bounded region has no content to show.
4
+ It is a successful, known result—not loading, failure, or denied access.
5
+
6
+ ## Component composition
7
+
8
+ - [EmptyState](../components/empty-state.md) owns the title, description, and
9
+ optional action.
10
+ - Use [Button](../components/button.md) when the action changes the current
11
+ view, such as creating a record or clearing filters.
12
+ - Use [Link](../components/link.md) when the next step navigates elsewhere.
13
+ - In a [Table / DataTable](../components/table.md), keep useful headers and
14
+ place EmptyState in the body region. A list screen must not reinvent search,
15
+ filters, pagination, and empty state.
16
+
17
+ The surrounding region uses `--color-background` or `--color-surface`.
18
+ EmptyState copy uses `--color-foreground` and `--color-muted-foreground`;
19
+ actions retain their component tokens. Do not use a status color: empty is not
20
+ an error or warning.
21
+
22
+ ## Flow
23
+
24
+ 1. Resolve the collection request before deciding that it is empty.
25
+ 2. Distinguish first use, no matches, and expected informational emptiness.
26
+ 3. State what is empty and why, when the reason is useful.
27
+ 4. Offer one next action only when the person can change the state.
28
+ 5. After the action, move to loading, then populated, empty, or error based on
29
+ the result.
30
+
31
+ The action is optional. Do not add a disabled or dead-end action merely to
32
+ balance the layout. Informational copy is complete when no useful action exists.
33
+
34
+ | Situation | Copy and action |
35
+ | --- | --- |
36
+ | First use | “No queries yet. Create your first query to see it here.” + **Create query** Button. |
37
+ | No matches | “No queries match these filters.” + **Clear filters** Button when filters can be reset. |
38
+ | Informational | “No completed runs in this period.” No action when the person cannot produce one here. |
39
+
40
+ ## States
41
+
42
+ | State | Treatment |
43
+ | --- | --- |
44
+ | Loading | Do not show EmptyState. Preserve the region with Skeleton; lists use Skeleton rows. |
45
+ | Empty | Show the matching EmptyState variant with an optional Button or Link. |
46
+ | Error | Replace the empty treatment with the errors pattern and Alert. A failed request is not zero records. |
47
+ | Permission denied | Use the permission-denied pattern. Do not imply the protected collection is empty. |
48
+ | Populated | Replace EmptyState with the collection without moving surrounding controls. |
49
+
50
+ ## Layout sketch
51
+
52
+ ```text
53
+ PageHeader: Queries [Create query]
54
+ Search / filters / result count remain in place
55
+ ┌─────────────────────────────────────────────────────────┐
56
+ │ Name Owner Updated │
57
+ ├─────────────────────────────────────────────────────────┤
58
+ │ │
59
+ │ No queries yet │
60
+ │ Create your first query to see it here. │
61
+ │ [Create query] │
62
+ │ │
63
+ └─────────────────────────────────────────────────────────┘
64
+ ```
65
+
66
+ For no matches, keep Search and filters visible and replace the central action
67
+ with **Clear filters**. For informational emptiness, omit the action row.
68
+
69
+ ## Accessibility and copy
70
+
71
+ - Give the region an accessible name from the EmptyState title. Announce a
72
+ change to no results politely when it follows search or filtering.
73
+ - Do not make the whole empty region interactive. Keyboard focus reaches the
74
+ Button or Link only.
75
+ - Follow [voice and tone](../voice-and-tone.md): what is empty, why when useful,
76
+ and what to do. Avoid jokes, apologies, and terminal flourish.
@@ -0,0 +1,93 @@
1
+ # Errors
2
+
3
+ Use an error state when an operation failed or valid content could not be
4
+ loaded. Every error must explain a recovery path; a code, danger color, or
5
+ “Something went wrong” is not sufficient.
6
+
7
+ Permission denied is not a generic error. When the system succeeded in
8
+ determining that access is missing, use the
9
+ [permission-denied pattern](permission-denied.md).
10
+
11
+ ## Component composition
12
+
13
+ - [Alert](../components/alert.md) presents page-, section-, and operation-level
14
+ errors in context with an optional recovery Button or Link.
15
+ - [ValidationMessage](../components/validation-message.md) presents a
16
+ field-level error beside its FormField and points to the affected control.
17
+ - [Button](../components/button.md) performs an immediate recovery such as
18
+ retry; [Link](../components/link.md) navigates to settings or documentation.
19
+ - [Toast](../components/toast.md) is only for a brief failure whose recovery is
20
+ already available in context. Never put the only explanation or action in a
21
+ transient Toast.
22
+
23
+ Error meaning uses `--color-danger`; primary and supporting copy use
24
+ `--color-foreground` and `--color-muted-foreground` on `--color-surface`.
25
+ Recovery controls retain their semantic component tokens, including
26
+ `--color-focus`. Do not fill the whole region with danger color.
27
+
28
+ ## Mandatory what / why / now structure
29
+
30
+ Every error follows the hard rule in
31
+ [voice and tone](../voice-and-tone.md), in this order:
32
+
33
+ 1. **What happened.** Name the failed operation or unavailable content.
34
+ 2. **Why, when known.** Give a brief verified cause. Omit this part when the
35
+ cause is unknown; never guess.
36
+ 3. **What to do now.** Give a concrete recovery action or next step.
37
+
38
+ ```text
39
+ What: Connection to the database failed.
40
+ Why: The server at db.example.com:5432 did not respond within 5 seconds.
41
+ Now: Check that the database is reachable, then retry. [Retry]
42
+ ```
43
+
44
+ Keep diagnostic identifiers as secondary, copyable details when they help
45
+ support or debugging. They never replace the human explanation.
46
+
47
+ ## Flow
48
+
49
+ 1. Stop the pending presentation and preserve the person's input and context.
50
+ 2. Classify the scope: field, operation/section, or whole page.
51
+ 3. Write what happened, the known reason, and what the person can do now.
52
+ 4. Place the message beside the affected content and expose the recovery as a
53
+ Button or Link when it can be performed directly.
54
+ 5. Move or announce focus appropriately. On retry, keep the Alert visible with
55
+ its Button loading until the outcome is known.
56
+ 6. On success, remove the resolved error; on repeated failure, update verified
57
+ details without stacking duplicate Alerts.
58
+
59
+ ## States
60
+
61
+ | State | Treatment |
62
+ | --- | --- |
63
+ | Loading / retrying | Keep the error explanation visible; the recovery Button shows Spinner and the affected region is busy. |
64
+ | Field error | ValidationMessage follows what/why/now at the smallest useful scale and is linked to the invalid control. |
65
+ | Section or page error | One persistent Alert sits before or in place of the affected content. |
66
+ | Unknown cause | State what failed and what to do now; omit why. |
67
+ | Permission denied | Switch to the permission-denied pattern, without error severity or retry loops. |
68
+ | Recovered | Remove the Alert, clear stale invalid state, and restore the content without a redundant success message unless confirmation is needed. |
69
+
70
+ ## Layout sketch
71
+
72
+ ```text
73
+ PageHeader: Query results
74
+ ┌─ Alert: error ───────────────────────────────────────────┐
75
+ │ Query results could not be loaded. │ What
76
+ │ The database connection closed during execution. │ Why
77
+ │ Reconnect, then retry the query. [Reconnect] │ Now
78
+ └──────────────────────────────────────────────────────────┘
79
+
80
+ FormField: Connection name
81
+ [production db___________________________________________]
82
+ ValidationMessage: Use letters, numbers, hyphens, or underscores. [What/now]
83
+ ```
84
+
85
+ ## Accessibility and copy
86
+
87
+ - Use one assertive Alert for a newly introduced blocking error. Avoid several
88
+ competing live regions.
89
+ - On failed submission, focus the error summary or first invalid control.
90
+ Recovery actions remain reachable by keyboard and use visible focus.
91
+ - Error meaning must be present in text and iconography, not color alone.
92
+ - Be direct and non-accusatory. Do not apologize, joke, add terminal flourish,
93
+ or expose cryptic codes without context.
@@ -0,0 +1,147 @@
1
+ # Filtering
2
+
3
+ Structured filter controls that narrow a collection by attribute, not by free
4
+ text. This pattern composes [Select](../components/select.md),
5
+ [DropdownMenu](../components/dropdown-menu.md), [Popover](../components/popover.md),
6
+ [Checkbox](../components/checkbox.md), and [Switch](../components/switch.md) into
7
+ a consistent filter bar alongside [Search](search.md).
8
+
9
+ User story #2.
10
+
11
+ ## Purpose
12
+
13
+ Filters let the person narrow a collection by known attributes — status,
14
+ region, engine version, tagged label — with controls whose options are a closed
15
+ or bounded set. They complement [Search](search.md): Search narrows by free
16
+ text; filters narrow by discrete facet. A list screen composes both rather than
17
+ reinventing either.
18
+
19
+ **Canonical rule:** A list screen must not reinvent search, filters,
20
+ pagination, and empty state. Compose filter controls in the toolbar — do not
21
+ invent a per-list filter kit.
22
+
23
+ ## Component composition
24
+
25
+ | Filter shape | Compose with | Example |
26
+ | --- | --- | --- |
27
+ | One value from a set | [Select](../components/select.md) | "Status: any / healthy / degraded / down" |
28
+ | Toggle a single facet on/off | [Switch](../components/switch.md) or [Checkbox](../components/checkbox.md) | "Show only replicas with lag" |
29
+ | Multiple values from a set | [Checkbox](../components/checkbox.md) group inside a [Popover](../components/popover.md) | "Region: ☑ eu ☑ us ☐ ap" |
30
+ | Range or complex facet | [Popover](../components/popover.md) with form controls | "Lag: 0–500 ms" |
31
+ | Quick toggles (few, stable) | [Button](../components/button.md) `ghost` toggle or [Tabs](../components/tabs.md) | "All / Active / Archived" |
32
+ | Active-filter summary | [Badge](../components/badge.md) per active filter or a text line | "Status: degraded ×" |
33
+
34
+ Filters live in the list toolbar, beside [Search](search.md) and above
35
+ [Pagination](../components/pagination.md). They are siblings of the table, not
36
+ columns.
37
+
38
+ ## Flow
39
+
40
+ 1. Person opens the list. No filters active; full collection (or default
41
+ filter) is visible.
42
+ 2. Person activates a filter control (Select, Popover trigger, Switch).
43
+ 3. The collection re-queries or re-filters. The results region shows
44
+ [Skeleton](../components/skeleton.md) rows for server-side filters; for
45
+ client-side filters the set updates without a loading flash.
46
+ 4. Active filters are summarized as removable [Badge](../components/badge.md)s
47
+ or a text line in the toolbar.
48
+ 5. If filters exclude everything, the collection body shows
49
+ [EmptyState](../components/empty-state.md) `no-results` with a
50
+ "Clear filters" action.
51
+ 6. Clearing a filter (via its Badge × or a "Clear filters" control) restores
52
+ the wider set.
53
+
54
+ ## States
55
+
56
+ | State | Behavior |
57
+ | --- | --- |
58
+ | idle | No filters active. Default set visible. |
59
+ | applying | Server-side: results region `aria-busy`, Skeleton rows. Client-side: set updates immediately. |
60
+ | active | One or more filters active. Summarized as Badges or a text line. |
61
+ | no matches | Filters exclude everything → [EmptyState](../components/empty-state.md) `no-results`. Offer "Clear filters". Keep filter controls visible and editable. |
62
+ | error | Server query failed → [Alert](../components/alert.md) with retry. Do not show EmptyState for a failure. |
63
+
64
+ Filter controls themselves follow their component states (Select open/closed,
65
+ Switch on/off). The list-level states above describe the collection.
66
+
67
+ ## Layout sketch
68
+
69
+ ```text
70
+ ┌──────────────────────────────────────────────────────────────────────┐
71
+ │ PageHeader: Replicas [Add replica] │
72
+ ├──────────────────────────────────────────────────────────────────────┤
73
+ │ Toolbar │
74
+ │ [🔍 Search replicas...] [Status▾] [Region▾] [Show lag only ◯] │
75
+ │ │
76
+ │ Active: [degraded ×] [eu ×] [Clear filters] │
77
+ │ 3 of 18 replicas │
78
+ ├──────────────────────────────────────────────────────────────────────┤
79
+ │ Table / DataTable │
80
+ │ ┌────────────────────────────────────────────────────────────────┐ │
81
+ │ │ Name Host Status Lag Region │ │
82
+ │ │ replica-01 db.eu.example degraded 820 ms eu │ │
83
+ │ │ replica-03 db.eu.backup degraded 1.2 s eu │ │
84
+ │ │ replica-07 db.eu.dr degraded — eu │ │
85
+ │ └────────────────────────────────────────────────────────────────┘ │
86
+ │ ← 1 (of 1) → │
87
+ └──────────────────────────────────────────────────────────────────────┘
88
+ ```
89
+
90
+ When filters exclude everything:
91
+
92
+ ```text
93
+ ┌──────────────────────────────────────────────────────────────────────┐
94
+ │ Toolbar │
95
+ │ [🔍 ...] [Status▾] [Region▾] [Show lag only ●] │
96
+ │ Active: [down ×] [ap ×] [Clear filters] │
97
+ ├──────────────────────────────────────────────────────────────────────┤
98
+ │ │
99
+ │ No replicas match these filters │
100
+ │ No replicas with status "down" in region "ap". │
101
+ │ [Clear filters] │
102
+ │ │
103
+ └──────────────────────────────────────────────────────────────────────┘
104
+ ```
105
+
106
+ ## Rules
107
+
108
+ - Filters and [Search](search.md) narrow the collection **together**. The
109
+ active query and active filters form one result set. Document whether
110
+ "Clear search" also clears filters (default: no — they are independent unless
111
+ the surface offers a single "Reset all").
112
+ - Active filters must be visible and removable individually. A person should
113
+ not have to open a Popover to discover which filters are active.
114
+ - Default filters are allowed when they reflect a sensible default view
115
+ ("Active only"). The active-filter summary must still show the default as
116
+ active so it is not a hidden filter.
117
+ - Do not invent a filter UI that competes with [Select](../components/select.md)
118
+ / [Checkbox](../components/checkbox.md) / [Popover](../components/popover.md).
119
+ If the facet is one-of-many, use Select; if many-of-many, use a Checkbox
120
+ group in a Popover.
121
+ - Filter state is part of the list's state, not global. Navigating away and
122
+ back may restore it (documented per surface) but filters must not leak into
123
+ unrelated lists.
124
+ - A filter that changes the set dramatically (e.g. "Show deleted") should make
125
+ the change obvious — a visible Badge and, if the consequence is surprising, a
126
+ short note.
127
+ - Combine filters with [sorting](sorting.md) and [pagination](pagination.md)
128
+ consistently: filter narrows, sort orders, pagination pages.
129
+
130
+ ## Accessibility
131
+
132
+ - Each filter control has an accessible name ("Status", "Region", "Show only
133
+ replicas with lag"). Placeholder alone is not a name for Select.
134
+ - Active-filter Badges that are removable are [IconButton](../components/icon-button.md)s
135
+ or Buttons with `aria-label` like "Remove status filter: degraded".
136
+ - When filters change the result set, update a polite live region or the result
137
+ count so screen reader users know the set changed.
138
+ - No-matches [EmptyState](../components/empty-state.md) must be reachable and
139
+ announced; keep filter controls in the tab order so the person can adjust.
140
+
141
+ ## Related patterns
142
+
143
+ - [Search](search.md) — free-text narrowing that composes with filters.
144
+ - [Sorting](sorting.md) — ordering the filtered set.
145
+ - [Pagination](pagination.md) — paging the filtered set.
146
+ - [Large data tables](large-data-tables.md) — tables where filters are
147
+ essential to manage volume.