pagepilot-visual-editor 1.0.7 → 1.0.8

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 (92) hide show
  1. package/README.md +214 -16
  2. package/dist/blocks-internal/block-button/src/index.d.ts +15 -9
  3. package/dist/blocks-internal/block-button-group/src/index.d.ts +6 -6
  4. package/dist/blocks-internal/block-columns-container/src/index.d.ts +3 -3
  5. package/dist/blocks-internal/block-container/src/index.d.ts +11 -11
  6. package/dist/blocks-internal/block-grid/src/index.d.ts +1 -1
  7. package/dist/blocks-internal/block-heading/src/index.d.ts +11 -5
  8. package/dist/blocks-internal/block-html/src/index.d.ts +2 -2
  9. package/dist/blocks-internal/block-iframe/src/index.d.ts +2 -2
  10. package/dist/blocks-internal/block-image/src/index.d.ts +3 -3
  11. package/dist/blocks-internal/block-list/src/index.d.ts +90 -0
  12. package/dist/blocks-internal/block-logo/src/index.d.ts +2 -2
  13. package/dist/blocks-internal/block-stepper/src/index.d.ts +10 -4
  14. package/dist/blocks-internal/block-text/src/index.d.ts +9 -3
  15. package/dist/blocks-internal/block-video/src/index.d.ts +3 -3
  16. package/dist/blocks-internal/block-youtube-url/src/index.d.ts +3 -3
  17. package/dist/editor/Shell.d.ts +1 -1
  18. package/dist/editor/Topbar.d.ts +5 -1
  19. package/dist/editor/blockToggles.d.ts +1 -1
  20. package/dist/editor/publish/PagePublishDialog.d.ts +7 -0
  21. package/dist/editor/types.d.ts +28 -0
  22. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/AppBannerPickerSidebarPanel.d.ts +7 -0
  23. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/FaqPickerSidebarPanel.d.ts +7 -0
  24. package/dist/editor-sample/App/InspectorDrawer/ConfigurationPanel/input-panels/ListSidebarPanel.d.ts +7 -0
  25. package/dist/editor-sample/App/InspectorDrawer/LayersPanelStyles.d.ts +2 -2
  26. package/dist/editor-sample/App/InspectorDrawer/LayoutPanel/TemplatesList.d.ts +19 -4
  27. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/UpgradeDialogView.d.ts +1 -0
  28. package/dist/editor-sample/App/InspectorDrawer/VariablesPanel/upgradeDialog.d.ts +15 -0
  29. package/dist/editor-sample/App/InspectorDrawer/useLayerNode.d.ts +1 -2
  30. package/dist/editor-sample/App/TemplatePanel/minimap/MiniMap.d.ts +6 -0
  31. package/dist/editor-sample/App/TemplatePanel/minimap/MiniMapFrame.d.ts +17 -0
  32. package/dist/editor-sample/App/TemplatePanel/minimap/useMiniMapSync.d.ts +24 -0
  33. package/dist/editor-sample/App/TemplatePanel/minimap/useMiniMapThumbnail.d.ts +8 -0
  34. package/dist/editor-sample/App/hooks/useAutosave.d.ts +10 -0
  35. package/dist/editor-sample/App/shared/editor.styles.d.ts +3 -3
  36. package/dist/editor-sample/documents/blocks/Accordion/AccordionPropsSchema.d.ts +6 -0
  37. package/dist/editor-sample/documents/blocks/AppBannerPicker/AppBannerEditor.d.ts +7 -0
  38. package/dist/editor-sample/documents/blocks/AppBannerPicker/AppBannerPropsSchema.d.ts +6 -0
  39. package/dist/editor-sample/documents/blocks/ButtonGroup/ButtonGroupPropsSchema.d.ts +6 -6
  40. package/dist/editor-sample/documents/blocks/ColumnsContainer/ColumnsContainerPropsSchema.d.ts +3 -3
  41. package/dist/editor-sample/documents/blocks/Container/ContainerPropsSchema.d.ts +11 -11
  42. package/dist/editor-sample/documents/blocks/DemoPicker/DemoPropsSchema.d.ts +2 -2
  43. package/dist/editor-sample/documents/blocks/EmailLayout/EmailLayoutPropsSchema.d.ts +3 -3
  44. package/dist/editor-sample/documents/blocks/FaqPicker/FaqEditor.d.ts +7 -0
  45. package/dist/editor-sample/documents/blocks/FaqPicker/FaqPickerPropsSchema.d.ts +6 -0
  46. package/dist/editor-sample/documents/blocks/FormsPicker/FormsPropsSchema.d.ts +2 -2
  47. package/dist/editor-sample/documents/blocks/Grid/GridPropsSchema.d.ts +3 -3
  48. package/dist/editor-sample/documents/blocks/Marquee/MarqueePropsSchema.d.ts +6 -1
  49. package/dist/editor-sample/documents/blocks/MenuPicker/MenuPropsSchema.d.ts +2 -2
  50. package/dist/editor-sample/documents/blocks/PricingAccordion/PricingAccordionPropsSchema.d.ts +2 -2
  51. package/dist/editor-sample/documents/blocks/Rating/RatingPropsSchema.d.ts +8 -2
  52. package/dist/editor-sample/documents/blocks/TabsBlock/TabsBlockPropsSchema.d.ts +6 -0
  53. package/dist/editor-sample/documents/blocks/Timer/TimerPropsSchema.d.ts +6 -0
  54. package/dist/editor-sample/documents/blocks/helpers/EditorChildrenIds/index.d.ts +4 -1
  55. package/dist/editor-sample/documents/blocks/helpers/block-wrappers/EditorBlockWrapper.d.ts +3 -2
  56. package/dist/editor-sample/documents/blocks/helpers/block-wrappers/useCanvasDrop.d.ts +14 -8
  57. package/dist/editor-sample/documents/blocks/helpers/documentUtils.d.ts +1 -0
  58. package/dist/editor-sample/documents/blocks/helpers/zod.d.ts +2 -2
  59. package/dist/editor-sample/documents/editor/EditorBlock.d.ts +6 -2
  60. package/dist/editor-sample/documents/editor/EditorContext.d.ts +15 -1
  61. package/dist/editor-sample/documents/editor/core.d.ts +246 -85
  62. package/dist/email-builder-core/blocks/AccessibilityTools/AccessibilityToolsPropsSchema.d.ts +21 -3
  63. package/dist/email-builder-core/blocks/Accordion/AccordionPropsSchema.d.ts +6 -0
  64. package/dist/email-builder-core/blocks/AppBannerPicker/AppBannerPropsSchema.d.ts +6 -0
  65. package/dist/email-builder-core/blocks/ButtonGroup/ButtonGroupPropsSchema.d.ts +6 -6
  66. package/dist/email-builder-core/blocks/Calendly/CalendlyPropsSchema.d.ts +8 -2
  67. package/dist/email-builder-core/blocks/ColumnsContainer/ColumnsContainerPropsSchema.d.ts +3 -3
  68. package/dist/email-builder-core/blocks/Container/ContainerPropsSchema.d.ts +11 -11
  69. package/dist/email-builder-core/blocks/DemoPicker/DemoPropsSchema.d.ts +2 -2
  70. package/dist/email-builder-core/blocks/EmailLayout/EmailLayoutPropsSchema.d.ts +5 -5
  71. package/dist/email-builder-core/blocks/FaqPicker/FaqPickerPropsSchema.d.ts +6 -0
  72. package/dist/email-builder-core/blocks/FlexColumns/FlexColumnsPropsSchema.d.ts +5 -5
  73. package/dist/email-builder-core/blocks/FormsPicker/FormsPropsSchema.d.ts +2 -2
  74. package/dist/email-builder-core/blocks/Grid/GridPropsSchema.d.ts +3 -3
  75. package/dist/email-builder-core/blocks/Marquee/MarqueePropsSchema.d.ts +6 -1
  76. package/dist/email-builder-core/blocks/Marquee/marqueeMotion.d.ts +3 -1
  77. package/dist/email-builder-core/blocks/MenuPicker/MenuPropsSchema.d.ts +4 -4
  78. package/dist/email-builder-core/blocks/Pagination/PaginationPropsSchema.d.ts +5 -5
  79. package/dist/email-builder-core/blocks/PricingAccordion/PricingAccordionPropsSchema.d.ts +2 -2
  80. package/dist/email-builder-core/blocks/Rating/RatingPropsSchema.d.ts +8 -2
  81. package/dist/email-builder-core/blocks/SkipLink/SkipLinkPropsSchema.d.ts +12 -2
  82. package/dist/email-builder-core/blocks/Table/TablePropsSchema.d.ts +8 -2
  83. package/dist/email-builder-core/blocks/TabsBlock/TabsBlockPropsSchema.d.ts +6 -0
  84. package/dist/email-builder-core/blocks/Timer/TimerPropsSchema.d.ts +6 -0
  85. package/dist/email-builder-core/blocks/helpers/blockStyleHelpers.d.ts +1 -0
  86. package/dist/email-builder-core/renderers/pageScripts.d.ts +8 -0
  87. package/dist/host-stubs/i18n.d.ts +1 -1
  88. package/dist/host-stubs/style/menu.styled.d.ts +7 -1
  89. package/dist/host-stubs/view/shared/modals/PopupConfirm.d.ts +8 -6
  90. package/dist/index.cjs +269 -268
  91. package/dist/index.js +30467 -27841
  92. package/package.json +11 -10
