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(svelte): WIP add checkbox #3173

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script module lang="ts">
import type { Snippet } from 'svelte'
import type { UseCheckboxContext } from './use-checkbox-context'

export interface CheckboxContextProps {
api?: Snippet<[UseCheckboxContext]>
}
</script>

<script lang="ts">
import { useCheckboxContext } from './use-checkbox-context'

const { api }: CheckboxContextProps = $props()
const checkbox = useCheckboxContext()
</script>

{@render api?.(checkbox)}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script module lang="ts">
import type { HTMLProps, PolymorphicProps } from '$lib/types'

export interface CheckboxControlBaseProps extends PolymorphicProps<'div'> {}
export interface CheckboxControlProps extends HTMLProps<'div'>, CheckboxControlBaseProps {}
</script>

<script lang="ts">
import { useCheckboxContext } from './use-checkbox-context'
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'

const props: CheckboxControlProps = $props()

const checkbox = useCheckboxContext()
const mergedProps = $derived(mergeProps(checkbox().getControlProps(), props))
</script>

<Ark as="div" {...mergedProps} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script module lang="ts">
import type { HTMLProps, PolymorphicProps } from '$lib/types'

export interface CheckboxHiddenInputBaseProps extends PolymorphicProps<'input'> {}
export interface CheckboxHiddenInputProps
extends HTMLProps<'input'>,
CheckboxHiddenInputBaseProps {}
</script>

<script lang="ts">
import { useCheckboxContext } from './use-checkbox-context'
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'

// TODO: use Field component
const props: CheckboxHiddenInputProps = $props()

const checkbox = useCheckboxContext()
const mergedProps = $derived(mergeProps(checkbox().getHiddenInputProps(), props))
</script>

<Ark as="input" {...mergedProps} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script module lang="ts">
import type { HTMLProps, PolymorphicProps } from '$lib/types'

interface IndicatorProps {
indeterminate?: boolean
}

export interface CheckboxIndicatorBaseProps extends IndicatorProps, PolymorphicProps<'div'> {}
export interface CheckboxIndicatorProps extends HTMLProps<'div'>, CheckboxIndicatorBaseProps {}
</script>

<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'
import { useCheckboxContext } from './use-checkbox-context'

const { indeterminate, ...rest }: CheckboxIndicatorProps = $props()
// const props: CheckboxIndicatorProps = $props()
$inspect('props', indeterminate)
const checkbox = useCheckboxContext()
$inspect('checkbox', checkbox())
const isVisible = $derived(indeterminate ? checkbox().indeterminate : checkbox().checked)
// const isVisible = $derived(props.indeterminate ? checkbox().indeterminate : checkbox().checked)
// const isVisible = $derived(checkbox().checked)
$inspect('isVisible', isVisible)
const mergedProps = $derived(mergeProps(checkbox().getIndicatorProps(), rest))
// const mergedProps = $derived(mergeProps(checkbox().getIndicatorProps(), props))
console.log('--------------')
</script>

<Ark as="div" {...mergedProps} hidden={!isVisible} />
19 changes: 19 additions & 0 deletions packages/svelte/src/lib/components/checkbox/checkbox-label.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script module lang="ts">
import type { HTMLProps, PolymorphicProps } from '$lib/types'

export interface CheckboxLabelBaseProps extends PolymorphicProps<'span'> {}
export interface CheckboxLabelProps extends HTMLProps<'span'>, CheckboxLabelBaseProps {}
</script>

<script lang="ts">
import { useCheckboxContext } from './use-checkbox-context'
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'

const props: CheckboxLabelProps = $props()

const checkbox = useCheckboxContext()
const mergedProps = $derived(mergeProps(checkbox().getLabelProps(), props))
</script>

<Ark as="span" {...mergedProps} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script module lang="ts">
import type { Assign, HTMLProps } from '$lib/types'
import type { UseCheckboxReturn } from './use-checkbox.svelte'

interface RootProviderProps {
value: UseCheckboxReturn
}

export interface CheckboxRootProviderBaseProps extends RootProviderProps {}
export interface CheckboxRootProviderProps
extends Assign<HTMLProps<'div'>, CheckboxRootProviderBaseProps> {}
</script>

<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'
import { CheckboxProvider } from './use-checkbox-context'

const props: CheckboxRootProviderProps = $props()
const { value: checkbox, ...localProps } = props
const mergedProps = $derived(mergeProps(checkbox().getRootProps(), localProps))

CheckboxProvider(checkbox)
</script>

<Ark as="div" {...mergedProps} />
40 changes: 40 additions & 0 deletions packages/svelte/src/lib/components/checkbox/checkbox-root.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script module lang="ts">
import type { Assign, HTMLProps, PolymorphicProps } from '$lib/types'
import type { UseCheckboxProps } from './use-checkbox.svelte'

export interface CheckboxRootBaseProps extends UseCheckboxProps, PolymorphicProps<'label'> {}
export interface CheckboxRootProps extends Assign<HTMLProps<'label'>, CheckboxRootBaseProps> {}
</script>

<script lang="ts">
import { mergeProps, reflect } from '@zag-js/svelte'
import { createSplitProps } from '../../utils/create-split-props'
import { Ark } from '../factory'
import { CheckboxProvider } from './use-checkbox-context'
import { useCheckbox } from './use-checkbox.svelte'

