@upstart.gg/sdk 0.0.137 → 0.0.138
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/dist/shared/ai/schemas.js +2 -2
- package/dist/shared/ai/schemas.js.map +1 -1
- package/dist/shared/ai/types.d.ts +2 -2
- package/dist/shared/ai/types.d.ts.map +1 -1
- package/dist/shared/ajv.js +26 -25
- package/dist/shared/ajv.js.map +1 -1
- package/dist/shared/attributes.d.ts +8 -0
- package/dist/shared/attributes.d.ts.map +1 -1
- package/dist/shared/attributes.js +15 -14
- package/dist/shared/brick-manifest.js +2 -2
- package/dist/shared/bricks/manifests/accordion.manifest.js +8 -7
- package/dist/shared/bricks/manifests/all-manifests.js +38 -37
- package/dist/shared/bricks/manifests/all-props.d.ts +32 -22
- package/dist/shared/bricks/manifests/all-props.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/all-props.js +40 -39
- package/dist/shared/bricks/manifests/all-props.js.map +1 -1
- package/dist/shared/bricks/manifests/box.manifest.js +11 -10
- package/dist/shared/bricks/manifests/button.manifest.js +10 -9
- package/dist/shared/bricks/manifests/card.manifest.d.ts +2 -0
- package/dist/shared/bricks/manifests/card.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/card.manifest.js +13 -12
- package/dist/shared/bricks/manifests/carousel.manifest.d.ts +1 -0
- package/dist/shared/bricks/manifests/carousel.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/carousel.manifest.js +11 -10
- package/dist/shared/bricks/manifests/footer.manifest.d.ts +2 -0
- package/dist/shared/bricks/manifests/footer.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/footer.manifest.js +9 -8
- package/dist/shared/bricks/manifests/form.manifest.js +9 -8
- package/dist/shared/bricks/manifests/hero.manifest.d.ts +2 -4
- package/dist/shared/bricks/manifests/hero.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/hero.manifest.js +10 -9
- package/dist/shared/bricks/manifests/html.manifest.d.ts +1 -0
- package/dist/shared/bricks/manifests/html.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/html.manifest.js +6 -5
- package/dist/shared/bricks/manifests/icon.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/icon.manifest.js +9 -8
- package/dist/shared/bricks/manifests/image.manifest.d.ts +1 -0
- package/dist/shared/bricks/manifests/image.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/image.manifest.js +12 -11
- package/dist/shared/bricks/manifests/images-gallery.manifest.d.ts +2 -0
- package/dist/shared/bricks/manifests/images-gallery.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/images-gallery.manifest.js +11 -10
- package/dist/shared/bricks/manifests/map.manifest.d.ts +1 -0
- package/dist/shared/bricks/manifests/map.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/map.manifest.js +9 -8
- package/dist/shared/bricks/manifests/navbar.manifest.d.ts +2 -0
- package/dist/shared/bricks/manifests/navbar.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/navbar.manifest.js +11 -10
- package/dist/shared/bricks/manifests/sidebar.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/sidebar.manifest.js +11 -10
- package/dist/shared/bricks/manifests/social-links.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/social-links.manifest.js +10 -9
- package/dist/shared/bricks/manifests/spacer.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/spacer.manifest.js +6 -5
- package/dist/shared/bricks/manifests/table.manifest.d.ts +1 -0
- package/dist/shared/bricks/manifests/table.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/table.manifest.js +10 -9
- package/dist/shared/bricks/manifests/tabs.manifest.d.ts +1 -1
- package/dist/shared/bricks/manifests/tabs.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/tabs.manifest.js +11 -10
- package/dist/shared/bricks/manifests/testimonials.manifest.d.ts +3 -1
- package/dist/shared/bricks/manifests/testimonials.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/testimonials.manifest.js +13 -12
- package/dist/shared/bricks/manifests/text.manifest.d.ts +2 -5
- package/dist/shared/bricks/manifests/text.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/text.manifest.js +10 -9
- package/dist/shared/bricks/manifests/timeline.manifest.js +11 -10
- package/dist/shared/bricks/manifests/video.manifest.js +9 -8
- package/dist/shared/bricks/props/background.d.ts.map +1 -1
- package/dist/shared/bricks/props/background.js +1 -1
- package/dist/shared/bricks/props/border.js +2 -2
- package/dist/shared/bricks/props/color.d.ts.map +1 -1
- package/dist/shared/bricks/props/color.js +1 -1
- package/dist/shared/bricks/props/common.d.ts.map +1 -1
- package/dist/shared/bricks/props/common.js +2 -1
- package/dist/shared/bricks/props/grow.d.ts +3 -0
- package/dist/shared/bricks/props/grow.d.ts.map +1 -0
- package/dist/shared/bricks/props/grow.js +10 -0
- package/dist/shared/bricks/props/grow.js.map +1 -0
- package/dist/shared/bricks/props/helpers.js +3 -2
- package/dist/shared/bricks/props/image.d.ts +1 -0
- package/dist/shared/bricks/props/image.d.ts.map +1 -1
- package/dist/shared/bricks/props/image.js +1 -1
- package/dist/shared/bricks/props/string.d.ts.map +1 -1
- package/dist/shared/bricks/props/string.js +1 -1
- package/dist/shared/bricks.d.ts +18 -17
- package/dist/shared/bricks.d.ts.map +1 -1
- package/dist/shared/bricks.js +39 -38
- package/dist/shared/chunk-2EOCK66Z.js +19 -0
- package/dist/shared/chunk-2EOCK66Z.js.map +1 -0
- package/dist/shared/{chunk-XXPSM6UA.js → chunk-2UEPTT5J.js} +5 -9
- package/dist/shared/chunk-2UEPTT5J.js.map +1 -0
- package/dist/shared/{chunk-DRQKKPTX.js → chunk-2Z5WOCFS.js} +41 -1
- package/dist/shared/chunk-2Z5WOCFS.js.map +1 -0
- package/dist/shared/{chunk-7U5WPHXB.js → chunk-34IUWNRX.js} +7 -7
- package/dist/shared/chunk-57NRTXRA.js +309 -0
- package/dist/shared/chunk-57NRTXRA.js.map +1 -0
- package/dist/shared/{chunk-T6C3NG2L.js → chunk-5HJT5NJ3.js} +8 -8
- package/dist/shared/{chunk-BZTWZC77.js → chunk-5J4Y43RM.js} +37 -179
- package/dist/shared/chunk-5J4Y43RM.js.map +1 -0
- package/dist/shared/{chunk-KKWT3OXF.js → chunk-5OVOXUFX.js} +3 -2
- package/dist/shared/{chunk-KKWT3OXF.js.map → chunk-5OVOXUFX.js.map} +1 -1
- package/dist/shared/{chunk-XK2CERPB.js → chunk-5SNSUC6Q.js} +7 -7
- package/dist/shared/{chunk-JLDAS3VE.js → chunk-B5T2LFV2.js} +10 -14
- package/dist/shared/chunk-B5T2LFV2.js.map +1 -0
- package/dist/shared/{chunk-PF75LW33.js → chunk-E3ZW57HF.js} +18 -9
- package/dist/shared/chunk-E3ZW57HF.js.map +1 -0
- package/dist/shared/{chunk-JSDKK5QN.js → chunk-EUFVTHAG.js} +5 -3
- package/dist/shared/chunk-EUFVTHAG.js.map +1 -0
- package/dist/shared/{chunk-U4KZUX37.js → chunk-FC52EHCC.js} +8 -8
- package/dist/shared/chunk-FC52EHCC.js.map +1 -0
- package/dist/shared/{chunk-JW7MQAU4.js → chunk-FVV27R73.js} +9 -94
- package/dist/shared/chunk-FVV27R73.js.map +1 -0
- package/dist/shared/{chunk-SQXZNGQF.js → chunk-FYGFB5U5.js} +3 -1
- package/dist/shared/chunk-FYGFB5U5.js.map +1 -0
- package/dist/shared/{chunk-J45LSQT6.js → chunk-GNTJT7MR.js} +2 -2
- package/dist/shared/chunk-HHUFGV7J.js +259 -0
- package/dist/shared/chunk-HHUFGV7J.js.map +1 -0
- package/dist/shared/{chunk-W2RFDII5.js → chunk-IMDOF55E.js} +12 -4
- package/dist/shared/chunk-IMDOF55E.js.map +1 -0
- package/dist/shared/{chunk-KQH6V22E.js → chunk-IPWYNE6Y.js} +25 -25
- package/dist/shared/{chunk-H6TMBELF.js → chunk-J6R3GSKS.js} +46 -34
- package/dist/shared/chunk-J6R3GSKS.js.map +1 -0
- package/dist/shared/{chunk-TBT2PTGB.js → chunk-KRODRZNS.js} +9 -9
- package/dist/shared/chunk-KTA7XES3.js +168 -0
- package/dist/shared/chunk-KTA7XES3.js.map +1 -0
- package/dist/shared/{chunk-SK2O7GFC.js → chunk-L4W4B2RQ.js} +15 -70
- package/dist/shared/chunk-L4W4B2RQ.js.map +1 -0
- package/dist/shared/{chunk-MYOLWTB2.js → chunk-NTP6BKRU.js} +9 -9
- package/dist/shared/chunk-NTP6BKRU.js.map +1 -0
- package/dist/shared/{chunk-JF52BBFD.js → chunk-O53V22BK.js} +18 -10
- package/dist/shared/chunk-O53V22BK.js.map +1 -0
- package/dist/shared/{chunk-ZVJNRKT4.js → chunk-ORIUCOED.js} +7 -7
- package/dist/shared/{chunk-LGDDJJHK.js → chunk-PFZMRSHJ.js} +11 -11
- package/dist/shared/{chunk-6AE7UD73.js → chunk-QHKOAIOK.js} +31 -60
- package/dist/shared/chunk-QHKOAIOK.js.map +1 -0
- package/dist/shared/{chunk-LPAQ47C6.js → chunk-RDOCVLCF.js} +11 -11
- package/dist/shared/{chunk-VSLRTXLF.js → chunk-RFH7PEVS.js} +5 -4
- package/dist/shared/chunk-RFH7PEVS.js.map +1 -0
- package/dist/shared/{chunk-XNRSL6FL.js → chunk-T3UPW5OW.js} +5 -4
- package/dist/shared/{chunk-XNRSL6FL.js.map → chunk-T3UPW5OW.js.map} +1 -1
- package/dist/shared/{chunk-FUUSAMN3.js → chunk-TGKNA2JS.js} +8 -8
- package/dist/shared/{chunk-HY7JOP3J.js → chunk-TZ6X7ZM5.js} +19 -11
- package/dist/shared/chunk-TZ6X7ZM5.js.map +1 -0
- package/dist/shared/{chunk-VTCHJT4O.js → chunk-UC75KRLX.js} +2 -2
- package/dist/shared/{chunk-4KY7OZWD.js → chunk-VMIJ6MG5.js} +13 -13
- package/dist/shared/{chunk-SRYBJ6NQ.js → chunk-VYA2FCTY.js} +2 -2
- package/dist/shared/{chunk-LGGPCCCY.js → chunk-XYWSIMZ6.js} +3 -3
- package/dist/shared/chunk-XYWSIMZ6.js.map +1 -0
- package/dist/shared/{chunk-FHA4DFIM.js → chunk-ZYQZUWF7.js} +10 -10
- package/dist/shared/{chunk-2O5HVPID.js → chunk-ZZVYD4BG.js} +3 -3
- package/dist/shared/context.d.ts +4 -0
- package/dist/shared/context.d.ts.map +1 -1
- package/dist/shared/context.js +43 -42
- package/dist/shared/context.js.map +1 -1
- package/dist/shared/page.d.ts +2 -0
- package/dist/shared/page.d.ts.map +1 -1
- package/dist/shared/page.js +41 -40
- package/dist/shared/site.d.ts +7 -0
- package/dist/shared/site.d.ts.map +1 -1
- package/dist/shared/site.js +43 -42
- package/dist/shared/sitemap.js +42 -41
- package/dist/shared/utils/schema.d.ts +0 -5
- package/dist/shared/utils/schema.d.ts.map +1 -1
- package/dist/shared/utils/schema.js +1 -3
- package/package.json +2 -2
- package/src/shared/ai/schemas.ts +1 -1
- package/src/shared/ai/types.ts +2 -2
- package/src/shared/bricks/manifests/card.manifest.ts +25 -168
- package/src/shared/bricks/manifests/hero.manifest.ts +44 -249
- package/src/shared/bricks/manifests/html.manifest.ts +6 -0
- package/src/shared/bricks/manifests/icon.manifest.ts +1 -89
- package/src/shared/bricks/manifests/image.manifest.ts +0 -4
- package/src/shared/bricks/manifests/images-gallery.manifest.ts +8 -0
- package/src/shared/bricks/manifests/map.manifest.ts +9 -65
- package/src/shared/bricks/manifests/sidebar.manifest.ts +0 -1
- package/src/shared/bricks/manifests/social-links.manifest.ts +0 -1
- package/src/shared/bricks/manifests/spacer.manifest.ts +0 -1
- package/src/shared/bricks/manifests/table.manifest.ts +6 -0
- package/src/shared/bricks/manifests/tabs.manifest.ts +12 -429
- package/src/shared/bricks/manifests/testimonials.manifest.ts +28 -226
- package/src/shared/bricks/manifests/text.manifest.ts +16 -44
- package/src/shared/bricks/props/background.ts +2 -1
- package/src/shared/bricks/props/color.ts +5 -2
- package/src/shared/bricks/props/common.ts +2 -8
- package/src/shared/bricks/props/grow.ts +11 -0
- package/src/shared/bricks/props/image.ts +40 -0
- package/src/shared/bricks/props/string.ts +2 -0
- package/src/shared/bricks.ts +33 -23
- package/src/shared/page.ts +1 -0
- package/src/shared/site.ts +1 -0
- package/src/shared/utils/schema.ts +28 -18
- package/src/shared/utils/tests/schema.test.ts +211 -4
- package/dist/shared/chunk-6AE7UD73.js.map +0 -1
- package/dist/shared/chunk-BZTWZC77.js.map +0 -1
- package/dist/shared/chunk-DRQKKPTX.js.map +0 -1
- package/dist/shared/chunk-H6TMBELF.js.map +0 -1
- package/dist/shared/chunk-HUWMIXNN.js +0 -570
- package/dist/shared/chunk-HUWMIXNN.js.map +0 -1
- package/dist/shared/chunk-HY7JOP3J.js.map +0 -1
- package/dist/shared/chunk-JF52BBFD.js.map +0 -1
- package/dist/shared/chunk-JLDAS3VE.js.map +0 -1
- package/dist/shared/chunk-JSDKK5QN.js.map +0 -1
- package/dist/shared/chunk-JW7MQAU4.js.map +0 -1
- package/dist/shared/chunk-LGGPCCCY.js.map +0 -1
- package/dist/shared/chunk-MYOLWTB2.js.map +0 -1
- package/dist/shared/chunk-O24RDXZS.js +0 -505
- package/dist/shared/chunk-O24RDXZS.js.map +0 -1
- package/dist/shared/chunk-PF75LW33.js.map +0 -1
- package/dist/shared/chunk-QEJGPYTB.js +0 -462
- package/dist/shared/chunk-QEJGPYTB.js.map +0 -1
- package/dist/shared/chunk-SK2O7GFC.js.map +0 -1
- package/dist/shared/chunk-SQXZNGQF.js.map +0 -1
- package/dist/shared/chunk-U4KZUX37.js.map +0 -1
- package/dist/shared/chunk-VSLRTXLF.js.map +0 -1
- package/dist/shared/chunk-W2RFDII5.js.map +0 -1
- package/dist/shared/chunk-XXPSM6UA.js.map +0 -1
- /package/dist/shared/{chunk-7U5WPHXB.js.map → chunk-34IUWNRX.js.map} +0 -0
- /package/dist/shared/{chunk-T6C3NG2L.js.map → chunk-5HJT5NJ3.js.map} +0 -0
- /package/dist/shared/{chunk-XK2CERPB.js.map → chunk-5SNSUC6Q.js.map} +0 -0
- /package/dist/shared/{chunk-J45LSQT6.js.map → chunk-GNTJT7MR.js.map} +0 -0
- /package/dist/shared/{chunk-KQH6V22E.js.map → chunk-IPWYNE6Y.js.map} +0 -0
- /package/dist/shared/{chunk-TBT2PTGB.js.map → chunk-KRODRZNS.js.map} +0 -0
- /package/dist/shared/{chunk-ZVJNRKT4.js.map → chunk-ORIUCOED.js.map} +0 -0
- /package/dist/shared/{chunk-LGDDJJHK.js.map → chunk-PFZMRSHJ.js.map} +0 -0
- /package/dist/shared/{chunk-LPAQ47C6.js.map → chunk-RDOCVLCF.js.map} +0 -0
- /package/dist/shared/{chunk-FUUSAMN3.js.map → chunk-TGKNA2JS.js.map} +0 -0
- /package/dist/shared/{chunk-VTCHJT4O.js.map → chunk-UC75KRLX.js.map} +0 -0
- /package/dist/shared/{chunk-4KY7OZWD.js.map → chunk-VMIJ6MG5.js.map} +0 -0
- /package/dist/shared/{chunk-SRYBJ6NQ.js.map → chunk-VYA2FCTY.js.map} +0 -0
- /package/dist/shared/{chunk-FHA4DFIM.js.map → chunk-ZYQZUWF7.js.map} +0 -0
- /package/dist/shared/{chunk-2O5HVPID.js.map → chunk-ZZVYD4BG.js.map} +0 -0
package/src/shared/bricks.ts
CHANGED
|
@@ -101,15 +101,36 @@ export const brickSchema = Type.Object({
|
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
export function makeFullBrickSchemaForLLM(type: string, otherTypes?: string[]) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
if (!otherTypes || !otherTypes.length) {
|
|
105
|
+
return toLLMSchema(
|
|
106
|
+
Type.Object(
|
|
107
|
+
{
|
|
108
|
+
id: Type.String({
|
|
109
|
+
title: "ID",
|
|
110
|
+
description: "A unique identifier for the brick.",
|
|
111
|
+
}),
|
|
112
|
+
type: Type.Literal(type),
|
|
113
|
+
props: manifests[type].props,
|
|
114
|
+
mobileProps: Type.Optional(Type.Partial(manifests[type].props)),
|
|
115
|
+
},
|
|
116
|
+
// IMPORTANT: DO NOT set "additionalProperties" to `false` because it would break validation with Cabidela library
|
|
117
|
+
// { additionalProperties: false },
|
|
118
|
+
),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return toLLMSchema(
|
|
122
|
+
Type.Object(
|
|
123
|
+
{
|
|
124
|
+
id: Type.String({
|
|
125
|
+
title: "ID",
|
|
126
|
+
description: "A unique identifier for the brick.",
|
|
127
|
+
}),
|
|
128
|
+
type: Type.Literal(type),
|
|
129
|
+
props: Type.Composite([
|
|
130
|
+
brickSchema.properties.props,
|
|
131
|
+
Type.Object({
|
|
132
|
+
$children: Type.Array(
|
|
133
|
+
Type.Union(
|
|
113
134
|
otherTypes.map((t) =>
|
|
114
135
|
Type.Object({
|
|
115
136
|
id: Type.String({
|
|
@@ -122,20 +143,9 @@ export function makeFullBrickSchemaForLLM(type: string, otherTypes?: string[]) {
|
|
|
122
143
|
}),
|
|
123
144
|
),
|
|
124
145
|
),
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
])
|
|
129
|
-
: manifests[type].props;
|
|
130
|
-
return toLLMSchema(
|
|
131
|
-
Type.Object(
|
|
132
|
-
{
|
|
133
|
-
id: Type.String({
|
|
134
|
-
title: "ID",
|
|
135
|
-
description: "A unique identifier for the brick.",
|
|
136
|
-
}),
|
|
137
|
-
type: Type.Literal(type),
|
|
138
|
-
props,
|
|
146
|
+
),
|
|
147
|
+
}),
|
|
148
|
+
]),
|
|
139
149
|
mobileProps: Type.Optional(Type.Partial(manifests[type].props)),
|
|
140
150
|
},
|
|
141
151
|
// IMPORTANT: DO NOT set "additionalProperties" to `false` because it would break validation with Cabidela library
|
package/src/shared/page.ts
CHANGED
|
@@ -6,6 +6,7 @@ export const pageSchema = Type.Object({
|
|
|
6
6
|
id: Type.String({
|
|
7
7
|
description: "The unique ID of the page. Use a human readable url-safe slug",
|
|
8
8
|
examples: ["home", "about-us", "products-list"],
|
|
9
|
+
pattern: "^[a-z0-9-_]+$",
|
|
9
10
|
}),
|
|
10
11
|
label: Type.String({
|
|
11
12
|
description: "The label (name) of the page",
|
package/src/shared/site.ts
CHANGED
|
@@ -73,18 +73,27 @@ export function getSchemaDefaults<T extends TObject | TArray>(
|
|
|
73
73
|
// Handle object schemas
|
|
74
74
|
if (schema.type === "object" && "properties" in schema) {
|
|
75
75
|
const objectSchema = schema as TObject;
|
|
76
|
-
const
|
|
76
|
+
const required = objectSchema.required || [];
|
|
77
77
|
|
|
78
|
+
// First pass: collect all properties that have defaults
|
|
79
|
+
const propertiesWithDefaults: Record<string, unknown> = {};
|
|
78
80
|
for (const [key, propertySchema] of Object.entries(objectSchema.properties)) {
|
|
79
81
|
const defaultValue = getNestedDefaults(propertySchema as TSchema, mode);
|
|
80
|
-
|
|
81
|
-
// Only include properties that have explicit defaults
|
|
82
82
|
if (defaultValue !== undefined) {
|
|
83
|
-
|
|
83
|
+
propertiesWithDefaults[key] = defaultValue;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
// Second pass: validate that all required properties have defaults
|
|
88
|
+
// If any required property lacks a default, return empty object
|
|
89
|
+
for (const requiredProp of required) {
|
|
90
|
+
if (!(requiredProp in propertiesWithDefaults)) {
|
|
91
|
+
return {} as Static<T>;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// If we get here, all required properties have defaults, so we can include all properties
|
|
96
|
+
return propertiesWithDefaults as Static<T>;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
// Handle array schemas
|
|
@@ -120,18 +129,28 @@ function getNestedDefaults(schema: TSchema, mode?: "mobile" | "desktop"): unknow
|
|
|
120
129
|
// Handle nested object schemas
|
|
121
130
|
if (schema.type === "object" && "properties" in schema) {
|
|
122
131
|
const objectSchema = schema as TObject;
|
|
132
|
+
const required = objectSchema.required || [];
|
|
123
133
|
const defaults: Record<string, unknown> = {};
|
|
124
134
|
|
|
135
|
+
// First pass: collect all properties that have defaults
|
|
136
|
+
const propertiesWithDefaults: Record<string, unknown> = {};
|
|
125
137
|
for (const [key, propertySchema] of Object.entries(objectSchema.properties)) {
|
|
126
138
|
const defaultValue = getNestedDefaults(propertySchema as TSchema, mode);
|
|
127
|
-
|
|
128
|
-
// Only include properties that have explicit defaults
|
|
129
139
|
if (defaultValue !== undefined) {
|
|
130
|
-
|
|
140
|
+
propertiesWithDefaults[key] = defaultValue;
|
|
131
141
|
}
|
|
132
142
|
}
|
|
133
143
|
|
|
134
|
-
|
|
144
|
+
// Second pass: validate that all required properties have defaults
|
|
145
|
+
// If any required property lacks a default, this nested object cannot be included
|
|
146
|
+
for (const requiredProp of required) {
|
|
147
|
+
if (!(requiredProp in propertiesWithDefaults)) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// If we get here, all required properties have defaults
|
|
153
|
+
return Object.keys(propertiesWithDefaults).length > 0 ? propertiesWithDefaults : undefined;
|
|
135
154
|
}
|
|
136
155
|
|
|
137
156
|
// Handle nested array schemas
|
|
@@ -167,15 +186,6 @@ export function filterSchemaProperties(schema: TObject, filter: (prop: TSchema)
|
|
|
167
186
|
return extractProperties(schema);
|
|
168
187
|
}
|
|
169
188
|
|
|
170
|
-
/**
|
|
171
|
-
* Resolves a JSON schema by following $ref references recursively.
|
|
172
|
-
* Handles nested objects, arrays, and complex schema structures.
|
|
173
|
-
*/
|
|
174
|
-
export function resolveSchema<T extends TSchema = TSchema>(schema: T): T {
|
|
175
|
-
console.warn("resolveSchema is deprecated, use resolveSchemaRecursive instead");
|
|
176
|
-
return schema;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
189
|
export function validate<T extends TSchema>(schema: TSchema, data: unknown): Static<T> {
|
|
180
190
|
try {
|
|
181
191
|
const valid = Value.Check(schema, data);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach } from "vitest";
|
|
2
2
|
import { type Static, Type } from "@sinclair/typebox";
|
|
3
|
-
import {
|
|
3
|
+
import { validate, getSchemaDefaults } from "../schema";
|
|
4
4
|
import { toLLMSchema } from "../llm";
|
|
5
5
|
import { sitemapSchema } from "~/shared/sitemap";
|
|
6
6
|
import type { Manifest } from "~/shared/bricks/manifests/text.manifest";
|
|
@@ -424,6 +424,215 @@ describe("toLLMSchema consistency", () => {
|
|
|
424
424
|
});
|
|
425
425
|
});
|
|
426
426
|
|
|
427
|
+
describe("getSchemaDefaults", () => {
|
|
428
|
+
test("should not generate partial objects when required properties lack defaults", () => {
|
|
429
|
+
// Schema with mixed required/optional properties and defaults
|
|
430
|
+
const problematicSchema = Type.Object(
|
|
431
|
+
{
|
|
432
|
+
requiredWithoutDefault: Type.String(), // Required but no default
|
|
433
|
+
optionalWithDefault: Type.Optional(Type.String({ default: "has default" })), // Optional with default
|
|
434
|
+
requiredWithDefault: Type.String({ default: "required default" }), // Required with default
|
|
435
|
+
nested: Type.Object(
|
|
436
|
+
{
|
|
437
|
+
nestedRequired: Type.String(), // Required but no default
|
|
438
|
+
nestedOptionalWithDefault: Type.Optional(Type.String({ default: "nested default" })), // Optional with default
|
|
439
|
+
},
|
|
440
|
+
{ required: ["nestedRequired"] },
|
|
441
|
+
), // Make nestedRequired actually required
|
|
442
|
+
},
|
|
443
|
+
{ required: ["requiredWithoutDefault", "requiredWithDefault", "nested"] },
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
const result = getSchemaDefaults(problematicSchema);
|
|
447
|
+
|
|
448
|
+
// Should not include nested object since nestedRequired lacks a default
|
|
449
|
+
// Should not include the root object at all since requiredWithoutDefault lacks a default
|
|
450
|
+
expect(result).toEqual({});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test("should generate complete objects when all required properties have defaults", () => {
|
|
454
|
+
const validSchema = Type.Object(
|
|
455
|
+
{
|
|
456
|
+
requiredWithDefault: Type.String({ default: "required default" }),
|
|
457
|
+
optionalWithDefault: Type.Optional(Type.String({ default: "optional default" })),
|
|
458
|
+
nested: Type.Object(
|
|
459
|
+
{
|
|
460
|
+
nestedRequiredWithDefault: Type.String({ default: "nested required default" }),
|
|
461
|
+
nestedOptionalWithDefault: Type.Optional(Type.String({ default: "nested optional default" })),
|
|
462
|
+
},
|
|
463
|
+
{ required: ["nestedRequiredWithDefault"] },
|
|
464
|
+
),
|
|
465
|
+
},
|
|
466
|
+
{ required: ["requiredWithDefault", "nested"] },
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const result = getSchemaDefaults(validSchema);
|
|
470
|
+
|
|
471
|
+
expect(result).toEqual({
|
|
472
|
+
requiredWithDefault: "required default",
|
|
473
|
+
optionalWithDefault: "optional default",
|
|
474
|
+
nested: {
|
|
475
|
+
nestedRequiredWithDefault: "nested required default",
|
|
476
|
+
nestedOptionalWithDefault: "nested optional default",
|
|
477
|
+
},
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("should handle schemas with no required properties", () => {
|
|
482
|
+
const allOptionalSchema = Type.Object({
|
|
483
|
+
optional1: Type.Optional(Type.String({ default: "default1" })),
|
|
484
|
+
optional2: Type.Optional(Type.String({ default: "default2" })),
|
|
485
|
+
optional3: Type.Optional(Type.String()), // No default
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
const result = getSchemaDefaults(allOptionalSchema);
|
|
489
|
+
|
|
490
|
+
expect(result).toEqual({
|
|
491
|
+
optional1: "default1",
|
|
492
|
+
optional2: "default2",
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
test("should handle deeply nested objects with mixed required properties", () => {
|
|
497
|
+
const deepSchema = Type.Object(
|
|
498
|
+
{
|
|
499
|
+
level1: Type.Object(
|
|
500
|
+
{
|
|
501
|
+
level2Required: Type.String({ default: "level2 default" }),
|
|
502
|
+
level2Optional: Type.Optional(Type.String({ default: "level2 optional" })),
|
|
503
|
+
level2: Type.Object(
|
|
504
|
+
{
|
|
505
|
+
level3Required: Type.String(), // Missing default - should break the chain
|
|
506
|
+
level3WithDefault: Type.String({ default: "level3 default" }),
|
|
507
|
+
},
|
|
508
|
+
{ required: ["level3Required"] },
|
|
509
|
+
),
|
|
510
|
+
},
|
|
511
|
+
{ required: ["level2Required", "level2"] },
|
|
512
|
+
),
|
|
513
|
+
},
|
|
514
|
+
{ required: ["level1"] },
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
const result = getSchemaDefaults(deepSchema);
|
|
518
|
+
|
|
519
|
+
// Should return empty because level3Required lacks a default, making level2 invalid,
|
|
520
|
+
// which makes level1 invalid, which makes the root invalid
|
|
521
|
+
expect(result).toEqual({});
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
test("should handle schema with only required properties that all have defaults", () => {
|
|
525
|
+
const allRequiredSchema = Type.Object(
|
|
526
|
+
{
|
|
527
|
+
required1: Type.String({ default: "default1" }),
|
|
528
|
+
required2: Type.Number({ default: 42 }),
|
|
529
|
+
required3: Type.Boolean({ default: true }),
|
|
530
|
+
},
|
|
531
|
+
{ required: ["required1", "required2", "required3"] },
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
const result = getSchemaDefaults(allRequiredSchema);
|
|
535
|
+
|
|
536
|
+
expect(result).toEqual({
|
|
537
|
+
required1: "default1",
|
|
538
|
+
required2: 42,
|
|
539
|
+
required3: true,
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
test("should handle empty required array", () => {
|
|
544
|
+
const schema = Type.Object(
|
|
545
|
+
{
|
|
546
|
+
prop1: Type.String({ default: "default1" }),
|
|
547
|
+
prop2: Type.Optional(Type.String({ default: "default2" })),
|
|
548
|
+
},
|
|
549
|
+
{ required: [] },
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const result = getSchemaDefaults(schema);
|
|
553
|
+
|
|
554
|
+
expect(result).toEqual({
|
|
555
|
+
prop1: "default1",
|
|
556
|
+
prop2: "default2",
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test("should handle mobile/desktop mode defaults", () => {
|
|
561
|
+
const schemaWithModes = Type.Object(
|
|
562
|
+
{
|
|
563
|
+
requiredProp: Type.String({
|
|
564
|
+
default: "desktop default",
|
|
565
|
+
"default:mobile": "mobile default",
|
|
566
|
+
}),
|
|
567
|
+
optionalProp: Type.Optional(
|
|
568
|
+
Type.String({
|
|
569
|
+
default: "desktop optional",
|
|
570
|
+
"default:mobile": "mobile optional",
|
|
571
|
+
}),
|
|
572
|
+
),
|
|
573
|
+
},
|
|
574
|
+
{ required: ["requiredProp"] },
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
const desktopResult = getSchemaDefaults(schemaWithModes, "desktop");
|
|
578
|
+
const mobileResult = getSchemaDefaults(schemaWithModes, "mobile");
|
|
579
|
+
|
|
580
|
+
expect(desktopResult).toEqual({
|
|
581
|
+
requiredProp: "desktop default",
|
|
582
|
+
optionalProp: "desktop optional",
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
expect(mobileResult).toEqual({
|
|
586
|
+
requiredProp: "mobile default",
|
|
587
|
+
optionalProp: "mobile optional",
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
test("should handle mobile/desktop mode with missing mobile defaults", () => {
|
|
592
|
+
const schemaWithPartialModes = Type.Object(
|
|
593
|
+
{
|
|
594
|
+
requiredProp: Type.String({
|
|
595
|
+
default: "desktop default",
|
|
596
|
+
// No mobile default - should fallback to desktop
|
|
597
|
+
}),
|
|
598
|
+
optionalProp: Type.Optional(
|
|
599
|
+
Type.String({
|
|
600
|
+
default: "desktop optional",
|
|
601
|
+
"default:mobile": "mobile optional",
|
|
602
|
+
}),
|
|
603
|
+
),
|
|
604
|
+
},
|
|
605
|
+
{ required: ["requiredProp"] },
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
const mobileResult = getSchemaDefaults(schemaWithPartialModes, "mobile");
|
|
609
|
+
|
|
610
|
+
expect(mobileResult).toEqual({
|
|
611
|
+
requiredProp: "desktop default", // Falls back to desktop default
|
|
612
|
+
optionalProp: "mobile optional", // Uses mobile default
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
test("should handle arrays with defaults", () => {
|
|
617
|
+
const arraySchema = Type.Array(Type.String(), { default: ["item1", "item2"] });
|
|
618
|
+
const result = getSchemaDefaults(arraySchema);
|
|
619
|
+
expect(result).toEqual(["item1", "item2"]);
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
test("should handle arrays with mobile/desktop defaults", () => {
|
|
623
|
+
const arraySchemaWithModes = Type.Array(Type.String(), {
|
|
624
|
+
default: ["desktop1", "desktop2"],
|
|
625
|
+
"default:mobile": ["mobile1", "mobile2"],
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
const desktopResult = getSchemaDefaults(arraySchemaWithModes, "desktop");
|
|
629
|
+
const mobileResult = getSchemaDefaults(arraySchemaWithModes, "mobile");
|
|
630
|
+
|
|
631
|
+
expect(desktopResult).toEqual(["desktop1", "desktop2"]);
|
|
632
|
+
expect(mobileResult).toEqual(["mobile1", "mobile2"]);
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
|
|
427
636
|
describe("validation with validate()", () => {
|
|
428
637
|
test("should validate correct schema with @sinclair/typebox", () => {
|
|
429
638
|
const sectionSchemaLLM = toLLMSchema(sectionSchema);
|
|
@@ -535,9 +744,7 @@ describe("validation with validate()", () => {
|
|
|
535
744
|
content: "Hello, world!",
|
|
536
745
|
},
|
|
537
746
|
mobileProps: {
|
|
538
|
-
|
|
539
|
-
color: "primary-100",
|
|
540
|
-
},
|
|
747
|
+
color: "text-primary-100",
|
|
541
748
|
},
|
|
542
749
|
};
|
|
543
750
|
expect(() => validate(schema, example2)).not.toThrow();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/bricks/manifests/text.manifest.ts"],"sourcesContent":["import { defineBrickManifest } from \"~/shared/brick-manifest\";\nimport { textContent } from \"../props/text\";\nimport { defineProps } from \"../props/helpers\";\nimport { border, rounding } from \"../props/border\";\nimport { RxTextAlignLeft } from \"react-icons/rx\";\nimport { Type } from \"@sinclair/typebox\";\nimport { alignItems } from \"../props/align\";\nimport { shadow } from \"../props/effects\";\nimport { colorPreset } from \"../props/color-preset\";\nimport { loop } from \"../props/dynamic\";\nimport { cssLength } from \"../props/css-length\";\nimport type { BrickExample } from \"./_types\";\n\nexport const manifest = defineBrickManifest({\n type: \"text\",\n category: \"basic\",\n name: \"Text\",\n description: \"Text with formatting options\",\n aiInstructions: `Use the text component for rich content blocks, announcements, descriptions, and formatted text throughout your site.\n\nCONTENT FORMATTING:\n- Supports HTML tags: <h1>, <h2>, <h3>, <h4>, <p>, <span>, <strong>, <em>, <br>, <a>, <ul>, <li>, <ol>\n- Only 'text-align' style is supported (center, left, right) - avoid other inline styles\n- Use <strong> for emphasis, <em> for italics, <br> for line breaks\n- Links: <a href=\"/page\">Internal</a> or <a href=\"https://external.com\">External</a>\n- Lists: <ul><li>Item 1</li><li>Item 2</li></ul>\n\nSTYLING OPTIONS:\n- colorPreset: Leave empty to inherit parent colors, or use \"primary-100\", \"secondary-200\", \"neutral-50\", \"accent-100\" for backgrounds\n- padding: Use CSS values like \"1rem\", \"2rem\", \"24px\" for internal spacing\n- rounding: \"rounded-none\" (sharp), \"rounded-md\" (standard), \"rounded-lg\" (friendly), \"rounded-xl\" (soft)\n- border: Add borders with width (\"border\", \"border-2\") and color (\"border-gray-300\", \"border-primary-500\")\n- shadow: Add depth with \"shadow-sm\", \"shadow-md\", \"shadow-lg\"\n\nWHEN TO USE:\n- Rich content sections (About Us, Service descriptions)\n- Announcements and notices\n- Product descriptions with formatting\n- Quotes and testimonials\n- FAQ content and detailed explanations\n- Footer information and legal text\n\nBEST PRACTICES:\n- Keep HTML minimal - complex layouts should use multiple components\n- Use semantic headings (h2, h3, h4) for proper hierarchy\n- Center-align for quotes/testimonials, left-align for body text\n- Choose background colors that provide good contrast, or no background for inline text`,\n defaultWidth: {\n mobile: \"100%\",\n },\n defaultHeight: {\n desktop: \"auto\",\n mobile: \"auto\",\n },\n staticClasses: \"prose lg:prose-lg\",\n icon: RxTextAlignLeft,\n props: defineProps({\n colorPreset: Type.Optional(\n colorPreset({\n title: \"Color\",\n }),\n ),\n content: textContent({\n title: \"Content\",\n // metadata: {\n // category: \"content\",\n // },\n }),\n verticalAlign: Type.Optional(\n alignItems({\n default: \"items-center\",\n title: \"Align\",\n }),\n ),\n padding: Type.Optional(\n cssLength({\n default: \"2rem\",\n description: \"Padding inside the text.\",\n \"ai:instructions\": \"Use only a single value like '1rem' or '10px'\",\n title: \"Padding\",\n \"ui:responsive\": true,\n \"ui:placeholder\": \"Not specified\",\n \"ui:styleId\": \"styles:padding\",\n }),\n ),\n rounding: rounding({\n default: \"rounded-md\",\n }),\n border: Type.Optional(border()),\n shadow: Type.Optional(shadow()),\n }),\n});\n\nexport type Manifest = typeof manifest;\n\nexport const examples: BrickExample<Manifest>[] = [\n {\n description: \"Welcome paragraph with emphasis and padding\",\n type: \"text\",\n props: {\n content:\n \"Welcome to our platform! We're <strong>excited</strong> to have you here. Our mission is to <em>transform</em> the way you work with cutting-edge technology and <a href='/features'>innovative features</a>.\",\n padding: \"2rem\",\n },\n },\n {\n description: \"Feature list with HTML formatting and smaller padding\",\n type: \"text\",\n props: {\n content:\n \"<h3>Key Features</h3><ul><li><strong>Advanced Analytics</strong> - Real-time data insights</li><li><strong>Cloud Integration</strong> - Seamless connectivity</li><li><strong>24/7 Support</strong> - Always here to help</li></ul>\",\n padding: \"1rem\",\n },\n },\n {\n description: \"Quote block with text styling but no background\",\n type: \"text\",\n props: {\n content:\n \"<p style='text-align: center'><em>\\\"Innovation distinguishes between a leader and a follower.\\\"</em><br><strong>- Steve Jobs</strong></p>\",\n padding: \"3rem\",\n },\n },\n {\n description: \"Simple heading with subtle background\",\n type: \"text\",\n props: {\n content:\n \"<h2>About Our Company</h2><p>We've been serving customers since 2010, building trust through quality products and exceptional service.</p>\",\n colorPreset: {\n color: \"primary-100\",\n },\n },\n },\n {\n description: \"Team introduction with formatting, no background color\",\n type: \"text\",\n props: {\n content:\n \"<p style='text-align: center'><strong>Meet Our Team</strong></p><p>Our diverse team of experts brings together decades of experience in technology, design, and business strategy. We're passionate about <em>creating solutions</em> that make a real difference.</p><p><a href='/team'>Learn more about our team</a> and the values that drive us forward.</p>\",\n padding: \"2rem\",\n },\n },\n {\n description: \"Maintenance notice with neutral background and border\",\n type: \"text\",\n props: {\n content:\n \"<p>Scheduled maintenance will occur on <em>Sunday, March 15th</em> from 2:00 AM to 6:00 AM UTC.</p><p>During this time, some features may be temporarily unavailable. We apologize for any inconvenience.</p>\",\n padding: \"1rem\",\n colorPreset: {\n color: \"neutral-700\",\n },\n border: {\n width: \"border\",\n color: \"border-neutral-400\",\n },\n rounding: \"rounded-lg\",\n },\n },\n {\n description: \"Minimal text with no padding or background\",\n type: \"text\",\n props: {\n content: \"This is some minimal text.\",\n padding: \"0rem\",\n },\n },\n {\n description: \"Call-to-action text with secondary background and shadow\",\n type: \"text\",\n props: {\n content:\n \"<h3 style='text-align: center'>Ready to Get Started?</h3><p style='text-align: center'>Join thousands of satisfied customers who trust our platform. <strong>Sign up today</strong> and experience the difference!</p><p style='text-align: center'><a href='/signup'>Create Your Free Account</a></p>\",\n colorPreset: {\n color: \"secondary-200\",\n },\n padding: \"2.5rem\",\n rounding: \"rounded-xl\",\n shadow: \"shadow-md\",\n verticalAlign: \"items-center\",\n },\n },\n {\n description: \"Technical documentation with accent colors and code-like formatting\",\n type: \"text\",\n props: {\n content:\n \"<h4>API Authentication</h4><p>To authenticate your requests, include your API key in the header:</p><p><strong>Authorization: Bearer YOUR_API_KEY</strong></p><p>All API endpoints require authentication. You can find your API key in the <a href='/dashboard'>dashboard settings</a>.</p>\",\n colorPreset: {\n color: \"accent-100\",\n },\n padding: \"1.5rem\",\n rounding: \"rounded-md\",\n border: {\n width: \"border-4\",\n color: \"border-accent-500\",\n },\n },\n },\n {\n description: \"Success message with primary background and top alignment\",\n type: \"text\",\n props: {\n content:\n \"<h3>✅ Payment Successful!</h3><p>Thank you for your purchase. Your order <strong>#12345</strong> has been confirmed.</p><p>You will receive an email confirmation shortly at your registered email address.</p>\",\n colorPreset: {\n color: \"primary-200\",\n },\n padding: \"2rem\",\n rounding: \"rounded-lg\",\n shadow: \"shadow-sm\",\n verticalAlign: \"items-start\",\n },\n },\n {\n description: \"Footer information with neutral dark theme and multiple links\",\n type: \"text\",\n props: {\n content:\n \"<p style='text-align: center'>© 2024 Company Name. All rights reserved.</p><p style='text-align: center'><a href='/privacy'>Privacy Policy</a> | <a href='/terms'>Terms of Service</a> | <a href='/contact'>Contact Us</a></p><p style='text-align: center'><em>Follow us on social media for the latest updates</em></p>\",\n colorPreset: {\n color: \"neutral-800\",\n },\n padding: \"1.5rem\",\n verticalAlign: \"items-end\",\n },\n },\n {\n description: \"Product description with large padding and rounded corners\",\n type: \"text\",\n props: {\n content:\n \"<h2>Premium Wireless Headphones</h2><p>Experience <strong>crystal-clear audio</strong> with our latest wireless headphones featuring:</p><ul><li>Active noise cancellation</li><li>30-hour battery life</li><li>Premium leather comfort</li><li>Hi-res audio certification</li></ul><p>Perfect for <em>music lovers</em> and <em>professionals</em> alike.</p>\",\n padding: \"3rem\",\n rounding: \"rounded-2xl\",\n shadow: \"shadow-lg\",\n border: {\n width: \"border\",\n color: \"border-neutral-300\",\n },\n },\n },\n {\n description: \"Emergency alert with accent background and extra bold formatting\",\n type: \"text\",\n props: {\n content:\n \"<h3 style='text-align: center'>⚠️ URGENT NOTICE</h3><p style='text-align: center'><strong>System maintenance is currently in progress.</strong></p><p style='text-align: center'>Some services may be <em>temporarily unavailable</em>. We expect full restoration by 4:00 PM EST.</p><p style='text-align: center'>For urgent support, please <a href='/emergency-contact'>contact our emergency line</a>.</p>\",\n colorPreset: {\n color: \"accent-400\",\n },\n padding: \"2rem\",\n rounding: \"rounded-md\",\n border: {\n width: \"border-2\",\n color: \"border-accent-600\",\n },\n shadow: \"shadow-xl\",\n verticalAlign: \"items-center\",\n },\n },\n];\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/bricks/manifests/card.manifest.ts"],"sourcesContent":["import { defineBrickManifest } from \"~/shared/brick-manifest\";\nimport { defineProps } from \"../props/helpers\";\nimport { textContent } from \"../props/text\";\nimport { BsCardText } from \"react-icons/bs\";\nimport { image } from \"../props/image\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport type { BrickProps } from \"../props/types\";\nimport { shadow } from \"../props/effects\";\nimport { border, rounding } from \"../props/border\";\nimport { colorPreset } from \"../props/color-preset\";\nimport { loop } from \"../props/dynamic\";\nimport { StringEnum } from \"~/shared/utils/string-enum\";\nimport { urlOrPageId } from \"../props/string\";\nimport type { BrickExample } from \"./_types\";\n\nexport const manifest = defineBrickManifest({\n type: \"card\",\n name: \"Card\",\n description: \"A card that can have a title, image, and content.\",\n aiInstructions: `Use this brick to create visually distinct content blocks (product, feature, testimonial, event, article, CTA, etc.).\n\n Guidelines:\n- Button is REQUIRED.\n- Always provide a short action label (1-3 words) and pick a color matching semantic weight (primary/accent for primary actions, neutral/secondary for low emphasis).\n- Image is OPTIONAL. If present you may set imagePosition to top | middle | bottom. Default is top.\n- Pick middle for vertically centered feature highlights, bottom for caption-first layouts.\n- Set noTitle: true when the card is intentionally title-less (e.g. a quote card or pure media focus).\n- Do NOT include an empty title string alongside noTitle.\n- Use dynamic tokens (e.g. {{products.price}}) instead of duplicating literal values.\n- Prefer gradient presets for more visual emphasis (e.g. primary-gradient-400 with gradientDirection).\n- border + rounding + shadow should be cohesive: stronger borders pair well with larger rounding + moderate shadow; minimal / flat cards may use border-0 + no shadow.\n- For internal navigation you can supply a page ID (e.g. 'about') OR a relative/absolute URL (e.g. '/pricing', 'https://example.com').\n- Keep HTML inside text minimal (<strong>, <em>, <br>) — for richer structure consider multiple bricks instead.\n- Avoid mixing noTitle with large heading text embedded inside the text field — in that case keep a proper title.\n- Return ONLY valid properties defined in the schema; do not invent new ones.`,\n icon: BsCardText,\n defaultWidth: { desktop: \"400px\", mobile: \"100%\" },\n minWidth: { desktop: 300 },\n minHeight: { mobile: 200, desktop: 200 },\n maxWidth: { desktop: 650 },\n props: defineProps({\n colorPreset: Type.Optional(\n colorPreset({\n title: \"Color preset\",\n default: { color: \"base-100\" },\n }),\n ),\n\n cardImage: Type.Optional(\n image({\n \"ui:responsive\": \"desktop\",\n metadata: {\n category: \"content\",\n },\n }),\n ),\n imagePosition: Type.Optional(\n StringEnum([\"top\", \"middle\", \"bottom\"], {\n enumNames: [\"Top\", \"Middle\", \"Bottom\"],\n title: \"Image Position\",\n description: \"Where the image should be placed in the card\",\n default: \"top\",\n \"ui:responsive\": \"desktop\",\n metadata: {\n category: \"content\",\n filter: (manifestProps: Manifest[\"props\"], formData: Static<Manifest[\"props\"]>) => {\n return !!formData.cardImage?.src;\n },\n },\n }),\n ),\n noTitle: Type.Optional(\n Type.Boolean({\n title: \"No Title\",\n description: \"Whether to hide the card title\",\n default: false,\n \"ui:responsive\": \"desktop\",\n }),\n ),\n title: Type.Optional(textContent({ title: \"Title\" })),\n text: Type.Optional(textContent({ title: \"Text\" })),\n rounding: Type.Optional(\n rounding({\n default: \"rounded-md\",\n }),\n ),\n border: Type.Optional(\n border({\n // default: { width: \"border\", color: \"border-base-300\" },\n }),\n ),\n shadow: Type.Optional(\n shadow({\n default: \"shadow-sm\",\n }),\n ),\n loop: Type.Optional(loop()),\n button: Type.Object(\n {\n label: Type.String({\n title: \"Button label\",\n default: \"Click me\",\n examples: [\"Learn more\", \"Buy now\", \"Sign up\"],\n metadata: {\n category: \"content\",\n },\n }),\n url: urlOrPageId({\n title: \"Button URL\",\n description: \"The URL the button should link to.\",\n metadata: {\n category: \"content\",\n },\n }),\n color: Type.Optional(\n StringEnum([\"btn-neutral\", \"btn-primary\", \"btn-secondary\", \"btn-accent\"], {\n enumNames: [\"Neutral\", \"Primary\", \"Secondary\", \"Accent\"],\n title: \"Color\",\n default: \"btn-primary\",\n }),\n ),\n },\n { title: \"Button\", description: \"Button displayed at the bottom of the card\" },\n ),\n }),\n});\n\nexport type Manifest = typeof manifest;\n\nexport const examples: BrickExample<Manifest>[] = [\n {\n description: \"A simple card with a title and content\",\n type: \"card\",\n props: {\n title: \"Card Title\",\n text: \"This is the body of the card.\",\n button: {\n label: \"Learn more\",\n url: \"/learn-more\",\n color: \"btn-primary\",\n },\n },\n },\n // IMAGE POSITION MIDDLE VARIANT\n {\n description: \"Feature highlight card with centered image (imagePosition=middle)\",\n type: \"card\",\n props: {\n cardImage: { src: \"https://via.placeholder.com/420x240\", alt: \"Feature visual\" },\n imagePosition: \"middle\",\n title: \"Blazing Performance\",\n text: \"Our new engine reduces processing time by 45% while maintaining reliability.\",\n colorPreset: { color: \"primary-100\" },\n border: { width: \"border\", color: \"border-primary-200\" },\n rounding: \"rounded-lg\",\n shadow: \"shadow-sm\",\n button: { label: \"Learn More\", url: \"/features/performance\", color: \"btn-primary\" },\n },\n },\n // IMAGE POSITION BOTTOM VARIANT\n {\n description: \"Case study card with image at the bottom (imagePosition=bottom)\",\n type: \"card\",\n props: {\n title: \"Case Study: ScaleOps\",\n text: \"How ScaleOps handled 10x growth with zero downtime using our platform.\",\n cardImage: { src: \"https://via.placeholder.com/600x260\", alt: \"Scale graph\" },\n imagePosition: \"bottom\",\n colorPreset: { color: \"secondary-50\" },\n rounding: \"rounded-md\",\n shadow: \"shadow-sm\",\n button: { label: \"Read Study\", url: \"/cases/scaleops\", color: \"btn-secondary\" },\n },\n },\n // NO TITLE VARIANT\n {\n description: \"Quote / testimonial style card without a title (uses noTitle=true)\",\n type: \"card\",\n props: {\n noTitle: true,\n text: '\"This toolkit accelerated our launch by weeks — the component quality is outstanding.\"<br><em>— CTO, FinEdge</em>',\n colorPreset: { color: \"neutral-100\" },\n border: { width: \"border\", color: \"border-neutral-300\" },\n rounding: \"rounded-xl\",\n shadow: \"shadow-sm\",\n button: { label: \"See More\", url: \"/testimonials\", color: \"btn-neutral\" },\n },\n },\n // INTERNAL PAGE ID LINK VARIANT\n {\n description: \"Internal navigation card using a page ID instead of a URL\",\n type: \"card\",\n props: {\n title: \"About Our Mission\",\n text: \"Learn how we're building an open, extensible site generation platform for modern teams.\",\n colorPreset: { color: \"base-100\" },\n rounding: \"rounded-md\",\n button: { label: \"About Us\", url: \"about\", color: \"btn-primary\" },\n },\n },\n // GRADIENT & STRONG BORDER VARIANT\n {\n description: \"High-emphasis promotional card using gradient background and thick border\",\n type: \"card\",\n props: {\n title: \"Limited Time Offer\",\n text: \"Upgrade now and receive a complimentary strategy session plus extended analytics access.\",\n colorPreset: { color: \"primary-gradient-400\", gradientDirection: \"bg-gradient-to-tr\" },\n border: { width: \"border-4\", color: \"border-primary-400\" },\n rounding: \"rounded-xl\",\n shadow: \"shadow-lg\",\n button: { label: \"Upgrade\", url: \"/pricing\", color: \"btn-accent\" },\n },\n },\n // MINIMAL / FLAT VARIANT (no border, no shadow, subtle preset)\n {\n description: \"Minimal flat information card (border-0, no shadow)\",\n type: \"card\",\n props: {\n title: \"Maintenance Window\",\n text: \"Scheduled maintenance on Saturday 02:00–03:00 UTC. API responses may be delayed.\",\n colorPreset: { color: \"neutral-50\" },\n border: { width: \"border-0\", color: \"border-neutral-200\" },\n button: { label: \"Status Page\", url: \"/status\", color: \"btn-neutral\" },\n },\n },\n // DARK / INVERTED VARIANT\n {\n description: \"Dark themed spotlight card (primary-800 background)\",\n type: \"card\",\n props: {\n title: \"Night Mode Preview\",\n text: \"Experience the new adaptive dark theme optimized for low ambient light environments.\",\n colorPreset: { color: \"primary-800\" },\n border: { width: \"border\", color: \"border-primary-600\" },\n rounding: \"rounded-lg\",\n shadow: \"shadow-md\",\n button: { label: \"Preview\", url: \"/themes/dark\", color: \"btn-primary\" },\n },\n },\n {\n description: \"Feature card with large padding and background\",\n type: \"card\",\n props: {\n title: \"Key Feature\",\n text: \"This feature provides exceptional value and enhances user experience significantly.\",\n colorPreset: { color: \"primary-50\" },\n border: { width: \"border\", color: \"border-primary-200\" },\n rounding: \"rounded-lg\",\n shadow: \"shadow-sm\",\n button: {\n label: \"Discover More\",\n url: \"/features\",\n color: \"btn-primary\",\n },\n },\n },\n {\n description: \"Blog post card with image at the bottom\",\n type: \"card\",\n props: {\n title: \"Future of Tech\",\n text: \"Exploring emerging trends and innovations that will shape our digital landscape in the coming decade.\",\n cardImage: {\n src: \"https://via.placeholder.com/400x200\",\n alt: \"Technology concept\",\n },\n button: {\n label: \"Read More\",\n url: \"/blog/{{ blogPosts.$slug }}\",\n color: \"btn-primary\",\n },\n },\n },\n {\n description: \"Minimal centered card without image\",\n type: \"card\",\n props: {\n title: \"Simple Announcement\",\n text: \"Important updates will be posted here regularly.\",\n button: {\n label: \"View Updates\",\n url: \"/updates\",\n color: \"btn-neutral\",\n },\n },\n },\n {\n description: \"Event card with multiple variants\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"https://via.placeholder.com/400x250\",\n alt: \"Event venue\",\n },\n title: \"Annual Conference 2025\",\n text: \"Join us for three days of inspiring talks, networking opportunities, and hands-on workshops.\",\n button: {\n label: \"Register Now\",\n url: \"/events/conference-2025\",\n color: \"btn-primary\",\n },\n },\n },\n {\n description: \"News article card with compact layout\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"https://via.placeholder.com/120x120\",\n alt: \"News thumbnail\",\n },\n title: \"Breaking News Update\",\n text: \"Latest developments in the ongoing story with expert analysis and community reactions.\",\n button: {\n label: \"Read Full Article\",\n url: \"/news/breaking-update\",\n color: \"btn-secondary\",\n },\n },\n },\n {\n description: \"Call-to-action card with prominent styling\",\n type: \"card\",\n props: {\n title: \"Get Started Today\",\n text: \"Transform your workflow with our powerful tools. Sign up now and get 30 days free!\",\n button: {\n label: \"Sign Up Now\",\n url: \"/signup\",\n color: \"btn-primary\",\n },\n },\n },\n {\n description: \"Dynamic product card using products query with pricing and details\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"{{products.image}}\",\n alt: \"{{products.name}}\",\n },\n title: \"{{products.name}}\",\n text: \"{{products.description}}<br><strong>Price: ${{products.price}}</strong><br>Category: {{products.category}}\",\n colorPreset: { color: \"primary-50\" },\n border: { width: \"border\", color: \"border-primary-200\" },\n rounding: \"rounded-lg\",\n shadow: \"shadow-md\",\n button: {\n label: \"Buy Now\",\n url: \"{{products.purchaseUrl}}\",\n color: \"btn-primary\",\n },\n loop: {\n over: \"products\",\n },\n },\n },\n {\n description: \"Employee profile card using teamMembers query with contact information\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"{{teamMembers.photo}}\",\n alt: \"Photo of {{teamMembers.fullName}}\",\n },\n imagePosition: \"top\",\n title: \"{{teamMembers.fullName}}\",\n text: \"<strong>{{teamMembers.position}}</strong><br>{{teamMembers.department}}<br>Email: {{teamMembers.email}}<br>Phone: {{teamMembers.phone}}\",\n colorPreset: { color: \"neutral-100\" },\n rounding: \"rounded-xl\",\n shadow: \"shadow-lg\",\n button: {\n label: \"Contact\",\n url: \"mailto:{{teamMembers.email}}\",\n color: \"btn-neutral\",\n },\n loop: {\n over: \"teamMembers\",\n },\n },\n },\n {\n description: \"Blog post card using blogPosts query with author and date\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"{{blogPosts.featuredImage}}\",\n alt: \"{{blogPosts.title}}\",\n },\n imagePosition: \"top\",\n title: \"{{blogPosts.title}}\",\n text: \"{{blogPosts.excerpt}}<br><br><em>By {{blogPosts.author}} • {{blogPosts.publishDate}}</em><br>Tags: {{blogPosts.tags}}\",\n colorPreset: { color: \"secondary-50\" },\n border: { width: \"border\", color: \"border-secondary-300\" },\n rounding: \"rounded-md\",\n shadow: \"shadow-sm\",\n button: {\n label: \"Read More\",\n url: \"{{blogPosts.url}}\",\n color: \"btn-secondary\",\n },\n loop: {\n over: \"blogPosts\",\n },\n },\n },\n {\n description: \"Event listing card using upcomingEvents query with venue details\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"{{upcomingEvents.banner}}\",\n alt: \"{{upcomingEvents.title}}\",\n },\n imagePosition: \"top\",\n title: \"{{upcomingEvents.title}}\",\n text: \"<strong>{{upcomingEvents.date}} at {{upcomingEvents.time}}</strong><br>{{upcomingEvents.venue}}, {{upcomingEvents.city}}<br><br>{{upcomingEvents.description}}<br><br>Tickets: ${{upcomingEvents.price}}\",\n colorPreset: { color: \"accent-100\" },\n border: { width: \"border-2\", color: \"border-accent-400\" },\n rounding: \"rounded-lg\",\n shadow: \"shadow-md\",\n button: {\n label: \"Book Tickets\",\n url: \"{{upcomingEvents.ticketUrl}}\",\n color: \"btn-accent\",\n },\n loop: {\n over: \"upcomingEvents\",\n },\n },\n },\n {\n description: \"Testimonial card using customerReviews query with ratings\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"{{customerReviews.customerPhoto}}\",\n alt: \"{{customerReviews.customerName}}\",\n },\n imagePosition: \"top\",\n title: \"{{customerReviews.customerName}}\",\n text: '\"{{customerReviews.review}}\"<br><br><strong>Rating: {{customerReviews.rating}}/5 stars</strong><br>{{customerReviews.company}} • {{customerReviews.position}}',\n colorPreset: { color: \"neutral-50\" },\n rounding: \"rounded-xl\",\n shadow: \"shadow-lg\",\n button: {\n label: \"See All Reviews\",\n url: \"/reviews\",\n color: \"btn-neutral\",\n },\n loop: {\n over: \"customerReviews\",\n },\n },\n },\n {\n description: \"Service offering card using companyServices query with pricing tiers\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"{{companyServices.icon}}\",\n alt: \"{{companyServices.serviceName}}\",\n },\n imagePosition: \"top\",\n title: \"{{companyServices.serviceName}}\",\n text: \"{{companyServices.description}}<br><br><strong>Starting at ${{companyServices.startingPrice}}</strong><br>Duration: {{companyServices.duration}}<br>Includes: {{companyServices.features}}\",\n colorPreset: { color: \"primary-100\" },\n border: { width: \"border\", color: \"border-primary-300\" },\n rounding: \"rounded-lg\",\n shadow: \"shadow-md\",\n button: {\n label: \"Learn More\",\n url: \"{{companyServices.detailsUrl}}\",\n color: \"btn-primary\",\n },\n loop: {\n over: \"companyServices\",\n },\n },\n },\n {\n description: \"Portfolio project card using portfolioWork query with project details\",\n type: \"card\",\n props: {\n cardImage: {\n src: \"{{portfolioWork.thumbnail}}\",\n alt: \"{{portfolioWork.projectName}}\",\n },\n imagePosition: \"top\",\n title: \"{{portfolioWork.projectName}}\",\n text: \"<strong>Client:</strong> {{portfolioWork.clientName}}<br><strong>Year:</strong> {{portfolioWork.year}}<br><strong>Category:</strong> {{portfolioWork.category}}<br><br>{{portfolioWork.description}}\",\n colorPreset: { color: \"secondary-100\" },\n rounding: \"rounded-md\",\n shadow: \"shadow-sm\",\n button: {\n label: \"View Project\",\n url: \"{{portfolioWork.projectUrl}}\",\n color: \"btn-secondary\",\n },\n loop: {\n over: \"portfolioWork\",\n },\n },\n },\n];\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/bricks/props/image.ts"],"sourcesContent":["import { Type, type Static, type ObjectOptions } from \"@sinclair/typebox\";\nimport { StringEnum } from \"~/shared/utils/string-enum\";\n\ntype PropImageOptions = {\n defaultImageUrl?: string;\n showImgSearch?: boolean;\n noObjectOptions?: boolean;\n} & ObjectOptions;\n\nexport function image(options: PropImageOptions = {}) {\n const { defaultImageUrl, showImgSearch = false, noObjectOptions = false } = options;\n const schema = Type.Object(\n {\n src: Type.String({\n title: options.title ?? \"Image URL\",\n description: \"Image URL. Can be a link to an image or a data URI\",\n }),\n alt: Type.Optional(\n Type.String({\n title: \"Alternate Text\",\n description: \"Alternative text for the image. Recommended for screen readers and SEO\",\n \"ui:placeholder\": \"Your image description\",\n }),\n ),\n fit: Type.Optional(\n StringEnum([\"object-none\", \"object-contain\", \"object-cover\", \"object-fill\", \"object-scale-down\"], {\n enumNames: [\"None\", \"Contain\", \"Cover\", \"Fill\", \"Scale down\"],\n title: \"Fit\",\n description: \"How the image should be resized to fit its container\",\n \"ui:field\": \"enum\",\n \"ui:styleId\": \"styles:objectFit\",\n }),\n ),\n position: Type.Optional(\n StringEnum(\n [\n \"object-top\",\n \"object-center\",\n \"object-bottom\",\n \"object-left\",\n \"object-right\",\n \"object-top-left\",\n \"object-top-right\",\n \"object-bottom-left\",\n \"object-bottom-right\",\n ],\n {\n enumNames: [\n \"Top\",\n \"Center\",\n \"Bottom\",\n \"Left\",\n \"Right\",\n \"Top left\",\n \"Top right\",\n \"Bottom left\",\n \"Bottom right\",\n ],\n \"ui:styleId\": \"styles:objectPosition\",\n title: \"Position\",\n description: \"The position of the image inside its container\",\n \"ui:field\": \"enum\",\n },\n ),\n ),\n },\n {\n // $id: \"assets:image\",\n title: \"Image\",\n \"ui:field\": \"image\",\n \"ui:accept\": \"image/*\",\n \"ui:show-img-search\": showImgSearch,\n \"ui:no-object-options\": noObjectOptions,\n // \"ui:responsive\": \"desktop\",\n metadata: {\n category: \"content\",\n },\n ...options,\n },\n );\n return schema;\n}\n\nexport type ImageProps = Static<ReturnType<typeof image>>;\n"],"mappings":";;;;;;;AAAA,SAAS,YAA6C;AAS/C,SAAS,MAAM,UAA4B,CAAC,GAAG;AACpD,QAAM,EAAE,iBAAiB,gBAAgB,OAAO,kBAAkB,MAAM,IAAI;AAC5E,QAAM,SAAS,KAAK;AAAA,IAClB;AAAA,MACE,KAAK,KAAK,OAAO;AAAA,QACf,OAAO,QAAQ,SAAS;AAAA,QACxB,aAAa;AAAA,MACf,CAAC;AAAA,MACD,KAAK,KAAK;AAAA,QACR,KAAK,OAAO;AAAA,UACV,OAAO;AAAA,UACP,aAAa;AAAA,UACb,kBAAkB;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,MACA,KAAK,KAAK;AAAA,QACR,WAAW,CAAC,eAAe,kBAAkB,gBAAgB,eAAe,mBAAmB,GAAG;AAAA,UAChG,WAAW,CAAC,QAAQ,WAAW,SAAS,QAAQ,YAAY;AAAA,UAC5D,OAAO;AAAA,UACP,aAAa;AAAA,UACb,YAAY;AAAA,UACZ,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,MACA,UAAU,KAAK;AAAA,QACb;AAAA,UACE;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,YACE,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YACA,cAAc;AAAA,YACd,OAAO;AAAA,YACP,aAAa;AAAA,YACb,YAAY;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA;AAAA,MAEE,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,sBAAsB;AAAA,MACtB,wBAAwB;AAAA;AAAA,MAExB,UAAU;AAAA,QACR,UAAU;AAAA,MACZ;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/bricks.ts"],"sourcesContent":["import { Type, type Static } from \"@sinclair/typebox\";\nimport { customAlphabet } from \"nanoid\";\nimport { defaultProps, manifests } from \"./bricks/manifests/all-manifests\";\nimport { cssLength } from \"./bricks/props/css-length\";\nimport { colorPreset } from \"./bricks/props/color-preset\";\nimport { mergeIgnoringArrays } from \"./utils/merge\";\nimport { getSchemaDefaults } from \"./utils/schema\";\nimport { StringEnum } from \"./utils/string-enum\";\nimport { alignItems, justifyContent } from \"./bricks/props/align\";\nimport type { CommonBrickProps } from \"./bricks/props/common\";\nimport { direction } from \"./bricks/props/direction\";\nimport type { PageAttributes, SiteAttributes } from \"./attributes\";\nimport { toLLMSchema } from \"./utils/llm\";\nimport { background } from \"./bricks/props/background\";\n\n/**\n * Generates a unique identifier for bricks.\n */\nexport const generateId = customAlphabet(\"azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN\", 7);\n\nconst brickAbsolutePositionSchema = Type.Object({\n left: Type.Optional(\n Type.String({\n title: \"top\",\n description: \"The left position in css unit.\",\n }),\n ),\n top: Type.Optional(\n Type.String({\n title: \"top\",\n description: \"The top position in css unit.\",\n }),\n ),\n right: Type.Optional(\n Type.String({\n title: \"right\",\n description: \"The right position in css unit.\",\n }),\n ),\n bottom: Type.Optional(\n Type.String({\n title: \"bottom\",\n description: \"The bottom position in css unit.\",\n }),\n ),\n inset: Type.Optional(\n Type.String({\n title: \"inset\",\n description: \"The inset position in css unit.\",\n }),\n ),\n translateX: Type.Optional(\n Type.String({\n title: \"translateX\",\n description: \"The translateX position in css unit.\",\n }),\n ),\n translateY: Type.Optional(\n Type.String({\n title: \"translateY\",\n description: \"The translateY position in css unit.\",\n }),\n ),\n rotate: Type.Optional(\n Type.String({\n title: \"rotate\",\n description: \"The rotate position in css unit.\",\n }),\n ),\n});\n\nexport type BrickAbsolutePosition = Static<typeof brickAbsolutePositionSchema>;\n\nexport const brickTypeSchema = StringEnum(Object.keys(defaultProps), {\n title: \"Brick type\",\n});\n\nexport const brickSchema = Type.Object({\n id: Type.String({\n title: \"ID\",\n description: \"A unique identifier for the brick.\",\n }),\n type: brickTypeSchema,\n label: Type.Optional(\n Type.String({\n title: \"Label\",\n description: \"A human-readable label for the brick. Used for organization and identification.\",\n }),\n ),\n props: Type.Any({\n title: \"Props\",\n description: \"The static props of the brick. The available props depends on the brick type.\",\n }),\n mobileProps: Type.Optional(\n Type.Any({\n title: \"Props\",\n description:\n \"The overriden props for mobile, merged with desktop props. Same type as props but partial.\",\n }),\n ),\n});\n\nexport function makeFullBrickSchemaForLLM(type: string, otherTypes?: string[]) {\n const originalProps = Type.Pick(brickSchema, [\"props\"]);\n const props = otherTypes\n ? Type.Composite([\n Type.Omit(brickSchema, [\"props\"]),\n Type.Object({\n props: Type.Composite([\n originalProps,\n Type.Object({\n $children: Type.Union(\n otherTypes.map((t) =>\n Type.Object({\n id: Type.String({\n title: \"ID\",\n description: \"A unique identifier for the brick.\",\n }),\n type: Type.Literal(t),\n props: manifests[t].props,\n mobileProps: Type.Optional(Type.Partial(manifests[t].props)),\n }),\n ),\n ),\n }),\n ]),\n }),\n ])\n : manifests[type].props;\n return toLLMSchema(\n Type.Object(\n {\n id: Type.String({\n title: \"ID\",\n description: \"A unique identifier for the brick.\",\n }),\n type: Type.Literal(type),\n props,\n mobileProps: Type.Optional(Type.Partial(manifests[type].props)),\n },\n // IMPORTANT: DO NOT set \"additionalProperties\" to `false` because it would break validation with Cabidela library\n // { additionalProperties: false },\n ),\n );\n}\n\nexport type Brick = Omit<Static<typeof brickSchema>, \"props\" | \"mobileProps\"> & {\n props: CommonBrickProps & Record<string, unknown>;\n mobileProps?: Partial<CommonBrickProps & Record<string, unknown>>;\n};\n\nexport const sectionProps = Type.Object({\n colorPreset: Type.Optional(\n colorPreset({\n title: \"Color\",\n }),\n ),\n backgroundImage: Type.Optional(\n background({\n title: \"Background\",\n }),\n ),\n direction: Type.Optional(\n direction({\n default: \"flex-row\",\n title: \"Direction\",\n description:\n \"The direction of the section. Only apply to desktop. On mobile, it is always vertical. By default, horizontal (row), which is the most common.\",\n \"ui:responsive\": \"desktop\",\n }),\n ),\n minHeight: Type.Optional(\n cssLength({\n title: \"Min height\",\n default: \"fit-content\",\n description:\n \"The min height of the section. default is 'fit-content'. You can also use the keyword 'full' to make it full viewport height. Lastly, you can use any valid CSS length unit.\",\n \"ui:field\": \"hidden\",\n }),\n ),\n variant: Type.Optional(\n StringEnum([\"navbar\", \"footer\", \"sidebar\"], {\n title: \"Custom section variant\",\n description: \"Used for custom styling and layout.\",\n enumNames: [\"Navbar\", \"Footer\", \"Sidebar\"],\n \"ui:field\": \"hidden\",\n \"ai:hidden\": true,\n }),\n ),\n maxWidth: Type.Optional(\n StringEnum([\"max-w-screen-lg\", \"max-w-screen-xl\", \"max-w-screen-2xl\", \"max-w-full\"], {\n title: \"Max width\",\n default: \"max-w-full\",\n enumNames: [\"M\", \"L\", \"XL\", \"Full\"],\n description: \"The maximum width of the section. Desktop only\",\n \"ai:instructions\":\n \"Choose the most appropriate max width for the section. The value 'max-w-full' is the most common and the default. Use the same value for all sections on the same page unless there is a good reason to do otherwise.\",\n displayAs: \"button-group\",\n \"ui:responsive\": \"desktop\",\n }),\n ),\n verticalMargin: Type.Optional(\n cssLength({\n title: \"Vertical Margin\",\n description:\n \"The vertical margin of the section. By default, all sections touch each other with no space in between. If you want to add space between sections, set this value to e.g. '2rem' or '32px'. Adding a vertical margin will reveal the background color of the page.\",\n default: \"0\",\n \"ui:styleId\": \"styles:verticalMargin\",\n }),\n ),\n justifyContent: Type.Optional(\n justifyContent({\n default: \"justify-center\",\n }),\n ),\n alignItems: Type.Optional(\n alignItems({\n default: \"items-center\",\n }),\n ),\n padding: Type.Optional(\n cssLength({\n default: \"2rem\",\n description: \"Padding inside the section.\",\n title: \"Padding\",\n \"ui:responsive\": true,\n \"ui:placeholder\": \"Not specified\",\n \"ui:styleId\": \"styles:padding\",\n }),\n ),\n gap: Type.Optional(\n cssLength({\n title: \"Gap\",\n description: \"The gap between the bricks in the section.\",\n default: \"2rem\",\n \"ui:styleId\": \"styles:gap\",\n }),\n ),\n wrap: Type.Optional(\n Type.Boolean({\n title: \"Wrap\",\n description: \"Wrap bricks if they overflow the section.\",\n default: true,\n \"ui:styleId\": \"styles:wrap\",\n }),\n ),\n lastTouched: Type.Optional(\n Type.Number({\n description: \"Do not use this field. It is used internally by the editor.\",\n \"ui:field\": \"hidden\",\n \"ai:hidden\": true,\n }),\n ),\n});\n\nexport const sectionSchema = Type.Object(\n {\n id: Type.String({\n description: \"The unique ID of the section. Use a human readable url-safe slug\",\n examples: [\"content-section\", \"contact-section\"],\n }),\n label: Type.String({\n description: \"The label of the section. Shown only to the website owner, not public.\",\n examples: [\"Content\", \"Contact\"],\n }),\n order: Type.Number({\n description: \"Determines section order in the page (lower numbers appear first). 0-based\",\n }),\n props: sectionProps,\n mobileProps: Type.Optional(Type.Partial(sectionProps)),\n bricks: Type.Array(brickSchema),\n },\n {\n description: \"Sections are direct children of the page that are stacked vertically.\",\n },\n);\n\nexport const sectionSchemaNoBricks = Type.Omit(sectionSchema, [\"bricks\"]);\nexport type SectionSchemaNoBricks = Static<typeof sectionSchemaNoBricks>;\n\nconst sectionDefaultprops = getSchemaDefaults(sectionSchema.properties.props, \"desktop\") as Section[\"props\"];\nconst sectionMobileDefaultprops = getSchemaDefaults(\n sectionSchema.properties.mobileProps,\n \"mobile\",\n) as Section[\"mobileProps\"];\n\nexport type Section = Static<typeof sectionSchema>;\n\nexport function processSections(\n sections: Section[],\n siteAttributes: SiteAttributes,\n pageAttributes: PageAttributes,\n): Section[] {\n const processSection = (section: Section) => {\n return {\n ...section,\n props: mergeIgnoringArrays({} as Section[\"props\"], sectionDefaultprops, section.props),\n mobileProps: mergeIgnoringArrays({}, sectionMobileDefaultprops, section.mobileProps || {}),\n bricks: section.bricks.map(processBrick).filter(Boolean) as Brick[],\n } as const;\n };\n\n const finalSections = sections.map(processSection);\n\n if (siteAttributes.navbar && !pageAttributes.noNavbar) {\n finalSections.unshift(\n processSection({\n order: -1,\n id: \"navbar-section\",\n label: \"Navbar\",\n props: {\n variant: \"navbar\",\n direction: \"flex-row\",\n },\n mobileProps: {},\n bricks: [\n {\n id: \"navbar\",\n type: \"navbar\",\n props: siteAttributes.navbar,\n },\n ],\n }),\n );\n }\n if (siteAttributes.footer && !pageAttributes.noFooter) {\n finalSections.push(\n processSection({\n order: 1000,\n id: \"footer-section\",\n label: \"Footer\",\n props: {\n variant: \"footer\",\n direction: \"flex-row\",\n },\n mobileProps: {},\n bricks: [\n {\n id: \"footer\",\n type: \"footer\",\n props: siteAttributes.footer,\n },\n ],\n }),\n );\n }\n\n return finalSections satisfies Section[];\n}\n\n/**\n * process a brick and add default props\n */\nexport function processBrick<T extends Brick>(brick: T): T {\n const defProps = defaultProps[brick.type];\n // if (!defProps) {\n // console.warn(`No default props found for brick type: ${brick.type}`);\n // return false; // or throw an error if you prefer\n // }\n const result = {\n ...brick,\n props: mergeIgnoringArrays({} as Brick[\"props\"], defProps.props, {\n ...brick.props,\n ...(brick.props.$children\n ? { $children: (brick.props.$children as T[]).map(processBrick).filter(Boolean) }\n : {}),\n }),\n };\n\n return result;\n}\n\nexport function getDefaultPropsForBrick(type: string) {\n return defaultProps[type].props;\n}\n\nexport function createEmptyBrick(type: string, ghost = false): Brick {\n const props = { ...defaultProps[type].props, ghost };\n const newBrick = {\n id: `b-${generateId()}`,\n type,\n props,\n };\n return newBrick;\n}\n"],"mappings":"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","names":[]}
|