frontend/src/common/ButtonGroup.tsx

177 lines
5 KiB
TypeScript

import { Box, Button, darken, Theme, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { cloneDeep } from "lodash";
import { useEffect } from "react";
import { useState } from "react";
import { getSecondaryColour } from "services/whiteLabel";
import { getThemeType } from "theme/themeType";
export interface ButtonData {
/**
* The title and description of the button
*/
title: string
/**
* An icon that would replace the text of the button
*/
icon?: JSX.Element
/**
* The function to run when the button is clicked or toggled on when toggle is true
*/
function: () => void
/**
* whether the button is disabled or not
*/
disabled?: boolean
}
interface Props {
/**
* The array of button data to be rendered by the group
*/
buttons: ButtonData[]
/**
* When true will track the toggle state of the buttons, false will just be basic buttons
*
* @default false
*/
toggle?: boolean
/**
* When true will allow multiple buttons to be toggled, false will untoggle the previous button when another is selected
*
* @default false
*/
multiToggle?: boolean
/**
* Can be used to control which buttons are toggled on from the parent by passing the indexes of the buttons to toggle on.
* If not passed in will default to toggle the first button and then be controlled internally
*
* @default undefined
*/
toggledButtons?: number[]
/**
* This can be used to set which button starts toggled by default, and from there it will be controlled internally, toggledButtons will override this
*/
defaultToggle?: number
/**
* Numerical value for the size of the text for buttons that dont use the icon
*/
textSize?: number
/**
* When true will disable all of the buttons in the group, will be overridded by individual buttons disabled state in the button data
*/
disableAll?: boolean
}
const useStyles = makeStyles((theme: Theme) => {
return ({
container: {
backgroundColor: darken(
theme.palette.background.paper,
getThemeType() === "light" ? 0.10 : 0.05
),
borderRadius: 24,
content: "border-box",
border: "none",
//padding: theme.spacing(1),
},
button: {
backgroundColor: "transparent",
color: theme.palette.text.primary,
overflow: "visible",
content: "content-box",
borderRadius: 24,
marginLeft: theme.spacing(0.05),
marginRight: theme.spacing(0.05),
"&:hover": {
//backgroundColor: getSecondaryColour(), //use the colour of the whitelabel
backgroundColor: "gold", //for now Dustin just wants it to be gold
color: "black",
}
},
buttonToggled: {
//backgroundColor: getSecondaryColour(), //use the colour of the whitelabel
backgroundColor: "gold", //for now Dustin just wants it to be gold
color: "black",
borderRadius: 24,
fontWeight: "bold"
}
})
})
export default function ButtonGroup(props: Props){
const { buttons, toggle, toggledButtons, defaultToggle, multiToggle, textSize, disableAll } = props
const classes = useStyles()
const [currentToggle, setCurrentToggle] = useState<number[]>([])
useEffect(()=>{
//determine the default state of the button toggles if toggle is true
if(toggle){
let toggled: number [] = [0]
if(toggledButtons){
toggled = toggledButtons
} else if(defaultToggle){
toggled = [defaultToggle]
}
setCurrentToggle(toggled)
}
},[toggle, toggledButtons])
const checkToggled = (index: number) => {
return currentToggle.includes(index)
}
const toggleControl = (i: number) => {
let toggled = cloneDeep(currentToggle)
//is the button currently toggled
if(checkToggled(i)){
//if the button is toggled
if(multiToggle){
//un-toggle the button (remove it from the array)
console.log(toggled)
toggled.splice(currentToggle.indexOf(i), 1)
}
//and if it is single toggle do nothing
} else {
//if multiToggle is false
if(!multiToggle){
//replace the currentToggle array
toggled = [i]
}else{
//add it to the currentToggle array
toggled.push(i)
}
}
setCurrentToggle(toggled)
}
return (
<Box className={classes.container} display="flex" flexDirection="row">
{buttons.map((b, i) => (
<Button
disabled={disableAll ?? b.disabled}
key={i}
className={checkToggled(i) ? classes.buttonToggled : classes.button}
onClick={() => {
if(toggle){
//control the toggle internally if the array was not passed in
if(!toggledButtons){
toggleControl(i)
}
}
b.function()
}}>
{b.icon
?
b.icon
:
<Typography sx={{fontSize: textSize ?? 13, fontWeight: checkToggled(i) ? 650 : 500}}>
{b.title}
</Typography>
}
</Button>
))}
</Box>
)
}