Skip to content

Commit

Permalink
Add color-scheme style along with classes (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Oct 23, 2023
1 parent cd08174 commit a03b451
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-rockets-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'mode-watcher': patch
---

Add `color-scheme` style to document element
24 changes: 15 additions & 9 deletions src/lib/mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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';
}
}

Expand All @@ -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);
Expand Down
26 changes: 26 additions & 0 deletions src/tests/mode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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');
});

Expand All @@ -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;
}

0 comments on commit a03b451

Please sign in to comment.