@cdx-ui/components 0.2.3 → 0.2.4
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 +235 -0
- package/docs/components/bottom-sheet/content.md +351 -0
- package/docs/components/bottom-sheet/design.md +249 -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 +416 -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 +86 -0
- package/docs/components/color-field/content.md +134 -0
- package/docs/components/color-picker/content.md +208 -0
- package/docs/components/color-slider/content.md +120 -0
- package/docs/components/color-swatch/content.md +64 -0
- package/docs/components/color-swatch-picker/content.md +126 -0
- package/docs/components/content.md +97 -0
- package/docs/components/currency-input/content.md +205 -0
- package/docs/components/data-grid/content.md +522 -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 +436 -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 +281 -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 +1247 -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 +309 -0
- package/docs/components/scoped-theme/content.md +47 -0
- package/docs/components/scroll-shadow/content.md +686 -0
- package/docs/components/select/content.md +400 -0
- package/docs/components/select/design.md +301 -0
- package/docs/components/skeleton/content.md +103 -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 +292 -0
- package/docs/components/text/content.md +142 -0
- package/docs/components/textarea/content.md +222 -0
- package/docs/components/tile/content.md +703 -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 +193 -0
- package/docs/llms.txt +193 -0
- package/docs/patterns/account-management/content.md +75 -0
- package/docs/patterns/authentication/content.md +52 -0
- package/docs/patterns/content.md +10 -0
- package/docs/patterns/dashboard/content.md +39 -0
- package/docs/patterns/empty-states/content.md +31 -0
- package/docs/patterns/forms/content.md +109 -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/content.md +64 -0
- 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/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/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/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/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/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/figma/ListItem.SectionHeader.figma.d.ts.map +1 -1
- package/package.json +8 -6
- 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/Tabs/index.tsx +25 -35
- package/src/components/Tabs/styles.ts +0 -9
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# ReorderableList (https://design.candescent.com/docs/components/reorderable-list)
|
|
2
|
+
|
|
3
|
+
Resources: [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/layout-reorderablelist--default)
|
|
4
|
+
|
|
5
|
+
Use `ReorderableList` for small ordered collections (accounts, favorites, dashboard tiles). Every row stays mounted so drop targets can be measured. For long read-only lists, use [`VirtualizedList`](https://design.candescent.com/docs/components/virtualized-list/content.md) instead.
|
|
6
|
+
|
|
7
|
+
Drag-to-reorder uses `react-native-sortables` on native and `@dnd-kit/sortable` on web. Compose rows the same way on both platforms.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
`ReorderableList` ships from its own entry point, `@cdx-ui/components/reorderable-list`, not the main `@cdx-ui/components` entry. Its drag engines are optional peer dependencies, so apps that never import that entry point do not install them. Install the ones for the platforms you target.
|
|
12
|
+
|
|
13
|
+
Native (iOS/Android) — also requires `react-native-gesture-handler` and `react-native-reanimated`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add react-native-sortables
|
|
17
|
+
# or: npm install react-native-sortables
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Web:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
|
|
24
|
+
# or: npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { ListItem } from '@cdx-ui/components';
|
|
29
|
+
import { ReorderableList } from '@cdx-ui/components/reorderable-list';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Basic
|
|
33
|
+
|
|
34
|
+
Compose with [`ListItem`](https://design.candescent.com/docs/components/list-item/content.md) and `ListItem.DragHandle`. Parent state owns `data`; `onReorder` receives the new array after a drop. Give the list a bounded height (same as `VirtualizedList`) so the `ScrollView` can layout; set flex sizing through `style` (for example `style={{ flex: 1 }}`) so native and web size the list the same way.
|
|
35
|
+
|
|
36
|
+
`keyExtractor` must return a stable, unique key per item — never the index. Keys identify rows while they move; duplicates log a warning in development.
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { useState } from 'react';
|
|
40
|
+
import { Avatar, Box, Card, ListItem } from '@cdx-ui/components';
|
|
41
|
+
import { ReorderableList } from '@cdx-ui/components/reorderable-list';
|
|
42
|
+
import { ChevronRight } from '@cdx-ui/icons';
|
|
43
|
+
|
|
44
|
+
const INITIAL = [
|
|
45
|
+
{ id: '1', name: 'Alex Anderson', role: 'Software Engineer' },
|
|
46
|
+
{ id: '2', name: 'Jordan Brooks', role: 'Product Designer' },
|
|
47
|
+
{ id: '3', name: 'Taylor Chen', role: 'Engineering Manager' },
|
|
48
|
+
{ id: '4', name: 'Morgan Davis', role: 'Data Scientist' },
|
|
49
|
+
{ id: '5', name: 'Casey Evans', role: 'QA Lead' },
|
|
50
|
+
{ id: '6', name: 'Riley Foster', role: 'Product Manager' },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
export default function ReorderableListBasicDemo() {
|
|
54
|
+
const [contacts, setContacts] = useState(INITIAL);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<Box className="h-96 w-full max-w-md">
|
|
58
|
+
<Card fullBleed className="flex-1">
|
|
59
|
+
<Card.Content className="flex-1">
|
|
60
|
+
<ReorderableList
|
|
61
|
+
data={contacts}
|
|
62
|
+
keyExtractor={(item) => item.id}
|
|
63
|
+
onReorder={setContacts}
|
|
64
|
+
style={{ flex: 1 }}
|
|
65
|
+
renderItem={({ item, index }) => (
|
|
66
|
+
<ListItem showSeparator={index < contacts.length - 1}>
|
|
67
|
+
<ListItem.DragHandle accessibilityLabel={`Reorder ${item.name}`} />
|
|
68
|
+
<ListItem.LeadingSlot>
|
|
69
|
+
<Avatar size="md">
|
|
70
|
+
<Avatar.Text>{item.name}</Avatar.Text>
|
|
71
|
+
</Avatar>
|
|
72
|
+
</ListItem.LeadingSlot>
|
|
73
|
+
<ListItem.Content>
|
|
74
|
+
<ListItem.Title>{item.name}</ListItem.Title>
|
|
75
|
+
<ListItem.Description>{item.role}</ListItem.Description>
|
|
76
|
+
</ListItem.Content>
|
|
77
|
+
<ListItem.TrailingSlot>
|
|
78
|
+
<ChevronRight size={20} />
|
|
79
|
+
</ListItem.TrailingSlot>
|
|
80
|
+
</ListItem>
|
|
81
|
+
)}
|
|
82
|
+
/>
|
|
83
|
+
</Card.Content>
|
|
84
|
+
</Card>
|
|
85
|
+
</Box>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Pressable rows
|
|
91
|
+
|
|
92
|
+
Rows can navigate with `onPress` (or `asChild` with a `Link`) and still reorder. Put `ListItem.DragHandle` first or last among the row's direct children: the row renders it beside the pressable element, so pressing the handle never opens the row.
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { useState } from 'react';
|
|
96
|
+
import { Box, Card, ListItem, Text } from '@cdx-ui/components';
|
|
97
|
+
import { ReorderableList } from '@cdx-ui/components/reorderable-list';
|
|
98
|
+
import { ChevronRight } from '@cdx-ui/icons';
|
|
99
|
+
|
|
100
|
+
const INITIAL = [
|
|
101
|
+
{ id: 'checking', name: 'Everyday Checking', balance: '$2,450.18' },
|
|
102
|
+
{ id: 'savings', name: 'High-Yield Savings', balance: '$12,903.55' },
|
|
103
|
+
{ id: 'credit', name: 'Rewards Credit Card', balance: '$384.20' },
|
|
104
|
+
{ id: 'loan', name: 'Auto Loan', balance: '$9,112.00' },
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
export default function ReorderableListPressableDemo() {
|
|
108
|
+
const [accounts, setAccounts] = useState(INITIAL);
|
|
109
|
+
const [opened, setOpened] = useState<string | null>(null);
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<Box className="w-full max-w-md gap-3">
|
|
113
|
+
<Card fullBleed>
|
|
114
|
+
<Card.Content>
|
|
115
|
+
<ReorderableList
|
|
116
|
+
data={accounts}
|
|
117
|
+
keyExtractor={(item) => item.id}
|
|
118
|
+
onReorder={setAccounts}
|
|
119
|
+
getItemLabel={(item) => item.name}
|
|
120
|
+
renderItem={({ item, index }) => (
|
|
121
|
+
<ListItem
|
|
122
|
+
onPress={() => setOpened(item.name)}
|
|
123
|
+
accessibilityLabel={`Open ${item.name}`}
|
|
124
|
+
showSeparator={index < accounts.length - 1}
|
|
125
|
+
>
|
|
126
|
+
<ListItem.DragHandle accessibilityLabel={`Reorder ${item.name}`} />
|
|
127
|
+
<ListItem.Content>
|
|
128
|
+
<ListItem.Title>{item.name}</ListItem.Title>
|
|
129
|
+
<ListItem.Description>{item.balance}</ListItem.Description>
|
|
130
|
+
</ListItem.Content>
|
|
131
|
+
<ListItem.TrailingSlot>
|
|
132
|
+
<ChevronRight size={20} />
|
|
133
|
+
</ListItem.TrailingSlot>
|
|
134
|
+
</ListItem>
|
|
135
|
+
)}
|
|
136
|
+
/>
|
|
137
|
+
</Card.Content>
|
|
138
|
+
</Card>
|
|
139
|
+
<Text aria-live="polite">{opened ? `Opened ${opened}` : 'Select an account'}</Text>
|
|
140
|
+
</Box>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Scrollable content
|
|
146
|
+
|
|
147
|
+
When the rows overflow the list's height, the list scrolls on its own. Dragging a row near the top or bottom edge auto-scrolls so the row can reach any position.
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { useState } from 'react';
|
|
151
|
+
import { Box, Card, ListItem } from '@cdx-ui/components';
|
|
152
|
+
import { ReorderableList } from '@cdx-ui/components/reorderable-list';
|
|
153
|
+
|
|
154
|
+
const INITIAL = [
|
|
155
|
+
{ id: 'rent', name: 'Rent', detail: 'Due on the 1st' },
|
|
156
|
+
{ id: 'electric', name: 'City Electric', detail: 'Autopay' },
|
|
157
|
+
{ id: 'water', name: 'Water & Sewer', detail: 'Due on the 12th' },
|
|
158
|
+
{ id: 'internet', name: 'Fiber Internet', detail: 'Autopay' },
|
|
159
|
+
{ id: 'phone', name: 'Mobile Phone', detail: 'Due on the 18th' },
|
|
160
|
+
{ id: 'auto-loan', name: 'Auto Loan', detail: 'Due on the 20th' },
|
|
161
|
+
{ id: 'insurance', name: 'Auto Insurance', detail: 'Autopay' },
|
|
162
|
+
{ id: 'daycare', name: 'Little Oaks Daycare', detail: 'Due on the 1st' },
|
|
163
|
+
{ id: 'gym', name: 'Gym Membership', detail: 'Autopay' },
|
|
164
|
+
{ id: 'streaming', name: 'Streaming', detail: 'Autopay' },
|
|
165
|
+
{ id: 'student-loan', name: 'Student Loan', detail: 'Due on the 25th' },
|
|
166
|
+
{ id: 'credit-card', name: 'Rewards Credit Card', detail: 'Due on the 28th' },
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
export default function ReorderableListScrollableDemo() {
|
|
170
|
+
const [payees, setPayees] = useState(INITIAL);
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<Box className="h-80 w-full max-w-md">
|
|
174
|
+
<Card fullBleed className="flex-1">
|
|
175
|
+
<Card.Content className="flex-1">
|
|
176
|
+
<ReorderableList
|
|
177
|
+
data={payees}
|
|
178
|
+
keyExtractor={(item) => item.id}
|
|
179
|
+
onReorder={setPayees}
|
|
180
|
+
getItemLabel={(item) => item.name}
|
|
181
|
+
style={{ flex: 1 }}
|
|
182
|
+
renderItem={({ item, index }) => (
|
|
183
|
+
<ListItem size="compact" showSeparator={index < payees.length - 1}>
|
|
184
|
+
<ListItem.DragHandle accessibilityLabel={`Reorder ${item.name}`} />
|
|
185
|
+
<ListItem.Content>
|
|
186
|
+
<ListItem.Title>{item.name}</ListItem.Title>
|
|
187
|
+
<ListItem.Description>{item.detail}</ListItem.Description>
|
|
188
|
+
</ListItem.Content>
|
|
189
|
+
</ListItem>
|
|
190
|
+
)}
|
|
191
|
+
/>
|
|
192
|
+
</Card.Content>
|
|
193
|
+
</Card>
|
|
194
|
+
</Box>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Removing rows
|
|
200
|
+
|
|
201
|
+
To remove a row, filter it out of `data`; the remaining rows close the gap. Put the remove control in `ListItem.TrailingSlot` and name the row in its label.
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import { useState } from 'react';
|
|
205
|
+
import { Box, Button, Card, IconButton, ListItem, Text } from '@cdx-ui/components';
|
|
206
|
+
import { ReorderableList } from '@cdx-ui/components/reorderable-list';
|
|
207
|
+
import { Delete } from '@cdx-ui/icons';
|
|
208
|
+
|
|
209
|
+
const INITIAL = [
|
|
210
|
+
{ id: 'rent', name: 'Rent', detail: 'Due on the 1st' },
|
|
211
|
+
{ id: 'electric', name: 'City Electric', detail: 'Autopay' },
|
|
212
|
+
{ id: 'water', name: 'Water & Sewer', detail: 'Due on the 12th' },
|
|
213
|
+
{ id: 'internet', name: 'Fiber Internet', detail: 'Autopay' },
|
|
214
|
+
{ id: 'phone', name: 'Mobile Phone', detail: 'Due on the 18th' },
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
export default function ReorderableListRemovableDemo() {
|
|
218
|
+
const [payees, setPayees] = useState(INITIAL);
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<Box className="w-full max-w-md gap-3">
|
|
222
|
+
<Card fullBleed>
|
|
223
|
+
<Card.Content>
|
|
224
|
+
{payees.length > 0 ? (
|
|
225
|
+
<ReorderableList
|
|
226
|
+
data={payees}
|
|
227
|
+
keyExtractor={(item) => item.id}
|
|
228
|
+
onReorder={setPayees}
|
|
229
|
+
getItemLabel={(item) => item.name}
|
|
230
|
+
renderItem={({ item, index }) => (
|
|
231
|
+
<ListItem size="compact" showSeparator={index < payees.length - 1}>
|
|
232
|
+
<ListItem.DragHandle accessibilityLabel={`Reorder ${item.name}`} />
|
|
233
|
+
<ListItem.Content>
|
|
234
|
+
<ListItem.Title>{item.name}</ListItem.Title>
|
|
235
|
+
<ListItem.Description>{item.detail}</ListItem.Description>
|
|
236
|
+
</ListItem.Content>
|
|
237
|
+
<ListItem.TrailingSlot>
|
|
238
|
+
<IconButton
|
|
239
|
+
as={Delete}
|
|
240
|
+
variant="ghost"
|
|
241
|
+
size="small"
|
|
242
|
+
accessibilityLabel={`Remove ${item.name}`}
|
|
243
|
+
onPress={() =>
|
|
244
|
+
setPayees((current) => current.filter((payee) => payee.id !== item.id))
|
|
245
|
+
}
|
|
246
|
+
/>
|
|
247
|
+
</ListItem.TrailingSlot>
|
|
248
|
+
</ListItem>
|
|
249
|
+
)}
|
|
250
|
+
/>
|
|
251
|
+
) : (
|
|
252
|
+
<Text className="body-sm text-content-secondary p-4">No payees left.</Text>
|
|
253
|
+
)}
|
|
254
|
+
</Card.Content>
|
|
255
|
+
</Card>
|
|
256
|
+
<Button variant="outline" onPress={() => setPayees(INITIAL)}>
|
|
257
|
+
<Button.Label>Reset</Button.Label>
|
|
258
|
+
</Button>
|
|
259
|
+
</Box>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## API
|
|
265
|
+
|
|
266
|
+
### ReorderableList
|
|
267
|
+
|
|
268
|
+
| Prop | Type | Default | Description |
|
|
269
|
+
| --- | --- | --- | --- |
|
|
270
|
+
| `className?` | `string` | — | — |
|
|
271
|
+
| `data` | `unknown[]` | — | Items in their current order. The parent owns this array and updates it from `onReorder`. |
|
|
272
|
+
| `keyExtractor` | `(item: unknown, index: number) => string` | — | Returns a stable, unique key for an item. Keys identify rows while they move, so they must not be derived from `index`. Duplicate keys log a warning in development. |
|
|
273
|
+
| `renderItem` | `(info: ReorderableListRenderItemInfo<unknown>) => ReactNode` | — | Renders one row. Compose with `ListItem` and `ListItem.DragHandle`. |
|
|
274
|
+
| `onReorder` | `(data: unknown[]) => void` | — | Called with the reordered array after a drop or an accessibility move. |
|
|
275
|
+
| `onReorderIndices?` | `((from: number, to: number) => void)` | — | Called after `onReorder` with the moved row's previous and new zero-based positions. |
|
|
276
|
+
| `getItemLabel?` | `((item: unknown, index: number) => string)` | — | Returns the name screen readers use for a row in reorder announcements. Without it, announcements use the `item` label (`item 2`). Keys are never announced. |
|
|
277
|
+
| `labels?` | `Partial<ReorderableListLabels>` | `{}` | Overrides for announcement and accessibility-action copy. Unset keys keep their defaults. |
|
|
278
|
+
|
|
279
|
+
Inherits [`ScrollViewProps`](https://reactnative.dev/docs/scrollview#props) except `children`, `horizontal`, and `role`, which the list owns. `onScroll` and `onContentSizeChange` pass through to the `ScrollView`.
|
|
280
|
+
|
|
281
|
+
### Labels
|
|
282
|
+
|
|
283
|
+
Pass `labels` to translate or reword announcements and accessibility actions. `{item}` is the row name (from `getItemLabel`, or `item {position}`), `{position}` is 1-based, and `{count}` is the number of rows.
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
<ReorderableList
|
|
287
|
+
getItemLabel={(account) => account.nickname}
|
|
288
|
+
labels={{ movedTo: '{item} déplacé en position {position} sur {count}.' }}
|
|
289
|
+
{...props}
|
|
290
|
+
/>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Anatomy
|
|
294
|
+
|
|
295
|
+
| `data-slot` | Element |
|
|
296
|
+
| ----------------------- | ------------------------------- |
|
|
297
|
+
| `reorderable-list` | Scrollable list root |
|
|
298
|
+
| `list-item-drag-handle` | Handle on a composed `ListItem` |
|
|
299
|
+
|
|
300
|
+
## Accessibility
|
|
301
|
+
|
|
302
|
+
| Attribute | Behavior |
|
|
303
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
304
|
+
| **Role** | Root sets `role="list"`. |
|
|
305
|
+
| **Handle** | `ListItem.DragHandle` is a button with default label `Reorder`. Pass a row-specific `accessibilityLabel`. On native its default hint names the move actions; on web the keyboard instructions are linked through `aria-describedby`. |
|
|
306
|
+
| **Activation** | Drag starts from the handle, which sits beside a pressable row's interactive element rather than inside it, so row `onPress` can still navigate. The click that ends a pointer drag does not press the row. |
|
|
307
|
+
| **Single-pointer alternative** | On native, each handle exposes `Move up`, `Move down`, `Move to top`, and `Move to bottom` accessibility actions; actions that do not apply at the ends are omitted. |
|
|
308
|
+
| **Keyboard (web)** | Focus the handle, press Space or Enter to pick up, the arrow keys to move, Space or Enter to drop, or Escape to cancel. |
|
|
309
|
+
| **Announcements** | Pick-up, move, drop, and cancel are announced by position (`Moved item 2 to position 3 of 5.`). Pass `getItemLabel` to name rows; keys are never announced. |
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# ScopedTheme (https://design.candescent.com/docs/components/scoped-theme)
|
|
2
|
+
|
|
3
|
+
Resources: [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/theming-scopedtheme--default)
|
|
4
|
+
|
|
5
|
+
`ScopedTheme` locks a subtree to one theme, for a section, widget, or preview that must stay in a fixed mode.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { ScopedTheme } from '@cdx-ui/components';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic
|
|
12
|
+
|
|
13
|
+
Force dark tokens on the wrapped content. On web the wrapper is a `display: contents` element with the theme class, so CSS variables cascade into the children. On iOS and Android the theme is applied through React context.
|
|
14
|
+
|
|
15
|
+
On web, `theme="light"` applies when no `.dark` ancestor is present. There is no light custom variant to override one. Native honors either value through context.
|
|
16
|
+
|
|
17
|
+
Web apps enable the class cascade with the dark custom variant in `global.css`. See [Getting Started](https://design.candescent.com/docs/getting-started/developers/content.md).
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { Card, Heading, ScopedTheme, Text } from '@cdx-ui/components';
|
|
21
|
+
|
|
22
|
+
export default function ScopedThemeBasicDemo() {
|
|
23
|
+
return (
|
|
24
|
+
<ScopedTheme theme="dark">
|
|
25
|
+
<Card className="w-full max-w-md">
|
|
26
|
+
<Card.Header>
|
|
27
|
+
<Heading size="sm">Dark section</Heading>
|
|
28
|
+
</Card.Header>
|
|
29
|
+
<Card.Content>
|
|
30
|
+
<Text size="sm">This content always renders in dark mode.</Text>
|
|
31
|
+
</Card.Content>
|
|
32
|
+
</Card>
|
|
33
|
+
</ScopedTheme>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## API
|
|
39
|
+
|
|
40
|
+
### ScopedTheme
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Default | Description |
|
|
43
|
+
| --- | --- | --- | --- |
|
|
44
|
+
| `theme` | `string` | — | The theme forced on the subtree, such as `'dark'` or `'light'`. |
|
|
45
|
+
| `children?` | `React.ReactNode` | — | The subtree that renders in `theme`. |
|
|
46
|
+
|
|
47
|
+
Does not extend a React Native base component — every prop is listed above. Forge UI themes are `light` and `dark`.
|