Skip to content

Commit

Permalink
fix(react): correctly handle controlled selectfields
Browse files Browse the repository at this point in the history
  • Loading branch information
dackmin committed Nov 25, 2022
1 parent 981b316 commit 26dede1
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 5 deletions.
1 change: 0 additions & 1 deletion packages/react/lib/SelectField/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ declare interface SelectFieldProps extends React.ComponentPropsWithRef<any> {
searchThreshold?: number;
required?: Boolean;
onChange?: (props: { value: any; valid: Boolean }) => void;
parseItem?: (option: any) => any;
parseTitle?: (option: any) => String;
parseValue?: (option: any) => any;
onBlur?: (event: Event) => void;
Expand Down
4 changes: 1 addition & 3 deletions packages/react/lib/SelectField/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const SelectField = forwardRef(({
searchThreshold = 400,
required = false,
onChange,
parseItem = val => val,
parseTitle = val => val?.toString?.(),
parseValue = val => val,
onBlur,
Expand Down Expand Up @@ -317,7 +316,7 @@ const SelectField = forwardRef(({
const findOptions = val => {
const isMultiple = multiple && Array.isArray(val);
const res = (isMultiple ? val : [val]).map(v =>
findDeep(options, o => parseItem(o) === parseItem(v), o => o.options) ||
findDeep(options, o => parseValue(o) === parseValue(v), o => o.options) ||
v
);

Expand Down Expand Up @@ -479,7 +478,6 @@ SelectField.propTypes = {
onKeyUp: PropTypes.func,
onSearch: PropTypes.func,
onValidate: PropTypes.func,
parseItem: PropTypes.func,
parseTitle: PropTypes.func,
parseValue: PropTypes.func,
};
Expand Down
18 changes: 18 additions & 0 deletions packages/react/lib/SelectField/index.stories.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useState } from 'react';
import { slideInDownMenu } from '@junipero/transitions';
import { action } from '@storybook/addon-actions';

import FieldControl from '../FieldControl';
import Label from '../Label';
Expand All @@ -11,9 +13,25 @@ export const basic = () => (
<SelectField
placeholder="Type a name"
options={['Item 1', 'Item 2', 'Item 3']}
onChange={action('onChange')}
/>
);

export const controlled = () => {
const [value, setValue] = useState('Item 1');

return (
<SelectField
value={value}
placeholder="Type a name"
options={['Item 1', 'Item 2', { title: 'Item 3', value: 'item-3' }]}
parseTitle={o => o.title || o}
parseValue={o => o.value || o}
onChange={field => setValue(field.value)}
/>
);
};

export const autoFocused = () => (
<SelectField
autoFocus
Expand Down
39 changes: 38 additions & 1 deletion packages/react/lib/SelectField/index.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createRef } from 'react';
import { createRef, useState } from 'react';
import { render, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

Expand Down Expand Up @@ -289,4 +289,41 @@ describe('<SelectField />', () => {

unmount();
});

it('should allow to use object options and display custom titles on a ' +
'controlled field', async () => {
const user = userEvent.setup();

const ControlledField = () => {
const [value, setValue] = useState('Item 1');

return (
<>
<p>Value: { value }</p>
<SelectField
value={value}
placeholder="Type a name"
options={[
'Item 1',
'Item 2',
{ title: 'Item 3', value: 'item-3' },
]}
parseTitle={o => o.title || o}
parseValue={o => o.value || o}
onChange={field => setValue(field.value)}
/>
</>
);
};

const { unmount, container, getByText } = render(<ControlledField />);

const input = container.querySelector('input');
await user.click(input);
await user.click(getByText('Item 3'));

expect(container).toMatchSnapshot();

unmount();
});
});
52 changes: 52 additions & 0 deletions packages/react/lib/SelectField/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,58 @@ exports[`<SelectField /> should allow to search for an external value 2`] = `
</div>
`;

exports[`<SelectField /> should allow to use object options and display custom titles on a controlled field 1`] = `
<div>
<p>
Value:
item-3
</p>
<div
class="junipero dropdown select-field dirty valid"
>
<div
class="field dropdown-toggle"
>
<input
readonly=""
type="text"
value="Item 3"
/>
<div
class="icons"
>
<svg
class="junipero icon remove"
height="10"
viewBox="0 0 9 10"
width="10"
>
<path
d="M8 1.5L1 8.5"
/>
<path
d="M1 1.5L8 8.5"
/>
</svg>
<svg
class="junipero icon arrows"
height="13"
viewBox="0 0 8 13"
width="8"
>
<path
d="M1 4.5L4 1.5L7 4.5"
/>
<path
d="M1 8.5L4 11.5L7 8.5"
/>
</svg>
</div>
</div>
</div>
</div>
`;

exports[`<SelectField /> should be invalid if validation fails 1`] = `
<div>
<div
Expand Down

0 comments on commit 26dede1

Please sign in to comment.