diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-06-29 14:49:13 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-07-01 11:37:48 +0200 |
| commit | e6d83cc9fe4b8e951403bc3ee6d0744934b041ee (patch) | |
| tree | 29a4738c20ce56e2f29855111a235a251807e96c /gui/src/renderer | |
| parent | d962e59af7ebe3980686324d430ff1854a832445 (diff) | |
| download | mullvadvpn-e6d83cc9fe4b8e951403bc3ee6d0744934b041ee.tar.xz mullvadvpn-e6d83cc9fe4b8e951403bc3ee6d0744934b041ee.zip | |
Replace history methods with new ones more aligned with our needs
Diffstat (limited to 'gui/src/renderer')
| -rw-r--r-- | gui/src/renderer/lib/history.ts | 147 |
1 files changed, 96 insertions, 51 deletions
diff --git a/gui/src/renderer/lib/history.ts b/gui/src/renderer/lib/history.ts index 3f98508ce1..c3a06b98e3 100644 --- a/gui/src/renderer/lib/history.ts +++ b/gui/src/renderer/lib/history.ts @@ -1,9 +1,44 @@ import { Location, Action, LocationDescriptor } from 'history'; +export interface ITransitionSpecification { + name: string; + duration: number; +} + +interface ITransitionMap { + [name: string]: ITransitionSpecification; +} + +/** + * Transition descriptors + */ +export const transitions: ITransitionMap = { + show: { + name: 'slide-up', + duration: 450, + }, + dismiss: { + name: 'slide-down', + duration: 450, + }, + push: { + name: 'push', + duration: 450, + }, + pop: { + name: 'pop', + duration: 450, + }, + none: { + name: '', + duration: 0, + }, +}; + type LocationListener<S = unknown> = ( location: Location<S>, action: Action, - entries: Location<S>[], + transition: ITransitionSpecification, ) => void; // It currently isn't possible to implement this correctly with support for a generic state. State @@ -33,80 +68,90 @@ export default class History { } public push = (nextLocation: LocationDescriptor<S>, nextState?: S) => { - const affectedEntries = [this.entries[this.index]]; - const location = this.createLocation(nextLocation, nextState); - this.lastAction = 'PUSH'; - this.index += 1; - this.entries.splice(this.index, this.entries.length - this.index, location); - this.notify(affectedEntries); - }; - - public replace = (nextLocation: LocationDescriptor<S>, nextState?: S) => { - const affectedEntries = [this.entries[this.index]]; - this.entries[this.index] = this.createLocation(nextLocation, nextState); - this.lastAction = 'REPLACE'; - this.notify(affectedEntries); + this.pushImpl(nextLocation, nextState); + this.notify(transitions.push); }; - public go = (n: number) => { - if (this.canGo(n)) { - const nextIndex = this.index + n; - const affectedEntries = - this.index < nextIndex - ? this.entries.slice(this.index, nextIndex) - : this.entries.slice(nextIndex + 1, this.index + 1); - - this.index = nextIndex; - this.lastAction = 'POP'; - this.notify(affectedEntries); + public pop = () => { + if (this.popImpl()) { + this.notify(transitions.pop); } }; - public goBack = () => this.go(-1); - public goForward = () => this.go(1); + public show = (nextLocation: LocationDescriptor<S>, nextState?: S) => { + this.pushImpl(nextLocation, nextState); + this.notify(transitions.show); + }; - public reset = () => { - const affectedEntries = this.entries.slice(1); - this.lastAction = 'POP'; - this.index = 0; - this.notify(affectedEntries); + public dismiss = (all?: boolean) => { + if (this.popImpl(all ? this.index : 1)) { + this.notify(transitions.dismiss); + } }; - public resetWith = (nextLocation: LocationDescriptor<S>, nextState?: S) => { - const affectedEntries = [...this.entries]; - this.entries = [this.createLocation(nextLocation, nextState)]; + public reset = ( + nextLocation: LocationDescriptor<S>, + transition?: ITransitionSpecification, + nextState?: S, + ) => { + const location = this.createLocation(nextLocation, nextState); this.lastAction = 'REPLACE'; this.index = 0; - this.notify(affectedEntries); - }; + this.entries = [location]; - public resetWithIfDifferent = (nextLocation: LocationDescriptor<S>, nextState?: S) => { - const location = this.createLocation(nextLocation, nextState); - if (this.entries[0].pathname !== location.pathname) { - this.resetWith(nextLocation, nextState); - } + this.notify(transition ?? transitions.none); }; + public listen(callback: LocationListener<S>) { + this.listeners.push(callback); + return () => (this.listeners = this.listeners.filter((listener) => listener !== callback)); + } + public canGo(n: number) { const nextIndex = this.index + n; return nextIndex >= 0 && nextIndex < this.entries.length; } - public listen(callback: LocationListener<S>) { - this.listeners.push(callback); - return () => (this.listeners = this.listeners.filter((listener) => listener !== callback)); + public block(): never { + throw Error('Not implemented'); } - - public block(): () => void { + public replace(): never { throw Error('Not implemented'); } - - public createHref(): string { + public go(): never { + throw Error('Not implemented'); + } + public goBack(): never { + throw Error('Not implemented'); + } + public goForward(): never { + throw Error('Not implemented'); + } + public createHref(): never { throw Error('Not implemented'); } - private notify(affectedEntries: Location<S>[]) { - this.listeners.forEach((listener) => listener(this.location, this.action, affectedEntries)); + private pushImpl(nextLocation: LocationDescriptor<S>, nextState?: S) { + const location = this.createLocation(nextLocation, nextState); + this.lastAction = 'PUSH'; + this.index += 1; + this.entries.splice(this.index, this.entries.length - this.index, location); + } + + private popImpl(n = 1): boolean { + if (this.canGo(-n)) { + this.lastAction = 'POP'; + this.index -= n; + this.entries = this.entries.slice(0, this.index + 1); + + return true; + } else { + return false; + } + } + + private notify(transition: ITransitionSpecification) { + this.listeners.forEach((listener) => listener(this.location, this.action, transition)); } private createLocation(location: LocationDescriptor<S>, state?: S): Location<S> { |
