@cdx-ui/components 0.3.1 → 0.3.3
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 +2 -2
- package/coverage.svg +1 -1
- package/docs/components/bottom-sheet/content.md +2 -2
- package/docs/components/content.md +2 -0
- package/docs/components/currency-input/content.md +94 -5
- package/docs/components/data-grid/content.md +125 -1
- package/docs/components/insight/content.md +644 -0
- package/docs/components/insight-stack/content.md +231 -0
- package/docs/foundations/styles/tokens/all-tokens/content.md +23 -3
- package/docs/llms.txt +4 -0
- package/docs/patterns/forms/content.md +255 -0
- package/docs/resources/release-notes/0.3.1/content.md +13 -0
- package/docs/resources/release-notes/0.3.2/content.md +17 -0
- package/docs/resources/release-notes/content.md +2 -0
- package/lib/commonjs/components/BottomSheet/index.js +63 -16
- package/lib/commonjs/components/BottomSheet/index.js.map +1 -1
- package/lib/commonjs/components/CurrencyInput/index.js +35 -10
- package/lib/commonjs/components/CurrencyInput/index.js.map +1 -1
- package/lib/commonjs/components/CurrencyInput/styles.js +40 -3
- package/lib/commonjs/components/CurrencyInput/styles.js.map +1 -1
- package/lib/commonjs/components/Insight/index.js +438 -0
- package/lib/commonjs/components/Insight/index.js.map +1 -0
- package/lib/commonjs/components/Insight/insetRadius.js +35 -0
- package/lib/commonjs/components/Insight/insetRadius.js.map +1 -0
- package/lib/commonjs/components/Insight/styles.js +186 -0
- package/lib/commonjs/components/Insight/styles.js.map +1 -0
- package/lib/commonjs/components/InsightStack/index.js +93 -0
- package/lib/commonjs/components/InsightStack/index.js.map +1 -0
- package/lib/commonjs/components/InsightStack/styles.js +61 -0
- package/lib/commonjs/components/InsightStack/styles.js.map +1 -0
- package/lib/commonjs/components/index.js +24 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/figma/CurrencyInput.figma.js +8 -8
- package/lib/commonjs/figma/CurrencyInput.figma.js.map +1 -1
- package/lib/commonjs/figma/Insight.figma.js +73 -0
- package/lib/commonjs/figma/Insight.figma.js.map +1 -0
- package/lib/commonjs/figma/InsightStack.figma.js +39 -0
- package/lib/commonjs/figma/InsightStack.figma.js.map +1 -0
- package/lib/module/components/BottomSheet/index.js +64 -17
- package/lib/module/components/BottomSheet/index.js.map +1 -1
- package/lib/module/components/CurrencyInput/index.js +37 -12
- package/lib/module/components/CurrencyInput/index.js.map +1 -1
- package/lib/module/components/CurrencyInput/styles.js +38 -3
- package/lib/module/components/CurrencyInput/styles.js.map +1 -1
- package/lib/module/components/Insight/index.js +433 -0
- package/lib/module/components/Insight/index.js.map +1 -0
- package/lib/module/components/Insight/insetRadius.js +30 -0
- package/lib/module/components/Insight/insetRadius.js.map +1 -0
- package/lib/module/components/Insight/styles.js +183 -0
- package/lib/module/components/Insight/styles.js.map +1 -0
- package/lib/module/components/InsightStack/index.js +89 -0
- package/lib/module/components/InsightStack/index.js.map +1 -0
- package/lib/module/components/InsightStack/styles.js +58 -0
- package/lib/module/components/InsightStack/styles.js.map +1 -0
- package/lib/module/components/index.js +2 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/figma/CurrencyInput.figma.js +8 -8
- package/lib/module/figma/CurrencyInput.figma.js.map +1 -1
- package/lib/module/figma/Insight.figma.js +67 -0
- package/lib/module/figma/Insight.figma.js.map +1 -0
- package/lib/module/figma/InsightStack.figma.js +33 -0
- package/lib/module/figma/InsightStack.figma.js.map +1 -0
- package/lib/typescript/components/BottomSheet/index.d.ts.map +1 -1
- package/lib/typescript/components/CurrencyInput/index.d.ts +4 -1
- package/lib/typescript/components/CurrencyInput/index.d.ts.map +1 -1
- package/lib/typescript/components/CurrencyInput/styles.d.ts +17 -6
- package/lib/typescript/components/CurrencyInput/styles.d.ts.map +1 -1
- package/lib/typescript/components/Insight/index.d.ts +87 -0
- package/lib/typescript/components/Insight/index.d.ts.map +1 -0
- package/lib/typescript/components/Insight/insetRadius.d.ts +8 -0
- package/lib/typescript/components/Insight/insetRadius.d.ts.map +1 -0
- package/lib/typescript/components/Insight/styles.d.ts +33 -0
- package/lib/typescript/components/Insight/styles.d.ts.map +1 -0
- package/lib/typescript/components/InsightStack/index.d.ts +21 -0
- package/lib/typescript/components/InsightStack/index.d.ts.map +1 -0
- package/lib/typescript/components/InsightStack/styles.d.ts +11 -0
- package/lib/typescript/components/InsightStack/styles.d.ts.map +1 -0
- package/lib/typescript/components/index.d.ts +2 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/figma/CurrencyInput.figma.d.ts.map +1 -1
- package/lib/typescript/figma/Insight.figma.d.ts +8 -0
- package/lib/typescript/figma/Insight.figma.d.ts.map +1 -0
- package/lib/typescript/figma/InsightStack.figma.d.ts +8 -0
- package/lib/typescript/figma/InsightStack.figma.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/components/BottomSheet/index.tsx +88 -13
- package/src/components/CurrencyInput/index.tsx +36 -12
- package/src/components/CurrencyInput/styles.ts +51 -4
- package/src/components/Insight/index.tsx +531 -0
- package/src/components/Insight/insetRadius.ts +30 -0
- package/src/components/Insight/styles.ts +193 -0
- package/src/components/InsightStack/index.tsx +86 -0
- package/src/components/InsightStack/styles.ts +61 -0
- package/src/components/index.ts +2 -0
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ The [component reference](https://design.candescent.com/docs/components) is the
|
|
|
48
48
|
|
|
49
49
|
The package also ships that reference as markdown in `docs/`, matched to the installed version; coding agents should start at `AGENTS.md` in the package root.
|
|
50
50
|
|
|
51
|
-
> `Box`
|
|
51
|
+
> Use [`Box`](https://design.candescent.com/docs/components/box) for layout containers. The `View` re-export below is deprecated.
|
|
52
52
|
|
|
53
53
|
### Providers
|
|
54
54
|
|
|
@@ -91,7 +91,7 @@ For convenience, the package re-exports several core RN components and hooks wit
|
|
|
91
91
|
|
|
92
92
|
| Export | Source |
|
|
93
93
|
| ---------------------- | -------------------------------- |
|
|
94
|
-
| `View`
|
|
94
|
+
| `View` (deprecated) | `react-native` |
|
|
95
95
|
| `ScrollView` | `react-native` |
|
|
96
96
|
| `KeyboardAvoidingView` | `react-native` |
|
|
97
97
|
| `SafeAreaView` | `react-native-safe-area-context` |
|
package/coverage.svg
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="108" height="20" role="img" aria-label="coverage: 92.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="108" height="20" role="img" aria-label="coverage: 92.9%"><title>coverage: 92.9%</title><filter id="blur"><feGaussianBlur stdDeviation="16"/></filter><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="108" height="20" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="47" height="20" fill="#4b0"/><rect width="108" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="315" y="150" fill-opacity=".8" filter="url(#blur)" textLength="510">coverage</text><text x="315" y="150" fill-opacity=".3" textLength="510">coverage</text></g><text x="315" y="140" textLength="510">coverage</text></g><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="835" y="150" fill-opacity=".8" filter="url(#blur)" textLength="370">92.9%</text><text x="835" y="150" fill-opacity=".3" textLength="370">92.9%</text></g><text x="835" y="140" textLength="370">92.9%</text></g></g></svg>
|
|
@@ -310,11 +310,11 @@ Required once at the app root. Wraps the tree to enable modal presentation.
|
|
|
310
310
|
|
|
311
311
|
### BottomSheet.ScrollView
|
|
312
312
|
|
|
313
|
-
Scrollable content wrapper for sheets with long content. Enables footer margin adjustment by default.
|
|
313
|
+
Scrollable content wrapper for sheets with long content. Enables footer margin adjustment by default when the sheet has a footer.
|
|
314
314
|
|
|
315
315
|
### BottomSheet.View
|
|
316
316
|
|
|
317
|
-
Non-scrollable content wrapper for fit-to-content sheets. Enables footer margin adjustment by default.
|
|
317
|
+
Non-scrollable content wrapper for fit-to-content sheets. Enables footer margin adjustment by default when the sheet has a footer.
|
|
318
318
|
|
|
319
319
|
## Hook
|
|
320
320
|
|
|
@@ -82,6 +82,8 @@
|
|
|
82
82
|
- [Box](https://design.candescent.com/docs/components/box/content.md) — The layout container for building screens, with semantic web elements through role and an asChild escape hatch.
|
|
83
83
|
- [Card](https://design.candescent.com/docs/components/card/content.md) — A composable surface for grouping related content, with optional brand stripe, header, content, and footer regions.
|
|
84
84
|
- [Drawer](https://design.candescent.com/docs/components/drawer/content.md) — A panel attached to an edge of the viewport or container, with modal and permanent presentations.
|
|
85
|
+
- [Insight](https://design.candescent.com/docs/components/insight/content.md) — A bordered card for a personalised, often AI-generated, insight, shown as a pressable summary or a detail card.
|
|
86
|
+
- [Insight Stack](https://design.candescent.com/docs/components/insight-stack/content.md) — Draws decorative cards behind a summary Insight to show that more insights are waiting.
|
|
85
87
|
- [Scoped Theme](https://design.candescent.com/docs/components/scoped-theme/content.md) — Forces a specific theme on a component subtree, regardless of the application's global theme.
|
|
86
88
|
- [Scroll Shadow](https://design.candescent.com/docs/components/scroll-shadow/content.md) — Fades the edges of a scroll view so overflowing content reads as scrollable on iOS, Android, and web.
|
|
87
89
|
- [Stack](https://design.candescent.com/docs/components/stack/content.md) — Horizontal and vertical layout primitives with token-based spacing and optional reversed order.
|
|
@@ -23,9 +23,50 @@ export default function CurrencyInputBasicDemo() {
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Variants
|
|
27
|
+
|
|
28
|
+
Use the default `ghost` variant for a large, centered amount that is the focus of the screen. Use `outline` when the amount sits in a form next to other fields: it renders the same bordered shell as `Input`, with the currency symbol as a separate prefix.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { useState } from 'react';
|
|
32
|
+
import { Box, CurrencyInput, Text, type CurrencyInputProps } from '@cdx-ui/components';
|
|
33
|
+
|
|
34
|
+
const variants = ['ghost', 'outline'] as const satisfies readonly NonNullable<
|
|
35
|
+
CurrencyInputProps['variant']
|
|
36
|
+
>[];
|
|
37
|
+
|
|
38
|
+
function VariantRow({ variant }: { variant: NonNullable<CurrencyInputProps['variant']> }) {
|
|
39
|
+
const [amount, setAmount] = useState(4890);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Box className="gap-2">
|
|
43
|
+
<Text size="sm" color="secondary">
|
|
44
|
+
{variant}
|
|
45
|
+
</Text>
|
|
46
|
+
<CurrencyInput
|
|
47
|
+
accessibilityLabel={`${variant} transfer amount`}
|
|
48
|
+
variant={variant}
|
|
49
|
+
value={amount}
|
|
50
|
+
onChangeValue={setAmount}
|
|
51
|
+
/>
|
|
52
|
+
</Box>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default function CurrencyInputVariantsDemo() {
|
|
57
|
+
return (
|
|
58
|
+
<Box className="w-full gap-4">
|
|
59
|
+
{variants.map((variant) => (
|
|
60
|
+
<VariantRow key={variant} variant={variant} />
|
|
61
|
+
))}
|
|
62
|
+
</Box>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
26
67
|
## Sizes
|
|
27
68
|
|
|
28
|
-
Use `size="small"`
|
|
69
|
+
Use `size="small"` for a more compact amount. When the amount appears alongside other form fields, use `variant="outline"` instead so it matches them.
|
|
29
70
|
|
|
30
71
|
```tsx
|
|
31
72
|
import { useState } from 'react';
|
|
@@ -121,7 +162,26 @@ export default function CurrencyInputStatesDemo() {
|
|
|
121
162
|
|
|
122
163
|
## With field
|
|
123
164
|
|
|
124
|
-
Compose with `Field` to provide a visible label, helper text, and required state.
|
|
165
|
+
Compose with `Field` to provide a visible label, helper text, and required state. In a form, use `variant="outline"` with the label and helper aligned to the start, as with `Input`.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { useState } from 'react';
|
|
169
|
+
import { CurrencyInput, Field } from '@cdx-ui/components';
|
|
170
|
+
|
|
171
|
+
export default function CurrencyInputOutlineWithFieldDemo() {
|
|
172
|
+
const [amount, setAmount] = useState(0);
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<Field className="w-full" isRequired>
|
|
176
|
+
<Field.Label>Amount</Field.Label>
|
|
177
|
+
<CurrencyInput isRequired variant="outline" value={amount} onChangeValue={setAmount} />
|
|
178
|
+
<Field.Helper>Daily limit remaining: $1,200</Field.Helper>
|
|
179
|
+
</Field>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
For the `ghost` pattern, center the label and helper over the amount.
|
|
125
185
|
|
|
126
186
|
```tsx
|
|
127
187
|
import { useState } from 'react';
|
|
@@ -150,6 +210,34 @@ import { CurrencyInput, Field } from '@cdx-ui/components';
|
|
|
150
210
|
|
|
151
211
|
const DAILY_LIMIT = 1200;
|
|
152
212
|
|
|
213
|
+
export default function CurrencyInputOutlineWithFieldInvalidDemo() {
|
|
214
|
+
const [amount, setAmount] = useState(1500);
|
|
215
|
+
const isInvalid = amount > DAILY_LIMIT;
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<Field className="w-full" isRequired isInvalid={isInvalid}>
|
|
219
|
+
<Field.Label>Amount</Field.Label>
|
|
220
|
+
<CurrencyInput
|
|
221
|
+
isInvalid={isInvalid}
|
|
222
|
+
isRequired
|
|
223
|
+
variant="outline"
|
|
224
|
+
value={amount}
|
|
225
|
+
onChangeValue={setAmount}
|
|
226
|
+
/>
|
|
227
|
+
<Field.Error>Amount exceeds your daily limit.</Field.Error>
|
|
228
|
+
</Field>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The same validation in the `ghost` pattern, with a centered label and error.
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
import { useState } from 'react';
|
|
237
|
+
import { CurrencyInput, Field } from '@cdx-ui/components';
|
|
238
|
+
|
|
239
|
+
const DAILY_LIMIT = 1200;
|
|
240
|
+
|
|
153
241
|
export default function CurrencyInputWithFieldInvalidDemo() {
|
|
154
242
|
const [amount, setAmount] = useState(1500);
|
|
155
243
|
const isInvalid = amount > DAILY_LIMIT;
|
|
@@ -181,14 +269,15 @@ Controlled calculator-style monetary entry. The numeric `value` is expressed in
|
|
|
181
269
|
| `className?` | `string` | — | — |
|
|
182
270
|
| `value?` | `number` | — | Current amount in major currency units, not cents. Renders a formatted zero when omitted or null. |
|
|
183
271
|
| `style?` | `StyleProp<ViewStyle>` | — | — |
|
|
184
|
-
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
185
272
|
| `onChangeValue?` | `((value: number) => void)` | — | Called with the parsed amount in major currency units, not cents, when the user edits the field. |
|
|
186
|
-
| `currencySymbol?` | `string` | — | Currency symbol
|
|
273
|
+
| `currencySymbol?` | `string` | — | Currency symbol shown before the amount. Defaults to `"$"`. Part of the field text in `ghost`; a separate, non-editable prefix in `outline`. |
|
|
187
274
|
| `isInvalid?` | `boolean` | — | If true, the input will indicate an error. |
|
|
188
275
|
| `isDisabled?` | `boolean` | — | If true, the input will be disabled. |
|
|
189
276
|
| `isRequired?` | `boolean` | — | Sets `aria-required="true"` on web when passed in form control. |
|
|
190
277
|
| `isReadOnly?` | `boolean` | — | If true, prevents the value of the input from being edited. |
|
|
191
278
|
| `isFullWidth?` | `boolean` | — | If true, the input element will span the full width of its parent. |
|
|
279
|
+
| `variant?` | `'ghost' \| 'outline'` | `'ghost'` | Visual style. `ghost` is the large, centered, borderless amount entry; `outline` renders the bordered `Input` shell with a leading currency-symbol prefix, for amounts that sit alongside other form fields. |
|
|
280
|
+
| `size?` | `'default' \| 'small'` | `'default'` | Height, padding, and text size. |
|
|
192
281
|
|
|
193
282
|
Supports `accessibilityLabel`, `accessibilityHint`, `testID`, `onFocus`, `onBlur`, and `returnKeyType` from [`TextInputProps`](https://reactnative.dev/docs/textinput#props). `style` applies to the root container, and the forwarded ref targets the underlying `TextInput`.
|
|
194
283
|
|
|
@@ -201,5 +290,5 @@ Only digits contribute to the amount. Each new digit appends to the cents value,
|
|
|
201
290
|
| Item | Behavior |
|
|
202
291
|
| --------------- | ------------------------------------------------------------------------------------ |
|
|
203
292
|
| Accessible name | Compose with `Field.Label` or pass `accessibilityLabel` directly. |
|
|
204
|
-
| Value | `accessibilityValue.text` contains the fully formatted amount.
|
|
293
|
+
| Value | `accessibilityValue.text` contains the fully formatted amount, including the symbol. |
|
|
205
294
|
| Validation | Pair `isInvalid` with `Field.Error` so the error is not communicated by color alone. |
|
|
@@ -5,7 +5,16 @@ Resources: [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?
|
|
|
5
5
|
`DataGrid` is a **web-only** data-driven grid. Install `@cdx-ui/data-grid` in addition to `@cdx-ui/components`. For fully custom markup use `Table`. For a standalone pager use `TablePagination`.
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Avatar,
|
|
10
|
+
Checkbox,
|
|
11
|
+
Chip,
|
|
12
|
+
IconButton,
|
|
13
|
+
Menu,
|
|
14
|
+
ProgressBar,
|
|
15
|
+
Text,
|
|
16
|
+
VStack,
|
|
17
|
+
} from '@cdx-ui/components';
|
|
9
18
|
import { DataGrid } from '@cdx-ui/data-grid';
|
|
10
19
|
```
|
|
11
20
|
|
|
@@ -332,6 +341,121 @@ export default function DataGridSelectionDemo() {
|
|
|
332
341
|
}
|
|
333
342
|
```
|
|
334
343
|
|
|
344
|
+
## Checkbox cells
|
|
345
|
+
|
|
346
|
+
To edit boolean fields in place, render a `Checkbox` from `renderCell`. This is separate from `checkboxSelection`: the checkbox reflects a row field, not row selection. Keep `rows` in state and update the matching row in `onChange` so the grid re-renders with the new value.
|
|
347
|
+
|
|
348
|
+
Give each checkbox an accessible label that names both the column and the row, such as "View — Accounts", so every control keeps a distinct name when reached outside the table context. Set `isDisabled` where an action does not apply, and turn off `sortable` and `filterable` on checkbox columns. Build columns that close over the change handler with `useMemo` so they stay stable between renders.
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
352
|
+
import { Checkbox, Text, VStack } from '@cdx-ui/components';
|
|
353
|
+
import { DataGrid, type GridColDef } from '@cdx-ui/data-grid';
|
|
354
|
+
import { permissions, type PermissionAction, type PermissionRow } from './_data';
|
|
355
|
+
|
|
356
|
+
type ToggleField = PermissionAction | 'additional';
|
|
357
|
+
|
|
358
|
+
const actionColumns: { field: PermissionAction; headerName: string }[] = [
|
|
359
|
+
{ field: 'view', headerName: 'View' },
|
|
360
|
+
{ field: 'create', headerName: 'Create' },
|
|
361
|
+
{ field: 'modify', headerName: 'Modify' },
|
|
362
|
+
{ field: 'delete', headerName: 'Delete' },
|
|
363
|
+
];
|
|
364
|
+
|
|
365
|
+
function createColumns(
|
|
366
|
+
onToggle: (id: string, field: ToggleField, checked: boolean) => void,
|
|
367
|
+
): GridColDef<PermissionRow>[] {
|
|
368
|
+
return [
|
|
369
|
+
{
|
|
370
|
+
field: 'name',
|
|
371
|
+
headerName: 'Permission',
|
|
372
|
+
minWidth: 240,
|
|
373
|
+
flex: 1,
|
|
374
|
+
renderCell: ({ row }) => (
|
|
375
|
+
<VStack>
|
|
376
|
+
<Text numberOfLines={1} weight="medium">
|
|
377
|
+
{row.name}
|
|
378
|
+
</Text>
|
|
379
|
+
<Text numberOfLines={1} color="secondary" size="sm">
|
|
380
|
+
{row.description}
|
|
381
|
+
</Text>
|
|
382
|
+
</VStack>
|
|
383
|
+
),
|
|
384
|
+
},
|
|
385
|
+
...actionColumns.map(
|
|
386
|
+
({ field, headerName }): GridColDef<PermissionRow> => ({
|
|
387
|
+
field,
|
|
388
|
+
headerName,
|
|
389
|
+
width: 96,
|
|
390
|
+
align: 'center',
|
|
391
|
+
headerAlign: 'center',
|
|
392
|
+
sortable: false,
|
|
393
|
+
filterable: false,
|
|
394
|
+
renderCell: ({ row }) => (
|
|
395
|
+
<Checkbox
|
|
396
|
+
value={`${row.id}-${field}`}
|
|
397
|
+
isChecked={row[field] === true}
|
|
398
|
+
isDisabled={row[field] === null}
|
|
399
|
+
onChange={(checked) => onToggle(row.id, field, checked)}
|
|
400
|
+
accessibilityLabel={`${headerName} — ${row.name}`}
|
|
401
|
+
aria-label={`${headerName} — ${row.name}`}
|
|
402
|
+
/>
|
|
403
|
+
),
|
|
404
|
+
}),
|
|
405
|
+
),
|
|
406
|
+
{
|
|
407
|
+
field: 'additional',
|
|
408
|
+
headerName: 'Additional',
|
|
409
|
+
width: 140,
|
|
410
|
+
sortable: false,
|
|
411
|
+
filterable: false,
|
|
412
|
+
renderCell: ({ row }) =>
|
|
413
|
+
row.additional ? (
|
|
414
|
+
<Checkbox
|
|
415
|
+
value={`${row.id}-additional`}
|
|
416
|
+
isChecked={row.additional.checked}
|
|
417
|
+
onChange={(checked) => onToggle(row.id, 'additional', checked)}
|
|
418
|
+
accessibilityLabel={`${row.additional.label} — ${row.name}`}
|
|
419
|
+
aria-label={`${row.additional.label} — ${row.name}`}
|
|
420
|
+
>
|
|
421
|
+
<Checkbox.Label>{row.additional.label}</Checkbox.Label>
|
|
422
|
+
</Checkbox>
|
|
423
|
+
) : null,
|
|
424
|
+
},
|
|
425
|
+
];
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export default function DataGridCheckboxCellsDemo() {
|
|
429
|
+
const [rows, setRows] = useState(permissions);
|
|
430
|
+
|
|
431
|
+
const handleToggle = useCallback((id: string, field: ToggleField, checked: boolean) => {
|
|
432
|
+
setRows((current) =>
|
|
433
|
+
current.map((row) => {
|
|
434
|
+
if (row.id !== id) {
|
|
435
|
+
return row;
|
|
436
|
+
}
|
|
437
|
+
if (field === 'additional') {
|
|
438
|
+
return row.additional ? { ...row, additional: { ...row.additional, checked } } : row;
|
|
439
|
+
}
|
|
440
|
+
return { ...row, [field]: checked };
|
|
441
|
+
}),
|
|
442
|
+
);
|
|
443
|
+
}, []);
|
|
444
|
+
|
|
445
|
+
const columns = useMemo(() => createColumns(handleToggle), [handleToggle]);
|
|
446
|
+
|
|
447
|
+
return (
|
|
448
|
+
<DataGrid
|
|
449
|
+
rows={rows}
|
|
450
|
+
columns={columns}
|
|
451
|
+
hideFooter
|
|
452
|
+
aria-label="Set permissions"
|
|
453
|
+
className="h-85"
|
|
454
|
+
/>
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
335
459
|
## Server data
|
|
336
460
|
|
|
337
461
|
Set `paginationMode="server"` and `sortingMode="server"` to let your data source own those operations. `filterMode` follows `paginationMode` unless you set it, so server pagination also means server filtering. Keep the models controlled, pass the current page in `rows`, and provide the full `rowCount` of matching rows.
|