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