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(v2)/switch components #707

Merged
merged 8 commits into from
Oct 27, 2024
7 changes: 7 additions & 0 deletions packages/ui/src/components/switch/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Root from './switch.svelte'

export {
Root,
//
Root as Switch,
}
92 changes: 92 additions & 0 deletions packages/ui/src/components/switch/switch.stories.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<script context="module" lang="ts">
import type { Meta } from '@storybook/svelte'

import { Switch } from './index.js'

export const meta = {
title: 'Atom/Switch',
component: Switch,
tags: ['autodocs'],
argTypes: {
'aria-label': {
control: 'text',
description: 'string value that labels an interactive element',
},
checked: {
control: 'boolean',
description: 'Whether the switch is checked or not.',
defaultValue: false,
},
label: {
control: 'text',
description: 'The label associated with the switch.',
defaultValue: 'Switch Label',
},
id: {
control: 'text',
description: 'ID for the switch element and its label.',
defaultValue: 'switch',
},
class: {
control: false,
},
'on:click': {
action: 'onClick',
},
'on:keydown': {
action: 'onKeyDown',
},
},
} satisfies Meta<Switch>
</script>

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

<!-- Define the template for the switch component -->
<Template let:args>
<Switch {...args} />
</Template>

<!-- Define the stories with different states -->
<Story
name="Default"
args="{{
checked: false,
label: 'Switch Label',
id: 'switch',
'aria-label': 'for example of default switch',
}}"
/>

<Story
name="Checked"
args="{{
checked: true,
label: 'Checked Switch',
id: 'checked-switch',
'aria-label': 'for example of checked switch ',
}}"
/>

<Story
name="With Custom Label"
args="{{
checked: false,
label: 'Custom Label',
id: 'custom-switch',
'aria-label': 'for example of custom label switch ',
}}"
/>

<Story
name="Disabled"
args="{{
checked: false,
label: 'Disabled Switch',
id: 'disabled-switch',
disabled: true,
'aria-label': 'for example of disable switch ',
}}"
/>
44 changes: 44 additions & 0 deletions packages/ui/src/components/switch/switch.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script lang="ts">
import { Label, Switch as SwitchPrimitive } from 'bits-ui'

import { cn } from '../../utils'

type $$Props = SwitchPrimitive.Props & {
label?: string | undefined | null
}
type $$Events = SwitchPrimitive.Events

let className: $$Props['class'] = undefined
export let checked: $$Props['checked'] = undefined
export let id: $$Props['id'] = null
export let label: $$Props['label'] = 'label'
export { className as class }
</script>

<div class="flex items-center space-x-2">
<SwitchPrimitive.Root
bind:checked
class="{cn(
'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:border-primary data-[state=checked]:bg-primary-low data-[state=unchecked]:bg-surface-container-lowest peer inline-flex h-[18px] w-[32px] shrink-0 cursor-pointer items-center rounded-full border border-surface-container-high transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}"
{...$$restProps}
on:click
on:keydown
{id}
>
<SwitchPrimitive.Thumb
class="{cn(
'p-1 bg-surface-container-high data-[state=checked]:bg-primary pointer-events-none block h-3.5 w-3.5 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-[14.5px] data-[state=unchecked]:translate-x-[1px]',
)}"
/>
</SwitchPrimitive.Root>
{#if label}
<Label.Root
for="{id}"
class="text-button2 font-normal leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
{label}
</Label.Root>
{/if}
</div>
Loading