Skip to content

Commit

Permalink
Solve conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
Diana Fulga committed Jan 22, 2024
2 parents e9e603a + fe4c099 commit c8cb49d
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 1 deletion.
55 changes: 55 additions & 0 deletions src/components/__tests__/input.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { render } from '@testing-library/react'
import React from 'react'

import { Input } from '@/components/input'

describe('Input', () => {
it('should default to `type="text"`', () => {
const { queryByLabelText } = render(<Input aria-label="test input" />)

expect(queryByLabelText('test input')).toBeInTheDocument()
expect(queryByLabelText('test input')).toHaveAttribute('type', 'text')
})

it('should not have the `disabled` attribute and `aria-disabled="false"` if `loading` is false', () => {
const { queryByLabelText } = render(<Input aria-label="test input" />)

expect(queryByLabelText('test input')).toBeInTheDocument()
expect(queryByLabelText('test input')).not.toHaveAttribute('disabled')
expect(queryByLabelText('test input')).toHaveAttribute('aria-disabled', 'false')
expect(queryByLabelText('test input')).not.toBeDisabled()
})

it('should have the `border-base` class by default', () => {
const { queryByLabelText } = render(<Input aria-label="test input" />)

expect(queryByLabelText('test input')).toBeInTheDocument()
expect(queryByLabelText('test input')).toHaveClass('border-base')
})

it('should have the `pl-12` class when the `icon` variant is passed', () => {
const { queryByLabelText } = render(<Input aria-label="test input" icon={<div />} />)

expect(queryByLabelText('test input')).toBeInTheDocument()
expect(queryByLabelText('test input')).toHaveClass('pl-12')
})

it('should have the `bg-disabled` and `border-transparent` classes when the `disabled` variant is passed', () => {
const { queryByLabelText } = render(<Input aria-label="test input" disabled />)

expect(queryByLabelText('test input')).toBeInTheDocument()
expect(queryByLabelText('test input')).toHaveClass('bg-disabled')
expect(queryByLabelText('test input')).toHaveClass('border-transparent')
})

it('should have the `aria-invalid` and `aria-describedby` attributes if errorMessage is present', () => {
const { queryByLabelText, queryByText } = render(
<Input aria-label="test input" errorMessage="some error" />,
)

expect(queryByLabelText('test input')).toBeInTheDocument()
expect(queryByLabelText('test input')).toHaveAttribute('aria-invalid')
expect(queryByLabelText('test input')).toHaveAttribute('aria-describedby')
expect(queryByText('some error')).toBeInTheDocument()
})
})
69 changes: 69 additions & 0 deletions src/components/__tests__/switch.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import '@testing-library/jest-dom'

import { fireEvent, render, screen } from '@testing-library/react'
import React from 'react'

import { Switch } from '@/components/switch'

describe('Switch', () => {
it('renders without crashing', () => {
render(<Switch />)
expect(screen.getByRole('switch')).toBeInTheDocument()
})

it('applies default classes', () => {
render(<Switch />)
const switchElement = screen.getByRole('switch').nextSibling
expect(switchElement).toHaveClass('w-[42px] h-[26px] before:h-5 before:w-5')
})

it('applies small size classes when size prop is small', () => {
render(<Switch size="small" />)
const switchElement = screen.getByRole('switch').nextSibling
expect(switchElement).toHaveClass('w-9 h-[22px] before:h-4 before:w-4 before:left-[3px]')
})

it('forwards ref to input element', () => {
const ref = React.createRef<HTMLInputElement>()
render(<Switch ref={ref} />)
expect(ref.current).toBeInstanceOf(HTMLInputElement)
})

it('forwards checked prop to input element', () => {
render(<Switch checked />)
const inputElement = screen.getByRole('switch')
expect(inputElement).toBeChecked()
})

it('handles additional props', () => {
render(<Switch aria-label="Custom Switch" />)
const inputElement = screen.getByRole('switch')
expect(inputElement).toHaveAttribute('aria-label', 'Custom Switch')
})

it('applies custom class names', () => {
const customClass = 'custom-class'
render(<Switch className={customClass} />)
const switchElement = screen.getByRole('switch').nextSibling
expect(switchElement).toHaveClass(customClass)
})

it('toggles switch state when clicked', () => {
render(<Switch />)
const inputElement = screen.getByRole('switch')
expect(inputElement).not.toBeChecked()

fireEvent.click(inputElement)
expect(inputElement).toBeChecked()

fireEvent.click(inputElement)
expect(inputElement).not.toBeChecked()
})

it('handles additional HTML attributes', () => {
const testId = 'switch-test'
render(<Switch data-testid={testId} />)
const switchElement = screen.getByTestId(testId)
expect(switchElement).toBeInTheDocument()
})
})
32 changes: 32 additions & 0 deletions src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,35 @@ export const Settings = (props: React.SVGProps<SVGSVGElement>) => {
</svg>
)
}

