Skip to content

Commit 133d573

Browse files
committed
fix(devtools): enhance Select component UX in user preferences
The clickable area was limited to the text of the selected option, not the entire visible button area. This made the component feel unresponsive. I was unable to directly stretch the select element to expand its clickable area, and so added a span. Initially, an unintended side effect of the change caused the button's width to change dynamically with the selection, losing the stable width behavior of the original select element. To restore this, a hidden `<span>` sets a consistent width based on the longest option.
1 parent ee94be9 commit 133d573

File tree

1 file changed

+45
-3
lines changed
  • packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-info

1 file changed

+45
-3
lines changed

packages/next/src/client/components/react-dev-overlay/ui/components/errors/dev-tools-indicator/dev-tools-info/user-preferences.tsx

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, type HTMLProps } from 'react'
1+
import React, { useState, type HTMLProps } from 'react'
22
import { css } from '../../../../../utils/css'
33
import EyeIcon from '../../../../icons/eye-icon'
44
import { STORAGE_KEY_POSITION, STORAGE_KEY_THEME } from '../../../../../shared'
@@ -237,14 +237,40 @@ export function UserPreferences({
237237
function Select({
238238
children,
239239
prefix,
240+
value,
240241
...props
241242
}: {
242243
prefix?: React.ReactNode
243-
} & Omit<React.HTMLProps<HTMLSelectElement>, 'prefix'>) {
244+
value?: string | number
245+
} & Omit<React.HTMLProps<HTMLSelectElement>, 'prefix' | 'value'>) {
246+
let displayValue = ''
247+
let longestText = ''
248+
249+
React.Children.forEach(children, (child) => {
250+
if (
251+
React.isValidElement<React.OptionHTMLAttributes<HTMLOptionElement>>(child)
252+
) {
253+
const childText = child.props.children as string
254+
if (childText.length > longestText.length) {
255+
longestText = childText
256+
}
257+
if (child.props.value === value) {
258+
displayValue = childText
259+
}
260+
}
261+
})
262+
244263
return (
245264
<div className="select-button">
246265
{prefix}
247-
<select {...props}>{children}</select>
266+
<div className="select-value-wrapper">
267+
<span>{longestText}</span>
268+
<span>{displayValue}</span>
269+
</div>
270+
271+
<select value={value} {...props}>
272+
{children}
273+
</select>
248274
<ChevronDownIcon />
249275
</div>
250276
)
@@ -328,12 +354,17 @@ export const DEV_TOOLS_INFO_USER_PREFERENCES_STYLES = css`
328354
}
329355
330356
.select-button {
357+
position: relative;
331358
&:focus-within {
332359
outline: var(--focus-ring);
333360
}
334361
335362
select {
336363
all: unset;
364+
position: absolute;
365+
inset: 0;
366+
opacity: 0;
367+
cursor: pointer;
337368
}
338369
339370
option {
@@ -342,6 +373,17 @@ export const DEV_TOOLS_INFO_USER_PREFERENCES_STYLES = css`
342373
}
343374
}
344375
376+
.select-value-wrapper {
377+
display: grid;
378+
}
379+
380+
.select-value-wrapper > span {
381+
grid-area: 1 / 1;
382+
}
383+
.select-value-wrapper > span:first-child {
384+
visibility: hidden;
385+
}
386+
345387
:global(.icon) {
346388
width: 18px;
347389
height: 18px;

0 commit comments

Comments
 (0)