riverbankcms 0.22.0 → 0.22.1
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/acceptance/matrix.mjs +3 -3
- package/dist/cli/index.mjs +1087 -429
- package/dist/{entryCommands-CoGu0G2R.mjs → entryCommands-Bu-z9kxb.mjs} +176 -76
- package/dist/{eventUpsertInputSchema-B0ubhUu5.mjs → eventUpsertInputSchema-xHmuEKwM.mjs} +2 -2
- package/dist/load-config-BRd0EUsF.mjs +4 -0
- package/dist/{load-config-j58KSqxl.mjs → load-config-pAPKpeE0.mjs} +2 -2
- package/dist/{plan-C4IphkPc.mjs → plan-DUdJbgTV.mjs} +1 -1
- package/dist/scaffold/index.mjs +2 -2
- package/dist/{sdk-event-upsert-BqjzK2zT.mjs → sdk-event-upsert-B3gflo1K.mjs} +344 -133
- package/dist/{src-zzwJUef5.mjs → src-RfhyMOpX.mjs} +133 -81
- package/dist/testing.mjs +4 -4
- package/package.json +1 -1
- package/dist/load-config-Kg45qY-N.mjs +0 -4
package/dist/cli/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
3
|
-
import { $ as
|
|
4
|
-
import { $ as
|
|
5
|
-
import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-
|
|
6
|
-
import { a as RichTextDocSchema, c as isRecord$18, i as findUnfilledSentinels, n as buildEntryScaffold, o as isRichTextDoc, r as validateEntryInstance, s as isObjectRecord, t as eventUpsertInputSchema } from "../eventUpsertInputSchema-
|
|
7
|
-
import { a as prepareScaffoldExecution, c as LOCAL_PACKAGE_VENDOR_DIR, d as loadGeneratedPackageRanges, i as preflightScaffoldTargets, n as createScaffoldCompletion, s as deriveScaffoldLocalManifest, t as deriveScaffoldPlan } from "../plan-
|
|
2
|
+
import { $ as createFormRef, $n as managementMediaLibraryUploadLimitForMimeType, $r as parseThemeColorToken, An as mediaPosterSchema, Ar as surfaceDecorationColors, At as BREAKPOINT_MD, Bn as parseMediaIdentifier, Br as resolveOnColorForThemeToken, Bt as themeButtonExtraClassesWithTrailingIcon, C as sortRecord, Cn as isExplicitRectCrop, Cr as makeBoundaryId, Ct as deriveSiteStyleBlockPolicy, D as mapEventCommandContent, Dn as getDirectImageUrlForSiteScopedPath, Dr as toNonEmptyReadonlyArray, Dt as getHeaderPaintTargets, En as getDirectImageUrlForRelativePath, Er as tileTreatmentValues, Et as generateMobileOverlayBackdropFilterFix, F as pageIdentifierForBlockCommand, Fn as resolveManagedMediaReference, Fr as mergeStyles, Ft as getComponentBorderWidthPx, G as ianaTimezoneSchema, Gr as surfaceToneFromForegroundToken, Gt as footerForegroundCandidates, H as bookingPaymentTermsSchema, Hr as resolveTokenOrCssColorValue, Ht as themeButtonVariantClassNames, I as pageIdentifierForCommand, In as mediaTypeDiscriminants, Ir as rgbColorValue, It as getComponentShadowVar, J as createCommandRef, Jr as surfaceForegroundInputFromResolved, Jt as arrangementLookHooks, K as createBlockRef, Kn as getMimeType, Kr as defaultThemeTokens, Kt as buildTextContrastShadow, L as pagePathForCommand, Ln as mediaIdentifierSchema, Lr as textColorStyle, Lt as ICON_CONFIG, M as blockIdentifierForCommand, Mn as persistableMediaSchema, Mr as TokenResolver, Mt as BREAKPOINT_XL, N as blockOrderIdentifiersForCommand, Nn as runtimeMediaSchema, Nr as backgroundColorStyle, Nt as MQ_MD_DOWN, On as getImageUrl, Or as visibleHeadingDecorationFamilyValues, Ot as renderHeaderPaintTargetRules, P as entryIdentifierForCommand, Pn as buildRenderableMediaAssetIndex, Pr as borderColorStyle, Pt as headerVariantValues, Q as createFooterRef, Qn as classifyKnownMimeType, Qr as getTextColorForBackground, R as hasConfiguredBookingVertical, Rn as buildMediaIdentifierFromFilename, Rr as opaqueSurfaceDeclarations, Rt as generateDefaultButtonSystem, S as venueManagementFields, Sn as normalizeWidthCandidates, Sr as introCompositionTreatmentValues, St as parseGradientPresetId, Tn as resolveMediaTransformForAspect, Tr as testimonialsCompositionTreatmentValues, Tt as generateHeaderScrollTreatmentStyles, U as require_jsx_runtime, Un as deriveVideoSlotPolicy, Ur as PUBLIC_BUTTON_ROLES, Ut as parseThemeForPersistence, V as bookingPaymentCollectionOptionSchema, Vr as resolveThemeColorReferenceValue, Vt as themeButtonSizeClassName, W as require_react, Wn as resolveVideoSelectionIntentForMediaField, Wr as selectLogoVariant, X as createEventCategoryRef, Xn as FILE_SIZE_LIMITS, Xr as surfaceForegroundValue, Xt as resolveItemSurface, Y as createContentEntryRef, Yn as parseRelativeStoragePath, Yr as surfaceForegroundStyle, Yt as arrangementSlotNames, Z as createEventSeriesRef, Zr as expandPalette, Zt as resolveLookSlotSurfaces, _n as summarizePortableMediaReferences, _r as defineNoBlockDesignCapability, _t as resolvePublishedLook, an as deriveSectionGround, ar as defineBlockDesignMetadata, b as isEventVisibility, bn as looksLikeUuid, br as featureCardCompositionTreatmentValues, bt as gradientToCss, c as customLinkSchema$1, cn as resolveSectionBackground, cr as cardListKnobBlocks, ct as headerLeafTextColor, d as internalLinkSchema, dn as boxBackgroundOverlaySchema, dr as asLayoutVariantKey, dt as mergeHeaderNavTypographyPreference, ei as parseBlockColorToken, er as parseSafeDownloadFilename, et as createNavigationRef, f as internalResolvedLinkSchema, fn as boxBackgroundSchema, ft as readHeaderNavFontSizePreference, g as linkSchema, gn as collectPortableMediaReferencesFromContent, gr as defineFrameCapability, gt as resolveModeArrangement, h as isResolvedInternalLinkEntityType, hn as stripStaleTransitionStyleGroup, hr as defineBlockDesignCapability, ht as resolveEffectiveArrangement, in as sectionFactsForContent, ir as normalizeCardRole, it as refSlug, j as eventManagementTiming, jn as mediaSchema, jr as resolveSurfaceForeground, jt as BREAKPOINT_SM, kn as isSiteScopedDirectImageStoragePath, kr as resolveSurface, kt as BREAKPOINT_LG, l as entryLinkSchema$1, ln as resolveSectionPhotoPlacement, lt as transparentHeaderForegroundInput, mn as siteChromeBackgroundOverrideOwner, mr as assertNever$11, mt as readStoredMode, ni as __toESM, nn as boundaryLayout, nr as cardRoleSchema, o as classifySdkEventBookingOffer, on as heroPhotoPaintsGround, or as resolveEffectiveKnobs, ot as effectiveHeaderNavLinkStyle, p as internalRouteOnlyLinkSchema, pn as runtimeBoxBackgroundSchema, pr as asSiteStyleId, pt as arrangementManifestFromVariants, q as createBlocksRef, qn as asRecord, qr as surfaceForegroundDeclarations, qt as generateNavLinkCSS, rn as composeBoundary, rr as cardVariantRoleValues, rt as createVenueRef, s as RESOLVED_INTERNAL_LINK_ENTITY_TYPES, sn as parseCanonicalRuntimeBackground, sr as cardListFamilyBlocks, st as headerForegroundCandidates, t as classifySdkEventTiming, ti as __commonJSMin, tn as headerRootPaint, tr as renderCssDeclarations, tt as createPageRef, u as externalLinkSchema$1, un as sectionForegroundBackground, ur as asDesignBlockId, ut as readOpeningForegroundProjection, v as pageLinkSchema$1, vn as walkAndCollectImageAttrs, vr as eventListTreatmentValues, vt as requireCuratedSiteStyle, w as stableStringify, wn as parseAspectRatioValue, wr as offeringsPreviewCompositionTreatmentValues, wt as themeSchema, xn as rotateNormalizedPoint, xr as headingDecorationColorTokenValues, xt as getGradientPreset, yn as deleteEnvSpecificKeys, yr as eyebrowTreatmentValues, yt as compiledRuntimeStyleFieldNames, z as eventCommandScheduleSchema, zn as parseCanonicalMediaIdentifier, zr as isCssColorLiteral, zt as parseThemeButtonVariantId } from "../sdk-event-upsert-B3gflo1K.mjs";
|
|
3
|
+
import { $ as resolveBookingDisplayContext, $t as formatDurationUnitLabel, A as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, An as unsafeAsPricingOptionId, At as parseEventPageSurfaceSubject, B as parseWeeklyOpeningHours, Bt as fromArray, Ct as getBookingInstalmentPlanIntervalCount, D as parseMailingListSignedSourceToken, Dn as unsafeAsPassId, Dt as resolveFlexibleBalanceDueAt, E as parseMailingListContentVersionId, Et as splitAmountWithRemainderInFirst, F as DEFAULT_MAILING_LIST_TARGETING, Ft as publicEventPricingDisplay, G as selectCategoryView, Gt as parsePositiveCents, Hn as ok, Ht as mapReadonlyNonEmptyArray, I as planMailingListChoicePresentation, It as publicEventPricingOptions, J as formatDateTime, Jt as unsafeAsNonNegativeCents, K as formatDate, Kt as toCents, L as isCanonicalRichTextDoc, Lt as publicEventPricingType, M as parseFooterCompositionV1, Mt as formatEventPricing, Nt as isPublicEventPricingOptionDisplayable, O as parseMailingListRuntimeContext, On as unsafeAsPositiveByteCount, Ot as resolveFlexibleBalanceInitialPaymentCents, P as parseMailingListPlacementTargeting, Pt as publicEventPricingCurrency, Q as inferSiteDateLocale, Qt as assertNever, R as formatOpeningHoursRows, Rt as resolveExactOrFreePriceDisplay, S as parseManagementKey, St as getBookingInstalmentDepositRefundability, T as parseMailingListBlockId, Tn as unsafeAsOccurrenceId, Tt as omitZeroAmountFutureRows, U as normalizeLocationAddressText, Ut as isNonNegativeWholeCents$1, V as assertAllowedPublicUrl, Vn as err, W as toLocationCoordinates, Wt as parseNonNegativeCents, X as formatTime$1, Xt as formatCurrencyAmount, Y as formatDateTimeRange, Yt as unsafeAsPositiveCents, Z as formatTimeRange, Zt as parseCurrencyCode, _ as orderedLiveRunSessions, _n as unsafeAsDemoCapability, _t as isLiveOrderInstalmentPlanStatus, at as getLocalScheduleDate, b as createSecret, bn as unsafeAsEventInstanceId, bt as addIntervalPreservingMonthAnchor, c as resolveSiteVerticalBookingConfig, cn as parseRetiredCourseId, ct as parseBookingLocalDate, dn as parseUserId, dt as resolveBookingTimeZoneId, en as parseApiKeyId, et as buildBookingUtcDateWindow, f as SURFACE_EVENT_PRESET_VALUES, ft as toBookingTimeZone, g as nextLiveRunSessionStartMs, gt as validateBookingPaymentOptionKinds, h as CANCELLED_SESSION_STATUS, hn as unsafeAsCheckoutLineId, in as parseEventSeriesId, it as getBookingLocalDateKey, j as parseMailingListProviderScope, jt as formatBookingPriceDisplay, k as assessMailingListTargeting, kt as deriveTotalTicketQuantity, ln as parseSiteId, lt as parseUtcIsoDateTimeString, mt as toUtcIsoDateTimeString, n as EVENT_PRESET_VOCABULARY, nn as parseDatedOfferingCapacityHoldAuditRef, nt as formatLocalScheduleDate, on as parseMembershipId, ot as getLocalScheduleTime, p as WHOLE_SERIES_EVENT_PRESET_VALUES, pt as toScheduledBookingDateTime, q as formatDateRange, qt as toNonNegativeCents, r as NAVIGATION_LOCATIONS, rn as parseDatedOfferingCapacityHoldId, rt as formatLocalScheduleTime, tn as parseCustomerId, tt as compareLocalScheduleDates, u as EVENT_PRESET_VALUES, un as parseSiteTermsVersionId, ut as resolveBookingBusinessTimeZone, v as resolveWholeSeriesBookingPhase, vt as isSettleableFlexibleBalanceContractStatus, w as slugify, wn as unsafeAsMediaAssetId, wt as getBookingInstalmentProtectedDepositAmountCents, x as exposeSecret, xt as clampConfiguredAmount, y as resolveWholeSeriesRunLifecycle, yt as isSettleableOrderInstalmentPlanStatus, zt as resolvePricingOptionsPriceDisplay } from "../src-RfhyMOpX.mjs";
|
|
4
|
+
import { $ as normalizeMediaValueToIdentifierOnly, $t as bindRequestTimeout, A as formatDiffDetail, An as transportSuggestion, At as navigationIdentity, B as buildFieldChanges, Bn as sdkEventScheduleSchema, Bt as preparePushConfigTarget, C as reportFromOutcomes, Cn as parseEnvironmentSelection, Ct as fileExists, D as normalizeRemoteHomepageReference, Dn as withRiverbankEnv, Dt as writeJsonFileAtomic, E as createEmptySyncResult, En as requireEnvironmentWriteAuthorization, Et as writeJsonFile, F as calculatePullDiff, Fn as isLocalConfigured, Ft as navigationCommandItemToManagementInput, G as syncLocalMediaForPull, Gt as APPOINTMENT_SERVICE_VISIBILITY_VALUES, H as formatFieldPath, Hn as linkPayloadSchema, Ht as extractApiErrorMessage, I as buildJsonDiff, In as isRemoteConfigured, It as normalizeNavigationConfigItemForCommand, J as admitBinaryWriteDestination, Jt as ApiEnvelopeError, K as applyLocalMediaPush, Kt as ApiRequestError, L as hasPageOperations, Ln as loadSdkEnvironment, Lt as applyPushConfigPlan, M as hasPendingChanges, Mt as convertPulledFooterToLocal, N as findChangedFieldsWithValues, Nn as getEnvPrefix, Nt as convertPulledNavigationToLocal, O as calculateDiff, On as ErrorCodes, Ot as isMediaValue, P as formatHumanDiff, Pn as getEnvironmentDebugInfo, Pt as convertPulledPagesToLocal, Q as normalizeMediaIdentifierInput, Qt as mapEnvironmentExecutionOutcomesJson, R as pageMetadataForUpsert, Rn as createManagementClient, Rt as createPushConfigCommand, S as planCliCommandBatchForBindings, Sn as executeEnvironmentPlan, St as ensureDir, T as executeResidualSettingsSyncPlan, Tn as planEnvironmentWriteAuthorization, Tt as readJsonFile, U as revalidateLocalMediaPushPlan, Un as portablePageDesignSchema, Ut as normalizeApiError, V as formatFieldChange, Vn as sdkSettingsUpdateSchema, Vt as revalidatePushConfigPlan, Wn as sdkConfiguredBookingVerticalConfigSchema, Wt as isRecord$2, X as writeBinaryFileAtomic, Xt as deriveCmsApiUrlFromDashboardUrl, Y as readStableBinaryFile, Yt as unwrapResponse, Z as sha256, Zt as API_ENDPOINTS, _ as commandExecutionToReport, _n as runWithInvocation, _t as metadataFilePath, a as executeEntryCommandPlanAsReport, an as createOutputForCommand, at as readEntries, b as executeCompiledCliCommandPlanAsReport, bn as withErrorHandling, bt as writeMetadataFile, c as titleFromEntryData, cn as getOutputContext, ct as readEventsMeta, d as unsafeAsCliEntryIdentifier, dn as managementClientConfigFor, dt as readNavigationMeta, en as confirmAction, et as walkLocalContentMedia, f as unsafeAsCliFormSlug, fn as mapEntryForOutput, ft as readPagesMeta, g as commandCompileFailureToReport, gn as resolveCommandPath, gt as ensureMetadataDir, h as mutationCounterForEffect, hn as parsePaginationOptions, ht as writeMediaManifest, i as entrySiteCommandTypes, in as createListCommand, it as findLegacyEntryFiles, j as formatDiffSummary, jn as CliExit, jt as navigationIdentityMap, k as calculateFooterDiff, kn as formatError, kt as duplicateNavigationIdentityMessage, l as unsafeAsCliBlockIdentifier, ln as getOutputOnlyContext, lt as readFooterMeta, m as commandReportToSyncResult, mn as parseJsonData, mt as readVenuesMeta, n as entryCommandCompileErrorToReport, nn as createCommandContext, nt as downloadMedia, o as executeEntryCommandPlanAsSyncResult, on as currentInvocationEnvelope, ot as readAllMeta, p as unsafeAsCliPageIdentifier, pn as parseJsonArray, pt as readSettingsMeta, q as prepareLocalMediaForPush, qt as createBearerAPIClient, r as entryCommandReportToSyncResult, rn as createGetCommand, rt as extractMediaIdentifiers, s as syncResultForEntryCommandCompileError, sn as formatDateShort, st as readEventCategoriesMeta, t as compileEntryPushCommands, tn as createClientForEnv, tt as buildStorageUrl, u as unsafeAsCliContentTypeKey, un as handleCommandError, ut as readFormsMeta, v as commandReportHasFailures, vn as withCommandContext, vt as metadataTargetFromEnvironment, w as mergeManySyncResults, wn as planEnvironmentExecution, wt as listFiles, x as formatManagementError, xn as withOutputOnlyErrorHandling, xt as writeMetadataRecordMap, y as executeCliCommandPlan, yn as withConfirmation, yt as readMetadataFile, zn as ManagementApiError, zt as loadPushConfigTarget } from "../entryCommands-Bu-z9kxb.mjs";
|
|
5
|
+
import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-pAPKpeE0.mjs";
|
|
6
|
+
import { a as RichTextDocSchema, c as isRecord$18, i as findUnfilledSentinels, n as buildEntryScaffold, o as isRichTextDoc, r as validateEntryInstance, s as isObjectRecord, t as eventUpsertInputSchema } from "../eventUpsertInputSchema-xHmuEKwM.mjs";
|
|
7
|
+
import { a as prepareScaffoldExecution, c as LOCAL_PACKAGE_VENDOR_DIR, d as loadGeneratedPackageRanges, i as preflightScaffoldTargets, n as createScaffoldCompletion, s as deriveScaffoldLocalManifest, t as deriveScaffoldPlan } from "../plan-DUdJbgTV.mjs";
|
|
8
8
|
import { config } from "dotenv";
|
|
9
9
|
import { Command, CommanderError } from "commander";
|
|
10
10
|
import * as fs$2 from "fs/promises";
|
|
@@ -6001,7 +6001,8 @@ const DEFAULT_REPEATER_GRID_SPAN_FIELD_ID = "gridSpan";
|
|
|
6001
6001
|
const DEFAULT_REPEATER_GRID_ROW_FIELD_ID = "gridRow";
|
|
6002
6002
|
const DEFAULT_REPEATER_GRID_COLUMN_FIELD_ID = "gridColumn";
|
|
6003
6003
|
const MIN_COLUMNS = 1;
|
|
6004
|
-
const
|
|
6004
|
+
const MAX_REPEATER_GRID_COLUMNS = 6;
|
|
6005
|
+
const MAX_COLUMNS = MAX_REPEATER_GRID_COLUMNS;
|
|
6005
6006
|
function normalizeInteger(value) {
|
|
6006
6007
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
6007
6008
|
return Math.trunc(value);
|
|
@@ -6073,7 +6074,7 @@ function createRepeaterGridSpanField(options) {
|
|
|
6073
6074
|
const fieldId = resolveRepeaterGridSpanFieldId(options);
|
|
6074
6075
|
const label = asNonEmptyString(options?.label) ?? "Grid span";
|
|
6075
6076
|
const description = asNonEmptyString(options?.description) ?? "Columns occupied by this item in layout-grid mode.";
|
|
6076
|
-
const defaultSpan = normalizeRepeaterGridColumns(options?.defaultSpan ?? 1);
|
|
6077
|
+
const defaultSpan = clamp(normalizeRepeaterGridColumns(options?.defaultSpan ?? 1), 1, 4);
|
|
6077
6078
|
return {
|
|
6078
6079
|
id: fieldId,
|
|
6079
6080
|
type: "select",
|
|
@@ -6192,7 +6193,26 @@ function resolveRepeaterGridColumnsForBreakpoint(values, bindings, breakpoint) {
|
|
|
6192
6193
|
}
|
|
6193
6194
|
return MIN_COLUMNS;
|
|
6194
6195
|
}
|
|
6195
|
-
|
|
6196
|
+
/** Strict admission; rendering normalization never grants permission to persist. */
|
|
6197
|
+
function parseRepeaterGridInteger(value) {
|
|
6198
|
+
if (typeof value !== "number" && (typeof value !== "string" || !value.trim())) return null;
|
|
6199
|
+
const number = Number(value);
|
|
6200
|
+
return Number.isInteger(number) ? number : null;
|
|
6201
|
+
}
|
|
6202
|
+
function isAcceptedRepeaterGridSpan(value, columns, acceptedSpans$1) {
|
|
6203
|
+
const span = parseRepeaterGridInteger(value);
|
|
6204
|
+
return span != null && span >= 1 && span <= columns && (!acceptedSpans$1 || acceptedSpans$1.includes(span));
|
|
6205
|
+
}
|
|
6206
|
+
function resolveRepeaterGridAcceptedSpans(fields$1, spanField) {
|
|
6207
|
+
const field = fields$1.find((candidate) => candidate.id === spanField);
|
|
6208
|
+
return field?.type === "select" ? (field.options ?? []).map((option) => Number(option.value)) : undefined;
|
|
6209
|
+
}
|
|
6210
|
+
function normalizeRepeaterGridSpan(value, activeColumns, acceptedSpans$1) {
|
|
6211
|
+
if (acceptedSpans$1) {
|
|
6212
|
+
const valid = acceptedSpans$1.filter((span) => span <= activeColumns);
|
|
6213
|
+
const parsed$1 = parseRepeaterGridInteger(value);
|
|
6214
|
+
return parsed$1 != null && valid.includes(parsed$1) ? parsed$1 : valid.length ? Math.min(...valid) : 1;
|
|
6215
|
+
}
|
|
6196
6216
|
const parsed = normalizeInteger(value);
|
|
6197
6217
|
if (parsed == null) {
|
|
6198
6218
|
return 1;
|
|
@@ -6237,12 +6257,14 @@ function getOverlappingItemIds(input) {
|
|
|
6237
6257
|
return new Set(buildPlacementCells(input).flatMap((col) => Array.from(input.occupancy.get(toRowCellKey(input.row, col, input.columns)) ?? []).filter((id) => !input.excludedIds?.has(id))));
|
|
6238
6258
|
}
|
|
6239
6259
|
function normalizeInputItem(item, columns, sourceIndex) {
|
|
6240
|
-
const span = normalizeRepeaterGridSpan(item.span, columns);
|
|
6260
|
+
const span = normalizeRepeaterGridSpan(item.span, columns, item.acceptedSpans);
|
|
6241
6261
|
const row$1 = normalizeRepeaterGridRow(item.row);
|
|
6242
6262
|
const colStart = normalizeRepeaterGridColStart(item.colStart, columns, span);
|
|
6243
6263
|
const colEnd = colStart + span - 1;
|
|
6244
6264
|
return {
|
|
6245
6265
|
id: item.id,
|
|
6266
|
+
startNewRow: item.startNewRow,
|
|
6267
|
+
acceptedSpans: item.acceptedSpans,
|
|
6246
6268
|
sourceIndex,
|
|
6247
6269
|
span,
|
|
6248
6270
|
row: row$1,
|
|
@@ -6251,8 +6273,132 @@ function normalizeInputItem(item, columns, sourceIndex) {
|
|
|
6251
6273
|
startCell: toRowCellKey(row$1, colStart, columns)
|
|
6252
6274
|
};
|
|
6253
6275
|
}
|
|
6276
|
+
/** Ordered, non-dense placement. Rendering clamps widths; admission checks originals separately. */
|
|
6277
|
+
function flowRepeaterGridItems(items, columns) {
|
|
6278
|
+
const count = normalizeRepeaterGridColumns(columns);
|
|
6279
|
+
return items.reduce((placed, item) => {
|
|
6280
|
+
const span = normalizeRepeaterGridSpan(item.span, count);
|
|
6281
|
+
const previous = placed.at(-1);
|
|
6282
|
+
const nextColumn = previous ? previous.colStart + previous.span : 1;
|
|
6283
|
+
const wraps = previous != null && (item.startNewRow === true || nextColumn + span - 1 > count);
|
|
6284
|
+
return [...placed, {
|
|
6285
|
+
...item,
|
|
6286
|
+
span,
|
|
6287
|
+
row: (previous?.row ?? 1) + (wraps ? 1 : 0),
|
|
6288
|
+
colStart: wraps ? 1 : nextColumn
|
|
6289
|
+
}];
|
|
6290
|
+
}, []);
|
|
6291
|
+
}
|
|
6292
|
+
function orderedGridItems(layout) {
|
|
6293
|
+
return [...layout.placements].sort((a$1, b$1) => a$1.sourceIndex - b$1.sourceIndex);
|
|
6294
|
+
}
|
|
6295
|
+
function isRepeaterGridLayoutInvalid(layout) {
|
|
6296
|
+
return layout.hasInvalidItems || layout.hasCollisions || layout.overCapacity;
|
|
6297
|
+
}
|
|
6298
|
+
function hasInvalidGridItems(items, columns, policy) {
|
|
6299
|
+
const flow = policy === "flow" ? flowRepeaterGridItems(items, columns) : null;
|
|
6300
|
+
return items.some((item, index) => !isValidGridItemGeometry(item, columns) || flow != null && (item.row !== flow[index]?.row || item.colStart !== flow[index]?.colStart));
|
|
6301
|
+
}
|
|
6302
|
+
function isValidGridItemGeometry(item, columns) {
|
|
6303
|
+
return isAcceptedRepeaterGridSpan(item.span, columns, item.acceptedSpans) && parseRepeaterGridInteger(item.row) != null && item.row >= 1 && parseRepeaterGridInteger(item.colStart) != null && item.colStart >= 1 && item.colStart + item.span - 1 <= columns;
|
|
6304
|
+
}
|
|
6305
|
+
function findFlowAppendPlacement(layout, span, startNewRow) {
|
|
6306
|
+
const next = flowRepeaterGridItems([...orderedGridItems(layout), {
|
|
6307
|
+
id: "new",
|
|
6308
|
+
span,
|
|
6309
|
+
row: 1,
|
|
6310
|
+
colStart: 1,
|
|
6311
|
+
startNewRow
|
|
6312
|
+
}], layout.columns).at(-1);
|
|
6313
|
+
return !isRepeaterGridLayoutInvalid(layout) && next && (layout.maxRows == null || next.row <= layout.maxRows) ? {
|
|
6314
|
+
row: next.row,
|
|
6315
|
+
colStart: next.colStart
|
|
6316
|
+
} : null;
|
|
6317
|
+
}
|
|
6318
|
+
function planFlowItems(layout, items) {
|
|
6319
|
+
const placed = flowRepeaterGridItems(items, layout.columns);
|
|
6320
|
+
if (isRepeaterGridLayoutInvalid(layout) || placed.some((item) => !isAcceptedRepeaterGridSpan(item.span, layout.columns, item.acceptedSpans) || layout.maxRows != null && item.row > layout.maxRows)) return { kind: "blocked" };
|
|
6321
|
+
const [first, ...rest] = placed.map(({ id, row: row$1, colStart, span }) => ({
|
|
6322
|
+
id,
|
|
6323
|
+
row: row$1,
|
|
6324
|
+
colStart,
|
|
6325
|
+
span
|
|
6326
|
+
}));
|
|
6327
|
+
return first ? {
|
|
6328
|
+
kind: "move",
|
|
6329
|
+
updates: [first, ...rest]
|
|
6330
|
+
} : { kind: "unchanged" };
|
|
6331
|
+
}
|
|
6332
|
+
/** Insertion reorder, with a complete coordinate write for the resulting order. */
|
|
6333
|
+
function planRepeaterGridReorder(layout, id, to, interaction = "step") {
|
|
6334
|
+
if (layout.placementPolicy !== "flow") return { kind: "blocked" };
|
|
6335
|
+
const items = orderedGridItems(layout);
|
|
6336
|
+
const from = items.findIndex((item) => item.id === id);
|
|
6337
|
+
if (from < 0 || to < 0 || to >= items.length) return { kind: "blocked" };
|
|
6338
|
+
if (from === to) return { kind: "unchanged" };
|
|
6339
|
+
const active = items[from];
|
|
6340
|
+
if (!active) return { kind: "blocked" };
|
|
6341
|
+
return decideFlowReorder({
|
|
6342
|
+
layout,
|
|
6343
|
+
items,
|
|
6344
|
+
active,
|
|
6345
|
+
from,
|
|
6346
|
+
to,
|
|
6347
|
+
interaction
|
|
6348
|
+
});
|
|
6349
|
+
}
|
|
6350
|
+
function decideFlowReorder(input) {
|
|
6351
|
+
const { layout, items, active, from, to, interaction } = input;
|
|
6352
|
+
const id = active.id;
|
|
6353
|
+
const remaining = items.filter((item) => item.id !== id);
|
|
6354
|
+
const inserted = [
|
|
6355
|
+
...remaining.slice(0, to),
|
|
6356
|
+
active,
|
|
6357
|
+
...remaining.slice(to)
|
|
6358
|
+
];
|
|
6359
|
+
const clearRowBreak = interaction === "drag" && active.startNewRow === true && dragInsertsWithinRow(items, from, to, layout.columns);
|
|
6360
|
+
const nextItems = clearRowBreak ? inserted.map((item) => item.id === id ? {
|
|
6361
|
+
...item,
|
|
6362
|
+
startNewRow: false
|
|
6363
|
+
} : item) : inserted;
|
|
6364
|
+
const decision = planFlowItems(layout, nextItems);
|
|
6365
|
+
return decision.kind === "move" ? {
|
|
6366
|
+
...decision,
|
|
6367
|
+
reorder: {
|
|
6368
|
+
id,
|
|
6369
|
+
from,
|
|
6370
|
+
to
|
|
6371
|
+
},
|
|
6372
|
+
...clearRowBreak ? { startNewRowUpdate: {
|
|
6373
|
+
id,
|
|
6374
|
+
value: false
|
|
6375
|
+
} } : {}
|
|
6376
|
+
} : decision;
|
|
6377
|
+
}
|
|
6378
|
+
/** Read the insertion bar position, independently of the dragged width. */
|
|
6379
|
+
function dragInsertsWithinRow(items, from, to, columns) {
|
|
6380
|
+
const target = items[to];
|
|
6381
|
+
if (!target) return false;
|
|
6382
|
+
const column = from < to ? target.colEnd + 1 : target.colStart;
|
|
6383
|
+
return column > 1 && column <= columns;
|
|
6384
|
+
}
|
|
6385
|
+
function planRepeaterGridStartNewRow(layout, id, value) {
|
|
6386
|
+
const active = layout.byId[id];
|
|
6387
|
+
if (layout.placementPolicy !== "flow" || !active) return { kind: "blocked" };
|
|
6388
|
+
const decision = planFlowItems(layout, orderedGridItems(layout).map((item) => item.id === id ? {
|
|
6389
|
+
...item,
|
|
6390
|
+
startNewRow: value
|
|
6391
|
+
} : item));
|
|
6392
|
+
return decision.kind === "move" ? {
|
|
6393
|
+
...decision,
|
|
6394
|
+
startNewRowUpdate: {
|
|
6395
|
+
id,
|
|
6396
|
+
value
|
|
6397
|
+
}
|
|
6398
|
+
} : decision;
|
|
6399
|
+
}
|
|
6254
6400
|
function buildRepeaterGridLayout(input) {
|
|
6255
|
-
const columns =
|
|
6401
|
+
const columns = normalizeRepeaterGridColumns(input.columns);
|
|
6256
6402
|
const maxRows = input.maxRows != null ? Math.max(1, Math.trunc(input.maxRows)) : undefined;
|
|
6257
6403
|
const capacityCells = maxRows != null ? maxRows * columns : undefined;
|
|
6258
6404
|
const placements = input.items.map((item, sourceIndex) => normalizeInputItem(item, columns, sourceIndex)).sort((a$1, b$1) => {
|
|
@@ -6265,51 +6411,50 @@ function buildRepeaterGridLayout(input) {
|
|
|
6265
6411
|
const { hasCollisions } = buildOccupancyByCell(placements, columns);
|
|
6266
6412
|
const overCapacity = maxRows != null && maxRowUsed > maxRows;
|
|
6267
6413
|
return {
|
|
6414
|
+
placementPolicy: input.placementPolicy,
|
|
6268
6415
|
columns,
|
|
6269
6416
|
maxRows,
|
|
6270
6417
|
capacityCells,
|
|
6271
6418
|
maxRowUsed,
|
|
6272
6419
|
overCapacity,
|
|
6273
6420
|
hasCollisions,
|
|
6421
|
+
hasInvalidItems: hasInvalidGridItems(input.items, columns, input.placementPolicy),
|
|
6274
6422
|
placements,
|
|
6275
6423
|
byId
|
|
6276
6424
|
};
|
|
6277
6425
|
}
|
|
6278
6426
|
function findFirstAvailableRepeaterGridPlacement(input) {
|
|
6279
|
-
const columns =
|
|
6427
|
+
const columns = normalizeRepeaterGridColumns(input.columns);
|
|
6280
6428
|
const maxRows = input.maxRows != null ? Math.max(1, Math.trunc(input.maxRows)) : undefined;
|
|
6281
|
-
|
|
6429
|
+
if (!isAcceptedRepeaterGridSpan(input.newItemSpan, columns, input.acceptedSpans)) return null;
|
|
6430
|
+
const span = normalizeRepeaterGridSpan(input.newItemSpan, columns, input.acceptedSpans);
|
|
6282
6431
|
const layout = buildRepeaterGridLayout({
|
|
6283
6432
|
items: input.items,
|
|
6284
6433
|
columns,
|
|
6285
|
-
maxRows
|
|
6434
|
+
maxRows,
|
|
6435
|
+
placementPolicy: input.placementPolicy
|
|
6286
6436
|
});
|
|
6437
|
+
if (input.placementPolicy === "flow") return findFlowAppendPlacement(layout, span, input.startNewRow);
|
|
6287
6438
|
const { occupancy } = buildOccupancyByCell(layout.placements, columns);
|
|
6288
6439
|
const rowLimit = maxRows ?? Math.max(1, layout.maxRowUsed + 1);
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
row: row$1,
|
|
6302
|
-
colStart
|
|
6303
|
-
};
|
|
6304
|
-
}
|
|
6305
|
-
}
|
|
6306
|
-
}
|
|
6307
|
-
return null;
|
|
6440
|
+
if (isRepeaterGridLayoutInvalid(layout)) return null;
|
|
6441
|
+
const maxColStart = columns - span + 1;
|
|
6442
|
+
return Array.from({ length: rowLimit * maxColStart }, (_$1, index) => ({
|
|
6443
|
+
row: Math.floor(index / maxColStart) + 1,
|
|
6444
|
+
colStart: index % maxColStart + 1
|
|
6445
|
+
})).find(({ row: row$1, colStart }) => getOverlappingItemIds({
|
|
6446
|
+
occupancy,
|
|
6447
|
+
row: row$1,
|
|
6448
|
+
colStart,
|
|
6449
|
+
span,
|
|
6450
|
+
columns
|
|
6451
|
+
}).size === 0) ?? null;
|
|
6308
6452
|
}
|
|
6309
6453
|
function canAppendRepeaterGridItem(input) {
|
|
6310
6454
|
return findFirstAvailableRepeaterGridPlacement({
|
|
6311
6455
|
items: input.items,
|
|
6312
6456
|
newItemSpan: input.newItemSpan,
|
|
6457
|
+
acceptedSpans: input.acceptedSpans,
|
|
6313
6458
|
columns: input.columns,
|
|
6314
6459
|
maxRows: input.maxRows
|
|
6315
6460
|
}) != null;
|
|
@@ -6336,7 +6481,7 @@ function swapPositionUpdates(active, target) {
|
|
|
6336
6481
|
function validateGridMove(layout, updates) {
|
|
6337
6482
|
const moved = updates;
|
|
6338
6483
|
const stationary = layout.placements.filter((placement) => !updates.some((update) => update.id === placement.id));
|
|
6339
|
-
const valid = moved.every((placement, index) => placement.colStart >= 1 && placement.colStart + placement.span - 1 <= layout.columns && placement.row >= 1 && (layout.maxRows == null || placement.row <= layout.maxRows) && !stationary.some((other) => placementsOverlap(placement, other)) && !moved.slice(index + 1).some((other) => placementsOverlap(placement, other)));
|
|
6484
|
+
const valid = !layout.hasInvalidItems && !layout.hasCollisions && !layout.overCapacity && moved.every((placement, index) => isAcceptedRepeaterGridSpan(placement.span, layout.columns, layout.byId[placement.id]?.acceptedSpans) && placement.colStart >= 1 && placement.colStart + placement.span - 1 <= layout.columns && placement.row >= 1 && (layout.maxRows == null || placement.row <= layout.maxRows) && !stationary.some((other) => placementsOverlap(placement, other)) && !moved.slice(index + 1).some((other) => placementsOverlap(placement, other)));
|
|
6340
6485
|
return valid ? {
|
|
6341
6486
|
kind: "move",
|
|
6342
6487
|
updates
|
|
@@ -6358,7 +6503,14 @@ function decideGridDrop(layout, active, destination) {
|
|
|
6358
6503
|
function buildRepeaterGridDropTargets(input) {
|
|
6359
6504
|
const { layout, draggedId, rowsToRender } = input;
|
|
6360
6505
|
const active = layout.byId[draggedId];
|
|
6361
|
-
if (!active) return [];
|
|
6506
|
+
if (!active || isRepeaterGridLayoutInvalid(layout)) return [];
|
|
6507
|
+
if (layout.placementPolicy === "flow") return orderedGridItems(layout).map((item, index) => ({
|
|
6508
|
+
id: `repeater-grid-drop-${item.row}-${item.colStart}`,
|
|
6509
|
+
row: item.row,
|
|
6510
|
+
colStart: item.colStart,
|
|
6511
|
+
cell: item.startCell,
|
|
6512
|
+
decision: planRepeaterGridReorder(layout, draggedId, index, input.interaction ?? "drag")
|
|
6513
|
+
}));
|
|
6362
6514
|
const rowCeiling = layout.maxRows ?? Math.max(1, rowsToRender ?? layout.maxRowUsed + 1, active.row + 1);
|
|
6363
6515
|
return Array.from({ length: rowCeiling * layout.columns }, (_$1, index) => {
|
|
6364
6516
|
const row$1 = Math.floor(index / layout.columns) + 1;
|
|
@@ -6375,6 +6527,166 @@ function buildRepeaterGridDropTargets(input) {
|
|
|
6375
6527
|
};
|
|
6376
6528
|
});
|
|
6377
6529
|
}
|
|
6530
|
+
/** Width edits keep the item's start when it fits; otherwise relocate it to the first free cell.
|
|
6531
|
+
* Neighbours keep their positions. A full bounded grid blocks the change without partial writes.
|
|
6532
|
+
*/
|
|
6533
|
+
function planRepeaterGridSpanChange(input) {
|
|
6534
|
+
const { layout, id, span } = input;
|
|
6535
|
+
const active = layout.byId[id];
|
|
6536
|
+
if (isRepeaterGridLayoutInvalid(layout)) return { kind: "blocked" };
|
|
6537
|
+
if (!active || !isAcceptedRepeaterGridSpan(span, layout.columns, active.acceptedSpans)) return { kind: "blocked" };
|
|
6538
|
+
const nextSpan = Number(span);
|
|
6539
|
+
if (active.span === nextSpan) return { kind: "unchanged" };
|
|
6540
|
+
if (layout.placementPolicy === "flow") return planFlowItems(layout, orderedGridItems(layout).map((item) => item.id === id ? {
|
|
6541
|
+
...item,
|
|
6542
|
+
span: nextSpan
|
|
6543
|
+
} : item));
|
|
6544
|
+
const atCurrent = validateGridMove(layout, [{
|
|
6545
|
+
id,
|
|
6546
|
+
span: nextSpan,
|
|
6547
|
+
row: active.row,
|
|
6548
|
+
colStart: active.colStart
|
|
6549
|
+
}]);
|
|
6550
|
+
if (atCurrent.kind === "move") return atCurrent;
|
|
6551
|
+
const destination = findFirstAvailableRepeaterGridPlacement({
|
|
6552
|
+
items: layout.placements.filter((item) => item.id !== id),
|
|
6553
|
+
newItemSpan: nextSpan,
|
|
6554
|
+
acceptedSpans: active.acceptedSpans,
|
|
6555
|
+
columns: layout.columns,
|
|
6556
|
+
maxRows: layout.maxRows
|
|
6557
|
+
});
|
|
6558
|
+
return destination ? validateGridMove(layout, [{
|
|
6559
|
+
id,
|
|
6560
|
+
span: nextSpan,
|
|
6561
|
+
...destination
|
|
6562
|
+
}]) : { kind: "blocked" };
|
|
6563
|
+
}
|
|
6564
|
+
/** Narrow rendering is a projection only. Never feed these placements into an authoring write. */
|
|
6565
|
+
function projectRepeaterGridLayout(layout, columns) {
|
|
6566
|
+
if (isRepeaterGridLayoutInvalid(layout)) return projectRepeaterGridLayoutForRendering(layout, columns);
|
|
6567
|
+
if (columns === layout.columns) return layout;
|
|
6568
|
+
if (layout.placementPolicy === "flow") return buildProjectedRepeaterGridLayout(layout, flowRepeaterGridItems(orderedGridItems(layout), columns), columns);
|
|
6569
|
+
const items = layout.placements.reduce((placed, item) => {
|
|
6570
|
+
const span = normalizeRepeaterGridSpan(item.span, columns);
|
|
6571
|
+
const destination = findFirstAvailableRepeaterGridPlacement({
|
|
6572
|
+
items: placed,
|
|
6573
|
+
newItemSpan: span,
|
|
6574
|
+
columns
|
|
6575
|
+
});
|
|
6576
|
+
return [...placed, {
|
|
6577
|
+
id: item.id,
|
|
6578
|
+
span,
|
|
6579
|
+
row: destination?.row ?? placed.length + 1,
|
|
6580
|
+
colStart: destination?.colStart ?? 1
|
|
6581
|
+
}];
|
|
6582
|
+
}, []);
|
|
6583
|
+
return buildProjectedRepeaterGridLayout(layout, items, columns);
|
|
6584
|
+
}
|
|
6585
|
+
function buildProjectedRepeaterGridLayout(source, items, columns) {
|
|
6586
|
+
const projected = buildRepeaterGridLayout({
|
|
6587
|
+
items: items.map(({ id, span, row: row$1, colStart, startNewRow }) => ({
|
|
6588
|
+
id,
|
|
6589
|
+
span,
|
|
6590
|
+
row: row$1,
|
|
6591
|
+
colStart,
|
|
6592
|
+
startNewRow
|
|
6593
|
+
})),
|
|
6594
|
+
columns,
|
|
6595
|
+
placementPolicy: source.placementPolicy === "flow" || isRepeaterGridLayoutInvalid(source) ? "flow" : source.placementPolicy
|
|
6596
|
+
});
|
|
6597
|
+
const placements = projected.placements.map((item) => ({
|
|
6598
|
+
...item,
|
|
6599
|
+
sourceIndex: source.byId[item.id]?.sourceIndex ?? item.sourceIndex
|
|
6600
|
+
}));
|
|
6601
|
+
return {
|
|
6602
|
+
...projected,
|
|
6603
|
+
placements,
|
|
6604
|
+
byId: Object.fromEntries(placements.map((item) => [item.id, item]))
|
|
6605
|
+
};
|
|
6606
|
+
}
|
|
6607
|
+
/** Public fallback: preserve saved array order, use non-dense auto-placement, and ignore authoring capacity. */
|
|
6608
|
+
function projectRepeaterGridLayoutForRendering(layout, columns = layout.columns) {
|
|
6609
|
+
if (!isRepeaterGridLayoutInvalid(layout)) {
|
|
6610
|
+
return projectRepeaterGridLayout(layout, columns);
|
|
6611
|
+
}
|
|
6612
|
+
const count = normalizeRepeaterGridColumns(columns);
|
|
6613
|
+
return buildProjectedRepeaterGridLayout(layout, flowRepeaterGridItems(orderedGridItems(layout), count), count);
|
|
6614
|
+
}
|
|
6615
|
+
|
|
6616
|
+
//#endregion
|
|
6617
|
+
//#region ../blocks/src/system/manifest/layoutGridConfiguration.ts
|
|
6618
|
+
const itemFieldsSchema = z.object({ fields: z.array(z.object({
|
|
6619
|
+
id: z.string(),
|
|
6620
|
+
type: z.string(),
|
|
6621
|
+
defaultValue: z.unknown().optional(),
|
|
6622
|
+
options: z.array(z.object({ value: z.string() })).optional(),
|
|
6623
|
+
multiple: z.boolean().optional(),
|
|
6624
|
+
source: z.object({ kind: z.string() }).optional()
|
|
6625
|
+
})) });
|
|
6626
|
+
function validateSpanSelect(span, columns, ctx) {
|
|
6627
|
+
if (span.type !== "select") return;
|
|
6628
|
+
const options = span.options ?? [];
|
|
6629
|
+
const invalidOptions = options.some((option) => !isAcceptedRepeaterGridSpan(option.value, columns) || String(Number(option.value)) !== option.value);
|
|
6630
|
+
if (span.multiple || options.length === 0 || invalidOptions || span.source && span.source.kind !== "static") {
|
|
6631
|
+
ctx.addIssue({
|
|
6632
|
+
code: "custom",
|
|
6633
|
+
path: ["ui", "layoutGridSpanField"],
|
|
6634
|
+
message: `Layout-grid span select must have single, static integer options within 1..${columns}`
|
|
6635
|
+
});
|
|
6636
|
+
}
|
|
6637
|
+
if (span.defaultValue !== undefined && !options.some((option) => option.value === span.defaultValue)) {
|
|
6638
|
+
ctx.addIssue({
|
|
6639
|
+
code: "custom",
|
|
6640
|
+
path: ["ui", "layoutGridSpanField"],
|
|
6641
|
+
message: "Layout-grid default span must be one of the span select options"
|
|
6642
|
+
});
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
/** Both monomorphic and polymorphic item schemas have the same layout contract. */
|
|
6646
|
+
function validateLayoutGridConfiguration(data, ctx) {
|
|
6647
|
+
const ui = data.ui;
|
|
6648
|
+
if (ui?.repeaterPreset !== "layoutGrid") return;
|
|
6649
|
+
if (ui.layoutGridColumns !== undefined === (ui.layoutGridColumnsFields !== undefined)) {
|
|
6650
|
+
ctx.addIssue({
|
|
6651
|
+
code: "custom",
|
|
6652
|
+
path: ["ui", "layoutGridColumns"],
|
|
6653
|
+
message: "Layout-grid requires exactly one of ui.layoutGridColumns or ui.layoutGridColumnsFields.lg; do not set both"
|
|
6654
|
+
});
|
|
6655
|
+
}
|
|
6656
|
+
const spanId = resolveRepeaterGridSpanFieldId({ id: ui.layoutGridSpanField });
|
|
6657
|
+
const requiredIds = [
|
|
6658
|
+
spanId,
|
|
6659
|
+
resolveRepeaterGridRowFieldId({ id: ui.layoutGridRowField }),
|
|
6660
|
+
resolveRepeaterGridColumnFieldId({ id: ui.layoutGridColumnField })
|
|
6661
|
+
];
|
|
6662
|
+
const schemas = data.polymorphic && data.itemTypes ? Object.values(data.itemTypes) : [data.schema];
|
|
6663
|
+
schemas.forEach((schema) => {
|
|
6664
|
+
const parsed = itemFieldsSchema.safeParse(schema);
|
|
6665
|
+
if (!parsed.success) return;
|
|
6666
|
+
if (!requiredIds.every((id) => parsed.data.fields.some((field) => field.id === id))) {
|
|
6667
|
+
ctx.addIssue({
|
|
6668
|
+
code: "custom",
|
|
6669
|
+
path: ["ui", "layoutGridRowField"],
|
|
6670
|
+
message: `layoutGrid repeaters require span/row/column fields (${requiredIds.join(", ")}) to exist in repeater item fields`
|
|
6671
|
+
});
|
|
6672
|
+
}
|
|
6673
|
+
if (ui.layoutGridStartNewRowField && !parsed.data.fields.some((field) => field.id === ui.layoutGridStartNewRowField && field.type === "boolean")) {
|
|
6674
|
+
ctx.addIssue({
|
|
6675
|
+
code: "custom",
|
|
6676
|
+
path: ["ui", "layoutGridStartNewRowField"],
|
|
6677
|
+
message: "Layout-grid Start a new row field must reference a boolean item field"
|
|
6678
|
+
});
|
|
6679
|
+
}
|
|
6680
|
+
if (ui.layoutGridStartNewRowField && ui.layoutGridColumns === undefined) {
|
|
6681
|
+
ctx.addIssue({
|
|
6682
|
+
code: "custom",
|
|
6683
|
+
path: ["ui", "layoutGridStartNewRowField"],
|
|
6684
|
+
message: "Layout-grid Start a new row requires fixed columns (flow placement)"
|
|
6685
|
+
});
|
|
6686
|
+
}
|
|
6687
|
+
parsed.data.fields.filter((field) => field.id === spanId).forEach((span) => validateSpanSelect(span, ui.layoutGridColumns ?? MAX_REPEATER_GRID_COLUMNS, ctx));
|
|
6688
|
+
});
|
|
6689
|
+
}
|
|
6378
6690
|
|
|
6379
6691
|
//#endregion
|
|
6380
6692
|
//#region ../blocks/src/system/icons/presets.ts
|
|
@@ -6560,6 +6872,14 @@ const uiSchema = z.object({
|
|
|
6560
6872
|
thumbnailLabelField: z.string().optional(),
|
|
6561
6873
|
thumbnailAspectRatio: z.string().optional(),
|
|
6562
6874
|
thumbnailCardDensity: z.enum(["compact", "comfortable"]).optional(),
|
|
6875
|
+
layoutGridColumns: z.union([
|
|
6876
|
+
z.literal(1),
|
|
6877
|
+
z.literal(2),
|
|
6878
|
+
z.literal(3),
|
|
6879
|
+
z.literal(4),
|
|
6880
|
+
z.literal(5),
|
|
6881
|
+
z.literal(6)
|
|
6882
|
+
]).optional(),
|
|
6563
6883
|
layoutGridColumnsFields: z.object({
|
|
6564
6884
|
base: z.string().optional(),
|
|
6565
6885
|
sm: z.string().optional(),
|
|
@@ -6568,6 +6888,7 @@ const uiSchema = z.object({
|
|
|
6568
6888
|
xl: z.string().optional()
|
|
6569
6889
|
}).optional(),
|
|
6570
6890
|
layoutGridSpanField: z.string().optional(),
|
|
6891
|
+
layoutGridStartNewRowField: z.string().optional(),
|
|
6571
6892
|
layoutGridRowField: z.string().optional(),
|
|
6572
6893
|
layoutGridColumnField: z.string().optional(),
|
|
6573
6894
|
layoutGridMaxRows: z.number().int().positive().optional(),
|
|
@@ -6589,7 +6910,26 @@ const uiSchema = z.object({
|
|
|
6589
6910
|
"style"
|
|
6590
6911
|
]).optional(),
|
|
6591
6912
|
valueContract: z.enum(["boxBackground"]).optional()
|
|
6592
|
-
}).partial()
|
|
6913
|
+
}).partial().superRefine((ui, ctx) => {
|
|
6914
|
+
if (ui.layoutGridColumns !== undefined && ui.layoutGridColumnsFields !== undefined) {
|
|
6915
|
+
ctx.addIssue({
|
|
6916
|
+
code: "custom",
|
|
6917
|
+
path: ["layoutGridColumns"],
|
|
6918
|
+
message: "Layout-grid requires exactly one of ui.layoutGridColumns or ui.layoutGridColumnsFields.lg; do not set both"
|
|
6919
|
+
});
|
|
6920
|
+
}
|
|
6921
|
+
}).transform((input) => {
|
|
6922
|
+
const { layoutGridColumns, layoutGridColumnsFields, ...ui } = input;
|
|
6923
|
+
if (layoutGridColumns !== undefined) return {
|
|
6924
|
+
...ui,
|
|
6925
|
+
layoutGridColumns
|
|
6926
|
+
};
|
|
6927
|
+
if (layoutGridColumnsFields !== undefined) return {
|
|
6928
|
+
...ui,
|
|
6929
|
+
layoutGridColumnsFields
|
|
6930
|
+
};
|
|
6931
|
+
return ui;
|
|
6932
|
+
});
|
|
6593
6933
|
const baseFieldSchema = z.object({
|
|
6594
6934
|
id: z.string().min(1, "Field id is required"),
|
|
6595
6935
|
label: z.string().min(1, "Field label is required"),
|
|
@@ -6775,44 +7115,7 @@ const repeaterFieldSchema = baseFieldSchema.extend({
|
|
|
6775
7115
|
const hasSchema = data.schema !== undefined;
|
|
6776
7116
|
const hasPolymorphic = data.polymorphic === true && data.itemTypes !== undefined;
|
|
6777
7117
|
return hasSchema !== hasPolymorphic;
|
|
6778
|
-
}, { message: "Repeater must have either 'schema' (monomorphic) or 'polymorphic: true' with 'itemTypes' (polymorphic)" }).refine((data) => {
|
|
6779
|
-
if (data.ui?.repeaterPreset !== "layoutGrid") {
|
|
6780
|
-
return true;
|
|
6781
|
-
}
|
|
6782
|
-
const columnsFields = data.ui.layoutGridColumnsFields;
|
|
6783
|
-
return !!columnsFields?.lg;
|
|
6784
|
-
}, {
|
|
6785
|
-
message: "ui.layoutGridColumnsFields.lg is required when ui.repeaterPreset is 'layoutGrid'",
|
|
6786
|
-
path: [
|
|
6787
|
-
"ui",
|
|
6788
|
-
"layoutGridColumnsFields",
|
|
6789
|
-
"lg"
|
|
6790
|
-
]
|
|
6791
|
-
}).refine((data) => {
|
|
6792
|
-
if (data.ui?.repeaterPreset !== "layoutGrid") {
|
|
6793
|
-
return true;
|
|
6794
|
-
}
|
|
6795
|
-
const spanField = resolveRepeaterGridSpanFieldId({ id: typeof data.ui.layoutGridSpanField === "string" ? data.ui.layoutGridSpanField : undefined });
|
|
6796
|
-
const rowField = resolveRepeaterGridRowFieldId({ id: typeof data.ui.layoutGridRowField === "string" ? data.ui.layoutGridRowField : undefined });
|
|
6797
|
-
const columnField = resolveRepeaterGridColumnFieldId({ id: typeof data.ui.layoutGridColumnField === "string" ? data.ui.layoutGridColumnField : undefined });
|
|
6798
|
-
const requiredFieldIds = [
|
|
6799
|
-
spanField,
|
|
6800
|
-
rowField,
|
|
6801
|
-
columnField
|
|
6802
|
-
];
|
|
6803
|
-
if (data.polymorphic && data.itemTypes) {
|
|
6804
|
-
const itemTypes = Object.values(data.itemTypes);
|
|
6805
|
-
return itemTypes.every((itemType) => Array.isArray(itemType.fields) && requiredFieldIds.every((requiredId) => itemType.fields?.some((field) => field.id === requiredId)));
|
|
6806
|
-
}
|
|
6807
|
-
const schemaFields = data.schema?.fields;
|
|
6808
|
-
if (!schemaFields) {
|
|
6809
|
-
return true;
|
|
6810
|
-
}
|
|
6811
|
-
return requiredFieldIds.every((requiredId) => schemaFields.some((field) => field.id === requiredId));
|
|
6812
|
-
}, {
|
|
6813
|
-
message: `layoutGrid repeaters require span/row/column fields (defaults: '${DEFAULT_REPEATER_GRID_SPAN_FIELD_ID}', '${DEFAULT_REPEATER_GRID_ROW_FIELD_ID}', '${DEFAULT_REPEATER_GRID_COLUMN_FIELD_ID}') to exist in repeater item fields`,
|
|
6814
|
-
path: ["ui", "layoutGridRowField"]
|
|
6815
|
-
}).refine((data) => {
|
|
7118
|
+
}, { message: "Repeater must have either 'schema' (monomorphic) or 'polymorphic: true' with 'itemTypes' (polymorphic)" }).superRefine(validateLayoutGridConfiguration).refine((data) => {
|
|
6816
7119
|
const thumbnailAspectRatio = data.ui?.thumbnailAspectRatio;
|
|
6817
7120
|
if (!thumbnailAspectRatio) {
|
|
6818
7121
|
return true;
|
|
@@ -7144,6 +7447,187 @@ const manifestSchema = z.object({
|
|
|
7144
7447
|
icon: z.string().optional()
|
|
7145
7448
|
});
|
|
7146
7449
|
|
|
7450
|
+
//#endregion
|
|
7451
|
+
//#region ../blocks/src/lib/media.ts
|
|
7452
|
+
const MEDIA_TYPE_DISCRIMINANTS = mediaTypeDiscriminants;
|
|
7453
|
+
const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
7454
|
+
"document",
|
|
7455
|
+
"spreadsheet",
|
|
7456
|
+
"archive",
|
|
7457
|
+
"audio"
|
|
7458
|
+
];
|
|
7459
|
+
function isMediaTypeDiscriminant(value) {
|
|
7460
|
+
return typeof value === "string" && MEDIA_TYPE_DISCRIMINANTS.includes(value);
|
|
7461
|
+
}
|
|
7462
|
+
function mediaTypeDiscriminantFromMimeType(mimeType) {
|
|
7463
|
+
const classified = classifyKnownMimeType(mimeType);
|
|
7464
|
+
if (!classified.ok) return null;
|
|
7465
|
+
switch (classified.value.tag) {
|
|
7466
|
+
case "image":
|
|
7467
|
+
case "video":
|
|
7468
|
+
case "audio":
|
|
7469
|
+
case "document":
|
|
7470
|
+
case "spreadsheet":
|
|
7471
|
+
case "archive": return classified.value.tag;
|
|
7472
|
+
case "font": return null;
|
|
7473
|
+
}
|
|
7474
|
+
}
|
|
7475
|
+
|
|
7476
|
+
//#endregion
|
|
7477
|
+
//#region ../blocks/src/system/manifest/fieldValidation/writeCanonicalization.ts
|
|
7478
|
+
function allGroupChildPlans(plan) {
|
|
7479
|
+
return plan.childSelection.kind === "all" ? plan.childSelection.fields : plan.childSelection.tabs.flatMap((tab) => tab.fields);
|
|
7480
|
+
}
|
|
7481
|
+
function selectedGroupChildPlans(plan, value) {
|
|
7482
|
+
if (plan.childSelection.kind === "all") return plan.childSelection.fields;
|
|
7483
|
+
if (!isPlainObject$7(value)) return [];
|
|
7484
|
+
const selectedType = value[plan.childSelection.activeTabField];
|
|
7485
|
+
return plan.childSelection.tabs.find((tab) => tab.typeId === selectedType)?.fields ?? [];
|
|
7486
|
+
}
|
|
7487
|
+
function canonicalizeObjectForWrite(plans, value) {
|
|
7488
|
+
if (!isPlainObject$7(value)) return value;
|
|
7489
|
+
const canonical$1 = { ...value };
|
|
7490
|
+
for (const plan of plans) {
|
|
7491
|
+
if (!(plan.fieldId in canonical$1)) continue;
|
|
7492
|
+
canonical$1[plan.fieldId] = canonicalizeFieldValue(plan, canonical$1[plan.fieldId]);
|
|
7493
|
+
}
|
|
7494
|
+
return omitUndefined(canonical$1);
|
|
7495
|
+
}
|
|
7496
|
+
function canonicalizeFieldValue(plan, value) {
|
|
7497
|
+
switch (plan.kind) {
|
|
7498
|
+
case "media": return canonicalizeMedia(value);
|
|
7499
|
+
case "group": return plan.childSelection.kind === "discriminatedTabs" ? canonicalizeDiscriminatedGroup(plan, value) : canonicalizeObjectForWrite(plan.childSelection.fields, value);
|
|
7500
|
+
case "repeater": return canonicalizeRepeater(plan, value);
|
|
7501
|
+
case "string":
|
|
7502
|
+
case "number":
|
|
7503
|
+
case "boolean":
|
|
7504
|
+
case "richText":
|
|
7505
|
+
case "inlineText":
|
|
7506
|
+
case "link":
|
|
7507
|
+
case "select":
|
|
7508
|
+
case "passthrough": return value;
|
|
7509
|
+
}
|
|
7510
|
+
}
|
|
7511
|
+
function canonicalizeMedia(value) {
|
|
7512
|
+
if (!isPlainObject$7(value)) return value;
|
|
7513
|
+
const canonical$1 = { ...value };
|
|
7514
|
+
if (mediaIdentifierSchema.safeParse(canonical$1.identifier).success) {
|
|
7515
|
+
deleteEnvSpecificKeys(canonical$1);
|
|
7516
|
+
}
|
|
7517
|
+
return canonical$1;
|
|
7518
|
+
}
|
|
7519
|
+
function canonicalizeRepeater(plan, value) {
|
|
7520
|
+
if (!isUnknownArray$3(value)) return value;
|
|
7521
|
+
return value.map((item) => {
|
|
7522
|
+
if (!isPlainObject$7(item)) return item;
|
|
7523
|
+
const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
|
|
7524
|
+
return childPlans ? canonicalizeObjectForWrite(childPlans, item) : item;
|
|
7525
|
+
});
|
|
7526
|
+
}
|
|
7527
|
+
function canonicalizeDiscriminatedGroup(plan, value) {
|
|
7528
|
+
if (!isPlainObject$7(value) || plan.childSelection.kind !== "discriminatedTabs") {
|
|
7529
|
+
return value;
|
|
7530
|
+
}
|
|
7531
|
+
const selection = plan.childSelection;
|
|
7532
|
+
const selectedPlans = selectedGroupChildPlans(plan, value);
|
|
7533
|
+
const selectedIds = rootFieldIds(selectedPlans);
|
|
7534
|
+
const allChildIds = rootFieldIds(allGroupChildPlans(plan));
|
|
7535
|
+
const projected = Object.fromEntries(Object.entries(value).filter(([key]) => key === selection.activeTabField || selectedIds.has(key) || !allChildIds.has(key)));
|
|
7536
|
+
const canonical$1 = omitUndefined(canonicalizeObjectForWrite(selectedPlans, projected));
|
|
7537
|
+
if (plan.valueContract !== "boxBackground") return canonical$1;
|
|
7538
|
+
const parsed = boxBackgroundSchema.safeParse(canonical$1);
|
|
7539
|
+
return parsed.success ? parsed.data : canonical$1;
|
|
7540
|
+
}
|
|
7541
|
+
function rootFieldIds(plans) {
|
|
7542
|
+
return new Set(plans.map((child) => child.fieldId.split(".")[0] ?? child.fieldId));
|
|
7543
|
+
}
|
|
7544
|
+
function omitUndefined(value) {
|
|
7545
|
+
if (isUnknownArray$3(value)) return value.map(omitUndefined);
|
|
7546
|
+
if (!isPlainObject$7(value)) return value;
|
|
7547
|
+
return Object.fromEntries(Object.entries(value).filter(([, field]) => field !== undefined).map(([key, field]) => [key, omitUndefined(field)]));
|
|
7548
|
+
}
|
|
7549
|
+
function isPlainObject$7(value) {
|
|
7550
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7551
|
+
}
|
|
7552
|
+
function isUnknownArray$3(value) {
|
|
7553
|
+
return Array.isArray(value);
|
|
7554
|
+
}
|
|
7555
|
+
|
|
7556
|
+
//#endregion
|
|
7557
|
+
//#region ../blocks/src/system/manifest/fieldValidation/layoutGrid.ts
|
|
7558
|
+
function layoutGridRecord(value) {
|
|
7559
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7560
|
+
}
|
|
7561
|
+
function resolveLayoutGridItemPlans(plan, item) {
|
|
7562
|
+
return plan.repeatedItemVariants?.find((variant) => variant.typeId === item._type)?.fields ?? plan.repeatedItemPlan ?? [];
|
|
7563
|
+
}
|
|
7564
|
+
function layoutGridCoordinateFieldIds(plan) {
|
|
7565
|
+
const grid$5 = plan.layoutGrid;
|
|
7566
|
+
return grid$5 ? [
|
|
7567
|
+
grid$5.spanField,
|
|
7568
|
+
grid$5.rowField,
|
|
7569
|
+
grid$5.columnField
|
|
7570
|
+
] : [];
|
|
7571
|
+
}
|
|
7572
|
+
function acceptedSpans(plans, spanField) {
|
|
7573
|
+
const span = plans.find((field) => field.fieldId === spanField);
|
|
7574
|
+
if (span?.kind !== "select") return undefined;
|
|
7575
|
+
const constraint = span.constraints.find((entry) => entry.kind === "selectOption");
|
|
7576
|
+
return constraint?.kind === "selectOption" && constraint.source.kind === "static" ? constraint.source.values.map(Number) : [];
|
|
7577
|
+
}
|
|
7578
|
+
function gridIssue(plan, path$3, message) {
|
|
7579
|
+
return {
|
|
7580
|
+
kind: "invalidLayoutGrid",
|
|
7581
|
+
fieldId: plan.fieldId,
|
|
7582
|
+
label: plan.label,
|
|
7583
|
+
path: path$3,
|
|
7584
|
+
message
|
|
7585
|
+
};
|
|
7586
|
+
}
|
|
7587
|
+
function buildLayoutGridForPlan(plan, value, values, ids) {
|
|
7588
|
+
const grid$5 = plan.layoutGrid;
|
|
7589
|
+
if (!grid$5) return null;
|
|
7590
|
+
const columns = grid$5.columns ?? (grid$5.columnsFields ? resolveRepeaterGridColumnsForBreakpoint(values, grid$5.columnsFields, "lg") : 1);
|
|
7591
|
+
const items = value.flatMap((item, index) => {
|
|
7592
|
+
const row$1 = layoutGridRecord(item);
|
|
7593
|
+
return row$1 ? [{
|
|
7594
|
+
id: ids?.[index] ?? String(index),
|
|
7595
|
+
startNewRow: grid$5.startNewRowField ? row$1[grid$5.startNewRowField] === true : false,
|
|
7596
|
+
span: parseRepeaterGridInteger(row$1[grid$5.spanField]) ?? NaN,
|
|
7597
|
+
row: parseRepeaterGridInteger(row$1[grid$5.rowField]) ?? NaN,
|
|
7598
|
+
colStart: parseRepeaterGridInteger(row$1[grid$5.columnField]) ?? NaN,
|
|
7599
|
+
acceptedSpans: acceptedSpans(resolveLayoutGridItemPlans(plan, row$1), grid$5.spanField)
|
|
7600
|
+
}] : [];
|
|
7601
|
+
});
|
|
7602
|
+
return buildRepeaterGridLayout({
|
|
7603
|
+
items,
|
|
7604
|
+
columns,
|
|
7605
|
+
maxRows: grid$5.maxRows,
|
|
7606
|
+
placementPolicy: grid$5.columns === undefined ? "free" : "flow"
|
|
7607
|
+
});
|
|
7608
|
+
}
|
|
7609
|
+
function validateGrid(plan, value, values, path$3) {
|
|
7610
|
+
const layout = buildLayoutGridForPlan(plan, value, values);
|
|
7611
|
+
if (!layout) return [];
|
|
7612
|
+
if (layout.hasCollisions || layout.overCapacity) return [gridIssue(plan, path$3, "Some items overlap or do not fit in this layout. Adjust their widths or positions before saving.")];
|
|
7613
|
+
return layout.hasInvalidItems ? [gridIssue(plan, path$3, "Choose an available width and a valid position for each item before saving.")] : [];
|
|
7614
|
+
}
|
|
7615
|
+
/** Root values resolve the same column bindings as the editor; recurse without changing any content. */
|
|
7616
|
+
function validateLayoutGridPlans(plans, value, rootValues = layoutGridRecord(value) ?? {}, parent = []) {
|
|
7617
|
+
const values = layoutGridRecord(value);
|
|
7618
|
+
if (!values) return [];
|
|
7619
|
+
return plans.flatMap((plan) => {
|
|
7620
|
+
const fieldValue = values[plan.fieldId];
|
|
7621
|
+
const path$3 = [...parent, plan.fieldId];
|
|
7622
|
+
if (plan.kind === "group") return validateLayoutGridPlans(allGroupChildPlans(plan), fieldValue, rootValues, path$3);
|
|
7623
|
+
if (plan.kind !== "repeater" || !Array.isArray(fieldValue)) return [];
|
|
7624
|
+
return [...validateGrid(plan, fieldValue, rootValues, path$3), ...fieldValue.flatMap((item, index) => {
|
|
7625
|
+
const row$1 = layoutGridRecord(item);
|
|
7626
|
+
return row$1 ? validateLayoutGridPlans(resolveLayoutGridItemPlans(plan, row$1), row$1, rootValues, [...path$3, index]) : [];
|
|
7627
|
+
})];
|
|
7628
|
+
});
|
|
7629
|
+
}
|
|
7630
|
+
|
|
7147
7631
|
//#endregion
|
|
7148
7632
|
//#region ../blocks/src/system/inlineText.ts
|
|
7149
7633
|
const inlineTextAccentTones = [
|
|
@@ -8602,112 +9086,6 @@ function isGeneratedBlockIconStale(value, currentStyleGuideVersionId) {
|
|
|
8602
9086
|
return getGeneratedBlockIconStyleState(value, currentStyleGuideVersionId).kind === "stale";
|
|
8603
9087
|
}
|
|
8604
9088
|
|
|
8605
|
-
//#endregion
|
|
8606
|
-
//#region ../blocks/src/lib/media.ts
|
|
8607
|
-
const MEDIA_TYPE_DISCRIMINANTS = mediaTypeDiscriminants;
|
|
8608
|
-
const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
8609
|
-
"document",
|
|
8610
|
-
"spreadsheet",
|
|
8611
|
-
"archive",
|
|
8612
|
-
"audio"
|
|
8613
|
-
];
|
|
8614
|
-
function isMediaTypeDiscriminant(value) {
|
|
8615
|
-
return typeof value === "string" && MEDIA_TYPE_DISCRIMINANTS.includes(value);
|
|
8616
|
-
}
|
|
8617
|
-
function mediaTypeDiscriminantFromMimeType(mimeType) {
|
|
8618
|
-
const classified = classifyKnownMimeType(mimeType);
|
|
8619
|
-
if (!classified.ok) return null;
|
|
8620
|
-
switch (classified.value.tag) {
|
|
8621
|
-
case "image":
|
|
8622
|
-
case "video":
|
|
8623
|
-
case "audio":
|
|
8624
|
-
case "document":
|
|
8625
|
-
case "spreadsheet":
|
|
8626
|
-
case "archive": return classified.value.tag;
|
|
8627
|
-
case "font": return null;
|
|
8628
|
-
}
|
|
8629
|
-
}
|
|
8630
|
-
|
|
8631
|
-
//#endregion
|
|
8632
|
-
//#region ../blocks/src/system/manifest/fieldValidation/writeCanonicalization.ts
|
|
8633
|
-
function allGroupChildPlans(plan) {
|
|
8634
|
-
return plan.childSelection.kind === "all" ? plan.childSelection.fields : plan.childSelection.tabs.flatMap((tab) => tab.fields);
|
|
8635
|
-
}
|
|
8636
|
-
function selectedGroupChildPlans(plan, value) {
|
|
8637
|
-
if (plan.childSelection.kind === "all") return plan.childSelection.fields;
|
|
8638
|
-
if (!isPlainObject$7(value)) return [];
|
|
8639
|
-
const selectedType = value[plan.childSelection.activeTabField];
|
|
8640
|
-
return plan.childSelection.tabs.find((tab) => tab.typeId === selectedType)?.fields ?? [];
|
|
8641
|
-
}
|
|
8642
|
-
function canonicalizeObjectForWrite(plans, value) {
|
|
8643
|
-
if (!isPlainObject$7(value)) return value;
|
|
8644
|
-
const canonical$1 = { ...value };
|
|
8645
|
-
for (const plan of plans) {
|
|
8646
|
-
if (!(plan.fieldId in canonical$1)) continue;
|
|
8647
|
-
canonical$1[plan.fieldId] = canonicalizeFieldValue(plan, canonical$1[plan.fieldId]);
|
|
8648
|
-
}
|
|
8649
|
-
return omitUndefined(canonical$1);
|
|
8650
|
-
}
|
|
8651
|
-
function canonicalizeFieldValue(plan, value) {
|
|
8652
|
-
switch (plan.kind) {
|
|
8653
|
-
case "media": return canonicalizeMedia(value);
|
|
8654
|
-
case "group": return plan.childSelection.kind === "discriminatedTabs" ? canonicalizeDiscriminatedGroup(plan, value) : canonicalizeObjectForWrite(plan.childSelection.fields, value);
|
|
8655
|
-
case "repeater": return canonicalizeRepeater(plan, value);
|
|
8656
|
-
case "string":
|
|
8657
|
-
case "number":
|
|
8658
|
-
case "boolean":
|
|
8659
|
-
case "richText":
|
|
8660
|
-
case "inlineText":
|
|
8661
|
-
case "link":
|
|
8662
|
-
case "select":
|
|
8663
|
-
case "passthrough": return value;
|
|
8664
|
-
}
|
|
8665
|
-
}
|
|
8666
|
-
function canonicalizeMedia(value) {
|
|
8667
|
-
if (!isPlainObject$7(value)) return value;
|
|
8668
|
-
const canonical$1 = { ...value };
|
|
8669
|
-
if (mediaIdentifierSchema.safeParse(canonical$1.identifier).success) {
|
|
8670
|
-
deleteEnvSpecificKeys(canonical$1);
|
|
8671
|
-
}
|
|
8672
|
-
return canonical$1;
|
|
8673
|
-
}
|
|
8674
|
-
function canonicalizeRepeater(plan, value) {
|
|
8675
|
-
if (!isUnknownArray$3(value)) return value;
|
|
8676
|
-
return value.map((item) => {
|
|
8677
|
-
if (!isPlainObject$7(item)) return item;
|
|
8678
|
-
const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
|
|
8679
|
-
return childPlans ? canonicalizeObjectForWrite(childPlans, item) : item;
|
|
8680
|
-
});
|
|
8681
|
-
}
|
|
8682
|
-
function canonicalizeDiscriminatedGroup(plan, value) {
|
|
8683
|
-
if (!isPlainObject$7(value) || plan.childSelection.kind !== "discriminatedTabs") {
|
|
8684
|
-
return value;
|
|
8685
|
-
}
|
|
8686
|
-
const selection = plan.childSelection;
|
|
8687
|
-
const selectedPlans = selectedGroupChildPlans(plan, value);
|
|
8688
|
-
const selectedIds = rootFieldIds(selectedPlans);
|
|
8689
|
-
const allChildIds = rootFieldIds(allGroupChildPlans(plan));
|
|
8690
|
-
const projected = Object.fromEntries(Object.entries(value).filter(([key]) => key === selection.activeTabField || selectedIds.has(key) || !allChildIds.has(key)));
|
|
8691
|
-
const canonical$1 = omitUndefined(canonicalizeObjectForWrite(selectedPlans, projected));
|
|
8692
|
-
if (plan.valueContract !== "boxBackground") return canonical$1;
|
|
8693
|
-
const parsed = boxBackgroundSchema.safeParse(canonical$1);
|
|
8694
|
-
return parsed.success ? parsed.data : canonical$1;
|
|
8695
|
-
}
|
|
8696
|
-
function rootFieldIds(plans) {
|
|
8697
|
-
return new Set(plans.map((child) => child.fieldId.split(".")[0] ?? child.fieldId));
|
|
8698
|
-
}
|
|
8699
|
-
function omitUndefined(value) {
|
|
8700
|
-
if (isUnknownArray$3(value)) return value.map(omitUndefined);
|
|
8701
|
-
if (!isPlainObject$7(value)) return value;
|
|
8702
|
-
return Object.fromEntries(Object.entries(value).filter(([, field]) => field !== undefined).map(([key, field]) => [key, omitUndefined(field)]));
|
|
8703
|
-
}
|
|
8704
|
-
function isPlainObject$7(value) {
|
|
8705
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8706
|
-
}
|
|
8707
|
-
function isUnknownArray$3(value) {
|
|
8708
|
-
return Array.isArray(value);
|
|
8709
|
-
}
|
|
8710
|
-
|
|
8711
9089
|
//#endregion
|
|
8712
9090
|
//#region ../blocks/src/system/fields/backgroundContentAudit.ts
|
|
8713
9091
|
const BACKGROUND_SLOTS = [
|
|
@@ -8773,7 +9151,7 @@ function validationContext(options = {}) {
|
|
|
8773
9151
|
const isDraft = options.mode === "draft";
|
|
8774
9152
|
return {
|
|
8775
9153
|
allowNull: options.allowNull ?? true,
|
|
8776
|
-
allowIncomplete: isDraft || (options.allowIncomplete ?? false),
|
|
9154
|
+
allowIncomplete: options.mode === "storable" ? false : isDraft || (options.allowIncomplete ?? false),
|
|
8777
9155
|
mode: options.mode ?? "strict"
|
|
8778
9156
|
};
|
|
8779
9157
|
}
|
|
@@ -8797,18 +9175,20 @@ function parseFieldPathKey(key) {
|
|
|
8797
9175
|
return Number.isInteger(numeric) && String(numeric) === segment ? numeric : segment;
|
|
8798
9176
|
});
|
|
8799
9177
|
}
|
|
9178
|
+
const simpleIssueMessages = {
|
|
9179
|
+
required: "This field is required",
|
|
9180
|
+
invalidEmail: "Enter a valid email address",
|
|
9181
|
+
invalidPhone: "Enter a valid phone number",
|
|
9182
|
+
invalidPattern: "Check the format and try again",
|
|
9183
|
+
invalidUrl: "Enter a valid web address",
|
|
9184
|
+
invalidDate: "Choose a valid date",
|
|
9185
|
+
invalidTime: "Choose a valid time",
|
|
9186
|
+
invalidDateTime: "Choose a valid date and time"
|
|
9187
|
+
};
|
|
8800
9188
|
function fieldIssueToMessage(issue$1) {
|
|
8801
9189
|
switch (issue$1.kind) {
|
|
8802
|
-
case "required": return "This field is required";
|
|
8803
9190
|
case "wrongType": return `${issue$1.label} needs ${issue$1.expected}`;
|
|
8804
9191
|
case "tooLong": return `Use ${issue$1.maximum} characters or fewer`;
|
|
8805
|
-
case "invalidEmail": return "Enter a valid email address";
|
|
8806
|
-
case "invalidPhone": return "Enter a valid phone number";
|
|
8807
|
-
case "invalidPattern": return "Check the format and try again";
|
|
8808
|
-
case "invalidUrl": return "Enter a valid web address";
|
|
8809
|
-
case "invalidDate": return "Choose a valid date";
|
|
8810
|
-
case "invalidTime": return "Choose a valid time";
|
|
8811
|
-
case "invalidDateTime": return "Choose a valid date and time";
|
|
8812
9192
|
case "invalidNumber": return `${issue$1.label} needs a number`;
|
|
8813
9193
|
case "tooSmall": return `${issue$1.label} must be ${issue$1.minimum} or more`;
|
|
8814
9194
|
case "tooLarge": return `${issue$1.label} must be ${issue$1.maximum} or less`;
|
|
@@ -8821,7 +9201,16 @@ function fieldIssueToMessage(issue$1) {
|
|
|
8821
9201
|
case "invalidMedia": return `${issue$1.label} must be a media object with an identifier`;
|
|
8822
9202
|
case "invalidBoxBackground": return `${issue$1.label} must use a valid background type and matching fields`;
|
|
8823
9203
|
case "invalidLink": return `${issue$1.label} must be a valid link`;
|
|
9204
|
+
case "invalidLayoutGrid": return issue$1.message;
|
|
8824
9205
|
case "invalidReference": return `${issue$1.label} must reference a valid item`;
|
|
9206
|
+
case "required":
|
|
9207
|
+
case "invalidDate":
|
|
9208
|
+
case "invalidDateTime":
|
|
9209
|
+
case "invalidEmail":
|
|
9210
|
+
case "invalidPattern":
|
|
9211
|
+
case "invalidPhone":
|
|
9212
|
+
case "invalidTime":
|
|
9213
|
+
case "invalidUrl": return simpleIssueMessages[issue$1.kind];
|
|
8825
9214
|
default: return assertNever$12(issue$1);
|
|
8826
9215
|
}
|
|
8827
9216
|
}
|
|
@@ -8936,11 +9325,7 @@ function deriveFieldValidationPlan(field, path$3 = [field.id]) {
|
|
|
8936
9325
|
}
|
|
8937
9326
|
case "link": return makePlan("link", "object", field, path$3, required, commonConstraints(required, { kind: "linkObject" }));
|
|
8938
9327
|
case "boolean": return makePlan("boolean", "boolean", field, path$3, required, requiredConstraints(required));
|
|
8939
|
-
case "repeater": return
|
|
8940
|
-
...makePlan("repeater", "array", field, path$3, required, commonConstraints(required, { kind: "arrayType" })),
|
|
8941
|
-
...field.polymorphic && field.itemTypes ? { repeatedItemVariants: deriveRepeatedItemVariants(field, [...path$3, 0]) } : { repeatedItemPlan: deriveNestedFieldPlans(getRepeaterFields(field), [...path$3, 0]) },
|
|
8942
|
-
constraints: withRepeaterItemConstraints(field, commonConstraints(required, { kind: "arrayType" }))
|
|
8943
|
-
};
|
|
9328
|
+
case "repeater": return deriveRepeaterFieldValidationPlan(field, path$3);
|
|
8944
9329
|
case "group":
|
|
8945
9330
|
case "modal": return {
|
|
8946
9331
|
...makePlan("group", "object", field, path$3, required, requiredConstraints(required)),
|
|
@@ -8957,6 +9342,27 @@ function deriveFieldValidationPlan(field, path$3 = [field.id]) {
|
|
|
8957
9342
|
default: return assertNever$12(field);
|
|
8958
9343
|
}
|
|
8959
9344
|
}
|
|
9345
|
+
function deriveRepeaterFieldValidationPlan(field, path$3) {
|
|
9346
|
+
const required = Boolean(field.required);
|
|
9347
|
+
const constraints = commonConstraints(required, { kind: "arrayType" });
|
|
9348
|
+
return {
|
|
9349
|
+
...makePlan("repeater", "array", field, path$3, required, constraints),
|
|
9350
|
+
...field.ui?.repeaterPreset === "layoutGrid" ? { layoutGrid: {
|
|
9351
|
+
startNewRowField: field.ui.layoutGridStartNewRowField,
|
|
9352
|
+
columns: field.ui.layoutGridColumns,
|
|
9353
|
+
columnsFields: field.ui.layoutGridColumnsFields,
|
|
9354
|
+
spanField: resolveRepeaterGridSpanFieldId({ id: field.ui.layoutGridSpanField }),
|
|
9355
|
+
rowField: resolveRepeaterGridRowFieldId({ id: field.ui.layoutGridRowField }),
|
|
9356
|
+
columnField: resolveRepeaterGridColumnFieldId({ id: field.ui.layoutGridColumnField }),
|
|
9357
|
+
maxRows: field.ui.layoutGridMaxRows
|
|
9358
|
+
} } : {},
|
|
9359
|
+
...field.polymorphic && field.itemTypes ? { repeatedItemVariants: deriveRepeatedItemVariants(field, [...path$3, 0]) } : {
|
|
9360
|
+
repeatedItemPlan: deriveNestedFieldPlans(getRepeaterFields(field), [...path$3, 0]),
|
|
9361
|
+
flattenedGroupIds: getFlattenedGroupIds(field.schema?.fields ?? [])
|
|
9362
|
+
},
|
|
9363
|
+
constraints: withRepeaterItemConstraints(field, constraints)
|
|
9364
|
+
};
|
|
9365
|
+
}
|
|
8960
9366
|
function deriveFieldValidationPlans(fields$1, parentPath = []) {
|
|
8961
9367
|
return fields$1.map((field) => deriveFieldValidationPlan(field, [...parentPath, field.id]));
|
|
8962
9368
|
}
|
|
@@ -9006,7 +9412,8 @@ function withRepeaterItemConstraints(field, constraints) {
|
|
|
9006
9412
|
function deriveRepeatedItemVariants(field, parentPath) {
|
|
9007
9413
|
return Object.entries(field.itemTypes ?? {}).map(([typeId, itemType]) => ({
|
|
9008
9414
|
typeId,
|
|
9009
|
-
fields: deriveNestedFieldPlans(getFlattenedRepeaterFields(itemType.fields), parentPath)
|
|
9415
|
+
fields: deriveNestedFieldPlans(getFlattenedRepeaterFields(itemType.fields), parentPath),
|
|
9416
|
+
flattenedGroupIds: getFlattenedGroupIds(itemType.fields)
|
|
9010
9417
|
}));
|
|
9011
9418
|
}
|
|
9012
9419
|
function deriveNestedFieldPlans(fields$1, parentPath) {
|
|
@@ -9016,6 +9423,11 @@ function getRepeaterFields(field) {
|
|
|
9016
9423
|
const fields$1 = field.polymorphic && field.itemTypes ? Object.values(field.itemTypes).flatMap((itemType) => itemType.fields) : field.schema?.fields ?? [];
|
|
9017
9424
|
return getFlattenedRepeaterFields(fields$1);
|
|
9018
9425
|
}
|
|
9426
|
+
/** Only group ids absent from the actual data fields are forbidden containers. */
|
|
9427
|
+
function getFlattenedGroupIds(fields$1) {
|
|
9428
|
+
const dataIds = new Set(getFlattenedRepeaterFields(fields$1).map((field) => field.id));
|
|
9429
|
+
return fields$1.flatMap((field) => field.type === "group" && field.ui?.flattenInRepeater && !dataIds.has(field.id) ? [field.id] : []);
|
|
9430
|
+
}
|
|
9019
9431
|
function getFlattenedRepeaterFields(fields$1) {
|
|
9020
9432
|
return fields$1.flatMap((child) => {
|
|
9021
9433
|
if (child.type === "group" && child.ui?.flattenInRepeater) {
|
|
@@ -9096,6 +9508,32 @@ function fieldPlanToNativeInputProps(plan) {
|
|
|
9096
9508
|
function normalizeFieldInput(plan, value, options = {}) {
|
|
9097
9509
|
return normalizeFieldValue(plan, value, validationContext(options));
|
|
9098
9510
|
}
|
|
9511
|
+
/** Drop obsolete presentation containers only when reading persisted content.
|
|
9512
|
+
* Flat data remains authoritative; unknown variants and legitimate groups survive.
|
|
9513
|
+
*/
|
|
9514
|
+
function normalizeLegacyStoredGroupContainers(plans, content) {
|
|
9515
|
+
if (!isPlainObject$6(content)) return content;
|
|
9516
|
+
const planMap = new Map(plans.map((plan) => [plan.fieldId, plan]));
|
|
9517
|
+
const entries = Object.entries(content).map(([key, value]) => {
|
|
9518
|
+
const plan = planMap.get(key);
|
|
9519
|
+
return [key, plan ? normalizeLegacyStoredField(plan, value) : value];
|
|
9520
|
+
});
|
|
9521
|
+
return entries.every(([key, value]) => value === content[key]) ? content : Object.fromEntries(entries);
|
|
9522
|
+
}
|
|
9523
|
+
function normalizeLegacyStoredField(plan, value) {
|
|
9524
|
+
if (plan.kind === "group") {
|
|
9525
|
+
return normalizeLegacyStoredGroupContainers(selectedGroupChildPlans(plan, value), value);
|
|
9526
|
+
}
|
|
9527
|
+
if (plan.kind !== "repeater" || !isUnknownArray$2(value)) return value;
|
|
9528
|
+
const items = value.map((item) => {
|
|
9529
|
+
if (!isPlainObject$6(item)) return item;
|
|
9530
|
+
const selection = selectRepeaterItemPlan(plan, item);
|
|
9531
|
+
if (selection.kind !== "fields") return item;
|
|
9532
|
+
const retained = selection.flattenedGroupIds.some((key) => Object.prototype.hasOwnProperty.call(item, key)) ? Object.fromEntries(Object.entries(item).filter(([key]) => !selection.flattenedGroupIds.includes(key))) : item;
|
|
9533
|
+
return normalizeLegacyStoredGroupContainers(selection.fields, retained);
|
|
9534
|
+
});
|
|
9535
|
+
return items.every((item, index) => item === value[index]) ? value : items;
|
|
9536
|
+
}
|
|
9099
9537
|
function normalizeStoredContentValues(plans, content, options = {}) {
|
|
9100
9538
|
if (!content || typeof content !== "object" || Array.isArray(content)) {
|
|
9101
9539
|
return {};
|
|
@@ -9158,7 +9596,8 @@ function normalizeStoredRepeaterItems(plan, value, ctx) {
|
|
|
9158
9596
|
return item;
|
|
9159
9597
|
}
|
|
9160
9598
|
const itemRecord = item;
|
|
9161
|
-
const
|
|
9599
|
+
const selection = selectRepeaterItemPlan(plan, itemRecord);
|
|
9600
|
+
const fields$1 = selection.kind === "fields" ? selection.fields : undefined;
|
|
9162
9601
|
if (!fields$1) {
|
|
9163
9602
|
return item;
|
|
9164
9603
|
}
|
|
@@ -9215,7 +9654,8 @@ function normalizeRepeaterItems(plan, value, ctx) {
|
|
|
9215
9654
|
return value.map((item) => {
|
|
9216
9655
|
if (!item || typeof item !== "object" || Array.isArray(item)) return item;
|
|
9217
9656
|
const itemRecord = item;
|
|
9218
|
-
const
|
|
9657
|
+
const selection = selectRepeaterItemPlan(plan, itemRecord);
|
|
9658
|
+
const fields$1 = selection.kind === "fields" ? selection.fields : undefined;
|
|
9219
9659
|
if (!fields$1) return item;
|
|
9220
9660
|
return normalizeObjectChildren(fields$1, itemRecord, ctx);
|
|
9221
9661
|
});
|
|
@@ -9230,13 +9670,13 @@ function acceptsOptionalBlankAsMissing(plan, value) {
|
|
|
9230
9670
|
return plan.constraints.some((constraint) => constraint.kind === "urlFormat" || constraint.kind === "slugFormat" || constraint.kind === "emailFormat" || constraint.kind === "phoneFormat" || constraint.kind === "patternFormat");
|
|
9231
9671
|
}
|
|
9232
9672
|
function validateNormalizedFieldValue(plan, value, ctx) {
|
|
9233
|
-
if (value === null && (ctx
|
|
9234
|
-
if (isMissingForPlan(plan, value)) {
|
|
9673
|
+
if (value === null && acceptsNullValue(plan, ctx)) return [];
|
|
9674
|
+
if (isMissingForPlan(plan, value, ctx.mode)) {
|
|
9235
9675
|
return shouldRequireValue(plan, value, ctx) ? [requiredIssue(plan, value)] : [];
|
|
9236
9676
|
}
|
|
9237
9677
|
switch (plan.kind) {
|
|
9238
9678
|
case "string": return validateStringPlan(plan, value, ctx);
|
|
9239
|
-
case "number": return validateNumberPlan(plan, value);
|
|
9679
|
+
case "number": return validateNumberPlan(plan, value, ctx);
|
|
9240
9680
|
case "boolean": return typeof value === "boolean" ? [] : [issue(plan, "wrongType", { expected: "a true/false value" })];
|
|
9241
9681
|
case "select": return validateSelectPlan(plan, value);
|
|
9242
9682
|
case "richText": return isValidRichTextDoc(value) ? [] : [issue(plan, "invalidRichText")];
|
|
@@ -9260,14 +9700,18 @@ function validateMediaPlan(plan, value, ctx) {
|
|
|
9260
9700
|
}
|
|
9261
9701
|
function shouldRequireValue(plan, value, ctx) {
|
|
9262
9702
|
if (!plan.required || ctx.allowIncomplete) return false;
|
|
9263
|
-
if (value === null && ctx.allowNull) return false;
|
|
9703
|
+
if (value === null && ctx.allowNull && ctx.mode !== "storable") return false;
|
|
9264
9704
|
return true;
|
|
9265
9705
|
}
|
|
9706
|
+
function acceptsNullValue(plan, ctx) {
|
|
9707
|
+
return ctx.mode === "storable" ? !plan.required : ctx.allowNull || acceptsOptionalNullValue(plan);
|
|
9708
|
+
}
|
|
9266
9709
|
function acceptsOptionalNullValue(plan) {
|
|
9267
9710
|
return !plan.required && (plan.kind === "media" || plan.kind === "number");
|
|
9268
9711
|
}
|
|
9269
|
-
function isMissingForPlan(plan, value) {
|
|
9712
|
+
function isMissingForPlan(plan, value, mode) {
|
|
9270
9713
|
if (value === undefined) return true;
|
|
9714
|
+
if (mode === "storable") return value === null || value === "";
|
|
9271
9715
|
if (value === null) return plan.required;
|
|
9272
9716
|
if (typeof value === "string" && value.trim() === "") return true;
|
|
9273
9717
|
if (Array.isArray(value) && value.length === 0) return true;
|
|
@@ -9286,7 +9730,7 @@ function validateStringConstraint(plan, constraint, value, ctx) {
|
|
|
9286
9730
|
return isValidIconPickerValue(value) ? [] : [issue(plan, "wrongType", { expected: "text or icon" })];
|
|
9287
9731
|
}
|
|
9288
9732
|
if (typeof value !== "string") return [issue(plan, "wrongType", { expected: "text" })];
|
|
9289
|
-
if (constraint.kind === "textType" || constraint.kind === "referenceText") return [];
|
|
9733
|
+
if (constraint.kind === "textType" || constraint.kind === "referenceText" || ctx.mode === "storable") return [];
|
|
9290
9734
|
return constraint.kind === "maxLength" ? validateAuthoredTextLength(plan, value, constraint.maximum, ctx) : validateStringFormat(plan, constraint, value);
|
|
9291
9735
|
}
|
|
9292
9736
|
const SIMPLE_STRING_FORMATS = {
|
|
@@ -9328,7 +9772,7 @@ function validateStringFormat(plan, constraint, value) {
|
|
|
9328
9772
|
}
|
|
9329
9773
|
/** Authoring limits govern stored block copy; resolved entry text has its own owner. */
|
|
9330
9774
|
function validateAuthoredTextLength(plan, text$1, maximum, ctx) {
|
|
9331
|
-
return ctx.mode !== "render" && maximum !== undefined && text$1.length > maximum ? [issue(plan, "tooLong", { maximum })] : [];
|
|
9775
|
+
return ctx.mode !== "render" && ctx.mode !== "storable" && maximum !== undefined && text$1.length > maximum ? [issue(plan, "tooLong", { maximum })] : [];
|
|
9332
9776
|
}
|
|
9333
9777
|
function isValidIconPickerValue(value) {
|
|
9334
9778
|
if (typeof value === "string") return true;
|
|
@@ -9336,8 +9780,9 @@ function isValidIconPickerValue(value) {
|
|
|
9336
9780
|
if (value.kind === "none") return true;
|
|
9337
9781
|
return parseBlockIconValue(value).kind !== "none";
|
|
9338
9782
|
}
|
|
9339
|
-
function validateNumberPlan(plan, value) {
|
|
9783
|
+
function validateNumberPlan(plan, value, ctx) {
|
|
9340
9784
|
if (!isValidNumber(value)) return [issue(plan, "invalidNumber")];
|
|
9785
|
+
if (ctx.mode === "storable") return [];
|
|
9341
9786
|
return plan.constraints.flatMap((constraint) => validateNumberConstraint(plan, constraint, Number(value)));
|
|
9342
9787
|
}
|
|
9343
9788
|
function validateNumberConstraint(plan, constraint, value) {
|
|
@@ -9356,7 +9801,7 @@ function validateSelectPlan(plan, value) {
|
|
|
9356
9801
|
}
|
|
9357
9802
|
function validateRepeaterPlan(plan, value, ctx) {
|
|
9358
9803
|
if (!Array.isArray(value)) return [issue(plan, "wrongType", { expected: "a list" })];
|
|
9359
|
-
const constraintIssues = plan.constraints.flatMap((constraint) => {
|
|
9804
|
+
const constraintIssues = ctx.mode === "storable" ? [] : plan.constraints.flatMap((constraint) => {
|
|
9360
9805
|
switch (constraint.kind) {
|
|
9361
9806
|
case "required":
|
|
9362
9807
|
case "arrayType": return [];
|
|
@@ -9373,6 +9818,22 @@ function validateRepeaterPlan(plan, value, ctx) {
|
|
|
9373
9818
|
});
|
|
9374
9819
|
return [...constraintIssues, ...value.flatMap((item, index) => validateRepeaterItem(plan, item, index, ctx))];
|
|
9375
9820
|
}
|
|
9821
|
+
/** Selects both the value fields and forbidden presentation containers together. */
|
|
9822
|
+
function selectRepeaterItemPlan(plan, item) {
|
|
9823
|
+
if (plan.repeatedItemVariants) {
|
|
9824
|
+
const variant = plan.repeatedItemVariants.find((candidate) => candidate.typeId === item._type);
|
|
9825
|
+
return variant ? {
|
|
9826
|
+
kind: "fields",
|
|
9827
|
+
fields: variant.fields,
|
|
9828
|
+
flattenedGroupIds: variant.flattenedGroupIds ?? []
|
|
9829
|
+
} : { kind: "invalidType" };
|
|
9830
|
+
}
|
|
9831
|
+
return plan.repeatedItemPlan ? {
|
|
9832
|
+
kind: "fields",
|
|
9833
|
+
fields: plan.repeatedItemPlan,
|
|
9834
|
+
flattenedGroupIds: plan.flattenedGroupIds ?? []
|
|
9835
|
+
} : { kind: "untyped" };
|
|
9836
|
+
}
|
|
9376
9837
|
function validateRepeaterItem(plan, item, index, ctx) {
|
|
9377
9838
|
if (!isPlainObject$6(item)) {
|
|
9378
9839
|
return [{
|
|
@@ -9383,9 +9844,8 @@ function validateRepeaterItem(plan, item, index, ctx) {
|
|
|
9383
9844
|
expected: "an object"
|
|
9384
9845
|
}];
|
|
9385
9846
|
}
|
|
9386
|
-
const
|
|
9387
|
-
|
|
9388
|
-
if (plan.repeatedItemVariants && !variant) {
|
|
9847
|
+
const selection = selectRepeaterItemPlan(plan, item);
|
|
9848
|
+
if (selection.kind === "invalidType") {
|
|
9389
9849
|
return [{
|
|
9390
9850
|
kind: "invalidOption",
|
|
9391
9851
|
path: [
|
|
@@ -9397,12 +9857,27 @@ function validateRepeaterItem(plan, item, index, ctx) {
|
|
|
9397
9857
|
label: `${plan.label} item type`
|
|
9398
9858
|
}];
|
|
9399
9859
|
}
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
return fields
|
|
9860
|
+
if (selection.kind === "untyped") return [];
|
|
9861
|
+
const containerIssues = validateFlattenedGroupContainers(selection.flattenedGroupIds, item, plan, index, ctx);
|
|
9862
|
+
return [...containerIssues, ...selection.fields.flatMap((childPlan) => {
|
|
9863
|
+
if (ctx.layoutGridCoordinates === "projected" && layoutGridCoordinateFieldIds(plan).includes(childPlan.fieldId)) return [];
|
|
9403
9864
|
const indexedPlan = materializeRepeaterItemPlan(childPlan, plan.path, index);
|
|
9404
9865
|
return validateNormalizedFieldValue(indexedPlan, item[childPlan.fieldId], ctx);
|
|
9405
|
-
});
|
|
9866
|
+
})];
|
|
9867
|
+
}
|
|
9868
|
+
function validateFlattenedGroupContainers(groupIds, item, plan, index, ctx) {
|
|
9869
|
+
if (ctx.mode === "render") return [];
|
|
9870
|
+
return groupIds.flatMap((fieldId) => Object.prototype.hasOwnProperty.call(item, fieldId) ? [{
|
|
9871
|
+
kind: "wrongType",
|
|
9872
|
+
path: [
|
|
9873
|
+
...plan.path,
|
|
9874
|
+
index,
|
|
9875
|
+
fieldId
|
|
9876
|
+
],
|
|
9877
|
+
fieldId,
|
|
9878
|
+
label: plan.label,
|
|
9879
|
+
expected: "valid settings"
|
|
9880
|
+
}] : []);
|
|
9406
9881
|
}
|
|
9407
9882
|
function validateGroupPlan(plan, value, ctx) {
|
|
9408
9883
|
if (!isPlainObject$6(value)) return [issue(plan, "wrongType", { expected: "an object" })];
|
|
@@ -9505,19 +9980,22 @@ function requiredIssue(plan, value) {
|
|
|
9505
9980
|
if (Array.isArray(value)) return issue(plan, "required", { emptyOrigin: "array" });
|
|
9506
9981
|
return issue(plan, "required");
|
|
9507
9982
|
}
|
|
9508
|
-
function fieldPlanToZod(plan, options = {}) {
|
|
9509
|
-
const ctx =
|
|
9983
|
+
function fieldPlanToZod(plan, options = {}, layoutGridCoordinates = "validate") {
|
|
9984
|
+
const ctx = {
|
|
9985
|
+
...validationContext(options),
|
|
9986
|
+
layoutGridCoordinates
|
|
9987
|
+
};
|
|
9510
9988
|
return z.any().transform((value) => normalizeFieldValue(plan, value, ctx)).superRefine((value, zodCtx) => {
|
|
9511
|
-
|
|
9989
|
+
validateNormalizedFieldValue(plan, value, ctx).forEach((validationIssue) => {
|
|
9512
9990
|
addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
|
|
9513
|
-
}
|
|
9991
|
+
});
|
|
9514
9992
|
});
|
|
9515
9993
|
}
|
|
9516
9994
|
function fieldPresenceForPlan(plan) {
|
|
9517
9995
|
return plan.required ? { kind: "required" } : { kind: "optional" };
|
|
9518
9996
|
}
|
|
9519
|
-
function fieldPlanToObjectPropertyZod(plan, options = {}) {
|
|
9520
|
-
const schema = fieldPlanToZod(plan, options);
|
|
9997
|
+
function fieldPlanToObjectPropertyZod(plan, options = {}, layoutGridCoordinates = "validate") {
|
|
9998
|
+
const schema = fieldPlanToZod(plan, options, layoutGridCoordinates);
|
|
9521
9999
|
const presence = fieldPresenceForPlan(plan);
|
|
9522
10000
|
switch (presence.kind) {
|
|
9523
10001
|
case "required": return schema;
|
|
@@ -9526,11 +10004,14 @@ function fieldPlanToObjectPropertyZod(plan, options = {}) {
|
|
|
9526
10004
|
}
|
|
9527
10005
|
}
|
|
9528
10006
|
/** Validate stored or runtime fields without applying editor/write normalization. */
|
|
9529
|
-
function fieldPlanToStrictObjectPropertyZod(plan, mode = "strict") {
|
|
9530
|
-
const ctx =
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
10007
|
+
function fieldPlanToStrictObjectPropertyZod(plan, mode = "strict", layoutGridCoordinates = "validate") {
|
|
10008
|
+
const ctx = {
|
|
10009
|
+
...strictValidationContext({
|
|
10010
|
+
allowNull: false,
|
|
10011
|
+
mode
|
|
10012
|
+
}),
|
|
10013
|
+
layoutGridCoordinates
|
|
10014
|
+
};
|
|
9534
10015
|
const schema = z.any().superRefine((value, zodCtx) => {
|
|
9535
10016
|
validateNormalizedFieldValue(plan, value, ctx).forEach((validationIssue) => {
|
|
9536
10017
|
addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
|
|
@@ -9538,76 +10019,35 @@ function fieldPlanToStrictObjectPropertyZod(plan, mode = "strict") {
|
|
|
9538
10019
|
});
|
|
9539
10020
|
return plan.required ? schema : schema.optional();
|
|
9540
10021
|
}
|
|
9541
|
-
function
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
maximum: validationIssue.maximum,
|
|
9571
|
-
inclusive: true,
|
|
9572
|
-
message
|
|
9573
|
-
});
|
|
9574
|
-
return;
|
|
9575
|
-
case "invalidOption":
|
|
9576
|
-
zodCtx.addIssue({
|
|
9577
|
-
...issuePath,
|
|
9578
|
-
code: "invalid_value",
|
|
9579
|
-
values: [],
|
|
9580
|
-
message
|
|
9581
|
-
});
|
|
9582
|
-
return;
|
|
9583
|
-
case "wrongType":
|
|
9584
|
-
case "invalidEmail":
|
|
9585
|
-
case "invalidPhone":
|
|
9586
|
-
case "invalidPattern":
|
|
9587
|
-
case "invalidUrl":
|
|
9588
|
-
case "invalidDate":
|
|
9589
|
-
case "invalidTime":
|
|
9590
|
-
case "invalidDateTime":
|
|
9591
|
-
case "invalidNumber":
|
|
9592
|
-
case "tooSmall":
|
|
9593
|
-
case "tooLarge":
|
|
9594
|
-
case "invalidSlug":
|
|
9595
|
-
case "tooFewItems":
|
|
9596
|
-
case "tooManyItems":
|
|
9597
|
-
case "invalidRichText":
|
|
9598
|
-
case "invalidInlineText":
|
|
9599
|
-
case "invalidMedia":
|
|
9600
|
-
case "invalidBoxBackground":
|
|
9601
|
-
case "invalidLink":
|
|
9602
|
-
case "invalidReference":
|
|
9603
|
-
zodCtx.addIssue({
|
|
9604
|
-
...issuePath,
|
|
9605
|
-
code: "custom",
|
|
9606
|
-
message
|
|
9607
|
-
});
|
|
9608
|
-
return;
|
|
9609
|
-
default: assertNever$12(validationIssue);
|
|
9610
|
-
}
|
|
10022
|
+
function fieldIssueToZodDetail(issue$1) {
|
|
10023
|
+
if (issue$1.kind === "required") return issue$1.emptyOrigin ? {
|
|
10024
|
+
code: "too_small",
|
|
10025
|
+
origin: issue$1.emptyOrigin,
|
|
10026
|
+
minimum: 1,
|
|
10027
|
+
inclusive: true
|
|
10028
|
+
} : {
|
|
10029
|
+
code: "invalid_type",
|
|
10030
|
+
expected: "nonoptional"
|
|
10031
|
+
};
|
|
10032
|
+
if (issue$1.kind === "tooLong") return {
|
|
10033
|
+
code: "too_big",
|
|
10034
|
+
origin: "string",
|
|
10035
|
+
maximum: issue$1.maximum,
|
|
10036
|
+
inclusive: true
|
|
10037
|
+
};
|
|
10038
|
+
if (issue$1.kind === "invalidOption") return {
|
|
10039
|
+
code: "invalid_value",
|
|
10040
|
+
values: []
|
|
10041
|
+
};
|
|
10042
|
+
return { code: "custom" };
|
|
10043
|
+
}
|
|
10044
|
+
function addFieldIssueToZodContext(zodCtx, issue$1, rootPath) {
|
|
10045
|
+
const detail = fieldIssueToZodDetail(issue$1);
|
|
10046
|
+
zodCtx.addIssue({
|
|
10047
|
+
...detail,
|
|
10048
|
+
path: toZodIssuePath(relativeZodIssuePath(issue$1.path, rootPath)),
|
|
10049
|
+
message: fieldIssueToMessage(issue$1)
|
|
10050
|
+
});
|
|
9611
10051
|
}
|
|
9612
10052
|
function relativeZodIssuePath(path$3, rootPath) {
|
|
9613
10053
|
return startsWithFieldPath(path$3, rootPath) ? path$3.slice(rootPath.length) : path$3;
|
|
@@ -9668,7 +10108,7 @@ function sameFieldPath(left, right) {
|
|
|
9668
10108
|
function validateManifestValues(fields$1, values, options = {}) {
|
|
9669
10109
|
const plans = deriveFieldValidationPlans(fields$1);
|
|
9670
10110
|
const normalized = normalizeStoredContentValues(plans, values, options);
|
|
9671
|
-
return plans.flatMap((plan) => validateFieldValue(plan, normalized[plan.fieldId], options));
|
|
10111
|
+
return [...plans.flatMap((plan) => validateFieldValue(plan, normalized[plan.fieldId], options)), ...validateLayoutGridPlans(plans, normalized)];
|
|
9672
10112
|
}
|
|
9673
10113
|
function compilePattern(pattern) {
|
|
9674
10114
|
try {
|
|
@@ -9771,6 +10211,60 @@ function isEmptyRichTextDoc(value) {
|
|
|
9771
10211
|
return first?.type === "paragraph" && (!Array.isArray(first.content) || first.content.length === 0);
|
|
9772
10212
|
}
|
|
9773
10213
|
|
|
10214
|
+
//#endregion
|
|
10215
|
+
//#region ../blocks/src/system/manifest/fieldValidation/layoutGridRendering.ts
|
|
10216
|
+
function hasInvalidCoordinateValues(plan, items) {
|
|
10217
|
+
const ids = layoutGridCoordinateFieldIds(plan);
|
|
10218
|
+
return items.some((item) => {
|
|
10219
|
+
const row$1 = layoutGridRecord(item);
|
|
10220
|
+
return row$1 !== null && resolveLayoutGridItemPlans(plan, row$1).some((field) => ids.includes(field.fieldId) && !fieldPlanToStrictObjectPropertyZod(field).safeParse(row$1[field.fieldId]).success);
|
|
10221
|
+
});
|
|
10222
|
+
}
|
|
10223
|
+
/** Shared raw-coordinate admission for editor and public rendering; retains diagnostics. */
|
|
10224
|
+
function admitLayoutGridForPlan(plan, value, rootValues, ids) {
|
|
10225
|
+
const layout = buildLayoutGridForPlan(plan, value, rootValues, ids);
|
|
10226
|
+
return layout && !layout.hasInvalidItems && hasInvalidCoordinateValues(plan, value) ? {
|
|
10227
|
+
...layout,
|
|
10228
|
+
hasInvalidItems: true
|
|
10229
|
+
} : layout;
|
|
10230
|
+
}
|
|
10231
|
+
function projectGrid(plan, value, rootValues) {
|
|
10232
|
+
const grid$5 = plan.layoutGrid;
|
|
10233
|
+
const layout = admitLayoutGridForPlan(plan, value, rootValues);
|
|
10234
|
+
if (!grid$5 || !layout) return value;
|
|
10235
|
+
const authored = layout;
|
|
10236
|
+
const projected = projectRepeaterGridLayoutForRendering(authored);
|
|
10237
|
+
if (projected === authored) return value;
|
|
10238
|
+
return value.map((item, index) => {
|
|
10239
|
+
const row$1 = layoutGridRecord(item);
|
|
10240
|
+
const placement = projected.byId[String(index)];
|
|
10241
|
+
if (!row$1 || !placement) return item;
|
|
10242
|
+
const spanPlan = resolveLayoutGridItemPlans(plan, row$1).find((field) => field.fieldId === grid$5.spanField);
|
|
10243
|
+
return {
|
|
10244
|
+
...row$1,
|
|
10245
|
+
[grid$5.spanField]: spanPlan?.kind === "number" ? placement.span : String(placement.span),
|
|
10246
|
+
[grid$5.rowField]: placement.row,
|
|
10247
|
+
[grid$5.columnField]: placement.colStart
|
|
10248
|
+
};
|
|
10249
|
+
});
|
|
10250
|
+
}
|
|
10251
|
+
/** Only layout coordinates are projected. Array order, item data and media references remain intact. */
|
|
10252
|
+
function projectLayoutGridPlansForRendering(plans, value, rootValues = layoutGridRecord(value) ?? {}) {
|
|
10253
|
+
const values = layoutGridRecord(value);
|
|
10254
|
+
if (!values) return value;
|
|
10255
|
+
return plans.reduce((projected, plan) => {
|
|
10256
|
+
const fieldValue = projected[plan.fieldId];
|
|
10257
|
+
const next = plan.kind === "group" ? projectLayoutGridPlansForRendering(allGroupChildPlans(plan), fieldValue, rootValues) : plan.kind === "repeater" && Array.isArray(fieldValue) ? projectGrid(plan, fieldValue, rootValues).map((item) => {
|
|
10258
|
+
const row$1 = layoutGridRecord(item);
|
|
10259
|
+
return row$1 ? projectLayoutGridPlansForRendering(resolveLayoutGridItemPlans(plan, row$1), row$1, rootValues) : item;
|
|
10260
|
+
}) : fieldValue;
|
|
10261
|
+
return next === fieldValue ? projected : {
|
|
10262
|
+
...projected,
|
|
10263
|
+
[plan.fieldId]: next
|
|
10264
|
+
};
|
|
10265
|
+
}, values);
|
|
10266
|
+
}
|
|
10267
|
+
|
|
9774
10268
|
//#endregion
|
|
9775
10269
|
//#region ../blocks/src/system/manifest/validation.ts
|
|
9776
10270
|
const compiledManifestContentContract = Symbol("compiledManifestContentContract");
|
|
@@ -9802,6 +10296,7 @@ function compileManifestContentContract(manifestOrFields, options = {}) {
|
|
|
9802
10296
|
return Object.freeze({ [compiledManifestContentContract]: Object.freeze({
|
|
9803
10297
|
plans,
|
|
9804
10298
|
strictStoredSchema,
|
|
10299
|
+
renderSourceSchema: deriveStrictContentZodFromPlans(plans, "render-source"),
|
|
9805
10300
|
writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).superRefine((value, ctx) => {
|
|
9806
10301
|
if (options.unknownFields !== "reject") return;
|
|
9807
10302
|
unknownManifestFieldPaths(plans, value).forEach((path$3) => {
|
|
@@ -9817,6 +10312,11 @@ function compileManifestContentContract(manifestOrFields, options = {}) {
|
|
|
9817
10312
|
allowIncomplete: true,
|
|
9818
10313
|
mode: "draft"
|
|
9819
10314
|
}, normalizeStoredContentValues),
|
|
10315
|
+
renderDraftSchema: deriveNormalizedContentZodFromPlans(plans, {
|
|
10316
|
+
allowNull: true,
|
|
10317
|
+
allowIncomplete: true,
|
|
10318
|
+
mode: "draft"
|
|
10319
|
+
}, normalizeStoredContentValues, false),
|
|
9820
10320
|
renderSchema: deriveStrictContentZodFromPlans(plans, "render"),
|
|
9821
10321
|
findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
|
|
9822
10322
|
}) });
|
|
@@ -9855,7 +10355,8 @@ function findNonPortableManifestMediaPaths(contract, content) {
|
|
|
9855
10355
|
/** Strictly admits already-persisted content without repairing it. */
|
|
9856
10356
|
function admitStoredManifestContent(contract, content) {
|
|
9857
10357
|
const state = contract[compiledManifestContentContract];
|
|
9858
|
-
const
|
|
10358
|
+
const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
|
|
10359
|
+
const nonPortablePaths = state.findNonPortableMediaPaths(normalized);
|
|
9859
10360
|
if (nonPortablePaths.length > 0) {
|
|
9860
10361
|
return {
|
|
9861
10362
|
ok: false,
|
|
@@ -9865,10 +10366,32 @@ function admitStoredManifestContent(contract, content) {
|
|
|
9865
10366
|
}
|
|
9866
10367
|
};
|
|
9867
10368
|
}
|
|
9868
|
-
const parsed = state.strictStoredSchema.safeParse(
|
|
10369
|
+
const parsed = state.strictStoredSchema.safeParse(normalized);
|
|
9869
10370
|
return parsed.success ? {
|
|
9870
10371
|
ok: true,
|
|
9871
|
-
value:
|
|
10372
|
+
value: normalized
|
|
10373
|
+
} : {
|
|
10374
|
+
ok: false,
|
|
10375
|
+
error: zodAdmissionError(parsed.error)
|
|
10376
|
+
};
|
|
10377
|
+
}
|
|
10378
|
+
/** Public reads alone may project invalid grid geometry. All other stored-shape and portability checks remain strict. */
|
|
10379
|
+
function admitStoredManifestContentForRendering(contract, content) {
|
|
10380
|
+
const state = contract[compiledManifestContentContract];
|
|
10381
|
+
const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
|
|
10382
|
+
const paths = state.findNonPortableMediaPaths(normalized);
|
|
10383
|
+
if (paths.length > 0) return {
|
|
10384
|
+
ok: false,
|
|
10385
|
+
error: {
|
|
10386
|
+
kind: "non_portable_media",
|
|
10387
|
+
paths
|
|
10388
|
+
}
|
|
10389
|
+
};
|
|
10390
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, normalized);
|
|
10391
|
+
const parsed = state.renderSourceSchema.safeParse(projected);
|
|
10392
|
+
return parsed.success ? {
|
|
10393
|
+
ok: true,
|
|
10394
|
+
value: projected
|
|
9872
10395
|
} : {
|
|
9873
10396
|
ok: false,
|
|
9874
10397
|
error: zodAdmissionError(parsed.error)
|
|
@@ -9916,6 +10439,24 @@ function validateManifestDraft(contract, data) {
|
|
|
9916
10439
|
issues: [firstIssue, ...remainingIssues]
|
|
9917
10440
|
};
|
|
9918
10441
|
}
|
|
10442
|
+
/** Public template bases may be incomplete until bindings resolve; only grid geometry is projected. */
|
|
10443
|
+
function validateManifestDraftForRendering(contract, data) {
|
|
10444
|
+
const state = contract[compiledManifestContentContract];
|
|
10445
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, data);
|
|
10446
|
+
const parsed = state.renderDraftSchema.safeParse(projected);
|
|
10447
|
+
if (parsed.success) return {
|
|
10448
|
+
kind: "previewable",
|
|
10449
|
+
data: projected,
|
|
10450
|
+
issues: []
|
|
10451
|
+
};
|
|
10452
|
+
const [firstIssue, ...remainingIssues] = zodAdmissionIssues(parsed.error);
|
|
10453
|
+
if (!firstIssue) throw new Error("Render draft validation failed without an issue");
|
|
10454
|
+
return {
|
|
10455
|
+
kind: "invalid",
|
|
10456
|
+
data: projected,
|
|
10457
|
+
issues: [firstIssue, ...remainingIssues]
|
|
10458
|
+
};
|
|
10459
|
+
}
|
|
9919
10460
|
/**
|
|
9920
10461
|
* Checks whether a raw editor candidate is schema-ready for the effectful
|
|
9921
10462
|
* media-resolution/write boundary without granting a stored proof.
|
|
@@ -9942,8 +10483,9 @@ function validateManifestWriteCandidate(contract, data) {
|
|
|
9942
10483
|
* the resulting render shape before granting the renderable proof.
|
|
9943
10484
|
*/
|
|
9944
10485
|
function deriveRenderableManifestContent(contract, stored, project) {
|
|
9945
|
-
const
|
|
9946
|
-
const
|
|
10486
|
+
const state = contract[compiledManifestContentContract];
|
|
10487
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, normalizeLegacyStoredGroupContainers(state.plans, project(stored)));
|
|
10488
|
+
const parsed = state.renderSchema.safeParse(projected);
|
|
9947
10489
|
return parsed.success ? {
|
|
9948
10490
|
ok: true,
|
|
9949
10491
|
value: projected
|
|
@@ -9958,33 +10500,50 @@ function deriveRenderableManifestContent(contract, stored, project) {
|
|
|
9958
10500
|
* grants a stored proof, so hydrated media cannot flow back to persistence.
|
|
9959
10501
|
*/
|
|
9960
10502
|
function admitTransportedRenderableManifestContent(contract, content) {
|
|
9961
|
-
const
|
|
10503
|
+
const state = contract[compiledManifestContentContract];
|
|
10504
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, content);
|
|
10505
|
+
const parsed = state.renderSchema.safeParse(projected);
|
|
9962
10506
|
return parsed.success ? {
|
|
9963
10507
|
ok: true,
|
|
9964
|
-
value:
|
|
10508
|
+
value: projected
|
|
9965
10509
|
} : {
|
|
9966
10510
|
ok: false,
|
|
9967
10511
|
error: zodAdmissionError(parsed.error)
|
|
9968
10512
|
};
|
|
9969
10513
|
}
|
|
9970
|
-
function deriveNormalizedContentZodFromPlans(plans, options, normalize$4) {
|
|
10514
|
+
function deriveNormalizedContentZodFromPlans(plans, options, normalize$4, validateLayoutGrids = true) {
|
|
9971
10515
|
const isDraft = options.mode === "draft";
|
|
9972
|
-
const baseSchema = deriveContentZodFromPlans(plans, options);
|
|
10516
|
+
const baseSchema = deriveContentZodFromPlans(plans, options, validateLayoutGrids);
|
|
9973
10517
|
if (isDraft) {
|
|
9974
10518
|
return z.preprocess((content) => preprocessEmptyValues(normalize$4(plans, content, options)), baseSchema);
|
|
9975
10519
|
}
|
|
9976
10520
|
return z.preprocess((content) => normalize$4(plans, content, options), baseSchema);
|
|
9977
10521
|
}
|
|
9978
|
-
function deriveContentZodFromPlans(plans, options) {
|
|
9979
|
-
const shape =
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
10522
|
+
function deriveContentZodFromPlans(plans, options, validateLayoutGrids = true) {
|
|
10523
|
+
const shape = Object.fromEntries(plans.map((plan) => [plan.fieldId, fieldPlanToObjectPropertyZod(plan, options, validateLayoutGrids ? "validate" : "projected")]));
|
|
10524
|
+
return z.object(shape).catchall(z.unknown()).passthrough().superRefine((values, ctx) => {
|
|
10525
|
+
if (!validateLayoutGrids) return;
|
|
10526
|
+
validateLayoutGridPlans(plans, values).forEach((issue$1) => {
|
|
10527
|
+
ctx.addIssue({
|
|
10528
|
+
code: "custom",
|
|
10529
|
+
path: [...issue$1.path],
|
|
10530
|
+
message: issue$1.message
|
|
10531
|
+
});
|
|
10532
|
+
});
|
|
10533
|
+
});
|
|
9984
10534
|
}
|
|
9985
10535
|
function deriveStrictContentZodFromPlans(plans, mode = "strict") {
|
|
9986
|
-
const shape = Object.fromEntries(plans.map((plan) => [plan.fieldId, fieldPlanToStrictObjectPropertyZod(plan, mode)]));
|
|
9987
|
-
return z.object(shape).catchall(z.unknown()).passthrough()
|
|
10536
|
+
const shape = Object.fromEntries(plans.map((plan) => [plan.fieldId, fieldPlanToStrictObjectPropertyZod(plan, mode === "render" ? "render" : "strict", mode === "strict" ? "validate" : "projected")]));
|
|
10537
|
+
return z.object(shape).catchall(z.unknown()).passthrough().superRefine((values, ctx) => {
|
|
10538
|
+
if (mode !== "strict") return;
|
|
10539
|
+
validateLayoutGridPlans(plans, values).forEach((issue$1) => {
|
|
10540
|
+
ctx.addIssue({
|
|
10541
|
+
code: "custom",
|
|
10542
|
+
path: [...issue$1.path],
|
|
10543
|
+
message: issue$1.message
|
|
10544
|
+
});
|
|
10545
|
+
});
|
|
10546
|
+
});
|
|
9988
10547
|
}
|
|
9989
10548
|
function derivePlansFromManifestOrFields(manifestOrFields) {
|
|
9990
10549
|
const fields$1 = Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields ?? [];
|
|
@@ -12306,6 +12865,7 @@ function styledSection(config$1) {
|
|
|
12306
12865
|
baseClass,
|
|
12307
12866
|
spacing,
|
|
12308
12867
|
fullWidthPath,
|
|
12868
|
+
photoPaintsGround: renderBackgroundImage,
|
|
12309
12869
|
skinSlot: config$1.skinSlot
|
|
12310
12870
|
}), [renderedBackgroundNode, ...childrenArray]);
|
|
12311
12871
|
}
|
|
@@ -12317,7 +12877,10 @@ function sectionAppearanceProps(input) {
|
|
|
12317
12877
|
from: `${input.bindFrom}.background`,
|
|
12318
12878
|
transforms: [{
|
|
12319
12879
|
id: "sectionStyles.resolveColorsStyle",
|
|
12320
|
-
options: {
|
|
12880
|
+
options: {
|
|
12881
|
+
fallbackToken: input.background,
|
|
12882
|
+
photoPaintsGround: input.photoPaintsGround
|
|
12883
|
+
}
|
|
12321
12884
|
}]
|
|
12322
12885
|
} },
|
|
12323
12886
|
className: { $bind: {
|
|
@@ -13487,70 +14050,6 @@ function applyAlpha(color, opacity) {
|
|
|
13487
14050
|
return color;
|
|
13488
14051
|
}
|
|
13489
14052
|
|
|
13490
|
-
//#endregion
|
|
13491
|
-
//#region ../blocks/src/system/fields/backgroundContent.ts
|
|
13492
|
-
/**
|
|
13493
|
-
* Replaces only the background medium while retaining presentation fields that
|
|
13494
|
-
* are valid for the resulting image variant. Stale color/gradient tab state is
|
|
13495
|
-
* never copied into the new value.
|
|
13496
|
-
*/
|
|
13497
|
-
function replaceBackgroundWithImage(value, image, defaults = {}) {
|
|
13498
|
-
const current = parseBackgroundContent(value);
|
|
13499
|
-
let candidate;
|
|
13500
|
-
if (current?.type === "image") {
|
|
13501
|
-
const { type: _type, image: _image, ...presentation } = current;
|
|
13502
|
-
candidate = {
|
|
13503
|
-
...defaults,
|
|
13504
|
-
...presentation,
|
|
13505
|
-
type: "image",
|
|
13506
|
-
image
|
|
13507
|
-
};
|
|
13508
|
-
} else if (current?.type === "video") {
|
|
13509
|
-
const { type: _type, image: _image, showVideoOnMobile: _mobile, ...presentation } = current;
|
|
13510
|
-
candidate = {
|
|
13511
|
-
...defaults,
|
|
13512
|
-
...presentation,
|
|
13513
|
-
type: "image",
|
|
13514
|
-
image
|
|
13515
|
-
};
|
|
13516
|
-
} else {
|
|
13517
|
-
candidate = {
|
|
13518
|
-
...defaults,
|
|
13519
|
-
...commonPresentation(current),
|
|
13520
|
-
type: "image",
|
|
13521
|
-
image
|
|
13522
|
-
};
|
|
13523
|
-
}
|
|
13524
|
-
const canonical$1 = boxBackgroundSchema.parse(candidate);
|
|
13525
|
-
if (canonical$1.type !== "image") {
|
|
13526
|
-
throw new Error("Image background construction produced a non-image variant");
|
|
13527
|
-
}
|
|
13528
|
-
return canonical$1;
|
|
13529
|
-
}
|
|
13530
|
-
function parseBackgroundContent(value) {
|
|
13531
|
-
const result = boxBackgroundSchema.safeParse(value);
|
|
13532
|
-
return result.success ? result.data : null;
|
|
13533
|
-
}
|
|
13534
|
-
function commonPresentation(background) {
|
|
13535
|
-
return background ? {
|
|
13536
|
-
contentOwner: background.contentOwner,
|
|
13537
|
-
textColor: background.textColor,
|
|
13538
|
-
headingColor: background.headingColor,
|
|
13539
|
-
linkColor: background.linkColor,
|
|
13540
|
-
supportingColor: background.supportingColor
|
|
13541
|
-
} : {};
|
|
13542
|
-
}
|
|
13543
|
-
function parseBackgroundOverlay(value) {
|
|
13544
|
-
const result = boxBackgroundOverlaySchema.safeParse(value);
|
|
13545
|
-
return result.success ? result.data : undefined;
|
|
13546
|
-
}
|
|
13547
|
-
/** Rendering accepts explicit application sources separately from stored references. */
|
|
13548
|
-
const runtimeBackgroundContentSchema = runtimeBoxBackgroundSchema;
|
|
13549
|
-
function parseRuntimeBackgroundContent(value) {
|
|
13550
|
-
const result = runtimeBackgroundContentSchema.safeParse(value);
|
|
13551
|
-
return result.success ? result.data : null;
|
|
13552
|
-
}
|
|
13553
|
-
|
|
13554
14053
|
//#endregion
|
|
13555
14054
|
//#region ../blocks/src/system/transforms/registry/_utils/themeColorResolution.ts
|
|
13556
14055
|
function resolveBackgroundColorValue(value, context) {
|
|
@@ -13578,7 +14077,7 @@ function resolveSurfaceForegroundStyles(value, context, options) {
|
|
|
13578
14077
|
const key = JSON.stringify([
|
|
13579
14078
|
value,
|
|
13580
14079
|
context.proseHoverCandidate,
|
|
13581
|
-
options
|
|
14080
|
+
options,
|
|
13582
14081
|
context.data?._lookSlots !== undefined
|
|
13583
14082
|
]);
|
|
13584
14083
|
const cache = sectionSurfaceCache.get(context.theme) ?? new Map();
|
|
@@ -13595,9 +14094,13 @@ function resolveSurfaceForegroundStyles(value, context, options) {
|
|
|
13595
14094
|
}
|
|
13596
14095
|
/** Cache only the owner's result; no foreground or button rules live here. */
|
|
13597
14096
|
function resolveRuntimeSectionSurface(value, context, options) {
|
|
14097
|
+
const background = resolveSectionBackground(parseCanonicalRuntimeBackground({ _sectionStyles: { background: value } }), null, undefined, {
|
|
14098
|
+
paintsGround: options?.photoPaintsGround !== false,
|
|
14099
|
+
fallbackToken: options?.fallbackToken
|
|
14100
|
+
});
|
|
13598
14101
|
return resolveSurface({
|
|
13599
14102
|
kind: "section",
|
|
13600
|
-
background:
|
|
14103
|
+
background: sectionForegroundBackground(background, context.theme.palette)
|
|
13601
14104
|
}, {
|
|
13602
14105
|
palette: context.theme.palette,
|
|
13603
14106
|
buttonSystem: context.theme.buttons,
|
|
@@ -13622,6 +14125,70 @@ function surfaceInkStyles(foreground, palette) {
|
|
|
13622
14125
|
};
|
|
13623
14126
|
}
|
|
13624
14127
|
|
|
14128
|
+
//#endregion
|
|
14129
|
+
//#region ../blocks/src/system/fields/backgroundContent.ts
|
|
14130
|
+
/**
|
|
14131
|
+
* Replaces only the background medium while retaining presentation fields that
|
|
14132
|
+
* are valid for the resulting image variant. Stale color/gradient tab state is
|
|
14133
|
+
* never copied into the new value.
|
|
14134
|
+
*/
|
|
14135
|
+
function replaceBackgroundWithImage(value, image, defaults = {}) {
|
|
14136
|
+
const current = parseBackgroundContent(value);
|
|
14137
|
+
let candidate;
|
|
14138
|
+
if (current?.type === "image") {
|
|
14139
|
+
const { type: _type, image: _image, ...presentation } = current;
|
|
14140
|
+
candidate = {
|
|
14141
|
+
...defaults,
|
|
14142
|
+
...presentation,
|
|
14143
|
+
type: "image",
|
|
14144
|
+
image
|
|
14145
|
+
};
|
|
14146
|
+
} else if (current?.type === "video") {
|
|
14147
|
+
const { type: _type, image: _image, showVideoOnMobile: _mobile, ...presentation } = current;
|
|
14148
|
+
candidate = {
|
|
14149
|
+
...defaults,
|
|
14150
|
+
...presentation,
|
|
14151
|
+
type: "image",
|
|
14152
|
+
image
|
|
14153
|
+
};
|
|
14154
|
+
} else {
|
|
14155
|
+
candidate = {
|
|
14156
|
+
...defaults,
|
|
14157
|
+
...commonPresentation(current),
|
|
14158
|
+
type: "image",
|
|
14159
|
+
image
|
|
14160
|
+
};
|
|
14161
|
+
}
|
|
14162
|
+
const canonical$1 = boxBackgroundSchema.parse(candidate);
|
|
14163
|
+
if (canonical$1.type !== "image") {
|
|
14164
|
+
throw new Error("Image background construction produced a non-image variant");
|
|
14165
|
+
}
|
|
14166
|
+
return canonical$1;
|
|
14167
|
+
}
|
|
14168
|
+
function parseBackgroundContent(value) {
|
|
14169
|
+
const result = boxBackgroundSchema.safeParse(value);
|
|
14170
|
+
return result.success ? result.data : null;
|
|
14171
|
+
}
|
|
14172
|
+
function commonPresentation(background) {
|
|
14173
|
+
return background ? {
|
|
14174
|
+
contentOwner: background.contentOwner,
|
|
14175
|
+
textColor: background.textColor,
|
|
14176
|
+
headingColor: background.headingColor,
|
|
14177
|
+
linkColor: background.linkColor,
|
|
14178
|
+
supportingColor: background.supportingColor
|
|
14179
|
+
} : {};
|
|
14180
|
+
}
|
|
14181
|
+
function parseBackgroundOverlay(value) {
|
|
14182
|
+
const result = boxBackgroundOverlaySchema.safeParse(value);
|
|
14183
|
+
return result.success ? result.data : undefined;
|
|
14184
|
+
}
|
|
14185
|
+
/** Rendering accepts explicit application sources separately from stored references. */
|
|
14186
|
+
const runtimeBackgroundContentSchema = runtimeBoxBackgroundSchema;
|
|
14187
|
+
function parseRuntimeBackgroundContent(value) {
|
|
14188
|
+
const result = runtimeBackgroundContentSchema.safeParse(value);
|
|
14189
|
+
return result.success ? result.data : null;
|
|
14190
|
+
}
|
|
14191
|
+
|
|
13625
14192
|
//#endregion
|
|
13626
14193
|
//#region ../blocks/src/system/transforms/registry/_utils/boxStyleClassNames.ts
|
|
13627
14194
|
/**
|
|
@@ -17857,7 +18424,7 @@ function splitLayoutWith(children) {
|
|
|
17857
18424
|
children
|
|
17858
18425
|
}
|
|
17859
18426
|
}),
|
|
17860
|
-
renderBackgroundImage:
|
|
18427
|
+
renderBackgroundImage: heroPhotoPaintsGround("split"),
|
|
17861
18428
|
baseClass: ""
|
|
17862
18429
|
});
|
|
17863
18430
|
}
|
|
@@ -17873,7 +18440,7 @@ const lookPhoto = el("figure", lookSlot("media"), [media({
|
|
|
17873
18440
|
const lookCopy = el("div", lookSlot("copy"), heroContentNodes);
|
|
17874
18441
|
const heroLookLayout = (children) => styledSection({
|
|
17875
18442
|
baseClass: "",
|
|
17876
|
-
renderBackgroundImage:
|
|
18443
|
+
renderBackgroundImage: heroPhotoPaintsGround("headline-row"),
|
|
17877
18444
|
children: styledContainer({ children: el("div", lookSlot("frame"), children) })
|
|
17878
18445
|
});
|
|
17879
18446
|
const headlineRowLayout = heroLookLayout([
|
|
@@ -18921,8 +19488,24 @@ const blogListingBlockDefinition = {
|
|
|
18921
19488
|
//#endregion
|
|
18922
19489
|
//#region ../blocks/src/system/blocks/cta-full.ts
|
|
18923
19490
|
const ctaComposition = composeFragments([{ fragment: ctaCopyFragment }, { fragment: ctaRowFragment }]);
|
|
19491
|
+
const figureLayout = styledSection({
|
|
19492
|
+
children: sectionContainer([el("div", lookSlot("layout"), [el("div", lookSlot("figure"), [text({
|
|
19493
|
+
as: "p",
|
|
19494
|
+
...lookSlot("figure-value")
|
|
19495
|
+
}, when("content.figure"), bind("content.figure")), text({
|
|
19496
|
+
as: "p",
|
|
19497
|
+
...lookSlot("figure-label")
|
|
19498
|
+
}, when("content.figureNote"), bind("content.figureNote"))], when("content.figure")), el("div", lookSlot("copy"), [...ctaComposition.layout])])], {
|
|
19499
|
+
gap: "md",
|
|
19500
|
+
className: "rb-relative"
|
|
19501
|
+
}),
|
|
19502
|
+
baseClass: ""
|
|
19503
|
+
});
|
|
18924
19504
|
const ctaFullConfig = {
|
|
18925
|
-
variantMeaning: {
|
|
19505
|
+
variantMeaning: {
|
|
19506
|
+
kind: "arrangement",
|
|
19507
|
+
lookOnlyKeys: ["figure"]
|
|
19508
|
+
},
|
|
18926
19509
|
id: "block.cta-full",
|
|
18927
19510
|
title: "Full-width CTA",
|
|
18928
19511
|
category: "marketing",
|
|
@@ -18934,6 +19517,21 @@ const ctaFullConfig = {
|
|
|
18934
19517
|
fragment: ctaRowFragment,
|
|
18935
19518
|
fieldPriority: 2
|
|
18936
19519
|
}],
|
|
19520
|
+
additionalFields: [parseFieldDefinition({
|
|
19521
|
+
id: "figure",
|
|
19522
|
+
type: "text",
|
|
19523
|
+
label: "Big figure",
|
|
19524
|
+
help: "A short number or price, like £12 or 6 weeks.",
|
|
19525
|
+
required: false,
|
|
19526
|
+
defaultValue: ""
|
|
19527
|
+
}), parseFieldDefinition({
|
|
19528
|
+
id: "figureNote",
|
|
19529
|
+
type: "text",
|
|
19530
|
+
label: "Under the figure",
|
|
19531
|
+
help: "A few words under it, like 'your first class'.",
|
|
19532
|
+
required: false,
|
|
19533
|
+
defaultValue: ""
|
|
19534
|
+
})],
|
|
18937
19535
|
layout: styledSection({
|
|
18938
19536
|
children: props(lookSlot("copy"))(sectionContainer(ctaComposition.layout, {
|
|
18939
19537
|
gap: "md",
|
|
@@ -18941,6 +19539,7 @@ const ctaFullConfig = {
|
|
|
18941
19539
|
})),
|
|
18942
19540
|
baseClass: ""
|
|
18943
19541
|
}),
|
|
19542
|
+
variants: { figure: figureLayout },
|
|
18944
19543
|
description: "Centered call to action with optional background image.",
|
|
18945
19544
|
tags: [
|
|
18946
19545
|
"cta",
|
|
@@ -19786,6 +20385,21 @@ const splitHeadingColumnsLayout = styledSection({
|
|
|
19786
20385
|
}),
|
|
19787
20386
|
baseClass: ""
|
|
19788
20387
|
});
|
|
20388
|
+
const openAnswer = el("div", lookSlot("item"), [text({
|
|
20389
|
+
as: "h3",
|
|
20390
|
+
...lookSlot("item-title")
|
|
20391
|
+
}, bind("faqItem.question")), richText({ ...lookSlot("item-text") }, when("faqItem.answer"), bind("faqItem.answer"))], repeat("content.items", "faqItem", { indexName: "faqIndex" }));
|
|
20392
|
+
const openLayout = styledSection({
|
|
20393
|
+
children: styledContainer({
|
|
20394
|
+
baseClassName: "rb-relative rb-isolate",
|
|
20395
|
+
children: stack({
|
|
20396
|
+
gap: "lg",
|
|
20397
|
+
className: "rb-w-full",
|
|
20398
|
+
...lookSlot("layout")
|
|
20399
|
+
}, [headingLayout, el("div", lookSlot("items"), [openAnswer])])
|
|
20400
|
+
}),
|
|
20401
|
+
baseClass: ""
|
|
20402
|
+
});
|
|
19789
20403
|
const faqManifest = createBlockManifest({
|
|
19790
20404
|
id: "block.faq",
|
|
19791
20405
|
title: "FAQ",
|
|
@@ -19809,9 +20423,13 @@ const faqManifest = createBlockManifest({
|
|
|
19809
20423
|
default: defaultLayout,
|
|
19810
20424
|
"two-column": twoColumnLayout,
|
|
19811
20425
|
"question-columns": questionColumnsLayout,
|
|
19812
|
-
"split-heading-columns": splitHeadingColumnsLayout
|
|
20426
|
+
"split-heading-columns": splitHeadingColumnsLayout,
|
|
20427
|
+
open: openLayout
|
|
20428
|
+
},
|
|
20429
|
+
variantMeaning: {
|
|
20430
|
+
kind: "arrangement",
|
|
20431
|
+
lookOnlyKeys: ["open"]
|
|
19813
20432
|
},
|
|
19814
|
-
variantMeaning: { kind: "arrangement" },
|
|
19815
20433
|
defaultVariant: "default",
|
|
19816
20434
|
variantOptions: {
|
|
19817
20435
|
default: {
|
|
@@ -40939,6 +41557,15 @@ const eventRegistrationManifest = createBlockManifest({
|
|
|
40939
41557
|
], { gap: "lg" })
|
|
40940
41558
|
})]
|
|
40941
41559
|
});
|
|
41560
|
+
const registrationEventScopeParams = {
|
|
41561
|
+
detailAdmission: { $bind: { from: "$root.subject.detailAdmission" } },
|
|
41562
|
+
seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
|
|
41563
|
+
seriesIds: { $bind: {
|
|
41564
|
+
from: "$root.subject.catalogueEventSeriesIds",
|
|
41565
|
+
transforms: [{ id: "value.csv" }]
|
|
41566
|
+
} },
|
|
41567
|
+
runSeriesId: { $bind: { from: "$root.entrySubrouteContext.run.seriesId" } }
|
|
41568
|
+
};
|
|
40942
41569
|
const eventRegistrationBlockDefinition = {
|
|
40943
41570
|
manifest: eventRegistrationManifest,
|
|
40944
41571
|
runtime: eventRegistrationBlockRuntime,
|
|
@@ -40965,12 +41592,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
40965
41592
|
fallback: "published"
|
|
40966
41593
|
} },
|
|
40967
41594
|
readProfile: "registration",
|
|
40968
|
-
|
|
40969
|
-
seriesIds: { $bind: {
|
|
40970
|
-
from: "$root.subject.catalogueEventSeriesIds",
|
|
40971
|
-
transforms: [{ id: "value.csv" }]
|
|
40972
|
-
} },
|
|
40973
|
-
runSeriesId: { $bind: { from: "$root.entrySubrouteContext.run.seriesId" } },
|
|
41595
|
+
...registrationEventScopeParams,
|
|
40974
41596
|
includeOccurrenceId: { $bind: { from: "$root.occurrenceContext.id" } }
|
|
40975
41597
|
},
|
|
40976
41598
|
mode: "server"
|
|
@@ -40990,12 +41612,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
40990
41612
|
fallback: "published"
|
|
40991
41613
|
} },
|
|
40992
41614
|
readProfile: "registration",
|
|
40993
|
-
|
|
40994
|
-
seriesIds: { $bind: {
|
|
40995
|
-
from: "$root.subject.catalogueEventSeriesIds",
|
|
40996
|
-
transforms: [{ id: "value.csv" }]
|
|
40997
|
-
} },
|
|
40998
|
-
runSeriesId: { $bind: { from: "$root.entrySubrouteContext.run.seriesId" } }
|
|
41615
|
+
...registrationEventScopeParams
|
|
40999
41616
|
},
|
|
41000
41617
|
mode: "server"
|
|
41001
41618
|
},
|
|
@@ -41472,6 +42089,7 @@ const eventDetailsBlockDefinition = {
|
|
|
41472
42089
|
} },
|
|
41473
42090
|
limit: "100",
|
|
41474
42091
|
readProfile: "details",
|
|
42092
|
+
detailAdmission: { $bind: { from: "$root.subject.detailAdmission" } },
|
|
41475
42093
|
seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
|
|
41476
42094
|
seriesIds: { $bind: {
|
|
41477
42095
|
from: "$root.subject.catalogueEventSeriesIds",
|
|
@@ -53062,6 +53680,7 @@ function describeUnresolvedLocationMapLocation(resolvedLocation) {
|
|
|
53062
53680
|
}
|
|
53063
53681
|
}
|
|
53064
53682
|
function normalizeLocationMapProps(input) {
|
|
53683
|
+
const parsedHours = parseWeeklyOpeningHours(input.openingHours);
|
|
53065
53684
|
const resolvedLocation = resolveLocationMapLocation(input);
|
|
53066
53685
|
const locationValue = resolvedLocation.kind === "unresolved" ? null : resolvedLocation.locationValue;
|
|
53067
53686
|
const directionsLabel = normalizeLocationAddressText(input.directionsLabel) ?? LOCATION_MAP_DEFAULTS.directionsLabel;
|
|
@@ -53073,6 +53692,8 @@ function normalizeLocationMapProps(input) {
|
|
|
53073
53692
|
location: toLocationCoordinates(locationValue),
|
|
53074
53693
|
zoom: Math.min(LOCATION_MAP_LIMITS.zoom.max, Math.max(LOCATION_MAP_LIMITS.zoom.min, Math.round(normalizeNumber(input.zoom, LOCATION_MAP_DEFAULTS.zoom)))),
|
|
53075
53694
|
heightPx: Math.min(LOCATION_MAP_LIMITS.heightPx.max, Math.max(LOCATION_MAP_LIMITS.heightPx.min, Math.round(normalizeNumber(input.heightPx, LOCATION_MAP_DEFAULTS.heightPx)))),
|
|
53695
|
+
openingHours: parsedHours.ok ? parsedHours.value : null,
|
|
53696
|
+
showOpeningHours: normalizeBoolean$1(input.showOpeningHours, true),
|
|
53076
53697
|
showAddressText: normalizeBoolean$1(input.showAddressText, LOCATION_MAP_DEFAULTS.showAddressText),
|
|
53077
53698
|
showDirections: normalizeBoolean$1(input.showDirections, LOCATION_MAP_DEFAULTS.showDirections),
|
|
53078
53699
|
directionsLabel,
|
|
@@ -53085,6 +53706,8 @@ function toLocationMapHydrationProps(input) {
|
|
|
53085
53706
|
location: normalized.locationValue,
|
|
53086
53707
|
zoom: normalized.zoom,
|
|
53087
53708
|
heightPx: normalized.heightPx,
|
|
53709
|
+
openingHours: normalized.openingHours,
|
|
53710
|
+
showOpeningHours: normalized.showOpeningHours,
|
|
53088
53711
|
showAddressText: normalized.showAddressText,
|
|
53089
53712
|
showDirections: normalized.showDirections,
|
|
53090
53713
|
directionsLabel: normalized.directionsLabel,
|
|
@@ -53122,6 +53745,7 @@ function normalizeLocationMapContent(content) {
|
|
|
53122
53745
|
heading: typeof record.heading === "string" ? record.heading : undefined,
|
|
53123
53746
|
locationSource,
|
|
53124
53747
|
...authoredLocationMapSourceFields(locationSource, venueId, normalized.locationValue),
|
|
53748
|
+
showOpeningHours: record.showOpeningHours !== false,
|
|
53125
53749
|
showAddressText: normalized.showAddressText,
|
|
53126
53750
|
showDirections: normalized.showDirections,
|
|
53127
53751
|
directionsLabel: normalized.directionsLabel,
|
|
@@ -53255,6 +53879,13 @@ const locationMapManifest = createBlockManifest({
|
|
|
53255
53879
|
}
|
|
53256
53880
|
] }
|
|
53257
53881
|
}),
|
|
53882
|
+
parseFieldDefinition({
|
|
53883
|
+
id: "showOpeningHours",
|
|
53884
|
+
type: "boolean",
|
|
53885
|
+
label: "Show opening hours",
|
|
53886
|
+
defaultValue: true,
|
|
53887
|
+
ui: { intent: "display" }
|
|
53888
|
+
}),
|
|
53258
53889
|
parseFieldDefinition({
|
|
53259
53890
|
id: "showAddressText",
|
|
53260
53891
|
type: "boolean",
|
|
@@ -53316,6 +53947,14 @@ const locationMapManifest = createBlockManifest({
|
|
|
53316
53947
|
baseClass: "",
|
|
53317
53948
|
spacing: "comfortable",
|
|
53318
53949
|
children: sectionContainer([text({ as: "h2" }, bind("content.heading"), when("content.heading")), el("location-map", {
|
|
53950
|
+
openingHours: { $bind: {
|
|
53951
|
+
from: "$root.openingHours",
|
|
53952
|
+
fallback: null
|
|
53953
|
+
} },
|
|
53954
|
+
showOpeningHours: { $bind: {
|
|
53955
|
+
from: "content.showOpeningHours",
|
|
53956
|
+
fallback: true
|
|
53957
|
+
} },
|
|
53319
53958
|
location: { $bind: {
|
|
53320
53959
|
from: "content.location",
|
|
53321
53960
|
fallback: null
|
|
@@ -53368,6 +54007,7 @@ const locationMapBlockDefinition = {
|
|
|
53368
54007
|
"venueId",
|
|
53369
54008
|
"location",
|
|
53370
54009
|
"showAddressText",
|
|
54010
|
+
"showOpeningHours",
|
|
53371
54011
|
"showDirections",
|
|
53372
54012
|
"directionsLabel",
|
|
53373
54013
|
"zoom",
|
|
@@ -58504,6 +59144,7 @@ function validateAppointmentBookingFormSource(input) {
|
|
|
58504
59144
|
}
|
|
58505
59145
|
function normalizeAppointmentBookingServices(input) {
|
|
58506
59146
|
return input.services.map((service) => ({
|
|
59147
|
+
...service.image === undefined ? {} : { image: service.image },
|
|
58507
59148
|
id: service.id,
|
|
58508
59149
|
siteId: input.siteId,
|
|
58509
59150
|
title: service.title,
|
|
@@ -58598,6 +59239,7 @@ const blockBookingPaymentTermsAvailabilitySchema = z.union([z.object({
|
|
|
58598
59239
|
reason: z.literal("online_payment_configured_before_launch")
|
|
58599
59240
|
})]);
|
|
58600
59241
|
const bookingServiceSchema = z.object({
|
|
59242
|
+
image: runtimeMediaSchema.nullable().optional(),
|
|
58601
59243
|
location: z.object({ mode: z.enum([
|
|
58602
59244
|
"online",
|
|
58603
59245
|
"in_person",
|
|
@@ -59284,7 +59926,7 @@ function scheduleLine(summary, event, now) {
|
|
|
59284
59926
|
date: "short",
|
|
59285
59927
|
year: now ? year(value) : "omit"
|
|
59286
59928
|
});
|
|
59287
|
-
const dates = (startsAt, endsAt) => formatDateRange({
|
|
59929
|
+
const dates = (startsAt, endsAt, order = "chronological") => formatDateRange({
|
|
59288
59930
|
kind: "civil",
|
|
59289
59931
|
value: getLocalScheduleDate(new Date(startsAt), context.timeZone)
|
|
59290
59932
|
}, {
|
|
@@ -59292,6 +59934,7 @@ function scheduleLine(summary, event, now) {
|
|
|
59292
59934
|
value: getLocalScheduleDate(new Date(endsAt), resolveBookingBusinessTimeZone(last.timeZone))
|
|
59293
59935
|
}, context, {
|
|
59294
59936
|
date: "short",
|
|
59937
|
+
order,
|
|
59295
59938
|
year: now && year(startsAt) === "omit" && year(endsAt, resolveBookingBusinessTimeZone(last.timeZone)) === "omit" ? "omit" : now ? "numeric" : "omit"
|
|
59296
59939
|
});
|
|
59297
59940
|
switch (summary.kind) {
|
|
@@ -59305,8 +59948,8 @@ function scheduleLine(summary, event, now) {
|
|
|
59305
59948
|
zone
|
|
59306
59949
|
}) : date(summary.occurrence.startsAt);
|
|
59307
59950
|
case "multi-day-span": return dates(summary.occurrence.startsAt, summary.occurrence.endsAt);
|
|
59308
|
-
case "fixed-recurring-run": return `${dates(summary.first.startsAt, summary.last.startsAt)} · ${summary.recurrenceLabel}`;
|
|
59309
|
-
case "irregular-multi-session-run": return `${dates(summary.first.startsAt, summary.last.startsAt)} · ${summary.sessionCount} dates`;
|
|
59951
|
+
case "fixed-recurring-run": return `${dates(summary.first.startsAt, summary.last.startsAt, "session")} · ${summary.recurrenceLabel}`;
|
|
59952
|
+
case "irregular-multi-session-run": return `${dates(summary.first.startsAt, summary.last.startsAt, "session")} · ${summary.sessionCount} dates`;
|
|
59310
59953
|
}
|
|
59311
59954
|
}
|
|
59312
59955
|
function offeringAvailability(event) {
|
|
@@ -59945,16 +60588,44 @@ var event_details_server_default = EventDetailsSSR;
|
|
|
59945
60588
|
|
|
59946
60589
|
//#endregion
|
|
59947
60590
|
//#region ../blocks/src/system/runtime/nodes/location-map.view.tsx
|
|
59948
|
-
function
|
|
59949
|
-
|
|
60591
|
+
function OpeningHoursTable({ hours: hours$1 }) {
|
|
60592
|
+
if (!hours$1) return null;
|
|
60593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("caption", { children: "Opening hours" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: formatOpeningHoursRows(hours$1).map((row$1) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", {
|
|
60594
|
+
"data-closed": row$1.kind === "closed" ? true : undefined,
|
|
60595
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
60596
|
+
scope: "row",
|
|
60597
|
+
children: row$1.label
|
|
60598
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: row$1.hours })]
|
|
60599
|
+
}, row$1.label)) })] }), hours$1.note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: hours$1.note }) : null] });
|
|
60600
|
+
}
|
|
60601
|
+
function LocationMapDirections({ url, label }) {
|
|
60602
|
+
return url ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
|
|
60603
|
+
href: url,
|
|
60604
|
+
target: "_blank",
|
|
60605
|
+
rel: "noreferrer",
|
|
60606
|
+
variant: "ghost",
|
|
60607
|
+
size: "sm",
|
|
60608
|
+
extraClassName: "rb-w-fit",
|
|
60609
|
+
label
|
|
60610
|
+
}) : null;
|
|
60611
|
+
}
|
|
60612
|
+
function LocationMapView(props$1) {
|
|
60613
|
+
const { addressText, location, renderMap, zoom, heightPx, showAddressText, directionsLabel } = props$1;
|
|
60614
|
+
const directionsUrl = props$1.showDirections ? buildGoogleMapsDirectionsUrl({
|
|
59950
60615
|
addressText,
|
|
59951
60616
|
location
|
|
59952
|
-
});
|
|
59953
|
-
|
|
60617
|
+
}) : null;
|
|
60618
|
+
const hours$1 = props$1.showOpeningHours === false ? null : props$1.openingHours ?? null;
|
|
60619
|
+
if (![
|
|
60620
|
+
location,
|
|
60621
|
+
addressText,
|
|
60622
|
+
directionsUrl,
|
|
60623
|
+
hours$1
|
|
60624
|
+
].some(Boolean)) {
|
|
59954
60625
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
59955
60626
|
className: "rb-caption",
|
|
59956
60627
|
style: textColorStyle("mutedText"),
|
|
59957
|
-
children: unresolvedMessage ?? "Location details coming soon."
|
|
60628
|
+
children: props$1.unresolvedMessage ?? "Location details coming soon."
|
|
59958
60629
|
});
|
|
59959
60630
|
}
|
|
59960
60631
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -59972,15 +60643,11 @@ function LocationMapView({ addressText, location, zoom, heightPx, showAddressTex
|
|
|
59972
60643
|
style: textColorStyle("mutedText"),
|
|
59973
60644
|
children: addressText
|
|
59974
60645
|
}) : null,
|
|
59975
|
-
|
|
59976
|
-
|
|
59977
|
-
|
|
59978
|
-
rel: "noreferrer",
|
|
59979
|
-
variant: "ghost",
|
|
59980
|
-
size: "sm",
|
|
59981
|
-
extraClassName: "rb-w-fit",
|
|
60646
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpeningHoursTable, { hours: hours$1 }),
|
|
60647
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapDirections, {
|
|
60648
|
+
url: directionsUrl,
|
|
59982
60649
|
label: directionsLabel
|
|
59983
|
-
})
|
|
60650
|
+
})
|
|
59984
60651
|
]
|
|
59985
60652
|
});
|
|
59986
60653
|
}
|
|
@@ -59997,14 +60664,7 @@ function LocationMapSSR(props$1) {
|
|
|
59997
60664
|
children: [
|
|
59998
60665
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IslandPropsScript, { value: hydrationProps }),
|
|
59999
60666
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapView, {
|
|
60000
|
-
|
|
60001
|
-
location: normalized.location,
|
|
60002
|
-
zoom: normalized.zoom,
|
|
60003
|
-
heightPx: normalized.heightPx,
|
|
60004
|
-
showAddressText: normalized.showAddressText,
|
|
60005
|
-
showDirections: normalized.showDirections,
|
|
60006
|
-
directionsLabel: normalized.directionsLabel,
|
|
60007
|
-
unresolvedMessage: normalized.unresolvedMessage,
|
|
60667
|
+
...normalized,
|
|
60008
60668
|
renderMap: ({ addressText, className, height }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
60009
60669
|
className,
|
|
60010
60670
|
style: {
|
|
@@ -67189,7 +67849,8 @@ function arrangementContentFacts(content) {
|
|
|
67189
67849
|
photo: photoCount > 0,
|
|
67190
67850
|
facts: Array.isArray(content.facts) && content.facts.length > 0,
|
|
67191
67851
|
featured,
|
|
67192
|
-
outcome: typeof content.outcome === "string" && content.outcome.length > 0
|
|
67852
|
+
outcome: typeof content.outcome === "string" && content.outcome.length > 0,
|
|
67853
|
+
figure: typeof content.figure === "string" && content.figure.trim().length > 0
|
|
67193
67854
|
}
|
|
67194
67855
|
};
|
|
67195
67856
|
}
|
|
@@ -67349,7 +68010,7 @@ function resolveArrangementRoleSurfaces(look, runtime, background) {
|
|
|
67349
68010
|
}
|
|
67350
68011
|
/** The arrangement key is resolved once by planBlock, including pinned Looks. */
|
|
67351
68012
|
function heroPhotoGround(entry) {
|
|
67352
|
-
return entry.kind === "renderable" && entry.block.kind === "block.hero" ? { paintsGround: entry.effectiveArrangementKey
|
|
68013
|
+
return entry.kind === "renderable" && entry.block.kind === "block.hero" ? { paintsGround: heroPhotoPaintsGround(entry.effectiveArrangementKey ?? undefined) } : undefined;
|
|
67353
68014
|
}
|
|
67354
68015
|
/** Header consumers receive the opening that the public render plan actually admits. */
|
|
67355
68016
|
function resolvePageOpeningSection(page, options = {}) {
|
|
@@ -68470,7 +69131,7 @@ function compilePagePushCommands(input) {
|
|
|
68470
69131
|
});
|
|
68471
69132
|
}
|
|
68472
69133
|
function pageCommandRouting(diff) {
|
|
68473
|
-
const changedPages = diff.pages.filter(
|
|
69134
|
+
const changedPages = diff.pages.filter(hasPageOperations);
|
|
68474
69135
|
if (changedPages.length === 0) return { kind: "no_page_changes" };
|
|
68475
69136
|
return { kind: "command_backed" };
|
|
68476
69137
|
}
|
|
@@ -68562,7 +69223,7 @@ function pageCommandReportToSyncResult(report) {
|
|
|
68562
69223
|
});
|
|
68563
69224
|
}
|
|
68564
69225
|
function pageCommandsForDiff(input) {
|
|
68565
|
-
if (
|
|
69226
|
+
if (!hasPageOperations(input.pageDiff)) {
|
|
68566
69227
|
return ok(emptyPageCommandCompileFragment());
|
|
68567
69228
|
}
|
|
68568
69229
|
if (!input.localPage) {
|
|
@@ -68585,10 +69246,7 @@ function pageCommandsForDiff(input) {
|
|
|
68585
69246
|
input: {
|
|
68586
69247
|
identifier: localPageIdentifier,
|
|
68587
69248
|
slug: localPageIdentifier,
|
|
68588
|
-
|
|
68589
|
-
path: input.localPage.path,
|
|
68590
|
-
...input.localPage.seoTitle ? { seoTitle: input.localPage.seoTitle } : {},
|
|
68591
|
-
...input.localPage.seoDescription ? { seoDescription: input.localPage.seoDescription } : {},
|
|
69249
|
+
...pageMetadataForUpsert(input.localPage),
|
|
68592
69250
|
...input.localPage.status ? { status: input.localPage.status } : {}
|
|
68593
69251
|
}
|
|
68594
69252
|
};
|
|
@@ -78049,7 +78707,7 @@ async function loadConfig(configPath, output) {
|
|
|
78049
78707
|
return { errorMessage: "No config path provided." };
|
|
78050
78708
|
}
|
|
78051
78709
|
try {
|
|
78052
|
-
const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-
|
|
78710
|
+
const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-BRd0EUsF.mjs");
|
|
78053
78711
|
const rawConfig = await loadConfigFile$1(configPath);
|
|
78054
78712
|
const parsed = riverbankSiteConfigSchema.safeParse(rawConfig);
|
|
78055
78713
|
if (!parsed.success) {
|