paris 0.14.2 → 0.15.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 +14 -0
- package/package.json +2 -2
- package/src/stories/checkbox/Checkbox.module.scss +44 -0
- package/src/stories/checkbox/Checkbox.stories.ts +33 -0
- package/src/stories/checkbox/Checkbox.tsx +67 -35
- package/src/stories/combobox/Combobox.stories.ts +84 -0
- package/src/stories/combobox/Combobox.tsx +21 -11
- package/src/stories/dialog/Dialog.module.scss +1 -1
- package/src/stories/dialog/Dialog.tsx +15 -15
- package/src/stories/drawer/Drawer.module.scss +1 -1
- package/src/stories/drawer/Drawer.stories.tsx +25 -25
- package/src/stories/drawer/Drawer.tsx +15 -15
- package/src/stories/menu/Menu.stories.tsx +9 -9
- package/src/stories/menu/Menu.tsx +23 -28
- package/src/stories/select/Select.module.scss +11 -15
- package/src/stories/select/Select.stories.ts +1 -1
- package/src/stories/select/Select.tsx +15 -14
- package/src/stories/tabs/Tabs.tsx +11 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# paris
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5072392: Menu: refactored from dot notation to named exports, so new MenuButton, MenuItems, and MenuItem replaces Menu.Button, etc
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 5072392: Checkbox: new `switch` kind and `hideLabel` prop
|
|
12
|
+
- 5072392: Select: multiselect listbox stays open for selecting multiple options
|
|
13
|
+
- 5072392: Combobox: options dropdown opens initially on focus, can disable with `hideOptionsInitially` prop
|
|
14
|
+
- 5072392: General: upgraded headlessui package to v2
|
|
15
|
+
- 5072392: Menu, Select, Combobox: dropdowns now render as modal, meaning page scroll is locked
|
|
16
|
+
|
|
3
17
|
## 0.14.2
|
|
4
18
|
|
|
5
19
|
### 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.15.0",
|
|
6
6
|
"homepage": "https://paris.slingshot.fm",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@fortawesome/free-regular-svg-icons": "^6.4.2",
|
|
65
65
|
"@fortawesome/free-solid-svg-icons": "^6.4.2",
|
|
66
66
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
|
67
|
-
"@headlessui/react": "^
|
|
67
|
+
"@headlessui/react": "^2.2.4",
|
|
68
68
|
"@radix-ui/react-checkbox": "^1.0.4",
|
|
69
69
|
"@radix-ui/react-tooltip": "^1.1.8",
|
|
70
70
|
"clsx": "^1.2.1",
|
|
@@ -114,3 +114,47 @@
|
|
|
114
114
|
color: var(--pte-new-colors-contentDisabled);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
.switchContainer {
|
|
119
|
+
width: 24px;
|
|
120
|
+
height: 14px;
|
|
121
|
+
border-radius: 100px;
|
|
122
|
+
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: center;
|
|
126
|
+
|
|
127
|
+
background-color: var(--pte-new-colors-contentTertiary);
|
|
128
|
+
|
|
129
|
+
&[data-checked], &[data-state="indeterminate"] {
|
|
130
|
+
background-color: var(--pte-new-colors-contentPrimary);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
&[data-disabled=true] {
|
|
134
|
+
background-color: var(--pte-new-colors-contentInverseSecondary);
|
|
135
|
+
|
|
136
|
+
&[data-checked], &[data-state="indeterminate"] {
|
|
137
|
+
background-color: var(--pte-new-colors-contentInverseTertiary);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&:hover {
|
|
142
|
+
background-color: var(--pte-new-colors-contentSecondary);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.knob {
|
|
147
|
+
width: 10px;
|
|
148
|
+
height: 10px;
|
|
149
|
+
display: inline-block;
|
|
150
|
+
border-radius: 100%;
|
|
151
|
+
|
|
152
|
+
background-color: var(--pte-new-colors-contentInversePrimary);
|
|
153
|
+
|
|
154
|
+
transform: translateX(-5px);
|
|
155
|
+
transition: transform var(--pte-animations-interaction);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.knobChecked {
|
|
159
|
+
transform: translateX(5px);
|
|
160
|
+
}
|
|
@@ -41,3 +41,36 @@ export const Surface: Story = {
|
|
|
41
41
|
});
|
|
42
42
|
},
|
|
43
43
|
};
|
|
44
|
+
|
|
45
|
+
export const Switch: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
children: 'ACH Bank Transfer',
|
|
48
|
+
kind: 'switch',
|
|
49
|
+
},
|
|
50
|
+
render: (args) => {
|
|
51
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
52
|
+
const [checked, setChecked] = useState(false);
|
|
53
|
+
return createElement(Checkbox, {
|
|
54
|
+
...args,
|
|
55
|
+
checked,
|
|
56
|
+
onChange: (e) => setChecked(!!e),
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const HideLabel: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
children: 'ACH Bank Transfer',
|
|
64
|
+
kind: 'switch',
|
|
65
|
+
hideLabel: true,
|
|
66
|
+
},
|
|
67
|
+
render: (args) => {
|
|
68
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
69
|
+
const [checked, setChecked] = useState(false);
|
|
70
|
+
return createElement(Checkbox, {
|
|
71
|
+
...args,
|
|
72
|
+
checked,
|
|
73
|
+
onChange: (e) => setChecked(!!e),
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
};
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import type { FC, ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useId } from 'react';
|
|
3
3
|
import * as RadixCheckbox from '@radix-ui/react-checkbox';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
|
+
import { Switch } from '@headlessui/react';
|
|
5
6
|
import styles from './Checkbox.module.scss';
|
|
6
|
-
import {
|
|
7
|
-
import { TextWhenString } from '../utility';
|
|
7
|
+
import { TextWhenString, VisuallyHidden } from '../utility';
|
|
8
8
|
import { Check, Icon } from '../icon';
|
|
9
9
|
|
|
10
10
|
export type CheckboxProps = {
|
|
11
|
-
/** The visual style of the Checkbox. `default` is a standard checkbox with a label next to it, `surface` is a clickable card that displays a check when selected. */
|
|
12
|
-
kind?: 'default' | 'surface'
|
|
11
|
+
/** The visual style of the Checkbox. `default` is a standard checkbox with a label next to it, `surface` is a clickable card that displays a check when selected, `switch` is a switch toggle. */
|
|
12
|
+
kind?: 'default' | 'surface' | 'switch'
|
|
13
13
|
checked?: boolean;
|
|
14
14
|
onChange?: (checked: boolean | 'indeterminate') => void;
|
|
15
15
|
disabled?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to hide the label text of the Checkbox. Does not apply to `kind="surface"` because there would be nothing visible.
|
|
18
|
+
*
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
hideLabel?: boolean;
|
|
16
22
|
/** The contents of the Checkbox. */
|
|
17
23
|
children?: ReactNode | ReactNode[];
|
|
18
24
|
} & Omit<React.ComponentPropsWithoutRef<'label'>, 'onChange' | 'children'>;
|
|
@@ -34,6 +40,7 @@ export const Checkbox: FC<CheckboxProps> = ({
|
|
|
34
40
|
checked,
|
|
35
41
|
onChange,
|
|
36
42
|
disabled,
|
|
43
|
+
hideLabel = false,
|
|
37
44
|
children,
|
|
38
45
|
className,
|
|
39
46
|
...props
|
|
@@ -45,43 +52,68 @@ export const Checkbox: FC<CheckboxProps> = ({
|
|
|
45
52
|
className={clsx(styles.container, disabled && styles.disabled, className, checked && styles.checked)}
|
|
46
53
|
{...props}
|
|
47
54
|
>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
{(kind === 'default' || kind === 'surface') && (
|
|
56
|
+
<RadixCheckbox.Root
|
|
57
|
+
id={inputID}
|
|
58
|
+
className={clsx(styles.root, styles[kind])}
|
|
59
|
+
checked={checked}
|
|
60
|
+
onCheckedChange={onChange}
|
|
61
|
+
data-disabled={disabled}
|
|
62
|
+
aria-details={typeof children === 'string' ? children : undefined}
|
|
63
|
+
>
|
|
64
|
+
{kind === 'surface' && (
|
|
65
|
+
<TextWhenString kind="paragraphXSmall">
|
|
66
|
+
{children}
|
|
67
|
+
</TextWhenString>
|
|
68
|
+
)}
|
|
69
|
+
<RadixCheckbox.Indicator className={styles.indicator}>
|
|
70
|
+
{kind === 'default' && (
|
|
71
|
+
<svg width={14} height={14} viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
72
|
+
<path
|
|
73
|
+
className={styles.checkSvg}
|
|
74
|
+
data-disabled={disabled}
|
|
75
|
+
d="M0.333374 0.333252V13.6666H13.6667V0.333252H0.333374ZM6.00004 10.3999L2.26672 6.66658L3.66671 5.26658L5.93339 7.53325L10.2 3.26658L11.6001 4.66659L6.00004 10.3999Z"
|
|
76
|
+
/>
|
|
77
|
+
</svg>
|
|
78
|
+
)}
|
|
79
|
+
{kind === 'surface' && (
|
|
80
|
+
<Icon
|
|
81
|
+
icon={Check}
|
|
82
|
+
size={12.8}
|
|
65
83
|
data-disabled={disabled}
|
|
66
|
-
|
|
84
|
+
className={styles.checkIcon}
|
|
67
85
|
/>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
86
|
+
)}
|
|
87
|
+
</RadixCheckbox.Indicator>
|
|
88
|
+
</RadixCheckbox.Root>
|
|
89
|
+
)}
|
|
90
|
+
{kind === 'switch' && (
|
|
91
|
+
<>
|
|
92
|
+
<Switch
|
|
93
|
+
checked={checked}
|
|
94
|
+
onChange={onChange}
|
|
95
|
+
className={styles.switchContainer}
|
|
96
|
+
data-disabled={disabled}
|
|
97
|
+
id={inputID}
|
|
98
|
+
aria-details={typeof children === 'string' ? children : undefined}
|
|
99
|
+
>
|
|
100
|
+
<span
|
|
101
|
+
aria-hidden="true"
|
|
102
|
+
className={clsx(styles.knob, checked && styles.knobChecked)}
|
|
76
103
|
/>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{kind === 'default' && (
|
|
104
|
+
</Switch>
|
|
105
|
+
</>
|
|
106
|
+
)}
|
|
107
|
+
{(kind === 'default' || kind === 'switch') && !hideLabel && (
|
|
81
108
|
<TextWhenString kind="paragraphXSmall">
|
|
82
109
|
{children}
|
|
83
110
|
</TextWhenString>
|
|
84
111
|
)}
|
|
112
|
+
{hideLabel && (
|
|
113
|
+
<VisuallyHidden>
|
|
114
|
+
{children}
|
|
115
|
+
</VisuallyHidden>
|
|
116
|
+
)}
|
|
85
117
|
</label>
|
|
86
118
|
);
|
|
87
119
|
};
|
|
@@ -59,6 +59,42 @@ const ComboboxArgs: ComboboxProps<{ name: string }> = {
|
|
|
59
59
|
],
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
const ComboboxArgs2: ComboboxProps<{ name: string }> = {
|
|
63
|
+
label: 'Share',
|
|
64
|
+
description: 'Search for a friend to share this document with.',
|
|
65
|
+
placeholder: 'Search...',
|
|
66
|
+
options: [
|
|
67
|
+
{
|
|
68
|
+
id: '1',
|
|
69
|
+
node: 'Mia Dolan',
|
|
70
|
+
metadata: {
|
|
71
|
+
name: 'Mia Dolan',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: '2',
|
|
76
|
+
node: 'SEB',
|
|
77
|
+
metadata: {
|
|
78
|
+
name: 'Sebastian Wilder',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: '3',
|
|
83
|
+
node: 'Amy Brandt',
|
|
84
|
+
metadata: {
|
|
85
|
+
name: 'Amy Brandt',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: '4',
|
|
90
|
+
node: 'Laura Wilder',
|
|
91
|
+
metadata: {
|
|
92
|
+
name: 'Laura Wilder',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
|
|
62
98
|
export const Default: Story = {
|
|
63
99
|
args: ComboboxArgs,
|
|
64
100
|
render: (args) => {
|
|
@@ -104,3 +140,51 @@ export const AllowCustomValue: Story = {
|
|
|
104
140
|
}));
|
|
105
141
|
},
|
|
106
142
|
};
|
|
143
|
+
|
|
144
|
+
export const HideOptionsInitially: Story = {
|
|
145
|
+
args: ComboboxArgs,
|
|
146
|
+
render: (args) => {
|
|
147
|
+
const [selected, setSelected] = useState<Option<{ name: string }> | null>(null);
|
|
148
|
+
const [inputValue, setInputValue] = useState<string>('');
|
|
149
|
+
return createElement('div', {
|
|
150
|
+
style: { minHeight: '200px' },
|
|
151
|
+
}, createElement(Combobox<{ name: string }>, {
|
|
152
|
+
...args,
|
|
153
|
+
value: (selected?.id === null) ? {
|
|
154
|
+
id: null,
|
|
155
|
+
node: inputValue,
|
|
156
|
+
metadata: {
|
|
157
|
+
name: inputValue,
|
|
158
|
+
},
|
|
159
|
+
} : selected as Option<{ name: string }> | null,
|
|
160
|
+
options: (args.options as Option<{ name: string }>[]).filter((o) => (o.metadata?.name as string || '').toLowerCase().includes(inputValue.toLowerCase())),
|
|
161
|
+
onChange: (e) => setSelected(e),
|
|
162
|
+
onInputChange: (e) => setInputValue(e),
|
|
163
|
+
hideOptionsInitially: true,
|
|
164
|
+
}));
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const HideClearButton: Story = {
|
|
169
|
+
args: ComboboxArgs2,
|
|
170
|
+
render: (args) => {
|
|
171
|
+
const [selected, setSelected] = useState<Option<{ name: string }> | null>(null);
|
|
172
|
+
const [inputValue, setInputValue] = useState<string>('');
|
|
173
|
+
return createElement('div', {
|
|
174
|
+
style: { minHeight: '200px' },
|
|
175
|
+
}, createElement(Combobox<{ name: string }>, {
|
|
176
|
+
...args,
|
|
177
|
+
value: (selected?.id === null) ? {
|
|
178
|
+
id: null,
|
|
179
|
+
node: inputValue,
|
|
180
|
+
metadata: {
|
|
181
|
+
name: inputValue,
|
|
182
|
+
},
|
|
183
|
+
} : selected as Option<{ name: string }> | null,
|
|
184
|
+
options: (args.options as Option<{ name: string }>[]).filter((o) => (o.metadata?.name as string || '').toLowerCase().includes(inputValue.toLowerCase())),
|
|
185
|
+
onChange: (e) => setSelected(e),
|
|
186
|
+
onInputChange: (e) => setInputValue(e),
|
|
187
|
+
hideClearButton: true,
|
|
188
|
+
}));
|
|
189
|
+
},
|
|
190
|
+
};
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react';
|
|
4
4
|
import {
|
|
5
|
-
Fragment,
|
|
6
|
-
|
|
7
5
|
useMemo, useId, useState,
|
|
8
6
|
} from 'react';
|
|
9
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Combobox as HCombobox, ComboboxInput, ComboboxOptions, ComboboxOption, Transition,
|
|
9
|
+
} from '@headlessui/react';
|
|
10
10
|
import clsx from 'clsx';
|
|
11
11
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
12
12
|
import { faClose } from '@fortawesome/free-solid-svg-icons';
|
|
@@ -23,6 +23,7 @@ import { Field } from '../field';
|
|
|
23
23
|
import type { ButtonProps } from '../button';
|
|
24
24
|
import { Button } from '../button';
|
|
25
25
|
import { TextWhenString } from '../utility';
|
|
26
|
+
import { Check, Icon } from '../icon';
|
|
26
27
|
|
|
27
28
|
export type Option<T extends Record<string, any> = Record<string, any>> = {
|
|
28
29
|
id: string,
|
|
@@ -97,6 +98,11 @@ export type ComboboxProps<T extends Record<string, any>> = {
|
|
|
97
98
|
* @default false
|
|
98
99
|
*/
|
|
99
100
|
hasOptionBorder?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Whether the dropdown should open immediately when focused, vs only after starting to type.
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
hideOptionsInitially?: boolean;
|
|
100
106
|
/**
|
|
101
107
|
* Prop overrides for other rendered elements. Overrides for the input itself should be passed directly to the component.
|
|
102
108
|
*/
|
|
@@ -153,6 +159,7 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
153
159
|
hideClearButton = false,
|
|
154
160
|
maxHeight = 320,
|
|
155
161
|
hasOptionBorder = false,
|
|
162
|
+
hideOptionsInitially = false,
|
|
156
163
|
overrides,
|
|
157
164
|
}: ComboboxProps<T>) {
|
|
158
165
|
const inputID = useId();
|
|
@@ -184,6 +191,7 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
184
191
|
>
|
|
185
192
|
<HCombobox
|
|
186
193
|
as="div"
|
|
194
|
+
immediate={!hideOptionsInitially}
|
|
187
195
|
value={selectedID}
|
|
188
196
|
onChange={(id) => {
|
|
189
197
|
if (onChange) {
|
|
@@ -224,7 +232,7 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
224
232
|
)}
|
|
225
233
|
<div className={styles.content}>
|
|
226
234
|
{(value?.node && typeof value.node !== 'string') ? value.node : (
|
|
227
|
-
<
|
|
235
|
+
<ComboboxInput
|
|
228
236
|
id={inputID}
|
|
229
237
|
{...overrides?.input}
|
|
230
238
|
placeholder={placeholder}
|
|
@@ -293,7 +301,8 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
293
301
|
leaveFrom={dropdownStyles.leaveFrom}
|
|
294
302
|
leaveTo={dropdownStyles.leaveTo}
|
|
295
303
|
>
|
|
296
|
-
<
|
|
304
|
+
<ComboboxOptions
|
|
305
|
+
as="ul"
|
|
297
306
|
{...overrides?.optionsContainer}
|
|
298
307
|
className={clsx(
|
|
299
308
|
overrides?.optionsContainer?.className,
|
|
@@ -305,7 +314,8 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
305
314
|
} as CSSProperties}
|
|
306
315
|
>
|
|
307
316
|
{(allowCustomValue && showCustomValueOption && !customValueToOption && query.length > 0) && (
|
|
308
|
-
<
|
|
317
|
+
<ComboboxOption
|
|
318
|
+
as="li"
|
|
309
319
|
value={query}
|
|
310
320
|
data-selected={false}
|
|
311
321
|
className={clsx(
|
|
@@ -317,18 +327,18 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
317
327
|
<Text as="span" kind="paragraphSmall">
|
|
318
328
|
{customValueString.replace('%v', query)}
|
|
319
329
|
</Text>
|
|
320
|
-
</
|
|
330
|
+
</ComboboxOption>
|
|
321
331
|
)}
|
|
322
332
|
{
|
|
323
333
|
(
|
|
324
334
|
optionsWithCustomValue || []
|
|
325
335
|
)
|
|
326
336
|
.map((option) => (
|
|
327
|
-
<
|
|
337
|
+
<ComboboxOption
|
|
338
|
+
as="li"
|
|
328
339
|
key={option.id}
|
|
329
340
|
value={option.id}
|
|
330
341
|
{...overrides?.option}
|
|
331
|
-
data-selected={option.id === value}
|
|
332
342
|
className={clsx(
|
|
333
343
|
overrides?.option?.className,
|
|
334
344
|
styles.option,
|
|
@@ -338,10 +348,10 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
338
348
|
<TextWhenString as="span" kind="paragraphSmall">
|
|
339
349
|
{option.node}
|
|
340
350
|
</TextWhenString>
|
|
341
|
-
</
|
|
351
|
+
</ComboboxOption>
|
|
342
352
|
))
|
|
343
353
|
}
|
|
344
|
-
</
|
|
354
|
+
</ComboboxOptions>
|
|
345
355
|
</Transition>
|
|
346
356
|
</HCombobox>
|
|
347
357
|
</Field>
|
|
@@ -17,7 +17,7 @@ $panelAnimationDelay: var(--pte-animations-duration-fast);
|
|
|
17
17
|
transition: var(--pte-animations-duration-normal) var(--pte-animations-timing-easeInOut);
|
|
18
18
|
|
|
19
19
|
&.overlayBlur {
|
|
20
|
-
backdrop-filter: blur(
|
|
20
|
+
backdrop-filter: blur(2px);
|
|
21
21
|
background-color: var(--pte-new-colors-overlayPageBackground);
|
|
22
22
|
will-change: backdrop-filter, opacity;
|
|
23
23
|
}
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
import type {
|
|
4
4
|
ComponentPropsWithoutRef, FC, MouseEventHandler, PropsWithChildren, ReactNode,
|
|
5
5
|
} from 'react';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { useEffect, useState } from 'react';
|
|
7
|
+
import {
|
|
8
|
+
Dialog as HDialog, DialogPanel, DialogTitle, Transition, TransitionChild,
|
|
9
|
+
} from '@headlessui/react';
|
|
8
10
|
import clsx from 'clsx';
|
|
9
11
|
import styles from './Dialog.module.scss';
|
|
10
12
|
import { Text } from '../text';
|
|
@@ -166,7 +168,6 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
166
168
|
<Transition
|
|
167
169
|
appear
|
|
168
170
|
show={isOpen}
|
|
169
|
-
as={Fragment}
|
|
170
171
|
>
|
|
171
172
|
<HDialog
|
|
172
173
|
as="div"
|
|
@@ -176,8 +177,9 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
176
177
|
styles.root,
|
|
177
178
|
overrides.root?.className,
|
|
178
179
|
)}
|
|
180
|
+
role="dialog"
|
|
179
181
|
>
|
|
180
|
-
<
|
|
182
|
+
<div
|
|
181
183
|
{...overrides.overlayContainer}
|
|
182
184
|
className={clsx(
|
|
183
185
|
overlayStyle === 'blur' && styles.overlayBlurContainer,
|
|
@@ -185,8 +187,7 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
185
187
|
overrides.overlayContainer?.className,
|
|
186
188
|
)}
|
|
187
189
|
>
|
|
188
|
-
<
|
|
189
|
-
as={Fragment}
|
|
190
|
+
<TransitionChild
|
|
190
191
|
enter={styles.enter}
|
|
191
192
|
enterFrom={styles.enterFrom}
|
|
192
193
|
enterTo={styles.enterTo}
|
|
@@ -203,8 +204,8 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
203
204
|
overrides.overlay?.className,
|
|
204
205
|
)}
|
|
205
206
|
/>
|
|
206
|
-
</
|
|
207
|
-
</
|
|
207
|
+
</TransitionChild>
|
|
208
|
+
</div>
|
|
208
209
|
|
|
209
210
|
<div
|
|
210
211
|
{...overrides.panelContainer}
|
|
@@ -213,8 +214,7 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
213
214
|
overrides.panelContainer?.className,
|
|
214
215
|
)}
|
|
215
216
|
>
|
|
216
|
-
<
|
|
217
|
-
as={Fragment}
|
|
217
|
+
<TransitionChild
|
|
218
218
|
enter={styles.enter}
|
|
219
219
|
enterFrom={styles.enterFrom}
|
|
220
220
|
enterTo={styles.enterTo}
|
|
@@ -222,7 +222,7 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
222
222
|
leaveFrom={styles.leaveFrom}
|
|
223
223
|
leaveTo={styles.leaveTo}
|
|
224
224
|
>
|
|
225
|
-
<
|
|
225
|
+
<DialogPanel
|
|
226
226
|
{...overrides.panel}
|
|
227
227
|
className={clsx(
|
|
228
228
|
styles.panel,
|
|
@@ -248,7 +248,7 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
248
248
|
} : {}}
|
|
249
249
|
>
|
|
250
250
|
<VisuallyHidden when={hideTitle}>
|
|
251
|
-
<
|
|
251
|
+
<DialogTitle
|
|
252
252
|
{...overrides.panelTitle}
|
|
253
253
|
as="h1"
|
|
254
254
|
className={clsx(
|
|
@@ -261,7 +261,7 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
261
261
|
>
|
|
262
262
|
{title}
|
|
263
263
|
</TextWhenString>
|
|
264
|
-
</
|
|
264
|
+
</DialogTitle>
|
|
265
265
|
</VisuallyHidden>
|
|
266
266
|
<RemoveFromDOM when={hideCloseButton}>
|
|
267
267
|
<div className={clsx(styles.closeButton)}>
|
|
@@ -285,8 +285,8 @@ export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
|
285
285
|
</div>
|
|
286
286
|
</VisuallyHidden>
|
|
287
287
|
{children}
|
|
288
|
-
</
|
|
289
|
-
</
|
|
288
|
+
</DialogPanel>
|
|
289
|
+
</TransitionChild>
|
|
290
290
|
</div>
|
|
291
291
|
</HDialog>
|
|
292
292
|
</Transition>
|
|
@@ -27,7 +27,7 @@ $panelAnimationDelay: var(--pte-animations-duration-fast);
|
|
|
27
27
|
inset: 0;
|
|
28
28
|
|
|
29
29
|
&.overlayBlur {
|
|
30
|
-
backdrop-filter: blur(
|
|
30
|
+
backdrop-filter: blur(2px);
|
|
31
31
|
background-color: var(--pte-new-colors-overlayPageBackground);
|
|
32
32
|
will-change: backdrop-filter, opacity;
|
|
33
33
|
}
|
|
@@ -6,7 +6,7 @@ import { Drawer } from './Drawer';
|
|
|
6
6
|
import { Button } from '../button';
|
|
7
7
|
import { Callout } from '../callout';
|
|
8
8
|
import {
|
|
9
|
-
Menu,
|
|
9
|
+
Menu, MenuButton, MenuItems, MenuItem,
|
|
10
10
|
} from '../menu';
|
|
11
11
|
import { usePagination } from '../pagination';
|
|
12
12
|
import { ChevronRight, Ellipsis } from '../icon';
|
|
@@ -41,7 +41,7 @@ export const Default: Story = {
|
|
|
41
41
|
onClose={setIsOpen}
|
|
42
42
|
additionalActions={(
|
|
43
43
|
<Menu as="div">
|
|
44
|
-
<
|
|
44
|
+
<MenuButton>
|
|
45
45
|
<Button
|
|
46
46
|
kind="tertiary"
|
|
47
47
|
shape="circle"
|
|
@@ -51,16 +51,16 @@ export const Default: Story = {
|
|
|
51
51
|
>
|
|
52
52
|
Action menu
|
|
53
53
|
</Button>
|
|
54
|
-
</
|
|
55
|
-
<
|
|
56
|
-
<
|
|
54
|
+
</MenuButton>
|
|
55
|
+
<MenuItems position="right">
|
|
56
|
+
<MenuItem as="button">
|
|
57
57
|
Dispute
|
|
58
|
-
</
|
|
59
|
-
<
|
|
58
|
+
</MenuItem>
|
|
59
|
+
<MenuItem as="button">
|
|
60
60
|
Transfer
|
|
61
61
|
<ChevronRight size={20} />
|
|
62
|
-
</
|
|
63
|
-
</
|
|
62
|
+
</MenuItem>
|
|
63
|
+
</MenuItems>
|
|
64
64
|
</Menu>
|
|
65
65
|
)}
|
|
66
66
|
>
|
|
@@ -101,7 +101,7 @@ export const Paginated: Story = {
|
|
|
101
101
|
title={currentPageTitle}
|
|
102
102
|
additionalActions={(
|
|
103
103
|
<Menu as="div">
|
|
104
|
-
<
|
|
104
|
+
<MenuButton>
|
|
105
105
|
<Button
|
|
106
106
|
kind="tertiary"
|
|
107
107
|
shape="circle"
|
|
@@ -111,16 +111,16 @@ export const Paginated: Story = {
|
|
|
111
111
|
>
|
|
112
112
|
Action menu
|
|
113
113
|
</Button>
|
|
114
|
-
</
|
|
115
|
-
<
|
|
116
|
-
<
|
|
114
|
+
</MenuButton>
|
|
115
|
+
<MenuItems position="right">
|
|
116
|
+
<MenuItem as="button">
|
|
117
117
|
Dispute
|
|
118
|
-
</
|
|
119
|
-
<
|
|
118
|
+
</MenuItem>
|
|
119
|
+
<MenuItem as="button">
|
|
120
120
|
Transfer
|
|
121
121
|
<ChevronRight size={20} />
|
|
122
|
-
</
|
|
123
|
-
</
|
|
122
|
+
</MenuItem>
|
|
123
|
+
</MenuItems>
|
|
124
124
|
</Menu>
|
|
125
125
|
)}
|
|
126
126
|
>
|
|
@@ -222,7 +222,7 @@ export const BottomPanel: Story = {
|
|
|
222
222
|
onClose={setIsOpen}
|
|
223
223
|
additionalActions={(
|
|
224
224
|
<Menu as="div">
|
|
225
|
-
<
|
|
225
|
+
<MenuButton>
|
|
226
226
|
<Button
|
|
227
227
|
kind="tertiary"
|
|
228
228
|
shape="circle"
|
|
@@ -232,16 +232,16 @@ export const BottomPanel: Story = {
|
|
|
232
232
|
>
|
|
233
233
|
Action menu
|
|
234
234
|
</Button>
|
|
235
|
-
</
|
|
236
|
-
<
|
|
237
|
-
<
|
|
235
|
+
</MenuButton>
|
|
236
|
+
<MenuItems position="right">
|
|
237
|
+
<MenuItem as="button">
|
|
238
238
|
Dispute
|
|
239
|
-
</
|
|
240
|
-
<
|
|
239
|
+
</MenuItem>
|
|
240
|
+
<MenuItem as="button">
|
|
241
241
|
Transfer
|
|
242
242
|
<ChevronRight size={20} />
|
|
243
|
-
</
|
|
244
|
-
</
|
|
243
|
+
</MenuItem>
|
|
244
|
+
</MenuItems>
|
|
245
245
|
</Menu>
|
|
246
246
|
)}
|
|
247
247
|
>
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import type { ReactNode, ComponentPropsWithoutRef } from 'react';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
useRef, Fragment, useMemo, useState,
|
|
5
|
+
useMemo, useState,
|
|
7
6
|
} from 'react';
|
|
8
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Dialog, DialogPanel, DialogTitle, Transition, TransitionChild,
|
|
9
|
+
} from '@headlessui/react';
|
|
9
10
|
import clsx from 'clsx';
|
|
10
11
|
import type { CSSLength } from '@ssh/csstypes';
|
|
11
12
|
import styles from './Drawer.module.scss';
|
|
@@ -205,7 +206,7 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
205
206
|
}, [children, pagination]);
|
|
206
207
|
|
|
207
208
|
return (
|
|
208
|
-
<Transition show={isOpen}
|
|
209
|
+
<Transition show={isOpen}>
|
|
209
210
|
<Dialog
|
|
210
211
|
as="div"
|
|
211
212
|
className={clsx(
|
|
@@ -214,6 +215,7 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
214
215
|
)}
|
|
215
216
|
onClose={onClose}
|
|
216
217
|
{...overrides?.dialog}
|
|
218
|
+
role="dialog"
|
|
217
219
|
>
|
|
218
220
|
<div
|
|
219
221
|
className={clsx(
|
|
@@ -222,8 +224,7 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
222
224
|
overrides?.overlay?.className,
|
|
223
225
|
)}
|
|
224
226
|
>
|
|
225
|
-
<
|
|
226
|
-
as={Fragment}
|
|
227
|
+
<TransitionChild
|
|
227
228
|
enter={styles.enter}
|
|
228
229
|
enterFrom={styles.enterFrom}
|
|
229
230
|
enterTo={styles.enterTo}
|
|
@@ -231,14 +232,14 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
231
232
|
leaveFrom={styles.leaveFrom}
|
|
232
233
|
leaveTo={styles.leaveTo}
|
|
233
234
|
>
|
|
234
|
-
<
|
|
235
|
+
<div
|
|
235
236
|
className={clsx(
|
|
236
237
|
styles.overlay,
|
|
237
238
|
overlayStyle === 'blur' && styles.overlayBlur,
|
|
238
239
|
overlayStyle === 'grey' && styles.overlayGrey,
|
|
239
240
|
)}
|
|
240
241
|
/>
|
|
241
|
-
</
|
|
242
|
+
</TransitionChild>
|
|
242
243
|
</div>
|
|
243
244
|
|
|
244
245
|
<div
|
|
@@ -254,8 +255,7 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
254
255
|
} : overrides?.panelContainer?.style}
|
|
255
256
|
{...overrides?.panelContainer}
|
|
256
257
|
>
|
|
257
|
-
<
|
|
258
|
-
as={Fragment}
|
|
258
|
+
<TransitionChild
|
|
259
259
|
enter={styles.enter}
|
|
260
260
|
enterFrom={styles.enterFrom}
|
|
261
261
|
enterTo={styles.enterTo}
|
|
@@ -263,7 +263,7 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
263
263
|
leaveFrom={styles.leaveFrom}
|
|
264
264
|
leaveTo={styles.leaveTo}
|
|
265
265
|
>
|
|
266
|
-
<
|
|
266
|
+
<DialogPanel
|
|
267
267
|
className={clsx(
|
|
268
268
|
styles.panel,
|
|
269
269
|
styles[`from-${from}`],
|
|
@@ -316,11 +316,11 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
316
316
|
// Hide when requested, or when pagination is enabled (the title isn't relevant to any specific page).
|
|
317
317
|
when={hideTitle}
|
|
318
318
|
>
|
|
319
|
-
<
|
|
319
|
+
<DialogTitle as="h2" className={styles.titleTextContainer}>
|
|
320
320
|
<TextWhenString kind="paragraphSmall" weight="medium">
|
|
321
321
|
{title}
|
|
322
322
|
</TextWhenString>
|
|
323
|
-
</
|
|
323
|
+
</DialogTitle>
|
|
324
324
|
</VisuallyHidden>
|
|
325
325
|
</div>
|
|
326
326
|
<div className={clsx(styles.titleBarButtons, overrides?.titleBarButtons?.className)}>
|
|
@@ -389,8 +389,8 @@ export const Drawer = <T extends string[] | readonly string[] = string[]>({
|
|
|
389
389
|
</>
|
|
390
390
|
)}
|
|
391
391
|
</div>
|
|
392
|
-
</
|
|
393
|
-
</
|
|
392
|
+
</DialogPanel>
|
|
393
|
+
</TransitionChild>
|
|
394
394
|
</div>
|
|
395
395
|
</Dialog>
|
|
396
396
|
</Transition>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import {
|
|
3
|
-
Menu,
|
|
3
|
+
Menu, MenuButton, MenuItems, MenuItem,
|
|
4
4
|
} from './Menu';
|
|
5
5
|
import { Button } from '../button';
|
|
6
6
|
import { ChevronRight, Ellipsis } from '../icon';
|
|
@@ -21,7 +21,7 @@ export const Default: Story = {
|
|
|
21
21
|
render: (args) => (
|
|
22
22
|
<div style={{ height: '150px' }}>
|
|
23
23
|
<Menu as="div">
|
|
24
|
-
<
|
|
24
|
+
<MenuButton>
|
|
25
25
|
<Button
|
|
26
26
|
kind="tertiary"
|
|
27
27
|
shape="circle"
|
|
@@ -31,16 +31,16 @@ export const Default: Story = {
|
|
|
31
31
|
>
|
|
32
32
|
Action menu
|
|
33
33
|
</Button>
|
|
34
|
-
</
|
|
35
|
-
<
|
|
36
|
-
<
|
|
34
|
+
</MenuButton>
|
|
35
|
+
<MenuItems>
|
|
36
|
+
<MenuItem as="button">
|
|
37
37
|
Dispute
|
|
38
|
-
</
|
|
39
|
-
<
|
|
38
|
+
</MenuItem>
|
|
39
|
+
<MenuItem as="button">
|
|
40
40
|
Transfer
|
|
41
41
|
<ChevronRight size={20} />
|
|
42
|
-
</
|
|
43
|
-
</
|
|
42
|
+
</MenuItem>
|
|
43
|
+
</MenuItems>
|
|
44
44
|
</Menu>
|
|
45
45
|
</div>
|
|
46
46
|
),
|
|
@@ -1,42 +1,33 @@
|
|
|
1
1
|
import type { FC } from 'react';
|
|
2
|
-
import { Fragment, ReactNode } from 'react';
|
|
3
2
|
import type {
|
|
4
3
|
MenuProps, MenuItemsProps, MenuItemProps, MenuButtonProps,
|
|
5
4
|
} from '@headlessui/react';
|
|
6
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Menu as HeadlessMenu, MenuButton as HMenuButton, MenuItems as HMenuItems, MenuItem as HMenuItem, Transition,
|
|
7
|
+
} from '@headlessui/react';
|
|
7
8
|
import clsx from 'clsx';
|
|
8
9
|
|
|
9
10
|
import styles from './Menu.module.scss';
|
|
10
11
|
import dropdownStyles from '../utility/Dropdown.module.scss';
|
|
11
12
|
|
|
12
|
-
export { Menu as HeadlessMenu } from '@headlessui/react';
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* Wraps the `HeadlessMenu` component from `@headlessui/react` to provide a styled dropdown menu.
|
|
16
15
|
*
|
|
17
|
-
* This component serves as the root of the menu and should wrap `
|
|
16
|
+
* This component serves as the root of the menu and should wrap `MenuButton`, `MenuItems`, and `MenuItem` components.
|
|
18
17
|
*
|
|
19
18
|
* Usage:
|
|
20
19
|
*
|
|
21
20
|
* ```tsx
|
|
22
21
|
* <Menu>
|
|
23
|
-
* <
|
|
24
|
-
* <
|
|
25
|
-
* <
|
|
26
|
-
* <
|
|
27
|
-
* </
|
|
22
|
+
* <MenuButton>Options</MenuButton>
|
|
23
|
+
* <MenuItems>
|
|
24
|
+
* <MenuItem>Item 1</MenuItem>
|
|
25
|
+
* <MenuItem>Item 2</MenuItem>
|
|
26
|
+
* </MenuItems>
|
|
28
27
|
* </Menu>
|
|
29
28
|
* ```
|
|
30
29
|
*/
|
|
31
|
-
export const Menu: FC<MenuProps<React.ElementType>>
|
|
32
|
-
Button: FC<MenuButtonProps<React.ElementType>>;
|
|
33
|
-
Items: FC<MenuItemsProps<React.ElementType> & {
|
|
34
|
-
position?: 'left' | 'right';
|
|
35
|
-
}>;
|
|
36
|
-
Item: FC<MenuItemProps<React.ElementType> & {
|
|
37
|
-
isNew?: boolean;
|
|
38
|
-
}>;
|
|
39
|
-
} = ({ className, children, ...props }) => (
|
|
30
|
+
export const Menu: FC<MenuProps<React.ElementType>> = ({ className, children, ...props }) => (
|
|
40
31
|
<HeadlessMenu as="div" className={clsx(styles.menu, className)} {...props}>
|
|
41
32
|
{children}
|
|
42
33
|
</HeadlessMenu>
|
|
@@ -47,10 +38,10 @@ export const Menu: FC<MenuProps<React.ElementType>> & {
|
|
|
47
38
|
*
|
|
48
39
|
* Should be used inside a `Menu` component to serve as the toggle for `MenuItems`.
|
|
49
40
|
*/
|
|
50
|
-
|
|
51
|
-
<
|
|
41
|
+
export const MenuButton: FC<MenuButtonProps<React.ElementType>> = ({ className, children, ...props }) => (
|
|
42
|
+
<HMenuButton className={clsx(styles.menuButton, className)} {...props}>
|
|
52
43
|
{children}
|
|
53
|
-
</
|
|
44
|
+
</HMenuButton>
|
|
54
45
|
);
|
|
55
46
|
|
|
56
47
|
/**
|
|
@@ -60,7 +51,9 @@ Menu.Button = ({ className, children, ...props }) => (
|
|
|
60
51
|
*
|
|
61
52
|
* @param position - Controls the positioning of the menu items ('left' or 'right').
|
|
62
53
|
*/
|
|
63
|
-
|
|
54
|
+
export const MenuItems: FC<MenuItemsProps<React.ElementType> & {
|
|
55
|
+
position?: 'left' | 'right';
|
|
56
|
+
}> = ({
|
|
64
57
|
className, children, position = 'left', ...props
|
|
65
58
|
}) => (
|
|
66
59
|
<Transition
|
|
@@ -73,9 +66,9 @@ Menu.Items = ({
|
|
|
73
66
|
leaveFrom={dropdownStyles.leaveFrom}
|
|
74
67
|
leaveTo={dropdownStyles.leaveTo}
|
|
75
68
|
>
|
|
76
|
-
<
|
|
69
|
+
<HMenuItems className={clsx(styles.menuItems, position === 'left' && styles.leftPosition, position === 'right' && styles.rightPosition, className)} {...props}>
|
|
77
70
|
{children}
|
|
78
|
-
</
|
|
71
|
+
</HMenuItems>
|
|
79
72
|
</Transition>
|
|
80
73
|
);
|
|
81
74
|
|
|
@@ -86,10 +79,12 @@ Menu.Items = ({
|
|
|
86
79
|
*
|
|
87
80
|
* @param isNew - Whether the menu items should be styled as new items.
|
|
88
81
|
*/
|
|
89
|
-
|
|
82
|
+
export const MenuItem: FC<MenuItemProps<React.ElementType> & {
|
|
83
|
+
isNew?: boolean;
|
|
84
|
+
}> = ({
|
|
90
85
|
className, children, isNew = false, ...props
|
|
91
86
|
}) => (
|
|
92
|
-
<
|
|
87
|
+
<HMenuItem className={clsx(styles.menuItem, isNew && styles.newItem, className)} {...props}>
|
|
93
88
|
{children}
|
|
94
|
-
</
|
|
89
|
+
</HMenuItem>
|
|
95
90
|
);
|
|
@@ -66,15 +66,15 @@
|
|
|
66
66
|
|
|
67
67
|
transition: var(--pte-animations-interaction);
|
|
68
68
|
|
|
69
|
-
&[data-selected
|
|
69
|
+
&[data-selected] {
|
|
70
70
|
background-color: var(--pte-new-colors-overlaySubtle);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
&:hover, &[data-
|
|
73
|
+
&:hover, &[data-active], &[data-focus] {
|
|
74
74
|
background-color: var(--pte-new-colors-overlayMedium);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
&[data-status="disabled"], &[data-
|
|
77
|
+
&[data-status="disabled"], &[data-disabled] {
|
|
78
78
|
pointer-events: none;
|
|
79
79
|
cursor: default;
|
|
80
80
|
|
|
@@ -110,19 +110,19 @@
|
|
|
110
110
|
justify-content: flex-start;
|
|
111
111
|
align-items: center;
|
|
112
112
|
|
|
113
|
-
&[data-
|
|
113
|
+
&[data-focus] {
|
|
114
114
|
.radioCircle {
|
|
115
115
|
border-color: var(--pte-new-colors-contentPrimary);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
&[data-
|
|
119
|
+
&[data-checked] {
|
|
120
120
|
.radioCircle {
|
|
121
121
|
border: 5px solid var(--pte-new-colors-contentPrimary);
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
&[data-status="disabled"], &[data-
|
|
125
|
+
&[data-status="disabled"], &[data-disabled] {
|
|
126
126
|
pointer-events: none;
|
|
127
127
|
cursor: default;
|
|
128
128
|
|
|
@@ -171,21 +171,21 @@
|
|
|
171
171
|
border-radius: 6px;
|
|
172
172
|
width: 100%;
|
|
173
173
|
|
|
174
|
-
&[data-
|
|
174
|
+
&[data-focus] {
|
|
175
175
|
//.cardSurface {
|
|
176
176
|
// background-color: var(--pte-new-colors-overlayWhiteSubtle);
|
|
177
177
|
// border-color: var(--pte-new-colors-borderStrong);
|
|
178
178
|
//}
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
&[data-
|
|
181
|
+
&[data-checked] {
|
|
182
182
|
.cardSurface {
|
|
183
183
|
background-color: var(--pte-new-colors-overlayMedium);
|
|
184
184
|
border-color: var(--pte-new-colors-borderUltrastrong);
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
&[data-status="disabled"], &[data-
|
|
188
|
+
&[data-status="disabled"], &[data-disabled] {
|
|
189
189
|
pointer-events: none;
|
|
190
190
|
cursor: default;
|
|
191
191
|
|
|
@@ -262,11 +262,7 @@
|
|
|
262
262
|
padding: 6px 20px;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
&[data-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
&[data-status="disabled"], &[data-headlessui-state~="disabled"] {
|
|
265
|
+
&[data-status="disabled"], &[data-disabled] {
|
|
270
266
|
pointer-events: none;
|
|
271
267
|
cursor: default;
|
|
272
268
|
|
|
@@ -284,7 +280,7 @@
|
|
|
284
280
|
color: var(--pte-new-colors-contentPrimary);
|
|
285
281
|
}
|
|
286
282
|
|
|
287
|
-
&[data-
|
|
283
|
+
&[data-checked] {
|
|
288
284
|
color: var(--pte-new-colors-contentPrimary);
|
|
289
285
|
}
|
|
290
286
|
}
|
|
@@ -6,7 +6,9 @@ import type {
|
|
|
6
6
|
CSSProperties, ComponentPropsWithoutRef, ForwardedRef, ReactNode,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import { forwardRef, useId } from 'react';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
Listbox, ListboxButton, ListboxOptions, ListboxOption, RadioGroup, Radio, Transition,
|
|
11
|
+
} from '@headlessui/react';
|
|
10
12
|
import clsx from 'clsx';
|
|
11
13
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
12
14
|
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
|
@@ -187,7 +189,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
187
189
|
onChange={onChange}
|
|
188
190
|
multiple={multiple}
|
|
189
191
|
>
|
|
190
|
-
<
|
|
192
|
+
<ListboxButton
|
|
191
193
|
id={inputID}
|
|
192
194
|
{...overrides?.selectInput}
|
|
193
195
|
aria-disabled={disabled}
|
|
@@ -230,7 +232,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
230
232
|
) : (
|
|
231
233
|
<FontAwesomeIcon className={clsx(inputStyles.enhancer, styles.chevron)} data-status={disabled ? 'disabled' : (status || 'default')} width="10px" icon={faChevronDown} />
|
|
232
234
|
)}
|
|
233
|
-
</
|
|
235
|
+
</ListboxButton>
|
|
234
236
|
<Transition
|
|
235
237
|
as="div"
|
|
236
238
|
className={dropdownStyles.transitionContainer}
|
|
@@ -241,7 +243,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
241
243
|
leaveFrom={dropdownStyles.leaveFrom}
|
|
242
244
|
leaveTo={dropdownStyles.leaveTo}
|
|
243
245
|
>
|
|
244
|
-
<
|
|
246
|
+
<ListboxOptions
|
|
245
247
|
className={clsx(
|
|
246
248
|
overrides?.optionsContainer,
|
|
247
249
|
styles.options,
|
|
@@ -251,10 +253,9 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
251
253
|
} as CSSProperties}
|
|
252
254
|
>
|
|
253
255
|
{(options || []).map((option) => (
|
|
254
|
-
<
|
|
256
|
+
<ListboxOption
|
|
255
257
|
key={option.id}
|
|
256
258
|
value={option.id}
|
|
257
|
-
data-selected={option.id === value || (value && value.includes(option.id))}
|
|
258
259
|
className={clsx(
|
|
259
260
|
overrides?.option,
|
|
260
261
|
styles.option,
|
|
@@ -270,16 +271,16 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
270
271
|
{(option.id === value || (value && value.includes(option.id))) && (
|
|
271
272
|
<Icon icon={Check} size={12} />
|
|
272
273
|
)}
|
|
273
|
-
</
|
|
274
|
+
</ListboxOption>
|
|
274
275
|
))}
|
|
275
|
-
</
|
|
276
|
+
</ListboxOptions>
|
|
276
277
|
</Transition>
|
|
277
278
|
</Listbox>
|
|
278
279
|
)}
|
|
279
280
|
{kind === 'radio' && (
|
|
280
281
|
<RadioGroup ref={ref} as="div" className={styles.radioContainer} value={value} onChange={onChange}>
|
|
281
282
|
{options.map((option) => (
|
|
282
|
-
<
|
|
283
|
+
<Radio
|
|
283
284
|
as="div"
|
|
284
285
|
className={clsx(
|
|
285
286
|
styles.radioOption,
|
|
@@ -293,14 +294,14 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
293
294
|
<TextWhenString kind="paragraphXSmall">
|
|
294
295
|
{option.node}
|
|
295
296
|
</TextWhenString>
|
|
296
|
-
</
|
|
297
|
+
</Radio>
|
|
297
298
|
))}
|
|
298
299
|
</RadioGroup>
|
|
299
300
|
)}
|
|
300
301
|
{kind === 'card' && (
|
|
301
302
|
<RadioGroup ref={ref} as="div" className={styles.cardContainer} value={value} onChange={onChange}>
|
|
302
303
|
{options.map((option) => (
|
|
303
|
-
<
|
|
304
|
+
<Radio
|
|
304
305
|
as="div"
|
|
305
306
|
className={clsx(
|
|
306
307
|
styles.cardOption,
|
|
@@ -315,14 +316,14 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
315
316
|
{option.node}
|
|
316
317
|
</TextWhenString>
|
|
317
318
|
</div>
|
|
318
|
-
</
|
|
319
|
+
</Radio>
|
|
319
320
|
))}
|
|
320
321
|
</RadioGroup>
|
|
321
322
|
)}
|
|
322
323
|
{kind === 'segmented' && (
|
|
323
324
|
<RadioGroup ref={ref} as="div" className={styles.segmentedContainer} value={value || options[0].id} onChange={onChange}>
|
|
324
325
|
{options.map((option) => (
|
|
325
|
-
<
|
|
326
|
+
<Radio
|
|
326
327
|
as="div"
|
|
327
328
|
className={clsx(
|
|
328
329
|
styles.segmentedOption,
|
|
@@ -346,7 +347,7 @@ export const Select = forwardRef(function <T = Record<string, any>>({
|
|
|
346
347
|
<TextWhenString kind="paragraphXSmall" weight="medium" className={styles.segmentedText}>
|
|
347
348
|
{option.node}
|
|
348
349
|
</TextWhenString>
|
|
349
|
-
</
|
|
350
|
+
</Radio>
|
|
350
351
|
))}
|
|
351
352
|
</RadioGroup>
|
|
352
353
|
)}
|
|
@@ -5,7 +5,9 @@ import type {
|
|
|
5
5
|
} from 'react';
|
|
6
6
|
import { useId, useState } from 'react';
|
|
7
7
|
import type { TabGroupProps, TabPanelProps, TabProps } from '@headlessui/react';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Tab, TabGroup, TabList, TabPanels, TabPanel,
|
|
10
|
+
} from '@headlessui/react';
|
|
9
11
|
import clsx from 'clsx';
|
|
10
12
|
import type { CSSLength } from '@ssh/csstypes';
|
|
11
13
|
import { motion } from 'framer-motion';
|
|
@@ -99,7 +101,7 @@ export const Tabs: FC<TabsProps> = ({
|
|
|
99
101
|
const [selectedIndex, setSelectedIndex] = useState(defaultIndex);
|
|
100
102
|
|
|
101
103
|
return (
|
|
102
|
-
<
|
|
104
|
+
<TabGroup
|
|
103
105
|
as="div"
|
|
104
106
|
selectedIndex={index ?? selectedIndex}
|
|
105
107
|
onChange={(i) => {
|
|
@@ -121,7 +123,7 @@ export const Tabs: FC<TabsProps> = ({
|
|
|
121
123
|
<div className={styles.glassBlend} />
|
|
122
124
|
</div>
|
|
123
125
|
)}
|
|
124
|
-
<
|
|
126
|
+
<TabList
|
|
125
127
|
{...overrides?.tabList}
|
|
126
128
|
style={{
|
|
127
129
|
'--tab-width': tabWidth,
|
|
@@ -160,19 +162,19 @@ export const Tabs: FC<TabsProps> = ({
|
|
|
160
162
|
))}
|
|
161
163
|
|
|
162
164
|
{/* <div key={`${id}-tab-active-border`} className={styles.activeTabBorder} /> */}
|
|
163
|
-
</
|
|
165
|
+
</TabList>
|
|
164
166
|
<div
|
|
165
167
|
{...overrides?.tabListBorder}
|
|
166
168
|
className={clsx(styles.tabListBorder, styles[barStyle], overrides?.tabListBorder?.className)}
|
|
167
169
|
/>
|
|
168
170
|
</div>
|
|
169
171
|
|
|
170
|
-
<
|
|
172
|
+
<TabPanels
|
|
171
173
|
{...overrides?.panelContainer}
|
|
172
174
|
className={clsx(styles.tabPanels, styles[backgroundStyle], overrides?.panelContainer?.className)}
|
|
173
175
|
>
|
|
174
176
|
{tabs.map(({ title, content }) => (
|
|
175
|
-
<
|
|
177
|
+
<TabPanel
|
|
176
178
|
key={`${id}-tab-${title}-content`}
|
|
177
179
|
{...overrides?.panel}
|
|
178
180
|
className={clsx(
|
|
@@ -184,9 +186,9 @@ export const Tabs: FC<TabsProps> = ({
|
|
|
184
186
|
)}
|
|
185
187
|
>
|
|
186
188
|
{content}
|
|
187
|
-
</
|
|
189
|
+
</TabPanel>
|
|
188
190
|
))}
|
|
189
|
-
</
|
|
190
|
-
</
|
|
191
|
+
</TabPanels>
|
|
192
|
+
</TabGroup>
|
|
191
193
|
);
|
|
192
194
|
};
|