SelectField.options now supports more formats
Massimo Melina committed
Mar 8, 2022 at 15:36 UTC
48794a36eeb9aebac18523dc7a22d9cfe7d50808
1 file changed
+21
-17
admin/src/Form.ts
+21
-17
@@ -149,16 +149,15 @@ export function DisplayField({ value, empty='-', ...props }: any) {
149
return h(StringField, { ...props, value, disabled: true })
150
}
151
152
+type SelectOptions<T> = { [label:string]:T } | SelectOption<T>[]
153
+type SelectOption<T> = SelectPair<T> | (T extends string | number ? T : never)
154
interface SelectPair<T> { label: string, value:T }
153
-export function SelectField<T>(props: FieldProps<T> & { options:SelectPair<T>[] }) {
155
+
156
+export function SelectField<T>(props: FieldProps<T> & { options:SelectOptions<T> }) {
157
const { value, onChange, options, ...rest } = props
155
- const jsonValue = JSON.stringify(value)
156
- const currentOption = options.find(x => JSON.stringify(x.value) === jsonValue)
158
return h(TextField, { // using TextField because Select is not displaying label correctly
159
...rest,
160
...commonSelectProps(props),
160
- // avoid warning for invalid option. This can easily happen for a split-second when you keep value in a useState (or other async way) and calculate options with a useMemo (or other sync way) causing a temporary misalignment.
161
- value: currentOption ? jsonValue : '',
161
onChange(event) {
162
try {
163
let newVal: any = event.target.value
@@ -170,36 +169,41 @@ export function SelectField<T>(props: FieldProps<T> & { options:SelectPair<T>[]
169
})
170
}
171
173
-export function MultiSelectField<T>(props: FieldProps<T[]> & { options:SelectPair<T>[] }) {
174
- const { value, onChange, options, ...rest } = props
172
+export function MultiSelectField<T>(props: FieldProps<T[]> & { options:SelectOptions<T> }) {
173
+ const { value, options, ...rest } = props
174
return h(TextField, {
175
...rest,
177
- ...commonSelectProps(props),
176
+ ...commonSelectProps({ ...props, value:undefined }),
177
SelectProps: { multiple: true },
178
value: !Array.isArray(value) ? [] : value.map(x => JSON.stringify(x)),
179
onChange(event) {
180
try {
181
let v: any = event.target.value
182
v = Array.isArray(v) ? v.map(x => JSON.parse(x)) : []
184
- onChange(v as T[], { was: value, event })
183
+ props.onChange(v as T[], { was: value, event })
184
}
185
catch {}
186
}
187
})
188
}
189
191
-function commonSelectProps<T>(props: { disabled?: boolean, options:SelectPair<T>[] }) {
190
+function commonSelectProps<T>(props: { value?: T, disabled?: boolean, options:SelectOptions<T> }) {
191
const { options, disabled } = props
192
+ const normalizedOptions = !Array.isArray(options) ? Object.entries(options).map(([label,value]) => ({ value, label }))
193
+ : options.map(o => typeof o === 'string' || typeof o === 'number' ? { value: o, label: String(o) } : o as SelectPair<T>)
194
+ const jsonValue = JSON.stringify(props.value)
195
+ const currentOption = normalizedOptions.find(x => JSON.stringify(x.value) === jsonValue)
196
return {
197
select: true,
198
fullWidth: true,
196
- disabled: !options?.length || disabled,
197
- children: options.map((o, i) => {
198
- const obj = o && typeof o === 'object'
199
- const value = obj && 'value' in o ? o.value : o
200
- const label = obj && 'label' in o ? o.label : o
201
- return h(MenuItem, { key: i, value: JSON.stringify(value), children: label })
202
- })
199
+ // avoid warning for invalid option. This can easily happen for a split-second when you keep value in a useState (or other async way) and calculate options with a useMemo (or other sync way) causing a temporary misalignment.
200
+ value: currentOption ? jsonValue : '',
201
+ disabled: !normalizedOptions?.length || disabled,
202
+ children: normalizedOptions.map((o, i) => h(MenuItem, {
203
+ key: i,
204
+ value: JSON.stringify(o?.value),
205
+ children: o?.label
206
+ }))
207
}
208
}
209