/** * CSS colour parsing, formatting and contrast — the one place Photon Grid turns * whatever a column stores into numbers it can reason about. * * A colour arrives from an API as any of the forms CSS accepts: `#f00`, * `#ff0000`, `#ff0000cc`, `rgb(255 0 0)`, `rgba(255, 0, 0, .5)`, * `hsl(0deg 100% 50%)`, or the keyword `red`. Every one of those is the same * colour, and a grid that only understood one of them would render the rest as * empty cells. This module reduces all of them to a single {@link ParsedColor} * so the cell renderer, the editor and any application code agree on what a * value means. * * ### Why parse at all, rather than hand the text to CSS * CSS *would* accept most of these directly — but silently. Assigning an * unrecognised value to a custom property leaves the previous value in place, so * a typo would paint the row above's colour rather than showing an error, and a * value the browser rejects paints nothing at all. Parsing first means an * unparseable value is a fact the renderer can act on (show the raw text, show a * fallback) instead of a blank square. It is also what lets the editor seed a * native ``, which accepts `#rrggbb` and nothing else. * * ### Performance * Results are memoised per distinct input string. A colour column typically * holds a few dozen distinct values across hundreds of thousands of rows, so * scrolling it costs one parse per distinct value for the lifetime of the page * rather than one per rendered cell. Every returned object is frozen and shared, * so repeat reads allocate nothing at all. * * @packageDocumentation */ /** * The notation a colour value was written in. * * Preserved through parsing so a value can be written back the way it arrived — * see {@link formatColor} and the colour editor's `outputFormat`. A column fed * `hsl()` values by its API should not quietly become a column of hex codes the * first time somebody edits a row. */ export type ColorNotation = /** `#rgb`, `#rgba`, `#rrggbb` or `#rrggbbaa`. */ 'hex' /** `rgb()` or `rgba()`, in either the legacy comma or the modern space syntax. */ | 'rgb' /** `hsl()` or `hsla()`, in either syntax. */ | 'hsl' /** A CSS colour keyword — `red`, `rebeccapurple`. */ | 'name' /** The `transparent` keyword. */ | 'transparent'; /** * A colour, resolved to numbers. * * Frozen and shared out of the parse cache, so it must be treated as immutable — * two cells holding `"red"` receive the very same object. */ export interface ParsedColor { /** Red channel, an integer in `[0, 255]`. */ readonly r: number; /** Green channel, an integer in `[0, 255]`. */ readonly g: number; /** Blue channel, an integer in `[0, 255]`. */ readonly b: number; /** Alpha in `[0, 1]`, rounded to three decimal places. `1` when the source carried none. */ readonly a: number; /** How the source value was written. */ readonly notation: ColorNotation; /** The original text, trimmed. What a `'value'` display format shows. */ readonly source: string; /** * The opaque colour as `#rrggbb`. * * Alpha is **not** encoded here: this is the form `` * requires, and that control has no alpha channel. Use {@link a} or * {@link css} when transparency matters. */ readonly hex: string; /** * A CSS value safe to paint with, alpha included. * * `#rrggbb` for an opaque colour and `rgba(…)` for a translucent one — the two * shortest forms every engine understands. */ readonly css: string; } /** Test seam — drops the memo so cache behaviour can be asserted directly. */ export declare function clearColorParseCache(): void; /** * Parses any CSS colour this grid understands. * * Accepts, in the order they are tried: hex (3, 4, 6 or 8 digits), `rgb()` / * `rgba()`, `hsl()` / `hsla()`, the `transparent` keyword, and the CSS colour * keywords. Leading and trailing whitespace is ignored and matching is * case-insensitive throughout, because real data is not tidy. * * Values are looked up in a memo first, so a column of a million rows drawn from * twenty distinct colours performs twenty parses in total. * * ### What is deliberately not supported * The wide-gamut and perceptual functions — `color()`, `lab()`, `lch()`, * `oklab()`, `oklch()`, `color-mix()` — and `currentColor`. Each needs either a * colour-space conversion the grid has no other use for or a live DOM to resolve * against, and a column storing them is vanishingly rare next to the five forms * above. They parse as `null`, which the `color` renderer surfaces as the raw * text rather than an empty cell. * * @param value - Anything a cell might hold. Non-strings are stringified, so a * `String` object or a value object with a sensible `toString` works; `null`, * `undefined` and blank text are misses. * @returns The parsed colour — frozen and shared, never mutate it — or `null` * when the value is not a colour this module recognises. * * @example * ```ts * parseColor('#f00')?.hex; // '#ff0000' * parseColor('rgb(255 0 0 / 50%)')?.a; // 0.5 * parseColor('hsl(120, 100%, 25%)')?.hex; // '#008000' * parseColor('rebeccapurple')?.hex; // '#663399' * parseColor('not a colour'); // null * ``` */ export declare function parseColor(value: unknown): ParsedColor | null; /** `true` when `value` is a colour {@link parseColor} understands. */ export declare function isColor(value: unknown): boolean; /** * Writes a parsed colour back out in a chosen notation. * * The counterpart to {@link parseColor}, and what lets an edit preserve the form * a column's data is stored in instead of rewriting every row as hex. * * @param color - A parsed colour. * @param notation - The form to produce. `'name'` falls back to hex when the * colour has no CSS keyword, since most colours do not. `'transparent'` is * accepted for symmetry and produces the keyword only for a fully transparent * colour, hex otherwise. * @returns CSS text. Alpha is included whenever it is below `1`, which upgrades * `'hex'` to eight digits and `'rgb'`/`'hsl'` to their `a` forms — dropping it * would silently make a translucent colour opaque. * * @example * ```ts * const red = parseColor('#ff0000')!; * formatColor(red, 'rgb'); // 'rgb(255, 0, 0)' * formatColor(red, 'hsl'); // 'hsl(0, 100%, 50%)' * formatColor(red, 'name'); // 'red' * ``` */ export declare function formatColor(color: ParsedColor, notation: ColorNotation): string; /** * The colour as hue, saturation and lightness — degrees and whole percentages, * the units `hsl()` is written in. * * Rounded rather than exact: this feeds display text and `hsl()` output, where * fractional percentages are noise, and rounding here keeps * `formatColor(…, 'hsl')` free of eleven-decimal values. */ export declare function toHsl(color: ParsedColor): { h: number; s: number; l: number; }; /** * WCAG relative luminance, `0` (black) to `1` (white). * * The gamma-corrected definition rather than a naive weighted average of the * raw channels: the difference decides whether text on a mid-tone swatch is * legible, which is the only reason this function exists. * * Alpha is ignored — a translucent colour's apparent luminance depends on what * is behind it, which is {@link contrastColor}'s job to know. */ export declare function relativeLuminance(color: ParsedColor): number; /** * Black or white, whichever stays readable on top of `color`. * * What the `color` renderer's filled variant uses to keep its label legible on * every swatch from `lemonchiffon` to `midnightblue`, without the author * choosing a text colour per row. * * A translucent colour is composited over `backdrop` first, because a 10%-alpha * red is very nearly the surface behind it and asking for white text on that * would be wrong. * * @param color - The background colour. * @param backdrop - What shows through a translucent `color`. Defaults to white, * the light theme's cell surface; pass the real surface colour in a dark theme. * @returns `'#000000'` or `'#ffffff'`. */ export declare function contrastColor(color: ParsedColor, backdrop?: ParsedColor): string; /** * Composites a translucent colour over an opaque one — the `source-over` * operation a browser performs when painting. * * @returns The visible result, always opaque when `backdrop` is. */ export declare function composite(color: ParsedColor, backdrop: ParsedColor): ParsedColor; //# sourceMappingURL=color-parser.d.ts.map