@styleflow.app/flowpress-astro-core 0.2.0-beta.2 → 0.2.0-beta.21
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/CHANGELOG.md +111 -0
- package/README.md +59 -1
- package/dist/astro/BaseLayout.astro +7 -1
- package/dist/astro/DefaultTemplate.astro +31 -21
- package/dist/astro/GutenbergRenderer.astro +151 -120
- package/dist/astro/blocks/ColumnBlock.astro +83 -0
- package/dist/astro/blocks/FormBlock.astro +233 -0
- package/dist/astro/blocks/GridBlock.astro +70 -0
- package/dist/astro/blocks/HeroBlock.astro +119 -0
- package/dist/astro/blocks/ListItemFallback.astro +28 -0
- package/dist/astro/blocks/NumberSpinnerBlock.astro +130 -0
- package/dist/astro/blocks/TextBlock.astro +83 -0
- package/dist/astro/blocks/helpers.d.ts +32 -0
- package/dist/astro/blocks/helpers.d.ts.map +1 -0
- package/dist/astro/blocks/helpers.js +152 -0
- package/dist/astro/blocks/helpers.js.map +1 -0
- package/dist/astro/blocks/helpers.ts +211 -0
- package/dist/block-renderers.d.ts +10 -0
- package/dist/block-renderers.d.ts.map +1 -0
- package/dist/block-renderers.js +2 -0
- package/dist/block-renderers.js.map +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +26 -1
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/number-spinner.d.ts +6 -0
- package/dist/number-spinner.d.ts.map +1 -0
- package/dist/number-spinner.js +136 -0
- package/dist/number-spinner.js.map +1 -0
- package/dist/style-classes.d.ts +9 -0
- package/dist/style-classes.d.ts.map +1 -0
- package/dist/style-classes.js +47 -0
- package/dist/style-classes.js.map +1 -0
- package/dist/styleflow.d.ts.map +1 -1
- package/dist/styleflow.js +7 -0
- package/dist/styleflow.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,117 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.2.0-beta.21
|
|
6
|
+
|
|
7
|
+
- Forced locale-aware thousands grouping for four-digit number spinner values,
|
|
8
|
+
matching the grouping already applied to larger values.
|
|
9
|
+
|
|
10
|
+
## 0.2.0-beta.20
|
|
11
|
+
|
|
12
|
+
- Added typed installable feature capabilities and normalized public JSON
|
|
13
|
+
configuration returned by FlowPress WordPress Core.
|
|
14
|
+
- Added deterministic CSP, consent and tag-manager head slots before the
|
|
15
|
+
existing project-owned `head` slot.
|
|
16
|
+
|
|
17
|
+
## 0.2.0-beta.19
|
|
18
|
+
|
|
19
|
+
- Let the number spinner's visual and accessible value spans inherit the
|
|
20
|
+
selected number typography instead of assigning the StyleFlow `body-md`
|
|
21
|
+
fallback to both technical descendants.
|
|
22
|
+
|
|
23
|
+
## 0.2.0-beta.18
|
|
24
|
+
|
|
25
|
+
- Updated the exact StyleFlow Astro dependency to `0.3.0-beta.6`, matching
|
|
26
|
+
the final StyleFlow release that includes the corrected importer and the
|
|
27
|
+
branded Figma plugin bundle.
|
|
28
|
+
|
|
29
|
+
## 0.2.0-beta.17
|
|
30
|
+
|
|
31
|
+
- Updated the exact StyleFlow Astro dependency to `0.3.0-beta.5`, keeping
|
|
32
|
+
consumers on one runtime aligned with the corrected Figma contract import
|
|
33
|
+
release.
|
|
34
|
+
|
|
35
|
+
## 0.2.0-beta.16
|
|
36
|
+
|
|
37
|
+
- Updated the exact StyleFlow Astro dependency to `0.3.0-beta.4` so consumers
|
|
38
|
+
use the responsive compiler contract and a single matching runtime.
|
|
39
|
+
|
|
40
|
+
## 0.2.0-beta.15
|
|
41
|
+
|
|
42
|
+
- Applied Hero image and video `object-position` from a sanitized pair of
|
|
43
|
+
percentage coordinates, with a safe centered fallback.
|
|
44
|
+
|
|
45
|
+
## 0.2.0-beta.14
|
|
46
|
+
|
|
47
|
+
- Added a recursive project block-renderer registry to
|
|
48
|
+
`GutenbergRenderer.astro`, including imported `sf/template` and resolved
|
|
49
|
+
query-item descendants.
|
|
50
|
+
|
|
51
|
+
## 0.2.0-beta.13
|
|
52
|
+
|
|
53
|
+
- Kept number spinners static on their final values when
|
|
54
|
+
`IntersectionObserver` or motion preference detection is unavailable,
|
|
55
|
+
rather than starting outside a verifiable viewport intersection.
|
|
56
|
+
|
|
57
|
+
## 0.2.0-beta.12
|
|
58
|
+
|
|
59
|
+
- Added the reusable `sf/number-spinner` Astro renderer with independently
|
|
60
|
+
styled prefix, number and suffix text segments.
|
|
61
|
+
- Started counting only on first viewport intersection, retained the final
|
|
62
|
+
target in no-JavaScript markup and disabled animation for reduced-motion
|
|
63
|
+
preferences, including preference changes during an active count.
|
|
64
|
+
- Kept the final numeric value permanently available to assistive technology
|
|
65
|
+
while visual frame updates remain hidden from accessibility APIs.
|
|
66
|
+
|
|
67
|
+
## 0.2.0-beta.11
|
|
68
|
+
|
|
69
|
+
- Rendered empty Gutenberg and FlowPress text blocks with an internal
|
|
70
|
+
` `, preserving their typographic line height without visible
|
|
71
|
+
characters or synthetic break elements.
|
|
72
|
+
|
|
73
|
+
## 0.2.0-beta.10
|
|
74
|
+
|
|
75
|
+
- Preserved intentionally empty core Gutenberg paragraphs as visible line
|
|
76
|
+
breaks, including paragraphs resolved through FlowPress templates.
|
|
77
|
+
- Exported safe recursive collection of CMS-authored block class names for
|
|
78
|
+
Tailwind `@source inline()` generation.
|
|
79
|
+
|
|
80
|
+
## 0.2.0-beta.9
|
|
81
|
+
|
|
82
|
+
- Preserved repeated Gutenberg RichText spacing across `<br>` sequences,
|
|
83
|
+
legacy empty paragraphs and literal double/triple newlines.
|
|
84
|
+
|
|
85
|
+
## 0.2.0-beta.8
|
|
86
|
+
|
|
87
|
+
- Applied Gutenberg `anchor` and `className` attributes to each rendered
|
|
88
|
+
block root, merging custom classes with the required FlowPress renderer
|
|
89
|
+
classes and preserving transparent template blocks when neither is set.
|
|
90
|
+
|
|
91
|
+
## 0.2.0-beta.5
|
|
92
|
+
|
|
93
|
+
- Split Gutenberg rendering into dedicated hero, responsive layout, text,
|
|
94
|
+
list/template and CF7 modules.
|
|
95
|
+
- Added semantic foreground/modifier propagation and core text block
|
|
96
|
+
rendering.
|
|
97
|
+
- Added responsive 12-column inheritance, token-based partial containers,
|
|
98
|
+
hero media/scrim rendering and reduced-motion handling.
|
|
99
|
+
- Added repeated query-item template rendering with the previous plain-list
|
|
100
|
+
fallback.
|
|
101
|
+
- Added an accessible Turnstile/CF7 browser form compatible with static and
|
|
102
|
+
server builds.
|
|
103
|
+
- Added Astro component checking to the release gate.
|
|
104
|
+
|
|
105
|
+
## 0.2.0-beta.4
|
|
106
|
+
|
|
107
|
+
- Updated the exact StyleFlow Astro dependency to `0.3.0-beta.2`.
|
|
108
|
+
- Validated the npm Trusted Publisher path with a new OIDC-only publication.
|
|
109
|
+
|
|
110
|
+
## 0.2.0-beta.3
|
|
111
|
+
|
|
112
|
+
- Updated the exact StyleFlow Astro dependency to `0.3.0-beta.1`.
|
|
113
|
+
- Made the optional PHP parity test compatible with standalone CI checkouts;
|
|
114
|
+
the TypeScript hierarchy tests remain mandatory.
|
|
115
|
+
|
|
5
116
|
## 0.2.0-beta.2
|
|
6
117
|
|
|
7
118
|
- Made Gutenberg color axes inherit by omission until authors explicitly set
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ The package must not import from an application or project plugin.
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
pnpm add @styleflow.app/flowpress-astro-core@0.2.0-beta.
|
|
12
|
+
pnpm add @styleflow.app/flowpress-astro-core@0.2.0-beta.19
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Prereleases are pinned exactly. The package expects Astro 7 or newer and the
|
|
@@ -30,6 +30,57 @@ For local Cloudflare development, prefer an HTTP loopback endpoint dedicated
|
|
|
30
30
|
to server-to-server traffic. Keep the public HTTPS backend URL separate for
|
|
31
31
|
canonical URL rewriting.
|
|
32
32
|
|
|
33
|
+
`GutenbergRenderer.astro` renders the responsive hero/grid/column contract,
|
|
34
|
+
StyleFlow text axes and resolved content/query templates. CF7 schemas
|
|
35
|
+
serialized by WordPress become accessible client forms that submit directly
|
|
36
|
+
to the protected FlowPress REST endpoint, so the same component works in
|
|
37
|
+
static and server output modes. Gutenberg `anchor` and `className` attributes
|
|
38
|
+
are applied to the rendered block root as HTML `id` and `class`. Rich Text
|
|
39
|
+
preserves intentional double, triple and longer line breaks, including content
|
|
40
|
+
saved by older editor versions as empty paragraphs. Empty textual blocks render
|
|
41
|
+
an internal ` `, preserving their typographic line height without adding
|
|
42
|
+
visible characters. The exported
|
|
43
|
+
`collectFlowpressClassNames()` helper recursively extracts safe class tokens
|
|
44
|
+
from rendered CMS blocks so consumers can generate Tailwind
|
|
45
|
+
`@source inline()` directives before compiling their frontend CSS.
|
|
46
|
+
|
|
47
|
+
Hero image and video backgrounds apply the catalog `objectPosition` value as
|
|
48
|
+
two percentages (for example `77% 100%`). Invalid or missing CMS values safely
|
|
49
|
+
fall back to `50% 50%`.
|
|
50
|
+
|
|
51
|
+
Projects can add renderers for project-owned Gutenberg blocks without copying
|
|
52
|
+
or patching the core renderer. Pass a `FlowpressBlockRenderers` map keyed by the
|
|
53
|
+
full block name; the registry is propagated through every recursive rendering
|
|
54
|
+
path, including imported `sf/template` content and resolved query-item
|
|
55
|
+
templates.
|
|
56
|
+
|
|
57
|
+
```astro
|
|
58
|
+
---
|
|
59
|
+
import GutenbergRenderer from "@styleflow.app/flowpress-astro-core/GutenbergRenderer.astro";
|
|
60
|
+
import type {
|
|
61
|
+
FlowpressBlockRenderers
|
|
62
|
+
} from "@styleflow.app/flowpress-astro-core";
|
|
63
|
+
import ProjectTimelineBlock from "./ProjectTimelineBlock.astro";
|
|
64
|
+
|
|
65
|
+
const blockRenderers = {
|
|
66
|
+
"sf/timeline": ProjectTimelineBlock
|
|
67
|
+
} satisfies FlowpressBlockRenderers;
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
<GutenbergRenderer blocks={blocks} blockRenderers={blockRenderers} />
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Each custom renderer receives the original `block` and optional StyleFlow
|
|
74
|
+
`contract`. Its default slot contains recursively rendered child blocks, so a
|
|
75
|
+
container override can place `<slot />` where its children belong.
|
|
76
|
+
|
|
77
|
+
`sf/number-spinner` renders prefix, target number and suffix with independent
|
|
78
|
+
semantic tags and StyleFlow text coordinates. Its numeric value counts from
|
|
79
|
+
zero only when it enters the viewport. The final target remains available to
|
|
80
|
+
assistive technology and without JavaScript; `prefers-reduced-motion: reduce`
|
|
81
|
+
skips the animation entirely. Browsers without viewport observation keep the
|
|
82
|
+
server-rendered final value instead of guessing when to start.
|
|
83
|
+
|
|
33
84
|
## Release
|
|
34
85
|
|
|
35
86
|
```bash
|
|
@@ -45,3 +96,10 @@ release and in CI.
|
|
|
45
96
|
The first publish requires npm organization access and 2FA. Subsequent
|
|
46
97
|
publishes use `.github/workflows/publish.yml` with npm trusted publishing
|
|
47
98
|
(OIDC); no long-lived publish token belongs in this repository.
|
|
99
|
+
|
|
100
|
+
The TypeScript template-hierarchy suite is self-contained. Its additional PHP
|
|
101
|
+
parity test runs when the sibling `flowpress-wordpress-core` checkout is
|
|
102
|
+
available locally and is skipped in a standalone package checkout.
|
|
103
|
+
|
|
104
|
+
Release activity reports are indexed in
|
|
105
|
+
[`docs/activities/README.md`](docs/activities/README.md).
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { SfSeo } from "../types.js";
|
|
3
|
+
import S from "@styleflow.app/astro/S.astro";
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
lang?: string;
|
|
@@ -41,9 +42,14 @@ const jsonLd = seo?.jsonLd ? JSON.stringify(seo.jsonLd) : null;
|
|
|
41
42
|
{seo?.twitter?.image?.url && <meta name="twitter:image" content={seo.twitter.image.url} />}
|
|
42
43
|
{seo?.twitter?.image?.alt && <meta name="twitter:image:alt" content={seo.twitter.image.alt} />}
|
|
43
44
|
{jsonLd && <script type="application/ld+json" set:html={jsonLd} />}
|
|
45
|
+
<slot name="head-csp" />
|
|
46
|
+
<slot name="head-consent" />
|
|
47
|
+
<slot name="head-tag-manager" />
|
|
44
48
|
<slot name="head" />
|
|
45
49
|
</head>
|
|
46
50
|
<body>
|
|
47
|
-
<
|
|
51
|
+
<S.main tone="neutral" intensity={1} surface="default" layoutRole="none" density="md">
|
|
52
|
+
<slot />
|
|
53
|
+
</S.main>
|
|
48
54
|
</body>
|
|
49
55
|
</html>
|
|
@@ -7,28 +7,38 @@ import type { FlowpressTemplateProps } from "../types.js";
|
|
|
7
7
|
const { route, content, styleflowContract } = Astro.props as FlowpressTemplateProps;
|
|
8
8
|
const title = content?.title || route.seo?.title || "Contenuto";
|
|
9
9
|
const isNotFound = route.queryType === "404" || route.status === 404;
|
|
10
|
+
const hasGutembergBlocks = Array.isArray(content?.contentBlocks) && content.contentBlocks.length > 0 ? true : false;
|
|
11
|
+
//TODO SET GLOBAL LOCAL ON ENV
|
|
10
12
|
---
|
|
11
13
|
|
|
12
14
|
<BaseLayout lang={route.locale || "it"} seo={route.seo}>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
|
|
16
|
+
{hasGutembergBlocks ? (
|
|
17
|
+
<GutenbergRenderer
|
|
18
|
+
blocks={content?.contentBlocks as import("../types.js").FlowpressBlock[]}
|
|
19
|
+
contract={styleflowContract}
|
|
20
|
+
/>
|
|
21
|
+
) : (
|
|
22
|
+
<S.section tone="neutral" intensity={1} surface="default" layoutRole="section" density="md">
|
|
23
|
+
<S.h1 ty="heading" v="1" w="strong">{isNotFound ? "Pagina non trovata" : title}</S.h1>
|
|
24
|
+
{content?.excerpt && <S.p ty="body" v="md" w="default">{content.excerpt}</S.p>}
|
|
25
|
+
{Array.isArray(content?.contentBlocks) && content.contentBlocks.length > 0 ? (
|
|
26
|
+
<GutenbergRenderer
|
|
27
|
+
blocks={content.contentBlocks as import("../types.js").FlowpressBlock[]}
|
|
28
|
+
contract={styleflowContract}
|
|
29
|
+
/>
|
|
30
|
+
) : content?.content && (
|
|
31
|
+
<S.div
|
|
32
|
+
tone="neutral"
|
|
33
|
+
intensity={1}
|
|
34
|
+
surface="default"
|
|
35
|
+
layoutRole="stack"
|
|
36
|
+
density="md"
|
|
37
|
+
set:html={String(content.content)}
|
|
38
|
+
/>
|
|
39
|
+
)}
|
|
40
|
+
</S.section>
|
|
41
|
+
)}
|
|
42
|
+
|
|
43
|
+
|
|
34
44
|
</BaseLayout>
|
|
@@ -1,68 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
import S from "@styleflow.app/astro/S.astro";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
type StyleflowContract
|
|
6
|
-
} from "../styleflow.js";
|
|
3
|
+
import type { FlowpressBlockRenderers } from "../block-renderers.js";
|
|
4
|
+
import type { StyleflowContract } from "../styleflow.js";
|
|
7
5
|
import type { FlowpressBlock } from "../types.js";
|
|
6
|
+
import ColumnBlock from "./blocks/ColumnBlock.astro";
|
|
7
|
+
import FormBlock from "./blocks/FormBlock.astro";
|
|
8
|
+
import GridBlock from "./blocks/GridBlock.astro";
|
|
9
|
+
import HeroBlock from "./blocks/HeroBlock.astro";
|
|
10
|
+
import ListItemFallback from "./blocks/ListItemFallback.astro";
|
|
11
|
+
import NumberSpinnerBlock from "./blocks/NumberSpinnerBlock.astro";
|
|
12
|
+
import TextBlock from "./blocks/TextBlock.astro";
|
|
13
|
+
import {
|
|
14
|
+
blockHtmlAttributes,
|
|
15
|
+
linkValue,
|
|
16
|
+
objectValue,
|
|
17
|
+
semanticProps,
|
|
18
|
+
textValue
|
|
19
|
+
} from "./blocks/helpers.js";
|
|
8
20
|
|
|
9
21
|
interface Props {
|
|
10
22
|
blocks: FlowpressBlock[];
|
|
11
23
|
contract?: StyleflowContract;
|
|
24
|
+
blockRenderers?: FlowpressBlockRenderers;
|
|
12
25
|
}
|
|
13
26
|
|
|
14
|
-
const { blocks, contract } = Astro.props;
|
|
15
|
-
|
|
16
|
-
const defaults = {
|
|
17
|
-
surface: "default",
|
|
18
|
-
layoutRole: "stack",
|
|
19
|
-
density: "md"
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function styleflowProps(attributes: Record<string, unknown>) {
|
|
23
|
-
if (!contract) return defaults;
|
|
24
|
-
return resolveDynamicStyleflowProps(attributes, defaults, contract);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function dynamicProps(
|
|
28
|
-
attributes: Record<string, unknown>,
|
|
29
|
-
fallback: Record<string, unknown>
|
|
30
|
-
) {
|
|
31
|
-
if (!contract) return fallback;
|
|
32
|
-
return resolveDynamicStyleflowProps(attributes, fallback, contract);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function text(block: FlowpressBlock, key = "text"): string {
|
|
36
|
-
return String(block.attributes[key] ?? "");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function objectValue(
|
|
40
|
-
block: FlowpressBlock,
|
|
41
|
-
key: string
|
|
42
|
-
): Record<string, unknown> {
|
|
43
|
-
const value = block.attributes[key];
|
|
44
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
45
|
-
? value as Record<string, unknown>
|
|
46
|
-
: {};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function linkValue(block: FlowpressBlock, key = "link"): string {
|
|
50
|
-
const value = block.attributes[key];
|
|
51
|
-
const href = typeof value === "string"
|
|
52
|
-
? value
|
|
53
|
-
: String(objectValue(block, key).url ?? "");
|
|
54
|
-
if (/^(?:\/(?!\/)|#|https?:\/\/|mailto:|tel:)/i.test(href)) {
|
|
55
|
-
return href;
|
|
56
|
-
}
|
|
57
|
-
return "";
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function itemImage(item: Record<string, unknown>): Record<string, unknown> {
|
|
61
|
-
const value = item.image;
|
|
62
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
63
|
-
? value as Record<string, unknown>
|
|
64
|
-
: {};
|
|
65
|
-
}
|
|
27
|
+
const { blocks, contract, blockRenderers = {} } = Astro.props;
|
|
66
28
|
|
|
67
29
|
function youtubeEmbedUrl(value: unknown): string | null {
|
|
68
30
|
try {
|
|
@@ -85,52 +47,97 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
85
47
|
{blocks.map((block) => {
|
|
86
48
|
const name = block.name.replace(/^sf\//, "");
|
|
87
49
|
const children = block.innerBlocks ?? [];
|
|
88
|
-
const semantic =
|
|
50
|
+
const semantic = semanticProps(block.attributes, contract);
|
|
51
|
+
const htmlAttributes = blockHtmlAttributes(block.attributes);
|
|
52
|
+
const CustomBlockRenderer = blockRenderers[block.name];
|
|
89
53
|
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
{ ty: "heading", v: String(level), w: "strong" }
|
|
54
|
+
if (CustomBlockRenderer) {
|
|
55
|
+
return (
|
|
56
|
+
<CustomBlockRenderer block={block} contract={contract}>
|
|
57
|
+
<Astro.self
|
|
58
|
+
blocks={children}
|
|
59
|
+
contract={contract}
|
|
60
|
+
blockRenderers={blockRenderers}
|
|
61
|
+
/>
|
|
62
|
+
</CustomBlockRenderer>
|
|
100
63
|
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (name === "hero") {
|
|
101
67
|
return (
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
68
|
+
<HeroBlock block={block} contract={contract}>
|
|
69
|
+
<Astro.self
|
|
70
|
+
blocks={children}
|
|
71
|
+
contract={contract}
|
|
72
|
+
blockRenderers={blockRenderers}
|
|
73
|
+
/>
|
|
74
|
+
</HeroBlock>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (name === "grid") {
|
|
79
|
+
return (
|
|
80
|
+
<GridBlock block={block} contract={contract}>
|
|
81
|
+
<Astro.self
|
|
82
|
+
blocks={children}
|
|
83
|
+
contract={contract}
|
|
84
|
+
blockRenderers={blockRenderers}
|
|
85
|
+
/>
|
|
86
|
+
</GridBlock>
|
|
108
87
|
);
|
|
109
88
|
}
|
|
110
89
|
|
|
111
|
-
if (name === "
|
|
112
|
-
|
|
113
|
-
|
|
90
|
+
if (name === "column") {
|
|
91
|
+
return (
|
|
92
|
+
<ColumnBlock block={block} contract={contract}>
|
|
93
|
+
<Astro.self
|
|
94
|
+
blocks={children}
|
|
95
|
+
contract={contract}
|
|
96
|
+
blockRenderers={blockRenderers}
|
|
97
|
+
/>
|
|
98
|
+
</ColumnBlock>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (name === "number-spinner") {
|
|
103
|
+
return <NumberSpinnerBlock block={block} contract={contract} />;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if ([
|
|
107
|
+
"heading",
|
|
108
|
+
"rich-text",
|
|
109
|
+
"quote",
|
|
110
|
+
"core/paragraph",
|
|
111
|
+
"core/heading",
|
|
112
|
+
"core/list",
|
|
113
|
+
"core/list-item",
|
|
114
|
+
"core/quote"
|
|
115
|
+
].includes(name)) {
|
|
116
|
+
return (
|
|
117
|
+
<TextBlock block={block} contract={contract} hasChildren={children.length > 0}>
|
|
118
|
+
<Astro.self
|
|
119
|
+
blocks={children}
|
|
120
|
+
contract={contract}
|
|
121
|
+
blockRenderers={blockRenderers}
|
|
122
|
+
/>
|
|
123
|
+
</TextBlock>
|
|
124
|
+
);
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
if (name === "button") {
|
|
117
128
|
const href = linkValue(block, "href") || "#";
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
interactivePriority: String(
|
|
121
|
-
block.attributes.interactivePriority ?? "primary"
|
|
122
|
-
)
|
|
123
|
-
},
|
|
124
|
-
{ interactivePriority: "primary" }
|
|
125
|
-
);
|
|
129
|
+
const link = objectValue(block, "href");
|
|
130
|
+
const opensInNewTab = Boolean(link.opensInNewTab);
|
|
126
131
|
return (
|
|
127
132
|
<S
|
|
128
133
|
as="a"
|
|
129
134
|
href={href}
|
|
135
|
+
target={opensInNewTab ? "_blank" : undefined}
|
|
136
|
+
rel={opensInNewTab ? "noopener noreferrer" : undefined}
|
|
130
137
|
{...semantic}
|
|
131
|
-
{...
|
|
138
|
+
{...htmlAttributes}
|
|
132
139
|
>
|
|
133
|
-
{
|
|
140
|
+
{textValue(block, "label")}
|
|
134
141
|
</S>
|
|
135
142
|
);
|
|
136
143
|
}
|
|
@@ -144,7 +151,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
144
151
|
} | undefined;
|
|
145
152
|
const src = image?.url ?? image?.sourceUrl;
|
|
146
153
|
return src ? (
|
|
147
|
-
<S as="div" {...semantic}>
|
|
154
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
148
155
|
<img
|
|
149
156
|
src={src}
|
|
150
157
|
alt={String(block.attributes.alt ?? image?.alt ?? image?.altText ?? "")}
|
|
@@ -160,7 +167,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
160
167
|
? block.attributes.images as Array<Record<string, unknown>>
|
|
161
168
|
: [];
|
|
162
169
|
return (
|
|
163
|
-
<S as="div" {...semantic}>
|
|
170
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
164
171
|
{images.map((image) => image.url ? (
|
|
165
172
|
<img
|
|
166
173
|
src={String(image.url)}
|
|
@@ -177,7 +184,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
177
184
|
const video = objectValue(block, "video");
|
|
178
185
|
const poster = objectValue(block, "poster");
|
|
179
186
|
return video.url ? (
|
|
180
|
-
<S as="div" {...semantic}>
|
|
187
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
181
188
|
<video
|
|
182
189
|
src={String(video.url)}
|
|
183
190
|
poster={poster.url ? String(poster.url) : undefined}
|
|
@@ -193,7 +200,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
193
200
|
if (name === "video-youtube") {
|
|
194
201
|
const embed = youtubeEmbedUrl(block.attributes.url);
|
|
195
202
|
return embed ? (
|
|
196
|
-
<S as="div" {...semantic}>
|
|
203
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
197
204
|
<iframe
|
|
198
205
|
src={embed}
|
|
199
206
|
title={String(block.attributes.title ?? "YouTube video")}
|
|
@@ -205,24 +212,19 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
205
212
|
) : null;
|
|
206
213
|
}
|
|
207
214
|
|
|
208
|
-
if (name === "
|
|
215
|
+
if (name === "chip") {
|
|
209
216
|
return (
|
|
210
|
-
<S as="
|
|
211
|
-
|
|
212
|
-
{block.attributes.citation && <cite>{String(block.attributes.citation)}</cite>}
|
|
217
|
+
<S as="span" {...semantic} {...htmlAttributes}>
|
|
218
|
+
{textValue(block, "label")}
|
|
213
219
|
</S>
|
|
214
220
|
);
|
|
215
221
|
}
|
|
216
222
|
|
|
217
|
-
if (name === "chip") {
|
|
218
|
-
return <S as="span" {...semantic}>{text(block, "label")}</S>;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
223
|
if (name === "card") {
|
|
222
224
|
const media = objectValue(block, "image");
|
|
223
225
|
const href = linkValue(block);
|
|
224
226
|
return (
|
|
225
|
-
<S as="article" {...semantic}>
|
|
227
|
+
<S as="article" {...semantic} {...htmlAttributes}>
|
|
226
228
|
{media.url && (
|
|
227
229
|
<img src={String(media.url)} alt={String(media.alt ?? "")} loading="lazy" />
|
|
228
230
|
)}
|
|
@@ -237,37 +239,60 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
237
239
|
const items = Array.isArray(block.attributes.resolvedItems)
|
|
238
240
|
? block.attributes.resolvedItems as Array<Record<string, unknown>>
|
|
239
241
|
: [];
|
|
242
|
+
const resolvedBlocks = Array.isArray(block.attributes.resolvedBlocks)
|
|
243
|
+
? block.attributes.resolvedBlocks as FlowpressBlock[][]
|
|
244
|
+
: [];
|
|
240
245
|
return (
|
|
241
|
-
<S as="ul" {...semantic}>
|
|
242
|
-
{items.map((item) => (
|
|
246
|
+
<S as="ul" {...semantic} {...htmlAttributes}>
|
|
247
|
+
{items.map((item, index) => (
|
|
243
248
|
<S as="li">
|
|
244
|
-
{
|
|
245
|
-
<
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
decoding="async"
|
|
249
|
+
{resolvedBlocks[index]?.length ? (
|
|
250
|
+
<Astro.self
|
|
251
|
+
blocks={resolvedBlocks[index]}
|
|
252
|
+
contract={contract}
|
|
253
|
+
blockRenderers={blockRenderers}
|
|
250
254
|
/>
|
|
251
|
-
)}
|
|
252
|
-
{item.uri ? (
|
|
253
|
-
<S as="a" href={String(item.uri)}>{String(item.title ?? "")}</S>
|
|
254
255
|
) : (
|
|
255
|
-
<
|
|
256
|
+
<ListItemFallback item={item} />
|
|
256
257
|
)}
|
|
257
|
-
{item.excerpt && <S as="p">{String(item.excerpt)}</S>}
|
|
258
|
-
{item.priceHtml && <S as="div" set:html={String(item.priceHtml)} />}
|
|
259
258
|
</S>
|
|
260
259
|
))}
|
|
261
260
|
</S>
|
|
262
261
|
);
|
|
263
262
|
}
|
|
264
263
|
|
|
264
|
+
if (name === "template") {
|
|
265
|
+
return Object.keys(htmlAttributes).length > 0 ? (
|
|
266
|
+
<div {...htmlAttributes}>
|
|
267
|
+
<Astro.self
|
|
268
|
+
blocks={children}
|
|
269
|
+
contract={contract}
|
|
270
|
+
blockRenderers={blockRenderers}
|
|
271
|
+
/>
|
|
272
|
+
</div>
|
|
273
|
+
) : (
|
|
274
|
+
<Astro.self
|
|
275
|
+
blocks={children}
|
|
276
|
+
contract={contract}
|
|
277
|
+
blockRenderers={blockRenderers}
|
|
278
|
+
/>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (name === "form") {
|
|
283
|
+
return <FormBlock block={block} contract={contract} />;
|
|
284
|
+
}
|
|
285
|
+
|
|
265
286
|
if (name === "accordion-item") {
|
|
266
287
|
return (
|
|
267
|
-
<S as="div" {...semantic}>
|
|
288
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
268
289
|
<details>
|
|
269
290
|
<summary>{String(block.attributes.title ?? "")}</summary>
|
|
270
|
-
<Astro.self
|
|
291
|
+
<Astro.self
|
|
292
|
+
blocks={children}
|
|
293
|
+
contract={contract}
|
|
294
|
+
blockRenderers={blockRenderers}
|
|
295
|
+
/>
|
|
271
296
|
</details>
|
|
272
297
|
</S>
|
|
273
298
|
);
|
|
@@ -290,7 +315,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
290
315
|
+ `?key=${encodeURIComponent(googleMapsApiKey)}`
|
|
291
316
|
+ `&q=${encodeURIComponent(query)}`;
|
|
292
317
|
return (
|
|
293
|
-
<S as="div" {...semantic}>
|
|
318
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
294
319
|
<iframe
|
|
295
320
|
src={source}
|
|
296
321
|
title={address || "Map"}
|
|
@@ -301,7 +326,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
301
326
|
);
|
|
302
327
|
}
|
|
303
328
|
return query ? (
|
|
304
|
-
<S as="div" {...semantic}>
|
|
329
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
305
330
|
<S
|
|
306
331
|
as="a"
|
|
307
332
|
href={`https://www.openstreetmap.org/search?query=${encodeURIComponent(query)}`}
|
|
@@ -313,12 +338,18 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
313
338
|
) : null;
|
|
314
339
|
}
|
|
315
340
|
|
|
316
|
-
const layoutTag =
|
|
341
|
+
const layoutTag = name === "section" ? "section" : "div";
|
|
317
342
|
return (
|
|
318
|
-
<S as={layoutTag} {...semantic}>
|
|
343
|
+
<S as={layoutTag} {...semantic} {...htmlAttributes}>
|
|
319
344
|
{block.innerHtml && children.length === 0
|
|
320
345
|
? <S as="div" set:html={block.innerHtml} />
|
|
321
|
-
:
|
|
346
|
+
: (
|
|
347
|
+
<Astro.self
|
|
348
|
+
blocks={children}
|
|
349
|
+
contract={contract}
|
|
350
|
+
blockRenderers={blockRenderers}
|
|
351
|
+
/>
|
|
352
|
+
)}
|
|
322
353
|
</S>
|
|
323
354
|
);
|
|
324
355
|
})}
|