pagepilot-visual-editor 1.0.5 → 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.
Files changed (193) hide show
  1. package/README.md +276 -30
  2. package/dist/api/ApiClientContext.d.ts +17 -0
  3. package/dist/api/PagepilotApiClient.d.ts +63 -0
  4. package/dist/api/useTenantPlan.d.ts +25 -0
  5. package/dist/blocks-internal/block-button/src/index.d.ts +32 -1
  6. package/dist/blocks-internal/block-button-group/src/index.d.ts +20 -1
  7. package/dist/blocks-internal/block-columns-container/src/index.d.ts +38 -0
  8. package/dist/blocks-internal/block-container/src/index.d.ts +44 -5
  9. package/dist/blocks-internal/block-divider/src/index.d.ts +6 -0
  10. package/dist/blocks-internal/block-grid/src/index.d.ts +6 -0
  11. package/dist/blocks-internal/block-heading/src/index.d.ts +3 -2
  12. package/dist/blocks-internal/block-html/src/index.d.ts +6 -0
  13. package/dist/blocks-internal/block-iframe/src/index.d.ts +4 -0
  14. package/dist/blocks-internal/block-image/src/index.d.ts +17 -0
  15. package/dist/blocks-internal/block-logo/src/index.d.ts +20 -7
  16. package/dist/blocks-internal/block-stepper/src/index.d.ts +2 -2
  17. package/dist/blocks-internal/block-text/src/index.d.ts +1 -1
  18. package/dist/blocks-internal/block-video/src/index.d.ts +4 -0
  19. package/dist/blocks-internal/block-youtube-url/src/index.d.ts +4 -0
  20. package/dist/editor/Shell.d.ts +1 -1
  21. package/dist/editor/blockToggles.d.ts +1 -1
  22. package/dist/editor/publish/PagePublishDialog.d.ts +21 -0
  23. package/dist/editor/types.d.ts +63 -0
  24. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/ResponsiveModeContext.d.ts +12 -0
  25. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/blockStyleClipboard.d.ts +4 -4
  26. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/AppBannerPickerSidebarPanel.d.ts +19 -0
  27. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/DemoPickerSidebarPanel.d.ts +31 -0
  28. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/EmailLayoutSidebarPanel.d.ts +26 -0
  29. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/FaqPickerSidebarPanel.d.ts +18 -0
  30. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/FormsPickerSidebarPanel.d.ts +18 -0
  31. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/MenuPickerSidebarPanel.d.ts +34 -0
  32. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/PaginationSidebarPanel.d.ts +7 -0
  33. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/TableSidebarPanel.d.ts +9 -0
  34. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/TimerSidebarPanel.d.ts +7 -0
  35. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/CollapsibleSection.d.ts +8 -2
  36. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/MediaLibraryButton.d.ts +1 -1
  37. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/SectionWrapper.d.ts +2 -1
  38. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/deviceProp.d.ts +14 -0
  39. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/ColorInput/BaseColorInput.d.ts +4 -2
  40. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/ColorInput/Picker.d.ts +7 -1
  41. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/ColorInput/index.d.ts +3 -0
  42. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/PaddingInput.d.ts +4 -1
  43. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/RadiusInput.d.ts +13 -11
  44. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/SelectInput.d.ts +15 -0
  45. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/StepperInput.d.ts +19 -0
  46. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/inputs/WidthInputWithSelect.d.ts +4 -1
  47. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/sanitizeAgainstSchema.d.ts +11 -0
  48. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/helpers/style-inputs/MultiStylePropertyPanel.d.ts +2 -1
  49. package/dist/editor-sample/App/InspectorDrawer/EditorBehavior.d.ts +16 -0
  50. package/dist/editor-sample/App/InspectorDrawer/LayersPanelStyles.d.ts +2 -2
  51. package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/SectionsModal.d.ts +15 -0
  52. package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/TemplatePreviewDialog.d.ts +14 -0
  53. package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/TemplatesList.d.ts +45 -0
  54. package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/icons/index.d.ts +37 -1
  55. package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/templateApplyHelpers.d.ts +101 -0
  56. package/dist/editor-sample/App/InspectorDrawer/PagePilotAiPanel.d.ts +1 -0
  57. package/dist/editor-sample/App/InspectorDrawer/SeoPanel/SeoFieldLabel.d.ts +7 -0
  58. package/dist/editor-sample/App/InspectorDrawer/SeoPanel/SeoPanel.styled.d.ts +12 -0
  59. package/dist/editor-sample/App/InspectorDrawer/SeoPanel/index.d.ts +6 -0
  60. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/ApiResponseDialog.d.ts +10 -0
  61. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/ArrayFieldEditor.d.ts +14 -0
  62. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/ContainerRepeatSection.d.ts +9 -0
  63. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/DataReferenceDialog.d.ts +15 -0
  64. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/DataReferencePanel.d.ts +20 -0
  65. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/GrowDirectionDialog.d.ts +13 -0
  66. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/RowCard.d.ts +23 -0
  67. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/SectionHeader.d.ts +13 -0
  68. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/VariablesPaywall.d.ts +1 -0
  69. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/constants.d.ts +2 -0
  70. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/dataReferenceUtils.d.ts +34 -0
  71. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/index.d.ts +1 -0
  72. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/repeatRowActions.d.ts +31 -0
  73. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/styles.d.ts +53 -0
  74. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/upgradeDialog.d.ts +4 -0
  75. package/dist/editor-sample/App/InspectorDrawer/components/MiniRichTextInput.d.ts +7 -0
  76. package/dist/editor-sample/App/InspectorDrawer/components/ScalarFieldInput.d.ts +10 -0
  77. package/dist/editor-sample/App/shared/editor.styles.d.ts +3 -3
  78. package/dist/editor-sample/documents/blocks/Accordion/AccordionPropsSchema.d.ts +6 -0
  79. package/dist/editor-sample/documents/blocks/AppBannerPicker/AppBannerEditor.d.ts +18 -0
  80. package/dist/editor-sample/documents/blocks/AppBannerPicker/AppBannerPropsSchema.d.ts +14 -0
  81. package/dist/editor-sample/documents/blocks/AppBannerPicker/appBanner.styled.d.ts +2 -0
  82. package/dist/editor-sample/documents/blocks/ButtonGroup/ButtonGroupPropsSchema.d.ts +20 -1
  83. package/dist/editor-sample/documents/blocks/Carousel/CarouselPropsSchema.d.ts +7 -0
  84. package/dist/editor-sample/documents/blocks/ColumnsContainer/ColumnsContainerPropsSchema.d.ts +38 -0
  85. package/dist/editor-sample/documents/blocks/Container/ContainerPropsSchema.d.ts +56 -3
  86. package/dist/editor-sample/documents/blocks/DemoPicker/DemoEditor.d.ts +3 -0
  87. package/dist/editor-sample/documents/blocks/DemoPicker/DemoPropsSchema.d.ts +37 -0
  88. package/dist/editor-sample/documents/blocks/EmailLayout/EmailLayoutEditor.d.ts +2 -0
  89. package/dist/editor-sample/documents/blocks/{PagePilotLayout/PagePilotLayoutPropsSchema.d.ts → EmailLayout/EmailLayoutPropsSchema.d.ts} +51 -4
  90. package/dist/editor-sample/documents/blocks/FaqPicker/FaqEditor.d.ts +18 -0
  91. package/dist/editor-sample/documents/blocks/FaqPicker/FaqPickerPropsSchema.d.ts +14 -0
  92. package/dist/editor-sample/documents/blocks/FaqPicker/faqPicker.styled.d.ts +3 -0
  93. package/dist/editor-sample/documents/blocks/FlexColumns/FlexColumnsEditor.d.ts +6 -0
  94. package/dist/editor-sample/documents/blocks/FormsPicker/FormsEditor.d.ts +3 -0
  95. package/dist/editor-sample/documents/blocks/FormsPicker/FormsPropsSchema.d.ts +33 -0
  96. package/dist/editor-sample/documents/blocks/Grid/GridPropsSchema.d.ts +13 -2
  97. package/dist/editor-sample/documents/blocks/Marquee/MarqueePropsSchema.d.ts +12 -0
  98. package/dist/editor-sample/documents/blocks/MenuPicker/MenuEditor.d.ts +7 -0
  99. package/dist/editor-sample/documents/blocks/MenuPicker/MenuPropsSchema.d.ts +45 -0
  100. package/dist/editor-sample/documents/blocks/MenuPicker/mergeMenuItems.d.ts +13 -0
  101. package/dist/editor-sample/documents/blocks/Pagination/PaginationEditor.d.ts +2 -0
  102. package/dist/editor-sample/documents/blocks/Pagination/PaginationPropsSchema.d.ts +4 -0
  103. package/dist/editor-sample/documents/blocks/Table/TableCellEditor.d.ts +11 -0
  104. package/dist/editor-sample/documents/blocks/Table/TableEditor.d.ts +2 -0
  105. package/dist/editor-sample/documents/blocks/Table/TablePropsSchema.d.ts +1 -0
  106. package/dist/editor-sample/documents/blocks/TabsBlock/TabsBlockPropsSchema.d.ts +12 -0
  107. package/dist/editor-sample/documents/blocks/Timer/TimerEditor.d.ts +2 -0
  108. package/dist/editor-sample/documents/blocks/Timer/TimerPropsSchema.d.ts +38 -0
  109. package/dist/editor-sample/documents/blocks/Timer/timerMath.d.ts +9 -0
  110. package/dist/editor-sample/documents/blocks/Timer/variants/CircularProgressView.d.ts +9 -0
  111. package/dist/editor-sample/documents/blocks/Timer/variants/DigitalFlipView.d.ts +9 -0
  112. package/dist/editor-sample/documents/blocks/Timer/variants/TextInlineView.d.ts +9 -0
  113. package/dist/editor-sample/documents/blocks/helpers/BlockCategories.d.ts +1 -0
  114. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/BlockButton.d.ts +1 -1
  115. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/BlocksMenu.d.ts +1 -1
  116. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/DividerButton.d.ts +2 -1
  117. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/PlaceholderButton.d.ts +2 -1
  118. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/blockMenuStyles.d.ts +11 -0
  119. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/brandButtonDefaults.d.ts +4 -2
  120. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/buttons.d.ts +8 -0
  121. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/gridPresets.d.ts +17 -0
  122. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/AddBlockMenu/index.d.ts +3 -2
  123. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/index.d.ts +2 -1
  124. package/dist/editor-sample/documents/blocks/helpers/TStyle.d.ts +2 -0
  125. package/dist/editor-sample/documents/blocks/helpers/block-wrappers/saveAsTemplateUtils.d.ts +97 -0
  126. package/dist/editor-sample/documents/blocks/helpers/documentUtils.d.ts +96 -17
  127. package/dist/editor-sample/documents/blocks/helpers/responsiveStyle.d.ts +106 -0
  128. package/dist/editor-sample/documents/blocks/helpers/zod.d.ts +1 -1
  129. package/dist/editor-sample/documents/editor/EditorContext.d.ts +11 -2
  130. package/dist/editor-sample/documents/editor/core.d.ts +575 -16
  131. package/dist/editor-sample/documents/editor/templateVariables.d.ts +73 -0
  132. package/dist/email-builder-core/blocks/Accordion/AccordionPropsSchema.d.ts +6 -0
  133. package/dist/email-builder-core/blocks/AppBannerPicker/AppBannerPropsSchema.d.ts +16 -0
  134. package/dist/email-builder-core/blocks/AppBannerPicker/AppBannerReader.d.ts +3 -0
  135. package/dist/email-builder-core/blocks/ButtonGroup/ButtonGroupPropsSchema.d.ts +20 -1
  136. package/dist/email-builder-core/blocks/Calendly/CalendlyPropsSchema.d.ts +4 -0
  137. package/dist/email-builder-core/blocks/Carousel/CarouselPropsSchema.d.ts +6 -0
  138. package/dist/email-builder-core/blocks/ColumnsContainer/ColumnsContainerPropsSchema.d.ts +38 -0
  139. package/dist/email-builder-core/blocks/Container/ContainerPropsSchema.d.ts +56 -3
  140. package/dist/email-builder-core/blocks/DemoPicker/DemoPropsSchema.d.ts +36 -0
  141. package/dist/email-builder-core/blocks/DemoPicker/DemoReader.d.ts +3 -0
  142. package/dist/email-builder-core/blocks/{PagePilotLayout/PagePilotLayoutPropsSchema.d.ts → EmailLayout/EmailLayoutPropsSchema.d.ts} +41 -2
  143. package/dist/email-builder-core/blocks/EmailLayout/EmailLayoutReader.d.ts +3 -0
  144. package/dist/email-builder-core/blocks/EmailLayout/emailLayoutResponsive.d.ts +46 -0
  145. package/dist/email-builder-core/blocks/FaqPicker/FaqPickerPropsSchema.d.ts +16 -0
  146. package/dist/email-builder-core/blocks/FaqPicker/FaqReader.d.ts +3 -0
  147. package/dist/email-builder-core/blocks/FlexColumns/FlexColumnsPropsSchema.d.ts +23 -2
  148. package/dist/email-builder-core/blocks/FlexColumns/FlexColumnsReader.d.ts +6 -0
  149. package/dist/email-builder-core/blocks/FlexColumns/flexColumnsHelpers.d.ts +71 -1
  150. package/dist/email-builder-core/blocks/FormsPicker/FormsPropsSchema.d.ts +19 -0
  151. package/dist/email-builder-core/blocks/FormsPicker/FormsReader.d.ts +3 -0
  152. package/dist/email-builder-core/blocks/Grid/GridPropsSchema.d.ts +12 -2
  153. package/dist/email-builder-core/blocks/Marquee/MarqueePropsSchema.d.ts +16 -0
  154. package/dist/email-builder-core/blocks/Marquee/MarqueeReader.d.ts +1 -1
  155. package/dist/email-builder-core/blocks/Marquee/marqueeMotion.d.ts +40 -0
  156. package/dist/email-builder-core/blocks/MenuPicker/MenuPropsSchema.d.ts +87 -0
  157. package/dist/email-builder-core/blocks/MenuPicker/MenuReader.d.ts +3 -0
  158. package/dist/email-builder-core/blocks/MenuPicker/menuResponsiveCss.d.ts +27 -0
  159. package/dist/email-builder-core/blocks/Pagination/PaginationPropsSchema.d.ts +119 -0
  160. package/dist/email-builder-core/blocks/Pagination/PaginationReader.d.ts +2 -0
  161. package/dist/email-builder-core/blocks/Pagination/paginationShared.d.ts +74 -0
  162. package/dist/email-builder-core/blocks/Table/TablePropsSchema.d.ts +48 -0
  163. package/dist/email-builder-core/blocks/Table/TableReader.d.ts +13 -0
  164. package/dist/email-builder-core/blocks/TabsBlock/TabsBlockPropsSchema.d.ts +12 -0
  165. package/dist/email-builder-core/blocks/Timer/TimerPropsSchema.d.ts +38 -0
  166. package/dist/email-builder-core/blocks/Timer/TimerReader.d.ts +2 -0
  167. package/dist/email-builder-core/blocks/Timer/variants/CircularProgressView.d.ts +11 -0
  168. package/dist/email-builder-core/blocks/Timer/variants/DigitalFlipView.d.ts +11 -0
  169. package/dist/email-builder-core/blocks/Timer/variants/TextInlineView.d.ts +11 -0
  170. package/dist/email-builder-core/blocks/responsiveBreakpoints.d.ts +32 -0
  171. package/dist/host-stubs/modules/_hostListShim.d.ts +18 -0
  172. package/dist/host-stubs/modules/appBannerV2/list/appBannerListActions.d.ts +1 -0
  173. package/dist/host-stubs/modules/appBannerV2/list/appBannerListSelectors.d.ts +1 -0
  174. package/dist/host-stubs/modules/demo/list/demoListActions.d.ts +1 -0
  175. package/dist/host-stubs/modules/demo/list/demoListSelectors.d.ts +1 -0
  176. package/dist/host-stubs/modules/faqGroup/list/faqGroupListActions.d.ts +1 -0
  177. package/dist/host-stubs/modules/faqGroup/list/faqGroupListSelectors.d.ts +1 -0
  178. package/dist/host-stubs/modules/forms/formsService.d.ts +9 -0
  179. package/dist/host-stubs/modules/menu/list/menuListActions.d.ts +1 -0
  180. package/dist/host-stubs/modules/menu/list/menuListSelectors.d.ts +1 -0
  181. package/dist/host-stubs/modules/store.d.ts +3 -0
  182. package/dist/host-stubs/react-redux.d.ts +3 -0
  183. package/dist/host-stubs/style/menu.styled.d.ts +73 -15
  184. package/dist/host-stubs/tanstack-react-query.d.ts +9 -0
  185. package/dist/host-stubs/view/shared/htmlSanitize.d.ts +15 -0
  186. package/dist/index.cjs +368 -339
  187. package/dist/index.d.ts +2 -0
  188. package/dist/index.js +47974 -36617
  189. package/dist/style.css +1 -1
  190. package/package.json +1 -1
  191. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/PagePilotLayoutSidebarPanel.d.ts +0 -24
  192. package/dist/editor-sample/documents/blocks/PagePilotLayout/PagePilotLayoutEditor.d.ts +0 -2
  193. 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
