* icon picker functionalities and UI implemented * appicon component added for icon picker * PR comments resolved * PR comment on appicon size resolved * icon picker story fixed and enum added for names
341 lines
9.9 KiB
TypeScript
341 lines
9.9 KiB
TypeScript
import React from "react";
|
|
import { CommonComponentProps, hexToRgba, ThemeProp } from "./common";
|
|
import styled from "styled-components";
|
|
import Icon, { IconName } from "./Icon";
|
|
import Spinner from "./Spinner";
|
|
import {
|
|
mediumButton,
|
|
smallButton,
|
|
largeButton,
|
|
} from "../../constants/DefaultTheme";
|
|
|
|
export enum Category {
|
|
primary = "primary",
|
|
secondary = "secondary",
|
|
tertiary = "tertiary",
|
|
}
|
|
|
|
export enum Variant {
|
|
success = "success",
|
|
info = "info",
|
|
warning = "warning",
|
|
danger = "danger",
|
|
}
|
|
|
|
export enum Size {
|
|
small = "small",
|
|
medium = "medium",
|
|
large = "large",
|
|
}
|
|
|
|
type stateStyleType = {
|
|
bgColorPrimary: string;
|
|
borderColorPrimary: string;
|
|
txtColorPrimary: string;
|
|
bgColorSecondary: string;
|
|
borderColorSecondary: string;
|
|
txtColorSecondary: string;
|
|
bgColorTertiary: string;
|
|
borderColorTertiary: string;
|
|
txtColorTertiary: string;
|
|
};
|
|
|
|
type BtnColorType = {
|
|
bgColor: string;
|
|
txtColor: string;
|
|
border: string;
|
|
};
|
|
|
|
type BtnFontType = {
|
|
buttonFont: any;
|
|
padding: string;
|
|
};
|
|
|
|
type ButtonProps = CommonComponentProps & {
|
|
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
|
text?: string;
|
|
category?: Category;
|
|
variant?: Variant;
|
|
icon?: IconName;
|
|
size?: Size;
|
|
};
|
|
|
|
const stateStyles = (
|
|
props: ThemeProp & ButtonProps,
|
|
state: string,
|
|
): stateStyleType => {
|
|
let bgColorPrimary,
|
|
borderColorPrimary,
|
|
txtColorPrimary,
|
|
bgColorSecondary,
|
|
borderColorSecondary,
|
|
txtColorSecondary,
|
|
bgColorTertiary,
|
|
borderColorTertiary,
|
|
txtColorTertiary;
|
|
|
|
if (props.isLoading || props.disabled) {
|
|
switch (props.category) {
|
|
case Category.primary:
|
|
if (props.variant) {
|
|
bgColorPrimary = props.theme.colors[props.variant].darkest;
|
|
borderColorPrimary = props.theme.colors[props.variant].darkest;
|
|
}
|
|
txtColorPrimary = props.theme.colors.blackShades[6];
|
|
break;
|
|
case Category.secondary:
|
|
if (props.variant) {
|
|
bgColorSecondary = props.theme.colors[props.variant].darkest;
|
|
borderColorSecondary = props.theme.colors[props.variant].darker;
|
|
}
|
|
txtColorSecondary = props.theme.colors.blackShades[6];
|
|
break;
|
|
case Category.tertiary:
|
|
bgColorTertiary = props.theme.colors.tertiary.darker;
|
|
borderColorTertiary = props.theme.colors.tertiary.dark;
|
|
txtColorTertiary = props.theme.colors.blackShades[6];
|
|
break;
|
|
}
|
|
} else if (state === "main") {
|
|
switch (props.category) {
|
|
case Category.primary:
|
|
if (props.variant) {
|
|
bgColorPrimary = props.theme.colors[props.variant].main;
|
|
borderColorPrimary = props.theme.colors[props.variant].main;
|
|
}
|
|
txtColorPrimary = props.theme.colors.blackShades[9];
|
|
break;
|
|
case Category.secondary:
|
|
if (props.variant) {
|
|
borderColorSecondary = props.theme.colors[props.variant].main;
|
|
txtColorSecondary = props.theme.colors[props.variant].main;
|
|
}
|
|
bgColorSecondary = "transparent";
|
|
break;
|
|
case Category.tertiary:
|
|
bgColorTertiary = "transparent";
|
|
borderColorTertiary = props.theme.colors.tertiary.main;
|
|
txtColorTertiary = props.theme.colors.tertiary.main;
|
|
break;
|
|
}
|
|
} else if (state === "hover") {
|
|
switch (props.category) {
|
|
case Category.primary:
|
|
if (props.variant) {
|
|
bgColorPrimary = props.theme.colors[props.variant].dark;
|
|
borderColorPrimary = props.theme.colors[props.variant].dark;
|
|
}
|
|
txtColorPrimary = props.theme.colors.blackShades[9];
|
|
break;
|
|
case Category.secondary:
|
|
if (props.variant) {
|
|
bgColorSecondary = hexToRgba(
|
|
props.theme.colors[props.variant].main,
|
|
0.1,
|
|
);
|
|
txtColorSecondary = props.theme.colors[props.variant].main;
|
|
borderColorSecondary = props.theme.colors[props.variant].main;
|
|
}
|
|
break;
|
|
case Category.tertiary:
|
|
bgColorTertiary = hexToRgba(props.theme.colors.tertiary.main, 0.1);
|
|
borderColorTertiary = props.theme.colors.tertiary.main;
|
|
txtColorTertiary = props.theme.colors.tertiary.main;
|
|
break;
|
|
}
|
|
} else if (state === "active") {
|
|
switch (props.category) {
|
|
case Category.primary:
|
|
if (props.variant) {
|
|
bgColorPrimary = props.theme.colors[props.variant].dark;
|
|
borderColorPrimary = props.theme.colors[props.variant].main;
|
|
}
|
|
txtColorPrimary = props.theme.colors.blackShades[9];
|
|
break;
|
|
case Category.secondary:
|
|
if (props.variant) {
|
|
bgColorSecondary = hexToRgba(
|
|
props.theme.colors[props.variant].main,
|
|
0.1,
|
|
);
|
|
txtColorSecondary = props.theme.colors[props.variant].light;
|
|
borderColorSecondary = props.theme.colors[props.variant].light;
|
|
}
|
|
break;
|
|
case Category.tertiary:
|
|
bgColorTertiary = hexToRgba(props.theme.colors.tertiary.main, 0.1);
|
|
borderColorTertiary = props.theme.colors.tertiary.light;
|
|
txtColorTertiary = props.theme.colors.tertiary.light;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return {
|
|
bgColorPrimary,
|
|
borderColorPrimary,
|
|
txtColorPrimary,
|
|
bgColorSecondary,
|
|
borderColorSecondary,
|
|
txtColorSecondary,
|
|
bgColorTertiary,
|
|
borderColorTertiary,
|
|
txtColorTertiary,
|
|
};
|
|
};
|
|
|
|
const btnColorStyles = (
|
|
props: ThemeProp & ButtonProps,
|
|
state: string,
|
|
): BtnColorType => {
|
|
let bgColor = "",
|
|
txtColor = "",
|
|
border = "";
|
|
switch (props.category) {
|
|
case Category.primary:
|
|
bgColor = stateStyles(props, state).bgColorPrimary;
|
|
txtColor = stateStyles(props, state).txtColorPrimary;
|
|
border = `2px solid ${stateStyles(props, state).borderColorPrimary}`;
|
|
break;
|
|
case Category.secondary:
|
|
bgColor = stateStyles(props, state).bgColorSecondary;
|
|
txtColor = stateStyles(props, state).txtColorSecondary;
|
|
border = `2px solid ${stateStyles(props, state).borderColorSecondary}`;
|
|
break;
|
|
case Category.tertiary:
|
|
bgColor = stateStyles(props, state).bgColorTertiary;
|
|
txtColor = stateStyles(props, state).txtColorTertiary;
|
|
border = `2px solid ${stateStyles(props, state).borderColorTertiary}`;
|
|
break;
|
|
}
|
|
return { bgColor, txtColor, border };
|
|
};
|
|
|
|
const btnFontStyles = (props: ThemeProp & ButtonProps): BtnFontType => {
|
|
let buttonFont,
|
|
padding = "";
|
|
switch (props.size) {
|
|
case Size.small:
|
|
buttonFont = smallButton;
|
|
padding =
|
|
!props.text && props.icon
|
|
? `${props.theme.spaces[1]}px ${props.theme.spaces[1]}px`
|
|
: `${props.theme.spaces[1]}px ${props.theme.spaces[6]}px ${props.theme
|
|
.spaces[1] - 1}px`;
|
|
break;
|
|
case Size.medium:
|
|
buttonFont = mediumButton;
|
|
padding =
|
|
!props.text && props.icon
|
|
? `${props.theme.spaces[2]}px ${props.theme.spaces[2]}px`
|
|
: `${props.theme.spaces[3] - 1}px ${props.theme.spaces[7]}px`;
|
|
break;
|
|
case Size.large:
|
|
buttonFont = largeButton;
|
|
padding =
|
|
!props.text && props.icon
|
|
? `${props.theme.spaces[3]}px`
|
|
: `${props.theme.spaces[5] - 1}px ${props.theme.spaces[12] - 4}px`;
|
|
break;
|
|
}
|
|
return { buttonFont, padding };
|
|
};
|
|
|
|
const StyledButton = styled("button")<ThemeProp & ButtonProps>`
|
|
border: none;
|
|
outline: none;
|
|
text-transform: uppercase;
|
|
background-color: ${props => btnColorStyles(props, "main").bgColor};
|
|
color: ${props => btnColorStyles(props, "main").txtColor};
|
|
border: ${props => btnColorStyles(props, "main").border};
|
|
border-radius: ${props => props.theme.radii[0]};
|
|
${props => btnFontStyles(props).buttonFont};
|
|
padding: ${props => btnFontStyles(props).padding};
|
|
.ads-icon {
|
|
margin-right: ${props =>
|
|
props.text && props.icon ? `${props.theme.spaces[4]}px` : `0`}
|
|
path {
|
|
fill: ${props => btnColorStyles(props, "main").txtColor};
|
|
}
|
|
}
|
|
&:hover {
|
|
background-color: ${props => btnColorStyles(props, "hover").bgColor};
|
|
color: ${props => btnColorStyles(props, "hover").txtColor};
|
|
border: ${props => btnColorStyles(props, "hover").border};
|
|
cursor: ${props =>
|
|
props.isLoading || props.disabled ? `not-allowed` : `pointer`};
|
|
.ads-icon {
|
|
margin-right: ${props =>
|
|
props.text && props.icon ? `${props.theme.spaces[4]}px` : `0`}
|
|
path {
|
|
fill: ${props => btnColorStyles(props, "hover").txtColor};
|
|
}
|
|
}
|
|
}
|
|
font-style: normal;
|
|
&:active {
|
|
background-color: ${props => btnColorStyles(props, "active").bgColor};
|
|
color: ${props => btnColorStyles(props, "active").txtColor};
|
|
border: ${props => btnColorStyles(props, "active").border};
|
|
cursor: ${props =>
|
|
props.isLoading || props.disabled ? `not-allowed` : `pointer`};
|
|
.ads-icon {
|
|
path {
|
|
fill: ${props => btnColorStyles(props, "active").txtColor};
|
|
}
|
|
}
|
|
}
|
|
display: flex;
|
|
position: relative;
|
|
.new-spinner {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
`;
|
|
|
|
Button.defaultProps = {
|
|
category: Category.primary,
|
|
variant: Variant.success,
|
|
size: Size.small,
|
|
isLoading: false,
|
|
disabled: false,
|
|
};
|
|
|
|
export const VisibilityWrapper = styled.div`
|
|
visibility: hidden;
|
|
`;
|
|
|
|
function Button(props: ButtonProps) {
|
|
const IconLoadingState = (
|
|
<Icon name={props.icon} size={props.size} invisible={true} />
|
|
);
|
|
|
|
const TextLoadingState = <VisibilityWrapper>{props.text}</VisibilityWrapper>;
|
|
|
|
return (
|
|
<StyledButton
|
|
data-cy={props.cypressSelector}
|
|
{...props}
|
|
onClick={(e: React.MouseEvent<HTMLElement>) =>
|
|
props.onClick && props.onClick(e)
|
|
}
|
|
>
|
|
{props.icon ? (
|
|
props.isLoading ? (
|
|
IconLoadingState
|
|
) : (
|
|
<Icon name={props.icon} size={props.size} />
|
|
)
|
|
) : null}
|
|
|
|
{props.text ? (props.isLoading ? TextLoadingState : props.text) : null}
|
|
|
|
{props.isLoading ? <Spinner size={props.size} /> : null}
|
|
</StyledButton>
|
|
);
|
|
}
|
|
|
|
export default Button;
|