@cdx-ui/components 0.2.3 → 0.2.5
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/AGENTS.md +24 -0
- package/README.md +2 -0
- package/coverage.svg +1 -1
- package/docs/components/accordion/content.md +538 -0
- package/docs/components/alert/content.md +203 -0
- package/docs/components/alert-dialog/content.md +319 -0
- package/docs/components/avatar/content.md +368 -0
- package/docs/components/avatar/design.md +202 -0
- package/docs/components/badge/content.md +225 -0
- package/docs/components/bottom-sheet/content.md +353 -0
- package/docs/components/bottom-sheet/design.md +249 -0
- package/docs/components/box/content.md +141 -0
- package/docs/components/breadcrumbs/content.md +169 -0
- package/docs/components/button/content.md +398 -0
- package/docs/components/button/design.md +258 -0
- package/docs/components/calendar/content.md +137 -0
- package/docs/components/card/content.md +283 -0
- package/docs/components/carousel/content.md +417 -0
- package/docs/components/checkbox/content.md +236 -0
- package/docs/components/checkbox/design.md +214 -0
- package/docs/components/chip/content.md +439 -0
- package/docs/components/chip/design.md +418 -0
- package/docs/components/color-area/content.md +84 -0
- package/docs/components/color-field/content.md +132 -0
- package/docs/components/color-picker/content.md +209 -0
- package/docs/components/color-slider/content.md +118 -0
- package/docs/components/color-swatch/content.md +62 -0
- package/docs/components/color-swatch-picker/content.md +124 -0
- package/docs/components/content.md +98 -0
- package/docs/components/currency-input/content.md +205 -0
- package/docs/components/data-grid/content.md +521 -0
- package/docs/components/date-field/content.md +147 -0
- package/docs/components/date-picker/content.md +360 -0
- package/docs/components/date-range-picker/content.md +301 -0
- package/docs/components/date-time-field/content.md +157 -0
- package/docs/components/date-time-list/content.md +105 -0
- package/docs/components/date-time-picker/content.md +272 -0
- package/docs/components/dialog/content.md +436 -0
- package/docs/components/dialog/design.md +192 -0
- package/docs/components/divider/content.md +112 -0
- package/docs/components/drawer/content.md +428 -0
- package/docs/components/field/content.md +277 -0
- package/docs/components/form/content.md +62 -0
- package/docs/components/full-screen-dialog/content.md +881 -0
- package/docs/components/heading/content.md +55 -0
- package/docs/components/icon/content.md +190 -0
- package/docs/components/icon-button/content.md +200 -0
- package/docs/components/icon-button/design.md +165 -0
- package/docs/components/image/content.md +104 -0
- package/docs/components/input/content.md +346 -0
- package/docs/components/input/design.md +389 -0
- package/docs/components/insurance-disclosure/content.md +103 -0
- package/docs/components/link/content.md +180 -0
- package/docs/components/link/design.md +160 -0
- package/docs/components/list-item/content.md +695 -0
- package/docs/components/menu/content.md +1254 -0
- package/docs/components/month-calendar/content.md +84 -0
- package/docs/components/month-picker/content.md +273 -0
- package/docs/components/otp-input/content.md +327 -0
- package/docs/components/progress-bar/content.md +87 -0
- package/docs/components/progress-circle/content.md +176 -0
- package/docs/components/progress-segmented/content.md +119 -0
- package/docs/components/quick-action-button/content.md +154 -0
- package/docs/components/quick-action-button/design.md +170 -0
- package/docs/components/radio/content.md +224 -0
- package/docs/components/range-calendar/content.md +123 -0
- package/docs/components/reorderable-list/content.md +311 -0
- package/docs/components/scoped-theme/content.md +47 -0
- package/docs/components/scroll-shadow/content.md +693 -0
- package/docs/components/select/content.md +473 -0
- package/docs/components/select/design.md +301 -0
- package/docs/components/skeleton/content.md +104 -0
- package/docs/components/slider/content.md +423 -0
- package/docs/components/stack/content.md +161 -0
- package/docs/components/switch/content.md +150 -0
- package/docs/components/switch/design.md +208 -0
- package/docs/components/table/content.md +548 -0
- package/docs/components/table-pagination/content.md +177 -0
- package/docs/components/tabs/content.md +297 -0
- package/docs/components/text/content.md +142 -0
- package/docs/components/textarea/content.md +222 -0
- package/docs/components/tile/content.md +702 -0
- package/docs/components/toast/content.md +456 -0
- package/docs/components/toggle-button/content.md +505 -0
- package/docs/components/tooltip/content.md +350 -0
- package/docs/components/virtualized-list/content.md +250 -0
- package/docs/foundations/content.md +9 -0
- package/docs/foundations/expressions/icons/content.md +19 -0
- package/docs/foundations/styles/tokens/all-tokens/content.md +192 -0
- package/docs/foundations/styles/tokens/what-are-tokens/content.md +33 -0
- package/docs/foundations/styles/tokens/what-are-tokens/design.md +33 -0
- package/docs/getting-started/content.md +4 -0
- package/docs/getting-started/designers/content.md +13 -0
- package/docs/getting-started/designers/design.md +13 -0
- package/docs/getting-started/developers/accessibility/content.md +31 -0
- package/docs/getting-started/developers/content.md +612 -0
- package/docs/getting-started/developers/styling/content.md +195 -0
- package/docs/llms.txt +195 -0
- package/docs/patterns/account-management/content.md +75 -0
- package/docs/patterns/authentication/content.md +50 -0
- package/docs/patterns/content.md +10 -0
- package/docs/patterns/dashboard/content.md +34 -0
- package/docs/patterns/empty-states/content.md +32 -0
- package/docs/patterns/forms/content.md +108 -0
- package/docs/patterns/onboarding/content.md +69 -0
- package/docs/patterns/payments/content.md +35 -0
- package/docs/patterns/settings/content.md +72 -0
- package/docs/resources/content.md +9 -0
- package/docs/resources/figma-libraries/content.md +42 -0
- package/docs/resources/release-notes/0.0.1-beta.118/content.md +27 -0
- package/docs/resources/release-notes/0.0.1-beta.122/content.md +21 -0
- package/docs/resources/release-notes/0.0.1-beta.124/content.md +16 -0
- package/docs/resources/release-notes/0.0.1-beta.126/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.127/content.md +14 -0
- package/docs/resources/release-notes/0.0.1-beta.128/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.129/content.md +18 -0
- package/docs/resources/release-notes/0.0.1-beta.130/content.md +18 -0
- package/docs/resources/release-notes/0.0.1-beta.133/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.134/content.md +17 -0
- package/docs/resources/release-notes/0.0.1-beta.136/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.137/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.138/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.139/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.140/content.md +26 -0
- package/docs/resources/release-notes/0.0.1-beta.141/content.md +63 -0
- package/docs/resources/release-notes/0.0.1-beta.142/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.143/content.md +12 -0
- package/docs/resources/release-notes/0.0.1-beta.144/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.145/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.147/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.149/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.150/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.152/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.154/content.md +15 -0
- package/docs/resources/release-notes/0.0.1-beta.156/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.158/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.159/content.md +11 -0
- package/docs/resources/release-notes/0.0.1-beta.160/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.161/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.163/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.164/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.166/content.md +17 -0
- package/docs/resources/release-notes/0.0.1-beta.167/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.168/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.169/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.171/content.md +16 -0
- package/docs/resources/release-notes/0.0.1-beta.172/content.md +24 -0
- package/docs/resources/release-notes/0.0.1-beta.173/content.md +15 -0
- package/docs/resources/release-notes/0.0.1-beta.174/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.176/content.md +32 -0
- package/docs/resources/release-notes/0.0.1-beta.179/content.md +11 -0
- package/docs/resources/release-notes/0.0.1-beta.182/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.185/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.187/content.md +27 -0
- package/docs/resources/release-notes/0.1.1/content.md +23 -0
- package/docs/resources/release-notes/0.1.2/content.md +7 -0
- package/docs/resources/release-notes/0.1.4/content.md +19 -0
- package/docs/resources/release-notes/0.1.5/content.md +7 -0
- package/docs/resources/release-notes/0.1.6/content.md +7 -0
- package/docs/resources/release-notes/0.2.0/content.md +31 -0
- package/docs/resources/release-notes/0.2.1/content.md +17 -0
- package/docs/resources/release-notes/0.2.2/content.md +11 -0
- package/docs/resources/release-notes/0.2.3/content.md +15 -0
- package/docs/resources/release-notes/0.2.4/content.md +17 -0
- package/docs/resources/release-notes/content.md +65 -0
- package/lib/commonjs/components/Box/Box.js +9 -1
- package/lib/commonjs/components/Box/Box.js.map +1 -1
- package/lib/commonjs/components/Breadcrumbs/index.js +28 -3
- package/lib/commonjs/components/Breadcrumbs/index.js.map +1 -1
- package/lib/commonjs/components/Breadcrumbs/styles.js +27 -0
- package/lib/commonjs/components/Breadcrumbs/styles.js.map +1 -1
- package/lib/commonjs/components/DateTimeList/index.js +11 -26
- package/lib/commonjs/components/DateTimeList/index.js.map +1 -1
- package/lib/commonjs/components/DateTimeList/styles.js +2 -12
- package/lib/commonjs/components/DateTimeList/styles.js.map +1 -1
- package/lib/commonjs/components/ListItem/index.js.map +1 -1
- package/lib/commonjs/components/ListItem/styles.js +2 -1
- package/lib/commonjs/components/ListItem/styles.js.map +1 -1
- package/lib/commonjs/components/Menu/index.js +11 -5
- package/lib/commonjs/components/Menu/index.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/gradient.js +29 -0
- package/lib/commonjs/components/ScrollShadow/gradient.js.map +1 -0
- package/lib/commonjs/components/ScrollShadow/index.js +171 -44
- package/lib/commonjs/components/ScrollShadow/index.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/styles.js +58 -14
- package/lib/commonjs/components/ScrollShadow/styles.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js +63 -0
- package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +48 -8
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/commonjs/components/Stack/HStack.js +6 -2
- package/lib/commonjs/components/Stack/HStack.js.map +1 -1
- package/lib/commonjs/components/Stack/VStack.js +6 -2
- package/lib/commonjs/components/Stack/VStack.js.map +1 -1
- package/lib/commonjs/components/Tabs/index.js +16 -23
- package/lib/commonjs/components/Tabs/index.js.map +1 -1
- package/lib/commonjs/components/Tabs/styles.js +1 -10
- package/lib/commonjs/components/Tabs/styles.js.map +1 -1
- package/lib/commonjs/figma/ListItem.SectionHeader.figma.js +20 -5
- package/lib/commonjs/figma/ListItem.SectionHeader.figma.js.map +1 -1
- package/lib/commonjs/index.js +10 -10
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/components/Box/Box.js +9 -1
- package/lib/module/components/Box/Box.js.map +1 -1
- package/lib/module/components/Breadcrumbs/index.js +29 -4
- package/lib/module/components/Breadcrumbs/index.js.map +1 -1
- package/lib/module/components/Breadcrumbs/styles.js +26 -0
- package/lib/module/components/Breadcrumbs/styles.js.map +1 -1
- package/lib/module/components/DateTimeList/index.js +12 -27
- package/lib/module/components/DateTimeList/index.js.map +1 -1
- package/lib/module/components/DateTimeList/styles.js +1 -11
- package/lib/module/components/DateTimeList/styles.js.map +1 -1
- package/lib/module/components/ListItem/index.js.map +1 -1
- package/lib/module/components/ListItem/styles.js +2 -1
- package/lib/module/components/ListItem/styles.js.map +1 -1
- package/lib/module/components/Menu/index.js +11 -5
- package/lib/module/components/Menu/index.js.map +1 -1
- package/lib/module/components/ScrollShadow/gradient.js +24 -0
- package/lib/module/components/ScrollShadow/gradient.js.map +1 -0
- package/lib/module/components/ScrollShadow/index.js +170 -48
- package/lib/module/components/ScrollShadow/index.js.map +1 -1
- package/lib/module/components/ScrollShadow/styles.js +57 -13
- package/lib/module/components/ScrollShadow/styles.js.map +1 -1
- package/lib/module/components/ScrollShadow/useComposedScrollHandler.js +57 -0
- package/lib/module/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
- package/lib/module/components/ScrollShadow/useScrollShadow.js +46 -8
- package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/module/components/Stack/HStack.js +6 -2
- package/lib/module/components/Stack/HStack.js.map +1 -1
- package/lib/module/components/Stack/VStack.js +6 -2
- package/lib/module/components/Stack/VStack.js.map +1 -1
- package/lib/module/components/Tabs/index.js +17 -24
- package/lib/module/components/Tabs/index.js.map +1 -1
- package/lib/module/components/Tabs/styles.js +0 -9
- package/lib/module/components/Tabs/styles.js.map +1 -1
- package/lib/module/figma/ListItem.SectionHeader.figma.js +20 -5
- package/lib/module/figma/ListItem.SectionHeader.figma.js.map +1 -1
- package/lib/module/index.js +6 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/animation/hooks/usePopupDialogContentAnimation.d.ts +2 -2
- package/lib/typescript/animation/hooks/usePopupOverlayAnimation.d.ts +2 -2
- package/lib/typescript/components/Box/Box.d.ts +4 -0
- package/lib/typescript/components/Box/Box.d.ts.map +1 -1
- package/lib/typescript/components/Breadcrumbs/index.d.ts +3 -1
- package/lib/typescript/components/Breadcrumbs/index.d.ts.map +1 -1
- package/lib/typescript/components/Breadcrumbs/styles.d.ts +2 -0
- package/lib/typescript/components/Breadcrumbs/styles.d.ts.map +1 -1
- package/lib/typescript/components/DateTimeList/index.d.ts.map +1 -1
- package/lib/typescript/components/DateTimeList/styles.d.ts +1 -4
- package/lib/typescript/components/DateTimeList/styles.d.ts.map +1 -1
- package/lib/typescript/components/ListItem/index.d.ts +5 -4
- package/lib/typescript/components/ListItem/index.d.ts.map +1 -1
- package/lib/typescript/components/ListItem/styles.d.ts +1 -1
- package/lib/typescript/components/ListItem/styles.d.ts.map +1 -1
- package/lib/typescript/components/Menu/index.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/gradient.d.ts +7 -0
- package/lib/typescript/components/ScrollShadow/gradient.d.ts.map +1 -0
- package/lib/typescript/components/ScrollShadow/index.d.ts +57 -15
- package/lib/typescript/components/ScrollShadow/index.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/styles.d.ts +8 -2
- package/lib/typescript/components/ScrollShadow/styles.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts +13 -0
- package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts.map +1 -0
- package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts +15 -2
- package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
- package/lib/typescript/components/Stack/HStack.d.ts +3 -2
- package/lib/typescript/components/Stack/HStack.d.ts.map +1 -1
- package/lib/typescript/components/Stack/VStack.d.ts +3 -2
- package/lib/typescript/components/Stack/VStack.d.ts.map +1 -1
- package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
- package/lib/typescript/components/Tabs/styles.d.ts +0 -7
- package/lib/typescript/components/Tabs/styles.d.ts.map +1 -1
- package/lib/typescript/components/Toast/animation.d.ts +3 -3
- package/lib/typescript/components/Toast/animation.d.ts.map +1 -1
- package/lib/typescript/figma/ListItem.SectionHeader.figma.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +6 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +11 -9
- package/src/components/Box/Box.tsx +18 -4
- package/src/components/Breadcrumbs/index.tsx +28 -4
- package/src/components/Breadcrumbs/styles.ts +30 -0
- package/src/components/DateTimeList/index.tsx +13 -26
- package/src/components/DateTimeList/styles.ts +1 -10
- package/src/components/ListItem/index.tsx +5 -4
- package/src/components/ListItem/styles.ts +1 -0
- package/src/components/Menu/index.tsx +11 -8
- package/src/components/ScrollShadow/gradient.ts +48 -0
- package/src/components/ScrollShadow/index.tsx +300 -69
- package/src/components/ScrollShadow/styles.ts +45 -28
- package/src/components/ScrollShadow/useComposedScrollHandler.ts +58 -0
- package/src/components/ScrollShadow/useScrollShadow.ts +72 -10
- package/src/components/Stack/HStack.tsx +8 -4
- package/src/components/Stack/VStack.tsx +8 -4
- package/src/components/Tabs/index.tsx +25 -35
- package/src/components/Tabs/styles.ts +0 -9
- package/src/index.ts +8 -1
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
# Data Grid (https://design.candescent.com/docs/components/data-grid)
|
|
2
|
+
|
|
3
|
+
Resources: [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/data-visualization-datagrid--default)
|
|
4
|
+
|
|
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
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Avatar, Chip, IconButton, Menu, ProgressBar, Text, VStack } from '@cdx-ui/components';
|
|
9
|
+
import { DataGrid } from '@cdx-ui/data-grid';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Basic
|
|
13
|
+
|
|
14
|
+
Pass `rows` and `columns`. This account grid starts with the features most applications need: formatted values, status `Chip` cells, search, header filters, selection, sorting, and pagination.
|
|
15
|
+
|
|
16
|
+
Search is **not** always on. Set `showToolbar` to show the search field (same opt-in as MUI Community’s toolbar / quick filter). Set `headerFilters` to show per-column filter inputs in a second header row.
|
|
17
|
+
|
|
18
|
+
The grid is a fixed viewport like MUI Data Grid Community: **300px** tall by default. Column headers stay visible while rows scroll; pagination stays at the bottom. Override height with a `className` such as `h-full` or a spacing-scale height (`h-130`).
|
|
19
|
+
|
|
20
|
+
When `rows` is empty, a centered "No rows" message is shown and pagination is omitted. Pass `noRowsOverlay` to replace the default message.
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { Chip } from '@cdx-ui/components';
|
|
24
|
+
import { DataGrid, type GridColDef } from '@cdx-ui/data-grid';
|
|
25
|
+
import { accounts, type Account, type AccountStatus } from './_data';
|
|
26
|
+
|
|
27
|
+
const currencyFormatter = new Intl.NumberFormat('en-US', {
|
|
28
|
+
style: 'currency',
|
|
29
|
+
currency: 'USD',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const statusColors: Record<AccountStatus, 'success' | 'warning' | 'info' | 'neutral'> = {
|
|
33
|
+
Active: 'success',
|
|
34
|
+
Pending: 'warning',
|
|
35
|
+
Frozen: 'info',
|
|
36
|
+
Closed: 'neutral',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const columns: GridColDef<Account>[] = [
|
|
40
|
+
{ field: 'id', headerName: 'Account', width: 120 },
|
|
41
|
+
{ field: 'name', headerName: 'Name', flex: 1, minWidth: 160 },
|
|
42
|
+
{ field: 'type', headerName: 'Type', width: 140 },
|
|
43
|
+
{
|
|
44
|
+
field: 'status',
|
|
45
|
+
headerName: 'Status',
|
|
46
|
+
width: 120,
|
|
47
|
+
renderCell: ({ row }) => (
|
|
48
|
+
<Chip color={statusColors[row.status]} size="small">
|
|
49
|
+
<Chip.Label>{row.status}</Chip.Label>
|
|
50
|
+
</Chip>
|
|
51
|
+
),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
field: 'balance',
|
|
55
|
+
headerName: 'Balance',
|
|
56
|
+
width: 140,
|
|
57
|
+
align: 'end',
|
|
58
|
+
valueFormatter: (_, row) => currencyFormatter.format(row.balance),
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
export default function DataGridBasicDemo() {
|
|
63
|
+
return (
|
|
64
|
+
<DataGrid
|
|
65
|
+
rows={accounts}
|
|
66
|
+
columns={columns}
|
|
67
|
+
checkboxSelection
|
|
68
|
+
showToolbar
|
|
69
|
+
headerFilters
|
|
70
|
+
aria-label="Accounts"
|
|
71
|
+
defaultPaginationModel={{ page: 0, pageSize: 5 }}
|
|
72
|
+
pageSizeOptions={[5, 10, 25]}
|
|
73
|
+
className="h-105"
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Rich cells
|
|
80
|
+
|
|
81
|
+
Use `renderCell` to compose Forge UI components inside a cell. This operations view combines `Avatar`, `Chip`, `ProgressBar`, and an action `Menu`, while `valueFormatter` keeps sortable numeric data separate from its display value.
|
|
82
|
+
|
|
83
|
+
Rows are currently fixed at 48px, so use compact component variants and single-line content.
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { Avatar, Chip, HStack, IconButton, Menu, ProgressBar, Text } from '@cdx-ui/components';
|
|
87
|
+
import { DataGrid, type GridColDef } from '@cdx-ui/data-grid';
|
|
88
|
+
import { MoreHoriz } from '@cdx-ui/icons';
|
|
89
|
+
import { accounts, type Account, type AccountStatus } from './_data';
|
|
90
|
+
|
|
91
|
+
const currencyFormatter = new Intl.NumberFormat('en-US', {
|
|
92
|
+
style: 'currency',
|
|
93
|
+
currency: 'USD',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const statusColors: Record<AccountStatus, 'success' | 'warning' | 'info' | 'neutral'> = {
|
|
97
|
+
Active: 'success',
|
|
98
|
+
Pending: 'warning',
|
|
99
|
+
Frozen: 'info',
|
|
100
|
+
Closed: 'neutral',
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const columns: GridColDef<Account>[] = [
|
|
104
|
+
{ field: 'id', headerName: 'Account', width: 120 },
|
|
105
|
+
{
|
|
106
|
+
field: 'name',
|
|
107
|
+
headerName: 'Account name',
|
|
108
|
+
minWidth: 210,
|
|
109
|
+
flex: 1,
|
|
110
|
+
renderCell: ({ row }) => (
|
|
111
|
+
<HStack space="sm" className="items-center">
|
|
112
|
+
<Avatar size="sm">
|
|
113
|
+
<Avatar.Text>{row.name}</Avatar.Text>
|
|
114
|
+
</Avatar>
|
|
115
|
+
<Text numberOfLines={1} weight="medium">
|
|
116
|
+
{row.name}
|
|
117
|
+
</Text>
|
|
118
|
+
</HStack>
|
|
119
|
+
),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
field: 'status',
|
|
123
|
+
headerName: 'Status',
|
|
124
|
+
width: 120,
|
|
125
|
+
renderCell: ({ row }) => (
|
|
126
|
+
<Chip color={statusColors[row.status]} size="small">
|
|
127
|
+
<Chip.Label>{row.status}</Chip.Label>
|
|
128
|
+
</Chip>
|
|
129
|
+
),
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
field: 'automation',
|
|
133
|
+
headerName: 'Automated',
|
|
134
|
+
width: 170,
|
|
135
|
+
renderCell: ({ row }) => (
|
|
136
|
+
<HStack space="sm" className="items-center">
|
|
137
|
+
<ProgressBar
|
|
138
|
+
value={row.automation}
|
|
139
|
+
max={100}
|
|
140
|
+
accessibilityLabel={`${row.name} is ${row.automation.toString()}% automated`}
|
|
141
|
+
className="w-full max-w-20"
|
|
142
|
+
>
|
|
143
|
+
<ProgressBar.Indicator />
|
|
144
|
+
</ProgressBar>
|
|
145
|
+
<Text color="secondary" size="sm">
|
|
146
|
+
{row.automation}%
|
|
147
|
+
</Text>
|
|
148
|
+
</HStack>
|
|
149
|
+
),
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
field: 'balance',
|
|
153
|
+
headerName: 'Balance',
|
|
154
|
+
width: 140,
|
|
155
|
+
align: 'end',
|
|
156
|
+
valueFormatter: (_, row) => currencyFormatter.format(row.balance),
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
field: 'actions',
|
|
160
|
+
headerName: 'Actions',
|
|
161
|
+
width: 72,
|
|
162
|
+
align: 'center',
|
|
163
|
+
headerAlign: 'center',
|
|
164
|
+
sortable: false,
|
|
165
|
+
filterable: false,
|
|
166
|
+
renderCell: ({ row }) => (
|
|
167
|
+
<Menu placement="bottom-end">
|
|
168
|
+
<Menu.Trigger asChild>
|
|
169
|
+
<IconButton
|
|
170
|
+
as={MoreHoriz}
|
|
171
|
+
variant="ghost"
|
|
172
|
+
size="small"
|
|
173
|
+
accessibilityLabel={`Actions for ${row.name}`}
|
|
174
|
+
/>
|
|
175
|
+
</Menu.Trigger>
|
|
176
|
+
<Menu.Popup>
|
|
177
|
+
<Menu.Content accessibilityLabel={`${row.name} actions`}>
|
|
178
|
+
<Menu.Item>
|
|
179
|
+
<Menu.ItemLabel>View account</Menu.ItemLabel>
|
|
180
|
+
</Menu.Item>
|
|
181
|
+
<Menu.Item>
|
|
182
|
+
<Menu.ItemLabel>Assign owner</Menu.ItemLabel>
|
|
183
|
+
</Menu.Item>
|
|
184
|
+
<Menu.Item color="danger">
|
|
185
|
+
<Menu.ItemLabel>Freeze account</Menu.ItemLabel>
|
|
186
|
+
</Menu.Item>
|
|
187
|
+
</Menu.Content>
|
|
188
|
+
</Menu.Popup>
|
|
189
|
+
</Menu>
|
|
190
|
+
),
|
|
191
|
+
},
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
export default function DataGridRichCellsDemo() {
|
|
195
|
+
return (
|
|
196
|
+
<DataGrid
|
|
197
|
+
rows={accounts.slice(0, 10)}
|
|
198
|
+
columns={columns}
|
|
199
|
+
hideFooter
|
|
200
|
+
aria-label="Account operations"
|
|
201
|
+
className="h-130"
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Toolbar actions
|
|
208
|
+
|
|
209
|
+
`toolbarActions` is an extension slot for your own toolbar controls beside search — export, density, view toggles, and so on. DataGrid does not ship toolbar buttons; you compose them and wire `onPress` to state that drives grid props.
|
|
210
|
+
|
|
211
|
+
A common pattern is a **Filters** button that toggles the `headerFilters` row on demand instead of leaving filter inputs always visible:
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
import { useState } from 'react';
|
|
215
|
+
import { Button, Chip } from '@cdx-ui/components';
|
|
216
|
+
import { DataGrid, type GridColDef, type GridFilterModel } from '@cdx-ui/data-grid';
|
|
217
|
+
import { FilterList } from '@cdx-ui/icons';
|
|
218
|
+
import { accounts, type Account } from './_data';
|
|
219
|
+
|
|
220
|
+
const currencyFormatter = new Intl.NumberFormat('en-US', {
|
|
221
|
+
style: 'currency',
|
|
222
|
+
currency: 'USD',
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const columns: GridColDef<Account>[] = [
|
|
226
|
+
{ field: 'id', headerName: 'Account', width: 120 },
|
|
227
|
+
{ field: 'name', headerName: 'Name', flex: 1, minWidth: 160 },
|
|
228
|
+
{ field: 'type', headerName: 'Type', width: 140 },
|
|
229
|
+
{ field: 'status', headerName: 'Status', width: 120 },
|
|
230
|
+
{
|
|
231
|
+
field: 'balance',
|
|
232
|
+
headerName: 'Balance',
|
|
233
|
+
width: 140,
|
|
234
|
+
align: 'end',
|
|
235
|
+
valueFormatter: (_, row) => currencyFormatter.format(row.balance),
|
|
236
|
+
},
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
export default function DataGridToolbarActionsDemo() {
|
|
240
|
+
const [headerFiltersOpen, setHeaderFiltersOpen] = useState(false);
|
|
241
|
+
const [filterModel, setFilterModel] = useState<GridFilterModel>([]);
|
|
242
|
+
|
|
243
|
+
const toggleHeaderFilters = () => {
|
|
244
|
+
setHeaderFiltersOpen((open) => {
|
|
245
|
+
if (open) {
|
|
246
|
+
setFilterModel([]);
|
|
247
|
+
}
|
|
248
|
+
return !open;
|
|
249
|
+
});
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
return (
|
|
253
|
+
<DataGrid
|
|
254
|
+
rows={accounts}
|
|
255
|
+
columns={columns}
|
|
256
|
+
showToolbar
|
|
257
|
+
headerFilters={headerFiltersOpen}
|
|
258
|
+
filterModel={filterModel}
|
|
259
|
+
onFilterModelChange={setFilterModel}
|
|
260
|
+
toolbarActions={
|
|
261
|
+
<>
|
|
262
|
+
<Chip color={filterModel.length > 0 ? 'action' : 'neutral'} size="small">
|
|
263
|
+
<Chip.Label>{filterModel.length} active</Chip.Label>
|
|
264
|
+
</Chip>
|
|
265
|
+
<Button variant="ghost" size="small" onPress={toggleHeaderFilters}>
|
|
266
|
+
<Button.Label>Filters</Button.Label>
|
|
267
|
+
<Button.Icon as={FilterList} position="trailing" />
|
|
268
|
+
</Button>
|
|
269
|
+
</>
|
|
270
|
+
}
|
|
271
|
+
aria-label="Accounts"
|
|
272
|
+
defaultPaginationModel={{ page: 0, pageSize: 5 }}
|
|
273
|
+
pageSizeOptions={[5, 10, 25]}
|
|
274
|
+
className="h-105"
|
|
275
|
+
/>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Selection
|
|
281
|
+
|
|
282
|
+
Set `checkboxSelection` for a leading checkbox column with select-all in the header. Control `rowSelectionModel` when bulk-action UI outside the rows needs the current selection.
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
import { useState } from 'react';
|
|
286
|
+
import { Button, Chip } from '@cdx-ui/components';
|
|
287
|
+
import { DataGrid, type GridColDef, type GridRowSelectionModel } from '@cdx-ui/data-grid';
|
|
288
|
+
import { accounts, type Account } from './_data';
|
|
289
|
+
|
|
290
|
+
const columns: GridColDef<Account>[] = [
|
|
291
|
+
{ field: 'id', headerName: 'Account', width: 120 },
|
|
292
|
+
{ field: 'name', headerName: 'Name', flex: 1, minWidth: 160 },
|
|
293
|
+
{ field: 'owner', headerName: 'Owner', width: 170 },
|
|
294
|
+
{ field: 'status', headerName: 'Status', width: 120 },
|
|
295
|
+
];
|
|
296
|
+
|
|
297
|
+
export default function DataGridSelectionDemo() {
|
|
298
|
+
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>({
|
|
299
|
+
type: 'include',
|
|
300
|
+
ids: new Set(['ACC-0002', 'ACC-0004']),
|
|
301
|
+
});
|
|
302
|
+
const selectedCount = selectionModel.ids.size;
|
|
303
|
+
|
|
304
|
+
return (
|
|
305
|
+
<DataGrid
|
|
306
|
+
rows={accounts.slice(0, 12)}
|
|
307
|
+
columns={columns}
|
|
308
|
+
checkboxSelection
|
|
309
|
+
rowSelectionModel={selectionModel}
|
|
310
|
+
onRowSelectionModelChange={setSelectionModel}
|
|
311
|
+
toolbarActions={
|
|
312
|
+
<>
|
|
313
|
+
<Chip color={selectedCount > 0 ? 'action' : 'neutral'} size="small">
|
|
314
|
+
<Chip.Label>{selectedCount} selected</Chip.Label>
|
|
315
|
+
</Chip>
|
|
316
|
+
<Button
|
|
317
|
+
variant="ghost"
|
|
318
|
+
size="small"
|
|
319
|
+
isDisabled={selectedCount === 0}
|
|
320
|
+
onPress={() => setSelectionModel({ type: 'include', ids: new Set() })}
|
|
321
|
+
>
|
|
322
|
+
<Button.Label>Clear selection</Button.Label>
|
|
323
|
+
</Button>
|
|
324
|
+
</>
|
|
325
|
+
}
|
|
326
|
+
aria-label="Accounts"
|
|
327
|
+
defaultPaginationModel={{ page: 0, pageSize: 5 }}
|
|
328
|
+
pageSizeOptions={[5, 10]}
|
|
329
|
+
className="h-105"
|
|
330
|
+
/>
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Server data
|
|
336
|
+
|
|
337
|
+
Set `paginationMode="server"` and `sortingMode="server"` to let your data source own those operations. Keep the models controlled, pass the current page in `rows`, and provide the full `rowCount`.
|
|
338
|
+
|
|
339
|
+
Server-side filtering is not supported yet. Do not combine quick or header filters with server-paged rows; those filters only inspect the current `rows` array.
|
|
340
|
+
|
|
341
|
+
```tsx
|
|
342
|
+
import { useState } from 'react';
|
|
343
|
+
import {
|
|
344
|
+
DataGrid,
|
|
345
|
+
type GridColDef,
|
|
346
|
+
type GridPaginationModel,
|
|
347
|
+
type GridSortModel,
|
|
348
|
+
} from '@cdx-ui/data-grid';
|
|
349
|
+
import { accounts, type Account } from './_data';
|
|
350
|
+
|
|
351
|
+
const currencyFormatter = new Intl.NumberFormat('en-US', {
|
|
352
|
+
style: 'currency',
|
|
353
|
+
currency: 'USD',
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const columns: GridColDef<Account>[] = [
|
|
357
|
+
{ field: 'id', headerName: 'Account', width: 120 },
|
|
358
|
+
{ field: 'name', headerName: 'Name', flex: 1, minWidth: 160 },
|
|
359
|
+
{ field: 'owner', headerName: 'Owner', width: 170 },
|
|
360
|
+
{
|
|
361
|
+
field: 'balance',
|
|
362
|
+
headerName: 'Balance',
|
|
363
|
+
width: 140,
|
|
364
|
+
align: 'end',
|
|
365
|
+
valueFormatter: (_, row) => currencyFormatter.format(row.balance),
|
|
366
|
+
},
|
|
367
|
+
];
|
|
368
|
+
|
|
369
|
+
function queryAccounts(paginationModel: GridPaginationModel, sortModel: GridSortModel): Account[] {
|
|
370
|
+
const sortedRows = [...accounts];
|
|
371
|
+
const activeSort = sortModel.length > 0 ? sortModel[0] : undefined;
|
|
372
|
+
|
|
373
|
+
if (activeSort) {
|
|
374
|
+
sortedRows.sort((leftRow, rightRow) => {
|
|
375
|
+
const left = leftRow[activeSort.field as keyof Account];
|
|
376
|
+
const right = rightRow[activeSort.field as keyof Account];
|
|
377
|
+
const comparison =
|
|
378
|
+
typeof left === 'number' && typeof right === 'number'
|
|
379
|
+
? left - right
|
|
380
|
+
: String(left).localeCompare(String(right));
|
|
381
|
+
return activeSort.sort === 'asc' ? comparison : -comparison;
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const start = paginationModel.page * paginationModel.pageSize;
|
|
386
|
+
return sortedRows.slice(start, start + paginationModel.pageSize);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export default function DataGridServerDataDemo() {
|
|
390
|
+
const [paginationModel, setPaginationModel] = useState<GridPaginationModel>({
|
|
391
|
+
page: 0,
|
|
392
|
+
pageSize: 5,
|
|
393
|
+
});
|
|
394
|
+
const [sortModel, setSortModel] = useState<GridSortModel>([]);
|
|
395
|
+
const rows = queryAccounts(paginationModel, sortModel);
|
|
396
|
+
|
|
397
|
+
return (
|
|
398
|
+
<DataGrid
|
|
399
|
+
rows={rows}
|
|
400
|
+
columns={columns}
|
|
401
|
+
rowCount={accounts.length}
|
|
402
|
+
paginationMode="server"
|
|
403
|
+
sortingMode="server"
|
|
404
|
+
paginationModel={paginationModel}
|
|
405
|
+
onPaginationModelChange={setPaginationModel}
|
|
406
|
+
sortModel={sortModel}
|
|
407
|
+
onSortModelChange={setSortModel}
|
|
408
|
+
pageSizeOptions={[5, 10]}
|
|
409
|
+
aria-label="Server-managed accounts"
|
|
410
|
+
className="h-105"
|
|
411
|
+
/>
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Loading
|
|
417
|
+
|
|
418
|
+
Set `loading` to mark the grid busy and show skeleton rows. Pagination is disabled and the empty state is suppressed while loading. Pass `loadingOverlay` to replace the default skeletons.
|
|
419
|
+
|
|
420
|
+
```tsx
|
|
421
|
+
import { DataGrid, type GridColDef } from '@cdx-ui/data-grid';
|
|
422
|
+
|
|
423
|
+
// GridValidRowModel's index signature rejects otherwise equivalent interfaces.
|
|
424
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
425
|
+
type Account = {
|
|
426
|
+
id: string;
|
|
427
|
+
name: string;
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const columns: GridColDef<Account>[] = [
|
|
431
|
+
{ field: 'id', headerName: 'Account' },
|
|
432
|
+
{ field: 'name', headerName: 'Name' },
|
|
433
|
+
];
|
|
434
|
+
|
|
435
|
+
export default function DataGridLoadingDemo() {
|
|
436
|
+
return (
|
|
437
|
+
<DataGrid
|
|
438
|
+
rows={[{ id: 'ACC-0001', name: 'Operating' }]}
|
|
439
|
+
columns={columns}
|
|
440
|
+
loading
|
|
441
|
+
hideFooter
|
|
442
|
+
aria-label="Accounts"
|
|
443
|
+
/>
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Empty state
|
|
449
|
+
|
|
450
|
+
When no rows match, use `noRowsOverlay` to replace the default message with product-specific guidance. Pagination is omitted automatically.
|
|
451
|
+
|
|
452
|
+
```tsx
|
|
453
|
+
import { Heading, Text, VStack } from '@cdx-ui/components';
|
|
454
|
+
import { DataGrid, type GridColDef } from '@cdx-ui/data-grid';
|
|
455
|
+
import type { Account } from './_data';
|
|
456
|
+
|
|
457
|
+
const rows: Account[] = [];
|
|
458
|
+
|
|
459
|
+
const columns: GridColDef<Account>[] = [
|
|
460
|
+
{ field: 'id', headerName: 'Account', width: 120 },
|
|
461
|
+
{ field: 'name', headerName: 'Name', flex: 1, minWidth: 160 },
|
|
462
|
+
{ field: 'type', headerName: 'Type', width: 140 },
|
|
463
|
+
{ field: 'status', headerName: 'Status', width: 120 },
|
|
464
|
+
];
|
|
465
|
+
|
|
466
|
+
export default function DataGridEmptyDemo() {
|
|
467
|
+
return (
|
|
468
|
+
<DataGrid
|
|
469
|
+
rows={rows}
|
|
470
|
+
columns={columns}
|
|
471
|
+
noRowsOverlay={
|
|
472
|
+
<VStack space="xs" className="items-center">
|
|
473
|
+
<Heading size="sm">No matching accounts</Heading>
|
|
474
|
+
<Text color="secondary" size="sm">
|
|
475
|
+
Adjust the search or filters and try again.
|
|
476
|
+
</Text>
|
|
477
|
+
</VStack>
|
|
478
|
+
}
|
|
479
|
+
aria-label="Accounts"
|
|
480
|
+
className="h-75"
|
|
481
|
+
/>
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## API
|
|
487
|
+
|
|
488
|
+
### DataGrid
|
|
489
|
+
|
|
490
|
+
Web-only. Inspired by MUI Data Grid Community props; not a wrap of `@mui/x-data-grid`.
|
|
491
|
+
|
|
492
|
+
| Attribute | Values | Description |
|
|
493
|
+
| ----------- | ----------- | ----------- |
|
|
494
|
+
| `data-slot` | `data-grid` | Shell |
|
|
495
|
+
|
|
496
|
+
### GridColDef
|
|
497
|
+
|
|
498
|
+
Column definition. `valueGetter`, `valueFormatter`, and `renderCell` take no `apiRef`.
|
|
499
|
+
Use `start`, `center`, or `end` for `align` and `headerAlign`; the legacy `left` and `right`
|
|
500
|
+
values are deprecated aliases.
|
|
501
|
+
|
|
502
|
+
| Prop | Type | Default | Description |
|
|
503
|
+
| --- | --- | --- | --- |
|
|
504
|
+
| `field` | `string` | — | — |
|
|
505
|
+
| `headerName?` | `string` | — | — |
|
|
506
|
+
| `width?` | `number` | — | — |
|
|
507
|
+
| `minWidth?` | `number` | — | — |
|
|
508
|
+
| `flex?` | `number` | — | — |
|
|
509
|
+
| `align?` | `'start' \| 'center' \| 'end' \| 'left' \| 'right'` | `'start'` | Logical cell-content alignment. `left` and `right` are deprecated compatibility aliases for `start` and `end`. |
|
|
510
|
+
| `headerAlign?` | `'start' \| 'center' \| 'end' \| 'left' \| 'right'` | — | Logical header-content alignment. Defaults to `align`. `left` and `right` are deprecated compatibility aliases for `start` and `end`. |
|
|
511
|
+
| `sortable?` | `boolean` | — | — |
|
|
512
|
+
| `filterable?` | `boolean` | — | — |
|
|
513
|
+
| `type?` | `'string'` | — | — |
|
|
514
|
+
| `valueGetter?` | `((value: unknown, row: GridValidRowModel, col: GridColDef<GridValidRowModel>) => unknown)` | — | — |
|
|
515
|
+
| `valueFormatter?` | `((value: unknown, row: GridValidRowModel, col: GridColDef<GridValidRowModel>) => ReactNode \| string)` | — | — |
|
|
516
|
+
| `renderCell?` | `((params: GridRenderCellParams<GridValidRowModel>) => ReactNode)` | — | — |
|
|
517
|
+
| `renderHeader?` | `(() => ReactNode)` | — | — |
|
|
518
|
+
|
|
519
|
+
## Accessibility
|
|
520
|
+
|
|
521
|
+
The grid renders a semantic HTML table on web. Sortable headers expose `aria-sort`. Select-all and row checkboxes are labelled.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Date Field (https://design.candescent.com/docs/components/date-field)
|
|
2
|
+
|
|
3
|
+
Resources: [Figma](https://www.figma.com/design/0lEVMVlLj8ZS4fgItr3pmd/%E2%AD%90-Forge-DS--Components?node-id=11787-9802), [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/date-time-datefield--default)
|
|
4
|
+
|
|
5
|
+
`DateField` is a segmented input for typing a date or a month. Values are `DateId` strings — `YYYY-MM-DD` in date mode and `YYYY-MM-01` in month mode.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { DateField } from '@cdx-ui/components';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic
|
|
12
|
+
|
|
13
|
+
Wrap `DateField.Input` in `DateField.Group` and control the value with `value` and `onValueChange`. Empty segments show localized placeholders until the user types.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { useState } from 'react';
|
|
17
|
+
import { DateField } from '@cdx-ui/components';
|
|
18
|
+
import type { DateId, MonthId } from '@cdx-ui/formatters';
|
|
19
|
+
|
|
20
|
+
export default function DateFieldBasicDemo() {
|
|
21
|
+
const [value, setValue] = useState<DateId | MonthId | undefined>();
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<DateField
|
|
25
|
+
mode="date"
|
|
26
|
+
value={value}
|
|
27
|
+
onValueChange={setValue}
|
|
28
|
+
aria-label="Transfer date"
|
|
29
|
+
className="w-full max-w-xs"
|
|
30
|
+
>
|
|
31
|
+
<DateField.Group>
|
|
32
|
+
<DateField.Input />
|
|
33
|
+
</DateField.Group>
|
|
34
|
+
</DateField>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Month mode
|
|
40
|
+
|
|
41
|
+
Set `mode` to `month` to enter only a month and year. The wire value fixes the day to the first (`YYYY-MM-01`).
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { useState } from 'react';
|
|
45
|
+
import { DateField } from '@cdx-ui/components';
|
|
46
|
+
import { monthId, type DateId, type MonthId } from '@cdx-ui/formatters';
|
|
47
|
+
|
|
48
|
+
export default function DateFieldMonthDemo() {
|
|
49
|
+
const [value, setValue] = useState<DateId | MonthId | undefined>(monthId('2026-07-01'));
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<DateField
|
|
53
|
+
mode="month"
|
|
54
|
+
value={value}
|
|
55
|
+
onValueChange={setValue}
|
|
56
|
+
aria-label="Statement month"
|
|
57
|
+
className="w-full max-w-xs"
|
|
58
|
+
>
|
|
59
|
+
<DateField.Group>
|
|
60
|
+
<DateField.Input />
|
|
61
|
+
</DateField.Group>
|
|
62
|
+
</DateField>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## API
|
|
68
|
+
|
|
69
|
+
### DateField
|
|
70
|
+
|
|
71
|
+
Root of the compound. Owns the value, `mode`, and `locale`, and provides `variant`, `size`, and `fullWidth` styling context to `DateField.Group`.
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Default | Description |
|
|
74
|
+
| --- | --- | --- | --- |
|
|
75
|
+
| `className?` | `string` | — | — |
|
|
76
|
+
| `children?` | `ReactNode` | — | — |
|
|
77
|
+
| `variant?` | `'outline' \| null` | — | — |
|
|
78
|
+
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
79
|
+
| `fullWidth?` | `boolean` | — | When true (the default), the group stretches to fill its container; when false, it hugs the segments. |
|
|
80
|
+
| `labels?` | `Partial<DateComponentLabels>` | — | Overrides the accessible labels announced for each segment. |
|
|
81
|
+
| `asChild?` | `boolean` | — | — |
|
|
82
|
+
| `value?` | `DateId \| MonthId` | — | Controlled value: a `DateId` (`YYYY-MM-DD`) in date mode, or a `MonthId` (`YYYY-MM-01`) in month mode. Build one with `dateId(...)` / `monthId(...)` from `@cdx-ui/formatters` — a bare string will not type-check. |
|
|
83
|
+
| `defaultValue?` | `DateId \| MonthId` | — | Uncontrolled initial value, in the same format as `value`. |
|
|
84
|
+
| `onValueChange?` | `((value: DateId \| MonthId) => void)` | — | Called with the new value once every segment is filled, or `undefined` when the field is cleared. |
|
|
85
|
+
| `mode?` | `'date' \| 'month'` | — | Which segments to render: `date` shows month, day, and year; `month` shows month and year only. |
|
|
86
|
+
| `locale?` | `string` | — | BCP-47 locale that controls segment order and separators. Defaults to `en-US`. |
|
|
87
|
+
| `isDisabled?` | `boolean` | — | — |
|
|
88
|
+
| `isReadOnly?` | `boolean` | — | — |
|
|
89
|
+
| `isInvalid?` | `boolean` | — | — |
|
|
90
|
+
| `isRequired?` | `boolean` | — | — |
|
|
91
|
+
|
|
92
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
93
|
+
|
|
94
|
+
## Sub-components
|
|
95
|
+
|
|
96
|
+
### DateField.Group
|
|
97
|
+
|
|
98
|
+
Input chrome that surrounds the segments, sharing `Input`'s outline styling. Add a trailing `DateField.Suffix` inside it for a picker trigger.
|
|
99
|
+
|
|
100
|
+
| Prop | Type | Default | Description |
|
|
101
|
+
| --- | --- | --- | --- |
|
|
102
|
+
| `className?` | `string` | — | — |
|
|
103
|
+
| `children?` | `ReactNode` | — | — |
|
|
104
|
+
| `variant?` | `'outline' \| null` | — | — |
|
|
105
|
+
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
106
|
+
| `fullWidth?` | `boolean` | — | — |
|
|
107
|
+
|
|
108
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
109
|
+
|
|
110
|
+
### DateField.Input
|
|
111
|
+
|
|
112
|
+
Renders the editable segments. It renders styled segments by default; pass a render function as `children` to customize an individual segment.
|
|
113
|
+
|
|
114
|
+
| Prop | Type | Default | Description |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| `className?` | `string` | — | — |
|
|
117
|
+
| `children?` | `((segment: DateFieldSegmentPrimitiveProps["segment"]) => ReactNode)` | — | — |
|
|
118
|
+
| `slot?` | `'start' \| 'end'` | — | — |
|
|
119
|
+
|
|
120
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
121
|
+
|
|
122
|
+
### DateField.Segment
|
|
123
|
+
|
|
124
|
+
A single editable or literal segment, yielded to the `DateField.Input` render function so a specific segment type can be styled.
|
|
125
|
+
|
|
126
|
+
| Prop | Type | Default | Description |
|
|
127
|
+
| --- | --- | --- | --- |
|
|
128
|
+
| `className?` | `string` | — | — |
|
|
129
|
+
| `asChild?` | `boolean` | — | — |
|
|
130
|
+
| `segmentIndex?` | `number` | — | — |
|
|
131
|
+
| `segment` | `DateSegment` | — | — |
|
|
132
|
+
|
|
133
|
+
### DateField.Suffix
|
|
134
|
+
|
|
135
|
+
Trailing content inside `DateField.Group`, typically a picker trigger icon. Set `asChild` to render a custom trigger element in its place.
|
|
136
|
+
|
|
137
|
+
| Prop | Type | Default | Description |
|
|
138
|
+
| --- | --- | --- | --- |
|
|
139
|
+
| `className?` | `string` | — | — |
|
|
140
|
+
| `children?` | `ReactNode` | — | — |
|
|
141
|
+
| `asChild?` | `boolean` | — | — |
|
|
142
|
+
|
|
143
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
144
|
+
|
|
145
|
+
## Accessibility
|
|
146
|
+
|
|
147
|
+
Give the field an accessible name with `aria-label` or by pairing it with `Field.Label`; the root carries no label of its own. Each segment is individually focusable and editable with the keyboard, and `labels` overrides the name announced for each one. While `isDisabled` or `isReadOnly`, segments do not accept edits.
|