@vexcms/core 0.0.8 → 0.0.10
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/index.d.ts +528 -33
- package/dist/index.js +643 -81
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -178,32 +178,41 @@ function resolveMediaCollection(props) {
|
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
180
|
function defineConfig(vexConfig) {
|
|
181
|
-
|
|
181
|
+
let resolvedInput = vexConfig;
|
|
182
|
+
if (vexConfig.plugins && vexConfig.plugins.length > 0) {
|
|
183
|
+
for (const plugin of vexConfig.plugins) {
|
|
184
|
+
resolvedInput = plugin(resolvedInput);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const { plugins: _plugins, ...inputWithoutPlugins } = resolvedInput;
|
|
188
|
+
const { media: mediaInput, ...restInput } = inputWithoutPlugins;
|
|
189
|
+
const resolved = inputWithoutPlugins;
|
|
182
190
|
const config = {
|
|
183
191
|
...BASE_VEX_CONFIG,
|
|
184
192
|
...restInput,
|
|
185
193
|
admin: {
|
|
186
194
|
...BASE_VEX_CONFIG.admin,
|
|
187
|
-
...
|
|
195
|
+
...resolved.admin,
|
|
188
196
|
meta: {
|
|
189
197
|
...BASE_VEX_CONFIG.admin.meta,
|
|
190
|
-
...
|
|
198
|
+
...resolved.admin?.meta
|
|
191
199
|
},
|
|
192
200
|
sidebar: {
|
|
193
201
|
...BASE_VEX_CONFIG.admin.sidebar,
|
|
194
|
-
...
|
|
202
|
+
...resolved.admin?.sidebar
|
|
195
203
|
},
|
|
196
204
|
onboarding: {
|
|
197
205
|
...BASE_VEX_CONFIG.admin.onboarding,
|
|
198
|
-
...
|
|
206
|
+
...resolved.admin?.onboarding
|
|
199
207
|
},
|
|
200
|
-
livePreview:
|
|
208
|
+
livePreview: resolved.admin?.livePreview
|
|
201
209
|
},
|
|
202
210
|
schema: {
|
|
203
211
|
...BASE_VEX_CONFIG.schema,
|
|
204
|
-
...
|
|
212
|
+
...resolved.schema
|
|
205
213
|
},
|
|
206
|
-
access:
|
|
214
|
+
access: resolved.access,
|
|
215
|
+
breakpoints: resolved.breakpoints
|
|
207
216
|
};
|
|
208
217
|
if (mediaInput) {
|
|
209
218
|
if (mediaInput.collections.length === 0) {
|
|
@@ -272,6 +281,11 @@ function defineMediaCollection(props) {
|
|
|
272
281
|
return props;
|
|
273
282
|
}
|
|
274
283
|
|
|
284
|
+
// src/config/defineGlobal.ts
|
|
285
|
+
function defineGlobal(props) {
|
|
286
|
+
return props;
|
|
287
|
+
}
|
|
288
|
+
|
|
275
289
|
// src/access/defineAccess.ts
|
|
276
290
|
function defineAccess(props) {
|
|
277
291
|
if (props.orgCollection && !props.userOrgField) {
|
|
@@ -461,6 +475,51 @@ function hasPermission(props) {
|
|
|
461
475
|
return merged;
|
|
462
476
|
}
|
|
463
477
|
|
|
478
|
+
// src/access/checkAdminAccess.ts
|
|
479
|
+
function checkAdminAccess(props) {
|
|
480
|
+
if (props.access === void 0) {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
if (props.userRoles.length === 0) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
const knownRolesSet = new Set(props.access.roles);
|
|
487
|
+
for (const role of props.userRoles) {
|
|
488
|
+
if (!knownRolesSet.has(role)) continue;
|
|
489
|
+
const rolePerms = props.access.permissions[role];
|
|
490
|
+
if (rolePerms === void 0) continue;
|
|
491
|
+
const adminPerm = rolePerms.admin;
|
|
492
|
+
if (adminPerm === void 0) continue;
|
|
493
|
+
if (typeof adminPerm === "boolean") {
|
|
494
|
+
if (adminPerm) return true;
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
if (typeof adminPerm === "function") {
|
|
498
|
+
const callbackProps = props.organization !== void 0 ? { user: props.user, organization: props.organization } : { user: props.user };
|
|
499
|
+
if (adminPerm(callbackProps)) return true;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// src/metadata/buildSiteMetadata.ts
|
|
506
|
+
function buildSiteMetadata(props) {
|
|
507
|
+
const title = props.page?.metaTitle || props.page?.title || props.site.metaTitle || props.site.name || "Untitled";
|
|
508
|
+
const description = props.page?.metaDescription || props.site.metaDescription || props.site.description || "";
|
|
509
|
+
const ogImage = props.page?.ogImage || props.site.ogImage || void 0;
|
|
510
|
+
const twitterHandle = props.site.twitterHandle || void 0;
|
|
511
|
+
let finalTitle = title;
|
|
512
|
+
if (props.titleSuffix && !title.endsWith(props.titleSuffix) && title !== props.site.name) {
|
|
513
|
+
finalTitle = title + props.titleSuffix;
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
title: finalTitle,
|
|
517
|
+
description,
|
|
518
|
+
ogImage,
|
|
519
|
+
twitterHandle
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
464
523
|
// src/config/sanitizeConfig.ts
|
|
465
524
|
function sanitizeConfigForClient(config) {
|
|
466
525
|
const { media, ...rest } = config;
|
|
@@ -920,6 +979,50 @@ function jsonToValueTypeString(props) {
|
|
|
920
979
|
});
|
|
921
980
|
}
|
|
922
981
|
|
|
982
|
+
// src/fields/object/config.ts
|
|
983
|
+
function object(options) {
|
|
984
|
+
return { type: "object", ...options };
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// src/fields/object/schemaValueType.ts
|
|
988
|
+
function objectToValueTypeString(props) {
|
|
989
|
+
const fieldEntries = [];
|
|
990
|
+
for (const [subFieldName, subField] of Object.entries(props.field.fields)) {
|
|
991
|
+
const valueType = props.resolveInnerField({
|
|
992
|
+
field: subField,
|
|
993
|
+
collectionSlug: props.collectionSlug,
|
|
994
|
+
fieldName: `${props.fieldName}.${subFieldName}`
|
|
995
|
+
});
|
|
996
|
+
fieldEntries.push(`${subFieldName}: ${valueType}`);
|
|
997
|
+
}
|
|
998
|
+
const objectType = fieldEntries.length <= 2 ? `v.object({ ${fieldEntries.join(", ")} })` : `v.object({
|
|
999
|
+
${fieldEntries.map((e) => ` ${e},`).join("\n")}
|
|
1000
|
+
})`;
|
|
1001
|
+
return processFieldValueTypeOptions({
|
|
1002
|
+
field: props.field,
|
|
1003
|
+
collectionSlug: props.collectionSlug,
|
|
1004
|
+
fieldName: props.fieldName,
|
|
1005
|
+
expectedType: "object",
|
|
1006
|
+
valueType: objectType,
|
|
1007
|
+
skipDefaultValidation: true
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// src/fields/object/columnDef.ts
|
|
1012
|
+
function objectColumnDef(props) {
|
|
1013
|
+
return {
|
|
1014
|
+
accessorKey: props.fieldKey,
|
|
1015
|
+
header: props.field.label ?? toTitleCase(props.fieldKey),
|
|
1016
|
+
meta: { align: props.field.admin?.cellAlignment ?? "left" },
|
|
1017
|
+
cell: (info) => {
|
|
1018
|
+
const value = info.getValue();
|
|
1019
|
+
if (value == null) return "";
|
|
1020
|
+
const str = JSON.stringify(value);
|
|
1021
|
+
return str.length > 50 ? str.slice(0, 50) + "..." : str;
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
|
|
923
1026
|
// src/fields/richtext/config.ts
|
|
924
1027
|
function richtext(options) {
|
|
925
1028
|
return {
|
|
@@ -997,11 +1100,17 @@ function arrayColumnDef(props) {
|
|
|
997
1100
|
// src/fields/array/schemaValueType.ts
|
|
998
1101
|
function arrayToValueTypeString(props) {
|
|
999
1102
|
const innerValueType = props.resolveInnerField({
|
|
1000
|
-
field: props.field.
|
|
1103
|
+
field: props.field.items,
|
|
1001
1104
|
collectionSlug: props.collectionSlug,
|
|
1002
1105
|
fieldName: `${props.fieldName}[]`
|
|
1003
1106
|
});
|
|
1004
|
-
|
|
1107
|
+
let unwrapped = innerValueType;
|
|
1108
|
+
if (unwrapped.startsWith("v.optional(")) {
|
|
1109
|
+
const inner = unwrapped.slice("v.optional(".length);
|
|
1110
|
+
if (inner.endsWith(")")) {
|
|
1111
|
+
unwrapped = inner.slice(0, -1);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1005
1114
|
const arrayType = `v.array(${unwrapped})`;
|
|
1006
1115
|
return processFieldValueTypeOptions({
|
|
1007
1116
|
field: props.field,
|
|
@@ -1064,6 +1173,7 @@ function blocksToValueTypeString(props) {
|
|
|
1064
1173
|
const fieldEntries = [
|
|
1065
1174
|
`blockType: v.literal("${block.slug}")`,
|
|
1066
1175
|
`blockName: v.optional(v.string())`,
|
|
1176
|
+
`blockStyles: v.optional(v.string())`,
|
|
1067
1177
|
`_key: v.string()`
|
|
1068
1178
|
];
|
|
1069
1179
|
for (const [fieldName, field] of Object.entries(block.fields)) {
|
|
@@ -1075,10 +1185,18 @@ function blocksToValueTypeString(props) {
|
|
|
1075
1185
|
});
|
|
1076
1186
|
fieldEntries.push(`${fieldName}: ${valueType}`);
|
|
1077
1187
|
}
|
|
1078
|
-
objectTypes.push(
|
|
1188
|
+
objectTypes.push(
|
|
1189
|
+
`v.object({
|
|
1190
|
+
${fieldEntries.map((e) => ` ${e},`).join("\n")}
|
|
1191
|
+
})`
|
|
1192
|
+
);
|
|
1079
1193
|
}
|
|
1080
|
-
const innerType = objectTypes.length === 1 ? objectTypes[0] : `v.union(
|
|
1081
|
-
|
|
1194
|
+
const innerType = objectTypes.length === 1 ? objectTypes[0] : `v.union(
|
|
1195
|
+
${objectTypes.map((o) => ` ${o},`).join("\n")}
|
|
1196
|
+
)`;
|
|
1197
|
+
const arrayType = `v.array(
|
|
1198
|
+
${innerType}
|
|
1199
|
+
)`;
|
|
1082
1200
|
return processFieldValueTypeOptions({
|
|
1083
1201
|
field: props.field,
|
|
1084
1202
|
collectionSlug: props.collectionSlug,
|
|
@@ -1106,6 +1224,42 @@ function blocksColumnDef(props) {
|
|
|
1106
1224
|
};
|
|
1107
1225
|
}
|
|
1108
1226
|
|
|
1227
|
+
// src/fields/color/config.ts
|
|
1228
|
+
function color(props) {
|
|
1229
|
+
return {
|
|
1230
|
+
...props,
|
|
1231
|
+
type: "color"
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// src/fields/color/schemaValueType.ts
|
|
1236
|
+
function colorToValueTypeString(props) {
|
|
1237
|
+
return processFieldValueTypeOptions({
|
|
1238
|
+
field: props.field,
|
|
1239
|
+
collectionSlug: props.collectionSlug,
|
|
1240
|
+
fieldName: props.fieldName,
|
|
1241
|
+
expectedType: "string",
|
|
1242
|
+
valueType: TEXT_VALUETYPE
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// src/fields/color/columnDef.ts
|
|
1247
|
+
function colorColumnDef(props) {
|
|
1248
|
+
return {
|
|
1249
|
+
accessorKey: props.fieldKey,
|
|
1250
|
+
header: props.field.label ?? props.fieldKey,
|
|
1251
|
+
size: 120,
|
|
1252
|
+
cell: (info) => {
|
|
1253
|
+
const value = info.getValue();
|
|
1254
|
+
if (!value) return "";
|
|
1255
|
+
return value;
|
|
1256
|
+
},
|
|
1257
|
+
meta: {
|
|
1258
|
+
type: "color"
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1109
1263
|
// src/valueTypes/extract.ts
|
|
1110
1264
|
function fieldToValueType(props) {
|
|
1111
1265
|
const { field, collectionSlug, fieldName } = props;
|
|
@@ -1128,6 +1282,13 @@ function fieldToValueType(props) {
|
|
|
1128
1282
|
return uploadToValueTypeString({ field, collectionSlug, fieldName });
|
|
1129
1283
|
case "json":
|
|
1130
1284
|
return jsonToValueTypeString({ field, collectionSlug, fieldName });
|
|
1285
|
+
case "object":
|
|
1286
|
+
return objectToValueTypeString({
|
|
1287
|
+
field,
|
|
1288
|
+
collectionSlug,
|
|
1289
|
+
fieldName,
|
|
1290
|
+
resolveInnerField: fieldToValueType
|
|
1291
|
+
});
|
|
1131
1292
|
case "richtext":
|
|
1132
1293
|
return richtextToValueTypeString({ field, collectionSlug, fieldName });
|
|
1133
1294
|
case "array":
|
|
@@ -1150,6 +1311,10 @@ function fieldToValueType(props) {
|
|
|
1150
1311
|
}),
|
|
1151
1312
|
visitedBlockSlugs: props.visitedBlockSlugs
|
|
1152
1313
|
});
|
|
1314
|
+
case "color":
|
|
1315
|
+
return colorToValueTypeString({ field, collectionSlug, fieldName });
|
|
1316
|
+
case "tabs":
|
|
1317
|
+
return "v.any()";
|
|
1153
1318
|
case "ui":
|
|
1154
1319
|
throw new VexFieldValidationError(
|
|
1155
1320
|
collectionSlug,
|
|
@@ -1390,6 +1555,43 @@ function buildSlugRegistry(props) {
|
|
|
1390
1555
|
}
|
|
1391
1556
|
|
|
1392
1557
|
// src/valueTypes/generate.ts
|
|
1558
|
+
function expandFields(props) {
|
|
1559
|
+
const result = [];
|
|
1560
|
+
for (const [fieldName, field] of Object.entries(props.fields)) {
|
|
1561
|
+
if (field.type === "ui") continue;
|
|
1562
|
+
if (field.type === "tabs") {
|
|
1563
|
+
const tabsField = field;
|
|
1564
|
+
for (const tab of tabsField.tabs) {
|
|
1565
|
+
const innerFields = [];
|
|
1566
|
+
for (const [innerName, innerField] of Object.entries(tab.fields)) {
|
|
1567
|
+
if (innerField.type === "ui") continue;
|
|
1568
|
+
const innerValueType = fieldToValueType({
|
|
1569
|
+
field: innerField,
|
|
1570
|
+
collectionSlug: props.collectionSlug,
|
|
1571
|
+
fieldName: innerName
|
|
1572
|
+
});
|
|
1573
|
+
innerFields.push(`${innerName}: ${innerValueType}`);
|
|
1574
|
+
}
|
|
1575
|
+
if (innerFields.length > 0) {
|
|
1576
|
+
result.push({
|
|
1577
|
+
name: tab.slug,
|
|
1578
|
+
valueType: `v.optional(v.object({ ${innerFields.join(", ")} }))`
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
} else {
|
|
1583
|
+
result.push({
|
|
1584
|
+
name: fieldName,
|
|
1585
|
+
valueType: fieldToValueType({
|
|
1586
|
+
fieldName,
|
|
1587
|
+
field,
|
|
1588
|
+
collectionSlug: props.collectionSlug
|
|
1589
|
+
})
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
return result;
|
|
1594
|
+
}
|
|
1393
1595
|
function generateVexSchema(props) {
|
|
1394
1596
|
const config = props.config;
|
|
1395
1597
|
buildSlugRegistry({ config });
|
|
@@ -1440,19 +1642,10 @@ function generateVexSchema(props) {
|
|
|
1440
1642
|
searchIndexes.push(si);
|
|
1441
1643
|
}
|
|
1442
1644
|
} else {
|
|
1443
|
-
|
|
1444
|
-
collection.fields
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
fields.push({
|
|
1448
|
-
name: fieldName,
|
|
1449
|
-
valueType: fieldToValueType({
|
|
1450
|
-
fieldName,
|
|
1451
|
-
field,
|
|
1452
|
-
collectionSlug: collection.slug
|
|
1453
|
-
})
|
|
1454
|
-
});
|
|
1455
|
-
}
|
|
1645
|
+
fields.push(...expandFields({
|
|
1646
|
+
fields: collection.fields,
|
|
1647
|
+
collectionSlug: collection.slug
|
|
1648
|
+
}));
|
|
1456
1649
|
}
|
|
1457
1650
|
lines.push(
|
|
1458
1651
|
"",
|
|
@@ -1575,6 +1768,11 @@ function generateVexSchema(props) {
|
|
|
1575
1768
|
for (const f of fields) {
|
|
1576
1769
|
lines.push(` ${f.name}: ${f.valueType},`);
|
|
1577
1770
|
}
|
|
1771
|
+
lines.push(` vex_status: v.optional(v.union(v.literal("draft"), v.literal("published"))),`);
|
|
1772
|
+
if (global.versions?.drafts) {
|
|
1773
|
+
lines.push(` vex_version: v.optional(v.number()),`);
|
|
1774
|
+
lines.push(` vex_publishedAt: v.optional(v.number()),`);
|
|
1775
|
+
}
|
|
1578
1776
|
lines.push("})");
|
|
1579
1777
|
for (const i of indexes) {
|
|
1580
1778
|
const fieldList = i.fields.map((f) => `"${f}"`).join(", ");
|
|
@@ -1588,7 +1786,12 @@ function generateVexSchema(props) {
|
|
|
1588
1786
|
lines.push(" collection: v.string(),");
|
|
1589
1787
|
lines.push(" documentId: v.string(),");
|
|
1590
1788
|
lines.push(" version: v.number(),");
|
|
1591
|
-
lines.push(
|
|
1789
|
+
lines.push(" status: v.union(");
|
|
1790
|
+
lines.push(` v.literal("draft"),`);
|
|
1791
|
+
lines.push(` v.literal("published"),`);
|
|
1792
|
+
lines.push(` v.literal("autosave"),`);
|
|
1793
|
+
lines.push(` v.literal("previewSnapshot"),`);
|
|
1794
|
+
lines.push(" ),");
|
|
1592
1795
|
lines.push(" snapshot: v.any(),");
|
|
1593
1796
|
lines.push(" createdAt: v.number(),");
|
|
1594
1797
|
lines.push(" createdBy: v.optional(v.string()),");
|
|
@@ -1683,7 +1886,7 @@ function generateColumns(props) {
|
|
|
1683
1886
|
continue;
|
|
1684
1887
|
}
|
|
1685
1888
|
if (field.admin?.hidden) continue;
|
|
1686
|
-
if (field.type === "ui") continue;
|
|
1889
|
+
if (field.type === "ui" || field.type === "tabs") continue;
|
|
1687
1890
|
const col = buildColumnDef(fieldKey, field);
|
|
1688
1891
|
if (useAsTitle && fieldKey === useAsTitle) {
|
|
1689
1892
|
col.meta = { ...col.meta, isTitle: true };
|
|
@@ -1706,7 +1909,7 @@ function generateColumns(props) {
|
|
|
1706
1909
|
for (const fieldKey of allFieldKeys) {
|
|
1707
1910
|
const field = fields[fieldKey] ?? authFields[fieldKey];
|
|
1708
1911
|
if (field.admin?.hidden) continue;
|
|
1709
|
-
if (field.type === "ui") continue;
|
|
1912
|
+
if (field.type === "ui" || field.type === "tabs") continue;
|
|
1710
1913
|
const col = buildColumnDef(fieldKey, field);
|
|
1711
1914
|
if (useAsTitle && fieldKey === useAsTitle) {
|
|
1712
1915
|
col.meta = { ...col.meta, isTitle: true };
|
|
@@ -1741,6 +1944,8 @@ function buildColumnDef(fieldKey, field) {
|
|
|
1741
1944
|
return relationshipColumnDef({ fieldKey, field });
|
|
1742
1945
|
case "json":
|
|
1743
1946
|
return jsonColumnDef({ fieldKey, field });
|
|
1947
|
+
case "object":
|
|
1948
|
+
return objectColumnDef({ fieldKey, field });
|
|
1744
1949
|
case "richtext":
|
|
1745
1950
|
return richtextColumnDef({ fieldKey, field });
|
|
1746
1951
|
case "array":
|
|
@@ -1749,6 +1954,8 @@ function buildColumnDef(fieldKey, field) {
|
|
|
1749
1954
|
return uploadColumnDef({ fieldKey, field });
|
|
1750
1955
|
case "blocks":
|
|
1751
1956
|
return blocksColumnDef({ fieldKey, field });
|
|
1957
|
+
case "color":
|
|
1958
|
+
return colorColumnDef({ fieldKey, field });
|
|
1752
1959
|
default:
|
|
1753
1960
|
return {
|
|
1754
1961
|
accessorKey: fieldKey,
|
|
@@ -1764,6 +1971,19 @@ function generateFormSchema(props) {
|
|
|
1764
1971
|
for (const [fieldName, field] of Object.entries(props.fields)) {
|
|
1765
1972
|
if (field.admin?.hidden) continue;
|
|
1766
1973
|
if (field.type === "ui") continue;
|
|
1974
|
+
if (field.type === "tabs") {
|
|
1975
|
+
for (const tab of field.tabs) {
|
|
1976
|
+
const tabFields = {};
|
|
1977
|
+
for (const [subName, subField] of Object.entries(tab.fields)) {
|
|
1978
|
+
if (subField.type === "ui") continue;
|
|
1979
|
+
let subValidator = fieldMetaToZod({ field: subField });
|
|
1980
|
+
if (!subField.required) subValidator = subValidator.optional();
|
|
1981
|
+
tabFields[subName] = subValidator;
|
|
1982
|
+
}
|
|
1983
|
+
shape[tab.slug] = z.object(tabFields).optional();
|
|
1984
|
+
}
|
|
1985
|
+
continue;
|
|
1986
|
+
}
|
|
1767
1987
|
let validator = fieldMetaToZod({ field });
|
|
1768
1988
|
if (!field.required) {
|
|
1769
1989
|
validator = validator.optional();
|
|
@@ -1815,10 +2035,23 @@ function fieldMetaToZod(props) {
|
|
|
1815
2035
|
}
|
|
1816
2036
|
case "json":
|
|
1817
2037
|
return z.any();
|
|
2038
|
+
case "object": {
|
|
2039
|
+
const shape = {};
|
|
2040
|
+
for (const [subName, subField] of Object.entries(props.field.fields)) {
|
|
2041
|
+
let subValidator = fieldMetaToZod({ field: subField });
|
|
2042
|
+
if (!subField.required) subValidator = subValidator.optional();
|
|
2043
|
+
shape[subName] = subValidator;
|
|
2044
|
+
}
|
|
2045
|
+
return z.object(shape);
|
|
2046
|
+
}
|
|
1818
2047
|
case "richtext":
|
|
1819
2048
|
return z.any();
|
|
2049
|
+
case "color":
|
|
2050
|
+
return z.string();
|
|
2051
|
+
case "tabs":
|
|
2052
|
+
return z.any();
|
|
1820
2053
|
case "array": {
|
|
1821
|
-
let schema = z.array(fieldMetaToZod({ field: props.field.
|
|
2054
|
+
let schema = z.array(fieldMetaToZod({ field: props.field.items }));
|
|
1822
2055
|
if (props.field.min != null) schema = schema.min(props.field.min);
|
|
1823
2056
|
if (props.field.max != null) schema = schema.max(props.field.max);
|
|
1824
2057
|
return schema;
|
|
@@ -1878,15 +2111,26 @@ function getFormDefaultValue(props) {
|
|
|
1878
2111
|
case "imageUrl":
|
|
1879
2112
|
return props.field.defaultValue ?? "";
|
|
1880
2113
|
case "relationship":
|
|
1881
|
-
return props.field.hasMany ? [] :
|
|
2114
|
+
return props.field.hasMany ? [] : void 0;
|
|
1882
2115
|
case "upload":
|
|
1883
|
-
return props.field.hasMany ? [] :
|
|
2116
|
+
return props.field.hasMany ? [] : void 0;
|
|
1884
2117
|
case "json":
|
|
1885
2118
|
return {};
|
|
2119
|
+
case "object": {
|
|
2120
|
+
const defaults = {};
|
|
2121
|
+
for (const [subName, subField] of Object.entries(props.field.fields)) {
|
|
2122
|
+
defaults[subName] = getFormDefaultValue({ field: subField });
|
|
2123
|
+
}
|
|
2124
|
+
return defaults;
|
|
2125
|
+
}
|
|
1886
2126
|
case "richtext":
|
|
1887
2127
|
return [];
|
|
2128
|
+
case "color":
|
|
2129
|
+
return props.field.defaultValue ?? "";
|
|
2130
|
+
case "tabs":
|
|
2131
|
+
return {};
|
|
1888
2132
|
case "array":
|
|
1889
|
-
return [];
|
|
2133
|
+
return props.field.defaultValue ?? [];
|
|
1890
2134
|
case "blocks":
|
|
1891
2135
|
return [];
|
|
1892
2136
|
case "ui":
|
|
@@ -1900,6 +2144,17 @@ function generateFormDefaultValues(props) {
|
|
|
1900
2144
|
for (const [fieldName, field] of Object.entries(props.fields)) {
|
|
1901
2145
|
if (field.admin?.hidden) continue;
|
|
1902
2146
|
if (field.type === "ui") continue;
|
|
2147
|
+
if (field.type === "tabs") {
|
|
2148
|
+
for (const tab of field.tabs) {
|
|
2149
|
+
const tabDefaults = {};
|
|
2150
|
+
for (const [subName, subField] of Object.entries(tab.fields)) {
|
|
2151
|
+
if (subField.type === "ui") continue;
|
|
2152
|
+
tabDefaults[subName] = getFormDefaultValue({ field: subField });
|
|
2153
|
+
}
|
|
2154
|
+
result[tab.slug] = tabDefaults;
|
|
2155
|
+
}
|
|
2156
|
+
continue;
|
|
2157
|
+
}
|
|
1903
2158
|
result[fieldName] = getFormDefaultValue({ field });
|
|
1904
2159
|
}
|
|
1905
2160
|
return result;
|
|
@@ -1915,8 +2170,16 @@ function ui(props) {
|
|
|
1915
2170
|
};
|
|
1916
2171
|
}
|
|
1917
2172
|
|
|
2173
|
+
// src/fields/tabs/config.ts
|
|
2174
|
+
function tabs(props) {
|
|
2175
|
+
return {
|
|
2176
|
+
...props,
|
|
2177
|
+
type: "tabs"
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
|
|
1918
2181
|
// src/types/fields.ts
|
|
1919
|
-
var RESERVED_BLOCK_FIELD_NAMES = ["blockType", "blockName", "_key"];
|
|
2182
|
+
var RESERVED_BLOCK_FIELD_NAMES = ["blockType", "blockName", "_key", "blockStyles"];
|
|
1920
2183
|
|
|
1921
2184
|
// src/blocks/defineBlock.ts
|
|
1922
2185
|
function defineBlock(props) {
|
|
@@ -1934,6 +2197,23 @@ function defineBlock(props) {
|
|
|
1934
2197
|
);
|
|
1935
2198
|
}
|
|
1936
2199
|
}
|
|
2200
|
+
const VALID_STYLE_TIERS = ["container", "text", "layout", "media"];
|
|
2201
|
+
if (props.admin?.blockStyles && props.admin.blockStyles !== true) {
|
|
2202
|
+
if (!Array.isArray(props.admin.blockStyles)) {
|
|
2203
|
+
throw new VexBlockValidationError(
|
|
2204
|
+
props.slug,
|
|
2205
|
+
`admin.blockStyles must be true or an array of style tier names. Got: ${typeof props.admin.blockStyles}`
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
for (const tier of props.admin.blockStyles) {
|
|
2209
|
+
if (!VALID_STYLE_TIERS.includes(tier)) {
|
|
2210
|
+
throw new VexBlockValidationError(
|
|
2211
|
+
props.slug,
|
|
2212
|
+
`Invalid style tier "${tier}" in admin.blockStyles. Valid tiers: ${VALID_STYLE_TIERS.join(", ")}`
|
|
2213
|
+
);
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
1937
2217
|
return {
|
|
1938
2218
|
slug: props.slug,
|
|
1939
2219
|
label: props.label,
|
|
@@ -1943,6 +2223,237 @@ function defineBlock(props) {
|
|
|
1943
2223
|
};
|
|
1944
2224
|
}
|
|
1945
2225
|
|
|
2226
|
+
// src/styles/presets.ts
|
|
2227
|
+
var SPACING_PRESETS = [
|
|
2228
|
+
{ value: "0", label: "0", hint: "0px" },
|
|
2229
|
+
{ value: "0.5", label: "0.5", hint: "2px / 0.125rem" },
|
|
2230
|
+
{ value: "1", label: "1", hint: "4px / 0.25rem" },
|
|
2231
|
+
{ value: "1.5", label: "1.5", hint: "6px / 0.375rem" },
|
|
2232
|
+
{ value: "2", label: "2", hint: "8px / 0.5rem" },
|
|
2233
|
+
{ value: "3", label: "3", hint: "12px / 0.75rem" },
|
|
2234
|
+
{ value: "4", label: "4", hint: "16px / 1rem" },
|
|
2235
|
+
{ value: "5", label: "5", hint: "20px / 1.25rem" },
|
|
2236
|
+
{ value: "6", label: "6", hint: "24px / 1.5rem" },
|
|
2237
|
+
{ value: "8", label: "8", hint: "32px / 2rem" },
|
|
2238
|
+
{ value: "10", label: "10", hint: "40px / 2.5rem" },
|
|
2239
|
+
{ value: "12", label: "12", hint: "48px / 3rem" },
|
|
2240
|
+
{ value: "16", label: "16", hint: "64px / 4rem" },
|
|
2241
|
+
{ value: "20", label: "20", hint: "80px / 5rem" },
|
|
2242
|
+
{ value: "24", label: "24", hint: "96px / 6rem" }
|
|
2243
|
+
];
|
|
2244
|
+
var FONT_SIZE_PRESETS = [
|
|
2245
|
+
{ value: "xs", label: "XS", hint: "12px / 0.75rem" },
|
|
2246
|
+
{ value: "sm", label: "SM", hint: "14px / 0.875rem" },
|
|
2247
|
+
{ value: "base", label: "Base", hint: "16px / 1rem" },
|
|
2248
|
+
{ value: "lg", label: "LG", hint: "18px / 1.125rem" },
|
|
2249
|
+
{ value: "xl", label: "XL", hint: "20px / 1.25rem" },
|
|
2250
|
+
{ value: "2xl", label: "2XL", hint: "24px / 1.5rem" },
|
|
2251
|
+
{ value: "3xl", label: "3XL", hint: "30px / 1.875rem" },
|
|
2252
|
+
{ value: "4xl", label: "4XL", hint: "36px / 2.25rem" },
|
|
2253
|
+
{ value: "5xl", label: "5XL", hint: "48px / 3rem" }
|
|
2254
|
+
];
|
|
2255
|
+
var FONT_WEIGHT_PRESETS = [
|
|
2256
|
+
{ value: "thin", label: "Thin", hint: "100" },
|
|
2257
|
+
{ value: "light", label: "Light", hint: "300" },
|
|
2258
|
+
{ value: "normal", label: "Normal", hint: "400" },
|
|
2259
|
+
{ value: "medium", label: "Medium", hint: "500" },
|
|
2260
|
+
{ value: "semibold", label: "Semibold", hint: "600" },
|
|
2261
|
+
{ value: "bold", label: "Bold", hint: "700" },
|
|
2262
|
+
{ value: "extrabold", label: "Extra Bold", hint: "800" }
|
|
2263
|
+
];
|
|
2264
|
+
var BORDER_RADIUS_PRESETS = [
|
|
2265
|
+
{ value: "none", label: "None", hint: "0px" },
|
|
2266
|
+
{ value: "sm", label: "SM", hint: "2px / 0.125rem" },
|
|
2267
|
+
{ value: "DEFAULT", label: "Default", hint: "4px / 0.25rem" },
|
|
2268
|
+
{ value: "md", label: "MD", hint: "6px / 0.375rem" },
|
|
2269
|
+
{ value: "lg", label: "LG", hint: "8px / 0.5rem" },
|
|
2270
|
+
{ value: "xl", label: "XL", hint: "12px / 0.75rem" },
|
|
2271
|
+
{ value: "2xl", label: "2XL", hint: "16px / 1rem" },
|
|
2272
|
+
{ value: "3xl", label: "3XL", hint: "24px / 1.5rem" },
|
|
2273
|
+
{ value: "full", label: "Full", hint: "9999px" }
|
|
2274
|
+
];
|
|
2275
|
+
var BOX_SHADOW_PRESETS = [
|
|
2276
|
+
{ value: "none", label: "None", hint: "no shadow" },
|
|
2277
|
+
{ value: "sm", label: "SM", hint: "small" },
|
|
2278
|
+
{ value: "DEFAULT", label: "Default", hint: "medium" },
|
|
2279
|
+
{ value: "md", label: "MD", hint: "medium" },
|
|
2280
|
+
{ value: "lg", label: "LG", hint: "large" },
|
|
2281
|
+
{ value: "xl", label: "XL", hint: "extra large" },
|
|
2282
|
+
{ value: "2xl", label: "2XL", hint: "xx-large" }
|
|
2283
|
+
];
|
|
2284
|
+
var OPACITY_PRESETS = [
|
|
2285
|
+
{ value: "0", label: "0%", hint: "invisible" },
|
|
2286
|
+
{ value: "5", label: "5%", hint: "" },
|
|
2287
|
+
{ value: "10", label: "10%", hint: "" },
|
|
2288
|
+
{ value: "25", label: "25%", hint: "" },
|
|
2289
|
+
{ value: "50", label: "50%", hint: "" },
|
|
2290
|
+
{ value: "75", label: "75%", hint: "" },
|
|
2291
|
+
{ value: "100", label: "100%", hint: "fully visible" }
|
|
2292
|
+
];
|
|
2293
|
+
var WIDTH_PRESETS = [
|
|
2294
|
+
{ value: "auto", label: "Auto", hint: "auto" },
|
|
2295
|
+
{ value: "full", label: "Full", hint: "100%" },
|
|
2296
|
+
{ value: "screen", label: "Screen", hint: "100vw" },
|
|
2297
|
+
{ value: "1/2", label: "1/2", hint: "50%" },
|
|
2298
|
+
{ value: "1/3", label: "1/3", hint: "33.33%" },
|
|
2299
|
+
{ value: "2/3", label: "2/3", hint: "66.67%" },
|
|
2300
|
+
{ value: "1/4", label: "1/4", hint: "25%" },
|
|
2301
|
+
{ value: "3/4", label: "3/4", hint: "75%" },
|
|
2302
|
+
{ value: "max", label: "Max Content", hint: "max-content" },
|
|
2303
|
+
{ value: "fit", label: "Fit Content", hint: "fit-content" }
|
|
2304
|
+
];
|
|
2305
|
+
var MAX_WIDTH_PRESETS = [
|
|
2306
|
+
{ value: "none", label: "None", hint: "no limit" },
|
|
2307
|
+
{ value: "xs", label: "XS", hint: "320px / 20rem" },
|
|
2308
|
+
{ value: "sm", label: "SM", hint: "384px / 24rem" },
|
|
2309
|
+
{ value: "md", label: "MD", hint: "448px / 28rem" },
|
|
2310
|
+
{ value: "lg", label: "LG", hint: "512px / 32rem" },
|
|
2311
|
+
{ value: "xl", label: "XL", hint: "576px / 36rem" },
|
|
2312
|
+
{ value: "2xl", label: "2XL", hint: "672px / 42rem" },
|
|
2313
|
+
{ value: "3xl", label: "3XL", hint: "768px / 48rem" },
|
|
2314
|
+
{ value: "4xl", label: "4XL", hint: "896px / 56rem" },
|
|
2315
|
+
{ value: "5xl", label: "5XL", hint: "1024px / 64rem" },
|
|
2316
|
+
{ value: "6xl", label: "6XL", hint: "1152px / 72rem" },
|
|
2317
|
+
{ value: "7xl", label: "7XL", hint: "1280px / 80rem" },
|
|
2318
|
+
{ value: "full", label: "Full", hint: "100%" },
|
|
2319
|
+
{ value: "screen", label: "Screen", hint: "100vw" }
|
|
2320
|
+
];
|
|
2321
|
+
var LINE_HEIGHT_PRESETS = [
|
|
2322
|
+
{ value: "none", label: "None", hint: "1" },
|
|
2323
|
+
{ value: "tight", label: "Tight", hint: "1.25" },
|
|
2324
|
+
{ value: "snug", label: "Snug", hint: "1.375" },
|
|
2325
|
+
{ value: "normal", label: "Normal", hint: "1.5" },
|
|
2326
|
+
{ value: "relaxed", label: "Relaxed", hint: "1.625" },
|
|
2327
|
+
{ value: "loose", label: "Loose", hint: "2" }
|
|
2328
|
+
];
|
|
2329
|
+
var LETTER_SPACING_PRESETS = [
|
|
2330
|
+
{ value: "tighter", label: "Tighter", hint: "-0.05em" },
|
|
2331
|
+
{ value: "tight", label: "Tight", hint: "-0.025em" },
|
|
2332
|
+
{ value: "normal", label: "Normal", hint: "0em" },
|
|
2333
|
+
{ value: "wide", label: "Wide", hint: "0.025em" },
|
|
2334
|
+
{ value: "wider", label: "Wider", hint: "0.05em" },
|
|
2335
|
+
{ value: "widest", label: "Widest", hint: "0.1em" }
|
|
2336
|
+
];
|
|
2337
|
+
var BORDER_WIDTH_PRESETS = [
|
|
2338
|
+
{ value: "0", label: "None", hint: "0px" },
|
|
2339
|
+
{ value: "DEFAULT", label: "Default", hint: "1px" },
|
|
2340
|
+
{ value: "2", label: "2", hint: "2px" },
|
|
2341
|
+
{ value: "4", label: "4", hint: "4px" },
|
|
2342
|
+
{ value: "8", label: "8", hint: "8px" }
|
|
2343
|
+
];
|
|
2344
|
+
var ASPECT_RATIO_PRESETS = [
|
|
2345
|
+
{ value: "auto", label: "Auto", hint: "auto" },
|
|
2346
|
+
{ value: "square", label: "Square", hint: "1 / 1" },
|
|
2347
|
+
{ value: "video", label: "Video", hint: "16 / 9" },
|
|
2348
|
+
{ value: "4/3", label: "4:3", hint: "4 / 3" },
|
|
2349
|
+
{ value: "3/2", label: "3:2", hint: "3 / 2" }
|
|
2350
|
+
];
|
|
2351
|
+
|
|
2352
|
+
// src/styles/blockStylesToTailwind.ts
|
|
2353
|
+
var PROPERTY_CLASS_MAP = {
|
|
2354
|
+
// Container — spacing
|
|
2355
|
+
margin: (v2) => `m-${v2}`,
|
|
2356
|
+
marginTop: (v2) => `mt-${v2}`,
|
|
2357
|
+
marginRight: (v2) => `mr-${v2}`,
|
|
2358
|
+
marginBottom: (v2) => `mb-${v2}`,
|
|
2359
|
+
marginLeft: (v2) => `ml-${v2}`,
|
|
2360
|
+
padding: (v2) => `p-${v2}`,
|
|
2361
|
+
paddingTop: (v2) => `pt-${v2}`,
|
|
2362
|
+
paddingRight: (v2) => `pr-${v2}`,
|
|
2363
|
+
paddingBottom: (v2) => `pb-${v2}`,
|
|
2364
|
+
paddingLeft: (v2) => `pl-${v2}`,
|
|
2365
|
+
// Container — sizing
|
|
2366
|
+
width: (v2) => `w-${v2}`,
|
|
2367
|
+
maxWidth: (v2) => `max-w-${v2}`,
|
|
2368
|
+
// Container — background
|
|
2369
|
+
backgroundColor: (v2) => {
|
|
2370
|
+
if (v2.startsWith("var(") || v2.startsWith("#") || v2.startsWith("rgb") || v2.startsWith("hsl") || v2.startsWith("oklch")) {
|
|
2371
|
+
return `bg-[${v2}]`;
|
|
2372
|
+
}
|
|
2373
|
+
return `bg-${v2}`;
|
|
2374
|
+
},
|
|
2375
|
+
// Container — border
|
|
2376
|
+
borderWidth: (v2) => v2 === "DEFAULT" ? "border" : `border-${v2}`,
|
|
2377
|
+
borderColor: (v2) => {
|
|
2378
|
+
if (v2.startsWith("var(") || v2.startsWith("#") || v2.startsWith("rgb") || v2.startsWith("hsl") || v2.startsWith("oklch")) {
|
|
2379
|
+
return `border-[${v2}]`;
|
|
2380
|
+
}
|
|
2381
|
+
return `border-${v2}`;
|
|
2382
|
+
},
|
|
2383
|
+
borderStyle: (v2) => `border-${v2}`,
|
|
2384
|
+
borderRadius: (v2) => v2 === "DEFAULT" ? "rounded" : `rounded-${v2}`,
|
|
2385
|
+
// Container — effects
|
|
2386
|
+
boxShadow: (v2) => v2 === "DEFAULT" ? "shadow" : `shadow-${v2}`,
|
|
2387
|
+
opacity: (v2) => `opacity-${v2}`,
|
|
2388
|
+
// Container — display
|
|
2389
|
+
display: (v2) => {
|
|
2390
|
+
if (v2 === "inline-flex") return "inline-flex";
|
|
2391
|
+
return v2;
|
|
2392
|
+
},
|
|
2393
|
+
overflow: (v2) => `overflow-${v2}`,
|
|
2394
|
+
// Text
|
|
2395
|
+
textAlign: (v2) => `text-${v2}`,
|
|
2396
|
+
fontSize: (v2) => `text-${v2}`,
|
|
2397
|
+
fontWeight: (v2) => `font-${v2}`,
|
|
2398
|
+
color: (v2) => {
|
|
2399
|
+
if (v2.startsWith("var(") || v2.startsWith("#") || v2.startsWith("rgb") || v2.startsWith("hsl") || v2.startsWith("oklch")) {
|
|
2400
|
+
return `text-[${v2}]`;
|
|
2401
|
+
}
|
|
2402
|
+
return `text-${v2}`;
|
|
2403
|
+
},
|
|
2404
|
+
lineHeight: (v2) => `leading-${v2}`,
|
|
2405
|
+
letterSpacing: (v2) => `tracking-${v2}`,
|
|
2406
|
+
// Layout
|
|
2407
|
+
gap: (v2) => `gap-${v2}`,
|
|
2408
|
+
flexDirection: (v2) => {
|
|
2409
|
+
const map = {
|
|
2410
|
+
row: "flex-row",
|
|
2411
|
+
column: "flex-col",
|
|
2412
|
+
"row-reverse": "flex-row-reverse",
|
|
2413
|
+
"column-reverse": "flex-col-reverse"
|
|
2414
|
+
};
|
|
2415
|
+
return map[v2] ?? `flex-${v2}`;
|
|
2416
|
+
},
|
|
2417
|
+
alignItems: (v2) => `items-${v2}`,
|
|
2418
|
+
justifyContent: (v2) => `justify-${v2}`,
|
|
2419
|
+
flexWrap: (v2) => `flex-${v2}`,
|
|
2420
|
+
// Media
|
|
2421
|
+
objectFit: (v2) => `object-${v2}`,
|
|
2422
|
+
aspectRatio: (v2) => `aspect-${v2}`,
|
|
2423
|
+
objectPosition: (v2) => `object-${v2}`
|
|
2424
|
+
};
|
|
2425
|
+
function stylesToClasses(props) {
|
|
2426
|
+
const classes = [];
|
|
2427
|
+
for (const [key, value] of Object.entries(props.styles)) {
|
|
2428
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
2429
|
+
const mapper = PROPERTY_CLASS_MAP[key];
|
|
2430
|
+
if (!mapper) continue;
|
|
2431
|
+
classes.push(mapper(String(value)));
|
|
2432
|
+
}
|
|
2433
|
+
return classes;
|
|
2434
|
+
}
|
|
2435
|
+
function blockStylesToTailwind(props) {
|
|
2436
|
+
if (!props.blockStylesJson) return "";
|
|
2437
|
+
let data;
|
|
2438
|
+
try {
|
|
2439
|
+
data = JSON.parse(props.blockStylesJson);
|
|
2440
|
+
} catch {
|
|
2441
|
+
return "";
|
|
2442
|
+
}
|
|
2443
|
+
const result = [];
|
|
2444
|
+
if (data.base) {
|
|
2445
|
+
result.push(...stylesToClasses({ styles: data.base }));
|
|
2446
|
+
}
|
|
2447
|
+
const breakpointKeys = Object.keys(data).filter((k) => k !== "base").sort();
|
|
2448
|
+
for (const bp of breakpointKeys) {
|
|
2449
|
+
const classes = stylesToClasses({ styles: data[bp] });
|
|
2450
|
+
for (const cls of classes) {
|
|
2451
|
+
result.push(`${bp}:${cls}`);
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
return result.join(" ");
|
|
2455
|
+
}
|
|
2456
|
+
|
|
1946
2457
|
// src/typeGen/slugToInterfaceName.ts
|
|
1947
2458
|
function slugToInterfaceName(props) {
|
|
1948
2459
|
return props.slug.replace(/[-_]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").split(/\s+/).filter(Boolean).map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1).toLowerCase()).join("");
|
|
@@ -1963,8 +2474,14 @@ function fieldToTypeString(props) {
|
|
|
1963
2474
|
return "string";
|
|
1964
2475
|
case "json":
|
|
1965
2476
|
return "Record<string, unknown>";
|
|
2477
|
+
case "object":
|
|
2478
|
+
return "Record<string, unknown>";
|
|
1966
2479
|
case "richtext":
|
|
1967
2480
|
return "RichTextDocument";
|
|
2481
|
+
case "color":
|
|
2482
|
+
return "string";
|
|
2483
|
+
case "tabs":
|
|
2484
|
+
return "Record<string, unknown>";
|
|
1968
2485
|
case "ui":
|
|
1969
2486
|
return "never";
|
|
1970
2487
|
case "select": {
|
|
@@ -1986,7 +2503,7 @@ function fieldToTypeString(props) {
|
|
|
1986
2503
|
}
|
|
1987
2504
|
case "array": {
|
|
1988
2505
|
const inner = fieldToTypeString({
|
|
1989
|
-
field: props.field.
|
|
2506
|
+
field: props.field.items,
|
|
1990
2507
|
blockInterfaceNames: props.blockInterfaceNames
|
|
1991
2508
|
});
|
|
1992
2509
|
const needsParens = inner.includes("|");
|
|
@@ -2023,6 +2540,10 @@ function generateVexTypes(props) {
|
|
|
2023
2540
|
collectBlocks(block.fields);
|
|
2024
2541
|
}
|
|
2025
2542
|
}
|
|
2543
|
+
} else if (field.type === "tabs") {
|
|
2544
|
+
for (const tab of field.tabs) {
|
|
2545
|
+
collectBlocks(tab.fields);
|
|
2546
|
+
}
|
|
2026
2547
|
}
|
|
2027
2548
|
}
|
|
2028
2549
|
}
|
|
@@ -2093,6 +2614,10 @@ function generateVexTypes(props) {
|
|
|
2093
2614
|
for (const field of Object.values(fields)) {
|
|
2094
2615
|
if (field.type === "relationship" || field.type === "upload") {
|
|
2095
2616
|
needsIdImport = true;
|
|
2617
|
+
} else if (field.type === "tabs") {
|
|
2618
|
+
for (const tab of field.tabs) {
|
|
2619
|
+
checkForIdFields(tab.fields);
|
|
2620
|
+
}
|
|
2096
2621
|
}
|
|
2097
2622
|
}
|
|
2098
2623
|
}
|
|
@@ -2118,6 +2643,10 @@ function generateVexTypes(props) {
|
|
|
2118
2643
|
for (const field of Object.values(fields)) {
|
|
2119
2644
|
if (field.type === "richtext") {
|
|
2120
2645
|
needsRichTextImport = true;
|
|
2646
|
+
} else if (field.type === "tabs") {
|
|
2647
|
+
for (const tab of field.tabs) {
|
|
2648
|
+
checkForRichTextFields(tab.fields);
|
|
2649
|
+
}
|
|
2121
2650
|
}
|
|
2122
2651
|
}
|
|
2123
2652
|
}
|
|
@@ -2212,6 +2741,7 @@ function generateVexTypes(props) {
|
|
|
2212
2741
|
generateGlobalInterface({
|
|
2213
2742
|
name,
|
|
2214
2743
|
slug: g.slug,
|
|
2744
|
+
tableName: g.tableName ?? g.slug,
|
|
2215
2745
|
fields: g.fields,
|
|
2216
2746
|
blockInterfaceNames
|
|
2217
2747
|
})
|
|
@@ -2240,18 +2770,7 @@ function generateBlockInterface(props) {
|
|
|
2240
2770
|
lines.push(` blockType: '${props.block.slug}';`);
|
|
2241
2771
|
lines.push(` blockName?: string;`);
|
|
2242
2772
|
lines.push(` _key: string;`);
|
|
2243
|
-
|
|
2244
|
-
const f = field;
|
|
2245
|
-
if (f.type === "ui") continue;
|
|
2246
|
-
const label = f.label;
|
|
2247
|
-
if (label) lines.push(` /** ${label} */`);
|
|
2248
|
-
const optional = f.required ? "" : "?";
|
|
2249
|
-
const typeStr = fieldToTypeString({
|
|
2250
|
-
field: f,
|
|
2251
|
-
blockInterfaceNames: props.blockInterfaceNames
|
|
2252
|
-
});
|
|
2253
|
-
lines.push(` ${fieldName}${optional}: ${typeStr};`);
|
|
2254
|
-
}
|
|
2773
|
+
lines.push(...generateFieldLines({ fields: props.block.fields, blockInterfaceNames: props.blockInterfaceNames }));
|
|
2255
2774
|
lines.push("}");
|
|
2256
2775
|
return lines.join("\n");
|
|
2257
2776
|
}
|
|
@@ -2265,18 +2784,7 @@ function generateCollectionInterface(props) {
|
|
|
2265
2784
|
lines.push(` vex_version?: number;`);
|
|
2266
2785
|
lines.push(` vex_publishedAt?: number;`);
|
|
2267
2786
|
}
|
|
2268
|
-
|
|
2269
|
-
const f = field;
|
|
2270
|
-
if (f.type === "ui") continue;
|
|
2271
|
-
const label = f.label;
|
|
2272
|
-
if (label) lines.push(` /** ${label} */`);
|
|
2273
|
-
const optional = f.required ? "" : "?";
|
|
2274
|
-
const typeStr = fieldToTypeString({
|
|
2275
|
-
field: f,
|
|
2276
|
-
blockInterfaceNames: props.blockInterfaceNames
|
|
2277
|
-
});
|
|
2278
|
-
lines.push(` ${fieldName}${optional}: ${typeStr};`);
|
|
2279
|
-
}
|
|
2787
|
+
lines.push(...generateFieldLines({ fields: props.fields, blockInterfaceNames: props.blockInterfaceNames }));
|
|
2280
2788
|
lines.push("}");
|
|
2281
2789
|
return lines.join("\n");
|
|
2282
2790
|
}
|
|
@@ -2293,42 +2801,58 @@ function generateMediaCollectionInterface(props) {
|
|
|
2293
2801
|
lines.push(` width?: number;`);
|
|
2294
2802
|
lines.push(` height?: number;`);
|
|
2295
2803
|
const lockedSet = /* @__PURE__ */ new Set([...LOCKED_MEDIA_FIELDS, ...OVERRIDABLE_MEDIA_FIELDS]);
|
|
2804
|
+
const filteredFields = {};
|
|
2296
2805
|
for (const [fieldName, field] of Object.entries(props.userFields)) {
|
|
2297
2806
|
if (lockedSet.has(fieldName)) continue;
|
|
2298
|
-
|
|
2299
|
-
if (f.type === "ui") continue;
|
|
2300
|
-
const label = f.label;
|
|
2301
|
-
if (label) lines.push(` /** ${label} */`);
|
|
2302
|
-
const optional = f.required ? "" : "?";
|
|
2303
|
-
const typeStr = fieldToTypeString({
|
|
2304
|
-
field: f,
|
|
2305
|
-
blockInterfaceNames: props.blockInterfaceNames
|
|
2306
|
-
});
|
|
2307
|
-
lines.push(` ${fieldName}${optional}: ${typeStr};`);
|
|
2807
|
+
filteredFields[fieldName] = field;
|
|
2308
2808
|
}
|
|
2809
|
+
lines.push(...generateFieldLines({ fields: filteredFields, blockInterfaceNames: props.blockInterfaceNames }));
|
|
2309
2810
|
lines.push("}");
|
|
2310
2811
|
return lines.join("\n");
|
|
2311
2812
|
}
|
|
2312
2813
|
function generateGlobalInterface(props) {
|
|
2313
2814
|
const lines = [];
|
|
2314
2815
|
lines.push(`export interface ${props.name} {`);
|
|
2315
|
-
lines.push(` _id: Id<'
|
|
2816
|
+
lines.push(` _id: Id<'${props.tableName}'>;`);
|
|
2316
2817
|
lines.push(` _creationTime: number;`);
|
|
2317
|
-
lines.push(
|
|
2818
|
+
lines.push(...generateFieldLines({ fields: props.fields, blockInterfaceNames: props.blockInterfaceNames }));
|
|
2819
|
+
lines.push("}");
|
|
2820
|
+
return lines.join("\n");
|
|
2821
|
+
}
|
|
2822
|
+
function generateFieldLines(props) {
|
|
2823
|
+
const lines = [];
|
|
2318
2824
|
for (const [fieldName, field] of Object.entries(props.fields)) {
|
|
2319
2825
|
const f = field;
|
|
2320
2826
|
if (f.type === "ui") continue;
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2827
|
+
if (f.type === "tabs") {
|
|
2828
|
+
const tabsField = f;
|
|
2829
|
+
for (const tab of tabsField.tabs) {
|
|
2830
|
+
const innerProps = [];
|
|
2831
|
+
for (const [innerName, innerField] of Object.entries(tab.fields)) {
|
|
2832
|
+
if (innerField.type === "ui") continue;
|
|
2833
|
+
const innerOptional = innerField.required ? "" : "?";
|
|
2834
|
+
const innerTypeStr = fieldToTypeString({
|
|
2835
|
+
field: innerField,
|
|
2836
|
+
blockInterfaceNames: props.blockInterfaceNames
|
|
2837
|
+
});
|
|
2838
|
+
innerProps.push(`${innerName}${innerOptional}: ${innerTypeStr}`);
|
|
2839
|
+
}
|
|
2840
|
+
if (innerProps.length > 0) {
|
|
2841
|
+
lines.push(` ${tab.slug}?: { ${innerProps.join("; ")} };`);
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
} else {
|
|
2845
|
+
const label = f.label;
|
|
2846
|
+
if (label) lines.push(` /** ${label} */`);
|
|
2847
|
+
const optional = f.required ? "" : "?";
|
|
2848
|
+
const typeStr = fieldToTypeString({
|
|
2849
|
+
field: f,
|
|
2850
|
+
blockInterfaceNames: props.blockInterfaceNames
|
|
2851
|
+
});
|
|
2852
|
+
lines.push(` ${fieldName}${optional}: ${typeStr};`);
|
|
2853
|
+
}
|
|
2329
2854
|
}
|
|
2330
|
-
lines
|
|
2331
|
-
return lines.join("\n");
|
|
2855
|
+
return lines;
|
|
2332
2856
|
}
|
|
2333
2857
|
|
|
2334
2858
|
// src/versioning/constants.ts
|
|
@@ -2621,6 +3145,25 @@ function generateCollectionQueries(props) {
|
|
|
2621
3145
|
slugs.push(collection.slug);
|
|
2622
3146
|
}
|
|
2623
3147
|
}
|
|
3148
|
+
if (config.globals) {
|
|
3149
|
+
for (const global of config.globals) {
|
|
3150
|
+
if (slugs.includes(global.slug)) continue;
|
|
3151
|
+
const collection = {
|
|
3152
|
+
slug: global.slug,
|
|
3153
|
+
tableName: global.tableName ?? global.slug,
|
|
3154
|
+
fields: global.fields,
|
|
3155
|
+
searchIndexes: void 0
|
|
3156
|
+
};
|
|
3157
|
+
const { apiFile, modelFile } = generateCollectionPair({
|
|
3158
|
+
collection,
|
|
3159
|
+
isMedia: false,
|
|
3160
|
+
imports
|
|
3161
|
+
});
|
|
3162
|
+
result[`api/${global.slug}.ts`] = apiFile;
|
|
3163
|
+
result[`model/api/${global.slug}.ts`] = modelFile;
|
|
3164
|
+
slugs.push(global.slug);
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
2624
3167
|
if (config.auth?.collections) {
|
|
2625
3168
|
for (const collection of config.auth.collections) {
|
|
2626
3169
|
if (!collection.generateApi) continue;
|
|
@@ -3156,13 +3699,24 @@ function planMigration(props) {
|
|
|
3156
3699
|
}
|
|
3157
3700
|
export {
|
|
3158
3701
|
ALL_SYSTEM_FIELDS,
|
|
3702
|
+
ASPECT_RATIO_PRESETS,
|
|
3703
|
+
BORDER_RADIUS_PRESETS,
|
|
3704
|
+
BORDER_WIDTH_PRESETS,
|
|
3705
|
+
BOX_SHADOW_PRESETS,
|
|
3159
3706
|
DEFAULT_AUTOSAVE_INTERVAL,
|
|
3160
3707
|
DEFAULT_BREAKPOINTS,
|
|
3161
3708
|
DEFAULT_MAX_VERSIONS_PER_DOC,
|
|
3709
|
+
FONT_SIZE_PRESETS,
|
|
3710
|
+
FONT_WEIGHT_PRESETS,
|
|
3162
3711
|
GENERATED_HEADER,
|
|
3712
|
+
LETTER_SPACING_PRESETS,
|
|
3713
|
+
LINE_HEIGHT_PRESETS,
|
|
3163
3714
|
LOCKED_MEDIA_FIELDS,
|
|
3715
|
+
MAX_WIDTH_PRESETS,
|
|
3716
|
+
OPACITY_PRESETS,
|
|
3164
3717
|
OVERRIDABLE_MEDIA_FIELDS,
|
|
3165
3718
|
PREVIEW_SNAPSHOT_DEBOUNCE_MS,
|
|
3719
|
+
SPACING_PRESETS,
|
|
3166
3720
|
VERSION_SYSTEM_FIELDS,
|
|
3167
3721
|
VexAccessConfigError,
|
|
3168
3722
|
VexAccessError,
|
|
@@ -3172,10 +3726,15 @@ export {
|
|
|
3172
3726
|
VexFieldValidationError,
|
|
3173
3727
|
VexMediaConfigError,
|
|
3174
3728
|
VexSlugConflictError,
|
|
3729
|
+
WIDTH_PRESETS,
|
|
3175
3730
|
addRemovedFieldsAsOptional,
|
|
3176
3731
|
array,
|
|
3732
|
+
blockStylesToTailwind,
|
|
3177
3733
|
blocks,
|
|
3734
|
+
buildSiteMetadata,
|
|
3735
|
+
checkAdminAccess,
|
|
3178
3736
|
checkbox,
|
|
3737
|
+
color,
|
|
3179
3738
|
createDocument,
|
|
3180
3739
|
createVexQuery,
|
|
3181
3740
|
date,
|
|
@@ -3183,6 +3742,7 @@ export {
|
|
|
3183
3742
|
defineBlock,
|
|
3184
3743
|
defineCollection,
|
|
3185
3744
|
defineConfig,
|
|
3745
|
+
defineGlobal,
|
|
3186
3746
|
defineMediaCollection,
|
|
3187
3747
|
deleteDocument,
|
|
3188
3748
|
deletePreviewSnapshot,
|
|
@@ -3210,6 +3770,7 @@ export {
|
|
|
3210
3770
|
makeFieldsOptional,
|
|
3211
3771
|
mergeAuthCollectionWithUserCollection,
|
|
3212
3772
|
number,
|
|
3773
|
+
object,
|
|
3213
3774
|
planMigration,
|
|
3214
3775
|
relationship,
|
|
3215
3776
|
resolvePreviewURL,
|
|
@@ -3219,6 +3780,7 @@ export {
|
|
|
3219
3780
|
select,
|
|
3220
3781
|
shouldReloadURL,
|
|
3221
3782
|
slugToInterfaceName,
|
|
3783
|
+
tabs,
|
|
3222
3784
|
text,
|
|
3223
3785
|
toTitleCase,
|
|
3224
3786
|
ui,
|