@bettercms-ai/astro 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -0
- package/components/BcmsBlocks.astro +6 -1
- package/components/BcmsField.astro +0 -0
- package/components/BcmsForm.astro +0 -0
- package/components/BcmsImage.astro +0 -0
- package/components/BcmsLive.astro +0 -0
- package/components/BcmsLiveBlocks.astro +72 -0
- package/components/BcmsSearch.astro +0 -0
- package/components/BcmsVisualEditing.astro +0 -0
- package/env.d.ts +0 -0
- package/package.json +14 -5
package/README.md
CHANGED
|
@@ -112,9 +112,58 @@ or on-demand-revalidation hook.
|
|
|
112
112
|
| `@bettercms-ai/astro/components/BcmsBlocks.astro` | Render a page's `blockJson` — every block type the builder can author (heading, text/richtext, image, button, spacer, video, columns, form, section, navbar, footer, slider, tabs, component), with block style tokens applied. |
|
|
113
113
|
| `@bettercms-ai/astro/components/BcmsForm.astro` | Render + submit a form (conditional fields, honeypot, Turnstile). |
|
|
114
114
|
| `@bettercms-ai/astro/components/BcmsImage.astro` | Optimized image with a 1x/2x srcset via the media transform endpoint. |
|
|
115
|
+
| `@bettercms-ai/astro/components/BcmsLiveBlocks.astro` | `BcmsBlocks` as a hydrated island that lets the Visual Editor re-render your DRAFTS with your own components and CSS. See below. |
|
|
115
116
|
|
|
116
117
|
Markup is class-driven and unstyled — you own the CSS.
|
|
117
118
|
|
|
119
|
+
## Live editing on a static site — `<BcmsLiveBlocks>`
|
|
120
|
+
|
|
121
|
+
When the Visual Editor frames a static build it can only show what was built, so editing a
|
|
122
|
+
draft falls back to the platform's approximate renderer and the canvas stops looking like your
|
|
123
|
+
site. `<BcmsLiveBlocks>` fixes that for pages whose body is a block tree: it renders the same
|
|
124
|
+
markup `<BcmsBlocks>` does, but as a `client:load` island that accepts draft documents from the
|
|
125
|
+
editor over `postMessage` (same-origin, parent frame only, and only after the editor's own
|
|
126
|
+
handshake — a third-party page that iframes your site is on a foreign origin and gets nothing).
|
|
127
|
+
Nothing is fetched by the page and no credentials enter it.
|
|
128
|
+
|
|
129
|
+
It needs a JSX renderer, which a component cannot add for you:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
npm i @astrojs/preact preact
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
// astro.config.mjs
|
|
137
|
+
import preact from "@astrojs/preact";
|
|
138
|
+
export default defineConfig({ integrations: [bettercms(), preact({ compat: true })] });
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```astro
|
|
142
|
+
---
|
|
143
|
+
import BcmsLiveBlocks from "@bettercms-ai/astro/components/BcmsLiveBlocks.astro";
|
|
144
|
+
const page = await getPage(Astro.params.slug);
|
|
145
|
+
const { forms } = await readForms();
|
|
146
|
+
---
|
|
147
|
+
<BcmsLiveBlocks slug={page.slug} blocks={page.blocks} forms={forms} />
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`compat: true` is required — the island reuses the React `<BcmsDraftBridge>` from
|
|
151
|
+
`@bettercms-ai/next` so both SDKs speak one protocol. Roughly 10 kB of Preact plus the block
|
|
152
|
+
renderer; `@astrojs/react` works too if your project already uses it.
|
|
153
|
+
|
|
154
|
+
⚠️ **It emits the React class names, not this package's.** `<BcmsBlocks>` from
|
|
155
|
+
[`@bettercms-ai/next`](https://www.npmjs.com/package/@bettercms-ai/next) classes its output
|
|
156
|
+
`bcms-block bcms-block--text`, `bcms-button--primary`, `bcms-column`; `BcmsBlocks.astro` above
|
|
157
|
+
classes the same tree `bcms-text`, `bcms-btn-primary`, `bcms-cols`. They are NOT interchangeable: a
|
|
158
|
+
stylesheet written for the `.astro` grammar styles nothing on this island, so swapping a page over
|
|
159
|
+
unstyles it. Cover both spellings — the starters wrap them in one `:is()` selector for exactly this
|
|
160
|
+
reason — or take the class list from `@bettercms-ai/next`'s `src/blocks.tsx`.
|
|
161
|
+
|
|
162
|
+
**It only helps pages you render through `BcmsBlocks`.** A hand-written `.astro` layout, or
|
|
163
|
+
content pulled into your own components, is invisible to the bridge — for those, structural
|
|
164
|
+
draft preview needs a server-rendered draft route instead (`output: 'server'` + the draft-mode
|
|
165
|
+
routes below).
|
|
166
|
+
|
|
118
167
|
## Draft mode
|
|
119
168
|
|
|
120
169
|
The integration injects `/api/bcms/draft/enable?token=<jwt>&redirect=/path` and
|
|
@@ -448,7 +448,12 @@ const pass = { forms, components, turnstileSiteKey, nested: true, fieldAddresses
|
|
|
448
448
|
blocks={resolved.blocks}
|
|
449
449
|
depth={depth + 1}
|
|
450
450
|
seen={[...seen, resolved.id]}
|
|
451
|
-
containerAttrs={
|
|
451
|
+
containerAttrs={{
|
|
452
|
+
...blockAttrs,
|
|
453
|
+
"data-bcms-component": resolved.id,
|
|
454
|
+
"data-bcms-variant": "base",
|
|
455
|
+
"data-bcms-instance": block.id,
|
|
456
|
+
}}
|
|
452
457
|
{...pass}
|
|
453
458
|
fieldAddresses={componentInstanceAddresses(block.id, resolved.props)}
|
|
454
459
|
/>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* <BcmsLiveBlocks> — <BcmsBlocks>, but as a hydrated island that speaks the visual editor's
|
|
4
|
+
* draft bridge (E5 / FLO-1178).
|
|
5
|
+
*
|
|
6
|
+
* WHY IT IS NOT A .astro RENDERER. An .astro component is server-only: once the page is built
|
|
7
|
+
* there is nothing on the client to hand a new document to, so an Astro site can only show the
|
|
8
|
+
* editor a STATIC build and the canvas falls back to the platform's approximate renderer for
|
|
9
|
+
* every draft. The bridge needs a live component tree, and the only one that already exists,
|
|
10
|
+
* is at parity with this package, and speaks the protocol is <BcmsDraftBridge> from
|
|
11
|
+
* @bettercms-ai/next — which imports nothing from `next/*` (React and @bettercms-ai/* only),
|
|
12
|
+
* so it mounts here unchanged. Reused rather than reimplemented: one protocol, one twin to
|
|
13
|
+
* keep in step instead of two.
|
|
14
|
+
*
|
|
15
|
+
* RUNTIME: Preact + `compat`, verified by the P2-1 spike (see ../SPIKE.md — SSR and hydration
|
|
16
|
+
* of a heading + PortableText richtext + BcmsForm tree, both clean). The cost is real and worth
|
|
17
|
+
* naming: preact plus its compat aliases on the island (~10 kB of runtime, so `react` itself is
|
|
18
|
+
* never bundled even though @bettercms-ai/ui declares React peers), and `@bettercms-ai/next` as a
|
|
19
|
+
* dependency of this package.
|
|
20
|
+
*
|
|
21
|
+
* 🔴 THE CLASS NAMES ARE THE REACT GRAMMAR, NOT THIS PACKAGE'S. <BcmsBlocks> in @bettercms-ai/next
|
|
22
|
+
* emits `bcms-block bcms-block--text`, `bcms-button--primary`, `bcms-column`; BcmsBlocks.astro
|
|
23
|
+
* emits `bcms-text`, `bcms-btn-primary`, `bcms-cols`. Same markup shape, different hooks — a
|
|
24
|
+
* stylesheet written against the .astro grammar styles NOTHING here, and swapping a page from
|
|
25
|
+
* <BcmsBlocks> to <BcmsLiveBlocks> unstyles it. Either cover both spellings (the starters use
|
|
26
|
+
* `:is()` for exactly this) or read the React classes off @bettercms-ai/next's src/blocks.tsx.
|
|
27
|
+
*
|
|
28
|
+
* The consumer supplies the renderer, because an integration cannot be added from a component:
|
|
29
|
+
*
|
|
30
|
+
* // astro.config.mjs
|
|
31
|
+
* import preact from "@astrojs/preact";
|
|
32
|
+
* export default defineConfig({ integrations: [bettercms(), preact({ compat: true })] });
|
|
33
|
+
*
|
|
34
|
+
* ---
|
|
35
|
+
* import BcmsLiveBlocks from "@bettercms-ai/astro/components/BcmsLiveBlocks.astro";
|
|
36
|
+
* const page = await getPage(Astro.params.slug);
|
|
37
|
+
* ---
|
|
38
|
+
* <BcmsLiveBlocks slug={page.slug} blocks={page.blocks} forms={forms} />
|
|
39
|
+
*
|
|
40
|
+
* Standalone the island renders exactly what <BcmsBlocks> renders (inside the
|
|
41
|
+
* `data-bcms-canvas="bridge"` marker <div> that <BcmsDraftBridge> emits); the bridge only
|
|
42
|
+
* wakes when the editor frames the page and pushes a draft. This only helps pages whose body
|
|
43
|
+
* IS a block tree — a hand-written .astro layout is unreachable from here by construction.
|
|
44
|
+
*/
|
|
45
|
+
import { BcmsDraftBridge } from "@bettercms-ai/next/draft-bridge";
|
|
46
|
+
import type { ContentBlock } from "@bettercms-ai/types";
|
|
47
|
+
import type { DeliveryComponent, DeliveryForm } from "@bettercms-ai/sdk";
|
|
48
|
+
|
|
49
|
+
interface Props {
|
|
50
|
+
/** The page's slug. A pushed draft is applied only when its slug matches. */
|
|
51
|
+
slug: string;
|
|
52
|
+
blocks: ContentBlock[];
|
|
53
|
+
forms?: DeliveryForm[];
|
|
54
|
+
components?: DeliveryComponent[];
|
|
55
|
+
turnstileSiteKey?: string;
|
|
56
|
+
apiBase?: string;
|
|
57
|
+
class?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const { slug, blocks, forms, components, turnstileSiteKey, apiBase, class: className } = Astro.props;
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
<BcmsDraftBridge
|
|
64
|
+
client:load
|
|
65
|
+
slug={slug}
|
|
66
|
+
blocks={blocks}
|
|
67
|
+
forms={forms}
|
|
68
|
+
components={components}
|
|
69
|
+
turnstileSiteKey={turnstileSiteKey}
|
|
70
|
+
apiBase={apiBase}
|
|
71
|
+
className={className}
|
|
72
|
+
/>
|
|
File without changes
|
|
File without changes
|
package/env.d.ts
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bettercms-ai/astro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "The BetterCMS adapter for Astro
|
|
5
|
+
"description": "The BetterCMS adapter for Astro — a `bettercms()` integration, a `bettercms:client` virtual module, typed content loaders, draft preview, and native .astro rendering components.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"./draft-enable": "./dist/routes/draft-enable.js",
|
|
32
32
|
"./draft-disable": "./dist/routes/draft-disable.js",
|
|
33
33
|
"./components/BcmsBlocks.astro": "./components/BcmsBlocks.astro",
|
|
34
|
+
"./components/BcmsLiveBlocks.astro": "./components/BcmsLiveBlocks.astro",
|
|
34
35
|
"./components/BcmsField.astro": "./components/BcmsField.astro",
|
|
35
36
|
"./components/BcmsForm.astro": "./components/BcmsForm.astro",
|
|
36
37
|
"./components/BcmsSearch.astro": "./components/BcmsSearch.astro",
|
|
@@ -56,20 +57,28 @@
|
|
|
56
57
|
"@bettercms-ai/sdk": "^1.14.0",
|
|
57
58
|
"@bettercms-ai/types": "^1.11.0",
|
|
58
59
|
"@bettercms-ai/ui": "^0.6.0",
|
|
59
|
-
"@bettercms-ai/richtext": "^0.
|
|
60
|
+
"@bettercms-ai/richtext": "^0.2.0",
|
|
61
|
+
"@bettercms-ai/next": "^0.11.2"
|
|
60
62
|
},
|
|
61
63
|
"peerDependencies": {
|
|
62
|
-
"astro": ">=4"
|
|
64
|
+
"astro": ">=4",
|
|
65
|
+
"@astrojs/preact": ">=4"
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
65
68
|
"@types/node": "^20",
|
|
66
69
|
"astro": "^5.0.0",
|
|
67
70
|
"tsup": "^8.5.1",
|
|
68
71
|
"typescript": "^5",
|
|
69
|
-
"vitest": "^4.1.4"
|
|
72
|
+
"vitest": "^4.1.4",
|
|
73
|
+
"@types/react": "^19.0.0"
|
|
70
74
|
},
|
|
71
75
|
"publishConfig": {
|
|
72
76
|
"registry": "https://registry.npmjs.org/",
|
|
73
77
|
"access": "public"
|
|
78
|
+
},
|
|
79
|
+
"peerDependenciesMeta": {
|
|
80
|
+
"@astrojs/preact": {
|
|
81
|
+
"optional": true
|
|
82
|
+
}
|
|
74
83
|
}
|
|
75
84
|
}
|