# Native

Select one precompiled native style per variant combination, and compose native style props.

Native compilation rewrites a definition whose styles fit one table into a `Native.create` call. Applications normally do not import it. The table holds one frozen style object per combination of choices, so applying the callable is a lookup.

```ts title="badge.ts"
import { Native } from 'zyzz/runtime'

// Keys 0 and 1 select small and large, and 2 a cleared size
const badge = Native.create({
  axes: { size: ['small', 'large'] },
  defaults: { size: 'small' },
  styles: { 0: { padding: 4 }, 1: { padding: 8 }, 2: {} },
})

// { style: { padding: 8 } }
export const props = badge({ size: 'large' })
```

## Native.create

```ts
// Generated table for one set and scheme
Native.create(options)
```

### options.axes

* **Type:** `{ [axis: string]: readonly string[] }`

Each axis and its choices, in authored order. Boolean choices appear as `'true'` and `'false'` and accept `true` and `false`.

```ts
// A definition without variants has one entry, at key 0
Native.create({ axes: {}, defaults: {}, styles: { 0: { padding: 8 } } })
```

### options.defaults

* **Type:** `{ [axis: string]: string | null }`

The choice used when an axis is omitted or `undefined`. `null` and axes without a default select the cleared entry.

```ts
// An omitted size selects small
Native.create({
  axes: { size: ['small', 'large'] },
  defaults: { size: 'small' },
  styles,
})
```

### options.styles

* **Type:** `{ [index: string]: StyleSheet.NativeStyle }`

One style per combination, frozen at creation. The key is a mixed-radix number with the first axis as its lowest digit. Each axis contributes its choice index, or its choice count when cleared, in base choice count plus one.

```ts
// With two choices, index 2 is the cleared size
const styles = { 0: { padding: 4 }, 1: { padding: 8 }, 2: {} }
```

### input\[axis]

* **Type:** `string | boolean | null | undefined`
* **Default:** `options.defaults[axis]`

The selected choice. `null` clears the axis, overriding its default.

```ts
// { style: {} }
badge({ size: null })
```

### input.style

* **Type:** `StyleSheet.StyleProp<overrides>`
* **Default:** `undefined`

Native overrides placed after the selected style. Their identity and type are kept, including `Animated` values and platform colors, and the helper never freezes or copies them.

A falsy override, such as `false` or `null`, is dropped, so the result is the selected style alone.

```ts
// { style: [{ padding: 4 }, { opacity: 0.5 }] }
badge({ style: { opacity: 0.5 } })
```

### props

* **Type:** `Native.Props<style>`

`{ style }`, with the selected style alone or followed by the override. A definition without axes returns the same frozen object for every call without input.

```ts
// { padding: 8 }
props.style
```

### style

* **Type:** `StyleSheet.StyleProp<style>`

The frozen selected style, or a new `[selected, override]` array when `input.style` is truthy.

```ts
// [{ padding: 4 }, { opacity: 0.5 }]
badge({ style: { opacity: 0.5 } }).style
```

## Native.compose

```ts
// Applied native props in order
Native.compose(...entries)
```

### entries

* **Type:** `readonly (Native.Props<object> | false | null | undefined)[]`

Applied props, or falsy values that are skipped. Each entry must have only a `style` key.

```ts
// A false entry drops out
Native.compose(badge(), active && badge({ size: 'large' }))
```

### props

* **Type:** `Native.Props<style>`

`{ style }` holding the entries' styles in order, for React Native's later-wins merging. A single entry keeps its style reference, and nested arrays stay as they are.

```ts
// { style: [{ padding: 4 }, { padding: 8 }] }
Native.compose(badge(), badge({ size: 'large' }))
```

### style

* **Type:** `StyleSheet.StyleProp<style>`

A new array of the entries' styles in order, or the single entry's own style when one entry remains.

```ts
// The same object as badge().style
Native.compose(badge(), false).style
```

## Types

* **`Native.Callable<axes, style>`:** A table callable with inferred choices and native overrides.
* **`Native.create.Options<axes, styles>`:** The `{ axes, defaults, styles }` input.
* **`Native.Props<style>`:** The returned `{ style }`.

```ts title="emphasize.ts"
import { Native } from 'zyzz/runtime'

// Accepts props from any compiled native definition
export function emphasize(props: Native.Props): Native.Props {
  return Native.compose(props, { style: { fontWeight: '600' } })
}
```

## Errors

### Native.SelectionError

Thrown for an unknown input key or choice, a missing table entry, or a `compose` entry that is not native style props.

```ts title="invalid.ts"
import { Native } from 'zyzz/runtime'

const badge = Native.create({
  axes: { size: ['small'] },
  defaults: {},
  styles: { 0: {}, 1: {} },
})

try {
  // `huge` is not a declared choice
  badge({ size: 'huge' } as never)
} catch (error) {
  if (error instanceof Native.SelectionError) console.error(error.message)
}
```
