@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,94 @@
|
|
|
1
|
+
# Onboarding
|
|
2
|
+
|
|
3
|
+
Onboarding guides a new person through the minimum setup required to reach a
|
|
4
|
+
useful product state. It is a finite task flow, not a product tour, marketing
|
|
5
|
+
carousel, or substitute for clear everyday UI.
|
|
6
|
+
|
|
7
|
+
## Component composition
|
|
8
|
+
|
|
9
|
+
- [Card](../components/card.md) groups each setup task or the active task.
|
|
10
|
+
- [Button](../components/button.md) performs setup actions; at most one primary
|
|
11
|
+
Button advances the current step.
|
|
12
|
+
- [Link](../components/link.md) opens optional documentation or a route that
|
|
13
|
+
must remain navigable.
|
|
14
|
+
- [FormField](../components/form-field.md), [Input](../components/input.md),
|
|
15
|
+
[Select](../components/select.md), and their existing validation composition
|
|
16
|
+
collect setup data.
|
|
17
|
+
- [Alert](../components/alert.md) and
|
|
18
|
+
[ValidationMessage](../components/validation-message.md) handle failures at
|
|
19
|
+
their proper scope. Skeleton or a loading Button handles pending work.
|
|
20
|
+
|
|
21
|
+
The issue calls the progress composition “Steps”, but Kiso has no Steps
|
|
22
|
+
component. Represent progress as a semantic ordered list with current and
|
|
23
|
+
completed text states; do not invent a new component in this pattern.
|
|
24
|
+
|
|
25
|
+
Cards use `--color-surface`, `--color-border`, `--radius-lg`, and semantic
|
|
26
|
+
spacing. Current-step emphasis uses `--color-primary`; completed status may use
|
|
27
|
+
`--color-success`; primary and secondary copy use `--color-foreground` and
|
|
28
|
+
`--color-muted-foreground`. Keyboard focus uses `--color-focus`.
|
|
29
|
+
|
|
30
|
+
## Flow
|
|
31
|
+
|
|
32
|
+
1. Define the first useful outcome and include only setup steps required to
|
|
33
|
+
reach it.
|
|
34
|
+
2. Show the total sequence and identify the current step in text.
|
|
35
|
+
3. Explain why the current input or permission is needed before asking for it.
|
|
36
|
+
4. Preserve valid input while an action loads or fails. Advance only after the
|
|
37
|
+
step succeeds.
|
|
38
|
+
5. Let the person go back without losing completed work. Offer **Skip** only
|
|
39
|
+
for genuinely optional steps and state the consequence.
|
|
40
|
+
6. Finish in the useful product view, not a celebration screen that blocks the
|
|
41
|
+
next task. Keep a way to resume incomplete setup later.
|
|
42
|
+
|
|
43
|
+
Do not force onboarding when the required state already exists. Returning
|
|
44
|
+
people resume at the first incomplete required step; they do not replay the
|
|
45
|
+
whole flow.
|
|
46
|
+
|
|
47
|
+
## States
|
|
48
|
+
|
|
49
|
+
| State | Treatment |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| New / incomplete | Show ordered progress, the current Card, and one primary advance action. |
|
|
52
|
+
| Loading | Preserve fields and progress; the active Button shows Spinner or known Card content uses Skeleton. |
|
|
53
|
+
| Empty dependency | Explain the missing prerequisite and offer the action that creates or connects it; do not show a generic empty dashboard. |
|
|
54
|
+
| Validation error | Keep the step open and show ValidationMessage at the field. |
|
|
55
|
+
| Operation error | Keep the step open, show an actionable Alert using what/why/now, and allow retry. |
|
|
56
|
+
| Permission denied | Explain the blocked setup task and access path with the permission-denied pattern; do not call the whole onboarding failed. |
|
|
57
|
+
| Complete | Mark required steps complete and navigate to the useful destination. |
|
|
58
|
+
|
|
59
|
+
## Layout sketch
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
PageHeader: Set up your workspace
|
|
63
|
+
|
|
64
|
+
1. Workspace details Complete
|
|
65
|
+
2. Connect database Current
|
|
66
|
+
3. Invite team Optional
|
|
67
|
+
|
|
68
|
+
┌─ Card: Connect database ────────────────────────────────┐
|
|
69
|
+
│ Add a connection to run your first query. │
|
|
70
|
+
│ │
|
|
71
|
+
│ Connection name │
|
|
72
|
+
│ [production___________________________________________] │
|
|
73
|
+
│ Database URL │
|
|
74
|
+
│ [postgres://__________________________________________] │
|
|
75
|
+
│ │
|
|
76
|
+
│ Docs [Back] [Test connection]│
|
|
77
|
+
└─────────────────────────────────────────────────────────┘
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`Docs` is a Link. `Back` and `Test connection` are Buttons; only **Test
|
|
81
|
+
connection** is primary. The ordered list communicates “2 of 3” and current,
|
|
82
|
+
completed, and optional states in text rather than color alone.
|
|
83
|
+
|
|
84
|
+
## Accessibility and copy
|
|
85
|
+
|
|
86
|
+
- Use an ordered list for progress and expose the current item with text and
|
|
87
|
+
`aria-current="step"`. Announce step changes politely and move focus to the
|
|
88
|
+
new step heading.
|
|
89
|
+
- Keep native form order and visible labels. Back navigation must not discard
|
|
90
|
+
input without warning.
|
|
91
|
+
- Do not use disabled future steps as the only explanation of prerequisites.
|
|
92
|
+
State what is needed beside the active task.
|
|
93
|
+
- Keep copy direct and task-oriented. Avoid tours, jargon without context,
|
|
94
|
+
playful filler, and terminal flourish in functional text.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Pagination
|
|
2
|
+
|
|
3
|
+
Explicit page navigation for known or meaningfully bounded datasets. This
|
|
4
|
+
pattern composes the [Pagination](../components/pagination.md) component below a
|
|
5
|
+
[Table / DataTable](../components/table.md) and governs when paging is the right
|
|
6
|
+
model versus [large-data-tables](large-data-tables.md) virtualization or
|
|
7
|
+
incremental loading.
|
|
8
|
+
|
|
9
|
+
User story #3.
|
|
10
|
+
|
|
11
|
+
## Purpose
|
|
12
|
+
|
|
13
|
+
Pagination exposes position and direct page navigation when page numbers help
|
|
14
|
+
the person reason about a dataset: "page 7 of 40", "show me the next 20
|
|
15
|
+
replicas". It composes with [Search](search.md), [filtering](filtering.md), and
|
|
16
|
+
[sorting](sorting.md) — those narrow and order the set; Pagination pages it.
|
|
17
|
+
|
|
18
|
+
**Canonical rule:** A list screen must not reinvent search, filters,
|
|
19
|
+
pagination, and empty state. Compose [Pagination](../components/pagination.md)
|
|
20
|
+
— do not invent a per-list pager.
|
|
21
|
+
|
|
22
|
+
## Component composition
|
|
23
|
+
|
|
24
|
+
| Region | Compose with | Role |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Page navigation | [Pagination](../components/pagination.md) | Previous / page numbers / Next below the table |
|
|
27
|
+
| Position summary | text line or Pagination result summary | "Page 3 of 12 · 41–60 of 230 replicas" |
|
|
28
|
+
| Page size control | [Select](../components/select.md) (optional) | "20 / 50 / 100 per page" |
|
|
29
|
+
| Loading state | [Skeleton](../components/skeleton.md) rows in the body | While a page fetch runs |
|
|
30
|
+
|
|
31
|
+
Pagination is a sibling below the table, not a table row. It is a navigation
|
|
32
|
+
region: `<nav aria-label="Pagination">`.
|
|
33
|
+
|
|
34
|
+
## Flow
|
|
35
|
+
|
|
36
|
+
1. Person views page 1 of the result set (already narrowed by Search/filters
|
|
37
|
+
and ordered by sort).
|
|
38
|
+
2. Person activates a page number, Previous, or Next.
|
|
39
|
+
3. The results region enters loading: [Skeleton](../components/skeleton.md)
|
|
40
|
+
rows replace the body, `aria-busy` on the region. Pagination controls stay
|
|
41
|
+
visible and the current page is still indicated.
|
|
42
|
+
4. The new page arrives; body swaps to populated rows.
|
|
43
|
+
5. If the page is empty (e.g. filters changed and the set shrank), show
|
|
44
|
+
[EmptyState](../components/empty-state.md) `no-results` and reset to page 1.
|
|
45
|
+
|
|
46
|
+
Changing [Search](search.md) query, [filters](filtering.md), or
|
|
47
|
+
[sort](sorting.md) resets to page 1 — the person expects the top of the new
|
|
48
|
+
result set.
|
|
49
|
+
|
|
50
|
+
## States
|
|
51
|
+
|
|
52
|
+
| State | Behavior |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| idle | Page loaded; Pagination shows current position. |
|
|
55
|
+
| loading | Body shows Skeleton rows; `aria-busy` on the region. Controls remain; duplicate page requests are prevented. Previous/Next at a boundary are disabled with `--color-disabled`. |
|
|
56
|
+
| boundary | Previous disabled on page 1; Next disabled on last page. Page Links are never disabled — they are omitted or replaced by ellipsis. |
|
|
57
|
+
| empty | Set shrank to zero → [EmptyState](../components/empty-state.md) `no-results`; reset to page 1. |
|
|
58
|
+
| error | Page fetch failed → [Alert](../components/alert.md) with retry. Do not leave Skeleton rows up after failure. |
|
|
59
|
+
|
|
60
|
+
## Layout sketch
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
64
|
+
│ Toolbar │
|
|
65
|
+
│ [🔍 Search replicas...] [Status▾] │
|
|
66
|
+
│ 230 replicas · Page 3 of 12 │
|
|
67
|
+
├──────────────────────────────────────────────────────────────────────┤
|
|
68
|
+
│ Table / DataTable │
|
|
69
|
+
│ ┌────────────────────────────────────────────────────────────────┐ │
|
|
70
|
+
│ │ Name ▲ Host Status Lag ▼ Region │ │
|
|
71
|
+
│ │ replica-41 db.eu.example ok 12 ms eu │ │
|
|
72
|
+
│ │ replica-42 db.eu.backup ok 8 ms eu │ │
|
|
73
|
+
│ │ ... │ │
|
|
74
|
+
│ └────────────────────────────────────────────────────────────────┘ │
|
|
75
|
+
│ │
|
|
76
|
+
│ Page 3 of 12 · 41–60 of 230 [20 / page ▾] │
|
|
77
|
+
│ ← 1 2 [3] 4 5 … 12 → │
|
|
78
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Rules
|
|
82
|
+
|
|
83
|
+
- Use Pagination when the dataset size is **known or meaningfully bounded** and
|
|
84
|
+
page position helps the person. For unbounded activity streams, use
|
|
85
|
+
incremental loading instead.
|
|
86
|
+
- Do not use Pagination to hide a missing [Search](search.md) or
|
|
87
|
+
[filtering](filtering.md) capability. If the person must page through 200
|
|
88
|
+
pages to find one row, the list is missing Search.
|
|
89
|
+
- Changing Search, filters, or sort resets to page 1.
|
|
90
|
+
- Selection policy across pages must be explicit: either clear selection on
|
|
91
|
+
page change, or keep a cross-page selection model with a visible count
|
|
92
|
+
("3 selected across pages"). Pick one per surface and document it.
|
|
93
|
+
- Page size, if configurable, is a [Select](../components/select.md) with a
|
|
94
|
+
small set of sensible options. Changing page size resets to page 1.
|
|
95
|
+
- For very large client-side sets (thousands of rows) where paging is not the
|
|
96
|
+
task, prefer virtualization — see [large-data-tables](large-data-tables.md).
|
|
97
|
+
Pagination is for known, page-shaped sets; virtualization is for scrolling
|
|
98
|
+
one large loaded set.
|
|
99
|
+
- Do not combine Pagination and infinite scroll on the same table. Pick one
|
|
100
|
+
model per surface.
|
|
101
|
+
|
|
102
|
+
## Accessibility
|
|
103
|
+
|
|
104
|
+
- Use `<nav aria-label="Pagination">`. Give controls names such as "Go to
|
|
105
|
+
page 4", "Previous page", "Next page"; the visible numeral alone is not
|
|
106
|
+
enough.
|
|
107
|
+
- Current page has `aria-current="page"`. Ellipses are not focusable.
|
|
108
|
+
- After a page change, move focus to the results heading or announce the
|
|
109
|
+
updated range in a polite live region ("Showing 41 to 60 of 230 replicas").
|
|
110
|
+
- Previous/Next at a boundary use `--color-disabled` and `aria-disabled`;
|
|
111
|
+
page Links are never disabled.
|
|
112
|
+
- Native Link or Button keyboard behavior applies; `Tab` moves through
|
|
113
|
+
controls.
|
|
114
|
+
|
|
115
|
+
## Related patterns
|
|
116
|
+
|
|
117
|
+
- [Search](search.md) — narrows the set before paging.
|
|
118
|
+
- [Filtering](filtering.md) — narrows the set before paging.
|
|
119
|
+
- [Sorting](sorting.md) — orders the set before paging.
|
|
120
|
+
- [Large data tables](large-data-tables.md) — when virtualization is the
|
|
121
|
+
better model than paging.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Permission denied
|
|
2
|
+
|
|
3
|
+
Permission denied is a distinct product state: the requested resource or action
|
|
4
|
+
exists, and the system has determined that the current person cannot access it.
|
|
5
|
+
It is not a generic error, an empty collection, or a failed request.
|
|
6
|
+
|
|
7
|
+
## Component composition
|
|
8
|
+
|
|
9
|
+
- Use [Alert](../components/alert.md) with `info` semantics when a denied action
|
|
10
|
+
sits inside otherwise available content.
|
|
11
|
+
- Use [EmptyState](../components/empty-state.md) as a dedicated locked state
|
|
12
|
+
when denial replaces an entire bounded region or page. Its title and
|
|
13
|
+
description explain access, never emptiness.
|
|
14
|
+
- Use [Link](../components/link.md) to open access documentation, workspace
|
|
15
|
+
settings, or a request-access route.
|
|
16
|
+
- Use [Button](../components/button.md) only when the product can submit an
|
|
17
|
+
access request directly. Do not present a retry action unless permissions may
|
|
18
|
+
genuinely have changed.
|
|
19
|
+
|
|
20
|
+
Permission-denied content uses `--color-foreground` and
|
|
21
|
+
`--color-muted-foreground` on `--color-surface` or `--color-background`.
|
|
22
|
+
An informational Alert may use `--color-info`. **Do not use
|
|
23
|
+
`--color-danger`: denied access is not an error severity.** Link and focus
|
|
24
|
+
treatments use `--color-primary` and `--color-focus`.
|
|
25
|
+
|
|
26
|
+
## Flow
|
|
27
|
+
|
|
28
|
+
1. Identify exactly which resource or action is blocked.
|
|
29
|
+
2. State the applicable access rule or required role when known.
|
|
30
|
+
3. Offer the shortest real route to access: request access, contact a named
|
|
31
|
+
role, or open access settings/documentation.
|
|
32
|
+
4. Preserve navigation and any safe surrounding context. Hide protected data
|
|
33
|
+
rather than rendering redacted fragments that reveal its shape.
|
|
34
|
+
5. If access is granted, re-check authorization and replace the denied state
|
|
35
|
+
with loading, then the authorized result.
|
|
36
|
+
|
|
37
|
+
Copy follows **blocked / why / access path**:
|
|
38
|
+
|
|
39
|
+
> You can't edit this query. Only the query author and workspace admins can
|
|
40
|
+
> edit it. Ask a workspace admin to grant you access.
|
|
41
|
+
|
|
42
|
+
This resembles the clarity of what/why/now, but it does not label the condition
|
|
43
|
+
as a failure and does not use error severity.
|
|
44
|
+
|
|
45
|
+
## States
|
|
46
|
+
|
|
47
|
+
| State | Treatment |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| Checking access | Show the loading pattern without protected content. Do not flash a denied state before authorization resolves. |
|
|
50
|
+
| Action denied | Keep available content and place an informational Alert beside the blocked action. Explain why the control is absent or unavailable. |
|
|
51
|
+
| Region/page denied | Replace protected content with a dedicated locked EmptyState composition and one access path when available. |
|
|
52
|
+
| Requesting access | The request Button shows its loading state; keep the explanation visible and prevent duplicates. |
|
|
53
|
+
| Request sent | Confirm in context with the expected next step; do not imply access is already granted. |
|
|
54
|
+
| Access granted | Re-enter loading, then show authorized content. |
|
|
55
|
+
| Access check failed | Use the errors pattern. An inability to determine permission is a system failure, not a denial. |
|
|
56
|
+
|
|
57
|
+
## Layout sketch
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
PageHeader: Production workspace
|
|
61
|
+
Breadcrumb and safe workspace navigation remain visible
|
|
62
|
+
┌─────────────────────────────────────────────────────────┐
|
|
63
|
+
│ Restricted query │
|
|
64
|
+
│ You can't view this query. It is limited to members │
|
|
65
|
+
│ of the Production Operators group. │
|
|
66
|
+
│ │
|
|
67
|
+
│ [Request access] Access policy │
|
|
68
|
+
└─────────────────────────────────────────────────────────┘
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`Request access` is a Button because it submits an action. `Access policy` is a
|
|
72
|
+
Link because it navigates. If neither path exists, say whom to contact and omit
|
|
73
|
+
the action rather than showing a disabled control.
|
|
74
|
+
|
|
75
|
+
## Accessibility and copy
|
|
76
|
+
|
|
77
|
+
- Name the denied region from its title. Use a polite status for a denial that
|
|
78
|
+
appears after interaction; reserve assertive alerts for actual urgent errors.
|
|
79
|
+
- Move focus to the explanation when denial follows activation and the person
|
|
80
|
+
would otherwise land on removed content.
|
|
81
|
+
- Do not disclose protected names, counts, field values, or membership beyond
|
|
82
|
+
what the person is allowed to know.
|
|
83
|
+
- Avoid “Access denied,” “unauthorized,” blame, corporate language, and false
|
|
84
|
+
retry actions. State what is blocked, why, and how to request access.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Search
|
|
2
|
+
|
|
3
|
+
Search-driven interaction for narrowing a visible collection by query. This
|
|
4
|
+
pattern composes the [Search](../components/search.md) component into a list or
|
|
5
|
+
table toolbar and governs when, how, and where filtering by query happens.
|
|
6
|
+
|
|
7
|
+
User story #6.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Search lets the person type a query to narrow what they already see — rows in a
|
|
12
|
+
[Table / DataTable](../components/table.md), items in a list-detail master, or
|
|
13
|
+
entries in a panel. The collection owns the data; Search only supplies the query
|
|
14
|
+
string. It is **not** global navigation or command execution — that is the
|
|
15
|
+
[command palette](command-palette.md).
|
|
16
|
+
|
|
17
|
+
**Canonical rule:** A list screen must not reinvent search, filters,
|
|
18
|
+
pagination, and empty state. Compose [Search](../components/search.md) — do not
|
|
19
|
+
invent a parallel query field per list.
|
|
20
|
+
|
|
21
|
+
## Component composition
|
|
22
|
+
|
|
23
|
+
| Region | Compose with | Role |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| Query field | [Search](../components/search.md) | Live-filter or submit-filter the collection; scoped to this list |
|
|
26
|
+
| Clear control | Search's built-in Clear [IconButton](../components/icon-button.md) | Resets query; keeps focus in the field |
|
|
27
|
+
| Pending indicator | [Spinner](../components/spinner.md) inside Search | Results are resolving (server-side or slow index) |
|
|
28
|
+
| Result count | polite live region or toolbar text | "12 of 40 replicas" after results settle |
|
|
29
|
+
| No matches | [EmptyState](../components/empty-state.md) `no-results` | Replaces the collection body, not a Search error |
|
|
30
|
+
| Invalid query | [ValidationMessage](../components/validation-message.md) via [FormField](../components/form-field.md) | Only when the query syntax itself is invalid (regex, etc.) |
|
|
31
|
+
|
|
32
|
+
Search sits in the list toolbar, beside [filtering](filtering.md) controls and
|
|
33
|
+
above [Pagination](../components/pagination.md). It is a sibling of those
|
|
34
|
+
controls, not nested inside the table.
|
|
35
|
+
|
|
36
|
+
## Flow
|
|
37
|
+
|
|
38
|
+
### Instant (client-side or fast index)
|
|
39
|
+
|
|
40
|
+
1. Person types into the Search field.
|
|
41
|
+
2. Query is debounced (product-defined; short enough to feel live).
|
|
42
|
+
3. Collection re-filters. Result count updates in a polite live region.
|
|
43
|
+
4. If the query matches nothing, the collection body shows
|
|
44
|
+
[EmptyState](../components/empty-state.md) `no-results` with a
|
|
45
|
+
"Clear search" action.
|
|
46
|
+
5. Clearing the query restores the full collection; focus stays in the field.
|
|
47
|
+
|
|
48
|
+
### Submit (expensive server query)
|
|
49
|
+
|
|
50
|
+
1. Person types the query. Results do not change yet.
|
|
51
|
+
2. Person presses `Enter` or activates a visible "Search" [Button](../components/button.md).
|
|
52
|
+
3. The results region enters loading ([Skeleton](../components/skeleton.md)
|
|
53
|
+
rows), and `aria-busy` is set on the region.
|
|
54
|
+
4. Results arrive; region swaps to populated or no-matches EmptyState.
|
|
55
|
+
|
|
56
|
+
Do not mix instant and submit behavior on the same Search field without making
|
|
57
|
+
the mode obvious. Pick one per surface and keep it consistent.
|
|
58
|
+
|
|
59
|
+
## States
|
|
60
|
+
|
|
61
|
+
| State | Behavior |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| idle | Empty query; full collection visible. Field is ready to type. |
|
|
64
|
+
| typing (instant) | Debounced; results update without focus leaving the field. |
|
|
65
|
+
| resolving | Query submitted; [Spinner](../components/spinner.md) inside Search; region `aria-busy`. Query value stays visible — do not clear it. |
|
|
66
|
+
| no matches | Collection body → [EmptyState](../components/empty-state.md) `no-results`. Offer "Clear search". The Search field keeps the query so the person can edit it. |
|
|
67
|
+
| error | Results failed to load. Show [Alert](../components/alert.md) (what/why/now) above or in place of the body with a retry [Button](../components/button.md). Do not show an EmptyState for a failure. |
|
|
68
|
+
| invalid query | Rare. Only when the query syntax is invalid (e.g. malformed regex). `aria-invalid` + [ValidationMessage](../components/validation-message.md). Zero hits is **not** invalid. |
|
|
69
|
+
|
|
70
|
+
Loading, empty, and error must never be ambiguous: Skeleton rows ≠ EmptyState
|
|
71
|
+
no-results ≠ Alert.
|
|
72
|
+
|
|
73
|
+
## Layout sketch
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
77
|
+
│ PageHeader: Queries [Create query] │
|
|
78
|
+
├──────────────────────────────────────────────────────────────────────┤
|
|
79
|
+
│ Toolbar │
|
|
80
|
+
│ [🔍 Search queries..............] [Status▾] [Clear filters] │
|
|
81
|
+
│ │
|
|
82
|
+
│ 12 of 40 queries │
|
|
83
|
+
├──────────────────────────────────────────────────────────────────────┤
|
|
84
|
+
│ Table / DataTable │
|
|
85
|
+
│ ┌────────────────────────────────────────────────────────────────┐ │
|
|
86
|
+
│ │ Name Author Status Modified │ │
|
|
87
|
+
│ │ slow-join ada warn 2d ago │ │
|
|
88
|
+
│ │ index-health sam ok 5d ago │ │
|
|
89
|
+
│ │ ... │ │
|
|
90
|
+
│ └────────────────────────────────────────────────────────────────┘ │
|
|
91
|
+
│ ← 1 2 3 … → │
|
|
92
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
When the query matches nothing:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
99
|
+
│ Toolbar │
|
|
100
|
+
│ [🔍 no matching..............] [Clear filters] │
|
|
101
|
+
├──────────────────────────────────────────────────────────────────────┤
|
|
102
|
+
│ │
|
|
103
|
+
│ No queries match "no matching" │
|
|
104
|
+
│ Try a different search or clear filters. │
|
|
105
|
+
│ [Clear search] │
|
|
106
|
+
│ │
|
|
107
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Rules
|
|
111
|
+
|
|
112
|
+
- Search is scoped to **one collection**. Do not make a single Search field
|
|
113
|
+
filter two independent tables on the same screen; give each its own field.
|
|
114
|
+
- Zero hits is an empty state, not a Search error. Never show
|
|
115
|
+
[ValidationMessage](../components/validation-message.md) for "no results".
|
|
116
|
+
- Keep the query visible during loading and no-matches. Clearing the query is
|
|
117
|
+
the person's action, not a side effect of a failed fetch.
|
|
118
|
+
- `Escape` clears the query if non-empty (pick one behavior per surface and
|
|
119
|
+
keep it consistent). `Escape` does **not** open the
|
|
120
|
+
[command palette](command-palette.md) — that is `⌘K` / `Ctrl+K`.
|
|
121
|
+
- After clearing, keep focus in the Search field and refresh results.
|
|
122
|
+
- Do not move focus into the table on every keystroke.
|
|
123
|
+
- Highlight matched query terms in results by default. Highlighting is
|
|
124
|
+
reinforcement; the filtered set is the real signal. A product may opt out
|
|
125
|
+
only when highlighting is impractical (e.g. server-side search with no
|
|
126
|
+
match offsets) and must document the opt-out. Keep highlighted text readable
|
|
127
|
+
— use `--color-primary` as a background tint, never as text color that
|
|
128
|
+
drops below contrast.
|
|
129
|
+
- Search composes with [filtering](filtering.md): the active query and active
|
|
130
|
+
filters narrow the collection together. Clearing Search does not clear
|
|
131
|
+
filters unless the surface defines that as its single clear action.
|
|
132
|
+
|
|
133
|
+
## Accessibility
|
|
134
|
+
|
|
135
|
+
- Accessible name always present (`label` / `aria-label` / `aria-labelledby`).
|
|
136
|
+
Placeholder is not the name.
|
|
137
|
+
- Use native `type="search"` so platform clear and semantics work.
|
|
138
|
+
- Debounced instant search updates results without trapping focus. Use a polite
|
|
139
|
+
status region ("12 of 40 replicas") only when the change would otherwise be
|
|
140
|
+
silent.
|
|
141
|
+
- No-matches EmptyState must be announced or discoverable; do not leave the
|
|
142
|
+
region visually and accessibly empty.
|
|
143
|
+
|
|
144
|
+
## Related patterns
|
|
145
|
+
|
|
146
|
+
- [Filtering](filtering.md) — structured filters that compose with Search.
|
|
147
|
+
- [Sorting](sorting.md) — order of the filtered set.
|
|
148
|
+
- [Pagination](pagination.md) — paging the filtered set.
|
|
149
|
+
- [Command palette](command-palette.md) — global actions and navigation, not
|
|
150
|
+
list filtering.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Settings
|
|
2
|
+
|
|
3
|
+
Configuration pages with predictable form layout and explicit save behavior.
|
|
4
|
+
Settings are preferences and product configuration — not entity CRUD for a
|
|
5
|
+
list of resources.
|
|
6
|
+
|
|
7
|
+
User story #31.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Let the person change durable product or workspace options with clear grouping,
|
|
12
|
+
immediate vs deferred persistence, and unambiguous save feedback.
|
|
13
|
+
|
|
14
|
+
## Component composition
|
|
15
|
+
|
|
16
|
+
| Region | Compose with | Role |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| Page framing | [PageHeader](../components/page-header.md) | "Settings" or section title; optional save actions when the page uses explicit save |
|
|
19
|
+
| Section nav | [Tabs](../components/tabs.md) or Sidebar sub-nav [Link](../components/link.md)s | Split General / Notifications / API, etc. |
|
|
20
|
+
| Groups | [Card](../components/card.md) | One settings group per Card |
|
|
21
|
+
| Text / choice fields | [FormField](../components/form-field.md) | [Label](../components/label.md) + [Input](../components/input.md) / [Select](../components/select.md) / [Textarea](../components/textarea.md) + [HelperText](../components/helper-text.md) + [ValidationMessage](../components/validation-message.md) |
|
|
22
|
+
| Booleans | [Switch](../components/switch.md) (immediate) or [Checkbox](../components/checkbox.md) inside FormField (part of a saved form) | Switch for single immediate preferences; Checkbox when the value submits with Save |
|
|
23
|
+
| Actions | [Button](../components/button.md) | Save (primary), Reset/Cancel (secondary) for explicit-save sections |
|
|
24
|
+
| Feedback | [Toast](../components/toast.md), [Alert](../components/alert.md), [ValidationMessage](../components/validation-message.md) | Saved confirmation; section errors; field errors |
|
|
25
|
+
| Shell | [Application shell](application-shell.md) | Authenticated framing |
|
|
26
|
+
|
|
27
|
+
Tokens: `--color-background` canvas, `--color-surface` Cards, `--color-border`
|
|
28
|
+
separators, `--color-foreground` / `--color-muted-foreground` copy,
|
|
29
|
+
`--color-primary` for current section/nav, `--color-focus` on controls.
|
|
30
|
+
|
|
31
|
+
## Flow
|
|
32
|
+
|
|
33
|
+
### Explicit save (default for multi-field sections)
|
|
34
|
+
|
|
35
|
+
1. Person opens Settings and optionally a section Tab.
|
|
36
|
+
2. Edits FormFields; Save stays disabled until dirty (recommended) or remains
|
|
37
|
+
available — pick one rule per product and keep it.
|
|
38
|
+
3. Save validates; ValidationMessage on fields; Alert for section-level
|
|
39
|
+
failures (what / why / now).
|
|
40
|
+
4. On success: Toast "Settings saved" (or equivalent); clear dirty state.
|
|
41
|
+
5. Leaving a dirty section prompts only when unsaved loss is material.
|
|
42
|
+
|
|
43
|
+
### Immediate Switch
|
|
44
|
+
|
|
45
|
+
1. Person toggles Switch.
|
|
46
|
+
2. Value persists immediately; failure reverts the Switch and shows Toast or
|
|
47
|
+
inline Alert with recovery.
|
|
48
|
+
3. Do not also require Save for that same boolean.
|
|
49
|
+
|
|
50
|
+
Do not mix both persistence models inside one Card without labeling which
|
|
51
|
+
controls save immediately.
|
|
52
|
+
|
|
53
|
+
## States
|
|
54
|
+
|
|
55
|
+
| State | Behavior |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| loading | Skeleton for known Card/field layout; keep section nav visible. |
|
|
58
|
+
| empty | Rare; if a section has no configurable options yet, short explanatory copy — not a collection EmptyState. |
|
|
59
|
+
| dirty | Visual cue that Save applies; warn on navigate-away when appropriate. |
|
|
60
|
+
| invalid | Field ValidationMessage; focus first error; preserve other values. |
|
|
61
|
+
| saving | Save Button loading; prevent duplicate submits. |
|
|
62
|
+
| error | Alert with what / why / now; values preserved; Switch failures revert. |
|
|
63
|
+
| success | Toast or quiet confirmation; do not block the page. |
|
|
64
|
+
|
|
65
|
+
## Layout sketch
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
69
|
+
│ PageHeader: Settings │
|
|
70
|
+
│ Tabs: [General] Notifications API │
|
|
71
|
+
├──────────────────────────────────────────────────────────────────────┤
|
|
72
|
+
│ Card: Workspace │
|
|
73
|
+
│ FormField Display name │
|
|
74
|
+
│ FormField Default region [Select] │
|
|
75
|
+
│ │
|
|
76
|
+
│ Card: Query defaults │
|
|
77
|
+
│ Switch Persist query history │
|
|
78
|
+
│ FormField Statement timeout │
|
|
79
|
+
│ │
|
|
80
|
+
│ [Reset] [Save changes] │
|
|
81
|
+
└──────────────────────────────────────────────────────────────────────┘
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## When to use
|
|
85
|
+
|
|
86
|
+
- Product, workspace, or user preference screens.
|
|
87
|
+
- Multi-section configuration that is not a resource list.
|
|
88
|
+
|
|
89
|
+
## When NOT to use
|
|
90
|
+
|
|
91
|
+
- Creating/editing listed resources (connections, users as entities) —
|
|
92
|
+
[CRUD](crud.md) + [List-detail](list-detail.md).
|
|
93
|
+
- One-off destructive operations — confirmation / destructive-action patterns.
|
|
94
|
+
|
|
95
|
+
## Related patterns
|
|
96
|
+
|
|
97
|
+
- [CRUD](crud.md) — entity forms vs preference forms.
|
|
98
|
+
- [Application shell](application-shell.md)
|
|
99
|
+
- [Login / authentication](login-authentication.md) — account recovery and
|
|
100
|
+
auth entry, not general settings.
|