Skip to main content
Version: Next

Utility blocks

Blocks that surface project-level state rather than tokens themselves.

<Diagnostics />

<Diagnostics />

Project-load diagnostics (parser errors, resolver warnings, disabled-axis validation) as a collapsible list. Green OK badge when clean; auto-expands with a severity summary when warnings or errors are present.

Props: caption?: string overrides the summary heading.

The Diagnostic shape

Every loadProject() call returns a diagnostics: Diagnostic[] list. The block renders it directly.

interface Diagnostic {
severity: 'error' | 'warn' | 'info';
group: string;
message: string;
filename?: string;
line?: number;
}

group identifies the subsystem that produced the diagnostic:

  • parser: Terrazzo's token-file parser (malformed JSON, invalid $value, wrong $type, …).
  • resolver: resolver-file issues (missing $ref, unknown modifier, context with no files).
  • swatchbook/presets: preset validation (unknown axis key, invalid context value).
  • Plugin-originated groups: depends on your setup.

Severities

  • error: something is structurally broken. A token may be missing from the graph, an alias may be unresolved. The block shows these with a red badge.
  • warn: something is unusual or probably-a-mistake but the project loaded. Example: a preset with an unknown axis key is dropped and produces a warn.
  • info: diagnostic for the curious. Rare.

Reading common diagnostics

  • parser: Could not resolve alias "{color.palette.blue.500}": the alias target doesn't exist in the merged graph. Check for a typo in the path, or a missing token file that wasn't included in tokens globs.
  • parser: Invalid token value for $type "color": the $value doesn't parse as the declared $type. Usually a string missing a unit or a color in the wrong format.
  • swatchbook/presets: Preset "X" has unknown axis key "Y": a preset references an axis that doesn't exist on the project. Either the axis name was renamed or the preset predates the resolver change.

Failing CI on errors

The block surfaces diagnostics without failing the Storybook build. For CI that should fail on error-severity diagnostics, check them in a pre-build script:

import { loadProject } from '@unpunnyfuns/swatchbook-core';
import config from './swatchbook.config.ts';

const project = await loadProject(config, process.cwd());
const errors = project.diagnostics.filter((d) => d.severity === 'error');
if (errors.length > 0) {
console.error(errors);
process.exit(1);
}

Color formatting

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.