diff --git a/.changeset/violet-rockets-explain.md b/.changeset/violet-rockets-explain.md new file mode 100644 index 0000000..bcb85be --- /dev/null +++ b/.changeset/violet-rockets-explain.md @@ -0,0 +1,5 @@ +--- +'mode-watcher': patch +--- + +Add `color-scheme` style to document element diff --git a/src/lib/mode.ts b/src/lib/mode.ts index c1ccae9..33a0677 100644 --- a/src/lib/mode.ts +++ b/src/lib/mode.ts @@ -50,12 +50,14 @@ function setModeUserPrefers(value: boolean | undefined): void { /** Set the current mode */ export function setModeCurrent(value: boolean): void { - const htmlElClasses = document.documentElement.classList; + const htmlEl = document.documentElement; const classDark = 'dark'; if (value === true) { - htmlElClasses.remove(classDark); + htmlEl.classList.remove(classDark); + htmlEl.style.colorScheme = 'light'; } else { - htmlElClasses.add(classDark); + htmlEl.classList.add(classDark); + htmlEl.style.colorScheme = 'dark'; } modeCurrent.set(value); } @@ -66,16 +68,18 @@ export function setModeCurrent(value: boolean): void { /** Set the visible light/dark mode on page load */ export function setInitialClassState() { - const htmlElClasses = document.documentElement.classList; + const htmlEl = document.documentElement; const condLocalStorageUserPrefs = localStorage.getItem('modeUserPrefers') === 'false'; const condLocalStorageUserPrefsExist = !('modeUserPrefers' in localStorage); const condMatchMedia = window.matchMedia('(prefers-color-scheme: dark)').matches; if (condLocalStorageUserPrefs || (condLocalStorageUserPrefsExist && condMatchMedia)) { - htmlElClasses.add('dark'); + htmlEl.classList.add('dark'); + htmlEl.style.colorScheme = 'dark'; } else { - htmlElClasses.remove('dark'); + htmlEl.classList.remove('dark'); + htmlEl.style.colorScheme = 'light'; } } @@ -87,12 +91,14 @@ export function setInitialClassState() { export function autoModeWatcher(): void { const mql = window.matchMedia('(prefers-color-scheme: dark)'); function setMode(value: boolean) { - const htmlElClasses = document.documentElement.classList; + const htmlEl = document.documentElement; const classDark = 'dark'; if (value === true) { - htmlElClasses.remove(classDark); + htmlEl.classList.remove(classDark); + htmlEl.style.colorScheme = 'light'; } else { - htmlElClasses.add(classDark); + htmlEl.classList.add(classDark); + htmlEl.style.colorScheme = 'dark'; } } setMode(mql.matches); diff --git a/src/tests/mode.spec.ts b/src/tests/mode.spec.ts index 264025e..1db7f17 100644 --- a/src/tests/mode.spec.ts +++ b/src/tests/mode.spec.ts @@ -13,31 +13,44 @@ it('renders mode', async () => { it('toggles the mode', async () => { const { container, getByTestId } = render(Mode); const rootEl = container.parentElement; + const classes = getClasses(rootEl); + const colorScheme = getColorScheme(rootEl); expect(classes).toContain('dark'); + expect(colorScheme).toBe('dark'); const toggle = getByTestId('toggle'); await userEvent.click(toggle); const classes2 = getClasses(rootEl); + const colorScheme2 = getColorScheme(rootEl); expect(classes2).not.toContain('dark'); + expect(colorScheme2).toBe('light'); await userEvent.click(toggle); const classes3 = getClasses(rootEl); + const colorScheme3 = getColorScheme(rootEl); expect(classes3).toContain('dark'); + expect(colorScheme3).toBe('dark'); }); it('allows the user to set the mode', async () => { const { container, getByTestId } = render(Mode); const rootEl = container.parentElement; const classes = getClasses(rootEl); + const colorScheme = getColorScheme(rootEl); expect(classes).toContain('dark'); + expect(colorScheme).toBe('dark'); const light = getByTestId('light'); await userEvent.click(light); const classes2 = getClasses(rootEl); + const colorScheme2 = getColorScheme(rootEl); expect(classes2).not.toContain('dark'); + expect(colorScheme2).toBe('light'); const dark = getByTestId('dark'); await userEvent.click(dark); const classes3 = getClasses(rootEl); + const colorScheme3 = getColorScheme(rootEl); expect(classes3).toContain('dark'); + expect(colorScheme3).toBe('dark'); }); it('keeps the mode store in sync with current mode', async () => { @@ -47,17 +60,23 @@ it('keeps the mode store in sync with current mode', async () => { const dark = getByTestId('dark'); const mode = getByTestId('mode'); const classes = getClasses(rootEl); + const colorScheme = getColorScheme(rootEl); expect(classes).toContain('dark'); + expect(colorScheme).toBe('dark'); expect(mode.textContent).toBe('dark'); await userEvent.click(light); const classes2 = getClasses(rootEl); + const colorScheme2 = getColorScheme(rootEl); expect(classes2).not.toContain('dark'); + expect(colorScheme2).toBe('light'); expect(mode.textContent).toBe('light'); await userEvent.click(dark); const classes3 = getClasses(rootEl); + const colorScheme3 = getColorScheme(rootEl); expect(classes3).toContain('dark'); + expect(colorScheme3).toBe('dark'); expect(mode.textContent).toBe('dark'); }); @@ -68,3 +87,10 @@ function getClasses(element: HTMLElement | null): string[] { const classes = element.className.split(' ').filter((c) => c.length > 0); return classes; } + +function getColorScheme(element: HTMLElement | null) { + if (element === null) { + return ''; + } + return element.style.colorScheme; +}