@pbroom/color-kit/reactPlane geometry

useContrastRegion

Solves the colors of one hue that meet a contrast threshold against a reference color, as contour lines and fillable polygons in plane coordinates.

functionimport { useContrastRegion } from '@pbroom/color-kit/react';use-contrast-region.ts:245
function useContrastRegion(
  plane: ColorPlaneSpec,
  options?: UseContrastRegionOptions,
): ContrastRegionGeometry;

The region is solved in the lightness/chroma plane (axes l and c in either order; other planes return empty geometry) with WCAG 2 or APCA, measured in gamut. The hook returns geometry only: stroke path and fill fillPath in an SVG over the plane. It solves synchronously at rest and in a shared Web Worker while isDragging (when workers are available); during a drag the sampling stays at its last idle level and the last region stays in place until a fresh one arrives.

Parameters

planeColorPlaneSpec
Color and axes of the plane.

Returns

ContrastRegionGeometryMemoized ContrastRegionGeometry.

Throws

  • When both axes use the same channel.
  • When gamut is not 'srgb' or 'display-p3'.

Example

TSX
import { parse, type Color } from '@pbroom/color-kit';
import { useContrastRegion } from '@pbroom/color-kit/react';

const white = parse('#ffffff');

export function ReadableOnWhite({ color }: { color: Color }) {
  const region = useContrastRegion({ color }, { reference: white, level: 'AA' });
  return (
    <svg viewBox="0 0 100 100" preserveAspectRatio="none">
      <path d={region.fillPath} fill="#000" fillOpacity={0.2} />
      <path d={region.path} fill="none" stroke="#fff" vectorEffect="non-scaling-stroke" />
    </svg>
  );
}

Edge cases

  • Lightness and chroma only. The region is solved in the plane's lightness/chroma slice. Axes l and c work in either order; any other pair (a hue axis, say) returns empty geometry rather than throwing.
  • The reference defaults to the plane's color. Without reference, every color of the hue is measured against the color being picked, which is rarely what a text-on-background check wants. Pass the fixed background (or text) color explicitly.
  • Gamut. Samples and the reference are measured in gamut ('srgb' by default) and paths stay inside it, so the region never promises a color the target display cannot show.
  • Thresholds. threshold overrides level and apcaPreset. With metric: 'apca' it is a normalized Lc magnitude: 0.6 means Lc 60.
  • Stroke path, fill fillPath. paths are the solver's contours, snapped onto the gamut boundary. fillPaths closes each open contour along the boundary on the side that passes, and drops polygons that would contain the reference.
  • While dragging. With isDragging the region is solved in a shared Web Worker where available, at the sampling of the last idle frame; the last region stays in place until a fresh one arrives, so the outline can trail the thumb by a frame or two.