Skip to content

Commit

Permalink
feat(svelte): add qr-code
Browse files Browse the repository at this point in the history
  • Loading branch information
segunadebayo committed Nov 29, 2024
1 parent 8acaabd commit 4d04b54
Show file tree
Hide file tree
Showing 23 changed files with 370 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/svelte/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ description: All notable changes will be documented in this file.
- Added `Environment` component.
- Added `Collection` helpers.
- Added `Timer` component.
- Added `Highlight` component.
- Added `QrCode` component.

## [0.1.0] - 2024-11-27

Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/lib/components/avatar/avatar-root.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { createSplitProps } from '../../utils/create-split-props'
import { Ark } from '../factory'
import { AvatarProvider } from './use-avatar-context'
import { useAvatar } from './use-avatar.svelte'
import { Ark } from '../factory'
let props: AvatarRootProps = $props()
const props: AvatarRootProps = $props()
const [useAvatarProps, localProps] = createSplitProps<UseAvatarProps>()(props, [
'id',
'ids',
Expand Down
6 changes: 6 additions & 0 deletions packages/svelte/src/lib/components/factory/factory.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<script lang="ts" generics="T extends keyof SvelteHTMLElements">
import type { HTMLProps, PolymorphicProps, PropsFn } from '$lib/types'
import { isVoidHTMLTag, isVoidSVGTag } from '$lib/utils/tags'
import { mergeProps } from '@zag-js/svelte'
import type { SvelteHTMLElements } from 'svelte/elements'
import SvgElement from './svg-element.svelte'
type Props = HTMLProps<T> &
PolymorphicProps<T> & {
Expand All @@ -15,6 +17,10 @@

{#if asChild}
{@render render?.(propsFn)}
{:else if isVoidSVGTag(as)}
<SvgElement {as} {...rest} />
{:else if isVoidHTMLTag(as)}
<svelte:element this={as} {...rest} />
{:else}
<svelte:element this={as} {...rest}>
{@render children?.()}
Expand Down
15 changes: 15 additions & 0 deletions packages/svelte/src/lib/components/factory/svg-element.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<svelte:options namespace="svg" />

<script lang="ts" generics="T extends keyof SvelteHTMLElements">
import type { HTMLProps, PolymorphicProps } from '$lib/types'
import type { SvelteHTMLElements } from 'svelte/elements'
type Props = HTMLProps<T> &
PolymorphicProps<T> & {
as: T
}
const { as, ...props }: Props = $props()
</script>

<svelte:element this={as} {...props} />
1 change: 1 addition & 0 deletions packages/svelte/src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './avatar'
export * from './factory'
export * from './timer'
export * from './highlight'
export * from './qr-code'
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script lang="ts">
import { QrCode } from '@ark-ui/svelte/qr-code'
</script>

<QrCode.Root value="http://ark-ui.com">
<QrCode.Frame>
<QrCode.Pattern />
</QrCode.Frame>
</QrCode.Root>
18 changes: 18 additions & 0 deletions packages/svelte/src/lib/components/qr-code/examples/context.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import { QrCode } from '@ark-ui/svelte/qr-code'
import type { UseQrCodeContext } from '@ark-ui/svelte/qr-code'
</script>

<QrCode.Root value="http://ark-ui.com">
<QrCode.Context>
{#snippet api(qrCode: UseQrCodeContext)}
<QrCode.Frame>
{#if qrCode().value === 'http://ark-ui.com'}
<QrCode.Pattern />
{:else}
<p>Loading...</p>
{/if}
</QrCode.Frame>
{/snippet}
</QrCode.Context>
</QrCode.Root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script lang="ts">
import { QrCode } from '@ark-ui/svelte/qr-code'
</script>

<QrCode.Root value="http://ark-ui.com" encoding={{ ecc: 'H' }}>
<QrCode.Frame>
<QrCode.Pattern />
</QrCode.Frame>
</QrCode.Root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
import { QrCode, useQrCode } from '@ark-ui/svelte/qr-code'
const qrCode = useQrCode({ value: 'http://ark-ui.com' })
const setValue = () => qrCode().setValue('https://ark-ui.com')
</script>

<button onclick={setValue}>Set Value</button>

<QrCode.RootProvider value={qrCode}>
<QrCode.Frame>
<QrCode.Pattern />
</QrCode.Frame>
</QrCode.RootProvider>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script lang="ts">
import { QrCode } from '@ark-ui/svelte/qr-code'
</script>

<QrCode.Root value="http://ark-ui.com" encoding={{ ecc: 'H' }}>
<QrCode.Frame>
<QrCode.Pattern />
</QrCode.Frame>
<QrCode.Overlay>
<img src="https://ark-ui.com/icon-192.png" alt="Ark UI Logo" />
</QrCode.Overlay>
</QrCode.Root>
35 changes: 35 additions & 0 deletions packages/svelte/src/lib/components/qr-code/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export type { QrCodeGenerateOptions, QrCodeGenerateResult } from '@zag-js/qr-code'
export {
default as QrCodeRoot,
type QrCodeRootProps,
type QrCodeRootBaseProps,
} from './qr-code-root.svelte'
export {
default as QrCodeFrame,
type QrCodeFrameProps,
type QrCodeFrameBaseProps,
} from './qr-code-frame.svelte'
export {
default as QrCodePattern,
type QrCodePatternProps,
type QrCodePatternBaseProps,
} from './qr-code-pattern.svelte'
export {
default as QrCodeOverlay,
type QrCodeOverlayProps,
type QrCodeOverlayBaseProps,
} from './qr-code-overlay.svelte'
export {
default as QrCodeRootProvider,
type QrCodeRootProviderProps,
type QrCodeRootProviderBaseProps,
} from './qr-code-root-provider.svelte'
export {
default as QrCodeContext,
type QrCodeContextProps,
} from './qr-code-context.svelte'
export { qrCodeAnatomy } from './qr-code.anatomy'
export { useQrCodeContext, type UseQrCodeContext } from './use-qr-code-context'
export { useQrCode, type UseQrCodeProps, type UseQrCodeReturn } from './use-qr-code.svelte'

export * as QrCode from './qr-code'
17 changes: 17 additions & 0 deletions packages/svelte/src/lib/components/qr-code/qr-code-context.svelte
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 { UseQrCodeContext } from './use-qr-code-context'
export interface QrCodeContextProps {
api?: Snippet<[UseQrCodeContext]>
}
</script>

<script lang="ts">
import { useQrCodeContext } from './use-qr-code-context'
const { api }: QrCodeContextProps = $props()
const qrCode = useQrCodeContext()
</script>

{@render api?.(qrCode)}
18 changes: 18 additions & 0 deletions packages/svelte/src/lib/components/qr-code/qr-code-frame.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script module lang="ts">
import type { HTMLProps, PolymorphicProps } from '$lib/types'
export interface QrCodeFrameBaseProps extends PolymorphicProps<'svg'> {}
export interface QrCodeFrameProps extends HTMLProps<'svg'>, QrCodeFrameBaseProps {}
</script>

<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'
import { useQrCodeContext } from './use-qr-code-context'
const props: QrCodeFrameProps = $props()
const qrCode = useQrCodeContext()
const mergedProps = $derived(mergeProps(qrCode().getFrameProps(), props))
</script>

<Ark as="svg" {...mergedProps} />
18 changes: 18 additions & 0 deletions packages/svelte/src/lib/components/qr-code/qr-code-overlay.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script module lang="ts">
import type { HTMLProps, PolymorphicProps } from '$lib/types'
export interface QrCodeOverlayBaseProps extends PolymorphicProps<'div'> {}
export interface QrCodeOverlayProps extends HTMLProps<'div'>, QrCodeOverlayBaseProps {}
</script>

<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'
import { useQrCodeContext } from './use-qr-code-context'
const props: QrCodeOverlayProps = $props()
const qrCode = useQrCodeContext()
const mergedProps = $derived(mergeProps(qrCode().getOverlayProps(), props))
</script>

<Ark as="div" {...mergedProps} />
19 changes: 19 additions & 0 deletions packages/svelte/src/lib/components/qr-code/qr-code-pattern.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 QrCodePatternBaseProps extends PolymorphicProps<'path'> {}
export interface QrCodePatternProps extends HTMLProps<'path'>, QrCodePatternBaseProps {}
</script>

<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { Ark } from '../factory'
import { useQrCodeContext } from './use-qr-code-context'
const props: QrCodePatternProps = $props()
const qrCode = useQrCodeContext()
const mergedProps = $derived(mergeProps(qrCode().getPatternProps(), props))
</script>

<Ark as="path" {...mergedProps} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script module lang="ts">
import type { Assign, HTMLProps } from '$lib/types'
import type { UseQrCodeReturn } from './use-qr-code.svelte'
interface RootProviderProps {
value: UseQrCodeReturn
}
export interface QrCodeRootProviderBaseProps extends RootProviderProps {}
export interface QrCodeRootProviderProps
extends Assign<HTMLProps<'div'>, QrCodeRootProviderBaseProps> {}
</script>

<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { createSplitProps } from '../../utils/create-split-props'
import { Ark } from '../factory'
import { QrCodeProvider } from './use-qr-code-context'
const props: QrCodeRootProviderProps = $props()
const [{ value: qrCode }, localProps] = createSplitProps<RootProviderProps>()(props, ['value'])
const mergedProps = $derived(mergeProps(qrCode().getRootProps(), localProps))
QrCodeProvider(qrCode)
</script>

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

<script lang="ts">
import { mergeProps } from '@zag-js/svelte'
import { createSplitProps } from '../../utils/create-split-props'
import { Ark } from '../factory'
import { QrCodeProvider } from './use-qr-code-context'
import { useQrCode } from './use-qr-code.svelte'
const props: QrCodeRootProps = $props()
const [useQrCodeProps, localProps] = createSplitProps<UseQrCodeProps>()(props, [
'id',
'ids',
'value',
'encoding',
])
const qrCode = useQrCode(useQrCodeProps)
const mergedProps = $derived(mergeProps(qrCode().getRootProps(), localProps))
QrCodeProvider(qrCode)
</script>

<Ark as="div" {...mergedProps} />
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { anatomy as qrCodeAnatomy } from '@zag-js/qr-code'
42 changes: 42 additions & 0 deletions packages/svelte/src/lib/components/qr-code/qr-code.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Meta } from '@storybook/svelte'
import BasicExample from './examples/basic.svelte'
import ContextExample from './examples/context.svelte'
import ErrorCorrectionExample from './examples/error-correction.svelte'
import RootProviderExample from './examples/root-provider.svelte'
import WithOverlayExample from './examples/with-overlay.svelte'

const meta = {
title: 'Components / QR Code',
} satisfies Meta

export default meta

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

export const Context = {
render: () => ({
Component: ContextExample,
}),
}

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

export const WithOverlay = {
render: () => ({
Component: WithOverlayExample,
}),
}

export const ErrorCorrection = {
render: () => ({
Component: ErrorCorrectionExample,
}),
}
33 changes: 33 additions & 0 deletions packages/svelte/src/lib/components/qr-code/qr-code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export type {
QrCodeGenerateOptions as GenerateOptions,
QrCodeGenerateResult as GenerateResult,
} from '@zag-js/qr-code'
export {
default as Root,
type QrCodeRootProps as RootProps,
type QrCodeRootBaseProps as RootBaseProps,
} from './qr-code-root.svelte'
export {
default as Frame,
type QrCodeFrameProps as FrameProps,
type QrCodeFrameBaseProps as FrameBaseProps,
} from './qr-code-frame.svelte'
export {
default as Pattern,
type QrCodePatternProps as PatternProps,
type QrCodePatternBaseProps as PatternBaseProps,
} from './qr-code-pattern.svelte'
export {
default as Overlay,
type QrCodeOverlayProps as OverlayProps,
type QrCodeOverlayBaseProps as OverlayBaseProps,
} from './qr-code-overlay.svelte'
export {
default as RootProvider,
type QrCodeRootProviderProps as RootProviderProps,
type QrCodeRootProviderBaseProps as RootProviderBaseProps,
} from './qr-code-root-provider.svelte'
export {
default as Context,
type QrCodeContextProps as ContextProps,
} from './qr-code-context.svelte'
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createContext } from '$lib/utils/create-context'
import type { UseQrCodeReturn } from './use-qr-code.svelte'

export interface UseQrCodeContext extends UseQrCodeReturn {}
export const [QrCodeProvider, useQrCodeContext] = createContext<UseQrCodeContext>({
key: 'QrCodeContext',
})
Loading

0 comments on commit 4d04b54

Please sign in to comment.