@styleflow.app/flowpress-astro-core 0.2.0-beta.2 → 0.2.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/README.md +59 -1
  3. package/dist/astro/BaseLayout.astro +7 -1
  4. package/dist/astro/DefaultTemplate.astro +31 -21
  5. package/dist/astro/GutenbergRenderer.astro +151 -120
  6. package/dist/astro/blocks/ColumnBlock.astro +83 -0
  7. package/dist/astro/blocks/FormBlock.astro +233 -0
  8. package/dist/astro/blocks/GridBlock.astro +70 -0
  9. package/dist/astro/blocks/HeroBlock.astro +119 -0
  10. package/dist/astro/blocks/ListItemFallback.astro +28 -0
  11. package/dist/astro/blocks/NumberSpinnerBlock.astro +130 -0
  12. package/dist/astro/blocks/TextBlock.astro +83 -0
  13. package/dist/astro/blocks/helpers.d.ts +32 -0
  14. package/dist/astro/blocks/helpers.d.ts.map +1 -0
  15. package/dist/astro/blocks/helpers.js +152 -0
  16. package/dist/astro/blocks/helpers.js.map +1 -0
  17. package/dist/astro/blocks/helpers.ts +211 -0
  18. package/dist/block-renderers.d.ts +10 -0
  19. package/dist/block-renderers.d.ts.map +1 -0
  20. package/dist/block-renderers.js +2 -0
  21. package/dist/block-renderers.js.map +1 -0
  22. package/dist/client.d.ts.map +1 -1
  23. package/dist/client.js +26 -1
  24. package/dist/client.js.map +1 -1
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +3 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/number-spinner.d.ts +6 -0
  30. package/dist/number-spinner.d.ts.map +1 -0
  31. package/dist/number-spinner.js +136 -0
  32. package/dist/number-spinner.js.map +1 -0
  33. package/dist/style-classes.d.ts +9 -0
  34. package/dist/style-classes.d.ts.map +1 -0
  35. package/dist/style-classes.js +47 -0
  36. package/dist/style-classes.js.map +1 -0
  37. package/dist/styleflow.d.ts.map +1 -1
  38. package/dist/styleflow.js +7 -0
  39. package/dist/styleflow.js.map +1 -1
  40. package/dist/tsconfig.tsbuildinfo +1 -1
  41. package/dist/types.d.ts +8 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/dist/types.js.map +1 -1
  44. package/package.json +6 -4
