Skip to content

Commit

Permalink
feat: ✨ add checkbox component
Browse files Browse the repository at this point in the history
use checkbox to control elements that toggles between two options, checked or unchecked.
  • Loading branch information
kampsy committed Oct 27, 2024
1 parent da80f40 commit 595b4e6
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 24 deletions.
32 changes: 32 additions & 0 deletions src/docs/data/checkbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export const checkboxDefault = `
import { Checkbox } from 'kampsy-ui';
let value = $state(false);
<Checkbox bind:checked>option 1</Checkbox>`;

export const checkboxDisabled = `
import { Checkbox } from 'kampsy-ui';
<div class="w-full space-y-4">
<Checkbox disabled>Disabled</Checkbox>
<Checkbox checked disabled>Disabled Checked</Checkbox>
<Checkbox disabled indeterminate>Disabled Indeterminate</Checkbox>
</div>`;


export const checkboxIndeterminate = `
import { Checkbox } from 'kampsy-ui';
<Checkbox indeterminate>option 1</Checkbox>`;

export const checkboxItems = `
import { Checkbox } from 'kampsy-ui';
let items = $state(['avatar', 'choicebox']);
<div class="w-full space-y-4">
<Checkbox value="avatar" bind:items>avatar</Checkbox>
<Checkbox value="button" bind:items>button</Checkbox>
<Checkbox value="calendar" bind:items>calendar</Checkbox>
<Checkbox value="choicebox" bind:items>choicebox</Checkbox>
</div>`;
34 changes: 11 additions & 23 deletions src/docs/utils/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,14 @@ export const asideData: Array<AsideT> = [
},
{
name: 'calendar',
url: '/calendar',
url: '/calendar'
},
{
name: 'checkbox',
url: '/checkbox',
badge: {
name: 'updated',
variant: 'purple'
name: 'new',
variant: 'green'
}
},
{
Expand All @@ -69,23 +73,15 @@ export const asideData: Array<AsideT> = [
},
{
name: 'input',
url: '/input',
badge: {
name: 'updated',
variant: 'purple'
}
url: '/input'
},
{
name: 'menu',
url: '/menu',
},
{
name: 'modal',
url: '/modal',
badge: {
name: 'new',
variant: 'green'
}
url: '/modal'
},
{
name: 'note',
Expand Down Expand Up @@ -133,19 +129,11 @@ export const asideData: Array<AsideT> = [
},
{
name: 'text',
url: '/text',
badge: {
name: 'new',
variant: 'green'
}
url: '/text'
},
{
name: 'textarea',
url: '/textarea',
badge: {
name: 'updated',
variant: 'purple'
}
url: '/textarea'
},
{
name: 'theme switcher',
Expand Down
123 changes: 123 additions & 0 deletions src/lib/checkbox/checkbox.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<script lang="ts">
import Check from '$lib/icons/check.svelte';
import Minus from '$lib/icons/minus.svelte';
import { randomString } from '$lib/utils/random.js';
import type { Snippet } from 'svelte';
type propT = {
checked?: boolean | undefined;
value?: string | undefined;
items?: Array<string> | undefined;
indeterminate?: boolean | undefined;
disabled?: boolean | undefined;
children?: Snippet;
};
let {
checked = $bindable(false),
value = undefined,
items = $bindable(undefined),
indeterminate = false,
disabled = false,
children
}: propT = $props();
// random string for unique id
const unique = `${randomString(4)}_${value}`;
const onchange = () => {
checked = !checked;
// if checked is true add the value to the item
if (items && value) {
if (checked) {
items = [...items, value];
} else {
items = items.filter((item) => item !== value);
}
}
};
$effect(() => {
if (items && value) {
if (items.includes(value)) {
checked = true;
}
}
});
// The rounded radio cont
let checkboxContClass = $derived.by(() => {
if (disabled) {
if (indeterminate) {
return `border-kui-light-gray-600 dark:border-kui-dark-gray-600 text-kui-light-gray-600 dark:text-kui-dark-gray-600
bg-kui-light-gray-100 dark:bg-kui-dark-gray-100`;
}
// will check for indeterminate and checked
if (checked) {
return `border-kui-light-gray-600 dark:border-kui-dark-gray-600 bg-kui-light-gray-600 dark:bg-kui-dark-gray-600`;
}
return `border-kui-light-gray-500 dark:border-kui-dark-gray-500 bg-kui-light-gray-100 dark:bg-kui-dark-gray-100`;
}
// if its indeterminate
if (indeterminate) {
return `border-kui-light-gray-900 dark:border-kui-dark-gray-900`;
}
// If checked is true
if (checked) {
return `border-kui-dark-bg-secondary dark:border-kui-light-bg bg-kui-dark-bg-secondary dark:bg-kui-light-bg `;
}
return `border-kui-light-gray-500 dark:border-kui-dark-gray-500 hover:bg-kui-light-gray-100 dark:hover:bg-kui-dark-gray-100`;
});
let checkboxClass = $derived.by(() => {
if (indeterminate) {
return `text-kui-light-gray-900 dark:text-kui-dark-gray-900`;
}
if (checked) {
return `text-kui-light-bg dark:text-kui-black`;
}
return `text-transparent`;
});
let textClass = $derived.by(() => {
if (disabled) {
return `text-kui-light-gray-500 dark:text-kui-dark-gray-500`;
}
return `text-kui-light-gray-900 dark:text-kui-dark-gray-900`;
});
</script>

<section class="flex">
<label for={unique}>
<div class="flex items-center gap-2 cursor-pointer">
<div
class="w-[16px] h-[16px] rounded-[4px] p-[2px] box-border transition-colors ease-in flex items-center justify-center border {checkboxContClass} "
>
<input
{onchange}
type="checkbox"
{checked}
id={unique}
{value}
{disabled}
{indeterminate}
class="hidden"
/>
<div class="w-[16px] h-[16px] font-bold transition-colors ease-in {checkboxClass}">
{#if indeterminate}
<Minus />
{:else}
<Check />
{/if}
</div>
</div>

{#if children}
<div class="text-sm select-none first-letter:capitalize {textClass}">
{@render children()}
</div>
{/if}
</div>
</label>
</section>
14 changes: 14 additions & 0 deletions src/lib/icons/check-square-fill.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<svg
data-testid="geist-icon"
height="100%"
stroke-linejoin="round"
viewBox="0 0 16 16"
width="100%"
style="color: currentcolor;"
><path
fill-rule="evenodd"
clip-rule="evenodd"
d="M14.5 1.5V14.5L1.5 14.5L1.5 1.5H14.5ZM16 15C16 15.5523 15.5523 16 15 16L1 16C0.447715 16 0 15.5523 0 15V1C0 0.447715 0.447716 0 1 0H15C15.5523 0 16 0.447715 16 1V15ZM11.7803 6.28033L12.3107 5.75L11.25 4.68934L10.7197 5.21967L6.5 9.43935L5.28033 8.21967L4.75001 7.68934L3.68934 8.74999L4.21967 9.28033L5.96967 11.0303C6.11032 11.171 6.30109 11.25 6.5 11.25C6.69891 11.25 6.88968 11.171 7.03033 11.0303L11.7803 6.28033Z"
fill="currentColor"
></path></svg
>
4 changes: 3 additions & 1 deletion src/lib/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export { default as GridSquare } from './grid-square.svelte'
export { default as ListUnordered } from './list-unordered.svelte'
export { default as Check } from './check.svelte'
export { default as CheckSquare } from './check-square.svelte'
export { default as CheckSquareFill } from './check-square-fill.svelte'
export { default as Hook } from './hook.svelte'
export { default as Webhook } from './webhook.svelte'
export { default as InformationFillSmall } from './information-fill-small.svelte'
Expand Down Expand Up @@ -51,4 +52,5 @@ export { default as Accessibility } from './accessibility.svelte'
export { default as MenuAlt } from './menu-alt.svelte'
export { default as Cross } from './cross.svelte'
export { default as Star } from './star.svelte'
export { default as StarFill } from './star-fill.svelte'
export { default as StarFill } from './star-fill.svelte'
export { default as Minus } from './minus.svelte'
14 changes: 14 additions & 0 deletions src/lib/icons/minus.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<svg
data-testid="geist-icon"
height="100%"
stroke-linejoin="round"
viewBox="0 0 16 16"
width="100%"
style="color: currentcolor;"
><path
fill-rule="evenodd"
clip-rule="evenodd"
d="M2 7.25H2.75H13.25H14V8.75H13.25H2.75H2V7.25Z"
fill="currentColor"
></path></svg
>
3 changes: 3 additions & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export { default as Button } from './button/button.svelte';
// Calendar
export { default as Calendar } from './calendar/calendar.svelte'

// Checkbox
export {default as Checkbox} from './checkbox/checkbox.svelte'

// Choicebox
export * as Choicebox from './choicebox/index.js'

Expand Down
Loading

0 comments on commit 595b4e6

Please sign in to comment.