@automattic/vip-design-system 0.22.0 → 0.23.1

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.
@@ -24,7 +24,7 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
24
24
  */
25
25
  var styles = {
26
26
  height: '1px',
27
- backgroundColor: 'border',
27
+ backgroundColor: 'borders.2',
28
28
  my: '5px'
29
29
  };
30
30
  exports.styles = styles;
@@ -9,7 +9,7 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")
9
9
 
10
10
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
11
11
 
12
- var _react = _interopRequireDefault(require("react"));
12
+ var _react = _interopRequireWildcard(require("react"));
13
13
 
14
14
  var _propTypes = _interopRequireDefault(require("prop-types"));
15
15
 
@@ -21,7 +21,13 @@ var _FormSelectContent = require("./FormSelectContent");
21
21
 
22
22
  var _jsxRuntime = require("theme-ui/jsx-runtime");
23
23
 
24
- var _excluded = ["isInline", "placeholder", "forLabel", "options", "label"];
24
+ var _excluded = ["isInline", "placeholder", "forLabel", "options", "label", "getOptionLabel", "getOptionValue", "onChange"],
25
+ _excluded2 = ["options"];
26
+
27
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
28
+
29
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
30
+
25
31
  var MAX_SUGGESTED_OPTIONS = 15;
26
32
  var isDev = process.env.NODE_ENV !== 'production';
