@capra/core 1.13.0 → 1.14.1
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/dist/index.cjs +357 -76
- package/dist/index.d.cts +229 -56
- package/dist/index.d.mts +229 -56
- package/dist/index.mjs +355 -79
- package/dist/style.css +370 -148
- package/docs/core-alert--design.md +3 -3
- package/docs/core-autocompletefield--design.md +5 -5
- package/docs/core-badge--design.md +12 -4
- package/docs/core-badge--usage.md +7 -1
- package/docs/core-breadcrumbs--design.md +1 -1
- package/docs/core-button--design.md +7 -7
- package/docs/core-buttonlink--design.md +1 -1
- package/docs/core-card--design.md +4 -4
- package/docs/core-checkbox--design.md +2 -2
- package/docs/core-checkbox--usage.md +1 -0
- package/docs/core-collapse--design.md +2 -2
- package/docs/core-divider--design.md +1 -1
- package/docs/core-link--design.md +2 -2
- package/docs/core-selectfield--design.md +1 -1
- package/docs/core-table--design.md +17 -0
- package/docs/core-table--usage.md +198 -0
- package/docs/core-textinput--usage.md +1 -1
- package/docs/core-togglebuttongroup--design.md +89 -0
- package/docs/core-togglebuttongroup--usage.md +113 -0
- package/docs/foundation-page-templates--docs.md +15 -0
- package/docs/history-changelogs-capra-core--docs.md +29 -0
- package/docs/index.md +5 -0
- package/package.json +3 -3
|
@@ -105,6 +105,6 @@ Don't:
|
|
|
105
105
|
|
|
106
106
|
## Related components
|
|
107
107
|
|
|
108
|
-
* [Toast](
|
|
109
|
-
* [Pill](
|
|
110
|
-
* [Modal](
|
|
108
|
+
* [Toast](/llms/core-toast--design.txt) — For non-blocking, auto-dismissing notifications.
|
|
109
|
+
* [Pill](/llms/core-pill--design.txt) — For inline semantic status indicators without body copy.
|
|
110
|
+
* [Modal](/llms/core-modal--design.txt) — When the error or warning requires an immediate blocking decision.
|
|
@@ -39,7 +39,7 @@ space is limited.
|
|
|
39
39
|
|
|
40
40
|
## Layout and spacing
|
|
41
41
|
|
|
42
|
-
* Input renders identically to [TextField](
|
|
42
|
+
* Input renders identically to [TextField](/llms/core-textfield--design.txt).
|
|
43
43
|
* Suggestions are presented using a ListBox.
|
|
44
44
|
|
|
45
45
|
## Behavior
|
|
@@ -70,8 +70,8 @@ Do:
|
|
|
70
70
|
|
|
71
71
|
Don't:
|
|
72
72
|
|
|
73
|
-
* Don't use AutocompleteField for small mutually exclusive sets (about seven or fewer visible options) — use [RadioGroup](
|
|
74
|
-
* Don't use AutocompleteField for plain freeform text with no list validation — use [TextField](
|
|
73
|
+
* Don't use AutocompleteField for small mutually exclusive sets (about seven or fewer visible options) — use [RadioGroup](/llms/core-radiogroup--design.txt) or Select.
|
|
74
|
+
* Don't use AutocompleteField for plain freeform text with no list validation — use [TextField](/llms/core-textfield--design.txt).
|
|
75
75
|
* Don't require picking from the list while still allowing arbitrary text without explaining that behavior.
|
|
76
76
|
|
|
77
77
|
## Accessibility
|
|
@@ -87,5 +87,5 @@ Don't:
|
|
|
87
87
|
|
|
88
88
|
## Related components
|
|
89
89
|
|
|
90
|
-
* [TextField](
|
|
91
|
-
* [RadioGroup](
|
|
90
|
+
* [TextField](/llms/core-textfield--design.txt) — For freeform text without suggestions.
|
|
91
|
+
* [RadioGroup](/llms/core-radiogroup--design.txt) — For small mutually exclusive option sets.
|
|
@@ -16,6 +16,10 @@ Badges support `md` and `sm` sizes. Use `sm` when composing with smaller control
|
|
|
16
16
|
|
|
17
17
|
Use a dot to show notifications without a count.
|
|
18
18
|
|
|
19
|
+
### Decorative
|
|
20
|
+
|
|
21
|
+
Use `decorative` when the badge is purely visual and its meaning is already conveyed nearby, such as adjacent text. Decorative badges are removed from the accessibility tree and must not be combined with `aria-label` or `aria-labelledby`.
|
|
22
|
+
|
|
19
23
|
### Appearance
|
|
20
24
|
|
|
21
25
|
Badges can be colored based on their status. The `attention` appearance is the general purpose color used for numbered badges and does not necessarily communicate severity.
|
|
@@ -49,6 +53,7 @@ Do:
|
|
|
49
53
|
* Do cap displayed values at 99 with a "99+" label.
|
|
50
54
|
* Do use the dot variant for simple presence indicators.
|
|
51
55
|
* Do associate interactive anchors with badge count context using `aria-describedby`.
|
|
56
|
+
* Do use `decorative` when the badge is redundant with nearby text or another accessible name.
|
|
52
57
|
|
|
53
58
|
Don't:
|
|
54
59
|
|
|
@@ -57,12 +62,15 @@ Don't:
|
|
|
57
62
|
* Don't place Badge on non-interactive decorative elements.
|
|
58
63
|
* Don't use Badge colors as the only method to communicate status.
|
|
59
64
|
* Don't include badge count context in the anchor's `aria-label`.
|
|
65
|
+
* Don't combine `decorative` with `aria-label` or `aria-labelledby`.
|
|
60
66
|
|
|
61
67
|
## Accessibility
|
|
62
68
|
|
|
63
|
-
*
|
|
69
|
+
* Named badges require `aria-label` or `aria-labelledby` that describes the count or status (e.g., "76 unread").
|
|
70
|
+
* Counter badges use `role="status"` so naming attributes are valid and the visible count is not presentational. Dot badges use `role="img"` because they have no text.
|
|
71
|
+
* Use `decorative` when the badge is purely presentational and the meaning is already available to assistive technology. Decorative badges omit the role and accessible name and set `aria-hidden`. Do not combine `decorative` with `aria-label` or `aria-labelledby`.
|
|
64
72
|
* When composing with interactive controls such as `Button` or `IconButton`, set `aria-describedby` on the anchor to the badge's `id`. Keep the anchor's accessible name limited to the control action or label (e.g., "Messages"), not the badge content.
|
|
65
|
-
* Use `aria-live="polite"` on
|
|
73
|
+
* Counter badges are a polite live region via `role="status"`. Use `aria-live="polite"` on a parent only when you need to announce grouped updates beyond the badge itself.
|
|
66
74
|
|
|
67
75
|
## Content
|
|
68
76
|
|
|
@@ -71,5 +79,5 @@ Don't:
|
|
|
71
79
|
|
|
72
80
|
## Related components
|
|
73
81
|
|
|
74
|
-
* [Pill](
|
|
75
|
-
* [Tag](
|
|
82
|
+
* [Pill](/llms/core-pill--design.txt) — For semantic status labels.
|
|
83
|
+
* [Tag](/llms/core-tag--design.txt) — For removable text chips.
|
|
@@ -13,4 +13,10 @@ Badges display an indicator/counter on an associated component.
|
|
|
13
13
|
| `className` | `never` | No | `--` | Use `FORCE__className` instead. |
|
|
14
14
|
| `style` | `never` | No | `--` | Inline styles are not supported; use component props or `FORCE__className`. |
|
|
15
15
|
| `FORCE__className` | `string` | No | `--` | 🚨 This prop is meant to be an escape hatch. 🚨<br><br>If the desired style cannot be achieved using component props, use this as a last resort. The inner workings of Capra components are implementation details and this escape hatch gives one access to those implementation details. We cannot make any guarantees that styles will applied correctly across version updates. Please use it responsibly.<br><br>Add a CSS class to the component. |
|
|
16
|
-
| `aria-live` | `React.AriaAttributes['aria-live']` | No | `--` | `--` |
|
|
16
|
+
| `aria-live` | `React.AriaAttributes['aria-live']` | No | `--` | `--` |
|
|
17
|
+
|
|
18
|
+
## Accessibility
|
|
19
|
+
|
|
20
|
+
Named badges require `aria-label` or `aria-labelledby`. Counter badges expose `role="status"` so the visible count is not treated as presentational. Dot badges expose `role="img"` because they have no text.
|
|
21
|
+
|
|
22
|
+
Use `decorative` when the badge is purely presentational and the meaning is already conveyed nearby. Decorative badges omit the role and accessible name and set `aria-hidden`. Do not combine `decorative` with `aria-label` or `aria-labelledby`.
|
|
@@ -76,9 +76,9 @@ Do:
|
|
|
76
76
|
|
|
77
77
|
Don't:
|
|
78
78
|
|
|
79
|
-
* Don't use a Button for navigation to another page — use [Link](
|
|
80
|
-
* Don't use a Button for text-only inline navigation — use [Link](
|
|
81
|
-
* Don't use a Button for icon-only actions — use [IconButton](
|
|
79
|
+
* Don't use a Button for navigation to another page — use [Link](/llms/core-link--design.txt) or [Anchor](/llms/core-anchor--design.txt).
|
|
80
|
+
* Don't use a Button for text-only inline navigation — use [Link](/llms/core-link--design.txt).
|
|
81
|
+
* Don't use a Button for icon-only actions — use [IconButton](/llms/core-iconbutton--design.txt).
|
|
82
82
|
* Don't use two primary buttons side by side.
|
|
83
83
|
* Don't truncate button labels.
|
|
84
84
|
* Don't disable a button without explaining why (use `aria-disabled` with a tooltip).
|
|
@@ -86,12 +86,12 @@ Don't:
|
|
|
86
86
|
## Accessibility
|
|
87
87
|
|
|
88
88
|
* Always provide a visible text label; if the design requires a short label, add `aria-label` for context.
|
|
89
|
-
* For icon-only use cases, use [IconButton](
|
|
89
|
+
* For icon-only use cases, use [IconButton](/llms/core-iconbutton--design.txt) instead (which enforces an accessible label).
|
|
90
90
|
* Tab / Shift+Tab to focus. Enter or Space to activate.
|
|
91
91
|
* The pending state must be communicated to assistive technology (e.g., `aria-label="Saving..."` when `pending` is true).
|
|
92
92
|
|
|
93
93
|
## Related components
|
|
94
94
|
|
|
95
|
-
* [IconButton](
|
|
96
|
-
* [Link](
|
|
97
|
-
* [Modal](
|
|
95
|
+
* [IconButton](/llms/core-iconbutton--design.txt) — For icon-only actions.
|
|
96
|
+
* [Link](/llms/core-link--design.txt) — For inline text navigation.
|
|
97
|
+
* [Modal](/llms/core-modal--design.txt) — Buttons typically appear in modal footers for confirm/cancel patterns.
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Primary interactive element displaying text and supporting leading and trailing icons.
|
|
4
4
|
|
|
5
|
-
`ButtonLink` follows the design guidelines for [`Button`](
|
|
5
|
+
`ButtonLink` follows the design guidelines for [`Button`](/llms/core-button--design.txt) and uses [`Link`](/llms/core-link--design.txt) interally. Use it when you need a link styled as a button.
|
|
6
6
|
|
|
7
7
|
See those pages for more details on the properties and usage of `ButtonLink`.
|
|
@@ -69,7 +69,7 @@ Treat the card as a container: put links and buttons inside slots rather than ma
|
|
|
69
69
|
## Behavior
|
|
70
70
|
|
|
71
71
|
* Cards are static containers by default.
|
|
72
|
-
* If the entire card is interactive (e.g., a selectable card), use `role="button"` with keyboard support. Prefer [RadioTile](
|
|
72
|
+
* If the entire card is interactive (e.g., a selectable card), use `role="button"` with keyboard support. Prefer [RadioTile](/llms/core-radiotile--design.txt) for selection scenarios.
|
|
73
73
|
|
|
74
74
|
## Content
|
|
75
75
|
|
|
@@ -86,7 +86,7 @@ Do:
|
|
|
86
86
|
|
|
87
87
|
Don't:
|
|
88
88
|
|
|
89
|
-
* Don't make the entire card surface the only navigation affordance — put a [Link](
|
|
89
|
+
* Don't make the entire card surface the only navigation affordance — put a [Link](/llms/core-link--design.txt) or [Button](/llms/core-button--design.txt) inside the content.
|
|
90
90
|
* Don't use Card for tabular data — use a table.
|
|
91
91
|
|
|
92
92
|
## Accessibility
|
|
@@ -96,5 +96,5 @@ Don't:
|
|
|
96
96
|
|
|
97
97
|
## Related components
|
|
98
98
|
|
|
99
|
-
* [RadioTile](
|
|
100
|
-
* [Modal](
|
|
99
|
+
* [RadioTile](/llms/core-radiotile--design.txt) — For selectable card options.
|
|
100
|
+
* [Modal](/llms/core-modal--design.txt) — For focused overlay containers.
|
|
@@ -62,5 +62,5 @@ Don't:
|
|
|
62
62
|
|
|
63
63
|
## Related components
|
|
64
64
|
|
|
65
|
-
* [Switch](
|
|
66
|
-
* [RadioGroup](
|
|
65
|
+
* [Switch](/llms/core-switch--design.txt) — For immediate binary settings.
|
|
66
|
+
* [RadioGroup](/llms/core-radiogroup--design.txt) — For mutually exclusive selections.
|
|
@@ -8,6 +8,7 @@ Checkbox component for capturing boolean user input. Supports controlled and unc
|
|
|
8
8
|
| `checked` | `boolean` | No | `--` | Controlled checked state. Use with onChange for controlled component. |
|
|
9
9
|
| `defaultChecked` | `boolean` | No | `--` | Default checked state for uncontrolled component. |
|
|
10
10
|
| `children` | `string \| React.ReactNode` | No | `--` | The label for the checkbox. |
|
|
11
|
+
| `slot` | `string \| null` | No | `--` | Slot name for React Aria context wiring (e.g. "selection" in Table). |
|
|
11
12
|
| `className` | `never` | No | `--` | Use `FORCE__className` instead. |
|
|
12
13
|
| `style` | `never` | No | `--` | Inline styles are not supported; use component props or `FORCE__className`. |
|
|
13
14
|
| `FORCE__className` | `string` | No | `--` | 🚨 This prop is meant to be an escape hatch. 🚨<br><br>If the desired style cannot be achieved using component props, use this as a last resort. The inner workings of Capra components are implementation details and this escape hatch gives one access to those implementation details. We cannot make any guarantees that styles will applied correctly across version updates. Please use it responsibly.<br><br>Add a CSS class to the component. |
|
|
@@ -24,5 +24,5 @@ Use Collapse to structure readable content, separate regions, or group related i
|
|
|
24
24
|
|
|
25
25
|
## Related components
|
|
26
26
|
|
|
27
|
-
* [Card](
|
|
28
|
-
* [Divider](
|
|
27
|
+
* [Card](/llms/core-card--design.txt)
|
|
28
|
+
* [Divider](/llms/core-divider--design.txt)
|
|
@@ -54,5 +54,5 @@ Links inherit the standard focus indicator standard to all focusable elements.
|
|
|
54
54
|
|
|
55
55
|
## Related components
|
|
56
56
|
|
|
57
|
-
* [Button](
|
|
58
|
-
* [Anchor](
|
|
57
|
+
* [Button](/llms/core-button--design.txt)
|
|
58
|
+
* [Anchor](/llms/core-anchor--design.txt)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
1. **Label**: describes the field and carries the required marker when needed.
|
|
6
6
|
2. **Trigger**: matches Capra text-input sizing and state treatments.
|
|
7
7
|
3. **Popover**: contains the option list and optional search field.
|
|
8
|
-
4. **ListBox items**:
|
|
8
|
+
4. **ListBox items**: selected rows are marked with a checkmark in both single- and multiple-select modes.
|
|
9
9
|
5. **Sections**: optional grouped options with a non-selectable header label.
|
|
10
10
|
|
|
11
11
|
## Properties
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Core/Table - Design
|
|
2
|
+
|
|
3
|
+
A component for rendering tabular data
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
### Density
|
|
8
|
+
|
|
9
|
+
Tables have 3 different row sizes: `default`, `compact`, and `tight`.
|
|
10
|
+
|
|
11
|
+
### Appearance
|
|
12
|
+
|
|
13
|
+
Striped rows (aka: Zebra striping) provide contrast between rows by alternating the background color. This can be disabled with `appearance="flat"`.
|
|
14
|
+
|
|
15
|
+
### Loading
|
|
16
|
+
|
|
17
|
+
When tables are in a loading state the content is replaced with 5 rows of skeleton content that represents the general shape of the data.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Core/Table - Usage
|
|
2
|
+
|
|
3
|
+
A component for rendering tabular data
|
|
4
|
+
|
|
5
|
+
## Basic usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Table } from '@capra/core';
|
|
9
|
+
|
|
10
|
+
type User = {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const userColumns = defineColumns<User>([
|
|
16
|
+
{ id: 'name', label: 'Name', allowsSorting: true },
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
const users = [
|
|
20
|
+
{
|
|
21
|
+
id: 1,
|
|
22
|
+
name: 'Alice Johnson',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 2,
|
|
26
|
+
name: 'Bob Williams',
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
<Table
|
|
31
|
+
columns={userColumns}
|
|
32
|
+
visibleColumns={['name']}
|
|
33
|
+
items={users}
|
|
34
|
+
/>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Props
|
|
38
|
+
|
|
39
|
+
| Prop | Type | Required | Default | Description |
|
|
40
|
+
| --- | --- | --- | --- | --- |
|
|
41
|
+
| `items` | `ItemRecord[]` | Yes | `--` | The data to render as rows in the Table |
|
|
42
|
+
| `density` | `'default' \| 'compact' \| 'tight'` | No | 'default' | The density of the table, affects row height |
|
|
43
|
+
| `appearance` | `'zebra' \| 'flat'` | No | 'zebra' | Whether to apply zebra-striping to rows |
|
|
44
|
+
| `sortDescriptor` | `SortDescriptor` | No | `--` | Key and direction for sorting the Table |
|
|
45
|
+
| `onSortChange` | `(sortDescriptor: SortDescriptor) => void` | No | `--` | Callback function fired when a the sorting configuration is changed |
|
|
46
|
+
| `columns` | `ColumnConfig<ColumnKey, ItemRecord>[]` | Yes | `--` | The columns to render in the Table |
|
|
47
|
+
| `visibleColumns` | `ColumnKey[]` | Yes | `--` | Which columns should be visible |
|
|
48
|
+
| `isLoading` | `boolean` | No | false | Whether the table is in a loading state |
|
|
49
|
+
| `enableDragAndDrop` | `boolean` | No | false | Whether drag-and-dropping rows is enabled |
|
|
50
|
+
| `renderActionColumn` | `(item: ItemRecord) => React.ReactNode` | No | `--` | todo: is this prop needed? |
|
|
51
|
+
| `selectionMode` | `SelectionMode` | No | `--` | Mode of row selection<br>@default 'none' |
|
|
52
|
+
| `selectedKeys` | `Selection` | No | `--` | The currently selected keys (controlled) |
|
|
53
|
+
| `onSelectionChange` | `(keys: Selection) => void` | No | `--` | Callback fired when selection changes |
|
|
54
|
+
| `className` | `never` | No | `--` | Use `FORCE__className` instead. |
|
|
55
|
+
| `style` | `never` | No | `--` | Inline styles are not supported; use component props or `FORCE__className`. |
|
|
56
|
+
| `FORCE__className` | `string` | No | `--` | 🚨 This prop is meant to be an escape hatch. 🚨<br><br>If the desired style cannot be achieved using component props, use this as a last resort. The inner workings of Capra components are implementation details and this escape hatch gives one access to those implementation details. We cannot make any guarantees that styles will applied correctly across version updates. Please use it responsibly.<br><br>Add a CSS class to the component. |
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
### Sorting
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { Table } from '@capra/core';
|
|
64
|
+
|
|
65
|
+
const userColumns = defineColumns<User>([
|
|
66
|
+
{ id: 'name', label: 'Name', allowsSorting: true },
|
|
67
|
+
// ...
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
function SortableTable() {
|
|
71
|
+
const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor | undefined>({
|
|
72
|
+
column: 'name',
|
|
73
|
+
direction: 'ascending',
|
|
74
|
+
});
|
|
75
|
+
const sortedItems = useMemo(() => sortItems(items, sortDescriptor), [sortDescriptor, items]);
|
|
76
|
+
return (
|
|
77
|
+
<Table
|
|
78
|
+
{...props}
|
|
79
|
+
items={sortedItems}
|
|
80
|
+
sortDescriptor={sortDescriptor}
|
|
81
|
+
onSortChange={setSortDescriptor}
|
|
82
|
+
visibleColumns={reverseColumns ? visibleColumns.toReversed() : visibleColumns}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Selection
|
|
89
|
+
|
|
90
|
+
Use the `selectionMode` prop to enable `single` or `multiple` selection of rows.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Table
|
|
94
|
+
columns={userColumns}
|
|
95
|
+
visibleColumns={['name', 'email', 'balance', 'enabled', 'description', 'trend']}
|
|
96
|
+
items={sortedItems}
|
|
97
|
+
selectionMode="multiple"
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Filter toolbar
|
|
102
|
+
|
|
103
|
+
Use the `FilterToolbar` component to support filtering and/or bulk editing.
|
|
104
|
+
|
|
105
|
+
Note: `FilterToolbar` is only supported instances of `Table` with controlled selection.
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { FilterToolbar, Table } from '@capra/core';
|
|
109
|
+
|
|
110
|
+
function TableWithToolbar() {
|
|
111
|
+
const [filterString, setFilterString] = useState('');
|
|
112
|
+
const [selectedKeys, setSelectedKeys] = useState<Selection>(new Set());
|
|
113
|
+
const sortedItems = useMemo(() => sortItems(users, sortDescriptor), [sortDescriptor] );
|
|
114
|
+
const filteredItems = filterUsers(sortedItems, filterString)
|
|
115
|
+
const selectableCount = sortedItems.filter((item) => !item.isDisabled).length;
|
|
116
|
+
const selectedCount = selectedKeys === 'all' ? selectableCount : selectedKeys.size;
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<div style={{ display: 'flex', gap: '8px', flexDirection: 'column' }}>
|
|
120
|
+
<TableToolbar
|
|
121
|
+
filterInputProps={{
|
|
122
|
+
onChange: (value: string) => setFilterString(value)
|
|
123
|
+
}}
|
|
124
|
+
renderActions={() => (
|
|
125
|
+
<Button size="sm" variant="primary">Add user</Button>
|
|
126
|
+
)}
|
|
127
|
+
renderBulkEditText={() => (
|
|
128
|
+
<Text>
|
|
129
|
+
{selectedCount} of {sortedItems.length} users selected
|
|
130
|
+
</Text>
|
|
131
|
+
)}
|
|
132
|
+
renderBulkEditActions={() => (
|
|
133
|
+
<div style={{ display: 'flex', gap: '8px' }}>
|
|
134
|
+
<Button appearance="neutral" size="sm">
|
|
135
|
+
Delete
|
|
136
|
+
</Button>
|
|
137
|
+
<Button appearance="neutral" variant="tertiary" size="sm">
|
|
138
|
+
Cancel
|
|
139
|
+
</Button>
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
selectedKeys={selectedKeys}
|
|
143
|
+
/>
|
|
144
|
+
<Table
|
|
145
|
+
columns={userColumns}
|
|
146
|
+
visibleColumns={['name', 'email', 'balance']}
|
|
147
|
+
items={filteredItems}
|
|
148
|
+
selectionMode="multiple"
|
|
149
|
+
selectedKeys={selectedKeys}
|
|
150
|
+
onSelectionChange={setSelectedKeys}
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Custom cell rendering
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { Table } from '@capra/core';
|
|
161
|
+
|
|
162
|
+
type User = {
|
|
163
|
+
id: string;
|
|
164
|
+
name: string;
|
|
165
|
+
email: string;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const userColumns = defineColumns<User>([
|
|
169
|
+
{ id: 'name', label: 'Name', allowsSorting: true },
|
|
170
|
+
{
|
|
171
|
+
id: 'email',
|
|
172
|
+
label: 'Email',
|
|
173
|
+
allowsSorting: true,
|
|
174
|
+
render(value) {
|
|
175
|
+
return <Link href={`mailto:${value as string}`}>{value as string}</Link>;
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
])
|
|
179
|
+
|
|
180
|
+
const users = [
|
|
181
|
+
{
|
|
182
|
+
id: 1,
|
|
183
|
+
name: 'Alice Johnson',
|
|
184
|
+
email: 'alice@example.com',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: 2,
|
|
188
|
+
name: 'Bob Williams',
|
|
189
|
+
email: 'bob@example.com',
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
|
|
193
|
+
<Table
|
|
194
|
+
columns={userColumns}
|
|
195
|
+
visibleColumns={['name', 'email']}
|
|
196
|
+
items={users}
|
|
197
|
+
/>
|
|
198
|
+
```
|
|
@@ -4,7 +4,7 @@ TextInput component for single-line text entry. Backwards compatible with Ant De
|
|
|
4
4
|
|
|
5
5
|
:::warning[Internal only]
|
|
6
6
|
|
|
7
|
-
`TextInput` is not exported from the public `@capra/core` API. For single-line text entry in product code, use [`TextField`](
|
|
7
|
+
`TextInput` is not exported from the public `@capra/core` API. For single-line text entry in product code, use [`TextField`](/llms/core-textfield--design.txt).
|
|
8
8
|
|
|
9
9
|
:::
|
|
10
10
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Core/ToggleButtonGroup - Design
|
|
2
|
+
|
|
3
|
+
A group of toggle buttons for choosing one or more options from a set.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
Toggle button groups behave similarly to radio buttons, providing selection between multiple mutually exclusive options. They are also used to switch views, such as between list and grid view.
|
|
8
|
+
|
|
9
|
+
Toggle button groups affect section-level views and are not a replacement for tabs.
|
|
10
|
+
|
|
11
|
+
## Properties
|
|
12
|
+
|
|
13
|
+
### Size
|
|
14
|
+
|
|
15
|
+
The default size for toggle button groups is medium, which should be used in most cases. A small size is also available when the group appears inline with another component.
|
|
16
|
+
|
|
17
|
+
### Label
|
|
18
|
+
|
|
19
|
+
Labels should be short and succinct. For longer labels, consider a [Radio](/llms/core-radio--design.txt) or [SelectField](/llms/core-selectfield--design.txt).
|
|
20
|
+
|
|
21
|
+
### Icon
|
|
22
|
+
|
|
23
|
+
Icons may appear with a label as part of each button. All buttons within a group should have an icon, or none should.
|
|
24
|
+
|
|
25
|
+
## Behavior
|
|
26
|
+
|
|
27
|
+
### Control count
|
|
28
|
+
|
|
29
|
+
Toggle button groups can have between 2 and 4 buttons.
|
|
30
|
+
|
|
31
|
+
### View switching
|
|
32
|
+
|
|
33
|
+
Toggle button groups can be used to switch the view of data at the section level, such as between a list view and grid view.
|
|
34
|
+
|
|
35
|
+
Views should be presented in a consistent order:
|
|
36
|
+
|
|
37
|
+
* List
|
|
38
|
+
* Grid
|
|
39
|
+
* Graph / Chart
|
|
40
|
+
* Metrics
|
|
41
|
+
|
|
42
|
+
### Filtering
|
|
43
|
+
|
|
44
|
+
Toggle button groups can be used to filter data at the section level, such as a data range within a graph.
|
|
45
|
+
|
|
46
|
+
## Best practices
|
|
47
|
+
|
|
48
|
+
### Count
|
|
49
|
+
|
|
50
|
+
**Do**
|
|
51
|
+
|
|
52
|
+
Do consider a toggle button group if you have 2 to 4 succinct choices.
|
|
53
|
+
|
|
54
|
+
**Don't**
|
|
55
|
+
|
|
56
|
+
Don't use more than 4 buttons in a single group. Consider a [SelectField](/llms/core-selectfield--design.txt) if more than 4 choices are needed.
|
|
57
|
+
|
|
58
|
+
### Wording
|
|
59
|
+
|
|
60
|
+
**Do**
|
|
61
|
+
|
|
62
|
+
Do keep labels short.
|
|
63
|
+
|
|
64
|
+
**Don't**
|
|
65
|
+
|
|
66
|
+
Don't use long, multi-word labels.
|
|
67
|
+
|
|
68
|
+
### Consistent layout
|
|
69
|
+
|
|
70
|
+
**Do**
|
|
71
|
+
|
|
72
|
+
Do keep icons consistent and unchanged when a button becomes active.
|
|
73
|
+
|
|
74
|
+
**Don't**
|
|
75
|
+
|
|
76
|
+
Don't replace icons when in an active state.
|
|
77
|
+
|
|
78
|
+
## Accessibility
|
|
79
|
+
|
|
80
|
+
### Keyboard interaction
|
|
81
|
+
|
|
82
|
+
| Key | Function |
|
|
83
|
+
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `Tab`<br />`Shift + Tab` | Move focus into and out of the button group. When focus moves into a button group:<br />- if a button is checked, focus is set on the checked button;<br />- if no buttons are checked, focus is set on the first button in the group. |
|
|
85
|
+
| `Enter`<br />`Space` | Checks the focused button if not already selected. |
|
|
86
|
+
| `Right Arrow`<br />`Down Arrow` | Move focus to the next button in the group. |
|
|
87
|
+
| `Left Arrow`<br />`Up Arrow` | Move focus to the previous button in the group. |
|
|
88
|
+
|
|
89
|
+
Icon-only items require an `aria-label` because there is no visible text label. The group itself requires an `aria-label` (or `aria-labelledby`) so assistive technologies can identify the control set.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Core/ToggleButtonGroup - Usage
|
|
2
|
+
|
|
3
|
+
A group of toggle buttons for choosing one or more options from a set.
|
|
4
|
+
|
|
5
|
+
## Basic usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { useState } from 'react';
|
|
9
|
+
import { ToggleButtonGroup, type Key } from '@capra/core';
|
|
10
|
+
|
|
11
|
+
function Example() {
|
|
12
|
+
const [selectedKeys, setSelectedKeys] = useState<Set<Key>>(new Set(['day']));
|
|
13
|
+
return (
|
|
14
|
+
<ToggleButtonGroup
|
|
15
|
+
aria-label="Time period"
|
|
16
|
+
selectedKeys={selectedKeys}
|
|
17
|
+
onSelectionChange={setSelectedKeys}
|
|
18
|
+
items={[
|
|
19
|
+
{ key: 'day', text: 'Day' },
|
|
20
|
+
{ key: 'week', text: 'Week' },
|
|
21
|
+
{ key: 'month', text: 'Month' },
|
|
22
|
+
]}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
| Prop | Type | Required | Default | Description |
|
|
31
|
+
| --- | --- | --- | --- | --- |
|
|
32
|
+
| `items` | `ToggleButtonGroupItem[]` | Yes | `--` | Items to render as toggle buttons. |
|
|
33
|
+
| `size` | `Extract<ButtonSize, 'sm' \| 'md'>` | No | 'md' | Size forwarded to every rendered button. Defaults to `md`. |
|
|
34
|
+
| `disabled` | `boolean` | No | false | Whether the entire group is disabled. |
|
|
35
|
+
| `selectionMode` | `'single' \| 'multiple'` | No | 'single' | Whether single or multiple selection is enabled. Defaults to `single`. |
|
|
36
|
+
| `selectedKeys` | `Iterable<Key>` | No | `--` | Controlled selected keys. |
|
|
37
|
+
| `defaultSelectedKeys` | `Iterable<Key>` | No | `--` | Uncontrolled initial selected keys. |
|
|
38
|
+
| `onSelectionChange` | `(keys: Set<Key>) => void` | No | `--` | Handler called when the selection changes. |
|
|
39
|
+
| `disallowEmptySelection` | `boolean` | No | `--` | Whether the group must always have at least one selected item. |
|
|
40
|
+
| `className` | `never` | No | `--` | Use `FORCE__className` instead. |
|
|
41
|
+
| `style` | `never` | No | `--` | Inline styles are not supported; use component props or `FORCE__className`. |
|
|
42
|
+
| `FORCE__className` | `string` | No | `--` | 🚨 This prop is meant to be an escape hatch. 🚨<br><br>If the desired style cannot be achieved using component props, use this as a last resort. The inner workings of Capra components are implementation details and this escape hatch gives one access to those implementation details. We cannot make any guarantees that styles will applied correctly across version updates. Please use it responsibly.<br><br>Add a CSS class to the component. |
|
|
43
|
+
|
|
44
|
+
## Examples
|
|
45
|
+
|
|
46
|
+
### Icons
|
|
47
|
+
|
|
48
|
+
Buttons can display icons in addition to text, or replace text entirely.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<ToggleButtonGroup
|
|
52
|
+
aria-label="Time period"
|
|
53
|
+
items={[
|
|
54
|
+
{ key: 'align-left', text: 'Align left', icon: AlignLeft },
|
|
55
|
+
{ key: 'align-center', text: 'Align center', icon: AlignCenter },
|
|
56
|
+
{ key: 'align-right', text: 'Align right', icon: AlignRight },
|
|
57
|
+
]}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
When using icons only, `aria-label` is required.
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
<ToggleButtonGroup
|
|
64
|
+
aria-label="Time period"
|
|
65
|
+
items={[
|
|
66
|
+
{ key: 'align-left', icon: AlignLeft, 'aria-label': 'Align left' },
|
|
67
|
+
{ key: 'align-center', icon: AlignCenter, 'aria-label': 'Align center' },
|
|
68
|
+
{ key: 'align-right', icon: AlignRight, 'aria-label': 'Align right' },
|
|
69
|
+
]}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Multi-select
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
<ToggleButtonGroup
|
|
76
|
+
aria-label="Time period"
|
|
77
|
+
selectionMode="multiple"
|
|
78
|
+
items={[
|
|
79
|
+
{ key: 'day', text: 'Day' },
|
|
80
|
+
{ key: 'week', text: 'Week' },
|
|
81
|
+
{ key: 'month', text: 'Month' },
|
|
82
|
+
]}
|
|
83
|
+
/>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Disabled state
|
|
87
|
+
|
|
88
|
+
The entire `ToggleButtonGroup` can be disabled by setting the `disabled` prop.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<ToggleButtonGroup
|
|
92
|
+
aria-label="Time period"
|
|
93
|
+
disabled
|
|
94
|
+
items={[
|
|
95
|
+
{ key: 'day', text: 'Day' },
|
|
96
|
+
{ key: 'week', text: 'Week' },
|
|
97
|
+
{ key: 'month', text: 'Month' },
|
|
98
|
+
]}
|
|
99
|
+
/>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Alternatively, individual buttons can be disabled by setting the `disabled` prop on the individual item.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<ToggleButtonGroup
|
|
106
|
+
aria-label="Time period"
|
|
107
|
+
items={[
|
|
108
|
+
{ key: 'day', text: 'Day', disabled: true },
|
|
109
|
+
{ key: 'week', text: 'Week' },
|
|
110
|
+
{ key: 'month', text: 'Month' },
|
|
111
|
+
]}
|
|
112
|
+
/>
|
|
113
|
+
```
|