npm package: @rnzeus/harmonia
Description: Typed colour registry + utilities for React Native / TypeScript
Latest version: 0.1.3

# @rnzeus/harmonia

Typed colour registry + utilities for React Native / TypeScript.

## Why

Design tokens tend to drift over time. You start with a clean UI kit, then designers gradually introduce random colours (different HEX / alpha variants), and your codebase ends up with a giant `misc` bucket.

This package helps you:

- keep a **typed palette** (`list`) and **typed aliases** (`aliases`) using `as const`
- use `pick()` with **autocomplete** (token names + palette hexes)
- get consistent output in RN (`#RRGGBBAA` via `.rn()`)
- choose readable text colour via `autoText()`
- safely handle “designer went wild” colours without leaking them into tokens

## Install

```bash
yarn add @rnzeus/harmonia
# or
npm i @rnzeus/harmonia
```

## Usage

Create a single instance in your app init (not inside JSX):

```ts
import { createColour } from '@rnzeus/harmonia';

export const MY_LIST = [
  '#6C00F6',
  '#865BFF',
  '#191919',
  '#FFFFFF',
  '#000000',
] as const;

export const MY_ALIASES = {
  primary: '#6C00F6',
  border: '#FFFFFF',
  text: '#191919',
} as const;

export const Colour = createColour({
  list: MY_LIST,
  aliases: MY_ALIASES,

  strict: __DEV__,
  debug: __DEV__,
  fallback: '#FF00FF',
});
```

Then anywhere:

```ts
Colour.pick('primary').rn();
Colour.pick('#865BFF').darken(0.1).rn();
Colour.mix('primary', '#FFFFFF', 0.2).rn();
Colour.contrast('text', 'primary');
```

## Configuration

`createColour()` accepts a configuration object that defines how the colour system behaves.

```ts
export const Colour = createColour({
  list: MY_LIST,
  aliases: MY_ALIASES,

  // errors
  strict: __DEV__,
  fallback: '#FF00FF',
  onError: (error, context) => {
    console.warn('[Colour]', error.message, context);
  },

  // debug (one-time init log)
  debug: __DEV__,

  // autoText defaults
  textCandidates: ['#FFFFFF', '#000000'],
  textMinContrast: 4.5,
  textPrefer: 'first-pass',
});
```

### autoText defaults

Most apps can keep the defaults, but you can customise them if needed:

```ts
export const Colour = createColour({
  list: MY_LIST,
  aliases: MY_ALIASES,

  strict: __DEV__,
  debug: __DEV__,

  // Example: prefer max contrast and allow a brand colour as candidate
  textCandidates: ['#FFFFFF', '#000000', 'primary'],
  textMinContrast: 4.5,
  textPrefer: 'max-contrast',
});
```

### autoText usage

`autoText()` helps you pick a readable text colour for a given background.

By default, it chooses between `#FFFFFF` and `#000000` using WCAG contrast (≥ 4.5).

```ts
// background can be a token or any valid hex
const text = Colour.autoText('primary').rn();
```

#### Custom candidates

You can provide your own candidates (tokens or hex values):

```ts
const text = Colour.autoText('#101010', ['text', '#FFFFFF', '#B3FF00']).rn();
```

#### Strategy & contrast threshold

```ts
const text = Colour.autoText('bg.primary', ['#FFFFFF', '#000000'], {
  prefer: 'max-contrast',
  minContrast: 4.5,
}).rn();
```

This is useful when:
- designers introduce unexpected background colours
- you want predictable readable text without adding more tokens

### Debug

If `debug: true`, it logs one compact summary on init:
- strict / fallback
- tokens list
- palette size + canonical palette (`#RRGGBBAA`)

## License

MIT