package/README.md CHANGED
@@ -114,10 +114,10 @@ built-in layout doesn't scale unexpectedly.
114
114
  ```
115
115
 
116
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.
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).
120
- - **3-dot menu** — currently exposes a single item, **Add Section**. Hidden by default; set `topbar.moreMenu` to `true`.
117
+ - **Topbar** — every control is individually toggleable via the `topbar` prop. Includes zoom out / zoom-% / zoom in (also driven by Ctrl/Cmd + wheel) / undo / redo / **deselect block** (auto-hidden when nothing is selected) / save / **auto save** (opt-in) / desktop-tablet-mobile / theme / more menu / fullscreen / preview / publish.
118
+ - **Canvas** — the block-based page editor. Click the empty-state "Add first section" or the ⋮ → Add Section. A **minimap** overview (togglable from the 3-dot menu) docks to the bottom-right and lets you click / drag to scroll long pages. Unsaved edits show the browser's native "Leave site?" prompt on tab close or reload.
119
+ - **Block TuneMenu** — appears above any selected block: **drag handle** (native reorder) / move up / move down / delete / **open in Layers** / **edit variables** (template-bound blocks only) / **more menu** (Save as template / Duplicate / Copy / Paste / **Replace** / Hide).
120
+ - **3-dot menu** — hidden by default; enable via `topbar.moreMenu`. Contains **Add Section** and **Show / Hide Minimap**.
121
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.
122
122
 
123
123
  ---
@@ -191,6 +191,8 @@ interface PageSection {
191
191
  | `translations` | `Record<string, string>` | `{}` | Merged on top of the built-in English dictionary. Missing keys fall back to defaults; missing default keys fall back to humanizing the last segment of the key. |
192
192
  | `topbar` | `TopbarToggles` | see below | Per-control visibility for the topbar. |
193
193
  | `blocks` | `BlockToggles` | all true | Per-tile visibility for the Add-Block menu. |
194
+ | `autoSaveEnabled` | `boolean` | `undefined` | Controlled value for the Auto Save switch. When `undefined` the switch is uncontrolled and its state is persisted to `localStorage` under `pagepilot.editor.autoSave.v1`. When set, the host owns the checked state and must update it via `onAutoSaveChange`. The switch itself is only rendered when `topbar.autoSave === true`. |
195
+ | `autoSaveIntervalMs` | `number` | `60000` | Autosave interval in milliseconds. Matches ahd-fe's 60-second cadence. Set to `0` to disable the interval while still showing the switch (useful for tests). |
194
196
  | `headerExtra` | `ReactNode` | `undefined` | Rendered immediately below the topbar — use for custom banners/announcement bars. |
195
197
  | `children` | `ReactNode` | `undefined` | Rendered after the editor body. |
196
198
 
@@ -223,6 +225,10 @@ interface TopbarToggles {
223
225
  unselect?: boolean; // default true — Deselect Block button
224
226
  // (auto-hides when nothing selected)
225
227
  save?: boolean; // default true
228
+ autoSave?: boolean; // default FALSE — Auto Save switch next to Save Changes
229
+ screenSize?: boolean; // default true — Desktop/Tablet/Mobile icon strip
230
+ // (also drives which per-device slice
231
+ // the sidebar is editing)
226
232
  themeToggle?: boolean; // default true — sun/moon button flipping light/dark
227
233
  fullscreen?: boolean; // default true
228
234
  preview?: boolean; // default true
@@ -231,7 +237,7 @@ interface TopbarToggles {
231
237
  }
232
238
  ```
