-
-
Notifications
You must be signed in to change notification settings - Fork 783
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ui): adds many components to design system (#232)
- Loading branch information
Showing
28 changed files
with
781 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { render, screen } from '@noodle/test-utils/renderer'; | ||
|
||
import { AspectRatio } from '.'; | ||
|
||
describe('Aspect Ratio', () => { | ||
it('should render children', () => { | ||
render( | ||
<AspectRatio ratio={16 / 9}> | ||
<div>children</div> | ||
</AspectRatio>, | ||
); | ||
|
||
expect(screen.getByText('children')).toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { type FC } from 'react'; | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { AspectRatio } from '.'; | ||
|
||
const component: FC<{ ratio: number }> = ({ ratio }) => ( | ||
<div className="w-[450px] overflow-hidden"> | ||
<AspectRatio ratio={ratio}> | ||
<img | ||
src="https://source.unsplash.com/random/450x450" | ||
className="object-cover" | ||
alt="random" | ||
/> | ||
</AspectRatio> | ||
</div> | ||
); | ||
|
||
export default { | ||
title: 'UI / Aspect Ratio', | ||
component, | ||
args: { | ||
ratio: 16 / 9, | ||
}, | ||
} as Meta<typeof component>; | ||
|
||
type Story = StoryObj<typeof component>; | ||
|
||
export const _16_9: Story = {}; | ||
|
||
export const _1_1: Story = { | ||
args: { | ||
ratio: 1, | ||
}, | ||
}; | ||
|
||
export const _4_3: Story = { | ||
args: { | ||
ratio: 4 / 3, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio'; | ||
|
||
const AspectRatio = AspectRatioPrimitive.Root; | ||
|
||
export { AspectRatio }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { render, screen } from '@noodle/test-utils/renderer'; | ||
|
||
import { Avatar, AvatarFallback, AvatarImage } from '.'; | ||
|
||
declare global { | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions | ||
interface Window { | ||
Image: typeof Image; | ||
} | ||
} | ||
|
||
class MockImage extends Image { | ||
override set onload(value: (() => void) | null) { | ||
super.onload = value; | ||
} | ||
|
||
override set src(value: string) { | ||
super.src = value; | ||
if (this.onload) { | ||
this.onload(); | ||
} | ||
} | ||
} | ||
|
||
describe('Avatar', () => { | ||
let originalImage: typeof Image; | ||
|
||
beforeAll(() => { | ||
// Save the original Image object | ||
originalImage = window.Image; | ||
|
||
// Assign the mock Image | ||
window.Image = MockImage as unknown as typeof Image; | ||
}); | ||
|
||
afterAll(() => { | ||
// Restore the original Image object after all tests in this block are done | ||
window.Image = originalImage; | ||
}); | ||
|
||
it('should render the image', () => { | ||
render( | ||
<Avatar> | ||
<AvatarImage | ||
src="https://avatars.githubusercontent.com/u/20271968?v=4" | ||
alt="@ixahmedxi" | ||
/> | ||
</Avatar>, | ||
); | ||
|
||
expect(screen.getByRole('img')).toHaveAttribute( | ||
'src', | ||
'https://avatars.githubusercontent.com/u/20271968?v=4', | ||
); | ||
}); | ||
|
||
it('should render the fallback', () => { | ||
render( | ||
<Avatar> | ||
<AvatarFallback>AE</AvatarFallback> | ||
</Avatar>, | ||
); | ||
|
||
expect(screen.getByText('AE')).toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { type FC } from 'react'; | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { Avatar, AvatarFallback, AvatarImage } from '.'; | ||
|
||
const component: FC<{ fallback: boolean }> = ({ fallback }) => { | ||
return ( | ||
<Avatar> | ||
{!fallback && ( | ||
<AvatarImage | ||
src="https://avatars.githubusercontent.com/u/20271968?v=4" | ||
alt="@ixahmedxi" | ||
/> | ||
)} | ||
<AvatarFallback>AE</AvatarFallback> | ||
</Avatar> | ||
); | ||
}; | ||
|
||
export default { | ||
title: 'Design System / Avatar', | ||
component, | ||
args: { | ||
fallback: false, | ||
}, | ||
} as Meta<typeof component>; | ||
|
||
type Story = StoryObj<typeof component>; | ||
|
||
export const Image: Story = {}; | ||
|
||
export const Fallback: Story = { | ||
args: { | ||
fallback: true, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { forwardRef } from 'react'; | ||
import type { ComponentPropsWithoutRef, ElementRef } from 'react'; | ||
import { Fallback, Image, Root } from '@radix-ui/react-avatar'; | ||
|
||
import { cn } from '../utils/cn'; | ||
|
||
export const Avatar = forwardRef< | ||
ElementRef<typeof Root>, | ||
ComponentPropsWithoutRef<typeof Root> | ||
>(({ className, ...props }, ref) => ( | ||
<Root | ||
ref={ref} | ||
className={cn( | ||
'relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
|
||
Avatar.displayName = Root.displayName; | ||
|
||
export const AvatarImage = forwardRef< | ||
ElementRef<typeof Image>, | ||
ComponentPropsWithoutRef<typeof Image> | ||
>(({ className, ...props }, ref) => ( | ||
<Image | ||
ref={ref} | ||
className={cn('aspect-square h-full w-full', className)} | ||
{...props} | ||
/> | ||
)); | ||
|
||
AvatarImage.displayName = Image.displayName; | ||
|
||
export const AvatarFallback = forwardRef< | ||
ElementRef<typeof Fallback>, | ||
ComponentPropsWithoutRef<typeof Fallback> | ||
>(({ className, ...props }, ref) => ( | ||
<Fallback | ||
ref={ref} | ||
className={cn( | ||
'from-primary-500 via-primary-800 to-primary-500 text-gray-12 flex h-full w-full items-center justify-center rounded-full bg-gradient-to-tr font-medium', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
|
||
AvatarFallback.displayName = Fallback.displayName; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,7 @@ | ||
export { Brand } from './brand'; | ||
export { cn } from './utils/cn'; | ||
export * from './brand'; | ||
export * from './utils/cn'; | ||
export * from './typography'; | ||
export * from './aspect-ratio'; | ||
export * from './skeleton'; | ||
export * from './avatar'; | ||
export * from './tooltip'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { type HTMLAttributes } from 'react'; | ||
|
||
import { cn } from '../utils/cn'; | ||
|
||
export const Skeleton = ({ | ||
className, | ||
...props | ||
}: HTMLAttributes<HTMLDivElement>) => { | ||
return ( | ||
<div | ||
role="presentation" | ||
className={cn( | ||
'bg-gray-3 dark:bg-graydark-3 animate-pulse rounded-lg', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { render, screen } from '@noodle/test-utils/renderer'; | ||
|
||
import { Skeleton } from '.'; | ||
|
||
describe('Skeleton', () => { | ||
it('should render the component', () => { | ||
render(<Skeleton />); | ||
|
||
expect(screen.getByRole('presentation')).toHaveClass('animate-pulse'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { Skeleton } from '.'; | ||
|
||
const component = () => { | ||
return ( | ||
<div className="flex items-center space-x-4"> | ||
<Skeleton className="h-12 w-12 rounded-full" /> | ||
<div className="space-y-2"> | ||
<Skeleton className="h-4 w-[250px]" /> | ||
<Skeleton className="h-4 w-[200px]" /> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default { | ||
title: 'UI / Skeleton', | ||
component, | ||
} as Meta; | ||
|
||
type Story = StoryObj; | ||
|
||
export const Default: Story = { | ||
name: 'Skeleton', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import * as React from 'react'; | ||
import * as TooltipPrimitive from '@radix-ui/react-tooltip'; | ||
|
||
import { cn } from '../utils/cn'; | ||
|
||
const TooltipProvider = TooltipPrimitive.Provider; | ||
|
||
const Tooltip = TooltipPrimitive.Root; | ||
|
||
const TooltipTrigger = TooltipPrimitive.Trigger; | ||
|
||
const TooltipContent = React.forwardRef< | ||
React.ElementRef<typeof TooltipPrimitive.Content>, | ||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> | ||
>(({ className, sideOffset = 4, ...props }, ref) => ( | ||
<TooltipPrimitive.Content | ||
ref={ref} | ||
sideOffset={sideOffset} | ||
className={cn( | ||
'animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 bg-gray-3 dark:bg-graydark-3 border-gray-6 dark:border-graydark-6 text-gray-11 dark:text-graydark-11 z-50 overflow-hidden rounded-lg border px-2 py-1.5 text-sm', | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
|
||
TooltipContent.displayName = TooltipPrimitive.Content.displayName; | ||
|
||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import userEvent from '@testing-library/user-event'; | ||
|
||
import { render, screen } from '@noodle/test-utils/renderer'; | ||
|
||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '.'; | ||
|
||
describe('Tooltip', () => { | ||
it('should render the tooltip content', async () => { | ||
render( | ||
<TooltipProvider> | ||
<Tooltip> | ||
<TooltipTrigger>Trigger Tooltip</TooltipTrigger> | ||
<TooltipContent> | ||
<p className="max-w-[40ch] text-center"> | ||
You can invoke the bold styling by clicking on this button or | ||
using the CMD + B keyboard shortcut. | ||
</p> | ||
</TooltipContent> | ||
</Tooltip> | ||
</TooltipProvider>, | ||
); | ||
|
||
await userEvent.hover( | ||
screen.getByRole('button', { name: /trigger tooltip/i }), | ||
); | ||
|
||
const all = await screen.findAllByText(/invoke the bold styling/i); | ||
|
||
// IDK why but it renders twice | ||
expect(all).toHaveLength(2); | ||
}); | ||
}); |
Oops, something went wrong.