resonare 0.0.17 → 0.1.0
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 +157 -151
- package/dist/index.d.ts +21 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -243
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +3 -11
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +1 -70
- package/dist/react.js.map +1 -1
- package/package.json +7 -16
- package/dist/inline-script.ts +0 -1
- package/dist/resonare.iife.min.js +0 -7
- package/global.d.ts +0 -3
package/README.md
CHANGED
|
@@ -38,50 +38,12 @@ pnpm add resonare
|
|
|
38
38
|
|
|
39
39
|
## Basic Usage
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Load via CDN:
|
|
44
|
-
|
|
45
|
-
```html
|
|
46
|
-
<script src="https://unpkg.com/resonare"></script>
|
|
47
|
-
<!-- or -->
|
|
48
|
-
<script src="https://cdn.jsdelivr.net/npm/resonare"></script>
|
|
49
|
-
|
|
50
|
-
<script>
|
|
51
|
-
;(() => {
|
|
52
|
-
const themeStore = window.resonare.createThemeStore({
|
|
53
|
-
config: {
|
|
54
|
-
colorScheme: {
|
|
55
|
-
options: [
|
|
56
|
-
{
|
|
57
|
-
value: 'system',
|
|
58
|
-
media: ['(prefers-color-scheme: dark)', 'dark', 'light'],
|
|
59
|
-
},
|
|
60
|
-
'light',
|
|
61
|
-
'dark',
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
})
|
|
41
|
+
### 1. Create inline script
|
|
66
42
|
|
|
67
|
-
|
|
68
|
-
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
69
|
-
document.documentElement.dataset[key] = value
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
themeStore.restore()
|
|
74
|
-
|
|
75
|
-
themeStore.sync()
|
|
76
|
-
})()
|
|
77
|
-
</script>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Alternatively, inline the stringified version to reduce the number of HTTP requests:
|
|
43
|
+
When storing theme selection in `localStorage`, an inline `<script>` that restores user preferences and updates the DOM before first paint is required to prevent flicker.
|
|
81
44
|
|
|
82
45
|
```ts
|
|
83
|
-
import
|
|
84
|
-
import { resonareInlineScript } from 'resonare/inline-script'
|
|
46
|
+
import { createInlineThemeScript, type ThemeStoreConfig } from 'resonare'
|
|
85
47
|
|
|
86
48
|
const CONFIG = {
|
|
87
49
|
colorScheme: {
|
|
@@ -96,42 +58,49 @@ const CONFIG = {
|
|
|
96
58
|
},
|
|
97
59
|
} as const satisfies ThemeStoreConfig
|
|
98
60
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
61
|
+
export const themeScript = createInlineThemeScript([
|
|
62
|
+
{
|
|
63
|
+
config: CONFIG,
|
|
64
|
+
handler: ({ resolvedThemes }) => {
|
|
65
|
+
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
66
|
+
document.documentElement.dataset[key] = value
|
|
67
|
+
})
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
])
|
|
71
|
+
```
|
|
104
72
|
|
|
105
|
-
|
|
106
|
-
const themeStore = window.resonare.createThemeStore({ config })
|
|
73
|
+
### 2. Inject inline script
|
|
107
74
|
|
|
108
|
-
|
|
109
|
-
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
110
|
-
document.documentElement.dataset[key] = value
|
|
111
|
-
})
|
|
112
|
-
})
|
|
75
|
+
Inject the script as below into the `<head>` of your HTML document. This differs by framework. See the examples below.
|
|
113
76
|
|
|
114
|
-
|
|
77
|
+
```tsx
|
|
78
|
+
// React.js
|
|
79
|
+
<script>{themeScript}</script>
|
|
115
80
|
|
|
116
|
-
|
|
117
|
-
}
|
|
81
|
+
// TanStack Router/Start
|
|
82
|
+
import { ScriptOnce } from '@tanstack/router'
|
|
118
83
|
|
|
119
|
-
|
|
120
|
-
|
|
84
|
+
<ScriptOnce>{themeScript}</ScriptOnce>
|
|
85
|
+
|
|
86
|
+
// Astro.js
|
|
87
|
+
<script is:inline set:html={themeScript} />
|
|
121
88
|
```
|
|
122
89
|
|
|
123
|
-
|
|
90
|
+
### 3. Initialize the store
|
|
124
91
|
|
|
125
|
-
|
|
126
|
-
/// <reference types="resonare/global" />
|
|
127
|
-
```
|
|
92
|
+
Refer to the [Framework Integration](#framework-integration) section for examples.
|
|
128
93
|
|
|
129
94
|
## API
|
|
130
95
|
|
|
131
96
|
### `createThemeStore`
|
|
132
97
|
|
|
133
98
|
```ts
|
|
134
|
-
import {
|
|
99
|
+
import {
|
|
100
|
+
createThemeStore,
|
|
101
|
+
localStorageAdapter,
|
|
102
|
+
type ThemeStoreConfig,
|
|
103
|
+
} from 'resonare'
|
|
135
104
|
|
|
136
105
|
const CONFIG = {
|
|
137
106
|
colorScheme: {
|
|
@@ -164,57 +133,13 @@ const CONFIG = {
|
|
|
164
133
|
},
|
|
165
134
|
} as const satisfies ThemeStoreConfig
|
|
166
135
|
|
|
167
|
-
|
|
168
|
-
interface ThemeStoreRegistry {
|
|
169
|
-
resonare: ThemeStore<typeof CONFIG>
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const themeStore = createThemeStore({
|
|
174
|
-
// optional, default 'resonare'
|
|
175
|
-
// should be unique, also used as client storage key
|
|
176
|
-
key: 'resonare',
|
|
177
|
-
|
|
178
|
-
// required, specify theme and options
|
|
179
|
-
config: CONFIG,
|
|
180
|
-
|
|
136
|
+
const themeStore = createThemeStore(CONFIG, {
|
|
181
137
|
// optional, useful for server-side persistence
|
|
182
138
|
initialState: persistedStateFromDb, // persisted state returned by themeStore.toPersist()
|
|
183
139
|
|
|
184
|
-
// optional, specify your own client storage
|
|
140
|
+
// optional, specify your own client storage or null to disable client-side persistence
|
|
185
141
|
// localStorage is used by default
|
|
186
|
-
storage: ({
|
|
187
|
-
get: (key: string) => {
|
|
188
|
-
return JSON.parse(localStorage.getItem(key) || 'null')
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
set: (key: string, value: object) => {
|
|
192
|
-
localStorage.setItem(key, JSON.stringify(value))
|
|
193
|
-
},
|
|
194
|
-
|
|
195
|
-
watch: (cb: (key: string, value: unknown) => void) => {
|
|
196
|
-
const controller = new AbortController()
|
|
197
|
-
|
|
198
|
-
window.addEventListener(
|
|
199
|
-
'storage',
|
|
200
|
-
(e) => {
|
|
201
|
-
if (e.storageArea !== window.localStorage) return
|
|
202
|
-
|
|
203
|
-
cb(e.key, JSON.parse(e.newValue!))
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
signal: AbortSignal.any([
|
|
207
|
-
abortController.signal,
|
|
208
|
-
controller.signal,
|
|
209
|
-
]),
|
|
210
|
-
},
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
return () => {
|
|
214
|
-
controller.abort()
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
})
|
|
142
|
+
storage: localStorageAdapter({ key: 'resonare' }),
|
|
218
143
|
})
|
|
219
144
|
|
|
220
145
|
// get current theme selection
|
|
@@ -235,11 +160,13 @@ themeStore.toPersist()
|
|
|
235
160
|
// restore persisted state from client-side storage
|
|
236
161
|
themeStore.restore()
|
|
237
162
|
|
|
238
|
-
// sync
|
|
239
|
-
themeStore.sync()
|
|
163
|
+
// sync user preferences across tabs/windows if supported by the storage adapter
|
|
164
|
+
const stopSync = themeStore.sync()
|
|
165
|
+
|
|
166
|
+
stopSync?.()
|
|
240
167
|
|
|
241
168
|
// subscribe to theme changes
|
|
242
|
-
themeStore.subscribe(({ themes, resolvedThemes }) => {
|
|
169
|
+
const unsubscribe = themeStore.subscribe(({ themes, resolvedThemes }) => {
|
|
243
170
|
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
244
171
|
if (key === 'sidebarWidth') {
|
|
245
172
|
document.documentElement.style.setProperty('--sidebar-width', `${value}px`)
|
|
@@ -248,36 +175,19 @@ themeStore.subscribe(({ themes, resolvedThemes }) => {
|
|
|
248
175
|
}
|
|
249
176
|
})
|
|
250
177
|
})
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### `getThemeStore`
|
|
254
|
-
|
|
255
|
-
```ts
|
|
256
|
-
import { getThemeStore } from 'resonare'
|
|
257
|
-
|
|
258
|
-
// get an existing theme store by key
|
|
259
|
-
const themeStore = getThemeStore('resonare')
|
|
260
|
-
```
|
|
261
178
|
|
|
262
|
-
|
|
179
|
+
unsubscribe()
|
|
263
180
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
// destroy an existing theme store by key
|
|
268
|
-
destroyThemeStore('resonare')
|
|
181
|
+
// destroy the store and clean up event listeners
|
|
182
|
+
themeStore.destroy()
|
|
269
183
|
```
|
|
270
184
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
### React
|
|
185
|
+
### `createInlineThemeScript`
|
|
274
186
|
|
|
275
|
-
|
|
187
|
+
Generates a self-contained script string that restores persisted user preferences before first paint.
|
|
276
188
|
|
|
277
|
-
```
|
|
278
|
-
import
|
|
279
|
-
import { getThemesAndOptions, type ThemeStoreConfig } from 'resonare'
|
|
280
|
-
import { useResonare } from 'resonare/react'
|
|
189
|
+
```ts
|
|
190
|
+
import { createInlineThemeScript, type ThemeStoreConfig } from 'resonare'
|
|
281
191
|
|
|
282
192
|
const CONFIG = {
|
|
283
193
|
colorScheme: {
|
|
@@ -292,12 +202,92 @@ const CONFIG = {
|
|
|
292
202
|
},
|
|
293
203
|
} as const satisfies ThemeStoreConfig
|
|
294
204
|
|
|
205
|
+
const script = createInlineThemeScript([
|
|
206
|
+
{
|
|
207
|
+
config: CONFIG,
|
|
208
|
+
handler: ({ resolvedThemes }) => {
|
|
209
|
+
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
210
|
+
document.documentElement.dataset[key] = value
|
|
211
|
+
})
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
])
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Framework Integration
|
|
218
|
+
|
|
219
|
+
### React
|
|
220
|
+
|
|
221
|
+
#### Client-side persistence
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
import * as React from 'react'
|
|
225
|
+
import {
|
|
226
|
+
createInlineThemeScript,
|
|
227
|
+
createThemeStore,
|
|
228
|
+
getThemesAndOptions,
|
|
229
|
+
type ThemeStoreConfig,
|
|
230
|
+
} from 'resonare'
|
|
231
|
+
import { useResonare } from 'resonare/react'
|
|
232
|
+
|
|
233
|
+
const STORE = {
|
|
234
|
+
key: 'demo',
|
|
235
|
+
config: {
|
|
236
|
+
colorScheme: {
|
|
237
|
+
options: [
|
|
238
|
+
{
|
|
239
|
+
value: 'system',
|
|
240
|
+
media: ['(prefers-color-scheme: dark)', 'dark', 'light'],
|
|
241
|
+
},
|
|
242
|
+
'light',
|
|
243
|
+
'dark',
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
contrast: {
|
|
247
|
+
options: [
|
|
248
|
+
{
|
|
249
|
+
value: 'system',
|
|
250
|
+
media: [
|
|
251
|
+
'(prefers-contrast: more) and (forced-colors: none)',
|
|
252
|
+
'high',
|
|
253
|
+
'standard',
|
|
254
|
+
],
|
|
255
|
+
},
|
|
256
|
+
'standard',
|
|
257
|
+
'high',
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
handler: ({ resolvedThemes }) => {
|
|
262
|
+
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
263
|
+
document.documentElement.dataset[key] = String(value)
|
|
264
|
+
})
|
|
265
|
+
},
|
|
266
|
+
} as const satisfies Parameters<typeof createInlineThemeScript>[0][number]
|
|
267
|
+
|
|
268
|
+
export const themeScript = createInlineThemeScript([STORE])
|
|
269
|
+
|
|
270
|
+
const themeStore = createThemeStore(STORE.config)
|
|
271
|
+
|
|
295
272
|
function ThemeSelect() {
|
|
296
|
-
const { themes, setThemes } =
|
|
297
|
-
|
|
298
|
-
)
|
|
273
|
+
const { themes, setThemes, restore, subscribe, sync } =
|
|
274
|
+
useResonare(themeStore)
|
|
299
275
|
|
|
300
|
-
|
|
276
|
+
React.useEffect(() => {
|
|
277
|
+
restore()
|
|
278
|
+
|
|
279
|
+
const unsubscribe = subscribe(STORE.handler)
|
|
280
|
+
|
|
281
|
+
const stopSync = sync()
|
|
282
|
+
|
|
283
|
+
return () => {
|
|
284
|
+
unsubscribe()
|
|
285
|
+
|
|
286
|
+
stopSync?.()
|
|
287
|
+
}
|
|
288
|
+
}, [restore, subscribe, sync])
|
|
289
|
+
|
|
290
|
+
return getThemesAndOptions(STORE.config).map(([theme, options]) => (
|
|
301
291
|
<div key={theme}>
|
|
302
292
|
<label htmlFor={theme}>{theme}</label>
|
|
303
293
|
<select
|
|
@@ -319,11 +309,12 @@ function ThemeSelect() {
|
|
|
319
309
|
}
|
|
320
310
|
```
|
|
321
311
|
|
|
322
|
-
|
|
312
|
+
#### Server-side persistence
|
|
323
313
|
|
|
324
|
-
|
|
314
|
+
The inline script is not required.
|
|
325
315
|
|
|
326
316
|
```tsx
|
|
317
|
+
import * as React from 'react'
|
|
327
318
|
import {
|
|
328
319
|
createThemeStore,
|
|
329
320
|
getThemesAndOptions,
|
|
@@ -331,7 +322,6 @@ import {
|
|
|
331
322
|
type ThemeStoreConfig,
|
|
332
323
|
} from 'resonare'
|
|
333
324
|
import { useResonare } from 'resonare/react'
|
|
334
|
-
import * as React from 'react'
|
|
335
325
|
|
|
336
326
|
const CONFIG = {
|
|
337
327
|
colorScheme: {
|
|
@@ -344,16 +334,33 @@ const CONFIG = {
|
|
|
344
334
|
|
|
345
335
|
export function ThemeSelect({ persistedStateFromDb }) {
|
|
346
336
|
const [themeStore] = React.useState(() =>
|
|
347
|
-
createThemeStore({
|
|
348
|
-
config: CONFIG,
|
|
337
|
+
createThemeStore(CONFIG, {
|
|
349
338
|
initialState: persistedStateFromDb,
|
|
350
|
-
|
|
339
|
+
// pass null instead if syncing across tabs/windows is not needed
|
|
340
|
+
storage: memoryStorageAdapter({ key: 'resonare' }),
|
|
351
341
|
}),
|
|
352
342
|
)
|
|
353
343
|
|
|
354
|
-
const { themes, setThemes
|
|
355
|
-
|
|
356
|
-
|
|
344
|
+
const { themes, setThemes, restore, subscribe, sync } =
|
|
345
|
+
useResonare(themeStore)
|
|
346
|
+
|
|
347
|
+
React.useEffect(() => {
|
|
348
|
+
restore()
|
|
349
|
+
|
|
350
|
+
const unsubscribe = subscribe(({ resolvedThemes }) => {
|
|
351
|
+
Object.entries(resolvedThemes).forEach(([key, value]) => {
|
|
352
|
+
document.documentElement.dataset[key] = String(value)
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
const stopSync = sync()
|
|
357
|
+
|
|
358
|
+
return () => {
|
|
359
|
+
unsubscribe()
|
|
360
|
+
|
|
361
|
+
stopSync?.()
|
|
362
|
+
}
|
|
363
|
+
}, [restore, subscribe, sync])
|
|
357
364
|
|
|
358
365
|
return getThemesAndOptions(CONFIG).map(([theme, options]) => (
|
|
359
366
|
<div key={theme}>
|
|
@@ -364,7 +371,6 @@ export function ThemeSelect({ persistedStateFromDb }) {
|
|
|
364
371
|
onChange={async (e) => {
|
|
365
372
|
setThemes({ [theme]: e.target.value })
|
|
366
373
|
|
|
367
|
-
// save to server-side storage
|
|
368
374
|
await saveToDb(themeStore.toPersist())
|
|
369
375
|
}}
|
|
370
376
|
value={themes[theme]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
//#region src/storage.d.ts
|
|
2
2
|
type StorageAdapter = {
|
|
3
|
-
get: (
|
|
4
|
-
set: (
|
|
5
|
-
broadcast?: (
|
|
6
|
-
watch?: (cb: (
|
|
3
|
+
get: () => object | null;
|
|
4
|
+
set: (value: object) => void;
|
|
5
|
+
broadcast?: (value: object) => void;
|
|
6
|
+
watch?: (cb: (value: object) => void) => () => void;
|
|
7
7
|
};
|
|
8
8
|
type StorageAdapterCreate = ({
|
|
9
9
|
abortController
|
|
10
10
|
}: {
|
|
11
11
|
abortController: AbortController;
|
|
12
12
|
}) => StorageAdapter;
|
|
13
|
-
type StorageAdapterCreator<Options> = (options
|
|
13
|
+
type StorageAdapterCreator<Options> = (options: Options) => StorageAdapterCreate;
|
|
14
14
|
declare const localStorageAdapter: StorageAdapterCreator<{
|
|
15
|
+
key: string;
|
|
15
16
|
type?: 'localStorage' | 'sessionStorage';
|
|
16
17
|
}>;
|
|
17
|
-
declare const memoryStorageAdapter: StorageAdapterCreator<
|
|
18
|
+
declare const memoryStorageAdapter: StorageAdapterCreator<{
|
|
19
|
+
key: string;
|
|
20
|
+
}>;
|
|
18
21
|
//#endregion
|
|
19
22
|
//#region src/index.d.ts
|
|
20
23
|
type ThemeValue = string | number | boolean;
|
|
@@ -51,13 +54,10 @@ type NonSystemOptionValues<T extends ThemeStoreConfig, K extends keyof T> = T[K]
|
|
|
51
54
|
} ? never : U['value'] : never : never;
|
|
52
55
|
type SystemOptions<T extends ThemeStoreConfig> = { [K in ThemeKeysWithSystemOption<T>]?: [NonSystemOptionValues<T, K>, NonSystemOptionValues<T, K>] };
|
|
53
56
|
type PersistedState<T extends ThemeStoreConfig> = {
|
|
54
|
-
version: 1;
|
|
55
57
|
themes: Partial<Themes<T>>;
|
|
56
58
|
systemOptions: SystemOptions<T>;
|
|
57
59
|
};
|
|
58
|
-
type
|
|
59
|
-
key?: string;
|
|
60
|
-
config: T;
|
|
60
|
+
type ThemeStoreOptions<T extends ThemeStoreConfig> = {
|
|
61
61
|
initialState?: Partial<PersistedState<T>>;
|
|
62
62
|
storage?: StorageAdapterCreate | null;
|
|
63
63
|
};
|
|
@@ -68,30 +68,26 @@ declare function getThemesAndOptions<T extends ThemeStoreConfig>(config: T): The
|
|
|
68
68
|
declare function getDefaultThemes<T extends ThemeStoreConfig>(config: T): Themes<T>;
|
|
69
69
|
declare class ThemeStore<T extends ThemeStoreConfig> {
|
|
70
70
|
#private;
|
|
71
|
-
constructor({
|
|
72
|
-
key,
|
|
73
|
-
config,
|
|
71
|
+
constructor(config: T, {
|
|
74
72
|
initialState,
|
|
75
73
|
storage
|
|
76
|
-
}
|
|
74
|
+
}?: ThemeStoreOptions<T>);
|
|
77
75
|
getThemes: () => Themes<T>;
|
|
78
76
|
getResolvedThemes: () => Themes<T>;
|
|
79
77
|
setThemes: (themes: Partial<Themes<T>> | ((currentThemes: Themes<T>) => Partial<Themes<T>>)) => void;
|
|
80
78
|
updateSystemOption: <K extends ThemeKeysWithSystemOption<T>>(themeKey: K, [ifMatch, ifNotMatch]: [NonSystemOptionValues<T, K>, NonSystemOptionValues<T, K>]) => void;
|
|
81
79
|
toPersist: () => PersistedState<T>;
|
|
82
80
|
restore: () => void;
|
|
83
|
-
subscribe: (callback: Listener<T
|
|
84
|
-
immediate
|
|
85
|
-
}?: {
|
|
86
|
-
immediate?: boolean;
|
|
87
|
-
}) => (() => void);
|
|
81
|
+
subscribe: (callback: Listener<T>) => (() => void);
|
|
88
82
|
sync: () => (() => void) | undefined;
|
|
89
|
-
|
|
83
|
+
destroy: () => void;
|
|
90
84
|
}
|
|
91
|
-
declare
|
|
92
|
-
declare
|
|
93
|
-
|
|
94
|
-
|
|
85
|
+
declare function createThemeStore<T extends ThemeStoreConfig>(config: T, options?: ThemeStoreOptions<T>): ThemeStore<T>;
|
|
86
|
+
declare function createInlineThemeScript(configs: Array<{
|
|
87
|
+
key?: string;
|
|
88
|
+
config: ThemeStoreConfig;
|
|
89
|
+
handler: Listener<ThemeStoreConfig>;
|
|
90
|
+
}>): string;
|
|
95
91
|
//#endregion
|
|
96
|
-
export { StorageAdapter, StorageAdapterCreate, StorageAdapterCreator, ThemeAndOptions, ThemeStore, ThemeStoreConfig,
|
|
92
|
+
export { StorageAdapter, StorageAdapterCreate, StorageAdapterCreator, ThemeAndOptions, type ThemeStore, ThemeStoreConfig, Themes, createInlineThemeScript, createThemeStore, getDefaultThemes, getThemesAndOptions, localStorageAdapter, memoryStorageAdapter };
|
|
97
93
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/storage.ts","../src/index.ts"],"mappings":";KAEY,cAAA;EACX,GAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/storage.ts","../src/index.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,244 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
var name = "resonare";
|
|
3
|
-
//#endregion
|
|
4
|
-
//#region src/storage.ts
|
|
5
|
-
const localStorageAdapter = ({ type = "localStorage" } = {}) => {
|
|
6
|
-
return ({ abortController }) => {
|
|
7
|
-
return {
|
|
8
|
-
get: (key) => {
|
|
9
|
-
return JSON.parse(window[type].getItem(key) || "null");
|
|
10
|
-
},
|
|
11
|
-
set: (key, value) => {
|
|
12
|
-
window[type].setItem(key, JSON.stringify(value));
|
|
13
|
-
},
|
|
14
|
-
watch: (cb) => {
|
|
15
|
-
const controller = new AbortController();
|
|
16
|
-
window.addEventListener("storage", (e) => {
|
|
17
|
-
if (e.storageArea !== window[type]) return;
|
|
18
|
-
cb(e.key, JSON.parse(e.newValue));
|
|
19
|
-
}, { signal: AbortSignal.any([abortController.signal, controller.signal]) });
|
|
20
|
-
return () => {
|
|
21
|
-
controller.abort();
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
const memoryStorageAdapter = () => {
|
|
28
|
-
return ({ abortController }) => {
|
|
29
|
-
const storage = /* @__PURE__ */ new Map();
|
|
30
|
-
const channel = new BroadcastChannel(name);
|
|
31
|
-
return {
|
|
32
|
-
get: (key) => {
|
|
33
|
-
return storage.get(key) || null;
|
|
34
|
-
},
|
|
35
|
-
set: (key, value) => {
|
|
36
|
-
storage.set(key, value);
|
|
37
|
-
},
|
|
38
|
-
broadcast: (key, value) => {
|
|
39
|
-
channel.postMessage({
|
|
40
|
-
key,
|
|
41
|
-
value
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
watch: (cb) => {
|
|
45
|
-
const controller = new AbortController();
|
|
46
|
-
channel.addEventListener("message", (e) => {
|
|
47
|
-
cb(e.data.key, e.data.value);
|
|
48
|
-
}, { signal: AbortSignal.any([abortController.signal, controller.signal]) });
|
|
49
|
-
return () => {
|
|
50
|
-
controller.abort();
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/index.ts
|
|
58
|
-
function getThemesAndOptions(config) {
|
|
59
|
-
return Object.entries(config).map(([themeKey, themeConfig]) => {
|
|
60
|
-
return [themeKey, (themeConfig.options || []).map((option) => typeof option === "object" ? option.value : option)];
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
function getDefaultThemes(config) {
|
|
64
|
-
return Object.fromEntries(Object.entries(config).map(([themeKey, themeConfig]) => {
|
|
65
|
-
return [themeKey, themeConfig.initialValue ?? (typeof themeConfig.options[0] === "object" ? themeConfig.options[0].value : themeConfig.options[0])];
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
68
|
-
var ThemeStore = class {
|
|
69
|
-
#defaultThemes;
|
|
70
|
-
#currentThemes;
|
|
71
|
-
#options;
|
|
72
|
-
#systemOptions;
|
|
73
|
-
#storage;
|
|
74
|
-
#listeners = /* @__PURE__ */ new Set();
|
|
75
|
-
#mediaQueryCache;
|
|
76
|
-
#abortController = new AbortController();
|
|
77
|
-
constructor({ key = name, config, initialState = {}, storage = localStorageAdapter() }) {
|
|
78
|
-
const systemOptions = { ...initialState.systemOptions };
|
|
79
|
-
this.#options = {
|
|
80
|
-
key,
|
|
81
|
-
config: Object.fromEntries(Object.entries(config).map(([themeKey, themeConfig]) => {
|
|
82
|
-
const entries = (themeConfig.options || []).map((option) => {
|
|
83
|
-
if (typeof option === "object") {
|
|
84
|
-
if (option.media && !Object.hasOwn(systemOptions, themeKey)) systemOptions[themeKey] = [option.media[1], option.media[2]];
|
|
85
|
-
return [String(option.value), option];
|
|
86
|
-
}
|
|
87
|
-
return [String(option), { value: option }];
|
|
88
|
-
});
|
|
89
|
-
return [themeKey, Object.fromEntries(entries)];
|
|
90
|
-
}))
|
|
91
|
-
};
|
|
92
|
-
this.#systemOptions = systemOptions;
|
|
93
|
-
this.#defaultThemes = getDefaultThemes(config);
|
|
94
|
-
this.#currentThemes = {
|
|
95
|
-
...this.#defaultThemes,
|
|
96
|
-
...initialState.themes
|
|
97
|
-
};
|
|
98
|
-
this.#storage = storage?.({ abortController: this.#abortController }) ?? null;
|
|
99
|
-
this.#mediaQueryCache = {};
|
|
100
|
-
}
|
|
101
|
-
getThemes = () => {
|
|
102
|
-
return this.#currentThemes;
|
|
103
|
-
};
|
|
104
|
-
getResolvedThemes = () => {
|
|
105
|
-
return this.#resolveThemes();
|
|
106
|
-
};
|
|
107
|
-
setThemes = (themes) => {
|
|
108
|
-
const updatedThemes = typeof themes === "function" ? themes(this.#currentThemes) : themes;
|
|
109
|
-
this.#setThemesAndNotify({
|
|
110
|
-
...this.#currentThemes,
|
|
111
|
-
...updatedThemes
|
|
112
|
-
});
|
|
113
|
-
const stateToPersist = this.toPersist();
|
|
114
|
-
if (this.#storage) {
|
|
115
|
-
this.#storage.set(this.#options.key, stateToPersist);
|
|
116
|
-
this.#storage.broadcast?.(this.#options.key, stateToPersist);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
updateSystemOption = (themeKey, [ifMatch, ifNotMatch]) => {
|
|
120
|
-
this.#systemOptions[themeKey] = [ifMatch, ifNotMatch];
|
|
121
|
-
this.setThemes({ ...this.#currentThemes });
|
|
122
|
-
};
|
|
123
|
-
toPersist = () => {
|
|
124
|
-
return {
|
|
125
|
-
version: 1,
|
|
126
|
-
themes: this.#currentThemes,
|
|
127
|
-
systemOptions: this.#systemOptions
|
|
128
|
-
};
|
|
129
|
-
};
|
|
130
|
-
restore = () => {
|
|
131
|
-
let persistedState = this.#storage?.get(this.#options.key);
|
|
132
|
-
if (!persistedState) {
|
|
133
|
-
this.#setThemesAndNotify({ ...this.#defaultThemes });
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (!Object.hasOwn(persistedState, "version")) persistedState = {
|
|
137
|
-
version: 1,
|
|
138
|
-
themes: persistedState,
|
|
139
|
-
systemOptions: this.#systemOptions
|
|
140
|
-
};
|
|
141
|
-
this.#systemOptions = {
|
|
142
|
-
...this.#systemOptions,
|
|
143
|
-
...persistedState.systemOptions
|
|
144
|
-
};
|
|
145
|
-
this.#setThemesAndNotify({
|
|
146
|
-
...this.#defaultThemes,
|
|
147
|
-
...persistedState.themes
|
|
148
|
-
});
|
|
149
|
-
};
|
|
150
|
-
subscribe = (callback, { immediate = false } = {}) => {
|
|
151
|
-
if (immediate) callback({
|
|
152
|
-
themes: this.#currentThemes,
|
|
153
|
-
resolvedThemes: this.#resolveThemes()
|
|
154
|
-
});
|
|
155
|
-
this.#listeners.add(callback);
|
|
156
|
-
return () => {
|
|
157
|
-
this.#listeners.delete(callback);
|
|
158
|
-
};
|
|
159
|
-
};
|
|
160
|
-
sync = () => {
|
|
161
|
-
if (!this.#storage?.watch) return;
|
|
162
|
-
return this.#storage.watch((key, persistedState) => {
|
|
163
|
-
if (key !== this.#options.key) return;
|
|
164
|
-
this.#systemOptions = persistedState.systemOptions;
|
|
165
|
-
this.#setThemesAndNotify(persistedState.themes);
|
|
166
|
-
});
|
|
167
|
-
};
|
|
168
|
-
___destroy = () => {
|
|
169
|
-
this.#listeners.clear();
|
|
170
|
-
this.#abortController.abort();
|
|
171
|
-
};
|
|
172
|
-
#setThemesAndNotify = (themes) => {
|
|
173
|
-
this.#currentThemes = themes;
|
|
174
|
-
this.#notify();
|
|
175
|
-
};
|
|
176
|
-
#resolveThemes = () => {
|
|
177
|
-
return Object.fromEntries(Object.entries(this.#currentThemes).map(([themeKey, optionKey]) => {
|
|
178
|
-
const option = this.#options.config[themeKey]?.[optionKey];
|
|
179
|
-
return [themeKey, option ? this.#resolveThemeOption({
|
|
180
|
-
themeKey,
|
|
181
|
-
option
|
|
182
|
-
}) : optionKey];
|
|
183
|
-
}));
|
|
184
|
-
};
|
|
185
|
-
#resolveThemeOption = ({ themeKey, option }) => {
|
|
186
|
-
if (!option.media) return option.value;
|
|
187
|
-
if (!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined")) {
|
|
188
|
-
console.warn(`[${name}] Option with key "media" cannot be resolved in server environment.`);
|
|
189
|
-
return option.value;
|
|
190
|
-
}
|
|
191
|
-
const [mediaQuery] = option.media;
|
|
192
|
-
if (!this.#mediaQueryCache[mediaQuery]) {
|
|
193
|
-
const mediaQueryList = window.matchMedia(mediaQuery);
|
|
194
|
-
this.#mediaQueryCache[mediaQuery] = mediaQueryList;
|
|
195
|
-
mediaQueryList.addEventListener("change", () => {
|
|
196
|
-
if (this.#currentThemes[themeKey] === option.value) this.#setThemesAndNotify({ ...this.#currentThemes });
|
|
197
|
-
}, { signal: this.#abortController.signal });
|
|
198
|
-
}
|
|
199
|
-
const [ifMatch, ifNotMatch] = this.#systemOptions[themeKey];
|
|
200
|
-
return this.#mediaQueryCache[mediaQuery].matches ? ifMatch : ifNotMatch;
|
|
201
|
-
};
|
|
202
|
-
#notify = () => {
|
|
203
|
-
for (const listener of this.#listeners) listener({
|
|
204
|
-
themes: this.#currentThemes,
|
|
205
|
-
resolvedThemes: this.#resolveThemes()
|
|
206
|
-
});
|
|
207
|
-
};
|
|
208
|
-
};
|
|
209
|
-
var Registry = class {
|
|
210
|
-
#registry = /* @__PURE__ */ new Map();
|
|
211
|
-
create = (params) => {
|
|
212
|
-
const storeKey = params.key || name;
|
|
213
|
-
let store = this.#registry.get(storeKey);
|
|
214
|
-
if (!store) {
|
|
215
|
-
store = new ThemeStore(params);
|
|
216
|
-
this.#registry.set(storeKey, store);
|
|
217
|
-
}
|
|
218
|
-
return store;
|
|
219
|
-
};
|
|
220
|
-
get = (key) => {
|
|
221
|
-
const storeKey = key || name;
|
|
222
|
-
const store = this.#registry.get(storeKey);
|
|
223
|
-
if (!store) {
|
|
224
|
-
console.error(`[${name}] Theme store with key '${storeKey}' could not be found. Please run \`createThemeStore\` with key '${storeKey}' first.`);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
return store;
|
|
228
|
-
};
|
|
229
|
-
destroy = (key) => {
|
|
230
|
-
const storeKey = key || name;
|
|
231
|
-
const store = this.#registry.get(storeKey);
|
|
232
|
-
if (!store) return;
|
|
233
|
-
store.___destroy();
|
|
234
|
-
this.#registry.delete(storeKey);
|
|
235
|
-
};
|
|
236
|
-
};
|
|
237
|
-
const registry = new Registry();
|
|
238
|
-
const createThemeStore = registry.create;
|
|
239
|
-
const getThemeStore = registry.get;
|
|
240
|
-
const destroyThemeStore = registry.destroy;
|
|
241
|
-
//#endregion
|
|
242
|
-
export { ThemeStore, createThemeStore, destroyThemeStore, getDefaultThemes, getThemeStore, getThemesAndOptions, localStorageAdapter, memoryStorageAdapter };
|
|
243
|
-
|
|
1
|
+
var e=`resonare-monorepo`;const t=({key:e,type:t=`localStorage`})=>({abortController:n})=>({get:()=>JSON.parse(window[t].getItem(e)||`null`),set:n=>{window[t].setItem(e,JSON.stringify(n))},watch:r=>{let i=new AbortController;return window.addEventListener(`storage`,n=>{n.storageArea===window[t]&&n.key===e&&r(JSON.parse(n.newValue))},{signal:AbortSignal.any([n.signal,i.signal])}),()=>{i.abort()}}}),n=({key:t})=>({abortController:n})=>{let r=new Map,i=new BroadcastChannel(e);return{get:()=>r.get(t)||null,set:e=>{r.set(t,e)},broadcast:e=>{i.postMessage({key:t,value:e})},watch:e=>{let r=new AbortController;return i.addEventListener(`message`,n=>{n.data.key===t&&e(n.data.value)},{signal:AbortSignal.any([n.signal,r.signal])}),()=>{r.abort()}}}};function r(e){return Object.entries(e).map(([e,t])=>[e,(t.options||[]).map(e=>typeof e==`object`?e.value:e)])}function i(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,t.initialValue??(typeof t.options[0]==`object`?t.options[0].value:t.options[0])]))}var a=class{#e;#t;#n;#r;#i;#a=new Set;#o;#s=new AbortController;constructor(n,{initialState:r={},storage:a=t({key:e})}={}){let o={...r.systemOptions};this.#n=Object.fromEntries(Object.entries(n).map(([e,t])=>{let n=(t.options||[]).map(t=>typeof t==`object`?(t.media&&!Object.hasOwn(o,e)&&(o[e]=[t.media[1],t.media[2]]),[String(t.value),t]):[String(t),{value:t}]);return[e,Object.fromEntries(n)]})),this.#r=o,this.#e=i(n),this.#t={...this.#e,...r.themes},this.#i=a?.({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(n),this.#i.broadcast?.(n))};updateSystemOption=(e,[t,n])=>{this.#r[e]=[t,n],this.setThemes({...this.#t})};toPersist=()=>({themes:this.#t,systemOptions:this.#r});restore=()=>{let e=this.#i?.get();if(!e){this.#c({...this.#e});return}this.#r={...this.#r,...e.systemOptions},this.#c({...this.#e,...e.themes})};subscribe=e=>(this.#a.add(e),()=>{this.#a.delete(e)});sync=()=>{if(this.#i?.watch)return this.#i.watch(e=>{this.#r=e.systemOptions,this.#c(e.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[e]?.[t];return[e,n?this.#u({themeKey:e,option:n}):t]}));#u=({themeKey:t,option:n})=>{if(!n.media)return n.value;if(!(typeof window<`u`&&window.document!==void 0&&window.document.createElement!==void 0))return console.warn(`[${e}] Option with key "media" cannot be resolved in server environment.`),n.value;let[r]=n.media;if(!this.#o[r]){let e=window.matchMedia(r);this.#o[r]=e,e.addEventListener(`change`,()=>{this.#t[t]===n.value&&this.#c({...this.#t})},{signal:this.#s.signal})}let[i,a]=this.#r[t];return this.#o[r].matches?i:a};#d=()=>{for(let e of this.#a)e({themes:this.#t,resolvedThemes:this.#l()})}};function o(e,t={}){return new a(e,t)}const s=(({key:e,config:t})=>{let n=JSON.parse(localStorage.getItem(e)||`{"themes":{}}`).themes;return Object.entries(t).reduce((e,[t,r])=>{let i=r.options,a=i?.[0],o=n[t]??r.initialValue??(typeof a==`object`?a.value:a);if(e.themes[t]=o,i){let n=i.find(e=>typeof e==`object`&&!!e.media&&e.value===o);if(n){let[r,i,a]=n.media;e.resolvedThemes[t]=matchMedia(r).matches?i:a}else e.resolvedThemes[t]=o}else e.resolvedThemes[t]=o;return e},{themes:{},resolvedThemes:{}})}).toString();function c(t){return`(()=>{var r=${s};[${t.map(({key:t=e,config:n,handler:r})=>`{key:${JSON.stringify(t)},config:${JSON.stringify(n)},h:${r.toString()}}`).join(`,`)}].forEach((c)=>c.h(r(c)))})()`}export{c as createInlineThemeScript,o as createThemeStore,i as getDefaultThemes,r as getThemesAndOptions,t as localStorageAdapter,n as memoryStorageAdapter};
|
|
244
2
|
//# 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","ThemeValue","ThemeOption","value","T","media","ThemeConfig","options","ReadonlyArray","initialValue","ThemeStoreConfig","Record","KeyedThemeStoreConfig","Themes","K","U","Listener","themes","resolvedThemes","ThemeKeysWithSystemOption","NonSystemOptionValues","SystemOptions","PersistedState","version","Partial","systemOptions","ThemeStoreConstructor","key","config","initialState","storage","ThemeAndOptions","Array","getThemesAndOptions","Object","entries","map","themeKey","themeConfig","option","getDefaultThemes","fromEntries","ThemeStore","defaultThemes","currentThemes","listeners","Set","mediaQueryCache","MediaQueryList","abortController","AbortController","constructor","keyedConfig","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","params","storeKey","store","ThemeStoreRegistry","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 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\tversion: 1\n\tthemes: Partial<Themes<T>>\n\tsystemOptions: SystemOptions<T>\n}\n\ntype ThemeStoreConstructor<T extends ThemeStoreConfig> = {\n\tkey?: string\n\tconfig: T\n\tinitialState?: Partial<PersistedState<T>>\n\tstorage?: StorageAdapterCreate | null\n}\n\nexport type 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\nexport class ThemeStore<T extends ThemeStoreConfig> {\n\t#defaultThemes: Themes<T>\n\t#currentThemes: Themes<T>\n\n\t#options: {\n\t\tkey: string\n\t\tconfig: KeyedThemeStoreConfig<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}: ThemeStoreConstructor<T>) {\n\t\tconst systemOptions: Record<string, [ThemeValue, ThemeValue]> = {\n\t\t\t...initialState.systemOptions,\n\t\t}\n\n\t\tconst 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 && !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\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\t\t\t\treturn [themeKey, Object.fromEntries(entries)]\n\t\t\t}),\n\t\t) as KeyedThemeStoreConfig<T>\n\n\t\tthis.#options = {\n\t\t\tkey,\n\t\t\tconfig: keyedConfig,\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): 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\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<ThemeStoreConfig>>()\n\n\tcreate = <T extends ThemeStoreConfig>(\n\t\tparams: ThemeStoreConstructor<T>,\n\t): ThemeStore<T> => {\n\t\tconst storeKey = params.key || PACKAGE_NAME\n\n\t\tlet store = this.#registry.get(storeKey) as ThemeStore<T>\n\n\t\tif (!store) {\n\t\t\tstore = new ThemeStore<T>(params)\n\n\t\t\tthis.#registry.set(storeKey, store as ThemeStore<ThemeStoreConfig>)\n\t\t}\n\n\t\treturn store\n\t}\n\n\tget = <T extends keyof ThemeStoreRegistry>(key?: T) => {\n\t\tconst storeKey = key || PACKAGE_NAME\n\n\t\tconst store = this.#registry.get(storeKey)\n\n\t\tif (!store) {\n\t\t\tif (IIFE) {\n\t\t\t\tconsole.error(`Theme store '${storeKey}' not found.`)\n\t\t\t} else {\n\t\t\t\tconsole.error(\n\t\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\t)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\treturn store as ThemeStoreRegistry[T]\n\t}\n\n\tdestroy = <T extends keyof ThemeStoreRegistry>(key?: T) => {\n\t\tconst storeKey = key || PACKAGE_NAME\n\n\t\tconst store = this.#registry.get(storeKey)\n\n\t\tif (!store) return\n\n\t\tstore.___destroy()\n\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","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","listeners","Set","mediaQueryCache","MediaQueryList","abortController","AbortController","constructor","key","hasOwn","String","getThemes","getResolvedThemes","resolveThemes","setThemes","updatedThemes","setThemesAndNotify","stateToPersist","toPersist","set","broadcast","updateSystemOption","ifMatch","ifNotMatch","restore","persistedState","get","subscribe","callback","add","delete","sync","watch","destroy","clear","abort","#setThemesAndNotify","notify","#resolveThemes","optionKey","resolveThemeOption","#resolveThemeOption","window","document","createElement","console","warn","mediaQuery","mediaQueryList","matchMedia","addEventListener","signal","matches","#notify","listener","createThemeStore","restoreThemesString","persistedThemes","JSON","parse","localStorage","getItem","reduce","acc","firstOption","mediaOption","find","Required","toString","createInlineThemeScript","configs","handler","serializedConfigs","stringify","join"],"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: () => object | null\n\tset: (value: object) => void\n\t// del: () => void\n\tbroadcast?: (value: object) => void\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\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\t// del: () => {\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\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\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\t// del: () => {\n\t\t\t// \tstorage.delete(key)\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\nexport type 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\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#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\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\t\t\t...initialState.systemOptions,\n\t\t}\n\n\t\tconst 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 && !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\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\t\t\t\treturn [themeKey, Object.fromEntries(entries)]\n\t\t\t}),\n\t\t) as KeyedThemeStoreConfig<T>\n\n\t\tthis.#keyedConfig = keyedConfig\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(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\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\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.#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\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\tconsole.warn(\n\t\t\t\t`[${PACKAGE_NAME}] Option with key \"media\" cannot be resolved in server environment.`,\n\t\t\t)\n\n\t\t\treturn option.value\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\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 restoreThemesString = (({\n\tkey,\n\tconfig,\n}: {\n\tkey: string\n\tconfig: ThemeStoreConfig\n}) => {\n\tconst persistedThemes = JSON.parse(\n\t\tlocalStorage.getItem(key) || '{\"themes\":{}}',\n\t).themes\n\n\treturn Object.entries(config).reduce<{\n\t\tthemes: Record<string, ThemeValue>\n\t\tresolvedThemes: Record<string, ThemeValue>\n\t}>(\n\t\t(acc, [themeKey, themeConfig]) => {\n\t\t\tconst options = themeConfig.options\n\n\t\t\tconst firstOption = options?.[0]\n\n\t\t\tconst initialValue =\n\t\t\t\tpersistedThemes[themeKey] ??\n\t\t\t\tthemeConfig.initialValue ??\n\t\t\t\t(typeof firstOption === 'object' ? firstOption.value : firstOption!)\n\n\t\t\tacc.themes[themeKey] = initialValue\n\n\t\t\tif (options) {\n\t\t\t\tconst mediaOption = options.find(\n\t\t\t\t\t(option): option is Required<ThemeOption> =>\n\t\t\t\t\t\ttypeof option === 'object' &&\n\t\t\t\t\t\t!!option.media &&\n\t\t\t\t\t\toption.value === initialValue,\n\t\t\t\t)\n\n\t\t\t\tif (mediaOption) {\n\t\t\t\t\tconst [mediaQuery, ifMatch, ifNotMatch] = mediaOption.media\n\n\t\t\t\t\tacc.resolvedThemes[themeKey] = matchMedia(mediaQuery).matches\n\t\t\t\t\t\t? ifMatch\n\t\t\t\t\t\t: ifNotMatch\n\t\t\t\t} else {\n\t\t\t\t\tacc.resolvedThemes[themeKey] = initialValue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tacc.resolvedThemes[themeKey] = initialValue\n\t\t\t}\n\n\t\t\treturn acc\n\t\t},\n\t\t{\n\t\t\tthemes: {},\n\t\t\tresolvedThemes: {},\n\t\t},\n\t)\n}).toString()\n\nexport function createInlineThemeScript(\n\tconfigs: Array<{\n\t\tkey?: string\n\t\tconfig: ThemeStoreConfig\n\t\thandler: Listener<ThemeStoreConfig>\n\t}>,\n) {\n\tconst serializedConfigs = configs.map(\n\t\t({ key = PACKAGE_NAME, config, handler }) =>\n\t\t\t`{key:${JSON.stringify(key)},config:${JSON.stringify(config)},h:${handler.toString()}}`,\n\t)\n\n\treturn `(()=>{var r=${restoreThemesString};[${serializedConfigs.join(',')}].forEach((c)=>c.h(r(c)))})()`\n}\n"],"mappings":"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"}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { ThemeStore, ThemeStoreConfig, Themes } from "./index.js";
|
|
2
2
|
|
|
3
3
|
//#region src/react.d.ts
|
|
4
|
-
declare function useResonare<T extends ThemeStoreConfig>(
|
|
5
|
-
initOnMount
|
|
6
|
-
}?: {
|
|
7
|
-
initOnMount?: boolean | undefined;
|
|
8
|
-
}): {
|
|
4
|
+
declare function useResonare<T extends ThemeStoreConfig>(store: ThemeStore<T>): {
|
|
9
5
|
themes: Themes<T>;
|
|
10
6
|
resolvedThemes: Themes<T>;
|
|
11
7
|
setThemes: (themes: Partial<Themes<T>> | ((currentThemes: Themes<T>) => Partial<Themes<T>>)) => void;
|
|
@@ -29,7 +25,6 @@ declare function useResonare<T extends ThemeStoreConfig>(getStore: () => ThemeSt
|
|
|
29
25
|
media: [string, string, string];
|
|
30
26
|
} ? never : U["value"] : never : never]) => void;
|
|
31
27
|
toPersist: () => {
|
|
32
|
-
version: 1;
|
|
33
28
|
themes: Partial<Themes<T>>;
|
|
34
29
|
systemOptions: { [K_1 in { [K in keyof T]: T[K] extends {
|
|
35
30
|
options: ReadonlyArray<infer U>;
|
|
@@ -56,11 +51,8 @@ declare function useResonare<T extends ThemeStoreConfig>(getStore: () => ThemeSt
|
|
|
56
51
|
subscribe: (callback: (value: {
|
|
57
52
|
themes: Themes<T>;
|
|
58
53
|
resolvedThemes: Themes<T>;
|
|
59
|
-
}) => void
|
|
60
|
-
|
|
61
|
-
}?: {
|
|
62
|
-
immediate?: boolean;
|
|
63
|
-
}) => (() => void);
|
|
54
|
+
}) => void) => (() => void);
|
|
55
|
+
destroy: () => void;
|
|
64
56
|
};
|
|
65
57
|
//#endregion
|
|
66
58
|
export { useResonare };
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","names":[],"sources":["../src/react.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"react.d.ts","names":[],"sources":["../src/react.ts"],"mappings":";;;iBAGgB,WAAA,WAAsB,gBAAA,CAAA,CAAkB,KAAA,EAAO,UAAA,CAAW,CAAA"}
|
package/dist/react.js
CHANGED
|
@@ -1,71 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
//#region src/react.ts
|
|
4
|
-
function noop() {}
|
|
5
|
-
const emptyObject = {};
|
|
6
|
-
const emptyStore = {
|
|
7
|
-
getThemes: () => emptyObject,
|
|
8
|
-
getResolvedThemes: () => emptyObject,
|
|
9
|
-
setThemes: noop,
|
|
10
|
-
updateSystemOption: noop,
|
|
11
|
-
toPersist: noop,
|
|
12
|
-
restore: noop,
|
|
13
|
-
sync: noop,
|
|
14
|
-
subscribe: () => noop
|
|
15
|
-
};
|
|
16
|
-
function useResonare(getStore, t0) {
|
|
17
|
-
const $ = c(13);
|
|
18
|
-
let t1;
|
|
19
|
-
if ($[0] !== t0) {
|
|
20
|
-
t1 = t0 === void 0 ? {} : t0;
|
|
21
|
-
$[0] = t0;
|
|
22
|
-
$[1] = t1;
|
|
23
|
-
} else t1 = $[1];
|
|
24
|
-
const { initOnMount: t2 } = t1;
|
|
25
|
-
const initOnMount = t2 === void 0 ? false : t2;
|
|
26
|
-
const [isMounted, setIsMounted] = React.useState(initOnMount);
|
|
27
|
-
let t3;
|
|
28
|
-
let t4;
|
|
29
|
-
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
30
|
-
t3 = () => {
|
|
31
|
-
setIsMounted(true);
|
|
32
|
-
};
|
|
33
|
-
t4 = [];
|
|
34
|
-
$[2] = t3;
|
|
35
|
-
$[3] = t4;
|
|
36
|
-
} else {
|
|
37
|
-
t3 = $[2];
|
|
38
|
-
t4 = $[3];
|
|
39
|
-
}
|
|
40
|
-
React.useEffect(t3, t4);
|
|
41
|
-
const { getThemes, getResolvedThemes, setThemes, updateSystemOption, toPersist, restore, sync, subscribe } = isMounted ? getStore() : emptyStore;
|
|
42
|
-
const themes = React.useSyncExternalStore(subscribe, getThemes, getThemes);
|
|
43
|
-
const t5 = getResolvedThemes();
|
|
44
|
-
let t6;
|
|
45
|
-
if ($[4] !== restore || $[5] !== setThemes || $[6] !== subscribe || $[7] !== sync || $[8] !== t5 || $[9] !== themes || $[10] !== toPersist || $[11] !== updateSystemOption) {
|
|
46
|
-
t6 = {
|
|
47
|
-
themes,
|
|
48
|
-
resolvedThemes: t5,
|
|
49
|
-
setThemes,
|
|
50
|
-
updateSystemOption,
|
|
51
|
-
toPersist,
|
|
52
|
-
restore,
|
|
53
|
-
sync,
|
|
54
|
-
subscribe
|
|
55
|
-
};
|
|
56
|
-
$[4] = restore;
|
|
57
|
-
$[5] = setThemes;
|
|
58
|
-
$[6] = subscribe;
|
|
59
|
-
$[7] = sync;
|
|
60
|
-
$[8] = t5;
|
|
61
|
-
$[9] = themes;
|
|
62
|
-
$[10] = toPersist;
|
|
63
|
-
$[11] = updateSystemOption;
|
|
64
|
-
$[12] = t6;
|
|
65
|
-
} else t6 = $[12];
|
|
66
|
-
return t6;
|
|
67
|
-
}
|
|
68
|
-
//#endregion
|
|
69
|
-
export { useResonare };
|
|
70
|
-
|
|
1
|
+
import{c as e}from"react-compiler-runtime";import*as t from"react";function n(n){let r=e(12),{getThemes:i,getResolvedThemes:a,setThemes:o,updateSystemOption:s,toPersist:c,restore:l,sync:u,subscribe:d,destroy:f}=n,p=t.useSyncExternalStore(d,i,i),m;r[0]===a?m=r[1]:(m=a(),r[0]=a,r[1]=m);let h;return r[2]!==f||r[3]!==l||r[4]!==o||r[5]!==d||r[6]!==u||r[7]!==m||r[8]!==p||r[9]!==c||r[10]!==s?(h={themes:p,resolvedThemes:m,setThemes:o,updateSystemOption:s,toPersist:c,restore:l,sync:u,subscribe:d,destroy:f},r[2]=f,r[3]=l,r[4]=o,r[5]=d,r[6]=u,r[7]=m,r[8]=p,r[9]=c,r[10]=s,r[11]=h):h=r[11],h}export{n as useResonare};
|
|
71
2
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":["React","ThemeStore","ThemeStoreConfig","
|
|
1
|
+
{"version":3,"file":"react.js","names":["React","ThemeStore","ThemeStoreConfig","useResonare","store","$","_c","getThemes","getResolvedThemes","setThemes","updateSystemOption","toPersist","restore","sync","subscribe","destroy","themes","useSyncExternalStore","t0","t1","resolvedThemes"],"sources":["../src/react.ts"],"sourcesContent":["import * as React from 'react'\nimport type { ThemeStore, ThemeStoreConfig } from '.'\n\nexport function useResonare<T extends ThemeStoreConfig>(store: ThemeStore<T>) {\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\tsubscribe,\n\t\tdestroy,\n\t} = store\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\tsubscribe,\n\t\tdestroy,\n\t}\n}\n"],"mappings":"mEAGA,SAAOG,EAAAC,EAAA,CAAA,IAAAC,EAAAC,EAAA,GAAA,CACN,CAAAC,YAAAC,oBAAAC,YAAAC,qBAAAC,YAAAC,UAAAC,OAAAC,YAAAC,WAUIX,EAEJY,EAAehB,EAAKiB,qBAAsBH,EAAWP,EAAWA,EAAU,CAAAW,EAAAb,EAAA,KAAAG,EAItCU,EAAAb,EAAA,IAAnBa,EAAAV,GAAmB,CAAAH,EAAA,GAAAG,EAAAH,EAAA,GAAAa,GAAA,IAAAC,EAQnC,OARmCd,EAAA,KAAAU,GAAAV,EAAA,KAAAO,GAAAP,EAAA,KAAAI,GAAAJ,EAAA,KAAAS,GAAAT,EAAA,KAAAQ,GAAAR,EAAA,KAAAa,GAAAb,EAAA,KAAAW,GAAAX,EAAA,KAAAM,GAAAN,EAAA,MAAAK,GAF7BS,EAAA,CAAAH,SAAAI,eAEUF,EAAmBT,YAAAC,qBAAAC,YAAAC,UAAAC,OAAAC,YAAAC,UAQnC,CAAAV,EAAA,GAAAU,EAAAV,EAAA,GAAAO,EAAAP,EAAA,GAAAI,EAAAJ,EAAA,GAAAS,EAAAT,EAAA,GAAAQ,EAAAR,EAAA,GAAAa,EAAAb,EAAA,GAAAW,EAAAX,EAAA,GAAAM,EAAAN,EAAA,IAAAK,EAAAL,EAAA,IAAAc,GAAAA,EAAAd,EAAA,IAVMc"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resonare",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Resonare",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"theming",
|
|
@@ -21,23 +21,14 @@
|
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"import": "./dist/index.js"
|
|
23
23
|
},
|
|
24
|
-
"./global": {
|
|
25
|
-
"types": "./global.d.ts"
|
|
26
|
-
},
|
|
27
|
-
"./inline-script": {
|
|
28
|
-
"import": "./dist/inline-script.ts"
|
|
29
|
-
},
|
|
30
24
|
"./react": {
|
|
31
25
|
"types": "./dist/react.d.ts",
|
|
32
26
|
"import": "./dist/react.js"
|
|
33
27
|
}
|
|
34
28
|
},
|
|
35
|
-
"jsdelivr": "./dist/resonare.iife.min.js",
|
|
36
|
-
"unpkg": "./dist/resonare.iife.min.js",
|
|
37
29
|
"types": "./dist/index.d.ts",
|
|
38
30
|
"files": [
|
|
39
|
-
"dist"
|
|
40
|
-
"global.d.ts"
|
|
31
|
+
"dist"
|
|
41
32
|
],
|
|
42
33
|
"dependencies": {
|
|
43
34
|
"react-compiler-runtime": "1.0.0"
|
|
@@ -45,7 +36,7 @@
|
|
|
45
36
|
"devDependencies": {
|
|
46
37
|
"@rolldown/plugin-babel": "0.2.2",
|
|
47
38
|
"@size-limit/preset-small-lib": "12.0.1",
|
|
48
|
-
"@types/node": "25.5.
|
|
39
|
+
"@types/node": "25.5.2",
|
|
49
40
|
"@types/react": "19.2.14",
|
|
50
41
|
"@vitejs/plugin-react": "6.0.1",
|
|
51
42
|
"babel-plugin-react-compiler": "1.0.0",
|
|
@@ -54,10 +45,10 @@
|
|
|
54
45
|
"react": "19.2.4",
|
|
55
46
|
"react-dom": "19.2.4",
|
|
56
47
|
"size-limit": "12.0.1",
|
|
57
|
-
"tsdown": "0.21.
|
|
58
|
-
"typescript": "
|
|
59
|
-
"vite": "8.0.
|
|
60
|
-
"vitest": "4.1.
|
|
48
|
+
"tsdown": "0.21.7",
|
|
49
|
+
"typescript": "6.0.2",
|
|
50
|
+
"vite": "8.0.3",
|
|
51
|
+
"vitest": "4.1.2"
|
|
61
52
|
},
|
|
62
53
|
"peerDependencies": {
|
|
63
54
|
"react": "^18.0.0 || ^19.0.0"
|
package/dist/inline-script.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const resonareInlineScript = "/**\n* resonare v0.0.17\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??(typeof t.options[0]==`object`?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={...a.systemOptions};this.#n={key:e,config:Object.fromEntries(Object.entries(i).map(([e,t])=>{let n=(t.options||[]).map(t=>typeof t==`object`?(t.media&&!Object.hasOwn(s,e)&&(s[e]=[t.media[1],t.media[2]]),[String(t.value),t]):[String(t),{value:t}]);return[e,Object.fromEntries(n)]}))},this.#r=s,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,r=this.#e.get(n);if(!r){console.error(`Theme store '${n}' not found.`);return}return r};destroy=e=>{let n=e||t,r=this.#e.get(n);r&&(r.___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})({});"
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* resonare v0.0.17
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
var 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??(typeof t.options[0]==`object`?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={...a.systemOptions};this.#n={key:e,config:Object.fromEntries(Object.entries(i).map(([e,t])=>{let n=(t.options||[]).map(t=>typeof t==`object`?(t.media&&!Object.hasOwn(s,e)&&(s[e]=[t.media[1],t.media[2]]),[String(t.value),t]):[String(t),{value:t}]);return[e,Object.fromEntries(n)]}))},this.#r=s,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,r=this.#e.get(n);if(!r){console.error(`Theme store '${n}' not found.`);return}return r};destroy=e=>{let n=e||t,r=this.#e.get(n);r&&(r.___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/global.d.ts
DELETED