mirror of
https://github.com/gromlab-ru/svg-sprites.git
synced 2026-08-02 09:50:15 +03:00
Compare commits
32 Commits
v1.1.0
...
ab7042001a
| Author | SHA1 | Date | |
|---|---|---|---|
| ab7042001a | |||
| 1280eb6fcd | |||
| c596f9f1c3 | |||
| 3dd385bfda | |||
| 632b450c8b | |||
| 7992adc9d3 | |||
| f4f464a568 | |||
|
|
bc4bece3c5 | ||
| c47fbdad8c | |||
|
|
06fef6bd96 | ||
| 00fa6cea28 | |||
|
|
b9451c8ff3 | ||
| 1b6a5cb90c | |||
|
|
cb40d4eb04 | ||
| 873704abd6 | |||
| 3f6b186a5b | |||
|
|
c7e6a27236 | ||
| b4869deb97 | |||
|
|
07d57e3838 | ||
| 1b5b446d8f | |||
|
|
b3a3a8347a | ||
| b72a113955 | |||
|
|
838cb7cfff | ||
| 4833b31516 | |||
|
|
38068d7c9f | ||
| 82bc9e7d77 | |||
|
|
b6c4561c28 | ||
| 03858aa1f4 | |||
|
|
9439682235 | ||
| df096126a7 | |||
|
|
4b47df9898 | ||
| 40138788e0 |
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@@ -40,3 +40,36 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
integration:
|
||||
name: Integration playground
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: |
|
||||
package-lock.json
|
||||
integration/package-lock.json
|
||||
|
||||
- name: Install package dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build package
|
||||
run: npm run build:package
|
||||
|
||||
- name: Install playground dependencies
|
||||
run: npm ci --prefix integration
|
||||
|
||||
- name: Install Chromium
|
||||
run: npm exec --prefix integration -- playwright install --with-deps chromium
|
||||
|
||||
- name: Verify playground
|
||||
run: npm run verify --prefix integration
|
||||
|
||||
42
.github/workflows/release.yml
vendored
42
.github/workflows/release.yml
vendored
@@ -4,13 +4,19 @@ on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: Existing release tag to publish
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: release-${{ github.event.release.tag_name }}
|
||||
group: release-${{ github.event.release.tag_name || inputs.tag }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
@@ -22,22 +28,23 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout release tag
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
ref: ${{ github.event.release.tag_name || inputs.tag }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
registry-url: https://registry.npmjs.org
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Update npm
|
||||
run: npm install --global npm@latest
|
||||
|
||||
- name: Check release version
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }}
|
||||
run: |
|
||||
node --input-type=module -e '
|
||||
import { readFileSync } from "node:fs"
|
||||
@@ -79,9 +86,19 @@ jobs:
|
||||
- name: Create checksums
|
||||
run: sha256sum release/* > release/SHA256SUMS
|
||||
|
||||
- name: Upload GitHub Release assets
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.event.release.tag_name || inputs.tag }}
|
||||
files: |
|
||||
release/*.tgz
|
||||
release/*.zip
|
||||
release/SHA256SUMS
|
||||
overwrite_files: true
|
||||
|
||||
- name: Publish npm package
|
||||
env:
|
||||
IS_PRERELEASE: ${{ github.event.release.prerelease }}
|
||||
IS_PRERELEASE: ${{ github.event.release.prerelease || false }}
|
||||
run: |
|
||||
PACKAGE_SPEC=$(node -p "const pkg = require('./package.json'); pkg.name + '@' + pkg.version")
|
||||
|
||||
@@ -95,13 +112,4 @@ jobs:
|
||||
DIST_TAG=next
|
||||
fi
|
||||
|
||||
npm publish release/*.tgz --access public --provenance --tag "$DIST_TAG"
|
||||
|
||||
- name: Upload GitHub Release assets
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
release/*.tgz
|
||||
release/*.zip
|
||||
release/SHA256SUMS
|
||||
overwrite_files: true
|
||||
npm publish --ignore-scripts --access public --tag "$DIST_TAG"
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,7 +2,9 @@ node_modules/
|
||||
dist/
|
||||
public/
|
||||
test/public/
|
||||
test/.next-fixture-*/
|
||||
.tmp/
|
||||
skills/artifacts/
|
||||
*.generated.ts
|
||||
*.tgz
|
||||
.DS_Store
|
||||
|
||||
99
AGENTS.md
Normal file
99
AGENTS.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Архитектурные правила
|
||||
|
||||
## Изоляция modes
|
||||
|
||||
Каждый полный mode key является независимым adapter со своим generated-контрактом:
|
||||
|
||||
- `react@vite`;
|
||||
- `react@webpack`;
|
||||
- `next@app/turbopack`;
|
||||
- `next@app/webpack`;
|
||||
- `next@pages/turbopack`;
|
||||
- `next@pages/webpack`;
|
||||
- `standalone`;
|
||||
- `standalone@vite`;
|
||||
- `standalone@webpack`;
|
||||
- будущие `vue@*` и другие modes.
|
||||
|
||||
Для каждого exact mode используется отдельный каталог `src/modes/<mode-slug>/`. Adapter самостоятельно определяет:
|
||||
|
||||
- compile options;
|
||||
- список и имена generated-файлов;
|
||||
- runtime JavaScript;
|
||||
- TypeScript declarations;
|
||||
- manifest source;
|
||||
- CSS;
|
||||
- способ получения asset URL;
|
||||
- mode-specific result metadata.
|
||||
|
||||
Изменение output одного mode не должно менять output другого mode. Дублирование component, manifest, declaration и CSS codegen между adapters является сознательной ценой изоляции.
|
||||
|
||||
Запрещено:
|
||||
|
||||
- импортировать один `src/modes/<exact>/` из другого mode;
|
||||
- создавать общий framework/component/manifest/CSS codegen для нескольких modes;
|
||||
- создавать общий runtime asset URL generator для нескольких modes;
|
||||
- ветвиться по generic target внутри adapter;
|
||||
- писать generated-файлы непосредственно из adapter через `fs`;
|
||||
- импортировать exact-mode adapters из core.
|
||||
|
||||
Единственное место, которое импортирует все adapters, — `src/mode-registry.ts`.
|
||||
|
||||
## Общий core
|
||||
|
||||
Общими могут быть только mode-neutral данные и инфраструктура:
|
||||
|
||||
- загрузка, merge и валидация config;
|
||||
- scanner исходных SVG;
|
||||
- shape IDs и проверка конфликтов;
|
||||
- низкоуровневый SVG compiler и transformations;
|
||||
- подготовка нейтрального compiled artifact;
|
||||
- protocol `ModeAdapter`/`OutputPlan`;
|
||||
- проверка output paths;
|
||||
- staged directory writer и symlink protection;
|
||||
- logger и базовые result types.
|
||||
|
||||
Core не генерирует JavaScript, declarations, manifest source, CSS или framework-specific exports. Изменение общего compiler может ожидаемо изменить SVG всех modes; изменение generated source должно быть локально одному adapter.
|
||||
|
||||
## Generated-контракт
|
||||
|
||||
Один config разрешается ровно в один mode и один output. Множественные modes не генерируются в один root; orchestration выполняется независимыми config/API/CLI вызовами.
|
||||
|
||||
Runtime генерируется как ESM JavaScript. Типизация добавляется отдельными `.d.ts`; TypeScript/TSX не используется как runtime output.
|
||||
|
||||
Core writer полностью владеет каталогом `.svg-sprite` и при каждой генерации заменяет его через временный каталог с rollback при ошибке. Корневым `.gitignore` writer владеет, когда exact-mode adapter запрашивает его через `OutputPlan`. Bare `standalone` не создаёт `.gitignore`; остальные modes создают.
|
||||
|
||||
Sprite-level asset, icon data, manifest и facade лежат непосредственно в `.svg-sprite/`. `standalone@vite` и `standalone@webpack` генерируют нативный icon Web Component внутри своего facade; bare `standalone` остаётся без JavaScript runtime. Framework runtime группируется отдельно: React adapters используют `.svg-sprite/react/`, будущие framework adapters получают собственный framework-каталог.
|
||||
|
||||
Adapter возвращает файлы в памяти. Только core writer проверяет paths, полностью заменяет `.svg-sprite` и обновляет управляемый `.gitignore`.
|
||||
|
||||
## Зависимости
|
||||
|
||||
Допустимое направление импортов:
|
||||
|
||||
```text
|
||||
public API / CLI
|
||||
-> generate
|
||||
-> mode-registry
|
||||
-> один exact-mode adapter
|
||||
-> core protocols and services
|
||||
```
|
||||
|
||||
Обратные и горизонтальные зависимости запрещены:
|
||||
|
||||
```text
|
||||
core -X-> modes
|
||||
mode A -X-> mode B
|
||||
mode A -X-> shared output codegen
|
||||
```
|
||||
|
||||
`src/viewer/` с Web Component является framework-neutral browser runtime пакета, а не mode adapter. `src/react/` содержит только React bridge к этому runtime.
|
||||
|
||||
## Изменение mode
|
||||
|
||||
При работе с adapter:
|
||||
|
||||
1. Изменяйте только его каталог и mode-neutral protocol, если это действительно необходимо.
|
||||
2. Не переносите output-логику в core ради устранения дублирования.
|
||||
3. Не меняйте generated-контракты других adapters автоматически.
|
||||
4. Проверяйте отсутствие cross-mode imports.
|
||||
55
FEATURES.md
Normal file
55
FEATURES.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Иконки без лишней цены для приложения
|
||||
|
||||
`@gromlab/svg-sprites` превращает SVG проекта в кешируемую, типизированную систему иконок для vanilla-приложений, React и Next.js. В коде остаются простые компоненты, а приложение получает преимущества спрайтов без сложной инфраструктуры.
|
||||
|
||||
1. **AI-friendly из коробки**
|
||||
|
||||
`@gromlab/svg-sprites` сразу рассчитан на работу с AI-агентами. Подключите готовый skill и поручите агенту настройку, миграцию или диагностику без длинных инструкций и ручного изучения документации.
|
||||
|
||||
2. **Типизированный React-компонент с автокомплитом**
|
||||
|
||||
Каждый спрайт получает собственный готовый компонент. Prop `icon` формируется из реальных имён SVG, поэтому редактор показывает точный список доступных иконок, а TypeScript сразу обнаруживает опечатки. Не нужно вручную поддерживать компоненты, union-типы или реестр имён.
|
||||
|
||||
3. **Next.js App Router и SSR из коробки**
|
||||
|
||||
Generated-компоненты работают в Server Components, SSR и SSG без `'use client'`. Подключение иконки не переносит страницу на клиент и не требует provider или дополнительной гидратации.
|
||||
|
||||
4. **Множественные спрайты вместо одного глобального**
|
||||
|
||||
Проект не ограничен одним набором иконок. Создавайте независимые спрайты для общих элементов, отдельных страниц и крупных UI-модулей. Каждый набор получает собственный типизированный компонент и SVG asset, поэтому разделы приложения не несут иконки, которые им не нужны.
|
||||
|
||||
5. **Каждая иконка хранится в одном экземпляре**
|
||||
|
||||
Одна SVG-иконка может входить в любое количество спрайтов. Общие иконки не приходится копировать между страницами и модулями: они хранятся в одном месте и обновляются сразу для всех наборов.
|
||||
|
||||
6. **Браузерное кэширование**
|
||||
|
||||
Каждый спрайт выпускается отдельным версионированным SVG-файлом. Пока его набор иконок не меняется, браузер может использовать сохранённую копию независимо от обновлений JavaScript приложения.
|
||||
|
||||
7. **JavaScript без SVG-балласта**
|
||||
|
||||
Контуры иконок остаются во внешних SVG assets и не увеличивают chunks приложения. JavaScript отвечает за интерфейс и поведение, а графика загружается и кешируется отдельно.
|
||||
|
||||
8. **Трансформации SVG из коробки**
|
||||
|
||||
Во время генерации пакет автоматически подготавливает исходные SVG для интерфейса: удаляет фиксированные `width` и `height` с сохранением `viewBox`, преобразует `fill` и `stroke` в CSS-переменные и добавляет плавные transitions непосредственно в цветные элементы иконки. Каждую трансформацию можно настроить или отключить независимо.
|
||||
|
||||
9. **Каждый цвет под контролем CSS**
|
||||
|
||||
При генерации цвета `fill` и `stroke` автоматически преобразуются в CSS-переменные `--icon-color-N`. Монохромная иконка наследует `currentColor`, а в многоцветной каждый цвет можно менять отдельно. Темы, состояния и hover-эффекты создаются без редактирования SVG и дополнительных копий иконки.
|
||||
|
||||
10. **SpriteViewer: все спрайты на одной debug-странице**
|
||||
|
||||
`SpriteViewer` рендерит все спрайты проекта в одном месте и показывает, какие иконки вошли в каждый набор и как они выглядят. Для каждой иконки видны созданные CSS-переменные и их fallback-цвета. Значения можно менять прямо в Viewer и сразу наблюдать результат. Здесь же доступны готовые примеры подключения через React, `<svg><use>`, `<img>` и CSS.
|
||||
|
||||
11. **Standalone, React и Next.js**
|
||||
|
||||
Для vanilla-приложений с Vite или Webpack пакет генерирует нативный типизированный Web Component без runtime-зависимостей. Для React и Next.js создаётся React-компонент с поддержкой Vite, Webpack 5, App Router, Pages Router и Turbopack.
|
||||
|
||||
12. **Чистый Git**
|
||||
|
||||
Generated-файлы автоматически исключаются из Git и не засоряют историю, pull requests и код проекта. В репозитории остаются только исходные SVG и конфигурация, а локально и в CI спрайты, компоненты и типы заново создаются через `prebuild`.
|
||||
|
||||
13. **В production только иконки**
|
||||
|
||||
Генератор можно запускать через `npx`, не добавляя package в проект. Локальная установка нужна только для необязательного Viewer, типизации config через package или программного API. Compiler и CLI не попадают в клиентское приложение: после сборки остаются только локальный типизированный компонент и внешний SVG-файл.
|
||||
561
README.md
561
README.md
@@ -4,394 +4,281 @@
|
||||
|
||||
 
|
||||
|
||||
A CLI for generating SVG sprites and typed icon components for React and Next.js.
|
||||
`@gromlab/svg-sprites` is an SVG sprite generator for modern web applications. It combines selected SVG icons into one or more external, cacheable sprites and prepares them for use in the UI.
|
||||
|
||||

