Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add sheet component #35

Merged
merged 6 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
},
"dependencies": {
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
Expand Down
37 changes: 37 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions src/presentation/components/ui/sheet/content/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ElementRef, forwardRef } from 'react'

import {
Content as ContentPrimitive,
Close as ClosePrimitive,
Portal as PortalPrimitive
} from '@radix-ui/react-dialog'
import { X } from 'lucide-react'

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

import { Overlay } from '../overlay'

import { sheetVariants } from './styles'
import { ContentProps } from './types'

export const Content = forwardRef<
ElementRef<typeof ContentPrimitive>,
ContentProps
>(({ side = 'right', className, children, ...props }, ref) => (
<PortalPrimitive>
<Overlay />
<ContentPrimitive
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<ClosePrimitive className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Fechar</span>
</ClosePrimitive>
</ContentPrimitive>
</PortalPrimitive>
))

Content.displayName = ContentPrimitive.displayName
18 changes: 18 additions & 0 deletions src/presentation/components/ui/sheet/content/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { cva } from 'class-variance-authority'
import clsx from 'clsx'

const baseStyles = clsx`flex flex-col fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500`

export const sheetVariants = cva(baseStyles, {
variants: {
side: {
top: clsx`inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top`,
bottom: clsx`inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom`,
left: clsx`inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm`,
right: clsx`inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm`
}
},
defaultVariants: {
side: 'right'
}
})
7 changes: 7 additions & 0 deletions src/presentation/components/ui/sheet/content/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Content } from '@radix-ui/react-dialog'
import { VariantProps } from 'class-variance-authority'

import { sheetVariants } from './styles'

export type ContentProps = React.ComponentPropsWithoutRef<typeof Content> &
VariantProps<typeof sheetVariants>
18 changes: 18 additions & 0 deletions src/presentation/components/ui/sheet/description.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { forwardRef, ElementRef, ComponentPropsWithoutRef } from 'react'

import { Description as DescriptionPrimitive } from '@radix-ui/react-dialog'

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

export const Description = forwardRef<
ElementRef<typeof DescriptionPrimitive>,
ComponentPropsWithoutRef<typeof DescriptionPrimitive>
>(({ className, ...props }, ref) => (
<DescriptionPrimitive
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
))

Description.displayName = DescriptionPrimitive.displayName
16 changes: 16 additions & 0 deletions src/presentation/components/ui/sheet/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { cn } from '@/main/utils'

export const Footer = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col-reverse gap-4 mt-auto sm:flex-row sm:justify-center',
className
)}
{...props}
/>
)

Footer.displayName = 'SheetFooter'
16 changes: 16 additions & 0 deletions src/presentation/components/ui/sheet/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { cn } from '@/main/utils'

export const Header = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col space-y-2 text-center sm:text-left',
className
)}
{...props}
/>
)

Header.displayName = 'SheetHeader'
76 changes: 76 additions & 0 deletions src/presentation/components/ui/sheet/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Meta, StoryFn } from '@storybook/react/'

import { Button } from '../button'
import { Input } from '../input'
import { Label } from '../label'

import { ContentProps } from './content/types'

import { Sheet } from '.'

export default {
title: 'Components/UI/Sheet'
} as Meta

const Template: StoryFn<ContentProps> = ({ side, ...args }) => (
<Sheet.Root>
<Sheet.Trigger asChild>
<Button variant="outline">{side}</Button>
</Sheet.Trigger>
<Sheet.Content {...args} side={side}>
<Sheet.Header>
<Sheet.Title>Edit profile</Sheet.Title>
<Sheet.Description>
Make changes to your profile here. Click save when you are done.
</Sheet.Description>
</Sheet.Header>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Username
</Label>
<Input id="username" value="@peduarte" className="col-span-3" />
</div>
</div>
<Sheet.Footer>
<Sheet.Close asChild>
<Button className="w-full" type="submit" variant="outline">
Close
</Button>
</Sheet.Close>

<Sheet.Close asChild>
<Button className="w-full" type="submit">
Save changes
</Button>
</Sheet.Close>
</Sheet.Footer>
</Sheet.Content>
</Sheet.Root>
)

export const Top = Template.bind({})
Top.args = {
side: 'top'
}

export const Right = Template.bind({})
Right.args = {
side: 'right'
}

export const Bottom = Template.bind({})
Bottom.args = {
side: 'bottom'
}

export const Left = Template.bind({})
Left.args = {
side: 'left'
}
21 changes: 21 additions & 0 deletions src/presentation/components/ui/sheet/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Root, Portal, Trigger, Close } from '@radix-ui/react-dialog'

import { Content } from './content'
import { Description } from './description'
import { Footer } from './footer'
import { Header } from './header'
import { Overlay } from './overlay'
import { Title } from './title'

export const Sheet = {
Root,
Portal,
Overlay,
Trigger,
Close,
Content,
Header,
Footer,
Title,
Description
}
21 changes: 21 additions & 0 deletions src/presentation/components/ui/sheet/overlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { forwardRef, ElementRef, ComponentPropsWithoutRef } from 'react'

import { Overlay as OverlayPrimitive } from '@radix-ui/react-dialog'

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

export const Overlay = forwardRef<
ElementRef<typeof OverlayPrimitive>,
ComponentPropsWithoutRef<typeof OverlayPrimitive>
>(({ className, ...props }, ref) => (
<OverlayPrimitive
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className
)}
{...props}
ref={ref}
/>
))

Overlay.displayName = OverlayPrimitive.displayName
18 changes: 18 additions & 0 deletions src/presentation/components/ui/sheet/title.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { forwardRef, ElementRef, ComponentPropsWithoutRef } from 'react'

import { Title as TitlePrimitive } from '@radix-ui/react-dialog'

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

export const Title = forwardRef<
ElementRef<typeof TitlePrimitive>,
ComponentPropsWithoutRef<typeof TitlePrimitive>
>(({ className, ...props }, ref) => (
<TitlePrimitive
ref={ref}
className={cn('text-lg font-semibold text-foreground', className)}
{...props}
/>
))

Title.displayName = TitlePrimitive.displayName
Loading