- The package is **purely the editor**. No backend calls, no host-app coupling.
9
- The host owns persistence, navigation, plan gating, theming overrides, and
10
- everything else.
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
  ---
@@ -93,21 +100,25 @@ built-in layout doesn't scale unexpectedly.
93
100
 
94
101
  ```
95
102
  ┌──────────────────────────────────────────────────────────────────────────┐
96
- │ ← Back My Page ● Draft [Section ▾] ↶ ↷ Save ⋮ ⤢ ▶ Publish ▾ │ Topbar
103
+ │ ← Back My Page ● Draft [Section ▾] ↶ ↷ Save ⋮ ⤢ ▶ Publish ▾ │ Topbar
97
104
  ├──────┬───────────────────┬─────────────────────────────────────────────┤
98
105
  │Style │ Appearance │ │
99
106
  │Layout│ Color ▢ ... │ (canvas — block-based editor) │
100
107
  │Inspct│ Font ▾ │ │
101
108
  │Layers│ Radius PX │ │
102
- │ Layout │ │
103
- │ Width 100 % │ │
109
+ Vars* │ Layout │ │
110
+ SEO │ Width 100 % │ │
111
+ │PgPlt │ │ │
104
112
  └──────┴───────────────────┴─────────────────────────────────────────────┘
113
+ * only when template has vars
105
114
  ```
