paris 0.13.5 → 0.14.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/CHANGELOG.md +18 -0
- package/package.json +1 -1
- package/src/stories/combobox/Combobox.tsx +4 -0
- package/src/stories/informationaltooltip/InformationalTooltip.stories.tsx +6 -17
- package/src/stories/informationaltooltip/InformationalTooltip.tsx +86 -59
- package/src/stories/menu/Menu.tsx +2 -1
- package/src/stories/select/Select.module.scss +1 -7
- package/src/stories/select/Select.stories.ts +26 -4
- package/src/stories/select/Select.tsx +70 -21
- package/src/stories/utility/Dropdown.module.scss +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# paris
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a805866: Select: added `multiple` prop to convert listbox into a multiselect
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- fa49d95: Select: updated hover state for segemented control
|
|
12
|
+
- fa49d95: InformationalTooltip: added `defaultOpen` prop, replacing previous `open` prop
|
|
13
|
+
- fa49d95: InformationalTooltip: added exit animation, and animations use duration theme variables
|
|
14
|
+
|
|
15
|
+
## 0.13.6
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 1d092ca: Dropdowns: fix z-index positioning with transition containers
|
|
20
|
+
|
|
3
21
|
## 0.13.5
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "paris",
|
|
3
3
|
"author": "Sanil Chawla <sanil@slingshot.fm> (https://sanil.co)",
|
|
4
4
|
"description": "Paris is Slingshot's React design system. It's a collection of reusable components, design tokens, and guidelines that help us build consistent, accessible, and performant user interfaces.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.14.0",
|
|
6
6
|
"homepage": "https://paris.slingshot.fm",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react';
|
|
4
4
|
import {
|
|
5
|
+
Fragment,
|
|
6
|
+
|
|
5
7
|
useMemo, useId, useState,
|
|
6
8
|
} from 'react';
|
|
7
9
|
import { Combobox as HCombobox, Transition } from '@headlessui/react';
|
|
@@ -282,6 +284,8 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
282
284
|
)}
|
|
283
285
|
</div>
|
|
284
286
|
<Transition
|
|
287
|
+
as="div"
|
|
288
|
+
className={dropdownStyles.transitionContainer}
|
|
285
289
|
enter={dropdownStyles.transition}
|
|
286
290
|
enterFrom={dropdownStyles.enterFrom}
|
|
287
291
|
enterTo={dropdownStyles.enterTo}
|
|
@@ -13,17 +13,15 @@ const meta: Meta<typeof InformationalTooltip> = {
|
|
|
13
13
|
export default meta;
|
|
14
14
|
type Story = StoryObj<typeof InformationalTooltip>;
|
|
15
15
|
|
|
16
|
-
const render: Story['render'] = (args) =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
...args,
|
|
22
|
-
}));
|
|
16
|
+
const render: Story['render'] = (args) => createElement('div', {
|
|
17
|
+
style: { minHeight: '200px' },
|
|
18
|
+
}, createElement(InformationalTooltip, {
|
|
19
|
+
...args,
|
|
20
|
+
}));
|
|
23
21
|
|
|
24
22
|
export const Default: Story = {
|
|
25
23
|
args: {
|
|
26
|
-
children: 'If you are being
|
|
24
|
+
children: 'If you are being paid on 1099s (through transfer outs) you need to pay taxes quarterly. The amount you pay each quarter is a portion of your estimated tax burden for the year, based on your anticipated income amount. If you over/underpay, you will be refunded/owe the difference at the end of the year. ',
|
|
27
25
|
heading: 'Quarterly taxes',
|
|
28
26
|
},
|
|
29
27
|
render,
|
|
@@ -51,15 +49,6 @@ export const CustomTrigger: Story = {
|
|
|
51
49
|
render,
|
|
52
50
|
};
|
|
53
51
|
|
|
54
|
-
export const Open: Story = {
|
|
55
|
-
args: {
|
|
56
|
-
children: 'Open boolean set to true',
|
|
57
|
-
size: 'medium',
|
|
58
|
-
open: true,
|
|
59
|
-
},
|
|
60
|
-
render,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
52
|
export const CustomAlign: Story = {
|
|
64
53
|
args: {
|
|
65
54
|
children: 'With some text below',
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { FC, ReactNode } from 'react';
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import clsx from 'clsx';
|
|
3
4
|
import * as RadixTooltip from '@radix-ui/react-tooltip';
|
|
4
|
-
import { motion } from 'framer-motion';
|
|
5
|
+
import { motion, AnimatePresence } from 'framer-motion';
|
|
5
6
|
import styles from './InformationalTooltip.module.scss';
|
|
6
7
|
import { TextWhenString } from '../utility';
|
|
7
8
|
import { Icon, Info } from '../icon';
|
|
8
|
-
import { pvar } from '../theme';
|
|
9
|
+
import { pvar, pget } from '../theme';
|
|
9
10
|
|
|
10
11
|
export type InformationalTooltipProps = {
|
|
11
12
|
/**
|
|
@@ -41,15 +42,10 @@ export type InformationalTooltipProps = {
|
|
|
41
42
|
*/
|
|
42
43
|
align?: 'start' | 'center' | 'end';
|
|
43
44
|
/**
|
|
44
|
-
*
|
|
45
|
+
* Whether the tooltip should be open by default.
|
|
46
|
+
* @default false
|
|
45
47
|
*/
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Event handler called when the open state of the tooltip changes.
|
|
49
|
-
*
|
|
50
|
-
* @param value {boolean} - The new open state of the tooltip.
|
|
51
|
-
*/
|
|
52
|
-
onOpenChange?: (value: boolean) => void | Promise<void>;
|
|
48
|
+
defaultOpen?: boolean;
|
|
53
49
|
};
|
|
54
50
|
|
|
55
51
|
/**
|
|
@@ -73,53 +69,84 @@ export const InformationalTooltip: FC<InformationalTooltipProps> = ({
|
|
|
73
69
|
side = 'bottom',
|
|
74
70
|
sideOffset = 6,
|
|
75
71
|
align = 'start',
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
defaultOpen = false,
|
|
73
|
+
}) => {
|
|
74
|
+
const [isOpen, setOpen] = useState(defaultOpen);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Converts a CSS time value string to milliseconds
|
|
78
|
+
* @param timeValue - The CSS time value (e.g. '100ms', '0.5s')
|
|
79
|
+
* @returns The time value in milliseconds
|
|
80
|
+
* @throws Error if the time value format is invalid
|
|
81
|
+
*/
|
|
82
|
+
const parseCSSTime = (timeValue: string): number => {
|
|
83
|
+
// Match the value and unit
|
|
84
|
+
const match = timeValue.match(/^([\d.]+)(ms|s)$/);
|
|
85
|
+
|
|
86
|
+
if (!match) {
|
|
87
|
+
console.warn('Invalid CSS time format. Expected formats: "100ms", "0.5s"');
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const [, value, unit] = match;
|
|
92
|
+
const numValue = parseFloat(value);
|
|
93
|
+
|
|
94
|
+
// Convert to milliseconds based on the unit
|
|
95
|
+
return unit === 's' ? numValue * 1000 : numValue;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<RadixTooltip.Provider
|
|
100
|
+
delayDuration={parseCSSTime(pget('new.animations.duration.normal'))}
|
|
85
101
|
>
|
|
86
|
-
<RadixTooltip.
|
|
87
|
-
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
102
|
+
<RadixTooltip.Root
|
|
103
|
+
open={isOpen}
|
|
104
|
+
onOpenChange={setOpen}
|
|
105
|
+
>
|
|
106
|
+
<RadixTooltip.Trigger>
|
|
107
|
+
{!trigger ? (
|
|
108
|
+
<Icon icon={Info} size={14} className={styles.icon} style={{ color: pvar('new.colors.contentSecondary') }} />
|
|
109
|
+
) : (
|
|
110
|
+
<>
|
|
111
|
+
{trigger}
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
114
|
+
</RadixTooltip.Trigger>
|
|
115
|
+
<AnimatePresence>
|
|
116
|
+
{isOpen && (
|
|
117
|
+
<RadixTooltip.Portal forceMount>
|
|
118
|
+
<RadixTooltip.Content
|
|
119
|
+
side={side}
|
|
120
|
+
sideOffset={sideOffset}
|
|
121
|
+
align={align}
|
|
122
|
+
asChild
|
|
123
|
+
>
|
|
124
|
+
<motion.div
|
|
125
|
+
initial={{ opacity: 0, y: 3 }}
|
|
126
|
+
animate={{ opacity: 1, y: 0 }}
|
|
127
|
+
exit={{ opacity: 0, y: 3 }}
|
|
128
|
+
transition={{ duration: parseCSSTime(pget('new.animations.duration.normal')) / 1000 }}
|
|
129
|
+
className={clsx(styles.tooltip, styles[size])}
|
|
130
|
+
>
|
|
131
|
+
{heading && (
|
|
132
|
+
<div className={styles.heading}>
|
|
133
|
+
{headingIcon === null ? null : headingIcon || (
|
|
134
|
+
<Icon icon={Info} size={14} className={styles.icon} />
|
|
135
|
+
)}
|
|
136
|
+
<TextWhenString as="p" kind="paragraphXSmall" weight="medium">
|
|
137
|
+
{heading}
|
|
138
|
+
</TextWhenString>
|
|
139
|
+
</div>
|
|
140
|
+
)}
|
|
141
|
+
<TextWhenString as="p" kind="paragraphXSmall">
|
|
142
|
+
{children}
|
|
143
|
+
</TextWhenString>
|
|
144
|
+
</motion.div>
|
|
145
|
+
</RadixTooltip.Content>
|
|
146
|
+
</RadixTooltip.Portal>
|
|
147
|
+
)}
|
|
148
|
+
</AnimatePresence>
|
|
149
|
+
</RadixTooltip.Root>
|
|
150
|
+
</RadixTooltip.Provider>
|
|
151
|
+
);
|
|
152
|
+
};
|
|
@@ -64,7 +64,8 @@ Menu.Items = ({
|
|
|
64
64
|
className, children, position = 'left', ...props
|
|
65
65
|
}) => (
|
|
66
66
|
<Transition
|
|
67
|
-
as=
|
|
67
|
+
as="div"
|
|
68
|
+
className={dropdownStyles.transitionContainer}
|
|
68
69
|
enter={dropdownStyles.transition}
|
|
69
70
|
enterFrom={dropdownStyles.enterFrom}
|
|
70
71
|
enterTo={dropdownStyles.enterTo}
|
|
@@ -24,11 +24,6 @@
|
|
|
24
24
|
align-items: center;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
.transitionContainer {
|
|
28
|
-
position: relative;
|
|
29
|
-
z-index: 10;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
27
|
.options {
|
|
33
28
|
max-height: var(--options-maxHeight, auto);
|
|
34
29
|
overflow-y: auto;
|
|
@@ -286,8 +281,7 @@
|
|
|
286
281
|
}
|
|
287
282
|
|
|
288
283
|
&:hover {
|
|
289
|
-
|
|
290
|
-
color: var(--pte-new-colors-contentSecondary);
|
|
284
|
+
color: var(--pte-new-colors-contentPrimary);
|
|
291
285
|
}
|
|
292
286
|
|
|
293
287
|
&[data-headlessui-state~="checked"] {
|
|
@@ -15,13 +15,20 @@ type Story = StoryObj<typeof Select>;
|
|
|
15
15
|
const render: Story['render'] = (args) => {
|
|
16
16
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
17
17
|
const [selected, setSelected] = useState<string | null>(null);
|
|
18
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
19
|
+
const [selectedMultiple, setSelectedMultiple] = useState<string[] | null>([]);
|
|
18
20
|
return createElement('div', {
|
|
19
21
|
style: { minHeight: '400px' },
|
|
20
|
-
}, createElement(Select, {
|
|
22
|
+
}, createElement(Select, args.multiple ? {
|
|
21
23
|
...args,
|
|
22
|
-
value:
|
|
23
|
-
onChange: (
|
|
24
|
-
}
|
|
24
|
+
value: selectedMultiple,
|
|
25
|
+
onChange: (value: string[] | null) => setSelectedMultiple(value),
|
|
26
|
+
}
|
|
27
|
+
: {
|
|
28
|
+
...args,
|
|
29
|
+
value: selected,
|
|
30
|
+
onChange: (value: string | null) => setSelected(value),
|
|
31
|
+
}));
|
|
25
32
|
};
|
|
26
33
|
|
|
27
34
|
export const Default: Story = {
|
|
@@ -112,6 +119,21 @@ export const Card: Story = {
|
|
|
112
119
|
render,
|
|
113
120
|
};
|
|
114
121
|
|
|
122
|
+
export const Multiple: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
label: 'Release type',
|
|
125
|
+
description: 'Select the type of release you want to create.',
|
|
126
|
+
options: [
|
|
127
|
+
{ id: '1', node: 'Single' },
|
|
128
|
+
{ id: '2', node: 'EP' },
|
|
129
|
+
{ id: '3', node: 'Album (LP)' },
|
|
130
|
+
],
|
|
131
|
+
multiple: true,
|
|
132
|
+
multipleItemsName: 'releases',
|
|
133
|
+
},
|
|
134
|
+
render,
|
|
135
|
+
};
|
|
136
|
+
|
|
115
137
|
export const Segmented: Story = {
|
|
116
138
|
args: {
|
|
117
139
|
label: 'Donation',
|
|
@@ -29,7 +29,7 @@ export type Option<T = Record<string, any>> = {
|
|
|
29
29
|
disabled?: boolean,
|
|
30
30
|
metadata?: T,
|
|
31
31
|
};
|
|
32
|
-
export type
|
|
32
|
+
export type CommonSelectProps<T = Record<string, any>> = {
|
|
33
33
|
/**
|
|
34
34
|
* The {@link Option}s to render in the select box.
|
|
35
35
|
*
|
|
@@ -38,21 +38,6 @@ export type SelectProps<T = Record<string, any>> = {
|
|
|
38
38
|
* For type safety, you can pass in a type parameter to `SelectProps` component. This will be used as the type for the `metadata` property of each option.
|
|
39
39
|
*/
|
|
40
40
|
options: Option<T>[];
|
|
41
|
-
/**
|
|
42
|
-
* The option ID to render as selected in the select box.
|
|
43
|
-
*
|
|
44
|
-
* This should exactly match one of the option IDs passed in the `options` prop. If `null`, no option will be selected.
|
|
45
|
-
*/
|
|
46
|
-
value?: Option<T>['id'] | null;
|
|
47
|
-
/**
|
|
48
|
-
* The interaction handler for the Select.
|
|
49
|
-
*/
|
|
50
|
-
onChange?: (value: Option<T>['id'] | null) => void | Promise<void>;
|
|
51
|
-
/**
|
|
52
|
-
* The visual variant of the Select. `listbox` will render as a dropdown menu, `radio` will render as a radio group, `card` will render as selectable cards, and `segmented` will render as a segmented control.
|
|
53
|
-
* @default listbox
|
|
54
|
-
*/
|
|
55
|
-
kind?: 'listbox' | 'radio' | 'card' | 'segmented';
|
|
56
41
|
/**
|
|
57
42
|
* The size of the options dropdown, in pixels. Only applicable to kind="listbox".
|
|
58
43
|
*/
|
|
@@ -67,7 +52,6 @@ export type SelectProps<T = Record<string, any>> = {
|
|
|
67
52
|
* @default compact
|
|
68
53
|
*/
|
|
69
54
|
segmentedHeight?: 'compact' | 'tall';
|
|
70
|
-
|
|
71
55
|
/**
|
|
72
56
|
* Prop overrides for other rendered elements. Overrides for the input itself should be passed directly to the component.
|
|
73
57
|
*/
|
|
@@ -83,6 +67,55 @@ export type SelectProps<T = Record<string, any>> = {
|
|
|
83
67
|
}
|
|
84
68
|
} & Omit<InputProps, 'type' | 'overrides'>;
|
|
85
69
|
|
|
70
|
+
export type SingleSelectProps<T = Record<string, any>> = {
|
|
71
|
+
/**
|
|
72
|
+
* The option ID to render as selected in the select box.
|
|
73
|
+
*
|
|
74
|
+
* This should exactly match the option IDs passed in the `options` prop. If `null`, no option will be selected.
|
|
75
|
+
*/
|
|
76
|
+
value?: Option<T>['id'] | null;
|
|
77
|
+
/**
|
|
78
|
+
* The interaction handler for the Select.
|
|
79
|
+
*/
|
|
80
|
+
onChange?: (value: Option<T>['id'] | null) => void | Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* The visual variant of the Select. `listbox` will render as a dropdown menu, `radio` will render as a radio group, `card` will render as selectable cards, and `segmented` will render as a segmented control.
|
|
83
|
+
* @default listbox
|
|
84
|
+
*/
|
|
85
|
+
kind?: 'listbox' | 'radio' | 'card' | 'segmented';
|
|
86
|
+
multiple?: false;
|
|
87
|
+
multipleItemsName?: never;
|
|
88
|
+
} & CommonSelectProps;
|
|
89
|
+
|
|
90
|
+
export type MultiSelectProps<T = Record<string, any>> = {
|
|
91
|
+
/**
|
|
92
|
+
* Controls the text of the Multiselect button when multiple items selected, such as "All ___" or "2 ___"
|
|
93
|
+
* @default items
|
|
94
|
+
*/
|
|
95
|
+
multipleItemsName?: string;
|
|
96
|
+
/**
|
|
97
|
+
* The visual variant of the Select. For multiselect, only `listbox` is supported.
|
|
98
|
+
* @default listbox
|
|
99
|
+
*/
|
|
100
|
+
kind?: 'listbox',
|
|
101
|
+
/**
|
|
102
|
+
* Converts the single select into a multiselect.
|
|
103
|
+
*/
|
|
104
|
+
multiple: true;
|
|
105
|
+
/**
|
|
106
|
+
* For multiselect, should be a string[] that matches the option IDs passed in the `options` prop. If `null`, no option will be selected.
|
|
107
|
+
*/
|
|
108
|
+
value?: Option<T>['id'][] | null;
|
|
109
|
+
/**
|
|
110
|
+
* The interaction handler for the Select.
|
|
111
|
+
*/
|
|
112
|
+
onChange?: (value: Option<T>['id'][] | null) => void | Promise<void>;
|
|
113
|
+
} & CommonSelectProps;
|
|
114
|
+
|
|
115
|
+
type SelectProps<T = Record<string, any>> =
|
|
116
|
+
| (SingleSelectProps<T>)
|
|
117
|
+
| (MultiSelectProps<T>);
|
|
118
|
+
|
|
86
119
|
/**
|
|
87
120
|
* A Select component is used to render a `select` box.
|
|
88
121
|
*
|
|
@@ -112,10 +145,25 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
112
145
|
kind = 'listbox',
|
|
113
146
|
maxHeight = 320,
|
|
114
147
|
hasOptionBorder = false,
|
|
148
|
+
multiple = false,
|
|
149
|
+
multipleItemsName,
|
|
115
150
|
segmentedHeight = 'compact',
|
|
116
151
|
overrides,
|
|
117
152
|
}: SelectProps<T>, ref: ForwardedRef<any>) {
|
|
118
153
|
const inputID = useId();
|
|
154
|
+
const multiItems = multipleItemsName || 'items';
|
|
155
|
+
const buttonText = () => {
|
|
156
|
+
if (!value || value.length === 0) {
|
|
157
|
+
return placeholder || 'Select an option';
|
|
158
|
+
} if (!multiple) {
|
|
159
|
+
return options?.find((o) => o.id === value)?.node;
|
|
160
|
+
} if (value && value.length === 1) {
|
|
161
|
+
return options?.find((o) => o.id === value[0])?.node;
|
|
162
|
+
} if (value.length === options.length) {
|
|
163
|
+
return `All ${multiItems}`;
|
|
164
|
+
}
|
|
165
|
+
return `${value.length} ${multiItems}`;
|
|
166
|
+
};
|
|
119
167
|
return (
|
|
120
168
|
<Field
|
|
121
169
|
htmlFor={inputID}
|
|
@@ -137,6 +185,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
137
185
|
ref={ref}
|
|
138
186
|
value={value}
|
|
139
187
|
onChange={onChange}
|
|
188
|
+
multiple={multiple}
|
|
140
189
|
>
|
|
141
190
|
<Listbox.Button
|
|
142
191
|
id={inputID}
|
|
@@ -164,7 +213,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
164
213
|
)}
|
|
165
214
|
</div>
|
|
166
215
|
)}
|
|
167
|
-
{
|
|
216
|
+
{buttonText()}
|
|
168
217
|
{endEnhancer ? (
|
|
169
218
|
<div
|
|
170
219
|
{...overrides?.endEnhancerContainer}
|
|
@@ -184,13 +233,13 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
184
233
|
</Listbox.Button>
|
|
185
234
|
<Transition
|
|
186
235
|
as="div"
|
|
236
|
+
className={dropdownStyles.transitionContainer}
|
|
187
237
|
enter={dropdownStyles.transition}
|
|
188
238
|
enterFrom={dropdownStyles.enterFrom}
|
|
189
239
|
enterTo={dropdownStyles.enterTo}
|
|
190
240
|
leave={dropdownStyles.transition}
|
|
191
241
|
leaveFrom={dropdownStyles.leaveFrom}
|
|
192
242
|
leaveTo={dropdownStyles.leaveTo}
|
|
193
|
-
className={styles.transitionContainer}
|
|
194
243
|
>
|
|
195
244
|
<Listbox.Options
|
|
196
245
|
className={clsx(
|
|
@@ -205,7 +254,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
205
254
|
<Listbox.Option
|
|
206
255
|
key={option.id}
|
|
207
256
|
value={option.id}
|
|
208
|
-
data-selected={option.id === value}
|
|
257
|
+
data-selected={option.id === value || (value && value.includes(option.id))}
|
|
209
258
|
className={clsx(
|
|
210
259
|
overrides?.option,
|
|
211
260
|
styles.option,
|
|
@@ -218,7 +267,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
218
267
|
{option.node}
|
|
219
268
|
</Text>
|
|
220
269
|
) : option.node}
|
|
221
|
-
{option.id === value && (
|
|
270
|
+
{(option.id === value || (value && value.includes(option.id))) && (
|
|
222
271
|
<Icon icon={Check} size={12} />
|
|
223
272
|
)}
|
|
224
273
|
</Listbox.Option>
|