@styleflow.app/flowpress-astro-core 0.2.0-beta.13 → 0.2.0-beta.14

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 CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.2.0-beta.14
6
+
7
+ - Added a recursive project block-renderer registry to
8
+ `GutenbergRenderer.astro`, including imported `sf/template` and resolved
9
+ query-item descendants.
10
+
5
11
  ## 0.2.0-beta.13
6
12
 
7
13
  - Kept number spinners static on their final values when
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.13
12
+ pnpm add @styleflow.app/flowpress-astro-core@0.2.0-beta.14
13
13
  ```
14
14
 
15
15
  Prereleases are pinned exactly. The package expects Astro 7 or newer and the
@@ -44,6 +44,32 @@ 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
+ Projects can add renderers for project-owned Gutenberg blocks without copying
48
+ or patching the core renderer. Pass a `FlowpressBlockRenderers` map keyed by the
49
+ full block name; the registry is propagated through every recursive rendering
50
+ path, including imported `sf/template` content and resolved query-item
51
+ templates.
52
+
53
+ ```astro
54
+ ---
55
+ import GutenbergRenderer from "@styleflow.app/flowpress-astro-core/GutenbergRenderer.astro";
56
+ import type {
57
+ FlowpressBlockRenderers
58
+ } from "@styleflow.app/flowpress-astro-core";
59
+ import ProjectTimelineBlock from "./ProjectTimelineBlock.astro";
60
+
61
+ const blockRenderers = {
62
+ "sf/timeline": ProjectTimelineBlock
63
+ } satisfies FlowpressBlockRenderers;
64
+ ---
65
+
66
+ <GutenbergRenderer blocks={blocks} blockRenderers={blockRenderers} />
67
+ ```
68
+
69
+ Each custom renderer receives the original `block` and optional StyleFlow
70
+ `contract`. Its default slot contains recursively rendered child blocks, so a
71
+ container override can place `<slot />` where its children belong.
72
+
47
73
  `sf/number-spinner` renders prefix, target number and suffix with independent
48
74
  semantic tags and StyleFlow text coordinates. Its numeric value counts from
49
75
  zero only when it enters the viewport. The final target remains available to
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  import S from "@styleflow.app/astro/S.astro";
3
+ import type { FlowpressBlockRenderers } from "../block-renderers.js";
3
4
  import type { StyleflowContract } from "../styleflow.js";
4
5
  import type { FlowpressBlock } from "../types.js";
5
6
  import ColumnBlock from "./blocks/ColumnBlock.astro";
@@ -20,9 +21,10 @@ import {
20
21
  interface Props {
21
22
  blocks: FlowpressBlock[];
22
23
  contract?: StyleflowContract;
24
+ blockRenderers?: FlowpressBlockRenderers;
23
25
  }
24
26
 
25
- const { blocks, contract } = Astro.props;
27
+ const { blocks, contract, blockRenderers = {} } = Astro.props;
26
28
 
27
29
  function youtubeEmbedUrl(value: unknown): string | null {
28
30
  try {
@@ -47,11 +49,28 @@ function youtubeEmbedUrl(value: unknown): string | null {
47
49
  const children = block.innerBlocks ?? [];
48
50
  const semantic = semanticProps(block.attributes, contract);
49
51
  const htmlAttributes = blockHtmlAttributes(block.attributes);
52
+ const CustomBlockRenderer = blockRenderers[block.name];
53
+
54
+ if (CustomBlockRenderer) {
55
+ return (
56
+ <CustomBlockRenderer block={block} contract={contract}>
57
+ <Astro.self
58
+ blocks={children}
59
+ contract={contract}
60
+ blockRenderers={blockRenderers}
61
+ />
62
+ </CustomBlockRenderer>
63
+ );
64
+ }
50
65
 
51
66
  if (name === "hero") {
52
67
  return (
53
68
  <HeroBlock block={block} contract={contract}>
54
- <Astro.self blocks={children} contract={contract} />
69
+ <Astro.self
70
+ blocks={children}
71
+ contract={contract}
72
+ blockRenderers={blockRenderers}
73
+ />
55
74
  </HeroBlock>
56
75
  );
57
76
  }
@@ -59,7 +78,11 @@ function youtubeEmbedUrl(value: unknown): string | null {
59
78
  if (name === "grid") {
60
79
  return (
61
80
  <GridBlock block={block} contract={contract}>
62
- <Astro.self blocks={children} contract={contract} />
81
+ <Astro.self
82
+ blocks={children}
83
+ contract={contract}
84
+ blockRenderers={blockRenderers}
85
+ />
63
86
  </GridBlock>
64
87
  );
65
88
  }
@@ -67,7 +90,11 @@ function youtubeEmbedUrl(value: unknown): string | null {
67
90
  if (name === "column") {
68
91
  return (
69
92
  <ColumnBlock block={block} contract={contract}>
70
- <Astro.self blocks={children} contract={contract} />
93
+ <Astro.self
94
+ blocks={children}
95
+ contract={contract}
96
+ blockRenderers={blockRenderers}
97
+ />
71
98
  </ColumnBlock>
72
99
  );
73
100
  }
@@ -88,7 +115,11 @@ function youtubeEmbedUrl(value: unknown): string | null {
88
115
  ].includes(name)) {
89
116
  return (
90
117
  <TextBlock block={block} contract={contract} hasChildren={children.length > 0}>
91
- <Astro.self blocks={children} contract={contract} />
118
+ <Astro.self
119
+ blocks={children}
120
+ contract={contract}
121
+ blockRenderers={blockRenderers}
122
+ />
92
123
  </TextBlock>
93
124
  );
94
125
  }
@@ -216,7 +247,11 @@ function youtubeEmbedUrl(value: unknown): string | null {
216
247
  {items.map((item, index) => (
217
248
  <S as="li">
218
249
  {resolvedBlocks[index]?.length ? (
219
- <Astro.self blocks={resolvedBlocks[index]} contract={contract} />
250
+ <Astro.self
251
+ blocks={resolvedBlocks[index]}
252
+ contract={contract}
253
+ blockRenderers={blockRenderers}
254
+ />
220
255
  ) : (
221
256
  <ListItemFallback item={item} />
222
257
  )}
@@ -229,10 +264,18 @@ function youtubeEmbedUrl(value: unknown): string | null {
229
264
  if (name === "template") {
230
265
  return Object.keys(htmlAttributes).length > 0 ? (
231
266
  <div {...htmlAttributes}>
232
- <Astro.self blocks={children} contract={contract} />
267
+ <Astro.self
268
+ blocks={children}
269
+ contract={contract}
270
+ blockRenderers={blockRenderers}
271
+ />
233
272
  </div>
234
273
  ) : (
235
- <Astro.self blocks={children} contract={contract} />
274
+ <Astro.self
275
+ blocks={children}
276
+ contract={contract}
277
+ blockRenderers={blockRenderers}
278
+ />
236
279
  );
237
280
  }
238
281
 
@@ -245,7 +288,11 @@ function youtubeEmbedUrl(value: unknown): string | null {
245
288
  <S as="div" {...semantic} {...htmlAttributes}>
246
289
  <details>
247
290
  <summary>{String(block.attributes.title ?? "")}</summary>
248
- <Astro.self blocks={children} contract={contract} />
291
+ <Astro.self
292
+ blocks={children}
293
+ contract={contract}
294
+ blockRenderers={blockRenderers}
295
+ />
249
296
  </details>
250
297
  </S>
251
298
  );
@@ -296,7 +343,13 @@ function youtubeEmbedUrl(value: unknown): string | null {
296
343
  <S as={layoutTag} {...semantic} {...htmlAttributes}>
297
344
  {block.innerHtml && children.length === 0
298
345
  ? <S as="div" set:html={block.innerHtml} />
299
- : <Astro.self blocks={children} contract={contract} />}
346
+ : (
347
+ <Astro.self
348
+ blocks={children}
349
+ contract={contract}
350
+ blockRenderers={blockRenderers}
351
+ />
352
+ )}
300
353
  </S>
301
354
  );
302
355
  })}
@@ -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"]}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./client.js";
2
+ export * from "./block-renderers.js";
2
3
  export * from "./env.js";
3
4
  export * from "./number-spinner.js";
4
5
  export * from "./styleflow.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./client.js";
2
+ export * from "./block-renderers.js";
2
3
  export * from "./env.js";
3
4
  export * from "./number-spinner.js";
4
5
  export * from "./styleflow.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./client.js\";\nexport * from \"./env.js\";\nexport * from \"./number-spinner.js\";\nexport * from \"./styleflow.js\";\nexport * from \"./style-classes.js\";\nexport * from \"./template-hierarchy.js\";\nexport * from \"./types.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./client.js\";\nexport * from \"./block-renderers.js\";\nexport * from \"./env.js\";\nexport * from \"./number-spinner.js\";\nexport * from \"./styleflow.js\";\nexport * from \"./style-classes.js\";\nexport * from \"./template-hierarchy.js\";\nexport * from \"./types.js\";\n"]}
@@ -1 +1 @@
1
- {"root":["../src/astro.d.ts","../src/client.ts","../src/env.ts","../src/index.ts","../src/number-spinner.ts","../src/style-classes.ts","../src/styleflow.ts","../src/template-hierarchy.ts","../src/templates.ts","../src/types.ts","../src/astro/blocks/helpers.ts"],"version":"5.9.3"}
1
+ {"root":["../src/astro.d.ts","../src/block-renderers.ts","../src/client.ts","../src/env.ts","../src/index.ts","../src/number-spinner.ts","../src/style-classes.ts","../src/styleflow.ts","../src/template-hierarchy.ts","../src/templates.ts","../src/types.ts","../src/astro/blocks/helpers.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@styleflow.app/flowpress-astro-core",
3
- "version": "0.2.0-beta.13",
3
+ "version": "0.2.0-beta.14",
4
4
  "description": "Project-agnostic WordPress routing, templates, SEO and GraphQL runtime for FlowPress Astro apps.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -36,7 +36,8 @@
36
36
  "scripts": {
37
37
  "build": "tsc -b && node ./scripts/copy-astro.mjs",
38
38
  "typecheck": "tsc -b --pretty false && node ./scripts/copy-astro.mjs && astro check",
39
- "test": "vitest run",
39
+ "test": "vitest run && npm run test:renderer",
40
+ "test:renderer": "node ./scripts/test-custom-renderer.mjs",
40
41
  "release:check": "npm run typecheck && npm test && npm pack --dry-run",
41
42
  "release:publish:next": "npm publish --access public --tag next",
42
43
  "release:publish:latest": "npm publish --access public --tag latest",