@ceed/ads 1.36.0 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Select/Select.d.ts +9 -1
- package/dist/components/inputs/Select.md +75 -20
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +3 -3
- package/dist/index.cjs +17 -3
- package/dist/index.js +17 -3
- package/framer/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import React, { ComponentProps } from 'react';
|
|
2
2
|
import { Select as JoySelect, type SelectProps as JoySelectProps } from '@mui/joy';
|
|
3
|
+
import FormControl from '../FormControl';
|
|
4
|
+
import FormLabel from '../FormLabel';
|
|
5
|
+
import FormHelperText from '../FormHelperText';
|
|
3
6
|
import { SelectValue } from '@mui/base';
|
|
4
7
|
export type { JoySelectProps };
|
|
5
8
|
export type { OptionProps } from '@mui/joy';
|
|
@@ -24,11 +27,16 @@ export { Option };
|
|
|
24
27
|
export type InferOptionValue<OptionValue> = OptionValue extends {
|
|
25
28
|
value: infer V;
|
|
26
29
|
} ? V : OptionValue;
|
|
27
|
-
export interface SelectProps<OptionValue extends OptionType, Multiple extends boolean = false> extends Omit<ComponentProps<typeof JoySelect<OptionValue, any, Multiple>>, 'value' | 'onChange' | 'multiple'> {
|
|
30
|
+
export interface SelectProps<OptionValue extends OptionType, Multiple extends boolean = false> extends Omit<ComponentProps<typeof JoySelect<OptionValue, any, Multiple>>, 'value' | 'onChange' | 'multiple' | 'slotProps'> {
|
|
28
31
|
options: OptionValue[];
|
|
29
32
|
label?: string;
|
|
30
33
|
helperText?: string;
|
|
31
34
|
error?: boolean;
|
|
35
|
+
slotProps?: ComponentProps<typeof JoySelect<OptionValue, any, Multiple>>['slotProps'] & {
|
|
36
|
+
formControl?: ComponentProps<typeof FormControl>;
|
|
37
|
+
formLabel?: ComponentProps<typeof FormLabel>;
|
|
38
|
+
formHelperText?: ComponentProps<typeof FormHelperText>;
|
|
39
|
+
};
|
|
32
40
|
value?: SelectValue<InferOptionValue<OptionValue>, Multiple>;
|
|
33
41
|
onChange?: (event: Omit<React.SyntheticEvent<HTMLElement>, 'target'> & {
|
|
34
42
|
target: {
|
|
@@ -207,6 +207,58 @@ Combining `label`, `helperText`, and `error` produces a complete form field. Her
|
|
|
207
207
|
</>
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
+
## Slot Props and Deterministic Ids
|
|
211
|
+
|
|
212
|
+
The `slotProps` prop targets both Joy Select's own slots (`button`, `listbox`, `root`, …) and the wrapper slots that `Select` composes around it (`formControl`, `formLabel`, `formHelperText`). Pass `id` (or `slotProps.formControl.id`) to pin the field's ids deterministically — `FormControl` derives the button `id` and the label `id` (`${id}-label`) from it, which keeps `byLabelText` / `byRole('combobox', { name })` queries stable in tests.
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<Stack
|
|
216
|
+
spacing={3}
|
|
217
|
+
sx={{
|
|
218
|
+
minWidth: 240
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
{/* id seeds deterministic FormControl ids: button#pet, label#pet-label (testable via byLabelText/byRole) */}
|
|
222
|
+
<Select
|
|
223
|
+
id="pet"
|
|
224
|
+
label="Pet"
|
|
225
|
+
defaultValue="cat"
|
|
226
|
+
options={options}
|
|
227
|
+
slotProps={{
|
|
228
|
+
formLabel: {
|
|
229
|
+
sx: {
|
|
230
|
+
color: "primary.500"
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
formHelperText: {
|
|
234
|
+
sx: {
|
|
235
|
+
fontStyle: "italic"
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
button: {
|
|
239
|
+
"aria-describedby": "pet-extra"
|
|
240
|
+
}
|
|
241
|
+
}}
|
|
242
|
+
helperText="Wired via slotProps"
|
|
243
|
+
/>
|
|
244
|
+
</Stack>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
<Select
|
|
249
|
+
id="pet"
|
|
250
|
+
label="Pet"
|
|
251
|
+
helperText="Wired via slotProps"
|
|
252
|
+
options={options}
|
|
253
|
+
slotProps={{
|
|
254
|
+
formLabel: { sx: { color: 'primary.500' } },
|
|
255
|
+
formHelperText: { sx: { fontStyle: 'italic' } },
|
|
256
|
+
button: { 'aria-describedby': 'pet-extra' },
|
|
257
|
+
}}
|
|
258
|
+
/>
|
|
259
|
+
// → renders button#pet and label#pet-label, connected via aria-labelledby
|
|
260
|
+
```
|
|
261
|
+
|
|
210
262
|
## Required Field
|
|
211
263
|
|
|
212
264
|
Set `required` to mark the field as required. An asterisk is added to the label automatically.
|
|
@@ -557,25 +609,27 @@ function LocationSelect() {
|
|
|
557
609
|
|
|
558
610
|
### Key Props
|
|
559
611
|
|
|
560
|
-
| Prop | Type
|
|
561
|
-
| ---------------- |
|
|
562
|
-
| `options` | `OptionType[]`
|
|
563
|
-
| `value` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]`
|
|
564
|
-
| `defaultValue` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]`
|
|
565
|
-
| `onChange` | `(event: { target: { name?, value } }, newValue) => void`
|
|
566
|
-
| `multiple` | `boolean`
|
|
567
|
-
| `label` | `string`
|
|
568
|
-
| `helperText` | `string`
|
|
569
|
-
| `error` | `boolean`
|
|
570
|
-
| `required` | `boolean`
|
|
571
|
-
| `disabled` | `boolean`
|
|
572
|
-
| `placeholder` | `string`
|
|
573
|
-
| `size` | `'sm' \| 'md' \| 'lg'`
|
|
574
|
-
| `variant` | `'outlined' \| 'plain' \| 'solid' \| 'soft'`
|
|
575
|
-
| `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'`
|
|
576
|
-
| `startDecorator` | `ReactNode`
|
|
577
|
-
| `endDecorator` | `ReactNode`
|
|
578
|
-
| `
|
|
612
|
+
| Prop | Type | Default | Description |
|
|
613
|
+
| ---------------- | ----------------------------------------------------------------------- | ----------------- | -------------------------------------------------------------- |
|
|
614
|
+
| `options` | `OptionType[]` | `[]` | Array of options (objects or primitives) |
|
|
615
|
+
| `value` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]` | - | Selected value(s) for controlled mode |
|
|
616
|
+
| `defaultValue` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]` | - | Initial value for uncontrolled mode |
|
|
617
|
+
| `onChange` | `(event: { target: { name?, value } }, newValue) => void` | - | Callback when selection changes |
|
|
618
|
+
| `multiple` | `boolean` | `false` | Allow multiple selections (value becomes an array) |
|
|
619
|
+
| `label` | `string` | - | Form label displayed above the select |
|
|
620
|
+
| `helperText` | `string` | - | Helper text displayed below the select |
|
|
621
|
+
| `error` | `boolean` | `false` | Applies danger color to indicate validation error |
|
|
622
|
+
| `required` | `boolean` | `false` | Marks the field as required (adds asterisk to label) |
|
|
623
|
+
| `disabled` | `boolean` | `false` | Disables the select |
|
|
624
|
+
| `placeholder` | `string` | `'Choose one...'` | Placeholder text when no value is selected |
|
|
625
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Select size |
|
|
626
|
+
| `variant` | `'outlined' \| 'plain' \| 'solid' \| 'soft'` | `'outlined'` | Visual style variant |
|
|
627
|
+
| `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | `'neutral'` | Color scheme |
|
|
628
|
+
| `startDecorator` | `ReactNode` | - | Content rendered before the select trigger text |
|
|
629
|
+
| `endDecorator` | `ReactNode` | - | Content rendered after the select trigger text |
|
|
630
|
+
| `id` | `string` | - | Seeds deterministic ids: button `id`, label `${id}-label` |
|
|
631
|
+
| `slotProps` | `{ formControl?, formLabel?, formHelperText?, button?, listbox?, ... }` | - | Props forwarded to composed wrapper slots and Joy Select slots |
|
|
632
|
+
| `sx` | `SxProps` | - | Custom styles using the MUI system |
|
|
579
633
|
|
|
580
634
|
### Option Type
|
|
581
635
|
|
|
@@ -611,7 +665,8 @@ const options = [
|
|
|
611
665
|
|
|
612
666
|
## Accessibility
|
|
613
667
|
|
|
614
|
-
- **Label association**: When you use the `label` prop, the component automatically connects the label to the select element via `aria-labelledby
|
|
668
|
+
- **Label association**: When you use the `label` prop, the component automatically connects the label to the select element via `aria-labelledby` (the internal `FormControl` propagates a `labelId` to both the label and the button slot). You do not need to wire `useId` or a custom `FormLabel` externally. Always provide a label for screen reader users.
|
|
669
|
+
- **Deterministic ids for tests**: Pass `id` (or `slotProps.formControl.id`) to fix the generated ids, so `byLabelText` / `byRole('combobox', { name })` resolve to a stable accessible name.
|
|
615
670
|
- **Keyboard navigation**: The select can be opened with Enter or Space, navigated with Arrow Up/Down and Home/End, confirmed with Enter, and dismissed with Escape.
|
|
616
671
|
- **Error announcement**: When `error` is set, `aria-invalid` is applied. Pair it with a descriptive `helperText` so assistive technology can announce the error reason.
|
|
617
672
|
- **Required state**: The `required` prop adds `aria-required` and a visible asterisk to the label, communicating the requirement both visually and programmatically.
|