feat: improve ui components
This commit is contained in:
+21
-15
@@ -1,35 +1,41 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes'
|
||||
import { FontAwesomeIcon, type FontAwesomeIconProps } from '@fortawesome/react-fontawesome'
|
||||
import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
|
||||
import { type DetailedHTMLProps, type FC, type HTMLAttributes, type ReactNode } from 'react'
|
||||
import IconButton, { type IconButtonProps } from './IconButton'
|
||||
|
||||
export type AlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps>
|
||||
type ComposedAlertProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, AlertVariantProps>
|
||||
|
||||
const Alert: FC<AlertProps> = ({ children, className, ...props }) => {
|
||||
const [alertArgs, allOtherProps] = alert.splitVariantProps(props)
|
||||
const Alert: FC<ComposedAlertProps> = ({ className, children, ...props }) => {
|
||||
const [alertRecipeArgs, allOtherAlertProps] = alert.splitVariantProps(props)
|
||||
return (
|
||||
<div
|
||||
className={cx(alert(alertArgs).body, className)}
|
||||
{...allOtherProps}
|
||||
className={cx(alert(alertRecipeArgs).body, className)}
|
||||
{...allOtherAlertProps}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export type AlertCloseButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, AlertVariantProps>
|
||||
type ComposedAlertCloseButtonProps = MergeOmitting<IconButtonProps, AlertVariantProps> & {
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
export const AlertCloseButton: FC<AlertCloseButtonProps> = ({ children, className, ...props }) => {
|
||||
const [alertArgs, allOtherProps] = alert.splitVariantProps(props)
|
||||
export const AlertCloseButton: FC<ComposedAlertCloseButtonProps> = ({ children, className, ...props }) => {
|
||||
const [alertRecipeArgs, allOtherAlertProps] = alert.splitVariantProps(props)
|
||||
return (
|
||||
<button
|
||||
className={cx(alert(alertArgs).closeButton, className)}
|
||||
{...allOtherProps}
|
||||
<IconButton
|
||||
className={cx(alert(alertRecipeArgs).closeButton, className)}
|
||||
{...allOtherAlertProps}
|
||||
>
|
||||
{children !== undefined ? children : <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth />}
|
||||
</button>
|
||||
{children === undefined
|
||||
? <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth size='sm' />
|
||||
: children
|
||||
}
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { buttonGroup, type ButtonGroupVariantProps } from '@/styled-system/recipes/button-group'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
|
||||
|
||||
export type ButtonGroupProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, ButtonGroupVariantProps>
|
||||
|
||||
const ButtonGroup: FC<ButtonGroupProps> = ({ children, className, ...rest }) => {
|
||||
const [buttonGroupRecipeArgs, allOtherButtonGroupProps] = buttonGroup.splitVariantProps(rest)
|
||||
return (
|
||||
<div
|
||||
className={cx(buttonGroup(buttonGroupRecipeArgs), className)}
|
||||
{...allOtherButtonGroupProps}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ButtonGroup
|
||||
@@ -0,0 +1,19 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { chip, type ChipVariantProps } from '@/styled-system/recipes/chip'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
|
||||
|
||||
export type ChipProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, ChipVariantProps>
|
||||
|
||||
const Chip: FC<ChipProps> = ({ children, className, ...rest }) => {
|
||||
const [chipRecipeArgs, allOtherChipProps] = chip.splitVariantProps(rest)
|
||||
return (
|
||||
<span
|
||||
className={cx(chip(chipRecipeArgs), className)}
|
||||
{...allOtherChipProps}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
export default Chip
|
||||
@@ -0,0 +1,36 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { collapse, type CollapseVariantProps } from '@/styled-system/recipes/collapse'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type DetailsHTMLAttributes, type FC, type HTMLAttributes, type ReactNode } from 'react'
|
||||
|
||||
export type CollapseProps = MergeOmitting<DetailedHTMLProps<DetailsHTMLAttributes<HTMLDetailsElement>, HTMLDetailsElement>, CollapseVariantProps> & {
|
||||
children?: ReactNode
|
||||
contentProps?: HTMLAttributes<HTMLElement>
|
||||
summary: ReactNode
|
||||
summaryProps?: HTMLAttributes<HTMLElement>
|
||||
}
|
||||
|
||||
const Collapse: FC<CollapseProps> = ({ children, className, summary, summaryProps, contentProps, ...rest }) => {
|
||||
const [collapseRecipeArgs, allOtherCollapseProps] = collapse.splitVariantProps(rest)
|
||||
return (
|
||||
<details
|
||||
className={cx(collapse(collapseRecipeArgs).root, className)}
|
||||
{...allOtherCollapseProps}
|
||||
>
|
||||
<summary
|
||||
{...summaryProps}
|
||||
className={cx(collapse(collapseRecipeArgs).summary, summaryProps?.className)}
|
||||
>
|
||||
{summary}
|
||||
</summary>
|
||||
<div
|
||||
{...contentProps}
|
||||
className={cx(collapse(collapseRecipeArgs).content, contentProps?.className)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</details>
|
||||
)
|
||||
}
|
||||
|
||||
export default Collapse
|
||||
@@ -1,9 +1,9 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import React, { type FC } from 'react'
|
||||
import { type ButtonHTMLAttributes, type DetailedHTMLProps, type FC } from 'react'
|
||||
|
||||
type ComposedIconButtonProps = MergeOmitting<React.HTMLAttributes<HTMLButtonElement>, IconButtonVariantProps>
|
||||
type ComposedIconButtonProps = MergeOmitting<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, IconButtonVariantProps>
|
||||
|
||||
export interface IconButtonProps extends ComposedIconButtonProps {}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { listGroup, type ListGroupVariantProps } from '@/styled-system/recipes/list-group'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type FC, type HTMLAttributes } from 'react'
|
||||
|
||||
type ComposedInputProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLUListElement>, HTMLUListElement>, ListGroupVariantProps>
|
||||
|
||||
const ListGroup: FC<ComposedInputProps> = ({ children, className, ...rest }) => {
|
||||
const [listGroupRecipeArgs, allOtherListGroupProps] = listGroup.splitVariantProps(rest)
|
||||
return (
|
||||
<ul
|
||||
className={cx(listGroup(listGroupRecipeArgs).root, className)}
|
||||
{...allOtherListGroupProps}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListGroup
|
||||
@@ -0,0 +1,19 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { listGroup, type ListGroupVariantProps } from '@/styled-system/recipes/list-group'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type FC, type LiHTMLAttributes } from 'react'
|
||||
|
||||
type ComposedInputProps = MergeOmitting<DetailedHTMLProps<LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, ListGroupVariantProps>
|
||||
|
||||
const ListGroupItem: FC<ComposedInputProps> = ({ children, className, ...rest }) => {
|
||||
const [listGroupRecipeArgs, allOtherListGroupProps] = listGroup.splitVariantProps(rest)
|
||||
return (
|
||||
<li
|
||||
className={cx(listGroup(listGroupRecipeArgs).item, className)}
|
||||
{...allOtherListGroupProps}
|
||||
>
|
||||
{children}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
export default ListGroupItem
|
||||
@@ -0,0 +1,28 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { tooltip, type TooltipVariantProps } from '@/styled-system/recipes/tooltip'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type FC, type HTMLAttributes, type ReactNode } from 'react'
|
||||
|
||||
type ComposedTooltipProps = MergeOmitting<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, TooltipVariantProps> & {
|
||||
title: ReactNode
|
||||
}
|
||||
|
||||
const Tooltip: FC<ComposedTooltipProps> = ({ children, className, title, ...rest }) => {
|
||||
const [tooltipRecipeArgs, allOtherTooltipProps] = tooltip.splitVariantProps(rest)
|
||||
return (
|
||||
<div
|
||||
className={cx(tooltip(tooltipRecipeArgs), className)}
|
||||
{...allOtherTooltipProps}
|
||||
>
|
||||
{children}
|
||||
<span
|
||||
className="tooltip__content"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Tooltip
|
||||
@@ -1,9 +1,9 @@
|
||||
import { cx } from '@/styled-system/css'
|
||||
import { typography, type TypographyVariantProps } from '@/styled-system/recipes'
|
||||
import { typography, type TypographyVariantProps } from '@/styled-system/recipes/typography'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import React, { type ElementType, type FC } from 'react'
|
||||
import { type ElementType, type FC, type HTMLAttributes } from 'react'
|
||||
|
||||
type ComposedTypographyProps = MergeOmitting<React.HTMLAttributes<HTMLElement>, TypographyVariantProps>
|
||||
type ComposedTypographyProps = MergeOmitting<HTMLAttributes<HTMLElement>, TypographyVariantProps>
|
||||
|
||||
export interface TypographyProps extends ComposedTypographyProps {
|
||||
component?: ElementType
|
||||
@@ -33,19 +33,14 @@ const variantToComponent = (variant: TypographyVariantProps['variant']): Element
|
||||
}
|
||||
}
|
||||
|
||||
const isHeading = (text: string): boolean => {
|
||||
return text.startsWith('h')
|
||||
}
|
||||
|
||||
const Typography: FC<TypographyProps> = ({ children, className, component, ...rest }) => {
|
||||
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
|
||||
const Component = component ?? variantToComponent(typographyRecipeArgs.variant)
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
typographyRecipeArgs.color = typographyRecipeArgs.color !== undefined
|
||||
? typographyRecipeArgs.color
|
||||
: typeof typographyRecipeArgs.variant === 'string' && isHeading(typographyRecipeArgs.variant)
|
||||
typographyRecipeArgs.color = typographyRecipeArgs.color ?? (
|
||||
typeof typographyRecipeArgs.variant === 'string' && typographyRecipeArgs.variant.startsWith('h')
|
||||
? 'primary'
|
||||
: undefined
|
||||
: 'inherit'
|
||||
)
|
||||
return (
|
||||
<Component
|
||||
className={cx(typography(typographyRecipeArgs), className)}
|
||||
|
||||
@@ -3,15 +3,20 @@ import { input, type InputVariantProps } from '@/styled-system/recipes/input'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { type DetailedHTMLProps, type FC, type InputHTMLAttributes } from 'react'
|
||||
|
||||
export type InputProps = MergeOmitting<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, InputVariantProps>
|
||||
type ComposedInputProps = MergeOmitting<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, InputVariantProps>
|
||||
|
||||
const Input: FC<InputProps> = ({ className, ...props }) => {
|
||||
const [inputCss, rest] = input.splitVariantProps(props)
|
||||
export interface InputProps extends ComposedInputProps {}
|
||||
|
||||
const Input: FC<InputProps> = ({ children, className, ...rest }) => {
|
||||
const [inputRecipeArgs, allOtherInputProps] = input.splitVariantProps(rest)
|
||||
return (
|
||||
<input
|
||||
className={cx(input(inputCss), className)}
|
||||
{...rest}
|
||||
/>
|
||||
className={cx(input(inputRecipeArgs), className)}
|
||||
{...allOtherInputProps}
|
||||
>
|
||||
{children}
|
||||
</input>
|
||||
)
|
||||
}
|
||||
|
||||
export default Input
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import IconButton from '@/components/ui/IconButton'
|
||||
import Tooltip from '@/components/ui/Tooltip'
|
||||
import { css, cx } from '@/styled-system/css'
|
||||
import { input, type InputVariantProps } from '@/styled-system/recipes/input'
|
||||
import { type MergeOmitting } from '@/types/utilities'
|
||||
import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { useState, type FC, type InputHTMLAttributes } from 'react'
|
||||
|
||||
export type InputProps = MergeOmitting<Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>, InputVariantProps>
|
||||
|
||||
const PasswordInput: FC<InputProps> = ({ className, ...props }) => {
|
||||
const [showPassword, setShowPassword] = useState(false)
|
||||
const [inputCss, rest] = input.splitVariantProps(props)
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
position: 'relative'
|
||||
})}
|
||||
>
|
||||
<input
|
||||
className={cx(
|
||||
input(inputCss),
|
||||
css({ fontSize: 'medium' }),
|
||||
className
|
||||
)}
|
||||
{...rest}
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
/>
|
||||
<div
|
||||
className={css({
|
||||
position: 'absolute',
|
||||
right: '16px',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)'
|
||||
})}
|
||||
>
|
||||
<Tooltip
|
||||
title={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
|
||||
position="top"
|
||||
>
|
||||
<IconButton
|
||||
type="button"
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={() => { setShowPassword(!showPassword) }}
|
||||
>
|
||||
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} fixedWidth/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default PasswordInput
|
||||
Reference in New Issue
Block a user