Skip to content

Commit

Permalink
refactor: period selector component (#9202)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
thomasheartman authored Feb 4, 2025
1 parent 2980c0d commit 96dac84
Showing 1 changed file with 83 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,52 +9,79 @@ import { selectablePeriods } from './selectable-periods';
const dropdownWidth = '15rem';
const dropdownInlinePadding = (theme: Theme) => theme.spacing(3);

const Wrapper = styled('article')(({ theme }) => ({
width: dropdownWidth,
paddingBlock: theme.spacing(2),
display: 'flex',
flexFlow: 'column',
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,
},
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,
},
'button:disabled': {
}));

const GridButton = styled(BaseButton)(({ theme }) => ({
':disabled': {
cursor: 'default',
color: theme.palette.text.disabled,
},
'button:hover:not(:disabled)': {
backgroundColor: theme.palette.action.hover,
}));

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,
},
'button:focus': {
outline: `2px solid ${theme.palette.primary.main}`,
':hover': {
borderColor: theme.palette.text.disabled,
backgroundColor: 'inherit',
},

transition: 'border-color 0.1s ease',
}));

const Wrapper = styled('article')(({ theme }) => ({
width: dropdownWidth,
paddingBlock: theme.spacing(2),
display: 'flex',
flexFlow: 'column',
gap: theme.spacing(2),
}));

const MonthSelector = styled('article')(({ theme }) => ({
border: 'none',
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,
},
}));

Expand All @@ -64,20 +91,21 @@ const MonthGrid = styled('ul')(({ theme }) => ({
display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)',
rowGap: theme.spacing(1),
columnGap: theme.spacing(2),
}));

const RangeSelector = styled('article')(({ theme }) => ({
display: 'flex',
width: '100%',
flexFlow: 'column',
gap: theme.spacing(0),
h4: {
paddingInline: dropdownInlinePadding(theme),
fontSize: theme.typography.body2.fontSize,
margin: 0,
color: theme.palette.text.secondary,
},
gap: theme.spacing(0.5),
}));

const RangeHeader = styled('p')(({ theme }) => ({
paddingInline: dropdownInlinePadding(theme),
fontSize: theme.typography.body2.fontSize,
margin: 0,
color: theme.palette.text.secondary,
fontWeight: 'bold',
}));

const RangeList = styled('ul')(({ theme }) => ({
Expand All @@ -88,14 +116,6 @@ const RangeList = styled('ul')(({ theme }) => ({
li: {
width: '100%',
},

button: {
width: '100%',
paddingBlock: theme.spacing(1),
textAlign: 'left',
borderRadius: 0,
paddingInline: dropdownInlinePadding(theme),
},
}));

type Props = {
Expand Down Expand Up @@ -136,31 +156,14 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {

return (
<Box ref={ref}>
<Button
<SelectorDropdownButton
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'
disableRipple
onClick={() => setOpen(true)}
>
{buttonText}
</Button>
</SelectorDropdownButton>
<StyledPopover
open={open}
anchorEl={ref.current}
Expand All @@ -176,22 +179,19 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {
>
<Wrapper>
<MonthSelector>
<hgroup>
<MonthSelectorHeaderGroup>
<h3>Select month</h3>
<p>Last 12 months</p>
</hgroup>
</MonthSelectorHeaderGroup>
<MonthGrid>
{selectablePeriods.map((period, index) => (
<li key={period.label}>
<button
className={
<GridButton
selected={
selectedPeriod.grouping ===
'daily' &&
period.key === selectedPeriod.month
? 'selected'
: ''
}
type='button'
disabled={!period.selectable}
onClick={() => {
selectPeriod({
Expand All @@ -201,25 +201,23 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {
}}
>
{period.shortLabel}
</button>
</GridButton>
</li>
))}
</MonthGrid>
</MonthSelector>
<RangeSelector>
<h4>Range</h4>
<RangeHeader>Range</RangeHeader>

<RangeList>
{rangeOptions.map((option) => (
<li key={option.label}>
<button
className={
<RangeButton
selected={
selectedPeriod.grouping ===
'monthly' &&
option.value ===
selectedPeriod.monthsBack
? 'selected'
: ''
}
type='button'
onClick={() => {
Expand All @@ -230,7 +228,7 @@ export const PeriodSelector: FC<Props> = ({ selectedPeriod, setPeriod }) => {
}}
>
Last {option.value} months
</button>
</RangeButton>
</li>
))}
</RangeList>
Expand Down

0 comments on commit 96dac84

Please sign in to comment.