Files
modeling-app/src/components/ActionButton.tsx

95 lines
2.8 KiB
TypeScript
Raw Normal View History

import { ActionIcon, ActionIconProps } from './ActionIcon'
2023-07-27 18:59:40 -04:00
import React from 'react'
import { paths } from '../Router'
import { Link } from 'react-router-dom'
import type { LinkProps } from 'react-router-dom'
interface BaseActionButtonProps {
icon?: ActionIconProps
className?: string
}
type ActionButtonAsButton = BaseActionButtonProps &
Omit<
React.ButtonHTMLAttributes<HTMLButtonElement>,
keyof BaseActionButtonProps
> & {
Element: 'button'
}
type ActionButtonAsLink = BaseActionButtonProps &
Omit<LinkProps, keyof BaseActionButtonProps> & {
Element: 'link'
}
type ActionButtonAsExternal = BaseActionButtonProps &
Omit<LinkProps, keyof BaseActionButtonProps> & {
Element: 'externalLink'
}
type ActionButtonAsElement = BaseActionButtonProps &
Omit<React.HTMLAttributes<HTMLElement>, keyof BaseActionButtonProps> & {
Element: React.ComponentType<React.HTMLAttributes<HTMLButtonElement>>
}
type ActionButtonProps =
| ActionButtonAsButton
| ActionButtonAsLink
| ActionButtonAsExternal
| ActionButtonAsElement
export const ActionButton = (props: ActionButtonProps) => {
const classNames = `group mono text-base flex items-center gap-2 rounded-sm border border-chalkboard-40 dark:border-chalkboard-60 hover:border-liquid-40 dark:hover:bg-chalkboard-90 p-[3px] text-chalkboard-110 dark:text-chalkboard-10 hover:text-chalkboard-110 hover:dark:text-chalkboard-10 ${
props.icon ? 'pr-2' : 'px-2'
} ${props.className || ''}`
switch (props.Element) {
case 'button': {
// Note we have to destructure 'className' and 'Element' out of props
// because we don't want to pass them to the button element;
// the same is true for the other cases below.
const { Element, icon, children, className, ...rest } = props
return (
<button className={classNames} {...rest}>
{props.icon && <ActionIcon {...icon} />}
{children}
</button>
)
}
case 'link': {
const { Element, to, icon, children, className, ...rest } = props
return (
<Link to={to || paths.INDEX} className={classNames} {...rest}>
{icon && <ActionIcon {...icon} />}
{children}
</Link>
)
}
case 'externalLink': {
const { Element, to, icon, children, className, ...rest } = props
return (
<Link
to={to || paths.INDEX}
className={classNames}
{...rest}
target="_blank"
>
{icon && <ActionIcon {...icon} />}
{children}
</Link>
)
}
default: {
const { Element, icon, children, className, ...rest } = props
if (!Element) throw new Error('Element is required')
return (
<Element className={classNames} {...rest}>
{props.icon && <ActionIcon {...props.icon} />}
{children}
</Element>
)
}
2023-07-27 18:59:40 -04:00
}
}