File size: 2,704 Bytes
04ec17f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
import { PersistedState, watch } from "runed";
import { isBrowser, noopStorage } from "./utils.js";
import { modeStorageKey } from "./storage-keys.svelte.js";
import { isValidMode } from "./modes.js";
import { MediaQuery } from "svelte/reactivity";
export class UserPrefersMode {
#defaultValue = "system";
#storage = isBrowser ? localStorage : noopStorage;
#initialValue = this.#storage.getItem(modeStorageKey.current);
#value = isValidMode(this.#initialValue) ? this.#initialValue : this.#defaultValue;
#persisted = $state(this.#makePersisted());
#makePersisted(value = this.#value) {
return new PersistedState(modeStorageKey.current, value, {
serializer: {
serialize: (v) => v,
deserialize: (v) => {
if (isValidMode(v))
return v;
return this.#defaultValue;
},
},
});
}
constructor() {
$effect.root(() => {
return watch.pre(() => modeStorageKey.current, (_, prevStorageKey) => {
const currModeValue = this.#persisted.current;
this.#persisted = this.#makePersisted(currModeValue);
if (prevStorageKey) {
localStorage.removeItem(prevStorageKey);
}
});
});
}
get current() {
return this.#persisted.current;
}
set current(newValue) {
this.#persisted.current = newValue;
}
}
export class SystemPrefersMode {
#defaultValue = undefined;
#track = true;
#current = $state(this.#defaultValue);
#mediaQueryState = typeof window !== "undefined" && typeof window.matchMedia === "function"
? new MediaQuery("prefers-color-scheme: light")
: { current: false };
query() {
if (!isBrowser)
return;
this.#current = this.#mediaQueryState.current ? "light" : "dark";
}
tracking(active) {
this.#track = active;
}
constructor() {
$effect.root(() => {
$effect.pre(() => {
if (!this.#track)
return;
this.query();
});
});
this.query = this.query.bind(this);
this.tracking = this.tracking.bind(this);
}
get current() {
return this.#current;
}
}
/**
* Writable state that represents the user's preferred mode
* (`"dark"`, `"light"` or `"system"`)
*/
export const userPrefersMode = new UserPrefersMode();
/**
* Readable store that represents the system's preferred mode (`"dark"`, `"light"` or `undefined`)
*/
export const systemPrefersMode = new SystemPrefersMode();
|