|
||||
For vanilla applications using Vite/Webpack, the package generates a native typed Web Component; for React and Next.js, it generates a React component. In every case, the SVG remains a separate cacheable asset.
|
||||
|
||||
## Navigation
|
||||
## An SVG sprite as simple as a regular SVG icon
|
||||
|
||||
- [Features](#features)
|
||||
- [Support matrix](#support-matrix)
|
||||
- [Requirements](#requirements)
|
||||
- [Quick start](#quick-start)
|
||||
- [React + Vite](docs/en/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||
- [Next.js App Router](docs/en/next-app.md)
|
||||
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||
- [Configuration](#configuration)
|
||||
- [React](#react)
|
||||
- [Next.js](#nextjs)
|
||||
- [Multiple sprites](#multiple-sprites)
|
||||
- [TypeScript](#typescript)
|
||||
- [Sprite formats](#sprite-formats)
|
||||
- [Rendering methods](#rendering-methods)
|
||||
- [Transformations](#transformations)
|
||||
- [Icon color management](#icon-color-management)
|
||||
- [Caching](#caching)
|
||||
- [SpriteViewer](#spriteviewer)
|
||||
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||
- [Documentation](#documentation)
|
||||
One typed React component is generated for the entire sprite. Choose an icon with the `icon` prop, and your editor will autocomplete every available name.
|
||||
|
||||
## Features
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
- **AI-agent friendly** - the repository includes a ready-to-use skill with up-to-date documentation for configuring, migrating, and troubleshooting `@gromlab/svg-sprites`.
|
||||
- **TypeScript-friendly** - typed React components, union types, and runtime lists of available icons.
|
||||
- **Clean generation** - generated files are automatically excluded from Git, the sprite does not need to be placed in `public` manually, and the generator updates only files it owns.
|
||||
- **Shared icons without copying** - SVGs from the local folder and `inputFiles` are merged into a single sprite; one file can be used in multiple sprites.
|
||||
- **Built-in interactive preview** - `<SpriteViewer>` is integrated as an application page and displays the provided React and Next.js sprites with search, color controls, and usage examples.
|
||||
- **Configurable SVG transformations** - remove `width` and `height` while preserving `viewBox`, replace source colors with CSS variables, and add transitions for `fill` and `stroke`.
|
||||
- **Separate cacheable SVG asset** - SVG path data does not end up in JavaScript chunks, and the bundler emits a file with a content hash.
|
||||
- **Multiple sprites** - independent React and Next.js modules with their own components, types, and SVG assets.
|
||||
- **Server-first Next.js** - generated components work in Server Components, SSR, and SSG without the `'use client'` directive.
|
||||
- **Formats for different use cases** - React and Next.js use `stack`; legacy mode also supports `symbol` for existing integrations.
|
||||
The component accepts familiar SVG attributes: dimensions, `color`, `className`, `style`, `aria-*`, and event handlers. If you need an outer container, add `wrapped`.
|
||||
|
||||
## Support matrix
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
| Environment | API mode key | Status |
|
||||
|---|---|---|
|
||||
| React + Vite | `react@vite` | Ready |
|
||||
| React + Webpack 5 | `react@webpack` | Ready |
|
||||
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Ready |
|
||||
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Ready |
|
||||
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Ready |
|
||||
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Ready |
|
||||
| Vue | - | Coming soon |
|
||||
| Standalone | - | Coming soon |
|
||||
You do not have to work with the sprite directly in your application. Use it like a regular SVG icon while benefiting from a single component, autocomplete, and TypeScript validation for every name.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18 or newer;
|
||||
- the package is distributed as ESM only and is loaded via `import`;
|
||||
- React 18 or 19 is required only for generated components and the `@gromlab/svg-sprites/react` entry point;
|
||||
- for subpath export typings, use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
||||
|
||||
## Quick start
|
||||
|
||||
For a quick start, follow the guide for your stack:
|
||||
|
||||
- [React + Vite](docs/en/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||
- [Next.js App Router](docs/en/next-app.md)
|
||||
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||
|
||||
## Configuration
|
||||
|
||||
### React
|
||||
In `standalone@vite` and `standalone@webpack`, the same approach works without React:
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
import { defineAppIconElement } from './app-icons'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: [
|
||||
'../../shared/icons/check.svg',
|
||||
defineAppIconElement()
|
||||
```
|
||||
|
||||
```html
|
||||
<app-icon icon="search" style="font-size: 24px"></app-icon>
|
||||
```
|
||||
|
||||
Bare `standalone` remains minimal and generates only an SVG asset and JSON manifest, with no JavaScript runtime.
|
||||
|
||||
## AI-friendly out of the box
|
||||
|
||||
`@gromlab/svg-sprites` is designed to work with AI agents from the start. Add the ready-made skill and ask an agent to configure, migrate, or troubleshoot the package without lengthy instructions or manual documentation research.
|
||||
|
||||
[🇬🇧 Download AI skill (English)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites.zip)
|
||||
|
||||
[🇷🇺 Download AI skill (Russian)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites-ru.zip)
|
||||
|
||||
## From SVG to component in four steps
|
||||
|
||||
The main example uses the Next.js App Router and Turbopack.
|
||||
|
||||
### 1. Generate without installing the package
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites --help
|
||||
```
|
||||
|
||||
`npx` downloads the CLI temporarily. It does not add `@gromlab/svg-sprites` to
|
||||
`package.json`, and the generated production runtime does not import the package.
|
||||
|
||||
### 2. Specify the icons you need
|
||||
|
||||
SVG files can remain in your project's existing structure:
|
||||
|
||||
```text
|
||||
src/
|
||||
├── assets/icons/
|
||||
│ ├── search.svg
|
||||
│ └── settings.svg
|
||||
├── features/profile/
|
||||
│ └── user.svg
|
||||
└── ui/app-icons/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Create the sprite configuration:
|
||||
|
||||
```ts
|
||||
// src/ui/app-icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'app',
|
||||
input: [
|
||||
'../../assets/icons/search.svg',
|
||||
'../../assets/icons/settings.svg',
|
||||
'../../features/profile/user.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
| Option | Type | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `name` | `string` | Folder name | Name of the sprite, component, and public types |
|
||||
| `description` | `string` | None | Description for types and the debug manifest |
|
||||
| `inputFolder` | `string` | `./icons` | Folder containing source SVGs, relative to the config |
|
||||
| `inputFiles` | `string[]` | `[]` | Additional SVG files, relative to the config |
|
||||
| `transform` | `TransformOptions` | All enabled | [Transformation settings](#transformations) for source SVGs |
|
||||
| `generatedNotice` | `boolean` | `true` | Full or short warning in generated files |
|
||||
|
||||
`inputFolder` and `inputFiles` are merged into a single sprite, so one SVG file can be used in multiple sprites without copying. If the implicit `./icons` folder does not exist but `inputFiles` is populated, generation continues using only the list. An explicitly specified missing folder is an error. Duplicate paths are deduplicated, while different files with the same icon name are treated as an error.
|
||||
|
||||
`name` is stored in kebab-case and must start with a Latin letter. The React and Next.js presets produce the `stack` format.
|
||||
|
||||
### Next.js
|
||||
|
||||
Next.js uses the same `svg-sprite.config.ts` and set of options. For type checking, you can use a dedicated helper:
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
})
|
||||
```
|
||||
|
||||
The router and bundler are selected through the mode key, so switching between Turbopack and Webpack is always explicitly reflected in the generation command.
|
||||
|
||||
## Multiple sprites
|
||||
|
||||
An application can contain several independent sprites for different scopes:
|
||||
|
||||
**Problem:** one global sprite loads icons that the current screen does not need.
|
||||
|
||||
**Solution:** keep shared icons globally, and place icon sets for pages and large components in separate sprites that load alongside them.
|
||||
|
||||
```text
|
||||
global -> GlobalIcon -> shared application icons
|
||||
analytics-page -> AnalyticsPageIcon -> icons for a specific page
|
||||
file-manager -> FileManagerIcon -> icons for a large component
|
||||
```
|
||||
|
||||
- **Global sprite** contains a small set of shared icons used in different parts of the application: navigation, states, and basic actions.
|
||||
- **Page sprite** loads with a specific section and does not increase the shared sprite with icons that are not needed anywhere else.
|
||||
- **Large component sprite** encapsulates the icon set of a complex UI module, such as a file manager or editor.
|
||||
|
||||
Each group gets:
|
||||
|
||||
- its own SVG asset;
|
||||
- its own typed component;
|
||||
- a separate list of icon names;
|
||||
- a separate debug manifest;
|
||||
- an independent cache lifecycle.
|
||||
|
||||
|
||||
## TypeScript
|
||||
|
||||
The main feature of the TypeScript API is icon name autocomplete directly in the `icon` prop:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="folder" />
|
||||
// ^ the editor suggests every icon in the sprite
|
||||
```
|
||||
|
||||
SVG file names become valid `icon` values. A typo or unknown name immediately becomes a TypeScript error:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="unknown" /> // TypeScript error
|
||||
```
|
||||
|
||||
For programmatic access, the generated module exports a readonly array of all icons available in a specific sprite:
|
||||
|
||||
```ts
|
||||
import { fileManagerIconNames } from './svg-sprite'
|
||||
|
||||
// readonly ['check', 'folder', ...]
|
||||
```
|
||||
|
||||
You can use this list in custom catalogs, select components, tests, and other runtime scenarios. The `FileManagerIconName` union type is also derived from it.
|
||||
|
||||
File names containing spaces and other characters unsafe for SVG IDs remain part of the public TypeScript API. For the internal `<symbol id>`, the generator creates a stable hash ID.
|
||||
|
||||
```text
|
||||
folder open.svg -> icon="folder open" -> id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
For such names, use the generated component or the `id` from the debug manifest. The manual examples below using `#<name>` are suitable only for names that are already safe SVG IDs.
|
||||
|
||||
## Sprite formats
|
||||
|
||||
`stack` is the more modern format, so it is used by default. Icons can be rendered through `<svg><use>`, `<img>`, and CSS `background-image`.
|
||||
|
||||
`symbol` is retained for compatibility with existing integrations and supports rendering only through `<svg><use>`.
|
||||
|
||||
## Rendering methods
|
||||
|
||||
### React component - recommended
|
||||
|
||||
The generated component provides type safety and icon name autocomplete, and constructs the SVG asset URL itself.
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="check" width={24} height={24} />
|
||||
```
|
||||
|
||||
Monochrome and multicolor icons are supported through `color` and `--icon-color-N`.
|
||||
|
||||
### Manually with `<svg><use>`
|
||||
|
||||
A good low-level method that provides full control over dimensions and colors. This is exactly what the React component uses under the hood.
|
||||
|
||||
How you obtain `spriteUrl` depends on the bundler.
|
||||
|
||||
**Vite:**
|
||||
|
||||
```tsx
|
||||
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
**Webpack 5:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
**Next.js with Webpack 5 or Turbopack:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
After obtaining the URL, the icon is rendered the same way:
|
||||
|
||||
```tsx
|
||||
<svg width={24} height={24}>
|
||||
<use href={`${spriteUrl}#check`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
Vite, Webpack 5, and Next.js replace the source path with the final hashed asset URL automatically.
|
||||
|
||||
### With `<img>` - less efficient
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Done" />
|
||||
```
|
||||
|
||||
The SVG loads as an isolated image: its colors cannot be changed through `color` or `--icon-color-N`.
|
||||
|
||||
### With CSS `background-image` - less efficient
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
Like `<img>`, this method does not allow you to control internal SVG colors. The path is specified relative to the CSS file, and Vite/Webpack replaces it with the final hashed URL during the build.
|
||||
### 3. Add generation
|
||||
|
||||
### With CSS mask - less efficient
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A mask retains only the silhouette and colors it with a single color. The original colors, gradients, and distinctions between `fill` and `stroke` are lost.
|
||||
Run it for the first time:
|
||||
|
||||
## Transformations
|
||||
|
||||
All transformations are enabled by default and configured independently through `transform`.
|
||||
|
||||
| Option | Default | What it does |
|
||||
|---|---|---|
|
||||
| `removeSize` | `true` | Removes `width` and `height` from the root `<svg>` while preserving the existing `viewBox`. The icon size is then set externally. |
|
||||
| `replaceColors` | `true` | Replaces `fill` and `stroke` colors with `--icon-color-N`. For a monochrome icon, the fallback becomes `currentColor`; for a multicolor icon, the original colors are preserved. |
|
||||
| `addTransition` | `true` | Adds `style="transition:fill 0.3s,stroke 0.3s;"` directly to colored SVG elements. An existing `transition` is not overwritten. |
|
||||
|
||||
To disable a transformation, pass `false` for the corresponding option. For more details about the result of `replaceColors`, see [Icon color management](#icon-color-management).
|
||||
|
||||
## Icon color management
|
||||
|
||||
When color replacement is enabled, the generator analyzes `fill` and `stroke` and converts them to CSS custom properties.
|
||||
|
||||
### Monochrome icons
|
||||
|
||||
If one color is found, the fallback is replaced with `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```bash
|
||||
npm run sprites
|
||||
```
|
||||
|
||||
The color is controlled by the CSS `color` property of the outer `<svg>` or its parent.
|
||||
The package will generate `AppIcon`, TypeScript types, and a separate SVG sprite.
|
||||
|
||||
### Multicolor icons
|
||||
### 4. Use it like a regular icon
|
||||
|
||||
Each unique color gets a separate variable with the original fallback:
|
||||
```tsx
|
||||
import { AppIcon } from '@/ui/app-icons'
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
```
|
||||
|
||||
The page can override only the required colors:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
export default function SearchButton() {
|
||||
return (
|
||||
<button type="button">
|
||||
<AppIcon icon="search" width={20} height={20} />
|
||||
Search
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Color limitations
|
||||
This is a Server Component. The icon does not require a provider, `'use client'`, or manual URL construction.
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset`, and `initial` are not replaced;
|
||||
- colors in `fill`, `stroke`, and inline `style` attributes are handled most reliably;
|
||||
- CSS classes and external stylesheets inside the source SVG are not the primary transformation use case;
|
||||
- gradients, patterns, filters, and `url(#...)` values require separate verification and may be incompatible with automatic color replacement;
|
||||
- page CSS variables are available with `<svg><use>`, but are not available inside `<img>` and `background-image`.
|
||||
## Typed React component with autocomplete
|
||||
|
||||
## Caching
|
||||
Each sprite gets its own ready-to-use component. The `icon` prop is derived from the actual SVG names, so your editor shows the exact list of available icons and TypeScript catches typos immediately.
|
||||
|
||||
The Vite, Webpack, and Next.js targets emit the sprite as a separate asset with a content hash:
|
||||
```tsx
|
||||
<AppIcon icon="search" /> // available icon
|
||||
<AppIcon icon="serach" /> // TypeScript error
|
||||
```
|
||||
|
||||
After you add a new SVG icon and run generation again, its name automatically appears in the types and autocomplete. There is no need to maintain components, union types, or a name registry manually.
|
||||
|
||||
## Next.js App Router and SSR out of the box
|
||||
|
||||
Generated components work in Server Components, SSR, and SSG without `'use client'`.
|
||||
|
||||
Using an icon does not turn the page into a Client Component, require a provider, or create an additional hydration boundary.
|
||||
|
||||
The same component can be used in `page.tsx`, `layout.tsx`, and both server and client components.
|
||||
|
||||
## Multiple sprites instead of one global sprite
|
||||
|
||||
Your project is not limited to a single icon set. Create independent sprites for shared elements, individual pages, and large UI modules.
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AnalyticsIcon icon="chart" />
|
||||
<EditorIcon icon="bold" />
|
||||
```
|
||||
|
||||
Each set gets its own typed component and SVG asset, so application sections do not load icons they do not need.
|
||||
|
||||
## Store each icon only once
|
||||
|
||||
Each SVG icon is stored once in the source library and can be included in any number of sprites. Shared icons do not need to be copied between pages and modules: a single source updates every set.
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
search.svg ─┬─→ AppIcon
|
||||
├─→ AnalyticsIcon
|
||||
└─→ EditorIcon
|
||||
```
|
||||
|
||||
This provides the following properties:
|
||||
Sprites are split for performance, while the source icon library remains unified.
|
||||
|
||||
- the SVG is cached independently of JavaScript;
|
||||
- changes to React code do not alter the sprite contents;
|
||||
- icon changes produce a new hashed asset;
|
||||
- one file is used by every instance of the generated component;
|
||||
- SVG path data is absent from JavaScript chunks.
|
||||
## Browser caching
|
||||
|
||||
The Vite target prevents inlining through `?no-inline`. The Webpack 5 target uses Asset Modules through `new URL(..., import.meta.url)`.
|
||||
With a standard Vite, Webpack, or Next.js configuration, each sprite is emitted as a separate versioned SVG file.
|
||||
|
||||
## SpriteViewer
|
||||
As long as the icon set does not change, the browser can reuse its cached copy independently of JavaScript application updates.
|
||||
|
||||
`SpriteViewer` is a React component for viewing generated sprites inside an application's debug route.
|
||||
Changes to React components do not require downloading the geometry of every icon again.
|
||||
|
||||
It uses separate manifests and displays:
|
||||
## JavaScript without SVG bloat
|
||||
|
||||
- sprite groups;
|
||||
- the icon list and count;
|
||||
- search and the system light/dark theme;
|
||||
- a preview modal with the `viewBox` and color variable controls;
|
||||
- React, SVG, IMG, and CSS examples with code copying.
|
||||
Icon paths remain in external SVG assets and do not add to application chunks.
|
||||
|
||||
Production components do not import debug manifests. How you integrate the Viewer depends on the bundler:
|
||||
|
||||
- [React + Vite: automatic `import.meta.glob`](docs/en/react-vite.md#6-add-a-debug-page);
|
||||
- [React + Webpack 5: static `import()`](docs/en/react-webpack.md#6-add-a-debug-page);
|
||||
- [Next.js App Router](docs/en/next-app.md#5-add-spriteviewer);
|
||||
- [Next.js Pages Router](docs/en/next-pages.md#5-add-spriteviewer).
|
||||
|
||||
The Viewer is imported from the separate `@gromlab/svg-sprites/react` client entry point and is not included in production icon components.
|
||||
|
||||
### Viewer theme
|
||||
|
||||
By default, `colorTheme="auto"`: the Viewer follows `prefers-color-scheme` and responds to system theme changes. The application theme can be passed explicitly:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```text
|
||||
React code → JavaScript chunks
|
||||
SVG icons → separate SVG assets
|
||||
```
|
||||
|
||||
Valid `colorTheme` values are `auto`, `light`, and `dark`. When the theme is controlled externally, the built-in switch is hidden. To keep it and update the application theme through the Viewer, pass a callback:
|
||||
JavaScript handles the interface and behavior, while graphics are loaded and cached separately.
|
||||
|
||||
## Built-in SVG transformations
|
||||
|
||||
During generation, the package automatically prepares source SVG files for use in the UI:
|
||||
|
||||
- removes fixed `width` and `height` attributes;
|
||||
- preserves the existing `viewBox`;
|
||||
- converts `fill` and `stroke` values to CSS variables;
|
||||
- adds smooth transitions directly to colored icon elements.
|
||||
|
||||
Each transformation can be configured or disabled independently.
|
||||
|
||||
## Control every color with CSS
|
||||
|
||||
During generation, `fill` and `stroke` colors are automatically converted to `--icon-color-N` CSS variables.
|
||||
|
||||
A monochrome icon inherits `currentColor`:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
For a multicolor icon, each color can be changed independently:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
Create themes, states, and hover effects without editing the SVG or making additional copies of the icon.
|
||||
|
||||
## SpriteViewer: every sprite on one debug page
|
||||
|
||||
`SpriteViewer` renders all standalone, React, and Next.js project sprites in one place. One Web Component owns the visuals, while React uses a thin bridge to it.
|
||||
|
||||
For each icon, you can see the generated CSS variables and their fallback colors. Change the values directly in the Viewer and see the result immediately.
|
||||
|
||||
It also provides ready-to-use integration examples for:
|
||||
|
||||
- React;
|
||||
- `<svg><use>`;
|
||||
- `<img>`;
|
||||
- CSS.
|
||||
|
||||

|
||||
|
||||
The Viewer is added only to an internal debug page and does not become part of the generated icon components.
|
||||
|
||||
Bare standalone loads the Viewer as a browser script and HTML element; bundler modes use the npm entry, while React and Next.js import `SpriteViewer` from `@gromlab/svg-sprites/react`.
|
||||
|
||||
## Standalone, React, and Next.js
|
||||
|
||||
The package generates low-level standalone sprites for static HTML, Vite, and Webpack 5, plus typed React components for React and Next.js.
|
||||
|
||||
## Clean Git history
|
||||
|
||||
Bundler and framework modes create a local `.gitignore` that excludes generated files and keeps them from cluttering project history, pull requests, and the codebase. Bare `standalone` leaves the repository policy to the application.
|
||||
|
||||
In bundler and framework modes, the repository contains the source SVG files, configuration, and `.gitignore` rule, while sprites, components, and types are regenerated locally and in CI through `prebuild`.
|
||||
|
||||
## Only icons in production
|
||||
|
||||
Generation can run entirely through `npx`, without adding the package to the project. Install it as a development dependency only when you need the Viewer, config types, or the programmatic API.
|
||||
|
||||
Production components use only local generated code, styles, and the external SVG file. The compiler and CLI are not bundled into the client application, while `SpriteViewer` is imported separately only where a debug page is needed.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [React + Vite](docs/en/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||
- [Next.js App Router](docs/en/next-app.md)
|
||||
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||
- [Legacy mode](docs/en/legacy.md)
|
||||
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||
- [Programmatic API](docs/en/programmatic-api.md)
|
||||
This README introduces the project's capabilities and demonstrates the primary use case. For setup, choose the guide for your stack.
|
||||
|
||||
### Quick start
|
||||
|
||||
- [Bare standalone](docs/en/guides/standalone.md)
|
||||
- [Standalone + Vite](docs/en/guides/standalone-vite.md)
|
||||
- [Standalone + Webpack 5](docs/en/guides/standalone-webpack.md)
|
||||
- [React + Vite](docs/en/guides/react-vite.md)
|
||||
- [React + Webpack 5](docs/en/guides/react-webpack.md)
|
||||
- [Next.js App Router + Turbopack](docs/en/guides/next-app-turbopack.md)
|
||||
- [Next.js App Router + Webpack](docs/en/guides/next-app-webpack.md)
|
||||
- [Next.js Pages Router + Turbopack](docs/en/guides/next-pages-turbopack.md)
|
||||
- [Next.js Pages Router + Webpack](docs/en/guides/next-pages-webpack.md)
|
||||
|
||||
### Technical resources
|
||||
|
||||
- [Documentation index](docs/en/README.md)
|
||||
- [Technical reference](docs/en/reference/technical.md)
|
||||
- [Programmatic API](docs/en/reference/programmatic-api.md)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
561
README_RU.md
561
README_RU.md
@@ -4,394 +4,281 @@
|
||||
|
||||
 
|
||||
|
||||
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
|
||||
`@gromlab/svg-sprites` — генератор SVG-спрайтов для современных веб-приложений. Он собирает выбранные SVG-иконки в один или несколько внешних кешируемых спрайтов и подготавливает их для использования в интерфейсе.
|
||||
|
||||

|
||||
Для vanilla-приложений с Vite/Webpack пакет создаёт нативный типизированный Web Component, а для React и Next.js — React-компонент. SVG во всех случаях остаётся отдельным кешируемым asset.
|
||||
|
||||
## Навигация
|
||||
## SVG-спрайт так же прост, как обычная SVG-иконка
|
||||
|
||||
- [Возможности](#возможности)
|
||||
- [Таблица поддержки](#таблица-поддержки)
|
||||
- [Требования](#требования)
|
||||
- [Быстрый старт](#быстрый-старт)
|
||||
- [React + Vite](docs/ru/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||
- [Next.js App Router](docs/ru/next-app.md)
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
||||
- [Конфигурация](#конфигурация)
|
||||
- [React](#react)
|
||||
- [Next.js](#nextjs)
|
||||
- [Множественные спрайты](#множественные-спрайты)
|
||||
- [TypeScript](#typescript)
|
||||
- [Форматы спрайтов](#форматы-спрайтов)
|
||||
- [Способы отображения](#способы-отображения)
|
||||
- [Трансформации](#трансформации)
|
||||
- [Управление цветом иконок](#управление-цветом-иконок)
|
||||
- [Кеширование](#кеширование)
|
||||
- [SpriteViewer](#spriteviewer)
|
||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
||||
- [Документация](#документация)
|
||||
Для всего спрайта генерируется один типизированный React-компонент. Выберите иконку через `icon`, а редактор покажет автокомплит всех доступных имён.
|
||||
|
||||
## Возможности
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
- **AI-agent friendly** — репозиторий содержит готовый skill с актуальной документацией для настройки, миграции и диагностики `@gromlab/svg-sprites`.
|
||||
- **TypeScript-friendly** — типизированные React-компоненты, union-типы и runtime-списки доступных иконок.
|
||||
- **Чистая генерация** — generated-файлы автоматически исключаются из Git, спрайт не нужно вручную размещать в `public`, а генератор обновляет только принадлежащие ему файлы.
|
||||
- **Общие иконки без копирования** — SVG из локальной папки и `inputFiles` объединяются в один спрайт; один файл можно использовать в нескольких спрайтах.
|
||||
- **Встроенное интерактивное превью** — `<SpriteViewer>` подключается как страница приложения и показывает переданные React- и Next.js-спрайты с поиском, настройкой цветов и примерами использования.
|
||||
- **Настраиваемые трансформации SVG** — удаление `width` и `height` с сохранением `viewBox`, замена исходных цветов на CSS-переменные и transitions для `fill` и `stroke`.
|
||||
- **Отдельный кешируемый SVG asset** — SVG path-данные не попадают в JavaScript chunks, а сборщик выпускает файл с content hash.
|
||||
- **Множественные спрайты** — независимые React- и Next.js-модули со своими компонентами, типами и SVG assets.
|
||||
- **Server-first Next.js** — generated-компоненты работают в Server Components, SSR и SSG без директивы `'use client'`.
|
||||
- **Форматы под разные сценарии** — React и Next.js используют `stack`, legacy-режим также поддерживает `symbol` для существующих интеграций.
|
||||
Компонент принимает привычные SVG-атрибуты: размеры, `color`, `className`, `style`, `aria-*` и обработчики событий. Если нужен внешний контейнер, добавьте `wrapped`.
|
||||
|
||||
## Таблица поддержки
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
| Среда | Ключ мода API | Статус |
|
||||
|---|---|---|
|
||||
| React + Vite | `react@vite` | Готово |
|
||||
| React + Webpack 5 | `react@webpack` | Готово |
|
||||
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Готово |
|
||||
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Готово |
|
||||
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Готово |
|
||||
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Готово |
|
||||
| Vue | — | Скоро |
|
||||
| Standalone | — | Скоро |
|
||||
В приложении не приходится работать со спрайтом напрямую. Вы используете его так же, как обычную SVG-иконку, но получаете один компонент, автокомплит и TypeScript-проверку всех имён.
|
||||
|
||||
## Требования
|
||||
|
||||
- Node.js 18 или новее;
|
||||
- пакет распространяется только как ESM и подключается через `import`;
|
||||
- React 18 или 19 требуется только для generated-компонентов и точки входа `@gromlab/svg-sprites/react`;
|
||||
- для типизации subpath exports используйте TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
Для быстрого старта воспользуйтесь инструкцией для вашего стека:
|
||||
|
||||
- [React + Vite](docs/ru/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||
- [Next.js App Router](docs/ru/next-app.md)
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
||||
|
||||
## Конфигурация
|
||||
|
||||
### React
|
||||
В `standalone@vite` и `standalone@webpack` тот же подход доступен без React:
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
import { defineAppIconElement } from './app-icons'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: [
|
||||
'../../shared/icons/check.svg',
|
||||
defineAppIconElement()
|
||||
```
|
||||
|
||||
```html
|
||||
<app-icon icon="search" style="font-size: 24px"></app-icon>
|
||||
```
|
||||
|
||||
Bare `standalone` остаётся минимальным и генерирует только SVG asset и JSON manifest без JavaScript runtime.
|
||||
|
||||
## AI-friendly из коробки
|
||||
|
||||
`@gromlab/svg-sprites` сразу рассчитан на работу с AI-агентами. Подключите готовый skill и поручите агенту настройку, миграцию или диагностику без длинных инструкций и ручного изучения документации.
|
||||
|
||||
[🇷🇺 Скачать AI skill (на русском)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites-ru.zip)
|
||||
|
||||
[🇬🇧 Скачать AI skill (на английском)](https://github.com/gromlab-ru/svg-sprites/releases/latest/download/svg-sprites.zip)
|
||||
|
||||
## От SVG до компонента за четыре шага
|
||||
|
||||
Основной пример использует Next.js App Router и Turbopack.
|
||||
|
||||
### 1. Генерируйте без установки пакета
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites --help
|
||||
```
|
||||
|
||||
`npx` временно скачивает CLI, не добавляет `@gromlab/svg-sprites` в
|
||||
`package.json`, а generated production runtime не импортирует package.
|
||||
|
||||
### 2. Укажите нужные иконки
|
||||
|
||||
SVG могут оставаться в существующей структуре проекта:
|
||||
|
||||
```text
|
||||
src/
|
||||
├── assets/icons/
|
||||
│ ├── search.svg
|
||||
│ └── settings.svg
|
||||
├── features/profile/
|
||||
│ └── user.svg
|
||||
└── ui/app-icons/
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Создайте конфигурацию спрайта:
|
||||
|
||||
```ts
|
||||
// src/ui/app-icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'app',
|
||||
input: [
|
||||
'../../assets/icons/search.svg',
|
||||
'../../assets/icons/settings.svg',
|
||||
'../../features/profile/user.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
| Опция | Тип | По умолчанию | Назначение |
|
||||
|---|---|---|---|
|
||||
| `name` | `string` | Имя папки | Имя спрайта, компонента и публичных типов |
|
||||
| `description` | `string` | Нет | Описание для типов и debug-манифеста |
|
||||
| `inputFolder` | `string` | `./icons` | Папка с исходными SVG относительно конфига |
|
||||
| `inputFiles` | `string[]` | `[]` | Дополнительные SVG-файлы относительно конфига |
|
||||
| `transform` | `TransformOptions` | Все включены | [Настройки трансформации](#трансформации) исходных SVG |
|
||||
| `generatedNotice` | `boolean` | `true` | Полное либо короткое предупреждение в generated-файлах |
|
||||
|
||||
`inputFolder` и `inputFiles` объединяются в один спрайт, поэтому один SVG-файл можно использовать в нескольких спрайтах без копирования. Если неявной папки `./icons` нет, но `inputFiles` заполнен, генерация продолжается только по списку. Явно указанная отсутствующая папка считается ошибкой. Одинаковые пути дедуплицируются, а разные файлы с одинаковым именем иконки считаются ошибкой.
|
||||
|
||||
`name` записывается в kebab-case и должно начинаться с латинской буквы. React и Next.js presets создают формат `stack`.
|
||||
|
||||
### Next.js
|
||||
|
||||
Next.js использует тот же `svg-sprite.config.ts` и набор опций. Для типизации можно использовать отдельный хелпер:
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
})
|
||||
```
|
||||
|
||||
Роутер и сборщик выбираются через mode key, поэтому переключение между Turbopack и Webpack всегда явно отражено в команде генерации.
|
||||
|
||||
## Множественные спрайты
|
||||
|
||||
Приложение может содержать несколько независимых спрайтов с разной областью использования:
|
||||
|
||||
**Проблема:** один глобальный спрайт загружает иконки, которые текущему экрану не нужны.
|
||||
|
||||
**Решение:** общие иконки хранить глобально, а наборы страниц и крупных компонентов — в отдельных спрайтах, загружаемых вместе с ними.
|
||||
|
||||
```text
|
||||
global → GlobalIcon → общие иконки приложения
|
||||
analytics-page → AnalyticsPageIcon → иконки отдельной страницы
|
||||
file-manager → FileManagerIcon → иконки крупного компонента
|
||||
```
|
||||
|
||||
- **Глобальный спрайт** содержит небольшие общие иконки, используемые в разных частях приложения: навигацию, состояния и базовые действия.
|
||||
- **Спрайт страницы** загружается вместе с конкретным разделом и не увеличивает общий спрайт иконками, которые больше нигде не нужны.
|
||||
- **Спрайт крупного компонента** инкапсулирует собственный набор иконок сложного UI-модуля, например файлового менеджера или редактора.
|
||||
|
||||
Каждая группа получает:
|
||||
|
||||
- собственный SVG asset;
|
||||
- собственный типизированный компонент;
|
||||
- отдельный список имён иконок;
|
||||
- отдельный debug-манифест;
|
||||
- независимый cache lifecycle.
|
||||
|
||||
|
||||
## TypeScript
|
||||
|
||||
Главная возможность TypeScript API — автодополнение имён иконок непосредственно в prop `icon`:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="folder" />
|
||||
// ↑ редактор предлагает все иконки спрайта
|
||||
```
|
||||
|
||||
Имена SVG-файлов становятся допустимыми значениями `icon`. Опечатка или неизвестное имя сразу становятся ошибкой TypeScript:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Для программного доступа generated-модуль экспортирует readonly-массив всех доступных иконок конкретного спрайта:
|
||||
|
||||
```ts
|
||||
import { fileManagerIconNames } from './svg-sprite'
|
||||
|
||||
// readonly ['check', 'folder', ...]
|
||||
```
|
||||
|
||||
Этот список можно использовать в собственных каталогах, select-компонентах, тестах и других runtime-сценариях. Из него также выводится union-тип `FileManagerIconName`.
|
||||
|
||||
Имена файлов с пробелами и другими небезопасными для SVG ID символами остаются частью публичного TypeScript API. Для внутреннего `<symbol id>` генератор создаёт стабильный hash ID.
|
||||
|
||||
```text
|
||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
Для таких имён используйте generated-компонент или `id` из debug-манифеста. Ручные примеры ниже с `#<имя>` подходят только для имён, которые уже являются безопасными SVG ID.
|
||||
|
||||
## Форматы спрайтов
|
||||
|
||||
`stack` — более современный формат, поэтому он используется по умолчанию. Иконки можно отображать через `<svg><use>`, `<img>` и CSS `background-image`.
|
||||
|
||||
`symbol` сохраняется для совместимости с существующими интеграциями и поддерживает отображение только через `<svg><use>`.
|
||||
|
||||
## Способы отображения
|
||||
|
||||
### React-компонент — рекомендуется
|
||||
|
||||
Generated-компонент предоставляет типизацию, автодополнение имён иконок и сам формирует URL SVG asset.
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="check" width={24} height={24} />
|
||||
```
|
||||
|
||||
Через `color` и `--icon-color-N` доступны одноцветные и многоцветные иконки.
|
||||
|
||||
### Самостоятельно через `<svg><use>`
|
||||
|
||||
Хороший низкоуровневый способ с полным управлением размерами и цветами. React-компонент под капотом использует именно его.
|
||||
|
||||
Способ получения `spriteUrl` зависит от сборщика.
|
||||
|
||||
**Vite:**
|
||||
|
||||
```tsx
|
||||
import spriteUrl from './svg-sprite/generated/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
**Webpack 5:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
**Next.js с Webpack 5 или Turbopack:**
|
||||
|
||||
```tsx
|
||||
const spriteUrl = new URL(
|
||||
'./svg-sprite/generated/sprite.svg',
|
||||
import.meta.url,
|
||||
).href
|
||||
```
|
||||
|
||||
После получения URL иконка отображается одинаково:
|
||||
|
||||
```tsx
|
||||
<svg width={24} height={24}>
|
||||
<use href={`${spriteUrl}#check`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
Vite, Webpack 5 и Next.js сами заменяют исходный путь на итоговый URL asset с hash.
|
||||
|
||||
### Через `<img>` — менее эффективно
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Готово" />
|
||||
```
|
||||
|
||||
SVG загружается как изолированное изображение: изменить его цвета через `color` или `--icon-color-N` нельзя.
|
||||
|
||||
### Через CSS `background-image` — менее эффективно
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
Как и `<img>`, этот способ не позволяет управлять внутренними цветами SVG. Путь указывается относительно CSS-файла, а Vite/Webpack заменяет его на итоговый URL с hash при сборке.
|
||||
### 3. Добавьте генерацию
|
||||
|
||||
### Через CSS mask — менее эффективно
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Mask оставляет только силуэт и окрашивает его одним цветом. Исходные цвета, gradients и различия между `fill` и `stroke` теряются.
|
||||
Первый запуск:
|
||||
|
||||
## Трансформации
|
||||
|
||||
Все трансформации включены по умолчанию и настраиваются независимо через `transform`.
|
||||
|
||||
| Опция | По умолчанию | Что делает |
|
||||
|---|---|---|
|
||||
| `removeSize` | `true` | Удаляет `width` и `height` с корневого `<svg>`, сохраняя существующий `viewBox`. Размер иконки после этого задаётся снаружи. |
|
||||
| `replaceColors` | `true` | Заменяет цвета `fill` и `stroke` на `--icon-color-N`. Для одноцветной иконки fallback становится `currentColor`, для многоцветной сохраняются исходные цвета. |
|
||||
| `addTransition` | `true` | Добавляет `style="transition:fill 0.3s,stroke 0.3s;"` непосредственно цветным элементам SVG. Существующий `transition` не перезаписывается. |
|
||||
|
||||
Чтобы отключить преобразование, передайте для соответствующей опции `false`. Подробнее о результате `replaceColors` — в разделе [«Управление цветом иконок»](#управление-цветом-иконок).
|
||||
|
||||
## Управление цветом иконок
|
||||
|
||||
При включённой замене цветов генератор анализирует `fill` и `stroke` и преобразует их в CSS custom properties.
|
||||
|
||||
### Монохромные иконки
|
||||
|
||||
Если найден один цвет, fallback заменяется на `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```bash
|
||||
npm run sprites
|
||||
```
|
||||
|
||||
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
|
||||
Пакет создаст `AppIcon`, TypeScript-типы и отдельный SVG-спрайт.
|
||||
|
||||
### Многоцветные иконки
|
||||
### 4. Используйте как обычную иконку
|
||||
|
||||
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
|
||||
```tsx
|
||||
import { AppIcon } from '@/ui/app-icons'
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
```
|
||||
|
||||
Страница может заменить только необходимые цвета:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
export default function SearchButton() {
|
||||
return (
|
||||
<button type="button">
|
||||
<AppIcon icon="search" width={20} height={20} />
|
||||
Найти
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Ограничения цветов
|
||||
Это Server Component. Для иконки не нужны provider, `'use client'` или ручная сборка URL.
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
|
||||
- цвета в атрибутах `fill`, `stroke` и inline `style` обрабатываются надёжнее всего;
|
||||
- CSS-классы и внешние stylesheets внутри исходного SVG не являются основным сценарием трансформации;
|
||||
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
|
||||
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
|
||||
## Типизированный React-компонент с автокомплитом
|
||||
|
||||
## Кеширование
|
||||
Каждый спрайт получает собственный готовый компонент. Свойство `icon` формируется из реальных имён SVG, поэтому редактор показывает точный список доступных иконок, а TypeScript сразу обнаруживает опечатки.
|
||||
|
||||
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
|
||||
```tsx
|
||||
<AppIcon icon="search" /> // доступная иконка
|
||||
<AppIcon icon="serach" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
После добавления новой SVG-иконки и повторной генерации её имя автоматически появляется в типах и автокомплите. Не нужно вручную поддерживать компоненты, union-типы или реестр имён.
|
||||
|
||||
## Next.js App Router и SSR из коробки
|
||||
|
||||
Generated-компоненты работают в Server Components, SSR и SSG без `'use client'`.
|
||||
|
||||
Подключение иконки не переносит страницу на клиент, не требует provider и не создаёт дополнительную границу гидратации.
|
||||
|
||||
Один и тот же компонент можно использовать в `page.tsx`, `layout.tsx`, серверных и клиентских компонентах.
|
||||
|
||||
## Множественные спрайты вместо одного глобального
|
||||
|
||||
Проект не ограничен одним набором иконок. Создавайте независимые спрайты для общих элементов, отдельных страниц и крупных UI-модулей.
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AnalyticsIcon icon="chart" />
|
||||
<EditorIcon icon="bold" />
|
||||
```
|
||||
|
||||
Каждый набор получает собственный типизированный компонент и SVG asset, поэтому разделы приложения не несут иконки, которые им не нужны.
|
||||
|
||||
## Каждая иконка хранится в одном экземпляре
|
||||
|
||||
В библиотеке исходников каждая SVG-иконка хранится в одном экземпляре и может входить в любое количество спрайтов. Общие иконки не приходится копировать между страницами и модулями: они обновляются для всех наборов из одного места.
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
search.svg ─┬─→ AppIcon
|
||||
├─→ AnalyticsIcon
|
||||
└─→ EditorIcon
|
||||
```
|
||||
|
||||
Это даёт следующие свойства:
|
||||
Спрайты разделяются ради производительности, но библиотека исходных иконок остаётся единой.
|
||||
|
||||
- SVG кешируется независимо от JavaScript;
|
||||
- изменение React-кода не меняет содержимое спрайта;
|
||||
- изменение иконок создаёт новый hash asset;
|
||||
- один файл используется всеми экземплярами generated-компонента;
|
||||
- SVG path-данные отсутствуют в JavaScript chunks.
|
||||
## Браузерное кеширование
|
||||
|
||||
Vite target запрещает inline через `?no-inline`. Webpack 5 target использует Asset Modules через `new URL(..., import.meta.url)`.
|
||||
При стандартной конфигурации Vite, Webpack или Next.js каждый спрайт выпускается отдельным версионированным SVG-файлом.
|
||||
|
||||
## SpriteViewer
|
||||
Пока набор иконок не меняется, браузер может использовать сохранённую копию независимо от обновлений JavaScript приложения.
|
||||
|
||||
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
|
||||
Изменение React-компонентов не требует повторно загружать геометрию всех иконок.
|
||||
|
||||
Он использует отдельные манифесты и показывает:
|
||||
## JavaScript без SVG-балласта
|
||||
|
||||
- группы спрайтов;
|
||||
- список и количество иконок;
|
||||
- поиск и системную светлую/тёмную тему;
|
||||
- модальное превью с `viewBox` и настройкой цветовых переменных;
|
||||
- примеры React, SVG, IMG и CSS с копированием кода.
|
||||
Контуры иконок остаются во внешних SVG assets и не увеличивают chunks приложения.
|
||||
|
||||
Production-компоненты не импортируют debug-манифесты. Способ подключения Viewer зависит от сборщика:
|
||||
|
||||
- [React + Vite: автоматический `import.meta.glob`](docs/ru/react-vite.md#6-добавьте-debug-страницу);
|
||||
- [React + Webpack 5: статические `import()`](docs/ru/react-webpack.md#6-добавьте-debug-страницу);
|
||||
- [Next.js App Router](docs/ru/next-app.md#5-добавьте-spriteviewer);
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md#5-добавьте-spriteviewer).
|
||||
|
||||
Viewer подключается из отдельной клиентской точки входа `@gromlab/svg-sprites/react` и не попадает в production-компоненты иконок.
|
||||
|
||||
### Тема Viewer
|
||||
|
||||
По умолчанию `colorTheme="auto"`: Viewer следует `prefers-color-scheme` и реагирует на смену системной темы. Тему приложения можно передать явно:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```text
|
||||
React-код → JavaScript chunks
|
||||
SVG-иконки → отдельные SVG assets
|
||||
```
|
||||
|
||||
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
|
||||
JavaScript отвечает за интерфейс и поведение, а графика загружается и кешируется отдельно.
|
||||
|
||||
## Трансформации SVG из коробки
|
||||
|
||||
Во время генерации пакет автоматически подготавливает исходные SVG для интерфейса:
|
||||
|
||||
- удаляет фиксированные `width` и `height`;
|
||||
- сохраняет существующий `viewBox`;
|
||||
- преобразует `fill` и `stroke` в CSS-переменные;
|
||||
- добавляет плавные transitions непосредственно в цветные элементы иконки.
|
||||
|
||||
Каждую трансформацию можно настроить или отключить независимо.
|
||||
|
||||
## Каждый цвет под контролем CSS
|
||||
|
||||
При генерации цвета `fill` и `stroke` автоматически преобразуются в CSS-переменные `--icon-color-N`.
|
||||
|
||||
Монохромная иконка наследует `currentColor`:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
В многоцветной иконке каждый цвет можно менять отдельно:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
Темы, состояния и hover-эффекты создаются без редактирования SVG и дополнительных копий иконки.
|
||||
|
||||
## SpriteViewer: все спрайты на одной debug-странице
|
||||
|
||||
`SpriteViewer` рендерит все standalone, React и Next.js спрайты проекта в одном месте. Один Web Component отвечает за визуал, а React использует тонкий bridge к нему.
|
||||
|
||||
Для каждой иконки видны созданные CSS-переменные и их fallback-цвета. Значения можно менять прямо в Viewer и сразу наблюдать результат.
|
||||
|
||||
Здесь же доступны готовые примеры подключения через:
|
||||
|
||||
- React;
|
||||
- `<svg><use>`;
|
||||
- `<img>`;
|
||||
- CSS.
|
||||
|
||||

|
||||
|
||||
Viewer подключается только к внутренней debug-странице и не становится частью generated-компонентов иконок.
|
||||
|
||||
Bare standalone подключает Viewer через browser script и HTML element; bundler modes используют npm entry, а React и Next.js импортируют `SpriteViewer` из `@gromlab/svg-sprites/react`.
|
||||
|
||||
## Standalone, React и Next.js
|
||||
|
||||
Пакет генерирует низкоуровневые standalone-спрайты для static HTML, Vite и Webpack 5, а также типизированные React-компоненты для React и Next.js.
|
||||
|
||||
## Чистый Git
|
||||
|
||||
Bundler и framework modes создают локальный `.gitignore`, который исключает generated-файлы и не позволяет им засорять историю, pull requests и код проекта. Bare `standalone` оставляет политику репозитория приложению.
|
||||
|
||||
В bundler и framework modes в репозитории остаются исходные SVG, конфигурация и правило `.gitignore`, а локально и в CI спрайты, компоненты и типы заново создаются через `prebuild`.
|
||||
|
||||
## В production только иконки
|
||||
|
||||
Генерация полностью работает через `npx`, без добавления package в проект. Устанавливайте его как development dependency, только если нужны Viewer, типы конфига или программный API.
|
||||
|
||||
Production-компоненты используют только локальный generated-код, стили и внешний SVG-файл. Compiler и CLI не попадают в клиентское приложение, а `SpriteViewer` подключается отдельно только там, где нужна debug-страница.
|
||||
|
||||
## Документация
|
||||
|
||||
- [React + Vite](docs/ru/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
||||
- [Next.js App Router](docs/ru/next-app.md)
|
||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
||||
- [Legacy mode](docs/ru/legacy.md)
|
||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
||||
- [Программный API](docs/ru/programmatic-api.md)
|
||||
README знакомит с возможностями проекта и показывает основной сценарий использования. Для настройки выберите руководство под свой стек.
|
||||
|
||||
### Быстрый старт
|
||||
|
||||
- [Bare standalone](docs/ru/guides/standalone.md)
|
||||
- [Standalone + Vite](docs/ru/guides/standalone-vite.md)
|
||||
- [Standalone + Webpack 5](docs/ru/guides/standalone-webpack.md)
|
||||
- [React + Vite](docs/ru/guides/react-vite.md)
|
||||
- [React + Webpack 5](docs/ru/guides/react-webpack.md)
|
||||
- [Next.js App Router + Turbopack](docs/ru/guides/next-app-turbopack.md)
|
||||
- [Next.js App Router + Webpack](docs/ru/guides/next-app-webpack.md)
|
||||
- [Next.js Pages Router + Turbopack](docs/ru/guides/next-pages-turbopack.md)
|
||||
- [Next.js Pages Router + Webpack](docs/ru/guides/next-pages-webpack.md)
|
||||
|
||||
### Технические материалы
|
||||
|
||||
- [Индекс документации](docs/ru/README.md)
|
||||
- [Технический справочник](docs/ru/reference/technical.md)
|
||||
- [Программный API](docs/ru/reference/programmatic-api.md)
|
||||
|
||||
## Лицензия
|
||||
|
||||
|
||||
@@ -1,58 +1,41 @@
|
||||
# Third-Party Notices
|
||||
|
||||
The distributed React entry and preview template include code from the projects listed below.
|
||||
The distributed Viewer browser bundle includes code from the projects listed below.
|
||||
|
||||
## React, React DOM and Scheduler
|
||||
## Lit
|
||||
|
||||
Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## react-colorful
|
||||
|
||||
Copyright (c) 2020 Vlad Shilov <omgovich@ya.ru>
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## clsx
|
||||
|
||||
Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
|
||||
Copyright (c) 2017 Google LLC. All rights reserved.
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
## vanilla-colorful
|
||||
|
||||
Copyright (c) 2020 Serhii Kulykov <iamkulykov@gmail.com>
|
||||
|
||||
MIT License
|
||||
|
||||
|
||||
29
docs/en/README.md
Normal file
29
docs/en/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Documentation
|
||||
|
||||
Choose one exact mode guide for setup. The guides are standalone documents and
|
||||
can also be used unchanged by AI skills.
|
||||
|
||||
## Quick Start Guides
|
||||
|
||||
| Project | Exact mode | Guide |
|
||||
|---|---|---|
|
||||
| Static HTML or custom publishing | `standalone` | [Bare standalone](guides/standalone.md) |
|
||||
| Vanilla + Vite | `standalone@vite` | [Standalone + Vite](guides/standalone-vite.md) |
|
||||
| Vanilla + Webpack 5 | `standalone@webpack` | [Standalone + Webpack](guides/standalone-webpack.md) |
|
||||
| React + Vite | `react@vite` | [React + Vite](guides/react-vite.md) |
|
||||
| React + Webpack 5 | `react@webpack` | [React + Webpack](guides/react-webpack.md) |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` | [App Router + Turbopack](guides/next-app-turbopack.md) |
|
||||
| Next.js App Router + Webpack | `next@app/webpack` | [App Router + Webpack](guides/next-app-webpack.md) |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` | [Pages Router + Turbopack](guides/next-pages-turbopack.md) |
|
||||
| Next.js Pages Router + Webpack | `next@pages/webpack` | [Pages Router + Webpack](guides/next-pages-webpack.md) |
|
||||
|
||||
Every guide follows the same order:
|
||||
|
||||
1. Generate the sprite through `npx` without adding the package to the project.
|
||||
2. Optionally install and connect the debug Viewer.
|
||||
3. Optionally type the config through the package or a local copy-paste type.
|
||||
|
||||
## Reference
|
||||
|
||||
- [Technical reference](reference/technical.md)
|
||||
- [Programmatic API](reference/programmatic-api.md)
|
||||
11
docs/en/guides/README.md
Normal file
11
docs/en/guides/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Quick Start Guides
|
||||
|
||||
- `standalone`: [bare standalone](standalone.md)
|
||||
- `standalone@vite`: [standalone with Vite](standalone-vite.md)
|
||||
- `standalone@webpack`: [standalone with Webpack](standalone-webpack.md)
|
||||
- `react@vite`: [React with Vite](react-vite.md)
|
||||
- `react@webpack`: [React with Webpack](react-webpack.md)
|
||||
- `next@app/turbopack`: [App Router with Turbopack](next-app-turbopack.md)
|
||||
- `next@app/webpack`: [App Router with Webpack](next-app-webpack.md)
|
||||
- `next@pages/turbopack`: [Pages Router with Turbopack](next-pages-turbopack.md)
|
||||
- `next@pages/webpack`: [Pages Router with Webpack](next-pages-webpack.md)
|
||||
153
docs/en/guides/next-app-turbopack.md
Normal file
153
docs/en/guides/next-app-turbopack.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Next.js App Router Turbopack SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `next@app/turbopack`: a generated typed React icon for the Next.js App Router and Turbopack.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config and source icons together:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Generate once per invocation and keep the exact Turbopack flags on both commands:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --turbopack",
|
||||
"build": "npm run sprites && next build --turbopack"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. Generated declarations are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
The generated icon has no `'use client'` directive and is Server Component-compatible. Import it directly in an App Router page or layout:
|
||||
|
||||
```tsx
|
||||
// src/app/page.tsx
|
||||
import {
|
||||
IconsIcon,
|
||||
iconsIconNames,
|
||||
} from '../ui/icons/.svg-sprite/index.js'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon icon="folder" width={24} height={24} aria-label="Files" />
|
||||
<p>{iconsIconNames.length} icons available</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Turbopack resolves the generated `new URL('../sprite.svg', import.meta.url)` and CSS Module, emitting a separate SVG asset. Keep the mode and the `--turbopack` dev/build flags aligned.
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Viewer is interactive, so place the React bridge in a separate Client Component:
|
||||
|
||||
```tsx
|
||||
// src/app/icon-debug/IconsViewer.tsx
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../../ui/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export function IconsViewer() {
|
||||
return <SpriteViewer sources={sources} title="Project icons" />
|
||||
}
|
||||
```
|
||||
|
||||
Render it from the route's Server Component:
|
||||
|
||||
```tsx
|
||||
// src/app/icon-debug/page.tsx
|
||||
import { IconsViewer } from './IconsViewer'
|
||||
|
||||
export default function IconDebugPage() {
|
||||
return <IconsViewer />
|
||||
}
|
||||
```
|
||||
|
||||
Keep the route internal or development-only. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@app/turbopack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
153
docs/en/guides/next-app-webpack.md
Normal file
153
docs/en/guides/next-app-webpack.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Next.js App Router Webpack SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `next@app/webpack`: a generated typed React icon for the Next.js App Router and Webpack 5.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config adjacent to its source icons:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'next@app/webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Generate once per invocation and keep the exact Webpack flags on both commands:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --webpack",
|
||||
"build": "npm run sprites && next build --webpack"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. Generated declarations are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
The generated icon has no `'use client'` directive and is Server Component-compatible. Import it directly in an App Router page or layout:
|
||||
|
||||
```tsx
|
||||
// src/app/page.tsx
|
||||
import {
|
||||
IconsIcon,
|
||||
iconsIconNames,
|
||||
} from '../ui/icons/.svg-sprite/index.js'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon icon="folder" width={24} height={24} aria-label="Files" />
|
||||
<p>{iconsIconNames.length} icons available</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Webpack resolves the generated `new URL('../sprite.svg', import.meta.url)` and CSS Module, emitting a separate SVG asset. Keep the mode and the `--webpack` dev/build flags aligned. If custom Next.js webpack rules process SVG through SVGR, exclude `.svg-sprite/sprite.svg` from those rules.
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Viewer is interactive, so place the React bridge in a separate Client Component:
|
||||
|
||||
```tsx
|
||||
// src/app/icon-debug/IconsViewer.tsx
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../../ui/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export function IconsViewer() {
|
||||
return <SpriteViewer sources={sources} title="Project icons" />
|
||||
}
|
||||
```
|
||||
|
||||
Render it from the route's Server Component:
|
||||
|
||||
```tsx
|
||||
// src/app/icon-debug/page.tsx
|
||||
import { IconsViewer } from './IconsViewer'
|
||||
|
||||
export default function IconDebugPage() {
|
||||
return <IconsViewer />
|
||||
}
|
||||
```
|
||||
|
||||
Keep the route internal or development-only. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@app/webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@app/webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
140
docs/en/guides/next-pages-turbopack.md
Normal file
140
docs/en/guides/next-pages-turbopack.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Next.js Pages Router Turbopack SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `next@pages/turbopack`: a generated typed React icon for the Next.js Pages Router and Turbopack.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config and source icons together:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'next@pages/turbopack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Generate once per invocation and keep the exact Turbopack flags on both commands:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --turbopack",
|
||||
"build": "npm run sprites && next build --turbopack"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. Generated declarations are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
Import the generated component and icon-name list into a Pages Router page:
|
||||
|
||||
```tsx
|
||||
// src/pages/index.tsx
|
||||
import {
|
||||
IconsIcon,
|
||||
iconsIconNames,
|
||||
} from '../ui/icons/.svg-sprite/index.js'
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon icon="folder" width={24} height={24} aria-label="Files" />
|
||||
<p>{iconsIconNames.length} icons available</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The component works with SSR, SSG, and client-side navigation. Turbopack resolves the generated SVG URL and CSS Module and emits a separate asset. Keep the mode and the `--turbopack` dev/build flags aligned.
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Pages Router does not require an App Router Client Component boundary. Use the React bridge directly in a page with a static loader array:
|
||||
|
||||
```tsx
|
||||
// src/pages/icon-debug.tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../ui/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export default function IconDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Project icons" />
|
||||
}
|
||||
```
|
||||
|
||||
Keep the page internal or development-only. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@pages/turbopack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@pages/turbopack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@pages/turbopack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
140
docs/en/guides/next-pages-webpack.md
Normal file
140
docs/en/guides/next-pages-webpack.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Next.js Pages Router Webpack SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `next@pages/webpack`: a generated typed React icon for the Next.js Pages Router and Webpack 5.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config adjacent to its source icons:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'next@pages/webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Generate once per invocation and keep the exact Webpack flags on both commands:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --webpack",
|
||||
"build": "npm run sprites && next build --webpack"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. Generated declarations are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
Import the generated component and icon-name list into a Pages Router page:
|
||||
|
||||
```tsx
|
||||
// src/pages/index.tsx
|
||||
import {
|
||||
IconsIcon,
|
||||
iconsIconNames,
|
||||
} from '../ui/icons/.svg-sprite/index.js'
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon icon="folder" width={24} height={24} aria-label="Files" />
|
||||
<p>{iconsIconNames.length} icons available</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The component works with SSR, SSG, and client-side navigation. Webpack resolves the generated SVG URL and CSS Module and emits a separate asset. Keep the mode and the `--webpack` dev/build flags aligned. If custom Next.js webpack rules process SVG through SVGR, exclude `.svg-sprite/sprite.svg` from those rules.
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Pages Router does not require an App Router Client Component boundary. Use the React bridge directly in a page with a static loader array:
|
||||
|
||||
```tsx
|
||||
// src/pages/icon-debug.tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../ui/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export default function IconDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Project icons" />
|
||||
}
|
||||
```
|
||||
|
||||
Keep the page internal or development-only. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@pages/webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@pages/webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@pages/webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
148
docs/en/guides/react-vite.md
Normal file
148
docs/en/guides/react-vite.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# React Vite SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `react@vite`: a generated typed React component with a Vite-managed SVG asset.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config and source icons together:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'react@vite',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use the exact Vite dev/build commands and generate once per invocation:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && vite",
|
||||
"build": "npm run sprites && tsc --noEmit && vite build"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. Generated declarations are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
Import the generated component and icon-name list directly:
|
||||
|
||||
```tsx
|
||||
// src/App.tsx
|
||||
import {
|
||||
IconsIcon,
|
||||
iconsIconNames,
|
||||
} from './ui/icons/.svg-sprite/index.js'
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon icon="check" width={24} height={24} aria-label="Complete" />
|
||||
<small>{iconsIconNames.length} icons available</small>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
`icon` is a generated union of SVG file names. Vite automatically handles the generated CSS Module and the `sprite.svg?no-inline` import, emitting the sprite as a separate asset. If your own TypeScript source imports Vite query assets, include Vite's ambient types:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vite/client"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Use the React `SpriteViewer` bridge with a static loader array. Keep every `import()` path a string literal:
|
||||
|
||||
```tsx
|
||||
// src/IconsDebugPage.tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('./ui/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export function IconsDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Project icons" />
|
||||
}
|
||||
```
|
||||
|
||||
Keep this component on a debug route or in an internal tool. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'react@vite',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'react@vite'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'react@vite',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
156
docs/en/guides/react-webpack.md
Normal file
156
docs/en/guides/react-webpack.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# React Webpack SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `react@webpack`: a generated typed React component using Webpack 5 Asset Modules and CSS Modules.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config adjacent to its source icons:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'react@webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use the exact Webpack 5 flags and generate once per invocation:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && webpack serve --mode development",
|
||||
"build": "npm run sprites && webpack --mode production"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. Generated declarations are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
Import the generated component and icon-name list directly:
|
||||
|
||||
```tsx
|
||||
// src/App.tsx
|
||||
import {
|
||||
IconsIcon,
|
||||
iconsIconNames,
|
||||
} from './ui/icons/.svg-sprite/index.js'
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon icon="folder" width={24} height={24} aria-label="Files" />
|
||||
<small>{iconsIconNames.length} icons available</small>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The generated component uses `new URL('../sprite.svg', import.meta.url)`, which Webpack 5 processes through Asset Modules and emits as a separate SVG asset. Exclude `.svg-sprite/sprite.svg` from SVG component or SVGR rules so they do not intercept that URL dependency.
|
||||
|
||||
The generated component also imports `react-component.module.css`. Configure `.module.css` through `css-loader` with modules enabled, plus `style-loader` or `MiniCssExtractPlugin`:
|
||||
|
||||
```js
|
||||
// webpack.config.js (relevant rule)
|
||||
export default {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.module\.css$/i,
|
||||
use: ['style-loader', { loader: 'css-loader', options: { modules: true } }],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Use the React `SpriteViewer` bridge with a static loader array. Keep every `import()` path a string literal so Webpack can create the chunk:
|
||||
|
||||
```tsx
|
||||
// src/IconsDebugPage.tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('./ui/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export function IconsDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Project icons" />
|
||||
}
|
||||
```
|
||||
|
||||
Keep this component on a debug route or in an internal tool. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'react@webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'react@webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'react@webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
156
docs/en/guides/standalone-vite.md
Normal file
156
docs/en/guides/standalone-vite.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Standalone Vite SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `standalone@vite`: a native generated Web Component with Vite-managed SVG assets.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config and source icons together:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'standalone@vite',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate once directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use the exact Vite dev/build commands and generate once per invocation:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && vite",
|
||||
"build": "npm run sprites && vite build"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. The generated JavaScript and declarations live together, and the declarations are self-contained: they do not require `@gromlab/svg-sprites`.
|
||||
|
||||
### Production usage
|
||||
|
||||
Register the generated element once, then use `<icons-icon>`:
|
||||
|
||||
```ts
|
||||
// src/main.ts
|
||||
import {
|
||||
defineIconsIconElement,
|
||||
iconsIconNames,
|
||||
} from './ui/icons/.svg-sprite/index.js'
|
||||
|
||||
defineIconsIconElement()
|
||||
console.log('Available icons:', iconsIconNames)
|
||||
```
|
||||
|
||||
```html
|
||||
<icons-icon icon="check" role="img" aria-label="Complete"></icons-icon>
|
||||
```
|
||||
|
||||
The host is `1em` by `1em`, so `font-size` controls its default size. Transformed colors use `currentColor` and custom properties such as `--icon-color-1`:
|
||||
|
||||
```css
|
||||
icons-icon {
|
||||
font-size: 24px;
|
||||
color: #2563eb;
|
||||
--icon-color-2: #dbeafe;
|
||||
}
|
||||
```
|
||||
|
||||
Vite handles the generated `sprite.svg?no-inline` import automatically and emits a separate asset. If your own TypeScript source imports Vite query assets, include Vite's ambient types:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vite/client"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Register the Viewer element, import its type, and assign the generated JavaScript manifest to `sources`:
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
import spriteManifest from './ui/icons/.svg-sprite/svg-sprite.manifest.js'
|
||||
|
||||
document.querySelector<HTMLDivElement>('#debug')!.innerHTML = `
|
||||
<gromlab-sprite-viewer viewer-title="Project icons"></gromlab-sprite-viewer>
|
||||
`
|
||||
|
||||
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
|
||||
viewer.sources = [spriteManifest]
|
||||
```
|
||||
|
||||
Keep this code on a debug route or in an internal tool. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'standalone@vite',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'standalone@vite'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'standalone@vite',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
143
docs/en/guides/standalone-webpack.md
Normal file
143
docs/en/guides/standalone-webpack.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Standalone Webpack SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `standalone@webpack`: a native generated Web Component using Webpack 5 Asset Modules.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`.
|
||||
|
||||
Keep the config adjacent to its source icons:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use a plain default object export with no package import:
|
||||
|
||||
```ts
|
||||
// src/ui/icons/svg-sprite.config.ts
|
||||
export default {
|
||||
mode: 'standalone@webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, SVG files are read from `./icons` relative to the config. A `.js` config with a default export and a `.json` config are also supported. Generate directly with:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Use the exact Webpack 5 flags and generate once per invocation:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && webpack serve --mode development",
|
||||
"build": "npm run sprites && webpack --mode production"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Do not add `predev` or `prebuild` hooks to these scripts; that would run generation twice. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Generation creates a local `.gitignore`; commit that file once, but do not commit `.svg-sprite/`. Generated declarations are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
Register the generated element once, then use `<icons-icon>`:
|
||||
|
||||
```ts
|
||||
// src/main.ts
|
||||
import {
|
||||
defineIconsIconElement,
|
||||
iconsIconNames,
|
||||
} from './ui/icons/.svg-sprite/index.js'
|
||||
|
||||
defineIconsIconElement()
|
||||
console.log('Available icons:', iconsIconNames)
|
||||
```
|
||||
|
||||
```html
|
||||
<icons-icon
|
||||
icon="check"
|
||||
role="img"
|
||||
aria-label="Complete"
|
||||
style="font-size:24px;color:#16a34a;--icon-color-1:#16a34a"
|
||||
></icons-icon>
|
||||
```
|
||||
|
||||
The generated facade uses `new URL('./sprite.svg', import.meta.url)`, which Webpack 5 processes through Asset Modules and emits as a separate asset. If the project has SVG-to-component or SVGR rules, exclude `.svg-sprite/sprite.svg` from them so they do not intercept this URL dependency. Check `output.publicPath` if the emitted URL is wrong.
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only users who need the Viewer or icon previews should install:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Register the Viewer element, import its type, and assign the generated JavaScript manifest to `sources`:
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
import spriteManifest from './ui/icons/.svg-sprite/svg-sprite.manifest.js'
|
||||
|
||||
document.querySelector<HTMLDivElement>('#debug')!.innerHTML = `
|
||||
<gromlab-sprite-viewer viewer-title="Project icons"></gromlab-sprite-viewer>
|
||||
`
|
||||
|
||||
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
|
||||
viewer.sources = [spriteManifest]
|
||||
```
|
||||
|
||||
Keep this code on a debug route or in an internal tool. Viewer is not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
Choose one of these two paths.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'standalone@webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Copy a mode-specific type directly into the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'standalone@webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'standalone@webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
171
docs/en/guides/standalone.md
Normal file
171
docs/en/guides/standalone.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Standalone SVG Sprite Quick Start
|
||||
|
||||
This guide targets the exact mode key `standalone`: static HTML or a custom asset pipeline with no generated JavaScript facade.
|
||||
|
||||
## 1. Generate the sprite
|
||||
|
||||
No package installation and no `package.json` dependency are needed. `npx` downloads the CLI temporarily, and generated runtime does not import `@gromlab/svg-sprites`; bare `standalone` does not generate a JavaScript runtime at all.
|
||||
|
||||
Keep the config next to its source icons:
|
||||
|
||||
```text
|
||||
src/ui/icons/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.json
|
||||
```
|
||||
|
||||
Create a JSON config:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "standalone",
|
||||
"name": "icons"
|
||||
}
|
||||
```
|
||||
|
||||
When `input` is omitted, the generator reads `./icons` next to the config.
|
||||
|
||||
To include SVG files from nested directories, set one glob pattern:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "standalone",
|
||||
"name": "icons",
|
||||
"input": "../assets/icons/**/*.svg"
|
||||
}
|
||||
```
|
||||
|
||||
An array can mix folders, individual SVG files, and glob patterns:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "standalone",
|
||||
"name": "icons",
|
||||
"input": [
|
||||
"../assets/icons",
|
||||
"../features/profile/user.svg",
|
||||
"../features/admin/*.svg"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
All relative paths start at the config directory. Pass the config path explicitly:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.json
|
||||
```
|
||||
|
||||
For repeatable local commands, the same temporary CLI can be used from a script:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/icons/svg-sprite.config.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Run that script once from your existing dev/build pipeline. If you use a `predev` or `prebuild` hook instead, do not also call `npm run sprites` inside the corresponding script. Bare `standalone` has no bundler-specific dev or build flag. In CI, replace `latest` with an exact package version.
|
||||
|
||||
Bare `standalone` does not create or modify `.gitignore`; the application decides whether `.svg-sprite/` is committed or ignored. It emits no declarations, facade, or component. Generated declarations in typed modes are self-contained and do not require the package.
|
||||
|
||||
### Production usage
|
||||
|
||||
The application owns the public URL, versioning, and cache policy. Copy both generated assets into the deploy output:
|
||||
|
||||
```bash
|
||||
cp src/ui/icons/.svg-sprite/sprite.svg public/assets/icons.svg
|
||||
cp src/ui/icons/.svg-sprite/svg-sprite.manifest.json public/assets/icons.manifest.json
|
||||
```
|
||||
|
||||
Use the published URL manually:
|
||||
|
||||
```html
|
||||
<svg width="24" height="24" role="img" aria-label="Complete">
|
||||
<use href="/assets/icons.svg#check"></use>
|
||||
</svg>
|
||||
```
|
||||
|
||||
Safe icon names normally match their fragment IDs. Names containing spaces or other SVG-ID-unsafe characters receive a generated ID; read that icon's `id` from `icons.manifest.json` instead of constructing the fragment yourself.
|
||||
|
||||
## 2. Debug and preview
|
||||
|
||||
This section is optional. Only install the package locally if you need the debug Viewer or an icon preview:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Without a bundler, self-host the browser bundle by copying it from `node_modules` into the deploy output:
|
||||
|
||||
```bash
|
||||
cp node_modules/@gromlab/svg-sprites/dist/viewer-element.js public/debug/viewer-element.js
|
||||
```
|
||||
|
||||
Then provide both public asset URLs through HTML attributes:
|
||||
|
||||
```html
|
||||
<script type="module" src="/debug/viewer-element.js"></script>
|
||||
|
||||
<gromlab-sprite-viewer
|
||||
viewer-title="Project icons"
|
||||
manifest-url="/assets/icons.manifest.json"
|
||||
sprite-url="/assets/icons.svg"
|
||||
></gromlab-sprite-viewer>
|
||||
```
|
||||
|
||||
For a quick preview, a pinned CDN file can replace the self-hosted script:
|
||||
|
||||
```html
|
||||
<script
|
||||
type="module"
|
||||
src="https://unpkg.com/@gromlab/svg-sprites@1.1.5/dist/viewer-element.js"
|
||||
></script>
|
||||
```
|
||||
|
||||
Self-host the file for controlled environments and pin the CDN version if you use the alternative. Viewer is optional tooling, not part of the production icon runtime.
|
||||
|
||||
## 3. Type the config
|
||||
|
||||
This guide uses a JSON config, which works without TypeScript types. If config autocomplete is needed, replace `svg-sprite.config.json` with `svg-sprite.config.ts` and choose one of these approaches.
|
||||
|
||||
### With a local package installation
|
||||
|
||||
After installing the package locally, use the helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'standalone',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
You can alternatively import `type SpriteConfig` and apply `satisfies SpriteConfig`.
|
||||
|
||||
### Without the package
|
||||
|
||||
Keep a narrow local type directly in the config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'standalone'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'standalone',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
@@ -1,102 +0,0 @@
|
||||
# Legacy mode
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
A quick guide to generating centralized SVG sprites in `symbol` and `stack` formats, with an optional HTML preview.
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Prepare the icons and config
|
||||
|
||||
```text
|
||||
project/
|
||||
├── src/assets/icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprites.config.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
// svg-sprites.config.ts
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Run generation
|
||||
|
||||
```bash
|
||||
npx svg-sprites --mode legacy .
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
public/sprites/
|
||||
├── icons.sprite.svg
|
||||
└── preview.html
|
||||
```
|
||||
|
||||
With `preview: false`, the HTML file is not created. For the `stack` format, specify `format: 'stack'`.
|
||||
|
||||
## 4. Use the symbol sprite
|
||||
|
||||
```html
|
||||
<svg width="24" height="24" aria-label="Done">
|
||||
<use href="/sprites/icons.sprite.svg#check"></use>
|
||||
</svg>
|
||||
```
|
||||
|
||||
## 5. Add a package script
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Multiple sprites
|
||||
|
||||
Add multiple entries to `sprites`:
|
||||
|
||||
```ts
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
{
|
||||
name: 'logos',
|
||||
input: 'src/assets/logos',
|
||||
format: 'stack',
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
All output files and the shared `preview.html` will be written to `output`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Config not found: make sure `svg-sprites.config.ts` is located in the specified root directory.
|
||||
- No icons: check `sprites[].input` and the `.svg` extension.
|
||||
- Preview not needed: set `preview: false`.
|
||||
|
||||
For programmatic use, see [`generateLegacy`](programmatic-api.md#generatelegacy).
|
||||
@@ -1,96 +0,0 @@
|
||||
# Migrating from 0.1.x to 1.0
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
Version 1.0 separates local generation for React and Next.js from the centralized legacy mode. The old config cannot be mixed with the new API in a single CLI invocation.
|
||||
|
||||
## CLI
|
||||
|
||||
The CLI now always requires an explicit `--mode` and a path to the configuration directory:
|
||||
|
||||
```text
|
||||
svg-sprites
|
||||
→ svg-sprites --mode <mode> <path>
|
||||
```
|
||||
|
||||
Choose a mode based on your environment:
|
||||
|
||||
| Environment | Mode |
|
||||
|---|---|
|
||||
| React + Vite | `react@vite` |
|
||||
| React + Webpack 5 | `react@webpack` |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` |
|
||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||
| Centralized legacy setup | `legacy` |
|
||||
|
||||
## React and Next.js
|
||||
|
||||
Instead of a root-level `svg-sprites.config.ts`, create a local `svg-sprite.config.ts` next to the icon set:
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'global',
|
||||
inputFolder: './icons',
|
||||
})
|
||||
```
|
||||
|
||||
For regular React, use `defineReactSpriteConfig`. A folder and an explicit list of shared SVG files can be combined using `inputFolder` and `inputFiles`.
|
||||
|
||||
The old `publicPath` and `react` options are no longer needed. The generated module is created next to the config and adds its own `.gitignore`, while Vite, Webpack, or Next.js emits the SVG as a separate asset with a content hash.
|
||||
|
||||
The `<SvgSprite icon="..." />` component is replaced by a component whose name is derived from `name`:
|
||||
|
||||
```tsx
|
||||
<GlobalIcon icon="check" />
|
||||
```
|
||||
|
||||
To browse the icons, add `<SpriteViewer>` as a debug page in the application. A separate `preview.html` is available only in legacy mode.
|
||||
|
||||
## Legacy mode
|
||||
|
||||
If you need to preserve the centralized structure, rename the helper and the format fields:
|
||||
|
||||
```ts
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'stack',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
- `defineConfig` has been replaced with `defineLegacyConfig`;
|
||||
- `sprites[].mode` has been renamed to `sprites[].format`;
|
||||
- `generate` has been replaced with `generateLegacy`;
|
||||
- `loadConfig` has been replaced with `loadLegacyConfig`;
|
||||
- `publicPath` and generation of the old shared React component have been removed.
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
svg-sprites --mode legacy .
|
||||
```
|
||||
|
||||
## Programmatic API
|
||||
|
||||
The package is distributed as ESM only. Replace `require()` with `import`.
|
||||
|
||||
`compileSpriteContent` now returns `Promise<Uint8Array>` so that the public declarations do not require `@types/node` to be installed. In Node.js, the actual result is compatible with APIs that accept `Uint8Array`.
|
||||
|
||||
## After migration
|
||||
|
||||
1. Remove the old generated files and rules that ignored the entire directory containing the source icons.
|
||||
2. Add an explicit generation command before `dev`, `build`, and `typecheck`.
|
||||
3. Run generation and type checking.
|
||||
4. Check all icons and color variables using `SpriteViewer` or the legacy `preview.html`.
|
||||
@@ -1,102 +1,4 @@
|
||||
# Next.js App Router
|
||||
# Next.js App Router Guides Moved
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
Two explicit modes are supported:
|
||||
|
||||
| Bundler | Mode key | Next.js version |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@app/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@app/webpack` | 13.4+ |
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create a sprite module
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Add generation
|
||||
|
||||
For Turbopack:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For Webpack, replace the mode key with `next@app/webpack`. In Next 13–15, Webpack is used with the regular `next build` command; in Next 16, use `next build --webpack`.
|
||||
|
||||
## 4. Use it in a Server Component
|
||||
|
||||
The generated component does not contain `'use client'`, so it can be imported directly into `page.tsx` or `layout.tsx`:
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from '@/ui/file-manager/svg-sprite'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<FileManagerIcon icon="folder" width={24} height={24} />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Next.js emits a separate SVG asset with a content hash. The same generated code is used during SSR and in the browser, with no URL mismatch.
|
||||
|
||||
## 5. Add SpriteViewer
|
||||
|
||||
The viewer is interactive, so it requires a separate Client Component boundary:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
||||
]
|
||||
|
||||
export default function SpritesPage() {
|
||||
return <SpriteViewer sources={sources} />
|
||||
}
|
||||
```
|
||||
|
||||
## Verify the bundler
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
For Next 13–15 with Webpack, use `npx next build` without the flag.
|
||||
|
||||
The Next.js command and the generator mode key must target the same bundler.
|
||||
- [App Router + Turbopack](guides/next-app-turbopack.md)
|
||||
- [App Router + Webpack](guides/next-app-webpack.md)
|
||||
|
||||
@@ -1,96 +1,4 @@
|
||||
# Next.js Pages Router
|
||||
# Next.js Pages Router Guides Moved
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
Two explicit modes are supported:
|
||||
|
||||
| Bundler | Mode key | Next.js version |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@pages/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@pages/webpack` | 12.2+ |
|
||||
|
||||
Next.js 12.2 requires React 18.
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create a sprite module
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Add generation
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For Next.js 16.2 with Turbopack, replace the mode key with `next@pages/turbopack`.
|
||||
|
||||
## 4. Use it on a page
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from '@/ui/file-manager/svg-sprite'
|
||||
|
||||
export default function FilesPage() {
|
||||
return <FileManagerIcon icon="folder" width={24} height={24} />
|
||||
}
|
||||
|
||||
export function getServerSideProps() {
|
||||
return { props: {} }
|
||||
}
|
||||
```
|
||||
|
||||
The component works the same way with SSR, SSG, and client-side navigation. Next.js emits a separate SVG asset with a content hash.
|
||||
|
||||
## 5. Add SpriteViewer
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
||||
]
|
||||
|
||||
export default function SpritesPage() {
|
||||
return <SpriteViewer sources={sources} />
|
||||
}
|
||||
```
|
||||
|
||||
## Verify the bundler
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
For Next 12–15 with Webpack, use `npx next build` without the flag.
|
||||
|
||||
The Next.js command and the generator mode key must target the same bundler.
|
||||
- [Pages Router + Turbopack](guides/next-pages-turbopack.md)
|
||||
- [Pages Router + Webpack](guides/next-pages-webpack.md)
|
||||
|
||||
@@ -1,203 +1,3 @@
|
||||
# Programmatic API
|
||||
# Programmatic API Moved
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
The package provides a main Node.js entry point and a separate React runtime entry point. Both are distributed as ESM only and must be loaded with `import`.
|
||||
|
||||
To resolve `@gromlab/svg-sprites/react` in TypeScript, use `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
||||
|
||||
## Main entry point
|
||||
|
||||
```ts
|
||||
import {
|
||||
defineNextSpriteConfig,
|
||||
defineReactSpriteConfig,
|
||||
generateNextSprite,
|
||||
generateReactSprite,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
The main entry point does not import React and can be used in CLIs, build scripts, and Node.js tools.
|
||||
|
||||
## `generateReactSprite`
|
||||
|
||||
```ts
|
||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
const result = await generateReactSprite(
|
||||
'src/ui/file-manager/svg-sprite',
|
||||
'vite',
|
||||
)
|
||||
```
|
||||
|
||||
The second argument is required:
|
||||
|
||||
```ts
|
||||
type ReactAssetTarget = 'vite' | 'webpack'
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```ts
|
||||
type ReactSpriteGenerationResult = {
|
||||
name: string
|
||||
rootDir: string
|
||||
generatedDir: string
|
||||
spritePath: string
|
||||
manifestPath: string
|
||||
iconCount: number
|
||||
target: 'vite' | 'webpack'
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
console.log(result.name)
|
||||
console.log(result.iconCount)
|
||||
console.log(result.spritePath)
|
||||
console.log(result.manifestPath)
|
||||
```
|
||||
|
||||
The function loads `svg-sprite.config.ts` from the specified root, compiles the SVG files, and safely updates managed files.
|
||||
|
||||
## `generateNextSprite`
|
||||
|
||||
```ts
|
||||
import { generateNextSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
const result = await generateNextSprite(
|
||||
'src/ui/file-manager/svg-sprite',
|
||||
{
|
||||
router: 'app',
|
||||
bundler: 'turbopack',
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
Available values:
|
||||
|
||||
```ts
|
||||
type NextSpriteGenerationOptions = {
|
||||
router: 'app' | 'pages'
|
||||
bundler: 'turbopack' | 'webpack'
|
||||
}
|
||||
```
|
||||
|
||||
The result also contains the selected `router`, `bundler`, and the full target in the form `next@app/turbopack`.
|
||||
|
||||
## `defineReactSpriteConfig`
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
inputFiles: [
|
||||
'../../shared/icons/check.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
`inputFolder` and `inputFiles` are combined. The helper returns the configuration without runtime transformations and provides TypeScript autocomplete.
|
||||
|
||||
## `defineNextSpriteConfig`
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
inputFolder: './icons',
|
||||
})
|
||||
```
|
||||
|
||||
Next.js uses the same configuration contract as the React presets.
|
||||
|
||||
## `generateLegacy`
|
||||
|
||||
```ts
|
||||
import { generateLegacy } from '@gromlab/svg-sprites'
|
||||
|
||||
const results = await generateLegacy({
|
||||
output: 'public/sprites',
|
||||
preview: false,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Returns an array:
|
||||
|
||||
```ts
|
||||
type SpriteResult = {
|
||||
name: string
|
||||
format: 'symbol' | 'stack'
|
||||
spritePath: string
|
||||
iconCount: number
|
||||
}
|
||||
```
|
||||
|
||||
For details, see [Legacy mode](legacy.md).
|
||||
|
||||
## Low-level functions
|
||||
|
||||
The main entry point also exports:
|
||||
|
||||
```ts
|
||||
import {
|
||||
compileSprite,
|
||||
compileSpriteContent,
|
||||
createShapeTransform,
|
||||
generatePreview,
|
||||
loadLegacyConfig,
|
||||
loadReactSpriteConfig,
|
||||
resolveSpriteEntry,
|
||||
resolveSprites,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
These functions are intended for custom orchestration built on top of the existing compiler and writer. For standard usage, prefer `generateReactSprite` and `generateLegacy`.
|
||||
|
||||
## React runtime entry point
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
Types:
|
||||
|
||||
```ts
|
||||
import type {
|
||||
SpriteManifest,
|
||||
SpriteManifestColor,
|
||||
SpriteManifestIcon,
|
||||
SpriteManifestLoader,
|
||||
SpriteManifestModule,
|
||||
SpriteViewerColorTheme,
|
||||
SpriteViewerProps,
|
||||
SpriteViewerSource,
|
||||
SpriteViewerSources,
|
||||
} from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
The React entry point contains `'use client'` and is intended for debug tools. Generated production components are imported from the application's local sprite modules, not from the package's React entry point.
|
||||
|
||||
`SpriteViewerProps.colorTheme` accepts `auto | light | dark`. The default is `auto`, which follows `prefers-color-scheme`; to synchronize it with the application theme, pass the computed `light` or `dark` value.
|
||||
|
||||
## Related guides
|
||||
|
||||
- [React + Vite](react-vite.md)
|
||||
- [React + Webpack 5](react-webpack.md)
|
||||
The canonical document is now the [programmatic API](reference/programmatic-api.md).
|
||||
|
||||
@@ -1,116 +1,3 @@
|
||||
# React + Vite
|
||||
# React + Vite Guide Moved
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
A quick guide to installing and using SVG sprites in a React and Vite project.
|
||||
|
||||
The result is a typed React component and a separate cacheable SVG asset.
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create the sprite directory
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Place the source SVG files in `icons/`.
|
||||
|
||||
## 3. Add the configuration
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
})
|
||||
```
|
||||
|
||||
By default, SVG files are loaded from `./icons`. You can add shared icons from other directories through `inputFiles`: the directory and file list are combined into a single sprite.
|
||||
|
||||
The complete list of options is available under [Configuration → React](../../README.md#react).
|
||||
|
||||
## 4. Add generation to package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generated files are excluded from Git, so generation must run before `dev`, `build`, and `typecheck`.
|
||||
|
||||
First run:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 5. Use the component
|
||||
|
||||
The name `file-manager` is converted to `FileManagerIcon`:
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from './svg-sprite'
|
||||
|
||||
export const OpenFolderButton = () => (
|
||||
<button type="button">
|
||||
<FileManagerIcon icon="folder" width={24} height={24} />
|
||||
Open
|
||||
</button>
|
||||
)
|
||||
```
|
||||
|
||||
TypeScript checks the `icon` value against the file names:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="check" /> // valid
|
||||
<FileManagerIcon icon="unknown" /> // TypeScript error
|
||||
```
|
||||
|
||||
Types, display methods, and color controls are described in the [main documentation](../../README.md#display-methods).
|
||||
|
||||
Vite emits the sprite as a separate file named like `assets/sprite-<hash>.svg`. SVG path data is not included in JavaScript.
|
||||
|
||||
## 6. Add a debug page
|
||||
|
||||
After integrating the icons, you can display all React sprites with `SpriteViewer`:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = import.meta.glob<SpriteManifestModule>(
|
||||
'/src/**/svg-sprite/manifest.ts',
|
||||
)
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Project icons" />
|
||||
)
|
||||
```
|
||||
|
||||
Vite automatically finds the generated `manifest.ts` for each React sprite. The `import.meta.glob` pattern must be a string literal, and generation must run before Vite starts.
|
||||
|
||||
Only include the Viewer on a debug route or in an internal tool.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Missing `index.ts`: run `npm run sprite:file-manager`.
|
||||
- The Viewer cannot find the sprite: check the glob path and make sure `manifest.ts` exists.
|
||||
- `Refusing to overwrite a user file` error: there is a user file at a generated path.
|
||||
- The icon does not change color: use `color` or `--icon-color-N`.
|
||||
The canonical guide is now [React + Vite](guides/react-vite.md).
|
||||
|
||||
@@ -1,118 +1,3 @@
|
||||
# React + Webpack 5
|
||||
# React + Webpack Guide Moved
|
||||
|
||||
[← Back to home](../../README.md)
|
||||
|
||||
A quick guide to installing and using SVG sprites in a React and Webpack 5 project.
|
||||
|
||||
The result is a typed React component and a separate SVG asset emitted through Webpack Asset Modules.
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Create the sprite directory
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Place the source SVG files in `icons/`.
|
||||
|
||||
## 3. Add the configuration
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
})
|
||||
```
|
||||
|
||||
By default, SVG files are loaded from `./icons`. You can add shared icons from other directories through `inputFiles`: the directory and file list are combined into a single sprite.
|
||||
|
||||
The complete list of options is available under [Configuration → React](../../README.md#react).
|
||||
|
||||
## 4. Add generation to package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generated files are excluded from Git, so generation must run before `dev`, `build`, and `typecheck`.
|
||||
|
||||
First run:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 5. Use the component
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from './svg-sprite'
|
||||
|
||||
export const OpenFolderButton = () => (
|
||||
<button type="button">
|
||||
<FileManagerIcon icon="folder" width={24} height={24} />
|
||||
Open
|
||||
</button>
|
||||
)
|
||||
```
|
||||
|
||||
TypeScript checks the `icon` value against the file names:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="folder" /> // valid
|
||||
<FileManagerIcon icon="missing" /> // TypeScript error
|
||||
```
|
||||
|
||||
Types, display methods, and color controls are described in the [main documentation](../../README.md#display-methods).
|
||||
|
||||
Webpack processes the generated `new URL('./sprite.svg', import.meta.url)` through Asset Modules and emits a separate SVG asset.
|
||||
|
||||
If the project already uses a custom SVG loader, make sure it does not intercept the generated `sprite.svg` instead of Asset Modules.
|
||||
|
||||
## 6. Add a debug page
|
||||
|
||||
Webpack does not support Vite's `import.meta.glob` API, so provide static loaders:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('./ui/file-manager/svg-sprite/manifest'),
|
||||
() => import('./ui/navigation/svg-sprite/manifest'),
|
||||
]
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Project icons" />
|
||||
)
|
||||
```
|
||||
|
||||
The paths in `import()` must be string literals. Webpack creates chunks for the manifests and associates them with the SVG assets.
|
||||
|
||||
Only include the Viewer on a debug route or in an internal tool.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Missing `index.ts`: run `npm run sprite:file-manager`.
|
||||
- The Viewer does not load the sprite: check the path in `import()` and make sure `manifest.ts` exists.
|
||||
- Incorrect asset URL: check `output.publicPath`.
|
||||
- Another loader intercepts the SVG: exclude the generated sprite from the incompatible rule.
|
||||
|
||||
For Next.js, use the separate mode keys described in the [App Router](next-app.md) and [Pages Router](next-pages.md) guides.
|
||||
The canonical guide is now [React + Webpack](guides/react-webpack.md).
|
||||
|
||||
3
docs/en/reference.md
Normal file
3
docs/en/reference.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Technical Reference Moved
|
||||
|
||||
The canonical document is now the [technical reference](reference/technical.md).
|
||||
4
docs/en/reference/README.md
Normal file
4
docs/en/reference/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Reference
|
||||
|
||||
- [Technical reference](technical.md)
|
||||
- [Programmatic API](programmatic-api.md)
|
||||
147
docs/en/reference/programmatic-api.md
Normal file
147
docs/en/reference/programmatic-api.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Programmatic API
|
||||
|
||||
[Documentation index](../README.md)
|
||||
|
||||
The package is ESM-only and provides one Node.js generation API. The framework-neutral Viewer is available from `@gromlab/svg-sprites/viewer`, its auto-register entry from `@gromlab/svg-sprites/viewer/element`, and the React bridge from `@gromlab/svg-sprites/react`.
|
||||
|
||||
## `generateSprite`
|
||||
|
||||
```ts
|
||||
import { generateSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
const result = await generateSprite(
|
||||
'src/ui/file-manager/svg-sprite/svg-sprite.config.ts',
|
||||
)
|
||||
```
|
||||
|
||||
For static standalone mode, use `result.spritePath` in a build script to publish the
|
||||
SVG under an application URL:
|
||||
|
||||
```ts
|
||||
import { copyFile } from 'node:fs/promises'
|
||||
|
||||
const result = await generateSprite('src/sprite/svg-sprite.config.ts', {
|
||||
mode: 'standalone',
|
||||
})
|
||||
await copyFile(result.spritePath, 'dist/app-icons/sprite.svg')
|
||||
```
|
||||
|
||||
`spritePath` is a filesystem path, not a browser URL. A deployment-neutral JSON
|
||||
manifest is available through `result.manifestPath` and is copied independently.
|
||||
|
||||
The first argument accepts the full path to an explicitly selected `.ts`, `.js`, or `.json` config file with any name. Passing a directory enables config-less mode and uses that directory as the sprite module root.
|
||||
|
||||
The second argument contains optional overrides and always takes precedence over the config:
|
||||
|
||||
```ts
|
||||
await generateSprite('src/ui/file-manager/svg-sprite/custom-config.json', {
|
||||
mode: 'react@webpack',
|
||||
name: 'documents',
|
||||
input: ['./assets', '../../shared/search.svg'],
|
||||
transform: {
|
||||
addTransition: false,
|
||||
},
|
||||
generatedNotice: false,
|
||||
})
|
||||
```
|
||||
|
||||
Configuration is resolved in this order:
|
||||
|
||||
```text
|
||||
defaults → config → API overrides
|
||||
```
|
||||
|
||||
For fully programmatic generation, pass a directory and provide the required settings as overrides:
|
||||
|
||||
```ts
|
||||
await generateSprite('src/ui/file-manager/svg-sprite', {
|
||||
mode: 'react@vite',
|
||||
name: 'file-manager',
|
||||
input: [
|
||||
'../../shared/search.svg',
|
||||
'../../shared/settings.svg',
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'react@vite',
|
||||
name: 'file-manager',
|
||||
description: 'File manager icons',
|
||||
input: ['./icons', '../../shared/check.svg'],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
`input` accepts one folder, SVG file, or glob pattern, or an array that combines them. When omitted, it defaults to `./icons`; relative paths start at the config directory.
|
||||
|
||||
`defineSpriteConfig` is an identity helper for TypeScript autocomplete. JavaScript can export the same object with `export default`, while JSON contains the object directly.
|
||||
|
||||
## Specialized wrappers
|
||||
|
||||
The specialized functions are available as wrappers around `generateSprite`:
|
||||
|
||||
```ts
|
||||
import { generateNextSprite, generateReactSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
await generateReactSprite('path/to/config.ts', 'vite')
|
||||
await generateNextSprite('path/to/config.ts', {
|
||||
router: 'app',
|
||||
bundler: 'turbopack',
|
||||
})
|
||||
```
|
||||
|
||||
An explicitly supplied target overrides `mode` from the file. Prefer `generateSprite` in new code.
|
||||
|
||||
## Config API
|
||||
|
||||
```ts
|
||||
import {
|
||||
loadSpriteConfig,
|
||||
resolveSpriteConfig,
|
||||
validateSpriteConfig,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
- `loadSpriteConfig(file)` loads an explicitly selected `.ts`, `.js`, or `.json` file.
|
||||
- `validateSpriteConfig(value)` performs runtime validation.
|
||||
- `resolveSpriteConfig(root, config, overrides)` merges values, applies defaults, and resolves paths relative to `root`.
|
||||
|
||||
## Low-level compiler
|
||||
|
||||
```ts
|
||||
import {
|
||||
compileSprite,
|
||||
compileSpriteContent,
|
||||
createShapeTransform,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
These functions are intended for custom orchestration. Standard generation should use `generateSprite`.
|
||||
|
||||
## Viewer runtime
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
```
|
||||
|
||||
The browser entry registers `<gromlab-sprite-viewer>`. Bare standalone can also load the self-contained `dist/viewer-element.js` without a bundler.
|
||||
|
||||
The React bridge keeps the component API:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
`SpriteViewer` accepts generated manifests, remote standalone sources, lazy loaders, or an `import.meta.glob` result. The React entry contains `'use client'` and is intended for debug tools; production components are imported from local sprite modules.
|
||||
632
docs/en/reference/technical.md
Normal file
632
docs/en/reference/technical.md
Normal file
@@ -0,0 +1,632 @@
|
||||
# Technical reference
|
||||
|
||||
[Documentation index](../README.md)
|
||||
|
||||
Reference for the configuration, generated API, and behavior of `@gromlab/svg-sprites`. For step-by-step setup instructions, see the guide for your stack:
|
||||
|
||||
- [Bare standalone](../guides/standalone.md)
|
||||
- [Standalone + Vite](../guides/standalone-vite.md)
|
||||
- [Standalone + Webpack 5](../guides/standalone-webpack.md)
|
||||
- [React + Vite](../guides/react-vite.md)
|
||||
- [React + Webpack 5](../guides/react-webpack.md)
|
||||
- [Next.js App Router + Turbopack](../guides/next-app-turbopack.md)
|
||||
- [Next.js App Router + Webpack](../guides/next-app-webpack.md)
|
||||
- [Next.js Pages Router + Turbopack](../guides/next-pages-turbopack.md)
|
||||
- [Next.js Pages Router + Webpack](../guides/next-pages-webpack.md)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18 or newer;
|
||||
- the package is distributed as ESM and is loaded with `import`;
|
||||
- React 18 or 19 is required only for React/Next generated components and `@gromlab/svg-sprites/react`;
|
||||
- for typed package exports, use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`.
|
||||
|
||||
Generation does not require a project dependency. Run the CLI through `npx`:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites path/to/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Install the package as a development dependency only when the project needs the
|
||||
Viewer, config types, or the programmatic API:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## CLI and generation modes
|
||||
|
||||
The CLI accepts exactly one path: an explicitly selected config file or a directory for config-less generation:
|
||||
|
||||
```text
|
||||
svg-sprites [options] <config-file-or-directory>
|
||||
```
|
||||
|
||||
| Environment | Mode |
|
||||
|---|---|
|
||||
| Static HTML / custom publishing | `standalone` |
|
||||
| Standalone + Vite | `standalone@vite` |
|
||||
| Standalone + Webpack 5 | `standalone@webpack` |
|
||||
| React + Vite | `react@vite` |
|
||||
| React + Webpack 5 | `react@webpack` |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` |
|
||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
The config file may have any name and use the `.ts`, `.js`, or `.json` extension. The CLI does not discover it by convention: pass the file explicitly. The guides use `svg-sprite.config.ts` as the recommended name.
|
||||
|
||||
When a directory is passed, all settings come from CLI options. When a config file is passed, CLI options override the file. The full order is `defaults → config → CLI`.
|
||||
|
||||
Available options are `--mode`, `--name`, `--description`, repeatable `--input <path-or-glob>`, plus the `--remove-size`/`--no-remove-size`, `--replace-colors`/`--no-replace-colors`, `--add-transition`/`--no-add-transition`, and `--generated-notice`/`--no-generated-notice` pairs. Transform flags override individual fields, while supplying at least one `--input` replaces the complete config `input` value.
|
||||
|
||||
Quote CLI glob patterns with single quotes so the shell does not expand them before the generator receives them:
|
||||
|
||||
```bash
|
||||
svg-sprites --input './icons/**/*.svg' --input '!./icons/legacy/**' svg-sprite.config.ts
|
||||
```
|
||||
|
||||
The mode must match the application's publishing strategy. Bare `standalone` leaves the public URL to the application; Vite and Webpack modes generate bundler-specific SVG asset integration.
|
||||
|
||||
## Unified configuration
|
||||
|
||||
Each config file defines one independent sprite.
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'app',
|
||||
description: 'Shared application icons',
|
||||
input: [
|
||||
'./local-icons',
|
||||
'../../assets/icons/*.svg',
|
||||
'!../../assets/icons/deprecated-*.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
| Option | Type | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `mode` | `SpriteMode` | None | Generation mode; may be supplied by CLI/API |
|
||||
| `name` | `string` | Derived from the directory | Name of the sprite, component, and public types |
|
||||
| `description` | `string` | None | Description for types and the debug manifest |
|
||||
| `input` | `string \| string[]` | `./icons` | SVG folders, files, and glob patterns relative to the config directory |
|
||||
| `transform` | `TransformOptions` | All enabled | SVG preparation settings |
|
||||
| `generatedNotice` | `boolean` | `true` | Full or abbreviated warning in generated files |
|
||||
|
||||
### Sprite name
|
||||
|
||||
`name` is written in kebab-case and must start with an ASCII letter:
|
||||
|
||||
```text
|
||||
app → AppIcon
|
||||
file-manager → FileManagerIcon
|
||||
```
|
||||
|
||||
If `name` is omitted, the generator derives it from the directory. For a directory named `svg-sprite` or `svg-sprites`, the parent directory's name is used.
|
||||
|
||||
### Icon sources
|
||||
|
||||
`SpriteConfig.input` is optional and has the type `string | string[]`. When it is omitted, the source is the literal `./icons` folder relative to the config directory. In config-less mode, relative paths start at the directory passed to the CLI or API.
|
||||
|
||||
Each positive string may be a literal folder, a literal `.svg` file, or a glob pattern. A literal folder includes only its immediate `*.svg` children. Use an explicit pattern such as `icons/**/*.svg` to traverse nested directories.
|
||||
|
||||
An array combines all positive sources. A pattern prefixed with `!` excludes its matches from the combined result globally, regardless of which positive source included them.
|
||||
|
||||
Supported glob syntax includes:
|
||||
|
||||
| Syntax | Meaning |
|
||||
|---|---|
|
||||
| `*` | Any characters within one path segment |
|
||||
| `**` | Any number of nested directories |
|
||||
| `?` | One character within a path segment |
|
||||
| `{a,b}` | Either alternative |
|
||||
| `[abc]` | One character from the set or range |
|
||||
| `!pattern` | Exclude matches from the full combined input |
|
||||
|
||||
Every positive source or pattern must find at least one SVG, otherwise generation fails. Duplicate paths are removed and the final file list is sorted deterministically. Different SVG files with the same basename remain a conflict because the basename defines the public icon name.
|
||||
|
||||
## Generated module
|
||||
|
||||
After generation, a React or Next.js sprite directory looks like this:
|
||||
|
||||
```text
|
||||
app-icons/
|
||||
├── .gitignore
|
||||
├── svg-sprite.config.ts
|
||||
├── index.ts # optional user-owned barrel
|
||||
└── .svg-sprite/
|
||||
├── index.js
|
||||
├── index.d.ts
|
||||
├── icon-data.js
|
||||
├── icon-data.d.ts
|
||||
├── sprite.svg
|
||||
├── svg-sprite.manifest.js
|
||||
├── svg-sprite.manifest.d.ts
|
||||
└── react/
|
||||
├── react-component.js
|
||||
├── react-component.d.ts
|
||||
└── react-component.module.css
|
||||
```
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `.svg-sprite/index.js` | Mode-specific production facade and runtime icon-name list |
|
||||
| `.svg-sprite/index.d.ts` | Public declarations for the facade, component, and icon-name union |
|
||||
| `.svg-sprite/svg-sprite.manifest.js` | Debug metadata and the asset URL for `SpriteViewer` |
|
||||
| `.svg-sprite/sprite.svg` | Compiled SVG sprite |
|
||||
| `.svg-sprite/react/react-component.js` | React component runtime without TypeScript or JSX |
|
||||
| `.svg-sprite/react/react-component.d.ts` | React component props, style, and declaration |
|
||||
| `.svg-sprite/react/react-component.module.css` | Styles for the React implementation |
|
||||
| `.svg-sprite/icon-data.js` | Runtime icon-name list and internal IDs |
|
||||
| `.svg-sprite/*.d.ts` | TypeScript declarations for the corresponding JavaScript modules |
|
||||
|
||||
Standalone contracts do not create `react/`. Bare `standalone` contains only the
|
||||
runtime asset and deployment-neutral manifest data:
|
||||
|
||||
```text
|
||||
.svg-sprite/
|
||||
├── sprite.svg
|
||||
└── svg-sprite.manifest.json
|
||||
```
|
||||
|
||||
`standalone@vite` and `standalone@webpack` additionally create `index.*`,
|
||||
`icon-data.*`, and a resolved `svg-sprite.manifest.*`. Their facade contains a
|
||||
native generated Web Component with no external runtime dependencies. Bare
|
||||
`standalone` intentionally does not generate a JavaScript component.
|
||||
|
||||
The generator overwrites and deletes only files that contain its marker. If a user file occupies a managed path, generation fails. The root `index.ts` is user-owned; create a barrel when needed:
|
||||
|
||||
```ts
|
||||
export * from './.svg-sprite'
|
||||
```
|
||||
|
||||
## Standalone Web Component and TypeScript
|
||||
|
||||
In `standalone@vite` and `standalone@webpack`, a sprite with `name: 'app'`
|
||||
exports the `defineAppIconElement()` registration function and the `<app-icon>`
|
||||
tag:
|
||||
|
||||
```ts
|
||||
import { defineAppIconElement } from '@/ui/app-icons'
|
||||
|
||||
defineAppIconElement()
|
||||
```
|
||||
|
||||
After registration, use the element in HTML:
|
||||
|
||||
```html
|
||||
<app-icon icon="search" aria-hidden="true"></app-icon>
|
||||
|
||||
<app-icon
|
||||
icon="settings"
|
||||
role="img"
|
||||
aria-label="Settings"
|
||||
></app-icon>
|
||||
```
|
||||
|
||||
The component renders `<svg><use>` in an open Shadow DOM, selects the internal
|
||||
ID and `viewBox`, and obtains the asset URL through the corresponding Vite or
|
||||
Webpack mechanism. The host defaults to `1em × 1em`; set `class`, `style`,
|
||||
`color`, and `--icon-color-N` with ordinary CSS.
|
||||
|
||||
The generated `HTMLElementTagNameMap` types the property API:
|
||||
|
||||
```ts
|
||||
const icon = document.createElement('app-icon')
|
||||
|
||||
icon.icon = 'search'
|
||||
icon.icon = 'unknown' // TypeScript error
|
||||
```
|
||||
|
||||
TypeScript does not validate attribute values in plain HTML. Therefore an
|
||||
unknown `icon="unknown"` is also validated at runtime: the component hides its
|
||||
inner SVG and reports an error instead of creating a `#undefined` fragment.
|
||||
Calling `defineAppIconElement()` repeatedly is safe for the same sprite; a
|
||||
different element already registered as `<app-icon>` causes an error.
|
||||
|
||||
## React component and TypeScript
|
||||
|
||||
A sprite with `name: 'app'` exports:
|
||||
|
||||
```ts
|
||||
export { AppIcon, appIconNames }
|
||||
export type { AppIconName, AppIconProps, AppIconStyle }
|
||||
```
|
||||
|
||||
### Icon names
|
||||
|
||||
SVG file names become valid `icon` values:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AppIcon icon="unknown" /> // TypeScript error
|
||||
```
|
||||
|
||||
The runtime list contains the same values:
|
||||
|
||||
```ts
|
||||
import { appIconNames } from '@/ui/app-icons'
|
||||
|
||||
// readonly ['search', 'settings', 'user']
|
||||
```
|
||||
|
||||
Names containing spaces or other characters that are unsafe in SVG IDs remain part of the public API. For the internal fragment ID, the generator creates a stable, safe hash:
|
||||
|
||||
```text
|
||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
For these names, use the generated component or the `id` from the debug manifest instead of constructing the fragment ID manually.
|
||||
|
||||
### SVG attributes
|
||||
|
||||
By default, the component renders an `<svg>` and accepts standard SVG attributes:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="search"
|
||||
width={24}
|
||||
height={24}
|
||||
color="rebeccapurple"
|
||||
className="searchIcon"
|
||||
aria-label="Search"
|
||||
/>
|
||||
```
|
||||
|
||||
The component does not add accessibility semantics automatically. Pass appropriate `aria-*` attributes, a `role`, or a label based on the icon's purpose.
|
||||
|
||||
### Wrapper
|
||||
|
||||
`wrapped` renders a `<span>` containing the SVG. In this mode, the remaining props apply to the `<span>`:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
### Typed CSS custom properties
|
||||
|
||||
`AppIconStyle` extends `CSSProperties` and supports properties in the form `--icon-color-N`:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
## Multiple sprites
|
||||
|
||||
Each directory with a configuration creates an independent component, types, manifest, and SVG asset:
|
||||
|
||||
```text
|
||||
app-icons → AppIcon → shared icons
|
||||
analytics-icons → AnalyticsIcon → analytics page icons
|
||||
editor-icons → EditorIcon → editor icons
|
||||
```
|
||||
|
||||
The same source SVG can be added to multiple configurations through `input`. You do not need to copy the file into each sprite directory.
|
||||
|
||||
For multiple sprites, add a separate CLI command for each directory or combine the commands in a shared npm script.
|
||||
|
||||
## Formats and rendering methods
|
||||
|
||||
All current modes generate the `stack` format.
|
||||
|
||||
| Format | `<svg><use>` | `<img>` | CSS background |
|
||||
|---|---:|---:|---:|
|
||||
| `stack` | Yes | Yes | Yes |
|
||||
|
||||
### Generated component
|
||||
|
||||
For React and Next.js, use the generated React component. It knows the internal IDs, constructs the URL, and provides a TypeScript API:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
For `standalone@vite` and `standalone@webpack`, use the generated Web Component:
|
||||
|
||||
```html
|
||||
<app-icon icon="search" style="font-size: 24px"></app-icon>
|
||||
```
|
||||
|
||||
### Manually with `<svg><use>`
|
||||
|
||||
How you obtain `spriteUrl` depends on the bundler.
|
||||
|
||||
Static HTML after the application publishes `.svg-sprite/sprite.svg`:
|
||||
|
||||
```html
|
||||
<svg aria-hidden="true">
|
||||
<use href="/assets/icons.svg#search"></use>
|
||||
</svg>
|
||||
```
|
||||
|
||||
Standalone Vite/Webpack provides generated `getIconsIconHref()` and an internal ID
|
||||
map. Do not construct fragments from unsafe file names manually.
|
||||
|
||||
Vite:
|
||||
|
||||
```ts
|
||||
import spriteUrl from './.svg-sprite/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
Webpack 5, Turbopack, and Next.js:
|
||||
|
||||
```ts
|
||||
const spriteUrl = new URL('./.svg-sprite/sprite.svg', import.meta.url).href
|
||||
```
|
||||
|
||||
After obtaining the URL, use it in JSX:
|
||||
|
||||
```tsx
|
||||
<svg width="24" height="24" aria-label="Search">
|
||||
<use href={`${spriteUrl}#search`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
For names that are unsafe as SVG IDs, use the internal `id` from the manifest.
|
||||
|
||||
### With `<img>`
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#search`} width={24} height={24} alt="Search" />
|
||||
```
|
||||
|
||||
An SVG inside `<img>` is isolated from the page's CSS. Setting `color` or `--icon-color-N` on the outer element does not change its internal colors.
|
||||
|
||||
### With CSS
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
For a single-color silhouette, you can use a mask:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
A mask does not preserve original colors, gradients, or differences between `fill` and `stroke`.
|
||||
|
||||
The path in CSS is resolved relative to the CSS file itself. In these examples, the CSS file is next to `svg-sprite.config.ts`.
|
||||
|
||||
## Assets and caching
|
||||
|
||||
The generated component or standalone facade passes the SVG to the bundler as a separate asset:
|
||||
|
||||
- Vite uses a static import with `?no-inline`;
|
||||
- Webpack 5, Turbopack, and Next.js use `new URL(..., import.meta.url)`;
|
||||
- SVG path data is not serialized into generated JavaScript.
|
||||
|
||||
Bare `standalone` does not participate in an asset pipeline: the application copies
|
||||
or publishes `sprite.svg` and owns its URL, versioning, and cache policy.
|
||||
|
||||
With standard asset naming, the bundler adds a content hash:
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
```
|
||||
|
||||
This allows the SVG to be cached separately from JavaScript. Changing React code does not change the sprite contents, while changing icons creates a new asset version.
|
||||
|
||||
HTTP cache headers, CDN behavior, and `Cache-Control` are configured by the application or hosting platform. With Webpack, the final file name depends on the project's `assetModuleFilename`.
|
||||
|
||||
## SVG transformations
|
||||
|
||||
All transformations are enabled by default and can be configured independently:
|
||||
|
||||
| Option | Behavior |
|
||||
|---|---|
|
||||
| `removeSize` | Removes `width` and `height` from the root `<svg>` while preserving an existing `viewBox` |
|
||||
| `replaceColors` | Replaces detected `fill` and `stroke` values with `--icon-color-N` |
|
||||
| `addTransition` | Adds transitions for `fill` and `stroke` to colored elements and generated styles |
|
||||
|
||||
To disable an individual operation:
|
||||
|
||||
```ts
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/turbopack',
|
||||
transform: {
|
||||
removeSize: false,
|
||||
replaceColors: false,
|
||||
addTransition: false,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Source SVG files are not modified. Transformations apply only to the generated sprite contents.
|
||||
|
||||
## Color management
|
||||
|
||||
### Monochrome icons
|
||||
|
||||
If one color is detected, its fallback becomes `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```
|
||||
|
||||
Set the color through a prop or CSS:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
### Multicolor icons
|
||||
|
||||
Each unique color gets its own custom property with the original color as its fallback:
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
```
|
||||
|
||||
You can override only the values you need:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
}
|
||||
```
|
||||
|
||||
### Limitations
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset`, and `initial` are not replaced;
|
||||
- colors in `fill`, `stroke`, and inline `style` attributes are handled most reliably;
|
||||
- CSS classes and external stylesheets inside the SVG are not the primary transformation use case;
|
||||
- `url(#...)` values may be replaced along with colors, so gradients and patterns require a separate sprite with `replaceColors: false`;
|
||||
- masks, filters, and complex internal CSS rules require visual verification;
|
||||
- page CSS custom properties are available through `<svg><use>`, but not inside `<img>` or a CSS background.
|
||||
|
||||
For a complex icon, you can disable `replaceColors` in a separate sprite configuration.
|
||||
|
||||
## SpriteViewer
|
||||
|
||||
The Viewer uses one Shadow DOM Web Component for every mode. React and future framework components are bridges to that same element, so the visuals and behavior are not duplicated.
|
||||
|
||||
Bare `standalone` loads the self-contained browser bundle and supplies the JSON manifest URL and the published SVG URL:
|
||||
|
||||
```html
|
||||
<script
|
||||
type="module"
|
||||
src="https://unpkg.com/@gromlab/svg-sprites@<version>/dist/viewer-element.js"
|
||||
></script>
|
||||
|
||||
<gromlab-sprite-viewer
|
||||
viewer-title="Project icons"
|
||||
manifest-url="/app-icons/manifest.json"
|
||||
sprite-url="/app-icons/sprite.svg"
|
||||
></gromlab-sprite-viewer>
|
||||
```
|
||||
|
||||
`viewer-element.js` has no additional runtime files and can be copied with the other static assets for self-hosting.
|
||||
|
||||
`standalone@vite` and `standalone@webpack` register the same element through an npm entry and pass the generated JS manifest through the `sources` property:
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
import spriteManifest from './svg-sprite/.svg-sprite/svg-sprite.manifest.js'
|
||||
|
||||
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
|
||||
viewer.sources = [spriteManifest]
|
||||
```
|
||||
|
||||
React and Next.js keep the component API:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
It accepts ready-made manifests, remote standalone sources, an array of lazy loaders, or a record in the format returned by `import.meta.glob`.
|
||||
|
||||
Vite:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = import.meta.glob<SpriteManifestModule>(
|
||||
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||
)
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Project icons" />
|
||||
)
|
||||
```
|
||||
|
||||
Webpack and Next.js:
|
||||
|
||||
```tsx
|
||||
const sources = [
|
||||
() => import('@/ui/app-icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
() => import('@/features/analytics/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} />
|
||||
)
|
||||
```
|
||||
|
||||
The Viewer displays groups, search, `viewBox`, CSS custom properties, and fallback colors. React/Next manifests get React, SVG, IMG, and CSS tabs; standalone manifests get SVG, IMG, and CSS. You can change color values in the interface and immediately inspect the result.
|
||||
|
||||
### Viewer theme
|
||||
|
||||
By default, `colorTheme="auto"` follows `prefers-color-scheme`. You can explicitly pass `light` or `dark`:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```
|
||||
|
||||
To synchronize it with the application theme:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
/>
|
||||
```
|
||||
|
||||
`@gromlab/svg-sprites/react` contains `'use client'` and renders the Web Component host; its internal Shadow DOM is created after the browser runtime loads. In the Next.js App Router, place the Viewer inside a separate Client Component boundary and use it only on a debug route or in an internal tool.
|
||||
|
||||
## Generated files, Git, and CI
|
||||
|
||||
Every mode except bare `standalone` creates a local `.gitignore` for:
|
||||
|
||||
```text
|
||||
/.svg-sprite/
|
||||
```
|
||||
|
||||
Commit the local `.gitignore` to the repository once. It excludes the other generated files, so generation must run before commands that import the sprite module:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites",
|
||||
"pretypecheck": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
CI must run generation before building or type-checking. Replace `latest` with an exact version for reproducibility. A local package installation is not required unless CI also uses the Viewer, package config types, or the programmatic API.
|
||||
|
||||
Bare `standalone` does not create or modify `.gitignore`; the application decides whether its `.svg-sprite/` output is committed or ignored. In other modes, the generator will not overwrite a user-created `.gitignore`. It also refuses to overwrite a user-owned file inside `.svg-sprite`. The root `index.ts` remains user-owned and may re-export the generated API.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Missing `.svg-sprite/index.js`: run the generation script before importing the generated module.
|
||||
- Source not found: pass an existing config file or sprite module directory.
|
||||
- Mode missing: add `mode` to the config or pass `--mode`.
|
||||
- Icon missing from the type: check `input`, the `.svg` extension, glob exclusions, and whether nested folders require `**/*.svg`.
|
||||
- Name conflict: two different SVG files have the same basename; rename one of them.
|
||||
- `Refusing to overwrite a user file`: a file without the generated marker occupies a managed path.
|
||||
- The icon does not change color: use `<svg><use>` or the generated component and check `replaceColors`.
|
||||
- Webpack emits an incorrect URL: check Asset Modules, `output.publicPath`, and SVG loaders.
|
||||
- Static sprite returns 404: check the post-generation copy or server alias, and do not put a filesystem `spritePath` into HTML.
|
||||
- The Viewer cannot find the sprite: check the path to `.svg-sprite/svg-sprite.manifest.js` and run generation before starting the application.
|
||||
- Build and mode do not match: use the target that corresponds to the actual bundler.
|
||||
|
||||
For custom orchestration and low-level compilation, see the [Programmatic API](programmatic-api.md).
|
||||
29
docs/ru/README.md
Normal file
29
docs/ru/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Документация
|
||||
|
||||
Для настройки выберите guide одного exact mode. Каждый guide является
|
||||
самостоятельным документом и без изменений используется в AI skills.
|
||||
|
||||
## Гайды быстрого старта
|
||||
|
||||
| Проект | Exact mode | Guide |
|
||||
|---|---|---|
|
||||
| Static HTML или собственная публикация | `standalone` | [Bare standalone](guides/standalone.md) |
|
||||
| Vanilla + Vite | `standalone@vite` | [Standalone + Vite](guides/standalone-vite.md) |
|
||||
| Vanilla + Webpack 5 | `standalone@webpack` | [Standalone + Webpack](guides/standalone-webpack.md) |
|
||||
| React + Vite | `react@vite` | [React + Vite](guides/react-vite.md) |
|
||||
| React + Webpack 5 | `react@webpack` | [React + Webpack](guides/react-webpack.md) |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` | [App Router + Turbopack](guides/next-app-turbopack.md) |
|
||||
| Next.js App Router + Webpack | `next@app/webpack` | [App Router + Webpack](guides/next-app-webpack.md) |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` | [Pages Router + Turbopack](guides/next-pages-turbopack.md) |
|
||||
| Next.js Pages Router + Webpack | `next@pages/webpack` | [Pages Router + Webpack](guides/next-pages-webpack.md) |
|
||||
|
||||
Все guides используют один порядок:
|
||||
|
||||
1. Генерация спрайта через `npx` без добавления package в проект.
|
||||
2. Необязательное подключение Viewer для дебага и превью.
|
||||
3. Необязательная типизация конфига через package или локальный copy-paste type.
|
||||
|
||||
## Справочники
|
||||
|
||||
- [Технический справочник](reference/technical.md)
|
||||
- [Программный API](reference/programmatic-api.md)
|
||||
11
docs/ru/guides/README.md
Normal file
11
docs/ru/guides/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Гайды быстрого старта
|
||||
|
||||
- `standalone`: [bare standalone](standalone.md)
|
||||
- `standalone@vite`: [standalone с Vite](standalone-vite.md)
|
||||
- `standalone@webpack`: [standalone с Webpack](standalone-webpack.md)
|
||||
- `react@vite`: [React с Vite](react-vite.md)
|
||||
- `react@webpack`: [React с Webpack](react-webpack.md)
|
||||
- `next@app/turbopack`: [App Router с Turbopack](next-app-turbopack.md)
|
||||
- `next@app/webpack`: [App Router с Webpack](next-app-webpack.md)
|
||||
- `next@pages/turbopack`: [Pages Router с Turbopack](next-pages-turbopack.md)
|
||||
- `next@pages/webpack`: [Pages Router с Webpack](next-pages-webpack.md)
|
||||
153
docs/ru/guides/next-app-turbopack.md
Normal file
153
docs/ru/guides/next-app-turbopack.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Next.js App Router с Turbopack
|
||||
|
||||
Это автономный quick start для exact mode key `next@app/turbopack`: generated `IconsIcon` совместим с Server Components и asset pipeline Turbopack.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный plain config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Конфиг может быть `.ts`, `.js` с `default export` или `.json`.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
В CI зафиксируйте точную версию, например `@gromlab/svg-sprites@1.1.5`. Mode и команды Next должны указывать один bundler:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --turbopack",
|
||||
"build": "npm run sprites && next build --turbopack",
|
||||
"start": "next start",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не добавляйте одновременно `predev`/`prebuild` и явный `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Его `.d.ts` self-contained и не импортируют generator package.
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Generated icon не содержит `'use client'`, поэтому его можно импортировать прямо в Server Component:
|
||||
|
||||
```tsx
|
||||
// app/page.tsx
|
||||
import { IconsIcon, iconsIconNames } from '../src/sprite'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon
|
||||
icon="check"
|
||||
width={24}
|
||||
height={24}
|
||||
aria-label="Готово"
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
<span>{iconsIconNames.length} иконок</span>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Turbopack обрабатывает generated `new URL('../sprite.svg', import.meta.url).href` и выпускает внешний hashed asset. Не добавляйте Client Component boundary только ради `IconsIcon`.
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен и нужен только для debug/preview:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Viewer интерактивен, поэтому создайте для него отдельный Client Component:
|
||||
|
||||
```tsx
|
||||
// app/icons-debug/sprite-viewer.tsx
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export function AppSpriteViewer() {
|
||||
return <SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
}
|
||||
```
|
||||
|
||||
Server page импортирует только эту boundary:
|
||||
|
||||
```tsx
|
||||
// app/icons-debug/page.tsx
|
||||
import { AppSpriteViewer } from './sprite-viewer'
|
||||
|
||||
export default function IconsDebugPage() {
|
||||
return <AppSpriteViewer />
|
||||
}
|
||||
```
|
||||
|
||||
Viewer не входит в production icon runtime и не нужен обычным страницам с `IconsIcon`.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
После локальной установки package используйте helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Возможен и type-only import `SpriteConfig` с `satisfies SpriteConfig`.
|
||||
|
||||
Без package добавьте локальный type в config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@app/turbopack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Exact literal защищает от смешивания App Router и других bundler contracts.
|
||||
151
docs/ru/guides/next-app-webpack.md
Normal file
151
docs/ru/guides/next-app-webpack.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Next.js App Router с Webpack
|
||||
|
||||
Это автономный quick start для exact mode key `next@app/webpack`: generated `IconsIcon` совместим с Server Components и Webpack pipeline Next.js.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный plain config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'next@app/webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Также поддерживаются `.js` с `default export` и `.json`.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
В CI замените `latest` точной версией, например `@gromlab/svg-sprites@1.1.5`. Exact Next commands для этого mode:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --webpack",
|
||||
"build": "npm run sprites && next build --webpack",
|
||||
"start": "next start",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не сочетайте явный `npm run sprites` с `predev` или `prebuild`. `.svg-sprite` generated и не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated declarations self-contained и не зависят от `@gromlab/svg-sprites`.
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Production usage в Server Component:
|
||||
|
||||
```tsx
|
||||
// app/page.tsx
|
||||
import { IconsIcon, iconsIconNames } from '../src/sprite'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon
|
||||
icon="check"
|
||||
width={24}
|
||||
height={24}
|
||||
aria-label="Готово"
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
<span>{iconsIconNames.length} иконок</span>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Generated component не содержит `'use client'`. Next Webpack обрабатывает `new URL('../sprite.svg', import.meta.url).href` и публикует отдельный SVG asset; не переписывайте этот URL и не переносите sprite в `public` вручную.
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен. Для debug/preview установите package:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
App Router требует отдельную Client Component boundary для Viewer:
|
||||
|
||||
```tsx
|
||||
// app/icons-debug/sprite-viewer.tsx
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export function AppSpriteViewer() {
|
||||
return <SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// app/icons-debug/page.tsx
|
||||
import { AppSpriteViewer } from './sprite-viewer'
|
||||
|
||||
export default function IconsDebugPage() {
|
||||
return <AppSpriteViewer />
|
||||
}
|
||||
```
|
||||
|
||||
Статический loader позволяет Webpack связать manifest и emitted SVG. Viewer не входит в production runtime `IconsIcon`.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
При локально установленном package используйте helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Другой package-вариант: type-only import `SpriteConfig` и `satisfies SpriteConfig`.
|
||||
|
||||
Без package вставьте локальный type прямо в config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@app/webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@app/webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Локальный exact literal исключает случайную генерацию Turbopack или Pages Router output.
|
||||
140
docs/ru/guides/next-pages-turbopack.md
Normal file
140
docs/ru/guides/next-pages-turbopack.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Next.js Pages Router с Turbopack
|
||||
|
||||
Это автономный quick start для exact mode key `next@pages/turbopack`: generated `IconsIcon` работает при SSR, SSG и клиентских переходах Pages Router.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный plain config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'next@pages/turbopack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Конфиг также может быть `.js` с `default export` или `.json`.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Для CI зафиксируйте точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact commands должны сохранять Turbopack и для dev, и для production build:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --turbopack",
|
||||
"build": "npm run sprites && next build --turbopack",
|
||||
"start": "next start",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не добавляйте `predev`/`prebuild`, если scripts уже явно вызывают `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated `.d.ts` self-contained и не импортируют generator package.
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Production usage на обычной page:
|
||||
|
||||
```tsx
|
||||
// pages/index.tsx
|
||||
import { IconsIcon, iconsIconNames } from '../src/sprite'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon
|
||||
icon="check"
|
||||
width={24}
|
||||
height={24}
|
||||
aria-label="Готово"
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
<span>{iconsIconNames.length} иконок</span>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Компонент одинаково работает с `getServerSideProps`, `getStaticProps` и client navigation. Turbopack разрешает generated `new URL('../sprite.svg', import.meta.url).href` в отдельный hashed asset.
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен и нужен только для debug/preview:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
В Pages Router Viewer можно использовать прямо в page, без отдельной App Router Client Component boundary:
|
||||
|
||||
```tsx
|
||||
// pages/icons-debug.tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export default function IconsDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
}
|
||||
```
|
||||
|
||||
Оставляйте эту page только во внутреннем debug-разделе. Viewer не входит в production icon runtime `IconsIcon`.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
Если package установлен локально, используйте helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@pages/turbopack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Альтернатива: type-only import `SpriteConfig` и объект `satisfies SpriteConfig`.
|
||||
|
||||
Без package добавьте copy-paste type в config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@pages/turbopack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@pages/turbopack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Exact literal не позволяет незаметно смешать Pages Router с App Router или Webpack output.
|
||||
140
docs/ru/guides/next-pages-webpack.md
Normal file
140
docs/ru/guides/next-pages-webpack.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Next.js Pages Router с Webpack
|
||||
|
||||
Это автономный quick start для exact mode key `next@pages/webpack`: generated `IconsIcon` работает в Pages Router и публикует SVG через Webpack pipeline Next.js.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный plain config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'next@pages/webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Поддерживаются `.ts`, `.js` с `default export` и `.json` configs.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
В CI замените `latest` на точную проверенную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Next commands для Webpack:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && next dev --webpack",
|
||||
"build": "npm run sprites && next build --webpack",
|
||||
"start": "next start",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не дублируйте эти вызовы через `predev`, `prebuild` или `pretypecheck`. `.svg-sprite` generated и не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated declarations self-contained и не требуют `@gromlab/svg-sprites`.
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Production usage:
|
||||
|
||||
```tsx
|
||||
// pages/index.tsx
|
||||
import { IconsIcon, iconsIconNames } from '../src/sprite'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<IconsIcon
|
||||
icon="check"
|
||||
width={24}
|
||||
height={24}
|
||||
aria-label="Готово"
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
<span>{iconsIconNames.length} иконок</span>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Компонент поддерживает SSR, SSG и клиентские переходы. Next Webpack преобразует generated `new URL('../sprite.svg', import.meta.url).href` во внешний hashed asset; не конструируйте URL спрайта вручную.
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен. Устанавливайте package только для debug/preview:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Pages Router позволяет разместить Viewer непосредственно в page без отдельной App Router boundary:
|
||||
|
||||
```tsx
|
||||
// pages/icons-debug.tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export default function IconsDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
}
|
||||
```
|
||||
|
||||
Статический loader даёт Webpack точный manifest module и связанный SVG asset. Не импортируйте Viewer из production pages, если preview там не нужен; runtime `IconsIcon` от него независим.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
После локальной установки package доступен helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@pages/webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Также можно применить `satisfies SpriteConfig` с type-only импортом `SpriteConfig`.
|
||||
|
||||
Без package вставьте локальный type прямо в config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'next@pages/webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'next@pages/webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Такой exact literal выявляет ошибочный выбор App Router или Turbopack ещё при проверке config.
|
||||
141
docs/ru/guides/react-vite.md
Normal file
141
docs/ru/guides/react-vite.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# React-компонент для Vite
|
||||
|
||||
Это автономный quick start для exact mode key `react@vite`: генератор создаёт типизированный `IconsIcon`, а Vite публикует отдельный SVG asset.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный plain config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'react@vite',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Вместо `.ts` можно использовать `.js` с `default export` или `.json`.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
В CI замените `latest` на точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Vite commands:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && vite",
|
||||
"build": "npm run sprites && tsc --noEmit && vite build",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не добавляйте `predev`, `prebuild` или `pretypecheck`, если соответствующие scripts уже явно запускают `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated declarations self-contained: они описывают компонент и manifest без импорта `@gromlab/svg-sprites`.
|
||||
|
||||
Пользовательский barrel возвращает generated API:
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Production usage:
|
||||
|
||||
```tsx
|
||||
import { IconsIcon, iconsIconNames } from './sprite'
|
||||
|
||||
export function SaveButton() {
|
||||
return (
|
||||
<button type="button">
|
||||
<IconsIcon
|
||||
icon="check"
|
||||
width={24}
|
||||
height={24}
|
||||
aria-hidden="true"
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
Сохранить
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
console.log(iconsIconNames)
|
||||
```
|
||||
|
||||
Prop `icon` является union имён исходных файлов. Vite автоматически обрабатывает generated CSS Module и импорт `sprite.svg?no-inline`; query запрещает inline и заставляет Vite выпустить отдельный hashed SVG asset. Если TypeScript не знает Vite asset imports, добавьте `/// <reference types="vite/client" />` в `src/vite-env.d.ts`.
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен и нужен только для debug/preview. Установите package отдельно:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Используйте React bridge со статическим массивом loaders:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('./sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export function IconsDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
}
|
||||
```
|
||||
|
||||
Строковый путь в `import()` должен указывать на generated JS manifest. Держите страницу за debug-маршрутом; `SpriteViewer` не входит в production runtime `IconsIcon`.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
Если package установлен локально, используйте helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'react@vite',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Также можно импортировать `SpriteConfig` только как type и написать объект `satisfies SpriteConfig`.
|
||||
|
||||
Без package добавьте локальный type прямо в config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'react@vite'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'react@vite',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Локальный type проверяет только этот exact mode и не создаёт runtime-зависимость.
|
||||
141
docs/ru/guides/react-webpack.md
Normal file
141
docs/ru/guides/react-webpack.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# React-компонент для Webpack 5
|
||||
|
||||
Это автономный quick start для exact mode key `react@webpack`: generated `IconsIcon` использует Webpack 5 Asset Modules и CSS Modules.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный plain config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'react@webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Поддерживаются `.ts`, `.js` с `default export` и `.json` configs.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
В CI замените `latest` на точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Webpack commands:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && webpack serve --mode development",
|
||||
"build": "npm run sprites && webpack --mode production",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не сочетайте эти явные вызовы с `predev`/`prebuild`: иначе генерация задублируется. `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated `.d.ts` self-contained и не импортируют generator package.
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Production usage:
|
||||
|
||||
```tsx
|
||||
import { IconsIcon, iconsIconNames } from './sprite'
|
||||
|
||||
export function SaveButton() {
|
||||
return (
|
||||
<button type="button">
|
||||
<IconsIcon
|
||||
icon="check"
|
||||
width={24}
|
||||
height={24}
|
||||
aria-hidden="true"
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
Сохранить
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
console.log(iconsIconNames)
|
||||
```
|
||||
|
||||
Generated component получает URL через `new URL('../sprite.svg', import.meta.url).href`. Webpack 5 должен обработать SVG как Asset Module. Исключите generated `sprite.svg` из `@svgr/webpack`, inline/raw loaders и других общих SVG rules либо задайте для него `type: 'asset/resource'`.
|
||||
|
||||
Компонент импортирует `react-component.module.css`. Webpack config должен обрабатывать `*.module.css` через `css-loader` с CSS Modules и `style-loader` или `MiniCssExtractPlugin`. Для TypeScript при необходимости добавьте декларацию `declare module '*.module.css'`.
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен. Устанавливайте package только для debug/preview:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Webpack не использует `import.meta.glob`; передайте статический loader:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('./sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export function IconsDebugPage() {
|
||||
return <SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
}
|
||||
```
|
||||
|
||||
Webpack создаст chunk manifest и разрешит его SVG через тот же Asset Modules pipeline. Viewer держите только в debug route; production `IconsIcon` от него не зависит.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
С локально установленным package доступен helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'react@webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Эквивалентная проверка: type-only import `SpriteConfig` и `satisfies SpriteConfig`.
|
||||
|
||||
Без package используйте copy-paste type в config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'react@webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'react@webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Локальный literal не разрешит случайно выбрать Vite или Next mode.
|
||||
151
docs/ru/guides/standalone-vite.md
Normal file
151
docs/ru/guides/standalone-vite.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Нативный icon Web Component с Vite
|
||||
|
||||
Это автономный quick start для exact mode key `standalone@vite`: generated facade регистрирует `<icons-icon>` и отдаёт SVG в asset pipeline Vite.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
Рекомендуемая структура держит конфиг и иконки рядом:
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный plain config:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'standalone@vite',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Конфиг также может быть `.js` с `default export` или `.json`.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
В CI замените `latest` на точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact dev/build commands для Vite:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && vite",
|
||||
"build": "npm run sprites && vite build",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не добавляйте одновременно `predev`/`prebuild` и явный `npm run sprites` в этих scripts. `.svg-sprite` является generated-каталогом и не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Generated `.d.ts` self-contained и не импортируют `@gromlab/svg-sprites`.
|
||||
|
||||
Верните facade через пользовательский barrel:
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Production entry регистрирует native Web Component:
|
||||
|
||||
```ts
|
||||
import { defineIconsIconElement, iconsIconNames } from './sprite'
|
||||
|
||||
defineIconsIconElement()
|
||||
|
||||
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
|
||||
<icons-icon icon="check" role="img" aria-label="Готово"></icons-icon>
|
||||
`
|
||||
|
||||
console.log(iconsIconNames)
|
||||
```
|
||||
|
||||
Generated facade импортирует `sprite.svg?no-inline`: Vite автоматически выпускает отдельный hashed SVG asset и не превращает его в data URL. TypeScript-проекту при необходимости добавьте стандартные Vite types:
|
||||
|
||||
```ts
|
||||
/// <reference types="vite/client" />
|
||||
```
|
||||
|
||||
Размер по умолчанию равен `1em`, поэтому компонент удобно масштабировать через `font-size`. Цвет задаётся через `color` и generated custom properties:
|
||||
|
||||
```css
|
||||
icons-icon {
|
||||
font-size: 24px;
|
||||
color: #334155;
|
||||
--icon-color-2: #f59e0b;
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен и нужен только для debug/preview. Установите его отдельно:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Зарегистрируйте Viewer и передайте generated JS manifest через свойство `sources`:
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
import spriteManifest from './sprite/.svg-sprite/svg-sprite.manifest.js'
|
||||
|
||||
document.querySelector<HTMLDivElement>('#app')!.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
'<gromlab-sprite-viewer></gromlab-sprite-viewer>',
|
||||
)
|
||||
|
||||
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
|
||||
viewer.viewerTitle = 'Иконки проекта'
|
||||
viewer.sources = [spriteManifest]
|
||||
```
|
||||
|
||||
Расположите этот код только в debug entry или внутреннем маршруте. Viewer не входит в production runtime `<icons-icon>`.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
При локально установленном package используйте helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'standalone@vite',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Альтернатива с package: `import type { SpriteConfig }` и объект `satisfies SpriteConfig`.
|
||||
|
||||
Без package скопируйте локальный type прямо в config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'standalone@vite'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'standalone@vite',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Локальный type ограничивает `mode` одним exact literal и ничего не загружает во время генерации.
|
||||
145
docs/ru/guides/standalone-webpack.md
Normal file
145
docs/ru/guides/standalone-webpack.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Нативный icon Web Component с Webpack 5
|
||||
|
||||
Это автономный quick start для exact mode key `standalone@webpack`: generated facade предоставляет `<icons-icon>`, а Webpack 5 публикует SVG через Asset Modules.
|
||||
|
||||
## 1. Генерация спрайта
|
||||
|
||||
Главное преимущество: генератор не нужно устанавливать и добавлять в `package.json`. `npx` временно скачивает CLI, а generated production runtime не импортирует `@gromlab/svg-sprites`.
|
||||
|
||||
```text
|
||||
src/sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── warning.svg
|
||||
├── index.ts
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Минимальный config рядом с `icons/`:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'standalone@webpack',
|
||||
name: 'icons',
|
||||
}
|
||||
```
|
||||
|
||||
Если `input` не указан, SVG читаются из `./icons` относительно конфига. Поддерживаются также `.js` с `default export` и `.json`.
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Для CI закрепите точную версию, например `@gromlab/svg-sprites@1.1.5`. Exact Webpack commands:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"dev": "npm run sprites && webpack serve --mode development",
|
||||
"build": "npm run sprites && webpack --mode production",
|
||||
"typecheck": "npm run sprites && tsc --noEmit"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Не дублируйте запуск через `predev`/`prebuild`, если scripts уже явно вызывают `npm run sprites`. Generated `.svg-sprite` не коммитится. Generated локальный `.gitignore`, который исключает этот каталог, нужно добавить в Git один раз. Его declarations self-contained и не требуют `@gromlab/svg-sprites`.
|
||||
|
||||
```ts
|
||||
// src/sprite/index.ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Production usage:
|
||||
|
||||
```ts
|
||||
import { defineIconsIconElement, iconsIconNames } from './sprite'
|
||||
|
||||
defineIconsIconElement()
|
||||
|
||||
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
|
||||
<icons-icon icon="check" role="img" aria-label="Готово"></icons-icon>
|
||||
`
|
||||
|
||||
console.log(iconsIconNames)
|
||||
```
|
||||
|
||||
Generated facade использует `new URL('./sprite.svg', import.meta.url).href`. Webpack 5 Asset Modules выпускают отдельный asset; его итоговый URL учитывает `output.publicPath` и `assetModuleFilename`.
|
||||
|
||||
Если проект использует `@svgr/webpack`, `svg-inline-loader`, `raw-loader` или общий SVG rule, исключите `src/sprite/.svg-sprite/sprite.svg` из этого правила. Generated SVG должен обрабатываться как `asset/resource`, а не как React-компонент или inline source.
|
||||
|
||||
Размер Web Component по умолчанию `1em`; управляйте им и цветами обычным CSS:
|
||||
|
||||
```css
|
||||
icons-icon {
|
||||
font-size: 24px;
|
||||
color: #334155;
|
||||
--icon-color-2: #f59e0b;
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Дебаг и превью
|
||||
|
||||
Viewer необязателен. Для debug/preview установите package как dev dependency:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
Подключите element entry и generated JS manifest:
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
import spriteManifest from './sprite/.svg-sprite/svg-sprite.manifest.js'
|
||||
|
||||
document.querySelector<HTMLDivElement>('#app')!.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
'<gromlab-sprite-viewer></gromlab-sprite-viewer>',
|
||||
)
|
||||
|
||||
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
|
||||
viewer.viewerTitle = 'Иконки проекта'
|
||||
viewer.sources = [spriteManifest]
|
||||
```
|
||||
|
||||
Webpack свяжет manifest с тем же emitted SVG asset. Оставляйте Viewer только в debug entry: production `<icons-icon>` от него не зависит.
|
||||
|
||||
## 3. Типизация конфига
|
||||
|
||||
После локальной установки package можно использовать helper:
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'standalone@webpack',
|
||||
name: 'icons',
|
||||
})
|
||||
```
|
||||
|
||||
Либо импортируйте только `SpriteConfig` как type и примените `satisfies SpriteConfig`.
|
||||
|
||||
Без package добавьте copy-paste type в сам config:
|
||||
|
||||
```ts
|
||||
type LocalSpriteConfig = {
|
||||
mode: 'standalone@webpack'
|
||||
name?: string
|
||||
description?: string
|
||||
input?: string | string[]
|
||||
transform?: {
|
||||
removeSize?: boolean
|
||||
replaceColors?: boolean
|
||||
addTransition?: boolean
|
||||
}
|
||||
generatedNotice?: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
mode: 'standalone@webpack',
|
||||
name: 'icons',
|
||||
} satisfies LocalSpriteConfig
|
||||
```
|
||||
|
||||
Этот вариант сохраняет проверку exact mode без runtime import и без записи generator package в проект.
|
||||
108
docs/ru/guides/standalone.md
Normal file
108
docs/ru/guides/standalone.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# SVG-спрайт для сайта без сборщика
|
||||
|
||||
Соберите SVG-иконки в один файл и используйте их на HTML-странице.
|
||||
|
||||
## Генерация спрайта
|
||||
|
||||
Устанавливать пакет в проект не нужно.
|
||||
|
||||
В руководстве используется следующая структура проекта:
|
||||
|
||||
```text
|
||||
/
|
||||
├── index.html
|
||||
└── assets/
|
||||
├── app-icons/
|
||||
└── svg-icons/
|
||||
├── check.svg
|
||||
└── warning.svg
|
||||
```
|
||||
|
||||
### 1. Создайте конфиг спрайта
|
||||
|
||||
Выберите папку для спрайта. В этом примере используется `assets/app-icons`. Создайте в ней файл `svg-sprite.config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "standalone",
|
||||
"name": "icons"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Укажите источник иконок
|
||||
|
||||
В `input` можно указать папку, отдельный SVG-файл или glob-шаблон. Для нескольких источников используйте массив с любой комбинацией этих значений:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "standalone",
|
||||
"name": "icons",
|
||||
"input": "../svg-icons/**/*.svg"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Сгенерируйте спрайт
|
||||
|
||||
Передайте команде путь к конфигу:
|
||||
|
||||
```bash
|
||||
npx --yes @gromlab/svg-sprites assets/app-icons/svg-sprite.config.json
|
||||
```
|
||||
|
||||
Пакет соберёт иконки в каталог `.svg-sprite` рядом с конфигом:
|
||||
|
||||
```text
|
||||
assets/app-icons/.svg-sprite/
|
||||
├── sprite.svg
|
||||
└── svg-sprite.manifest.json
|
||||
```
|
||||
|
||||
- `sprite.svg` — готовый спрайт для использования на сайте.
|
||||
- `svg-sprite.manifest.json` — данные об иконках для Viewer.
|
||||
|
||||
Каталог `.svg-sprite` создаётся автоматически и полностью заменяется при каждой генерации. Не редактируйте его содержимое вручную.
|
||||
|
||||
### 4. Используйте иконку
|
||||
|
||||
В `index.html` укажите путь к созданному `sprite.svg`. После `#` добавьте имя нужной иконки без расширения `.svg`:
|
||||
|
||||
```html
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
aria-label="Готово"
|
||||
>
|
||||
<use href="./assets/app-icons/.svg-sprite/sprite.svg#check"></use>
|
||||
</svg>
|
||||
```
|
||||
|
||||
Иконка из файла `check.svg` будет доступна как `#check`.
|
||||
|
||||
## Дебаг и превью
|
||||
|
||||
`sprite.svg` — технический файл, а не галерея иконок. При его открытии нельзя удобно просмотреть весь набор. Кроме того, градиенты, маски, фильтры и ссылки на внутренние `id` могут отображаться с артефактами.
|
||||
|
||||
Для визуальной проверки используйте официальный Viewer. Он показывает все иконки спрайта и помогает проверить их цвета и отображение.
|
||||
|
||||
Viewer необязателен и предназначен только для разработки. Устанавливать пакет через npm не нужно.
|
||||
|
||||
Viewer работает напрямую с файлами из `.svg-sprite`. Ничего копировать не нужно.
|
||||
|
||||
### Добавьте Viewer на страницу
|
||||
|
||||
Добавьте в `index.html` module script и укажите пути к generated manifest и спрайту:
|
||||
|
||||
```html
|
||||
<script
|
||||
type="module"
|
||||
src="https://cdn.jsdelivr.net/npm/@gromlab/svg-sprites/dist/viewer-element.js"
|
||||
></script>
|
||||
|
||||
<gromlab-sprite-viewer
|
||||
viewer-title="Иконки проекта"
|
||||
manifest-url="./assets/app-icons/.svg-sprite/svg-sprite.manifest.json"
|
||||
sprite-url="./assets/app-icons/.svg-sprite/sprite.svg"
|
||||
></gromlab-sprite-viewer>
|
||||
```
|
||||
|
||||
Viewer можно вынести в отдельный HTML-файл в корне сайта, предназначенный только для разработки и проверки иконок.
|
||||
@@ -1,102 +0,0 @@
|
||||
# Legacy mode
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Краткая инструкция по генерации централизованных SVG-спрайтов форматов `symbol` и `stack` с optional HTML preview.
|
||||
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Подготовьте иконки и конфиг
|
||||
|
||||
```text
|
||||
project/
|
||||
├── src/assets/icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprites.config.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
// svg-sprites.config.ts
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Запустите генерацию
|
||||
|
||||
```bash
|
||||
npx svg-sprites --mode legacy .
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```text
|
||||
public/sprites/
|
||||
├── icons.sprite.svg
|
||||
└── preview.html
|
||||
```
|
||||
|
||||
При `preview: false` HTML-файл не создаётся. Для формата `stack` укажите `format: 'stack'`.
|
||||
|
||||
## 4. Используйте symbol-спрайт
|
||||
|
||||
```html
|
||||
<svg width="24" height="24" aria-label="Готово">
|
||||
<use href="/sprites/icons.sprite.svg#check"></use>
|
||||
</svg>
|
||||
```
|
||||
|
||||
## 5. Добавьте package script
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"prebuild": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Несколько спрайтов
|
||||
|
||||
Добавьте несколько записей в `sprites`:
|
||||
|
||||
```ts
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
{
|
||||
name: 'logos',
|
||||
input: 'src/assets/logos',
|
||||
format: 'stack',
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
Все результаты и общий `preview.html` будут записаны в `output`.
|
||||
|
||||
## Если что-то не работает
|
||||
|
||||
- Не найден конфиг: убедитесь, что `svg-sprites.config.ts` находится в переданном корне.
|
||||
- Нет иконок: проверьте `sprites[].input` и расширение `.svg`.
|
||||
- Не нужен preview: установите `preview: false`.
|
||||
|
||||
Для программного запуска используйте [`generateLegacy`](programmatic-api.md#generatelegacy).
|
||||
@@ -1,96 +0,0 @@
|
||||
# Миграция с 0.1.x на 1.0
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
|
||||
|
||||
## CLI
|
||||
|
||||
CLI теперь всегда требует явный `--mode` и путь к каталогу конфигурации:
|
||||
|
||||
```text
|
||||
svg-sprites
|
||||
→ svg-sprites --mode <mode> <path>
|
||||
```
|
||||
|
||||
Выберите mode по окружению:
|
||||
|
||||
| Окружение | Mode |
|
||||
|---|---|
|
||||
| React + Vite | `react@vite` |
|
||||
| React + Webpack 5 | `react@webpack` |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` |
|
||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||
| Централизованная старая схема | `legacy` |
|
||||
|
||||
## React и Next.js
|
||||
|
||||
Вместо корневого `svg-sprites.config.ts` создайте локальный `svg-sprite.config.ts` рядом с набором иконок:
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'global',
|
||||
inputFolder: './icons',
|
||||
})
|
||||
```
|
||||
|
||||
Для обычного React используйте `defineReactSpriteConfig`. Папку и явный список общих SVG можно объединить через `inputFolder` и `inputFiles`.
|
||||
|
||||
Старые `publicPath` и `react` больше не нужны. Generated-модуль создаётся рядом с конфигом, сам добавляет `.gitignore`, а Vite, Webpack или Next.js выпускает SVG как отдельный asset с content hash.
|
||||
|
||||
Компонент `<SvgSprite icon="..." />` заменяется компонентом, имя которого выводится из `name`:
|
||||
|
||||
```tsx
|
||||
<GlobalIcon icon="check" />
|
||||
```
|
||||
|
||||
Для просмотра иконок добавьте `<SpriteViewer>` как debug-страницу приложения. Отдельный `preview.html` остаётся только в legacy-режиме.
|
||||
|
||||
## Legacy-режим
|
||||
|
||||
Если централизованную структуру нужно сохранить, переименуйте helper и поля формата:
|
||||
|
||||
```ts
|
||||
import { defineLegacyConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineLegacyConfig({
|
||||
output: 'public/sprites',
|
||||
preview: true,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'stack',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
- `defineConfig` заменён на `defineLegacyConfig`;
|
||||
- `sprites[].mode` переименован в `sprites[].format`;
|
||||
- `generate` заменён на `generateLegacy`;
|
||||
- `loadConfig` заменён на `loadLegacyConfig`;
|
||||
- `publicPath` и генерация старого общего React-компонента удалены.
|
||||
|
||||
Запуск:
|
||||
|
||||
```bash
|
||||
svg-sprites --mode legacy .
|
||||
```
|
||||
|
||||
## Программный API
|
||||
|
||||
Пакет распространяется только как ESM. Замените `require()` на `import`.
|
||||
|
||||
`compileSpriteContent` теперь возвращает `Promise<Uint8Array>`, чтобы публичные декларации не требовали установки `@types/node`. В Node.js фактический результат совместим с API, принимающими `Uint8Array`.
|
||||
|
||||
## После миграции
|
||||
|
||||
1. Удалите старые generated-файлы и правила, которые игнорировали целиком каталог с исходными иконками.
|
||||
2. Добавьте явную команду генерации перед `dev`, `build` и `typecheck`.
|
||||
3. Запустите генерацию и проверку типов.
|
||||
4. Проверьте все иконки и цветовые переменные через `SpriteViewer` или legacy `preview.html`.
|
||||
@@ -1,102 +1,4 @@
|
||||
# Next.js App Router
|
||||
# Guides Next.js App Router перемещены
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Поддерживаются два явных режима:
|
||||
|
||||
| Сборщик | Mode key | Версия Next.js |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@app/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@app/webpack` | 13.4+ |
|
||||
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте sprite-модуль
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Добавьте генерацию
|
||||
|
||||
Для Turbopack:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode next@app/turbopack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Для Webpack замените mode key на `next@app/webpack`. В Next 13–15 Webpack используется обычной командой `next build`, в Next 16 — командой `next build --webpack`.
|
||||
|
||||
## 4. Используйте в Server Component
|
||||
|
||||
Generated-компонент не содержит `'use client'`, поэтому его можно импортировать непосредственно в `page.tsx` или `layout.tsx`:
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from '@/ui/file-manager/svg-sprite'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<FileManagerIcon icon="folder" width={24} height={24} />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Next.js выпустит отдельный SVG asset с content hash. Один generated-код используется при SSR и в браузере без расхождения URL.
|
||||
|
||||
## 5. Добавьте SpriteViewer
|
||||
|
||||
Viewer интерактивен, поэтому для него нужна отдельная Client Component граница:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
||||
]
|
||||
|
||||
export default function SpritesPage() {
|
||||
return <SpriteViewer sources={sources} />
|
||||
}
|
||||
```
|
||||
|
||||
## Проверка сборщика
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
Для Next 13–15 с Webpack используйте `npx next build` без флага.
|
||||
|
||||
Команда Next.js и mode key генератора должны указывать один и тот же сборщик.
|
||||
- [App Router + Turbopack](guides/next-app-turbopack.md)
|
||||
- [App Router + Webpack](guides/next-app-webpack.md)
|
||||
|
||||
@@ -1,96 +1,4 @@
|
||||
# Next.js Pages Router
|
||||
# Guides Next.js Pages Router перемещены
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Поддерживаются два явных режима:
|
||||
|
||||
| Сборщик | Mode key | Версия Next.js |
|
||||
|---|---|---|
|
||||
| Turbopack | `next@pages/turbopack` | 16.2+ |
|
||||
| Webpack 5 | `next@pages/webpack` | 12.2+ |
|
||||
|
||||
Для Next.js 12.2 требуется React 18.
|
||||
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте sprite-модуль
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Добавьте генерацию
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode next@pages/webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Для Next.js 16.2 с Turbopack замените mode key на `next@pages/turbopack`.
|
||||
|
||||
## 4. Используйте на странице
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from '@/ui/file-manager/svg-sprite'
|
||||
|
||||
export default function FilesPage() {
|
||||
return <FileManagerIcon icon="folder" width={24} height={24} />
|
||||
}
|
||||
|
||||
export function getServerSideProps() {
|
||||
return { props: {} }
|
||||
}
|
||||
```
|
||||
|
||||
Компонент одинаково работает при SSR, SSG и клиентских переходах. Next.js выпускает отдельный SVG asset с content hash.
|
||||
|
||||
## 5. Добавьте SpriteViewer
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('@/ui/file-manager/svg-sprite/manifest'),
|
||||
]
|
||||
|
||||
export default function SpritesPage() {
|
||||
return <SpriteViewer sources={sources} />
|
||||
}
|
||||
```
|
||||
|
||||
## Проверка сборщика
|
||||
|
||||
```bash
|
||||
# Turbopack
|
||||
npx next build --turbopack
|
||||
|
||||
# Webpack 5
|
||||
npx next build --webpack
|
||||
```
|
||||
|
||||
Для Next 12–15 с Webpack используйте `npx next build` без флага.
|
||||
|
||||
Команда Next.js и mode key генератора должны указывать один и тот же сборщик.
|
||||
- [Pages Router + Turbopack](guides/next-pages-turbopack.md)
|
||||
- [Pages Router + Webpack](guides/next-pages-webpack.md)
|
||||
|
||||
@@ -1,203 +1,3 @@
|
||||
# Программный API
|
||||
# Программный API перемещён
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Пакет предоставляет основную Node.js точку входа и отдельный React runtime entry. Обе точки распространяются только как ESM и подключаются через `import`.
|
||||
|
||||
Для разрешения `@gromlab/svg-sprites/react` в TypeScript используйте `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||||
|
||||
## Основной entry
|
||||
|
||||
```ts
|
||||
import {
|
||||
defineNextSpriteConfig,
|
||||
defineReactSpriteConfig,
|
||||
generateNextSprite,
|
||||
generateReactSprite,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
Основной entry не импортирует React и может использоваться в CLI, build scripts и Node.js инструментах.
|
||||
|
||||
## `generateReactSprite`
|
||||
|
||||
```ts
|
||||
import { generateReactSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
const result = await generateReactSprite(
|
||||
'src/ui/file-manager/svg-sprite',
|
||||
'vite',
|
||||
)
|
||||
```
|
||||
|
||||
Второй аргумент обязателен:
|
||||
|
||||
```ts
|
||||
type ReactAssetTarget = 'vite' | 'webpack'
|
||||
```
|
||||
|
||||
Результат:
|
||||
|
||||
```ts
|
||||
type ReactSpriteGenerationResult = {
|
||||
name: string
|
||||
rootDir: string
|
||||
generatedDir: string
|
||||
spritePath: string
|
||||
manifestPath: string
|
||||
iconCount: number
|
||||
target: 'vite' | 'webpack'
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
console.log(result.name)
|
||||
console.log(result.iconCount)
|
||||
console.log(result.spritePath)
|
||||
console.log(result.manifestPath)
|
||||
```
|
||||
|
||||
Функция загружает `svg-sprite.config.ts` из указанного корня, компилирует SVG и безопасно обновляет managed-файлы.
|
||||
|
||||
## `generateNextSprite`
|
||||
|
||||
```ts
|
||||
import { generateNextSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
const result = await generateNextSprite(
|
||||
'src/ui/file-manager/svg-sprite',
|
||||
{
|
||||
router: 'app',
|
||||
bundler: 'turbopack',
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
Доступные значения:
|
||||
|
||||
```ts
|
||||
type NextSpriteGenerationOptions = {
|
||||
router: 'app' | 'pages'
|
||||
bundler: 'turbopack' | 'webpack'
|
||||
}
|
||||
```
|
||||
|
||||
Результат дополнительно содержит выбранные `router`, `bundler` и полный target вида `next@app/turbopack`.
|
||||
|
||||
## `defineReactSpriteConfig`
|
||||
|
||||
```ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
inputFiles: [
|
||||
'../../shared/icons/check.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
`inputFolder` и `inputFiles` объединяются. Хелпер возвращает конфиг без runtime-преобразований и предоставляет TypeScript autocomplete.
|
||||
|
||||
## `defineNextSpriteConfig`
|
||||
|
||||
```ts
|
||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineNextSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
inputFolder: './icons',
|
||||
})
|
||||
```
|
||||
|
||||
Next.js использует тот же контракт конфигурации, что и React presets.
|
||||
|
||||
## `generateLegacy`
|
||||
|
||||
```ts
|
||||
import { generateLegacy } from '@gromlab/svg-sprites'
|
||||
|
||||
const results = await generateLegacy({
|
||||
output: 'public/sprites',
|
||||
preview: false,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: 'src/assets/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Возвращается массив:
|
||||
|
||||
```ts
|
||||
type SpriteResult = {
|
||||
name: string
|
||||
format: 'symbol' | 'stack'
|
||||
spritePath: string
|
||||
iconCount: number
|
||||
}
|
||||
```
|
||||
|
||||
Подробнее: [Legacy mode](legacy.md).
|
||||
|
||||
## Низкоуровневые функции
|
||||
|
||||
Основная точка входа также экспортирует:
|
||||
|
||||
```ts
|
||||
import {
|
||||
compileSprite,
|
||||
compileSpriteContent,
|
||||
createShapeTransform,
|
||||
generatePreview,
|
||||
loadLegacyConfig,
|
||||
loadReactSpriteConfig,
|
||||
resolveSpriteEntry,
|
||||
resolveSprites,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
Эти функции предназначены для собственного orchestration поверх существующего compiler и writer. Для стандартного использования предпочтительны `generateReactSprite` и `generateLegacy`.
|
||||
|
||||
## React runtime entry
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
Типы:
|
||||
|
||||
```ts
|
||||
import type {
|
||||
SpriteManifest,
|
||||
SpriteManifestColor,
|
||||
SpriteManifestIcon,
|
||||
SpriteManifestLoader,
|
||||
SpriteManifestModule,
|
||||
SpriteViewerColorTheme,
|
||||
SpriteViewerProps,
|
||||
SpriteViewerSource,
|
||||
SpriteViewerSources,
|
||||
} from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
React entry содержит `'use client'` и предназначен для debug-инструментов. Generated production-компоненты импортируются из локальных sprite-модулей приложения, а не из React entry пакета.
|
||||
|
||||
`SpriteViewerProps.colorTheme` принимает `auto | light | dark`. Значение `auto` используется по умолчанию и следует `prefers-color-scheme`; для синхронизации с темой приложения передавайте вычисленное `light` или `dark`.
|
||||
|
||||
## Связанные руководства
|
||||
|
||||
- [React + Vite](react-vite.md)
|
||||
- [React + Webpack 5](react-webpack.md)
|
||||
Canonical документ: [программный API](reference/programmatic-api.md).
|
||||
|
||||
@@ -1,116 +1,3 @@
|
||||
# React + Vite
|
||||
# Guide React + Vite перемещён
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Vite.
|
||||
|
||||
В результате вы получите типизированный React-компонент и отдельный кешируемый SVG asset.
|
||||
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте папку спрайта
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Поместите исходные SVG-файлы в `icons/`.
|
||||
|
||||
## 3. Добавьте конфиг
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
})
|
||||
```
|
||||
|
||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||
|
||||
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||
|
||||
## 4. Добавьте генерацию в package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode react@vite src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generated-файлы исключаются из Git, поэтому генерация должна выполняться перед `dev`, `build` и `typecheck`.
|
||||
|
||||
Первый запуск:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 5. Используйте компонент
|
||||
|
||||
Имя `file-manager` преобразуется в `FileManagerIcon`:
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from './svg-sprite'
|
||||
|
||||
export const OpenFolderButton = () => (
|
||||
<button type="button">
|
||||
<FileManagerIcon icon="folder" width={24} height={24} />
|
||||
Открыть
|
||||
</button>
|
||||
)
|
||||
```
|
||||
|
||||
Значение `icon` проверяется TypeScript по именам файлов:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="check" /> // допустимо
|
||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||
|
||||
Vite выпустит спрайт отдельным файлом вида `assets/sprite-<hash>.svg`. SVG path-данные не попадут в JavaScript.
|
||||
|
||||
## 6. Добавьте debug-страницу
|
||||
|
||||
После подключения иконок можно вывести все React-спрайты через `SpriteViewer`:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = import.meta.glob<SpriteManifestModule>(
|
||||
'/src/**/svg-sprite/manifest.ts',
|
||||
)
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
)
|
||||
```
|
||||
|
||||
Vite автоматически найдёт generated `manifest.ts` каждого React-спрайта. Шаблон `import.meta.glob` должен быть строковым литералом, а генерация должна выполниться до запуска Vite.
|
||||
|
||||
Размещайте Viewer только на debug-маршруте или во внутреннем инструменте.
|
||||
|
||||
## Если что-то не работает
|
||||
|
||||
- Нет `index.ts`: запустите `npm run sprite:file-manager`.
|
||||
- Viewer не видит спрайт: проверьте путь glob и наличие `manifest.ts`.
|
||||
- Ошибка `Refusing to overwrite a user file`: в generated-пути находится пользовательский файл.
|
||||
- Иконка не меняет цвет: используйте `color` или `--icon-color-N`.
|
||||
Canonical guide: [React + Vite](guides/react-vite.md).
|
||||
|
||||
@@ -1,118 +1,3 @@
|
||||
# React + Webpack 5
|
||||
# Guide React + Webpack перемещён
|
||||
|
||||
[← Главная](../../README_RU.md)
|
||||
|
||||
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Webpack 5.
|
||||
|
||||
В результате вы получите типизированный React-компонент и отдельный SVG asset через Webpack Asset Modules.
|
||||
|
||||
## 1. Установите пакет
|
||||
|
||||
```bash
|
||||
npm install @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## 2. Создайте папку спрайта
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Поместите исходные SVG-файлы в `icons/`.
|
||||
|
||||
## 3. Добавьте конфиг
|
||||
|
||||
```ts
|
||||
// src/ui/file-manager/svg-sprite/svg-sprite.config.ts
|
||||
import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineReactSpriteConfig({
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
})
|
||||
```
|
||||
|
||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||
|
||||
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||
|
||||
## 4. Добавьте генерацию в package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "svg-sprites --mode react@webpack src/ui/file-manager/svg-sprite",
|
||||
"predev": "npm run sprite:file-manager",
|
||||
"prebuild": "npm run sprite:file-manager",
|
||||
"pretypecheck": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Generated-файлы исключаются из Git, поэтому генерация должна выполняться перед `dev`, `build` и `typecheck`.
|
||||
|
||||
Первый запуск:
|
||||
|
||||
```bash
|
||||
npm run sprite:file-manager
|
||||
```
|
||||
|
||||
## 5. Используйте компонент
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from './svg-sprite'
|
||||
|
||||
export const OpenFolderButton = () => (
|
||||
<button type="button">
|
||||
<FileManagerIcon icon="folder" width={24} height={24} />
|
||||
Открыть
|
||||
</button>
|
||||
)
|
||||
```
|
||||
|
||||
Значение `icon` проверяется TypeScript по именам файлов:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon icon="folder" /> // допустимо
|
||||
<FileManagerIcon icon="missing" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||
|
||||
Webpack обработает generated `new URL('./sprite.svg', import.meta.url)` через Asset Modules и выпустит отдельный SVG asset.
|
||||
|
||||
Если проект уже использует собственный SVG loader, убедитесь, что он не перехватывает generated `sprite.svg` вместо Asset Modules.
|
||||
|
||||
## 6. Добавьте debug-страницу
|
||||
|
||||
Webpack не поддерживает Vite API `import.meta.glob`, поэтому передайте статические loaders:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = [
|
||||
() => import('./ui/file-manager/svg-sprite/manifest'),
|
||||
() => import('./ui/navigation/svg-sprite/manifest'),
|
||||
]
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
)
|
||||
```
|
||||
|
||||
Пути в `import()` должны быть строковыми литералами. Webpack создаст chunks для манифестов и свяжет их с SVG assets.
|
||||
|
||||
Размещайте Viewer только на debug-маршруте или во внутреннем инструменте.
|
||||
|
||||
## Если что-то не работает
|
||||
|
||||
- Нет `index.ts`: запустите `npm run sprite:file-manager`.
|
||||
- Viewer не загружает спрайт: проверьте путь в `import()` и наличие `manifest.ts`.
|
||||
- Неверный URL asset: проверьте `output.publicPath`.
|
||||
- SVG перехватывает другой loader: исключите generated sprite из несовместимого правила.
|
||||
|
||||
Для Next.js используйте отдельные mode key из руководств [App Router](next-app.md) и [Pages Router](next-pages.md).
|
||||
Canonical guide: [React + Webpack](guides/react-webpack.md).
|
||||
|
||||
3
docs/ru/reference.md
Normal file
3
docs/ru/reference.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Технический справочник перемещён
|
||||
|
||||
Canonical документ: [технический справочник](reference/technical.md).
|
||||
4
docs/ru/reference/README.md
Normal file
4
docs/ru/reference/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Справочники
|
||||
|
||||
- [Технический справочник](technical.md)
|
||||
- [Программный API](programmatic-api.md)
|
||||
147
docs/ru/reference/programmatic-api.md
Normal file
147
docs/ru/reference/programmatic-api.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Программный API
|
||||
|
||||
[Индекс документации](../README.md)
|
||||
|
||||
Пакет распространяется как ESM и предоставляет единый Node.js API генерации. Framework-neutral Viewer находится в `@gromlab/svg-sprites/viewer`, auto-register entry — в `@gromlab/svg-sprites/viewer/element`, React bridge — в `@gromlab/svg-sprites/react`.
|
||||
|
||||
## `generateSprite`
|
||||
|
||||
```ts
|
||||
import { generateSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
const result = await generateSprite(
|
||||
'src/ui/file-manager/svg-sprite/svg-sprite.config.ts',
|
||||
)
|
||||
```
|
||||
|
||||
Для static standalone mode `result.spritePath` можно использовать в build-скрипте,
|
||||
чтобы опубликовать SVG по URL приложения:
|
||||
|
||||
```ts
|
||||
import { copyFile } from 'node:fs/promises'
|
||||
|
||||
const result = await generateSprite('src/sprite/svg-sprite.config.ts', {
|
||||
mode: 'standalone',
|
||||
})
|
||||
await copyFile(result.spritePath, 'dist/app-icons/sprite.svg')
|
||||
```
|
||||
|
||||
`spritePath` является filesystem path, а не browser URL. Deployment-neutral JSON
|
||||
manifest доступен через `result.manifestPath` и копируется независимо от SVG.
|
||||
|
||||
Первый аргумент принимает полный путь к config-файлу с любым именем и расширением `.ts`, `.js` или `.json`. Каталог вместо файла включает config-less режим: корнем sprite-модуля становится этот каталог.
|
||||
|
||||
Второй аргумент содержит необязательные overrides и всегда имеет приоритет над конфигом:
|
||||
|
||||
```ts
|
||||
await generateSprite('src/ui/file-manager/svg-sprite/custom-config.json', {
|
||||
mode: 'react@webpack',
|
||||
name: 'documents',
|
||||
input: ['./assets', '../../shared/search.svg'],
|
||||
transform: {
|
||||
addTransition: false,
|
||||
},
|
||||
generatedNotice: false,
|
||||
})
|
||||
```
|
||||
|
||||
Порядок разрешения настроек:
|
||||
|
||||
```text
|
||||
defaults → config → API overrides
|
||||
```
|
||||
|
||||
Для полностью программной генерации передайте каталог и все обязательные настройки через overrides:
|
||||
|
||||
```ts
|
||||
await generateSprite('src/ui/file-manager/svg-sprite', {
|
||||
mode: 'react@vite',
|
||||
name: 'file-manager',
|
||||
input: [
|
||||
'../../shared/search.svg',
|
||||
'../../shared/settings.svg',
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## Конфигурация
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'react@vite',
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
input: ['./icons', '../../shared/check.svg'],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
`input` принимает одну папку, SVG-файл или glob-паттерн либо массив, объединяющий такие источники. Если поле не задано, используется `./icons`; относительные пути считаются от папки с конфигом.
|
||||
|
||||
`defineSpriteConfig` является identity helper для TypeScript autocomplete. JS может экспортировать тот же объект через `export default`, а JSON содержит объект непосредственно.
|
||||
|
||||
## Специализированные обёртки
|
||||
|
||||
Специализированные функции доступны как обёртки над `generateSprite`:
|
||||
|
||||
```ts
|
||||
import { generateNextSprite, generateReactSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
await generateReactSprite('path/to/config.ts', 'vite')
|
||||
await generateNextSprite('path/to/config.ts', {
|
||||
router: 'app',
|
||||
bundler: 'turbopack',
|
||||
})
|
||||
```
|
||||
|
||||
Явно переданный target перекрывает `mode` из файла. Для нового кода используйте `generateSprite`.
|
||||
|
||||
## Config API
|
||||
|
||||
```ts
|
||||
import {
|
||||
loadSpriteConfig,
|
||||
resolveSpriteConfig,
|
||||
validateSpriteConfig,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
- `loadSpriteConfig(file)` загружает явно указанный `.ts`, `.js` или `.json` файл.
|
||||
- `validateSpriteConfig(value)` выполняет runtime-валидацию объекта.
|
||||
- `resolveSpriteConfig(root, config, overrides)` объединяет значения, добавляет defaults и разрешает пути относительно `root`.
|
||||
|
||||
## Низкоуровневый compiler
|
||||
|
||||
```ts
|
||||
import {
|
||||
compileSprite,
|
||||
compileSpriteContent,
|
||||
createShapeTransform,
|
||||
} from '@gromlab/svg-sprites'
|
||||
```
|
||||
|
||||
Эти функции предназначены для собственного orchestration. Стандартная генерация должна выполняться через `generateSprite`.
|
||||
|
||||
## Viewer runtime
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
```
|
||||
|
||||
Browser entry регистрирует `<gromlab-sprite-viewer>`. Bare standalone также может загрузить самостоятельный `dist/viewer-element.js` без bundler.
|
||||
|
||||
React bridge сохраняет компонентный API:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
`SpriteViewer` принимает generated manifests, remote standalone sources, lazy loaders или результат `import.meta.glob`. React entry содержит `'use client'` и предназначен для debug-инструментов; production-компоненты импортируются из локальных sprite-модулей приложения.
|
||||
631
docs/ru/reference/technical.md
Normal file
631
docs/ru/reference/technical.md
Normal file
@@ -0,0 +1,631 @@
|
||||
# Технический справочник
|
||||
|
||||
[Индекс документации](../README.md)
|
||||
|
||||
Справочник по конфигурации, generated API и поведению `@gromlab/svg-sprites`. Пошаговую установку смотрите в руководстве для вашего стека:
|
||||
|
||||
- [Bare standalone](../guides/standalone.md)
|
||||
- [Standalone + Vite](../guides/standalone-vite.md)
|
||||
- [Standalone + Webpack 5](../guides/standalone-webpack.md)
|
||||
- [React + Vite](../guides/react-vite.md)
|
||||
- [React + Webpack 5](../guides/react-webpack.md)
|
||||
- [Next.js App Router + Turbopack](../guides/next-app-turbopack.md)
|
||||
- [Next.js App Router + Webpack](../guides/next-app-webpack.md)
|
||||
- [Next.js Pages Router + Turbopack](../guides/next-pages-turbopack.md)
|
||||
- [Next.js Pages Router + Webpack](../guides/next-pages-webpack.md)
|
||||
|
||||
## Требования
|
||||
|
||||
- Node.js 18 или новее;
|
||||
- пакет распространяется как ESM и подключается через `import`;
|
||||
- React 18 или 19 требуется только для React/Next generated-компонентов и `@gromlab/svg-sprites/react`;
|
||||
- для типизации package exports используйте TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
||||
|
||||
Для генерации не нужна dependency проекта. Запускайте CLI через `npx`:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites path/to/svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Устанавливайте пакет как development dependency, только если проекту нужны
|
||||
Viewer, типы конфига или программный API:
|
||||
|
||||
```bash
|
||||
npm install --save-dev @gromlab/svg-sprites
|
||||
```
|
||||
|
||||
## CLI и режимы генерации
|
||||
|
||||
CLI принимает ровно один путь: явно выбранный config-файл либо каталог для config-less генерации:
|
||||
|
||||
```text
|
||||
svg-sprites [options] <config-file-or-directory>
|
||||
```
|
||||
|
||||
| Среда | Mode |
|
||||
|---|---|
|
||||
| Static HTML / собственная публикация | `standalone` |
|
||||
| Standalone + Vite | `standalone@vite` |
|
||||
| Standalone + Webpack 5 | `standalone@webpack` |
|
||||
| React + Vite | `react@vite` |
|
||||
| React + Webpack 5 | `react@webpack` |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` |
|
||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
Config-файл может иметь любое имя и расширение `.ts`, `.js` или `.json`. CLI не ищет конфиг по соглашению: файл нужно передать явно. В руководствах используется рекомендуемое имя `svg-sprite.config.ts`.
|
||||
|
||||
Если передан каталог, все настройки берутся из CLI. Если передан config-файл, CLI-параметры перекрывают значения файла. Общий порядок: `defaults → config → CLI`.
|
||||
|
||||
Доступны `--mode`, `--name`, `--description`, повторяемый `--input <path-or-glob>`, а также пары `--remove-size`/`--no-remove-size`, `--replace-colors`/`--no-replace-colors`, `--add-transition`/`--no-add-transition` и `--generated-notice`/`--no-generated-notice`. Переданные transform-флаги перекрывают отдельные поля, а хотя бы один `--input` полностью заменяет значение `input` из config.
|
||||
|
||||
В CLI заключайте glob-паттерны в одинарные кавычки, чтобы shell не раскрыл их до запуска генератора:
|
||||
|
||||
```bash
|
||||
svg-sprites --input './icons/**/*.svg' --input '!./icons/legacy/**' svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Mode должен соответствовать способу публикации приложения. Bare `standalone` оставляет публичный URL приложению; Vite и Webpack modes генерируют bundler-specific подключение SVG asset.
|
||||
|
||||
## Единая конфигурация
|
||||
|
||||
Каждый config-файл описывает один независимый спрайт.
|
||||
|
||||
```ts
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'app',
|
||||
description: 'Общие иконки приложения',
|
||||
input: [
|
||||
'./local-icons',
|
||||
'../../assets/icons/*.svg',
|
||||
'!../../assets/icons/deprecated-*.svg',
|
||||
],
|
||||
transform: {
|
||||
removeSize: true,
|
||||
replaceColors: true,
|
||||
addTransition: true,
|
||||
},
|
||||
generatedNotice: true,
|
||||
})
|
||||
```
|
||||
|
||||
| Опция | Тип | По умолчанию | Назначение |
|
||||
|---|---|---|---|
|
||||
| `mode` | `SpriteMode` | Нет | Режим генерации; можно передать через CLI/API |
|
||||
| `name` | `string` | Выводится из каталога | Имя спрайта, компонента и публичных типов |
|
||||
| `description` | `string` | Нет | Описание для типов и debug manifest |
|
||||
| `input` | `string \| string[]` | `./icons` | Папки, SVG-файлы и glob-паттерны относительно папки конфига |
|
||||
| `transform` | `TransformOptions` | Все включены | Настройки подготовки SVG |
|
||||
| `generatedNotice` | `boolean` | `true` | Полное или короткое предупреждение в generated-файлах |
|
||||
|
||||
### Имя спрайта
|
||||
|
||||
`name` записывается в kebab-case и должно начинаться с латинской буквы:
|
||||
|
||||
```text
|
||||
app → AppIcon
|
||||
file-manager → FileManagerIcon
|
||||
```
|
||||
|
||||
Если `name` не задано, генератор выводит его из каталога. Для каталога с именем `svg-sprite` или `svg-sprites` используется имя родительского каталога.
|
||||
|
||||
### Источники иконок
|
||||
|
||||
`SpriteConfig.input` является необязательным и имеет тип `string | string[]`. Если поле отсутствует, источником служит папка `./icons` относительно папки конфига. В config-less режиме относительные пути считаются от каталога, переданного CLI или API.
|
||||
|
||||
Каждая строка без префикса `!` может быть путём к конкретной папке, конкретному файлу `.svg` или glob-паттерном. Папка включает только непосредственные дочерние `*.svg`. Для рекурсивного обхода вложенных каталогов укажите явный паттерн, например `icons/**/*.svg`.
|
||||
|
||||
Массив объединяет все включающие источники. Паттерн с префиксом `!` глобально исключает совпадения из общего результата независимо от того, какой источник их добавил.
|
||||
|
||||
Поддерживается следующий glob-синтаксис:
|
||||
|
||||
| Синтаксис | Значение |
|
||||
|---|---|
|
||||
| `*` | Любые символы внутри одного сегмента пути |
|
||||
| `**` | Любое число вложенных каталогов |
|
||||
| `?` | Один символ внутри сегмента пути |
|
||||
| `{a,b}` | Одна из альтернатив |
|
||||
| `[abc]` | Один символ из набора или диапазона |
|
||||
| `!pattern` | Исключение совпадений из всего объединённого input |
|
||||
|
||||
Каждый включающий источник или паттерн должен найти хотя бы один SVG, иначе генерация завершается ошибкой. Повторяющиеся пути удаляются, а итоговый список файлов детерминированно сортируется. Разные SVG с одинаковым basename по-прежнему считаются конфликтом, потому что basename задаёт публичное имя иконки.
|
||||
|
||||
## Generated-модуль
|
||||
|
||||
После генерации React- или Next.js-каталог спрайта выглядит так:
|
||||
|
||||
```text
|
||||
app-icons/
|
||||
├── .gitignore
|
||||
├── svg-sprite.config.ts
|
||||
├── index.ts # необязательный пользовательский barrel
|
||||
└── .svg-sprite/
|
||||
├── index.js
|
||||
├── index.d.ts
|
||||
├── icon-data.js
|
||||
├── icon-data.d.ts
|
||||
├── sprite.svg
|
||||
├── svg-sprite.manifest.js
|
||||
├── svg-sprite.manifest.d.ts
|
||||
└── react/
|
||||
├── react-component.js
|
||||
├── react-component.d.ts
|
||||
└── react-component.module.css
|
||||
```
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `.svg-sprite/index.js` | Mode-specific production facade и runtime-список имён |
|
||||
| `.svg-sprite/index.d.ts` | Публичные декларации facade, компонента и union-типа имён |
|
||||
| `.svg-sprite/svg-sprite.manifest.js` | Debug metadata и URL asset для `SpriteViewer` |
|
||||
| `.svg-sprite/sprite.svg` | Собранный SVG-спрайт |
|
||||
| `.svg-sprite/react/react-component.js` | Runtime React-компонента без TypeScript и JSX |
|
||||
| `.svg-sprite/react/react-component.d.ts` | Props, style и declaration React-компонента |
|
||||
| `.svg-sprite/react/react-component.module.css` | Стили конкретной React-реализации |
|
||||
| `.svg-sprite/icon-data.js` | Runtime-список имён и внутренние IDs |
|
||||
| `.svg-sprite/*.d.ts` | TypeScript-декларации соответствующих JS-модулей |
|
||||
|
||||
Standalone-контракты не создают каталог `react/`. Bare `standalone` содержит только
|
||||
runtime asset и deployment-neutral manifest data:
|
||||
|
||||
```text
|
||||
.svg-sprite/
|
||||
├── sprite.svg
|
||||
└── svg-sprite.manifest.json
|
||||
```
|
||||
|
||||
`standalone@vite` и `standalone@webpack` дополнительно создают `index.*`,
|
||||
`icon-data.*` и resolved `svg-sprite.manifest.*`. Их facade содержит нативный
|
||||
generated Web Component без внешних runtime-зависимостей. Bare `standalone`
|
||||
намеренно не создаёт JavaScript-компонент.
|
||||
|
||||
Генератор перезаписывает и удаляет только файлы со своим marker. Если в managed-пути находится пользовательский файл, генерация завершается ошибкой. Корневой `index.ts` генератору не принадлежит; при необходимости создайте пользовательский barrel:
|
||||
|
||||
```ts
|
||||
export * from './.svg-sprite'
|
||||
```
|
||||
|
||||
## Standalone Web Component и TypeScript
|
||||
|
||||
В modes `standalone@vite` и `standalone@webpack` спрайт с `name: 'app'`
|
||||
экспортирует функцию регистрации `defineAppIconElement()` и tag `<app-icon>`:
|
||||
|
||||
```ts
|
||||
import { defineAppIconElement } from '@/ui/app-icons'
|
||||
|
||||
defineAppIconElement()
|
||||
```
|
||||
|
||||
После регистрации элемент можно использовать в HTML:
|
||||
|
||||
```html
|
||||
<app-icon icon="search" aria-hidden="true"></app-icon>
|
||||
|
||||
<app-icon
|
||||
icon="settings"
|
||||
role="img"
|
||||
aria-label="Настройки"
|
||||
></app-icon>
|
||||
```
|
||||
|
||||
Компонент рендерит `<svg><use>` в открытом Shadow DOM, сам выбирает внутренний
|
||||
ID и `viewBox`, а URL asset получает через соответствующий Vite или Webpack
|
||||
механизм. Размер host по умолчанию равен `1em × 1em`; `class`, `style`, `color`
|
||||
и `--icon-color-N` задаются обычным CSS.
|
||||
|
||||
Generated `HTMLElementTagNameMap` типизирует property API:
|
||||
|
||||
```ts
|
||||
const icon = document.createElement('app-icon')
|
||||
|
||||
icon.icon = 'search'
|
||||
icon.icon = 'unknown' // ошибка TypeScript
|
||||
```
|
||||
|
||||
Значения атрибутов в обычной HTML-разметке TypeScript не проверяет. Поэтому
|
||||
неизвестный `icon="unknown"` дополнительно проверяется в runtime: компонент
|
||||
скрывает внутренний SVG и сообщает об ошибке, не создавая fragment
|
||||
`#undefined`. Повторный вызов `defineAppIconElement()` безопасен для того же
|
||||
спрайта; конфликт с другим элементом под tag `<app-icon>` завершается ошибкой.
|
||||
|
||||
## React-компонент и TypeScript
|
||||
|
||||
Спрайт с `name: 'app'` экспортирует:
|
||||
|
||||
```ts
|
||||
export { AppIcon, appIconNames }
|
||||
export type { AppIconName, AppIconProps, AppIconStyle }
|
||||
```
|
||||
|
||||
### Имена иконок
|
||||
|
||||
Имена SVG-файлов становятся допустимыми значениями `icon`:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" />
|
||||
<AppIcon icon="unknown" /> // ошибка TypeScript
|
||||
```
|
||||
|
||||
Runtime-список содержит те же значения:
|
||||
|
||||
```ts
|
||||
import { appIconNames } from '@/ui/app-icons'
|
||||
|
||||
// readonly ['search', 'settings', 'user']
|
||||
```
|
||||
|
||||
Имена с пробелами и другими небезопасными для SVG ID символами остаются частью публичного API. Для внутреннего fragment ID генератор создаёт стабильный безопасный hash:
|
||||
|
||||
```text
|
||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
||||
```
|
||||
|
||||
Для таких имён используйте generated-компонент или `id` из debug manifest, а не формируйте fragment ID вручную.
|
||||
|
||||
### SVG-атрибуты
|
||||
|
||||
По умолчанию компонент рендерит `<svg>` и принимает стандартные SVG-атрибуты:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="search"
|
||||
width={24}
|
||||
height={24}
|
||||
color="rebeccapurple"
|
||||
className="searchIcon"
|
||||
aria-label="Поиск"
|
||||
/>
|
||||
```
|
||||
|
||||
Компонент не добавляет accessibility-семантику автоматически. Передавайте подходящие `aria-*`, `role` или подпись в зависимости от назначения иконки.
|
||||
|
||||
### Обёртка
|
||||
|
||||
`wrapped` рендерит `<span>` с внутренним SVG. Остальные props в этом режиме относятся к `<span>`:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" wrapped className="iconWrapper" />
|
||||
```
|
||||
|
||||
### Типизированные CSS-переменные
|
||||
|
||||
`AppIconStyle` расширяет `CSSProperties` и поддерживает свойства вида `--icon-color-N`:
|
||||
|
||||
```tsx
|
||||
<AppIcon
|
||||
icon="user"
|
||||
style={{
|
||||
'--icon-color-1': '#2563eb',
|
||||
'--icon-color-2': '#dbeafe',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
## Множественные спрайты
|
||||
|
||||
Каждый каталог с конфигом создаёт независимый компонент, типы, manifest и SVG asset:
|
||||
|
||||
```text
|
||||
app-icons → AppIcon → общие иконки
|
||||
analytics-icons → AnalyticsIcon → иконки страницы аналитики
|
||||
editor-icons → EditorIcon → иконки редактора
|
||||
```
|
||||
|
||||
Один исходный SVG можно добавить через `input` в несколько конфигураций. Копировать файл в каталоги каждого спрайта не требуется.
|
||||
|
||||
Для нескольких спрайтов добавьте отдельную CLI-команду для каждого каталога или объедините команды в общем npm script.
|
||||
|
||||
## Форматы и способы отображения
|
||||
|
||||
Все текущие modes создают формат `stack`.
|
||||
|
||||
| Формат | `<svg><use>` | `<img>` | CSS background |
|
||||
|---|---:|---:|---:|
|
||||
| `stack` | Да | Да | Да |
|
||||
|
||||
### Generated-компонент
|
||||
|
||||
Для React и Next.js используйте generated React-компонент. Он знает внутренние ID, формирует URL и предоставляет TypeScript API:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" width={24} height={24} />
|
||||
```
|
||||
|
||||
Для `standalone@vite` и `standalone@webpack` используйте generated Web Component:
|
||||
|
||||
```html
|
||||
<app-icon icon="search" style="font-size: 24px"></app-icon>
|
||||
```
|
||||
|
||||
### Вручную через `<svg><use>`
|
||||
|
||||
Способ получения `spriteUrl` зависит от сборщика.
|
||||
|
||||
Static HTML после публикации `.svg-sprite/sprite.svg` приложением:
|
||||
|
||||
```html
|
||||
<svg aria-hidden="true">
|
||||
<use href="/assets/icons.svg#search"></use>
|
||||
</svg>
|
||||
```
|
||||
|
||||
Standalone Vite/Webpack предоставляет generated `getIconsIconHref()` и mapping
|
||||
внутренних IDs. Не конструируйте fragment из небезопасного имени файла вручную.
|
||||
|
||||
Vite:
|
||||
|
||||
```ts
|
||||
import spriteUrl from './.svg-sprite/sprite.svg?no-inline'
|
||||
```
|
||||
|
||||
Webpack 5, Turbopack и Next.js:
|
||||
|
||||
```ts
|
||||
const spriteUrl = new URL('./.svg-sprite/sprite.svg', import.meta.url).href
|
||||
```
|
||||
|
||||
После получения URL используйте его в JSX:
|
||||
|
||||
```tsx
|
||||
<svg width="24" height="24" aria-label="Поиск">
|
||||
<use href={`${spriteUrl}#search`} />
|
||||
</svg>
|
||||
```
|
||||
|
||||
Для имён, небезопасных как SVG ID, используйте внутренний `id` из manifest.
|
||||
|
||||
### Через `<img>`
|
||||
|
||||
```tsx
|
||||
<img src={`${spriteUrl}#search`} width={24} height={24} alt="Поиск" />
|
||||
```
|
||||
|
||||
SVG внутри `<img>` изолирован от CSS страницы. `color` и `--icon-color-N` на внешнем элементе не изменяют его внутренние цвета.
|
||||
|
||||
### Через CSS
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
Для одноцветного силуэта можно использовать mask:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
background-color: currentColor;
|
||||
mask: url('./.svg-sprite/sprite.svg#search') center / contain no-repeat;
|
||||
}
|
||||
```
|
||||
|
||||
Mask не сохраняет исходные цвета, gradients и различия между `fill` и `stroke`.
|
||||
|
||||
Путь в CSS разрешается относительно самого CSS-файла. В примерах CSS-файл находится рядом с `svg-sprite.config.ts`.
|
||||
|
||||
## Assets и кеширование
|
||||
|
||||
Generated component или standalone facade передаёт SVG сборщику как отдельный asset:
|
||||
|
||||
- Vite использует статический импорт с `?no-inline`;
|
||||
- Webpack 5, Turbopack и Next.js используют `new URL(..., import.meta.url)`;
|
||||
- SVG path-данные не сериализуются в generated JavaScript.
|
||||
|
||||
Bare `standalone` не участвует в asset pipeline: приложение само копирует или
|
||||
публикует `sprite.svg` и отвечает за URL, версионирование и cache policy.
|
||||
|
||||
При стандартном именовании assets сборщик добавляет content hash:
|
||||
|
||||
```text
|
||||
/assets/sprite-<hash>.svg
|
||||
```
|
||||
|
||||
Это позволяет кешировать SVG отдельно от JavaScript. Изменение React-кода не меняет содержимое спрайта, а изменение иконок создаёт новую версию asset.
|
||||
|
||||
HTTP cache headers, CDN и `Cache-Control` настраиваются приложением или платформой размещения. Для Webpack имя итогового файла зависит от `assetModuleFilename` проекта.
|
||||
|
||||
## Трансформации SVG
|
||||
|
||||
Все трансформации включены по умолчанию и настраиваются независимо:
|
||||
|
||||
| Опция | Что делает |
|
||||
|---|---|
|
||||
| `removeSize` | Удаляет `width` и `height` с корневого `<svg>`, сохраняя существующий `viewBox` |
|
||||
| `replaceColors` | Заменяет найденные `fill` и `stroke` на `--icon-color-N` |
|
||||
| `addTransition` | Добавляет transitions для `fill` и `stroke` в цветные элементы и generated styles |
|
||||
|
||||
Чтобы отключить отдельную операцию:
|
||||
|
||||
```ts
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/turbopack',
|
||||
transform: {
|
||||
removeSize: false,
|
||||
replaceColors: false,
|
||||
addTransition: false,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Исходные SVG не изменяются. Трансформации применяются только к содержимому generated-спрайта.
|
||||
|
||||
## Управление цветами
|
||||
|
||||
### Монохромные иконки
|
||||
|
||||
Если найден один цвет, fallback становится `currentColor`:
|
||||
|
||||
```svg
|
||||
stroke="var(--icon-color-1, currentColor)"
|
||||
```
|
||||
|
||||
Цвет задаётся через prop или CSS:
|
||||
|
||||
```tsx
|
||||
<AppIcon icon="search" color="rebeccapurple" />
|
||||
```
|
||||
|
||||
### Многоцветные иконки
|
||||
|
||||
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
|
||||
|
||||
```svg
|
||||
fill="var(--icon-color-1, #798198)"
|
||||
fill="var(--icon-color-2, #ffffff)"
|
||||
fill="var(--icon-color-3, #129d9d)"
|
||||
```
|
||||
|
||||
Можно заменить только необходимые значения:
|
||||
|
||||
```css
|
||||
.icon {
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-3: #14b8a6;
|
||||
}
|
||||
```
|
||||
|
||||
### Ограничения
|
||||
|
||||
- `none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
|
||||
- надёжнее всего обрабатываются цвета в атрибутах `fill`, `stroke` и inline `style`;
|
||||
- CSS-классы и внешние stylesheets внутри SVG не являются основным сценарием трансформации;
|
||||
- значения `url(#...)` могут быть заменены вместе с цветами, поэтому gradients и patterns требуют отдельного спрайта с `replaceColors: false`;
|
||||
- masks, filters и сложные внутренние CSS-правила требуют визуальной проверки;
|
||||
- CSS-переменные страницы доступны через `<svg><use>`, но не внутри `<img>` и CSS background.
|
||||
|
||||
Для сложной иконки можно отключить `replaceColors` в конфигурации отдельного спрайта.
|
||||
|
||||
## SpriteViewer
|
||||
|
||||
Viewer использует один Web Component с Shadow DOM для всех modes. React и будущие framework-компоненты являются bridge к этому же элементу, поэтому визуал и поведение не дублируются.
|
||||
|
||||
Bare `standalone` подключает самостоятельный browser bundle и передаёт URL JSON manifest и опубликованного SVG:
|
||||
|
||||
```html
|
||||
<script
|
||||
type="module"
|
||||
src="https://unpkg.com/@gromlab/svg-sprites@<version>/dist/viewer-element.js"
|
||||
></script>
|
||||
|
||||
<gromlab-sprite-viewer
|
||||
viewer-title="Иконки проекта"
|
||||
manifest-url="/app-icons/manifest.json"
|
||||
sprite-url="/app-icons/sprite.svg"
|
||||
></gromlab-sprite-viewer>
|
||||
```
|
||||
|
||||
`viewer-element.js` не имеет дополнительных runtime-файлов и может быть скопирован с остальными static assets для self-hosting.
|
||||
|
||||
`standalone@vite` и `standalone@webpack` регистрируют тот же элемент через npm entry и передают generated JS manifest через свойство `sources`:
|
||||
|
||||
```ts
|
||||
import '@gromlab/svg-sprites/viewer/element'
|
||||
import type { SpriteViewerElement } from '@gromlab/svg-sprites/viewer'
|
||||
import spriteManifest from './svg-sprite/.svg-sprite/svg-sprite.manifest.js'
|
||||
|
||||
const viewer = document.querySelector<SpriteViewerElement>('gromlab-sprite-viewer')!
|
||||
viewer.sources = [spriteManifest]
|
||||
```
|
||||
|
||||
React и Next.js сохраняют компонентный API:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
```
|
||||
|
||||
Он принимает готовые manifests, remote standalone sources, массив lazy loaders или record формата `import.meta.glob`.
|
||||
|
||||
Vite:
|
||||
|
||||
```tsx
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
import type { SpriteManifestModule } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const sources = import.meta.glob<SpriteManifestModule>(
|
||||
'/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js',
|
||||
)
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} title="Иконки проекта" />
|
||||
)
|
||||
```
|
||||
|
||||
Webpack и Next.js:
|
||||
|
||||
```tsx
|
||||
const sources = [
|
||||
() => import('@/ui/app-icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
() => import('@/features/analytics/icons/.svg-sprite/svg-sprite.manifest.js'),
|
||||
]
|
||||
|
||||
export const IconsDebugPage = () => (
|
||||
<SpriteViewer sources={sources} />
|
||||
)
|
||||
```
|
||||
|
||||
Viewer показывает группы, поиск, `viewBox`, CSS-переменные и fallback-цвета. React/Next manifests получают вкладки React, SVG, IMG и CSS; standalone manifests получают SVG, IMG и CSS. Цветовые значения можно менять в интерфейсе и сразу проверять результат.
|
||||
|
||||
### Тема Viewer
|
||||
|
||||
По умолчанию `colorTheme="auto"` следует `prefers-color-scheme`. Можно передать `light` или `dark` явно:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||
```
|
||||
|
||||
Для синхронизации с темой приложения:
|
||||
|
||||
```tsx
|
||||
<SpriteViewer
|
||||
sources={sources}
|
||||
colorTheme={appTheme}
|
||||
onColorThemeChange={setAppTheme}
|
||||
/>
|
||||
```
|
||||
|
||||
`@gromlab/svg-sprites/react` содержит `'use client'` и рендерит Web Component host; внутренний Shadow DOM создаётся после загрузки browser runtime. В Next.js App Router размещайте Viewer внутри отдельной Client Component boundary и используйте только на debug-маршруте или во внутреннем инструменте.
|
||||
|
||||
## Generated-файлы, Git и CI
|
||||
|
||||
Все modes, кроме bare `standalone`, создают локальный `.gitignore` для:
|
||||
|
||||
```text
|
||||
/.svg-sprite/
|
||||
```
|
||||
|
||||
Локальный `.gitignore` следует один раз добавить в репозиторий. Он исключает остальные generated-файлы, поэтому генерацию нужно запускать перед командами, которые импортируют sprite-модуль:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprites": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/app-icons/svg-sprite.config.ts",
|
||||
"predev": "npm run sprites",
|
||||
"prebuild": "npm run sprites",
|
||||
"pretypecheck": "npm run sprites"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
CI должен выполнять generation script до сборки или проверки типов. Для воспроизводимости замените `latest` на точную версию. Локальная установка package не нужна, если CI не использует Viewer, package-типы config или программный API.
|
||||
|
||||
Bare `standalone` не создаёт и не изменяет `.gitignore`: приложение само решает, коммитить или игнорировать его `.svg-sprite/`. В остальных modes генератор не перезапишет пользовательский `.gitignore`. Он также откажется перезаписывать пользовательский файл внутри `.svg-sprite`. Корневой `index.ts` остаётся пользовательским и может переэкспортировать generated API.
|
||||
|
||||
## Диагностика
|
||||
|
||||
- Нет `.svg-sprite/index.js`: запустите generation script до импорта generated-модуля.
|
||||
- Не найден источник: передайте существующий config-файл или каталог sprite-модуля.
|
||||
- Не указан mode: добавьте `mode` в config либо передайте `--mode`.
|
||||
- Иконка отсутствует в типе: проверьте `input`, расширение `.svg`, glob-исключения и необходимость `**/*.svg` для вложенных папок.
|
||||
- Конфликт имени: два разных SVG имеют одинаковый basename; переименуйте один файл.
|
||||
- `Refusing to overwrite a user file`: в managed-пути находится файл без generated marker.
|
||||
- Иконка не меняет цвет: используйте `<svg><use>` или generated-компонент и проверьте `replaceColors`.
|
||||
- Webpack выдаёт неверный URL: проверьте Asset Modules, `output.publicPath` и SVG loaders.
|
||||
- Static sprite возвращает 404: проверьте post-generation copy или server alias и не передавайте filesystem `spritePath` в HTML.
|
||||
- Viewer не видит спрайт: проверьте путь к `.svg-sprite/svg-sprite.manifest.js` и выполните генерацию до запуска приложения.
|
||||
- Build и mode не совпадают: используйте target, соответствующий фактическому сборщику.
|
||||
|
||||
Для собственного orchestration и низкоуровневой компиляции смотрите [Программный API](programmatic-api.md).
|
||||
16
integration/.gitignore
vendored
Normal file
16
integration/.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
node_modules/
|
||||
playwright-report/
|
||||
test-results/
|
||||
apps/*/dist/
|
||||
apps/*/.angular/
|
||||
apps/*/.astro/
|
||||
apps/*/.next/
|
||||
apps/*/.nuxt/
|
||||
apps/*/.output/
|
||||
apps/*/.svelte-kit/
|
||||
apps/*/build/
|
||||
apps/*/out-tsc/
|
||||
apps/*/public/sprites/
|
||||
apps/*/static/sprites/
|
||||
apps/*/*.tsbuildinfo
|
||||
apps/*/src/sprite/.svg-sprite/
|
||||
77
integration/README.md
Normal file
77
integration/README.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Integration playground
|
||||
|
||||
Постоянные минимальные consumer-приложения для проверки генерации, typecheck,
|
||||
production build и отображения внешнего SVG-спрайта в настоящем Chromium.
|
||||
|
||||
## Матрица
|
||||
|
||||
| Fixture | Генератор | Runtime |
|
||||
| --- | --- | --- |
|
||||
| `standalone` | `standalone` | Static HTML + явный copy SVG |
|
||||
| `standalone-vite` | `standalone@vite` | Vanilla TypeScript + Vite |
|
||||
| `standalone-webpack` | `standalone@webpack` | Vanilla TypeScript + Webpack 5 |
|
||||
| `react-vite` | `react@vite` | React + Vite |
|
||||
| `react-webpack` | `react@webpack` | React + Webpack 5 |
|
||||
| `next-app-turbopack` | `next@app/turbopack` | App Router + Turbopack |
|
||||
| `next-app-webpack` | `next@app/webpack` | App Router + Webpack |
|
||||
| `next-pages-turbopack` | `next@pages/turbopack` | Pages Router + Turbopack |
|
||||
| `next-pages-webpack` | `next@pages/webpack` | Pages Router + Webpack |
|
||||
|
||||
В verify-матрицу входят только поддерживаемые exact modes. Fixtures остальных
|
||||
frameworks сохранены как заготовки и будут подключаться после появления их adapters.
|
||||
|
||||
## Первый запуск
|
||||
|
||||
Из корня репозитория:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
npm run build:package
|
||||
npm run integration:install
|
||||
npm exec --prefix integration -- playwright install chromium
|
||||
npm run integration:verify
|
||||
```
|
||||
|
||||
`integration:verify` последовательно выполняет генерацию, typecheck, production build
|
||||
активных fixtures и Playwright smoke-тесты.
|
||||
|
||||
## Отдельные этапы
|
||||
|
||||
```bash
|
||||
npm run integration:generate
|
||||
npm run integration:build
|
||||
npm run integration:test
|
||||
```
|
||||
|
||||
Для запуска команды только в одном fixture:
|
||||
|
||||
```bash
|
||||
node integration/scripts/run-workspaces.mjs build react-vite
|
||||
npm run dev --workspace @svg-sprites-fixtures/react-vite --prefix integration
|
||||
```
|
||||
|
||||
Перед E2E production builds должны существовать. Тест запускает каждый server
|
||||
последовательно, проверяет внешний `href`, HTTP status и Content-Type спрайта,
|
||||
наличие symbol ID, отсутствие browser errors и зелёные пиксели отрисованной иконки.
|
||||
Для каждого active mode тест также открывает единый Viewer, проверяет его Shadow DOM,
|
||||
совпадение sprite URL, карточку `check`, dialog и mode-specific вкладки кода.
|
||||
|
||||
Static fixture копирует managed SVG и JSON manifest в `dist/app-icons/` и использует
|
||||
literal `<use href="/app-icons/sprite.svg#check">`.
|
||||
Vite и Webpack fixtures получают URL только из generated facade и сверяют его с
|
||||
resolved manifest.
|
||||
|
||||
## Структура
|
||||
|
||||
```text
|
||||
integration/
|
||||
├── apps/ # реальные consumer package boundaries
|
||||
├── fixtures/icons/ # общие исходные SVG
|
||||
├── scripts/ # workspace runner и static production server
|
||||
├── tests/ # Playwright runtime smoke
|
||||
├── package.json # отдельный npm workspace
|
||||
└── package-lock.json # зафиксированная framework matrix
|
||||
```
|
||||
|
||||
Generated-файлы, framework build outputs и Playwright artifacts исключены через
|
||||
`integration/.gitignore`.
|
||||
53
integration/apps/angular/angular.json
Normal file
53
integration/apps/angular/angular.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"$schema": "../../node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"angular": {
|
||||
"projectType": "application",
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"browser": "src/main.ts",
|
||||
"index": "src/index.html",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": ["src/styles.css"],
|
||||
"outputPath": "dist/angular"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular/build:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "angular:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "angular:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
integration/apps/angular/package.json
Normal file
27
integration/apps/angular/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@svg-sprites-fixtures/angular",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"typecheck": "ngc -p tsconfig.app.json --noEmit",
|
||||
"build": "npm run sprites && ng build --configuration production",
|
||||
"dev": "npm run sprites && ng serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/common": "21.2.18",
|
||||
"@angular/compiler": "21.2.18",
|
||||
"@angular/core": "21.2.18",
|
||||
"@angular/platform-browser": "21.2.18",
|
||||
"rxjs": "7.8.2",
|
||||
"tslib": "2.8.1",
|
||||
"zone.js": "0.16.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "21.2.18",
|
||||
"@angular/cli": "21.2.18",
|
||||
"@angular/compiler-cli": "21.2.18",
|
||||
"@gromlab/svg-sprites": "file:../../..",
|
||||
"typescript": "5.9.3"
|
||||
}
|
||||
}
|
||||
20
integration/apps/angular/src/app.component.ts
Normal file
20
integration/apps/angular/src/app.component.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Component } from '@angular/core'
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
template: `
|
||||
<main>
|
||||
<h1>Angular</h1>
|
||||
<svg
|
||||
data-testid="icon"
|
||||
data-app="angular"
|
||||
aria-label="Check icon"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<use href="/sprites/icons.sprite.svg#check"></use>
|
||||
</svg>
|
||||
</main>
|
||||
`,
|
||||
})
|
||||
export class AppComponent {}
|
||||
11
integration/apps/angular/src/index.html
Normal file
11
integration/apps/angular/src/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Angular sprite fixture</title>
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
5
integration/apps/angular/src/main.ts
Normal file
5
integration/apps/angular/src/main.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser'
|
||||
|
||||
import { AppComponent } from './app.component'
|
||||
|
||||
bootstrapApplication(AppComponent).catch((error: unknown) => console.error(error))
|
||||
16
integration/apps/angular/src/styles.css
Normal file
16
integration/apps/angular/src/styles.css
Normal file
@@ -0,0 +1,16 @@
|
||||
:root {
|
||||
font-family: system-ui, sans-serif;
|
||||
color: #172033;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
[data-testid='icon'] {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
color: #16a34a;
|
||||
}
|
||||
11
integration/apps/angular/svg-sprites.config.ts
Normal file
11
integration/apps/angular/svg-sprites.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export default {
|
||||
output: 'public/sprites',
|
||||
preview: false,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: '../../fixtures/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
}
|
||||
9
integration/apps/angular/tsconfig.app.json
Normal file
9
integration/apps/angular/tsconfig.app.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": ["src/main.ts"],
|
||||
"include": ["src/**/*.d.ts"]
|
||||
}
|
||||
27
integration/apps/angular/tsconfig.json
Normal file
27
integration/apps/angular/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "bundler",
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"lib": ["ES2022", "DOM"]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
20
integration/apps/astro/package.json
Normal file
20
integration/apps/astro/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@svg-sprites-fixtures/astro",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites --mode legacy .",
|
||||
"typecheck": "astro check",
|
||||
"build": "npm run sprites && astro check && astro build",
|
||||
"dev": "npm run sprites && astro dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "7.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "0.9.9",
|
||||
"@gromlab/svg-sprites": "file:../../..",
|
||||
"typescript": "6.0.2"
|
||||
}
|
||||
}
|
||||
44
integration/apps/astro/src/pages/index.astro
Normal file
44
integration/apps/astro/src/pages/index.astro
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
const title = 'Astro sprite fixture'
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Astro</h1>
|
||||
<svg
|
||||
data-testid="icon"
|
||||
data-app="astro"
|
||||
aria-label="Check icon"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<use href="/sprites/icons.sprite.svg#check"></use>
|
||||
</svg>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style is:global>
|
||||
:root {
|
||||
font-family: system-ui, sans-serif;
|
||||
color: #172033;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
[data-testid='icon'] {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
color: #16a34a;
|
||||
}
|
||||
</style>
|
||||
11
integration/apps/astro/svg-sprites.config.ts
Normal file
11
integration/apps/astro/svg-sprites.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export default {
|
||||
output: 'public/sprites',
|
||||
preview: false,
|
||||
sprites: [
|
||||
{
|
||||
name: 'icons',
|
||||
input: '../../fixtures/icons',
|
||||
format: 'symbol',
|
||||
},
|
||||
],
|
||||
}
|
||||
3
integration/apps/astro/tsconfig.json
Normal file
3
integration/apps/astro/tsconfig.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "astro/tsconfigs/strict"
|
||||
}
|
||||
11
integration/apps/next-app-turbopack/app/layout.tsx
Normal file
11
integration/apps/next-app-turbopack/app/layout.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
import './style.css'
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
20
integration/apps/next-app-turbopack/app/page.tsx
Normal file
20
integration/apps/next-app-turbopack/app/page.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { IconsIcon } from '../src/sprite'
|
||||
import { AppSpriteViewer } from './sprite-viewer'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Next.js App Router + Turbopack</h1>
|
||||
<IconsIcon
|
||||
data-testid="icon"
|
||||
data-app="next-app-turbopack"
|
||||
icon="check"
|
||||
aria-label="Check icon"
|
||||
width={64}
|
||||
height={64}
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
<AppSpriteViewer />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
11
integration/apps/next-app-turbopack/app/sprite-viewer.tsx
Normal file
11
integration/apps/next-app-turbopack/app/sprite-viewer.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const viewerSources = [
|
||||
() => import('../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export function AppSpriteViewer() {
|
||||
return <SpriteViewer sources={viewerSources} title="Next App Turbopack Viewer" style={{ marginTop: 32 }} />
|
||||
}
|
||||
10
integration/apps/next-app-turbopack/app/style.css
Normal file
10
integration/apps/next-app-turbopack/app/style.css
Normal file
@@ -0,0 +1,10 @@
|
||||
:root {
|
||||
font-family: system-ui, sans-serif;
|
||||
color: #172033;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { IconsIcon, iconsIconNames } from './src/sprite'
|
||||
import type { IconsIconName, IconsIconProps, IconsIconStyle } from './src/sprite'
|
||||
import { IconsIcon as GeneratedIconsIcon } from './src/sprite/.svg-sprite/react/react-component.js'
|
||||
import type { IconsIconName as GeneratedIconName } from './src/sprite/.svg-sprite/icon-data.js'
|
||||
import { iconsIconNames as generatedIconNames } from './src/sprite/.svg-sprite/icon-data.js'
|
||||
|
||||
const iconName: IconsIconName = iconsIconNames[0]
|
||||
const generatedIconName: GeneratedIconName = generatedIconNames[0]
|
||||
const allIconNames: readonly IconsIconName[] = iconsIconNames
|
||||
const style: IconsIconStyle = { '--icon-color-1': '#16a34a' }
|
||||
const props: IconsIconProps = { icon: iconName, style }
|
||||
|
||||
void allIconNames
|
||||
void <IconsIcon {...props} />
|
||||
void <GeneratedIconsIcon icon={generatedIconName} />
|
||||
|
||||
// @ts-expect-error Unknown icon names must be rejected by generated declarations.
|
||||
void <IconsIcon icon="missing" />
|
||||
6
integration/apps/next-app-turbopack/next-env.d.ts
vendored
Normal file
6
integration/apps/next-app-turbopack/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
10
integration/apps/next-app-turbopack/next.config.mjs
Normal file
10
integration/apps/next-app-turbopack/next.config.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
import path from 'node:path'
|
||||
|
||||
const repositoryRoot = path.resolve(import.meta.dirname, '../../..')
|
||||
|
||||
export default {
|
||||
outputFileTracingRoot: repositoryRoot,
|
||||
turbopack: {
|
||||
root: repositoryRoot,
|
||||
},
|
||||
}
|
||||
24
integration/apps/next-app-turbopack/package.json
Normal file
24
integration/apps/next-app-turbopack/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@svg-sprites-fixtures/next-app-turbopack",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "npm run sprites && next build --turbopack",
|
||||
"dev": "npm run sprites && next dev --turbopack",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "16.2.10",
|
||||
"react": "19.2.5",
|
||||
"react-dom": "19.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gromlab/svg-sprites": "file:../../..",
|
||||
"@types/node": "24.12.0",
|
||||
"@types/react": "19.2.17",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"typescript": "6.0.2"
|
||||
}
|
||||
}
|
||||
2
integration/apps/next-app-turbopack/src/sprite/.gitignore
vendored
Normal file
2
integration/apps/next-app-turbopack/src/sprite/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# @generated by @gromlab/svg-sprites. Do not edit.
|
||||
/.svg-sprite/
|
||||
1
integration/apps/next-app-turbopack/src/sprite/index.ts
Normal file
1
integration/apps/next-app-turbopack/src/sprite/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './.svg-sprite'
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/turbopack',
|
||||
name: 'icons',
|
||||
input: '../../../../fixtures/icons/check.svg',
|
||||
generatedNotice: false,
|
||||
})
|
||||
36
integration/apps/next-app-turbopack/tsconfig.json
Normal file
36
integration/apps/next-app-turbopack/tsconfig.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ES2022"
|
||||
],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"incremental": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
".next/types/**/*.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
11
integration/apps/next-app-webpack/app/layout.tsx
Normal file
11
integration/apps/next-app-webpack/app/layout.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
import './style.css'
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
20
integration/apps/next-app-webpack/app/page.tsx
Normal file
20
integration/apps/next-app-webpack/app/page.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { IconsIcon } from '../src/sprite'
|
||||
import { AppSpriteViewer } from './sprite-viewer'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Next.js App Router + Webpack</h1>
|
||||
<IconsIcon
|
||||
data-testid="icon"
|
||||
data-app="next-app-webpack"
|
||||
icon="check"
|
||||
aria-label="Check icon"
|
||||
width={64}
|
||||
height={64}
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
<AppSpriteViewer />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
11
integration/apps/next-app-webpack/app/sprite-viewer.tsx
Normal file
11
integration/apps/next-app-webpack/app/sprite-viewer.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
|
||||
const viewerSources = [
|
||||
() => import('../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export function AppSpriteViewer() {
|
||||
return <SpriteViewer sources={viewerSources} title="Next App Webpack Viewer" style={{ marginTop: 32 }} />
|
||||
}
|
||||
10
integration/apps/next-app-webpack/app/style.css
Normal file
10
integration/apps/next-app-webpack/app/style.css
Normal file
@@ -0,0 +1,10 @@
|
||||
:root {
|
||||
font-family: system-ui, sans-serif;
|
||||
color: #172033;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
}
|
||||
6
integration/apps/next-app-webpack/next-env.d.ts
vendored
Normal file
6
integration/apps/next-app-webpack/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
10
integration/apps/next-app-webpack/next.config.mjs
Normal file
10
integration/apps/next-app-webpack/next.config.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
import path from 'node:path'
|
||||
|
||||
const repositoryRoot = path.resolve(import.meta.dirname, '../../..')
|
||||
|
||||
export default {
|
||||
outputFileTracingRoot: repositoryRoot,
|
||||
turbopack: {
|
||||
root: repositoryRoot,
|
||||
},
|
||||
}
|
||||
24
integration/apps/next-app-webpack/package.json
Normal file
24
integration/apps/next-app-webpack/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@svg-sprites-fixtures/next-app-webpack",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "npm run sprites && next build --webpack",
|
||||
"dev": "npm run sprites && next dev --webpack",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "16.2.10",
|
||||
"react": "19.2.5",
|
||||
"react-dom": "19.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gromlab/svg-sprites": "file:../../..",
|
||||
"@types/node": "24.12.0",
|
||||
"@types/react": "19.2.17",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"typescript": "6.0.2"
|
||||
}
|
||||
}
|
||||
2
integration/apps/next-app-webpack/src/sprite/.gitignore
vendored
Normal file
2
integration/apps/next-app-webpack/src/sprite/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# @generated by @gromlab/svg-sprites. Do not edit.
|
||||
/.svg-sprite/
|
||||
1
integration/apps/next-app-webpack/src/sprite/index.ts
Normal file
1
integration/apps/next-app-webpack/src/sprite/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './.svg-sprite'
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@app/webpack',
|
||||
name: 'icons',
|
||||
input: '../../../../fixtures/icons/check.svg',
|
||||
generatedNotice: false,
|
||||
})
|
||||
36
integration/apps/next-app-webpack/tsconfig.json
Normal file
36
integration/apps/next-app-webpack/tsconfig.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ES2022"
|
||||
],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"incremental": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
".next/types/**/*.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
6
integration/apps/next-pages-turbopack/next-env.d.ts
vendored
Normal file
6
integration/apps/next-pages-turbopack/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
|
||||
10
integration/apps/next-pages-turbopack/next.config.mjs
Normal file
10
integration/apps/next-pages-turbopack/next.config.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
import path from 'node:path'
|
||||
|
||||
const repositoryRoot = path.resolve(import.meta.dirname, '../../..')
|
||||
|
||||
export default {
|
||||
outputFileTracingRoot: repositoryRoot,
|
||||
turbopack: {
|
||||
root: repositoryRoot,
|
||||
},
|
||||
}
|
||||
24
integration/apps/next-pages-turbopack/package.json
Normal file
24
integration/apps/next-pages-turbopack/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@svg-sprites-fixtures/next-pages-turbopack",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"sprites": "svg-sprites src/sprite/svg-sprite.config.ts",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "npm run sprites && next build --turbopack",
|
||||
"dev": "npm run sprites && next dev --turbopack",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "16.2.10",
|
||||
"react": "19.2.5",
|
||||
"react-dom": "19.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gromlab/svg-sprites": "file:../../..",
|
||||
"@types/node": "24.12.0",
|
||||
"@types/react": "19.2.17",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"typescript": "6.0.2"
|
||||
}
|
||||
}
|
||||
7
integration/apps/next-pages-turbopack/pages/_app.tsx
Normal file
7
integration/apps/next-pages-turbopack/pages/_app.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { AppProps } from 'next/app'
|
||||
|
||||
import './style.css'
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
24
integration/apps/next-pages-turbopack/pages/index.tsx
Normal file
24
integration/apps/next-pages-turbopack/pages/index.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { SpriteViewer } from '@gromlab/svg-sprites/react'
|
||||
import { IconsIcon } from '../src/sprite'
|
||||
|
||||
const viewerSources = [
|
||||
() => import('../src/sprite/.svg-sprite/svg-sprite.manifest.js'),
|
||||
] as const
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Next.js Pages Router + Turbopack</h1>
|
||||
<IconsIcon
|
||||
data-testid="icon"
|
||||
data-app="next-pages-turbopack"
|
||||
icon="check"
|
||||
aria-label="Check icon"
|
||||
width={64}
|
||||
height={64}
|
||||
style={{ '--icon-color-1': '#16a34a' }}
|
||||
/>
|
||||
<SpriteViewer sources={viewerSources} title="Next Pages Turbopack Viewer" style={{ marginTop: 32 }} />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
10
integration/apps/next-pages-turbopack/pages/style.css
Normal file
10
integration/apps/next-pages-turbopack/pages/style.css
Normal file
@@ -0,0 +1,10 @@
|
||||
:root {
|
||||
font-family: system-ui, sans-serif;
|
||||
color: #172033;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 40px;
|
||||
}
|
||||
2
integration/apps/next-pages-turbopack/src/sprite/.gitignore
vendored
Normal file
2
integration/apps/next-pages-turbopack/src/sprite/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# @generated by @gromlab/svg-sprites. Do not edit.
|
||||
/.svg-sprite/
|
||||
@@ -0,0 +1 @@
|
||||
export * from './.svg-sprite'
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineSpriteConfig } from '@gromlab/svg-sprites'
|
||||
|
||||
export default defineSpriteConfig({
|
||||
mode: 'next@pages/turbopack',
|
||||
name: 'icons',
|
||||
input: '../../../../fixtures/icons/check.svg',
|
||||
generatedNotice: false,
|
||||
})
|
||||
35
integration/apps/next-pages-turbopack/tsconfig.json
Normal file
35
integration/apps/next-pages-turbopack/tsconfig.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
"ES2022"
|
||||
],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"incremental": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
".next/types/**/*.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user