usewagen 0.0.0 → 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ahmet Tinastepe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # usewagen
2
+
3
+ Reactive state for URL and storage in Vue. Type-safe, with the value in exactly one place.
4
+
5
+ Documentation lives at [usewagen.dev](https://usewagen.dev).
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ pnpm add usewagen
11
+ ```
12
+
13
+ `vue` is a peer dependency. `vue-router` is only needed if you use the router composables.
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ import { parseAsInteger } from 'usewagen'
19
+ import { useRouteState } from 'usewagen/router'
20
+ import { useLocalStorage } from 'usewagen/storage'
21
+
22
+ const page = useRouteState({ key: 'page', parser: parseAsInteger.withDefault(1) })
23
+ const theme = useLocalStorage({ key: 'theme' })
24
+ ```
25
+
26
+ `page` is a `Ref<number>` over `?page=` and `theme` a `Ref<string | null>` over the `theme`
27
+ entry in `localStorage`.
28
+
29
+ ## License
30
+
31
+ [MIT](./LICENSE)
package/client.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ declare module 'virtual:usewagen/parsers' {
2
+ import type { Parser } from 'usewagen'
3
+
4
+ export const parsers: Record<string, Parser<any>>
5
+ }
@@ -0,0 +1,15 @@
1
+ import { a as parseAsFloat, i as parseAsDate, o as parseAsIndex, r as parseAsBoolean, s as parseAsInteger, u as parseAsString } from "./parsers-CA8aZuF-.mjs";
2
+ //#region src/parser/builtins.ts
3
+ const builtinParsers = {
4
+ parseAsString,
5
+ parseAsInteger,
6
+ parseAsFloat,
7
+ parseAsIndex,
8
+ parseAsBoolean,
9
+ parseAsDate
10
+ };
11
+ function isBuiltinParserName(name) {
12
+ return Object.hasOwn(builtinParsers, name);
13
+ }
14
+ //#endregion
15
+ export { isBuiltinParserName as n, builtinParsers as t };
@@ -0,0 +1,38 @@
1
+ //#region src/storage/create-storage.d.ts
2
+ type ErrorHandler = (error: unknown) => void;
3
+ type Unsubscribe = () => void;
4
+ type KeyListener = () => void;
5
+ type StorageListener = (key: string | null) => void;
6
+ interface StorageAdapter {
7
+ getItem: (key: string) => string | null;
8
+ setItem: (key: string, value: string) => void;
9
+ removeItem: (key: string) => void;
10
+ keys: () => string[];
11
+ watch?: (onChange: (key: string | null) => void) => Unsubscribe;
12
+ }
13
+ interface StorageConfig {
14
+ prefix?: string;
15
+ crossTab?: boolean;
16
+ onError?: ErrorHandler;
17
+ }
18
+ type StorageOptions = StorageAdapter & StorageConfig;
19
+ interface StorageInstance {
20
+ readonly name: string;
21
+ readonly prefix: string;
22
+ getItem: (key: string) => string | null;
23
+ setItem: (key: string, value: string) => void;
24
+ removeItem: (key: string) => void;
25
+ has: (key: string) => boolean;
26
+ keys: () => string[];
27
+ clear: (options?: {
28
+ except?: string[];
29
+ }) => void;
30
+ subscribe: {
31
+ (key: string, listener: KeyListener): Unsubscribe;
32
+ (listener: StorageListener): Unsubscribe;
33
+ };
34
+ destroy: () => void;
35
+ }
36
+ declare function createStorage(name: string, options: StorageOptions): StorageInstance;
37
+ //#endregion
38
+ export { StorageInstance as a, Unsubscribe as c, StorageConfig as i, createStorage as l, KeyListener as n, StorageListener as o, StorageAdapter as r, StorageOptions as s, ErrorHandler as t };
@@ -0,0 +1,43 @@
1
+ import { C as parseAsStringLiteral, S as parseAsStringEnum, T as unwrapDefault, _ as parseAsIndex, a as InferParserValue, b as parseAsNumberLiteral, c as DefaultValue, d as ParserWithDefault, f as defineParser, g as parseAsFloat, h as parseAsDate, i as InferInputWritable, l as Parser, m as parseAsBoolean, n as CustomParsers, o as KnownParsers, p as parseAsArrayOf, r as InferInputValue, s as ParserInput, t as BuiltinParsers, u as ParserOptions, v as parseAsInteger, w as tryParse, x as parseAsString, y as parseAsJson } from "./types-CNt2lcP1.mjs";
2
+ import { i as RouteStateSource, t as HistoryMode } from "./types-CuwASQTi.mjs";
3
+ import { a as StorageInstance, t as ErrorHandler } from "./create-storage-DESmB4bY.mjs";
4
+ import { App } from "vue";
5
+ //#region src/wagen.d.ts
6
+ interface WagenStorageOptions {
7
+ prefix?: string;
8
+ crossTab?: boolean;
9
+ onError?: ErrorHandler;
10
+ local?: StorageInstance;
11
+ session?: StorageInstance;
12
+ default?: 'local' | 'session';
13
+ }
14
+ interface WagenRouterOptions {
15
+ history?: HistoryMode;
16
+ source?: RouteStateSource;
17
+ clearOnDefault?: boolean;
18
+ }
19
+ type WagenParsers = Record<string, Parser<any>>;
20
+ interface WagenConfig {
21
+ parsers?: WagenParsers;
22
+ storage?: WagenStorageOptions;
23
+ router?: WagenRouterOptions;
24
+ }
25
+ interface WagenStorage {
26
+ readonly local: StorageInstance;
27
+ readonly session: StorageInstance;
28
+ readonly default: StorageInstance;
29
+ }
30
+ type ResolvedWagenRouterOptions = Required<WagenRouterOptions>;
31
+ interface Wagen {
32
+ readonly parsers: WagenParsers;
33
+ readonly storage: WagenStorage;
34
+ readonly router: ResolvedWagenRouterOptions;
35
+ install: (app: App) => void;
36
+ destroy: () => void;
37
+ }
38
+ declare function defineWagenConfig(config: WagenConfig): WagenConfig;
39
+ declare function createWagen(config?: WagenConfig): Wagen;
40
+ declare function getActiveWagen(): Wagen;
41
+ declare function useWagen(): Wagen;
42
+ //#endregion
43
+ export { type BuiltinParsers, type CustomParsers, DefaultValue, type InferInputValue, type InferInputWritable, type InferParserValue, type KnownParsers, Parser, type ParserInput, ParserOptions, ParserWithDefault, type ResolvedWagenRouterOptions, type Wagen, type WagenConfig, type WagenParsers, type WagenRouterOptions, type WagenStorage, type WagenStorageOptions, createWagen, defineParser, defineWagenConfig, getActiveWagen, parseAsArrayOf, parseAsBoolean, parseAsDate, parseAsFloat, parseAsIndex, parseAsInteger, parseAsJson, parseAsNumberLiteral, parseAsString, parseAsStringEnum, parseAsStringLiteral, tryParse, unwrapDefault, useWagen };
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import { a as parseAsFloat, c as parseAsJson, d as parseAsStringEnum, f as parseAsStringLiteral, i as parseAsDate, l as parseAsNumberLiteral, m as unwrapDefault, n as parseAsArrayOf, o as parseAsIndex, p as tryParse, r as parseAsBoolean, s as parseAsInteger, t as defineParser, u as parseAsString } from "./parsers-CA8aZuF-.mjs";
2
+ import "./parser-B6hfbAwA.mjs";
3
+ import { i as useWagen, n as defineWagenConfig, r as getActiveWagen, t as createWagen } from "./wagen-C9_CPUdF.mjs";
4
+ export { createWagen, defineParser, defineWagenConfig, getActiveWagen, parseAsArrayOf, parseAsBoolean, parseAsDate, parseAsFloat, parseAsIndex, parseAsInteger, parseAsJson, parseAsNumberLiteral, parseAsString, parseAsStringEnum, parseAsStringLiteral, tryParse, unwrapDefault, useWagen };
@@ -0,0 +1,7 @@
1
+ import { MaybeRefOrGetter } from "vue";
2
+ //#region src/options.d.ts
3
+ type MaybeRefsOrGetters<T> = { [K in keyof T]: MaybeRefOrGetter<T[K]>; };
4
+ type ReactiveFields<T, TStatic extends keyof T = never> = MaybeRefsOrGetters<Omit<T, TStatic>> & Pick<T, TStatic>;
5
+ type ReactiveOptions<T, TStatic extends keyof T = never> = MaybeRefOrGetter<ReactiveFields<T, TStatic>>;
6
+ //#endregion
7
+ export { ReactiveOptions as n, ReactiveFields as t };
@@ -0,0 +1,2 @@
1
+ import "./parsers-CA8aZuF-.mjs";
2
+ export {};
@@ -0,0 +1,156 @@
1
+ //#region src/messages.ts
2
+ const PREFIX = "[usewagen]";
3
+ const ErrorCodes = {
4
+ PARSE_FAILED: 0,
5
+ UNKNOWN_PARSER_NAME: 1,
6
+ WEB_STORAGE_UNAVAILABLE: 2,
7
+ RESERVED_PARSER_NAME: 3,
8
+ DUPLICATE_PARSER_NAME: 4,
9
+ NO_INJECTION_CONTEXT: 5,
10
+ NO_EFFECT_SCOPE: 6
11
+ };
12
+ const errorMessages = {
13
+ [ErrorCodes.PARSE_FAILED]: "Failed to parse the input:",
14
+ [ErrorCodes.UNKNOWN_PARSER_NAME]: "No parser is registered under this name; falling back to `parseAsString`. Pass it to `createWagen({ parsers })`:",
15
+ [ErrorCodes.WEB_STORAGE_UNAVAILABLE]: "The storage area is not accessible; falling back to in-memory storage. Values will not persist:",
16
+ [ErrorCodes.RESERVED_PARSER_NAME]: "Skipping a parser whose name is reserved by a built-in:",
17
+ [ErrorCodes.DUPLICATE_PARSER_NAME]: "A parser with this name was already found in another file — the last one wins:",
18
+ [ErrorCodes.NO_INJECTION_CONTEXT]: "Composables should be called inside `setup()` or a function that runs in an injection context; falling back to the active instance. Outside one, use `getActiveWagen()` or the `define*` APIs:",
19
+ [ErrorCodes.NO_EFFECT_SCOPE]: "Composables should be called inside `setup()` or a running effect scope; outside one the effects they create are never released, which leaks:"
20
+ };
21
+ function getMessage(code) {
22
+ return `${PREFIX} ${errorMessages[code]}`;
23
+ }
24
+ function warn(code, ...details) {
25
+ console.warn(getMessage(code), ...details);
26
+ }
27
+ function warnDev(code, ...details) {
28
+ if (process.env.NODE_ENV !== "production") warn(code, ...details);
29
+ }
30
+ //#endregion
31
+ //#region src/parser/parsers.ts
32
+ function tryParse(fn, input) {
33
+ try {
34
+ return fn(input);
35
+ } catch (error) {
36
+ warn(ErrorCodes.PARSE_FAILED, input, error);
37
+ return null;
38
+ }
39
+ }
40
+ function defineParser(options) {
41
+ const parse = options.parse;
42
+ const serialize = options.serialize ?? String;
43
+ return {
44
+ parse,
45
+ serialize,
46
+ withDefault(value) {
47
+ const parser = defineParser({
48
+ parse,
49
+ serialize
50
+ });
51
+ Object.defineProperty(parser, "defaultValue", {
52
+ value,
53
+ enumerable: true
54
+ });
55
+ return parser;
56
+ }
57
+ };
58
+ }
59
+ function unwrapDefault(value) {
60
+ return typeof value === "function" ? value() : value;
61
+ }
62
+ const parseAsString = defineParser({
63
+ parse: (v) => v,
64
+ serialize: String
65
+ });
66
+ const parseAsInteger = defineParser({
67
+ parse: (v) => {
68
+ const n = Number.parseInt(v, 10);
69
+ return Number.isNaN(n) ? null : n;
70
+ },
71
+ serialize: (v) => Math.trunc(v).toString()
72
+ });
73
+ const parseAsFloat = defineParser({
74
+ parse: (v) => {
75
+ const n = Number.parseFloat(v);
76
+ return Number.isNaN(n) ? null : n;
77
+ },
78
+ serialize: (v) => v.toString()
79
+ });
80
+ const parseAsIndex = defineParser({
81
+ parse: (v) => {
82
+ const n = Number.parseInt(v, 10);
83
+ return Number.isNaN(n) ? null : n - 1;
84
+ },
85
+ serialize: (v) => (Math.trunc(v) + 1).toString()
86
+ });
87
+ const parseAsBoolean = defineParser({
88
+ parse: (v) => v === "true" ? true : v === "false" ? false : null,
89
+ serialize: (v) => v ? "true" : "false"
90
+ });
91
+ function parseAsStringLiteral(values) {
92
+ return defineParser({
93
+ parse: (v) => values.includes(v) ? v : null,
94
+ serialize: (v) => v.toString()
95
+ });
96
+ }
97
+ function parseAsNumberLiteral(values) {
98
+ return defineParser({
99
+ parse: (v) => {
100
+ const n = Number.parseFloat(v);
101
+ return values.includes(n) ? n : null;
102
+ },
103
+ serialize: (v) => v.toString()
104
+ });
105
+ }
106
+ function parseAsStringEnum(values) {
107
+ return parseAsStringLiteral(values);
108
+ }
109
+ const parseAsDate = Object.assign(defineParser({
110
+ parse: (v) => {
111
+ const d = new Date(v.includes("T") ? v : `${v}T00:00:00.000Z`);
112
+ return Number.isNaN(d.getTime()) ? null : d;
113
+ },
114
+ serialize: (v) => v.toISOString().slice(0, 10)
115
+ }), {
116
+ iso: () => defineParser({
117
+ parse: (v) => {
118
+ const d = new Date(v);
119
+ return Number.isNaN(d.getTime()) ? null : d;
120
+ },
121
+ serialize: (v) => v.toISOString()
122
+ }),
123
+ timestamp: () => defineParser({
124
+ parse: (v) => {
125
+ const n = Number.parseInt(v, 10);
126
+ if (Number.isNaN(n)) return null;
127
+ const d = new Date(n);
128
+ return Number.isNaN(d.getTime()) ? null : d;
129
+ },
130
+ serialize: (v) => v.getTime().toString()
131
+ })
132
+ });
133
+ function parseAsArrayOf(itemParser, separator = ",") {
134
+ const encodedSeparator = encodeURIComponent(separator);
135
+ return defineParser({
136
+ parse: (raw) => {
137
+ if (raw === "") return [];
138
+ return raw.split(separator).map((item) => tryParse(itemParser.parse, item.replaceAll(encodedSeparator, separator))).filter((value) => value !== null);
139
+ },
140
+ serialize: (values) => values.map((value) => itemParser.serialize(value).replaceAll(separator, encodedSeparator)).join(separator)
141
+ });
142
+ }
143
+ function parseAsJson() {
144
+ return defineParser({
145
+ parse: (v) => {
146
+ try {
147
+ return JSON.parse(v);
148
+ } catch {
149
+ return null;
150
+ }
151
+ },
152
+ serialize: (v) => JSON.stringify(v)
153
+ });
154
+ }
155
+ //#endregion
156
+ export { warnDev as _, parseAsFloat as a, parseAsJson as c, parseAsStringEnum as d, parseAsStringLiteral as f, warn as g, ErrorCodes as h, parseAsDate as i, parseAsNumberLiteral as l, unwrapDefault as m, parseAsArrayOf as n, parseAsIndex as o, tryParse as p, parseAsBoolean as r, parseAsInteger as s, defineParser as t, parseAsString as u };
@@ -0,0 +1,40 @@
1
+ import { i as InferInputWritable, r as InferInputValue, s as ParserInput } from "../types-CNt2lcP1.mjs";
2
+ import { i as RouteStateSource, n as ResolvedRouteStateOptions, r as RouteStateOptions, t as HistoryMode } from "../types-CuwASQTi.mjs";
3
+ import { n as ReactiveOptions, t as ReactiveFields } from "../options-BKybciek.mjs";
4
+ import { Ref } from "vue";
5
+ //#region src/router/use-route-hash.d.ts
6
+ interface RouteHashOptions {
7
+ parser?: ParserInput;
8
+ history?: HistoryMode;
9
+ clearOnDefault?: boolean;
10
+ }
11
+ type UseRouteHashOptions<P extends ParserInput | undefined = ParserInput | undefined> = ReactiveOptions<Omit<RouteHashOptions, 'parser'> & {
12
+ parser?: P;
13
+ }, 'parser'>;
14
+ declare function useRouteHash<P extends ParserInput | undefined = undefined>(options?: UseRouteHashOptions<P>): Ref<InferInputValue<P>, InferInputWritable<P>>;
15
+ //#endregion
16
+ //#region src/router/use-route-state.d.ts
17
+ type UseRouteStateOptions<P extends ParserInput | undefined = ParserInput | undefined> = ReactiveOptions<Omit<RouteStateOptions, 'parser'> & {
18
+ parser?: P;
19
+ }, 'parser'>;
20
+ declare function useRouteState<P extends ParserInput | undefined = undefined>(options: UseRouteStateOptions<P>): Ref<InferInputValue<P>, InferInputWritable<P>>;
21
+ //#endregion
22
+ //#region src/router/use-route-states.d.ts
23
+ type RouteStateConfig<P extends ParserInput | undefined = ParserInput | undefined> = ReactiveFields<Omit<RouteStateOptions, 'parser'> & {
24
+ parser?: P;
25
+ }, 'key' | 'parser'>;
26
+ interface BatchOptions {
27
+ history?: HistoryMode;
28
+ }
29
+ type Refs<TOptions extends readonly RouteStateConfig[]> = { [TOption in TOptions[number] as TOption['key']]: Ref<InferInputValue<TOption['parser']>, InferInputWritable<TOption['parser']>>; };
30
+ type StatePatch<TOptions extends readonly RouteStateConfig[]> = Partial<{ [TOption in TOptions[number] as TOption['key']]: InferInputWritable<TOption['parser']>; }>;
31
+ type StateSnapshot<TOptions extends readonly RouteStateConfig[]> = { [TOption in TOptions[number] as TOption['key']]: InferInputValue<TOption['parser']>; };
32
+ interface UseRouteStatesApi<TOptions extends readonly RouteStateConfig[]> {
33
+ set: (patch: StatePatch<TOptions>, options?: BatchOptions) => void;
34
+ reset: (options?: BatchOptions) => void;
35
+ toObject: () => StateSnapshot<TOptions>;
36
+ }
37
+ type UseRouteStatesReturn<TOptions extends readonly RouteStateConfig[]> = Refs<TOptions> & UseRouteStatesApi<TOptions>;
38
+ declare function useRouteStates<const TOptions extends readonly RouteStateConfig[]>(configs: TOptions): UseRouteStatesReturn<TOptions>;
39
+ //#endregion
40
+ export { type BatchOptions, type HistoryMode, type ResolvedRouteStateOptions, type RouteHashOptions, type RouteStateConfig, type RouteStateOptions, type RouteStateSource, type UseRouteHashOptions, type UseRouteStateOptions, type UseRouteStatesApi, type UseRouteStatesReturn, useRouteHash, useRouteState, useRouteStates };
@@ -0,0 +1,179 @@
1
+ import { _ as warnDev, h as ErrorCodes, m as unwrapDefault } from "../parsers-CA8aZuF-.mjs";
2
+ import "../parser-B6hfbAwA.mjs";
3
+ import { r as getActiveWagen } from "../wagen-C9_CPUdF.mjs";
4
+ import { i as toValueDeep, n as serializeValue, r as resolveParser, t as parseValue } from "../utils-B-885gDp.mjs";
5
+ import { computed, customRef, getCurrentScope, nextTick, toValue } from "vue";
6
+ import { useRoute, useRouter } from "vue-router";
7
+ //#region src/router/use-route-hash.ts
8
+ function toResolvedHashOptions(options, defaults) {
9
+ return {
10
+ parser: resolveParser(options.parser),
11
+ history: options.history ?? defaults.history,
12
+ clearOnDefault: options.clearOnDefault ?? defaults.clearOnDefault
13
+ };
14
+ }
15
+ function useRouteHash(options = {}) {
16
+ if (!getCurrentScope()) warnDev(ErrorCodes.NO_EFFECT_SCOPE, "useRouteHash");
17
+ const route = useRoute();
18
+ const router = useRouter();
19
+ const defaults = getActiveWagen().router;
20
+ const resolvedOptions = computed(() => toResolvedHashOptions(toValueDeep(options), defaults));
21
+ return customRef((track) => ({
22
+ get: () => {
23
+ track();
24
+ const raw = route.hash === "" ? void 0 : route.hash;
25
+ return parseValue(resolvedOptions.value.parser, raw);
26
+ },
27
+ set: (next) => {
28
+ const { parser, history, clearOnDefault } = resolvedOptions.value;
29
+ const serialized = serializeValue(parser, clearOnDefault, next);
30
+ nextTick(() => {
31
+ if ((route.hash === "" ? null : route.hash) === serialized) return;
32
+ router[history]({
33
+ query: route.query,
34
+ params: route.params,
35
+ hash: serialized === null ? void 0 : serialized
36
+ });
37
+ });
38
+ }
39
+ }));
40
+ }
41
+ //#endregion
42
+ //#region src/router/use-base-route-state.ts
43
+ function useBaseRouteState() {
44
+ const route = useRoute();
45
+ const router = useRouter();
46
+ function hasChanged(change) {
47
+ const current = change.source === "params" ? route.params[change.urlKey] : route.query[change.urlKey];
48
+ if (Array.isArray(current)) return true;
49
+ if (change.serialized === null) return current !== void 0;
50
+ return current !== change.serialized;
51
+ }
52
+ function navigate(changes, history) {
53
+ const changed = changes.filter(hasChanged);
54
+ if (changed.length === 0) return;
55
+ const params = { ...route.params };
56
+ const query = { ...route.query };
57
+ for (const change of changed) {
58
+ const target = change.source === "params" ? params : query;
59
+ target[change.urlKey] = change.serialized === null ? void 0 : change.serialized;
60
+ }
61
+ router[history]({
62
+ params,
63
+ query,
64
+ hash: route.hash
65
+ });
66
+ }
67
+ function createRouteStateRef(options) {
68
+ return customRef((track) => ({
69
+ get: () => {
70
+ track();
71
+ const { urlKey, source, parser } = toValue(options);
72
+ const raw = source === "params" ? route.params[urlKey] : route.query[urlKey];
73
+ return parseValue(parser, raw);
74
+ },
75
+ set: (next) => {
76
+ const { urlKey, source, parser, history, clearOnDefault } = toValue(options);
77
+ const serialized = serializeValue(parser, clearOnDefault, next);
78
+ nextTick(() => {
79
+ navigate([{
80
+ urlKey,
81
+ source,
82
+ serialized
83
+ }], history);
84
+ });
85
+ }
86
+ }));
87
+ }
88
+ return {
89
+ createRouteStateRef,
90
+ navigate
91
+ };
92
+ }
93
+ //#endregion
94
+ //#region src/router/utils.ts
95
+ function toResolvedOptions(input, defaults) {
96
+ return {
97
+ key: input.key,
98
+ parser: resolveParser(input.parser),
99
+ urlKey: input.urlKey ?? input.key,
100
+ source: input.source ?? defaults.source,
101
+ history: input.history ?? defaults.history,
102
+ clearOnDefault: input.clearOnDefault ?? defaults.clearOnDefault
103
+ };
104
+ }
105
+ //#endregion
106
+ //#region src/router/use-route-state.ts
107
+ function useRouteState(options) {
108
+ if (!getCurrentScope()) warnDev(ErrorCodes.NO_EFFECT_SCOPE, "useRouteState");
109
+ const { createRouteStateRef } = useBaseRouteState();
110
+ const defaults = getActiveWagen().router;
111
+ return createRouteStateRef(computed(() => toResolvedOptions(toValueDeep(options), defaults)));
112
+ }
113
+ //#endregion
114
+ //#region src/router/use-route-states.ts
115
+ function resolveBatchHistory(candidates, override) {
116
+ if (override) return override;
117
+ return candidates.includes("push") ? "push" : "replace";
118
+ }
119
+ function useRouteStates(configs) {
120
+ if (!getCurrentScope()) warnDev(ErrorCodes.NO_EFFECT_SCOPE, "useRouteStates");
121
+ const { createRouteStateRef, navigate } = useBaseRouteState();
122
+ const defaults = getActiveWagen().router;
123
+ const resolvedList = configs.map((config) => computed(() => toResolvedOptions(toValueDeep(config), defaults)));
124
+ const refs = Object.fromEntries(resolvedList.map((resolved) => [resolved.value.key, createRouteStateRef(resolved)]));
125
+ const api = {
126
+ set(patch, options) {
127
+ const changes = [];
128
+ const historyCandidates = [];
129
+ for (const resolved of resolvedList) {
130
+ const { key, urlKey, source, parser, clearOnDefault, history } = resolved.value;
131
+ if (!(key in patch)) continue;
132
+ const next = patch[key];
133
+ changes.push({
134
+ urlKey,
135
+ source,
136
+ serialized: serializeValue(parser, clearOnDefault, next)
137
+ });
138
+ historyCandidates.push(history);
139
+ }
140
+ if (changes.length === 0) return;
141
+ const history = resolveBatchHistory(historyCandidates, options?.history);
142
+ nextTick(() => {
143
+ navigate(changes, history);
144
+ });
145
+ },
146
+ reset(options) {
147
+ const changes = [];
148
+ const historyCandidates = [];
149
+ for (const resolved of resolvedList) {
150
+ const { urlKey, source, parser, clearOnDefault, history } = resolved.value;
151
+ const next = parser.defaultValue !== void 0 ? unwrapDefault(parser.defaultValue) : null;
152
+ changes.push({
153
+ urlKey,
154
+ source,
155
+ serialized: serializeValue(parser, clearOnDefault, next)
156
+ });
157
+ historyCandidates.push(history);
158
+ }
159
+ const history = resolveBatchHistory(historyCandidates, options?.history);
160
+ nextTick(() => {
161
+ navigate(changes, history);
162
+ });
163
+ },
164
+ toObject() {
165
+ const snapshot = {};
166
+ for (const resolved of resolvedList) {
167
+ const { key } = resolved.value;
168
+ snapshot[key] = refs[key].value;
169
+ }
170
+ return snapshot;
171
+ }
172
+ };
173
+ return {
174
+ ...refs,
175
+ ...api
176
+ };
177
+ }
178
+ //#endregion
179
+ export { useRouteHash, useRouteState, useRouteStates };
@@ -0,0 +1,43 @@
1
+ import { i as InferInputWritable, r as InferInputValue, s as ParserInput } from "../types-CNt2lcP1.mjs";
2
+ import { a as StorageInstance, c as Unsubscribe, i as StorageConfig, l as createStorage, n as KeyListener, o as StorageListener, r as StorageAdapter, s as StorageOptions, t as ErrorHandler } from "../create-storage-DESmB4bY.mjs";
3
+ import { n as ReactiveOptions } from "../options-BKybciek.mjs";
4
+ import { Ref } from "vue";
5
+ //#region src/storage/define-storage-state.d.ts
6
+ type StorageSource = StorageInstance | 'local' | 'session';
7
+ interface StorageStateOptions {
8
+ key: string;
9
+ storage?: StorageSource;
10
+ parser?: ParserInput;
11
+ clearOnDefault?: boolean;
12
+ }
13
+ interface StorageState<T = string | null, W = T | null | undefined> {
14
+ readonly key: string;
15
+ readonly storage: StorageInstance;
16
+ get: () => T;
17
+ set: (value: W) => void;
18
+ remove: () => void;
19
+ subscribe: (listener: () => void) => Unsubscribe;
20
+ }
21
+ declare function defineStorageState<P extends ParserInput | undefined = undefined>(options: Omit<StorageStateOptions, 'parser'> & {
22
+ parser?: P;
23
+ }): StorageState<InferInputValue<P>, InferInputWritable<P>>;
24
+ //#endregion
25
+ //#region src/storage/presets.d.ts
26
+ declare function createMemoryStorage(config?: StorageConfig): StorageInstance;
27
+ declare function createLocalStorage(config?: StorageConfig): StorageInstance;
28
+ declare function createSessionStorage(config?: StorageConfig): StorageInstance;
29
+ //#endregion
30
+ //#region src/storage/use-storage.d.ts
31
+ type UseStorageOptions<P extends ParserInput | undefined = ParserInput | undefined> = ReactiveOptions<Omit<StorageStateOptions, 'parser'> & {
32
+ parser?: P;
33
+ }, 'parser'>;
34
+ type UseLocalStorageOptions<P extends ParserInput | undefined = ParserInput | undefined> = ReactiveOptions<Omit<StorageStateOptions, 'parser' | 'storage'> & {
35
+ parser?: P;
36
+ }, 'parser'>;
37
+ type UseSessionStorageOptions<P extends ParserInput | undefined = ParserInput | undefined> = UseLocalStorageOptions<P>;
38
+ declare function useStorage<T, W>(state: StorageState<T, W>): Ref<T, W>;
39
+ declare function useStorage<P extends ParserInput | undefined = undefined>(options: UseStorageOptions<P>): Ref<InferInputValue<P>, InferInputWritable<P>>;
40
+ declare function useLocalStorage<P extends ParserInput | undefined = undefined>(options: UseLocalStorageOptions<P>): Ref<InferInputValue<P>, InferInputWritable<P>>;
41
+ declare function useSessionStorage<P extends ParserInput | undefined = undefined>(options: UseSessionStorageOptions<P>): Ref<InferInputValue<P>, InferInputWritable<P>>;
42
+ //#endregion
43
+ export { type ErrorHandler, type KeyListener, type StorageAdapter, type StorageConfig, type StorageInstance, type StorageListener, type StorageOptions, type StorageSource, type StorageState, type StorageStateOptions, type Unsubscribe, type UseLocalStorageOptions, type UseSessionStorageOptions, type UseStorageOptions, createLocalStorage, createMemoryStorage, createSessionStorage, createStorage, defineStorageState, useLocalStorage, useSessionStorage, useStorage };