diff --git a/lib/use-hash-state.js b/lib/use-hash-state.js index ea71cbb0..8e82a25c 100644 --- a/lib/use-hash-state.js +++ b/lib/use-hash-state.js @@ -2,58 +2,71 @@ import { useCallback, useState } from 'haunted'; import { navigate } from '@neovici/cosmoz-router'; import { identity } from '@neovici/cosmoz-utils/function'; import { invoke } from './invoke'; +import { + hashUrl, + multiParse, + singleParse, +} from '@neovici/cosmoz-utils/location'; -const - hashUrl = () => new URL(location.hash.replace(/^#!?/iu, '').replace('%23', '#'), location.origin), +const makeLinker = + (parameterize) => + (hashParam, value, codec = identity) => { + const url = hashUrl(), + searchParams = new URLSearchParams(url.hash.replace('#', '')); - singleParse = (hashParam, codec = identity) => codec(new URLSearchParams(hashUrl().hash.replace('#', '')).get(hashParam)), - multiParse = (hashParam, codec = identity) => { - const params = Array.from(new URLSearchParams(hashUrl().hash.replace('#', '')).entries()) - .filter(([param]) => param.startsWith(hashParam)) - .map(([param, value]) => codec([param.replace(hashParam, ''), value])) - .filter(([, value]) => value != null); + // TODO: make parameterize pure + parameterize(hashParam, value, codec, searchParams); - return Object.fromEntries(params); - }, - - makeLinker = parameterize => (hashParam, value, codec = identity) => { - const - url = hashUrl(), - searchParams = new URLSearchParams(url.hash.replace('#', '')); - - // TODO: make parameterize pure - parameterize(hashParam, value, codec, searchParams); - - return '#!' + Object.assign(url, { hash: searchParams }).href.replace(location.origin, ''); - }, - isEmpty = v => v == null || v === '', + return ( + '#!' + + Object.assign(url, { hash: searchParams }).href.replace( + location.origin, + '' + ) + ); + }, + isEmpty = (v) => v == null || v === '', singleLink = makeLinker((hashParam, value, codec, searchParams) => !isEmpty(codec(value)) ? searchParams.set(hashParam, codec(value)) - : searchParams.delete(hashParam)), + : searchParams.delete(hashParam) + ), multiLink = makeLinker((hashParam, value, codec, searchParams) => Object.entries(value) .map(codec) - .forEach(([key, value]) => !isEmpty(value) - ? searchParams.set(hashParam + key, value) - : searchParams.delete(hashParam + key))); - -export const useHashState = (initial, param, { suffix = '', read, write, multi } = {}) => { - const - [link, parseHash] = multi ? [multiLink, multiParse] : [singleLink, singleParse], - [state, _setState] = useState(() => param == null - ? initial - : parseHash(param + suffix, read) ?? initial), + .forEach(([key, value]) => + !isEmpty(value) + ? searchParams.set(hashParam + key, value) + : searchParams.delete(hashParam + key) + ) + ); - setState = useCallback(state => _setState(oldState => { - const newState = invoke(state, oldState); +export const useHashState = ( + initial, + param, + { suffix = '', read, write, multi } = {} +) => { + const [link, parseHash] = multi + ? [multiLink, multiParse] + : [singleLink, singleParse], + [state, _setState] = useState(() => + param == null ? initial : parseHash(param + suffix, read) ?? initial + ), + setState = useCallback( + (state) => + _setState((oldState) => { + const newState = invoke(state, oldState); - if (param != null) { - navigate(link(param + suffix, newState, write), null, { notify: false }); - } + if (param != null) { + navigate(link(param + suffix, newState, write), null, { + notify: false, + }); + } - return newState; - }), [param, suffix, link, write]); + return newState; + }), + [param, suffix, link, write] + ); return [state, setState]; }; diff --git a/package-lock.json b/package-lock.json index f329284c..a014fc25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@neovici/cosmoz-grouped-list": "^6.0.0", "@neovici/cosmoz-i18next": "^3.1.1", "@neovici/cosmoz-router": "^10.0.0", - "@neovici/cosmoz-utils": "^5.0.0", + "@neovici/cosmoz-utils": "^5.10.1", "@neovici/nullxlsx": "^3.0.0", "@polymer/iron-icon": "^3.0.0", "@polymer/iron-icons": "^3.0.0", @@ -698,9 +698,9 @@ } }, "node_modules/@neovici/cosmoz-utils": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@neovici/cosmoz-utils/-/cosmoz-utils-5.9.0.tgz", - "integrity": "sha512-BO8GRmdycwQfYZojj3waw3PfI+KbXdBK8hh915/oIJacSncpHLS8UmirbuwLXL9Ht3VTJEDBqy4OIOhwCOBxzA==", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/@neovici/cosmoz-utils/-/cosmoz-utils-5.10.1.tgz", + "integrity": "sha512-YAxnK7kf7TA+TEk49DVKDL2Kb8p05xDeW8EPE55e48JM/8nfUeJ2x2vYyvPxKWTUoZuJjNac+QUFZ5rWdeyAmA==", "dependencies": { "haunted": "^5.0.0" } @@ -13539,9 +13539,9 @@ } }, "@neovici/cosmoz-utils": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@neovici/cosmoz-utils/-/cosmoz-utils-5.9.0.tgz", - "integrity": "sha512-BO8GRmdycwQfYZojj3waw3PfI+KbXdBK8hh915/oIJacSncpHLS8UmirbuwLXL9Ht3VTJEDBqy4OIOhwCOBxzA==", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/@neovici/cosmoz-utils/-/cosmoz-utils-5.10.1.tgz", + "integrity": "sha512-YAxnK7kf7TA+TEk49DVKDL2Kb8p05xDeW8EPE55e48JM/8nfUeJ2x2vYyvPxKWTUoZuJjNac+QUFZ5rWdeyAmA==", "requires": { "haunted": "^5.0.0" } diff --git a/package.json b/package.json index ab858e21..4065c216 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@neovici/cosmoz-grouped-list": "^6.0.0", "@neovici/cosmoz-i18next": "^3.1.1", "@neovici/cosmoz-router": "^10.0.0", - "@neovici/cosmoz-utils": "^5.0.0", + "@neovici/cosmoz-utils": "^5.10.1", "@neovici/nullxlsx": "^3.0.0", "@polymer/iron-icon": "^3.0.0", "@polymer/iron-icons": "^3.0.0",