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 +21 -0
- package/README.md +31 -0
- package/client.d.ts +5 -0
- package/dist/builtins-DiCjLgsG.mjs +15 -0
- package/dist/create-storage-DESmB4bY.d.mts +38 -0
- package/dist/index.d.mts +43 -0
- package/dist/index.mjs +4 -0
- package/dist/options-BKybciek.d.mts +7 -0
- package/dist/parser-B6hfbAwA.mjs +2 -0
- package/dist/parsers-CA8aZuF-.mjs +156 -0
- package/dist/router/index.d.mts +40 -0
- package/dist/router/index.mjs +179 -0
- package/dist/storage/index.d.mts +43 -0
- package/dist/storage/index.mjs +84 -0
- package/dist/types-CNt2lcP1.d.mts +60 -0
- package/dist/types-CuwASQTi.d.mts +24 -0
- package/dist/utils-B-885gDp.mjs +76 -0
- package/dist/vite/index.d.mts +19 -0
- package/dist/vite/index.mjs +230 -0
- package/dist/wagen-C9_CPUdF.mjs +276 -0
- package/package.json +76 -3
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,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 };
|
package/dist/index.d.mts
ADDED
|
@@ -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,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 };
|