@styleflow.app/flowpress-astro-core 0.2.0-beta.8 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -0
- package/LICENSE +21 -0
- package/README.md +92 -3
- package/dist/astro/BaseLayout.astro +7 -2
- package/dist/astro/DefaultTemplate.astro +5 -7
- package/dist/astro/GutenbergRenderer.astro +132 -28
- package/dist/astro/blocks/GridBlock.astro +1 -1
- package/dist/astro/blocks/HeroBlock.astro +8 -2
- package/dist/astro/blocks/ImageBlock.astro +90 -0
- package/dist/astro/blocks/NumberSpinnerBlock.astro +130 -0
- package/dist/astro/blocks/TextBlock.astro +21 -7
- package/dist/astro/blocks/helpers.d.ts +16 -0
- package/dist/astro/blocks/helpers.d.ts.map +1 -1
- package/dist/astro/blocks/helpers.js +104 -4
- package/dist/astro/blocks/helpers.js.map +1 -1
- package/dist/astro/blocks/helpers.ts +137 -4
- package/dist/block-renderers.d.ts +22 -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 +49 -0
- package/dist/style-classes.js.map +1 -0
- package/dist/styleflow.d.ts +37 -8
- package/dist/styleflow.d.ts.map +1 -1
- package/dist/styleflow.js +85 -42
- 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 -5
|
@@ -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}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
import S from "@styleflow.app/astro/S.astro";
|
|
3
|
+
import {
|
|
4
|
+
clampSpinnerDuration,
|
|
5
|
+
spinnerFractionDigits
|
|
6
|
+
} from "../../number-spinner.js";
|
|
7
|
+
import type { StyleflowContract } from "../../styleflow.js";
|
|
8
|
+
import type { FlowpressBlock } from "../../types.js";
|
|
9
|
+
import {
|
|
10
|
+
blockHtmlAttributes,
|
|
11
|
+
prefixedTextSemanticProps,
|
|
12
|
+
semanticProps,
|
|
13
|
+
textHtmlTag
|
|
14
|
+
} from "./helpers.js";
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
block: FlowpressBlock;
|
|
18
|
+
contract?: StyleflowContract;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { block, contract } = Astro.props;
|
|
22
|
+
const attributes = block.attributes;
|
|
23
|
+
const prefix = String(attributes.prefix ?? "");
|
|
24
|
+
const suffix = String(attributes.suffix ?? "");
|
|
25
|
+
const candidateNumber = Number(attributes.number);
|
|
26
|
+
const number = Number.isFinite(candidateNumber) ? candidateNumber : 0;
|
|
27
|
+
const duration = clampSpinnerDuration(attributes.duration);
|
|
28
|
+
const fractionDigits = spinnerFractionDigits(number);
|
|
29
|
+
const locale = Astro.currentLocale ?? "";
|
|
30
|
+
const numberText = String(number);
|
|
31
|
+
const semantic = semanticProps(attributes, contract);
|
|
32
|
+
const htmlAttributes = blockHtmlAttributes(
|
|
33
|
+
attributes,
|
|
34
|
+
"flowpress-number-spinner"
|
|
35
|
+
);
|
|
36
|
+
const prefixSemantic = prefixedTextSemanticProps(
|
|
37
|
+
attributes,
|
|
38
|
+
"prefix",
|
|
39
|
+
contract,
|
|
40
|
+
{ ty: "body", v: "md", w: "default", foreground: "primary" }
|
|
41
|
+
);
|
|
42
|
+
const numberSemantic = prefixedTextSemanticProps(
|
|
43
|
+
attributes,
|
|
44
|
+
"number",
|
|
45
|
+
contract,
|
|
46
|
+
{ ty: "heading", v: "2", w: "strong", foreground: "primary" }
|
|
47
|
+
);
|
|
48
|
+
const suffixSemantic = prefixedTextSemanticProps(
|
|
49
|
+
attributes,
|
|
50
|
+
"suffix",
|
|
51
|
+
contract,
|
|
52
|
+
{ ty: "body", v: "md", w: "default", foreground: "primary" }
|
|
53
|
+
);
|
|
54
|
+
const prefixTag = textHtmlTag(attributes.prefixTag);
|
|
55
|
+
const numberTag = textHtmlTag(attributes.numberTag);
|
|
56
|
+
const suffixTag = textHtmlTag(attributes.suffixTag);
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
<S
|
|
60
|
+
as="div"
|
|
61
|
+
{...semantic}
|
|
62
|
+
{...htmlAttributes}
|
|
63
|
+
data-flowpress-number-spinner
|
|
64
|
+
data-spinner-target={number}
|
|
65
|
+
data-spinner-duration={duration}
|
|
66
|
+
data-spinner-fraction-digits={fractionDigits}
|
|
67
|
+
data-spinner-locale={locale || undefined}
|
|
68
|
+
>
|
|
69
|
+
{prefix ? (
|
|
70
|
+
<S
|
|
71
|
+
as={prefixTag}
|
|
72
|
+
class="flowpress-number-spinner__segment"
|
|
73
|
+
{...prefixSemantic}
|
|
74
|
+
>
|
|
75
|
+
{prefix}
|
|
76
|
+
</S>
|
|
77
|
+
) : null}
|
|
78
|
+
<S
|
|
79
|
+
as={numberTag}
|
|
80
|
+
class="flowpress-number-spinner__segment flowpress-number-spinner__number"
|
|
81
|
+
{...numberSemantic}
|
|
82
|
+
>
|
|
83
|
+
<span class="flowpress-number-spinner__accessible-value">
|
|
84
|
+
{numberText}
|
|
85
|
+
</span>
|
|
86
|
+
<span
|
|
87
|
+
aria-hidden="true"
|
|
88
|
+
data-flowpress-number-spinner-value
|
|
89
|
+
>
|
|
90
|
+
{numberText}
|
|
91
|
+
</span>
|
|
92
|
+
</S>
|
|
93
|
+
{suffix ? (
|
|
94
|
+
<S
|
|
95
|
+
as={suffixTag}
|
|
96
|
+
class="flowpress-number-spinner__segment"
|
|
97
|
+
{...suffixSemantic}
|
|
98
|
+
>
|
|
99
|
+
{suffix}
|
|
100
|
+
</S>
|
|
101
|
+
) : null}
|
|
102
|
+
</S>
|
|
103
|
+
|
|
104
|
+
<script>
|
|
105
|
+
import { initializeNumberSpinners } from "../../number-spinner.js";
|
|
106
|
+
|
|
107
|
+
initializeNumberSpinners();
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<style>
|
|
111
|
+
.flowpress-number-spinner {
|
|
112
|
+
display: inline-flex;
|
|
113
|
+
align-items: baseline;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.flowpress-number-spinner__segment {
|
|
117
|
+
display: inline;
|
|
118
|
+
margin: 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.flowpress-number-spinner__accessible-value {
|
|
122
|
+
position: absolute;
|
|
123
|
+
width: 1px;
|
|
124
|
+
height: 1px;
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
clip: rect(0 0 0 0);
|
|
127
|
+
clip-path: inset(50%);
|
|
128
|
+
white-space: nowrap;
|
|
129
|
+
}
|
|
130
|
+
</style>
|
|
@@ -4,7 +4,10 @@ import type { FlowpressBlock } from "../../types.js";
|
|
|
4
4
|
import type { StyleflowContract } from "../../styleflow.js";
|
|
5
5
|
import {
|
|
6
6
|
blockHtmlAttributes,
|
|
7
|
+
preserveEmptyTextBlock,
|
|
8
|
+
preserveRichTextSpacing,
|
|
7
9
|
semanticProps,
|
|
10
|
+
textAlignmentStyle,
|
|
8
11
|
textValue,
|
|
9
12
|
unwrapCoreHtml
|
|
10
13
|
} from "./helpers.js";
|
|
@@ -36,29 +39,39 @@ const defaults = heading
|
|
|
36
39
|
};
|
|
37
40
|
const semantic = semanticProps(attributes, contract, defaults);
|
|
38
41
|
const htmlAttributes = blockHtmlAttributes(attributes);
|
|
39
|
-
const
|
|
42
|
+
const alignmentStyle = textAlignmentStyle(attributes);
|
|
43
|
+
const coreHtml = String(
|
|
44
|
+
attributes.content
|
|
45
|
+
?? attributes.value
|
|
46
|
+
?? block.innerHtml
|
|
47
|
+
?? ""
|
|
48
|
+
);
|
|
49
|
+
const normalizedHtml = name === "heading"
|
|
40
50
|
? textValue(block)
|
|
41
51
|
: name === "rich-text"
|
|
42
|
-
? String(attributes.content ?? "")
|
|
52
|
+
? preserveRichTextSpacing(String(attributes.content ?? ""))
|
|
43
53
|
: name === "quote"
|
|
44
54
|
? textValue(block, "quote")
|
|
45
|
-
: unwrapCoreHtml(
|
|
55
|
+
: unwrapCoreHtml(preserveRichTextSpacing(coreHtml));
|
|
56
|
+
const html = name === "core/list"
|
|
57
|
+
? normalizedHtml
|
|
58
|
+
: preserveEmptyTextBlock(normalizedHtml);
|
|
46
59
|
const listTag = Boolean(attributes.ordered) ? "ol" : "ul";
|
|
47
60
|
---
|
|
48
61
|
|
|
49
62
|
{heading ? (
|
|
50
|
-
<S as={headingTag} {...semantic} {...htmlAttributes} set:html={html} />
|
|
63
|
+
<S as={headingTag} {...semantic} {...htmlAttributes} style={alignmentStyle} set:html={html} />
|
|
51
64
|
) : name === "core/list" ? (
|
|
52
|
-
<S as={listTag} {...semantic} {...htmlAttributes}>
|
|
65
|
+
<S as={listTag} {...semantic} {...htmlAttributes} style={alignmentStyle}>
|
|
53
66
|
{hasChildren ? <slot /> : <Fragment set:html={html} />}
|
|
54
67
|
</S>
|
|
55
68
|
) : name === "core/list-item" ? (
|
|
56
|
-
<S as="li" {...semantic} {...htmlAttributes}>
|
|
69
|
+
<S as="li" {...semantic} {...htmlAttributes} style={alignmentStyle}>
|
|
57
70
|
<span set:html={html}></span>
|
|
58
71
|
{hasChildren ? <slot /> : null}
|
|
59
72
|
</S>
|
|
60
73
|
) : name === "quote" || name === "core/quote" ? (
|
|
61
|
-
<S as="blockquote" {...semantic} {...htmlAttributes}>
|
|
74
|
+
<S as="blockquote" {...semantic} {...htmlAttributes} style={alignmentStyle}>
|
|
62
75
|
{hasChildren ? <slot /> : <div set:html={html}></div>}
|
|
63
76
|
{attributes.citation ? <cite>{String(attributes.citation)}</cite> : null}
|
|
64
77
|
</S>
|
|
@@ -67,6 +80,7 @@ const listTag = Boolean(attributes.ordered) ? "ol" : "ul";
|
|
|
67
80
|
as={name === "core/paragraph" ? "p" : "div"}
|
|
68
81
|
{...semantic}
|
|
69
82
|
{...htmlAttributes}
|
|
83
|
+
style={alignmentStyle}
|
|
70
84
|
set:html={html}
|
|
71
85
|
/>
|
|
72
86
|
)}
|
|
@@ -5,13 +5,29 @@ export declare const DEFAULT_SEMANTIC_PROPS: {
|
|
|
5
5
|
layoutRole: string;
|
|
6
6
|
density: string;
|
|
7
7
|
};
|
|
8
|
+
export declare const DEFAULT_HERO_OBJECT_POSITION = "50% 50%";
|
|
9
|
+
export declare function heroObjectPosition(value: unknown): string;
|
|
8
10
|
export declare function blockHtmlAttributes(attributes: Record<string, unknown>, baseClass?: string): {
|
|
9
11
|
id?: string;
|
|
10
12
|
class?: string;
|
|
11
13
|
};
|
|
14
|
+
export declare const TEXT_HTML_TAGS: readonly ["span", "p", "h1", "h2", "h3", "h4", "h5", "h6", "strong", "em", "small", "mark"];
|
|
15
|
+
export type TextHtmlTag = (typeof TEXT_HTML_TAGS)[number];
|
|
16
|
+
export declare function textHtmlTag(value: unknown): TextHtmlTag;
|
|
12
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;
|
|
20
|
+
export declare function prefixedTextSemanticProps(attributes: Record<string, unknown>, prefix: string, contract?: StyleflowContract, defaults?: Record<string, unknown>): Record<string, unknown>;
|
|
13
21
|
export declare function objectValue(block: FlowpressBlock, key: string): Record<string, unknown>;
|
|
14
22
|
export declare function textValue(block: FlowpressBlock, key?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Keep intentional blank lines visible across current and legacy RichText
|
|
25
|
+
* serializations. Gutenberg can represent them either as repeated `<br>` tags,
|
|
26
|
+
* empty paragraph elements, or literal newlines in an attribute value.
|
|
27
|
+
*/
|
|
28
|
+
export declare function preserveRichTextSpacing(html: string): string;
|
|
29
|
+
/** Keep an empty text element at its typographic line height without visible text. */
|
|
30
|
+
export declare function preserveEmptyTextBlock(html: string): string;
|
|
15
31
|
export declare function linkValue(block: FlowpressBlock, key?: string): string;
|
|
16
32
|
export declare function responsiveValues(attributes: Record<string, unknown>, prefix: "columns" | "span", fallback: number): Record<"base" | "sm" | "md" | "lg" | "xl" | "2xl", number>;
|
|
17
33
|
export declare function unwrapCoreHtml(html: 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,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;
|
|
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;AAsBD,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,CAoBzB;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"}
|
|
@@ -2,8 +2,23 @@ import { resolveDynamicStyleflowProps } from "../../styleflow.js";
|
|
|
2
2
|
export const DEFAULT_SEMANTIC_PROPS = {
|
|
3
3
|
surface: "default",
|
|
4
4
|
layoutRole: "stack",
|
|
5
|
-
density: "
|
|
5
|
+
density: "regular"
|
|
6
6
|
};
|
|
7
|
+
export const DEFAULT_HERO_OBJECT_POSITION = "50% 50%";
|
|
8
|
+
export function heroObjectPosition(value) {
|
|
9
|
+
if (typeof value !== "string") {
|
|
10
|
+
return DEFAULT_HERO_OBJECT_POSITION;
|
|
11
|
+
}
|
|
12
|
+
const match = value.trim().match(/^(\d+(?:\.\d+)?|\.\d+)%\s+(\d+(?:\.\d+)?|\.\d+)%$/);
|
|
13
|
+
if (!match
|
|
14
|
+
|| [match[1], match[2]].some((coordinate) => {
|
|
15
|
+
const numeric = Number(coordinate);
|
|
16
|
+
return !Number.isFinite(numeric) || numeric < 0 || numeric > 100;
|
|
17
|
+
})) {
|
|
18
|
+
return DEFAULT_HERO_OBJECT_POSITION;
|
|
19
|
+
}
|
|
20
|
+
return `${match[1]}% ${match[2]}%`;
|
|
21
|
+
}
|
|
7
22
|
export function blockHtmlAttributes(attributes, baseClass = "") {
|
|
8
23
|
const anchor = typeof attributes.anchor === "string"
|
|
9
24
|
? attributes.anchor.trim()
|
|
@@ -21,6 +36,7 @@ export function blockHtmlAttributes(attributes, baseClass = "") {
|
|
|
21
36
|
};
|
|
22
37
|
}
|
|
23
38
|
const SEMANTIC_KEYS = [
|
|
39
|
+
"theme",
|
|
24
40
|
"tone",
|
|
25
41
|
"intensity",
|
|
26
42
|
"surface",
|
|
@@ -38,13 +54,74 @@ const SEMANTIC_KEYS = [
|
|
|
38
54
|
"noRadius",
|
|
39
55
|
"noForeground"
|
|
40
56
|
];
|
|
57
|
+
export const TEXT_HTML_TAGS = [
|
|
58
|
+
"span",
|
|
59
|
+
"p",
|
|
60
|
+
"h1",
|
|
61
|
+
"h2",
|
|
62
|
+
"h3",
|
|
63
|
+
"h4",
|
|
64
|
+
"h5",
|
|
65
|
+
"h6",
|
|
66
|
+
"strong",
|
|
67
|
+
"em",
|
|
68
|
+
"small",
|
|
69
|
+
"mark"
|
|
70
|
+
];
|
|
71
|
+
export function textHtmlTag(value) {
|
|
72
|
+
const candidate = String(value ?? "span");
|
|
73
|
+
return TEXT_HTML_TAGS.includes(candidate)
|
|
74
|
+
? candidate
|
|
75
|
+
: "span";
|
|
76
|
+
}
|
|
41
77
|
export function semanticProps(attributes, contract, defaults = DEFAULT_SEMANTIC_PROPS) {
|
|
42
78
|
const input = Object.fromEntries(SEMANTIC_KEYS
|
|
43
79
|
.filter((key) => attributes[key] !== undefined)
|
|
44
80
|
.map((key) => [key, attributes[key]]));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
81
|
+
if (contract) {
|
|
82
|
+
return resolveDynamicStyleflowProps(input, defaults, contract, {
|
|
83
|
+
strict: process.env.NODE_ENV === "production" || process.env.STYLEFLOW_STRICT === "1",
|
|
84
|
+
onDiagnostic: (diagnostic) => console.warn(`[${diagnostic.code}] ${diagnostic.message}`)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const resolved = { ...defaults, ...input };
|
|
88
|
+
for (const key of ["tone", "intensity", "foreground"]) {
|
|
89
|
+
if (input[key] === "inherit") {
|
|
90
|
+
delete resolved[key];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return resolved;
|
|
94
|
+
}
|
|
95
|
+
const TEXT_ALIGNMENTS = new Set([
|
|
96
|
+
"left",
|
|
97
|
+
"center",
|
|
98
|
+
"right",
|
|
99
|
+
"justify",
|
|
100
|
+
"start",
|
|
101
|
+
"end"
|
|
102
|
+
]);
|
|
103
|
+
/** Resolve only Gutenberg's supported text-alignment values to inline CSS. */
|
|
104
|
+
export function textAlignmentStyle(attributes) {
|
|
105
|
+
const style = attributes.style && typeof attributes.style === "object"
|
|
106
|
+
&& !Array.isArray(attributes.style)
|
|
107
|
+
? attributes.style
|
|
108
|
+
: {};
|
|
109
|
+
const typography = style.typography && typeof style.typography === "object"
|
|
110
|
+
&& !Array.isArray(style.typography)
|
|
111
|
+
? style.typography
|
|
112
|
+
: {};
|
|
113
|
+
const candidate = typography.textAlign ?? attributes.textAlign;
|
|
114
|
+
const alignment = String(candidate ?? "");
|
|
115
|
+
return TEXT_ALIGNMENTS.has(alignment) ? `text-align: ${alignment};` : undefined;
|
|
116
|
+
}
|
|
117
|
+
export function prefixedTextSemanticProps(attributes, prefix, contract, defaults = {}) {
|
|
118
|
+
const attributeName = (name) => `${prefix}${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
119
|
+
return semanticProps({
|
|
120
|
+
ty: attributes[attributeName("ty")],
|
|
121
|
+
v: attributes[attributeName("v")],
|
|
122
|
+
w: attributes[attributeName("w")],
|
|
123
|
+
foreground: attributes[attributeName("foreground")]
|
|
124
|
+
}, contract, defaults);
|
|
48
125
|
}
|
|
49
126
|
export function objectValue(block, key) {
|
|
50
127
|
const value = block.attributes[key];
|
|
@@ -55,6 +132,29 @@ export function objectValue(block, key) {
|
|
|
55
132
|
export function textValue(block, key = "text") {
|
|
56
133
|
return String(block.attributes[key] ?? "");
|
|
57
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Keep intentional blank lines visible across current and legacy RichText
|
|
137
|
+
* serializations. Gutenberg can represent them either as repeated `<br>` tags,
|
|
138
|
+
* empty paragraph elements, or literal newlines in an attribute value.
|
|
139
|
+
*/
|
|
140
|
+
export function preserveRichTextSpacing(html) {
|
|
141
|
+
const visibleEmptyBlocks = html
|
|
142
|
+
.replace(/\r\n?/g, "\n")
|
|
143
|
+
.replace(/<(p|div)(\s[^>]*)?>(?:\s| | )*<\/\1>/gi, (_match, tag, attributes = "") => `<${tag}${attributes}> </${tag}>`);
|
|
144
|
+
return visibleEmptyBlocks
|
|
145
|
+
.split(/(<[^>]+>)/g)
|
|
146
|
+
.map((part) => {
|
|
147
|
+
if (part.startsWith("<") || part.trim() === "") {
|
|
148
|
+
return part;
|
|
149
|
+
}
|
|
150
|
+
return part.replace(/\n(?:[ \t]*\n)+/g, (newlines) => "<br>".repeat((newlines.match(/\n/g) || []).length));
|
|
151
|
+
})
|
|
152
|
+
.join("");
|
|
153
|
+
}
|
|
154
|
+
/** Keep an empty text element at its typographic line height without visible text. */
|
|
155
|
+
export function preserveEmptyTextBlock(html) {
|
|
156
|
+
return html.trim() === "" ? " " : html;
|
|
157
|
+
}
|
|
58
158
|
export function linkValue(block, key = "link") {
|
|
59
159
|
const value = block.attributes[key];
|
|
60
160
|
const href = typeof value === "string"
|
|
@@ -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 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"]}
|
|
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: \"regular\"\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 \"theme\",\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 strict: process.env.NODE_ENV === \"production\" || process.env.STYLEFLOW_STRICT === \"1\",\n onDiagnostic: (diagnostic) => console.warn(`[${diagnostic.code}] ${diagnostic.message}`)\n });\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"]}
|