Skip to content

Commit 6962b05

Browse files
authored
Merge pull request #142 from lambda-curry/codegen-bot/improve-select-width-matching-with-resize-observer
2 parents 875bc53 + 733efee commit 6962b05

File tree

1 file changed

+27
-17
lines changed

1 file changed

+27
-17
lines changed

packages/components/src/ui/select.tsx

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Popover } from '@radix-ui/react-popover';
2+
import * as PopoverPrimitive from '@radix-ui/react-popover';
23
import { Check as DefaultCheckIcon, ChevronDown as DefaultChevronIcon } from 'lucide-react';
34
import * as React from 'react';
45
import { useOverlayTriggerState } from 'react-stately';
5-
import { PopoverContent, PopoverTrigger } from './popover';
6+
import { PopoverTrigger } from './popover';
67
import { cn } from './utils';
78

89
export interface SelectOption {
@@ -52,11 +53,7 @@ export function Select({
5253
const triggerRef = React.useRef<HTMLButtonElement>(null);
5354
const popoverRef = React.useRef<HTMLDivElement>(null);
5455
const selectedItemRef = React.useRef<HTMLButtonElement>(null);
55-
const [menuWidth, setMenuWidth] = React.useState<number | undefined>(undefined);
56-
57-
React.useEffect(() => {
58-
if (triggerRef.current) setMenuWidth(triggerRef.current.offsetWidth);
59-
}, []);
56+
// No need for JavaScript width measurement - Radix provides --radix-popover-trigger-width CSS variable
6057

6158
// Scroll to selected item when dropdown opens
6259
React.useEffect(() => {
@@ -130,15 +127,27 @@ export function Select({
130127
<ChevronIcon className="w-4 h-4 opacity-50" />
131128
</Trigger>
132129
</PopoverTrigger>
133-
<PopoverContent
134-
ref={popoverRef}
135-
className={cn('z-50 p-0 shadow-md border-0', contentClassName)}
136-
// biome-ignore lint/a11y/useSemanticElements: using <div> for PopoverContent to ensure keyboard accessibility and focus management
137-
role="listbox"
138-
id={listboxId}
139-
style={{ width: menuWidth ? `${menuWidth}px` : undefined }}
140-
>
141-
<div className="bg-white p-1.5 rounded-md focus:outline-none sm:text-sm">
130+
<PopoverPrimitive.Portal>
131+
<PopoverPrimitive.Content
132+
ref={popoverRef}
133+
align="start"
134+
sideOffset={4}
135+
className={cn(
136+
'z-50 rounded-md border bg-popover text-popover-foreground shadow-md outline-none',
137+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
138+
'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
139+
'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',
140+
'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
141+
'p-0 shadow-md border-0',
142+
contentClassName
143+
)}
144+
// biome-ignore lint/a11y/useSemanticElements: using <div> for PopoverContent to ensure keyboard accessibility and focus management
145+
role="listbox"
146+
id={listboxId}
147+
style={{ width: 'var(--radix-popover-trigger-width)' }}
148+
data-slot="popover-content"
149+
>
150+
<div className="bg-white p-1.5 rounded-md focus:outline-none sm:text-sm w-full">
142151
<div className="px-1.5 pb-1.5">
143152
<SearchInput
144153
type="text"
@@ -168,7 +177,7 @@ export function Select({
168177
className="w-full h-9 rounded-md bg-white px-2 text-sm leading-none focus:ring-0 focus:outline-none border-0"
169178
/>
170179
</div>
171-
<ul className="max-h-[200px] overflow-y-auto rounded-md">
180+
<ul className="max-h-[200px] overflow-y-auto rounded-md w-full">
172181
{filtered.length === 0 && <li className="px-3 py-2 text-sm text-gray-500">No results.</li>}
173182
{filtered.map((option) => {
174183
const isSelected = option.value === value;
@@ -208,7 +217,8 @@ export function Select({
208217
})}
209218
</ul>
210219
</div>
211-
</PopoverContent>
220+
</PopoverPrimitive.Content>
221+
</PopoverPrimitive.Portal>
212222
</Popover>
213223
);
214224
}

0 commit comments

Comments
 (0)