riverbankcms 0.22.0 → 0.22.2
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 +1518 -842
- package/dist/{entryCommands-CoGu0G2R.mjs → entryCommands-BGVgMNMw.mjs} +187 -80
- package/dist/{eventUpsertInputSchema-B0ubhUu5.mjs → eventUpsertInputSchema-CdX--hHz.mjs} +2 -2
- package/dist/{load-config-j58KSqxl.mjs → load-config-BV9Ig2CH.mjs} +2 -2
- package/dist/load-config-JWz__Dkx.mjs +4 -0
- package/dist/{plan-C4IphkPc.mjs → plan-CFMj_Hee.mjs} +1 -1
- package/dist/scaffold/index.mjs +2 -2
- package/dist/{sdk-event-upsert-BqjzK2zT.mjs → sdk-event-upsert-zWw5VolM.mjs} +351 -133
- package/dist/{src-zzwJUef5.mjs → src-ZACBG29u.mjs} +143 -85
- 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-zWw5VolM.mjs";
|
|
3
|
+
import { $ as resolveBookingDisplayContext, $t as assertNever, A as DEFAULT_MAILING_LIST_SUCCESS_MESSAGE, At as deriveTotalTicketQuantity, B as parseWeeklyOpeningHours, Bt as resolvePricingOptionsPriceDisplay, Ct as getBookingInstalmentDepositRefundability, D as parseMailingListSignedSourceToken, Dt as splitAmountWithRemainderInFirst, E as parseMailingListContentVersionId, En as unsafeAsOccurrenceId, Et as omitZeroAmountFutureRows, F as DEFAULT_MAILING_LIST_TARGETING, Ft as publicEventPricingCurrency, G as selectCategoryView, Gt as parseNonNegativeCents, Hn as err, I as planMailingListChoicePresentation, It as publicEventPricingDisplay, J as formatDateTime, Jt as toNonNegativeCents, K as formatDate, Kt as parsePositiveCents, L as isCanonicalRichTextDoc, Lt as publicEventPricingOptions, M as parseFooterCompositionV1, Mt as formatBookingPriceDisplay, Nt as formatEventPricing, O as parseMailingListRuntimeContext, On as unsafeAsPassId, Ot as resolveFlexibleBalanceDueAt, P as parseMailingListPlacementTargeting, Pt as isPublicEventPricingOptionDisplayable, Q as inferSiteDateLocale, Qt as parseCurrencyCode, R as formatOpeningHoursRows, Rt as publicEventPricingType, S as parseManagementKey, St as clampConfiguredAmount, T as parseMailingListBlockId, Tn as unsafeAsMediaAssetId, Tt as getBookingInstalmentProtectedDepositAmountCents, U as normalizeLocationAddressText, Un as ok, Ut as mapReadonlyNonEmptyArray, V as assertAllowedPublicUrl, Vt as fromArray, W as toLocationCoordinates, Wt as isNonNegativeWholeCents$1, X as formatTime$1, Xt as unsafeAsPositiveCents, Y as formatDateTimeRange, Yt as unsafeAsNonNegativeCents, Z as formatTimeRange, Zt as formatCurrencyAmount, _ as orderedLiveRunSessions, _t as validateBookingPaymentOptionKinds, an as parseEventSeriesId, at as getLocalScheduleDate, b as createSecret, bt as isSettleableOrderInstalmentPlanStatus, c as resolveSiteVerticalBookingConfig, ct as parseBookingLocalDate, dn as parseSiteTermsVersionId, dt as resolveBookingBusinessTimeZone, en as formatDurationUnitLabel, et as buildBookingUtcDateWindow, f as SURFACE_EVENT_PRESET_VALUES, fn as parseUserId, ft as resolveBookingTimeZoneId, g as nextLiveRunSessionStartMs, gn as unsafeAsCheckoutLineId, h as CANCELLED_SESSION_STATUS, ht as toUtcIsoDateTimeString, in as parseDatedOfferingCapacityHoldId, it as getBookingLocalDateKey, j as parseMailingListProviderScope, jn as unsafeAsPricingOptionId, jt as parseEventPageSurfaceSubject, k as assessMailingListTargeting, kn as unsafeAsPositiveByteCount, kt as resolveFlexibleBalanceInitialPaymentCents, ln as parseRetiredCourseId, lt as parseLocalScheduleTime, mt as toScheduledBookingDateTime, n as EVENT_PRESET_VOCABULARY, nn as parseCustomerId, nt as formatLocalScheduleDate, ot as getLocalScheduleTime, p as WHOLE_SERIES_EVENT_PRESET_VALUES, pt as toBookingTimeZone, q as formatDateRange, qt as toCents, r as NAVIGATION_LOCATIONS, rn as parseDatedOfferingCapacityHoldAuditRef, rt as formatLocalScheduleTime, sn as parseMembershipId, tn as parseApiKeyId, tt as compareLocalScheduleDates, u as EVENT_PRESET_VALUES, un as parseSiteId, ut as parseUtcIsoDateTimeString, v as resolveWholeSeriesBookingPhase, vn as unsafeAsDemoCapability, vt as isLiveOrderInstalmentPlanStatus, w as slugify, wt as getBookingInstalmentPlanIntervalCount, x as exposeSecret, xn as unsafeAsEventInstanceId, xt as addIntervalPreservingMonthAnchor, y as resolveWholeSeriesRunLifecycle, yt as isSettleableFlexibleBalanceContractStatus, zt as resolveExactOrFreePriceDisplay } from "../src-ZACBG29u.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-BGVgMNMw.mjs";
|
|
5
|
+
import { r as CLI_VERSION, t as loadConfigFile } from "../load-config-BV9Ig2CH.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-CdX--hHz.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-CFMj_Hee.mjs";
|
|
8
8
|
import { config } from "dotenv";
|
|
9
9
|
import { Command, CommanderError } from "commander";
|
|
10
10
|
import * as fs$2 from "fs/promises";
|
|
@@ -5996,12 +5996,13 @@ function isAllowedTransformId(id) {
|
|
|
5996
5996
|
}
|
|
5997
5997
|
|
|
5998
5998
|
//#endregion
|
|
5999
|
-
//#region ../blocks/src/system/layout/
|
|
5999
|
+
//#region ../blocks/src/system/layout/repeaterGridModel.ts
|
|
6000
6000
|
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",
|
|
@@ -6136,16 +6137,10 @@ function withRepeaterGridSpanField(fields$1, options) {
|
|
|
6136
6137
|
return [createRepeaterGridSpanField(options), ...fields$1];
|
|
6137
6138
|
}
|
|
6138
6139
|
function withRepeaterGridPositionFields(fields$1, options) {
|
|
6139
|
-
let nextFields = [...fields$1];
|
|
6140
6140
|
const rowFieldId = resolveRepeaterGridRowFieldId(options?.row);
|
|
6141
|
-
|
|
6142
|
-
nextFields = [createRepeaterGridRowField(options?.row), ...nextFields];
|
|
6143
|
-
}
|
|
6141
|
+
const withRow = fields$1.some((field) => field.id === rowFieldId) ? [...fields$1] : [createRepeaterGridRowField(options?.row), ...fields$1];
|
|
6144
6142
|
const columnFieldId = resolveRepeaterGridColumnFieldId(options?.column);
|
|
6145
|
-
|
|
6146
|
-
nextFields = [createRepeaterGridColumnField(options?.column), ...nextFields];
|
|
6147
|
-
}
|
|
6148
|
-
return nextFields;
|
|
6143
|
+
return withRow.some((field) => field.id === columnFieldId) ? withRow : [createRepeaterGridColumnField(options?.column), ...withRow];
|
|
6149
6144
|
}
|
|
6150
6145
|
function withRepeaterGridSpanFieldOnItemTypes(itemTypes, options) {
|
|
6151
6146
|
const entries = Object.entries(itemTypes).map(([typeKey, itemType]) => {
|
|
@@ -6192,7 +6187,26 @@ function resolveRepeaterGridColumnsForBreakpoint(values, bindings, breakpoint) {
|
|
|
6192
6187
|
}
|
|
6193
6188
|
return MIN_COLUMNS;
|
|
6194
6189
|
}
|
|
6195
|
-
|
|
6190
|
+
/** Strict admission; rendering normalization never grants permission to persist. */
|
|
6191
|
+
function parseRepeaterGridInteger(value) {
|
|
6192
|
+
if (typeof value !== "number" && (typeof value !== "string" || !value.trim())) return null;
|
|
6193
|
+
const number = Number(value);
|
|
6194
|
+
return Number.isInteger(number) ? number : null;
|
|
6195
|
+
}
|
|
6196
|
+
function isAcceptedRepeaterGridSpan(value, columns, acceptedSpans$1) {
|
|
6197
|
+
const span = parseRepeaterGridInteger(value);
|
|
6198
|
+
return span != null && span >= 1 && span <= columns && (!acceptedSpans$1 || acceptedSpans$1.includes(span));
|
|
6199
|
+
}
|
|
6200
|
+
function resolveRepeaterGridAcceptedSpans(fields$1, spanField) {
|
|
6201
|
+
const field = fields$1.find((candidate) => candidate.id === spanField);
|
|
6202
|
+
return field?.type === "select" ? (field.options ?? []).map((option) => Number(option.value)) : undefined;
|
|
6203
|
+
}
|
|
6204
|
+
function normalizeRepeaterGridSpan(value, activeColumns, acceptedSpans$1) {
|
|
6205
|
+
if (acceptedSpans$1) {
|
|
6206
|
+
const valid = acceptedSpans$1.filter((span) => span <= activeColumns);
|
|
6207
|
+
const parsed$1 = parseRepeaterGridInteger(value);
|
|
6208
|
+
return parsed$1 != null && valid.includes(parsed$1) ? parsed$1 : valid.length ? Math.min(...valid) : 1;
|
|
6209
|
+
}
|
|
6196
6210
|
const parsed = normalizeInteger(value);
|
|
6197
6211
|
if (parsed == null) {
|
|
6198
6212
|
return 1;
|
|
@@ -6237,12 +6251,14 @@ function getOverlappingItemIds(input) {
|
|
|
6237
6251
|
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
6252
|
}
|
|
6239
6253
|
function normalizeInputItem(item, columns, sourceIndex) {
|
|
6240
|
-
const span = normalizeRepeaterGridSpan(item.span, columns);
|
|
6254
|
+
const span = normalizeRepeaterGridSpan(item.span, columns, item.acceptedSpans);
|
|
6241
6255
|
const row$1 = normalizeRepeaterGridRow(item.row);
|
|
6242
6256
|
const colStart = normalizeRepeaterGridColStart(item.colStart, columns, span);
|
|
6243
6257
|
const colEnd = colStart + span - 1;
|
|
6244
6258
|
return {
|
|
6245
6259
|
id: item.id,
|
|
6260
|
+
startNewRow: item.startNewRow,
|
|
6261
|
+
acceptedSpans: item.acceptedSpans,
|
|
6246
6262
|
sourceIndex,
|
|
6247
6263
|
span,
|
|
6248
6264
|
row: row$1,
|
|
@@ -6251,8 +6267,134 @@ function normalizeInputItem(item, columns, sourceIndex) {
|
|
|
6251
6267
|
startCell: toRowCellKey(row$1, colStart, columns)
|
|
6252
6268
|
};
|
|
6253
6269
|
}
|
|
6270
|
+
/** Ordered, non-dense placement. Rendering clamps widths; admission checks originals separately. */
|
|
6271
|
+
function flowRepeaterGridItems(items, columns) {
|
|
6272
|
+
const count = normalizeRepeaterGridColumns(columns);
|
|
6273
|
+
return items.reduce((placed, item) => {
|
|
6274
|
+
const span = normalizeRepeaterGridSpan(item.span, count);
|
|
6275
|
+
const previous = placed.at(-1);
|
|
6276
|
+
const nextColumn = previous ? previous.colStart + previous.span : 1;
|
|
6277
|
+
const wraps = previous != null && (item.startNewRow === true || nextColumn + span - 1 > count);
|
|
6278
|
+
return [...placed, {
|
|
6279
|
+
...item,
|
|
6280
|
+
span,
|
|
6281
|
+
row: (previous?.row ?? 1) + (wraps ? 1 : 0),
|
|
6282
|
+
colStart: wraps ? 1 : nextColumn
|
|
6283
|
+
}];
|
|
6284
|
+
}, []);
|
|
6285
|
+
}
|
|
6286
|
+
/** @internal */
|
|
6287
|
+
function orderedGridItems(layout) {
|
|
6288
|
+
return [...layout.placements].sort((a$1, b$1) => a$1.sourceIndex - b$1.sourceIndex);
|
|
6289
|
+
}
|
|
6290
|
+
function isRepeaterGridLayoutInvalid(layout) {
|
|
6291
|
+
return layout.hasInvalidItems || layout.hasCollisions || layout.overCapacity;
|
|
6292
|
+
}
|
|
6293
|
+
function hasInvalidGridItems(items, columns, policy) {
|
|
6294
|
+
const flow = policy === "flow" ? flowRepeaterGridItems(items, columns) : null;
|
|
6295
|
+
return items.some((item, index) => !isValidGridItemGeometry(item, columns) || flow != null && (item.row !== flow[index]?.row || item.colStart !== flow[index]?.colStart));
|
|
6296
|
+
}
|
|
6297
|
+
function isValidGridItemGeometry(item, columns) {
|
|
6298
|
+
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;
|
|
6299
|
+
}
|
|
6300
|
+
function findFlowAppendPlacement(layout, span, startNewRow) {
|
|
6301
|
+
const next = flowRepeaterGridItems([...orderedGridItems(layout), {
|
|
6302
|
+
id: "new",
|
|
6303
|
+
span,
|
|
6304
|
+
row: 1,
|
|
6305
|
+
colStart: 1,
|
|
6306
|
+
startNewRow
|
|
6307
|
+
}], layout.columns).at(-1);
|
|
6308
|
+
return !isRepeaterGridLayoutInvalid(layout) && next && (layout.maxRows == null || next.row <= layout.maxRows) ? {
|
|
6309
|
+
row: next.row,
|
|
6310
|
+
colStart: next.colStart
|
|
6311
|
+
} : null;
|
|
6312
|
+
}
|
|
6313
|
+
/** @internal */
|
|
6314
|
+
function planFlowItems(layout, items) {
|
|
6315
|
+
const placed = flowRepeaterGridItems(items, layout.columns);
|
|
6316
|
+
if (isRepeaterGridLayoutInvalid(layout) || placed.some((item) => !isAcceptedRepeaterGridSpan(item.span, layout.columns, item.acceptedSpans) || layout.maxRows != null && item.row > layout.maxRows)) return { kind: "blocked" };
|
|
6317
|
+
const [first, ...rest] = placed.map(({ id, row: row$1, colStart, span }) => ({
|
|
6318
|
+
id,
|
|
6319
|
+
row: row$1,
|
|
6320
|
+
colStart,
|
|
6321
|
+
span
|
|
6322
|
+
}));
|
|
6323
|
+
return first ? {
|
|
6324
|
+
kind: "move",
|
|
6325
|
+
updates: [first, ...rest]
|
|
6326
|
+
} : { kind: "unchanged" };
|
|
6327
|
+
}
|
|
6328
|
+
/** Insertion reorder, with a complete coordinate write for the resulting order. */
|
|
6329
|
+
function planRepeaterGridReorder(layout, id, to, interaction = "step") {
|
|
6330
|
+
if (layout.placementPolicy !== "flow") return { kind: "blocked" };
|
|
6331
|
+
const items = orderedGridItems(layout);
|
|
6332
|
+
const from = items.findIndex((item) => item.id === id);
|
|
6333
|
+
if (from < 0 || to < 0 || to >= items.length) return { kind: "blocked" };
|
|
6334
|
+
if (from === to) return { kind: "unchanged" };
|
|
6335
|
+
const active = items[from];
|
|
6336
|
+
if (!active) return { kind: "blocked" };
|
|
6337
|
+
return decideFlowReorder({
|
|
6338
|
+
layout,
|
|
6339
|
+
items,
|
|
6340
|
+
active,
|
|
6341
|
+
from,
|
|
6342
|
+
to,
|
|
6343
|
+
interaction
|
|
6344
|
+
});
|
|
6345
|
+
}
|
|
6346
|
+
function decideFlowReorder(input) {
|
|
6347
|
+
const { layout, items, active, from, to, interaction } = input;
|
|
6348
|
+
const id = active.id;
|
|
6349
|
+
const remaining = items.filter((item) => item.id !== id);
|
|
6350
|
+
const inserted = [
|
|
6351
|
+
...remaining.slice(0, to),
|
|
6352
|
+
active,
|
|
6353
|
+
...remaining.slice(to)
|
|
6354
|
+
];
|
|
6355
|
+
const clearRowBreak = interaction === "drag" && active.startNewRow === true && dragInsertsWithinRow(items, from, to, layout.columns);
|
|
6356
|
+
const nextItems = clearRowBreak ? inserted.map((item) => item.id === id ? {
|
|
6357
|
+
...item,
|
|
6358
|
+
startNewRow: false
|
|
6359
|
+
} : item) : inserted;
|
|
6360
|
+
const decision = planFlowItems(layout, nextItems);
|
|
6361
|
+
return decision.kind === "move" ? {
|
|
6362
|
+
...decision,
|
|
6363
|
+
reorder: {
|
|
6364
|
+
id,
|
|
6365
|
+
from,
|
|
6366
|
+
to
|
|
6367
|
+
},
|
|
6368
|
+
...clearRowBreak ? { startNewRowUpdate: {
|
|
6369
|
+
id,
|
|
6370
|
+
value: false
|
|
6371
|
+
} } : {}
|
|
6372
|
+
} : decision;
|
|
6373
|
+
}
|
|
6374
|
+
/** Read the insertion bar position, independently of the dragged width. */
|
|
6375
|
+
function dragInsertsWithinRow(items, from, to, columns) {
|
|
6376
|
+
const target = items[to];
|
|
6377
|
+
if (!target) return false;
|
|
6378
|
+
const column = from < to ? target.colEnd + 1 : target.colStart;
|
|
6379
|
+
return column > 1 && column <= columns;
|
|
6380
|
+
}
|
|
6381
|
+
function planRepeaterGridStartNewRow(layout, id, value) {
|
|
6382
|
+
const active = layout.byId[id];
|
|
6383
|
+
if (layout.placementPolicy !== "flow" || !active) return { kind: "blocked" };
|
|
6384
|
+
const decision = planFlowItems(layout, orderedGridItems(layout).map((item) => item.id === id ? {
|
|
6385
|
+
...item,
|
|
6386
|
+
startNewRow: value
|
|
6387
|
+
} : item));
|
|
6388
|
+
return decision.kind === "move" ? {
|
|
6389
|
+
...decision,
|
|
6390
|
+
startNewRowUpdate: {
|
|
6391
|
+
id,
|
|
6392
|
+
value
|
|
6393
|
+
}
|
|
6394
|
+
} : decision;
|
|
6395
|
+
}
|
|
6254
6396
|
function buildRepeaterGridLayout(input) {
|
|
6255
|
-
const columns =
|
|
6397
|
+
const columns = normalizeRepeaterGridColumns(input.columns);
|
|
6256
6398
|
const maxRows = input.maxRows != null ? Math.max(1, Math.trunc(input.maxRows)) : undefined;
|
|
6257
6399
|
const capacityCells = maxRows != null ? maxRows * columns : undefined;
|
|
6258
6400
|
const placements = input.items.map((item, sourceIndex) => normalizeInputItem(item, columns, sourceIndex)).sort((a$1, b$1) => {
|
|
@@ -6265,55 +6407,58 @@ function buildRepeaterGridLayout(input) {
|
|
|
6265
6407
|
const { hasCollisions } = buildOccupancyByCell(placements, columns);
|
|
6266
6408
|
const overCapacity = maxRows != null && maxRowUsed > maxRows;
|
|
6267
6409
|
return {
|
|
6410
|
+
placementPolicy: input.placementPolicy,
|
|
6411
|
+
sourceItems: input.items.map((item) => ({ ...item })),
|
|
6268
6412
|
columns,
|
|
6269
6413
|
maxRows,
|
|
6270
6414
|
capacityCells,
|
|
6271
6415
|
maxRowUsed,
|
|
6272
6416
|
overCapacity,
|
|
6273
6417
|
hasCollisions,
|
|
6418
|
+
hasInvalidItems: hasInvalidGridItems(input.items, columns, input.placementPolicy),
|
|
6274
6419
|
placements,
|
|
6275
6420
|
byId
|
|
6276
6421
|
};
|
|
6277
6422
|
}
|
|
6278
6423
|
function findFirstAvailableRepeaterGridPlacement(input) {
|
|
6279
|
-
const columns =
|
|
6424
|
+
const columns = normalizeRepeaterGridColumns(input.columns);
|
|
6280
6425
|
const maxRows = input.maxRows != null ? Math.max(1, Math.trunc(input.maxRows)) : undefined;
|
|
6281
|
-
|
|
6426
|
+
if (!isAcceptedRepeaterGridSpan(input.newItemSpan, columns, input.acceptedSpans)) return null;
|
|
6427
|
+
const span = normalizeRepeaterGridSpan(input.newItemSpan, columns, input.acceptedSpans);
|
|
6282
6428
|
const layout = buildRepeaterGridLayout({
|
|
6283
6429
|
items: input.items,
|
|
6284
6430
|
columns,
|
|
6285
|
-
maxRows
|
|
6431
|
+
maxRows,
|
|
6432
|
+
placementPolicy: input.placementPolicy
|
|
6286
6433
|
});
|
|
6434
|
+
if (input.placementPolicy === "flow") return findFlowAppendPlacement(layout, span, input.startNewRow);
|
|
6287
6435
|
const { occupancy } = buildOccupancyByCell(layout.placements, columns);
|
|
6288
6436
|
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;
|
|
6437
|
+
if (isRepeaterGridLayoutInvalid(layout)) return null;
|
|
6438
|
+
const maxColStart = columns - span + 1;
|
|
6439
|
+
return Array.from({ length: rowLimit * maxColStart }, (_$1, index) => ({
|
|
6440
|
+
row: Math.floor(index / maxColStart) + 1,
|
|
6441
|
+
colStart: index % maxColStart + 1
|
|
6442
|
+
})).find(({ row: row$1, colStart }) => getOverlappingItemIds({
|
|
6443
|
+
occupancy,
|
|
6444
|
+
row: row$1,
|
|
6445
|
+
colStart,
|
|
6446
|
+
span,
|
|
6447
|
+
columns
|
|
6448
|
+
}).size === 0) ?? null;
|
|
6308
6449
|
}
|
|
6309
6450
|
function canAppendRepeaterGridItem(input) {
|
|
6310
6451
|
return findFirstAvailableRepeaterGridPlacement({
|
|
6311
6452
|
items: input.items,
|
|
6312
6453
|
newItemSpan: input.newItemSpan,
|
|
6454
|
+
acceptedSpans: input.acceptedSpans,
|
|
6313
6455
|
columns: input.columns,
|
|
6314
6456
|
maxRows: input.maxRows
|
|
6315
6457
|
}) != null;
|
|
6316
6458
|
}
|
|
6459
|
+
|
|
6460
|
+
//#endregion
|
|
6461
|
+
//#region ../blocks/src/system/layout/repeaterGrid.ts
|
|
6317
6462
|
function placementsOverlap(left, right) {
|
|
6318
6463
|
return left.row === right.row && left.colStart < right.colStart + right.span && right.colStart < left.colStart + left.span;
|
|
6319
6464
|
}
|
|
@@ -6333,10 +6478,44 @@ function swapPositionUpdates(active, target) {
|
|
|
6333
6478
|
span: target.span
|
|
6334
6479
|
}];
|
|
6335
6480
|
}
|
|
6481
|
+
/** Admission retains raw authoring geometry; display-only callers may supply placements alone. */
|
|
6482
|
+
function sourceGridItems(layout) {
|
|
6483
|
+
return layout.sourceItems ?? layout.placements;
|
|
6484
|
+
}
|
|
6485
|
+
/** Repair edits may remove existing defects, but cannot introduce another one. */
|
|
6486
|
+
function gridDefects(layout) {
|
|
6487
|
+
const geometry = sourceGridItems(layout).flatMap((item) => [
|
|
6488
|
+
...!isAcceptedRepeaterGridSpan(item.span, layout.columns, item.acceptedSpans) ? [`span:${item.id}`] : [],
|
|
6489
|
+
...!Number.isInteger(item.row) || item.row < 1 ? [`row:${item.id}`] : [],
|
|
6490
|
+
...!Number.isInteger(item.colStart) || item.colStart < 1 || item.colStart + item.span - 1 > layout.columns ? [`column:${item.id}`] : []
|
|
6491
|
+
]);
|
|
6492
|
+
const collisions = layout.placements.flatMap((item, index) => layout.placements.slice(index + 1).filter((other) => placementsOverlap(item, other)).map((other) => `collision:${[item.id, other.id].sort().join(":")}`));
|
|
6493
|
+
const capacity = layout.placements.filter((item) => layout.maxRows != null && item.row > layout.maxRows).map((item) => `capacity:${item.id}`);
|
|
6494
|
+
return new Set([
|
|
6495
|
+
...geometry,
|
|
6496
|
+
...collisions,
|
|
6497
|
+
...capacity,
|
|
6498
|
+
...(layout.invalidCoordinateIds ?? []).map((id) => `coordinate:${id}`)
|
|
6499
|
+
]);
|
|
6500
|
+
}
|
|
6336
6501
|
function validateGridMove(layout, updates) {
|
|
6337
|
-
const
|
|
6338
|
-
|
|
6339
|
-
|
|
6502
|
+
const items = sourceGridItems(layout).map((item) => ({
|
|
6503
|
+
...item,
|
|
6504
|
+
...updates.find((update) => update.id === item.id)
|
|
6505
|
+
}));
|
|
6506
|
+
const candidate = buildRepeaterGridLayout({
|
|
6507
|
+
items,
|
|
6508
|
+
columns: layout.columns,
|
|
6509
|
+
maxRows: layout.maxRows,
|
|
6510
|
+
placementPolicy: layout.placementPolicy
|
|
6511
|
+
});
|
|
6512
|
+
const unresolved = (layout.invalidCoordinateIds ?? []).filter((id) => !updates.some((update) => update.id === id));
|
|
6513
|
+
const before = gridDefects(layout);
|
|
6514
|
+
const after = gridDefects({
|
|
6515
|
+
...candidate,
|
|
6516
|
+
invalidCoordinateIds: unresolved
|
|
6517
|
+
});
|
|
6518
|
+
const valid = before.size === 0 ? after.size === 0 : after.size < before.size && [...after].every((defect) => before.has(defect));
|
|
6340
6519
|
return valid ? {
|
|
6341
6520
|
kind: "move",
|
|
6342
6521
|
updates
|
|
@@ -6347,7 +6526,7 @@ function decideGridDrop(layout, active, destination) {
|
|
|
6347
6526
|
if (occupants.length > 1) return { kind: "blocked" };
|
|
6348
6527
|
const target = occupants[0];
|
|
6349
6528
|
if (target) return validateGridMove(layout, swapPositionUpdates(active, target));
|
|
6350
|
-
if (destination.row === active.row && destination.colStart === active.colStart) return { kind: "unchanged" };
|
|
6529
|
+
if (destination.row === active.row && destination.colStart === active.colStart && !isRepeaterGridLayoutInvalid(layout)) return { kind: "unchanged" };
|
|
6351
6530
|
return validateGridMove(layout, [{
|
|
6352
6531
|
id: active.id,
|
|
6353
6532
|
row: destination.row,
|
|
@@ -6358,9 +6537,16 @@ function decideGridDrop(layout, active, destination) {
|
|
|
6358
6537
|
function buildRepeaterGridDropTargets(input) {
|
|
6359
6538
|
const { layout, draggedId, rowsToRender } = input;
|
|
6360
6539
|
const active = layout.byId[draggedId];
|
|
6361
|
-
if (!active) return [];
|
|
6540
|
+
if (!active || layout.placementPolicy === "flow" && isRepeaterGridLayoutInvalid(layout)) return [];
|
|
6541
|
+
if (layout.placementPolicy === "flow") return orderedGridItems(layout).map((item, index) => ({
|
|
6542
|
+
id: `repeater-grid-drop-${item.row}-${item.colStart}`,
|
|
6543
|
+
row: item.row,
|
|
6544
|
+
colStart: item.colStart,
|
|
6545
|
+
cell: item.startCell,
|
|
6546
|
+
decision: planRepeaterGridReorder(layout, draggedId, index, input.interaction ?? "drag")
|
|
6547
|
+
}));
|
|
6362
6548
|
const rowCeiling = layout.maxRows ?? Math.max(1, rowsToRender ?? layout.maxRowUsed + 1, active.row + 1);
|
|
6363
|
-
|
|
6549
|
+
const targets = Array.from({ length: rowCeiling * layout.columns }, (_$1, index) => {
|
|
6364
6550
|
const row$1 = Math.floor(index / layout.columns) + 1;
|
|
6365
6551
|
const colStart = index % layout.columns + 1;
|
|
6366
6552
|
return {
|
|
@@ -6374,6 +6560,205 @@ function buildRepeaterGridDropTargets(input) {
|
|
|
6374
6560
|
})
|
|
6375
6561
|
};
|
|
6376
6562
|
});
|
|
6563
|
+
return targets.some((target) => target.row === active.row && target.colStart === active.colStart) ? targets : [...targets, {
|
|
6564
|
+
id: `repeater-grid-drop-${active.row}-${active.colStart}`,
|
|
6565
|
+
row: active.row,
|
|
6566
|
+
colStart: active.colStart,
|
|
6567
|
+
cell: active.startCell,
|
|
6568
|
+
decision: { kind: "unchanged" }
|
|
6569
|
+
}];
|
|
6570
|
+
}
|
|
6571
|
+
/** Width edits keep the item's start when it fits; otherwise relocate it to the first free cell.
|
|
6572
|
+
* Neighbours keep their positions. A full bounded grid blocks the change without partial writes.
|
|
6573
|
+
*/
|
|
6574
|
+
function planRepeaterGridSpanChange(input) {
|
|
6575
|
+
const { layout, id, span } = input;
|
|
6576
|
+
const active = layout.byId[id];
|
|
6577
|
+
if (layout.placementPolicy === "flow" && isRepeaterGridLayoutInvalid(layout)) return { kind: "blocked" };
|
|
6578
|
+
if (!active || !isAcceptedRepeaterGridSpan(span, layout.columns, active.acceptedSpans)) return { kind: "blocked" };
|
|
6579
|
+
const nextSpan = Number(span);
|
|
6580
|
+
if (!isRepeaterGridLayoutInvalid(layout) && sourceGridItems(layout).find((item) => item.id === id)?.span === nextSpan) return { kind: "unchanged" };
|
|
6581
|
+
if (layout.placementPolicy === "flow") return planFlowItems(layout, orderedGridItems(layout).map((item) => item.id === id ? {
|
|
6582
|
+
...item,
|
|
6583
|
+
span: nextSpan
|
|
6584
|
+
} : item));
|
|
6585
|
+
return planFreeGridSpanChange(layout, active, nextSpan);
|
|
6586
|
+
}
|
|
6587
|
+
/** Free width edits retain the current start when possible, then use the shared first-free planner. */
|
|
6588
|
+
function planFreeGridSpanChange(layout, active, nextSpan) {
|
|
6589
|
+
const id = active.id;
|
|
6590
|
+
const atCurrent = validateGridMove(layout, [{
|
|
6591
|
+
id,
|
|
6592
|
+
span: nextSpan,
|
|
6593
|
+
row: active.row,
|
|
6594
|
+
colStart: active.colStart
|
|
6595
|
+
}]);
|
|
6596
|
+
if (atCurrent.kind === "move") return atCurrent;
|
|
6597
|
+
const destination = findFirstAvailableRepeaterGridPlacement({
|
|
6598
|
+
items: layout.placements.filter((item) => item.id !== id),
|
|
6599
|
+
newItemSpan: nextSpan,
|
|
6600
|
+
acceptedSpans: active.acceptedSpans,
|
|
6601
|
+
columns: layout.columns,
|
|
6602
|
+
maxRows: layout.maxRows
|
|
6603
|
+
});
|
|
6604
|
+
return destination ? validateGridMove(layout, [{
|
|
6605
|
+
id,
|
|
6606
|
+
span: nextSpan,
|
|
6607
|
+
...destination
|
|
6608
|
+
}]) : { kind: "blocked" };
|
|
6609
|
+
}
|
|
6610
|
+
/** Narrow rendering is a projection only. Never feed these placements into an authoring write. */
|
|
6611
|
+
function projectRepeaterGridLayout(layout, columns) {
|
|
6612
|
+
if (isRepeaterGridLayoutInvalid(layout)) return projectRepeaterGridLayoutForRendering(layout, columns);
|
|
6613
|
+
if (columns === layout.columns) return layout;
|
|
6614
|
+
if (layout.placementPolicy === "flow") return buildProjectedRepeaterGridLayout(layout, flowRepeaterGridItems(orderedGridItems(layout), columns), columns);
|
|
6615
|
+
const items = layout.placements.reduce((placed, item) => {
|
|
6616
|
+
const span = normalizeRepeaterGridSpan(item.span, columns);
|
|
6617
|
+
const destination = findFirstAvailableRepeaterGridPlacement({
|
|
6618
|
+
items: placed,
|
|
6619
|
+
newItemSpan: span,
|
|
6620
|
+
columns
|
|
6621
|
+
});
|
|
6622
|
+
return [...placed, {
|
|
6623
|
+
id: item.id,
|
|
6624
|
+
span,
|
|
6625
|
+
row: destination?.row ?? placed.length + 1,
|
|
6626
|
+
colStart: destination?.colStart ?? 1
|
|
6627
|
+
}];
|
|
6628
|
+
}, []);
|
|
6629
|
+
return buildProjectedRepeaterGridLayout(layout, items, columns);
|
|
6630
|
+
}
|
|
6631
|
+
function buildProjectedRepeaterGridLayout(source, items, columns) {
|
|
6632
|
+
const projected = buildRepeaterGridLayout({
|
|
6633
|
+
items: items.map(({ id, span, row: row$1, colStart, startNewRow }) => ({
|
|
6634
|
+
id,
|
|
6635
|
+
span,
|
|
6636
|
+
row: row$1,
|
|
6637
|
+
colStart,
|
|
6638
|
+
startNewRow
|
|
6639
|
+
})),
|
|
6640
|
+
columns,
|
|
6641
|
+
placementPolicy: source.placementPolicy === "flow" || isRepeaterGridLayoutInvalid(source) ? "flow" : source.placementPolicy
|
|
6642
|
+
});
|
|
6643
|
+
const placements = projected.placements.map((item) => ({
|
|
6644
|
+
...item,
|
|
6645
|
+
sourceIndex: source.byId[item.id]?.sourceIndex ?? item.sourceIndex
|
|
6646
|
+
}));
|
|
6647
|
+
return {
|
|
6648
|
+
...projected,
|
|
6649
|
+
placements,
|
|
6650
|
+
byId: Object.fromEntries(placements.map((item) => [item.id, item]))
|
|
6651
|
+
};
|
|
6652
|
+
}
|
|
6653
|
+
/** Public fallback: preserve saved array order, use non-dense auto-placement, and ignore authoring capacity. */
|
|
6654
|
+
function projectRepeaterGridLayoutForRendering(layout, columns = layout.columns) {
|
|
6655
|
+
if (!isRepeaterGridLayoutInvalid(layout)) {
|
|
6656
|
+
return projectRepeaterGridLayout(layout, columns);
|
|
6657
|
+
}
|
|
6658
|
+
const count = normalizeRepeaterGridColumns(columns);
|
|
6659
|
+
return buildProjectedRepeaterGridLayout(layout, flowRepeaterGridItems(orderedGridItems(layout), count), count);
|
|
6660
|
+
}
|
|
6661
|
+
/** An explicit column reduction re-places free grids through the existing placement primitive. */
|
|
6662
|
+
function planRepeaterGridColumnChange(layout, columns) {
|
|
6663
|
+
if (layout.placementPolicy === "flow" || columns >= layout.columns) return { kind: "unchanged" };
|
|
6664
|
+
if (isRepeaterGridLayoutInvalid(layout)) return { kind: "blocked" };
|
|
6665
|
+
const placed = orderedGridItems(layout).reduce((items, item) => {
|
|
6666
|
+
if (!items) return null;
|
|
6667
|
+
const bounded = normalizeRepeaterGridSpan(item.span, columns);
|
|
6668
|
+
const span = item.acceptedSpans ? Math.max(0, ...item.acceptedSpans.filter((width) => width <= bounded)) : bounded;
|
|
6669
|
+
const destination = findFirstAvailableRepeaterGridPlacement({
|
|
6670
|
+
items,
|
|
6671
|
+
columns,
|
|
6672
|
+
maxRows: layout.maxRows,
|
|
6673
|
+
newItemSpan: span,
|
|
6674
|
+
acceptedSpans: item.acceptedSpans
|
|
6675
|
+
});
|
|
6676
|
+
return destination ? [...items, {
|
|
6677
|
+
...item,
|
|
6678
|
+
span,
|
|
6679
|
+
...destination
|
|
6680
|
+
}] : null;
|
|
6681
|
+
}, []);
|
|
6682
|
+
const [first, ...rest] = placed ?? [];
|
|
6683
|
+
return first ? {
|
|
6684
|
+
kind: "move",
|
|
6685
|
+
updates: [first, ...rest]
|
|
6686
|
+
} : placed ? { kind: "unchanged" } : { kind: "blocked" };
|
|
6687
|
+
}
|
|
6688
|
+
|
|
6689
|
+
//#endregion
|
|
6690
|
+
//#region ../blocks/src/system/manifest/layoutGridConfiguration.ts
|
|
6691
|
+
const itemFieldsSchema = z.object({ fields: z.array(z.object({
|
|
6692
|
+
id: z.string(),
|
|
6693
|
+
type: z.string(),
|
|
6694
|
+
defaultValue: z.unknown().optional(),
|
|
6695
|
+
options: z.array(z.object({ value: z.string() })).optional(),
|
|
6696
|
+
multiple: z.boolean().optional(),
|
|
6697
|
+
source: z.object({ kind: z.string() }).optional()
|
|
6698
|
+
})) });
|
|
6699
|
+
function validateSpanSelect(span, columns, ctx) {
|
|
6700
|
+
if (span.type !== "select") return;
|
|
6701
|
+
const options = span.options ?? [];
|
|
6702
|
+
const invalidOptions = options.some((option) => !isAcceptedRepeaterGridSpan(option.value, columns) || String(Number(option.value)) !== option.value);
|
|
6703
|
+
if (span.multiple || options.length === 0 || invalidOptions || span.source && span.source.kind !== "static") {
|
|
6704
|
+
ctx.addIssue({
|
|
6705
|
+
code: "custom",
|
|
6706
|
+
path: ["ui", "layoutGridSpanField"],
|
|
6707
|
+
message: `Layout-grid span select must have single, static integer options within 1..${columns}`
|
|
6708
|
+
});
|
|
6709
|
+
}
|
|
6710
|
+
if (span.defaultValue !== undefined && !options.some((option) => option.value === span.defaultValue)) {
|
|
6711
|
+
ctx.addIssue({
|
|
6712
|
+
code: "custom",
|
|
6713
|
+
path: ["ui", "layoutGridSpanField"],
|
|
6714
|
+
message: "Layout-grid default span must be one of the span select options"
|
|
6715
|
+
});
|
|
6716
|
+
}
|
|
6717
|
+
}
|
|
6718
|
+
/** Both monomorphic and polymorphic item schemas have the same layout contract. */
|
|
6719
|
+
function validateLayoutGridConfiguration(data, ctx) {
|
|
6720
|
+
const ui = data.ui;
|
|
6721
|
+
if (ui?.repeaterPreset !== "layoutGrid") return;
|
|
6722
|
+
if (ui.layoutGridColumns !== undefined === (ui.layoutGridColumnsFields !== undefined)) {
|
|
6723
|
+
ctx.addIssue({
|
|
6724
|
+
code: "custom",
|
|
6725
|
+
path: ["ui", "layoutGridColumns"],
|
|
6726
|
+
message: "Layout-grid requires exactly one of ui.layoutGridColumns or ui.layoutGridColumnsFields.lg; do not set both"
|
|
6727
|
+
});
|
|
6728
|
+
}
|
|
6729
|
+
const spanId = resolveRepeaterGridSpanFieldId({ id: ui.layoutGridSpanField });
|
|
6730
|
+
const requiredIds = [
|
|
6731
|
+
spanId,
|
|
6732
|
+
resolveRepeaterGridRowFieldId({ id: ui.layoutGridRowField }),
|
|
6733
|
+
resolveRepeaterGridColumnFieldId({ id: ui.layoutGridColumnField })
|
|
6734
|
+
];
|
|
6735
|
+
const schemas = data.polymorphic && data.itemTypes ? Object.values(data.itemTypes) : [data.schema];
|
|
6736
|
+
schemas.forEach((schema) => {
|
|
6737
|
+
const parsed = itemFieldsSchema.safeParse(schema);
|
|
6738
|
+
if (!parsed.success) return;
|
|
6739
|
+
if (!requiredIds.every((id) => parsed.data.fields.some((field) => field.id === id))) {
|
|
6740
|
+
ctx.addIssue({
|
|
6741
|
+
code: "custom",
|
|
6742
|
+
path: ["ui", "layoutGridRowField"],
|
|
6743
|
+
message: `layoutGrid repeaters require span/row/column fields (${requiredIds.join(", ")}) to exist in repeater item fields`
|
|
6744
|
+
});
|
|
6745
|
+
}
|
|
6746
|
+
if (ui.layoutGridStartNewRowField && !parsed.data.fields.some((field) => field.id === ui.layoutGridStartNewRowField && field.type === "boolean")) {
|
|
6747
|
+
ctx.addIssue({
|
|
6748
|
+
code: "custom",
|
|
6749
|
+
path: ["ui", "layoutGridStartNewRowField"],
|
|
6750
|
+
message: "Layout-grid Start a new row field must reference a boolean item field"
|
|
6751
|
+
});
|
|
6752
|
+
}
|
|
6753
|
+
if (ui.layoutGridStartNewRowField && ui.layoutGridColumns === undefined) {
|
|
6754
|
+
ctx.addIssue({
|
|
6755
|
+
code: "custom",
|
|
6756
|
+
path: ["ui", "layoutGridStartNewRowField"],
|
|
6757
|
+
message: "Layout-grid Start a new row requires fixed columns (flow placement)"
|
|
6758
|
+
});
|
|
6759
|
+
}
|
|
6760
|
+
parsed.data.fields.filter((field) => field.id === spanId).forEach((span) => validateSpanSelect(span, ui.layoutGridColumns ?? MAX_REPEATER_GRID_COLUMNS, ctx));
|
|
6761
|
+
});
|
|
6377
6762
|
}
|
|
6378
6763
|
|
|
6379
6764
|
//#endregion
|
|
@@ -6560,6 +6945,14 @@ const uiSchema = z.object({
|
|
|
6560
6945
|
thumbnailLabelField: z.string().optional(),
|
|
6561
6946
|
thumbnailAspectRatio: z.string().optional(),
|
|
6562
6947
|
thumbnailCardDensity: z.enum(["compact", "comfortable"]).optional(),
|
|
6948
|
+
layoutGridColumns: z.union([
|
|
6949
|
+
z.literal(1),
|
|
6950
|
+
z.literal(2),
|
|
6951
|
+
z.literal(3),
|
|
6952
|
+
z.literal(4),
|
|
6953
|
+
z.literal(5),
|
|
6954
|
+
z.literal(6)
|
|
6955
|
+
]).optional(),
|
|
6563
6956
|
layoutGridColumnsFields: z.object({
|
|
6564
6957
|
base: z.string().optional(),
|
|
6565
6958
|
sm: z.string().optional(),
|
|
@@ -6568,6 +6961,7 @@ const uiSchema = z.object({
|
|
|
6568
6961
|
xl: z.string().optional()
|
|
6569
6962
|
}).optional(),
|
|
6570
6963
|
layoutGridSpanField: z.string().optional(),
|
|
6964
|
+
layoutGridStartNewRowField: z.string().optional(),
|
|
6571
6965
|
layoutGridRowField: z.string().optional(),
|
|
6572
6966
|
layoutGridColumnField: z.string().optional(),
|
|
6573
6967
|
layoutGridMaxRows: z.number().int().positive().optional(),
|
|
@@ -6589,7 +6983,26 @@ const uiSchema = z.object({
|
|
|
6589
6983
|
"style"
|
|
6590
6984
|
]).optional(),
|
|
6591
6985
|
valueContract: z.enum(["boxBackground"]).optional()
|
|
6592
|
-
}).partial()
|
|
6986
|
+
}).partial().superRefine((ui, ctx) => {
|
|
6987
|
+
if (ui.layoutGridColumns !== undefined && ui.layoutGridColumnsFields !== undefined) {
|
|
6988
|
+
ctx.addIssue({
|
|
6989
|
+
code: "custom",
|
|
6990
|
+
path: ["layoutGridColumns"],
|
|
6991
|
+
message: "Layout-grid requires exactly one of ui.layoutGridColumns or ui.layoutGridColumnsFields.lg; do not set both"
|
|
6992
|
+
});
|
|
6993
|
+
}
|
|
6994
|
+
}).transform((input) => {
|
|
6995
|
+
const { layoutGridColumns, layoutGridColumnsFields, ...ui } = input;
|
|
6996
|
+
if (layoutGridColumns !== undefined) return {
|
|
6997
|
+
...ui,
|
|
6998
|
+
layoutGridColumns
|
|
6999
|
+
};
|
|
7000
|
+
if (layoutGridColumnsFields !== undefined) return {
|
|
7001
|
+
...ui,
|
|
7002
|
+
layoutGridColumnsFields
|
|
7003
|
+
};
|
|
7004
|
+
return ui;
|
|
7005
|
+
});
|
|
6593
7006
|
const baseFieldSchema = z.object({
|
|
6594
7007
|
id: z.string().min(1, "Field id is required"),
|
|
6595
7008
|
label: z.string().min(1, "Field label is required"),
|
|
@@ -6775,44 +7188,7 @@ const repeaterFieldSchema = baseFieldSchema.extend({
|
|
|
6775
7188
|
const hasSchema = data.schema !== undefined;
|
|
6776
7189
|
const hasPolymorphic = data.polymorphic === true && data.itemTypes !== undefined;
|
|
6777
7190
|
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) => {
|
|
7191
|
+
}, { message: "Repeater must have either 'schema' (monomorphic) or 'polymorphic: true' with 'itemTypes' (polymorphic)" }).superRefine(validateLayoutGridConfiguration).refine((data) => {
|
|
6816
7192
|
const thumbnailAspectRatio = data.ui?.thumbnailAspectRatio;
|
|
6817
7193
|
if (!thumbnailAspectRatio) {
|
|
6818
7194
|
return true;
|
|
@@ -7144,6 +7520,195 @@ const manifestSchema = z.object({
|
|
|
7144
7520
|
icon: z.string().optional()
|
|
7145
7521
|
});
|
|
7146
7522
|
|
|
7523
|
+
//#endregion
|
|
7524
|
+
//#region ../blocks/src/lib/media.ts
|
|
7525
|
+
const MEDIA_TYPE_DISCRIMINANTS = mediaTypeDiscriminants;
|
|
7526
|
+
const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
|
|
7527
|
+
"document",
|
|
7528
|
+
"spreadsheet",
|
|
7529
|
+
"archive",
|
|
7530
|
+
"audio"
|
|
7531
|
+
];
|
|
7532
|
+
function isMediaTypeDiscriminant(value) {
|
|
7533
|
+
return typeof value === "string" && MEDIA_TYPE_DISCRIMINANTS.includes(value);
|
|
7534
|
+
}
|
|
7535
|
+
function mediaTypeDiscriminantFromMimeType(mimeType) {
|
|
7536
|
+
const classified = classifyKnownMimeType(mimeType);
|
|
7537
|
+
if (!classified.ok) return null;
|
|
7538
|
+
switch (classified.value.tag) {
|
|
7539
|
+
case "image":
|
|
7540
|
+
case "video":
|
|
7541
|
+
case "audio":
|
|
7542
|
+
case "document":
|
|
7543
|
+
case "spreadsheet":
|
|
7544
|
+
case "archive": return classified.value.tag;
|
|
7545
|
+
case "font": return null;
|
|
7546
|
+
}
|
|
7547
|
+
}
|
|
7548
|
+
|
|
7549
|
+
//#endregion
|
|
7550
|
+
//#region ../blocks/src/system/manifest/fieldValidation/writeCanonicalization.ts
|
|
7551
|
+
function allGroupChildPlans(plan) {
|
|
7552
|
+
return plan.childSelection.kind === "all" ? plan.childSelection.fields : plan.childSelection.tabs.flatMap((tab) => tab.fields);
|
|
7553
|
+
}
|
|
7554
|
+
function selectedGroupChildPlans(plan, value) {
|
|
7555
|
+
if (plan.childSelection.kind === "all") return plan.childSelection.fields;
|
|
7556
|
+
if (!isPlainObject$7(value)) return [];
|
|
7557
|
+
const selectedType = value[plan.childSelection.activeTabField];
|
|
7558
|
+
return plan.childSelection.tabs.find((tab) => tab.typeId === selectedType)?.fields ?? [];
|
|
7559
|
+
}
|
|
7560
|
+
function canonicalizeObjectForWrite(plans, value) {
|
|
7561
|
+
if (!isPlainObject$7(value)) return value;
|
|
7562
|
+
const canonical$1 = { ...value };
|
|
7563
|
+
for (const plan of plans) {
|
|
7564
|
+
if (!(plan.fieldId in canonical$1)) continue;
|
|
7565
|
+
canonical$1[plan.fieldId] = canonicalizeFieldValue(plan, canonical$1[plan.fieldId]);
|
|
7566
|
+
}
|
|
7567
|
+
return omitUndefined(canonical$1);
|
|
7568
|
+
}
|
|
7569
|
+
function canonicalizeFieldValue(plan, value) {
|
|
7570
|
+
switch (plan.kind) {
|
|
7571
|
+
case "media": return canonicalizeMedia(value);
|
|
7572
|
+
case "group": return plan.childSelection.kind === "discriminatedTabs" ? canonicalizeDiscriminatedGroup(plan, value) : canonicalizeObjectForWrite(plan.childSelection.fields, value);
|
|
7573
|
+
case "repeater": return canonicalizeRepeater(plan, value);
|
|
7574
|
+
case "string":
|
|
7575
|
+
case "number":
|
|
7576
|
+
case "boolean":
|
|
7577
|
+
case "richText":
|
|
7578
|
+
case "inlineText":
|
|
7579
|
+
case "link":
|
|
7580
|
+
case "select":
|
|
7581
|
+
case "passthrough": return value;
|
|
7582
|
+
}
|
|
7583
|
+
}
|
|
7584
|
+
function canonicalizeMedia(value) {
|
|
7585
|
+
if (!isPlainObject$7(value)) return value;
|
|
7586
|
+
const canonical$1 = { ...value };
|
|
7587
|
+
if (mediaIdentifierSchema.safeParse(canonical$1.identifier).success) {
|
|
7588
|
+
deleteEnvSpecificKeys(canonical$1);
|
|
7589
|
+
}
|
|
7590
|
+
return canonical$1;
|
|
7591
|
+
}
|
|
7592
|
+
function canonicalizeRepeater(plan, value) {
|
|
7593
|
+
if (!isUnknownArray$3(value)) return value;
|
|
7594
|
+
return value.map((item) => {
|
|
7595
|
+
if (!isPlainObject$7(item)) return item;
|
|
7596
|
+
const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
|
|
7597
|
+
return childPlans ? canonicalizeObjectForWrite(childPlans, item) : item;
|
|
7598
|
+
});
|
|
7599
|
+
}
|
|
7600
|
+
function canonicalizeDiscriminatedGroup(plan, value) {
|
|
7601
|
+
if (!isPlainObject$7(value) || plan.childSelection.kind !== "discriminatedTabs") {
|
|
7602
|
+
return value;
|
|
7603
|
+
}
|
|
7604
|
+
const selection = plan.childSelection;
|
|
7605
|
+
const selectedPlans = selectedGroupChildPlans(plan, value);
|
|
7606
|
+
const selectedIds = rootFieldIds(selectedPlans);
|
|
7607
|
+
const allChildIds = rootFieldIds(allGroupChildPlans(plan));
|
|
7608
|
+
const projected = Object.fromEntries(Object.entries(value).filter(([key]) => key === selection.activeTabField || selectedIds.has(key) || !allChildIds.has(key)));
|
|
7609
|
+
const canonical$1 = omitUndefined(canonicalizeObjectForWrite(selectedPlans, projected));
|
|
7610
|
+
if (plan.valueContract !== "boxBackground") return canonical$1;
|
|
7611
|
+
const parsed = boxBackgroundSchema.safeParse(canonical$1);
|
|
7612
|
+
return parsed.success ? parsed.data : canonical$1;
|
|
7613
|
+
}
|
|
7614
|
+
function rootFieldIds(plans) {
|
|
7615
|
+
return new Set(plans.map((child) => child.fieldId.split(".")[0] ?? child.fieldId));
|
|
7616
|
+
}
|
|
7617
|
+
function omitUndefined(value) {
|
|
7618
|
+
if (isUnknownArray$3(value)) return value.map(omitUndefined);
|
|
7619
|
+
if (!isPlainObject$7(value)) return value;
|
|
7620
|
+
return Object.fromEntries(Object.entries(value).filter(([, field]) => field !== undefined).map(([key, field]) => [key, omitUndefined(field)]));
|
|
7621
|
+
}
|
|
7622
|
+
function isPlainObject$7(value) {
|
|
7623
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7624
|
+
}
|
|
7625
|
+
function isUnknownArray$3(value) {
|
|
7626
|
+
return Array.isArray(value);
|
|
7627
|
+
}
|
|
7628
|
+
|
|
7629
|
+
//#endregion
|
|
7630
|
+
//#region ../blocks/src/system/manifest/fieldValidation/layoutGrid.ts
|
|
7631
|
+
function layoutGridRecord(value) {
|
|
7632
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
7633
|
+
}
|
|
7634
|
+
function resolveLayoutGridItemPlans(plan, item) {
|
|
7635
|
+
return plan.repeatedItemVariants?.find((variant) => variant.typeId === item._type)?.fields ?? plan.repeatedItemPlan ?? [];
|
|
7636
|
+
}
|
|
7637
|
+
function layoutGridCoordinateFieldIds(plan) {
|
|
7638
|
+
const grid$5 = plan.layoutGrid;
|
|
7639
|
+
return grid$5 ? [
|
|
7640
|
+
grid$5.spanField,
|
|
7641
|
+
grid$5.rowField,
|
|
7642
|
+
grid$5.columnField
|
|
7643
|
+
] : [];
|
|
7644
|
+
}
|
|
7645
|
+
function acceptedSpans(plans, spanField) {
|
|
7646
|
+
const span = plans.find((field) => field.fieldId === spanField);
|
|
7647
|
+
if (span?.kind !== "select") return undefined;
|
|
7648
|
+
const constraint = span.constraints.find((entry) => entry.kind === "selectOption");
|
|
7649
|
+
return constraint?.kind === "selectOption" && constraint.source.kind === "static" ? constraint.source.values.map(Number) : [];
|
|
7650
|
+
}
|
|
7651
|
+
function gridIssue(plan, path$3, message) {
|
|
7652
|
+
return {
|
|
7653
|
+
kind: "invalidLayoutGrid",
|
|
7654
|
+
fieldId: plan.fieldId,
|
|
7655
|
+
label: plan.label,
|
|
7656
|
+
path: path$3,
|
|
7657
|
+
message
|
|
7658
|
+
};
|
|
7659
|
+
}
|
|
7660
|
+
function buildLayoutGridForPlan(plan, value, values, ids) {
|
|
7661
|
+
const grid$5 = plan.layoutGrid;
|
|
7662
|
+
if (!grid$5) return null;
|
|
7663
|
+
const columns = grid$5.columns ?? (grid$5.columnsFields ? resolveRepeaterGridColumnsForBreakpoint(values, grid$5.columnsFields, "lg") : 1);
|
|
7664
|
+
const items = value.flatMap((item, index) => {
|
|
7665
|
+
const row$1 = layoutGridRecord(item);
|
|
7666
|
+
return row$1 ? [{
|
|
7667
|
+
id: ids?.[index] ?? String(index),
|
|
7668
|
+
startNewRow: grid$5.startNewRowField ? row$1[grid$5.startNewRowField] === true : false,
|
|
7669
|
+
span: parseRepeaterGridInteger(row$1[grid$5.spanField]) ?? NaN,
|
|
7670
|
+
row: parseRepeaterGridInteger(row$1[grid$5.rowField]) ?? NaN,
|
|
7671
|
+
colStart: parseRepeaterGridInteger(row$1[grid$5.columnField]) ?? NaN,
|
|
7672
|
+
acceptedSpans: acceptedSpans(resolveLayoutGridItemPlans(plan, row$1), grid$5.spanField)
|
|
7673
|
+
}] : [];
|
|
7674
|
+
});
|
|
7675
|
+
return buildRepeaterGridLayout({
|
|
7676
|
+
items,
|
|
7677
|
+
columns,
|
|
7678
|
+
maxRows: grid$5.maxRows,
|
|
7679
|
+
placementPolicy: grid$5.columns === undefined ? "free" : "flow"
|
|
7680
|
+
});
|
|
7681
|
+
}
|
|
7682
|
+
function validateGrid(plan, value, values, path$3) {
|
|
7683
|
+
const layout = buildLayoutGridForPlan(plan, value, values);
|
|
7684
|
+
if (!layout) return [];
|
|
7685
|
+
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.")];
|
|
7686
|
+
return layout.hasInvalidItems ? [gridIssue(plan, path$3, "Choose an available width and a valid position for each item before saving.")] : [];
|
|
7687
|
+
}
|
|
7688
|
+
/** Root values resolve the same column bindings as the editor; recurse without changing any content. */
|
|
7689
|
+
function validateLayoutGridPlans(plans, value, rootValues = layoutGridRecord(value) ?? {}, parent = []) {
|
|
7690
|
+
const values = layoutGridRecord(value);
|
|
7691
|
+
if (!values) return [];
|
|
7692
|
+
return plans.flatMap((plan) => {
|
|
7693
|
+
const fieldValue = values[plan.fieldId];
|
|
7694
|
+
const path$3 = [...parent, plan.fieldId];
|
|
7695
|
+
if (plan.kind === "group") return validateLayoutGridPlans(allGroupChildPlans(plan), fieldValue, rootValues, path$3);
|
|
7696
|
+
if (plan.kind !== "repeater" || !Array.isArray(fieldValue)) return [];
|
|
7697
|
+
return [...validateGrid(plan, fieldValue, rootValues, path$3), ...fieldValue.flatMap((item, index) => {
|
|
7698
|
+
const row$1 = layoutGridRecord(item);
|
|
7699
|
+
return row$1 ? validateLayoutGridPlans(resolveLayoutGridItemPlans(plan, row$1), row$1, rootValues, [...path$3, index]) : [];
|
|
7700
|
+
})];
|
|
7701
|
+
});
|
|
7702
|
+
}
|
|
7703
|
+
/** User-authored column edits only; never run this as a load/render projection. */
|
|
7704
|
+
function planLayoutGridColumnEdit(plan, items, before, after) {
|
|
7705
|
+
const grid$5 = plan.layoutGrid;
|
|
7706
|
+
if (!grid$5?.columnsFields) return { kind: "unchanged" };
|
|
7707
|
+
const columns = resolveRepeaterGridColumnsForBreakpoint(after, grid$5.columnsFields, "lg");
|
|
7708
|
+
const previous = buildLayoutGridForPlan(plan, items, before);
|
|
7709
|
+
return previous ? planRepeaterGridColumnChange(previous, columns) : { kind: "unchanged" };
|
|
7710
|
+
}
|
|
7711
|
+
|
|
7147
7712
|
//#endregion
|
|
7148
7713
|
//#region ../blocks/src/system/inlineText.ts
|
|
7149
7714
|
const inlineTextAccentTones = [
|
|
@@ -8602,112 +9167,6 @@ function isGeneratedBlockIconStale(value, currentStyleGuideVersionId) {
|
|
|
8602
9167
|
return getGeneratedBlockIconStyleState(value, currentStyleGuideVersionId).kind === "stale";
|
|
8603
9168
|
}
|
|
8604
9169
|
|
|
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
9170
|
//#endregion
|
|
8712
9171
|
//#region ../blocks/src/system/fields/backgroundContentAudit.ts
|
|
8713
9172
|
const BACKGROUND_SLOTS = [
|
|
@@ -8773,7 +9232,7 @@ function validationContext(options = {}) {
|
|
|
8773
9232
|
const isDraft = options.mode === "draft";
|
|
8774
9233
|
return {
|
|
8775
9234
|
allowNull: options.allowNull ?? true,
|
|
8776
|
-
allowIncomplete: isDraft || (options.allowIncomplete ?? false),
|
|
9235
|
+
allowIncomplete: options.mode === "storable" ? false : isDraft || (options.allowIncomplete ?? false),
|
|
8777
9236
|
mode: options.mode ?? "strict"
|
|
8778
9237
|
};
|
|
8779
9238
|
}
|
|
@@ -8797,18 +9256,20 @@ function parseFieldPathKey(key) {
|
|
|
8797
9256
|
return Number.isInteger(numeric) && String(numeric) === segment ? numeric : segment;
|
|
8798
9257
|
});
|
|
8799
9258
|
}
|
|
9259
|
+
const simpleIssueMessages = {
|
|
9260
|
+
required: "This field is required",
|
|
9261
|
+
invalidEmail: "Enter a valid email address",
|
|
9262
|
+
invalidPhone: "Enter a valid phone number",
|
|
9263
|
+
invalidPattern: "Check the format and try again",
|
|
9264
|
+
invalidUrl: "Enter a valid web address",
|
|
9265
|
+
invalidDate: "Choose a valid date",
|
|
9266
|
+
invalidTime: "Choose a valid time",
|
|
9267
|
+
invalidDateTime: "Choose a valid date and time"
|
|
9268
|
+
};
|
|
8800
9269
|
function fieldIssueToMessage(issue$1) {
|
|
8801
9270
|
switch (issue$1.kind) {
|
|
8802
|
-
case "required": return "This field is required";
|
|
8803
9271
|
case "wrongType": return `${issue$1.label} needs ${issue$1.expected}`;
|
|
8804
9272
|
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
9273
|
case "invalidNumber": return `${issue$1.label} needs a number`;
|
|
8813
9274
|
case "tooSmall": return `${issue$1.label} must be ${issue$1.minimum} or more`;
|
|
8814
9275
|
case "tooLarge": return `${issue$1.label} must be ${issue$1.maximum} or less`;
|
|
@@ -8821,7 +9282,16 @@ function fieldIssueToMessage(issue$1) {
|
|
|
8821
9282
|
case "invalidMedia": return `${issue$1.label} must be a media object with an identifier`;
|
|
8822
9283
|
case "invalidBoxBackground": return `${issue$1.label} must use a valid background type and matching fields`;
|
|
8823
9284
|
case "invalidLink": return `${issue$1.label} must be a valid link`;
|
|
9285
|
+
case "invalidLayoutGrid": return issue$1.message;
|
|
8824
9286
|
case "invalidReference": return `${issue$1.label} must reference a valid item`;
|
|
9287
|
+
case "required":
|
|
9288
|
+
case "invalidDate":
|
|
9289
|
+
case "invalidDateTime":
|
|
9290
|
+
case "invalidEmail":
|
|
9291
|
+
case "invalidPattern":
|
|
9292
|
+
case "invalidPhone":
|
|
9293
|
+
case "invalidTime":
|
|
9294
|
+
case "invalidUrl": return simpleIssueMessages[issue$1.kind];
|
|
8825
9295
|
default: return assertNever$12(issue$1);
|
|
8826
9296
|
}
|
|
8827
9297
|
}
|
|
@@ -8936,11 +9406,7 @@ function deriveFieldValidationPlan(field, path$3 = [field.id]) {
|
|
|
8936
9406
|
}
|
|
8937
9407
|
case "link": return makePlan("link", "object", field, path$3, required, commonConstraints(required, { kind: "linkObject" }));
|
|
8938
9408
|
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
|
-
};
|
|
9409
|
+
case "repeater": return deriveRepeaterFieldValidationPlan(field, path$3);
|
|
8944
9410
|
case "group":
|
|
8945
9411
|
case "modal": return {
|
|
8946
9412
|
...makePlan("group", "object", field, path$3, required, requiredConstraints(required)),
|
|
@@ -8957,6 +9423,27 @@ function deriveFieldValidationPlan(field, path$3 = [field.id]) {
|
|
|
8957
9423
|
default: return assertNever$12(field);
|
|
8958
9424
|
}
|
|
8959
9425
|
}
|
|
9426
|
+
function deriveRepeaterFieldValidationPlan(field, path$3) {
|
|
9427
|
+
const required = Boolean(field.required);
|
|
9428
|
+
const constraints = commonConstraints(required, { kind: "arrayType" });
|
|
9429
|
+
return {
|
|
9430
|
+
...makePlan("repeater", "array", field, path$3, required, constraints),
|
|
9431
|
+
...field.ui?.repeaterPreset === "layoutGrid" ? { layoutGrid: {
|
|
9432
|
+
startNewRowField: field.ui.layoutGridStartNewRowField,
|
|
9433
|
+
columns: field.ui.layoutGridColumns,
|
|
9434
|
+
columnsFields: field.ui.layoutGridColumnsFields,
|
|
9435
|
+
spanField: resolveRepeaterGridSpanFieldId({ id: field.ui.layoutGridSpanField }),
|
|
9436
|
+
rowField: resolveRepeaterGridRowFieldId({ id: field.ui.layoutGridRowField }),
|
|
9437
|
+
columnField: resolveRepeaterGridColumnFieldId({ id: field.ui.layoutGridColumnField }),
|
|
9438
|
+
maxRows: field.ui.layoutGridMaxRows
|
|
9439
|
+
} } : {},
|
|
9440
|
+
...field.polymorphic && field.itemTypes ? { repeatedItemVariants: deriveRepeatedItemVariants(field, [...path$3, 0]) } : {
|
|
9441
|
+
repeatedItemPlan: deriveNestedFieldPlans(getRepeaterFields(field), [...path$3, 0]),
|
|
9442
|
+
flattenedGroupIds: getFlattenedGroupIds(field.schema?.fields ?? [])
|
|
9443
|
+
},
|
|
9444
|
+
constraints: withRepeaterItemConstraints(field, constraints)
|
|
9445
|
+
};
|
|
9446
|
+
}
|
|
8960
9447
|
function deriveFieldValidationPlans(fields$1, parentPath = []) {
|
|
8961
9448
|
return fields$1.map((field) => deriveFieldValidationPlan(field, [...parentPath, field.id]));
|
|
8962
9449
|
}
|
|
@@ -9006,7 +9493,8 @@ function withRepeaterItemConstraints(field, constraints) {
|
|
|
9006
9493
|
function deriveRepeatedItemVariants(field, parentPath) {
|
|
9007
9494
|
return Object.entries(field.itemTypes ?? {}).map(([typeId, itemType]) => ({
|
|
9008
9495
|
typeId,
|
|
9009
|
-
fields: deriveNestedFieldPlans(getFlattenedRepeaterFields(itemType.fields), parentPath)
|
|
9496
|
+
fields: deriveNestedFieldPlans(getFlattenedRepeaterFields(itemType.fields), parentPath),
|
|
9497
|
+
flattenedGroupIds: getFlattenedGroupIds(itemType.fields)
|
|
9010
9498
|
}));
|
|
9011
9499
|
}
|
|
9012
9500
|
function deriveNestedFieldPlans(fields$1, parentPath) {
|
|
@@ -9016,6 +9504,11 @@ function getRepeaterFields(field) {
|
|
|
9016
9504
|
const fields$1 = field.polymorphic && field.itemTypes ? Object.values(field.itemTypes).flatMap((itemType) => itemType.fields) : field.schema?.fields ?? [];
|
|
9017
9505
|
return getFlattenedRepeaterFields(fields$1);
|
|
9018
9506
|
}
|
|
9507
|
+
/** Only group ids absent from the actual data fields are forbidden containers. */
|
|
9508
|
+
function getFlattenedGroupIds(fields$1) {
|
|
9509
|
+
const dataIds = new Set(getFlattenedRepeaterFields(fields$1).map((field) => field.id));
|
|
9510
|
+
return fields$1.flatMap((field) => field.type === "group" && field.ui?.flattenInRepeater && !dataIds.has(field.id) ? [field.id] : []);
|
|
9511
|
+
}
|
|
9019
9512
|
function getFlattenedRepeaterFields(fields$1) {
|
|
9020
9513
|
return fields$1.flatMap((child) => {
|
|
9021
9514
|
if (child.type === "group" && child.ui?.flattenInRepeater) {
|
|
@@ -9096,6 +9589,32 @@ function fieldPlanToNativeInputProps(plan) {
|
|
|
9096
9589
|
function normalizeFieldInput(plan, value, options = {}) {
|
|
9097
9590
|
return normalizeFieldValue(plan, value, validationContext(options));
|
|
9098
9591
|
}
|
|
9592
|
+
/** Drop obsolete presentation containers only when reading persisted content.
|
|
9593
|
+
* Flat data remains authoritative; unknown variants and legitimate groups survive.
|
|
9594
|
+
*/
|
|
9595
|
+
function normalizeLegacyStoredGroupContainers(plans, content) {
|
|
9596
|
+
if (!isPlainObject$6(content)) return content;
|
|
9597
|
+
const planMap = new Map(plans.map((plan) => [plan.fieldId, plan]));
|
|
9598
|
+
const entries = Object.entries(content).map(([key, value]) => {
|
|
9599
|
+
const plan = planMap.get(key);
|
|
9600
|
+
return [key, plan ? normalizeLegacyStoredField(plan, value) : value];
|
|
9601
|
+
});
|
|
9602
|
+
return entries.every(([key, value]) => value === content[key]) ? content : Object.fromEntries(entries);
|
|
9603
|
+
}
|
|
9604
|
+
function normalizeLegacyStoredField(plan, value) {
|
|
9605
|
+
if (plan.kind === "group") {
|
|
9606
|
+
return normalizeLegacyStoredGroupContainers(selectedGroupChildPlans(plan, value), value);
|
|
9607
|
+
}
|
|
9608
|
+
if (plan.kind !== "repeater" || !isUnknownArray$2(value)) return value;
|
|
9609
|
+
const items = value.map((item) => {
|
|
9610
|
+
if (!isPlainObject$6(item)) return item;
|
|
9611
|
+
const selection = selectRepeaterItemPlan(plan, item);
|
|
9612
|
+
if (selection.kind !== "fields") return item;
|
|
9613
|
+
const retained = selection.flattenedGroupIds.some((key) => Object.prototype.hasOwnProperty.call(item, key)) ? Object.fromEntries(Object.entries(item).filter(([key]) => !selection.flattenedGroupIds.includes(key))) : item;
|
|
9614
|
+
return normalizeLegacyStoredGroupContainers(selection.fields, retained);
|
|
9615
|
+
});
|
|
9616
|
+
return items.every((item, index) => item === value[index]) ? value : items;
|
|
9617
|
+
}
|
|
9099
9618
|
function normalizeStoredContentValues(plans, content, options = {}) {
|
|
9100
9619
|
if (!content || typeof content !== "object" || Array.isArray(content)) {
|
|
9101
9620
|
return {};
|
|
@@ -9158,7 +9677,8 @@ function normalizeStoredRepeaterItems(plan, value, ctx) {
|
|
|
9158
9677
|
return item;
|
|
9159
9678
|
}
|
|
9160
9679
|
const itemRecord = item;
|
|
9161
|
-
const
|
|
9680
|
+
const selection = selectRepeaterItemPlan(plan, itemRecord);
|
|
9681
|
+
const fields$1 = selection.kind === "fields" ? selection.fields : undefined;
|
|
9162
9682
|
if (!fields$1) {
|
|
9163
9683
|
return item;
|
|
9164
9684
|
}
|
|
@@ -9215,7 +9735,8 @@ function normalizeRepeaterItems(plan, value, ctx) {
|
|
|
9215
9735
|
return value.map((item) => {
|
|
9216
9736
|
if (!item || typeof item !== "object" || Array.isArray(item)) return item;
|
|
9217
9737
|
const itemRecord = item;
|
|
9218
|
-
const
|
|
9738
|
+
const selection = selectRepeaterItemPlan(plan, itemRecord);
|
|
9739
|
+
const fields$1 = selection.kind === "fields" ? selection.fields : undefined;
|
|
9219
9740
|
if (!fields$1) return item;
|
|
9220
9741
|
return normalizeObjectChildren(fields$1, itemRecord, ctx);
|
|
9221
9742
|
});
|
|
@@ -9230,13 +9751,13 @@ function acceptsOptionalBlankAsMissing(plan, value) {
|
|
|
9230
9751
|
return plan.constraints.some((constraint) => constraint.kind === "urlFormat" || constraint.kind === "slugFormat" || constraint.kind === "emailFormat" || constraint.kind === "phoneFormat" || constraint.kind === "patternFormat");
|
|
9231
9752
|
}
|
|
9232
9753
|
function validateNormalizedFieldValue(plan, value, ctx) {
|
|
9233
|
-
if (value === null && (ctx
|
|
9234
|
-
if (isMissingForPlan(plan, value)) {
|
|
9754
|
+
if (value === null && acceptsNullValue(plan, ctx)) return [];
|
|
9755
|
+
if (isMissingForPlan(plan, value, ctx.mode)) {
|
|
9235
9756
|
return shouldRequireValue(plan, value, ctx) ? [requiredIssue(plan, value)] : [];
|
|
9236
9757
|
}
|
|
9237
9758
|
switch (plan.kind) {
|
|
9238
9759
|
case "string": return validateStringPlan(plan, value, ctx);
|
|
9239
|
-
case "number": return validateNumberPlan(plan, value);
|
|
9760
|
+
case "number": return validateNumberPlan(plan, value, ctx);
|
|
9240
9761
|
case "boolean": return typeof value === "boolean" ? [] : [issue(plan, "wrongType", { expected: "a true/false value" })];
|
|
9241
9762
|
case "select": return validateSelectPlan(plan, value);
|
|
9242
9763
|
case "richText": return isValidRichTextDoc(value) ? [] : [issue(plan, "invalidRichText")];
|
|
@@ -9260,14 +9781,18 @@ function validateMediaPlan(plan, value, ctx) {
|
|
|
9260
9781
|
}
|
|
9261
9782
|
function shouldRequireValue(plan, value, ctx) {
|
|
9262
9783
|
if (!plan.required || ctx.allowIncomplete) return false;
|
|
9263
|
-
if (value === null && ctx.allowNull) return false;
|
|
9784
|
+
if (value === null && ctx.allowNull && ctx.mode !== "storable") return false;
|
|
9264
9785
|
return true;
|
|
9265
9786
|
}
|
|
9787
|
+
function acceptsNullValue(plan, ctx) {
|
|
9788
|
+
return ctx.mode === "storable" ? !plan.required : ctx.allowNull || acceptsOptionalNullValue(plan);
|
|
9789
|
+
}
|
|
9266
9790
|
function acceptsOptionalNullValue(plan) {
|
|
9267
9791
|
return !plan.required && (plan.kind === "media" || plan.kind === "number");
|
|
9268
9792
|
}
|
|
9269
|
-
function isMissingForPlan(plan, value) {
|
|
9793
|
+
function isMissingForPlan(plan, value, mode) {
|
|
9270
9794
|
if (value === undefined) return true;
|
|
9795
|
+
if (mode === "storable") return value === null || value === "";
|
|
9271
9796
|
if (value === null) return plan.required;
|
|
9272
9797
|
if (typeof value === "string" && value.trim() === "") return true;
|
|
9273
9798
|
if (Array.isArray(value) && value.length === 0) return true;
|
|
@@ -9286,7 +9811,7 @@ function validateStringConstraint(plan, constraint, value, ctx) {
|
|
|
9286
9811
|
return isValidIconPickerValue(value) ? [] : [issue(plan, "wrongType", { expected: "text or icon" })];
|
|
9287
9812
|
}
|
|
9288
9813
|
if (typeof value !== "string") return [issue(plan, "wrongType", { expected: "text" })];
|
|
9289
|
-
if (constraint.kind === "textType" || constraint.kind === "referenceText") return [];
|
|
9814
|
+
if (constraint.kind === "textType" || constraint.kind === "referenceText" || ctx.mode === "storable") return [];
|
|
9290
9815
|
return constraint.kind === "maxLength" ? validateAuthoredTextLength(plan, value, constraint.maximum, ctx) : validateStringFormat(plan, constraint, value);
|
|
9291
9816
|
}
|
|
9292
9817
|
const SIMPLE_STRING_FORMATS = {
|
|
@@ -9328,7 +9853,7 @@ function validateStringFormat(plan, constraint, value) {
|
|
|
9328
9853
|
}
|
|
9329
9854
|
/** Authoring limits govern stored block copy; resolved entry text has its own owner. */
|
|
9330
9855
|
function validateAuthoredTextLength(plan, text$1, maximum, ctx) {
|
|
9331
|
-
return ctx.mode !== "render" && maximum !== undefined && text$1.length > maximum ? [issue(plan, "tooLong", { maximum })] : [];
|
|
9856
|
+
return ctx.mode !== "render" && ctx.mode !== "storable" && maximum !== undefined && text$1.length > maximum ? [issue(plan, "tooLong", { maximum })] : [];
|
|
9332
9857
|
}
|
|
9333
9858
|
function isValidIconPickerValue(value) {
|
|
9334
9859
|
if (typeof value === "string") return true;
|
|
@@ -9336,8 +9861,9 @@ function isValidIconPickerValue(value) {
|
|
|
9336
9861
|
if (value.kind === "none") return true;
|
|
9337
9862
|
return parseBlockIconValue(value).kind !== "none";
|
|
9338
9863
|
}
|
|
9339
|
-
function validateNumberPlan(plan, value) {
|
|
9864
|
+
function validateNumberPlan(plan, value, ctx) {
|
|
9340
9865
|
if (!isValidNumber(value)) return [issue(plan, "invalidNumber")];
|
|
9866
|
+
if (ctx.mode === "storable") return [];
|
|
9341
9867
|
return plan.constraints.flatMap((constraint) => validateNumberConstraint(plan, constraint, Number(value)));
|
|
9342
9868
|
}
|
|
9343
9869
|
function validateNumberConstraint(plan, constraint, value) {
|
|
@@ -9356,7 +9882,7 @@ function validateSelectPlan(plan, value) {
|
|
|
9356
9882
|
}
|
|
9357
9883
|
function validateRepeaterPlan(plan, value, ctx) {
|
|
9358
9884
|
if (!Array.isArray(value)) return [issue(plan, "wrongType", { expected: "a list" })];
|
|
9359
|
-
const constraintIssues = plan.constraints.flatMap((constraint) => {
|
|
9885
|
+
const constraintIssues = ctx.mode === "storable" ? [] : plan.constraints.flatMap((constraint) => {
|
|
9360
9886
|
switch (constraint.kind) {
|
|
9361
9887
|
case "required":
|
|
9362
9888
|
case "arrayType": return [];
|
|
@@ -9373,6 +9899,22 @@ function validateRepeaterPlan(plan, value, ctx) {
|
|
|
9373
9899
|
});
|
|
9374
9900
|
return [...constraintIssues, ...value.flatMap((item, index) => validateRepeaterItem(plan, item, index, ctx))];
|
|
9375
9901
|
}
|
|
9902
|
+
/** Selects both the value fields and forbidden presentation containers together. */
|
|
9903
|
+
function selectRepeaterItemPlan(plan, item) {
|
|
9904
|
+
if (plan.repeatedItemVariants) {
|
|
9905
|
+
const variant = plan.repeatedItemVariants.find((candidate) => candidate.typeId === item._type);
|
|
9906
|
+
return variant ? {
|
|
9907
|
+
kind: "fields",
|
|
9908
|
+
fields: variant.fields,
|
|
9909
|
+
flattenedGroupIds: variant.flattenedGroupIds ?? []
|
|
9910
|
+
} : { kind: "invalidType" };
|
|
9911
|
+
}
|
|
9912
|
+
return plan.repeatedItemPlan ? {
|
|
9913
|
+
kind: "fields",
|
|
9914
|
+
fields: plan.repeatedItemPlan,
|
|
9915
|
+
flattenedGroupIds: plan.flattenedGroupIds ?? []
|
|
9916
|
+
} : { kind: "untyped" };
|
|
9917
|
+
}
|
|
9376
9918
|
function validateRepeaterItem(plan, item, index, ctx) {
|
|
9377
9919
|
if (!isPlainObject$6(item)) {
|
|
9378
9920
|
return [{
|
|
@@ -9383,9 +9925,8 @@ function validateRepeaterItem(plan, item, index, ctx) {
|
|
|
9383
9925
|
expected: "an object"
|
|
9384
9926
|
}];
|
|
9385
9927
|
}
|
|
9386
|
-
const
|
|
9387
|
-
|
|
9388
|
-
if (plan.repeatedItemVariants && !variant) {
|
|
9928
|
+
const selection = selectRepeaterItemPlan(plan, item);
|
|
9929
|
+
if (selection.kind === "invalidType") {
|
|
9389
9930
|
return [{
|
|
9390
9931
|
kind: "invalidOption",
|
|
9391
9932
|
path: [
|
|
@@ -9397,12 +9938,27 @@ function validateRepeaterItem(plan, item, index, ctx) {
|
|
|
9397
9938
|
label: `${plan.label} item type`
|
|
9398
9939
|
}];
|
|
9399
9940
|
}
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
return fields
|
|
9941
|
+
if (selection.kind === "untyped") return [];
|
|
9942
|
+
const containerIssues = validateFlattenedGroupContainers(selection.flattenedGroupIds, item, plan, index, ctx);
|
|
9943
|
+
return [...containerIssues, ...selection.fields.flatMap((childPlan) => {
|
|
9944
|
+
if (ctx.layoutGridCoordinates === "projected" && layoutGridCoordinateFieldIds(plan).includes(childPlan.fieldId)) return [];
|
|
9403
9945
|
const indexedPlan = materializeRepeaterItemPlan(childPlan, plan.path, index);
|
|
9404
9946
|
return validateNormalizedFieldValue(indexedPlan, item[childPlan.fieldId], ctx);
|
|
9405
|
-
});
|
|
9947
|
+
})];
|
|
9948
|
+
}
|
|
9949
|
+
function validateFlattenedGroupContainers(groupIds, item, plan, index, ctx) {
|
|
9950
|
+
if (ctx.mode === "render") return [];
|
|
9951
|
+
return groupIds.flatMap((fieldId) => Object.prototype.hasOwnProperty.call(item, fieldId) ? [{
|
|
9952
|
+
kind: "wrongType",
|
|
9953
|
+
path: [
|
|
9954
|
+
...plan.path,
|
|
9955
|
+
index,
|
|
9956
|
+
fieldId
|
|
9957
|
+
],
|
|
9958
|
+
fieldId,
|
|
9959
|
+
label: plan.label,
|
|
9960
|
+
expected: "valid settings"
|
|
9961
|
+
}] : []);
|
|
9406
9962
|
}
|
|
9407
9963
|
function validateGroupPlan(plan, value, ctx) {
|
|
9408
9964
|
if (!isPlainObject$6(value)) return [issue(plan, "wrongType", { expected: "an object" })];
|
|
@@ -9505,19 +10061,22 @@ function requiredIssue(plan, value) {
|
|
|
9505
10061
|
if (Array.isArray(value)) return issue(plan, "required", { emptyOrigin: "array" });
|
|
9506
10062
|
return issue(plan, "required");
|
|
9507
10063
|
}
|
|
9508
|
-
function fieldPlanToZod(plan, options = {}) {
|
|
9509
|
-
const ctx =
|
|
10064
|
+
function fieldPlanToZod(plan, options = {}, layoutGridCoordinates = "validate") {
|
|
10065
|
+
const ctx = {
|
|
10066
|
+
...validationContext(options),
|
|
10067
|
+
layoutGridCoordinates
|
|
10068
|
+
};
|
|
9510
10069
|
return z.any().transform((value) => normalizeFieldValue(plan, value, ctx)).superRefine((value, zodCtx) => {
|
|
9511
|
-
|
|
10070
|
+
validateNormalizedFieldValue(plan, value, ctx).forEach((validationIssue) => {
|
|
9512
10071
|
addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
|
|
9513
|
-
}
|
|
10072
|
+
});
|
|
9514
10073
|
});
|
|
9515
10074
|
}
|
|
9516
10075
|
function fieldPresenceForPlan(plan) {
|
|
9517
10076
|
return plan.required ? { kind: "required" } : { kind: "optional" };
|
|
9518
10077
|
}
|
|
9519
|
-
function fieldPlanToObjectPropertyZod(plan, options = {}) {
|
|
9520
|
-
const schema = fieldPlanToZod(plan, options);
|
|
10078
|
+
function fieldPlanToObjectPropertyZod(plan, options = {}, layoutGridCoordinates = "validate") {
|
|
10079
|
+
const schema = fieldPlanToZod(plan, options, layoutGridCoordinates);
|
|
9521
10080
|
const presence = fieldPresenceForPlan(plan);
|
|
9522
10081
|
switch (presence.kind) {
|
|
9523
10082
|
case "required": return schema;
|
|
@@ -9526,11 +10085,14 @@ function fieldPlanToObjectPropertyZod(plan, options = {}) {
|
|
|
9526
10085
|
}
|
|
9527
10086
|
}
|
|
9528
10087
|
/** Validate stored or runtime fields without applying editor/write normalization. */
|
|
9529
|
-
function fieldPlanToStrictObjectPropertyZod(plan, mode = "strict") {
|
|
9530
|
-
const ctx =
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
10088
|
+
function fieldPlanToStrictObjectPropertyZod(plan, mode = "strict", layoutGridCoordinates = "validate") {
|
|
10089
|
+
const ctx = {
|
|
10090
|
+
...strictValidationContext({
|
|
10091
|
+
allowNull: false,
|
|
10092
|
+
mode
|
|
10093
|
+
}),
|
|
10094
|
+
layoutGridCoordinates
|
|
10095
|
+
};
|
|
9534
10096
|
const schema = z.any().superRefine((value, zodCtx) => {
|
|
9535
10097
|
validateNormalizedFieldValue(plan, value, ctx).forEach((validationIssue) => {
|
|
9536
10098
|
addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
|
|
@@ -9538,76 +10100,35 @@ function fieldPlanToStrictObjectPropertyZod(plan, mode = "strict") {
|
|
|
9538
10100
|
});
|
|
9539
10101
|
return plan.required ? schema : schema.optional();
|
|
9540
10102
|
}
|
|
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
|
-
}
|
|
10103
|
+
function fieldIssueToZodDetail(issue$1) {
|
|
10104
|
+
if (issue$1.kind === "required") return issue$1.emptyOrigin ? {
|
|
10105
|
+
code: "too_small",
|
|
10106
|
+
origin: issue$1.emptyOrigin,
|
|
10107
|
+
minimum: 1,
|
|
10108
|
+
inclusive: true
|
|
10109
|
+
} : {
|
|
10110
|
+
code: "invalid_type",
|
|
10111
|
+
expected: "nonoptional"
|
|
10112
|
+
};
|
|
10113
|
+
if (issue$1.kind === "tooLong") return {
|
|
10114
|
+
code: "too_big",
|
|
10115
|
+
origin: "string",
|
|
10116
|
+
maximum: issue$1.maximum,
|
|
10117
|
+
inclusive: true
|
|
10118
|
+
};
|
|
10119
|
+
if (issue$1.kind === "invalidOption") return {
|
|
10120
|
+
code: "invalid_value",
|
|
10121
|
+
values: []
|
|
10122
|
+
};
|
|
10123
|
+
return { code: "custom" };
|
|
10124
|
+
}
|
|
10125
|
+
function addFieldIssueToZodContext(zodCtx, issue$1, rootPath) {
|
|
10126
|
+
const detail = fieldIssueToZodDetail(issue$1);
|
|
10127
|
+
zodCtx.addIssue({
|
|
10128
|
+
...detail,
|
|
10129
|
+
path: toZodIssuePath(relativeZodIssuePath(issue$1.path, rootPath)),
|
|
10130
|
+
message: fieldIssueToMessage(issue$1)
|
|
10131
|
+
});
|
|
9611
10132
|
}
|
|
9612
10133
|
function relativeZodIssuePath(path$3, rootPath) {
|
|
9613
10134
|
return startsWithFieldPath(path$3, rootPath) ? path$3.slice(rootPath.length) : path$3;
|
|
@@ -9668,7 +10189,7 @@ function sameFieldPath(left, right) {
|
|
|
9668
10189
|
function validateManifestValues(fields$1, values, options = {}) {
|
|
9669
10190
|
const plans = deriveFieldValidationPlans(fields$1);
|
|
9670
10191
|
const normalized = normalizeStoredContentValues(plans, values, options);
|
|
9671
|
-
return plans.flatMap((plan) => validateFieldValue(plan, normalized[plan.fieldId], options));
|
|
10192
|
+
return [...plans.flatMap((plan) => validateFieldValue(plan, normalized[plan.fieldId], options)), ...validateLayoutGridPlans(plans, normalized)];
|
|
9672
10193
|
}
|
|
9673
10194
|
function compilePattern(pattern) {
|
|
9674
10195
|
try {
|
|
@@ -9771,6 +10292,63 @@ function isEmptyRichTextDoc(value) {
|
|
|
9771
10292
|
return first?.type === "paragraph" && (!Array.isArray(first.content) || first.content.length === 0);
|
|
9772
10293
|
}
|
|
9773
10294
|
|
|
10295
|
+
//#endregion
|
|
10296
|
+
//#region ../blocks/src/system/manifest/fieldValidation/layoutGridRendering.ts
|
|
10297
|
+
function invalidCoordinateIds(plan, items, itemIds) {
|
|
10298
|
+
const ids = layoutGridCoordinateFieldIds(plan);
|
|
10299
|
+
return items.flatMap((item, index) => {
|
|
10300
|
+
const row$1 = layoutGridRecord(item);
|
|
10301
|
+
const invalid$1 = row$1 !== null && resolveLayoutGridItemPlans(plan, row$1).some((field) => ids.includes(field.fieldId) && !fieldPlanToStrictObjectPropertyZod(field).safeParse(row$1[field.fieldId]).success);
|
|
10302
|
+
return invalid$1 ? [itemIds?.[index] ?? String(index)] : [];
|
|
10303
|
+
});
|
|
10304
|
+
}
|
|
10305
|
+
/** Shared raw-coordinate admission for editor and public rendering; retains diagnostics. */
|
|
10306
|
+
function admitLayoutGridForPlan(plan, value, rootValues, ids) {
|
|
10307
|
+
const layout = buildLayoutGridForPlan(plan, value, rootValues, ids);
|
|
10308
|
+
const invalidIds = invalidCoordinateIds(plan, value, ids);
|
|
10309
|
+
return layout && invalidIds.length > 0 ? {
|
|
10310
|
+
...layout,
|
|
10311
|
+
hasInvalidItems: true,
|
|
10312
|
+
invalidCoordinateIds: invalidIds
|
|
10313
|
+
} : layout;
|
|
10314
|
+
}
|
|
10315
|
+
function projectGrid(plan, value, rootValues) {
|
|
10316
|
+
const grid$5 = plan.layoutGrid;
|
|
10317
|
+
const layout = admitLayoutGridForPlan(plan, value, rootValues);
|
|
10318
|
+
if (!grid$5 || !layout) return value;
|
|
10319
|
+
const authored = layout;
|
|
10320
|
+
const projected = projectRepeaterGridLayoutForRendering(authored);
|
|
10321
|
+
if (projected === authored) return value;
|
|
10322
|
+
return value.map((item, index) => {
|
|
10323
|
+
const row$1 = layoutGridRecord(item);
|
|
10324
|
+
const placement = projected.byId[String(index)];
|
|
10325
|
+
if (!row$1 || !placement) return item;
|
|
10326
|
+
const spanPlan = resolveLayoutGridItemPlans(plan, row$1).find((field) => field.fieldId === grid$5.spanField);
|
|
10327
|
+
return {
|
|
10328
|
+
...row$1,
|
|
10329
|
+
[grid$5.spanField]: spanPlan?.kind === "number" ? placement.span : String(placement.span),
|
|
10330
|
+
[grid$5.rowField]: placement.row,
|
|
10331
|
+
[grid$5.columnField]: placement.colStart
|
|
10332
|
+
};
|
|
10333
|
+
});
|
|
10334
|
+
}
|
|
10335
|
+
/** Only layout coordinates are projected. Array order, item data and media references remain intact. */
|
|
10336
|
+
function projectLayoutGridPlansForRendering(plans, value, rootValues = layoutGridRecord(value) ?? {}) {
|
|
10337
|
+
const values = layoutGridRecord(value);
|
|
10338
|
+
if (!values) return value;
|
|
10339
|
+
return plans.reduce((projected, plan) => {
|
|
10340
|
+
const fieldValue = projected[plan.fieldId];
|
|
10341
|
+
const next = plan.kind === "group" ? projectLayoutGridPlansForRendering(allGroupChildPlans(plan), fieldValue, rootValues) : plan.kind === "repeater" && Array.isArray(fieldValue) ? projectGrid(plan, fieldValue, rootValues).map((item) => {
|
|
10342
|
+
const row$1 = layoutGridRecord(item);
|
|
10343
|
+
return row$1 ? projectLayoutGridPlansForRendering(resolveLayoutGridItemPlans(plan, row$1), row$1, rootValues) : item;
|
|
10344
|
+
}) : fieldValue;
|
|
10345
|
+
return next === fieldValue ? projected : {
|
|
10346
|
+
...projected,
|
|
10347
|
+
[plan.fieldId]: next
|
|
10348
|
+
};
|
|
10349
|
+
}, values);
|
|
10350
|
+
}
|
|
10351
|
+
|
|
9774
10352
|
//#endregion
|
|
9775
10353
|
//#region ../blocks/src/system/manifest/validation.ts
|
|
9776
10354
|
const compiledManifestContentContract = Symbol("compiledManifestContentContract");
|
|
@@ -9802,6 +10380,7 @@ function compileManifestContentContract(manifestOrFields, options = {}) {
|
|
|
9802
10380
|
return Object.freeze({ [compiledManifestContentContract]: Object.freeze({
|
|
9803
10381
|
plans,
|
|
9804
10382
|
strictStoredSchema,
|
|
10383
|
+
renderSourceSchema: deriveStrictContentZodFromPlans(plans, "render-source"),
|
|
9805
10384
|
writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).superRefine((value, ctx) => {
|
|
9806
10385
|
if (options.unknownFields !== "reject") return;
|
|
9807
10386
|
unknownManifestFieldPaths(plans, value).forEach((path$3) => {
|
|
@@ -9817,6 +10396,11 @@ function compileManifestContentContract(manifestOrFields, options = {}) {
|
|
|
9817
10396
|
allowIncomplete: true,
|
|
9818
10397
|
mode: "draft"
|
|
9819
10398
|
}, normalizeStoredContentValues),
|
|
10399
|
+
renderDraftSchema: deriveNormalizedContentZodFromPlans(plans, {
|
|
10400
|
+
allowNull: true,
|
|
10401
|
+
allowIncomplete: true,
|
|
10402
|
+
mode: "draft"
|
|
10403
|
+
}, normalizeStoredContentValues, false),
|
|
9820
10404
|
renderSchema: deriveStrictContentZodFromPlans(plans, "render"),
|
|
9821
10405
|
findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
|
|
9822
10406
|
}) });
|
|
@@ -9855,7 +10439,8 @@ function findNonPortableManifestMediaPaths(contract, content) {
|
|
|
9855
10439
|
/** Strictly admits already-persisted content without repairing it. */
|
|
9856
10440
|
function admitStoredManifestContent(contract, content) {
|
|
9857
10441
|
const state = contract[compiledManifestContentContract];
|
|
9858
|
-
const
|
|
10442
|
+
const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
|
|
10443
|
+
const nonPortablePaths = state.findNonPortableMediaPaths(normalized);
|
|
9859
10444
|
if (nonPortablePaths.length > 0) {
|
|
9860
10445
|
return {
|
|
9861
10446
|
ok: false,
|
|
@@ -9865,10 +10450,32 @@ function admitStoredManifestContent(contract, content) {
|
|
|
9865
10450
|
}
|
|
9866
10451
|
};
|
|
9867
10452
|
}
|
|
9868
|
-
const parsed = state.strictStoredSchema.safeParse(
|
|
10453
|
+
const parsed = state.strictStoredSchema.safeParse(normalized);
|
|
9869
10454
|
return parsed.success ? {
|
|
9870
10455
|
ok: true,
|
|
9871
|
-
value:
|
|
10456
|
+
value: normalized
|
|
10457
|
+
} : {
|
|
10458
|
+
ok: false,
|
|
10459
|
+
error: zodAdmissionError(parsed.error)
|
|
10460
|
+
};
|
|
10461
|
+
}
|
|
10462
|
+
/** Public reads alone may project invalid grid geometry. All other stored-shape and portability checks remain strict. */
|
|
10463
|
+
function admitStoredManifestContentForRendering(contract, content) {
|
|
10464
|
+
const state = contract[compiledManifestContentContract];
|
|
10465
|
+
const normalized = normalizeLegacyStoredGroupContainers(state.plans, content);
|
|
10466
|
+
const paths = state.findNonPortableMediaPaths(normalized);
|
|
10467
|
+
if (paths.length > 0) return {
|
|
10468
|
+
ok: false,
|
|
10469
|
+
error: {
|
|
10470
|
+
kind: "non_portable_media",
|
|
10471
|
+
paths
|
|
10472
|
+
}
|
|
10473
|
+
};
|
|
10474
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, normalized);
|
|
10475
|
+
const parsed = state.renderSourceSchema.safeParse(projected);
|
|
10476
|
+
return parsed.success ? {
|
|
10477
|
+
ok: true,
|
|
10478
|
+
value: projected
|
|
9872
10479
|
} : {
|
|
9873
10480
|
ok: false,
|
|
9874
10481
|
error: zodAdmissionError(parsed.error)
|
|
@@ -9916,6 +10523,24 @@ function validateManifestDraft(contract, data) {
|
|
|
9916
10523
|
issues: [firstIssue, ...remainingIssues]
|
|
9917
10524
|
};
|
|
9918
10525
|
}
|
|
10526
|
+
/** Public template bases may be incomplete until bindings resolve; only grid geometry is projected. */
|
|
10527
|
+
function validateManifestDraftForRendering(contract, data) {
|
|
10528
|
+
const state = contract[compiledManifestContentContract];
|
|
10529
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, data);
|
|
10530
|
+
const parsed = state.renderDraftSchema.safeParse(projected);
|
|
10531
|
+
if (parsed.success) return {
|
|
10532
|
+
kind: "previewable",
|
|
10533
|
+
data: projected,
|
|
10534
|
+
issues: []
|
|
10535
|
+
};
|
|
10536
|
+
const [firstIssue, ...remainingIssues] = zodAdmissionIssues(parsed.error);
|
|
10537
|
+
if (!firstIssue) throw new Error("Render draft validation failed without an issue");
|
|
10538
|
+
return {
|
|
10539
|
+
kind: "invalid",
|
|
10540
|
+
data: projected,
|
|
10541
|
+
issues: [firstIssue, ...remainingIssues]
|
|
10542
|
+
};
|
|
10543
|
+
}
|
|
9919
10544
|
/**
|
|
9920
10545
|
* Checks whether a raw editor candidate is schema-ready for the effectful
|
|
9921
10546
|
* media-resolution/write boundary without granting a stored proof.
|
|
@@ -9942,8 +10567,9 @@ function validateManifestWriteCandidate(contract, data) {
|
|
|
9942
10567
|
* the resulting render shape before granting the renderable proof.
|
|
9943
10568
|
*/
|
|
9944
10569
|
function deriveRenderableManifestContent(contract, stored, project) {
|
|
9945
|
-
const
|
|
9946
|
-
const
|
|
10570
|
+
const state = contract[compiledManifestContentContract];
|
|
10571
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, normalizeLegacyStoredGroupContainers(state.plans, project(stored)));
|
|
10572
|
+
const parsed = state.renderSchema.safeParse(projected);
|
|
9947
10573
|
return parsed.success ? {
|
|
9948
10574
|
ok: true,
|
|
9949
10575
|
value: projected
|
|
@@ -9958,33 +10584,50 @@ function deriveRenderableManifestContent(contract, stored, project) {
|
|
|
9958
10584
|
* grants a stored proof, so hydrated media cannot flow back to persistence.
|
|
9959
10585
|
*/
|
|
9960
10586
|
function admitTransportedRenderableManifestContent(contract, content) {
|
|
9961
|
-
const
|
|
10587
|
+
const state = contract[compiledManifestContentContract];
|
|
10588
|
+
const projected = projectLayoutGridPlansForRendering(state.plans, content);
|
|
10589
|
+
const parsed = state.renderSchema.safeParse(projected);
|
|
9962
10590
|
return parsed.success ? {
|
|
9963
10591
|
ok: true,
|
|
9964
|
-
value:
|
|
10592
|
+
value: projected
|
|
9965
10593
|
} : {
|
|
9966
10594
|
ok: false,
|
|
9967
10595
|
error: zodAdmissionError(parsed.error)
|
|
9968
10596
|
};
|
|
9969
10597
|
}
|
|
9970
|
-
function deriveNormalizedContentZodFromPlans(plans, options, normalize$4) {
|
|
10598
|
+
function deriveNormalizedContentZodFromPlans(plans, options, normalize$4, validateLayoutGrids = true) {
|
|
9971
10599
|
const isDraft = options.mode === "draft";
|
|
9972
|
-
const baseSchema = deriveContentZodFromPlans(plans, options);
|
|
10600
|
+
const baseSchema = deriveContentZodFromPlans(plans, options, validateLayoutGrids);
|
|
9973
10601
|
if (isDraft) {
|
|
9974
10602
|
return z.preprocess((content) => preprocessEmptyValues(normalize$4(plans, content, options)), baseSchema);
|
|
9975
10603
|
}
|
|
9976
10604
|
return z.preprocess((content) => normalize$4(plans, content, options), baseSchema);
|
|
9977
10605
|
}
|
|
9978
|
-
function deriveContentZodFromPlans(plans, options) {
|
|
9979
|
-
const shape =
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
10606
|
+
function deriveContentZodFromPlans(plans, options, validateLayoutGrids = true) {
|
|
10607
|
+
const shape = Object.fromEntries(plans.map((plan) => [plan.fieldId, fieldPlanToObjectPropertyZod(plan, options, validateLayoutGrids ? "validate" : "projected")]));
|
|
10608
|
+
return z.object(shape).catchall(z.unknown()).passthrough().superRefine((values, ctx) => {
|
|
10609
|
+
if (!validateLayoutGrids) return;
|
|
10610
|
+
validateLayoutGridPlans(plans, values).forEach((issue$1) => {
|
|
10611
|
+
ctx.addIssue({
|
|
10612
|
+
code: "custom",
|
|
10613
|
+
path: [...issue$1.path],
|
|
10614
|
+
message: issue$1.message
|
|
10615
|
+
});
|
|
10616
|
+
});
|
|
10617
|
+
});
|
|
9984
10618
|
}
|
|
9985
10619
|
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()
|
|
10620
|
+
const shape = Object.fromEntries(plans.map((plan) => [plan.fieldId, fieldPlanToStrictObjectPropertyZod(plan, mode === "render" ? "render" : "strict", mode === "strict" ? "validate" : "projected")]));
|
|
10621
|
+
return z.object(shape).catchall(z.unknown()).passthrough().superRefine((values, ctx) => {
|
|
10622
|
+
if (mode !== "strict") return;
|
|
10623
|
+
validateLayoutGridPlans(plans, values).forEach((issue$1) => {
|
|
10624
|
+
ctx.addIssue({
|
|
10625
|
+
code: "custom",
|
|
10626
|
+
path: [...issue$1.path],
|
|
10627
|
+
message: issue$1.message
|
|
10628
|
+
});
|
|
10629
|
+
});
|
|
10630
|
+
});
|
|
9988
10631
|
}
|
|
9989
10632
|
function derivePlansFromManifestOrFields(manifestOrFields) {
|
|
9990
10633
|
const fields$1 = Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields ?? [];
|
|
@@ -12306,6 +12949,7 @@ function styledSection(config$1) {
|
|
|
12306
12949
|
baseClass,
|
|
12307
12950
|
spacing,
|
|
12308
12951
|
fullWidthPath,
|
|
12952
|
+
photoPaintsGround: renderBackgroundImage,
|
|
12309
12953
|
skinSlot: config$1.skinSlot
|
|
12310
12954
|
}), [renderedBackgroundNode, ...childrenArray]);
|
|
12311
12955
|
}
|
|
@@ -12317,7 +12961,10 @@ function sectionAppearanceProps(input) {
|
|
|
12317
12961
|
from: `${input.bindFrom}.background`,
|
|
12318
12962
|
transforms: [{
|
|
12319
12963
|
id: "sectionStyles.resolveColorsStyle",
|
|
12320
|
-
options: {
|
|
12964
|
+
options: {
|
|
12965
|
+
fallbackToken: input.background,
|
|
12966
|
+
photoPaintsGround: input.photoPaintsGround
|
|
12967
|
+
}
|
|
12321
12968
|
}]
|
|
12322
12969
|
} },
|
|
12323
12970
|
className: { $bind: {
|
|
@@ -13487,70 +14134,6 @@ function applyAlpha(color, opacity) {
|
|
|
13487
14134
|
return color;
|
|
13488
14135
|
}
|
|
13489
14136
|
|
|
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
14137
|
//#endregion
|
|
13555
14138
|
//#region ../blocks/src/system/transforms/registry/_utils/themeColorResolution.ts
|
|
13556
14139
|
function resolveBackgroundColorValue(value, context) {
|
|
@@ -13578,7 +14161,7 @@ function resolveSurfaceForegroundStyles(value, context, options) {
|
|
|
13578
14161
|
const key = JSON.stringify([
|
|
13579
14162
|
value,
|
|
13580
14163
|
context.proseHoverCandidate,
|
|
13581
|
-
options
|
|
14164
|
+
options,
|
|
13582
14165
|
context.data?._lookSlots !== undefined
|
|
13583
14166
|
]);
|
|
13584
14167
|
const cache = sectionSurfaceCache.get(context.theme) ?? new Map();
|
|
@@ -13595,9 +14178,13 @@ function resolveSurfaceForegroundStyles(value, context, options) {
|
|
|
13595
14178
|
}
|
|
13596
14179
|
/** Cache only the owner's result; no foreground or button rules live here. */
|
|
13597
14180
|
function resolveRuntimeSectionSurface(value, context, options) {
|
|
14181
|
+
const background = resolveSectionBackground(parseCanonicalRuntimeBackground({ _sectionStyles: { background: value } }), null, undefined, {
|
|
14182
|
+
paintsGround: options?.photoPaintsGround !== false,
|
|
14183
|
+
fallbackToken: options?.fallbackToken
|
|
14184
|
+
});
|
|
13598
14185
|
return resolveSurface({
|
|
13599
14186
|
kind: "section",
|
|
13600
|
-
background:
|
|
14187
|
+
background: sectionForegroundBackground(background, context.theme.palette)
|
|
13601
14188
|
}, {
|
|
13602
14189
|
palette: context.theme.palette,
|
|
13603
14190
|
buttonSystem: context.theme.buttons,
|
|
@@ -13622,6 +14209,70 @@ function surfaceInkStyles(foreground, palette) {
|
|
|
13622
14209
|
};
|
|
13623
14210
|
}
|
|
13624
14211
|
|
|
14212
|
+
//#endregion
|
|
14213
|
+
//#region ../blocks/src/system/fields/backgroundContent.ts
|
|
14214
|
+
/**
|
|
14215
|
+
* Replaces only the background medium while retaining presentation fields that
|
|
14216
|
+
* are valid for the resulting image variant. Stale color/gradient tab state is
|
|
14217
|
+
* never copied into the new value.
|
|
14218
|
+
*/
|
|
14219
|
+
function replaceBackgroundWithImage(value, image, defaults = {}) {
|
|
14220
|
+
const current = parseBackgroundContent(value);
|
|
14221
|
+
let candidate;
|
|
14222
|
+
if (current?.type === "image") {
|
|
14223
|
+
const { type: _type, image: _image, ...presentation } = current;
|
|
14224
|
+
candidate = {
|
|
14225
|
+
...defaults,
|
|
14226
|
+
...presentation,
|
|
14227
|
+
type: "image",
|
|
14228
|
+
image
|
|
14229
|
+
};
|
|
14230
|
+
} else if (current?.type === "video") {
|
|
14231
|
+
const { type: _type, image: _image, showVideoOnMobile: _mobile, ...presentation } = current;
|
|
14232
|
+
candidate = {
|
|
14233
|
+
...defaults,
|
|
14234
|
+
...presentation,
|
|
14235
|
+
type: "image",
|
|
14236
|
+
image
|
|
14237
|
+
};
|
|
14238
|
+
} else {
|
|
14239
|
+
candidate = {
|
|
14240
|
+
...defaults,
|
|
14241
|
+
...commonPresentation(current),
|
|
14242
|
+
type: "image",
|
|
14243
|
+
image
|
|
14244
|
+
};
|
|
14245
|
+
}
|
|
14246
|
+
const canonical$1 = boxBackgroundSchema.parse(candidate);
|
|
14247
|
+
if (canonical$1.type !== "image") {
|
|
14248
|
+
throw new Error("Image background construction produced a non-image variant");
|
|
14249
|
+
}
|
|
14250
|
+
return canonical$1;
|
|
14251
|
+
}
|
|
14252
|
+
function parseBackgroundContent(value) {
|
|
14253
|
+
const result = boxBackgroundSchema.safeParse(value);
|
|
14254
|
+
return result.success ? result.data : null;
|
|
14255
|
+
}
|
|
14256
|
+
function commonPresentation(background) {
|
|
14257
|
+
return background ? {
|
|
14258
|
+
contentOwner: background.contentOwner,
|
|
14259
|
+
textColor: background.textColor,
|
|
14260
|
+
headingColor: background.headingColor,
|
|
14261
|
+
linkColor: background.linkColor,
|
|
14262
|
+
supportingColor: background.supportingColor
|
|
14263
|
+
} : {};
|
|
14264
|
+
}
|
|
14265
|
+
function parseBackgroundOverlay(value) {
|
|
14266
|
+
const result = boxBackgroundOverlaySchema.safeParse(value);
|
|
14267
|
+
return result.success ? result.data : undefined;
|
|
14268
|
+
}
|
|
14269
|
+
/** Rendering accepts explicit application sources separately from stored references. */
|
|
14270
|
+
const runtimeBackgroundContentSchema = runtimeBoxBackgroundSchema;
|
|
14271
|
+
function parseRuntimeBackgroundContent(value) {
|
|
14272
|
+
const result = runtimeBackgroundContentSchema.safeParse(value);
|
|
14273
|
+
return result.success ? result.data : null;
|
|
14274
|
+
}
|
|
14275
|
+
|
|
13625
14276
|
//#endregion
|
|
13626
14277
|
//#region ../blocks/src/system/transforms/registry/_utils/boxStyleClassNames.ts
|
|
13627
14278
|
/**
|
|
@@ -17857,7 +18508,7 @@ function splitLayoutWith(children) {
|
|
|
17857
18508
|
children
|
|
17858
18509
|
}
|
|
17859
18510
|
}),
|
|
17860
|
-
renderBackgroundImage:
|
|
18511
|
+
renderBackgroundImage: heroPhotoPaintsGround("split"),
|
|
17861
18512
|
baseClass: ""
|
|
17862
18513
|
});
|
|
17863
18514
|
}
|
|
@@ -17873,7 +18524,7 @@ const lookPhoto = el("figure", lookSlot("media"), [media({
|
|
|
17873
18524
|
const lookCopy = el("div", lookSlot("copy"), heroContentNodes);
|
|
17874
18525
|
const heroLookLayout = (children) => styledSection({
|
|
17875
18526
|
baseClass: "",
|
|
17876
|
-
renderBackgroundImage:
|
|
18527
|
+
renderBackgroundImage: heroPhotoPaintsGround("headline-row"),
|
|
17877
18528
|
children: styledContainer({ children: el("div", lookSlot("frame"), children) })
|
|
17878
18529
|
});
|
|
17879
18530
|
const headlineRowLayout = heroLookLayout([
|
|
@@ -18921,8 +19572,24 @@ const blogListingBlockDefinition = {
|
|
|
18921
19572
|
//#endregion
|
|
18922
19573
|
//#region ../blocks/src/system/blocks/cta-full.ts
|
|
18923
19574
|
const ctaComposition = composeFragments([{ fragment: ctaCopyFragment }, { fragment: ctaRowFragment }]);
|
|
19575
|
+
const figureLayout = styledSection({
|
|
19576
|
+
children: sectionContainer([el("div", lookSlot("layout"), [el("div", lookSlot("figure"), [text({
|
|
19577
|
+
as: "p",
|
|
19578
|
+
...lookSlot("figure-value")
|
|
19579
|
+
}, when("content.figure"), bind("content.figure")), text({
|
|
19580
|
+
as: "p",
|
|
19581
|
+
...lookSlot("figure-label")
|
|
19582
|
+
}, when("content.figureNote"), bind("content.figureNote"))], when("content.figure")), el("div", lookSlot("copy"), [...ctaComposition.layout])])], {
|
|
19583
|
+
gap: "md",
|
|
19584
|
+
className: "rb-relative"
|
|
19585
|
+
}),
|
|
19586
|
+
baseClass: ""
|
|
19587
|
+
});
|
|
18924
19588
|
const ctaFullConfig = {
|
|
18925
|
-
variantMeaning: {
|
|
19589
|
+
variantMeaning: {
|
|
19590
|
+
kind: "arrangement",
|
|
19591
|
+
lookOnlyKeys: ["figure"]
|
|
19592
|
+
},
|
|
18926
19593
|
id: "block.cta-full",
|
|
18927
19594
|
title: "Full-width CTA",
|
|
18928
19595
|
category: "marketing",
|
|
@@ -18934,6 +19601,21 @@ const ctaFullConfig = {
|
|
|
18934
19601
|
fragment: ctaRowFragment,
|
|
18935
19602
|
fieldPriority: 2
|
|
18936
19603
|
}],
|
|
19604
|
+
additionalFields: [parseFieldDefinition({
|
|
19605
|
+
id: "figure",
|
|
19606
|
+
type: "text",
|
|
19607
|
+
label: "Big figure",
|
|
19608
|
+
help: "A short number or price, like £12 or 6 weeks.",
|
|
19609
|
+
required: false,
|
|
19610
|
+
defaultValue: ""
|
|
19611
|
+
}), parseFieldDefinition({
|
|
19612
|
+
id: "figureNote",
|
|
19613
|
+
type: "text",
|
|
19614
|
+
label: "Under the figure",
|
|
19615
|
+
help: "A few words under it, like 'your first class'.",
|
|
19616
|
+
required: false,
|
|
19617
|
+
defaultValue: ""
|
|
19618
|
+
})],
|
|
18937
19619
|
layout: styledSection({
|
|
18938
19620
|
children: props(lookSlot("copy"))(sectionContainer(ctaComposition.layout, {
|
|
18939
19621
|
gap: "md",
|
|
@@ -18941,6 +19623,7 @@ const ctaFullConfig = {
|
|
|
18941
19623
|
})),
|
|
18942
19624
|
baseClass: ""
|
|
18943
19625
|
}),
|
|
19626
|
+
variants: { figure: figureLayout },
|
|
18944
19627
|
description: "Centered call to action with optional background image.",
|
|
18945
19628
|
tags: [
|
|
18946
19629
|
"cta",
|
|
@@ -19786,6 +20469,21 @@ const splitHeadingColumnsLayout = styledSection({
|
|
|
19786
20469
|
}),
|
|
19787
20470
|
baseClass: ""
|
|
19788
20471
|
});
|
|
20472
|
+
const openAnswer = el("div", lookSlot("item"), [text({
|
|
20473
|
+
as: "h3",
|
|
20474
|
+
...lookSlot("item-title")
|
|
20475
|
+
}, bind("faqItem.question")), richText({ ...lookSlot("item-text") }, when("faqItem.answer"), bind("faqItem.answer"))], repeat("content.items", "faqItem", { indexName: "faqIndex" }));
|
|
20476
|
+
const openLayout = styledSection({
|
|
20477
|
+
children: styledContainer({
|
|
20478
|
+
baseClassName: "rb-relative rb-isolate",
|
|
20479
|
+
children: stack({
|
|
20480
|
+
gap: "lg",
|
|
20481
|
+
className: "rb-w-full",
|
|
20482
|
+
...lookSlot("layout")
|
|
20483
|
+
}, [headingLayout, el("div", lookSlot("items"), [openAnswer])])
|
|
20484
|
+
}),
|
|
20485
|
+
baseClass: ""
|
|
20486
|
+
});
|
|
19789
20487
|
const faqManifest = createBlockManifest({
|
|
19790
20488
|
id: "block.faq",
|
|
19791
20489
|
title: "FAQ",
|
|
@@ -19809,9 +20507,13 @@ const faqManifest = createBlockManifest({
|
|
|
19809
20507
|
default: defaultLayout,
|
|
19810
20508
|
"two-column": twoColumnLayout,
|
|
19811
20509
|
"question-columns": questionColumnsLayout,
|
|
19812
|
-
"split-heading-columns": splitHeadingColumnsLayout
|
|
20510
|
+
"split-heading-columns": splitHeadingColumnsLayout,
|
|
20511
|
+
open: openLayout
|
|
20512
|
+
},
|
|
20513
|
+
variantMeaning: {
|
|
20514
|
+
kind: "arrangement",
|
|
20515
|
+
lookOnlyKeys: ["open"]
|
|
19813
20516
|
},
|
|
19814
|
-
variantMeaning: { kind: "arrangement" },
|
|
19815
20517
|
defaultVariant: "default",
|
|
19816
20518
|
variantOptions: {
|
|
19817
20519
|
default: {
|
|
@@ -24634,7 +25336,7 @@ const publicEventAttendanceModeSchema = z.enum(["in_person", "online"]);
|
|
|
24634
25336
|
const publicEventAttendanceModeAvailabilitySchema = z.object({
|
|
24635
25337
|
mode: publicEventAttendanceModeSchema,
|
|
24636
25338
|
capacity: z.number().nullable(),
|
|
24637
|
-
registeredCount: z.number(),
|
|
25339
|
+
registeredCount: z.number().nullable(),
|
|
24638
25340
|
availableSpots: z.number().nullable(),
|
|
24639
25341
|
waitlistEnabled: z.boolean()
|
|
24640
25342
|
});
|
|
@@ -24799,7 +25501,7 @@ const publicEventBaseSchema = z.object({
|
|
|
24799
25501
|
startsAt: z.string(),
|
|
24800
25502
|
endsAt: z.string(),
|
|
24801
25503
|
capacity: z.number().nullable(),
|
|
24802
|
-
registeredCount: z.number(),
|
|
25504
|
+
registeredCount: z.number().nullable(),
|
|
24803
25505
|
availableSpots: z.number().nullable(),
|
|
24804
25506
|
waitlistEnabled: z.boolean(),
|
|
24805
25507
|
venue: eventVenueSchema.nullable(),
|
|
@@ -25204,6 +25906,10 @@ function getEventAvailability(event) {
|
|
|
25204
25906
|
isFull: false
|
|
25205
25907
|
};
|
|
25206
25908
|
}
|
|
25909
|
+
if (event.registeredCount === null) return {
|
|
25910
|
+
available: 0,
|
|
25911
|
+
isFull: true
|
|
25912
|
+
};
|
|
25207
25913
|
const available = event.availableSpots ?? event.capacity - event.registeredCount;
|
|
25208
25914
|
if (available <= 0) {
|
|
25209
25915
|
return {
|
|
@@ -25259,12 +25965,12 @@ function lowCapacityThreshold(capacity) {
|
|
|
25259
25965
|
}
|
|
25260
25966
|
function getRemainingPlaces(source) {
|
|
25261
25967
|
const { available, isFull: isFull$1 } = getEventAvailability(source);
|
|
25262
|
-
if (available === null
|
|
25968
|
+
if (available === null) return { kind: "unlimited" };
|
|
25263
25969
|
if (isFull$1) return {
|
|
25264
25970
|
kind: "full",
|
|
25265
25971
|
waitlist: canJoinEventWaitlist(source)
|
|
25266
25972
|
};
|
|
25267
|
-
if (available <= lowCapacityThreshold(source.capacity)) {
|
|
25973
|
+
if (source.capacity !== null && available <= lowCapacityThreshold(source.capacity)) {
|
|
25268
25974
|
return {
|
|
25269
25975
|
kind: "low",
|
|
25270
25976
|
remaining: available
|
|
@@ -25563,6 +26269,30 @@ function createHostedBlockApiConfig(input) {
|
|
|
25563
26269
|
};
|
|
25564
26270
|
}
|
|
25565
26271
|
|
|
26272
|
+
//#endregion
|
|
26273
|
+
//#region ../blocks/src/system/runtime/nodes/events/shared/eventScheduleSummary.ts
|
|
26274
|
+
function bookingDateLocale(siteTimeZone) {
|
|
26275
|
+
return inferSiteDateLocale(resolveBookingBusinessTimeZone(siteTimeZone));
|
|
26276
|
+
}
|
|
26277
|
+
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
26278
|
+
function formatBookingSchedulePresentation(event) {
|
|
26279
|
+
const summary = event.scheduleSummary;
|
|
26280
|
+
if (!summary) return null;
|
|
26281
|
+
const start = summary.startTime ? parseUtcIsoDateTimeString(`1970-01-01T${summary.startTime}:00Z`) : null;
|
|
26282
|
+
const time = start?.ok ? formatTime$1(start.value, {
|
|
26283
|
+
timeZone: resolveBookingTimeZoneId("UTC"),
|
|
26284
|
+
locale: bookingDateLocale(event.siteTimeZone)
|
|
26285
|
+
}, { zone: "omit" }) : null;
|
|
26286
|
+
return {
|
|
26287
|
+
text: [summary.recurrenceDescription, time].filter(Boolean).join(", "),
|
|
26288
|
+
clock: time
|
|
26289
|
+
};
|
|
26290
|
+
}
|
|
26291
|
+
/** Text-only consumers delegate to the same authored-clock presentation. */
|
|
26292
|
+
function formatBookingScheduleSummary(event) {
|
|
26293
|
+
return formatBookingSchedulePresentation(event)?.text ?? null;
|
|
26294
|
+
}
|
|
26295
|
+
|
|
25566
26296
|
//#endregion
|
|
25567
26297
|
//#region ../blocks/src/system/runtime/nodes/events/domain/bookability.ts
|
|
25568
26298
|
/**
|
|
@@ -27786,8 +28516,13 @@ function buildCalendarViewport(input) {
|
|
|
27786
28516
|
}
|
|
27787
28517
|
/** Tick digits are civil clock values, not session instants. */
|
|
27788
28518
|
function formatEventHourLabel(hour, timeZone) {
|
|
27789
|
-
return
|
|
27790
|
-
|
|
28519
|
+
return formatEventClockLabel(`${String(hour % 24).padStart(2, "0")}:00`, eventDateLocale(timeZone));
|
|
28520
|
+
}
|
|
28521
|
+
/** Weekly cadence and tick clocks are civil values; UTC only carries their components. */
|
|
28522
|
+
function formatEventClockLabel(value, locale) {
|
|
28523
|
+
const clock = parseLocalScheduleTime(value);
|
|
28524
|
+
return formatTime$1(toUtcIsoDateTimeString(new Date(Date.UTC(2e3, 0, 1, clock.hour, clock.minute)).toISOString()), {
|
|
28525
|
+
locale,
|
|
27791
28526
|
timeZone: resolveBookingBusinessTimeZone("UTC")
|
|
27792
28527
|
}, { zone: "omit" });
|
|
27793
28528
|
}
|
|
@@ -28206,9 +28941,9 @@ function findBookedEvent(events, identity) {
|
|
|
28206
28941
|
|
|
28207
28942
|
//#endregion
|
|
28208
28943
|
//#region ../blocks/src/system/runtime/nodes/event-registration/ticketSelectionLines.ts
|
|
28209
|
-
/**
|
|
28210
|
-
function canRequestTicketOption(availability) {
|
|
28211
|
-
return availability.kind === "available" || availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable";
|
|
28944
|
+
/** Waitlists request places; bookings can only request currently available capacity. */
|
|
28945
|
+
function canRequestTicketOption(availability, purpose) {
|
|
28946
|
+
return availability.kind === "available" || purpose === "waitlist" && (availability.reason === "sold_out" || availability.reason === "overallCapacityUnavailable");
|
|
28212
28947
|
}
|
|
28213
28948
|
function normalizeTicketSelectionLines(lines) {
|
|
28214
28949
|
const quantitiesByTicketType = new Map();
|
|
@@ -28236,8 +28971,20 @@ function getSingleSelectedPricingOptionId(lines) {
|
|
|
28236
28971
|
function hasValidPricingOptionSelection(input) {
|
|
28237
28972
|
if (!input.selectionRequired) return true;
|
|
28238
28973
|
if (input.lines.length === 0) return false;
|
|
28239
|
-
const
|
|
28240
|
-
return input.lines.every((line) =>
|
|
28974
|
+
const totalSelectedQuantity = getTicketSelectionTotal(input.lines);
|
|
28975
|
+
return input.lines.every((line) => {
|
|
28976
|
+
const option = input.visibleOptions.find((option$1) => option$1.pricingOptionId === line.pricingOptionId);
|
|
28977
|
+
return option !== undefined && line.quantity <= getTicketTypeLineMax({
|
|
28978
|
+
currentQuantity: line.quantity,
|
|
28979
|
+
totalSelectedQuantity,
|
|
28980
|
+
maxTickets: input.maxTickets,
|
|
28981
|
+
purpose: input.purpose,
|
|
28982
|
+
pricingOptionId: option.pricingOptionId,
|
|
28983
|
+
availability: option.availability,
|
|
28984
|
+
heldPlacesBySelection: input.heldPlacesBySelection,
|
|
28985
|
+
overallRemainingPlaces: input.overallRemainingPlaces
|
|
28986
|
+
});
|
|
28987
|
+
});
|
|
28241
28988
|
}
|
|
28242
28989
|
function setTicketLineQuantity(input) {
|
|
28243
28990
|
const nextQuantity = Math.max(0, Math.floor(input.quantity));
|
|
@@ -28251,9 +28998,19 @@ function setTicketLineQuantity(input) {
|
|
|
28251
28998
|
}];
|
|
28252
28999
|
}
|
|
28253
29000
|
function getTicketTypeLineMax(input) {
|
|
29001
|
+
if (!canRequestTicketOption(input.availability, "waitlist")) return 0;
|
|
28254
29002
|
const otherSelectedQuantity = input.totalSelectedQuantity - input.currentQuantity;
|
|
28255
29003
|
const maxByBlock = input.maxTickets - otherSelectedQuantity;
|
|
28256
|
-
return Math.max(0, maxByBlock);
|
|
29004
|
+
if (input.purpose === "waitlist") return Math.max(0, maxByBlock);
|
|
29005
|
+
const heldPlaces = input.heldPlacesBySelection ?? [];
|
|
29006
|
+
const heldForType = getTicketLineQuantity(heldPlaces, input.pricingOptionId);
|
|
29007
|
+
const publicRemaining = canRequestTicketOption(input.availability, input.purpose) ? input.availability.remainingPlaces ?? Infinity : 0;
|
|
29008
|
+
const maxByOverall = (input.overallRemainingPlaces ?? Infinity) + getTicketSelectionTotal(heldPlaces) - otherSelectedQuantity;
|
|
29009
|
+
return Math.max(0, Math.min(maxByBlock, publicRemaining + heldForType, maxByOverall));
|
|
29010
|
+
}
|
|
29011
|
+
/** Holds belong to the original event, mode and ticket types, not the edited draft. */
|
|
29012
|
+
function getHeldPlacesBySelection(current, held) {
|
|
29013
|
+
return held?.selectionId === current.selectionId && held?.attendanceMode === current.attendanceMode ? held.lines : [];
|
|
28257
29014
|
}
|
|
28258
29015
|
|
|
28259
29016
|
//#endregion
|
|
@@ -30174,20 +30931,6 @@ function formatTime$2(isoTimestamp, options) {
|
|
|
30174
30931
|
const { context, zone } = bookingContext(options);
|
|
30175
30932
|
return instant.ok ? formatTime$1(instant.value, context, { zone }) : isoTimestamp;
|
|
30176
30933
|
}
|
|
30177
|
-
function bookingDateLocale(siteTimeZone) {
|
|
30178
|
-
return inferSiteDateLocale(resolveBookingBusinessTimeZone(siteTimeZone));
|
|
30179
|
-
}
|
|
30180
|
-
/** A stored local clock has no date or DST offset; UTC preserves its digits. */
|
|
30181
|
-
function formatBookingScheduleSummary(event) {
|
|
30182
|
-
const summary = event.scheduleSummary;
|
|
30183
|
-
if (!summary) return null;
|
|
30184
|
-
const start = summary.startTime ? parseUtcIsoDateTimeString(`1970-01-01T${summary.startTime}:00Z`) : null;
|
|
30185
|
-
const time = start?.ok ? formatTime$1(start.value, {
|
|
30186
|
-
timeZone: resolveBookingTimeZoneId("UTC"),
|
|
30187
|
-
locale: bookingDateLocale(event.siteTimeZone)
|
|
30188
|
-
}, { zone: "omit" }) : null;
|
|
30189
|
-
return [summary.recurrenceDescription, time].filter(Boolean).join(", ");
|
|
30190
|
-
}
|
|
30191
30934
|
/** Variant meaning is closed here; core owns the resulting typography. */
|
|
30192
30935
|
const BOOKING_DATE_PRESENTATIONS = {
|
|
30193
30936
|
day: {
|
|
@@ -30436,10 +31179,34 @@ function getVisibleTicketTypes(input) {
|
|
|
30436
31179
|
pricingOptionId: id
|
|
30437
31180
|
})) : [];
|
|
30438
31181
|
const source = input.eligibility?.ticketTypes ?? eventTicketTypes;
|
|
30439
|
-
|
|
31182
|
+
const selectedIds = new Set(input.ticketSelections?.map((line) => line.pricingOptionId));
|
|
31183
|
+
return source.map((ticketType) => ticketTypeForSelectionMode(ticketType, input.selectedAttendanceMode)).filter((ticketType) => selectedIds.has(ticketType.pricingOptionId) || ticketType.isActive && ticketTypeMatchesMode(ticketType, input.selectedAttendanceMode));
|
|
31184
|
+
}
|
|
31185
|
+
function ticketTypeForSelectionMode(ticketType, mode) {
|
|
31186
|
+
if (!ticketType.isActive) return {
|
|
31187
|
+
...ticketType,
|
|
31188
|
+
availability: {
|
|
31189
|
+
kind: "unavailable",
|
|
31190
|
+
reason: "inactive",
|
|
31191
|
+
remainingPlaces: ticketType.availability.remainingPlaces
|
|
31192
|
+
}
|
|
31193
|
+
};
|
|
31194
|
+
if (!ticketTypeMatchesMode(ticketType, mode)) return {
|
|
31195
|
+
...ticketType,
|
|
31196
|
+
availability: {
|
|
31197
|
+
kind: "unavailable",
|
|
31198
|
+
reason: "attendance_mode_unavailable",
|
|
31199
|
+
remainingPlaces: ticketType.availability.remainingPlaces
|
|
31200
|
+
}
|
|
31201
|
+
};
|
|
31202
|
+
return ticketType;
|
|
30440
31203
|
}
|
|
30441
|
-
function
|
|
30442
|
-
|
|
31204
|
+
function ticketTypeMatchesMode(ticketType, mode) {
|
|
31205
|
+
const scope = ticketType.attendanceScope ?? "both";
|
|
31206
|
+
return !mode || scope === "both" || scope === mode;
|
|
31207
|
+
}
|
|
31208
|
+
function getImplicitSingleTicketType(ticketTypes, purpose = "book") {
|
|
31209
|
+
return ticketTypes.length === 1 && ticketTypes[0] && canRequestTicketOption(ticketTypes[0].availability, purpose) ? ticketTypes[0] : null;
|
|
30443
31210
|
}
|
|
30444
31211
|
function findSelectedTicketType(input) {
|
|
30445
31212
|
if (!input.selectedPricingOptionId) {
|
|
@@ -32786,6 +33553,27 @@ function getEligibilityFlowFlags(input) {
|
|
|
32786
33553
|
isMembershipFastTrack: input.portalAuthState === "authenticated" && hasMembership && input.ticketsCount === 1 && input.paymentMethod === "membership"
|
|
32787
33554
|
};
|
|
32788
33555
|
}
|
|
33556
|
+
/** Prefer refreshed capacity, including a known zero; fall back while options load. */
|
|
33557
|
+
function getTicketSelectionRemainingPlaces(input) {
|
|
33558
|
+
const availability = input.eligibility?.availability;
|
|
33559
|
+
if (availability && "remainingPlaces" in availability) return availability.remainingPlaces ?? null;
|
|
33560
|
+
return input.event ? getEventAvailability(selectEventCapacitySource(input.event, input.attendanceMode)).available : null;
|
|
33561
|
+
}
|
|
33562
|
+
function resolveHeldTicketPlaces(current, invitation, paymentHold) {
|
|
33563
|
+
const held = invitation.kind === "ready" ? {
|
|
33564
|
+
selectionId: invitation.restoration.event?.selectionId ?? current.selectionId,
|
|
33565
|
+
attendanceMode: invitation.restoration.attendanceMode,
|
|
33566
|
+
lines: invitation.restoration.ticketSelections
|
|
33567
|
+
} : paymentHold;
|
|
33568
|
+
return getHeldPlacesBySelection(current, held);
|
|
33569
|
+
}
|
|
33570
|
+
function getCurrentTicketSelection(event, attendanceMode, lines) {
|
|
33571
|
+
return {
|
|
33572
|
+
selectionId: event?.selectionId ?? null,
|
|
33573
|
+
attendanceMode,
|
|
33574
|
+
lines
|
|
33575
|
+
};
|
|
33576
|
+
}
|
|
32789
33577
|
|
|
32790
33578
|
//#endregion
|
|
32791
33579
|
//#region ../blocks/src/system/runtime/nodes/event-registration/registrationDraft.state.ts
|
|
@@ -35068,9 +35856,7 @@ function buildConfirmationPaymentCandidate(input) {
|
|
|
35068
35856
|
default: return assertNever$7(input);
|
|
35069
35857
|
}
|
|
35070
35858
|
}
|
|
35071
|
-
/**
|
|
35072
|
-
* snapshots deliberately use the amount calculation below instead of this boundary.
|
|
35073
|
-
*/
|
|
35859
|
+
/** Persisted booking payment evidence returns only schema-valid decisions. */
|
|
35074
35860
|
function buildConfirmationPayment(input) {
|
|
35075
35861
|
const payment = buildConfirmationPaymentCandidate(input);
|
|
35076
35862
|
if (!payment.ok) return payment;
|
|
@@ -35081,24 +35867,6 @@ function buildConfirmationPayment(input) {
|
|
|
35081
35867
|
function settledOrderItemTotalCents(item) {
|
|
35082
35868
|
return effectiveOrderItemNetTotalCents(item) + (item.creditCents ?? 0);
|
|
35083
35869
|
}
|
|
35084
|
-
/** Historical notification amounts, not a validated public payment decision.
|
|
35085
|
-
* Preserve HEAD's raw snapshot numbers; strict evidence validation belongs to
|
|
35086
|
-
* the public read boundary, not notification-plan construction (#1587).
|
|
35087
|
-
*/
|
|
35088
|
-
function calculateOrderItemsConfirmationPaymentAmounts(input) {
|
|
35089
|
-
const totalCents = input.items.reduce((total, item) => total + settledOrderItemTotalCents(item), 0);
|
|
35090
|
-
const amountPaidCents = input.settlement.kind === "settled_in_full" ? totalCents : input.settlement.collectedCents;
|
|
35091
|
-
return {
|
|
35092
|
-
amountPaidCents,
|
|
35093
|
-
amountOutstandingCents: calculateOutstandingOrderAmountCents({
|
|
35094
|
-
totalCents,
|
|
35095
|
-
settledCents: amountPaidCents
|
|
35096
|
-
})
|
|
35097
|
-
};
|
|
35098
|
-
}
|
|
35099
|
-
function collectedOrderItemsConfirmationCents(items, collectedCentsByOrderItemId) {
|
|
35100
|
-
return items.reduce((total, item) => total + (collectedCentsByOrderItemId[item.id] ?? 0), 0);
|
|
35101
|
-
}
|
|
35102
35870
|
|
|
35103
35871
|
//#endregion
|
|
35104
35872
|
//#region ../commerce/src/purchase/confirmationEmailPayment.ts
|
|
@@ -35160,56 +35928,9 @@ function toConfirmationEmailPaymentSummary(payment) {
|
|
|
35160
35928
|
default: return assertNever$7(payment);
|
|
35161
35929
|
}
|
|
35162
35930
|
}
|
|
35163
|
-
/** Legacy notification adapter, retained unchanged in meaning until #1587. */
|
|
35164
|
-
function buildOrderItemsConfirmationEmailPaymentSummary(options) {
|
|
35165
|
-
switch (options.orderPaymentMethod) {
|
|
35166
|
-
case "stripe":
|
|
35167
|
-
case "store_credit":
|
|
35168
|
-
case "mixed": {
|
|
35169
|
-
const amounts = calculateOrderItemsConfirmationPaymentAmounts({
|
|
35170
|
-
items: options.items,
|
|
35171
|
-
settlement: options.settlement
|
|
35172
|
-
});
|
|
35173
|
-
return {
|
|
35174
|
-
kind: "monetary",
|
|
35175
|
-
amountPaidCents: amounts.amountPaidCents,
|
|
35176
|
-
...options.settlement.kind === "settled_in_full" ? {} : {
|
|
35177
|
-
amountOutstandingCents: amounts.amountOutstandingCents,
|
|
35178
|
-
dueAt: options.flexibleBalanceDueAt ?? null
|
|
35179
|
-
},
|
|
35180
|
-
currency: options.currency,
|
|
35181
|
-
paymentMethod: options.orderPaymentMethod
|
|
35182
|
-
};
|
|
35183
|
-
}
|
|
35184
|
-
case "pass_redemption": return { kind: "pass" };
|
|
35185
|
-
case "membership_access": return { kind: "membership" };
|
|
35186
|
-
case "manual": return options.flexibleBalanceDueAt ? {
|
|
35187
|
-
kind: "managed_balance_due",
|
|
35188
|
-
dueAt: options.flexibleBalanceDueAt
|
|
35189
|
-
} : { kind: "manual_due" };
|
|
35190
|
-
case "waived": return { kind: "waived" };
|
|
35191
|
-
case "free": return { kind: "free" };
|
|
35192
|
-
default: return assertNever$7(options.orderPaymentMethod);
|
|
35193
|
-
}
|
|
35194
|
-
}
|
|
35195
|
-
function buildOrderItemConfirmationEmailPaymentSummary(options) {
|
|
35196
|
-
return buildOrderItemsConfirmationEmailPaymentSummary({
|
|
35197
|
-
...options,
|
|
35198
|
-
items: [options.item]
|
|
35199
|
-
});
|
|
35200
|
-
}
|
|
35201
|
-
function buildEventRegistrationConfirmationEmailPaymentSummary(options) {
|
|
35202
|
-
return buildNonMonetaryConfirmationEmailPaymentSummary({
|
|
35203
|
-
paymentMethod: options.paymentMethod,
|
|
35204
|
-
passCreditsUsed: options.passCreditsUsed
|
|
35205
|
-
});
|
|
35206
|
-
}
|
|
35207
35931
|
function buildManualAttendeeConfirmationEmailPaymentSummary(options) {
|
|
35208
35932
|
return buildNonMonetaryConfirmationEmailPaymentSummary(options);
|
|
35209
35933
|
}
|
|
35210
|
-
function buildBundleConfirmationEmailPaymentSummary(options) {
|
|
35211
|
-
return buildNonMonetaryConfirmationEmailPaymentSummary(options);
|
|
35212
|
-
}
|
|
35213
35934
|
function buildTransferredAttendeeConfirmationEmailPaymentSummary(options) {
|
|
35214
35935
|
switch (options.paymentMethod) {
|
|
35215
35936
|
case "free":
|
|
@@ -35223,34 +35944,6 @@ function buildTransferredAttendeeConfirmationEmailPaymentSummary(options) {
|
|
|
35223
35944
|
}
|
|
35224
35945
|
return assertNever$7(options.paymentMethod);
|
|
35225
35946
|
}
|
|
35226
|
-
function buildEventSeriesRegistrationConfirmationEmailPaymentSummary(options) {
|
|
35227
|
-
switch (options.paymentMethod) {
|
|
35228
|
-
case "free":
|
|
35229
|
-
case "membership": return buildNonMonetaryConfirmationEmailPaymentSummary({
|
|
35230
|
-
paymentMethod: options.paymentMethod,
|
|
35231
|
-
membershipName: options.membershipName
|
|
35232
|
-
});
|
|
35233
|
-
case "stripe": return buildMonetaryConfirmationEmailPaymentSummary({
|
|
35234
|
-
amountPaidCents: options.amountPaidCents,
|
|
35235
|
-
currency: options.currency,
|
|
35236
|
-
paymentMethod: "stripe"
|
|
35237
|
-
});
|
|
35238
|
-
}
|
|
35239
|
-
return assertNever$7(options.paymentMethod);
|
|
35240
|
-
}
|
|
35241
|
-
function buildBypassedCheckoutConfirmationEmailPaymentSummary(options) {
|
|
35242
|
-
switch (options.bypassReason) {
|
|
35243
|
-
case "free":
|
|
35244
|
-
case "discount_free": return { kind: "free" };
|
|
35245
|
-
case "store_credit": return {
|
|
35246
|
-
kind: "monetary",
|
|
35247
|
-
amountPaidCents: options.settledAmountCents,
|
|
35248
|
-
currency: options.currency,
|
|
35249
|
-
paymentMethod: "store_credit"
|
|
35250
|
-
};
|
|
35251
|
-
}
|
|
35252
|
-
return assertNever$7(options.bypassReason);
|
|
35253
|
-
}
|
|
35254
35947
|
function toConfirmationEmailTemplatePaymentFields(summary) {
|
|
35255
35948
|
if (!summary) {
|
|
35256
35949
|
return {};
|
|
@@ -35814,170 +36507,143 @@ function resolveInstalmentPlanIntroText(input) {
|
|
|
35814
36507
|
|
|
35815
36508
|
//#endregion
|
|
35816
36509
|
//#region ../commerce/src/purchase/orderCompletionEmailPlan.ts
|
|
35817
|
-
function buildEventConfirmationAction(items, options) {
|
|
35818
|
-
const firstItem = items[0];
|
|
35819
|
-
if (!firstItem) {
|
|
35820
|
-
throw new Error("Cannot build an event confirmation without order items");
|
|
35821
|
-
}
|
|
35822
|
-
const settlement = options.settlement;
|
|
35823
|
-
const paymentSummary = buildOrderItemsConfirmationEmailPaymentSummary({
|
|
35824
|
-
orderPaymentMethod: options.orderPaymentMethod,
|
|
35825
|
-
items,
|
|
35826
|
-
currency: options.currency,
|
|
35827
|
-
flexibleBalanceDueAt: options.flexibleBalanceDueAt,
|
|
35828
|
-
settlement: settlement.kind === "settled_in_full" ? settlement : {
|
|
35829
|
-
kind: "collected",
|
|
35830
|
-
collectedCents: collectedOrderItemsConfirmationCents(items, settlement.collectedCentsByOrderItemId)
|
|
35831
|
-
}
|
|
35832
|
-
});
|
|
35833
|
-
return {
|
|
35834
|
-
kind: "send_event_confirmation",
|
|
35835
|
-
attendeeId: firstItem.eventAttendeeId,
|
|
35836
|
-
metadata: {
|
|
35837
|
-
...firstItem.metadata,
|
|
35838
|
-
ticketCount: items.reduce((total, item) => total + item.metadata.ticketCount, 0)
|
|
35839
|
-
},
|
|
35840
|
-
paymentSummary
|
|
35841
|
-
};
|
|
35842
|
-
}
|
|
35843
36510
|
function hasPassBundleFulfillment(metadata) {
|
|
35844
36511
|
return !!metadata.bundleFulfillment;
|
|
35845
36512
|
}
|
|
35846
36513
|
function hasMembershipBundleFulfillment(metadata) {
|
|
35847
36514
|
return !!metadata.bundleFulfillment;
|
|
35848
36515
|
}
|
|
35849
|
-
|
|
35850
|
-
|
|
35851
|
-
|
|
35852
|
-
|
|
36516
|
+
const noActions = () => ({
|
|
36517
|
+
actions: [],
|
|
36518
|
+
warnings: []
|
|
36519
|
+
});
|
|
36520
|
+
function planEventItem(item, input) {
|
|
36521
|
+
const id = item.kind === "event_ticket" ? item.eventAttendeeId : item.eventSeriesRegistrationId;
|
|
36522
|
+
if (!id) return {
|
|
36523
|
+
actions: [],
|
|
36524
|
+
warnings: [{
|
|
36525
|
+
kind: item.kind === "event_ticket" ? "missing_event_attendee_id" : "missing_event_series_registration_id",
|
|
36526
|
+
orderId: item.orderId,
|
|
36527
|
+
orderItemId: item.id
|
|
36528
|
+
}]
|
|
36529
|
+
};
|
|
36530
|
+
const facts = input.bookingFacts.get(id);
|
|
36531
|
+
if (!facts) return noActions();
|
|
36532
|
+
if (item.kind === "event_ticket" && item.eventAttendeeId) return {
|
|
36533
|
+
warnings: [],
|
|
36534
|
+
actions: [{
|
|
36535
|
+
kind: "send_event_confirmation",
|
|
36536
|
+
facts,
|
|
36537
|
+
metadata: item.metadata
|
|
36538
|
+
}]
|
|
36539
|
+
};
|
|
36540
|
+
return {
|
|
36541
|
+
warnings: [],
|
|
36542
|
+
actions: [{
|
|
36543
|
+
kind: "send_event_series_registration_confirmation",
|
|
36544
|
+
orderId: item.orderId,
|
|
36545
|
+
facts
|
|
36546
|
+
}]
|
|
36547
|
+
};
|
|
36548
|
+
}
|
|
36549
|
+
function planPassItem(item, input) {
|
|
36550
|
+
if (!hasPassBundleFulfillment(item.metadata)) return noActions();
|
|
36551
|
+
if (!item.eventAttendeeId) return {
|
|
36552
|
+
actions: [],
|
|
36553
|
+
warnings: [{
|
|
36554
|
+
kind: "missing_event_attendee_id",
|
|
36555
|
+
orderId: item.orderId,
|
|
36556
|
+
orderItemId: item.id
|
|
36557
|
+
}]
|
|
36558
|
+
};
|
|
36559
|
+
const facts = input.bookingFacts.get(item.eventAttendeeId);
|
|
36560
|
+
return facts ? {
|
|
36561
|
+
warnings: [],
|
|
36562
|
+
actions: [{
|
|
36563
|
+
kind: "send_pass_bundle_confirmation",
|
|
36564
|
+
facts,
|
|
36565
|
+
metadata: item.metadata
|
|
36566
|
+
}]
|
|
36567
|
+
} : noActions();
|
|
36568
|
+
}
|
|
36569
|
+
function planMembershipItem(item, input) {
|
|
36570
|
+
if (hasMembershipBundleFulfillment(item.metadata)) {
|
|
36571
|
+
if (!item.eventAttendeeId) return {
|
|
35853
36572
|
actions: [],
|
|
35854
|
-
warnings: [
|
|
36573
|
+
warnings: [{
|
|
36574
|
+
kind: "missing_event_attendee_id",
|
|
36575
|
+
orderId: item.orderId,
|
|
36576
|
+
orderItemId: item.id
|
|
36577
|
+
}]
|
|
35855
36578
|
};
|
|
36579
|
+
const facts = input.bookingFacts.get(item.eventAttendeeId);
|
|
36580
|
+
return facts ? {
|
|
36581
|
+
warnings: [],
|
|
36582
|
+
actions: [{
|
|
36583
|
+
kind: "send_membership_bundle_confirmation",
|
|
36584
|
+
facts,
|
|
36585
|
+
metadata: item.metadata
|
|
36586
|
+
}]
|
|
36587
|
+
} : noActions();
|
|
36588
|
+
}
|
|
36589
|
+
if (!item.customerMembershipId) return {
|
|
36590
|
+
actions: [],
|
|
36591
|
+
warnings: [{
|
|
36592
|
+
kind: "missing_customer_membership_id",
|
|
36593
|
+
orderId: item.orderId,
|
|
36594
|
+
orderItemId: item.id
|
|
36595
|
+
}]
|
|
36596
|
+
};
|
|
36597
|
+
return {
|
|
36598
|
+
warnings: [],
|
|
36599
|
+
actions: [{
|
|
36600
|
+
kind: "send_membership_activation",
|
|
36601
|
+
customerMembershipId: item.customerMembershipId,
|
|
36602
|
+
amountPaidCents: settledOrderItemTotalCents(item)
|
|
36603
|
+
}]
|
|
36604
|
+
};
|
|
36605
|
+
}
|
|
36606
|
+
function planItem(item, input) {
|
|
36607
|
+
switch (item.kind) {
|
|
36608
|
+
case "event_ticket":
|
|
36609
|
+
case "event_series_registration": return planEventItem(item, input);
|
|
36610
|
+
case "pass": return planPassItem(item, input);
|
|
36611
|
+
case "membership": return planMembershipItem(item, input);
|
|
36612
|
+
case "appointment": return item.appointmentId ? {
|
|
36613
|
+
warnings: [],
|
|
36614
|
+
actions: [{
|
|
36615
|
+
kind: "send_appointment_confirmation",
|
|
36616
|
+
appointmentId: item.appointmentId
|
|
36617
|
+
}]
|
|
36618
|
+
} : {
|
|
36619
|
+
actions: [],
|
|
36620
|
+
warnings: [{
|
|
36621
|
+
kind: "missing_appointment_id",
|
|
36622
|
+
orderId: item.orderId,
|
|
36623
|
+
orderItemId: item.id
|
|
36624
|
+
}]
|
|
36625
|
+
};
|
|
36626
|
+
case "product": return noActions();
|
|
35856
36627
|
}
|
|
35857
|
-
|
|
35858
|
-
|
|
35859
|
-
|
|
35860
|
-
|
|
35861
|
-
|
|
35862
|
-
|
|
35863
|
-
|
|
35864
|
-
|
|
35865
|
-
|
|
35866
|
-
|
|
35867
|
-
|
|
35868
|
-
|
|
35869
|
-
|
|
35870
|
-
|
|
35871
|
-
|
|
35872
|
-
|
|
35873
|
-
}
|
|
35874
|
-
plannedEventAttendeeIds.add(item.eventAttendeeId);
|
|
35875
|
-
actions$1.push(buildEventConfirmationAction(options.items.filter((candidate) => candidate.kind === "event_ticket" && candidate.eventAttendeeId === item.eventAttendeeId), {
|
|
35876
|
-
orderPaymentMethod: options.orderPaymentMethod,
|
|
35877
|
-
currency: options.currency,
|
|
35878
|
-
flexibleBalanceDueAt: options.flexibleBalanceDueAt ?? null,
|
|
35879
|
-
settlement: options.settlement
|
|
35880
|
-
}));
|
|
35881
|
-
break;
|
|
35882
|
-
case "pass":
|
|
35883
|
-
if (hasPassBundleFulfillment(item.metadata)) {
|
|
35884
|
-
if (!item.eventAttendeeId) {
|
|
35885
|
-
warnings.push({
|
|
35886
|
-
kind: "missing_event_attendee_id",
|
|
35887
|
-
orderItemId: item.id,
|
|
35888
|
-
orderId: item.orderId
|
|
35889
|
-
});
|
|
35890
|
-
break;
|
|
35891
|
-
}
|
|
35892
|
-
actions$1.push({
|
|
35893
|
-
kind: "send_pass_bundle_confirmation",
|
|
35894
|
-
attendeeId: item.eventAttendeeId,
|
|
35895
|
-
metadata: item.metadata
|
|
35896
|
-
});
|
|
35897
|
-
}
|
|
35898
|
-
break;
|
|
35899
|
-
case "event_series_registration":
|
|
35900
|
-
if (!item.eventSeriesRegistrationId) {
|
|
35901
|
-
warnings.push({
|
|
35902
|
-
kind: "missing_event_series_registration_id",
|
|
35903
|
-
orderItemId: item.id,
|
|
35904
|
-
orderId: item.orderId
|
|
35905
|
-
});
|
|
35906
|
-
break;
|
|
35907
|
-
}
|
|
35908
|
-
actions$1.push({
|
|
35909
|
-
kind: "send_event_series_registration_confirmation",
|
|
35910
|
-
orderId: item.orderId,
|
|
35911
|
-
registrationId: item.eventSeriesRegistrationId,
|
|
35912
|
-
paymentSummary: buildOrderItemConfirmationEmailPaymentSummary({
|
|
35913
|
-
orderPaymentMethod: options.orderPaymentMethod,
|
|
35914
|
-
item,
|
|
35915
|
-
currency: options.currency,
|
|
35916
|
-
flexibleBalanceDueAt: options.flexibleBalanceDueAt ?? null,
|
|
35917
|
-
settlement: options.settlement.kind === "settled_in_full" ? options.settlement : {
|
|
35918
|
-
kind: "collected",
|
|
35919
|
-
collectedCents: options.settlement.collectedCentsByOrderItemId[item.id] ?? 0
|
|
35920
|
-
}
|
|
35921
|
-
})
|
|
35922
|
-
});
|
|
35923
|
-
break;
|
|
35924
|
-
case "appointment":
|
|
35925
|
-
if (!item.appointmentId) {
|
|
35926
|
-
warnings.push({
|
|
35927
|
-
kind: "missing_appointment_id",
|
|
35928
|
-
orderItemId: item.id,
|
|
35929
|
-
orderId: item.orderId
|
|
35930
|
-
});
|
|
35931
|
-
break;
|
|
35932
|
-
}
|
|
35933
|
-
actions$1.push({
|
|
35934
|
-
kind: "send_appointment_confirmation",
|
|
35935
|
-
appointmentId: item.appointmentId
|
|
35936
|
-
});
|
|
35937
|
-
break;
|
|
35938
|
-
case "membership":
|
|
35939
|
-
if (hasMembershipBundleFulfillment(item.metadata)) {
|
|
35940
|
-
if (!item.eventAttendeeId) {
|
|
35941
|
-
warnings.push({
|
|
35942
|
-
kind: "missing_event_attendee_id",
|
|
35943
|
-
orderItemId: item.id,
|
|
35944
|
-
orderId: item.orderId
|
|
35945
|
-
});
|
|
35946
|
-
break;
|
|
35947
|
-
}
|
|
35948
|
-
actions$1.push({
|
|
35949
|
-
kind: "send_membership_bundle_confirmation",
|
|
35950
|
-
attendeeId: item.eventAttendeeId,
|
|
35951
|
-
metadata: item.metadata
|
|
35952
|
-
});
|
|
35953
|
-
break;
|
|
35954
|
-
}
|
|
35955
|
-
if (!item.customerMembershipId) {
|
|
35956
|
-
warnings.push({
|
|
35957
|
-
kind: "missing_customer_membership_id",
|
|
35958
|
-
orderItemId: item.id,
|
|
35959
|
-
orderId: item.orderId
|
|
35960
|
-
});
|
|
35961
|
-
break;
|
|
35962
|
-
}
|
|
35963
|
-
actions$1.push({
|
|
35964
|
-
kind: "send_membership_activation",
|
|
35965
|
-
customerMembershipId: item.customerMembershipId,
|
|
35966
|
-
amountPaidCents: settledOrderItemTotalCents(item)
|
|
35967
|
-
});
|
|
35968
|
-
break;
|
|
35969
|
-
case "product": break;
|
|
35970
|
-
}
|
|
35971
|
-
}
|
|
35972
|
-
if (options.items.some((item) => item.kind === "product" || item.kind === "pass")) {
|
|
35973
|
-
actions$1.unshift({
|
|
35974
|
-
kind: "send_order_confirmation",
|
|
35975
|
-
orderId: firstItem.orderId
|
|
35976
|
-
});
|
|
35977
|
-
}
|
|
36628
|
+
}
|
|
36629
|
+
function bookingGroupId(item) {
|
|
36630
|
+
return item.eventAttendeeId ?? item.eventSeriesRegistrationId ?? null;
|
|
36631
|
+
}
|
|
36632
|
+
/** Complete booking facts are already decided; purchase receipts remain separate. */
|
|
36633
|
+
function buildOrderCompletionEmailPlan(input) {
|
|
36634
|
+
const first = input.items[0];
|
|
36635
|
+
if (!first) return noActions();
|
|
36636
|
+
const plans = input.items.filter((item, index) => {
|
|
36637
|
+
const id = bookingGroupId(item);
|
|
36638
|
+
return id === null || !input.items.slice(0, index).some((previous) => bookingGroupId(previous) === id);
|
|
36639
|
+
}).map((item) => planItem(item, input));
|
|
36640
|
+
const receipt = input.items.some((item) => item.kind === "product" || item.kind === "pass") ? [{
|
|
36641
|
+
kind: "send_order_confirmation",
|
|
36642
|
+
orderId: first.orderId
|
|
36643
|
+
}] : [];
|
|
35978
36644
|
return {
|
|
35979
|
-
actions: actions
|
|
35980
|
-
warnings
|
|
36645
|
+
actions: [...receipt, ...plans.flatMap((plan) => plan.actions)],
|
|
36646
|
+
warnings: plans.flatMap((plan) => plan.warnings)
|
|
35981
36647
|
};
|
|
35982
36648
|
}
|
|
35983
36649
|
|
|
@@ -38389,6 +39055,9 @@ function getStepLabel(step) {
|
|
|
38389
39055
|
function visitorHoldsOwnPlace(input) {
|
|
38390
39056
|
return input.hasWaitlistClaim || input.retryingHeldPlace;
|
|
38391
39057
|
}
|
|
39058
|
+
function getTicketSelectionPurpose(admission) {
|
|
39059
|
+
return admission.kind === "waitlist" ? "waitlist" : "book";
|
|
39060
|
+
}
|
|
38392
39061
|
function resolveRegistrationAdmission(input) {
|
|
38393
39062
|
if (input.holdsOwnPlace) return { kind: "resume" };
|
|
38394
39063
|
if (input.eligibilityLoading) return { kind: "checking" };
|
|
@@ -40939,6 +41608,15 @@ const eventRegistrationManifest = createBlockManifest({
|
|
|
40939
41608
|
], { gap: "lg" })
|
|
40940
41609
|
})]
|
|
40941
41610
|
});
|
|
41611
|
+
const registrationEventScopeParams = {
|
|
41612
|
+
detailAdmission: { $bind: { from: "$root.subject.detailAdmission" } },
|
|
41613
|
+
seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
|
|
41614
|
+
seriesIds: { $bind: {
|
|
41615
|
+
from: "$root.subject.catalogueEventSeriesIds",
|
|
41616
|
+
transforms: [{ id: "value.csv" }]
|
|
41617
|
+
} },
|
|
41618
|
+
runSeriesId: { $bind: { from: "$root.entrySubrouteContext.run.seriesId" } }
|
|
41619
|
+
};
|
|
40942
41620
|
const eventRegistrationBlockDefinition = {
|
|
40943
41621
|
manifest: eventRegistrationManifest,
|
|
40944
41622
|
runtime: eventRegistrationBlockRuntime,
|
|
@@ -40965,12 +41643,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
40965
41643
|
fallback: "published"
|
|
40966
41644
|
} },
|
|
40967
41645
|
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" } },
|
|
41646
|
+
...registrationEventScopeParams,
|
|
40974
41647
|
includeOccurrenceId: { $bind: { from: "$root.occurrenceContext.id" } }
|
|
40975
41648
|
},
|
|
40976
41649
|
mode: "server"
|
|
@@ -40990,12 +41663,7 @@ const eventRegistrationBlockDefinition = {
|
|
|
40990
41663
|
fallback: "published"
|
|
40991
41664
|
} },
|
|
40992
41665
|
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" } }
|
|
41666
|
+
...registrationEventScopeParams
|
|
40999
41667
|
},
|
|
41000
41668
|
mode: "server"
|
|
41001
41669
|
},
|
|
@@ -41472,6 +42140,7 @@ const eventDetailsBlockDefinition = {
|
|
|
41472
42140
|
} },
|
|
41473
42141
|
limit: "100",
|
|
41474
42142
|
readProfile: "details",
|
|
42143
|
+
detailAdmission: { $bind: { from: "$root.subject.detailAdmission" } },
|
|
41475
42144
|
seriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
|
|
41476
42145
|
seriesIds: { $bind: {
|
|
41477
42146
|
from: "$root.subject.catalogueEventSeriesIds",
|
|
@@ -47422,6 +48091,7 @@ const recurringScheduleLayout = styledSection({
|
|
|
47422
48091
|
fallback: "secondary"
|
|
47423
48092
|
} }
|
|
47424
48093
|
}, [text({}, bind("content.seeAllLabel"))], when("content.seeAllUrl"))]), el("recurring-schedule", {
|
|
48094
|
+
dateContext: { $bind: { from: "$root.dateContext" } },
|
|
47425
48095
|
schedule: { $bind: { from: "data.schedule" } },
|
|
47426
48096
|
buttonText: { $bind: {
|
|
47427
48097
|
from: "content.buttonText",
|
|
@@ -50378,7 +51048,12 @@ const contentEntrySchema = z.object({
|
|
|
50378
51048
|
id: z.string().nullable().optional(),
|
|
50379
51049
|
slug: z.string().nullable().optional()
|
|
50380
51050
|
}).nullable();
|
|
51051
|
+
const shopDateContextSchema = z.object({
|
|
51052
|
+
locale: z.string(),
|
|
51053
|
+
timeZone: z.string().transform(resolveBookingBusinessTimeZone)
|
|
51054
|
+
});
|
|
50381
51055
|
const shopSourceSchema = z.object({
|
|
51056
|
+
dateContext: shopDateContextSchema.optional(),
|
|
50382
51057
|
...cardListPresentationSchemaShape,
|
|
50383
51058
|
featured: z.string().nullable().optional(),
|
|
50384
51059
|
className: z.string().nullable().optional(),
|
|
@@ -50543,6 +51218,7 @@ const checkoutDisplaySchema = z.object({
|
|
|
50543
51218
|
submitButtonText: z.string()
|
|
50544
51219
|
});
|
|
50545
51220
|
const passesMembershipsHydrationSchema = z.object({
|
|
51221
|
+
dateContext: shopDateContextSchema,
|
|
50546
51222
|
presentation: z.object(cardListPresentationSchemaShape).optional(),
|
|
50547
51223
|
featured: z.string().optional(),
|
|
50548
51224
|
memberships: z.array(publicMembershipProductSchema),
|
|
@@ -50623,6 +51299,7 @@ const shopBlockRuntime = defineProgressiveBlockRuntime({
|
|
|
50623
51299
|
const passPurchaseMode = source.passPurchaseMode ?? "add_to_cart";
|
|
50624
51300
|
const subscribeButtonText = source.subscribeButtonText ?? "Subscribe";
|
|
50625
51301
|
const products = shopDisplayedProducts(source);
|
|
51302
|
+
const dateContext = source.dateContext ?? resolveDateRuntimeContext(undefined);
|
|
50626
51303
|
return {
|
|
50627
51304
|
display: buildPassesMembershipsDisplay({
|
|
50628
51305
|
cardList: source.lookSlots !== undefined,
|
|
@@ -50643,6 +51320,10 @@ const shopBlockRuntime = defineProgressiveBlockRuntime({
|
|
|
50643
51320
|
hydration: {
|
|
50644
51321
|
...source.lookSlots ? { presentation: shopCardListPresentation(source) } : {},
|
|
50645
51322
|
...shopFeaturedProduct(source, products),
|
|
51323
|
+
dateContext: {
|
|
51324
|
+
locale: dateContext.locale,
|
|
51325
|
+
timeZone: dateContext.timeZone
|
|
51326
|
+
},
|
|
50646
51327
|
memberships: products.memberships,
|
|
50647
51328
|
passPurchaseMode,
|
|
50648
51329
|
buttonVariant: source.buttonVariant ?? "primary",
|
|
@@ -51167,6 +51848,7 @@ const shopManifest = createBlockManifest({
|
|
|
51167
51848
|
featured: { $bind: { from: "content.featured" } },
|
|
51168
51849
|
readAuthority: { $bind: { from: "$root.readAuthority" } },
|
|
51169
51850
|
siteTerms: { $bind: { from: "$root.siteTerms" } },
|
|
51851
|
+
dateContext: { $bind: { from: "$root.dateContext" } },
|
|
51170
51852
|
demoEmailSuppressed: { $bind: {
|
|
51171
51853
|
from: "$root.demoEmailSuppressed",
|
|
51172
51854
|
fallback: false
|
|
@@ -53062,6 +53744,7 @@ function describeUnresolvedLocationMapLocation(resolvedLocation) {
|
|
|
53062
53744
|
}
|
|
53063
53745
|
}
|
|
53064
53746
|
function normalizeLocationMapProps(input) {
|
|
53747
|
+
const parsedHours = parseWeeklyOpeningHours(input.openingHours);
|
|
53065
53748
|
const resolvedLocation = resolveLocationMapLocation(input);
|
|
53066
53749
|
const locationValue = resolvedLocation.kind === "unresolved" ? null : resolvedLocation.locationValue;
|
|
53067
53750
|
const directionsLabel = normalizeLocationAddressText(input.directionsLabel) ?? LOCATION_MAP_DEFAULTS.directionsLabel;
|
|
@@ -53073,6 +53756,8 @@ function normalizeLocationMapProps(input) {
|
|
|
53073
53756
|
location: toLocationCoordinates(locationValue),
|
|
53074
53757
|
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
53758
|
heightPx: Math.min(LOCATION_MAP_LIMITS.heightPx.max, Math.max(LOCATION_MAP_LIMITS.heightPx.min, Math.round(normalizeNumber(input.heightPx, LOCATION_MAP_DEFAULTS.heightPx)))),
|
|
53759
|
+
openingHours: parsedHours.ok ? parsedHours.value : null,
|
|
53760
|
+
showOpeningHours: normalizeBoolean$1(input.showOpeningHours, true),
|
|
53076
53761
|
showAddressText: normalizeBoolean$1(input.showAddressText, LOCATION_MAP_DEFAULTS.showAddressText),
|
|
53077
53762
|
showDirections: normalizeBoolean$1(input.showDirections, LOCATION_MAP_DEFAULTS.showDirections),
|
|
53078
53763
|
directionsLabel,
|
|
@@ -53085,6 +53770,8 @@ function toLocationMapHydrationProps(input) {
|
|
|
53085
53770
|
location: normalized.locationValue,
|
|
53086
53771
|
zoom: normalized.zoom,
|
|
53087
53772
|
heightPx: normalized.heightPx,
|
|
53773
|
+
openingHours: normalized.openingHours,
|
|
53774
|
+
showOpeningHours: normalized.showOpeningHours,
|
|
53088
53775
|
showAddressText: normalized.showAddressText,
|
|
53089
53776
|
showDirections: normalized.showDirections,
|
|
53090
53777
|
directionsLabel: normalized.directionsLabel,
|
|
@@ -53122,6 +53809,7 @@ function normalizeLocationMapContent(content) {
|
|
|
53122
53809
|
heading: typeof record.heading === "string" ? record.heading : undefined,
|
|
53123
53810
|
locationSource,
|
|
53124
53811
|
...authoredLocationMapSourceFields(locationSource, venueId, normalized.locationValue),
|
|
53812
|
+
showOpeningHours: record.showOpeningHours !== false,
|
|
53125
53813
|
showAddressText: normalized.showAddressText,
|
|
53126
53814
|
showDirections: normalized.showDirections,
|
|
53127
53815
|
directionsLabel: normalized.directionsLabel,
|
|
@@ -53255,6 +53943,13 @@ const locationMapManifest = createBlockManifest({
|
|
|
53255
53943
|
}
|
|
53256
53944
|
] }
|
|
53257
53945
|
}),
|
|
53946
|
+
parseFieldDefinition({
|
|
53947
|
+
id: "showOpeningHours",
|
|
53948
|
+
type: "boolean",
|
|
53949
|
+
label: "Show opening hours",
|
|
53950
|
+
defaultValue: true,
|
|
53951
|
+
ui: { intent: "display" }
|
|
53952
|
+
}),
|
|
53258
53953
|
parseFieldDefinition({
|
|
53259
53954
|
id: "showAddressText",
|
|
53260
53955
|
type: "boolean",
|
|
@@ -53316,6 +54011,14 @@ const locationMapManifest = createBlockManifest({
|
|
|
53316
54011
|
baseClass: "",
|
|
53317
54012
|
spacing: "comfortable",
|
|
53318
54013
|
children: sectionContainer([text({ as: "h2" }, bind("content.heading"), when("content.heading")), el("location-map", {
|
|
54014
|
+
openingHours: { $bind: {
|
|
54015
|
+
from: "$root.openingHours",
|
|
54016
|
+
fallback: null
|
|
54017
|
+
} },
|
|
54018
|
+
showOpeningHours: { $bind: {
|
|
54019
|
+
from: "content.showOpeningHours",
|
|
54020
|
+
fallback: true
|
|
54021
|
+
} },
|
|
53319
54022
|
location: { $bind: {
|
|
53320
54023
|
from: "content.location",
|
|
53321
54024
|
fallback: null
|
|
@@ -53368,6 +54071,7 @@ const locationMapBlockDefinition = {
|
|
|
53368
54071
|
"venueId",
|
|
53369
54072
|
"location",
|
|
53370
54073
|
"showAddressText",
|
|
54074
|
+
"showOpeningHours",
|
|
53371
54075
|
"showDirections",
|
|
53372
54076
|
"directionsLabel",
|
|
53373
54077
|
"zoom",
|
|
@@ -58504,6 +59208,7 @@ function validateAppointmentBookingFormSource(input) {
|
|
|
58504
59208
|
}
|
|
58505
59209
|
function normalizeAppointmentBookingServices(input) {
|
|
58506
59210
|
return input.services.map((service) => ({
|
|
59211
|
+
...service.image === undefined ? {} : { image: service.image },
|
|
58507
59212
|
id: service.id,
|
|
58508
59213
|
siteId: input.siteId,
|
|
58509
59214
|
title: service.title,
|
|
@@ -58598,6 +59303,7 @@ const blockBookingPaymentTermsAvailabilitySchema = z.union([z.object({
|
|
|
58598
59303
|
reason: z.literal("online_payment_configured_before_launch")
|
|
58599
59304
|
})]);
|
|
58600
59305
|
const bookingServiceSchema = z.object({
|
|
59306
|
+
image: runtimeMediaSchema.nullable().optional(),
|
|
58601
59307
|
location: z.object({ mode: z.enum([
|
|
58602
59308
|
"online",
|
|
58603
59309
|
"in_person",
|
|
@@ -59103,7 +59809,7 @@ function resolveEventDetailsPresentation(input) {
|
|
|
59103
59809
|
//#region ../blocks/src/system/blocks/offerings-preview/scheduleSummary.ts
|
|
59104
59810
|
function deriveEventScheduleSummary(event) {
|
|
59105
59811
|
const occurrence = occurrenceFromEvent(event);
|
|
59106
|
-
return
|
|
59812
|
+
return compareLocalScheduleDates(getLocalScheduleDate(new Date(occurrence.endsAt), resolveBookingBusinessTimeZone(occurrence.timeZone)), getLocalScheduleDate(new Date(occurrence.startsAt), resolveBookingBusinessTimeZone(occurrence.timeZone))) > 0 ? {
|
|
59107
59813
|
kind: "multi-day-span",
|
|
59108
59814
|
occurrence
|
|
59109
59815
|
} : {
|
|
@@ -59111,23 +59817,18 @@ function deriveEventScheduleSummary(event) {
|
|
|
59111
59817
|
occurrence
|
|
59112
59818
|
};
|
|
59113
59819
|
}
|
|
59114
|
-
function derivePreviewRunSchedule(
|
|
59115
|
-
const sessions = orderedLiveRunSessions(
|
|
59820
|
+
function derivePreviewRunSchedule(event) {
|
|
59821
|
+
const sessions = orderedLiveRunSessions(event.run.sessions).filter(isValidOccurrence);
|
|
59116
59822
|
const first = sessions[0];
|
|
59117
59823
|
const last = sessions[sessions.length - 1];
|
|
59118
59824
|
if (!first || !last) return { kind: "no-live-sessions" };
|
|
59119
|
-
const
|
|
59120
|
-
const summary = sessions.length === 1 ? deriveEventScheduleSummary(first) :
|
|
59121
|
-
kind: "
|
|
59825
|
+
const authoredSummary = formatBookingSchedulePresentation("representative" in event ? event.representative : event);
|
|
59826
|
+
const summary = !authoredSummary && sessions.length === 1 ? deriveEventScheduleSummary(first) : {
|
|
59827
|
+
kind: "scheduled-run",
|
|
59122
59828
|
first,
|
|
59123
59829
|
last,
|
|
59124
59830
|
sessionCount: sessions.length,
|
|
59125
|
-
|
|
59126
|
-
} : {
|
|
59127
|
-
kind: "irregular-multi-session-run",
|
|
59128
|
-
first,
|
|
59129
|
-
last,
|
|
59130
|
-
sessionCount: sessions.length
|
|
59831
|
+
authoredSummary
|
|
59131
59832
|
};
|
|
59132
59833
|
return {
|
|
59133
59834
|
kind: "scheduled",
|
|
@@ -59143,62 +59844,9 @@ function occurrenceFromEvent(event) {
|
|
|
59143
59844
|
timeZone: event.timeZone
|
|
59144
59845
|
};
|
|
59145
59846
|
}
|
|
59146
|
-
function deriveFixedRecurrence(sessions) {
|
|
59147
|
-
const [first, second] = sessions;
|
|
59148
|
-
if (!first || !second) return null;
|
|
59149
|
-
if (!sessions.every((session) => sameLocalTime(first, session))) return null;
|
|
59150
|
-
const intervalDays = localDayNumber(second.startsAt, second.timeZone) - localDayNumber(first.startsAt, first.timeZone);
|
|
59151
|
-
if (intervalDays <= 0) return null;
|
|
59152
|
-
for (let index = 2; index < sessions.length; index += 1) {
|
|
59153
|
-
const previous = sessions[index - 1];
|
|
59154
|
-
const current = sessions[index];
|
|
59155
|
-
if (!previous || !current) return null;
|
|
59156
|
-
const currentInterval = localDayNumber(current.startsAt, current.timeZone) - localDayNumber(previous.startsAt, previous.timeZone);
|
|
59157
|
-
if (currentInterval !== intervalDays) return null;
|
|
59158
|
-
}
|
|
59159
|
-
if (intervalDays === 1) return "Every day";
|
|
59160
|
-
const weekday = localDateParts(first.startsAt, first.timeZone).weekday;
|
|
59161
|
-
if (intervalDays === 7) return `Every ${weekday}`;
|
|
59162
|
-
if (intervalDays % 7 === 0) {
|
|
59163
|
-
return `Every ${intervalDays / 7} weeks on ${weekday}`;
|
|
59164
|
-
}
|
|
59165
|
-
return `Every ${intervalDays} days`;
|
|
59166
|
-
}
|
|
59167
|
-
function sameLocalTime(reference, candidate) {
|
|
59168
|
-
const referenceStart = localDateParts(reference.startsAt, reference.timeZone);
|
|
59169
|
-
const candidateStart = localDateParts(candidate.startsAt, candidate.timeZone);
|
|
59170
|
-
const referenceEnd = localDateParts(reference.endsAt, reference.timeZone);
|
|
59171
|
-
const candidateEnd = localDateParts(candidate.endsAt, candidate.timeZone);
|
|
59172
|
-
return referenceStart.hour === candidateStart.hour && referenceStart.minute === candidateStart.minute && referenceEnd.hour === candidateEnd.hour && referenceEnd.minute === candidateEnd.minute;
|
|
59173
|
-
}
|
|
59174
59847
|
function isValidOccurrence(value) {
|
|
59175
59848
|
return Number.isFinite(Date.parse(value.startsAt)) && Number.isFinite(Date.parse(value.endsAt));
|
|
59176
59849
|
}
|
|
59177
|
-
function localDayNumber(isoTimestamp, timeZone) {
|
|
59178
|
-
const parts = localDateParts(isoTimestamp, timeZone);
|
|
59179
|
-
return Math.floor(Date.UTC(parts.year, parts.month - 1, parts.day) / 864e5);
|
|
59180
|
-
}
|
|
59181
|
-
function localDateParts(isoTimestamp, timeZone) {
|
|
59182
|
-
const parts = new Intl.DateTimeFormat("en-GB", {
|
|
59183
|
-
timeZone,
|
|
59184
|
-
year: "numeric",
|
|
59185
|
-
month: "numeric",
|
|
59186
|
-
day: "numeric",
|
|
59187
|
-
hour: "2-digit",
|
|
59188
|
-
minute: "2-digit",
|
|
59189
|
-
hourCycle: "h23",
|
|
59190
|
-
weekday: "long"
|
|
59191
|
-
}).formatToParts(new Date(isoTimestamp));
|
|
59192
|
-
const value = (type) => parts.find((part) => part.type === type)?.value ?? "";
|
|
59193
|
-
return {
|
|
59194
|
-
year: Number(value("year")),
|
|
59195
|
-
month: Number(value("month")),
|
|
59196
|
-
day: Number(value("day")),
|
|
59197
|
-
hour: Number(value("hour")),
|
|
59198
|
-
minute: Number(value("minute")),
|
|
59199
|
-
weekday: value("weekday")
|
|
59200
|
-
};
|
|
59201
|
-
}
|
|
59202
59850
|
|
|
59203
59851
|
//#endregion
|
|
59204
59852
|
//#region ../blocks/src/system/runtime/nodes/events/shared/eventCardListContent.ts
|
|
@@ -59253,7 +59901,7 @@ function offeringLeadDate(event, startMs) {
|
|
|
59253
59901
|
};
|
|
59254
59902
|
}
|
|
59255
59903
|
function offeringSchedule(event, now) {
|
|
59256
|
-
const run = event.bookingScope === "whole_series" ? derivePreviewRunSchedule(event
|
|
59904
|
+
const run = event.bookingScope === "whole_series" ? derivePreviewRunSchedule(event) : null;
|
|
59257
59905
|
if (run?.kind === "no-live-sessions") return {
|
|
59258
59906
|
numeral: null,
|
|
59259
59907
|
schedule: null
|
|
@@ -59284,7 +59932,7 @@ function scheduleLine(summary, event, now) {
|
|
|
59284
59932
|
date: "short",
|
|
59285
59933
|
year: now ? year(value) : "omit"
|
|
59286
59934
|
});
|
|
59287
|
-
const dates = (startsAt, endsAt) => formatDateRange({
|
|
59935
|
+
const dates = (startsAt, endsAt, order = "chronological") => formatDateRange({
|
|
59288
59936
|
kind: "civil",
|
|
59289
59937
|
value: getLocalScheduleDate(new Date(startsAt), context.timeZone)
|
|
59290
59938
|
}, {
|
|
@@ -59292,6 +59940,7 @@ function scheduleLine(summary, event, now) {
|
|
|
59292
59940
|
value: getLocalScheduleDate(new Date(endsAt), resolveBookingBusinessTimeZone(last.timeZone))
|
|
59293
59941
|
}, context, {
|
|
59294
59942
|
date: "short",
|
|
59943
|
+
order,
|
|
59295
59944
|
year: now && year(startsAt) === "omit" && year(endsAt, resolveBookingBusinessTimeZone(last.timeZone)) === "omit" ? "omit" : now ? "numeric" : "omit"
|
|
59296
59945
|
});
|
|
59297
59946
|
switch (summary.kind) {
|
|
@@ -59305,8 +59954,7 @@ function scheduleLine(summary, event, now) {
|
|
|
59305
59954
|
zone
|
|
59306
59955
|
}) : date(summary.occurrence.startsAt);
|
|
59307
59956
|
case "multi-day-span": return dates(summary.occurrence.startsAt, summary.occurrence.endsAt);
|
|
59308
|
-
case "
|
|
59309
|
-
case "irregular-multi-session-run": return `${dates(summary.first.startsAt, summary.last.startsAt)} · ${summary.sessionCount} dates`;
|
|
59957
|
+
case "scheduled-run": return `${dates(summary.first.startsAt, summary.last.startsAt, "session")} · ${summary.authoredSummary?.text ?? `${summary.sessionCount} dates`}`;
|
|
59310
59958
|
}
|
|
59311
59959
|
}
|
|
59312
59960
|
function offeringAvailability(event) {
|
|
@@ -59945,16 +60593,44 @@ var event_details_server_default = EventDetailsSSR;
|
|
|
59945
60593
|
|
|
59946
60594
|
//#endregion
|
|
59947
60595
|
//#region ../blocks/src/system/runtime/nodes/location-map.view.tsx
|
|
59948
|
-
function
|
|
59949
|
-
|
|
60596
|
+
function OpeningHoursTable({ hours: hours$1 }) {
|
|
60597
|
+
if (!hours$1) return null;
|
|
60598
|
+
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", {
|
|
60599
|
+
"data-closed": row$1.kind === "closed" ? true : undefined,
|
|
60600
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
60601
|
+
scope: "row",
|
|
60602
|
+
children: row$1.label
|
|
60603
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: row$1.hours })]
|
|
60604
|
+
}, row$1.label)) })] }), hours$1.note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: hours$1.note }) : null] });
|
|
60605
|
+
}
|
|
60606
|
+
function LocationMapDirections({ url, label }) {
|
|
60607
|
+
return url ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemedButtonLink, {
|
|
60608
|
+
href: url,
|
|
60609
|
+
target: "_blank",
|
|
60610
|
+
rel: "noreferrer",
|
|
60611
|
+
variant: "ghost",
|
|
60612
|
+
size: "sm",
|
|
60613
|
+
extraClassName: "rb-w-fit",
|
|
60614
|
+
label
|
|
60615
|
+
}) : null;
|
|
60616
|
+
}
|
|
60617
|
+
function LocationMapView(props$1) {
|
|
60618
|
+
const { addressText, location, renderMap, zoom, heightPx, showAddressText, directionsLabel } = props$1;
|
|
60619
|
+
const directionsUrl = props$1.showDirections ? buildGoogleMapsDirectionsUrl({
|
|
59950
60620
|
addressText,
|
|
59951
60621
|
location
|
|
59952
|
-
});
|
|
59953
|
-
|
|
60622
|
+
}) : null;
|
|
60623
|
+
const hours$1 = props$1.showOpeningHours === false ? null : props$1.openingHours ?? null;
|
|
60624
|
+
if (![
|
|
60625
|
+
location,
|
|
60626
|
+
addressText,
|
|
60627
|
+
directionsUrl,
|
|
60628
|
+
hours$1
|
|
60629
|
+
].some(Boolean)) {
|
|
59954
60630
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
59955
60631
|
className: "rb-caption",
|
|
59956
60632
|
style: textColorStyle("mutedText"),
|
|
59957
|
-
children: unresolvedMessage ?? "Location details coming soon."
|
|
60633
|
+
children: props$1.unresolvedMessage ?? "Location details coming soon."
|
|
59958
60634
|
});
|
|
59959
60635
|
}
|
|
59960
60636
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -59972,15 +60648,11 @@ function LocationMapView({ addressText, location, zoom, heightPx, showAddressTex
|
|
|
59972
60648
|
style: textColorStyle("mutedText"),
|
|
59973
60649
|
children: addressText
|
|
59974
60650
|
}) : null,
|
|
59975
|
-
|
|
59976
|
-
|
|
59977
|
-
|
|
59978
|
-
rel: "noreferrer",
|
|
59979
|
-
variant: "ghost",
|
|
59980
|
-
size: "sm",
|
|
59981
|
-
extraClassName: "rb-w-fit",
|
|
60651
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpeningHoursTable, { hours: hours$1 }),
|
|
60652
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationMapDirections, {
|
|
60653
|
+
url: directionsUrl,
|
|
59982
60654
|
label: directionsLabel
|
|
59983
|
-
})
|
|
60655
|
+
})
|
|
59984
60656
|
]
|
|
59985
60657
|
});
|
|
59986
60658
|
}
|
|
@@ -59997,14 +60669,7 @@ function LocationMapSSR(props$1) {
|
|
|
59997
60669
|
children: [
|
|
59998
60670
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IslandPropsScript, { value: hydrationProps }),
|
|
59999
60671
|
/* @__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,
|
|
60672
|
+
...normalized,
|
|
60008
60673
|
renderMap: ({ addressText, className, height }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
60009
60674
|
className,
|
|
60010
60675
|
style: {
|
|
@@ -60646,7 +61311,7 @@ function FeaturedOfferingSummary({ item }) {
|
|
|
60646
61311
|
children: [
|
|
60647
61312
|
details.recurrence ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { children: "Repeats" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: details.recurrence })] }) : null,
|
|
60648
61313
|
details.sessionCount ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { children: "Sessions" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: details.sessionCount })] }) : null,
|
|
60649
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { children: "Time" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: details.timeRange })] }),
|
|
61314
|
+
details.timeRange ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { children: "Time" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: details.timeRange })] }) : null,
|
|
60650
61315
|
details.venue ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", { children: "Venue" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: details.venue })] }) : null
|
|
60651
61316
|
]
|
|
60652
61317
|
})]
|
|
@@ -60660,7 +61325,7 @@ function featuredSummaryDetails(item) {
|
|
|
60660
61325
|
deliveryMode: item.event.deliveryMode
|
|
60661
61326
|
});
|
|
60662
61327
|
case "run": {
|
|
60663
|
-
const schedule = derivePreviewRunSchedule(item.run
|
|
61328
|
+
const schedule = derivePreviewRunSchedule(item.run);
|
|
60664
61329
|
return schedule.kind === "scheduled" ? formatFeaturedSummary(schedule.summary, {
|
|
60665
61330
|
venue: item.run.representative.venue?.name ?? null,
|
|
60666
61331
|
siteTimeZone: item.run.representative.siteTimeZone,
|
|
@@ -60674,33 +61339,33 @@ function formatFeaturedSummary(summary, place) {
|
|
|
60674
61339
|
switch (summary.kind) {
|
|
60675
61340
|
case "single-occurrence": return detailsFromOccurrences({
|
|
60676
61341
|
first: summary.occurrence,
|
|
60677
|
-
|
|
61342
|
+
end: null,
|
|
60678
61343
|
place
|
|
60679
61344
|
});
|
|
60680
61345
|
case "multi-day-span": return detailsFromOccurrences({
|
|
60681
61346
|
first: summary.occurrence,
|
|
60682
|
-
|
|
60683
|
-
|
|
60684
|
-
|
|
60685
|
-
|
|
60686
|
-
|
|
60687
|
-
first: summary.first,
|
|
60688
|
-
last: summary.last,
|
|
60689
|
-
place,
|
|
60690
|
-
recurrence: summary.recurrenceLabel
|
|
61347
|
+
end: {
|
|
61348
|
+
dateTime: summary.occurrence.endsAt,
|
|
61349
|
+
timeZone: summary.occurrence.timeZone
|
|
61350
|
+
},
|
|
61351
|
+
place
|
|
60691
61352
|
});
|
|
60692
|
-
case "
|
|
61353
|
+
case "scheduled-run": return detailsFromOccurrences({
|
|
60693
61354
|
first: summary.first,
|
|
60694
|
-
|
|
61355
|
+
end: {
|
|
61356
|
+
dateTime: summary.last.startsAt,
|
|
61357
|
+
timeZone: summary.last.timeZone
|
|
61358
|
+
},
|
|
60695
61359
|
place,
|
|
60696
|
-
|
|
61360
|
+
recurrence: summary.authoredSummary ?? undefined,
|
|
61361
|
+
sessionCount: `${summary.sessionCount} date${summary.sessionCount === 1 ? "" : "s"}`
|
|
60697
61362
|
});
|
|
60698
61363
|
default: return assertNever(summary, "Unhandled offerings preview schedule summary");
|
|
60699
61364
|
}
|
|
60700
61365
|
}
|
|
60701
61366
|
function detailsFromOccurrences(input) {
|
|
60702
|
-
const { first,
|
|
60703
|
-
const endDateTime =
|
|
61367
|
+
const { first, end, place } = input;
|
|
61368
|
+
const endDateTime = end?.dateTime ?? first.startsAt;
|
|
60704
61369
|
const options = eventDateOptions({
|
|
60705
61370
|
timeZone: first.timeZone,
|
|
60706
61371
|
siteTimeZone: place.siteTimeZone,
|
|
@@ -60710,13 +61375,15 @@ function detailsFromOccurrences(input) {
|
|
|
60710
61375
|
timeZone,
|
|
60711
61376
|
locale: options.locale
|
|
60712
61377
|
});
|
|
61378
|
+
const startDate = summaryDate(first.startsAt, first.timeZone);
|
|
61379
|
+
const endDate = end ? summaryDate(end.dateTime, end.timeZone) : null;
|
|
60713
61380
|
return {
|
|
60714
|
-
startDate
|
|
61381
|
+
startDate,
|
|
60715
61382
|
startDateTime: first.startsAt,
|
|
60716
|
-
endDate:
|
|
61383
|
+
endDate: endDate === startDate ? null : endDate,
|
|
60717
61384
|
endDateTime,
|
|
60718
|
-
timeRange: formatEventTimeRange(first, options),
|
|
60719
|
-
recurrence: input.recurrence ?? null,
|
|
61385
|
+
timeRange: input.recurrence?.clock ? null : formatEventTimeRange(first, options),
|
|
61386
|
+
recurrence: input.recurrence?.text ?? null,
|
|
60720
61387
|
sessionCount: input.sessionCount ?? null,
|
|
60721
61388
|
venue: place.venue
|
|
60722
61389
|
};
|
|
@@ -60766,8 +61433,13 @@ function renderSingleOfferingCard(item, options) {
|
|
|
60766
61433
|
}, item.run.eventSeriesId);
|
|
60767
61434
|
}
|
|
60768
61435
|
}
|
|
61436
|
+
/** The authored clock replaces live time only when it was successfully formatted. */
|
|
61437
|
+
function formatRunScheduleTime(schedule, options) {
|
|
61438
|
+
const authored = schedule.summary.kind === "scheduled-run" ? schedule.summary.authoredSummary : null;
|
|
61439
|
+
return [authored?.text, authored?.clock ? null : formatEventTimeRange(schedule.firstSession, options)].filter(Boolean).join(" · ");
|
|
61440
|
+
}
|
|
60769
61441
|
function WholeSeriesRunCompactRow({ group, path: path$3, now }) {
|
|
60770
|
-
const schedule = derivePreviewRunSchedule(group
|
|
61442
|
+
const schedule = derivePreviewRunSchedule(group);
|
|
60771
61443
|
if (schedule.kind === "no-live-sessions") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunWithoutLiveDates, {
|
|
60772
61444
|
group,
|
|
60773
61445
|
path: path$3
|
|
@@ -60779,7 +61451,7 @@ function WholeSeriesRunCompactRow({ group, path: path$3, now }) {
|
|
|
60779
61451
|
deliveryMode: group.representative.deliveryMode
|
|
60780
61452
|
});
|
|
60781
61453
|
const dateRail = formatEventCompactDateRail(firstSession.startsAt, options);
|
|
60782
|
-
const timeRange =
|
|
61454
|
+
const timeRange = formatRunScheduleTime(schedule, options);
|
|
60783
61455
|
const price$1 = formatEventPriceDisplay(group.representative.pricing);
|
|
60784
61456
|
const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
|
|
60785
61457
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
|
|
@@ -60853,7 +61525,7 @@ function WholeSeriesRunCompactRow({ group, path: path$3, now }) {
|
|
|
60853
61525
|
});
|
|
60854
61526
|
}
|
|
60855
61527
|
function WholeSeriesRunFeatureCard({ group, now, path: path$3, buttonVariant, buttonText }) {
|
|
60856
|
-
const schedule = derivePreviewRunSchedule(group
|
|
61528
|
+
const schedule = derivePreviewRunSchedule(group);
|
|
60857
61529
|
if (schedule.kind === "no-live-sessions") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunWithoutLiveDates, {
|
|
60858
61530
|
group,
|
|
60859
61531
|
path: path$3
|
|
@@ -60865,7 +61537,7 @@ function WholeSeriesRunFeatureCard({ group, now, path: path$3, buttonVariant, bu
|
|
|
60865
61537
|
deliveryMode: group.representative.deliveryMode
|
|
60866
61538
|
});
|
|
60867
61539
|
const formattedDate = formatEventCompactDateRail(firstSession.startsAt, options).label;
|
|
60868
|
-
const timeRange =
|
|
61540
|
+
const timeRange = formatRunScheduleTime(schedule, options);
|
|
60869
61541
|
const price$1 = formatEventPriceDisplay(group.representative.pricing);
|
|
60870
61542
|
const statusLabel = resolveWholeSeriesBookingPhase(group.run, now).kind === "open" ? null : "Registration closed";
|
|
60871
61543
|
const description = group.representative.description;
|
|
@@ -61197,7 +61869,7 @@ function bookingActionContent(input) {
|
|
|
61197
61869
|
default: return assertNever(input.booking);
|
|
61198
61870
|
}
|
|
61199
61871
|
}
|
|
61200
|
-
function RecurringSchedule({ schedule, buttonText = "Book", buttonVariant = "primary", showVenue = true, emptyMessage = "Regular schedule details will be added shortly." }) {
|
|
61872
|
+
function RecurringSchedule({ dateContext = resolveDateRuntimeContext(undefined), schedule, buttonText = "Book", buttonVariant = "primary", showVenue = true, emptyMessage = "Regular schedule details will be added shortly." }) {
|
|
61201
61873
|
const projection = schedule ?? {
|
|
61202
61874
|
items: [],
|
|
61203
61875
|
diagnostics: []
|
|
@@ -61209,8 +61881,28 @@ function RecurringSchedule({ schedule, buttonText = "Book", buttonVariant = "pri
|
|
|
61209
61881
|
children: emptyMessage
|
|
61210
61882
|
});
|
|
61211
61883
|
}
|
|
61212
|
-
|
|
61213
|
-
|
|
61884
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
61885
|
+
className: "recurring-schedule",
|
|
61886
|
+
"data-diagnostic-count": projection.diagnostics.length,
|
|
61887
|
+
role: "list",
|
|
61888
|
+
children: projection.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RecurringScheduleRow, {
|
|
61889
|
+
item,
|
|
61890
|
+
locale: dateContext.locale,
|
|
61891
|
+
buttonText: buttonText ?? "Book",
|
|
61892
|
+
buttonVariant: buttonVariant ?? "primary",
|
|
61893
|
+
showVenue: showVenue ?? true
|
|
61894
|
+
}, item.seriesId))
|
|
61895
|
+
});
|
|
61896
|
+
}
|
|
61897
|
+
function RecurringScheduleRow({ item, locale, buttonText, buttonVariant, showVenue }) {
|
|
61898
|
+
const startLabel = formatEventClockLabel(item.cadence.startTime, locale);
|
|
61899
|
+
const endLabel = formatEventClockLabel(item.cadence.endTime, locale);
|
|
61900
|
+
const description = `${item.title}, ${item.cadence.weekday} at ${startLabel}`;
|
|
61901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", {
|
|
61902
|
+
className: "recurring-schedule-row",
|
|
61903
|
+
role: "listitem",
|
|
61904
|
+
"aria-label": description,
|
|
61905
|
+
children: [
|
|
61214
61906
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
61215
61907
|
className: "recurring-schedule-day",
|
|
61216
61908
|
children: item.cadence.weekday
|
|
@@ -61220,7 +61912,7 @@ function RecurringSchedule({ schedule, buttonText = "Book", buttonVariant = "pri
|
|
|
61220
61912
|
children: [
|
|
61221
61913
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("time", {
|
|
61222
61914
|
dateTime: item.cadence.startTime,
|
|
61223
|
-
children:
|
|
61915
|
+
children: startLabel
|
|
61224
61916
|
}),
|
|
61225
61917
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
61226
61918
|
"aria-hidden": "true",
|
|
@@ -61228,7 +61920,7 @@ function RecurringSchedule({ schedule, buttonText = "Book", buttonVariant = "pri
|
|
|
61228
61920
|
}),
|
|
61229
61921
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("time", {
|
|
61230
61922
|
dateTime: item.cadence.endTime,
|
|
61231
|
-
children:
|
|
61923
|
+
children: endLabel
|
|
61232
61924
|
})
|
|
61233
61925
|
]
|
|
61234
61926
|
}),
|
|
@@ -61246,24 +61938,12 @@ function RecurringSchedule({ schedule, buttonText = "Book", buttonVariant = "pri
|
|
|
61246
61938
|
className: "recurring-schedule-action",
|
|
61247
61939
|
children: bookingActionContent({
|
|
61248
61940
|
booking: item.booking,
|
|
61249
|
-
buttonVariant
|
|
61250
|
-
buttonText
|
|
61251
|
-
accessibleName: `${buttonText
|
|
61941
|
+
buttonVariant,
|
|
61942
|
+
buttonText,
|
|
61943
|
+
accessibleName: `${buttonText} ${description}`
|
|
61252
61944
|
})
|
|
61253
61945
|
})
|
|
61254
|
-
]
|
|
61255
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("article", {
|
|
61256
|
-
className: "recurring-schedule-row",
|
|
61257
|
-
role: "listitem",
|
|
61258
|
-
"aria-label": `${item.title}, ${item.cadence.weekday} at ${item.cadence.startTime}`,
|
|
61259
|
-
children: rowContent
|
|
61260
|
-
});
|
|
61261
|
-
};
|
|
61262
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
61263
|
-
className: "recurring-schedule",
|
|
61264
|
-
"data-diagnostic-count": projection.diagnostics.length,
|
|
61265
|
-
role: "list",
|
|
61266
|
-
children: projection.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Fragment, { children: renderRow(item) }, item.seriesId))
|
|
61946
|
+
]
|
|
61267
61947
|
});
|
|
61268
61948
|
}
|
|
61269
61949
|
|
|
@@ -67189,7 +67869,8 @@ function arrangementContentFacts(content) {
|
|
|
67189
67869
|
photo: photoCount > 0,
|
|
67190
67870
|
facts: Array.isArray(content.facts) && content.facts.length > 0,
|
|
67191
67871
|
featured,
|
|
67192
|
-
outcome: typeof content.outcome === "string" && content.outcome.length > 0
|
|
67872
|
+
outcome: typeof content.outcome === "string" && content.outcome.length > 0,
|
|
67873
|
+
figure: typeof content.figure === "string" && content.figure.trim().length > 0
|
|
67193
67874
|
}
|
|
67194
67875
|
};
|
|
67195
67876
|
}
|
|
@@ -67349,7 +68030,7 @@ function resolveArrangementRoleSurfaces(look, runtime, background) {
|
|
|
67349
68030
|
}
|
|
67350
68031
|
/** The arrangement key is resolved once by planBlock, including pinned Looks. */
|
|
67351
68032
|
function heroPhotoGround(entry) {
|
|
67352
|
-
return entry.kind === "renderable" && entry.block.kind === "block.hero" ? { paintsGround: entry.effectiveArrangementKey
|
|
68033
|
+
return entry.kind === "renderable" && entry.block.kind === "block.hero" ? { paintsGround: heroPhotoPaintsGround(entry.effectiveArrangementKey ?? undefined) } : undefined;
|
|
67353
68034
|
}
|
|
67354
68035
|
/** Header consumers receive the opening that the public render plan actually admits. */
|
|
67355
68036
|
function resolvePageOpeningSection(page, options = {}) {
|
|
@@ -68470,7 +69151,7 @@ function compilePagePushCommands(input) {
|
|
|
68470
69151
|
});
|
|
68471
69152
|
}
|
|
68472
69153
|
function pageCommandRouting(diff) {
|
|
68473
|
-
const changedPages = diff.pages.filter(
|
|
69154
|
+
const changedPages = diff.pages.filter(hasPageOperations);
|
|
68474
69155
|
if (changedPages.length === 0) return { kind: "no_page_changes" };
|
|
68475
69156
|
return { kind: "command_backed" };
|
|
68476
69157
|
}
|
|
@@ -68562,7 +69243,7 @@ function pageCommandReportToSyncResult(report) {
|
|
|
68562
69243
|
});
|
|
68563
69244
|
}
|
|
68564
69245
|
function pageCommandsForDiff(input) {
|
|
68565
|
-
if (
|
|
69246
|
+
if (!hasPageOperations(input.pageDiff)) {
|
|
68566
69247
|
return ok(emptyPageCommandCompileFragment());
|
|
68567
69248
|
}
|
|
68568
69249
|
if (!input.localPage) {
|
|
@@ -68585,10 +69266,7 @@ function pageCommandsForDiff(input) {
|
|
|
68585
69266
|
input: {
|
|
68586
69267
|
identifier: localPageIdentifier,
|
|
68587
69268
|
slug: localPageIdentifier,
|
|
68588
|
-
|
|
68589
|
-
path: input.localPage.path,
|
|
68590
|
-
...input.localPage.seoTitle ? { seoTitle: input.localPage.seoTitle } : {},
|
|
68591
|
-
...input.localPage.seoDescription ? { seoDescription: input.localPage.seoDescription } : {},
|
|
69269
|
+
...pageMetadataForUpsert(input.localPage),
|
|
68592
69270
|
...input.localPage.status ? { status: input.localPage.status } : {}
|
|
68593
69271
|
}
|
|
68594
69272
|
};
|
|
@@ -78049,7 +78727,7 @@ async function loadConfig(configPath, output) {
|
|
|
78049
78727
|
return { errorMessage: "No config path provided." };
|
|
78050
78728
|
}
|
|
78051
78729
|
try {
|
|
78052
|
-
const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-
|
|
78730
|
+
const { loadConfigFile: loadConfigFile$1 } = await import("../load-config-JWz__Dkx.mjs");
|
|
78053
78731
|
const rawConfig = await loadConfigFile$1(configPath);
|
|
78054
78732
|
const parsed = riverbankSiteConfigSchema.safeParse(rawConfig);
|
|
78055
78733
|
if (!parsed.success) {
|
|
@@ -80616,15 +81294,13 @@ function occurrenceCapacityFromOptions(options) {
|
|
|
80616
81294
|
return options.inheritCapacity ? { kind: "inherit" } : undefined;
|
|
80617
81295
|
}
|
|
80618
81296
|
function formatOccurrenceLocal(iso, timeZone) {
|
|
80619
|
-
return
|
|
80620
|
-
|
|
80621
|
-
|
|
80622
|
-
|
|
80623
|
-
|
|
80624
|
-
|
|
80625
|
-
|
|
80626
|
-
hourCycle: "h23"
|
|
80627
|
-
}).format(new Date(iso));
|
|
81297
|
+
return formatDateTime(toUtcIsoDateTimeString(iso), {
|
|
81298
|
+
locale: "en-GB",
|
|
81299
|
+
timeZone: resolveBookingTimeZoneId(timeZone)
|
|
81300
|
+
}, {
|
|
81301
|
+
date: "short",
|
|
81302
|
+
zone: "omit"
|
|
81303
|
+
});
|
|
80628
81304
|
}
|
|
80629
81305
|
function formatDeletionEligibility(occurrence) {
|
|
80630
81306
|
switch (occurrence.deletionEligibility.kind) {
|