mirror of
https://github.com/gromlab-ru/svg-sprites.git
synced 2026-07-22 04:40:17 +03:00
feat: добавить локализацию документации и скиллов
- добавлены английские README и руководства с переключением языка - сборка скиллов разделена на английскую и русскую версии - локализованные документы включены в npm-пакет
This commit is contained in:
331
README.md
331
README.md
@@ -1,77 +1,80 @@
|
|||||||
# @gromlab/svg-sprites
|
# @gromlab/svg-sprites
|
||||||
|
|
||||||
|
🇬🇧 English | [🇷🇺 Русский](README_RU.md)
|
||||||
|
|
||||||
 
|
 
|
||||||
|
|
||||||
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
|
A CLI for generating SVG sprites and typed icon components for React and Next.js.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Навигация
|
## Navigation
|
||||||
|
|
||||||
- [Возможности](#возможности)
|
- [Features](#features)
|
||||||
- [Таблица поддержки](#таблица-поддержки)
|
- [Support matrix](#support-matrix)
|
||||||
- [Требования](#требования)
|
- [Requirements](#requirements)
|
||||||
- [Быстрый старт](#быстрый-старт)
|
- [Quick start](#quick-start)
|
||||||
- [React + Vite](docs/ru/react-vite.md)
|
- [React + Vite](docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](docs/ru/next-app.md)
|
- [Next.js App Router](docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||||
- [Конфигурация](#конфигурация)
|
- [Configuration](#configuration)
|
||||||
- [React](#react)
|
- [React](#react)
|
||||||
- [Next.js](#nextjs)
|
- [Next.js](#nextjs)
|
||||||
- [Множественные спрайты](#множественные-спрайты)
|
- [Multiple sprites](#multiple-sprites)
|
||||||
- [TypeScript](#typescript)
|
- [TypeScript](#typescript)
|
||||||
- [Форматы спрайтов](#форматы-спрайтов)
|
- [Sprite formats](#sprite-formats)
|
||||||
- [Способы отображения](#способы-отображения)
|
- [Rendering methods](#rendering-methods)
|
||||||
- [Трансформации](#трансформации)
|
- [Transformations](#transformations)
|
||||||
- [Управление цветом иконок](#управление-цветом-иконок)
|
- [Icon color management](#icon-color-management)
|
||||||
- [Кеширование](#кеширование)
|
- [Caching](#caching)
|
||||||
- [SpriteViewer](#spriteviewer)
|
- [SpriteViewer](#spriteviewer)
|
||||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||||
- [Документация](#документация)
|
- [Documentation](#documentation)
|
||||||
|
|
||||||
## Возможности
|
## Features
|
||||||
|
|
||||||
- **TypeScript-friendly** — типизированные React-компоненты, union-типы и runtime-списки доступных иконок.
|
- **AI-agent friendly** - the repository includes a ready-to-use skill with up-to-date documentation for configuring, migrating, and troubleshooting `@gromlab/svg-sprites`.
|
||||||
- **Чистая генерация** — generated-файлы автоматически исключаются из Git, спрайт не нужно вручную размещать в `public`, а генератор обновляет только принадлежащие ему файлы.
|
- **TypeScript-friendly** - typed React components, union types, and runtime lists of available icons.
|
||||||
- **Общие иконки без копирования** — SVG из локальной папки и `inputFiles` объединяются в один спрайт; один файл можно использовать в нескольких спрайтах.
|
- **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.
|
||||||
- **Встроенное интерактивное превью** — `<SpriteViewer>` подключается как страница приложения и показывает переданные React- и Next.js-спрайты с поиском, настройкой цветов и примерами использования.
|
- **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.
|
||||||
- **Настраиваемые трансформации SVG** — удаление `width` и `height` с сохранением `viewBox`, замена исходных цветов на CSS-переменные и transitions для `fill` и `stroke`.
|
- **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.
|
||||||
- **Отдельный кешируемый SVG asset** — SVG path-данные не попадают в JavaScript chunks, а сборщик выпускает файл с content hash.
|
- **Configurable SVG transformations** - remove `width` and `height` while preserving `viewBox`, replace source colors with CSS variables, and add transitions for `fill` and `stroke`.
|
||||||
- **Множественные спрайты** — независимые React- и Next.js-модули со своими компонентами, типами и SVG assets.
|
- **Separate cacheable SVG asset** - SVG path data does not end up in JavaScript chunks, and the bundler emits a file with a content hash.
|
||||||
- **Server-first Next.js** — generated-компоненты работают в Server Components, SSR и SSG без директивы `'use client'`.
|
- **Multiple sprites** - independent React and Next.js modules with their own components, types, and SVG assets.
|
||||||
- **Форматы под разные сценарии** — React и Next.js используют `stack`, legacy-режим также поддерживает `symbol` для существующих интеграций.
|
- **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.
|
||||||
|
|
||||||
## Таблица поддержки
|
## Support matrix
|
||||||
|
|
||||||
| Среда | Ключ мода API | Статус |
|
| Environment | API mode key | Status |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| React + Vite | `react@vite` | Готово |
|
| React + Vite | `react@vite` | Ready |
|
||||||
| React + Webpack 5 | `react@webpack` | Готово |
|
| React + Webpack 5 | `react@webpack` | Ready |
|
||||||
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Готово |
|
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Ready |
|
||||||
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Готово |
|
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Ready |
|
||||||
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Готово |
|
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Ready |
|
||||||
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Готово |
|
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Ready |
|
||||||
| Vue | — | Скоро |
|
| Vue | - | Coming soon |
|
||||||
| Standalone | — | Скоро |
|
| Standalone | - | Coming soon |
|
||||||
|
|
||||||
## Требования
|
## Requirements
|
||||||
|
|
||||||
- Node.js 18 или новее;
|
- Node.js 18 or newer;
|
||||||
- пакет распространяется только как ESM и подключается через `import`;
|
- the package is distributed as ESM only and is loaded via `import`;
|
||||||
- React 18 или 19 требуется только для generated-компонентов и точки входа `@gromlab/svg-sprites/react`;
|
- React 18 or 19 is required only for generated components and the `@gromlab/svg-sprites/react` entry point;
|
||||||
- для типизации subpath exports используйте TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
- 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/ru/react-vite.md)
|
- [React + Vite](docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](docs/ru/next-app.md)
|
- [Next.js App Router](docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||||
|
|
||||||
## Конфигурация
|
## Configuration
|
||||||
|
|
||||||
### React
|
### React
|
||||||
|
|
||||||
@@ -80,7 +83,7 @@ import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
|||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineReactSpriteConfig({
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
inputFiles: [
|
inputFiles: [
|
||||||
'../../shared/icons/check.svg',
|
'../../shared/icons/check.svg',
|
||||||
@@ -94,78 +97,78 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
| Опция | Тип | По умолчанию | Назначение |
|
| Option | Type | Default | Purpose |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `name` | `string` | Имя папки | Имя спрайта, компонента и публичных типов |
|
| `name` | `string` | Folder name | Name of the sprite, component, and public types |
|
||||||
| `description` | `string` | Нет | Описание для типов и debug-манифеста |
|
| `description` | `string` | None | Description for types and the debug manifest |
|
||||||
| `inputFolder` | `string` | `./icons` | Папка с исходными SVG относительно конфига |
|
| `inputFolder` | `string` | `./icons` | Folder containing source SVGs, relative to the config |
|
||||||
| `inputFiles` | `string[]` | `[]` | Дополнительные SVG-файлы относительно конфига |
|
| `inputFiles` | `string[]` | `[]` | Additional SVG files, relative to the config |
|
||||||
| `transform` | `TransformOptions` | Все включены | [Настройки трансформации](#трансформации) исходных SVG |
|
| `transform` | `TransformOptions` | All enabled | [Transformation settings](#transformations) for source SVGs |
|
||||||
| `generatedNotice` | `boolean` | `true` | Полное либо короткое предупреждение в generated-файлах |
|
| `generatedNotice` | `boolean` | `true` | Full or short warning in generated files |
|
||||||
|
|
||||||
`inputFolder` и `inputFiles` объединяются в один спрайт, поэтому один SVG-файл можно использовать в нескольких спрайтах без копирования. Если неявной папки `./icons` нет, но `inputFiles` заполнен, генерация продолжается только по списку. Явно указанная отсутствующая папка считается ошибкой. Одинаковые пути дедуплицируются, а разные файлы с одинаковым именем иконки считаются ошибкой.
|
`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` записывается в kebab-case и должно начинаться с латинской буквы. React и Next.js presets создают формат `stack`.
|
`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
|
||||||
|
|
||||||
Next.js использует тот же `svg-sprite.config.ts` и набор опций. Для типизации можно использовать отдельный хелпер:
|
Next.js uses the same `svg-sprite.config.ts` and set of options. For type checking, you can use a dedicated helper:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineNextSpriteConfig({
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Роутер и сборщик выбираются через mode key, поэтому переключение между Turbopack и Webpack всегда явно отражено в команде генерации.
|
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
|
```text
|
||||||
global → GlobalIcon → общие иконки приложения
|
global -> GlobalIcon -> shared application icons
|
||||||
analytics-page → AnalyticsPageIcon → иконки отдельной страницы
|
analytics-page -> AnalyticsPageIcon -> icons for a specific page
|
||||||
file-manager → FileManagerIcon → иконки крупного компонента
|
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.
|
||||||
- **Спрайт крупного компонента** инкапсулирует собственный набор иконок сложного UI-модуля, например файлового менеджера или редактора.
|
- **Large component sprite** encapsulates the icon set of a complex UI module, such as a file manager or editor.
|
||||||
|
|
||||||
Каждая группа получает:
|
Each group gets:
|
||||||
|
|
||||||
- собственный SVG asset;
|
- its own SVG asset;
|
||||||
- собственный типизированный компонент;
|
- its own typed component;
|
||||||
- отдельный список имён иконок;
|
- a separate list of icon names;
|
||||||
- отдельный debug-манифест;
|
- a separate debug manifest;
|
||||||
- независимый cache lifecycle.
|
- an independent cache lifecycle.
|
||||||
|
|
||||||
|
|
||||||
## TypeScript
|
## TypeScript
|
||||||
|
|
||||||
Главная возможность TypeScript API — автодополнение имён иконок непосредственно в prop `icon`:
|
The main feature of the TypeScript API is icon name autocomplete directly in the `icon` prop:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<FileManagerIcon icon="folder" />
|
<FileManagerIcon icon="folder" />
|
||||||
// ↑ редактор предлагает все иконки спрайта
|
// ^ the editor suggests every icon in the sprite
|
||||||
```
|
```
|
||||||
|
|
||||||
Имена SVG-файлов становятся допустимыми значениями `icon`. Опечатка или неизвестное имя сразу становятся ошибкой TypeScript:
|
SVG file names become valid `icon` values. A typo or unknown name immediately becomes a TypeScript error:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
<FileManagerIcon icon="unknown" /> // TypeScript error
|
||||||
```
|
```
|
||||||
|
|
||||||
Для программного доступа generated-модуль экспортирует readonly-массив всех доступных иконок конкретного спрайта:
|
For programmatic access, the generated module exports a readonly array of all icons available in a specific sprite:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { fileManagerIconNames } from './svg-sprite'
|
import { fileManagerIconNames } from './svg-sprite'
|
||||||
@@ -173,39 +176,39 @@ import { fileManagerIconNames } from './svg-sprite'
|
|||||||
// readonly ['check', 'folder', ...]
|
// readonly ['check', 'folder', ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
Этот список можно использовать в собственных каталогах, select-компонентах, тестах и других runtime-сценариях. Из него также выводится union-тип `FileManagerIconName`.
|
You can use this list in custom catalogs, select components, tests, and other runtime scenarios. The `FileManagerIconName` union type is also derived from it.
|
||||||
|
|
||||||
Имена файлов с пробелами и другими небезопасными для SVG ID символами остаются частью публичного TypeScript API. Для внутреннего `<symbol id>` генератор создаёт стабильный hash ID.
|
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
|
```text
|
||||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
folder open.svg -> icon="folder open" -> id="icon-<stable-hash>"
|
||||||
```
|
```
|
||||||
|
|
||||||
Для таких имён используйте generated-компонент или `id` из debug-манифеста. Ручные примеры ниже с `#<имя>` подходят только для имён, которые уже являются безопасными SVG ID.
|
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` — более современный формат, поэтому он используется по умолчанию. Иконки можно отображать через `<svg><use>`, `<img>` и CSS `background-image`.
|
`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` сохраняется для совместимости с существующими интеграциями и поддерживает отображение только через `<svg><use>`.
|
`symbol` is retained for compatibility with existing integrations and supports rendering only through `<svg><use>`.
|
||||||
|
|
||||||
## Способы отображения
|
## Rendering methods
|
||||||
|
|
||||||
### React-компонент — рекомендуется
|
### React component - recommended
|
||||||
|
|
||||||
Generated-компонент предоставляет типизацию, автодополнение имён иконок и сам формирует URL SVG asset.
|
The generated component provides type safety and icon name autocomplete, and constructs the SVG asset URL itself.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<FileManagerIcon icon="check" width={24} height={24} />
|
<FileManagerIcon icon="check" width={24} height={24} />
|
||||||
```
|
```
|
||||||
|
|
||||||
Через `color` и `--icon-color-N` доступны одноцветные и многоцветные иконки.
|
Monochrome and multicolor icons are supported through `color` and `--icon-color-N`.
|
||||||
|
|
||||||
### Самостоятельно через `<svg><use>`
|
### Manually with `<svg><use>`
|
||||||
|
|
||||||
Хороший низкоуровневый способ с полным управлением размерами и цветами. React-компонент под капотом использует именно его.
|
A good low-level method that provides full control over dimensions and colors. This is exactly what the React component uses under the hood.
|
||||||
|
|
||||||
Способ получения `spriteUrl` зависит от сборщика.
|
How you obtain `spriteUrl` depends on the bundler.
|
||||||
|
|
||||||
**Vite:**
|
**Vite:**
|
||||||
|
|
||||||
@@ -222,7 +225,7 @@ const spriteUrl = new URL(
|
|||||||
).href
|
).href
|
||||||
```
|
```
|
||||||
|
|
||||||
**Next.js с Webpack 5 или Turbopack:**
|
**Next.js with Webpack 5 or Turbopack:**
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const spriteUrl = new URL(
|
const spriteUrl = new URL(
|
||||||
@@ -231,7 +234,7 @@ const spriteUrl = new URL(
|
|||||||
).href
|
).href
|
||||||
```
|
```
|
||||||
|
|
||||||
После получения URL иконка отображается одинаково:
|
After obtaining the URL, the icon is rendered the same way:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<svg width={24} height={24}>
|
<svg width={24} height={24}>
|
||||||
@@ -239,17 +242,17 @@ const spriteUrl = new URL(
|
|||||||
</svg>
|
</svg>
|
||||||
```
|
```
|
||||||
|
|
||||||
Vite, Webpack 5 и Next.js сами заменяют исходный путь на итоговый URL asset с hash.
|
Vite, Webpack 5, and Next.js replace the source path with the final hashed asset URL automatically.
|
||||||
|
|
||||||
### Через `<img>` — менее эффективно
|
### With `<img>` - less efficient
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Готово" />
|
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Done" />
|
||||||
```
|
```
|
||||||
|
|
||||||
SVG загружается как изолированное изображение: изменить его цвета через `color` или `--icon-color-N` нельзя.
|
The SVG loads as an isolated image: its colors cannot be changed through `color` or `--icon-color-N`.
|
||||||
|
|
||||||
### Через CSS `background-image` — менее эффективно
|
### With CSS `background-image` - less efficient
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
@@ -257,9 +260,9 @@ SVG загружается как изолированное изображен
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Как и `<img>`, этот способ не позволяет управлять внутренними цветами SVG. Путь указывается относительно CSS-файла, а Vite/Webpack заменяет его на итоговый URL с hash при сборке.
|
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.
|
||||||
|
|
||||||
### Через CSS mask — менее эффективно
|
### With CSS mask - less efficient
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
@@ -268,37 +271,37 @@ SVG загружается как изолированное изображен
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Mask оставляет только силуэт и окрашивает его одним цветом. Исходные цвета, gradients и различия между `fill` и `stroke` теряются.
|
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.
|
||||||
|
|
||||||
## Трансформации
|
## Transformations
|
||||||
|
|
||||||
Все трансформации включены по умолчанию и настраиваются независимо через `transform`.
|
All transformations are enabled by default and configured independently through `transform`.
|
||||||
|
|
||||||
| Опция | По умолчанию | Что делает |
|
| Option | Default | What it does |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `removeSize` | `true` | Удаляет `width` и `height` с корневого `<svg>`, сохраняя существующий `viewBox`. Размер иконки после этого задаётся снаружи. |
|
| `removeSize` | `true` | Removes `width` and `height` from the root `<svg>` while preserving the existing `viewBox`. The icon size is then set externally. |
|
||||||
| `replaceColors` | `true` | Заменяет цвета `fill` и `stroke` на `--icon-color-N`. Для одноцветной иконки fallback становится `currentColor`, для многоцветной сохраняются исходные цвета. |
|
| `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` | Добавляет `style="transition:fill 0.3s,stroke 0.3s;"` непосредственно цветным элементам SVG. Существующий `transition` не перезаписывается. |
|
| `addTransition` | `true` | Adds `style="transition:fill 0.3s,stroke 0.3s;"` directly to colored SVG elements. An existing `transition` is not overwritten. |
|
||||||
|
|
||||||
Чтобы отключить преобразование, передайте для соответствующей опции `false`. Подробнее о результате `replaceColors` — в разделе [«Управление цветом иконок»](#управление-цветом-иконок).
|
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
|
||||||
|
|
||||||
При включённой замене цветов генератор анализирует `fill` и `stroke` и преобразует их в CSS custom properties.
|
When color replacement is enabled, the generator analyzes `fill` and `stroke` and converts them to CSS custom properties.
|
||||||
|
|
||||||
### Монохромные иконки
|
### Monochrome icons
|
||||||
|
|
||||||
Если найден один цвет, fallback заменяется на `currentColor`:
|
If one color is found, the fallback is replaced with `currentColor`:
|
||||||
|
|
||||||
```svg
|
```svg
|
||||||
stroke="var(--icon-color-1, currentColor)"
|
stroke="var(--icon-color-1, currentColor)"
|
||||||
```
|
```
|
||||||
|
|
||||||
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
|
The color is controlled by the CSS `color` property of the outer `<svg>` or its parent.
|
||||||
|
|
||||||
### Многоцветные иконки
|
### Multicolor icons
|
||||||
|
|
||||||
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
|
Each unique color gets a separate variable with the original fallback:
|
||||||
|
|
||||||
```svg
|
```svg
|
||||||
fill="var(--icon-color-1, #798198)"
|
fill="var(--icon-color-1, #798198)"
|
||||||
@@ -306,7 +309,7 @@ fill="var(--icon-color-2, #ffffff)"
|
|||||||
fill="var(--icon-color-3, #129d9d)"
|
fill="var(--icon-color-3, #129d9d)"
|
||||||
```
|
```
|
||||||
|
|
||||||
Страница может заменить только необходимые цвета:
|
The page can override only the required colors:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
@@ -315,62 +318,62 @@ fill="var(--icon-color-3, #129d9d)"
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Ограничения цветов
|
### Color limitations
|
||||||
|
|
||||||
- `none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
|
- `none`, `transparent`, `inherit`, `unset`, and `initial` are not replaced;
|
||||||
- цвета в атрибутах `fill`, `stroke` и inline `style` обрабатываются надёжнее всего;
|
- colors in `fill`, `stroke`, and inline `style` attributes are handled most reliably;
|
||||||
- CSS-классы и внешние stylesheets внутри исходного SVG не являются основным сценарием трансформации;
|
- CSS classes and external stylesheets inside the source SVG are not the primary transformation use case;
|
||||||
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
|
- gradients, patterns, filters, and `url(#...)` values require separate verification and may be incompatible with automatic color replacement;
|
||||||
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
|
- page CSS variables are available with `<svg><use>`, but are not available inside `<img>` and `background-image`.
|
||||||
|
|
||||||
## Кеширование
|
## Caching
|
||||||
|
|
||||||
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
|
The Vite, Webpack, and Next.js targets emit the sprite as a separate asset with a content hash:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/assets/sprite-<hash>.svg
|
/assets/sprite-<hash>.svg
|
||||||
```
|
```
|
||||||
|
|
||||||
Это даёт следующие свойства:
|
This provides the following properties:
|
||||||
|
|
||||||
- SVG кешируется независимо от JavaScript;
|
- the SVG is cached independently of JavaScript;
|
||||||
- изменение React-кода не меняет содержимое спрайта;
|
- changes to React code do not alter the sprite contents;
|
||||||
- изменение иконок создаёт новый hash asset;
|
- icon changes produce a new hashed asset;
|
||||||
- один файл используется всеми экземплярами generated-компонента;
|
- one file is used by every instance of the generated component;
|
||||||
- SVG path-данные отсутствуют в JavaScript chunks.
|
- SVG path data is absent from JavaScript chunks.
|
||||||
|
|
||||||
Vite target запрещает inline через `?no-inline`. Webpack 5 target использует Asset Modules через `new URL(..., import.meta.url)`.
|
The Vite target prevents inlining through `?no-inline`. The Webpack 5 target uses Asset Modules through `new URL(..., import.meta.url)`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
|
`SpriteViewer` is a React component for viewing generated sprites inside an application's debug route.
|
||||||
|
|
||||||
Он использует отдельные манифесты и показывает:
|
It uses separate manifests and displays:
|
||||||
|
|
||||||
- группы спрайтов;
|
- sprite groups;
|
||||||
- список и количество иконок;
|
- the icon list and count;
|
||||||
- поиск и системную светлую/тёмную тему;
|
- search and the system light/dark theme;
|
||||||
- модальное превью с `viewBox` и настройкой цветовых переменных;
|
- a preview modal with the `viewBox` and color variable controls;
|
||||||
- примеры React, SVG, IMG и CSS с копированием кода.
|
- React, SVG, IMG, and CSS examples with code copying.
|
||||||
|
|
||||||
Production-компоненты не импортируют debug-манифесты. Способ подключения Viewer зависит от сборщика:
|
Production components do not import debug manifests. How you integrate the Viewer depends on the bundler:
|
||||||
|
|
||||||
- [React + Vite: автоматический `import.meta.glob`](docs/ru/react-vite.md#6-добавьте-debug-страницу);
|
- [React + Vite: automatic `import.meta.glob`](docs/en/react-vite.md#6-add-a-debug-page);
|
||||||
- [React + Webpack 5: статические `import()`](docs/ru/react-webpack.md#6-добавьте-debug-страницу);
|
- [React + Webpack 5: static `import()`](docs/en/react-webpack.md#6-add-a-debug-page);
|
||||||
- [Next.js App Router](docs/ru/next-app.md#5-добавьте-spriteviewer);
|
- [Next.js App Router](docs/en/next-app.md#5-add-spriteviewer);
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md#5-добавьте-spriteviewer).
|
- [Next.js Pages Router](docs/en/next-pages.md#5-add-spriteviewer).
|
||||||
|
|
||||||
Viewer подключается из отдельной клиентской точки входа `@gromlab/svg-sprites/react` и не попадает в production-компоненты иконок.
|
The Viewer is imported from the separate `@gromlab/svg-sprites/react` client entry point and is not included in production icon components.
|
||||||
|
|
||||||
### Тема Viewer
|
### Viewer theme
|
||||||
|
|
||||||
По умолчанию `colorTheme="auto"`: Viewer следует `prefers-color-scheme` и реагирует на смену системной темы. Тему приложения можно передать явно:
|
By default, `colorTheme="auto"`: the Viewer follows `prefers-color-scheme` and responds to system theme changes. The application theme can be passed explicitly:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||||
```
|
```
|
||||||
|
|
||||||
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
|
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:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<SpriteViewer
|
<SpriteViewer
|
||||||
@@ -380,16 +383,16 @@ Viewer подключается из отдельной клиентской т
|
|||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Документация
|
## Documentation
|
||||||
|
|
||||||
- [React + Vite](docs/ru/react-vite.md)
|
- [React + Vite](docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](docs/ru/next-app.md)
|
- [Next.js App Router](docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||||
- [Legacy mode](docs/ru/legacy.md)
|
- [Legacy mode](docs/en/legacy.md)
|
||||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||||
- [Программный API](docs/ru/programmatic-api.md)
|
- [Programmatic API](docs/en/programmatic-api.md)
|
||||||
|
|
||||||
## Лицензия
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
398
README_RU.md
Normal file
398
README_RU.md
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
# @gromlab/svg-sprites
|
||||||
|
|
||||||
|
[🇬🇧 English](README.md) | 🇷🇺 Русский
|
||||||
|
|
||||||
|
 
|
||||||
|
|
||||||
|
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Навигация
|
||||||
|
|
||||||
|
- [Возможности](#возможности)
|
||||||
|
- [Таблица поддержки](#таблица-поддержки)
|
||||||
|
- [Требования](#требования)
|
||||||
|
- [Быстрый старт](#быстрый-старт)
|
||||||
|
- [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)
|
||||||
|
- [Документация](#документация)
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- **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` для существующих интеграций.
|
||||||
|
|
||||||
|
## Таблица поддержки
|
||||||
|
|
||||||
|
| Среда | Ключ мода 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 | — | Скоро |
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
```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,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
| Опция | Тип | По умолчанию | Назначение |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `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 при сборке.
|
||||||
|
|
||||||
|
### Через CSS mask — менее эффективно
|
||||||
|
|
||||||
|
```css
|
||||||
|
.icon {
|
||||||
|
background-color: currentColor;
|
||||||
|
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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)"
|
||||||
|
```
|
||||||
|
|
||||||
|
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
|
||||||
|
|
||||||
|
### Многоцветные иконки
|
||||||
|
|
||||||
|
Каждый уникальный цвет получает отдельную переменную с исходным 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 не являются основным сценарием трансформации;
|
||||||
|
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
|
||||||
|
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
|
||||||
|
|
||||||
|
## Кеширование
|
||||||
|
|
||||||
|
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/assets/sprite-<hash>.svg
|
||||||
|
```
|
||||||
|
|
||||||
|
Это даёт следующие свойства:
|
||||||
|
|
||||||
|
- 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)`.
|
||||||
|
|
||||||
|
## SpriteViewer
|
||||||
|
|
||||||
|
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
|
||||||
|
|
||||||
|
Он использует отдельные манифесты и показывает:
|
||||||
|
|
||||||
|
- группы спрайтов;
|
||||||
|
- список и количество иконок;
|
||||||
|
- поиск и системную светлую/тёмную тему;
|
||||||
|
- модальное превью с `viewBox` и настройкой цветовых переменных;
|
||||||
|
- примеры React, SVG, IMG и CSS с копированием кода.
|
||||||
|
|
||||||
|
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" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<SpriteViewer
|
||||||
|
sources={sources}
|
||||||
|
colorTheme={appTheme}
|
||||||
|
onColorThemeChange={setAppTheme}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Документация
|
||||||
|
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT
|
||||||
102
docs/en/legacy.md
Normal file
102
docs/en/legacy.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# 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).
|
||||||
96
docs/en/migration-1.md
Normal file
96
docs/en/migration-1.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# 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`.
|
||||||
102
docs/en/next-app.md
Normal file
102
docs/en/next-app.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Next.js App Router
|
||||||
|
|
||||||
|
[← 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.
|
||||||
96
docs/en/next-pages.md
Normal file
96
docs/en/next-pages.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# Next.js Pages Router
|
||||||
|
|
||||||
|
[← 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.
|
||||||
203
docs/en/programmatic-api.md
Normal file
203
docs/en/programmatic-api.md
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# Programmatic API
|
||||||
|
|
||||||
|
[← 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)
|
||||||
116
docs/en/react-vite.md
Normal file
116
docs/en/react-vite.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# React + Vite
|
||||||
|
|
||||||
|
[← 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`.
|
||||||
118
docs/en/react-webpack.md
Normal file
118
docs/en/react-webpack.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# React + Webpack 5
|
||||||
|
|
||||||
|
[← 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.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Legacy mode
|
# Legacy mode
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Краткая инструкция по генерации централизованных SVG-спрайтов форматов `symbol` и `stack` с optional HTML preview.
|
Краткая инструкция по генерации централизованных SVG-спрайтов форматов `symbol` и `stack` с optional HTML preview.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Миграция с 0.1.x на 1.0
|
# Миграция с 0.1.x на 1.0
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
|
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Next.js App Router
|
# Next.js App Router
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Поддерживаются два явных режима:
|
Поддерживаются два явных режима:
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Next.js Pages Router
|
# Next.js Pages Router
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Поддерживаются два явных режима:
|
Поддерживаются два явных режима:
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Программный API
|
# Программный API
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Пакет предоставляет основную Node.js точку входа и отдельный React runtime entry. Обе точки распространяются только как ESM и подключаются через `import`.
|
Пакет предоставляет основную Node.js точку входа и отдельный React runtime entry. Обе точки распространяются только как ESM и подключаются через `import`.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# React + Vite
|
# React + Vite
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Vite.
|
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Vite.
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
|||||||
|
|
||||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||||
|
|
||||||
Полный список опций находится в разделе [Конфигурация → React](../../README.md#react).
|
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||||
|
|
||||||
## 4. Добавьте генерацию в package.json
|
## 4. Добавьте генерацию в package.json
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ export const OpenFolderButton = () => (
|
|||||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
||||||
```
|
```
|
||||||
|
|
||||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README.md#способы-отображения).
|
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||||
|
|
||||||
Vite выпустит спрайт отдельным файлом вида `assets/sprite-<hash>.svg`. SVG path-данные не попадут в JavaScript.
|
Vite выпустит спрайт отдельным файлом вида `assets/sprite-<hash>.svg`. SVG path-данные не попадут в JavaScript.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# React + Webpack 5
|
# React + Webpack 5
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Webpack 5.
|
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Webpack 5.
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
|||||||
|
|
||||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||||
|
|
||||||
Полный список опций находится в разделе [Конфигурация → React](../../README.md#react).
|
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||||
|
|
||||||
## 4. Добавьте генерацию в package.json
|
## 4. Добавьте генерацию в package.json
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ export const OpenFolderButton = () => (
|
|||||||
<FileManagerIcon icon="missing" /> // ошибка TypeScript
|
<FileManagerIcon icon="missing" /> // ошибка TypeScript
|
||||||
```
|
```
|
||||||
|
|
||||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README.md#способы-отображения).
|
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||||
|
|
||||||
Webpack обработает generated `new URL('./sprite.svg', import.meta.url)` через Asset Modules и выпустит отдельный SVG asset.
|
Webpack обработает generated `new URL('./sprite.svg', import.meta.url)` через Asset Modules и выпустит отдельный SVG asset.
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
"dist/chunk-*.js",
|
"dist/chunk-*.js",
|
||||||
"dist/chunk-*.js.map",
|
"dist/chunk-*.js.map",
|
||||||
"dist/preview-template.html",
|
"dist/preview-template.html",
|
||||||
|
"README_RU.md",
|
||||||
|
"docs/en/*.md",
|
||||||
"docs/ru/*.md",
|
"docs/ru/*.md",
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"THIRD_PARTY_NOTICES.md"
|
"THIRD_PARTY_NOTICES.md"
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# AI skills
|
# AI skills
|
||||||
|
|
||||||
Исходники скила `svg-sprites` находятся в `skills/svg-sprites/`. Готовый самодостаточный артефакт записывается в `skills/artifacts/svg-sprites/` и коммитится в Git.
|
Исходники скилов `svg-sprites` и `svg-sprites-ru` находятся в `skills/svg-sprites/`. Готовые самодостаточные артефакты записываются в `skills/artifacts/svg-sprites/` и `skills/artifacts/svg-sprites-ru/` и коммитятся в Git.
|
||||||
|
|
||||||
Основные `README.md` и `docs/ru/*.md` являются источником истины. Сборка копирует их в `references/` готового скила, поэтому вручную редактировать файлы внутри `skills/artifacts/` нельзя.
|
Основные `README.md`, `README_RU.md` и файлы `docs/{en,ru}/*.md` являются источником истины. Сборка копирует их в `references/` готового скила, поэтому вручную редактировать файлы внутри `skills/artifacts/` нельзя.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build:skill
|
npm run build:skill
|
||||||
npm run check:skill
|
npm run check:skill
|
||||||
```
|
```
|
||||||
|
|
||||||
`build:skill` обновляет артефакт, а `check:skill` без изменения файлов проверяет его содержимое и синхронность с документацией.
|
`build:skill` обновляет оба артефакта, а `check:skill` без изменения файлов проверяет их содержимое и синхронность с документацией. Версия без суффикса использует английский язык, версия с суффиксом `-ru` — русский.
|
||||||
|
|||||||
64
skills/artifacts/svg-sprites-ru/SKILL.md
Normal file
64
skills/artifacts/svg-sprites-ru/SKILL.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
name: svg-sprites-ru
|
||||||
|
description: "Используй при настройке, генерации, миграции или диагностике SVG-спрайтов через @gromlab/svg-sprites. Триггеры: SVG sprite, SVG-спрайт, svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer, icon=\"...\", --icon-color-N, generated-компонент или иконка не появилась в превью и автодополнении. НЕ используй для favicon, растровых изображений, icon fonts, выбора набора иконок или inline SVG без спрайтов."
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Generated from skills/svg-sprites/src/SKILL_RU.md. Do not edit manually. -->
|
||||||
|
|
||||||
|
# SVG Sprites
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Используй этот скил для работы с `@gromlab/svg-sprites`: первичной настройки, добавления и переиспользования иконок, генерации React-компонентов, подключения `SpriteViewer`, миграции legacy-конфигурации и диагностики ошибок.
|
||||||
|
|
||||||
|
Не навязывай проекту конкретную архитектуру каталогов. Сначала изучи существующие `package.json`, конфигурацию спрайта, используемый фреймворк, роутер и сборщик.
|
||||||
|
|
||||||
|
## Рабочий алгоритм
|
||||||
|
|
||||||
|
1. Определи существующий режим и не смешивай его API с другим режимом.
|
||||||
|
2. Для React выбери `react@vite` или `react@webpack` и открой соответствующий reference.
|
||||||
|
3. Для Next.js определи App Router или Pages Router, затем Turbopack или Webpack, и открой соответствующий reference.
|
||||||
|
4. Для существующего `svg-sprites.config.ts` с несколькими спрайтами используй legacy-документацию. Не мигрируй такой проект без явного запроса.
|
||||||
|
5. Изучи локальные scripts и добавляй генерацию перед `dev`, `build` и `typecheck`, если generated-файлы не хранятся в Git.
|
||||||
|
6. После изменения конфигурации или SVG запусти генерацию, затем доступную проверку типов или сборку проекта.
|
||||||
|
|
||||||
|
## Правила React и Next.js
|
||||||
|
|
||||||
|
- Используй локальный `svg-sprite.config.ts` и подходящий config helper: `defineReactSpriteConfig` или `defineNextSpriteConfig`.
|
||||||
|
- Не редактируй `generated/`, `index.ts`, `manifest.ts` и созданный генератором `.gitignore` вручную.
|
||||||
|
- Имена исходных SVG становятся допустимыми значениями prop `icon`; используй generated-компонент и его публичные типы вместо deep imports.
|
||||||
|
- Объединяй локальную папку и `inputFiles`, когда общая иконка нужна нескольким спрайтам. Не создавай копии одного SVG без необходимости.
|
||||||
|
- В Next.js generated-компонент можно использовать в Server Components, SSR и SSG. Не добавляй `'use client'` только ради иконки.
|
||||||
|
- Спрайт должен оставаться внешним asset сборщика: не переносить SVG path-данные в JavaScript и не класть generated-файл вручную в `public`.
|
||||||
|
|
||||||
|
## Цвета и трансформации
|
||||||
|
|
||||||
|
- По умолчанию генератор удаляет `width` и `height`, заменяет поддерживаемые `fill` и `stroke` на CSS-переменные и добавляет transitions.
|
||||||
|
- Для монохромной иконки сначала управляй `color`; для многоцветной используй `--icon-color-N`.
|
||||||
|
- Не обещай автоматическую замену цветов внутри внешних stylesheets, gradients, patterns, filters и значений `url(#...)` без проверки результата.
|
||||||
|
- CSS-переменные страницы работают при `<svg><use>`, но не проникают внутрь `<img>` и `background-image`.
|
||||||
|
|
||||||
|
## Превью
|
||||||
|
|
||||||
|
Для React и Next.js подключай `<SpriteViewer>` отдельной debug-страницей приложения. Передай ему manifests или lazy loaders спрайтов. Viewer поддерживает поиск, светлую и тёмную темы, настройку цветов и примеры React, SVG, IMG и CSS.
|
||||||
|
|
||||||
|
`SpriteViewer` является клиентским debug-инструментом и импортируется из `@gromlab/svg-sprites/react`; production-компоненты иконок от него не зависят.
|
||||||
|
|
||||||
|
## Диагностика
|
||||||
|
|
||||||
|
- Если имя иконки отсутствует в автодополнении, проверь входную папку и `inputFiles`, затем перезапусти генерацию.
|
||||||
|
- Если два файла имеют одинаковое имя иконки, устрани конфликт вместо выбора одного файла неявно.
|
||||||
|
- Если генератор отказывается перезаписывать файл, не удаляй защитный marker и не обходи writer: перенеси пользовательский файл или выбери другой каталог спрайта.
|
||||||
|
- Если asset не загружается, сначала проверь соответствие CLI mode реальному сборщику проекта и обработку generated SVG его asset pipeline.
|
||||||
|
- Если проект использует старый API, сверь установленную версию пакета и legacy reference перед изменениями.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Основная документация и API](./references/README_RU.md)
|
||||||
|
- [React + Vite](./references/docs/ru/react-vite.md)
|
||||||
|
- [React + Webpack 5](./references/docs/ru/react-webpack.md)
|
||||||
|
- [Next.js App Router](./references/docs/ru/next-app.md)
|
||||||
|
- [Next.js Pages Router](./references/docs/ru/next-pages.md)
|
||||||
|
- [Legacy mode](./references/docs/ru/legacy.md)
|
||||||
|
- [Миграция с 0.1.x](./references/docs/ru/migration-1.md)
|
||||||
|
- [Программный API](./references/docs/ru/programmatic-api.md)
|
||||||
398
skills/artifacts/svg-sprites-ru/references/README.md
Normal file
398
skills/artifacts/svg-sprites-ru/references/README.md
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
# @gromlab/svg-sprites
|
||||||
|
|
||||||
|
🇬🇧 English | [🇷🇺 Русский](README_RU.md)
|
||||||
|
|
||||||
|
 
|
||||||
|
|
||||||
|
A CLI for generating SVG sprites and typed icon components for React and Next.js.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Navigation
|
||||||
|
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **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.
|
||||||
|
|
||||||
|
## Support matrix
|
||||||
|
|
||||||
|
| 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 |
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
```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,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
| 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.
|
||||||
|
|
||||||
|
### With CSS mask - less efficient
|
||||||
|
|
||||||
|
```css
|
||||||
|
.icon {
|
||||||
|
background-color: currentColor;
|
||||||
|
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## 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)"
|
||||||
|
```
|
||||||
|
|
||||||
|
The color is controlled by the CSS `color` property of the outer `<svg>` or its parent.
|
||||||
|
|
||||||
|
### Multicolor icons
|
||||||
|
|
||||||
|
Each unique color gets a separate variable with the original fallback:
|
||||||
|
|
||||||
|
```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;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Color 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 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`.
|
||||||
|
|
||||||
|
## Caching
|
||||||
|
|
||||||
|
The Vite, Webpack, and Next.js targets emit the sprite as a separate asset with a content hash:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/assets/sprite-<hash>.svg
|
||||||
|
```
|
||||||
|
|
||||||
|
This provides the following properties:
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
The Vite target prevents inlining through `?no-inline`. The Webpack 5 target uses Asset Modules through `new URL(..., import.meta.url)`.
|
||||||
|
|
||||||
|
## SpriteViewer
|
||||||
|
|
||||||
|
`SpriteViewer` is a React component for viewing generated sprites inside an application's debug route.
|
||||||
|
|
||||||
|
It uses separate manifests and displays:
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
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" />
|
||||||
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<SpriteViewer
|
||||||
|
sources={sources}
|
||||||
|
colorTheme={appTheme}
|
||||||
|
onColorThemeChange={setAppTheme}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
398
skills/artifacts/svg-sprites-ru/references/README_RU.md
Normal file
398
skills/artifacts/svg-sprites-ru/references/README_RU.md
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
# @gromlab/svg-sprites
|
||||||
|
|
||||||
|
[🇬🇧 English](README.md) | 🇷🇺 Русский
|
||||||
|
|
||||||
|
 
|
||||||
|
|
||||||
|
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Навигация
|
||||||
|
|
||||||
|
- [Возможности](#возможности)
|
||||||
|
- [Таблица поддержки](#таблица-поддержки)
|
||||||
|
- [Требования](#требования)
|
||||||
|
- [Быстрый старт](#быстрый-старт)
|
||||||
|
- [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)
|
||||||
|
- [Документация](#документация)
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- **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` для существующих интеграций.
|
||||||
|
|
||||||
|
## Таблица поддержки
|
||||||
|
|
||||||
|
| Среда | Ключ мода 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 | — | Скоро |
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
```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,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
| Опция | Тип | По умолчанию | Назначение |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `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 при сборке.
|
||||||
|
|
||||||
|
### Через CSS mask — менее эффективно
|
||||||
|
|
||||||
|
```css
|
||||||
|
.icon {
|
||||||
|
background-color: currentColor;
|
||||||
|
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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)"
|
||||||
|
```
|
||||||
|
|
||||||
|
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
|
||||||
|
|
||||||
|
### Многоцветные иконки
|
||||||
|
|
||||||
|
Каждый уникальный цвет получает отдельную переменную с исходным 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 не являются основным сценарием трансформации;
|
||||||
|
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
|
||||||
|
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
|
||||||
|
|
||||||
|
## Кеширование
|
||||||
|
|
||||||
|
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/assets/sprite-<hash>.svg
|
||||||
|
```
|
||||||
|
|
||||||
|
Это даёт следующие свойства:
|
||||||
|
|
||||||
|
- 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)`.
|
||||||
|
|
||||||
|
## SpriteViewer
|
||||||
|
|
||||||
|
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
|
||||||
|
|
||||||
|
Он использует отдельные манифесты и показывает:
|
||||||
|
|
||||||
|
- группы спрайтов;
|
||||||
|
- список и количество иконок;
|
||||||
|
- поиск и системную светлую/тёмную тему;
|
||||||
|
- модальное превью с `viewBox` и настройкой цветовых переменных;
|
||||||
|
- примеры React, SVG, IMG и CSS с копированием кода.
|
||||||
|
|
||||||
|
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" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<SpriteViewer
|
||||||
|
sources={sources}
|
||||||
|
colorTheme={appTheme}
|
||||||
|
onColorThemeChange={setAppTheme}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Документация
|
||||||
|
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT
|
||||||
102
skills/artifacts/svg-sprites-ru/references/docs/en/legacy.md
Normal file
102
skills/artifacts/svg-sprites-ru/references/docs/en/legacy.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# 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).
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# 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`.
|
||||||
102
skills/artifacts/svg-sprites-ru/references/docs/en/next-app.md
Normal file
102
skills/artifacts/svg-sprites-ru/references/docs/en/next-app.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Next.js App Router
|
||||||
|
|
||||||
|
[← 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.
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# Next.js Pages Router
|
||||||
|
|
||||||
|
[← 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.
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
# Programmatic API
|
||||||
|
|
||||||
|
[← 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)
|
||||||
116
skills/artifacts/svg-sprites-ru/references/docs/en/react-vite.md
Normal file
116
skills/artifacts/svg-sprites-ru/references/docs/en/react-vite.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# React + Vite
|
||||||
|
|
||||||
|
[← 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`.
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# React + Webpack 5
|
||||||
|
|
||||||
|
[← 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.
|
||||||
102
skills/artifacts/svg-sprites-ru/references/docs/ru/legacy.md
Normal file
102
skills/artifacts/svg-sprites-ru/references/docs/ru/legacy.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# 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).
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# Миграция с 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`.
|
||||||
102
skills/artifacts/svg-sprites-ru/references/docs/ru/next-app.md
Normal file
102
skills/artifacts/svg-sprites-ru/references/docs/ru/next-app.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# 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 генератора должны указывать один и тот же сборщик.
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# 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 генератора должны указывать один и тот же сборщик.
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
# Программный 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)
|
||||||
116
skills/artifacts/svg-sprites-ru/references/docs/ru/react-vite.md
Normal file
116
skills/artifacts/svg-sprites-ru/references/docs/ru/react-vite.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# 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`.
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# React + Webpack 5
|
||||||
|
|
||||||
|
[← Главная](../../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).
|
||||||
@@ -1,64 +1,64 @@
|
|||||||
---
|
---
|
||||||
name: svg-sprites
|
name: svg-sprites
|
||||||
description: "Используй при настройке, генерации, миграции или диагностике SVG-спрайтов через @gromlab/svg-sprites. Триггеры: SVG sprite, SVG-спрайт, svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer, icon=\"...\", --icon-color-N, generated-компонент или иконка не появилась в превью и автодополнении. НЕ используй для favicon, растровых изображений, icon fonts, выбора набора иконок или inline SVG без спрайтов."
|
description: "Use when configuring, generating, migrating, or troubleshooting SVG sprites with @gromlab/svg-sprites. Triggers: SVG sprite, svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer, icon=\"...\", --icon-color-N, generated component, or an icon missing from preview or autocomplete. Do NOT use for favicons, raster images, icon fonts, choosing an icon set, or inline SVG without sprites."
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Generated from skills/svg-sprites/src/SKILL.md. Do not edit manually. -->
|
<!-- Generated from skills/svg-sprites/src/SKILL.md. Do not edit manually. -->
|
||||||
|
|
||||||
# SVG Sprites
|
# SVG Sprites
|
||||||
|
|
||||||
## Назначение
|
## Purpose
|
||||||
|
|
||||||
Используй этот скил для работы с `@gromlab/svg-sprites`: первичной настройки, добавления и переиспользования иконок, генерации React-компонентов, подключения `SpriteViewer`, миграции legacy-конфигурации и диагностики ошибок.
|
Use this skill when working with `@gromlab/svg-sprites`: initial setup, adding and reusing icons, generating React components, integrating `SpriteViewer`, migrating legacy configurations, and troubleshooting errors.
|
||||||
|
|
||||||
Не навязывай проекту конкретную архитектуру каталогов. Сначала изучи существующие `package.json`, конфигурацию спрайта, используемый фреймворк, роутер и сборщик.
|
Do not impose a specific directory architecture on the project. First inspect the existing `package.json`, sprite configuration, framework, router, and bundler.
|
||||||
|
|
||||||
## Рабочий алгоритм
|
## Workflow
|
||||||
|
|
||||||
1. Определи существующий режим и не смешивай его API с другим режимом.
|
1. Identify the existing mode and do not mix its API with another mode.
|
||||||
2. Для React выбери `react@vite` или `react@webpack` и открой соответствующий reference.
|
2. For React, choose `react@vite` or `react@webpack` and open the corresponding reference.
|
||||||
3. Для Next.js определи App Router или Pages Router, затем Turbopack или Webpack, и открой соответствующий reference.
|
3. For Next.js, identify the App Router or Pages Router, then Turbopack or Webpack, and open the corresponding reference.
|
||||||
4. Для существующего `svg-sprites.config.ts` с несколькими спрайтами используй legacy-документацию. Не мигрируй такой проект без явного запроса.
|
4. For an existing `svg-sprites.config.ts` with multiple sprites, use the legacy documentation. Do not migrate such a project unless explicitly requested.
|
||||||
5. Изучи локальные scripts и добавляй генерацию перед `dev`, `build` и `typecheck`, если generated-файлы не хранятся в Git.
|
5. Inspect local scripts and run generation before `dev`, `build`, and `typecheck` when generated files are not committed to Git.
|
||||||
6. После изменения конфигурации или SVG запусти генерацию, затем доступную проверку типов или сборку проекта.
|
6. After changing a configuration or SVG file, run generation followed by the available type check or project build.
|
||||||
|
|
||||||
## Правила React и Next.js
|
## React And Next.js Rules
|
||||||
|
|
||||||
- Используй локальный `svg-sprite.config.ts` и подходящий config helper: `defineReactSpriteConfig` или `defineNextSpriteConfig`.
|
- Use a local `svg-sprite.config.ts` and the appropriate config helper: `defineReactSpriteConfig` or `defineNextSpriteConfig`.
|
||||||
- Не редактируй `generated/`, `index.ts`, `manifest.ts` и созданный генератором `.gitignore` вручную.
|
- Do not manually edit `generated/`, `index.ts`, `manifest.ts`, or the generator-created `.gitignore`.
|
||||||
- Имена исходных SVG становятся допустимыми значениями prop `icon`; используй generated-компонент и его публичные типы вместо deep imports.
|
- Source SVG names become valid values for the `icon` prop; use the generated component and its public types instead of deep imports.
|
||||||
- Объединяй локальную папку и `inputFiles`, когда общая иконка нужна нескольким спрайтам. Не создавай копии одного SVG без необходимости.
|
- Combine the local folder with `inputFiles` when multiple sprites need a shared icon. Do not create unnecessary copies of the same SVG.
|
||||||
- В Next.js generated-компонент можно использовать в Server Components, SSR и SSG. Не добавляй `'use client'` только ради иконки.
|
- In Next.js, generated components work in Server Components, SSR, and SSG. Do not add `'use client'` only for an icon.
|
||||||
- Спрайт должен оставаться внешним asset сборщика: не переносить SVG path-данные в JavaScript и не класть generated-файл вручную в `public`.
|
- Keep the sprite as an external bundler asset: do not move SVG path data into JavaScript or manually place the generated file in `public`.
|
||||||
|
|
||||||
## Цвета и трансформации
|
## Colors And Transformations
|
||||||
|
|
||||||
- По умолчанию генератор удаляет `width` и `height`, заменяет поддерживаемые `fill` и `stroke` на CSS-переменные и добавляет transitions.
|
- By default, the generator removes `width` and `height`, replaces supported `fill` and `stroke` values with CSS variables, and adds transitions.
|
||||||
- Для монохромной иконки сначала управляй `color`; для многоцветной используй `--icon-color-N`.
|
- For a monochrome icon, control `color` first; for a multicolor icon, use `--icon-color-N`.
|
||||||
- Не обещай автоматическую замену цветов внутри внешних stylesheets, gradients, patterns, filters и значений `url(#...)` без проверки результата.
|
- Do not promise automatic color replacement inside external stylesheets, gradients, patterns, filters, or `url(#...)` values without checking the result.
|
||||||
- CSS-переменные страницы работают при `<svg><use>`, но не проникают внутрь `<img>` и `background-image`.
|
- Page CSS variables work with `<svg><use>`, but do not propagate into `<img>` or `background-image`.
|
||||||
|
|
||||||
## Превью
|
## Preview
|
||||||
|
|
||||||
Для React и Next.js подключай `<SpriteViewer>` отдельной debug-страницей приложения. Передай ему manifests или lazy loaders спрайтов. Viewer поддерживает поиск, светлую и тёмную темы, настройку цветов и примеры React, SVG, IMG и CSS.
|
For React and Next.js, add `<SpriteViewer>` as a separate debug page in the application. Pass sprite manifests or lazy loaders to it. The Viewer supports search, light and dark themes, color controls, and React, SVG, IMG, and CSS examples.
|
||||||
|
|
||||||
`SpriteViewer` является клиентским debug-инструментом и импортируется из `@gromlab/svg-sprites/react`; production-компоненты иконок от него не зависят.
|
`SpriteViewer` is a client-side debug tool imported from `@gromlab/svg-sprites/react`; production icon components do not depend on it.
|
||||||
|
|
||||||
## Диагностика
|
## Troubleshooting
|
||||||
|
|
||||||
- Если имя иконки отсутствует в автодополнении, проверь входную папку и `inputFiles`, затем перезапусти генерацию.
|
- If an icon name is missing from autocomplete, check the input folder and `inputFiles`, then rerun generation.
|
||||||
- Если два файла имеют одинаковое имя иконки, устрани конфликт вместо выбора одного файла неявно.
|
- If two files have the same icon name, resolve the conflict instead of implicitly selecting one file.
|
||||||
- Если генератор отказывается перезаписывать файл, не удаляй защитный marker и не обходи writer: перенеси пользовательский файл или выбери другой каталог спрайта.
|
- If the generator refuses to overwrite a file, do not remove the protection marker or bypass the writer: move the user file or choose another sprite directory.
|
||||||
- Если asset не загружается, сначала проверь соответствие CLI mode реальному сборщику проекта и обработку generated SVG его asset pipeline.
|
- If an asset fails to load, first confirm that the CLI mode matches the project's actual bundler and that its asset pipeline handles the generated SVG.
|
||||||
- Если проект использует старый API, сверь установленную версию пакета и legacy reference перед изменениями.
|
- If the project uses the old API, check the installed package version and the legacy reference before making changes.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- [Основная документация и API](./references/README.md)
|
- [Main documentation and API](./references/README.md)
|
||||||
- [React + Vite](./references/docs/ru/react-vite.md)
|
- [React + Vite](./references/docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](./references/docs/ru/react-webpack.md)
|
- [React + Webpack 5](./references/docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](./references/docs/ru/next-app.md)
|
- [Next.js App Router](./references/docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](./references/docs/ru/next-pages.md)
|
- [Next.js Pages Router](./references/docs/en/next-pages.md)
|
||||||
- [Legacy mode](./references/docs/ru/legacy.md)
|
- [Legacy mode](./references/docs/en/legacy.md)
|
||||||
- [Миграция с 0.1.x](./references/docs/ru/migration-1.md)
|
- [Migrating from 0.1.x](./references/docs/en/migration-1.md)
|
||||||
- [Программный API](./references/docs/ru/programmatic-api.md)
|
- [Programmatic API](./references/docs/en/programmatic-api.md)
|
||||||
|
|||||||
@@ -1,77 +1,80 @@
|
|||||||
# @gromlab/svg-sprites
|
# @gromlab/svg-sprites
|
||||||
|
|
||||||
|
🇬🇧 English | [🇷🇺 Русский](README_RU.md)
|
||||||
|
|
||||||
 
|
 
|
||||||
|
|
||||||
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
|
A CLI for generating SVG sprites and typed icon components for React and Next.js.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Навигация
|
## Navigation
|
||||||
|
|
||||||
- [Возможности](#возможности)
|
- [Features](#features)
|
||||||
- [Таблица поддержки](#таблица-поддержки)
|
- [Support matrix](#support-matrix)
|
||||||
- [Требования](#требования)
|
- [Requirements](#requirements)
|
||||||
- [Быстрый старт](#быстрый-старт)
|
- [Quick start](#quick-start)
|
||||||
- [React + Vite](docs/ru/react-vite.md)
|
- [React + Vite](docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](docs/ru/next-app.md)
|
- [Next.js App Router](docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||||
- [Конфигурация](#конфигурация)
|
- [Configuration](#configuration)
|
||||||
- [React](#react)
|
- [React](#react)
|
||||||
- [Next.js](#nextjs)
|
- [Next.js](#nextjs)
|
||||||
- [Множественные спрайты](#множественные-спрайты)
|
- [Multiple sprites](#multiple-sprites)
|
||||||
- [TypeScript](#typescript)
|
- [TypeScript](#typescript)
|
||||||
- [Форматы спрайтов](#форматы-спрайтов)
|
- [Sprite formats](#sprite-formats)
|
||||||
- [Способы отображения](#способы-отображения)
|
- [Rendering methods](#rendering-methods)
|
||||||
- [Трансформации](#трансформации)
|
- [Transformations](#transformations)
|
||||||
- [Управление цветом иконок](#управление-цветом-иконок)
|
- [Icon color management](#icon-color-management)
|
||||||
- [Кеширование](#кеширование)
|
- [Caching](#caching)
|
||||||
- [SpriteViewer](#spriteviewer)
|
- [SpriteViewer](#spriteviewer)
|
||||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||||
- [Документация](#документация)
|
- [Documentation](#documentation)
|
||||||
|
|
||||||
## Возможности
|
## Features
|
||||||
|
|
||||||
- **TypeScript-friendly** — типизированные React-компоненты, union-типы и runtime-списки доступных иконок.
|
- **AI-agent friendly** - the repository includes a ready-to-use skill with up-to-date documentation for configuring, migrating, and troubleshooting `@gromlab/svg-sprites`.
|
||||||
- **Чистая генерация** — generated-файлы автоматически исключаются из Git, спрайт не нужно вручную размещать в `public`, а генератор обновляет только принадлежащие ему файлы.
|
- **TypeScript-friendly** - typed React components, union types, and runtime lists of available icons.
|
||||||
- **Общие иконки без копирования** — SVG из локальной папки и `inputFiles` объединяются в один спрайт; один файл можно использовать в нескольких спрайтах.
|
- **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.
|
||||||
- **Встроенное интерактивное превью** — `<SpriteViewer>` подключается как страница приложения и показывает переданные React- и Next.js-спрайты с поиском, настройкой цветов и примерами использования.
|
- **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.
|
||||||
- **Настраиваемые трансформации SVG** — удаление `width` и `height` с сохранением `viewBox`, замена исходных цветов на CSS-переменные и transitions для `fill` и `stroke`.
|
- **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.
|
||||||
- **Отдельный кешируемый SVG asset** — SVG path-данные не попадают в JavaScript chunks, а сборщик выпускает файл с content hash.
|
- **Configurable SVG transformations** - remove `width` and `height` while preserving `viewBox`, replace source colors with CSS variables, and add transitions for `fill` and `stroke`.
|
||||||
- **Множественные спрайты** — независимые React- и Next.js-модули со своими компонентами, типами и SVG assets.
|
- **Separate cacheable SVG asset** - SVG path data does not end up in JavaScript chunks, and the bundler emits a file with a content hash.
|
||||||
- **Server-first Next.js** — generated-компоненты работают в Server Components, SSR и SSG без директивы `'use client'`.
|
- **Multiple sprites** - independent React and Next.js modules with their own components, types, and SVG assets.
|
||||||
- **Форматы под разные сценарии** — React и Next.js используют `stack`, legacy-режим также поддерживает `symbol` для существующих интеграций.
|
- **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.
|
||||||
|
|
||||||
## Таблица поддержки
|
## Support matrix
|
||||||
|
|
||||||
| Среда | Ключ мода API | Статус |
|
| Environment | API mode key | Status |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| React + Vite | `react@vite` | Готово |
|
| React + Vite | `react@vite` | Ready |
|
||||||
| React + Webpack 5 | `react@webpack` | Готово |
|
| React + Webpack 5 | `react@webpack` | Ready |
|
||||||
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Готово |
|
| Next.js 16.2+ App Router + Turbopack | `next@app/turbopack` | Ready |
|
||||||
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Готово |
|
| Next.js 13.4+ App Router + Webpack 5 | `next@app/webpack` | Ready |
|
||||||
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Готово |
|
| Next.js 16.2+ Pages Router + Turbopack | `next@pages/turbopack` | Ready |
|
||||||
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Готово |
|
| Next.js 12.2+ Pages Router + Webpack 5 | `next@pages/webpack` | Ready |
|
||||||
| Vue | — | Скоро |
|
| Vue | - | Coming soon |
|
||||||
| Standalone | — | Скоро |
|
| Standalone | - | Coming soon |
|
||||||
|
|
||||||
## Требования
|
## Requirements
|
||||||
|
|
||||||
- Node.js 18 или новее;
|
- Node.js 18 or newer;
|
||||||
- пакет распространяется только как ESM и подключается через `import`;
|
- the package is distributed as ESM only and is loaded via `import`;
|
||||||
- React 18 или 19 требуется только для generated-компонентов и точки входа `@gromlab/svg-sprites/react`;
|
- React 18 or 19 is required only for generated components and the `@gromlab/svg-sprites/react` entry point;
|
||||||
- для типизации subpath exports используйте TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` или `"nodenext"`.
|
- 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/ru/react-vite.md)
|
- [React + Vite](docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](docs/ru/next-app.md)
|
- [Next.js App Router](docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||||
|
|
||||||
## Конфигурация
|
## Configuration
|
||||||
|
|
||||||
### React
|
### React
|
||||||
|
|
||||||
@@ -80,7 +83,7 @@ import { defineReactSpriteConfig } from '@gromlab/svg-sprites'
|
|||||||
|
|
||||||
export default defineReactSpriteConfig({
|
export default defineReactSpriteConfig({
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
inputFiles: [
|
inputFiles: [
|
||||||
'../../shared/icons/check.svg',
|
'../../shared/icons/check.svg',
|
||||||
@@ -94,78 +97,78 @@ export default defineReactSpriteConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
| Опция | Тип | По умолчанию | Назначение |
|
| Option | Type | Default | Purpose |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `name` | `string` | Имя папки | Имя спрайта, компонента и публичных типов |
|
| `name` | `string` | Folder name | Name of the sprite, component, and public types |
|
||||||
| `description` | `string` | Нет | Описание для типов и debug-манифеста |
|
| `description` | `string` | None | Description for types and the debug manifest |
|
||||||
| `inputFolder` | `string` | `./icons` | Папка с исходными SVG относительно конфига |
|
| `inputFolder` | `string` | `./icons` | Folder containing source SVGs, relative to the config |
|
||||||
| `inputFiles` | `string[]` | `[]` | Дополнительные SVG-файлы относительно конфига |
|
| `inputFiles` | `string[]` | `[]` | Additional SVG files, relative to the config |
|
||||||
| `transform` | `TransformOptions` | Все включены | [Настройки трансформации](#трансформации) исходных SVG |
|
| `transform` | `TransformOptions` | All enabled | [Transformation settings](#transformations) for source SVGs |
|
||||||
| `generatedNotice` | `boolean` | `true` | Полное либо короткое предупреждение в generated-файлах |
|
| `generatedNotice` | `boolean` | `true` | Full or short warning in generated files |
|
||||||
|
|
||||||
`inputFolder` и `inputFiles` объединяются в один спрайт, поэтому один SVG-файл можно использовать в нескольких спрайтах без копирования. Если неявной папки `./icons` нет, но `inputFiles` заполнен, генерация продолжается только по списку. Явно указанная отсутствующая папка считается ошибкой. Одинаковые пути дедуплицируются, а разные файлы с одинаковым именем иконки считаются ошибкой.
|
`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` записывается в kebab-case и должно начинаться с латинской буквы. React и Next.js presets создают формат `stack`.
|
`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
|
||||||
|
|
||||||
Next.js использует тот же `svg-sprite.config.ts` и набор опций. Для типизации можно использовать отдельный хелпер:
|
Next.js uses the same `svg-sprite.config.ts` and set of options. For type checking, you can use a dedicated helper:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
import { defineNextSpriteConfig } from '@gromlab/svg-sprites'
|
||||||
|
|
||||||
export default defineNextSpriteConfig({
|
export default defineNextSpriteConfig({
|
||||||
name: 'file-manager',
|
name: 'file-manager',
|
||||||
description: 'Иконки файлового менеджера',
|
description: 'File manager icons',
|
||||||
inputFolder: './icons',
|
inputFolder: './icons',
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Роутер и сборщик выбираются через mode key, поэтому переключение между Turbopack и Webpack всегда явно отражено в команде генерации.
|
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
|
```text
|
||||||
global → GlobalIcon → общие иконки приложения
|
global -> GlobalIcon -> shared application icons
|
||||||
analytics-page → AnalyticsPageIcon → иконки отдельной страницы
|
analytics-page -> AnalyticsPageIcon -> icons for a specific page
|
||||||
file-manager → FileManagerIcon → иконки крупного компонента
|
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.
|
||||||
- **Спрайт крупного компонента** инкапсулирует собственный набор иконок сложного UI-модуля, например файлового менеджера или редактора.
|
- **Large component sprite** encapsulates the icon set of a complex UI module, such as a file manager or editor.
|
||||||
|
|
||||||
Каждая группа получает:
|
Each group gets:
|
||||||
|
|
||||||
- собственный SVG asset;
|
- its own SVG asset;
|
||||||
- собственный типизированный компонент;
|
- its own typed component;
|
||||||
- отдельный список имён иконок;
|
- a separate list of icon names;
|
||||||
- отдельный debug-манифест;
|
- a separate debug manifest;
|
||||||
- независимый cache lifecycle.
|
- an independent cache lifecycle.
|
||||||
|
|
||||||
|
|
||||||
## TypeScript
|
## TypeScript
|
||||||
|
|
||||||
Главная возможность TypeScript API — автодополнение имён иконок непосредственно в prop `icon`:
|
The main feature of the TypeScript API is icon name autocomplete directly in the `icon` prop:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<FileManagerIcon icon="folder" />
|
<FileManagerIcon icon="folder" />
|
||||||
// ↑ редактор предлагает все иконки спрайта
|
// ^ the editor suggests every icon in the sprite
|
||||||
```
|
```
|
||||||
|
|
||||||
Имена SVG-файлов становятся допустимыми значениями `icon`. Опечатка или неизвестное имя сразу становятся ошибкой TypeScript:
|
SVG file names become valid `icon` values. A typo or unknown name immediately becomes a TypeScript error:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
<FileManagerIcon icon="unknown" /> // TypeScript error
|
||||||
```
|
```
|
||||||
|
|
||||||
Для программного доступа generated-модуль экспортирует readonly-массив всех доступных иконок конкретного спрайта:
|
For programmatic access, the generated module exports a readonly array of all icons available in a specific sprite:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { fileManagerIconNames } from './svg-sprite'
|
import { fileManagerIconNames } from './svg-sprite'
|
||||||
@@ -173,39 +176,39 @@ import { fileManagerIconNames } from './svg-sprite'
|
|||||||
// readonly ['check', 'folder', ...]
|
// readonly ['check', 'folder', ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
Этот список можно использовать в собственных каталогах, select-компонентах, тестах и других runtime-сценариях. Из него также выводится union-тип `FileManagerIconName`.
|
You can use this list in custom catalogs, select components, tests, and other runtime scenarios. The `FileManagerIconName` union type is also derived from it.
|
||||||
|
|
||||||
Имена файлов с пробелами и другими небезопасными для SVG ID символами остаются частью публичного TypeScript API. Для внутреннего `<symbol id>` генератор создаёт стабильный hash ID.
|
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
|
```text
|
||||||
folder open.svg → icon="folder open" → id="icon-<stable-hash>"
|
folder open.svg -> icon="folder open" -> id="icon-<stable-hash>"
|
||||||
```
|
```
|
||||||
|
|
||||||
Для таких имён используйте generated-компонент или `id` из debug-манифеста. Ручные примеры ниже с `#<имя>` подходят только для имён, которые уже являются безопасными SVG ID.
|
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` — более современный формат, поэтому он используется по умолчанию. Иконки можно отображать через `<svg><use>`, `<img>` и CSS `background-image`.
|
`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` сохраняется для совместимости с существующими интеграциями и поддерживает отображение только через `<svg><use>`.
|
`symbol` is retained for compatibility with existing integrations and supports rendering only through `<svg><use>`.
|
||||||
|
|
||||||
## Способы отображения
|
## Rendering methods
|
||||||
|
|
||||||
### React-компонент — рекомендуется
|
### React component - recommended
|
||||||
|
|
||||||
Generated-компонент предоставляет типизацию, автодополнение имён иконок и сам формирует URL SVG asset.
|
The generated component provides type safety and icon name autocomplete, and constructs the SVG asset URL itself.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<FileManagerIcon icon="check" width={24} height={24} />
|
<FileManagerIcon icon="check" width={24} height={24} />
|
||||||
```
|
```
|
||||||
|
|
||||||
Через `color` и `--icon-color-N` доступны одноцветные и многоцветные иконки.
|
Monochrome and multicolor icons are supported through `color` and `--icon-color-N`.
|
||||||
|
|
||||||
### Самостоятельно через `<svg><use>`
|
### Manually with `<svg><use>`
|
||||||
|
|
||||||
Хороший низкоуровневый способ с полным управлением размерами и цветами. React-компонент под капотом использует именно его.
|
A good low-level method that provides full control over dimensions and colors. This is exactly what the React component uses under the hood.
|
||||||
|
|
||||||
Способ получения `spriteUrl` зависит от сборщика.
|
How you obtain `spriteUrl` depends on the bundler.
|
||||||
|
|
||||||
**Vite:**
|
**Vite:**
|
||||||
|
|
||||||
@@ -222,7 +225,7 @@ const spriteUrl = new URL(
|
|||||||
).href
|
).href
|
||||||
```
|
```
|
||||||
|
|
||||||
**Next.js с Webpack 5 или Turbopack:**
|
**Next.js with Webpack 5 or Turbopack:**
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const spriteUrl = new URL(
|
const spriteUrl = new URL(
|
||||||
@@ -231,7 +234,7 @@ const spriteUrl = new URL(
|
|||||||
).href
|
).href
|
||||||
```
|
```
|
||||||
|
|
||||||
После получения URL иконка отображается одинаково:
|
After obtaining the URL, the icon is rendered the same way:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<svg width={24} height={24}>
|
<svg width={24} height={24}>
|
||||||
@@ -239,17 +242,17 @@ const spriteUrl = new URL(
|
|||||||
</svg>
|
</svg>
|
||||||
```
|
```
|
||||||
|
|
||||||
Vite, Webpack 5 и Next.js сами заменяют исходный путь на итоговый URL asset с hash.
|
Vite, Webpack 5, and Next.js replace the source path with the final hashed asset URL automatically.
|
||||||
|
|
||||||
### Через `<img>` — менее эффективно
|
### With `<img>` - less efficient
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Готово" />
|
<img src={`${spriteUrl}#check`} width={24} height={24} alt="Done" />
|
||||||
```
|
```
|
||||||
|
|
||||||
SVG загружается как изолированное изображение: изменить его цвета через `color` или `--icon-color-N` нельзя.
|
The SVG loads as an isolated image: its colors cannot be changed through `color` or `--icon-color-N`.
|
||||||
|
|
||||||
### Через CSS `background-image` — менее эффективно
|
### With CSS `background-image` - less efficient
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
@@ -257,9 +260,9 @@ SVG загружается как изолированное изображен
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Как и `<img>`, этот способ не позволяет управлять внутренними цветами SVG. Путь указывается относительно CSS-файла, а Vite/Webpack заменяет его на итоговый URL с hash при сборке.
|
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.
|
||||||
|
|
||||||
### Через CSS mask — менее эффективно
|
### With CSS mask - less efficient
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
@@ -268,37 +271,37 @@ SVG загружается как изолированное изображен
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Mask оставляет только силуэт и окрашивает его одним цветом. Исходные цвета, gradients и различия между `fill` и `stroke` теряются.
|
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.
|
||||||
|
|
||||||
## Трансформации
|
## Transformations
|
||||||
|
|
||||||
Все трансформации включены по умолчанию и настраиваются независимо через `transform`.
|
All transformations are enabled by default and configured independently through `transform`.
|
||||||
|
|
||||||
| Опция | По умолчанию | Что делает |
|
| Option | Default | What it does |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `removeSize` | `true` | Удаляет `width` и `height` с корневого `<svg>`, сохраняя существующий `viewBox`. Размер иконки после этого задаётся снаружи. |
|
| `removeSize` | `true` | Removes `width` and `height` from the root `<svg>` while preserving the existing `viewBox`. The icon size is then set externally. |
|
||||||
| `replaceColors` | `true` | Заменяет цвета `fill` и `stroke` на `--icon-color-N`. Для одноцветной иконки fallback становится `currentColor`, для многоцветной сохраняются исходные цвета. |
|
| `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` | Добавляет `style="transition:fill 0.3s,stroke 0.3s;"` непосредственно цветным элементам SVG. Существующий `transition` не перезаписывается. |
|
| `addTransition` | `true` | Adds `style="transition:fill 0.3s,stroke 0.3s;"` directly to colored SVG elements. An existing `transition` is not overwritten. |
|
||||||
|
|
||||||
Чтобы отключить преобразование, передайте для соответствующей опции `false`. Подробнее о результате `replaceColors` — в разделе [«Управление цветом иконок»](#управление-цветом-иконок).
|
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
|
||||||
|
|
||||||
При включённой замене цветов генератор анализирует `fill` и `stroke` и преобразует их в CSS custom properties.
|
When color replacement is enabled, the generator analyzes `fill` and `stroke` and converts them to CSS custom properties.
|
||||||
|
|
||||||
### Монохромные иконки
|
### Monochrome icons
|
||||||
|
|
||||||
Если найден один цвет, fallback заменяется на `currentColor`:
|
If one color is found, the fallback is replaced with `currentColor`:
|
||||||
|
|
||||||
```svg
|
```svg
|
||||||
stroke="var(--icon-color-1, currentColor)"
|
stroke="var(--icon-color-1, currentColor)"
|
||||||
```
|
```
|
||||||
|
|
||||||
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
|
The color is controlled by the CSS `color` property of the outer `<svg>` or its parent.
|
||||||
|
|
||||||
### Многоцветные иконки
|
### Multicolor icons
|
||||||
|
|
||||||
Каждый уникальный цвет получает отдельную переменную с исходным fallback:
|
Each unique color gets a separate variable with the original fallback:
|
||||||
|
|
||||||
```svg
|
```svg
|
||||||
fill="var(--icon-color-1, #798198)"
|
fill="var(--icon-color-1, #798198)"
|
||||||
@@ -306,7 +309,7 @@ fill="var(--icon-color-2, #ffffff)"
|
|||||||
fill="var(--icon-color-3, #129d9d)"
|
fill="var(--icon-color-3, #129d9d)"
|
||||||
```
|
```
|
||||||
|
|
||||||
Страница может заменить только необходимые цвета:
|
The page can override only the required colors:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.icon {
|
.icon {
|
||||||
@@ -315,62 +318,62 @@ fill="var(--icon-color-3, #129d9d)"
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Ограничения цветов
|
### Color limitations
|
||||||
|
|
||||||
- `none`, `transparent`, `inherit`, `unset` и `initial` не заменяются;
|
- `none`, `transparent`, `inherit`, `unset`, and `initial` are not replaced;
|
||||||
- цвета в атрибутах `fill`, `stroke` и inline `style` обрабатываются надёжнее всего;
|
- colors in `fill`, `stroke`, and inline `style` attributes are handled most reliably;
|
||||||
- CSS-классы и внешние stylesheets внутри исходного SVG не являются основным сценарием трансформации;
|
- CSS classes and external stylesheets inside the source SVG are not the primary transformation use case;
|
||||||
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
|
- gradients, patterns, filters, and `url(#...)` values require separate verification and may be incompatible with automatic color replacement;
|
||||||
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
|
- page CSS variables are available with `<svg><use>`, but are not available inside `<img>` and `background-image`.
|
||||||
|
|
||||||
## Кеширование
|
## Caching
|
||||||
|
|
||||||
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
|
The Vite, Webpack, and Next.js targets emit the sprite as a separate asset with a content hash:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/assets/sprite-<hash>.svg
|
/assets/sprite-<hash>.svg
|
||||||
```
|
```
|
||||||
|
|
||||||
Это даёт следующие свойства:
|
This provides the following properties:
|
||||||
|
|
||||||
- SVG кешируется независимо от JavaScript;
|
- the SVG is cached independently of JavaScript;
|
||||||
- изменение React-кода не меняет содержимое спрайта;
|
- changes to React code do not alter the sprite contents;
|
||||||
- изменение иконок создаёт новый hash asset;
|
- icon changes produce a new hashed asset;
|
||||||
- один файл используется всеми экземплярами generated-компонента;
|
- one file is used by every instance of the generated component;
|
||||||
- SVG path-данные отсутствуют в JavaScript chunks.
|
- SVG path data is absent from JavaScript chunks.
|
||||||
|
|
||||||
Vite target запрещает inline через `?no-inline`. Webpack 5 target использует Asset Modules через `new URL(..., import.meta.url)`.
|
The Vite target prevents inlining through `?no-inline`. The Webpack 5 target uses Asset Modules through `new URL(..., import.meta.url)`.
|
||||||
|
|
||||||
## SpriteViewer
|
## SpriteViewer
|
||||||
|
|
||||||
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
|
`SpriteViewer` is a React component for viewing generated sprites inside an application's debug route.
|
||||||
|
|
||||||
Он использует отдельные манифесты и показывает:
|
It uses separate manifests and displays:
|
||||||
|
|
||||||
- группы спрайтов;
|
- sprite groups;
|
||||||
- список и количество иконок;
|
- the icon list and count;
|
||||||
- поиск и системную светлую/тёмную тему;
|
- search and the system light/dark theme;
|
||||||
- модальное превью с `viewBox` и настройкой цветовых переменных;
|
- a preview modal with the `viewBox` and color variable controls;
|
||||||
- примеры React, SVG, IMG и CSS с копированием кода.
|
- React, SVG, IMG, and CSS examples with code copying.
|
||||||
|
|
||||||
Production-компоненты не импортируют debug-манифесты. Способ подключения Viewer зависит от сборщика:
|
Production components do not import debug manifests. How you integrate the Viewer depends on the bundler:
|
||||||
|
|
||||||
- [React + Vite: автоматический `import.meta.glob`](docs/ru/react-vite.md#6-добавьте-debug-страницу);
|
- [React + Vite: automatic `import.meta.glob`](docs/en/react-vite.md#6-add-a-debug-page);
|
||||||
- [React + Webpack 5: статические `import()`](docs/ru/react-webpack.md#6-добавьте-debug-страницу);
|
- [React + Webpack 5: static `import()`](docs/en/react-webpack.md#6-add-a-debug-page);
|
||||||
- [Next.js App Router](docs/ru/next-app.md#5-добавьте-spriteviewer);
|
- [Next.js App Router](docs/en/next-app.md#5-add-spriteviewer);
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md#5-добавьте-spriteviewer).
|
- [Next.js Pages Router](docs/en/next-pages.md#5-add-spriteviewer).
|
||||||
|
|
||||||
Viewer подключается из отдельной клиентской точки входа `@gromlab/svg-sprites/react` и не попадает в production-компоненты иконок.
|
The Viewer is imported from the separate `@gromlab/svg-sprites/react` client entry point and is not included in production icon components.
|
||||||
|
|
||||||
### Тема Viewer
|
### Viewer theme
|
||||||
|
|
||||||
По умолчанию `colorTheme="auto"`: Viewer следует `prefers-color-scheme` и реагирует на смену системной темы. Тему приложения можно передать явно:
|
By default, `colorTheme="auto"`: the Viewer follows `prefers-color-scheme` and responds to system theme changes. The application theme can be passed explicitly:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<SpriteViewer sources={sources} colorTheme="dark" />
|
<SpriteViewer sources={sources} colorTheme="dark" />
|
||||||
```
|
```
|
||||||
|
|
||||||
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
|
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:
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<SpriteViewer
|
<SpriteViewer
|
||||||
@@ -380,16 +383,16 @@ Viewer подключается из отдельной клиентской т
|
|||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Документация
|
## Documentation
|
||||||
|
|
||||||
- [React + Vite](docs/ru/react-vite.md)
|
- [React + Vite](docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](docs/ru/react-webpack.md)
|
- [React + Webpack 5](docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](docs/ru/next-app.md)
|
- [Next.js App Router](docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](docs/ru/next-pages.md)
|
- [Next.js Pages Router](docs/en/next-pages.md)
|
||||||
- [Legacy mode](docs/ru/legacy.md)
|
- [Legacy mode](docs/en/legacy.md)
|
||||||
- [Миграция с 0.1.x](docs/ru/migration-1.md)
|
- [Migrating from 0.1.x](docs/en/migration-1.md)
|
||||||
- [Программный API](docs/ru/programmatic-api.md)
|
- [Programmatic API](docs/en/programmatic-api.md)
|
||||||
|
|
||||||
## Лицензия
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
398
skills/artifacts/svg-sprites/references/README_RU.md
Normal file
398
skills/artifacts/svg-sprites/references/README_RU.md
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
# @gromlab/svg-sprites
|
||||||
|
|
||||||
|
[🇬🇧 English](README.md) | 🇷🇺 Русский
|
||||||
|
|
||||||
|
 
|
||||||
|
|
||||||
|
CLI для генерации SVG-спрайтов и типизированных компонентов иконок для React и Next.js.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Навигация
|
||||||
|
|
||||||
|
- [Возможности](#возможности)
|
||||||
|
- [Таблица поддержки](#таблица-поддержки)
|
||||||
|
- [Требования](#требования)
|
||||||
|
- [Быстрый старт](#быстрый-старт)
|
||||||
|
- [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)
|
||||||
|
- [Документация](#документация)
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
- **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` для существующих интеграций.
|
||||||
|
|
||||||
|
## Таблица поддержки
|
||||||
|
|
||||||
|
| Среда | Ключ мода 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 | — | Скоро |
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
```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,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
| Опция | Тип | По умолчанию | Назначение |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `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 при сборке.
|
||||||
|
|
||||||
|
### Через CSS mask — менее эффективно
|
||||||
|
|
||||||
|
```css
|
||||||
|
.icon {
|
||||||
|
background-color: currentColor;
|
||||||
|
mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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)"
|
||||||
|
```
|
||||||
|
|
||||||
|
Цветом управляет CSS-свойство `color` внешнего `<svg>` или его родителя.
|
||||||
|
|
||||||
|
### Многоцветные иконки
|
||||||
|
|
||||||
|
Каждый уникальный цвет получает отдельную переменную с исходным 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 не являются основным сценарием трансформации;
|
||||||
|
- gradients, patterns, filters и значения `url(#...)` требуют отдельной проверки и могут быть несовместимы с автоматической заменой цветов;
|
||||||
|
- CSS-переменные страницы доступны при `<svg><use>`, но недоступны внутри `<img>` и `background-image`.
|
||||||
|
|
||||||
|
## Кеширование
|
||||||
|
|
||||||
|
Vite, Webpack и Next.js target выпускают спрайт отдельным asset с content hash:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/assets/sprite-<hash>.svg
|
||||||
|
```
|
||||||
|
|
||||||
|
Это даёт следующие свойства:
|
||||||
|
|
||||||
|
- 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)`.
|
||||||
|
|
||||||
|
## SpriteViewer
|
||||||
|
|
||||||
|
`SpriteViewer` — React-компонент для просмотра generated-спрайтов внутри debug-маршрута приложения.
|
||||||
|
|
||||||
|
Он использует отдельные манифесты и показывает:
|
||||||
|
|
||||||
|
- группы спрайтов;
|
||||||
|
- список и количество иконок;
|
||||||
|
- поиск и системную светлую/тёмную тему;
|
||||||
|
- модальное превью с `viewBox` и настройкой цветовых переменных;
|
||||||
|
- примеры React, SVG, IMG и CSS с копированием кода.
|
||||||
|
|
||||||
|
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" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Допустимые значения `colorTheme`: `auto`, `light`, `dark`. При управлении темой извне встроенный переключатель скрывается. Чтобы оставить его и обновлять тему приложения через Viewer, передайте callback:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<SpriteViewer
|
||||||
|
sources={sources}
|
||||||
|
colorTheme={appTheme}
|
||||||
|
onColorThemeChange={setAppTheme}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Документация
|
||||||
|
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT
|
||||||
102
skills/artifacts/svg-sprites/references/docs/en/legacy.md
Normal file
102
skills/artifacts/svg-sprites/references/docs/en/legacy.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# 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).
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# 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`.
|
||||||
102
skills/artifacts/svg-sprites/references/docs/en/next-app.md
Normal file
102
skills/artifacts/svg-sprites/references/docs/en/next-app.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Next.js App Router
|
||||||
|
|
||||||
|
[← 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.
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# Next.js Pages Router
|
||||||
|
|
||||||
|
[← 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.
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
# Programmatic API
|
||||||
|
|
||||||
|
[← 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)
|
||||||
116
skills/artifacts/svg-sprites/references/docs/en/react-vite.md
Normal file
116
skills/artifacts/svg-sprites/references/docs/en/react-vite.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# React + Vite
|
||||||
|
|
||||||
|
[← 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`.
|
||||||
118
skills/artifacts/svg-sprites/references/docs/en/react-webpack.md
Normal file
118
skills/artifacts/svg-sprites/references/docs/en/react-webpack.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# React + Webpack 5
|
||||||
|
|
||||||
|
[← 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.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Legacy mode
|
# Legacy mode
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Краткая инструкция по генерации централизованных SVG-спрайтов форматов `symbol` и `stack` с optional HTML preview.
|
Краткая инструкция по генерации централизованных SVG-спрайтов форматов `symbol` и `stack` с optional HTML preview.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Миграция с 0.1.x на 1.0
|
# Миграция с 0.1.x на 1.0
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
|
Версия 1.0 разделяет локальную генерацию для React и Next.js и централизованный legacy-режим. Старый config нельзя смешивать с новым API в одном вызове CLI.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Next.js App Router
|
# Next.js App Router
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Поддерживаются два явных режима:
|
Поддерживаются два явных режима:
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Next.js Pages Router
|
# Next.js Pages Router
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Поддерживаются два явных режима:
|
Поддерживаются два явных режима:
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Программный API
|
# Программный API
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Пакет предоставляет основную Node.js точку входа и отдельный React runtime entry. Обе точки распространяются только как ESM и подключаются через `import`.
|
Пакет предоставляет основную Node.js точку входа и отдельный React runtime entry. Обе точки распространяются только как ESM и подключаются через `import`.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# React + Vite
|
# React + Vite
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Vite.
|
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Vite.
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
|||||||
|
|
||||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||||
|
|
||||||
Полный список опций находится в разделе [Конфигурация → React](../../README.md#react).
|
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||||
|
|
||||||
## 4. Добавьте генерацию в package.json
|
## 4. Добавьте генерацию в package.json
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ export const OpenFolderButton = () => (
|
|||||||
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
<FileManagerIcon icon="unknown" /> // ошибка TypeScript
|
||||||
```
|
```
|
||||||
|
|
||||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README.md#способы-отображения).
|
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||||
|
|
||||||
Vite выпустит спрайт отдельным файлом вида `assets/sprite-<hash>.svg`. SVG path-данные не попадут в JavaScript.
|
Vite выпустит спрайт отдельным файлом вида `assets/sprite-<hash>.svg`. SVG path-данные не попадут в JavaScript.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# React + Webpack 5
|
# React + Webpack 5
|
||||||
|
|
||||||
[← Главная](../../README.md)
|
[← Главная](../../README_RU.md)
|
||||||
|
|
||||||
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Webpack 5.
|
Краткая инструкция по установке и использованию SVG-спрайтов в проекте на React и Webpack 5.
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ export default defineReactSpriteConfig({
|
|||||||
|
|
||||||
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
По умолчанию SVG берутся из `./icons`. Общие иконки из других папок можно добавить через `inputFiles`: папка и список объединяются в один спрайт.
|
||||||
|
|
||||||
Полный список опций находится в разделе [Конфигурация → React](../../README.md#react).
|
Полный список опций находится в разделе [Конфигурация → React](../../README_RU.md#react).
|
||||||
|
|
||||||
## 4. Добавьте генерацию в package.json
|
## 4. Добавьте генерацию в package.json
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ export const OpenFolderButton = () => (
|
|||||||
<FileManagerIcon icon="missing" /> // ошибка TypeScript
|
<FileManagerIcon icon="missing" /> // ошибка TypeScript
|
||||||
```
|
```
|
||||||
|
|
||||||
Типы, способы отображения и управление цветами описаны в [основной документации](../../README.md#способы-отображения).
|
Типы, способы отображения и управление цветами описаны в [основной документации](../../README_RU.md#способы-отображения).
|
||||||
|
|
||||||
Webpack обработает generated `new URL('./sprite.svg', import.meta.url)` через Asset Modules и выпустит отдельный SVG asset.
|
Webpack обработает generated `new URL('./sprite.svg', import.meta.url)` через Asset Modules и выпустит отдельный SVG asset.
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ import { tmpdir } from 'node:os'
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
import config from './skill.config.mjs'
|
import configs from './skill.config.mjs'
|
||||||
|
|
||||||
const skillDir = path.dirname(fileURLToPath(import.meta.url))
|
const skillDir = path.dirname(fileURLToPath(import.meta.url))
|
||||||
const outputDir = path.resolve(skillDir, config.output)
|
|
||||||
const artifactsDir = path.resolve(skillDir, '../artifacts')
|
const artifactsDir = path.resolve(skillDir, '../artifacts')
|
||||||
const isCheck = process.argv.slice(2).includes('--check')
|
const isCheck = process.argv.slice(2).includes('--check')
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ function assertInside(parentDir, childPath) {
|
|||||||
throw new Error(`Path is outside ${parentDir}: ${childPath}`)
|
throw new Error(`Path is outside ${parentDir}: ${childPath}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateConfig() {
|
function validateConfig(config, outputDir) {
|
||||||
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(config.name)) {
|
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(config.name)) {
|
||||||
throw new Error(`Invalid skill name: ${config.name}`)
|
throw new Error(`Invalid skill name: ${config.name}`)
|
||||||
}
|
}
|
||||||
@@ -68,7 +67,7 @@ function readRegularFile(filePath) {
|
|||||||
return readFileSync(filePath, 'utf8')
|
return readFileSync(filePath, 'utf8')
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSkill() {
|
function renderSkill(config) {
|
||||||
const sourcePath = path.resolve(skillDir, config.source)
|
const sourcePath = path.resolve(skillDir, config.source)
|
||||||
assertInside(skillDir, sourcePath)
|
assertInside(skillDir, sourcePath)
|
||||||
const body = readRegularFile(sourcePath).trim()
|
const body = readRegularFile(sourcePath).trim()
|
||||||
@@ -80,17 +79,17 @@ function renderSkill() {
|
|||||||
`description: ${JSON.stringify(config.description)}`,
|
`description: ${JSON.stringify(config.description)}`,
|
||||||
'---',
|
'---',
|
||||||
'',
|
'',
|
||||||
'<!-- Generated from skills/svg-sprites/src/SKILL.md. Do not edit manually. -->',
|
`<!-- Generated from skills/svg-sprites/${config.source}. Do not edit manually. -->`,
|
||||||
'',
|
'',
|
||||||
body,
|
body,
|
||||||
'',
|
'',
|
||||||
].join('\n')
|
].join('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSkill(targetDir) {
|
function buildSkill(config, targetDir) {
|
||||||
rmSync(targetDir, { recursive: true, force: true })
|
rmSync(targetDir, { recursive: true, force: true })
|
||||||
mkdirSync(targetDir, { recursive: true })
|
mkdirSync(targetDir, { recursive: true })
|
||||||
writeFileSync(path.join(targetDir, 'SKILL.md'), renderSkill())
|
writeFileSync(path.join(targetDir, 'SKILL.md'), renderSkill(config))
|
||||||
|
|
||||||
for (const reference of config.references) {
|
for (const reference of config.references) {
|
||||||
const sourcePath = path.resolve(skillDir, reference.from)
|
const sourcePath = path.resolve(skillDir, reference.from)
|
||||||
@@ -133,7 +132,7 @@ function validateMarkdown(skillRoot, relativePath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateArtifact(skillRoot) {
|
function validateArtifact(config, skillRoot) {
|
||||||
const expectedFiles = [
|
const expectedFiles = [
|
||||||
'SKILL.md',
|
'SKILL.md',
|
||||||
...config.references.map((reference) => reference.to),
|
...config.references.map((reference) => reference.to),
|
||||||
@@ -174,21 +173,36 @@ function compareArtifacts(expectedDir, actualDir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateConfig()
|
if (!Array.isArray(configs) || configs.length === 0) {
|
||||||
|
throw new Error('Skill configs must be a non-empty array')
|
||||||
if (isCheck) {
|
}
|
||||||
const temporaryRoot = mkdtempSync(path.join(tmpdir(), 'svg-sprites-skill-'))
|
|
||||||
try {
|
const names = new Set()
|
||||||
const expectedDir = path.join(temporaryRoot, config.name)
|
const outputs = new Set()
|
||||||
buildSkill(expectedDir)
|
|
||||||
validateArtifact(expectedDir)
|
for (const config of configs) {
|
||||||
compareArtifacts(expectedDir, outputDir)
|
const outputDir = path.resolve(skillDir, config.output)
|
||||||
console.log(`Skill is up to date: ${path.relative(process.cwd(), outputDir)}`)
|
validateConfig(config, outputDir)
|
||||||
} finally {
|
|
||||||
rmSync(temporaryRoot, { recursive: true, force: true })
|
if (names.has(config.name)) throw new Error(`Duplicate skill name: ${config.name}`)
|
||||||
}
|
if (outputs.has(outputDir)) throw new Error(`Duplicate skill output: ${config.output}`)
|
||||||
} else {
|
names.add(config.name)
|
||||||
buildSkill(outputDir)
|
outputs.add(outputDir)
|
||||||
validateArtifact(outputDir)
|
|
||||||
console.log(`Built skill: ${path.relative(process.cwd(), outputDir)}`)
|
if (isCheck) {
|
||||||
|
const temporaryRoot = mkdtempSync(path.join(tmpdir(), `${config.name}-skill-`))
|
||||||
|
try {
|
||||||
|
const expectedDir = path.join(temporaryRoot, config.name)
|
||||||
|
buildSkill(config, expectedDir)
|
||||||
|
validateArtifact(config, expectedDir)
|
||||||
|
compareArtifacts(expectedDir, outputDir)
|
||||||
|
console.log(`Skill is up to date: ${path.relative(process.cwd(), outputDir)}`)
|
||||||
|
} finally {
|
||||||
|
rmSync(temporaryRoot, { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buildSkill(config, outputDir)
|
||||||
|
validateArtifact(config, outputDir)
|
||||||
|
console.log(`Built skill: ${path.relative(process.cwd(), outputDir)}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,35 @@
|
|||||||
export default {
|
const references = [
|
||||||
name: 'svg-sprites',
|
{ from: '../../README.md', to: 'references/README.md' },
|
||||||
description: 'Используй при настройке, генерации, миграции или диагностике SVG-спрайтов через @gromlab/svg-sprites. Триггеры: SVG sprite, SVG-спрайт, svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer, icon="...", --icon-color-N, generated-компонент или иконка не появилась в превью и автодополнении. НЕ используй для favicon, растровых изображений, icon fonts, выбора набора иконок или inline SVG без спрайтов.',
|
{ from: '../../README_RU.md', to: 'references/README_RU.md' },
|
||||||
source: 'src/SKILL.md',
|
{ from: '../../docs/en/react-vite.md', to: 'references/docs/en/react-vite.md' },
|
||||||
output: '../artifacts/svg-sprites',
|
{ from: '../../docs/en/react-webpack.md', to: 'references/docs/en/react-webpack.md' },
|
||||||
references: [
|
{ from: '../../docs/en/next-app.md', to: 'references/docs/en/next-app.md' },
|
||||||
{ from: '../../README.md', to: 'references/README.md' },
|
{ from: '../../docs/en/next-pages.md', to: 'references/docs/en/next-pages.md' },
|
||||||
{ from: '../../docs/ru/react-vite.md', to: 'references/docs/ru/react-vite.md' },
|
{ from: '../../docs/en/legacy.md', to: 'references/docs/en/legacy.md' },
|
||||||
{ from: '../../docs/ru/react-webpack.md', to: 'references/docs/ru/react-webpack.md' },
|
{ from: '../../docs/en/migration-1.md', to: 'references/docs/en/migration-1.md' },
|
||||||
{ from: '../../docs/ru/next-app.md', to: 'references/docs/ru/next-app.md' },
|
{ from: '../../docs/en/programmatic-api.md', to: 'references/docs/en/programmatic-api.md' },
|
||||||
{ from: '../../docs/ru/next-pages.md', to: 'references/docs/ru/next-pages.md' },
|
{ from: '../../docs/ru/react-vite.md', to: 'references/docs/ru/react-vite.md' },
|
||||||
{ from: '../../docs/ru/legacy.md', to: 'references/docs/ru/legacy.md' },
|
{ from: '../../docs/ru/react-webpack.md', to: 'references/docs/ru/react-webpack.md' },
|
||||||
{ from: '../../docs/ru/migration-1.md', to: 'references/docs/ru/migration-1.md' },
|
{ from: '../../docs/ru/next-app.md', to: 'references/docs/ru/next-app.md' },
|
||||||
{ from: '../../docs/ru/programmatic-api.md', to: 'references/docs/ru/programmatic-api.md' },
|
{ from: '../../docs/ru/next-pages.md', to: 'references/docs/ru/next-pages.md' },
|
||||||
],
|
{ from: '../../docs/ru/legacy.md', to: 'references/docs/ru/legacy.md' },
|
||||||
}
|
{ from: '../../docs/ru/migration-1.md', to: 'references/docs/ru/migration-1.md' },
|
||||||
|
{ from: '../../docs/ru/programmatic-api.md', to: 'references/docs/ru/programmatic-api.md' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
name: 'svg-sprites',
|
||||||
|
description: 'Use when configuring, generating, migrating, or troubleshooting SVG sprites with @gromlab/svg-sprites. Triggers: SVG sprite, svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer, icon="...", --icon-color-N, generated component, or an icon missing from preview or autocomplete. Do NOT use for favicons, raster images, icon fonts, choosing an icon set, or inline SVG without sprites.',
|
||||||
|
source: 'src/SKILL.md',
|
||||||
|
output: '../artifacts/svg-sprites',
|
||||||
|
references,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'svg-sprites-ru',
|
||||||
|
description: 'Используй при настройке, генерации, миграции или диагностике SVG-спрайтов через @gromlab/svg-sprites. Триггеры: SVG sprite, SVG-спрайт, svg-sprites, svg-sprite.config.ts, svg-sprites.config.ts, defineReactSpriteConfig, defineNextSpriteConfig, react@vite, react@webpack, next@app, next@pages, inputFiles, SpriteViewer, icon="...", --icon-color-N, generated-компонент или иконка не появилась в превью и автодополнении. НЕ используй для favicon, растровых изображений, icon fonts, выбора набора иконок или inline SVG без спрайтов.',
|
||||||
|
source: 'src/SKILL_RU.md',
|
||||||
|
output: '../artifacts/svg-sprites-ru',
|
||||||
|
references,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
# SVG Sprites
|
# SVG Sprites
|
||||||
|
|
||||||
## Назначение
|
## Purpose
|
||||||
|
|
||||||
Используй этот скил для работы с `@gromlab/svg-sprites`: первичной настройки, добавления и переиспользования иконок, генерации React-компонентов, подключения `SpriteViewer`, миграции legacy-конфигурации и диагностики ошибок.
|
Use this skill when working with `@gromlab/svg-sprites`: initial setup, adding and reusing icons, generating React components, integrating `SpriteViewer`, migrating legacy configurations, and troubleshooting errors.
|
||||||
|
|
||||||
Не навязывай проекту конкретную архитектуру каталогов. Сначала изучи существующие `package.json`, конфигурацию спрайта, используемый фреймворк, роутер и сборщик.
|
Do not impose a specific directory architecture on the project. First inspect the existing `package.json`, sprite configuration, framework, router, and bundler.
|
||||||
|
|
||||||
## Рабочий алгоритм
|
## Workflow
|
||||||
|
|
||||||
1. Определи существующий режим и не смешивай его API с другим режимом.
|
1. Identify the existing mode and do not mix its API with another mode.
|
||||||
2. Для React выбери `react@vite` или `react@webpack` и открой соответствующий reference.
|
2. For React, choose `react@vite` or `react@webpack` and open the corresponding reference.
|
||||||
3. Для Next.js определи App Router или Pages Router, затем Turbopack или Webpack, и открой соответствующий reference.
|
3. For Next.js, identify the App Router or Pages Router, then Turbopack or Webpack, and open the corresponding reference.
|
||||||
4. Для существующего `svg-sprites.config.ts` с несколькими спрайтами используй legacy-документацию. Не мигрируй такой проект без явного запроса.
|
4. For an existing `svg-sprites.config.ts` with multiple sprites, use the legacy documentation. Do not migrate such a project unless explicitly requested.
|
||||||
5. Изучи локальные scripts и добавляй генерацию перед `dev`, `build` и `typecheck`, если generated-файлы не хранятся в Git.
|
5. Inspect local scripts and run generation before `dev`, `build`, and `typecheck` when generated files are not committed to Git.
|
||||||
6. После изменения конфигурации или SVG запусти генерацию, затем доступную проверку типов или сборку проекта.
|
6. After changing a configuration or SVG file, run generation followed by the available type check or project build.
|
||||||
|
|
||||||
## Правила React и Next.js
|
## React And Next.js Rules
|
||||||
|
|
||||||
- Используй локальный `svg-sprite.config.ts` и подходящий config helper: `defineReactSpriteConfig` или `defineNextSpriteConfig`.
|
- Use a local `svg-sprite.config.ts` and the appropriate config helper: `defineReactSpriteConfig` or `defineNextSpriteConfig`.
|
||||||
- Не редактируй `generated/`, `index.ts`, `manifest.ts` и созданный генератором `.gitignore` вручную.
|
- Do not manually edit `generated/`, `index.ts`, `manifest.ts`, or the generator-created `.gitignore`.
|
||||||
- Имена исходных SVG становятся допустимыми значениями prop `icon`; используй generated-компонент и его публичные типы вместо deep imports.
|
- Source SVG names become valid values for the `icon` prop; use the generated component and its public types instead of deep imports.
|
||||||
- Объединяй локальную папку и `inputFiles`, когда общая иконка нужна нескольким спрайтам. Не создавай копии одного SVG без необходимости.
|
- Combine the local folder with `inputFiles` when multiple sprites need a shared icon. Do not create unnecessary copies of the same SVG.
|
||||||
- В Next.js generated-компонент можно использовать в Server Components, SSR и SSG. Не добавляй `'use client'` только ради иконки.
|
- In Next.js, generated components work in Server Components, SSR, and SSG. Do not add `'use client'` only for an icon.
|
||||||
- Спрайт должен оставаться внешним asset сборщика: не переносить SVG path-данные в JavaScript и не класть generated-файл вручную в `public`.
|
- Keep the sprite as an external bundler asset: do not move SVG path data into JavaScript or manually place the generated file in `public`.
|
||||||
|
|
||||||
## Цвета и трансформации
|
## Colors And Transformations
|
||||||
|
|
||||||
- По умолчанию генератор удаляет `width` и `height`, заменяет поддерживаемые `fill` и `stroke` на CSS-переменные и добавляет transitions.
|
- By default, the generator removes `width` and `height`, replaces supported `fill` and `stroke` values with CSS variables, and adds transitions.
|
||||||
- Для монохромной иконки сначала управляй `color`; для многоцветной используй `--icon-color-N`.
|
- For a monochrome icon, control `color` first; for a multicolor icon, use `--icon-color-N`.
|
||||||
- Не обещай автоматическую замену цветов внутри внешних stylesheets, gradients, patterns, filters и значений `url(#...)` без проверки результата.
|
- Do not promise automatic color replacement inside external stylesheets, gradients, patterns, filters, or `url(#...)` values without checking the result.
|
||||||
- CSS-переменные страницы работают при `<svg><use>`, но не проникают внутрь `<img>` и `background-image`.
|
- Page CSS variables work with `<svg><use>`, but do not propagate into `<img>` or `background-image`.
|
||||||
|
|
||||||
## Превью
|
## Preview
|
||||||
|
|
||||||
Для React и Next.js подключай `<SpriteViewer>` отдельной debug-страницей приложения. Передай ему manifests или lazy loaders спрайтов. Viewer поддерживает поиск, светлую и тёмную темы, настройку цветов и примеры React, SVG, IMG и CSS.
|
For React and Next.js, add `<SpriteViewer>` as a separate debug page in the application. Pass sprite manifests or lazy loaders to it. The Viewer supports search, light and dark themes, color controls, and React, SVG, IMG, and CSS examples.
|
||||||
|
|
||||||
`SpriteViewer` является клиентским debug-инструментом и импортируется из `@gromlab/svg-sprites/react`; production-компоненты иконок от него не зависят.
|
`SpriteViewer` is a client-side debug tool imported from `@gromlab/svg-sprites/react`; production icon components do not depend on it.
|
||||||
|
|
||||||
## Диагностика
|
## Troubleshooting
|
||||||
|
|
||||||
- Если имя иконки отсутствует в автодополнении, проверь входную папку и `inputFiles`, затем перезапусти генерацию.
|
- If an icon name is missing from autocomplete, check the input folder and `inputFiles`, then rerun generation.
|
||||||
- Если два файла имеют одинаковое имя иконки, устрани конфликт вместо выбора одного файла неявно.
|
- If two files have the same icon name, resolve the conflict instead of implicitly selecting one file.
|
||||||
- Если генератор отказывается перезаписывать файл, не удаляй защитный marker и не обходи writer: перенеси пользовательский файл или выбери другой каталог спрайта.
|
- If the generator refuses to overwrite a file, do not remove the protection marker or bypass the writer: move the user file or choose another sprite directory.
|
||||||
- Если asset не загружается, сначала проверь соответствие CLI mode реальному сборщику проекта и обработку generated SVG его asset pipeline.
|
- If an asset fails to load, first confirm that the CLI mode matches the project's actual bundler and that its asset pipeline handles the generated SVG.
|
||||||
- Если проект использует старый API, сверь установленную версию пакета и legacy reference перед изменениями.
|
- If the project uses the old API, check the installed package version and the legacy reference before making changes.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- [Основная документация и API](./references/README.md)
|
- [Main documentation and API](./references/README.md)
|
||||||
- [React + Vite](./references/docs/ru/react-vite.md)
|
- [React + Vite](./references/docs/en/react-vite.md)
|
||||||
- [React + Webpack 5](./references/docs/ru/react-webpack.md)
|
- [React + Webpack 5](./references/docs/en/react-webpack.md)
|
||||||
- [Next.js App Router](./references/docs/ru/next-app.md)
|
- [Next.js App Router](./references/docs/en/next-app.md)
|
||||||
- [Next.js Pages Router](./references/docs/ru/next-pages.md)
|
- [Next.js Pages Router](./references/docs/en/next-pages.md)
|
||||||
- [Legacy mode](./references/docs/ru/legacy.md)
|
- [Legacy mode](./references/docs/en/legacy.md)
|
||||||
- [Миграция с 0.1.x](./references/docs/ru/migration-1.md)
|
- [Migrating from 0.1.x](./references/docs/en/migration-1.md)
|
||||||
- [Программный API](./references/docs/ru/programmatic-api.md)
|
- [Programmatic API](./references/docs/en/programmatic-api.md)
|
||||||
|
|||||||
57
skills/svg-sprites/src/SKILL_RU.md
Normal file
57
skills/svg-sprites/src/SKILL_RU.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# SVG Sprites
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Используй этот скил для работы с `@gromlab/svg-sprites`: первичной настройки, добавления и переиспользования иконок, генерации React-компонентов, подключения `SpriteViewer`, миграции legacy-конфигурации и диагностики ошибок.
|
||||||
|
|
||||||
|
Не навязывай проекту конкретную архитектуру каталогов. Сначала изучи существующие `package.json`, конфигурацию спрайта, используемый фреймворк, роутер и сборщик.
|
||||||
|
|
||||||
|
## Рабочий алгоритм
|
||||||
|
|
||||||
|
1. Определи существующий режим и не смешивай его API с другим режимом.
|
||||||
|
2. Для React выбери `react@vite` или `react@webpack` и открой соответствующий reference.
|
||||||
|
3. Для Next.js определи App Router или Pages Router, затем Turbopack или Webpack, и открой соответствующий reference.
|
||||||
|
4. Для существующего `svg-sprites.config.ts` с несколькими спрайтами используй legacy-документацию. Не мигрируй такой проект без явного запроса.
|
||||||
|
5. Изучи локальные scripts и добавляй генерацию перед `dev`, `build` и `typecheck`, если generated-файлы не хранятся в Git.
|
||||||
|
6. После изменения конфигурации или SVG запусти генерацию, затем доступную проверку типов или сборку проекта.
|
||||||
|
|
||||||
|
## Правила React и Next.js
|
||||||
|
|
||||||
|
- Используй локальный `svg-sprite.config.ts` и подходящий config helper: `defineReactSpriteConfig` или `defineNextSpriteConfig`.
|
||||||
|
- Не редактируй `generated/`, `index.ts`, `manifest.ts` и созданный генератором `.gitignore` вручную.
|
||||||
|
- Имена исходных SVG становятся допустимыми значениями prop `icon`; используй generated-компонент и его публичные типы вместо deep imports.
|
||||||
|
- Объединяй локальную папку и `inputFiles`, когда общая иконка нужна нескольким спрайтам. Не создавай копии одного SVG без необходимости.
|
||||||
|
- В Next.js generated-компонент можно использовать в Server Components, SSR и SSG. Не добавляй `'use client'` только ради иконки.
|
||||||
|
- Спрайт должен оставаться внешним asset сборщика: не переносить SVG path-данные в JavaScript и не класть generated-файл вручную в `public`.
|
||||||
|
|
||||||
|
## Цвета и трансформации
|
||||||
|
|
||||||
|
- По умолчанию генератор удаляет `width` и `height`, заменяет поддерживаемые `fill` и `stroke` на CSS-переменные и добавляет transitions.
|
||||||
|
- Для монохромной иконки сначала управляй `color`; для многоцветной используй `--icon-color-N`.
|
||||||
|
- Не обещай автоматическую замену цветов внутри внешних stylesheets, gradients, patterns, filters и значений `url(#...)` без проверки результата.
|
||||||
|
- CSS-переменные страницы работают при `<svg><use>`, но не проникают внутрь `<img>` и `background-image`.
|
||||||
|
|
||||||
|
## Превью
|
||||||
|
|
||||||
|
Для React и Next.js подключай `<SpriteViewer>` отдельной debug-страницей приложения. Передай ему manifests или lazy loaders спрайтов. Viewer поддерживает поиск, светлую и тёмную темы, настройку цветов и примеры React, SVG, IMG и CSS.
|
||||||
|
|
||||||
|
`SpriteViewer` является клиентским debug-инструментом и импортируется из `@gromlab/svg-sprites/react`; production-компоненты иконок от него не зависят.
|
||||||
|
|
||||||
|
## Диагностика
|
||||||
|
|
||||||
|
- Если имя иконки отсутствует в автодополнении, проверь входную папку и `inputFiles`, затем перезапусти генерацию.
|
||||||
|
- Если два файла имеют одинаковое имя иконки, устрани конфликт вместо выбора одного файла неявно.
|
||||||
|
- Если генератор отказывается перезаписывать файл, не удаляй защитный marker и не обходи writer: перенеси пользовательский файл или выбери другой каталог спрайта.
|
||||||
|
- Если asset не загружается, сначала проверь соответствие CLI mode реальному сборщику проекта и обработку generated SVG его asset pipeline.
|
||||||
|
- Если проект использует старый API, сверь установленную версию пакета и legacy reference перед изменениями.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Основная документация и API](./references/README_RU.md)
|
||||||
|
- [React + Vite](./references/docs/ru/react-vite.md)
|
||||||
|
- [React + Webpack 5](./references/docs/ru/react-webpack.md)
|
||||||
|
- [Next.js App Router](./references/docs/ru/next-app.md)
|
||||||
|
- [Next.js Pages Router](./references/docs/ru/next-pages.md)
|
||||||
|
- [Legacy mode](./references/docs/ru/legacy.md)
|
||||||
|
- [Миграция с 0.1.x](./references/docs/ru/migration-1.md)
|
||||||
|
- [Программный API](./references/docs/ru/programmatic-api.md)
|
||||||
Reference in New Issue
Block a user