-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathlocal-storage-events.ts
118 lines (106 loc) · 3.41 KB
/
local-storage-events.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { storage } from './storage';
import { isBrowser } from './is-browser'
export const LOCAL_STORAGE_CHANGE_EVENT_NAME = 'onLocalStorageChange';
/**
* CustomEvent polyfill derived from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
*/
(() => {
if (!isBrowser()) {
return;
}
if (typeof global.window.CustomEvent === 'function') {
return;
}
function CustomEvent<T>(
typeArg: string,
params: CustomEventInit<T> = { bubbles: false, cancelable: false }
): CustomEvent<T> {
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<TValue> {
key: string;
value: TValue;
}
/**
* Checks if the event that is passed in is the same type as LocalStorageChanged.
*
* @export
* @template TValue
* @param {*} evt the object you wish to assert as a onLocalStorageChange event.
* @returns {evt is LOCAL_STORAGE_CHANGE_EVENT_NAME} if true, evt is asserted to be onLocalStorageChange.
*/
export function isTypeOfLocalStorageChanged<TValue>(evt: CustomEvent): boolean {
return !!evt && evt.type === LOCAL_STORAGE_CHANGE_EVENT_NAME
}
/**
* Use this instead of directly using localStorage.setItem
* in order to correctly send events within the same window.
*
* @example
* ```js
* writeStorage('hello', JSON.stringify({ name: 'world' }));
* const { name } = JSON.parse(localStorage.getItem('hello'));
* ```
*
* @export
* @param {string} key The key to write to in the localStorage.
* @param {string} value The value to write to in the localStorage.
*/
export function writeStorage<TValue>(key: string, value: TValue) {
if (!isBrowser()) {
return;
}
try {
storage.setItem(key, typeof value === 'object' ? JSON.stringify(value) : `${value}`);
window.dispatchEvent(
new CustomEvent(LOCAL_STORAGE_CHANGE_EVENT_NAME, {
detail: { key, value },
})
)
} catch (err) {
if (err instanceof TypeError && err.message.includes('circular structure')) {
throw new TypeError(
'The object that was given to the writeStorage function has circular references.\n' +
'For more information, check here: ' +
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value'
);
}
throw err;
}
}
/**
* Use this function to delete a value from localStorage.
*
* After calling this function, the localStorage value will be null.
*
* @example
* ```js
* const user = { name: 'John', email: 'John@fakemail.com' };
*
* // Add a user to your localStorage
* writeStorage('user', JSON.stringify(user));
*
* // This will also trigger an update to the state of your component
* deleteFromStorage('user');
*
* localStorage.getItem('user') === null // ✔ This is now null
* ```
*
* @export
* @param {string} key The key of the item you wish to delete from localStorage.
*/
export function deleteFromStorage(key: string) {
if (!isBrowser()) {
return;
}
storage.removeItem(key);
window.dispatchEvent(
new CustomEvent(LOCAL_STORAGE_CHANGE_EVENT_NAME, {
detail: { key, value: null },
})
)
}