paris 0.21.1 → 0.21.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# paris
|
|
2
2
|
|
|
3
|
+
## 0.21.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d4b6239: fix(select,combobox): fix portaled dropdown width and alignment
|
|
8
|
+
|
|
9
|
+
- Use correct CSS variables (`--button-width`, `--input-width`) for portaled dropdown width in Select and Combobox since Headless UI v2.2.x no longer sets `--anchor-width`
|
|
10
|
+
- Measure actual pixel offset between container and input to align Combobox dropdown with the input container, not the input element
|
|
11
|
+
- Prevent `ComboboxButton` wrapper from intercepting keyboard events (e.g. space key) meant for the input
|
|
12
|
+
|
|
13
|
+
## 0.21.2
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 61edbc8: Fix portaled dropdowns (Select, Menu, Combobox) not appearing inside Drawers and Dialogs by moving the dropdown z-index layer (350) above the overlay layer (300).
|
|
18
|
+
|
|
3
19
|
## 0.21.1
|
|
4
20
|
|
|
5
21
|
### 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.21.
|
|
5
|
+
"version": "0.21.3",
|
|
6
6
|
"homepage": "https://paris.slingshot.fm",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import { faClose } from '@fortawesome/free-solid-svg-icons';
|
|
4
4
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ComboboxButton,
|
|
7
|
+
ComboboxInput,
|
|
8
|
+
ComboboxOption,
|
|
9
|
+
ComboboxOptions,
|
|
10
|
+
Combobox as HCombobox,
|
|
11
|
+
} from '@headlessui/react';
|
|
6
12
|
import { clsx } from 'clsx';
|
|
7
|
-
import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react';
|
|
8
|
-
import { useId, useMemo, useState } from 'react';
|
|
13
|
+
import type { ComponentPropsWithoutRef, CSSProperties, MouseEvent, ReactNode } from 'react';
|
|
14
|
+
import { useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
9
15
|
import { MemoizedEnhancer } from '../../helpers/renderEnhancer';
|
|
10
16
|
import type { ButtonProps } from '../button';
|
|
11
17
|
import { Button } from '../button';
|
|
@@ -162,6 +168,25 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
162
168
|
const inputID = useId();
|
|
163
169
|
const [selectedID, setSelectedID] = useState<string | null>(value?.id || null);
|
|
164
170
|
const [query, setQuery] = useState('');
|
|
171
|
+
const containerElRef = useRef<HTMLElement | null>(null);
|
|
172
|
+
const inputElRef = useRef<HTMLElement | null>(null);
|
|
173
|
+
const [anchorOffset, setAnchorOffset] = useState(0);
|
|
174
|
+
|
|
175
|
+
const containerRef = useCallback((node: HTMLButtonElement | null) => {
|
|
176
|
+
containerElRef.current = node;
|
|
177
|
+
}, []);
|
|
178
|
+
|
|
179
|
+
const inputRef = useCallback((node: HTMLInputElement | null) => {
|
|
180
|
+
inputElRef.current = node;
|
|
181
|
+
}, []);
|
|
182
|
+
|
|
183
|
+
useLayoutEffect(() => {
|
|
184
|
+
if (containerElRef.current && inputElRef.current) {
|
|
185
|
+
const containerLeft = containerElRef.current.getBoundingClientRect().left;
|
|
186
|
+
const inputLeft = inputElRef.current.getBoundingClientRect().left;
|
|
187
|
+
setAnchorOffset(containerLeft - inputLeft);
|
|
188
|
+
}
|
|
189
|
+
}, [startEnhancer, value]);
|
|
165
190
|
|
|
166
191
|
const optionsWithCustomValue = useMemo(
|
|
167
192
|
() => [...(allowCustomValue && customValueToOption ? [customValueToOption(query)] : []), ...options],
|
|
@@ -203,7 +228,10 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
203
228
|
}
|
|
204
229
|
}}
|
|
205
230
|
>
|
|
206
|
-
<
|
|
231
|
+
<ComboboxButton
|
|
232
|
+
as="div"
|
|
233
|
+
ref={containerRef}
|
|
234
|
+
tabIndex={-1}
|
|
207
235
|
data-status={disabled ? 'disabled' : status || 'default'}
|
|
208
236
|
{...overrides?.inputContainer}
|
|
209
237
|
className={clsx(overrides?.inputContainer?.className, inputStyles.inputContainer)}
|
|
@@ -231,11 +259,20 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
231
259
|
value.node
|
|
232
260
|
) : (
|
|
233
261
|
<ComboboxInput
|
|
262
|
+
ref={inputRef}
|
|
234
263
|
id={inputID}
|
|
235
264
|
{...overrides?.input}
|
|
236
265
|
placeholder={placeholder}
|
|
237
266
|
// value={query}
|
|
238
267
|
displayValue={() => value?.node as string}
|
|
268
|
+
onClick={(e: MouseEvent<HTMLInputElement>) => {
|
|
269
|
+
e.stopPropagation();
|
|
270
|
+
overrides?.input?.onClick?.(e);
|
|
271
|
+
}}
|
|
272
|
+
onKeyDown={(e) => {
|
|
273
|
+
e.stopPropagation();
|
|
274
|
+
overrides?.input?.onKeyDown?.(e);
|
|
275
|
+
}}
|
|
239
276
|
onChange={(e) => {
|
|
240
277
|
setQuery(e.target.value);
|
|
241
278
|
if (onInputChange) onInputChange(e.target.value);
|
|
@@ -261,7 +298,8 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
261
298
|
size="xs"
|
|
262
299
|
shape="circle"
|
|
263
300
|
startEnhancer={<FontAwesomeIcon icon={faClose} fontSize="10px" />}
|
|
264
|
-
onClick={() => {
|
|
301
|
+
onClick={(e) => {
|
|
302
|
+
e.stopPropagation();
|
|
265
303
|
if (onChange) {
|
|
266
304
|
onChange(null);
|
|
267
305
|
}
|
|
@@ -290,10 +328,14 @@ export function Combobox<T extends Record<string, any> = Record<string, any>>({
|
|
|
290
328
|
)}
|
|
291
329
|
</div>
|
|
292
330
|
)}
|
|
293
|
-
</
|
|
331
|
+
</ComboboxButton>
|
|
294
332
|
<ComboboxOptions
|
|
295
333
|
as="ul"
|
|
296
|
-
anchor=
|
|
334
|
+
anchor={{
|
|
335
|
+
to: 'bottom start',
|
|
336
|
+
gap: 9,
|
|
337
|
+
offset: anchorOffset,
|
|
338
|
+
}}
|
|
297
339
|
transition
|
|
298
340
|
{...overrides?.optionsContainer}
|
|
299
341
|
className={clsx(overrides?.optionsContainer?.className, styles.options)}
|
|
@@ -5,6 +5,7 @@ import { Callout } from '../callout';
|
|
|
5
5
|
import { ChevronRight, Ellipsis } from '../icon';
|
|
6
6
|
import { Menu, MenuButton, MenuItem, MenuItems } from '../menu';
|
|
7
7
|
import { usePagination } from '../pagination';
|
|
8
|
+
import { Select } from '../select';
|
|
8
9
|
import { Drawer } from './Drawer';
|
|
9
10
|
|
|
10
11
|
const meta: Meta<typeof Drawer> = {
|
|
@@ -259,6 +260,42 @@ export const BottomPanelMultiSection: Story = {
|
|
|
259
260
|
},
|
|
260
261
|
};
|
|
261
262
|
|
|
263
|
+
export const WithSelectDropdown: Story = {
|
|
264
|
+
args: {
|
|
265
|
+
title: 'Settings',
|
|
266
|
+
size: 'default',
|
|
267
|
+
},
|
|
268
|
+
render: function Render(args) {
|
|
269
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
270
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
271
|
+
return (
|
|
272
|
+
<>
|
|
273
|
+
<Button onClick={() => setIsOpen(true)}>Open drawer</Button>
|
|
274
|
+
<Drawer {...args} isOpen={isOpen} onClose={setIsOpen}>
|
|
275
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
276
|
+
<p>Try opening the Select dropdown below — it should appear above the Drawer.</p>
|
|
277
|
+
<Select
|
|
278
|
+
label="Country"
|
|
279
|
+
placeholder="Select a country"
|
|
280
|
+
value={selected}
|
|
281
|
+
onChange={setSelected}
|
|
282
|
+
options={[
|
|
283
|
+
{ id: 'us', node: 'United States' },
|
|
284
|
+
{ id: 'uk', node: 'United Kingdom' },
|
|
285
|
+
{ id: 'ca', node: 'Canada' },
|
|
286
|
+
{ id: 'au', node: 'Australia' },
|
|
287
|
+
{ id: 'de', node: 'Germany' },
|
|
288
|
+
{ id: 'fr', node: 'France' },
|
|
289
|
+
{ id: 'jp', node: 'Japan' },
|
|
290
|
+
]}
|
|
291
|
+
/>
|
|
292
|
+
</div>
|
|
293
|
+
</Drawer>
|
|
294
|
+
</>
|
|
295
|
+
);
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
|
|
262
299
|
export const Full: Story = {
|
|
263
300
|
args: {
|
|
264
301
|
title: 'Transaction details',
|
|
@@ -435,8 +435,8 @@ export type Theme = {
|
|
|
435
435
|
layers: {
|
|
436
436
|
below: number;
|
|
437
437
|
sticky: number;
|
|
438
|
-
dropdown: number;
|
|
439
438
|
overlay: number;
|
|
439
|
+
dropdown: number;
|
|
440
440
|
popover: number;
|
|
441
441
|
menu: number;
|
|
442
442
|
};
|
|
@@ -1065,8 +1065,8 @@ export const LightTheme: Theme = {
|
|
|
1065
1065
|
layers: {
|
|
1066
1066
|
below: -1,
|
|
1067
1067
|
sticky: 100,
|
|
1068
|
-
dropdown: 200,
|
|
1069
1068
|
overlay: 300,
|
|
1069
|
+
dropdown: 350,
|
|
1070
1070
|
popover: 400,
|
|
1071
1071
|
menu: 500,
|
|
1072
1072
|
},
|