@bettercms-ai/astro 0.4.0 → 0.5.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/components/BcmsBlocks.astro +65 -7
- package/package.json +3 -2
|
@@ -1,24 +1,51 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
|
-
* <BcmsBlocks> — renders a page's blockJson tree natively in Astro. Covers
|
|
4
|
-
*
|
|
5
|
-
* with `columns` recursing via Astro.self and `form`
|
|
6
|
-
*
|
|
3
|
+
* <BcmsBlocks> — renders a page's blockJson tree natively in Astro. Covers
|
|
4
|
+
* heading, text, image, button, spacer, video, columns, form and `component`,
|
|
5
|
+
* with `columns` and `component` recursing via Astro.self and `form`/`component`
|
|
6
|
+
* resolving from the `forms`/`components` props. Class names mirror the
|
|
7
|
+
* server-side renderer.
|
|
8
|
+
*
|
|
9
|
+
* `component` was previously absent, so every placed component instance hit
|
|
10
|
+
* `default: return null` — a silently blank section on Astro sites while the
|
|
11
|
+
* dashboard canvas and the Next adapter both rendered it. Resolution mirrors
|
|
12
|
+
* render-page.ts: the same shared `applyOverrides`, the same depth/cycle guard,
|
|
13
|
+
* the same fail-soft on a missing definition.
|
|
7
14
|
*/
|
|
8
15
|
import type { ContentBlock } from "@bettercms-ai/types";
|
|
9
|
-
import type { DeliveryForm } from "@bettercms-ai/sdk";
|
|
16
|
+
import type { DeliveryComponent, DeliveryForm } from "@bettercms-ai/sdk";
|
|
17
|
+
import { applyOverrides } from "@bettercms-ai/ui/resolve";
|
|
10
18
|
import BcmsImage from "./BcmsImage.astro";
|
|
11
19
|
import BcmsForm from "./BcmsForm.astro";
|
|
12
20
|
|
|
13
21
|
interface Props {
|
|
14
22
|
blocks: ContentBlock[];
|
|
15
23
|
forms?: DeliveryForm[];
|
|
24
|
+
/** Definitions for `component` blocks — pass `readComponents()` from @bettercms-ai/next
|
|
25
|
+
* or fetch `/delivery/:workspace/components`. Absent ⇒ instances render nothing. */
|
|
26
|
+
components?: DeliveryComponent[];
|
|
16
27
|
turnstileSiteKey?: string | null;
|
|
28
|
+
/** Recursion depth for nested components. Internal; do not pass. */
|
|
29
|
+
depth?: number;
|
|
30
|
+
/** Component ids already on this branch — cycle guard. Internal; do not pass. */
|
|
31
|
+
seen?: string[];
|
|
17
32
|
class?: string;
|
|
18
33
|
}
|
|
19
34
|
|
|
20
|
-
|
|
35
|
+
/** Matches render-page.ts and @bettercms-ai/next; a component tree deeper than this is a bug. */
|
|
36
|
+
const MAX_COMPONENT_DEPTH = 10;
|
|
37
|
+
|
|
38
|
+
const {
|
|
39
|
+
blocks = [],
|
|
40
|
+
forms = [],
|
|
41
|
+
components = [],
|
|
42
|
+
turnstileSiteKey,
|
|
43
|
+
depth = 0,
|
|
44
|
+
seen = [],
|
|
45
|
+
class: className,
|
|
46
|
+
} = Astro.props;
|
|
21
47
|
const formMap = new Map(forms.map((f) => [f.id, f]));
|
|
48
|
+
const componentMap = new Map(components.map((c) => [c.id, c]));
|
|
22
49
|
|
|
23
50
|
const clamp = (n: number, min: number, max: number) => Math.min(max, Math.max(min, n));
|
|
24
51
|
const anyProps = (b: ContentBlock) => (b as { props?: Record<string, any> }).props ?? {};
|
|
@@ -69,7 +96,14 @@ const anyProps = (b: ContentBlock) => (b as { props?: Record<string, any> }).pro
|
|
|
69
96
|
>
|
|
70
97
|
{cols.map((col) => (
|
|
71
98
|
<div class="bcms-col">
|
|
72
|
-
<Astro.self
|
|
99
|
+
<Astro.self
|
|
100
|
+
blocks={col}
|
|
101
|
+
forms={forms}
|
|
102
|
+
components={components}
|
|
103
|
+
turnstileSiteKey={turnstileSiteKey}
|
|
104
|
+
depth={depth}
|
|
105
|
+
seen={seen}
|
|
106
|
+
/>
|
|
73
107
|
</div>
|
|
74
108
|
))}
|
|
75
109
|
</div>
|
|
@@ -79,6 +113,30 @@ const anyProps = (b: ContentBlock) => (b as { props?: Record<string, any> }).pro
|
|
|
79
113
|
const form = formMap.get(p.formId);
|
|
80
114
|
return form ? <BcmsForm form={form} turnstileSiteKey={turnstileSiteKey} /> : null;
|
|
81
115
|
}
|
|
116
|
+
case "component": {
|
|
117
|
+
const def = componentMap.get(String(p.componentId ?? ""));
|
|
118
|
+
// Fail soft on a deleted/unknown component, exactly like the server renderer —
|
|
119
|
+
// a dangling reference must never break the build or the page.
|
|
120
|
+
if (!def) return null;
|
|
121
|
+
// A component's blockJson can embed other components, and nothing validates
|
|
122
|
+
// against a cycle at write time, so the guard has to live at render.
|
|
123
|
+
if (depth >= MAX_COMPONENT_DEPTH || seen.includes(def.id)) return null;
|
|
124
|
+
const resolved = applyOverrides<ContentBlock>(
|
|
125
|
+
def.blockJson,
|
|
126
|
+
def.props ?? [],
|
|
127
|
+
(p.overrides as Record<string, unknown>) ?? {},
|
|
128
|
+
);
|
|
129
|
+
return (
|
|
130
|
+
<Astro.self
|
|
131
|
+
blocks={resolved}
|
|
132
|
+
forms={forms}
|
|
133
|
+
components={components}
|
|
134
|
+
turnstileSiteKey={turnstileSiteKey}
|
|
135
|
+
depth={depth + 1}
|
|
136
|
+
seen={[...seen, def.id]}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
82
140
|
default:
|
|
83
141
|
return null;
|
|
84
142
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bettercms-ai/astro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
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",
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@bettercms-ai/image-url": "^0.1.0",
|
|
51
51
|
"@bettercms-ai/sdk": "^1.5.0",
|
|
52
|
-
"@bettercms-ai/types": "^1.4.0"
|
|
52
|
+
"@bettercms-ai/types": "^1.4.0",
|
|
53
|
+
"@bettercms-ai/ui": "^0.4.0"
|
|
53
54
|
},
|
|
54
55
|
"peerDependencies": {
|
|
55
56
|
"astro": ">=4"
|