export const DollarSign = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}>
<g id="attach_money">
<mask
id="mask0_140_3168"
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="24"
height="24">
<rect id="Bounding box" width="24" height="24" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_140_3168)">
<path
id="attach_money_2"
d="M11.0252 21V18.85C10.1419 18.65 9.37953 18.2667 8.7382 17.7C8.0962 17.1333 7.6252 16.3333 7.3252 15.3L9.1752 14.55C9.4252 15.35 9.7962 15.9583 10.2882 16.375C10.7795 16.7917 11.4252 17 12.2252 17C12.9085 17 13.4879 16.846 13.9632 16.538C14.4379 16.2293 14.6752 15.75 14.6752 15.1C14.6752 14.5167 14.4919 14.054 14.1252 13.712C13.7585 13.3707 12.9085 12.9833 11.5752 12.55C10.1419 12.1 9.15853 11.5627 8.6252 10.938C8.09186 10.3127 7.8252 9.55 7.8252 8.65C7.8252 7.56667 8.1752 6.725 8.8752 6.125C9.5752 5.525 10.2919 5.18333 11.0252 5.1V3H13.0252V5.1C13.8585 5.23333 14.5462 5.53733 15.0882 6.012C15.6295 6.48733 16.0252 7.06667 16.2752 7.75L14.4252 8.55C14.2252 8.01667 13.9419 7.61667 13.5752 7.35C13.2085 7.08333 12.7085 6.95 12.0752 6.95C11.3419 6.95 10.7835 7.11267 10.4002 7.438C10.0169 7.76267 9.8252 8.16667 9.8252 8.65C9.8252 9.2 10.0752 9.63333 10.5752 9.95C11.0752 10.2667 11.9419 10.6 13.1752 10.95C14.3252 11.2833 15.1962 11.8123 15.7882 12.537C16.3795 13.2623 16.6752 14.1 16.6752 15.05C16.6752 16.2333 16.3252 17.1333 15.6252 17.75C14.9252 18.3667 14.0585 18.75 13.0252 18.9V21H11.0252Z"
fill="#475569"
/>
</g>
</g>
</svg>
)
}
56 changes: 56 additions & 0 deletions src/components/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { type VariantProps, cva } from 'class-variance-authority'
import React, { forwardRef } from 'react'

import { cn } from '@/utils/cn'

const inputVariants = cva(
[
'w-full h-14 rounded-xl border border-2 px-4 text-base text-medium',
'focus:outline-none focus:border-focus',
'placeholder-disabled',
],

{
variants: {
variant: {
default: 'border-base',
},
disabled: {
true: 'bg-disabled border-transparent',
},
},
defaultVariants: {
variant: 'default',
},
},
)

export interface InputProps
extends VariantProps<typeof inputVariants>,
React.InputHTMLAttributes<HTMLInputElement> {
errorMessage?: string
disabled?: boolean
icon?: React.ReactNode
}