233
239
 
234
- **Defaults note:** `moreMenu` and `publish` are **off by default** — they only appear when explicitly enabled. Everything else is on by default.
240
+ **Defaults note:** `autoSave`, `moreMenu`, and `publish` are **off by default** — they only appear when explicitly enabled. Everything else is on by default.
235
241
 
236
242
  #### `BlockToggles`
237
243
 
@@ -239,7 +245,7 @@ Per-tile visibility for the Add-Block menu. Each key defaults to `true`.
239
245
 
240
246
  ```ts
241
247
  type BlockKey =
242
- | "heading" | "text" | "button" | "image" | "logo" | "video"
248
+ | "heading" | "list" | "text" | "button" | "image" | "logo" | "video"
243
249
  | "avatar" | "divider" | "spacer" | "html"
244
250
  | "columns" | "flexColumns" | "grid"
245
251
  | "buttonGroup" | "container"
@@ -280,8 +286,9 @@ type BlockToggles = Partial<Record<BlockKey, boolean>>;
280
286
  | `onBackgroundChange` | `(image: string) => void` | Fires when the page-level background image changes. |
281
287
  | `onNavigateBranding` | `() => void` | Fires from the Brand panel (currently stripped from the standalone build — kept for forward-compat). |
282
288
  | `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. |
