@genetik/renderer-react 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eugene Michasiw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # @genetik/renderer-react
2
+
3
+ React binding for **@genetik/renderer**: renders resolved content with a map of block type → React component. Consumes flat content and a schema from @genetik/content and @genetik/schema.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @genetik/renderer-react
9
+ ```
10
+
11
+ Peer dependency: `react` (>=18.0.0).
12
+
13
+ ## Usage
14
+
15
+ - **renderContent(content, schema, componentMap)** — Resolves content with the schema and renders the root. Returns a React node or null if the entry is missing.
16
+ - **renderNode(node, componentMap)** — Renders a single resolved node (and its slots recursively). Unknown block types render as null.
17
+
18
+ Block components receive **BlockProps**: `config` (block config) and `slots` (record of slot name → `ReactNode[]`).
19
+
20
+ See the [docs](/docs/packages/renderer-react) for API and examples.
package/dist/index.cjs ADDED
@@ -0,0 +1,34 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let react = require("react");
3
+ let _genetik_renderer = require("@genetik/renderer");
4
+
5
+ //#region src/render.tsx
6
+ /**
7
+ * Resolves content with the schema and renders the root with the component map.
8
+ * Content may be a GenetikContent object or a JSON string (parsing is done by resolve).
9
+ * Returns null if content is invalid, the entry node is missing, or cannot be resolved.
10
+ */
11
+ function renderContent(content, schema, componentMap) {
12
+ const root = (0, _genetik_renderer.resolve)(content, schema);
13
+ if (!root) return null;
14
+ return renderNode(root, componentMap);
15
+ }
16
+ /**
17
+ * Renders a resolved node tree with the given component map. Unknown block types
18
+ * are skipped (render as null).
19
+ */
20
+ function renderNode(node, componentMap) {
21
+ const Component = componentMap[node.block];
22
+ if (!Component) return null;
23
+ const slots = {};
24
+ for (const [slotName, children] of Object.entries(node.slots)) slots[slotName] = children.map((child) => (0, react.createElement)(react.Fragment, { key: child.id }, renderNode(child, componentMap)));
25
+ return (0, react.createElement)(Component, {
26
+ config: node.config,
27
+ slots
28
+ });
29
+ }
30
+
31
+ //#endregion
32
+ exports.renderContent = renderContent;
33
+ exports.renderNode = renderNode;
34
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["Fragment"],"sources":["../src/render.tsx"],"sourcesContent":["import { createElement, Fragment } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { resolve } from \"@genetik/renderer\";\nimport type { GenetikContent } from \"@genetik/content\";\nimport type { GenetikSchema } from \"@genetik/schema\";\nimport type { ResolvedNode } from \"@genetik/renderer\";\nimport type { BlockProps, ComponentMap } from \"./types.js\";\n\n/**\n * Resolves content with the schema and renders the root with the component map.\n * Content may be a GenetikContent object or a JSON string (parsing is done by resolve).\n * Returns null if content is invalid, the entry node is missing, or cannot be resolved.\n */\nexport function renderContent(\n content: GenetikContent | string,\n schema: GenetikSchema,\n componentMap: ComponentMap,\n): ReactNode {\n const root = resolve(content, schema);\n if (!root) return null;\n return renderNode(root, componentMap);\n}\n\n/**\n * Renders a resolved node tree with the given component map. Unknown block types\n * are skipped (render as null).\n */\nexport function renderNode(\n node: ResolvedNode,\n componentMap: ComponentMap,\n): ReactNode {\n const Component = componentMap[node.block];\n if (!Component) return null;\n\n const slots: Record<string, ReactNode[]> = {};\n for (const [slotName, children] of Object.entries(node.slots)) {\n slots[slotName] = children.map((child) =>\n createElement(Fragment, { key: child.id }, renderNode(child, componentMap)),\n );\n }\n\n return createElement(Component, {\n config: node.config,\n slots,\n } as BlockProps);\n}\n"],"mappings":";;;;;;;;;;AAaA,SAAgB,cACd,SACA,QACA,cACW;CACX,MAAM,sCAAe,SAAS,OAAO;AACrC,KAAI,CAAC,KAAM,QAAO;AAClB,QAAO,WAAW,MAAM,aAAa;;;;;;AAOvC,SAAgB,WACd,MACA,cACW;CACX,MAAM,YAAY,aAAa,KAAK;AACpC,KAAI,CAAC,UAAW,QAAO;CAEvB,MAAM,QAAqC,EAAE;AAC7C,MAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,KAAK,MAAM,CAC3D,OAAM,YAAY,SAAS,KAAK,mCAChBA,gBAAU,EAAE,KAAK,MAAM,IAAI,EAAE,WAAW,OAAO,aAAa,CAAC,CAC5E;AAGH,iCAAqB,WAAW;EAC9B,QAAQ,KAAK;EACb;EACD,CAAe"}
@@ -0,0 +1,36 @@
1
+ import { ComponentType, ReactNode } from "react";
2
+ import { GenetikContent } from "@genetik/content";
3
+ import { GenetikSchema } from "@genetik/schema";
4
+ import { ResolvedNode } from "@genetik/renderer";
5
+
6
+ //#region src/types.d.ts
7
+ /**
8
+ * Props passed to every block component: config and resolved slot content.
9
+ * Each slot is an array of React nodes (already rendered children).
10
+ */
11
+ interface BlockProps {
12
+ /** Block-specific config from content. */
13
+ config: Record<string, unknown>;
14
+ /** Rendered children by slot name. Each value is an array of ReactNode. */
15
+ slots: Record<string, ReactNode[]>;
16
+ }
17
+ /**
18
+ * Map from block type name to React component. Used by renderContent.
19
+ */
20
+ type ComponentMap = Record<string, ComponentType<BlockProps>>;
21
+ //#endregion
22
+ //#region src/render.d.ts
23
+ /**
24
+ * Resolves content with the schema and renders the root with the component map.
25
+ * Content may be a GenetikContent object or a JSON string (parsing is done by resolve).
26
+ * Returns null if content is invalid, the entry node is missing, or cannot be resolved.
27
+ */
28
+ declare function renderContent(content: GenetikContent | string, schema: GenetikSchema, componentMap: ComponentMap): ReactNode;
29
+ /**
30
+ * Renders a resolved node tree with the given component map. Unknown block types
31
+ * are skipped (render as null).
32
+ */
33
+ declare function renderNode(node: ResolvedNode, componentMap: ComponentMap): ReactNode;
34
+ //#endregion
35
+ export { type BlockProps, type ComponentMap, renderContent, renderNode };
36
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/render.tsx"],"mappings":";;;;;;;;;;UAMiB,UAAA;EAAA;EAEf,MAAA,EAAQ,MAAA;;EAER,KAAA,EAAO,MAAA,SAAe,SAAA;AAAA;;;;KAMZ,YAAA,GAAe,MAAA,SAAe,aAAA,CAAc,UAAA;;;;AAVxD;;;;iBCOgB,aAAA,CACd,OAAA,EAAS,cAAA,WACT,MAAA,EAAQ,aAAA,EACR,YAAA,EAAc,YAAA,GACb,SAAA;;;;;iBAUa,UAAA,CACd,IAAA,EAAM,YAAA,EACN,YAAA,EAAc,YAAA,GACb,SAAA"}
@@ -0,0 +1,36 @@
1
+ import { ComponentType, ReactNode } from "react";
2
+ import { ResolvedNode } from "@genetik/renderer";
3
+ import { GenetikContent } from "@genetik/content";
4
+ import { GenetikSchema } from "@genetik/schema";
5
+
6
+ //#region src/types.d.ts
7
+ /**
8
+ * Props passed to every block component: config and resolved slot content.
9
+ * Each slot is an array of React nodes (already rendered children).
10
+ */
11
+ interface BlockProps {
12
+ /** Block-specific config from content. */
13
+ config: Record<string, unknown>;
14
+ /** Rendered children by slot name. Each value is an array of ReactNode. */
15
+ slots: Record<string, ReactNode[]>;
16
+ }
17
+ /**
18
+ * Map from block type name to React component. Used by renderContent.
19
+ */
20
+ type ComponentMap = Record<string, ComponentType<BlockProps>>;
21
+ //#endregion
22
+ //#region src/render.d.ts
23
+ /**
24
+ * Resolves content with the schema and renders the root with the component map.
25
+ * Content may be a GenetikContent object or a JSON string (parsing is done by resolve).
26
+ * Returns null if content is invalid, the entry node is missing, or cannot be resolved.
27
+ */
28
+ declare function renderContent(content: GenetikContent | string, schema: GenetikSchema, componentMap: ComponentMap): ReactNode;
29
+ /**
30
+ * Renders a resolved node tree with the given component map. Unknown block types
31
+ * are skipped (render as null).
32
+ */
33
+ declare function renderNode(node: ResolvedNode, componentMap: ComponentMap): ReactNode;
34
+ //#endregion
35
+ export { type BlockProps, type ComponentMap, renderContent, renderNode };
36
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/render.tsx"],"mappings":";;;;;;;;;;UAMiB,UAAA;EAAA;EAEf,MAAA,EAAQ,MAAA;;EAER,KAAA,EAAO,MAAA,SAAe,SAAA;AAAA;;;;KAMZ,YAAA,GAAe,MAAA,SAAe,aAAA,CAAc,UAAA;;;;AAVxD;;;;iBCOgB,aAAA,CACd,OAAA,EAAS,cAAA,WACT,MAAA,EAAQ,aAAA,EACR,YAAA,EAAc,YAAA,GACb,SAAA;;;;;iBAUa,UAAA,CACd,IAAA,EAAM,YAAA,EACN,YAAA,EAAc,YAAA,GACb,SAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,32 @@
1
+ import { Fragment, createElement } from "react";
2
+ import { resolve } from "@genetik/renderer";
3
+
4
+ //#region src/render.tsx
5
+ /**
6
+ * Resolves content with the schema and renders the root with the component map.
7
+ * Content may be a GenetikContent object or a JSON string (parsing is done by resolve).
8
+ * Returns null if content is invalid, the entry node is missing, or cannot be resolved.
9
+ */
10
+ function renderContent(content, schema, componentMap) {
11
+ const root = resolve(content, schema);
12
+ if (!root) return null;
13
+ return renderNode(root, componentMap);
14
+ }
15
+ /**
16
+ * Renders a resolved node tree with the given component map. Unknown block types
17
+ * are skipped (render as null).
18
+ */
19
+ function renderNode(node, componentMap) {
20
+ const Component = componentMap[node.block];
21
+ if (!Component) return null;
22
+ const slots = {};
23
+ for (const [slotName, children] of Object.entries(node.slots)) slots[slotName] = children.map((child) => createElement(Fragment, { key: child.id }, renderNode(child, componentMap)));
24
+ return createElement(Component, {
25
+ config: node.config,
26
+ slots
27
+ });
28
+ }
29
+
30
+ //#endregion
31
+ export { renderContent, renderNode };
32
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/render.tsx"],"sourcesContent":["import { createElement, Fragment } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { resolve } from \"@genetik/renderer\";\nimport type { GenetikContent } from \"@genetik/content\";\nimport type { GenetikSchema } from \"@genetik/schema\";\nimport type { ResolvedNode } from \"@genetik/renderer\";\nimport type { BlockProps, ComponentMap } from \"./types.js\";\n\n/**\n * Resolves content with the schema and renders the root with the component map.\n * Content may be a GenetikContent object or a JSON string (parsing is done by resolve).\n * Returns null if content is invalid, the entry node is missing, or cannot be resolved.\n */\nexport function renderContent(\n content: GenetikContent | string,\n schema: GenetikSchema,\n componentMap: ComponentMap,\n): ReactNode {\n const root = resolve(content, schema);\n if (!root) return null;\n return renderNode(root, componentMap);\n}\n\n/**\n * Renders a resolved node tree with the given component map. Unknown block types\n * are skipped (render as null).\n */\nexport function renderNode(\n node: ResolvedNode,\n componentMap: ComponentMap,\n): ReactNode {\n const Component = componentMap[node.block];\n if (!Component) return null;\n\n const slots: Record<string, ReactNode[]> = {};\n for (const [slotName, children] of Object.entries(node.slots)) {\n slots[slotName] = children.map((child) =>\n createElement(Fragment, { key: child.id }, renderNode(child, componentMap)),\n );\n }\n\n return createElement(Component, {\n config: node.config,\n slots,\n } as BlockProps);\n}\n"],"mappings":";;;;;;;;;AAaA,SAAgB,cACd,SACA,QACA,cACW;CACX,MAAM,OAAO,QAAQ,SAAS,OAAO;AACrC,KAAI,CAAC,KAAM,QAAO;AAClB,QAAO,WAAW,MAAM,aAAa;;;;;;AAOvC,SAAgB,WACd,MACA,cACW;CACX,MAAM,YAAY,aAAa,KAAK;AACpC,KAAI,CAAC,UAAW,QAAO;CAEvB,MAAM,QAAqC,EAAE;AAC7C,MAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,KAAK,MAAM,CAC3D,OAAM,YAAY,SAAS,KAAK,UAC9B,cAAc,UAAU,EAAE,KAAK,MAAM,IAAI,EAAE,WAAW,OAAO,aAAa,CAAC,CAC5E;AAGH,QAAO,cAAc,WAAW;EAC9B,QAAQ,KAAK;EACb;EACD,CAAe"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@genetik/renderer-react",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.mts",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.cjs",
15
+ "types": "./dist/index.d.mts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "@genetik/content": "0.0.0",
23
+ "@genetik/schema": "0.0.0",
24
+ "@genetik/renderer": "0.0.0"
25
+ },
26
+ "peerDependencies": {
27
+ "react": ">=18.0.0"
28
+ },
29
+ "peerDependenciesMeta": {
30
+ "react-dom": {
31
+ "optional": true
32
+ }
33
+ },
34
+ "devDependencies": {
35
+ "@testing-library/jest-dom": "^6.6.3",
36
+ "@testing-library/react": "^16.0.1",
37
+ "eslint": "^9.39.1",
38
+ "jsdom": "^25.0.1",
39
+ "react": "^19.0.0",
40
+ "react-dom": "^19.0.0",
41
+ "tsdown": "0.20.3",
42
+ "typescript": "5.9.2",
43
+ "vitest": "^2.1.8",
44
+ "@genetik/eslint-config": "0.0.0",
45
+ "@genetik/typescript-config": "0.0.0"
46
+ },
47
+ "engines": {
48
+ "node": ">=18"
49
+ },
50
+ "license": "MIT",
51
+ "scripts": {
52
+ "build": "tsdown",
53
+ "dev": "tsdown --watch",
54
+ "lint": "eslint . --max-warnings 0",
55
+ "check-types": "tsc --noEmit",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest"
58
+ }
59
+ }