Skip to content

Commit 94d31f4

Browse files
committed
Add block.zod.ts for component property schemas and update page.zod.ts references
1 parent 2982d76 commit 94d31f4

File tree

4 files changed

+216
-1
lines changed

4 files changed

+216
-1
lines changed

packages/spec/src/ui/block.zod.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { z } from 'zod';
2+
import { PageComponentType } from './page.zod';
3+
4+
/**
5+
* Empty Properties Schema
6+
*/
7+
const EmptyProps = z.object({});
8+
9+
/**
10+
* ----------------------------------------------------------------------
11+
* 1. Structure Components
12+
* ----------------------------------------------------------------------
13+
*/
14+
15+
export const PageHeaderProps = z.object({
16+
title: z.string().describe('Page title'),
17+
subtitle: z.string().optional().describe('Page subtitle'),
18+
icon: z.string().optional().describe('Icon name'),
19+
breadcrumb: z.boolean().default(true).describe('Show breadcrumb'),
20+
actions: z.array(z.string()).optional().describe('Action IDs to show in header'),
21+
});
22+
23+
export const PageTabsProps = z.object({
24+
type: z.enum(['line', 'card', 'pill']).default('line'),
25+
position: z.enum(['top', 'left']).default('top'),
26+
items: z.array(z.object({
27+
label: z.string(),
28+
icon: z.string().optional(),
29+
children: z.array(z.any()).describe('Child components')
30+
}))
31+
});
32+
33+
export const PageCardProps = z.object({
34+
title: z.string().optional(),
35+
bordered: z.boolean().default(true),
36+
actions: z.array(z.string()).optional(),
37+
children: z.array(z.any()).describe('Card content')
38+
});
39+
40+
/**
41+
* ----------------------------------------------------------------------
42+
* 2. Record Context Components
43+
* ----------------------------------------------------------------------
44+
*/
45+
46+
export const RecordDetailsProps = z.object({
47+
columns: z.enum(['1', '2', '3', '4']).default('2'),
48+
layout: z.enum(['auto', 'custom']).default('auto'),
49+
// If custom layout
50+
sections: z.array(z.string()).optional().describe('Section IDs to show')
51+
});
52+
53+
export const RecordRelatedListProps = z.object({
54+
objectName: z.string().describe('Related object name'),
55+
relationshipField: z.string().describe('Field on related object that points to this record'),
56+
columns: z.array(z.string()).describe('Fields to display'),
57+
sort: z.string().optional(),
58+
limit: z.number().default(5)
59+
});
60+
61+
export const RecordHighlightsProps = z.object({
62+
fields: z.array(z.string()).min(1).max(7).describe('Key fields to highlights (max 7)')
63+
});
64+
65+
/**
66+
* ----------------------------------------------------------------------
67+
* Component Props Map
68+
* Maps Component Type to its Property Schema
69+
* ----------------------------------------------------------------------
70+
*/
71+
export const ComponentPropsMap = {
72+
// Structure
73+
'page:header': PageHeaderProps,
74+
'page:tabs': PageTabsProps,
75+
'page:card': PageCardProps,
76+
'page:footer': EmptyProps,
77+
'page:sidebar': EmptyProps,
78+
'page:accordion': EmptyProps,
79+
'page:section': EmptyProps,
80+
81+
// Record
82+
'record:details': RecordDetailsProps,
83+
'record:related_list': RecordRelatedListProps,
84+
'record:highlights': RecordHighlightsProps,
85+
'record:activity': EmptyProps,
86+
'record:chatter': EmptyProps,
87+
'record:path': EmptyProps,
88+
89+
// Navigation
90+
'app:launcher': EmptyProps,
91+
'nav:menu': EmptyProps,
92+
'nav:breadcrumb': EmptyProps,
93+
94+
// Utility
95+
'global:search': EmptyProps,
96+
'global:notifications': EmptyProps,
97+
'user:profile': EmptyProps,
98+
99+
// AI
100+
'ai:chat_window': z.object({ mode: z.enum(['float', 'sidebar', 'inline']).default('float') }),
101+
'ai:suggestion': z.object({ context: z.string().optional() })
102+
} as const;
103+
104+
/**
105+
* Type Helper to extract props from map
106+
*/
107+
export type ComponentProps<T extends keyof typeof ComponentPropsMap> = z.infer<typeof ComponentPropsMap[T]>;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { z } from 'zod';
2+
import { PageComponentType } from './page.zod';
3+
4+
/**
5+
* Empty Properties Schema
6+
*/
7+
const EmptyProps = z.object({});
8+
9+
/**
10+
* ----------------------------------------------------------------------
11+
* 1. Structure Components
12+
* ----------------------------------------------------------------------
13+
*/
14+
15+
export const PageHeaderProps = z.object({
16+
title: z.string().describe('Page title'),
17+
subtitle: z.string().optional().describe('Page subtitle'),
18+
icon: z.string().optional().describe('Icon name'),
19+
breadcrumb: z.boolean().default(true).describe('Show breadcrumb'),
20+
actions: z.array(z.string()).optional().describe('Action IDs to show in header'),
21+
});
22+
23+
export const PageTabsProps = z.object({
24+
type: z.enum(['line', 'card', 'pill']).default('line'),
25+
position: z.enum(['top', 'left']).default('top'),
26+
items: z.array(z.object({
27+
label: z.string(),
28+
icon: z.string().optional(),
29+
children: z.array(z.any()).describe('Child components')
30+
}))
31+
});
32+
33+
export const PageCardProps = z.object({
34+
title: z.string().optional(),
35+
bordered: z.boolean().default(true),
36+
actions: z.array(z.string()).optional(),
37+
children: z.array(z.any()).describe('Card content')
38+
});
39+
40+
/**
41+
* ----------------------------------------------------------------------
42+
* 2. Record Context Components
43+
* ----------------------------------------------------------------------
44+
*/
45+
46+
export const RecordDetailsProps = z.object({
47+
columns: z.enum(['1', '2', '3', '4']).default('2'),
48+
layout: z.enum(['auto', 'custom']).default('auto'),
49+
// If custom layout
50+
sections: z.array(z.string()).optional().describe('Section IDs to show')
51+
});
52+
53+
export const RecordRelatedListProps = z.object({
54+
objectName: z.string().describe('Related object name'),
55+
relationshipField: z.string().describe('Field on related object that points to this record'),
56+
columns: z.array(z.string()).describe('Fields to display'),
57+
sort: z.string().optional(),
58+
limit: z.number().default(5)
59+
});
60+
61+
export const RecordHighlightsProps = z.object({
62+
fields: z.array(z.string()).min(1).max(7).describe('Key fields to highlights (max 7)')
63+
});
64+
65+
/**
66+
* ----------------------------------------------------------------------
67+
* Component Props Map
68+
* Maps Component Type to its Property Schema
69+
* ----------------------------------------------------------------------
70+
*/
71+
export const ComponentPropsMap = {
72+
// Structure
73+
'page:header': PageHeaderProps,
74+
'page:tabs': PageTabsProps,
75+
'page:card': PageCardProps,
76+
'page:footer': EmptyProps,
77+
'page:sidebar': EmptyProps,
78+
'page:accordion': EmptyProps,
79+
'page:section': EmptyProps,
80+
81+
// Record
82+
'record:details': RecordDetailsProps,
83+
'record:related_list': RecordRelatedListProps,
84+
'record:highlights': RecordHighlightsProps,
85+
'record:activity': EmptyProps,
86+
'record:chatter': EmptyProps,
87+
'record:path': EmptyProps,
88+
89+
// Navigation
90+
'app:launcher': EmptyProps,
91+
'nav:menu': EmptyProps,
92+
'nav:breadcrumb': EmptyProps,
93+
94+
// Utility
95+
'global:search': EmptyProps,
96+
'global:notifications': EmptyProps,
97+
'user:profile': EmptyProps,
98+
99+
// AI
100+
'ai:chat_window': z.object({ mode: z.enum(['float', 'sidebar', 'inline']).default('float') }),
101+
'ai:suggestion': z.object({ context: z.string().optional() })
102+
} as const;
103+
104+
/**
105+
* Type Helper to extract props from map
106+
*/
107+
export type ComponentProps<T extends keyof typeof ComponentPropsMap> = z.infer<typeof ComponentPropsMap[T]>;

packages/spec/src/ui/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ export * from './report.zod';
1414
export * from './action.zod';
1515
export * from './page.zod';
1616
export * from './widget.zod';
17+
export * from './block.zod';
1718
export * from './theme.zod';

packages/spec/src/ui/page.zod.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const PageComponentSchema = z.object({
4141

4242
/** Configuration */
4343
label: z.string().optional(),
44-
properties: z.record(z.any()).describe('Component props passed to the widget'),
44+
properties: z.record(z.any()).describe('Component props passed to the widget. See block.zod.ts for schemas.'),
4545

4646
/** Visibility Rule */
4747
visibility: z.string().optional().describe('Visibility filter/formula')

0 commit comments

Comments
 (0)