Skip to content

Commit

Permalink
fix/modal (#273)
Browse files Browse the repository at this point in the history
* fix: made modal footer button lg

* fix: updated form modal styles to match design, used asChild prop to get rid of nested buttons

* refactor: moved Modal.example to ModalForm.example

* refactor: updated styling for modals and added info and custom modal examples

* fix: right aligned buttons on custom modal to show layout options
  • Loading branch information
nstolpe committed Jan 5, 2024
1 parent 09f203b commit 9fa7d43
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 83 deletions.
80 changes: 59 additions & 21 deletions src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import * as React from 'react'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import { CloseIcon } from '@/assets'
import { cva, type VariantProps } from 'class-variance-authority'

import { CloseIcon } from '@/assets'
import { cn } from '@/lib/utils'

const Modal = DialogPrimitive.Root
Expand Down Expand Up @@ -35,7 +36,7 @@ const ModalContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 shadow-lg bg-background dark:bg-foreground duration-200 sm:rounded-lg',
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-6 shadow-lg bg-background dark:bg-foreground duration-200 sm:rounded-lg',
className
)}
{...props}
Expand All @@ -46,31 +47,47 @@ const ModalContent = React.forwardRef<
))
ModalContent.displayName = DialogPrimitive.Content.displayName

const headerVariants = cva(
[
'flex',
'items-center',
'justify-between',
'p-6',
'space-y-1.5',
'text-center',
'sm:text-left',
'border-border-subtle',
'dark:border-border-subtle-dark'
],
{
variants: {
variant: {
default: ['border-b'],
form: ['pb-0', 'border-b-0']
}
},
defaultVariants: {
variant: 'default'
}
}
)

const ModalHeader = ({
className,
variant,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex items-center justify-between p-6 space-y-1.5 text-center sm:text-left',
className
)}
{...props}
/>
}: React.HTMLAttributes<HTMLDivElement> &
VariantProps<typeof headerVariants>) => (
<div className={cn(headerVariants({ variant, className }))} {...props} />
)

ModalHeader.displayName = 'ModalHeader'

const ModalFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col-reverse p-6 sm:flex-row sm:justify-start sm:space-x-2',
className
)}
{...props}
/>
<div className={cn('flex flex-col p-6 pt-0 gap-2.5', className)} {...props} />
)
ModalFooter.displayName = 'ModalFooter'

Expand Down Expand Up @@ -108,17 +125,38 @@ const ModalClose = React.forwardRef<
</DialogPrimitive.Close>
))

const descriptionVariants = cva(
[
'text-sm',
'text-foreground-muted',
'border-border-subtle',
'dark:border-border-subtle-dark'
],
{
variants: {
variant: {
default: ['border-b'],
form: ['border-b-0']
}
},
defaultVariants: {
variant: 'default'
}
}
)

const ModalDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> &
VariantProps<typeof descriptionVariants>
>(({ className, variant, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn('text-sm px-6 text-foreground-muted', className)}
className={cn(descriptionVariants({ variant, className }))}
{...props}
/>
))
ModalDescription.displayName = DialogPrimitive.Description.displayName
ModalDescription.displayName = 'ModalDescription'

export {
Modal,
Expand Down
13 changes: 11 additions & 2 deletions stories/Modal/Docs.mdx
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { Canvas, Meta } from '@storybook/blocks'

import * as ModalStories from './Modal.stories'
import { ModalInfoDemo } from './ModalInfo.example'

<Meta of={ModalStories} />

# Modal

A modal is a window that can be overlaid on the main window, which when opened, the main window is left partially visible and doesn't allow any user interaction.

## Default
## Info

<Canvas of={ModalStories.Default} />
<Canvas of={ModalStories.Info} />

## Custom

<Canvas of={ModalStories.Custom} />

## Form

<Canvas of={ModalStories.Form} />

## Attributes

Expand Down
54 changes: 0 additions & 54 deletions stories/Modal/Modal.example.tsx

This file was deleted.

23 changes: 17 additions & 6 deletions stories/Modal/Modal.stories.ts → stories/Modal/Modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
import type { Meta, StoryObj } from '@storybook/react'

import { ModalDemo } from './Modal.example'
import { ModalInfoDemo } from './ModalInfo.example'
import { ModalCustomDemo } from './ModalCustom.example'
import { ModalFormDemo } from './ModalForm.example'

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
const meta = {
title: 'Components/Modal',
component: ModalDemo,
component: ModalFormDemo,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
layout: 'centered'
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
argTypes: {
className: {
controle: 'text',
control: 'text',
description: 'Alter the className to change the style'
}
}
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
} satisfies Meta<typeof ModalDemo>
} satisfies Meta<typeof ModalFormDemo>

