@kb.ui/react 0.11.0 → 0.12.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/README.md +79 -66
- package/dist/components/ConfirmAction/ConfirmAction.d.ts +42 -0
- package/dist/components/Dashboard/Dashboard.d.ts +17 -0
- package/dist/components/Form/Form.d.ts +19 -0
- package/dist/components/FormSection/FormSection.d.ts +26 -0
- package/dist/components/Gallery/Gallery.d.ts +26 -0
- package/dist/components/PageHeader/PageHeader.d.ts +27 -0
- package/dist/components/Panel/Panel.d.ts +3 -1
- package/dist/components/Settings/Settings.d.ts +11 -0
- package/dist/components/Skeleton/Skeleton.d.ts +8 -6
- package/dist/components/Stack/Stack.d.ts +15 -0
- package/dist/components/StatsRow/StatsRow.d.ts +33 -0
- package/dist/components/SupportingPane/SupportingPane.d.ts +15 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +718 -333
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/docs/components/Accordion.md +9 -9
- package/docs/components/Avatar.md +4 -4
- package/docs/components/Badge.md +4 -4
- package/docs/components/Button.md +8 -8
- package/docs/components/Callout.md +3 -3
- package/docs/components/Card.md +4 -4
- package/docs/components/Checkbox.md +5 -5
- package/docs/components/Code.md +2 -2
- package/docs/components/CodeBlock.md +7 -7
- package/docs/components/Collection.md +5 -5
- package/docs/components/CollectionList.md +6 -6
- package/docs/components/CollectionRow.md +11 -11
- package/docs/components/Combobox.md +3 -3
- package/docs/components/ConfirmAction.md +100 -0
- package/docs/components/Container.md +2 -2
- package/docs/components/CopyableText.md +9 -9
- package/docs/components/Dashboard.md +81 -0
- package/docs/components/DescriptionList.md +3 -3
- package/docs/components/Dialog.md +7 -7
- package/docs/components/Disclosure.md +4 -4
- package/docs/components/EmptyState.md +1 -1
- package/docs/components/ErrorSummary.md +5 -3
- package/docs/components/Fieldset.md +6 -6
- package/docs/components/FileInput.md +5 -5
- package/docs/components/Form.md +67 -0
- package/docs/components/FormActions.md +3 -3
- package/docs/components/FormSection.md +57 -0
- package/docs/components/Gallery.md +84 -0
- package/docs/components/Grid.md +13 -13
- package/docs/components/Heading.md +3 -3
- package/docs/components/Image.md +3 -3
- package/docs/components/Inline.md +3 -3
- package/docs/components/Input.md +3 -3
- package/docs/components/Link.md +2 -2
- package/docs/components/Menu.md +5 -5
- package/docs/components/MultiSelect.md +2 -2
- package/docs/components/NumberField.md +5 -5
- package/docs/components/PageHeader.md +68 -0
- package/docs/components/Panel.md +11 -3
- package/docs/components/Popover.md +9 -9
- package/docs/components/Progress.md +1 -1
- package/docs/components/RadioGroup.md +3 -3
- package/docs/components/ScrollArea.md +1 -1
- package/docs/components/Select.md +2 -2
- package/docs/components/Separator.md +3 -3
- package/docs/components/Settings.md +57 -0
- package/docs/components/Skeleton.md +56 -16
- package/docs/components/Spinner.md +9 -4
- package/docs/components/Split.md +4 -4
- package/docs/components/Stack.md +54 -0
- package/docs/components/Stat.md +1 -1
- package/docs/components/StatsRow.md +80 -0
- package/docs/components/Status.md +7 -6
- package/docs/components/SupportingPane.md +59 -0
- package/docs/components/Switch.md +5 -5
- package/docs/components/Table.md +12 -12
- package/docs/components/Tabs.md +10 -10
- package/docs/components/Text.md +2 -2
- package/docs/components/Textarea.md +4 -4
- package/docs/components/Thumbnail.md +7 -7
- package/docs/components/Toast.md +9 -9
- package/docs/components/Toolbar.md +4 -4
- package/docs/components/Tooltip.md +3 -3
- package/package.json +1 -1
|
@@ -23,7 +23,7 @@ export function Example() {
|
|
|
23
23
|
|
|
24
24
|
`value` is the clipboard source. Case, whitespace, Unicode and trailing newlines are preserved. `children` can format the collapsed display independently; expanding or a copy failure reveals the exact value for inspection and manual copying. Do not use this component to conceal secrets.
|
|
25
25
|
|
|
26
|
-
The native button retains focus while a write is pending. Repeated activation during that write does nothing. Success appears only after the Clipboard API resolves; its callback receives the copied value. If value changes, the component is disabled, or it unmounts, outstanding writes cannot update feedback or fire callbacks. A write already sent to the operating system cannot be cancelled.
|
|
26
|
+
The native `button` retains focus while a write is pending. Repeated activation during that write does nothing. Success appears only after the Clipboard API resolves; its callback receives the copied value. If value changes, the component is disabled, or it unmounts, outstanding writes cannot update feedback or fire callbacks. A write already sent to the operating system cannot be cancelled.
|
|
27
27
|
|
|
28
28
|
A visible failure message remains until retry or content change. Users can select the full value and copy manually. Clipboard writes require a secure context such as HTTPS or localhost; browser permission, user activation, iframe policy or host restrictions can still reject them. No legacy clipboard fallback is attempted.
|
|
29
29
|
|
|
@@ -33,11 +33,11 @@ Set `tone` to color the value and softly tint field appearance. Neutral is the d
|
|
|
33
33
|
|
|
34
34
|
Set `highlight` to a string or array of literal, case-sensitive terms. Matches use semantic `mark` elements with bold emphasis; the longest match wins when terms overlap at the same position. Matching never interprets HTML or regular expressions and never changes copied content.
|
|
35
35
|
|
|
36
|
-
Automatic `format="auto"` recognizes HTTP(S) and `www.` URLs, qualified ASCII email addresses, backtick-delimited inline code, fenced code, valid JSON objects/arrays, and conservative JavaScript/TypeScript, CSS, HTML and common package-manager/Git/curl command patterns. Code receives the existing syntax colors and suppresses navigation inside source. Delimiters, whitespace and clipboard bytes remain literal.
|
|
36
|
+
Automatic `format="auto"` recognizes HTTP(S) and `www.` URLs, qualified ASCII email addresses, backtick-delimited inline code, fenced code, valid JSON objects/arrays, and conservative JavaScript/TypeScript, CSS, HTML and common package-manager/Git/curl command patterns. `Code` receives the existing syntax colors and suppresses navigation inside source. Delimiters, whitespace and clipboard bytes remain literal.
|
|
37
37
|
|
|
38
|
-
Use `format="text"` for identifiers or prose that resemble code, or `format="code"` with `language` for explicit source. A language hint forces code in automatic mode. Detection is intentionally conservative; it does not validate email deliverability or infer every programming language. Unknown fenced languages render as plain code. For large listings, prefer CodeBlock
|
|
38
|
+
Use `format="text"` for identifiers or prose that resemble code, or `format="code"` with `language` for explicit source. A language hint forces code in automatic mode. Detection is intentionally conservative; it does not validate email deliverability or infer every programming language. Unknown fenced languages render as plain code. For large listings, prefer `CodeBlock`.
|
|
39
39
|
|
|
40
|
-
Detected links reuse Link styling and Link.Provider
|
|
40
|
+
Detected links reuse `Link` styling and `Link.Provider`. Emails use mailto destinations with an encoded address; web links remain underlined native anchors. Sentence punctuation and unmatched closing brackets stay outside anchors. Set `linkify={false}` to disable detected links, or `linkify` with `format="text"` to opt back into links without code detection. Authored children retain caller-owned `Link`, strong, em or `Code` composition; automatic formatting applies to displayed raw source.
|
|
41
41
|
|
|
42
42
|
In truncated previews, detected links become interactive only after expansion. This keeps clipped links out of Tab order. After expanding, Shift+Tab reaches links above the disclosure; Tab continues to Copy. Copying remains a separate action. Errors expand the same formatted raw source for manual selection. `mono={false}` gives prose the proportional font and body line spacing.
|
|
43
43
|
|
|
@@ -65,8 +65,8 @@ In truncated previews, detected links become interactive only after expansion. T
|
|
|
65
65
|
| `mono` | `boolean` | `true` | Monospace value display |
|
|
66
66
|
| `tone` | `CopyableTextTone` | `"neutral"` | `neutral`, `accent`, `info`, `success`, `warning` or `danger`; independent of copy state |
|
|
67
67
|
| `truncate` | `boolean` | `false` | Single-line preview with explicit full-value disclosure |
|
|
68
|
-
| `expandLabel` | `string` | `"Show full value"` | Disclosure text when collapsed |
|
|
69
|
-
| `collapseLabel` | `string` | `"Show less"` | Disclosure text when expanded |
|
|
68
|
+
| `expandLabel` | `string` | `"Show full value"` | `Disclosure` text when collapsed |
|
|
69
|
+
| `collapseLabel` | `string` | `"Show less"` | `Disclosure` text when expanded |
|
|
70
70
|
| `disabled` | `boolean` | `false` | Disables copying, retains selectable value |
|
|
71
71
|
| `copyLabel` | `string` | `"Copy"` | Visible action and accessible name; use specific purpose |
|
|
72
72
|
| `copyingLabel` | `string` | `"Copying…"` | Pending label and polite announcement |
|
|
@@ -79,15 +79,15 @@ In truncated previews, detected links become interactive only after expansion. T
|
|
|
79
79
|
| `onCopyError` | `(error: unknown) => void` | unset | Current write failed, including unavailable API |
|
|
80
80
|
| `highlight` | `string \| readonly string[]` | unset | Literal case-sensitive terms; empty terms ignored, longest overlapping match wins |
|
|
81
81
|
| `format` | `CopyableTextFormat` | `"auto"` | `auto`, `text`, or `code`; conservative recognition with explicit overrides |
|
|
82
|
-
| `language` | `CodeLanguage` | unset | Code hint; forces code in auto mode; text mode remains literal |
|
|
82
|
+
| `language` | `CodeLanguage` | unset | `Code` hint; forces code in auto mode; text mode remains literal |
|
|
83
83
|
| `linkify` | `boolean` | automatic | Override detected web/email links; false disables links; code ranges never become links |
|
|
84
84
|
| `classNames` | `Partial<Record<CopyableTextPart, string>>` | unset | `label`, `value`, `actions`, `toggle`, `copy`, `feedback`, `link`, `highlight`, `code` slots |
|
|
85
85
|
| `className`, `ref`, other props | Native `span` props | unset | Root element; native `onCopy` replaced by success callback |
|
|
86
86
|
|
|
87
87
|
The root exposes `data-copy-state="idle|pending|copied|failed"`, appearance, size, tone, mono, expandable, expanded, truncate and disabled attributes. Pending sets `aria-disabled` on the button while preserving focus. The status region exists before interaction and is empty initially. Failure is both visible and announced; success has a visible button label and polite announcement.
|
|
88
88
|
|
|
89
|
-
Use `--kb-copyabletext-highlight-background` for marked text and Link tokens for navigation styling. Standalone CSS users also load `link.css` and `code.css` for detected links and syntax styling. Use `--kb-copyabletext-*` tokens for gap, padding, radius, border, background, neutral value color, target size and minimum copy width. `className` styles the root; `classNames` styles individual parts. Verify contrast and target sizes after overrides. Automated tests cover component behavior, browser keyboard activation and accessibility scans; screen-reader announcement quality remains a human verification task.
|
|
89
|
+
Use `--kb-copyabletext-highlight-background` for marked text and `Link` tokens for navigation styling. Standalone CSS users also load `link.css` and `code.css` for detected links and syntax styling. Use `--kb-copyabletext-*` tokens for gap, padding, radius, border, background, neutral value color, target size and minimum copy width. `className` styles the root; `classNames` styles individual parts. Verify contrast and target sizes after overrides. Automated tests cover component behavior, browser keyboard activation and accessibility scans; screen-reader announcement quality remains a human verification task.
|
|
90
90
|
|
|
91
91
|
## Related components
|
|
92
92
|
|
|
93
|
-
Use [CodeBlock](CodeBlock.md) for highlighted source and multiline commands, [Code](Code.md) for inline literals, and [Link](Link.md) for navigation. [Copyable content guidance](https://github.com/KhallilB/kbui/blob/main/docs/guides/copyable-content.md) covers shared recovery and localization.
|
|
93
|
+
Use [`CodeBlock`](CodeBlock.md) for highlighted source and multiline commands, [`Code`](Code.md) for inline literals, and [`Link`](Link.md) for navigation. [Copyable content guidance](https://github.com/KhallilB/kbui/blob/main/docs/guides/copyable-content.md) covers shared recovery and localization.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Dashboard
|
|
2
|
+
|
|
3
|
+
Use `Dashboard` for an overview page: a header, a row of headline metrics, then primary and secondary panels. Primary and secondary sit side by side, two thirds and one third, once the panels region is 60rem wide, and stack with primary first below that. `Dashboard` is also the page frame: it fills the width up to 80rem with 1, 1.5 or 2rem gutters, so it does not need a [`Container`](Container.md). For a main column with one supporting aside, such as an order summary, use [`Split`](Split.md).
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/layout-dashboard--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Card, Dashboard, Grid, PageHeader, Panel, Progress, Stat, Status } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<main>
|
|
16
|
+
<Dashboard
|
|
17
|
+
header={
|
|
18
|
+
<PageHeader
|
|
19
|
+
title="Sales dashboard"
|
|
20
|
+
description="Performance overview for your online store."
|
|
21
|
+
meta={<Status tone="success">Updated 5 minutes ago</Status>}
|
|
22
|
+
/>
|
|
23
|
+
}
|
|
24
|
+
metrics={
|
|
25
|
+
<Grid as="ul" aria-label="Key metrics" minItemWidth="sm" gap="md">
|
|
26
|
+
<Card as="li">
|
|
27
|
+
<Stat label="Total revenue" value="$128,450" />
|
|
28
|
+
</Card>
|
|
29
|
+
<Card as="li">
|
|
30
|
+
<Stat label="Orders" value="2,184" />
|
|
31
|
+
</Card>
|
|
32
|
+
</Grid>
|
|
33
|
+
}
|
|
34
|
+
primary={
|
|
35
|
+
<Panel aria-labelledby="channels-title">
|
|
36
|
+
<Panel.Header>
|
|
37
|
+
<h2 id="channels-title">Revenue by channel</h2>
|
|
38
|
+
</Panel.Header>
|
|
39
|
+
<Panel.Body>Organic search brought in 36% of revenue.</Panel.Body>
|
|
40
|
+
</Panel>
|
|
41
|
+
}
|
|
42
|
+
secondary={
|
|
43
|
+
<Panel aria-labelledby="goals-title">
|
|
44
|
+
<Panel.Header>
|
|
45
|
+
<h2 id="goals-title">Monthly goals</h2>
|
|
46
|
+
</Panel.Header>
|
|
47
|
+
<Panel.Body>
|
|
48
|
+
<Progress label="Revenue" value={86} valueText="$128k of $150k" />
|
|
49
|
+
</Panel.Body>
|
|
50
|
+
</Panel>
|
|
51
|
+
}
|
|
52
|
+
/>
|
|
53
|
+
</main>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## More examples
|
|
59
|
+
|
|
60
|
+
- [Sales overview](https://kbui.kcb.pro/storybook/?path=/story/layout-dashboard--sales-overview): A store dashboard with a date range, four metrics, channel revenue and top products beside monthly goals.
|
|
61
|
+
- [Metrics and primary](https://kbui.kcb.pro/storybook/?path=/story/layout-dashboard--metrics-and-primary): Without secondary panels, the primary region fills the page.
|
|
62
|
+
|
|
63
|
+
## Reference
|
|
64
|
+
|
|
65
|
+
| Prop | Type | Default | Notes |
|
|
66
|
+
| --- | --- | --- | --- |
|
|
67
|
+
| `header` | `ReactNode` | unset | Page title, freshness and page actions; usually a `PageHeader` |
|
|
68
|
+
| `metrics` | `ReactNode` | unset | Row of headline metrics below the header |
|
|
69
|
+
| `primary` | `ReactNode` | unset | Main panels; two thirds of the row on wide pages |
|
|
70
|
+
| `secondary` | `ReactNode` | unset | Supporting panels; one third on wide pages, below primary on narrow ones |
|
|
71
|
+
| `classNames` | `{ header?, metrics?, panels?, primary?, secondary? }` | unset | Classes for the regions |
|
|
72
|
+
|
|
73
|
+
Other native `div` props and `ref` pass through. Regions render in the order above and only when they have content; with only one of primary or secondary, it fills the row. Each panel region stacks its children with the dashboard gap.
|
|
74
|
+
|
|
75
|
+
Gutters follow the width of the dashboard's parent: 1rem below 48rem, 1.5rem from 48rem and 2rem from 64rem. As a direct flex item, such as beside a sidebar, the parent is the whole row, so wrap `Dashboard` in its own block, such as `main`. Tokens: `--kb-dashboard-gap`, `--kb-dashboard-max-width`, `--kb-dashboard-gutter-sm`, `-md`, `-lg`, `--kb-dashboard-gutter-md-from`, `--kb-dashboard-gutter-lg-from` and `--kb-dashboard-collapse`.
|
|
76
|
+
|
|
77
|
+
Give the page one `h1`, usually `PageHeader`'s title, and name each panel with its `h2`. Label the metrics list, and show when the data was last updated, or that it is partial, as text in the header. Your app owns data loading, date ranges and refresh.
|
|
78
|
+
|
|
79
|
+
## Related components
|
|
80
|
+
|
|
81
|
+
Use [`PageHeader`](PageHeader.md) for the header, [`Stat`](Stat.md) in a [`Grid`](Grid.md) for metrics and [`Panel`](Panel.md) for each panel.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DescriptionList
|
|
2
2
|
|
|
3
|
-
Present named facts about one record with native description-list relationships. Use Table when readers need to compare the same fields across records.
|
|
3
|
+
Present named facts about one record with native description-list relationships. Use `Table` when readers need to compare the same fields across records.
|
|
4
4
|
|
|
5
5
|
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-descriptionlist--docs)
|
|
6
6
|
|
|
@@ -52,10 +52,10 @@ export function Example() {
|
|
|
52
52
|
|
|
53
53
|
Every part accepts its native attributes, `className`, `style` and ref. Types are `DescriptionListProps`, `DescriptionListItemProps`, `DescriptionListTermProps` and `DescriptionListDetailProps`. Use a real `dt` before its `dd` values; the description list does not become a table or listbox. Group alternate names inside one Term when they share values. Native IDs and `aria-labelledby` remain available for richer relationships.
|
|
54
54
|
|
|
55
|
-
Values align to the same column across Items. Long labels, identifiers and composed Status text wrap, including chips with decorative icons; native links and controls retain their keyboard behavior. Use a deliberate stacked layout for narrow details, or override `--kb-descriptionlist-term-width` when the default 12rem label cap does not fit your labels. Other tokens control column/row gaps and comfortable/dense block padding. Nested lists keep their own layout and density.
|
|
55
|
+
Values align to the same column across Items. Long labels, identifiers and composed `Status` text wrap, including chips with decorative icons; native links and controls retain their keyboard behavior. Use a deliberate stacked layout for narrow details, or override `--kb-descriptionlist-term-width` when the default 12rem label cap does not fit your labels. Other tokens control column/row gaps and comfortable/dense block padding. Nested lists keep their own layout and density.
|
|
56
56
|
|
|
57
57
|
Keep zero values visible. Write a meaningful unavailable value such as Not scheduled rather than silently omitting a required fact. Your app owns formatting, units, timezone, localization, loading, errors and announcements. Do not use term text as an input label; controls still need their own labels and relationships. A description list supplies native relationships, not interactive field validation.
|
|
58
58
|
|
|
59
59
|
## Related components
|
|
60
60
|
|
|
61
|
-
Use [Table](Table.md) for comparing fields across records, [CollectionRow](CollectionRow.md) for summarizing records with actions, and [Status](Status.md) for an explicit state. See [Structured data](../../../../docs/guides/structured-data.md) for choosing and composing these patterns.
|
|
61
|
+
Use [`Table`](Table.md) for comparing fields across records, [`CollectionRow`](CollectionRow.md) for summarizing records with actions, and [`Status`](Status.md) for an explicit state. See [Structured data](../../../../docs/guides/structured-data.md) for choosing and composing these patterns.
|
|
@@ -49,11 +49,11 @@ export function Example() {
|
|
|
49
49
|
|
|
50
50
|
| Prop on root or Content | Type | Default | Notes |
|
|
51
51
|
| ------------------------ | ---------------- | ------------- | ----------------------------------------------------------------------------- |
|
|
52
|
-
| `open` on Dialog | `boolean` | uncontrolled | Current visibility when your app controls the dialog |
|
|
53
|
-
| `defaultOpen` on Dialog | `boolean` | `false` | Initial visibility; avoid starting open in a reading surface |
|
|
54
|
-
| `onOpenChange` on Dialog | Base UI callback | unset | Receives the next visibility and change details |
|
|
55
|
-
| `title` on Content | `ReactNode` | unset | Visible title and accessible name; use Dialog.Title for custom markup instead |
|
|
56
|
-
| `description` on Content | `ReactNode` | unset | Supporting description; use Dialog.Description for custom markup instead |
|
|
52
|
+
| `open` on `Dialog` | `boolean` | uncontrolled | Current visibility when your app controls the dialog |
|
|
53
|
+
| `defaultOpen` on `Dialog` | `boolean` | `false` | Initial visibility; avoid starting open in a reading surface |
|
|
54
|
+
| `onOpenChange` on `Dialog` | Base UI callback | unset | Receives the next visibility and change details |
|
|
55
|
+
| `title` on Content | `ReactNode` | unset | Visible title and accessible name; use `Dialog.Title` for custom markup instead |
|
|
56
|
+
| `description` on Content | `ReactNode` | unset | Supporting description; use `Dialog.Description` for custom markup instead |
|
|
57
57
|
| `container` on Content | portal container | document body | Themed host for a nested dialog |
|
|
58
58
|
|
|
59
59
|
```tsx
|
|
@@ -71,7 +71,7 @@ export function Example() {
|
|
|
71
71
|
|
|
72
72
|
## Related components
|
|
73
73
|
|
|
74
|
-
Use [Menu](Menu.md) for a short action list and [Callout](Callout.md) for a message that belongs in the page.
|
|
74
|
+
Use [`ConfirmAction`](ConfirmAction.md) for a destructive action behind a confirmation, [`Menu`](Menu.md) for a short action list and [`Callout`](Callout.md) for a message that belongs in the page.
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
## Drawer and confirmation patterns
|
|
@@ -81,4 +81,4 @@ The [overlay guide](../../../../docs/guides/forms-and-overlays.md#drawer-pattern
|
|
|
81
81
|
- [Drawer](https://kbui.kcb.pro/storybook/?path=/story/components-dialog--drawer)
|
|
82
82
|
- [Failure and retry](https://kbui.kcb.pro/storybook/?path=/story/components-dialog--confirmation-recovery)
|
|
83
83
|
|
|
84
|
-
Use [Popover](Popover.md) for non-modal anchored controls and [Disclosure](Disclosure.md) for supporting details inline.
|
|
84
|
+
Use [`Popover`](Popover.md) for non-modal anchored controls and [`Disclosure`](Disclosure.md) for supporting details inline.
|
|
@@ -39,15 +39,15 @@ export function AdvancedSettings() {
|
|
|
39
39
|
| `Disclosure.Trigger` | Base UI Collapsible trigger props | `button` | Native Enter/Space activation and expanded/controls relationships. |
|
|
40
40
|
| `Disclosure.Panel` | Base UI Collapsible panel props | `div` | Contains optional details and controls. |
|
|
41
41
|
| `Panel.keepMounted` | `boolean` | `false` | Retains DOM and uncontrolled draft state while closed. |
|
|
42
|
-
| `Panel.hiddenUntilFound` | `boolean` | `false` | Uses browser find-in-page reveal where supported; overrides keepMounted
|
|
42
|
+
| `Panel.hiddenUntilFound` | `boolean` | `false` | Uses browser find-in-page reveal where supported; overrides `keepMounted`. |
|
|
43
43
|
| `className` / `render` / `ref` | Part-specific native props | — | Style, compose and reference each DOM part. Class names accept strings. |
|
|
44
44
|
|
|
45
|
-
Tab reaches the trigger; Enter and Space toggle it without moving focus into the panel. Collapsed controls leave the accessibility tree and Tab order. No arrow-key navigation or modal behavior is added. Put essential instructions and errors where they remain discoverable. Unmounted content loses uncontrolled state; use keepMounted or store values outside the panel. Browser find-in-page reveal depends on engine support and the caller accepting controlled state changes.
|
|
45
|
+
Tab reaches the trigger; Enter and Space toggle it without moving focus into the panel. Collapsed controls leave the accessibility tree and Tab order. No arrow-key navigation or modal behavior is added. Put essential instructions and errors where they remain discoverable. Unmounted content loses uncontrolled state; use `keepMounted` or store values outside the panel. Browser find-in-page reveal depends on engine support and the caller accepting controlled state changes.
|
|
46
46
|
|
|
47
47
|
Style `--kb-disclosure-padding`, `-radius`, `-background`, `-color`, `-border` and `-trigger-height`. Preserve visible focus, hidden semantics and disabled state when overriding styles.
|
|
48
48
|
|
|
49
|
-
Panels expand and collapse through measured height transitions; reversing mid-transition follows the latest toggle. Content grows naturally once expanded. `--kb-disclosure-motion-duration` and `-motion-easing` control panel and caret motion; reduced motion disables transitions. `.kb-disclosure-panel-content` owns inner padding, keeping the outer Panel measurable without clipping collapsed padding. Panel props, className
|
|
49
|
+
Panels expand and collapse through measured height transitions; reversing mid-transition follows the latest toggle. Content grows naturally once expanded. `--kb-disclosure-motion-duration` and `-motion-easing` control panel and caret motion; reduced motion disables transitions. `.kb-disclosure-panel-content` owns inner padding, keeping the outer `Panel` measurable without clipping collapsed padding. `Panel` props, `className`, render and ref still target the outer node.
|
|
50
50
|
|
|
51
51
|
## Related components
|
|
52
52
|
|
|
53
|
-
Use [Accordion](Accordion.md) for related sections with headings, [Panel](Panel.md) for a structured work surface, or [Popover](Popover.md) for anchored supporting controls. [Overlay guidance](../../../../docs/guides/forms-and-overlays.md) covers choosing disclosure, popovers and modal patterns.
|
|
53
|
+
Use [`Accordion`](Accordion.md) for related sections with headings, [`Panel`](Panel.md) for a structured work surface, or [`Popover`](Popover.md) for anchored supporting controls. [Overlay guidance](../../../../docs/guides/forms-and-overlays.md) covers choosing disclosure, popovers and modal patterns.
|
|
@@ -47,4 +47,4 @@ export function Example() {
|
|
|
47
47
|
|
|
48
48
|
## Related components
|
|
49
49
|
|
|
50
|
-
Use [Skeleton](Skeleton.md) while the collection is still loading, [Callout](Callout.md) for inline notices beside populated content, and [Toast](Toast.md) for transient action feedback.
|
|
50
|
+
Use [`Skeleton`](Skeleton.md) while the collection is still loading, [`Callout`](Callout.md) for inline notices beside populated content, and [`Toast`](Toast.md) for transient action feedback.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ErrorSummary
|
|
2
2
|
|
|
3
|
-
Place ErrorSummary at the top of a form when submission fails so people can see what went wrong and jump directly to each invalid field. When `items` is empty, nothing is rendered.
|
|
3
|
+
Place `ErrorSummary` at the top of a form when submission fails so people can see what went wrong and jump directly to each invalid field. When `items` is empty, nothing is rendered.
|
|
4
4
|
|
|
5
5
|
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-errorsummary--docs)
|
|
6
6
|
|
|
@@ -39,8 +39,10 @@ This example shows a failed-submission state. The Form recovery story below demo
|
|
|
39
39
|
| `onItemSelect` | `(href: string, event: MouseEvent<HTMLAnchorElement>) => void` | unset | Called when a recovery link is clicked |
|
|
40
40
|
| `classNames` | `ClassNames<"title" \| "description" \| "list" \| "item" \| "link">` | unset | Classes for inner parts |
|
|
41
41
|
|
|
42
|
-
ErrorSummary renders an alert region with `tabIndex={-1}` so your submit handler can focus it when validation fails. Clicking an `#id` link focuses the matching control or the first enabled control inside a referenced group. Pair ErrorSummary with inline `error` props on each invalid field.
|
|
42
|
+
`ErrorSummary` renders an alert region with `tabIndex={-1}` so your submit handler can focus it when validation fails. Clicking an `#id` link focuses the matching control or the first enabled control inside a referenced group. Pair `ErrorSummary` with inline `error` props on each invalid field.
|
|
43
|
+
|
|
44
|
+
Error links keep their list markers. The list's `gap` controls spacing between items without added prose margins.
|
|
43
45
|
|
|
44
46
|
## Related components
|
|
45
47
|
|
|
46
|
-
Keep inline errors on [Input](Input.md), [Textarea](Textarea.md), and other fields. Use [FormActions](FormActions.md) for the submit controls.
|
|
48
|
+
Keep inline errors on [`Input`](Input.md), [`Textarea`](Textarea.md), and other fields. Use [`FormActions`](FormActions.md) for the submit controls.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Fieldset
|
|
2
2
|
|
|
3
|
-
Use Fieldset to group related controls into a named form section using native `fieldset` and `legend` semantics. Setting `disabled` disables descendant form controls natively.
|
|
3
|
+
Use `Fieldset` to group related controls into a named form section using native `fieldset` and `legend` semantics. Setting `disabled` disables descendant form controls natively.
|
|
4
4
|
|
|
5
5
|
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-fieldset--docs)
|
|
6
6
|
|
|
@@ -28,15 +28,15 @@ export function Example() {
|
|
|
28
28
|
|
|
29
29
|
| Prop | Type | Default | Notes |
|
|
30
30
|
| ---------------- | -------------------------------------------------------------- | -------- | ------------------------------------------------------ |
|
|
31
|
-
| `legend` | `ReactNode` | required | Section heading rendered inside the native legend |
|
|
31
|
+
| `legend` | `ReactNode` | required | Section heading rendered inside the native `legend` |
|
|
32
32
|
| `visuallyHidden` | `boolean` | `false` | Hides the legend visually while keeping the group name |
|
|
33
|
-
| `description` | `ReactNode` | unset | Section help text linked through aria-describedby |
|
|
34
|
-
| `error` | `ReactNode` | unset | Group-level error linked through aria-describedby |
|
|
33
|
+
| `description` | `ReactNode` | unset | Section help text linked through `aria-describedby` |
|
|
34
|
+
| `error` | `ReactNode` | unset | Group-level error linked through `aria-describedby` |
|
|
35
35
|
| `disabled` | `boolean` | `false` | Disables all descendant controls in the fieldset |
|
|
36
36
|
| `classNames` | `ClassNames<"legend" \| "description" \| "fields" \| "error">` | unset | Classes for inner parts |
|
|
37
37
|
|
|
38
|
-
Other native fieldset props and `ref` pass through to the `<fieldset>` element. Use `--kb-fieldset-gap`, `--kb-fieldset-fields-gap`, and `--kb-fieldset-legend-size` to tune spacing and legend typography.
|
|
38
|
+
Other native `fieldset` props and `ref` pass through to the `<fieldset>` element. Use `--kb-fieldset-gap`, `--kb-fieldset-fields-gap`, and `--kb-fieldset-legend-size` to tune spacing and legend typography.
|
|
39
39
|
|
|
40
40
|
## Related components
|
|
41
41
|
|
|
42
|
-
Use [Textarea](Textarea.md) and [Input](Input.md) for answers, [ErrorSummary](ErrorSummary.md) for submission recovery, and [FormActions](FormActions.md) for the action row.
|
|
42
|
+
Use [`Textarea`](Textarea.md) and [`Input`](Input.md) for answers, [`ErrorSummary`](ErrorSummary.md) for submission recovery, and [`FormActions`](FormActions.md) for the action row.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# FileInput
|
|
2
2
|
|
|
3
|
-
Use FileInput to choose files, review the selected list, and remove items. Your app decides which files to accept, keeps the File objects, and handles uploads. See [Retained file selection](https://github.com/KhallilB/kbui/blob/main/docs/guides/file-inputs.md) for examples, keyboard behavior, and styling. Available since v0.6.0.
|
|
3
|
+
Use `FileInput` to choose files, review the selected list, and remove items. Your app decides which files to accept, keeps the `File` objects, and handles uploads. See [Retained file selection](https://github.com/KhallilB/kbui/blob/main/docs/guides/file-inputs.md) for examples, keyboard behavior, and styling. Available since v0.6.0.
|
|
4
4
|
|
|
5
5
|
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-fileinput--docs)
|
|
6
6
|
|
|
@@ -54,7 +54,7 @@ The example retains each original `File` alongside its display metadata. Your ap
|
|
|
54
54
|
| `onFiles` | `(files: File[]) => void` | required | Check the selection and update retained files in your app |
|
|
55
55
|
| `onRemove` | `(id: string) => void` | required | Request removal; update items to confirm it |
|
|
56
56
|
| `accept` | `string` | unset | Native picker hint, such as image/*; does not validate files |
|
|
57
|
-
| `multiple` | `boolean` | `true` | Allow multiple selection; use a singular chooseLabel for single mode |
|
|
57
|
+
| `multiple` | `boolean` | `true` | Allow multiple selection; use a singular `chooseLabel` for single mode |
|
|
58
58
|
| `disabled`, `readOnly` | `boolean` | `false` | Prevent edits while keeping the retained list visible |
|
|
59
59
|
| `description`, `error` | `string` | unset | Help or actionable rejection text associated with the field |
|
|
60
60
|
| `visuallyHidden` | `boolean` | `false` | Hide the visual label while preserving its accessible name |
|
|
@@ -64,11 +64,11 @@ The example retains each original `File` alongside its display metadata. Your ap
|
|
|
64
64
|
| `removedMessage` | `(item: FileInputItem) => string` | filename + removed. | Announcement after removal is confirmed |
|
|
65
65
|
| `selectionMessage` | `(count: number) => string` | count + files selected. | Announcement after native selection |
|
|
66
66
|
| `renderItem` | `(item: FileInputItem) => ReactNode` | name + description | Custom item content; keep visible file identity |
|
|
67
|
-
| `inputRef`, `triggerRef` | element refs | unset | Hidden native input and visible picker access |
|
|
67
|
+
| `inputRef`, `triggerRef` | element refs | unset | Hidden native `input` and visible picker access |
|
|
68
68
|
| `triggerClassName`, `listClassName`, `itemClassName` | `string` | unset | Classes for picker, retained list, and items |
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
Native `<div>` props, `ref` and `className` apply to the root. Root `aria-describedby` IDs follow the help and error IDs. Item button refs stay internal so removal can restore focus. Customize items through the item/content classes and `renderItem`; avoid changing individual item buttons. The `×` is decorative, and each removal button is named with the full filename.
|
|
71
71
|
|
|
72
72
|
## Related components
|
|
73
73
|
|
|
74
|
-
Use [Progress](Progress.md) to
|
|
74
|
+
Use [`Progress`](Progress.md) to show upload progress supplied by your app. File selection and uploading are separate steps.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Form
|
|
2
|
+
|
|
3
|
+
Use `Form` for one task with one submit action, such as checkout, booking or sign-up. It renders a native `form` with three regions in reading order: an optional header, the fields, and an actions row. Fill the regions and the arrangement comes with them: a readable maximum width, even spacing between sections, and actions that fill the row on narrow screens. For pages of independently saved sections, use [`Settings`](Settings.md).
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/layout-form--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Form, FormSection, Heading, Input } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Form
|
|
16
|
+
aria-labelledby="booking-title"
|
|
17
|
+
onSubmit={(event) => event.preventDefault()}
|
|
18
|
+
header={
|
|
19
|
+
<Heading level={1} id="booking-title">
|
|
20
|
+
Book a room
|
|
21
|
+
</Heading>
|
|
22
|
+
}
|
|
23
|
+
actions={
|
|
24
|
+
<>
|
|
25
|
+
<Button type="submit">Confirm booking</Button>
|
|
26
|
+
<Button type="button" variant="ghost">
|
|
27
|
+
Back to rooms
|
|
28
|
+
</Button>
|
|
29
|
+
</>
|
|
30
|
+
}
|
|
31
|
+
>
|
|
32
|
+
<FormSection title="Dates">
|
|
33
|
+
<Input label="Check-in" type="date" name="checkIn" />
|
|
34
|
+
<Input label="Check-out" type="date" name="checkOut" />
|
|
35
|
+
</FormSection>
|
|
36
|
+
<FormSection title="Guest">
|
|
37
|
+
<Input label="Full name" name="name" autoComplete="name" />
|
|
38
|
+
</FormSection>
|
|
39
|
+
</Form>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## More examples
|
|
45
|
+
|
|
46
|
+
- [Hotel booking](https://kbui.kcb.pro/storybook/?path=/story/layout-form--hotel-booking): Dates, room type and extras in three sections, then one confirm action.
|
|
47
|
+
- [Sign up](https://kbui.kcb.pro/storybook/?path=/story/layout-form--sign-up): A short form at the narrow width, with plain fields and no sections.
|
|
48
|
+
|
|
49
|
+
## Reference
|
|
50
|
+
|
|
51
|
+
| Prop | Type | Default | Notes |
|
|
52
|
+
| --- | --- | --- | --- |
|
|
53
|
+
| `header` | `ReactNode` | unset | Title and intro above the fields |
|
|
54
|
+
| `actions` | `ReactNode` | unset | Rendered in [`FormActions`](FormActions.md) with a divider; put the submit button first |
|
|
55
|
+
| `actionsAlign` | `"end" \| "start" \| "between"` | `"end"` | Alignment of the actions row at 30rem and wider |
|
|
56
|
+
| `width` | `"sm" \| "md" \| "full"` | `"md"` | Maximum inline size: 32rem, 40rem or none |
|
|
57
|
+
| `classNames` | `{ header?, body?, actions? }` | unset | Classes for the regions |
|
|
58
|
+
|
|
59
|
+
Other native form props and `ref` pass through. Children fill the body: [`FormSection`](FormSection.md) groups for longer tasks, or plain fields for short ones.
|
|
60
|
+
|
|
61
|
+
Below 30rem of row width, each button or link in the actions fills its own row in source order, so the submit button sits on top and every button is a full-width target. Tokens: `--kb-form-gap`, `--kb-form-width-sm` and `--kb-form-width-md`.
|
|
62
|
+
|
|
63
|
+
A form is a landmark only when it has a name; add `aria-label` or `aria-labelledby` when people should find it from the landmark list. Your app owns validation, [`ErrorSummary`](ErrorSummary.md) focus after a failed submit, pending state and success feedback.
|
|
64
|
+
|
|
65
|
+
## Related components
|
|
66
|
+
|
|
67
|
+
Use [`Settings`](Settings.md) for independently saved sections, [`FormSection`](FormSection.md) to group fields and [`Container`](Container.md) for the page boundary around the form.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# FormActions
|
|
2
2
|
|
|
3
|
-
Use FormActions at the bottom of a form or section to align submit, reset, and secondary buttons with consistent wrapping and spacing. Buttons stay in natural Tab order without toolbar arrow-key navigation.
|
|
3
|
+
Use `FormActions` at the bottom of a form or section to align submit, reset, and secondary buttons with consistent wrapping and spacing. Buttons stay in natural Tab order without toolbar arrow-key navigation.
|
|
4
4
|
|
|
5
5
|
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-formactions--docs)
|
|
6
6
|
|
|
@@ -38,8 +38,8 @@ export function Example() {
|
|
|
38
38
|
| `divider` | `boolean` | `false` | Adds a top border and spacing above the action row |
|
|
39
39
|
| `children` | `ReactNode` | unset | Form buttons in reading and Tab order |
|
|
40
40
|
|
|
41
|
-
Other native div props and `ref` pass through. Use `--kb-formactions-gap` and `--kb-formactions-padding-top` to adjust spacing.
|
|
41
|
+
Other native `div` props and `ref` pass through. Use `--kb-formactions-gap` and `--kb-formactions-padding-top` to adjust spacing.
|
|
42
42
|
|
|
43
43
|
## Related components
|
|
44
44
|
|
|
45
|
-
Use [Fieldset](Fieldset.md) for named groups and [ErrorSummary](ErrorSummary.md) for failed submission recovery. Use [Toolbar](Toolbar.md) when controls need arrow-key navigation.
|
|
45
|
+
Use [`Fieldset`](Fieldset.md) for named groups and [`ErrorSummary`](ErrorSummary.md) for failed submission recovery. Use [`Toolbar`](Toolbar.md) when controls need arrow-key navigation.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# FormSection
|
|
2
|
+
|
|
3
|
+
Use `FormSection` to group related fields under a section heading, with optional help, a section error and the section's own actions. It renders a native `fieldset` named by its heading, so screen reader users can browse sections by heading and hear the group name on entry. Use [`Form`](Form.md) or [`Settings`](Settings.md) to arrange several sections.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-formsection--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, FormSection, Input } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<form onSubmit={(event) => event.preventDefault()}>
|
|
16
|
+
<FormSection
|
|
17
|
+
title="Profile"
|
|
18
|
+
description="Shown to everyone in your workspace."
|
|
19
|
+
actions={<Button type="submit">Save profile</Button>}
|
|
20
|
+
>
|
|
21
|
+
<Input label="Display name" name="name" />
|
|
22
|
+
<Input label="Job title" name="title" />
|
|
23
|
+
</FormSection>
|
|
24
|
+
</form>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## More examples
|
|
30
|
+
|
|
31
|
+
- [Heading beside fields](https://kbui.kcb.pro/storybook/?path=/story/components-formsection--split-layout): `Split` layout, which stacks below 40rem of section width.
|
|
32
|
+
- [Section error](https://kbui.kcb.pro/storybook/?path=/story/components-formsection--section-error): A group-level error alongside a field error.
|
|
33
|
+
- [Pending save](https://kbui.kcb.pro/storybook/?path=/story/components-formsection--pending-save): Lock every field and action while a save is in flight.
|
|
34
|
+
|
|
35
|
+
## Reference
|
|
36
|
+
|
|
37
|
+
| Prop | Type | Default | Notes |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| `title` | `ReactNode` | required | Section heading; also names the group |
|
|
40
|
+
| `headingLevel` | `2 \| 3 \| 4 \| 5 \| 6` | `2` | Heading rank; follow the page outline |
|
|
41
|
+
| `description` | `ReactNode` | unset | Help text; added to the group's `aria-describedby` |
|
|
42
|
+
| `error` | `ReactNode` | unset | Section error; sets `data-invalid` and `aria-invalid` and describes the group |
|
|
43
|
+
| `actions` | `ReactNode` | unset | Buttons rendered in [`FormActions`](FormActions.md) after the fields |
|
|
44
|
+
| `actionsAlign` | `"start" \| "end" \| "between"` | `"end"` | Alignment of the actions row |
|
|
45
|
+
| `layout` | `"stack" \| "split"` | unset | Heading above or beside the fields; unset stacks, or splits inside `Settings` |
|
|
46
|
+
| `disabled` | `boolean` | `false` | Native fieldset disabling for every field and action |
|
|
47
|
+
| `classNames` | `{ header?, title?, description?, body?, fields?, error?, actions? }` | unset | Classes for inner parts |
|
|
48
|
+
|
|
49
|
+
Other native `fieldset` props and `ref` pass through. A caller `aria-describedby` follows the description and error ids, and a caller `aria-invalid` token such as `"spelling"` is kept. The section heading names the group with `aria-labelledby`, unless you pass `aria-label`: a native `legend` cannot sit in the split layout's first column.
|
|
50
|
+
|
|
51
|
+
`Split` layout puts the header in one third and the fields in two thirds when the section is at least `--kb-formsection-collapse` (40rem) wide, and stacks them below that. Actions sit last in the section body, end-aligned. Below 30rem of row width, each button or link in the actions fills its own row so targets stay wide on phones; other content, such as a spinner, keeps its size. Tokens: `--kb-formsection-gap`, `--kb-formsection-header-gap`, `--kb-formsection-fields-gap` and `--kb-formsection-collapse`.
|
|
52
|
+
|
|
53
|
+
Your app owns validation, saving and the announcement of saved or failed sections. While saving, pass `disabled` and `aria-busy`. Native disabling takes focus away from the pressed Save button, so move focus to a status message outside the section (`role="status"`, `tabIndex={-1}`) and report the result there.
|
|
54
|
+
|
|
55
|
+
## Related components
|
|
56
|
+
|
|
57
|
+
Use [`Fieldset`](Fieldset.md) for a question-style group with a legend inside a section, [`FormActions`](FormActions.md) for a form-wide action row and [`ErrorSummary`](ErrorSummary.md) for recovery after a failed submit.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Gallery
|
|
2
|
+
|
|
3
|
+
Use `Gallery` for a page of image-led items, such as a product catalog, a portfolio or a media library. It is the page frame, up to 80rem wide, with a header region, an optional filters region and the items as a list, with one to four columns as the gallery widens. For records you scan by text, use [`CollectionList`](CollectionList.md) or [`Table`](Table.md); for a handful of metrics or links, use [`Grid`](Grid.md).
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/layout-gallery--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Card, Gallery, Grid, Heading, Image, Input, PageHeader, Text } from "@kb.ui/react";
|
|
12
|
+
import { useState } from "react";
|
|
13
|
+
|
|
14
|
+
const products = [
|
|
15
|
+
{ id: "classic", name: "The Schu Classic", price: 89, src: "/schu-classic.jpg", alt: "Sage knit sneaker with a white sole" },
|
|
16
|
+
{ id: "trail", name: "The Schu Trail", price: 99, src: "/schu-trail.jpg", alt: "Charcoal knit sneaker with an amber sole" },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export function Example() {
|
|
20
|
+
const [query, setQuery] = useState("");
|
|
21
|
+
const visible = products.filter((product) => product.name.toLowerCase().includes(query.toLowerCase()));
|
|
22
|
+
return (
|
|
23
|
+
<main>
|
|
24
|
+
<Gallery
|
|
25
|
+
header={<PageHeader title="Sneakers" description="Our own model beside the brands you love." />}
|
|
26
|
+
filters={
|
|
27
|
+
<>
|
|
28
|
+
<Input label="Search" type="search" value={query} onChange={(event) => setQuery(event.currentTarget.value)} />
|
|
29
|
+
<Text role="status" size="sm" tone="muted">
|
|
30
|
+
{visible.length === 1 ? "1 sneaker" : `${visible.length} sneakers`}
|
|
31
|
+
</Text>
|
|
32
|
+
</>
|
|
33
|
+
}
|
|
34
|
+
itemsLabel="Sneakers"
|
|
35
|
+
empty={<Text>No sneakers match your search.</Text>}
|
|
36
|
+
>
|
|
37
|
+
{visible.map((product, index) => (
|
|
38
|
+
<Gallery.Item key={product.id} featured={index === 0}>
|
|
39
|
+
<Card aria-labelledby={`${product.id}-name`}>
|
|
40
|
+
<Grid layout="stack" gap="sm">
|
|
41
|
+
<Image src={product.src} alt={product.alt} ratio={index === 0 ? "wide" : "landscape"} loading="lazy" />
|
|
42
|
+
<Heading level={2} size="sm" id={`${product.id}-name`}>
|
|
43
|
+
{product.name}
|
|
44
|
+
</Heading>
|
|
45
|
+
<Text>${product.price}</Text>
|
|
46
|
+
<Button variant="secondary">
|
|
47
|
+
Add to cart<span className="kb-sr-only">, {product.name}</span>
|
|
48
|
+
</Button>
|
|
49
|
+
</Grid>
|
|
50
|
+
</Card>
|
|
51
|
+
</Gallery.Item>
|
|
52
|
+
))}
|
|
53
|
+
</Gallery>
|
|
54
|
+
</main>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## More examples
|
|
60
|
+
|
|
61
|
+
- [Product catalog](https://kbui.kcb.pro/storybook/?path=/story/layout-gallery--product-catalog): A sneaker shop that features its own model, with search, brand and sort filters.
|
|
62
|
+
- [No results](https://kbui.kcb.pro/storybook/?path=/story/layout-gallery--no-results): The empty region replaces the list until the filters are cleared.
|
|
63
|
+
- [Inspection](https://kbui.kcb.pro/storybook/?path=/story/layout-gallery--inspection): Square thumbnails that open a full, uncropped preview in a `Dialog`.
|
|
64
|
+
|
|
65
|
+
## Reference
|
|
66
|
+
|
|
67
|
+
| Part / prop | Type | Default | Notes |
|
|
68
|
+
| --- | --- | --- | --- |
|
|
69
|
+
| `header` | `ReactNode` | unset | Page title, intro and actions; usually a `PageHeader` |
|
|
70
|
+
| `filters` | `ReactNode` | unset | Search, filter and sort controls and a result count |
|
|
71
|
+
| `itemsLabel` | `string` | unset | Accessible name for the item list |
|
|
72
|
+
| `empty` | `ReactNode` | unset | Shown in place of the list when there are no items |
|
|
73
|
+
| `classNames` | `{ header?, filters?, items?, empty? }` | unset | Classes for the regions |
|
|
74
|
+
| `Gallery.Item` | native `li` props | `li` | One item; `featured` spans two columns once the list has two |
|
|
75
|
+
|
|
76
|
+
Other native `div` props and `ref` pass through to the root; `Gallery.Item` forwards its own. The items region is a [`Grid`](Grid.md) rendered as `ul`, so wrap every item in `Gallery.Item`.
|
|
77
|
+
|
|
78
|
+
Placement is fixed in the stylesheet and measured on the gallery's own width, not the viewport: one column below 30rem, two from 30rem, three from 48rem and four from 64rem. Filters share a row, each at least 12rem wide, and wrap below it. Item content stretches to the row height; spacing inside an item belongs to its content, such as a stacked `Grid`. Pass items directly or inside fragments: a component that renders no items still counts as one, so `empty` cannot replace the list. Put featured items first: the list keeps DOM order and does not backfill gaps. `Gallery` is also the page frame: it fills its parent up to 80rem, centred, with gutters of 1rem, then 1.5rem from 48rem and 2rem from 64rem of viewport width, so do not wrap it in a [`Container`](Container.md). Tokens: `--kb-gallery-max-width`, `--kb-gallery-gutter-sm`, `--kb-gallery-gutter-md`, `--kb-gallery-gutter-lg`, `--kb-gallery-gap`, `--kb-gallery-filters-gap` and `--kb-gallery-filter-min-width`.
|
|
79
|
+
|
|
80
|
+
Give every meaningful image an `alt` that says what differs between items, such as colour or material; repeat nothing the item heading already says. Name each item with its heading and include that name in item actions. Announce result counts after filtering with a status message, and when a recovery action such as "Clear filters" removes the empty region, move focus to the control it reset. Your app owns data, filtering, pagination and cart state.
|
|
81
|
+
|
|
82
|
+
## Related components
|
|
83
|
+
|
|
84
|
+
Frame media with [`Image`](Image.md) or [`Thumbnail`](Thumbnail.md), open the page with [`PageHeader`](PageHeader.md), show an empty result with [`EmptyState`](EmptyState.md) and inspect an item in a [`Dialog`](Dialog.md).
|
package/docs/components/Grid.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Grid
|
|
2
2
|
|
|
3
|
-
Arrange cards or other content in responsive columns, fixed column counts, or a single vertical stack. Grid uses ordinary CSS layout, without an ARIA grid role or special keyboard navigation, and resets native list markers and margins when rendered as `ul` or `ol`.
|
|
3
|
+
Arrange cards or other content in responsive columns, fixed column counts, or a single vertical stack. `Grid` uses ordinary CSS layout, without an ARIA grid role or special keyboard navigation, and resets native list markers and margins when rendered as `ul` or `ol`.
|
|
4
4
|
|
|
5
5
|
[All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/layout-grid--docs)
|
|
6
6
|
|
|
@@ -35,16 +35,16 @@ export function Example() {
|
|
|
35
35
|
|
|
36
36
|
## Reference
|
|
37
37
|
|
|
38
|
-
| Prop | Type | Default | Notes
|
|
39
|
-
| --------------------------- | --------------------------------------------------- | ---------------------- |
|
|
40
|
-
| `as` | `div` / `ul` / `ol` | `div` | Use ul or ol for a collection; children must then be list items
|
|
41
|
-
| `layout` | `auto` / `stack` | `auto` | Auto fits equal columns to available width; stack uses one column
|
|
42
|
-
| `columns` | `auto` / `1` / `2` / `3` / `4` | `auto` | Explicit equal column count (collapsing to 1
|
|
43
|
-
| `minItemWidth` | `sm` / `md` / `lg` | `md` | Minimum width (`14rem`, `18.75rem`, `24rem`) before automatic columns wrap
|
|
44
|
-
| `gap` | `none` / `sm` / `md` / `lg` | `lg` (`--kb-grid-gap`) | Space between columns and stacked rows
|
|
45
|
-
| `align` | `start` / `center` / `end` / `baseline` / `stretch` | `stretch` | Cross-axis alignment within each grid row
|
|
46
|
-
| `children` | `ReactNode` | unset | Content in document and keyboard order
|
|
47
|
-
| `className`, `style`, `ref` | native element props | unset | Style and reference the chosen container
|
|
38
|
+
| Prop | Type | Default | Notes |
|
|
39
|
+
| --------------------------- | --------------------------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| `as` | `div` / `ul` / `ol` | `div` | Use ul or ol for a collection; children must then be list items |
|
|
41
|
+
| `layout` | `auto` / `stack` | `auto` | Auto fits equal columns to available width; stack uses one column |
|
|
42
|
+
| `columns` | `auto` / `1` / `2` / `3` / `4` | `auto` | Explicit equal column count (collapsing to 1 when the grid is narrower than 30rem) or automatic wrapping |
|
|
43
|
+
| `minItemWidth` | `sm` / `md` / `lg` | `md` | Minimum width (`14rem`, `18.75rem`, `24rem`) before automatic columns wrap |
|
|
44
|
+
| `gap` | `none` / `sm` / `md` / `lg` | `lg` (`--kb-grid-gap`) | Space between columns and stacked rows |
|
|
45
|
+
| `align` | `start` / `center` / `end` / `baseline` / `stretch` | `stretch` | Cross-axis alignment within each grid row |
|
|
46
|
+
| `children` | `ReactNode` | unset | Content in document and keyboard order |
|
|
47
|
+
| `className`, `style`, `ref` | native element props | unset | Style and reference the chosen container |
|
|
48
48
|
|
|
49
49
|
```tsx
|
|
50
50
|
<Grid as="ul" role="list" layout="stack" gap="md" aria-label="Projects">
|
|
@@ -59,8 +59,8 @@ export function Example() {
|
|
|
59
59
|
|
|
60
60
|
Use `minItemWidth`, `columns`, `gap`, and `align` for common layouts, or override `--kb-grid-gap` and `--kb-grid-min-item-width` (`-sm`, `-md`, `-lg`) on a subtree. Keep the visual order the same as the reading order.
|
|
61
61
|
|
|
62
|
-
Grid removes list markers. Include `role="list"` on list renderings to retain list exposure in Safari when `list-style: none` is applied; see [MDN’s list-style accessibility guidance](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/list-style#accessibility). Confirm list/item announcement with your supported browser and screen reader.
|
|
62
|
+
`Grid` removes list markers. Include `role="list"` on list renderings to retain list exposure in Safari when `list-style: none` is applied; see [MDN’s list-style accessibility guidance](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/list-style#accessibility). Confirm list/item announcement with your supported browser and screen reader.
|
|
63
63
|
|
|
64
64
|
## Related components
|
|
65
65
|
|
|
66
|
-
Use [Split](Split.md) for exactly two weighted columns
|
|
66
|
+
Use [`Split`](Split.md) for exactly two weighted columns, [`Inline`](Inline.md) for a wrapping row of independent items, and [`Stack`](Stack.md) for vertical flow that never forms columns.
|