@emailmaker/extensions-react 1.1.95 → 1.1.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -9
- package/externals.json +4 -4
- package/index.js +124 -74
- package/package.json +4 -4
- package/types.d.ts +9 -0
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ npm install @emailmaker/emailmaker @emailmaker/extensions-app @emailmaker/extens
|
|
|
79
79
|
|
|
80
80
|
| Пакет | Назначение | Что экспортирует |
|
|
81
81
|
|-------|------------|------------------|
|
|
82
|
-
| `@emailmaker/emailmaker` | Основной пакет | `init()`, `
|
|
82
|
+
| `@emailmaker/emailmaker` | Основной пакет | `init()`, `preload()`, типы `IPlugin`, `Instance`; runtime React/Ant Design — subpath `@emailmaker/emailmaker/runtime/*` (отдельный npm не нужен) |
|
|
83
83
|
| `@emailmaker/extensions-app` | API для app-плагинов | `pluginRegistry`, `DomComponentRegistry`, `ElementsApi`, `SettingsPanelApi`, `ModalApi` |
|
|
84
84
|
| `@emailmaker/extensions-react` | React API для плагинов | `ComponentRegistry`, `createComponentIdentifier()` |
|
|
85
85
|
| `@emailmaker/extensions-sandbox` | API для sandbox-плагинов | `App`, `MessageService`, `SyncService` |
|
|
@@ -205,6 +205,11 @@ module.exports = {
|
|
|
205
205
|
- `встраиваемый bundle` -> `globals`
|
|
206
206
|
- `advanced` -> только если host уже требует async/globals контракт Webpack
|
|
207
207
|
|
|
208
|
+
`globals` читает зависимости из глобального реестра **синхронно**, когда выполняется скрипт
|
|
209
|
+
плагина. Хост готовит реестр сам, если грузит плагин по URL через `init()` или `useAsync()`; при
|
|
210
|
+
ручной вставке `<script>` дождитесь `preload()` — подробности в разделе
|
|
211
|
+
`Подключение плагина`.
|
|
212
|
+
|
|
208
213
|
Для `встраиваемый bundle` и `advanced` рекомендуемый runtime-контракт — descriptor вида `{ type: 'umd', url, name, resolve: 'registry' }`, где `name` совпадает с ключом из `PluginTypeMap`.
|
|
209
214
|
|
|
210
215
|
### Ручная настройка (без PluginDev)
|
|
@@ -212,9 +217,16 @@ module.exports = {
|
|
|
212
217
|
Нужна только для продвинутой интеграции или собственного бандлерного пайплайна. Основной сценарий для внешнего плагина — отдельный пакет с `PluginDev`.
|
|
213
218
|
|
|
214
219
|
- `resolve.alias`: `react` → `@emailmaker/emailmaker/runtime/react` (и т.д.) для `esm` / dev; локальные shared internals идут через compat facades runtime; UI-kit (`@emailmaker/ui-kit`) → **`@emailmaker/emailmaker/ui-kit`** (singleton bytes на main, не `runtime/@scope/ui-kit`)
|
|
215
|
-
- `externals`: `@emailmaker/emailmaker/runtime
|
|
220
|
+
- `externals`: `@emailmaker/emailmaker/runtime-core`, runtime npm-модули; ui-kit external → **`@emailmaker/emailmaker/ui-kit`** (глобальный ключ `UiKit` в `runtimeExports`, см. манифест)
|
|
216
221
|
- Список модулей: `@emailmaker/emailmaker/runtime/plugin-dev-manifest.json` → `runtimeModules`
|
|
217
222
|
|
|
223
|
+
**Иконки — особый случай.** Общим (singleton) обязан быть только класс
|
|
224
|
+
`@ant-design/icons/es/components/AntdIcon`: он вычисляет иконку, читая `IconContext`, и вторая его
|
|
225
|
+
копия сломает тему. Сам каталог из восьми с лишним сотен определений singleton'ом не является —
|
|
226
|
+
каждый потребитель берёт его себе и вытрясает неиспользуемое. Поэтому обычный
|
|
227
|
+
`import { UserOutlined } from '@ant-design/icons'` в плагине законен: в сборку попадут только взятые
|
|
228
|
+
иконки, а общая машинерия придёт из продукта. `PluginDev` разводит эти два случая сам.
|
|
229
|
+
|
|
218
230
|
Если release bundle неожиданно стал толстым или target `встраиваемый bundle` не загружается, начните с раздела `Troubleshooting`.
|
|
219
231
|
|
|
220
232
|
Типы для плагина всё равно собираются отдельно: CLI-шаблон запускает `build:types` и кладёт `dist/public-types.d.ts` рядом с JS bundle, поэтому TypeScript support сохраняется и для browser/advanced targets.
|
|
@@ -248,6 +260,114 @@ import { ComponentRegistry } from '@emailmaker/extensions-react';
|
|
|
248
260
|
> Обычно достаточно использовать готовый шаблон CLI и не настраивать alias/external вручную.
|
|
249
261
|
|
|
250
262
|
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
# Совместимость: как плагин встречается с редактором
|
|
266
|
+
|
|
267
|
+
Одна страница на вопрос «что с чем работает». Всё остальное в этом разделе — подробности.
|
|
268
|
+
|
|
269
|
+
## Главное правило
|
|
270
|
+
|
|
271
|
+
Плагин и редактор обязаны использовать **один экземпляр** React, antd и ui-kit. Не потому, что так
|
|
272
|
+
аккуратнее: компоненты плагина рисуются внутри дерева редактора, и если экземпляры разные, хуки
|
|
273
|
+
вызываются против чужого диспетчера. На странице это выглядит как
|
|
274
|
+
`Cannot read properties of null (reading 'useState')` — падает не панель плагина, а весь интерфейс.
|
|
275
|
+
|
|
276
|
+
Сводить их вручную не нужно: этим занимается `PluginDev` в сборке плагина.
|
|
277
|
+
|
|
278
|
+
## Формат плагина × способ подключения
|
|
279
|
+
|
|
280
|
+
| Формат плагина | Как подключается | Где берёт React, antd, ui-kit |
|
|
281
|
+
|---|---|---|
|
|
282
|
+
| **ESM** (npm-пакет, собирается вместе с хостом) | импортом: `plugins: [MyPlugin]` или `useAsync(() => import(…))` | `PluginDev` переписывает импорты на подпути продукта |
|
|
283
|
+
| **UMD / globals** (файл по URL) | `{ type: 'umd', url, name, resolve: 'registry' }` | из реестра `window.emailmaker.modules` на странице |
|
|
284
|
+
| ~~**ESM по URL**~~ | **не поддерживается** | — |
|
|
285
|
+
|
|
286
|
+
**Почему `{ type: 'esm', url }` не работает.** В собранном ESM-плагине остаются имена подпутей
|
|
287
|
+
продукта (`@emailmaker/emailmaker/runtime/*`). Браузеру разрешать их нечем: карту импортов
|
|
288
|
+
продукт не выдаёт. Плагин в формате ESM подключают как npm-пакет, собирая вместе с хостом.
|
|
289
|
+
|
|
290
|
+
## Что приходит из продукта, а что собирается в плагин
|
|
291
|
+
|
|
292
|
+
| Зависимость | Откуда берётся | Почему так |
|
|
293
|
+
|---|---|---|
|
|
294
|
+
| `react`, `react-dom` | из продукта (`@emailmaker/emailmaker/runtime/react`) | один диспетчер хуков на страницу |
|
|
295
|
+
| `antd` | из продукта | контексты темы и формы общие |
|
|
296
|
+
| `@emailmaker/ui-kit` | из продукта (`@emailmaker/emailmaker/ui-kit`) | общий `ThemeProvider`, стили вставляются один раз |
|
|
297
|
+
| `@ant-design/icons` — **класс `AntdIcon`** | из продукта | читает `IconContext`; вторая копия ломает тему |
|
|
298
|
+
| `@ant-design/icons` — **каталог иконок** | собирается в плагин | каждый берёт только те иконки, что использует |
|
|
299
|
+
| всё остальное | собирается в плагин | к общему состоянию отношения не имеет |
|
|
300
|
+
|
|
301
|
+
## Как проверить, что всё сошлось
|
|
302
|
+
|
|
303
|
+
Сборка хоста сама скажет, если в граф попала вторая копия React или ui-kit: плагин хоста
|
|
304
|
+
(Vite/webpack) печатает предупреждение с именем файла-виновника и обоими путями. Молчание на сборке
|
|
305
|
+
— признак того, что копии сведены.
|
|
306
|
+
|
|
307
|
+
Плагин **на глобалах** при этом ничего не импортирует и в графе не появляется: он берёт зависимости
|
|
308
|
+
из реестра уже на странице, и проверять там нечего.
|
|
309
|
+
|
|
310
|
+
## Вход редактора тоже участвует
|
|
311
|
+
|
|
312
|
+
Редактор подключают двумя способами, и не с каждым работает ESM-плагин:
|
|
313
|
+
|
|
314
|
+
| Вход редактора | ESM-плагин | Плагин на глобалах |
|
|
315
|
+
|---|---|---|
|
|
316
|
+
| **ESM** (собирается вместе с хостом) | да | да |
|
|
317
|
+
| **UMD** (`<script>` на странице) | **нет** | да |
|
|
318
|
+
|
|
319
|
+
**Почему UMD-вход и ESM-плагин не сходятся.** UMD-вход несёт React внутри себя и объявляет его на
|
|
320
|
+
странице сам. ESM-плагин собирает ваш сборщик, и подпуть `@emailmaker/emailmaker/runtime/react`
|
|
321
|
+
он разрешает в копию внутри пакета. Это два разных файла с двумя диспетчерами хуков — тот самый
|
|
322
|
+
`Cannot read properties of null (reading 'useState')`, падающий вместе со всем интерфейсом.
|
|
323
|
+
|
|
324
|
+
Сборка про это молчать обязана: UMD-редактор подключён скриптом и в граф сборки хоста не входит, а
|
|
325
|
+
в момент сборки плагина ещё неизвестно, какой вход выберет хост. Поэтому **редактор говорит сам** —
|
|
326
|
+
при инициализации он сверяет копии и, найдя вторую, пишет в консоль, что нашёл и как это чинить.
|
|
327
|
+
|
|
328
|
+
Чинится любым из двух способов: собрать плагин **на глобалах** — тогда он возьмёт React из реестра
|
|
329
|
+
`window.emailmaker.modules` на странице, — либо подключить **ESM-вход** редактора и
|
|
330
|
+
собрать оба одним сборщиком.
|
|
331
|
+
|
|
332
|
+
## Что бывает, если собрать плагин без `PluginDev`
|
|
333
|
+
|
|
334
|
+
Плагин соберётся, сборка хоста пройдёт — и редактор упадёт на странице. Ровно этот случай:
|
|
335
|
+
|
|
336
|
+
- в плагине остались `import 'react'` и `import '@emailmaker/ui-kit'` как есть;
|
|
337
|
+
- сборщик хоста разрешил их из `node_modules` проекта — это **вторые** копии;
|
|
338
|
+
- редактор при этом работает на своих, вендоренных.
|
|
339
|
+
|
|
340
|
+
Лечится добавлением `PluginDev` в конфигурацию сборки плагина (`externals: 'esm'`) либо сборкой
|
|
341
|
+
плагина на глобалах.
|
|
342
|
+
|
|
343
|
+
## Ваши настройки резолва редактора не касаются
|
|
344
|
+
|
|
345
|
+
Внутри пакета React адресуется **путём** к копии, которая лежит в нём же, а не именем `react`.
|
|
346
|
+
Следствий два, и оба в вашу пользу:
|
|
347
|
+
|
|
348
|
+
- `resolve.dedupe`, `resolve.alias`, `resolve.modules` и Module Federation `shared` работают у вас
|
|
349
|
+
так, как вы их написали. Мы не занимаем имя `react` и ничего у вас не перехватываем.
|
|
350
|
+
- Редактор не зависит от того, что вы с этим именем делаете: своя копия достаётся ему при любой
|
|
351
|
+
конфигурации сборки, в том числе если наш плагин у вас не подключён.
|
|
352
|
+
|
|
353
|
+
Одно исключение — `sharedReact` ниже: им вы просите обратного.
|
|
354
|
+
|
|
355
|
+
## Общий React (необязательно)
|
|
356
|
+
|
|
357
|
+
Плагин хоста умеет обратное: отдать редактору **ваш** React вместо вендоренного —
|
|
358
|
+
`VitePlugin({ sharedReact: true })` или `new WebpackPlugin({ sharedReact: true })`.
|
|
359
|
+
|
|
360
|
+
| | по умолчанию | `sharedReact: true` |
|
|
361
|
+
|---|---|---|
|
|
362
|
+
| React редактора | свой, внутри пакета | ваш |
|
|
363
|
+
| требования к вашему React | нет | мажорная версия 19 |
|
|
364
|
+
| Strict Mode и dev-сборка React | не касаются редактора | касаются |
|
|
365
|
+
| antd | свой, внутри пакета | свой, внутри пакета |
|
|
366
|
+
| вес поставки | как есть | меньше примерно на 98 КБ gzip |
|
|
367
|
+
|
|
368
|
+
Версия проверяется до сборки: несовпадение мажора будет названо в предупреждении.
|
|
369
|
+
|
|
370
|
+
|
|
251
371
|
---
|
|
252
372
|
|
|
253
373
|
## 📂 PublicPath
|
|
@@ -444,12 +564,17 @@ emailmaker.init({
|
|
|
444
564
|
```ts
|
|
445
565
|
emailmaker.init({
|
|
446
566
|
plugins: [
|
|
447
|
-
{ type: 'esm', url: 'https://cdn.example.com/my-plugin.js' },
|
|
448
567
|
{ type: 'umd', url: 'https://cdn.example.com/my-plugin.umd.js', name: 'MyPlugin', resolve: 'registry' },
|
|
449
568
|
]
|
|
450
569
|
});
|
|
451
570
|
```
|
|
452
571
|
|
|
572
|
+
> **По URL работает `umd` с `resolve: 'registry'`.** Вариант `{ type: 'esm', url }` в браузере не
|
|
573
|
+
> поддерживается: в собранном ESM-плагине остаются имена подпутей продукта
|
|
574
|
+
> (`@emailmaker/emailmaker/runtime/*`), а разрешить их браузеру нечем — карту импортов
|
|
575
|
+
> продукт не выдаёт. ESM-плагин подключают как npm-пакет: способами 1 и 2 выше, собирая его вместе
|
|
576
|
+
> с хостом.
|
|
577
|
+
|
|
453
578
|
| Параметр | Описание |
|
|
454
579
|
|----------|----------|
|
|
455
580
|
| `type` | `'esm'` — ESM модуль (`import()`), `'umd'` — UMD/IIFE (`<script>`) |
|
|
@@ -457,6 +582,30 @@ emailmaker.init({
|
|
|
457
582
|
| `name` | Для `resolve: 'registry'` — строковый ключ из `PluginTypeMap`; для legacy `umd`/`window` — ключ в `window` |
|
|
458
583
|
| `resolve` | Опционально. `'module'` (default ESM), `'window'` (legacy default UMD), `'registry'` |
|
|
459
584
|
|
|
585
|
+
#### Кто готовит runtime до запуска скрипта
|
|
586
|
+
|
|
587
|
+
Плагин, собранный под `globals` (targets `встраиваемый bundle` и `advanced`), читает
|
|
588
|
+
`window.__emailmaker__.modules.Antd` **синхронно** — в момент, когда выполняется его скрипт.
|
|
589
|
+
До этого момента в реестре лежат ожидания: часть runtime приезжает по требованию, чтобы первый
|
|
590
|
+
экран не платил за то, чем не пользуется.
|
|
591
|
+
|
|
592
|
+
Если плагин подключён через `init({ plugins: [...] })` или `useAsync(...)`, делать ничего не
|
|
593
|
+
нужно: хост сам дожидается готовности runtime перед тем, как выполнить скрипт. Тормозится только
|
|
594
|
+
загрузка такого плагина, остальное приложение работает своим ходом.
|
|
595
|
+
|
|
596
|
+
Если же вы вставляете `<script>` с плагином сами, мимо API — дождитесь `preload()`:
|
|
597
|
+
|
|
598
|
+
```ts
|
|
599
|
+
import { preload } from '@emailmaker/emailmaker';
|
|
600
|
+
|
|
601
|
+
await preload();
|
|
602
|
+
document.head.appendChild(Object.assign(document.createElement('script'), {
|
|
603
|
+
src: 'https://cdn.example.com/my-plugin.umd.js',
|
|
604
|
+
}));
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Плагинов на `esm` это не касается: их импорты разрешает сборщик, ждать им нечего.
|
|
608
|
+
|
|
460
609
|
### 4. Регистрация по имени (связь между плагинами)
|
|
461
610
|
|
|
462
611
|
Если плагин A должен обращаться к плагину B через `editor.use('PluginB')` — используйте `pluginRegistry.add`:
|
|
@@ -504,10 +653,6 @@ const myPlugin = await this.editor.useAsync(
|
|
|
504
653
|
() => import('my-plugin').then(m => m.MyPlugin)
|
|
505
654
|
);
|
|
506
655
|
|
|
507
|
-
const myPlugin = await this.editor.useAsync(
|
|
508
|
-
{ type: 'esm', url: '/plugins/analytics.js' }
|
|
509
|
-
);
|
|
510
|
-
|
|
511
656
|
const myPluginByKey = await this.editor.useAsync(
|
|
512
657
|
{ type: 'umd', url: '/plugins/my-plugin.umd.js', name: 'MyPlugin', resolve: 'registry' }
|
|
513
658
|
);
|
|
@@ -733,6 +878,22 @@ App.registerPlugin('MyPluginSandbox', MyPluginSandbox);
|
|
|
733
878
|
|
|
734
879
|
> ⚠️ Sandbox работает в изолированном iframe. React-компоненты здесь недоступны — только нативный DOM.
|
|
735
880
|
|
|
881
|
+
### Скрипт живёт одно письмо
|
|
882
|
+
|
|
883
|
+
Документ холста пересоздаётся на каждое письмо: скрипт песочницы выполняется заново, и ничего из
|
|
884
|
+
прошлого письма в нём не остаётся. `handle.ready` — обещание, оно разрешается один раз, для первого
|
|
885
|
+
холста. Чтобы узнавать о готовности каждый раз, подпишитесь на `onReady`:
|
|
886
|
+
|
|
887
|
+
```ts
|
|
888
|
+
const script = sandboxApi.registerSandboxScript(url);
|
|
889
|
+
script.onReady(() => {
|
|
890
|
+
messageService.send('my-plugin:settings', mySettings);
|
|
891
|
+
});
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
Последнее, что вы отправили скрипту после его готовности, редактор повторяет в новый холст сам —
|
|
895
|
+
по каждому ключу сообщения. `onReady` нужен для состояния, которое вы считаете заново.
|
|
896
|
+
|
|
736
897
|
|
|
737
898
|
### MessageService (внутри sandbox)
|
|
738
899
|
|
|
@@ -845,6 +1006,20 @@ import { Form, FormColorField } from "@emailmaker/ui-kit";
|
|
|
845
1006
|
</Form>
|
|
846
1007
|
```
|
|
847
1008
|
|
|
1009
|
+
### Значки
|
|
1010
|
+
|
|
1011
|
+
Значки ui-kit берите по одному из подпути `icons` — в сборку плагина попадут только те, что вы
|
|
1012
|
+
используете. В release-сборке этот путь уходит на `@emailmaker/emailmaker/ui-kit/icons` хоста.
|
|
1013
|
+
|
|
1014
|
+
```tsx
|
|
1015
|
+
import { AIRequests, Sun } from "@emailmaker/ui-kit/icons";
|
|
1016
|
+
|
|
1017
|
+
<AIRequests />
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
`<EmIcons icon="Sun" />` тоже работает, но подтягивает весь каталог значков и пишет в консоль
|
|
1021
|
+
предупреждение.
|
|
1022
|
+
|
|
848
1023
|
|
|
849
1024
|
---
|
|
850
1025
|
|
|
@@ -1020,7 +1195,7 @@ settingsPanel.showSettingsPanel({
|
|
|
1020
1195
|
|
|
1021
1196
|
### `--dev` / `--dev-packages`
|
|
1022
1197
|
|
|
1023
|
-
**Самый частый флаг для разработки:**
|
|
1198
|
+
**Самый частый флаг для разработки:** в сгенерированном проекте пакеты экосистемы получают dist-tag `dev` вместо `latest`. Используйте, когда нужны свежие предрелизные сборки.
|
|
1024
1199
|
|
|
1025
1200
|
```bash
|
|
1026
1201
|
npx @emailmaker/cli my-plugin --kind plugin --preset advanced --bundler vite --target npm-package --dev --output-dir ./my-plugin
|
|
@@ -1136,6 +1311,18 @@ npm run start:release
|
|
|
1136
1311
|
- что release bundle собран под target `встраиваемый bundle`
|
|
1137
1312
|
- что sandbox и main bundle публикуются по ожидаемым URL
|
|
1138
1313
|
|
|
1314
|
+
### Плагин на `globals` падает: вместо `antd` приходит объект с `then`
|
|
1315
|
+
|
|
1316
|
+
Значит скрипт плагина выполнился раньше, чем хост подготовил реестр runtime. Часть runtime
|
|
1317
|
+
приезжает по требованию, и до этого момента в `window.__emailmaker__.modules` лежат
|
|
1318
|
+
ожидания, а не значения.
|
|
1319
|
+
|
|
1320
|
+
Проверьте:
|
|
1321
|
+
|
|
1322
|
+
- плагин подключён через `init({ plugins: [{ type, url, ... }] })` или `useAsync(...)` — тогда
|
|
1323
|
+
хост дожидается готовности сам;
|
|
1324
|
+
- если `<script>` вставляете вы, перед вставкой вызван `await preload()`.
|
|
1325
|
+
|
|
1139
1326
|
### Duplicate React / hooks error
|
|
1140
1327
|
|
|
1141
1328
|
Почти всегда это значит, что React попал в bundle плагина вместо runtime externals.
|
|
@@ -1162,7 +1349,7 @@ npm run start:release
|
|
|
1162
1349
|
## ❓ FAQ / Типичные ошибки
|
|
1163
1350
|
|
|
1164
1351
|
- **«Invalid hook call» или два React на странице**
|
|
1165
|
-
> Для обычного плагина используйте стандартные импорты `react` / `antd` и собирайте проект через `PluginDev` с `alias: true` (по умолчанию). Не смешивайте обычные импорты с прямыми импортами из runtime в одном
|
|
1352
|
+
> Для обычного плагина используйте стандартные импорты `react` / `antd` и собирайте проект через `PluginDev` с `alias: true` (по умолчанию). Не смешивайте обычные импорты с прямыми импортами из runtime в одном интерфейсе плагина: выбирается что-то одно на весь плагин, подробности — в README пакета runtime.
|
|
1166
1353
|
|
|
1167
1354
|
- **Externals не работают в dev server**
|
|
1168
1355
|
> В serve-режиме externals должны быть отключены: `PluginDev({ externals: false })`. Зависимости резолвятся из runtime через alias.
|
package/externals.json
CHANGED
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
"promise __emailmaker__.modules",
|
|
24
24
|
"Antd"
|
|
25
25
|
],
|
|
26
|
+
"@ant-design/icons/es/components/AntdIcon": [
|
|
27
|
+
"promise __emailmaker__.modules",
|
|
28
|
+
"AntDesignIconBase"
|
|
29
|
+
],
|
|
26
30
|
"@ant-design/icons": [
|
|
27
31
|
"promise __emailmaker__.modules",
|
|
28
32
|
"AntDesignIcons"
|
|
@@ -39,10 +43,6 @@
|
|
|
39
43
|
"promise __emailmaker__.modules",
|
|
40
44
|
"Dayjs"
|
|
41
45
|
],
|
|
42
|
-
"uuid": [
|
|
43
|
-
"promise __emailmaker__.modules",
|
|
44
|
-
"Uuid"
|
|
45
|
-
],
|
|
46
46
|
"@emailmaker/ui-kit": [
|
|
47
47
|
"promise __emailmaker__.modules",
|
|
48
48
|
"UiKit"
|
package/index.js
CHANGED
|
@@ -33,12 +33,16 @@ var a = class e {
|
|
|
33
33
|
function o(e) {
|
|
34
34
|
return `service_container_${e}`;
|
|
35
35
|
}
|
|
36
|
-
var s =
|
|
36
|
+
var s = /* @__PURE__ */ new Set();
|
|
37
|
+
function c(e) {
|
|
38
|
+
s.delete(e);
|
|
39
|
+
}
|
|
40
|
+
var l = class e extends a {
|
|
37
41
|
_parent;
|
|
38
42
|
_injectCallbacks = [];
|
|
39
43
|
_injections = Object.create(null);
|
|
40
44
|
_runCallbacks(e) {
|
|
41
|
-
this._injectCallbacks.forEach((t) => t(e));
|
|
45
|
+
[...this._injectCallbacks].forEach((t) => t(e));
|
|
42
46
|
}
|
|
43
47
|
constructor(e = null) {
|
|
44
48
|
super(), this._parent = e, e && this.addDisposable(e.onInject((e) => this._runCallbacks(e)));
|
|
@@ -59,7 +63,7 @@ var s = class e extends a {
|
|
|
59
63
|
}
|
|
60
64
|
_onInject(e, t, n = new a()) {
|
|
61
65
|
return n.addDisposable(this.onInject((r) => {
|
|
62
|
-
e === r && (n.dispose(), t(this.getInstance(r)));
|
|
66
|
+
e === r && !n.isDisposed() && (n.dispose(), t(this.getInstance(r)));
|
|
63
67
|
})), this._parent && n.addDisposable(this._parent._onInject(e, t, n)), this.addDisposable(n), n;
|
|
64
68
|
}
|
|
65
69
|
getInstance(e, t = !0) {
|
|
@@ -74,7 +78,24 @@ var s = class e extends a {
|
|
|
74
78
|
}
|
|
75
79
|
getInstanceAsync(e) {
|
|
76
80
|
let t = this._find(e);
|
|
77
|
-
return typeof t == "function" ? Promise.resolve(t()) : new Promise((t
|
|
81
|
+
return typeof t == "function" ? Promise.resolve(t()) : new Promise((t, n) => {
|
|
82
|
+
let r = {
|
|
83
|
+
id: String(e),
|
|
84
|
+
startedAt: Date.now(),
|
|
85
|
+
origin: void 0,
|
|
86
|
+
container: this,
|
|
87
|
+
reject: n
|
|
88
|
+
};
|
|
89
|
+
s.add(r), this._onInject(e, () => {
|
|
90
|
+
c(r), t(this.getInstance(e));
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
failPendingWaits(e) {
|
|
95
|
+
for (let t of Array.from(s)) t.container === this && (c(t), t.reject(e));
|
|
96
|
+
}
|
|
97
|
+
pendingWaits() {
|
|
98
|
+
return [...s].filter((e) => e.container === this);
|
|
78
99
|
}
|
|
79
100
|
addService(e, t) {
|
|
80
101
|
let n = o(e);
|
|
@@ -105,62 +126,70 @@ var s = class e extends a {
|
|
|
105
126
|
return new e(n);
|
|
106
127
|
});
|
|
107
128
|
}
|
|
129
|
+
remove(e) {
|
|
130
|
+
let t = this._injections;
|
|
131
|
+
delete t[String(e)];
|
|
132
|
+
}
|
|
133
|
+
injectListenerCount() {
|
|
134
|
+
return this._injectCallbacks.length;
|
|
135
|
+
}
|
|
108
136
|
dispose() {
|
|
109
|
-
|
|
137
|
+
for (let e of Array.from(s)) e.container === this && c(e);
|
|
138
|
+
this._injections = Object.create(null), this._injectCallbacks = [], super.dispose();
|
|
110
139
|
}
|
|
111
140
|
};
|
|
112
141
|
//#endregion
|
|
113
142
|
//#region packages/runtime-core/di/namespace.ts
|
|
114
|
-
function
|
|
143
|
+
function u(e) {
|
|
115
144
|
return e.startsWith("__") ? e : `__${e}__`;
|
|
116
145
|
}
|
|
117
|
-
function
|
|
146
|
+
function d(e) {
|
|
118
147
|
if (typeof globalThis > "u") throw Error("[di] globalThis is required for namespace container access.");
|
|
119
|
-
let t =
|
|
148
|
+
let t = u(e), n = globalThis;
|
|
120
149
|
return n[t] ??= {};
|
|
121
150
|
}
|
|
122
151
|
//#endregion
|
|
123
152
|
//#region packages/runtime-core/di/ensureContainer.ts
|
|
124
|
-
function
|
|
153
|
+
function f(e) {
|
|
125
154
|
return typeof e == "object" && !!e && typeof e.inject == "function" && typeof e.getInstance == "function";
|
|
126
155
|
}
|
|
127
|
-
function
|
|
128
|
-
return
|
|
156
|
+
function p(e) {
|
|
157
|
+
return u(e || "emailmaker");
|
|
129
158
|
}
|
|
130
|
-
function
|
|
131
|
-
let t =
|
|
132
|
-
if (
|
|
133
|
-
let n = new
|
|
159
|
+
function m(e) {
|
|
160
|
+
let t = d(p(e));
|
|
161
|
+
if (f(t.container)) return t.container;
|
|
162
|
+
let n = new l(null);
|
|
134
163
|
return t.container = n, n;
|
|
135
164
|
}
|
|
136
|
-
function
|
|
137
|
-
return
|
|
165
|
+
function h(e) {
|
|
166
|
+
return m(e);
|
|
138
167
|
}
|
|
139
168
|
//#endregion
|
|
140
169
|
//#region packages/runtime-core/guid/index.ts
|
|
141
|
-
function
|
|
170
|
+
function g() {
|
|
142
171
|
let e = (/* @__PURE__ */ new Date()).getTime(), t = typeof performance < "u" && performance.now && performance.now() * 1e3 || 0;
|
|
143
172
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(n) {
|
|
144
173
|
let r = Math.random() * 16;
|
|
145
174
|
return e > 0 ? (r = (e + r) % 16 | 0, e = Math.floor(e / 16)) : (r = (t + r) % 16 | 0, t = Math.floor(t / 16)), (n === "x" ? r : r & 3 | 8).toString(16);
|
|
146
175
|
});
|
|
147
176
|
}
|
|
148
|
-
function
|
|
149
|
-
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() :
|
|
177
|
+
function _() {
|
|
178
|
+
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : g();
|
|
150
179
|
}
|
|
151
180
|
//#endregion
|
|
152
181
|
//#region packages/runtime-core/di/identifier.ts
|
|
153
|
-
function
|
|
182
|
+
function v(e = _()) {
|
|
154
183
|
return e;
|
|
155
184
|
}
|
|
156
185
|
//#endregion
|
|
157
186
|
//#region packages/runtime-core/di/index.ts
|
|
158
|
-
function
|
|
187
|
+
function y() {
|
|
159
188
|
return "app";
|
|
160
189
|
}
|
|
161
|
-
function
|
|
190
|
+
function b(e) {
|
|
162
191
|
if (typeof globalThis > "u") return;
|
|
163
|
-
let t =
|
|
192
|
+
let t = y(), n = globalThis[e] ?? {};
|
|
164
193
|
globalThis[e] = n;
|
|
165
194
|
let r = n.__diagnostics ??= {}, i = r.diModuleEval ??= {
|
|
166
195
|
evalCount: 0,
|
|
@@ -172,12 +201,12 @@ function v(e) {
|
|
|
172
201
|
stack: (/* @__PURE__ */ Error()).stack
|
|
173
202
|
}), i.evalCount += 1;
|
|
174
203
|
}
|
|
175
|
-
function
|
|
204
|
+
function x() {
|
|
176
205
|
return "__emailmaker__";
|
|
177
206
|
}
|
|
178
|
-
function
|
|
179
|
-
if (
|
|
180
|
-
let n =
|
|
207
|
+
function S(e, t) {
|
|
208
|
+
if (b(t), typeof globalThis > "u") return e;
|
|
209
|
+
let n = y(), r = globalThis, i = r[t] = r[t] || {}, a = i.__diagnostics = i.__diagnostics || {}, o = a.dependencyResolver = a.dependencyResolver || { entries: [] }, s = {
|
|
181
210
|
container: e,
|
|
182
211
|
source: "packages/runtime-core/di/index.ts",
|
|
183
212
|
buildSource: n,
|
|
@@ -186,16 +215,16 @@ function b(e, t) {
|
|
|
186
215
|
};
|
|
187
216
|
return o.entries.push(s), e;
|
|
188
217
|
}
|
|
189
|
-
var
|
|
190
|
-
function
|
|
191
|
-
if (
|
|
192
|
-
let e =
|
|
193
|
-
return
|
|
218
|
+
var C;
|
|
219
|
+
function w() {
|
|
220
|
+
if (C) return C;
|
|
221
|
+
let e = x();
|
|
222
|
+
return C = S(m(e), e), C;
|
|
194
223
|
}
|
|
195
|
-
var
|
|
196
|
-
let r =
|
|
224
|
+
var T = new Proxy({}, { get(e, t, n) {
|
|
225
|
+
let r = w(), i = Reflect.get(r, t, n);
|
|
197
226
|
return typeof i == "function" ? i.bind(r) : i;
|
|
198
|
-
} }),
|
|
227
|
+
} }), E = class {
|
|
199
228
|
_plugins = /* @__PURE__ */ new Map();
|
|
200
229
|
_listeners = /* @__PURE__ */ new Map();
|
|
201
230
|
_getOrCreateEntry(e) {
|
|
@@ -310,7 +339,7 @@ var C = new Proxy({}, { get(e, t, n) {
|
|
|
310
339
|
e.add(t, n);
|
|
311
340
|
} };
|
|
312
341
|
}
|
|
313
|
-
},
|
|
342
|
+
}, D = class {
|
|
314
343
|
resolveRegistry;
|
|
315
344
|
constructor(e) {
|
|
316
345
|
this.resolveRegistry = e;
|
|
@@ -357,7 +386,30 @@ var C = new Proxy({}, { get(e, t, n) {
|
|
|
357
386
|
forContext() {
|
|
358
387
|
return this.target().forContext();
|
|
359
388
|
}
|
|
360
|
-
},
|
|
389
|
+
}, O = v("ComponentRegistry"), k = v("ComponentRegistryGate");
|
|
390
|
+
function A() {
|
|
391
|
+
return T.getOrCreateInstance(k, () => ({ pending: [] }));
|
|
392
|
+
}
|
|
393
|
+
function j(e) {
|
|
394
|
+
let t = A();
|
|
395
|
+
t.factory = e;
|
|
396
|
+
let n = t.pending.splice(0, t.pending.length);
|
|
397
|
+
for (let e of n) try {
|
|
398
|
+
e();
|
|
399
|
+
} catch (e) {
|
|
400
|
+
console.error("[extensions] deferred UI call failed once the component registry arrived:", e);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function M(e, t = O) {
|
|
404
|
+
let n = T.getInstance(t);
|
|
405
|
+
if (n) return n;
|
|
406
|
+
let r = A().factory;
|
|
407
|
+
if (!r) throw Error("[extensions] component registry is not loaded yet — UI work starts at init()");
|
|
408
|
+
return T.getOrCreateInstance(t, r);
|
|
409
|
+
}
|
|
410
|
+
//#endregion
|
|
411
|
+
//#region packages/extensions-core/components/DomComponentRegistry.ts
|
|
412
|
+
var N = class {
|
|
361
413
|
_factories = /* @__PURE__ */ new Map();
|
|
362
414
|
add(e, t) {
|
|
363
415
|
let n = e;
|
|
@@ -368,28 +420,28 @@ var C = new Proxy({}, { get(e, t, n) {
|
|
|
368
420
|
get(e) {
|
|
369
421
|
return this._factories.get(e);
|
|
370
422
|
}
|
|
371
|
-
},
|
|
372
|
-
function
|
|
373
|
-
return
|
|
423
|
+
}, P = v("DomComponentRegistry");
|
|
424
|
+
function F(e, t = P) {
|
|
425
|
+
return T.getOrCreateInstance(t, () => new N());
|
|
374
426
|
}
|
|
375
427
|
//#endregion
|
|
376
428
|
//#region packages/extensions-core/components/ComponentRegistry.ts
|
|
377
|
-
function
|
|
429
|
+
function I(e) {
|
|
378
430
|
return typeof e == "function";
|
|
379
431
|
}
|
|
380
|
-
function
|
|
432
|
+
function L(e) {
|
|
381
433
|
return i(e);
|
|
382
434
|
}
|
|
383
|
-
function
|
|
384
|
-
return typeof e == "function" ||
|
|
435
|
+
function R(e) {
|
|
436
|
+
return typeof e == "function" || L(e);
|
|
385
437
|
}
|
|
386
|
-
function
|
|
387
|
-
return typeof e == "object" && !!e && "type" in e && "props" in e && !
|
|
438
|
+
function z(e) {
|
|
439
|
+
return typeof e == "object" && !!e && "type" in e && "props" in e && !L(e);
|
|
388
440
|
}
|
|
389
|
-
function
|
|
441
|
+
function B(e, t) {
|
|
390
442
|
return n(e, t);
|
|
391
443
|
}
|
|
392
|
-
function
|
|
444
|
+
function V(t) {
|
|
393
445
|
return class extends e {
|
|
394
446
|
_ref = r();
|
|
395
447
|
_instance;
|
|
@@ -407,7 +459,7 @@ function P(t) {
|
|
|
407
459
|
}
|
|
408
460
|
};
|
|
409
461
|
}
|
|
410
|
-
var
|
|
462
|
+
var H = class {
|
|
411
463
|
_domComponentRegistry;
|
|
412
464
|
_components = /* @__PURE__ */ new Map();
|
|
413
465
|
_domAdapters = /* @__PURE__ */ new Map();
|
|
@@ -441,26 +493,26 @@ var F = class {
|
|
|
441
493
|
t.component = t.replacers.reduce((e, { replacer: t }) => t(e), void 0);
|
|
442
494
|
}
|
|
443
495
|
get(e) {
|
|
444
|
-
if (
|
|
496
|
+
if (R(e)) return e;
|
|
445
497
|
let t = e, n = this._components.get(t);
|
|
446
498
|
if (n?.component) return n.component;
|
|
447
499
|
let r = this._domComponentRegistry.get(e);
|
|
448
500
|
if (r) {
|
|
449
501
|
let e = this._domAdapters.get(t);
|
|
450
|
-
return e || (e =
|
|
502
|
+
return e || (e = V(r), this._domAdapters.set(t, e)), e;
|
|
451
503
|
}
|
|
452
504
|
}
|
|
453
505
|
_resolveComponentInput(e) {
|
|
454
506
|
if (e == null) return null;
|
|
455
|
-
if (typeof e == "number" || typeof e == "boolean" ||
|
|
507
|
+
if (typeof e == "number" || typeof e == "boolean" || L(e)) return e;
|
|
456
508
|
if (typeof e == "string") {
|
|
457
509
|
let t = this.get(e);
|
|
458
|
-
return
|
|
510
|
+
return L(t) ? t : t ? B(t) : e;
|
|
459
511
|
}
|
|
460
|
-
if (
|
|
461
|
-
if (
|
|
512
|
+
if (I(e)) return B(e);
|
|
513
|
+
if (z(e)) {
|
|
462
514
|
let t = this.get(e.type);
|
|
463
|
-
return
|
|
515
|
+
return L(t) ? t : t ? B(t, e.props) : null;
|
|
464
516
|
}
|
|
465
517
|
return null;
|
|
466
518
|
}
|
|
@@ -469,38 +521,36 @@ var F = class {
|
|
|
469
521
|
}
|
|
470
522
|
getReactElement(e) {
|
|
471
523
|
let r = this._resolveComponentInput(e);
|
|
472
|
-
return
|
|
524
|
+
return L(r) ? r : typeof r == "string" || r == null || typeof r == "boolean" || typeof r == "number" ? n(t, null, r) : n(t, null);
|
|
473
525
|
}
|
|
474
|
-
},
|
|
475
|
-
|
|
476
|
-
return C.getOrCreateInstance(t, () => new F(O(C, D)));
|
|
477
|
-
}
|
|
526
|
+
}, U = () => new H(F(T, P));
|
|
527
|
+
j(U), T.getOrCreateInstance(O, U);
|
|
478
528
|
//#endregion
|
|
479
529
|
//#region src/plugin/registryId.ts
|
|
480
|
-
var
|
|
530
|
+
var W = "PluginRegistry";
|
|
481
531
|
//#endregion
|
|
482
532
|
//#region src/plugin/pluginRegistry.ts
|
|
483
|
-
function
|
|
484
|
-
return e.getOrCreateInstance(
|
|
533
|
+
function G(e = h()) {
|
|
534
|
+
return e.getOrCreateInstance(W, () => new E());
|
|
485
535
|
}
|
|
486
|
-
new
|
|
536
|
+
new D(() => G()), v("ELEMENT_INSERT_HTML_PIPELINE"), v("BLOCK_INSERT_HTML_PIPELINE");
|
|
487
537
|
//#endregion
|
|
488
538
|
//#region packages/extensions-core/identifiers/index.ts
|
|
489
|
-
function
|
|
490
|
-
return
|
|
539
|
+
function K(e) {
|
|
540
|
+
return v(e);
|
|
491
541
|
}
|
|
492
|
-
|
|
542
|
+
v("extensions.atomsHandlers"), K("HANDLE_ATOM_INSERT"), v("HeadlessMode"), v("extensions.sandboxExtensions"), v("MESSAGE_SERVICE"), K("SETTINGS_PANEL_EVENT"), K("MODAL_SHOW_EVENT"), K("MODAL_CLOSE_EVENT"), K("MODAL_UPDATE_EVENT");
|
|
493
543
|
//#endregion
|
|
494
544
|
//#region src/extensions/api/src/index.ts
|
|
495
|
-
function
|
|
545
|
+
function q() {
|
|
496
546
|
return typeof globalThis.crypto?.randomUUID == "function" ? globalThis.crypto.randomUUID() : `component-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
497
547
|
}
|
|
498
|
-
function
|
|
548
|
+
function J(e = q()) {
|
|
499
549
|
return e;
|
|
500
550
|
}
|
|
501
|
-
|
|
551
|
+
F(T);
|
|
502
552
|
//#endregion
|
|
503
553
|
//#region src/extensions/react/src/index.ts
|
|
504
|
-
var
|
|
554
|
+
var Y = M(T);
|
|
505
555
|
//#endregion
|
|
506
|
-
export {
|
|
556
|
+
export { Y as ComponentRegistry, J as createComponentIdentifier };
|
package/package.json
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"antd": "^6.3
|
|
8
|
+
"antd": "^6.4.3",
|
|
9
9
|
"react": "^19.2.7",
|
|
10
10
|
"react-dom": "^19.2.7",
|
|
11
11
|
"@types/react": "^19.2.17",
|
|
12
12
|
"@types/react-dom": "^19.2.3",
|
|
13
|
-
"@emailmaker/emailmaker": "1.1.
|
|
14
|
-
"@emailmaker/extensions-app": "1.1.
|
|
13
|
+
"@emailmaker/emailmaker": "1.1.103",
|
|
14
|
+
"@emailmaker/extensions-app": "1.1.103"
|
|
15
15
|
},
|
|
16
16
|
"name": "@emailmaker/extensions-react",
|
|
17
|
-
"version": "1.1.
|
|
17
|
+
"version": "1.1.103"
|
|
18
18
|
}
|
package/types.d.ts
CHANGED
|
@@ -322,6 +322,15 @@ interface ISandboxScriptHandle extends IDisposable {
|
|
|
322
322
|
* lifecycle initialization (`afterInit`).
|
|
323
323
|
*/
|
|
324
324
|
readonly ready: Promise<void>;
|
|
325
|
+
/**
|
|
326
|
+
* Fires every time the script becomes ready, including the first time.
|
|
327
|
+
*
|
|
328
|
+
* The canvas document is recreated for every email, so the script is evaluated again and becomes
|
|
329
|
+
* ready again — `ready` is a promise and settles only once, for the first canvas. A host that keeps
|
|
330
|
+
* state in the script subscribes here and sends it again; the editor also replays, on its own, the
|
|
331
|
+
* last message the host sent to the script after `ready`.
|
|
332
|
+
*/
|
|
333
|
+
onReady(listener: () => void): IDisposable;
|
|
325
334
|
}
|
|
326
335
|
interface ISandboxScriptApi {
|
|
327
336
|
/**
|