@vojtaholik/static-kit-core 2.0.0 → 2.1.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/package.json +4 -2
- package/src/config.ts +0 -2
- package/src/html-renderer.ts +30 -3
- package/src/index.ts +1 -13
- package/src/schema.ts +0 -164
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vojtaholik/static-kit-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"types": "./src/index.ts"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"files": [
|
|
11
|
+
"files": [
|
|
12
|
+
"src"
|
|
13
|
+
],
|
|
12
14
|
"repository": {
|
|
13
15
|
"type": "git",
|
|
14
16
|
"url": "https://github.com/vojtaholik/module-kit",
|
package/src/config.ts
CHANGED
|
@@ -16,8 +16,6 @@ export const configSchema = z.object({
|
|
|
16
16
|
publicPath: z.string().default("/public"),
|
|
17
17
|
/** Dev server port */
|
|
18
18
|
devPort: z.number().default(3000),
|
|
19
|
-
/** Path to cms-blocks file (relative to project root) */
|
|
20
|
-
cmsBlocksFile: z.string().optional(),
|
|
21
19
|
});
|
|
22
20
|
|
|
23
21
|
export type StaticKitConfig = z.infer<typeof configSchema>;
|
package/src/html-renderer.ts
CHANGED
|
@@ -5,14 +5,41 @@ import { blockRegistry, type RenderContext } from "./block-registry.ts";
|
|
|
5
5
|
import type { SchemaAddress } from "./schema-address.ts";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Augmentable block props map — users register their block types via:
|
|
9
|
+
*
|
|
10
|
+
* declare module "@vojtaholik/static-kit-core" {
|
|
11
|
+
* interface BlockPropsMap {
|
|
12
|
+
* hero: HeroProps;
|
|
13
|
+
* // ...
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
9
16
|
*/
|
|
10
|
-
export interface
|
|
17
|
+
export interface BlockPropsMap {}
|
|
18
|
+
|
|
19
|
+
type TypedBlockInstance = {
|
|
20
|
+
[K in keyof BlockPropsMap & string]: {
|
|
21
|
+
id: string;
|
|
22
|
+
type: K;
|
|
23
|
+
props: BlockPropsMap[K];
|
|
24
|
+
layout?: Partial<LayoutProps>;
|
|
25
|
+
};
|
|
26
|
+
}[keyof BlockPropsMap & string];
|
|
27
|
+
|
|
28
|
+
type UntypedBlockInstance = {
|
|
11
29
|
id: string;
|
|
12
30
|
type: string;
|
|
13
31
|
props: Record<string, unknown>;
|
|
14
32
|
layout?: Partial<LayoutProps>;
|
|
15
|
-
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Block instance in a page config.
|
|
37
|
+
* When BlockPropsMap is augmented, known types get typed props + autocomplete.
|
|
38
|
+
* Arbitrary types still accepted via the fallback.
|
|
39
|
+
*/
|
|
40
|
+
export type BlockInstance = keyof BlockPropsMap extends never
|
|
41
|
+
? UntypedBlockInstance
|
|
42
|
+
: TypedBlockInstance | (UntypedBlockInstance & { type: string & {} });
|
|
16
43
|
|
|
17
44
|
/**
|
|
18
45
|
* Region config - blocks in a named region
|
package/src/index.ts
CHANGED
|
@@ -22,19 +22,6 @@ export {
|
|
|
22
22
|
type SchemaAddress,
|
|
23
23
|
} from "./schema-address.ts";
|
|
24
24
|
|
|
25
|
-
// CMS schema utilities
|
|
26
|
-
export {
|
|
27
|
-
cmsFieldTypeEnum,
|
|
28
|
-
cmsFieldSchema,
|
|
29
|
-
cmsBlockSchemaMapSchema,
|
|
30
|
-
createSchemaFromCmsFields,
|
|
31
|
-
createSchemaFromCmsBlocks,
|
|
32
|
-
type CmsFieldType,
|
|
33
|
-
type CmsField,
|
|
34
|
-
type CmsBlockSchema,
|
|
35
|
-
type CmsBlockSchemaMap,
|
|
36
|
-
} from "./schema.ts";
|
|
37
|
-
|
|
38
25
|
// Block registry
|
|
39
26
|
export {
|
|
40
27
|
defineBlock,
|
|
@@ -52,6 +39,7 @@ export {
|
|
|
52
39
|
export {
|
|
53
40
|
renderPage,
|
|
54
41
|
renderBlock,
|
|
42
|
+
type BlockPropsMap,
|
|
55
43
|
type BlockInstance,
|
|
56
44
|
type RegionConfig,
|
|
57
45
|
type PageConfig,
|
package/src/schema.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { z } from "zod/v4";
|
|
2
|
-
|
|
3
|
-
// CMS field type definitions
|
|
4
|
-
export const cmsFieldTypeEnum = z.enum([
|
|
5
|
-
"text",
|
|
6
|
-
"richText",
|
|
7
|
-
"image",
|
|
8
|
-
"link",
|
|
9
|
-
"boolean",
|
|
10
|
-
"select",
|
|
11
|
-
"number",
|
|
12
|
-
"array",
|
|
13
|
-
"object",
|
|
14
|
-
]);
|
|
15
|
-
|
|
16
|
-
// Single CMS field definition
|
|
17
|
-
export const cmsFieldSchema: z.ZodType<CmsField> = z.lazy(() =>
|
|
18
|
-
z.object({
|
|
19
|
-
type: cmsFieldTypeEnum,
|
|
20
|
-
label: z.string(),
|
|
21
|
-
required: z.boolean().optional(),
|
|
22
|
-
defaultValue: z.unknown().optional(),
|
|
23
|
-
// For select fields
|
|
24
|
-
options: z.array(z.object({ label: z.string(), value: z.string() })).optional(),
|
|
25
|
-
// For array fields
|
|
26
|
-
itemSchema: cmsFieldSchema.optional(),
|
|
27
|
-
// For object fields
|
|
28
|
-
fields: z.record(z.string(), cmsFieldSchema).optional(),
|
|
29
|
-
})
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
export type CmsFieldType = z.infer<typeof cmsFieldTypeEnum>;
|
|
33
|
-
|
|
34
|
-
export interface CmsField {
|
|
35
|
-
type: CmsFieldType;
|
|
36
|
-
label: string;
|
|
37
|
-
required?: boolean;
|
|
38
|
-
defaultValue?: unknown;
|
|
39
|
-
options?: { label: string; value: string }[];
|
|
40
|
-
itemSchema?: CmsField;
|
|
41
|
-
fields?: Record<string, CmsField>;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Block schema definition for CMS
|
|
45
|
-
export interface CmsBlockSchema {
|
|
46
|
-
type: string;
|
|
47
|
-
label: string;
|
|
48
|
-
fields: Record<string, CmsField>;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Map of block type -> CMS schema
|
|
52
|
-
export const cmsBlockSchemaMapSchema = z.record(
|
|
53
|
-
z.string(),
|
|
54
|
-
z.object({
|
|
55
|
-
type: z.string(),
|
|
56
|
-
label: z.string(),
|
|
57
|
-
fields: z.record(z.string(), cmsFieldSchema),
|
|
58
|
-
})
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
export type CmsBlockSchemaMap = z.infer<typeof cmsBlockSchemaMapSchema>;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Transform a CMS field definition into a runtime Zod schema
|
|
65
|
-
*/
|
|
66
|
-
function fieldToZod(field: CmsField): z.ZodType {
|
|
67
|
-
let schema: z.ZodType;
|
|
68
|
-
|
|
69
|
-
switch (field.type) {
|
|
70
|
-
case "text":
|
|
71
|
-
schema = z.string();
|
|
72
|
-
break;
|
|
73
|
-
case "richText":
|
|
74
|
-
schema = z.string(); // HTML string
|
|
75
|
-
break;
|
|
76
|
-
case "image":
|
|
77
|
-
schema = z.object({
|
|
78
|
-
src: z.string(),
|
|
79
|
-
alt: z.string(),
|
|
80
|
-
width: z.number().optional(),
|
|
81
|
-
height: z.number().optional(),
|
|
82
|
-
});
|
|
83
|
-
break;
|
|
84
|
-
case "link":
|
|
85
|
-
schema = z.object({
|
|
86
|
-
href: z.string(),
|
|
87
|
-
label: z.string(),
|
|
88
|
-
external: z.boolean().optional(),
|
|
89
|
-
});
|
|
90
|
-
break;
|
|
91
|
-
case "boolean":
|
|
92
|
-
schema = z.boolean();
|
|
93
|
-
break;
|
|
94
|
-
case "select":
|
|
95
|
-
if (field.options && field.options.length > 0) {
|
|
96
|
-
const values = field.options.map((o) => o.value) as [string, ...string[]];
|
|
97
|
-
schema = z.enum(values);
|
|
98
|
-
} else {
|
|
99
|
-
schema = z.string();
|
|
100
|
-
}
|
|
101
|
-
break;
|
|
102
|
-
case "number":
|
|
103
|
-
schema = z.number();
|
|
104
|
-
break;
|
|
105
|
-
case "array":
|
|
106
|
-
if (field.itemSchema) {
|
|
107
|
-
schema = z.array(fieldToZod(field.itemSchema));
|
|
108
|
-
} else {
|
|
109
|
-
schema = z.array(z.unknown());
|
|
110
|
-
}
|
|
111
|
-
break;
|
|
112
|
-
case "object":
|
|
113
|
-
if (field.fields) {
|
|
114
|
-
const shape: Record<string, z.ZodType> = {};
|
|
115
|
-
for (const [key, subField] of Object.entries(field.fields)) {
|
|
116
|
-
shape[key] = fieldToZod(subField);
|
|
117
|
-
}
|
|
118
|
-
schema = z.object(shape);
|
|
119
|
-
} else {
|
|
120
|
-
schema = z.record(z.string(), z.unknown());
|
|
121
|
-
}
|
|
122
|
-
break;
|
|
123
|
-
default:
|
|
124
|
-
schema = z.unknown();
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Apply required/optional
|
|
128
|
-
if (!field.required) {
|
|
129
|
-
schema = schema.optional();
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Apply default if present
|
|
133
|
-
if (field.defaultValue !== undefined) {
|
|
134
|
-
schema = (schema as z.ZodOptional<z.ZodType>).default(field.defaultValue as never);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return schema;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Transform CMS block fields into a Zod object schema
|
|
142
|
-
*/
|
|
143
|
-
export function createSchemaFromCmsFields(
|
|
144
|
-
fields: Record<string, CmsField>
|
|
145
|
-
): z.ZodObject<Record<string, z.ZodType>> {
|
|
146
|
-
const shape: Record<string, z.ZodType> = {};
|
|
147
|
-
for (const [key, field] of Object.entries(fields)) {
|
|
148
|
-
shape[key] = fieldToZod(field);
|
|
149
|
-
}
|
|
150
|
-
return z.object(shape);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Create runtime Zod schemas for all blocks from CMS definitions
|
|
155
|
-
*/
|
|
156
|
-
export function createSchemaFromCmsBlocks(
|
|
157
|
-
blockSchemas: CmsBlockSchemaMap
|
|
158
|
-
): Record<string, z.ZodObject<Record<string, z.ZodType>>> {
|
|
159
|
-
const result: Record<string, z.ZodObject<Record<string, z.ZodType>>> = {};
|
|
160
|
-
for (const [blockType, blockSchema] of Object.entries(blockSchemas)) {
|
|
161
|
-
result[blockType] = createSchemaFromCmsFields(blockSchema.fields);
|
|
162
|
-
}
|
|
163
|
-
return result;
|
|
164
|
-
}
|