Skip to content

Commit 3ef626b

Browse files
committed
add chakra NativeSelectWidget
1 parent 3f65c1a commit 3ef626b

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { ChangeEvent, FocusEvent, useMemo } from 'react';
2+
3+
import {
4+
ariaDescribedByIds,
5+
EnumOptionsType,
6+
enumOptionsIndexForValue,
7+
enumOptionsValueForIndex,
8+
labelValue,
9+
FormContextType,
10+
RJSFSchema,
11+
StrictRJSFSchema,
12+
WidgetProps,
13+
} from '@rjsf/utils';
14+
import { Field } from '../components/ui/field';
15+
import { OptionsOrGroups } from 'chakra-react-select';
16+
import { createListCollection } from '@chakra-ui/react';
17+
import { NativeSelect as ChakraSelect } from '@chakra-ui/react';
18+
19+
export default function NativeSelectWidget<
20+
T = any,
21+
S extends StrictRJSFSchema = RJSFSchema,
22+
F extends FormContextType = any
23+
>(props: WidgetProps<T, S, F>) {
24+
const {
25+
id,
26+
options,
27+
label,
28+
hideLabel,
29+
placeholder,
30+
multiple,
31+
required,
32+
disabled,
33+
readonly,
34+
value,
35+
autofocus,
36+
onChange,
37+
onBlur,
38+
onFocus,
39+
rawErrors = [],
40+
schema,
41+
} = props;
42+
const { enumOptions, enumDisabled, emptyValue } = options;
43+
// const chakraProps = getChakra({ uiSchema });
44+
45+
const _onChange = ({ target }: ChangeEvent<HTMLSelectElement>) => {
46+
return onChange(enumOptionsValueForIndex<S>(target && target.value, enumOptions, emptyValue));
47+
};
48+
49+
const _onBlur = ({ target }: FocusEvent<HTMLSelectElement>) =>
50+
onBlur(id, enumOptionsValueForIndex<S>(target && target.value, enumOptions, emptyValue));
51+
52+
const _onFocus = ({ target }: FocusEvent<HTMLSelectElement>) =>
53+
onFocus(id, enumOptionsValueForIndex<S>(target && target.value, enumOptions, emptyValue));
54+
55+
const showPlaceholderOption = !multiple && schema.default === undefined;
56+
const { valueLabelMap, displayEnumOptions } = useMemo((): {
57+
valueLabelMap: Record<string | number, string>;
58+
displayEnumOptions: OptionsOrGroups<any, any>;
59+
} => {
60+
const valueLabelMap: Record<string | number, string> = {};
61+
let displayEnumOptions: OptionsOrGroups<any, any> = [];
62+
if (Array.isArray(enumOptions)) {
63+
displayEnumOptions = enumOptions.map((option: EnumOptionsType<S>, index: number) => {
64+
const { value, label } = option;
65+
valueLabelMap[index] = label || String(value);
66+
return {
67+
label,
68+
value: String(index),
69+
disabled: Array.isArray(enumDisabled) && enumDisabled.indexOf(value) !== -1,
70+
};
71+
});
72+
if (showPlaceholderOption) {
73+
(displayEnumOptions as any[]).unshift({ value: '', label: placeholder || '' });
74+
}
75+
}
76+
return { valueLabelMap: valueLabelMap, displayEnumOptions: displayEnumOptions };
77+
}, [enumDisabled, enumOptions, placeholder, showPlaceholderOption]);
78+
79+
const selectedIndex = enumOptionsIndexForValue<S>(value, enumOptions, false);
80+
81+
const getSingleValue = () =>
82+
typeof selectedIndex !== 'undefined'
83+
? [
84+
{
85+
label: valueLabelMap[selectedIndex as string] || '',
86+
value: selectedIndex.toString(),
87+
},
88+
]
89+
: [];
90+
91+
const formValue = getSingleValue()[0]?.value || '';
92+
93+
const selectOptions = createListCollection({
94+
items: displayEnumOptions.filter((item) => item.value),
95+
});
96+
97+
return (
98+
<Field
99+
mb={1}
100+
// {...chakraProps}
101+
disabled={disabled || readonly}
102+
required={required}
103+
readOnly={readonly}
104+
invalid={rawErrors && rawErrors.length > 0}
105+
label={labelValue(label, hideLabel || !label)}
106+
>
107+
<ChakraSelect.Root>
108+
<ChakraSelect.Field
109+
id={id}
110+
onBlur={_onBlur}
111+
onChange={_onChange}
112+
onFocus={_onFocus}
113+
autoFocus={autofocus}
114+
value={formValue}
115+
aria-describedby={ariaDescribedByIds<T>(id)}
116+
>
117+
{selectOptions.items.map((item) => (
118+
<option key={item.value} value={item.value}>
119+
{item.label}
120+
</option>
121+
))}
122+
</ChakraSelect.Field>
123+
<ChakraSelect.Indicator />
124+
</ChakraSelect.Root>
125+
</Field>
126+
);
127+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default } from './NativeSelectWidget';
2+
export * from './NativeSelectWidget';

packages/chakra-ui/src/Widgets/Widgets.ts

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import CheckboxesWidget from '../CheckboxesWidget/CheckboxesWidget';
55
import RadioWidget from '../RadioWidget/RadioWidget';
66
import RangeWidget from '../RangeWidget/RangeWidget';
77
import SelectWidget from '../SelectWidget/SelectWidget';
8+
import NativeSelectWidget from '../SelectNativeWidget/NativeSelectWidget';
89
import TextareaWidget from '../TextareaWidget/TextareaWidget';
910
import UpDownWidget from '../UpDownWidget/UpDownWidget';
1011
import { FormContextType, RegistryWidgetsType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
@@ -22,6 +23,7 @@ export function generateWidgets<
2223
RadioWidget,
2324
RangeWidget,
2425
SelectWidget,
26+
NativeSelectWidget,
2527
TextareaWidget,
2628
UpDownWidget,
2729
};

0 commit comments

Comments
 (0)