import { HTMLAttributes } from 'react'; import { motion } from 'framer-motion'; import styled from 'styled-components'; import { background, BackgroundProps, border, BorderProps, ButtonStyleProps, compose, flexbox, FlexboxProps, grid, GridProps, layout, LayoutProps, opacity, OpacityProps, position, PositionProps, space, SpaceProps, style, textStyle, TextStyleProps, typography, TypographyProps, } from 'styled-system'; import { ColorProps, colorStyle, ColorVariants } from '../../util/colors'; type TextDecorationOption = 'overline' | 'line-through' | 'underline'; type TextTransformOption = 'uppercase' | 'lowercase' | 'capitalize'; export type ButtonProps = { gap?: string | number | undefined; pointerEvents?: boolean; } & BackgroundProps & ButtonStyleProps & ColorProps & FlexboxProps & GridProps & BorderProps & LayoutProps & OpacityProps & PositionProps & SpaceProps & TextStyleProps & TypographyProps & { textDecoration?: | TextDecorationOption | Array; textTransform?: | TextTransformOption | Array; } & HTMLAttributes; const textDecoration = style({ prop: 'textDecoration', cssProperty: 'textDecoration', }); const pointerEvents = style({ prop: 'pointerEvents', cssProperty: 'pointerEvents', transformValue: (value: boolean | undefined) => { if (value === undefined) return 'auto'; return !value ? 'none' : 'auto'; }, }); const textTransform = style({ prop: 'textTransform', cssProperty: 'textTransform', }); const buttonStyles = compose( background, flexbox, grid, layout, opacity, position, space, textStyle, textDecoration, pointerEvents, textTransform, typography, border ); const Base = styled(motion.button)` box-sizing: border-box; appearance: none; width: fit-content; display: inline-flex; user-select: none; align-items: center; flex-basis: initial; font-size: 0.889rem; gap: 4px; border: 1px solid transparent; border-radius: var(--rlm-border-radius-4); transition: var(--transition); ${buttonStyles} ${colorStyle} &:hover:not([disabled]) { cursor: pointer; transition: var(--transition); filter: brightness(0.975); } &:active:not([disabled]) { transition: var(--transition); filter: brightness(0.95); } &:disabled { opacity: 0.5; transition: var(--transition); } svg { pointer-events: none; } `; const Primary = styled(Base)` background-color: rgba(var(--rlm-accent-rgba)); color: #ffffff; &:hover:not([disabled]) { background-color: rgba(var(--rlm-accent-rgba)); filter: brightness(1.1); } &:active:not([disabled]) { background-color: rgba(var(--rlm-accent-rgba)); filter: brightness(1.2); } svg { fill: #ffffff; } `; const Secondary = styled(Base)` color: rgba(var(--rlm-text-rgba)); background-color: rgba(var(--rlm-window-rgba)); filter: brightness(0.975); &:hover:not([disabled]) { background-color: rgba(var(--rlm-window-rgba)); filter: brightness(0.975); } &:active:not([disabled]) { background-color: rgba(var(--rlm-window-rgba)); filter: brightness(0.925); } `; const Minimal = styled(Base)` color: rgba(var(--rlm-accent-rgba)); background-color: rgba(var(--rlm-accent-rgba), 0.1); &:hover:not([disabled]) { background-color: rgba(var(--rlm-accent-rgba), 0.15); } &:active:not([disabled]) { background-color: rgba(var(--rlm-accent-rgba), 0.3); } svg { fill: rgba(var(--rlm-accent-rgba)); } `; const Transparent = styled(Base)` color: rgba(var(--rlm-text-rgba)); background-color: transparent; &:hover:not([disabled]) { background-color: rgba(var(--rlm-window-rgba)); filter: brightness(0.975); } &:active:not([disabled]) { background-color: rgba(var(--rlm-window-rgba)); filter: brightness(0.95); } svg { fill: rgba(var(--rlm-text-rgba)); } `; type TextButtonProps = ButtonProps & { showOnHover?: boolean }; const TextButton = styled(Base)` font-weight: 500; padding: 4px 8px; color: ${(props) => props.color ? `rgba(var(--rlm-${props.color}-rgba))` : 'rgba(var(--rlm-accent-rgba))'}; background-color: ${(props) => props.showOnHover ? 'transparent' : props.color ? `rgba(var(--rlm-${props.color}-rgba), 0.1)` : 'rgba(var(--rlm-accent-rgba), 0.1)'}; &:hover:not([disabled]) { background-color: ${(props) => props.color ? `rgba(var(--rlm-${props.color}-rgba), 0.15)` : 'rgba(var(--rlm-accent-rgba), 0.15)'}; } &:active:not([disabled]) { background-color: ${(props) => props.color ? `rgba(var(--rlm-${props.color}-rgba), 0.2)` : 'rgba(var(--rlm-accent-rgba), 0.2)'}; } svg { fill: rgba(var(--rlm-accent-rgba)); } `; export type IconButtonProps = ButtonProps & { showOnHover?: boolean; isSelected?: boolean; customColor?: ColorVariants; }; const IconButton = styled(Base)` padding: 0px; display: flex; flex-direction: row; align-items: center; justify-content: center; background-color: ${({ isSelected }) => isSelected ? 'rgba(var(--rlm-overlay-active-rgba))' : 'transparent'}; transition: var(--transition); &:hover:not([disabled]) { background-color: rgba(var(--rlm-overlay-hover-rgba)); } svg { fill: ${({ customColor }) => customColor ? `rgba(var(--rlm-${customColor}-rgba))` : 'rgba(var(--rlm-icon-rgba))'}; } `; export const Button = { Base, Primary, Secondary, Minimal, Transparent, TextButton, IconButton, };