Skip to content

Commit

Permalink
fix: fixes after review
Browse files Browse the repository at this point in the history
  • Loading branch information
iatopilskii committed Dec 3, 2024
1 parent a46685d commit fc00601
Show file tree
Hide file tree
Showing 15 changed files with 279 additions and 204 deletions.
12 changes: 6 additions & 6 deletions packages/ui/src/components/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ const buttonVariants = cva(
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
tertiary: 'bg-tertiary text-secondary-foreground shadow-sm hover:bg-tertiary/80',
default: 'bg-primary text-primary-foreground hover:bg-primary/90 shadow',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm',
outline: 'border-input bg-background hover:bg-accent hover:text-accent-foreground border shadow-sm',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80 shadow-sm',
tertiary: 'bg-tertiary text-secondary-foreground hover:bg-tertiary/80 shadow-sm',
ghost: 'hover:bg-background-12 hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
link_accent: 'text-foreground-accent underline-offset-4 hover:underline',
Expand All @@ -34,7 +34,7 @@ const buttonVariants = cva(
},
borderRadius: {
default: '',
full: 'rounded-full',
full: 'rounded-full focus-visible:rounded-full',
none: 'rounded-none'
},
theme: {
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { forwardRef, HTMLAttributes } from 'react'
import { cn } from '@utils/cn'
import { cva, type VariantProps } from 'class-variance-authority'

const cardVariants = cva('rounded-lg border bg-card text-card-foreground shadow', {
const cardVariants = cva('bg-card text-card-foreground rounded-lg border shadow', {
variants: {
variant: {
default: '',
Expand All @@ -19,7 +19,7 @@ export interface CardProps extends HTMLAttributes<HTMLDivElement>, VariantProps<
width?: 'auto' | 'full' | 'screen' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | string
}

const widthClasses = {
const widthVariants = {
auto: 'w-auto',
full: 'w-full',
screen: 'w-screen',
Expand All @@ -33,9 +33,9 @@ const widthClasses = {
}

const Card = forwardRef<HTMLDivElement, CardProps>(({ variant, className, width = 'auto', ...props }, ref) => {
const widthClass = widthClasses[width as keyof typeof widthClasses] || width
const widthClassName = widthVariants[width as keyof typeof widthVariants] || width

return <div ref={ref} className={cn(cardVariants({ variant }), widthClass, className)} {...props} />
return <div ref={ref} className={cn(cardVariants({ variant }), widthClassName, className)} {...props} />
})

Card.displayName = 'Card'
Expand Down
20 changes: 20 additions & 0 deletions packages/ui/src/components/control-group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { HTMLAttributes } from 'react'

import { cn } from '@utils/cn'

interface ControlGroupProps extends HTMLAttributes<HTMLDivElement> {
type?: 'button' | 'input'
}

export function ControlGroup({ children, type, className, ...props }: ControlGroupProps) {
return (
<div
className={cn('relative flex flex-col', { 'mt-2': type === 'button' }, className)}
role="group"
aria-label={type === 'button' ? 'Button control group' : 'Input control group'}
{...props}
>
{children}
</div>
)
}
37 changes: 37 additions & 0 deletions packages/ui/src/components/form-error-message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { HTMLAttributes } from 'react'

import { cn } from '@utils/cn'

import { Text } from './text'

export enum ErrorMessageTheme {
SUCCESS = 'success',
WARNING = 'warning',
ERROR = 'error',
DEFAULT = 'default'
}

interface FormErrorMessageProps extends HTMLAttributes<HTMLDivElement> {
theme: ErrorMessageTheme
}

const themeClassMap: Record<ErrorMessageTheme, string> = {
[ErrorMessageTheme.SUCCESS]: 'text-success',
[ErrorMessageTheme.WARNING]: 'text-warning',
[ErrorMessageTheme.ERROR]: 'text-foreground-danger',
[ErrorMessageTheme.DEFAULT]: 'text-tertiary-background'
}

export function FormErrorMessage({ children, theme, className }: FormErrorMessageProps) {
const textClass = themeClassMap[theme]
const role = theme === ErrorMessageTheme.ERROR ? 'alert' : 'status'
const ariaLive = theme === ErrorMessageTheme.ERROR ? 'assertive' : 'polite'

return (
<div className={cn(textClass, className)} role={role} aria-live={ariaLive}>
<Text as="p" size={2} className="text-inherit">
{children}
</Text>
</div>
)
}
2 changes: 2 additions & 0 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export * from './dialog'
export * from './path-breadcrumbs'
export * from './card'
export * from './input-otp'
export * from './control-group'
export * from './form-error-message'

export * as ShaBadge from './sha-badge'
export * as ListActions from './list-actions'
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/input-otp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const InputOTPSlot = forwardRef<HTMLDivElement, InputOTPSlotProps>(({ index, cla
{char}
{hasFakeCaret && (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="animate-caret-blink h-4 w-px bg-foreground duration-1000" />
<div className="animate-caret-blink bg-foreground-1 h-4 w-px duration-1000" />
</div>
)}
</div>
Expand Down
157 changes: 66 additions & 91 deletions packages/ui/src/components/input.tsx
Original file line number Diff line number Diff line change
@@ -1,119 +1,94 @@
import { forwardRef, InputHTMLAttributes } from 'react'
import { forwardRef, InputHTMLAttributes, ReactNode } from 'react'

import { cva, VariantProps } from 'class-variance-authority'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from '../utils/cn'
import { Text } from './'
import { ControlGroup } from './control-group'
import { ErrorMessageTheme, FormErrorMessage } from './form-error-message'
import { Label } from './label'
import { Text } from './text'

export interface BaseInputProps
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'>,
VariantProps<typeof inputVariants> {
wrapperClassName?: string
error?: string
}
VariantProps<typeof inputVariants> {}

const inputVariants = cva(
'remove-autocomplete-styles bg-transparent placeholder:text-foreground-5 text-foreground-1 px-3 py-1',
{
variants: {
variant: {
default:
'flex h-9 w-full rounded border text-sm shadow-sm transition-colors file:border-0 focus-visible:outline-none file:bg-transparent file:text-sm file:font-medium placeholder:text-foreground-4 disabled:cursor-not-allowed disabled:opacity-50',
extended: 'grow border-none focus-visible:outline-none'
},
theme: {
default: 'border-borders-2 focus-visible:border-borders-3',
danger: 'border-borders-danger'
}
const inputVariants = cva('text-foreground-1 bg-transparent px-2.5 py-1 disabled:cursor-not-allowed', {
variants: {
variant: {
default:
'placeholder:text-foreground-4 flex w-full rounded border text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:rounded focus-visible:outline-none',
extended: 'grow border-none focus-visible:outline-none'
},
size: {
32: 'h-8',
36: 'h-9'
},
theme: {
default:
'border-borders-2 focus-visible:border-borders-3 disabled:border-borders-1 disabled:placeholder:text-foreground-9',
danger: 'border-borders-danger'
}
},
defaultVariants: {
variant: 'default',
theme: 'default',
size: 32
}
)
})

const BaseInput = forwardRef<HTMLInputElement, BaseInputProps>(
({ className, type, variant = 'default', theme = 'default', error, wrapperClassName, ...props }, ref) => {
return (
<div className={cn('relative flex flex-col', wrapperClassName)}>
<input
className={cn(
inputVariants({ variant, theme }),
className,
error ? 'border-borders-danger' : 'border-borders-2'
)}
type={type}
ref={ref}
{...props}
/>
{error && (
<Text
className="absolute top-full translate-y-1 text-foreground-danger leading-none tracking-tight"
weight="light"
size={0}
>
{error}
</Text>
)}
</div>
)
({ className, type, variant, size, theme, ...props }, ref) => {
return <input className={cn(inputVariants({ variant, size, theme }), className)} type={type} ref={ref} {...props} />
}
)

BaseInput.displayName = 'BaseInput'

export interface ExtendedInputProps extends BaseInputProps {
left?: React.ReactNode
leftStyle?: boolean
leftClassName?: string
right?: React.ReactNode
rightStyle?: boolean
rightClassName?: string
interface InputError {
theme: ErrorMessageTheme
message?: string
}

const containerClassName =
'remove-autocomplete-styles flex h-9 w-full rounded border border-input text-sm shadow-sm transition-colors placeholder:text-foreground-4 focus-within:outline-none focus-within:ring-1 focus-within:ring-ring disabled:cursor-not-allowed disabled:opacity-50'
const leftRightCommonClassName = 'flex items-center text-muted-foreground'
interface InputProps extends BaseInputProps {
label?: string
caption?: ReactNode
error?: InputError
optional?: boolean
wrapperClassName?: string
}

const ExtendedInput = forwardRef<HTMLInputElement, ExtendedInputProps>(
({ className, type, left, leftStyle, leftClassName, right, rightStyle, rightClassName, ...props }, ref) => {
const Input = forwardRef<HTMLInputElement, InputProps>(
({ label, caption, error, id, theme, disabled, optional, className, wrapperClassName, ...props }, ref) => {
return (
<div className={cn(containerClassName, className)}>
{left && (
<div
className={cn(
leftRightCommonClassName,
'rounded-l',
leftStyle ? 'bg-muted border-r' : '-mr-3',
leftClassName
)}
>
{left}
</div>
<ControlGroup className={wrapperClassName}>
{label && (
<Label className="mb-2.5" color={disabled ? 'foreground-9' : 'foreground-2'} optional={optional} htmlFor={id}>
{label}
</Label>
)}
<BaseInput
className={className}
id={id}
ref={ref}
theme={error ? 'danger' : theme}
disabled={disabled}
{...props}
/>
{error && (
<FormErrorMessage className={cn(caption ? 'mt-1' : 'absolute top-full translate-y-1')} theme={error.theme}>
{error.message}
</FormErrorMessage>
)}
<BaseInput className={className} type={type} {...props} ref={ref} variant="extended" />
{right && (
<div
className={cn(
leftRightCommonClassName,
'rounded-r',
rightStyle ? 'bg-muted border-l' : '-ml-3',
rightClassName
)}
>
{right}
</div>
{caption && (
<Text className="text-foreground-4 mt-1 leading-snug" size={2}>
{caption}
</Text>
)}
</div>
</ControlGroup>
)
}
)
ExtendedInput.displayName = 'ExtendedInput'

interface InputProps extends ExtendedInputProps {}

const Input = forwardRef<HTMLInputElement, InputProps>(({ left, right, ...props }, ref) => {
if (left || right) {
return <ExtendedInput left={left} right={right} {...props} ref={ref} />
}
return <BaseInput {...props} ref={ref} />
})
Input.displayName = 'Input'

export { Input }
Expand Down
44 changes: 30 additions & 14 deletions packages/ui/src/components/label.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,49 @@
// ToDo: Need to be reviewed by the XD team

import { ComponentPropsWithoutRef, ElementRef, forwardRef } from 'react'
import { ComponentPropsWithoutRef, ElementRef, forwardRef, PropsWithChildren } from 'react'

import * as LabelPrimitive from '@radix-ui/react-label'
import { cn } from '@utils/cn'
import { cva, type VariantProps } from 'class-variance-authority'

const labelVariants = cva('block leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', {
const labelVariants = cva('peer-disabled:cursor-not-allowed peer-disabled:opacity-70', {
variants: {
variant: {
default: 'text-sm leading-none',
sm: 'text-xs font-light'
default: 'text-sm font-normal leading-none'
},
color: {
'foreground-1': 'text-foreground-1',
'foreground-2': 'text-foreground-2',
'foreground-5': 'text-foreground-5',
'foreground-9': 'text-foreground-9'
}
},
defaultVariants: {
variant: 'default'
variant: 'default',
color: 'foreground-1'
}
})

const Label = forwardRef<
const LabelRoot = forwardRef<
ElementRef<typeof LabelPrimitive.Root>,
ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
>(({ className, variant, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn('text-foreground-2', labelVariants({ variant }), className)}
{...props}
/>
Omit<ComponentPropsWithoutRef<typeof LabelPrimitive.Root>, 'color'> & VariantProps<typeof labelVariants>
>(({ className, variant, color, ...props }, ref) => (
<LabelPrimitive.Root ref={ref} className={cn(labelVariants({ variant, color }), className)} {...props} />
))
Label.displayName = LabelPrimitive.Root.displayName
LabelRoot.displayName = LabelPrimitive.Root.displayName

interface LabelProps extends VariantProps<typeof labelVariants>, PropsWithChildren {
htmlFor?: string
optional?: boolean
className?: string
}

const Label = ({ htmlFor, optional, color, variant, children, className }: LabelProps) => {
return (
<LabelRoot htmlFor={htmlFor} variant={variant} color={color} className={className}>
{children} {optional && <span className="text-foreground-7 align-top">(optional)</span>}
</LabelRoot>
)
}

export { Label }
Loading

0 comments on commit fc00601

Please sign in to comment.