# Native

Compile shared style authoring into native callables, fixed or contextual per scheme.

`Native.compile` rewrites a module's `style`, `variants`, and `cx` authoring into callables that return React Native `style` props, and `useVars` arguments into token profiles. Static tokens and units resolve at compile time, while dynamic values convert their units on each call. Babel and `Graph.compile` call it per module.

```ts title="native.ts"
import { Native } from 'zyzz/compiler'

// Rewrites the module for iOS in the light scheme
const output = Native.compile({
  colorScheme: 'light',
  moduleId: 'app/Button.tsx',
  platform: 'ios',
  source: `import { variants } from 'zyzz'

export const button = variants({
  base: { paddingTop: '8px' },
  variants: { tone: { quiet: { opacity: 0.5 }, loud: { opacity: 1 } } },
  defaultVariants: { tone: 'quiet' },
})
`,
})
```

## Signature

```ts
// Native callables for one module and color scheme
Native.compile(options)
```

## Parameters

### options.colorScheme

* **Type:** `'light' | 'dark'`

The color scheme compiled into the callables in `code`. Their color pairs resolve to this scheme's value unless `contextual` keeps both, while `recipes` always holds both schemes.

```ts
// Resolves { light: '#171717', dark: '#fafafa' } to '#fafafa'
Native.compile({ colorScheme: 'dark', moduleId: 'app/Label.tsx', source })
```

### options.moduleId

* **Type:** `string`

A stable module identity, including its extension. A `.ts` or `.tsx` ID emits typed TypeScript, and dynamic styles require it to read their typed values.

```ts Label.tsx'/
// Emits TypeScript with the callables' finite choice types
Native.compile({ colorScheme: 'light', moduleId: 'app/Label.tsx', source })
```

### options.source

* **Type:** `string`

The complete module text, parsed as TypeScript with JSX. Stylesheet contributions, `variable` declarations, `vars` selections, and theme `.className` reads fail native compilation, as do `appearance` and `script` reads without `contextual`.

```ts
// The text is parsed, never executed
Native.compile({
  colorScheme: 'light',
  moduleId: 'app/Label.tsx',
  source: text,
})
```

### options.platform

* **Type:** `'ios' | 'android'`
* **Default:** `undefined`

The platform whose `targets` branches apply. It is required when any style has platform branches.

```ts
// Applies targets.android branches
Native.compile({
  colorScheme: 'light',
  moduleId: 'app/Label.tsx',
  platform: 'android',
  source,
})
```

### options.units

* **Type:** `{ px?: number; rem?: number }`
* **Default:** `{ px: 1 }`

Scales from CSS lengths to native logical units. `px` defaults to one. `rem` has no default, so rem lengths fail without it.

```ts
// Compiles padding: '1rem' to 16
Native.compile({
  colorScheme: 'light',
  moduleId: 'app/Label.tsx',
  source,
  units: { rem: 16 },
})
```

### options.fonts

* **Type:** `Readonly<Record<string, string>>`
* **Default:** `undefined`

Native font family names, keyed by the exact authored `fontFamily` text. Every authored family needs an entry.

```ts
// Compiles fontFamily: 'Geist' to 'Geist-Regular'
Native.compile({
  colorScheme: 'light',
  fonts: { Geist: 'Geist-Regular' },
  moduleId: 'app/Label.tsx',
  source,
})
```

### options.vars

* **Type:** `Native.compile.Options['vars']`
* **Default:** `undefined`

