diff --git a/packages/router/src/components/redirect/redirect.tsx b/packages/router/src/components/redirect/redirect.tsx index e12d8b5..eed935b 100644 --- a/packages/router/src/components/redirect/redirect.tsx +++ b/packages/router/src/components/redirect/redirect.tsx @@ -3,9 +3,9 @@ import { RouterHistory } from '../../global/interfaces'; import ActiveRouter from '../../global/active-router'; // Get the URL for this route link without the root from the router -function getUrl(url: string, root: string) { +const getUrl = (url: string, root: string) => { // Don't allow double slashes - if(url.charAt(0) == '/' && root.charAt(root.length - 1) == '/') { + if (url.charAt(0) == '/' && root.charAt(root.length - 1) == '/') { return root.slice(0, root.length-1) + url; } return root + url; diff --git a/packages/router/src/components/route-title/route-title.tsx b/packages/router/src/components/route-title/route-title.tsx index 256adba..e60a5d4 100644 --- a/packages/router/src/components/route-title/route-title.tsx +++ b/packages/router/src/components/route-title/route-title.tsx @@ -1,4 +1,4 @@ -import { Component, Prop, Element, Watch, ComponentInterface, getDocument } from '@stencil/core'; +import { Component, Prop, Element, Watch, ComponentInterface } from '@stencil/core'; import ActiveRouter from '../../global/active-router'; /** @@ -11,14 +11,16 @@ import ActiveRouter from '../../global/active-router'; tag: 'stencil-route-title' }) export class RouteTitle implements ComponentInterface { - doc = getDocument(this); @Element() el!: HTMLElement; @Prop() titleSuffix: string = ''; @Prop() pageTitle: string = ''; @Watch('pageTitle') updateDocumentTitle() { - this.doc.title = `${this.pageTitle}${this.titleSuffix || ''}`; + const el = this.el; + if (el.ownerDocument) { + el.ownerDocument.title = `${this.pageTitle}${this.titleSuffix || ''}`; + } } componentWillLoad() { diff --git a/packages/router/src/components/router/router.tsx b/packages/router/src/components/router/router.tsx index 67ce04a..98d2ca3 100644 --- a/packages/router/src/components/router/router.tsx +++ b/packages/router/src/components/router/router.tsx @@ -1,4 +1,4 @@ -import { Component, Prop, State, ComponentInterface, getDocument, getWindow, h } from '@stencil/core'; +import { Component, Element, Prop, State, ComponentInterface, h } from '@stencil/core'; import createHistory from '../../utils/createBrowserHistory'; import createHashHistory from '../../utils/createHashHistory'; import { LocationSegments, HistoryType, RouterHistory, RouteViewOptions } from '../../global/interfaces'; @@ -31,7 +31,7 @@ const HISTORIES: { [key in HistoryType]: (win: Window) => RouterHistory } = { tag: 'stencil-router' }) export class Router implements ComponentInterface { - win = getWindow(this); + @Element() el!: HTMLElement; @Prop() root: string = '/'; @Prop({ context: 'isServer' }) private isServer!: boolean; @Prop({ context: 'queue'}) queue!: QueueApi; @@ -47,9 +47,9 @@ export class Router implements ComponentInterface { @State() history?: RouterHistory; componentWillLoad() { - this.history = HISTORIES[this.historyType](this.win); + this.history = HISTORIES[this.historyType]((this.el.ownerDocument as any).defaultView); - this.history.listen(async (location: LocationSegments) => { + this.history.listen((location: LocationSegments) => { location = getLocation(location, this.root); this.location = location; }); @@ -57,8 +57,8 @@ export class Router implements ComponentInterface { } routeViewsUpdated = (options: RouteViewOptions = {}) => { - if (options.scrollToId && this.historyType === 'browser') { - const elm = getDocument(this).getElementById(options.scrollToId); + if (this.history && options.scrollToId && this.historyType === 'browser') { + const elm = this.history.win.document.getElementById(options.scrollToId); if (elm) { return elm.scrollIntoView(); } @@ -67,20 +67,22 @@ export class Router implements ComponentInterface { } scrollTo(scrollToLocation?: number) { - if (scrollToLocation == null || this.isServer || !this.history) { + const history = this.history; + + if (scrollToLocation == null || this.isServer || !history) { return; } - if (this.history.action === 'POP' && Array.isArray(this.history.location.scrollPosition)) { + if (history.action === 'POP' && Array.isArray(history.location.scrollPosition)) { return this.queue.write(() => { - if (this.history && this.history.location && Array.isArray(this.history.location.scrollPosition)) { - this.win.scrollTo(this.history.location.scrollPosition[0], this.history.location.scrollPosition[1]); + if (history && history.location && Array.isArray(history.location.scrollPosition)) { + history.win.scrollTo(history.location.scrollPosition[0], history.location.scrollPosition[1]); } }); } // okay, the frame has passed. Go ahead and render now return this.queue.write(() => { - this.win.scrollTo(0, scrollToLocation); + history.win.scrollTo(0, scrollToLocation); }); } diff --git a/packages/router/src/global/interfaces.ts b/packages/router/src/global/interfaces.ts index d8d36d1..72c7515 100644 --- a/packages/router/src/global/interfaces.ts +++ b/packages/router/src/global/interfaces.ts @@ -53,6 +53,7 @@ export interface RouterHistory { goForward: () => void; block: (prompt?: string | Prompt) => () => void; listen: (listener: Function) => () => void; + win: Window; } export interface RouterGroup { diff --git a/packages/router/src/utils/createBrowserHistory.ts b/packages/router/src/utils/createBrowserHistory.ts index 89f1409..558c95d 100644 --- a/packages/router/src/utils/createBrowserHistory.ts +++ b/packages/router/src/utils/createBrowserHistory.ts @@ -34,26 +34,18 @@ interface NextState { const PopStateEvent = 'popstate'; const HashChangeEvent = 'hashchange'; -const getHistoryState = (win: Window) => { - try { - return win.history.state || {}; - } catch (e) { - // IE 11 sometimes throws when accessing window.history.state - // See https://github.com/ReactTraining/history/pull/289 - return {}; - } -}; - /** * Creates a history object that uses the HTML5 history API including * pushState, replaceState, and the popstate event. */ -const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = {}): RouterHistory => { +const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = {}) => { let forceNextPop = false; const globalHistory = win.history; + const globalLocation = win.location; + const globalNavigator = win.navigator; const canUseHistory = supportsHistory(win); - const needsHashChangeListener = !supportsPopStateOnHashChange(win.navigator); + const needsHashChangeListener = !supportsPopStateOnHashChange(globalNavigator); const scrollHistory = createScrollHistory(win); const forceRefresh = (props.forceRefresh != null) ? props.forceRefresh : false; @@ -61,10 +53,20 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = const keyLength = (props.keyLength != null) ? props.keyLength : 6; const basename = props.basename ? stripTrailingSlash(addLeadingSlash(props.basename)) : ''; - const getDOMLocation = (win: Window, historyState: LocationSegments) => { + const getHistoryState = () => { + try { + return win.history.state || {}; + } catch (e) { + // IE 11 sometimes throws when accessing window.history.state + // See https://github.com/ReactTraining/history/pull/289 + return {}; + } + }; + + const getDOMLocation = (historyState: LocationSegments) => { historyState = historyState || {}; const { key, state } = historyState; - const { pathname, search, hash } = win.location; + const { pathname, search, hash } = globalLocation; let path = pathname + search + hash; @@ -103,13 +105,13 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = const handlePopState = (event: any) => { // Ignore extraneous popstate events in WebKit. - if (!isExtraneousPopstateEvent(win.navigator, event)) { - handlePop(getDOMLocation(win, event.state)); + if (!isExtraneousPopstateEvent(globalNavigator, event)) { + handlePop(getDOMLocation(event.state)); } }; const handleHashChange = () => { - handlePop(getDOMLocation(win, getHistoryState(win))); + handlePop(getDOMLocation(getHistoryState())); }; @@ -138,13 +140,12 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = // Instead, we just default to 0 for keys we don't know. let toIndex = allKeys.indexOf(toLocation.key); + let fromIndex = allKeys.indexOf(fromLocation.key); if (toIndex === -1) { toIndex = 0; } - let fromIndex = allKeys.indexOf(fromLocation.key); - if (fromIndex === -1) { fromIndex = 0; } @@ -157,7 +158,7 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = } }; - const initialLocation = getDOMLocation(win, getHistoryState(win)); + const initialLocation = getDOMLocation(getHistoryState()); let allKeys = [ initialLocation.key ]; let listenerCount = 0; let isBlocked = false; @@ -190,7 +191,7 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = globalHistory.pushState({ key, state }, '', href); if (forceRefresh) { - win.location.href = href; + globalLocation.href = href; } else { const prevIndex = allKeys.indexOf(history.location.key); const nextKeys = allKeys.slice(0, prevIndex === -1 ? 0 : prevIndex + 1); @@ -206,7 +207,7 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = 'Browser history cannot push state in browsers that do not support HTML5 history' ); - win.location.href = href; + globalLocation.href = href; } }); }; @@ -233,7 +234,8 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = globalHistory.replaceState({ key, state }, '', href); if (forceRefresh) { - win.location.replace(href); + globalLocation.replace(href); + } else { const prevIndex = allKeys.indexOf(history.location.key); @@ -249,7 +251,7 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = 'Browser history cannot replace state in browsers that do not support HTML5 history' ); - win.location.replace(href); + globalLocation.replace(href); } }); }; @@ -308,7 +310,7 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = }; }; - const history = { + const history: RouterHistory = { length: globalHistory.length, action: 'POP', location: initialLocation, @@ -319,7 +321,8 @@ const createBrowserHistory = (win: Window, props: CreateBrowserHistoryOptions = goBack, goForward, block, - listen + listen, + win: win }; return history; diff --git a/packages/router/src/utils/createHashHistory.ts b/packages/router/src/utils/createHashHistory.ts index 4fa30cc..be2a8a0 100644 --- a/packages/router/src/utils/createHashHistory.ts +++ b/packages/router/src/utils/createHashHistory.ts @@ -40,27 +40,13 @@ const HashPathCoders = { } }; -const getHashPath = (win: Window) => { - // We can't use window.location.hash here because it's not - // consistent across browsers - Firefox will pre-decode it! - const href = win.location.href; - const hashIndex = href.indexOf('#'); - return hashIndex === -1 ? '' : href.substring(hashIndex + 1); -}; - -const pushHashPath = (win: Window, path: string) => ( - win.location.hash = path -); - -const replaceHashPath = (win: Window, path: string) => { - const hashIndex = win.location.href.indexOf('#'); - - win.location.replace( - win.location.href.slice(0, hashIndex >= 0 ? hashIndex : 0) + '#' + path - ); -}; +const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}) => { + let forceNextPop = false; + let ignorePath: any = null; + let listenerCount = 0; + let isBlocked = false; -const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): RouterHistory => { + const globalLocation = win.location; const globalHistory = win.history; const canGoWithoutReload = supportsGoWithoutReloadUsingHash(win.navigator); const keyLength = (props.keyLength != null) ? props.keyLength : 6; @@ -73,8 +59,28 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R const { encodePath, decodePath } = HashPathCoders[hashType]; - const getDOMLocation = (win: Window) => { - let path = decodePath(getHashPath(win)); + const getHashPath = () => { + // We can't use window.location.hash here because it's not + // consistent across browsers - Firefox will pre-decode it! + const href = globalLocation.href; + const hashIndex = href.indexOf('#'); + return hashIndex === -1 ? '' : href.substring(hashIndex + 1); + }; + + const pushHashPath = (path: string) => ( + globalLocation.hash = path + ); + + const replaceHashPath = (path: string) => { + const hashIndex = globalLocation.href.indexOf('#'); + + globalLocation.replace( + globalLocation.href.slice(0, hashIndex >= 0 ? hashIndex : 0) + '#' + path + ); + }; + + const getDOMLocation = () => { + let path = decodePath(getHashPath()); warning( (!basename || hasBasename(path, basename)), @@ -102,18 +108,16 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R ); }; - let forceNextPop = false; - let ignorePath: any = null; - const handleHashChange = () => { - const path = getHashPath(win); + const path = getHashPath(); const encodedPath = encodePath(path); if (path !== encodedPath) { // Ensure we always have a properly-encoded hash. - replaceHashPath(win, encodedPath); + replaceHashPath(encodedPath); + } else { - const location = getDOMLocation(win); + const location = getDOMLocation(); const prevLocation = history.location; if (!forceNextPop && locationsAreEqual(prevLocation, location)) { @@ -155,13 +159,12 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R // Instead, we just default to 0 for paths we don't know. let toIndex = allPaths.lastIndexOf(createPath(toLocation)); + let fromIndex = allPaths.lastIndexOf(createPath(fromLocation)); if (toIndex === -1) { toIndex = 0; } - let fromIndex = allPaths.lastIndexOf(createPath(fromLocation)); - if (fromIndex === -1) { fromIndex = 0; } @@ -175,14 +178,14 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R }; // Ensure the hash is encoded properly before doing anything else. - const path = getHashPath(win); + const path = getHashPath(); const encodedPath = encodePath(path); if (path !== encodedPath) { - replaceHashPath(win, encodedPath); + replaceHashPath(encodedPath); } - const initialLocation = getDOMLocation(win); + const initialLocation = getDOMLocation(); let allPaths = [ createPath(initialLocation) ]; // Public interface @@ -207,14 +210,14 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R const path = createPath(location); const encodedPath = encodePath(basename + path); - const hashChanged = getHashPath(win) !== encodedPath; + const hashChanged = getHashPath() !== encodedPath; if (hashChanged) { // We cannot tell if a hashchange was caused by a PUSH, so we'd // rather setState here and ignore the hashchange. The caveat here // is that other hash histories in the page will consider it a POP. ignorePath = path; - pushHashPath(win, encodedPath); + pushHashPath(encodedPath); const prevIndex = allPaths.lastIndexOf(createPath(history.location)); const nextPaths = allPaths.slice(0, prevIndex === -1 ? 0 : prevIndex + 1); @@ -250,14 +253,14 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R const path = createPath(location); const encodedPath = encodePath(basename + path); - const hashChanged = getHashPath(win) !== encodedPath; + const hashChanged = getHashPath() !== encodedPath; if (hashChanged) { // We cannot tell if a hashchange was caused by a REPLACE, so we'd // rather setState here and ignore the hashchange. The caveat here // is that other hash histories in the page will consider it a POP. ignorePath = path; - replaceHashPath(win, encodedPath); + replaceHashPath(encodedPath); } const prevIndex = allPaths.indexOf(createPath(history.location)); @@ -283,8 +286,6 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R const goForward = () => go(1); - let listenerCount = 0; - const checkDOMListeners = (win: Window, delta: number) => { listenerCount += delta; @@ -295,8 +296,6 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R } }; - let isBlocked = false; - const block = (prompt: string | Prompt = '') => { const unblock = transitionManager.setPrompt(prompt); @@ -325,7 +324,7 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R }; }; - const history = { + const history: RouterHistory = { length: globalHistory.length, action: 'POP', location: initialLocation, @@ -336,7 +335,8 @@ const createHashHistory = (win: Window, props: CreateHashHistoryOptions = {}): R goBack, goForward, block, - listen + listen, + win: win }; return history; diff --git a/packages/router/src/utils/createTransitionManager.ts b/packages/router/src/utils/createTransitionManager.ts index e386e58..4816e64 100644 --- a/packages/router/src/utils/createTransitionManager.ts +++ b/packages/router/src/utils/createTransitionManager.ts @@ -6,6 +6,7 @@ import { LocationSegments, Prompt } from '../global/interfaces'; const createTransitionManager = () => { let prompt: Prompt | string | null; + let listeners: Function[] = []; const setPrompt = (nextPrompt: Prompt | string | null) => { warning( @@ -49,8 +50,6 @@ const createTransitionManager = () => { } } - let listeners: Function[] = []; - const appendListener = (fn: Function) => { let isActive = true; diff --git a/packages/router/src/utils/dom-utils.ts b/packages/router/src/utils/dom-utils.ts index b161e8e..0c973c6 100644 --- a/packages/router/src/utils/dom-utils.ts +++ b/packages/router/src/utils/dom-utils.ts @@ -3,8 +3,8 @@ export const getConfirmation = (win: Window, message: string, callback: (confirm callback(win.confirm(message)) ); -export const isModifiedEvent = (event: MouseEvent) => ( - event.metaKey || event.altKey || event.ctrlKey || event.shiftKey +export const isModifiedEvent = (ev: MouseEvent) => ( + ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey ); /** diff --git a/packages/router/src/utils/location-utils.ts b/packages/router/src/utils/location-utils.ts index eefe7d2..512e002 100644 --- a/packages/router/src/utils/location-utils.ts +++ b/packages/router/src/utils/location-utils.ts @@ -1,16 +1,16 @@ import { parsePath, parseQueryString } from './path-utils'; import { LocationSegments } from '../global/interfaces'; -function isAbsolute(pathname: string) { +const isAbsolute = (pathname: string) => { return pathname.charAt(0) === '/'; } -export function createKey(keyLength: number) { +export const createKey = (keyLength: number) => { return Math.random().toString(36).substr(2, keyLength) }; // About 1.5x faster than the two-arg version of Array#splice() -function spliceOne(list: string[], index: number) { +const spliceOne = (list: string[], index: number) => { for (let i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) { list[i] = list[k]; } @@ -19,10 +19,12 @@ function spliceOne(list: string[], index: number) { } // This implementation is based heavily on node's url.parse -export function resolvePathname(to: string, from = '') { - const toParts = to && to.split('/') || []; +export const resolvePathname = (to: string, from = '') => { let fromParts = from && from.split('/') || []; + let hasTrailingSlash; + let up = 0; + const toParts = to && to.split('/') || []; const isToAbs = to && isAbsolute(to); const isFromAbs = from && isAbsolute(from); const mustEndAbs = isToAbs || isFromAbs; @@ -40,7 +42,6 @@ export function resolvePathname(to: string, from = '') { return '/'; } - let hasTrailingSlash; if (fromParts.length) { const last = fromParts[fromParts.length - 1]; hasTrailingSlash = (last === '.' || last === '..' || last === ''); @@ -48,7 +49,6 @@ export function resolvePathname(to: string, from = '') { hasTrailingSlash = false; } - let up = 0; for (let i = fromParts.length; i >= 0; i--) { const part = fromParts[i]; @@ -82,7 +82,7 @@ export function resolvePathname(to: string, from = '') { return result; } -export function valueEqual(a: any, b: any): boolean { +export const valueEqual = (a: any, b: any): boolean => { if (a === b) { return true; } @@ -128,7 +128,7 @@ export function valueEqual(a: any, b: any): boolean { } -export function locationsAreEqual(a: LocationSegments, b: LocationSegments) { +export const locationsAreEqual = (a: LocationSegments, b: LocationSegments) => { return a.pathname === b.pathname && a.search === b.search && a.hash === b.hash && @@ -136,8 +136,9 @@ export function locationsAreEqual(a: LocationSegments, b: LocationSegments) { valueEqual(a.state, b.state); } -export function createLocation(path: string | LocationSegments, state: any, key: string, currentLocation?: LocationSegments): LocationSegments { - let location; +export const createLocation = (path: string | LocationSegments, state: any, key: string, currentLocation?: LocationSegments) => { + let location: LocationSegments; + if (typeof path === 'string') { // Two-arg form: push(path, state) location = parsePath(path); diff --git a/packages/router/src/utils/path-to-regex.ts b/packages/router/src/utils/path-to-regex.ts index 6cbfe26..8f8d6e1 100644 --- a/packages/router/src/utils/path-to-regex.ts +++ b/packages/router/src/utils/path-to-regex.ts @@ -37,13 +37,13 @@ export type PathFunction = (data?: { [key: string]: any }, options?: PathFunctio /** * Default configs. */ -var DEFAULT_DELIMITER = '/' -var DEFAULT_DELIMITERS = './' +const DEFAULT_DELIMITER = '/' +const DEFAULT_DELIMITERS = './' /** * The main path matching regexp utility. */ -var PATH_REGEXP = new RegExp([ +const PATH_REGEXP = new RegExp([ // Match escaped characters that would otherwise appear in future matches. // This allows the user to escape special characters that won't transform. '(\\\\.)', diff --git a/packages/router/src/utils/path-utils.ts b/packages/router/src/utils/path-utils.ts index 8924cea..9bc5e7a 100644 --- a/packages/router/src/utils/path-utils.ts +++ b/packages/router/src/utils/path-utils.ts @@ -1,30 +1,30 @@ import { LocationSegments } from '../global/interfaces'; -export function hasBasename(path: string, prefix: string) { +export const hasBasename = (path: string, prefix: string) => { return (new RegExp('^' + prefix + '(\\/|\\?|#|$)', 'i')).test(path); } -export function stripBasename(path: string, prefix: string) { +export const stripBasename = (path: string, prefix: string) => { return hasBasename(path, prefix) ? path.substr(prefix.length) : path; } -export function stripTrailingSlash(path: string) { +export const stripTrailingSlash = (path: string) => { return path.charAt(path.length - 1) === '/' ? path.slice(0, -1) : path; } -export function addLeadingSlash(path: string) { +export const addLeadingSlash = (path: string) => { return path.charAt(0) === '/' ? path : '/' + path; } -export function stripLeadingSlash(path: string) { +export const stripLeadingSlash = (path: string) => { return path.charAt(0) === '/' ? path.substr(1) : path; } -export function stripPrefix(path: string, prefix: string) { +export const stripPrefix = (path: string, prefix: string) => { return path.indexOf(prefix) === 0 ? path.substr(prefix.length) : path; } -export function parsePath(path: string): LocationSegments { +export const parsePath = (path: string): LocationSegments => { let pathname = path || '/'; let search = ''; let hash = ''; @@ -50,7 +50,7 @@ export function parsePath(path: string): LocationSegments { }; } -export function createPath(location: LocationSegments): string { +export const createPath = (location: LocationSegments) => { const { pathname, search, hash } = location; let path = pathname || '/'; @@ -65,7 +65,7 @@ export function createPath(location: LocationSegments): string { return path; } -export function parseQueryString(query: string) { +export const parseQueryString = (query: string) => { if (!query) { return { }; } diff --git a/packages/router/src/utils/shallow-equal.ts b/packages/router/src/utils/shallow-equal.ts index 11a7b6f..ebb1d59 100644 --- a/packages/router/src/utils/shallow-equal.ts +++ b/packages/router/src/utils/shallow-equal.ts @@ -12,13 +12,13 @@ 'use strict'; -var hasOwnProperty = Object.prototype.hasOwnProperty; +const hasOwnProperty = Object.prototype.hasOwnProperty; /** * inlined Object.is polyfill to avoid requiring consumers ship their own * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is */ -function is(x: any, y: any) { +const is = (x: any, y: any) => { // SameValue algorithm if (x === y) { // Steps 1-5, 7-10 @@ -36,7 +36,7 @@ function is(x: any, y: any) { * when any key has values which are not strictly equal between the arguments. * Returns true when the values of all keys are strictly equal. */ -export function shallowEqual(objA: any, objB: any) { +export const shallowEqual = (objA: any, objB: any) => { if (is(objA, objB)) { return true; }