# @spark-web/icon — AI Context

## What this package is

A library of ~230 single-color, stroke-based SVG icons plus the `createIcon`
factory used to build them. Every icon is imported by name (e.g. `SearchIcon`,
`ChevronDownIcon`) and shares one props interface (`IconProps`): `size`, `tone`,
and `data`. Icons render a 24×24 `viewBox` `<svg>` with `aria-hidden="true"`.

## What this is NOT

- Not an ad-hoc SVG drop point — never hand-write `<svg>` markup in product
  code; use a named icon, or `createIcon` if a glyph is genuinely missing
- Not a colored/filled illustration system — icons are single-tone strokes
  driven by theme foreground tones
- Not interactive — icons carry no click handling or label; wrap them in
  `@spark-web/button` / `@spark-web/icon-button` for actions
- Not a logo or brand-mark component

## Props interface

### `IconProps` (shared by every icon)

| Prop   | Type                                                                               | Default     | Notes                                             |
| ------ | ---------------------------------------------------------------------------------- | ----------- | ------------------------------------------------- |
| `size` | `'xxsmall' \| 'xsmall' \| 'small' \| 'medium' \| 'large' \| 'xlarge' \| 'xxlarge'` | `'small'`   | Maps to `theme.sizing[size]` for width and height |
| `tone` | `ForegroundTone`                                                                   | `'neutral'` | Stroke color via `theme.color.foreground[tone]`   |
| `data` | `DataAttributeMap`                                                                 | —           | Test/analytics attributes                         |

`size` is `Exclude<keyof theme.sizing, 'full' | 'none'>`. `ForegroundTone` is
the same tone union used by `Text`
(`'neutral' | 'muted' | 'link' | 'disabled' | 'field' | 'fieldAccent' | 'placeholder' | 'accent' | 'primary' | 'primaryHover' | 'primaryActive' | 'secondary' | 'secondaryHover' | 'secondaryActive' | 'caution' | 'critical' | 'info' | 'positive' | 'dark' | 'brandSubtle'`).

Each icon is a `forwardRef<SVGSVGElement, IconProps>`, so a `ref` passes through
to the underlying `<svg>`.

### `createIcon(children, name)`

| Arg        | Type        | Notes                                              |
| ---------- | ----------- | -------------------------------------------------- |
| `children` | `ReactNode` | The SVG path(s), rendered inside a 24×24 `viewBox` |
| `name`     | `string`    | Sets the component `displayName`                   |

Returns a fully-styled icon component. Use only when a needed glyph does not
already exist in the package.

## Token usage

All values from `useTheme()` from `@spark-web/theme`. Never hard-code px or hex.

| Property        | Token / Value                                            |
| --------------- | -------------------------------------------------------- |
| Width/height    | `theme.sizing[size]` (e.g. `xxsmall` = 16, `small` = 32) |
| Stroke color    | `theme.color.foreground[tone]` via `useForegroundTone`   |
| Stroke width    | `2` (fixed in `createIcon`)                              |
| Fill            | `none` (stroke-based glyphs)                             |
| Line caps/joins | `round` (fixed)                                          |

## Import-by-name convention

Import each icon individually by its named export from the package root:

```tsx
import { SearchIcon, ChevronDownIcon, XIcon } from '@spark-web/icon';
```

There is no default export and no dynamic name-to-icon lookup. To find an exact
export name, search the exports list in `packages/icon/src/index.ts` (each icon
is `export { FooIcon } from './icons/foo-icon';`). Names are PascalCase and end
in `Icon` (e.g. `SearchIcon`, `InformationCircleIcon`, `ExclamationIcon`,
`CheckCircleIcon`, `XIcon`).

Canonical icons used in the internal-admin patterns: `SearchIcon` (list-page
search field adornment). `Alert` selects `ExclamationIcon`,
`InformationCircleIcon`, `CheckCircleIcon`, and `XIcon` internally by tone.

## Composition

- Icons are leaf components — they accept no children beyond what `createIcon`
  bakes in
- Commonly nested inside `InputAdornment` (`@spark-web/text-input`), `Button`
  (`@spark-web/button`), and `Alert` (`@spark-web/alert`)
- List page — Section 4 uses `<SearchIcon size="xxsmall" tone="muted" />` inside
  a start `InputAdornment`. See
  `node_modules/@spark-web/design-system/patterns/internal-admin/list-page.md`.

## Correct usage

### Search field adornment (from internal-admin list-page pattern)

```tsx
import { SearchIcon } from '@spark-web/icon';
import { InputAdornment, TextInput } from '@spark-web/text-input';

<TextInput placeholder="Search by...">
  <InputAdornment placement="start">
    <SearchIcon size="xxsmall" tone="muted" />
  </InputAdornment>
</TextInput>;
```

### Tone-colored status icon

```tsx
<CheckCircleIcon size="small" tone="positive" />
```

### Creating a missing glyph

```tsx
import { Fragment } from 'react';
import { createIcon } from '@spark-web/icon';

export const SparkleIcon = createIcon(
  <Fragment>
    <path d="M12 3v18M3 12h18" />
  </Fragment>,
  'SparkleIcon'
);
```

## Do NOTs

- NEVER hand-write raw `<svg>` markup in product code — import a named icon
- NEVER set `size` or `tone` with raw px/hex — use the `size` and `tone` props
- NEVER use a `size` outside the seven named values, or a `tone` outside the
  `ForegroundTone` union
- NEVER rely on a default icon export or string-keyed lookup — every icon is a
  named import
- NEVER add an `onClick` to an icon for interactivity — wrap it in a button
  component; icons are `aria-hidden`

## Component gaps / known limitations

- Single stroke color only — no multi-color or filled icons
- Stroke width is fixed at `2` and not configurable per icon
- Icons are decorative (`aria-hidden="true"`); meaning must come from an
  accessible label on the surrounding interactive element
