@styleflow.app/flowpress-astro-core 0.2.0-beta.5 → 0.2.0-beta.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.
- package/CHANGELOG.md +6 -0
- package/README.md +3 -2
- package/dist/astro/BaseLayout.astro +4 -1
- package/dist/astro/DefaultTemplate.astro +31 -21
- package/dist/astro/GutenbergRenderer.astro +25 -12
- package/dist/astro/blocks/ColumnBlock.astro +7 -2
- package/dist/astro/blocks/FormBlock.astro +4 -3
- package/dist/astro/blocks/GridBlock.astro +7 -2
- package/dist/astro/blocks/HeroBlock.astro +7 -2
- package/dist/astro/blocks/TextBlock.astro +17 -6
- package/dist/astro/blocks/helpers.d.ts +4 -0
- package/dist/astro/blocks/helpers.d.ts.map +1 -1
- package/dist/astro/blocks/helpers.js +16 -0
- package/dist/astro/blocks/helpers.js.map +1 -1
- package/dist/astro/blocks/helpers.ts +21 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.2.0-beta.8
|
|
6
|
+
|
|
7
|
+
- Applied Gutenberg `anchor` and `className` attributes to each rendered
|
|
8
|
+
block root, merging custom classes with the required FlowPress renderer
|
|
9
|
+
classes and preserving transparent template blocks when neither is set.
|
|
10
|
+
|
|
5
11
|
## 0.2.0-beta.5
|
|
6
12
|
|
|
7
13
|
- Split Gutenberg rendering into dedicated hero, responsive layout, text,
|
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.8
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Prereleases are pinned exactly. The package expects Astro 7 or newer and the
|
|
@@ -34,7 +34,8 @@ canonical URL rewriting.
|
|
|
34
34
|
StyleFlow text axes and resolved content/query templates. CF7 schemas
|
|
35
35
|
serialized by WordPress become accessible client forms that submit directly
|
|
36
36
|
to the protected FlowPress REST endpoint, so the same component works in
|
|
37
|
-
static and server output modes.
|
|
37
|
+
static and server output modes. Gutenberg `anchor` and `className` attributes
|
|
38
|
+
are applied to the rendered block root as HTML `id` and `class`.
|
|
38
39
|
|
|
39
40
|
## Release
|
|
40
41
|
|
|
@@ -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;
|
|
@@ -44,6 +45,8 @@ const jsonLd = seo?.jsonLd ? JSON.stringify(seo.jsonLd) : null;
|
|
|
44
45
|
<slot name="head" />
|
|
45
46
|
</head>
|
|
46
47
|
<body>
|
|
47
|
-
<
|
|
48
|
+
<S.main tone="neutral" intensity={1} surface="default" layoutRole="none" density="md">
|
|
49
|
+
<slot />
|
|
50
|
+
</S.main>
|
|
48
51
|
</body>
|
|
49
52
|
</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>
|
|
@@ -9,6 +9,7 @@ import HeroBlock from "./blocks/HeroBlock.astro";
|
|
|
9
9
|
import ListItemFallback from "./blocks/ListItemFallback.astro";
|
|
10
10
|
import TextBlock from "./blocks/TextBlock.astro";
|
|
11
11
|
import {
|
|
12
|
+
blockHtmlAttributes,
|
|
12
13
|
linkValue,
|
|
13
14
|
objectValue,
|
|
14
15
|
semanticProps,
|
|
@@ -44,6 +45,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
44
45
|
const name = block.name.replace(/^sf\//, "");
|
|
45
46
|
const children = block.innerBlocks ?? [];
|
|
46
47
|
const semantic = semanticProps(block.attributes, contract);
|
|
48
|
+
const htmlAttributes = blockHtmlAttributes(block.attributes);
|
|
47
49
|
|
|
48
50
|
if (name === "hero") {
|
|
49
51
|
return (
|
|
@@ -97,6 +99,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
97
99
|
target={opensInNewTab ? "_blank" : undefined}
|
|
98
100
|
rel={opensInNewTab ? "noopener noreferrer" : undefined}
|
|
99
101
|
{...semantic}
|
|
102
|
+
{...htmlAttributes}
|
|
100
103
|
>
|
|
101
104
|
{textValue(block, "label")}
|
|
102
105
|
</S>
|
|
@@ -112,7 +115,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
112
115
|
} | undefined;
|
|
113
116
|
const src = image?.url ?? image?.sourceUrl;
|
|
114
117
|
return src ? (
|
|
115
|
-
<S as="div" {...semantic}>
|
|
118
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
116
119
|
<img
|
|
117
120
|
src={src}
|
|
118
121
|
alt={String(block.attributes.alt ?? image?.alt ?? image?.altText ?? "")}
|
|
@@ -128,7 +131,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
128
131
|
? block.attributes.images as Array<Record<string, unknown>>
|
|
129
132
|
: [];
|
|
130
133
|
return (
|
|
131
|
-
<S as="div" {...semantic}>
|
|
134
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
132
135
|
{images.map((image) => image.url ? (
|
|
133
136
|
<img
|
|
134
137
|
src={String(image.url)}
|
|
@@ -145,7 +148,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
145
148
|
const video = objectValue(block, "video");
|
|
146
149
|
const poster = objectValue(block, "poster");
|
|
147
150
|
return video.url ? (
|
|
148
|
-
<S as="div" {...semantic}>
|
|
151
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
149
152
|
<video
|
|
150
153
|
src={String(video.url)}
|
|
151
154
|
poster={poster.url ? String(poster.url) : undefined}
|
|
@@ -161,7 +164,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
161
164
|
if (name === "video-youtube") {
|
|
162
165
|
const embed = youtubeEmbedUrl(block.attributes.url);
|
|
163
166
|
return embed ? (
|
|
164
|
-
<S as="div" {...semantic}>
|
|
167
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
165
168
|
<iframe
|
|
166
169
|
src={embed}
|
|
167
170
|
title={String(block.attributes.title ?? "YouTube video")}
|
|
@@ -174,14 +177,18 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
174
177
|
}
|
|
175
178
|
|
|
176
179
|
if (name === "chip") {
|
|
177
|
-
return
|
|
180
|
+
return (
|
|
181
|
+
<S as="span" {...semantic} {...htmlAttributes}>
|
|
182
|
+
{textValue(block, "label")}
|
|
183
|
+
</S>
|
|
184
|
+
);
|
|
178
185
|
}
|
|
179
186
|
|
|
180
187
|
if (name === "card") {
|
|
181
188
|
const media = objectValue(block, "image");
|
|
182
189
|
const href = linkValue(block);
|
|
183
190
|
return (
|
|
184
|
-
<S as="article" {...semantic}>
|
|
191
|
+
<S as="article" {...semantic} {...htmlAttributes}>
|
|
185
192
|
{media.url && (
|
|
186
193
|
<img src={String(media.url)} alt={String(media.alt ?? "")} loading="lazy" />
|
|
187
194
|
)}
|
|
@@ -200,7 +207,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
200
207
|
? block.attributes.resolvedBlocks as FlowpressBlock[][]
|
|
201
208
|
: [];
|
|
202
209
|
return (
|
|
203
|
-
<S as="ul" {...semantic}>
|
|
210
|
+
<S as="ul" {...semantic} {...htmlAttributes}>
|
|
204
211
|
{items.map((item, index) => (
|
|
205
212
|
<S as="li">
|
|
206
213
|
{resolvedBlocks[index]?.length ? (
|
|
@@ -215,7 +222,13 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
215
222
|
}
|
|
216
223
|
|
|
217
224
|
if (name === "template") {
|
|
218
|
-
return
|
|
225
|
+
return Object.keys(htmlAttributes).length > 0 ? (
|
|
226
|
+
<div {...htmlAttributes}>
|
|
227
|
+
<Astro.self blocks={children} contract={contract} />
|
|
228
|
+
</div>
|
|
229
|
+
) : (
|
|
230
|
+
<Astro.self blocks={children} contract={contract} />
|
|
231
|
+
);
|
|
219
232
|
}
|
|
220
233
|
|
|
221
234
|
if (name === "form") {
|
|
@@ -224,7 +237,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
224
237
|
|
|
225
238
|
if (name === "accordion-item") {
|
|
226
239
|
return (
|
|
227
|
-
<S as="div" {...semantic}>
|
|
240
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
228
241
|
<details>
|
|
229
242
|
<summary>{String(block.attributes.title ?? "")}</summary>
|
|
230
243
|
<Astro.self blocks={children} contract={contract} />
|
|
@@ -250,7 +263,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
250
263
|
+ `?key=${encodeURIComponent(googleMapsApiKey)}`
|
|
251
264
|
+ `&q=${encodeURIComponent(query)}`;
|
|
252
265
|
return (
|
|
253
|
-
<S as="div" {...semantic}>
|
|
266
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
254
267
|
<iframe
|
|
255
268
|
src={source}
|
|
256
269
|
title={address || "Map"}
|
|
@@ -261,7 +274,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
261
274
|
);
|
|
262
275
|
}
|
|
263
276
|
return query ? (
|
|
264
|
-
<S as="div" {...semantic}>
|
|
277
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
265
278
|
<S
|
|
266
279
|
as="a"
|
|
267
280
|
href={`https://www.openstreetmap.org/search?query=${encodeURIComponent(query)}`}
|
|
@@ -275,7 +288,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
275
288
|
|
|
276
289
|
const layoutTag = name === "section" ? "section" : "div";
|
|
277
290
|
return (
|
|
278
|
-
<S as={layoutTag} {...semantic}>
|
|
291
|
+
<S as={layoutTag} {...semantic} {...htmlAttributes}>
|
|
279
292
|
{block.innerHtml && children.length === 0
|
|
280
293
|
? <S as="div" set:html={block.innerHtml} />
|
|
281
294
|
: <Astro.self blocks={children} contract={contract} />}
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
import S from "@styleflow.app/astro/S.astro";
|
|
3
3
|
import type { FlowpressBlock } from "../../types.js";
|
|
4
4
|
import type { StyleflowContract } from "../../styleflow.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
blockHtmlAttributes,
|
|
7
|
+
responsiveValues,
|
|
8
|
+
semanticProps
|
|
9
|
+
} from "./helpers.js";
|
|
6
10
|
|
|
7
11
|
interface Props {
|
|
8
12
|
block: FlowpressBlock;
|
|
@@ -18,6 +22,7 @@ const partialBreakpoint = ["base", "sm", "md", "lg", "xl", "2xl"].includes(
|
|
|
18
22
|
String(block.attributes.partialContainerBreakpoint)
|
|
19
23
|
) ? String(block.attributes.partialContainerBreakpoint) : "lg";
|
|
20
24
|
const semantic = semanticProps(block.attributes, contract);
|
|
25
|
+
const htmlAttributes = blockHtmlAttributes(block.attributes, "flowpress-column");
|
|
21
26
|
const style = [
|
|
22
27
|
`--flowpress-span-base:${values.base}`,
|
|
23
28
|
`--flowpress-span-sm:${values.sm}`,
|
|
@@ -31,7 +36,7 @@ const style = [
|
|
|
31
36
|
<S
|
|
32
37
|
as="div"
|
|
33
38
|
{...semantic}
|
|
34
|
-
|
|
39
|
+
{...htmlAttributes}
|
|
35
40
|
data-partial={partial}
|
|
36
41
|
data-partial-breakpoint={partialBreakpoint}
|
|
37
42
|
style={style}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import S from "@styleflow.app/astro/S.astro";
|
|
3
3
|
import type { FlowpressBlock } from "../../types.js";
|
|
4
4
|
import type { StyleflowContract } from "../../styleflow.js";
|
|
5
|
-
import { semanticProps } from "./helpers.js";
|
|
5
|
+
import { blockHtmlAttributes, semanticProps } from "./helpers.js";
|
|
6
6
|
|
|
7
7
|
interface FormField {
|
|
8
8
|
name: string;
|
|
@@ -30,6 +30,7 @@ interface Props {
|
|
|
30
30
|
const { block, contract } = Astro.props;
|
|
31
31
|
const schema = block.attributes.formSchema as FormSchema | undefined;
|
|
32
32
|
const semantic = semanticProps(block.attributes, contract);
|
|
33
|
+
const htmlAttributes = blockHtmlAttributes(block.attributes);
|
|
33
34
|
const labelFor = (field: FormField): string => field.name
|
|
34
35
|
.replace(/[-_]+/g, " ")
|
|
35
36
|
.replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
@@ -38,7 +39,7 @@ const optionLabel = (field: FormField, index: number): string =>
|
|
|
38
39
|
---
|
|
39
40
|
|
|
40
41
|
{schema?.available ? (
|
|
41
|
-
<S as="div" {...semantic}>
|
|
42
|
+
<S as="div" {...semantic} {...htmlAttributes}>
|
|
42
43
|
<flowpress-cf7-form>
|
|
43
44
|
<form action={schema.submitUrl} method="post" enctype="multipart/form-data" novalidate>
|
|
44
45
|
{block.attributes.title || schema.title ? (
|
|
@@ -131,7 +132,7 @@ const optionLabel = (field: FormField, index: number): string =>
|
|
|
131
132
|
</flowpress-cf7-form>
|
|
132
133
|
</S>
|
|
133
134
|
) : (
|
|
134
|
-
<S as="p" {...semantic} role="status">
|
|
135
|
+
<S as="p" {...semantic} {...htmlAttributes} role="status">
|
|
135
136
|
Il modulo non è temporaneamente disponibile.
|
|
136
137
|
</S>
|
|
137
138
|
)}
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
import S from "@styleflow.app/astro/S.astro";
|
|
3
3
|
import type { FlowpressBlock } from "../../types.js";
|
|
4
4
|
import type { StyleflowContract } from "../../styleflow.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
blockHtmlAttributes,
|
|
7
|
+
responsiveValues,
|
|
8
|
+
semanticProps
|
|
9
|
+
} from "./helpers.js";
|
|
6
10
|
|
|
7
11
|
interface Props {
|
|
8
12
|
block: FlowpressBlock;
|
|
@@ -23,6 +27,7 @@ const semantic = semanticProps(block.attributes, contract, {
|
|
|
23
27
|
layoutRole: "container",
|
|
24
28
|
density: "md"
|
|
25
29
|
});
|
|
30
|
+
const htmlAttributes = blockHtmlAttributes(block.attributes, "flowpress-grid");
|
|
26
31
|
const style = [
|
|
27
32
|
`--flowpress-grid-base:${values.base}`,
|
|
28
33
|
`--flowpress-grid-sm:${values.sm}`,
|
|
@@ -33,7 +38,7 @@ const style = [
|
|
|
33
38
|
].join(";");
|
|
34
39
|
---
|
|
35
40
|
|
|
36
|
-
<S as="div" {...semantic}
|
|
41
|
+
<S as="div" {...semantic} {...htmlAttributes} data-align={align} style={style}>
|
|
37
42
|
<slot />
|
|
38
43
|
</S>
|
|
39
44
|
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
import S from "@styleflow.app/astro/S.astro";
|
|
3
3
|
import type { FlowpressBlock } from "../../types.js";
|
|
4
4
|
import type { StyleflowContract } from "../../styleflow.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
blockHtmlAttributes,
|
|
7
|
+
objectValue,
|
|
8
|
+
semanticProps
|
|
9
|
+
} from "./helpers.js";
|
|
6
10
|
|
|
7
11
|
interface Props {
|
|
8
12
|
block: FlowpressBlock;
|
|
@@ -16,6 +20,7 @@ const semantic = semanticProps(attributes, contract, {
|
|
|
16
20
|
layoutRole: "region",
|
|
17
21
|
density: "md"
|
|
18
22
|
});
|
|
23
|
+
const htmlAttributes = blockHtmlAttributes(attributes, "flowpress-hero");
|
|
19
24
|
const backgroundType = ["color", "image", "video"].includes(
|
|
20
25
|
String(attributes.backgroundType)
|
|
21
26
|
) ? String(attributes.backgroundType) : "color";
|
|
@@ -30,7 +35,7 @@ const scrimIntensity = Math.min(10, Math.max(1, Number(attributes.scrimIntensity
|
|
|
30
35
|
<S
|
|
31
36
|
as="section"
|
|
32
37
|
{...semantic}
|
|
33
|
-
|
|
38
|
+
{...htmlAttributes}
|
|
34
39
|
style={`--flowpress-scrim-opacity:${scrimIntensity * 10}%`}
|
|
35
40
|
>
|
|
36
41
|
{backgroundType === "image" && imageSrc ? (
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
import S from "@styleflow.app/astro/S.astro";
|
|
3
3
|
import type { FlowpressBlock } from "../../types.js";
|
|
4
4
|
import type { StyleflowContract } from "../../styleflow.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
blockHtmlAttributes,
|
|
7
|
+
semanticProps,
|
|
8
|
+
textValue,
|
|
9
|
+
unwrapCoreHtml
|
|
10
|
+
} from "./helpers.js";
|
|
6
11
|
|
|
7
12
|
interface Props {
|
|
8
13
|
block: FlowpressBlock;
|
|
@@ -30,6 +35,7 @@ const defaults = heading
|
|
|
30
35
|
foreground: "primary"
|
|
31
36
|
};
|
|
32
37
|
const semantic = semanticProps(attributes, contract, defaults);
|
|
38
|
+
const htmlAttributes = blockHtmlAttributes(attributes);
|
|
33
39
|
const html = name === "heading"
|
|
34
40
|
? textValue(block)
|
|
35
41
|
: name === "rich-text"
|
|
@@ -41,21 +47,26 @@ const listTag = Boolean(attributes.ordered) ? "ol" : "ul";
|
|
|
41
47
|
---
|
|
42
48
|
|
|
43
49
|
{heading ? (
|
|
44
|
-
<S as={headingTag} {...semantic} set:html={html} />
|
|
50
|
+
<S as={headingTag} {...semantic} {...htmlAttributes} set:html={html} />
|
|
45
51
|
) : name === "core/list" ? (
|
|
46
|
-
<S as={listTag} {...semantic}>
|
|
52
|
+
<S as={listTag} {...semantic} {...htmlAttributes}>
|
|
47
53
|
{hasChildren ? <slot /> : <Fragment set:html={html} />}
|
|
48
54
|
</S>
|
|
49
55
|
) : name === "core/list-item" ? (
|
|
50
|
-
<S as="li" {...semantic}>
|
|
56
|
+
<S as="li" {...semantic} {...htmlAttributes}>
|
|
51
57
|
<span set:html={html}></span>
|
|
52
58
|
{hasChildren ? <slot /> : null}
|
|
53
59
|
</S>
|
|
54
60
|
) : name === "quote" || name === "core/quote" ? (
|
|
55
|
-
<S as="blockquote" {...semantic}>
|
|
61
|
+
<S as="blockquote" {...semantic} {...htmlAttributes}>
|
|
56
62
|
{hasChildren ? <slot /> : <div set:html={html}></div>}
|
|
57
63
|
{attributes.citation ? <cite>{String(attributes.citation)}</cite> : null}
|
|
58
64
|
</S>
|
|
59
65
|
) : (
|
|
60
|
-
<S
|
|
66
|
+
<S
|
|
67
|
+
as={name === "core/paragraph" ? "p" : "div"}
|
|
68
|
+
{...semantic}
|
|
69
|
+
{...htmlAttributes}
|
|
70
|
+
set:html={html}
|
|
71
|
+
/>
|
|
61
72
|
)}
|
|
@@ -5,6 +5,10 @@ export declare const DEFAULT_SEMANTIC_PROPS: {
|
|
|
5
5
|
layoutRole: string;
|
|
6
6
|
density: string;
|
|
7
7
|
};
|
|
8
|
+
export declare function blockHtmlAttributes(attributes: Record<string, unknown>, baseClass?: string): {
|
|
9
|
+
id?: string;
|
|
10
|
+
class?: string;
|
|
11
|
+
};
|
|
8
12
|
export declare function semanticProps(attributes: Record<string, unknown>, contract?: StyleflowContract, defaults?: Record<string, unknown>): Record<string, unknown>;
|
|
9
13
|
export declare function objectValue(block: FlowpressBlock, key: string): Record<string, unknown>;
|
|
10
14
|
export declare function textValue(block: FlowpressBlock, key?: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/astro/blocks/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,sBAAsB;;;;CAIlC,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/astro/blocks/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,eAAO,MAAM,sBAAsB;;;;CAIlC,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,SAAS,SAAK,GACb;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAgBjC;AAqBD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAA0B,GACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAErE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAMrE;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,MAAM,EAAE,SAAS,GAAG,MAAM,EAC1B,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE,MAAM,CAAC,CAe5D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD"}
|
|
@@ -4,6 +4,22 @@ export const DEFAULT_SEMANTIC_PROPS = {
|
|
|
4
4
|
layoutRole: "stack",
|
|
5
5
|
density: "md"
|
|
6
6
|
};
|
|
7
|
+
export function blockHtmlAttributes(attributes, baseClass = "") {
|
|
8
|
+
const anchor = typeof attributes.anchor === "string"
|
|
9
|
+
? attributes.anchor.trim()
|
|
10
|
+
: "";
|
|
11
|
+
const customClass = typeof attributes.className === "string"
|
|
12
|
+
? attributes.className.trim()
|
|
13
|
+
: "";
|
|
14
|
+
const className = [baseClass.trim(), customClass]
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.join(" ")
|
|
17
|
+
.replace(/\s+/g, " ");
|
|
18
|
+
return {
|
|
19
|
+
...(anchor ? { id: anchor } : {}),
|
|
20
|
+
...(className ? { class: className } : {})
|
|
21
|
+
};
|
|
22
|
+
}
|
|
7
23
|
const SEMANTIC_KEYS = [
|
|
8
24
|
"tone",
|
|
9
25
|
"intensity",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/astro/blocks/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAE7B,MAAM,oBAAoB,CAAC;AAG5B,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,OAAO,EAAE,SAAS;IAClB,UAAU,EAAE,OAAO;IACnB,OAAO,EAAE,IAAI;CACd,CAAC;AAEF,MAAM,aAAa,GAAG;IACpB,MAAM;IACN,WAAW;IACX,SAAS;IACT,YAAY;IACZ,SAAS;IACT,IAAI;IACJ,GAAG;IACH,GAAG;IACH,YAAY;IACZ,qBAAqB;IACrB,cAAc;IACd,UAAU;IACV,WAAW;IACX,OAAO;IACP,UAAU;IACV,cAAc;CACN,CAAC;AAEX,MAAM,UAAU,aAAa,CAC3B,UAAmC,EACnC,QAA4B,EAC5B,WAAoC,sBAAsB;IAE1D,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,aAAa;SACV,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;SAC9C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CACxC,CAAC;IACF,OAAO,QAAQ;QACb,CAAC,CAAC,4BAA4B,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC;QACzD,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,KAAqB,EACrB,GAAW;IAEX,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAChE,CAAC,CAAC,KAAgC;QAClC,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAqB,EAAE,GAAG,GAAG,MAAM;IAC3D,OAAO,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAqB,EAAE,GAAG,GAAG,MAAM;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ;QACpC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IAC9C,OAAO,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,UAAmC,EACnC,MAA0B,EAC1B,QAAgB;IAEhB,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAU,CAAC;IAC9D,MAAM,MAAM,GAAG,EAA2C,CAAC;IAC3D,IAAI,SAAS,GAAG,QAAQ,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,GAAG,KAAK,MAAM;YAC3B,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;QAC3D,IAAI,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;YACrE,SAAS,GAAG,SAAS,CAAC;QACxB,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAC7B,+DAA+D,CAChE,CAAC;IACF,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC","sourcesContent":["import {\n resolveDynamicStyleflowProps,\n type StyleflowContract\n} from \"../../styleflow.js\";\nimport type { FlowpressBlock } from \"../../types.js\";\n\nexport const DEFAULT_SEMANTIC_PROPS = {\n surface: \"default\",\n layoutRole: \"stack\",\n density: \"md\"\n};\n\nconst SEMANTIC_KEYS = [\n \"tone\",\n \"intensity\",\n \"surface\",\n \"layoutRole\",\n \"density\",\n \"ty\",\n \"v\",\n \"w\",\n \"foreground\",\n \"interactivePriority\",\n \"noBackground\",\n \"noBorder\",\n \"noPadding\",\n \"noGap\",\n \"noRadius\",\n \"noForeground\"\n] as const;\n\nexport function semanticProps(\n attributes: Record<string, unknown>,\n contract?: StyleflowContract,\n defaults: Record<string, unknown> = DEFAULT_SEMANTIC_PROPS\n): Record<string, unknown> {\n const input = Object.fromEntries(\n SEMANTIC_KEYS\n .filter((key) => attributes[key] !== undefined)\n .map((key) => [key, attributes[key]])\n );\n return contract\n ? resolveDynamicStyleflowProps(input, defaults, contract)\n : { ...defaults, ...input };\n}\n\nexport function objectValue(\n block: FlowpressBlock,\n key: string\n): Record<string, unknown> {\n const value = block.attributes[key];\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : {};\n}\n\nexport function textValue(block: FlowpressBlock, key = \"text\"): string {\n return String(block.attributes[key] ?? \"\");\n}\n\nexport function linkValue(block: FlowpressBlock, key = \"link\"): string {\n const value = block.attributes[key];\n const href = typeof value === \"string\"\n ? value\n : String(objectValue(block, key).url ?? \"\");\n return /^(?:\\/(?!\\/)|#|https?:\\/\\/|mailto:|tel:)/i.test(href) ? href : \"\";\n}\n\nexport function responsiveValues(\n attributes: Record<string, unknown>,\n prefix: \"columns\" | \"span\",\n fallback: number\n): Record<\"base\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\", number> {\n const keys = [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\"] as const;\n const result = {} as Record<(typeof keys)[number], number>;\n let inherited = fallback;\n for (const key of keys) {\n const suffix = key === \"base\"\n ? \"Base\"\n : key === \"2xl\" ? \"2xl\" : key.charAt(0).toUpperCase() + key.slice(1);\n const candidate = Number(attributes[`${prefix}${suffix}`]);\n if (Number.isInteger(candidate) && candidate >= 1 && candidate <= 12) {\n inherited = candidate;\n }\n result[key] = inherited;\n }\n return result;\n}\n\nexport function unwrapCoreHtml(html: string): string {\n const match = html.trim().match(\n /^<(p|h[1-6]|ul|ol|li|blockquote)(?:\\s[^>]*)?>([\\s\\S]*)<\\/\\1>$/\n );\n return match?.[2] ?? html;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/astro/blocks/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n resolveDynamicStyleflowProps,\n type StyleflowContract\n} from \"../../styleflow.js\";\nimport type { FlowpressBlock } from \"../../types.js\";\n\nexport const DEFAULT_SEMANTIC_PROPS = {\n surface: \"default\",\n layoutRole: \"stack\",\n density: \"md\"\n};\n\nexport function blockHtmlAttributes(\n attributes: Record<string, unknown>,\n baseClass = \"\"\n): { id?: string; class?: string } {\n const anchor = typeof attributes.anchor === \"string\"\n ? attributes.anchor.trim()\n : \"\";\n const customClass = typeof attributes.className === \"string\"\n ? attributes.className.trim()\n : \"\";\n const className = [baseClass.trim(), customClass]\n .filter(Boolean)\n .join(\" \")\n .replace(/\\s+/g, \" \");\n\n return {\n ...(anchor ? { id: anchor } : {}),\n ...(className ? { class: className } : {})\n };\n}\n\nconst SEMANTIC_KEYS = [\n \"tone\",\n \"intensity\",\n \"surface\",\n \"layoutRole\",\n \"density\",\n \"ty\",\n \"v\",\n \"w\",\n \"foreground\",\n \"interactivePriority\",\n \"noBackground\",\n \"noBorder\",\n \"noPadding\",\n \"noGap\",\n \"noRadius\",\n \"noForeground\"\n] as const;\n\nexport function semanticProps(\n attributes: Record<string, unknown>,\n contract?: StyleflowContract,\n defaults: Record<string, unknown> = DEFAULT_SEMANTIC_PROPS\n): Record<string, unknown> {\n const input = Object.fromEntries(\n SEMANTIC_KEYS\n .filter((key) => attributes[key] !== undefined)\n .map((key) => [key, attributes[key]])\n );\n return contract\n ? resolveDynamicStyleflowProps(input, defaults, contract)\n : { ...defaults, ...input };\n}\n\nexport function objectValue(\n block: FlowpressBlock,\n key: string\n): Record<string, unknown> {\n const value = block.attributes[key];\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value as Record<string, unknown>\n : {};\n}\n\nexport function textValue(block: FlowpressBlock, key = \"text\"): string {\n return String(block.attributes[key] ?? \"\");\n}\n\nexport function linkValue(block: FlowpressBlock, key = \"link\"): string {\n const value = block.attributes[key];\n const href = typeof value === \"string\"\n ? value\n : String(objectValue(block, key).url ?? \"\");\n return /^(?:\\/(?!\\/)|#|https?:\\/\\/|mailto:|tel:)/i.test(href) ? href : \"\";\n}\n\nexport function responsiveValues(\n attributes: Record<string, unknown>,\n prefix: \"columns\" | \"span\",\n fallback: number\n): Record<\"base\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\", number> {\n const keys = [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\"] as const;\n const result = {} as Record<(typeof keys)[number], number>;\n let inherited = fallback;\n for (const key of keys) {\n const suffix = key === \"base\"\n ? \"Base\"\n : key === \"2xl\" ? \"2xl\" : key.charAt(0).toUpperCase() + key.slice(1);\n const candidate = Number(attributes[`${prefix}${suffix}`]);\n if (Number.isInteger(candidate) && candidate >= 1 && candidate <= 12) {\n inherited = candidate;\n }\n result[key] = inherited;\n }\n return result;\n}\n\nexport function unwrapCoreHtml(html: string): string {\n const match = html.trim().match(\n /^<(p|h[1-6]|ul|ol|li|blockquote)(?:\\s[^>]*)?>([\\s\\S]*)<\\/\\1>$/\n );\n return match?.[2] ?? html;\n}\n"]}
|
|
@@ -10,6 +10,27 @@ export const DEFAULT_SEMANTIC_PROPS = {
|
|
|
10
10
|
density: "md"
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
export function blockHtmlAttributes(
|
|
14
|
+
attributes: Record<string, unknown>,
|
|
15
|
+
baseClass = ""
|
|
16
|
+
): { id?: string; class?: string } {
|
|
17
|
+
const anchor = typeof attributes.anchor === "string"
|
|
18
|
+
? attributes.anchor.trim()
|
|
19
|
+
: "";
|
|
20
|
+
const customClass = typeof attributes.className === "string"
|
|
21
|
+
? attributes.className.trim()
|
|
22
|
+
: "";
|
|
23
|
+
const className = [baseClass.trim(), customClass]
|
|
24
|
+
.filter(Boolean)
|
|
25
|
+
.join(" ")
|
|
26
|
+
.replace(/\s+/g, " ");
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
...(anchor ? { id: anchor } : {}),
|
|
30
|
+
...(className ? { class: className } : {})
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
13
34
|
const SEMANTIC_KEYS = [
|
|
14
35
|
"tone",
|
|
15
36
|
"intensity",
|
package/package.json
CHANGED