npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

perfect-dark-mode

v1.0.0

Published

Perfect dark mode.

Downloads

66

Readme

perfect-dark-mode

Version Size Build Codecov

  • No flicker.
  • Framework agnostic. Supports React | Vue | Svelte.
  • Tiny, less than 1kb.
  • Works with server side rendering.
  • Uses system color mode when JS is disabled.
  • Listens for changes to the system color mode.
  • Allows user to override the system color mode and save their preference.
  • Allows clearing the saved preference and falling back to the system mode.
  • Supports any number of color modes, not just light and dark.
  • Syncs across tabs.
  • Built for the web.

Installation

There are a few options for installing perfect-dark-mode. Note, if you use Gatsby or Next.js you do not need to do this.

Yarn

yarn add perfect-dark-mode

Then you must add node_modules/perfect-dark-mode/dist/index.js as a script in the <head> of your page.

How you do this will depend on the framework you are using.

UNPKG

Add this code to the <head> of your page:

<script src="https://unpkg.com/[email protected]/dist/index.js"></script>

Copy and Paste

Add this code to the <head> of your page:

<script>(()=>{var W=({prefix:r="pdm",modes:w=["light","dark"]}={})=>{var n=r,l=window.localStorage,t=w,c=new Set,h=e=>{t=e,c.forEach(o=>o(e))},O={subscribe(e){return e(t),c.add(e),()=>c.delete(e)},set:h,update(e){h(e(t))}},u=new Set,a=matchMedia("(prefers-color-scheme: dark)"),m,f=({matches:e})=>{m=e?"dark":"light",u.forEach(o=>o(m))};a.addEventListener?a.addEventListener("change",f):a.addListener(f),f(a);var v={subscribe(e){return e(m),u.add(e),()=>u.delete(e)}},P=e=>{if(!(!e||!t.includes(e)))return e},p=new Set,s=P(l.getItem(n)),M=(e,o=!0)=>{e!==s&&(o&&(e!==void 0?l.setItem(n,e):l.removeItem(n)),p.forEach(T=>T(e)),s=e)};window.addEventListener("storage",e=>e.key===n&&M(e.newValue||void 0,!1));var i={subscribe(e){return e(s),p.add(e),()=>p.delete(e)},set:M,update(e){M(e(s))}},g,k,d,b=new Set,x=()=>{var e=g||k;e!==d&&(d=e,b.forEach(o=>o(d)))};i.subscribe(e=>{g=e,x()}),v.subscribe(e=>{k=e,x()});var E={subscribe(e){return e(d),b.add(e),()=>b.delete(e)},set:i.set,update(e){var o=t.indexOf(d);o=o===-1?0:o,i.set(e(d,t,o))}},C=document.documentElement.classList,S;return E.subscribe(e=>{S&&C.remove(`${r}-${S}`),C.add(`${r}-${e}`),S=e}),C.add(r),{mode:E,modes:O,modeOS:v,modeSaved:i}};window.__pdm__=W({modes:document.documentElement.dataset.pdm?.split(" ")});})();</script>

Usage

A class indicating the color mode will be added to <html> (e.g. pdm-light or pdm-dark). This is done before the rest of your page is rendered (that's why it needs to be in head).

This does:

  • Determine the correct color mode when the page is loaded.
  • Save changes to the mode.
  • Allow for listening to the mode and building controls that depend on it.

This does not:

  • Handle styling for you.
    • Styling should be done using CSS variables.
  • Automatically convert your page to dark mode.
    • This would be error prone, it is better to intentionally design your color modes using CSS variables.
  • Provide UI components for you.
    • This page does show some examples of how to make simple controls in various frameworks that listen to the mode.

Example CSS

Here is a simple implementation of dark and light modes using CSS variables and the classes added by PDM:

/* This supports users with JS disabled. */
@media (prefers-color-scheme: dark) {
  :root {
    --color: white;
    --background: black;
  }
}

/* This supports users with JS disabled. */
@media (prefers-color-scheme: light) {
  :root {
    --color: black;
    --background: white;
  }
}

/* Styles for when light mode is enabled. */
.pdm-light {
  --color: black;
  --background: white;
}

/* Styles for when dark mode is enabled. */
.pdm-dark {
  --color: white;
  --background: black;
}

/* Default color and background. */
/* If you add a color or background on other components (e.g. body or some custom Button) */
/* that will override these. You will need to change those styles to use these CSS variables. */
:root {
  color: var(--color);
  background: var(--background);
}

In the rest of your app use --color and --background as needed.

Listening

  • You can subscribe to the mode, this can be used for rendering a toggle component.
  • The first call of your listener is synchronous so you can get the value before rendering.
const { mode } = window.__pdm__
const unsubscribe = mode.subscribe((v) => console.log(v))

Setting

  • You can set the mode.
  • You can update the mode based on the current mode.
const { mode } = window.__pdm__
mode.set('light')
mode.update((mode) => (mode === 'light' ? 'dark' : 'light'))

API Reference

  • window.__pdm__
    • mode: Writable<ColorMode>
      • The resolved mode, modeSaved || modeOS.
      • Can be set or updated.
      • subscribe(listener: (mode: ColorMode) => void): () => void
      • set(mode: ColorMode): void
      • update(updater: (mode: ColorMode, modes: ColorMode[], index: number | undefined) => ColorMode): void
        • The update function gives you the current modes and the current mode index so you can cycle through by returning modes[(modeIndex + 1) % modes.length].
    • modes: Writable<ColorMode[]>
      • Valid color modes, can be used to render a list.
      • Can be set or updated.
      • subscribe(listener: (modes: ColorMode[]) => void): () => void
      • set(modes: ColorMode[]): void
      • update(updater: (modes: ColorMode[]) => ColorMode[]): void
    • modeSaved: Writable<ColorMode>
      • This is mainly for debugging, prefer using mode.
      • subscribe(listener: (mode: ColorMode) => void): () => void
    • modeOS: Readable<ColorMode>
      • This is mainly for debugging, prefer using mode.
      • The system mode cannot be written by JS, it can be updated by the user in their system settings.
      • We do listen for changes to the system color mode.
      • subscribe(listener: (mode: ColorMode) => void): () => void

Pure Usage

If for some reason you don't want PDM to automatically initialize itself and add itself on window.__pdm__ you can use the pure version:

import { createPerfectDarkMode } from 'perfect-dark-mode'

const pdm = createPerfectDarkMode()