@instructure/ui-simple-select 10.2.3-snapshot-5 → 10.2.3-snapshot-7
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.
- package/CHANGELOG.md +5 -2
- package/es/SimpleSelect/__new-tests__/SimpleSelect.test.js +49 -1
- package/es/SimpleSelect/index.js +18 -0
- package/lib/SimpleSelect/__new-tests__/SimpleSelect.test.js +48 -0
- package/lib/SimpleSelect/index.js +18 -0
- package/package.json +15 -15
- package/src/SimpleSelect/__new-tests__/SimpleSelect.test.tsx +61 -1
- package/src/SimpleSelect/index.tsx +26 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/SimpleSelect/index.d.ts +1 -0
- package/types/SimpleSelect/index.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
@@ -3,9 +3,12 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
5
5
|
|
6
|
-
## [10.2.3-snapshot-
|
6
|
+
## [10.2.3-snapshot-7](https://github.com/instructure/instructure-ui/compare/v10.2.2...v10.2.3-snapshot-7) (2024-09-27)
|
7
7
|
|
8
|
-
|
8
|
+
|
9
|
+
### Bug Fixes
|
10
|
+
|
11
|
+
* **ui-simple-select:** ensure input value updates correctly when options change ([4dc7cb2](https://github.com/instructure/instructure-ui/commit/4dc7cb2cfde69d28baaaced32a5e63aea9a48ee1))
|
9
12
|
|
10
13
|
|
11
14
|
|
@@ -22,7 +22,7 @@
|
|
22
22
|
* SOFTWARE.
|
23
23
|
*/
|
24
24
|
import React from 'react';
|
25
|
-
import { render } from '@testing-library/react';
|
25
|
+
import { render, fireEvent, screen } from '@testing-library/react';
|
26
26
|
import { vi } from 'vitest';
|
27
27
|
import '@testing-library/jest-dom';
|
28
28
|
import SimpleSelect from '../index';
|
@@ -63,4 +63,52 @@ describe('<SimpleSelect />', () => {
|
|
63
63
|
const input = container.querySelector('input');
|
64
64
|
expect(input).toHaveAttribute('role', 'combobox');
|
65
65
|
});
|
66
|
+
describe('children', () => {
|
67
|
+
const initialOptions = ['foo', 'bar'];
|
68
|
+
const updatedOptions = ['bar', 'baz'];
|
69
|
+
const getOptions = options => options.map(opt => /*#__PURE__*/React.createElement(SimpleSelect.Option, {
|
70
|
+
id: opt,
|
71
|
+
key: opt,
|
72
|
+
value: opt
|
73
|
+
}, opt));
|
74
|
+
const renderSimpleSelect = options => {
|
75
|
+
return render( /*#__PURE__*/React.createElement(SimpleSelect, {
|
76
|
+
renderLabel: "Choose an option"
|
77
|
+
}, getOptions(options)));
|
78
|
+
};
|
79
|
+
it('should clear selection if selected option does not exist in updated options', () => {
|
80
|
+
const _renderSimpleSelect = renderSimpleSelect(initialOptions),
|
81
|
+
rerender = _renderSimpleSelect.rerender;
|
82
|
+
const input = screen.getByRole('combobox', {
|
83
|
+
name: 'Choose an option'
|
84
|
+
});
|
85
|
+
fireEvent.click(input);
|
86
|
+
const fooOption = screen.getByRole('option', {
|
87
|
+
name: 'foo'
|
88
|
+
});
|
89
|
+
fireEvent.click(fooOption);
|
90
|
+
expect(input).toHaveValue('foo');
|
91
|
+
rerender( /*#__PURE__*/React.createElement(SimpleSelect, {
|
92
|
+
renderLabel: "Choose an option"
|
93
|
+
}, getOptions(updatedOptions)));
|
94
|
+
expect(input).toHaveValue('');
|
95
|
+
});
|
96
|
+
it('should persist selected option if it exists in updated options', () => {
|
97
|
+
const _renderSimpleSelect2 = renderSimpleSelect(initialOptions),
|
98
|
+
rerender = _renderSimpleSelect2.rerender;
|
99
|
+
const input = screen.getByRole('combobox', {
|
100
|
+
name: 'Choose an option'
|
101
|
+
});
|
102
|
+
fireEvent.click(input);
|
103
|
+
const barOption = screen.getByRole('option', {
|
104
|
+
name: 'bar'
|
105
|
+
});
|
106
|
+
fireEvent.click(barOption);
|
107
|
+
expect(input).toHaveValue('bar');
|
108
|
+
rerender( /*#__PURE__*/React.createElement(SimpleSelect, {
|
109
|
+
renderLabel: "Choose an option"
|
110
|
+
}, getOptions(updatedOptions)));
|
111
|
+
expect(input).toHaveValue('bar');
|
112
|
+
});
|
113
|
+
});
|
66
114
|
});
|
package/es/SimpleSelect/index.js
CHANGED
@@ -176,7 +176,25 @@ let SimpleSelect = (_dec = withDeterministicId(), _dec2 = testable(), _dec(_clas
|
|
176
176
|
props: this.props
|
177
177
|
});
|
178
178
|
}
|
179
|
+
hasOptionsChanged(prevChildren, currentChildren) {
|
180
|
+
const getValues = children => React.Children.map(children, child => {
|
181
|
+
if ( /*#__PURE__*/React.isValidElement(child)) {
|
182
|
+
return child.props.value;
|
183
|
+
}
|
184
|
+
return null;
|
185
|
+
});
|
186
|
+
const prevValues = getValues(prevChildren);
|
187
|
+
const currentValues = getValues(currentChildren);
|
188
|
+
return JSON.stringify(prevValues) !== JSON.stringify(currentValues);
|
189
|
+
}
|
179
190
|
componentDidUpdate(prevProps) {
|
191
|
+
if (this.hasOptionsChanged(prevProps.children, this.props.children)) {
|
192
|
+
const option = this.getOption('value', this.state.inputValue);
|
193
|
+
this.setState({
|
194
|
+
inputValue: option ? option.props.children : void 0,
|
195
|
+
selectedOptionId: option ? option.props.id : ''
|
196
|
+
});
|
197
|
+
}
|
180
198
|
if (this.props.value !== prevProps.value) {
|
181
199
|
let option = this.getOption('value', this.props.value);
|
182
200
|
if (typeof this.props.value === 'undefined') {
|
@@ -68,4 +68,52 @@ describe('<SimpleSelect />', () => {
|
|
68
68
|
const input = container.querySelector('input');
|
69
69
|
expect(input).toHaveAttribute('role', 'combobox');
|
70
70
|
});
|
71
|
+
describe('children', () => {
|
72
|
+
const initialOptions = ['foo', 'bar'];
|
73
|
+
const updatedOptions = ['bar', 'baz'];
|
74
|
+
const getOptions = options => options.map(opt => /*#__PURE__*/_react.default.createElement(_index.default.Option, {
|
75
|
+
id: opt,
|
76
|
+
key: opt,
|
77
|
+
value: opt
|
78
|
+
}, opt));
|
79
|
+
const renderSimpleSelect = options => {
|
80
|
+
return (0, _react2.render)( /*#__PURE__*/_react.default.createElement(_index.default, {
|
81
|
+
renderLabel: "Choose an option"
|
82
|
+
}, getOptions(options)));
|
83
|
+
};
|
84
|
+
it('should clear selection if selected option does not exist in updated options', () => {
|
85
|
+
const _renderSimpleSelect = renderSimpleSelect(initialOptions),
|
86
|
+
rerender = _renderSimpleSelect.rerender;
|
87
|
+
const input = _react2.screen.getByRole('combobox', {
|
88
|
+
name: 'Choose an option'
|
89
|
+
});
|
90
|
+
_react2.fireEvent.click(input);
|
91
|
+
const fooOption = _react2.screen.getByRole('option', {
|
92
|
+
name: 'foo'
|
93
|
+
});
|
94
|
+
_react2.fireEvent.click(fooOption);
|
95
|
+
expect(input).toHaveValue('foo');
|
96
|
+
rerender( /*#__PURE__*/_react.default.createElement(_index.default, {
|
97
|
+
renderLabel: "Choose an option"
|
98
|
+
}, getOptions(updatedOptions)));
|
99
|
+
expect(input).toHaveValue('');
|
100
|
+
});
|
101
|
+
it('should persist selected option if it exists in updated options', () => {
|
102
|
+
const _renderSimpleSelect2 = renderSimpleSelect(initialOptions),
|
103
|
+
rerender = _renderSimpleSelect2.rerender;
|
104
|
+
const input = _react2.screen.getByRole('combobox', {
|
105
|
+
name: 'Choose an option'
|
106
|
+
});
|
107
|
+
_react2.fireEvent.click(input);
|
108
|
+
const barOption = _react2.screen.getByRole('option', {
|
109
|
+
name: 'bar'
|
110
|
+
});
|
111
|
+
_react2.fireEvent.click(barOption);
|
112
|
+
expect(input).toHaveValue('bar');
|
113
|
+
rerender( /*#__PURE__*/_react.default.createElement(_index.default, {
|
114
|
+
renderLabel: "Choose an option"
|
115
|
+
}, getOptions(updatedOptions)));
|
116
|
+
expect(input).toHaveValue('bar');
|
117
|
+
});
|
118
|
+
});
|
71
119
|
});
|
@@ -187,7 +187,25 @@ let SimpleSelect = exports.SimpleSelect = (_dec = (0, _withDeterministicId.withD
|
|
187
187
|
props: this.props
|
188
188
|
});
|
189
189
|
}
|
190
|
+
hasOptionsChanged(prevChildren, currentChildren) {
|
191
|
+
const getValues = children => _react.default.Children.map(children, child => {
|
192
|
+
if ( /*#__PURE__*/_react.default.isValidElement(child)) {
|
193
|
+
return child.props.value;
|
194
|
+
}
|
195
|
+
return null;
|
196
|
+
});
|
197
|
+
const prevValues = getValues(prevChildren);
|
198
|
+
const currentValues = getValues(currentChildren);
|
199
|
+
return JSON.stringify(prevValues) !== JSON.stringify(currentValues);
|
200
|
+
}
|
190
201
|
componentDidUpdate(prevProps) {
|
202
|
+
if (this.hasOptionsChanged(prevProps.children, this.props.children)) {
|
203
|
+
const option = this.getOption('value', this.state.inputValue);
|
204
|
+
this.setState({
|
205
|
+
inputValue: option ? option.props.children : void 0,
|
206
|
+
selectedOptionId: option ? option.props.id : ''
|
207
|
+
});
|
208
|
+
}
|
191
209
|
if (this.props.value !== prevProps.value) {
|
192
210
|
let option = this.getOption('value', this.props.value);
|
193
211
|
if (typeof this.props.value === 'undefined') {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@instructure/ui-simple-select",
|
3
|
-
"version": "10.2.3-snapshot-
|
3
|
+
"version": "10.2.3-snapshot-7",
|
4
4
|
"description": "A component for standard select element behavior.",
|
5
5
|
"author": "Instructure, Inc. Engineering and Product Design",
|
6
6
|
"module": "./es/index.js",
|
@@ -24,23 +24,23 @@
|
|
24
24
|
"license": "MIT",
|
25
25
|
"dependencies": {
|
26
26
|
"@babel/runtime": "^7.24.5",
|
27
|
-
"@instructure/console": "10.2.3-snapshot-
|
28
|
-
"@instructure/shared-types": "10.2.3-snapshot-
|
29
|
-
"@instructure/ui-form-field": "10.2.3-snapshot-
|
30
|
-
"@instructure/ui-position": "10.2.3-snapshot-
|
31
|
-
"@instructure/ui-prop-types": "10.2.3-snapshot-
|
32
|
-
"@instructure/ui-react-utils": "10.2.3-snapshot-
|
33
|
-
"@instructure/ui-select": "10.2.3-snapshot-
|
34
|
-
"@instructure/ui-testable": "10.2.3-snapshot-
|
27
|
+
"@instructure/console": "10.2.3-snapshot-7",
|
28
|
+
"@instructure/shared-types": "10.2.3-snapshot-7",
|
29
|
+
"@instructure/ui-form-field": "10.2.3-snapshot-7",
|
30
|
+
"@instructure/ui-position": "10.2.3-snapshot-7",
|
31
|
+
"@instructure/ui-prop-types": "10.2.3-snapshot-7",
|
32
|
+
"@instructure/ui-react-utils": "10.2.3-snapshot-7",
|
33
|
+
"@instructure/ui-select": "10.2.3-snapshot-7",
|
34
|
+
"@instructure/ui-testable": "10.2.3-snapshot-7",
|
35
35
|
"prop-types": "^15.8.1"
|
36
36
|
},
|
37
37
|
"devDependencies": {
|
38
|
-
"@instructure/ui-babel-preset": "10.2.3-snapshot-
|
39
|
-
"@instructure/ui-color-utils": "10.2.3-snapshot-
|
40
|
-
"@instructure/ui-icons": "10.2.3-snapshot-
|
41
|
-
"@instructure/ui-test-locator": "10.2.3-snapshot-
|
42
|
-
"@instructure/ui-test-utils": "10.2.3-snapshot-
|
43
|
-
"@instructure/ui-utils": "10.2.3-snapshot-
|
38
|
+
"@instructure/ui-babel-preset": "10.2.3-snapshot-7",
|
39
|
+
"@instructure/ui-color-utils": "10.2.3-snapshot-7",
|
40
|
+
"@instructure/ui-icons": "10.2.3-snapshot-7",
|
41
|
+
"@instructure/ui-test-locator": "10.2.3-snapshot-7",
|
42
|
+
"@instructure/ui-test-utils": "10.2.3-snapshot-7",
|
43
|
+
"@instructure/ui-utils": "10.2.3-snapshot-7",
|
44
44
|
"@testing-library/jest-dom": "^6.4.6",
|
45
45
|
"@testing-library/react": "^15.0.7",
|
46
46
|
"vitest": "^2.0.2"
|
@@ -22,7 +22,7 @@
|
|
22
22
|
* SOFTWARE.
|
23
23
|
*/
|
24
24
|
import React from 'react'
|
25
|
-
import { render } from '@testing-library/react'
|
25
|
+
import { render, fireEvent, screen } from '@testing-library/react'
|
26
26
|
import { vi } from 'vitest'
|
27
27
|
import '@testing-library/jest-dom'
|
28
28
|
import SimpleSelect from '../index'
|
@@ -73,4 +73,64 @@ describe('<SimpleSelect />', () => {
|
|
73
73
|
const input = container.querySelector('input')
|
74
74
|
expect(input).toHaveAttribute('role', 'combobox')
|
75
75
|
})
|
76
|
+
|
77
|
+
describe('children', () => {
|
78
|
+
const initialOptions: ExampleOption[] = ['foo', 'bar']
|
79
|
+
const updatedOptions: ExampleOption[] = ['bar', 'baz']
|
80
|
+
|
81
|
+
const getOptions = (options: string[]) =>
|
82
|
+
options.map((opt) => (
|
83
|
+
<SimpleSelect.Option id={opt} key={opt} value={opt}>
|
84
|
+
{opt}
|
85
|
+
</SimpleSelect.Option>
|
86
|
+
))
|
87
|
+
|
88
|
+
const renderSimpleSelect = (options: ExampleOption[]) => {
|
89
|
+
return render(
|
90
|
+
<SimpleSelect renderLabel="Choose an option">
|
91
|
+
{getOptions(options)}
|
92
|
+
</SimpleSelect>
|
93
|
+
)
|
94
|
+
}
|
95
|
+
|
96
|
+
it('should clear selection if selected option does not exist in updated options', () => {
|
97
|
+
const { rerender } = renderSimpleSelect(initialOptions)
|
98
|
+
|
99
|
+
const input = screen.getByRole('combobox', { name: 'Choose an option' })
|
100
|
+
fireEvent.click(input)
|
101
|
+
|
102
|
+
const fooOption = screen.getByRole('option', { name: 'foo' })
|
103
|
+
fireEvent.click(fooOption)
|
104
|
+
|
105
|
+
expect(input).toHaveValue('foo')
|
106
|
+
|
107
|
+
rerender(
|
108
|
+
<SimpleSelect renderLabel="Choose an option">
|
109
|
+
{getOptions(updatedOptions)}
|
110
|
+
</SimpleSelect>
|
111
|
+
)
|
112
|
+
|
113
|
+
expect(input).toHaveValue('')
|
114
|
+
})
|
115
|
+
|
116
|
+
it('should persist selected option if it exists in updated options', () => {
|
117
|
+
const { rerender } = renderSimpleSelect(initialOptions)
|
118
|
+
|
119
|
+
const input = screen.getByRole('combobox', { name: 'Choose an option' })
|
120
|
+
fireEvent.click(input)
|
121
|
+
|
122
|
+
const barOption = screen.getByRole('option', { name: 'bar' })
|
123
|
+
fireEvent.click(barOption)
|
124
|
+
|
125
|
+
expect(input).toHaveValue('bar')
|
126
|
+
|
127
|
+
rerender(
|
128
|
+
<SimpleSelect renderLabel="Choose an option">
|
129
|
+
{getOptions(updatedOptions)}
|
130
|
+
</SimpleSelect>
|
131
|
+
)
|
132
|
+
|
133
|
+
expect(input).toHaveValue('bar')
|
134
|
+
})
|
135
|
+
})
|
76
136
|
})
|
@@ -130,7 +130,33 @@ class SimpleSelect extends Component<SimpleSelectProps, SimpleSelectState> {
|
|
130
130
|
return getInteraction({ props: this.props })
|
131
131
|
}
|
132
132
|
|
133
|
+
hasOptionsChanged(
|
134
|
+
prevChildren: SimpleSelectProps['children'],
|
135
|
+
currentChildren: SimpleSelectProps['children']
|
136
|
+
) {
|
137
|
+
const getValues = (children: SimpleSelectProps['children']) =>
|
138
|
+
React.Children.map(children, (child) => {
|
139
|
+
if (React.isValidElement(child)) {
|
140
|
+
return child.props.value
|
141
|
+
}
|
142
|
+
return null
|
143
|
+
})
|
144
|
+
|
145
|
+
const prevValues = getValues(prevChildren)
|
146
|
+
const currentValues = getValues(currentChildren)
|
147
|
+
|
148
|
+
return JSON.stringify(prevValues) !== JSON.stringify(currentValues)
|
149
|
+
}
|
150
|
+
|
133
151
|
componentDidUpdate(prevProps: SimpleSelectProps) {
|
152
|
+
if (this.hasOptionsChanged(prevProps.children, this.props.children)) {
|
153
|
+
const option = this.getOption('value', this.state.inputValue)
|
154
|
+
this.setState({
|
155
|
+
inputValue: option ? option.props.children : undefined,
|
156
|
+
selectedOptionId: option ? option.props.id : ''
|
157
|
+
})
|
158
|
+
}
|
159
|
+
|
134
160
|
if (this.props.value !== prevProps.value) {
|
135
161
|
let option = this.getOption('value', this.props.value)
|
136
162
|
if (typeof this.props.value === 'undefined') {
|