UNPKG

@jeremyckahn/farmhand

Version:
73 lines (59 loc) 2.38 kB
import globalWindow from 'global/window.js' export const VIEW_QUERY_PARAM_NAME = 'view' // The app is served behind a HashRouter (see src/index.tsx), which owns // everything after "#" for its own path-based routing (e.g. // "#online/my-room"). These helpers append/read a query string on that // same hash, after any router path, so persisted UI state (e.g. the // current view) round-trips through a reload without going through // react-router's history/location - which requires a <Router> ancestor // that isn't present in every test/render context this is used from. const splitHash = () => { const hash = globalWindow.location.hash.replace(/^#/, '') const queryIndex = hash.indexOf('?') return queryIndex === -1 ? { path: hash, query: '' } : { path: hash.slice(0, queryIndex), query: hash.slice(queryIndex + 1) } } export type HashHistoryMode = 'push' | 'replace' const writeHashQueryParams = ( params: URLSearchParams, mode: HashHistoryMode = 'replace' ): void => { const { path } = splitHash() const queryString = params.toString() const newHash = `${path}${queryString ? `?${queryString}` : ''}` const { origin, pathname, search } = globalWindow.location const url = `${origin}${pathname}${search}#${newHash}` if (mode === 'push') { globalWindow.history.pushState({}, '', url) } else { globalWindow.history.replaceState({}, '', url) } } export const getHashQueryParams = (): URLSearchParams => new URLSearchParams(splitHash().query) export const setHashQueryParam = ( key: string, value: string, mode: HashHistoryMode = 'replace' ): void => { const params = getHashQueryParams() params.set(key, value) writeHashQueryParams(params, mode) } export const removeHashQueryParam = ( key: string, mode: HashHistoryMode = 'replace' ): void => { const params = getHashQueryParams() params.delete(key) writeHashQueryParams(params, mode) } // react-router's <Redirect to={path}> replaces the whole hash with `path`, // dropping whatever query params (view/tab) were already on it - this // carries them over onto a new redirect target (e.g. going online/offline, // switching rooms) so navigating doesn't lose your place. export const withCurrentHashQuery = (path: string): string => { const queryString = getHashQueryParams().toString() return queryString ? `${path}?${queryString}` : path }