npm package: @reforgium/icon
Description: reforgium Icon component
Author: rtommievich
Latest version: 1.0.0

# @reforgium/icon

[![npm version](https://badge.fury.io/js/%40reforgium%2Ficon.svg)](https://www.npmjs.com/package/@reforgium/icon)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Configurable SVG icon component for Angular (17.1+).**

`@reforgium/icon` provides a standalone `re-icon` component, a cached `SvgService`, and a DI-driven provider for asset paths, URL resolution, default size/measure, and appearance colors.

Designed for shared UI libraries and apps that need one icon system instead of scattered local wrappers.

Minimum Angular version is `17.1+` because the package relies on signal inputs API (`input(...)`, `input.required(...)`).

---

## Highlights

- Framework-native standalone component with no separate module setup
- One DI configuration layer for path resolution, default sizing, default units, and appearance colors
- Works with plain static assets, CDN paths, or fully custom URL resolution
- Keeps the icon component surface small while allowing application-level defaults
- Reuses one appearance color contract across icon consumers
- Suitable both for application code and for shared design-system style libraries

---

## Features

- Standalone Angular icon component: `re-icon`
- Cached SVG loading through `SvgService`
- Safe SVG sanitization before DOM insertion
- Global DI configuration via `provideSvgConfig(...)`
- Configurable static asset path
- Configurable file extension
- Optional custom URL resolver for CDN or versioned assets
- Global appearance color map
- Global default size and default measure
- Explicit input overrides still win per component instance

---

## Typical use cases

- A product app where all icons live in `assets/icons`, but some feature areas override colors and size defaults through DI
- A shell app that serves icons from a CDN or versioned static endpoint via `assetUrlResolver`
- A shared UI layer that wants one consistent `appearance` contract instead of repeating icon color maps in multiple components
- A standalone Angular codebase that needs a light SVG icon wrapper without binding the package to a specific icon set

---

## Delivery model

This package intentionally keeps icons as external static assets instead of bundling every icon into application JavaScript.

Why this is often a good fit:

- Application bundle size stays smaller because SVG payloads are not embedded into the main JS graph
- Icon delivery remains transparent: files can be served from app assets, CDN, or any custom resolver
- Updating or replacing icon files does not require changing component code
- The library stays independent from a specific icon pack build pipeline

Trade-off:

- The first load of a specific icon usually means a separate network request

In practice this is often an acceptable trade:

- the service caches icon payloads
- repeated icon usage does not re-fetch the same asset
- an external SVG request is not fundamentally worse than loading extra JavaScript just to carry icon markup

If a project needs a different delivery strategy, `assetUrlResolver` allows adapting the URL model without changing component usage.

---

## Where icons come from

By default, the library expects plain SVG files to be available under:

```text
assets/icons/<name>.svg
```

That means:

- `name="check"` resolves to `assets/icons/check.svg`
- `name="auth-page/pass-check"` resolves to `assets/icons/auth-page/pass-check.svg`

Example project structure:

```text
src/
  assets/
    icons/
      check.svg
      warning.svg
      auth-page/
        pass-check.svg
        login-user.svg
```

Example usage:

```html
<re-icon name="check" />
<re-icon name="auth-page/pass-check" appearance="success" />
<re-icon name="auth-page/login-user" [size]="18" />
```

If your icons live elsewhere, adjust the provider:

```ts
provideSvgConfig({
  staticAssetPath: 'assets/ui/icons',
});
```

Then:

- `name="check"` resolves to `assets/ui/icons/check.svg`
- `name="auth-page/pass-check"` resolves to `assets/ui/icons/auth-page/pass-check.svg`

If the URL should not be path-based at all, use `assetUrlResolver`.

---

## Installation

```bash
npm install @reforgium/icon
```

```ts
import { IconComponent } from '@reforgium/icon';

@Component({
  standalone: true,
  imports: [IconComponent],
})
export class SomeComponent {}
```

```html
<re-icon name="check" appearance="primary" />
<re-icon name="warning" [size]="18" color="#f59e0b" />
<re-icon name="user" width="1.5" height="1.5" measure="rem" />
```

---

## Configuration

### Global provider

You can override icon defaults for the current injector scope:

```ts
import { provideSvgConfig } from '@reforgium/icon';

export const appConfig: ApplicationConfig = {
  providers: [
    provideSvgConfig({
      staticAssetPath: 'assets/ui/icons',
      assetFileExtension: '.svg',
      defaultSize: 18,
      defaultMeasure: 'px',
      appearanceColors: {
        primary: 'var(--brand-primary)',
        gray: 'var(--text-secondary)',
      },
    }),
  ],
};
```

Supported config fields:

- `staticAssetPath`
- `assetFileExtension`
- `assetUrlResolver`
- `defaultSize`
- `defaultMeasure`
- `appearanceColors`

### Custom asset URL resolver

Use `assetUrlResolver` when icons are served from a CDN, proxy, or versioned endpoint:

```ts
provideSvgConfig({
  assetUrlResolver: (name) => `/cdn/icons/${name}.svg?v=20260327`,
});
```

When `assetUrlResolver` is defined, it has priority over `staticAssetPath` and `assetFileExtension`.

### Appearance colors

Default appearance keys:

- `primary`
- `success`
- `warning`
- `error`
- `info`
- `light`
- `gray`
- `inherit`

`inherit` defaults to `currentColor`.

---

## API

### `IconComponent`

Inputs:

- `name: string` required icon name
- `appearance: Appearance = 'inherit'`
- `size?: number`
- `width?: number`
- `height?: number`
- `measure?: IconMeasure`
- `color?: string`
- `decorative = true`
- `ariaLabel?: string | null`

Resolution rules:

1. Explicit `color` overrides `appearance`
2. Explicit `size` overrides `width` and `height`
3. Explicit `width` / `height` override provider `defaultSize`
4. Explicit `measure` overrides provider `defaultMeasure`

Supported measures:

- `px`
- `rem`
- `%`
- `em`
- `vh`
- `vw`

### `SvgService`

Main methods:

- `loadIcon(name, width?, height?, measure?)`
- `clear(name?)`

`loadIcon(...)` returns a signal with sanitized SVG content and avoids duplicate concurrent HTTP requests for the same icon.

### Public exports

```ts
import {
  IconComponent,
  SvgService,
  SVG_PROVIDER_CONFIG,
  DEFAULT_SVG_PROVIDER_CONFIG,
  provideSvgConfig,
  type SvgProviderConfig,
  type SvgProviderConfigOverrides,
  type Appearance,
  type IconMeasure,
} from '@reforgium/icon';
```

---

## Notes

- `re-icon` renders SVG via `[innerHTML]`, so sanitization is handled centrally in `SvgService`
- Missing or invalid SVG content resolves to `null` instead of throwing in the template