@riverbankcms/sdk 0.70.2 → 0.70.4
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/README.md +29 -0
- package/dist/_dts/api/src/contentTypes.d.ts +2 -1
- package/dist/_dts/block-form/src/client/index.d.ts +1 -1
- package/dist/_dts/block-form/src/fields/types.d.ts +14 -2
- package/dist/_dts/block-form/src/registry/schemas.d.ts +2 -0
- package/dist/_dts/block-form/src/widgets/MediaField/mediaFieldDefaults.d.ts +2 -2
- package/dist/_dts/block-form/src/widgets/MediaField/mediaFieldSchema.d.ts +2 -2
- package/dist/_dts/blocks/src/lib/media.d.ts +1 -1
- package/dist/_dts/blocks/src/system/blocks/appointment-booking.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/blog-listing.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/cart.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/checkout.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/collection.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/cta-full.d.ts +1 -30727
- package/dist/_dts/blocks/src/system/blocks/events/event-spotlight.d.ts +11 -30827
- package/dist/_dts/blocks/src/system/blocks/faq.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/file-download.d.ts +3 -3
- package/dist/_dts/blocks/src/system/blocks/gifting.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +106 -1
- package/dist/_dts/blocks/src/system/blocks/product-detail.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/product-list.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/blocks/shop.d.ts +1829 -149
- package/dist/_dts/blocks/src/system/defineBlock.d.ts +3 -3
- package/dist/_dts/blocks/src/system/fragments/library/card.d.ts +2 -30793
- package/dist/_dts/blocks/src/system/fragments/library/ctaRow.d.ts +2 -30727
- package/dist/_dts/blocks/src/system/fragments/library/feedbackCallout.d.ts +2 -30779
- package/dist/_dts/blocks/src/system/fragments/library/heroCtaRow.d.ts +33 -30743
- package/dist/_dts/blocks/src/system/fragments/library/sectionState.d.ts +2 -30770
- package/dist/_dts/blocks/src/system/fragments/types.d.ts +8 -7
- package/dist/_dts/blocks/src/system/manifest/derivedContent.d.ts +7 -5
- package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +1 -1
- package/dist/_dts/blocks/src/system/manifest/schema.d.ts +192 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/file-download.d.ts +1 -1
- package/dist/_dts/content-model/src/content-types/schema.d.ts +7 -0
- package/dist/_dts/content-model/src/contentManifest.d.ts +4 -1
- package/dist/_dts/content-model/src/templates/bindingTypeCompatibility.d.ts +1 -1
- package/dist/_dts/core/src/index.d.ts +1 -1
- package/dist/_dts/core/src/planner.d.ts +4 -0
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +53 -20
- package/dist/_dts/editor-blocks/src/index.d.ts +1 -1
- package/dist/_dts/editor-blocks/src/media/MediaField.d.ts +6 -5
- package/dist/_dts/media-core/src/videoSlotPolicy.d.ts +0 -1
- package/dist/_dts/media-editor/src/context.d.ts +4 -1
- package/dist/_dts/media-react/src/hooks/useApiMediaUploader.d.ts +8 -1
- package/dist/_dts/media-react/src/index.d.ts +1 -5
- package/dist/_dts/preview-next/src/client/widgets/PreviewMediaField.d.ts +2 -1
- package/dist/_dts/preview-next/src/client/widgets/widgetOverrides.d.ts +1 -0
- package/dist/_dts/sdk/src/cli/commands/delete.d.ts +3 -0
- package/dist/_dts/sdk/src/cli/commands/style.d.ts +18 -0
- package/dist/_dts/sdk/src/cli/helpers.d.ts +8 -33
- package/dist/_dts/sdk/src/cli/site-commands/oneOffCommands.d.ts +81 -0
- package/dist/_dts/sdk/src/components.d.ts +2 -1
- package/dist/_dts/sdk/src/config/field-definitions.d.ts +6 -2
- package/dist/_dts/sdk/src/config/typed-entries.d.ts +4 -2
- package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +2 -1
- package/dist/_dts/sdk/src/manifest/prompt/examples/cta.d.ts +5 -5
- package/dist/_dts/sdk/src/manifest/prompt/examples/features-grid.d.ts +2 -2
- package/dist/_dts/sdk/src/manifest/prompt/examples/hero.d.ts +2 -2
- package/dist/_dts/sdk/src/manifest/prompt/examples/pricing.d.ts +10 -10
- package/dist/_dts/sdk/src/manifest/prompt/examples/testimonials.d.ts +4 -4
- package/dist/_dts/sdk/src/manifest/validation/output-schema.d.ts +11 -1
- package/dist/_dts/sdk/src/next/types.d.ts +4 -2
- package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -1
- package/dist/_dts/sdk/src/rendering/index.d.ts +2 -1
- package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +10 -0
- package/dist/_dts/sdk/src/rendering/overrides.d.ts +12 -0
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/cli/index.mjs +1072 -289
- package/dist/cli/init-docs/content/workflow-preview-mode.md +167 -0
- package/dist/client/client.mjs +443 -403
- package/dist/client/hooks.mjs +172 -121
- package/dist/client/rendering/client.mjs +148 -112
- package/dist/client/rendering/islands.mjs +80 -31
- package/dist/client/rendering.mjs +25531 -25481
- package/dist/preview-next/client/runtime.mjs +394 -1136
- package/dist/server/components.mjs +229 -171
- package/dist/server/config-template-validation.mjs +31 -1
- package/dist/server/config-validation.mjs +172 -121
- package/dist/server/config.mjs +172 -121
- package/dist/server/data.mjs +172 -121
- package/dist/server/index.mjs +1 -1
- package/dist/server/next.mjs +301 -174
- package/dist/server/page-converter.mjs +379 -185
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +219 -171
- package/dist/server/rendering.mjs +229 -171
- package/dist/server/routing.mjs +175 -124
- package/dist/server/server.mjs +173 -122
- package/package.json +5 -3
|
@@ -305,6 +305,28 @@ function resolveRepeaterGridColumnFieldId(options) {
|
|
|
305
305
|
|
|
306
306
|
// ../blocks/src/system/manifest/schema.ts
|
|
307
307
|
var visibilityLevels = ["admin", "designer", "author"];
|
|
308
|
+
var MEDIA_KINDS = [
|
|
309
|
+
"image",
|
|
310
|
+
"video",
|
|
311
|
+
"audio",
|
|
312
|
+
"document",
|
|
313
|
+
"spreadsheet",
|
|
314
|
+
"archive"
|
|
315
|
+
];
|
|
316
|
+
var DISPLAY_MEDIA_KINDS = [
|
|
317
|
+
"image",
|
|
318
|
+
"video",
|
|
319
|
+
"audio"
|
|
320
|
+
];
|
|
321
|
+
var PUBLIC_FILE_FIELD_KINDS = [
|
|
322
|
+
"document",
|
|
323
|
+
"spreadsheet",
|
|
324
|
+
"archive",
|
|
325
|
+
"audio"
|
|
326
|
+
];
|
|
327
|
+
function isDisplayMediaKind(kind) {
|
|
328
|
+
return DISPLAY_MEDIA_KINDS.includes(kind);
|
|
329
|
+
}
|
|
308
330
|
var siteOptionSources = [
|
|
309
331
|
"eventCategories",
|
|
310
332
|
"venues",
|
|
@@ -468,11 +490,19 @@ var richTextFieldSchema = baseFieldSchema.extend({
|
|
|
468
490
|
});
|
|
469
491
|
var mediaFieldSchema = baseFieldSchema.extend({
|
|
470
492
|
type: z2.literal("media"),
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
493
|
+
// Keep full MEDIA_KINDS parse compatibility for pre-file-field manifests.
|
|
494
|
+
// New authoring surfaces should use `file.fileKinds` for document/archive
|
|
495
|
+
// style assets, but old saved schemas must not fail to open.
|
|
496
|
+
mediaKinds: z2.array(z2.enum(MEDIA_KINDS)).default(["image"]).transform((kinds) => {
|
|
497
|
+
const displayKinds = kinds.filter(isDisplayMediaKind);
|
|
498
|
+
return displayKinds.length > 0 ? displayKinds : ["image"];
|
|
499
|
+
}),
|
|
474
500
|
aspectRatio: z2.string().optional()
|
|
475
501
|
});
|
|
502
|
+
var fileFieldSchema = baseFieldSchema.extend({
|
|
503
|
+
type: z2.literal("file"),
|
|
504
|
+
fileKinds: z2.array(z2.enum(PUBLIC_FILE_FIELD_KINDS)).default([...PUBLIC_FILE_FIELD_KINDS])
|
|
505
|
+
});
|
|
476
506
|
var booleanFieldSchema = baseFieldSchema.extend({
|
|
477
507
|
type: z2.literal("boolean")
|
|
478
508
|
});
|
|
@@ -778,6 +808,7 @@ function getFieldSchemaInternal() {
|
|
|
778
808
|
textFieldSchema,
|
|
779
809
|
richTextFieldSchema,
|
|
780
810
|
mediaFieldSchema,
|
|
811
|
+
fileFieldSchema,
|
|
781
812
|
booleanFieldSchema,
|
|
782
813
|
numberFieldSchema,
|
|
783
814
|
dateFieldSchema,
|
|
@@ -7210,13 +7241,18 @@ var fragmentDataSchema = z25.object({
|
|
|
7210
7241
|
loader: dataLoaderSchema.optional()
|
|
7211
7242
|
});
|
|
7212
7243
|
var fragmentConfigSchema = z25.object({
|
|
7213
|
-
id: z25.string().min(1, "Fragment id is required").regex(
|
|
7244
|
+
id: z25.string().min(1, "Fragment id is required").regex(
|
|
7245
|
+
FRAGMENT_ID_PATTERN,
|
|
7246
|
+
"Fragment id must be alphanumeric with optional . _ - separators"
|
|
7247
|
+
),
|
|
7214
7248
|
title: z25.string().optional(),
|
|
7215
7249
|
description: z25.string().optional(),
|
|
7216
7250
|
category: z25.enum(["content", "media", "interactive", "layout"]).optional(),
|
|
7217
7251
|
icon: z25.string().optional(),
|
|
7218
7252
|
fields: fieldSchema.array().default([]),
|
|
7219
|
-
layout: z25.union([NodeSchema, NodeSchema.array()]).transform(
|
|
7253
|
+
layout: z25.union([NodeSchema, NodeSchema.array()]).transform(
|
|
7254
|
+
(value) => Array.isArray(value) ? value : [value]
|
|
7255
|
+
),
|
|
7220
7256
|
data: fragmentDataSchema.optional()
|
|
7221
7257
|
});
|
|
7222
7258
|
var FragmentConfigError = class extends Error {
|
|
@@ -7238,13 +7274,19 @@ function defineFragment(config) {
|
|
|
7238
7274
|
function scopeFragmentFields(fragment, scope) {
|
|
7239
7275
|
const normalizedScope = scope.trim();
|
|
7240
7276
|
if (!normalizedScope) {
|
|
7241
|
-
return fragment.fields.map(
|
|
7277
|
+
return fragment.fields.map(
|
|
7278
|
+
(field) => cloneFieldDefinition2(field)
|
|
7279
|
+
);
|
|
7242
7280
|
}
|
|
7243
|
-
return fragment.fields.map(
|
|
7281
|
+
return fragment.fields.map(
|
|
7282
|
+
(field) => prefixFieldId(field, normalizedScope)
|
|
7283
|
+
);
|
|
7244
7284
|
}
|
|
7245
7285
|
function scopeFragmentLayout(fragment, scope) {
|
|
7246
7286
|
const normalizedScope = scope.trim();
|
|
7247
|
-
return fragment.layout.map(
|
|
7287
|
+
return fragment.layout.map(
|
|
7288
|
+
(node) => cloneAndScopeNode(node, normalizedScope)
|
|
7289
|
+
);
|
|
7248
7290
|
}
|
|
7249
7291
|
function validateFieldDefinitions(fields3, fragmentId) {
|
|
7250
7292
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -7326,7 +7368,9 @@ function cloneAndScopeNode(node, scope) {
|
|
|
7326
7368
|
...node
|
|
7327
7369
|
};
|
|
7328
7370
|
if (node.children) {
|
|
7329
|
-
cloned.children = node.children.map(
|
|
7371
|
+
cloned.children = node.children.map(
|
|
7372
|
+
(child) => cloneAndScopeNode(child, scope)
|
|
7373
|
+
);
|
|
7330
7374
|
}
|
|
7331
7375
|
if (node.props) {
|
|
7332
7376
|
cloned.props = scopePropBindings(node.props, scope);
|
|
@@ -7352,7 +7396,9 @@ function scopeBinding(binding, scope) {
|
|
|
7352
7396
|
const cloned = {
|
|
7353
7397
|
...binding,
|
|
7354
7398
|
transforms: binding.transforms?.map(
|
|
7355
|
-
(step) => ({
|
|
7399
|
+
(step) => ({
|
|
7400
|
+
...step
|
|
7401
|
+
})
|
|
7356
7402
|
) ?? []
|
|
7357
7403
|
};
|
|
7358
7404
|
cloned.from = scopeContentPath(binding.from, scope);
|
|
@@ -7396,7 +7442,9 @@ function scopePropValue(value, scope) {
|
|
|
7396
7442
|
};
|
|
7397
7443
|
}
|
|
7398
7444
|
const result = {};
|
|
7399
|
-
for (const [key, entry] of Object.entries(
|
|
7445
|
+
for (const [key, entry] of Object.entries(
|
|
7446
|
+
value
|
|
7447
|
+
)) {
|
|
7400
7448
|
result[key] = scopePropValue(entry, scope);
|
|
7401
7449
|
}
|
|
7402
7450
|
return result;
|
|
@@ -7845,28 +7893,29 @@ var ctaRowFragment = defineFragment({
|
|
|
7845
7893
|
});
|
|
7846
7894
|
|
|
7847
7895
|
// ../blocks/src/system/fragments/library/heroCtaRow.ts
|
|
7896
|
+
var heroCtaFields = [
|
|
7897
|
+
createCtasRepeater({
|
|
7898
|
+
label: "Calls to action",
|
|
7899
|
+
itemLabel: "CTA",
|
|
7900
|
+
maxItems: 3,
|
|
7901
|
+
button: {
|
|
7902
|
+
variants: [
|
|
7903
|
+
{ value: "default", label: "Default" },
|
|
7904
|
+
{ value: "primary", label: "Primary" },
|
|
7905
|
+
{ value: "secondary", label: "Secondary" },
|
|
7906
|
+
{ value: "outline", label: "Outline" }
|
|
7907
|
+
],
|
|
7908
|
+
defaultVariant: "default",
|
|
7909
|
+
includeSize: true,
|
|
7910
|
+
defaultSize: "lg"
|
|
7911
|
+
}
|
|
7912
|
+
})
|
|
7913
|
+
];
|
|
7848
7914
|
var heroCtaRowFragment = defineFragment({
|
|
7849
7915
|
id: "heroCtaRow",
|
|
7850
7916
|
title: "Hero CTAs",
|
|
7851
7917
|
description: "Repeatable hero calls to action rendered inline.",
|
|
7852
|
-
fields:
|
|
7853
|
-
createCtasRepeater({
|
|
7854
|
-
label: "Calls to action",
|
|
7855
|
-
itemLabel: "CTA",
|
|
7856
|
-
maxItems: 3,
|
|
7857
|
-
button: {
|
|
7858
|
-
variants: [
|
|
7859
|
-
{ value: "default", label: "Default" },
|
|
7860
|
-
{ value: "primary", label: "Primary" },
|
|
7861
|
-
{ value: "secondary", label: "Secondary" },
|
|
7862
|
-
{ value: "outline", label: "Outline" }
|
|
7863
|
-
],
|
|
7864
|
-
defaultVariant: "default",
|
|
7865
|
-
includeSize: true,
|
|
7866
|
-
defaultSize: "lg"
|
|
7867
|
-
}
|
|
7868
|
-
})
|
|
7869
|
-
],
|
|
7918
|
+
fields: heroCtaFields,
|
|
7870
7919
|
layout: [
|
|
7871
7920
|
ctaRow({
|
|
7872
7921
|
collectionPath: "content.ctas",
|
|
@@ -12534,8 +12583,7 @@ var PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
|
12534
12583
|
"document",
|
|
12535
12584
|
"spreadsheet",
|
|
12536
12585
|
"archive",
|
|
12537
|
-
"audio"
|
|
12538
|
-
"video"
|
|
12586
|
+
"audio"
|
|
12539
12587
|
];
|
|
12540
12588
|
var hotspotSchema2 = z31.object({
|
|
12541
12589
|
x: z31.number().min(0).max(1),
|
|
@@ -14110,104 +14158,107 @@ var courseDetailsBlockDefinition = {
|
|
|
14110
14158
|
};
|
|
14111
14159
|
|
|
14112
14160
|
// ../blocks/src/system/blocks/events/event-spotlight.ts
|
|
14113
|
-
var
|
|
14161
|
+
var eventSpotlightFields = [
|
|
14162
|
+
...sectionHeaderFields("Upcoming Events"),
|
|
14163
|
+
{
|
|
14164
|
+
id: "maxEvents",
|
|
14165
|
+
type: "select",
|
|
14166
|
+
label: "Events to display",
|
|
14167
|
+
description: "Number of events to show",
|
|
14168
|
+
required: false,
|
|
14169
|
+
multiple: false,
|
|
14170
|
+
defaultValue: "3",
|
|
14171
|
+
options: [
|
|
14172
|
+
{ value: "1", label: "1 event" },
|
|
14173
|
+
{ value: "2", label: "2 events" },
|
|
14174
|
+
{ value: "3", label: "3 events" },
|
|
14175
|
+
{ value: "4", label: "4 events" },
|
|
14176
|
+
{ value: "5", label: "5 events" },
|
|
14177
|
+
{ value: "6", label: "6 events" }
|
|
14178
|
+
],
|
|
14179
|
+
ui: { intent: "display" }
|
|
14180
|
+
},
|
|
14181
|
+
{
|
|
14182
|
+
id: "ctaLabel",
|
|
14183
|
+
type: "text",
|
|
14184
|
+
label: "Section button text",
|
|
14185
|
+
description: "Optional button shown below the spotlight cards",
|
|
14186
|
+
required: false,
|
|
14187
|
+
multiline: false,
|
|
14188
|
+
maxLength: 40,
|
|
14189
|
+
ui: { intent: "content" }
|
|
14190
|
+
},
|
|
14191
|
+
{
|
|
14192
|
+
id: "ctaUrl",
|
|
14193
|
+
type: "link",
|
|
14194
|
+
label: "Section button destination",
|
|
14195
|
+
required: false,
|
|
14196
|
+
ui: { intent: "display" }
|
|
14197
|
+
},
|
|
14198
|
+
layoutField,
|
|
14199
|
+
columnsField(["2", "3"]),
|
|
14200
|
+
...cardStylingFields,
|
|
14201
|
+
...eventDisplayFields,
|
|
14202
|
+
emptyStateField,
|
|
14203
|
+
sectionStylesField({
|
|
14204
|
+
id: "_sectionStyles",
|
|
14205
|
+
label: "Section styles"
|
|
14206
|
+
})
|
|
14207
|
+
];
|
|
14208
|
+
var eventSpotlightLayout = [
|
|
14209
|
+
styledSection({
|
|
14210
|
+
children: sectionContainer([
|
|
14211
|
+
// Optional heading
|
|
14212
|
+
text(
|
|
14213
|
+
{ as: "h2" },
|
|
14214
|
+
bind("content.heading"),
|
|
14215
|
+
when("content.heading")
|
|
14216
|
+
),
|
|
14217
|
+
// Optional description
|
|
14218
|
+
richText(
|
|
14219
|
+
{ className: "rb-prose rb-max-w-none" },
|
|
14220
|
+
bind("content.description"),
|
|
14221
|
+
when("content.description")
|
|
14222
|
+
),
|
|
14223
|
+
// Event spotlight component
|
|
14224
|
+
el("event-spotlight", {
|
|
14225
|
+
events: { $bind: { from: "data.events" } },
|
|
14226
|
+
layout: { $bind: { from: "content.layout", fallback: "grid" } },
|
|
14227
|
+
columns: { $bind: { from: "content.columns", fallback: "3" } },
|
|
14228
|
+
cardVariant: { $bind: { from: "content.cardVariant", fallback: "default" } },
|
|
14229
|
+
buttonVariant: { $bind: { from: "content.buttonVariant", fallback: "primary" } },
|
|
14230
|
+
buttonText: { $bind: { from: "content.buttonText", fallback: "View event" } },
|
|
14231
|
+
ctaLabel: { $bind: { from: "content.ctaLabel" } },
|
|
14232
|
+
ctaUrl: { $bind: { from: "content.ctaUrl", transforms: [{ id: "links.resolve" }] } },
|
|
14233
|
+
showVenue: { $bind: { from: "content.showVenue" } },
|
|
14234
|
+
showMap: { $bind: { from: "content.showMap" } },
|
|
14235
|
+
showCapacity: { $bind: { from: "content.showCapacity" } },
|
|
14236
|
+
emptyMessage: { $bind: { from: "content.emptyMessage" } }
|
|
14237
|
+
})
|
|
14238
|
+
], {
|
|
14239
|
+
gap: "lg"
|
|
14240
|
+
}),
|
|
14241
|
+
// sectionContainer (rb-container) already provides horizontal padding
|
|
14242
|
+
baseClass: "",
|
|
14243
|
+
spacing: "comfortable"
|
|
14244
|
+
})
|
|
14245
|
+
];
|
|
14246
|
+
var eventSpotlightConfig = {
|
|
14114
14247
|
id: "block.event-spotlight",
|
|
14115
14248
|
version: "1.1.0",
|
|
14116
14249
|
title: "Event Spotlight",
|
|
14117
14250
|
titleSource: "heading",
|
|
14118
14251
|
description: "Feature a few upcoming events on your homepage",
|
|
14119
14252
|
skipSectionStyles: true,
|
|
14120
|
-
additionalFields:
|
|
14121
|
-
...sectionHeaderFields("Upcoming Events"),
|
|
14122
|
-
{
|
|
14123
|
-
id: "maxEvents",
|
|
14124
|
-
type: "select",
|
|
14125
|
-
label: "Events to display",
|
|
14126
|
-
description: "Number of events to show",
|
|
14127
|
-
required: false,
|
|
14128
|
-
multiple: false,
|
|
14129
|
-
defaultValue: "3",
|
|
14130
|
-
options: [
|
|
14131
|
-
{ value: "1", label: "1 event" },
|
|
14132
|
-
{ value: "2", label: "2 events" },
|
|
14133
|
-
{ value: "3", label: "3 events" },
|
|
14134
|
-
{ value: "4", label: "4 events" },
|
|
14135
|
-
{ value: "5", label: "5 events" },
|
|
14136
|
-
{ value: "6", label: "6 events" }
|
|
14137
|
-
],
|
|
14138
|
-
ui: { intent: "display" }
|
|
14139
|
-
},
|
|
14140
|
-
{
|
|
14141
|
-
id: "ctaLabel",
|
|
14142
|
-
type: "text",
|
|
14143
|
-
label: "Section button text",
|
|
14144
|
-
description: "Optional button shown below the spotlight cards",
|
|
14145
|
-
required: false,
|
|
14146
|
-
multiline: false,
|
|
14147
|
-
maxLength: 40,
|
|
14148
|
-
ui: { intent: "content" }
|
|
14149
|
-
},
|
|
14150
|
-
{
|
|
14151
|
-
id: "ctaUrl",
|
|
14152
|
-
type: "link",
|
|
14153
|
-
label: "Section button destination",
|
|
14154
|
-
required: false,
|
|
14155
|
-
ui: { intent: "display" }
|
|
14156
|
-
},
|
|
14157
|
-
layoutField,
|
|
14158
|
-
columnsField(["2", "3"]),
|
|
14159
|
-
...cardStylingFields,
|
|
14160
|
-
...eventDisplayFields,
|
|
14161
|
-
emptyStateField,
|
|
14162
|
-
sectionStylesField({
|
|
14163
|
-
id: "_sectionStyles",
|
|
14164
|
-
label: "Section styles"
|
|
14165
|
-
})
|
|
14166
|
-
],
|
|
14253
|
+
additionalFields: eventSpotlightFields,
|
|
14167
14254
|
styleTokens: { background: "surface", typography: "body", spacing: "md" },
|
|
14168
14255
|
behaviours: { supportsThemeSwitching: true, inlineEditing: false, animation: false, paletteHidden: false },
|
|
14169
14256
|
category: "content",
|
|
14170
14257
|
tags: ["events", "featured", "homepage", "spotlight", "upcoming"],
|
|
14171
14258
|
icon: "Star",
|
|
14172
|
-
layout:
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
// Optional heading
|
|
14176
|
-
text(
|
|
14177
|
-
{ as: "h2" },
|
|
14178
|
-
bind("content.heading"),
|
|
14179
|
-
when("content.heading")
|
|
14180
|
-
),
|
|
14181
|
-
// Optional description
|
|
14182
|
-
richText(
|
|
14183
|
-
{ className: "rb-prose rb-max-w-none" },
|
|
14184
|
-
bind("content.description"),
|
|
14185
|
-
when("content.description")
|
|
14186
|
-
),
|
|
14187
|
-
// Event spotlight component
|
|
14188
|
-
el("event-spotlight", {
|
|
14189
|
-
events: { $bind: { from: "data.events" } },
|
|
14190
|
-
layout: { $bind: { from: "content.layout", fallback: "grid" } },
|
|
14191
|
-
columns: { $bind: { from: "content.columns", fallback: "3" } },
|
|
14192
|
-
cardVariant: { $bind: { from: "content.cardVariant", fallback: "default" } },
|
|
14193
|
-
buttonVariant: { $bind: { from: "content.buttonVariant", fallback: "primary" } },
|
|
14194
|
-
buttonText: { $bind: { from: "content.buttonText", fallback: "View event" } },
|
|
14195
|
-
ctaLabel: { $bind: { from: "content.ctaLabel" } },
|
|
14196
|
-
ctaUrl: { $bind: { from: "content.ctaUrl", transforms: [{ id: "links.resolve" }] } },
|
|
14197
|
-
showVenue: { $bind: { from: "content.showVenue" } },
|
|
14198
|
-
showMap: { $bind: { from: "content.showMap" } },
|
|
14199
|
-
showCapacity: { $bind: { from: "content.showCapacity" } },
|
|
14200
|
-
emptyMessage: { $bind: { from: "content.emptyMessage" } }
|
|
14201
|
-
})
|
|
14202
|
-
], {
|
|
14203
|
-
gap: "lg"
|
|
14204
|
-
}),
|
|
14205
|
-
// sectionContainer (rb-container) already provides horizontal padding
|
|
14206
|
-
baseClass: "",
|
|
14207
|
-
spacing: "comfortable"
|
|
14208
|
-
})
|
|
14209
|
-
]
|
|
14210
|
-
});
|
|
14259
|
+
layout: eventSpotlightLayout
|
|
14260
|
+
};
|
|
14261
|
+
var eventSpotlightManifest = createBlockManifest(eventSpotlightConfig);
|
|
14211
14262
|
var eventSpotlightBlockDefinition = {
|
|
14212
14263
|
manifest: eventSpotlightManifest,
|
|
14213
14264
|
dataSchemas: {
|
|
@@ -16821,18 +16872,18 @@ var fileDownloadManifest = createBlockManifest({
|
|
|
16821
16872
|
title: "File Download",
|
|
16822
16873
|
titleSource: ["title", "file.filename"],
|
|
16823
16874
|
category: "media",
|
|
16824
|
-
description: "Add a simple public download link for a document, ZIP,
|
|
16875
|
+
description: "Add a simple public download link for a document, ZIP, or audio file.",
|
|
16825
16876
|
tags: ["file", "download", "document", "zip", "media"],
|
|
16826
16877
|
icon: "Download",
|
|
16827
16878
|
includeContainerStyles: true,
|
|
16828
16879
|
additionalFields: [
|
|
16829
16880
|
{
|
|
16830
16881
|
id: "file",
|
|
16831
|
-
type: "
|
|
16882
|
+
type: "file",
|
|
16832
16883
|
label: "Download file",
|
|
16833
16884
|
description: "Choose the file visitors can download.",
|
|
16834
16885
|
required: false,
|
|
16835
|
-
|
|
16886
|
+
fileKinds: [...PUBLIC_DOWNLOAD_MEDIA_TYPES],
|
|
16836
16887
|
ui: { intent: "content" }
|
|
16837
16888
|
},
|
|
16838
16889
|
{
|
|
@@ -20551,7 +20602,14 @@ var titleSourceValueSchema = z54.union([
|
|
|
20551
20602
|
]);
|
|
20552
20603
|
|
|
20553
20604
|
// src/manifest/validation/output-schema.ts
|
|
20554
|
-
var blockCategoryEnum2 = z55.enum([
|
|
20605
|
+
var blockCategoryEnum2 = z55.enum([
|
|
20606
|
+
"marketing",
|
|
20607
|
+
"content",
|
|
20608
|
+
"blog",
|
|
20609
|
+
"media",
|
|
20610
|
+
"layout",
|
|
20611
|
+
"interactive"
|
|
20612
|
+
]);
|
|
20555
20613
|
var llmColorValue = z55.object({
|
|
20556
20614
|
name: z55.string(),
|
|
20557
20615
|
hex: z55.string()
|
|
@@ -20569,8 +20627,16 @@ var llmThemePatchValue = z55.union([
|
|
|
20569
20627
|
z55.array(llmThemePrimitive)
|
|
20570
20628
|
]);
|
|
20571
20629
|
var llmThemePatchOpSchema = z55.discriminatedUnion("op", [
|
|
20572
|
-
z55.object({
|
|
20573
|
-
|
|
20630
|
+
z55.object({
|
|
20631
|
+
op: z55.literal("add"),
|
|
20632
|
+
path: z55.string().min(1),
|
|
20633
|
+
value: llmThemePatchValue
|
|
20634
|
+
}),
|
|
20635
|
+
z55.object({
|
|
20636
|
+
op: z55.literal("replace"),
|
|
20637
|
+
path: z55.string().min(1),
|
|
20638
|
+
value: llmThemePatchValue
|
|
20639
|
+
}),
|
|
20574
20640
|
z55.object({ op: z55.literal("remove"), path: z55.string().min(1) })
|
|
20575
20641
|
]);
|
|
20576
20642
|
var llmCssDeclaration = z55.object({
|
|
@@ -20647,7 +20713,11 @@ var llmRichTextFieldSchema = llmBaseFieldSchema.extend({
|
|
|
20647
20713
|
});
|
|
20648
20714
|
var llmMediaFieldSchema = llmBaseFieldSchema.extend({
|
|
20649
20715
|
type: z55.literal("media"),
|
|
20650
|
-
mediaKinds: z55.array(z55.enum(["image", "video", "audio"
|
|
20716
|
+
mediaKinds: z55.array(z55.enum(["image", "video", "audio"])).nullable()
|
|
20717
|
+
});
|
|
20718
|
+
var llmFileFieldSchema = llmBaseFieldSchema.extend({
|
|
20719
|
+
type: z55.literal("file"),
|
|
20720
|
+
fileKinds: z55.array(z55.enum(["document", "spreadsheet", "archive", "audio"])).nullable()
|
|
20651
20721
|
});
|
|
20652
20722
|
var llmBooleanFieldSchema = llmBaseFieldSchema.extend({
|
|
20653
20723
|
type: z55.literal("boolean")
|
|
@@ -20657,10 +20727,12 @@ var llmLinkFieldSchema = llmBaseFieldSchema.extend({
|
|
|
20657
20727
|
});
|
|
20658
20728
|
var llmSelectFieldSchema = llmBaseFieldSchema.extend({
|
|
20659
20729
|
type: z55.literal("select"),
|
|
20660
|
-
options: z55.array(
|
|
20661
|
-
|
|
20662
|
-
|
|
20663
|
-
|
|
20730
|
+
options: z55.array(
|
|
20731
|
+
z55.object({
|
|
20732
|
+
value: z55.string(),
|
|
20733
|
+
label: z55.string()
|
|
20734
|
+
})
|
|
20735
|
+
),
|
|
20664
20736
|
multiple: z55.boolean().nullable()
|
|
20665
20737
|
});
|
|
20666
20738
|
var llmNumberFieldSchema = llmBaseFieldSchema.extend({
|
|
@@ -20696,6 +20768,7 @@ var llmFieldSchema = z55.union([
|
|
|
20696
20768
|
llmTextFieldSchema,
|
|
20697
20769
|
llmRichTextFieldSchema,
|
|
20698
20770
|
llmMediaFieldSchema,
|
|
20771
|
+
llmFileFieldSchema,
|
|
20699
20772
|
llmBooleanFieldSchema,
|
|
20700
20773
|
llmLinkFieldSchema,
|
|
20701
20774
|
llmSelectFieldSchema,
|
|
@@ -20706,9 +20779,11 @@ var llmFieldSchema = z55.union([
|
|
|
20706
20779
|
var llmBindingSchema = z55.object({
|
|
20707
20780
|
from: z55.string(),
|
|
20708
20781
|
fallback: z55.string().nullable(),
|
|
20709
|
-
transforms: z55.array(
|
|
20710
|
-
|
|
20711
|
-
|
|
20782
|
+
transforms: z55.array(
|
|
20783
|
+
z55.object({
|
|
20784
|
+
id: z55.string()
|
|
20785
|
+
})
|
|
20786
|
+
).nullable()
|
|
20712
20787
|
});
|
|
20713
20788
|
var llmRepeatSchema = z55.object({
|
|
20714
20789
|
collection: z55.object({ from: z55.string() }),
|
|
@@ -20767,11 +20842,17 @@ function collectValidationErrors(output) {
|
|
|
20767
20842
|
const blockIds = output.blocks.map((b) => b.id);
|
|
20768
20843
|
const singleBlockId = blockIds.length === 1 ? blockIds[0] ?? null : null;
|
|
20769
20844
|
for (const block of output.blocks) {
|
|
20770
|
-
const layoutErrors = validateLayoutDeep(
|
|
20845
|
+
const layoutErrors = validateLayoutDeep(
|
|
20846
|
+
block.layout,
|
|
20847
|
+
block.id,
|
|
20848
|
+
block.fields
|
|
20849
|
+
);
|
|
20771
20850
|
errors.push(...layoutErrors);
|
|
20772
20851
|
const fieldInfo = collectFieldInfo(block.fields);
|
|
20773
20852
|
const used = collectUsedFieldRefs(block.layout);
|
|
20774
|
-
const unusedTopLevelFields = Array.from(fieldInfo.topLevelFieldIds).filter(
|
|
20853
|
+
const unusedTopLevelFields = Array.from(fieldInfo.topLevelFieldIds).filter(
|
|
20854
|
+
(id) => !used.topLevel.has(id)
|
|
20855
|
+
);
|
|
20775
20856
|
if (unusedTopLevelFields.length > 0) {
|
|
20776
20857
|
errors.push({
|
|
20777
20858
|
path: `blocks["${block.id}"].fields`,
|
|
@@ -20779,10 +20860,15 @@ function collectValidationErrors(output) {
|
|
|
20779
20860
|
suggestion: `Every field should be bound to a layout node. Add $bind: { from: "content.${unusedTopLevelFields[0]}" } to an appropriate node, or remove unused fields.`
|
|
20780
20861
|
});
|
|
20781
20862
|
}
|
|
20782
|
-
for (const [
|
|
20863
|
+
for (const [
|
|
20864
|
+
repeaterFieldId,
|
|
20865
|
+
nestedFieldIds
|
|
20866
|
+
] of fieldInfo.repeaterNestedFieldIds.entries()) {
|
|
20783
20867
|
if (!used.topLevel.has(repeaterFieldId)) continue;
|
|
20784
20868
|
const usedNested = used.nestedByRepeater.get(repeaterFieldId) ?? /* @__PURE__ */ new Set();
|
|
20785
|
-
const missingNested = Array.from(nestedFieldIds).filter(
|
|
20869
|
+
const missingNested = Array.from(nestedFieldIds).filter(
|
|
20870
|
+
(id) => !usedNested.has(id)
|
|
20871
|
+
);
|
|
20786
20872
|
if (missingNested.length === 0) continue;
|
|
20787
20873
|
const itemName = used.itemNameByRepeater.get(repeaterFieldId) ?? "item";
|
|
20788
20874
|
errors.push({
|
|
@@ -20795,10 +20881,18 @@ function collectValidationErrors(output) {
|
|
|
20795
20881
|
errors.push(...missingBindings);
|
|
20796
20882
|
errors.push(...validateLinkFieldDefaultValues(block));
|
|
20797
20883
|
errors.push(...findMissingLinkHrefs(block.layout, block.id, block.fields));
|
|
20798
|
-
errors.push(
|
|
20884
|
+
errors.push(
|
|
20885
|
+
...detectRedundantLinkLabels(block.layout, block.id, block.fields)
|
|
20886
|
+
);
|
|
20799
20887
|
}
|
|
20800
20888
|
if (output.customCssRules && output.customCssRules.length > 0) {
|
|
20801
|
-
errors.push(
|
|
20889
|
+
errors.push(
|
|
20890
|
+
...validateCustomCssRules(
|
|
20891
|
+
output.customCssRules,
|
|
20892
|
+
singleBlockId,
|
|
20893
|
+
output.blocks
|
|
20894
|
+
)
|
|
20895
|
+
);
|
|
20802
20896
|
}
|
|
20803
20897
|
return errors;
|
|
20804
20898
|
}
|
|
@@ -20874,7 +20968,9 @@ function resolveFieldTypeForFrom(allFields, from, repeatStack) {
|
|
|
20874
20968
|
const segments = from.slice(prefix.length).split(".").filter(Boolean);
|
|
20875
20969
|
const [nestedId, ...rest] = segments;
|
|
20876
20970
|
if (!nestedId) return null;
|
|
20877
|
-
let current = ctx.fields.find(
|
|
20971
|
+
let current = ctx.fields.find(
|
|
20972
|
+
(f) => f.id === nestedId
|
|
20973
|
+
);
|
|
20878
20974
|
if (!current) return null;
|
|
20879
20975
|
for (const seg of rest) {
|
|
20880
20976
|
const nested = getNestedFields(current);
|
|
@@ -20890,7 +20986,9 @@ function bindingHasTransform(bind2, id) {
|
|
|
20890
20986
|
if (!bind2) return false;
|
|
20891
20987
|
const transforms = bind2.transforms;
|
|
20892
20988
|
if (!Array.isArray(transforms)) return false;
|
|
20893
|
-
return transforms.some(
|
|
20989
|
+
return transforms.some(
|
|
20990
|
+
(t) => t && typeof t === "object" && t.id === id
|
|
20991
|
+
);
|
|
20894
20992
|
}
|
|
20895
20993
|
function extractNestedHrefBindFromProps(props2) {
|
|
20896
20994
|
if (!props2 || typeof props2 !== "object") return null;
|
|
@@ -20951,7 +21049,15 @@ function findMissingLinkHrefs(node, blockId, fields3, path2 = "layout", repeatSt
|
|
|
20951
21049
|
}
|
|
20952
21050
|
if ("children" in n && Array.isArray(n.children)) {
|
|
20953
21051
|
for (let i = 0; i < n.children.length; i++) {
|
|
20954
|
-
errors.push(
|
|
21052
|
+
errors.push(
|
|
21053
|
+
...findMissingLinkHrefs(
|
|
21054
|
+
n.children[i],
|
|
21055
|
+
blockId,
|
|
21056
|
+
fields3,
|
|
21057
|
+
`${path2}.children[${i}]`,
|
|
21058
|
+
nextRepeatStack
|
|
21059
|
+
)
|
|
21060
|
+
);
|
|
20955
21061
|
}
|
|
20956
21062
|
}
|
|
20957
21063
|
return errors;
|
|
@@ -20975,22 +21081,30 @@ function detectRedundantLinkLabels(node, blockId, fields3, path2 = "layout", rep
|
|
|
20975
21081
|
}
|
|
20976
21082
|
if (Array.isArray(n.children) && n.children.length > 1) {
|
|
20977
21083
|
const children = n.children;
|
|
20978
|
-
const redundancies = findRedundantLinkTextSiblings(
|
|
20979
|
-
|
|
20980
|
-
|
|
20981
|
-
|
|
20982
|
-
|
|
20983
|
-
|
|
21084
|
+
const redundancies = findRedundantLinkTextSiblings(
|
|
21085
|
+
children,
|
|
21086
|
+
nextRepeatStack,
|
|
21087
|
+
path2
|
|
21088
|
+
);
|
|
21089
|
+
errors.push(
|
|
21090
|
+
...redundancies.map((r) => ({
|
|
21091
|
+
path: r.path,
|
|
21092
|
+
message: `Block "${blockId}": ${r.message}`,
|
|
21093
|
+
suggestion: r.suggestion
|
|
21094
|
+
}))
|
|
21095
|
+
);
|
|
20984
21096
|
}
|
|
20985
21097
|
if (Array.isArray(n.children)) {
|
|
20986
21098
|
for (let i = 0; i < n.children.length; i++) {
|
|
20987
|
-
errors.push(
|
|
20988
|
-
|
|
20989
|
-
|
|
20990
|
-
|
|
20991
|
-
|
|
20992
|
-
|
|
20993
|
-
|
|
21099
|
+
errors.push(
|
|
21100
|
+
...detectRedundantLinkLabels(
|
|
21101
|
+
n.children[i],
|
|
21102
|
+
blockId,
|
|
21103
|
+
fields3,
|
|
21104
|
+
`${path2}.children[${i}]`,
|
|
21105
|
+
nextRepeatStack
|
|
21106
|
+
)
|
|
21107
|
+
);
|
|
20994
21108
|
}
|
|
20995
21109
|
}
|
|
20996
21110
|
return errors;
|
|
@@ -21044,7 +21158,8 @@ function checkRedundantLabelBinding(linkBindFrom, textBindFrom, repeatStack) {
|
|
|
21044
21158
|
const ctx = repeatStack[i];
|
|
21045
21159
|
if (!ctx) continue;
|
|
21046
21160
|
const prefix = `${ctx.itemName}.`;
|
|
21047
|
-
if (!linkBindFrom.startsWith(prefix) || !textBindFrom.startsWith(prefix))
|
|
21161
|
+
if (!linkBindFrom.startsWith(prefix) || !textBindFrom.startsWith(prefix))
|
|
21162
|
+
continue;
|
|
21048
21163
|
const linkFieldId = linkBindFrom.slice(prefix.length).split(".")[0] ?? "";
|
|
21049
21164
|
const textFieldId = textBindFrom.slice(prefix.length).split(".")[0] ?? "";
|
|
21050
21165
|
const linkField = ctx.fields.find((f) => f.id === linkFieldId);
|
|
@@ -21069,7 +21184,10 @@ function validateCustomCssRules(rules, singleBlockId, blocks) {
|
|
|
21069
21184
|
const layoutClassNamesByBlockId = /* @__PURE__ */ new Map();
|
|
21070
21185
|
const layoutNodeInfosByBlockId = /* @__PURE__ */ new Map();
|
|
21071
21186
|
for (const block of blocks) {
|
|
21072
|
-
layoutClassNamesByBlockId.set(
|
|
21187
|
+
layoutClassNamesByBlockId.set(
|
|
21188
|
+
block.id,
|
|
21189
|
+
collectLayoutClassNames(block.layout)
|
|
21190
|
+
);
|
|
21073
21191
|
layoutNodeInfosByBlockId.set(block.id, collectLayoutNodeInfos(block.layout));
|
|
21074
21192
|
}
|
|
21075
21193
|
const missingLayoutHooksByBlockId = /* @__PURE__ */ new Map();
|
|
@@ -21138,11 +21256,18 @@ function validateCustomCssRules(rules, singleBlockId, blocks) {
|
|
|
21138
21256
|
}
|
|
21139
21257
|
}
|
|
21140
21258
|
}
|
|
21141
|
-
for (const [
|
|
21259
|
+
for (const [
|
|
21260
|
+
blockId,
|
|
21261
|
+
missingClassNames
|
|
21262
|
+
] of missingLayoutHooksByBlockId.entries()) {
|
|
21142
21263
|
const missing = Array.from(missingClassNames).sort();
|
|
21143
21264
|
if (missing.length === 0) continue;
|
|
21144
21265
|
const layoutNodeInfos = layoutNodeInfosByBlockId.get(blockId) ?? [];
|
|
21145
|
-
const attachSuggestions = buildClassHookAttachSuggestions(
|
|
21266
|
+
const attachSuggestions = buildClassHookAttachSuggestions(
|
|
21267
|
+
blockId,
|
|
21268
|
+
missing,
|
|
21269
|
+
layoutNodeInfos
|
|
21270
|
+
);
|
|
21146
21271
|
const attachSuggestionsLine = attachSuggestions ? `
|
|
21147
21272
|
|
|
21148
21273
|
Suggested attachments:
|
|
@@ -21176,7 +21301,9 @@ function buildClassHookAttachSuggestions(blockId, missingClassNames, nodes) {
|
|
|
21176
21301
|
continue;
|
|
21177
21302
|
}
|
|
21178
21303
|
if ((lower.includes("headline") || lower.includes("title")) && (headlineNode ?? firstStack)) {
|
|
21179
|
-
lines.push(
|
|
21304
|
+
lines.push(
|
|
21305
|
+
`- ${className} \u2192 add to ${headlineNode ?? firstStack}.props.className`
|
|
21306
|
+
);
|
|
21180
21307
|
continue;
|
|
21181
21308
|
}
|
|
21182
21309
|
if (lower.includes("highlight") && highlightNode) {
|
|
@@ -21184,7 +21311,9 @@ function buildClassHookAttachSuggestions(blockId, missingClassNames, nodes) {
|
|
|
21184
21311
|
continue;
|
|
21185
21312
|
}
|
|
21186
21313
|
if ((lower.includes("body") || lower.includes("copy") || lower.includes("paragraph")) && (paragraphNode ?? firstStack)) {
|
|
21187
|
-
lines.push(
|
|
21314
|
+
lines.push(
|
|
21315
|
+
`- ${className} \u2192 add to ${paragraphNode ?? firstStack}.props.className`
|
|
21316
|
+
);
|
|
21188
21317
|
continue;
|
|
21189
21318
|
}
|
|
21190
21319
|
lines.push(`- ${className} \u2192 add to ${rootPath}.props.className (fallback)`);
|
|
@@ -21192,7 +21321,10 @@ function buildClassHookAttachSuggestions(blockId, missingClassNames, nodes) {
|
|
|
21192
21321
|
return lines.slice(0, 8).join("\n");
|
|
21193
21322
|
}
|
|
21194
21323
|
function extractSelectorClasses(selector) {
|
|
21195
|
-
const withoutDataBlockAttrs = selector.replace(
|
|
21324
|
+
const withoutDataBlockAttrs = selector.replace(
|
|
21325
|
+
/\[data-block=(["']).*?\1\]/g,
|
|
21326
|
+
""
|
|
21327
|
+
);
|
|
21196
21328
|
const classes = /* @__PURE__ */ new Set();
|
|
21197
21329
|
const re = /\.([_a-zA-Z][-_a-zA-Z0-9]*)/g;
|
|
21198
21330
|
let match;
|
|
@@ -21209,7 +21341,9 @@ function extractBlockIdFromSelector(selector) {
|
|
|
21209
21341
|
return match?.[2] ?? null;
|
|
21210
21342
|
}
|
|
21211
21343
|
function validateNodeType(nodeType, path2, ctx) {
|
|
21212
|
-
if (!ALLOWED_NODE_TYPES.includes(
|
|
21344
|
+
if (!ALLOWED_NODE_TYPES.includes(
|
|
21345
|
+
nodeType
|
|
21346
|
+
)) {
|
|
21213
21347
|
return {
|
|
21214
21348
|
path: `${path2}.type`,
|
|
21215
21349
|
message: `Block "${ctx.blockId}": Unknown node type "${nodeType}" at ${path2}`,
|
|
@@ -21223,7 +21357,9 @@ function validateTransforms(transforms, path2, ctx) {
|
|
|
21223
21357
|
for (let i = 0; i < transforms.length; i++) {
|
|
21224
21358
|
const transform = transforms[i];
|
|
21225
21359
|
if (transform.id && typeof transform.id === "string") {
|
|
21226
|
-
if (!ALLOWED_TRANSFORM_IDS.includes(
|
|
21360
|
+
if (!ALLOWED_TRANSFORM_IDS.includes(
|
|
21361
|
+
transform.id
|
|
21362
|
+
)) {
|
|
21227
21363
|
errors.push({
|
|
21228
21364
|
path: `${path2}.transforms[${i}].id`,
|
|
21229
21365
|
message: `Block "${ctx.blockId}": Unknown transform "${transform.id}"`,
|
|
@@ -21272,16 +21408,28 @@ function validateLayoutNode(node, path2, ctx) {
|
|
|
21272
21408
|
if (typeError) errors.push(typeError);
|
|
21273
21409
|
}
|
|
21274
21410
|
if ("$bind" in n && n.$bind && typeof n.$bind === "object") {
|
|
21275
|
-
const bindErrors = validateBinding(
|
|
21411
|
+
const bindErrors = validateBinding(
|
|
21412
|
+
n.$bind,
|
|
21413
|
+
`${path2}.$bind`,
|
|
21414
|
+
ctx
|
|
21415
|
+
);
|
|
21276
21416
|
errors.push(...bindErrors);
|
|
21277
21417
|
}
|
|
21278
21418
|
if ("props" in n && n.props && typeof n.props === "object") {
|
|
21279
|
-
const propsErrors = validatePropsBindings(
|
|
21419
|
+
const propsErrors = validatePropsBindings(
|
|
21420
|
+
n.props,
|
|
21421
|
+
`${path2}.props`,
|
|
21422
|
+
ctx
|
|
21423
|
+
);
|
|
21280
21424
|
errors.push(...propsErrors);
|
|
21281
21425
|
}
|
|
21282
21426
|
if ("children" in n && Array.isArray(n.children)) {
|
|
21283
21427
|
for (let i = 0; i < n.children.length; i++) {
|
|
21284
|
-
const childErrors = validateLayoutNode(
|
|
21428
|
+
const childErrors = validateLayoutNode(
|
|
21429
|
+
n.children[i],
|
|
21430
|
+
`${path2}.children[${i}]`,
|
|
21431
|
+
ctx
|
|
21432
|
+
);
|
|
21285
21433
|
errors.push(...childErrors);
|
|
21286
21434
|
}
|
|
21287
21435
|
}
|
|
@@ -21295,7 +21443,11 @@ function validatePropsBindings(props2, path2, ctx) {
|
|
|
21295
21443
|
const bindErrors = validateBinding(bind2, `${path2}.${key}.$bind`, ctx);
|
|
21296
21444
|
errors.push(...bindErrors);
|
|
21297
21445
|
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
21298
|
-
const nestedErrors = validatePropsBindings(
|
|
21446
|
+
const nestedErrors = validatePropsBindings(
|
|
21447
|
+
value,
|
|
21448
|
+
`${path2}.${key}`,
|
|
21449
|
+
ctx
|
|
21450
|
+
);
|
|
21299
21451
|
errors.push(...nestedErrors);
|
|
21300
21452
|
}
|
|
21301
21453
|
}
|
|
@@ -21336,7 +21488,10 @@ function collectFieldInfo(fields3) {
|
|
|
21336
21488
|
topLevelFieldIds.add(field.id);
|
|
21337
21489
|
if (field.type === "repeater" && field.schema && typeof field.schema === "object" && "fields" in field.schema) {
|
|
21338
21490
|
const nestedFields = field.schema.fields ?? [];
|
|
21339
|
-
repeaterNestedFieldIds.set(
|
|
21491
|
+
repeaterNestedFieldIds.set(
|
|
21492
|
+
field.id,
|
|
21493
|
+
new Set(nestedFields.map((f) => f.id))
|
|
21494
|
+
);
|
|
21340
21495
|
}
|
|
21341
21496
|
}
|
|
21342
21497
|
return { topLevelFieldIds, repeaterNestedFieldIds };
|
|
@@ -21456,7 +21611,11 @@ function findMissingBindings(node, blockId, path2 = "layout") {
|
|
|
21456
21611
|
}
|
|
21457
21612
|
if ("children" in n && Array.isArray(n.children)) {
|
|
21458
21613
|
for (let i = 0; i < n.children.length; i++) {
|
|
21459
|
-
const childErrors = findMissingBindings(
|
|
21614
|
+
const childErrors = findMissingBindings(
|
|
21615
|
+
n.children[i],
|
|
21616
|
+
blockId,
|
|
21617
|
+
`${path2}.children[${i}]`
|
|
21618
|
+
);
|
|
21460
21619
|
errors.push(...childErrors);
|
|
21461
21620
|
}
|
|
21462
21621
|
}
|
|
@@ -21467,7 +21626,9 @@ function getMaxDepth(node, currentDepth = 0) {
|
|
|
21467
21626
|
const n = node;
|
|
21468
21627
|
if (!n.children || !Array.isArray(n.children)) return currentDepth;
|
|
21469
21628
|
if (n.children.length === 0) return currentDepth;
|
|
21470
|
-
return Math.max(
|
|
21629
|
+
return Math.max(
|
|
21630
|
+
...n.children.map((child) => getMaxDepth(child, currentDepth + 1))
|
|
21631
|
+
);
|
|
21471
21632
|
}
|
|
21472
21633
|
var CONTAINER_NODE_TYPES = ["section", "stack", "grid", "div", "inline"];
|
|
21473
21634
|
function detectPotentialTruncation(node, maxAllowedDepth, currentDepth = 0, path2 = "layout") {
|
|
@@ -21482,7 +21643,12 @@ function detectPotentialTruncation(node, maxAllowedDepth, currentDepth = 0, path
|
|
|
21482
21643
|
if (n.children && Array.isArray(n.children)) {
|
|
21483
21644
|
n.children.forEach((child, i) => {
|
|
21484
21645
|
truncatedPaths.push(
|
|
21485
|
-
...detectPotentialTruncation(
|
|
21646
|
+
...detectPotentialTruncation(
|
|
21647
|
+
child,
|
|
21648
|
+
maxAllowedDepth,
|
|
21649
|
+
currentDepth + 1,
|
|
21650
|
+
`${path2}.children[${i}]`
|
|
21651
|
+
)
|
|
21486
21652
|
);
|
|
21487
21653
|
});
|
|
21488
21654
|
}
|
|
@@ -21497,14 +21663,20 @@ function formatValidationFeedback(errors, output) {
|
|
|
21497
21663
|
if (truncatedPaths.length > 0) {
|
|
21498
21664
|
lines.push("### DEPTH LIMIT WARNING");
|
|
21499
21665
|
lines.push("");
|
|
21500
|
-
lines.push(
|
|
21666
|
+
lines.push(
|
|
21667
|
+
`The layout reached the maximum depth of ${MAX_LAYOUT_DEPTH} levels.`
|
|
21668
|
+
);
|
|
21501
21669
|
lines.push("These container nodes at the depth limit have no children:");
|
|
21502
21670
|
for (const path2 of truncatedPaths) {
|
|
21503
21671
|
lines.push(` \u26A0\uFE0F ${path2}`);
|
|
21504
21672
|
}
|
|
21505
21673
|
lines.push("");
|
|
21506
|
-
lines.push(
|
|
21507
|
-
|
|
21674
|
+
lines.push(
|
|
21675
|
+
"**FIX**: Flatten your layout structure or use $repeat for lists."
|
|
21676
|
+
);
|
|
21677
|
+
lines.push(
|
|
21678
|
+
"- Combine wrapper nodes where possible (e.g., section > stack > div \u2192 section > stack)"
|
|
21679
|
+
);
|
|
21508
21680
|
lines.push("- Use $repeat instead of manual nesting for repeated items");
|
|
21509
21681
|
lines.push(`- Current max depth: ${maxDepth}, limit: ${MAX_LAYOUT_DEPTH}`);
|
|
21510
21682
|
lines.push("");
|
|
@@ -21513,13 +21685,19 @@ function formatValidationFeedback(errors, output) {
|
|
|
21513
21685
|
if (errors.length === 0) {
|
|
21514
21686
|
return lines.length > 0 ? lines.join("\n") : "";
|
|
21515
21687
|
}
|
|
21516
|
-
lines.push(
|
|
21688
|
+
lines.push(
|
|
21689
|
+
"## CRITICAL: Your output failed validation. You MUST fix these errors."
|
|
21690
|
+
);
|
|
21517
21691
|
lines.push("");
|
|
21518
21692
|
lines.push("Your previous output had the following problems:");
|
|
21519
21693
|
lines.push("");
|
|
21520
21694
|
const missingBindErrors = errors.filter((e) => e.message.includes("no $bind"));
|
|
21521
|
-
const unusedFieldErrors = errors.filter(
|
|
21522
|
-
|
|
21695
|
+
const unusedFieldErrors = errors.filter(
|
|
21696
|
+
(e) => e.message.includes("never used")
|
|
21697
|
+
);
|
|
21698
|
+
const otherErrors = errors.filter(
|
|
21699
|
+
(e) => !e.message.includes("no $bind") && !e.message.includes("never used")
|
|
21700
|
+
);
|
|
21523
21701
|
if (missingBindErrors.length > 0) {
|
|
21524
21702
|
lines.push("### MISSING $bind ERRORS (nodes that display nothing)");
|
|
21525
21703
|
lines.push("");
|
|
@@ -21527,16 +21705,22 @@ function formatValidationFeedback(errors, output) {
|
|
|
21527
21705
|
lines.push(`\u274C ${error.message}`);
|
|
21528
21706
|
}
|
|
21529
21707
|
lines.push("");
|
|
21530
|
-
lines.push(
|
|
21708
|
+
lines.push(
|
|
21709
|
+
"**FIX**: Every text, richText, media, button, and link node MUST have $bind."
|
|
21710
|
+
);
|
|
21531
21711
|
lines.push("");
|
|
21532
21712
|
lines.push("WRONG (displays nothing):");
|
|
21533
21713
|
lines.push("```json");
|
|
21534
|
-
lines.push(
|
|
21714
|
+
lines.push(
|
|
21715
|
+
'{ "type": "text", "props": { "as": "h1" }, "children": null, "$bind": null }'
|
|
21716
|
+
);
|
|
21535
21717
|
lines.push("```");
|
|
21536
21718
|
lines.push("");
|
|
21537
21719
|
lines.push("CORRECT (bound to field):");
|
|
21538
21720
|
lines.push("```json");
|
|
21539
|
-
lines.push(
|
|
21721
|
+
lines.push(
|
|
21722
|
+
'{ "type": "text", "props": { "as": "h1" }, "children": null, "$bind": { "from": "content.headline", "fallback": null, "transforms": null } }'
|
|
21723
|
+
);
|
|
21540
21724
|
lines.push("```");
|
|
21541
21725
|
lines.push("");
|
|
21542
21726
|
}
|
|
@@ -21555,11 +21739,15 @@ function formatValidationFeedback(errors, output) {
|
|
|
21555
21739
|
if (fieldNames.length > 0) {
|
|
21556
21740
|
lines.push("**CHECKLIST - Add a binding for EACH of these fields:**");
|
|
21557
21741
|
for (const field of fieldNames) {
|
|
21558
|
-
lines.push(
|
|
21742
|
+
lines.push(
|
|
21743
|
+
`- [ ] ${field} \u2192 text node with $bind: { from: "content.${field}" }`
|
|
21744
|
+
);
|
|
21559
21745
|
}
|
|
21560
21746
|
lines.push("");
|
|
21561
21747
|
}
|
|
21562
|
-
lines.push(
|
|
21748
|
+
lines.push(
|
|
21749
|
+
"**COMMON MISTAKE**: Creating container nodes with `children: null` instead of actual bindings."
|
|
21750
|
+
);
|
|
21563
21751
|
lines.push("");
|
|
21564
21752
|
lines.push("This is WRONG (container with no content inside):");
|
|
21565
21753
|
lines.push("```json");
|
|
@@ -21569,12 +21757,18 @@ function formatValidationFeedback(errors, output) {
|
|
|
21569
21757
|
lines.push("This is CORRECT (container with bound text node):");
|
|
21570
21758
|
lines.push("```json");
|
|
21571
21759
|
lines.push('{ "type": "inline", "children": [');
|
|
21572
|
-
lines.push(
|
|
21760
|
+
lines.push(
|
|
21761
|
+
' { "type": "text", "$bind": { "from": "content.fieldName", "fallback": null, "transforms": null }, "props": null, "$repeat": null, "$when": null, "children": null }'
|
|
21762
|
+
);
|
|
21573
21763
|
lines.push("] }");
|
|
21574
21764
|
lines.push("```");
|
|
21575
21765
|
lines.push("");
|
|
21576
|
-
lines.push(
|
|
21577
|
-
|
|
21766
|
+
lines.push(
|
|
21767
|
+
"**FIX**: Every field you define MUST be used in a $bind somewhere in the layout."
|
|
21768
|
+
);
|
|
21769
|
+
lines.push(
|
|
21770
|
+
'If you have a field "highlight", you MUST have a node with $bind: { from: "content.highlight" }'
|
|
21771
|
+
);
|
|
21578
21772
|
lines.push("");
|
|
21579
21773
|
}
|
|
21580
21774
|
if (otherErrors.length > 0) {
|