27
33
  var defaultStyles = {
@@ -69,6 +75,9 @@ var FormSelect = /*#__PURE__*/_react["default"].forwardRef(function (_ref2, forw
69
75
  forLabel = _ref2.forLabel,
70
76
  options = _ref2.options,
71
77
  label = _ref2.label,
78
+ getOptionLabel = _ref2.getOptionLabel,
79
+ getOptionValue = _ref2.getOptionValue,
80
+ onChange = _ref2.onChange,
72
81
  props = (0, _objectWithoutPropertiesLoose2["default"])(_ref2, _excluded);
73
82
 
74
83
  if (isDev && options.length > MAX_SUGGESTED_OPTIONS) {
@@ -76,6 +85,32 @@ var FormSelect = /*#__PURE__*/_react["default"].forwardRef(function (_ref2, forw
76
85
  console.info('For 16 or more items, consider using another component with a typeahead capability.');
77
86
  }
78
87
 
88
+ var getAllOptions = (0, _react.useMemo)(function () {
89
+ return [].concat(options.filter(function (option) {
90
+ return !option.options;
91
+ }), options.filter(function (option) {
92
+ return option.options;
93
+ }).map(function (option) {
94
+ return option.options;
95
+ })).reduce(function (a, b) {
96
+ return a.concat(b);
97
+ }, []);
98
+ }, [options]);
99
+ var optionLabel = (0, _react.useCallback)(function (option) {
100
+ return getOptionLabel ? getOptionLabel(option) : option.label;
101
+ }, [getOptionLabel]);
102
+ var optionValue = (0, _react.useCallback)(function (option) {
103
+ return getOptionValue ? getOptionValue(option) : option.value;
104
+ }, [getOptionValue]);
105
+ var getOptionByValue = (0, _react.useCallback)(function (value) {
106
+ return getAllOptions.find(function (option) {
107
+ return "" + optionValue(option) === "" + value;
108
+ });
109
+ }, [getAllOptions, optionValue]);
110
+ var onValueChange = (0, _react.useCallback)(function (event) {
111
+ return onChange ? onChange(getOptionByValue(event.target.value), event) : getOptionByValue(event.target.value);
112
+ }, [onChange, getOptionByValue]);
113
+
79
114
  var SelectLabel = function SelectLabel() {
80
115
  return (0, _jsxRuntime.jsx)(_Label.Label, {
81
116
  htmlFor: forLabel || props.id,
@@ -89,16 +124,17 @@ var FormSelect = /*#__PURE__*/_react["default"].forwardRef(function (_ref2, forw
89
124
  isInline: inlineLabel,
90
125
  label: inlineLabel ? (0, _jsxRuntime.jsx)(SelectLabel, {}) : null,
91
126
  children: [(0, _jsxRuntime.jsxs)("select", (0, _extends2["default"])({
127
+ onChange: onValueChange,
92
128
  ref: forwardRef,
93
129
  sx: defaultStyles
94
130
  }, props, {
95
131
  children: [placeholder && (0, _jsxRuntime.jsx)("option", {
96
132
  children: placeholder
97
133
  }), options.map(function (_ref3) {
98
- var optionLabel = _ref3.label,
99
- value = _ref3.value,
100
- groupOptions = _ref3.options;
101
- return value ? renderOption(optionLabel, value) : renderGroup(optionLabel, groupOptions);
134
+ var groupOptions = _ref3.options,
135
+ option = (0, _objectWithoutPropertiesLoose2["default"])(_ref3, _excluded2);
136
+ var value = optionValue(option);
137
+ return value ? renderOption(optionLabel(option), value) : renderGroup(optionLabel(option), groupOptions);
102
138
  })]
103
139
  })), (0, _jsxRuntime.jsx)(_FormSelectArrow.FormSelectArrow, {})]
104
140
  })]
@@ -112,6 +148,9 @@ FormSelect.propTypes = {
112
148
  forLabel: _propTypes["default"].string,
113
149
  placeholder: _propTypes["default"].string,
114
150
  label: _propTypes["default"].string,
115
- options: _propTypes["default"].array
151
+ options: _propTypes["default"].array,
152
+ getOptionLabel: _propTypes["default"].func,
153
+ getOptionValue: _propTypes["default"].func,
154
+ onChange: _propTypes["default"].func
116
155
  };
117
156
  FormSelect.displayName = 'FormSelect';
@@ -3,17 +3,19 @@
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
5
  exports.__esModule = true;
6
- exports["default"] = exports.WithGroup = exports.IsInline = exports.Default = void 0;
6
+ exports["default"] = exports.WithOptionLabelAndValue = exports.WithOnChange = exports.WithGroup = exports.IsInline = exports.Default = void 0;
7
7
 
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
 
10
10
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
11
11
 
12
+ var _react = require("react");
13
+
12
14
  var Form = _interopRequireWildcard(require("."));
13
15
 
14
16
  var _jsxRuntime = require("theme-ui/jsx-runtime");
15
17
 
16
- var _excluded = ["label", "width"];
18
+ var _excluded = ["label", "width", "onChange"];
17
19
 
18
20
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
19
21
 
@@ -52,6 +54,13 @@ var options = [{
52
54
  }, {
53
55
  value: 'vanilla',
54
56
  label: 'Vanilla'
57
+ }];
58
+ var groupedOptions = [{
59
+ label: 'Group name',
60
+ options: options
61
+ }, {
62
+ label: 'Another Group name',
63
+ options: options
55
64
  }]; // eslint-disable-next-line react/prop-types
56
65
 
57
66
  var DefaultComponent = function DefaultComponent(_ref) {
@@ -59,6 +68,7 @@ var DefaultComponent = function DefaultComponent(_ref) {
59
68
  label = _ref$label === void 0 ? 'Label' : _ref$label,
60
69
  _ref$width = _ref.width,
61
70
  width = _ref$width === void 0 ? 250 : _ref$width,
71
+ onChange = _ref.onChange,
62
72
  rest = (0, _objectWithoutPropertiesLoose2["default"])(_ref, _excluded);
63
73
  return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
64
74
  children: [(0, _jsxRuntime.jsxs)("p", {
@@ -79,7 +89,8 @@ var DefaultComponent = function DefaultComponent(_ref) {
79
89
  },
80
90
  children: (0, _jsxRuntime.jsx)(Form.Select, (0, _extends2["default"])({
81
91
  id: "form-select",
82
- label: label
92
+ label: label,
93
+ onChange: onChange
83
94
  }, rest))
84
95
  })
85
96
  })]
@@ -96,13 +107,7 @@ var WithGroup = DefaultComponent.bind({});
96
107
  exports.WithGroup = WithGroup;
97
108
  WithGroup.args = {
98
109
  label: 'Group Label',
99
- options: [{
100
- label: 'Group name',
101
- options: options
102
- }, {
103
- label: 'Another Group name',
104
- options: options
105
- }]
110
+ options: [].concat(options, groupedOptions)
106
111
  };
107
112
  var IsInline = DefaultComponent.bind({});
108
113
  exports.IsInline = IsInline;
@@ -110,11 +115,56 @@ IsInline.args = {
110
115
  label: 'Inline Select',
111
116
  isInline: true,
112
117
  width: '100%',
113
- options: [{
114
- label: 'Group name',
115
- options: options
116
- }, {
117
- label: 'Another Group name',
118
- options: options
119
- }]
120
- };
118
+ options: groupedOptions
119
+ };
120
+ var WithOptionLabelAndValue = DefaultComponent.bind({});
121
+ exports.WithOptionLabelAndValue = WithOptionLabelAndValue;
122
+ WithOptionLabelAndValue.args = {
123
+ label: 'Select with getOptionLabel / getOptionValue',
124
+ width: '100%',
125
+ options: options.map(function (_ref2) {
126
+ var label = _ref2.label,
127
+ value = _ref2.value;
128
+ return {
129
+ name: label,
130
+ id: value
131
+ };
132
+ }),
133
+ getOptionLabel: function getOptionLabel(option) {
134
+ return option.name;
135
+ },
136
+ getOptionValue: function getOptionValue(option) {
137
+ return option.id;
138
+ }
139
+ };
140
+
141
+ var WithOnChange = function WithOnChange() {
142
+ var _useState = (0, _react.useState)(null),
143
+ option = _useState[0],
144
+ setOption = _useState[1];
145
+
146
+ var onChange = (0, _react.useCallback)(function (val, event) {
147
+ return setOption({
148
+ obj: val,
149
+ eventValue: event.target.value
150
+ });
151
+ });
152
+ var args = {
153
+ label: 'Select with onChange',
154
+ placeholder: '- Select -',
155
+ width: '100%',
156
+ onChange: onChange,
157
+ options: [].concat(options, groupedOptions)
158
+ };
159
+ return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
160
+ children: [(0, _jsxRuntime.jsx)(DefaultComponent, (0, _extends2["default"])({
161
+ onChange: onChange
162
+ }, args)), option && (0, _jsxRuntime.jsxs)("p", {
163
+ children: ["Object to JSON: ", JSON.stringify(option.obj)]
164
+ }), option && (0, _jsxRuntime.jsxs)("p", {
165
+ children: ["Original Event Value: ", option.eventValue]
166
+ })]
167
+ });
168
+ };
169
+
170
+ exports.WithOnChange = WithOnChange;
@@ -140,4 +140,54 @@ describe('<FormSelect />', function () {
140
140
  }
141
141
  }, _callee3);
142
142
  })));