export default meta
type Story = StoryObj<typeof meta>

// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Default: Story = {
args: {}

export const Info: Story = {
render: () => <ModalInfoDemo />
}

export const Custom: Story = {
render: () => <ModalCustomDemo />
}

export const Form: Story = {
render: () => <ModalFormDemo />
}
39 changes: 39 additions & 0 deletions stories/Modal/ModalCustom.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
Modal,
ModalContent,
ModalClose,
ModalFooter,
ModalDescription,
ModalHeader,
ModalTitle,
ModalTrigger
} from '@/components/Modal'
import { Button } from '@/components'

export const ModalCustomDemo = () => (
<Modal>
<Button size="sm" variant="primary" asChild>
<ModalTrigger>Open</ModalTrigger>
</Button>
<ModalContent>
<ModalHeader>
<ModalTitle>Title</ModalTitle>
<ModalClose />
</ModalHeader>
<ModalDescription asChild>
<div>
<div className="bg-blue-50 dark:bg-blue-900 dark:text-foreground-inverse h-40 text-lg font-semibold items-center flex justify-center mb-6 mx-6">
Replace this component with your content
</div>
</div>
</ModalDescription>
<ModalFooter>
<div className="flex justify-end gap-2.5">
<Button variant="tertiary">Label</Button>
<Button variant="secondary">Label</Button>
<Button>Label</Button>
</div>
</ModalFooter>
</ModalContent>
</Modal>
)
46 changes: 46 additions & 0 deletions stories/Modal/ModalForm.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
Modal,
ModalContent,
ModalClose,
ModalCloseFooter,
ModalFooter,
ModalDescription,
ModalHeader,
ModalTitle,
ModalTrigger
} from '@/components/Modal'
import { Button } from '@/components'

export const ModalFormDemo = () => (
<Modal>
<Button size="sm" variant="primary" asChild>
<ModalTrigger>Open</ModalTrigger>
</Button>
<ModalContent>
<ModalHeader variant="form">
<ModalTitle>Title</ModalTitle>
<ModalClose />
</ModalHeader>
<ModalDescription variant="form" asChild>
<div>
<div className="bg-blue-50 dark:bg-blue-900 dark:text-foreground-inverse h-40 text-lg font-semibold items-center flex justify-center mb-6 mx-6">
Replace this component with your form
</div>
</div>
</ModalDescription>
<ModalFooter>
<Button size="lg" variant="primary" asChild>
<ModalCloseFooter className="w-full grid gap-2">
Close
</ModalCloseFooter>
</Button>
<div className="flex justify-center gap-4">
<div className="text-foreground-muted">Additional text line</div>
<div className="dark:text-primary-300 underline text-primary-600">
Additional text line
</div>
</div>
</ModalFooter>
</ModalContent>
</Modal>
)
37 changes: 37 additions & 0 deletions stories/Modal/ModalInfo.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
Modal,
ModalContent,
ModalClose,
ModalFooter,
ModalDescription,
ModalHeader,
ModalTitle,
ModalTrigger
} from '@/components/Modal'
import { Button } from '@/components'

export const ModalInfoDemo = () => (
<Modal>
<Button size="sm" variant="primary" asChild>
<ModalTrigger>Open</ModalTrigger>
</Button>
<ModalContent>
<ModalHeader>
<ModalTitle>Title</ModalTitle>
<ModalClose />
</ModalHeader>
<ModalDescription className="h-40 text-foreground text-base" asChild>
<div>
<p className="mb-6 mx-6">Test</p>
</div>
</ModalDescription>
<ModalFooter>
<div className="flex justify-start gap-2.5">
<Button>Label</Button>
<Button variant="secondary">Label</Button>
<Button variant="tertiary">Label</Button>
</div>
</ModalFooter>
</ModalContent>
</Modal>
)

0 comments on commit 9fa7d43

Please sign in to comment.