UNPKG

@coveord/plasma-mantine

Version:

A Plasma flavoured Mantine theme

94 lines (93 loc) 3.89 kB
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