feat: improve ui components
This commit is contained in:
+4
-1
@@ -192,4 +192,7 @@ dist
|
|||||||
# End of https://www.toptal.com/developers/gitignore/api/node,yarn,nextjs
|
# End of https://www.toptal.com/developers/gitignore/api/node,yarn,nextjs
|
||||||
|
|
||||||
# Panda Css
|
# Panda Css
|
||||||
src/styled-system
|
src/styled-system
|
||||||
|
|
||||||
|
# Vscode
|
||||||
|
.vscode
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"appwrite": "^13.0.1",
|
"appwrite": "^13.0.1",
|
||||||
"entgamers-database": "^0.0.5",
|
"entgamers-database": "^0.0.5",
|
||||||
"entgamers-panda-preset": "0.1.0",
|
"entgamers-panda-preset": "0.1.1",
|
||||||
"formik": "^2.4.5",
|
"formik": "^2.4.5",
|
||||||
"framer-motion": "^10.16.16",
|
"framer-motion": "^10.16.16",
|
||||||
"isomorphic-fetch": "^3.0.0",
|
"isomorphic-fetch": "^3.0.0",
|
||||||
|
|||||||
+21
-15
@@ -1,35 +1,41 @@
|
|||||||
import { cx } from '@/styled-system/css'
|
import { cx } from '@/styled-system/css'
|
||||||
import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert'
|
import { alert, type AlertVariantProps } from '@/styled-system/recipes/alert'
|
||||||
import { type MergeOmitting } from '@/types/utilities'
|
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 { 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 Alert: FC<ComposedAlertProps> = ({ className, children, ...props }) => {
|
||||||
const [alertArgs, allOtherProps] = alert.splitVariantProps(props)
|
const [alertRecipeArgs, allOtherAlertProps] = alert.splitVariantProps(props)
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cx(alert(alertArgs).body, className)}
|
className={cx(alert(alertRecipeArgs).body, className)}
|
||||||
{...allOtherProps}
|
{...allOtherAlertProps}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</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 }) => {
|
export const AlertCloseButton: FC<ComposedAlertCloseButtonProps> = ({ children, className, ...props }) => {
|
||||||
const [alertArgs, allOtherProps] = alert.splitVariantProps(props)
|
const [alertRecipeArgs, allOtherAlertProps] = alert.splitVariantProps(props)
|
||||||
return (
|
return (
|
||||||
<button
|
<IconButton
|
||||||
className={cx(alert(alertArgs).closeButton, className)}
|
className={cx(alert(alertRecipeArgs).closeButton, className)}
|
||||||
{...allOtherProps}
|
{...allOtherAlertProps}
|
||||||
>
|
>
|
||||||
{children !== undefined ? children : <FontAwesomeIcon icon={faTimes as FontAwesomeIconProps['icon']} fixedWidth />}
|
{children === undefined
|
||||||
</button>
|
? <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 { cx } from '@/styled-system/css'
|
||||||
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
|
import { iconButton, type IconButtonVariantProps } from '@/styled-system/recipes/icon-button'
|
||||||
import { type MergeOmitting } from '@/types/utilities'
|
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 {}
|
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 { 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 { 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 {
|
export interface TypographyProps extends ComposedTypographyProps {
|
||||||
component?: ElementType
|
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 Typography: FC<TypographyProps> = ({ children, className, component, ...rest }) => {
|
||||||
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
|
const [typographyRecipeArgs, allOtherTypographyProps] = typography.splitVariantProps(rest)
|
||||||
const Component = component ?? variantToComponent(typographyRecipeArgs.variant)
|
const Component = component ?? variantToComponent(typographyRecipeArgs.variant)
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
typographyRecipeArgs.color = typographyRecipeArgs.color ?? (
|
||||||
typographyRecipeArgs.color = typographyRecipeArgs.color !== undefined
|
typeof typographyRecipeArgs.variant === 'string' && typographyRecipeArgs.variant.startsWith('h')
|
||||||
? typographyRecipeArgs.color
|
|
||||||
: typeof typographyRecipeArgs.variant === 'string' && isHeading(typographyRecipeArgs.variant)
|
|
||||||
? 'primary'
|
? 'primary'
|
||||||
: undefined
|
: 'inherit'
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<Component
|
<Component
|
||||||
className={cx(typography(typographyRecipeArgs), className)}
|
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 MergeOmitting } from '@/types/utilities'
|
||||||
import { type DetailedHTMLProps, type FC, type InputHTMLAttributes } from 'react'
|
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 }) => {
|
export interface InputProps extends ComposedInputProps {}
|
||||||
const [inputCss, rest] = input.splitVariantProps(props)
|
|
||||||
|
const Input: FC<InputProps> = ({ children, className, ...rest }) => {
|
||||||
|
const [inputRecipeArgs, allOtherInputProps] = input.splitVariantProps(rest)
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
className={cx(input(inputCss), className)}
|
className={cx(input(inputRecipeArgs), className)}
|
||||||
{...rest}
|
{...allOtherInputProps}
|
||||||
/>
|
>
|
||||||
|
{children}
|
||||||
|
</input>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default 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