UNPKG

svelte

Version:

Cybernetically enhanced web apps

175 lines (151 loc) 3.79 kB
import { DEV } from 'esm-env'; import { state, increment } from '../internal/client/reactivity/sources.js'; import { tag } from '../internal/client/dev/tracing.js'; import { get } from '../internal/client/runtime.js'; import { get_current_url } from './url.js'; export const REPLACE = Symbol(); /** * A reactive version of the built-in [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) object. * Reading its contents (by iterating, or by calling `params.get(...)` or `params.getAll(...)` as in the [example](https://svelte.dev/playground/b3926c86c5384bab9f2cf993bc08c1c8) below) in an [effect](https://svelte.dev/docs/svelte/$effect) or [derived](https://svelte.dev/docs/svelte/$derived) * will cause it to be re-evaluated as necessary when the params are updated. * * ```svelte * <script> * import { SvelteURLSearchParams } from 'svelte/reactivity'; * * const params = new SvelteURLSearchParams('message=hello'); * * let key = $state('key'); * let value = $state('value'); * </script> * * <input bind:value={key} /> * <input bind:value={value} /> * <button onclick={() => params.append(key, value)}>append</button> * * <p>?{params.toString()}</p> * * {#each params as [key, value]} * <p>{key}: {value}</p> * {/each} * ``` */ export class SvelteURLSearchParams extends URLSearchParams { #version = DEV ? tag(state(0), 'SvelteURLSearchParams version') : state(0); #url = get_current_url(); #updating = false; #update_url() { if (!this.#url || this.#updating) return; this.#updating = true; const search = this.toString(); this.#url.search = search && `?${search}`; this.#updating = false; } /** * @param {URLSearchParams} params * @internal */ [REPLACE](params) { if (this.#updating) return; this.#updating = true; for (const key of [...super.keys()]) { super.delete(key); } for (const [key, value] of params) { super.append(key, value); } increment(this.#version); this.#updating = false; } /** * @param {string} name * @param {string} value * @returns {void} */ append(name, value) { super.append(name, value); this.#update_url(); increment(this.#version); } /** * @param {string} name * @param {string=} value * @returns {void} */ delete(name, value) { var has_value = super.has(name, value); super.delete(name, value); if (has_value) { this.#update_url(); increment(this.#version); } } /** * @param {string} name * @returns {string|null} */ get(name) { get(this.#version); return super.get(name); } /** * @param {string} name * @returns {string[]} */ getAll(name) { get(this.#version); return super.getAll(name); } /** * @param {string} name * @param {string=} value * @returns {boolean} */ has(name, value) { get(this.#version); return super.has(name, value); } keys() { get(this.#version); return super.keys(); } /** * @param {string} name * @param {string} value * @returns {void} */ set(name, value) { var previous = super.getAll(name).join(''); super.set(name, value); // can't use has(name, value), because for something like https://svelte.dev?foo=1&bar=2&foo=3 // if you set `foo` to 1, then foo=3 gets deleted whilst `has("foo", "1")` returns true if (previous !== super.getAll(name).join('')) { this.#update_url(); increment(this.#version); } } sort() { super.sort(); this.#update_url(); increment(this.#version); } toString() { get(this.#version); return super.toString(); } values() { get(this.#version); return super.values(); } entries() { get(this.#version); return super.entries(); } [Symbol.iterator]() { return this.entries(); } get size() { get(this.#version); return super.size; } }