From df04273339d6fc4715e294975876722da0e5b98b Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 25 Jul 2021 13:20:40 -0400 Subject: [PATCH] Add CustomEvent polyfill (#78) * Change how localstorage events are created * Add CustomEvent polyfill * Use class again * Update node version * 2.4.2 * Update node versions --- .github/workflows/nodejs.yml | 2 +- .github/workflows/npmpublish.yml | 6 ++--- package-lock.json | 2 +- package.json | 2 +- src/index.ts | 2 +- src/local-storage-events.ts | 43 ++++++++++++++++++++++++------- src/use-localstorage.ts | 2 +- test/local-storage-events.test.ts | 17 ++++++------ 8 files changed, 49 insertions(+), 27 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 2fed7cb..f7d32fa 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: - node-version: [10.x, 12.x, 14.x] + node-version: [12.x, 14.x, 16.x] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml index 861e372..b422812 100644 --- a/.github/workflows/npmpublish.yml +++ b/.github/workflows/npmpublish.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 - run: npm ci - run: npm test @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 registry-url: https://registry.npmjs.org/ - run: npm ci - run: npm publish @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 registry-url: https://npm.pkg.github.com/ - run: npm ci - run: npm publish diff --git a/package-lock.json b/package-lock.json index 58a99e1..cf0f8fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@rehooks/local-storage", - "version": "2.4.1", + "version": "2.4.2", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 72786d5..9bf9c51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rehooks/local-storage", - "version": "2.4.1", + "version": "2.4.2", "description": "React hook for local-storage", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 66d9bac..8dc091b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { useLocalStorage } from './use-localstorage'; -export { writeStorage, deleteFromStorage } from './local-storage-events'; +export { writeStorage, deleteFromStorage, LocalStorageChanged } from './local-storage-events'; export { useLocalStorage }; diff --git a/src/local-storage-events.ts b/src/local-storage-events.ts index c6d9816..fe785e3 100644 --- a/src/local-storage-events.ts +++ b/src/local-storage-events.ts @@ -1,7 +1,32 @@ -import { storage } from './storage' -interface KVP { - key: K, - value: V +import { storage } from './storage'; + +/** + * CustomEvent polyfill derived from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent + */ +(() => { + if (typeof global.window === 'undefined') { + global.window = {} as unknown as Window & typeof globalThis; + } + + if (typeof global.window.CustomEvent === 'function') { + return; + } + + function CustomEvent( + typeArg: string, + params: CustomEventInit = { bubbles: false, cancelable: false } + ): CustomEvent { + const evt = document.createEvent('CustomEvent'); + evt.initCustomEvent(typeArg, params?.bubbles ?? false, params?.cancelable ?? false, params?.detail); + return evt; + } + + window.CustomEvent = CustomEvent as unknown as typeof window.CustomEvent; +})(); + +export interface LocalStorageEventPayload { + key: string; + value: TValue; } @@ -10,14 +35,12 @@ interface KVP { * have the ability of updating the LocalStorage from outside of the component, * but still update the component without prop drilling or creating a dependency * on a large library such as Redux. - * - * @class LocalStorageChanged - * @extends {CustomEvent>} */ -export class LocalStorageChanged extends CustomEvent> { + +export class LocalStorageChanged extends CustomEvent> { static eventName = 'onLocalStorageChange'; - constructor(payload: KVP) { + constructor(payload: LocalStorageEventPayload) { super(LocalStorageChanged.eventName, { detail: payload }); } } @@ -31,7 +54,7 @@ export class LocalStorageChanged extends CustomEvent * @returns {evt is LocalStorageChanged} if true, evt is asserted to be LocalStorageChanged. */ export function isTypeOfLocalStorageChanged(evt: any): evt is LocalStorageChanged { - return (!!evt) && (evt instanceof LocalStorageChanged || (evt.detail && evt.type === LocalStorageChanged.eventName)); + return !!evt && evt.type === LocalStorageChanged.eventName; } /** diff --git a/src/use-localstorage.ts b/src/use-localstorage.ts index 940d091..b448c4f 100644 --- a/src/use-localstorage.ts +++ b/src/use-localstorage.ts @@ -63,7 +63,7 @@ export function useLocalStorage( const onLocalStorageChange = (event: LocalStorageChanged | StorageEvent) => { // An event value can be of TValue when `localStorage.setItem` is called, or null when // `localStorage.removeItem` is called. - if (isTypeOfLocalStorageChanged(event)) { + if (isTypeOfLocalStorageChanged(event)) { if (event.detail.key === key) { updateLocalState(event.detail.value); } diff --git a/test/local-storage-events.test.ts b/test/local-storage-events.test.ts index b2190bb..130aa22 100644 --- a/test/local-storage-events.test.ts +++ b/test/local-storage-events.test.ts @@ -5,20 +5,19 @@ describe('Module: local-storage-events', () => { it('is constructable with an object containing key and value', () => { const key = 'foo'; const value = 'bar'; - + const localStorageChanged = new LocalStorageChanged({ key, value }); - - expect(localStorageChanged).toBeInstanceOf(LocalStorageChanged); + expect(localStorageChanged.detail.key).toBe(key); expect(localStorageChanged.detail.value).toBe(value); }); - + it('uses the correct event name', () => { const key = 'foo'; const value = 'bar'; - + const localStorageChanged = new LocalStorageChanged({ key, value }); - + expect(localStorageChanged.type).toBe(LocalStorageChanged.eventName); }); }); @@ -29,7 +28,7 @@ describe('Module: local-storage-events', () => { const value = 'bar'; writeStorage(key, value); - + expect(localStorage.getItem(key)).toBe(value); }); @@ -59,7 +58,7 @@ describe('Module: local-storage-events', () => { it('can write negative numbers', () => { const key = 'onestepforward'; const value = -2; - + writeStorage(key, value); expect(localStorage.getItem(key)).toBe(`${value}`); @@ -91,7 +90,7 @@ describe('Module: local-storage-events', () => { describe('when deleting a value that does not exist', () => { it('is still null', () => { const key = 'chocolate'; - + expect(localStorage.getItem(key)).toBe(null); expect(() => deleteFromStorage(key)).not.toThrow(); expect(localStorage.getItem(key)).toBe(null);