seitu 0.7.0 → 0.9.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.
@@ -0,0 +1,21 @@
1
+ import type { Readable, Subscribable } from './subscription';
2
+ export interface DebouncedFn<A extends unknown[], R> extends Readable<R | undefined>, Subscribable<R | undefined> {
3
+ (...args: A): void;
4
+ }
5
+ /**
6
+ * Wraps a plain function in a debounced callable that also acts as a subscribable.
7
+ *
8
+ * Each call resets the debounce timer. When the timer fires, the wrapped function
9
+ * is invoked and its return value becomes the current state, notifying subscribers.
10
+ *
11
+ * @example
12
+ * ```ts twoslash
13
+ * import { createDebounceFn } from 'seitu'
14
+ *
15
+ * const search = createDebounceFn((query: string) => fetch(`/api?q=${query}`), 300)
16
+ * search.subscribe(result => console.log('result:', result))
17
+ * search('hello') // debounced — fires after 300ms of inactivity
18
+ * search.get() // latest return value (undefined until first call)
19
+ * ```
20
+ */
21
+ export declare function createDebounceFn<A extends unknown[], R>(fn: (...args: A) => R, wait: number): DebouncedFn<A, R>;
@@ -0,0 +1,19 @@
1
+ import type { Readable, Subscribable } from './subscription';
2
+ export interface Debounced<T> extends Readable<T>, Subscribable<T> {
3
+ }
4
+ /**
5
+ * Creates a debounced readable that delays updates from a source subscribable.
6
+ *
7
+ * The debounced store will only emit the latest value after `wait` milliseconds
8
+ * of inactivity from the source.
9
+ *
10
+ * @example
11
+ * ```ts twoslash
12
+ * import { createStore, createDebounce } from 'seitu'
13
+ *
14
+ * const store = createStore('')
15
+ * const debounced = createDebounce(store, 300)
16
+ * debounced.subscribe(value => console.log('debounced:', value))
17
+ * ```
18
+ */
19
+ export declare function createDebounce<T>(source: Readable<T> & Subscribable<T>, wait: number): Debounced<T>;
@@ -1,4 +1,8 @@
1
1
  export * from './computed';
2
+ export * from './debounce';
3
+ export * from './debounce-fn';
2
4
  export * from './schema-store';
3
5
  export * from './store';
4
6
  export * from './subscription';
7
+ export * from './throttle';
8
+ export * from './throttle-fn';
@@ -1,11 +1,11 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
2
  import type { Simplify } from '../utils';
3
- import type { Destroyable, Readable, Subscribable, Writable } from './index';
3
+ import type { Readable, Subscribable, Writable } from './index';
4
4
  export type SchemaStoreSchema = Record<string, StandardSchemaV1<unknown, unknown>>;
5
5
  export type SchemaStoreOutput<S extends SchemaStoreSchema> = Simplify<{
6
6
  [K in keyof S]: StandardSchemaV1.InferOutput<S[K]>;
7
7
  }>;
