@cdx-ui/components 0.3.3 → 0.3.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/coverage.svg +1 -1
- package/docs/components/color-field/content.md +2 -2
- package/docs/components/content.md +4 -4
- package/docs/components/date-field/content.md +2 -2
- package/docs/components/date-time-field/content.md +2 -2
- package/docs/components/input/content.md +20 -2
- package/docs/components/input/design.md +1 -1
- package/docs/components/insurance-disclosure/content.md +1 -1
- package/docs/components/otp-input/content.md +2 -2
- package/docs/components/select/content.md +223 -24
- package/docs/components/text/content.md +97 -0
- package/docs/llms.txt +5 -4
- package/docs/patterns/forms/content.md +152 -0
- package/docs/resources/release-notes/0.3.3/content.md +23 -0
- package/docs/resources/release-notes/content.md +1 -0
- package/lib/commonjs/components/Drawer/index.js +1 -1
- package/lib/commonjs/components/Drawer/index.js.map +1 -1
- package/lib/commonjs/components/Input/index.js.map +1 -1
- package/lib/commonjs/components/Input/styles.js +13 -6
- package/lib/commonjs/components/Input/styles.js.map +1 -1
- package/lib/commonjs/components/OtpInput/index.js.map +1 -1
- package/lib/commonjs/components/Select/index.js +326 -24
- package/lib/commonjs/components/Select/index.js.map +1 -1
- package/lib/commonjs/components/Select/styles.js +32 -1
- package/lib/commonjs/components/Select/styles.js.map +1 -1
- package/lib/commonjs/components/picker/surfaces.js +18 -3
- package/lib/commonjs/components/picker/surfaces.js.map +1 -1
- package/lib/module/components/Drawer/index.js +1 -1
- package/lib/module/components/Drawer/index.js.map +1 -1
- package/lib/module/components/Input/index.js.map +1 -1
- package/lib/module/components/Input/styles.js +14 -6
- package/lib/module/components/Input/styles.js.map +1 -1
- package/lib/module/components/OtpInput/index.js.map +1 -1
- package/lib/module/components/Select/index.js +328 -26
- package/lib/module/components/Select/index.js.map +1 -1
- package/lib/module/components/Select/styles.js +31 -0
- package/lib/module/components/Select/styles.js.map +1 -1
- package/lib/module/components/picker/surfaces.js +17 -3
- package/lib/module/components/picker/surfaces.js.map +1 -1
- package/lib/typescript/components/ColorField/styles.d.ts +4 -2
- package/lib/typescript/components/ColorField/styles.d.ts.map +1 -1
- package/lib/typescript/components/DateField/styles.d.ts +4 -2
- package/lib/typescript/components/DateField/styles.d.ts.map +1 -1
- package/lib/typescript/components/Input/index.d.ts +3 -2
- package/lib/typescript/components/Input/index.d.ts.map +1 -1
- package/lib/typescript/components/Input/styles.d.ts +1 -1
- package/lib/typescript/components/Input/styles.d.ts.map +1 -1
- package/lib/typescript/components/OtpInput/index.d.ts +3 -2
- package/lib/typescript/components/OtpInput/index.d.ts.map +1 -1
- package/lib/typescript/components/Select/index.d.ts +73 -6
- package/lib/typescript/components/Select/index.d.ts.map +1 -1
- package/lib/typescript/components/Select/styles.d.ts +9 -0
- package/lib/typescript/components/Select/styles.d.ts.map +1 -1
- package/lib/typescript/components/picker/surfaces.d.ts +14 -3
- package/lib/typescript/components/picker/surfaces.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/components/ColorField/styles.ts +3 -1
- package/src/components/DateField/styles.ts +6 -1
- package/src/components/Drawer/index.tsx +1 -1
- package/src/components/Input/index.tsx +3 -2
- package/src/components/Input/styles.ts +35 -15
- package/src/components/OtpInput/index.tsx +3 -2
- package/src/components/Select/index.tsx +411 -29
- package/src/components/Select/styles.ts +36 -0
- package/src/components/picker/surfaces.tsx +29 -4
package/coverage.svg
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="108" height="20" role="img" aria-label="coverage:
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="108" height="20" role="img" aria-label="coverage: 93.1%"><title>coverage: 93.1%</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">93.1%</text><text x="835" y="150" fill-opacity=".3" textLength="370">93.1%</text></g><text x="835" y="140" textLength="370">93.1%</text></g></g></svg>
|
|
@@ -53,7 +53,7 @@ Owns standalone text and color state or edits the shared value when nested in `C
|
|
|
53
53
|
| --- | --- | --- | --- |
|
|
54
54
|
| `className?` | `string` | — | — |
|
|
55
55
|
| `children?` | `ReactNode` | — | — |
|
|
56
|
-
| `variant?` | `'outline'
|
|
56
|
+
| `variant?` | `'outline'` | — | — |
|
|
57
57
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
58
58
|
| `value?` | `Color` | — | — |
|
|
59
59
|
| `defaultValue?` | `Color` | — | — |
|
|
@@ -79,7 +79,7 @@ Provides the styled input shell and optional slots.
|
|
|
79
79
|
| --- | --- | --- | --- |
|
|
80
80
|
| `className?` | `string` | — | — |
|
|
81
81
|
| `children?` | `ReactNode` | — | — |
|
|
82
|
-
| `variant?` | `'outline'
|
|
82
|
+
| `variant?` | `'outline'` | — | — |
|
|
83
83
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
84
84
|
| `asChild?` | `boolean` | — | — |
|
|
85
85
|
| `fullWidth?` | `boolean` | — | — |
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
- [Currency Input](https://design.candescent.com/docs/components/currency-input/content.md) — A calculator-style monetary input that formats digits as currency while the user types.
|
|
15
15
|
- [Field](https://design.candescent.com/docs/components/field/content.md) — A form-control wrapper that coordinates labels, supporting text, validation messages, and shared state.
|
|
16
16
|
- [Form](https://design.candescent.com/docs/components/form/content.md) — A container that spaces related fields vertically and renders a form on web or a view on native.
|
|
17
|
-
- [Input
|
|
17
|
+
- [Input](https://design.candescent.com/docs/components/input/content.md) — A single-line text entry with optional label, helper text, and adornments.
|
|
18
18
|
- [Menu](https://design.candescent.com/docs/components/menu/content.md) — Menus present actions or selectable options in an anchored overlay or a standalone list surface.
|
|
19
|
-
- [OTP Input
|
|
19
|
+
- [OTP Input](https://design.candescent.com/docs/components/otp-input/content.md) — A controlled multi-cell input for one-time passwords and verification codes.
|
|
20
20
|
- [Radio](https://design.candescent.com/docs/components/radio/content.md) — A radio group is an input control that allows the user to select a single option from a set of mutually exclusive options.
|
|
21
21
|
- [Range Calendar](https://design.candescent.com/docs/components/range-calendar/content.md) — A two-tap day grid for selecting a start and end date, with a continuous range band, month navigation, and a year picker.
|
|
22
|
-
- [Select](https://design.candescent.com/docs/components/select/content.md) — A form control that allows users to choose one
|
|
22
|
+
- [Select](https://design.candescent.com/docs/components/select/content.md) — A form control that allows users to choose one or more options from a dropdown list.
|
|
23
23
|
- [Textarea](https://design.candescent.com/docs/components/textarea/content.md) — A multi-line text entry for longer free-form content.
|
|
24
24
|
- [Slider](https://design.candescent.com/docs/components/slider/content.md) — A control for selecting a numeric value along a track.
|
|
25
25
|
- [Color Picker](https://design.candescent.com/docs/components/color-picker/content.md) — A compound color picker that coordinates an opaque color value with a trigger and popover.
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
- [Avatar](https://design.candescent.com/docs/components/avatar/content.md) — A visual representation of a user or entity, displayed as an image, initials, or fallback icon.
|
|
59
59
|
- [Carousel](https://design.candescent.com/docs/components/carousel/content.md) — A swipeable, paginated carousel for promotional banners, onboarding, and card browsing. Wraps react-native-reanimated-carousel with token-styled Pagination and Prev/Next nav button compounds plus useCarousel hook.
|
|
60
60
|
- [Divider](https://design.candescent.com/docs/components/divider/content.md) — A horizontal or vertical separator for grouping related content, with an optional inline label.
|
|
61
|
-
- [
|
|
61
|
+
- [Insurance Disclosure](https://design.candescent.com/docs/components/insurance-disclosure/content.md) — Domain-specific regulatory disclosure — official FDIC lockup with optional copy for account footers, deposit screens, and onboarding.
|
|
62
62
|
- [Icon](https://design.candescent.com/docs/components/icon/content.md) — A cross-platform SVG icon wrapper with semantic color, sizing, filled variants, and accessibility support.
|
|
63
63
|
- [Image](https://design.candescent.com/docs/components/image/content.md) — Displays local or remote images across native and web platforms.
|
|
64
64
|
- [List Item](https://design.candescent.com/docs/components/list-item/content.md) — A composable row for display and navigation — accounts, transactions, alerts, settings, and nav rows.
|
|
@@ -74,7 +74,7 @@ Root of the compound. Owns the value, `mode`, and `locale`, and provides `varian
|
|
|
74
74
|
| --- | --- | --- | --- |
|
|
75
75
|
| `className?` | `string` | — | — |
|
|
76
76
|
| `children?` | `ReactNode` | — | — |
|
|
77
|
-
| `variant?` | `'outline'
|
|
77
|
+
| `variant?` | `'outline'` | — | — |
|
|
78
78
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
79
79
|
| `fullWidth?` | `boolean` | — | When true (the default), the group stretches to fill its container; when false, it hugs the segments. |
|
|
80
80
|
| `labels?` | `Partial<DateComponentLabels>` | — | Overrides the accessible labels announced for each segment. |
|
|
@@ -101,7 +101,7 @@ Input chrome that surrounds the segments, sharing `Input`'s outline styling. Add
|
|
|
101
101
|
| --- | --- | --- | --- |
|
|
102
102
|
| `className?` | `string` | — | — |
|
|
103
103
|
| `children?` | `ReactNode` | — | — |
|
|
104
|
-
| `variant?` | `'outline'
|
|
104
|
+
| `variant?` | `'outline'` | — | — |
|
|
105
105
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
106
106
|
| `fullWidth?` | `boolean` | — | — |
|
|
107
107
|
|
|
@@ -80,7 +80,7 @@ Root of the compound. Owns the value, `granularity`, `hour12`, and `locale`, and
|
|
|
80
80
|
| --- | --- | --- | --- |
|
|
81
81
|
| `className?` | `string` | — | — |
|
|
82
82
|
| `children?` | `ReactNode` | — | — |
|
|
83
|
-
| `variant?` | `'outline'
|
|
83
|
+
| `variant?` | `'outline'` | — | — |
|
|
84
84
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
85
85
|
| `fullWidth?` | `boolean` | — | When true (the default), the group stretches to fill its container; when false, it hugs the segments. |
|
|
86
86
|
| `asChild?` | `boolean` | — | — |
|
|
@@ -109,7 +109,7 @@ Input chrome that surrounds the segments, shared with [`DateField.Group`](https:
|
|
|
109
109
|
| `className?` | `string` | — | — |
|
|
110
110
|
| `children?` | `ReactNode` | — | — |
|
|
111
111
|
| `ref?` | `React.Ref<View>` | — | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). |
|
|
112
|
-
| `variant?` | `'outline'
|
|
112
|
+
| `variant?` | `'outline'` | — | — |
|
|
113
113
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
114
114
|
| `fullWidth?` | `boolean` | — | — |
|
|
115
115
|
| `key?` | `React.Key \| null` | — | — |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Input
|
|
1
|
+
# Input (https://design.candescent.com/docs/components/input)
|
|
2
2
|
|
|
3
3
|
Resources: [Figma](https://www.figma.com/design/0lEVMVlLj8ZS4fgItr3pmd/%E2%AD%90-CDS-V2--React-Native?node-id=159-22), [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/inputs-input--default)
|
|
4
4
|
|
|
@@ -22,6 +22,24 @@ export default function InputBasicDemo() {
|
|
|
22
22
|
}
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Subtle
|
|
26
|
+
|
|
27
|
+
Use `variant="subtle"` for a filled, borderless field on a surface that already frames it, such as a search field at the top of a popover or sheet. Focus, invalid, disabled, and read-only states stay visible in both variants.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { Input } from '@cdx-ui/components';
|
|
31
|
+
import { Search } from '@cdx-ui/icons';
|
|
32
|
+
|
|
33
|
+
export default function InputSubtleDemo() {
|
|
34
|
+
return (
|
|
35
|
+
<Input variant="subtle">
|
|
36
|
+
<Input.Icon as={Search} />
|
|
37
|
+
<Input.Field accessibilityLabel="Search teams" placeholder="Search teams" />
|
|
38
|
+
</Input>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
25
43
|
## Sizes
|
|
26
44
|
|
|
27
45
|
```tsx
|
|
@@ -266,7 +284,7 @@ The root shell that lays out the field alongside optional slots and icons, and p
|
|
|
266
284
|
| `className?` | `string` | — | Additional Uniwind/Tailwind classes, merged after the shell's own styles. |
|
|
267
285
|
| `children?` | `ReactNode` | — | Shell content — typically `Input.Field` plus optional `Input.Slot`/`Input.Icon`. |
|
|
268
286
|
| `asChild?` | `boolean` | — | Render the consumer's child element in place of the default `View` host. |
|
|
269
|
-
| `variant?` | `'outline'` | `'outline'` | Visual style variant. |
|
|
287
|
+
| `variant?` | `'outline' \| 'subtle'` | `'outline'` | Visual style variant. `outline` is a bordered field on the page surface; `subtle` is a filled, borderless field for dense or nested surfaces such as a search field in a popup. |
|
|
270
288
|
| `size?` | `'default' \| 'small'` | `'default'` | Height, padding, and field font size. |
|
|
271
289
|
| `isInvalid?` | `boolean` | — | If true, the input will indicate an error. |
|
|
272
290
|
| `isDisabled?` | `boolean` | — | If true, the input will be disabled. |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Insurance Disclosure (https://design.candescent.com/docs/components/insurance-disclosure)
|
|
2
2
|
|
|
3
3
|
Resources: [Figma](https://www.figma.com/design/0lEVMVlLj8ZS4fgItr3pmd/%E2%AD%90-Forge-DS--Components?node-id=8550-3291), [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/domain-insurancedisclosure--default)
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# OTP Input
|
|
1
|
+
# OTP Input (https://design.candescent.com/docs/components/otp-input)
|
|
2
2
|
|
|
3
3
|
Resources: [Figma](https://www.figma.com/design/0lEVMVlLj8ZS4fgItr3pmd/%E2%AD%90-Forge-DS--Components?node-id=5653-5035), [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/inputs-otpinput--default)
|
|
4
4
|
|
|
@@ -298,7 +298,7 @@ Styled cell chrome built on `Input`. Inherits variant and size from the parent `
|
|
|
298
298
|
| --- | --- | --- | --- |
|
|
299
299
|
| `className?` | `string` | — | — |
|
|
300
300
|
| `children?` | `React.ReactNode` | — | — |
|
|
301
|
-
| `variant?` | `'outline'
|
|
301
|
+
| `variant?` | `'outline'` | — | — |
|
|
302
302
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
303
303
|
| `isInvalid?` | `boolean` | — | — |
|
|
304
304
|
| `isReadOnly?` | `boolean` | — | — |
|
|
@@ -107,6 +107,120 @@ export default function SelectWithFieldDemo() {
|
|
|
107
107
|
}
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
## Multiple selection
|
|
111
|
+
|
|
112
|
+
Set `type="multiple"` to let users pick several options. `value` becomes a `string[]`, each press toggles an option and keeps the dropdown open, and every toggle calls `onValueChange` with the full array. Add `Select.ItemControl` for a leading checkbox. Without custom children, `Select.Value` shows the selected labels on one line.
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
import { useState } from 'react';
|
|
116
|
+
import { Field, Select } from '@cdx-ui/components';
|
|
117
|
+
import { teams } from './_data';
|
|
118
|
+
|
|
119
|
+
export default function SelectMultipleDemo() {
|
|
120
|
+
const [teamIds, setTeamIds] = useState<string[]>([]);
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<Field className="w-full" isRequired>
|
|
124
|
+
<Field.Label>Assign teams</Field.Label>
|
|
125
|
+
<Select type="multiple" items={teams} value={teamIds} onValueChange={setTeamIds} isRequired>
|
|
126
|
+
<Select.Trigger>
|
|
127
|
+
<Select.Value placeholder="Select teams">
|
|
128
|
+
{({ isPlaceholder, selectedItems }) =>
|
|
129
|
+
isPlaceholder ? null : `${selectedItems.length} teams selected`
|
|
130
|
+
}
|
|
131
|
+
</Select.Value>
|
|
132
|
+
</Select.Trigger>
|
|
133
|
+
<Select.Content>
|
|
134
|
+
{teams.map((team) => (
|
|
135
|
+
<Select.Item key={team.value} value={team.value}>
|
|
136
|
+
<Select.ItemControl />
|
|
137
|
+
<Select.ItemLabel>{team.label}</Select.ItemLabel>
|
|
138
|
+
</Select.Item>
|
|
139
|
+
))}
|
|
140
|
+
</Select.Content>
|
|
141
|
+
</Select>
|
|
142
|
+
<Field.Helper>Each change applies immediately.</Field.Helper>
|
|
143
|
+
</Field>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## With search
|
|
149
|
+
|
|
150
|
+
Add `Select.Search` as the first child of `Select.Content` to build a searchable select, the pattern other libraries call an autocomplete. Typing filters the options in both `single` and `multiple` mode, and `Select.Empty` shows when nothing matches. Selected options that the query hides stay selected and still count in `Select.Value`. The default filter is a case- and accent-insensitive "contains" on each option's `label`; pass `filter` to replace it, or control `inputValue` and `onInputChange` to swap `items` for server results. The query clears when the dropdown closes.
|
|
151
|
+
|
|
152
|
+
In `Select.Content` on iOS and Android, the search input renders inside the anchored dropdown and the on-screen keyboard can cover the options. Use `Select.BottomSheet` for native search.
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { useState } from 'react';
|
|
156
|
+
import { Field, Select } from '@cdx-ui/components';
|
|
157
|
+
import { teams } from './_data';
|
|
158
|
+
|
|
159
|
+
export default function SelectWithSearchDemo() {
|
|
160
|
+
const [teamIds, setTeamIds] = useState<string[]>([]);
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<Field className="w-full" isRequired>
|
|
164
|
+
<Field.Label>Assign teams</Field.Label>
|
|
165
|
+
<Select type="multiple" items={teams} value={teamIds} onValueChange={setTeamIds}>
|
|
166
|
+
<Select.Trigger>
|
|
167
|
+
<Select.Value placeholder="Select teams you want to assign to this user">
|
|
168
|
+
{({ isPlaceholder, selectedItems }) =>
|
|
169
|
+
isPlaceholder ? null : `${String(selectedItems.length)} teams selected`
|
|
170
|
+
}
|
|
171
|
+
</Select.Value>
|
|
172
|
+
</Select.Trigger>
|
|
173
|
+
<Select.Content>
|
|
174
|
+
<Select.Search placeholder="Search Teams" accessibilityLabel="Search teams" />
|
|
175
|
+
{teams.map((t) => (
|
|
176
|
+
<Select.Item key={t.value} value={t.value} disabled={t.disabled}>
|
|
177
|
+
<Select.ItemControl />
|
|
178
|
+
<Select.ItemLabel>{t.label}</Select.ItemLabel>
|
|
179
|
+
</Select.Item>
|
|
180
|
+
))}
|
|
181
|
+
<Select.Empty>No teams found</Select.Empty>
|
|
182
|
+
</Select.Content>
|
|
183
|
+
</Select>
|
|
184
|
+
</Field>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Bottom sheet
|
|
190
|
+
|
|
191
|
+
Use `Select.BottomSheet` in place of `Select.Content` to present the options in a sheet that slides up from the bottom — the preferred surface on native, especially with `Select.Search`. It takes the same children: `Select.Search`, the options, and `Select.Empty`. The sheet keeps the search input and the results above the on-screen keyboard, and swiping it down, pressing the backdrop, or pressing Android back closes it without changing the value. On web it renders the same dropdown as `Select.Content`, so one composition serves every platform. On native it requires `BottomSheet.Provider` at the app root.
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import { useState } from 'react';
|
|
195
|
+
import { Field, Select } from '@cdx-ui/components';
|
|
196
|
+
import { teams } from './_data';
|
|
197
|
+
|
|
198
|
+
export default function SelectBottomSheetDemo() {
|
|
199
|
+
const [teamIds, setTeamIds] = useState<string[]>([]);
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<Field className="w-full">
|
|
203
|
+
<Field.Label>Assign teams</Field.Label>
|
|
204
|
+
<Select type="multiple" items={teams} value={teamIds} onValueChange={setTeamIds}>
|
|
205
|
+
<Select.Trigger>
|
|
206
|
+
<Select.Value placeholder="Select teams" />
|
|
207
|
+
</Select.Trigger>
|
|
208
|
+
<Select.BottomSheet>
|
|
209
|
+
<Select.Search placeholder="Search Teams" accessibilityLabel="Search teams" />
|
|
210
|
+
{teams.map((t) => (
|
|
211
|
+
<Select.Item key={t.value} value={t.value} disabled={t.disabled}>
|
|
212
|
+
<Select.ItemControl />
|
|
213
|
+
<Select.ItemLabel>{t.label}</Select.ItemLabel>
|
|
214
|
+
</Select.Item>
|
|
215
|
+
))}
|
|
216
|
+
<Select.Empty>No teams found</Select.Empty>
|
|
217
|
+
</Select.BottomSheet>
|
|
218
|
+
</Select>
|
|
219
|
+
</Field>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
110
224
|
## Custom trigger
|
|
111
225
|
|
|
112
226
|
Set `asChild` on `Select.Trigger` to use a Forge pressable such as `Button`, `IconButton`, or `Chip`. Use the trigger and item `indicator` props to replace their default icons, or pass `null` to suppress an indicator.
|
|
@@ -145,7 +259,7 @@ export default function SelectCustomTriggerDemo() {
|
|
|
145
259
|
|
|
146
260
|
## Custom value display
|
|
147
261
|
|
|
148
|
-
Pass children to `Select.Value` to replace the default label. Read the selected option from your own state, and render the placeholder by leaving the children empty when nothing is selected.
|
|
262
|
+
Pass children to `Select.Value` to replace the default label. Read the selected option from your own state, and render the placeholder by leaving the children empty when nothing is selected. A function child receives `isPlaceholder`, `selectedItems`, and `selectedText`; return `null` to fall back to the default.
|
|
149
263
|
|
|
150
264
|
```tsx
|
|
151
265
|
import { useState } from 'react';
|
|
@@ -295,7 +409,7 @@ export default function SelectPlacementDemo() {
|
|
|
295
409
|
|
|
296
410
|
### Select
|
|
297
411
|
|
|
298
|
-
The root manages the selected value, open state, options, and form-control state.
|
|
412
|
+
The root manages the selected value, open state, options, and form-control state. `type` sets the selection mode: `single` (the default) takes a `string` value, and `multiple` takes a `string[]`, where an empty array means no selection.
|
|
299
413
|
|
|
300
414
|
| Prop | Type | Default | Description |
|
|
301
415
|
| --- | --- | --- | --- |
|
|
@@ -303,18 +417,23 @@ The root manages the selected value, open state, options, and form-control state
|
|
|
303
417
|
| `children?` | `ReactNode` | — | — |
|
|
304
418
|
| `variant?` | `'outline' \| null` | — | — |
|
|
305
419
|
| `size?` | `'default' \| 'small' \| null` | — | — |
|
|
306
|
-
| `
|
|
307
|
-
| `value?` | `string` | — | — |
|
|
308
|
-
| `defaultValue?` | `string` | — | — |
|
|
309
|
-
| `onValueChange?` | `((value: string) => void)` | — | — |
|
|
310
|
-
| `
|
|
420
|
+
| `type?` | `'single' \| 'multiple'` | — | — |
|
|
421
|
+
| `value?` | `string \| string[]` | — | — |
|
|
422
|
+
| `defaultValue?` | `string \| string[]` | — | — |
|
|
423
|
+
| `onValueChange?` | `((value: string) => void) \| ((value: string[]) => void)` | — | — |
|
|
424
|
+
| `items?` | `SelectItemData[]` | — | — |
|
|
425
|
+
| `isOpen?` | `boolean` | — | — |
|
|
311
426
|
| `defaultOpen?` | `boolean` | — | — |
|
|
312
427
|
| `onOpenChange?` | `((open: boolean) => void)` | — | — |
|
|
313
428
|
| `disabled?` | `boolean` | — | — |
|
|
314
429
|
| `isRequired?` | `boolean` | — | — |
|
|
315
430
|
| `isInvalid?` | `boolean` | — | — |
|
|
316
431
|
| `isReadOnly?` | `boolean` | — | — |
|
|
317
|
-
| `native?` | `boolean` | — |
|
|
432
|
+
| `native?` | `boolean` | — | — |
|
|
433
|
+
| `inputValue?` | `string` | — | — |
|
|
434
|
+
| `defaultInputValue?` | `string` | — | — |
|
|
435
|
+
| `onInputChange?` | `((inputValue: string) => void)` | — | — |
|
|
436
|
+
| `filter?` | `SelectFilter` | — | — |
|
|
318
437
|
|
|
319
438
|
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
320
439
|
|
|
@@ -361,12 +480,12 @@ Inherits all [`PressableProps`](https://reactnative.dev/docs/pressable#props).
|
|
|
361
480
|
|
|
362
481
|
### Select.Value
|
|
363
482
|
|
|
364
|
-
Displays the label from `items` that matches the selected value, or the placeholder when no value is selected.
|
|
483
|
+
Displays the label from `items` that matches the selected value, or the placeholder when no value is selected. In multiple mode it shows the selected labels joined with commas, truncated to one line. A function child receives `{ isPlaceholder, selectedItems, selectedText }`.
|
|
365
484
|
|
|
366
485
|
| Prop | Type | Default | Description |
|
|
367
486
|
| --- | --- | --- | --- |
|
|
368
487
|
| `className?` | `string` | — | — |
|
|
369
|
-
| `children?` | `ReactNode` | — |
|
|
488
|
+
| `children?` | `ReactNode \| ((state: SelectValueRenderProps) => ReactNode)` | — | Replaces the default display. A function child receives the selection state; return `null` or `undefined` to fall back to the default (placeholder or `selectedText`). |
|
|
370
489
|
| `asChild?` | `boolean` | — | — |
|
|
371
490
|
| `placeholder?` | `string` | — | — |
|
|
372
491
|
|
|
@@ -394,7 +513,7 @@ Inherits all `ForgeIconProps` (react-native-svg `SvgProps` plus `filled` and `si
|
|
|
394
513
|
|
|
395
514
|
### Select.Content
|
|
396
515
|
|
|
397
|
-
Dropdown panel that positions itself around the trigger, scrolls long option lists, and closes when dismissed.
|
|
516
|
+
Dropdown panel that positions itself around the trigger, scrolls long option lists, and closes when dismissed. Dismissing never changes the value.
|
|
398
517
|
|
|
399
518
|
| Prop | Type | Default | Description |
|
|
400
519
|
| --- | --- | --- | --- |
|
|
@@ -406,12 +525,65 @@ Dropdown panel that positions itself around the trigger, scrolls long option lis
|
|
|
406
525
|
| `crossOffset?` | `number` | — | Cross-axis adjustment from the aligned dropdown position in pixels. Defaults to 0. |
|
|
407
526
|
| `enteringAnimation?` | `EntryOrExitLayoutType` | — | Enter animation for the dropdown. Defaults to a 150ms fade. |
|
|
408
527
|
| `exitingAnimation?` | `EntryOrExitLayoutType` | — | Exit animation for the dropdown. Defaults to a 100ms fade. |
|
|
528
|
+
| `dismissAccessibilityLabel?` | `string` | `'Dismiss'` | Accessible name of the visually hidden button that lets screen-reader users close the popup on web. |
|
|
409
529
|
|
|
410
530
|
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
411
531
|
|
|
532
|
+
### Select.BottomSheet
|
|
533
|
+
|
|
534
|
+
Presents the options in a bottom sheet on iOS and Android, in place of `Select.Content`. Compose exactly one of `Select.Content` or `Select.BottomSheet` per select. It sorts its direct children into the same regions as `Select.Content`: `Select.Search` stays above the scrolling options and `Select.Empty` follows them. On web it renders the `Select.Content` dropdown, and `dismissAccessibilityLabel` names its hidden dismiss button. With `Select.Search`, keyboard avoidance applies to the default search input; an `asChild` input does not move the sheet.
|
|
535
|
+
|
|
536
|
+
| Prop | Type | Default | Description |
|
|
537
|
+
| --- | --- | --- | --- |
|
|
538
|
+
| `className?` | `string` | — | Additional Uniwind/Tailwind classes, merged after the sheet body's own styles. |
|
|
539
|
+
| `children?` | `ReactNode` | — | `Select.Search`, `Select.Item` elements, and `Select.Empty`, as in `Select.Content`. |
|
|
540
|
+
| `asChild?` | `boolean` | — | Render the consumer's child as the sheet body, skipping the region split. |
|
|
541
|
+
| `dismissAccessibilityLabel?` | `string` | `'Dismiss'` | Accessible name of the visually hidden dismiss button on web, where the surface is the `Select.Content` dropdown. |
|
|
542
|
+
|
|
543
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
544
|
+
|
|
545
|
+
| Attribute | Values | Description |
|
|
546
|
+
| ------------ | --------------------- | ------------------------------- |
|
|
547
|
+
| `data-slot` | `select-bottom-sheet` | Sheet body on native |
|
|
548
|
+
| `data-state` | `open` | Present while the sheet is open |
|
|
549
|
+
|
|
550
|
+
### Select.Search
|
|
551
|
+
|
|
552
|
+
A search input for the top of `Select.Content` or `Select.BottomSheet`, with a leading search icon. Its query filters the options through the root `filter`, and it takes focus when the dropdown opens on web. Place it as a direct child of the surface; a wrapped `Select.Search` is not recognized and renders among the options.
|
|
553
|
+
|
|
554
|
+
| Prop | Type | Default | Description |
|
|
555
|
+
| --- | --- | --- | --- |
|
|
556
|
+
| `className?` | `string` | — | Additional Uniwind/Tailwind classes, merged after the search container's own styles. |
|
|
557
|
+
| `children?` | `ReactNode` | — | The text input to render when `asChild` is set. Otherwise not rendered. |
|
|
558
|
+
| `asChild?` | `boolean` | — | Merge the search wiring onto the single child text input instead of rendering the default `Input` with a search icon. |
|
|
559
|
+
| `variant?` | `'outline' \| 'subtle'` | `'subtle'` | `Input` variant of the default search field. Ignored when `asChild` is set. |
|
|
560
|
+
| `getResultCountLabel?` | `((count: number) => string)` | — | Text the polite live region announces when the result count changes, such as `"3 results"` (the English default). When nothing matches, the `Select.Empty` text is announced instead. |
|
|
561
|
+
|
|
562
|
+
Inherits [`TextInputProps`](https://reactnative.dev/docs/textinput#props) except `value`, `defaultValue`, and `onChangeText`, which the root owns through `inputValue`, `defaultInputValue`, and `onInputChange`.
|
|
563
|
+
|
|
564
|
+
| Attribute | Values | Description |
|
|
565
|
+
| ----------- | --------------- | ---------------- |
|
|
566
|
+
| `data-slot` | `select-search` | Search container |
|
|
567
|
+
|
|
568
|
+
### Select.Empty
|
|
569
|
+
|
|
570
|
+
Content shown below the options only when no option matches the query. Plain text children are styled to match the options. Place it as a direct child of `Select.Content` or `Select.BottomSheet`.
|
|
571
|
+
|
|
572
|
+
| Prop | Type | Default | Description |
|
|
573
|
+
| --- | --- | --- | --- |
|
|
574
|
+
| `className?` | `string` | — | Additional Uniwind/Tailwind classes, merged after the empty state's own styles. |
|
|
575
|
+
| `children?` | `ReactNode` | — | — |
|
|
576
|
+
| `asChild?` | `boolean` | — | — |
|
|
577
|
+
|
|
578
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
579
|
+
|
|
580
|
+
| Attribute | Values | Description |
|
|
581
|
+
| ----------- | -------------- | ----------- |
|
|
582
|
+
| `data-slot` | `select-empty` | Empty state |
|
|
583
|
+
|
|
412
584
|
### Select.Item
|
|
413
585
|
|
|
414
|
-
An individual option. Its `value` must match an entry in the root `items` array. The `indicator` prop replaces the default selected-item checkmark, and `indicator={null}` suppresses it.
|
|
586
|
+
An individual option. Its `value` must match an entry in the root `items` array. Disable an option with `disabled` here or on its `items` entry. The `indicator` prop replaces the default selected-item checkmark, and `indicator={null}` suppresses it. The default checkmark is omitted when the item contains a `Select.ItemControl`.
|
|
415
587
|
|
|
416
588
|
| Prop | Type | Default | Description |
|
|
417
589
|
| --- | --- | --- | --- |
|
|
@@ -419,7 +591,7 @@ An individual option. Its `value` must match an entry in the root `items` array.
|
|
|
419
591
|
| `children?` | `ReactNode` | — | Either children or a render prop that receives a boolean reflecting whether the component is currently pressed. |
|
|
420
592
|
| `disabled?` | `boolean` | — | Whether the press behavior is disabled. |
|
|
421
593
|
| `asChild?` | `boolean` | — | — |
|
|
422
|
-
| `indicator?` | `ReactNode` | — | Replaces the default selected-item checkmark. The replacement is rendered only while the item is selected. Pass `null` to suppress the indicator. |
|
|
594
|
+
| `indicator?` | `ReactNode` | — | Replaces the default selected-item checkmark. The replacement is rendered only while the item is selected. Pass `null` to suppress the indicator. The default checkmark is omitted when the item contains a `Select.ItemControl`. |
|
|
423
595
|
| `value` | `string` | — | — |
|
|
424
596
|
| `isHovered?` | `boolean` | — | — |
|
|
425
597
|
| `isActive?` | `boolean` | — | — |
|
|
@@ -452,22 +624,49 @@ Text label rendered inside a `Select.Item`.
|
|
|
452
624
|
|
|
453
625
|
Inherits all [`TextProps`](https://reactnative.dev/docs/text#props).
|
|
454
626
|
|
|
627
|
+
### Select.ItemControl
|
|
628
|
+
|
|
629
|
+
A leading checkbox that mirrors the item's selected state. It is presentational: the option itself carries the selected state for assistive technology.
|
|
630
|
+
|
|
631
|
+
| Prop | Type | Default | Description |
|
|
632
|
+
| --- | --- | --- | --- |
|
|
633
|
+
| `className?` | `string` | — | Additional Uniwind/Tailwind classes, merged after the control's own styles. |
|
|
634
|
+
| `children?` | `ReactNode` | — | The element to render when `asChild` is set. Otherwise not rendered. |
|
|
635
|
+
| `asChild?` | `boolean` | — | Render the consumer's child element in place of the default checkbox glyph. |
|
|
636
|
+
|
|
637
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
638
|
+
|
|
639
|
+
| Attribute | Values | Description |
|
|
640
|
+
| -------------- | --------------------- | --------------- |
|
|
641
|
+
| `data-slot` | `select-item-control` | Checkbox glyph |
|
|
642
|
+
| `data-checked` | `true` \| `false` | Selection state |
|
|
643
|
+
|
|
455
644
|
## Anatomy
|
|
456
645
|
|
|
457
|
-
| `data-slot`
|
|
458
|
-
|
|
|
459
|
-
| `select`
|
|
460
|
-
| `select-trigger`
|
|
461
|
-
| `select-value`
|
|
462
|
-
| `select-icon`
|
|
463
|
-
| `select-content`
|
|
464
|
-
| `select-
|
|
465
|
-
| `select-
|
|
646
|
+
| `data-slot` | Element |
|
|
647
|
+
| --------------------- | ----------------------------- |
|
|
648
|
+
| `select` | Root container |
|
|
649
|
+
| `select-trigger` | Dropdown trigger |
|
|
650
|
+
| `select-value` | Selected label or placeholder |
|
|
651
|
+
| `select-icon` | Dropdown indicator |
|
|
652
|
+
| `select-content` | Dropdown panel |
|
|
653
|
+
| `select-bottom-sheet` | Sheet body (native) |
|
|
654
|
+
| `select-search` | Search input |
|
|
655
|
+
| `select-empty` | No-results message |
|
|
656
|
+
| `select-item` | Option |
|
|
657
|
+
| `select-item-label` | Option label |
|
|
658
|
+
| `select-item-control` | Option checkbox |
|
|
466
659
|
|
|
467
660
|
## Accessibility
|
|
468
661
|
|
|
469
|
-
The trigger uses `role="combobox"` with `aria-haspopup="listbox"`, reflects open, required, invalid, and read-only state, and points to the dropdown content. The content uses `role="listbox"` and each item uses `role="option"` with selected and disabled state.
|
|
662
|
+
The trigger uses `role="combobox"` with `aria-haspopup="listbox"`, reflects open, required, invalid, and read-only state, and points to the dropdown content. The content uses `role="listbox"` and each item uses `role="option"` with selected and disabled state. In multiple mode the listbox sets `aria-multiselectable="true"`, and `Select.ItemControl` is hidden from assistive technology.
|
|
470
663
|
|
|
471
664
|
Compose with `Field.Label` for a visible associated label. When no visible label is present, provide `accessibilityLabel` on `Select`.
|
|
472
665
|
|
|
473
|
-
On web,
|
|
666
|
+
With `Select.Search`, the dropdown becomes a `role="dialog"` named by the field label that contains the search input (`role="searchbox"`) and the `role="listbox"`. The trigger keeps `aria-haspopup="listbox"`. On web, focus stays in the search input while Arrow Up and Arrow Down move the highlight through the visible, enabled options, announced through `aria-activedescendant`. Enter selects and closes, or toggles in multiple mode, and Space types a space. The highlight moves to the first match each time the query changes, and a polite live region announces the number of results, or the `Select.Empty` text when nothing matches. Escape and Tab close the dropdown, keep the value, and clear the query. Inside a `Drawer`, closing returns focus to the trigger and leaves the drawer open.
|
|
667
|
+
|
|
668
|
+
On web, Enter, Space, Arrow Down, or Arrow Up opens the dropdown. Arrow keys, Home, and End move through enabled options; Enter or Space selects and closes, or toggles in multiple mode; Escape closes; and Tab closes while continuing focus navigation. Focus returns to the trigger when the dropdown closes.
|
|
669
|
+
|
|
670
|
+
Screen-reader users can close the dropdown without a keyboard. On web, a visually hidden button labelled by `dismissAccessibilityLabel` on `Select.Content` closes it. On iOS, the VoiceOver escape gesture closes it, and on Android the back button does. Closing never changes the value.
|
|
671
|
+
|
|
672
|
+
In `Select.BottomSheet` on iOS and Android, VoiceOver and TalkBack move through the search input and each option directly, with no virtual focus, and each option announces its selected state. The sheet takes the same role and name as the dropdown. The VoiceOver escape gesture, Android back, a swipe down, and the backdrop close it, keep the value, and clear the query.
|
|
@@ -124,6 +124,103 @@ export default function TextItalicDemo() {
|
|
|
124
124
|
}
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
+
## Nested
|
|
128
|
+
|
|
129
|
+
Place a `Text` inside another text element to style part of a sentence. A nested `Text` inherits `color`, `size`, `weight` and the font family from its parent, and each prop it sets overrides only that one.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { Box, Text } from '@cdx-ui/components';
|
|
133
|
+
|
|
134
|
+
export default function TextNestedDemo() {
|
|
135
|
+
return (
|
|
136
|
+
<Box className="gap-4">
|
|
137
|
+
<Text color="secondary" size="lg" weight="medium">
|
|
138
|
+
Inherits everything: <Text>Your statement is ready to download.</Text>
|
|
139
|
+
</Text>
|
|
140
|
+
<Text color="secondary" size="lg" weight="medium">
|
|
141
|
+
Overrides color only: <Text color="danger">Your payment is past due.</Text>
|
|
142
|
+
</Text>
|
|
143
|
+
<Text color="secondary" size="lg" weight="medium">
|
|
144
|
+
Overrides size and weight:{' '}
|
|
145
|
+
<Text size="sm" weight="bold">
|
|
146
|
+
Your statement is ready to download.
|
|
147
|
+
</Text>
|
|
148
|
+
</Text>
|
|
149
|
+
<Text color="secondary" size="lg" weight="bold">
|
|
150
|
+
Overrides size only, keeps bold: <Text size="sm">Your statement is ready to download.</Text>
|
|
151
|
+
</Text>
|
|
152
|
+
</Box>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Inside text slots
|
|
158
|
+
|
|
159
|
+
The same inheritance applies inside `Heading` and text slots such as `Button.Label` and `Alert.Description`, so emphasis follows the surrounding component's styles.
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
import { Alert, Box, Button, Heading, Text } from '@cdx-ui/components';
|
|
163
|
+
|
|
164
|
+
export default function TextNestedSlotsDemo() {
|
|
165
|
+
return (
|
|
166
|
+
<Box className="gap-4">
|
|
167
|
+
<Heading size="sm">
|
|
168
|
+
Inside a Heading: <Text color="action">Savings goals</Text>
|
|
169
|
+
</Heading>
|
|
170
|
+
<Button>
|
|
171
|
+
<Button.Label>
|
|
172
|
+
Inside Button.Label: <Text weight="bold">Transfer</Text>
|
|
173
|
+
</Button.Label>
|
|
174
|
+
</Button>
|
|
175
|
+
<Alert severity="info">
|
|
176
|
+
<Alert.Description>
|
|
177
|
+
Inside Alert.Description: <Text weight="semibold">Transfers settle by 5 p.m.</Text>
|
|
178
|
+
</Alert.Description>
|
|
179
|
+
</Alert>
|
|
180
|
+
</Box>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Inline emphasis
|
|
186
|
+
|
|
187
|
+
Combine nested `Text` elements to highlight amounts, statuses and links within running copy.
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
import { Box, Text } from '@cdx-ui/components';
|
|
191
|
+
|
|
192
|
+
export default function TextNestedInlineDemo() {
|
|
193
|
+
return (
|
|
194
|
+
<Box className="gap-3">
|
|
195
|
+
<Text>
|
|
196
|
+
Your available balance is <Text weight="bold">$2,481.16</Text>, up{' '}
|
|
197
|
+
<Text color="success" weight="semibold">
|
|
198
|
+
$120.00
|
|
199
|
+
</Text>{' '}
|
|
200
|
+
since yesterday.
|
|
201
|
+
</Text>
|
|
202
|
+
<Text color="secondary" size="sm">
|
|
203
|
+
Posted <Text weight="medium">Oct 14</Text> · Pending{' '}
|
|
204
|
+
<Text color="warning" italic>
|
|
205
|
+
2 transactions
|
|
206
|
+
</Text>
|
|
207
|
+
</Text>
|
|
208
|
+
<Text size="sm" color="tertiary">
|
|
209
|
+
By continuing you agree to the{' '}
|
|
210
|
+
<Text color="action" weight="medium">
|
|
211
|
+
Terms of Service
|
|
212
|
+
</Text>{' '}
|
|
213
|
+
and{' '}
|
|
214
|
+
<Text color="action" weight="medium">
|
|
215
|
+
Privacy Policy
|
|
216
|
+
</Text>
|
|
217
|
+
.
|
|
218
|
+
</Text>
|
|
219
|
+
</Box>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
127
224
|
## API
|
|
128
225
|
|
|
129
226
|
### Text
|