Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit 9adf3a5

Browse files
committed
refactor: split out selector from base select
The selector itself could be reused to make other types of selects such as a larger area, or a grid of things. This splits out the selector part from BaseSelect into BaseSelectSelector. In addition this adds a forwardRef to Paper so it can be reused in dropdowns.
1 parent 3d99b18 commit 9adf3a5

File tree

10 files changed

+672
-609
lines changed

10 files changed

+672
-609
lines changed

.yarn/versions/97a94915.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
releases:
2+
practical-react-components: minor
3+
4+
undecided:
5+
- practical-react-components-core

packages/core/src/Input/__snapshots__/index.test.tsx.snap

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4217,6 +4217,42 @@ exports[`TextInput TimeInput 1`] = `
42174217
white-space: nowrap;
42184218
}
42194219
4220+
.c24 {
4221+
height: 40px;
4222+
display: -webkit-box;
4223+
display: -webkit-flex;
4224+
display: -ms-flexbox;
4225+
display: flex;
4226+
-webkit-align-items: center;
4227+
-webkit-box-align: center;
4228+
-ms-flex-align: center;
4229+
align-items: center;
4230+
color: rgb(82,82,82);
4231+
cursor: default;
4232+
}
4233+
4234+
.c26 {
4235+
display: -webkit-box;
4236+
display: -webkit-flex;
4237+
display: -ms-flexbox;
4238+
display: flex;
4239+
-webkit-flex-direction: row;
4240+
-ms-flex-direction: row;
4241+
flex-direction: row;
4242+
-webkit-align-items: center;
4243+
-webkit-box-align: center;
4244+
-ms-flex-align: center;
4245+
align-items: center;
4246+
}
4247+
4248+
.c27 {
4249+
color: rgb(82,82,82);
4250+
margin-left: 8px;
4251+
-webkit-flex-shrink: 0;
4252+
-ms-flex-negative: 0;
4253+
flex-shrink: 0;
4254+
}
4255+
42204256
.c29 {
42214257
position: fixed;
42224258
top: 0;
@@ -4260,10 +4296,6 @@ exports[`TextInput TimeInput 1`] = `
42604296
width: 100%;
42614297
}
42624298
4263-
.c9 {
4264-
width: 100%;
4265-
}
4266-
42674299
.c10 {
42684300
display: -webkit-box;
42694301
display: -webkit-flex;
@@ -4315,40 +4347,8 @@ exports[`TextInput TimeInput 1`] = `
43154347
padding: 2px;
43164348
}
43174349
4318-
.c24 {
4319-
height: 40px;
4320-
display: -webkit-box;
4321-
display: -webkit-flex;
4322-
display: -ms-flexbox;
4323-
display: flex;
4324-
-webkit-align-items: center;
4325-
-webkit-box-align: center;
4326-
-ms-flex-align: center;
4327-
align-items: center;
4328-
color: rgb(82,82,82);
4329-
cursor: default;
4330-
}
4331-
4332-
.c26 {
4333-
display: -webkit-box;
4334-
display: -webkit-flex;
4335-
display: -ms-flexbox;
4336-
display: flex;
4337-
-webkit-flex-direction: row;
4338-
-ms-flex-direction: row;
4339-
flex-direction: row;
4340-
-webkit-align-items: center;
4341-
-webkit-box-align: center;
4342-
-ms-flex-align: center;
4343-
align-items: center;
4344-
}
4345-
4346-
.c27 {
4347-
color: rgb(82,82,82);
4348-
margin-left: 8px;
4349-
-webkit-flex-shrink: 0;
4350-
-ms-flex-negative: 0;
4351-
flex-shrink: 0;
4350+
.c9 {
4351+
width: 100%;
43524352
}
43534353
43544354
.c13 {
@@ -4713,12 +4713,12 @@ exports[`TextInput TimeInput 1`] = `
47134713
</div>
47144714
<div
47154715
className="c9"
4716+
onBlur={[Function]}
47164717
width="full"
47174718
>
47184719
<div
47194720
className="c10"
47204721
disabled={false}
4721-
onBlur={[Function]}
47224722
onClick={[Function]}
47234723
onKeyDown={[Function]}
47244724
onPointerDown={[Function]}

packages/core/src/Paper/index.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react'
1+
import React, { forwardRef } from 'react'
22
import styled, { css } from 'styled-components'
33
import { shape, spacing } from '../designparams'
44

@@ -46,13 +46,11 @@ interface IPaperProps extends BaseProps {
4646
readonly space?: boolean
4747
}
4848

49-
export const Paper: React.FC<IPaperProps> = ({
50-
square = false,
51-
space = false,
52-
children,
53-
...props
54-
}) => (
55-
<PaperDiv square={square} space={space} {...props}>
56-
{children}
57-
</PaperDiv>
49+
/* eslint-disable-next-line react/display-name */
50+
export const Paper = forwardRef<BaseElement, IPaperProps>(
51+
({ square = false, space = false, children, ...props }, ref) => (
52+
<PaperDiv square={square} space={space} {...props} ref={ref}>
53+
{children}
54+
</PaperDiv>
55+
)
5856
)

packages/core/src/Select/BaseSelect.tsx

Lines changed: 24 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import styled, { css, useTheme } from 'styled-components'
1010
import { useBoolean } from 'react-hooks-shareable'
1111

1212
import { Icon } from '../Icon'
13-
import { ArrowDownIcon, ArrowUpIcon, SmallerCheckIcon } from './icons'
14-
import { componentSize, opacity, shape, spacing } from '../designparams'
13+
import { SmallerCheckIcon } from './icons'
14+
import { componentSize, shape, spacing } from '../designparams'
1515
import { Typography } from '../Typography'
1616
import { getWidth, scrollIntoView, findPrevIndex, findNextIndex } from './utils'
1717
import { ISelectMarker } from '../theme'
1818

1919
import { PopOver, IPopOverProps } from '../PopOver'
2020
import { anchorPosition } from '../PopOver/utils'
21+
import { SelectVariant, BaseSelectSelector } from '.'
2122

2223
export type DirectionType = 'auto' | 'up' | 'down'
2324

@@ -304,138 +305,12 @@ export const SelectPopover: React.FC<ISelectPopoverProps> = ({
304305
)
305306
}
306307

307-
const SelectInsideContainer = styled.div`
308-
display: flex;
309-
flex-direction: row;
310-
align-items: center;
311-
justify-content: space-between;
312-
height: 100%;
313-
width: 100%;
314-
`
315-
316308
const SelectContainer = styled.div<{
317309
readonly width: string
318310
}>`
319311
width: ${({ width }) => getWidth(width)};
320312
`
321313

322-
const SelectInput = styled.div<{
323-
readonly compact: boolean
324-
readonly variant: string
325-
readonly hasError: boolean
326-
readonly openedFocus: boolean
327-
readonly visibleFocus: boolean
328-
readonly disabled: boolean
329-
}>`
330-
display: flex;
331-
align-items: center;
332-
min-height: ${({ compact }) =>
333-
compact ? componentSize.small : componentSize.medium};
334-
color: ${({ theme }) => theme.color.text01()};
335-
336-
background-color: ${({ variant, theme }) =>
337-
variant === 'filled' || variant === 'framed'
338-
? theme.color.background02()
339-
: 'transparent'};
340-
341-
padding: 2px;
342-
border: 0 solid transparent;
343-
border-radius: ${shape.radius.medium};
344-
345-
${({ variant, theme }) =>
346-
variant === 'framed'
347-
? css`
348-
padding: 1px;
349-
border: 1px solid ${theme.color.element01()};
350-
`
351-
: undefined}
352-
353-
font-family: ${({ theme }) => theme.font.family};
354-
font-size: ${({ theme }) => theme.font.size.regular};
355-
line-height: ${({ theme }) => theme.font.lineHeight.large};
356-
text-align: left;
357-
cursor: pointer;
358-
359-
${SelectInsideContainer} {
360-
padding: ${({ compact }) =>
361-
compact
362-
? `0 ${spacing.small} 0 ${spacing.medium}`
363-
: `0 ${spacing.medium}`};
364-
}
365-
366-
> div > span > svg {
367-
width: 100%;
368-
height: 100%;
369-
cursor: pointer;
370-
background-color: transparent;
371-
fill: ${({ theme }) => theme.color.element01()};
372-
}
373-
374-
&:hover {
375-
background-color: ${({ variant, theme }) =>
376-
variant === 'filled' || variant === 'framed'
377-
? theme.color.background01()
378-
: theme.color.background02()};
379-
380-
${({ variant, theme }) =>
381-
variant === 'framed'
382-
? css`
383-
padding: 0;
384-
border: 2px solid ${theme.color.element01()};
385-
`
386-
: undefined}
387-
}
388-
389-
&:focus {
390-
outline: none;
391-
392-
${({ openedFocus, visibleFocus, variant, theme }) =>
393-
openedFocus
394-
? css`
395-
background-color: ${theme.color.background01()};
396-
border: none;
397-
padding: 2px;
398-
`
399-
: visibleFocus
400-
? css`
401-
background-color: ${variant === 'filled' || variant === 'framed'
402-
? theme.color.background01()
403-
: 'transparent'};
404-
border: 2px solid ${theme.color.textPrimary()};
405-
padding: 0;
406-
`
407-
: undefined}
408-
}
409-
410-
&:active {
411-
background-color: ${({ theme }) => theme.color.background01()};
412-
border: none;
413-
padding: 2px;
414-
}
415-
416-
${({ disabled }) =>
417-
disabled
418-
? css`
419-
opacity: ${opacity[48]};
420-
pointer-events: none;
421-
`
422-
: undefined}
423-
424-
${({ theme, hasError }) =>
425-
hasError
426-
? css`
427-
&,
428-
&:hover,
429-
&:focus {
430-
background-color: ${theme.color.backgroundError()};
431-
border-color: ${theme.color.elementError()};
432-
}
433-
`
434-
: undefined};
435-
`
436-
437-
type SelectVariant = 'filled' | 'transparent' | 'framed'
438-
439314
export enum SelectKeys {
440315
Space = ' ',
441316
ArrowUp = 'ArrowUp',
@@ -699,35 +574,38 @@ export function BaseSelect<V extends string = string>({
699574
}
700575
}, [isOpen, listRef, itemRefs, valueIndex])
701576

702-
const handleBlur = useCallback(() => {
703-
if (onBlur !== undefined) {
704-
onBlur(true)
705-
}
706-
setKeyboardOn()
707-
closePopover()
708-
}, [onBlur, closePopover, setKeyboardOn])
577+
const handleFocusOut: React.EventHandler<React.FocusEvent> = useCallback(
578+
e => {
579+
if (popupAnchorEl?.contains(e.target) ?? false) {
580+
setKeyboardOn()
581+
closePopover()
582+
}
583+
},
584+
[closePopover, popupAnchorEl, setKeyboardOn]
585+
)
709586

710587
return (
711-
<SelectContainer width={width} ref={setPopupAnchorEl} {...props}>
712-
<SelectInput
713-
onClick={toggleOpen}
588+
<SelectContainer
589+
width={width}
590+
ref={setPopupAnchorEl}
591+
onBlur={handleFocusOut}
592+
{...props}
593+
>
594+
<BaseSelectSelector
595+
onToggleOpen={toggleOpen}
596+
open={isOpen}
714597
compact={compact}
715598
variant={variant}
716599
onKeyDown={handleKeyDown}
717600
onPointerDown={setKeyboardOff}
718-
onBlur={handleBlur}
719-
openedFocus={isOpen}
720-
visibleFocus={isKeyboard}
721601
hasError={error.length > 0}
722602
role="button"
723603
tabIndex={0}
724604
disabled={disabled}
605+
visibleFocus={isKeyboard}
725606
>
726-
<SelectInsideContainer>
727-
{component}
728-
<Icon icon={isOpen ? ArrowUpIcon : ArrowDownIcon} />
729-
</SelectInsideContainer>
730-
</SelectInput>
607+
{component}
608+
</BaseSelectSelector>
731609
<SelectPopover
732610
anchorEl={popupAnchorEl}
733611
onScroll={closePopover}

0 commit comments

Comments
 (0)