Skip to content

Commit c2b5717

Browse files
committed
feat: Select styles
1 parent fc555c9 commit c2b5717

File tree

2 files changed

+65
-41
lines changed

2 files changed

+65
-41
lines changed

example/src/stories/Select.stories.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export default {
1313
items: {
1414
control: 'none',
1515
},
16+
fullWidth: {
17+
control: 'boolean',
18+
description:
19+
'Whether the selector should take up the full width of its container',
20+
},
1621
},
1722
} as ComponentMeta<typeof Select>
1823

@@ -26,6 +31,14 @@ Default.args = {
2631
.map((_, i) => `Item ${i}`),
2732
}
2833

34+
export const LongEntries = Template.bind({})
35+
LongEntries.args = {
36+
value: 'Select',
37+
items: Array(256)
38+
.fill(undefined)
39+
.map((_, i) => `Item ${i}`),
40+
}
41+
2942
export const CustomRender = Template.bind({})
3043
CustomRender.args = {
3144
value: 'Select',

src/components/Select.tsx

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,43 @@
11
import styled from '@emotion/styled'
22
import {
3-
autoUpdate,
4-
flip,
5-
FloatingFocusManager,
6-
FloatingOverlay,
7-
inner,
8-
offset,
9-
shift,
10-
SideObject,
11-
size,
12-
useClick,
13-
useDismiss,
14-
useFloating,
15-
useInnerOffset,
16-
useInteractions,
17-
useListNavigation,
18-
useRole,
19-
useTypeahead
3+
autoUpdate,
4+
flip,
5+
FloatingFocusManager,
6+
FloatingOverlay,
7+
inner,
8+
offset,
9+
shift,
10+
SideObject,
11+
size,
12+
useClick,
13+
useDismiss,
14+
useFloating,
15+
useInnerOffset,
16+
useInteractions,
17+
useListNavigation,
18+
useRole,
19+
useTypeahead
2020
} from '@floating-ui/react-dom-interactions'
2121
import React, {
22-
ElementType,
23-
ReactNode,
24-
useEffect,
25-
useLayoutEffect,
26-
useRef,
27-
useState
22+
ElementType,
23+
ReactNode,
24+
useEffect,
25+
useLayoutEffect,
26+
useRef,
27+
useState
2828
} from 'react'
2929
import { PC, PP } from '../types/PolymorphicElementProps'
30-
import { cssDisablable } from '../utils/styles'
30+
import { cssClickable, cssDisablable } from '../utils/styles'
31+
import { ListItem } from './$List'
3132

3233
interface SelectDisplayProps {
3334
fullWidth: boolean
3435
}
3536

3637
const SelectDisplay = styled.div<SelectDisplayProps>`
3738
${cssDisablable}
39+
${cssClickable}
40+
display: inline-block;
3841
font-family: inherit;
3942
height: auto;
4043
line-height: normal;
@@ -47,6 +50,13 @@ const SelectDisplay = styled.div<SelectDisplayProps>`
4750
width: ${({ fullWidth }) => (fullWidth ? '100%' : 'auto')};
4851
`
4952

53+
const SelectItemsWrapper = styled.div`
54+
background: ${({ theme }) => theme.color.background.page};
55+
border: ${({ theme }) => theme.styles.border()};
56+
border-radius: 8px;
57+
overflow-y: auto;
58+
`
59+
5060
// Adopted from https://codesandbox.io/s/shy-snowflake-kp6479?file=/src/Select.tsx:5939-5954
5161

5262
type SelectItemNode = string | { value: string }
@@ -80,8 +90,6 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
8090
const allowSelectRef = useRef(false)
8191
const allowMouseUpRef = useRef(true)
8292
const selectTimeoutRef = useRef<any>()
83-
const upArrowRef = useRef<HTMLDivElement | null>(null)
84-
const downArrowRef = useRef<HTMLDivElement | null>(null)
8593

8694
const [open, setOpen] = useState(false)
8795
const [selectedIndex, setSelectedIndex] = useState(0)
@@ -114,16 +122,17 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
114122
offset(5),
115123
...[
116124
touch
117-
? shift({ crossAxis: true, padding: 10 })
118-
: flip({ padding: 10 }),
125+
? shift({ crossAxis: true, padding: 8 })
126+
: flip({ padding: 8 }),
119127
],
120128
size({
121-
apply({ elements, availableHeight }) {
129+
apply({ elements, availableHeight, rects }) {
122130
Object.assign(elements.floating.style, {
123131
maxHeight: `${availableHeight}px`,
132+
width: `${rects.reference.width}px`,
124133
})
125134
},
126-
padding: 10,
135+
padding: 8,
127136
}),
128137
]
129138
: [
@@ -133,7 +142,7 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
133142
index: selectedIndex,
134143
offset: innerOffset,
135144
onFallbackChange: setFallback,
136-
padding: 10,
145+
padding: 8,
137146
minItemsVisible: touch ? 10 : 4,
138147
referenceOverflowThreshold: 20,
139148
}),
@@ -184,11 +193,7 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
184193
useLayoutEffect(() => {
185194
const onPointerDown = (e: PointerEvent): void => {
186195
const target = e.target as Node
187-
if (
188-
!refs.floating.current?.contains(target) &&
189-
!upArrowRef.current?.contains(target) &&
190-
!downArrowRef.current?.contains(target)
191-
) {
196+
if (!refs.floating.current?.contains(target)) {
192197
setOpen(false)
193198
}
194199
}
@@ -255,12 +260,13 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
255260
{open && (
256261
<FloatingOverlay lockScroll={!touch} style={{ zIndex: 1 }}>
257262
<FloatingFocusManager context={context} preventTabbing>
258-
<div
263+
<SelectItemsWrapper
259264
ref={floating}
260265
style={{
261266
position: strategy,
262267
top: y ?? 0,
263268
left: x ?? 0,
269+
width: fullWidth ? '100%' : undefined,
264270
}}
265271
{...getFloatingProps({
266272
onKeyDown() {
@@ -276,7 +282,8 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
276282
>
277283
{items.map((item, i) => {
278284
return (
279-
<div
285+
<ListItem<'div'>
286+
clickable
280287
key={typeof item === 'string' ? item : item.value}
281288
role="option"
282289
tabIndex={0}
@@ -300,8 +307,12 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
300307
allowSelectRef.current = true
301308
allowMouseUpRef.current = false
302309
},
303-
onKeyDown() {
310+
onKeyDown(e) {
304311
allowSelectRef.current = true
312+
if (e.key === 'Enter' && allowSelectRef.current) {
313+
setSelectedIndex(i)
314+
setOpen(false)
315+
}
305316
},
306317
onClick() {
307318
if (allowSelectRef.current) {
@@ -327,10 +338,10 @@ export const Select: PC<'button', SelectProps> = React.forwardRef(
327338
})}
328339
>
329340
{render(item)}
330-
</div>
341+
</ListItem>
331342
)
332343
})}
333-
</div>
344+
</SelectItemsWrapper>
334345
</FloatingFocusManager>
335346
</FloatingOverlay>
336347
)}

0 commit comments

Comments
 (0)