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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@patternmode/swatch

v4.1.1

Published

Color, gradient, image, and palette swatch primitives for Patternmode interfaces.

Readme

@patternmode/swatch

Color, gradient, image, and palette swatch primitives for React.

import { DistributionBar, Swatch } from "@patternmode/swatch";
import "@patternmode/swatch/styles.css";

export function Example() {
  return (
    <>
      <Swatch
        aria-label="Palette"
        colors={[
          { color: "#315c4b", ratio: 60 },
          { color: "#e1ebe5", ratio: 40 },
        ]}
        shape="pill"
        size="2xl"
      />
      <DistributionBar
        aria-label="Finish distribution"
        segments={[
          { id: "evergreen", color: "#315c4b", label: "Evergreen", value: 48 },
          { id: "saffron", color: "#d9a441", label: "Saffron", value: 30 },
          { id: "oxblood", color: "#9b3d32", label: "Oxblood", value: 22 },
        ]}
      />
    </>
  );
}

Use color for a solid fill, background for a CSS background value, or colors for weighted palette stops. Swatch remains representation-only: compose selection around it, or pass onRemove when the swatch should expose its built-in remove request affordance.

Transparent values

A partially transparent fill composites against whatever is behind it, so on a white page a 40% colour renders as a pale solid — indistinguishable from a lighter opaque colour, or from an empty swatch. Pass transparencyBackdrop to put a chequerboard behind the fill so the transparency reads as transparency:

<Swatch aria-label="Overlay tint" color="rgb(49 92 75 / 40%)" transparencyBackdrop />

It is an explicit declaration, never inferred. Alpha cannot be detected across everything a swatch accepts — a gradient, a color-mix(), a CSS variable or child media can all carry alpha the component cannot see — so a swatch that guessed would be right sometimes and silently wrong the rest of the time. You know whether your value is transparent; say so.

Three knobs, each read at the point of use, so setting them on any ancestor works:

| Custom property | Default | Effect | | ------------------------------------- | ------------------- | --------------------- | | --patternmode-swatch-backdrop-size | 8px | Chequer square size | | --patternmode-swatch-backdrop-color | var(--border, …) | Chequer colour | | --patternmode-swatch-backdrop-base | var(--card, #fff) | The surface behind it |

The two colour defaults come from the theme, so the backdrop follows a dark mode without any work from you.

Rendering as a child element

By default Swatch renders its own <figure> wrapper. Pass asChild to render the swatch styling through a single child element instead — the Radix Slot pattern. Swatch merges its className, style (including the --patternmode-swatch-size / --patternmode-swatch-fill variables), data-* attributes, and remaining props onto the child, and injects the fill / scrim layers inside it. The child's own props win on conflict, and event handlers are composed.

Use this when the swatch must be an interactive element, such as a <button> cell in a color matrix:

<Swatch asChild color="#315c4b" flat shape="block" size="lg">
  <button onClick={() => select("#315c4b")} type="button" />
</Swatch>

asChild requires exactly one React element child and does not support onRemove (its remove affordance cannot be composed into an arbitrary slotted element). Wrap a default Swatch when a remove control is required.

Optimized images

Swatch can frame media via children, but it does not optimize images itself. If your app uses Next.js, pass your own next/image Image component as the child:

import { Swatch } from "@patternmode/swatch";
import Image from "next/image";

<Swatch aria-label="Oak veneer" objectFit="cover" shape="square" size="4xl">
  <Image alt="" fill sizes="4.5rem" src="/finishes/oak.jpg" />
</Swatch>;

Distributions: two components, and they are not interchangeable

Use DistributionBar when a human allocates the weights and must be able to change them: it renders a <fieldset> with role="slider" boundary handles that drag and answer arrow keys.

Use DistributionDisplay when the weights were computed — a bin a calculation filled rather than a share someone assigned. It draws the same contiguous track and legend and nothing else. Dragging the edge of a computed bin just lies about what the number is, which is why the read-only one exists rather than being the editor with its handles hidden.

import { DistributionDisplay } from "@patternmode/swatch";

<DistributionDisplay
  aria-label="Colour distribution"
  emptyLabel="unclassified"
  emptyValue={12}
  legend="summary"
  segments={[
    { id: "evergreen", color: "#315c4b", label: "Evergreen", value: 48 },
    { id: "saffron", color: "#d9a441", label: "Saffron", value: 30 },
  ]}
/>;

One bordered track with hairline boundaries, not a flex row of individually rounded Swatch blocks — contiguity is the hard part, and separate blocks leak each swatch's own radius and shadow as seams.

  • legend"segments" (default, one entry per segment), "summary" (assigned vs unassigned percentages), or false.
  • emptyValue / emptyLabel — unassigned weight, drawn as a muted remainder and included in the derived percentages.
  • onSegmentSelect + selectedSegmentId — makes each segment a button and rings the selected one. Selection is not editing; the element only becomes a <fieldset> when it becomes interactive.
  • Height and corner radius come from --patternmode-distribution-height and --patternmode-distribution-radius.

Distribution segment values are weights, not persisted percentages. Both components render segment widths proportionally and their legends display derived percentages.

For external segment controls, keep segments controlled and pass the next value to onChange. updateDistributionSegment does not change distribution values.

Exports

Everything the package ships. If it is not here, it is not public.

Components

| | | | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | Swatch | Colour, gradient, image and palette swatch. SwatchProps is the union of SwatchDefaultProps (own <figure>) and SwatchRenderProps (asChild). | | DistributionBar | The editor — draggable, keyboard-adjustable boundary handles. DistributionBarProps. | | DistributionDisplay | The read-only strip. DistributionDisplayProps. |

Distribution helpers

Pure functions over a segment list, so custom controls do not duplicate the bar math. All return a new array; none mutate.

| | | | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | getDistributionTotal(segments) | Sum of sanitised weights; invalid or negative values count as 0. | | getDistributionBoundaryPercent(segments, boundaryIndex) | Percentage position of the boundary after boundaryIndex. | | moveDistributionBoundary(segments, boundaryIndex, deltaValue, minValue) | Moves weight between two adjacent segments, preserving their sum and holding each side above minValue. | | updateDistributionSegment(segments, segmentId, update) | Changes segment metadata (label, colour). Cannot change value — the type forbids it. | | removeDistributionSegment(segments, segmentId) | Removes a segment and redistributes its weight proportionally across the rest. |

Swatch helpers

| | | | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | getSwatchColorsBackground(colors, blend?) | The CSS background a palette produces. blend is "step" (default, hard boundaries) or "smooth" (interpolated in OKLab). Returns undefined for an empty palette. | | getSwatchAtmosphereBackground(colors, options?) | The soft layered-radial "atmosphere" fill — overlapping elliptical pools rather than a flat or linear ramp. SwatchAtmosphereOptions: density (0 diffuse → 1 dense, default 0.5) and gravity (-1 sinks → 1 rises, default 0). | | getSwatchSizeVariableStyle(size, variableName?) | The inline style object setting --patternmode-swatch-size for a size token, for framing something Swatch does not render itself. |

Constants and types

SWATCH_SIZES, SWATCH_SIZE_VALUES, SWATCH_SHAPES, SWATCH_TEXTURES — the allowed token lists, with SwatchSize, SwatchShape, SwatchTexture derived from them, plus SwatchColorStop and SwatchSharedProps.

DistributionSegment and DistributionSegmentUpdate are the segment types. DistributionBarSegment and DistributionBarSegmentUpdate are their former names, kept as identical-shape aliases — prefer the neutral ones, since the segment belongs to both components rather than to the editor.

Import @patternmode/swatch/styles.css once in your app.