<p align="left">
  <a href="https://emailmaker.ru/" target="blank"><img src="https://emcdn.ru/389992/240402_17_0uOwHpL.png" width="500" alt="EmailMaker" /></a>
</p>


# Установка

Установите пакет из npm:

```bash
npm install @emailmaker/emailmaker
```

### Полезные ссылки

- Каталог пакета на npm: [@emailmaker/emailmaker](https://www.npmjs.com/package/@emailmaker/emailmaker)
- Справка на сайте EmailMaker: [Подключение редактора](https://emailmaker.ru/docs/help/plugin/connecting-the-editor/)

Добавьте плагин сборки EmailMaker в конфигурацию приложения (он копирует статику пакета и задаёт **`__emailmaker__.publicPath`** для загрузки чанков). Без Webpack/Vite-плагина вручную нужно обеспечить корректный базовый путь к бандлу.

## Чеклист для агентов и автоматизации

Используйте таблицу при генерации кода интеграции или ревью. Источник типов — **`emailmaker.d.ts`** в пакете (**`ExportedApi`**); не подставляйте вымышленные поля API.

Подробнее о том, как в `.d.ts` сливаются **`ExportedApi.Options` / `Instance`**, что такое **`AppEvent`** и **`SaveEventPayload`**, и как читать исключения (**`handleSubjectChanged`** и др.): в репозитории EmailMaker — **`docs/plugin-types-agents.md`**.

| Правило | Детали |
| --- | --- |
| **`init`** | Обязательно **`content`**. Сигнатура: **`init(options)` → `Promise<Instance>`**. |
| Namespace vs **instance** | У модуля **`emailmaker`** — в основном **`init`** (+ именованные ESM-экспорты). **`setConfig`**, **`show`**, **`save`**, **`destroy`** — у **экземпляра** после **`init`**. |
| Повтор на том же DOM | Повторный **`init`** на тот же узел ведёт к **`reset`** — не запускайте два параллельных **`init`** на один контейнер. |
| События | **`instance.handle*(…)`** обычно возвращает **отписку**. **`handleSubjectChanged`** / **`handlePreheaderChanged`** — другая сигнатура (см. типы). |
| Async | Колбэки и **`getAuthToken`** могут быть **`async`**; ошибки — через **`handleError`** или свою логику. |
| Сборка | Без штатного плагина Webpack/Vite задайте **`publicPath`** (**`__emailmaker__`**). Бандл крупный (React, Monaco и др.). |
| Авторизация | **`getAuthToken`** или **`jwtAuth`**; **`client_secret`** только на сервере. |
| Файловый менеджер | **`storageProvider`**, **`config.imageCenterFileManagerView: true`**, при необходимости секция **`config.fileManager`** (**`ExportedApi.FileManagerOptions`**). Контракт **`StorageProvider`** объёмен — сверяйтесь с типами. |
| **`baseUrl`** | Origin API без суффикса `/wp-json` (напр. `https://api.emailmaker.ru` или `https://app.emailmaker.ru/api`); SDK добавляет `/wp-json` сам. |
| **`standaloneKey`** | Режимы с прокси файлов через события (см. код плагина); редкие сценарии. |
| **`commonStyles`** | Опционально на **`init` / `reset`**: объект стилей контента (частичный merge с **`COMMON_STYLES`**). Подробности — **`docs/plugin-content-styles.md`**. |

Примеры в репозитории: **`src/pluginExamples/`** (например **`plugin_default.html`**).

### Для сборщика Webpack

Импортируйте класс и передайте его в `plugins` под тем же именем:

```javascript
const EmailmakerWebpackPlugin = require('@emailmaker/emailmaker/webpack');

module.exports = {
  plugins: [
    new EmailmakerWebpackPlugin({
      // По желанию: outputFolder, modulesPath, publicPath — см. пакет.
    }),
  ],
};
```

### Для сборщика Vite

Импорт только из **scoped-пакета**:

```javascript
import { defineConfig } from 'vite';
import emailmakerVite from '@emailmaker/emailmaker/vite';

export default defineConfig({
  plugins: [
    emailmakerVite({
      // По желанию: outputFolder, modulesPath, publicPath — см. пакет.
    }),
  ],
});
```

## `__emailmaker__`

Плагины Webpack/Vite добавляют в бандл объект **`__emailmaker__ = { publicPath: '...' }`** с базовым URL к чанкам пакета. Вручную менять его обычно не нужно; без штатного плагина задайте **`publicPath`** самостоятельно так, чтобы загрузчик нашёл собранные **`emailmaker.js`** / **`emailmaker-esm.js`**.

Имя класса Webpack-плагина строится из имени приложения в `package.json` (для **`@emailmaker/emailmaker`** это **`EmailmakerWebpackPlugin`**).

# Инициализация

Импортируйте плагин в коде приложения:

```javascript
import * as emailmaker from '@emailmaker/emailmaker';
```

У **`init`** обязательное поле — **`content`** (HTML-строка или объект письма / шаблона). После успешной инициализации методы **`setConfig`**, **`updateConfig`**, **`show`**, **`save`** и др. доступны у **экземпляра**, возвращённого из **`init`** (не у объекта `emailmaker`).

Частые поля верхнего уровня — в таблице; детали конфигурации и содержимого см. ниже в разделе **«Конфигурация»**.

| Поле | Назначение |
| --- | --- |
| **`getAuthToken`** или **`jwtAuth`** | OAuth-колбэк **или** вход по логину/паролю (**`ExportedApi.JWTMixin`** / **`jwtAuth`**). Не смешивайте сценарии без необходимости. |
| **`element`** | Контейнер монтирования (селектор, узел или фрагмент). |
| **`content`** | Обязательно: HTML-строка или объект письма/шаблона. |
| **`config`** | Настройки UI редактора (**`ExportedApi.Config`**). |
| **`project`** | Идентификатор проекта в вашей системе / в EmailMaker. |
| **`baseUrl`** | Origin API без `/wp-json` (см. **`AppInitMixin.Options`**). |
| **`storageProvider`** | Реализация **`StorageProvider`** для файлового менеджера. |
| **`standaloneKey`** | Редкие режимы прокси файлов (**`instance.handleFileProxy`** / **`handleUrlProxy`**). |
| **`commonStyles`** | Объект стилей контента (частичный **merge** с **`COMMON_STYLES`**). См. **`docs/plugin-content-styles.md`**. |

- **`getAuthToken`** — функция **`(user?, project?, prevToken?) => string | Promise<string>`**, возвращающая OAuth access token. **`client_secret`** получайте **только на сервере**.
- **`jwtAuth`** — **`{ email, password, remember? }`** вместо **`getAuthToken`** (см. **`ExportedApi.JWTMixin`** в **`emailmaker.d.ts`**).

Именованные экспорты в ESM-сборке (**`emailmaker-esm.js`**):

```javascript
import { init, parseAMP, COMMON_STYLES, version, helpers, errors } from '@emailmaker/emailmaker';
```

| Экспорт | Назначение |
| --- | --- |
| **`init`** | То же, что **`emailmaker.init`**, с ленивой подгрузкой ядра (**`Promise<Instance>`**). |
| **`parseAMP`** | Разбор AMP: вход — строка или **`{ code }`**, результат **`ParsedAMP`** (html / ampHtml и т.д.). |
| **`COMMON_STYLES`** | Дефолтный пресет стилей контента текущей сборки EmailMaker. Для **`init({ commonStyles: { ...COMMON_STYLES, … } })`**. Исходник с JSDoc: **`src/constants/commonStyles.defaults.ts`**. |
| **`version`** | Строка версии сборки. |
| **`helpers`** | Вспомогательные утилиты (например, соответствие HTTP-статусов кодам ошибок). |
| **`errors`** | Ошибки API, в т.ч. **`errors.FileManagerApiError`** для контракта с файловым менеджером. |

### Получение OAuth токена на бэкенде

```bash
curl --location 'https://api.emailmaker.ru/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=*******' \
--data-urlencode 'client_secret=*******' \
--data-urlencode 'grant_type=client_credentials'
```

Пример **клиентской** функции: токен отдаёт ваш бэкенд (секрет не уходит в браузер):

```javascript
async function getAuthToken(user, project, prevToken) {
  const res = await fetch('/api/your-backend/emailmaker-token', { method: 'POST' });
  const data = await res.json();
  return data.access_token;
}
```

### Создание сущности EmailMaker plugin

Простейший вариант — HTML письма и тема:

```javascript
emailmaker
  .init({
    getAuthToken,
    element: '#test',
    content: {
      subject: 'Тема письма',
      html: `КОД_ПИСЬМА`,
    },
    config: {},
  })
  .then((instance) => {});
```

Вариант с **шаблоном** и внешним id письма:

```javascript
emailmaker
  .init({
    getAuthToken,
    element: '#editor',
    project: 'ключ-проекта-в-вашей-системе',
    content: {
      templateId: 22304,
      email: {
        id: 'crm-email-id-123',
      },
      blocks: [],
    },
    config: {
      theme: 'light',
      // advancedConfigs: { editor: { … }, pro: { … } },
    },
  })
  .then((instance) => {});
```

КОД_ПИСЬМА можно взять из <a href="https://emcdn.ru/plugin/new-email.html" target="_blank">нашего образца</a> или вставить HTML-код своего письма.

### React (обёртка)

Минимальный каркас: монтирование, **`destroy`** при размонтировании.

```tsx
import { useEffect, useRef } from 'react';
import * as emailmaker from '@emailmaker/emailmaker';

export function EmailmakerEditor({
  project,
  templateId,
  getAuthToken,
}: {
  project: string | number;
  templateId: number;
  getAuthToken: NonNullable<Parameters<typeof emailmaker.init>[0]['getAuthToken']>;
}) {
  const rootRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    let instance: Awaited<ReturnType<typeof emailmaker.init>> | undefined;

    (async () => {
      instance = await emailmaker.init({
        getAuthToken,
        element: rootRef.current ?? '#emailmaker-root',
        project,
        content: { email: { id: 'new' }, templateId },
        config: { theme: 'light' },
      });
    })();

    return () => {
      instance?.destroy();
    };
  }, [project, templateId, getAuthToken]);

  return <div id="emailmaker-root" ref={rootRef} style={{ height: '100vh' \}} />;
}
```

# Конфигурация

Конфигурация задаётся объектом с несколькими уровнями вложенности: внешний вид редактора, стартовое содержимое и обработчики событий.

Повторный вызов **`init`** на **тот же DOM-элемент** внутри приводит к **`reset`** с новыми опциями — не запускайте параллельно два **`init`** на один контейнер.

### element

Строка-селектор, **`Element`** или **`DocumentFragment`**: контейнер, куда монтируется редактор. Если элемент не задан, приложение может работать в фоновом режиме без видимого контейнера.

### content

Секция **`content`** задаёт данные для редактора. Варианты:

#### {string}

HTML-разметка письма.

#### {object} параметры письма

```javascript
{
	id?: string; // Уникальный ID письма в вашей системе.
	html?: string; // HTML письма.
	subject?: string; // Тема письма.
	preheader?: string; // Прехедер.
}
```

#### {object} шаблон, блоки, комментарии

```javascript
{
	templateId?: string | number; // ID шаблона в EmailMaker.
	email?: object; // параметры письма (см. выше).
	blocks?: []; // блоки.
	comments?: []; // комментарии к письму.
}
```

Сменить контент после инициализации: **`instance.show(content)`**.

### Стили контента (`commonStyles`)

Не путать с **`config`**: объект **`commonStyles`** передаётся **на верхнем уровне** **`init`** / **`reset`** (тип **`ExportedApi.AppConfigMixin.Options`**).

- **Дефолт из сборки:** именованный экспорт **`COMMON_STYLES`** (см. исходник **`src/constants/commonStyles.defaults.ts`**, там же подробный **JSDoc** для IDE).
- **Частичное переопределение:** можно передать только нужные ветки (например `{ block: { backgroundColor: '#000' } }`) — приложение **сливает** их с **`COMMON_STYLES`**, чтобы панель «Стили контента», iframe и список общих блоков не ломались на «дырах» в объекте.
- **Приоритет:** сохранённое **`email.common_styles`** важнее, чем **`init.commonStyles`**.
- **Сброс** сохранённого в сторе плагина override: **`commonStyles: undefined`** в **`reset`** или **`updateConfig`** (с ключом).
- **Вкладка в UI:** флаг **`config.commonStylesEnabled`** (часто `true` по умолчанию).

Полное описание: **`docs/plugin-content-styles.md`** в репозитории EmailMaker.

### config

Настройки UI редактора. После **`init`** используйте **`instance.setConfig`**, **`instance.updateConfig`** и **`instance.getConfig`** — не методы объекта **`emailmaker`**.

##### Список параметров секции config
| Параметр                               | Описание                                                                    | Значение по умолчанию |
| -------------------------------------- | --------------------------------------------------------------------------- | --------------------- |
| theme                                  | Тема плагина: light, dark.                                                  | light                 |
| autosaveTimeout                        | Задержка перед автосохранением, мс.                                         | 10000                 |
| mergeTags                              | JSON со списком динамических переменных.                                    | undefined             |
| styles                                 | Строка со стилями в формате CSS.                                            | ''                    |
|                                        |                                                                             |                       |
| headerShow                             | Показ шапки.                                                                | true                  |
| headerArrowBackVisible                 | Показ стрелки "Назад".                                                      | true                  |
| headerTitleVisible                     | Показ поля "Тема".                                                          | true                  |
| headerPreheaderVisible                 | Показ поля "Прехедер".                                                      | true                  |
| historyEnabled                         | Показ кнопки "История версий".                                              | true                  |
| codeEnabled                            | Показ кнопки "Code-mode".                                                   | true                  |
| codeModeDirection                      | Режим показа редактора кода по умолчанию                                    | none|left|right|bottom|
| codeSideEnabled                        | Показ кнопки "Code-mode" в режиме, когда есть переключатель десктоп/мобайл. | true                  |
| previewIconEnabled                     | Показ кнопки "Предпросмотр".                                                | true                  |
| previewModeEnabled                     | Ссылка на Предпросмотр.                                                     | true                  |
| livePreviewEnabled                     | Показ кнопки "Тестировние в почтовиках".                                    | true                  |
| sendTestEnabled                        | Показ кнопки "Отправить тест".                                              | true                  |
| sharePreviewEnabled                    | Показ кнопки "Поделиться".                                                  | true                  |
| webversionEnabled                      | Показ ссылки на веб-версию.                                                 | true                  |
| commonStylesEnabled                    | Показ стилей контента.                                                      | true                  |
| emailResponsiveControlEnabled          | Показ переключателя адаптивности письма.                                    | true                  |
| templateNotEmAlertShow                 | Показ уведомления о том, что шаблон не из EM.                               | true                  |
|                                        |                                                                             |                       |
| emailDropdownMenuEnabled               | Показ меню письма.                                                          | true                  |
| emailDropdownMenuClone                 | Показ пункта "Клонировать".                                                 | true                  |
| emailDropdownMenuImport                | Показ пункта "Импортировать".                                               | true                  |
| emailDropdownMenuImportButton          | Показ пункта "Импортировать" кнопкой                                        | true                  |
| emailDropdownMenuLock                  | Показ пункта "Заблокировать".                                               | true                  |
| emailDropdownMenuRemove                | Показ пункта "Удалить".                                                     | true                  |
|                                        |                                                                             |                       |
| emailExportEnabled                     | Показ кнопки "Экспорт".                                                     | true                  |
| exportHtmlEnabled                      | Экспорт в HTML.                                                             | true                  |
| exportZipEnabled                       | Экспорт в ZIP.                                                              | true                  |
| exportClipboardEnabled                 | Экспорт в буфер.                                                            | true                  |
| exportWebHookEnabled                   | Экспорт в вебхук.                                                           | true                  |
| exportOutlookEnabled                   | Экспорт в Outlook.                                                          | true                  |
| exportPdfEnabled                       | Экспорт в PDF.                                                              | true                  |
| exportPngEnabled                       | Экспорт в PNG.                                                              | true                  |
|                                        |                                                                             |                       |
| nextButtonEnabled                      | Показ второстепенной кнопки.                                                | false                 |
| nextButtonText                         | Текст на второстепенной кнопке.                                             | ''                    |
| saveButtonEnabled                      | Показ основной кнопки.                                                      | true                  |
| saveButtonText                         | Текст основной кнопки.                                                      | ''                    |
| commandButtonsEnabled                  | Показ основной и второстепенной кнопки.                                     | true                  |
|                                        |                                                                             |                       |
| sidePanelFloating                      | Плавающая боковая панель.                                                   | true                  |
| desktopMobileSwitchRule                | Полоса переключения режимов.                                                | true                  |
| desktopMobileSwitchPanel               | Панель переключения режимов.                                                | false                 |
| onlyCodeModeInMobile                   | вывод в мобиле только кода.                                                 | false                 |
|                                        |                                                                             |                       |
| pathEnabled                            | Показ хлебных крошек.                                                       | true                  |
| copyPasteEnabled                       | Показ копирования-вставки блока в iframe.                                   | true                  |
| saveBlockEnabled                       | Показ кнопки сохранения блока.                                              | true                  |
| editImageControlEnabled                | Показ кнопки редактирования изображения.                                    | true                  |
|                                        |                                                                             |                       |
| menuDirection                          | Расположение боковой панели.                                                | 'right'               |
| defaultBuildPanel                      | Настройка открывающейся вкладки по умолчанию.                               | ''/'empty'/'project'/'common'/'template'                 |
| commentsEnabled                        | Показ кнопки "Комментарии".                                                 | true                  |
| aiAssistentEnabled                     | Показ "AI ассистента".                                                      | true                  |
| optimizeEnabled                        | Показ кнопки "Оптимизация".                                                 | true                  |
| optimizeLinksEnabled                   | Показ проверки ссылок.                                                      | true                  |
| optimizeImagesEnabled                  | Показ проверки картинок.                                                    | true                  |
| optimizeSpamAssassinEnabled            | Показ проверки SpamAssassin.                                                | true                  |
| optimizeCheckCodeEnabled               | Показ проверки кода.                                                        | true                  |
| settingsEnabled                        | Показ кнопки "Настройки".                                                   | true                  |
| UTMEnabled                             | Показ таба UTM-метки.                                                       | true                  |
| descriptionEnabled                     | Показ поля "Описание" в настройках.                                         | true                  |
| tagsEnabled                            | Показ поля Теги в настройках.                                               | true                  |
| switchDesktopMobilePropsEnabled        | Показ переключателя мобильных свойств.                                      | true                  |
| stepToOtherElementEnabled              | Показ кнопок перехода к другим элементам.                                   | true                  |
| deleteButtonEnabled                    | Показ кнопки удаления элемента.                                             | true                  |
| toggleSidePanel                        | Возможность схлопывать боковую панель.                                      | true                  |
| blocksSectionsShow                     | Показ меню блоков.                                                          | true                  |
| blocksEmptyEnabled                     | Показ пустых блоков.                                                        | true                  |
| blocksSavedEnabled                     | Показ сохранённых блоков.                                                   | true                  |
| blocksCommonEnabled                    | Показ общих блоков.                                                         | true                  |
| blocksTemplateEnabled                  | Показ блоков шаблона.                                                       | true                  |
| blocksSearchEnabled                    | Показ поиска по блокам.                                                     | true                  |
| blocksAddPanelEnabled                  | Показ панели добавления блока в визуальном редакторе.                       | true                  |
| imagePathDropdownEnabled               | Показ выпадашки с путём к изображению.                                      | true                  |
|                                        |                                                                             |                       |
| formFieldImageTitleEnabled             | Показ поля title в форме картинки.                                          | true                  |
| formFieldBorderEnabled                 | Показ полей изменения рамки.                                                | true                  |
| formFieldBorderRadiusEnabled           | Показ полей изменения скругления.                                           | true                  |
| formFieldBoxShadowEnabled              | Показ полей изменения тени.                                                 | true                  |
| formFieldVisibilityEnabled             | Показ кнопок изменения видимости элемента.                                  | true                  |
| formFieldExportAsPictureEnabled        | Показ переключателя экспорт в картинку.                                     | true                  |
|                                        |                                                                             |                       |
| formButtonFieldInsertImageEnabled      | Показ кнопки вставки изображения в текст у кнопки.                          | true                  |
| formButtonFieldVerticalAlignEnabled    | Показ кнопок вертикального выравнивания у кнопки.                           | true                  |
| formButtonFieldTextAlignEnabled        | Показ кнопок выравнивания текста у кнопки.                                  | true                  |
| formButtonFieldBackgroundImageEnabled  | Показ полей фонового изображения у кнопки.                                  | true                  |
| formButtonFieldPaddingsEnabled         | Показ полей внутренних отступов у кнопки.                                   | true                  |
| formButtonFieldReplacerEnabled         | Показ реплейсера у кнопки.                                                  | true                  |
|                                        |                                                                             |                       |
| formCellFieldVerticalAlignEnabled      | Показ кнопок вертикального выравнивания у ячейки.                           | true                  |
| formCellFieldBackgroundImageEnabled    | Показ полей фонового изображения у ячейки.                                  | true                  |
| formCellFieldPaddingsEnabled           | Показ полей внутренних отступов у ячейки.                                   | true                  |
| formCellFieldSizeEnabled               | Показ полей ширины и высоты.                                                | true                  |
|                                        |                                                                             |                       |
| formImageFieldVerticalAlignEnabled     | Показ кнопок вертикального выравнивания у картинки.                         | true                  |
| formImageFieldReplacerEnabled          | Показ кнопок вертикального выравнивания у картинки.                         | true                  |
| formImageFieldHeightEnabled            | Показ поля высоты у картинки.                                               | true                  |
|                                        |                                                                             |                       |
| formTableFieldBackgroundImageEnabled   | Показ полей фонового изображения у таблицы.                                 | true                  |
| formDivFieldBackgroundImageEnabled     | Показ полей фонового изображения у контейнера.                              | true                  |
| formEmailFieldBackgroundImageEnabled   | Показ полей фонового изображения у письма.                                  | true                  |
|                                        |                                                                             |                       |
| formTextFieldTypografEnabled           | Показ кнопки типографа.                                                     | true                  |
| formTextFieldReplacerEnabled           | Показ кнопки реплейсера.                                                    | true                  |
|                                        |                                                                             |                       |
| elementImageEnabled                    | Элемент Картинка.                                                           | true                  |
| elementTextEnabled                     | Элемент Текст.                                                              | true                  |
| elementHeaderEnabled                   | Элемент Заголовок.                                                          | true                  |
| elementButtonEnabled                   | Элемент Кнопка.                                                             | true                  |
| elementListULEnabled                   | Элемент Список UL.                                                          | true                  |
| elementListOLEnabled                   | Элемент Список OL.                                                          | true                  |
| elementDividerEnabled                  | Элемент Разделитель.                                                        | true                  |
| elementSpacerEnabled                   | Элемент Отступ.                                                             | true                  |
| elementSocialEnabled                   | Элемент Соцсети                                                             | true                  |
| elementTableEnabled                    | Элемент Таблица.                                                            | true                  |
| elementCountdownEnabled                | Элемент Счётчик.                                                            | true                  |
| elementVideoEnabled                    | Элемент Видео.                                                              | true                  |
| elementAIimageEnabled                  | Элемент AI картинка.                                                        | true                  |
| elementAItextEnabled                   | Элемент AI текст.                                                           | true                  |
| elementCarouselEnabled                 | Элемент AMP карусель.                                                       | true                  |
| elementAccordionEnabled                | Элемент AMP аккордион.                                                      | true                  |
| elementFormEnabled                     | Элемент AMP форма.                                                          | true                  |
|                                        |                                                                             |                       |
| imageCenterLocalUploadEnabled          | Поле загрузки файла с компьютера в Image Center.                            | true                  |
| imageCenterStockEnabled                | Таб Стока фотографий.                                                       | true                  |
| imageCenterGifEnabled                  | Таб Стока гифок.                                                            | true                  |
| imageCenterEditorEnabled               | Таб редактора изображений.                                                  | true                  |
| compressMaxSize                        | Макс. размер файла для клиентского сжатия в файловом менеджере, байт (по умолчанию порядка 5 MiB). | см. типы |
| compressMaxWidthOrHeight               | Макс. ширина/высота после ресайза, px (по умолчанию 2000).                   | см. типы |

### Обработка событий

Обработчики передаются в **`init({ ... })`** или подписываются на экземпляре: **`instance.handle*(listener, priority?)`**. Подписка обычно возвращает **функцию отписки**. Обработчики могут быть **`async`**.

События **`handleSaveEmail`**, **`handleSaveBlock`**, **`handleSaveComment`** получают **не сырой объект**, а **`SaveEventPayload`**: **`{ patch, value, prev?, source? }`** — полезно сравнивать **`patch`** и итоговое **`value`**.

**`handleSubjectChanged`** и **`handlePreheaderChanged`** оформлены иначе: через них подписываются на строковые значения темы и прехедера — см. **`emailmaker.d.ts`**.

#### Пример

```javascript
emailmaker.init({
  element: '#test',
  content: { email: { id: '1' } },
  getAuthToken,
  handleReadEmail: async (id) => fetchEmail(id),
  handleSaveEmail: async (payload) => saveEmail(payload.value),
}).then((instance) => {
  const unsubscribe = instance.handleEmailChanged(async () => {
    /* ... */
  });
  /* unsubscribe(); */
});
```

### События

| Обработчик | Описание |
| ---------- | -------- |
| handleReadEmail | Загрузка письма по id с вашего API (**аргумент — строка id**). |
| handleSaveEmail | Сохранение письма; полезная нагрузка — **`SaveEventPayload`** с **`value`** и **`patch`**. |
| handleRemoveEmail | Удаление письма. |
| handleReadEmailRevisions | Список автосохранений / ревизий для письма. |
| handleEmailAutosave | Создано автосохранение (**`EmailRevision`**). |
| handleRemoveEmailAutoSave | Удалено автосохранение. |
| handleReadBlocks | Список блоков проекта. |
| handleReadCommonBlocks | Общие блоки. |
| handleReadTemplateBlocks | Блоки шаблона в контексте письма. |
| handleSaveBlock | Сохранение блока (**`SaveEventPayload`**). |
| handleRemoveBlock | Удаление блока. |
| handlePropagateGlobalBlock | Обновление шаблона глобального блока из iframe (**`{ emBlockId, blockHtml }`**). |
| handleReadComments | Комментарии к письму. |
| handleSaveComment | Сохранение комментария. |
| handleRemoveComment | Удаление комментария. |
| handleSaveButtonClick | Клик по основной кнопке (например «Сохранить»). |
| handleNextButtonClick | Клик по «Далее». |
| handlePreviousButtonClick | Клик «Назад» в шапке. |
| handleEmailInit | Инициализирован контур письма. |
| handleEmailChanged | Изменился параметр письма. |
| handleHtmlChanged | Изменился HTML-код. |
| handleSubjectChanged | Изменилась тема (особая подпись — см. типы). |
| handlePreheaderChanged | Изменился прехедер (особая подпись — см. типы). |
| handleCloneEmail | Клонирование письма. |
| handleShareEmail | Поделиться. |
| handleLivePreviewEmail | Живой предпросмотр. |
| handlePreviewEmail | Предпросмотр. |
| handleValidate | Результат проверки кода (**`CodeError[]`**). |
| handleTestEmailSend | Отправка тестового письма. |
| handleTestEmailModal | Открыто окно тестовой отправки. |
| handleDestroy | Перед уничтожением экземпляра. |
| handleLoad | Завершена загрузка экземпляра; можно безопасно вызывать **`getEmail`** и др. |
| handleLoadImage | Загрузка изображения пользователем; **`handleFileProxy`**, **`handleUrlProxy`** — прокси файлов/URL при необходимости. |
| handleNotify | Произвольное уведомление. |
| handleError | Ошибка (можно переопределить UI). |
| handleSuccess | Успешная операция. |
| handleReadLocale | Язык интерфейса (**`AppConfigMixin`**). |
| handleTranslate | Пользовательский перевод строк. |
| handleLimitUsage | Отображение квот / лимитов. |

Полный перечень и сигнатуры — в **`emailmaker.d.ts`** (**`ExportedApi.DataMixin.Events`** и смежные миксины).

### Методы

Модуль экспортирует **`init`** (и именованные символы в ESM). Остальное — методы **экземпляра** после **`await emailmaker.init(...)`**.

| Метод | Описание |
| ----- | -------- |
| init | Асинхронная инициализация: **`Promise<Instance>`**. |
| show | Подмена контента (**строка или объект `Content`**). |
| save | Сохранить текущее письмо по цепочке приложения. |
| getEmail | Текущее письмо; для скомпилированных полей см. **`compileEmail`** / **`CompiledEmail`**. |
| compileEmail | Явная компиляция HTML/AMP/текста; опционально **`email`** и флаги форматов. |
| setEmailMeta | Обновить **`meta`** текущего письма без полной замены. |
| setBlockMeta | Обновить **`meta`** блока в кэше blocks DataSource по **`blockId`**. |
| getBlocks | Блоки в текущем контексте (**`Block.meta`** round-trip при own-property). |
| getComments | Комментарии. |
| getEmailRevisions | Ревизии / автосохранения. |
| getCodeErrors | Ошибки линтера кода в редакторе. |
| getConfig | Текущий **`config`**. |
| setConfig | Полная замена настроек UI. |
| updateConfig | Глубокое слияние с текущим **`config`**. |
| notify | Показать уведомление (строка или объект). |
| getElement | DOM-узел или фрагмент монтирования. |
| destroy | Уничтожить экземпляр (вызывайте при размонтировании в SPA). |
| reset | Переинициализация с новыми **`Options`** (**`Promise<Instance>`**). |
| undoRedoService | Сервис отмены/повтора (**`undo`**, **`redo`**, снимки истории и др.). |

### 📂 Файловый менеджер

Для включения файлового менеджера необходимо в конфигурации инициализации указать параметры:

```ts
emailmaker.init({
  storageProvider: ..., // реализация интерфейса StorageProvider
  config: {
    imageCenterFileManagerView: true
  }
});
```

Секция `fileManager` управляет возможностями файлового менеджера. Все поля необязательные; если не заданы или `false`, соответствующая функция отключена.

#### Basic Operations

- **enableTrash** — включает функциональность корзины для удаленных файлов. При включении файлы перемещаются в корзину вместо полного удаления. По умолчанию true
- **enableRenameFolder** — разрешает переименование папок. По умолчанию true
- **enableRenameFile** — разрешает переименование файлов. По умолчанию true
- **enableUpdateFile** — разрешает обновление содержимого или метаданных файлов. По умолчанию true
- **enableEdit** — разрешает редактирование файлов (изменение содержимого или свойств). По умолчанию true
- **enableMoveFile** — разрешает перемещение файлов между папками. По умолчанию true
- **enableMoveFolder** — разрешает перемещение папок. По умолчанию true
- **enableCopyFile** — разрешает копирование файлов. По умолчанию true
- **enableCopyFolder** — разрешает копирование папок. По умолчанию true
- **enableDelete** — разрешает удаление файлов и папок. При включенной корзине файлы перемещаются в корзину. По умолчанию true
- **multiSelect** — разрешает множественный выбор файлов и папок для групповых операций. По умолчанию true
- **defaultFolderName** — Имя папки по умолчанию
- **sortOptions** — белый список значений сортировки в дропдауне списка файлов (`'date-desc' \| 'date-asc' \| 'size-desc' \| 'size-asc' \| 'name-asc' \| 'name-desc' \| 'type-asc'`). Если не задан или массив пустой — доступны все варианты, которые отображает file-manager. Пример: `['date-desc', 'name-asc']` — скрыть сортировки по размеру и типу, если платформа их не реализует.

#### Pagination & Display

- **enablePagination** — разрешает постраничную навигацию. Если отключено, все элементы загружаются сразу. По умолчанию true

#### Client-Side Processing

- **clientSideSorting** — клиентская сортировка файлов.
  - Если `true`, применяется стандартная сортировка (по имени по возрастанию).
  - Если указана функция, она принимает текущий массив файлов, необязательные `sortBy` и `sortOrder`, и возвращает отсортированный массив.

- **clientSidePaging** — клиентская пагинация файлов.
  - Если `true`, применяется стандартная нарезка массива по `page` и `limit`.
  - Если указана функция, она принимает массив файлов, `page` и `limit`, и возвращает массив только для нужной страницы.

- **clientSideFilter** — клиентская фильтрация файлов.
  - Если `true`, применяется стандартная фильтрация по тексту `search`.
  - Если указана функция, она принимает массив файлов и необязательный `search`, и возвращает отфильтрованный массив.

#### Cache Strategy

- **cacheStrategy** — стратегия кэширования для оптимизации производительности.
  - **ttl** — время жизни кэша в миллисекундах. По умолчанию 300000 (5 минут)
  - **errorTtl** — время жизни кэша для ошибок в миллисекундах. По умолчанию 60000 (1 минута)
  - **allowSortedInsert** — разрешает вставку элемента в отсортированный массив без полной инвалидации кэша. По умолчанию false
  - **allowSearchInsert** — разрешает вставку элемента в массив с фильтрами без полной инвалидации кэша. По умолчанию false
  - **invalidateOnPaginationFull** — если страница полная, кэш помечается как устаревший при вставке нового элемента. По умолчанию true
  - **comparator** — функция сравнения двух файлов для сортировки. По умолчанию сравнение по имени
  - **filterMatch** — функция проверки, проходит ли файл текущий фильтр. По умолчанию поиск по имени

### Интерфейс `StorageProvider`

#### Свойства

| Свойство                    | Тип       | Описание                                                    | По умолчанию |
| --------------------------- | --------- | ----------------------------------------------------------- | ------------ |
| `pathMode`                  | `boolean` | Использовать путь как идентификатор для папок               | -            |
| `rootId`                    | `string`  | Пользовательский идентификатор корневой папки               | `''`         |
| `trashPath`                 | `string`  | Путь к корзине/папке для удаленных файлов                   | -            |
| `tempPath`                  | `string`  | Путь к временной папке для загрузок                         | -            |
| `useSoftDelete`             | `boolean` | Включить программное мягкое удаление                        | `false`      |
| `ensureFolderTrailingSlash` | `boolean` | Добавлять к путям папок завершающий слэш                    | `true`       |
| `validateDuplicates`        | `boolean` | Проверка на существование при операциях с файлами и папками | -            |

#### Методы

##### Основные методы

| Метод               | Параметры                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Возвращает                                                                 | Описание                                                                                                              |
| ------------------- |   | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **getItems**        | `options`:<br>- `folderId?: string`<br>- `search?: string`<br>- `sortBy?: string`<br>- `sortOrder?: 'asc'\|'desc'`<br>- `page?: number`<br>- `limit?: number`<br>- `itemType: 'all'\|'file'\|'folder'`                                                                                                                                                                                                                                                                                                                                                                                                                                   | `{ items: FileSystemItem[], pagination?: Partial<ApiPaginationResponse> }` | Получить список файлов и папок с фильтрацией, сортировкой, пагинацией                                                 |
| **createFolder**    | `name: string`, `parentid?: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | `FileSystemItem`                                                           | Создать новую папку                                                                                                   |
| uploadFile          | `file`: <br>- `name: string`<br>- `size: number`<br>- `type: string`<br>- `folderId?: string`<br>- `data: Blob \| string`<br>- `thumbnail?: string`<br>- `dimensions?: string`<br>- `aspectRatio?: string`<br>- `extension?: string`                                                                                                                                                                                                                                                                                                                                                                                                     | `FileSystemItemUpdate`                                                     | Загрузить файл с метаданными                                                                                          |
| uploadFiles         | `request`:<br>- `items`: массив объектов:<br>&nbsp;&nbsp;&nbsp;&nbsp;- `requestId?: string` — необязательный идентификатор для сопоставления результата<br>&nbsp;&nbsp;&nbsp;&nbsp;- `name: string` — имя файла<br>&nbsp;&nbsp;&nbsp;&nbsp;- `size: number` — размер файла в байтах<br>&nbsp;&nbsp;&nbsp;&nbsp;- `type: string` — MIME-тип файла<br>&nbsp;&nbsp;&nbsp;&nbsp;- `folderId?: string \| null` — целевая папка<br>&nbsp;&nbsp;&nbsp;&nbsp;- `data: Blob \| string` — содержимое файла<br>&nbsp;&nbsp;&nbsp;&nbsp;- `extension?: string` — расширение файла<br>- `folderId?: string \| null` — папка для загрузки по умолчанию | `BatchResult<UploadFileResultData>`                                        | Загрузить несколько файлов. Порядок элементов важен — при отсутствии `requestId` результаты сопоставляются по индексу |
| **uploadFileByUrl** | `url: string`, `folderId?: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | `FileSystemItem`                                                           | Загрузить файл по URL (проверять существующие файлы)                                                                  |
| `findItemByPath`    | `path: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | `FileSystemItem \| undefined`                                              | Найти системные файлы/папки по пути                                                                                   |
| `setController`     | `controller: StorageProviderController`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | `void`                                                                     | Установить контроллер управления кэшем                                                                                |
| `getFileData`       | `file: FileSystemItem`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | `Blob`                                                                     | Получить содержимое файла как blob                                                                                    |
| `getUrl`            | `file: FileSystemItem`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | `string`                                                                   | Получить URL для доступа к файлу                                                                                      |
| `getThumbnailUrl`   | `file: FileSystemItem`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | `string`                                                                   | Получить URL миниатюры                                                                                                |
| `renameItem`        | `item: FileSystemItem`, `newName: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | `FileSystemItemUpdate`                                                     | Переименовать файл/папку                                                                                              |
| `deleteItem`        | `item: FileSystemItem`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | `void`                                                                     | Удалить один элемент (перемещает в корзину при мягком удалении)                                                       |
| `deleteItems`       | `items: FileSystemItem[]`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | `BatchResult<never>`                                                       | Удалить несколько элементов                                                                                           |
| `moveItem`          | `item: FileSystemItem`, `targetFolderId?: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `FileSystemItemUpdate`                                                     | Переместить один элемент                                                                                              |
| `moveItems`         | `items: FileSystemItem[]`, `targetFolderId?: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | `BatchResult<FileSystemItemUpdate>`                                        | Переместить несколько элементов                                                                                       |
| `copyItem`          | `item: FileSystemItem`, `targetFolderId?: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | `FileSystemItemUpdate`                                                     | Копировать один элемент                                                                                               |
| `copyItems`         | `items: FileSystemItem[]`, `targetFolderId?: string`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | `BatchResult<FileSystemItemUpdate>`                                        | Копировать несколько элементов                                                                                        |
| `updateFile`        | `file: FileSystemItem`, `updates`: объект с метаданными                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | `FileSystemItemUpdate`                                                     | Обновить метаданные/содержимое файла                                                                                  |

##### Определения типов

- **`MayBePromise<T>`**: `T | Promise<T>`
- **`FileSystemItem`**: Объект файла или папки
- **`FileSystemItemUpdate`**: Элемент с измененными полями
- **`BatchResult<T>`**: Результат с деталями успеха/ошибки
- **`ApiPaginationResponse`**: Метаданные пагинации

##### Важные примечания

- **Мягкое удаление**: Когда `useSoftDelete=true`, операции удаления перемещают элементы в `trashPath`
- **Корневая папка**: Используйте `rootId` или пустую строку для операций с корневой папкой
- **Разрешение путей**: `trashPath` и `tempPath` преобразуются в реальные идентификаторы папок
- **Загрузка по URL**: Должна проверять, существует ли файл уже на текущем сервере
- **Управление кэшем**: Используйте `setController` для запросов инвалидации кэша
- **Двойное мягкое удаление**: Если бэкенд уже реализует мягкое удаление, оставьте `useSoftDelete=false`