289
+ | `onAutoSaveChange` | `(enabled: boolean) => void` | Fires when the user flips the Auto Save switch. Always fires (both controlled and uncontrolled use) so hosts can mirror the flag to their own settings store. Only relevant when `topbar.autoSave === true`. |
283
290
  | `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. |
291
+ | `onUpgrade` | `() => void` | Fires when the user clicks the **Upgrade to unlock** CTA on the Variables-panel paywall. Route it to your billing / upgrade UI and the host owns the whole flow. **Without this callback the built-in `<UpgradeDialog>` opens instead** — a lightweight fallback whose "Upgrade Plan" button links to the pagepilot billing URL in a new tab. Only relevant when `apiConfig` is set. |
285
292
 
286
293
  #### `SaveChangesPayload`
287
294
 
@@ -348,6 +355,191 @@ Passing `apiConfig` to `<PagePilotEditor>` turns the editor into a full page-man
348
355
  | Variables panel with paywall gated on tenant plan | Left rail → Variables (auto-shown when template has fields) |
349
356
  | `getTenant()` for plan detection | Runs once on mount when `apiConfig` is set |
350
357
 
358
+ ### Getting your credentials
359
+
360
+ Before you can pass `apiConfig`, you need two things from your pagepilot admin console: a **`tenantId`** and an **`authToken`**. Both come from screens inside pagepilot itself. Skim the subsections in order — steps 1 and 2 are the actual credentials, the rest is production plumbing.
361
+
362
+ - [Prerequisites](#prerequisites)
363
+ - [Step 1 — Get your tenantId](#step-1--get-your-tenantid)
364
+ - [Step 2 — Mint an authToken](#step-2--mint-an-authtoken)
365
+ - [Storing credentials safely](#storing-credentials-safely)
366
+ - [Rotating a token](#rotating-a-token)
367
+ - [Troubleshooting credentials](#troubleshooting-credentials)
368
+ - [Verifying your setup](#verifying-your-setup)
369
+
370
+ #### Prerequisites
371
+
372
+ - A pagepilot account on [pagepilot.fabbuilder.com](https://pagepilot.fabbuilder.com) with access to at least one **workspace** (called a "tenant" everywhere in the API). The Free plan is enough to get save + publish working; some features gate behind Pro (see [Variables panel + tenant plan gating](#variables-panel--tenant-plan-gating)).
373
+ - **Owner or Admin** role in that workspace. Members with `Editor` / `Viewer` roles can't mint service accounts — the "Create Service Account" link is hidden.
374
+ - The workspace must already have at least one **page record** created (via `pagepilot.fabbuilder.com` or a direct `POST /tenant/:tenantId/page`). The editor's `record.id` must be a real backend id — see [Setup](#setup).
375
+
376
+ #### Step 1 — Get your tenantId
377
+
378
+ *(Workspaces → Workspace Id)*
379
+
380
+ Open [pagepilot.fabbuilder.com/tenant](https://pagepilot.fabbuilder.com/tenant). The page lists every workspace you belong to; the one shown at the top with the green **Active** badge is the workspace whose pages the editor will read + write. The **Workspace Id** printed under the workspace name IS your `tenantId` — copy it.
381
+
382
+ ![Workspaces page — the Workspace Id field is your tenantId](./src/assets/integration-guide/step-1-workspace-id.svg)
383
+
384
+ Notes:
385
+ - The id is a 24-char MongoDB ObjectId (e.g. `69e34f656c1eca798ec815bd`). If yours has dashes or spaces, you've grabbed something else.
386
+ - If you belong to multiple workspaces, each has its own tenantId — pages don't cross tenant boundaries. Pick the workspace that owns the pages you want to edit.
387
+ - Switching workspaces? Change the Active workspace in pagepilot first (via the top-left workspace picker), then re-copy the id — or just remember that `tenantId` is a per-workspace value.
388
+
389
+ > Tip: use the copy icon next to the id — the workspace name in the header is a link and can trigger a navigation if you double-click into the text.
390
+
391
+ #### Step 2 — Mint an authToken
392
+
393
+ *(Settings → Teams → Service Account)*
394
+
395
+ The editor authenticates to the pagepilot API with a **service-account bearer token** (a long-lived JWT scoped to the workspace). To create one:
396
+
397
+ 1. Go to **Settings → Teams** in pagepilot ([pagepilot.fabbuilder.com/settings/invite-members](https://pagepilot.fabbuilder.com/settings/invite-members)).
398
+ 2. Toggle **Show Service Accounts** on (top-right, next to "Invite Member"). This reveals the **Create Service Account** link — service accounts are hidden by default so the Teams tab stays clean for admins who don't use them.
399
+ 3. Click **Create Service Account**.
400
+
401
+ ![Settings → Teams tab with "Create Service Account" highlighted](./src/assets/integration-guide/step-2-service-accounts.svg)
402
+
403
+ In the modal that opens, fill in three fields:
404
+
405
+ | Field | What to enter | Notes |
406
+ |---|---|---|
407
+ | **Service Account ID** | A descriptive name, e.g. `visual-editor-prod`. | Free-form. Shows up in the Teams table so you can revoke it later. |
408
+ | **Access** | Pick the **lowest** role that satisfies your use case. | See the access-level table below. `Admin` is a safe default for editing + publishing. |
409
+ | **Expiration** | Any horizon from 7 days to 1 year. | The editor **does not refresh the token itself** — pick a window that matches your rotation policy. 30 days is a reasonable default; use a shorter window for dev / demo tokens. |
410
+
411
+ **Access levels (which one to pick):**
412
+
413
+ | Role | Can read pages | Can save (draft) | Can publish (`status: "live"`) | Can list / create templates |
414
+ |---|---|---|---|---|
415
+ | `Viewer` | ✅ | ❌ | ❌ | Read-only |
416
+ | `Editor` | ✅ | ✅ | ❌ | Read + save-as-template |
417
+ | `Admin` | ✅ | ✅ | ✅ | Full |
418
+ | `Owner` | ✅ | ✅ | ✅ | Full + billing |
419
+
420
+ **For most editor integrations, pick `Admin`** — the editor needs both save + publish and reads Templates / Saved / global-template endpoints. Only drop to `Editor` if the embedded editor is a "draft-only" surface where publishing happens elsewhere.
421
+
422
+ ![Service Account creation modal — click Create to mint the token](./src/assets/integration-guide/step-3-service-account-form.svg)
423
+
424
+ Click **Create**. Pagepilot shows the generated token **exactly once** in the row that appears in the Teams table — copy it into your secret store immediately. If you miss it, revoke the account and mint a new one; there's no way to re-view the token later.
425
+
426
+ This is the same value ahd-fe stores in `VITE_PAGEPILOT_SERVICE_AUTH_TOKEN`, so if you're migrating from an ahd-fe integration you already have one.
427
+
428
+ #### Storing credentials safely
429
+
430
+ Anyone with the token can read + write every page under your tenant, so treat it like a database password.
431
+
432
+ **Never commit it to the repo.** Read it from an env var at build time (Vite / Next.js) or fetch it from your own backend at runtime (recommended for browser apps that don't want a long-lived admin token shipped to the client).
433
+
434
+ **Vite** — put the token in `.env.local` (already gitignored by the Vite starter):
435
+
436
+ ```bash
437
+ # .env.local
438
+ VITE_PAGEPILOT_BASE_URL=https://pagepilot.fabbuilder.com/api
439
+ VITE_PAGEPILOT_TENANT_ID=6655bc2b30a6760d8f897581
440
+ VITE_PAGEPILOT_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
441
+ ```
442
+
443
+ ```tsx
444
+ <PagePilotEditor
445
+ apiConfig={{
446
+ baseUrl: import.meta.env.VITE_PAGEPILOT_BASE_URL,
447
+ tenantId: import.meta.env.VITE_PAGEPILOT_TENANT_ID,
448
+ authToken: import.meta.env.VITE_PAGEPILOT_TOKEN,
449
+ }}
450
+ />
451
+ ```
452
+
453
+ **Next.js** — use a **server component + prop drilling** (or a server action) so the token never enters the client bundle:
454
+
455
+ ```tsx
456
+ // app/editor/[id]/page.tsx — server component
457
+ import { PagePilotEditorClient } from "./PagePilotEditorClient";
458
+
459
+ export default async function EditorPage({ params }: { params: { id: string } }) {
460
+ const token = process.env.PAGEPILOT_TOKEN!; // server-only, no NEXT_PUBLIC_
461
+ return (
462
+ <PagePilotEditorClient
463
+ pageId={params.id}
464
+ baseUrl={process.env.PAGEPILOT_BASE_URL!}
465
+ tenantId={process.env.PAGEPILOT_TENANT_ID!}
466
+ authToken={token}
467
+ />
468
+ );
469
+ }
470
+ ```
471
+
472
+ ```tsx
473
+ // app/editor/[id]/PagePilotEditorClient.tsx — "use client"
474
+ "use client";
475
+ import { PagePilotEditor } from "pagepilot-visual-editor";
476
+ export function PagePilotEditorClient(props: { pageId: string; baseUrl: string; tenantId: string; authToken: string }) {
477
+ return (
478
+ <PagePilotEditor
479
+ record={{ id: props.pageId, type: "page" }}
480
+ apiConfig={{ baseUrl: props.baseUrl, tenantId: props.tenantId, authToken: props.authToken }}
481
+ />
482
+ );
483
+ }
484
+ ```
485
+
486
+ **Backend proxy (safest for multi-user apps).** Instead of shipping a service-account token to the browser, put your own backend in front of pagepilot: the browser authenticates to *your* backend with the user's session cookie, and your backend adds the pagepilot bearer server-side. Point `apiConfig.baseUrl` at your proxy (`https://myapp.com/pagepilot-proxy`), keep `authToken` empty (or a proxy-side session id — the editor sends whatever you give it verbatim), and enforce per-user auth on the proxy. This is how ahd-fe handles pagepilot in production.
487
+
488
+ #### Rotating a token
489
+
490
+ The editor doesn't refresh tokens itself — when yours expires, every save + publish call returns **401 Unauthorized** and lands in `onApiError`. The rotation flow is manual:
491
+
492
+ 1. Mint a new service account (or edit the existing one's expiration) in pagepilot Settings → Teams.
493
+ 2. Update the token in your env var / secret store.
494
+ 3. Redeploy (or trigger a config refresh — the editor re-reads `apiConfig` on prop change, so hot-swapping in-place works if you can update the prop).
495
+ 4. **Revoke the old service account** in the Teams table so a leaked copy stops working.
496
+
497
+ Handle expiration gracefully in `onApiError`:
498
+
499
+ ```tsx
500
+ <PagePilotEditor
501
+ apiConfig={apiConfig}
502
+ onApiError={(err, action) => {
503
+ if (err.message.includes("401") || err.message.includes("Unauthorized")) {
504
+ // Token expired or was revoked. Redirect to your re-auth flow.
505
+ window.location.href = "/reauth-pagepilot?returnTo=" + encodeURIComponent(window.location.pathname);
506
+ return;
507
+ }
508
+ toast.error(`${action} failed: ${err.message}`);
509
+ }}
510
+ />
511
+ ```
512
+
513
+ #### Troubleshooting credentials
514
+
515
+ | Symptom | Likely cause | Fix |
516
+ |---|---|---|
517
+ | `401 Unauthorized` on every save | Token expired, revoked, or copied incompletely. | Mint a fresh token; make sure you copied the whole `eyJ…` string with no trailing whitespace. |
518
+ | `403 Forbidden` on Publish only | Service account role is `Editor` (or lower). | Recreate as `Admin`, or move publish to a separate token / server route. |
519
+ | `404 Not Found` on save, but the page exists in pagepilot | `record.id` doesn't match a page in this tenant, OR `tenantId` points at the wrong workspace. | Double-check the Active workspace on the Workspaces page. `record.id` must be a MongoDB ObjectId that already exists — the editor doesn't create pages, it only updates them. |
520
+ | CORS error in the browser console (`Access-Control-Allow-Origin`) | Origin isn't in pagepilot's allowed origins for this tenant. | Add your dev / prod origin to the tenant's allowed origins in pagepilot Configurations, OR proxy the request through your own backend. |
521
+ | Save appears silent — no error, no persisted change | `apiConfig` is set but `record.id === "doc-1"` (the demo seed). | Pass a real backend id via `record.id` before the API path fires. Demo ids are intentionally skipped. |
522
+ | `onApiError` never fires but Save is stuck "dirty" | `onApiError` isn't set and errors are going to `console.error` only. | Wire `onApiError` — see the snippet in [Rotating a token](#rotating-a-token). |
523
+
524
+ #### Verifying your setup
525
+
526
+ Before wiring the credentials into the editor, sanity-check them with a plain `curl` (or fetch) from a terminal:
527
+
528
+ ```bash
529
+ curl -i \
530
+ -H "Authorization: Bearer $VITE_PAGEPILOT_TOKEN" \
531
+ "https://pagepilot.fabbuilder.com/api/tenant/$VITE_PAGEPILOT_TENANT_ID/page?limit=1&offset=0"
532
+ ```
533
+
534
+ Expected: **HTTP/1.1 200 OK** and a JSON body with a `rows` array. If you see:
535
+
536
+ - **401** — token is wrong or expired. Re-mint.
537
+ - **403** — token is valid but role too low for reads. Mint an Admin token.
538
+ - **404** — the `tenantId` doesn't exist. Re-copy from the Workspaces page.
539
+ - **200 with `rows: []`** — credentials are fine; the tenant just has no pages yet. Create one in pagepilot, then use its id in `record.id`.
540
+
541
+ Once the curl returns 200, drop the same three values into `apiConfig` and the editor's Save + Publish will hit the same endpoint.
542
+
351
543
  ### Setup
352
544
 
353
545
  ```tsx
@@ -357,8 +549,8 @@ import { PagePilotEditor } from "pagepilot-visual-editor";
357
549
  record={page}
358
550
  apiConfig={{
359
551
  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
552
+ tenantId: "6655bc2b30a6760d8f897581", // from step 1 above
553
+ authToken: "eyJhbGciOi…", // from step 2 above
362
554
  }}
363
555
  onApiError={(err, action) => toast.error(`${action}: ${err.message}`)}
364
556
  onUpgrade={() => openBillingModal()}
@@ -371,7 +563,7 @@ import { PagePilotEditor } from "pagepilot-visual-editor";
371
563
  Requirements for the API path to actually fire:
372
564
 
373
565
  - `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`).
566
+ - The `authToken` must be a valid service-account bearer for the given `tenantId` see [Getting your credentials](#getting-your-credentials) above.
375
567
 
376
568
  ### PagepilotApiConfig shape
377
569
 
@@ -437,6 +629,7 @@ When `apiConfig` is set, clicking **Publish** opens a full dialog instead of fir
437
629
 
438
630
  - **Basic Info** tab: page name, slug, publish date, "All Time Live" toggle, end date (when off).
439
631
  - **Menu Links** tab: pick a tenant menu (fetched via `apiClient.listMenus`) and append this page as a new item to that menu's `configuration`.
632
+ - **Scripts & Styles** tab: paste a stylesheet snippet that's inlined into the published HTML, and flip per-page injection toggles for the built-in tabs scroll-sync and carousel scripts. Both toggles default on inside `renderToStaticMarkup`; setting them here lets a page opt out.
440
633
  - **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
634
 
442
635
  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.
@@ -462,7 +655,7 @@ The Variables tab surfaces template tokens for filling at edit time. Visibility
462
655
  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
656
  - `plan === "proCombo" | "enterprise"` → real field editors render.
464
657
  - 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.
658
+ 3. **The paywall CTA** ("Upgrade to unlock") fires `onUpgrade` if the host provided it; otherwise it opens the built-in `<UpgradeDialog>`, which links to the pagepilot billing URL in a new tab.
466
659
 
467
660
  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
661
 
@@ -523,11 +716,14 @@ All methods send `Content-Type: application/json` + the bearer token automatical
523
716
  | **← Back** | Calls `onBack`. The host typically navigates away. |
524
717
  | **Page title + status pill** | Display-only. Sourced from `recordTitle` / `recordStatus` (or `record.title / record.name / record.status`). |
525
718
  | **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. |
719
+ | **Zoom controls** (− / % / +) | Zoom out, current zoom level (click to reset to 100%), zoom in. Range is 25%–100%; buttons disable at the endpoints. Users can also hold **Ctrl / Cmd** and scroll on the canvas to zoom cursor-anchored. Hidden together with Undo/Redo via `topbar={{ undo: false }}` (they share the toggle since they sit in the same group). |
526
720
  | **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. |
527
721
  | **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
722
  | **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`. |
723
+ | **Auto Save** | **Opt-in** — hidden unless `topbar={{ autoSave: true }}`. Bordered label + toggle switch rendered immediately left of Save Changes. While on, the editor re-runs the same handler `Save Changes` uses on a fixed interval (`autoSaveIntervalMs`, default 60s), gated by the same dirty flag — a clean editor never fires. The switch is uncontrolled by default and its checked state is persisted to `localStorage` under `pagepilot.editor.autoSave.v1`; pass `autoSaveEnabled` + `onAutoSaveChange` to control it from the host. Every flip fires `onAutoSaveChange` so hosts can mirror the flag to their own settings. |
724
+ | **Screen size** (Desktop / Tablet / Mobile) | Three-way icon strip that constrains the canvas preview width and keeps the sidebar's per-device tabs in lock-step — switching here also switches which per-device slice the Inspect panel is editing. Hidden via `topbar={{ screenSize: false }}`. |
529
725
  | **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). |
