Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/rich-hotels-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mode-watcher": patch
---

chore: move setInitialMode to own module and import with raw
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ CHANGELOG.md
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

docs/.velite/**/*
docs/.velite/**/*
packages/mode-watcher/src/lib/set-initial-mode.js
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default ts.config(
".svelte-kit",
"packages/mode-watcher/dist/**/*",
"packages/mode-watcher/.svelte-kit/**/*",
"packages/mode-watcher/src/lib/set-initial-mode.js",
],
}
);
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { setInitialMode } from "../mode.js";
import setInitialMode from "../set-initial-mode.js?raw";
import type { SetInitialModeArgs } from "../mode.js";
import type { ThemeColors } from "../types.js";

let {
Expand All @@ -8,7 +9,7 @@
themeColors,
}: {
trueNonce: string;
initConfig: Parameters<typeof setInitialMode>[0];
initConfig: SetInitialModeArgs;
themeColors: ThemeColors;
} = $props();
</script>
Expand All @@ -20,9 +21,9 @@
<!-- but that snippet does not run in vitest -->
<meta name="theme-color" content={themeColors.dark} />
{/if}
<!-- eslint-disable-next-line svelte/no-at-html-tags, prefer-template, svelte/no-unused-svelte-ignore --><!-- svelte-ignore hydration_html_changed -->
<!-- eslint-disable-next-line svelte/no-at-html-tags, prefer-template, svelte/no-unused-svelte-ignore -->
{@html `<script${trueNonce ? ` nonce=${trueNonce}` : ""}>(` +
setInitialMode.toString() +
setInitialMode +
`)(` +
JSON.stringify(initConfig) +
`);</script>`}
Expand Down
48 changes: 3 additions & 45 deletions packages/mode-watcher/src/lib/mode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { derivedMode, customTheme, userPrefersMode } from "./states.svelte.js";
import type { Mode, ThemeColors } from "./types.js";
import setInitialMode from "./set-initial-mode.js?raw";

/** Toggle between light and dark mode */
export function toggleMode(): void {
Expand All @@ -25,7 +26,7 @@ export function defineConfig(config: SetInitialModeArgs) {
return config;
}

type SetInitialModeArgs = {
export type SetInitialModeArgs = {
defaultMode?: Mode;
themeColors?: ThemeColors;
darkClassNames?: string[];
Expand All @@ -35,52 +36,9 @@ type SetInitialModeArgs = {
themeStorageKey?: string;
};

/** Used to set the mode on initial page load to prevent FOUC */
export function setInitialMode({
defaultMode = "system",
themeColors,
darkClassNames = ["dark"],
lightClassNames = [],
defaultTheme = "",
modeStorageKey = "mode-watcher-mode",
themeStorageKey = "mode-watcher-theme",
}: SetInitialModeArgs) {
const rootEl = document.documentElement;
const mode = localStorage.getItem(modeStorageKey) ?? defaultMode;
const theme = localStorage.getItem(themeStorageKey) ?? defaultTheme;
const light =
mode === "light" ||
(mode === "system" && window.matchMedia("(prefers-color-scheme: light)").matches);
if (light) {
if (darkClassNames.length) rootEl.classList.remove(...darkClassNames);
if (lightClassNames.length) rootEl.classList.add(...lightClassNames);
} else {
if (lightClassNames.length) rootEl.classList.remove(...lightClassNames);
if (darkClassNames.length) rootEl.classList.add(...darkClassNames);
}
rootEl.style.colorScheme = light ? "light" : "dark";

if (themeColors) {
const themeMetaEl = document.querySelector('meta[name="theme-color"]');
if (themeMetaEl) {
themeMetaEl.setAttribute(
"content",
mode === "light" ? themeColors.light : themeColors.dark
);
}
}

if (theme) {
rootEl.setAttribute("data-theme", theme);
localStorage.setItem(themeStorageKey, theme);
}

localStorage.setItem(modeStorageKey, mode);
}

/**
* A type-safe way to generate the source expression used to set the initial mode and avoid FOUC.
*/
export function generateSetInitialModeExpression(config: SetInitialModeArgs = {}): string {
return `(${setInitialMode.toString()})(${JSON.stringify(config)});`;
return `(${setInitialMode})(${JSON.stringify(config)});`;
}
1 change: 1 addition & 0 deletions packages/mode-watcher/src/lib/set-initial-mode.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion packages/mode-watcher/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,16 @@
"moduleResolution": "NodeNext",
"module": "NodeNext",
"types": ["node"]
}
},
// copying over the svelte tsconfig excludes to add set-initial-mode
"exclude": [
"node_modules/**",
"src/service-worker.js",
"src/service-worker/**/*.js",
"src/service-worker.ts",
"src/service-worker/**/*.ts",
"src/service-worker.d.ts",
"src/service-worker/**/*.d.ts",
"src/lib/set-initial-mode.js"
]
}