Skip to content

Commit

Permalink
feat(svelte): add environment provider
Browse files Browse the repository at this point in the history
  • Loading branch information
cschroeter committed Nov 28, 2024
1 parent f6052e7 commit bb76fc4
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 2 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions packages/svelte/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ description: All notable changes will be documented in this file.
## Added

- Added `factory` component for `asChild` prop.
- Added `Environment` component.

## [0.1.0] - 2024-11-27

Expand Down
7 changes: 7 additions & 0 deletions packages/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
"types": "./src/lib/components/anatomy.ts",
"svelte": "./src/lib/components/anatomy.ts"
},
"./environment": {
"types": "./src/lib/providers/environment/index.ts",
"svelte": "./src/lib/providers/environment/index.ts"
},
"./locale": {
"types": "./src/lib/providers/locale/index.ts",
"svelte": "./src/lib/providers/locale/index.ts"
Expand Down Expand Up @@ -54,6 +58,8 @@
"exports.\\./anatomy.types": "./dist/components/anatomy.d.ts",
"exports.\\./locale.svelte": "./dist/providers/locale/index.js",
"exports.\\./locale.types": "./dist/providers/locale/index.d.ts",
"exports.\\./environment.svelte": "./dist/providers/environment/index.js",
"exports.\\./environment.types": "./dist/providers/environment/index.d.ts",
"exports.\\./*.svelte": "./dist/components/*/index.js",
"exports.\\./*.types": "./dist/components/*/index.d.ts"
}
Expand All @@ -66,6 +72,7 @@
"@zag-js/anatomy": "0.78.0",
"@zag-js/avatar": "0.78.0",
"@zag-js/core": "0.78.0",
"@zag-js/dom-query": "0.78.0",
"@zag-js/i18n-utils": "0.78.0",
"@zag-js/svelte": "0.78.0",
"nanoid": "5.0.9"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useEnvironmentContext } from '$lib/providers/environment'
import { useLocaleContext } from '$lib/providers/locale'
import type { Accessor, Optional } from '$lib/types'
import { createId } from '$lib/utils/create-id'
Expand All @@ -10,9 +11,11 @@ export interface UseAvatarReturn extends Accessor<avatar.Api<PropTypes>> {}

export const useAvatar = (props: UseAvatarProps = {}) => {
const { dir } = useLocaleContext()
const { getRootNode } = useEnvironmentContext()
const context = $derived({
id: createId(),
dir,
getRootNode,
...props,
})

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script module lang="ts">
import { getDocument, getWindow } from '@zag-js/dom-query'
import type { Snippet } from 'svelte'
import type { RootNode } from './use-environment-context'
export interface EnvironmentProviderProps {
/**
* The root node to use for the environment.
*/
value?: RootNode | (() => RootNode)
/**
* The children to render.
*/
children?: Snippet
}
</script>

<script lang="ts">
import { EnvironmentContextProvider } from './use-environment-context'
import { runIfFn } from '$lib/utils/run-if-fn'
const { value, children }: EnvironmentProviderProps = $props()
let spanRef: HTMLSpanElement | null = $state(null)
const getRootNode = () => runIfFn(value) ?? spanRef?.ownerDocument ?? document
const environment = $state({
getRootNode,
getDocument: () => getDocument(getRootNode()),
getWindow: () => getWindow(getRootNode()),
})
EnvironmentContextProvider(environment)
</script>

{@render children?.()}
{#if !value}
<span bind:this={spanRef} hidden></span>
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Meta } from '@storybook/svelte'
import BasicExample from './examples/basic.svelte'

const meta = {
title: 'Providers / Environment',
} as Meta

export default meta

export const Basic = {
render: () => ({
Component: BasicExample,
}),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script lang="ts">
import { EnvironmentProvider } from '@ark-ui/svelte/environment'
import Usage from './usage.svelte'
</script>

<ifrmae title="IFrame Context">
<EnvironmentProvider>
<Usage />
</EnvironmentProvider>
</ifrmae>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import { EnvironmentProvider } from '@ark-ui/svelte/environment'
</script>

<ifrmae title="IFrame Context">
<EnvironmentProvider><!-- Your App --></EnvironmentProvider>
</ifrmae>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import { useEnvironmentContext } from '@ark-ui/svelte/environment'
const environment = useEnvironmentContext()
</script>

<pre>{JSON.stringify(environment?.getRootNode(), null, 2)}</pre>
9 changes: 9 additions & 0 deletions packages/svelte/src/lib/providers/environment/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export {
default as EnvironmentProvider,
type EnvironmentProviderProps,
} from './environment-provider.svelte'
export {
useEnvironmentContext,
type EnvironmentContext,
type RootNode,
} from './use-environment-context'
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { createContext } from '$lib/utils/create-context'

export type RootNode = ShadowRoot | Document | Node

export interface EnvironmentContext {
/**
* The root node of the application.
* This is used to determine the window and document objects.
* @default document
*/
getRootNode(): RootNode
/**
* The document context for the root node.
* @default document
*/
getDocument(): Document
/**
* The window context for the root node.
* @default window
*/
getWindow(): Window & typeof globalThis
}

export const [EnvironmentContextProvider, useEnvironmentContext] =
createContext<EnvironmentContext>({
key: 'EnvironmentContext',
defaultValue: {
getRootNode: () => document,
getDocument: () => document,
getWindow: () => window,
},
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script module lang="ts">
import type { Locale } from '@zag-js/i18n-utils'
import type { Snippet } from 'svelte'
import type { UseLocaleContext } from './use-locale-context'
export interface LocaleProviderProps {
/**
Expand All @@ -21,7 +21,7 @@
let { locale, children }: LocaleProviderProps = $props()
const context = $state<Locale>({
const context = $state<UseLocaleContext>({
locale,
dir: isRTL(locale) ? 'rtl' : 'ltr',
})
Expand Down
11 changes: 11 additions & 0 deletions packages/svelte/src/lib/utils/run-if-fn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type AnyFunction<Arg = unknown, ReturnValue = unknown> = (...args: Arg[]) => ReturnValue

const isFunction = <T = AnyFunction>(value: unknown): value is T => typeof value === 'function'

export const runIfFn = <MaybeReturnValue, FunctionArgs>(
valueOrFn: MaybeReturnValue | ((...fnArgs: FunctionArgs[]) => MaybeReturnValue),
...args: FunctionArgs[]
) =>
isFunction<AnyFunction<FunctionArgs, MaybeReturnValue>>(valueOrFn)
? valueOrFn(...args)
: (valueOrFn as unknown as MaybeReturnValue)

0 comments on commit bb76fc4

Please sign in to comment.