{"version":3,"file":"useQueryParam-0c12ba73.js","sources":["../../../app/javascript/shared/helper/serializer/IdentitySerializer.ts","../../../app/javascript/shared/hooks/useUpdatedRef.ts","../../../app/javascript/shared/hooks/useQueryParam.ts"],"sourcesContent":["import { Serializer } from 'shared/helper/serializer/Serializer'\n\nexport default class IdentitySerializer implements Serializer {\n deserialize(raw: string): T {\n return raw as unknown as T\n }\n\n serialize(value: T): string {\n return value as unknown as string\n }\n}\n","import { MutableRefObject, useRef } from 'react'\n\nexport default function useUpdatedRef(value: T): MutableRefObject {\n const ref = useRef(value)\n ref.current = value\n return ref\n}\n","import { useCallback, useMemo } from 'react'\nimport { isArray, isEmpty, isEqual } from 'lodash'\nimport { navigate, useLocation } from '@reach/router'\n\nimport { Serializer } from 'shared/helper/serializer/Serializer'\nimport IdentitySerializer from 'shared/helper/serializer/IdentitySerializer'\nimport { Maybe } from 'shared/util/types.util'\nimport useUpdatedRef from 'shared/hooks/useUpdatedRef'\n\nexport interface Options {\n serializer?: Serializer\n beforeNavigate?: (queryParams: URLSearchParams) => void\n}\n\nexport type QueryParamResult = [T, (value?: S) => void]\n\n// The identity serializer is a no-op and just passed through its argument, thus any is appropriate\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst identitySerializer = new IdentitySerializer()\n\n/**\n * React hook which makes a URL query parameter available for consumption. The API is very similar to React's\n * `useState()`.\n *\n * Example:\n *\n * ```tsx\n * export default function MyComponent() {\n * const [value, setValue] = useQueryParam('foo', '')\n * return \n * }\n * ```\n *\n * @param name The name of the query parameter to synchronize on\n * @param defaultValue The default value to return if the query parameter is not present\n * @param serializer An optional object to turn non-string `T`s into strings which can be stored\n * in the URL (and back again). Make sure to pass a memoized instance.\n * @param beforeNavigate A function called before navigating to the new URL.\n * Useful for modifying the URL to navigate to.\n * @return [QueryParamResult] Returns an array with two items:\n *\n * - The first item (of type `T`) is the current value of the query parameter (or the default\n * value if the query parameter is not present)\n * - The second item is a setter function. Call it with a new value (of type `T` or `undefined`) to\n * change the query parameter.\n */\nexport default function useQueryParam(\n name: string,\n defaultValue: T,\n { serializer = identitySerializer, beforeNavigate }: Options = {},\n): QueryParamResult {\n const location = useLocation()\n const queryParams = new URLSearchParams(location.search)\n\n // We use refs here to avoid having to invalidate the callback when the serializer instance changes.\n const serializerRef = useUpdatedRef>(serializer)\n const beforeNavigateRef = useUpdatedRef(beforeNavigate)\n\n const setValue = useCallback((value?: T) => {\n const newQueryParams = new URLSearchParams(window.location.search)\n setQueryParam(newQueryParams, name, value, defaultValue, serializerRef.current)\n beforeNavigateRef.current?.(newQueryParams)\n navigateToQueryString(window.location, newQueryParams)\n }, [name, defaultValue])\n\n const currentParam = queryParams.get(name)\n const currentValue = useMemo(\n () => (currentParam ? serializer.deserialize(currentParam) : undefined),\n [currentParam, serializer],\n )\n\n return [currentValue ?? defaultValue, setValue]\n}\n\nfunction shouldParamBeSet(value: T, defaultValue: T): boolean {\n if (value == null) return false\n if (isArray(value)) {\n if (isEmpty(value)) return false\n if (isEqual(value, defaultValue)) return false\n }\n\n return value !== defaultValue\n}\n\ninterface NavigateToQueryStringParams {\n beforeNavigate?: (qp: URLSearchParams) => void\n replace?: boolean\n}\n\nexport function buildUrlSuffix(currentLocation: Location, queryParams: URLSearchParams): string {\n return `${currentLocation.pathname}${formatQueryString(queryParams)}${currentLocation.hash}`\n}\n\nexport function navigateToQueryString(\n currentLocation: Location,\n queryParams: URLSearchParams,\n { beforeNavigate, replace }: NavigateToQueryStringParams = { replace: false },\n): void {\n if (currentLocation.search !== formatQueryString(queryParams)) {\n beforeNavigate?.(queryParams)\n navigate(buildUrlSuffix(currentLocation, queryParams), { replace })\n }\n}\n\nexport function setQueryParam(\n queryParams: URLSearchParams,\n name: string,\n value: Maybe,\n defaultValue: T,\n serializer: Serializer,\n): void {\n if (value != null && shouldParamBeSet(value, defaultValue)) {\n queryParams.set(name, serializer.serialize(value))\n } else {\n queryParams.delete(name)\n }\n}\n\nfunction formatQueryString(queryString: URLSearchParams): string {\n const stringRepresentation = queryString.toString()\n return stringRepresentation ? `?${stringRepresentation}` : ''\n}\n"],"names":["IdentitySerializer","raw","value","useUpdatedRef","ref","useRef","identitySerializer","useQueryParam","name","defaultValue","serializer","beforeNavigate","location","useLocation","queryParams","serializerRef","beforeNavigateRef","setValue","useCallback","newQueryParams","setQueryParam","_a","navigateToQueryString","currentParam","useMemo","shouldParamBeSet","isArray","isEmpty","isEqual","buildUrlSuffix","currentLocation","formatQueryString","replace","navigate","queryString","stringRepresentation"],"mappings":"wIAEA,MAAqBA,CAA+C,CAClE,YAAYC,EAAgB,CACnB,OAAAA,CACT,CAEA,UAAUC,EAAkB,CACnB,OAAAA,CACT,CACF,CCRA,SAAwBC,EAAiBD,EAA+B,CAChE,MAAAE,EAAMC,SAAUH,CAAK,EAC3B,OAAAE,EAAI,QAAUF,EACPE,CACT,CCYA,MAAME,EAAqB,IAAIN,EA4BP,SAAAO,EACtBC,EACAC,EACA,CAAE,WAAAC,EAAaJ,EAAoB,eAAAK,CAA+B,EAAA,GAC7C,CACrB,MAAMC,EAAWC,IACXC,EAAc,IAAI,gBAAgBF,EAAS,MAAM,EAGjDG,EAAgBZ,EAA6BO,CAAU,EACvDM,EAAoBb,EAAcQ,CAAc,EAEhDM,EAAWC,cAAahB,GAAc,OAC1C,MAAMiB,EAAiB,IAAI,gBAAgB,OAAO,SAAS,MAAM,EACjEC,EAAcD,EAAgBX,EAAMN,EAAOO,EAAcM,EAAc,OAAO,GAC9EM,EAAAL,EAAkB,UAAlB,MAAAK,EAAA,KAAAL,EAA4BG,GACNG,EAAA,OAAO,SAAUH,CAAc,CAAA,EACpD,CAACX,EAAMC,CAAY,CAAC,EAEjBc,EAAeT,EAAY,IAAIN,CAAI,EAMlC,MAAA,CALcgB,EAAA,QACnB,IAAOD,EAAeb,EAAW,YAAYa,CAAY,EAAI,OAC7D,CAACA,EAAcb,CAAU,CAAA,GAGHD,EAAcQ,CAAQ,CAChD,CAEA,SAASQ,EAAoBvB,EAAUO,EAA0B,CAE3D,OADAP,GAAS,MACTwB,EAAAA,QAAQxB,CAAK,IACXyB,EAAAA,QAAQzB,CAAK,GACb0B,EAAA,QAAQ1B,EAAOO,CAAY,GAAU,GAGpCP,IAAUO,CACnB,CAOgB,SAAAoB,EAAeC,EAA2BhB,EAAsC,CACvF,MAAA,GAAGgB,EAAgB,QAAQ,GAAGC,EAAkBjB,CAAW,CAAC,GAAGgB,EAAgB,IAAI,EAC5F,CAEgB,SAAAR,EACdQ,EACAhB,EACA,CAAE,eAAAH,EAAgB,QAAAqB,GAAyC,CAAE,QAAS,IAChE,CACFF,EAAgB,SAAWC,EAAkBjB,CAAW,IAC1DH,GAAA,MAAAA,EAAiBG,GACjBmB,EAASJ,EAAeC,EAAiBhB,CAAW,EAAG,CAAE,QAAAkB,EAAS,EAEtE,CAEO,SAASZ,EACdN,EACAN,EACAN,EACAO,EACAC,EACM,CACFR,GAAS,MAAQuB,EAAiBvB,EAAOO,CAAY,EACvDK,EAAY,IAAIN,EAAME,EAAW,UAAUR,CAAK,CAAC,EAEjDY,EAAY,OAAON,CAAI,CAE3B,CAEA,SAASuB,EAAkBG,EAAsC,CACzD,MAAAC,EAAuBD,EAAY,WAClC,OAAAC,EAAuB,IAAIA,CAAoB,GAAK,EAC7D"}