@just-web/toolkits 2.0.0 → 3.0.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/dist/attributes/get-attribute.cjs +1 -1
- package/dist/attributes/get-attribute.cjs.map +1 -1
- package/dist/attributes/get-attribute.d.cts +2 -2
- package/dist/attributes/get-attribute.d.cts.map +1 -1
- package/dist/attributes/get-attribute.d.mts +2 -2
- package/dist/attributes/get-attribute.d.mts.map +1 -1
- package/dist/attributes/get-attribute.mjs +1 -1
- package/dist/attributes/get-attribute.mjs.map +1 -1
- package/dist/attributes/get-data-attribute.cjs +1 -1
- package/dist/attributes/get-data-attribute.cjs.map +1 -1
- package/dist/attributes/get-data-attribute.d.cts +2 -2
- package/dist/attributes/get-data-attribute.d.cts.map +1 -1
- package/dist/attributes/get-data-attribute.d.mts +2 -2
- package/dist/attributes/get-data-attribute.d.mts.map +1 -1
- package/dist/attributes/get-data-attribute.mjs +1 -1
- package/dist/attributes/get-data-attribute.mjs.map +1 -1
- package/dist/attributes/observe-attribute.cjs +11 -8
- package/dist/attributes/observe-attribute.cjs.map +1 -1
- package/dist/attributes/observe-attribute.d.cts +7 -7
- package/dist/attributes/observe-attribute.d.cts.map +1 -1
- package/dist/attributes/observe-attribute.d.mts +7 -7
- package/dist/attributes/observe-attribute.d.mts.map +1 -1
- package/dist/attributes/observe-attribute.mjs +11 -8
- package/dist/attributes/observe-attribute.mjs.map +1 -1
- package/dist/attributes/observe-data-attribute.cjs +7 -10
- package/dist/attributes/observe-data-attribute.cjs.map +1 -1
- package/dist/attributes/observe-data-attribute.d.cts +8 -11
- package/dist/attributes/observe-data-attribute.d.cts.map +1 -1
- package/dist/attributes/observe-data-attribute.d.mts +8 -11
- package/dist/attributes/observe-data-attribute.d.mts.map +1 -1
- package/dist/attributes/observe-data-attribute.mjs +7 -10
- package/dist/attributes/observe-data-attribute.mjs.map +1 -1
- package/dist/color-scheme/color-scheme.types.d.cts +11 -0
- package/dist/color-scheme/color-scheme.types.d.cts.map +1 -0
- package/dist/color-scheme/color-scheme.types.d.mts +11 -0
- package/dist/color-scheme/color-scheme.types.d.mts.map +1 -0
- package/dist/color-scheme/get-prefers-color-scheme.cjs +3 -1
- package/dist/color-scheme/get-prefers-color-scheme.cjs.map +1 -1
- package/dist/color-scheme/get-prefers-color-scheme.d.cts +7 -2
- package/dist/color-scheme/get-prefers-color-scheme.d.cts.map +1 -1
- package/dist/color-scheme/get-prefers-color-scheme.d.mts +7 -2
- package/dist/color-scheme/get-prefers-color-scheme.d.mts.map +1 -1
- package/dist/color-scheme/get-prefers-color-scheme.mjs +3 -1
- package/dist/color-scheme/get-prefers-color-scheme.mjs.map +1 -1
- package/dist/color-scheme/observe-prefers-color-scheme.cjs.map +1 -1
- package/dist/color-scheme/observe-prefers-color-scheme.d.cts +4 -1
- package/dist/color-scheme/observe-prefers-color-scheme.d.cts.map +1 -1
- package/dist/color-scheme/observe-prefers-color-scheme.d.mts +4 -1
- package/dist/color-scheme/observe-prefers-color-scheme.d.mts.map +1 -1
- package/dist/color-scheme/observe-prefers-color-scheme.mjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.mts +2 -1
- package/dist/react/hooks/use-attribute.cjs +8 -9
- package/dist/react/hooks/use-attribute.cjs.map +1 -1
- package/dist/react/hooks/use-attribute.d.cts +4 -4
- package/dist/react/hooks/use-attribute.d.mts +4 -4
- package/dist/react/hooks/use-attribute.mjs +8 -9
- package/dist/react/hooks/use-attribute.mjs.map +1 -1
- package/dist/react/hooks/use-theme-by-class-name.cjs +1 -1
- package/dist/react/hooks/use-theme-by-class-name.cjs.map +1 -1
- package/dist/react/hooks/use-theme-by-class-name.d.cts +2 -2
- package/dist/react/hooks/use-theme-by-class-name.d.mts +2 -2
- package/dist/react/hooks/use-theme-by-class-name.mjs +1 -1
- package/dist/react/hooks/use-theme-by-class-name.mjs.map +1 -1
- package/dist/react/hooks/use-theme-by-data-attribute.cjs +1 -1
- package/dist/react/hooks/use-theme-by-data-attribute.cjs.map +1 -1
- package/dist/react/hooks/use-theme-by-data-attribute.d.cts +2 -2
- package/dist/react/hooks/use-theme-by-data-attribute.d.mts +2 -2
- package/dist/react/hooks/use-theme-by-data-attribute.mjs +1 -1
- package/dist/react/hooks/use-theme-by-data-attribute.mjs.map +1 -1
- package/dist/react/theme/create-theme-hook.cjs.map +1 -1
- package/dist/react/theme/create-theme-hook.mjs.map +1 -1
- package/dist/theme/_utils/parse-stored-theme.cjs +1 -1
- package/dist/theme/_utils/parse-stored-theme.cjs.map +1 -1
- package/dist/theme/_utils/parse-stored-theme.mjs +1 -1
- package/dist/theme/_utils/parse-stored-theme.mjs.map +1 -1
- package/dist/theme/_utils/set-theme-to-stores.cjs +1 -1
- package/dist/theme/_utils/set-theme-to-stores.cjs.map +1 -1
- package/dist/theme/_utils/set-theme-to-stores.mjs +1 -1
- package/dist/theme/_utils/set-theme-to-stores.mjs.map +1 -1
- package/dist/theme/class-name/parse-class-name.cjs +1 -1
- package/dist/theme/class-name/parse-class-name.cjs.map +1 -1
- package/dist/theme/class-name/parse-class-name.d.cts +2 -2
- package/dist/theme/class-name/parse-class-name.d.cts.map +1 -1
- package/dist/theme/class-name/parse-class-name.d.mts +2 -2
- package/dist/theme/class-name/parse-class-name.d.mts.map +1 -1
- package/dist/theme/class-name/parse-class-name.mjs +1 -1
- package/dist/theme/class-name/parse-class-name.mjs.map +1 -1
- package/dist/theme/class-name/read-class-name.cjs +1 -1
- package/dist/theme/class-name/read-class-name.cjs.map +1 -1
- package/dist/theme/class-name/read-class-name.d.cts +2 -2
- package/dist/theme/class-name/read-class-name.d.cts.map +1 -1
- package/dist/theme/class-name/read-class-name.d.mts +2 -2
- package/dist/theme/class-name/read-class-name.d.mts.map +1 -1
- package/dist/theme/class-name/read-class-name.mjs +1 -1
- package/dist/theme/class-name/read-class-name.mjs.map +1 -1
- package/dist/theme/class-name/stringify-class-name.cjs +4 -4
- package/dist/theme/class-name/stringify-class-name.cjs.map +1 -1
- package/dist/theme/class-name/stringify-class-name.d.cts +3 -3
- package/dist/theme/class-name/stringify-class-name.d.cts.map +1 -1
- package/dist/theme/class-name/stringify-class-name.d.mts +3 -3
- package/dist/theme/class-name/stringify-class-name.d.mts.map +1 -1
- package/dist/theme/class-name/stringify-class-name.mjs +4 -4
- package/dist/theme/class-name/stringify-class-name.mjs.map +1 -1
- package/dist/theme/class-name/subscribe-class-name.cjs +2 -3
- package/dist/theme/class-name/subscribe-class-name.cjs.map +1 -1
- package/dist/theme/class-name/subscribe-class-name.d.cts +2 -2
- package/dist/theme/class-name/subscribe-class-name.d.cts.map +1 -1
- package/dist/theme/class-name/subscribe-class-name.d.mts +2 -2
- package/dist/theme/class-name/subscribe-class-name.d.mts.map +1 -1
- package/dist/theme/class-name/subscribe-class-name.mjs +2 -3
- package/dist/theme/class-name/subscribe-class-name.mjs.map +1 -1
- package/dist/theme/class-name/write-class-name.cjs +2 -2
- package/dist/theme/class-name/write-class-name.cjs.map +1 -1
- package/dist/theme/class-name/write-class-name.d.cts +4 -4
- package/dist/theme/class-name/write-class-name.d.cts.map +1 -1
- package/dist/theme/class-name/write-class-name.d.mts +4 -4
- package/dist/theme/class-name/write-class-name.d.mts.map +1 -1
- package/dist/theme/class-name/write-class-name.mjs +2 -2
- package/dist/theme/class-name/write-class-name.mjs.map +1 -1
- package/dist/theme/compose-theme-stores.cjs.map +1 -1
- package/dist/theme/compose-theme-stores.mjs.map +1 -1
- package/dist/theme/cookie/write-cookie-theme.cjs +2 -2
- package/dist/theme/cookie/write-cookie-theme.cjs.map +1 -1
- package/dist/theme/cookie/write-cookie-theme.d.cts +2 -2
- package/dist/theme/cookie/write-cookie-theme.d.cts.map +1 -1
- package/dist/theme/cookie/write-cookie-theme.d.mts +2 -2
- package/dist/theme/cookie/write-cookie-theme.d.mts.map +1 -1
- package/dist/theme/cookie/write-cookie-theme.mjs +2 -2
- package/dist/theme/cookie/write-cookie-theme.mjs.map +1 -1
- package/dist/theme/data-attribute/parse-data-attribute.cjs +1 -1
- package/dist/theme/data-attribute/parse-data-attribute.cjs.map +1 -1
- package/dist/theme/data-attribute/parse-data-attribute.d.cts +2 -2
- package/dist/theme/data-attribute/parse-data-attribute.d.mts +2 -2
- package/dist/theme/data-attribute/parse-data-attribute.mjs +1 -1
- package/dist/theme/data-attribute/parse-data-attribute.mjs.map +1 -1
- package/dist/theme/data-attribute/read-data-attribute.cjs +1 -1
- package/dist/theme/data-attribute/read-data-attribute.cjs.map +1 -1
- package/dist/theme/data-attribute/read-data-attribute.d.cts +2 -2
- package/dist/theme/data-attribute/read-data-attribute.d.cts.map +1 -1
- package/dist/theme/data-attribute/read-data-attribute.d.mts +2 -2
- package/dist/theme/data-attribute/read-data-attribute.d.mts.map +1 -1
- package/dist/theme/data-attribute/read-data-attribute.mjs +1 -1
- package/dist/theme/data-attribute/read-data-attribute.mjs.map +1 -1
- package/dist/theme/data-attribute/stringify-data-attribute.cjs +4 -4
- package/dist/theme/data-attribute/stringify-data-attribute.cjs.map +1 -1
- package/dist/theme/data-attribute/stringify-data-attribute.d.cts +3 -3
- package/dist/theme/data-attribute/stringify-data-attribute.d.cts.map +1 -1
- package/dist/theme/data-attribute/stringify-data-attribute.d.mts +3 -3
- package/dist/theme/data-attribute/stringify-data-attribute.d.mts.map +1 -1
- package/dist/theme/data-attribute/stringify-data-attribute.mjs +4 -4
- package/dist/theme/data-attribute/stringify-data-attribute.mjs.map +1 -1
- package/dist/theme/data-attribute/subscribe-data-attribute.cjs +2 -3
- package/dist/theme/data-attribute/subscribe-data-attribute.cjs.map +1 -1
- package/dist/theme/data-attribute/subscribe-data-attribute.d.cts +2 -2
- package/dist/theme/data-attribute/subscribe-data-attribute.d.cts.map +1 -1
- package/dist/theme/data-attribute/subscribe-data-attribute.d.mts +2 -2
- package/dist/theme/data-attribute/subscribe-data-attribute.d.mts.map +1 -1
- package/dist/theme/data-attribute/subscribe-data-attribute.mjs +2 -3
- package/dist/theme/data-attribute/subscribe-data-attribute.mjs.map +1 -1
- package/dist/theme/data-attribute/write-data-attribute.cjs +3 -3
- package/dist/theme/data-attribute/write-data-attribute.cjs.map +1 -1
- package/dist/theme/data-attribute/write-data-attribute.d.cts +4 -4
- package/dist/theme/data-attribute/write-data-attribute.d.cts.map +1 -1
- package/dist/theme/data-attribute/write-data-attribute.d.mts +4 -4
- package/dist/theme/data-attribute/write-data-attribute.d.mts.map +1 -1
- package/dist/theme/data-attribute/write-data-attribute.mjs +3 -3
- package/dist/theme/data-attribute/write-data-attribute.mjs.map +1 -1
- package/dist/theme/local-storage/write-local-storage.cjs +1 -1
- package/dist/theme/local-storage/write-local-storage.cjs.map +1 -1
- package/dist/theme/local-storage/write-local-storage.d.cts +2 -2
- package/dist/theme/local-storage/write-local-storage.d.mts +2 -2
- package/dist/theme/local-storage/write-local-storage.mjs +1 -1
- package/dist/theme/local-storage/write-local-storage.mjs.map +1 -1
- package/dist/theme/session-storage/write-session-storage.cjs +1 -1
- package/dist/theme/session-storage/write-session-storage.cjs.map +1 -1
- package/dist/theme/session-storage/write-session-storage.d.cts +2 -2
- package/dist/theme/session-storage/write-session-storage.d.mts +2 -2
- package/dist/theme/session-storage/write-session-storage.mjs +1 -1
- package/dist/theme/session-storage/write-session-storage.mjs.map +1 -1
- package/dist/theme/theme-entry.types.d.cts +4 -2
- package/dist/theme/theme-entry.types.d.cts.map +1 -1
- package/dist/theme/theme-entry.types.d.mts +4 -2
- package/dist/theme/theme-entry.types.d.mts.map +1 -1
- package/dist/theme/theme-store/async-theme-store.types.d.cts +1 -1
- package/dist/theme/theme-store/async-theme-store.types.d.cts.map +1 -1
- package/dist/theme/theme-store/async-theme-store.types.d.mts +1 -1
- package/dist/theme/theme-store/async-theme-store.types.d.mts.map +1 -1
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs +1 -1
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.cjs.map +1 -1
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.cts +2 -2
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.d.mts +2 -2
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs +1 -1
- package/dist/theme/theme-store/class-name-theme-store/class-name-theme-store.mjs.map +1 -1
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs +1 -1
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.cjs.map +1 -1
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.cts +3 -3
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.d.mts +3 -3
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs +1 -1
- package/dist/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.mjs.map +1 -1
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs +1 -1
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.cjs.map +1 -1
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.cts +1 -1
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.d.mts +1 -1
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs +1 -1
- package/dist/theme/theme-store/in-memory-theme-store/in-memory-theme-store.mjs.map +1 -1
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.cts +1 -1
- package/dist/theme/theme-store/local-storage-theme-store/local-storage-theme-store.d.mts +1 -1
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.cts +1 -1
- package/dist/theme/theme-store/session-storage-theme-store/session-storage-theme-store.d.mts +1 -1
- package/dist/theme/theme-store/theme-store.types.d.cts +1 -1
- package/dist/theme/theme-store/theme-store.types.d.cts.map +1 -1
- package/dist/theme/theme-store/theme-store.types.d.mts +1 -1
- package/dist/theme/theme-store/theme-store.types.d.mts.map +1 -1
- package/dist/theme/web-storage/write-web-storage.cjs +3 -3
- package/dist/theme/web-storage/write-web-storage.cjs.map +1 -1
- package/dist/theme/web-storage/write-web-storage.d.cts +2 -2
- package/dist/theme/web-storage/write-web-storage.d.mts +2 -2
- package/dist/theme/web-storage/write-web-storage.mjs +3 -3
- package/dist/theme/web-storage/write-web-storage.mjs.map +1 -1
- package/dist/utils/append-id.cjs +2 -2
- package/dist/utils/append-id.cjs.map +1 -1
- package/dist/utils/append-id.d.cts +3 -3
- package/dist/utils/append-id.d.mts +3 -3
- package/dist/utils/append-id.mjs +2 -2
- package/dist/utils/append-id.mjs.map +1 -1
- package/package.json +1 -1
- package/src/attributes/get-attribute.ts +5 -2
- package/src/attributes/get-data-attribute.ts +5 -2
- package/src/attributes/observe-attribute.ts +15 -10
- package/src/attributes/observe-data-attribute.ts +8 -11
- package/src/color-scheme/color-scheme.types.ts +7 -0
- package/src/color-scheme/get-prefers-color-scheme.ts +6 -4
- package/src/color-scheme/observe-prefers-color-scheme.ts +3 -1
- package/src/index.ts +1 -0
- package/src/react/hooks/use-attribute.ts +12 -13
- package/src/react/hooks/use-theme-by-class-name.ts +2 -2
- package/src/react/hooks/use-theme-by-data-attribute.ts +2 -2
- package/src/react/theme/create-theme-hook.ts +4 -6
- package/src/theme/_utils/parse-stored-theme.ts +2 -2
- package/src/theme/_utils/set-theme-to-stores.ts +3 -3
- package/src/theme/class-name/parse-class-name.ts +2 -2
- package/src/theme/class-name/read-class-name.ts +2 -2
- package/src/theme/class-name/stringify-class-name.ts +6 -6
- package/src/theme/class-name/subscribe-class-name.ts +3 -4
- package/src/theme/class-name/write-class-name.ts +4 -4
- package/src/theme/compose-theme-stores.ts +1 -1
- package/src/theme/cookie/write-cookie-theme.ts +3 -3
- package/src/theme/data-attribute/parse-data-attribute.ts +2 -2
- package/src/theme/data-attribute/read-data-attribute.ts +2 -2
- package/src/theme/data-attribute/stringify-data-attribute.ts +6 -6
- package/src/theme/data-attribute/subscribe-data-attribute.ts +3 -4
- package/src/theme/data-attribute/write-data-attribute.ts +5 -5
- package/src/theme/local-storage/write-local-storage.ts +2 -2
- package/src/theme/session-storage/write-session-storage.ts +2 -2
- package/src/theme/theme-entry.types.ts +5 -3
- package/src/theme/theme-store/async-theme-store.types.ts +1 -3
- package/src/theme/theme-store/class-name-theme-store/class-name-theme-store.ts +2 -2
- package/src/theme/theme-store/data-attribute-theme-store/data-attribute-theme-store.ts +2 -2
- package/src/theme/theme-store/in-memory-theme-store/in-memory-theme-store.ts +1 -1
- package/src/theme/theme-store/theme-store.types.ts +1 -3
- package/src/theme/web-storage/write-web-storage.ts +5 -5
- package/src/utils/append-id.ts +3 -3
|
@@ -6,47 +6,46 @@ import { observeAttributes } from '../../attributes/observe-attribute.ts'
|
|
|
6
6
|
* and a setter to update it. Stays in sync when the attribute changes (e.g. from elsewhere).
|
|
7
7
|
*
|
|
8
8
|
* @param attributeName - The attribute to observe (e.g. `'class'`, `'data-theme'`).
|
|
9
|
-
* @param element - The element to observe. Defaults to `document.documentElement` when omitted.
|
|
10
|
-
* @returns Tuple of [value, setValue]. Pass null to setValue to remove the attribute.
|
|
9
|
+
* @param element - The element to observe (accepts null e.g. from refs). Defaults to `document.documentElement` when omitted.
|
|
10
|
+
* @returns Tuple of [value, setValue]. Pass null or undefined to setValue to remove the attribute.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```tsx
|
|
14
14
|
* const [className, setClassName] = useAttribute('class')
|
|
15
15
|
* const [theme, setTheme] = useAttribute('data-theme', myElement)
|
|
16
16
|
* setTheme('dark')
|
|
17
|
-
* setClassName(
|
|
17
|
+
* setClassName(undefined) // removes class attribute
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
export function useAttribute(
|
|
21
21
|
attributeName: string,
|
|
22
|
-
element: Element | undefined = typeof document !== 'undefined'
|
|
22
|
+
element: Element | null | undefined = typeof document !== 'undefined'
|
|
23
23
|
? document.documentElement
|
|
24
24
|
: undefined
|
|
25
|
-
): [string |
|
|
26
|
-
const [value, setValueState] = useState<string |
|
|
27
|
-
() => element?.getAttribute(attributeName) ??
|
|
25
|
+
): [string | undefined, (value: string | null | undefined) => void] {
|
|
26
|
+
const [value, setValueState] = useState<string | undefined>(
|
|
27
|
+
() => element?.getAttribute(attributeName) ?? undefined
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
useEffect(() => {
|
|
31
31
|
if (!element) return
|
|
32
32
|
|
|
33
|
-
setValueState(element.getAttribute(attributeName))
|
|
33
|
+
setValueState(element.getAttribute(attributeName) ?? undefined)
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
return observeAttributes(
|
|
36
36
|
{
|
|
37
37
|
[attributeName]: (next) => {
|
|
38
|
-
setValueState(next)
|
|
38
|
+
setValueState(next ?? undefined)
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
element
|
|
42
42
|
)
|
|
43
|
-
return () => observer.disconnect()
|
|
44
43
|
}, [element, attributeName])
|
|
45
44
|
|
|
46
45
|
const setValue = useCallback(
|
|
47
|
-
(next: string | null) => {
|
|
46
|
+
(next: string | null | undefined) => {
|
|
48
47
|
if (!element) return
|
|
49
|
-
if (next
|
|
48
|
+
if (next == null) {
|
|
50
49
|
element.removeAttribute(attributeName)
|
|
51
50
|
} else {
|
|
52
51
|
element.setAttribute(attributeName, next)
|
|
@@ -11,7 +11,7 @@ import { classNameThemeStore } from '../../theme/theme-store/class-name-theme-st
|
|
|
11
11
|
*
|
|
12
12
|
* @param themes - Record mapping theme keys to their class name values
|
|
13
13
|
* @param options.theme - Fallback theme key when no matching class is found
|
|
14
|
-
* @param options.element - Element to read/set theme on (
|
|
14
|
+
* @param options.element - Element to read/set theme on (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
15
15
|
* @returns Tuple of [currentTheme, setTheme]
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
@@ -32,7 +32,7 @@ export function useThemeByClassName<Themes extends ThemeMap>(
|
|
|
32
32
|
themes: Themes,
|
|
33
33
|
options?: {
|
|
34
34
|
defaultTheme?: keyof Themes | undefined
|
|
35
|
-
element?: Element | undefined
|
|
35
|
+
element?: Element | null | undefined
|
|
36
36
|
}
|
|
37
37
|
): [keyof Themes | undefined, (theme: keyof Themes) => void] {
|
|
38
38
|
const element =
|
|
@@ -12,7 +12,7 @@ import { dataAttributeThemeStore } from '../../theme/theme-store/data-attribute-
|
|
|
12
12
|
* @param themes - Record mapping theme keys to their data attribute values
|
|
13
13
|
* @param options.attributeName - Data attribute name (e.g. `data-theme`)
|
|
14
14
|
* @param options.defaultTheme - Fallback theme key when no matching attribute value is found
|
|
15
|
-
* @param options.element - Element to read/set theme on (
|
|
15
|
+
* @param options.element - Element to read/set theme on (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
16
16
|
* @returns Tuple of [currentTheme, setTheme]
|
|
17
17
|
*
|
|
18
18
|
* @example
|
|
@@ -37,7 +37,7 @@ export function useThemeByDataAttribute<Themes extends ThemeMap>(
|
|
|
37
37
|
options: {
|
|
38
38
|
attributeName: `data-${string}`
|
|
39
39
|
defaultTheme?: keyof Themes | undefined
|
|
40
|
-
element?: Element | undefined
|
|
40
|
+
element?: Element | null | undefined
|
|
41
41
|
}
|
|
42
42
|
): [keyof Themes | undefined, (theme: keyof Themes) => void] {
|
|
43
43
|
const element =
|
|
@@ -101,16 +101,14 @@ function createSharedChannel<Themes extends ThemeMap>(
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const handleStoreUpdate = (entry: ThemeEntry<Themes> | undefined
|
|
104
|
+
const handleStoreUpdate = (entry: ThemeEntry<Themes> | undefined) => {
|
|
105
105
|
notify(entry?.theme ?? defaultTheme)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// Initial read to populate lastTheme (compose store subscribe has no initial notify)
|
|
109
|
-
void Promise.resolve(composedStore.read()).then(
|
|
110
|
-
(entry
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
)
|
|
109
|
+
void Promise.resolve(composedStore.read()).then((entry: ThemeEntry<Themes> | undefined) => {
|
|
110
|
+
notify(entry?.theme ?? defaultTheme)
|
|
111
|
+
})
|
|
114
112
|
|
|
115
113
|
let unobserve: () => void = composedStore.subscribe(handleStoreUpdate)
|
|
116
114
|
let isSubscribedToStore = true
|
|
@@ -38,12 +38,12 @@ function getCanonicalShapeAndComparable(v: ThemeMapValue): {
|
|
|
38
38
|
* returns { theme, value: stored.value }. Else returns undefined.
|
|
39
39
|
*
|
|
40
40
|
* @param themes - Record of valid theme keys and values (required for validation)
|
|
41
|
-
* @param value - Raw string from localStorage/sessionStorage/cookie
|
|
41
|
+
* @param value - Raw string from localStorage/sessionStorage/cookie (accepts null)
|
|
42
42
|
* @returns ThemeEntry when valid, otherwise undefined
|
|
43
43
|
*/
|
|
44
44
|
export function parseStoredTheme<Themes extends ThemeMap>(
|
|
45
45
|
themes: Themes | undefined,
|
|
46
|
-
value: string | undefined
|
|
46
|
+
value: string | null | undefined
|
|
47
47
|
): ThemeEntry<Themes> | undefined {
|
|
48
48
|
const parsed = tryParseJSON<{ theme: string; value?: unknown }>(value ?? null)
|
|
49
49
|
if (!parsed?.theme || typeof parsed.theme !== 'string') return undefined
|
|
@@ -4,18 +4,18 @@ import type { AsyncThemeStore } from '../theme-store/async-theme-store.types.ts'
|
|
|
4
4
|
import type { ThemeStore } from '../theme-store/theme-store.types.ts'
|
|
5
5
|
|
|
6
6
|
type StoreWithWrite<Themes extends ThemeMap> = (ThemeStore<Themes> | AsyncThemeStore<Themes>) & {
|
|
7
|
-
write: (entry: ThemeEntry<Themes> | undefined) => void | Promise<void>
|
|
7
|
+
write: (entry: ThemeEntry<Themes> | null | undefined) => void | Promise<void>
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Writes theme entry to all stores that have a write method.
|
|
12
12
|
*
|
|
13
13
|
* @param stores - Array of theme stores
|
|
14
|
-
* @param entry - Theme entry to write, or undefined to clear
|
|
14
|
+
* @param entry - Theme entry to write, or null/undefined to clear
|
|
15
15
|
*/
|
|
16
16
|
export async function setThemeToStores<Themes extends ThemeMap>(
|
|
17
17
|
stores: (ThemeStore<Themes> | AsyncThemeStore<Themes>)[],
|
|
18
|
-
entry: ThemeEntry<Themes> | undefined
|
|
18
|
+
entry: ThemeEntry<Themes> | null | undefined
|
|
19
19
|
): Promise<void> {
|
|
20
20
|
const withWrite = stores.filter((s): s is StoreWithWrite<Themes> => typeof s.write === 'function')
|
|
21
21
|
|
|
@@ -12,12 +12,12 @@ import type { ThemeMap } from '../theme-map.types.ts'
|
|
|
12
12
|
* Arrays in theme map use first value for matching.
|
|
13
13
|
*
|
|
14
14
|
* @param themes - Record mapping theme keys to class name(s)
|
|
15
|
-
* @param className - Raw class attribute value (e.g. from element.className)
|
|
15
|
+
* @param className - Raw class attribute value (e.g. from element.className; accepts null)
|
|
16
16
|
* @returns ThemeEntry if a match is found, otherwise undefined
|
|
17
17
|
*/
|
|
18
18
|
export function parseClassName<Themes extends ThemeMap>(
|
|
19
19
|
themes: Themes,
|
|
20
|
-
className: string | undefined
|
|
20
|
+
className: string | null | undefined
|
|
21
21
|
): ThemeEntry<Themes> | undefined {
|
|
22
22
|
const cls = className ?? ''
|
|
23
23
|
const theme = findKey(themes, (key) => {
|
|
@@ -6,14 +6,14 @@ import { parseClassName } from './parse-class-name.ts'
|
|
|
6
6
|
* Reads a theme entry from the class attribute on an element.
|
|
7
7
|
*
|
|
8
8
|
* @param themes - Record mapping theme keys to class name(s)
|
|
9
|
-
* @param options.element - Element to read from (
|
|
9
|
+
* @param options.element - Element to read from (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
10
10
|
* @param options.parse - Custom parser (default: parseClassName)
|
|
11
11
|
* @returns ThemeEntry if found, undefined otherwise. Returns undefined when element is not available (e.g. SSR).
|
|
12
12
|
*/
|
|
13
13
|
export function readClassName<Themes extends ThemeMap>(
|
|
14
14
|
themes: Themes,
|
|
15
15
|
options?:
|
|
16
|
-
| { element?: Element | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
16
|
+
| { element?: Element | null | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
17
17
|
| undefined
|
|
18
18
|
): ThemeEntry<Themes> | undefined {
|
|
19
19
|
const element = options?.element ?? document?.documentElement
|
|
@@ -10,23 +10,23 @@ import type { ThemeMap } from '../theme-map.types.ts'
|
|
|
10
10
|
* (unlike stringifyDataAttribute which uses first only).
|
|
11
11
|
*
|
|
12
12
|
* @param themes - Record mapping theme keys to class names (used to identify theme tokens)
|
|
13
|
-
* @param existing - Current class attribute value string
|
|
14
|
-
* @param entry - Theme entry to stringify, or undefined to clear theme (keeps non-theme classes)
|
|
13
|
+
* @param existing - Current class attribute value string (accepts null)
|
|
14
|
+
* @param entry - Theme entry to stringify, or null/undefined to clear theme (keeps non-theme classes)
|
|
15
15
|
* @returns Class attribute value string
|
|
16
16
|
*/
|
|
17
17
|
export function stringifyClassName<Themes extends ThemeMap>(
|
|
18
18
|
themes: Themes,
|
|
19
|
-
existing: string | undefined,
|
|
20
|
-
entry: ThemeEntry<Themes> | undefined
|
|
19
|
+
existing: string | null | undefined,
|
|
20
|
+
entry: ThemeEntry<Themes> | null | undefined
|
|
21
21
|
): string {
|
|
22
22
|
const allThemeClasses = Object.values(themes).flatMap((v) => {
|
|
23
23
|
const resolved = resolveThemeMapValue(v)
|
|
24
24
|
return Array.isArray(resolved) ? [...resolved] : [resolved]
|
|
25
25
|
})
|
|
26
|
-
const existingClasses = existing?.trim() ? existing.trim().split(/\s+/) : []
|
|
26
|
+
const existingClasses = (existing ?? '')?.trim() ? (existing ?? '').trim().split(/\s+/) : []
|
|
27
27
|
const withoutThemes = existingClasses.filter((c) => !allThemeClasses.includes(c))
|
|
28
28
|
const activeClasses =
|
|
29
|
-
entry
|
|
29
|
+
entry != null
|
|
30
30
|
? (() => {
|
|
31
31
|
const resolved = resolveThemeMapValue(entry.value)
|
|
32
32
|
return Array.isArray(resolved) ? [...resolved] : [resolved]
|
|
@@ -8,7 +8,7 @@ import { parseClassName } from './parse-class-name.ts'
|
|
|
8
8
|
*
|
|
9
9
|
* @param themes - Record mapping theme keys to class name(s)
|
|
10
10
|
* @param handler - Callback invoked when the class attribute changes
|
|
11
|
-
* @param options.element - Element to observe (
|
|
11
|
+
* @param options.element - Element to observe (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
12
12
|
* @param options.parse - Custom parser (default: parseClassName)
|
|
13
13
|
* @returns Unsubscribe function. Returns a no-op function when element is not available (e.g. SSR).
|
|
14
14
|
*/
|
|
@@ -16,14 +16,14 @@ export function subscribeClassName<Themes extends ThemeMap>(
|
|
|
16
16
|
themes: Themes,
|
|
17
17
|
handler: (entry: ThemeEntry<Themes> | undefined) => void,
|
|
18
18
|
options?:
|
|
19
|
-
| { element?: Element | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
19
|
+
| { element?: Element | null | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
20
20
|
| undefined
|
|
21
21
|
): () => void {
|
|
22
22
|
const element = options?.element ?? document?.documentElement
|
|
23
23
|
if (!element) return () => {}
|
|
24
24
|
const parse = options?.parse ?? parseClassName
|
|
25
25
|
let lastEmitted: keyof Themes | undefined | null = null
|
|
26
|
-
|
|
26
|
+
return observeAttributes(
|
|
27
27
|
{
|
|
28
28
|
class: (value) => {
|
|
29
29
|
const entry = parse(themes, value ?? undefined)
|
|
@@ -35,5 +35,4 @@ export function subscribeClassName<Themes extends ThemeMap>(
|
|
|
35
35
|
},
|
|
36
36
|
element
|
|
37
37
|
)
|
|
38
|
-
return () => observer.disconnect()
|
|
39
38
|
}
|
|
@@ -6,15 +6,15 @@ import { stringifyClassName } from './stringify-class-name.ts'
|
|
|
6
6
|
* Writes a theme entry to the class attribute on an element.
|
|
7
7
|
*
|
|
8
8
|
* @param themes - Record mapping theme keys to class name(s)
|
|
9
|
-
* @param entry - Theme entry to write, or undefined to remove the theme
|
|
10
|
-
* @param options.element - Element to write to (
|
|
9
|
+
* @param entry - Theme entry to write, or null/undefined to remove the theme
|
|
10
|
+
* @param options.element - Element to write to (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
11
11
|
* @param options.stringify - Custom serializer (default: stringifyClassName)
|
|
12
12
|
*/
|
|
13
13
|
export function writeClassName<Themes extends ThemeMap>(
|
|
14
14
|
themes: Themes,
|
|
15
|
-
entry: ThemeEntry<Themes> | undefined,
|
|
15
|
+
entry: ThemeEntry<Themes> | null | undefined,
|
|
16
16
|
options?:
|
|
17
|
-
| { element?: Element | undefined; stringify?: StringifyStoredTheme<Themes> | undefined }
|
|
17
|
+
| { element?: Element | null | undefined; stringify?: StringifyStoredTheme<Themes> | undefined }
|
|
18
18
|
| undefined
|
|
19
19
|
): void {
|
|
20
20
|
const element = options?.element ?? document?.documentElement
|
|
@@ -74,7 +74,7 @@ export function composeThemeStores<
|
|
|
74
74
|
(s): s is StoreWithSubscribe<Themes> => typeof s.subscribe === 'function'
|
|
75
75
|
)
|
|
76
76
|
|
|
77
|
-
function subscribe(handler: (theme: ThemeEntry<Themes> | undefined
|
|
77
|
+
function subscribe(handler: (theme: ThemeEntry<Themes> | undefined) => void): () => void {
|
|
78
78
|
let scheduled = false
|
|
79
79
|
let lastEmitted: keyof Themes | undefined
|
|
80
80
|
|
|
@@ -16,12 +16,12 @@ export interface WriteCookieThemeOptions<_Themes extends ThemeMap = ThemeMap> {
|
|
|
16
16
|
* Performs cookie set/delete only. Does not notify subscribers; the store must call notify() after this.
|
|
17
17
|
*
|
|
18
18
|
* @param themes - Record mapping theme keys to values (used for type validation)
|
|
19
|
-
* @param entry - Theme entry to write, or undefined to remove
|
|
19
|
+
* @param entry - Theme entry to write, or null/undefined to remove
|
|
20
20
|
* @param options - Cookie options
|
|
21
21
|
*/
|
|
22
22
|
export function writeCookieTheme<Themes extends ThemeMap>(
|
|
23
23
|
_themes: Themes,
|
|
24
|
-
entry: ThemeEntry<Themes> | undefined,
|
|
24
|
+
entry: ThemeEntry<Themes> | null | undefined,
|
|
25
25
|
options: WriteCookieThemeOptions<Themes>
|
|
26
26
|
): void {
|
|
27
27
|
const { cookieName, path = '/', maxAge, sameSite, secure } = options
|
|
@@ -30,7 +30,7 @@ export function writeCookieTheme<Themes extends ThemeMap>(
|
|
|
30
30
|
return
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
if (entry
|
|
33
|
+
if (entry == null) {
|
|
34
34
|
deleteCookie(cookieName, path)
|
|
35
35
|
return
|
|
36
36
|
}
|
|
@@ -10,13 +10,13 @@ import { SEPARATOR_SPACE } from './_constant.ts'
|
|
|
10
10
|
* Pure function: no DOM access. Uses first token when separator is defined.
|
|
11
11
|
*
|
|
12
12
|
* @param themes - Record mapping theme keys to attribute values
|
|
13
|
-
* @param value - Raw attribute value string (e.g. from getAttribute)
|
|
13
|
+
* @param value - Raw attribute value string (e.g. from getAttribute; accepts null)
|
|
14
14
|
* @param options.separator - When defined, split by separator and use first token (default: space)
|
|
15
15
|
* @returns ThemeEntry if a match is found, otherwise undefined
|
|
16
16
|
*/
|
|
17
17
|
export function parseDataAttribute<Themes extends ThemeMap>(
|
|
18
18
|
themes: Themes,
|
|
19
|
-
value: string | undefined,
|
|
19
|
+
value: string | null | undefined,
|
|
20
20
|
options?: { separator?: string | undefined } | undefined
|
|
21
21
|
): ThemeEntry<Themes> | undefined {
|
|
22
22
|
const separator = options?.separator ?? SEPARATOR_SPACE
|
|
@@ -9,7 +9,7 @@ import { parseDataAttribute } from './parse-data-attribute.ts'
|
|
|
9
9
|
*
|
|
10
10
|
* @param themes - Record mapping theme keys to attribute values
|
|
11
11
|
* @param attributeName - Data attribute name (e.g. `data-theme`)
|
|
12
|
-
* @param options.element - Element to read from (
|
|
12
|
+
* @param options.element - Element to read from (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
13
13
|
* @param options.parse - Custom parser (default: parseDataAttribute with space separator)
|
|
14
14
|
* @returns ThemeEntry if found, undefined otherwise. Returns undefined when element is not available (e.g. SSR).
|
|
15
15
|
*/
|
|
@@ -17,7 +17,7 @@ export function readDataAttribute<Themes extends ThemeMap>(
|
|
|
17
17
|
themes: Themes,
|
|
18
18
|
attributeName: `data-${string}`,
|
|
19
19
|
options?:
|
|
20
|
-
| { element?: Element | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
20
|
+
| { element?: Element | null | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
21
21
|
| undefined
|
|
22
22
|
): ThemeEntry<Themes> | undefined {
|
|
23
23
|
const element = options?.element ?? document?.documentElement
|
|
@@ -10,15 +10,15 @@ import { SEPARATOR_SPACE } from './_constant.ts'
|
|
|
10
10
|
* Aligns with stringifyClassName logic.
|
|
11
11
|
*
|
|
12
12
|
* @param themes - Record mapping theme keys to attribute values (used to identify theme tokens)
|
|
13
|
-
* @param existing - Current attribute value string
|
|
14
|
-
* @param entry - Theme entry to stringify, or undefined to clear theme (keeps non-theme tokens)
|
|
13
|
+
* @param existing - Current attribute value string (accepts null e.g. from getAttribute)
|
|
14
|
+
* @param entry - Theme entry to stringify, or null/undefined to clear theme (keeps non-theme tokens)
|
|
15
15
|
* @param options.separator - Token separator (default: space)
|
|
16
16
|
* @returns Attribute value string
|
|
17
17
|
*/
|
|
18
18
|
export function stringifyDataAttribute<Themes extends ThemeMap>(
|
|
19
19
|
themes: Themes,
|
|
20
|
-
existing: string | undefined,
|
|
21
|
-
entry: ThemeEntry<Themes> | undefined,
|
|
20
|
+
existing: string | null | undefined,
|
|
21
|
+
entry: ThemeEntry<Themes> | null | undefined,
|
|
22
22
|
options?: { separator?: string | undefined } | undefined
|
|
23
23
|
): string {
|
|
24
24
|
const separator = options?.separator ?? SEPARATOR_SPACE
|
|
@@ -26,10 +26,10 @@ export function stringifyDataAttribute<Themes extends ThemeMap>(
|
|
|
26
26
|
const resolved = resolveThemeMapValue(v)
|
|
27
27
|
return Array.isArray(resolved) ? [...resolved] : [resolved]
|
|
28
28
|
})
|
|
29
|
-
const existingTokens = existing?.trim() ? existing.trim().split(separator) : []
|
|
29
|
+
const existingTokens = (existing ?? '')?.trim() ? (existing ?? '').trim().split(separator) : []
|
|
30
30
|
const withoutThemeValues = existingTokens.filter((t) => !allThemeValues.includes(t.trim()))
|
|
31
31
|
const newTokens =
|
|
32
|
-
entry
|
|
32
|
+
entry != null
|
|
33
33
|
? (() => {
|
|
34
34
|
const resolved = resolveThemeMapValue(entry.value)
|
|
35
35
|
return Array.isArray(resolved) ? [resolved[0]] : [resolved]
|
|
@@ -10,7 +10,7 @@ import { parseDataAttribute } from './parse-data-attribute.ts'
|
|
|
10
10
|
* @param themes - Record mapping theme keys to attribute values
|
|
11
11
|
* @param attributeName - Data attribute name (e.g. `data-theme`)
|
|
12
12
|
* @param handler - Callback invoked when the attribute changes
|
|
13
|
-
* @param options.element - Element to observe (
|
|
13
|
+
* @param options.element - Element to observe (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
14
14
|
* @param options.parse - Custom parser (default: parseDataAttribute with space separator)
|
|
15
15
|
* @returns Unsubscribe function. Returns a no-op function when element is not available (e.g. SSR).
|
|
16
16
|
*/
|
|
@@ -19,14 +19,14 @@ export function subscribeDataAttribute<Themes extends ThemeMap>(
|
|
|
19
19
|
attributeName: `data-${string}`,
|
|
20
20
|
handler: (entry: ThemeEntry<Themes> | undefined) => void,
|
|
21
21
|
options?:
|
|
22
|
-
| { element?: Element | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
22
|
+
| { element?: Element | null | undefined; parse?: ParseStoredTheme<Themes> | undefined }
|
|
23
23
|
| undefined
|
|
24
24
|
): () => void {
|
|
25
25
|
const element = options?.element ?? document?.documentElement
|
|
26
26
|
if (!element) return () => {}
|
|
27
27
|
const parse =
|
|
28
28
|
options?.parse ?? ((t, v) => parseDataAttribute(t, v, { separator: SEPARATOR_SPACE }))
|
|
29
|
-
|
|
29
|
+
return observeDataAttributes<string, `data-${string}`>(
|
|
30
30
|
{
|
|
31
31
|
[attributeName]: (value) => {
|
|
32
32
|
const entry = parse(themes, value ?? undefined)
|
|
@@ -35,5 +35,4 @@ export function subscribeDataAttribute<Themes extends ThemeMap>(
|
|
|
35
35
|
},
|
|
36
36
|
element
|
|
37
37
|
)
|
|
38
|
-
return () => observer.disconnect()
|
|
39
38
|
}
|
|
@@ -9,16 +9,16 @@ import { stringifyDataAttribute } from './stringify-data-attribute.ts'
|
|
|
9
9
|
*
|
|
10
10
|
* @param themes - Record mapping theme keys to attribute values
|
|
11
11
|
* @param attributeName - Data attribute name (e.g. `data-theme`)
|
|
12
|
-
* @param entry - Theme entry to write, or undefined to remove the theme
|
|
13
|
-
* @param options.element - Element to write to (
|
|
12
|
+
* @param entry - Theme entry to write, or null/undefined to remove the theme
|
|
13
|
+
* @param options.element - Element to write to (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
14
14
|
* @param options.stringify - Custom serializer (default: stringifyDataAttribute with space separator)
|
|
15
15
|
*/
|
|
16
16
|
export function writeDataAttribute<Themes extends ThemeMap>(
|
|
17
17
|
themes: Themes,
|
|
18
18
|
attributeName: `data-${string}`,
|
|
19
|
-
entry: ThemeEntry<Themes> | undefined,
|
|
19
|
+
entry: ThemeEntry<Themes> | null | undefined,
|
|
20
20
|
options?:
|
|
21
|
-
| { element?: Element | undefined; stringify?: StringifyStoredTheme<Themes> | undefined }
|
|
21
|
+
| { element?: Element | null | undefined; stringify?: StringifyStoredTheme<Themes> | undefined }
|
|
22
22
|
| undefined
|
|
23
23
|
): void {
|
|
24
24
|
const element = options?.element ?? document?.documentElement
|
|
@@ -26,7 +26,7 @@ export function writeDataAttribute<Themes extends ThemeMap>(
|
|
|
26
26
|
const stringify =
|
|
27
27
|
options?.stringify ??
|
|
28
28
|
((t, x, e) => stringifyDataAttribute(t, x, e, { separator: SEPARATOR_SPACE }))
|
|
29
|
-
if (entry
|
|
29
|
+
if (entry == null) {
|
|
30
30
|
element.removeAttribute(attributeName)
|
|
31
31
|
return
|
|
32
32
|
}
|
|
@@ -9,14 +9,14 @@ import { writeWebStorage } from '../web-storage/write-web-storage.ts'
|
|
|
9
9
|
*
|
|
10
10
|
* @param themes - Record mapping theme keys to values (used by stringify)
|
|
11
11
|
* @param storageKey - localStorage key to write to
|
|
12
|
-
* @param entry - Theme entry to write, or undefined to remove
|
|
12
|
+
* @param entry - Theme entry to write, or null/undefined to remove
|
|
13
13
|
* @param options.stringify - Custom serializer (default: JSON.stringify)
|
|
14
14
|
* @param options.onError - Optional callback invoked when storage write throws
|
|
15
15
|
*/
|
|
16
16
|
export function writeLocalStorage<Themes extends ThemeMap>(
|
|
17
17
|
themes: Themes,
|
|
18
18
|
storageKey: string,
|
|
19
|
-
entry: ThemeEntry<Themes> | undefined,
|
|
19
|
+
entry: ThemeEntry<Themes> | null | undefined,
|
|
20
20
|
options?: {
|
|
21
21
|
stringify?: StringifyStoredTheme<Themes> | undefined
|
|
22
22
|
onError?: ((error: unknown) => void) | undefined
|
|
@@ -9,14 +9,14 @@ import { writeWebStorage } from '../web-storage/write-web-storage.ts'
|
|
|
9
9
|
*
|
|
10
10
|
* @param themes - Record mapping theme keys to values (used by stringify)
|
|
11
11
|
* @param storageKey - sessionStorage key to write to
|
|
12
|
-
* @param entry - Theme entry to write, or undefined to remove
|
|
12
|
+
* @param entry - Theme entry to write, or null/undefined to remove
|
|
13
13
|
* @param options.stringify - Custom serializer (default: JSON.stringify)
|
|
14
14
|
* @param options.onError - Optional callback invoked when storage write throws
|
|
15
15
|
*/
|
|
16
16
|
export function writeSessionStorage<Themes extends ThemeMap>(
|
|
17
17
|
themes: Themes,
|
|
18
18
|
storageKey: string,
|
|
19
|
-
entry: ThemeEntry<Themes> | undefined,
|
|
19
|
+
entry: ThemeEntry<Themes> | null | undefined,
|
|
20
20
|
options?: {
|
|
21
21
|
stringify?: StringifyStoredTheme<Themes> | undefined
|
|
22
22
|
onError?: ((error: unknown) => void) | undefined
|
|
@@ -13,18 +13,20 @@ export interface ThemeEntry<Themes extends ThemeMap = ThemeMap> {
|
|
|
13
13
|
/**
|
|
14
14
|
* Function type for parsing stored string into ThemeEntry.
|
|
15
15
|
* Used as options.parse in persisting theme stores.
|
|
16
|
+
* Value accepts null (e.g. from getItem, getAttribute, cookie parsing).
|
|
16
17
|
*/
|
|
17
18
|
export type ParseStoredTheme<Themes extends ThemeMap> = (
|
|
18
19
|
themes: Themes,
|
|
19
|
-
value: string | undefined
|
|
20
|
+
value: string | null | undefined
|
|
20
21
|
) => ThemeEntry<Themes> | undefined
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Function type for stringify ThemeEntry to a stored string.
|
|
24
25
|
* Used as options.stringify in persisting theme stores.
|
|
26
|
+
* Existing accepts null (e.g. from getAttribute, getItem); entry accepts null for remove/clear.
|
|
25
27
|
*/
|
|
26
28
|
export type StringifyStoredTheme<Themes extends ThemeMap> = (
|
|
27
29
|
themes: Themes,
|
|
28
|
-
existing: string | undefined,
|
|
29
|
-
entry: ThemeEntry<Themes> | undefined
|
|
30
|
+
existing: string | null | undefined,
|
|
31
|
+
entry: ThemeEntry<Themes> | null | undefined
|
|
30
32
|
) => string
|
|
@@ -18,7 +18,5 @@ export interface AsyncThemeStore<Themes extends ThemeMap = ThemeMap> {
|
|
|
18
18
|
| (() => ThemeEntry<Themes> | undefined | Promise<ThemeEntry<Themes> | undefined>)
|
|
19
19
|
| undefined
|
|
20
20
|
write?: ((entry: ThemeEntry<Themes> | undefined) => void | Promise<void>) | undefined
|
|
21
|
-
subscribe?:
|
|
22
|
-
| ((handler: (entry: ThemeEntry<Themes> | undefined | null) => void) => () => void)
|
|
23
|
-
| undefined
|
|
21
|
+
subscribe?: ((handler: (entry: ThemeEntry<Themes> | undefined) => void) => () => void) | undefined
|
|
24
22
|
}
|
|
@@ -13,7 +13,7 @@ import type { ThemeStore } from '../theme-store.types.ts'
|
|
|
13
13
|
* Creates a theme store that reads and writes via element class names.
|
|
14
14
|
*
|
|
15
15
|
* @param themes - Record mapping theme keys to class name(s)
|
|
16
|
-
* @param options.element - Element to operate on (
|
|
16
|
+
* @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
17
17
|
* @param options.parse - Custom parser (default: parseClassName)
|
|
18
18
|
* @param options.stringify - Custom serializer (default: stringifyClassName)
|
|
19
19
|
* @returns ThemeStore
|
|
@@ -30,7 +30,7 @@ import type { ThemeStore } from '../theme-store.types.ts'
|
|
|
30
30
|
export function classNameThemeStore<Themes extends ThemeMap>(
|
|
31
31
|
themes: Themes,
|
|
32
32
|
options?: {
|
|
33
|
-
element?: Element | undefined
|
|
33
|
+
element?: Element | null | undefined
|
|
34
34
|
parse?: ParseStoredTheme<Themes> | undefined
|
|
35
35
|
stringify?: StringifyStoredTheme<Themes> | undefined
|
|
36
36
|
}
|
|
@@ -19,7 +19,7 @@ import type { ThemeStore } from '../theme-store.types.ts'
|
|
|
19
19
|
*
|
|
20
20
|
* @param themes - Record mapping theme keys to attribute values
|
|
21
21
|
* @param options.attributeName - Data attribute name (e.g. `data-theme`)
|
|
22
|
-
* @param options.element - Element to operate on (
|
|
22
|
+
* @param options.element - Element to operate on (accepts null e.g. from refs). Defaults to document.documentElement.
|
|
23
23
|
* @param options.parse - Custom parser (default: parseDataAttribute with space separator)
|
|
24
24
|
* @param options.stringify - Custom serializer (default: stringifyDataAttribute with space separator)
|
|
25
25
|
* @returns ThemeStore
|
|
@@ -47,7 +47,7 @@ export function dataAttributeThemeStore<Themes extends ThemeMap>(
|
|
|
47
47
|
themes: Themes,
|
|
48
48
|
options: {
|
|
49
49
|
attributeName: `data-${string}`
|
|
50
|
-
element?: Element | undefined
|
|
50
|
+
element?: Element | null | undefined
|
|
51
51
|
parse?: ParseStoredTheme<Themes> | undefined
|
|
52
52
|
stringify?: StringifyStoredTheme<Themes> | undefined
|
|
53
53
|
}
|
|
@@ -33,7 +33,7 @@ export function inMemoryThemeStore<Themes extends ThemeMap>(themes: Themes) {
|
|
|
33
33
|
return {
|
|
34
34
|
read,
|
|
35
35
|
write(entry) {
|
|
36
|
-
if (entry
|
|
36
|
+
if (entry == null) {
|
|
37
37
|
if (value === undefined || value === null) return
|
|
38
38
|
value = undefined
|
|
39
39
|
for (const fn of listeners) fn(undefined)
|
|
@@ -24,7 +24,5 @@ import type { ThemeMap } from '../theme-map.types.ts'
|
|
|
24
24
|
export interface ThemeStore<Themes extends ThemeMap = ThemeMap> {
|
|
25
25
|
read?: (() => ThemeEntry<Themes> | undefined) | undefined
|
|
26
26
|
write?: ((entry: ThemeEntry<Themes> | undefined) => void) | undefined
|
|
27
|
-
subscribe?:
|
|
28
|
-
| ((handler: (theme: ThemeEntry<Themes> | undefined | null) => void) => () => void)
|
|
29
|
-
| undefined
|
|
27
|
+
subscribe?: ((handler: (theme: ThemeEntry<Themes> | undefined) => void) => () => void) | undefined
|
|
30
28
|
}
|
|
@@ -4,9 +4,9 @@ import type { ThemeMap } from '../theme-map.types.ts'
|
|
|
4
4
|
function defaultStringify<Themes extends ThemeMap>(
|
|
5
5
|
_themes: Themes,
|
|
6
6
|
_existing: string | undefined,
|
|
7
|
-
entry: ThemeEntry<Themes> | undefined
|
|
7
|
+
entry: ThemeEntry<Themes> | null | undefined
|
|
8
8
|
): string {
|
|
9
|
-
return entry
|
|
9
|
+
return entry == null ? '' : JSON.stringify(entry)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -16,7 +16,7 @@ function defaultStringify<Themes extends ThemeMap>(
|
|
|
16
16
|
*
|
|
17
17
|
* @param themes - Record mapping theme keys to values (used by stringify)
|
|
18
18
|
* @param storageKey - Storage key to write to
|
|
19
|
-
* @param entry - Theme entry to write, or undefined to remove
|
|
19
|
+
* @param entry - Theme entry to write, or null/undefined to remove
|
|
20
20
|
* @param options.storage - Storage object (localStorage or sessionStorage)
|
|
21
21
|
* @param options.stringify - Custom serializer (default: JSON.stringify)
|
|
22
22
|
* @param options.onError - Optional callback invoked when setItem/removeItem throws
|
|
@@ -24,7 +24,7 @@ function defaultStringify<Themes extends ThemeMap>(
|
|
|
24
24
|
export function writeWebStorage<Themes extends ThemeMap>(
|
|
25
25
|
themes: Themes,
|
|
26
26
|
storageKey: string,
|
|
27
|
-
entry: ThemeEntry<Themes> | undefined,
|
|
27
|
+
entry: ThemeEntry<Themes> | null | undefined,
|
|
28
28
|
options: {
|
|
29
29
|
storage: Storage
|
|
30
30
|
stringify?: StringifyStoredTheme<Themes> | undefined
|
|
@@ -33,7 +33,7 @@ export function writeWebStorage<Themes extends ThemeMap>(
|
|
|
33
33
|
): void {
|
|
34
34
|
const { storage, stringify = defaultStringify, onError } = options
|
|
35
35
|
try {
|
|
36
|
-
if (entry
|
|
36
|
+
if (entry == null) {
|
|
37
37
|
storage.removeItem(storageKey)
|
|
38
38
|
} else {
|
|
39
39
|
const existing = storage.getItem(storageKey) ?? undefined
|
package/src/utils/append-id.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Appends a suffix to an ID if the ID is defined.
|
|
3
3
|
*
|
|
4
|
-
* @param id - The ID to append the suffix to.
|
|
4
|
+
* @param id - The ID to append the suffix to (accepts null e.g. from getAttribute).
|
|
5
5
|
* @param suffix - The suffix to append to the ID.
|
|
6
|
-
* @returns The ID with the suffix appended, or undefined if the ID is undefined.
|
|
6
|
+
* @returns The ID with the suffix appended, or undefined if the ID is null/undefined.
|
|
7
7
|
*/
|
|
8
|
-
export function appendId(id: string | undefined, suffix: string): string | undefined {
|
|
8
|
+
export function appendId(id: string | null | undefined, suffix: string): string | undefined {
|
|
9
9
|
return id ? `${id}-${suffix}` : undefined
|
|
10
10
|
}
|