@urbicon-ui/sveltekit-utils 8.19.0 → 8.20.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/README.md +58 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/search-params.d.ts +41 -0
- package/dist/search-params.js +62 -0
- package/dist/url.svelte.d.ts +10 -11
- package/dist/url.svelte.js +24 -44
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Small, focused SvelteKit helpers that Urbicon apps share. Zero runtime dependenc
|
|
|
4
4
|
|
|
5
5
|
Currently shipping:
|
|
6
6
|
|
|
7
|
-
- **URL-state runes** — reactive `useUrlParam` / `useUrlArrayParam` that keep component state in sync with `?query=` parameters
|
|
7
|
+
- **URL-state runes** — reactive `useUrlParam` / `useUrlArrayParam` that keep component state in sync with `?query=` parameters, and `withSearchParams` for the links that change them
|
|
8
8
|
- **Table view ↔ URL** — `bindViewToUrl`, the URL home for a `@urbicon-ui/table` view object (`?q=…&sort=…&page=…`), plus the pure serializers for the load path
|
|
9
9
|
- **Cron runner** — interval-based background fetcher for scheduled server endpoints
|
|
10
10
|
- **SSE stream reader** — `streamSse`, a spec-correct async-generator client for one-shot POST `text/event-stream` endpoints (LLM relays)
|
|
@@ -53,9 +53,57 @@ import { updateUrlSearchParams } from '@urbicon-ui/sveltekit-utils/url.svelte';
|
|
|
53
53
|
updateUrlSearchParams({ page: '1', tag: ['a', 'b'] }, { replaceState: true });
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
A link needs an address, not a setter. `withSearchParams(url, patch)` is the pure core that `updateUrlSearchParams` and `createUrlParam`'s setter navigate to: the address `url` has after `patch` — a scalar `set`s its key, an array `append`s each element, `null` removes the key, every other param stays as it is. An empty string is a value and keeps its key (`?a=`); an empty array appends nothing and so removes it. It reads nothing from the page and navigates nowhere, so the same call builds a link's `href` and a redirect's location.
|
|
57
|
+
|
|
58
|
+
<!-- typecheck -->
|
|
59
|
+
```typescript
|
|
60
|
+
import { withSearchParams } from '@urbicon-ui/sveltekit-utils/search-params';
|
|
61
|
+
|
|
62
|
+
const url = new URL('https://films.test/archive?sort=title&page=3');
|
|
63
|
+
|
|
64
|
+
withSearchParams(url, { sort: 'year' }); // '/archive?page=3&sort=year'
|
|
65
|
+
withSearchParams(url, { tag: ['noir', 'silent'] }); // '/archive?sort=title&page=3&tag=noir&tag=silent'
|
|
66
|
+
withSearchParams(url, { sort: null, page: null }); // '/archive'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`./search-params` is the import path that reaches no `$app/*` module, so a `load`, a form action or a plain test can use it; importing `withSearchParams` from `./url.svelte` (or from the package root) is the same function, but pulls SvelteKit's client runtime along:
|
|
70
|
+
|
|
71
|
+
<!-- typecheck -->
|
|
72
|
+
```typescript
|
|
73
|
+
// src/routes/archive/+page.server.ts
|
|
74
|
+
import { withSearchParams } from '@urbicon-ui/sveltekit-utils/search-params';
|
|
75
|
+
import type { PageServerLoad } from './$types';
|
|
76
|
+
|
|
77
|
+
export const load: PageServerLoad = ({ url }) => {
|
|
78
|
+
const current = Number(url.searchParams.get('page') ?? '1');
|
|
79
|
+
return {
|
|
80
|
+
// Page 1 is the default, so its link carries no `page` at all.
|
|
81
|
+
prevHref: withSearchParams(url, { page: current > 2 ? String(current - 1) : null }),
|
|
82
|
+
nextHref: withSearchParams(url, { page: String(current + 1) })
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
In a component the URL to start from is `page.url`, and the result is the `href`:
|
|
88
|
+
|
|
89
|
+
```svelte
|
|
90
|
+
<script lang="ts">
|
|
91
|
+
import { page } from '$app/state';
|
|
92
|
+
import { withSearchParams } from '@urbicon-ui/sveltekit-utils/url.svelte';
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<a href={withSearchParams(page.url, { sort: 'year', page: null })}>Sort by year</a>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Not on a prerendered page: SvelteKit makes `url.searchParams` throw there — the emitted HTML must not depend on a query string that will not exist at request time — and `withSearchParams` reads it. `useUrlParam` guards that case for you by yielding its `initial` while `building`; a link on such a page has to be built after hydration, or from a `URL` you construct rather than the page's.
|
|
99
|
+
|
|
100
|
+
Link or binding: an `href` from `withSearchParams` where the reader picks a destination — a sort header, a pagination step, a filter chip — and the address should exist before the click, so it can be hovered, middle-clicked and crawled; `useUrlParam` where a control owns a value that keeps changing — a search box, a slider — and the URL follows it.
|
|
101
|
+
|
|
56
102
|
**Design notes**
|
|
57
103
|
|
|
58
104
|
- URL updates use `goto()` with `replaceState: true`, `noScroll: true`, `keepFocus: true` — suited for filter/pagination UIs, not full page transitions.
|
|
105
|
+
- `updateUrlSearchParams` and `createUrlParam`'s setter hand `goto` the pathname-qualified address `withSearchParams` returns, never a bare `?query`. `goto` resolves a relative target against `document.baseURI`, which equals the page's own URL only while the document carries no `<base href>` — with one, `?page=2` keeps the base's path, not the page's.
|
|
106
|
+
- `bindViewToUrl` is a third URL writer and does **not** go through `withSearchParams`: it merges the view axes itself and carries the URL hash across, where `withSearchParams` drops it. Do not read one policy off the other.
|
|
59
107
|
- `useUrlParam` returns getters (not Svelte stores) so consumers can read the value lazily inside `$derived`/`$effect`.
|
|
60
108
|
|
|
61
109
|
## Table View ↔ URL (`url.svelte` + `table-view`)
|
|
@@ -228,15 +276,16 @@ export const POST: RequestHandler = async ({ request }) => {
|
|
|
228
276
|
|
|
229
277
|
## Exports
|
|
230
278
|
|
|
231
|
-
| Subpath
|
|
232
|
-
|
|
|
233
|
-
| `.`
|
|
234
|
-
| `./url.svelte`
|
|
235
|
-
| `./
|
|
236
|
-
| `./
|
|
237
|
-
| `./
|
|
279
|
+
| Subpath | Contents |
|
|
280
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
281
|
+
| `.` | Barrel of all modules |
|
|
282
|
+
| `./url.svelte` | `useUrlParam`, `useUrlArrayParam`, `createUrlParam`, `updateUrlSearchParams`, `bindViewToUrl`, types (re-exports `withSearchParams`) |
|
|
283
|
+
| `./search-params` | `withSearchParams`, `SearchParamsPatch` — no `$app/*` import |
|
|
284
|
+
| `./table-view` | `searchParamsToViewSnapshot`, `searchParamsToViewPartial`, `viewSnapshotToSearchParams`, `applyViewToSearchParams`, `assertValidViewSnapshot`, `viewAxesNamedBy`, `viewAxisKeys`, `TABLE_VIEW_AXES`, `TABLE_VIEW_FILTER_OPERATORS`, `TableViewLike`, types |
|
|
285
|
+
| `./cron` | `createCronRunner`, `CronJob`, `CronRunnerConfig`, `CronRunner` |
|
|
286
|
+
| `./sse` | `streamSse`, `SseEvent`, `StreamSseOptions`, `SseRequestError` |
|
|
238
287
|
|
|
239
|
-
`bindViewToUrl` lives in its own module (`view-binding.svelte.ts`) and is re-exported from `./url.svelte`, which is its documented import path — it has no subpath of its own. `./table-view`
|
|
288
|
+
`bindViewToUrl` lives in its own module (`view-binding.svelte.ts`) and is re-exported from `./url.svelte`, which is its documented import path — it has no subpath of its own. `./search-params` and `./table-view` are SvelteKit-free (they touch no `$app/*`), which is what lets a `load` function and a plain test use them; `./url.svelte` is the half that needs the router — importing it from server code pulls SvelteKit's client runtime in, which is why `withSearchParams` has a subpath of its own as well as the re-export.
|
|
240
289
|
|
|
241
290
|
## Development
|
|
242
291
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What {@link withSearchParams} applies to a URL: a plain record, or a
|
|
3
|
+
* `URLSearchParams` whose repeated keys survive the merge.
|
|
4
|
+
*/
|
|
5
|
+
export type SearchParamsPatch = URLSearchParams | Record<string, string | string[] | null | undefined>;
|
|
6
|
+
/**
|
|
7
|
+
* The address `url` has after `patch` — the pure core that
|
|
8
|
+
* `updateUrlSearchParams` and `createUrlParam`'s setter navigate to. Returns
|
|
9
|
+
* `pathname?query`, or the pathname alone once no param is left, so the result
|
|
10
|
+
* serves as a link's `href`, a redirect's location, or the argument of `goto`.
|
|
11
|
+
* Reads nothing from the page, mutates neither argument, navigates nowhere.
|
|
12
|
+
*
|
|
13
|
+
* Merge semantics per key in `patch`: the key is first cleared, then
|
|
14
|
+
* re-applied — a record value `set`s a scalar, `append`s each array element,
|
|
15
|
+
* and **removes** the key entirely for `null`/`undefined`; a `URLSearchParams`
|
|
16
|
+
* re-appends all of its entries, so repeated keys survive. An empty string is a
|
|
17
|
+
* value and keeps its key (`?a=`); an empty array appends nothing and therefore
|
|
18
|
+
* removes it. A param the patch does not name keeps its value and its position;
|
|
19
|
+
* a patched key moves behind them. The hash is not carried.
|
|
20
|
+
*
|
|
21
|
+
* A `url.pathname` that itself begins with `//` comes back origin-qualified
|
|
22
|
+
* (`https://host//films?page=2`): left relative, `//films` is a
|
|
23
|
+
* protocol-relative URL naming `films` as the host.
|
|
24
|
+
*
|
|
25
|
+
* @param url - The URL to start from — `page.url` in a component, `url` in a
|
|
26
|
+
* `load`. SvelteKit makes `url.searchParams` throw while prerendering
|
|
27
|
+
* (`@sveltejs/kit/src/utils/url.js` `disable_search`: the emitted HTML must
|
|
28
|
+
* not depend on a query string), and this reads it.
|
|
29
|
+
* @param patch - Params to apply. A record value of `null`/`undefined` deletes
|
|
30
|
+
* that key.
|
|
31
|
+
* @returns Pathname plus the merged query: `/films?sort=year`.
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* withSearchParams(new URL('https://x.test/films?sort=title&page=3'), {
|
|
35
|
+
* sort: 'year',
|
|
36
|
+
* page: null
|
|
37
|
+
* });
|
|
38
|
+
* // '/films?sort=year'
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function withSearchParams(url: URL, patch: SearchParamsPatch): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The address `url` has after `patch` — the pure core that
|
|
3
|
+
* `updateUrlSearchParams` and `createUrlParam`'s setter navigate to. Returns
|
|
4
|
+
* `pathname?query`, or the pathname alone once no param is left, so the result
|
|
5
|
+
* serves as a link's `href`, a redirect's location, or the argument of `goto`.
|
|
6
|
+
* Reads nothing from the page, mutates neither argument, navigates nowhere.
|
|
7
|
+
*
|
|
8
|
+
* Merge semantics per key in `patch`: the key is first cleared, then
|
|
9
|
+
* re-applied — a record value `set`s a scalar, `append`s each array element,
|
|
10
|
+
* and **removes** the key entirely for `null`/`undefined`; a `URLSearchParams`
|
|
11
|
+
* re-appends all of its entries, so repeated keys survive. An empty string is a
|
|
12
|
+
* value and keeps its key (`?a=`); an empty array appends nothing and therefore
|
|
13
|
+
* removes it. A param the patch does not name keeps its value and its position;
|
|
14
|
+
* a patched key moves behind them. The hash is not carried.
|
|
15
|
+
*
|
|
16
|
+
* A `url.pathname` that itself begins with `//` comes back origin-qualified
|
|
17
|
+
* (`https://host//films?page=2`): left relative, `//films` is a
|
|
18
|
+
* protocol-relative URL naming `films` as the host.
|
|
19
|
+
*
|
|
20
|
+
* @param url - The URL to start from — `page.url` in a component, `url` in a
|
|
21
|
+
* `load`. SvelteKit makes `url.searchParams` throw while prerendering
|
|
22
|
+
* (`@sveltejs/kit/src/utils/url.js` `disable_search`: the emitted HTML must
|
|
23
|
+
* not depend on a query string), and this reads it.
|
|
24
|
+
* @param patch - Params to apply. A record value of `null`/`undefined` deletes
|
|
25
|
+
* that key.
|
|
26
|
+
* @returns Pathname plus the merged query: `/films?sort=year`.
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* withSearchParams(new URL('https://x.test/films?sort=title&page=3'), {
|
|
30
|
+
* sort: 'year',
|
|
31
|
+
* page: null
|
|
32
|
+
* });
|
|
33
|
+
* // '/films?sort=year'
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function withSearchParams(url, patch) {
|
|
37
|
+
const next = new URLSearchParams(url.searchParams);
|
|
38
|
+
if (patch instanceof URLSearchParams) {
|
|
39
|
+
for (const [key] of patch)
|
|
40
|
+
next.delete(key);
|
|
41
|
+
for (const [key, value] of patch)
|
|
42
|
+
next.append(key, value);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
46
|
+
next.delete(key);
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
for (const v of value)
|
|
49
|
+
next.append(key, v);
|
|
50
|
+
}
|
|
51
|
+
else if (value != null) {
|
|
52
|
+
next.set(key, value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const query = next.toString();
|
|
57
|
+
const address = query ? `${url.pathname}?${query}` : url.pathname;
|
|
58
|
+
// A leading `//` makes the address protocol-relative: as an `href` or a
|
|
59
|
+
// `goto` target `//films` names `films` as the host, not a path on this one.
|
|
60
|
+
// The origin is what disambiguates it; every other pathname stays relative.
|
|
61
|
+
return url.pathname.startsWith('//') ? `${url.origin}${address}` : address;
|
|
62
|
+
}
|
package/dist/url.svelte.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type SearchParamsPatch } from './search-params.js';
|
|
2
|
+
export { type SearchParamsPatch, withSearchParams } from './search-params.js';
|
|
1
3
|
export { bindViewToUrl, type UrlViewBindingOptions } from './view-binding.svelte.js';
|
|
2
4
|
/**
|
|
3
5
|
* How {@link useUrlArrayParam} maps an array onto the URL:
|
|
@@ -30,24 +32,21 @@ export type UrlParamOptions<T> = {
|
|
|
30
32
|
};
|
|
31
33
|
/**
|
|
32
34
|
* Low-level escape hatch to update several params at once via `goto` (without a
|
|
33
|
-
* full navigation).
|
|
34
|
-
* every unrelated param
|
|
35
|
-
*
|
|
36
|
-
* Merge semantics per key in `next`: the key is first cleared, then re-applied
|
|
37
|
-
* — a `URLSearchParams` re-appends all of its entries (repeated keys survive),
|
|
38
|
-
* a record `set`s a scalar, `append`s each array element, and **removes** the
|
|
39
|
-
* key entirely for a `null`/`undefined` value.
|
|
35
|
+
* full navigation). Navigates to the address {@link withSearchParams} builds
|
|
36
|
+
* from the current URL and `next`, so every unrelated param is kept; the merge
|
|
37
|
+
* semantics per key are documented there.
|
|
40
38
|
*
|
|
41
39
|
* @param next - Params to apply, as `URLSearchParams` or a plain record. A
|
|
42
40
|
* record value of `null`/`undefined` deletes that key.
|
|
43
41
|
* @param opts - `replaceState` (default `true`) — replace vs. push history.
|
|
44
42
|
* @example
|
|
45
43
|
* ```typescript
|
|
44
|
+
* // on /films?filter=old
|
|
46
45
|
* updateUrlSearchParams({ page: '1', tag: ['a', 'b'], filter: null });
|
|
47
|
-
* // ?page=1&tag=a&tag=b (
|
|
46
|
+
* // navigates to /films?page=1&tag=a&tag=b (the prior `filter` param is dropped)
|
|
48
47
|
* ```
|
|
49
48
|
*/
|
|
50
|
-
export declare function updateUrlSearchParams(next:
|
|
49
|
+
export declare function updateUrlSearchParams(next: SearchParamsPatch, opts?: {
|
|
51
50
|
replaceState?: boolean;
|
|
52
51
|
}): void;
|
|
53
52
|
/**
|
|
@@ -58,8 +57,8 @@ export declare function updateUrlSearchParams(next: URLSearchParams | Record<str
|
|
|
58
57
|
* page URL (tests, a server `load`).
|
|
59
58
|
*
|
|
60
59
|
* `set` rewrites only the keys that `options.serialize` produces (clear +
|
|
61
|
-
* re-append) and preserves the rest, then navigates with `goto`
|
|
62
|
-
* (`replaceState`, `noScroll`, `keepFocus`).
|
|
60
|
+
* re-append) and preserves the rest, then navigates with `goto` to the address
|
|
61
|
+
* {@link withSearchParams} builds (`replaceState`, `noScroll`, `keepFocus`).
|
|
63
62
|
*
|
|
64
63
|
* @param _key - Ignored — `options.parse`/`options.serialize` already close
|
|
65
64
|
* over the key (see {@link useUrlArrayParam}); kept only for signature parity
|
package/dist/url.svelte.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { building } from '$app/environment';
|
|
2
2
|
import { goto } from '$app/navigation';
|
|
3
3
|
import { page } from '$app/state';
|
|
4
|
+
import { withSearchParams } from './search-params.js';
|
|
5
|
+
// The pure core of the two writers below, re-exported so this import path
|
|
6
|
+
// carries it next to them. Its own module — and its own `./search-params`
|
|
7
|
+
// subpath — because it must stay free of `$app`: importing this one pulls
|
|
8
|
+
// SvelteKit's client runtime, which a `load` or a form action must not.
|
|
9
|
+
export { withSearchParams } from './search-params.js';
|
|
4
10
|
// The v8 view-object binding lives in its own module; re-exported here so the
|
|
5
11
|
// documented import path (`@urbicon-ui/sveltekit-utils/url.svelte`) carries it.
|
|
6
12
|
// The mirror types (TableViewLike, TableViewSnapshot, …) are exported from the
|
|
@@ -12,50 +18,31 @@ import { page } from '$app/state';
|
|
|
12
18
|
export { bindViewToUrl } from './view-binding.svelte.js';
|
|
13
19
|
/**
|
|
14
20
|
* Low-level escape hatch to update several params at once via `goto` (without a
|
|
15
|
-
* full navigation).
|
|
16
|
-
* every unrelated param
|
|
17
|
-
*
|
|
18
|
-
* Merge semantics per key in `next`: the key is first cleared, then re-applied
|
|
19
|
-
* — a `URLSearchParams` re-appends all of its entries (repeated keys survive),
|
|
20
|
-
* a record `set`s a scalar, `append`s each array element, and **removes** the
|
|
21
|
-
* key entirely for a `null`/`undefined` value.
|
|
21
|
+
* full navigation). Navigates to the address {@link withSearchParams} builds
|
|
22
|
+
* from the current URL and `next`, so every unrelated param is kept; the merge
|
|
23
|
+
* semantics per key are documented there.
|
|
22
24
|
*
|
|
23
25
|
* @param next - Params to apply, as `URLSearchParams` or a plain record. A
|
|
24
26
|
* record value of `null`/`undefined` deletes that key.
|
|
25
27
|
* @param opts - `replaceState` (default `true`) — replace vs. push history.
|
|
26
28
|
* @example
|
|
27
29
|
* ```typescript
|
|
30
|
+
* // on /films?filter=old
|
|
28
31
|
* updateUrlSearchParams({ page: '1', tag: ['a', 'b'], filter: null });
|
|
29
|
-
* // ?page=1&tag=a&tag=b (
|
|
32
|
+
* // navigates to /films?page=1&tag=a&tag=b (the prior `filter` param is dropped)
|
|
30
33
|
* ```
|
|
31
34
|
*/
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
35
|
+
// This writer and `createUrlParam`'s setter hand `goto` the pathname-qualified
|
|
36
|
+
// address, never a bare `?query`: `goto` resolves a relative target against
|
|
37
|
+
// `document.baseURI` (`@sveltejs/kit/src/runtime/client/utils.js` `resolve_url`,
|
|
38
|
+
// which falls back to the first `<base>` tag), so with a `<base href>` in the
|
|
39
|
+
// document `?page=2` keeps the base's path, not the page's. No harness can
|
|
40
|
+
// separate the two spellings by outcome — both resolve against `page.url` there
|
|
41
|
+
// — so `url.test.ts` pins the string `goto` was handed instead.
|
|
42
|
+
// The address is not a route id either, so no `resolve()` here; callers are
|
|
43
|
+
// free to call it at their composition point.
|
|
36
44
|
export function updateUrlSearchParams(next, opts) {
|
|
37
|
-
|
|
38
|
-
if (next instanceof URLSearchParams) {
|
|
39
|
-
for (const [k] of next)
|
|
40
|
-
base.delete(k);
|
|
41
|
-
for (const [k, v] of next)
|
|
42
|
-
base.append(k, v);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
for (const [key, val] of Object.entries(next)) {
|
|
46
|
-
base.delete(key);
|
|
47
|
-
if (Array.isArray(val)) {
|
|
48
|
-
for (const v of val)
|
|
49
|
-
base.append(key, v);
|
|
50
|
-
}
|
|
51
|
-
else if (val != null) {
|
|
52
|
-
base.set(key, String(val));
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const q = base.toString();
|
|
57
|
-
const path = page.url.pathname;
|
|
58
|
-
goto(q ? `${path}?${q}` : path, {
|
|
45
|
+
goto(withSearchParams(page.url, next), {
|
|
59
46
|
replaceState: opts?.replaceState ?? true,
|
|
60
47
|
noScroll: true,
|
|
61
48
|
keepFocus: true
|
|
@@ -69,8 +56,8 @@ export function updateUrlSearchParams(next, opts) {
|
|
|
69
56
|
* page URL (tests, a server `load`).
|
|
70
57
|
*
|
|
71
58
|
* `set` rewrites only the keys that `options.serialize` produces (clear +
|
|
72
|
-
* re-append) and preserves the rest, then navigates with `goto`
|
|
73
|
-
* (`replaceState`, `noScroll`, `keepFocus`).
|
|
59
|
+
* re-append) and preserves the rest, then navigates with `goto` to the address
|
|
60
|
+
* {@link withSearchParams} builds (`replaceState`, `noScroll`, `keepFocus`).
|
|
74
61
|
*
|
|
75
62
|
* @param _key - Ignored — `options.parse`/`options.serialize` already close
|
|
76
63
|
* over the key (see {@link useUrlArrayParam}); kept only for signature parity
|
|
@@ -84,14 +71,7 @@ export function updateUrlSearchParams(next, opts) {
|
|
|
84
71
|
export function createUrlParam(_key, options) {
|
|
85
72
|
const get = (sp) => options.parse(sp) ?? options.initial;
|
|
86
73
|
function setValue(next) {
|
|
87
|
-
|
|
88
|
-
const nextSp = options.serialize(next);
|
|
89
|
-
for (const [k] of nextSp)
|
|
90
|
-
current.delete(k);
|
|
91
|
-
for (const [k, v] of nextSp)
|
|
92
|
-
current.append(k, v);
|
|
93
|
-
const q = current.toString();
|
|
94
|
-
goto(q ? `?${q}` : page.url.pathname, {
|
|
74
|
+
goto(withSearchParams(page.url, options.serialize(next)), {
|
|
95
75
|
replaceState: options.replaceState ?? true,
|
|
96
76
|
noScroll: true,
|
|
97
77
|
keepFocus: true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urbicon-ui/sveltekit-utils",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.20.0",
|
|
4
4
|
"description": "SvelteKit helper utilities — createCronRunner, streamSse, and URL-state runes",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
"import": "./dist/url.svelte.js",
|
|
39
39
|
"default": "./dist/url.svelte.js"
|
|
40
40
|
},
|
|
41
|
+
"./search-params": {
|
|
42
|
+
"types": "./dist/search-params.d.ts",
|
|
43
|
+
"import": "./dist/search-params.js",
|
|
44
|
+
"default": "./dist/search-params.js"
|
|
45
|
+
},
|
|
41
46
|
"./cron": {
|
|
42
47
|
"types": "./dist/cron.d.ts",
|
|
43
48
|
"import": "./dist/cron.js"
|