mirror of
https://github.com/gromlab-ru/svg-sprites.git
synced 2026-07-22 04:40:17 +03:00
sync
This commit is contained in:
@@ -1,31 +1,25 @@
|
||||
# AI skills
|
||||
|
||||
Исходники обязательного контекста английского и русского skills находятся в `skills/svg-sprites/src/{en,ru}/`. Канонические exact-mode guides находятся в `docs/{en,ru}/guides/` и копируются в соответствующий skill без изменения. Готовые переносимые артефакты генерируются в `skills/artifacts/`, игнорируются Git и упаковываются в ZIP во время release workflow.
|
||||
Исходники обязательного контекста английского и русского skills находятся в `skills/svg-sprites/src/{en,ru}/`. Готовые переносимые артефакты генерируются в `skills/artifacts/`, игнорируются Git и упаковываются в ZIP во время release workflow.
|
||||
|
||||
Обе языковые версии имеют одинаковую структуру:
|
||||
Русский skill хранит весь обязательный контекст в одном файле:
|
||||
|
||||
```text
|
||||
src/<language>/
|
||||
src/ru/
|
||||
├── SKILL.md
|
||||
├── core/
|
||||
│ ├── 00-package-overview.md
|
||||
│ ├── 10-mode-selection.md
|
||||
│ ├── 20-project-inspection.md
|
||||
│ ├── 30-react-next-setup.md
|
||||
│ ├── 40-generated-contract.md
|
||||
│ ├── 50-usage-and-colors.md
|
||||
│ ├── 60-verification.md
|
||||
│ └── 70-diagnostics.md
|
||||
└── references/
|
||||
├── programmatic-api.md
|
||||
└── complex-svg.md
|
||||
```
|
||||
|
||||
`core/` содержит обязательные знания, раскрываемые прямо в итоговый `SKILL.md`. Локальный `references/` содержит только agent-specific материалы. Девять файлов из `docs/<language>/guides/` копируются в `references/guides/`; английский artifact получает только английские guides, русский только русские. Второй набор mode guides и каталог `references/upstream/` не создаются.
|
||||
`src/ru/SKILL.md` содержит знания о пакете и рабочий процесс агента. Exact-mode настройка берётся из canonical guides, а не дублируется отдельными source-фрагментами.
|
||||
|
||||
Русский artifact дополнительно получает без изменений `README_RU.md` и содержательную пользовательскую документацию из `docs/ru/`. Локальный редакторский `guides/AGENTS.md`, а также навигационные `guides/README.md` и `reference/README.md` не копируются. Файлы находятся в `references/README_RU.md` и `references/docs/ru/`. Agent-specific `complex-svg.md` остаётся отдельным reference.
|
||||
|
||||
Английский source пока сохраняет составную структуру с `core/`, а artifact — английские exact-mode guides и локальные `programmatic-api.md`/`complex-svg.md`. Его перевод на единый `SKILL.md` и полную canonical-документацию выполняется отдельно.
|
||||
|
||||
## Композиция Markdown
|
||||
|
||||
В любой собираемый документ можно включать фрагменты:
|
||||
Сборщик сохраняет поддержку Markdown includes для английского skill и будущих документов:
|
||||
|
||||
```md
|
||||
<!-- include: ./core/10-mode-selection.md -->
|
||||
|
||||
@@ -137,7 +137,13 @@ function expandCopies(config) {
|
||||
assertSafeRelativePath(entry.toDirectory)
|
||||
const sourceDirectory = path.resolve(skillDir, entry.fromDirectory)
|
||||
const extensions = entry.extensions ?? []
|
||||
for (const relativePath of listDirectoryFiles(sourceDirectory, extensions)) {
|
||||
const sourceFiles = listDirectoryFiles(sourceDirectory, extensions)
|
||||
const excluded = new Set((entry.exclude ?? []).map((relativePath) => {
|
||||
assertSafeRelativePath(relativePath)
|
||||
return relativePath.replaceAll('\\', '/')
|
||||
}))
|
||||
for (const relativePath of sourceFiles) {
|
||||
if (excluded.has(relativePath)) continue
|
||||
copies.push({
|
||||
from: path.join(sourceDirectory, relativePath),
|
||||
to: path.posix.join(entry.toDirectory, relativePath),
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
const agentReferences = [
|
||||
'programmatic-api.md',
|
||||
'complex-svg.md',
|
||||
]
|
||||
const agentReferences = {
|
||||
en: [
|
||||
'programmatic-api.md',
|
||||
'complex-svg.md',
|
||||
],
|
||||
ru: [
|
||||
'complex-svg.md',
|
||||
],
|
||||
}
|
||||
|
||||
const guideFiles = [
|
||||
'standalone.md',
|
||||
@@ -18,7 +23,7 @@ const guideFiles = [
|
||||
function documents(language) {
|
||||
return [
|
||||
{ entry: `src/${language}/SKILL.md`, to: 'SKILL.md', skill: true },
|
||||
...agentReferences.map((file) => ({
|
||||
...agentReferences[language].map((file) => ({
|
||||
entry: `src/${language}/references/${file}`,
|
||||
to: `references/${file}`,
|
||||
})),
|
||||
@@ -32,6 +37,20 @@ function guides(language) {
|
||||
}))
|
||||
}
|
||||
|
||||
const russianDocumentation = [
|
||||
{ from: '../../README_RU.md', to: 'references/README_RU.md' },
|
||||
{
|
||||
fromDirectory: '../../docs/ru',
|
||||
toDirectory: 'references/docs/ru',
|
||||
extensions: ['.md'],
|
||||
exclude: [
|
||||
'guides/AGENTS.md',
|
||||
'guides/README.md',
|
||||
'reference/README.md',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export default [
|
||||
{
|
||||
name: 'svg-sprites',
|
||||
@@ -43,10 +62,10 @@ export default [
|
||||
},
|
||||
{
|
||||
name: 'svg-sprites-ru',
|
||||
description: 'Используй только при настройке, изменении или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.ts, defineSpriteConfig, generateSprite, standalone, standalone@vite, standalone@webpack, react@vite, react@webpack, next@app, next@pages, SpriteConfig.input, --input, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
|
||||
description: 'Используй только при настройке, изменении или диагностике @gromlab/svg-sprites. Триггеры: @gromlab/svg-sprites, svg-sprite.config.json, svg-sprite.config.ts, defineSpriteConfig, generateSprite, standalone, standalone@vite, standalone@webpack, react@vite, react@webpack, next@app, next@pages, SpriteConfig.input, --input, SpriteViewer и --icon-color-N. НЕ используй для самописных SVG-спрайтов, inline SVG, favicon, растровых изображений, icon fonts или выбора библиотеки иконок.',
|
||||
output: '../artifacts/svg-sprites-ru',
|
||||
maxSkillBytes: 48_000,
|
||||
documents: documents('ru'),
|
||||
copy: guides('ru'),
|
||||
copy: russianDocumentation,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,19 +1,282 @@
|
||||
# @gromlab/svg-sprites
|
||||
|
||||
<!-- include: ./core/00-package-overview.md -->
|
||||
<!-- include: ./core/10-mode-selection.md -->
|
||||
<!-- include: ./core/20-project-inspection.md -->
|
||||
<!-- include: ./core/30-react-next-setup.md -->
|
||||
<!-- include: ./core/40-generated-contract.md -->
|
||||
<!-- include: ./core/50-usage-and-colors.md -->
|
||||
<!-- include: ./core/60-verification.md -->
|
||||
<!-- include: ./core/70-diagnostics.md -->
|
||||
## Что делает пакет
|
||||
|
||||
## Справочники по необходимости
|
||||
`@gromlab/svg-sprites` — CLI-генератор SVG-спрайтов для пользовательских SVG-файлов. Пакет не содержит собственного набора иконок: он собирает SVG проекта во внешний sprite asset, создаёт нативный типизированный Web Component для standalone bundler modes и React-компонент для React/Next.js.
|
||||
|
||||
- Для статической публикации открой [bare standalone](./references/guides/standalone.md). Для vanilla-приложений со сборщиком открой [standalone + Vite](./references/guides/standalone-vite.md) или [standalone + Webpack](./references/guides/standalone-webpack.md).
|
||||
- Для React открой exact guide для [Vite](./references/guides/react-vite.md) или [Webpack](./references/guides/react-webpack.md).
|
||||
- Для Next.js App Router открой exact guide для [Turbopack](./references/guides/next-app-turbopack.md) или [Webpack](./references/guides/next-app-webpack.md).
|
||||
- Для Next.js Pages Router открой exact guide для [Turbopack](./references/guides/next-pages-turbopack.md) или [Webpack](./references/guides/next-pages-webpack.md).
|
||||
- Для вызова генератора из Node.js открой [программный API](./references/programmatic-api.md).
|
||||
- Для gradients, filters, `url(#...)`, нестандартных цветов и проблем с `viewBox` открой [сложные SVG](./references/complex-svg.md).
|
||||
Пакет рассчитан на несколько независимых спрайтов в одном проекте. Каждый явно выбранный config-файл или config-less каталог описывает один спрайт и получает собственные:
|
||||
|
||||
- SVG asset;
|
||||
- mode-specific manifest data;
|
||||
- для bundler modes — типы имён и production entry `.svg-sprite/index.js`;
|
||||
- для `standalone@vite`/`standalone@webpack` — нативный Web Component с явной функцией регистрации;
|
||||
- только для React/Next.js — React-компонент;
|
||||
- для bare `standalone` — deployment-neutral JSON manifest без публичного URL.
|
||||
|
||||
Количество и расположение каталогов определяет проект. Например, `name: 'file-manager'` создаёт `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames`, а другой каталог с `name: 'navigation'` создаст отдельный `NavigationIcon`. Это примеры API отдельных спрайтов, а не фиксированные экспорты пакета.
|
||||
|
||||
Generated production runtime и declarations не импортируют `@gromlab/svg-sprites`. Генерация через `npx --yes @gromlab/svg-sprites <path-to-config>` не добавляет package в проект. Устанавливай его как development dependency только для Viewer, package-типов config или программного API.
|
||||
|
||||
## Выбор режима
|
||||
|
||||
Выбери ровно один поддерживаемый mode key:
|
||||
|
||||
| Проект | Mode key |
|
||||
|---|---|
|
||||
| Static HTML / собственная публикация | `standalone` |
|
||||
| Standalone + Vite | `standalone@vite` |
|
||||
| Standalone + Webpack 5 | `standalone@webpack` |
|
||||
| React + Vite | `react@vite` |
|
||||
| React + Webpack 5 | `react@webpack` |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` |
|
||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
Mode задаётся в config, CLI или программном API. Порядок применения: `defaults → config → CLI/API overrides`. После объединения mode обязателен.
|
||||
|
||||
`name` необязателен. Если он не задан, генератор преобразует имя каталога sprite-модуля в kebab-case; для каталогов `svg-sprite` и `svg-sprites` используется имя родительского каталога. Явное `name` должно уже быть записано в kebab-case и начинаться с латинской буквы.
|
||||
|
||||
CLI принимает ровно один путь. Путь к файлу `.ts`, `.js` или `.json` загружает именно этот конфиг независимо от имени. Путь к каталогу включает config-less генерацию, и настройки передаются флагами CLI.
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:<name>": "npx --yes @gromlab/svg-sprites <path-to-config>",
|
||||
"sprite:<name>:cli": "npx --yes @gromlab/svg-sprites --mode <mode-key> <sprite-directory>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Генерация через `npx` не добавляет package в проект. Не используй неполные `react`, `next@app`, `next@pages`, `standalone@` или удалённый `legacy`. Bare `standalone` выбирай только когда приложение само публикует SVG; для Vite/Webpack используй соответствующий полный key. Для нескольких спрайтов создай отдельную команду для каждого config-файла или каталога.
|
||||
|
||||
## Инспекция проекта
|
||||
|
||||
До изменений установи фактический контракт проекта:
|
||||
|
||||
1. Прочитай корневой `package.json`, lock-файл и workspace-конфигурацию; определи framework, bundler и существующие команды.
|
||||
2. Найди config-файлы, команды `svg-sprites` и импорты generated-компонентов. Имя конфига произвольное; ориентируйся на переданный CLI путь и поля объекта.
|
||||
3. Для React определи Vite или Webpack 5 по scripts и конфигу. Для Next.js отдельно определи App/Pages Router и сборщик реальных `dev`/`build` команд.
|
||||
4. Проверь существующие `predev`, `prebuild`, `pretypecheck` и агрегирующие scripts. Не перезаписывай их.
|
||||
5. Для нового спрайта выбери целевой каталог, не навязывая конкретный слой или архитектуру приложения.
|
||||
6. Проверь TypeScript и alias-настройки. Для package subpath exports нужен TypeScript 5+ с `moduleResolution: 'bundler'`, `'node16'` или `'nodenext'`.
|
||||
|
||||
Все input-пути считаются относительно каталога, содержащего явно переданный config-файл; в config-less режиме — относительно переданного каталога. Проверяй `input` как единый контракт:
|
||||
|
||||
- `input?: string | string[]` по умолчанию равен `./icons`;
|
||||
- каждая строка задаёт папку, точный SVG-файл или glob;
|
||||
- папка сканируется плоско; вложенные файлы включаются только явным recursive glob, например `./icons/**/*.svg`;
|
||||
- массив объединяет positive-источники, а элемент с префиксом `!` исключает свои совпадения из общего набора;
|
||||
- каждый positive-источник должен разрешаться хотя бы в один SVG, поэтому отсутствующая или пустая папка, glob без совпадений, отсутствующий файл или точный путь не к SVG являются ошибкой;
|
||||
- разрешённые файлы дедуплицируются и детерминированно сортируются;
|
||||
- разные файлы с одинаковым basename конфликтуют, даже если получены из разных источников.
|
||||
|
||||
Не копируй общий SVG в несколько папок: добавь его точный путь или подходящий glob в `input` каждого нужного спрайта. Используй `**/*.svg` только для намеренного рекурсивного включения.
|
||||
|
||||
## Настройка интеграции
|
||||
|
||||
Не воспроизводи настройку mode по памяти. После инспекции проекта выбери один exact mode и открой соответствующий файл из `references/docs/ru/guides/`. Используй guide как базовый рабочий контракт, затем адаптируй его к существующей структуре проекта.
|
||||
|
||||
Работай в таком порядке:
|
||||
|
||||
1. Определи каталог исходных SVG и каталог одного sprite-модуля. Один config создаёт один независимый спрайт; для нескольких наборов нужны отдельные config-файлы и уникальные `name`.
|
||||
2. Сверь framework, router и bundler с exact mode. Для Next.js проверяй реальные `dev` и `build` scripts, а не только наличие `next.config.*`.
|
||||
3. Предпочитай JSON-конфиг, если проекту не нужны package-типы config. TypeScript-конфиг также загружается через CLI, но установка package нужна, когда он импортирует `defineSpriteConfig` или типы.
|
||||
4. Разрешай все `input` относительно каталога config-файла. Не меняй структуру SVG без необходимости: используй путь к папке, точный файл, glob или массив этих источников.
|
||||
5. Добавь sprite-команду с явным путём к config. Сохрани существующие `dev`, `build`, `typecheck` и lifecycle hooks; встрой генерацию до первого процесса, импортирующего `.svg-sprite`.
|
||||
6. Не запускай одну генерацию дважды через одновременный `predev` и `npm run sprites && ...`. Для нескольких спрайтов создай отдельные команды и один агрегирующий script.
|
||||
7. Если приложение импортирует каталог sprite-модуля, создай пользовательский `index.ts` рядом с `.svg-sprite`; не помещай пользовательские файлы внутрь generated-каталога.
|
||||
8. Выполни первую генерацию до typecheck или запуска приложения, затем проверь mode-specific output и фактический импорт компонента.
|
||||
|
||||
Не добавляй Viewer автоматически. Подключай его только по запросу пользователя или когда нужна визуальная проверка набора, цветов либо сложных SVG. Способ изоляции Viewer от production бери из exact guide: Vite, Webpack, App Router и Pages Router используют разные границы.
|
||||
|
||||
Не копируй snippets между exact modes даже при похожем API. Различаются asset URL, generated-файлы, CSS handling, router boundary и способ подключения debug-инструментов.
|
||||
|
||||
## Контракт generated-каталога
|
||||
|
||||
После генерации React/Next-каталог имеет следующий вид:
|
||||
|
||||
```text
|
||||
svg-sprite/
|
||||
├── icons/ # пользовательские исходники
|
||||
├── svg-sprite.config.json # рекомендуемое имя конфига
|
||||
├── index.ts # необязательный пользовательский barrel
|
||||
├── .gitignore # управляет генератор
|
||||
└── .svg-sprite/
|
||||
├── index.js
|
||||
├── index.d.ts
|
||||
├── icon-data.js
|
||||
├── icon-data.d.ts
|
||||
├── sprite.svg
|
||||
├── svg-sprite.manifest.js
|
||||
├── svg-sprite.manifest.d.ts
|
||||
└── react/
|
||||
├── react-component.js
|
||||
├── react-component.d.ts
|
||||
└── react-component.module.css
|
||||
```
|
||||
|
||||
Standalone не создаёт `react/`. Bare `standalone` генерирует `sprite.svg` и `svg-sprite.manifest.json`; `standalone@vite`/`standalone@webpack` дополнительно генерируют `index.*`, `icon-data.*` и resolved manifest. Их `index.*` также содержит нативный generated Web Component; bare `standalone` не получает JS runtime и не создаёт `.gitignore`.
|
||||
|
||||
Редактируй исходные SVG, config-файл и пользовательский `index.ts`. Не изменяй вручную содержимое `.svg-sprite`: повторная генерация его перезапишет. Во всех modes, кроме bare `standalone`, generated `.gitignore` также находится под управлением генератора. Для импорта из корня sprite-модуля создай barrel:
|
||||
|
||||
```ts
|
||||
export * from './.svg-sprite/index.js'
|
||||
```
|
||||
|
||||
Генератор полностью владеет каталогом `.svg-sprite` и заменяет его при каждом запуске. Никогда не помещай туда пользовательские файлы. Генератор также владеет `.gitignore`, когда выбранный mode его создаёт. Bare `standalone` сохраняет пользовательский `.gitignore`, но удаляет управляемый `.gitignore`, оставшийся после другого mode. Generated-пути не должны содержать symlink.
|
||||
|
||||
В React/Next modes внутренний `index.js` экспортирует компонент из `react/react-component.js` и readonly-массив имён, а `index.d.ts` добавляет props/style-типы и union имени. Standalone bundler modes экспортируют Web Component helpers и типы без `react/`; bare `standalone` не создаёт facade. Manifest declarations bundler modes объявляют типы локально и не импортируют generator package. Manifest содержит mode, target, список и метаданные иконок для debug-инструментов; bundler manifest также содержит URL и не импортируется production-компонентом.
|
||||
|
||||
В bundler modes спрайт остаётся отдельным asset, а SVG path-данные не встраиваются в JavaScript. Content hash зависит от настроек сборщика. Bare `standalone` создаёт файл с фиксированным именем, а приложение само определяет его публичное имя и версионирование:
|
||||
|
||||
- `react@vite` генерирует статический импорт `sprite.svg?no-inline`, запрещающий Vite inline;
|
||||
- `standalone@vite` использует тот же Vite asset-механизм и экспортирует href helper и нативный Web Component без React;
|
||||
- `standalone@webpack` использует Webpack Asset Modules и экспортирует такой же mode-local Web Component без React;
|
||||
- React Webpack 5 и все Next modes получают asset через `new URL(..., import.meta.url).href`, который должен обработать соответствующий сборщик;
|
||||
- кастомный Webpack SVG loader не должен перехватывать generated `sprite.svg`;
|
||||
- в Next mode generated-компонент не содержит `'use client'` и работает в Server Components, SSR и SSG; не добавляй клиентскую границу только ради иконки;
|
||||
- команда сборки Next и mode key должны совпадать: Turbopack с `.../turbopack`, Webpack с `.../webpack`.
|
||||
|
||||
Для bundler modes не перемещай generated sprite в `public` и не переписывай URL вручную. Для bare `standalone` не перемещай managed original: приложение может явно копировать его в deploy output и само отвечает за публичный URL и очистку копии. При смене mode перегенерируй спрайт с новым полным key.
|
||||
|
||||
## Использование, доступность и цвета
|
||||
|
||||
Имя компонента зависит от `name` конкретного спрайта. В `standalone@vite` и `standalone@webpack` значение `name: 'file-manager'` создаёт tag `<file-manager-icon>` и функцию `defineFileManagerIconElement()`:
|
||||
|
||||
```ts
|
||||
import { defineFileManagerIconElement } from './svg-sprite'
|
||||
|
||||
defineFileManagerIconElement()
|
||||
```
|
||||
|
||||
```html
|
||||
<file-manager-icon icon="folder" aria-hidden="true"></file-manager-icon>
|
||||
```
|
||||
|
||||
Нативный элемент не имеет runtime-зависимостей, сам выбирает generated ID и `viewBox`, получает URL через bundler и рендерит `<svg><use>` в Shadow DOM. Его property `icon` типизирован точным union имён, но строковые HTML attributes проверяются только в runtime. Размер по умолчанию равен `1em × 1em`; меняй его через CSS на host. Bare `standalone` Web Component не генерирует.
|
||||
|
||||
В React/Next.js тот же `name: 'file-manager'` создаёт React-компонент `FileManagerIcon`. Для `name: 'navigation'` используй сгенерированный `NavigationIcon`.
|
||||
|
||||
Импортируй компонент из корня соответствующего каталога спрайта. `width` и `height` не обязательны: размером можно управлять обычным CSS-классом.
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from './svg-sprite'
|
||||
|
||||
export const OpenButton = () => (
|
||||
<button type="button">
|
||||
<FileManagerIcon icon="folder" className="icon" aria-hidden="true" />
|
||||
<span>Открыть</span>
|
||||
</button>
|
||||
)
|
||||
```
|
||||
|
||||
```css
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: #4b5563;
|
||||
}
|
||||
```
|
||||
|
||||
`icon` принимает точные имена исходных файлов без `.svg`; неизвестное имя является ошибкой TypeScript. Для небезопасных SVG ID имён генератор хранит публичное имя, но создаёт внутренний стабильный hash ID, поэтому не собирай fragment URL из имени вручную.
|
||||
|
||||
По умолчанию компонент рендерит `<svg>` и принимает стандартные SVG attributes: необязательные `width`/`height`, `className`, `style`, `role`, `aria-*` и обработчики. С `wrapped={true}` корнем становится `<span>`, props относятся к span, а внутренний SVG занимает размер wrapper.
|
||||
|
||||
Generated-компонент не выбирает семантику за приложение и не добавляет `title`. Для декоративной иконки передай `aria-hidden="true"`; для самостоятельной смысловой иконки передай `role="img"` и доступное имя через `aria-label`. Не дублируй имя, если соседний текст уже озвучивает действие. Интерактивность размещай на `button` или `a`, а не на самой иконке.
|
||||
|
||||
Трансформации `removeSize`, `replaceColors` и `addTransition` включены по умолчанию. Для монохромной иконки единственный цвет получает fallback `currentColor`, поэтому управляй CSS-свойством `color`. Для многоцветной передавай типизированные custom properties:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon
|
||||
icon="folder"
|
||||
style={{
|
||||
'--icon-color-1': '#4b5563',
|
||||
'--icon-color-2': '#14b8a6',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
Автозамена рассчитана на `fill`/`stroke` attributes и inline `style`. Значения `none`, `transparent`, `inherit`, `unset`, `initial` не заменяются. CSS-классы и внешние stylesheets, gradients, patterns, filters и `url(#...)` проверяй на реальном результате. Переменные страницы работают через `<svg><use>`, но не проникают во внешний документ при `<img>` или `background-image`; CSS mask оставляет только одноцветный силуэт.
|
||||
|
||||
`SpriteViewer` необязателен. Установи `@gromlab/svg-sprites` как development dependency, только если проекту нужен Viewer. Он принимает manifests или статически обнаружимые loaders, показывает поиск, темы, цвета и примеры, но production-компоненты от него не зависят.
|
||||
|
||||
Перед подключением Viewer открой exact guide. Vite использует отдельную HTML entry, обычный Webpack — development-only entry, Next.js — debug route, а App Router дополнительно требует отдельную Client Component boundary. Не переноси способ подключения между modes.
|
||||
|
||||
## Проверка результата
|
||||
|
||||
После изменения конфига или SVG выполни обязательные проверки:
|
||||
|
||||
1. Запусти точную sprite-команду. Процесс должен завершиться с кодом `0` и сообщить имя, число иконок, mode и каталог `.svg-sprite`.
|
||||
2. Проверь output выбранного exact mode:
|
||||
- bare `standalone` создаёт `sprite.svg` и `svg-sprite.manifest.json`;
|
||||
- `standalone@vite` и `standalone@webpack` дополнительно создают `index.*`, `icon-data.*` и JS manifest, но не каталог `react/`;
|
||||
- React и Next.js modes также создают `react/react-component.js`, declaration и CSS Module.
|
||||
3. Для modes с public facade проверь `.svg-sprite/index.js`, соседний `index.d.ts`, список имён и фактический импорт через пользовательский barrel.
|
||||
4. Проверь manifest: mode и target должны соответствовать выбранному adapter, а список иконок — исходным SVG. В bundler modes URL должен формироваться mode-specific способом; bare JSON manifest намеренно не содержит публичного `spriteUrl`.
|
||||
5. Запусти существующий typecheck проекта, если mode создаёт типы или изменился пользовательский TypeScript-код.
|
||||
6. Запусти минимальную команду приложения, затронутую изменением: `dev`, build или специализированную проверку проекта.
|
||||
|
||||
Не запускай полную production-сборку только ради проверки нового имени иконки. Она нужна, если менялся bundler target, router, Webpack loader, asset URL, deployment path или диагностируется production-only ошибка.
|
||||
|
||||
Визуальную проверку, Network и accessibility tree выполняй только при наличии запущенного приложения и браузерных инструментов. Если таких инструментов нет, не утверждай, что цвета, темы, доступность или HTTP-ответ asset проверены; явно укажи непроверенную часть.
|
||||
|
||||
Viewer используй для сложных цветов, transforms и массовой визуальной проверки. Не добавляй debug route ради обычной генерации одного спрайта.
|
||||
|
||||
## Диагностика
|
||||
|
||||
Сопоставь симптом с проверкой и исправляй первопричину:
|
||||
|
||||
| Симптом | Вероятная причина | Действие |
|
||||
|---|---|---|
|
||||
| `Missing sprite config file or module directory` | Не передан позиционный путь | Передай один config-файл либо каталог для config-less запуска. |
|
||||
| `Expected one config file or module directory` | Передано несколько путей | Создай отдельную команду на каждый спрайт и объедини scripts. |
|
||||
| `Sprite mode is required` | Mode отсутствует и в config, и в CLI | Добавь `mode` в объект или передай полный `--mode`. |
|
||||
| `Unsupported sprite config extension` | Передан файл не `.ts`, `.js` или `.json` | Используй поддерживаемый формат config-файла. |
|
||||
| Positive input-источник не нашёл SVG | Папка отсутствует или пуста, glob не совпал либо точный путь отсутствует или ведёт не к SVG | Разреши источник от каталога конфига и исправь `input`; каждый positive-элемент должен дать хотя бы один SVG. |
|
||||
| Иконки из подпапки не появились | От папки ожидалось рекурсивное сканирование | Используй явный glob, например `./icons/**/*.svg`; папки сканируются плоско. |
|
||||
| Исключённая иконка всё ещё присутствует | У исключения нет префикса `!`, оно находится не в массиве `input` или считается не от того каталога | Добавь совпадающий `!`-элемент и считай его от каталога конфига. |
|
||||
| CLI выбрал не все источники | Несколько источников поместили в одно значение `--input` или пропустили option | Повтори `--input <path-or-glob>` отдельно для каждого источника или исключения. |
|
||||
| Конфликт имени иконки или SVG ID | Два разных файла имеют одинаковый basename либо hash-ID столкнулся с именем | Переименуй один исходный SVG; не выбирай файл неявно. |
|
||||
| `Refusing to overwrite a user file` | В корне sprite-модуля уже есть пользовательский `.gitignore`, который mode должен создать | Не перезаписывай файл: выбери другой sprite-каталог или согласуй перенос существующего `.gitignore`. |
|
||||
| Нет `.svg-sprite/index.js` или имя отсутствует в autocomplete | Для bare `standalone` это ожидаемо; в остальных modes генерация не запускалась, barrel неверен либо type server держит старый модуль | Сверь exact mode, запусти sprite-команду, проверь `export * from './.svg-sprite/index.js'`, затем typecheck; при необходимости перезапусти TypeScript server. |
|
||||
| SVG не загружается или URL неверен | Mode не совпадает со сборщиком, неверен Webpack `publicPath` либо кастомный loader перехватил asset | Сверь mode и build-команду, проверь Asset Modules/`publicPath`, исключи generated SVG из несовместимого loader. |
|
||||
| Next build расходится между SSR и браузером | Модуль сгенерирован для другого bundler/router или URL переписан вручную | Верни generated `new URL(...)`, выбери точный Next mode и перегенерируй. |
|
||||
| `color` не меняет многоцветную иконку | У иконки несколько переменных или она показана через `<img>`/CSS background | Используй `<FileManagerIcon>`/`<svg><use>` и нужные `--icon-color-N`. |
|
||||
| Gradient/filter выглядит неверно | Автозамена цветов не гарантирует сложные paint servers | Изучи generated SVG; при необходимости отключи `replaceColors` для спрайта или упрости источник. |
|
||||
| Viewer пуст | Manifest не создан, loader не обнаружен сборщиком или неверна Client Component boundary | Сначала сгенерируй спрайт, затем сверь manifest import и способ подключения с exact guide; в App Router оставь `'use client'` только в компоненте Viewer. |
|
||||
|
||||
При неизвестной ошибке зафиксируй полную CLI-команду, mode, путь к config-файлу или каталогу и первый stack/error message. Затем минимально воспроизведи проблему на одном спрайте, не удаляя пользовательские файлы и управляемый `.gitignore`.
|
||||
|
||||
## Карта reference-документации
|
||||
|
||||
References являются частью собранного skill. Открывай только документы, относящиеся к текущей задаче, но перед изменением интеграции exact-mode guide обязателен.
|
||||
|
||||
### Обзор
|
||||
|
||||
- [README пакета](./references/README_RU.md) — возможности, основной React/Next.js сценарий и ссылки на документацию.
|
||||
|
||||
### Конфигурация
|
||||
|
||||
- [Конфигурация](./references/docs/ru/configuration.md) — JSON, JavaScript, TypeScript, поля config, `input` и запуск CLI.
|
||||
|
||||
### Exact-mode guides
|
||||
|
||||
- [`standalone`](./references/docs/ru/guides/standalone.md) — static HTML и собственная публикация SVG.
|
||||
- [`standalone@vite`](./references/docs/ru/guides/standalone-vite.md) — vanilla-приложение с Vite и Web Component.
|
||||
- [`standalone@webpack`](./references/docs/ru/guides/standalone-webpack.md) — vanilla-приложение с Webpack 5 и Web Component.
|
||||
- [`react@vite`](./references/docs/ru/guides/react-vite.md) — React с Vite.
|
||||
- [`react@webpack`](./references/docs/ru/guides/react-webpack.md) — React с Webpack 5.
|
||||
- [`next@app/turbopack`](./references/docs/ru/guides/next-app-turbopack.md) — Next.js App Router с Turbopack.
|
||||
- [`next@app/webpack`](./references/docs/ru/guides/next-app-webpack.md) — Next.js App Router с Webpack.
|
||||
- [`next@pages/turbopack`](./references/docs/ru/guides/next-pages-turbopack.md) — Next.js Pages Router с Turbopack.
|
||||
- [`next@pages/webpack`](./references/docs/ru/guides/next-pages-webpack.md) — Next.js Pages Router с Webpack.
|
||||
|
||||
### Технические справочники
|
||||
|
||||
- [Технический справочник](./references/docs/ru/reference/technical.md) — requirements, CLI, naming, generated API, assets, transforms, цвета, Viewer, Git, CI и диагностика.
|
||||
- [Программный API](./references/docs/ru/reference/programmatic-api.md) — `generateSprite`, overrides, config API, compiler и Viewer runtime.
|
||||
|
||||
### Agent-specific reference
|
||||
|
||||
- [Сложные SVG](./references/complex-svg.md) — gradients, patterns, filters, masks, `url(#...)`, `viewBox`, fragment IDs и визуальная диагностика.
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
## Что делает пакет
|
||||
|
||||
`@gromlab/svg-sprites` — CLI-генератор SVG-спрайтов для пользовательских SVG-файлов. Пакет не содержит собственного набора иконок: он собирает SVG проекта во внешний sprite asset, создаёт нативный типизированный Web Component для standalone bundler modes и React-компонент для React/Next.js.
|
||||
|
||||
Пакет рассчитан на несколько независимых спрайтов в одном проекте. Каждый явно выбранный config-файл или config-less каталог описывает один спрайт и получает собственные:
|
||||
|
||||
- SVG asset;
|
||||
- mode-specific manifest data;
|
||||
- для bundler modes — типы имён и production entry `.svg-sprite/index.js`;
|
||||
- для `standalone@vite`/`standalone@webpack` — нативный Web Component с явной функцией регистрации;
|
||||
- только для React/Next.js — React-компонент;
|
||||
- для bare `standalone` — deployment-neutral JSON manifest без публичного URL.
|
||||
|
||||
Количество и расположение каталогов определяет проект. Например, `name: 'file-manager'` создаёт `FileManagerIcon`, а другой каталог с `name: 'navigation'` создаст отдельный `NavigationIcon`. Имена `FileManagerIcon` и `fileManagerIconNames` ниже являются примерами API одного из возможных спрайтов, а не фиксированными экспортами пакета.
|
||||
|
||||
Generated production runtime и declarations не импортируют `@gromlab/svg-sprites`. Генерация работает через `npx --package` с зафиксированной версией без добавления package в проект. Устанавливай его как development dependency только для Viewer, package-типов config или программного API.
|
||||
@@ -1,30 +0,0 @@
|
||||
## Выбор режима
|
||||
|
||||
Выбери ровно один поддерживаемый mode key:
|
||||
|
||||
| Проект | Mode key |
|
||||
|---|---|
|
||||
| Static HTML / собственная публикация | `standalone` |
|
||||
| Standalone + Vite | `standalone@vite` |
|
||||
| Standalone + Webpack 5 | `standalone@webpack` |
|
||||
| React + Vite | `react@vite` |
|
||||
| React + Webpack 5 | `react@webpack` |
|
||||
| Next.js App Router + Turbopack | `next@app/turbopack` |
|
||||
| Next.js App Router + Webpack 5 | `next@app/webpack` |
|
||||
| Next.js Pages Router + Turbopack | `next@pages/turbopack` |
|
||||
| Next.js Pages Router + Webpack 5 | `next@pages/webpack` |
|
||||
|
||||
Mode задаётся в config, CLI или программном API. Порядок применения: `defaults → config → CLI/API overrides`. После объединения mode обязателен.
|
||||
|
||||
CLI принимает ровно один путь. Путь к файлу `.ts`, `.js` или `.json` загружает именно этот конфиг независимо от имени. Путь к каталогу включает config-less генерацию, и настройки передаются флагами CLI.
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:<name>": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites <path-to-config>",
|
||||
"sprite:<name>:cli": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites --mode <mode-key> <sprite-directory>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Генерация через `npx` не добавляет package в проект. В CI укажи точную версию вместо `latest`. Не используй неполные `react`, `next@app`, `next@pages`, `standalone@` или удалённый `legacy`. Bare `standalone` выбирай только когда приложение само публикует SVG; для Vite/Webpack используй соответствующий полный key. Для нескольких спрайтов создай отдельную команду для каждого config-файла или каталога.
|
||||
@@ -1,22 +0,0 @@
|
||||
## Инспекция проекта
|
||||
|
||||
До изменений установи фактический контракт проекта:
|
||||
|
||||
1. Прочитай корневой `package.json`, lock-файл и workspace-конфигурацию; определи framework, bundler и существующие команды.
|
||||
2. Найди config-файлы, команды `svg-sprites` и импорты generated-компонентов. Имя конфига произвольное; ориентируйся на переданный CLI путь и поля объекта.
|
||||
3. Для React определи Vite или Webpack 5 по scripts и конфигу. Для Next.js отдельно определи App/Pages Router и сборщик реальных `dev`/`build` команд.
|
||||
4. Проверь существующие `predev`, `prebuild`, `pretypecheck` и агрегирующие scripts. Не перезаписывай их.
|
||||
5. Для нового спрайта выбери целевой каталог, не навязывая конкретный слой или архитектуру приложения.
|
||||
6. Проверь TypeScript и alias-настройки. Для package subpath exports нужен TypeScript 5+ с `moduleResolution: 'bundler'`, `'node16'` или `'nodenext'`.
|
||||
|
||||
Все input-пути считаются относительно каталога, содержащего явно переданный config-файл; в config-less режиме — относительно переданного каталога. Проверяй `input` как единый контракт:
|
||||
|
||||
- `input?: string | string[]` по умолчанию равен `./icons`;
|
||||
- каждая строка задаёт папку, точный SVG-файл или glob;
|
||||
- папка сканируется плоско; вложенные файлы включаются только явным recursive glob, например `./icons/**/*.svg`;
|
||||
- массив объединяет positive-источники, а элемент с префиксом `!` исключает свои совпадения из общего набора;
|
||||
- каждый positive-источник должен разрешаться хотя бы в один SVG, поэтому отсутствующая или пустая папка, glob без совпадений, отсутствующий файл или точный путь не к SVG являются ошибкой;
|
||||
- разрешённые файлы дедуплицируются и детерминированно сортируются;
|
||||
- разные файлы с одинаковым basename конфликтуют, даже если получены из разных источников.
|
||||
|
||||
Не копируй общий SVG в несколько папок: добавь его точный путь или подходящий glob в `input` каждого нужного спрайта. Используй `**/*.svg` только для намеренного рекурсивного включения.
|
||||
@@ -1,63 +0,0 @@
|
||||
## Настройка React или Next.js
|
||||
|
||||
Выбери целевой каталог для одного спрайта. Он может находиться рядом с feature, в общем каталоге иконок или в любом другом месте, принятом в проекте. Следующая структура является только примером:
|
||||
|
||||
```text
|
||||
src/ui/file-manager/svg-sprite/
|
||||
├── icons/
|
||||
│ ├── check.svg
|
||||
│ └── folder.svg
|
||||
└── svg-sprite.config.ts
|
||||
```
|
||||
|
||||
Один `svg-sprite.config.ts` создаёт один независимый спрайт. Для нескольких наборов выбери несколько каталогов и дай каждому уникальное `name`.
|
||||
|
||||
Генератор не нужно устанавливать в проект. Начни с plain config без package
|
||||
import:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
mode: 'react@vite',
|
||||
name: 'file-manager',
|
||||
description: 'Иконки файлового менеджера',
|
||||
input: ['./icons', '../../shared/icons/close.svg'],
|
||||
}
|
||||
```
|
||||
|
||||
`input` принимает одну папку, точный SVG-файл или glob либо массив, объединяющий эти источники. Элемент массива с префиксом `!` исключает совпадения. Папки сканируются плоско; для рекурсии нужен явный glob `**/*.svg`. Если `input` не задан, используется `./icons`. Все пути считаются от каталога конфига, и каждый positive-источник должен найти хотя бы один SVG.
|
||||
|
||||
Контракт объекта одинаков для React и Next.js; отличается полный `mode`. Устанавливай package только для необязательного Viewer, программного API или package-типизации config. В exact guides также есть локальный copy-paste type для проектов без package.
|
||||
|
||||
`name` должен начинаться с латинской буквы и записываться в kebab-case; из примера `file-manager` будут созданы `FileManagerIcon`, `FileManagerIconName` и `fileManagerIconNames`. Другой спрайт получает собственные имена. Если `name` не задан, генератор выводит его из каталога.
|
||||
|
||||
Добавь отдельную команду с выбранным mode key и одним путём:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"sprite:file-manager": "npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts",
|
||||
"sprites": "npm run sprite:file-manager"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Для Next.js укажи в config полный ключ, например `next@app/turbopack`. Для нескольких спрайтов добавь по команде `sprite:<name>` на каждый config-файл и последовательно вызови их из `sprites`.
|
||||
|
||||
Чтобы задать источники через CLI, повторяй `--input <path-or-glob>`; значения образуют тот же массивный контракт, включая исключения с `!`:
|
||||
|
||||
```bash
|
||||
npx --yes --package=@gromlab/svg-sprites@latest svg-sprites src/ui/file-manager/svg-sprite/svg-sprite.config.ts \
|
||||
--input ./icons \
|
||||
--input '../../shared/icons/**/*.svg' \
|
||||
--input '!../../shared/icons/legacy-*.svg'
|
||||
```
|
||||
|
||||
Generated-файлы в `.svg-sprite` по умолчанию исключаются из Git, поэтому запускай `sprites` до процессов, которым нужны компонент, типы или asset. Если проект импортирует корень sprite-модуля, создай пользовательский `index.ts` с `export * from './.svg-sprite'`. Generated declarations self-contained и не импортируют generator package.
|
||||
|
||||
Запускай генерацию либо через `predev`/`prebuild`/`pretypecheck`, либо явно внутри соответствующих команд. Не используй обе формы для одной команды, иначе генерация выполнится дважды. Сохраняй существующие команды и не создавай второй одноимённый JSON key.
|
||||
|
||||
Запусти первую генерацию вручную:
|
||||
|
||||
```bash
|
||||
npm run sprites
|
||||
```
|
||||
@@ -1,51 +0,0 @@
|
||||
## Контракт generated-каталога
|
||||
|
||||
После генерации React/Next-каталог имеет следующий вид:
|
||||
|
||||
```text
|
||||
svg-sprite/
|
||||
├── icons/ # пользовательские исходники
|
||||
├── svg-sprite.config.ts # рекомендуемое имя конфига
|
||||
├── index.ts # необязательный пользовательский barrel
|
||||
├── .gitignore # управляет генератор
|
||||
└── .svg-sprite/
|
||||
├── index.js
|
||||
├── index.d.ts
|
||||
├── icon-data.js
|
||||
├── icon-data.d.ts
|
||||
├── sprite.svg
|
||||
├── svg-sprite.manifest.js
|
||||
├── svg-sprite.manifest.d.ts
|
||||
└── react/
|
||||
├── react-component.js
|
||||
├── react-component.d.ts
|
||||
└── react-component.module.css
|
||||
```
|
||||
|
||||
Standalone не создаёт `react/`. Bare `standalone` генерирует `sprite.svg` и
|
||||
`svg-sprite.manifest.json`; `standalone@vite`/`standalone@webpack` дополнительно
|
||||
генерируют `index.*`, `icon-data.*` и resolved manifest. Их `index.*` также
|
||||
содержит нативный generated Web Component; bare `standalone` не получает JS runtime,
|
||||
не создаёт и не изменяет `.gitignore`.
|
||||
|
||||
Редактируй исходные SVG, config-файл и пользовательский `index.ts`. Не изменяй вручную содержимое `.svg-sprite`: повторная генерация его перезапишет. Во всех modes, кроме bare `standalone`, generated `.gitignore` также находится под управлением генератора. Для импорта из корня sprite-модуля создай barrel:
|
||||
|
||||
```ts
|
||||
export * from './.svg-sprite'
|
||||
```
|
||||
|
||||
Генератор полностью владеет каталогом `.svg-sprite` и заменяет его при каждом запуске. Никогда не помещай туда пользовательские файлы. Генератор также владеет `.gitignore`, когда выбранный mode его создаёт; bare `standalone` оставляет существующий `.gitignore` без изменений. Generated-пути не должны содержать symlink.
|
||||
|
||||
Внутренний `index.js` экспортирует компонент из `react/react-component.js` и readonly-массив имён; соседний `index.d.ts` добавляет props/style-типы и union имени. Manifest declarations bundler modes объявляют типы локально и не импортируют generator package. Manifest содержит mode, URL, target, список и метаданные иконок для debug-инструментов и не импортируется production-компонентом.
|
||||
|
||||
Спрайт остаётся отдельным asset с content hash; SVG path-данные не встраиваются в JavaScript:
|
||||
|
||||
- `react@vite` генерирует статический импорт `sprite.svg?no-inline`, запрещающий Vite inline;
|
||||
- `standalone@vite` использует тот же Vite asset-механизм и экспортирует href helper и нативный Web Component без React;
|
||||
- `standalone@webpack` использует Webpack Asset Modules и экспортирует такой же mode-local Web Component без React;
|
||||
- React Webpack 5 и все Next modes генерируют `new URL('./sprite.svg', import.meta.url).href`, который должен обработать Asset Modules соответствующего сборщика;
|
||||
- кастомный Webpack SVG loader не должен перехватывать generated `sprite.svg`;
|
||||
- в Next mode generated-компонент не содержит `'use client'` и работает в Server Components, SSR и SSG; не добавляй клиентскую границу только ради иконки;
|
||||
- команда сборки Next и mode key должны совпадать: Turbopack с `.../turbopack`, Webpack с `.../webpack`.
|
||||
|
||||
Для bundler modes не перемещай generated sprite в `public` и не переписывай URL вручную. Для bare `standalone` не перемещай managed original: приложение может явно копировать его в deploy output и само отвечает за публичный URL и очистку копии. При смене mode перегенерируй спрайт с новым полным key.
|
||||
@@ -1,87 +0,0 @@
|
||||
## Использование, доступность и цвета
|
||||
|
||||
Имя компонента зависит от `name` конкретного спрайта. В `standalone@vite` и `standalone@webpack` значение `name: 'file-manager'` создаёт tag `<file-manager-icon>` и функцию `defineFileManagerIconElement()`:
|
||||
|
||||
```ts
|
||||
import { defineFileManagerIconElement } from './svg-sprite'
|
||||
|
||||
defineFileManagerIconElement()
|
||||
```
|
||||
|
||||
```html
|
||||
<file-manager-icon icon="folder" aria-hidden="true"></file-manager-icon>
|
||||
```
|
||||
|
||||
Нативный элемент не имеет runtime-зависимостей, сам выбирает generated ID и `viewBox`, получает URL через bundler и рендерит `<svg><use>` в Shadow DOM. Его property `icon` типизирован точным union имён, но строковые HTML attributes проверяются только в runtime. Размер по умолчанию равен `1em × 1em`; меняй его через CSS на host. Bare `standalone` Web Component не генерирует.
|
||||
|
||||
В React/Next.js тот же `name: 'file-manager'` создаёт React-компонент `FileManagerIcon`. Для `name: 'navigation'` используй сгенерированный `NavigationIcon`.
|
||||
|
||||
Импортируй компонент из корня соответствующего каталога спрайта. `width` и `height` не обязательны: размером можно управлять обычным CSS-классом.
|
||||
|
||||
```tsx
|
||||
import { FileManagerIcon } from './svg-sprite'
|
||||
|
||||
export const OpenButton = () => (
|
||||
<button type="button">
|
||||
<FileManagerIcon icon="folder" className="icon" aria-hidden="true" />
|
||||
<span>Открыть</span>
|
||||
</button>
|
||||
)
|
||||
```
|
||||
|
||||
```css
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: #4b5563;
|
||||
}
|
||||
```
|
||||
|
||||
`icon` принимает точные имена исходных файлов без `.svg`; неизвестное имя является ошибкой TypeScript. Для небезопасных SVG ID имён генератор хранит публичное имя, но создаёт внутренний стабильный hash ID, поэтому не собирай fragment URL из имени вручную.
|
||||
|
||||
По умолчанию компонент рендерит `<svg>` и принимает стандартные SVG attributes: необязательные `width`/`height`, `className`, `style`, `role`, `aria-*` и обработчики. С `wrapped={true}` корнем становится `<span>`, props относятся к span, а внутренний SVG занимает размер wrapper. Это удобно, когда размер и цвета полностью задаются классом:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon
|
||||
icon="check"
|
||||
wrapped
|
||||
className="statusIcon"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
```
|
||||
|
||||
```css
|
||||
.statusIcon {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
color: currentColor;
|
||||
--icon-color-1: #4b5563;
|
||||
--icon-color-2: #14b8a6;
|
||||
}
|
||||
```
|
||||
|
||||
Generated-компонент не выбирает семантику за приложение и не добавляет `title`. Для декоративной иконки передай `aria-hidden="true"`; для самостоятельной смысловой иконки передай `role="img"` и доступное имя через `aria-label`. Не дублируй имя, если соседний текст уже озвучивает действие. Интерактивность размещай на `button` или `a`, а не на самой иконке.
|
||||
|
||||
Трансформации `removeSize`, `replaceColors` и `addTransition` включены по умолчанию. Для монохромной иконки единственный цвет получает fallback `currentColor`, поэтому управляй CSS-свойством `color`. Для многоцветной передавай типизированные custom properties:
|
||||
|
||||
```tsx
|
||||
<FileManagerIcon
|
||||
icon="folder"
|
||||
wrapped
|
||||
className="folderIcon"
|
||||
style={{
|
||||
'--icon-color-1': '#4b5563',
|
||||
'--icon-color-2': '#14b8a6',
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
Автозамена рассчитана на `fill`/`stroke` attributes и inline `style`. Значения `none`, `transparent`, `inherit`, `unset`, `initial` не заменяются. CSS-классы и внешние stylesheets, gradients, patterns, filters и `url(#...)` проверяй на реальном результате. Переменные страницы работают через `<svg><use>`, но не проникают во внешний документ при `<img>` или `background-image`; CSS mask оставляет только одноцветный силуэт.
|
||||
|
||||
`SpriteViewer` необязателен. Установи `@gromlab/svg-sprites` как development dependency, только если проекту нужен Viewer, и подключай его из `@gromlab/svg-sprites/react` на debug-маршруте:
|
||||
|
||||
- в Vite передай результат строкового literal `import.meta.glob('/src/**/svg-sprite/.svg-sprite/svg-sprite.manifest.js')`;
|
||||
- в Webpack передай массив статических `() => import('.../.svg-sprite/svg-sprite.manifest.js')`;
|
||||
- в Next.js используй такие же статические loaders, а для App Router помести Viewer в отдельный файл с `'use client'`.
|
||||
|
||||
Viewer принимает manifests/loaders, показывает поиск, темы, цвета и примеры, но production-компоненты от него не зависят.
|
||||
@@ -1,15 +0,0 @@
|
||||
## Проверка результата
|
||||
|
||||
После изменения конфига или SVG выполни обязательные быстрые проверки:
|
||||
|
||||
1. Запусти точную sprite-команду, например `npm run sprite:file-manager`; процесс должен завершиться с кодом `0` и сообщить имя, число иконок, mode и каталог `.svg-sprite`.
|
||||
2. Проверь наличие `.svg-sprite/index.js`, `.svg-sprite/index.d.ts`, `sprite.svg`, пары `icon-data.js`/`.d.ts`, manifest `.js`/`.d.ts`, `react/react-component.js`, его `.d.ts` и CSS Module.
|
||||
3. Убедись, что новая иконка присутствует в readonly-массиве имён и принимается prop `icon`.
|
||||
4. Запусти существующую проверку типов проекта, например `npm run typecheck`.
|
||||
5. Проверь в `.svg-sprite/svg-sprite.manifest.js`, что `target` совпадает с выбранным mode key; generated asset expression должен быть `?no-inline` для Vite и `new URL(...)` для Webpack/Next.
|
||||
|
||||
Не запускай полную production-сборку только ради проверки изменения списка иконок. Она нужна, если менялся bundler target, конфигурация asset pipeline, Next router/bundler, Webpack loader или диагностируется ошибка URL в runtime.
|
||||
|
||||
Визуальную проверку, Network и accessibility tree выполняй только при наличии запущенного приложения и браузерных инструментов. Если таких инструментов нет, не утверждай, что цвета, темы, доступность или HTTP-ответ asset проверены; явно укажи непроверенную часть.
|
||||
|
||||
`SpriteViewer` также необязателен. Используй его для сложных цветов, transforms и массовой визуальной проверки, но не добавляй debug route ради обычной генерации одного спрайта.
|
||||
@@ -1,24 +0,0 @@
|
||||
## Диагностика
|
||||
|
||||
Сопоставь симптом с проверкой и исправляй первопричину:
|
||||
|
||||
| Симптом | Вероятная причина | Действие |
|
||||
|---|---|---|
|
||||
| `Missing sprite config file or module directory` | Не передан позиционный путь | Передай один config-файл либо каталог для config-less запуска. |
|
||||
| `Expected one config file or module directory` | Передано несколько путей | Создай отдельную команду на каждый спрайт и объедини scripts. |
|
||||
| `Sprite mode is required` | Mode отсутствует и в config, и в CLI | Добавь `mode` в объект или передай полный `--mode`. |
|
||||
| `Unsupported sprite config extension` | Передан файл не `.ts`, `.js` или `.json` | Используй поддерживаемый формат config-файла. |
|
||||
| Positive input-источник не нашёл SVG | Папка отсутствует или пуста, glob не совпал либо точный путь отсутствует или ведёт не к SVG | Разреши источник от каталога конфига и исправь `input`; каждый positive-элемент должен дать хотя бы один SVG. |
|
||||
| Иконки из подпапки не появились | От папки ожидалось рекурсивное сканирование | Используй явный glob, например `./icons/**/*.svg`; папки сканируются плоско. |
|
||||
| Исключённая иконка всё ещё присутствует | У исключения нет префикса `!`, оно находится не в массиве `input` или считается не от того каталога | Добавь совпадающий `!`-элемент и считай его от каталога конфига. |
|
||||
| CLI выбрал не все источники | Несколько источников поместили в одно значение `--input` или пропустили option | Повтори `--input <path-or-glob>` отдельно для каждого источника или исключения. |
|
||||
| Конфликт имени иконки или SVG ID | Два разных файла имеют одинаковый basename либо hash-ID столкнулся с именем | Переименуй один исходный SVG; не выбирай файл неявно. |
|
||||
| `Refusing to overwrite/delete a user file` | Пользовательский файл занял managed-путь или потерял marker | Не обходи защиту: перенеси файл либо выбери другой sprite-каталог и перегенерируй. |
|
||||
| Нет `.svg-sprite/index.js` или имя отсутствует в autocomplete | Генерация не запускалась после изменения, пользовательский barrel не экспортирует `.svg-sprite` либо type server держит старый модуль | Запусти sprite-команду, проверь `export * from './.svg-sprite'`, затем typecheck; при необходимости перезапусти TypeScript server. |
|
||||
| SVG не загружается или URL неверен | Mode не совпадает со сборщиком, неверен Webpack `publicPath` либо кастомный loader перехватил asset | Сверь mode и build-команду, проверь Asset Modules/`publicPath`, исключи generated SVG из несовместимого loader. |
|
||||
| Next build расходится между SSR и браузером | Модуль сгенерирован для другого bundler/router или URL переписан вручную | Верни generated `new URL(...)`, выбери точный Next mode и перегенерируй. |
|
||||
| `color` не меняет многоцветную иконку | У иконки несколько переменных или она показана через `<img>`/CSS background | Используй `<FileManagerIcon>`/`<svg><use>` и нужные `--icon-color-N`. |
|
||||
| Gradient/filter выглядит неверно | Автозамена цветов не гарантирует сложные paint servers | Изучи generated SVG; при необходимости отключи `replaceColors` для спрайта или упрости источник. |
|
||||
| Viewer пуст | Манифесты не созданы, glob/import не статический или неверен Client Component boundary | Сначала сгенерируй спрайты; для Vite используй literal glob, для Webpack/Next статические loaders, для App Router добавь `'use client'` только Viewer-странице. |
|
||||
|
||||
При неизвестной ошибке зафиксируй полную CLI-команду, mode, путь к config-файлу или каталогу и первый stack/error message. Затем минимально воспроизведи проблему на одном спрайте, не удаляя пользовательские файлы и защитные markers.
|
||||
@@ -173,4 +173,4 @@ External stack fragment support и поведение paint servers могут
|
||||
- Ручной fragment не работает для имени с пробелом: используй ID из manifest.
|
||||
- Один сложный icon требует иных transforms: вынеси его в отдельный sprite; per-icon transform config отсутствует.
|
||||
|
||||
Target-specific запуск и проверка описаны в exact-mode файлах каталога [guides](guides/standalone.md).
|
||||
Target-specific запуск и проверка описаны в exact-mode файлах каталога [guides](docs/ru/guides/standalone.md).
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Программный API: операционный reference
|
||||
|
||||
Используй `generateSprite(source, overrides?)` как основной Node.js API.
|
||||
|
||||
## Из config-файла
|
||||
|
||||
```ts
|
||||
import { generateSprite } from '@gromlab/svg-sprites'
|
||||
|
||||
await generateSprite('src/ui/icons/svg-sprite.config.ts')
|
||||
```
|
||||
|
||||
`source` должен указывать на конкретный `.ts`, `.js` или `.json` файл. Имя файла произвольное; генератор не выполняет discovery. Корнем sprite-модуля и базой относительных путей становится каталог этого файла.
|
||||
|
||||
## Без config-файла
|
||||
|
||||
```ts
|
||||
await generateSprite('src/ui/icons', {
|
||||
mode: 'react@vite',
|
||||
name: 'app',
|
||||
input: './icons',
|
||||
})
|
||||
```
|
||||
|
||||
Каталог включает config-less режим. После объединения настроек `mode` обязателен.
|
||||
|
||||
`input?: string | string[]` по умолчанию равен `./icons`. Каждое значение задаёт папку, точный SVG-файл или glob и считается от каталога конфига либо config-less source-каталога. Папка сканируется плоско; рекурсия включается только явным glob, например `./icons/**/*.svg`. Массив объединяет источники, а элементы с префиксом `!` исключают совпадения. Каждый positive-элемент должен разрешаться хотя бы в один SVG. Итоговые файлы дедуплицируются и сортируются, а разные файлы с одинаковым basename вызывают ошибку.
|
||||
|
||||
## Overrides
|
||||
|
||||
```ts
|
||||
await generateSprite('src/ui/icons/custom.json', {
|
||||
mode: 'react@webpack',
|
||||
input: [
|
||||
'../../shared/icons/**/*.svg',
|
||||
'!../../shared/icons/legacy-*.svg',
|
||||
],
|
||||
transform: { addTransition: false },
|
||||
})
|
||||
```
|
||||
|
||||
Порядок: `defaults → config → API overrides`. `transform` объединяется по отдельным полям; переданный `input` заменяет значение из config.
|
||||
|
||||
Специализированные `generateReactSprite` и `generateNextSprite` оставлены как совместимые обёртки, но для нового кода предпочитай `generateSprite`.
|
||||
|
||||
Для загрузки и собственной оркестрации доступны `loadSpriteConfig`, `validateSpriteConfig`, `resolveSpriteConfig`, `compileSpriteContent` и `createShapeTransform`.
|
||||
Reference in New Issue
Block a user