530
- | **3-dot menu** ⋮ | Single item: **+ Add Section**. Off by default — enable via `topbar.moreMenu`. |
726
+ | **3-dot menu** ⋮ | Off by default — enable via `topbar.moreMenu`. Contains **+ Add Section** and **Show / Hide Minimap** (the minimap is a click-to-jump / drag-to-scroll canvas overview that docks to the bottom-right corner). |
531
727
  | **Fullscreen** ⤢ | Toggles the editor's container via the browser Fullscreen API. Icon swaps to "exit fullscreen" while active; pressing `Esc` exits. |
532
728
  | **Preview** ▶ | Opens the in-page Preview dialog with desktop/tablet/mobile size toggles. The iframe renders the **same HTML** that's sent to `onSaveChanges` / `onPublish`. If `onTogglePreview` is supplied, that callback fires instead. |
533
729
  | **Publish** | Calls `onPublish`. |
@@ -539,10 +735,12 @@ Selecting any block on the canvas surfaces a floating action popover just above
539
735
 
540
736
  | Action | Behavior |
541
737
  |---|---|
738
+ | **⋮⋮ Drag handle** | Native HTML5 drag source. Grab the leftmost dots to drag this block onto another block's drop target and reorder it on the canvas — no need to open the Layers panel. |
542
739
  | **↑ Move up** | Swaps this block with its previous sibling under the same parent. |
