use-prms 0.2.0 → 0.3.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/dist/hash.js CHANGED
@@ -28,6 +28,25 @@ function serializeMultiParams(params) {
28
28
  }
29
29
  return result;
30
30
  }
31
+ var LOCATION_CHANGE_EVENT = "use-prms:locationchange";
32
+ var historyPatched = false;
33
+ function patchHistoryApi() {
34
+ if (typeof window === "undefined" || historyPatched) return;
35
+ historyPatched = true;
36
+ const originalPushState = history.pushState.bind(history);
37
+ const originalReplaceState = history.replaceState.bind(history);
38
+ history.pushState = function(state, title, url) {
39
+ originalPushState(state, title, url);
40
+ window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT));
41
+ window.dispatchEvent(new PopStateEvent("popstate", { state }));
42
+ };
43
+ history.replaceState = function(state, title, url) {
44
+ originalReplaceState(state, title, url);
45
+ window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT));
46
+ window.dispatchEvent(new PopStateEvent("popstate", { state }));
47
+ };
48
+ }
49
+ patchHistoryApi();
31
50
  var queryStrategy = {
32
51
  getRaw() {
33
52
  if (typeof window === "undefined") return "";
@@ -45,7 +64,11 @@ var queryStrategy = {
45
64
  if (typeof window === "undefined") return () => {
46
65
  };
47
66
  window.addEventListener("popstate", callback);
48
- return () => window.removeEventListener("popstate", callback);
67
+ window.addEventListener(LOCATION_CHANGE_EVENT, callback);
68
+ return () => {
69
+ window.removeEventListener("popstate", callback);
70
+ window.removeEventListener(LOCATION_CHANGE_EVENT, callback);
71
+ };
49
72
  }
50
73
  };
51
74
  var hashStrategy = {
@@ -68,12 +91,28 @@ var hashStrategy = {
68
91
  };
69
92
  window.addEventListener("hashchange", callback);
70
93
  window.addEventListener("popstate", callback);
94
+ window.addEventListener(LOCATION_CHANGE_EVENT, callback);
71
95
  return () => {
72
96
  window.removeEventListener("hashchange", callback);
73
97
  window.removeEventListener("popstate", callback);
98
+ window.removeEventListener(LOCATION_CHANGE_EVENT, callback);
74
99
  };
75
100
  }
76
101
  };
102
+ function notifyLocationChange() {
103
+ if (typeof window === "undefined") return;
104
+ window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT));
105
+ }
106
+ function clearParams(strategy = "query") {
107
+ if (typeof window === "undefined") return;
108
+ const url = new URL(window.location.href);
109
+ if (strategy === "hash") {
110
+ url.hash = "";
111
+ } else {
112
+ url.search = "";
113
+ }
114
+ window.history.replaceState({}, "", url.toString());
115
+ }
77
116
  var defaultStrategy = queryStrategy;
