resonare 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -20
- package/dist/index.js +284 -1
- package/dist/index.js.map +1 -1
- package/dist/react.js +54 -1
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
- Framework-agnostic
|
|
14
14
|
- Prevent flicker on page load
|
|
15
15
|
- Honor system preferences
|
|
16
|
-
-
|
|
16
|
+
- Support sections with independent theming
|
|
17
17
|
- Sync theme selection across tabs and windows
|
|
18
18
|
- Flexible client-side persistence options, defaulting to localStorage
|
|
19
19
|
- Support server-side persistence
|
|
@@ -53,16 +53,14 @@ const CONFIG = {
|
|
|
53
53
|
},
|
|
54
54
|
} as const satisfies ThemeStoreConfig
|
|
55
55
|
|
|
56
|
-
export const themeScript = createInlineThemeScript(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
63
|
-
},
|
|
56
|
+
export const themeScript = createInlineThemeScript({
|
|
57
|
+
config: CONFIG,
|
|
58
|
+
handler: ({ resolvedThemes }) => {
|
|
59
|
+
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
60
|
+
document.documentElement.dataset[key] = value
|
|
61
|
+
})
|
|
64
62
|
},
|
|
65
|
-
|
|
63
|
+
})
|
|
66
64
|
```
|
|
67
65
|
|
|
68
66
|
### 2. Inject inline script
|
|
@@ -197,16 +195,14 @@ const CONFIG = {
|
|
|
197
195
|
},
|
|
198
196
|
} as const satisfies ThemeStoreConfig
|
|
199
197
|
|
|
200
|
-
const script = createInlineThemeScript(
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
})
|
|
207
|
-
},
|
|
198
|
+
const script = createInlineThemeScript({
|
|
199
|
+
config: CONFIG,
|
|
200
|
+
handler: ({ resolvedThemes }) => {
|
|
201
|
+
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
202
|
+
document.documentElement.dataset[key] = value
|
|
203
|
+
})
|
|
208
204
|
},
|
|
209
|
-
|
|
205
|
+
})
|
|
210
206
|
```
|
|
211
207
|
|
|
212
208
|
## Framework Integration
|
|
@@ -259,7 +255,7 @@ const PARAM = {
|
|
|
259
255
|
},
|
|
260
256
|
} as const satisfies ThemeScriptParameter
|
|
261
257
|
|
|
262
|
-
export const themeScript = createInlineThemeScript(
|
|
258
|
+
export const themeScript = createInlineThemeScript(PARAM)
|
|
263
259
|
|
|
264
260
|
const themeStore = createThemeStore(PARAM.config)
|
|
265
261
|
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,285 @@
|
|
|
1
|
-
|
|
1
|
+
//#region package.json
|
|
2
|
+
var name = "resonare";
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region src/storage.ts
|
|
5
|
+
/**
|
|
6
|
+
* Persists theme store in `localStorage` or `sessionStorage`.
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createThemeStore, localStorageAdapter } from 'resonare'
|
|
10
|
+
*
|
|
11
|
+
* const store = createThemeStore(
|
|
12
|
+
* { colorMode: { options: ['light', 'dark'] },
|
|
13
|
+
* { storage: localStorageAdapter({ key: 'app', type: 'localStorage' }) },
|
|
14
|
+
* )
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
const localStorageAdapter = ({ key, type = "localStorage" }) => {
|
|
18
|
+
return ({ abortController }) => {
|
|
19
|
+
return {
|
|
20
|
+
get: () => {
|
|
21
|
+
return JSON.parse(window[type].getItem(key) || "null");
|
|
22
|
+
},
|
|
23
|
+
set: (value) => {
|
|
24
|
+
window[type].setItem(key, JSON.stringify(value));
|
|
25
|
+
},
|
|
26
|
+
watch: (cb) => {
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
window.addEventListener("storage", (e) => {
|
|
29
|
+
if (e.storageArea !== window[type]) return;
|
|
30
|
+
if (e.key !== key) return;
|
|
31
|
+
cb(JSON.parse(e.newValue));
|
|
32
|
+
}, { signal: AbortSignal.any([abortController.signal, controller.signal]) });
|
|
33
|
+
return () => {
|
|
34
|
+
controller.abort();
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* In-memory persistence and sync via `BroadcastChannel`.
|
|
42
|
+
* Useful with server-side persistence.
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { createThemeStore, memoryStorageAdapter } from 'resonare'
|
|
46
|
+
*
|
|
47
|
+
* const store = createThemeStore(
|
|
48
|
+
* { colorMode: { options: ['light', 'dark'] },
|
|
49
|
+
* { storage: memoryStorageAdapter({ key: 'app' }) },
|
|
50
|
+
* )
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
const memoryStorageAdapter = ({ key }) => {
|
|
54
|
+
return ({ abortController }) => {
|
|
55
|
+
const storage = /* @__PURE__ */ new Map();
|
|
56
|
+
const channel = new BroadcastChannel(name);
|
|
57
|
+
return {
|
|
58
|
+
get: () => {
|
|
59
|
+
return storage.get(key) || null;
|
|
60
|
+
},
|
|
61
|
+
set: (value) => {
|
|
62
|
+
storage.set(key, value);
|
|
63
|
+
},
|
|
64
|
+
broadcast: (value) => {
|
|
65
|
+
channel.postMessage({
|
|
66
|
+
key,
|
|
67
|
+
value
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
watch: (cb) => {
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
channel.addEventListener("message", (e) => {
|
|
73
|
+
if (e.data.key !== key) return;
|
|
74
|
+
cb(e.data.value);
|
|
75
|
+
}, { signal: AbortSignal.any([abortController.signal, controller.signal]) });
|
|
76
|
+
return () => {
|
|
77
|
+
controller.abort();
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/index.ts
|
|
85
|
+
function getThemesAndOptions(config) {
|
|
86
|
+
return Object.entries(config).map(([themeKey, themeConfig]) => {
|
|
87
|
+
return [themeKey, (themeConfig.options || []).map((option) => typeof option === "object" ? option.value : option)];
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function getDefaultThemes(config) {
|
|
91
|
+
return Object.fromEntries(Object.entries(config).map(([themeKey, themeConfig]) => {
|
|
92
|
+
return [themeKey, themeConfig.initialValue ?? (typeof themeConfig.options[0] === "object" ? themeConfig.options[0].value : themeConfig.options[0])];
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
var ThemeStore = class {
|
|
96
|
+
#defaultThemes;
|
|
97
|
+
#currentThemes;
|
|
98
|
+
#keyedConfig;
|
|
99
|
+
#systemOptions;
|
|
100
|
+
#storage;
|
|
101
|
+
#mediaQueryCache = {};
|
|
102
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
103
|
+
#abortController = new AbortController();
|
|
104
|
+
constructor(config, { initialState = {}, storage = localStorageAdapter({ key: name }) } = {}) {
|
|
105
|
+
const systemOptions = {};
|
|
106
|
+
this.#defaultThemes = getDefaultThemes(config);
|
|
107
|
+
this.#currentThemes = {
|
|
108
|
+
...this.#defaultThemes,
|
|
109
|
+
...initialState.themes
|
|
110
|
+
};
|
|
111
|
+
this.#keyedConfig = Object.fromEntries(Object.entries(config).map(([themeKey, themeConfig]) => {
|
|
112
|
+
const entries = (themeConfig.options || []).map((option) => {
|
|
113
|
+
if (typeof option === "object") {
|
|
114
|
+
if (option.media) systemOptions[themeKey] = [option.media[1], option.media[2]];
|
|
115
|
+
return [String(option.value), option];
|
|
116
|
+
}
|
|
117
|
+
return [String(option), { value: option }];
|
|
118
|
+
});
|
|
119
|
+
return [themeKey, Object.fromEntries(entries)];
|
|
120
|
+
}));
|
|
121
|
+
this.#systemOptions = {
|
|
122
|
+
...systemOptions,
|
|
123
|
+
...initialState.systemOptions
|
|
124
|
+
};
|
|
125
|
+
this.#storage = storage?.({ abortController: this.#abortController }) ?? null;
|
|
126
|
+
}
|
|
127
|
+
getThemes = () => {
|
|
128
|
+
return this.#currentThemes;
|
|
129
|
+
};
|
|
130
|
+
getResolvedThemes = () => {
|
|
131
|
+
return Object.fromEntries(Object.entries(this.#currentThemes).map(([themeKey, optionKey]) => {
|
|
132
|
+
const option = this.#keyedConfig[themeKey]?.[optionKey];
|
|
133
|
+
return [themeKey, option ? this.#resolveThemeOption({
|
|
134
|
+
themeKey,
|
|
135
|
+
option
|
|
136
|
+
}) : optionKey];
|
|
137
|
+
}));
|
|
138
|
+
};
|
|
139
|
+
setThemes = (themes) => {
|
|
140
|
+
const updatedThemes = typeof themes === "function" ? themes(this.#currentThemes) : themes;
|
|
141
|
+
this.#setThemesAndNotify({
|
|
142
|
+
...this.#currentThemes,
|
|
143
|
+
...updatedThemes
|
|
144
|
+
});
|
|
145
|
+
const stateToPersist = this.toPersist();
|
|
146
|
+
if (this.#storage) {
|
|
147
|
+
this.#storage.set(stateToPersist);
|
|
148
|
+
this.#storage.broadcast?.(stateToPersist);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
updateSystemOption = (themeKey, [ifMatch, ifNotMatch]) => {
|
|
152
|
+
this.#systemOptions[themeKey] = [ifMatch, ifNotMatch];
|
|
153
|
+
this.setThemes({ ...this.#currentThemes });
|
|
154
|
+
};
|
|
155
|
+
toPersist = () => {
|
|
156
|
+
return {
|
|
157
|
+
themes: this.#currentThemes,
|
|
158
|
+
systemOptions: this.#systemOptions
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
restore = () => {
|
|
162
|
+
const persistedState = this.#storage?.get();
|
|
163
|
+
if (!persistedState) {
|
|
164
|
+
this.#setThemesAndNotify({ ...this.#defaultThemes });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
this.#systemOptions = {
|
|
168
|
+
...this.#systemOptions,
|
|
169
|
+
...persistedState.systemOptions
|
|
170
|
+
};
|
|
171
|
+
this.#setThemesAndNotify({
|
|
172
|
+
...this.#defaultThemes,
|
|
173
|
+
...persistedState.themes
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
subscribe = (callback) => {
|
|
177
|
+
this.#listeners.add(callback);
|
|
178
|
+
return () => {
|
|
179
|
+
this.#listeners.delete(callback);
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
sync = () => {
|
|
183
|
+
if (!this.#storage?.watch) return;
|
|
184
|
+
return this.#storage.watch((persistedState) => {
|
|
185
|
+
this.#systemOptions = persistedState.systemOptions;
|
|
186
|
+
this.#setThemesAndNotify(persistedState.themes);
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
/** Clears subscribers and aborts media-query listeners tied to this store instance. */
|
|
190
|
+
destroy = () => {
|
|
191
|
+
this.#listeners.clear();
|
|
192
|
+
this.#abortController.abort();
|
|
193
|
+
};
|
|
194
|
+
#setThemesAndNotify = (themes) => {
|
|
195
|
+
this.#currentThemes = themes;
|
|
196
|
+
for (const listener of this.#listeners) listener({
|
|
197
|
+
themes: this.#currentThemes,
|
|
198
|
+
resolvedThemes: this.getResolvedThemes()
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
#resolveThemeOption = ({ themeKey, option }) => {
|
|
202
|
+
if (!option.media) return option.value;
|
|
203
|
+
if (!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined")) {
|
|
204
|
+
if (!(process.env.NODE_ENV === "production")) console.warn(`[${name}] Option with key "media" cannot be resolved in server environment.`);
|
|
205
|
+
return option.value;
|
|
206
|
+
}
|
|
207
|
+
const cache = this.#mediaQueryCache;
|
|
208
|
+
const [mediaQuery] = option.media;
|
|
209
|
+
if (!cache[mediaQuery]) {
|
|
210
|
+
const mediaQueryList = window.matchMedia(mediaQuery);
|
|
211
|
+
cache[mediaQuery] = mediaQueryList;
|
|
212
|
+
mediaQueryList.addEventListener("change", () => {
|
|
213
|
+
if (this.#currentThemes[themeKey] === option.value) this.#setThemesAndNotify({ ...this.#currentThemes });
|
|
214
|
+
}, { signal: this.#abortController.signal });
|
|
215
|
+
}
|
|
216
|
+
const [ifMatch, ifNotMatch] = this.#systemOptions[themeKey];
|
|
217
|
+
return cache[mediaQuery].matches ? ifMatch : ifNotMatch;
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
function createThemeStore(config, options = {}) {
|
|
221
|
+
return new ThemeStore(config, options);
|
|
222
|
+
}
|
|
223
|
+
const restoreScript = (params) => {
|
|
224
|
+
params.forEach(([key, flattenedConfig, handler]) => {
|
|
225
|
+
const persistedThemes = JSON.parse(localStorage.getItem(key) || "{}").themes ?? {};
|
|
226
|
+
handler(flattenedConfig.reduce((acc, [themeKey, initial, systemOptionValue, mediaQuery, ifMatch, ifNotMatch]) => {
|
|
227
|
+
const currentValue = persistedThemes[themeKey] ?? initial;
|
|
228
|
+
acc.resolvedThemes[themeKey] = acc.themes[themeKey] = currentValue;
|
|
229
|
+
if (currentValue === systemOptionValue) acc.resolvedThemes[themeKey] = matchMedia(mediaQuery).matches ? ifMatch : ifNotMatch;
|
|
230
|
+
return acc;
|
|
231
|
+
}, {
|
|
232
|
+
themes: {},
|
|
233
|
+
resolvedThemes: {}
|
|
234
|
+
}));
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Creates an IIFE script string that reads persisted themes from `localStorage` and runs your handlers immediately.
|
|
239
|
+
*
|
|
240
|
+
* Useful for avoiding flash of incorrect styles.
|
|
241
|
+
* @example
|
|
242
|
+
* ```tsx
|
|
243
|
+
* import { createInlineThemeScript } from 'resonare'
|
|
244
|
+
*
|
|
245
|
+
* const inlineScript = createInlineThemeScript([
|
|
246
|
+
* {
|
|
247
|
+
* key: 'my-app',
|
|
248
|
+
* config: {
|
|
249
|
+
* colorMode: { options: ['light', 'dark'] },
|
|
250
|
+
* },
|
|
251
|
+
* handler: ({ resolvedThemes }) => {
|
|
252
|
+
* document.documentElement.dataset.colorMode = String(
|
|
253
|
+
* resolvedThemes.colorMode,
|
|
254
|
+
* )
|
|
255
|
+
* },
|
|
256
|
+
* },
|
|
257
|
+
* ])
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
function createInlineThemeScript(themeScriptParameters) {
|
|
261
|
+
return `(${restoreScript})([${(Array.isArray(themeScriptParameters) ? themeScriptParameters : [themeScriptParameters]).map(({ key = name, config, handler }) => {
|
|
262
|
+
const flattenedConfig = Object.entries(config).map(([themeKey, { options, initialValue }]) => {
|
|
263
|
+
const firstOption = options?.[0];
|
|
264
|
+
const resolvedInitialValue = initialValue ?? (typeof firstOption === "object" ? firstOption.value : firstOption);
|
|
265
|
+
const systemOption = options?.find((option) => typeof option === "object" && !!option.media);
|
|
266
|
+
if (systemOption) {
|
|
267
|
+
const { value, media: [mediaQuery, ifMatch, ifNotMatch] } = systemOption;
|
|
268
|
+
return [
|
|
269
|
+
themeKey,
|
|
270
|
+
resolvedInitialValue,
|
|
271
|
+
value,
|
|
272
|
+
mediaQuery,
|
|
273
|
+
ifMatch,
|
|
274
|
+
ifNotMatch
|
|
275
|
+
];
|
|
276
|
+
}
|
|
277
|
+
return [themeKey, resolvedInitialValue];
|
|
278
|
+
});
|
|
279
|
+
return `['${key}', ${JSON.stringify(flattenedConfig)}, ${handler}]`;
|
|
280
|
+
})}])`;
|
|
281
|
+
}
|
|
282
|
+
//#endregion
|
|
283
|
+
export { createInlineThemeScript, createThemeStore, getDefaultThemes, getThemesAndOptions, localStorageAdapter, memoryStorageAdapter };
|
|
284
|
+
|
|
2
285
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["name","PACKAGE_NAME","type","StorageAdapter","get","set","value","broadcast","watch","cb","StorageAdapterCreate","abortController","AbortController","StorageAdapterCreator","options","Options","localStorageAdapter","key","JSON","parse","window","getItem","setItem","stringify","controller","addEventListener","e","storageArea","newValue","signal","AbortSignal","any","abort","memoryStorageAdapter","storage","Map","channel","BroadcastChannel","postMessage","data","name","PACKAGE_NAME","type","localStorageAdapter","StorageAdapter","StorageAdapterCreate","ThemeValue","ThemeOption","value","T","media","ThemeConfig","options","ReadonlyArray","initialValue","ThemeStoreConfig","Record","KeyedThemeStoreConfig","Themes","K","U","Listener","themes","resolvedThemes","ThemeKeysWithSystemOption","NonSystemOptionValues","SystemOptions","PersistedState","Partial","systemOptions","ThemeStoreOptions","initialState","storage","ThemeAndOptions","Array","getThemesAndOptions","config","Object","entries","map","themeKey","themeConfig","option","getDefaultThemes","fromEntries","ThemeStore","defaultThemes","currentThemes","keyedConfig","mediaQueryCache","MediaQueryList","listeners","Set","abortController","AbortController","constructor","key","String","getThemes","getResolvedThemes","optionKey","resolveThemeOption","setThemes","updatedThemes","setThemesAndNotify","stateToPersist","toPersist","set","broadcast","updateSystemOption","ifMatch","ifNotMatch","restore","persistedState","get","subscribe","callback","add","delete","sync","watch","destroy","clear","abort","#setThemesAndNotify","listener","#resolveThemeOption","window","document","createElement","PROD","console","warn","cache","mediaQuery","mediaQueryList","matchMedia","addEventListener","signal","matches","createThemeStore","restoreScript","params","forEach","flattenedConfig","handler","persistedThemes","JSON","parse","localStorage","getItem","reduce","acc","initial","systemOptionValue","currentValue","ThemeScriptParameter","createInlineThemeScript","themeScriptParameters","serializedArgs","isArray","firstOption","resolvedInitialValue","systemOption","find","Required","stringify"],"sources":["../package.json","../src/storage.ts","../src/index.ts"],"sourcesContent":["","import { name as PACKAGE_NAME } from '../package.json' with { type: 'json' }\n\n/**\n * Pluggable persistence for `createThemeStore`.\n */\nexport type StorageAdapter = {\n\tget: () => object | null\n\tset: (value: object) => void\n\t/** Optional: notify other tabs/contexts after local `set` operation. */\n\tbroadcast?: (value: object) => void\n\t/** Optional: subscribes to other tabs/contexts' updates, returns `unsubscribe` function. */\n\twatch?: (cb: (value: object) => void) => () => void\n}\n\nexport type StorageAdapterCreate = ({\n\tabortController,\n}: {\n\tabortController: AbortController\n}) => StorageAdapter\n\nexport type StorageAdapterCreator<Options> = (\n\toptions: Options,\n) => StorageAdapterCreate\n\n/**\n * Persists theme store in `localStorage` or `sessionStorage`.\n * @example\n * ```ts\n * import { createThemeStore, localStorageAdapter } from 'resonare'\n *\n * const store = createThemeStore(\n * { colorMode: { options: ['light', 'dark'] },\n * { storage: localStorageAdapter({ key: 'app', type: 'localStorage' }) },\n * )\n * ```\n */\nexport const localStorageAdapter: StorageAdapterCreator<{\n\tkey: string\n\ttype?: 'localStorage' | 'sessionStorage'\n}> = ({ key, type = 'localStorage' }) => {\n\treturn ({ abortController }) => {\n\t\treturn {\n\t\t\tget: () => {\n\t\t\t\treturn JSON.parse(window[type].getItem(key) || 'null')\n\t\t\t},\n\n\t\t\tset: (value: object) => {\n\t\t\t\twindow[type].setItem(key, JSON.stringify(value))\n\t\t\t},\n\n\t\t\twatch: (cb) => {\n\t\t\t\tconst controller = new AbortController()\n\n\t\t\t\twindow.addEventListener(\n\t\t\t\t\t'storage',\n\t\t\t\t\t(e) => {\n\t\t\t\t\t\tif (e.storageArea !== window[type]) return\n\n\t\t\t\t\t\tif (e.key !== key) return\n\n\t\t\t\t\t\tcb(JSON.parse(e.newValue!))\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal: AbortSignal.any([\n\t\t\t\t\t\t\tabortController.signal,\n\t\t\t\t\t\t\tcontroller.signal,\n\t\t\t\t\t\t]),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn () => {\n\t\t\t\t\tcontroller.abort()\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}\n}\n\n/**\n * In-memory persistence and sync via `BroadcastChannel`.\n * Useful with server-side persistence.\n * @example\n * ```ts\n * import { createThemeStore, memoryStorageAdapter } from 'resonare'\n *\n * const store = createThemeStore(\n * { colorMode: { options: ['light', 'dark'] },\n * { storage: memoryStorageAdapter({ key: 'app' }) },\n * )\n * ```\n */\nexport const memoryStorageAdapter: StorageAdapterCreator<{\n\tkey: string\n}> = ({ key }) => {\n\treturn ({ abortController }) => {\n\t\tconst storage = new Map<string, object>()\n\t\tconst channel = new BroadcastChannel(PACKAGE_NAME)\n\n\t\treturn {\n\t\t\tget: () => {\n\t\t\t\treturn storage.get(key) || null\n\t\t\t},\n\n\t\t\tset: (value: object) => {\n\t\t\t\tstorage.set(key, value)\n\t\t\t},\n\n\t\t\tbroadcast: (value: object) => {\n\t\t\t\tchannel.postMessage({ key, value })\n\t\t\t},\n\n\t\t\twatch: (cb) => {\n\t\t\t\tconst controller = new AbortController()\n\n\t\t\t\tchannel.addEventListener(\n\t\t\t\t\t'message',\n\t\t\t\t\t(e) => {\n\t\t\t\t\t\tif (e.data.key !== key) return\n\n\t\t\t\t\t\tcb(e.data.value)\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal: AbortSignal.any([\n\t\t\t\t\t\t\tabortController.signal,\n\t\t\t\t\t\t\tcontroller.signal,\n\t\t\t\t\t\t]),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn () => {\n\t\t\t\t\tcontroller.abort()\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}\n}\n","import { name as PACKAGE_NAME } from '../package.json' with { type: 'json' }\nimport {\n\tlocalStorageAdapter,\n\ttype StorageAdapter,\n\ttype StorageAdapterCreate,\n} from './storage'\n\nexport * from './storage'\n\ntype ThemeValue = string | number | boolean\n\ntype ThemeOption<T extends ThemeValue = string> = {\n\tvalue: T\n\tmedia?: [string, T, T]\n}\n\ntype ThemeConfig<T extends ThemeValue = string> =\n\t| {\n\t\t\toptions: ReadonlyArray<T | ThemeOption<T>>\n\t\t\tinitialValue?: T\n\t }\n\t| { initialValue: T; options?: never }\n\nexport type ThemeStoreConfig = Record<\n\tstring,\n\tThemeConfig<string> | ThemeConfig<number> | ThemeConfig<boolean>\n>\n\n// { [themeKey]: { [optionKey]: ThemeOption } }\ntype KeyedThemeStoreConfig<T extends ThemeStoreConfig> = {\n\t[K in keyof T]: Record<string, ThemeOption>\n}\n\nexport type Themes<T extends ThemeStoreConfig> = {\n\t[K in keyof T]: T[K] extends { options: ReadonlyArray<infer U> }\n\t\t? U extends ThemeOption\n\t\t\t? U['value']\n\t\t\t: U\n\t\t: T[K] extends { initialValue: infer U }\n\t\t\t? U extends string\n\t\t\t\t? string\n\t\t\t\t: U extends number\n\t\t\t\t\t? number\n\t\t\t\t\t: boolean\n\t\t\t: never\n}\n\ntype Listener<T extends ThemeStoreConfig> = (value: {\n\tthemes: Themes<T>\n\tresolvedThemes: Themes<T>\n}) => void\n\ntype ThemeKeysWithSystemOption<T extends ThemeStoreConfig> = {\n\t[K in keyof T]: T[K] extends { options: ReadonlyArray<infer U> }\n\t\t? U extends { media: ReadonlyArray<unknown> }\n\t\t\t? K\n\t\t\t: never\n\t\t: never\n}[keyof T]\n\ntype NonSystemOptionValues<\n\tT extends ThemeStoreConfig,\n\tK extends keyof T,\n> = T[K] extends { options: ReadonlyArray<infer U> }\n\t? U extends ThemeValue\n\t\t? U\n\t\t: U extends ThemeOption\n\t\t\t? U extends { media: [string, string, string] }\n\t\t\t\t? never\n\t\t\t\t: U['value']\n\t\t\t: never\n\t: never\n\ntype SystemOptions<T extends ThemeStoreConfig> = {\n\t[K in ThemeKeysWithSystemOption<T>]?: [\n\t\tNonSystemOptionValues<T, K>,\n\t\tNonSystemOptionValues<T, K>,\n\t]\n}\n\ntype PersistedState<T extends ThemeStoreConfig> = {\n\tthemes: Partial<Themes<T>>\n\tsystemOptions: SystemOptions<T>\n}\n\ntype ThemeStoreOptions<T extends ThemeStoreConfig> = {\n\tinitialState?: Partial<PersistedState<T>>\n\tstorage?: StorageAdapterCreate | null\n}\n\ntype ThemeAndOptions<T extends ThemeStoreConfig> = Array<\n\t{\n\t\t[K in keyof T]: [\n\t\t\tK,\n\t\t\tArray<\n\t\t\t\tT[K] extends { options: ReadonlyArray<infer U> }\n\t\t\t\t\t? U extends ThemeOption\n\t\t\t\t\t\t? U['value']\n\t\t\t\t\t\t: U\n\t\t\t\t\t: never\n\t\t\t>,\n\t\t]\n\t}[keyof T]\n>\n\nexport function getThemesAndOptions<T extends ThemeStoreConfig>(config: T) {\n\treturn Object.entries(config).map(([themeKey, themeConfig]) => {\n\t\treturn [\n\t\t\tthemeKey,\n\t\t\t(themeConfig.options || []).map((option) =>\n\t\t\t\ttypeof option === 'object' ? option.value : option,\n\t\t\t),\n\t\t]\n\t}) as ThemeAndOptions<T>\n}\n\nexport function getDefaultThemes<T extends ThemeStoreConfig>(config: T) {\n\treturn Object.fromEntries(\n\t\tObject.entries(config).map(([themeKey, themeConfig]) => {\n\t\t\treturn [\n\t\t\t\tthemeKey,\n\t\t\t\tthemeConfig.initialValue ??\n\t\t\t\t\t(typeof themeConfig.options[0] === 'object'\n\t\t\t\t\t\t? themeConfig.options[0].value\n\t\t\t\t\t\t: themeConfig.options[0]),\n\t\t\t]\n\t\t}),\n\t) as Themes<T>\n}\n\nclass ThemeStore<T extends ThemeStoreConfig> {\n\t#defaultThemes: Themes<T>\n\n\t#currentThemes: Themes<T>\n\n\t#keyedConfig: KeyedThemeStoreConfig<T>\n\n\t#systemOptions: SystemOptions<T>\n\n\t#storage: StorageAdapter | null\n\n\t#mediaQueryCache: Record<string, MediaQueryList> = {}\n\n\t#listeners: Set<Listener<T>> = new Set<Listener<T>>()\n\n\t#abortController = new AbortController()\n\n\tconstructor(\n\t\tconfig: T,\n\t\t{\n\t\t\tinitialState = {},\n\t\t\tstorage = localStorageAdapter({ key: PACKAGE_NAME }),\n\t\t}: ThemeStoreOptions<T> = {},\n\t) {\n\t\tconst systemOptions: Record<string, [ThemeValue, ThemeValue]> = {}\n\n\t\tthis.#defaultThemes = getDefaultThemes(config)\n\n\t\tthis.#currentThemes = { ...this.#defaultThemes, ...initialState.themes }\n\n\t\tthis.#keyedConfig = Object.fromEntries(\n\t\t\tObject.entries(config).map(([themeKey, themeConfig]) => {\n\t\t\t\tconst entries = (themeConfig.options || []).map((option) => {\n\t\t\t\t\tif (typeof option === 'object') {\n\t\t\t\t\t\tif (option.media) {\n\t\t\t\t\t\t\tsystemOptions[themeKey] = [option.media[1], option.media[2]]\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn [String(option.value), option]\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [String(option), { value: option }]\n\t\t\t\t})\n\n\t\t\t\treturn [themeKey, Object.fromEntries(entries)]\n\t\t\t}),\n\t\t) as KeyedThemeStoreConfig<T>\n\n\t\tthis.#systemOptions = { ...systemOptions, ...initialState.systemOptions }\n\n\t\tthis.#storage =\n\t\t\tstorage?.({\n\t\t\t\tabortController: this.#abortController,\n\t\t\t}) ?? null\n\t}\n\n\tgetThemes = (): Themes<T> => {\n\t\treturn this.#currentThemes\n\t}\n\n\tgetResolvedThemes = (): Themes<T> => {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(this.#currentThemes).map(([themeKey, optionKey]) => {\n\t\t\t\tconst option = this.#keyedConfig[themeKey]?.[optionKey]\n\n\t\t\t\treturn [\n\t\t\t\t\tthemeKey,\n\t\t\t\t\toption ? this.#resolveThemeOption({ themeKey, option }) : optionKey,\n\t\t\t\t]\n\t\t\t}),\n\t\t) as Themes<T>\n\t}\n\n\tsetThemes = (\n\t\tthemes:\n\t\t\t| Partial<Themes<T>>\n\t\t\t| ((currentThemes: Themes<T>) => Partial<Themes<T>>),\n\t): void => {\n\t\tconst updatedThemes =\n\t\t\ttypeof themes === 'function' ? themes(this.#currentThemes) : themes\n\n\t\tthis.#setThemesAndNotify({ ...this.#currentThemes, ...updatedThemes })\n\n\t\tconst stateToPersist = this.toPersist()\n\n\t\tif (this.#storage) {\n\t\t\tthis.#storage.set(stateToPersist)\n\t\t\tthis.#storage.broadcast?.(stateToPersist)\n\t\t}\n\t}\n\n\tupdateSystemOption = <K extends ThemeKeysWithSystemOption<T>>(\n\t\tthemeKey: K,\n\t\t[ifMatch, ifNotMatch]: [\n\t\t\tNonSystemOptionValues<T, K>,\n\t\t\tNonSystemOptionValues<T, K>,\n\t\t],\n\t): void => {\n\t\tthis.#systemOptions[themeKey] = [ifMatch, ifNotMatch]\n\n\t\tthis.setThemes({ ...this.#currentThemes })\n\t}\n\n\ttoPersist = (): PersistedState<T> => {\n\t\treturn {\n\t\t\tthemes: this.#currentThemes,\n\t\t\tsystemOptions: this.#systemOptions,\n\t\t}\n\t}\n\n\trestore = (): void => {\n\t\tconst persistedState = this.#storage?.get()\n\n\t\tif (!persistedState) {\n\t\t\tthis.#setThemesAndNotify({ ...this.#defaultThemes })\n\t\t\treturn\n\t\t}\n\n\t\tthis.#systemOptions = {\n\t\t\t...this.#systemOptions,\n\t\t\t...persistedState.systemOptions,\n\t\t}\n\n\t\tthis.#setThemesAndNotify({\n\t\t\t...this.#defaultThemes,\n\t\t\t...persistedState.themes,\n\t\t})\n\t}\n\n\tsubscribe = (callback: Listener<T>): (() => void) => {\n\t\tthis.#listeners.add(callback)\n\n\t\treturn () => {\n\t\t\tthis.#listeners.delete(callback)\n\t\t}\n\t}\n\n\tsync = (): (() => void) | undefined => {\n\t\tif (!this.#storage?.watch) return\n\n\t\treturn this.#storage.watch((persistedState) => {\n\t\t\tthis.#systemOptions = (persistedState as PersistedState<T>).systemOptions\n\n\t\t\tthis.#setThemesAndNotify((persistedState as PersistedState<T>).themes)\n\t\t})\n\t}\n\n\t/** Clears subscribers and aborts media-query listeners tied to this store instance. */\n\tdestroy = (): void => {\n\t\tthis.#listeners.clear()\n\t\tthis.#abortController.abort()\n\t}\n\n\t#setThemesAndNotify = (themes: Themes<T>): void => {\n\t\tthis.#currentThemes = themes\n\n\t\tfor (const listener of this.#listeners) {\n\t\t\tlistener({\n\t\t\t\tthemes: this.#currentThemes,\n\t\t\t\tresolvedThemes: this.getResolvedThemes(),\n\t\t\t})\n\t\t}\n\t}\n\n\t#resolveThemeOption = ({\n\t\tthemeKey,\n\t\toption,\n\t}: {\n\t\tthemeKey: string\n\t\toption: ThemeOption\n\t}): string => {\n\t\tif (!option.media) return option.value\n\n\t\tif (\n\t\t\t!(\n\t\t\t\ttypeof window !== 'undefined' &&\n\t\t\t\ttypeof window.document !== 'undefined' &&\n\t\t\t\ttypeof window.document.createElement !== 'undefined'\n\t\t\t)\n\t\t) {\n\t\t\tif (!PROD) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[${PACKAGE_NAME}] Option with key \"media\" cannot be resolved in server environment.`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn option.value\n\t\t}\n\n\t\tconst cache = this.#mediaQueryCache\n\n\t\tconst [mediaQuery] = option.media\n\n\t\tif (!cache[mediaQuery]) {\n\t\t\tconst mediaQueryList = window.matchMedia(mediaQuery)\n\n\t\t\tcache[mediaQuery] = mediaQueryList\n\n\t\t\tmediaQueryList.addEventListener(\n\t\t\t\t'change',\n\t\t\t\t() => {\n\t\t\t\t\tif (this.#currentThemes[themeKey] === option.value) {\n\t\t\t\t\t\tthis.#setThemesAndNotify({ ...this.#currentThemes })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ signal: this.#abortController.signal },\n\t\t\t)\n\t\t}\n\n\t\tconst [ifMatch, ifNotMatch] = this.#systemOptions[themeKey]!\n\n\t\treturn cache[mediaQuery].matches ? ifMatch : ifNotMatch\n\t}\n}\n\nexport type { ThemeStore }\n\nexport function createThemeStore<T extends ThemeStoreConfig>(\n\tconfig: T,\n\toptions: ThemeStoreOptions<T> = {},\n): ThemeStore<T> {\n\treturn new ThemeStore<T>(config, options)\n}\n\nconst restoreScript = <T extends ThemeValue>(\n\tparams: Array<\n\t\t[string, Array<[string, T] | [string, T, T, string, T, T]>, Listener<any>]\n\t>,\n) => {\n\tparams.forEach(([key, flattenedConfig, handler]) => {\n\t\tconst persistedThemes =\n\t\t\tJSON.parse(localStorage.getItem(key) || '{}').themes ?? {}\n\n\t\thandler(\n\t\t\tflattenedConfig.reduce<{\n\t\t\t\tthemes: Record<string, ThemeValue>\n\t\t\t\tresolvedThemes: Record<string, ThemeValue>\n\t\t\t}>(\n\t\t\t\t(\n\t\t\t\t\tacc,\n\t\t\t\t\t[\n\t\t\t\t\t\tthemeKey,\n\t\t\t\t\t\tinitial,\n\t\t\t\t\t\tsystemOptionValue,\n\t\t\t\t\t\tmediaQuery,\n\t\t\t\t\t\tifMatch,\n\t\t\t\t\t\tifNotMatch,\n\t\t\t\t\t],\n\t\t\t\t) => {\n\t\t\t\t\tconst currentValue = persistedThemes[themeKey] ?? initial\n\n\t\t\t\t\tacc.resolvedThemes[themeKey] = acc.themes[themeKey] = currentValue\n\n\t\t\t\t\tif (currentValue === systemOptionValue) {\n\t\t\t\t\t\tacc.resolvedThemes[themeKey] = matchMedia(mediaQuery!).matches\n\t\t\t\t\t\t\t? ifMatch!\n\t\t\t\t\t\t\t: ifNotMatch!\n\t\t\t\t\t}\n\n\t\t\t\t\treturn acc\n\t\t\t\t},\n\t\t\t\t{ themes: {}, resolvedThemes: {} },\n\t\t\t),\n\t\t)\n\t})\n}\n\nexport type ThemeScriptParameter = {\n\t/** `localStorage` key; defaults to the 'resonare'. */\n\tkey?: string\n\tconfig: ThemeStoreConfig\n\thandler: Listener<any>\n}\n\n/**\n * Creates an IIFE script string that reads persisted themes from `localStorage` and runs your handlers immediately.\n *\n * Useful for avoiding flash of incorrect styles.\n * @example\n * ```tsx\n * import { createInlineThemeScript } from 'resonare'\n *\n * const inlineScript = createInlineThemeScript([\n * {\n * key: 'my-app',\n * config: {\n * colorMode: { options: ['light', 'dark'] },\n * },\n * handler: ({ resolvedThemes }) => {\n * document.documentElement.dataset.colorMode = String(\n * resolvedThemes.colorMode,\n * )\n * },\n * },\n * ])\n * ```\n */\nexport function createInlineThemeScript(\n\tthemeScriptParameters: ThemeScriptParameter | Array<ThemeScriptParameter>,\n) {\n\tconst serializedArgs = (\n\t\tArray.isArray(themeScriptParameters)\n\t\t\t? themeScriptParameters\n\t\t\t: [themeScriptParameters]\n\t).map(({ key = PACKAGE_NAME, config, handler }) => {\n\t\tconst flattenedConfig = Object.entries(config).map(\n\t\t\t([themeKey, { options, initialValue }]) => {\n\t\t\t\tconst firstOption = options?.[0]\n\n\t\t\t\tconst resolvedInitialValue =\n\t\t\t\t\tinitialValue ??\n\t\t\t\t\t(typeof firstOption === 'object' ? firstOption.value : firstOption!)\n\n\t\t\t\tconst systemOption = options?.find(\n\t\t\t\t\t(option): option is Required<ThemeOption> =>\n\t\t\t\t\t\ttypeof option === 'object' && !!option.media,\n\t\t\t\t)\n\n\t\t\t\tif (systemOption) {\n\t\t\t\t\tconst {\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tmedia: [mediaQuery, ifMatch, ifNotMatch],\n\t\t\t\t\t} = systemOption\n\n\t\t\t\t\treturn [\n\t\t\t\t\t\tthemeKey,\n\t\t\t\t\t\tresolvedInitialValue,\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tmediaQuery,\n\t\t\t\t\t\tifMatch,\n\t\t\t\t\t\tifNotMatch,\n\t\t\t\t\t]\n\t\t\t\t}\n\n\t\t\t\treturn [themeKey, resolvedInitialValue]\n\t\t\t},\n\t\t)\n\n\t\treturn `['${key}', ${JSON.stringify(flattenedConfig)}, ${handler}]`\n\t})\n\n\treturn `(${restoreScript})([${serializedArgs}])`\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["name","PACKAGE_NAME","type","StorageAdapter","get","set","value","broadcast","watch","cb","StorageAdapterCreate","abortController","AbortController","StorageAdapterCreator","options","Options","localStorageAdapter","key","JSON","parse","window","getItem","setItem","stringify","controller","addEventListener","e","storageArea","newValue","signal","AbortSignal","any","abort","memoryStorageAdapter","storage","Map","channel","BroadcastChannel","postMessage","data","name","PACKAGE_NAME","type","localStorageAdapter","StorageAdapter","StorageAdapterCreate","ThemeValue","ThemeOption","value","T","media","ThemeConfig","options","ReadonlyArray","initialValue","ThemeStoreConfig","Record","KeyedThemeStoreConfig","Themes","K","U","Listener","themes","resolvedThemes","ThemeKeysWithSystemOption","NonSystemOptionValues","SystemOptions","PersistedState","Partial","systemOptions","ThemeStoreOptions","initialState","storage","ThemeAndOptions","Array","getThemesAndOptions","config","Object","entries","map","themeKey","themeConfig","option","getDefaultThemes","fromEntries","ThemeStore","defaultThemes","currentThemes","keyedConfig","mediaQueryCache","MediaQueryList","listeners","Set","abortController","AbortController","constructor","key","String","getThemes","getResolvedThemes","optionKey","resolveThemeOption","setThemes","updatedThemes","setThemesAndNotify","stateToPersist","toPersist","set","broadcast","updateSystemOption","ifMatch","ifNotMatch","restore","persistedState","get","subscribe","callback","add","delete","sync","watch","destroy","clear","abort","#setThemesAndNotify","listener","#resolveThemeOption","window","document","createElement","PROD","console","warn","cache","mediaQuery","mediaQueryList","matchMedia","addEventListener","signal","matches","createThemeStore","restoreScript","params","forEach","flattenedConfig","handler","persistedThemes","JSON","parse","localStorage","getItem","reduce","acc","initial","systemOptionValue","currentValue","ThemeScriptParameter","createInlineThemeScript","themeScriptParameters","serializedArgs","isArray","firstOption","resolvedInitialValue","systemOption","find","Required","stringify"],"sources":["../package.json","../src/storage.ts","../src/index.ts"],"sourcesContent":["","import { name as PACKAGE_NAME } from '../package.json' with { type: 'json' }\n\n/**\n * Pluggable persistence for `createThemeStore`.\n */\nexport type StorageAdapter = {\n\tget: () => object | null\n\tset: (value: object) => void\n\t/** Optional: notify other tabs/contexts after local `set` operation. */\n\tbroadcast?: (value: object) => void\n\t/** Optional: subscribes to other tabs/contexts' updates, returns `unsubscribe` function. */\n\twatch?: (cb: (value: object) => void) => () => void\n}\n\nexport type StorageAdapterCreate = ({\n\tabortController,\n}: {\n\tabortController: AbortController\n}) => StorageAdapter\n\nexport type StorageAdapterCreator<Options> = (\n\toptions: Options,\n) => StorageAdapterCreate\n\n/**\n * Persists theme store in `localStorage` or `sessionStorage`.\n * @example\n * ```ts\n * import { createThemeStore, localStorageAdapter } from 'resonare'\n *\n * const store = createThemeStore(\n * { colorMode: { options: ['light', 'dark'] },\n * { storage: localStorageAdapter({ key: 'app', type: 'localStorage' }) },\n * )\n * ```\n */\nexport const localStorageAdapter: StorageAdapterCreator<{\n\tkey: string\n\ttype?: 'localStorage' | 'sessionStorage'\n}> = ({ key, type = 'localStorage' }) => {\n\treturn ({ abortController }) => {\n\t\treturn {\n\t\t\tget: () => {\n\t\t\t\treturn JSON.parse(window[type].getItem(key) || 'null')\n\t\t\t},\n\n\t\t\tset: (value: object) => {\n\t\t\t\twindow[type].setItem(key, JSON.stringify(value))\n\t\t\t},\n\n\t\t\twatch: (cb) => {\n\t\t\t\tconst controller = new AbortController()\n\n\t\t\t\twindow.addEventListener(\n\t\t\t\t\t'storage',\n\t\t\t\t\t(e) => {\n\t\t\t\t\t\tif (e.storageArea !== window[type]) return\n\n\t\t\t\t\t\tif (e.key !== key) return\n\n\t\t\t\t\t\tcb(JSON.parse(e.newValue!))\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal: AbortSignal.any([\n\t\t\t\t\t\t\tabortController.signal,\n\t\t\t\t\t\t\tcontroller.signal,\n\t\t\t\t\t\t]),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn () => {\n\t\t\t\t\tcontroller.abort()\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}\n}\n\n/**\n * In-memory persistence and sync via `BroadcastChannel`.\n * Useful with server-side persistence.\n * @example\n * ```ts\n * import { createThemeStore, memoryStorageAdapter } from 'resonare'\n *\n * const store = createThemeStore(\n * { colorMode: { options: ['light', 'dark'] },\n * { storage: memoryStorageAdapter({ key: 'app' }) },\n * )\n * ```\n */\nexport const memoryStorageAdapter: StorageAdapterCreator<{\n\tkey: string\n}> = ({ key }) => {\n\treturn ({ abortController }) => {\n\t\tconst storage = new Map<string, object>()\n\t\tconst channel = new BroadcastChannel(PACKAGE_NAME)\n\n\t\treturn {\n\t\t\tget: () => {\n\t\t\t\treturn storage.get(key) || null\n\t\t\t},\n\n\t\t\tset: (value: object) => {\n\t\t\t\tstorage.set(key, value)\n\t\t\t},\n\n\t\t\tbroadcast: (value: object) => {\n\t\t\t\tchannel.postMessage({ key, value })\n\t\t\t},\n\n\t\t\twatch: (cb) => {\n\t\t\t\tconst controller = new AbortController()\n\n\t\t\t\tchannel.addEventListener(\n\t\t\t\t\t'message',\n\t\t\t\t\t(e) => {\n\t\t\t\t\t\tif (e.data.key !== key) return\n\n\t\t\t\t\t\tcb(e.data.value)\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal: AbortSignal.any([\n\t\t\t\t\t\t\tabortController.signal,\n\t\t\t\t\t\t\tcontroller.signal,\n\t\t\t\t\t\t]),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn () => {\n\t\t\t\t\tcontroller.abort()\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}\n}\n","import { name as PACKAGE_NAME } from '../package.json' with { type: 'json' }\nimport {\n\tlocalStorageAdapter,\n\ttype StorageAdapter,\n\ttype StorageAdapterCreate,\n} from './storage'\n\nexport * from './storage'\n\ntype ThemeValue = string | number | boolean\n\ntype ThemeOption<T extends ThemeValue = string> = {\n\tvalue: T\n\tmedia?: [string, T, T]\n}\n\ntype ThemeConfig<T extends ThemeValue = string> =\n\t| {\n\t\t\toptions: ReadonlyArray<T | ThemeOption<T>>\n\t\t\tinitialValue?: T\n\t }\n\t| { initialValue: T; options?: never }\n\nexport type ThemeStoreConfig = Record<\n\tstring,\n\tThemeConfig<string> | ThemeConfig<number> | ThemeConfig<boolean>\n>\n\n// { [themeKey]: { [optionKey]: ThemeOption } }\ntype KeyedThemeStoreConfig<T extends ThemeStoreConfig> = {\n\t[K in keyof T]: Record<string, ThemeOption>\n}\n\nexport type Themes<T extends ThemeStoreConfig> = {\n\t[K in keyof T]: T[K] extends { options: ReadonlyArray<infer U> }\n\t\t? U extends ThemeOption\n\t\t\t? U['value']\n\t\t\t: U\n\t\t: T[K] extends { initialValue: infer U }\n\t\t\t? U extends string\n\t\t\t\t? string\n\t\t\t\t: U extends number\n\t\t\t\t\t? number\n\t\t\t\t\t: boolean\n\t\t\t: never\n}\n\ntype Listener<T extends ThemeStoreConfig> = (value: {\n\tthemes: Themes<T>\n\tresolvedThemes: Themes<T>\n}) => void\n\ntype ThemeKeysWithSystemOption<T extends ThemeStoreConfig> = {\n\t[K in keyof T]: T[K] extends { options: ReadonlyArray<infer U> }\n\t\t? U extends { media: ReadonlyArray<unknown> }\n\t\t\t? K\n\t\t\t: never\n\t\t: never\n}[keyof T]\n\ntype NonSystemOptionValues<\n\tT extends ThemeStoreConfig,\n\tK extends keyof T,\n> = T[K] extends { options: ReadonlyArray<infer U> }\n\t? U extends ThemeValue\n\t\t? U\n\t\t: U extends ThemeOption\n\t\t\t? U extends { media: [string, string, string] }\n\t\t\t\t? never\n\t\t\t\t: U['value']\n\t\t\t: never\n\t: never\n\ntype SystemOptions<T extends ThemeStoreConfig> = {\n\t[K in ThemeKeysWithSystemOption<T>]?: [\n\t\tNonSystemOptionValues<T, K>,\n\t\tNonSystemOptionValues<T, K>,\n\t]\n}\n\ntype PersistedState<T extends ThemeStoreConfig> = {\n\tthemes: Partial<Themes<T>>\n\tsystemOptions: SystemOptions<T>\n}\n\ntype ThemeStoreOptions<T extends ThemeStoreConfig> = {\n\tinitialState?: Partial<PersistedState<T>>\n\tstorage?: StorageAdapterCreate | null\n}\n\ntype ThemeAndOptions<T extends ThemeStoreConfig> = Array<\n\t{\n\t\t[K in keyof T]: [\n\t\t\tK,\n\t\t\tArray<\n\t\t\t\tT[K] extends { options: ReadonlyArray<infer U> }\n\t\t\t\t\t? U extends ThemeOption\n\t\t\t\t\t\t? U['value']\n\t\t\t\t\t\t: U\n\t\t\t\t\t: never\n\t\t\t>,\n\t\t]\n\t}[keyof T]\n>\n\nexport function getThemesAndOptions<T extends ThemeStoreConfig>(config: T) {\n\treturn Object.entries(config).map(([themeKey, themeConfig]) => {\n\t\treturn [\n\t\t\tthemeKey,\n\t\t\t(themeConfig.options || []).map((option) =>\n\t\t\t\ttypeof option === 'object' ? option.value : option,\n\t\t\t),\n\t\t]\n\t}) as ThemeAndOptions<T>\n}\n\nexport function getDefaultThemes<T extends ThemeStoreConfig>(config: T) {\n\treturn Object.fromEntries(\n\t\tObject.entries(config).map(([themeKey, themeConfig]) => {\n\t\t\treturn [\n\t\t\t\tthemeKey,\n\t\t\t\tthemeConfig.initialValue ??\n\t\t\t\t\t(typeof themeConfig.options[0] === 'object'\n\t\t\t\t\t\t? themeConfig.options[0].value\n\t\t\t\t\t\t: themeConfig.options[0]),\n\t\t\t]\n\t\t}),\n\t) as Themes<T>\n}\n\nclass ThemeStore<T extends ThemeStoreConfig> {\n\t#defaultThemes: Themes<T>\n\n\t#currentThemes: Themes<T>\n\n\t#keyedConfig: KeyedThemeStoreConfig<T>\n\n\t#systemOptions: SystemOptions<T>\n\n\t#storage: StorageAdapter | null\n\n\t#mediaQueryCache: Record<string, MediaQueryList> = {}\n\n\t#listeners: Set<Listener<T>> = new Set<Listener<T>>()\n\n\t#abortController = new AbortController()\n\n\tconstructor(\n\t\tconfig: T,\n\t\t{\n\t\t\tinitialState = {},\n\t\t\tstorage = localStorageAdapter({ key: PACKAGE_NAME }),\n\t\t}: ThemeStoreOptions<T> = {},\n\t) {\n\t\tconst systemOptions: Record<string, [ThemeValue, ThemeValue]> = {}\n\n\t\tthis.#defaultThemes = getDefaultThemes(config)\n\n\t\tthis.#currentThemes = { ...this.#defaultThemes, ...initialState.themes }\n\n\t\tthis.#keyedConfig = Object.fromEntries(\n\t\t\tObject.entries(config).map(([themeKey, themeConfig]) => {\n\t\t\t\tconst entries = (themeConfig.options || []).map((option) => {\n\t\t\t\t\tif (typeof option === 'object') {\n\t\t\t\t\t\tif (option.media) {\n\t\t\t\t\t\t\tsystemOptions[themeKey] = [option.media[1], option.media[2]]\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn [String(option.value), option]\n\t\t\t\t\t}\n\n\t\t\t\t\treturn [String(option), { value: option }]\n\t\t\t\t})\n\n\t\t\t\treturn [themeKey, Object.fromEntries(entries)]\n\t\t\t}),\n\t\t) as KeyedThemeStoreConfig<T>\n\n\t\tthis.#systemOptions = { ...systemOptions, ...initialState.systemOptions }\n\n\t\tthis.#storage =\n\t\t\tstorage?.({\n\t\t\t\tabortController: this.#abortController,\n\t\t\t}) ?? null\n\t}\n\n\tgetThemes = (): Themes<T> => {\n\t\treturn this.#currentThemes\n\t}\n\n\tgetResolvedThemes = (): Themes<T> => {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(this.#currentThemes).map(([themeKey, optionKey]) => {\n\t\t\t\tconst option = this.#keyedConfig[themeKey]?.[optionKey]\n\n\t\t\t\treturn [\n\t\t\t\t\tthemeKey,\n\t\t\t\t\toption ? this.#resolveThemeOption({ themeKey, option }) : optionKey,\n\t\t\t\t]\n\t\t\t}),\n\t\t) as Themes<T>\n\t}\n\n\tsetThemes = (\n\t\tthemes:\n\t\t\t| Partial<Themes<T>>\n\t\t\t| ((currentThemes: Themes<T>) => Partial<Themes<T>>),\n\t): void => {\n\t\tconst updatedThemes =\n\t\t\ttypeof themes === 'function' ? themes(this.#currentThemes) : themes\n\n\t\tthis.#setThemesAndNotify({ ...this.#currentThemes, ...updatedThemes })\n\n\t\tconst stateToPersist = this.toPersist()\n\n\t\tif (this.#storage) {\n\t\t\tthis.#storage.set(stateToPersist)\n\t\t\tthis.#storage.broadcast?.(stateToPersist)\n\t\t}\n\t}\n\n\tupdateSystemOption = <K extends ThemeKeysWithSystemOption<T>>(\n\t\tthemeKey: K,\n\t\t[ifMatch, ifNotMatch]: [\n\t\t\tNonSystemOptionValues<T, K>,\n\t\t\tNonSystemOptionValues<T, K>,\n\t\t],\n\t): void => {\n\t\tthis.#systemOptions[themeKey] = [ifMatch, ifNotMatch]\n\n\t\tthis.setThemes({ ...this.#currentThemes })\n\t}\n\n\ttoPersist = (): PersistedState<T> => {\n\t\treturn {\n\t\t\tthemes: this.#currentThemes,\n\t\t\tsystemOptions: this.#systemOptions,\n\t\t}\n\t}\n\n\trestore = (): void => {\n\t\tconst persistedState = this.#storage?.get()\n\n\t\tif (!persistedState) {\n\t\t\tthis.#setThemesAndNotify({ ...this.#defaultThemes })\n\t\t\treturn\n\t\t}\n\n\t\tthis.#systemOptions = {\n\t\t\t...this.#systemOptions,\n\t\t\t...persistedState.systemOptions,\n\t\t}\n\n\t\tthis.#setThemesAndNotify({\n\t\t\t...this.#defaultThemes,\n\t\t\t...persistedState.themes,\n\t\t})\n\t}\n\n\tsubscribe = (callback: Listener<T>): (() => void) => {\n\t\tthis.#listeners.add(callback)\n\n\t\treturn () => {\n\t\t\tthis.#listeners.delete(callback)\n\t\t}\n\t}\n\n\tsync = (): (() => void) | undefined => {\n\t\tif (!this.#storage?.watch) return\n\n\t\treturn this.#storage.watch((persistedState) => {\n\t\t\tthis.#systemOptions = (persistedState as PersistedState<T>).systemOptions\n\n\t\t\tthis.#setThemesAndNotify((persistedState as PersistedState<T>).themes)\n\t\t})\n\t}\n\n\t/** Clears subscribers and aborts media-query listeners tied to this store instance. */\n\tdestroy = (): void => {\n\t\tthis.#listeners.clear()\n\t\tthis.#abortController.abort()\n\t}\n\n\t#setThemesAndNotify = (themes: Themes<T>): void => {\n\t\tthis.#currentThemes = themes\n\n\t\tfor (const listener of this.#listeners) {\n\t\t\tlistener({\n\t\t\t\tthemes: this.#currentThemes,\n\t\t\t\tresolvedThemes: this.getResolvedThemes(),\n\t\t\t})\n\t\t}\n\t}\n\n\t#resolveThemeOption = ({\n\t\tthemeKey,\n\t\toption,\n\t}: {\n\t\tthemeKey: string\n\t\toption: ThemeOption\n\t}): string => {\n\t\tif (!option.media) return option.value\n\n\t\tif (\n\t\t\t!(\n\t\t\t\ttypeof window !== 'undefined' &&\n\t\t\t\ttypeof window.document !== 'undefined' &&\n\t\t\t\ttypeof window.document.createElement !== 'undefined'\n\t\t\t)\n\t\t) {\n\t\t\tif (!PROD) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[${PACKAGE_NAME}] Option with key \"media\" cannot be resolved in server environment.`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn option.value\n\t\t}\n\n\t\tconst cache = this.#mediaQueryCache\n\n\t\tconst [mediaQuery] = option.media\n\n\t\tif (!cache[mediaQuery]) {\n\t\t\tconst mediaQueryList = window.matchMedia(mediaQuery)\n\n\t\t\tcache[mediaQuery] = mediaQueryList\n\n\t\t\tmediaQueryList.addEventListener(\n\t\t\t\t'change',\n\t\t\t\t() => {\n\t\t\t\t\tif (this.#currentThemes[themeKey] === option.value) {\n\t\t\t\t\t\tthis.#setThemesAndNotify({ ...this.#currentThemes })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ signal: this.#abortController.signal },\n\t\t\t)\n\t\t}\n\n\t\tconst [ifMatch, ifNotMatch] = this.#systemOptions[themeKey]!\n\n\t\treturn cache[mediaQuery].matches ? ifMatch : ifNotMatch\n\t}\n}\n\nexport type { ThemeStore }\n\nexport function createThemeStore<T extends ThemeStoreConfig>(\n\tconfig: T,\n\toptions: ThemeStoreOptions<T> = {},\n): ThemeStore<T> {\n\treturn new ThemeStore<T>(config, options)\n}\n\nconst restoreScript = <T extends ThemeValue>(\n\tparams: Array<\n\t\t[string, Array<[string, T] | [string, T, T, string, T, T]>, Listener<any>]\n\t>,\n) => {\n\tparams.forEach(([key, flattenedConfig, handler]) => {\n\t\tconst persistedThemes =\n\t\t\tJSON.parse(localStorage.getItem(key) || '{}').themes ?? {}\n\n\t\thandler(\n\t\t\tflattenedConfig.reduce<{\n\t\t\t\tthemes: Record<string, ThemeValue>\n\t\t\t\tresolvedThemes: Record<string, ThemeValue>\n\t\t\t}>(\n\t\t\t\t(\n\t\t\t\t\tacc,\n\t\t\t\t\t[\n\t\t\t\t\t\tthemeKey,\n\t\t\t\t\t\tinitial,\n\t\t\t\t\t\tsystemOptionValue,\n\t\t\t\t\t\tmediaQuery,\n\t\t\t\t\t\tifMatch,\n\t\t\t\t\t\tifNotMatch,\n\t\t\t\t\t],\n\t\t\t\t) => {\n\t\t\t\t\tconst currentValue = persistedThemes[themeKey] ?? initial\n\n\t\t\t\t\tacc.resolvedThemes[themeKey] = acc.themes[themeKey] = currentValue\n\n\t\t\t\t\tif (currentValue === systemOptionValue) {\n\t\t\t\t\t\tacc.resolvedThemes[themeKey] = matchMedia(mediaQuery!).matches\n\t\t\t\t\t\t\t? ifMatch!\n\t\t\t\t\t\t\t: ifNotMatch!\n\t\t\t\t\t}\n\n\t\t\t\t\treturn acc\n\t\t\t\t},\n\t\t\t\t{ themes: {}, resolvedThemes: {} },\n\t\t\t),\n\t\t)\n\t})\n}\n\nexport type ThemeScriptParameter = {\n\t/** `localStorage` key; defaults to the 'resonare'. */\n\tkey?: string\n\tconfig: ThemeStoreConfig\n\thandler: Listener<any>\n}\n\n/**\n * Creates an IIFE script string that reads persisted themes from `localStorage` and runs your handlers immediately.\n *\n * Useful for avoiding flash of incorrect styles.\n * @example\n * ```tsx\n * import { createInlineThemeScript } from 'resonare'\n *\n * const inlineScript = createInlineThemeScript([\n * {\n * key: 'my-app',\n * config: {\n * colorMode: { options: ['light', 'dark'] },\n * },\n * handler: ({ resolvedThemes }) => {\n * document.documentElement.dataset.colorMode = String(\n * resolvedThemes.colorMode,\n * )\n * },\n * },\n * ])\n * ```\n */\nexport function createInlineThemeScript(\n\tthemeScriptParameters: ThemeScriptParameter | Array<ThemeScriptParameter>,\n) {\n\tconst serializedArgs = (\n\t\tArray.isArray(themeScriptParameters)\n\t\t\t? themeScriptParameters\n\t\t\t: [themeScriptParameters]\n\t).map(({ key = PACKAGE_NAME, config, handler }) => {\n\t\tconst flattenedConfig = Object.entries(config).map(\n\t\t\t([themeKey, { options, initialValue }]) => {\n\t\t\t\tconst firstOption = options?.[0]\n\n\t\t\t\tconst resolvedInitialValue =\n\t\t\t\t\tinitialValue ??\n\t\t\t\t\t(typeof firstOption === 'object' ? firstOption.value : firstOption!)\n\n\t\t\t\tconst systemOption = options?.find(\n\t\t\t\t\t(option): option is Required<ThemeOption> =>\n\t\t\t\t\t\ttypeof option === 'object' && !!option.media,\n\t\t\t\t)\n\n\t\t\t\tif (systemOption) {\n\t\t\t\t\tconst {\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tmedia: [mediaQuery, ifMatch, ifNotMatch],\n\t\t\t\t\t} = systemOption\n\n\t\t\t\t\treturn [\n\t\t\t\t\t\tthemeKey,\n\t\t\t\t\t\tresolvedInitialValue,\n\t\t\t\t\t\tvalue,\n\t\t\t\t\t\tmediaQuery,\n\t\t\t\t\t\tifMatch,\n\t\t\t\t\t\tifNotMatch,\n\t\t\t\t\t]\n\t\t\t\t}\n\n\t\t\t\treturn [themeKey, resolvedInitialValue]\n\t\t\t},\n\t\t)\n\n\t\treturn `['${key}', ${JSON.stringify(flattenedConfig)}, ${handler}]`\n\t})\n\n\treturn `(${restoreScript})([${serializedArgs}])`\n}\n"],"mappings":"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"}
|
package/dist/react.js
CHANGED
|
@@ -1,2 +1,55 @@
|
|
|
1
|
-
import{c
|
|
1
|
+
import { c } from "react-compiler-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
//#region src/react.ts
|
|
4
|
+
/**
|
|
5
|
+
* Subscribes a React component to a theme store.
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* export function ThemeToggle() {
|
|
9
|
+
* const { themes, resolvedThemes, setThemes } = useResonare(store)
|
|
10
|
+
*
|
|
11
|
+
* // ...
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
function useResonare(store) {
|
|
16
|
+
const $ = c(13);
|
|
17
|
+
const { destroy, getResolvedThemes, getThemes, restore, setThemes, subscribe, sync, toPersist, updateSystemOption } = store;
|
|
18
|
+
const themes = React.useSyncExternalStore(subscribe, getThemes, getThemes);
|
|
19
|
+
let t0;
|
|
20
|
+
if ($[0] !== getResolvedThemes || $[1] !== themes) {
|
|
21
|
+
t0 = getResolvedThemes(themes);
|
|
22
|
+
$[0] = getResolvedThemes;
|
|
23
|
+
$[1] = themes;
|
|
24
|
+
$[2] = t0;
|
|
25
|
+
} else t0 = $[2];
|
|
26
|
+
let t1;
|
|
27
|
+
if ($[3] !== destroy || $[4] !== restore || $[5] !== setThemes || $[6] !== subscribe || $[7] !== sync || $[8] !== t0 || $[9] !== themes || $[10] !== toPersist || $[11] !== updateSystemOption) {
|
|
28
|
+
t1 = {
|
|
29
|
+
themes,
|
|
30
|
+
resolvedThemes: t0,
|
|
31
|
+
destroy,
|
|
32
|
+
restore,
|
|
33
|
+
setThemes,
|
|
34
|
+
subscribe,
|
|
35
|
+
sync,
|
|
36
|
+
toPersist,
|
|
37
|
+
updateSystemOption
|
|
38
|
+
};
|
|
39
|
+
$[3] = destroy;
|
|
40
|
+
$[4] = restore;
|
|
41
|
+
$[5] = setThemes;
|
|
42
|
+
$[6] = subscribe;
|
|
43
|
+
$[7] = sync;
|
|
44
|
+
$[8] = t0;
|
|
45
|
+
$[9] = themes;
|
|
46
|
+
$[10] = toPersist;
|
|
47
|
+
$[11] = updateSystemOption;
|
|
48
|
+
$[12] = t1;
|
|
49
|
+
} else t1 = $[12];
|
|
50
|
+
return t1;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { useResonare };
|
|
54
|
+
|
|
2
55
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":["React","ThemeStore","ThemeStoreConfig","useResonare","store","$","_c","destroy","getResolvedThemes","getThemes","restore","setThemes","subscribe","sync","toPersist","updateSystemOption","themes","useSyncExternalStore","t0","t1","resolvedThemes"],"sources":["../src/react.ts"],"sourcesContent":["import * as React from 'react'\nimport type { ThemeStore, ThemeStoreConfig } from '.'\n\n/**\n * Subscribes a React component to a theme store.\n * @example\n * ```tsx\n * export function ThemeToggle() {\n * const { themes, resolvedThemes, setThemes } = useResonare(store)\n *\n * // ...\n * }\n * ```\n */\nexport function useResonare<T extends ThemeStoreConfig>(store: ThemeStore<T>) {\n\tconst {\n\t\tdestroy,\n\t\tgetResolvedThemes,\n\t\tgetThemes,\n\t\trestore,\n\t\tsetThemes,\n\t\tsubscribe,\n\t\tsync,\n\t\ttoPersist,\n\t\tupdateSystemOption,\n\t} = store\n\n\tconst themes = React.useSyncExternalStore(subscribe, getThemes, getThemes)\n\n\treturn {\n\t\tthemes,\n\t\tresolvedThemes: getResolvedThemes(),\n\t\tdestroy,\n\t\trestore,\n\t\tsetThemes,\n\t\tsubscribe,\n\t\tsync,\n\t\ttoPersist,\n\t\tupdateSystemOption,\n\t}\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"react.js","names":["React","ThemeStore","ThemeStoreConfig","useResonare","store","$","_c","destroy","getResolvedThemes","getThemes","restore","setThemes","subscribe","sync","toPersist","updateSystemOption","themes","useSyncExternalStore","t0","t1","resolvedThemes"],"sources":["../src/react.ts"],"sourcesContent":["import * as React from 'react'\nimport type { ThemeStore, ThemeStoreConfig } from '.'\n\n/**\n * Subscribes a React component to a theme store.\n * @example\n * ```tsx\n * export function ThemeToggle() {\n * const { themes, resolvedThemes, setThemes } = useResonare(store)\n *\n * // ...\n * }\n * ```\n */\nexport function useResonare<T extends ThemeStoreConfig>(store: ThemeStore<T>) {\n\tconst {\n\t\tdestroy,\n\t\tgetResolvedThemes,\n\t\tgetThemes,\n\t\trestore,\n\t\tsetThemes,\n\t\tsubscribe,\n\t\tsync,\n\t\ttoPersist,\n\t\tupdateSystemOption,\n\t} = store\n\n\tconst themes = React.useSyncExternalStore(subscribe, getThemes, getThemes)\n\n\treturn {\n\t\tthemes,\n\t\t// @ts-expect-error - workaround for React compiler as getResolvedThemes is not called again without 'themes' dependency\n\t\tresolvedThemes: getResolvedThemes(themes),\n\t\tdestroy,\n\t\trestore,\n\t\tsetThemes,\n\t\tsubscribe,\n\t\tsync,\n\t\ttoPersist,\n\t\tupdateSystemOption,\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAOG,YAAAC,OAAA;CAAA,MAAAC,IAAAC,EAAA,GAAA;CACN,MAAA,EAAAC,SAAAC,mBAAAC,WAAAC,SAAAC,WAAAC,WAAAC,MAAAC,WAAAC,uBAUIX;CAEJ,MAAAY,SAAehB,MAAKiB,qBAAsBL,WAAWH,WAAWA,UAAU;CAAA,IAAAS;AAAA,KAAAb,EAAA,OAAAG,qBAAAH,EAAA,OAAAW,QAAA;AAKzDE,OAAAV,kBAAkBQ,OAAO;AAAAX,IAAA,KAAAG;AAAAH,IAAA,KAAAW;AAAAX,IAAA,KAAAa;OAAAA,MAAAb,EAAA;CAAA,IAAAc;AAAA,KAAAd,EAAA,OAAAE,WAAAF,EAAA,OAAAK,WAAAL,EAAA,OAAAM,aAAAN,EAAA,OAAAO,aAAAP,EAAA,OAAAQ,QAAAR,EAAA,OAAAa,MAAAb,EAAA,OAAAW,UAAAX,EAAA,QAAAS,aAAAT,EAAA,QAAAU,oBAAA;AAHnCI,OAAA;GAAAH;GAAAI,gBAGUF;GAAyBX;GAAAG;GAAAC;GAAAC;GAAAC;GAAAC;GAAAC;GAQzC;AAAAV,IAAA,KAAAE;AAAAF,IAAA,KAAAK;AAAAL,IAAA,KAAAM;AAAAN,IAAA,KAAAO;AAAAP,IAAA,KAAAQ;AAAAR,IAAA,KAAAa;AAAAb,IAAA,KAAAW;AAAAX,IAAA,MAAAS;AAAAT,IAAA,MAAAU;AAAAV,IAAA,MAAAc;OAAAA,MAAAd,EAAA;AAAA,QAXMc"}
|