# counterStyle

Emit an `@counter-style` rule and return a reference for list markers and counters.

`counterStyle` emits a named counter style from its descriptors. The compiler replaces the call with a generated name, which `listStyleType` accepts.

```tsx title="Steps.tsx"
import { style } from 'zyzz'
import { counterStyle } from 'zyzz/web'

// Emits `@counter-style z-counterstyle-circled{…}`
const circled = counterStyle({
  suffix: '" "',
  symbols: '"①" "②" "③"',
  system: 'fixed',
})

export function Steps() {
  return (
    <ol {...styles.list()}>
      <li>Install</li>
      <li>Configure</li>
    </ol>
  )
}

namespace styles {
  export const list = style({ listStyleType: circled })
}
```

## Signature

```ts
// Counter descriptors, optionally inside grouping keys
counterStyle(descriptors, context?)
```

## Parameters

### descriptors

* **Type:** `counterStyle.Options`

Counter descriptors keyed in camelCase: `additiveSymbols`, `fallback`, `negative`, `pad`, `prefix`, `range`, `speakAs`, `suffix`, `symbols`, and `system`. String values are CSS text, so symbols keep their quotes.

```ts
import { counterStyle } from 'zyzz/web'

export const thumbs = counterStyle({
  // Repeats the symbols in order
  system: 'cyclic',
  symbols: '"👍"',
  suffix: '" "',
})
```

### descriptors.system

* **Type:** `` 'cyclic' | 'numeric' | 'alphabetic' | 'symbolic' | 'additive' | 'fixed' | `fixed ${bigint}` | `extends ${string}` ``
* **Default:** `undefined`

The counter algorithm, which CSS defaults to `symbolic`. `additive` requires `additiveSymbols`, `extends` reuses another style's algorithm, and every other system requires `symbols`.

```ts
import { counterStyle } from 'zyzz/web'

export const parenthesized = counterStyle({
  // Keeps decimal numbering with a different suffix
  system: 'extends decimal',
  suffix: '") "',
})
```

### descriptors\[atRule]

* **Type:** `` '@layer' | `@${'container' | 'layer' | 'media' | 'supports'}${' ' | '\t' | '\n' | '\r' | '\f' | '(' | `/*${string}*/`}${string}` ``

Grouping keys around a complete set of descriptors. Each value holds a complete definition or further grouping keys, and outer keys emit outer groups. A bare `@layer` key emits an anonymous layer.

```ts
import { counterStyle } from 'zyzz/web'

export const stars = counterStyle({
  // Emits the rule inside `@layer lists`
  '@layer lists': { system: 'cyclic', symbols: '"*"' },
})
```

### context.id

* **Type:** `string`
* **Default:** `undefined`

A fixed identity, which replaces the name derived from the binding. It also separates two modules that declare the same binding name. Without a compiler transform, a call requires it.

```ts
// Returns `z-counterstyleid-stars`
counterStyle({ system: 'cyclic', symbols: '"*"' }, { id: 'stars' })
```

## Returns

### reference

* **Type:** `counterStyle.Reference`

The generated counter style name. `listStyleType`, `listStyle`, and custom properties accept it, as do the `fallback`, `speakAs`, and `extends` system of another counter style. Other properties reject it. Packed libraries keep the name, and the compiler omits unreferenced definitions.

```ts
// Compiles to `list-style-type:z-counterstyle-circled`
style({ listStyleType: circled })
```

## Types

* **`counterStyle.Options`:** The accepted descriptors.
* **`counterStyle.Reference`:** The returned counter style name.

```ts
import type { counterStyle } from 'zyzz/web'

// Reads the accepted counter algorithms
type System = counterStyle.Options['system']
```

## Errors

TypeScript rejects unknown descriptors, unknown systems, and calls missing the symbols their system requires.

```ts
import { counterStyle } from 'zyzz/web'

// A cyclic system requires `symbols`
counterStyle({ system: 'cyclic' })
// error: Argument of type '{ system: "cyclic"; }' is not assignable to parameter of type '{ readonly system: "cyclic"; } & NoInfer<Accepted<{ readonly system: "cyclic"; }>>'.
// Type '{ system: "cyclic"; }' is not assignable to type 'Accepted<{ readonly system: "cyclic"; }>'.
// Property 'symbols' is missing in type '{ system: "cyclic"; }' but required in type '{ readonly symbols: string; }'.
```

The compiler reports `Source.ExtractError` for invalid descriptor values. Without a compiler transform, a call without `context.id` throws an `Error`. Native builds reject the call with `Native.CompileError`.
