@loadsmart/loadsmart-ui 5.9.0 → 5.10.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/Button/Button.d.ts +4 -1
- package/dist/components/Button/Button.stories.d.ts +1 -0
- package/dist/components/Select/Select.fixtures.d.ts +1 -1
- package/dist/index.js +502 -490
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Button/Button.stories.tsx +32 -12
- package/src/components/Button/Button.test.tsx +24 -8
- package/src/components/Button/Button.tsx +122 -26
- package/src/components/Select/Select.fixtures.ts +2 -2
- package/src/components/Select/Select.stories.tsx +6 -4
- package/src/components/Select/Select.test.tsx +20 -40
package/package.json
CHANGED
|
@@ -3,11 +3,16 @@ import { Meta } from '@storybook/react/types-6-0'
|
|
|
3
3
|
import BackButton from '../../common/BackButton'
|
|
4
4
|
import Button, { SelectorButton, IconButton, Caret, BaseButton } from './Button'
|
|
5
5
|
import CloseButton from '../../common/CloseButton'
|
|
6
|
+
import type { ReactNode } from 'react'
|
|
6
7
|
|
|
7
8
|
import type { BackButtonProps } from '../../common/BackButton'
|
|
8
9
|
import type { ButtonProps } from './Button'
|
|
9
10
|
import type { CloseButtonProps } from '../../common/CloseButton'
|
|
10
11
|
|
|
12
|
+
const Container = ({ children }: { children?: ReactNode }) => {
|
|
13
|
+
return <div className="flex flex-col space-y-2 items-center">{children}</div>
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
export default {
|
|
12
17
|
title: 'Components/Button',
|
|
13
18
|
component: Button,
|
|
@@ -34,6 +39,11 @@ export default {
|
|
|
34
39
|
type: 'boolean',
|
|
35
40
|
},
|
|
36
41
|
},
|
|
42
|
+
loading: {
|
|
43
|
+
control: {
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
37
47
|
className: {
|
|
38
48
|
table: {
|
|
39
49
|
disable: true,
|
|
@@ -78,9 +88,9 @@ export default {
|
|
|
78
88
|
|
|
79
89
|
export function Playground(args: ButtonProps): JSX.Element {
|
|
80
90
|
return (
|
|
81
|
-
<
|
|
91
|
+
<Container>
|
|
82
92
|
<Button {...args}>Button</Button>
|
|
83
|
-
</
|
|
93
|
+
</Container>
|
|
84
94
|
)
|
|
85
95
|
}
|
|
86
96
|
|
|
@@ -93,7 +103,7 @@ Playground.args = {
|
|
|
93
103
|
|
|
94
104
|
export function Base(args: ButtonProps): JSX.Element {
|
|
95
105
|
return (
|
|
96
|
-
<
|
|
106
|
+
<Container>
|
|
97
107
|
<BaseButton {...args}>Click me</BaseButton>
|
|
98
108
|
<BaseButton {...args} leading={<span>♣</span>}>
|
|
99
109
|
Click me
|
|
@@ -104,17 +114,17 @@ export function Base(args: ButtonProps): JSX.Element {
|
|
|
104
114
|
<BaseButton {...args} leading={<span>♣</span>} trailing={<span>♠</span>}>
|
|
105
115
|
Click me
|
|
106
116
|
</BaseButton>
|
|
107
|
-
</
|
|
117
|
+
</Container>
|
|
108
118
|
)
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
export function Selector(args: ButtonProps): JSX.Element {
|
|
112
122
|
return (
|
|
113
|
-
<
|
|
123
|
+
<Container>
|
|
114
124
|
<SelectorButton {...args} trailing={<Caret />}>
|
|
115
125
|
Button
|
|
116
126
|
</SelectorButton>
|
|
117
|
-
</
|
|
127
|
+
</Container>
|
|
118
128
|
)
|
|
119
129
|
}
|
|
120
130
|
|
|
@@ -125,11 +135,11 @@ Selector.args = {
|
|
|
125
135
|
|
|
126
136
|
export function Icon(args: ButtonProps): JSX.Element {
|
|
127
137
|
return (
|
|
128
|
-
<
|
|
138
|
+
<Container>
|
|
129
139
|
<IconButton {...args} variant="icon">
|
|
130
140
|
<span>♣</span>
|
|
131
141
|
</IconButton>
|
|
132
|
-
</
|
|
142
|
+
</Container>
|
|
133
143
|
)
|
|
134
144
|
}
|
|
135
145
|
|
|
@@ -139,16 +149,26 @@ Icon.args = {
|
|
|
139
149
|
|
|
140
150
|
export function Back(args: BackButtonProps): JSX.Element {
|
|
141
151
|
return (
|
|
142
|
-
<
|
|
152
|
+
<Container>
|
|
143
153
|
<BackButton {...args} />
|
|
144
|
-
</
|
|
154
|
+
</Container>
|
|
145
155
|
)
|
|
146
156
|
}
|
|
147
157
|
|
|
148
158
|
export function Close(args: CloseButtonProps): JSX.Element {
|
|
149
159
|
return (
|
|
150
|
-
<
|
|
160
|
+
<Container>
|
|
151
161
|
<CloseButton {...args} />
|
|
152
|
-
</
|
|
162
|
+
</Container>
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function Loading(args: ButtonProps): JSX.Element {
|
|
167
|
+
return (
|
|
168
|
+
<Container>
|
|
169
|
+
<Button loading {...args}>
|
|
170
|
+
Accessible Text
|
|
171
|
+
</Button>
|
|
172
|
+
</Container>
|
|
153
173
|
)
|
|
154
174
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import { screen } from '@testing-library/react'
|
|
2
3
|
|
|
3
4
|
import generator from '../../../tests/generator'
|
|
4
5
|
import renderer from '../../../tests/renderer'
|
|
@@ -13,8 +14,9 @@ describe('<Button />', () => {
|
|
|
13
14
|
children: generator.word(),
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
setup(props)
|
|
18
|
+
|
|
19
|
+
screen.getByRole('button', { name: props.children })
|
|
18
20
|
})
|
|
19
21
|
|
|
20
22
|
it('renders trailing correctly', () => {
|
|
@@ -23,9 +25,9 @@ describe('<Button />', () => {
|
|
|
23
25
|
trailing: generator.word(),
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
setup(props)
|
|
29
|
+
|
|
30
|
+
screen.getByRole('button', { name: `${props.children} ${props.trailing}` })
|
|
29
31
|
})
|
|
30
32
|
|
|
31
33
|
it('renders leading correctly', () => {
|
|
@@ -34,8 +36,22 @@ describe('<Button />', () => {
|
|
|
34
36
|
leading: generator.word(),
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
setup(props)
|
|
40
|
+
|
|
41
|
+
screen.getByRole('button', { name: `${props.leading} ${props.children}` })
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('renders loading state', () => {
|
|
45
|
+
const props = {
|
|
46
|
+
children: generator.word(),
|
|
47
|
+
loading: true,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setup(props)
|
|
51
|
+
|
|
52
|
+
const button = screen.getByRole('button')
|
|
53
|
+
|
|
54
|
+
expect(button).toHaveAttribute('aria-disabled', 'true')
|
|
55
|
+
expect(button).toHaveAccessibleName(props.children)
|
|
40
56
|
})
|
|
41
57
|
})
|
|
@@ -14,17 +14,23 @@ import rem from 'utils/toolset/rem'
|
|
|
14
14
|
import transition from 'styles/transition'
|
|
15
15
|
import typography from 'styles/typography'
|
|
16
16
|
|
|
17
|
+
import { LoadingDots } from 'components/Loaders'
|
|
18
|
+
|
|
17
19
|
import type { ButtonHTMLAttributes, ForwardedRef, ReactNode } from 'react'
|
|
18
20
|
import type { IconProps } from 'components/Icon'
|
|
19
21
|
import type ColorScheme from 'utils/types/ColorScheme'
|
|
22
|
+
import type { LoadingDotsProps } from 'components/Loaders'
|
|
23
|
+
|
|
24
|
+
export type ButtonVariants = 'primary' | 'secondary' | 'warning' | 'icon' | 'tertiary'
|
|
20
25
|
|
|
21
26
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
22
27
|
className?: string
|
|
23
28
|
leading?: ReactNode
|
|
24
29
|
scheme?: ColorScheme
|
|
25
30
|
trailing?: ReactNode
|
|
26
|
-
variant?:
|
|
31
|
+
variant?: ButtonVariants
|
|
27
32
|
scale?: 'small' | 'default' | 'large'
|
|
33
|
+
loading?: boolean
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
const StyledSpan = styled.span`
|
|
@@ -44,23 +50,24 @@ const Trailing = styled(StyledSpan)`
|
|
|
44
50
|
/* placeholder */
|
|
45
51
|
`
|
|
46
52
|
|
|
47
|
-
export const Children = styled.span
|
|
48
|
-
${({ children }
|
|
53
|
+
export const Children = styled.span<ButtonProps>`
|
|
54
|
+
${({ children }) =>
|
|
49
55
|
typeof children === 'string'
|
|
50
|
-
?
|
|
51
|
-
${ellipsizable()}
|
|
52
|
-
`
|
|
56
|
+
? ellipsizable()
|
|
53
57
|
: `
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
flex-flow: row nowrap;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
`}
|
|
59
63
|
|
|
60
64
|
padding: ${rem('6px')} 0;
|
|
61
65
|
`
|
|
62
66
|
|
|
63
|
-
const BaseStyledButton = styled.button<{
|
|
67
|
+
const BaseStyledButton = styled.button<{
|
|
68
|
+
$scale: ButtonProps['scale']
|
|
69
|
+
$loading?: ButtonProps['loading']
|
|
70
|
+
}>`
|
|
64
71
|
${transition()}
|
|
65
72
|
|
|
66
73
|
${typography(
|
|
@@ -98,6 +105,8 @@ const BaseStyledButton = styled.button<{ $scale: ButtonProps['scale'] }>`
|
|
|
98
105
|
|
|
99
106
|
${disableable()}
|
|
100
107
|
|
|
108
|
+
${({ $loading }) => $loading && 'pointer-events: none;'}
|
|
109
|
+
|
|
101
110
|
${Leading} {
|
|
102
111
|
margin: 0 ${token('space-xs')} 0 0;
|
|
103
112
|
}
|
|
@@ -359,15 +368,86 @@ const StyledSelector = styled(StyledButton)`
|
|
|
359
368
|
}
|
|
360
369
|
`
|
|
361
370
|
|
|
362
|
-
|
|
363
|
-
|
|
371
|
+
const TextHidden = styled.span`
|
|
372
|
+
transform: scale(0);
|
|
373
|
+
`
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Accessible attributes in `LoadingDots` aren't necessary
|
|
377
|
+
* because the `Button` will keep its content, but invisible
|
|
378
|
+
*/
|
|
379
|
+
const StyledLoadingDots = styled(LoadingDots).attrs({
|
|
380
|
+
'aria-label': undefined,
|
|
381
|
+
role: 'presentation',
|
|
382
|
+
})`
|
|
383
|
+
position: absolute;
|
|
384
|
+
|
|
385
|
+
display: flex;
|
|
386
|
+
align-items: center;
|
|
387
|
+
justify-content: center;
|
|
388
|
+
|
|
389
|
+
width: 100%;
|
|
390
|
+
`
|
|
391
|
+
|
|
392
|
+
const ButtonLoadingDots = ({
|
|
393
|
+
buttonVariant = 'secondary',
|
|
394
|
+
...remainingProps
|
|
395
|
+
}: Omit<LoadingDotsProps, 'variant'> & { buttonVariant?: ButtonVariants }) => {
|
|
396
|
+
const buttonLightVariants = new Set(['secondary', 'warning', 'icon', 'tertiary'])
|
|
397
|
+
/**
|
|
398
|
+
* Change LoadingDots variant between `light` and `dark` to have contrast with Button's variant
|
|
399
|
+
*/
|
|
400
|
+
const loadingDotsVariant: 'dark' | 'light' = buttonLightVariants.has(buttonVariant)
|
|
401
|
+
? 'dark'
|
|
402
|
+
: 'light'
|
|
403
|
+
|
|
404
|
+
return <StyledLoadingDots {...remainingProps} variant={loadingDotsVariant} />
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function ButtonChildrenWrapper({
|
|
408
|
+
loading,
|
|
409
|
+
children,
|
|
410
|
+
variant,
|
|
411
|
+
}: Pick<ButtonProps, 'loading' | 'children' | 'variant'>) {
|
|
412
|
+
if (loading) {
|
|
413
|
+
return (
|
|
414
|
+
<>
|
|
415
|
+
<ButtonLoadingDots buttonVariant={variant} />
|
|
416
|
+
<TextHidden>{children}</TextHidden>
|
|
417
|
+
</>
|
|
418
|
+
)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return <>{children}</>
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export const BaseButton = forwardRef<HTMLButtonElement, ButtonProps>(function BaseButton(
|
|
425
|
+
{
|
|
426
|
+
scale = 'default',
|
|
427
|
+
children,
|
|
428
|
+
leading,
|
|
429
|
+
trailing,
|
|
430
|
+
loading,
|
|
431
|
+
disabled,
|
|
432
|
+
variant,
|
|
433
|
+
...others
|
|
434
|
+
}: ButtonProps,
|
|
364
435
|
ref: ForwardedRef<HTMLButtonElement>
|
|
365
436
|
) {
|
|
366
437
|
return (
|
|
367
|
-
<BaseStyledButton
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
{
|
|
438
|
+
<BaseStyledButton
|
|
439
|
+
ref={ref}
|
|
440
|
+
{...others}
|
|
441
|
+
aria-disabled={loading ? 'true' : undefined}
|
|
442
|
+
disabled={disabled}
|
|
443
|
+
$scale={scale}
|
|
444
|
+
$loading={loading}
|
|
445
|
+
>
|
|
446
|
+
<ButtonChildrenWrapper loading={loading} variant={variant}>
|
|
447
|
+
{leading && <Leading aria-hidden="true">{leading}</Leading>}
|
|
448
|
+
<Children loading={loading}>{children}</Children>
|
|
449
|
+
{trailing && <Trailing aria-hidden="true">{trailing}</Trailing>}
|
|
450
|
+
</ButtonChildrenWrapper>
|
|
371
451
|
</BaseStyledButton>
|
|
372
452
|
)
|
|
373
453
|
})
|
|
@@ -381,6 +461,8 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|
|
381
461
|
children,
|
|
382
462
|
leading,
|
|
383
463
|
trailing,
|
|
464
|
+
disabled,
|
|
465
|
+
loading,
|
|
384
466
|
...others
|
|
385
467
|
}: ButtonProps,
|
|
386
468
|
ref: ForwardedRef<HTMLButtonElement>
|
|
@@ -390,13 +472,18 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
|
|
390
472
|
ref={ref}
|
|
391
473
|
{...others}
|
|
392
474
|
type={type}
|
|
475
|
+
aria-disabled={loading ? 'true' : undefined}
|
|
476
|
+
disabled={disabled}
|
|
393
477
|
$scheme={scheme}
|
|
394
478
|
$scale={scale}
|
|
395
479
|
$variant={variant}
|
|
480
|
+
$loading={loading}
|
|
396
481
|
>
|
|
397
|
-
{
|
|
398
|
-
|
|
399
|
-
|
|
482
|
+
<ButtonChildrenWrapper loading={loading} variant={variant}>
|
|
483
|
+
{leading && <Leading>{leading}</Leading>}
|
|
484
|
+
<Children>{children}</Children>
|
|
485
|
+
{trailing && <Trailing>{trailing}</Trailing>}
|
|
486
|
+
</ButtonChildrenWrapper>
|
|
400
487
|
</StyledButton>
|
|
401
488
|
)
|
|
402
489
|
})
|
|
@@ -405,7 +492,7 @@ export function Caret(props: Omit<IconProps, 'name'>): JSX.Element {
|
|
|
405
492
|
return <Icon size={20} {...props} name="caret-down" />
|
|
406
493
|
}
|
|
407
494
|
|
|
408
|
-
export const SelectorButton = forwardRef<HTMLButtonElement, ButtonProps>(function
|
|
495
|
+
export const SelectorButton = forwardRef<HTMLButtonElement, ButtonProps>(function SelectorButton(
|
|
409
496
|
{
|
|
410
497
|
scheme = 'light',
|
|
411
498
|
scale = 'default',
|
|
@@ -413,6 +500,8 @@ export const SelectorButton = forwardRef<HTMLButtonElement, ButtonProps>(functio
|
|
|
413
500
|
variant = 'secondary',
|
|
414
501
|
children,
|
|
415
502
|
trailing,
|
|
503
|
+
disabled,
|
|
504
|
+
loading,
|
|
416
505
|
...others
|
|
417
506
|
}: ButtonProps,
|
|
418
507
|
ref: ForwardedRef<HTMLButtonElement>
|
|
@@ -424,18 +513,25 @@ export const SelectorButton = forwardRef<HTMLButtonElement, ButtonProps>(functio
|
|
|
424
513
|
ref={ref}
|
|
425
514
|
{...others}
|
|
426
515
|
type={type}
|
|
516
|
+
aria-disabled={loading ? 'true' : undefined}
|
|
517
|
+
disabled={disabled}
|
|
518
|
+
$loading={loading}
|
|
427
519
|
$scheme={scheme}
|
|
428
520
|
$scale={scale}
|
|
429
521
|
$variant={variant}
|
|
430
522
|
>
|
|
431
|
-
<
|
|
432
|
-
|
|
523
|
+
<ButtonChildrenWrapper loading={loading} variant={variant}>
|
|
524
|
+
<Children>{children}</Children>
|
|
525
|
+
{trailing && <Trailing>{trailing}</Trailing>}
|
|
526
|
+
</ButtonChildrenWrapper>
|
|
433
527
|
</StyledSelector>
|
|
434
528
|
)
|
|
435
529
|
})
|
|
436
530
|
|
|
437
|
-
export
|
|
438
|
-
|
|
531
|
+
export type IconButtonProps = Omit<ButtonProps, 'leading' | 'trailing' | 'variant' | 'loading'>
|
|
532
|
+
|
|
533
|
+
export const IconButton = forwardRef<HTMLButtonElement, ButtonProps>(function IconButton(
|
|
534
|
+
{ scheme = 'light', scale = 'default', type = 'button', children, ...others }: IconButtonProps,
|
|
439
535
|
ref: ForwardedRef<HTMLButtonElement>
|
|
440
536
|
) {
|
|
441
537
|
others = omit<ButtonProps>(others, ['leading', 'trailing', 'variant'])
|
|
@@ -22,7 +22,7 @@ export const SelectableKeyTypeOptions: { label: string; value: SelectableKeyType
|
|
|
22
22
|
{ label: 'String', value: 'string' },
|
|
23
23
|
]
|
|
24
24
|
|
|
25
|
-
export const FRUITS: Fruit[] = [
|
|
25
|
+
export const FRUITS: Readonly<Fruit[]> = Object.freeze([
|
|
26
26
|
{ label: 'Acerola', value: 'acerola', family: 'Malpighiaceae' },
|
|
27
27
|
{ label: 'Apple', value: 'apple', family: 'Rosaceae' },
|
|
28
28
|
{ label: 'Apricots', value: 'apricots', family: 'Rosaceae' },
|
|
@@ -93,7 +93,7 @@ export const FRUITS: Fruit[] = [
|
|
|
93
93
|
{ label: 'Tamarind', value: 'tamarind', family: 'Fabaceae' },
|
|
94
94
|
{ label: 'Tangerine', value: 'tangerine', family: 'Rutaceae' },
|
|
95
95
|
{ label: 'Watermelon', value: 'watermelon', family: 'Cucurbitaceae' },
|
|
96
|
-
]
|
|
96
|
+
])
|
|
97
97
|
|
|
98
98
|
function generateSelectOptions() {
|
|
99
99
|
return generator.array(() => {
|
|
@@ -441,11 +441,13 @@ const MixedCustomOption = ({ value }: SelectOptionProps) => {
|
|
|
441
441
|
},
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
+
const fruits = [...FRUITS]
|
|
445
|
+
|
|
444
446
|
export const CreatableSync: Story<SelectProps> = (args: SelectProps) => {
|
|
445
447
|
const handleCreate = useCallback(function handleCreate(query: string) {
|
|
446
448
|
const item: Option = { label: query, value: query } as Option
|
|
447
449
|
|
|
448
|
-
|
|
450
|
+
fruits.push(item as Fruit)
|
|
449
451
|
return item
|
|
450
452
|
}, [])
|
|
451
453
|
|
|
@@ -466,7 +468,7 @@ export const CreatableSync: Story<SelectProps> = (args: SelectProps) => {
|
|
|
466
468
|
</div>
|
|
467
469
|
<div className="text-sm" style={{ width: 720 }}>
|
|
468
470
|
<p>Available options:</p>
|
|
469
|
-
<code>{
|
|
471
|
+
<code>{fruits.map(({ label }) => label).join(', ')}</code>
|
|
470
472
|
</div>
|
|
471
473
|
</div>
|
|
472
474
|
)
|
|
@@ -604,7 +606,7 @@ export const CustomCreatableOption: Story<SelectProps> = ({ onCreate, ...args }:
|
|
|
604
606
|
const item: Option = { label: query, value: query } as Option
|
|
605
607
|
|
|
606
608
|
setValue(item)
|
|
607
|
-
|
|
609
|
+
fruits.push(item as Fruit)
|
|
608
610
|
},
|
|
609
611
|
[onCreate]
|
|
610
612
|
)
|
|
@@ -631,7 +633,7 @@ export const CustomCreatableOption: Story<SelectProps> = ({ onCreate, ...args }:
|
|
|
631
633
|
</div>
|
|
632
634
|
<div className="text-sm" style={{ width: 720 }}>
|
|
633
635
|
<p>Available options:</p>
|
|
634
|
-
<code>{
|
|
636
|
+
<code>{fruits.map(({ label }) => label).join(', ')}</code>
|
|
635
637
|
</div>
|
|
636
638
|
</div>
|
|
637
639
|
)
|
|
@@ -9,7 +9,7 @@ import generator from '../../../tests/generator'
|
|
|
9
9
|
import renderer, { screen, fire, waitFor } from '../../../tests/renderer'
|
|
10
10
|
import selectEvent from '../../testing/SelectEvent'
|
|
11
11
|
|
|
12
|
-
import type { SelectProps, Option
|
|
12
|
+
import type { SelectProps, Option } from './Select.types'
|
|
13
13
|
import Select from './Select'
|
|
14
14
|
import userEvent from '@testing-library/user-event'
|
|
15
15
|
import type { Selectable } from 'hooks/useSelectable'
|
|
@@ -142,7 +142,7 @@ describe('Select', () => {
|
|
|
142
142
|
expect(screen.getByTestId('select-trigger-handle')).toBeDisabled()
|
|
143
143
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
|
|
144
144
|
|
|
145
|
-
rerender(<Playground options={FRUITS
|
|
145
|
+
rerender(<Playground options={[...FRUITS]} />)
|
|
146
146
|
|
|
147
147
|
await selectEvent.expand(searchInput)
|
|
148
148
|
|
|
@@ -213,10 +213,7 @@ describe('Select', () => {
|
|
|
213
213
|
setup({})
|
|
214
214
|
|
|
215
215
|
const searchInput = screen.getByLabelText('Select your favorite fruit')
|
|
216
|
-
const selectedFruit = generator.
|
|
217
|
-
label: string
|
|
218
|
-
value: string
|
|
219
|
-
}
|
|
216
|
+
const selectedFruit = generator.pickone([...FRUITS])
|
|
220
217
|
|
|
221
218
|
await selectEvent.select(selectedFruit.label, searchInput)
|
|
222
219
|
|
|
@@ -229,10 +226,7 @@ describe('Select', () => {
|
|
|
229
226
|
})
|
|
230
227
|
|
|
231
228
|
it('initializes with a selected item', async () => {
|
|
232
|
-
const selectedFruit = generator.
|
|
233
|
-
label: string
|
|
234
|
-
value: string
|
|
235
|
-
}
|
|
229
|
+
const selectedFruit = generator.pickone([...FRUITS])
|
|
236
230
|
|
|
237
231
|
setup({
|
|
238
232
|
value: selectedFruit as Option,
|
|
@@ -248,10 +242,7 @@ describe('Select', () => {
|
|
|
248
242
|
})
|
|
249
243
|
|
|
250
244
|
it('updates selected item after the initially selected item changes', async () => {
|
|
251
|
-
const selectedFruit = generator.
|
|
252
|
-
label: string
|
|
253
|
-
value: string
|
|
254
|
-
}
|
|
245
|
+
const selectedFruit = generator.pickone([...FRUITS])
|
|
255
246
|
const props = {
|
|
256
247
|
value: selectedFruit as Option,
|
|
257
248
|
}
|
|
@@ -265,10 +256,7 @@ describe('Select', () => {
|
|
|
265
256
|
|
|
266
257
|
expect(selectedOptions[0]).toHaveTextContent(selectedFruit.label)
|
|
267
258
|
|
|
268
|
-
const newSelectedFruit = generator.
|
|
269
|
-
label: string
|
|
270
|
-
value: string
|
|
271
|
-
}
|
|
259
|
+
const newSelectedFruit = generator.pickone([...FRUITS])
|
|
272
260
|
const newProps = {
|
|
273
261
|
value: newSelectedFruit as Option,
|
|
274
262
|
}
|
|
@@ -284,10 +272,7 @@ describe('Select', () => {
|
|
|
284
272
|
})
|
|
285
273
|
|
|
286
274
|
it('unselects the clicked item', async () => {
|
|
287
|
-
const selectedFruit = generator.
|
|
288
|
-
label: string
|
|
289
|
-
value: string
|
|
290
|
-
}
|
|
275
|
+
const selectedFruit = generator.pickone([...FRUITS])
|
|
291
276
|
|
|
292
277
|
setup({
|
|
293
278
|
value: selectedFruit as Option,
|
|
@@ -308,10 +293,7 @@ describe('Select', () => {
|
|
|
308
293
|
})
|
|
309
294
|
|
|
310
295
|
it('clears selection', async () => {
|
|
311
|
-
const selectedFruit = generator.
|
|
312
|
-
label: string
|
|
313
|
-
value: string
|
|
314
|
-
}
|
|
296
|
+
const selectedFruit = generator.pickone([...FRUITS])
|
|
315
297
|
|
|
316
298
|
setup({
|
|
317
299
|
value: selectedFruit as Option,
|
|
@@ -506,7 +488,7 @@ describe('Select', () => {
|
|
|
506
488
|
setup({})
|
|
507
489
|
|
|
508
490
|
const searchInput = screen.getByLabelText('Select your favorite fruit')
|
|
509
|
-
const selectedFruit = generator.
|
|
491
|
+
const selectedFruit = generator.pickone<Fruit>([...FRUITS])
|
|
510
492
|
const optionText = getOptionText(selectedFruit)
|
|
511
493
|
|
|
512
494
|
await selectEvent.select(optionText, searchInput)
|
|
@@ -520,23 +502,21 @@ describe('Select', () => {
|
|
|
520
502
|
it('selects multiple clicked custom items', async () => {
|
|
521
503
|
setup({ multiple: true })
|
|
522
504
|
|
|
523
|
-
const
|
|
505
|
+
const SELECTED_OPTIONS_AMOUNT = 2
|
|
524
506
|
const searchInput = screen.getByLabelText('Select your favorite fruit')
|
|
525
|
-
const options = generator.
|
|
507
|
+
const options = generator.pickset([...FRUITS], SELECTED_OPTIONS_AMOUNT)
|
|
526
508
|
|
|
527
|
-
for (
|
|
528
|
-
const option = options[i]
|
|
509
|
+
for await (const option of options) {
|
|
529
510
|
const optionText = getOptionText(option)
|
|
530
511
|
await selectEvent.select(optionText, searchInput)
|
|
531
512
|
}
|
|
532
513
|
|
|
533
514
|
const selectedOptions = await selectEvent.getSelectedOptions(searchInput)
|
|
534
|
-
expect(selectedOptions).toHaveLength(
|
|
515
|
+
expect(selectedOptions).toHaveLength(SELECTED_OPTIONS_AMOUNT)
|
|
535
516
|
|
|
536
|
-
for (
|
|
537
|
-
const option = options[i]
|
|
517
|
+
for await (const [index, option] of options.entries()) {
|
|
538
518
|
const optionText = getOptionText(option)
|
|
539
|
-
expect(selectedOptions[
|
|
519
|
+
expect(selectedOptions[index]).toHaveTextContent(optionText)
|
|
540
520
|
}
|
|
541
521
|
})
|
|
542
522
|
|
|
@@ -642,7 +622,7 @@ describe('Select', () => {
|
|
|
642
622
|
'renders creatable option at the end of the list when the entered query is not equal one of the available options - %s',
|
|
643
623
|
async (args) => {
|
|
644
624
|
setup({ ...args })
|
|
645
|
-
const { label: availableOption } = generator.
|
|
625
|
+
const { label: availableOption } = generator.pickone([...FRUITS])
|
|
646
626
|
const query = availableOption.slice(0, availableOption.length - 1)
|
|
647
627
|
|
|
648
628
|
const searchInput = screen.getByLabelText('Select your favorite fruit')
|
|
@@ -664,7 +644,7 @@ describe('Select', () => {
|
|
|
664
644
|
onCreate: (null as unknown) as undefined,
|
|
665
645
|
...args,
|
|
666
646
|
})
|
|
667
|
-
const { label: availableOption } = generator.
|
|
647
|
+
const { label: availableOption } = generator.pickone([...FRUITS])
|
|
668
648
|
const query = availableOption.slice(0, availableOption.length - 1)
|
|
669
649
|
|
|
670
650
|
const searchInput = screen.getByLabelText('Select your favorite fruit')
|
|
@@ -685,7 +665,7 @@ describe('Select', () => {
|
|
|
685
665
|
setup({
|
|
686
666
|
...args,
|
|
687
667
|
})
|
|
688
|
-
const { label: availableOption } = generator.
|
|
668
|
+
const { label: availableOption } = generator.pickone([...FRUITS])
|
|
689
669
|
|
|
690
670
|
const searchInput = screen.getByLabelText('Select your favorite fruit')
|
|
691
671
|
fire.change(searchInput, {
|
|
@@ -705,7 +685,7 @@ describe('Select', () => {
|
|
|
705
685
|
setup({
|
|
706
686
|
...args,
|
|
707
687
|
})
|
|
708
|
-
const { label: availableOption } = generator.
|
|
688
|
+
const { label: availableOption } = generator.pickone([...FRUITS])
|
|
709
689
|
|
|
710
690
|
await expandSelect()
|
|
711
691
|
|
|
@@ -865,7 +845,7 @@ describe('Select', () => {
|
|
|
865
845
|
)
|
|
866
846
|
}
|
|
867
847
|
|
|
868
|
-
const value = generator.pickone(FRUITS) as Selectable
|
|
848
|
+
const value = generator.pickone([...FRUITS]) as Selectable
|
|
869
849
|
|
|
870
850
|
setup({
|
|
871
851
|
...args,
|