@@ -0,0 +1,83 @@
1
+ ---
2
+ import S from "@styleflow.app/astro/S.astro";
3
+ import type { FlowpressBlock } from "../../types.js";
4
+ import type { StyleflowContract } from "../../styleflow.js";
5
+ import {
6
+ blockHtmlAttributes,
7
+ preserveEmptyTextBlock,
8
+ preserveRichTextSpacing,
9
+ semanticProps,
10
+ textValue,
11
+ unwrapCoreHtml
12
+ } from "./helpers.js";
13
+
14
+ interface Props {
15
+ block: FlowpressBlock;
16
+ contract?: StyleflowContract;
17
+ hasChildren?: boolean;
18
+ }
19
+
20
+ const { block, contract, hasChildren = false } = Astro.props;
21
+ const name = block.name.replace(/^sf\//, "");
22
+ const attributes = block.attributes;
23
+ const heading = name === "heading" || name === "core/heading";
24
+ const level = Math.min(6, Math.max(1, Number(attributes.level ?? 2)));
25
+ const headingTag = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
26
+ const defaults = heading
27
+ ? {
28
+ ty: "heading",
29
+ v: String(attributes.v ?? attributes.variant ?? level),
30
+ w: String(attributes.w ?? attributes.weight ?? "strong"),
31
+ foreground: "primary"
32
+ }
33
+ : {
34
+ ty: "body",
35
+ v: String(attributes.v ?? (name.includes("quote") ? "lg" : "md")),
36
+ w: String(attributes.w ?? "default"),
37
+ foreground: "primary"
38
+ };
39
+ const semantic = semanticProps(attributes, contract, defaults);
40
+ const htmlAttributes = blockHtmlAttributes(attributes);
41
+ const coreHtml = String(
42
+ attributes.content
43
+ ?? attributes.value
44
+ ?? block.innerHtml
45
+ ?? ""
46
+ );
47
+ const normalizedHtml = name === "heading"
48
+ ? textValue(block)
49
+ : name === "rich-text"
50
+ ? preserveRichTextSpacing(String(attributes.content ?? ""))
51
+ : name === "quote"
52
+ ? textValue(block, "quote")
53
+ : unwrapCoreHtml(preserveRichTextSpacing(coreHtml));
54
+ const html = name === "core/list"
55
+ ? normalizedHtml
56
+ : preserveEmptyTextBlock(normalizedHtml);
57
+ const listTag = Boolean(attributes.ordered) ? "ol" : "ul";
58
+ ---
59
+
60
+ {heading ? (
61
+ <S as={headingTag} {...semantic} {...htmlAttributes} set:html={html} />
62
+ ) : name === "core/list" ? (
63
+ <S as={listTag} {...semantic} {...htmlAttributes}>
64
+ {hasChildren ? <slot /> : <Fragment set:html={html} />}
65
+ </S>
66
+ ) : name === "core/list-item" ? (
67
+ <S as="li" {...semantic} {...htmlAttributes}>
68
+ <span set:html={html}></span>
69
+ {hasChildren ? <slot /> : null}
70
+ </S>
71
+ ) : name === "quote" || name === "core/quote" ? (
72
+ <S as="blockquote" {...semantic} {...htmlAttributes}>
73
+ {hasChildren ? <slot /> : <div set:html={html}></div>}
74
+ {attributes.citation ? <cite>{String(attributes.citation)}</cite> : null}
75
+ </S>
76
+ ) : (
77
+ <S
78
+ as={name === "core/paragraph" ? "p" : "div"}
79
+ {...semantic}
80
+ {...htmlAttributes}
81
+ set:html={html}
82
+ />
83
+ )}
@@ -0,0 +1,32 @@
1
+ import { type StyleflowContract } from "../../styleflow.js";
2
+ import type { FlowpressBlock } from "../../types.js";
3
+ export declare const DEFAULT_SEMANTIC_PROPS: {
4
+ surface: string;
5
+ layoutRole: string;
6
+ density: string;
7
+ };
8
+ export declare const DEFAULT_HERO_OBJECT_POSITION = "50% 50%";
9
+ export declare function heroObjectPosition(value: unknown): string;
10
+ export declare function blockHtmlAttributes(attributes: Record<string, unknown>, baseClass?: string): {
11
+ id?: string;
12
+ class?: string;
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;
17
+ export declare function semanticProps(attributes: Record<string, unknown>, contract?: StyleflowContract, defaults?: Record<string, unknown>): Record<string, unknown>;
18
+ export declare function prefixedTextSemanticProps(attributes: Record<string, unknown>, prefix: string, contract?: StyleflowContract, defaults?: Record<string, unknown>): Record<string, unknown>;
19
+ export declare function objectValue(block: FlowpressBlock, key: string): Record<string, unknown>;
20
+ export declare function textValue(block: FlowpressBlock, key?: string): string;
21
+ /**
22
+ * Keep intentional blank lines visible across current and legacy RichText
23
+ * serializations. Gutenberg can represent them either as repeated `<br>` tags,
24
+ * empty paragraph elements, or literal newlines in an attribute value.
25
+ */
26
+ export declare function preserveRichTextSpacing(html: string): string;
27
+ /** Keep an empty text element at its typographic line height without visible text. */
28
+ export declare function preserveEmptyTextBlock(html: string): string;
29
+ export declare function linkValue(block: FlowpressBlock, key?: string): string;
30
+ export declare function responsiveValues(attributes: Record<string, unknown>, prefix: "columns" | "span", fallback: number): Record<"base" | "sm" | "md" | "lg" | "xl" | "2xl", number>;
31
+ export declare function unwrapCoreHtml(html: string): string;
32
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +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,CASzB;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"}
@@ -0,0 +1,152 @@
1
+ import { resolveDynamicStyleflowProps } from "../../styleflow.js";
2
+ export const DEFAULT_SEMANTIC_PROPS = {
3
+ surface: "default",
4
+ layoutRole: "stack",
5
+ density: "md"
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
+ }
22
+ export function blockHtmlAttributes(attributes, baseClass = "") {
23
+ const anchor = typeof attributes.anchor === "string"
24
+ ? attributes.anchor.trim()
25
+ : "";
26
+ const customClass = typeof attributes.className === "string"
27
+ ? attributes.className.trim()
28
+ : "";
29
+ const className = [baseClass.trim(), customClass]
30
+ .filter(Boolean)
31
+ .join(" ")
32
+ .replace(/\s+/g, " ");
33
+ return {
34
+ ...(anchor ? { id: anchor } : {}),
35
+ ...(className ? { class: className } : {})
36
+ };
37
+ }
38
+ const SEMANTIC_KEYS = [
39
+ "tone",
40
+ "intensity",
41
+ "surface",
42
+ "layoutRole",
43
+ "density",
44
+ "ty",
45
+ "v",
46
+ "w",
47
+ "foreground",
48
+ "interactivePriority",
49
+ "noBackground",
50
+ "noBorder",
51
+ "noPadding",
52
+ "noGap",
53
+ "noRadius",
54
+ "noForeground"
55
+ ];
56
+ export const TEXT_HTML_TAGS = [
57
+ "span",
58
+ "p",
59
+ "h1",
60
+ "h2",
61
+ "h3",
62
+ "h4",
63
+ "h5",
64
+ "h6",
65
+ "strong",
66
+ "em",
67
+ "small",
68
+ "mark"
69
+ ];
70
+ export function textHtmlTag(value) {
71
+ const candidate = String(value ?? "span");
72
+ return TEXT_HTML_TAGS.includes(candidate)
73
+ ? candidate
74
+ : "span";
75
+ }
76
+ export function semanticProps(attributes, contract, defaults = DEFAULT_SEMANTIC_PROPS) {
77
+ const input = Object.fromEntries(SEMANTIC_KEYS
78
+ .filter((key) => attributes[key] !== undefined)
79
+ .map((key) => [key, attributes[key]]));
80
+ return contract
81
+ ? resolveDynamicStyleflowProps(input, defaults, contract)
82
+ : { ...defaults, ...input };
83
+ }
84
+ export function prefixedTextSemanticProps(attributes, prefix, contract, defaults = {}) {
85
+ const attributeName = (name) => `${prefix}${name.charAt(0).toUpperCase()}${name.slice(1)}`;
86
+ return semanticProps({
87
+ ty: attributes[attributeName("ty")],
88
+ v: attributes[attributeName("v")],
89
+ w: attributes[attributeName("w")],
90
+ foreground: attributes[attributeName("foreground")]
91
+ }, contract, defaults);
92
+ }
93
+ export function objectValue(block, key) {
94
+ const value = block.attributes[key];
95
+ return value && typeof value === "object" && !Array.isArray(value)
96
+ ? value
97
+ : {};
98
+ }
99
+ export function textValue(block, key = "text") {
100
+ return String(block.attributes[key] ?? "");
101
+ }
102
+ /**
103
+ * Keep intentional blank lines visible across current and legacy RichText
104
+ * serializations. Gutenberg can represent them either as repeated `<br>` tags,
105
+ * empty paragraph elements, or literal newlines in an attribute value.
106
+ */
107
+ export function preserveRichTextSpacing(html) {
108
+ const visibleEmptyBlocks = html
109
+ .replace(/\r\n?/g, "\n")
110
+ .replace(/<(p|div)(\s[^>]*)?>(?:\s|&nbsp;|&#160;)*<\/\1>/gi, (_match, tag, attributes = "") => `<${tag}${attributes}>&nbsp;</${tag}>`);
111
+ return visibleEmptyBlocks
112
+ .split(/(<[^>]+>)/g)
113
+ .map((part) => {
114
+ if (part.startsWith("<") || part.trim() === "") {
115
+ return part;
116
+ }
117
+ return part.replace(/\n(?:[ \t]*\n)+/g, (newlines) => "<br>".repeat((newlines.match(/\n/g) || []).length));
118
+ })
119
+ .join("");
120
+ }
121
+ /** Keep an empty text element at its typographic line height without visible text. */
122
+ export function preserveEmptyTextBlock(html) {
123
+ return html.trim() === "" ? "&nbsp;" : html;
124
+ }
125
+ export function linkValue(block, key = "link") {
126
+ const value = block.attributes[key];
127
+ const href = typeof value === "string"
128
+ ? value
129
+ : String(objectValue(block, key).url ?? "");
130
+ return /^(?:\/(?!\/)|#|https?:\/\/|mailto:|tel:)/i.test(href) ? href : "";
131
+ }
132
+ export function responsiveValues(attributes, prefix, fallback) {
133
+ const keys = ["base", "sm", "md", "lg", "xl", "2xl"];
134
+ const result = {};
135
+ let inherited = fallback;
136
+ for (const key of keys) {
137
+ const suffix = key === "base"
138
+ ? "Base"
139
+ : key === "2xl" ? "2xl" : key.charAt(0).toUpperCase() + key.slice(1);
140
+ const candidate = Number(attributes[`${prefix}${suffix}`]);
141
+ if (Number.isInteger(candidate) && candidate >= 1 && candidate <= 12) {
142
+ inherited = candidate;
143
+ }
144
+ result[key] = inherited;
145
+ }
146
+ return result;
147
+ }
148
+ export function unwrapCoreHtml(html) {
149
+ const match = html.trim().match(/^<(p|h[1-6]|ul|ol|li|blockquote)(?:\s[^>]*)?>([\s\S]*)<\/\1>$/);
150
+ return match?.[2] ?? html;
151
+ }
152
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +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,CAAC,MAAM,4BAA4B,GAAG,SAAS,CAAC;AAEtD,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAC9B,mDAAmD,CACpD,CAAC;IACF,IACE,CAAC,KAAK;WACH,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;YAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;YACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,GAAG,CAAC;QACnE,CAAC,CAAC,EACF,CAAC;QACD,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,UAAmC,EACnC,SAAS,GAAG,EAAE;IAEd,MAAM,MAAM,GAAG,OAAO,UAAU,CAAC,MAAM,KAAK,QAAQ;QAClD,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE;QAC1B,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,WAAW,GAAG,OAAO,UAAU,CAAC,SAAS,KAAK,QAAQ;QAC1D,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE;QAC7B,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,SAAS,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC;SAC9C,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAExB,OAAO;QACL,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3C,CAAC;AACJ,CAAC;AAED,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,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM;IACN,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,QAAQ;IACR,IAAI;IACJ,OAAO;IACP,MAAM;CACE,CAAC;AAIX,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC;IAC1C,OAAO,cAAc,CAAC,QAAQ,CAAC,SAAwB,CAAC;QACtD,CAAC,CAAC,SAAwB;QAC1B,CAAC,CAAC,MAAM,CAAC;AACb,CAAC;AAED,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,yBAAyB,CACvC,UAAmC,EACnC,MAAc,EACd,QAA4B,EAC5B,WAAoC,EAAE;IAEtC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CACrC,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,OAAO,aAAa,CAAC;QACnB,EAAE,EAAE,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QACjC,UAAU,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;KACpD,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACzB,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;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,kBAAkB,GAAG,IAAI;SAC5B,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC;SACvB,OAAO,CACN,kDAAkD,EAClD,CAAC,MAAM,EAAE,GAAW,EAAE,UAAU,GAAG,EAAE,EAAE,EAAE,CACvC,IAAI,GAAG,GAAG,UAAU,YAAY,GAAG,GAAG,CACzC,CAAC;IAEJ,OAAO,kBAAkB;SACtB,KAAK,CAAC,YAAY,CAAC;SACnB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,QAAQ,EAAE,EAAE,CACnD,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CACpD,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,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\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|&nbsp;|&#160;)*<\\/\\1>/gi,\n (_match, tag: string, attributes = \"\") =>\n `<${tag}${attributes}>&nbsp;</${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() === \"\" ? \"&nbsp;\" : 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"]}
@@ -0,0 +1,211 @@
1
+ import {
2
+ resolveDynamicStyleflowProps,
3
+ type StyleflowContract
4
+ } from "../../styleflow.js";
5
+ import type { FlowpressBlock } from "../../types.js";
6
+
7
+ export const DEFAULT_SEMANTIC_PROPS = {
8
+ surface: "default",
9
+ layoutRole: "stack",
10
+ density: "md"
11
+ };
12
+
13
+ export const DEFAULT_HERO_OBJECT_POSITION = "50% 50%";
14
+
15
+ export function heroObjectPosition(value: unknown): string {
16
+ if (typeof value !== "string") {
17
+ return DEFAULT_HERO_OBJECT_POSITION;
18
+ }
19
+
20
+ const match = value.trim().match(
21
+ /^(\d+(?:\.\d+)?|\.\d+)%\s+(\d+(?:\.\d+)?|\.\d+)%$/
22
+ );
23
+ if (
24
+ !match
25
+ || [match[1], match[2]].some((coordinate) => {
26
+ const numeric = Number(coordinate);
27
+ return !Number.isFinite(numeric) || numeric < 0 || numeric > 100;
28
+ })
29
+ ) {
30
+ return DEFAULT_HERO_OBJECT_POSITION;
31
+ }
32
+
33
+ return `${match[1]}% ${match[2]}%`;
34
+ }
35
+
36
+ export function blockHtmlAttributes(
37
+ attributes: Record<string, unknown>,
38
+ baseClass = ""
39
+ ): { id?: string; class?: string } {
40
+ const anchor = typeof attributes.anchor === "string"
41
+ ? attributes.anchor.trim()
42
+ : "";
43
+ const customClass = typeof attributes.className === "string"
44
+ ? attributes.className.trim()
45
+ : "";
46
+ const className = [baseClass.trim(), customClass]
47
+ .filter(Boolean)
48
+ .join(" ")
49
+ .replace(/\s+/g, " ");
50
+
51
+ return {
52
+ ...(anchor ? { id: anchor } : {}),
53
+ ...(className ? { class: className } : {})
54
+ };
55
+ }
56
+
57
+ const SEMANTIC_KEYS = [
58
+ "tone",
59
+ "intensity",
60
+ "surface",
61
+ "layoutRole",
62
+ "density",
63
+ "ty",
64
+ "v",
65
+ "w",
66
+ "foreground",
67
+ "interactivePriority",
68
+ "noBackground",
69
+ "noBorder",
70
+ "noPadding",
71
+ "noGap",
72
+ "noRadius",
73
+ "noForeground"
74
+ ] as const;
75
+
76
+ export const TEXT_HTML_TAGS = [
77
+ "span",
78
+ "p",
79
+ "h1",
80
+ "h2",
81
+ "h3",
82
+ "h4",
83
+ "h5",
84
+ "h6",
85
+ "strong",
86
+ "em",
87
+ "small",
88
+ "mark"
89
+ ] as const;
90
+
91
+ export type TextHtmlTag = (typeof TEXT_HTML_TAGS)[number];
92
+
93
+ export function textHtmlTag(value: unknown): TextHtmlTag {
94
+ const candidate = String(value ?? "span");
95
+ return TEXT_HTML_TAGS.includes(candidate as TextHtmlTag)
96
+ ? candidate as TextHtmlTag
97
+ : "span";
98
+ }
99
+
100
+ export function semanticProps(
101
+ attributes: Record<string, unknown>,
102
+ contract?: StyleflowContract,
103
+ defaults: Record<string, unknown> = DEFAULT_SEMANTIC_PROPS
104
+ ): Record<string, unknown> {
105
+ const input = Object.fromEntries(
106
+ SEMANTIC_KEYS
107
+ .filter((key) => attributes[key] !== undefined)
108
+ .map((key) => [key, attributes[key]])
109
+ );
110
+ return contract
111
+ ? resolveDynamicStyleflowProps(input, defaults, contract)
112
+ : { ...defaults, ...input };
113
+ }
114
+
115
+ export function prefixedTextSemanticProps(
116
+ attributes: Record<string, unknown>,
117
+ prefix: string,
118
+ contract?: StyleflowContract,
119
+ defaults: Record<string, unknown> = {}
120
+ ): Record<string, unknown> {
121
+ const attributeName = (name: string) =>
122
+ `${prefix}${name.charAt(0).toUpperCase()}${name.slice(1)}`;
123
+ return semanticProps({
124
+ ty: attributes[attributeName("ty")],
125
+ v: attributes[attributeName("v")],
126
+ w: attributes[attributeName("w")],
127
+ foreground: attributes[attributeName("foreground")]
128
+ }, contract, defaults);
129
+ }
130
+
131
+ export function objectValue(
132
+ block: FlowpressBlock,
133
+ key: string
134
+ ): Record<string, unknown> {
135
+ const value = block.attributes[key];
136
+ return value && typeof value === "object" && !Array.isArray(value)
137
+ ? value as Record<string, unknown>
138
+ : {};
139
+ }
140
+
141
+ export function textValue(block: FlowpressBlock, key = "text"): string {
142
+ return String(block.attributes[key] ?? "");
143
+ }
144
+
145
+ /**
146
+ * Keep intentional blank lines visible across current and legacy RichText
147
+ * serializations. Gutenberg can represent them either as repeated `<br>` tags,
148
+ * empty paragraph elements, or literal newlines in an attribute value.
149
+ */
150
+ export function preserveRichTextSpacing(html: string): string {
151
+ const visibleEmptyBlocks = html
152
+ .replace(/\r\n?/g, "\n")
153
+ .replace(
154
+ /<(p|div)(\s[^>]*)?>(?:\s|&nbsp;|&#160;)*<\/\1>/gi,
155
+ (_match, tag: string, attributes = "") =>
156
+ `<${tag}${attributes}>&nbsp;</${tag}>`
157
+ );
158
+
159
+ return visibleEmptyBlocks
160
+ .split(/(<[^>]+>)/g)
161
+ .map((part) => {
162
+ if (part.startsWith("<") || part.trim() === "") {
163
+ return part;
164
+ }
165
+ return part.replace(/\n(?:[ \t]*\n)+/g, (newlines) =>
166
+ "<br>".repeat((newlines.match(/\n/g) || []).length)
167
+ );
168
+ })
169
+ .join("");
170
+ }
171
+
172
+ /** Keep an empty text element at its typographic line height without visible text. */
173
+ export function preserveEmptyTextBlock(html: string): string {
174
+ return html.trim() === "" ? "&nbsp;" : html;
175
+ }
176
+
177
+ export function linkValue(block: FlowpressBlock, key = "link"): string {
178
+ const value = block.attributes[key];
179
+ const href = typeof value === "string"
180
+ ? value
181
+ : String(objectValue(block, key).url ?? "");
182
+ return /^(?:\/(?!\/)|#|https?:\/\/|mailto:|tel:)/i.test(href) ? href : "";
183
+ }
184
+
185
+ export function responsiveValues(
186
+ attributes: Record<string, unknown>,
187
+ prefix: "columns" | "span",
188
+ fallback: number
189
+ ): Record<"base" | "sm" | "md" | "lg" | "xl" | "2xl", number> {
190
+ const keys = ["base", "sm", "md", "lg", "xl", "2xl"] as const;
191
+ const result = {} as Record<(typeof keys)[number], number>;
192
+ let inherited = fallback;
193
+ for (const key of keys) {
194
+ const suffix = key === "base"
195
+ ? "Base"
196
+ : key === "2xl" ? "2xl" : key.charAt(0).toUpperCase() + key.slice(1);
197
+ const candidate = Number(attributes[`${prefix}${suffix}`]);
198
+ if (Number.isInteger(candidate) && candidate >= 1 && candidate <= 12) {
199
+ inherited = candidate;
200
+ }
201
+ result[key] = inherited;
202
+ }
203
+ return result;
204
+ }
205
+
206
+ export function unwrapCoreHtml(html: string): string {
207
+ const match = html.trim().match(
208
+ /^<(p|h[1-6]|ul|ol|li|blockquote)(?:\s[^>]*)?>([\s\S]*)<\/\1>$/
209
+ );
210
+ return match?.[2] ?? html;
211
+ }
@@ -0,0 +1,10 @@
1
+ import type { AstroComponentFactory } from "astro/runtime/server/index.js";
2
+ import type { StyleflowContract } from "./styleflow.js";
3
+ import type { FlowpressBlock } from "./types.js";
4
+ export interface FlowpressBlockRendererProps {
5
+ block: FlowpressBlock;
6
+ contract?: StyleflowContract;
7
+ }
8
+ export type FlowpressBlockRenderer = AstroComponentFactory;
9
+ export type FlowpressBlockRenderers = Readonly<Record<string, FlowpressBlockRenderer>>;
10
+ //# sourceMappingURL=block-renderers.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=block-renderers.js.map
@@ -0,0 +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 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE;QACX,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAOD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG5C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,EAAE;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM;gBAJ1B,OAAO,EAAE,MAAM,EACN,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,MAAM,CAAC,EAAE,qBAAqB,EAAE,YAAA,EAChC,aAAa,CAAC,EAAE,MAAM,YAAA,EACtB,QAAQ,CAAC,EAAE,MAAM,YAAA,EAC1B,KAAK,CAAC,EAAE,OAAO;CAKlB;AAED,qBAAa,eAAe;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBAEZ,OAAO,EAAE,sBAAsB;IAarC,OAAO,CAAC,CAAC,EACb,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACtC,OAAO,CAAC,CAAC,CAAC;IAmFP,eAAe,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAoBjD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAgCtE,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA6BrD,UAAU,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;CA2CpC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE;QACX,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAOD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAG5C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,EAAE;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM;gBAJ1B,OAAO,EAAE,MAAM,EACN,MAAM,CAAC,EAAE,MAAM,YAAA,EACf,MAAM,CAAC,EAAE,qBAAqB,EAAE,YAAA,EAChC,aAAa,CAAC,EAAE,MAAM,YAAA,EACtB,QAAQ,CAAC,EAAE,MAAM,YAAA,EAC1B,KAAK,CAAC,EAAE,OAAO;CAKlB;AAED,qBAAa,eAAe;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBAEZ,OAAO,EAAE,sBAAsB;IAarC,OAAO,CAAC,CAAC,EACb,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACtC,OAAO,CAAC,CAAC,CAAC;IAmFP,eAAe,IAAI,OAAO,CAAC,qBAAqB,CAAC;IA4CjD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAgCtE,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA6BrD,UAAU,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;CA2CpC"}
package/dist/client.js CHANGED
@@ -100,9 +100,34 @@ export class FlowpressClient {
100
100
  contactForm7
101
101
  defaultLocale
102
102
  locales { code slug homeUrl }
103
+ features { id version enabled capabilities configJson }
103
104
  }
104
105
  }`);
105
- return data.styleflowCapabilities;
106
+ return {
107
+ ...data.styleflowCapabilities,
108
+ features: (data.styleflowCapabilities.features ?? []).map((feature) => {
109
+ const wire = feature;
110
+ let config = {};
111
+ if (wire.configJson) {
112
+ try {
113
+ const parsed = JSON.parse(wire.configJson);
114
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
115
+ config = parsed;
116
+ }
117
+ }
118
+ catch {
119
+ config = {};
120
+ }
121
+ }
122
+ return {
123
+ id: feature.id,
124
+ version: feature.version ?? null,
125
+ enabled: feature.enabled,
126
+ capabilities: feature.capabilities ?? [],
127
+ config
128
+ };
129
+ })
130
+ };
106
131
  }
107
132
  async getRoute(uri, locale) {
108
133
  const data = await this.request(`query FlowpressRoute($uri: String!, $locale: String) {