jotai-location
Version:
76 lines (75 loc) • 3.07 kB
JavaScript
import { atom } from 'jotai/vanilla';
import { RESET } from 'jotai/vanilla/utils';
const safeJSONParse = (initialValue) => (str) => {
try {
return JSON.parse(str);
}
catch (_a) {
return initialValue;
}
};
export const setHashWithPush = (searchParams) => {
const newUrl = `${window.location.pathname}${window.location.search}${searchParams ? `#${searchParams}` : ''}`;
window.history.pushState(window.history.state, '', newUrl);
};
export const setHashWithReplace = (searchParams) => {
const newUrl = `${window.location.pathname}${window.location.search}${searchParams ? `#${searchParams}` : ''}`;
window.history.replaceState(window.history.state, '', newUrl);
};
function getSetHashFn(setHashOption) {
if (setHashOption === 'replaceState') {
return setHashWithReplace;
}
if (typeof setHashOption === 'function') {
return setHashOption;
}
return setHashWithPush;
}
export function atomWithHash(key, initialValue, options) {
const serialize = (options === null || options === void 0 ? void 0 : options.serialize) || JSON.stringify;
const deserialize = (options === null || options === void 0 ? void 0 : options.deserialize) || safeJSONParse(initialValue);
const subscribe = (options === null || options === void 0 ? void 0 : options.subscribe) ||
((callback) => {
window.addEventListener('hashchange', callback);
return () => {
window.removeEventListener('hashchange', callback);
};
});
const isLocationAvailable = typeof window !== 'undefined' && !!window.location;
const strAtom = atom(isLocationAvailable
? new URLSearchParams(window.location.hash.slice(1)).get(key)
: null);
strAtom.onMount = (setAtom) => {
if (!isLocationAvailable) {
return undefined;
}
const callback = () => {
setAtom(new URLSearchParams(window.location.hash.slice(1)).get(key));
};
const unsubscribe = subscribe(callback);
callback();
return unsubscribe;
};
const valueAtom = atom((get) => {
const str = get(strAtom);
return str === null ? initialValue : deserialize(str);
});
return atom((get) => get(valueAtom), (get, set, update, setOptions) => {
var _a;
const nextValue = typeof update === 'function'
? update(get(valueAtom))
: update;
const searchParams = new URLSearchParams(window.location.hash.slice(1));
if (nextValue === RESET) {
set(strAtom, null);
searchParams.delete(key);
}
else {
const str = serialize(nextValue);
set(strAtom, str);
searchParams.set(key, str);
}
const setHash = getSetHashFn((_a = setOptions === null || setOptions === void 0 ? void 0 : setOptions.setHash) !== null && _a !== void 0 ? _a : options === null || options === void 0 ? void 0 : options.setHash);
setHash(searchParams.toString());
});
}