diff --git a/README.md b/README.md index d02c684..0439982 100644 --- a/README.md +++ b/README.md @@ -4,400 +4,261 @@ ![npm](https://img.shields.io/npm/v/@gromlab/svg-sprites) ![license](https://img.shields.io/npm/l/@gromlab/svg-sprites) -A CLI for generating SVG sprites and typed icon components for React and Next.js. +`@gromlab/svg-sprites` is an SVG sprite generator for modern web applications. It combines selected SVG icons into one or more external, cacheable sprites and prepares them for use in the UI. -![Preview](https://raw.githubusercontent.com/gromov-sergei/svg-sprites/master/preview-image.png) +For React and Next.js, the package generates typed components and supports Vite, Webpack 5, and Turbopack. At its core is a standard SVG sprite that can be used without a framework, including in native HTML. -## AI Skills +## An SVG sprite as simple as a regular SVG icon -- [πŸ‡¬πŸ‡§ Download the English skill (latest)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites.zip) -- [πŸ‡·πŸ‡Ί Download the Russian skill (latest)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites-ru.zip) +One typed React component is generated for the entire sprite. Choose an icon with the `icon` prop, and your editor will autocomplete every available name. -## Navigation - -- [AI Skills](#ai-skills) -- [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** - `` 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 + App Router + Turbopack | `next@app/turbopack` | Ready | -| Next.js + App Router + Webpack 5 | `next@app/webpack` | Ready | -| Next.js + Pages Router + Turbopack | `next@pages/turbopack` | Ready | -| Next.js + 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, -}) +```tsx + ``` -| 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 | +The component accepts familiar SVG attributes: dimensions, `color`, `className`, `style`, `aria-*`, and event handlers. If you need an outer container, add `wrapped`. -`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. +```tsx + +``` -`name` is stored in kebab-case and must start with a Latin letter. The React and Next.js presets produce the `stack` format. +You do not have to work with the sprite directly in your application. Use it like a regular SVG icon while benefiting from a single component, autocomplete, and TypeScript validation for every name. -### Next.js +## AI-friendly out of the box -Next.js uses the same `svg-sprite.config.ts` and set of options. For type checking, you can use a dedicated helper: +`@gromlab/svg-sprites` is designed to work with AI agents from the start. Add the ready-made skill and ask an agent to configure, migrate, or troubleshoot the package without lengthy instructions or manual documentation research. + +[πŸ‡¬πŸ‡§ Download AI skill (English)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites.zip) + +[πŸ‡·πŸ‡Ί Download AI skill (Russian)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites-ru.zip) + +## From SVG to component in four steps + +The main example uses the Next.js App Router and Turbopack. + +### 1. Install the package + +```bash +npm install --save-dev @gromlab/svg-sprites +``` + +### 2. Specify the icons you need + +SVG files can remain in your project's existing structure: + +```text +src/ +β”œβ”€β”€ assets/icons/ +β”‚ β”œβ”€β”€ search.svg +β”‚ └── settings.svg +β”œβ”€β”€ features/profile/ +β”‚ └── user.svg +└── ui/app-icons/ + └── svg-sprite.config.ts +``` + +Create the sprite configuration: ```ts +// src/ui/app-icons/svg-sprite.config.ts import { defineNextSpriteConfig } from '@gromlab/svg-sprites' export default defineNextSpriteConfig({ - name: 'file-manager', - description: 'File manager icons', - inputFolder: './icons', + name: 'app', + inputFiles: [ + '../../assets/icons/search.svg', + '../../assets/icons/settings.svg', + '../../features/profile/user.svg', + ], }) ``` -The router and bundler are selected through the mode key, so switching between Turbopack and Webpack is always explicitly reflected in the generation command. +### 3. Add generation -## 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 - -// ^ 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 - // 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 ``, the generator creates a stable hash ID. - -```text -folder open.svg -> icon="folder open" -> id="icon-" -``` - -For such names, use the generated component or the `id` from the debug manifest. The manual examples below using `#` 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 ``, ``, and CSS `background-image`. - -`symbol` is retained for compatibility with existing integrations and supports rendering only through ``. - -## Rendering methods - -### React component - recommended - -The generated component provides type safety and icon name autocomplete, and constructs the SVG asset URL itself. - -```tsx - -``` - -Monochrome and multicolor icons are supported through `color` and `--icon-color-N`. - -### Manually with `` - -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 - - - -``` - -Vite, Webpack 5, and Next.js replace the source path with the final hashed asset URL automatically. - -### With `` - less efficient - -```tsx -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; +```json +{ + "scripts": { + "sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons", + "predev": "npm run sprites", + "prebuild": "npm run sprites" + } } ``` -Like ``, 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. +Run it for the first time: -### With CSS mask - less efficient +```bash +npm run sprites +``` -```css -.icon { - background-color: currentColor; - mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat; +The package will generate `AppIcon`, TypeScript types, and a separate SVG sprite. + +### 4. Use it like a regular icon + +```tsx +import { AppIcon } from '@/ui/app-icons' + +export default function SearchButton() { + return ( + + ) } ``` -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. +This is a Server Component. The icon does not require a provider, `'use client'`, or manual URL construction. -## Transformations +## Typed React component with autocomplete -All transformations are enabled by default and configured independently through `transform`. +Each sprite gets its own ready-to-use component. The `icon` prop is derived from the actual SVG names, so your editor shows the exact list of available icons and TypeScript catches typos immediately. -| Option | Default | What it does | -|---|---|---| -| `removeSize` | `true` | Removes `width` and `height` from the root `` 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)" +```tsx + // available icon + // TypeScript error ``` -The color is controlled by the CSS `color` property of the outer `` or its parent. +After you add a new SVG icon and run generation again, its name automatically appears in the types and autocomplete. There is no need to maintain components, union types, or a name registry manually. -### Multicolor icons +## Next.js App Router and SSR out of the box -Each unique color gets a separate variable with the original fallback: +Generated components work in Server Components, SSR, and SSG without `'use client'`. -```svg -fill="var(--icon-color-1, #798198)" -fill="var(--icon-color-2, #ffffff)" -fill="var(--icon-color-3, #129d9d)" +Using an icon does not turn the page into a Client Component, require a provider, or create an additional hydration boundary. + +The same component can be used in `page.tsx`, `layout.tsx`, and both server and client components. + +## Multiple sprites instead of one global sprite + +Your project is not limited to a single icon set. Create independent sprites for shared elements, individual pages, and large UI modules. + +```tsx + + + ``` -The page can override only the required colors: +Each set gets its own typed component and SVG asset, so application sections do not load icons they do not need. -```css -.icon { - --icon-color-1: #4b5563; - --icon-color-3: #14b8a6; -} -``` +## Store each icon only once -### 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 ``, but are not available inside `` and `background-image`. - -## Caching - -The Vite, Webpack, and Next.js targets emit the sprite as a separate asset with a content hash: +Each SVG icon is stored once in the source library and can be included in any number of sprites. Shared icons do not need to be copied between pages and modules: a single source updates every set. ```text -/assets/sprite-.svg +search.svg ─┬─→ AppIcon + β”œβ”€β†’ AnalyticsIcon + └─→ EditorIcon ``` -This provides the following properties: +Sprites are split for performance, while the source icon library remains unified. -- the SVG is cached independently of JavaScript; -- changes to React code do not alter the sprite contents; -- icon changes produce a new hashed asset; -- one file is used by every instance of the generated component; -- SVG path data is absent from JavaScript chunks. +## Browser caching -The Vite target prevents inlining through `?no-inline`. The Webpack 5 target uses Asset Modules through `new URL(..., import.meta.url)`. +With a standard Vite, Webpack, or Next.js configuration, each sprite is emitted as a separate versioned SVG file. -## SpriteViewer +As long as the icon set does not change, the browser can reuse its cached copy independently of JavaScript application updates. -`SpriteViewer` is a React component for viewing generated sprites inside an application's debug route. +Changes to React components do not require downloading the geometry of every icon again. -It uses separate manifests and displays: +## JavaScript without SVG bloat -- sprite groups; -- the icon list and count; -- search and the system light/dark theme; -- a preview modal with the `viewBox` and color variable controls; -- React, SVG, IMG, and CSS examples with code copying. +Icon paths remain in external SVG assets and do not add to application chunks. -Production components do not import debug manifests. How you integrate the Viewer depends on the bundler: - -- [React + Vite: automatic `import.meta.glob`](docs/en/react-vite.md#6-add-a-debug-page); -- [React + Webpack 5: static `import()`](docs/en/react-webpack.md#6-add-a-debug-page); -- [Next.js App Router](docs/en/next-app.md#5-add-spriteviewer); -- [Next.js Pages Router](docs/en/next-pages.md#5-add-spriteviewer). - -The Viewer is imported from the separate `@gromlab/svg-sprites/react` client entry point and is not included in production icon components. - -### Viewer theme - -By default, `colorTheme="auto"`: the Viewer follows `prefers-color-scheme` and responds to system theme changes. The application theme can be passed explicitly: - -```tsx - +```text +React code β†’ JavaScript chunks +SVG icons β†’ separate SVG assets ``` -Valid `colorTheme` values are `auto`, `light`, and `dark`. When the theme is controlled externally, the built-in switch is hidden. To keep it and update the application theme through the Viewer, pass a callback: +JavaScript handles the interface and behavior, while graphics are loaded and cached separately. + +## Built-in SVG transformations + +During generation, the package automatically prepares source SVG files for use in the UI: + +- removes fixed `width` and `height` attributes; +- preserves the existing `viewBox`; +- converts `fill` and `stroke` values to CSS variables; +- adds smooth transitions directly to colored icon elements. + +Each transformation can be configured or disabled independently. + +## Control every color with CSS + +During generation, `fill` and `stroke` colors are automatically converted to `--icon-color-N` CSS variables. + +A monochrome icon inherits `currentColor`: ```tsx - +``` + +For a multicolor icon, each color can be changed independently: + +```tsx + ``` +Create themes, states, and hover effects without editing the SVG or making additional copies of the icon. + +## SpriteViewer: every sprite on one debug page + +`SpriteViewer` renders all project sprites in one place and shows which icons are included in each set and how they look. + +For each icon, you can see the generated CSS variables and their fallback colors. Change the values directly in the Viewer and see the result immediately. + +It also provides ready-to-use integration examples for: + +- React; +- ``; +- ``; +- CSS. + +![SpriteViewer](https://raw.githubusercontent.com/gromov-sergei/svg-sprites/master/preview-image.png) + +The Viewer is added only to an internal debug page and does not become part of the generated icon components. + +## From native HTML to Next.js + +At its core is a standard SVG sprite that can be used even without a framework or bundler. + +For React and Next.js, the package generates typed components and supports Vite, Webpack 5, and Turbopack. The list of ready-made integrations will expand to include new frameworks. + +## Clean Git history + +The generator creates a local `.gitignore` that excludes generated files and keeps them from cluttering project history, pull requests, and the codebase. + +The repository contains the source SVG files, configuration, and `.gitignore` rule, while sprites, components, and types are regenerated locally and in CI through `prebuild`. + +## Only icons in production + +`@gromlab/svg-sprites` does its main work during generation and remains in `devDependencies`. + +Production components use only local generated code, styles, and the external SVG file. The compiler and CLI are not bundled into the client application, while `SpriteViewer` is imported separately only where a debug page is needed. + ## Documentation -- [React + Vite](docs/en/react-vite.md) -- [React + Webpack 5](docs/en/react-webpack.md) +This README introduces the project's capabilities and demonstrates the primary use case. For setup, choose the guide for your stack. + +### Quick start + - [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) +- [React + Vite](docs/en/react-vite.md) +- [React + Webpack 5](docs/en/react-webpack.md) +- [Native HTML and classic SVG sprites](docs/en/legacy.md) + +### Technical resources + +- [Technical reference](docs/en/reference.md) - [Programmatic API](docs/en/programmatic-api.md) +- [Migrating from 0.1.x](docs/en/migration-1.md) ## License diff --git a/README_RU.md b/README_RU.md index 704c647..e4cd95c 100644 --- a/README_RU.md +++ b/README_RU.md @@ -4,400 +4,261 @@ ![npm](https://img.shields.io/npm/v/@gromlab/svg-sprites) ![license](https://img.shields.io/npm/l/@gromlab/svg-sprites) -CLI для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ SVG-спрайтов ΠΈ Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈΠΊΠΎΠ½ΠΎΠΊ для React ΠΈ Next.js. +`@gromlab/svg-sprites` β€” Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ SVG-спрайтов для соврСмСнных Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ. Он собираСт Π²Ρ‹Π±Ρ€Π°Π½Π½Ρ‹Π΅ SVG-ΠΈΠΊΠΎΠ½ΠΊΠΈ Π² ΠΎΠ΄ΠΈΠ½ ΠΈΠ»ΠΈ нСсколько Π²Π½Π΅ΡˆΠ½ΠΈΡ… ΠΊΠ΅ΡˆΠΈΡ€ΡƒΠ΅ΠΌΡ‹Ρ… спрайтов ΠΈ ΠΏΠΎΠ΄Π³ΠΎΡ‚Π°Π²Π»ΠΈΠ²Π°Π΅Ρ‚ ΠΈΡ… для использования Π² интСрфСйсС. -![Preview](https://raw.githubusercontent.com/gromov-sergei/svg-sprites/master/preview-image.png) +Для React ΠΈ Next.js ΠΏΠ°ΠΊΠ΅Ρ‚ создаёт Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Vite, Webpack 5 ΠΈ Turbopack. Π’ основС ΠΏΡ€ΠΈ этом остаётся ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ SVG-спрайт, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π±Π΅Π· Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠ°, Π² Ρ‚ΠΎΠΌ числС Π² Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠΌ HTML. -## AI-скиллы +## SVG-спрайт Ρ‚Π°ΠΊ ΠΆΠ΅ прост, ΠΊΠ°ΠΊ обычная SVG-ΠΈΠΊΠΎΠ½ΠΊΠ° -- [πŸ‡¬πŸ‡§ Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ английский скилл (послСдняя вСрсия)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites.zip) -- [πŸ‡·πŸ‡Ί Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ русский скилл (послСдняя вСрсия)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites-ru.zip) +Для всСго спрайта гСнСрируСтся ΠΎΠ΄ΠΈΠ½ Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚. Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΈΠΊΠΎΠ½ΠΊΡƒ Ρ‡Π΅Ρ€Π΅Π· `icon`, Π° Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€ ΠΏΠΎΠΊΠ°ΠΆΠ΅Ρ‚ Π°Π²Ρ‚ΠΎΠΊΠΎΠΌΠΏΠ»ΠΈΡ‚ всСх доступных ΠΈΠΌΡ‘Π½. -## Навигация - -- [AI-скиллы](#ai-скиллы) -- [ВозмоТности](#возмоТности) -- [Π’Π°Π±Π»ΠΈΡ†Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ](#Ρ‚Π°Π±Π»ΠΈΡ†Π°-ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ) -- [ВрСбования](#трСбования) -- [Быстрый старт](#быстрый-старт) - - [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` ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‚ΡΡ Π² ΠΎΠ΄ΠΈΠ½ спрайт; ΠΎΠ΄ΠΈΠ½ Ρ„Π°ΠΉΠ» ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… спрайтах. -- **ВстроСнноС ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠ΅ ΠΏΡ€Π΅Π²ΡŒΡŽ** β€” `` ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ ΠΊΠ°ΠΊ страница прилоТСния ΠΈ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹Π΅ 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 + 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` | Π“ΠΎΡ‚ΠΎΠ²ΠΎ | -| 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, -}) +```tsx + ``` -| ΠžΠΏΡ†ΠΈΡ | Π’ΠΈΠΏ | По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ | НазначСниС | -|---|---|---|---| -| `name` | `string` | Имя ΠΏΠ°ΠΏΠΊΠΈ | Имя спрайта, ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΈ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² | -| `description` | `string` | НСт | ОписаниС для Ρ‚ΠΈΠΏΠΎΠ² ΠΈ debug-манифСста | -| `inputFolder` | `string` | `./icons` | Папка с исходными SVG ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° | -| `inputFiles` | `string[]` | `[]` | Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ SVG-Ρ„Π°ΠΉΠ»Ρ‹ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° | -| `transform` | `TransformOptions` | ВсС Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ | [Настройки трансформации](#трансформации) исходных SVG | -| `generatedNotice` | `boolean` | `true` | ПолноС Π»ΠΈΠ±ΠΎ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΎΠ΅ ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅ Π² generated-Ρ„Π°ΠΉΠ»Π°Ρ… | +ΠšΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΠΏΡ€ΠΈΠ²Ρ‹Ρ‡Π½Ρ‹Π΅ SVG-Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρ‹: Ρ€Π°Π·ΠΌΠ΅Ρ€Ρ‹, `color`, `className`, `style`, `aria-*` ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ событий. Если Π½ΡƒΠΆΠ΅Π½ внСшний ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€, Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ `wrapped`. -`inputFolder` ΠΈ `inputFiles` ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‚ΡΡ Π² ΠΎΠ΄ΠΈΠ½ спрайт, поэтому ΠΎΠ΄ΠΈΠ½ SVG-Ρ„Π°ΠΉΠ» ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… спрайтах Π±Π΅Π· копирования. Если нСявной ΠΏΠ°ΠΏΠΊΠΈ `./icons` Π½Π΅Ρ‚, Π½ΠΎ `inputFiles` Π·Π°ΠΏΠΎΠ»Π½Π΅Π½, гСнСрация продолТаСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎ списку. Π―Π²Π½ΠΎ указанная ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π°Ρ ΠΏΠ°ΠΏΠΊΠ° считаСтся ошибкой. ΠžΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Π΅ ΠΏΡƒΡ‚ΠΈ Π΄Π΅Π΄ΡƒΠΏΠ»ΠΈΡ†ΠΈΡ€ΡƒΡŽΡ‚ΡΡ, Π° Ρ€Π°Π·Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ с ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ ΠΈΠΊΠΎΠ½ΠΊΠΈ ΡΡ‡ΠΈΡ‚Π°ΡŽΡ‚ΡΡ ошибкой. +```tsx + +``` -`name` записываСтся Π² kebab-case ΠΈ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒΡΡ с латинской Π±ΡƒΠΊΠ²Ρ‹. React ΠΈ Next.js presets ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ `stack`. +Π’ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ Π½Π΅ приходится Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ со спрайтом Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ. Π’Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ Π΅Π³ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΡƒΡŽ SVG-ΠΈΠΊΠΎΠ½ΠΊΡƒ, Π½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚Π΅ ΠΎΠ΄ΠΈΠ½ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚, Π°Π²Ρ‚ΠΎΠΊΠΎΠΌΠΏΠ»ΠΈΡ‚ ΠΈ TypeScript-ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ всСх ΠΈΠΌΡ‘Π½. -### Next.js +## AI-friendly ΠΈΠ· ΠΊΠΎΡ€ΠΎΠ±ΠΊΠΈ -Next.js ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ‚ΠΎΡ‚ ΠΆΠ΅ `svg-sprite.config.ts` ΠΈ Π½Π°Π±ΠΎΡ€ ΠΎΠΏΡ†ΠΈΠΉ. Для Ρ‚ΠΈΠΏΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ…Π΅Π»ΠΏΠ΅Ρ€: +`@gromlab/svg-sprites` сразу рассчитан Π½Π° Ρ€Π°Π±ΠΎΡ‚Ρƒ с AI-Π°Π³Π΅Π½Ρ‚Π°ΠΌΠΈ. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΉ skill ΠΈ ΠΏΠΎΡ€ΡƒΡ‡ΠΈΡ‚Π΅ Π°Π³Π΅Π½Ρ‚Ρƒ настройку, ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ ΠΈΠ»ΠΈ диагностику Π±Π΅Π· Π΄Π»ΠΈΠ½Π½Ρ‹Ρ… инструкций ΠΈ Ρ€ΡƒΡ‡Π½ΠΎΠ³ΠΎ изучСния Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ. + +[πŸ‡·πŸ‡Ί Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ AI skill (Π½Π° русском)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites-ru.zip) + +[πŸ‡¬πŸ‡§ Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ AI skill (Π½Π° английском)](https://github.com/gromov-sergei/svg-sprites/releases/latest/download/svg-sprites.zip) + +## ΠžΡ‚ SVG Π΄ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Π·Π° Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ шага + +Основной ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Next.js App Router ΠΈ Turbopack. + +### 1. УстановитС ΠΏΠ°ΠΊΠ΅Ρ‚ + +```bash +npm install --save-dev @gromlab/svg-sprites +``` + +### 2. Π£ΠΊΠ°ΠΆΠΈΡ‚Π΅ Π½ΡƒΠΆΠ½Ρ‹Π΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ + +SVG ΠΌΠΎΠ³ΡƒΡ‚ ΠΎΡΡ‚Π°Π²Π°Ρ‚ΡŒΡΡ Π² ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅ΠΉ структурС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°: + +```text +src/ +β”œβ”€β”€ assets/icons/ +β”‚ β”œβ”€β”€ search.svg +β”‚ └── settings.svg +β”œβ”€β”€ features/profile/ +β”‚ └── user.svg +└── ui/app-icons/ + └── svg-sprite.config.ts +``` + +Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ спрайта: ```ts +// src/ui/app-icons/svg-sprite.config.ts import { defineNextSpriteConfig } from '@gromlab/svg-sprites' export default defineNextSpriteConfig({ - name: 'file-manager', - description: 'Иконки Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠ³ΠΎ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π°', - inputFolder: './icons', + name: 'app', + inputFiles: [ + '../../assets/icons/search.svg', + '../../assets/icons/settings.svg', + '../../features/profile/user.svg', + ], }) ``` -Π ΠΎΡƒΡ‚Π΅Ρ€ ΠΈ сборщик Π²Ρ‹Π±ΠΈΡ€Π°ΡŽΡ‚ΡΡ Ρ‡Π΅Ρ€Π΅Π· mode key, поэтому ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρƒ Turbopack ΠΈ Webpack всСгда явно ΠΎΡ‚Ρ€Π°ΠΆΠ΅Π½ΠΎ Π² ΠΊΠΎΠΌΠ°Π½Π΄Π΅ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ. +### 3. Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ -## ΠœΠ½ΠΎΠΆΠ΅ΡΡ‚Π²Π΅Π½Π½Ρ‹Π΅ спрайты - -ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ нСсколько нСзависимых спрайтов с Ρ€Π°Π·Π½ΠΎΠΉ ΠΎΠ±Π»Π°ΡΡ‚ΡŒΡŽ использования: - -**ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΠ°:** ΠΎΠ΄ΠΈΠ½ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹ΠΉ спрайт Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ ΠΈΠΊΠΎΠ½ΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌΡƒ экрану Π½Π΅ Π½ΡƒΠΆΠ½Ρ‹. - -**РСшСниС:** ΠΎΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ глобально, Π° Π½Π°Π±ΠΎΡ€Ρ‹ страниц ΠΈ ΠΊΡ€ΡƒΠΏΠ½Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² β€” Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… спрайтах, Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Ρ… вмСстС с Π½ΠΈΠΌΠΈ. - -```text -global β†’ GlobalIcon β†’ ΠΎΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ прилоТСния -analytics-page β†’ AnalyticsPageIcon β†’ ΠΈΠΊΠΎΠ½ΠΊΠΈ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ страницы -file-manager β†’ FileManagerIcon β†’ ΠΈΠΊΠΎΠ½ΠΊΠΈ ΠΊΡ€ΡƒΠΏΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° -``` - -- **Π“Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹ΠΉ спрайт** содСрТит нСбольшиС ΠΎΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ Π² Ρ€Π°Π·Π½Ρ‹Ρ… частях прилоТСния: Π½Π°Π²ΠΈΠ³Π°Ρ†ΠΈΡŽ, состояния ΠΈ Π±Π°Π·ΠΎΠ²Ρ‹Π΅ дСйствия. -- **Π‘ΠΏΡ€Π°ΠΉΡ‚ страницы** загруТаСтся вмСстС с ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΌ Ρ€Π°Π·Π΄Π΅Π»ΠΎΠΌ ΠΈ Π½Π΅ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ ΠΎΠ±Ρ‰ΠΈΠΉ спрайт ΠΈΠΊΠΎΠ½ΠΊΠ°ΠΌΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ большС Π½ΠΈΠ³Π΄Π΅ Π½Π΅ Π½ΡƒΠΆΠ½Ρ‹. -- **Π‘ΠΏΡ€Π°ΠΉΡ‚ ΠΊΡ€ΡƒΠΏΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°** инкапсулируСт собствСнный Π½Π°Π±ΠΎΡ€ ΠΈΠΊΠΎΠ½ΠΎΠΊ слоТного UI-модуля, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠ³ΠΎ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° ΠΈΠ»ΠΈ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€Π°. - -КаТдая Π³Ρ€ΡƒΠΏΠΏΠ° ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚: - -- собствСнный SVG asset; -- собствСнный Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚; -- ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ список ΠΈΠΌΡ‘Π½ ΠΈΠΊΠΎΠ½ΠΎΠΊ; -- ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ debug-манифСст; -- нСзависимый cache lifecycle. - - -## TypeScript - -Главная Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ TypeScript API β€” Π°Π²Ρ‚ΠΎΠ΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΈΠΌΡ‘Π½ ΠΈΠΊΠΎΠ½ΠΎΠΊ нСпосрСдствСнно Π² prop `icon`: - -```tsx - -// ↑ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€ ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅Ρ‚ всС ΠΈΠΊΠΎΠ½ΠΊΠΈ спрайта -``` - -ИмСна SVG-Ρ„Π°ΠΉΠ»ΠΎΠ² становятся допустимыми значСниями `icon`. ΠžΠΏΠ΅Ρ‡Π°Ρ‚ΠΊΠ° ΠΈΠ»ΠΈ нСизвСстноС имя сразу становятся ошибкой TypeScript: - -```tsx - // ошибка TypeScript -``` - -Для ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½ΠΎΠ³ΠΎ доступа generated-ΠΌΠΎΠ΄ΡƒΠ»ΡŒ экспортируСт readonly-массив всСх доступных ΠΈΠΊΠΎΠ½ΠΎΠΊ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ спрайта: - -```ts -import { fileManagerIconNames } from './svg-sprite' - -// readonly ['check', 'folder', ...] -``` - -Π­Ρ‚ΠΎΡ‚ список ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² собствСнных ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π°Ρ…, select-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°Ρ…, тСстах ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ… runtime-сцСнариях. Из Π½Π΅Π³ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ выводится union-Ρ‚ΠΈΠΏ `FileManagerIconName`. - -ИмСна Ρ„Π°ΠΉΠ»ΠΎΠ² с ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ нСбСзопасными для SVG ID символами ΠΎΡΡ‚Π°ΡŽΡ‚ΡΡ Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠ³ΠΎ TypeScript API. Для Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ `` Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ создаёт ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ hash ID. - -```text -folder open.svg β†’ icon="folder open" β†’ id="icon-" -``` - -Для Ρ‚Π°ΠΊΠΈΡ… ΠΈΠΌΡ‘Π½ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈΠ»ΠΈ `id` ΠΈΠ· debug-манифСста. Π ΡƒΡ‡Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π½ΠΈΠΆΠ΅ с `#<имя>` подходят Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΈΠΌΡ‘Π½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΠΆΠ΅ ΡΠ²Π»ΡΡŽΡ‚ΡΡ бСзопасными SVG ID. - -## Π€ΠΎΡ€ΠΌΠ°Ρ‚Ρ‹ спрайтов - -`stack` β€” Π±ΠΎΠ»Π΅Π΅ соврСмСнный Ρ„ΠΎΡ€ΠΌΠ°Ρ‚, поэтому ΠΎΠ½ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. Иконки ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· ``, `` ΠΈ CSS `background-image`. - -`symbol` сохраняСтся для совмСстимости с ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌΠΈ интСграциями ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Π΅Ρ€Π΅Π· ``. - -## Бпособы отобраТСния - -### React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ β€” рСкомСндуСтся - -Generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ прСдоставляСт Ρ‚ΠΈΠΏΠΈΠ·Π°Ρ†ΠΈΡŽ, Π°Π²Ρ‚ΠΎΠ΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΈΠΌΡ‘Π½ ΠΈΠΊΠΎΠ½ΠΎΠΊ ΠΈ сам Ρ„ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅Ρ‚ URL SVG asset. - -```tsx - -``` - -Π§Π΅Ρ€Π΅Π· `color` ΠΈ `--icon-color-N` доступны ΠΎΠ΄Π½ΠΎΡ†Π²Π΅Ρ‚Π½Ρ‹Π΅ ΠΈ ΠΌΠ½ΠΎΠ³ΠΎΡ†Π²Π΅Ρ‚Π½Ρ‹Π΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ. - -### Π‘Π°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ‡Π΅Ρ€Π΅Π· `` - -Π₯ΠΎΡ€ΠΎΡˆΠΈΠΉ Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²Ρ‹ΠΉ способ с ΠΏΠΎΠ»Π½Ρ‹ΠΌ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€Π°ΠΌΠΈ ΠΈ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ. 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 - - - -``` - -Vite, Webpack 5 ΠΈ Next.js сами Π·Π°ΠΌΠ΅Π½ΡΡŽΡ‚ исходный ΠΏΡƒΡ‚ΡŒ Π½Π° ΠΈΡ‚ΠΎΠ³ΠΎΠ²Ρ‹ΠΉ URL asset с hash. - -### Π§Π΅Ρ€Π΅Π· `` β€” ΠΌΠ΅Π½Π΅Π΅ эффСктивно - -```tsx -Π“ΠΎΡ‚ΠΎΠ²ΠΎ -``` - -SVG загруТаСтся ΠΊΠ°ΠΊ ΠΈΠ·ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅: ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Ρ†Π²Π΅Ρ‚Π° Ρ‡Π΅Ρ€Π΅Π· `color` ΠΈΠ»ΠΈ `--icon-color-N` нСльзя. - -### Π§Π΅Ρ€Π΅Π· CSS `background-image` β€” ΠΌΠ΅Π½Π΅Π΅ эффСктивно - -```css -.icon { - background: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat; +```json +{ + "scripts": { + "sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons", + "predev": "npm run sprites", + "prebuild": "npm run sprites" + } } ``` -Как ΠΈ ``, этот способ Π½Π΅ позволяСт ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΌΠΈ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ SVG. ΠŸΡƒΡ‚ΡŒ указываСтся ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ CSS-Ρ„Π°ΠΉΠ»Π°, Π° Vite/Webpack замСняСт Π΅Π³ΠΎ Π½Π° ΠΈΡ‚ΠΎΠ³ΠΎΠ²Ρ‹ΠΉ URL с hash ΠΏΡ€ΠΈ сборкС. +ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ запуск: -### Π§Π΅Ρ€Π΅Π· CSS mask β€” ΠΌΠ΅Π½Π΅Π΅ эффСктивно +```bash +npm run sprites +``` -```css -.icon { - background-color: currentColor; - mask: url('./svg-sprite/generated/sprite.svg#check') center / contain no-repeat; +ΠŸΠ°ΠΊΠ΅Ρ‚ создаст `AppIcon`, TypeScript-Ρ‚ΠΈΠΏΡ‹ ΠΈ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ SVG-спрайт. + +### 4. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΡƒΡŽ ΠΈΠΊΠΎΠ½ΠΊΡƒ + +```tsx +import { AppIcon } from '@/ui/app-icons' + +export default function SearchButton() { + return ( + + ) } ``` -Mask оставляСт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ силуэт ΠΈ ΠΎΠΊΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ Π΅Π³ΠΎ ΠΎΠ΄Π½ΠΈΠΌ Ρ†Π²Π΅Ρ‚ΠΎΠΌ. Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹Π΅ Ρ†Π²Π΅Ρ‚Π°, gradients ΠΈ различия ΠΌΠ΅ΠΆΠ΄Ρƒ `fill` ΠΈ `stroke` Ρ‚Π΅Ρ€ΡΡŽΡ‚ΡΡ. +Π­Ρ‚ΠΎ Server Component. Для ΠΈΠΊΠΎΠ½ΠΊΠΈ Π½Π΅ Π½ΡƒΠΆΠ½Ρ‹ provider, `'use client'` ΠΈΠ»ΠΈ ручная сборка URL. -## Врансформации +## Π’ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ с Π°Π²Ρ‚ΠΎΠΊΠΎΠΌΠΏΠ»ΠΈΡ‚ΠΎΠΌ -ВсС трансформации Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΈ Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°ΡŽΡ‚ΡΡ нСзависимо Ρ‡Π΅Ρ€Π΅Π· `transform`. +ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ спрайт ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ собствСнный Π³ΠΎΡ‚ΠΎΠ²Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚. Бвойство `icon` формируСтся ΠΈΠ· Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΈΠΌΡ‘Π½ SVG, поэтому Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Ρ‚ΠΎΡ‡Π½Ρ‹ΠΉ список доступных ΠΈΠΊΠΎΠ½ΠΎΠΊ, Π° TypeScript сразу ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ²Π°Π΅Ρ‚ ΠΎΠΏΠ΅Ρ‡Π°Ρ‚ΠΊΠΈ. -| ΠžΠΏΡ†ΠΈΡ | По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ | Π§Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ | -|---|---|---| -| `removeSize` | `true` | УдаляСт `width` ΠΈ `height` с ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠ³ΠΎ ``, сохраняя ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ `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)" +```tsx + // доступная ΠΈΠΊΠΎΠ½ΠΊΠ° + // ошибка TypeScript ``` -Π¦Π²Π΅Ρ‚ΠΎΠΌ управляСт CSS-свойство `color` внСшнСго `` ΠΈΠ»ΠΈ Π΅Π³ΠΎ родитСля. +ПослС добавлСния Π½ΠΎΠ²ΠΎΠΉ SVG-ΠΈΠΊΠΎΠ½ΠΊΠΈ ΠΈ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠΉ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ Π΅Ρ‘ имя автоматичСски появляСтся Π² Ρ‚ΠΈΠΏΠ°Ρ… ΠΈ Π°Π²Ρ‚ΠΎΠΊΠΎΠΌΠΏΠ»ΠΈΡ‚Π΅. НС Π½ΡƒΠΆΠ½ΠΎ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹, union-Ρ‚ΠΈΠΏΡ‹ ΠΈΠ»ΠΈ рССстр ΠΈΠΌΡ‘Π½. -### ΠœΠ½ΠΎΠ³ΠΎΡ†Π²Π΅Ρ‚Π½Ρ‹Π΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ +## Next.js App Router ΠΈ SSR ΠΈΠ· ΠΊΠΎΡ€ΠΎΠ±ΠΊΠΈ -ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ†Π²Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ с исходным fallback: +Generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π² Server Components, SSR ΠΈ SSG Π±Π΅Π· `'use client'`. -```svg -fill="var(--icon-color-1, #798198)" -fill="var(--icon-color-2, #ffffff)" -fill="var(--icon-color-3, #129d9d)" +ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ Π½Π΅ пСрСносит страницу Π½Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚, Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ provider ΠΈ Π½Π΅ создаёт Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ Π³Ρ€Π°Π½ΠΈΡ†Ρƒ Π³ΠΈΠ΄Ρ€Π°Ρ‚Π°Ρ†ΠΈΠΈ. + +Один ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² `page.tsx`, `layout.tsx`, сСрвСрных ΠΈ клиСнтских ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°Ρ…. + +## ΠœΠ½ΠΎΠΆΠ΅ΡΡ‚Π²Π΅Π½Π½Ρ‹Π΅ спрайты вмСсто ΠΎΠ΄Π½ΠΎΠ³ΠΎ глобального + +ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ Π½Π΅ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ ΠΎΠ΄Π½ΠΈΠΌ Π½Π°Π±ΠΎΡ€ΠΎΠΌ ΠΈΠΊΠΎΠ½ΠΎΠΊ. Π‘ΠΎΠ·Π΄Π°Π²Π°ΠΉΡ‚Π΅ нСзависимыС спрайты для ΠΎΠ±Ρ‰ΠΈΡ… элСмСнтов, ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… страниц ΠΈ ΠΊΡ€ΡƒΠΏΠ½Ρ‹Ρ… UI-ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ. + +```tsx + + + ``` -Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Ρ†Π²Π΅Ρ‚Π°: +ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ собствСнный Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈ SVG asset, поэтому Ρ€Π°Π·Π΄Π΅Π»Ρ‹ прилоТСния Π½Π΅ нСсут ΠΈΠΊΠΎΠ½ΠΊΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌ Π½Π΅ Π½ΡƒΠΆΠ½Ρ‹. -```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-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ страницы доступны ΠΏΡ€ΠΈ ``, Π½ΠΎ нСдоступны Π²Π½ΡƒΡ‚Ρ€ΠΈ `` ΠΈ `background-image`. - -## ΠšΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ - -Vite, Webpack ΠΈ Next.js target Π²Ρ‹ΠΏΡƒΡΠΊΠ°ΡŽΡ‚ спрайт ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌ asset с content hash: +Π’ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ исходников каТдая SVG-ΠΈΠΊΠΎΠ½ΠΊΠ° хранится Π² ΠΎΠ΄Π½ΠΎΠΌ экзСмплярС ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π² любоС количСство спрайтов. ΠžΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ Π½Π΅ приходится ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅ΠΆΠ΄Ρƒ страницами ΠΈ модулями: ΠΎΠ½ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡŽΡ‚ΡΡ для всСх Π½Π°Π±ΠΎΡ€ΠΎΠ² ΠΈΠ· ΠΎΠ΄Π½ΠΎΠ³ΠΎ мСста. ```text -/assets/sprite-.svg +search.svg ─┬─→ AppIcon + β”œβ”€β†’ AnalyticsIcon + └─→ EditorIcon ``` -Π­Ρ‚ΠΎ Π΄Π°Ρ‘Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ свойства: +Π‘ΠΏΡ€Π°ΠΉΡ‚Ρ‹ Ρ€Π°Π·Π΄Π΅Π»ΡΡŽΡ‚ΡΡ Ρ€Π°Π΄ΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, Π½ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° исходных ΠΈΠΊΠΎΠ½ΠΎΠΊ остаётся Π΅Π΄ΠΈΠ½ΠΎΠΉ. -- SVG ΠΊΠ΅ΡˆΠΈΡ€ΡƒΠ΅Ρ‚ΡΡ нСзависимо ΠΎΡ‚ JavaScript; -- ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ React-ΠΊΠΎΠ΄Π° Π½Π΅ мСняСт содСрТимоС спрайта; -- ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΎΠΊ создаёт Π½ΠΎΠ²Ρ‹ΠΉ hash asset; -- ΠΎΠ΄ΠΈΠ½ Ρ„Π°ΠΉΠ» ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ всСми экзСмплярами generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°; -- SVG path-Π΄Π°Π½Π½Ρ‹Π΅ ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚ Π² JavaScript chunks. +## Π‘Ρ€Π°ΡƒΠ·Π΅Ρ€Π½ΠΎΠ΅ ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ -Vite target Π·Π°ΠΏΡ€Π΅Ρ‰Π°Π΅Ρ‚ inline Ρ‡Π΅Ρ€Π΅Π· `?no-inline`. Webpack 5 target ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Asset Modules Ρ‡Π΅Ρ€Π΅Π· `new URL(..., import.meta.url)`. +ΠŸΡ€ΠΈ стандартной ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Vite, Webpack ΠΈΠ»ΠΈ Next.js ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ спрайт выпускаСтся ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌ вСрсионированным SVG-Ρ„Π°ΠΉΠ»ΠΎΠΌ. -## SpriteViewer +Пока Π½Π°Π±ΠΎΡ€ ΠΈΠΊΠΎΠ½ΠΎΠΊ Π½Π΅ мСняСтся, Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΎΡ…Ρ€Π°Π½Ρ‘Π½Π½ΡƒΡŽ копию нСзависимо ΠΎΡ‚ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ JavaScript прилоТСния. -`SpriteViewer` β€” React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ для просмотра generated-спрайтов Π²Π½ΡƒΡ‚Ρ€ΠΈ debug-ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Π° прилоТСния. +ИзмСнСниС React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π³Π΅ΠΎΠΌΠ΅Ρ‚Ρ€ΠΈΡŽ всСх ΠΈΠΊΠΎΠ½ΠΎΠΊ. -Он ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ манифСсты ΠΈ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚: +## JavaScript Π±Π΅Π· SVG-балласта -- Π³Ρ€ΡƒΠΏΠΏΡ‹ спрайтов; -- список ΠΈ количСство ΠΈΠΊΠΎΠ½ΠΎΠΊ; -- поиск ΠΈ ΡΠΈΡΡ‚Π΅ΠΌΠ½ΡƒΡŽ ΡΠ²Π΅Ρ‚Π»ΡƒΡŽ/Ρ‚Ρ‘ΠΌΠ½ΡƒΡŽ Ρ‚Π΅ΠΌΡƒ; -- модальноС ΠΏΡ€Π΅Π²ΡŒΡŽ с `viewBox` ΠΈ настройкой Ρ†Π²Π΅Ρ‚ΠΎΠ²Ρ‹Ρ… ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ…; -- ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ React, SVG, IMG ΠΈ CSS с ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΠΊΠΎΠ΄Π°. +ΠšΠΎΠ½Ρ‚ΡƒΡ€Ρ‹ ΠΈΠΊΠΎΠ½ΠΎΠΊ ΠΎΡΡ‚Π°ΡŽΡ‚ΡΡ Π²ΠΎ Π²Π½Π΅ΡˆΠ½ΠΈΡ… SVG assets ΠΈ Π½Π΅ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°ΡŽΡ‚ chunks прилоТСния. -Production-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Π½Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΡŽΡ‚ debug-манифСсты. Бпособ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Viewer зависит ΠΎΡ‚ сборщика: - -- [React + Vite: автоматичСский `import.meta.glob`](docs/ru/react-vite.md#6-Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅-debug-страницу); -- [React + Webpack 5: статичСскиС `import()`](docs/ru/react-webpack.md#6-Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅-debug-страницу); -- [Next.js App Router](docs/ru/next-app.md#5-Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅-spriteviewer); -- [Next.js Pages Router](docs/ru/next-pages.md#5-Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅-spriteviewer). - -Viewer ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ ΠΈΠ· ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ клиСнтской Ρ‚ΠΎΡ‡ΠΊΠΈ Π²Ρ…ΠΎΠ΄Π° `@gromlab/svg-sprites/react` ΠΈ Π½Π΅ ΠΏΠΎΠΏΠ°Π΄Π°Π΅Ρ‚ Π² production-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈΠΊΠΎΠ½ΠΎΠΊ. - -### Π’Π΅ΠΌΠ° Viewer - -По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ `colorTheme="auto"`: Viewer слСдуСт `prefers-color-scheme` ΠΈ Ρ€Π΅Π°Π³ΠΈΡ€ΡƒΠ΅Ρ‚ Π½Π° смСну систСмной Ρ‚Π΅ΠΌΡ‹. Π’Π΅ΠΌΡƒ прилоТСния ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ явно: - -```tsx - +```text +React-ΠΊΠΎΠ΄ β†’ JavaScript chunks +SVG-ΠΈΠΊΠΎΠ½ΠΊΠΈ β†’ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ SVG assets ``` -ДопустимыС значСния `colorTheme`: `auto`, `light`, `dark`. ΠŸΡ€ΠΈ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΈ Ρ‚Π΅ΠΌΠΎΠΉ ΠΈΠ·Π²Π½Π΅ встроСнный ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚Π΅Π»ΡŒ скрываСтся. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ Ρ‚Π΅ΠΌΡƒ прилоТСния Ρ‡Π΅Ρ€Π΅Π· Viewer, ΠΏΠ΅Ρ€Π΅Π΄Π°ΠΉΡ‚Π΅ callback: +JavaScript ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° интСрфСйс ΠΈ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅, Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ° загруТаСтся ΠΈ ΠΊΠ΅ΡˆΠΈΡ€ΡƒΠ΅Ρ‚ΡΡ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ. + +## Врансформации SVG ΠΈΠ· ΠΊΠΎΡ€ΠΎΠ±ΠΊΠΈ + +Π’ΠΎ врСмя Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚ автоматичСски ΠΏΠΎΠ΄Π³ΠΎΡ‚Π°Π²Π»ΠΈΠ²Π°Π΅Ρ‚ исходныС SVG для интСрфСйса: + +- удаляСт фиксированныС `width` ΠΈ `height`; +- сохраняСт ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ `viewBox`; +- ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ `fill` ΠΈ `stroke` Π² CSS-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅; +- добавляСт ΠΏΠ»Π°Π²Π½Ρ‹Π΅ transitions нСпосрСдствСнно Π² Ρ†Π²Π΅Ρ‚Π½Ρ‹Π΅ элСмСнты ΠΈΠΊΠΎΠ½ΠΊΠΈ. + +ΠšΠ°ΠΆΠ΄ΡƒΡŽ Ρ‚Ρ€Π°Π½ΡΡ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈΠ»ΠΈ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ нСзависимо. + +## ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ†Π²Π΅Ρ‚ ΠΏΠΎΠ΄ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π΅ΠΌ CSS + +ΠŸΡ€ΠΈ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ Ρ†Π²Π΅Ρ‚Π° `fill` ΠΈ `stroke` автоматичСски ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΡŽΡ‚ΡΡ Π² CSS-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ `--icon-color-N`. + +ΠœΠΎΠ½ΠΎΡ…Ρ€ΠΎΠΌΠ½Π°Ρ ΠΈΠΊΠΎΠ½ΠΊΠ° наслСдуСт `currentColor`: ```tsx - +``` + +Π’ ΠΌΠ½ΠΎΠ³ΠΎΡ†Π²Π΅Ρ‚Π½ΠΎΠΉ ΠΈΠΊΠΎΠ½ΠΊΠ΅ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ†Π²Π΅Ρ‚ ΠΌΠΎΠΆΠ½ΠΎ ΠΌΠ΅Π½ΡΡ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ: + +```tsx + ``` +Π’Π΅ΠΌΡ‹, состояния ΠΈ hover-эффСкты ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ Π±Π΅Π· рСдактирования SVG ΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΊΠΎΠΏΠΈΠΉ ΠΈΠΊΠΎΠ½ΠΊΠΈ. + +## SpriteViewer: всС спрайты Π½Π° ΠΎΠ΄Π½ΠΎΠΉ debug-страницС + +`SpriteViewer` Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ всС спрайты ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π² ΠΎΠ΄Π½ΠΎΠΌ мСстС ΠΈ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, ΠΊΠ°ΠΊΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ вошли Π² ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ ΠΈ ΠΊΠ°ΠΊ ΠΎΠ½ΠΈ выглядят. + +Для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΈΠΊΠΎΠ½ΠΊΠΈ Π²ΠΈΠ΄Π½Ρ‹ созданныС CSS-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΈ ΠΈΡ… fallback-Ρ†Π²Π΅Ρ‚Π°. ЗначСния ΠΌΠΎΠΆΠ½ΠΎ ΠΌΠ΅Π½ΡΡ‚ΡŒ прямо Π² Viewer ΠΈ сразу Π½Π°Π±Π»ΡŽΠ΄Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚. + +Π—Π΄Π΅ΡΡŒ ΠΆΠ΅ доступны Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Ρ‡Π΅Ρ€Π΅Π·: + +- React; +- ``; +- ``; +- CSS. + +![SpriteViewer](https://raw.githubusercontent.com/gromov-sergei/svg-sprites/master/preview-image.png) + +Viewer ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΉ debug-страницС ΠΈ Π½Π΅ становится Ρ‡Π°ΡΡ‚ΡŒΡŽ generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈΠΊΠΎΠ½ΠΎΠΊ. + +## ΠžΡ‚ Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ HTML Π΄ΠΎ Next.js + +Π’ основС остаётся ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ SVG-спрайт, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°ΠΆΠ΅ Π±Π΅Π· Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠ° ΠΈ сборщика. + +Для React ΠΈ Next.js ΠΏΠ°ΠΊΠ΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Vite, Webpack 5 ΠΈ Turbopack. Бписок Π³ΠΎΡ‚ΠΎΠ²Ρ‹Ρ… ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°ΡΡˆΠΈΡ€ΡΡ‚ΡŒΡΡ Π½ΠΎΠ²Ρ‹ΠΌΠΈ Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠ°ΠΌΠΈ. + +## Чистый Git + +Π“Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ создаёт Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ `.gitignore`, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ generated-Ρ„Π°ΠΉΠ»Ρ‹ ΠΈ Π½Π΅ позволяСт ΠΈΠΌ Π·Π°ΡΠΎΡ€ΡΡ‚ΡŒ ΠΈΡΡ‚ΠΎΡ€ΠΈΡŽ, pull requests ΠΈ ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. + +Π’ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ ΠΎΡΡ‚Π°ΡŽΡ‚ΡΡ исходныС SVG, конфигурация ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ `.gitignore`, Π° локально ΠΈ Π² CI спрайты, ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ Ρ‚ΠΈΠΏΡ‹ Π·Π°Π½ΠΎΠ²ΠΎ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ΡΡ Ρ‡Π΅Ρ€Π΅Π· `prebuild`. + +## Π’ production Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠΊΠΎΠ½ΠΊΠΈ + +`@gromlab/svg-sprites` выполняСт ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ Ρ€Π°Π±ΠΎΡ‚Ρƒ Π½Π° этапС Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ΠΈ остаётся Π² `devDependencies`. + +Production-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ generated-ΠΊΠΎΠ΄, стили ΠΈ внСшний SVG-Ρ„Π°ΠΉΠ». Compiler ΠΈ CLI Π½Π΅ ΠΏΠΎΠΏΠ°Π΄Π°ΡŽΡ‚ Π² клиСнтскоС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π° `SpriteViewer` ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚Π°ΠΌ, Π³Π΄Π΅ Π½ΡƒΠΆΠ½Π° debug-страница. + ## ДокумСнтация -- [React + Vite](docs/ru/react-vite.md) -- [React + Webpack 5](docs/ru/react-webpack.md) +README Π·Π½Π°ΠΊΠΎΠΌΠΈΡ‚ с возмоТностями ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΈ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ основной сцСнарий использования. Для настройки Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ руководство ΠΏΠΎΠ΄ свой стСк. + +### Быстрый старт + - [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) +- [React + Vite](docs/ru/react-vite.md) +- [React + Webpack 5](docs/ru/react-webpack.md) +- [Нативный HTML ΠΈ классичСскиС SVG-спрайты](docs/ru/legacy.md) + +### ВСхничСскиС ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ + +- [ВСхничСский справочник](docs/ru/reference.md) - [ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½Ρ‹ΠΉ API](docs/ru/programmatic-api.md) +- [ΠœΠΈΠ³Ρ€Π°Ρ†ΠΈΡ с 0.1.x](docs/ru/migration-1.md) ## ЛицСнзия diff --git a/docs/en/react-vite.md b/docs/en/react-vite.md index 599f508..9d00808 100644 --- a/docs/en/react-vite.md +++ b/docs/en/react-vite.md @@ -38,7 +38,7 @@ export default defineReactSpriteConfig({ 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). +The complete list of options is available under [React and Next.js configuration](reference.md#react-and-nextjs-configuration). ## 4. Add generation to package.json @@ -83,7 +83,7 @@ TypeScript checks the `icon` value against the file names: // TypeScript error ``` -Types, rendering methods, and color controls are described in the [main documentation](../../README.md#rendering-methods). +Types, rendering methods, and color controls are described in the [technical reference](reference.md#react-component-and-typescript). Vite emits the sprite as a separate file named like `assets/sprite-.svg`. SVG path data is not included in JavaScript. diff --git a/docs/en/react-webpack.md b/docs/en/react-webpack.md index 9ad0305..a33a234 100644 --- a/docs/en/react-webpack.md +++ b/docs/en/react-webpack.md @@ -38,7 +38,7 @@ export default defineReactSpriteConfig({ 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). +The complete list of options is available under [React and Next.js configuration](reference.md#react-and-nextjs-configuration). ## 4. Add generation to package.json @@ -81,12 +81,14 @@ TypeScript checks the `icon` value against the file names: // TypeScript error ``` -Types, rendering methods, and color controls are described in the [main documentation](../../README.md#rendering-methods). +Types, rendering methods, and color controls are described in the [technical reference](reference.md#react-component-and-typescript). 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. +The generated component imports `styles.module.css`, so Webpack must process CSS Modules through `css-loader` and `style-loader` or `MiniCssExtractPlugin`. If the TypeScript project does not include a declaration for CSS Modules, add one separately. + ## 6. Add a debug page Webpack does not support Vite's `import.meta.glob` API, so provide static loaders: diff --git a/docs/en/reference.md b/docs/en/reference.md new file mode 100644 index 0000000..61a3b1c --- /dev/null +++ b/docs/en/reference.md @@ -0,0 +1,484 @@ +# Technical reference + +[← Back to home](../../README.md) + +Reference for the configuration, generated API, and behavior of `@gromlab/svg-sprites`. For step-by-step setup instructions, see the guide for your stack: + +- [Next.js App Router](next-app.md) +- [Next.js Pages Router](next-pages.md) +- [React + Vite](react-vite.md) +- [React + Webpack 5](react-webpack.md) +- [Native HTML and classic SVG sprites](legacy.md) + +## Requirements + +- Node.js 18 or newer; +- the package is distributed as ESM and is loaded with `import`; +- React 18 or 19 is required for generated components and `@gromlab/svg-sprites/react`; +- for typed package exports, use TypeScript 5+ with `moduleResolution: "bundler"`, `"node16"`, or `"nodenext"`. + +Install the package as a development dependency: + +```bash +npm install --save-dev @gromlab/svg-sprites +``` + +## CLI and generation modes + +The CLI accepts one mode and a path to the configuration directory: + +```text +svg-sprites --mode +``` + +| 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` | +| Classic `stack` and `symbol` sprites | `legacy` | + +Modern React and Next.js modes use a local `svg-sprite.config.ts`. Legacy mode uses a separate `svg-sprites.config.ts` and is covered in [its own guide](legacy.md). + +The mode must match the application's bundler. The generator creates different SVG asset integration code for Vite and for bundlers compatible with Webpack Asset Modules. + +## React and Next.js configuration + +Each directory containing `svg-sprite.config.ts` defines one independent sprite. + +```ts +import { defineNextSpriteConfig } from '@gromlab/svg-sprites' + +export default defineNextSpriteConfig({ + name: 'app', + description: 'Shared application icons', + inputFolder: './local-icons', + inputFiles: [ + '../../assets/icons/search.svg', + '../../assets/icons/settings.svg', + ], + transform: { + removeSize: true, + replaceColors: true, + addTransition: true, + }, + generatedNotice: true, +}) +``` + +For React, use `defineReactSpriteConfig`. The configuration contract is the same: + +```ts +import { defineReactSpriteConfig } from '@gromlab/svg-sprites' +``` + +| Option | Type | Default | Purpose | +|---|---|---|---| +| `name` | `string` | Derived from the directory | Name of the sprite, component, and public types | +| `description` | `string` | None | Description for types and the debug manifest | +| `inputFolder` | `string` | `./icons` | SVG directory relative to the configuration file | +| `inputFiles` | `string[]` | `[]` | Paths to individual SVG files relative to the configuration file | +| `transform` | `TransformOptions` | All enabled | SVG preparation settings | +| `generatedNotice` | `boolean` | `true` | Full or abbreviated warning in generated files | + +### Sprite name + +`name` is written in kebab-case and must start with an ASCII letter: + +```text +app β†’ AppIcon +file-manager β†’ FileManagerIcon +``` + +If `name` is omitted, the generator derives it from the directory. For a directory named `svg-sprite` or `svg-sprites`, the parent directory's name is used. + +### Icon sources + +`inputFolder` and `inputFiles` are combined into one set. This lets you keep local SVG files next to a module and add shared icons from other parts of the project without copying them. + +If `inputFiles` is populated and the implicit `./icons` directory does not exist, generation uses only the file list. An explicitly configured `inputFolder` that does not exist is an error. + +Only the top level of the directory is scanned. Nested directories are not traversed recursively. For a nested structure, list the exact paths through `inputFiles`. + +Identical absolute paths are deduplicated. Different SVG files with the same file name are treated as a conflict because the public icon name is derived from the basename. + +## Generated module + +After generation, the sprite directory looks like this: + +```text +app-icons/ +β”œβ”€β”€ .gitignore +β”œβ”€β”€ index.ts +β”œβ”€β”€ manifest.ts +β”œβ”€β”€ svg-sprite.config.ts +└── generated/ + β”œβ”€β”€ .svg-sprites.manifest.json + β”œβ”€β”€ react-component.tsx + β”œβ”€β”€ sprite.svg + β”œβ”€β”€ styles.module.css + └── types.ts +``` + +| File | Purpose | +|---|---| +| `index.ts` | Production exports for the component, props, styles, and icon names | +| `manifest.ts` | Debug metadata and the asset URL for `SpriteViewer` | +| `generated/sprite.svg` | Compiled SVG sprite | +| `generated/react-component.tsx` | Typed React component | +| `generated/styles.module.css` | Base styles and transitions | +| `generated/types.ts` | Runtime list and union type of icon names | +| `generated/.svg-sprites.manifest.json` | List of files managed by the generator | + +The generator overwrites and deletes only files that contain its marker. If a user file occupies a managed path, generation fails. + +## React component and TypeScript + +A sprite with `name: 'app'` exports: + +```ts +export { AppIcon, appIconNames } +export type { AppIconName, AppIconProps, AppIconStyle } +``` + +### Icon names + +SVG file names become valid `icon` values: + +```tsx + + // TypeScript error +``` + +The runtime list contains the same values: + +```ts +import { appIconNames } from '@/ui/app-icons' + +// readonly ['search', 'settings', 'user'] +``` + +Names containing spaces or other characters that are unsafe in SVG IDs remain part of the public API. For the internal fragment ID, the generator creates a stable, safe hash: + +```text +folder open.svg β†’ icon="folder open" β†’ id="icon-" +``` + +For these names, use the generated component or the `id` from the debug manifest instead of constructing the fragment ID manually. + +### SVG attributes + +By default, the component renders an `` and accepts standard SVG attributes: + +```tsx + +``` + +The component does not add accessibility semantics automatically. Pass appropriate `aria-*` attributes, a `role`, or a label based on the icon's purpose. + +### Wrapper + +`wrapped` renders a `` containing the SVG. In this mode, the remaining props apply to the ``: + +```tsx + +``` + +### Typed CSS custom properties + +`AppIconStyle` extends `CSSProperties` and supports properties in the form `--icon-color-N`: + +```tsx + +``` + +## Multiple sprites + +Each directory with a configuration creates an independent component, types, manifest, and SVG asset: + +```text +app-icons β†’ AppIcon β†’ shared icons +analytics-icons β†’ AnalyticsIcon β†’ analytics page icons +editor-icons β†’ EditorIcon β†’ editor icons +``` + +The same source SVG can be added to multiple configurations through `inputFiles`. You do not need to copy the file into each sprite directory. + +For multiple sprites, add a separate CLI command for each directory or combine the commands in a shared npm script. + +## Formats and rendering methods + +Modern React and Next.js modes generate the `stack` format. Legacy mode supports both `stack` and `symbol`. + +| Format | `` | `` | CSS background | +|---|---:|---:|---:| +| `stack` | Yes | Yes | Yes | +| `symbol` | Yes | No | No | + +### Generated component + +For React and Next.js, use the generated component. It knows the internal IDs, constructs the URL, and provides a TypeScript API: + +```tsx + +``` + +### Manually with `` + +How you obtain `spriteUrl` depends on the bundler. + +Vite: + +```ts +import spriteUrl from './generated/sprite.svg?no-inline' +``` + +Webpack 5, Turbopack, and Next.js: + +```ts +const spriteUrl = new URL('./generated/sprite.svg', import.meta.url).href +``` + +After obtaining the URL, use it in JSX: + +```tsx + + + +``` + +For names that are unsafe as SVG IDs, use the internal `id` from the manifest. + +### With `` + +```tsx +Search +``` + +An SVG inside `` is isolated from the page's CSS. Setting `color` or `--icon-color-N` on the outer element does not change its internal colors. + +### With CSS + +```css +.icon { + background: url('./generated/sprite.svg#search') center / contain no-repeat; +} +``` + +For a single-color silhouette, you can use a mask: + +```css +.icon { + background-color: currentColor; + mask: url('./generated/sprite.svg#search') center / contain no-repeat; +} +``` + +A mask does not preserve original colors, gradients, or differences between `fill` and `stroke`. + +The path in CSS is resolved relative to the CSS file itself. In these examples, the CSS file is next to `svg-sprite.config.ts`. + +## Assets and caching + +The generated component passes the SVG to the bundler as a separate asset: + +- Vite uses a static import with `?no-inline`; +- Webpack 5, Turbopack, and Next.js use `new URL(..., import.meta.url)`; +- SVG path data is not serialized into the generated TSX. + +With standard asset naming, the bundler adds a content hash: + +```text +/assets/sprite-.svg +``` + +This allows the SVG to be cached separately from JavaScript. Changing React code does not change the sprite contents, while changing icons creates a new asset version. + +HTTP cache headers, CDN behavior, and `Cache-Control` are configured by the application or hosting platform. With Webpack, the final file name depends on the project's `assetModuleFilename`. + +## SVG transformations + +All transformations are enabled by default and can be configured independently: + +| Option | Behavior | +|---|---| +| `removeSize` | Removes `width` and `height` from the root `` while preserving an existing `viewBox` | +| `replaceColors` | Replaces detected `fill` and `stroke` values with `--icon-color-N` | +| `addTransition` | Adds transitions for `fill` and `stroke` to colored elements and generated styles | + +To disable an individual operation: + +```ts +export default defineNextSpriteConfig({ + transform: { + removeSize: false, + replaceColors: false, + addTransition: false, + }, +}) +``` + +Source SVG files are not modified. Transformations apply only to the generated sprite contents. + +## Color management + +### Monochrome icons + +If one color is detected, its fallback becomes `currentColor`: + +```svg +stroke="var(--icon-color-1, currentColor)" +``` + +Set the color through a prop or CSS: + +```tsx + +``` + +### Multicolor icons + +Each unique color gets its own custom property with the original color as its fallback: + +```svg +fill="var(--icon-color-1, #798198)" +fill="var(--icon-color-2, #ffffff)" +fill="var(--icon-color-3, #129d9d)" +``` + +You can override only the values you need: + +```css +.icon { + --icon-color-1: #4b5563; + --icon-color-3: #14b8a6; +} +``` + +### Limitations + +- `none`, `transparent`, `inherit`, `unset`, and `initial` are not replaced; +- colors in `fill`, `stroke`, and inline `style` attributes are handled most reliably; +- CSS classes and external stylesheets inside the SVG are not the primary transformation use case; +- `url(#...)` values may be replaced along with colors, so gradients and patterns require a separate sprite with `replaceColors: false`; +- masks, filters, and complex internal CSS rules require visual verification; +- page CSS custom properties are available through ``, but not inside `` or a CSS background. + +For a complex icon, you can disable `replaceColors` in a separate sprite configuration. + +## SpriteViewer + +`SpriteViewer` is imported from a separate client entry point: + +```tsx +import { SpriteViewer } from '@gromlab/svg-sprites/react' +``` + +It accepts ready-made manifests, an array of lazy loaders, or a record in the format returned by `import.meta.glob`. + +Vite: + +```tsx +import { SpriteViewer } from '@gromlab/svg-sprites/react' +import type { SpriteManifestModule } from '@gromlab/svg-sprites/react' + +const sources = import.meta.glob( + '/src/**/svg-sprite/manifest.ts', +) + +export const IconsDebugPage = () => ( + +) +``` + +Webpack and Next.js: + +```tsx +const sources = [ + () => import('@/ui/app-icons/manifest'), + () => import('@/features/analytics/icons/manifest'), +] + +export const IconsDebugPage = () => ( + +) +``` + +The Viewer displays groups, search, `viewBox`, CSS custom properties, fallback colors, and React, SVG, IMG, and CSS examples. You can change color values in the interface and immediately inspect the result. + +### Viewer theme + +By default, `colorTheme="auto"` follows `prefers-color-scheme`. You can explicitly pass `light` or `dark`: + +```tsx + +``` + +To synchronize it with the application theme: + +```tsx + +``` + +`@gromlab/svg-sprites/react` contains `'use client'`. In the Next.js App Router, place the Viewer inside a separate Client Component boundary and use it only on a debug route or in an internal tool. + +## Generated files, Git, and CI + +A modern sprite module creates a local `.gitignore` for: + +```text +/generated/ +/index.ts +/manifest.ts +``` + +Commit the local `.gitignore` to the repository once. It excludes the other generated files, so generation must run before commands that import the sprite module: + +```json +{ + "scripts": { + "sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons", + "predev": "npm run sprites", + "prebuild": "npm run sprites", + "pretypecheck": "npm run sprites" + } +} +``` + +CI must install development dependencies and run the generation script before building or type-checking. + +If the sprite directory already contains a user-created `.gitignore`, `index.ts`, or `manifest.ts`, the generator will not overwrite it. Move the user file or choose a separate sprite directory. + +## Troubleshooting + +- Missing `index.ts`: run the generation script before importing the module. +- Configuration not found: check the CLI path and the `svg-sprite.config.ts` file name. +- Icon missing from the type: check `inputFiles`, the `.svg` extension, and the nesting level under `inputFolder`. +- Name conflict: two different SVG files have the same basename; rename one of them. +- `Refusing to overwrite a user file`: a file without the generated marker occupies a managed path. +- The icon does not change color: use `` or the generated component and check `replaceColors`. +- Webpack emits an incorrect URL: check Asset Modules, `output.publicPath`, and SVG loaders. +- The Viewer cannot find the sprite: check the path to `manifest.ts` and run generation before starting the application. +- Build and mode do not match: use the target that corresponds to the actual bundler. + +For custom orchestration and low-level compilation, see the [Programmatic API](programmatic-api.md). diff --git a/docs/ru/react-vite.md b/docs/ru/react-vite.md index 205f9f3..f1c99ab 100644 --- a/docs/ru/react-vite.md +++ b/docs/ru/react-vite.md @@ -38,7 +38,7 @@ export default defineReactSpriteConfig({ По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ SVG бСрутся ΠΈΠ· `./icons`. ΠžΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠ°ΠΏΠΎΠΊ ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· `inputFiles`: ΠΏΠ°ΠΏΠΊΠ° ΠΈ список ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‚ΡΡ Π² ΠΎΠ΄ΠΈΠ½ спрайт. -ΠŸΠΎΠ»Π½Ρ‹ΠΉ список ΠΎΠΏΡ†ΠΈΠΉ находится Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ [ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ β†’ React](../../README_RU.md#react). +ΠŸΠΎΠ»Π½Ρ‹ΠΉ список ΠΎΠΏΡ†ΠΈΠΉ находится Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ [Β«ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ React ΠΈ Next.jsΒ»](reference.md#конфигурация-react-ΠΈ-nextjs). ## 4. Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ Π² package.json @@ -83,7 +83,7 @@ export const OpenFolderButton = () => ( // ошибка TypeScript ``` -Π’ΠΈΠΏΡ‹, способы отобраТСния ΠΈ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ описаны Π² [основной Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ](../../README_RU.md#способы-отобраТСния). +Π’ΠΈΠΏΡ‹, способы отобраТСния ΠΈ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ описаны Π² [тСхничСском справочникС](reference.md#react-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚-ΠΈ-typescript). Vite выпустит спрайт ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌ Ρ„Π°ΠΉΠ»ΠΎΠΌ Π²ΠΈΠ΄Π° `assets/sprite-.svg`. SVG path-Π΄Π°Π½Π½Ρ‹Π΅ Π½Π΅ ΠΏΠΎΠΏΠ°Π΄ΡƒΡ‚ Π² JavaScript. diff --git a/docs/ru/react-webpack.md b/docs/ru/react-webpack.md index fd9db21..567609f 100644 --- a/docs/ru/react-webpack.md +++ b/docs/ru/react-webpack.md @@ -38,7 +38,7 @@ export default defineReactSpriteConfig({ По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ SVG бСрутся ΠΈΠ· `./icons`. ΠžΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠ°ΠΏΠΎΠΊ ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· `inputFiles`: ΠΏΠ°ΠΏΠΊΠ° ΠΈ список ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‚ΡΡ Π² ΠΎΠ΄ΠΈΠ½ спрайт. -ΠŸΠΎΠ»Π½Ρ‹ΠΉ список ΠΎΠΏΡ†ΠΈΠΉ находится Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ [ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ β†’ React](../../README_RU.md#react). +ΠŸΠΎΠ»Π½Ρ‹ΠΉ список ΠΎΠΏΡ†ΠΈΠΉ находится Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ [Β«ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ React ΠΈ Next.jsΒ»](reference.md#конфигурация-react-ΠΈ-nextjs). ## 4. Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ Π² package.json @@ -81,12 +81,14 @@ export const OpenFolderButton = () => ( // ошибка TypeScript ``` -Π’ΠΈΠΏΡ‹, способы отобраТСния ΠΈ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ описаны Π² [основной Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ](../../README_RU.md#способы-отобраТСния). +Π’ΠΈΠΏΡ‹, способы отобраТСния ΠΈ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ описаны Π² [тСхничСском справочникС](reference.md#react-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚-ΠΈ-typescript). Webpack ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ generated `new URL('./sprite.svg', import.meta.url)` Ρ‡Π΅Ρ€Π΅Π· Asset Modules ΠΈ выпустит ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ SVG asset. Если ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΡƒΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ собствСнный SVG loader, ΡƒΠ±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ Π½Π΅ ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ generated `sprite.svg` вмСсто Asset Modules. +Generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ `styles.module.css`, поэтому Webpack Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ CSS Modules Ρ‡Π΅Ρ€Π΅Π· `css-loader` ΠΈ `style-loader` Π»ΠΈΠ±ΠΎ `MiniCssExtractPlugin`. Если TypeScript-ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Π½Π΅ содСрТит Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ†ΠΈΠΈ для CSS Modules, Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π΅Ρ‘ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ. + ## 6. Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ debug-страницу Webpack Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Vite API `import.meta.glob`, поэтому ΠΏΠ΅Ρ€Π΅Π΄Π°ΠΉΡ‚Π΅ статичСскиС loaders: diff --git a/docs/ru/reference.md b/docs/ru/reference.md new file mode 100644 index 0000000..218c67b --- /dev/null +++ b/docs/ru/reference.md @@ -0,0 +1,484 @@ +# ВСхничСский справочник + +[← Главная](../../README_RU.md) + +Π‘ΠΏΡ€Π°Π²ΠΎΡ‡Π½ΠΈΠΊ ΠΏΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ, generated API ΠΈ повСдСнию `@gromlab/svg-sprites`. ΠŸΠΎΡˆΠ°Π³ΠΎΠ²ΡƒΡŽ установку смотритС Π² руководствС для вашСго стСка: + +- [Next.js App Router](next-app.md) +- [Next.js Pages Router](next-pages.md) +- [React + Vite](react-vite.md) +- [React + Webpack 5](react-webpack.md) +- [Нативный HTML ΠΈ классичСскиС SVG-спрайты](legacy.md) + +## ВрСбования + +- Node.js 18 ΠΈΠ»ΠΈ Π½ΠΎΠ²Π΅Π΅; +- ΠΏΠ°ΠΊΠ΅Ρ‚ распространяСтся ΠΊΠ°ΠΊ ESM ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Ρ‡Π΅Ρ€Π΅Π· `import`; +- React 18 ΠΈΠ»ΠΈ 19 трСбуСтся для generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΈ `@gromlab/svg-sprites/react`; +- для Ρ‚ΠΈΠΏΠΈΠ·Π°Ρ†ΠΈΠΈ package exports ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ TypeScript 5+ с `moduleResolution: "bundler"`, `"node16"` ΠΈΠ»ΠΈ `"nodenext"`. + +ΠŸΠ°ΠΊΠ΅Ρ‚ устанавливаСтся ΠΊΠ°ΠΊ development dependency: + +```bash +npm install --save-dev @gromlab/svg-sprites +``` + +## CLI ΠΈ Ρ€Π΅ΠΆΠΈΠΌΡ‹ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ + +CLI ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ Ρ€Π΅ΠΆΠΈΠΌ ΠΈ ΠΏΡƒΡ‚ΡŒ ΠΊ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Ρƒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ: + +```text +svg-sprites --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` | +| ΠšΠ»Π°ΡΡΠΈΡ‡Π΅ΡΠΊΠΈΠ΅ `stack`- ΠΈ `symbol`-спрайты | `legacy` | + +Π‘ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ React- ΠΈ Next.js-Ρ€Π΅ΠΆΠΈΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ `svg-sprite.config.ts`. Legacy-Ρ€Π΅ΠΆΠΈΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ `svg-sprites.config.ts` ΠΈ описан Π² [собствСнном руководствС](legacy.md). + +Mode Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ сборщику прилоТСния. Π“Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ создаёт Ρ€Π°Π·Π½Ρ‹ΠΉ способ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ SVG asset для Vite ΠΈ сборщиков, совмСстимых с Webpack Asset Modules. + +## ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ React ΠΈ Next.js + +ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ с `svg-sprite.config.ts` описываСт ΠΎΠ΄ΠΈΠ½ нСзависимый спрайт. + +```ts +import { defineNextSpriteConfig } from '@gromlab/svg-sprites' + +export default defineNextSpriteConfig({ + name: 'app', + description: 'ΠžΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ прилоТСния', + inputFolder: './local-icons', + inputFiles: [ + '../../assets/icons/search.svg', + '../../assets/icons/settings.svg', + ], + transform: { + removeSize: true, + replaceColors: true, + addTransition: true, + }, + generatedNotice: true, +}) +``` + +Для React ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ `defineReactSpriteConfig`. ΠšΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΉ: + +```ts +import { defineReactSpriteConfig } from '@gromlab/svg-sprites' +``` + +| ΠžΠΏΡ†ΠΈΡ | Π’ΠΈΠΏ | По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ | НазначСниС | +|---|---|---|---| +| `name` | `string` | Выводится ΠΈΠ· ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° | Имя спрайта, ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΈ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² | +| `description` | `string` | НСт | ОписаниС для Ρ‚ΠΈΠΏΠΎΠ² ΠΈ debug manifest | +| `inputFolder` | `string` | `./icons` | ΠšΠ°Ρ‚Π°Π»ΠΎΠ³ с SVG ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° | +| `inputFiles` | `string[]` | `[]` | ΠŸΡƒΡ‚ΠΈ ΠΊ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌ SVG ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° | +| `transform` | `TransformOptions` | ВсС Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ | Настройки ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠΈ SVG | +| `generatedNotice` | `boolean` | `true` | ПолноС ΠΈΠ»ΠΈ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΎΠ΅ ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅ Π² generated-Ρ„Π°ΠΉΠ»Π°Ρ… | + +### Имя спрайта + +`name` записываСтся Π² kebab-case ΠΈ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒΡΡ с латинской Π±ΡƒΠΊΠ²Ρ‹: + +```text +app β†’ AppIcon +file-manager β†’ FileManagerIcon +``` + +Если `name` Π½Π΅ Π·Π°Π΄Π°Π½ΠΎ, Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ Π΅Π³ΠΎ ΠΈΠ· ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π°. Для ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° с ΠΈΠΌΠ΅Π½Π΅ΠΌ `svg-sprite` ΠΈΠ»ΠΈ `svg-sprites` ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ имя Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π°. + +### Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ ΠΈΠΊΠΎΠ½ΠΎΠΊ + +`inputFolder` ΠΈ `inputFiles` ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΡΡŽΡ‚ΡΡ Π² ΠΎΠ΄ΠΈΠ½ Π½Π°Π±ΠΎΡ€. Π­Ρ‚ΠΎ позволяСт Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ SVG рядом с ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΌ ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΠΎΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… частСй ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π±Π΅Π· копирования. + +Если `inputFiles` Π·Π°ΠΏΠΎΠ»Π½Π΅Π½, Π° нСявного ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° `./icons` Π½Π΅Ρ‚, гСнСрация Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎ списку Ρ„Π°ΠΉΠ»ΠΎΠ². Π―Π²Π½ΠΎ указанная ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π°Ρ `inputFolder` считаСтся ошибкой. + +ΠšΠ°Ρ‚Π°Π»ΠΎΠ³ сканируСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° ΠΏΠ΅Ρ€Π²ΠΎΠΌ ΡƒΡ€ΠΎΠ²Π½Π΅. Π’Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΈ рСкурсивно Π½Π΅ обходятся. Для Π²Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ структуры пСрСчислитС Ρ‚ΠΎΡ‡Π½Ρ‹Π΅ ΠΏΡƒΡ‚ΠΈ Ρ‡Π΅Ρ€Π΅Π· `inputFiles`. + +ΠžΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Π΅ Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½Ρ‹Π΅ ΠΏΡƒΡ‚ΠΈ Π΄Π΅Π΄ΡƒΠΏΠ»ΠΈΡ†ΠΈΡ€ΡƒΡŽΡ‚ΡΡ. Π Π°Π·Π½Ρ‹Π΅ SVG с ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ Ρ„Π°ΠΉΠ»Π° ΡΡ‡ΠΈΡ‚Π°ΡŽΡ‚ΡΡ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠΌ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠ΅ имя ΠΈΠΊΠΎΠ½ΠΊΠΈ выводится ΠΈΠ· basename. + +## Generated-ΠΌΠΎΠ΄ΡƒΠ»ΡŒ + +ПослС Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ спрайта выглядит Ρ‚Π°ΠΊ: + +```text +app-icons/ +β”œβ”€β”€ .gitignore +β”œβ”€β”€ index.ts +β”œβ”€β”€ manifest.ts +β”œβ”€β”€ svg-sprite.config.ts +└── generated/ + β”œβ”€β”€ .svg-sprites.manifest.json + β”œβ”€β”€ react-component.tsx + β”œβ”€β”€ sprite.svg + β”œβ”€β”€ styles.module.css + └── types.ts +``` + +| Π€Π°ΠΉΠ» | НазначСниС | +|---|---| +| `index.ts` | Production exports ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°, props, стилСй ΠΈ ΠΈΠΌΡ‘Π½ ΠΈΠΊΠΎΠ½ΠΎΠΊ | +| `manifest.ts` | Debug metadata ΠΈ URL asset для `SpriteViewer` | +| `generated/sprite.svg` | Π‘ΠΎΠ±Ρ€Π°Π½Π½Ρ‹ΠΉ SVG-спрайт | +| `generated/react-component.tsx` | Π’ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ | +| `generated/styles.module.css` | Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ стили ΠΈ transitions | +| `generated/types.ts` | Runtime-список ΠΈ union-Ρ‚ΠΈΠΏ ΠΈΠΌΡ‘Π½ | +| `generated/.svg-sprites.manifest.json` | Бписок Ρ„Π°ΠΉΠ»ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ управляСт Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ | + +Π“Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ пСрСзаписываСт ΠΈ удаляСт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ„Π°ΠΉΠ»Ρ‹ со своим marker. Если Π² managed-ΠΏΡƒΡ‚ΠΈ находится ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Ρ„Π°ΠΉΠ», гСнСрация Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ΡΡ ошибкой. + +## React-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈ TypeScript + +Π‘ΠΏΡ€Π°ΠΉΡ‚ с `name: 'app'` экспортируСт: + +```ts +export { AppIcon, appIconNames } +export type { AppIconName, AppIconProps, AppIconStyle } +``` + +### ИмСна ΠΈΠΊΠΎΠ½ΠΎΠΊ + +ИмСна SVG-Ρ„Π°ΠΉΠ»ΠΎΠ² становятся допустимыми значСниями `icon`: + +```tsx + + // ошибка TypeScript +``` + +Runtime-список содСрТит Ρ‚Π΅ ΠΆΠ΅ значСния: + +```ts +import { appIconNames } from '@/ui/app-icons' + +// readonly ['search', 'settings', 'user'] +``` + +ИмСна с ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ нСбСзопасными для SVG ID символами ΠΎΡΡ‚Π°ΡŽΡ‚ΡΡ Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠ³ΠΎ API. Для Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ fragment ID Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ создаёт ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ бСзопасный hash: + +```text +folder open.svg β†’ icon="folder open" β†’ id="icon-" +``` + +Для Ρ‚Π°ΠΊΠΈΡ… ΠΈΠΌΡ‘Π½ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈΠ»ΠΈ `id` ΠΈΠ· debug manifest, Π° Π½Π΅ Ρ„ΠΎΡ€ΠΌΠΈΡ€ΡƒΠΉΡ‚Π΅ fragment ID Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ. + +### SVG-Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρ‹ + +По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ `` ΠΈ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ стандартныС SVG-Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρ‹: + +```tsx + +``` + +ΠšΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π½Π΅ добавляСт accessibility-сСмантику автоматичСски. ΠŸΠ΅Ρ€Π΅Π΄Π°Π²Π°ΠΉΡ‚Π΅ подходящиС `aria-*`, `role` ΠΈΠ»ΠΈ подпись Π² зависимости ΠΎΡ‚ назначСния ΠΈΠΊΠΎΠ½ΠΊΠΈ. + +### ΠžΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° + +`wrapped` Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ `` с Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΌ SVG. ΠžΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ props Π² этом Ρ€Π΅ΠΆΠΈΠΌΠ΅ относятся ΠΊ ``: + +```tsx + +``` + +### Π’ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ CSS-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ + +`AppIconStyle` Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ `CSSProperties` ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ свойства Π²ΠΈΠ΄Π° `--icon-color-N`: + +```tsx + +``` + +## ΠœΠ½ΠΎΠΆΠ΅ΡΡ‚Π²Π΅Π½Π½Ρ‹Π΅ спрайты + +ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ с ΠΊΠΎΠ½Ρ„ΠΈΠ³ΠΎΠΌ создаёт нСзависимый ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚, Ρ‚ΠΈΠΏΡ‹, manifest ΠΈ SVG asset: + +```text +app-icons β†’ AppIcon β†’ ΠΎΠ±Ρ‰ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ +analytics-icons β†’ AnalyticsIcon β†’ ΠΈΠΊΠΎΠ½ΠΊΠΈ страницы Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΠΈ +editor-icons β†’ EditorIcon β†’ ΠΈΠΊΠΎΠ½ΠΊΠΈ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€Π° +``` + +Один исходный SVG ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· `inputFiles` Π² нСсколько ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΉ. ΠšΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» Π² ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ спрайта Π½Π΅ трСбуСтся. + +Для Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… спрайтов Π΄ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ CLI-ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° ΠΈΠ»ΠΈ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Π² ΠΎΠ±Ρ‰Π΅ΠΌ npm script. + +## Π€ΠΎΡ€ΠΌΠ°Ρ‚Ρ‹ ΠΈ способы отобраТСния + +Π‘ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ React- ΠΈ Next.js-Ρ€Π΅ΠΆΠΈΠΌΡ‹ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ `stack`. Legacy-Ρ€Π΅ΠΆΠΈΠΌ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ `stack` ΠΈ `symbol`. + +| Π€ΠΎΡ€ΠΌΠ°Ρ‚ | `` | `` | CSS background | +|---|---:|---:|---:| +| `stack` | Π”Π° | Π”Π° | Π”Π° | +| `symbol` | Π”Π° | НСт | НСт | + +### Generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ + +Для React ΠΈ Next.js ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚. Он Π·Π½Π°Π΅Ρ‚ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠ΅ ID, Ρ„ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅Ρ‚ URL ΠΈ прСдоставляСт TypeScript API: + +```tsx + +``` + +### Π’Ρ€ΡƒΡ‡Π½ΡƒΡŽ Ρ‡Π΅Ρ€Π΅Π· `` + +Бпособ получСния `spriteUrl` зависит ΠΎΡ‚ сборщика. + +Vite: + +```ts +import spriteUrl from './generated/sprite.svg?no-inline' +``` + +Webpack 5, Turbopack ΠΈ Next.js: + +```ts +const spriteUrl = new URL('./generated/sprite.svg', import.meta.url).href +``` + +ПослС получСния URL ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Π΅Π³ΠΎ Π² JSX: + +```tsx + + + +``` + +Для ΠΈΠΌΡ‘Π½, нСбСзопасных ΠΊΠ°ΠΊ SVG ID, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΉ `id` ΠΈΠ· manifest. + +### Π§Π΅Ρ€Π΅Π· `` + +```tsx +Поиск +``` + +SVG Π²Π½ΡƒΡ‚Ρ€ΠΈ `` ΠΈΠ·ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Π½ ΠΎΡ‚ CSS страницы. `color` ΠΈ `--icon-color-N` Π½Π° внСшнСм элСмСнтС Π½Π΅ ΠΈΠ·ΠΌΠ΅Π½ΡΡŽΡ‚ Π΅Π³ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠ΅ Ρ†Π²Π΅Ρ‚Π°. + +### Π§Π΅Ρ€Π΅Π· CSS + +```css +.icon { + background: url('./generated/sprite.svg#search') center / contain no-repeat; +} +``` + +Для ΠΎΠ΄Π½ΠΎΡ†Π²Π΅Ρ‚Π½ΠΎΠ³ΠΎ силуэта ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ mask: + +```css +.icon { + background-color: currentColor; + mask: url('./generated/sprite.svg#search') center / contain no-repeat; +} +``` + +Mask Π½Π΅ сохраняСт исходныС Ρ†Π²Π΅Ρ‚Π°, gradients ΠΈ различия ΠΌΠ΅ΠΆΠ΄Ρƒ `fill` ΠΈ `stroke`. + +ΠŸΡƒΡ‚ΡŒ Π² CSS Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ самого CSS-Ρ„Π°ΠΉΠ»Π°. Π’ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ… CSS-Ρ„Π°ΠΉΠ» находится рядом с `svg-sprite.config.ts`. + +## Assets ΠΈ ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ + +Generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ SVG сборщику ΠΊΠ°ΠΊ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ asset: + +- Vite ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ статичСский ΠΈΠΌΠΏΠΎΡ€Ρ‚ с `?no-inline`; +- Webpack 5, Turbopack ΠΈ Next.js ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ `new URL(..., import.meta.url)`; +- SVG path-Π΄Π°Π½Π½Ρ‹Π΅ Π½Π΅ ΡΠ΅Ρ€ΠΈΠ°Π»ΠΈΠ·ΡƒΡŽΡ‚ΡΡ Π² generated TSX. + +ΠŸΡ€ΠΈ стандартном ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠΈ assets сборщик добавляСт content hash: + +```text +/assets/sprite-.svg +``` + +Π­Ρ‚ΠΎ позволяСт ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ SVG ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ ΠΎΡ‚ JavaScript. ИзмСнСниС React-ΠΊΠΎΠ΄Π° Π½Π΅ мСняСт содСрТимоС спрайта, Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΈΠΊΠΎΠ½ΠΎΠΊ создаёт Π½ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ asset. + +HTTP cache headers, CDN ΠΈ `Cache-Control` Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ ΠΈΠ»ΠΈ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠΎΠΉ размСщСния. Для Webpack имя ΠΈΡ‚ΠΎΠ³ΠΎΠ²ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° зависит ΠΎΡ‚ `assetModuleFilename` ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. + +## Врансформации SVG + +ВсС трансформации Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΈ Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°ΡŽΡ‚ΡΡ нСзависимо: + +| ΠžΠΏΡ†ΠΈΡ | Π§Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ | +|---|---| +| `removeSize` | УдаляСт `width` ΠΈ `height` с ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠ³ΠΎ ``, сохраняя ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ `viewBox` | +| `replaceColors` | ЗамСняСт Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Π΅ `fill` ΠΈ `stroke` Π½Π° `--icon-color-N` | +| `addTransition` | ДобавляСт transitions для `fill` ΠΈ `stroke` Π² Ρ†Π²Π΅Ρ‚Π½Ρ‹Π΅ элСмСнты ΠΈ generated styles | + +Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ: + +```ts +export default defineNextSpriteConfig({ + transform: { + removeSize: false, + replaceColors: false, + addTransition: false, + }, +}) +``` + +Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹Π΅ SVG Π½Π΅ ΠΈΠ·ΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ. Врансформации ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ содСрТимому generated-спрайта. + +## Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ + +### ΠœΠΎΠ½ΠΎΡ…Ρ€ΠΎΠΌΠ½Ρ‹Π΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ + +Если Π½Π°ΠΉΠ΄Π΅Π½ ΠΎΠ΄ΠΈΠ½ Ρ†Π²Π΅Ρ‚, fallback становится `currentColor`: + +```svg +stroke="var(--icon-color-1, currentColor)" +``` + +Π¦Π²Π΅Ρ‚ задаётся Ρ‡Π΅Ρ€Π΅Π· prop ΠΈΠ»ΠΈ CSS: + +```tsx + +``` + +### ΠœΠ½ΠΎΠ³ΠΎΡ†Π²Π΅Ρ‚Π½Ρ‹Π΅ ΠΈΠΊΠΎΠ½ΠΊΠΈ + +ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ†Π²Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ с исходным fallback: + +```svg +fill="var(--icon-color-1, #798198)" +fill="var(--icon-color-2, #ffffff)" +fill="var(--icon-color-3, #129d9d)" +``` + +МоТно Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ значСния: + +```css +.icon { + --icon-color-1: #4b5563; + --icon-color-3: #14b8a6; +} +``` + +### ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΡ + +- `none`, `transparent`, `inherit`, `unset` ΠΈ `initial` Π½Π΅ Π·Π°ΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ; +- Π½Π°Π΄Ρ‘ΠΆΠ½Π΅Π΅ всСго ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ΡΡ Ρ†Π²Π΅Ρ‚Π° Π² Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π°Ρ… `fill`, `stroke` ΠΈ inline `style`; +- CSS-классы ΠΈ внСшниС stylesheets Π²Π½ΡƒΡ‚Ρ€ΠΈ SVG Π½Π΅ ΡΠ²Π»ΡΡŽΡ‚ΡΡ основным сцСнариСм трансформации; +- значСния `url(#...)` ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Π·Π°ΠΌΠ΅Π½Π΅Π½Ρ‹ вмСстС с Ρ†Π²Π΅Ρ‚Π°ΠΌΠΈ, поэтому gradients ΠΈ patterns Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ спрайта с `replaceColors: false`; +- masks, filters ΠΈ слоТныС Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠ΅ CSS-ΠΏΡ€Π°Π²ΠΈΠ»Π° Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ; +- CSS-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ страницы доступны Ρ‡Π΅Ρ€Π΅Π· ``, Π½ΠΎ Π½Π΅ Π²Π½ΡƒΡ‚Ρ€ΠΈ `` ΠΈ CSS background. + +Для слоТной ΠΈΠΊΠΎΠ½ΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ `replaceColors` Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ спрайта. + +## SpriteViewer + +`SpriteViewer` ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ ΠΈΠ· ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ клиСнтской Ρ‚ΠΎΡ‡ΠΊΠΈ Π²Ρ…ΠΎΠ΄Π°: + +```tsx +import { SpriteViewer } from '@gromlab/svg-sprites/react' +``` + +Он ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π³ΠΎΡ‚ΠΎΠ²Ρ‹Π΅ manifests, массив lazy loaders ΠΈΠ»ΠΈ record Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° `import.meta.glob`. + +Vite: + +```tsx +import { SpriteViewer } from '@gromlab/svg-sprites/react' +import type { SpriteManifestModule } from '@gromlab/svg-sprites/react' + +const sources = import.meta.glob( + '/src/**/svg-sprite/manifest.ts', +) + +export const IconsDebugPage = () => ( + +) +``` + +Webpack ΠΈ Next.js: + +```tsx +const sources = [ + () => import('@/ui/app-icons/manifest'), + () => import('@/features/analytics/icons/manifest'), +] + +export const IconsDebugPage = () => ( + +) +``` + +Viewer ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ Π³Ρ€ΡƒΠΏΠΏΡ‹, поиск, `viewBox`, CSS-ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅, fallback-Ρ†Π²Π΅Ρ‚Π° ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ React, SVG, IMG ΠΈ CSS. Π¦Π²Π΅Ρ‚ΠΎΠ²Ρ‹Π΅ значСния ΠΌΠΎΠΆΠ½ΠΎ ΠΌΠ΅Π½ΡΡ‚ΡŒ Π² интСрфСйсС ΠΈ сразу ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚. + +### Π’Π΅ΠΌΠ° Viewer + +По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ `colorTheme="auto"` слСдуСт `prefers-color-scheme`. МоТно ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ `light` ΠΈΠ»ΠΈ `dark` явно: + +```tsx + +``` + +Для синхронизации с Ρ‚Π΅ΠΌΠΎΠΉ прилоТСния: + +```tsx + +``` + +`@gromlab/svg-sprites/react` содСрТит `'use client'`. Π’ Next.js App Router Ρ€Π°Π·ΠΌΠ΅Ρ‰Π°ΠΉΡ‚Π΅ Viewer Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ Client Component boundary ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° debug-ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Π΅ ΠΈΠ»ΠΈ Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅ΠΌ инструмСнтС. + +## Generated-Ρ„Π°ΠΉΠ»Ρ‹, Git ΠΈ CI + +Π‘ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ sprite-ΠΌΠΎΠ΄ΡƒΠ»ΡŒ создаёт Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ `.gitignore` для: + +```text +/generated/ +/index.ts +/manifest.ts +``` + +Π›ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ `.gitignore` слСдуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π· Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ. Он ΠΈΡΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ generated-Ρ„Π°ΠΉΠ»Ρ‹, поэтому Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ ΠΏΠ΅Ρ€Π΅Π΄ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΡŽΡ‚ sprite-ΠΌΠΎΠ΄ΡƒΠ»ΡŒ: + +```json +{ + "scripts": { + "sprites": "svg-sprites --mode next@app/turbopack src/ui/app-icons", + "predev": "npm run sprites", + "prebuild": "npm run sprites", + "pretypecheck": "npm run sprites" + } +} +``` + +CI Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ development dependencies ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ generation script Π΄ΠΎ сборки ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Ρ‚ΠΈΠΏΠΎΠ². + +Если Π² ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ спрайта ΡƒΠΆΠ΅ находится ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ `.gitignore`, `index.ts` ΠΈΠ»ΠΈ `manifest.ts`, Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π½Π΅ ΠΏΠ΅Ρ€Π΅Π·Π°ΠΏΠΈΡˆΠ΅Ρ‚ Π΅Π³ΠΎ. ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Ρ„Π°ΠΉΠ» ΠΈΠ»ΠΈ Π²Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ спрайта. + +## Диагностика + +- НСт `index.ts`: запуститС generation script Π΄ΠΎ ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° модуля. +- НС Π½Π°ΠΉΠ΄Π΅Π½Π° конфигурация: ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ ΠΏΡƒΡ‚ΡŒ CLI ΠΈ имя `svg-sprite.config.ts`. +- Иконка отсутствуСт Π² Ρ‚ΠΈΠΏΠ΅: ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ `inputFiles`, Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ `.svg` ΠΈ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ влоТСнности `inputFolder`. +- ΠšΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ ΠΈΠΌΠ΅Π½ΠΈ: Π΄Π²Π° Ρ€Π°Π·Π½Ρ‹Ρ… SVG ΠΈΠΌΠ΅ΡŽΡ‚ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΉ basename; ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΡƒΠΉΡ‚Π΅ ΠΎΠ΄ΠΈΠ½ Ρ„Π°ΠΉΠ». +- `Refusing to overwrite a user file`: Π² managed-ΠΏΡƒΡ‚ΠΈ находится Ρ„Π°ΠΉΠ» Π±Π΅Π· generated marker. +- Иконка Π½Π΅ мСняСт Ρ†Π²Π΅Ρ‚: ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ `` ΠΈΠ»ΠΈ generated-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ `replaceColors`. +- Webpack Π²Ρ‹Π΄Π°Ρ‘Ρ‚ Π½Π΅Π²Π΅Ρ€Π½Ρ‹ΠΉ URL: ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ Asset Modules, `output.publicPath` ΠΈ SVG loaders. +- Viewer Π½Π΅ Π²ΠΈΠ΄ΠΈΡ‚ спрайт: ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ ΠΏΡƒΡ‚ΡŒ ΠΊ `manifest.ts` ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ Π΄ΠΎ запуска прилоТСния. +- Build ΠΈ mode Π½Π΅ ΡΠΎΠ²ΠΏΠ°Π΄Π°ΡŽΡ‚: ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ target, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ фактичСскому сборщику. + +Для собствСнного orchestration ΠΈ Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²ΠΎΠΉ компиляции смотритС [ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ½Ρ‹ΠΉ API](programmatic-api.md).