543
740
  | **↓ Move down** | Swaps with the next sibling. |
544
741
  | **🗑 Delete** | Removes the block and its subtree. Also prunes any `formFields` whose `sourceBlockId` pointed at this block. |
545
742
  | **⧉ 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. |
743
+ | **✎ Edit Variables** | Only appears on blocks that participate in template forms (repeatable containers + blocks bound to `formFields`). Opens the Variables panel focused on this block's fields. |
546
744
  | **⋯ More menu** | Opens the secondary popover below. |
547
745
 
548
746
  The **⋯ More** popover contains:
@@ -594,7 +792,7 @@ The Layout panel always shows the **Blocks** picker — a category-grouped tile
594
792
 
595
793
  When `apiConfig` is set, two additional tabs appear at the top of the Layout panel:
596
794
 
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).
795
+ - **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). A **Templates / Blocks** toggle at the top of the tab flips the fetch between `type=page` and `type=block`, matching ahd-fe. A refresh icon re-fetches the current list.
598
796
  - **Saved** — per-tenant `/mytemplate` list. Same card UI with an on-hover delete button.
599
797
 
600
798
  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.
@@ -695,14 +893,14 @@ The full set of keys the editor reads is documented inline at `src/host-stubs/i1
695
893
 
696
894
  ## Block types
697
895
 
698
- Out of the box the Add-Block menu exposes 33 block types, grouped into six categories:
896
+ Out of the box the Add-Block menu exposes 34 block types, grouped into six categories:
699
897
 
700
898
  | Text/Content | Media | Layout/Structure | Actions/Controls | Embeds/Integrations | Support/Utility |
701
899
  |---|---|---|---|---|---|
702
900
  | Heading | Image | Container | Button | Timer | Rating |
703
901
  | Text | Logo | Columns | Button Group | YouTube Url | Skip Link |
704
- | Table | Video | Flex Columns | Accordion | Demo Picker¹ | Accessibility |
705
- | | Avatar | Grid | Tabs | Header¹ (MenuPicker) | |
902
+ | List | Video | Flex Columns | Accordion | Demo Picker¹ | Accessibility |
903
+ | Table | Avatar | Grid | Tabs | Header¹ (MenuPicker) | |
706
904
  | | | Spacer | Stepper | Forms¹ | |
707
905
  | | | Divider | | App Banner¹ | |
708
906
  | | | Html | | FAQs¹ | |
@@ -36,21 +36,21 @@ export declare const ButtonPropsSchema: z.ZodObject<{
36
36
  }>>>;
37
37
  fontWeight: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
38
38
  bold: "bold";
39
+ normal: "normal";
39
40
  400: "400";
40
41
  500: "500";
41
42
  600: "600";
42
43
  700: "700";
43
- normal: "normal";
44
44
  }>>>;
45
45
  textAlign: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
46
- right: "right";
47
- left: "left";
48
46
  center: "center";
47
+ left: "left";
48
+ right: "right";
49
49
  }>>>;
50
50
  buttonTextAlign: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
51
- right: "right";
52
- left: "left";
53
51
  center: "center";
52
+ left: "left";
53
+ right: "right";
54
54
  }>>>;
55
55
  padding: z.ZodNullable<z.ZodOptional<z.ZodObject<{
56
56
  top: z.ZodNumber;
@@ -58,6 +58,12 @@ export declare const ButtonPropsSchema: z.ZodObject<{
58
58
  right: z.ZodNumber;
59
59
  left: z.ZodNumber;
60
60
  }, z.core.$strip>>>;
61
+ margin: z.ZodNullable<z.ZodOptional<z.ZodObject<{
62
+ top: z.ZodNumber;
63
+ bottom: z.ZodNumber;
64
+ right: z.ZodNumber;
65
+ left: z.ZodNumber;
66
+ }, z.core.$strip>>>;
61
67
  }, z.core.$strip>>>;
62
68
  props: z.ZodNullable<z.ZodOptional<z.ZodObject<{
63
69
  buttonBackground: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodString, z.ZodString, z.ZodLiteral<"transparent">]>>>;
@@ -102,21 +108,21 @@ export declare const ButtonPropsSchema: z.ZodObject<{
102
108
  widthMobile: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
103
109
  size: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
104
110
  small: "small";
105
- "x-small": "x-small";
106
111
  large: "large";
107
112
  medium: "medium";
113
+ "x-small": "x-small";
108
114
  }>>>;
109
115
  sizeTablet: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
110
116
  small: "small";
111
- "x-small": "x-small";
112
117
  large: "large";
113
118
  medium: "medium";
119
+ "x-small": "x-small";
114
120
  }>>>;
115
121
  sizeMobile: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
116
122
  small: "small";
117
- "x-small": "x-small";
118
123
  large: "large";
119
124
  medium: "medium";
125
+ "x-small": "x-small";
120
126
  }>>>;
121
127
  text: z.ZodNullable<z.ZodOptional<z.ZodString>>;
122
128
  url: z.ZodNullable<z.ZodOptional<z.ZodString>>;
@@ -134,8 +140,8 @@ export declare const ButtonPropsSchema: z.ZodObject<{
134
140
  iconEnabled: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
135
141
  iconName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
136
142
  iconAlignment: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
137
- right: "right";
138
143
  left: "left";
144
+ right: "right";
139
145
  }>>>;
140
146
  ariaLabel: z.ZodNullable<z.ZodOptional<z.ZodString>>;
141
147
  goToStep: z.ZodNullable<z.ZodOptional<z.ZodString>>;
@@ -26,21 +26,21 @@ export declare const ButtonGroupPropsSchema: z.ZodObject<{
26
26
  gap: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
27
27
  alignment: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
28
28
  center: "center";
29
- "space-between": "space-between";
30
- start: "start";
31
29
  end: "end";
30
+ start: "start";
31
+ "space-between": "space-between";
32
32
  }>>>;
33
33
  alignmentTablet: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
34
34
  center: "center";
35
- "space-between": "space-between";
36
- start: "start";
37
35
  end: "end";
36
+ start: "start";
37
+ "space-between": "space-between";
38
38
  }>>>;
39
39
  alignmentMobile: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
40
40
  center: "center";
41
- "space-between": "space-between";
42
- start: "start";
43
41
  end: "end";
42
+ start: "start";
43
+ "space-between": "space-between";
44
44
  }>>>;
45
45
  wrap: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
46
46
  ariaLabel: z.ZodNullable<z.ZodOptional<z.ZodString>>;
@@ -52,18 +52,18 @@ export declare const ColumnsContainerPropsSchema: z.ZodObject<{
52
52
  vertical: "vertical";
53
53
  }>>>;
54
54
  contentAlignment: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
55
- top: "top";
56
55
  bottom: "bottom";
56
+ top: "top";
57
57
  middle: "middle";
58
58
  }>>>;
59
59
  contentAlignmentTablet: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
60
- top: "top";
61
60
  bottom: "bottom";
61
+ top: "top";
62
62
  middle: "middle";
63
63
  }>>>;
64
64
  contentAlignmentMobile: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
65
- top: "top";
66
65
  bottom: "bottom";
66
+ top: "top";
67
67
  middle: "middle";
68
68
  }>>>;
69
69
  }, z.core.$strip>>>;
@@ -64,37 +64,37 @@ export declare const ContainerPropsSchema: z.ZodObject<{
64
64
  heightMobile: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
65
65
  overflow: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
66
66
  alignment: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
67
- right: "right";
68
- left: "left";
69
67
  center: "center";
68
+ left: "left";
69
+ right: "right";
70
70
  }>>>;
71
71
  alignmentTablet: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
72
- right: "right";
73
- left: "left";
74
72
  center: "center";
73
+ left: "left";
74
+ right: "right";
75
75
  }>>>;
76
76
  alignmentMobile: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
77
- right: "right";
78
- left: "left";
79
77
  center: "center";
78
+ left: "left";
79
+ right: "right";
80
80
  }>>>;
81
81
  tag: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
82
- div: "div";
83
- section: "section";
84
82
  article: "article";
85
- nav: "nav";
86
83
  aside: "aside";
87
- header: "header";
84
+ div: "div";
88
85
  footer: "footer";
86
+ header: "header";
89
87
  main: "main";
88
+ nav: "nav";
89
+ section: "section";
90
90
  }>>>;
91
91
  ariaLabel: z.ZodNullable<z.ZodOptional<z.ZodString>>;
92
92
  elementId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
93
93
  showLink: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
94
94
  linkHref: z.ZodNullable<z.ZodOptional<z.ZodString>>;
95
95
  linkTarget: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
96
- _self: "_self";
97
96
  _blank: "_blank";
97
+ _self: "_self";
98
98
  }>>>;
99
99
  }, z.core.$strip>>>;
100
100
  }, z.core.$strip>;
@@ -24,8 +24,8 @@ export declare const GridPropsSchema: z.ZodObject<{
24
24
  columnsGap: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
25
25
  rowsGap: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
26
26
  contentAlignment: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
27
- top: "top";
28
27
  bottom: "bottom";
28
+ top: "top";
29
29
  middle: "middle";
30
30
  }>>>;
31
31
  }, z.core.$strip>>>;
@@ -56,11 +56,11 @@ export declare const HeadingPropsSchema: z.ZodObject<{
56
56
  fontSize: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
57
57
  fontWeight: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
58
58
  bold: "bold";
59
+ normal: "normal";
59
60
  400: "400";
60
61
  500: "500";
61
62
  600: "600";
62
63
  700: "700";
63
- normal: "normal";
64
64
  }>>>;
65
65
  fontStyle: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
66
66
  normal: "normal";
@@ -68,14 +68,14 @@ export declare const HeadingPropsSchema: z.ZodObject<{
68
68
  }>>>;
69
69
  textDecoration: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
70
70
  none: "none";
71
- underline: "underline";
72
71
  "line-through": "line-through";
72
+ underline: "underline";
73
73
  "underline line-through": "underline line-through";
74
74
  }>>>;
75
75
  textAlign: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
76
- right: "right";
77
- left: "left";
78
76
  center: "center";
77
+ left: "left";
78
+ right: "right";
79
79
  }>>>;
80
80
  padding: z.ZodNullable<z.ZodOptional<z.ZodObject<{
81
81
  top: z.ZodNumber;
@@ -83,6 +83,12 @@ export declare const HeadingPropsSchema: z.ZodObject<{
83
83
  right: z.ZodNumber;
84
84
  left: z.ZodNumber;
85
85
  }, z.core.$strip>>>;
86
+ margin: z.ZodNullable<z.ZodOptional<z.ZodObject<{
87
+ top: z.ZodNumber;
88
+ bottom: z.ZodNumber;
89
+ right: z.ZodNumber;
90
+ left: z.ZodNumber;
91
+ }, z.core.$strip>>>;
86
92
  }, z.core.$strip>>>;
87
93
  }, z.core.$strip>;
88
94
  export type HeadingProps = z.infer<typeof HeadingPropsSchema>;
@@ -96,4 +102,4 @@ export declare const HeadingPropsDefaults: {
96
102
  readonly openInNewTab: false;
97
103
  };
98
104
  export declare function Heading({ props, style }: HeadingProps): import("react/jsx-runtime").JSX.Element;
99
- export declare function getFontSize(level: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'): 16 | 32 | 20 | 24 | 18 | 14;
105
+ export declare function getFontSize(level: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'): 14 | 16 | 18 | 20 | 24 | 32;
@@ -36,9 +36,9 @@ export declare const HtmlPropsSchema: z.ZodObject<{
36
36
  }>>>;
37
37
  fontSize: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
38
38
  textAlign: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
39
- right: "right";
40
- left: "left";
41
39
  center: "center";
40
+ left: "left";
41
+ right: "right";
42
42
  }>>>;
43
43
  padding: z.ZodNullable<z.ZodOptional<z.ZodObject<{
44
44
  top: z.ZodNumber;
@@ -12,9 +12,9 @@ export declare const IframePropsSchema: z.ZodObject<{
12
12
  left: z.ZodNumber;
13
13
  }, z.core.$strip>>>;
14
14
  textAlign: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
15
- right: "right";
16
- left: "left";
17
15
  center: "center";
16
+ left: "left";
17
+ right: "right";
18
18
  }>>>;
19
19
  }, z.core.$strip>>>;
20
20
  props: z.ZodNullable<z.ZodOptional<z.ZodObject<{
@@ -9,9 +9,9 @@ export declare const ImagePropsSchema: z.ZodObject<{
9
9
  }, z.core.$strip>>>;
10
10
  backgroundColor: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodString, z.ZodString, z.ZodLiteral<"transparent">]>>>>;
11
11
  textAlign: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
12
- right: "right";
13
- left: "left";
14
12
  center: "center";
13
+ left: "left";
14
+ right: "right";
15
15
  }>>>;
16
16
  }, z.core.$strip>>>;
17
17
  props: z.ZodNullable<z.ZodOptional<z.ZodObject<{
@@ -37,8 +37,8 @@ export declare const ImagePropsSchema: z.ZodObject<{
37
37
  decorative: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
38
38
  linkHref: z.ZodNullable<z.ZodOptional<z.ZodString>>;
39
39
  contentAlignment: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
40
- top: "top";
41
40
  bottom: "bottom";
41
+ top: "top";
42
42
  middle: "middle";
43
43
  }>>>;
44
44
  borderRadius: z.ZodNullable<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodObject<{