1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-14 00:19:16 +01:00

refactor: period selector component (#9202)

Refactors the period selector component now that the design / system is
pretty much finished.

Main points are: change from using CSS selectors to using styled
components; use props instead of classes. This is in keeping with the
general Unleash approach.

There's two very slight visual changes here:
1. There is 4px of added space below the "range" "header" text.
2. The months in the grid are a little closer together and not as wide.
This is because we remove the explicit column gap due to the grid having
a set width. Previously the width was automatic, but because we want
this to line up with the button, we need to set the width explicitly on
both items. As such, with the padding, the grid was a little too wide,
so there was too little padding on the right. This rectifies that.
This commit is contained in:
Thomas Heartman 2025-02-04 11:37:58 +01:00 committed by GitHub
parent 2980c0de4e
commit 96dac84880
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -9,52 +9,79 @@ import { selectablePeriods } from './selectable-periods';
const dropdownWidth = '15rem'; const dropdownWidth = '15rem';
const dropdownInlinePadding = (theme: Theme) => theme.spacing(3); const dropdownInlinePadding = (theme: Theme) => theme.spacing(3);
const BaseButton = styled('button', {
shouldForwardProp: (prop) => prop !== 'selected',
})<{ selected?: boolean }>(({ theme, selected }) => ({
cursor: 'pointer',
border: 'none',
backgroundColor: selected ? theme.palette.secondary.light : 'inherit',
fontSize: theme.typography.body1.fontSize,
padding: theme.spacing(0.5),
borderRadius: theme.shape.borderRadius,
color: theme.palette.text.primary,
transition: 'background-color 0.2s ease',
':focus-visible': {
outline: `2px solid ${theme.palette.primary.main}`,
},
':hover:not(:disabled)': {
backgroundColor: theme.palette.action.hover,
},
}));
const GridButton = styled(BaseButton)(({ theme }) => ({
':disabled': {
cursor: 'default',
color: theme.palette.text.disabled,
},
}));
const RangeButton = styled(BaseButton)(({ theme }) => ({
width: '100%',
paddingBlock: theme.spacing(1),
textAlign: 'left',
borderRadius: 0,
paddingInline: dropdownInlinePadding(theme),
}));
const SelectorDropdownButton = styled(Button)(({ theme }) => ({
whiteSpace: 'nowrap',
width: dropdownWidth,
justifyContent: 'space-between',
fontWeight: 'normal',
color: theme.palette.text.primary,
borderColor: theme.palette.divider,
':focus-within': {
borderColor: theme.palette.primary.main,
},
':hover': {
borderColor: theme.palette.text.disabled,
backgroundColor: 'inherit',
},
transition: 'border-color 0.1s ease',
}));
const Wrapper = styled('article')(({ theme }) => ({ const Wrapper = styled('article')(({ theme }) => ({
width: dropdownWidth, width: dropdownWidth,
paddingBlock: theme.spacing(2), paddingBlock: theme.spacing(2),
display: 'flex', display: 'flex',
flexFlow: 'column', flexFlow: 'column',
gap: theme.spacing(2), gap: theme.spacing(2),
button: {
cursor: 'pointer',
border: 'none',
background: 'none',
fontSize: theme.typography.body1.fontSize,
padding: theme.spacing(0.5),
borderRadius: theme.shape.borderRadius,
color: theme.palette.text.primary,
transition: 'background-color 0.2s ease',
'&.selected': {
backgroundColor: theme.palette.secondary.light,
},
},
'button:disabled': {
cursor: 'default',
color: theme.palette.text.disabled,
},
'button:hover:not(:disabled)': {
backgroundColor: theme.palette.action.hover,
},
'button:focus': {
outline: `2px solid ${theme.palette.primary.main}`,
},
})); }));
const MonthSelector = styled('article')(({ theme }) => ({ const MonthSelector = styled('article')(({ theme }) => ({
border: 'none',
paddingInline: dropdownInlinePadding(theme), paddingInline: dropdownInlinePadding(theme),
hgroup: { }));
h3: {
margin: 0,
fontSize: theme.typography.h3.fontSize,
},
p: {
color: theme.palette.text.secondary,
fontSize: theme.typography.body2.fontSize,
},
marginBottom: theme.spacing(1), const MonthSelectorHeaderGroup = styled('hgroup')(({ theme }) => ({
h3: {
margin: 0,
fontSize: theme.typography.h3.fontSize,
},
p: {
color: theme.palette.text.secondary,
fontSize: theme.typography.body2.fontSize,
}, },
})); }));
@ -64,20 +91,21 @@ const MonthGrid = styled('ul')(({ theme }) => ({
display: 'grid', display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)', gridTemplateColumns: 'repeat(4, 1fr)',
rowGap: theme.spacing(1), rowGap: theme.spacing(1),
columnGap: theme.spacing(2),
})); }));
const RangeSelector = styled('article')(({ theme }) => ({ const RangeSelector = styled('article')(({ theme }) => ({
display: 'flex', display: 'flex',
width: '100%', width: '100%',
flexFlow: 'column', flexFlow: 'column',
gap: theme.spacing(0), gap: theme.spacing(0.5),
h4: { }));
paddingInline: dropdownInlinePadding(theme),
fontSize: theme.typography.body2.fontSize, const RangeHeader = styled('p')(({ theme }) => ({
margin: 0, paddingInline: dropdownInlinePadding(theme),
color: theme.palette.text.secondary, fontSize: theme.typography.body2.fontSize,
}, margin: 0,
color: theme.palette.text.secondary,
fontWeight: 'bold',
})); }));
const RangeList = styled('ul')(({ theme }) => ({ const RangeList = styled('ul')(({ theme }) => ({
@ -88,14 +116,6 @@ const RangeList = styled('ul')(({ theme }) => ({
li: { li: {
width: '100%', width: '100%',
}, },
button: {
width: '100%',
paddingBlock: theme.spacing(1),
textAlign: 'left',
borderRadius: 0,
paddingInline: dropdownInlinePadding(theme),
},
})); }));
type Props = { type Props = {
@ -136,31 +156,14 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {
return ( return (
<Box ref={ref}> <Box ref={ref}>
<Button <SelectorDropdownButton
endIcon={open ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />} endIcon={open ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />}
sx={(theme) => ({
whiteSpace: 'nowrap',
width: dropdownWidth,
justifyContent: 'space-between',
fontWeight: 'normal',
color: theme.palette.text.primary,
borderColor: theme.palette.divider,
':focus-within': {
borderColor: theme.palette.primary.main,
},
':hover': {
borderColor: theme.palette.text.disabled,
backgroundColor: 'inherit',
},
transition: 'border-color 0.1s ease',
})}
variant='outlined' variant='outlined'
disableRipple disableRipple
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
> >
{buttonText} {buttonText}
</Button> </SelectorDropdownButton>
<StyledPopover <StyledPopover
open={open} open={open}
anchorEl={ref.current} anchorEl={ref.current}
@ -176,22 +179,19 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {
> >
<Wrapper> <Wrapper>
<MonthSelector> <MonthSelector>
<hgroup> <MonthSelectorHeaderGroup>
<h3>Select month</h3> <h3>Select month</h3>
<p>Last 12 months</p> <p>Last 12 months</p>
</hgroup> </MonthSelectorHeaderGroup>
<MonthGrid> <MonthGrid>
{selectablePeriods.map((period, index) => ( {selectablePeriods.map((period, index) => (
<li key={period.label}> <li key={period.label}>
<button <GridButton
className={ selected={
selectedPeriod.grouping === selectedPeriod.grouping ===
'daily' && 'daily' &&
period.key === selectedPeriod.month period.key === selectedPeriod.month
? 'selected'
: ''
} }
type='button'
disabled={!period.selectable} disabled={!period.selectable}
onClick={() => { onClick={() => {
selectPeriod({ selectPeriod({
@ -201,25 +201,23 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {
}} }}
> >
{period.shortLabel} {period.shortLabel}
</button> </GridButton>
</li> </li>
))} ))}
</MonthGrid> </MonthGrid>
</MonthSelector> </MonthSelector>
<RangeSelector> <RangeSelector>
<h4>Range</h4> <RangeHeader>Range</RangeHeader>
<RangeList> <RangeList>
{rangeOptions.map((option) => ( {rangeOptions.map((option) => (
<li key={option.label}> <li key={option.label}>
<button <RangeButton
className={ selected={
selectedPeriod.grouping === selectedPeriod.grouping ===
'monthly' && 'monthly' &&
option.value === option.value ===
selectedPeriod.monthsBack selectedPeriod.monthsBack
? 'selected'
: ''
} }
type='button' type='button'
onClick={() => { onClick={() => {
@ -230,7 +228,7 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {
}} }}
> >
Last {option.value} months Last {option.value} months
</button> </RangeButton>
</li> </li>
))} ))}
</RangeList> </RangeList>