@loadsmart/loadsmart-ui 5.11.2-beta.1 → 5.12.0
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/dist/components/Select/Select.types.d.ts +10 -3
- package/dist/components/Select/index.d.ts +1 -1
- package/dist/index.js +65 -65
- package/dist/index.js.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Select/Select.test.tsx +19 -0
- package/src/components/Select/Select.tsx +19 -17
- package/src/components/Select/Select.types.ts +13 -3
- package/src/components/Select/index.ts +4 -0
- package/src/testing/SelectEvent/SelectEvent.ts +42 -28
package/package.json
CHANGED
|
@@ -298,6 +298,25 @@ describe('Select', () => {
|
|
|
298
298
|
expect(await selectEvent.getSelectedOptions(searchInput)).toHaveLength(0)
|
|
299
299
|
expect(searchInput).toHaveDisplayValue('')
|
|
300
300
|
})
|
|
301
|
+
|
|
302
|
+
it('removes the clear button', async () => {
|
|
303
|
+
const selectedFruit = generator.pickone([...FRUITS])
|
|
304
|
+
|
|
305
|
+
setup({
|
|
306
|
+
value: selectedFruit as Option,
|
|
307
|
+
hideClear: true,
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
const searchInput = screen.getByLabelText('Select your favorite fruit')
|
|
311
|
+
expect(searchInput).toHaveDisplayValue(selectedFruit.label)
|
|
312
|
+
|
|
313
|
+
const selectedOptions = await selectEvent.getSelectedOptions(searchInput)
|
|
314
|
+
expect(selectedOptions).toHaveLength(1)
|
|
315
|
+
|
|
316
|
+
expect(selectedOptions[0]).toHaveTextContent(selectedFruit.label)
|
|
317
|
+
|
|
318
|
+
expect(screen.queryByTestId('select-trigger-clear')).not.toBeInTheDocument()
|
|
319
|
+
})
|
|
301
320
|
})
|
|
302
321
|
|
|
303
322
|
describe('Multi selection', () => {
|
|
@@ -207,7 +207,7 @@ function renderOptionsMultiple(select: useSelectReturn, components?: Components)
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
function Select(props: SelectProps): JSX.Element {
|
|
210
|
-
const { multiple, placeholder, components, ...others } = props
|
|
210
|
+
const { multiple, placeholder, components, hideClear = false, ...others } = props
|
|
211
211
|
|
|
212
212
|
const select = useSelect(props)
|
|
213
213
|
|
|
@@ -224,24 +224,26 @@ function Select(props: SelectProps): JSX.Element {
|
|
|
224
224
|
return <Loading data-testid="select-trigger-loading">···</Loading>
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
if (select.value) {
|
|
228
|
-
|
|
229
|
-
return <ClearMultiple select={select} />
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (!select.disabled) {
|
|
233
|
-
return (
|
|
234
|
-
<CloseButton
|
|
235
|
-
size={12}
|
|
236
|
-
{...getCommonClearButtonProps()}
|
|
237
|
-
{...select.getClearProps()}
|
|
238
|
-
type="button"
|
|
239
|
-
/>
|
|
240
|
-
)
|
|
241
|
-
}
|
|
227
|
+
if (!select.value) {
|
|
228
|
+
return null
|
|
242
229
|
}
|
|
243
230
|
|
|
244
|
-
|
|
231
|
+
if (multiple) {
|
|
232
|
+
return <ClearMultiple select={select} />
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (select.disabled || hideClear) {
|
|
236
|
+
return null
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<CloseButton
|
|
241
|
+
size={12}
|
|
242
|
+
{...getCommonClearButtonProps()}
|
|
243
|
+
{...select.getClearProps()}
|
|
244
|
+
type="button"
|
|
245
|
+
/>
|
|
246
|
+
)
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
return (
|
|
@@ -69,6 +69,12 @@ export type Components = {
|
|
|
69
69
|
|
|
70
70
|
export type CreateOptionPosition = 'first' | 'last'
|
|
71
71
|
|
|
72
|
+
export type OnChange = (event: EventLike<Option | Option[] | null>) => void
|
|
73
|
+
|
|
74
|
+
export type OnCreate = (query: string) => Promise<void | Option> | void | Option
|
|
75
|
+
|
|
76
|
+
export type OnQueryChange = (e: ChangeEvent<HTMLInputElement>) => void
|
|
77
|
+
|
|
72
78
|
export interface SelectProps extends DropdownProps {
|
|
73
79
|
name: string
|
|
74
80
|
placeholder?: string
|
|
@@ -78,11 +84,15 @@ export interface SelectProps extends DropdownProps {
|
|
|
78
84
|
datasources?: SelectDatasourceFunction<any>[]
|
|
79
85
|
options?: GenericOption[]
|
|
80
86
|
components?: Components
|
|
81
|
-
onChange?:
|
|
82
|
-
onCreate?:
|
|
83
|
-
onQueryChange?:
|
|
87
|
+
onChange?: OnChange
|
|
88
|
+
onCreate?: OnCreate
|
|
89
|
+
onQueryChange?: OnQueryChange
|
|
84
90
|
isValidNewOption?: ((query: string) => boolean) | boolean
|
|
85
91
|
createOptionPosition?: CreateOptionPosition
|
|
92
|
+
/**
|
|
93
|
+
* Hide the clear button on the Single Select.
|
|
94
|
+
*/
|
|
95
|
+
hideClear?: boolean
|
|
86
96
|
}
|
|
87
97
|
|
|
88
98
|
export type SelectOptionProps = {
|
|
@@ -4,5 +4,9 @@ export type {
|
|
|
4
4
|
useSelectExternalReturn as useSelectReturn,
|
|
5
5
|
SelectComponentsOptionProps as SelectOptionProps,
|
|
6
6
|
SelectComponentsEmptyProps as SelectEmptyProps,
|
|
7
|
+
Option as SelectOption,
|
|
8
|
+
OnChange as SelectOnChange,
|
|
9
|
+
OnCreate as SelectOnCreate,
|
|
10
|
+
OnQueryChange as SelectOnQueryChange,
|
|
7
11
|
} from './Select.types'
|
|
8
12
|
export { useSelectExternal as useSelect } from './useSelectExternal'
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import {
|
|
3
|
+
fireEvent,
|
|
4
|
+
queries,
|
|
5
|
+
waitFor,
|
|
6
|
+
within,
|
|
7
|
+
waitForElementToBeRemoved,
|
|
8
|
+
} from '@testing-library/dom'
|
|
2
9
|
import { act } from '@testing-library/react'
|
|
3
10
|
import userEvent from '@testing-library/user-event'
|
|
4
11
|
|
|
@@ -19,7 +26,6 @@ function getSelectMenu(input: HTMLElement): HTMLElement {
|
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
function getSelectTriggerHandle(input: HTMLElement): HTMLElement {
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
23
29
|
return input.parentNode!.nextSibling!.nextSibling as HTMLElement
|
|
24
30
|
}
|
|
25
31
|
|
|
@@ -54,12 +60,12 @@ function isSelectMenuExpanded(input: HTMLElement): boolean {
|
|
|
54
60
|
async function waitForPendingQuery(input: HTMLElement) {
|
|
55
61
|
const searchContainer = getSelectSearchContainer(input)
|
|
56
62
|
|
|
57
|
-
if (!
|
|
63
|
+
if (!queries.queryByTestId(searchContainer, 'select-trigger-loading')) {
|
|
58
64
|
return
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
await waitForElementToBeRemoved(
|
|
62
|
-
() =>
|
|
68
|
+
() => queries.queryByTestId(searchContainer, 'select-trigger-loading'),
|
|
63
69
|
{ timeout: 2500 }
|
|
64
70
|
)
|
|
65
71
|
}
|
|
@@ -82,10 +88,11 @@ async function expand(input: HTMLElement): Promise<void> {
|
|
|
82
88
|
expect(triggerHandle).toBeEnabled()
|
|
83
89
|
})
|
|
84
90
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
await act(async () => {
|
|
92
|
+
userEvent.click(triggerHandle)
|
|
93
|
+
await waitFor(() => {
|
|
94
|
+
expect(isSelectMenuExpanded(input)).toBe(true)
|
|
95
|
+
})
|
|
89
96
|
})
|
|
90
97
|
}
|
|
91
98
|
|
|
@@ -101,10 +108,12 @@ async function collapse(input: HTMLElement): Promise<void> {
|
|
|
101
108
|
|
|
102
109
|
const triggerHandle = getSelectTriggerHandle(input)
|
|
103
110
|
|
|
104
|
-
|
|
111
|
+
await act(async () => {
|
|
112
|
+
userEvent.click(triggerHandle)
|
|
105
113
|
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
await waitFor(() => {
|
|
115
|
+
expect(isSelectMenuExpanded(input)).toBe(false)
|
|
116
|
+
})
|
|
108
117
|
})
|
|
109
118
|
}
|
|
110
119
|
|
|
@@ -120,12 +129,14 @@ async function select(option: string, input: HTMLElement): Promise<void> {
|
|
|
120
129
|
|
|
121
130
|
const menuContainer = getSelectMenu(input)
|
|
122
131
|
|
|
123
|
-
|
|
132
|
+
await act(async () => {
|
|
133
|
+
const optionElement = await queries.findByLabelText(menuContainer, option)
|
|
124
134
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
// click the option if exists; Select currently closes when an item is clicked.
|
|
136
|
+
if (optionElement && optionElement.getAttribute('aria-selected') == 'false') {
|
|
137
|
+
userEvent.click(optionElement)
|
|
138
|
+
}
|
|
139
|
+
})
|
|
129
140
|
|
|
130
141
|
// we collapse in the case the option was not clicked
|
|
131
142
|
await collapse(input)
|
|
@@ -143,12 +154,14 @@ async function unselect(option: string, input: HTMLElement): Promise<void> {
|
|
|
143
154
|
|
|
144
155
|
const menuContainer = getSelectMenu(input)
|
|
145
156
|
|
|
146
|
-
|
|
157
|
+
await act(async () => {
|
|
158
|
+
const optionElement = await queries.findByLabelText(menuContainer, option)
|
|
147
159
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
160
|
+
// ensures that the option exists and IS selected
|
|
161
|
+
if (optionElement && optionElement.getAttribute('aria-selected') == 'true') {
|
|
162
|
+
userEvent.click(optionElement)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
152
165
|
|
|
153
166
|
// we collapse in the case the option was not clicked
|
|
154
167
|
await collapse(input)
|
|
@@ -164,9 +177,9 @@ async function clear(input: HTMLElement): Promise<void> {
|
|
|
164
177
|
|
|
165
178
|
const searchContainer = getSelectSearchContainer(input)
|
|
166
179
|
|
|
167
|
-
|
|
180
|
+
await act(async () => {
|
|
181
|
+
const clearButton = within(searchContainer).getByTestId('select-trigger-clear')
|
|
168
182
|
|
|
169
|
-
act(() => {
|
|
170
183
|
if (clearButton) {
|
|
171
184
|
userEvent.click(clearButton)
|
|
172
185
|
}
|
|
@@ -182,9 +195,11 @@ async function clear(input: HTMLElement): Promise<void> {
|
|
|
182
195
|
async function search(query: string, input: HTMLElement): Promise<void> {
|
|
183
196
|
const selectContainer = getSelectContainer(input)
|
|
184
197
|
|
|
185
|
-
|
|
198
|
+
await act(async () => {
|
|
199
|
+
fireEvent.change(input, { target: { value: query } })
|
|
186
200
|
|
|
187
|
-
|
|
201
|
+
await queries.findAllByRole(selectContainer, 'option')
|
|
202
|
+
})
|
|
188
203
|
}
|
|
189
204
|
|
|
190
205
|
/**
|
|
@@ -197,8 +212,7 @@ async function getOptions(input: HTMLElement): Promise<HTMLElement[]> {
|
|
|
197
212
|
|
|
198
213
|
const menuContainer = getSelectMenu(input)
|
|
199
214
|
|
|
200
|
-
const options =
|
|
201
|
-
|
|
215
|
+
const options = queries.queryAllByRole(menuContainer, 'option')
|
|
202
216
|
await collapse(input)
|
|
203
217
|
|
|
204
218
|
return options
|
|
@@ -216,7 +230,7 @@ async function getSelectedOptions(input: HTMLElement): Promise<HTMLElement[]> {
|
|
|
216
230
|
let selectedOptions: HTMLElement[] = []
|
|
217
231
|
|
|
218
232
|
try {
|
|
219
|
-
selectedOptions = await
|
|
233
|
+
selectedOptions = await queries.findAllByRole(menuContainer, 'option', {
|
|
220
234
|
selected: true,
|
|
221
235
|
})
|
|
222
236
|
} catch (err) {
|