106
115
 
107
- - **Left rail** — 4 panels: **Style**, **Layout**, **Inspect**, **Layers** (each can be toggled off via the `panels` prop).
108
- - **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.
109
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).
110
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.
111
122
 
112
123
  ---
113
124
 
@@ -123,6 +134,7 @@ built-in layout doesn't scale unexpectedly.
123
134
  | `activeStepIndex` | `number` | `0` | Index of the currently-active section in the canvas. The editor also tracks this internally via the section dropdown. |
124
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. |
125
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). |
126
138
 
127
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`.
128
140
 
@@ -190,6 +202,11 @@ interface EditorPanelToggles {
190
202
  layout?: boolean; // default true
191
203
  inspect?: boolean; // default true
192
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)
193
210
  }
194
211
  ```
195
212
 
@@ -203,6 +220,8 @@ interface TopbarToggles {
203
220
  sectionsDropdown?: boolean; // default true — still requires sections.length > 1
204
221
  undo?: boolean; // default true
205
222
  redo?: boolean; // default true
223
+ unselect?: boolean; // default true — Deselect Block button
224
+ // (auto-hides when nothing selected)
206
225
  save?: boolean; // default true
207
226
  themeToggle?: boolean; // default true — sun/moon button flipping light/dark
208
227
  fullscreen?: boolean; // default true
@@ -226,7 +245,10 @@ type BlockKey =
226
245
  | "buttonGroup" | "container"
227
246
  | "stepper" | "accordion" | "pricingAccordion"
228
247
  | "tabs" | "carousel" | "rating" | "marquee"
229
- | "iframe" | "skipToMain" | "accessibilityTools";
248
+ | "iframe" | "skipToMain" | "accessibilityTools"
249
+ | "timer" | "pagination" | "table"
250
+ | "demoPicker" | "menuPicker" | "formsPicker"
251
+ | "appBannerPicker" | "faqPicker";
230
252
 
231
253
  type BlockToggles = Partial<Record<BlockKey, boolean>>;
232
254
  ```
@@ -258,6 +280,8 @@ type BlockToggles = Partial<Record<BlockKey, boolean>>;
258
280
  | `onBackgroundChange` | `(image: string) => void` | Fires when the page-level background image changes. |
259
281
  | `onNavigateBranding` | `() => void` | Fires from the Brand panel (currently stripped from the standalone build — kept for forward-compat). |
260
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. |
261
285
 
262
286
  #### `SaveChangesPayload`
263
287
 
@@ -306,6 +330,190 @@ Single-doc mode (no `sections`) is unchanged — the payload still carries
306
330
 
307
331
  ---
308
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
+
309
517
  ## Behavior reference
310
518
 
311
519
  ### Topbar buttons
@@ -316,7 +524,8 @@ Single-doc mode (no `sections`) is unchanged — the payload still carries
316
524
  | **Page title + status pill** | Display-only. Sourced from `recordTitle` / `recordStatus` (or `record.title / record.name / record.status`). |
317
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. |
318
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. |
319
- | **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`. |
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`. |
320
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). |
321
530
  | **3-dot menu** ⋮ | Single item: **+ Add Section**. Off by default — enable via `topbar.moreMenu`. |
322
531
  | **Fullscreen** ⤢ | Toggles the editor's container via the browser Fullscreen API. Icon swaps to "exit fullscreen" while active; pressing `Esc` exits. |
@@ -324,13 +533,36 @@ Single-doc mode (no `sections`) is unchanged — the payload still carries
324
533
  | **Publish** | Calls `onPublish`. |
325
534
  | **Publish ▾** | Calls `onPublishMenu(anchorEl, payload)` so the host can open a custom dialog/popover anchored to the button. |
326
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
+
327
559
  ### Add Section flow
328
560
 
329
561
  1. User clicks ⋮ → **+ Add Section** (or the empty-state button).
330
562
  2. A modal asks for a **Title**.
331
563
  3. On submit:
332
564
  - The active section's in-progress canvas document is flushed into `record.sections[activeIndex].contentMetadata.document` (no edits lost).
333
- - A new section is appended, seeded with a default empty `PagePilotLayout` document.
565
+ - A new section is appended, seeded with a default empty `EmailLayout` document.
334
566
  - The host receives the updated record via `onUpdateRecord`.
335
567
  - The canvas swaps to the new section's document so the user can immediately edit it.
336
568
  - The active step index is bumped.
@@ -352,12 +584,20 @@ The image is inserted at the caret position and can then be resized
352
584
  appears when you click it. The standalone editor deliberately doesn't ship
353
585
  a media-library backend — the URL field is the integration point.
354
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
+
355
591
  ### Layout panel
356
592
 
357
- The Layout panel shows a single tile grid the **Blocks** picker. The
358
- Templates and Saved-templates tabs from the Pagepilot host app are
359
- intentionally omitted; those require the host's team-template backend.
360
- Add-Block tile visibility is controlled per-block via the `blocks` prop.
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.
361
601
 
362
602
  ### Image block sidebar
363
603
 
@@ -370,7 +610,7 @@ if the standalone integration model doesn't fit.
370
610
 
371
611
  ### Preview
372
612
 
373
- - **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 `PagePilotLayout.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.
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.
374
614
  - **Custom UI**: pass `onTogglePreview={(html, doc) => myDialog.open(html)}` to skip the built-in dialog and render your own.
375
615
 
376
616
  ### Save / Publish payload generation
@@ -381,7 +621,7 @@ When the user clicks **Save Changes** or **Publish**, the editor does the follow
381
621
  2. If the record has `sections`, flushes the canvas document into `sections[activeIndex].contentMetadata.document` so the active section is up-to-date.
382
622
  3. Renders every section's document via `renderToStaticMarkup({ rootBlockId: "root", injectElementIds: true, minifyCss: true, includePageCSS: true, lang, skipLink, accessibilityTools })`.
383
623
  4. Per-section HTML is written to `section.content` and per-section documents to `section.contentMetadata.document`.
384
- 5. All section fragments are concatenated inside a single HTML document with viewport meta, base font, and canvas color from `PagePilotLayout`.
624
+ 5. All section fragments are concatenated inside a single HTML document with viewport meta, base font, and canvas color from `EmailLayout`.
385
625
  6. **Multi-section payload**: `{ record, html }` with the record's redundant `contentMetadata` / empty `behaviour` / empty `steps` stripped, and the outer `document` key omitted.
386
626
  **Single-doc payload**: `{ record, document, html }` where `record.contentMetadata` carries `document` + `html`.
387
627
 
@@ -455,20 +695,22 @@ The full set of keys the editor reads is documented inline at `src/host-stubs/i1
455
695
 
456
696
  ## Block types
457
697
 
458
- Out of the box the Add-Block menu exposes 25 block types:
698
+ Out of the box the Add-Block menu exposes 33 block types, grouped into six categories:
459
699
 
460
- | Layout | Content | Media | Specialized |
461
- |---|---|---|---|
462
- | Container | Heading | Image | Stepper |
463
- | Columns | Text | Logo | Accordion |
464
- | Flex Columns | Button | Video | Pricing |
465
- | Grid | Button Group | Avatar | Tabs |
466
- | Spacer | Html | | Carousel |
467
- | Divider | | | Rating |
468
- | | | | Marquee |
469
- | | | | iFrame |
470
- | | | | Skip Link |
471
- | | | | Accessibility |
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.
472
714
 
473
715
  Hide any of them via the `blocks` prop. Tile labels can be re-translated via `translations`.
474
716
 
@@ -522,11 +764,15 @@ export {
522
764
  // Imperative store access
523
765
  export * as EditorContext from "pagepilot-visual-editor";
524
766
 
767
+ // Pagepilot API client (for hosts using `apiConfig`)
768
+ export { PagepilotApiClient } from "pagepilot-visual-editor";
769
+
525
770
  // Types
526
771
  export type {
527
772
  PagePilotEditorProps, PageRecord, SaveChangesPayload,
528
773
  EditorPanelToggles, TopbarToggles,
529
774
  BlockKey, BlockToggles,
775
+ PagepilotApiConfig, ListParams, PageListRow, PageListResponse,
530
776
  TReaderBlock, TReaderDocument, TReaderBlockProps, TReaderProps,
531
777
  } from "pagepilot-visual-editor";
532
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: "";