@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 +21 -0
- package/README.md +20 -0
- package/dist/index.cjs +34 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +36 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +36 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +32 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +59 -0
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"}
|
package/dist/index.d.cts
ADDED
|
@@ -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"}
|
package/dist/index.d.mts
ADDED
|
@@ -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
|
+
}
|