Skip to content

Hooks

Context-reading hooks for authoring custom blocks. They read from the nearest SwatchbookProvider, mounted automatically by the addon’s preview decorator inside Storybook, and are re-exported from the addon so either import path works. Outside Storybook, wrap the tree in SwatchbookProvider and pass a wire snapshot (snapshot prop, plus axes or defaultAxes) so the hooks have something to resolve against.

Returns the full ProjectSnapshot the provider is holding (axes, activeTheme, activeAxes, cssVarPrefix, diagnostics, css, listing, tokenGraph, defaultTuple, resolveAt). Useful for custom blocks that need graph-level information the canned blocks don’t expose.

The snapshot’s listing?: Readonly<Record<string, VirtualTokenListing>> field carries per-token metadata from @terrazzo/plugin-token-listing: authoritative CSS variable names (names.css), preview values, source file + line references. It’s empty for layered / plain-parse projects, so read it when present and fall back gracefully. For a token’s CSS var reference, prefer listing[path].names.css when a listing entry exists and fall back to cssVarRef(path, cssVarPrefix) from @unpunnyfuns/swatchbook-core/css-var otherwise.

Throws when no SwatchbookProvider is mounted above. For code paths that need to handle the no-provider case (MDX doc blocks rendered without a preview decorator, conditional fallbacks), use useOptionalSwatchbookData instead.

Returns the ProjectSnapshot | null from the nearest SwatchbookProvider, or null when no provider is mounted. Same shape and reactivity as useSwatchbookData(); the only difference is the null sentinel in the absent-provider case. Consumers that prefer to throw can stay on useSwatchbookData.

Returns the current composed theme ID as a string (e.g. "Dark · Brand A").

Returns the active tuple as Readonly<Record<string, string>>.

Flips the tuple of the nearest uncontrolled SwatchbookProvider. Provider-coupled, so it is documented with the provider: see useSetAxes.

Returns the active color format ('hex' | 'rgb' | 'hsl' | 'oklch' | 'raw') from the context/snapshot/source chain: a ColorFormatContext value (a host wrapping a subtree in its own provider), then defaultColorFormat from whichever project data is actually feeding the render (the SwatchbookProvider snapshot a story decorator or a standalone host mounts, or, for blocks embedded directly in MDX with no <Story/> and no provider, the ambient source a host pushed into via @unpunnyfuns/swatchbook-blocks/host), then 'hex'. No Storybook globals are involved; blocks carry no Storybook vocabulary of their own.

The full precedence order for a canned block also includes its own colorFormat prop, which sits above everything this hook resolves: colorFormat prop → ColorFormatContext → active snapshot/source defaultColorFormat'hex'. A block’s own prop always wins for that block; when unset, the block falls through to whatever useColorFormat() resolves. Pair with formatColor to render colors the same way the built-in blocks do.

The color-rendering blocks (<ColorPalette>, <ColorTable>, <TokenDetail>, sub-color fields in <ShadowPreview> / <BorderPreview> / <GradientPalette>) all route through one helper. The helper plus its types are exported from @unpunnyfuns/swatchbook-blocks for custom blocks that need to stringify a color the same way.

import {
formatColor,
COLOR_FORMATS,
type ColorFormat,
type FormatColorResult,
type NormalizedColor,
} from '@unpunnyfuns/swatchbook-blocks';
type ColorFormat = 'hex' | 'rgb' | 'hsl' | 'oklch' | 'raw';
const COLOR_FORMATS: readonly ColorFormat[];
function formatColor(
value: unknown,
format: ColorFormat,
fallback?: string,
): FormatColorResult;
interface FormatColorResult {
/** Display string, e.g. "rgb(59 132 246)" or "#3b82f6". */
value: string;
/** True when the requested format can't losslessly represent the color. */
outOfGamut: boolean;
}
  • hex falls back to space-separated rgb() for out-of-gamut colors and marks them outOfGamut: true; blocks render a ⚠ glyph beside the value.
  • oklch is wide-gamut and never marks outOfGamut.
  • raw returns a compact JSON of the normalized Terrazzo shape, useful for DTCG authors who want to see exactly what the parser stored.
  • fallback defaults to '—'; pass a custom string when integrating with surfaces that need a different placeholder.

COLOR_FORMATS is the runtime list used to validate stored user choices; reach for it when you need to enumerate the formats (toolbar pills, validation) without duplicating the union.

NormalizedColor is the shape formatColor accepts: a structural copy of Terrazzo’s ColorValueNormalized (colorSpace, components / channels, alpha, optional hex). Use it when typing custom block code that produces or consumes the same payload.

Hook consumers re-render on the same ambient project source (@unpunnyfuns/swatchbook-blocks/host’s useProjectSource()) the built-in blocks subscribe to, so the active axis tuple and color format both stay in sync without a story re-render. This works both inside story renders (through the SwatchbookProvider a decorator or standalone host mounts) and inside MDX doc blocks (where the preview HooksContext isn’t available, so the fallback path reads the ambient source directly). A host (the addon, or any other integration) is what keeps that source current; a standalone render with only a snapshot prop and no host has nothing external pushing updates into it beyond useSetAxes().