@intility/bifrost-react-select 4.0.0-alpha.3
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/.swcrc +16 -0
- package/CHANGELOG.md +12 -0
- package/dist/Select.d.ts +85 -0
- package/dist/Select.js +246 -0
- package/dist/Select.test.d.ts +1 -0
- package/dist/assets/bfSpinner.d.ts +10 -0
- package/dist/assets/bfSpinner.js +22 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/overrides/ClearIndicator.internal.d.ts +2 -0
- package/dist/overrides/ClearIndicator.internal.js +13 -0
- package/dist/overrides/CustomInput.internal.d.ts +2 -0
- package/dist/overrides/CustomInput.internal.js +32 -0
- package/dist/overrides/CustomMenuList.internal.d.ts +2 -0
- package/dist/overrides/CustomMenuList.internal.js +11 -0
- package/dist/overrides/CustomOption.internal.d.ts +2 -0
- package/dist/overrides/CustomOption.internal.js +29 -0
- package/dist/overrides/DropdownIndicator.internal.d.ts +2 -0
- package/dist/overrides/DropdownIndicator.internal.js +13 -0
- package/dist/overrides/LoadingIndicator.internal.d.ts +1 -0
- package/dist/overrides/LoadingIndicator.internal.js +11 -0
- package/dist/overrides/index.d.ts +6 -0
- package/dist/overrides/index.js +6 -0
- package/package.json +47 -0
- package/src/Select.md +410 -0
- package/src/Select.test.tsx +118 -0
- package/src/Select.tsx +436 -0
- package/src/assets/bfSpinner.ts +37 -0
- package/src/index.ts +8 -0
- package/src/overrides/ClearIndicator.internal.tsx +13 -0
- package/src/overrides/CustomInput.internal.tsx +32 -0
- package/src/overrides/CustomMenuList.internal.tsx +15 -0
- package/src/overrides/CustomOption.internal.tsx +29 -0
- package/src/overrides/DropdownIndicator.internal.tsx +13 -0
- package/src/overrides/LoadingIndicator.internal.tsx +9 -0
- package/src/overrides/index.ts +6 -0
- package/tsconfig.json +16 -0
- package/vitest.config.ts +12 -0
package/src/Select.tsx
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
'use client'
|
|
3
|
+
|
|
4
|
+
import { CSSProperties, forwardRef, ReactNode, RefAttributes } from 'react'
|
|
5
|
+
import ReactSelectDefaultExport, {
|
|
6
|
+
GroupBase,
|
|
7
|
+
Props as ReactSelectProps,
|
|
8
|
+
SelectInstance,
|
|
9
|
+
components
|
|
10
|
+
} from 'react-select'
|
|
11
|
+
import AsyncReactSelect, {
|
|
12
|
+
AsyncProps as AsyncSelectProps
|
|
13
|
+
} from 'react-select/async'
|
|
14
|
+
import CreatableReactSelect, {
|
|
15
|
+
CreatableProps as CreatableSelectProps
|
|
16
|
+
} from 'react-select/creatable'
|
|
17
|
+
import AsyncCreatableReactSelect, {
|
|
18
|
+
AsyncCreatableProps as AsyncCreatableSelectProps
|
|
19
|
+
} from 'react-select/async-creatable'
|
|
20
|
+
import classNames from 'classnames'
|
|
21
|
+
import {
|
|
22
|
+
Description,
|
|
23
|
+
Feedback,
|
|
24
|
+
Label,
|
|
25
|
+
useUniqueId
|
|
26
|
+
} from '@intility/bifrost-react'
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
DropdownIndicator,
|
|
30
|
+
ClearIndicator,
|
|
31
|
+
CustomInput,
|
|
32
|
+
CustomMenuList,
|
|
33
|
+
CustomOption,
|
|
34
|
+
LoadingIndicator
|
|
35
|
+
} from './overrides'
|
|
36
|
+
|
|
37
|
+
const ReactSelect =
|
|
38
|
+
(
|
|
39
|
+
ReactSelectDefaultExport as unknown as {
|
|
40
|
+
default: typeof ReactSelectDefaultExport
|
|
41
|
+
}
|
|
42
|
+
).default ?? ReactSelectDefaultExport
|
|
43
|
+
|
|
44
|
+
export const selectStyles = {
|
|
45
|
+
container: provided => ({
|
|
46
|
+
...provided,
|
|
47
|
+
'.bf-label-description + &, .bf-label + &': {
|
|
48
|
+
marginTop: 'var(--bfs4)' // add margin-top only when label or description is direct sibling with select
|
|
49
|
+
}
|
|
50
|
+
}),
|
|
51
|
+
control: (provided, state) => ({
|
|
52
|
+
...provided,
|
|
53
|
+
'&:hover': {
|
|
54
|
+
borderBottomColor: state.isFocused
|
|
55
|
+
? 'var(--bfc-base-c-theme)'
|
|
56
|
+
: 'var(--bfc-base-c-inverted-2)',
|
|
57
|
+
// Change color of dropdown icon when hover on Select
|
|
58
|
+
'.bf-select__dropdown-indicator': {
|
|
59
|
+
color: 'var(--bfc-theme-3)'
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
backgroundColor: state.isDisabled
|
|
63
|
+
? 'var(--bfc-base-dimmed)'
|
|
64
|
+
: 'var(--bfc-base-3)',
|
|
65
|
+
border: 0,
|
|
66
|
+
borderBottomWidth: '2px',
|
|
67
|
+
borderBottomStyle: 'solid',
|
|
68
|
+
borderBottomColor: state.isFocused
|
|
69
|
+
? 'var(--bfc-base-c-theme)'
|
|
70
|
+
: state.isDisabled
|
|
71
|
+
? 'transparent'
|
|
72
|
+
: 'var(--bfc-base-c-wcag)',
|
|
73
|
+
boxShadow: state.isFocused && '0 0 0 1px var(--bfc-theme-3)',
|
|
74
|
+
borderRadius: state.selectProps.menuIsOpen
|
|
75
|
+
? ' var(--bfl-border-radius) var(--bfl-border-radius) 0 0'
|
|
76
|
+
: 'var(--bfl-border-radius)',
|
|
77
|
+
minHeight: 'var(--bfs40)',
|
|
78
|
+
cursor: 'text'
|
|
79
|
+
}),
|
|
80
|
+
indicatorSeparator: () => ({
|
|
81
|
+
display: 'none'
|
|
82
|
+
}),
|
|
83
|
+
indicatorsContainer: provided => ({
|
|
84
|
+
...provided,
|
|
85
|
+
alignItems: 'flex-start',
|
|
86
|
+
padding: '7.5px 0'
|
|
87
|
+
}),
|
|
88
|
+
clearIndicator: provided => ({
|
|
89
|
+
...provided,
|
|
90
|
+
'&:hover': {
|
|
91
|
+
color: 'var(--bfc-base-c-1)'
|
|
92
|
+
},
|
|
93
|
+
color: 'var(--bfc-base-c-2)',
|
|
94
|
+
cursor: 'pointer',
|
|
95
|
+
padding: 'var(--bfs4)',
|
|
96
|
+
margin: '1px var(--bfs4) 0px 0px'
|
|
97
|
+
}),
|
|
98
|
+
dropdownIndicator: (provided, state) => ({
|
|
99
|
+
...provided,
|
|
100
|
+
color: state.isDisabled ? 'var(--bfc-base-c-2)' : 'var(--bfc-theme-1)',
|
|
101
|
+
cursor: 'pointer',
|
|
102
|
+
padding: 'var(--bfs4)',
|
|
103
|
+
marginRight: 'var(--bfs8)'
|
|
104
|
+
}),
|
|
105
|
+
input: provided => ({
|
|
106
|
+
...provided,
|
|
107
|
+
color: 'var(--bfc-base-c-1)',
|
|
108
|
+
fontFamily: 'inherit',
|
|
109
|
+
fontSize: 'var(--bf-font-size-l)'
|
|
110
|
+
}),
|
|
111
|
+
menuPortal: provided => ({
|
|
112
|
+
...provided,
|
|
113
|
+
zIndex: 9999
|
|
114
|
+
}),
|
|
115
|
+
menu: provided => ({
|
|
116
|
+
...provided,
|
|
117
|
+
backgroundColor: 'var(--bfc-base-3)',
|
|
118
|
+
boxShadow: 'none',
|
|
119
|
+
borderRadius: 'none',
|
|
120
|
+
marginTop: 0,
|
|
121
|
+
zIndex: 3
|
|
122
|
+
}),
|
|
123
|
+
menuList: provided => ({
|
|
124
|
+
...provided,
|
|
125
|
+
padding: 0,
|
|
126
|
+
boxShadow: '0 0 0 1px var(--bfc-theme-3)',
|
|
127
|
+
borderRadius: '0 0 var(--bfl-border-radius) var(--bfl-border-radius)'
|
|
128
|
+
}),
|
|
129
|
+
placeholder: provided => ({
|
|
130
|
+
...provided,
|
|
131
|
+
color: 'var(--bfc-base-c-2)',
|
|
132
|
+
fontSize: 'var(--bf-font-size-l)'
|
|
133
|
+
}),
|
|
134
|
+
singleValue: (provided, state) => ({
|
|
135
|
+
...provided,
|
|
136
|
+
color: state.selectProps.menuIsOpen
|
|
137
|
+
? 'var(--bfc-base-c-2)'
|
|
138
|
+
: 'var(--bfc-base-c)',
|
|
139
|
+
fontSize: 'var(--bf-font-size-l)'
|
|
140
|
+
}),
|
|
141
|
+
option: (provided, state) => ({
|
|
142
|
+
...provided,
|
|
143
|
+
display: 'flex',
|
|
144
|
+
justifyContent: !state.isMulti ? 'space-between' : 'normal',
|
|
145
|
+
alignItems: 'baseline',
|
|
146
|
+
padding: '7px 12px',
|
|
147
|
+
backgroundColor: state.isDisabled
|
|
148
|
+
? 'var(--bfc-base-dimmed)'
|
|
149
|
+
: state.isFocused
|
|
150
|
+
? 'var(--bfc-base-1)'
|
|
151
|
+
: 'var(--bfc-base-3)',
|
|
152
|
+
color: 'var(--bfc-base-c)',
|
|
153
|
+
'& .bf-select-checkbox': {
|
|
154
|
+
marginRight: 'var(--bfs8)',
|
|
155
|
+
color: 'var(--bfc-theme)'
|
|
156
|
+
},
|
|
157
|
+
'& .bf-select-selected-icon': {
|
|
158
|
+
color: 'var(--bfc-base-c-theme)',
|
|
159
|
+
marginLeft: 'var(--bfs4)'
|
|
160
|
+
},
|
|
161
|
+
'&:hover': {
|
|
162
|
+
backgroundColor: state.isDisabled
|
|
163
|
+
? 'var(--bfc-base-dimmed)'
|
|
164
|
+
: 'var(--bfc-base-1)',
|
|
165
|
+
cursor: state.isDisabled ? 'default' : 'pointer'
|
|
166
|
+
},
|
|
167
|
+
fontSize: 'var(--bf-font-size-l)',
|
|
168
|
+
fontWeight: state.isSelected ? 600 : 400,
|
|
169
|
+
wordBreak: 'break-word',
|
|
170
|
+
whiteSpace: 'normal'
|
|
171
|
+
}),
|
|
172
|
+
multiValue: (provided, state) => ({
|
|
173
|
+
...provided,
|
|
174
|
+
backgroundColor: state.isDisabled
|
|
175
|
+
? 'var(--bfc-base-c-inverted-2)'
|
|
176
|
+
: 'var(--bfc-theme-c)',
|
|
177
|
+
borderRadius: 'var(--bfl-border-radius)'
|
|
178
|
+
}),
|
|
179
|
+
multiValueLabel: (provided, state) => ({
|
|
180
|
+
...provided,
|
|
181
|
+
color: state.isDisabled ? 'var(--bfc-base-1)' : 'var(--bfc-base-c-theme)',
|
|
182
|
+
fontSize: 'var(--bf-font-size-m)'
|
|
183
|
+
}),
|
|
184
|
+
multiValueRemove: (provided, state) => ({
|
|
185
|
+
...provided,
|
|
186
|
+
color: state.isDisabled
|
|
187
|
+
? 'var(--bfc-base-1)'
|
|
188
|
+
: state.isFocused
|
|
189
|
+
? 'var(--bfc-theme-c-base-3)'
|
|
190
|
+
: 'var(--bfc-theme-1)',
|
|
191
|
+
borderRadius: 'unset',
|
|
192
|
+
borderTopRightRadius: 'var(--bfl-border-radius)',
|
|
193
|
+
borderBottomRightRadius: 'var(--bfl-border-radius)',
|
|
194
|
+
paddingLeft: 'var(--bfs2)',
|
|
195
|
+
paddingRight: 'var(--bfs2)',
|
|
196
|
+
marginLeft: 'var(--bfs2)',
|
|
197
|
+
background: state.isFocused && 'var(--bfc-theme-2)',
|
|
198
|
+
'&:hover': {
|
|
199
|
+
color: 'var(--bfc-theme-c-base-3)',
|
|
200
|
+
cursor: 'pointer',
|
|
201
|
+
background: 'var(--bfc-theme)'
|
|
202
|
+
},
|
|
203
|
+
'&:active': {
|
|
204
|
+
background: 'var(--bfc-theme-2)'
|
|
205
|
+
},
|
|
206
|
+
svg: {
|
|
207
|
+
marginTop: '1px'
|
|
208
|
+
}
|
|
209
|
+
}),
|
|
210
|
+
group: provided => ({
|
|
211
|
+
...provided,
|
|
212
|
+
padding: 'var(--bfs6) 0',
|
|
213
|
+
'&:first-of-type': {
|
|
214
|
+
marginTop: 'var(--bfs4)'
|
|
215
|
+
}
|
|
216
|
+
}),
|
|
217
|
+
groupHeading: provided => ({
|
|
218
|
+
...provided,
|
|
219
|
+
textTransform: 'capitalize',
|
|
220
|
+
color: 'var(--bfc-base-c-2)',
|
|
221
|
+
fontSize: 'var(--bf-font-size-s)',
|
|
222
|
+
marginBottom: 'var(--bfs2)'
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export const selectComponents: Partial<typeof components> = {
|
|
227
|
+
DropdownIndicator,
|
|
228
|
+
Input: CustomInput,
|
|
229
|
+
MenuList: CustomMenuList,
|
|
230
|
+
ClearIndicator,
|
|
231
|
+
Option: CustomOption,
|
|
232
|
+
LoadingIndicator
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const selectStates = ['default', 'alert'] as const
|
|
236
|
+
export type SelectState = (typeof selectStates)[number]
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Select HOC
|
|
240
|
+
*/
|
|
241
|
+
const SelectHOC = <Type, Selector>(Selector: Selector) => {
|
|
242
|
+
// @ts-ignore
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
|
+
const GeneratedSelect: Type = forwardRef<any, any>(
|
|
245
|
+
(
|
|
246
|
+
{
|
|
247
|
+
label,
|
|
248
|
+
hideLabel = false,
|
|
249
|
+
isDisabled = false,
|
|
250
|
+
state,
|
|
251
|
+
feedback,
|
|
252
|
+
required = false,
|
|
253
|
+
description,
|
|
254
|
+
requiredNoLabel = false,
|
|
255
|
+
optional = false,
|
|
256
|
+
inputId,
|
|
257
|
+
className,
|
|
258
|
+
style,
|
|
259
|
+
loading = false,
|
|
260
|
+
components,
|
|
261
|
+
...props
|
|
262
|
+
},
|
|
263
|
+
ref
|
|
264
|
+
) => {
|
|
265
|
+
const selectId = useUniqueId(inputId)
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<div
|
|
269
|
+
className={classNames(
|
|
270
|
+
className,
|
|
271
|
+
{ 'bf-select-container': true },
|
|
272
|
+
{ 'bf-select-disabled': isDisabled },
|
|
273
|
+
{ 'bf-select-alert': !isDisabled && state === 'alert' }
|
|
274
|
+
)}
|
|
275
|
+
style={style}
|
|
276
|
+
data-testid='bf-select-container'
|
|
277
|
+
>
|
|
278
|
+
{!hideLabel && (
|
|
279
|
+
<Label
|
|
280
|
+
htmlFor={selectId}
|
|
281
|
+
required={!isDisabled && required && !requiredNoLabel}
|
|
282
|
+
optional={optional}
|
|
283
|
+
disabled={isDisabled}
|
|
284
|
+
>
|
|
285
|
+
{label}
|
|
286
|
+
</Label>
|
|
287
|
+
)}
|
|
288
|
+
<Description>{description}</Description>
|
|
289
|
+
{/* @ts-ignore */}
|
|
290
|
+
<Selector
|
|
291
|
+
ref={ref}
|
|
292
|
+
inputId={selectId}
|
|
293
|
+
placeholder=''
|
|
294
|
+
components={{ ...selectComponents, ...components }}
|
|
295
|
+
styles={selectStyles}
|
|
296
|
+
isDisabled={isDisabled}
|
|
297
|
+
classNamePrefix='bf-select'
|
|
298
|
+
required={!isDisabled && (required || requiredNoLabel)}
|
|
299
|
+
aria-label={label}
|
|
300
|
+
hideSelectedOptions={false}
|
|
301
|
+
closeMenuOnSelect={props.isMulti ? false : true}
|
|
302
|
+
isLoading={loading ?? props.isLoading}
|
|
303
|
+
{...props}
|
|
304
|
+
/>
|
|
305
|
+
<Feedback>{feedback}</Feedback>
|
|
306
|
+
</div>
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return GeneratedSelect
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// this is somewhat useless on it's own
|
|
315
|
+
// has to be combined with one of the Select's props
|
|
316
|
+
export type SelectProps = {
|
|
317
|
+
/** Required label text */
|
|
318
|
+
label: ReactNode
|
|
319
|
+
/** Hide label text, will add label prop as aria-label for screen readers */
|
|
320
|
+
hideLabel?: boolean
|
|
321
|
+
/** Description text to show more information */
|
|
322
|
+
description?: ReactNode
|
|
323
|
+
/** Available states: `default` and `alert` */
|
|
324
|
+
state?: SelectState
|
|
325
|
+
/** Feedback text below the Select component */
|
|
326
|
+
feedback?: ReactNode
|
|
327
|
+
/** Required prop indicating mandatory field */
|
|
328
|
+
required?: boolean
|
|
329
|
+
/** Bool to mark Select component required, but hides the required label */
|
|
330
|
+
requiredNoLabel?: boolean
|
|
331
|
+
/** Marks Select component as optional */
|
|
332
|
+
optional?: boolean
|
|
333
|
+
/** Inline CSS styles */
|
|
334
|
+
style?: CSSProperties
|
|
335
|
+
/** Displays a loading spinner */
|
|
336
|
+
loading?: boolean
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Each select get its own type which uses the correctly imported props
|
|
340
|
+
// And calls the HOC
|
|
341
|
+
// The resulting component should be correctly typed
|
|
342
|
+
|
|
343
|
+
// Plain Select
|
|
344
|
+
export type SelectType = {
|
|
345
|
+
<
|
|
346
|
+
OptionType = { label: string; value: string },
|
|
347
|
+
IsMulti extends boolean = false,
|
|
348
|
+
Group extends GroupBase<OptionType> = GroupBase<OptionType>
|
|
349
|
+
>(
|
|
350
|
+
props: ReactSelectProps<OptionType, IsMulti, Group> &
|
|
351
|
+
RefAttributes<SelectInstance<OptionType, IsMulti, Group>> &
|
|
352
|
+
SelectProps
|
|
353
|
+
): React.ReactElement | null
|
|
354
|
+
displayName?: string
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Select component - dropdown list
|
|
359
|
+
*/
|
|
360
|
+
const SelectComponent: SelectType = SelectHOC<SelectType, typeof ReactSelect>(
|
|
361
|
+
ReactSelect
|
|
362
|
+
)
|
|
363
|
+
SelectComponent.displayName = 'Select'
|
|
364
|
+
|
|
365
|
+
// Async Select
|
|
366
|
+
export type AsyncType = {
|
|
367
|
+
<
|
|
368
|
+
OptionType = { label: string; value: string },
|
|
369
|
+
IsMulti extends boolean = false,
|
|
370
|
+
Group extends GroupBase<OptionType> = {
|
|
371
|
+
options: OptionType[]
|
|
372
|
+
label?: string
|
|
373
|
+
}
|
|
374
|
+
>(
|
|
375
|
+
props: AsyncSelectProps<OptionType, IsMulti, Group> &
|
|
376
|
+
RefAttributes<SelectInstance<OptionType, IsMulti, Group>> &
|
|
377
|
+
SelectProps
|
|
378
|
+
): React.ReactElement | null
|
|
379
|
+
displayName?: string
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const AsyncSelect = SelectHOC<AsyncType, typeof AsyncReactSelect>(
|
|
383
|
+
AsyncReactSelect
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
AsyncSelect.displayName = 'AsyncSelect'
|
|
387
|
+
|
|
388
|
+
// Creatable Select
|
|
389
|
+
export type CreatableType = {
|
|
390
|
+
<
|
|
391
|
+
OptionType = { label: string; value: string },
|
|
392
|
+
IsMulti extends boolean = false,
|
|
393
|
+
Group extends GroupBase<OptionType> = {
|
|
394
|
+
options: OptionType[]
|
|
395
|
+
label?: string
|
|
396
|
+
}
|
|
397
|
+
>(
|
|
398
|
+
props: CreatableSelectProps<OptionType, IsMulti, Group> &
|
|
399
|
+
RefAttributes<SelectInstance<OptionType, IsMulti, Group>> &
|
|
400
|
+
SelectProps
|
|
401
|
+
): React.ReactElement | null
|
|
402
|
+
displayName?: string
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const CreatableSelect = SelectHOC<CreatableType, typeof CreatableReactSelect>(
|
|
406
|
+
CreatableReactSelect
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
CreatableSelect.displayName = 'CreatableSelect'
|
|
410
|
+
|
|
411
|
+
// Async Creatable Select
|
|
412
|
+
export type AsyncCreatableType = {
|
|
413
|
+
<
|
|
414
|
+
OptionType = { label: string; value: string },
|
|
415
|
+
IsMulti extends boolean = false,
|
|
416
|
+
Group extends GroupBase<OptionType> = {
|
|
417
|
+
options: OptionType[]
|
|
418
|
+
label?: string
|
|
419
|
+
}
|
|
420
|
+
>(
|
|
421
|
+
props: AsyncCreatableSelectProps<OptionType, IsMulti, Group> &
|
|
422
|
+
RefAttributes<SelectInstance<OptionType, IsMulti, Group>> &
|
|
423
|
+
SelectProps
|
|
424
|
+
): React.ReactElement | null
|
|
425
|
+
displayName?: string
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const AsyncCreatableSelect = SelectHOC<
|
|
429
|
+
AsyncCreatableType,
|
|
430
|
+
typeof AsyncCreatableReactSelect
|
|
431
|
+
>(AsyncCreatableReactSelect)
|
|
432
|
+
|
|
433
|
+
AsyncCreatableSelect.displayName = 'AsyncCreatableSelect'
|
|
434
|
+
|
|
435
|
+
export { AsyncSelect, CreatableSelect, AsyncCreatableSelect }
|
|
436
|
+
export default SelectComponent
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IconDefinition,
|
|
3
|
+
IconName,
|
|
4
|
+
IconPathData,
|
|
5
|
+
IconPrefix
|
|
6
|
+
} from '@fortawesome/fontawesome-svg-core'
|
|
7
|
+
|
|
8
|
+
const prefix = 'fac' as IconPrefix
|
|
9
|
+
const iconName = 'bf-spinner' as IconName
|
|
10
|
+
const width = 18
|
|
11
|
+
const height = 18
|
|
12
|
+
const aliases = []
|
|
13
|
+
const unicode = ''
|
|
14
|
+
const svgPathData: IconPathData = [
|
|
15
|
+
'M9 2C5.13401 2 2 5.13401 2 9C2 12.866 5.13401 16 9 16C12.866 16 16 12.866 16 9C16 5.13401 12.866 2 9 2ZM0 9C0 4.02944 4.02944 0 9 0C13.9706 0 18 4.02944 18 9C18 13.9706 13.9706 18 9 18C4.02944 18 0 13.9706 0 9Z',
|
|
16
|
+
'M8 1C8 0.447715 8.44772 0 9 0C13.9706 0 18 4.02944 18 9C18 9.55229 17.5523 10 17 10C16.4477 10 16 9.55229 16 9C16 5.13401 12.866 2 9 2C8.44772 2 8 1.55228 8 1Z'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
const definition: IconDefinition = {
|
|
20
|
+
prefix,
|
|
21
|
+
iconName,
|
|
22
|
+
icon: [width, height, aliases, unicode, svgPathData]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
definition as default,
|
|
27
|
+
definition as faIndeterminate,
|
|
28
|
+
definition,
|
|
29
|
+
prefix,
|
|
30
|
+
iconName,
|
|
31
|
+
width,
|
|
32
|
+
height,
|
|
33
|
+
aliases as ligatures,
|
|
34
|
+
unicode,
|
|
35
|
+
svgPathData,
|
|
36
|
+
aliases
|
|
37
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Icon } from '@intility/bifrost-react'
|
|
2
|
+
import { components } from 'react-select'
|
|
3
|
+
import { faXmark } from '@fortawesome/free-solid-svg-icons/faXmark'
|
|
4
|
+
|
|
5
|
+
const ClearIndicator = props => {
|
|
6
|
+
return (
|
|
7
|
+
<components.ClearIndicator {...props}>
|
|
8
|
+
<Icon icon={faXmark} />
|
|
9
|
+
</components.ClearIndicator>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default ClearIndicator
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { components, Props } from 'react-select'
|
|
2
|
+
|
|
3
|
+
const CustomInput = props => {
|
|
4
|
+
const { required, value } = props.selectProps as Props & { required: boolean }
|
|
5
|
+
const updatedProps = {
|
|
6
|
+
...props,
|
|
7
|
+
autoComplete: 'noAutocomplete'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<>
|
|
12
|
+
<components.Input {...updatedProps} />
|
|
13
|
+
<input
|
|
14
|
+
style={{
|
|
15
|
+
opacity: 0,
|
|
16
|
+
height: 0,
|
|
17
|
+
position: 'absolute',
|
|
18
|
+
pointerEvents: 'none'
|
|
19
|
+
}}
|
|
20
|
+
onChange={e => e.preventDefault()}
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
value={(value as any)?.label ?? ''} // casting to any, because we don't know the type of an option
|
|
23
|
+
tabIndex={-1}
|
|
24
|
+
autoComplete='noAutocomplete'
|
|
25
|
+
required={required}
|
|
26
|
+
data-testid='bf-select-input'
|
|
27
|
+
/>
|
|
28
|
+
</>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default CustomInput
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { components } from 'react-select'
|
|
2
|
+
|
|
3
|
+
const CustomMenuList = props => {
|
|
4
|
+
return (
|
|
5
|
+
<components.MenuList
|
|
6
|
+
data-testid='bf-select-menulist'
|
|
7
|
+
className='bf-scrollbar-small'
|
|
8
|
+
{...props}
|
|
9
|
+
>
|
|
10
|
+
{props.children}
|
|
11
|
+
</components.MenuList>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default CustomMenuList
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { components } from 'react-select'
|
|
2
|
+
import { faSquare } from '@fortawesome/free-regular-svg-icons/faSquare'
|
|
3
|
+
import { faCheckSquare } from '@fortawesome/free-solid-svg-icons/faCheckSquare'
|
|
4
|
+
import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck'
|
|
5
|
+
import { Icon } from '@intility/bifrost-react'
|
|
6
|
+
|
|
7
|
+
const CustomOption = props => {
|
|
8
|
+
return (
|
|
9
|
+
<components.Option {...props}>
|
|
10
|
+
{props.isMulti && (
|
|
11
|
+
<div>
|
|
12
|
+
<Icon
|
|
13
|
+
icon={props.isSelected ? faCheckSquare : faSquare}
|
|
14
|
+
fixedWidth
|
|
15
|
+
className='bf-select-checkbox'
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
)}
|
|
19
|
+
{props.children}
|
|
20
|
+
{!props.isMulti && props.isSelected && (
|
|
21
|
+
<div>
|
|
22
|
+
<Icon icon={faCheck} fixedWidth className='bf-select-selected-icon' />
|
|
23
|
+
</div>
|
|
24
|
+
)}
|
|
25
|
+
</components.Option>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default CustomOption
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { components } from 'react-select'
|
|
2
|
+
import { faCaretDown } from '@fortawesome/free-solid-svg-icons/faCaretDown'
|
|
3
|
+
import { Icon } from '@intility/bifrost-react'
|
|
4
|
+
|
|
5
|
+
const DropdownIndicator = props => {
|
|
6
|
+
return (
|
|
7
|
+
<components.DropdownIndicator {...props}>
|
|
8
|
+
<Icon icon={faCaretDown} />
|
|
9
|
+
</components.DropdownIndicator>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default DropdownIndicator
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as ClearIndicator } from './ClearIndicator.internal'
|
|
2
|
+
export { default as CustomInput } from './CustomInput.internal'
|
|
3
|
+
export { default as LoadingIndicator } from './LoadingIndicator.internal'
|
|
4
|
+
export { default as CustomMenuList } from './CustomMenuList.internal'
|
|
5
|
+
export { default as DropdownIndicator } from './DropdownIndicator.internal'
|
|
6
|
+
export { default as CustomOption } from './CustomOption.internal'
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"declarationMap": false,
|
|
6
|
+
"isolatedModules": false,
|
|
7
|
+
"noEmit": false,
|
|
8
|
+
"allowJs": false,
|
|
9
|
+
"sourceMap": false,
|
|
10
|
+
"moduleResolution": "Bundler",
|
|
11
|
+
"emitDeclarationOnly": true,
|
|
12
|
+
"outDir": "dist"
|
|
13
|
+
},
|
|
14
|
+
"include": ["./src/"],
|
|
15
|
+
"exclude": []
|
|
16
|
+
}
|
package/vitest.config.ts
ADDED