@styleflow.app/flowpress-astro-core 0.2.0-beta.21 → 0.2.0-beta.23
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 +18 -0
- package/README.md +32 -1
- package/dist/astro/GutenbergRenderer.astro +66 -20
- package/dist/astro/blocks/ImageBlock.astro +90 -0
- package/dist/astro/blocks/TextBlock.astro +7 -4
- package/dist/astro/blocks/helpers.d.ts +2 -0
- package/dist/astro/blocks/helpers.d.ts.map +1 -1
- package/dist/astro/blocks/helpers.js +32 -3
- package/dist/astro/blocks/helpers.js.map +1 -1
- package/dist/astro/blocks/helpers.ts +37 -3
- package/dist/block-renderers.d.ts +12 -0
- package/dist/block-renderers.d.ts.map +1 -1
- package/dist/block-renderers.js.map +1 -1
- package/dist/style-classes.d.ts.map +1 -1
- package/dist/style-classes.js +4 -2
- package/dist/style-classes.js.map +1 -1
- package/dist/styleflow.js +1 -1
- package/dist/styleflow.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.2.0-beta.23
|
|
6
|
+
|
|
7
|
+
- Added validated Gutenberg text alignment for FlowPress and core text blocks.
|
|
8
|
+
- Added a typed project icon renderer, recursive propagation, standalone icon
|
|
9
|
+
blocks and ordered button icons with the StyleFlow `control` layout role.
|
|
10
|
+
- Treated `foreground=inherit` as omission, matching inherited tone and
|
|
11
|
+
intensity behavior.
|
|
12
|
+
- Rendered trusted `sf/code` documents in the main DOM only when WordPress
|
|
13
|
+
serialization supplies `codeApproved=true`; unapproved documents fail closed.
|
|
14
|
+
|
|
15
|
+
## 0.2.0-beta.22
|
|
16
|
+
|
|
17
|
+
- Added a dedicated `sf/image` renderer with WordPress responsive `srcset`,
|
|
18
|
+
authored or attachment-default `sizes`, intrinsic dimensions, per-image CSS
|
|
19
|
+
classes and validated loading, decoding and fetch-priority controls.
|
|
20
|
+
- Included per-image CSS classes in the recursive CMS class collector used by
|
|
21
|
+
consumer Tailwind safelists.
|
|
22
|
+
|
|
5
23
|
## 0.2.0-beta.21
|
|
6
24
|
|
|
7
25
|
- Forced locale-aware thousands grouping for four-digit number spinner values,
|
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.23
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Prereleases are pinned exactly. The package expects Astro 7 or newer and the
|
|
@@ -44,10 +44,22 @@ visible characters. The exported
|
|
|
44
44
|
from rendered CMS blocks so consumers can generate Tailwind
|
|
45
45
|
`@source inline()` directives before compiling their frontend CSS.
|
|
46
46
|
|
|
47
|
+
Heading, rich-text, quote and matching core blocks accept Gutenberg alignment
|
|
48
|
+
from either `style.typography.textAlign` or the FlowPress `textAlign` field.
|
|
49
|
+
Only `left`, `center`, `right`, `justify`, `start` and `end` reach CSS.
|
|
50
|
+
`foreground=inherit` is omitted so icons and text inherit the surrounding
|
|
51
|
+
foreground instead of serializing an invalid StyleFlow role.
|
|
52
|
+
|
|
47
53
|
Hero image and video backgrounds apply the catalog `objectPosition` value as
|
|
48
54
|
two percentages (for example `77% 100%`). Invalid or missing CMS values safely
|
|
49
55
|
fall back to `50% 50%`.
|
|
50
56
|
|
|
57
|
+
`sf/image` renders the responsive attachment data serialized by WordPress as a
|
|
58
|
+
single `<img>` with `srcset`, `sizes` and positive intrinsic dimensions. The
|
|
59
|
+
block-root `className` remains on its StyleFlow wrapper while `imageClassName`
|
|
60
|
+
targets the image. Loading defaults to `lazy`, decoding to `async` and fetch
|
|
61
|
+
priority to `auto`; invalid stored values fail closed to those defaults.
|
|
62
|
+
|
|
51
63
|
Projects can add renderers for project-owned Gutenberg blocks without copying
|
|
52
64
|
or patching the core renderer. Pass a `FlowpressBlockRenderers` map keyed by the
|
|
53
65
|
full block name; the registry is propagated through every recursive rendering
|
|
@@ -74,6 +86,25 @@ Each custom renderer receives the original `block` and optional StyleFlow
|
|
|
74
86
|
`contract`. Its default slot contains recursively rendered child blocks, so a
|
|
75
87
|
container override can place `<slot />` where its children belong.
|
|
76
88
|
|
|
89
|
+
Projects provide their SVG implementation through the typed `iconRenderer`
|
|
90
|
+
prop. It is used by `sf/icon`, propagated through all recursive paths and used
|
|
91
|
+
for optional button icons in `before` or `after` position.
|
|
92
|
+
|
|
93
|
+
```astro
|
|
94
|
+
---
|
|
95
|
+
import GutenbergRenderer from "@styleflow.app/flowpress-astro-core/GutenbergRenderer.astro";
|
|
96
|
+
import ProjectIcon from "@sf/ui/Icon.astro";
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
<GutenbergRenderer blocks={blocks} iconRenderer={ProjectIcon} />
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`sf/code` is deliberately a trusted-code boundary, not a sandbox. The renderer
|
|
103
|
+
emits its complete HTML fragment (including style, script, iframe and embed
|
|
104
|
+
elements) in the main document only when the serialized block contains the
|
|
105
|
+
server-issued boolean `codeApproved=true`. The WordPress editor must never
|
|
106
|
+
execute the document, and consumers must not synthesize this flag.
|
|
107
|
+
|
|
77
108
|
`sf/number-spinner` renders prefix, target number and suffix with independent
|
|
78
109
|
semantic tags and StyleFlow text coordinates. Its numeric value counts from
|
|
79
110
|
zero only when it enters the viewport. The final target remains available to
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
import S from "@styleflow.app/astro/S.astro";
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
FlowpressBlockRenderers,
|
|
5
|
+
FlowpressIconRenderer
|
|
6
|
+
} from "../block-renderers.js";
|
|
4
7
|
import type { StyleflowContract } from "../styleflow.js";
|
|
5
8
|
import type { FlowpressBlock } from "../types.js";
|
|
6
9
|
import ColumnBlock from "./blocks/ColumnBlock.astro";
|
|
7
10
|
import FormBlock from "./blocks/FormBlock.astro";
|
|
8
11
|
import GridBlock from "./blocks/GridBlock.astro";
|
|
9
12
|
import HeroBlock from "./blocks/HeroBlock.astro";
|
|
13
|
+
import ImageBlock from "./blocks/ImageBlock.astro";
|
|
10
14
|
import ListItemFallback from "./blocks/ListItemFallback.astro";
|
|
11
15
|
import NumberSpinnerBlock from "./blocks/NumberSpinnerBlock.astro";
|
|
12
16
|
import TextBlock from "./blocks/TextBlock.astro";
|
|
@@ -22,9 +26,10 @@ interface Props {
|
|
|
22
26
|
blocks: FlowpressBlock[];
|
|
23
27
|
contract?: StyleflowContract;
|
|
24
28
|
blockRenderers?: FlowpressBlockRenderers;
|
|
29
|
+
iconRenderer?: FlowpressIconRenderer;
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
const { blocks, contract, blockRenderers = {} } = Astro.props;
|
|
32
|
+
const { blocks, contract, blockRenderers = {}, iconRenderer: IconRenderer } = Astro.props;
|
|
28
33
|
|
|
29
34
|
function youtubeEmbedUrl(value: unknown): string | null {
|
|
30
35
|
try {
|
|
@@ -58,6 +63,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
58
63
|
blocks={children}
|
|
59
64
|
contract={contract}
|
|
60
65
|
blockRenderers={blockRenderers}
|
|
66
|
+
iconRenderer={IconRenderer}
|
|
61
67
|
/>
|
|
62
68
|
</CustomBlockRenderer>
|
|
63
69
|
);
|
|
@@ -70,6 +76,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
70
76
|
blocks={children}
|
|
71
77
|
contract={contract}
|
|
72
78
|
blockRenderers={blockRenderers}
|
|
79
|
+
iconRenderer={IconRenderer}
|
|
73
80
|
/>
|
|
74
81
|
</HeroBlock>
|
|
75
82
|
);
|
|
@@ -82,6 +89,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
82
89
|
blocks={children}
|
|
83
90
|
contract={contract}
|
|
84
91
|
blockRenderers={blockRenderers}
|
|
92
|
+
iconRenderer={IconRenderer}
|
|
85
93
|
/>
|
|
86
94
|
</GridBlock>
|
|
87
95
|
);
|
|
@@ -94,6 +102,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
94
102
|
blocks={children}
|
|
95
103
|
contract={contract}
|
|
96
104
|
blockRenderers={blockRenderers}
|
|
105
|
+
iconRenderer={IconRenderer}
|
|
97
106
|
/>
|
|
98
107
|
</ColumnBlock>
|
|
99
108
|
);
|
|
@@ -119,6 +128,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
119
128
|
blocks={children}
|
|
120
129
|
contract={contract}
|
|
121
130
|
blockRenderers={blockRenderers}
|
|
131
|
+
iconRenderer={IconRenderer}
|
|
122
132
|
/>
|
|
123
133
|
</TextBlock>
|
|
124
134
|
);
|
|
@@ -128,40 +138,71 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
128
138
|
const href = linkValue(block, "href") || "#";
|
|
129
139
|
const link = objectValue(block, "href");
|
|
130
140
|
const opensInNewTab = Boolean(link.opensInNewTab);
|
|
141
|
+
const icon = String(block.attributes.icon ?? "").trim();
|
|
142
|
+
const iconPosition = ["after", "right"].includes(
|
|
143
|
+
String(block.attributes.iconPosition ?? "before")
|
|
144
|
+
) ? "after" : "before";
|
|
145
|
+
const buttonSemantic = semanticProps(block.attributes, contract, {
|
|
146
|
+
layoutRole: "control",
|
|
147
|
+
density: "md"
|
|
148
|
+
});
|
|
149
|
+
const buttonIcon = IconRenderer && icon ? (
|
|
150
|
+
<IconRenderer name={icon} display="inline" size={4} />
|
|
151
|
+
) : null;
|
|
131
152
|
return (
|
|
132
153
|
<S
|
|
133
154
|
as="a"
|
|
134
155
|
href={href}
|
|
135
156
|
target={opensInNewTab ? "_blank" : undefined}
|
|
136
157
|
rel={opensInNewTab ? "noopener noreferrer" : undefined}
|
|
137
|
-
{...
|
|
158
|
+
{...buttonSemantic}
|
|
138
159
|
{...htmlAttributes}
|
|
139
160
|
>
|
|
161
|
+
{iconPosition === "before" ? buttonIcon : null}
|
|
140
162
|
{textValue(block, "label")}
|
|
163
|
+
{iconPosition === "after" ? buttonIcon : null}
|
|
141
164
|
</S>
|
|
142
165
|
);
|
|
143
166
|
}
|
|
144
167
|
|
|
145
|
-
if (name === "
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
168
|
+
if (name === "icon") {
|
|
169
|
+
const icon = String(block.attributes.icon ?? "").trim();
|
|
170
|
+
const display = block.attributes.display === "block" ? "block" : "inline";
|
|
171
|
+
const numericSize = Number(block.attributes.size ?? 4);
|
|
172
|
+
const size = Number.isFinite(numericSize) && numericSize > 0
|
|
173
|
+
? numericSize
|
|
174
|
+
: 4;
|
|
175
|
+
const iconSemantic = semanticProps({
|
|
176
|
+
foreground: block.attributes.foreground,
|
|
177
|
+
tone: block.attributes.tone,
|
|
178
|
+
intensity: block.attributes.intensity
|
|
179
|
+
}, contract, {});
|
|
180
|
+
return IconRenderer && icon ? (
|
|
181
|
+
<IconRenderer
|
|
182
|
+
name={icon}
|
|
183
|
+
display={display}
|
|
184
|
+
size={size}
|
|
185
|
+
label={String(block.attributes.label ?? "").trim() || undefined}
|
|
186
|
+
{...iconSemantic}
|
|
187
|
+
{...htmlAttributes}
|
|
188
|
+
/>
|
|
162
189
|
) : null;
|
|
163
190
|
}
|
|
164
191
|
|
|
192
|
+
if (name === "code") {
|
|
193
|
+
return block.attributes.codeApproved === true ? (
|
|
194
|
+
<div
|
|
195
|
+
data-flowpress-trusted-code
|
|
196
|
+
{...htmlAttributes}
|
|
197
|
+
set:html={String(block.attributes.document ?? "")}
|
|
198
|
+
/>
|
|
199
|
+
) : null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (name === "image") {
|
|
203
|
+
return <ImageBlock block={block} contract={contract} />;
|
|
204
|
+
}
|
|
205
|
+
|
|
165
206
|
if (name === "gallery") {
|
|
166
207
|
const images = Array.isArray(block.attributes.images)
|
|
167
208
|
? block.attributes.images as Array<Record<string, unknown>>
|
|
@@ -251,6 +292,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
251
292
|
blocks={resolvedBlocks[index]}
|
|
252
293
|
contract={contract}
|
|
253
294
|
blockRenderers={blockRenderers}
|
|
295
|
+
iconRenderer={IconRenderer}
|
|
254
296
|
/>
|
|
255
297
|
) : (
|
|
256
298
|
<ListItemFallback item={item} />
|
|
@@ -268,6 +310,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
268
310
|
blocks={children}
|
|
269
311
|
contract={contract}
|
|
270
312
|
blockRenderers={blockRenderers}
|
|
313
|
+
iconRenderer={IconRenderer}
|
|
271
314
|
/>
|
|
272
315
|
</div>
|
|
273
316
|
) : (
|
|
@@ -275,6 +318,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
275
318
|
blocks={children}
|
|
276
319
|
contract={contract}
|
|
277
320
|
blockRenderers={blockRenderers}
|
|
321
|
+
iconRenderer={IconRenderer}
|
|
278
322
|
/>
|
|
279
323
|
);
|
|
280
324
|
}
|
|
@@ -292,6 +336,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
292
336
|
blocks={children}
|
|
293
337
|
contract={contract}
|
|
294
338
|
blockRenderers={blockRenderers}
|
|
339
|
+
iconRenderer={IconRenderer}
|
|
295
340
|
/>
|
|
296
341
|
</details>
|
|
297
342
|
</S>
|
|
@@ -348,6 +393,7 @@ function youtubeEmbedUrl(value: unknown): string | null {
|
|
|
348
393
|
blocks={children}
|
|
349
394
|
contract={contract}
|
|
350
395
|
blockRenderers={blockRenderers}
|
|
396
|
+
iconRenderer={IconRenderer}
|
|
351
397
|
/>
|
|
352
398
|
)}
|
|
353
399
|
</S>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
import S from "@styleflow.app/astro/S.astro";
|
|
3
|
+
import type { StyleflowContract } from "../../styleflow.js";
|
|
4
|
+
import type { FlowpressBlock } from "../../types.js";
|
|
5
|
+
import {
|
|
6
|
+
blockHtmlAttributes,
|
|
7
|
+
semanticProps
|
|
8
|
+
} from "./helpers.js";
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
block: FlowpressBlock;
|
|
12
|
+
contract?: StyleflowContract;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type ImageLoading = "eager" | "lazy";
|
|
16
|
+
type ImageDecoding = "async" | "auto" | "sync";
|
|
17
|
+
type ImageFetchPriority = "auto" | "high" | "low";
|
|
18
|
+
|
|
19
|
+
const { block, contract } = Astro.props;
|
|
20
|
+
const attributes = block.attributes;
|
|
21
|
+
const media = attributes.image && typeof attributes.image === "object"
|
|
22
|
+
? attributes.image as Record<string, unknown>
|
|
23
|
+
: {};
|
|
24
|
+
|
|
25
|
+
function text(value: unknown): string {
|
|
26
|
+
return typeof value === "string" ? value.trim() : "";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function positiveInteger(value: unknown): number | undefined {
|
|
30
|
+
const number = typeof value === "number" ? value : Number(value);
|
|
31
|
+
return Number.isInteger(number) && number > 0 ? number : undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function loadingValue(value: unknown): ImageLoading {
|
|
35
|
+
return value === "eager" ? "eager" : "lazy";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function decodingValue(value: unknown): ImageDecoding {
|
|
39
|
+
return ["async", "auto", "sync"].includes(String(value))
|
|
40
|
+
? String(value) as ImageDecoding
|
|
41
|
+
: "async";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function fetchPriorityValue(value: unknown): ImageFetchPriority {
|
|
45
|
+
return ["auto", "high", "low"].includes(String(value))
|
|
46
|
+
? String(value) as ImageFetchPriority
|
|
47
|
+
: "auto";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const src = text(media.url) || text(media.sourceUrl);
|
|
51
|
+
const srcSet = text(media.srcSet) || text(media.srcset);
|
|
52
|
+
const sizes = srcSet
|
|
53
|
+
? text(attributes.sizes) || text(media.sizes) || undefined
|
|
54
|
+
: undefined;
|
|
55
|
+
const alt = typeof attributes.alt === "string"
|
|
56
|
+
? attributes.alt
|
|
57
|
+
: typeof media.alt === "string"
|
|
58
|
+
? media.alt
|
|
59
|
+
: typeof media.altText === "string"
|
|
60
|
+
? media.altText
|
|
61
|
+
: "";
|
|
62
|
+
const imageClassName = text(attributes.imageClassName)
|
|
63
|
+
.replace(/\s+/g, " ") || undefined;
|
|
64
|
+
const width = positiveInteger(media.width);
|
|
65
|
+
const height = positiveInteger(media.height);
|
|
66
|
+
const loading = loadingValue(attributes.loading);
|
|
67
|
+
const decoding = decodingValue(attributes.decoding);
|
|
68
|
+
const fetchPriority = fetchPriorityValue(attributes.fetchPriority);
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
{src ? (
|
|
72
|
+
<S
|
|
73
|
+
as="div"
|
|
74
|
+
{...semanticProps(attributes, contract)}
|
|
75
|
+
{...blockHtmlAttributes(attributes)}
|
|
76
|
+
>
|
|
77
|
+
<img
|
|
78
|
+
src={src}
|
|
79
|
+
srcset={srcSet || undefined}
|
|
80
|
+
sizes={sizes}
|
|
81
|
+
width={width}
|
|
82
|
+
height={height}
|
|
83
|
+
alt={alt}
|
|
84
|
+
class={imageClassName}
|
|
85
|
+
loading={loading}
|
|
86
|
+
decoding={decoding}
|
|
87
|
+
fetchpriority={fetchPriority}
|
|
88
|
+
/>
|
|
89
|
+
</S>
|
|
90
|
+
) : null}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
preserveEmptyTextBlock,
|
|
8
8
|
preserveRichTextSpacing,
|
|
9
9
|
semanticProps,
|
|
10
|
+
textAlignmentStyle,
|
|
10
11
|
textValue,
|
|
11
12
|
unwrapCoreHtml
|
|
12
13
|
} from "./helpers.js";
|
|
@@ -38,6 +39,7 @@ const defaults = heading
|
|
|
38
39
|
};
|
|
39
40
|
const semantic = semanticProps(attributes, contract, defaults);
|
|
40
41
|
const htmlAttributes = blockHtmlAttributes(attributes);
|
|
42
|
+
const alignmentStyle = textAlignmentStyle(attributes);
|
|
41
43
|
const coreHtml = String(
|
|
42
44
|
attributes.content
|
|
43
45
|
?? attributes.value
|
|
@@ -58,18 +60,18 @@ const listTag = Boolean(attributes.ordered) ? "ol" : "ul";
|
|
|
58
60
|
---
|
|
59
61
|
|
|
60
62
|
{heading ? (
|
|
61
|
-
<S as={headingTag} {...semantic} {...htmlAttributes} set:html={html} />
|
|
63
|
+
<S as={headingTag} {...semantic} {...htmlAttributes} style={alignmentStyle} set:html={html} />
|
|
62
64
|
) : name === "core/list" ? (
|
|
63
|
-
<S as={listTag} {...semantic} {...htmlAttributes}>
|
|
65
|
+
<S as={listTag} {...semantic} {...htmlAttributes} style={alignmentStyle}>
|
|
64
66
|
{hasChildren ? <slot /> : <Fragment set:html={html} />}
|
|
65
67
|
</S>
|
|
66
68
|
) : name === "core/list-item" ? (
|
|
67
|
-
<S as="li" {...semantic} {...htmlAttributes}>
|
|
69
|
+
<S as="li" {...semantic} {...htmlAttributes} style={alignmentStyle}>
|
|
68
70
|
<span set:html={html}></span>
|
|
69
71
|
{hasChildren ? <slot /> : null}
|
|
70
72
|
</S>
|
|
71
73
|
) : name === "quote" || name === "core/quote" ? (
|
|
72
|
-
<S as="blockquote" {...semantic} {...htmlAttributes}>
|
|
74
|
+
<S as="blockquote" {...semantic} {...htmlAttributes} style={alignmentStyle}>
|
|
73
75
|
{hasChildren ? <slot /> : <div set:html={html}></div>}
|
|
74
76
|
{attributes.citation ? <cite>{String(attributes.citation)}</cite> : null}
|
|
75
77
|
</S>
|
|
@@ -78,6 +80,7 @@ const listTag = Boolean(attributes.ordered) ? "ol" : "ul";
|
|
|
78
80
|
as={name === "core/paragraph" ? "p" : "div"}
|
|
79
81
|
{...semantic}
|
|
80
82
|
{...htmlAttributes}
|
|
83
|
+
style={alignmentStyle}
|
|
81
84
|
set:html={html}
|
|
82
85
|
/>
|
|
83
86
|
)}
|
|
@@ -15,6 +15,8 @@ export declare const TEXT_HTML_TAGS: readonly ["span", "p", "h1", "h2", "h3", "h
|
|
|
15
15
|
export type TextHtmlTag = (typeof TEXT_HTML_TAGS)[number];
|
|
16
16
|
export declare function textHtmlTag(value: unknown): TextHtmlTag;
|
|
17
17
|
export declare function semanticProps(attributes: Record<string, unknown>, contract?: StyleflowContract, defaults?: Record<string, unknown>): Record<string, unknown>;
|
|
18
|
+
/** Resolve only Gutenberg's supported text-alignment values to inline CSS. */
|
|
19
|
+
export declare function textAlignmentStyle(attributes: Record<string, unknown>): string | undefined;
|
|
18
20
|
export declare function prefixedTextSemanticProps(attributes: Record<string, unknown>, prefix: string, contract?: StyleflowContract, defaults?: Record<string, unknown>): Record<string, unknown>;
|
|
19
21
|
export declare function objectValue(block: FlowpressBlock, key: string): Record<string, unknown>;
|
|
20
22
|
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;AAEF,eAAO,MAAM,4BAA4B,YAAY,CAAC;AAEtD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAmBzD;AAED,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,eAAO,MAAM,cAAc,6FAajB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAKvD;AAED,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,
|
|
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,eAAO,MAAM,4BAA4B,YAAY,CAAC;AAEtD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAmBzD;AAED,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,eAAO,MAAM,cAAc,6FAajB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAKvD;AAED,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,CAiBzB;AAWD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,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;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB5D;AAED,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3D;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"}
|
|
@@ -77,9 +77,38 @@ export function semanticProps(attributes, contract, defaults = DEFAULT_SEMANTIC_
|
|
|
77
77
|
const input = Object.fromEntries(SEMANTIC_KEYS
|
|
78
78
|
.filter((key) => attributes[key] !== undefined)
|
|
79
79
|
.map((key) => [key, attributes[key]]));
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
if (contract) {
|
|
81
|
+
return resolveDynamicStyleflowProps(input, defaults, contract);
|
|
82
|
+
}
|
|
83
|
+
const resolved = { ...defaults, ...input };
|
|
84
|
+
for (const key of ["tone", "intensity", "foreground"]) {
|
|
85
|
+
if (input[key] === "inherit") {
|
|
86
|
+
delete resolved[key];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return resolved;
|
|
90
|
+
}
|
|
91
|
+
const TEXT_ALIGNMENTS = new Set([
|
|
92
|
+
"left",
|
|
93
|
+
"center",
|
|
94
|
+
"right",
|
|
95
|
+
"justify",
|
|
96
|
+
"start",
|
|
97
|
+
"end"
|
|
98
|
+
]);
|
|
99
|
+
/** Resolve only Gutenberg's supported text-alignment values to inline CSS. */
|
|
100
|
+
export function textAlignmentStyle(attributes) {
|
|
101
|
+
const style = attributes.style && typeof attributes.style === "object"
|
|
102
|
+
&& !Array.isArray(attributes.style)
|
|
103
|
+
? attributes.style
|
|
104
|
+
: {};
|
|
105
|
+
const typography = style.typography && typeof style.typography === "object"
|
|
106
|
+
&& !Array.isArray(style.typography)
|
|
107
|
+
? style.typography
|
|
108
|
+
: {};
|
|
109
|
+
const candidate = typography.textAlign ?? attributes.textAlign;
|
|
110
|
+
const alignment = String(candidate ?? "");
|
|
111
|
+
return TEXT_ALIGNMENTS.has(alignment) ? `text-align: ${alignment};` : undefined;
|
|
83
112
|
}
|
|
84
113
|
export function prefixedTextSemanticProps(attributes, prefix, contract, defaults = {}) {
|
|
85
114
|
const attributeName = (name) => `${prefix}${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
@@ -1 +1 @@
|
|
|
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 const DEFAULT_HERO_OBJECT_POSITION = \"50% 50%\";\n\nexport function heroObjectPosition(value: unknown): string {\n if (typeof value !== \"string\") {\n return DEFAULT_HERO_OBJECT_POSITION;\n }\n\n const match = value.trim().match(\n /^(\\d+(?:\\.\\d+)?|\\.\\d+)%\\s+(\\d+(?:\\.\\d+)?|\\.\\d+)%$/\n );\n if (\n !match\n || [match[1], match[2]].some((coordinate) => {\n const numeric = Number(coordinate);\n return !Number.isFinite(numeric) || numeric < 0 || numeric > 100;\n })\n ) {\n return DEFAULT_HERO_OBJECT_POSITION;\n }\n\n return `${match[1]}% ${match[2]}%`;\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 const TEXT_HTML_TAGS = [\n \"span\",\n \"p\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"strong\",\n \"em\",\n \"small\",\n \"mark\"\n] as const;\n\nexport type TextHtmlTag = (typeof TEXT_HTML_TAGS)[number];\n\nexport function textHtmlTag(value: unknown): TextHtmlTag {\n const candidate = String(value ?? \"span\");\n return TEXT_HTML_TAGS.includes(candidate as TextHtmlTag)\n ? candidate as TextHtmlTag\n : \"span\";\n}\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 prefixedTextSemanticProps(\n attributes: Record<string, unknown>,\n prefix: string,\n contract?: StyleflowContract,\n defaults: Record<string, unknown> = {}\n): Record<string, unknown> {\n const attributeName = (name: string) =>\n `${prefix}${name.charAt(0).toUpperCase()}${name.slice(1)}`;\n return semanticProps({\n ty: attributes[attributeName(\"ty\")],\n v: attributes[attributeName(\"v\")],\n w: attributes[attributeName(\"w\")],\n foreground: attributes[attributeName(\"foreground\")]\n }, contract, defaults);\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\n/**\n * Keep intentional blank lines visible across current and legacy RichText\n * serializations. Gutenberg can represent them either as repeated `<br>` tags,\n * empty paragraph elements, or literal newlines in an attribute value.\n */\nexport function preserveRichTextSpacing(html: string): string {\n const visibleEmptyBlocks = html\n .replace(/\\r\\n?/g, \"\\n\")\n .replace(\n /<(p|div)(\\s[^>]*)?>(?:\\s| | )*<\\/\\1>/gi,\n (_match, tag: string, attributes = \"\") =>\n `<${tag}${attributes}> </${tag}>`\n );\n\n return visibleEmptyBlocks\n .split(/(<[^>]+>)/g)\n .map((part) => {\n if (part.startsWith(\"<\") || part.trim() === \"\") {\n return part;\n }\n return part.replace(/\\n(?:[ \\t]*\\n)+/g, (newlines) =>\n \"<br>\".repeat((newlines.match(/\\n/g) || []).length)\n );\n })\n .join(\"\");\n}\n\n/** Keep an empty text element at its typographic line height without visible text. */\nexport function preserveEmptyTextBlock(html: string): string {\n return html.trim() === \"\" ? \" \" : html;\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 const DEFAULT_HERO_OBJECT_POSITION = \"50% 50%\";\n\nexport function heroObjectPosition(value: unknown): string {\n if (typeof value !== \"string\") {\n return DEFAULT_HERO_OBJECT_POSITION;\n }\n\n const match = value.trim().match(\n /^(\\d+(?:\\.\\d+)?|\\.\\d+)%\\s+(\\d+(?:\\.\\d+)?|\\.\\d+)%$/\n );\n if (\n !match\n || [match[1], match[2]].some((coordinate) => {\n const numeric = Number(coordinate);\n return !Number.isFinite(numeric) || numeric < 0 || numeric > 100;\n })\n ) {\n return DEFAULT_HERO_OBJECT_POSITION;\n }\n\n return `${match[1]}% ${match[2]}%`;\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 const TEXT_HTML_TAGS = [\n \"span\",\n \"p\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"strong\",\n \"em\",\n \"small\",\n \"mark\"\n] as const;\n\nexport type TextHtmlTag = (typeof TEXT_HTML_TAGS)[number];\n\nexport function textHtmlTag(value: unknown): TextHtmlTag {\n const candidate = String(value ?? \"span\");\n return TEXT_HTML_TAGS.includes(candidate as TextHtmlTag)\n ? candidate as TextHtmlTag\n : \"span\";\n}\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 if (contract) {\n return resolveDynamicStyleflowProps(input, defaults, contract);\n }\n\n const resolved = { ...defaults, ...input };\n for (const key of [\"tone\", \"intensity\", \"foreground\"]) {\n if (input[key] === \"inherit\") {\n delete resolved[key];\n }\n }\n return resolved;\n}\n\nconst TEXT_ALIGNMENTS = new Set([\n \"left\",\n \"center\",\n \"right\",\n \"justify\",\n \"start\",\n \"end\"\n]);\n\n/** Resolve only Gutenberg's supported text-alignment values to inline CSS. */\nexport function textAlignmentStyle(\n attributes: Record<string, unknown>\n): string | undefined {\n const style = attributes.style && typeof attributes.style === \"object\"\n && !Array.isArray(attributes.style)\n ? attributes.style as Record<string, unknown>\n : {};\n const typography = style.typography && typeof style.typography === \"object\"\n && !Array.isArray(style.typography)\n ? style.typography as Record<string, unknown>\n : {};\n const candidate = typography.textAlign ?? attributes.textAlign;\n const alignment = String(candidate ?? \"\");\n return TEXT_ALIGNMENTS.has(alignment) ? `text-align: ${alignment};` : undefined;\n}\n\nexport function prefixedTextSemanticProps(\n attributes: Record<string, unknown>,\n prefix: string,\n contract?: StyleflowContract,\n defaults: Record<string, unknown> = {}\n): Record<string, unknown> {\n const attributeName = (name: string) =>\n `${prefix}${name.charAt(0).toUpperCase()}${name.slice(1)}`;\n return semanticProps({\n ty: attributes[attributeName(\"ty\")],\n v: attributes[attributeName(\"v\")],\n w: attributes[attributeName(\"w\")],\n foreground: attributes[attributeName(\"foreground\")]\n }, contract, defaults);\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\n/**\n * Keep intentional blank lines visible across current and legacy RichText\n * serializations. Gutenberg can represent them either as repeated `<br>` tags,\n * empty paragraph elements, or literal newlines in an attribute value.\n */\nexport function preserveRichTextSpacing(html: string): string {\n const visibleEmptyBlocks = html\n .replace(/\\r\\n?/g, \"\\n\")\n .replace(\n /<(p|div)(\\s[^>]*)?>(?:\\s| | )*<\\/\\1>/gi,\n (_match, tag: string, attributes = \"\") =>\n `<${tag}${attributes}> </${tag}>`\n );\n\n return visibleEmptyBlocks\n .split(/(<[^>]+>)/g)\n .map((part) => {\n if (part.startsWith(\"<\") || part.trim() === \"\") {\n return part;\n }\n return part.replace(/\\n(?:[ \\t]*\\n)+/g, (newlines) =>\n \"<br>\".repeat((newlines.match(/\\n/g) || []).length)\n );\n })\n .join(\"\");\n}\n\n/** Keep an empty text element at its typographic line height without visible text. */\nexport function preserveEmptyTextBlock(html: string): string {\n return html.trim() === \"\" ? \" \" : html;\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"]}
|
|
@@ -107,9 +107,43 @@ export function semanticProps(
|
|
|
107
107
|
.filter((key) => attributes[key] !== undefined)
|
|
108
108
|
.map((key) => [key, attributes[key]])
|
|
109
109
|
);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
if (contract) {
|
|
111
|
+
return resolveDynamicStyleflowProps(input, defaults, contract);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const resolved = { ...defaults, ...input };
|
|
115
|
+
for (const key of ["tone", "intensity", "foreground"]) {
|
|
116
|
+
if (input[key] === "inherit") {
|
|
117
|
+
delete resolved[key];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return resolved;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const TEXT_ALIGNMENTS = new Set([
|
|
124
|
+
"left",
|
|
125
|
+
"center",
|
|
126
|
+
"right",
|
|
127
|
+
"justify",
|
|
128
|
+
"start",
|
|
129
|
+
"end"
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
/** Resolve only Gutenberg's supported text-alignment values to inline CSS. */
|
|
133
|
+
export function textAlignmentStyle(
|
|
134
|
+
attributes: Record<string, unknown>
|
|
135
|
+
): string | undefined {
|
|
136
|
+
const style = attributes.style && typeof attributes.style === "object"
|
|
137
|
+
&& !Array.isArray(attributes.style)
|
|
138
|
+
? attributes.style as Record<string, unknown>
|
|
139
|
+
: {};
|
|
140
|
+
const typography = style.typography && typeof style.typography === "object"
|
|
141
|
+
&& !Array.isArray(style.typography)
|
|
142
|
+
? style.typography as Record<string, unknown>
|
|
143
|
+
: {};
|
|
144
|
+
const candidate = typography.textAlign ?? attributes.textAlign;
|
|
145
|
+
const alignment = String(candidate ?? "");
|
|
146
|
+
return TEXT_ALIGNMENTS.has(alignment) ? `text-align: ${alignment};` : undefined;
|
|
113
147
|
}
|
|
114
148
|
|
|
115
149
|
export function prefixedTextSemanticProps(
|
|
@@ -5,6 +5,18 @@ export interface FlowpressBlockRendererProps {
|
|
|
5
5
|
block: FlowpressBlock;
|
|
6
6
|
contract?: StyleflowContract;
|
|
7
7
|
}
|
|
8
|
+
export interface FlowpressIconRendererProps {
|
|
9
|
+
name: string;
|
|
10
|
+
display?: "inline" | "block";
|
|
11
|
+
foreground?: string;
|
|
12
|
+
tone?: string;
|
|
13
|
+
intensity?: string | number;
|
|
14
|
+
size?: number;
|
|
15
|
+
label?: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
class?: string;
|
|
18
|
+
}
|
|
8
19
|
export type FlowpressBlockRenderer = AstroComponentFactory;
|
|
20
|
+
export type FlowpressIconRenderer = AstroComponentFactory;
|
|
9
21
|
export type FlowpressBlockRenderers = Readonly<Record<string, FlowpressBlockRenderer>>;
|
|
10
22
|
//# sourceMappingURL=block-renderers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-renderers.d.ts","sourceRoot":"","sources":["../src/block-renderers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AAE3D,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAC5C,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CACvC,CAAC"}
|
|
1
|
+
{"version":3,"file":"block-renderers.d.ts","sourceRoot":"","sources":["../src/block-renderers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAAG,qBAAqB,CAAC;AAE1D,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAC5C,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CACvC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-renderers.js","sourceRoot":"","sources":["../src/block-renderers.ts"],"names":[],"mappings":"","sourcesContent":["import type { AstroComponentFactory } from \"astro/runtime/server/index.js\";\nimport type { StyleflowContract } from \"./styleflow.js\";\nimport type { FlowpressBlock } from \"./types.js\";\n\nexport interface FlowpressBlockRendererProps {\n block: FlowpressBlock;\n contract?: StyleflowContract;\n}\n\nexport type FlowpressBlockRenderer = AstroComponentFactory;\n\nexport type FlowpressBlockRenderers = Readonly<\n Record<string, FlowpressBlockRenderer>\n>;\n"]}
|
|
1
|
+
{"version":3,"file":"block-renderers.js","sourceRoot":"","sources":["../src/block-renderers.ts"],"names":[],"mappings":"","sourcesContent":["import type { AstroComponentFactory } from \"astro/runtime/server/index.js\";\nimport type { StyleflowContract } from \"./styleflow.js\";\nimport type { FlowpressBlock } from \"./types.js\";\n\nexport interface FlowpressBlockRendererProps {\n block: FlowpressBlock;\n contract?: StyleflowContract;\n}\n\nexport interface FlowpressIconRendererProps {\n name: string;\n display?: \"inline\" | \"block\";\n foreground?: string;\n tone?: string;\n intensity?: string | number;\n size?: number;\n label?: string;\n id?: string;\n class?: string;\n}\n\nexport type FlowpressBlockRenderer = AstroComponentFactory;\n\nexport type FlowpressIconRenderer = AstroComponentFactory;\n\nexport type FlowpressBlockRenderers = Readonly<\n Record<string, FlowpressBlockRenderer>\n>;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style-classes.d.ts","sourceRoot":"","sources":["../src/style-classes.ts"],"names":[],"mappings":"AAoBA;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"style-classes.d.ts","sourceRoot":"","sources":["../src/style-classes.ts"],"names":[],"mappings":"AAoBA;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,CAgCpE"}
|
package/dist/style-classes.js
CHANGED
|
@@ -35,8 +35,10 @@ export function collectFlowpressClassNames(blocks) {
|
|
|
35
35
|
}
|
|
36
36
|
const block = value;
|
|
37
37
|
if (block.attributes && typeof block.attributes === "object") {
|
|
38
|
-
for (const
|
|
39
|
-
|
|
38
|
+
for (const attribute of ["className", "imageClassName"]) {
|
|
39
|
+
for (const token of classTokens(block.attributes[attribute])) {
|
|
40
|
+
classes.add(token);
|
|
41
|
+
}
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
Object.values(value).forEach(visit);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style-classes.js","sourceRoot":"","sources":["../src/style-classes.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,uBAAuB,GAAG,8BAA8B,CAAC;AAE/D,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,KAAK;SACT,KAAK,CAAC,KAAK,CAAC;SACZ,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACjB,KAAK,CAAC,MAAM,GAAG,CAAC;WACb,KAAK,CAAC,MAAM,IAAI,gBAAgB;WAChC,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CACxC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAe;IACxD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAU,CAAC;IAEtC,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEnB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,KAAgC,CAAC;QAC/C,IAAI,KAAK,CAAC,UAAU,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC7D,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"style-classes.js","sourceRoot":"","sources":["../src/style-classes.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,uBAAuB,GAAG,8BAA8B,CAAC;AAE/D,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,KAAK;SACT,KAAK,CAAC,KAAK,CAAC;SACZ,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACjB,KAAK,CAAC,MAAM,GAAG,CAAC;WACb,KAAK,CAAC,MAAM,IAAI,gBAAgB;WAChC,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CACxC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAe;IACxD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAU,CAAC;IAEtC,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEnB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,KAAgC,CAAC;QAC/C,IAAI,KAAK,CAAC,UAAU,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC7D,KAAK,MAAM,SAAS,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAU,EAAE,CAAC;gBACjE,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;oBAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,KAAK,CAAC,MAAM,CAAC,CAAC;IACd,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACvE,CAAC","sourcesContent":["import type { FlowpressBlock } from \"./types.js\";\n\nconst MAX_CLASS_LENGTH = 256;\nconst UNSAFE_CLASS_CHARACTERS = /[\\s\\\\{};\\u0000-\\u001f\\u007f]/;\n\nfunction classTokens(value: unknown): string[] {\n if (typeof value !== \"string\") {\n return [];\n }\n\n return value\n .split(/\\s+/)\n .map((token) => token.trim())\n .filter((token) => (\n token.length > 0\n && token.length <= MAX_CLASS_LENGTH\n && !UNSAFE_CLASS_CHARACTERS.test(token)\n ));\n}\n\n/**\n * Collect class names authored in Gutenberg from serialized FlowPress blocks.\n *\n * The traversal includes resolved template/list blocks stored inside\n * attributes as well as ordinary inner blocks. Tokens that could terminate a\n * generated Tailwind `@source inline()` directive are discarded.\n */\nexport function collectFlowpressClassNames(blocks: unknown): string[] {\n const classes = new Set<string>();\n const visited = new WeakSet<object>();\n\n const visit = (value: unknown): void => {\n if (!value || typeof value !== \"object\") {\n return;\n }\n if (visited.has(value)) {\n return;\n }\n visited.add(value);\n\n if (Array.isArray(value)) {\n value.forEach(visit);\n return;\n }\n\n const block = value as Partial<FlowpressBlock>;\n if (block.attributes && typeof block.attributes === \"object\") {\n for (const attribute of [\"className\", \"imageClassName\"] as const) {\n for (const token of classTokens(block.attributes[attribute])) {\n classes.add(token);\n }\n }\n }\n\n Object.values(value).forEach(visit);\n };\n\n visit(blocks);\n return [...classes].sort((left, right) => left.localeCompare(right));\n}\n"]}
|
package/dist/styleflow.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const INHERITED_COLOR_PROPS = new Set(["tone", "intensity"]);
|
|
1
|
+
const INHERITED_COLOR_PROPS = new Set(["tone", "intensity", "foreground"]);
|
|
2
2
|
const FOREGROUND_ROLES = ["primary", "secondary", "tertiary", "muted", "accent"];
|
|
3
3
|
const AXIS_BY_PROP = {
|
|
4
4
|
tone: ["color", "tones"],
|
package/dist/styleflow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styleflow.js","sourceRoot":"","sources":["../src/styleflow.ts"],"names":[],"mappings":"AA2BA,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"styleflow.js","sourceRoot":"","sources":["../src/styleflow.ts"],"names":[],"mappings":"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","sourcesContent":["export interface StyleflowContractAxes {\n color: {\n tones: string[];\n intensities: Array<string | number>;\n surfaces: string[];\n };\n layout: {\n roles: string[];\n densities: string[];\n };\n typography: {\n types: string[];\n variants: Record<string, string[]>;\n weights: string[];\n };\n interaction: {\n priorities: string[];\n states: string[];\n };\n}\n\nexport interface StyleflowContract {\n axes: StyleflowContractAxes;\n}\n\nexport type DynamicStyleflowProps = Record<string, unknown>;\n\nconst INHERITED_COLOR_PROPS = new Set([\"tone\", \"intensity\", \"foreground\"]);\nconst FOREGROUND_ROLES = [\"primary\", \"secondary\", \"tertiary\", \"muted\", \"accent\"];\n\nconst AXIS_BY_PROP = {\n tone: [\"color\", \"tones\"],\n intensity: [\"color\", \"intensities\"],\n surface: [\"color\", \"surfaces\"],\n layoutRole: [\"layout\", \"roles\"],\n density: [\"layout\", \"densities\"],\n ty: [\"typography\", \"types\"],\n w: [\"typography\", \"weights\"],\n interactivePriority: [\"interaction\", \"priorities\"],\n interactionState: [\"interaction\", \"states\"]\n} as const;\n\nfunction sameAxisValue(candidate: unknown, allowed: unknown): boolean {\n return String(candidate) === String(allowed);\n}\n\n/**\n * CMS values can outlive a contract revision. Invalid values fail closed to\n * component defaults before reaching Styleflow's Astro runtime.\n */\nexport function resolveDynamicStyleflowProps(\n input: DynamicStyleflowProps,\n defaults: DynamicStyleflowProps,\n contract: StyleflowContract\n): DynamicStyleflowProps {\n const resolved: DynamicStyleflowProps = { ...defaults };\n\n for (const [key, value] of Object.entries(input)) {\n if (value === undefined || value === null || value === \"\") {\n continue;\n }\n\n if (INHERITED_COLOR_PROPS.has(key) && value === \"inherit\") {\n delete resolved[key];\n continue;\n }\n\n if (key === \"v\") {\n const type = String(input.ty ?? defaults.ty ?? \"\");\n const variants = contract.axes.typography.variants[type] ?? [];\n resolved.v = variants.some((variant) => sameAxisValue(value, variant))\n ? value\n : defaults.v;\n continue;\n }\n\n if (key === \"foreground\") {\n resolved.foreground = FOREGROUND_ROLES.includes(String(value))\n ? value\n : defaults.foreground;\n continue;\n }\n\n const axisPath = AXIS_BY_PROP[key as keyof typeof AXIS_BY_PROP];\n if (!axisPath) {\n resolved[key] = value;\n continue;\n }\n\n const [group, axis] = axisPath;\n const groups = contract.axes as unknown as Record<\n string,\n Record<string, unknown[]>\n >;\n const allowed = groups[group]?.[axis] ?? [];\n resolved[key] = allowed.some((item) => sameAxisValue(value, item))\n ? value\n : defaults[key];\n }\n\n return resolved;\n}\n"]}
|
package/package.json
CHANGED