143
+ it('renders the FormSelect component when getOptionLabel and getOptionValue', /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4() {
144
+ var props, _render4, container;
145
+
146
+ return _regenerator["default"].wrap(function _callee4$(_context4) {
147
+ while (1) {
148
+ switch (_context4.prev = _context4.next) {
149
+ case 0:
150
+ props = (0, _extends2["default"])({}, defaultProps, {
151
+ options: options.map(function (_ref5) {
152
+ var label = _ref5.label,
153
+ value = _ref5.value;
154
+ return {
155
+ name: label,
156
+ id: value
157
+ };
158
+ }),
159
+ getOptionLabel: function getOptionLabel(option) {
160
+ return option.name;
161
+ },
162
+ getOptionValue: function getOptionValue(option) {
163
+ return option.id;
164
+ }
165
+ });
166
+ _render4 = (0, _react.render)((0, _jsxRuntime.jsx)(_FormSelect.FormSelect, (0, _extends2["default"])({
167
+ id: "my_desert_list"
168
+ }, props))), container = _render4.container;
169
+ expect(_react.screen.getByLabelText(defaultProps.label)).toBeInTheDocument();
170
+ expect(_react.screen.getByRole('combobox')).toBeInTheDocument();
171
+ expect(_react.screen.getAllByRole('option')).toHaveLength(3);
172
+ expect(_react.screen.getByText(options[0].label)).toBeInTheDocument();
173
+ expect(_react.screen.getByText(options[1].label)).toBeInTheDocument();
174
+ expect(_react.screen.getByText(options[2].label)).toBeInTheDocument();
175
+ expect(_react.screen.queryByRole('group')).not.toBeInTheDocument(); // Check for accessibility issues
176
+
177
+ _context4.t0 = expect;
178
+ _context4.next = 12;
179
+ return (0, _jestAxe.axe)(container);
180
+
181
+ case 12:
182
+ _context4.t1 = _context4.sent;
183
+ _context4.next = 15;
184
+ return (0, _context4.t0)(_context4.t1).toHaveNoViolations();
185
+
186
+ case 15:
187
+ case "end":
188
+ return _context4.stop();
189
+ }
190
+ }
191
+ }, _callee4);
192
+ })));
143
193
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/vip-design-system",
3
- "version": "0.22.0",
3
+ "version": "0.23.1",
4
4
  "main": "build/system/index.js",
