@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.
import { useContrastRegion } from '@pbroom/color-kit/react';use-contrast-region.ts:245function 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
- plane
ColorPlaneSpec - Color and axes of the plane.
- options?
UseContrastRegionOptionsdefault{} - See
UseContrastRegionOptions.
Returns
ContrastRegionGeometryMemoized ContrastRegionGeometry.
Throws
- When both axes use the same channel.
- When
gamutis not'srgb'or'display-p3'.
Example
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
landcwork 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.
thresholdoverrideslevelandapcaPreset. Withmetric: 'apca'it is a normalized Lc magnitude:0.6means Lc 60. - Stroke
path, fillfillPath.pathsare the solver's contours, snapped onto the gamut boundary.fillPathscloses each open contour along the boundary on the side that passes, and drops polygons that would contain the reference. - While dragging. With
isDraggingthe 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.