@kherge/prefers-color-scheme

A simple library for programatically consuming the CSS prefers-color-scheme media feature.

Usage no npm install needed!

<script type="module">
  import khergePrefersColorScheme from 'https://cdn.skypack.dev/@kherge/prefers-color-scheme';
</script>

README

Quality Check Quality Gate Status

prefers-color-scheme

A simple library for programatically consuming the CSS prefers-color-scheme media feature.

Documentation

This is an ES6 browser library written in TypeScript.

import {
  ColorScheme,
  getColorScheme,
  watchColorScheme,
} from '@kherge/prefers-color-scheme';

Recognized Color Schemes

enum ColorScheme

The ColorScheme enum has members that are the officially recognized color schemes.

console.log(ColorScheme.Dark); // 'dark'
console.log(ColorScheme.Light); // 'light'

Retrieving Color Scheme

const getColorScheme: () => ColorScheme;

The getColorScheme function retrieves the currently preferred color scheme.

console.log(getColorScheme()); // 'dark'

Watching for Changes

const watchColorScheme: (watcher: Watcher) => () => void;

// The watcher provided to watchColorsScheme.
type Watcher = (colorScheme: ColorScheme) => void;

The watchColorScheme function invokes a callback any time the preferred color scheme changes.

const removeWatcher = watchColorScheme(colorScheme => console.log(colorScheme));

If we want to stop listening to changes, we use the returned function.

removeWatcher();

Testing

import { matchMedia } from '@kherge/prefers-color-scheme';

interface Builder {
  once(specifier: Specifier): Implementation;
  many(specifier: Specifier): Implementation;
  reset(): Builder;
}

export interface Specification {
  addEventListener(mock?: jest.Mock): void;
  matches(state: boolean): void;
  removeEventListener(mock?: jest.Mock): void;
}

The matchMedia utility is an instance of Builder which simplifies the process of defining the mock implementation for window.matchMedia.

beforeEach(() => matchMedia.reset());

describe('example tests using matchMedia', () => {
  test('mock the return value for matches', () => {
    matchMedia.once(spec => {
      spec.matches(true);
    });

    expect(getColorScheme()).toBe(ColorScheme.Dark);

    matchMedia.once();

    expect(getColorScheme()).toBe(ColorScheme.Light);
  });

  test('mock event listener management', () => {
    const { addEventListener, removeEventListener } = matchMedia.once();

    const listener = jest.fn();
    const remove = watchColorScheme(listener);

    expect(addEventListener).toHaveBeenCalledWith(
      'change',
      expect.any(Function)
    );

    remove();

    expect(removeEventListener).toHaveBeenCalled();
  });

  test('mock event listener management (again)', () => {
    const addEventListener = jest.fn();
    const removeEventListener = jest.fn();

    matchMedia.once(spec => {
      spec.addEventListener(addEventListener);
      spec.removeEventListener(removeEventListener);
    });

    const listener = jest.fn();
    const remove = watchColorScheme(listener);

    expect(addEventListener).toHaveBeenCalledWith(
      'change',
      expect.any(Function)
    );

    remove();

    expect(removeEventListener).toHaveBeenCalled();
  });
});

Installation

npm install @kherge/prefers-color-scheme

Requirements

  • Browser Support for ES6/ESM

Development

Created using TSDX.

Building

npm run build

Builds to the dist/ folder.

Linting

npm run lint

Runs ESLint with Prettier.

Unit Testing

npm test

You can also run npm run test:watch to use interactive watch mode.