AK-21/Graphite-Industrial-Intelligence
0
1import { useSyncExternalStore } from "./react-deps.js";2 3/**4 * History API docs @see https://developer.mozilla.org/en-US/docs/Web/API/History5 */6const eventPopstate = "popstate";7const eventPushState = "pushState";8const eventReplaceState = "replaceState";9const eventHashchange = "hashchange";10const events = [11 eventPopstate,12 eventPushState,13 eventReplaceState,14 eventHashchange,15];16 17const subscribeToLocationUpdates = (callback) => {18 for (const event of events) {19 addEventListener(event, callback);20 }21 return () => {22 for (const event of events) {23 removeEventListener(event, callback);24 }25 };26};27 28export const useLocationProperty = (fn, ssrFn) =>29 useSyncExternalStore(subscribeToLocationUpdates, fn, ssrFn);30 31const currentSearch = () => location.search;32 33export const useSearch = ({ ssrSearch } = {}) =>34 useLocationProperty(35 currentSearch,36 // != null checks for both null and undefined, but allows empty string ""37 // This allows proper hydration: server renders with ssrSearch="?foo",38 // client hydrates with just <Router /> and reads from location.search39 ssrSearch != null ? () => ssrSearch : currentSearch40 );41 42const currentPathname = () => location.pathname;43 44export const usePathname = ({ ssrPath } = {}) =>45 useLocationProperty(46 currentPathname,47 // != null checks for both null and undefined, but allows empty string ""48 // This allows proper hydration: server renders with ssrPath="/foo",49 // client hydrates with just <Router /> and reads from location.pathname50 ssrPath != null ? () => ssrPath : currentPathname51 );52 53const currentHistoryState = () => history.state;54export const useHistoryState = () =>55 useLocationProperty(currentHistoryState, () => null);56 57export const navigate = (to, { replace = false, state = null } = {}) =>58 history[replace ? eventReplaceState : eventPushState](state, "", to);59 60// the 2nd argument of the `useBrowserLocation` return value is a function61// that allows to perform a navigation.62export const useBrowserLocation = (opts = {}) => [usePathname(opts), navigate];63 64const patchKey = Symbol.for("wouter_v3");65 66// While History API does have `popstate` event, the only67// proper way to listen to changes via `push/replaceState`68// is to monkey-patch these methods.69//70// See https://stackoverflow.com/a/458503171if (typeof history !== "undefined" && typeof window[patchKey] === "undefined") {72 for (const type of [eventPushState, eventReplaceState]) {73 const original = history[type];74 // TODO: we should be using unstable_batchedUpdates to avoid multiple re-renders,75 // however that will require an additional peer dependency on react-dom.76 // See: https://github.com/reactwg/react-18/discussions/86#discussioncomment-156714977 history[type] = function () {78 const result = original.apply(this, arguments);79 const event = new Event(type);80 event.arguments = arguments;81 82 dispatchEvent(event);83 return result;84 };85 }86 87 // patch history object only once88 // See: https://github.com/molefrog/wouter/issues/16789 Object.defineProperty(window, patchKey, { value: true });90}91 