@endora-commerce/page-builder-admin 0.100.0
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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/chrome/AssetPickers.d.ts +16 -0
- package/dist/chrome/AssetPickers.d.ts.map +1 -0
- package/dist/chrome/AssetPickers.js +112 -0
- package/dist/chrome/AssetPickers.js.map +1 -0
- package/dist/chrome/CatalogPickers.d.ts +6 -0
- package/dist/chrome/CatalogPickers.d.ts.map +1 -0
- package/dist/chrome/CatalogPickers.js +310 -0
- package/dist/chrome/CatalogPickers.js.map +1 -0
- package/dist/chrome/ColorPaletteModal.d.ts +11 -0
- package/dist/chrome/ColorPaletteModal.d.ts.map +1 -0
- package/dist/chrome/ColorPaletteModal.js +82 -0
- package/dist/chrome/ColorPaletteModal.js.map +1 -0
- package/dist/chrome/ColorPaletteProvider.d.ts +7 -0
- package/dist/chrome/ColorPaletteProvider.d.ts.map +1 -0
- package/dist/chrome/ColorPaletteProvider.js +40 -0
- package/dist/chrome/ColorPaletteProvider.js.map +1 -0
- package/dist/chrome/PageBuilderHeaderActions.d.ts +52 -0
- package/dist/chrome/PageBuilderHeaderActions.d.ts.map +1 -0
- package/dist/chrome/PageBuilderHeaderActions.js +242 -0
- package/dist/chrome/PageBuilderHeaderActions.js.map +1 -0
- package/dist/chrome/PageBuilderOverlayBridge.d.ts +10 -0
- package/dist/chrome/PageBuilderOverlayBridge.d.ts.map +1 -0
- package/dist/chrome/PageBuilderOverlayBridge.js +25 -0
- package/dist/chrome/PageBuilderOverlayBridge.js.map +1 -0
- package/dist/chrome/QuickTooltip.d.ts +8 -0
- package/dist/chrome/QuickTooltip.d.ts.map +1 -0
- package/dist/chrome/QuickTooltip.js +33 -0
- package/dist/chrome/QuickTooltip.js.map +1 -0
- package/dist/chrome/action-bar-target.d.ts +12 -0
- package/dist/chrome/action-bar-target.d.ts.map +1 -0
- package/dist/chrome/action-bar-target.js +37 -0
- package/dist/chrome/action-bar-target.js.map +1 -0
- package/dist/chrome/cms-page-builder-api.d.ts +21 -0
- package/dist/chrome/cms-page-builder-api.d.ts.map +1 -0
- package/dist/chrome/cms-page-builder-api.js +50 -0
- package/dist/chrome/cms-page-builder-api.js.map +1 -0
- package/dist/chrome/page-builder-data.d.ts +5 -0
- package/dist/chrome/page-builder-data.d.ts.map +1 -0
- package/dist/chrome/page-builder-data.js +12 -0
- package/dist/chrome/page-builder-data.js.map +1 -0
- package/dist/email/EmailBuilderActionBar.d.ts +8 -0
- package/dist/email/EmailBuilderActionBar.d.ts.map +1 -0
- package/dist/email/EmailBuilderActionBar.js +91 -0
- package/dist/email/EmailBuilderActionBar.js.map +1 -0
- package/dist/email/EmailEditorPane.d.ts +42 -0
- package/dist/email/EmailEditorPane.d.ts.map +1 -0
- package/dist/email/EmailEditorPane.js +637 -0
- package/dist/email/EmailEditorPane.js.map +1 -0
- package/dist/email/EmailRichTextField.d.ts +14 -0
- package/dist/email/EmailRichTextField.d.ts.map +1 -0
- package/dist/email/EmailRichTextField.js +45 -0
- package/dist/email/EmailRichTextField.js.map +1 -0
- package/dist/email/EmailRowLayoutPicker.d.ts +8 -0
- package/dist/email/EmailRowLayoutPicker.d.ts.map +1 -0
- package/dist/email/EmailRowLayoutPicker.js +17 -0
- package/dist/email/EmailRowLayoutPicker.js.map +1 -0
- package/dist/email/EmailVariableFields.d.ts +13 -0
- package/dist/email/EmailVariableFields.d.ts.map +1 -0
- package/dist/email/EmailVariableFields.js +49 -0
- package/dist/email/EmailVariableFields.js.map +1 -0
- package/dist/email/EmailVariablesProvider.d.ts +15 -0
- package/dist/email/EmailVariablesProvider.d.ts.map +1 -0
- package/dist/email/EmailVariablesProvider.js +54 -0
- package/dist/email/EmailVariablesProvider.js.map +1 -0
- package/dist/email/email-builder-plugin.d.ts +6 -0
- package/dist/email/email-builder-plugin.d.ts.map +1 -0
- package/dist/email/email-builder-plugin.js +14 -0
- package/dist/email/email-builder-plugin.js.map +1 -0
- package/dist/email/email-template-layout.d.ts +16 -0
- package/dist/email/email-template-layout.d.ts.map +1 -0
- package/dist/email/email-template-layout.js +55 -0
- package/dist/email/email-template-layout.js.map +1 -0
- package/dist/email/email-templates-api.d.ts +14 -0
- package/dist/email/email-templates-api.d.ts.map +1 -0
- package/dist/email/email-templates-api.js +54 -0
- package/dist/email/email-templates-api.js.map +1 -0
- package/dist/email/index.d.ts +33 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +33 -0
- package/dist/email/index.js.map +1 -0
- package/dist/email/insert-at-cursor.d.ts +8 -0
- package/dist/email/insert-at-cursor.d.ts.map +1 -0
- package/dist/email/insert-at-cursor.js +12 -0
- package/dist/email/insert-at-cursor.js.map +1 -0
- package/dist/email/variables.d.ts +20 -0
- package/dist/email/variables.d.ts.map +1 -0
- package/dist/email/variables.js +41 -0
- package/dist/email/variables.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
let selectedTarget = null;
|
|
3
|
+
let hoverTarget = null;
|
|
4
|
+
const listeners = new Set();
|
|
5
|
+
function notify() {
|
|
6
|
+
for (const listener of listeners)
|
|
7
|
+
listener();
|
|
8
|
+
}
|
|
9
|
+
export function setSelectedActionBarTarget(next) {
|
|
10
|
+
if (selectedTarget?.id === next?.id && selectedTarget?.type === next?.type)
|
|
11
|
+
return;
|
|
12
|
+
selectedTarget = next;
|
|
13
|
+
notify();
|
|
14
|
+
}
|
|
15
|
+
export function setHoverActionBarTarget(next) {
|
|
16
|
+
if (hoverTarget?.id === next?.id && hoverTarget?.type === next?.type)
|
|
17
|
+
return;
|
|
18
|
+
hoverTarget = next;
|
|
19
|
+
notify();
|
|
20
|
+
}
|
|
21
|
+
export function getSelectedActionBarTarget() {
|
|
22
|
+
return selectedTarget;
|
|
23
|
+
}
|
|
24
|
+
export function getHoverActionBarTarget() {
|
|
25
|
+
return hoverTarget;
|
|
26
|
+
}
|
|
27
|
+
/** Selected component wins over hovered — keeps Row actions while the row stays selected. */
|
|
28
|
+
export function getActionBarTarget() {
|
|
29
|
+
return selectedTarget ?? hoverTarget;
|
|
30
|
+
}
|
|
31
|
+
export function useActionBarTarget() {
|
|
32
|
+
return useSyncExternalStore((listener) => {
|
|
33
|
+
listeners.add(listener);
|
|
34
|
+
return () => listeners.delete(listener);
|
|
35
|
+
}, () => getActionBarTarget(), () => getActionBarTarget());
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=action-bar-target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-bar-target.js","sourceRoot":"","sources":["../../src/chrome/action-bar-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAI7C,IAAI,cAAc,GAA2B,IAAI,CAAC;AAClD,IAAI,WAAW,GAA2B,IAAI,CAAC;AAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;AAExC,SAAS,MAAM;IACb,KAAK,MAAM,QAAQ,IAAI,SAAS;QAAE,QAAQ,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,IAA4B;IACrE,IAAI,cAAc,EAAE,EAAE,KAAK,IAAI,EAAE,EAAE,IAAI,cAAc,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI;QAAE,OAAO;IACnF,cAAc,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,CAAC;AACX,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAA4B;IAClE,IAAI,WAAW,EAAE,EAAE,KAAK,IAAI,EAAE,EAAE,IAAI,WAAW,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI;QAAE,OAAO;IAC7E,WAAW,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,CAAC;AACX,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,kBAAkB;IAChC,OAAO,cAAc,IAAI,WAAW,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,oBAAoB,CACzB,CAAC,QAAQ,EAAE,EAAE;QACX,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC,EACD,GAAG,EAAE,CAAC,kBAAkB,EAAE,EAC1B,GAAG,EAAE,CAAC,kBAAkB,EAAE,CAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CmsColorPaletteEntry, CmsPageBuilderDescriptor, PutCmsColorPaletteRequest } from '@endora-commerce/contracts';
|
|
2
|
+
/** The saved palette, or an empty one for a descriptor that carries none. */
|
|
3
|
+
export declare function getPageBuilderColorPalette(): Promise<CmsColorPaletteEntry[]>;
|
|
4
|
+
/**
|
|
5
|
+
* The whole descriptor — every block and every palette section the composed,
|
|
6
|
+
* effectively present modules declare (feature 096, T210).
|
|
7
|
+
*
|
|
8
|
+
* The e-mail builder needs it for the same reason the CMS builder does: the
|
|
9
|
+
* sections it renders are no longer a `categories` map inside
|
|
10
|
+
* `@endora-commerce/email-components` but declarations made by
|
|
11
|
+
* `transactional_emails`, `orders` and `catalog`, merged per `(key, context)`
|
|
12
|
+
* and filtered to the modules an operator has switched on. Switching `orders`
|
|
13
|
+
* off is what takes the *Order* section out of the palette, and no constant in
|
|
14
|
+
* a package can answer that.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getPageBuilderDescriptor(): Promise<CmsPageBuilderDescriptor>;
|
|
17
|
+
/** Replace the palette wholesale; the server answers with what it stored. */
|
|
18
|
+
export declare function putPageBuilderColorPalette(body: PutCmsColorPaletteRequest): Promise<{
|
|
19
|
+
entries: CmsColorPaletteEntry[];
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=cms-page-builder-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cms-page-builder-api.d.ts","sourceRoot":"","sources":["../../src/chrome/cms-page-builder-api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,4BAA4B,CAAC;AAyBpC,6EAA6E;AAC7E,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAGlF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAGlF;AAED,6EAA6E;AAC7E,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,oBAAoB,EAAE,CAAA;CAAE,CAAC,CAM9C"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { apiClient } from '@endora-commerce/admin-kit/lib';
|
|
2
|
+
/**
|
|
3
|
+
* The two page-builder configuration calls the colour palette makes, rebuilt on
|
|
4
|
+
* the published `apiClient` — the **client exit**
|
|
5
|
+
* (`specs/091-module-owned-admin-surfaces/contracts/admin-component-contribution.md`
|
|
6
|
+
* Z1.2, which is P2's clarification of R6 and needs no new rule).
|
|
7
|
+
*
|
|
8
|
+
* `ColorPaletteProvider` reached `cms`' own `cmsClient` for these, which is the
|
|
9
|
+
* one kind of module knowledge a published component may carry and rebuild: an
|
|
10
|
+
* HTTP path plus a contract type. `CmsColorPaletteEntry`,
|
|
11
|
+
* `CmsPageBuilderDescriptor` and `PutCmsColorPaletteRequest` are all
|
|
12
|
+
* `@endora-commerce/contracts`', so nothing here is a copy of a `cms` type.
|
|
13
|
+
*
|
|
14
|
+
* **The exposure is carried across unchanged and is recorded rather than
|
|
15
|
+
* solved** (Z1.2). The endpoint is `cms`', so an operator who switches `cms` off
|
|
16
|
+
* gets a 503 here — as they did before this package existed. The call site
|
|
17
|
+
* degrades to an empty palette and the builder still opens, which is honest.
|
|
18
|
+
* Whether a colour palette belongs to `cms` at all or to the platform is a
|
|
19
|
+
* question for whoever next touches
|
|
20
|
+
* `GET /api/v1/admin/cms/page-builder/config`, and it is not P5's.
|
|
21
|
+
*/
|
|
22
|
+
const CONFIG_PATH = '/api/v1/admin/cms/page-builder/config';
|
|
23
|
+
const PALETTE_PATH = '/api/v1/admin/cms/page-builder/color-palette';
|
|
24
|
+
/** The saved palette, or an empty one for a descriptor that carries none. */
|
|
25
|
+
export async function getPageBuilderColorPalette() {
|
|
26
|
+
const out = await apiClient.get(CONFIG_PATH);
|
|
27
|
+
return out.data.colorPalette ?? [];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The whole descriptor — every block and every palette section the composed,
|
|
31
|
+
* effectively present modules declare (feature 096, T210).
|
|
32
|
+
*
|
|
33
|
+
* The e-mail builder needs it for the same reason the CMS builder does: the
|
|
34
|
+
* sections it renders are no longer a `categories` map inside
|
|
35
|
+
* `@endora-commerce/email-components` but declarations made by
|
|
36
|
+
* `transactional_emails`, `orders` and `catalog`, merged per `(key, context)`
|
|
37
|
+
* and filtered to the modules an operator has switched on. Switching `orders`
|
|
38
|
+
* off is what takes the *Order* section out of the palette, and no constant in
|
|
39
|
+
* a package can answer that.
|
|
40
|
+
*/
|
|
41
|
+
export async function getPageBuilderDescriptor() {
|
|
42
|
+
const out = await apiClient.get(CONFIG_PATH);
|
|
43
|
+
return out.data;
|
|
44
|
+
}
|
|
45
|
+
/** Replace the palette wholesale; the server answers with what it stored. */
|
|
46
|
+
export async function putPageBuilderColorPalette(body) {
|
|
47
|
+
const out = await apiClient.put(PALETTE_PATH, body);
|
|
48
|
+
return out.data;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=cms-page-builder-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cms-page-builder-api.js","sourceRoot":"","sources":["../../src/chrome/cms-page-builder-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAO3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,GAAG,uCAAuC,CAAC;AAC5D,MAAM,YAAY,GAAG,8CAA8C,CAAC;AAEpE,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAqC,WAAW,CAAC,CAAC;IACjF,OAAO,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAqC,WAAW,CAAC,CAAC;IACjF,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,IAA+B;IAE/B,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAC7B,YAAY,EACZ,IAAI,CACL,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Data } from '@measured/puck';
|
|
2
|
+
export declare function emptyPageBuilderData(): Data;
|
|
3
|
+
/** True when the canvas has no top-level components. */
|
|
4
|
+
export declare function isEmptyPageBuilderData(data: Data | null | undefined): boolean;
|
|
5
|
+
//# sourceMappingURL=page-builder-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-builder-data.d.ts","sourceRoot":"","sources":["../../src/chrome/page-builder-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAI3C,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED,wDAAwD;AACxD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAI7E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const EMPTY_DATA = { root: { props: {} }, content: [] };
|
|
2
|
+
export function emptyPageBuilderData() {
|
|
3
|
+
return structuredClone(EMPTY_DATA);
|
|
4
|
+
}
|
|
5
|
+
/** True when the canvas has no top-level components. */
|
|
6
|
+
export function isEmptyPageBuilderData(data) {
|
|
7
|
+
if (!data)
|
|
8
|
+
return true;
|
|
9
|
+
const content = data.content;
|
|
10
|
+
return !Array.isArray(content) || content.length === 0;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=page-builder-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-builder-data.js","sourceRoot":"","sources":["../../src/chrome/page-builder-data.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAS,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAE9D,MAAM,UAAU,oBAAoB;IAClC,OAAO,eAAe,CAAC,UAAU,CAAC,CAAC;AACrC,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,sBAAsB,CAAC,IAA6B;IAClE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode } from 'react';
|
|
2
|
+
/** Puck action bar — default actions plus EmailRow layout controls. */
|
|
3
|
+
export declare function EmailBuilderActionBar({ label, children, parentAction, }: {
|
|
4
|
+
label?: string;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
parentAction: ReactNode;
|
|
7
|
+
}): ReactElement;
|
|
8
|
+
//# sourceMappingURL=EmailBuilderActionBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailBuilderActionBar.d.ts","sourceRoot":"","sources":["../../src/email/EmailBuilderActionBar.tsx"],"names":[],"mappings":"AAGA,OAAO,EAOL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA8If,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,QAAQ,EACR,YAAY,GACb,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,CAAC;IACpB,YAAY,EAAE,SAAS,CAAC;CACzB,GAAG,YAAY,CAsBf"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { Children, useEffect, useLayoutEffect, useRef, useState, } from 'react';
|
|
5
|
+
import { ActionBar } from '@measured/puck';
|
|
6
|
+
import { LayoutGrid, Plus } from 'lucide-react';
|
|
7
|
+
import { EMAIL_ROW_LAYOUT_PRESETS, addEmailColumnFitRow, applyEmailRowLayoutPreset, replaceEmailRowInData, } from '@endora-commerce/email-components';
|
|
8
|
+
import { usePageBuilderPuck } from '@endora-commerce/page-builder-core/editor';
|
|
9
|
+
import { useActionBarTarget } from '../chrome/action-bar-target.js';
|
|
10
|
+
import { QuickTooltip, wrapQuickTooltip } from '../chrome/QuickTooltip.js';
|
|
11
|
+
function EmailRowLayoutFlyout({ anchorRef, onClose, onSelect, }) {
|
|
12
|
+
const [style, setStyle] = useState({ visibility: 'hidden' });
|
|
13
|
+
const [portalRoot, setPortalRoot] = useState(null);
|
|
14
|
+
const menuRef = useRef(null);
|
|
15
|
+
useLayoutEffect(() => {
|
|
16
|
+
const anchor = anchorRef.current;
|
|
17
|
+
if (!anchor)
|
|
18
|
+
return;
|
|
19
|
+
const doc = anchor.ownerDocument;
|
|
20
|
+
setPortalRoot(doc.body);
|
|
21
|
+
const rect = anchor.getBoundingClientRect();
|
|
22
|
+
setStyle({
|
|
23
|
+
position: 'fixed',
|
|
24
|
+
top: rect.bottom + 6,
|
|
25
|
+
left: rect.left,
|
|
26
|
+
zIndex: 9999,
|
|
27
|
+
visibility: 'visible',
|
|
28
|
+
});
|
|
29
|
+
}, [anchorRef]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const anchor = anchorRef.current;
|
|
32
|
+
const doc = anchor?.ownerDocument ?? document;
|
|
33
|
+
const onPointerDown = (event) => {
|
|
34
|
+
const target = event.target;
|
|
35
|
+
if (menuRef.current?.contains(target) || anchorRef.current?.contains(target))
|
|
36
|
+
return;
|
|
37
|
+
onClose();
|
|
38
|
+
};
|
|
39
|
+
const onKeyDown = (event) => {
|
|
40
|
+
if (event.key === 'Escape')
|
|
41
|
+
onClose();
|
|
42
|
+
};
|
|
43
|
+
doc.addEventListener('pointerdown', onPointerDown);
|
|
44
|
+
doc.addEventListener('keydown', onKeyDown);
|
|
45
|
+
return () => {
|
|
46
|
+
doc.removeEventListener('pointerdown', onPointerDown);
|
|
47
|
+
doc.removeEventListener('keydown', onKeyDown);
|
|
48
|
+
};
|
|
49
|
+
}, [anchorRef, onClose]);
|
|
50
|
+
if (!portalRoot)
|
|
51
|
+
return null;
|
|
52
|
+
return createPortal(_jsxs("div", { ref: menuRef, className: "pb-row-action-flyout", style: style, role: "menu", children: [_jsx("p", { className: "pb-row-action-flyout__heading", children: "Layout" }), EMAIL_ROW_LAYOUT_PRESETS.map((preset) => (_jsx("button", { type: "button", className: "pb-row-action-flyout__item", onClick: () => onSelect(preset.id), children: preset.label }, preset.id)))] }), portalRoot);
|
|
53
|
+
}
|
|
54
|
+
function EmailRowActionBarExtras({ rowId }) {
|
|
55
|
+
const dispatch = usePageBuilderPuck((s) => s.dispatch);
|
|
56
|
+
const getItemById = usePageBuilderPuck((s) => s.getItemById);
|
|
57
|
+
const [layoutOpen, setLayoutOpen] = useState(false);
|
|
58
|
+
const layoutAnchorRef = useRef(null);
|
|
59
|
+
/**
|
|
60
|
+
* Slot columns live in both `props.content` and `zones[rowId:content]`.
|
|
61
|
+
* A plain Puck `replace` updates props (Outline) but can leave the canvas
|
|
62
|
+
* DropZone on a stale zone — use setData + replaceEmailRowInData instead.
|
|
63
|
+
*/
|
|
64
|
+
const applyRow = (mutate) => {
|
|
65
|
+
const item = getItemById(rowId);
|
|
66
|
+
if (!item || item.type !== 'transactional_emails.EmailRow')
|
|
67
|
+
return;
|
|
68
|
+
const nextProps = mutate(item.props);
|
|
69
|
+
dispatch({
|
|
70
|
+
type: 'setData',
|
|
71
|
+
data: (previous) => replaceEmailRowInData(previous, rowId, {
|
|
72
|
+
type: 'transactional_emails.EmailRow',
|
|
73
|
+
props: { ...nextProps, id: rowId },
|
|
74
|
+
}),
|
|
75
|
+
recordHistory: true,
|
|
76
|
+
});
|
|
77
|
+
setLayoutOpen(false);
|
|
78
|
+
};
|
|
79
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { ref: layoutAnchorRef, className: "pb-row-action-bar__layout-anchor", children: _jsx(QuickTooltip, { text: "Column layout", children: _jsx(ActionBar.Action, { label: "Column layout", onClick: () => setLayoutOpen((open) => !open), children: _jsx(LayoutGrid, { size: 16 }) }) }) }), layoutOpen ? (_jsx(EmailRowLayoutFlyout, { anchorRef: layoutAnchorRef, onClose: () => setLayoutOpen(false), onSelect: (presetId) => applyRow((props) => applyEmailRowLayoutPreset(props, presetId)) })) : null, _jsx(QuickTooltip, { text: "Add column (max 6)", children: _jsx(ActionBar.Action, { label: "Add column", onClick: () => applyRow(addEmailColumnFitRow), children: _jsx(Plus, { size: 16 }) }) })] }));
|
|
80
|
+
}
|
|
81
|
+
/** Puck action bar — default actions plus EmailRow layout controls. */
|
|
82
|
+
export function EmailBuilderActionBar({ label, children, parentAction, }) {
|
|
83
|
+
const target = useActionBarTarget();
|
|
84
|
+
const selectedItem = usePageBuilderPuck((s) => s.selectedItem);
|
|
85
|
+
const selectedRowId = selectedItem?.type === 'transactional_emails.EmailRow' && typeof selectedItem.props.id === 'string'
|
|
86
|
+
? selectedItem.props.id
|
|
87
|
+
: null;
|
|
88
|
+
const rowId = label === 'Row' ? (target?.type === 'transactional_emails.EmailRow' ? target.id : selectedRowId) : null;
|
|
89
|
+
return (_jsxs(ActionBar, { children: [_jsxs(ActionBar.Group, { children: [wrapQuickTooltip(parentAction, 'parent'), label ? _jsx(ActionBar.Label, { label: label }) : null, rowId ? _jsx(EmailRowActionBarExtras, { rowId: rowId }) : null] }), _jsx(ActionBar.Group, { children: Children.map(children, (child, index) => wrapQuickTooltip(child, `action-${index}`)) })] }));
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=EmailBuilderActionBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailBuilderActionBar.js","sourceRoot":"","sources":["../../src/email/EmailBuilderActionBar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import '@endora-commerce/cms-components/styles.css';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import { type Data } from '@measured/puck';
|
|
4
|
+
import '@measured/puck/puck.css';
|
|
5
|
+
import { type EmailEmbeds, type EmailRenderEmbeds } from '@endora-commerce/email-components';
|
|
6
|
+
import { type PageBuilderContext } from '@endora-commerce/page-builder-core';
|
|
7
|
+
export type EmailPreviewWidth = 600 | 320;
|
|
8
|
+
export interface EmailEmbedCodeOption {
|
|
9
|
+
label: string;
|
|
10
|
+
value: string;
|
|
11
|
+
}
|
|
12
|
+
export interface EmailEditorPaneProps {
|
|
13
|
+
data: Data;
|
|
14
|
+
onChange: (data: Data) => void;
|
|
15
|
+
editorKey: string;
|
|
16
|
+
builderContext?: PageBuilderContext;
|
|
17
|
+
blockOptions?: EmailEmbedCodeOption[];
|
|
18
|
+
embeds?: EmailEmbeds;
|
|
19
|
+
/** Block/template trees for expanding EmailInsert* in HTML preview. */
|
|
20
|
+
embedTrees?: EmailRenderEmbeds;
|
|
21
|
+
/** Active content language — localizes built-in order sample strings / headers. */
|
|
22
|
+
previewLanguage?: string | null;
|
|
23
|
+
salesChannelId?: string | null;
|
|
24
|
+
/** Optional extra sample context (merged into preview variables). */
|
|
25
|
+
previewExtras?: Record<string, unknown>;
|
|
26
|
+
/** Save current canvas as an email template (TE templates store). */
|
|
27
|
+
onSaveAsTemplate?: (meta: {
|
|
28
|
+
name: string;
|
|
29
|
+
code: string;
|
|
30
|
+
}, data: Data) => void | Promise<void>;
|
|
31
|
+
/** List templates for the Apply template picker. */
|
|
32
|
+
onListTemplatesForApply?: () => Promise<Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
label: string;
|
|
35
|
+
}>>;
|
|
36
|
+
/** Load a template layout to replace the canvas. */
|
|
37
|
+
onResolveTemplateLayout?: (templateId: string) => Data | Promise<Data>;
|
|
38
|
+
}
|
|
39
|
+
declare function previewNode(content: Record<string, unknown>): ReactNode;
|
|
40
|
+
export declare function EmailEditorPane({ data, onChange, editorKey, builderContext, blockOptions, embeds: embedsProp, embedTrees: embedTreesProp, previewLanguage, salesChannelId, previewExtras, onSaveAsTemplate, onListTemplatesForApply, onResolveTemplateLayout, }: EmailEditorPaneProps): React.ReactElement;
|
|
41
|
+
export { previewNode };
|
|
42
|
+
//# sourceMappingURL=EmailEditorPane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailEditorPane.d.ts","sourceRoot":"","sources":["../../src/email/EmailEditorPane.tsx"],"names":[],"mappings":"AAAA,OAAO,4CAA4C,CAAC;AACpD,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC1F,OAAO,EAA2C,KAAK,IAAI,EAAmB,MAAM,gBAAgB,CAAC;AACrG,OAAO,yBAAyB,CAAC;AAEjC,OAAO,EAeL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EAIvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,oCAAoC,CAAC;AAyC5C,MAAM,MAAM,iBAAiB,GAAG,GAAG,GAAG,GAAG,CAAC;AA0B1C,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9F,oDAAoD;IACpD,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC9E,oDAAoD;IACpD,uBAAuB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAiCD,iBAAS,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAEhE;AA+bD,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,cAAwB,EACxB,YAAiB,EACjB,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,cAAc,EAC1B,eAAsB,EACtB,cAAqB,EACrB,aAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,GACxB,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,CAkV3C;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|