const props: CheckboxRootProps = $props()
const [useCheckboxProps, localProps] = $derived(
createSplitProps<UseCheckboxProps>()(props, [
'checked',
'defaultChecked',
'disabled',
'form',
'id',
'ids',
'invalid',
'name',
'onCheckedChange',
'readOnly',
'required',
'value',
]),
)

const checkbox = useCheckbox(reflect(() => useCheckboxProps))
const mergedProps = $derived(mergeProps(checkbox().getRootProps(), localProps))

CheckboxProvider(checkbox)
</script>

<Ark as="label" {...mergedProps} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { anatomy } from '@zag-js/checkbox'

export const checkboxAnatomy = anatomy.extendWith('group')
53 changes: 53 additions & 0 deletions packages/svelte/src/lib/components/checkbox/checkbox.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { Meta } from '@storybook/svelte'
import BasicExample from './examples/basic.svelte'
import ContextExample from './examples/context.svelte'
import IndeterminateExample from './examples/indeterminate.svelte'
import RootProviderExample from './examples/root-provider.svelte'

const meta = {
title: 'Components / Checkbox',
} as Meta

export default meta

export const Basic = {
render: () => ({
Component: BasicExample,
}),
}

export const Indeterminate = {
render: () => ({
Component: IndeterminateExample,
}),
}

// export const RenderProp = {
// render: () => ({
// Component: RenderPropExample,
// }),
// }

// export const Group = {
// render: () => ({
// Component: GroupExample,
// }),
// }

// export const WithField = {
// render: () => ({
// Component: WithFieldExample,
// }),
// }

export const RootProvider = {
render: () => ({
Component: RootProviderExample,
}),
}

export const Context = {
render: () => ({
Component: ContextExample,
}),
}
10 changes: 10 additions & 0 deletions packages/svelte/src/lib/components/checkbox/checkbox.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { render, screen } from '@testing-library/svelte'
import { describe, expect, it } from 'vitest'
import ComponentUnderTest from './examples/basic.svelte'

describe('Checkbox', async () => {
it('should render', async () => {
render(ComponentUnderTest)
expect(screen.getByText('Checkbox')).toBeInTheDocument()
})
})
35 changes: 35 additions & 0 deletions packages/svelte/src/lib/components/checkbox/checkbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export type { CheckedChangeDetails, CheckedState } from '@zag-js/checkbox'
export {
default as Context,
type CheckboxContextProps as ContextProps,
} from './checkbox-context.svelte'
export {
default as Control,
type CheckboxControlBaseProps as ControlBaseProps,
type CheckboxControlProps as ControlProps,
} from './checkbox-control.svelte'
export {
default as HiddenInput,
type CheckboxHiddenInputBaseProps as HiddenInputBaseProps,
type CheckboxHiddenInputProps as HiddenInputProps,
} from './checkbox-hidden-input.svelte'
export {
default as Indicator,
type CheckboxIndicatorBaseProps as IndicatorBaseProps,
type CheckboxIndicatorProps as IndicatorProps,
} from './checkbox-indicator.svelte'
export {
default as Label,
type CheckboxLabelBaseProps as LabelBaseProps,
type CheckboxLabelProps as LabelProps,
} from './checkbox-label.svelte'
export {
default as RootProvider,
type CheckboxRootProviderBaseProps as RootProviderBaseProps,
type CheckboxRootProviderProps as RootProviderProps,
} from './checkbox-root-provider.svelte'
export {
default as Root,
type CheckboxRootBaseProps as RootBaseProps,
type CheckboxRootProps as RootProps,
} from './checkbox-root.svelte'
17 changes: 17 additions & 0 deletions packages/svelte/src/lib/components/checkbox/examples/basic.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
import { Checkbox } from '..'
import type { RootProps } from '../checkbox'
import CheckIcon from './check-icon.svelte'

const props: RootProps = $props()
</script>

<Checkbox.Root {...props}>
<Checkbox.Label>Checkbox</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.Root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-check"
>
<title>Check Icon</title>
<path d="M20 6 9 17l-5-5" />
</svg>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import { Checkbox } from '..'
import CheckIcon from './check-icon.svelte'
</script>

<Checkbox.Root>
<Checkbox.Context>
{#snippet api(checkbox)}
<Checkbox.Label>Checkbox {checkbox().checked.toString()}</Checkbox.Label>
{/snippet}
</Checkbox.Context>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.Root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import { Checkbox } from '@ark-ui/svelte/checkbox'
import CheckIcon from './check-icon.svelte'
import MinusIcon from './minus-icon.svelte'
</script>

<Checkbox.Root checked="indeterminate">
<Checkbox.Label>Checkbox</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
<Checkbox.Indicator indeterminate>
<MinusIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.Root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-minus"
>
<title>Minus Icon</title>
<path d="M5 12h14" />
</svg>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts">
import { Checkbox, useCheckbox } from '..'
import CheckIcon from './check-icon.svelte'

const checkbox = useCheckbox({
onCheckedChange: (details) => {
console.log('checked', details.checked)
},
})
</script>

<button onclick={() => checkbox().toggleChecked()}>Toggle Checkbox</button>

<Checkbox.RootProvider value={checkbox}>
<Checkbox.Label>Checkbox</Checkbox.Label>
<Checkbox.Control>
<Checkbox.Indicator>
<CheckIcon />
</Checkbox.Indicator>
</Checkbox.Control>
<Checkbox.HiddenInput />
</Checkbox.RootProvider>
Loading
Loading