78
117
  function getDefaultStrategy() {
79
118
  return defaultStrategy;
@@ -102,17 +141,29 @@ var boolParam = {
102
141
  function intParam(init) {
103
142
  return {
104
143
  encode: (value) => value === init ? void 0 : value.toString(),
105
- decode: (encoded) => encoded !== void 0 ? parseInt(encoded, 10) : init
144
+ decode: (encoded) => {
145
+ if (encoded === void 0 || encoded === "") return init;
146
+ const parsed = parseInt(encoded, 10);
147
+ return isNaN(parsed) ? init : parsed;
148
+ }
106
149
  };
107
150
  }
108
151
  var optIntParam = {
109
152
  encode: (value) => value === null ? void 0 : value.toString(),
110
- decode: (encoded) => encoded !== void 0 ? parseInt(encoded, 10) : null
153
+ decode: (encoded) => {
154
+ if (encoded === void 0 || encoded === "") return null;
155
+ const parsed = parseInt(encoded, 10);
156
+ return isNaN(parsed) ? null : parsed;
157
+ }
111
158
  };
112
159
  function floatParam(init) {
113
160
  return {
114
161
  encode: (value) => value === init ? void 0 : value.toString(),
115
- decode: (encoded) => encoded !== void 0 ? parseFloat(encoded) : init
162
+ decode: (encoded) => {
163
+ if (encoded === void 0 || encoded === "") return init;
164
+ const parsed = parseFloat(encoded);
165
+ return isNaN(parsed) ? init : parsed;
166
+ }
116
167
  };
117
168
  }
118
169
  function enumParam(init, values) {
@@ -470,6 +521,6 @@ function updateUrl(params, push = false) {
470
521
  // src/hash.ts
471
522
  setDefaultStrategy(hashStrategy);
472
523
 
473
- export { boolParam, codeParam, codesParam, defStringParam, enumParam, floatParam, getCurrentParams, getDefaultStrategy, hashStrategy, intParam, multiFloatParam, multiIntParam, multiStringParam, numberArrayParam, optIntParam, paginationParam, parseMultiParams, parseParams, queryStrategy, serializeMultiParams, serializeParams, setDefaultStrategy, stringParam, stringsParam, updateUrl, useMultiUrlParam, useMultiUrlParams, useUrlParam, useUrlParams };
524
+ export { boolParam, clearParams, codeParam, codesParam, defStringParam, enumParam, floatParam, getCurrentParams, getDefaultStrategy, hashStrategy, intParam, multiFloatParam, multiIntParam, multiStringParam, notifyLocationChange, numberArrayParam, optIntParam, paginationParam, parseMultiParams, parseParams, queryStrategy, serializeMultiParams, serializeParams, setDefaultStrategy, stringParam, stringsParam, updateUrl, useMultiUrlParam, useMultiUrlParams, useUrlParam, useUrlParams };
474
525
  //# sourceMappingURL=hash.js.map
475
526
  //# sourceMappingURL=hash.js.map
package/dist/hash.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts","../src/params.ts","../src/multiParams.ts","../src/useUrlParam.ts","../src/index.ts","../src/hash.ts"],"names":["encoded"],"mappings":"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","file":"hash.js","sourcesContent":["/**\n * Core multi-value operations and location strategies\n */\n\n/**\n * Multi-value encoded representation\n * An array of strings representing multiple values for a single URL parameter key\n */\nexport type MultiEncoded = string[]\n\n/**\n * Location strategy interface for abstracting URL storage location\n * (query string vs hash fragment)\n */\nexport interface LocationStrategy {\n /** Get raw string from location (for caching comparison) */\n getRaw(): string\n /** Parse current location to multi-value params */\n parse(): Record<string, MultiEncoded>\n /** Build URL string with updated params */\n buildUrl(base: URL, params: Record<string, MultiEncoded>): string\n /** Subscribe to location changes, returns unsubscribe function */\n subscribe(callback: () => void): () => void\n}\n\n/**\n * Parse URL string to multi-value params\n * Each key maps to an array of all values for that key\n */\nexport function parseMultiParams(source: string | URLSearchParams): Record<string, MultiEncoded> {\n const searchParams = typeof source === 'string'\n ? new URLSearchParams(source)\n : source\n\n const result: Record<string, MultiEncoded> = {}\n const keys = new Set(searchParams.keys())\n\n for (const key of keys) {\n result[key] = searchParams.getAll(key)\n }\n\n return result\n}\n\n/**\n * Serialize multi-value params to URL string format\n * Repeated keys are serialized as separate entries: key=a&key=b\n */\nexport function serializeMultiParams(params: Record<string, MultiEncoded>): string {\n const searchParams = new URLSearchParams()\n\n for (const [key, values] of Object.entries(params)) {\n for (const value of values) {\n if (value === '') {\n // Valueless params handled separately\n continue\n }\n searchParams.append(key, value)\n }\n }\n\n let result = searchParams.toString()\n\n // Handle valueless params (empty string values) manually\n const valuelessKeys = Object.entries(params)\n .filter(([_, values]) => values.includes(''))\n .map(([key, _]) => encodeURIComponent(key))\n\n if (valuelessKeys.length > 0) {\n const valuelessPart = valuelessKeys.join('&')\n result = result ? `${result}&${valuelessPart}` : valuelessPart\n }\n\n return result\n}\n\n/**\n * Query string location strategy\n * Reads/writes to window.location.search\n */\nexport const queryStrategy: LocationStrategy = {\n getRaw(): string {\n if (typeof window === 'undefined') return ''\n return window.location.search\n },\n\n parse(): Record<string, MultiEncoded> {\n if (typeof window === 'undefined') return {}\n return parseMultiParams(window.location.search)\n },\n\n buildUrl(base: URL, params: Record<string, MultiEncoded>): string {\n base.search = serializeMultiParams(params)\n return base.toString()\n },\n\n subscribe(callback: () => void): () => void {\n if (typeof window === 'undefined') return () => {}\n window.addEventListener('popstate', callback)\n return () => window.removeEventListener('popstate', callback)\n },\n}\n\n/**\n * Hash fragment location strategy\n * Reads/writes to window.location.hash\n * Hash is parsed as URLSearchParams format: #key=value&key2=value2\n */\nexport const hashStrategy: LocationStrategy = {\n getRaw(): string {\n if (typeof window === 'undefined') return ''\n return window.location.hash\n },\n\n parse(): Record<string, MultiEncoded> {\n if (typeof window === 'undefined') return {}\n const hash = window.location.hash\n // Remove leading # if present\n const hashString = hash.startsWith('#') ? hash.slice(1) : hash\n return parseMultiParams(hashString)\n },\n\n buildUrl(base: URL, params: Record<string, MultiEncoded>): string {\n base.hash = serializeMultiParams(params)\n return base.toString()\n },\n\n subscribe(callback: () => void): () => void {\n if (typeof window === 'undefined') return () => {}\n // Listen to both hashchange and popstate for hash navigation\n window.addEventListener('hashchange', callback)\n window.addEventListener('popstate', callback)\n return () => {\n window.removeEventListener('hashchange', callback)\n window.removeEventListener('popstate', callback)\n }\n },\n}\n\n// Default strategy (can be changed by entry points like hash.ts)\nlet defaultStrategy: LocationStrategy = queryStrategy\n\n/**\n * Get the current default location strategy\n */\nexport function getDefaultStrategy(): LocationStrategy {\n return defaultStrategy\n}\n\n/**\n * Set the default location strategy\n * Called by entry points (e.g., hash.ts sets this to hashStrategy)\n */\nexport function setDefaultStrategy(strategy: LocationStrategy): void {\n defaultStrategy = strategy\n}\n","/**\n * Built-in parameter types with smart defaults and minimal encoding\n */\n\nimport type { Encoded, Param } from './index.js'\n\n/**\n * Optional string parameter.\n * - undefined → not present\n * - empty string → ?key=\n * - non-empty → ?key=value\n */\nexport function stringParam(init?: string): Param<string | undefined> {\n return {\n encode: (value) => value === init ? undefined : value,\n decode: (encoded) => encoded === undefined ? init : encoded,\n }\n}\n\n/**\n * Required string parameter with default.\n * Omitted from URL when equal to default.\n */\nexport function defStringParam(init: string): Param<string> {\n return {\n encode: (value) => value === init ? undefined : value,\n decode: (encoded) => encoded ?? init,\n }\n}\n\n/**\n * Boolean parameter.\n * - true → ?key (valueless)\n * - false → not present\n */\nexport const boolParam: Param<boolean> = {\n encode: (value) => value ? '' : undefined,\n decode: (encoded) => encoded !== undefined,\n}\n\n/**\n * Integer parameter with default.\n * Omitted from URL when equal to default.\n */\nexport function intParam(init: number): Param<number> {\n return {\n encode: (value) => value === init ? undefined : value.toString(),\n decode: (encoded) => encoded !== undefined ? parseInt(encoded, 10) : init,\n }\n}\n\n/**\n * Optional integer parameter.\n * - null → not present\n * - number → ?key=123\n */\nexport const optIntParam: Param<number | null> = {\n encode: (value) => value === null ? undefined : value.toString(),\n decode: (encoded) => encoded !== undefined ? parseInt(encoded, 10) : null,\n}\n\n/**\n * Float parameter with default.\n * Omitted from URL when equal to default.\n */\nexport function floatParam(init: number): Param<number> {\n return {\n encode: (value) => value === init ? undefined : value.toString(),\n decode: (encoded) => encoded !== undefined ? parseFloat(encoded) : init,\n }\n}\n\n/**\n * Enum parameter with validation.\n * Omitted from URL when equal to default.\n * Invalid values fall back to default with console warning.\n */\nexport function enumParam<T extends string>(\n init: T,\n values: readonly T[]\n): Param<T> {\n const validSet = new Set(values)\n\n return {\n encode: (value) => {\n if (!validSet.has(value)) {\n console.warn(`Invalid enum value: ${value}, expected one of ${values.join(', ')}`)\n return undefined\n }\n return value === init ? undefined : value\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n if (!validSet.has(encoded as T)) {\n console.warn(`Invalid enum value: ${encoded}, expected one of ${values.join(', ')}. Using default: ${init}`)\n return init\n }\n return encoded as T\n },\n }\n}\n\n/**\n * String array parameter with delimiter.\n * Omitted from URL when equal to default.\n * Empty array encodes as empty string (?key=)\n */\nexport function stringsParam(\n init: string[] = [],\n delimiter = ' '\n): Param<string[]> {\n const initEncoded = init.join(delimiter)\n\n return {\n encode: (values) => {\n const encoded = values.join(delimiter)\n if (encoded === initEncoded) return undefined\n return encoded\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n if (encoded === '') return []\n return encoded.split(delimiter)\n },\n }\n}\n\n/**\n * Number array parameter.\n * Omitted from URL when equal to default.\n * Uses comma delimiter.\n */\nexport function numberArrayParam(init: number[] = []): Param<number[]> {\n const isEqual = (a: number[], b: number[]) =>\n a.length === b.length && a.every((v, i) => v === b[i])\n\n return {\n encode: (values) => {\n if (isEqual(values, init)) return undefined\n return values.map(v => v.toString()).join(',')\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n if (encoded === '') return []\n return encoded.split(',').map(v => parseFloat(v))\n },\n }\n}\n\n/**\n * Pagination parameter combining offset and page size.\n * Uses space (which encodes as + in URLs) as delimiter.\n *\n * Encoding rules:\n * - offset=0, pageSize=default → not present (undefined)\n * - offset=0, pageSize=custom → \" pageSize\" (e.g., \" 20\" → +20 in URL)\n * - offset>0, pageSize=default → \"offset\" (e.g., \"100\")\n * - offset>0, pageSize=custom → \"offset pageSize\" (e.g., \"100 20\" → 100+20 in URL)\n *\n * @param defaultPageSize - The default page size (omitted from URL when used)\n * @param validPageSizes - Optional array of valid page sizes for validation\n */\nexport type Pagination = { offset: number; pageSize: number }\n\nexport function paginationParam(\n defaultPageSize: number,\n validPageSizes?: readonly number[],\n): Param<Pagination> {\n return {\n encode: ({ offset, pageSize }) => {\n if (offset === 0 && pageSize === defaultPageSize) return undefined\n if (offset === 0) return ` ${pageSize}` // Space prefix → +pageSize in URL\n if (pageSize === defaultPageSize) return String(offset)\n return `${offset} ${pageSize}` // Space encodes as + in URL\n },\n decode: (encoded) => {\n if (!encoded) return { offset: 0, pageSize: defaultPageSize }\n const parts = encoded.split(' ') // URL + decodes to space\n // Handle \" pageSize\" case (offset 0 with custom page size)\n const offset = parts[0] === '' ? 0 : parseInt(parts[0], 10) || 0\n let pageSize = parts[1] ? parseInt(parts[1], 10) : defaultPageSize\n // Validate page size if validation array provided\n if (validPageSizes && !validPageSizes.includes(pageSize)) {\n pageSize = defaultPageSize\n }\n return { offset, pageSize }\n },\n }\n}\n\n/**\n * Code mapping for enum values - maps full values to short codes for compact URLs.\n * Can be specified as:\n * - Array of [value, code] tuples: [['Rides', 'r'], ['Minutes', 'm']]\n * - Object mapping values to codes: { Rides: 'r', Minutes: 'm' }\n */\nexport type CodeMap<T extends string> = [T, string][] | Record<T, string>\n\nfunction normalizeCodeMap<T extends string>(codeMap: CodeMap<T>): [T, string][] {\n if (Array.isArray(codeMap)) return codeMap\n return Object.entries(codeMap) as [T, string][]\n}\n\n/**\n * Single-value enum parameter with short code mapping.\n * Maps full enum values to abbreviated codes for compact URLs.\n * Omitted from URL when equal to default.\n *\n * @example\n * // ?y=r for \"Rides\", ?y=m for \"Minutes\", omitted for default \"Rides\"\n * codeParam('Rides', [['Rides', 'r'], ['Minutes', 'm']])\n * // or with object syntax:\n * codeParam('Rides', { Rides: 'r', Minutes: 'm' })\n */\nexport function codeParam<T extends string>(\n init: T,\n codeMap: CodeMap<T>,\n): Param<T> {\n const entries = normalizeCodeMap(codeMap)\n const valueToCode = new Map(entries)\n const codeToValue = new Map(entries.map(([v, c]) => [c, v]))\n\n return {\n encode: (value) => {\n if (value === init) return undefined\n return valueToCode.get(value) ?? value\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n return codeToValue.get(encoded) ?? init\n },\n }\n}\n\n/**\n * Multi-value parameter with short code mapping.\n * Maps full values to abbreviated codes for compact URLs.\n * Omitted from URL when all values are selected.\n *\n * @param allValues - Array of all possible values (used to detect \"all selected\")\n * @param codeMap - Mapping from values to short codes\n * @param separator - Delimiter between codes (default: '' for most compact URLs)\n *\n * @example\n * // Regions: ?r=nj for NYC+JC, ?r=njh or omitted for all three\n * codesParam(['NYC', 'JC', 'HOB'], [['NYC', 'n'], ['JC', 'j'], ['HOB', 'h']])\n * // or with object syntax and custom separator:\n * codesParam(['NYC', 'JC', 'HOB'], { NYC: 'n', JC: 'j', HOB: 'h' }, ',')\n */\nexport function codesParam<T extends string>(\n allValues: readonly T[],\n codeMap: CodeMap<T>,\n separator: string = '',\n): Param<T[]> {\n const entries = normalizeCodeMap(codeMap)\n const valueToCode = new Map(entries)\n const codeToValue = new Map(entries.map(([v, c]) => [c, v]))\n\n return {\n encode: (values) => {\n // Omit when all values selected\n if (values.length === allValues.length && allValues.every(v => values.includes(v))) {\n return undefined\n }\n return values.map(v => valueToCode.get(v) ?? v).join(separator)\n },\n decode: (encoded) => {\n if (encoded === undefined) return [...allValues]\n if (encoded === '') return []\n const codes = separator ? encoded.split(separator) : encoded.split('')\n return codes.map(c => codeToValue.get(c)).filter((v): v is T => v !== undefined)\n },\n }\n}\n","/**\n * Multi-value parameter types for handling repeated URL params\n * e.g., ?tag=a&tag=b&tag=c\n */\n\nimport type { MultiEncoded } from './core.js'\n\n/**\n * A bidirectional converter between a typed value and its multi-value URL representation.\n * Similar to Param<T> but works with string[] instead of string | undefined.\n */\nexport type MultiParam<T> = {\n encode: (value: T) => MultiEncoded\n decode: (encoded: MultiEncoded) => T\n}\n\n/**\n * Multi-value string array parameter.\n * Each string becomes a separate URL param with the same key.\n *\n * @example\n * // ?tag=a&tag=b&tag=c → ['a', 'b', 'c']\n * const [tags, setTags] = useMultiUrlParam('tag', multiStringParam())\n */\nexport function multiStringParam(init: string[] = []): MultiParam<string[]> {\n return {\n encode: (values) => {\n if (values.length === 0 && init.length === 0) return []\n if (arraysEqual(values, init)) return []\n return values\n },\n decode: (encoded) => {\n if (encoded.length === 0) return init\n return encoded\n },\n }\n}\n\n/**\n * Multi-value integer array parameter.\n * Each number becomes a separate URL param with the same key.\n *\n * @example\n * // ?id=1&id=2&id=3 → [1, 2, 3]\n * const [ids, setIds] = useMultiUrlParam('id', multiIntParam())\n */\nexport function multiIntParam(init: number[] = []): MultiParam<number[]> {\n return {\n encode: (values) => {\n if (values.length === 0 && init.length === 0) return []\n if (arraysEqual(values, init)) return []\n return values.map(v => v.toString())\n },\n decode: (encoded) => {\n if (encoded.length === 0) return init\n return encoded.map(v => parseInt(v, 10))\n },\n }\n}\n\n/**\n * Multi-value float array parameter.\n * Each number becomes a separate URL param with the same key.\n *\n * @example\n * // ?val=1.5&val=2.7 → [1.5, 2.7]\n * const [vals, setVals] = useMultiUrlParam('val', multiFloatParam())\n */\nexport function multiFloatParam(init: number[] = []): MultiParam<number[]> {\n return {\n encode: (values) => {\n if (values.length === 0 && init.length === 0) return []\n if (arraysEqual(values, init)) return []\n return values.map(v => v.toString())\n },\n decode: (encoded) => {\n if (encoded.length === 0) return init\n return encoded.map(v => parseFloat(v))\n },\n }\n}\n\n/** Helper to compare arrays for equality */\nfunction arraysEqual<T>(a: T[], b: T[]): boolean {\n return a.length === b.length && a.every((v, i) => v === b[i])\n}\n","/**\n * React hooks for managing URL parameters\n */\n\nimport { useCallback, useRef, useSyncExternalStore } from 'react'\nimport type { Param } from './index.js'\nimport type { LocationStrategy, MultiEncoded } from './core.js'\nimport { getDefaultStrategy, serializeMultiParams } from './core.js'\nimport type { MultiParam } from './multiParams.js'\n\n/**\n * Cached snapshot to prevent infinite loops in useSyncExternalStore\n * Keyed by strategy (so query and hash don't share cache)\n */\nconst snapshotCache = new WeakMap<LocationStrategy, {\n raw: string\n snapshot: Record<string, MultiEncoded>\n}>()\n\n/**\n * Get URL snapshot for a given strategy\n * Returns cached snapshot if URL hasn't changed\n */\nfunction getSnapshot(strategy: LocationStrategy): Record<string, MultiEncoded> {\n const raw = strategy.getRaw()\n const cached = snapshotCache.get(strategy)\n\n if (cached && cached.raw === raw) {\n return cached.snapshot\n }\n\n const snapshot = strategy.parse()\n snapshotCache.set(strategy, { raw, snapshot })\n return snapshot\n}\n\n/**\n * Server-side snapshot (always empty)\n */\nfunction getServerSnapshot(): Record<string, MultiEncoded> {\n return {}\n}\n\n/**\n * Convert single-value Encoded to multi-value MultiEncoded\n */\nfunction singleToMulti(encoded: string | undefined): MultiEncoded {\n if (encoded === undefined) return []\n return [encoded]\n}\n\n/**\n * Convert multi-value MultiEncoded to single-value Encoded\n */\nfunction multiToSingle(multi: MultiEncoded): string | undefined {\n if (multi.length === 0) return undefined\n return multi[0]\n}\n\n/**\n * React hook for managing a single URL query parameter.\n *\n * @param key - Query parameter key\n * @param param - Param encoder/decoder\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Tuple of [value, setValue]\n *\n * @example\n * ```tsx\n * const [zoom, setZoom] = useUrlParam('z', boolParam)\n * const [device, setDevice] = useUrlParam('d', stringParam('default'))\n * ```\n */\nexport function useUrlParam<T>(\n key: string,\n param: Param<T>,\n push = false\n): [T, (value: T) => void] {\n const strategy = getDefaultStrategy()\n\n // Use ref to avoid recreating setValue when param changes\n const paramRef = useRef(param)\n paramRef.current = param\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Memoize decoded value based on encoded string AND param identity\n // Re-decode if either the URL param string changes OR the param object changes\n // (e.g., deviceIdsParam depends on devices array which loads asynchronously)\n const encoded = multiToSingle(urlParams[key] ?? [])\n const cacheRef = useRef<{ encoded: typeof encoded; param: Param<T>; decoded: T } | null>(null)\n\n if (cacheRef.current === null || cacheRef.current.encoded !== encoded || cacheRef.current.param !== param) {\n cacheRef.current = { encoded, param, decoded: param.decode(encoded) }\n }\n const value = cacheRef.current.decoded\n\n // Update URL when value changes\n const setValue = useCallback(\n (newValue: T) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n const encoded = paramRef.current.encode(newValue)\n\n // Update this parameter (single → multi)\n if (encoded === undefined) {\n delete currentParams[key]\n } else {\n currentParams[key] = [encoded]\n }\n\n // Build and update URL\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [key, push, strategy]\n )\n\n return [value, setValue]\n}\n\n/**\n * React hook for managing multiple URL query parameters together.\n * Updates are batched into a single history entry.\n *\n * @param params - Object mapping keys to Param types\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Object with decoded values and update function\n *\n * @example\n * ```tsx\n * const { values, setValues } = useUrlParams({\n * zoom: boolParam,\n * device: stringParam('default'),\n * count: intParam(10)\n * })\n *\n * // Update multiple params at once\n * setValues({ zoom: true, count: 20 })\n * ```\n */\nexport function useUrlParams<P extends Record<string, Param<any>>>(\n params: P,\n push = false\n): {\n values: { [K in keyof P]: P[K] extends Param<infer T> ? T : never }\n setValues: (updates: Partial<{ [K in keyof P]: P[K] extends Param<infer T> ? T : never }>) => void\n} {\n const strategy = getDefaultStrategy()\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Decode all values from URL\n const values = Object.fromEntries(\n Object.entries(params).map(([key, param]) => [\n key,\n param.decode(multiToSingle(urlParams[key] ?? []))\n ])\n ) as { [K in keyof P]: P[K] extends Param<infer T> ? T : never }\n\n // Update multiple parameters at once\n const setValues = useCallback(\n (updates: Partial<{ [K in keyof P]: P[K] extends Param<infer T> ? T : never }>) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n\n // Apply all updates\n for (const [key, value] of Object.entries(updates)) {\n const param = params[key]\n if (!param) continue\n\n const encoded = param.encode(value)\n if (encoded === undefined) {\n delete currentParams[key]\n } else {\n currentParams[key] = [encoded]\n }\n }\n\n // Build and update URL once\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [params, push, strategy]\n )\n\n return { values, setValues }\n}\n\n/**\n * React hook for managing a single multi-value URL parameter.\n * Supports repeated params like ?tag=a&tag=b&tag=c\n *\n * @param key - Query parameter key\n * @param param - MultiParam encoder/decoder\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Tuple of [value, setValue]\n *\n * @example\n * ```tsx\n * const [tags, setTags] = useMultiUrlParam('tag', multiStringParam())\n * // URL: ?tag=a&tag=b → tags = ['a', 'b']\n * ```\n */\nexport function useMultiUrlParam<T>(\n key: string,\n param: MultiParam<T>,\n push = false\n): [T, (value: T) => void] {\n const strategy = getDefaultStrategy()\n\n // Use ref to avoid recreating setValue when param changes\n const paramRef = useRef(param)\n paramRef.current = param\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Decode current value from URL\n const value = param.decode(urlParams[key] ?? [])\n\n // Update URL when value changes\n const setValue = useCallback(\n (newValue: T) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n const encoded = paramRef.current.encode(newValue)\n\n // Update this parameter\n if (encoded.length === 0) {\n delete currentParams[key]\n } else {\n currentParams[key] = encoded\n }\n\n // Build and update URL\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [key, push, strategy]\n )\n\n return [value, setValue]\n}\n\n/**\n * React hook for managing multiple multi-value URL parameters together.\n * Updates are batched into a single history entry.\n *\n * @param params - Object mapping keys to MultiParam types\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Object with decoded values and update function\n *\n * @example\n * ```tsx\n * const { values, setValues } = useMultiUrlParams({\n * tags: multiStringParam(),\n * ids: multiIntParam()\n * })\n *\n * // Update multiple multi-value params at once\n * setValues({ tags: ['a', 'b'], ids: [1, 2, 3] })\n * ```\n */\nexport function useMultiUrlParams<P extends Record<string, MultiParam<any>>>(\n params: P,\n push = false\n): {\n values: { [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }\n setValues: (updates: Partial<{ [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }>) => void\n} {\n const strategy = getDefaultStrategy()\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Decode all values from URL\n const values = Object.fromEntries(\n Object.entries(params).map(([key, param]) => [\n key,\n param.decode(urlParams[key] ?? [])\n ])\n ) as { [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }\n\n // Update multiple parameters at once\n const setValues = useCallback(\n (updates: Partial<{ [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }>) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n\n // Apply all updates\n for (const [key, value] of Object.entries(updates)) {\n const param = params[key]\n if (!param) continue\n\n const encoded = param.encode(value)\n if (encoded.length === 0) {\n delete currentParams[key]\n } else {\n currentParams[key] = encoded\n }\n }\n\n // Build and update URL once\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [params, push, strategy]\n )\n\n return { values, setValues }\n}\n","/**\n * Core types and utilities for URL parameter management\n */\n\n// Re-export core types and strategies\nexport type { MultiEncoded, LocationStrategy } from './core.js'\nexport {\n parseMultiParams,\n serializeMultiParams,\n queryStrategy,\n hashStrategy,\n getDefaultStrategy,\n setDefaultStrategy,\n} from './core.js'\n\n/**\n * Encodes a value to a URL query parameter string.\n * - undefined: parameter not present in URL\n * - \"\": valueless parameter (e.g., ?z)\n * - string: parameter with value (e.g., ?z=foo)\n */\nexport type Encoded = string | undefined\n\n/**\n * A bidirectional converter between a typed value and its URL representation.\n */\nexport type Param<T> = {\n encode: (value: T) => Encoded\n decode: (encoded: Encoded) => T\n}\n\n/**\n * Serialize query parameters to URL string.\n * Uses URLSearchParams for proper form-urlencoded format (space → +)\n * Handles valueless params (empty string → ?key without =) manually\n *\n * @deprecated For multi-value support, use serializeMultiParams instead\n */\nexport function serializeParams(params: Record<string, Encoded>): string {\n const searchParams = new URLSearchParams()\n\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined) {\n // Skip undefined values\n continue\n } else if (value === '') {\n // Valueless param: ?key without =\n // URLSearchParams doesn't support this, so we'll handle manually\n continue\n } else {\n searchParams.set(key, value)\n }\n }\n\n let result = searchParams.toString()\n\n // Handle valueless params manually\n const valuelessKeys = Object.entries(params)\n .filter(([_, value]) => value === '')\n .map(([key, _]) => encodeURIComponent(key))\n\n if (valuelessKeys.length > 0) {\n const valuelessPart = valuelessKeys.join('&')\n result = result ? `${result}&${valuelessPart}` : valuelessPart\n }\n\n return result\n}\n\n/**\n * Parse query parameters from URL string or URLSearchParams.\n * Note: URLSearchParams treats ?z and ?z= identically (both as empty string).\n * Note: For repeated params, only the first value is returned.\n *\n * @deprecated For multi-value support, use parseMultiParams instead\n */\nexport function parseParams(source: string | URLSearchParams): Record<string, Encoded> {\n const searchParams = typeof source === 'string'\n ? new URLSearchParams(source)\n : source\n\n const result: Record<string, Encoded> = {}\n\n for (const [key, value] of searchParams.entries()) {\n // Only take first value for each key (backward compat)\n if (!(key in result)) {\n result[key] = value\n }\n }\n\n return result\n}\n\n/**\n * Get current URL query parameters (browser only)\n */\nexport function getCurrentParams(): Record<string, Encoded> {\n if (typeof window === 'undefined') return {}\n return parseParams(window.location.search)\n}\n\n/**\n * Update URL without reloading (browser only)\n * @param params - New query parameters\n * @param push - Use pushState (true) or replaceState (false)\n */\nexport function updateUrl(params: Record<string, Encoded>, push = false): void {\n if (typeof window === 'undefined') return\n\n const url = new URL(window.location.href)\n const search = serializeParams(params)\n url.search = search\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', url.toString())\n}\n\nexport * from './params.js'\nexport * from './multiParams.js'\nexport * from './useUrlParam.js'\n","/**\n * Hash params entry point\n *\n * This module sets the default location strategy to hash (window.location.hash)\n * and re-exports everything from the main module.\n *\n * Usage:\n * ```typescript\n * // Instead of:\n * import { useUrlParam, stringParam } from 'use-prms'\n *\n * // Use:\n * import { useUrlParam, stringParam } from 'use-prms/hash'\n *\n * // Same API, but reads/writes to URL hash instead of query string\n * // e.g., #name=foo instead of ?name=foo\n * ```\n */\n\nimport { setDefaultStrategy, hashStrategy } from './core.js'\n\n// Set hash as the default strategy for this entry point\nsetDefaultStrategy(hashStrategy)\n\n// Re-export everything from main module\nexport * from './index.js'\n"]}
1
+ {"version":3,"sources":["../src/core.ts","../src/params.ts","../src/multiParams.ts","../src/useUrlParam.ts","../src/index.ts","../src/hash.ts"],"names":["encoded"],"mappings":"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","file":"hash.js","sourcesContent":["/**\n * Core multi-value operations and location strategies\n */\n\n/**\n * Multi-value encoded representation\n * An array of strings representing multiple values for a single URL parameter key\n */\nexport type MultiEncoded = string[]\n\n/**\n * Location strategy interface for abstracting URL storage location\n * (query string vs hash fragment)\n */\nexport interface LocationStrategy {\n /** Get raw string from location (for caching comparison) */\n getRaw(): string\n /** Parse current location to multi-value params */\n parse(): Record<string, MultiEncoded>\n /** Build URL string with updated params */\n buildUrl(base: URL, params: Record<string, MultiEncoded>): string\n /** Subscribe to location changes, returns unsubscribe function */\n subscribe(callback: () => void): () => void\n}\n\n/**\n * Parse URL string to multi-value params\n * Each key maps to an array of all values for that key\n */\nexport function parseMultiParams(source: string | URLSearchParams): Record<string, MultiEncoded> {\n const searchParams = typeof source === 'string'\n ? new URLSearchParams(source)\n : source\n\n const result: Record<string, MultiEncoded> = {}\n const keys = new Set(searchParams.keys())\n\n for (const key of keys) {\n result[key] = searchParams.getAll(key)\n }\n\n return result\n}\n\n/**\n * Serialize multi-value params to URL string format\n * Repeated keys are serialized as separate entries: key=a&key=b\n */\nexport function serializeMultiParams(params: Record<string, MultiEncoded>): string {\n const searchParams = new URLSearchParams()\n\n for (const [key, values] of Object.entries(params)) {\n for (const value of values) {\n if (value === '') {\n // Valueless params handled separately\n continue\n }\n searchParams.append(key, value)\n }\n }\n\n let result = searchParams.toString()\n\n // Handle valueless params (empty string values) manually\n const valuelessKeys = Object.entries(params)\n .filter(([_, values]) => values.includes(''))\n .map(([key, _]) => encodeURIComponent(key))\n\n if (valuelessKeys.length > 0) {\n const valuelessPart = valuelessKeys.join('&')\n result = result ? `${result}&${valuelessPart}` : valuelessPart\n }\n\n return result\n}\n\n/**\n * Custom event name for location changes triggered by History API\n */\nconst LOCATION_CHANGE_EVENT = 'use-prms:locationchange'\n\n/**\n * Patch History API to dispatch events on pushState/replaceState\n * This enables automatic reactivity to all programmatic URL changes\n */\nlet historyPatched = false\nfunction patchHistoryApi(): void {\n if (typeof window === 'undefined' || historyPatched) return\n historyPatched = true\n\n const originalPushState = history.pushState.bind(history)\n const originalReplaceState = history.replaceState.bind(history)\n\n history.pushState = function(state, title, url) {\n originalPushState(state, title, url)\n window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT))\n // Also dispatch popstate for React Router and other libraries that listen to it\n window.dispatchEvent(new PopStateEvent('popstate', { state }))\n }\n\n history.replaceState = function(state, title, url) {\n originalReplaceState(state, title, url)\n window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT))\n // Also dispatch popstate for React Router and other libraries that listen to it\n window.dispatchEvent(new PopStateEvent('popstate', { state }))\n }\n}\n\n// Patch on module load\npatchHistoryApi()\n\n/**\n * Query string location strategy\n * Reads/writes to window.location.search\n */\nexport const queryStrategy: LocationStrategy = {\n getRaw(): string {\n if (typeof window === 'undefined') return ''\n return window.location.search\n },\n\n parse(): Record<string, MultiEncoded> {\n if (typeof window === 'undefined') return {}\n return parseMultiParams(window.location.search)\n },\n\n buildUrl(base: URL, params: Record<string, MultiEncoded>): string {\n base.search = serializeMultiParams(params)\n return base.toString()\n },\n\n subscribe(callback: () => void): () => void {\n if (typeof window === 'undefined') return () => {}\n window.addEventListener('popstate', callback)\n window.addEventListener(LOCATION_CHANGE_EVENT, callback)\n return () => {\n window.removeEventListener('popstate', callback)\n window.removeEventListener(LOCATION_CHANGE_EVENT, callback)\n }\n },\n}\n\n/**\n * Hash fragment location strategy\n * Reads/writes to window.location.hash\n * Hash is parsed as URLSearchParams format: #key=value&key2=value2\n */\nexport const hashStrategy: LocationStrategy = {\n getRaw(): string {\n if (typeof window === 'undefined') return ''\n return window.location.hash\n },\n\n parse(): Record<string, MultiEncoded> {\n if (typeof window === 'undefined') return {}\n const hash = window.location.hash\n // Remove leading # if present\n const hashString = hash.startsWith('#') ? hash.slice(1) : hash\n return parseMultiParams(hashString)\n },\n\n buildUrl(base: URL, params: Record<string, MultiEncoded>): string {\n base.hash = serializeMultiParams(params)\n return base.toString()\n },\n\n subscribe(callback: () => void): () => void {\n if (typeof window === 'undefined') return () => {}\n // Listen to hashchange, popstate, and our custom event for all navigation types\n window.addEventListener('hashchange', callback)\n window.addEventListener('popstate', callback)\n window.addEventListener(LOCATION_CHANGE_EVENT, callback)\n return () => {\n window.removeEventListener('hashchange', callback)\n window.removeEventListener('popstate', callback)\n window.removeEventListener(LOCATION_CHANGE_EVENT, callback)\n }\n },\n}\n\n/**\n * Notify all use-prms hooks that the URL has changed.\n * Note: With the History API patch, this is rarely needed since pushState/replaceState\n * automatically trigger notifications. Use this for edge cases like direct location assignment.\n */\nexport function notifyLocationChange(): void {\n if (typeof window === 'undefined') return\n window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT))\n}\n\n/**\n * Clear all URL params.\n * @param strategy - Which location to clear (query or hash), defaults to query\n */\nexport function clearParams(strategy: 'query' | 'hash' = 'query'): void {\n if (typeof window === 'undefined') return\n const url = new URL(window.location.href)\n if (strategy === 'hash') {\n url.hash = ''\n } else {\n url.search = ''\n }\n // replaceState triggers our custom event automatically via the patch\n window.history.replaceState({}, '', url.toString())\n}\n\n// Default strategy (can be changed by entry points like hash.ts)\nlet defaultStrategy: LocationStrategy = queryStrategy\n\n/**\n * Get the current default location strategy\n */\nexport function getDefaultStrategy(): LocationStrategy {\n return defaultStrategy\n}\n\n/**\n * Set the default location strategy\n * Called by entry points (e.g., hash.ts sets this to hashStrategy)\n */\nexport function setDefaultStrategy(strategy: LocationStrategy): void {\n defaultStrategy = strategy\n}\n","/**\n * Built-in parameter types with smart defaults and minimal encoding\n */\n\nimport type { Encoded, Param } from './index.js'\n\n/**\n * Optional string parameter.\n * - undefined → not present\n * - empty string → ?key=\n * - non-empty → ?key=value\n */\nexport function stringParam(init?: string): Param<string | undefined> {\n return {\n encode: (value) => value === init ? undefined : value,\n decode: (encoded) => encoded === undefined ? init : encoded,\n }\n}\n\n/**\n * Required string parameter with default.\n * Omitted from URL when equal to default.\n */\nexport function defStringParam(init: string): Param<string> {\n return {\n encode: (value) => value === init ? undefined : value,\n decode: (encoded) => encoded ?? init,\n }\n}\n\n/**\n * Boolean parameter.\n * - true → ?key (valueless)\n * - false → not present\n */\nexport const boolParam: Param<boolean> = {\n encode: (value) => value ? '' : undefined,\n decode: (encoded) => encoded !== undefined,\n}\n\n/**\n * Integer parameter with default.\n * Omitted from URL when equal to default.\n */\nexport function intParam(init: number): Param<number> {\n return {\n encode: (value) => value === init ? undefined : value.toString(),\n decode: (encoded) => {\n if (encoded === undefined || encoded === '') return init\n const parsed = parseInt(encoded, 10)\n return isNaN(parsed) ? init : parsed\n },\n }\n}\n\n/**\n * Optional integer parameter.\n * - null → not present\n * - number → ?key=123\n */\nexport const optIntParam: Param<number | null> = {\n encode: (value) => value === null ? undefined : value.toString(),\n decode: (encoded) => {\n if (encoded === undefined || encoded === '') return null\n const parsed = parseInt(encoded, 10)\n return isNaN(parsed) ? null : parsed\n },\n}\n\n/**\n * Float parameter with default.\n * Omitted from URL when equal to default.\n */\nexport function floatParam(init: number): Param<number> {\n return {\n encode: (value) => value === init ? undefined : value.toString(),\n decode: (encoded) => {\n if (encoded === undefined || encoded === '') return init\n const parsed = parseFloat(encoded)\n return isNaN(parsed) ? init : parsed\n },\n }\n}\n\n/**\n * Enum parameter with validation.\n * Omitted from URL when equal to default.\n * Invalid values fall back to default with console warning.\n */\nexport function enumParam<T extends string>(\n init: T,\n values: readonly T[]\n): Param<T> {\n const validSet = new Set(values)\n\n return {\n encode: (value) => {\n if (!validSet.has(value)) {\n console.warn(`Invalid enum value: ${value}, expected one of ${values.join(', ')}`)\n return undefined\n }\n return value === init ? undefined : value\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n if (!validSet.has(encoded as T)) {\n console.warn(`Invalid enum value: ${encoded}, expected one of ${values.join(', ')}. Using default: ${init}`)\n return init\n }\n return encoded as T\n },\n }\n}\n\n/**\n * String array parameter with delimiter.\n * Omitted from URL when equal to default.\n * Empty array encodes as empty string (?key=)\n */\nexport function stringsParam(\n init: string[] = [],\n delimiter = ' '\n): Param<string[]> {\n const initEncoded = init.join(delimiter)\n\n return {\n encode: (values) => {\n const encoded = values.join(delimiter)\n if (encoded === initEncoded) return undefined\n return encoded\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n if (encoded === '') return []\n return encoded.split(delimiter)\n },\n }\n}\n\n/**\n * Number array parameter.\n * Omitted from URL when equal to default.\n * Uses comma delimiter.\n */\nexport function numberArrayParam(init: number[] = []): Param<number[]> {\n const isEqual = (a: number[], b: number[]) =>\n a.length === b.length && a.every((v, i) => v === b[i])\n\n return {\n encode: (values) => {\n if (isEqual(values, init)) return undefined\n return values.map(v => v.toString()).join(',')\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n if (encoded === '') return []\n return encoded.split(',').map(v => parseFloat(v))\n },\n }\n}\n\n/**\n * Pagination parameter combining offset and page size.\n * Uses space (which encodes as + in URLs) as delimiter.\n *\n * Encoding rules:\n * - offset=0, pageSize=default → not present (undefined)\n * - offset=0, pageSize=custom → \" pageSize\" (e.g., \" 20\" → +20 in URL)\n * - offset>0, pageSize=default → \"offset\" (e.g., \"100\")\n * - offset>0, pageSize=custom → \"offset pageSize\" (e.g., \"100 20\" → 100+20 in URL)\n *\n * @param defaultPageSize - The default page size (omitted from URL when used)\n * @param validPageSizes - Optional array of valid page sizes for validation\n */\nexport type Pagination = { offset: number; pageSize: number }\n\nexport function paginationParam(\n defaultPageSize: number,\n validPageSizes?: readonly number[],\n): Param<Pagination> {\n return {\n encode: ({ offset, pageSize }) => {\n if (offset === 0 && pageSize === defaultPageSize) return undefined\n if (offset === 0) return ` ${pageSize}` // Space prefix → +pageSize in URL\n if (pageSize === defaultPageSize) return String(offset)\n return `${offset} ${pageSize}` // Space encodes as + in URL\n },\n decode: (encoded) => {\n if (!encoded) return { offset: 0, pageSize: defaultPageSize }\n const parts = encoded.split(' ') // URL + decodes to space\n // Handle \" pageSize\" case (offset 0 with custom page size)\n const offset = parts[0] === '' ? 0 : parseInt(parts[0], 10) || 0\n let pageSize = parts[1] ? parseInt(parts[1], 10) : defaultPageSize\n // Validate page size if validation array provided\n if (validPageSizes && !validPageSizes.includes(pageSize)) {\n pageSize = defaultPageSize\n }\n return { offset, pageSize }\n },\n }\n}\n\n/**\n * Code mapping for enum values - maps full values to short codes for compact URLs.\n * Can be specified as:\n * - Array of [value, code] tuples: [['Rides', 'r'], ['Minutes', 'm']]\n * - Object mapping values to codes: { Rides: 'r', Minutes: 'm' }\n */\nexport type CodeMap<T extends string> = [T, string][] | Record<T, string>\n\nfunction normalizeCodeMap<T extends string>(codeMap: CodeMap<T>): [T, string][] {\n if (Array.isArray(codeMap)) return codeMap\n return Object.entries(codeMap) as [T, string][]\n}\n\n/**\n * Single-value enum parameter with short code mapping.\n * Maps full enum values to abbreviated codes for compact URLs.\n * Omitted from URL when equal to default.\n *\n * @example\n * // ?y=r for \"Rides\", ?y=m for \"Minutes\", omitted for default \"Rides\"\n * codeParam('Rides', [['Rides', 'r'], ['Minutes', 'm']])\n * // or with object syntax:\n * codeParam('Rides', { Rides: 'r', Minutes: 'm' })\n */\nexport function codeParam<T extends string>(\n init: T,\n codeMap: CodeMap<T>,\n): Param<T> {\n const entries = normalizeCodeMap(codeMap)\n const valueToCode = new Map(entries)\n const codeToValue = new Map(entries.map(([v, c]) => [c, v]))\n\n return {\n encode: (value) => {\n if (value === init) return undefined\n return valueToCode.get(value) ?? value\n },\n decode: (encoded) => {\n if (encoded === undefined) return init\n return codeToValue.get(encoded) ?? init\n },\n }\n}\n\n/**\n * Multi-value parameter with short code mapping.\n * Maps full values to abbreviated codes for compact URLs.\n * Omitted from URL when all values are selected.\n *\n * @param allValues - Array of all possible values (used to detect \"all selected\")\n * @param codeMap - Mapping from values to short codes\n * @param separator - Delimiter between codes (default: '' for most compact URLs)\n *\n * @example\n * // Regions: ?r=nj for NYC+JC, ?r=njh or omitted for all three\n * codesParam(['NYC', 'JC', 'HOB'], [['NYC', 'n'], ['JC', 'j'], ['HOB', 'h']])\n * // or with object syntax and custom separator:\n * codesParam(['NYC', 'JC', 'HOB'], { NYC: 'n', JC: 'j', HOB: 'h' }, ',')\n */\nexport function codesParam<T extends string>(\n allValues: readonly T[],\n codeMap: CodeMap<T>,\n separator: string = '',\n): Param<T[]> {\n const entries = normalizeCodeMap(codeMap)\n const valueToCode = new Map(entries)\n const codeToValue = new Map(entries.map(([v, c]) => [c, v]))\n\n return {\n encode: (values) => {\n // Omit when all values selected\n if (values.length === allValues.length && allValues.every(v => values.includes(v))) {\n return undefined\n }\n return values.map(v => valueToCode.get(v) ?? v).join(separator)\n },\n decode: (encoded) => {\n if (encoded === undefined) return [...allValues]\n if (encoded === '') return []\n const codes = separator ? encoded.split(separator) : encoded.split('')\n return codes.map(c => codeToValue.get(c)).filter((v): v is T => v !== undefined)\n },\n }\n}\n","/**\n * Multi-value parameter types for handling repeated URL params\n * e.g., ?tag=a&tag=b&tag=c\n */\n\nimport type { MultiEncoded } from './core.js'\n\n/**\n * A bidirectional converter between a typed value and its multi-value URL representation.\n * Similar to Param<T> but works with string[] instead of string | undefined.\n */\nexport type MultiParam<T> = {\n encode: (value: T) => MultiEncoded\n decode: (encoded: MultiEncoded) => T\n}\n\n/**\n * Multi-value string array parameter.\n * Each string becomes a separate URL param with the same key.\n *\n * @example\n * // ?tag=a&tag=b&tag=c → ['a', 'b', 'c']\n * const [tags, setTags] = useMultiUrlParam('tag', multiStringParam())\n */\nexport function multiStringParam(init: string[] = []): MultiParam<string[]> {\n return {\n encode: (values) => {\n if (values.length === 0 && init.length === 0) return []\n if (arraysEqual(values, init)) return []\n return values\n },\n decode: (encoded) => {\n if (encoded.length === 0) return init\n return encoded\n },\n }\n}\n\n/**\n * Multi-value integer array parameter.\n * Each number becomes a separate URL param with the same key.\n *\n * @example\n * // ?id=1&id=2&id=3 → [1, 2, 3]\n * const [ids, setIds] = useMultiUrlParam('id', multiIntParam())\n */\nexport function multiIntParam(init: number[] = []): MultiParam<number[]> {\n return {\n encode: (values) => {\n if (values.length === 0 && init.length === 0) return []\n if (arraysEqual(values, init)) return []\n return values.map(v => v.toString())\n },\n decode: (encoded) => {\n if (encoded.length === 0) return init\n return encoded.map(v => parseInt(v, 10))\n },\n }\n}\n\n/**\n * Multi-value float array parameter.\n * Each number becomes a separate URL param with the same key.\n *\n * @example\n * // ?val=1.5&val=2.7 → [1.5, 2.7]\n * const [vals, setVals] = useMultiUrlParam('val', multiFloatParam())\n */\nexport function multiFloatParam(init: number[] = []): MultiParam<number[]> {\n return {\n encode: (values) => {\n if (values.length === 0 && init.length === 0) return []\n if (arraysEqual(values, init)) return []\n return values.map(v => v.toString())\n },\n decode: (encoded) => {\n if (encoded.length === 0) return init\n return encoded.map(v => parseFloat(v))\n },\n }\n}\n\n/** Helper to compare arrays for equality */\nfunction arraysEqual<T>(a: T[], b: T[]): boolean {\n return a.length === b.length && a.every((v, i) => v === b[i])\n}\n","/**\n * React hooks for managing URL parameters\n */\n\nimport { useCallback, useRef, useSyncExternalStore } from 'react'\nimport type { Param } from './index.js'\nimport type { LocationStrategy, MultiEncoded } from './core.js'\nimport { getDefaultStrategy, serializeMultiParams } from './core.js'\nimport type { MultiParam } from './multiParams.js'\n\n/**\n * Cached snapshot to prevent infinite loops in useSyncExternalStore\n * Keyed by strategy (so query and hash don't share cache)\n */\nconst snapshotCache = new WeakMap<LocationStrategy, {\n raw: string\n snapshot: Record<string, MultiEncoded>\n}>()\n\n/**\n * Get URL snapshot for a given strategy\n * Returns cached snapshot if URL hasn't changed\n */\nfunction getSnapshot(strategy: LocationStrategy): Record<string, MultiEncoded> {\n const raw = strategy.getRaw()\n const cached = snapshotCache.get(strategy)\n\n if (cached && cached.raw === raw) {\n return cached.snapshot\n }\n\n const snapshot = strategy.parse()\n snapshotCache.set(strategy, { raw, snapshot })\n return snapshot\n}\n\n/**\n * Server-side snapshot (always empty)\n */\nfunction getServerSnapshot(): Record<string, MultiEncoded> {\n return {}\n}\n\n/**\n * Convert single-value Encoded to multi-value MultiEncoded\n */\nfunction singleToMulti(encoded: string | undefined): MultiEncoded {\n if (encoded === undefined) return []\n return [encoded]\n}\n\n/**\n * Convert multi-value MultiEncoded to single-value Encoded\n */\nfunction multiToSingle(multi: MultiEncoded): string | undefined {\n if (multi.length === 0) return undefined\n return multi[0]\n}\n\n/**\n * React hook for managing a single URL query parameter.\n *\n * @param key - Query parameter key\n * @param param - Param encoder/decoder\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Tuple of [value, setValue]\n *\n * @example\n * ```tsx\n * const [zoom, setZoom] = useUrlParam('z', boolParam)\n * const [device, setDevice] = useUrlParam('d', stringParam('default'))\n * ```\n */\nexport function useUrlParam<T>(\n key: string,\n param: Param<T>,\n push = false\n): [T, (value: T) => void] {\n const strategy = getDefaultStrategy()\n\n // Use ref to avoid recreating setValue when param changes\n const paramRef = useRef(param)\n paramRef.current = param\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Memoize decoded value based on encoded string AND param identity\n // Re-decode if either the URL param string changes OR the param object changes\n // (e.g., deviceIdsParam depends on devices array which loads asynchronously)\n const encoded = multiToSingle(urlParams[key] ?? [])\n const cacheRef = useRef<{ encoded: typeof encoded; param: Param<T>; decoded: T } | null>(null)\n\n if (cacheRef.current === null || cacheRef.current.encoded !== encoded || cacheRef.current.param !== param) {\n cacheRef.current = { encoded, param, decoded: param.decode(encoded) }\n }\n const value = cacheRef.current.decoded\n\n // Update URL when value changes\n const setValue = useCallback(\n (newValue: T) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n const encoded = paramRef.current.encode(newValue)\n\n // Update this parameter (single → multi)\n if (encoded === undefined) {\n delete currentParams[key]\n } else {\n currentParams[key] = [encoded]\n }\n\n // Build and update URL\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [key, push, strategy]\n )\n\n return [value, setValue]\n}\n\n/**\n * React hook for managing multiple URL query parameters together.\n * Updates are batched into a single history entry.\n *\n * @param params - Object mapping keys to Param types\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Object with decoded values and update function\n *\n * @example\n * ```tsx\n * const { values, setValues } = useUrlParams({\n * zoom: boolParam,\n * device: stringParam('default'),\n * count: intParam(10)\n * })\n *\n * // Update multiple params at once\n * setValues({ zoom: true, count: 20 })\n * ```\n */\nexport function useUrlParams<P extends Record<string, Param<any>>>(\n params: P,\n push = false\n): {\n values: { [K in keyof P]: P[K] extends Param<infer T> ? T : never }\n setValues: (updates: Partial<{ [K in keyof P]: P[K] extends Param<infer T> ? T : never }>) => void\n} {\n const strategy = getDefaultStrategy()\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Decode all values from URL\n const values = Object.fromEntries(\n Object.entries(params).map(([key, param]) => [\n key,\n param.decode(multiToSingle(urlParams[key] ?? []))\n ])\n ) as { [K in keyof P]: P[K] extends Param<infer T> ? T : never }\n\n // Update multiple parameters at once\n const setValues = useCallback(\n (updates: Partial<{ [K in keyof P]: P[K] extends Param<infer T> ? T : never }>) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n\n // Apply all updates\n for (const [key, value] of Object.entries(updates)) {\n const param = params[key]\n if (!param) continue\n\n const encoded = param.encode(value)\n if (encoded === undefined) {\n delete currentParams[key]\n } else {\n currentParams[key] = [encoded]\n }\n }\n\n // Build and update URL once\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [params, push, strategy]\n )\n\n return { values, setValues }\n}\n\n/**\n * React hook for managing a single multi-value URL parameter.\n * Supports repeated params like ?tag=a&tag=b&tag=c\n *\n * @param key - Query parameter key\n * @param param - MultiParam encoder/decoder\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Tuple of [value, setValue]\n *\n * @example\n * ```tsx\n * const [tags, setTags] = useMultiUrlParam('tag', multiStringParam())\n * // URL: ?tag=a&tag=b → tags = ['a', 'b']\n * ```\n */\nexport function useMultiUrlParam<T>(\n key: string,\n param: MultiParam<T>,\n push = false\n): [T, (value: T) => void] {\n const strategy = getDefaultStrategy()\n\n // Use ref to avoid recreating setValue when param changes\n const paramRef = useRef(param)\n paramRef.current = param\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Decode current value from URL\n const value = param.decode(urlParams[key] ?? [])\n\n // Update URL when value changes\n const setValue = useCallback(\n (newValue: T) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n const encoded = paramRef.current.encode(newValue)\n\n // Update this parameter\n if (encoded.length === 0) {\n delete currentParams[key]\n } else {\n currentParams[key] = encoded\n }\n\n // Build and update URL\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [key, push, strategy]\n )\n\n return [value, setValue]\n}\n\n/**\n * React hook for managing multiple multi-value URL parameters together.\n * Updates are batched into a single history entry.\n *\n * @param params - Object mapping keys to MultiParam types\n * @param push - Use pushState (true) or replaceState (false) when updating\n * @returns Object with decoded values and update function\n *\n * @example\n * ```tsx\n * const { values, setValues } = useMultiUrlParams({\n * tags: multiStringParam(),\n * ids: multiIntParam()\n * })\n *\n * // Update multiple multi-value params at once\n * setValues({ tags: ['a', 'b'], ids: [1, 2, 3] })\n * ```\n */\nexport function useMultiUrlParams<P extends Record<string, MultiParam<any>>>(\n params: P,\n push = false\n): {\n values: { [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }\n setValues: (updates: Partial<{ [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }>) => void\n} {\n const strategy = getDefaultStrategy()\n\n // Subscribe to URL changes\n const urlParams = useSyncExternalStore(\n (cb) => strategy.subscribe(cb),\n () => getSnapshot(strategy),\n getServerSnapshot\n )\n\n // Decode all values from URL\n const values = Object.fromEntries(\n Object.entries(params).map(([key, param]) => [\n key,\n param.decode(urlParams[key] ?? [])\n ])\n ) as { [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }\n\n // Update multiple parameters at once\n const setValues = useCallback(\n (updates: Partial<{ [K in keyof P]: P[K] extends MultiParam<infer T> ? T : never }>) => {\n if (typeof window === 'undefined') return\n\n const currentParams = strategy.parse()\n\n // Apply all updates\n for (const [key, value] of Object.entries(updates)) {\n const param = params[key]\n if (!param) continue\n\n const encoded = param.encode(value)\n if (encoded.length === 0) {\n delete currentParams[key]\n } else {\n currentParams[key] = encoded\n }\n }\n\n // Build and update URL once\n const url = new URL(window.location.href)\n const newUrl = strategy.buildUrl(url, currentParams)\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', newUrl)\n\n // Trigger events to notify other hooks\n window.dispatchEvent(new PopStateEvent('popstate'))\n },\n [params, push, strategy]\n )\n\n return { values, setValues }\n}\n","/**\n * Core types and utilities for URL parameter management\n */\n\n// Re-export core types and strategies\nexport type { MultiEncoded, LocationStrategy } from './core.js'\nexport {\n parseMultiParams,\n serializeMultiParams,\n queryStrategy,\n hashStrategy,\n getDefaultStrategy,\n setDefaultStrategy,\n notifyLocationChange,\n clearParams,\n} from './core.js'\n\n/**\n * Encodes a value to a URL query parameter string.\n * - undefined: parameter not present in URL\n * - \"\": valueless parameter (e.g., ?z)\n * - string: parameter with value (e.g., ?z=foo)\n */\nexport type Encoded = string | undefined\n\n/**\n * A bidirectional converter between a typed value and its URL representation.\n */\nexport type Param<T> = {\n encode: (value: T) => Encoded\n decode: (encoded: Encoded) => T\n}\n\n/**\n * Serialize query parameters to URL string.\n * Uses URLSearchParams for proper form-urlencoded format (space → +)\n * Handles valueless params (empty string → ?key without =) manually\n *\n * @deprecated For multi-value support, use serializeMultiParams instead\n */\nexport function serializeParams(params: Record<string, Encoded>): string {\n const searchParams = new URLSearchParams()\n\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined) {\n // Skip undefined values\n continue\n } else if (value === '') {\n // Valueless param: ?key without =\n // URLSearchParams doesn't support this, so we'll handle manually\n continue\n } else {\n searchParams.set(key, value)\n }\n }\n\n let result = searchParams.toString()\n\n // Handle valueless params manually\n const valuelessKeys = Object.entries(params)\n .filter(([_, value]) => value === '')\n .map(([key, _]) => encodeURIComponent(key))\n\n if (valuelessKeys.length > 0) {\n const valuelessPart = valuelessKeys.join('&')\n result = result ? `${result}&${valuelessPart}` : valuelessPart\n }\n\n return result\n}\n\n/**\n * Parse query parameters from URL string or URLSearchParams.\n * Note: URLSearchParams treats ?z and ?z= identically (both as empty string).\n * Note: For repeated params, only the first value is returned.\n *\n * @deprecated For multi-value support, use parseMultiParams instead\n */\nexport function parseParams(source: string | URLSearchParams): Record<string, Encoded> {\n const searchParams = typeof source === 'string'\n ? new URLSearchParams(source)\n : source\n\n const result: Record<string, Encoded> = {}\n\n for (const [key, value] of searchParams.entries()) {\n // Only take first value for each key (backward compat)\n if (!(key in result)) {\n result[key] = value\n }\n }\n\n return result\n}\n\n/**\n * Get current URL query parameters (browser only)\n */\nexport function getCurrentParams(): Record<string, Encoded> {\n if (typeof window === 'undefined') return {}\n return parseParams(window.location.search)\n}\n\n/**\n * Update URL without reloading (browser only)\n * @param params - New query parameters\n * @param push - Use pushState (true) or replaceState (false)\n */\nexport function updateUrl(params: Record<string, Encoded>, push = false): void {\n if (typeof window === 'undefined') return\n\n const url = new URL(window.location.href)\n const search = serializeParams(params)\n url.search = search\n\n const method = push ? 'pushState' : 'replaceState'\n window.history[method]({}, '', url.toString())\n}\n\nexport * from './params.js'\nexport * from './multiParams.js'\nexport * from './useUrlParam.js'\n","/**\n * Hash params entry point\n *\n * This module sets the default location strategy to hash (window.location.hash)\n * and re-exports everything from the main module.\n *\n * Usage:\n * ```typescript\n * // Instead of:\n * import { useUrlParam, stringParam } from 'use-prms'\n *\n * // Use:\n * import { useUrlParam, stringParam } from 'use-prms/hash'\n *\n * // Same API, but reads/writes to URL hash instead of query string\n * // e.g., #name=foo instead of ?name=foo\n * ```\n */\n\nimport { setDefaultStrategy, hashStrategy } from './core.js'\n\n// Set hash as the default strategy for this entry point\nsetDefaultStrategy(hashStrategy)\n\n// Re-export everything from main module\nexport * from './index.js'\n"]}
package/dist/index.cjs CHANGED
@@ -30,6 +30,25 @@ function serializeMultiParams(params) {
30
30
  }
31
31
  return result;
32
32
  }
33
+ var LOCATION_CHANGE_EVENT = "use-prms:locationchange";
34
+ var historyPatched = false;
35
+ function patchHistoryApi() {
36
+ if (typeof window === "undefined" || historyPatched) return;
37
+ historyPatched = true;
38
+ const originalPushState = history.pushState.bind(history);
39
+ const originalReplaceState = history.replaceState.bind(history);
40
+ history.pushState = function(state, title, url) {
41
+ originalPushState(state, title, url);
42
+ window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT));
43
+ window.dispatchEvent(new PopStateEvent("popstate", { state }));
44
+ };
45
+ history.replaceState = function(state, title, url) {
46
+ originalReplaceState(state, title, url);
47
+ window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT));
48
+ window.dispatchEvent(new PopStateEvent("popstate", { state }));
49
+ };
50
+ }
51
+ patchHistoryApi();
33
52
  var queryStrategy = {
34
53
  getRaw() {
35
54
  if (typeof window === "undefined") return "";
@@ -47,7 +66,11 @@ var queryStrategy = {
47
66
  if (typeof window === "undefined") return () => {
48
67
  };
49
68
  window.addEventListener("popstate", callback);
50
- return () => window.removeEventListener("popstate", callback);
69
+ window.addEventListener(LOCATION_CHANGE_EVENT, callback);
70
+ return () => {
71
+ window.removeEventListener("popstate", callback);
72
+ window.removeEventListener(LOCATION_CHANGE_EVENT, callback);
73
+ };
51
74
  }
52
75
  };
53
76
  var hashStrategy = {
@@ -70,12 +93,28 @@ var hashStrategy = {
70
93
  };
71
94
  window.addEventListener("hashchange", callback);
72
95
  window.addEventListener("popstate", callback);
96
+ window.addEventListener(LOCATION_CHANGE_EVENT, callback);
73
97
  return () => {
74
98
  window.removeEventListener("hashchange", callback);
75
99
  window.removeEventListener("popstate", callback);
100
+ window.removeEventListener(LOCATION_CHANGE_EVENT, callback);
76
101
  };
77
102
  }
78
103
  };
104
+ function notifyLocationChange() {
105
+ if (typeof window === "undefined") return;
106
+ window.dispatchEvent(new CustomEvent(LOCATION_CHANGE_EVENT));
107
+ }
108
+ function clearParams(strategy = "query") {
109
+ if (typeof window === "undefined") return;
110
+ const url = new URL(window.location.href);
111
+ if (strategy === "hash") {
112
+ url.hash = "";
113
+ } else {
114
+ url.search = "";
115
+ }
116
+ window.history.replaceState({}, "", url.toString());
117
+ }
79
118
  var defaultStrategy = queryStrategy;
80
119
  function getDefaultStrategy() {
81
120
  return defaultStrategy;
@@ -104,17 +143,29 @@ var boolParam = {
104
143
  function intParam(init) {
105
144
  return {
106
145
  encode: (value) => value === init ? void 0 : value.toString(),
107
- decode: (encoded) => encoded !== void 0 ? parseInt(encoded, 10) : init
146
+ decode: (encoded) => {
147
+ if (encoded === void 0 || encoded === "") return init;
148
+ const parsed = parseInt(encoded, 10);
149
+ return isNaN(parsed) ? init : parsed;
150
+ }
108
151
  };
109
152
  }
110
153
  var optIntParam = {
111
154
  encode: (value) => value === null ? void 0 : value.toString(),
112
- decode: (encoded) => encoded !== void 0 ? parseInt(encoded, 10) : null
155
+ decode: (encoded) => {
156
+ if (encoded === void 0 || encoded === "") return null;
157
+ const parsed = parseInt(encoded, 10);
158
+ return isNaN(parsed) ? null : parsed;
159
+ }
113
160
  };
114
161
  function floatParam(init) {
115
162
  return {
116
163
  encode: (value) => value === init ? void 0 : value.toString(),
117
- decode: (encoded) => encoded !== void 0 ? parseFloat(encoded) : init
164
+ decode: (encoded) => {
165
+ if (encoded === void 0 || encoded === "") return init;
166
+ const parsed = parseFloat(encoded);
167
+ return isNaN(parsed) ? init : parsed;
168
+ }
118
169
  };
119
170
  }
120
171
  function enumParam(init, values) {
@@ -470,6 +521,7 @@ function updateUrl(params, push = false) {
470
521
  }
471
522
 
472
523
  exports.boolParam = boolParam;
524
+ exports.clearParams = clearParams;
473
525
  exports.codeParam = codeParam;
474
526
  exports.codesParam = codesParam;
475
527
  exports.defStringParam = defStringParam;
@@ -482,6 +534,7 @@ exports.intParam = intParam;
482
534
  exports.multiFloatParam = multiFloatParam;
483
535
  exports.multiIntParam = multiIntParam;
484
536
  exports.multiStringParam = multiStringParam;
537
+ exports.notifyLocationChange = notifyLocationChange;
485
538
  exports.numberArrayParam = numberArrayParam;
486
539
  exports.optIntParam = optIntParam;
487
540
  exports.paginationParam = paginationParam;