/**
* 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