@jk2908/solas 0.5.3 → 0.6.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/CHANGELOG.md +29 -0
- package/README.md +81 -85
- package/dist/config.d.ts +25 -0
- package/dist/config.js +152 -0
- package/dist/events.d.ts +4 -0
- package/dist/events.js +5 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +59 -37
- package/dist/internal/boundary-error.d.ts +4 -0
- package/dist/internal/boundary-error.js +8 -0
- package/dist/internal/browser-router/history.d.ts +46 -0
- package/dist/internal/browser-router/history.js +131 -0
- package/dist/internal/browser-router/link.d.ts +1 -1
- package/dist/internal/browser-router/link.js +1 -1
- package/dist/internal/browser-router/router.d.ts +6 -14
- package/dist/internal/browser-router/router.js +39 -13
- package/dist/internal/browser-router/shared.d.ts +183 -164
- package/dist/internal/browser-router/shared.js +49 -56
- package/dist/internal/browser-router/use-router.d.ts +1 -10
- package/dist/internal/browser-router/use-search-params.js +3 -3
- package/dist/internal/build.d.ts +108 -110
- package/dist/internal/build.js +569 -581
- package/dist/internal/codegen/config.js +3 -3
- package/dist/internal/codegen/environments.js +5 -6
- package/dist/internal/codegen/format.d.ts +6 -0
- package/dist/internal/codegen/format.js +24 -0
- package/dist/internal/codegen/manifest.js +2 -2
- package/dist/internal/codegen/maps.d.ts +1 -1
- package/dist/internal/codegen/maps.js +2 -2
- package/dist/internal/codegen/types.js +4 -4
- package/dist/internal/codegen/utils.js +2 -2
- package/dist/internal/env/request-context.js +1 -1
- package/dist/internal/env/rsc.d.ts +6 -4
- package/dist/internal/env/rsc.js +27 -25
- package/dist/internal/env/ssr.js +4 -4
- package/dist/internal/http-router/router.js +8 -8
- package/dist/internal/metadata.d.ts +1 -1
- package/dist/internal/metadata.js +1 -1
- package/dist/internal/navigation/http-exception-boundary.d.ts +1 -1
- package/dist/internal/navigation/redirect-boundary.d.ts +1 -1
- package/dist/internal/navigation/redirect.js +6 -6
- package/dist/internal/postbuild.js +18 -17
- package/dist/internal/prerender.d.ts +130 -138
- package/dist/internal/prerender.js +326 -354
- package/dist/internal/public-files.js +2 -4
- package/dist/internal/render/head.js +2 -2
- package/dist/internal/resolver.js +1 -1
- package/dist/internal/server/actions.js +2 -2
- package/dist/internal/ui/error-boundary.d.ts +1 -1
- package/dist/manifest.d.ts +7 -0
- package/dist/manifest.js +85 -0
- package/dist/prerender.d.ts +1 -1
- package/dist/prerender.js +1 -1
- package/dist/solas.d.ts +2 -46
- package/dist/solas.js +6 -266
- package/dist/types.d.ts +14 -21
- package/dist/types.js +1 -1
- package/dist/utils/base-path.d.ts +12 -14
- package/dist/utils/base-path.js +75 -82
- package/dist/utils/compress.d.ts +9 -11
- package/dist/utils/compress.js +59 -64
- package/dist/utils/context.d.ts +4 -6
- package/dist/utils/context.js +17 -22
- package/dist/utils/logger.js +2 -2
- package/dist/utils/time.d.ts +2 -4
- package/dist/utils/time.js +23 -29
- package/package.json +18 -8
- package/dist/runtimes/bun.d.ts +0 -13
- package/dist/runtimes/bun.js +0 -39
|
@@ -1,170 +1,189 @@
|
|
|
1
|
-
import
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import * as Solas from '../../solas.js';
|
|
2
|
+
export type Params = Record<string, string>;
|
|
3
|
+
export type Query = Record<string, string | number | boolean>;
|
|
4
|
+
export type Path = keyof Solas.Routes & string;
|
|
5
|
+
type Replace = {
|
|
6
|
+
replace?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type GoOptions = {
|
|
9
|
+
replace?: boolean;
|
|
10
|
+
query?: Query;
|
|
11
|
+
params?: Params;
|
|
12
|
+
};
|
|
13
|
+
export type Context = {
|
|
14
|
+
go: Go;
|
|
15
|
+
prefetch: (path: string) => void;
|
|
16
|
+
refresh: Refresh;
|
|
17
|
+
isNavigating: boolean;
|
|
18
|
+
url: {
|
|
19
|
+
pathname: string;
|
|
20
|
+
search?: string;
|
|
21
|
+
hash?: string;
|
|
8
22
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
params?: Params;
|
|
23
|
+
history: {
|
|
24
|
+
entries: HistoryEntry[];
|
|
25
|
+
index: number;
|
|
13
26
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
27
|
+
};
|
|
28
|
+
export type HistoryEntry = {
|
|
29
|
+
pathname: string;
|
|
30
|
+
search: string;
|
|
31
|
+
hash: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* These targets are used as-is. They are not matched against the route table,
|
|
35
|
+
* so this covers normal external URLs and hash-only links
|
|
36
|
+
*/
|
|
37
|
+
export type ExternalTarget = `${string}:${string}` | `//${string}` | `#${string}`;
|
|
38
|
+
export declare function isHashOnlyTarget(target: string): boolean;
|
|
39
|
+
export declare function isExternalTarget(target: string, origin: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Turn a route pattern into the real path shape a caller can use. In practice,
|
|
42
|
+
* every ':param' or '*' part becomes a plain string slot
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // '/p/:id' becomes '/p/${string}'
|
|
47
|
+
* // '/test/*' becomes '/test/${string}'
|
|
48
|
+
* // '/posts' stays '/posts'
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* type A = ResolvedPath<'/posts/:id'>
|
|
54
|
+
* // '/posts/${string}'
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* type B = ResolvedPath<'/docs/*'>
|
|
60
|
+
* // '/docs/${string}'
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export type ResolvedPath<TPath extends string> = TPath extends `${infer Start}:${string}/${infer Rest}` ? `${Start}${string}/${ResolvedPath<Rest>}` : TPath extends `${infer Start}:${string}` ? `${Start}${string}` : TPath extends `${infer Start}*${infer Rest}` ? `${Start}${string}${ResolvedPath<Rest>}` : TPath;
|
|
64
|
+
/**
|
|
65
|
+
* Once we have a real path, also allow the usual query-string and hash forms
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* type A = TargetSuffix<'/posts/123'>
|
|
70
|
+
* // '/posts/123' | '/posts/123?${string}' | '/posts/123#${string}' | '/posts/123?${string}#${string}'
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export type TargetSuffix<TPath extends string> = TPath | `${TPath}?${string}` | `${TPath}#${string}` | `${TPath}?${string}#${string}`;
|
|
74
|
+
/**
|
|
75
|
+
* This is the final string form a caller can navigate to. It can be an external
|
|
76
|
+
* URL, or a concrete URL that matches one of the known routes
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* type A = Target
|
|
81
|
+
* // 'https://example.com'
|
|
82
|
+
* // '#intro'
|
|
83
|
+
* // '/posts/123'
|
|
84
|
+
* // '/posts/123?draft=true'
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export type Target = ExternalTarget | TargetSuffix<ResolvedPath<Path>>;
|
|
88
|
+
/**
|
|
89
|
+
* Extra options for callers who already have a finished target string
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* const a: TargetConfig = { query: { page: 2 } }
|
|
94
|
+
* // params is rejected here because the path is already complete
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
type TargetConfig = {
|
|
98
|
+
params?: never;
|
|
99
|
+
query?: Query;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Extra options for callers who pass a route pattern and params separately.
|
|
103
|
+
* If the route definition says that route needs params, this type makes
|
|
104
|
+
* those params required. If the route has no params, it rejects them
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* // if Solas.Routes['/posts/:id'] is { params: { id: string } }
|
|
109
|
+
* type A = PatternConfig<'/posts/:id'>
|
|
110
|
+
* // { query?: Query } & { params: { id: string } }
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // if Solas.Routes['/about'] has no params field
|
|
116
|
+
* type B = PatternConfig<'/about'>
|
|
117
|
+
* // { query?: Query } & { params?: never }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
type PatternConfig<TPath extends Path> = {
|
|
121
|
+
query?: Query;
|
|
122
|
+
} & (Solas.Routes[TPath] extends {
|
|
123
|
+
params: infer TParams extends Params;
|
|
124
|
+
} ? {
|
|
125
|
+
params: TParams;
|
|
126
|
+
} : {
|
|
127
|
+
params?: never;
|
|
128
|
+
});
|
|
129
|
+
/**
|
|
130
|
+
* Typed <Link /> props, using `href` instead of the internal `to` name
|
|
131
|
+
*
|
|
132
|
+
* `query` is always allowed
|
|
133
|
+
* `params` are only allowed when `href` is a known route pattern
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* const a: LinkProps = { href: '/posts/:id', params: { id: '123' } }
|
|
138
|
+
* const b: LinkProps = { href: '/posts/123?draft=true' }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export type LinkProps = ({
|
|
142
|
+
href: Target;
|
|
143
|
+
} & TargetConfig) | (keyof Solas.Routes extends never ? never : {
|
|
144
|
+
[TPath in Path]: {
|
|
145
|
+
href: TPath;
|
|
146
|
+
} & PatternConfig<TPath>;
|
|
147
|
+
}[Path]);
|
|
148
|
+
/**
|
|
149
|
+
* Typed input for router.go(), using the same route rules as <Link />
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* go('/p/post-2')
|
|
154
|
+
* go('/?foo=bar', { replace: true })
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* go('/p/:id', { params: { id: 'post-2' }, replace: true })
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* The last overload is the fallback for plain `string` values. The
|
|
163
|
+
* `string extends TTo` check stops that fallback from taking over
|
|
164
|
+
* when TypeScript already knows the caller passed a more specific
|
|
165
|
+
* string literal
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* declare const dynamicPath: string
|
|
170
|
+
* go(dynamicPath, { replace: true })
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export type Go = {
|
|
174
|
+
(to: number): Promise<string>;
|
|
175
|
+
<TTo extends Path>(to: TTo, opts?: PatternConfig<TTo> & Replace): Promise<string>;
|
|
176
|
+
<TTo extends Target>(to: TTo, opts?: TargetConfig & Replace): Promise<string>;
|
|
177
|
+
<TTo extends string>(to: string extends TTo ? TTo : never, opts?: GoOptions): Promise<string>;
|
|
178
|
+
};
|
|
179
|
+
export type Refresh = () => Promise<string>;
|
|
180
|
+
/**
|
|
181
|
+
* Convert a route pattern and params into a real path string. This is used internally
|
|
182
|
+
* to implement <Link /> and router.go
|
|
183
|
+
*/
|
|
184
|
+
export declare function toTarget(path: string, params?: Record<string, string>, query?: Query): string;
|
|
167
185
|
/**
|
|
168
186
|
* Apply the base path to a target string when needed
|
|
169
187
|
*/
|
|
170
188
|
export declare function withBase(target: string): string;
|
|
189
|
+
export {};
|
|
@@ -1,72 +1,65 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const BASE_PATH =
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { applyBasePath, normaliseBasePath } from '../../utils/base-path.js';
|
|
2
|
+
const BASE_PATH = normaliseBasePath(import.meta.env.BASE_URL);
|
|
3
|
+
export function isHashOnlyTarget(target) {
|
|
4
|
+
return target.startsWith('#');
|
|
5
|
+
}
|
|
6
|
+
export function isExternalTarget(target, origin) {
|
|
7
|
+
if (isHashOnlyTarget(target))
|
|
8
|
+
return false;
|
|
9
|
+
try {
|
|
10
|
+
return new URL(target, origin).origin !== origin;
|
|
8
11
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (isHashOnlyTarget(target))
|
|
12
|
-
return false;
|
|
13
|
-
try {
|
|
14
|
-
return new URL(target, origin).origin !== origin;
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
19
14
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
used.add(key);
|
|
34
|
-
return encodeURIComponent(value);
|
|
35
|
-
});
|
|
36
|
-
if (to.includes('*')) {
|
|
37
|
-
const remaining = Object.entries(params ?? {}).filter(([key]) => !used.has(key));
|
|
38
|
-
if (remaining.length !== 1) {
|
|
39
|
-
throw new Error('[Link]: wildcard routes require exactly one unmatched param');
|
|
40
|
-
}
|
|
41
|
-
to = to.replace('*', remaining[0][1].split('/').map(encodeURIComponent).join('/'));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert a route pattern and params into a real path string. This is used internally
|
|
18
|
+
* to implement <Link /> and router.go
|
|
19
|
+
*/
|
|
20
|
+
export function toTarget(path, params, query) {
|
|
21
|
+
const used = new Set();
|
|
22
|
+
// first, replace all the :param parts with the corresponding params
|
|
23
|
+
let to = path.replaceAll(/:([A-Za-z0-9_]+)/g, (_, key) => {
|
|
24
|
+
const value = params?.[key];
|
|
25
|
+
if (value == null) {
|
|
26
|
+
throw new Error(`[Link]: missing route param: ${key}`);
|
|
42
27
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const currentSearch = searchIndex >= 0 ? pathWithSearch.slice(searchIndex + 1) : '';
|
|
51
|
-
const search = new URLSearchParams(currentSearch);
|
|
52
|
-
for (const [key, value] of Object.entries(query)) {
|
|
53
|
-
search.set(key, String(value));
|
|
28
|
+
used.add(key);
|
|
29
|
+
return encodeURIComponent(value);
|
|
30
|
+
});
|
|
31
|
+
if (to.includes('*')) {
|
|
32
|
+
const remaining = Object.entries(params ?? {}).filter(([key]) => !used.has(key));
|
|
33
|
+
if (remaining.length !== 1) {
|
|
34
|
+
throw new Error('[Link]: wildcard routes require exactly one unmatched param');
|
|
54
35
|
}
|
|
55
|
-
|
|
56
|
-
return withBase(`${pathname}${value.length > 0 ? `?${value}` : ''}${hash}`);
|
|
36
|
+
to = to.replace('*', remaining[0][1].split('/').map(encodeURIComponent).join('/'));
|
|
57
37
|
}
|
|
58
|
-
|
|
59
|
-
|
|
38
|
+
if (!query)
|
|
39
|
+
return withBase(to);
|
|
40
|
+
const hashIndex = to.indexOf('#');
|
|
41
|
+
const hash = hashIndex >= 0 ? to.slice(hashIndex) : '';
|
|
42
|
+
const pathWithSearch = hashIndex >= 0 ? to.slice(0, hashIndex) : to;
|
|
43
|
+
const searchIndex = pathWithSearch.indexOf('?');
|
|
44
|
+
const pathname = searchIndex >= 0 ? pathWithSearch.slice(0, searchIndex) : pathWithSearch;
|
|
45
|
+
const currentSearch = searchIndex >= 0 ? pathWithSearch.slice(searchIndex + 1) : '';
|
|
46
|
+
const search = new URLSearchParams(currentSearch);
|
|
47
|
+
for (const [key, value] of Object.entries(query)) {
|
|
48
|
+
search.set(key, String(value));
|
|
49
|
+
}
|
|
50
|
+
const value = search.toString();
|
|
51
|
+
return withBase(`${pathname}${value.length > 0 ? `?${value}` : ''}${hash}`);
|
|
52
|
+
}
|
|
60
53
|
/**
|
|
61
54
|
* Apply the base path to a target string when needed
|
|
62
55
|
*/
|
|
63
56
|
export function withBase(target) {
|
|
64
|
-
if (
|
|
57
|
+
if (isHashOnlyTarget(target))
|
|
65
58
|
return target;
|
|
66
59
|
if (target.startsWith('//') || /^[A-Za-z][A-Za-z\d+.-]*:/.test(target))
|
|
67
60
|
return target;
|
|
68
61
|
const suffixIndex = target.search(/[?#]/);
|
|
69
62
|
const pathname = suffixIndex === -1 ? target : target.slice(0, suffixIndex);
|
|
70
63
|
const suffix = suffixIndex === -1 ? '' : target.slice(suffixIndex);
|
|
71
|
-
return `${
|
|
64
|
+
return `${applyBasePath(pathname || '/', BASE_PATH)}${suffix}`;
|
|
72
65
|
}
|
|
@@ -1,10 +1 @@
|
|
|
1
|
-
export declare function useRouter():
|
|
2
|
-
go: import("./shared.js").BrowserRouter.Go;
|
|
3
|
-
prefetch: (path: string) => void;
|
|
4
|
-
refresh: import("./shared.js").BrowserRouter.Refresh;
|
|
5
|
-
isNavigating: boolean;
|
|
6
|
-
url: {
|
|
7
|
-
pathname?: string | undefined;
|
|
8
|
-
search?: string | undefined;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
1
|
+
export declare function useRouter(): import("./shared.js").Context;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { useMemo, useSyncExternalStore } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import * as Events from '../../events.js';
|
|
3
3
|
import { useRouter } from '../browser-router/use-router.js';
|
|
4
4
|
export function useSearchParams() {
|
|
5
5
|
const { url } = useRouter();
|
|
6
6
|
const search = useSyncExternalStore(fn => {
|
|
7
7
|
window.addEventListener('popstate', fn);
|
|
8
|
-
window.addEventListener(
|
|
8
|
+
window.addEventListener(Events.names.NAVIGATION, fn);
|
|
9
9
|
return () => {
|
|
10
10
|
window.removeEventListener('popstate', fn);
|
|
11
|
-
window.removeEventListener(
|
|
11
|
+
window.removeEventListener(Events.names.NAVIGATION, fn);
|
|
12
12
|
};
|
|
13
13
|
}, () => window.location.search, () => url?.search);
|
|
14
14
|
return useMemo(() => new URLSearchParams(search), [search]);
|