Skip to content

Commit

Permalink
Added createHashHistory
Browse files Browse the repository at this point in the history
  • Loading branch information
smikhalevski committed Jul 19, 2024
1 parent 619ad26 commit dccc74d
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 18 deletions.
44 changes: 26 additions & 18 deletions src/main/history/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { forwardRef, HTMLAttributes, useContext, useEffect } from 'react';
import React, { forwardRef, HTMLAttributes, useContext, useEffect, MouseEvent } from 'react';
import { LocationOptions, To } from '../types';
import { useNavigation } from '../useNavigation';
import { toLocation } from '../utils';
Expand Down Expand Up @@ -43,28 +43,36 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
}
}, []);

const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {
if (typeof onClick === 'function') {
onClick(event);
}

if (
event.isDefaultPrevented() ||
event.getModifierState('Alt') ||
event.getModifierState('Control') ||
event.getModifierState('Shift') ||
event.getModifierState('Meta')
) {
return;
}

event.preventDefault();

if (replace) {
navigation.replace(to);
} else {
navigation.push(to);
}
};

return (
<a
{...anchorProps}
ref={ref}
href={history?.toURL(toLocation(to))}
onClick={event => {
if (typeof onClick === 'function') {
onClick(event);
}

if (event.isDefaultPrevented()) {
return;
}

event.preventDefault();

if (replace) {
navigation.replace(to);
} else {
navigation.push(to);
}
}}
onClick={handleClick}
/>
);
});
Expand Down
82 changes: 82 additions & 0 deletions src/main/history/createHashHistory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { PubSub } from 'parallel-universe';
import { toLocation } from '../utils';
import { History, SearchParamsAdapter } from './types';
import { Location } from '../types';
import { urlSearchParamsAdapter } from './urlSearchParamsAdapter';
import { parseURL, toURL } from './utils';

/**
* Options of {@link createHashHistory}.
*/
export interface HashHistoryOptions {
/**
* A default URL base used by {@link History.toURL}.
*/
base?: URL | string;

/**
* An adapter that extracts params from a URL search string and stringifies them back. By default, an adapter that
* relies on {@link !URLSearchParams} is used.
*/
searchParamsAdapter?: SearchParamsAdapter;
}

/**
* Create the history adapter that reads and writes location to a browser's session history.
*
* @param options History options.
*/
export function createHashHistory(options: HashHistoryOptions = {}): History {
const { base: defaultBase, searchParamsAdapter = urlSearchParamsAdapter } = options;
const pubSub = new PubSub();
const handlePopstate = () => pubSub.publish();

let prevHref: string;
let location: Location;

return {
get location() {
const href = decodeURIComponent(window.location.hash.substring(1));

return prevHref === href ? location : (location = parseURL((prevHref = href), searchParamsAdapter));
},

toURL(location, base = defaultBase) {
const url = '#' + encodeURIComponent(toURL(location, searchParamsAdapter));

return base === undefined ? url : new URL(url, base).toString();
},

push(to) {
location = toLocation(to);
history.pushState(location.state, '', '#' + encodeURIComponent(toURL(location, searchParamsAdapter)));
pubSub.publish();
},

replace(to) {
location = toLocation(to);
history.replaceState(location.state, '', '#' + encodeURIComponent(toURL(location, searchParamsAdapter)));
pubSub.publish();
},

back() {
history.back();
},

subscribe(listener) {
if (pubSub.listenerCount === 0) {
window.addEventListener('popstate', handlePopstate);
}

const unsubscribe = pubSub.subscribe(listener);

return () => {
unsubscribe();

if (pubSub.listenerCount === 0) {
window.removeEventListener('popstate', handlePopstate);
}
};
},
};
}
1 change: 1 addition & 0 deletions src/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { createBrowserHistory } from './history/createBrowserHistory';
export { createHashHistory } from './history/createHashHistory';
export { createMemoryHistory } from './history/createMemoryHistory';
export { Link } from './history/Link';
export { useHistorySubscription } from './history/useHistorySubscription';
Expand Down

0 comments on commit dccc74d

Please sign in to comment.