Skip to content

Commit

Permalink
component: Checkbox (#9)
Browse files Browse the repository at this point in the history
Co-authored-by: Davis SHYAKA <87414827+davis-shyaka@users.noreply.github.com>
  • Loading branch information
shyakadavis and shyakadavis authored Jul 17, 2024
1 parent ccbf7dd commit 7319c68
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/lib/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import LogoNext from './logo-next.svg?component';
import LogoTurborepo from './logo-turborepo.svg?component';
import LogoV0 from './logo-v0.svg?component';
import LogoVercel from './logo-vercel.svg?component';
import Minus from './minus.svg?component';
import Notification from './notification.svg?component';
import Paperclip from './paperclip.svg?component';
import PencilEdit from './pencil-edit.svg?component';
Expand Down Expand Up @@ -82,6 +83,7 @@ export const Icons = {
LogoTurborepo,
LogoV0,
LogoVercel,
Minus,
Notification,
Paperclip,
PencilEdit,
Expand Down
3 changes: 3 additions & 0 deletions src/lib/assets/icons/minus.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions src/lib/components/ui/checkbox/checkbox.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts">
import { Icons } from '$lib/assets/icons';
import { cn } from '$lib/utils.js';
import { Checkbox as CheckboxPrimitive } from 'bits-ui';
import { Label } from '../label';
type $$Props = CheckboxPrimitive.Props;
type $$Events = CheckboxPrimitive.Events;
let className: $$Props['class'] = undefined;
export let checked: $$Props['checked'] = false;
export let id: $$Props['id'] = undefined;
export let aria_labelledby: $$Props['aria-labelledby'] = undefined;
export { className as class };
</script>

<!--
TODO: How to properly document these styles?
Here are considerations: there are base classes for the likes such as focus, but the ugly ones are the data-[state=checked] and data-[disabled=true] classes.
Some are for individual states, e.g disabled, checked, while others are combinations of states, e.g checked and disabled.
-->
<div class="inline-flex items-center gap-2">
<CheckboxPrimitive.Root
class={cn(
'peer box-content size-4 shrink-0 items-center gap-2 rounded-[4px] border border-gray-700 bg-background-100 ring-offset-background-200 transition-[border-color,background,box-shadow] delay-0 duration-200 ease-in-out hover:bg-gray-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-color focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:border-gray-500 disabled:bg-gray-100 disabled:text-gray-500 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:border-gray-500 data-[state=checked]:border-gray-1000 data-[state=checked]:data-[disabled=true]:border-gray-600 data-[disabled=true]:bg-gray-100 data-[state=checked]:bg-gray-1000 data-[state=checked]:data-[disabled=true]:bg-gray-600 data-[disabled=true]:text-gray-500 data-[state=checked]:data-[disabled=true]:text-background-200 data-[state=checked]:text-background-200',
className
)}
{id}
bind:checked
{...$$restProps}
on:click
>
<CheckboxPrimitive.Indicator
class={cn('flex size-4 items-center justify-center p-0.5 text-current')}
let:isChecked
let:isIndeterminate
>
{#if isChecked}
<Icons.Check aria-hidden="true" class="size-4" />
{:else if isIndeterminate}
<Icons.Minus aria-hidden="true" class="size-4" />
{/if}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
<Label id={aria_labelledby} for={id}>
<slot></slot>
</Label>
</div>
6 changes: 6 additions & 0 deletions src/lib/components/ui/checkbox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Root from './checkbox.svelte';
export {
Root,
//
Root as Checkbox
};
7 changes: 7 additions & 0 deletions src/lib/components/ui/label/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Root from './label.svelte';

export {
Root,
//
Root as Label
};
21 changes: 21 additions & 0 deletions src/lib/components/ui/label/label.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script lang="ts">
import { cn } from '$lib/utils.js';
import { Label as LabelPrimitive } from 'bits-ui';
type $$Props = LabelPrimitive.Props;
type $$Events = LabelPrimitive.Events;
let className: $$Props['class'] = undefined;
export { className as class };
</script>

<LabelPrimitive.Root
class={cn(
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:text-gray-600',
className
)}
{...$$restProps}
on:mousedown
>
<slot />
</LabelPrimitive.Root>
2 changes: 1 addition & 1 deletion src/lib/config/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const aside_items: Aside = {
{
title: 'Checkbox',
href: '/checkbox',
status: 'soon'
status: 'draft'
},
{
title: 'Choicebox',
Expand Down
27 changes: 26 additions & 1 deletion src/routes/checkbox/+page.svelte
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
<h1>checkbox</h1>
<script lang="ts">
import Demo from '$lib/components/shared/demo.svelte';
import PageWrapper from '$lib/components/shared/page-wrapper.svelte';
import Default from './default.svelte';
import default_code from './default.svelte?raw';
import Disabled from './disabled.svelte';
import disabled_code from './disabled.svelte?raw';
import Indeterminate from './indeterminate.svelte';
import indeterminate_code from './indeterminate.svelte?raw';
export let data;
</script>

<PageWrapper title={data.title} description={data.description}>
<Demo id="default" class="space-y-2" code={default_code}>
<Default />
</Demo>

<Demo id="disabled" class="space-y-2" code={disabled_code}>
<Disabled />
</Demo>

<Demo id="indeterminate" class="space-y-2" code={indeterminate_code}>
<Indeterminate />
</Demo>
</PageWrapper>
21 changes: 21 additions & 0 deletions src/routes/checkbox/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { MetaTagsProps } from 'svelte-meta-tags';

export function load() {
const title = 'Checkbox';
const description = 'A control that toggles between two options, checked or unchecked.';

const pageMetaTags = Object.freeze({
title,
description,
openGraph: {
title,
description
}
}) satisfies MetaTagsProps;

return {
pageMetaTags,
title,
description
};
}
7 changes: 7 additions & 0 deletions src/routes/checkbox/default.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import { Checkbox } from '$lib/components/ui/checkbox';
let checked = false;
</script>

<Checkbox id="option-1" bind:checked aria-labelledby="options-label">Option 1</Checkbox>
9 changes: 9 additions & 0 deletions src/routes/checkbox/disabled.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script lang="ts">
import { Checkbox } from '$lib/components/ui/checkbox';
</script>

<div class="flex flex-col gap-4">
<Checkbox disabled>Disabled</Checkbox>
<Checkbox checked disabled>Disabled Checked</Checkbox>
<Checkbox disabled checked="indeterminate">Disabled Indeterminate</Checkbox>
</div>
5 changes: 5 additions & 0 deletions src/routes/checkbox/indeterminate.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { Checkbox } from '$lib/components/ui/checkbox';
</script>

<Checkbox id="option-2" checked="indeterminate" aria-labelledby="options-label">Option 2</Checkbox>

0 comments on commit 7319c68

Please sign in to comment.