export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
{ type = 'text', icon, errorMessage, disabled, className, ...props },
ref,
) {
return (
<div className="relative">
{icon && <div className="absolute left-4 top-4">{icon}</div>}
<input
ref={ref}
type={type}
className={cn(inputVariants({ disabled }), icon && 'pl-12', className)}
disabled={disabled ?? false}
aria-disabled={disabled ?? false}
aria-invalid={!!errorMessage}
aria-describedby={errorMessage}
{...props}
/>
{errorMessage && <p className="text-error text-sm px-2">{errorMessage}</p>}
</div>
)
})
23 changes: 23 additions & 0 deletions src/components/label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type VariantProps, cva } from 'class-variance-authority'
import React, { forwardRef } from 'react'

import { cn } from '@/utils/cn'

const labelVariants = cva('text-medium font-medium leading-6 px-2 flex items-center gap-2')

export interface LabelProps
extends VariantProps<typeof labelVariants>,
React.LabelHTMLAttributes<HTMLLabelElement> {
children: React.ReactNode
}

export const Label = forwardRef<HTMLLabelElement, LabelProps>(function Label(
{ className, children, ...props },
ref,
) {
return (
<label ref={ref} className={cn(labelVariants(), className)} {...props}>
{children}
</label>
)
})
54 changes: 54 additions & 0 deletions src/components/switch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { type VariantProps, cva } from 'class-variance-authority'
import React, { forwardRef } from 'react'

import { cn } from '@/utils/cn'

const switchVariants = cva(
[
'rounded-full bg-disabled-strong relative cursor-pointer transition-colors duration-300 ease-in-out',
'before:content-[""] before:absolute before:bg-white before:rounded-full',
'before:top-1/2 before:transform before:-translate-y-1/2 before:left-[4px]',
'before:transition-all before:duration-300 before:ease-in-out',
'peer-checked:before:left-[18px] peer-checked:bg-switch-base',
'peer-focus:outline peer-focus:outline-2 peer-focus:outline-blue-500',
],

{
variants: {
size: {
default: 'w-[42px] h-[26px] before:h-5 before:w-5',
small: [
'w-9 h-[22px] before:h-4 before:w-4 before:left-[3px]',
'peer-checked:before:left-4',
],
},
},
defaultVariants: {
size: 'default',
},
},
)

export interface SwitchProps
extends VariantProps<typeof switchVariants>,
React.HTMLAttributes<HTMLInputElement> {
checked?: boolean
}

export const Switch = forwardRef<HTMLInputElement, SwitchProps>(function Switch(
{ size, className, ...props },
ref,
) {
return (
<label>
<input
role="switch"
ref={ref}
type="checkbox"
{...props}
className="peer absolute opacity-0 -translate-x-[100%] pointer-events-none"
/>
<div className={cn(switchVariants({ size }), className)} />
</label>
)
})
3 changes: 2 additions & 1 deletion src/popup/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
/* Border colors */
--border-base: 203 213 225;
--border-focus: 59 130 246;

--border-error: 220 38 38;

/* Popup */
--popup-width: 448px;
--popup-height: 559px;
Expand Down
2 changes: 2 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ module.exports = {
'button-base': 'rgb(var(--bg-button-base) / <alpha-value>)',
'button-base-hover': 'rgb(var(--bg-button-base-hover) / <alpha-value>)',
'switch-base': 'rgb(var(--bg-switch-base) / <alpha-value>)',
'disabled-strong': 'rgb(var(--bg-disabled-strong) / <alpha-value>)',
'disabled-base': 'rgb(var(--bg-disabled-base) / <alpha-value>)',
'disabled-base-hover': 'rgb(var(--bg-disabled-base-hover) / <alpha-value>)',
},
borderColor: {
base: 'rgb(var(--border-base) / <alpha-value>)',
popup: 'rgb(var(--border-popup) / <alpha-value>)',
focus: 'rgb(var(--border-focus) / <alpha-value>)',
error: 'rgb(var(--border-error) / <alpha-value>)',
},
backgroundImage: {
'divider-gradient':
Expand Down

0 comments on commit c8cb49d

Please sign in to comment.