8
- export interface SchemaStore<O extends Record<string, unknown>> extends Subscribable<O>, Readable<O>, Writable<Partial<O>, O>, Destroyable {
8
+ export interface SchemaStore<O extends Record<string, unknown>> extends Subscribable<O>, Readable<O>, Writable<Partial<O>, O> {
9
9
  getDefaultValue: <K extends keyof O>(key: K) => O[K];
10
10
  }
11
11
  export interface SchemaStoreOptions<S extends Record<string, StandardSchemaV1>> {
@@ -39,7 +39,6 @@ export declare function createSchemaStore<S extends Record<string, StandardSchem
39
39
  export interface SchemaStoreProvider<S extends SchemaStoreSchema> {
40
40
  get: () => SchemaStoreOutput<S>;
41
41
  set: (value: Partial<SchemaStoreOutput<S>>) => void;
42
- destroy?: () => void;
43
42
  }
44
43
  /**
45
44
  * Creates an in-memory provider for a schema store. Use as the state backing when you don't
@@ -26,10 +26,9 @@ export interface Writable<T, P = T> {
26
26
  export interface Removable {
27
27
  remove: () => void;
28
28
  }
29
- export interface Destroyable {
30
- destroy: () => void;
31
- }
32
- export declare function createSubscription(): {
29
+ export declare function createSubscription(options?: {
30
+ onFirstSubscribe?: () => (void | (() => void));
31
+ }): {
33
32
  subscribe: (callback: () => any, options?: SubscribeOptions) => () => void;
34
33
  notify: () => void;
35
34
  };
@@ -0,0 +1,23 @@
1
+ import type { Readable, Subscribable } from './subscription';
2
+ export interface ThrottledFn<A extends unknown[], R> extends Readable<R | undefined>, Subscribable<R | undefined> {
3
+ (...args: A): void;
4
+ }
5
+ /**
6
+ * Wraps a plain function in a throttled callable that also acts as a subscribable.
7
+ *
8
+ * The first call fires immediately. Subsequent calls within the `wait` window are
9
+ * batched — only the last one fires when the interval elapses. The return value of
10
+ * the wrapped function becomes the current state, notifying subscribers.
11
+ *
12
+ * @example
13
+ * ```ts twoslash
14
+ * import { createThrottleFn } from 'seitu'
15
+ *
16
+ * const log = createThrottleFn((msg: string) => console.log(msg), 300)
17
+ * log.subscribe(result => console.log('result:', result))
18
+ * log('hello') // fires immediately
19
+ * log('world') // throttled — fires after 300ms
20
+ * log.get() // latest return value (undefined until first call)
21
+ * ```
22
+ */
23
+ export declare function createThrottleFn<A extends unknown[], R>(fn: (...args: A) => R, wait: number): ThrottledFn<A, R>;
@@ -0,0 +1,19 @@
1
+ import type { Readable, Subscribable } from './subscription';
2
+ export interface Throttled<T> extends Readable<T>, Subscribable<T> {
3
+ }
4
+ /**
5
+ * Creates a throttled readable that rate-limits updates from a source subscribable.
6
+ *
7
+ * Emits the latest value at most once every `wait` milliseconds. The first update
8
+ * fires immediately, then subsequent updates are batched until the interval elapses.
9
+ *
10
+ * @example
11
+ * ```ts twoslash
12
+ * import { createStore, createThrottle } from 'seitu'
13
+ *
14
+ * const store = createStore('')
15
+ * const throttled = createThrottle(store, 300)
16
+ * throttled.subscribe(value => console.log('throttled:', value))
17
+ * ```
18
+ */
19
+ export declare function createThrottle<T>(source: Readable<T> & Subscribable<T>, wait: number): Throttled<T>;
@@ -0,0 +1,187 @@
1
+ //#region src/core/subscription.ts
2
+ function e(e) {
3
+ let t = /* @__PURE__ */ new Set(), n = () => t.forEach((e) => e()), r;
4
+ return {
5
+ subscribe(n, i) {
6
+ return t.size === 0 && e?.onFirstSubscribe && (r = e.onFirstSubscribe() ?? void 0), i?.immediate && n(), t.add(n), () => {
7
+ t.delete(n), t.size === 0 && (r?.(), r = void 0);
8
+ };
9
+ },
10
+ notify: n
11
+ };
12
+ }
13
+ //#endregion
14
+ //#region src/core/computed.ts
15
+ function t(t, n) {
16
+ let { subscribe: r, notify: i } = e(), a = Array.isArray(t) ? t : [t], o = !Array.isArray(t), s = () => n(o ? a[0].get() : a.map((e) => e.get()));
17
+ for (let e of a) e.subscribe(() => i());
18
+ return {
19
+ get: s,
20
+ subscribe(e, t) {
21
+ return r(() => e(s()), t);
22
+ },
23
+ "~": {
24
+ output: null,
25
+ notify: i
26
+ }
27
+ };
28
+ }
29
+ //#endregion
30
+ //#region src/core/debounce.ts
31
+ function n(t, n) {
32
+ let r = t.get(), i, { subscribe: a, notify: o } = e({ onFirstSubscribe() {
33
+ let e = t.subscribe(() => {
34
+ clearTimeout(i), i = setTimeout(() => {
35
+ r = t.get(), o();
36
+ }, n);
37
+ });
38
+ return () => {
39
+ clearTimeout(i), e();
40
+ };
41
+ } }), s = () => r;
42
+ return {
43
+ get: s,
44
+ subscribe(e, t) {
45
+ return a(() => e(s()), t);
46
+ },
47
+ "~": {
48
+ output: null,
49
+ notify: o
50
+ }
51
+ };
52
+ }
53
+ //#endregion
54
+ //#region src/core/debounce-fn.ts
55
+ function r(t, n) {
56
+ let r, i, { subscribe: a, notify: o } = e(), s = () => r;
57
+ return Object.assign((...e) => {
58
+ clearTimeout(i), i = setTimeout(() => {
59
+ r = t(...e), o();
60
+ }, n);
61
+ }, {
62
+ get: s,
63
+ subscribe: (e, t) => a(() => e(s()), t),
64
+ "~": {
65
+ output: void 0,
66
+ notify: o
67
+ }
68
+ });
69
+ }
70
+ //#endregion
71
+ //#region src/utils.ts
72
+ function i(e) {
73
+ if (typeof e != "string") return e;
74
+ try {
75
+ return JSON.parse(e);
76
+ } catch {
77
+ return e;
78
+ }
79
+ }
80
+ //#endregion
81
+ //#region src/core/schema-store.ts
82
+ function a(t) {
83
+ let { subscribe: n, notify: r } = e(), a = { ...t.defaultValues }, s = t.provider ?? o(), c = () => {
84
+ let e = { ...a };
85
+ for (let [n, r] of Object.entries(t.schemas)) {
86
+ let t = s.get()[n], o = r["~standard"].validate(i(t));
87
+ if (o instanceof Promise) throw TypeError("[createStorage] Validation schema should not return a Promise.");
88
+ o.issues && console.warn(`[createSchemaStore] Returned value invalid for key ${String(n)}, returned default value instead`, JSON.stringify(o.issues, null, 2), { cause: o.issues }), e[n] = o.issues ? a[n] : o.value;
89
+ }
90
+ return e;
91
+ };
92
+ return {
93
+ get: c,
94
+ set: (e) => {
95
+ let t = typeof e == "function" ? e(c()) : e;
96
+ s.set(t), r();
97
+ },
98
+ getDefaultValue: (e) => a[e],
99
+ subscribe: (e, t) => n(() => e(c()), t),
100
+ "~": {
101
+ output: null,
102
+ notify: r
103
+ }
104
+ };
105
+ }
106
+ function o() {
107
+ let e = s({});
108
+ return {
109
+ get: () => e.get(),
110
+ set: (t) => {
111
+ e.set(t);
112
+ }
113
+ };
114
+ }
115
+ //#endregion
116
+ //#region src/core/store.ts
117
+ function s(t) {
118
+ let n = t, { subscribe: r, notify: i } = e(), a = () => n;
119
+ return {
120
+ get: a,
121
+ set: (e) => {
122
+ let t = typeof e == "function" ? e(n) : e;
123
+ t !== n && (n = t, i());
124
+ },
125
+ subscribe(e, t) {
126
+ return r(() => e(a()), t);
127
+ },
128
+ "~": {
129
+ output: null,
130
+ notify: i
131
+ }
132
+ };
133
+ }
134
+ //#endregion
135
+ //#region src/core/throttle.ts
136
+ function c(t, n) {
137
+ let r = t.get(), i, a = !1, { subscribe: o, notify: s } = e({ onFirstSubscribe() {
138
+ let e = t.subscribe(() => {
139
+ if (i) {
140
+ a = !0;
141
+ return;
142
+ }
143
+ r = t.get(), s(), i = setTimeout(() => {
144
+ i = void 0, a && (a = !1, r = t.get(), s());
145
+ }, n);
146
+ });
147
+ return () => {
148
+ clearTimeout(i), i = void 0, a = !1, e();
149
+ };
150
+ } }), c = () => r;
151
+ return {
152
+ get: c,
153
+ subscribe(e, t) {
154
+ return o(() => e(c()), t);
155
+ },
156
+ "~": {
157
+ output: null,
158
+ notify: s
159
+ }
160
+ };
161
+ }
162
+ //#endregion
163
+ //#region src/core/throttle-fn.ts
164
+ function l(t, n) {
165
+ let r, i, a, { subscribe: o, notify: s } = e(), c = () => r;
166
+ return Object.assign((...e) => {
167
+ if (i) {
168
+ a = e;
169
+ return;
170
+ }
171
+ r = t(...e), s(), i = setTimeout(() => {
172
+ if (i = void 0, a) {
173
+ let e = a;
174
+ a = void 0, r = t(...e), s();
175
+ }
176
+ }, n);
177
+ }, {
178
+ get: c,
179
+ subscribe: (e, t) => o(() => e(c()), t),
180
+ "~": {
181
+ output: void 0,
182
+ notify: s
183
+ }
184
+ });
185
+ }
186
+ //#endregion
187
+ export { o as a, n as c, a as i, t as l, c as n, i as o, s as r, r as s, l as t, e as u };
package/dist/core.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as e, n as t, o as n, r, t as i } from "./core-DLt97Ptv.js";
2
- export { e as createComputed, t as createSchemaStore, r as createSchemaStoreMemoryProvider, i as createStore, n as createSubscription };
1
+ import { a as e, c as t, i as n, l as r, n as i, r as a, s as o, t as s, u as c } from "./core-vtgV_plC.js";
2
+ export { r as createComputed, t as createDebounce, o as createDebounceFn, n as createSchemaStore, e as createSchemaStoreMemoryProvider, a as createStore, c as createSubscription, i as createThrottle, s as createThrottleFn };
@@ -1,4 +1,4 @@
1
- import type { Destroyable, Readable, Subscribable } from '../core/index';
1
+ import type { Readable, Subscribable } from '../core/index';
2
2
  import * as React from 'react';
3
3
  export interface UseSubscriptionOptions<S extends Subscribable<any> & Readable<any>, R = S['~']['output']> {
4
4
  selector?: (value: S['~']['output']) => R;
@@ -91,4 +91,4 @@ export interface UseSubscriptionOptions<S extends Subscribable<any> & Readable<a
91
91
  * }
92
92
  * ```
93
93
  */
94
- export declare function useSubscription<S extends Subscribable<any> & Readable<any> & Partial<Destroyable>, R = S['~']['output']>(source: S | (() => S), options?: UseSubscriptionOptions<S, R>): R;
94
+ export declare function useSubscription<S extends Subscribable<any> & Readable<any>, R = S['~']['output']>(source: S | (() => S), options?: UseSubscriptionOptions<S, R>): R;
package/dist/react.js CHANGED
@@ -2,23 +2,13 @@ import { deepEqual as e } from "fast-equals";
2
2
  import * as t from "react";
3
3
  //#region src/react/hooks.ts
4
4
  function n(n, r) {
5
- let { selector: i, deps: a = [] } = r ?? {}, o = typeof n == "function", s = o ? n : () => n, c = t.useMemo(() => s(), o ? a : [n, ...a]), l = t.useRef(c), u = t.useRef(c), d = t.useRef(void 0);
6
- if (u.current !== c) {
7
- let e = u.current;
8
- u.current = c, l.current = c, d.current = void 0, o && e.destroy?.();
9
- }
10
- t.useEffect(() => () => {
11
- o && l.current.destroy?.();
5
+ let { selector: i, deps: a = [] } = r ?? {}, o = typeof n == "function", s = o ? n : () => n, c = t.useMemo(() => s(), o ? a : [n, ...a]), l = t.useRef(void 0), u = t.useRef(c), d = t.useRef(i);
6
+ (u.current !== c || d.current !== i) && (u.current = c, d.current = i, l.current = void 0);
7
+ let f = t.useCallback(() => {
8
+ let t = d.current, n = t ? t(u.current.get()) : u.current.get(), r = l.current;
9
+ return r !== void 0 && e(r, n) ? r : (l.current = n, n);
12
10
  }, []);
13
- let f = t.useCallback((e) => c.subscribe(() => {
14
- e();
15
- }), [c]), p = t.useRef(i);
16
- p.current !== i && (p.current = i, d.current = void 0);
17
- let m = t.useCallback(() => {
18
- let t = p.current, n = t ? t(c.get()) : c.get(), r = d.current;
19
- return r !== void 0 && e(r, n) ? r : (d.current = n, n);
20
- }, [c]);
21
- return t.useSyncExternalStore(f, m, m);
11
+ return t.useSyncExternalStore(c.subscribe, f, f);
22
12
  }
23
13
  //#endregion
24
14
  //#region src/react/components.tsx
@@ -0,0 +1,67 @@
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
+ }
6
+ /**
7
+ * Use this composable to subscribe to a reactive value. Accepts a subscription object
8
+ * directly or a ref/getter that returns one.
9
+ *
10
+ * @example Inline subscription
11
+ * ```vue
12
+ * <script setup lang="ts">
13
+ * import { createSessionStorageValue } from 'seitu/web'
14
+ * import { useSubscription } from 'seitu/vue'
15
+ * import * as z from 'zod'
16
+ *
17
+ * const value = useSubscription(
18
+ * createSessionStorageValue({ key: 'test', defaultValue: 0, schema: z.number() }),
19
+ * )
20
+ * </script>
21
+ *
22
+ * <template>
23
+ * <div>{{ value }}</div>
24
+ * </template>
25
+ * ```
26
+ *
27
+ * @example Instance outside of the subscription
28
+ * ```vue
29
+ * <script setup lang="ts">
30
+ * import { createSessionStorage } from 'seitu/web'
31
+ * import { useSubscription } from 'seitu/vue'
32
+ * import * as z from 'zod'
33
+ *
34
+ * const sessionStorage = createSessionStorage({
35
+ * schemas: { count: z.number(), name: z.string() },
36
+ * defaultValues: { count: 0, name: '' },
37
+ * })
38
+ *
39
+ * const value = useSubscription(sessionStorage)
40
+ * </script>
41
+ *
42
+ * <template>
43
+ * <div>{{ value.count }}</div>
44
+ * </template>
45
+ * ```
46
+ *
47
+ * @example With selector
48
+ * ```vue
49
+ * <script setup lang="ts">
50
+ * import { createSessionStorage } from 'seitu/web'
51
+ * import { useSubscription } from 'seitu/vue'
52
+ * import * as z from 'zod'
53
+ *
54
+ * const sessionStorage = createSessionStorage({
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
+ export declare function useSubscription<S extends Subscribable<any> & Readable<any>, R = S['~']['output']>(source: MaybeRefOrGetter<S>, options?: UseSubscriptionOptions<S, R>): Readonly<ShallowRef<R>>;
@@ -0,0 +1 @@
1
+ export * from './composables';
@@ -0,0 +1,2 @@
1
+ import type { Component } from 'vue';
2
+ export declare function mount(component: Component): HTMLElement;
package/dist/vue.js ADDED
@@ -0,0 +1,22 @@
1
+ import { deepEqual as e } from "fast-equals";
2
+ import { computed as t, onWatcherCleanup as n, readonly as r, shallowRef as i, toValue as a, watch as o } from "vue";
3
+ //#region src/vue/composables.ts
4
+ function s(s, c) {
5
+ let { selector: l } = c ?? {};
6
+ function u(e) {
7
+ return l ? l(e.get()) : e.get();
8
+ }
9
+ let d = t(() => a(s)), f = i(u(d.value));
10
+ return o(d, (t) => {
11
+ f.value = u(t);
12
+ let r = t.subscribe(() => {
13
+ let n = u(t);
14
+ e(f.value, n) || (f.value = n);
15
+ });
16
+ n(() => {
17
+ r();
18
+ });
19
+ }, { immediate: !0 }), r(f);
20
+ }
21
+ //#endregion
22
+ export { s as useSubscription };
@@ -1,5 +1,5 @@
1
- import type { Destroyable, Readable, Subscribable } from '../core/index';
2
- export interface IsOnline extends Subscribable<boolean>, Readable<boolean>, Destroyable {
1
+ import type { Readable, Subscribable } from '../core/index';
2
+ export interface IsOnline extends Subscribable<boolean>, Readable<boolean> {
3
3
  }
4
4
  /**
5
5
  * Creates a reactive handle for browser online status.
@@ -1,5 +1,5 @@
1
- import type { Destroyable, Readable, Subscribable } from '../core/index';
2
- export interface MediaQuery extends Subscribable<boolean>, Readable<boolean>, Destroyable {
1
+ import type { Readable, Subscribable } from '../core/index';
2
+ export interface MediaQuery extends Subscribable<boolean>, Readable<boolean> {
3
3
  }
4
4
  type MinMaxPrefix = 'min-' | 'max-' | '';
5
5
  type CSSUnitSuffix = 'px' | 'em' | 'rem' | 'vw' | 'vh' | 'dvw' | 'dvh' | 'svw' | 'svh' | 'lvw' | 'lvh' | 'cqw' | 'cqh' | 'vmin' | 'vmax' | 'cm' | 'mm' | 'in' | 'pt' | 'pc';
@@ -1,7 +1,7 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
- import type { Destroyable, Readable, Removable, Subscribable, Writable } from '../core/index';
2
+ import type { Readable, Removable, Subscribable, Writable } from '../core/index';
3
3
  import type { WebStorage } from './web-storage';
4
- export interface WebStorageValue<V> extends Subscribable<V>, Readable<V>, Writable<V>, Destroyable, Removable {
4
+ export interface WebStorageValue<V> extends Subscribable<V>, Readable<V>, Writable<V>, Removable {
5
5
  }
6
6
  export interface WebStorageValueOptionsWithStorage<Storage extends WebStorage<any>, K extends keyof Storage['~']['output']> {
7
7
  storage: Storage;
package/dist/web.js CHANGED
@@ -1,116 +1,122 @@
1
- import { i as e, n as t, o as n } from "./core-DLt97Ptv.js";
1
+ import { o as e, u as t } from "./core-vtgV_plC.js";
2
2
  //#region src/web/is-online.ts
3
- function r() {
4
- let { subscribe: e, notify: t } = n(), r = () => typeof navigator > "u" ? !0 : navigator.onLine, i = () => t();
5
- return typeof window < "u" && (window.addEventListener("online", i), window.addEventListener("offline", i)), {
3
+ function n() {
4
+ let { subscribe: e, notify: n } = t({ onFirstSubscribe: () => (typeof window < "u" && (window.addEventListener("online", n), window.addEventListener("offline", n)), () => {
5
+ typeof window < "u" && (window.removeEventListener("online", n), window.removeEventListener("offline", n));
6
+ }) }), r = () => typeof navigator > "u" ? !0 : navigator.onLine;
7
+ return {
6
8
  get: r,
7
9
  subscribe: (t, n) => e(() => t(r()), n),
8
- destroy: () => {
9
- typeof window < "u" && (window.removeEventListener("online", i), window.removeEventListener("offline", i));
10
- },
11
10
  "~": {
12
11
  output: null,
13
- notify: t
12
+ notify: n
14
13
  }
15
14
  };
16
15
  }
17
16
  //#endregion
18
17
  //#region src/web/web-storage.ts
19
- function i(n) {
20
- let r = !1, i = t({
21
- defaultValues: n.defaultValues,
22
- schemas: n.schemas,
23
- provider: {
24
- get: () => {
25
- if (typeof window > "u") return n.defaultValues;
26
- let t = window[n.kind], r = { ...n.defaultValues };
27
- for (let i in r) {
28
- let a = t.getItem(n.keyTransform ? n.keyTransform(i) : i);
29
- if (a === null) {
30
- r[i] = n.defaultValues[i];
31
- continue;
32
- }
33
- let o = e(a), s = n.schemas[i]["~standard"].validate(o);
34
- if (s instanceof Promise) throw TypeError("[createWebSchemaStore] Validation schema should not return a Promise.");
35
- if (s.issues) if (n.onValidationError) {
36
- let e = n.onValidationError({
37
- issues: [...s.issues],
38
- key: i,
39
- value: o
40
- });
41
- if (e !== void 0) {
42
- let t = n.schemas[i]["~standard"].validate(e);
43
- if (t instanceof Promise) throw TypeError("Validation schema should not return a Promise.");
44
- t.issues ? console.error("Returned value invalid, returned default value instead", JSON.stringify(t.issues, null, 2), { cause: t.issues }) : r[i] = t.value;
45
- }
46
- } else console.warn(JSON.stringify(s.issues, null, 2), { cause: s.issues }), r[i] = n.defaultValues[i];
47
- else r[i] = s.value;
48
- }
49
- return r;
50
- },
51
- set: (e) => {
52
- if (typeof window > "u") return;
53
- let t = window[n.kind];
54
- r = !0, Object.entries(e).forEach(([e, r]) => {
55
- let i = typeof r == "string" ? r : JSON.stringify(r);
56
- t.setItem(n.keyTransform ? n.keyTransform(e) : e, i), window.dispatchEvent(new StorageEvent("storage", {
57
- key: n.keyTransform ? n.keyTransform(e) : e,
58
- newValue: i
59
- }));
60
- }), r = !1;
18
+ function r(n) {
19
+ let r = !1, { subscribe: i, notify: a } = t({ onFirstSubscribe: () => {
20
+ let e = () => {
21
+ r || a();
22
+ };
23
+ return typeof window < "u" && window.addEventListener("storage", e), () => {
24
+ typeof window < "u" && window.removeEventListener("storage", e);
25
+ };
26
+ } }), o = { ...n.defaultValues }, s = () => {
27
+ if (typeof window > "u") return n.defaultValues;
28
+ let t = window[n.kind], r = { ...n.defaultValues };
29
+ for (let i in r) {
30
+ let a = t.getItem(n.keyTransform ? n.keyTransform(i) : i);
31
+ if (a === null) {
32
+ r[i] = n.defaultValues[i];
33
+ continue;
61
34
  }
35
+ let o = e(a), s = n.schemas[i]["~standard"].validate(o);
36
+ if (s instanceof Promise) throw TypeError("[createWebStorage] Validation schema should not return a Promise.");
37
+ if (s.issues) if (n.onValidationError) {
38
+ let e = n.onValidationError({
39
+ issues: [...s.issues],
40
+ key: i,
41
+ value: o
42
+ });
43
+ if (e !== void 0) {
44
+ let t = n.schemas[i]["~standard"].validate(e);
45
+ if (t instanceof Promise) throw TypeError("[createWebStorage] Validation schema should not return a Promise.");
46
+ t.issues ? console.warn(`[createWebStorage] Returned value invalid for key ${i}, returned default value instead`, JSON.stringify(t.issues, null, 2), { cause: t.issues }) : r[i] = t.value;
47
+ }
48
+ } else console.warn(`[createWebStorage] Returned value invalid for key ${i}, returned default value instead`, JSON.stringify(s.issues, null, 2), { cause: s.issues }), r[i] = n.defaultValues[i];
49
+ else r[i] = s.value;
62
50
  }
63
- }), a = () => {
64
- r || i["~"].notify();
51
+ return r;
65
52
  };
66
- return typeof window < "u" && window.addEventListener("storage", a), {
67
- ...i,
68
- destroy: () => {
69
- i.destroy?.(), typeof window < "u" && window.removeEventListener("storage", a);
53
+ return {
54
+ get: s,
55
+ set: (e) => {
56
+ let t = typeof e == "function" ? e(s()) : e;
57
+ if (typeof window > "u") return;
58
+ let i = window[n.kind];
59
+ r = !0, Object.entries(t).forEach(([e, t]) => {
60
+ let r = typeof t == "string" ? t : JSON.stringify(t);
61
+ i.setItem(n.keyTransform ? n.keyTransform(e) : e, r), window.dispatchEvent(new StorageEvent("storage", {
62
+ key: n.keyTransform ? n.keyTransform(e) : e,
63
+ newValue: r
64
+ }));
65
+ }), r = !1, a();
70
66
  },
67
+ getDefaultValue: (e) => o[e],
68
+ subscribe: (e, t = {}) => i(() => e(s()), t),
71
69
  "~": {
72
70
  kind: n.kind,
73
- ...i["~"]
71
+ output: null,
72
+ notify: a
74
73
  }
75
74
  };
76
75
  }
77
76
  //#endregion
78
77
  //#region src/web/local-storage.ts
79
- function a(e) {
80
- return i({
78
+ function i(e) {
79
+ return r({
81
80
  kind: "localStorage",
82
81
  ...e
83
82
  });
84
83
  }
85
84
  //#endregion
86
85
  //#region src/web/web-storage-value.ts
87
- function o(t) {
88
- let r = "storage" in t ? t.storage["~"].kind : t.kind, i = !1, a = `${r}Value`;
89
- if ("schema" in t && t.defaultValue === void 0) throw Error(`[${a}] Default value is required`);
90
- if (t.key === void 0) throw Error(`[${a}] Key is required`);
91
- if (!("schema" in t || "storage" in t)) throw Error(`[${a}] Either schema or storage must be provided`);
92
- let o = ("schema" in t ? t.defaultValue : t.storage.getDefaultValue(t.key)) ?? null, { subscribe: s, notify: c } = n(), l = () => {
86
+ function a(n) {
87
+ let r = "storage" in n ? n.storage["~"].kind : n.kind, i = !1, a = `${r}Value`;
88
+ if ("schema" in n && n.defaultValue === void 0) throw Error(`[${a}] Default value is required`);
89
+ if (n.key === void 0) throw Error(`[${a}] Key is required`);
90
+ if (!("schema" in n || "storage" in n)) throw Error(`[${a}] Either schema or storage must be provided`);
91
+ let o = ("schema" in n ? n.defaultValue : n.storage.getDefaultValue(n.key)) ?? null, { subscribe: s, notify: c } = t({ onFirstSubscribe: () => {
92
+ let e = (e) => {
93
+ i || e.key === n.key && c();
94
+ };
95
+ return typeof window < "u" && window.addEventListener("storage", e), () => {
96
+ typeof window < "u" && window.removeEventListener("storage", e);
97
+ };
98
+ } }), l = () => {
93
99
  if (typeof window > "u") return o;
94
- let n = window[r].getItem(t.key);
95
- if (n === null) return o;
96
- let i = e(n);
100
+ let t = window[r].getItem(n.key);
101
+ if (t === null) return o;
102
+ let i = e(t);
97
103
  try {
98
- if ("schema" in t) {
99
- let e = t.schema["~standard"].validate(i);
104
+ if ("schema" in n) {
105
+ let e = n.schema["~standard"].validate(i);
100
106
  if (e instanceof Promise) throw TypeError("Validation schema should not return a Promise.");
101
107
  if (e.issues) {
102
- if (t.onValidationError) {
103
- let n = t.onValidationError({
108
+ if (n.onValidationError) {
109
+ let t = n.onValidationError({
104
110
  issues: [...e.issues],
105
111
  value: i
106
112
  });
107
- if (n !== void 0) {
108
- let e = t.schema["~standard"].validate(n);
113
+ if (t !== void 0) {
114
+ let e = n.schema["~standard"].validate(t);
109
115
  if (e instanceof Promise) throw TypeError("Validation schema should not return a Promise.");
110
- if (e.issues) console.error("Returned value invalid, returned default value instead", JSON.stringify(e.issues, null, 2), { cause: e.issues });
116
+ if (e.issues) console.warn(`[${a}] Returned value invalid for key ${n.key}, returned default value instead`, JSON.stringify(e.issues, null, 2), { cause: e.issues });
111
117
  else return e.value;
112
118
  }
113
- } else console.warn(JSON.stringify(e.issues, null, 2), { cause: e.issues });
119
+ } else console.warn(`[${a}] Returned value invalid for key ${n.key}, returned default value instead`, JSON.stringify(e.issues, null, 2), { cause: e.issues });
114
120
  return o;
115
121
  }
116
122
  return e.value;
@@ -118,25 +124,20 @@ function o(t) {
118
124
  } catch {
119
125
  return o !== void 0 && typeof o != "string" ? o : i;
120
126
  }
121
- }, u = (e) => {
122
- i || e.key === t.key && c();
123
127
  };
124
- return typeof window < "u" && window.addEventListener("storage", u), {
128
+ return {
125
129
  get: l,
126
130
  set: (e) => {
127
131
  if (typeof window > "u") return;
128
- let n = window[r], a = typeof e == "function" ? e(l()) : e;
129
- i = !0, n.setItem(t.key, typeof a == "string" ? a : JSON.stringify(a)), window.dispatchEvent(new StorageEvent("storage", {
130
- key: t.key,
132
+ let t = window[r], a = typeof e == "function" ? e(l()) : e;
133
+ i = !0, t.setItem(n.key, typeof a == "string" ? a : JSON.stringify(a)), window.dispatchEvent(new StorageEvent("storage", {
134
+ key: n.key,
131
135
  newValue: a
132
136
  })), i = !1, c();
133
137
  },
134
- subscribe: (e, t) => s(() => e(l()), t),
138
+ subscribe: (e, t = {}) => s(() => e(l()), t),
135
139
  remove: () => {
136
- typeof window > "u" || window[r].removeItem(t.key);
137
- },
138
- destroy: () => {
139
- typeof window < "u" && window.removeEventListener("storage", u);
140
+ typeof window > "u" || window[r].removeItem(n.key);
140
141
  },
141
142
  "~": {
142
143
  output: null,
@@ -146,36 +147,35 @@ function o(t) {
146
147
  }
147
148
  //#endregion
148
149
  //#region src/web/local-storage-value.ts
149
- function s(e) {
150
- return "storage" in e ? o(e) : o({
150
+ function o(e) {
151
+ return "storage" in e ? a(e) : a({
151
152
  ...e,
152
153
  kind: "localStorage"
153
154
  });
154
155
  }
155
156
  //#endregion
156
157
  //#region src/web/media-query.ts
157
- function c(e) {
158
- let { subscribe: t, notify: r } = n(), i = typeof window > "u" ? null : window.matchMedia(e.query), a = () => i?.matches ?? e.defaultMatches ?? !1, o = () => r();
159
- return i?.addEventListener("change", o), {
158
+ function s(e) {
159
+ let n = typeof window > "u" ? null : window.matchMedia(e.query), { subscribe: r, notify: i } = t({ onFirstSubscribe: () => (n?.addEventListener("change", i), () => {
160
+ n?.removeEventListener("change", i);
161
+ }) }), a = () => n?.matches ?? e.defaultMatches ?? !1;
162
+ return {
160
163
  get: a,
161
- subscribe: (e, n) => t(() => e(a()), n),
162
- destroy: () => {
163
- i?.removeEventListener("change", o);
164
- },
164
+ subscribe: (e, t = {}) => r(() => e(a()), t),
165
165
  "~": {
166
166
  output: null,
167
- notify: r
167
+ notify: i
168
168
  }
169
169
  };
170
170
  }
171
171
  //#endregion
172
172
  //#region src/web/scroll-state.ts
173
- var l = {
173
+ var c = {
174
174
  reached: !1,
175
175
  remaining: 0
176
176
  };
177
- function u(e) {
178
- let { direction: t = "both", threshold: r = 0 } = e, { subscribe: i, notify: a } = n(), o = typeof r == "number" ? {
177
+ function l(e) {
178
+ let { direction: n = "both", threshold: r = 0 } = e, { subscribe: i, notify: a } = t(), o = typeof r == "number" ? {
179
179
  top: r,
180
180
  bottom: r,
181
181
  left: r,
@@ -185,31 +185,31 @@ function u(e) {
185
185
  bottom: r.bottom ?? 0,
186
186
  left: r.left ?? 0,
187
187
  right: r.right ?? 0
188
- }, s = () => typeof e.element == "function" ? e.element() : e.element, c = () => {
189
- let e = s(), n = (e, t) => ({
188
+ }, s = () => typeof e.element == "function" ? e.element() : e.element, l = () => {
189
+ let e = s(), t = (e, t) => ({
190
190
  reached: e,
191
191
  remaining: Math.max(0, t)
192
192
  });
193
193
  if (!e) return {
194
- top: l,
195
- bottom: l,
196
- left: l,
197
- right: l
194
+ top: c,
195
+ bottom: c,
196
+ left: c,
197
+ right: c
198
198
  };
199
- let r = e.scrollTop, i = e.scrollHeight - e.scrollTop - e.clientHeight, a = e.scrollLeft, c = e.scrollWidth - e.scrollLeft - e.clientWidth;
199
+ let r = e.scrollTop, i = e.scrollHeight - e.scrollTop - e.clientHeight, a = e.scrollLeft, l = e.scrollWidth - e.scrollLeft - e.clientWidth;
200
200
  return {
201
- top: t === "horizontal" ? l : n(r <= o.top, r),
202
- bottom: t === "horizontal" ? l : n(i <= o.bottom, i),
203
- left: t === "vertical" ? l : n(a <= o.left, a),
204
- right: t === "vertical" ? l : n(c <= o.right, c)
201
+ top: n === "horizontal" ? c : t(r <= o.top, r),
202
+ bottom: n === "horizontal" ? c : t(i <= o.bottom, i),
203
+ left: n === "vertical" ? c : t(a <= o.left, a),
204
+ right: n === "vertical" ? c : t(l <= o.right, l)
205
205
  };
206
206
  };
207
207
  return {
208
- get: c,
209
- subscribe: (e, t) => {
208
+ get: l,
209
+ subscribe: (e, t = {}) => {
210
210
  let n = s();
211
- if (!n) return e(c()), () => {};
212
- let r = i(() => e(c()), t), a = () => e(c());
211
+ if (!n) return e(l()), () => {};
212
+ let r = i(() => e(l()), t), a = () => e(l());
213
213
  return n.addEventListener("scroll", a, { passive: !0 }), () => {
214
214
  r(), n.removeEventListener("scroll", a);
215
215
  };
@@ -222,19 +222,19 @@ function u(e) {
222
222
  }
223
223
  //#endregion
224
224
  //#region src/web/session-storage.ts
225
- function d(e) {
226
- return i({
225
+ function u(e) {
226
+ return r({
227
227
  kind: "sessionStorage",
228
228
  ...e
229
229
  });
230
230
  }
231
231
  //#endregion
232
232
  //#region src/web/session-storage-value.ts
233
- function f(e) {
234
- return "storage" in e ? o(e) : o({
233
+ function d(e) {
234
+ return "storage" in e ? a(e) : a({
235
235
  ...e,
236
236
  kind: "sessionStorage"
237
237
  });
238
238
  }
239
239
  //#endregion
240
- export { r as createIsOnline, a as createLocalStorage, s as createLocalStorageValue, c as createMediaQuery, u as createScrollState, d as createSessionStorage, f as createSessionStorageValue };
240
+ export { n as createIsOnline, i as createLocalStorage, o as createLocalStorageValue, s as createMediaQuery, l as createScrollState, u as createSessionStorage, d as createSessionStorageValue };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "seitu",
3
3
  "displayName": "Seitu",
4
4
  "type": "module",
5
- "version": "0.7.0",
5
+ "version": "0.9.0",
6
6
  "private": false,
7
7
  "author": "Valerii Strilets",
8
8
  "license": "MIT",
@@ -19,6 +19,7 @@
19
19
  "keywords": [
20
20
  "typescript",
21
21
  "react",
22
+ "vue",
22
23
  "utils",
23
24
  "type-safe"
24
25
  ],
@@ -34,6 +35,10 @@
34
35
  "./react": {
35
36
  "types": "./dist/react/index.d.ts",
36
37
  "import": "./dist/react.js"
38
+ },
39
+ "./vue": {
40
+ "types": "./dist/vue/index.d.ts",
41
+ "import": "./dist/vue.js"
37
42
  }
38
43
  },
39
44
  "main": "./dist/core.js",
@@ -46,7 +51,8 @@
46
51
  },
47
52
  "peerDependencies": {
48
53
  "react": ">=19",
49
- "react-dom": ">=19"
54
+ "react-dom": ">=19",
55
+ "vue": ">=3.5"
50
56
  },
51
57
  "peerDependenciesMeta": {
52
58
  "react": {
@@ -54,6 +60,9 @@
54
60
  },
55
61
  "react-dom": {
56
62
  "optional": true
63
+ },
64
+ "vue": {
65
+ "optional": true
57
66
  }
58
67
  },
59
68
  "dependencies": {
@@ -72,6 +81,7 @@
72
81
  "vite": "^8.0.3",
73
82
  "vite-plugin-dts": "^4.5.4",
74
83
  "vitest": "^4.1.2",
84
+ "vue": "^3.5.31",
75
85
  "zod": "^4.3.6"
76
86
  },
77
87
  "scripts": {
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,99 +0,0 @@
1
- //#region src/core/subscription.ts
2
- function e() {
3
- let e = /* @__PURE__ */ new Set();
4
- return {
5
- subscribe(t, n) {
6
- return n?.immediate && t(), e.add(t), () => {
7
- e.delete(t);
8
- };
9
- },
10
- notify() {
11
- e.forEach((e) => e());
12
- }
13
- };
14
- }
15
- //#endregion
16
- //#region src/core/computed.ts
17
- function t(t, n) {
18
- let { subscribe: r, notify: i } = e(), a = Array.isArray(t) ? t : [t], o = !Array.isArray(t), s = () => n(o ? a[0].get() : a.map((e) => e.get()));
19
- for (let e of a) e.subscribe(() => i());
20
- return {
21
- get: s,
22
- subscribe(e, t) {
23
- return r(() => e(s()), t);
24
- },
25
- "~": {
26
- output: null,
27
- notify: i
28
- }
29
- };
30
- }
31
- //#endregion
32
- //#region src/utils.ts
33
- function n(e) {
34
- if (typeof e != "string") return e;
35
- try {
36
- return JSON.parse(e);
37
- } catch {
38
- return e;
39
- }
40
- }
41
- //#endregion
42
- //#region src/core/schema-store.ts
43
- function r(t) {
44
- let { subscribe: r, notify: a } = e(), o = { ...t.defaultValues }, s = t.provider ?? i(), c = () => {
45
- let e = { ...o };
46
- for (let [r, i] of Object.entries(t.schemas)) {
47
- let t = s.get()[r], a = i["~standard"].validate(n(t));
48
- if (a instanceof Promise) throw TypeError("[createStorage] Validation schema should not return a Promise.");
49
- a.issues && console.warn(JSON.stringify(a.issues, null, 2), { cause: a.issues }), e[r] = a.issues ? o[r] : a.value;
50
- }
51
- return e;
52
- };
53
- return {
54
- get: c,
55
- set: (e) => {
56
- let t = typeof e == "function" ? e(c()) : e;
57
- s.set(t), a();
58
- },
59
- getDefaultValue: (e) => o[e],
60
- subscribe: (e, t) => r(() => e(c()), t),
61
- destroy: () => {
62
- s.destroy?.();
63
- },
64
- "~": {
65
- output: null,
66
- notify: a
67
- }
68
- };
69
- }
70
- function i() {
71
- let e = a({});
72
- return {
73
- get: () => e.get(),
74
- set: (t) => {
75
- e.set(t);
76
- }
77
- };
78
- }
79
- //#endregion
80
- //#region src/core/store.ts
81
- function a(t) {
82
- let n = t, { subscribe: r, notify: i } = e(), a = () => n;
83
- return {
84
- get: a,
85
- set: (e) => {
86
- let t = typeof e == "function" ? e(n) : e;
87
- t !== n && (n = t, i());
88
- },
89
- subscribe(e, t) {
90
- return r(() => e(a()), t);
91
- },
92
- "~": {
93
- output: null,
94
- notify: i
95
- }
96
- };
97
- }
98
- //#endregion
99
- export { t as a, n as i, r as n, e as o, i as r, a as t };
@@ -1 +0,0 @@
1
- import '@testing-library/jest-dom/vitest';
@@ -1 +0,0 @@
1
- import '@testing-library/jest-dom/vitest';
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};