resonare 0.0.12 → 0.0.13
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 +43 -39
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/inline-script.ts +1 -1
- package/dist/react.js +1 -2
- package/dist/react.js.map +1 -1
- package/dist/resonare.iife.min.js +1 -1
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Resonare [](https://www.npmjs.com/package/resonare)
|
|
2
2
|
|
|
3
|
-
A configuration-based
|
|
3
|
+
A configuration-based store for managing themes and user preferences.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -35,7 +35,9 @@ pnpm add resonare
|
|
|
35
35
|
|
|
36
36
|
## Basic Usage
|
|
37
37
|
|
|
38
|
-
It's recommended to initialize Resonare in a synchronous script to avoid theme flicker on page load.
|
|
38
|
+
It's recommended to initialize Resonare in a synchronous script to avoid theme flicker on page load.
|
|
39
|
+
|
|
40
|
+
Load via CDN:
|
|
39
41
|
|
|
40
42
|
```html
|
|
41
43
|
<script src="https://unpkg.com/resonare"></script>
|
|
@@ -66,11 +68,14 @@ It's recommended to initialize Resonare in a synchronous script to avoid theme f
|
|
|
66
68
|
})
|
|
67
69
|
|
|
68
70
|
themeStore.restore()
|
|
71
|
+
|
|
69
72
|
themeStore.sync()
|
|
70
73
|
})()
|
|
71
74
|
</script>
|
|
72
75
|
```
|
|
73
76
|
|
|
77
|
+
Alternatively, inline the stringified version to reduce the number of HTTP requests:
|
|
78
|
+
|
|
74
79
|
```ts
|
|
75
80
|
import { type ThemeConfig, type ThemeStore } from 'resonare'
|
|
76
81
|
import { resonareInlineScript } from 'resonare/inline-script'
|
|
@@ -150,6 +155,9 @@ const themeConfig = {
|
|
|
150
155
|
],
|
|
151
156
|
initialValue: 'standard',
|
|
152
157
|
},
|
|
158
|
+
sidebarWidth: {
|
|
159
|
+
initialValue: 240,
|
|
160
|
+
},
|
|
153
161
|
} as const satisfies ThemeConfig
|
|
154
162
|
|
|
155
163
|
declare module 'resonare' {
|
|
@@ -204,6 +212,38 @@ const themeStore = createThemeStore({
|
|
|
204
212
|
},
|
|
205
213
|
})
|
|
206
214
|
})
|
|
215
|
+
|
|
216
|
+
// get current theme selection
|
|
217
|
+
// e.g.: { colorScheme: 'system', contrast: 'standard', sidebarWidth: 240 }
|
|
218
|
+
themeStore.getThemes()
|
|
219
|
+
|
|
220
|
+
// get resolved theme selection (after media queries)
|
|
221
|
+
// e.g.: { colorScheme: 'dark', contrast: 'standard', sidebarWidth: 240 }
|
|
222
|
+
themeStore.getResolvedThemes()
|
|
223
|
+
|
|
224
|
+
// update theme
|
|
225
|
+
themeStore.setThemes({ colorScheme: 'light', sidebarWidth: 280 })
|
|
226
|
+
|
|
227
|
+
// get state to persist, useful for server-side persistence
|
|
228
|
+
// to restore, pass the returned object to createThemeStore's initialState
|
|
229
|
+
themeStore.toPersist()
|
|
230
|
+
|
|
231
|
+
// restore persisted state from client-side storage
|
|
232
|
+
themeStore.restore()
|
|
233
|
+
|
|
234
|
+
// sync theme selection across tabs/windows if supported by the storage adapter
|
|
235
|
+
themeStore.sync()
|
|
236
|
+
|
|
237
|
+
// subscribe to theme changes
|
|
238
|
+
themeStore.subscribe(({ themes, resolvedThemes }) => {
|
|
239
|
+
for (const [key, value] of Object.entries(resolvedThemes)) {
|
|
240
|
+
if (key === 'sidebarWidth') {
|
|
241
|
+
document.documentElement.style.setProperty('--sidebar-width', `${value}px`)
|
|
242
|
+
} else {
|
|
243
|
+
document.documentElement.dataset[key] = value
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
})
|
|
207
247
|
```
|
|
208
248
|
|
|
209
249
|
### `getThemeStore`
|
|
@@ -224,43 +264,6 @@ import { destroyThemeStore } from 'resonare'
|
|
|
224
264
|
destroyThemeStore('resonare')
|
|
225
265
|
```
|
|
226
266
|
|
|
227
|
-
### ThemeStore Methods
|
|
228
|
-
|
|
229
|
-
```ts
|
|
230
|
-
interface ThemeStore<T> {
|
|
231
|
-
// get current theme selection
|
|
232
|
-
getThemes(): Record<string, string>
|
|
233
|
-
|
|
234
|
-
// get resolved theme selection (after media queries)
|
|
235
|
-
getResolvedThemes(): Record<string, string>
|
|
236
|
-
|
|
237
|
-
// update theme
|
|
238
|
-
setThemes(themes: Partial<Record<string, string>>): void
|
|
239
|
-
|
|
240
|
-
// get state to persist, useful for server-side persistence
|
|
241
|
-
// to restore, pass the returned object to createThemeStore's initialState
|
|
242
|
-
toPersist(): object
|
|
243
|
-
|
|
244
|
-
// restore persisted state from client-side storage
|
|
245
|
-
restore(): void
|
|
246
|
-
|
|
247
|
-
// sync theme selection across tabs/windows
|
|
248
|
-
sync(): () => void
|
|
249
|
-
|
|
250
|
-
// subscribe to theme changes
|
|
251
|
-
subscribe(
|
|
252
|
-
callback: ({
|
|
253
|
-
themes,
|
|
254
|
-
resolvedThemes,
|
|
255
|
-
}: {
|
|
256
|
-
themes: Record<string, string>
|
|
257
|
-
resolvedThemes: Record<string, string>
|
|
258
|
-
}) => void,
|
|
259
|
-
options?: { immediate?: boolean }
|
|
260
|
-
): () => void
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
267
|
## Framework Integrations
|
|
265
268
|
|
|
266
269
|
### React
|
|
@@ -357,6 +360,7 @@ export function ThemeSelect({ persistedStateFromDb }) {
|
|
|
357
360
|
onChange={async (e) => {
|
|
358
361
|
setThemes({ [theme]: e.target.value })
|
|
359
362
|
|
|
363
|
+
// save to server-side storage
|
|
360
364
|
await saveToDb(themeStore.toPersist())
|
|
361
365
|
}}
|
|
362
366
|
value={themes[theme]}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
//#region package.json
|
|
2
2
|
var name = "resonare";
|
|
3
|
-
|
|
4
3
|
//#endregion
|
|
5
4
|
//#region src/storage.ts
|
|
6
5
|
const localStorageAdapter = ({ type = "localStorage" } = {}) => {
|
|
@@ -54,7 +53,6 @@ const memoryStorageAdapter = () => {
|
|
|
54
53
|
};
|
|
55
54
|
};
|
|
56
55
|
};
|
|
57
|
-
|
|
58
56
|
//#endregion
|
|
59
57
|
//#region src/index.ts
|
|
60
58
|
function getThemesAndOptions(config) {
|
|
@@ -236,7 +234,7 @@ const registry = new Registry();
|
|
|
236
234
|
const createThemeStore = registry.create;
|
|
237
235
|
const getThemeStore = registry.get;
|
|
238
236
|
const destroyThemeStore = registry.destroy;
|
|
239
|
-
|
|
240
237
|
//#endregion
|
|
241
238
|
export { ThemeStore, createThemeStore, destroyThemeStore, getDefaultThemes, getThemeStore, getThemesAndOptions, localStorageAdapter, memoryStorageAdapter };
|
|
239
|
+
|
|
242
240
|
//# 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","key","set","value","broadcast","watch","cb","StorageAdapterCreate","abortController","AbortController","StorageAdapterCreator","options","Options","localStorageAdapter","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","ThemeOptionValue","ThemeOption","value","T","media","ThemeOptions","options","ReadonlyArray","initialValue","ThemeConfig","Record","KeyedThemeConfig","Themes","K","U","Listener","themes","resolvedThemes","ThemeKeysWithSystemOption","NonSystemOptionValues","SystemOptions","PersistedState","version","Partial","systemOptions","ThemeStoreOptions","key","config","initialState","storage","ThemeAndOptions","Array","getThemesAndOptions","Object","entries","map","themeKey","themeOptions","option","getDefaultThemes","fromEntries","defaultValue","ThemeStore","defaultThemes","currentThemes","listeners","Set","mediaQueryCache","MediaQueryList","abortController","AbortController","constructor","keyedConfig","forEach","hasOwn","String","getThemes","getResolvedThemes","resolveThemes","setThemes","updatedThemes","setThemesAndNotify","stateToPersist","toPersist","set","broadcast","updateSystemOption","ifMatch","ifNotMatch","restore","persistedState","get","subscribe","callback","immediate","add","delete","sync","watch","___destroy","clear","abort","#setThemesAndNotify","notify","#resolveThemes","optionKey","resolveThemeOption","#resolveThemeOption","IIFE","window","document","createElement","console","warn","mediaQuery","mediaQueryList","matchMedia","addEventListener","signal","matches","#notify","listener","Registry","registry","Map","create","storeKey","themeStore","ThemeStoreRegistry","has","Error","destroy","createThemeStore","getThemeStore","destroyThemeStore"],"sources":["../package.json","../src/storage.ts","../src/index.ts"],"sourcesContent":["","import { name as PACKAGE_NAME } from '../package.json' with { type: 'json' }\n\nexport type StorageAdapter = {\n\tget: (key: string) => object | null\n\tset: (key: string, value: object) => void\n\t// del: (key: string) => void\n\tbroadcast?: (key: string, value: object) => void\n\twatch?: (cb: (key: string | null, 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\nexport const localStorageAdapter: StorageAdapterCreator<{\n\ttype?: 'localStorage' | 'sessionStorage'\n}> = ({ type = 'localStorage' } = {}) => {\n\treturn ({ abortController }) => {\n\t\treturn {\n\t\t\tget: (key: string) => {\n\t\t\t\treturn JSON.parse(window[type].getItem(key) || 'null')\n\t\t\t},\n\n\t\t\tset: (key: string, value: object) => {\n\t\t\t\twindow[type].setItem(key, JSON.stringify(value))\n\t\t\t},\n\n\t\t\t// del: (key: string) => {\n\t\t\t// \twindow[type].removeItem(key)\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\tcb(e.key, 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\nexport const memoryStorageAdapter: StorageAdapterCreator<never> = () => {\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: (key: string) => {\n\t\t\t\treturn storage.get(key) || null\n\t\t\t},\n\n\t\t\tset: (key: string, value: object) => {\n\t\t\t\tstorage.set(key, value)\n\t\t\t},\n\n\t\t\t// del: (key: string) => {\n\t\t\t// \tstorage.delete(key)\n\t\t\t// },\n\n\t\t\tbroadcast: (key: string, 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\tcb(e.data.key, 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\ntype ThemeOptionValue = string | number | boolean\n\ntype ThemeOption<T extends ThemeOptionValue = string> = {\n\tvalue: T\n\tmedia?: [string, T, T]\n}\n\ntype ThemeOptions<T extends ThemeOptionValue = string> =\n\t| {\n\t\t\toptions: [\n\t\t\t\tT | ThemeOption<T>,\n\t\t\t\tT | ThemeOption<T>,\n\t\t\t\t...ReadonlyArray<T | ThemeOption<T>>,\n\t\t\t]\n\t\t\tinitialValue?: T\n\t }\n\t| {\n\t\t\tinitialValue: T\n\t }\n\nexport type ThemeConfig = Record<\n\tstring,\n\tThemeOptions<string> | ThemeOptions<number> | ThemeOptions<boolean>\n>\n\n// { [themeKey]: { [optionKey]: ThemeOption } }\ntype KeyedThemeConfig<T extends ThemeConfig> = {\n\t[K in keyof T]: Record<string, ThemeOption>\n}\n\nexport type Themes<T extends ThemeConfig> = {\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 ThemeConfig> = (value: {\n\tthemes: Themes<T>\n\tresolvedThemes: Themes<T>\n}) => void\n\ntype ThemeKeysWithSystemOption<T extends ThemeConfig> = {\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 ThemeConfig,\n\tK extends keyof T,\n> = T[K] extends { options: ReadonlyArray<infer U> }\n\t? U extends ThemeOptionValue\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 ThemeConfig> = {\n\t[K in ThemeKeysWithSystemOption<T>]?: [\n\t\tNonSystemOptionValues<T, K>,\n\t\tNonSystemOptionValues<T, K>,\n\t]\n}\n\ntype PersistedState<T extends ThemeConfig> = {\n\tversion: 1\n\tthemes: Partial<Themes<T>>\n\tsystemOptions: SystemOptions<T>\n}\n\nexport type ThemeStoreOptions<T extends ThemeConfig> = {\n\tkey?: string\n\tconfig: T\n\tinitialState?: Partial<PersistedState<T>>\n\tstorage?: StorageAdapterCreate | null\n}\n\nexport type ThemeAndOptions<T extends ThemeConfig> = 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 ThemeConfig>(config: T) {\n\treturn Object.entries(config).map(([themeKey, themeOptions]) => {\n\t\treturn [\n\t\t\tthemeKey,\n\t\t\t'options' in themeOptions\n\t\t\t\t? themeOptions.options.map((option) =>\n\t\t\t\t\t\ttypeof option === 'string' ? option : option.value,\n\t\t\t\t\t)\n\t\t\t\t: [],\n\t\t]\n\t}) as ThemeAndOptions<T>\n}\n\nexport function getDefaultThemes<T extends ThemeConfig>(config: T) {\n\treturn Object.fromEntries(\n\t\tObject.entries(config).map(([themeKey, themeOptions]) => {\n\t\t\tconst defaultValue =\n\t\t\t\tthemeOptions.initialValue ??\n\t\t\t\tthemeOptions.options[0].value ??\n\t\t\t\tthemeOptions.options[0]\n\n\t\t\treturn [themeKey, defaultValue]\n\t\t}),\n\t) as Themes<T>\n}\n\nexport class ThemeStore<T extends ThemeConfig> {\n\t#defaultThemes: Themes<T>\n\t#currentThemes: Themes<T>\n\n\t#options: {\n\t\tkey: string\n\t\tconfig: KeyedThemeConfig<T>\n\t}\n\n\t#systemOptions: SystemOptions<T>\n\n\t#storage: StorageAdapter | null\n\n\t#listeners: Set<Listener<T>> = new Set<Listener<T>>()\n\n\t#mediaQueryCache: Record<string, MediaQueryList>\n\n\t#abortController = new AbortController()\n\n\tconstructor({\n\t\tkey = PACKAGE_NAME,\n\t\tconfig,\n\t\tinitialState = {},\n\t\tstorage = localStorageAdapter(),\n\t}: ThemeStoreOptions<T>) {\n\t\tconst keyedConfig: Record<string, Record<string, ThemeOption<any>>> = {}\n\t\tconst systemOptions: Record<string, [ThemeOptionValue, ThemeOptionValue]> =\n\t\t\t{\n\t\t\t\t...initialState.systemOptions,\n\t\t\t}\n\n\t\tObject.entries(config).forEach(([themeKey, themeOptions]) => {\n\t\t\tkeyedConfig[themeKey] = {}\n\n\t\t\tif ('options' in themeOptions) {\n\t\t\t\tthemeOptions.options.forEach((option) => {\n\t\t\t\t\tif (typeof option === 'object') {\n\t\t\t\t\t\tif (option.media && !Object.hasOwn(systemOptions, themeKey)) {\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\tkeyedConfig[themeKey]![String(option.value)] = option\n\t\t\t\t\t} else {\n\t\t\t\t\t\tkeyedConfig[themeKey]![String(option)] = { value: option }\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\tthis.#options = {\n\t\t\tkey,\n\t\t\tconfig: keyedConfig as KeyedThemeConfig<T>,\n\t\t}\n\n\t\tthis.#systemOptions = systemOptions as SystemOptions<T>\n\n\t\tthis.#defaultThemes = getDefaultThemes(config)\n\n\t\tthis.#currentThemes = { ...this.#defaultThemes, ...initialState.themes }\n\n\t\tthis.#storage =\n\t\t\tstorage?.({\n\t\t\t\tabortController: this.#abortController,\n\t\t\t}) ?? null\n\n\t\tthis.#mediaQueryCache = {}\n\t}\n\n\tgetThemes = (): Themes<T> => {\n\t\treturn this.#currentThemes\n\t}\n\n\tgetResolvedThemes = (): Themes<T> => {\n\t\treturn this.#resolveThemes()\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(this.#options.key, stateToPersist)\n\t\t\tthis.#storage.broadcast?.(this.#options.key, 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) => {\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\tversion: 1,\n\t\t\tthemes: this.#currentThemes,\n\t\t\tsystemOptions: this.#systemOptions,\n\t\t}\n\t}\n\n\trestore = (): void => {\n\t\tlet persistedState = this.#storage?.get(this.#options.key)\n\n\t\tif (!persistedState) {\n\t\t\tthis.#setThemesAndNotify({ ...this.#defaultThemes })\n\t\t\treturn\n\t\t}\n\n\t\t// for backward compatibility\n\t\tif (!Object.hasOwn(persistedState, 'version')) {\n\t\t\tpersistedState = {\n\t\t\t\tversion: 1,\n\t\t\t\tthemes: persistedState,\n\t\t\t\tsystemOptions: this.#systemOptions,\n\t\t\t}\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 = (\n\t\tcallback: Listener<T>,\n\t\t{ immediate = false }: { immediate?: boolean } = {},\n\t): (() => void) => {\n\t\tif (immediate) {\n\t\t\tcallback({\n\t\t\t\tthemes: this.#currentThemes,\n\t\t\t\tresolvedThemes: this.#resolveThemes(),\n\t\t\t})\n\t\t}\n\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) {\n\t\t\t// if (this.#storage) {\n\t\t\t// \tconsole.warn(\n\t\t\t// \t\t`[${PACKAGE_NAME}] No watch method was provided for storage.`,\n\t\t\t// \t)\n\t\t\t// } else {\n\t\t\t// \tconsole.warn(`[${PACKAGE_NAME}] No storage was provided.`)\n\t\t\t// }\n\n\t\t\treturn\n\t\t}\n\n\t\treturn this.#storage.watch((key, persistedState) => {\n\t\t\tif (key !== this.#options.key) return\n\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___destroy = (): 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\t\tthis.#notify()\n\t}\n\n\t#resolveThemes = (): Themes<T> => {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(this.#currentThemes).map(([themeKey, optionKey]) => {\n\t\t\t\tconst option = this.#options.config[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\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 (!IIFE) {\n\t\t\tif (\n\t\t\t\t!(\n\t\t\t\t\ttypeof window !== 'undefined' &&\n\t\t\t\t\ttypeof window.document !== 'undefined' &&\n\t\t\t\t\ttypeof window.document.createElement !== 'undefined'\n\t\t\t\t)\n\t\t\t) {\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\n\t\t\t\treturn option.value\n\t\t\t}\n\t\t}\n\n\t\tconst [mediaQuery] = option.media\n\n\t\tif (!this.#mediaQueryCache[mediaQuery]) {\n\t\t\tconst mediaQueryList = window.matchMedia(mediaQuery)\n\n\t\t\tthis.#mediaQueryCache[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 this.#mediaQueryCache[mediaQuery].matches ? ifMatch : ifNotMatch\n\t}\n\n\t#notify = (): void => {\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.#resolveThemes(),\n\t\t\t})\n\t\t}\n\t}\n}\n\nclass Registry {\n\t#registry = new Map<string, ThemeStore<ThemeConfig>>()\n\n\tcreate = <T extends ThemeConfig>(\n\t\toptions: ThemeStoreOptions<T>,\n\t): ThemeStore<T> => {\n\t\tconst storeKey = options.key || PACKAGE_NAME\n\n\t\tlet themeStore = this.#registry.get(storeKey) as ThemeStore<T>\n\n\t\tif (!themeStore) {\n\t\t\tthemeStore = new ThemeStore<T>(options)\n\t\t\tthis.#registry.set(storeKey, themeStore as ThemeStore<ThemeConfig>)\n\t\t}\n\n\t\treturn themeStore\n\t}\n\n\tget = <T extends keyof ThemeStoreRegistry>(key?: T) => {\n\t\tconst storeKey = key || PACKAGE_NAME\n\n\t\tif (!this.#registry.has(storeKey)) {\n\t\t\tif (IIFE) {\n\t\t\t\tthrow new Error(`Theme store '${storeKey}' not found.`)\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`[${PACKAGE_NAME}] Theme store with key '${storeKey}' could not be found. Please run \\`createThemeStore\\` with key '${storeKey}' first.`,\n\t\t\t)\n\t\t}\n\n\t\treturn this.#registry.get(storeKey)! as ThemeStoreRegistry[T]\n\t}\n\n\tdestroy = <T extends keyof ThemeStoreRegistry>(key?: T) => {\n\t\tconst storeKey = key || PACKAGE_NAME\n\n\t\tif (!this.#registry.has(storeKey)) return\n\n\t\tthis.#registry.get(storeKey)!.___destroy()\n\t\tthis.#registry.delete(storeKey)\n\t}\n}\n\nconst registry = new Registry()\n\nexport const createThemeStore = registry.create\nexport const getThemeStore = registry.get\nexport const destroyThemeStore = registry.destroy\n\nexport * from './storage'\n\nexport interface ThemeStoreRegistry {}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["name","PACKAGE_NAME","type","StorageAdapter","get","key","set","value","broadcast","watch","cb","StorageAdapterCreate","abortController","AbortController","StorageAdapterCreator","options","Options","localStorageAdapter","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","ThemeOptionValue","ThemeOption","value","T","media","ThemeOptions","options","ReadonlyArray","initialValue","ThemeConfig","Record","KeyedThemeConfig","Themes","K","U","Listener","themes","resolvedThemes","ThemeKeysWithSystemOption","NonSystemOptionValues","SystemOptions","PersistedState","version","Partial","systemOptions","ThemeStoreOptions","key","config","initialState","storage","ThemeAndOptions","Array","getThemesAndOptions","Object","entries","map","themeKey","themeOptions","option","getDefaultThemes","fromEntries","defaultValue","ThemeStore","defaultThemes","currentThemes","listeners","Set","mediaQueryCache","MediaQueryList","abortController","AbortController","constructor","keyedConfig","forEach","hasOwn","String","getThemes","getResolvedThemes","resolveThemes","setThemes","updatedThemes","setThemesAndNotify","stateToPersist","toPersist","set","broadcast","updateSystemOption","ifMatch","ifNotMatch","restore","persistedState","get","subscribe","callback","immediate","add","delete","sync","watch","___destroy","clear","abort","#setThemesAndNotify","notify","#resolveThemes","optionKey","resolveThemeOption","#resolveThemeOption","IIFE","window","document","createElement","console","warn","mediaQuery","mediaQueryList","matchMedia","addEventListener","signal","matches","#notify","listener","Registry","registry","Map","create","storeKey","themeStore","ThemeStoreRegistry","has","Error","destroy","createThemeStore","getThemeStore","destroyThemeStore"],"sources":["../package.json","../src/storage.ts","../src/index.ts"],"sourcesContent":["","import { name as PACKAGE_NAME } from '../package.json' with { type: 'json' }\n\nexport type StorageAdapter = {\n\tget: (key: string) => object | null\n\tset: (key: string, value: object) => void\n\t// del: (key: string) => void\n\tbroadcast?: (key: string, value: object) => void\n\twatch?: (cb: (key: string | null, 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\nexport const localStorageAdapter: StorageAdapterCreator<{\n\ttype?: 'localStorage' | 'sessionStorage'\n}> = ({ type = 'localStorage' } = {}) => {\n\treturn ({ abortController }) => {\n\t\treturn {\n\t\t\tget: (key: string) => {\n\t\t\t\treturn JSON.parse(window[type].getItem(key) || 'null')\n\t\t\t},\n\n\t\t\tset: (key: string, value: object) => {\n\t\t\t\twindow[type].setItem(key, JSON.stringify(value))\n\t\t\t},\n\n\t\t\t// del: (key: string) => {\n\t\t\t// \twindow[type].removeItem(key)\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\tcb(e.key, 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\nexport const memoryStorageAdapter: StorageAdapterCreator<never> = () => {\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: (key: string) => {\n\t\t\t\treturn storage.get(key) || null\n\t\t\t},\n\n\t\t\tset: (key: string, value: object) => {\n\t\t\t\tstorage.set(key, value)\n\t\t\t},\n\n\t\t\t// del: (key: string) => {\n\t\t\t// \tstorage.delete(key)\n\t\t\t// },\n\n\t\t\tbroadcast: (key: string, 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\tcb(e.data.key, 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\ntype ThemeOptionValue = string | number | boolean\n\ntype ThemeOption<T extends ThemeOptionValue = string> = {\n\tvalue: T\n\tmedia?: [string, T, T]\n}\n\ntype ThemeOptions<T extends ThemeOptionValue = string> =\n\t| {\n\t\t\toptions: [\n\t\t\t\tT | ThemeOption<T>,\n\t\t\t\tT | ThemeOption<T>,\n\t\t\t\t...ReadonlyArray<T | ThemeOption<T>>,\n\t\t\t]\n\t\t\tinitialValue?: T\n\t }\n\t| {\n\t\t\tinitialValue: T\n\t }\n\nexport type ThemeConfig = Record<\n\tstring,\n\tThemeOptions<string> | ThemeOptions<number> | ThemeOptions<boolean>\n>\n\n// { [themeKey]: { [optionKey]: ThemeOption } }\ntype KeyedThemeConfig<T extends ThemeConfig> = {\n\t[K in keyof T]: Record<string, ThemeOption>\n}\n\nexport type Themes<T extends ThemeConfig> = {\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 ThemeConfig> = (value: {\n\tthemes: Themes<T>\n\tresolvedThemes: Themes<T>\n}) => void\n\ntype ThemeKeysWithSystemOption<T extends ThemeConfig> = {\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 ThemeConfig,\n\tK extends keyof T,\n> = T[K] extends { options: ReadonlyArray<infer U> }\n\t? U extends ThemeOptionValue\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 ThemeConfig> = {\n\t[K in ThemeKeysWithSystemOption<T>]?: [\n\t\tNonSystemOptionValues<T, K>,\n\t\tNonSystemOptionValues<T, K>,\n\t]\n}\n\ntype PersistedState<T extends ThemeConfig> = {\n\tversion: 1\n\tthemes: Partial<Themes<T>>\n\tsystemOptions: SystemOptions<T>\n}\n\nexport type ThemeStoreOptions<T extends ThemeConfig> = {\n\tkey?: string\n\tconfig: T\n\tinitialState?: Partial<PersistedState<T>>\n\tstorage?: StorageAdapterCreate | null\n}\n\nexport type ThemeAndOptions<T extends ThemeConfig> = 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 ThemeConfig>(config: T) {\n\treturn Object.entries(config).map(([themeKey, themeOptions]) => {\n\t\treturn [\n\t\t\tthemeKey,\n\t\t\t'options' in themeOptions\n\t\t\t\t? themeOptions.options.map((option) =>\n\t\t\t\t\t\ttypeof option === 'string' ? option : option.value,\n\t\t\t\t\t)\n\t\t\t\t: [],\n\t\t]\n\t}) as ThemeAndOptions<T>\n}\n\nexport function getDefaultThemes<T extends ThemeConfig>(config: T) {\n\treturn Object.fromEntries(\n\t\tObject.entries(config).map(([themeKey, themeOptions]) => {\n\t\t\tconst defaultValue =\n\t\t\t\tthemeOptions.initialValue ??\n\t\t\t\tthemeOptions.options[0].value ??\n\t\t\t\tthemeOptions.options[0]\n\n\t\t\treturn [themeKey, defaultValue]\n\t\t}),\n\t) as Themes<T>\n}\n\nexport class ThemeStore<T extends ThemeConfig> {\n\t#defaultThemes: Themes<T>\n\t#currentThemes: Themes<T>\n\n\t#options: {\n\t\tkey: string\n\t\tconfig: KeyedThemeConfig<T>\n\t}\n\n\t#systemOptions: SystemOptions<T>\n\n\t#storage: StorageAdapter | null\n\n\t#listeners: Set<Listener<T>> = new Set<Listener<T>>()\n\n\t#mediaQueryCache: Record<string, MediaQueryList>\n\n\t#abortController = new AbortController()\n\n\tconstructor({\n\t\tkey = PACKAGE_NAME,\n\t\tconfig,\n\t\tinitialState = {},\n\t\tstorage = localStorageAdapter(),\n\t}: ThemeStoreOptions<T>) {\n\t\tconst keyedConfig: Record<string, Record<string, ThemeOption<any>>> = {}\n\t\tconst systemOptions: Record<string, [ThemeOptionValue, ThemeOptionValue]> =\n\t\t\t{\n\t\t\t\t...initialState.systemOptions,\n\t\t\t}\n\n\t\tObject.entries(config).forEach(([themeKey, themeOptions]) => {\n\t\t\tkeyedConfig[themeKey] = {}\n\n\t\t\tif ('options' in themeOptions) {\n\t\t\t\tthemeOptions.options.forEach((option) => {\n\t\t\t\t\tif (typeof option === 'object') {\n\t\t\t\t\t\tif (option.media && !Object.hasOwn(systemOptions, themeKey)) {\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\tkeyedConfig[themeKey]![String(option.value)] = option\n\t\t\t\t\t} else {\n\t\t\t\t\t\tkeyedConfig[themeKey]![String(option)] = { value: option }\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\tthis.#options = {\n\t\t\tkey,\n\t\t\tconfig: keyedConfig as KeyedThemeConfig<T>,\n\t\t}\n\n\t\tthis.#systemOptions = systemOptions as SystemOptions<T>\n\n\t\tthis.#defaultThemes = getDefaultThemes(config)\n\n\t\tthis.#currentThemes = { ...this.#defaultThemes, ...initialState.themes }\n\n\t\tthis.#storage =\n\t\t\tstorage?.({\n\t\t\t\tabortController: this.#abortController,\n\t\t\t}) ?? null\n\n\t\tthis.#mediaQueryCache = {}\n\t}\n\n\tgetThemes = (): Themes<T> => {\n\t\treturn this.#currentThemes\n\t}\n\n\tgetResolvedThemes = (): Themes<T> => {\n\t\treturn this.#resolveThemes()\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(this.#options.key, stateToPersist)\n\t\t\tthis.#storage.broadcast?.(this.#options.key, 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) => {\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\tversion: 1,\n\t\t\tthemes: this.#currentThemes,\n\t\t\tsystemOptions: this.#systemOptions,\n\t\t}\n\t}\n\n\trestore = (): void => {\n\t\tlet persistedState = this.#storage?.get(this.#options.key)\n\n\t\tif (!persistedState) {\n\t\t\tthis.#setThemesAndNotify({ ...this.#defaultThemes })\n\t\t\treturn\n\t\t}\n\n\t\t// for backward compatibility\n\t\tif (!Object.hasOwn(persistedState, 'version')) {\n\t\t\tpersistedState = {\n\t\t\t\tversion: 1,\n\t\t\t\tthemes: persistedState,\n\t\t\t\tsystemOptions: this.#systemOptions,\n\t\t\t}\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 = (\n\t\tcallback: Listener<T>,\n\t\t{ immediate = false }: { immediate?: boolean } = {},\n\t): (() => void) => {\n\t\tif (immediate) {\n\t\t\tcallback({\n\t\t\t\tthemes: this.#currentThemes,\n\t\t\t\tresolvedThemes: this.#resolveThemes(),\n\t\t\t})\n\t\t}\n\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) {\n\t\t\t// if (this.#storage) {\n\t\t\t// \tconsole.warn(\n\t\t\t// \t\t`[${PACKAGE_NAME}] No watch method was provided for storage.`,\n\t\t\t// \t)\n\t\t\t// } else {\n\t\t\t// \tconsole.warn(`[${PACKAGE_NAME}] No storage was provided.`)\n\t\t\t// }\n\n\t\t\treturn\n\t\t}\n\n\t\treturn this.#storage.watch((key, persistedState) => {\n\t\t\tif (key !== this.#options.key) return\n\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___destroy = (): 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\t\tthis.#notify()\n\t}\n\n\t#resolveThemes = (): Themes<T> => {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(this.#currentThemes).map(([themeKey, optionKey]) => {\n\t\t\t\tconst option = this.#options.config[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\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 (!IIFE) {\n\t\t\tif (\n\t\t\t\t!(\n\t\t\t\t\ttypeof window !== 'undefined' &&\n\t\t\t\t\ttypeof window.document !== 'undefined' &&\n\t\t\t\t\ttypeof window.document.createElement !== 'undefined'\n\t\t\t\t)\n\t\t\t) {\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\n\t\t\t\treturn option.value\n\t\t\t}\n\t\t}\n\n\t\tconst [mediaQuery] = option.media\n\n\t\tif (!this.#mediaQueryCache[mediaQuery]) {\n\t\t\tconst mediaQueryList = window.matchMedia(mediaQuery)\n\n\t\t\tthis.#mediaQueryCache[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 this.#mediaQueryCache[mediaQuery].matches ? ifMatch : ifNotMatch\n\t}\n\n\t#notify = (): void => {\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.#resolveThemes(),\n\t\t\t})\n\t\t}\n\t}\n}\n\nclass Registry {\n\t#registry = new Map<string, ThemeStore<ThemeConfig>>()\n\n\tcreate = <T extends ThemeConfig>(\n\t\toptions: ThemeStoreOptions<T>,\n\t): ThemeStore<T> => {\n\t\tconst storeKey = options.key || PACKAGE_NAME\n\n\t\tlet themeStore = this.#registry.get(storeKey) as ThemeStore<T>\n\n\t\tif (!themeStore) {\n\t\t\tthemeStore = new ThemeStore<T>(options)\n\t\t\tthis.#registry.set(storeKey, themeStore as ThemeStore<ThemeConfig>)\n\t\t}\n\n\t\treturn themeStore\n\t}\n\n\tget = <T extends keyof ThemeStoreRegistry>(key?: T) => {\n\t\tconst storeKey = key || PACKAGE_NAME\n\n\t\tif (!this.#registry.has(storeKey)) {\n\t\t\tif (IIFE) {\n\t\t\t\tthrow new Error(`Theme store '${storeKey}' not found.`)\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`[${PACKAGE_NAME}] Theme store with key '${storeKey}' could not be found. Please run \\`createThemeStore\\` with key '${storeKey}' first.`,\n\t\t\t)\n\t\t}\n\n\t\treturn this.#registry.get(storeKey)! as ThemeStoreRegistry[T]\n\t}\n\n\tdestroy = <T extends keyof ThemeStoreRegistry>(key?: T) => {\n\t\tconst storeKey = key || PACKAGE_NAME\n\n\t\tif (!this.#registry.has(storeKey)) return\n\n\t\tthis.#registry.get(storeKey)!.___destroy()\n\t\tthis.#registry.delete(storeKey)\n\t}\n}\n\nconst registry = new Registry()\n\nexport const createThemeStore = registry.create\nexport const getThemeStore = registry.get\nexport const destroyThemeStore = registry.destroy\n\nexport * from './storage'\n\nexport interface ThemeStoreRegistry {}\n"],"mappings":"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"}
|
package/dist/inline-script.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const resonareInlineScript = "/**\n* resonare v0.0.
|
|
1
|
+
export const resonareInlineScript = "/**\n* resonare v0.0.13\n*\n* This source code is licensed under the MIT license found in the\n* LICENSE file in the root directory of this source tree.\n*/\nvar resonare=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=`resonare`;let n=({type:e=`localStorage`}={})=>({abortController:t})=>({get:t=>JSON.parse(window[e].getItem(t)||`null`),set:(t,n)=>{window[e].setItem(t,JSON.stringify(n))},watch:n=>{let r=new AbortController;return window.addEventListener(`storage`,t=>{t.storageArea===window[e]&&n(t.key,JSON.parse(t.newValue))},{signal:AbortSignal.any([t.signal,r.signal])}),()=>{r.abort()}}});function r(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,t.initialValue??t.options[0].value??t.options[0]]))}var i=class{#e;#t;#n;#r;#i;#a=new Set;#o;#s=new AbortController;constructor({key:e=t,config:i,initialState:a={},storage:o=n()}){let s={},c={...a.systemOptions};Object.entries(i).forEach(([e,t])=>{s[e]={},`options`in t&&t.options.forEach(t=>{typeof t==`object`?(t.media&&!Object.hasOwn(c,e)&&(c[e]=[t.media[1],t.media[2]]),s[e][String(t.value)]=t):s[e][String(t)]={value:t}})}),this.#n={key:e,config:s},this.#r=c,this.#e=r(i),this.#t={...this.#e,...a.themes},this.#i=o?.({abortController:this.#s})??null,this.#o={}}getThemes=()=>this.#t;getResolvedThemes=()=>this.#l();setThemes=e=>{let t=typeof e==`function`?e(this.#t):e;this.#c({...this.#t,...t});let n=this.toPersist();this.#i&&(this.#i.set(this.#n.key,n),this.#i.broadcast?.(this.#n.key,n))};updateSystemOption=(e,[t,n])=>{this.#r[e]=[t,n],this.setThemes({...this.#t})};toPersist=()=>({version:1,themes:this.#t,systemOptions:this.#r});restore=()=>{let e=this.#i?.get(this.#n.key);if(!e){this.#c({...this.#e});return}Object.hasOwn(e,`version`)||(e={version:1,themes:e,systemOptions:this.#r}),this.#r={...this.#r,...e.systemOptions},this.#c({...this.#e,...e.themes})};subscribe=(e,{immediate:t=!1}={})=>(t&&e({themes:this.#t,resolvedThemes:this.#l()}),this.#a.add(e),()=>{this.#a.delete(e)});sync=()=>{if(this.#i?.watch)return this.#i.watch((e,t)=>{e===this.#n.key&&(this.#r=t.systemOptions,this.#c(t.themes))})};___destroy=()=>{this.#a.clear(),this.#s.abort()};#c=e=>{this.#t=e,this.#d()};#l=()=>Object.fromEntries(Object.entries(this.#t).map(([e,t])=>{let n=this.#n.config[e]?.[t];return[e,n?this.#u({themeKey:e,option:n}):t]}));#u=({themeKey:e,option:t})=>{if(!t.media)return t.value;let[n]=t.media;if(!this.#o[n]){let r=window.matchMedia(n);this.#o[n]=r,r.addEventListener(`change`,()=>{this.#t[e]===t.value&&this.#c({...this.#t})},{signal:this.#s.signal})}let[r,i]=this.#r[e];return this.#o[n].matches?r:i};#d=()=>{for(let e of this.#a)e({themes:this.#t,resolvedThemes:this.#l()})}};let a=new class{#e=new Map;create=e=>{let n=e.key||t,r=this.#e.get(n);return r||(r=new i(e),this.#e.set(n,r)),r};get=e=>{let n=e||t;if(!this.#e.has(n))throw Error(`Theme store '${n}' not found.`);return this.#e.get(n)};destroy=e=>{let n=e||t;this.#e.has(n)&&(this.#e.get(n).___destroy(),this.#e.delete(n))}},o=a.create,s=a.get,c=a.destroy;return e.createThemeStore=o,e.destroyThemeStore=c,e.getThemeStore=s,e})({});"
|
package/dist/react.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { c } from "react-compiler-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
|
|
4
3
|
//#region src/react.ts
|
|
5
4
|
function noop() {}
|
|
6
5
|
const emptyObject = {};
|
|
@@ -66,7 +65,7 @@ function useResonare(getStore, t0) {
|
|
|
66
65
|
} else t6 = $[12];
|
|
67
66
|
return t6;
|
|
68
67
|
}
|
|
69
|
-
|
|
70
68
|
//#endregion
|
|
71
69
|
export { useResonare };
|
|
70
|
+
|
|
72
71
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":["React","ThemeConfig","ThemeStore","noop","emptyObject","emptyStore","getThemes","getResolvedThemes","setThemes","updateSystemOption","toPersist","restore","sync","subscribe","useResonare","getStore","t0","$","_c","t1","undefined","initOnMount","t2","isMounted","setIsMounted","useState","t3","t4","Symbol","for","useEffect","T","themes","useSyncExternalStore","t5","t6","resolvedThemes"],"sources":["../src/react.ts"],"sourcesContent":["import * as React from 'react'\nimport type { ThemeConfig, ThemeStore } from '.'\n\nfunction noop() {}\nconst emptyObject = {}\n\nconst emptyStore = {\n\tgetThemes: () => emptyObject,\n\tgetResolvedThemes: () => emptyObject,\n\tsetThemes: noop,\n\tupdateSystemOption: noop,\n\ttoPersist: noop,\n\trestore: noop,\n\tsync: noop,\n\t// clear: noop,\n\tsubscribe: () => noop,\n}\n\nexport function useResonare<T extends ThemeConfig>(\n\tgetStore: () => ThemeStore<T>,\n\t{ initOnMount = false } = {},\n) {\n\tconst [isMounted, setIsMounted] = React.useState(initOnMount)\n\n\tReact.useEffect(() => {\n\t\tsetIsMounted(true)\n\t}, [])\n\n\tconst {\n\t\tgetThemes,\n\t\tgetResolvedThemes,\n\t\tsetThemes,\n\t\tupdateSystemOption,\n\t\ttoPersist,\n\t\trestore,\n\t\tsync,\n\t\t// clear,\n\t\tsubscribe,\n\t} = isMounted ? getStore() : (emptyStore as unknown as ThemeStore<T>)\n\n\tconst themes = React.useSyncExternalStore(subscribe, getThemes, getThemes)\n\n\treturn {\n\t\tthemes,\n\t\tresolvedThemes: getResolvedThemes(),\n\t\tsetThemes,\n\t\tupdateSystemOption,\n\t\ttoPersist,\n\t\trestore,\n\t\tsync,\n\t\t// clear,\n\t\tsubscribe,\n\t}\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"react.js","names":["React","ThemeConfig","ThemeStore","noop","emptyObject","emptyStore","getThemes","getResolvedThemes","setThemes","updateSystemOption","toPersist","restore","sync","subscribe","useResonare","getStore","t0","$","_c","t1","undefined","initOnMount","t2","isMounted","setIsMounted","useState","t3","t4","Symbol","for","useEffect","T","themes","useSyncExternalStore","t5","t6","resolvedThemes"],"sources":["../src/react.ts"],"sourcesContent":["import * as React from 'react'\nimport type { ThemeConfig, ThemeStore } from '.'\n\nfunction noop() {}\nconst emptyObject = {}\n\nconst emptyStore = {\n\tgetThemes: () => emptyObject,\n\tgetResolvedThemes: () => emptyObject,\n\tsetThemes: noop,\n\tupdateSystemOption: noop,\n\ttoPersist: noop,\n\trestore: noop,\n\tsync: noop,\n\t// clear: noop,\n\tsubscribe: () => noop,\n}\n\nexport function useResonare<T extends ThemeConfig>(\n\tgetStore: () => ThemeStore<T>,\n\t{ initOnMount = false } = {},\n) {\n\tconst [isMounted, setIsMounted] = React.useState(initOnMount)\n\n\tReact.useEffect(() => {\n\t\tsetIsMounted(true)\n\t}, [])\n\n\tconst {\n\t\tgetThemes,\n\t\tgetResolvedThemes,\n\t\tsetThemes,\n\t\tupdateSystemOption,\n\t\ttoPersist,\n\t\trestore,\n\t\tsync,\n\t\t// clear,\n\t\tsubscribe,\n\t} = isMounted ? getStore() : (emptyStore as unknown as ThemeStore<T>)\n\n\tconst themes = React.useSyncExternalStore(subscribe, getThemes, getThemes)\n\n\treturn {\n\t\tthemes,\n\t\tresolvedThemes: getResolvedThemes(),\n\t\tsetThemes,\n\t\tupdateSystemOption,\n\t\ttoPersist,\n\t\trestore,\n\t\tsync,\n\t\t// clear,\n\t\tsubscribe,\n\t}\n}\n"],"mappings":";;;AAGA,SAASG,OAAO;AAChB,MAAMC,cAAc,EAAE;AAEtB,MAAMC,aAAa;CAClBC,iBAAiBF;CACjBG,yBAAyBH;CACzBI,WAAWL;CACXM,oBAAoBN;CACpBO,WAAWP;CACXQ,SAASR;CACTS,MAAMT;CAENU,iBAAiBV;CACjB;AAED,SAAOW,YAAAC,UAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,GAAA;CAAA,IAAAC;AAAA,KAAAF,EAAA,OAAAD,IAAA;AAENG,OAAAH,OAAAI,KAAAA,IAAA,EAA4B,GAA5BJ;AAA4BC,IAAA,KAAAD;AAAAC,IAAA,KAAAE;OAAAA,MAAAF,EAAA;CAA5B,MAAA,EAAAI,aAAAC,OAAAH;CAAE,MAAAE,cAAAC,OAAAF,KAAAA,IAAA,QAAAE;CAEF,MAAA,CAAAC,WAAAC,gBAAkCxB,MAAKyB,SAAUJ,YAAY;CAAA,IAAAK;CAAA,IAAAC;AAAA,KAAAV,EAAA,OAAAW,OAAAC,IAAA,4BAAA,EAAA;AAE7CH,aAAA;AACfF,gBAAa,KAAK;;AAChBG,OAAA,EAAE;AAAAV,IAAA,KAAAS;AAAAT,IAAA,KAAAU;QAAA;AAAAD,OAAAT,EAAA;AAAAU,OAAAV,EAAA;;AAFLjB,OAAK8B,UAAWJ,IAEbC,GAAG;CAEN,MAAA,EAAArB,WAAAC,mBAAAC,WAAAC,oBAAAC,WAAAC,SAAAC,MAAAC,cAUIU,YAAYR,UAAqD,GAAvCV;CAE9B,MAAA2B,SAAehC,MAAKiC,qBAAsBpB,WAAWP,WAAWA,UAAU;CAIzD,MAAA4B,KAAA3B,mBAAmB;CAAA,IAAA4B;AAAA,KAAAlB,EAAA,OAAAN,WAAAM,EAAA,OAAAT,aAAAS,EAAA,OAAAJ,aAAAI,EAAA,OAAAL,QAAAK,EAAA,OAAAiB,MAAAjB,EAAA,OAAAe,UAAAf,EAAA,QAAAP,aAAAO,EAAA,QAAAR,oBAAA;AAF7B0B,OAAA;GAAAH;GAAAI,gBAEUF;GAAmB1B;GAAAC;GAAAC;GAAAC;GAAAC;GAAAC;GAQnC;AAAAI,IAAA,KAAAN;AAAAM,IAAA,KAAAT;AAAAS,IAAA,KAAAJ;AAAAI,IAAA,KAAAL;AAAAK,IAAA,KAAAiB;AAAAjB,IAAA,KAAAe;AAAAf,IAAA,MAAAP;AAAAO,IAAA,MAAAR;AAAAQ,IAAA,MAAAkB;OAAAA,MAAAlB,EAAA;AAAA,QAVMkB"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resonare",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "Resonare",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"theming"
|
|
6
|
+
"theming",
|
|
7
|
+
"dark mode",
|
|
8
|
+
"user preferences"
|
|
7
9
|
],
|
|
8
10
|
"repository": {
|
|
9
11
|
"type": "git",
|
|
@@ -41,18 +43,21 @@
|
|
|
41
43
|
"react-compiler-runtime": "1.0.0"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
|
-
"@
|
|
46
|
+
"@rolldown/plugin-babel": "0.2.2",
|
|
47
|
+
"@size-limit/preset-small-lib": "12.0.1",
|
|
48
|
+
"@types/node": "25.5.0",
|
|
45
49
|
"@types/react": "19.2.14",
|
|
46
|
-
"@vitejs/plugin-react": "
|
|
50
|
+
"@vitejs/plugin-react": "6.0.1",
|
|
47
51
|
"babel-plugin-react-compiler": "1.0.0",
|
|
48
52
|
"cross-env": "10.1.0",
|
|
49
|
-
"jsdom": "
|
|
53
|
+
"jsdom": "29.0.1",
|
|
50
54
|
"react": "19.2.4",
|
|
51
55
|
"react-dom": "19.2.4",
|
|
52
|
-
"size-limit": "12.0.
|
|
53
|
-
"tsdown": "0.
|
|
56
|
+
"size-limit": "12.0.1",
|
|
57
|
+
"tsdown": "0.21.4",
|
|
54
58
|
"typescript": "5.9.3",
|
|
55
|
-
"
|
|
59
|
+
"vite": "8.0.1",
|
|
60
|
+
"vitest": "4.1.0"
|
|
56
61
|
},
|
|
57
62
|
"peerDependencies": {
|
|
58
63
|
"react": "^18.0.0 || ^19.0.0"
|