UNPKG

@spark-web/icon

Version:

--- title: Icon isExperimentalPackage: false ---

139 lines (103 loc) • 5.99 kB
# @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