@instructure/ui-select 8.13.1-snapshot.25 → 8.13.1-snapshot.35
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/es/Select/Group/index.js +2 -3
- package/es/Select/Group/props.js +0 -7
- package/es/Select/Option/index.js +2 -2
- package/es/Select/Option/props.js +0 -27
- package/es/Select/SelectLocator.js +5 -2
- package/es/Select/index.js +92 -85
- package/es/Select/props.js +2 -142
- package/lib/Select/Group/index.js +2 -3
- package/lib/Select/Group/props.js +0 -7
- package/lib/Select/Option/index.js +2 -2
- package/lib/Select/Option/props.js +0 -27
- package/lib/Select/SelectLocator.js +3 -0
- package/lib/Select/index.js +96 -86
- package/lib/Select/props.js +2 -142
- package/package.json +23 -23
- package/src/Select/Group/index.tsx +2 -3
- package/src/Select/Group/props.ts +8 -8
- package/src/Select/Option/index.tsx +2 -2
- package/src/Select/Option/props.ts +33 -25
- package/src/Select/index.tsx +160 -168
- package/src/Select/props.ts +176 -117
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Select/Group/index.d.ts +4 -5
- package/types/Select/Group/index.d.ts.map +1 -1
- package/types/Select/Group/props.d.ts +7 -1
- package/types/Select/Group/props.d.ts.map +1 -1
- package/types/Select/Option/index.d.ts +3 -7
- package/types/Select/Option/index.d.ts.map +1 -1
- package/types/Select/Option/props.d.ts +28 -4
- package/types/Select/Option/props.d.ts.map +1 -1
- package/types/Select/index.d.ts +68 -99
- package/types/Select/index.d.ts.map +1 -1
- package/types/Select/props.d.ts +146 -21
- package/types/Select/props.d.ts.map +1 -1
package/src/Select/index.tsx
CHANGED
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
/** @jsx jsx */
|
|
26
|
-
import { Children, Component } from 'react'
|
|
26
|
+
import React, { Children, Component } from 'react'
|
|
27
27
|
|
|
28
28
|
import { createChainedFunction } from '@instructure/ui-utils'
|
|
29
29
|
import { testable } from '@instructure/ui-testable'
|
|
30
|
+
import { uid } from '@instructure/uid'
|
|
30
31
|
import {
|
|
31
32
|
matchComponentTypes,
|
|
32
33
|
omitProps,
|
|
@@ -46,7 +47,17 @@ import {
|
|
|
46
47
|
IconArrowOpenDownLine,
|
|
47
48
|
IconArrowOpenUpLine
|
|
48
49
|
} from '@instructure/ui-icons'
|
|
49
|
-
|
|
50
|
+
|
|
51
|
+
import type { ViewProps } from '@instructure/ui-view'
|
|
52
|
+
import type { TextInputProps } from '@instructure/ui-text-input'
|
|
53
|
+
import type {
|
|
54
|
+
OptionsItemProps,
|
|
55
|
+
OptionsSeparatorProps
|
|
56
|
+
} from '@instructure/ui-options'
|
|
57
|
+
import type {
|
|
58
|
+
SelectableProps,
|
|
59
|
+
SelectableRender
|
|
60
|
+
} from '@instructure/ui-selectable'
|
|
50
61
|
|
|
51
62
|
import { withStyle, jsx } from '@instructure/emotion'
|
|
52
63
|
|
|
@@ -55,6 +66,9 @@ import generateComponentTheme from './theme'
|
|
|
55
66
|
|
|
56
67
|
import { Group } from './Group'
|
|
57
68
|
import { Option } from './Option'
|
|
69
|
+
|
|
70
|
+
import type { RenderSelectOptionLabel } from './Option/props'
|
|
71
|
+
|
|
58
72
|
import type { SelectProps } from './props'
|
|
59
73
|
import { allowedProps, propTypes } from './props'
|
|
60
74
|
|
|
@@ -63,6 +77,7 @@ import { allowedProps, propTypes } from './props'
|
|
|
63
77
|
category: components
|
|
64
78
|
tags: autocomplete, typeahead, combobox, dropdown, search, form
|
|
65
79
|
---
|
|
80
|
+
@tsProps
|
|
66
81
|
**/
|
|
67
82
|
@withStyle(generateStyle, generateComponentTheme)
|
|
68
83
|
@testable()
|
|
@@ -76,7 +91,6 @@ class Select extends Component<SelectProps> {
|
|
|
76
91
|
inputValue: '',
|
|
77
92
|
isShowingOptions: false,
|
|
78
93
|
size: 'medium',
|
|
79
|
-
placeholder: null,
|
|
80
94
|
// Leave interaction default undefined so that `disabled` and `readOnly` can also be supplied
|
|
81
95
|
interaction: undefined,
|
|
82
96
|
isRequired: false,
|
|
@@ -84,33 +98,12 @@ class Select extends Component<SelectProps> {
|
|
|
84
98
|
visibleOptionsCount: 8,
|
|
85
99
|
placement: 'bottom stretch',
|
|
86
100
|
constrain: 'window',
|
|
87
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
|
|
88
|
-
onFocus: (event) => {},
|
|
89
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
|
|
90
|
-
onBlur: (event) => {},
|
|
91
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
|
|
92
|
-
onRequestShowOptions: (event) => {},
|
|
93
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
|
|
94
|
-
onRequestHideOptions: (event) => {},
|
|
95
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
|
|
96
|
-
onRequestHighlightOption: (event, data) => {},
|
|
97
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'event' is declared but its value is never read.
|
|
98
|
-
onRequestSelectOption: (event, data) => {},
|
|
99
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'node' is declared but its value is never read.
|
|
100
|
-
inputRef: (node) => {},
|
|
101
|
-
// @ts-expect-error ts-migrate(6133) FIXME: 'node' is declared but its value is never read.
|
|
102
|
-
listRef: (node) => {},
|
|
103
|
-
renderBeforeInput: null,
|
|
104
|
-
renderAfterInput: null,
|
|
105
|
-
children: null,
|
|
106
101
|
shouldNotWrap: false
|
|
107
102
|
}
|
|
108
103
|
|
|
109
104
|
static Option = Option
|
|
110
105
|
static Group = Group
|
|
111
106
|
|
|
112
|
-
ref: Element | null = null
|
|
113
|
-
|
|
114
107
|
componentDidMount() {
|
|
115
108
|
this.props.makeStyles?.()
|
|
116
109
|
}
|
|
@@ -126,19 +119,20 @@ class Select extends Component<SelectProps> {
|
|
|
126
119
|
hasInputRef: false
|
|
127
120
|
}
|
|
128
121
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
ref: HTMLInputElement | null = null
|
|
123
|
+
|
|
124
|
+
private _defaultId = uid('Select')
|
|
125
|
+
private _inputContainer: HTMLSpanElement | null = null
|
|
126
|
+
private _listView: Element | null = null
|
|
133
127
|
// temporarily stores actionable options
|
|
134
|
-
_optionIds = []
|
|
128
|
+
private _optionIds: string[] = []
|
|
135
129
|
// best guess for first calculation of list height
|
|
136
|
-
_optionHeight = 36
|
|
130
|
+
private _optionHeight = 36
|
|
137
131
|
|
|
138
132
|
focus() {
|
|
139
|
-
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
|
140
133
|
this.ref && this.ref.focus()
|
|
141
134
|
}
|
|
135
|
+
|
|
142
136
|
get _input() {
|
|
143
137
|
console.warn(
|
|
144
138
|
'_input property is deprecated and will be removed in v9, please use ref instead'
|
|
@@ -156,34 +150,31 @@ class Select extends Component<SelectProps> {
|
|
|
156
150
|
}
|
|
157
151
|
|
|
158
152
|
get width() {
|
|
159
|
-
|
|
160
|
-
return this._inputContainer && this._inputContainer.offsetWidth
|
|
153
|
+
return this._inputContainer ? this._inputContainer.offsetWidth : undefined
|
|
161
154
|
}
|
|
162
155
|
|
|
163
156
|
get interaction() {
|
|
164
157
|
return getInteraction({ props: this.props })
|
|
165
158
|
}
|
|
166
159
|
|
|
167
|
-
get highlightedOptionId() {
|
|
168
|
-
let highlightedOptionId
|
|
160
|
+
get highlightedOptionId(): string | undefined {
|
|
161
|
+
let highlightedOptionId: string | undefined
|
|
162
|
+
|
|
169
163
|
Children.toArray(this.props.children).forEach((child) => {
|
|
170
164
|
if (matchComponentTypes(child, [Group])) {
|
|
171
165
|
// group found
|
|
172
|
-
|
|
173
|
-
|
|
166
|
+
;(
|
|
167
|
+
Children.toArray((child as Group).props.children) as Option[]
|
|
168
|
+
).forEach((option) => {
|
|
174
169
|
// check options in group
|
|
175
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'string | ... Remove this comment to see the full error message
|
|
176
170
|
if (option.props.isHighlighted) {
|
|
177
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'string | ... Remove this comment to see the full error message
|
|
178
171
|
highlightedOptionId = option.props.id
|
|
179
172
|
}
|
|
180
173
|
})
|
|
181
174
|
} else {
|
|
182
175
|
// ungrouped option found
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'string | ... Remove this comment to see the full error message
|
|
186
|
-
highlightedOptionId = child.props.id
|
|
176
|
+
if ((child as Option).props.isHighlighted) {
|
|
177
|
+
highlightedOptionId = (child as Option).props.id
|
|
187
178
|
}
|
|
188
179
|
}
|
|
189
180
|
})
|
|
@@ -192,102 +183,89 @@ class Select extends Component<SelectProps> {
|
|
|
192
183
|
}
|
|
193
184
|
|
|
194
185
|
get selectedOptionId() {
|
|
195
|
-
|
|
196
|
-
|
|
186
|
+
const selectedOptionId: string[] = []
|
|
187
|
+
|
|
197
188
|
Children.toArray(this.props.children).forEach((child) => {
|
|
198
189
|
if (matchComponentTypes(child, [Group])) {
|
|
199
190
|
// group found
|
|
200
|
-
|
|
201
|
-
|
|
191
|
+
;(
|
|
192
|
+
Children.toArray((child as Group).props.children) as Option[]
|
|
193
|
+
).forEach((option) => {
|
|
202
194
|
// check options in group
|
|
203
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'string | ... Remove this comment to see the full error message
|
|
204
195
|
if (option.props.isSelected) {
|
|
205
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'string | ... Remove this comment to see the full error message
|
|
206
196
|
selectedOptionId.push(option.props.id)
|
|
207
197
|
}
|
|
208
198
|
})
|
|
209
199
|
} else {
|
|
210
200
|
// ungrouped option found
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'props' does not exist on type 'string | ... Remove this comment to see the full error message
|
|
214
|
-
selectedOptionId.push(child.props.id)
|
|
201
|
+
if ((child as Option).props.isSelected) {
|
|
202
|
+
selectedOptionId.push((child as Option).props.id)
|
|
215
203
|
}
|
|
216
204
|
}
|
|
217
205
|
})
|
|
218
206
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
207
|
+
if (selectedOptionId.length === 1) {
|
|
208
|
+
return selectedOptionId[0]
|
|
209
|
+
}
|
|
210
|
+
if (selectedOptionId.length === 0) {
|
|
211
|
+
return undefined
|
|
212
|
+
}
|
|
223
213
|
return selectedOptionId
|
|
224
214
|
}
|
|
225
215
|
|
|
226
|
-
|
|
227
|
-
handleInputRef = (node) => {
|
|
216
|
+
handleInputRef = (node: HTMLInputElement | null) => {
|
|
228
217
|
// ensures list is positioned with respect to input if list is open on mount
|
|
229
218
|
if (!this.state.hasInputRef) {
|
|
230
219
|
this.setState({ hasInputRef: true })
|
|
231
220
|
}
|
|
232
221
|
|
|
233
222
|
this.ref = node
|
|
234
|
-
|
|
235
|
-
this.props.inputRef(node)
|
|
223
|
+
this.props.inputRef?.(node)
|
|
236
224
|
}
|
|
237
225
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this._list = node
|
|
241
|
-
// @ts-expect-error ts-migrate(2722) FIXME: Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
|
242
|
-
this.props.listRef(node)
|
|
226
|
+
handleListRef = (node: HTMLUListElement | null) => {
|
|
227
|
+
this.props.listRef?.(node)
|
|
243
228
|
|
|
244
229
|
// store option height to calculate list maxHeight
|
|
245
230
|
if (node && node.querySelector('[role="option"]')) {
|
|
246
|
-
this._optionHeight =
|
|
231
|
+
this._optionHeight = (
|
|
232
|
+
node.querySelector('[role="option"]') as HTMLElement
|
|
233
|
+
).offsetHeight
|
|
247
234
|
}
|
|
248
235
|
}
|
|
249
236
|
|
|
250
|
-
|
|
251
|
-
handleInputContainerRef = (node) => {
|
|
237
|
+
handleInputContainerRef = (node: HTMLSpanElement | null) => {
|
|
252
238
|
this._inputContainer = node
|
|
253
239
|
}
|
|
254
240
|
|
|
255
|
-
|
|
256
|
-
scrollToOption(id) {
|
|
257
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_listView' does not exist on type 'Selec... Remove this comment to see the full error message
|
|
241
|
+
scrollToOption(id?: string) {
|
|
258
242
|
if (this._listView) {
|
|
259
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_listView' does not exist on type 'Selec... Remove this comment to see the full error message
|
|
260
243
|
const option = this._listView.querySelector(`[id="${id}"]`)
|
|
261
244
|
if (!option) return
|
|
262
245
|
|
|
263
246
|
const listItem = option.parentNode
|
|
264
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_listView' does not exist on type 'Selec... Remove this comment to see the full error message
|
|
265
247
|
const parentTop = getBoundingClientRect(this._listView).top
|
|
266
248
|
const elemTop = getBoundingClientRect(listItem).top
|
|
267
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_listView' does not exist on type 'Selec... Remove this comment to see the full error message
|
|
268
249
|
const parentBottom = parentTop + this._listView.clientHeight
|
|
269
|
-
const elemBottom =
|
|
250
|
+
const elemBottom =
|
|
251
|
+
elemTop + (listItem ? (listItem as Element).clientHeight : 0)
|
|
270
252
|
|
|
271
253
|
if (elemBottom > parentBottom) {
|
|
272
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_listView' does not exist on type 'Selec... Remove this comment to see the full error message
|
|
273
254
|
this._listView.scrollTop += elemBottom - parentBottom
|
|
274
255
|
} else if (elemTop < parentTop) {
|
|
275
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property '_listView' does not exist on type 'Selec... Remove this comment to see the full error message
|
|
276
256
|
this._listView.scrollTop -= parentTop - elemTop
|
|
277
257
|
}
|
|
278
258
|
}
|
|
279
259
|
}
|
|
280
260
|
|
|
281
|
-
|
|
282
|
-
highlightOption(event, id) {
|
|
261
|
+
highlightOption(event: React.SyntheticEvent, id: string) {
|
|
283
262
|
const { onRequestHighlightOption } = this.props
|
|
284
263
|
if (id) {
|
|
285
|
-
|
|
286
|
-
onRequestHighlightOption(event, { id })
|
|
264
|
+
onRequestHighlightOption?.(event, { id })
|
|
287
265
|
}
|
|
288
266
|
}
|
|
289
267
|
|
|
290
|
-
getEventHandlers() {
|
|
268
|
+
getEventHandlers(): Partial<SelectableProps> {
|
|
291
269
|
const {
|
|
292
270
|
isShowingOptions,
|
|
293
271
|
onRequestShowOptions,
|
|
@@ -300,28 +278,23 @@ class Select extends Component<SelectProps> {
|
|
|
300
278
|
|
|
301
279
|
return this.interaction === 'enabled'
|
|
302
280
|
? {
|
|
303
|
-
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
|
|
304
281
|
onRequestShowOptions: (event) => {
|
|
305
|
-
|
|
306
|
-
onRequestShowOptions(event)
|
|
282
|
+
onRequestShowOptions?.(event)
|
|
307
283
|
if (selectedOptionId && !Array.isArray(selectedOptionId)) {
|
|
308
284
|
// highlight selected option on show
|
|
309
285
|
this.highlightOption(event, selectedOptionId)
|
|
310
286
|
}
|
|
311
287
|
},
|
|
312
|
-
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
|
|
313
288
|
onRequestHideOptions: (event) => {
|
|
314
|
-
|
|
315
|
-
onRequestHideOptions(event)
|
|
289
|
+
onRequestHideOptions?.(event)
|
|
316
290
|
},
|
|
317
291
|
onRequestHighlightOption: (
|
|
318
|
-
event
|
|
292
|
+
event,
|
|
319
293
|
{ id, direction }: { id?: string; direction?: number }
|
|
320
294
|
) => {
|
|
321
295
|
if (!isShowingOptions) return
|
|
322
296
|
// if id exists, use that
|
|
323
|
-
|
|
324
|
-
let highlightId = this._optionIds.indexOf(id) > -1 ? id : null
|
|
297
|
+
let highlightId = this._optionIds.indexOf(id!) > -1 ? id : undefined
|
|
325
298
|
if (!highlightId) {
|
|
326
299
|
if (!highlightedOptionId) {
|
|
327
300
|
// nothing highlighted yet, highlight first option
|
|
@@ -330,7 +303,7 @@ class Select extends Component<SelectProps> {
|
|
|
330
303
|
// find next id based on direction
|
|
331
304
|
const index = this._optionIds.indexOf(highlightedOptionId)
|
|
332
305
|
highlightId =
|
|
333
|
-
index > -1 ? this._optionIds[index + direction!] :
|
|
306
|
+
index > -1 ? this._optionIds[index + direction!] : undefined
|
|
334
307
|
}
|
|
335
308
|
}
|
|
336
309
|
if (highlightId) {
|
|
@@ -338,31 +311,29 @@ class Select extends Component<SelectProps> {
|
|
|
338
311
|
this.highlightOption(event, highlightId)
|
|
339
312
|
}
|
|
340
313
|
},
|
|
341
|
-
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
|
|
342
314
|
onRequestHighlightFirstOption: (event) => {
|
|
343
315
|
this.highlightOption(event, this._optionIds[0])
|
|
344
316
|
},
|
|
345
|
-
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
|
|
346
317
|
onRequestHighlightLastOption: (event) => {
|
|
347
318
|
this.highlightOption(
|
|
348
319
|
event,
|
|
349
320
|
this._optionIds[this._optionIds.length - 1]
|
|
350
321
|
)
|
|
351
322
|
},
|
|
352
|
-
onRequestSelectOption: (event
|
|
353
|
-
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
|
|
323
|
+
onRequestSelectOption: (event, { id }) => {
|
|
354
324
|
if (id && this._optionIds.indexOf(id) !== -1) {
|
|
355
325
|
// only select if id exists as a valid option
|
|
356
|
-
|
|
357
|
-
onRequestSelectOption(event, { id })
|
|
326
|
+
onRequestSelectOption?.(event, { id })
|
|
358
327
|
}
|
|
359
328
|
}
|
|
360
329
|
}
|
|
361
330
|
: {}
|
|
362
331
|
}
|
|
363
332
|
|
|
364
|
-
|
|
365
|
-
|
|
333
|
+
renderOption(
|
|
334
|
+
option: Option,
|
|
335
|
+
data: Pick<SelectableRender, 'getOptionProps' | 'getDisabledOptionProps'>
|
|
336
|
+
) {
|
|
366
337
|
const { getOptionProps, getDisabledOptionProps } = data
|
|
367
338
|
const {
|
|
368
339
|
id,
|
|
@@ -374,19 +345,21 @@ class Select extends Component<SelectProps> {
|
|
|
374
345
|
children
|
|
375
346
|
} = option.props
|
|
376
347
|
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
348
|
+
const getRenderOptionLabel = (
|
|
349
|
+
renderOptionLabel: RenderSelectOptionLabel
|
|
350
|
+
): React.ReactNode => {
|
|
351
|
+
return typeof renderOptionLabel === 'function'
|
|
352
|
+
? renderOptionLabel.bind(null, {
|
|
380
353
|
id,
|
|
381
354
|
isDisabled,
|
|
382
355
|
isSelected,
|
|
383
356
|
isHighlighted,
|
|
384
357
|
children
|
|
385
358
|
})
|
|
386
|
-
:
|
|
359
|
+
: renderOptionLabel
|
|
387
360
|
}
|
|
388
361
|
|
|
389
|
-
let optionProps = {
|
|
362
|
+
let optionProps: Partial<OptionsItemProps> = {
|
|
390
363
|
// passthrough props
|
|
391
364
|
...omitProps(option.props, [
|
|
392
365
|
...Option.allowedProps,
|
|
@@ -395,8 +368,8 @@ class Select extends Component<SelectProps> {
|
|
|
395
368
|
// props from selectable
|
|
396
369
|
...getOptionProps({ id }),
|
|
397
370
|
// Options.Item props
|
|
398
|
-
renderBeforeLabel:
|
|
399
|
-
renderAfterLabel:
|
|
371
|
+
renderBeforeLabel: getRenderOptionLabel(renderBeforeLabel),
|
|
372
|
+
renderAfterLabel: getRenderOptionLabel(renderAfterLabel)
|
|
400
373
|
}
|
|
401
374
|
// should option be treated as highlighted or selected
|
|
402
375
|
if (isSelected) {
|
|
@@ -410,15 +383,23 @@ class Select extends Component<SelectProps> {
|
|
|
410
383
|
optionProps = { ...optionProps, ...getDisabledOptionProps() }
|
|
411
384
|
} else {
|
|
412
385
|
// track as valid option if not disabled
|
|
413
|
-
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
|
|
414
386
|
this._optionIds.push(id)
|
|
415
387
|
}
|
|
416
388
|
|
|
417
389
|
return <Options.Item {...optionProps}>{children}</Options.Item>
|
|
418
390
|
}
|
|
419
391
|
|
|
420
|
-
|
|
421
|
-
|
|
392
|
+
renderGroup(
|
|
393
|
+
group: Group,
|
|
394
|
+
data: Pick<
|
|
395
|
+
SelectableRender,
|
|
396
|
+
'getOptionProps' | 'getDisabledOptionProps'
|
|
397
|
+
> & {
|
|
398
|
+
isFirstChild: boolean
|
|
399
|
+
isLastChild: boolean
|
|
400
|
+
afterGroup: boolean
|
|
401
|
+
}
|
|
402
|
+
) {
|
|
422
403
|
const {
|
|
423
404
|
getOptionProps,
|
|
424
405
|
getDisabledOptionProps,
|
|
@@ -427,7 +408,10 @@ class Select extends Component<SelectProps> {
|
|
|
427
408
|
afterGroup
|
|
428
409
|
} = data
|
|
429
410
|
const { id, renderLabel, children, ...rest } = group.props
|
|
430
|
-
const groupChildren
|
|
411
|
+
const groupChildren: (
|
|
412
|
+
| React.ReactElement<OptionsItemProps>
|
|
413
|
+
| React.ReactElement<OptionsSeparatorProps>
|
|
414
|
+
)[] = []
|
|
431
415
|
// add a separator above
|
|
432
416
|
if (!isFirstChild && !afterGroup) {
|
|
433
417
|
groupChildren.push(<Options.Separator />)
|
|
@@ -442,7 +426,7 @@ class Select extends Component<SelectProps> {
|
|
|
442
426
|
renderLabel={renderLabel}
|
|
443
427
|
{...omitProps(rest, [...Options.allowedProps, ...Group.allowedProps])}
|
|
444
428
|
>
|
|
445
|
-
{Children.map(children, (child) => {
|
|
429
|
+
{Children.map(children as Option[], (child) => {
|
|
446
430
|
return this.renderOption(child, {
|
|
447
431
|
getOptionProps,
|
|
448
432
|
getDisabledOptionProps
|
|
@@ -458,53 +442,50 @@ class Select extends Component<SelectProps> {
|
|
|
458
442
|
return groupChildren
|
|
459
443
|
}
|
|
460
444
|
|
|
461
|
-
|
|
462
|
-
|
|
445
|
+
renderList(
|
|
446
|
+
data: Pick<
|
|
447
|
+
SelectableRender,
|
|
448
|
+
'getListProps' | 'getOptionProps' | 'getDisabledOptionProps'
|
|
449
|
+
>
|
|
450
|
+
) {
|
|
463
451
|
const { getListProps, getOptionProps, getDisabledOptionProps } = data
|
|
464
|
-
const {
|
|
465
|
-
|
|
466
|
-
optionsMaxWidth,
|
|
467
|
-
visibleOptionsCount,
|
|
468
|
-
children
|
|
469
|
-
} = this.props
|
|
452
|
+
const { isShowingOptions, optionsMaxWidth, visibleOptionsCount, children } =
|
|
453
|
+
this.props
|
|
470
454
|
|
|
471
455
|
let lastWasGroup = false
|
|
472
|
-
|
|
456
|
+
|
|
457
|
+
const viewProps: Partial<ViewProps> = isShowingOptions
|
|
473
458
|
? {
|
|
474
459
|
display: 'block',
|
|
475
460
|
overflowY: 'auto',
|
|
476
|
-
|
|
477
|
-
maxHeight: this._optionHeight * visibleOptionsCount,
|
|
461
|
+
maxHeight: this._optionHeight * visibleOptionsCount!,
|
|
478
462
|
maxWidth: optionsMaxWidth || this.width,
|
|
479
463
|
background: 'primary',
|
|
480
|
-
|
|
481
|
-
elementRef: (node) => (this._listView = node)
|
|
464
|
+
elementRef: (node: Element | null) => (this._listView = node)
|
|
482
465
|
}
|
|
483
466
|
: { maxHeight: 0 }
|
|
484
467
|
|
|
485
468
|
return (
|
|
486
|
-
//@ts-expect-error TODO: fix this
|
|
487
469
|
<View {...viewProps}>
|
|
488
470
|
<Options
|
|
489
471
|
{...getListProps({ as: 'ul', elementRef: this.handleListRef })}
|
|
490
472
|
>
|
|
491
473
|
{isShowingOptions
|
|
492
|
-
?
|
|
493
|
-
Children.map(children, (child, index) => {
|
|
474
|
+
? Children.map(children, (child, index) => {
|
|
494
475
|
if (!child || !matchComponentTypes(child, [Group, Option])) {
|
|
495
476
|
return // ignore invalid children
|
|
496
477
|
}
|
|
497
478
|
if (matchComponentTypes(child, [Option])) {
|
|
498
479
|
lastWasGroup = false
|
|
499
|
-
return this.renderOption(child, {
|
|
480
|
+
return this.renderOption(child as Option, {
|
|
500
481
|
getOptionProps,
|
|
501
482
|
getDisabledOptionProps
|
|
502
483
|
})
|
|
503
484
|
}
|
|
504
485
|
if (matchComponentTypes(child, [Group])) {
|
|
505
|
-
const afterGroup = lastWasGroup
|
|
486
|
+
const afterGroup = lastWasGroup
|
|
506
487
|
lastWasGroup = true
|
|
507
|
-
return this.renderGroup(child, {
|
|
488
|
+
return this.renderGroup(child as Group, {
|
|
508
489
|
getOptionProps,
|
|
509
490
|
getDisabledOptionProps,
|
|
510
491
|
// for rendering separators appropriately
|
|
@@ -513,6 +494,7 @@ class Select extends Component<SelectProps> {
|
|
|
513
494
|
afterGroup
|
|
514
495
|
})
|
|
515
496
|
}
|
|
497
|
+
return
|
|
516
498
|
})
|
|
517
499
|
: null}
|
|
518
500
|
</Options>
|
|
@@ -533,8 +515,9 @@ class Select extends Component<SelectProps> {
|
|
|
533
515
|
)
|
|
534
516
|
}
|
|
535
517
|
|
|
536
|
-
|
|
537
|
-
|
|
518
|
+
renderInput(
|
|
519
|
+
data: Pick<SelectableRender, 'getInputProps' | 'getTriggerProps'>
|
|
520
|
+
) {
|
|
538
521
|
const { getInputProps, getTriggerProps } = data
|
|
539
522
|
const {
|
|
540
523
|
renderLabel,
|
|
@@ -560,51 +543,60 @@ class Select extends Component<SelectProps> {
|
|
|
560
543
|
const passthroughProps = omitProps(rest, Select.allowedProps)
|
|
561
544
|
const { ref, ...triggerProps } = getTriggerProps({ ...passthroughProps })
|
|
562
545
|
const isEditable = typeof onInputChange !== 'undefined'
|
|
546
|
+
|
|
563
547
|
// props to ensure screen readers treat uneditable selects as accessible
|
|
564
548
|
// popup buttons rather than comboboxes.
|
|
565
|
-
const overrideProps = !isEditable
|
|
549
|
+
const overrideProps: Partial<TextInputProps> = !isEditable
|
|
566
550
|
? {
|
|
567
551
|
role: 'button',
|
|
568
552
|
title: inputValue,
|
|
569
|
-
'aria-autocomplete':
|
|
553
|
+
'aria-autocomplete': undefined
|
|
570
554
|
}
|
|
571
555
|
: {}
|
|
556
|
+
|
|
572
557
|
// backdoor to autocomplete attr to work around chrome autofill issues
|
|
573
558
|
if (passthroughProps['autoComplete']) {
|
|
574
|
-
// @ts-expect-error ts-migrate(2339) FIXME: Property 'autoComplete' does not exist on type '{ ... Remove this comment to see the full error message
|
|
575
559
|
overrideProps.autoComplete = passthroughProps['autoComplete']
|
|
576
560
|
}
|
|
577
561
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
interaction
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
562
|
+
const inputProps: Partial<TextInputProps> = {
|
|
563
|
+
id: this.id,
|
|
564
|
+
renderLabel,
|
|
565
|
+
placeholder,
|
|
566
|
+
size,
|
|
567
|
+
width,
|
|
568
|
+
htmlSize,
|
|
569
|
+
messages,
|
|
570
|
+
value: inputValue,
|
|
571
|
+
inputRef: createChainedFunction(ref, this.handleInputRef),
|
|
572
|
+
inputContainerRef: this.handleInputContainerRef,
|
|
573
|
+
interaction:
|
|
574
|
+
interaction === 'enabled' && !isEditable
|
|
575
|
+
? 'readonly' // prevent keyboard cursor
|
|
576
|
+
: interaction,
|
|
577
|
+
isRequired,
|
|
578
|
+
shouldNotWrap,
|
|
579
|
+
display: isInline ? 'inline-block' : 'block',
|
|
580
|
+
renderBeforeInput,
|
|
581
|
+
renderAfterInput: renderAfterInput || this.renderIcon(),
|
|
582
|
+
|
|
583
|
+
// If `inputValue` is provided, we need to pass a default onChange handler,
|
|
584
|
+
// because TextInput `value` is a controlled prop,
|
|
585
|
+
// and onChange is not required for Select
|
|
586
|
+
// (before it was handled by TextInput's defaultProp)
|
|
587
|
+
onChange:
|
|
588
|
+
typeof onInputChange === 'function'
|
|
589
|
+
? onInputChange
|
|
590
|
+
: inputValue
|
|
591
|
+
? () => {}
|
|
592
|
+
: undefined,
|
|
593
|
+
|
|
594
|
+
onFocus,
|
|
595
|
+
onBlur: createChainedFunction(onBlur, onRequestHideOptions),
|
|
596
|
+
...overrideProps
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return <TextInput {...triggerProps} {...getInputProps(inputProps)} />
|
|
608
600
|
}
|
|
609
601
|
|
|
610
602
|
render() {
|
|
@@ -626,7 +618,7 @@ class Select extends Component<SelectProps> {
|
|
|
626
618
|
<Selectable
|
|
627
619
|
highlightedOptionId={highlightedOptionId}
|
|
628
620
|
isShowingOptions={isShowingOptions}
|
|
629
|
-
selectedOptionId={selectedOptionId
|
|
621
|
+
selectedOptionId={selectedOptionId}
|
|
630
622
|
{...this.getEventHandlers()}
|
|
631
623
|
>
|
|
632
624
|
{({
|