UNPKG

seitu

Version:
88 lines (87 loc) • 2.33 kB
import { deepEqual } from "fast-equals"; import { readable } from "svelte/store"; //#region src/svelte/hooks/index.ts /** * Subscribe to a reactive value from a Svelte component. Pass a handle or a * factory (run once). Returns a Svelte `Readable` (`$value`); it attaches on * first subscriber and detaches on last. * * @example Inline subscription * ```svelte * <script lang="ts"> * import { createWebStorageValue } from 'seitu/web' * import { useSubscription } from 'seitu/svelte' * import * as z from 'zod' * * const value = useSubscription(() => createWebStorageValue({ * type: 'sessionStorage', * key: 'test', * defaultValue: 0, * schema: z.number(), * })) * <\/script> * * <div>{$value}</div> * ``` * * @example Instance outside of component * ```svelte * <script lang="ts"> * import { createWebStorage } from 'seitu/web' * import { useSubscription } from 'seitu/svelte' * import * as z from 'zod' * * const sessionStorage = createWebStorage({ * type: 'sessionStorage', * schemas: { count: z.number(), name: z.string() }, * defaultValues: { count: 0, name: '' }, * }) * * const value = useSubscription(sessionStorage) * <\/script> * * <div>{$value.count}</div> * ``` * * @example With selector * ```svelte * <script lang="ts"> * import { createWebStorage } from 'seitu/web' * import { useSubscription } from 'seitu/svelte' * import * as z from 'zod' * * const sessionStorage = createWebStorage({ * type: 'sessionStorage', * schemas: { count: z.number(), name: z.string() }, * defaultValues: { count: 0, name: '' }, * }) * * // Updates only when `count` changes * const count = useSubscription(sessionStorage, { selector: v => v.count }) * <\/script> * * <div>{$count}</div> * ``` */ function useSubscription(source, options) { const { selector, isEqual = deepEqual } = options ?? {}; const sub = typeof source === "function" ? source() : source; function getSnapshot() { return selector ? selector(sub.get()) : sub.get(); } const initial = getSnapshot(); return readable(initial, (set) => { let current = initial; function refresh() { const next = getSnapshot(); if (!isEqual(current, next)) { current = next; set(next); } } refresh(); return sub.subscribe(refresh); }); } //#endregion export { useSubscription };