Named variable sets or extracted config scopes, such as [`Source.extract`](/docs/api/compiler/namespaces/Source#vars) `vars`, that label the compiled tables in `recipes`. Without it, the tables use one `default` label, unless `contextual` keeps a local config's named sets as labels. Tokens from a local config keep the values that config defines.

```ts
// recipes tables gain `base` and `brand` labels
Native.compile({
  colorScheme: 'light',
  moduleId: 'app/Label.tsx',
  source,
  vars: { base, brand },
})
```

### options.set

* **Type:** `string`
* **Default:** `'default'`

The `vars` label compiled into the callables. An unknown label throws `StyleSheet.SelectionError`, except with `contextual`, where it becomes the render-time default unless a local config sets `defaultVars`. It then fails only when a Provider supplies no set of its own.

```ts
// Selects the `brand` table
Native.compile({
  colorScheme: 'light',
  moduleId: 'app/Label.tsx',
  set: 'brand',
  source,
  vars: { base, brand },
})
```

### options.contextual

* **Type:** `boolean`
* **Default:** `false`

Keeps every set and scheme in the output, so callables select one at render time from the nearest [`Provider`](/docs/guides/native/themes). It is also required for `@media` queries, which otherwise throw `StyleSheet.CompileError`. Without it, `colorScheme` and `set` are fixed at compile time.

```ts
// Retains the light and dark tables for render-time selection
Native.compile({
  colorScheme: 'light',
  contextual: true,
  moduleId: 'app/Label.tsx',
  source,
})
```

## Returns

### code

* **Type:** `string`

The rewritten module, with its exports intact. Each definition becomes a call to a `zyzz/runtime` native helper with its precompiled fragments, typed with its finite choices in TypeScript output.

```ts
// export const button = __zyzzNativeStatic.create({ axes: { tone: ['quiet', 'loud'] }, … })
output.code
```

### map

* **Type:** `string`

A version 3 source map from `code` to the original source, encoded as JSON and including the source content.

```ts
// Already JSON, so it is written as is
await Fs.writeFile('Button.js.map', output.map)
```

### recipes

* **Type:** `Readonly<Record<string, Variants.Definition>>`

Tables for each static `style` definition, keyed by definition name, with every set and scheme. Definitions with variants, dynamic values, or contextual media queries keep their data in `code` and have no entry here.

```ts
// { 'style-…': { styles: { default: { light: …, dark: … } }, … } }
output.recipes
```

## Callables

A compiled `style` or `variants` callable returns `{ style }` for a native component. Omitted choices use their defaults, and `null` suppresses a default. A `style` override is appended after the compiled style, and dynamic values bind from typed callback payloads.

```ts
import { style, variants } from 'zyzz'

const button = variants({
  base: { paddingTop: '8px' },
  variants: { tone: { quiet: { opacity: 0.5 }, loud: { opacity: 1 } } },
  defaultVariants: { tone: 'quiet' },
})

const bar = style((values: { alpha: number }) => ({ opacity: values.alpha }))

// { style: { paddingTop: 8, opacity: 1 } }
button({ tone: 'loud' })
// { style: { opacity: 0.25 } }
bar({ alpha: 0.25 })
```

Without `contextual`, a missing or invalid payload value throws before props are returned. Contextual callables defer that error until a Provider resolves the props.

## Variable Reads

Each `useVars` argument becomes a `NativeVars` profile with the set's resolved native values for every set and scheme. The nearest [`Provider`](/docs/guides/native/themes) selects one at render time. In a graph, the defining module exports the profile once, and readers import it.

```tsx title="Gap.tsx"
import { defineVars } from 'zyzz'
import { useVars } from 'zyzz/react-native/react'

const vars = defineVars({ spacing: { gap: '4px' } })

export function Gap() {
  // Reads 4 from the precompiled profile, not '4px'
  const tokens = useVars(vars)

  return tokens.spacing.gap
}
```

## Graph Output

`Graph.compile` accepts the same context as its [`native`](/docs/api/compiler/namespaces/Graph#optionsnative) option, so imports, re-exports, configs, and library contracts link across a native graph. Each module's `code` holds native callables, its `map` is the source map for that code, and its `css` and `classes` are empty.

```ts
import { Graph } from 'zyzz/compiler'

const output = Graph.compile({
  modules: {
    'app/card.ts': `import { style } from 'zyzz'

export const card = style({ opacity: 0.5 })
`,
    'app/index.ts': `export { card } from './card.js'
`,
  },
  // Compiles every module for iOS in the light scheme
  native: { colorScheme: 'light', platform: 'ios' },
})
```

## Types

* **`Native.compile.ErrorType`:** The errors `compile` throws.
* **`Native.compile.Options`:** The accepted options.
* **`Native.compile.ReturnType`:** The rewritten module, map, and tables.

```ts title="native-build.ts"
import { Native } from 'zyzz/compiler'

// Compiles both schemes of one module
export function schemes(options: Omit<Native.compile.Options, 'colorScheme'>) {
  return {
    dark: Native.compile({ ...options, colorScheme: 'dark' }),
    light: Native.compile({ ...options, colorScheme: 'light' }),
  }
}
```

A color scheme other than `light` or `dark` fails the type check.

```ts
import { Native } from 'zyzz/compiler'

declare const source: string

Native.compile({ colorScheme: 'auto', moduleId: 'app/Label.tsx', source })
// error: Type '"auto"' is not assignable to type 'ColorScheme'.
```

## Errors

`Native.compile` returns no partial output. It throws `Source.ExtractError` for source outside the [static input](/docs/api/compiler/namespaces/Source#static-input), and `StyleSheet.SelectionError` from `zyzz/react-native` for an unknown `set` without `contextual`.

### Native.CompileError

Thrown for source features without a native form, such as stylesheet contributions, `variable` declarations, named conditions, and HTML output.

```ts
import { Native } from 'zyzz/compiler'

try {
  Native.compile({
    colorScheme: 'light',
    moduleId: 'app/global.ts',
    // global rules have no native form
    source: `import { global } from 'zyzz/web'
global({ body: { margin: 0 } })
`,
  })
} catch (error) {
  if (error instanceof Native.CompileError) console.error(error.message)
}
```

### StyleSheet.CompileError

Thrown from `zyzz/react-native` for declaration values without a native form, such as `display: 'grid'` or a rem length without `units.rem`. `diagnostics` lists each failing set, scheme, and property.

```ts
import { Native } from 'zyzz/compiler'
import { StyleSheet } from 'zyzz/react-native'

try {
  Native.compile({
    colorScheme: 'light',
    moduleId: 'app/Card.tsx',
    // rem lengths need units.rem
    source: `import { style } from 'zyzz'
export const card = style({ padding: '1rem' })
`,
  })
} catch (error) {
  if (error instanceof StyleSheet.CompileError) console.error(error.diagnostics)
}
```
