seitu 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/core-BKImMfak.mjs +308 -0
  2. package/dist/core.d.mts +2 -0
  3. package/dist/core.mjs +2 -0
  4. package/dist/index-ChvHgGIa.d.mts +207 -0
  5. package/dist/{react/hooks.d.ts → react.d.mts} +73 -7
  6. package/dist/react.mjs +176 -0
  7. package/dist/{utils/validation.d.ts → utils.d.mts} +7 -3
  8. package/dist/utils.mjs +32 -0
  9. package/dist/validate-BzLxGOQt.d.mts +93 -0
  10. package/dist/{vue/composables.d.ts → vue.d.mts} +10 -6
  11. package/dist/vue.mjs +87 -0
  12. package/dist/web.d.mts +383 -0
  13. package/dist/web.mjs +445 -0
  14. package/package.json +24 -25
  15. package/dist/core/computed.d.ts +0 -33
  16. package/dist/core/debounce-fn.d.ts +0 -21
  17. package/dist/core/debounce.d.ts +0 -19
  18. package/dist/core/index.d.ts +0 -8
  19. package/dist/core/schema-store.d.ts +0 -35
  20. package/dist/core/store.d.ts +0 -20
  21. package/dist/core/subscription.d.ts +0 -35
  22. package/dist/core/throttle-fn.d.ts +0 -23
  23. package/dist/core/throttle.d.ts +0 -19
  24. package/dist/core-CIQELdxV.js +0 -158
  25. package/dist/core.js +0 -2
  26. package/dist/react/components.d.ts +0 -58
  27. package/dist/react/index.d.ts +0 -2
  28. package/dist/react.js +0 -19
  29. package/dist/utils/index.d.ts +0 -1
  30. package/dist/utils.d.ts +0 -7
  31. package/dist/utils.js +0 -9
  32. package/dist/validate.d.ts +0 -19
  33. package/dist/vue/index.d.ts +0 -1
  34. package/dist/vue/test-utils.d.ts +0 -2
  35. package/dist/vue.js +0 -22
  36. package/dist/web/index.d.ts +0 -5
  37. package/dist/web/is-online.d.ts +0 -33
  38. package/dist/web/media-query.d.ts +0 -77
  39. package/dist/web/scroll-state.d.ts +0 -111
  40. package/dist/web/web-storage-value.d.ts +0 -74
  41. package/dist/web/web-storage.d.ts +0 -70
  42. package/dist/web.js +0 -179
