Skip to content

Commit

Permalink
feat(v2)/radio group components (#706)
Browse files Browse the repository at this point in the history
* feat(v2): add radio-group components

* feat(v2): add storybook of radio-group components

* style(v2): update `aria-label` for accessibility of checkbox

* style(v2): update disabled color and `aria-label` of radio-group for accessibility

* fix(radio-group-item): typing and format

---------

Co-authored-by: Nutthapat Pongtanyavichai <[email protected]>
  • Loading branch information
phongit-kha and leomotors authored Oct 27, 2024
1 parent d5788d6 commit 12cfbc8
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 0 deletions.
15 changes: 15 additions & 0 deletions packages/ui/src/components/radio-group/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { RadioGroup as RadioGroupPrimitive } from 'bits-ui'

import Root from './radio-group.svelte'
import Item from './radio-group-item.svelte'
const Input = RadioGroupPrimitive.Input

export {
Input,
Item,
//
Root as RadioGroup,
Input as RadioGroupInput,
Item as RadioGroupItem,
Root,
}
42 changes: 42 additions & 0 deletions packages/ui/src/components/radio-group/radio-group-item.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
import { Label, RadioGroup as RadioGroupPrimitive } from 'bits-ui'
import { Circle } from 'lucide-svelte'
import { cn } from '../../utils'
type $$Props = RadioGroupPrimitive.ItemProps & {
id: string
label: string
}
type $$Events = RadioGroupPrimitive.ItemEvents
let className: $$Props['class'] = undefined
export let value: $$Props['value']
export let id: $$Props['id']
export let label: $$Props['label'] = 'label'
export { className as class }
</script>

<div class="flex items-center space-x-2">
<RadioGroupPrimitive.Item
{value}
class="{cn(
'peer border-on-surface-placeholder data-[state=checked]:border-primary text-primary ring-offset-background focus-visible:ring-ring aspect-square h-5 w-5 rounded-full border-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}"
{...$$restProps}
on:click
>
<div class="flex items-center justify-center">
<RadioGroupPrimitive.ItemIndicator>
<Circle class="h-2.5 w-2.5 fill-primary text-current" />
</RadioGroupPrimitive.ItemIndicator>
</div>
</RadioGroupPrimitive.Item>
<Label.Root
for="{id}"
class="text-button2 font-normal leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
{label}
</Label.Root>
</div>
96 changes: 96 additions & 0 deletions packages/ui/src/components/radio-group/radio-group.stories.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script context="module" lang="ts">
import type { Meta } from '@storybook/svelte'
import * as RadioGroup from './index.js'
export const meta = {
title: 'Atom/RadioGroup',
component: RadioGroup,
tags: ['autodocs'],
argTypes: {
'aria-label': {
control: 'text',
description: 'string value that labels an interactive element',
},
value: {
description: 'The selected value in the radio group.',
control: {
type: 'select',
},
options: ['option-one', 'option-two'],
defaultValue: 'option-one',
},
className: {
control: false,
},
itemValue1: {
control: 'text',
description: 'Value for the first RadioGroup.Item',
defaultValue: 'option-one',
},
'item1-label': {
control: 'text',
description: 'Label for the first RadioGroup.Item',
defaultValue: 'option 1',
},
itemValue2: {
control: 'text',
description: 'Value for the second RadioGroup.Item',
defaultValue: 'option-two',
},
'item2-label': {
control: 'text',
description: 'Label for the second RadioGroup.Item',
defaultValue: 'option 2',
},
onClick: {
action: 'onClick',
},
},
} satisfies Meta<RadioGroup>
</script>

<script lang="ts">
import { Story, Template } from '@storybook/addon-svelte-csf'
</script>

<Template let:args>
<RadioGroup.Root {...args}>
<RadioGroup.Item
value="{args.itemValue1}"
id="{args.itemValue1}"
label="{args['item1-label']}"
aria-label="{args['aria-label']}"
/>
<RadioGroup.Item
value="{args.itemValue2}"
id="{args.itemValue2}"
label="{args['item2-label']}"
aria-label="{args['aria-label']}"
/>
</RadioGroup.Root>
</Template>

<Story
name="Default"
args="{{
value: 'option-one',
itemValue1: 'option-one',
'item1-label': 'option 1',
itemValue2: 'option-two',
'item2-label': 'option 2',
'aria-label': 'for example of enable radio group',
}}"
/>

<Story
name="Disabled"
args="{{
itemValue1: 'option-one',
'item1-label': 'option 1',
itemValue2: 'option-two',
'item2-label': 'option 2',
disabled: true,
'aria-label': 'for example of disabled radio group',
}}"
/>
19 changes: 19 additions & 0 deletions packages/ui/src/components/radio-group/radio-group.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from 'bits-ui'
import { cn } from '../../utils'
type $$Props = RadioGroupPrimitive.Props
let className: $$Props['class'] = undefined
export let value: $$Props['value'] = undefined
export { className as class }
</script>

<RadioGroupPrimitive.Root
bind:value
class="{cn('grid gap-2 p-1', className)}"
{...$$restProps}
>
<slot />
</RadioGroupPrimitive.Root>

0 comments on commit 12cfbc8

Please sign in to comment.