5
5
  "scripts": {
6
6
  "build-storybook": "build-storybook",
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "@radix-ui/react-checkbox": "^1.0.0",
24
24
  "@radix-ui/react-dialog": "^1.0.0",
25
- "@radix-ui/react-dropdown-menu": "^1.0.0",
25
+ "@radix-ui/react-dropdown-menu": "^1.0.1-rc.6",
26
26
  "@radix-ui/react-radio-group": "^1.0.0",
27
27
  "@radix-ui/react-switch": "^1.0.0",
28
28
  "@radix-ui/react-tooltip": "^1.0.0",
@@ -8,7 +8,7 @@ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
8
8
 
9
9
  export const styles = {
10
10
  height: '1px',
11
- backgroundColor: 'border',
11
+ backgroundColor: 'borders.2',
12
12
  my: '5px',
13
13
  };
14
14
 
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
- import React from 'react';
6
+ import React, { useCallback, useMemo } from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import { Label } from '../Form/Label';
9
9
 
@@ -47,7 +47,20 @@ const renderGroup = ( groupLabel, groupOptions ) => {
47
47
  };
48
48
 
49
49
  const FormSelect = React.forwardRef(
50
- ( { isInline, placeholder, forLabel, options, label, ...props }, forwardRef ) => {
50
+ (
51
+ {
52
+ isInline,
53
+ placeholder,
54
+ forLabel,
55
+ options,
56
+ label,
57
+ getOptionLabel,
58
+ getOptionValue,
59
+ onChange,
60
+ ...props
61
+ },
62
+ forwardRef
63
+ ) => {
51
64
  if ( isDev && options.length > MAX_SUGGESTED_OPTIONS ) {
52
65
  // eslint-disable-next-line no-console
53
66
  console.info(
@@ -55,7 +68,40 @@ const FormSelect = React.forwardRef(
55
68
  );
56
69
  }
57
70
 
71
+ const getAllOptions = useMemo(
72
+ () =>
73
+ [
74
+ ...options.filter( option => ! option.options ),
75
+ ...options.filter( option => option.options ).map( option => option.options ),
76
+ ].reduce( ( a, b ) => a.concat( b ), [] ),
77
+ [ options ]
78
+ );
79
+
80
+ const optionLabel = useCallback(
81
+ option => ( getOptionLabel ? getOptionLabel( option ) : option.label ),
82
+ [ getOptionLabel ]
83
+ );
84
+
85
+ const optionValue = useCallback(
86
+ option => ( getOptionValue ? getOptionValue( option ) : option.value ),
87
+ [ getOptionValue ]
88
+ );
89
+
90
+ const getOptionByValue = useCallback(
91
+ value => getAllOptions.find( option => `${ optionValue( option ) }` === `${ value }` ),
92
+ [ getAllOptions, optionValue ]
93
+ );
94
+
95
+ const onValueChange = useCallback(
96
+ event =>
97
+ onChange
98
+ ? onChange( getOptionByValue( event.target.value ), event )
99
+ : getOptionByValue( event.target.value ),
100
+ [ onChange, getOptionByValue ]
101
+ );
102
+
58
103
  const SelectLabel = () => <Label htmlFor={ forLabel || props.id }>{ label }</Label>;
104
+
59
105
  const inlineLabel = !! ( isInline && label );
60
106
 
61
107
  return (
@@ -63,11 +109,15 @@ const FormSelect = React.forwardRef(
63
109
  { label && ! isInline && <SelectLabel /> }
64
110
 
65
111
  <FormSelectContent isInline={ inlineLabel } label={ inlineLabel ? <SelectLabel /> : null }>
66
- <select ref={ forwardRef } sx={ defaultStyles } { ...props }>
112
+ <select onChange={ onValueChange } ref={ forwardRef } sx={ defaultStyles } { ...props }>
67
113
  { placeholder && <option>{ placeholder }</option> }
68
- { options.map( ( { label: optionLabel, value, options: groupOptions } ) =>
69
- value ? renderOption( optionLabel, value ) : renderGroup( optionLabel, groupOptions )
70
- ) }
114
+ { options.map( ( { options: groupOptions, ...option } ) => {
115
+ const value = optionValue( option );
116
+
117
+ return value
118
+ ? renderOption( optionLabel( option ), value )
119
+ : renderGroup( optionLabel( option ), groupOptions );
120
+ } ) }
71
121
  </select>
72
122
 
73
123
  <FormSelectArrow />
@@ -84,6 +134,9 @@ FormSelect.propTypes = {
84
134
  placeholder: PropTypes.string,
85
135
  label: PropTypes.string,
86
136
  options: PropTypes.array,
137
+ getOptionLabel: PropTypes.func,
138
+ getOptionValue: PropTypes.func,
139
+ onChange: PropTypes.func,
87
140
  };
88
141
 
89
142
  FormSelect.displayName = 'FormSelect';
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * Internal dependencies
5
5
  */
6
+ import { useCallback, useState } from 'react';
6
7
  import * as Form from '.';
7
8
 
8
9
  export default {
@@ -25,8 +26,19 @@ const options = [
25
26
  { value: 'vanilla', label: 'Vanilla' },
26
27
  ];
27
28
 
29
+ const groupedOptions = [
30
+ {
31
+ label: 'Group name',
32
+ options: options,
33
+ },
34
+ {
35
+ label: 'Another Group name',
36
+ options: options,
37
+ },
38
+ ];
39
+
28
40
  // eslint-disable-next-line react/prop-types
29
- const DefaultComponent = ( { label = 'Label', width = 250, ...rest } ) => (
41
+ const DefaultComponent = ( { label = 'Label', width = 250, onChange, ...rest } ) => (
30
42
  <>
31
43
  <p>
32
44
  This is a simple wrapper at the top of a browser default select component. This component
@@ -49,7 +61,7 @@ const DefaultComponent = ( { label = 'Label', width = 250, ...rest } ) => (
49
61
  </p>
50
62
  <Form.Root>
51
63
  <div sx={ { width } }>
52
- <Form.Select id="form-select" label={ label } { ...rest } />
64
+ <Form.Select id="form-select" label={ label } onChange={ onChange } { ...rest } />
53
65
  </div>
54
66
  </Form.Root>
55
67
  </>
@@ -65,16 +77,7 @@ export const WithGroup = DefaultComponent.bind( {} );
65
77
 
66
78
  WithGroup.args = {
67
79
  label: 'Group Label',
68
- options: [
69
- {
70
- label: 'Group name',
71
- options: options,
72
- },
73
- {
74
- label: 'Another Group name',
75
- options: options,
76
- },
77
- ],
80
+ options: [ ...options, ...groupedOptions ],
78
81
  };
79
82
 
80
83
  export const IsInline = DefaultComponent.bind( {} );
@@ -83,14 +86,42 @@ IsInline.args = {
83
86
  label: 'Inline Select',
84
87
  isInline: true,
85
88
  width: '100%',
86
- options: [
87
- {
88
- label: 'Group name',
89
- options: options,
90
- },
91
- {
92
- label: 'Another Group name',
93
- options: options,
94
- },
95
- ],
89
+ options: groupedOptions,
90
+ };
91
+
92
+ export const WithOptionLabelAndValue = DefaultComponent.bind( {} );
93
+
94
+ WithOptionLabelAndValue.args = {
95
+ label: 'Select with getOptionLabel / getOptionValue',
96
+ width: '100%',
97
+ options: options.map( ( { label, value } ) => ( {
98
+ name: label,
99
+ id: value,
100
+ } ) ),
101
+ getOptionLabel: option => option.name,
102
+ getOptionValue: option => option.id,
103
+ };
104
+
105
+ export const WithOnChange = () => {
106
+ const [ option, setOption ] = useState( null );
107
+
108
+ const onChange = useCallback( ( val, event ) =>
109
+ setOption( { obj: val, eventValue: event.target.value } )
110
+ );
111
+
112
+ const args = {
113
+ label: 'Select with onChange',
114
+ placeholder: '- Select -',
115
+ width: '100%',
116
+ onChange,
117
+ options: [ ...options, ...groupedOptions ],
118
+ };
119
+
120
+ return (
121
+ <>
122
+ <DefaultComponent onChange={ onChange } { ...args } />
123
+ { option && <p>Object to JSON: { JSON.stringify( option.obj ) }</p> }
124
+ { option && <p>Original Event Value: { option.eventValue }</p> }
125
+ </>
126
+ );
96
127
  };
@@ -69,4 +69,29 @@ describe( '<FormSelect />', () => {
69
69
  // Check for accessibility issues
70
70
  await expect( await axe( container ) ).toHaveNoViolations();
71
71
  } );
72
+
73
+ it( 'renders the FormSelect component when getOptionLabel and getOptionValue', async () => {
74
+ const props = {
75
+ ...defaultProps,
76
+ options: options.map( ( { label, value } ) => ( {
77
+ name: label,
78
+ id: value,
79
+ } ) ),
80
+ getOptionLabel: option => option.name,
81
+ getOptionValue: option => option.id,
82
+ };
83
+
84
+ const { container } = render( <FormSelect id="my_desert_list" { ...props } /> );
85
+
86
+ expect( screen.getByLabelText( defaultProps.label ) ).toBeInTheDocument();
87
+ expect( screen.getByRole( 'combobox' ) ).toBeInTheDocument();
88
+ expect( screen.getAllByRole( 'option' ) ).toHaveLength( 3 );
89
+ expect( screen.getByText( options[ 0 ].label ) ).toBeInTheDocument();
90
+ expect( screen.getByText( options[ 1 ].label ) ).toBeInTheDocument();
91
+ expect( screen.getByText( options[ 2 ].label ) ).toBeInTheDocument();
92
+ expect( screen.queryByRole( 'group' ) ).not.toBeInTheDocument();
93
+
94
+ // Check for accessibility issues
95
+ await expect( await axe( container ) ).toHaveNoViolations();
96
+ } );
72
97
  } );