Skip to content

Commit

Permalink
fix rjsf-team#4197 for antd, chakra-ui, fluentui-rc, material-ui, mui…
Browse files Browse the repository at this point in the history
…, semantic-ui
  • Loading branch information
nickgros committed May 24, 2024
1 parent eec280a commit e54a620
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 32 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,36 @@ should change the heading of the (upcoming) version to include a major version b
-->

# 5.18.5

## @rjsf/antd

- SelectWidget now displays an empty option when appropriate, fixing [#4197](https://github.com/rjsf-team/react-jsonschema-form/issues/4197)

## @rjsf/chakra-ui

- SelectWidget now displays an empty option when appropriate, fixing [#4197](https://github.com/rjsf-team/react-jsonschema-form/issues/4197)

## @rjsf/core

- Added support for `default` values in `additionalProperties` in [#4199](https://github.com/rjsf-team/react-jsonschema-form/issues/4199), fixing [#3195](https://github.com/rjsf-team/react-jsonschema-form/issues/3915)

## @rjsf/fluentui-rc

- SelectWidget now displays an empty option when appropriate, fixing [#4197](https://github.com/rjsf-team/react-jsonschema-form/issues/4197)

## @rjsf/material-ui

- SelectWidget now displays an empty option when appropriate, fixing [#4197](https://github.com/rjsf-team/react-jsonschema-form/issues/4197)

## @rjsf/mui

- SelectWidget now displays an empty option when appropriate, fixing [#4197](https://github.com/rjsf-team/react-jsonschema-form/issues/4197)

## @rjsf/semantic-ui

- SelectWidget now displays an empty option when appropriate, fixing [#4197](https://github.com/rjsf-team/react-jsonschema-form/issues/4197)

# 5.18.4

## Dev / docs / playground
Expand Down
31 changes: 21 additions & 10 deletions packages/antd/src/widgets/SelectWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
WidgetProps,
} from '@rjsf/utils';
import isString from 'lodash/isString';
import { DefaultOptionType } from 'antd/es/select';
import { useMemo } from 'react';

const SELECT_STYLE = {
width: '100%',
Expand Down Expand Up @@ -37,6 +39,7 @@ export default function SelectWidget<
placeholder,
readonly,
value,
schema,
}: WidgetProps<T, S, F>) {
const { readonlyAsDisabled = true } = formContext as GenericObjectType;

Expand Down Expand Up @@ -65,6 +68,23 @@ export default function SelectWidget<
const extraProps = {
name: id,
};

const selectOptions: DefaultOptionType[] | undefined = useMemo(() => {
if (Array.isArray(enumOptions)) {
if (!multiple && schema.default === undefined) {
enumOptions.unshift({ value: '', label: placeholder || '' });
}

return enumOptions.map(({ value: optionValue, label: optionLabel }, index) => ({
disabled: Array.isArray(enumDisabled) && enumDisabled.indexOf(optionValue) !== -1,
key: String(index),
value: String(index),
label: optionLabel,
}));
}
return undefined;
}, [enumDisabled, enumOptions, multiple, placeholder, schema.default]);

return (
<Select
autoFocus={autofocus}
Expand All @@ -81,16 +101,7 @@ export default function SelectWidget<
{...extraProps}
filterOption={filterOption}
aria-describedby={ariaDescribedByIds<T>(id)}
options={
Array.isArray(enumOptions)
? enumOptions.map(({ value: optionValue, label: optionLabel }, index) => ({
disabled: Array.isArray(enumDisabled) && enumDisabled.indexOf(optionValue) !== -1,
key: String(index),
value: String(index),
label: optionLabel,
}))
: undefined
}
options={selectOptions}
/>
);
}
4 changes: 2 additions & 2 deletions packages/antd/test/__snapshots__/Form.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3354,9 +3354,9 @@ exports[`single fields select field single choice formData 1`] = `
</span>
<span
className="ant-select-selection-item"
title="bar"
title="foo"
>
bar
foo
</span>
</div>
<span
Expand Down
17 changes: 12 additions & 5 deletions packages/chakra-ui/src/SelectWidget/SelectWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FocusEvent } from 'react';
import { FocusEvent, useMemo } from 'react';
import { FormControl, FormLabel } from '@chakra-ui/react';
import {
ariaDescribedByIds,
Expand Down Expand Up @@ -34,6 +34,7 @@ export default function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFS
onFocus,
rawErrors = [],
uiSchema,
schema,
} = props;
const { enumOptions, enumDisabled, emptyValue } = options;
const chakraProps = getChakra({ uiSchema });
Expand Down Expand Up @@ -61,17 +62,23 @@ export default function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFS
onFocus(id, enumOptionsValueForIndex<S>(value, enumOptions, emptyValue));

const _valueLabelMap: any = {};
const displayEnumOptions: OptionsOrGroups<any, any> = Array.isArray(enumOptions)
? enumOptions.map((option: EnumOptionsType<S>, index: number) => {
const displayEnumOptions: OptionsOrGroups<any, any> = useMemo(() => {
if (Array.isArray(enumOptions)) {
if (!multiple && schema.default === undefined) {
enumOptions.unshift({ value: '', label: placeholder || '' });
}
return enumOptions.map((option: EnumOptionsType<S>, index: number) => {
const { value, label } = option;
_valueLabelMap[index] = label || String(value);
return {
label,
value: String(index),
isDisabled: Array.isArray(enumDisabled) && enumDisabled.indexOf(value) !== -1,
};
})
: [];
});
}
return [];
}, [_valueLabelMap, enumDisabled, enumOptions, multiple, placeholder, schema.default]);

const isMultiple = typeof multiple !== 'undefined' && multiple !== false && Boolean(enumOptions);
const selectedIndex = enumOptionsIndexForValue<S>(value, enumOptions, isMultiple);
Expand Down
3 changes: 3 additions & 0 deletions packages/fluentui-rc/src/SelectWidget/SelectWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extend
onChange,
onBlur,
onFocus,
schema,
placeholder,
}: WidgetProps<T, S, F>) {
const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;

Expand Down Expand Up @@ -81,6 +83,7 @@ function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extend
selectedOptions={selectedIndexesAsArray}
aria-describedby={ariaDescribedByIds<T>(id)}
>
{!multiple && schema.default === undefined && <Option value=''>{placeholder || ''}</Option>}
{Array.isArray(enumOptions) &&
enumOptions.map(({ value, label }, i) => {
const disabled = enumDisabled && enumDisabled.indexOf(value) !== -1;
Expand Down
1 change: 1 addition & 0 deletions packages/material-ui/src/SelectWidget/SelectWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export default function SelectWidget<
}}
aria-describedby={ariaDescribedByIds<T>(id)}
>
{!multiple && schema.default === undefined && <MenuItem value=''>{placeholder || ''}</MenuItem>}
{Array.isArray(enumOptions) &&
enumOptions.map(({ value, label }, i: number) => {
const disabled: boolean = Array.isArray(enumDisabled) && enumDisabled.indexOf(value) !== -1;
Expand Down
1 change: 1 addition & 0 deletions packages/mui/src/SelectWidget/SelectWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default function SelectWidget<
}}
aria-describedby={ariaDescribedByIds<T>(id)}
>
{!multiple && schema.default === undefined && <MenuItem value=''>{placeholder || ''}</MenuItem>}
{Array.isArray(enumOptions) &&
enumOptions.map(({ value, label }, i: number) => {
const disabled: boolean = Array.isArray(enumDisabled) && enumDisabled.indexOf(value) !== -1;
Expand Down
34 changes: 25 additions & 9 deletions packages/semantic-ui/src/SelectWidget/SelectWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
UIOptionsType,
} from '@rjsf/utils';
import map from 'lodash/map';
import { Form, DropdownProps } from 'semantic-ui-react';
import { Form, DropdownProps, DropdownItemProps } from 'semantic-ui-react';
import { getSemanticProps } from '../util';

/**
Expand All @@ -22,16 +22,25 @@ import { getSemanticProps } from '../util';
* @returns {*}
*/
function createDefaultValueOptionsForDropDown<S extends StrictRJSFSchema = RJSFSchema>(
schema: S,
enumOptions?: EnumOptionsType<S>[],
enumDisabled?: UIOptionsType['enumDisabled']
enumDisabled?: UIOptionsType['enumDisabled'],
multiple?: boolean,
placeholder?: string
) {
const disabledOptions = enumDisabled || [];
const options = map(enumOptions, ({ label, value }, index) => ({
disabled: disabledOptions.indexOf(value) !== -1,
key: label,
text: label,
value: String(index),
}));
const options: DropdownItemProps[] = [];
if (!multiple && schema.default === undefined) {
options.push({ value: '', text: placeholder || '' });
}
options.push(
...map(enumOptions, ({ label, value }, index) => ({
disabled: disabledOptions.indexOf(value) !== -1,
key: label,
text: label,
value: String(index),
}))
);
return options;
}

Expand Down Expand Up @@ -61,6 +70,7 @@ export default function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFS
onBlur,
onFocus,
rawErrors = [],
schema,
} = props;
const semanticProps = getSemanticProps<T, S, F>({
uiSchema,
Expand All @@ -76,7 +86,13 @@ export default function SelectWidget<T = any, S extends StrictRJSFSchema = RJSFS
});
const { enumDisabled, enumOptions, emptyValue: optEmptyVal } = options;
const emptyValue = multiple ? [] : '';
const dropdownOptions = createDefaultValueOptionsForDropDown<S>(enumOptions, enumDisabled);
const dropdownOptions = createDefaultValueOptionsForDropDown<S>(
schema,
enumOptions,
enumDisabled,
multiple,
placeholder
);
const _onChange = (_: SyntheticEvent<HTMLElement>, { value }: DropdownProps) =>
onChange(enumOptionsValueForIndex<S>(value as string[], enumOptions, optEmptyVal));
// eslint-disable-next-line no-shadow
Expand Down
76 changes: 70 additions & 6 deletions packages/semantic-ui/test/__snapshots__/Form.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,27 @@ exports[`semantic-ui specific tests field with special semantic options 1`] = `
<div
className="menu transition"
>
<div
aria-checked={true}
aria-selected={true}
className="active selected item"
onClick={[Function]}
role="option"
style={
{
"pointerEvents": "all",
}
}
>
<span
className="text"
/>
</div>
<div
aria-checked={false}
aria-disabled={false}
aria-selected={true}
className="selected item"
aria-selected={false}
className="item"
onClick={[Function]}
role="option"
style={
Expand Down Expand Up @@ -1278,11 +1294,27 @@ exports[`single fields select field 1`] = `
<div
className="menu transition"
>
<div
aria-checked={true}
aria-selected={true}
className="active selected item"
onClick={[Function]}
role="option"
style={
{
"pointerEvents": "all",
}
}
>
<span
className="text"
/>
</div>
<div
aria-checked={false}
aria-disabled={false}
aria-selected={true}
className="selected item"
aria-selected={false}
className="item"
onClick={[Function]}
role="option"
style={
Expand Down Expand Up @@ -1887,11 +1919,27 @@ exports[`single fields select field single choice enumDisabled 1`] = `
<div
className="menu transition"
>
<div
aria-checked={true}
aria-selected={true}
className="active selected item"
onClick={[Function]}
role="option"
style={
{
"pointerEvents": "all",
}
}
>
<span
className="text"
/>
</div>
<div
aria-checked={false}
aria-disabled={false}
aria-selected={true}
className="selected item"
aria-selected={false}
className="item"
onClick={[Function]}
role="option"
style={
Expand Down Expand Up @@ -1991,6 +2039,22 @@ exports[`single fields select field single choice formData 1`] = `
<div
className="menu transition"
>
<div
aria-checked={false}
aria-selected={false}
className="item"
onClick={[Function]}
role="option"
style={
{
"pointerEvents": "all",
}
}
>
<span
className="text"
/>
</div>
<div
aria-checked={false}
aria-disabled={false}
Expand Down

0 comments on commit e54a620

Please sign in to comment.