Skip to content

Commit

Permalink
First pass at RadioTileGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
spalmurray-codecov committed May 1, 2024
1 parent 44246b9 commit a2d7109
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/ui/RadioTileGroup/RadioTileGroup.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render, screen } from '@testing-library/react'

import { RadioTileGroup } from './RadioTileGroup'

describe('Card', () => {
it('renders', async () => {
render(
<RadioTileGroup>
<RadioTileGroup.Item value="asdf" label="Asdf" />
<RadioTileGroup.Item value="jkl;" label="Jkl;" />
</RadioTileGroup>
)
const item1 = await screen.findByText('Asdf')
expect(item1).toBeInTheDocument()
const item2 = await screen.findByText('Jkl;')
expect(item2).toBeInTheDocument()
})

describe('Item description', () => {
it('renders', async () => {
render(
<RadioTileGroup>
<RadioTileGroup.Item
value="asdf"
label="Asdf"
description="This is a description."
/>
</RadioTileGroup>
)
const description = await screen.findByText('This is a description.')
expect(description).toBeInTheDocument()
})
})
})
58 changes: 58 additions & 0 deletions src/ui/RadioTileGroup/RadioTileGroup.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Meta, StoryObj } from '@storybook/react'

import { RadioTileGroup } from './RadioTileGroup'

type RadioTileGroupStory = React.ComponentProps<typeof RadioTileGroup> & {
flex: 1 | 'none'
}

const meta: Meta<RadioTileGroupStory> = {
title: 'Components/RadioTileGroup',
component: RadioTileGroup,
argTypes: {
direction: {
description: 'Controls the flex direction of the RadioTileGroup',
control: 'radio',
options: ['row', 'col'],
},
flex: {
description: 'Toggles between the item flexing and not',
control: 'radio',
options: [1, 'none'],
},
},
}
export default meta

type Story = StoryObj<RadioTileGroupStory>

export const Default: Story = {
args: {
direction: 'row',
flex: 1,
},
render: (args) => (
<RadioTileGroup className="w-full" direction={args.direction}>
<RadioTileGroup.Item value="radio" label="Radio" flex={args.flex} />
<RadioTileGroup.Item value="tile" label="Tile" flex={args.flex} />
<RadioTileGroup.Item value="group" label="Group" flex={args.flex} />
</RadioTileGroup>
),
}

export const WithDescription: Story = {
args: {
direction: 'row',
flex: 1,
},
render: (args) => (
<RadioTileGroup className="w-full" direction={args.direction}>
<RadioTileGroup.Item
value="description"
label="Description"
description="A RadioTileGroup Item can optionally have a description"
/>
<RadioTileGroup.Item value="noDescription" label="No Description" />
</RadioTileGroup>
),
}
96 changes: 96 additions & 0 deletions src/ui/RadioTileGroup/RadioTileGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'
import { cva, VariantProps } from 'cva'
import React from 'react'

const group = cva(['flex', 'gap-4'], {
variants: {
direction: {
row: 'flex-row',
col: 'flex-col',
},
},
defaultVariants: {
direction: 'row',
},
})
interface GroupProps
extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>,
VariantProps<typeof group> {}

const Group = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Root>,
GroupProps
>(({ className, direction, ...props }, ref) => {
return (
<RadioGroupPrimitive.Root
className={group({ className, direction })}
{...props}
ref={ref}
/>
)
})
Group.displayName = RadioGroupPrimitive.Root.displayName

const item = cva(['relative'], {
variants: {
flex: {
1: 'flex-1',
none: 'flex-none',
},
},
defaultVariants: {
flex: 1,
},
})
interface ItemProps
extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>,
VariantProps<typeof item> {
label: string
description?: string
}

const Item = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Item>,
ItemProps
>(({ className, label, description, flex, ...props }, ref) => {
return (
<RadioGroupPrimitive.Item
ref={ref}
className={item({ className, flex })}
{...props}
>
<div className="flex h-full flex-col gap-2 rounded-md border border-ds-gray-quaternary p-4">
<div className="flex items-center justify-between gap-4">
<p className="font-medium">{label}</p>
<RadioButtonCircle />
</div>
{description ? (
<p className="text-left text-ds-gray-quinary">{description}</p>
) : null}
</div>
<RadioGroupPrimitive.Indicator className="absolute right-0 top-0 flex h-full w-full justify-end">
<div className="absolute h-full w-full rounded-md border-2 border-ds-blue" />
<div className="h-full w-full rounded-md border border-ds-blue p-4">
<div className="flex h-5 w-full items-center justify-end">
<RadioButtonCircle selected />
</div>
</div>
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
)
})
Item.displayName = RadioGroupPrimitive.Item.displayName

export const RadioTileGroup = Object.assign(Group, {
Item,
})

function RadioButtonCircle({ selected = false }: { selected?: boolean }) {
return selected ? (
<div className="flex h-4 w-4 items-center justify-center rounded-full bg-ds-blue">
<div className="h-1 w-1 rounded-full bg-white " />
</div>
) : (
<div className="h-4 w-4 rounded-full border border-ds-gray-quaternary" />
)
}
1 change: 1 addition & 0 deletions src/ui/RadioTileGroup/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { RadioTileGroup } from './RadioTileGroup'

0 comments on commit a2d7109

Please sign in to comment.