@coveord/plasma-mantine
Version:
A Plasma flavoured Mantine theme
94 lines (93 loc) • 3.89 kB
JavaScript
import { useMemo, useState } from 'react';
const slice = Function.prototype.call.bind(Array.prototype.slice);
/**
* Split a url into its parts.
*
* @param href The url to extract the parts from.
* @returns The separate parts, all are an empty string if not present.
*/ const extractParts = (href)=>slice(/^([^?#]*)(\?[^#]*|)(#[^?]*|)(\?.*|)$/.exec(href ?? ''), 1, 5);
/**
* The index of the search parameter to use, e.g. hashSearch for hash routes (hash starts with '#/').
*
* @param parts: The url parts, as returned by `extractParts`.
* @returns The index of the search parameter to use (1 or 3).
*/ const searchIndex = (parts)=>/^#\//.test(parts[2]) ? 3 : 1;
/**
* Read the **current** search params from `window.location`, with support for detecting React's HashRouter.
* Also returns a method that will yield the href (string) value, after any changes made on the params object.
*
* @returns The `URLSearchParams` instance, and a function that can be used to get an updated href.
*/ const getSearchParams = ()=>{
const parts = extractParts(window.location.href);
return new URLSearchParams(parts[searchIndex(parts)]);
};
/**
* Apply the search params to the current location, using `replaceState` (no navigation history).
* Note that only parameters in the `params` argument will be set, any other current params will be removed.
*
* @param params The parameters to apply.
*/ const applySearchParams = (params)=>{
const currentHref = window.location.href;
const parts = extractParts(currentHref);
const search = params.size > 0 ? `?${params.toString()}` : '';
const index = searchIndex(parts);
if (parts[index] !== search) {
parts[index] = search;
window.history.replaceState(null, '', parts.join(''));
}
};
const getInitialState = (options)=>options.initialState instanceof Function ? options.initialState() : options.initialState;
export const useUrlSyncedState = (options)=>{
const sync = options.sync !== false;
const [state, setState] = useState(()=>{
const initialState = getInitialState(options);
return sync ? options.deserializer(getSearchParams(), initialState) : initialState;
});
// Capture the initial state as a map (first render only!), to compare values and see if they should be set to the params.
const initialStateSerialized = useMemo(()=>{
const stateMap = new Map();
let initialize = null;
let needsApply = false;
for (const [key, value, alwaysEmit] of options.serializer(getInitialState(options))){
stateMap.set(key, value);
if (sync && alwaysEmit && value) {
initialize ?? (initialize = getSearchParams());
if (!initialize.has(key)) {
needsApply = true;
initialize.set(key, value);
}
}
}
if (needsApply) {
applySearchParams(initialize);
}
return stateMap;
}, []);
const enhancedSetState = useMemo(()=>{
if (!sync) {
return setState;
}
return (updater)=>{
setState((old)=>{
const newValue = updater instanceof Function ? updater(old) : updater;
const search = getSearchParams();
for (const [key, value, alwaysEmit] of options.serializer(newValue)){
if (value && (alwaysEmit || !Object.is(initialStateSerialized.get(key), value))) {
search.set(key, value);
} else {
search.delete(key);
}
}
applySearchParams(search);
return newValue;
});
};
}, [
sync
]);
return [
state,
enhancedSetState
];
};
//# sourceMappingURL=use-url-synced-state.js.map