first commit
This commit is contained in:
65
docs/media/image/colours/README.md
Normal file
65
docs/media/image/colours/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# @suaveplan/colours - Universal colour manipulation: parsing, conversion, analysis, mixing, blending, and palette generation
|
||||
|
||||
Universal colour manipulation library: parsing, conversion, analysis, mixing, blending, and palette generation. Parses hex (3/4/6/8 digit), CSS `rgb()`, `hsl()`, `lab()`, `lch()`, `oklab()`, `oklch()`, named colours, and plain objects. Converts between RGB, HSL, HSV, LAB, LCH, OKLAB, OKLCH, XYZ, and CMYK. Supports manipulation (lighten, darken, saturate, desaturate, rotate, alpha, fade, opaquer, negate, grayscale, mix), analysis (luminance, perceived brightness, contrast ratio, distance), and factories (random colours, temperature-based black-body curves, blend modes, gradient steps, harmonious palettes).
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [colour](./src/colour/colour.md) — `colour.ts` implements the `Colour` class — an immutable, chainable colour value object. It wraps an internal `RGBA` st…
|
||||
- [colour-formatters](./src/colour/colour-formatters.md) — `colour-formatters.ts` provides deterministic string-formatting functions for every colour representation supported by…
|
||||
- [colour](./src/colour/colour.md) — `colour.ts` implements the `Colour` class — an immutable, chainable colour value object. It wraps an internal `RGBA` st…
|
||||
- [colour-factories](./src/colour-factories/colour-factories.md) — `colour-factories.ts` provides pure, deterministic helpers for generating colours and colour collections. It is complet…
|
||||
- [colour-factories](./src/colour-factories/colour-factories.md) — `colour-factories.ts` provides pure, deterministic helpers for generating colours and colour collections. It is complet…
|
||||
- [conversions](./src/conversions/conversions.md) — `conversions.ts` provides deterministic, side-effect-free mathematical transforms between colour spaces. Every function…
|
||||
- [conversions](./src/conversions/conversions.md) — `conversions.ts` provides deterministic, side-effect-free mathematical transforms between colour spaces. Every function…
|
||||
- [error-codes](./src/error-codes/error-codes.md) — `error-codes.ts` declares the canonical error-code registry for `@suaveplan/colours`. Every failure mode that the colou…
|
||||
- [error-codes](./src/error-codes/error-codes.md) — `error-codes.ts` declares the canonical error-code registry for `@suaveplan/colours`. Every failure mode that the colou…
|
||||
- [errors](./src/errors/errors.md) — `errors.ts` provides the typed error hierarchy for `@suaveplan/colours`. `ColourError` extends `SuaveplanError` so that…
|
||||
- [errors](./src/errors/errors.md) — `errors.ts` provides the typed error hierarchy for `@suaveplan/colours`. `ColourError` extends `SuaveplanError` so that…
|
||||
- [parser](./src/parser/parser.md) — `parser.ts` converts arbitrary colour input into a canonical `RGBA` object. It supports hex strings (3/4/6/8 digit), mo…
|
||||
- [parser](./src/parser/parser.md) — `parser.ts` converts arbitrary colour input into a canonical `RGBA` object. It supports hex strings (3/4/6/8 digit), mo…
|
||||
- [colour-types](./src/types/colour-types/colour-types.md) — `colour-types.ts` is the universal type system and Zod schema registry for `@suaveplan/colours`. It defines TypeSc…
|
||||
- [colour-types](./src/types/colour-types/colour-types.md) — `colour-types.ts` is the universal type system and Zod schema registry for `@suaveplan/colours`. It defines TypeSc…
|
||||
- [utils](./src/utils/utils.md) — `utils.ts` provides small, pure mathematical utilities used throughout `@suaveplan/colours`. Every function is determin…
|
||||
- [utils](./src/utils/utils.md) — `utils.ts` provides small, pure mathematical utilities used throughout `@suaveplan/colours`. Every function is determin…
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/colours
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```ts
|
||||
import { Colour } from "@suaveplan/colours";
|
||||
|
||||
const c = new Colour("#ff9900");
|
||||
console.log(c.lighten(0.2).toHex()); // "#ffb34d"
|
||||
console.log(c.isDark()); // false
|
||||
console.log(c.contrast("#ffffff")); // WCAG contrast ratio
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
- [`src/colour/colour.md`](./src/colour/colour.md) — `Colour` class and instance methods
|
||||
- [`src/colour/colour-formatters.md`](./src/colour/colour-formatters.md) — Output formatters (hex, rgb, hsl, etc.)
|
||||
- [`src/colour-factories/colour-factories.md`](./src/colour-factories/colour-factories.md) — Random colours, temperature, blend modes, palettes
|
||||
- [`src/conversions/conversions.md`](./src/conversions/conversions.md) — Colour-space conversion functions
|
||||
- [`src/parser/parser.md`](./src/parser/parser.md) — `parseColour` input parser
|
||||
- [`src/types/colour-types/colour-types.md`](./src/types/colour-types/colour-types.md) — TypeScript interfaces and Zod schemas
|
||||
- [`src/utils/utils.md`](./src/utils/utils.md) — Clamping and rounding utilities
|
||||
- [`src/errors/errors.md`](./src/errors/errors.md) — `ColourError` hierarchy and typed factories
|
||||
- [`src/error-codes/error-codes.md`](./src/error-codes/error-codes.md) — `COLOUR_CODES` registry
|
||||
|
||||
## Subpath Exports
|
||||
|
||||
- `@suaveplan/colours/colour` — `Colour` class
|
||||
- `@suaveplan/colours/parser` — `parseColour`
|
||||
- `@suaveplan/colours/conversions` — colour-space conversion functions
|
||||
- `@suaveplan/colours/types` — TypeScript interfaces and Zod schemas
|
||||
- `@suaveplan/colours/utils` — clamping and rounding utilities
|
||||
- `@suaveplan/colours/errors` — `ColourError` and factory functions
|
||||
- `@suaveplan/colours/error-codes` — `COLOUR_CODES` registry
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# colour-factories
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`colour-factories.ts` provides pure, deterministic helpers for generating colours and colour collections. It is completely stateless and has no side effects. All functions return either a single `Colour` instance or an array of `Colour` instances. These helpers extend the core `Colour` class with common creative and programmatic colour tasks.
|
||||
|
||||
## Features
|
||||
|
||||
- Random colour generation with optional alpha
|
||||
- Temperature-based black-body approximation (Kelvin to RGB)
|
||||
- Colour blending with standard Photoshop-style blend modes
|
||||
- Gradient step generation between two colours
|
||||
- Palette generation (analogous, monochromatic, triadic, tetradic, complementary, split-complementary)
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { randomColour, steps } from "@suaveplan/colours/colour-factories";
|
||||
|
||||
const r = randomColour();
|
||||
const gradient = steps("#ff0000", "#0000ff", 5);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { palette, fromTemperature } from "@suaveplan/colours/colour-factories";
|
||||
|
||||
const warm = fromTemperature(3200);
|
||||
const brandPalette = palette("#3b82f6", "analogous", 5);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `randomColour(alpha?: number): Colour`
|
||||
|
||||
Returns a pseudo-random colour. If `alpha` is provided it is clamped to `[0,1]`.
|
||||
|
||||
### `fromTemperature(kelvin: number): Colour`
|
||||
|
||||
Approximates a black-body colour temperature in Kelvin. Valid range is roughly `1000K` to `40000K`. Values outside this range are clamped.
|
||||
|
||||
### `blend(bottom: ColourInput, top: ColourInput, mode: BlendMode): Colour`
|
||||
|
||||
Applies a standard blend mode to two colours and returns the result. Supported modes include `normal`, `multiply`, `screen`, `overlay`, `darken`, `lighten`, `color-dodge`, `color-burn`, `difference`, `exclusion`.
|
||||
|
||||
### `steps(start: ColourInput, end: ColourInput, count: number): Colour[]`
|
||||
|
||||
Generates `count` evenly spaced colours between `start` and `end` in OKLAB space for perceptual uniformity.
|
||||
|
||||
### `palette(base: ColourInput, type: PaletteType, count?: number): Colour[]`
|
||||
|
||||
Generates a harmonious palette from a base colour. `count` defaults to `5` for most types. Types:
|
||||
|
||||
- `analogous` — colours adjacent on the colour wheel
|
||||
- `monochromatic` — same hue, varying lightness
|
||||
- `triadic` — evenly spaced three-colour harmony
|
||||
- `tetradic` — four-colour rectangular harmony
|
||||
- `complementary` — opposite hue
|
||||
- `split-complementary` — opposite hue split by a small angle
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All factory functions create new `Colour` instances via the constructor; they never mutate existing instances. The `steps` function uses OKLAB interpolation because it preserves perceptual uniformity better than RGB or HSL. Temperature approximation uses the standard black-body polynomial from Tanner Helland.
|
||||
58
docs/media/image/colours/src/colour/colour-formatters.md
Normal file
58
docs/media/image/colours/src/colour/colour-formatters.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# colour-formatters
|
||||
|
||||
## Purpose
|
||||
|
||||
`colour-formatters.ts` provides deterministic string-formatting functions for every colour representation supported by `@suaveplan/colours`. Each formatter takes a canonical `RGBA` object and returns a human-readable or machine-parseable string. The module is pure, stateless, and side-effect-free.
|
||||
|
||||
## Features
|
||||
|
||||
- Hex formatters: 6-digit, 3-digit shorthand, and 8-digit with alpha
|
||||
- CSS functional notation: `rgb()`, `rgba()`, `hsl()`, `hsla()`, `hsv()`
|
||||
- CIE and OK colour spaces: `lab()`, `lch()`, `oklab()`, `oklch()`
|
||||
- Device colour: `cmyk()`
|
||||
- Named colour lookup with fallback to hex
|
||||
- Unified `formatColour` dispatcher
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { formatHex, formatRgb } from "@suaveplan/colours/colour";
|
||||
|
||||
const rgba = { r: 255, g: 128, b: 0, a: 1 };
|
||||
console.log(formatHex(rgba)); // "#ff8000"
|
||||
console.log(formatRgb(rgba)); // "rgb(255 128 0)"
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { formatColour } from "@suaveplan/colours/colour";
|
||||
|
||||
function exportColour(rgba: RGBA, targetFormat: string) {
|
||||
return formatColour(rgba, targetFormat as any);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `formatHex(rgba: RGBA): string`
|
||||
- `formatHex3(rgba: RGBA): string | null`
|
||||
- `formatHex8(rgba: RGBA): string`
|
||||
- `formatRgb(rgba: RGBA): string`
|
||||
- `formatRgba(rgba: RGBA): string`
|
||||
- `formatHsl(rgba: RGBA): string`
|
||||
- `formatHsla(rgba: RGBA): string`
|
||||
- `formatHsv(rgba: RGBA): string`
|
||||
- `formatLab(rgba: RGBA): string`
|
||||
- `formatLch(rgba: RGBA): string`
|
||||
- `formatOklab(rgba: RGBA): string`
|
||||
- `formatOklch(rgba: RGBA): string`
|
||||
- `formatCmyk(rgba: RGBA): string`
|
||||
- `formatNamed(rgba: RGBA): string`
|
||||
- `formatColour(rgba: RGBA, format?: string): string`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All formatters use fixed-precision rounding appropriate to their colour space. Hex formatters pad single-digit components with leading zeros. The `formatHex3` formatter returns `null` when the colour cannot be exactly represented in three-digit shorthand. `formatNamed` iterates the `NAMED_COLOURS` map and falls back to `formatHex` for unknown colours.
|
||||
|
||||
Formatters are grouped together so that the `Colour` class can delegate all string output to a single module. This keeps the class focused on manipulation logic while the formatters handle presentation details.
|
||||
88
docs/media/image/colours/src/colour/colour.md
Normal file
88
docs/media/image/colours/src/colour/colour.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# colour
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`colour.ts` implements the `Colour` class — an immutable, chainable colour value object. It wraps an internal `RGBA` state and exposes methods for manipulation, analysis, conversion, and output formatting. The class is the primary public API surface for the package and is used by the `colour-factories` helpers.
|
||||
|
||||
## Features
|
||||
|
||||
- Immutable chainable manipulation (lighten, darken, saturate, desaturate, rotate, alpha, fade, opaquer)
|
||||
- Colour-space conversion methods (hex, RGB, HSL, HSV, LAB, LCH, OKLAB, OKLCH, CMYK)
|
||||
- Analysis methods (luminance, perceived brightness, contrast ratio, isDark, isLight, best contrast, distance)
|
||||
- Utility methods (negate, grayscale, mix, clone, equals, toString)
|
||||
- Pure functional implementation with no mutation of internal state
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { Colour } from "@suaveplan/colours/colour";
|
||||
|
||||
const c = new Colour("#ff9900");
|
||||
console.log(c.lighten(0.2).toHex()); // "#ffb34d"
|
||||
console.log(c.isDark()); // false
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { Colour } from "@suaveplan/colours/colour";
|
||||
|
||||
const brand = new Colour("#3b82f6");
|
||||
const text = brand.bestContrast("#ffffff", "#1f2937");
|
||||
console.log(text.toHex()); // "#ffffff"
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Constructor
|
||||
|
||||
- `new Colour(input: ColourInput)` — parses any supported colour input into an immutable `Colour` instance.
|
||||
|
||||
### Manipulation
|
||||
|
||||
- `lighten(amount: number): Colour`
|
||||
- `darken(amount: number): Colour`
|
||||
- `saturate(amount: number): Colour`
|
||||
- `desaturate(amount: number): Colour`
|
||||
- `rotate(degrees: number): Colour`
|
||||
- `alpha(a: number): Colour`
|
||||
- `fade(amount: number): Colour`
|
||||
- `opaquer(amount: number): Colour`
|
||||
- `negate(): Colour`
|
||||
- `grayscale(): Colour`
|
||||
- `mix(other: ColourInput, amount?: number): Colour`
|
||||
|
||||
### Analysis
|
||||
|
||||
- `luminance(): number`
|
||||
- `perceivedBrightness(): number`
|
||||
- `contrast(other: ColourInput): number`
|
||||
- `isDark(): boolean`
|
||||
- `isLight(): boolean`
|
||||
- `bestContrast(...candidates: (Colour | string)[]): Colour`
|
||||
- `distance(other: ColourInput, mode?: DistanceMode): number`
|
||||
- `equals(other: ColourInput): boolean`
|
||||
|
||||
### Output
|
||||
|
||||
- `toHex(): string`
|
||||
- `toHex3(): string`
|
||||
- `toHex8(): string`
|
||||
- `toRgb(): RGB`
|
||||
- `toRgba(): RGBA`
|
||||
- `toHsl(): HSL`
|
||||
- `toHsv(): HSV`
|
||||
- `toLab(): LAB`
|
||||
- `toLch(): LCH`
|
||||
- `toOklab(): OKLAB`
|
||||
- `toOklch(): OKLCH`
|
||||
- `toCmyk(): CMYK`
|
||||
- `toString(): string`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The internal `_rgba` state is never mutated. Every chainable method returns a new `Colour` instance. Conversion methods delegate to the `conversions` module. Analysis methods use the standard WCAG 2.1 luminance formula and sRGB gamma. The `bestContrast` helper uses the APCA-like perceived brightness for candidate ranking.
|
||||
76
docs/media/image/colours/src/conversions/conversions.md
Normal file
76
docs/media/image/colours/src/conversions/conversions.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# conversions
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`conversions.ts` provides deterministic, side-effect-free mathematical transforms between colour spaces. Every function takes a tuple of numbers and returns a tuple of numbers. No object mutation, no I/O, no dependency on any other package logic except basic math. These functions form the numerical foundation for the `Colour` class.
|
||||
|
||||
## Features
|
||||
|
||||
- RGB to HSL/HSLA and back
|
||||
- RGB to HSV and back
|
||||
- RGB to XYZ and back
|
||||
- XYZ to LAB/LCH and back
|
||||
- RGB to OKLAB/OKLCH and back
|
||||
- RGB to CMYK
|
||||
- Alpha passthrough on every conversion
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { rgbToHsl, hslToRgb } from "@suaveplan/colours/conversions";
|
||||
|
||||
const hsl = rgbToHsl({ r: 255, g: 128, b: 0 });
|
||||
const back = hslToRgb(hsl);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { colourSteps } from "@suaveplan/colours/colour-factories";
|
||||
|
||||
const gradient = colourSteps("#ff0000", "#0000ff", 5);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### RGB ↔ HSL
|
||||
|
||||
- `rgbToHsl(rgb: RGB): HSL`
|
||||
- `hslToRgb(hsl: HSL): RGBA`
|
||||
|
||||
### RGB ↔ HSV
|
||||
|
||||
- `rgbToHsv(rgb: RGB): HSV`
|
||||
- `hsvToRgb(hsv: HSV, alpha?: number): RGBA`
|
||||
|
||||
### RGB ↔ XYZ
|
||||
|
||||
- `rgbToXyz(rgb: RGB): XYZ`
|
||||
- `xyzToRgb(xyz: XYZ, alpha?: number): RGBA`
|
||||
|
||||
### XYZ ↔ LAB/LCH
|
||||
|
||||
- `xyzToLab(xyz: XYZ): LAB`
|
||||
- `labToXyz(lab: LAB): XYZ`
|
||||
- `labToLch(lab: LAB): LCH`
|
||||
- `lchToLab(lch: LCH): LAB`
|
||||
|
||||
### RGB ↔ OKLAB/OKLCH
|
||||
|
||||
- `rgbToOklab(rgb: RGB): OKLAB`
|
||||
- `oklabToRgb(oklab: OKLAB, alpha?: number): RGBA`
|
||||
- `oklabToOklch(oklab: OKLAB): OKLCH`
|
||||
- `oklchToRgb(oklch: OKLCH): RGBA`
|
||||
|
||||
### RGB ↔ CMYK
|
||||
|
||||
- `rgbToCmyk(rgb: RGB): CMYK`
|
||||
- `cmykToRgb(cmyk: CMYK): RGBA`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All transforms use double-precision arithmetic and standard colour-science matrices. RGB values are normalised to `[0,1]` before matrix multiplication and clamped back to `[0,255]` afterwards. OKLAB uses the Bradley coefficients. CMYK uses the simple 100% minus RGB ratio formula. Alpha is never modified by colour-space conversion.
|
||||
61
docs/media/image/colours/src/error-codes/error-codes.md
Normal file
61
docs/media/image/colours/src/error-codes/error-codes.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`error-codes.ts` declares the canonical error-code registry for `@suaveplan/colours`. Every failure mode that the colour package can surface — from invalid hex strings to unsupported CSS colour formats — is assigned a stable, namespaced string via `defineCodes` from `@suaveplan/error`. This gives downstream log analysers, retry policies, and problem+json renderers a deterministic contract they can match against without parsing human-readable messages.
|
||||
|
||||
## Features
|
||||
|
||||
- Three stable codes under the `COLOUR.*` namespace
|
||||
- Type-safe `ColourCode` union derived from the registry object
|
||||
- Zero runtime side effects — the registry is a plain constant
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { COLOUR_CODES } from "@suaveplan/colours/error-codes";
|
||||
|
||||
function handleColourError(err: { code: string }) {
|
||||
if (err.code === COLOUR_CODES.INVALID_INPUT) {
|
||||
return { status: 400, message: "Invalid colour" };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { COLOUR_CODES, type ColourCode } from "@suaveplan/colours/error-codes";
|
||||
|
||||
const retryableCodes: ColourCode[] = [
|
||||
COLOUR_CODES.CONVERSION_FAILED,
|
||||
];
|
||||
|
||||
function shouldRetry(code: ColourCode): boolean {
|
||||
return retryableCodes.includes(code);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `COLOUR_CODES`
|
||||
|
||||
A frozen object mapping human-readable keys to namespaced string values:
|
||||
|
||||
- `INVALID_INPUT` → `"COLOUR.INVALID_INPUT"`
|
||||
- `UNSUPPORTED_FORMAT` → `"COLOUR.UNSUPPORTED_FORMAT"`
|
||||
- `CONVERSION_FAILED` → `"COLOUR.CONVERSION_FAILED"`
|
||||
|
||||
### `ColourCode`
|
||||
|
||||
A TypeScript union of all three code string literals. Useful for function parameters and discriminated unions.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The registry is produced by `defineCodes("COLOUR", [...])`. If the namespace or code list ever changes, every test that asserts against `COLOUR_CODES.*` will fail, which is the desired behaviour — it prevents silent drift in the error contract.
|
||||
|
||||
Error codes are intentionally coarse-grained. They group related failure modes under a single code so that retry policies and alerting rules do not need to track an ever-expanding list of micro-codes. When more detail is required, the factory functions attach a context object with the raw input or format string.
|
||||
65
docs/media/image/colours/src/errors/errors.md
Normal file
65
docs/media/image/colours/src/errors/errors.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# errors
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`errors.ts` provides the typed error hierarchy for `@suaveplan/colours`. `ColourError` extends `SuaveplanError` so that callers receive structured failures with a stable code, a message key, an optional context object, and an optional cause chain. Typed factory functions make it easy to construct correctly-coded errors without hand-typing string literals.
|
||||
|
||||
## Features
|
||||
|
||||
- `ColourError` class with `code`, `message`, `context`, and `cause`
|
||||
- Factory functions for every failure mode
|
||||
- Context carries `input` and `format` for debugging
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { colourInvalid } from "@suaveplan/colours/errors";
|
||||
|
||||
function parseUserColour(input: string) {
|
||||
if (input.length === 0) {
|
||||
throw colourInvalid(input);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ColourError, COLOUR_CODES } from "@suaveplan/colours/errors";
|
||||
|
||||
function enrichError(err: unknown): ColourError {
|
||||
if (err instanceof ColourError) return err;
|
||||
return new ColourError(
|
||||
COLOUR_CODES.CONVERSION_FAILED,
|
||||
"Unexpected failure",
|
||||
{ cause: err instanceof Error ? err : undefined }
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `ColourError`
|
||||
|
||||
Extends `SuaveplanError<ColourCode>`.
|
||||
|
||||
- `constructor(code, messageKey, options?)` — `options` may include `cause` and `context`.
|
||||
- `context?: ColourErrorContext` — carries `input` and `format`.
|
||||
|
||||
### Factory Functions
|
||||
|
||||
- `colourInvalid(input?)`
|
||||
- `colourUnsupportedFormat(format)`
|
||||
- `colourConversionFailed(message)`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All factories are thin wrappers — they do not duplicate logic. The `ColourErrorContext` interface extends `Record<string, unknown>` so callers can safely add custom fields without losing type safety.
|
||||
|
||||
Every factory accepts an optional input or format value and embeds it in the error context. This makes debugging straightforward because the thrown error carries the exact value that caused the failure. Callers should never construct `ColourError` manually; always use the exported factories to guarantee the correct code and context shape.
|
||||
|
||||
The error hierarchy follows the suaveplan standard of extending `SuaveplanError` so that all packages in the project throw errors with a consistent shape. This allows top-level error handlers to treat colour errors the same way they treat network, validation, or auth errors.
|
||||
51
docs/media/image/colours/src/parser/parser.md
Normal file
51
docs/media/image/colours/src/parser/parser.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# parser
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`parser.ts` converts arbitrary colour input into a canonical `RGBA` object. It supports hex strings (3/4/6/8 digit), modern and legacy CSS `rgb()` and `hsl()` syntax, CSS Color Module Level 4/5 `lab()`, `lch()`, `oklab()`, and `oklch()` syntax, named CSS colours, and plain JavaScript objects in every supported colour space. The parser is pure and side-effect-free.
|
||||
|
||||
## Features
|
||||
|
||||
- Hex parsing with optional `#` prefix
|
||||
- Modern space-separated and legacy comma-separated CSS syntax
|
||||
- Named colour lookup via `NAMED_COLOURS`
|
||||
- Object dispatch for RGB, HSL, HSV, LAB, OKLAB, and CMYK objects
|
||||
- Strict validation with typed `ColourError` throws
|
||||
- Safe parsing via `tryParseColour` with configurable fallback
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { parseColour } from "@suaveplan/colours/parser";
|
||||
|
||||
const rgba = parseColour("#ff9900");
|
||||
console.log(rgba); // { r: 255, g: 153, b: 0, a: 1 }
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { tryParseColour } from "@suaveplan/colours/parser";
|
||||
|
||||
const safe = tryParseColour(userInput, { r: 255, g: 255, b: 255, a: 1 });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `parseColour(input: ColourInput): RGBA`
|
||||
|
||||
Returns a canonical `RGBA` object. Throws `ColourError` with code `COLOUR.INVALID_INPUT` or `COLOUR.UNSUPPORTED_FORMAT` on failure.
|
||||
|
||||
### `tryParseColour(input: ColourInput, fallback?: RGBA): RGBA`
|
||||
|
||||
Returns the parsed `RGBA` object, or `fallback` if parsing fails. The default fallback is black with full opacity (`{ r: 0, g: 0, b: 0, a: 1 }`).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Regex patterns are compiled once at module load and reused for every parse call. Object parsing uses property detection (e.g. `'r' in obj`) rather than `instanceof` to avoid cross-realm issues. Alpha values in hex8 are normalised with `roundAlpha` to three decimal places.
|
||||
|
||||
The parser is designed to be strict rather than permissive. It does not attempt to guess intent when input is ambiguous; instead it throws a typed `ColourError` immediately. This fail-fast behaviour makes debugging easier for callers and prevents subtle colour drift caused by silently accepted malformed input. The `tryParseColour` variant provides a convenient escape hatch for callers who need graceful degradation rather than exceptions.
|
||||
@@ -0,0 +1,61 @@
|
||||
# colour-types
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`colour-types.ts` is the universal type system and Zod schema registry for `@suaveplan/colours`. It defines TypeScript interfaces for every colour space supported by the library, validates object inputs via Zod, and provides a lookup table of named CSS colours. Everything in this module is deterministic and side-effect free.
|
||||
|
||||
## Features
|
||||
|
||||
- TypeScript interfaces for RGB, RGBA, HSL, HSLA, HSV, LAB, LCH, OKLAB, OKLCH, CMYK
|
||||
- Zod schemas for runtime validation of each colour-space object
|
||||
- Named colour map with 19 CSS named colours plus transparent
|
||||
- Union types for `ColourInput`, `MixMode`, `DistanceMode`, `BlendMode`, and `PaletteType`
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { RgbSchema, NAMED_COLOURS } from "@suaveplan/colours/types";
|
||||
|
||||
const rgb = RgbSchema.parse({ r: 255, g: 128, b: 0 });
|
||||
const red = NAMED_COLOURS.get("red");
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { LabSchema, type LAB } from "@suaveplan/colours/types";
|
||||
|
||||
function processLab(input: unknown): LAB {
|
||||
return LabSchema.parse(input);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Zod Schemas
|
||||
|
||||
- `RgbSchema`, `RgbaSchema`
|
||||
- `HslSchema`, `HslaSchema`
|
||||
- `HsvSchema`
|
||||
- `LabSchema`, `LchSchema`
|
||||
- `OklabSchema`, `OklchSchema`
|
||||
- `CmykSchema`
|
||||
|
||||
### Types
|
||||
|
||||
- `RGB`, `RGBA`, `HSL`, `HSLA`, `HSV`, `LAB`, `LCH`, `OKLAB`, `OKLCH`, `CMYK`
|
||||
- `ColourInput`, `MixMode`, `DistanceMode`, `BlendMode`, `PaletteType`
|
||||
|
||||
### Constants
|
||||
|
||||
- `NAMED_COLOURS` — `ReadonlyMap<string, RGBA>`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The Zod schemas use `.int()` and `.min().max()` bounds to match CSS channel constraints. `NAMED_COLOURS` is a native `Map` wrapped in `ReadonlyMap` to prevent accidental mutation while preserving `O(1)` lookups.
|
||||
|
||||
Type definitions are kept as simple readonly interfaces so they can be used in both runtime Zod validation and compile-time TypeScript checks without duplication. The union types for modes and palettes are derived from const arrays, which means adding a new mode updates both the type and any Zod schema that references it automatically.
|
||||
56
docs/media/image/colours/src/utils/utils.md
Normal file
56
docs/media/image/colours/src/utils/utils.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# utils
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`utils.ts` provides small, pure mathematical utilities used throughout `@suaveplan/colours`. Every function is deterministic and side-effect-free, making the module safe to import in any JavaScript runtime. These helpers enforce the numeric invariants that keep colour channels, percentages, and alpha values within their valid ranges.
|
||||
|
||||
## Features
|
||||
|
||||
- `clamp` — restricts a number to a closed interval
|
||||
- `isFiniteNumber` — type guard rejecting `NaN` and `Infinity`
|
||||
- `roundChannel` — clamps and rounds to `[0, 255]`
|
||||
- `roundPercent` — clamps and rounds to `[0, 100]`
|
||||
- `roundAlpha` — clamps and rounds to three decimal places in `[0, 1]`
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { clamp, roundChannel } from "@suaveplan/colours/utils";
|
||||
|
||||
const value = clamp(300, 0, 255);
|
||||
console.log(value); // 255
|
||||
|
||||
const channel = roundChannel(128.6);
|
||||
console.log(channel); // 129
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { isFiniteNumber, roundAlpha } from "@suaveplan/colours/utils";
|
||||
|
||||
function safeAlpha(input: unknown): number {
|
||||
if (!isFiniteNumber(input)) return 1;
|
||||
return roundAlpha(input);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `clamp(val, min, max): number`
|
||||
- `isFiniteNumber(v): v is number`
|
||||
- `roundChannel(v): number`
|
||||
- `roundPercent(v): number`
|
||||
- `roundAlpha(v): number`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`roundAlpha` uses `Math.round(v * 1000) / 1000` to cap precision at three decimal places. This matches the CSS `opacity` resolution and prevents floating-point drift in serialised output.
|
||||
|
||||
All utilities are implemented as standalone functions with no shared state. They can be imported individually for tree-shaking or used together as a consistent numeric toolkit. Because every helper is pure, they are safe to call inside hot loops such as pixel shaders or animation frames without risk of side effects.
|
||||
|
||||
The clamp function uses simple comparison operators rather than Math.min and Math.max for slightly better performance in tight loops. The isFiniteNumber guard explicitly rejects NaN and Infinity, which is stricter than a plain typeof check and prevents invalid values from propagating through conversion chains.
|
||||
Reference in New Issue
Block a user