package/dist/react.mjs ADDED
@@ -0,0 +1,176 @@
1
+ import { deepEqual } from "fast-equals";
2
+ import * as React from "react";
3
+ //#region src/react/hooks.ts
4
+ /**
5
+ * Use this hook to subscribe to a reactive value. Accepts a subscription object
6
+ * directly, or a factory function that is called only once on first render —
7
+ * subsequent renders reuse the cached subscription unless dependency array changes.
8
+ *
9
+ * @example Inline subscription
10
+ * ```tsx twoslash title="/app/page.tsx"
11
+ * 'use client'
12
+ *
13
+ * import { createWebStorageValue } from 'seitu/web'
14
+ * import { useSubscription } from 'seitu/react'
15
+ * import * as z from 'zod'
16
+ *
17
+ * export default function Page() {
18
+ * const value = useSubscription(() => createWebStorageValue({
19
+ * type: 'sessionStorage',
20
+ * key: 'test',
21
+ * defaultValue: 0,
22
+ * schema: z.number(),
23
+ * }))
24
+ *
25
+ * return <div>{value}</div>
26
+ * }
27
+ * ```
28
+ *
29
+ * @example Instance outside of component
30
+ * ```tsx twoslash title="/app/page.tsx"
31
+ * 'use client'
32
+ *
33
+ * import { createWebStorage } from 'seitu/web'
34
+ * import { useSubscription } from 'seitu/react'
35
+ * import * as z from 'zod'
36
+ *
37
+ * const sessionStorage = createWebStorage({
38
+ * type: 'sessionStorage',
39
+ * schemas: { count: z.number(), name: z.string() },
40
+ * defaultValues: { count: 0, name: '' },
41
+ * })
42
+ *
43
+ * export default function Page() {
44
+ * const value = useSubscription(sessionStorage)
45
+ * return <div>{value.count}</div>
46
+ * }
47
+ * ```
48
+ *
49
+ * @example Subscription with selector
50
+ * ```tsx twoslash title="/app/page.tsx"
51
+ * 'use client'
52
+ *
53
+ * import { createWebStorage } from 'seitu/web'
54
+ * import { useSubscription } from 'seitu/react'
55
+ * import * as z from 'zod'
56
+ *
57
+ * const sessionStorage = createWebStorage({
58
+ * type: 'sessionStorage',
59
+ * schemas: {
60
+ * count: z.number(),
61
+ * name: z.string(),
62
+ * },
63
+ * defaultValues: { count: 0, name: '' },
64
+ * })
65
+ *
66
+ * export default function Page() {
67
+ * // Usage with selector, re-renders only when count changes
68
+ * const count = useSubscription(sessionStorage, { selector: value => value.count })
69
+ *
70
+ * return <div>{count}</div>
71
+ * }
72
+ * ```
73
+ *
74
+ * @example Ref example
75
+ * ```tsx twoslash title="/app/page.tsx"
76
+ * 'use client'
77
+ *
78
+ * import * as React from 'react'
79
+ * import { createScrollState } from 'seitu/web'
80
+ * import { useSubscription } from 'seitu/react'
81
+ *
82
+ * export default function Page() {
83
+ * const ref = React.useRef<HTMLDivElement>(null)
84
+ * const state = useSubscription(() => createScrollState({ element: () => ref.current, direction: 'vertical' }))
85
+ *
86
+ * return (
87
+ * <div ref={ref}>
88
+ * {String(state.top.reached)}
89
+ * </div>
90
+ * )
91
+ * }
92
+ * ```
93
+ */
94
+ function useSubscription(source, options) {
95
+ const { selector, deps = [], isEqual = deepEqual } = options ?? {};
96
+ const isFactory = typeof source === "function";
97
+ const factoryFn = isFactory ? source : () => source;
98
+ const subscription = React.useMemo(() => factoryFn(), isFactory ? deps : [source, ...deps]);
99
+ const lastSnapshotRef = React.useRef(void 0);
100
+ const subscriptionRef = React.useRef(subscription);
101
+ if (subscriptionRef.current !== subscription) {
102
+ subscriptionRef.current = subscription;
103
+ lastSnapshotRef.current = void 0;
104
+ }
105
+ const selectorRef = React.useRef(selector);
106
+ const isEqualRef = React.useRef(isEqual);
107
+ selectorRef.current = selector;
108
+ isEqualRef.current = isEqual;
109
+ const getSnapshot = React.useCallback(() => {
110
+ const sel = selectorRef.current;
111
+ const next = sel ? sel(subscriptionRef.current.get()) : subscriptionRef.current.get();
112
+ const prev = lastSnapshotRef.current;
113
+ if (prev !== void 0 && isEqualRef.current(prev, next)) return prev;
114
+ lastSnapshotRef.current = next;
115
+ return next;
116
+ }, []);
117
+ return React.useSyncExternalStore(subscription.subscribe, getSnapshot, getSnapshot);
118
+ }
119
+ //#endregion
120
+ //#region src/react/components.tsx
121
+ /**
122
+ * Declarative component that subscribes to a reactive value and passes it to a render function.
123
+ * Re-renders when the value (or selected value) changes. Use when you prefer a component API
124
+ * over the useSubscription hook.
125
+ *
126
+ * @example Basic usage
127
+ * ```tsx twoslash title="/app/page.tsx"
128
+ * 'use client'
129
+ *
130
+ * import { createWebStorage } from 'seitu/web'
131
+ * import { Subscription } from 'seitu/react'
132
+ * import * as z from 'zod'
133
+ *
134
+ * const sessionStorage = createWebStorage({
135
+ * type: 'sessionStorage',
136
+ * schemas: { count: z.number(), name: z.string() },
137
+ * defaultValues: { count: 0, name: '' },
138
+ * })
139
+ *
140
+ * export default function Page() {
141
+ * return (
142
+ * <Subscription value={sessionStorage}>
143
+ * {(value) => <div>{value.count}</div>}
144
+ * </Subscription>
145
+ * )
146
+ * }
147
+ * ```
148
+ *
149
+ * @example With selector
150
+ * ```tsx twoslash title="/app/page.tsx"
151
+ * 'use client'
152
+ *
153
+ * import { createWebStorage } from 'seitu/web'
154
+ * import { Subscription } from 'seitu/react'
155
+ * import * as z from 'zod'
156
+ *
157
+ * const sessionStorage = createWebStorage({
158
+ * type: 'sessionStorage',
159
+ * schemas: { count: z.number(), name: z.string() },
160
+ * defaultValues: { count: 0, name: '' },
161
+ * })
162
+ *
163
+ * export default function Page() {
164
+ * return (
165
+ * <Subscription value={sessionStorage} selector={(v) => v.count}>
166
+ * {(count) => <div>{count}</div>}
167
+ * </Subscription>
168
+ * )
169
+ * }
170
+ * ```
171
+ */
172
+ function Subscription({ value, selector, children }) {
173
+ return children(useSubscription(value, { selector }));
174
+ }
175
+ //#endregion
176
+ export { Subscription, useSubscription };
@@ -1,4 +1,6 @@
1
- import type { ValidationSchemaErrorProps } from '../validate';
1
+ import { t as ValidationSchemaErrorProps } from "./validate-BzLxGOQt.mjs";
2
+
3
+ //#region src/utils/validation.d.ts
2
4
  /**
3
5
  * Repair broken web storage value object if value was object but not all keys are in the default value object.
4
6
  *
@@ -22,6 +24,8 @@ import type { ValidationSchemaErrorProps } from '../validate';
22
24
  * value.get() // { a: 1, b: 'default' }
23
25
  * ```
24
26
  */
