mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02: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:
		
							parent
							
								
									2980c0de4e
								
							
						
					
					
						commit
						96dac84880
					
				| @ -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> | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user