@lmvz-ds/icons
v0.20.2
Published
LMVZ Design System Icons - Icon resolution providers and assets
Readme
@lmvz-ds/icons
Icon resolution providers and assets for the LMVZ Design System.
Installation
pnpm add @lmvz-ds/iconsPackage Structure
packages/icons/
├── assets/ # SVG icon files
├── scripts/ # Build-time scripts
├── src/ # Code for consumption in other packages or web applications
└── dist/ # Build outputThis package supports two primary use-cases:
- Consuming LMVZ Icons — Use an existing provider to display icons in your application
- Creating a Custom Icon Set — Generate type-safe icon manifests and providers from your own SVG files
Use-Case 1: Consuming LMVZ Icons
In this case, this @lmvz-ds/icons package is a production dependency.
Install as a regular dependency to use the LMVZ Design System icon set. Different Provider Modes are available for consuming the iconset.
Choosing a Provider Mode
| Mode | When to use | Trade-off | | ------------- | ----------------------------------------- | ------------------------------------------------------------------------------- | | Bundled | Most apps | All icons load at once; single sprite file; ~50–200 KB; zero follow-up requests | | On-Demand | Many icons, progressive loading preferred | Network requests on first use; smaller initial load; built-in caching |
Bundled Provider
The bundled provider gives you all icons in a single sprite file with zero network requests. This is recommended for most apps.
Its entrypoint (@lmvz-ds/icons/bundled) provides single-request icon resolution from a pre-built SVG sprite:
- Single sprite to load with all icons available immediately
- Smaller total bundle size - single sprite file vs individual SVGs
Quick Start
import { registerIconProvider, typedIconFromSet } from '@lmvz-ds/components';
import { LmvzBundledProvider, SPRITE_SVG } from '@lmvz-ds/icons/bundled';
// 1. Inject sprite into document head (once, early in app bootstrap)
const container = document.createElement('div');
container.innerHTML = SPRITE_SVG;
document.head.appendChild(container.firstElementChild);
// 2. Register the provider
const provider = new LmvzBundledProvider();
registerIconProvider('lmvz', provider);
// 3. Use icons in your components
function render() {
return <lmvz-icon {...typedIconFromSet('lmvz', 'checkmark')}></lmvz-icon>;
}Framework-Specific Setup
Angular:
// In your app initialization (main.ts or AppComponent)
import { registerIconProvider } from '@lmvz-ds/components';
import { LmvzBundledProvider, SPRITE_SVG } from '@lmvz-ds/icons/bundled';
// Inject sprite
const container = document.createElement('div');
container.innerHTML = SPRITE_SVG;
document.head.appendChild(container.firstElementChild);
// Register provider
const provider = new LmvzBundledProvider();
registerIconProvider('lmvz', provider);On-Demand Provider
The on-demand provider fetches individual icons on demand and caches them.
Its default entry point (@lmvz-ds/icons/on-demand) provides lazy-loading icon resolution:
- Loader Module for lightweight provider registration
- Runtime Module for on-demand and cached icon fetching
Quick Start
import { registerIconProvider, typedIconFromSet } from '@lmvz-ds/components';
import { LmvzOnDemandProvider } from '@lmvz-ds/icons/on-demand';
// 1. Register the provider
const provider = new LmvzOnDemandProvider();
registerIconProvider('lmvz', provider);
// 2. Use icons (they load on demand and are cached)
function render() {
return <lmvz-icon {...typedIconFromSet('lmvz', 'chevron-down')}></lmvz-icon>;
}Use-Case 2: Creating a Custom Icon Set
Use LMVZ icon generation tooling to build custom, type-safe icon sets for your application or package.
Prerequisites
- Install
@lmvz-ds/iconsas a dev dependency:pnpm add -D @lmvz-ds/icons - Collect SVG icon files into an
assets/icons/directory
Step 1: Generate Icon Manifest
Create a script to generate TypeScript types and metadata from your SVG files:
// scripts/generate-my-icons.ts
import { generateManifest } from '@lmvz-ds/icons/scripts/generate-manifest';
generateManifest({
assetsDir: './assets/icons',
outputFile: './src/generated/icon-manifest.ts',
typeName: 'MyCustomIconName', // optional, default: 'IconName'
manifestName: 'MY_CUSTOM_ICONS', // optional, default: 'ICON_MANIFEST'
});Generated outputs include:
- Type-safe icon name union:
MyCustomIconName - Icon metadata record:
MY_CUSTOM_ICONS - Icon names array:
MY_CUSTOM_ICON_NAMES - Icon count constant:
MY_CUSTOM_ICON_COUNT
Step 2: Generate SVG Sprite (for bundled mode)
Generate a sprite sheet for static, zero-request icon loading:
import { generateSprite } from '@lmvz-ds/icons/scripts/generate-sprite';
generateSprite({
assetsDir: './assets/icons',
outputFile: './dist/sprite.svg',
idPrefix: '', // optional prefix for svg symbol IDs, e.g., 'my-icon-'
});Step 3: Create a Custom Icon Provider
Implement an icon provider for your custom set:
import type { IconProvider, IconRecord } from '@lmvz-ds/lib-icon-api';
import { MY_CUSTOM_ICONS } from './generated/icon-manifest.js';
export class MyCustomIconProvider implements IconProvider<string> {
resolve(name: string): IconRecord | undefined {
const icon = MY_CUSTOM_ICONS[name];
return icon ? { name, svg: icon.svg } : undefined;
}
}Step 4: Register Your Custom Set
In your application, register the custom provider and augment types:
import { registerIconProvider } from '@lmvz-ds/components';
import { MyCustomIconProvider } from './my-icons.provider';
import type { MyCustomIconName } from './generated/icon-manifest.js';
// Register the provider
const myProvider = new MyCustomIconProvider();
registerIconProvider('my-icons', myProvider);
// Enable type-safe icon selection
declare module '@lmvz-ds/lib-icon-api' {
interface IconSetNameMap {
'my-icons': MyCustomIconName;
}
}Step 5: Use Custom Icons
Now <lmvz-icon> supports your custom icon set with full type safety:
import { typedIconFromSet } from '@lmvz-ds/components';
function MyComponent() {
return (
<>
{/* TypeScript ensures 'my-icons' only accepts names from MyCustomIconName */}
<lmvz-icon {...typedIconFromSet('my-icons', 'my-custom-icon')}></lmvz-icon>
</>
);
}Key Points
- Type augmentation goes in
@lmvz-ds/lib-icon-api(shared module), not in@lmvz-ds/components - Icon names are validated at compile time via the
typedIconFromSet()helper - All scripts are importable from
@lmvz-ds/icons/scripts/*
Accessibility
Icons are often decorative and should be hidden from the accessibility tree. Use aria-label only when the icon conveys additional meaning that has no textual representation.
Omitting aria-label for decorative icons prevents redundant announcements and keeps the accessibility tree clean:
<lmvz-button>
<lmvz-icon {...typedIconFromSet('lmvz', 'search')}></lmvz-icon>
Search
</lmvz-button>Stand-alone icons usually have semantic meaning. Include an aria-label:
<lmvz-icon {...typedIconFromSet('lmvz', 'warning')} aria-label="Warning"></lmvz-icon>Development
The icon manifest and sprite are auto-generated from the assets/icon directory. To add or update icons:
- Run
pnpm run update-iconsto update assets from supernova - Run
pnpm run generateto regenerate the manifest, sprite, and bundled types - Run
pnpm run verify:spriteto verify sprite generation quality - Run
pnpm testto run unit tests - Run
pnpm run buildto compile everything
Note that the script exports all assets flatly into the assets/icon directory. This behavior is slightly different from the Supernova SVG exporter, which retains the original structure. Supernova's layout is canonical, so adjust any outliers after manual updates.
CI/CD Automation
Supernova is configured to create a pull request with all assets upon change (using its Code Automation pipelines). Since the target folder assets/icons is fixed by the given exporter, that location for icons must not be changed!