25
- export declare function repairValueObjectWithDefault<O extends Record<string, unknown>>(props: ValidationSchemaErrorProps<O>): O & {
26
- [k: string]: any;
27
+ declare function repairValueObjectWithDefault<O extends Record<string, unknown>>(props: ValidationSchemaErrorProps<O>): O & {
28
+ [k: string]: any;
27
29
  };
30
+ //#endregion
31
+ export { repairValueObjectWithDefault };
package/dist/utils.mjs ADDED
@@ -0,0 +1,32 @@
1
+ //#region src/utils/validation.ts
2
+ /**
3
+ * Repair broken web storage value object if value was object but not all keys are in the default value object.
4
+ *
5
+ * @returns A new object with the existing keys in the value object that are not in the default value object.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { createWebStorageValue } from 'seitu/web'
10
+ * import { repairValueObjectWithDefault } from 'seitu/utils'
11
+ * import * as z from 'zod'
12
+ *
13
+ * const value = createWebStorageValue({
14
+ * type: 'localStorage',
15
+ * schema: z.object({ a: z.number(), b: z.string() }),
16
+ * key: 'storage-key',
17
+ * defaultValue: { a: 0, b: 'default' },
18
+ * onValidationError: repairValueObjectWithDefault,
19
+ * })
20
+ * value.get() // { a: 0, b: 'default' }
21
+ * window.localStorage.setItem('storage-key', JSON.stringify({ a: 1 }))
22
+ * value.get() // { a: 1, b: 'default' }
23
+ * ```
24
+ */
25
+ function repairValueObjectWithDefault(props) {
26
+ return {
27
+ ...props.defaultValue,
28
+ ...typeof props.value === "object" && props.value !== null ? Object.fromEntries(Object.entries(props.value).filter(([key, val]) => key in props.defaultValue && typeof val === typeof props.defaultValue[key])) : {}
29
+ };
30
+ }
31
+ //#endregion
32
+ export { repairValueObjectWithDefault };
@@ -0,0 +1,93 @@
1
+ //#region ../node_modules/.pnpm/@standard-schema+spec@1.1.0/node_modules/@standard-schema/spec/dist/index.d.ts
2
+ /** The Standard Typed interface. This is a base type extended by other specs. */
3
+ interface StandardTypedV1<Input = unknown, Output = Input> {
4
+ /** The Standard properties. */
5
+ readonly "~standard": StandardTypedV1.Props<Input, Output>;
6
+ }
7
+ declare namespace StandardTypedV1 {
8
+ /** The Standard Typed properties interface. */
9
+ interface Props<Input = unknown, Output = Input> {
10
+ /** The version number of the standard. */
11
+ readonly version: 1;
12
+ /** The vendor name of the schema library. */
13
+ readonly vendor: string;
14
+ /** Inferred types associated with the schema. */
15
+ readonly types?: Types<Input, Output> | undefined;
16
+ }
17
+ /** The Standard Typed types interface. */
18
+ interface Types<Input = unknown, Output = Input> {
19
+ /** The input type of the schema. */
20
+ readonly input: Input;
21
+ /** The output type of the schema. */
22
+ readonly output: Output;
23
+ }
24
+ /** Infers the input type of a Standard Typed. */
25
+ type InferInput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["input"];
26
+ /** Infers the output type of a Standard Typed. */
27
+ type InferOutput<Schema extends StandardTypedV1> = NonNullable<Schema["~standard"]["types"]>["output"];
28
+ }
29
+ /** The Standard Schema interface. */
30
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
31
+ /** The Standard Schema properties. */
32
+ readonly "~standard": StandardSchemaV1.Props<Input, Output>;
33
+ }
34
+ declare namespace StandardSchemaV1 {
35
+ /** The Standard Schema properties interface. */
36
+ interface Props<Input = unknown, Output = Input> extends StandardTypedV1.Props<Input, Output> {
37
+ /** Validates unknown input values. */
38
+ readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => Result<Output> | Promise<Result<Output>>;
39
+ }
40
+ /** The result interface of the validate function. */
41
+ type Result<Output> = SuccessResult<Output> | FailureResult;
42
+ /** The result interface if validation succeeds. */
43
+ interface SuccessResult<Output> {
44
+ /** The typed output value. */
45
+ readonly value: Output;
46
+ /** A falsy value for `issues` indicates success. */
47
+ readonly issues?: undefined;
48
+ }
49
+ interface Options {
50
+ /** Explicit support for additional vendor-specific parameters, if needed. */
51
+ readonly libraryOptions?: Record<string, unknown> | undefined;
52
+ }
53
+ /** The result interface if validation fails. */
54
+ interface FailureResult {
55
+ /** The issues of failed validation. */
56
+ readonly issues: ReadonlyArray<Issue>;
57
+ }
58
+ /** The issue interface of the failure output. */
59
+ interface Issue {
60
+ /** The error message of the issue. */
61
+ readonly message: string;
62
+ /** The path of the issue, if any. */
63
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
64
+ }
65
+ /** The path segment interface of the issue. */
66
+ interface PathSegment {
67
+ /** The key representing a path segment. */
68
+ readonly key: PropertyKey;
69
+ }
70
+ /** The Standard types interface. */
71
+ interface Types<Input = unknown, Output = Input> extends StandardTypedV1.Types<Input, Output> {}
72
+ /** Infers the input type of a Standard. */
73
+ type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
74
+ /** Infers the output type of a Standard. */
75
+ type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
76
+ }
77
+ /** The Standard JSON Schema interface. */
78
+ //#endregion
79
+ //#region src/validate.d.ts
80
+ type ValidationSchemaOutput<S extends StandardSchemaV1<unknown>> = StandardSchemaV1.InferOutput<S>;
81
+ interface ValidationSchemaErrorProps<O> {
82
+ defaultValue: O;
83
+ issues: StandardSchemaV1.Issue[];
84
+ value: unknown;
85
+ }
86
+ interface ValidationSchemaObjectErrorProps<O extends Record<string, unknown>> {
87
+ defaultValue: O[keyof O];
88
+ issues: StandardSchemaV1.Issue[];
89
+ value: unknown;
90
+ key: keyof O;
91
+ }
92
+ //#endregion
93
+ export { StandardSchemaV1 as i, ValidationSchemaObjectErrorProps as n, ValidationSchemaOutput as r, ValidationSchemaErrorProps as t };
@@ -1,8 +1,10 @@
1
- import type { MaybeRefOrGetter, ShallowRef } from 'vue';
2
- import type { Readable, Subscribable } from '../core/index';
3
- export interface UseSubscriptionOptions<S extends Subscribable<any> & Readable<any>, R = S['~']['output']> {
4
- selector?: (value: S['~']['output']) => R;
5
- isEqual?: (prev: R, next: R) => boolean;
1
+ import { _ as Readable, v as Subscribable } from "./index-ChvHgGIa.mjs";
2
+ import { MaybeRefOrGetter, ShallowRef } from "vue";
3
+
4
+ //#region src/vue/composables.d.ts
5
+ interface UseSubscriptionOptions<S extends Subscribable<any> & Readable<any>, R = S['~']['output']> {
6
+ selector?: (value: S['~']['output']) => R;
7
+ isEqual?: (prev: R, next: R) => boolean;
6
8
  }
7
9
  /**
8
10
  * Use this composable to subscribe to a reactive value. Accepts a subscription object
@@ -67,4 +69,6 @@ export interface UseSubscriptionOptions<S extends Subscribable<any> & Readable<a
67
69
  * </template>
68
70
  * ```
69
71
  */
70
- export declare function useSubscription<S extends Subscribable<any> & Readable<any>, R = S['~']['output']>(source: MaybeRefOrGetter<S>, options?: UseSubscriptionOptions<S, R>): Readonly<ShallowRef<R>>;
72
+ declare function useSubscription<S extends Subscribable<any> & Readable<any>, R = S['~']['output']>(source: MaybeRefOrGetter<S>, options?: UseSubscriptionOptions<S, R>): Readonly<ShallowRef<R>>;
73
+ //#endregion
74
+ export { UseSubscriptionOptions, useSubscription };
package/dist/vue.mjs ADDED
@@ -0,0 +1,87 @@
1
+ import { deepEqual } from "fast-equals";
2
+ import { computed, onWatcherCleanup, readonly, shallowRef, toValue, watch } from "vue";
3
+ //#region src/vue/composables.ts
4
+ /**
5
+ * Use this composable to subscribe to a reactive value. Accepts a subscription object
6
+ * directly or a ref/getter that returns one.
7
+ *
8
+ * @example Inline subscription
9
+ * ```vue
10
+ * <script setup lang="ts">
11
+ * import { createWebStorageValue } from 'seitu/web'
12
+ * import { useSubscription } from 'seitu/vue'
13
+ * import * as z from 'zod'
14
+ *
15
+ * const value = useSubscription(
16
+ * createWebStorageValue({ type: 'sessionStorage', key: 'test', defaultValue: 0, schema: z.number() }),
17
+ * )
18
+ * <\/script>
19
+ *
20
+ * <template>
21
+ * <div>{{ value }}</div>
22
+ * </template>
23
+ * ```
24
+ *
25
+ * @example Instance outside of the subscription
26
+ * ```vue
27
+ * <script setup lang="ts">
28
+ * import { createWebStorage } from 'seitu/web'
29
+ * import { useSubscription } from 'seitu/vue'
30
+ * import * as z from 'zod'
31
+ *
32
+ * const sessionStorage = createWebStorage({
33
+ * type: 'sessionStorage',
34
+ * schemas: { count: z.number(), name: z.string() },
35
+ * defaultValues: { count: 0, name: '' },
36
+ * })
37
+ *
38
+ * const value = useSubscription(sessionStorage)
39
+ * <\/script>
40
+ *
41
+ * <template>
42
+ * <div>{{ value.count }}</div>
43
+ * </template>
44
+ * ```
45
+ *
46
+ * @example With selector
47
+ * ```vue
48
+ * <script setup lang="ts">
49
+ * import { createWebStorage } from 'seitu/web'
50
+ * import { useSubscription } from 'seitu/vue'
51
+ * import * as z from 'zod'
52
+ *
53
+ * const sessionStorage = createWebStorage({
54
+ * type: 'sessionStorage',
55
+ * schemas: { count: z.number(), name: z.string() },
56
+ * defaultValues: { count: 0, name: '' },
57
+ * })
58
+ *
59
+ * const count = useSubscription(sessionStorage, { selector: v => v.count })
60
+ * <\/script>
61
+ *
62
+ * <template>
63
+ * <div>{{ count }}</div>
64
+ * </template>
65
+ * ```
66
+ */
67
+ function useSubscription(source, options) {
68
+ const { selector, isEqual = deepEqual } = options ?? {};
69
+ function getSnapshot(sub) {
70
+ return selector ? selector(sub.get()) : sub.get();
71
+ }
72
+ const sub = computed(() => toValue(source));
73
+ const state = shallowRef(getSnapshot(sub.value));
74
+ watch(sub, (sub) => {
75
+ state.value = getSnapshot(sub);
76
+ const unsubscribe = sub.subscribe(() => {
77
+ const next = getSnapshot(sub);
78
+ if (!isEqual(state.value, next)) state.value = next;
79
+ });
80
+ onWatcherCleanup(() => {
81
+ unsubscribe();
82
+ });
83
+ }, { immediate: true });
84
+ return readonly(state);
85
+ }
86
+ //#endregion
87
+ export { useSubscription };