pagepilot-visual-editor 1.0.4 → 1.0.6
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 +277 -54
- package/dist/api/ApiClientContext.d.ts +17 -0
- package/dist/api/PagepilotApiClient.d.ts +63 -0
- package/dist/api/useTenantPlan.d.ts +25 -0
- package/dist/blocks-internal/block-button/src/index.d.ts +32 -1
- package/dist/blocks-internal/block-button-group/src/index.d.ts +20 -1
- package/dist/blocks-internal/block-columns-container/src/index.d.ts +38 -0
- package/dist/blocks-internal/block-container/src/index.d.ts +44 -5
- package/dist/blocks-internal/block-divider/src/index.d.ts +6 -0
- package/dist/blocks-internal/block-grid/src/index.d.ts +6 -0
- package/dist/blocks-internal/block-heading/src/index.d.ts +3 -2
- package/dist/blocks-internal/block-html/src/index.d.ts +6 -0
- package/dist/blocks-internal/block-iframe/src/index.d.ts +4 -0
- package/dist/blocks-internal/block-image/src/index.d.ts +17 -0
- package/dist/blocks-internal/block-logo/src/index.d.ts +20 -7
- package/dist/blocks-internal/block-stepper/src/index.d.ts +2 -2
- package/dist/blocks-internal/block-text/src/index.d.ts +1 -1
- package/dist/blocks-internal/block-video/src/index.d.ts +4 -0
- package/dist/blocks-internal/block-youtube-url/src/index.d.ts +4 -0
- package/dist/editor/Shell.d.ts +1 -1
- package/dist/editor/blockToggles.d.ts +1 -1
- package/dist/editor/publish/PagePublishDialog.d.ts +21 -0
- package/dist/editor/types.d.ts +63 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/ResponsiveModeContext.d.ts +12 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/blockStyleClipboard.d.ts +4 -4
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/AppBannerPickerSidebarPanel.d.ts +19 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/DemoPickerSidebarPanel.d.ts +31 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/EmailLayoutSidebarPanel.d.ts +26 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/FaqPickerSidebarPanel.d.ts +18 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/FormsPickerSidebarPanel.d.ts +18 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/MenuPickerSidebarPanel.d.ts +34 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/PaginationSidebarPanel.d.ts +7 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/TableSidebarPanel.d.ts +9 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/TimerSidebarPanel.d.ts +7 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/CollapsibleSection.d.ts +8 -2
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/MediaLibraryButton.d.ts +1 -1
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/SectionWrapper.d.ts +2 -1
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/deviceProp.d.ts +14 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/ColorInput/BaseColorInput.d.ts +4 -2
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/ColorInput/Picker.d.ts +7 -1
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/ColorInput/index.d.ts +3 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/PaddingInput.d.ts +4 -1
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/RadiusInput.d.ts +13 -11
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/SelectInput.d.ts +15 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/StepperInput.d.ts +19 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/WidthInputWithSelect.d.ts +4 -1
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/sanitizeAgainstSchema.d.ts +11 -0
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/style-inputs/MultiStylePropertyPanel.d.ts +2 -1
- package/dist/editor-sample/App/InspectorDrawer/EditorBehavior.d.ts +16 -0
- package/dist/editor-sample/App/InspectorDrawer/LayersPanelStyles.d.ts +2 -2
- package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/SectionsModal.d.ts +15 -0
- package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/TemplatePreviewDialog.d.ts +14 -0
- package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/TemplatesList.d.ts +45 -0
- package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/icons/index.d.ts +37 -1
- package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/templateApplyHelpers.d.ts +101 -0
- package/dist/editor-sample/App/InspectorDrawer/PagePilotAiPanel.d.ts +1 -0
- package/dist/editor-sample/App/InspectorDrawer/SeoPanel/SeoFieldLabel.d.ts +7 -0
- package/dist/editor-sample/App/InspectorDrawer/SeoPanel/SeoPanel.styled.d.ts +12 -0
- package/dist/editor-sample/App/InspectorDrawer/SeoPanel/index.d.ts +6 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/ApiResponseDialog.d.ts +10 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/ArrayFieldEditor.d.ts +14 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/ContainerRepeatSection.d.ts +9 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/DataReferenceDialog.d.ts +15 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/DataReferencePanel.d.ts +20 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/GrowDirectionDialog.d.ts +13 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/RowCard.d.ts +23 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/SectionHeader.d.ts +13 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/VariablesPaywall.d.ts +1 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/constants.d.ts +2 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/dataReferenceUtils.d.ts +34 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/index.d.ts +1 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/repeatRowActions.d.ts +31 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/styles.d.ts +53 -0
- package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/upgradeDialog.d.ts +4 -0
- package/dist/editor-sample/App/InspectorDrawer/components/MiniRichTextInput.d.ts +7 -0
- package/dist/editor-sample/App/InspectorDrawer/components/ScalarFieldInput.d.ts +10 -0
- package/dist/editor-sample/App/shared/editor.styles.d.ts +3 -3
- package/dist/editor-sample/documents/blocks/Accordion/AccordionPropsSchema.d.ts +6 -0
- package/dist/editor-sample/documents/blocks/AppBannerPicker/AppBannerEditor.d.ts +18 -0
- package/dist/editor-sample/documents/blocks/AppBannerPicker/AppBannerPropsSchema.d.ts +14 -0
- package/dist/editor-sample/documents/blocks/AppBannerPicker/appBanner.styled.d.ts +2 -0
- package/dist/editor-sample/documents/blocks/ButtonGroup/ButtonGroupPropsSchema.d.ts +20 -1
- package/dist/editor-sample/documents/blocks/Carousel/CarouselPropsSchema.d.ts +7 -0
- package/dist/editor-sample/documents/blocks/ColumnsContainer/ColumnsContainerPropsSchema.d.ts +38 -0
- package/dist/editor-sample/documents/blocks/Container/ContainerPropsSchema.d.ts +56 -3
- package/dist/editor-sample/documents/blocks/DemoPicker/DemoEditor.d.ts +3 -0
- package/dist/editor-sample/documents/blocks/DemoPicker/DemoPropsSchema.d.ts +37 -0
- package/dist/editor-sample/documents/blocks/EmailLayout/EmailLayoutEditor.d.ts +2 -0
- package/dist/editor-sample/documents/blocks/{PagePilotLayout/PagePilotLayoutPropsSchema.d.ts → EmailLayout/EmailLayoutPropsSchema.d.ts} +51 -4
- package/dist/editor-sample/documents/blocks/FaqPicker/FaqEditor.d.ts +18 -0
- package/dist/editor-sample/documents/blocks/FaqPicker/FaqPickerPropsSchema.d.ts +14 -0
- package/dist/editor-sample/documents/blocks/FaqPicker/faqPicker.styled.d.ts +3 -0
- package/dist/editor-sample/documents/blocks/FlexColumns/FlexColumnsEditor.d.ts +6 -0
- package/dist/editor-sample/documents/blocks/FormsPicker/FormsEditor.d.ts +3 -0
- package/dist/editor-sample/documents/blocks/FormsPicker/FormsPropsSchema.d.ts +33 -0
- package/dist/editor-sample/documents/blocks/Grid/GridPropsSchema.d.ts +13 -2
- package/dist/editor-sample/documents/blocks/Marquee/MarqueePropsSchema.d.ts +12 -0
- package/dist/editor-sample/documents/blocks/MenuPicker/MenuEditor.d.ts +7 -0
- package/dist/editor-sample/documents/blocks/MenuPicker/MenuPropsSchema.d.ts +45 -0
- package/dist/editor-sample/documents/blocks/MenuPicker/mergeMenuItems.d.ts +13 -0
- package/dist/editor-sample/documents/blocks/Pagination/PaginationEditor.d.ts +2 -0
- package/dist/editor-sample/documents/blocks/Pagination/PaginationPropsSchema.d.ts +4 -0
- package/dist/editor-sample/documents/blocks/Table/TableCellEditor.d.ts +11 -0
- package/dist/editor-sample/documents/blocks/Table/TableEditor.d.ts +2 -0
- package/dist/editor-sample/documents/blocks/Table/TablePropsSchema.d.ts +1 -0
- package/dist/editor-sample/documents/blocks/TabsBlock/TabsBlockPropsSchema.d.ts +12 -0
- package/dist/editor-sample/documents/blocks/Timer/TimerEditor.d.ts +2 -0
- package/dist/editor-sample/documents/blocks/Timer/TimerPropsSchema.d.ts +38 -0
- package/dist/editor-sample/documents/blocks/Timer/timerMath.d.ts +9 -0
- package/dist/editor-sample/documents/blocks/Timer/variants/CircularProgressView.d.ts +9 -0
- package/dist/editor-sample/documents/blocks/Timer/variants/DigitalFlipView.d.ts +9 -0
- package/dist/editor-sample/documents/blocks/Timer/variants/TextInlineView.d.ts +9 -0
- package/dist/editor-sample/documents/blocks/helpers/BlockCategories.d.ts +1 -0
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/BlockButton.d.ts +1 -1
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/BlocksMenu.d.ts +1 -1
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/DividerButton.d.ts +2 -1
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/PlaceholderButton.d.ts +2 -1
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/blockMenuStyles.d.ts +11 -0
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/brandButtonDefaults.d.ts +4 -2
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/buttons.d.ts +8 -0
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/gridPresets.d.ts +17 -0
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/index.d.ts +3 -2
- package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/index.d.ts +2 -1
- package/dist/editor-sample/documents/blocks/helpers/TStyle.d.ts +2 -0
- package/dist/editor-sample/documents/blocks/helpers/block-wrappers/saveAsTemplateUtils.d.ts +97 -0
- package/dist/editor-sample/documents/blocks/helpers/documentUtils.d.ts +96 -17
- package/dist/editor-sample/documents/blocks/helpers/responsiveStyle.d.ts +106 -0
- package/dist/editor-sample/documents/blocks/helpers/zod.d.ts +1 -1
- package/dist/editor-sample/documents/editor/EditorContext.d.ts +11 -2
- package/dist/editor-sample/documents/editor/core.d.ts +575 -16
- package/dist/editor-sample/documents/editor/templateVariables.d.ts +73 -0
- package/dist/email-builder-core/blocks/Accordion/AccordionPropsSchema.d.ts +6 -0
- package/dist/email-builder-core/blocks/AppBannerPicker/AppBannerPropsSchema.d.ts +16 -0
- package/dist/email-builder-core/blocks/AppBannerPicker/AppBannerReader.d.ts +3 -0
- package/dist/email-builder-core/blocks/ButtonGroup/ButtonGroupPropsSchema.d.ts +20 -1
- package/dist/email-builder-core/blocks/Calendly/CalendlyPropsSchema.d.ts +4 -0
- package/dist/email-builder-core/blocks/Carousel/CarouselPropsSchema.d.ts +6 -0
- package/dist/email-builder-core/blocks/ColumnsContainer/ColumnsContainerPropsSchema.d.ts +38 -0
- package/dist/email-builder-core/blocks/Container/ContainerPropsSchema.d.ts +56 -3
- package/dist/email-builder-core/blocks/DemoPicker/DemoPropsSchema.d.ts +36 -0
- package/dist/email-builder-core/blocks/DemoPicker/DemoReader.d.ts +3 -0
- package/dist/email-builder-core/blocks/{PagePilotLayout/PagePilotLayoutPropsSchema.d.ts → EmailLayout/EmailLayoutPropsSchema.d.ts} +41 -2
- package/dist/email-builder-core/blocks/EmailLayout/EmailLayoutReader.d.ts +3 -0
- package/dist/email-builder-core/blocks/EmailLayout/emailLayoutResponsive.d.ts +46 -0
- package/dist/email-builder-core/blocks/FaqPicker/FaqPickerPropsSchema.d.ts +16 -0
- package/dist/email-builder-core/blocks/FaqPicker/FaqReader.d.ts +3 -0
- package/dist/email-builder-core/blocks/FlexColumns/FlexColumnsPropsSchema.d.ts +23 -2
- package/dist/email-builder-core/blocks/FlexColumns/FlexColumnsReader.d.ts +6 -0
- package/dist/email-builder-core/blocks/FlexColumns/flexColumnsHelpers.d.ts +71 -1
- package/dist/email-builder-core/blocks/FormsPicker/FormsPropsSchema.d.ts +19 -0
- package/dist/email-builder-core/blocks/FormsPicker/FormsReader.d.ts +3 -0
- package/dist/email-builder-core/blocks/Grid/GridPropsSchema.d.ts +12 -2
- package/dist/email-builder-core/blocks/Marquee/MarqueePropsSchema.d.ts +16 -0
- package/dist/email-builder-core/blocks/Marquee/MarqueeReader.d.ts +1 -1
- package/dist/email-builder-core/blocks/Marquee/marqueeMotion.d.ts +40 -0
- package/dist/email-builder-core/blocks/MenuPicker/MenuPropsSchema.d.ts +87 -0
- package/dist/email-builder-core/blocks/MenuPicker/MenuReader.d.ts +3 -0
- package/dist/email-builder-core/blocks/MenuPicker/menuResponsiveCss.d.ts +27 -0
- package/dist/email-builder-core/blocks/Pagination/PaginationPropsSchema.d.ts +119 -0
- package/dist/email-builder-core/blocks/Pagination/PaginationReader.d.ts +2 -0
- package/dist/email-builder-core/blocks/Pagination/paginationShared.d.ts +74 -0
- package/dist/email-builder-core/blocks/Table/TablePropsSchema.d.ts +48 -0
- package/dist/email-builder-core/blocks/Table/TableReader.d.ts +13 -0
- package/dist/email-builder-core/blocks/TabsBlock/TabsBlockPropsSchema.d.ts +12 -0
- package/dist/email-builder-core/blocks/Timer/TimerPropsSchema.d.ts +38 -0
- package/dist/email-builder-core/blocks/Timer/TimerReader.d.ts +2 -0
- package/dist/email-builder-core/blocks/Timer/variants/CircularProgressView.d.ts +11 -0
- package/dist/email-builder-core/blocks/Timer/variants/DigitalFlipView.d.ts +11 -0
- package/dist/email-builder-core/blocks/Timer/variants/TextInlineView.d.ts +11 -0
- package/dist/email-builder-core/blocks/responsiveBreakpoints.d.ts +32 -0
- package/dist/host-stubs/modules/_hostListShim.d.ts +18 -0
- package/dist/host-stubs/modules/appBannerV2/list/appBannerListActions.d.ts +1 -0
- package/dist/host-stubs/modules/appBannerV2/list/appBannerListSelectors.d.ts +1 -0
- package/dist/host-stubs/modules/demo/list/demoListActions.d.ts +1 -0
- package/dist/host-stubs/modules/demo/list/demoListSelectors.d.ts +1 -0
- package/dist/host-stubs/modules/faqGroup/list/faqGroupListActions.d.ts +1 -0
- package/dist/host-stubs/modules/faqGroup/list/faqGroupListSelectors.d.ts +1 -0
- package/dist/host-stubs/modules/forms/formsService.d.ts +9 -0
- package/dist/host-stubs/modules/menu/list/menuListActions.d.ts +1 -0
- package/dist/host-stubs/modules/menu/list/menuListSelectors.d.ts +1 -0
- package/dist/host-stubs/modules/store.d.ts +3 -0
- package/dist/host-stubs/react-redux.d.ts +3 -0
- package/dist/host-stubs/style/menu.styled.d.ts +73 -15
- package/dist/host-stubs/tanstack-react-query.d.ts +9 -0
- package/dist/host-stubs/view/shared/htmlSanitize.d.ts +15 -0
- package/dist/index.cjs +381 -817
- package/dist/index.d.ts +2 -0
- package/dist/index.js +64041 -101752
- package/dist/style.css +1 -1
- package/package.json +2 -10
- package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/PagePilotLayoutSidebarPanel.d.ts +0 -24
- package/dist/editor-sample/documents/blocks/PagePilotLayout/PagePilotLayoutEditor.d.ts +0 -2
- package/dist/email-builder-core/blocks/PagePilotLayout/PagePilotLayoutReader.d.ts +0 -3
package/README.md
CHANGED
|
@@ -5,9 +5,16 @@ A standalone, prop-driven **React page-type visual editor**. Drop
|
|
|
5
5
|
props, and listen for `onSaveChanges` / `onPublish` callbacks — the editor
|
|
6
6
|
handles the UI, block creation, multi-section management, and HTML rendering.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
Two integration modes:
|
|
9
|
+
|
|
10
|
+
1. **Callback-only** *(default)*. The package is purely the editor: no
|
|
11
|
+
backend calls, no host coupling. The host owns persistence, navigation,
|
|
12
|
+
plan gating, theming overrides, and everything else.
|
|
13
|
+
2. **Service-account API** *(opt-in via the `apiConfig` prop)*. Point the
|
|
14
|
+
editor at a pagepilot API instance and it takes over save / publish /
|
|
15
|
+
template listing / section library / tenant-plan gating for you. Same
|
|
16
|
+
auth pattern ahd-fe uses internally (`Authorization: Bearer <token>`),
|
|
17
|
+
configured once at mount time. See [Pagepilot API integration](#pagepilot-api-integration-optional).
|
|
11
18
|
|
|
12
19
|
|
|
13
20
|
---
|
|
@@ -27,35 +34,12 @@ Peer dependencies (your host should provide these):
|
|
|
27
34
|
| Peer | Range | Notes |
|
|
28
35
|
|---|---|---|
|
|
29
36
|
| `react` | `^18.0.0 \|\| ^19.0.0` | React 18 and 19 both supported |
|
|
30
|
-
| `react-dom` | `^18.0.0 \|\| ^19.0.0` |
|
|
37
|
+
| `react-dom` | `^18.0.0 \|\| ^19.0.0` | Match your `react` version |
|
|
31
38
|
| `@mui/material` | `>=5` | v6 tested; v5 works |
|
|
32
39
|
| `@mui/icons-material` | `>=5` | |
|
|
33
40
|
| `@emotion/react` | `>=11` | Required by MUI |
|
|
34
41
|
| `@emotion/styled` | `>=11` | Required by MUI |
|
|
35
42
|
|
|
36
|
-
> **Avoiding "Incompatible React versions" at runtime**
|
|
37
|
-
>
|
|
38
|
-
> npm 7+ auto-installs peer deps, which can pull `react-dom@latest` into your
|
|
39
|
-
> app even when your `react` is pinned to an older patch. React refuses to
|
|
40
|
-
> boot when the two versions differ. Force alignment by adding this to your
|
|
41
|
-
> host app's `package.json`:
|
|
42
|
-
>
|
|
43
|
-
> ```json
|
|
44
|
-
> {
|
|
45
|
-
> "overrides": {
|
|
46
|
-
> "react-dom": "$react",
|
|
47
|
-
> "@types/react-dom": "$@types/react"
|
|
48
|
-
> },
|
|
49
|
-
> "resolutions": {
|
|
50
|
-
> "react-dom": "$react",
|
|
51
|
-
> "@types/react-dom": "$@types/react"
|
|
52
|
-
> }
|
|
53
|
-
> }
|
|
54
|
-
> ```
|
|
55
|
-
>
|
|
56
|
-
> Then delete `node_modules` + `package-lock.json` and re-run `npm install`
|
|
57
|
-
> (`overrides` is npm/pnpm, `resolutions` is yarn — safe to keep both).
|
|
58
|
-
|
|
59
43
|
**Also required at runtime** (not currently listed as a peer, but the built
|
|
60
44
|
bundle keeps them external — install these alongside the peers above):
|
|
61
45
|
|
|
@@ -116,21 +100,25 @@ built-in layout doesn't scale unexpectedly.
|
|
|
116
100
|
|
|
117
101
|
```
|
|
118
102
|
┌──────────────────────────────────────────────────────────────────────────┐
|
|
119
|
-
│ ← Back My Page ● Draft [Section ▾] ↶ ↷ Save ⋮ ⤢ ▶ Publish ▾
|
|
103
|
+
│ ← Back My Page ● Draft [Section ▾] ↶ ↷ ⊟ Save ⋮ ⤢ ▶ Publish ▾ │ Topbar
|
|
120
104
|
├──────┬───────────────────┬─────────────────────────────────────────────┤
|
|
121
105
|
│Style │ Appearance │ │
|
|
122
106
|
│Layout│ Color ▢ ... │ (canvas — block-based editor) │
|
|
123
107
|
│Inspct│ Font ▾ │ │
|
|
124
108
|
│Layers│ Radius PX │ │
|
|
125
|
-
│
|
|
126
|
-
│
|
|
109
|
+
│Vars* │ Layout │ │
|
|
110
|
+
│SEO │ Width 100 % │ │
|
|
111
|
+
│PgPlt │ │ │
|
|
127
112
|
└──────┴───────────────────┴─────────────────────────────────────────────┘
|
|
113
|
+
* only when template has vars
|
|
128
114
|
```
|
|
129
115
|
|
|
130
|
-
- **Left rail** —
|
|
131
|
-
- **Topbar** — every control is individually toggleable via the `topbar` prop.
|
|
116
|
+
- **Left rail** — up to 7 panels: **Style**, **Layout**, **Inspect**, **Layers**, **Variables**, **SEO**, **Pagepilot** (each can be toggled off via the `panels` prop). Variables auto-hides unless a template with fields is applied or a repeatable container is selected. Pagepilot currently renders a "Coming soon" placeholder — the full AI page generator lands in a future release.
|
|
117
|
+
- **Topbar** — every control is individually toggleable via the `topbar` prop. Includes undo / redo / **deselect block** (auto-hidden when nothing is selected) / save / more menu / fullscreen / preview / publish.
|
|
132
118
|
- **Canvas** — the block-based page editor. Click the empty-state "Add first section" or the ⋮ → Add Section.
|
|
119
|
+
- **Block TuneMenu** — appears above any selected block: move up / move down / delete / **open in Layers** / **more menu** (Save as template / Duplicate / Copy / Paste / **Replace** / Hide).
|
|
133
120
|
- **3-dot menu** — currently exposes a single item, **Add Section**. Hidden by default; set `topbar.moreMenu` to `true`.
|
|
121
|
+
- **Layout panel** — the Blocks palette is grouped into six categories (`Text/Content`, `Media`, `Layout/Structure`, `Actions/Controls`, `Embeds/Integrations`, `Support/Utility`). When `apiConfig` is passed, two additional tabs appear: **Templates** (global page templates) and **Saved** (per-tenant templates), plus a **Section Library** tile that opens a full gallery of section templates.
|
|
134
122
|
|
|
135
123
|
---
|
|
136
124
|
|
|
@@ -146,6 +134,7 @@ built-in layout doesn't scale unexpectedly.
|
|
|
146
134
|
| `activeStepIndex` | `number` | `0` | Index of the currently-active section in the canvas. The editor also tracks this internally via the section dropdown. |
|
|
147
135
|
| `behaviour` | `Record<string, any>` | `undefined` | **Passthrough only** — the editor does not consume this. Preserved in the save/publish payload if non-empty so host-owned config survives a round-trip. |
|
|
148
136
|
| `steps` | `PageRecord["steps"]` | `undefined` | **Passthrough only** — legacy shape from the original tour/tooltip editor. The page editor does not read or render `steps`; it's preserved in the save payload when non-empty. |
|
|
137
|
+
| `apiConfig` | `PagepilotApiConfig` | `undefined` | Opt-in pagepilot API integration. When passed, save/publish PUT the record through the API, Layout gets Templates / Saved tabs, Add-Block menu gets the Section Library tile, Publish opens a rich dialog, Variables panel gates on tenant plan. See [Pagepilot API integration](#pagepilot-api-integration-optional). |
|
|
149
138
|
|
|
150
139
|
The editor reads `record.contentMetadata.document` (or `record.sections[activeStepIndex].contentMetadata.document` for multi-section pages) and seeds the canvas on first mount. After that the editor owns the document state; the host receives mutations via `onUpdateRecord`.
|
|
151
140
|
|
|
@@ -213,6 +202,11 @@ interface EditorPanelToggles {
|
|
|
213
202
|
layout?: boolean; // default true
|
|
214
203
|
inspect?: boolean; // default true
|
|
215
204
|
layers?: boolean; // default true
|
|
205
|
+
variables?: boolean; // default true — auto-hides when no template forms
|
|
206
|
+
// and no repeatable container selected
|
|
207
|
+
seo?: boolean; // default true
|
|
208
|
+
pagepilot?: boolean; // default true — Pagepilot AI tab (currently
|
|
209
|
+
// renders a "Coming soon" placeholder)
|
|
216
210
|
}
|
|
217
211
|
```
|
|
218
212
|
|
|
@@ -226,6 +220,8 @@ interface TopbarToggles {
|
|
|
226
220
|
sectionsDropdown?: boolean; // default true — still requires sections.length > 1
|
|
227
221
|
undo?: boolean; // default true
|
|
228
222
|
redo?: boolean; // default true
|
|
223
|
+
unselect?: boolean; // default true — Deselect Block button
|
|
224
|
+
// (auto-hides when nothing selected)
|
|
229
225
|
save?: boolean; // default true
|
|
230
226
|
themeToggle?: boolean; // default true — sun/moon button flipping light/dark
|
|
231
227
|
fullscreen?: boolean; // default true
|
|
@@ -249,7 +245,10 @@ type BlockKey =
|
|
|
249
245
|
| "buttonGroup" | "container"
|
|
250
246
|
| "stepper" | "accordion" | "pricingAccordion"
|
|
251
247
|
| "tabs" | "carousel" | "rating" | "marquee"
|
|
252
|
-
| "iframe" | "skipToMain" | "accessibilityTools"
|
|
248
|
+
| "iframe" | "skipToMain" | "accessibilityTools"
|
|
249
|
+
| "timer" | "pagination" | "table"
|
|
250
|
+
| "demoPicker" | "menuPicker" | "formsPicker"
|
|
251
|
+
| "appBannerPicker" | "faqPicker";
|
|
253
252
|
|
|
254
253
|
type BlockToggles = Partial<Record<BlockKey, boolean>>;
|
|
255
254
|
```
|
|
@@ -281,6 +280,8 @@ type BlockToggles = Partial<Record<BlockKey, boolean>>;
|
|
|
281
280
|
| `onBackgroundChange` | `(image: string) => void` | Fires when the page-level background image changes. |
|
|
282
281
|
| `onNavigateBranding` | `() => void` | Fires from the Brand panel (currently stripped from the standalone build — kept for forward-compat). |
|
|
283
282
|
| `onAddSection` | `() => void` | Custom Add-Section handler. **If provided**, the editor delegates entirely to the host — no built-in dialog. **If omitted**, clicking ⋮ → Add Section opens the built-in dialog. |
|
|
283
|
+
| `onApiError` | `(error: Error, action: "save" \| "publish") => void` | Fires when a save/publish through `apiConfig` fails (network error, non-2xx response, invalid credentials, missing page id, etc.). Without this callback, failures only surface via `console.error` — the Save button stays "dirty" with no user-visible feedback. Use it to show a toast, refresh the auth token, redirect to a login screen, etc. Only relevant when `apiConfig` is set. |
|
|
284
|
+
| `onUpgrade` | `() => void` | Fires when the user clicks the **Upgrade to unlock** CTA on the Variables-panel paywall. Route it to your billing / upgrade UI. Without this callback the button is a no-op. Only relevant when `apiConfig` is set. |
|
|
284
285
|
|
|
285
286
|
#### `SaveChangesPayload`
|
|
286
287
|
|
|
@@ -329,6 +330,190 @@ Single-doc mode (no `sections`) is unchanged — the payload still carries
|
|
|
329
330
|
|
|
330
331
|
---
|
|
331
332
|
|
|
333
|
+
## Pagepilot API integration (optional)
|
|
334
|
+
|
|
335
|
+
Passing `apiConfig` to `<PagePilotEditor>` turns the editor into a full page-management surface. Under the hood it uses the exact auth + endpoint shapes that ahd-fe uses internally (`Authorization: Bearer <serviceAccountToken>`), so pages saved from the standalone editor round-trip identically to pages saved from ahd-fe.
|
|
336
|
+
|
|
337
|
+
### What you get
|
|
338
|
+
|
|
339
|
+
| Feature | Where it appears |
|
|
340
|
+
|---|---|
|
|
341
|
+
| Save Changes → `POST /tenant/:tenantId/upsert-page-item` | Topbar Save button + `apiClient.updatePage` fallback |
|
|
342
|
+
| Publish → same endpoint with `status: "live"` + schedule | Topbar Publish opens a rich `PagePublishDialog` |
|
|
343
|
+
| Templates tab (global page templates) | Layout panel > Templates |
|
|
344
|
+
| Saved tab (per-tenant `my-templates`) | Layout panel > Saved |
|
|
345
|
+
| Section Library gallery | Add-Block menu → Section Library tile |
|
|
346
|
+
| Template preview dialog (Use / Use Styles / Add Section) | Clicking any template card |
|
|
347
|
+
| Menu Links tab (add page to tenant menu) | Publish dialog |
|
|
348
|
+
| Variables panel with paywall gated on tenant plan | Left rail → Variables (auto-shown when template has fields) |
|
|
349
|
+
| `getTenant()` for plan detection | Runs once on mount when `apiConfig` is set |
|
|
350
|
+
|
|
351
|
+
### Setup
|
|
352
|
+
|
|
353
|
+
```tsx
|
|
354
|
+
import { PagePilotEditor } from "pagepilot-visual-editor";
|
|
355
|
+
|
|
356
|
+
<PagePilotEditor
|
|
357
|
+
record={page}
|
|
358
|
+
apiConfig={{
|
|
359
|
+
baseUrl: "https://pagepilot.fabbuilder.com/api", // no trailing slash, no "/tenant"
|
|
360
|
+
tenantId: "6655bc2b30a6760d8f897581", // your pagepilot tenant id
|
|
361
|
+
authToken: "eyJhbGciOi…", // pre-issued service-account bearer
|
|
362
|
+
}}
|
|
363
|
+
onApiError={(err, action) => toast.error(`${action}: ${err.message}`)}
|
|
364
|
+
onUpgrade={() => openBillingModal()}
|
|
365
|
+
// onSaveChanges / onPublish still fire AFTER a successful API write
|
|
366
|
+
// if you also want to react (e.g. clear a dirty flag, refresh a listing).
|
|
367
|
+
onSaveChanges={async ({ record }) => { revalidatePageList(); }}
|
|
368
|
+
/>
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Requirements for the API path to actually fire:
|
|
372
|
+
|
|
373
|
+
- `record.id` must be a real backend id (a MongoDB ObjectId in the tenant). The built-in seed id `"doc-1"` is intentionally skipped so demo records don't POST to a non-existent page.
|
|
374
|
+
- The `authToken` must be a valid service-account bearer for the given `tenantId`. Get one from your pagepilot admin console (same token ahd-fe stores in `VITE_PAGEPILOT_SERVICE_AUTH_TOKEN`).
|
|
375
|
+
|
|
376
|
+
### PagepilotApiConfig shape
|
|
377
|
+
|
|
378
|
+
```ts
|
|
379
|
+
interface PagepilotApiConfig {
|
|
380
|
+
/** API root without a trailing slash, e.g. "https://pagepilot.fabbuilder.com/api". */
|
|
381
|
+
baseUrl: string;
|
|
382
|
+
/** Tenant id used in `/tenant/${tenantId}/...` paths. */
|
|
383
|
+
tenantId: string;
|
|
384
|
+
/** Pre-issued service-account bearer. Sent as `Authorization: Bearer <token>`. */
|
|
385
|
+
authToken: string;
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Save + Publish request shape
|
|
390
|
+
|
|
391
|
+
The editor batches the render + payload build for you. When the user clicks **Save Changes** or **Publish**, this exact request goes out:
|
|
392
|
+
|
|
393
|
+
```http
|
|
394
|
+
POST https://pagepilot.fabbuilder.com/api/tenant/${tenantId}/upsert-page-item
|
|
395
|
+
Content-Type: application/json
|
|
396
|
+
Authorization: Bearer ${authToken}
|
|
397
|
+
|
|
398
|
+
{
|
|
399
|
+
"data": {
|
|
400
|
+
...record, // full record — id, name, slug, tags, groups, tenant, …
|
|
401
|
+
"pageId": "6a43bc20…", // === record.id
|
|
402
|
+
"status": "live" | "draft", // "draft" for Save Changes, "live" for Publish
|
|
403
|
+
"sections": [ // rendered sections (source of truth for multi-section pages)
|
|
404
|
+
{
|
|
405
|
+
"title": "Section 1",
|
|
406
|
+
"sectionType": "internal",
|
|
407
|
+
"identifier": "section-1784032010220",
|
|
408
|
+
"content": "<div …>…rendered HTML…</div>",
|
|
409
|
+
"contentMetadata": {
|
|
410
|
+
"document": { "root": { "type": "EmailLayout", … }, "block-…": {…} }
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
"startDate": "…", // optional — only when Publish schedule is set
|
|
415
|
+
"endDate": "…" // optional — only when Publish schedule is set
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Same shape ahd-fe writes.** The rendered `sections[].content` HTML is what the pagepilot public page-serving layer reads.
|
|
421
|
+
|
|
422
|
+
**Failure handling.** Any non-2xx response throws inside the editor. Without `onApiError`, the error is logged to `console.error` and the Save button stays visually "dirty" (no state change). Passing `onApiError` lets you surface it to the user:
|
|
423
|
+
|
|
424
|
+
```tsx
|
|
425
|
+
<PagePilotEditor
|
|
426
|
+
apiConfig={apiConfig}
|
|
427
|
+
onApiError={(err, action) => {
|
|
428
|
+
console.error(`[pagepilot] ${action} failed`, err);
|
|
429
|
+
toast.error(err.message);
|
|
430
|
+
}}
|
|
431
|
+
/>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### The Publish dialog
|
|
435
|
+
|
|
436
|
+
When `apiConfig` is set, clicking **Publish** opens a full dialog instead of firing `onPublish` immediately. The dialog mirrors ahd-fe's `PagePublishDialog`:
|
|
437
|
+
|
|
438
|
+
- **Basic Info** tab: page name, slug, publish date, "All Time Live" toggle, end date (when off).
|
|
439
|
+
- **Menu Links** tab: pick a tenant menu (fetched via `apiClient.listMenus`) and append this page as a new item to that menu's `configuration`.
|
|
440
|
+
- **Save Draft** and **Publish** buttons at the bottom. Both use the same `upsert-page-item` endpoint above; the CTA differs by the `status` field.
|
|
441
|
+
|
|
442
|
+
If you'd rather keep the direct one-click publish (fires `onPublish` without a dialog), set `apiConfig` to `undefined` — the direct callback flow still works.
|
|
443
|
+
|
|
444
|
+
### Templates + Saved + Section Library
|
|
445
|
+
|
|
446
|
+
- **Templates tab** (`Layout > Templates`): fetches `GET /global-template?filter[type]=page&limit=10&offset=0`. Click a card → preview dialog with three actions:
|
|
447
|
+
- **Use this Template** — replaces the canvas with the template's document.
|
|
448
|
+
- **Use this Styles** — overlays only the template's root visual styles (colors, fonts, radius, padding) onto your current document; blocks stay put.
|
|
449
|
+
- **Add this section** — appends the template's blocks to the current document (id-remapped so a second apply doesn't collide with the first).
|
|
450
|
+
- **Saved tab** (`Layout > Saved`): same UI, fetches `GET /tenant/${tenantId}/mytemplate?filter[type]=page&limit=10&offset=0`. Includes a delete affordance on hover.
|
|
451
|
+
- **Section Library** modal: opened from the "Section Library" tile in the Add-Block menu. Fetches `GET /global-template?filter[type]=block&limit=100&offset=0`, groups by category (`hero`, `features`, `testimonial`, `pricing`, `cta`, `faq`, `about`, `team`, `contact`, `footer`, …), and inserts the picked block as a new section.
|
|
452
|
+
|
|
453
|
+
Every apply route also populates the Variables panel from the template's declared `formFields`, so template tokens (`{{name}}`, `{{price}}`, `{{FAQs}}`, …) are ready to fill in immediately.
|
|
454
|
+
|
|
455
|
+
**Paywall.** Templates with a `supportedPlans: ["proCombo"]` (or higher) show an "Upgrade to unlock" prompt in the preview dialog when the tenant plan is below that tier. The `onUpgrade` callback routes the CTA to your billing UI.
|
|
456
|
+
|
|
457
|
+
### Variables panel + tenant plan gating
|
|
458
|
+
|
|
459
|
+
The Variables tab surfaces template tokens for filling at edit time. Visibility is controlled by:
|
|
460
|
+
|
|
461
|
+
1. **The template must declare fields.** The tab auto-hides on documents with no template forms and no repeatable container selected.
|
|
462
|
+
2. **The tenant plan must be Pro or above** (or the template must be unrestricted). The gate is checked once via `apiClient.getTenant()` on mount:
|
|
463
|
+
- `plan === "proCombo" | "enterprise"` → real field editors render.
|
|
464
|
+
- Anything else (including `"free"`, `"starterCombo"`, missing plan, failed fetch) → paywall renders.
|
|
465
|
+
3. **The paywall CTA** ("Upgrade to unlock") fires `onUpgrade` if the host provided it; otherwise it's a no-op with a console message.
|
|
466
|
+
|
|
467
|
+
The whole gating logic mirrors ahd-fe's `useTenantPlan` hook and can be safely disabled by passing `panels={{ variables: false }}` — the whole tab disappears from the rail.
|
|
468
|
+
|
|
469
|
+
### Direct API client access
|
|
470
|
+
|
|
471
|
+
The `PagepilotApiClient` class the editor uses internally is also exported so hosts can hit the same endpoints outside the editor tree — e.g. to create a page before mounting:
|
|
472
|
+
|
|
473
|
+
```ts
|
|
474
|
+
import { PagepilotApiClient } from "pagepilot-visual-editor";
|
|
475
|
+
|
|
476
|
+
const client = new PagepilotApiClient({
|
|
477
|
+
baseUrl: "https://pagepilot.fabbuilder.com/api",
|
|
478
|
+
tenantId: "6655bc2b30a6760d8f897581",
|
|
479
|
+
authToken: process.env.PAGEPILOT_SERVICE_TOKEN!,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const created = await client.createPage({
|
|
483
|
+
name: "New Onboarding Page",
|
|
484
|
+
slug: "onboarding",
|
|
485
|
+
groups: [],
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// Then mount the editor pointing at the new page.
|
|
489
|
+
<PagePilotEditor record={{ id: created.id, name: created.name }} apiConfig={...} />
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Available methods:
|
|
493
|
+
|
|
494
|
+
| Method | Endpoint |
|
|
495
|
+
|---|---|
|
|
496
|
+
| `createPage(data)` | `POST /tenant/:tenantId/page` |
|
|
497
|
+
| `updatePage(id, data)` | `PUT /tenant/:tenantId/page/:id` |
|
|
498
|
+
| `quickSavePage(id, data)` | `PATCH /tenant/:tenantId/page/:id` |
|
|
499
|
+
| `upsertPage(data)` | `POST /tenant/:tenantId/upsert-page-item` (used by save + publish) |
|
|
500
|
+
| `findPage(id)` | `GET /tenant/:tenantId/page/:id` |
|
|
501
|
+
| `getTenant()` | `GET /tenant/:tenantId` (used by plan gate) |
|
|
502
|
+
| `listGlobalTemplates(params)` | `GET /global-template` |
|
|
503
|
+
| `findGlobalTemplate(id)` | `GET /global-template/:id` |
|
|
504
|
+
| `destroyGlobalTemplates(ids)` | `DELETE /global-template` |
|
|
505
|
+
| `listTenantTemplates(params)` | `GET /tenant/:tenantId/template` |
|
|
506
|
+
| `findTenantTemplate(id)` | `GET /tenant/:tenantId/template/:id` |
|
|
507
|
+
| `listMyTemplates(params)` | `GET /tenant/:tenantId/mytemplate` |
|
|
508
|
+
| `createTemplate(data)` | `POST /tenant/:tenantId/template` |
|
|
509
|
+
| `destroyTenantTemplates(ids)` | `DELETE /tenant/:tenantId/template` |
|
|
510
|
+
| `listMenus(params)` | `GET /tenant/:tenantId/menu` |
|
|
511
|
+
| `updateMenu(id, data)` | `PUT /tenant/:tenantId/menu/:id` |
|
|
512
|
+
|
|
513
|
+
All methods send `Content-Type: application/json` + the bearer token automatically.
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
332
517
|
## Behavior reference
|
|
333
518
|
|
|
334
519
|
### Topbar buttons
|
|
@@ -339,7 +524,8 @@ Single-doc mode (no `sections`) is unchanged — the payload still carries
|
|
|
339
524
|
| **Page title + status pill** | Display-only. Sourced from `recordTitle` / `recordStatus` (or `record.title / record.name / record.status`). |
|
|
340
525
|
| **Section dropdown** | Only appears when `record.sections.length > 1`. Lets the user pick / edit / delete sections. Switching a section flushes the current canvas edits into the active section, then loads the target section's document onto the canvas. |
|
|
341
526
|
| **Undo / Redo** | Hooked to the editor's internal history stack. Buttons disable when there's nothing to undo/redo. A settle-window guard on mount prevents block-level `useEffect`s (auto-seed, positioning re-measure, etc.) from preloading spurious entries — Undo starts disabled on every fresh load until the user makes a real edit. |
|
|
342
|
-
| **
|
|
527
|
+
| **Deselect Block** ⊟ | Only appears when a block is selected on the canvas. Clears `selectedBlockId` so the block's TuneMenu / handles collapse and the Inspect panel unfocuses. Same behavior as ahd-fe's `TabUnselectedOutlined` button. Hidden entirely via `topbar={{ unselect: false }}`. |
|
|
528
|
+
| **Save Changes** | **Dirty-tracked.** Disabled with tooltip "No unsaved changes" until the user makes their first edit; enables on every subsequent edit; disables again after `onSaveChanges` resolves (unless the handler returns `false`). Builds the payload (renders document → HTML, flushes sections) and calls `onSaveChanges`. When `apiConfig` is set, the editor **first** persists via `POST /upsert-page-item`, then fires `onSaveChanges` — errors surface via `onApiError`. |
|
|
343
529
|
| **Theme toggle** ☀/🌙 | Sun/moon icon flips between the built-in light and dark themes. The choice is persisted in `localStorage` under `pagepilot.editor.mode.v1`, so a page reload keeps the user's preference — even if `props.mode` changes. Hidden automatically when the host passes a custom `theme` prop (no `mode` to flip). |
|
|
344
530
|
| **3-dot menu** ⋮ | Single item: **+ Add Section**. Off by default — enable via `topbar.moreMenu`. |
|
|
345
531
|
| **Fullscreen** ⤢ | Toggles the editor's container via the browser Fullscreen API. Icon swaps to "exit fullscreen" while active; pressing `Esc` exits. |
|
|
@@ -347,13 +533,36 @@ Single-doc mode (no `sections`) is unchanged — the payload still carries
|
|
|
347
533
|
| **Publish** | Calls `onPublish`. |
|
|
348
534
|
| **Publish ▾** | Calls `onPublishMenu(anchorEl, payload)` so the host can open a custom dialog/popover anchored to the button. |
|
|
349
535
|
|
|
536
|
+
### Block TuneMenu
|
|
537
|
+
|
|
538
|
+
Selecting any block on the canvas surfaces a floating action popover just above it. The strip contains, in order:
|
|
539
|
+
|
|
540
|
+
| Action | Behavior |
|
|
541
|
+
|---|---|
|
|
542
|
+
| **↑ Move up** | Swaps this block with its previous sibling under the same parent. |
|
|
543
|
+
| **↓ Move down** | Swaps with the next sibling. |
|
|
544
|
+
| **🗑 Delete** | Removes the block and its subtree. Also prunes any `formFields` whose `sourceBlockId` pointed at this block. |
|
|
545
|
+
| **⧉ Open in Layers** | Selects this block and flips the sidebar to the **Layers** tab so you can see (and drag/reorder) the block inside the tree. |
|
|
546
|
+
| **⋯ More menu** | Opens the secondary popover below. |
|
|
547
|
+
|
|
548
|
+
The **⋯ More** popover contains:
|
|
549
|
+
|
|
550
|
+
| Item | Behavior |
|
|
551
|
+
|---|---|
|
|
552
|
+
| **Save as template** | Serialises the selected block into a template configuration. Only wired when the host provides its own persistence path — the standalone build has no built-in "save template" dialog. |
|
|
553
|
+
| **Duplicate** | Deep-clones the block (all descendants get fresh ids) and inserts the copy right after the original. |
|
|
554
|
+
| **Copy** | Writes the block's configuration to the editor's clipboard slot. Persists across selection changes so you can paste onto a different block. |
|
|
555
|
+
| **Paste** | Enabled only when there's a copied block. Appends the copied block as a child of THIS block (id-remapped so nothing collides). |
|
|
556
|
+
| **Replace** | Enabled only when there's a copied block. Swaps THIS block in place with a fresh id-remapped copy of the clipboard's block — same position, new content. |
|
|
557
|
+
| **Hide** | Toggles the block's canvas visibility (collapses to `display: none`). Unhide from the Layers panel. |
|
|
558
|
+
|
|
350
559
|
### Add Section flow
|
|
351
560
|
|
|
352
561
|
1. User clicks ⋮ → **+ Add Section** (or the empty-state button).
|
|
353
562
|
2. A modal asks for a **Title**.
|
|
354
563
|
3. On submit:
|
|
355
564
|
- The active section's in-progress canvas document is flushed into `record.sections[activeIndex].contentMetadata.document` (no edits lost).
|
|
356
|
-
- A new section is appended, seeded with a default empty `
|
|
565
|
+
- A new section is appended, seeded with a default empty `EmailLayout` document.
|
|
357
566
|
- The host receives the updated record via `onUpdateRecord`.
|
|
358
567
|
- The canvas swaps to the new section's document so the user can immediately edit it.
|
|
359
568
|
- The active step index is bumped.
|
|
@@ -375,12 +584,20 @@ The image is inserted at the caret position and can then be resized
|
|
|
375
584
|
appears when you click it. The standalone editor deliberately doesn't ship
|
|
376
585
|
a media-library backend — the URL field is the integration point.
|
|
377
586
|
|
|
587
|
+
### Pagepilot AI panel
|
|
588
|
+
|
|
589
|
+
Currently a **Coming soon** placeholder. The tab has the purple `AiPanelIcon` in the rail and opens a centered card that says AI-driven page generation is on the way. When the full generator is ported (prompt input + model picker + voice input, per the ahd-fe reference), the panel body swaps in without any other API changes. Hide the tab entirely via `panels={{ pagepilot: false }}`.
|
|
590
|
+
|
|
378
591
|
### Layout panel
|
|
379
592
|
|
|
380
|
-
The Layout panel shows a
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
593
|
+
The Layout panel always shows the **Blocks** picker — a category-grouped tile grid (`Text/Content`, `Media`, `Layout/Structure`, `Actions/Controls`, `Embeds/Integrations`, `Support/Utility`). Add-Block tile visibility is controlled per-block via the `blocks` prop.
|
|
594
|
+
|
|
595
|
+
When `apiConfig` is set, two additional tabs appear at the top of the Layout panel:
|
|
596
|
+
|
|
597
|
+
- **Templates** — global page templates from `/global-template?filter[type]=page`. Click any card → template preview dialog with three CTAs (Use Template / Use Styles / Add Section).
|
|
598
|
+
- **Saved** — per-tenant `/mytemplate` list. Same card UI with an on-hover delete button.
|
|
599
|
+
|
|
600
|
+
The Add-Block menu also gains a highlighted **Section Library** tile (opens a full-screen gallery of block-type templates grouped by category). Without `apiConfig`, all three affordances are hidden — the Layout panel stays a lean block palette.
|
|
384
601
|
|
|
385
602
|
### Image block sidebar
|
|
386
603
|
|
|
@@ -393,7 +610,7 @@ if the standalone integration model doesn't fit.
|
|
|
393
610
|
|
|
394
611
|
### Preview
|
|
395
612
|
|
|
396
|
-
- **Default behavior** (no `onTogglePreview`): the editor renders every section through `renderToStaticMarkup`, concatenates the fragments inside a minimal HTML shell (with viewport meta + base font + canvas color from `
|
|
613
|
+
- **Default behavior** (no `onTogglePreview`): the editor renders every section through `renderToStaticMarkup`, concatenates the fragments inside a minimal HTML shell (with viewport meta + base font + canvas color from `EmailLayout.canvasColor`), and shows it in an in-page MUI dialog with desktop / tablet / mobile size toggles. The iframe uses `srcDoc` (inline HTML) so no network round-trip and no blob-URL flake. The "Open in new tab" header icon is hidden in this mode (nothing to link to — the HTML is inline). A host that supplies a real `previewUrl` (via internal preview server) gets the icon.
|
|
397
614
|
- **Custom UI**: pass `onTogglePreview={(html, doc) => myDialog.open(html)}` to skip the built-in dialog and render your own.
|
|
398
615
|
|
|
399
616
|
### Save / Publish payload generation
|
|
@@ -404,7 +621,7 @@ When the user clicks **Save Changes** or **Publish**, the editor does the follow
|
|
|
404
621
|
2. If the record has `sections`, flushes the canvas document into `sections[activeIndex].contentMetadata.document` so the active section is up-to-date.
|
|
405
622
|
3. Renders every section's document via `renderToStaticMarkup({ rootBlockId: "root", injectElementIds: true, minifyCss: true, includePageCSS: true, lang, skipLink, accessibilityTools })`.
|
|
406
623
|
4. Per-section HTML is written to `section.content` and per-section documents to `section.contentMetadata.document`.
|
|
407
|
-
5. All section fragments are concatenated inside a single HTML document with viewport meta, base font, and canvas color from `
|
|
624
|
+
5. All section fragments are concatenated inside a single HTML document with viewport meta, base font, and canvas color from `EmailLayout`.
|
|
408
625
|
6. **Multi-section payload**: `{ record, html }` with the record's redundant `contentMetadata` / empty `behaviour` / empty `steps` stripped, and the outer `document` key omitted.
|
|
409
626
|
**Single-doc payload**: `{ record, document, html }` where `record.contentMetadata` carries `document` + `html`.
|
|
410
627
|
|
|
@@ -478,20 +695,22 @@ The full set of keys the editor reads is documented inline at `src/host-stubs/i1
|
|
|
478
695
|
|
|
479
696
|
## Block types
|
|
480
697
|
|
|
481
|
-
Out of the box the Add-Block menu exposes
|
|
698
|
+
Out of the box the Add-Block menu exposes 33 block types, grouped into six categories:
|
|
482
699
|
|
|
483
|
-
| Layout |
|
|
484
|
-
|
|
485
|
-
| Container |
|
|
486
|
-
| Columns |
|
|
487
|
-
| Flex Columns |
|
|
488
|
-
|
|
|
489
|
-
|
|
|
490
|
-
|
|
|
491
|
-
| | | |
|
|
492
|
-
| | | |
|
|
493
|
-
| | | |
|
|
494
|
-
| | | |
|
|
700
|
+
| Text/Content | Media | Layout/Structure | Actions/Controls | Embeds/Integrations | Support/Utility |
|
|
701
|
+
|---|---|---|---|---|---|
|
|
702
|
+
| Heading | Image | Container | Button | Timer | Rating |
|
|
703
|
+
| Text | Logo | Columns | Button Group | YouTube Url | Skip Link |
|
|
704
|
+
| Table | Video | Flex Columns | Accordion | Demo Picker¹ | Accessibility |
|
|
705
|
+
| | Avatar | Grid | Tabs | Header¹ (MenuPicker) | |
|
|
706
|
+
| | | Spacer | Stepper | Forms¹ | |
|
|
707
|
+
| | | Divider | | App Banner¹ | |
|
|
708
|
+
| | | Html | | FAQs¹ | |
|
|
709
|
+
| | | Carousel | | IFrame | |
|
|
710
|
+
| | | Pagination | | Calendly | |
|
|
711
|
+
| | | Marquee | | | |
|
|
712
|
+
|
|
713
|
+
¹ Picker blocks (Demo / Header / Forms / App Banner / FAQs) surface tenant-managed records. Without host-provided data (via `record.contentMetadata.document` or a bespoke integration) they render their empty state.
|
|
495
714
|
|
|
496
715
|
Hide any of them via the `blocks` prop. Tile labels can be re-translated via `translations`.
|
|
497
716
|
|
|
@@ -545,11 +764,15 @@ export {
|
|
|
545
764
|
// Imperative store access
|
|
546
765
|
export * as EditorContext from "pagepilot-visual-editor";
|
|
547
766
|
|
|
767
|
+
// Pagepilot API client (for hosts using `apiConfig`)
|
|
768
|
+
export { PagepilotApiClient } from "pagepilot-visual-editor";
|
|
769
|
+
|
|
548
770
|
// Types
|
|
549
771
|
export type {
|
|
550
772
|
PagePilotEditorProps, PageRecord, SaveChangesPayload,
|
|
551
773
|
EditorPanelToggles, TopbarToggles,
|
|
552
774
|
BlockKey, BlockToggles,
|
|
775
|
+
PagepilotApiConfig, ListParams, PageListRow, PageListResponse,
|
|
553
776
|
TReaderBlock, TReaderDocument, TReaderBlockProps, TReaderProps,
|
|
554
777
|
} from "pagepilot-visual-editor";
|
|
555
778
|
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { PagepilotApiClient, PagepilotApiConfig } from './PagepilotApiClient';
|
|
3
|
+
interface ProviderProps {
|
|
4
|
+
config?: PagepilotApiConfig;
|
|
5
|
+
/**
|
|
6
|
+
* Override the base URL used for the public `/global-template` fetch.
|
|
7
|
+
* Defaults to `DEFAULT_GLOBAL_TEMPLATES_BASE_URL`. If `config.baseUrl` is
|
|
8
|
+
* present it wins (same origin as the authed calls, keeps the environment
|
|
9
|
+
* consistent).
|
|
10
|
+
*/
|
|
11
|
+
globalTemplatesBaseUrl?: string;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
export declare function PagepilotApiClientProvider({ config, globalTemplatesBaseUrl, children, }: ProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function usePagepilotApiClient(): PagepilotApiClient | null;
|
|
16
|
+
export declare function useGlobalTemplatesBaseUrl(): string;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface PagepilotApiConfig {
|
|
2
|
+
/** API root without trailing slash, e.g. "https://pagepilot.fabbuilder.com/api" */
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
/** Tenant id used in `/tenant/${tenantId}/...` paths. */
|
|
5
|
+
tenantId: string;
|
|
6
|
+
/** Pre-issued service-account bearer token. Sent as `Authorization: Bearer <token>`. */
|
|
7
|
+
authToken: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ListParams {
|
|
10
|
+
filter?: Record<string, unknown>;
|
|
11
|
+
orderBy?: string | null;
|
|
12
|
+
limit?: number;
|
|
13
|
+
offset?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface PageListRow {
|
|
16
|
+
id: string;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
export interface PageListResponse {
|
|
20
|
+
rows: PageListRow[];
|
|
21
|
+
count?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class PagepilotApiClient {
|
|
24
|
+
readonly baseUrl: string;
|
|
25
|
+
readonly tenantId: string;
|
|
26
|
+
private readonly authToken;
|
|
27
|
+
constructor(cfg: PagepilotApiConfig);
|
|
28
|
+
private headers;
|
|
29
|
+
private buildUrl;
|
|
30
|
+
private request;
|
|
31
|
+
createPage(data: Record<string, unknown>): Promise<any>;
|
|
32
|
+
updatePage(id: string, data: Record<string, unknown>): Promise<any>;
|
|
33
|
+
/** PATCH — matches PageService.quickSave. */
|
|
34
|
+
quickSavePage(id: string, data: Record<string, unknown>): Promise<any>;
|
|
35
|
+
/**
|
|
36
|
+
* POST /tenant/:tenantId/upsert-page-item — matches `PageService.upsert`.
|
|
37
|
+
* This is the endpoint ahd-fe's editor uses for both save-draft and
|
|
38
|
+
* publish (via `useSaveHandler.saveContent`). The full record — including
|
|
39
|
+
* `pageId`, `status`, rendered `sections[]`, and optional
|
|
40
|
+
* `startDate`/`endDate` — travels inside `data`.
|
|
41
|
+
*/
|
|
42
|
+
upsertPage(data: Record<string, unknown>): Promise<any>;
|
|
43
|
+
findPage(id: string): Promise<any>;
|
|
44
|
+
listGlobalTemplates(params?: ListParams): Promise<PageListResponse>;
|
|
45
|
+
findGlobalTemplate(id: string): Promise<any>;
|
|
46
|
+
destroyGlobalTemplates(ids: string[]): Promise<any>;
|
|
47
|
+
listTenantTemplates(params?: ListParams): Promise<PageListResponse>;
|
|
48
|
+
findTenantTemplate(id: string): Promise<any>;
|
|
49
|
+
listMyTemplates(params?: ListParams): Promise<PageListResponse>;
|
|
50
|
+
createTemplate(data: Record<string, unknown>): Promise<any>;
|
|
51
|
+
destroyTenantTemplates(ids: string[]): Promise<any>;
|
|
52
|
+
listMenus(params?: ListParams): Promise<PageListResponse>;
|
|
53
|
+
updateMenu(id: string, data: Record<string, unknown>): Promise<any>;
|
|
54
|
+
getTenant(): Promise<{
|
|
55
|
+
id: string;
|
|
56
|
+
plan?: string;
|
|
57
|
+
[key: string]: any;
|
|
58
|
+
}>;
|
|
59
|
+
}
|
|
60
|
+
/** Default public API root. Hosts can override via `globalTemplatesBaseUrl`. */
|
|
61
|
+
export declare const DEFAULT_GLOBAL_TEMPLATES_BASE_URL = "https://pagepilot.fabbuilder.com/api";
|
|
62
|
+
export declare function listGlobalTemplatesPublic(baseUrl: string, params?: ListParams): Promise<PageListResponse>;
|
|
63
|
+
export declare function findGlobalTemplatePublic(baseUrl: string, id: string): Promise<any>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Plan tiers ranked lowest → highest, mirrors ahd-fe's `Plans.values`. */
|
|
2
|
+
export declare const PLAN_RANK: Record<string, number>;
|
|
3
|
+
export declare const isProOrAboveTenant: (tenant?: {
|
|
4
|
+
plan?: string;
|
|
5
|
+
}) => boolean;
|
|
6
|
+
export interface UseTenantPlanReturn {
|
|
7
|
+
currentTenant: {
|
|
8
|
+
id?: string;
|
|
9
|
+
plan?: string;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
} | null;
|
|
12
|
+
isPlanProOrAbove: boolean;
|
|
13
|
+
loading: boolean;
|
|
14
|
+
error: string | null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the tenant plan for gating paid features.
|
|
18
|
+
*
|
|
19
|
+
* Behaviour:
|
|
20
|
+
* - No apiClient → returns `{ currentTenant: null, isPlanProOrAbove: false }`
|
|
21
|
+
* - apiClient present → GETs `/tenant/:tenantId` once and caches
|
|
22
|
+
* - Fetch fails → `error` is set, `isPlanProOrAbove` defaults to `false`
|
|
23
|
+
* (safe-fail: paywall stays up when we can't verify plan)
|
|
24
|
+
*/
|
|
25
|
+
export declare function useTenantPlan(): UseTenantPlanReturn;
|
|
@@ -35,12 +35,12 @@ export declare const ButtonPropsSchema: z.ZodObject<{
|
|
|
35
35
|
BEBAS_NEUE: "BEBAS_NEUE";
|
|
36
36
|
}>>>;
|
|
37
37
|
fontWeight: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
bold: "bold";
|
|
38
39
|
400: "400";
|
|
39
40
|
500: "500";
|
|
40
41
|
600: "600";
|
|
41
42
|
700: "700";
|
|
42
43
|
normal: "normal";
|
|
43
|
-
bold: "bold";
|
|
44
44
|
}>>>;
|
|
45
45
|
textAlign: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
46
46
|
right: "right";
|
|
@@ -83,13 +83,41 @@ export declare const ButtonPropsSchema: z.ZodObject<{
|
|
|
83
83
|
fixed: "fixed";
|
|
84
84
|
fit: "fit";
|
|
85
85
|
}>>>;
|
|
86
|
+
widthTypeTablet: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
87
|
+
fill: "fill";
|
|
88
|
+
fixed: "fixed";
|
|
89
|
+
fit: "fit";
|
|
90
|
+
}>>>;
|
|
91
|
+
widthTypeMobile: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
92
|
+
fill: "fill";
|
|
93
|
+
fixed: "fixed";
|
|
94
|
+
fit: "fit";
|
|
95
|
+
}>>>;
|
|
86
96
|
width: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
97
|
+
widthUnit: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
98
|
+
px: "px";
|
|
99
|
+
"%": "%";
|
|
100
|
+
}>>>;
|
|
101
|
+
widthTablet: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
102
|
+
widthMobile: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
87
103
|
size: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
88
104
|
small: "small";
|
|
89
105
|
"x-small": "x-small";
|
|
90
106
|
large: "large";
|
|
91
107
|
medium: "medium";
|
|
92
108
|
}>>>;
|
|
109
|
+
sizeTablet: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
110
|
+
small: "small";
|
|
111
|
+
"x-small": "x-small";
|
|
112
|
+
large: "large";
|
|
113
|
+
medium: "medium";
|
|
114
|
+
}>>>;
|
|
115
|
+
sizeMobile: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
116
|
+
small: "small";
|
|
117
|
+
"x-small": "x-small";
|
|
118
|
+
large: "large";
|
|
119
|
+
medium: "medium";
|
|
120
|
+
}>>>;
|
|
93
121
|
text: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
94
122
|
url: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
95
123
|
action: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
@@ -115,12 +143,15 @@ export declare const ButtonPropsSchema: z.ZodObject<{
|
|
|
115
143
|
}, z.core.$strip>>>;
|
|
116
144
|
}, z.core.$strip>;
|
|
117
145
|
export type ButtonProps = z.infer<typeof ButtonPropsSchema>;
|
|
146
|
+
export declare const isValidButtonColor: (c: unknown) => c is string;
|
|
147
|
+
export declare const isValidButtonFontFamily: (f: unknown) => f is string;
|
|
118
148
|
export declare const ButtonPropsDefaults: {
|
|
119
149
|
readonly text: "";
|
|
120
150
|
readonly url: "";
|
|
121
151
|
readonly fullWidth: false;
|
|
122
152
|
readonly widthType: "fit";
|
|
123
153
|
readonly width: 200;
|
|
154
|
+
readonly widthUnit: "px";
|
|
124
155
|
readonly size: "medium";
|
|
125
156
|
readonly borderRadius: 4;
|
|
126
157
|
readonly borderColor: "";
|