@riverbankcms/sdk 0.109.0 → 0.111.0
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/{PreviewEditorSidebar-DWqwfy3_.mjs → PreviewEditorSidebar-CTR6LUhN.mjs} +178 -117
- package/dist/{PreviewEditorUI-B7OL4sfR.mjs → PreviewEditorUI-DZg15Zip.mjs} +3 -4
- package/dist/{PreviewQueryProvider-D0y2l8JN.mjs → PreviewQueryProvider-kkmjklLG.mjs} +1 -1
- package/dist/{SdkPreviewModeRuntime-D8Gt9Gbe.mjs → SdkPreviewModeRuntime-DeOTAFvR.mjs} +229 -219
- package/dist/{SiteChromeCustomizeContext-DUpalEdL.mjs → SiteChromeCustomizeContext-DOSDLCiJ.mjs} +1695 -2169
- package/dist/_dts/ai/src/contracts/proposals.d.ts +1716 -76
- package/dist/_dts/api/src/commercePortalEndpoints.d.ts +5 -5
- package/dist/_dts/api/src/contentRuntime.d.ts +4 -1
- package/dist/_dts/api/src/courses.d.ts +30 -15
- package/dist/_dts/api/src/endpoints.d.ts +14 -4
- package/dist/_dts/api/src/index.d.ts +2 -2
- package/dist/_dts/api/src/sdkContracts.d.ts +23 -11
- package/dist/_dts/api/src/siteManagementEndpoints.d.ts +5 -1
- package/dist/_dts/api/src/siteOperations.d.ts +11 -19
- package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +6 -6
- package/dist/_dts/api/src/webhooks.d.ts +98 -1
- package/dist/_dts/billing/src/site-arrangements.d.ts +3 -0
- package/dist/_dts/blocks/src/client/course-registration.d.ts +4 -1
- package/dist/_dts/blocks/src/client.d.ts +4 -1
- package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +4 -4
- package/dist/_dts/blocks/src/index.d.ts +3 -1
- package/dist/_dts/blocks/src/system/blocks/course-registration.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/courses/shared/types.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/cta-full.d.ts +2 -4
- package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/events/event-listing.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/events/event-spotlight.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/events/recurring-schedule.d.ts +3 -2
- package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/file-download.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/shop.d.ts +2 -1
- package/dist/_dts/blocks/src/system/blocks/single-button.d.ts +2 -1
- package/dist/_dts/blocks/src/system/constants/buttonRoles.d.ts +35 -0
- package/dist/_dts/blocks/src/system/fields/button.d.ts +10 -21
- package/dist/_dts/blocks/src/system/fields/ctas.d.ts +2 -1
- package/dist/_dts/blocks/src/system/fragments/library/heroCtaRow.d.ts +9 -5
- package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +18 -18
- package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +9 -9
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessWholeSeriesRegistrationFlow.d.ts +29 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/buttonAffordance.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/ErrorStep.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/PaymentFailedStep.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/VerifyingTimeoutStep.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/types.d.ts +21 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.d.ts +4 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/whole-series-registration.headless.contract.d.ts +326 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration/whole-series-registration.headless.planning.d.ts +27 -0
- package/dist/_dts/blocks/src/system/runtime/nodes/course-registration.interactive.d.ts +5 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +3 -2
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +5 -4
- package/dist/_dts/blocks/src/system/runtime/nodes/file-download.d.ts +2 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +6 -3
- package/dist/_dts/blocks/src/system/runtime/nodes/shop.interactive.d.ts +7 -6
- package/dist/_dts/blocks/src/system/runtime/nodes/shop.types.d.ts +2 -1
- package/dist/_dts/blocks/src/system/runtime/shared/types.d.ts +2 -1
- package/dist/_dts/content-editor/src/FooterComposerPanel.d.ts +4 -2
- package/dist/_dts/content-editor/src/index.d.ts +12 -12
- package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +17 -2
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +221 -53
- package/dist/_dts/editor-blocks/src/widgets/button/context.d.ts +3 -2
- package/dist/_dts/preview-next/src/client/index.d.ts +3 -2
- package/dist/_dts/preview-next/src/client/preview/ButtonStylePicker.d.ts +16 -0
- package/dist/_dts/preview-next/src/client/preview/PageBlockEditorPanel.d.ts +2 -3
- package/dist/_dts/preview-next/src/client/preview/PreviewDesignOpenRequestContext.d.ts +7 -0
- package/dist/_dts/preview-next/src/client/preview/PreviewEditorSidebar.d.ts +5 -11
- package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +5 -6
- package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +6 -7
- package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +7 -9
- package/dist/_dts/preview-next/src/client/preview/StyleConfigurator.d.ts +4 -11
- package/dist/_dts/preview-next/src/client/preview/StyleConfigurator.state.d.ts +7 -7
- package/dist/_dts/preview-next/src/client/preview/sidebarTabPreference.d.ts +0 -8
- package/dist/_dts/preview-next/src/client/preview/siteChromeLookRows.d.ts +1 -11
- package/dist/_dts/preview-next/src/client/preview/siteChromeQuickControlHistoryState.d.ts +1 -5
- package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +2 -3
- package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +3 -4
- package/dist/_dts/preview-next/src/client/preview/styleConfiguratorSnapshot.d.ts +3 -5
- package/dist/_dts/sdk/src/bookings/index.d.ts +5 -4
- package/dist/_dts/sdk/src/bookings/types.d.ts +3 -3
- package/dist/_dts/sdk/src/cli/commands/style.d.ts +3 -2
- package/dist/_dts/sdk/src/client/management/types.d.ts +2 -1
- package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +12 -15
- package/dist/_dts/sdk/src/public-api/contracts.d.ts +1 -1
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/sdk/src/webhooks/index.d.ts +1 -1
- package/dist/_dts/sdk/src/webhooks/verify.d.ts +3 -3
- package/dist/_dts/site-commands/src/commands.d.ts +129 -6
- package/dist/_dts/theme-core/src/buttons/index.d.ts +1 -1
- package/dist/_dts/theme-core/src/buttons/styles/domain.d.ts +80 -0
- package/dist/_dts/theme-core/src/buttons/styles/index.d.ts +3 -0
- package/dist/_dts/theme-core/src/buttons/styles/recipes/defineStaticButtonStyleRecipe.d.ts +49 -0
- package/dist/_dts/theme-core/src/buttons/styles/recipes/quietArrow.d.ts +67 -0
- package/dist/_dts/theme-core/src/buttons/styles/recipes/staticRecipes.d.ts +649 -0
- package/dist/_dts/theme-core/src/buttons/styles/registry.d.ts +753 -0
- package/dist/_dts/theme-core/src/buttons/styles/selection.d.ts +69 -0
- package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +26 -24
- package/dist/_dts/theme-core/src/site-styles/footerLooks.d.ts +19 -153
- package/dist/_dts/theme-core/src/site-styles/headerCtaVariants.d.ts +3 -1
- package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +8 -9
- package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +4 -4
- package/dist/_dts/ui/src/palette/hex.d.ts +3 -3
- package/dist/cli/index.mjs +1760 -1914
- package/dist/cli/init-docs/content/workflow-isr-revalidation.md +1 -1
- package/dist/client/{DiscountCodeDisclosure-DU1ygxU2.mjs → DiscountCodeDisclosure-C4xvTBux.mjs} +1 -1
- package/dist/client/{EventCombined.client-DB5zagCo.mjs → EventCombined.client-Cr7G131j.mjs} +2 -3
- package/dist/client/{EventListing.client-CTX9JHBL.mjs → EventListing.client-CAjbseNy.mjs} +2 -2
- package/dist/client/{LeafletStaticMap-BYImhgiB.mjs → LeafletStaticMap-BMlWfwz3.mjs} +1 -1
- package/dist/client/{MagicLinkForm-CRkw_M3l.mjs → MagicLinkForm-ChdFz96y.mjs} +1 -2
- package/dist/client/{StepIndicator-BnmVBJJh.mjs → StepIndicator-7D3GaBeM.mjs} +2 -2
- package/dist/client/{accordion-CeGreumd.mjs → accordion-D8JTs2Si.mjs} +1 -1
- package/dist/client/{bookingForm-CSzFNrpN.mjs → bookingForm-H3DCRBHs.mjs} +6 -7
- package/dist/client/bookings.mjs +3069 -1447
- package/dist/client/{carousel-B2jDtogf.mjs → carousel-DMr_QWlz.mjs} +1 -1
- package/dist/client/{cart-D-jZ-vaY.mjs → cart-DWMbfBdR.mjs} +3 -3
- package/dist/client/{checkout-Dza-LA7N.mjs → checkout-zmfdkXLx.mjs} +3 -3
- package/dist/client/client.mjs +1732 -1913
- package/dist/client/{colorStyles-CrgzoXsm.mjs → colorStyles-gcTh5yZT.mjs} +2 -12
- package/dist/client/{colorTokenParts-CMugwvX_.mjs → colorTokenParts-FSS3al6l.mjs} +31 -1
- package/dist/client/{courseRegistration-TYkNychb.mjs → courseRegistration-Z_mn18jy.mjs} +100 -37
- package/dist/client/{eventCalendar-BI_90SsT.mjs → eventCalendar-CYp0YJGF.mjs} +4 -5
- package/dist/client/{eventCombined-mNrpryE9.mjs → eventCombined-rKyYZUa9.mjs} +2 -2
- package/dist/client/{eventDetails-D4GVlCIY.mjs → eventDetails-X0ZaUuMj.mjs} +3 -3
- package/dist/client/{eventListing-YhKN018y.mjs → eventListing-W1SuL7EP.mjs} +2 -2
- package/dist/client/{eventRegistration-CdHGtilr.mjs → eventRegistration-ClWricui.mjs} +6 -7
- package/dist/client/{form-AcAL45rA.mjs → form--eKPwAAD.mjs} +1 -2
- package/dist/client/{headerSection-uEC52ueD.mjs → headerSection-BSeGr-FS.mjs} +2 -3
- package/dist/client/hooks.mjs +1554 -1871
- package/dist/client/{locationMap-_wJDSUYe.mjs → locationMap-BpOrtNYn.mjs} +8 -5
- package/dist/client/{media-BK0O3b-U.mjs → media-DoF0dcVx.mjs} +2 -2
- package/dist/client/{newsletterForm-DrArsb2B.mjs → newsletterForm-Bt7it7Dy.mjs} +1 -2
- package/dist/client/{pricing-BSYVghwo.mjs → pricing-BTjSDDr4.mjs} +1 -1
- package/dist/client/{productDetail-Dyk90sMs.mjs → productDetail-ICnVTcCg.mjs} +3 -3
- package/dist/client/{productList-BCKThwAI.mjs → productList-ZHr6D604.mjs} +3 -3
- package/dist/client/{propsDecoder-CkXxkdSR.mjs → propsDecoder-wWN0tBDF.mjs} +2351 -129
- package/dist/client/rendering/client.mjs +1664 -1824
- package/dist/client/rendering/islands.mjs +20 -20
- package/dist/client/rendering.mjs +1697 -1909
- package/dist/client/{shop-DeltVH10.mjs → shop-C1u_BUn0.mjs} +5 -6
- package/dist/client/{shop-commerce-BD9Jsm2Z.mjs → shop-commerce-CleZdRha.mjs} +5 -6
- package/dist/client/{shop-commerce-store-CmXD6FDS.mjs → shop-commerce-store-ycnoB2Ce.mjs} +1 -1
- package/dist/client/{shopShared-B8v-lH_F.mjs → shopShared-CPhByt2a.mjs} +3 -3
- package/dist/client/{useDiscountCodeUi-DbWJN8ld.mjs → useDiscountCodeUi-cStSQI6C.mjs} +1 -1
- package/dist/client/{useEventFilters-EJIMUnqT.mjs → useEventFilters-DKPN7hSY.mjs} +26 -27
- package/dist/client/{usePolling-Cmh14fc7.mjs → usePolling-BKAd6pkZ.mjs} +2 -2
- package/dist/preview-next/before-render.mjs +37 -6
- package/dist/preview-next/client/runtime.mjs +4 -4
- package/dist/preview-next/middleware.mjs +37 -6
- package/dist/{previewAuthStore-CTO7CRPk.mjs → previewAuthStore-BkT1D06A.mjs} +37 -6
- package/dist/{sdk-runtime-Dou0GAav.mjs → sdk-runtime-hu3wr3ng.mjs} +2 -2
- package/dist/{separator-CI5wZNXT.mjs → separator-Bln8izQ9.mjs} +1 -1
- package/dist/server/components.mjs +1472 -1788
- package/dist/server/config-validation.mjs +1559 -1876
- package/dist/server/config.mjs +1559 -1876
- package/dist/server/data.mjs +1554 -1871
- package/dist/server/index.mjs +38 -7
- package/dist/server/next/revalidate.mjs +53 -1
- package/dist/server/next.mjs +1584 -1869
- package/dist/server/page-converter.mjs +1543 -1860
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +1472 -1788
- package/dist/server/rendering.mjs +1472 -1788
- package/dist/server/routing.mjs +1600 -1891
- package/dist/server/server.mjs +1574 -1860
- package/dist/server/theme-bridge.mjs +1436 -1619
- package/dist/server/theme.mjs +1345 -1241
- package/dist/server/webhooks.mjs +54 -2
- package/package.json +1 -1
- package/dist/_dts/theme-core/src/buttons/personalities/brushed-wash.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/confident-chip.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/earth-pill.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/editorial-link.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/flat-ink.d.ts +0 -20
- package/dist/_dts/theme-core/src/buttons/personalities/index.d.ts +0 -172
- package/dist/_dts/theme-core/src/buttons/personalities/ink-stamp.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/joy-stamp.d.ts +0 -22
- package/dist/_dts/theme-core/src/buttons/personalities/ornate-ritual.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/pebble.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/quiet-arrow.d.ts +0 -17
- package/dist/_dts/theme-core/src/buttons/personalities/showtime-pill.d.ts +0 -17
- package/dist/_dts/theme-core/src/buttons/personalities/soft-pill.d.ts +0 -16
- package/dist/_dts/theme-core/src/buttons/personalities/two-tone-pill.d.ts +0 -17
- package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +0 -285
- package/dist/client/buttons-DoFV7KDL.mjs +0 -2115
- package/dist/client/foregroundContract-xICPq59x.mjs +0 -31
package/dist/client/bookings.mjs
CHANGED
|
@@ -3742,6 +3742,11 @@ function subtractDaysFromIso(isoString, dayCount) {
|
|
|
3742
3742
|
return addDaysToIso(isoString, -dayCount);
|
|
3743
3743
|
}
|
|
3744
3744
|
//#endregion
|
|
3745
|
+
//#region ../core/src/assert-never.ts
|
|
3746
|
+
function assertNever$3(value, message = "Unexpected variant") {
|
|
3747
|
+
throw new Error(`${message}: ${String(value)}`);
|
|
3748
|
+
}
|
|
3749
|
+
//#endregion
|
|
3745
3750
|
//#region ../core/src/currency-format.ts
|
|
3746
3751
|
const CURRENCY_LOCALE_BY_CODE = {
|
|
3747
3752
|
USD: "en-US",
|
|
@@ -4134,6 +4139,25 @@ function addLocalScheduleDays(date, days) {
|
|
|
4134
4139
|
day: utcDate.getUTCDate()
|
|
4135
4140
|
};
|
|
4136
4141
|
}
|
|
4142
|
+
//#endregion
|
|
4143
|
+
//#region ../core/src/planner.ts
|
|
4144
|
+
/** Default clock for production callers that do not inject time explicitly. */
|
|
4145
|
+
const systemPlanningClock = { now: () => Date.now() };
|
|
4146
|
+
/** Resolve current time as a Date from an explicit Date, injected clock, or system clock. */
|
|
4147
|
+
function resolvePlanningNowDate(input = {}) {
|
|
4148
|
+
if (input.now !== void 0) return input.now;
|
|
4149
|
+
return new Date((input.clock ?? systemPlanningClock).now());
|
|
4150
|
+
}
|
|
4151
|
+
/**
|
|
4152
|
+
* Resolve a Date-compatible planner input.
|
|
4153
|
+
*
|
|
4154
|
+
* Precedence: bare Date, `{ now }`, `{ clock }`, then `systemPlanningClock`.
|
|
4155
|
+
* Explicit Date inputs are returned by reference, not cloned.
|
|
4156
|
+
*/
|
|
4157
|
+
function resolvePlanningDateInput(input = {}) {
|
|
4158
|
+
if (input instanceof Date) return input;
|
|
4159
|
+
return resolvePlanningNowDate(input);
|
|
4160
|
+
}
|
|
4137
4161
|
function clearWorkflowFeedback(state) {
|
|
4138
4162
|
return {
|
|
4139
4163
|
...state,
|
|
@@ -7725,7 +7749,7 @@ const gradientDirectionSchema = z$1.enum([
|
|
|
7725
7749
|
"to-br",
|
|
7726
7750
|
"to-bl"
|
|
7727
7751
|
]);
|
|
7728
|
-
const
|
|
7752
|
+
const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
|
|
7729
7753
|
z$1.object({
|
|
7730
7754
|
type: z$1.literal("solid"),
|
|
7731
7755
|
colorToken: opaqueButtonColourTokenSchema
|
|
@@ -7749,6 +7773,7 @@ const buttonBackgroundSchema = z$1.discriminatedUnion("type", [
|
|
|
7749
7773
|
role: z$1.literal("link")
|
|
7750
7774
|
})
|
|
7751
7775
|
]);
|
|
7776
|
+
const buttonBackgroundSchema = buttonColourTreatmentSchema;
|
|
7752
7777
|
const effectApplicationSchema = z$1.object({
|
|
7753
7778
|
effectId: z$1.string(),
|
|
7754
7779
|
options: z$1.record(z$1.string(), z$1.json()).optional()
|
|
@@ -7977,298 +8002,429 @@ function themeButtonClassName(spec) {
|
|
|
7977
8002
|
}
|
|
7978
8003
|
buttonSizeNameSchema.options;
|
|
7979
8004
|
//#endregion
|
|
7980
|
-
//#region ../theme-core/src/
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
"bold"
|
|
7991
|
-
],
|
|
7992
|
-
energy: ["calm", "vibrant"],
|
|
7993
|
-
motion: [
|
|
7994
|
-
"subtle",
|
|
7995
|
-
"standard",
|
|
7996
|
-
"expressive"
|
|
7997
|
-
],
|
|
7998
|
-
era: [
|
|
7999
|
-
"editorial",
|
|
8000
|
-
"modern",
|
|
8001
|
-
"organic",
|
|
8002
|
-
"technical",
|
|
8003
|
-
"retro"
|
|
8004
|
-
]
|
|
8005
|
-
};
|
|
8006
|
-
const styleTagsSchema = z$1.object({
|
|
8007
|
-
tone: z$1.enum(STYLE_AXIS_VALUES.tone).optional(),
|
|
8008
|
-
energy: z$1.enum(STYLE_AXIS_VALUES.energy).optional(),
|
|
8009
|
-
motion: z$1.enum(STYLE_AXIS_VALUES.motion).optional(),
|
|
8010
|
-
era: z$1.enum(STYLE_AXIS_VALUES.era).optional()
|
|
8011
|
-
});
|
|
8012
|
-
//#endregion
|
|
8013
|
-
//#region ../theme-core/src/buttons/personalities/types.ts
|
|
8014
|
-
function asButtonPersonalityId(value) {
|
|
8015
|
-
if (value.length === 0) throw new Error("ButtonPersonalityId must be a non-empty string");
|
|
8016
|
-
return value;
|
|
8005
|
+
//#region ../theme-core/src/buttons/styles/domain.ts
|
|
8006
|
+
const PUBLIC_BUTTON_ROLES = [
|
|
8007
|
+
"primary",
|
|
8008
|
+
"secondary",
|
|
8009
|
+
"outline",
|
|
8010
|
+
"ghost",
|
|
8011
|
+
"accent"
|
|
8012
|
+
];
|
|
8013
|
+
function defineButtonStyleRecipe(recipe) {
|
|
8014
|
+
return recipe;
|
|
8017
8015
|
}
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
});
|
|
8026
|
-
/**
|
|
8027
|
-
* Helper for personality file modules to keep the call site short and
|
|
8028
|
-
* type-safe. `as const satisfies ...` would also work but produces wider
|
|
8029
|
-
* types at use sites.
|
|
8030
|
-
*/
|
|
8031
|
-
function defineButtonPersonality(input) {
|
|
8016
|
+
function materializeButtonRoles(definitions) {
|
|
8017
|
+
const primary = materializeCompleteRole("primary", definitions.primary.appearance);
|
|
8018
|
+
const secondary = materializeCompleteRole("secondary", definitions.secondary.appearance);
|
|
8019
|
+
const completeRoles = {
|
|
8020
|
+
primary,
|
|
8021
|
+
secondary
|
|
8022
|
+
};
|
|
8032
8023
|
return {
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8024
|
+
primary,
|
|
8025
|
+
secondary,
|
|
8026
|
+
outline: materializeSupportingRole("outline", definitions.outline, completeRoles),
|
|
8027
|
+
ghost: materializeSupportingRole("ghost", definitions.ghost, completeRoles),
|
|
8028
|
+
accent: materializeSupportingRole("accent", definitions.accent, completeRoles)
|
|
8029
|
+
};
|
|
8030
|
+
}
|
|
8031
|
+
function resolveButtonStyleRecipe(recipe, parameters) {
|
|
8032
|
+
const parsedParameters = recipe.parameterSchema.safeParse(parameters);
|
|
8033
|
+
if (!parsedParameters.success) return {
|
|
8034
|
+
kind: "error",
|
|
8035
|
+
error: {
|
|
8036
|
+
kind: "invalid-parameters",
|
|
8037
|
+
styleId: recipe.id,
|
|
8038
|
+
issues: parsedParameters.error.issues.map((issue) => issue.message)
|
|
8039
|
+
}
|
|
8040
|
+
};
|
|
8041
|
+
const definition = recipe.defineSystem(parsedParameters.data);
|
|
8042
|
+
const roles = materializeButtonRoles(definition.roles);
|
|
8043
|
+
const buttonSystem = {
|
|
8044
|
+
global: definition.global,
|
|
8045
|
+
variants: PUBLIC_BUTTON_ROLES.map((role) => roles[role]),
|
|
8046
|
+
...definition.sizes ? { sizes: definition.sizes } : {}
|
|
8047
|
+
};
|
|
8048
|
+
const parsedButtonSystem = buttonSystemSchema.safeParse(buttonSystem);
|
|
8049
|
+
if (!parsedButtonSystem.success) return {
|
|
8050
|
+
kind: "error",
|
|
8051
|
+
error: {
|
|
8052
|
+
kind: "invalid-button-system",
|
|
8053
|
+
styleId: recipe.id,
|
|
8054
|
+
issues: parsedButtonSystem.error.issues.map((issue) => issue.message)
|
|
8055
|
+
}
|
|
8056
|
+
};
|
|
8057
|
+
return {
|
|
8058
|
+
kind: "resolved",
|
|
8059
|
+
buttonSystem: parsedButtonSystem.data
|
|
8060
|
+
};
|
|
8061
|
+
}
|
|
8062
|
+
function materializeSupportingRole(role, definition, completeRoles) {
|
|
8063
|
+
if (definition.kind === "complete") return materializeCompleteRole(role, definition.appearance);
|
|
8064
|
+
return {
|
|
8065
|
+
...completeRoles[definition.from],
|
|
8066
|
+
...definition.overrides,
|
|
8067
|
+
id: role,
|
|
8068
|
+
name: roleName(role),
|
|
8069
|
+
enabled: true,
|
|
8070
|
+
priority: 3
|
|
8071
|
+
};
|
|
8072
|
+
}
|
|
8073
|
+
function materializeCompleteRole(role, appearance) {
|
|
8074
|
+
return {
|
|
8075
|
+
...appearance,
|
|
8076
|
+
id: role,
|
|
8077
|
+
name: roleName(role),
|
|
8078
|
+
enabled: true,
|
|
8079
|
+
priority: rolePriority(role)
|
|
8038
8080
|
};
|
|
8039
8081
|
}
|
|
8082
|
+
function roleName(role) {
|
|
8083
|
+
return role.charAt(0).toUpperCase() + role.slice(1);
|
|
8084
|
+
}
|
|
8085
|
+
function rolePriority(role) {
|
|
8086
|
+
if (role === "primary") return 1;
|
|
8087
|
+
if (role === "secondary") return 2;
|
|
8088
|
+
return 3;
|
|
8089
|
+
}
|
|
8040
8090
|
//#endregion
|
|
8041
|
-
//#region ../theme-core/src/buttons/
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8091
|
+
//#region ../theme-core/src/buttons/styles/selection.ts
|
|
8092
|
+
const BUTTON_STYLE_IDS = [
|
|
8093
|
+
"soft-pill",
|
|
8094
|
+
"earth-pill",
|
|
8095
|
+
"confident-chip",
|
|
8096
|
+
"editorial-link",
|
|
8097
|
+
"pebble",
|
|
8098
|
+
"ink-stamp",
|
|
8099
|
+
"flat-ink",
|
|
8100
|
+
"brushed-wash",
|
|
8101
|
+
"showtime-pill",
|
|
8102
|
+
"joy-stamp",
|
|
8103
|
+
"ornate-ritual",
|
|
8104
|
+
"quiet-arrow"
|
|
8105
|
+
];
|
|
8106
|
+
const quietArrowParametersSchema = z$1.object({ secondaryTreatment: z$1.enum(["outlined", "solid-accent"]) }).strict();
|
|
8107
|
+
const emptyParametersSchema$1 = z$1.object({}).strict();
|
|
8108
|
+
function selectionBranch(styleId, parameters) {
|
|
8109
|
+
return z$1.object({
|
|
8110
|
+
styleId: z$1.literal(styleId),
|
|
8111
|
+
parameters
|
|
8112
|
+
}).strict();
|
|
8113
|
+
}
|
|
8114
|
+
z$1.discriminatedUnion("styleId", [
|
|
8115
|
+
selectionBranch("soft-pill", emptyParametersSchema$1),
|
|
8116
|
+
selectionBranch("earth-pill", emptyParametersSchema$1),
|
|
8117
|
+
selectionBranch("confident-chip", emptyParametersSchema$1),
|
|
8118
|
+
selectionBranch("editorial-link", emptyParametersSchema$1),
|
|
8119
|
+
selectionBranch("pebble", emptyParametersSchema$1),
|
|
8120
|
+
selectionBranch("ink-stamp", emptyParametersSchema$1),
|
|
8121
|
+
selectionBranch("flat-ink", emptyParametersSchema$1),
|
|
8122
|
+
selectionBranch("brushed-wash", emptyParametersSchema$1),
|
|
8123
|
+
selectionBranch("showtime-pill", emptyParametersSchema$1),
|
|
8124
|
+
selectionBranch("joy-stamp", emptyParametersSchema$1),
|
|
8125
|
+
selectionBranch("ornate-ritual", emptyParametersSchema$1),
|
|
8126
|
+
selectionBranch("quiet-arrow", quietArrowParametersSchema)
|
|
8127
|
+
]);
|
|
8128
|
+
//#endregion
|
|
8129
|
+
//#region ../theme-core/src/buttons/styles/recipes/quietArrow.ts
|
|
8130
|
+
const quietArrowRecipe = defineButtonStyleRecipe({
|
|
8131
|
+
id: "quiet-arrow",
|
|
8132
|
+
accessibilityLabel: "Wide uppercase buttons with trailing arrows",
|
|
8050
8133
|
tags: {
|
|
8051
8134
|
tone: "classic",
|
|
8052
|
-
energy: "
|
|
8053
|
-
motion: "
|
|
8054
|
-
era: "
|
|
8135
|
+
energy: "calm",
|
|
8136
|
+
motion: "subtle",
|
|
8137
|
+
era: "editorial"
|
|
8055
8138
|
},
|
|
8056
|
-
|
|
8139
|
+
parameterSchema: quietArrowParametersSchema,
|
|
8140
|
+
defaultParameters: { secondaryTreatment: "outlined" },
|
|
8141
|
+
controls: [{
|
|
8142
|
+
kind: "choice",
|
|
8143
|
+
parameter: "secondaryTreatment",
|
|
8144
|
+
label: "Secondary button treatment",
|
|
8145
|
+
options: [{
|
|
8146
|
+
value: "outlined",
|
|
8147
|
+
label: "Outlined"
|
|
8148
|
+
}, {
|
|
8149
|
+
value: "solid-accent",
|
|
8150
|
+
label: "Solid accent"
|
|
8151
|
+
}]
|
|
8152
|
+
}],
|
|
8153
|
+
defineSystem: (parameters) => ({
|
|
8057
8154
|
global: {
|
|
8058
8155
|
cornerStyle: "rounded",
|
|
8059
|
-
|
|
8060
|
-
textTransform: "none",
|
|
8156
|
+
textTransform: "uppercase",
|
|
8061
8157
|
fontWeight: 500,
|
|
8062
8158
|
borderWidth: 1,
|
|
8159
|
+
typography: "body",
|
|
8160
|
+
fontSize: "text-sm",
|
|
8161
|
+
letterSpacing: "loose",
|
|
8063
8162
|
hoverTransform: "none",
|
|
8064
8163
|
hoverColor: "none"
|
|
8065
8164
|
},
|
|
8066
8165
|
sizes: {
|
|
8067
8166
|
sm: {
|
|
8068
|
-
padding: "0.
|
|
8167
|
+
padding: "0.625rem 1.25rem",
|
|
8168
|
+
fontSize: "text-xs"
|
|
8169
|
+
},
|
|
8170
|
+
md: {
|
|
8171
|
+
padding: "0.8125rem 1.75rem",
|
|
8069
8172
|
fontSize: "text-sm"
|
|
8070
8173
|
},
|
|
8071
|
-
md: { padding: "1rem 2.5rem" },
|
|
8072
8174
|
lg: {
|
|
8073
|
-
padding: "
|
|
8074
|
-
fontSize: "text-
|
|
8175
|
+
padding: "0.9375rem 2.125rem",
|
|
8176
|
+
fontSize: "text-sm"
|
|
8075
8177
|
},
|
|
8076
8178
|
xl: {
|
|
8077
|
-
padding: "1.
|
|
8078
|
-
fontSize: "text-
|
|
8179
|
+
padding: "1.0625rem 2.5rem",
|
|
8180
|
+
fontSize: "text-base"
|
|
8079
8181
|
}
|
|
8080
8182
|
},
|
|
8081
|
-
|
|
8082
|
-
{
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
elevation: "low",
|
|
8096
|
-
softness: "soft",
|
|
8097
|
-
position: "bottom"
|
|
8183
|
+
roles: {
|
|
8184
|
+
primary: {
|
|
8185
|
+
kind: "complete",
|
|
8186
|
+
appearance: {
|
|
8187
|
+
background: {
|
|
8188
|
+
type: "solid",
|
|
8189
|
+
colorToken: unsafeAsOpaqueButtonColourToken("primary")
|
|
8190
|
+
},
|
|
8191
|
+
borderRadius: "rounded-xl",
|
|
8192
|
+
affordance: { iconId: "ArrowRight" },
|
|
8193
|
+
effects: { hover: [{
|
|
8194
|
+
effectId: "darken-background",
|
|
8195
|
+
options: { amount: 100 }
|
|
8196
|
+
}] }
|
|
8098
8197
|
}
|
|
8099
8198
|
},
|
|
8100
|
-
{
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8199
|
+
secondary: {
|
|
8200
|
+
kind: "complete",
|
|
8201
|
+
appearance: parameters.secondaryTreatment === "solid-accent" ? {
|
|
8202
|
+
background: {
|
|
8203
|
+
type: "solid",
|
|
8204
|
+
colorToken: unsafeAsOpaqueButtonColourToken("accent")
|
|
8205
|
+
},
|
|
8206
|
+
borderRadius: "rounded-xl",
|
|
8207
|
+
affordance: { iconId: "ArrowRight" },
|
|
8208
|
+
effects: { hover: [{
|
|
8209
|
+
effectId: "darken-background",
|
|
8210
|
+
options: { amount: 100 }
|
|
8211
|
+
}] }
|
|
8212
|
+
} : {
|
|
8213
|
+
background: {
|
|
8214
|
+
type: "surface",
|
|
8215
|
+
role: "link"
|
|
8216
|
+
},
|
|
8217
|
+
borderRadius: "rounded-xl",
|
|
8218
|
+
border: { widthClass: "border" },
|
|
8219
|
+
affordance: { iconId: "ArrowRight" },
|
|
8220
|
+
effects: { hover: [{
|
|
8221
|
+
effectId: "background-on-hover",
|
|
8222
|
+
options: { colorToken: "surfaceAlt" }
|
|
8223
|
+
}] }
|
|
8116
8224
|
}
|
|
8117
8225
|
},
|
|
8118
|
-
{
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
border: { widthClass: "border" },
|
|
8129
|
-
effects: { hover: [{
|
|
8130
|
-
effectId: "background-on-hover",
|
|
8131
|
-
options: { colorToken: "surface" }
|
|
8132
|
-
}] }
|
|
8226
|
+
outline: {
|
|
8227
|
+
kind: "complete",
|
|
8228
|
+
appearance: {
|
|
8229
|
+
background: {
|
|
8230
|
+
type: "surface",
|
|
8231
|
+
role: "link"
|
|
8232
|
+
},
|
|
8233
|
+
borderRadius: "rounded-xl",
|
|
8234
|
+
border: { widthClass: "border" }
|
|
8235
|
+
}
|
|
8133
8236
|
},
|
|
8134
|
-
{
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
}
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8237
|
+
ghost: {
|
|
8238
|
+
kind: "complete",
|
|
8239
|
+
appearance: {
|
|
8240
|
+
background: {
|
|
8241
|
+
type: "surface",
|
|
8242
|
+
role: "link"
|
|
8243
|
+
},
|
|
8244
|
+
borderRadius: "rounded-xl"
|
|
8245
|
+
}
|
|
8246
|
+
},
|
|
8247
|
+
accent: {
|
|
8248
|
+
kind: "derive",
|
|
8249
|
+
from: "primary",
|
|
8250
|
+
overrides: { background: {
|
|
8251
|
+
type: "solid",
|
|
8252
|
+
colorToken: unsafeAsOpaqueButtonColourToken("accent")
|
|
8253
|
+
} }
|
|
8148
8254
|
}
|
|
8149
|
-
|
|
8150
|
-
}
|
|
8255
|
+
}
|
|
8256
|
+
})
|
|
8151
8257
|
});
|
|
8152
8258
|
//#endregion
|
|
8153
|
-
//#region ../theme-core/src/buttons/
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8259
|
+
//#region ../theme-core/src/buttons/styles/recipes/defineStaticButtonStyleRecipe.ts
|
|
8260
|
+
const emptyParametersSchema = z$1.object({}).strict();
|
|
8261
|
+
function defineStaticButtonStyleRecipe(input) {
|
|
8262
|
+
const system = normalizeSystem(input.system);
|
|
8263
|
+
return defineButtonStyleRecipe({
|
|
8264
|
+
id: input.id,
|
|
8265
|
+
accessibilityLabel: input.accessibilityLabel,
|
|
8266
|
+
tags: input.tags,
|
|
8267
|
+
parameterSchema: emptyParametersSchema,
|
|
8268
|
+
defaultParameters: {},
|
|
8269
|
+
controls: [],
|
|
8270
|
+
defineSystem: () => system
|
|
8271
|
+
});
|
|
8272
|
+
}
|
|
8273
|
+
function normalizeSystem(input) {
|
|
8274
|
+
return {
|
|
8275
|
+
global: buttonGlobalSettingsSchema.parse(input.global),
|
|
8276
|
+
...input.sizes ? { sizes: input.sizes } : {},
|
|
8277
|
+
roles: {
|
|
8278
|
+
primary: normalizeCompleteRole(input.roles.primary),
|
|
8279
|
+
secondary: normalizeCompleteRole(input.roles.secondary),
|
|
8280
|
+
outline: normalizeSupportingRole(input.roles.outline),
|
|
8281
|
+
ghost: normalizeSupportingRole(input.roles.ghost),
|
|
8282
|
+
accent: normalizeSupportingRole(input.roles.accent)
|
|
8283
|
+
}
|
|
8284
|
+
};
|
|
8285
|
+
}
|
|
8286
|
+
function normalizeCompleteRole(role) {
|
|
8287
|
+
return {
|
|
8288
|
+
kind: "complete",
|
|
8289
|
+
appearance: normalizeAppearance(role.appearance)
|
|
8290
|
+
};
|
|
8291
|
+
}
|
|
8292
|
+
function normalizeSupportingRole(role) {
|
|
8293
|
+
if (role.kind === "complete") return normalizeCompleteRole(role);
|
|
8294
|
+
return {
|
|
8295
|
+
kind: "derive",
|
|
8296
|
+
from: role.from,
|
|
8297
|
+
...role.overrides ? { overrides: normalizeAppearanceOverrides(role.overrides) } : {}
|
|
8298
|
+
};
|
|
8299
|
+
}
|
|
8300
|
+
function normalizeAppearance(appearance) {
|
|
8301
|
+
const { background, hoverBackgroundToken, ...rest } = appearance;
|
|
8302
|
+
return {
|
|
8303
|
+
...rest,
|
|
8304
|
+
background: buttonColourTreatmentSchema.parse(background),
|
|
8305
|
+
...hoverBackgroundToken ? { hoverBackgroundToken: opaqueButtonColourTokenSchema.parse(hoverBackgroundToken) } : {}
|
|
8306
|
+
};
|
|
8307
|
+
}
|
|
8308
|
+
function normalizeAppearanceOverrides(overrides) {
|
|
8309
|
+
const { background, hoverBackgroundToken, ...rest } = overrides;
|
|
8310
|
+
return {
|
|
8311
|
+
...rest,
|
|
8312
|
+
...background ? { background: buttonColourTreatmentSchema.parse(background) } : {},
|
|
8313
|
+
...hoverBackgroundToken ? { hoverBackgroundToken: opaqueButtonColourTokenSchema.parse(hoverBackgroundToken) } : {}
|
|
8314
|
+
};
|
|
8315
|
+
}
|
|
8316
|
+
//#endregion
|
|
8317
|
+
//#region ../theme-core/src/buttons/styles/recipes/staticRecipes.ts
|
|
8318
|
+
const softPillRecipe = defineStaticButtonStyleRecipe({
|
|
8319
|
+
id: "soft-pill",
|
|
8320
|
+
accessibilityLabel: "Rounded pill buttons with a gentle hover lift",
|
|
8162
8321
|
tags: {
|
|
8163
8322
|
tone: "classic",
|
|
8164
8323
|
energy: "calm",
|
|
8165
|
-
motion: "
|
|
8166
|
-
era: "
|
|
8324
|
+
motion: "subtle",
|
|
8325
|
+
era: "organic"
|
|
8167
8326
|
},
|
|
8168
|
-
|
|
8327
|
+
system: {
|
|
8169
8328
|
global: {
|
|
8170
|
-
cornerStyle: "
|
|
8171
|
-
shadow: "
|
|
8329
|
+
cornerStyle: "pill",
|
|
8330
|
+
shadow: "low",
|
|
8172
8331
|
textTransform: "none",
|
|
8173
|
-
fontWeight:
|
|
8174
|
-
borderWidth:
|
|
8175
|
-
hoverTransform: "
|
|
8332
|
+
fontWeight: 500,
|
|
8333
|
+
borderWidth: 2,
|
|
8334
|
+
hoverTransform: "lift",
|
|
8176
8335
|
hoverColor: "none"
|
|
8177
8336
|
},
|
|
8178
|
-
|
|
8179
|
-
{
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
}]
|
|
8337
|
+
roles: {
|
|
8338
|
+
primary: {
|
|
8339
|
+
kind: "complete",
|
|
8340
|
+
appearance: {
|
|
8341
|
+
background: {
|
|
8342
|
+
type: "solid",
|
|
8343
|
+
colorToken: "primary"
|
|
8344
|
+
},
|
|
8345
|
+
borderRadius: "rounded-full",
|
|
8346
|
+
shadow: {
|
|
8347
|
+
elevation: "low",
|
|
8348
|
+
softness: "soft",
|
|
8349
|
+
position: "bottom"
|
|
8350
|
+
},
|
|
8351
|
+
effects: {
|
|
8352
|
+
hover: [{
|
|
8353
|
+
effectId: "lift",
|
|
8354
|
+
options: { translateY: "-1px" }
|
|
8355
|
+
}],
|
|
8356
|
+
active: [{
|
|
8357
|
+
effectId: "scale-down",
|
|
8358
|
+
options: { scale: "0.98" }
|
|
8359
|
+
}]
|
|
8360
|
+
}
|
|
8203
8361
|
}
|
|
8204
8362
|
},
|
|
8205
|
-
{
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
}] }
|
|
8363
|
+
secondary: {
|
|
8364
|
+
kind: "complete",
|
|
8365
|
+
appearance: {
|
|
8366
|
+
background: {
|
|
8367
|
+
type: "surface",
|
|
8368
|
+
role: "link"
|
|
8369
|
+
},
|
|
8370
|
+
borderRadius: "rounded-full",
|
|
8371
|
+
border: { widthClass: "border-2" },
|
|
8372
|
+
effects: { hover: [{
|
|
8373
|
+
effectId: "background-on-hover",
|
|
8374
|
+
options: { colorToken: "surface" }
|
|
8375
|
+
}] }
|
|
8376
|
+
}
|
|
8220
8377
|
},
|
|
8221
|
-
{
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
}] }
|
|
8378
|
+
outline: {
|
|
8379
|
+
kind: "complete",
|
|
8380
|
+
appearance: {
|
|
8381
|
+
background: {
|
|
8382
|
+
type: "surface",
|
|
8383
|
+
role: "link"
|
|
8384
|
+
},
|
|
8385
|
+
borderRadius: "rounded-full",
|
|
8386
|
+
border: { widthClass: "border" },
|
|
8387
|
+
effects: { hover: [{
|
|
8388
|
+
effectId: "background-on-hover",
|
|
8389
|
+
options: { colorToken: "surface" }
|
|
8390
|
+
}] }
|
|
8391
|
+
}
|
|
8236
8392
|
},
|
|
8237
|
-
{
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8393
|
+
ghost: {
|
|
8394
|
+
kind: "complete",
|
|
8395
|
+
appearance: {
|
|
8396
|
+
background: {
|
|
8397
|
+
type: "surface",
|
|
8398
|
+
role: "link"
|
|
8399
|
+
},
|
|
8400
|
+
borderRadius: "rounded-full",
|
|
8401
|
+
effects: { hover: [{
|
|
8402
|
+
effectId: "background-on-hover",
|
|
8403
|
+
options: { colorToken: "surface" }
|
|
8404
|
+
}] }
|
|
8405
|
+
}
|
|
8406
|
+
},
|
|
8407
|
+
accent: {
|
|
8408
|
+
kind: "derive",
|
|
8409
|
+
from: "primary",
|
|
8410
|
+
overrides: { background: {
|
|
8411
|
+
type: "solid",
|
|
8412
|
+
colorToken: "accent"
|
|
8413
|
+
} }
|
|
8251
8414
|
}
|
|
8252
|
-
|
|
8415
|
+
}
|
|
8253
8416
|
}
|
|
8254
8417
|
});
|
|
8255
|
-
|
|
8256
|
-
//#region ../theme-core/src/buttons/personalities/earth-pill.ts
|
|
8257
|
-
/**
|
|
8258
|
-
* Earth Pill - warm studio pills with compact, primary-coloured ghost CTAs.
|
|
8259
|
-
* Built for grounded editorial wellness styles such as Soft Earth.
|
|
8260
|
-
*/
|
|
8261
|
-
const earthPill = defineButtonPersonality({
|
|
8418
|
+
const earthPillRecipe = defineStaticButtonStyleRecipe({
|
|
8262
8419
|
id: "earth-pill",
|
|
8263
|
-
|
|
8264
|
-
description: "Compact terracotta pills with quiet primary-coloured ghost CTAs.",
|
|
8420
|
+
accessibilityLabel: "Compact rounded buttons with a quiet hover lift",
|
|
8265
8421
|
tags: {
|
|
8266
8422
|
tone: "classic",
|
|
8267
8423
|
energy: "calm",
|
|
8268
8424
|
motion: "subtle",
|
|
8269
8425
|
era: "organic"
|
|
8270
8426
|
},
|
|
8271
|
-
|
|
8427
|
+
system: {
|
|
8272
8428
|
global: {
|
|
8273
8429
|
cornerStyle: "pill",
|
|
8274
8430
|
shadow: "low",
|
|
@@ -8295,576 +8451,547 @@ const earthPill = defineButtonPersonality({
|
|
|
8295
8451
|
fontSize: "text-xl"
|
|
8296
8452
|
}
|
|
8297
8453
|
},
|
|
8298
|
-
|
|
8299
|
-
{
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
}]
|
|
8454
|
+
roles: {
|
|
8455
|
+
primary: {
|
|
8456
|
+
kind: "complete",
|
|
8457
|
+
appearance: {
|
|
8458
|
+
background: {
|
|
8459
|
+
type: "solid",
|
|
8460
|
+
colorToken: "primary"
|
|
8461
|
+
},
|
|
8462
|
+
borderRadius: "rounded-full",
|
|
8463
|
+
shadow: {
|
|
8464
|
+
elevation: "low",
|
|
8465
|
+
softness: "soft",
|
|
8466
|
+
position: "bottom"
|
|
8467
|
+
},
|
|
8468
|
+
effects: {
|
|
8469
|
+
hover: [{
|
|
8470
|
+
effectId: "lift",
|
|
8471
|
+
options: { translateY: "-1px" }
|
|
8472
|
+
}, {
|
|
8473
|
+
effectId: "background-on-hover",
|
|
8474
|
+
options: { colorToken: "accent" }
|
|
8475
|
+
}],
|
|
8476
|
+
active: [{
|
|
8477
|
+
effectId: "scale-down",
|
|
8478
|
+
options: { scale: "0.98" }
|
|
8479
|
+
}]
|
|
8480
|
+
}
|
|
8326
8481
|
}
|
|
8327
8482
|
},
|
|
8328
|
-
{
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
}] }
|
|
8483
|
+
secondary: {
|
|
8484
|
+
kind: "complete",
|
|
8485
|
+
appearance: {
|
|
8486
|
+
background: {
|
|
8487
|
+
type: "surface",
|
|
8488
|
+
role: "link"
|
|
8489
|
+
},
|
|
8490
|
+
borderRadius: "rounded-full",
|
|
8491
|
+
border: { widthClass: "border" },
|
|
8492
|
+
effects: { hover: [{
|
|
8493
|
+
effectId: "background-on-hover",
|
|
8494
|
+
options: { colorToken: "muted" }
|
|
8495
|
+
}] }
|
|
8496
|
+
}
|
|
8343
8497
|
},
|
|
8344
|
-
{
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
}] }
|
|
8498
|
+
outline: {
|
|
8499
|
+
kind: "complete",
|
|
8500
|
+
appearance: {
|
|
8501
|
+
background: {
|
|
8502
|
+
type: "surface",
|
|
8503
|
+
role: "link"
|
|
8504
|
+
},
|
|
8505
|
+
borderRadius: "rounded-full",
|
|
8506
|
+
border: { widthClass: "border" },
|
|
8507
|
+
effects: { hover: [{
|
|
8508
|
+
effectId: "background-on-hover",
|
|
8509
|
+
options: { colorToken: "surfaceAlt" }
|
|
8510
|
+
}] }
|
|
8511
|
+
}
|
|
8359
8512
|
},
|
|
8360
|
-
{
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
type: "surface",
|
|
8367
|
-
role: "link"
|
|
8368
|
-
},
|
|
8369
|
-
borderRadius: "rounded-full",
|
|
8370
|
-
shadow: {
|
|
8371
|
-
elevation: "none",
|
|
8372
|
-
softness: null,
|
|
8373
|
-
position: "bottom"
|
|
8374
|
-
},
|
|
8375
|
-
sizes: {
|
|
8376
|
-
sm: {
|
|
8377
|
-
padding: "0.25rem 0",
|
|
8378
|
-
fontSize: "text-sm"
|
|
8513
|
+
ghost: {
|
|
8514
|
+
kind: "complete",
|
|
8515
|
+
appearance: {
|
|
8516
|
+
background: {
|
|
8517
|
+
type: "surface",
|
|
8518
|
+
role: "link"
|
|
8379
8519
|
},
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8520
|
+
borderRadius: "rounded-full",
|
|
8521
|
+
shadow: {
|
|
8522
|
+
elevation: "none",
|
|
8523
|
+
softness: null,
|
|
8524
|
+
position: "bottom"
|
|
8384
8525
|
},
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8526
|
+
sizes: {
|
|
8527
|
+
sm: {
|
|
8528
|
+
padding: "0.25rem 0",
|
|
8529
|
+
fontSize: "text-sm"
|
|
8530
|
+
},
|
|
8531
|
+
md: { padding: "0.375rem 0" },
|
|
8532
|
+
lg: {
|
|
8533
|
+
padding: "0.5rem 0",
|
|
8534
|
+
fontSize: "text-lg"
|
|
8535
|
+
},
|
|
8536
|
+
xl: {
|
|
8537
|
+
padding: "0.625rem 0",
|
|
8538
|
+
fontSize: "text-xl"
|
|
8539
|
+
}
|
|
8388
8540
|
}
|
|
8389
8541
|
}
|
|
8542
|
+
},
|
|
8543
|
+
accent: {
|
|
8544
|
+
kind: "derive",
|
|
8545
|
+
from: "primary",
|
|
8546
|
+
overrides: { background: {
|
|
8547
|
+
type: "solid",
|
|
8548
|
+
colorToken: "accent"
|
|
8549
|
+
} }
|
|
8390
8550
|
}
|
|
8391
|
-
|
|
8551
|
+
}
|
|
8392
8552
|
}
|
|
8393
8553
|
});
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
* Editorial Link — all variants are link-style with a growing underline.
|
|
8398
|
-
* Default for Warm Editorial and Quiet Luxury; reads as refined and quiet.
|
|
8399
|
-
*/
|
|
8400
|
-
const editorialLink = defineButtonPersonality({
|
|
8401
|
-
id: "editorial-link",
|
|
8402
|
-
name: "Editorial Link",
|
|
8403
|
-
description: "Link-style with a growing underline. Refined, typographic.",
|
|
8554
|
+
const confidentChipRecipe = defineStaticButtonStyleRecipe({
|
|
8555
|
+
id: "confident-chip",
|
|
8556
|
+
accessibilityLabel: "Moderately rounded solid buttons with a crisp hover",
|
|
8404
8557
|
tags: {
|
|
8405
|
-
tone: "
|
|
8558
|
+
tone: "classic",
|
|
8406
8559
|
energy: "calm",
|
|
8407
|
-
motion: "
|
|
8408
|
-
era: "
|
|
8560
|
+
motion: "standard",
|
|
8561
|
+
era: "modern"
|
|
8409
8562
|
},
|
|
8410
|
-
|
|
8563
|
+
system: {
|
|
8411
8564
|
global: {
|
|
8412
|
-
cornerStyle: "
|
|
8565
|
+
cornerStyle: "rounded",
|
|
8566
|
+
shadow: "medium",
|
|
8413
8567
|
textTransform: "none",
|
|
8414
|
-
fontWeight:
|
|
8568
|
+
fontWeight: 600,
|
|
8415
8569
|
borderWidth: 1,
|
|
8416
8570
|
hoverTransform: "none",
|
|
8417
8571
|
hoverColor: "none"
|
|
8418
8572
|
},
|
|
8419
|
-
|
|
8420
|
-
{
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8573
|
+
roles: {
|
|
8574
|
+
primary: {
|
|
8575
|
+
kind: "complete",
|
|
8576
|
+
appearance: {
|
|
8577
|
+
background: {
|
|
8578
|
+
type: "solid",
|
|
8579
|
+
colorToken: "primary"
|
|
8580
|
+
},
|
|
8581
|
+
borderRadius: "rounded-md",
|
|
8582
|
+
shadow: {
|
|
8583
|
+
elevation: "medium",
|
|
8584
|
+
softness: "soft",
|
|
8585
|
+
position: "bottom"
|
|
8586
|
+
},
|
|
8587
|
+
effects: {
|
|
8588
|
+
hover: [{
|
|
8589
|
+
effectId: "darken-background",
|
|
8590
|
+
options: { amount: 100 }
|
|
8591
|
+
}],
|
|
8592
|
+
active: [{
|
|
8593
|
+
effectId: "scale-down",
|
|
8594
|
+
options: { scale: "0.97" }
|
|
8595
|
+
}]
|
|
8442
8596
|
}
|
|
8443
|
-
}
|
|
8597
|
+
}
|
|
8444
8598
|
},
|
|
8445
|
-
{
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
xl: { padding: "0.75rem 0" }
|
|
8460
|
-
},
|
|
8461
|
-
effects: { base: [{
|
|
8462
|
-
effectId: "border-bottom-grow",
|
|
8463
|
-
options: {
|
|
8464
|
-
height: 1,
|
|
8465
|
-
colorToken: "mutedText",
|
|
8466
|
-
origin: "left"
|
|
8467
|
-
}
|
|
8468
|
-
}] }
|
|
8599
|
+
secondary: {
|
|
8600
|
+
kind: "complete",
|
|
8601
|
+
appearance: {
|
|
8602
|
+
background: {
|
|
8603
|
+
type: "solid",
|
|
8604
|
+
colorToken: "surface"
|
|
8605
|
+
},
|
|
8606
|
+
borderRadius: "rounded-md",
|
|
8607
|
+
border: { widthClass: "border" },
|
|
8608
|
+
effects: { hover: [{
|
|
8609
|
+
effectId: "background-on-hover",
|
|
8610
|
+
options: { colorToken: "background" }
|
|
8611
|
+
}] }
|
|
8612
|
+
}
|
|
8469
8613
|
},
|
|
8470
|
-
{
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
xl: { padding: "0.75rem 0" }
|
|
8485
|
-
},
|
|
8486
|
-
effects: { base: [{
|
|
8487
|
-
effectId: "border-bottom-grow",
|
|
8488
|
-
options: {
|
|
8489
|
-
height: 1,
|
|
8490
|
-
colorToken: "accent",
|
|
8491
|
-
origin: "left"
|
|
8492
|
-
}
|
|
8493
|
-
}] }
|
|
8614
|
+
outline: {
|
|
8615
|
+
kind: "complete",
|
|
8616
|
+
appearance: {
|
|
8617
|
+
background: {
|
|
8618
|
+
type: "surface",
|
|
8619
|
+
role: "link"
|
|
8620
|
+
},
|
|
8621
|
+
borderRadius: "rounded-md",
|
|
8622
|
+
border: { widthClass: "border" },
|
|
8623
|
+
effects: { hover: [{
|
|
8624
|
+
effectId: "background-on-hover",
|
|
8625
|
+
options: { colorToken: "surface" }
|
|
8626
|
+
}] }
|
|
8627
|
+
}
|
|
8494
8628
|
},
|
|
8495
|
-
{
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
md: { padding: "0.5rem 0" },
|
|
8508
|
-
lg: { padding: "0.625rem 0" },
|
|
8509
|
-
xl: { padding: "0.75rem 0" }
|
|
8629
|
+
ghost: {
|
|
8630
|
+
kind: "complete",
|
|
8631
|
+
appearance: {
|
|
8632
|
+
background: {
|
|
8633
|
+
type: "surface",
|
|
8634
|
+
role: "link"
|
|
8635
|
+
},
|
|
8636
|
+
borderRadius: "rounded-md",
|
|
8637
|
+
effects: { hover: [{
|
|
8638
|
+
effectId: "background-on-hover",
|
|
8639
|
+
options: { colorToken: "surface" }
|
|
8640
|
+
}] }
|
|
8510
8641
|
}
|
|
8642
|
+
},
|
|
8643
|
+
accent: {
|
|
8644
|
+
kind: "derive",
|
|
8645
|
+
from: "primary",
|
|
8646
|
+
overrides: { background: {
|
|
8647
|
+
type: "solid",
|
|
8648
|
+
colorToken: "accent"
|
|
8649
|
+
} }
|
|
8511
8650
|
}
|
|
8512
|
-
|
|
8651
|
+
}
|
|
8513
8652
|
}
|
|
8514
8653
|
});
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
*/
|
|
8525
|
-
const flatInk = defineButtonPersonality({
|
|
8526
|
-
id: "flat-ink",
|
|
8527
|
-
name: "Flat Ink",
|
|
8528
|
-
description: "Flat solid-ink primary, hairline ghost secondary, and a single amber accent climax — modest radius, no shadow.",
|
|
8654
|
+
const editorialSizes = {
|
|
8655
|
+
sm: { padding: "0.25rem 0" },
|
|
8656
|
+
md: { padding: "0.5rem 0" },
|
|
8657
|
+
lg: { padding: "0.625rem 0" },
|
|
8658
|
+
xl: { padding: "0.75rem 0" }
|
|
8659
|
+
};
|
|
8660
|
+
const editorialLinkRecipe = defineStaticButtonStyleRecipe({
|
|
8661
|
+
id: "editorial-link",
|
|
8662
|
+
accessibilityLabel: "Flat typographic buttons with an underline treatment",
|
|
8529
8663
|
tags: {
|
|
8530
|
-
tone: "
|
|
8664
|
+
tone: "minimal",
|
|
8531
8665
|
energy: "calm",
|
|
8532
8666
|
motion: "subtle",
|
|
8533
8667
|
era: "editorial"
|
|
8534
8668
|
},
|
|
8535
|
-
|
|
8669
|
+
system: {
|
|
8536
8670
|
global: {
|
|
8537
|
-
cornerStyle: "
|
|
8671
|
+
cornerStyle: "square",
|
|
8538
8672
|
textTransform: "none",
|
|
8539
|
-
fontWeight:
|
|
8673
|
+
fontWeight: 500,
|
|
8540
8674
|
borderWidth: 1,
|
|
8541
|
-
|
|
8542
|
-
letterSpacing: "tight",
|
|
8543
|
-
paddingPreset: "default",
|
|
8544
|
-
hoverTransform: "lift",
|
|
8675
|
+
hoverTransform: "none",
|
|
8545
8676
|
hoverColor: "none"
|
|
8546
8677
|
},
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8678
|
+
roles: {
|
|
8679
|
+
primary: {
|
|
8680
|
+
kind: "complete",
|
|
8681
|
+
appearance: {
|
|
8682
|
+
background: {
|
|
8683
|
+
type: "surface",
|
|
8684
|
+
role: "link"
|
|
8685
|
+
},
|
|
8686
|
+
borderRadius: "rounded-none",
|
|
8687
|
+
sizes: editorialSizes,
|
|
8688
|
+
effects: { base: [{
|
|
8689
|
+
effectId: "border-bottom-grow",
|
|
8690
|
+
options: {
|
|
8691
|
+
height: 2,
|
|
8692
|
+
colorToken: "text",
|
|
8693
|
+
origin: "left"
|
|
8694
|
+
}
|
|
8695
|
+
}] }
|
|
8696
|
+
}
|
|
8551
8697
|
},
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8698
|
+
secondary: {
|
|
8699
|
+
kind: "complete",
|
|
8700
|
+
appearance: {
|
|
8701
|
+
background: {
|
|
8702
|
+
type: "surface",
|
|
8703
|
+
role: "link"
|
|
8704
|
+
},
|
|
8705
|
+
borderRadius: "rounded-none",
|
|
8706
|
+
sizes: editorialSizes,
|
|
8707
|
+
effects: { base: [{
|
|
8708
|
+
effectId: "border-bottom-grow",
|
|
8709
|
+
options: {
|
|
8710
|
+
height: 1,
|
|
8711
|
+
colorToken: "mutedText",
|
|
8712
|
+
origin: "left"
|
|
8713
|
+
}
|
|
8714
|
+
}] }
|
|
8715
|
+
}
|
|
8556
8716
|
},
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
effectId: "lift",
|
|
8576
|
-
options: { translateY: "-2px" }
|
|
8577
|
-
}, {
|
|
8578
|
-
effectId: "background-on-hover",
|
|
8579
|
-
options: { colorToken: "secondary" }
|
|
8580
|
-
}] }
|
|
8717
|
+
outline: {
|
|
8718
|
+
kind: "complete",
|
|
8719
|
+
appearance: {
|
|
8720
|
+
background: {
|
|
8721
|
+
type: "surface",
|
|
8722
|
+
role: "link"
|
|
8723
|
+
},
|
|
8724
|
+
borderRadius: "rounded-none",
|
|
8725
|
+
sizes: editorialSizes,
|
|
8726
|
+
effects: { base: [{
|
|
8727
|
+
effectId: "border-bottom-grow",
|
|
8728
|
+
options: {
|
|
8729
|
+
height: 1,
|
|
8730
|
+
colorToken: "accent",
|
|
8731
|
+
origin: "left"
|
|
8732
|
+
}
|
|
8733
|
+
}] }
|
|
8734
|
+
}
|
|
8581
8735
|
},
|
|
8582
|
-
{
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
border: { widthClass: "border" },
|
|
8593
|
-
effects: { hover: [{
|
|
8594
|
-
effectId: "lift",
|
|
8595
|
-
options: { translateY: "-2px" }
|
|
8596
|
-
}, {
|
|
8597
|
-
effectId: "background-on-hover",
|
|
8598
|
-
options: { colorToken: "surfaceAlt" }
|
|
8599
|
-
}] }
|
|
8736
|
+
ghost: {
|
|
8737
|
+
kind: "complete",
|
|
8738
|
+
appearance: {
|
|
8739
|
+
background: {
|
|
8740
|
+
type: "surface",
|
|
8741
|
+
role: "link"
|
|
8742
|
+
},
|
|
8743
|
+
borderRadius: "rounded-none",
|
|
8744
|
+
sizes: editorialSizes
|
|
8745
|
+
}
|
|
8600
8746
|
},
|
|
8601
|
-
{
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
effects: { hover: [{
|
|
8613
|
-
effectId: "lift",
|
|
8614
|
-
options: { translateY: "-2px" }
|
|
8615
|
-
}] }
|
|
8747
|
+
accent: {
|
|
8748
|
+
kind: "derive",
|
|
8749
|
+
from: "primary",
|
|
8750
|
+
overrides: { effects: { base: [{
|
|
8751
|
+
effectId: "border-bottom-grow",
|
|
8752
|
+
options: {
|
|
8753
|
+
height: 2,
|
|
8754
|
+
colorToken: "accent",
|
|
8755
|
+
origin: "left"
|
|
8756
|
+
}
|
|
8757
|
+
}] } }
|
|
8616
8758
|
}
|
|
8617
|
-
|
|
8759
|
+
}
|
|
8618
8760
|
}
|
|
8619
8761
|
});
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
* Ink Stamp — solid earthy fills with a bordered, hand-stamped block-print
|
|
8624
|
-
* feel. Reads as bold and handmade; suits expressive craft brands.
|
|
8625
|
-
*/
|
|
8626
|
-
const inkStamp = defineButtonPersonality({
|
|
8627
|
-
id: "ink-stamp",
|
|
8628
|
-
name: "Ink Stamp",
|
|
8629
|
-
description: "Hand-stamped block-print buttons with a slight lift on hover.",
|
|
8762
|
+
const pebbleRecipe = defineStaticButtonStyleRecipe({
|
|
8763
|
+
id: "pebble",
|
|
8764
|
+
accessibilityLabel: "Generously padded pill buttons",
|
|
8630
8765
|
tags: {
|
|
8631
|
-
tone: "
|
|
8632
|
-
energy: "
|
|
8766
|
+
tone: "classic",
|
|
8767
|
+
energy: "calm",
|
|
8633
8768
|
motion: "standard",
|
|
8634
8769
|
era: "organic"
|
|
8635
8770
|
},
|
|
8636
|
-
|
|
8771
|
+
system: {
|
|
8637
8772
|
global: {
|
|
8638
|
-
cornerStyle: "
|
|
8639
|
-
textTransform: "
|
|
8640
|
-
fontWeight:
|
|
8641
|
-
borderWidth:
|
|
8773
|
+
cornerStyle: "pill",
|
|
8774
|
+
textTransform: "none",
|
|
8775
|
+
fontWeight: 500,
|
|
8776
|
+
borderWidth: 2,
|
|
8642
8777
|
hoverTransform: "none",
|
|
8643
|
-
hoverColor: "none"
|
|
8644
|
-
letterSpacing: "loose"
|
|
8778
|
+
hoverColor: "none"
|
|
8645
8779
|
},
|
|
8646
8780
|
sizes: {
|
|
8647
8781
|
sm: {
|
|
8648
|
-
padding: "0.
|
|
8649
|
-
fontSize: "text-xs"
|
|
8650
|
-
},
|
|
8651
|
-
md: {
|
|
8652
|
-
padding: "0.75rem 1.75rem",
|
|
8782
|
+
padding: "0.625rem 1.75rem",
|
|
8653
8783
|
fontSize: "text-sm"
|
|
8654
8784
|
},
|
|
8785
|
+
md: { padding: "0.875rem 2.25rem" },
|
|
8655
8786
|
lg: {
|
|
8656
|
-
padding: "0.875rem 2.25rem",
|
|
8657
|
-
fontSize: "text-base"
|
|
8658
|
-
},
|
|
8659
|
-
xl: {
|
|
8660
8787
|
padding: "1.125rem 2.75rem",
|
|
8661
8788
|
fontSize: "text-lg"
|
|
8789
|
+
},
|
|
8790
|
+
xl: {
|
|
8791
|
+
padding: "1.5rem 3.5rem",
|
|
8792
|
+
fontSize: "text-xl"
|
|
8662
8793
|
}
|
|
8663
8794
|
},
|
|
8664
|
-
|
|
8665
|
-
{
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
effectId: "drop-shadow",
|
|
8678
|
-
options: { intensity: "medium" }
|
|
8679
|
-
}, {
|
|
8680
|
-
effectId: "scale-up",
|
|
8681
|
-
options: { scale: "1.02" }
|
|
8682
|
-
}],
|
|
8683
|
-
active: [{
|
|
8684
|
-
effectId: "scale-down",
|
|
8685
|
-
options: { scale: "0.98" }
|
|
8686
|
-
}]
|
|
8795
|
+
roles: {
|
|
8796
|
+
primary: {
|
|
8797
|
+
kind: "complete",
|
|
8798
|
+
appearance: {
|
|
8799
|
+
background: {
|
|
8800
|
+
type: "solid",
|
|
8801
|
+
colorToken: "primary"
|
|
8802
|
+
},
|
|
8803
|
+
borderRadius: "rounded-full",
|
|
8804
|
+
effects: { hover: [{
|
|
8805
|
+
effectId: "darken-background",
|
|
8806
|
+
options: { amount: 100 }
|
|
8807
|
+
}] }
|
|
8687
8808
|
}
|
|
8688
8809
|
},
|
|
8689
|
-
{
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
type: "surface",
|
|
8696
|
-
role: "link"
|
|
8697
|
-
},
|
|
8698
|
-
borderRadius: "rounded-md",
|
|
8699
|
-
border: { widthClass: "border-2" },
|
|
8700
|
-
effects: { hover: [{
|
|
8701
|
-
effectId: "background-on-hover",
|
|
8702
|
-
options: { colorToken: "surface" }
|
|
8703
|
-
}] }
|
|
8704
|
-
},
|
|
8705
|
-
{
|
|
8706
|
-
id: "outline",
|
|
8707
|
-
name: "Outline",
|
|
8708
|
-
enabled: true,
|
|
8709
|
-
priority: 3,
|
|
8710
|
-
background: {
|
|
8711
|
-
type: "surface",
|
|
8712
|
-
role: "link"
|
|
8713
|
-
},
|
|
8714
|
-
borderRadius: "rounded-md",
|
|
8715
|
-
border: { widthClass: "border-2" },
|
|
8716
|
-
effects: { hover: [{
|
|
8717
|
-
effectId: "background-on-hover",
|
|
8718
|
-
options: { colorToken: "surface" }
|
|
8719
|
-
}] }
|
|
8720
|
-
},
|
|
8721
|
-
{
|
|
8722
|
-
id: "ghost",
|
|
8723
|
-
name: "Ghost",
|
|
8724
|
-
enabled: true,
|
|
8725
|
-
priority: 3,
|
|
8726
|
-
background: {
|
|
8727
|
-
type: "surface",
|
|
8728
|
-
role: "link"
|
|
8729
|
-
},
|
|
8730
|
-
borderRadius: "rounded-none",
|
|
8731
|
-
sizes: {
|
|
8732
|
-
sm: {
|
|
8733
|
-
padding: "0.375rem 0",
|
|
8734
|
-
fontSize: "text-xs"
|
|
8810
|
+
secondary: {
|
|
8811
|
+
kind: "complete",
|
|
8812
|
+
appearance: {
|
|
8813
|
+
background: {
|
|
8814
|
+
type: "surface",
|
|
8815
|
+
role: "link"
|
|
8735
8816
|
},
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8817
|
+
borderRadius: "rounded-full",
|
|
8818
|
+
border: { widthClass: "border-2" },
|
|
8819
|
+
effects: { hover: [{
|
|
8820
|
+
effectId: "background-on-hover",
|
|
8821
|
+
options: { colorToken: "accent" }
|
|
8822
|
+
}] }
|
|
8823
|
+
}
|
|
8824
|
+
},
|
|
8825
|
+
outline: {
|
|
8826
|
+
kind: "complete",
|
|
8827
|
+
appearance: {
|
|
8828
|
+
background: {
|
|
8829
|
+
type: "surface",
|
|
8830
|
+
role: "link"
|
|
8739
8831
|
},
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8832
|
+
borderRadius: "rounded-full",
|
|
8833
|
+
border: { widthClass: "border" },
|
|
8834
|
+
effects: { hover: [{
|
|
8835
|
+
effectId: "background-on-hover",
|
|
8836
|
+
options: { colorToken: "surface" }
|
|
8837
|
+
}] }
|
|
8838
|
+
}
|
|
8839
|
+
},
|
|
8840
|
+
ghost: {
|
|
8841
|
+
kind: "complete",
|
|
8842
|
+
appearance: {
|
|
8843
|
+
background: {
|
|
8844
|
+
type: "surface",
|
|
8845
|
+
role: "link"
|
|
8743
8846
|
},
|
|
8744
|
-
|
|
8745
|
-
|
|
8746
|
-
|
|
8747
|
-
|
|
8748
|
-
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8847
|
+
borderRadius: "rounded-full",
|
|
8848
|
+
sizes: {
|
|
8849
|
+
sm: {
|
|
8850
|
+
padding: "0.375rem 0.875rem",
|
|
8851
|
+
fontSize: "text-sm"
|
|
8852
|
+
},
|
|
8853
|
+
md: { padding: "0.5rem 1rem" },
|
|
8854
|
+
lg: {
|
|
8855
|
+
padding: "0.625rem 1.25rem",
|
|
8856
|
+
fontSize: "text-lg"
|
|
8857
|
+
},
|
|
8858
|
+
xl: {
|
|
8859
|
+
padding: "0.75rem 1.5rem",
|
|
8860
|
+
fontSize: "text-xl"
|
|
8861
|
+
}
|
|
8755
8862
|
}
|
|
8756
|
-
}
|
|
8863
|
+
}
|
|
8864
|
+
},
|
|
8865
|
+
accent: {
|
|
8866
|
+
kind: "derive",
|
|
8867
|
+
from: "primary",
|
|
8868
|
+
overrides: { background: {
|
|
8869
|
+
type: "solid",
|
|
8870
|
+
colorToken: "accent"
|
|
8871
|
+
} }
|
|
8757
8872
|
}
|
|
8758
|
-
|
|
8873
|
+
}
|
|
8759
8874
|
}
|
|
8760
8875
|
});
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
* Joy Stamp — neo-brutalist pills with a hard, brand-coloured offset shadow
|
|
8765
|
-
* that collapses as the button presses into it on hover. Authored for the
|
|
8766
|
-
* Original Joy site style: a cream "stamp" shadow under the solid primary, and
|
|
8767
|
-
* a brown shadow under the cream outline. Reads as bold, warm, and handmade.
|
|
8768
|
-
*
|
|
8769
|
-
* The coloured offset shadow relies on the per-variant `shadow.colorToken`
|
|
8770
|
-
* extension; the press is the shared `press-down` effect, which matches its
|
|
8771
|
-
* translate to each variant's own shadow offset.
|
|
8772
|
-
*/
|
|
8773
|
-
const joyStamp = defineButtonPersonality({
|
|
8774
|
-
id: "joy-stamp",
|
|
8775
|
-
name: "Joy Stamp",
|
|
8776
|
-
description: "Pill buttons with a hard, brand-coloured offset shadow that presses in on hover.",
|
|
8876
|
+
const brushedWashRecipe = defineStaticButtonStyleRecipe({
|
|
8877
|
+
id: "brushed-wash",
|
|
8878
|
+
accessibilityLabel: "Generously padded gradient buttons with soft shadows",
|
|
8777
8879
|
tags: {
|
|
8778
|
-
tone: "
|
|
8880
|
+
tone: "classic",
|
|
8779
8881
|
energy: "vibrant",
|
|
8780
|
-
motion: "
|
|
8882
|
+
motion: "standard",
|
|
8781
8883
|
era: "organic"
|
|
8782
8884
|
},
|
|
8783
|
-
|
|
8885
|
+
system: {
|
|
8784
8886
|
global: {
|
|
8785
|
-
cornerStyle: "
|
|
8786
|
-
shadow: "
|
|
8887
|
+
cornerStyle: "rounded",
|
|
8888
|
+
shadow: "low",
|
|
8787
8889
|
textTransform: "none",
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
fontSize: "text-lg",
|
|
8791
|
-
borderWidth: 2,
|
|
8890
|
+
fontWeight: 500,
|
|
8891
|
+
borderWidth: 1,
|
|
8792
8892
|
hoverTransform: "none",
|
|
8793
8893
|
hoverColor: "none"
|
|
8794
8894
|
},
|
|
8795
8895
|
sizes: {
|
|
8796
8896
|
sm: {
|
|
8797
|
-
padding: "0.
|
|
8798
|
-
fontSize: "text-
|
|
8799
|
-
},
|
|
8800
|
-
md: {
|
|
8801
|
-
padding: "0.875rem 1.75rem",
|
|
8802
|
-
fontSize: "text-lg"
|
|
8897
|
+
padding: "0.75rem 2rem",
|
|
8898
|
+
fontSize: "text-sm"
|
|
8803
8899
|
},
|
|
8900
|
+
md: { padding: "1rem 2.5rem" },
|
|
8804
8901
|
lg: {
|
|
8805
|
-
padding: "1.
|
|
8806
|
-
fontSize: "text-
|
|
8902
|
+
padding: "1.25rem 3rem",
|
|
8903
|
+
fontSize: "text-lg"
|
|
8807
8904
|
},
|
|
8808
8905
|
xl: {
|
|
8809
|
-
padding: "1.
|
|
8810
|
-
fontSize: "text-
|
|
8906
|
+
padding: "1.625rem 3.75rem",
|
|
8907
|
+
fontSize: "text-xl"
|
|
8811
8908
|
}
|
|
8812
8909
|
},
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8910
|
+
roles: {
|
|
8911
|
+
primary: {
|
|
8912
|
+
kind: "complete",
|
|
8913
|
+
appearance: {
|
|
8914
|
+
background: {
|
|
8915
|
+
type: "gradient",
|
|
8916
|
+
stops: ["primary", "accent"],
|
|
8917
|
+
direction: "to-r",
|
|
8918
|
+
foregroundToken: "primaryForeground"
|
|
8919
|
+
},
|
|
8920
|
+
borderRadius: "rounded-lg",
|
|
8921
|
+
shadow: {
|
|
8922
|
+
elevation: "low",
|
|
8923
|
+
softness: "soft",
|
|
8924
|
+
position: "bottom"
|
|
8925
|
+
}
|
|
8926
|
+
}
|
|
8821
8927
|
},
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8928
|
+
secondary: {
|
|
8929
|
+
kind: "complete",
|
|
8930
|
+
appearance: {
|
|
8931
|
+
background: {
|
|
8932
|
+
type: "gradient",
|
|
8933
|
+
stops: ["secondary", "accent"],
|
|
8934
|
+
direction: "to-br",
|
|
8935
|
+
foregroundToken: "primaryForeground"
|
|
8936
|
+
},
|
|
8937
|
+
borderRadius: "rounded-lg",
|
|
8938
|
+
shadow: {
|
|
8939
|
+
elevation: "low",
|
|
8940
|
+
softness: "soft",
|
|
8941
|
+
position: "bottom"
|
|
8942
|
+
}
|
|
8943
|
+
}
|
|
8828
8944
|
},
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
|
|
8945
|
+
outline: {
|
|
8946
|
+
kind: "complete",
|
|
8947
|
+
appearance: {
|
|
8948
|
+
background: {
|
|
8949
|
+
type: "surface",
|
|
8950
|
+
role: "link"
|
|
8951
|
+
},
|
|
8952
|
+
borderRadius: "rounded-lg",
|
|
8953
|
+
border: { widthClass: "border" },
|
|
8954
|
+
effects: { hover: [{
|
|
8955
|
+
effectId: "background-on-hover",
|
|
8956
|
+
options: { colorToken: "surface" }
|
|
8957
|
+
}] }
|
|
8958
|
+
}
|
|
8838
8959
|
},
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8960
|
+
ghost: {
|
|
8961
|
+
kind: "complete",
|
|
8962
|
+
appearance: {
|
|
8963
|
+
background: {
|
|
8964
|
+
type: "surface",
|
|
8965
|
+
role: "link"
|
|
8966
|
+
},
|
|
8967
|
+
borderRadius: "rounded-lg",
|
|
8968
|
+
effects: { hover: [{
|
|
8969
|
+
effectId: "background-on-hover",
|
|
8970
|
+
options: { colorToken: "surface" }
|
|
8971
|
+
}] }
|
|
8972
|
+
}
|
|
8846
8973
|
},
|
|
8847
|
-
|
|
8848
|
-
|
|
8974
|
+
accent: {
|
|
8975
|
+
kind: "derive",
|
|
8976
|
+
from: "primary",
|
|
8977
|
+
overrides: { background: {
|
|
8978
|
+
type: "solid",
|
|
8979
|
+
colorToken: "accent"
|
|
8980
|
+
} }
|
|
8981
|
+
}
|
|
8982
|
+
}
|
|
8849
8983
|
}
|
|
8850
8984
|
});
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
* Ornate Ritual — framed, ceremonial buttons with jewel-toned fills and
|
|
8855
|
-
* deliberate spacing. Designed for music, ceremony, and soulful event sites.
|
|
8856
|
-
*/
|
|
8857
|
-
const ornateRitual = defineButtonPersonality({
|
|
8858
|
-
id: "ornate-ritual",
|
|
8859
|
-
name: "Ornate Ritual",
|
|
8860
|
-
description: "Ceremonial framed buttons with jewel-toned fills and quiet color-change hover states.",
|
|
8985
|
+
const inkStampRecipe = defineStaticButtonStyleRecipe({
|
|
8986
|
+
id: "ink-stamp",
|
|
8987
|
+
accessibilityLabel: "Uppercase block-print buttons with a playful hover",
|
|
8861
8988
|
tags: {
|
|
8862
|
-
tone: "
|
|
8989
|
+
tone: "bold",
|
|
8863
8990
|
energy: "vibrant",
|
|
8864
|
-
motion: "
|
|
8991
|
+
motion: "standard",
|
|
8865
8992
|
era: "organic"
|
|
8866
8993
|
},
|
|
8867
|
-
|
|
8994
|
+
system: {
|
|
8868
8995
|
global: {
|
|
8869
8996
|
cornerStyle: "rounded",
|
|
8870
8997
|
textTransform: "uppercase",
|
|
@@ -8876,359 +9003,256 @@ const ornateRitual = defineButtonPersonality({
|
|
|
8876
9003
|
},
|
|
8877
9004
|
sizes: {
|
|
8878
9005
|
sm: {
|
|
8879
|
-
padding: "0.
|
|
9006
|
+
padding: "0.5rem 1.25rem",
|
|
8880
9007
|
fontSize: "text-xs"
|
|
8881
9008
|
},
|
|
8882
9009
|
md: {
|
|
8883
9010
|
padding: "0.75rem 1.75rem",
|
|
8884
|
-
fontSize: "text-
|
|
9011
|
+
fontSize: "text-sm"
|
|
8885
9012
|
},
|
|
8886
9013
|
lg: {
|
|
8887
9014
|
padding: "0.875rem 2.25rem",
|
|
8888
|
-
fontSize: "text-
|
|
9015
|
+
fontSize: "text-base"
|
|
8889
9016
|
},
|
|
8890
9017
|
xl: {
|
|
8891
|
-
padding: "
|
|
8892
|
-
fontSize: "text-
|
|
9018
|
+
padding: "1.125rem 2.75rem",
|
|
9019
|
+
fontSize: "text-lg"
|
|
8893
9020
|
}
|
|
8894
9021
|
},
|
|
8895
|
-
|
|
8896
|
-
{
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
9022
|
+
roles: {
|
|
9023
|
+
primary: {
|
|
9024
|
+
kind: "complete",
|
|
9025
|
+
appearance: {
|
|
9026
|
+
background: {
|
|
9027
|
+
type: "solid",
|
|
9028
|
+
colorToken: "primary"
|
|
9029
|
+
},
|
|
9030
|
+
borderRadius: "rounded-md",
|
|
9031
|
+
effects: {
|
|
9032
|
+
hover: [{
|
|
9033
|
+
effectId: "drop-shadow",
|
|
9034
|
+
options: { intensity: "medium" }
|
|
9035
|
+
}, {
|
|
9036
|
+
effectId: "scale-up",
|
|
9037
|
+
options: { scale: "1.02" }
|
|
9038
|
+
}],
|
|
9039
|
+
active: [{
|
|
9040
|
+
effectId: "scale-down",
|
|
9041
|
+
options: { scale: "0.98" }
|
|
9042
|
+
}]
|
|
9043
|
+
}
|
|
9044
|
+
}
|
|
9045
|
+
},
|
|
9046
|
+
secondary: {
|
|
9047
|
+
kind: "complete",
|
|
9048
|
+
appearance: {
|
|
9049
|
+
background: {
|
|
9050
|
+
type: "surface",
|
|
9051
|
+
role: "link"
|
|
9052
|
+
},
|
|
9053
|
+
borderRadius: "rounded-md",
|
|
9054
|
+
border: { widthClass: "border-2" },
|
|
9055
|
+
effects: { hover: [{
|
|
8909
9056
|
effectId: "background-on-hover",
|
|
8910
|
-
options: { colorToken: "
|
|
8911
|
-
}]
|
|
8912
|
-
active: [{
|
|
8913
|
-
effectId: "scale-down",
|
|
8914
|
-
options: { scale: "0.98" }
|
|
8915
|
-
}]
|
|
9057
|
+
options: { colorToken: "surface" }
|
|
9058
|
+
}] }
|
|
8916
9059
|
}
|
|
8917
9060
|
},
|
|
8918
|
-
{
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
type: "solid",
|
|
8925
|
-
colorToken: "secondary"
|
|
8926
|
-
},
|
|
8927
|
-
borderRadius: "rounded-md",
|
|
8928
|
-
border: { widthClass: "border" },
|
|
8929
|
-
effects: { hover: [{
|
|
8930
|
-
effectId: "background-on-hover",
|
|
8931
|
-
options: { colorToken: "surface" }
|
|
8932
|
-
}] }
|
|
8933
|
-
},
|
|
8934
|
-
{
|
|
8935
|
-
id: "outline",
|
|
8936
|
-
name: "Outline",
|
|
8937
|
-
enabled: true,
|
|
8938
|
-
priority: 3,
|
|
8939
|
-
background: {
|
|
8940
|
-
type: "surface",
|
|
8941
|
-
role: "link"
|
|
8942
|
-
},
|
|
8943
|
-
borderRadius: "rounded-md",
|
|
8944
|
-
border: { widthClass: "border" },
|
|
8945
|
-
effects: { hover: [{
|
|
8946
|
-
effectId: "background-on-hover",
|
|
8947
|
-
options: { colorToken: "muted" }
|
|
8948
|
-
}] }
|
|
8949
|
-
},
|
|
8950
|
-
{
|
|
8951
|
-
id: "ghost",
|
|
8952
|
-
name: "Ghost",
|
|
8953
|
-
enabled: true,
|
|
8954
|
-
priority: 3,
|
|
8955
|
-
background: {
|
|
8956
|
-
type: "surface",
|
|
8957
|
-
role: "link"
|
|
8958
|
-
},
|
|
8959
|
-
borderRadius: "rounded-none",
|
|
8960
|
-
sizes: {
|
|
8961
|
-
sm: {
|
|
8962
|
-
padding: "0.375rem 0",
|
|
8963
|
-
fontSize: "text-xs"
|
|
9061
|
+
outline: {
|
|
9062
|
+
kind: "complete",
|
|
9063
|
+
appearance: {
|
|
9064
|
+
background: {
|
|
9065
|
+
type: "surface",
|
|
9066
|
+
role: "link"
|
|
8964
9067
|
},
|
|
8965
|
-
|
|
8966
|
-
|
|
8967
|
-
|
|
8968
|
-
|
|
8969
|
-
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
},
|
|
8973
|
-
xl: {
|
|
8974
|
-
padding: "0.75rem 0",
|
|
8975
|
-
fontSize: "text-lg"
|
|
8976
|
-
}
|
|
8977
|
-
},
|
|
8978
|
-
effects: { base: [{
|
|
8979
|
-
effectId: "border-bottom-grow",
|
|
8980
|
-
options: {
|
|
8981
|
-
height: 1,
|
|
8982
|
-
colorToken: "accent",
|
|
8983
|
-
origin: "left"
|
|
8984
|
-
}
|
|
8985
|
-
}] }
|
|
8986
|
-
}
|
|
8987
|
-
]
|
|
8988
|
-
}
|
|
8989
|
-
});
|
|
8990
|
-
//#endregion
|
|
8991
|
-
//#region ../theme-core/src/buttons/personalities/pebble.ts
|
|
8992
|
-
/**
|
|
8993
|
-
* Pebble — large pill primaries with generous padding. Reads as spa-luxurious
|
|
8994
|
-
* and natural; pairs well with wellness/yoga/dance brands.
|
|
8995
|
-
*/
|
|
8996
|
-
const pebble = defineButtonPersonality({
|
|
8997
|
-
id: "pebble",
|
|
8998
|
-
name: "Pebble",
|
|
8999
|
-
description: "Generous pill buttons with a quiet colour-softening hover.",
|
|
9000
|
-
tags: {
|
|
9001
|
-
tone: "classic",
|
|
9002
|
-
energy: "calm",
|
|
9003
|
-
motion: "standard",
|
|
9004
|
-
era: "organic"
|
|
9005
|
-
},
|
|
9006
|
-
buttonSystem: {
|
|
9007
|
-
global: {
|
|
9008
|
-
cornerStyle: "pill",
|
|
9009
|
-
textTransform: "none",
|
|
9010
|
-
fontWeight: 500,
|
|
9011
|
-
borderWidth: 2,
|
|
9012
|
-
hoverTransform: "none",
|
|
9013
|
-
hoverColor: "none"
|
|
9014
|
-
},
|
|
9015
|
-
sizes: {
|
|
9016
|
-
sm: {
|
|
9017
|
-
padding: "0.625rem 1.75rem",
|
|
9018
|
-
fontSize: "text-sm"
|
|
9019
|
-
},
|
|
9020
|
-
md: { padding: "0.875rem 2.25rem" },
|
|
9021
|
-
lg: {
|
|
9022
|
-
padding: "1.125rem 2.75rem",
|
|
9023
|
-
fontSize: "text-lg"
|
|
9024
|
-
},
|
|
9025
|
-
xl: {
|
|
9026
|
-
padding: "1.5rem 3.5rem",
|
|
9027
|
-
fontSize: "text-xl"
|
|
9028
|
-
}
|
|
9029
|
-
},
|
|
9030
|
-
variants: [
|
|
9031
|
-
{
|
|
9032
|
-
id: "primary",
|
|
9033
|
-
name: "Primary",
|
|
9034
|
-
enabled: true,
|
|
9035
|
-
priority: 1,
|
|
9036
|
-
background: {
|
|
9037
|
-
type: "solid",
|
|
9038
|
-
colorToken: "primary"
|
|
9039
|
-
},
|
|
9040
|
-
borderRadius: "rounded-full",
|
|
9041
|
-
effects: { hover: [{
|
|
9042
|
-
effectId: "darken-background",
|
|
9043
|
-
options: { amount: 100 }
|
|
9044
|
-
}] }
|
|
9045
|
-
},
|
|
9046
|
-
{
|
|
9047
|
-
id: "secondary",
|
|
9048
|
-
name: "Secondary",
|
|
9049
|
-
enabled: true,
|
|
9050
|
-
priority: 2,
|
|
9051
|
-
background: {
|
|
9052
|
-
type: "surface",
|
|
9053
|
-
role: "link"
|
|
9054
|
-
},
|
|
9055
|
-
borderRadius: "rounded-full",
|
|
9056
|
-
border: { widthClass: "border-2" },
|
|
9057
|
-
effects: { hover: [{
|
|
9058
|
-
effectId: "background-on-hover",
|
|
9059
|
-
options: { colorToken: "accent" }
|
|
9060
|
-
}] }
|
|
9061
|
-
},
|
|
9062
|
-
{
|
|
9063
|
-
id: "outline",
|
|
9064
|
-
name: "Outline",
|
|
9065
|
-
enabled: true,
|
|
9066
|
-
priority: 3,
|
|
9067
|
-
background: {
|
|
9068
|
-
type: "surface",
|
|
9069
|
-
role: "link"
|
|
9070
|
-
},
|
|
9071
|
-
borderRadius: "rounded-full",
|
|
9072
|
-
border: { widthClass: "border" },
|
|
9073
|
-
effects: { hover: [{
|
|
9074
|
-
effectId: "background-on-hover",
|
|
9075
|
-
options: { colorToken: "surface" }
|
|
9076
|
-
}] }
|
|
9068
|
+
borderRadius: "rounded-md",
|
|
9069
|
+
border: { widthClass: "border-2" },
|
|
9070
|
+
effects: { hover: [{
|
|
9071
|
+
effectId: "background-on-hover",
|
|
9072
|
+
options: { colorToken: "surface" }
|
|
9073
|
+
}] }
|
|
9074
|
+
}
|
|
9077
9075
|
},
|
|
9078
|
-
{
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
type: "surface",
|
|
9085
|
-
role: "link"
|
|
9086
|
-
},
|
|
9087
|
-
borderRadius: "rounded-full",
|
|
9088
|
-
sizes: {
|
|
9089
|
-
sm: {
|
|
9090
|
-
padding: "0.375rem 0.875rem",
|
|
9091
|
-
fontSize: "text-sm"
|
|
9076
|
+
ghost: {
|
|
9077
|
+
kind: "complete",
|
|
9078
|
+
appearance: {
|
|
9079
|
+
background: {
|
|
9080
|
+
type: "surface",
|
|
9081
|
+
role: "link"
|
|
9092
9082
|
},
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9083
|
+
borderRadius: "rounded-none",
|
|
9084
|
+
sizes: {
|
|
9085
|
+
sm: {
|
|
9086
|
+
padding: "0.375rem 0",
|
|
9087
|
+
fontSize: "text-xs"
|
|
9088
|
+
},
|
|
9089
|
+
md: {
|
|
9090
|
+
padding: "0.5rem 0",
|
|
9091
|
+
fontSize: "text-sm"
|
|
9092
|
+
},
|
|
9093
|
+
lg: {
|
|
9094
|
+
padding: "0.625rem 0",
|
|
9095
|
+
fontSize: "text-base"
|
|
9096
|
+
},
|
|
9097
|
+
xl: {
|
|
9098
|
+
padding: "0.75rem 0",
|
|
9099
|
+
fontSize: "text-lg"
|
|
9100
|
+
}
|
|
9097
9101
|
},
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
+
effects: { base: [{
|
|
9103
|
+
effectId: "border-bottom-grow",
|
|
9104
|
+
options: {
|
|
9105
|
+
height: 1,
|
|
9106
|
+
colorToken: "accent",
|
|
9107
|
+
origin: "left"
|
|
9108
|
+
}
|
|
9109
|
+
}] }
|
|
9102
9110
|
}
|
|
9111
|
+
},
|
|
9112
|
+
accent: {
|
|
9113
|
+
kind: "derive",
|
|
9114
|
+
from: "primary",
|
|
9115
|
+
overrides: { background: {
|
|
9116
|
+
type: "solid",
|
|
9117
|
+
colorToken: "accent"
|
|
9118
|
+
} }
|
|
9103
9119
|
}
|
|
9104
|
-
|
|
9120
|
+
}
|
|
9105
9121
|
}
|
|
9106
9122
|
});
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
* Quiet Arrow — wide, flat editorial buttons for grounded service businesses.
|
|
9111
|
-
* Primary and secondary keep stable semantic colours; surrounding surfaces are
|
|
9112
|
-
* responsible for contrast rather than reversing the button roles.
|
|
9113
|
-
*/
|
|
9114
|
-
const quietArrow = defineButtonPersonality({
|
|
9115
|
-
id: "quiet-arrow",
|
|
9116
|
-
name: "Quiet Arrow",
|
|
9117
|
-
description: "Wide, flat arrow buttons with a solid primary and a primary-colour outlined secondary.",
|
|
9123
|
+
const flatInkRecipe = defineStaticButtonStyleRecipe({
|
|
9124
|
+
id: "flat-ink",
|
|
9125
|
+
accessibilityLabel: "Flat rounded buttons with arrow affordances",
|
|
9118
9126
|
tags: {
|
|
9119
9127
|
tone: "classic",
|
|
9120
9128
|
energy: "calm",
|
|
9121
9129
|
motion: "subtle",
|
|
9122
9130
|
era: "editorial"
|
|
9123
9131
|
},
|
|
9124
|
-
|
|
9132
|
+
system: {
|
|
9125
9133
|
global: {
|
|
9126
9134
|
cornerStyle: "rounded",
|
|
9127
|
-
textTransform: "
|
|
9128
|
-
fontWeight:
|
|
9135
|
+
textTransform: "none",
|
|
9136
|
+
fontWeight: 600,
|
|
9129
9137
|
borderWidth: 1,
|
|
9130
9138
|
typography: "body",
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
hoverTransform: "
|
|
9139
|
+
letterSpacing: "tight",
|
|
9140
|
+
paddingPreset: "default",
|
|
9141
|
+
hoverTransform: "lift",
|
|
9134
9142
|
hoverColor: "none"
|
|
9135
9143
|
},
|
|
9136
9144
|
sizes: {
|
|
9137
9145
|
sm: {
|
|
9138
|
-
padding: "0.625rem 1.
|
|
9139
|
-
fontSize: "text-xs"
|
|
9140
|
-
},
|
|
9141
|
-
md: {
|
|
9142
|
-
padding: "0.8125rem 1.75rem",
|
|
9146
|
+
padding: "0.625rem 1.125rem",
|
|
9143
9147
|
fontSize: "text-sm"
|
|
9144
9148
|
},
|
|
9149
|
+
md: { padding: "0.8125rem 1.375rem" },
|
|
9145
9150
|
lg: {
|
|
9146
|
-
padding: "0.9375rem
|
|
9147
|
-
fontSize: "text-
|
|
9151
|
+
padding: "0.9375rem 1.625rem",
|
|
9152
|
+
fontSize: "text-lg"
|
|
9148
9153
|
},
|
|
9149
9154
|
xl: {
|
|
9150
|
-
padding: "1.0625rem
|
|
9151
|
-
fontSize: "text-
|
|
9155
|
+
padding: "1.0625rem 2rem",
|
|
9156
|
+
fontSize: "text-xl"
|
|
9152
9157
|
}
|
|
9153
9158
|
},
|
|
9154
|
-
|
|
9155
|
-
{
|
|
9156
|
-
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9159
|
+
roles: {
|
|
9160
|
+
primary: {
|
|
9161
|
+
kind: "complete",
|
|
9162
|
+
appearance: {
|
|
9163
|
+
background: {
|
|
9164
|
+
type: "solid",
|
|
9165
|
+
colorToken: "primary"
|
|
9166
|
+
},
|
|
9167
|
+
borderRadius: "rounded-lg",
|
|
9168
|
+
affordance: { iconId: "ArrowRight" },
|
|
9169
|
+
effects: { hover: [{
|
|
9170
|
+
effectId: "lift",
|
|
9171
|
+
options: { translateY: "-2px" }
|
|
9172
|
+
}, {
|
|
9173
|
+
effectId: "background-on-hover",
|
|
9174
|
+
options: { colorToken: "secondary" }
|
|
9175
|
+
}] }
|
|
9176
|
+
}
|
|
9170
9177
|
},
|
|
9171
|
-
{
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
|
|
9178
|
+
secondary: {
|
|
9179
|
+
kind: "complete",
|
|
9180
|
+
appearance: {
|
|
9181
|
+
background: {
|
|
9182
|
+
type: "surface",
|
|
9183
|
+
role: "link"
|
|
9184
|
+
},
|
|
9185
|
+
borderRadius: "rounded-lg",
|
|
9186
|
+
border: { widthClass: "border" },
|
|
9187
|
+
effects: { hover: [{
|
|
9188
|
+
effectId: "lift",
|
|
9189
|
+
options: { translateY: "-2px" }
|
|
9190
|
+
}, {
|
|
9191
|
+
effectId: "background-on-hover",
|
|
9192
|
+
options: { colorToken: "surfaceAlt" }
|
|
9193
|
+
}] }
|
|
9194
|
+
}
|
|
9187
9195
|
},
|
|
9188
|
-
{
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
|
|
9198
|
-
|
|
9196
|
+
outline: {
|
|
9197
|
+
kind: "complete",
|
|
9198
|
+
appearance: {
|
|
9199
|
+
background: {
|
|
9200
|
+
type: "surface",
|
|
9201
|
+
role: "link"
|
|
9202
|
+
},
|
|
9203
|
+
borderRadius: "rounded-lg",
|
|
9204
|
+
border: { widthClass: "border" },
|
|
9205
|
+
effects: { hover: [{
|
|
9206
|
+
effectId: "lift",
|
|
9207
|
+
options: { translateY: "-2px" }
|
|
9208
|
+
}, {
|
|
9209
|
+
effectId: "background-on-hover",
|
|
9210
|
+
options: { colorToken: "surfaceAlt" }
|
|
9211
|
+
}] }
|
|
9212
|
+
}
|
|
9199
9213
|
},
|
|
9200
|
-
{
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9214
|
+
ghost: {
|
|
9215
|
+
kind: "complete",
|
|
9216
|
+
appearance: {
|
|
9217
|
+
background: {
|
|
9218
|
+
type: "surface",
|
|
9219
|
+
role: "link"
|
|
9220
|
+
},
|
|
9221
|
+
borderRadius: "rounded-lg",
|
|
9222
|
+
effects: { hover: [{
|
|
9223
|
+
effectId: "lift",
|
|
9224
|
+
options: { translateY: "-2px" }
|
|
9225
|
+
}] }
|
|
9226
|
+
}
|
|
9227
|
+
},
|
|
9228
|
+
accent: {
|
|
9229
|
+
kind: "complete",
|
|
9230
|
+
appearance: {
|
|
9231
|
+
background: {
|
|
9232
|
+
type: "solid",
|
|
9233
|
+
colorToken: "accent"
|
|
9234
|
+
},
|
|
9235
|
+
borderRadius: "rounded-lg",
|
|
9236
|
+
affordance: { iconId: "ArrowRight" },
|
|
9237
|
+
effects: { hover: [{
|
|
9238
|
+
effectId: "lift",
|
|
9239
|
+
options: { translateY: "-2px" }
|
|
9240
|
+
}] }
|
|
9241
|
+
}
|
|
9210
9242
|
}
|
|
9211
|
-
|
|
9243
|
+
}
|
|
9212
9244
|
}
|
|
9213
9245
|
});
|
|
9214
|
-
|
|
9215
|
-
//#region ../theme-core/src/buttons/personalities/showtime-pill.ts
|
|
9216
|
-
/**
|
|
9217
|
-
* Showtime Pill — bold, spacious, fully rounded buttons with playful pop
|
|
9218
|
-
* motion. Suits energetic schools, performers, festivals, and community brands
|
|
9219
|
-
* that need calls to action to feel loud without becoming visually chaotic.
|
|
9220
|
-
*/
|
|
9221
|
-
const showtimePill = defineButtonPersonality({
|
|
9246
|
+
const showtimePillRecipe = defineStaticButtonStyleRecipe({
|
|
9222
9247
|
id: "showtime-pill",
|
|
9223
|
-
|
|
9224
|
-
description: "Bold pill buttons with uppercase labels, generous padding, and a playful pop.",
|
|
9248
|
+
accessibilityLabel: "Bold uppercase pill buttons with playful movement",
|
|
9225
9249
|
tags: {
|
|
9226
9250
|
tone: "bold",
|
|
9227
9251
|
energy: "vibrant",
|
|
9228
9252
|
motion: "expressive",
|
|
9229
9253
|
era: "modern"
|
|
9230
9254
|
},
|
|
9231
|
-
|
|
9255
|
+
system: {
|
|
9232
9256
|
global: {
|
|
9233
9257
|
cornerStyle: "pill",
|
|
9234
9258
|
shadow: "low",
|
|
@@ -9259,272 +9283,376 @@ const showtimePill = defineButtonPersonality({
|
|
|
9259
9283
|
fontSize: "1.125rem"
|
|
9260
9284
|
}
|
|
9261
9285
|
},
|
|
9262
|
-
|
|
9263
|
-
{
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
effects: { hover: [{ effectId: "pop" }] }
|
|
9274
|
-
},
|
|
9275
|
-
{
|
|
9276
|
-
id: "secondary",
|
|
9277
|
-
name: "Secondary",
|
|
9278
|
-
enabled: true,
|
|
9279
|
-
priority: 2,
|
|
9280
|
-
background: {
|
|
9281
|
-
type: "surface",
|
|
9282
|
-
role: "link"
|
|
9283
|
-
},
|
|
9284
|
-
borderRadius: "rounded-full",
|
|
9285
|
-
border: { widthClass: "border-2" },
|
|
9286
|
-
effects: { hover: [{ effectId: "pop" }] }
|
|
9286
|
+
roles: {
|
|
9287
|
+
primary: {
|
|
9288
|
+
kind: "complete",
|
|
9289
|
+
appearance: {
|
|
9290
|
+
background: {
|
|
9291
|
+
type: "solid",
|
|
9292
|
+
colorToken: "primary"
|
|
9293
|
+
},
|
|
9294
|
+
borderRadius: "rounded-full",
|
|
9295
|
+
effects: { hover: [{ effectId: "pop" }] }
|
|
9296
|
+
}
|
|
9287
9297
|
},
|
|
9288
|
-
{
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
9292
|
-
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9298
|
+
secondary: {
|
|
9299
|
+
kind: "complete",
|
|
9300
|
+
appearance: {
|
|
9301
|
+
background: {
|
|
9302
|
+
type: "surface",
|
|
9303
|
+
role: "link"
|
|
9304
|
+
},
|
|
9305
|
+
borderRadius: "rounded-full",
|
|
9306
|
+
border: { widthClass: "border-2" },
|
|
9307
|
+
effects: { hover: [{ effectId: "pop" }] }
|
|
9308
|
+
}
|
|
9299
9309
|
},
|
|
9300
|
-
{
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
}] }
|
|
9310
|
+
outline: {
|
|
9311
|
+
kind: "complete",
|
|
9312
|
+
appearance: {
|
|
9313
|
+
background: {
|
|
9314
|
+
type: "surface",
|
|
9315
|
+
role: "link"
|
|
9316
|
+
},
|
|
9317
|
+
borderRadius: "rounded-full",
|
|
9318
|
+
border: { widthClass: "border-2" },
|
|
9319
|
+
effects: { hover: [{
|
|
9320
|
+
effectId: "background-on-hover",
|
|
9321
|
+
options: { colorToken: "background" }
|
|
9322
|
+
}] }
|
|
9323
|
+
}
|
|
9315
9324
|
},
|
|
9316
|
-
{
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
|
|
9323
|
-
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
options: { colorToken: "background" }
|
|
9330
|
-
}] }
|
|
9325
|
+
ghost: {
|
|
9326
|
+
kind: "complete",
|
|
9327
|
+
appearance: {
|
|
9328
|
+
background: {
|
|
9329
|
+
type: "surface",
|
|
9330
|
+
role: "link"
|
|
9331
|
+
},
|
|
9332
|
+
borderRadius: "rounded-full",
|
|
9333
|
+
effects: { hover: [{
|
|
9334
|
+
effectId: "background-on-hover",
|
|
9335
|
+
options: { colorToken: "surface" }
|
|
9336
|
+
}] }
|
|
9337
|
+
}
|
|
9331
9338
|
},
|
|
9332
|
-
{
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9342
|
-
effects: { hover: [{
|
|
9343
|
-
effectId: "background-on-hover",
|
|
9344
|
-
options: { colorToken: "surface" }
|
|
9345
|
-
}] }
|
|
9339
|
+
accent: {
|
|
9340
|
+
kind: "complete",
|
|
9341
|
+
appearance: {
|
|
9342
|
+
background: {
|
|
9343
|
+
type: "solid",
|
|
9344
|
+
colorToken: "secondary"
|
|
9345
|
+
},
|
|
9346
|
+
borderRadius: "rounded-full",
|
|
9347
|
+
effects: { hover: [{ effectId: "pop" }] }
|
|
9348
|
+
}
|
|
9346
9349
|
}
|
|
9347
|
-
|
|
9350
|
+
}
|
|
9348
9351
|
}
|
|
9349
9352
|
});
|
|
9350
|
-
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
* Soft Pill — rounded-full pill buttons with a hover lift. The default for
|
|
9354
|
-
* Calm Studio and Modern Wellness; reads as quietly modern and welcoming.
|
|
9355
|
-
*/
|
|
9356
|
-
const softPill = defineButtonPersonality({
|
|
9357
|
-
id: "soft-pill",
|
|
9358
|
-
name: "Soft Pill",
|
|
9359
|
-
description: "Rounded pills with a gentle lift on hover. Quietly modern.",
|
|
9353
|
+
const joyStampRecipe = defineStaticButtonStyleRecipe({
|
|
9354
|
+
id: "joy-stamp",
|
|
9355
|
+
accessibilityLabel: "Bold pill buttons with a hard offset shadow",
|
|
9360
9356
|
tags: {
|
|
9361
|
-
tone: "
|
|
9362
|
-
energy: "
|
|
9363
|
-
motion: "
|
|
9357
|
+
tone: "bold",
|
|
9358
|
+
energy: "vibrant",
|
|
9359
|
+
motion: "expressive",
|
|
9364
9360
|
era: "organic"
|
|
9365
9361
|
},
|
|
9366
|
-
|
|
9362
|
+
system: {
|
|
9367
9363
|
global: {
|
|
9368
9364
|
cornerStyle: "pill",
|
|
9369
|
-
shadow: "
|
|
9365
|
+
shadow: "high",
|
|
9370
9366
|
textTransform: "none",
|
|
9371
|
-
|
|
9367
|
+
typography: "heading",
|
|
9368
|
+
fontWeight: 700,
|
|
9369
|
+
fontSize: "text-lg",
|
|
9372
9370
|
borderWidth: 2,
|
|
9373
|
-
hoverTransform: "
|
|
9371
|
+
hoverTransform: "none",
|
|
9374
9372
|
hoverColor: "none"
|
|
9375
9373
|
},
|
|
9376
|
-
|
|
9377
|
-
{
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9374
|
+
sizes: {
|
|
9375
|
+
sm: {
|
|
9376
|
+
padding: "0.625rem 1.25rem",
|
|
9377
|
+
fontSize: "text-base"
|
|
9378
|
+
},
|
|
9379
|
+
md: {
|
|
9380
|
+
padding: "0.875rem 1.75rem",
|
|
9381
|
+
fontSize: "text-lg"
|
|
9382
|
+
},
|
|
9383
|
+
lg: {
|
|
9384
|
+
padding: "1.125rem 2.25rem",
|
|
9385
|
+
fontSize: "text-xl"
|
|
9386
|
+
},
|
|
9387
|
+
xl: {
|
|
9388
|
+
padding: "1.25rem 2.75rem",
|
|
9389
|
+
fontSize: "text-2xl"
|
|
9390
|
+
}
|
|
9391
|
+
},
|
|
9392
|
+
roles: {
|
|
9393
|
+
primary: {
|
|
9394
|
+
kind: "complete",
|
|
9395
|
+
appearance: {
|
|
9396
|
+
background: {
|
|
9397
|
+
type: "solid",
|
|
9398
|
+
colorToken: "primary"
|
|
9399
|
+
},
|
|
9400
|
+
borderRadius: "rounded-full",
|
|
9401
|
+
shadow: {
|
|
9402
|
+
elevation: "high",
|
|
9403
|
+
softness: "hard",
|
|
9404
|
+
position: "bottom-right",
|
|
9405
|
+
colorToken: "text"
|
|
9406
|
+
},
|
|
9407
|
+
effects: { hover: [{ effectId: "press-down" }] }
|
|
9401
9408
|
}
|
|
9402
9409
|
},
|
|
9403
|
-
{
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
|
|
9417
|
-
|
|
9410
|
+
secondary: {
|
|
9411
|
+
kind: "complete",
|
|
9412
|
+
appearance: {
|
|
9413
|
+
background: {
|
|
9414
|
+
type: "surface",
|
|
9415
|
+
role: "link"
|
|
9416
|
+
},
|
|
9417
|
+
borderRadius: "rounded-full",
|
|
9418
|
+
border: { widthClass: "border-2" },
|
|
9419
|
+
shadow: {
|
|
9420
|
+
elevation: "high",
|
|
9421
|
+
softness: "hard",
|
|
9422
|
+
position: "bottom-right",
|
|
9423
|
+
colorToken: "secondary"
|
|
9424
|
+
},
|
|
9425
|
+
effects: { hover: [{ effectId: "press-down" }] }
|
|
9426
|
+
}
|
|
9418
9427
|
},
|
|
9419
|
-
{
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
enabled: true,
|
|
9423
|
-
priority: 3,
|
|
9424
|
-
background: {
|
|
9425
|
-
type: "surface",
|
|
9426
|
-
role: "link"
|
|
9427
|
-
},
|
|
9428
|
-
borderRadius: "rounded-full",
|
|
9429
|
-
border: { widthClass: "border" },
|
|
9430
|
-
effects: { hover: [{
|
|
9431
|
-
effectId: "background-on-hover",
|
|
9432
|
-
options: { colorToken: "surface" }
|
|
9433
|
-
}] }
|
|
9428
|
+
outline: {
|
|
9429
|
+
kind: "derive",
|
|
9430
|
+
from: "secondary"
|
|
9434
9431
|
},
|
|
9435
|
-
{
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9432
|
+
ghost: {
|
|
9433
|
+
kind: "complete",
|
|
9434
|
+
appearance: {
|
|
9435
|
+
background: {
|
|
9436
|
+
type: "surface",
|
|
9437
|
+
role: "link"
|
|
9438
|
+
},
|
|
9439
|
+
borderRadius: "rounded-full",
|
|
9440
|
+
effects: { hover: [{ effectId: "press-down" }] }
|
|
9441
|
+
}
|
|
9442
|
+
},
|
|
9443
|
+
accent: {
|
|
9444
|
+
kind: "derive",
|
|
9445
|
+
from: "primary",
|
|
9446
|
+
overrides: { background: {
|
|
9447
|
+
type: "solid",
|
|
9448
|
+
colorToken: "accent"
|
|
9449
|
+
} }
|
|
9449
9450
|
}
|
|
9450
|
-
|
|
9451
|
+
}
|
|
9451
9452
|
}
|
|
9452
9453
|
});
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
type: "solid",
|
|
9462
|
-
colorToken: unsafeAsOpaqueButtonColourToken("secondary")
|
|
9454
|
+
const ornateRitualRecipe = defineStaticButtonStyleRecipe({
|
|
9455
|
+
id: "ornate-ritual",
|
|
9456
|
+
accessibilityLabel: "Uppercase framed buttons with restrained movement",
|
|
9457
|
+
tags: {
|
|
9458
|
+
tone: "classic",
|
|
9459
|
+
energy: "vibrant",
|
|
9460
|
+
motion: "subtle",
|
|
9461
|
+
era: "organic"
|
|
9463
9462
|
},
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9475
|
-
|
|
9463
|
+
system: {
|
|
9464
|
+
global: {
|
|
9465
|
+
cornerStyle: "rounded",
|
|
9466
|
+
textTransform: "uppercase",
|
|
9467
|
+
fontWeight: 600,
|
|
9468
|
+
borderWidth: 1,
|
|
9469
|
+
hoverTransform: "none",
|
|
9470
|
+
hoverColor: "none",
|
|
9471
|
+
letterSpacing: "loose"
|
|
9472
|
+
},
|
|
9473
|
+
sizes: {
|
|
9474
|
+
sm: {
|
|
9475
|
+
padding: "0.5625rem 1.25rem",
|
|
9476
|
+
fontSize: "text-xs"
|
|
9477
|
+
},
|
|
9478
|
+
md: {
|
|
9479
|
+
padding: "0.75rem 1.75rem",
|
|
9480
|
+
fontSize: "text-xs"
|
|
9481
|
+
},
|
|
9482
|
+
lg: {
|
|
9483
|
+
padding: "0.875rem 2.25rem",
|
|
9484
|
+
fontSize: "text-sm"
|
|
9485
|
+
},
|
|
9486
|
+
xl: {
|
|
9487
|
+
padding: "1rem 2.75rem",
|
|
9488
|
+
fontSize: "text-base"
|
|
9476
9489
|
}
|
|
9477
|
-
}
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9490
|
+
},
|
|
9491
|
+
roles: {
|
|
9492
|
+
primary: {
|
|
9493
|
+
kind: "complete",
|
|
9494
|
+
appearance: {
|
|
9495
|
+
background: {
|
|
9496
|
+
type: "solid",
|
|
9497
|
+
colorToken: "primary"
|
|
9498
|
+
},
|
|
9499
|
+
borderRadius: "rounded-md",
|
|
9500
|
+
border: { widthClass: "border" },
|
|
9501
|
+
effects: {
|
|
9502
|
+
hover: [{
|
|
9503
|
+
effectId: "background-on-hover",
|
|
9504
|
+
options: { colorToken: "primary-100" }
|
|
9505
|
+
}],
|
|
9506
|
+
active: [{
|
|
9507
|
+
effectId: "scale-down",
|
|
9508
|
+
options: { scale: "0.98" }
|
|
9509
|
+
}]
|
|
9510
|
+
}
|
|
9511
|
+
}
|
|
9512
|
+
},
|
|
9513
|
+
secondary: {
|
|
9514
|
+
kind: "complete",
|
|
9515
|
+
appearance: {
|
|
9516
|
+
background: {
|
|
9517
|
+
type: "solid",
|
|
9518
|
+
colorToken: "secondary"
|
|
9519
|
+
},
|
|
9520
|
+
borderRadius: "rounded-md",
|
|
9521
|
+
border: { widthClass: "border" },
|
|
9522
|
+
effects: { hover: [{
|
|
9523
|
+
effectId: "background-on-hover",
|
|
9524
|
+
options: { colorToken: "surface" }
|
|
9525
|
+
}] }
|
|
9526
|
+
}
|
|
9527
|
+
},
|
|
9528
|
+
outline: {
|
|
9529
|
+
kind: "complete",
|
|
9530
|
+
appearance: {
|
|
9531
|
+
background: {
|
|
9532
|
+
type: "surface",
|
|
9533
|
+
role: "link"
|
|
9534
|
+
},
|
|
9535
|
+
borderRadius: "rounded-md",
|
|
9536
|
+
border: { widthClass: "border" },
|
|
9537
|
+
effects: { hover: [{
|
|
9538
|
+
effectId: "background-on-hover",
|
|
9539
|
+
options: { colorToken: "muted" }
|
|
9540
|
+
}] }
|
|
9541
|
+
}
|
|
9542
|
+
},
|
|
9543
|
+
ghost: {
|
|
9544
|
+
kind: "complete",
|
|
9545
|
+
appearance: {
|
|
9546
|
+
background: {
|
|
9547
|
+
type: "surface",
|
|
9548
|
+
role: "link"
|
|
9549
|
+
},
|
|
9550
|
+
borderRadius: "rounded-none",
|
|
9551
|
+
sizes: {
|
|
9552
|
+
sm: {
|
|
9553
|
+
padding: "0.375rem 0",
|
|
9554
|
+
fontSize: "text-xs"
|
|
9555
|
+
},
|
|
9556
|
+
md: {
|
|
9557
|
+
padding: "0.5rem 0",
|
|
9558
|
+
fontSize: "text-sm"
|
|
9559
|
+
},
|
|
9560
|
+
lg: {
|
|
9561
|
+
padding: "0.625rem 0",
|
|
9562
|
+
fontSize: "text-base"
|
|
9563
|
+
},
|
|
9564
|
+
xl: {
|
|
9565
|
+
padding: "0.75rem 0",
|
|
9566
|
+
fontSize: "text-lg"
|
|
9567
|
+
}
|
|
9568
|
+
},
|
|
9569
|
+
effects: { base: [{
|
|
9570
|
+
effectId: "border-bottom-grow",
|
|
9571
|
+
options: {
|
|
9572
|
+
height: 1,
|
|
9573
|
+
colorToken: "accent",
|
|
9574
|
+
origin: "left"
|
|
9575
|
+
}
|
|
9576
|
+
}] }
|
|
9577
|
+
}
|
|
9578
|
+
},
|
|
9579
|
+
accent: {
|
|
9580
|
+
kind: "derive",
|
|
9581
|
+
from: "primary",
|
|
9582
|
+
overrides: { background: {
|
|
9583
|
+
type: "solid",
|
|
9584
|
+
colorToken: "accent"
|
|
9585
|
+
} }
|
|
9586
|
+
}
|
|
9587
|
+
}
|
|
9482
9588
|
}
|
|
9483
|
-
};
|
|
9589
|
+
});
|
|
9484
9590
|
//#endregion
|
|
9485
|
-
//#region ../theme-core/src/buttons/
|
|
9486
|
-
const
|
|
9487
|
-
|
|
9488
|
-
|
|
9489
|
-
|
|
9490
|
-
|
|
9491
|
-
|
|
9492
|
-
|
|
9493
|
-
|
|
9494
|
-
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
confidentChip,
|
|
9500
|
-
editorialLink,
|
|
9501
|
-
pebble,
|
|
9502
|
-
inkStamp,
|
|
9503
|
-
flatInk,
|
|
9504
|
-
brushedWash,
|
|
9505
|
-
showtimePill,
|
|
9506
|
-
joyStamp,
|
|
9507
|
-
ornateRitual,
|
|
9508
|
-
quietArrow
|
|
9591
|
+
//#region ../theme-core/src/buttons/styles/registry.ts
|
|
9592
|
+
const buttonStyleRecipes = [
|
|
9593
|
+
softPillRecipe,
|
|
9594
|
+
earthPillRecipe,
|
|
9595
|
+
confidentChipRecipe,
|
|
9596
|
+
editorialLinkRecipe,
|
|
9597
|
+
pebbleRecipe,
|
|
9598
|
+
inkStampRecipe,
|
|
9599
|
+
flatInkRecipe,
|
|
9600
|
+
brushedWashRecipe,
|
|
9601
|
+
showtimePillRecipe,
|
|
9602
|
+
joyStampRecipe,
|
|
9603
|
+
ornateRitualRecipe,
|
|
9604
|
+
quietArrowRecipe
|
|
9509
9605
|
];
|
|
9510
|
-
new Map(
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9606
|
+
const recipesById = new Map(buttonStyleRecipes.map((recipe) => [recipe.id, recipe]));
|
|
9607
|
+
function findButtonStyleRecipe(id) {
|
|
9608
|
+
const recipe = recipesById.get(id);
|
|
9609
|
+
if (recipe === void 0) throw new Error(`Button style registry is missing known style ${id}`);
|
|
9610
|
+
return recipe;
|
|
9611
|
+
}
|
|
9612
|
+
function resolveButtonStyleSelection(selection) {
|
|
9613
|
+
switch (selection.styleId) {
|
|
9614
|
+
case "soft-pill": return resolveButtonStyleRecipe(softPillRecipe, selection.parameters);
|
|
9615
|
+
case "earth-pill": return resolveButtonStyleRecipe(earthPillRecipe, selection.parameters);
|
|
9616
|
+
case "confident-chip": return resolveButtonStyleRecipe(confidentChipRecipe, selection.parameters);
|
|
9617
|
+
case "editorial-link": return resolveButtonStyleRecipe(editorialLinkRecipe, selection.parameters);
|
|
9618
|
+
case "pebble": return resolveButtonStyleRecipe(pebbleRecipe, selection.parameters);
|
|
9619
|
+
case "ink-stamp": return resolveButtonStyleRecipe(inkStampRecipe, selection.parameters);
|
|
9620
|
+
case "flat-ink": return resolveButtonStyleRecipe(flatInkRecipe, selection.parameters);
|
|
9621
|
+
case "brushed-wash": return resolveButtonStyleRecipe(brushedWashRecipe, selection.parameters);
|
|
9622
|
+
case "showtime-pill": return resolveButtonStyleRecipe(showtimePillRecipe, selection.parameters);
|
|
9623
|
+
case "joy-stamp": return resolveButtonStyleRecipe(joyStampRecipe, selection.parameters);
|
|
9624
|
+
case "ornate-ritual": return resolveButtonStyleRecipe(ornateRitualRecipe, selection.parameters);
|
|
9625
|
+
case "quiet-arrow": return resolveButtonStyleRecipe(quietArrowRecipe, selection.parameters);
|
|
9626
|
+
}
|
|
9627
|
+
}
|
|
9628
|
+
function defaultButtonStyleSelectionFor(styleId) {
|
|
9629
|
+
return {
|
|
9630
|
+
styleId,
|
|
9631
|
+
parameters: findButtonStyleRecipe(styleId).defaultParameters
|
|
9632
|
+
};
|
|
9633
|
+
}
|
|
9634
|
+
if (buttonStyleRecipes.map((recipe) => recipe.id).length !== BUTTON_STYLE_IDS.length || BUTTON_STYLE_IDS.some((id) => !recipesById.has(id))) throw new Error("Button style registry and ButtonStyleId catalog are out of sync");
|
|
9635
|
+
buttonStyleRecipes.map((recipe) => {
|
|
9636
|
+
const resolved = resolveButtonStyleSelection(defaultButtonStyleSelectionFor(recipe.id));
|
|
9637
|
+
if (resolved.kind === "error") throw new Error(`Invalid registered button style ${recipe.id}: ${resolved.error.issues.join(", ")}`);
|
|
9638
|
+
return {
|
|
9639
|
+
id: recipe.id,
|
|
9640
|
+
name: recipe.accessibilityLabel,
|
|
9641
|
+
description: recipe.accessibilityLabel,
|
|
9642
|
+
category: presetCategory(recipe),
|
|
9643
|
+
buttonSystem: resolved.buttonSystem,
|
|
9644
|
+
compatibility: {
|
|
9645
|
+
...recipe.tags.tone ? { tones: [recipe.tags.tone] } : {},
|
|
9646
|
+
...recipe.tags.energy ? { energies: [recipe.tags.energy] } : {}
|
|
9647
|
+
}
|
|
9648
|
+
};
|
|
9649
|
+
});
|
|
9650
|
+
function presetCategory(recipe) {
|
|
9651
|
+
switch (recipe.tags.era) {
|
|
9524
9652
|
case "retro": return "retro";
|
|
9525
9653
|
case "editorial": return "minimal";
|
|
9526
9654
|
case "organic": return "artistic";
|
|
9527
|
-
case "modern": return
|
|
9655
|
+
case "modern": return recipe.tags.tone === "bold" ? "modern" : "technical";
|
|
9528
9656
|
case "technical": return "technical";
|
|
9529
9657
|
case void 0: return "modern";
|
|
9530
9658
|
}
|
|
@@ -10868,6 +10996,43 @@ function consumeSearchParam(paramName) {
|
|
|
10868
10996
|
return value;
|
|
10869
10997
|
}
|
|
10870
10998
|
//#endregion
|
|
10999
|
+
//#region ../blocks/src/system/runtime/shared/utils/validation.ts
|
|
11000
|
+
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
11001
|
+
/**
|
|
11002
|
+
* Validate registration form data.
|
|
11003
|
+
*
|
|
11004
|
+
* Only `name` and `email` are required fields. The `phone` and `notes` fields
|
|
11005
|
+
* are optional and not validated by this function.
|
|
11006
|
+
*
|
|
11007
|
+
* @param data - Form data to validate
|
|
11008
|
+
* @returns Object with field errors (empty if valid)
|
|
11009
|
+
*/
|
|
11010
|
+
function validateFormData$1(data) {
|
|
11011
|
+
const errors = {};
|
|
11012
|
+
if (!data.name.trim()) errors.name = "Name is required";
|
|
11013
|
+
if (!data.email.trim()) errors.email = "Email is required";
|
|
11014
|
+
else if (!EMAIL_REGEX.test(data.email.trim())) errors.email = "Please enter a valid email";
|
|
11015
|
+
return errors;
|
|
11016
|
+
}
|
|
11017
|
+
//#endregion
|
|
11018
|
+
//#region ../blocks/src/system/runtime/shared/utils/wizardSteps.ts
|
|
11019
|
+
/**
|
|
11020
|
+
* Shared Wizard Step Utilities
|
|
11021
|
+
*
|
|
11022
|
+
* Helpers for wizard step navigation in registration blocks.
|
|
11023
|
+
*/
|
|
11024
|
+
/**
|
|
11025
|
+
* Get the 1-based step number for a step in the wizard.
|
|
11026
|
+
*
|
|
11027
|
+
* @param step - The step to find
|
|
11028
|
+
* @param wizardSteps - Array of wizard steps
|
|
11029
|
+
* @returns 1-based step number, or 1 if step not found
|
|
11030
|
+
*/
|
|
11031
|
+
function getStepNumber(step, wizardSteps) {
|
|
11032
|
+
const index = wizardSteps.indexOf(step);
|
|
11033
|
+
return index >= 0 ? index + 1 : 1;
|
|
11034
|
+
}
|
|
11035
|
+
//#endregion
|
|
10871
11036
|
//#region ../blocks/src/system/runtime/nodes/booking-form.client.tsx
|
|
10872
11037
|
const PORTAL_REBOOK_QUERY_PARAM = "rebook";
|
|
10873
11038
|
const PORTAL_REBOOK_QUERY_VALUE = "1";
|
|
@@ -13337,14 +13502,14 @@ const eventRegistrationWizardDeps = {
|
|
|
13337
13502
|
useEventRegistrationSubmit,
|
|
13338
13503
|
useDiscountCodeUi
|
|
13339
13504
|
};
|
|
13340
|
-
function parseCurrencyInputToCents(value) {
|
|
13505
|
+
function parseCurrencyInputToCents$1(value) {
|
|
13341
13506
|
const trimmed = value.trim();
|
|
13342
13507
|
if (!trimmed) return null;
|
|
13343
13508
|
const amount = Number(trimmed);
|
|
13344
13509
|
if (!Number.isFinite(amount) || amount < 0) return null;
|
|
13345
13510
|
return Math.round(amount * 100);
|
|
13346
13511
|
}
|
|
13347
|
-
function formatCentsAsCurrencyInput(amount) {
|
|
13512
|
+
function formatCentsAsCurrencyInput$1(amount) {
|
|
13348
13513
|
const major = amount / 100;
|
|
13349
13514
|
return Number.isInteger(major) ? String(major) : major.toFixed(2);
|
|
13350
13515
|
}
|
|
@@ -13405,7 +13570,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
13405
13570
|
const [selectedTicketLines, setSelectedTicketLines] = useState([]);
|
|
13406
13571
|
const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState(() => {
|
|
13407
13572
|
const slidingScale = getSlidingScaleForEvent(preSelectedEvent ?? null);
|
|
13408
|
-
return slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : "";
|
|
13573
|
+
return slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput$1(slidingScale.suggestedAmount) : "";
|
|
13409
13574
|
});
|
|
13410
13575
|
const [registrationResult, setRegistrationResult] = useState(null);
|
|
13411
13576
|
const [errorMessage, setErrorMessage] = useState("");
|
|
@@ -13478,7 +13643,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
13478
13643
|
occurrenceId,
|
|
13479
13644
|
attendanceMode: selectedAttendanceMode,
|
|
13480
13645
|
ticketSelections,
|
|
13481
|
-
selectedSlidingAmount: parseCurrencyInputToCents(selectedSlidingAmountInput),
|
|
13646
|
+
selectedSlidingAmount: parseCurrencyInputToCents$1(selectedSlidingAmountInput),
|
|
13482
13647
|
email: formData.email
|
|
13483
13648
|
});
|
|
13484
13649
|
const existingRegistrationResult = deps.useExistingEventRegistration({
|
|
@@ -13630,7 +13795,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
13630
13795
|
selectedAttendanceMode,
|
|
13631
13796
|
singleSelectedTicketTypeId
|
|
13632
13797
|
]);
|
|
13633
|
-
const selectedSlidingAmount = useMemo(() => parseCurrencyInputToCents(selectedSlidingAmountInput), [selectedSlidingAmountInput]);
|
|
13798
|
+
const selectedSlidingAmount = useMemo(() => parseCurrencyInputToCents$1(selectedSlidingAmountInput), [selectedSlidingAmountInput]);
|
|
13634
13799
|
const selectedEventSlidingScale = useMemo(() => getSlidingScaleForEvent(selectedEvent ?? preSelectedEvent), [selectedEvent, preSelectedEvent]);
|
|
13635
13800
|
const slidingScaleSelectionMessage = getSlidingScaleSelectionMessage({
|
|
13636
13801
|
slidingScale: selectedEventSlidingScale,
|
|
@@ -13884,7 +14049,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
|
|
|
13884
14049
|
const handleEventSelect = (event) => {
|
|
13885
14050
|
setSelectedEvent(event);
|
|
13886
14051
|
const slidingScale = getSlidingScaleForEvent(event);
|
|
13887
|
-
setSelectedSlidingAmountInput(slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(slidingScale.suggestedAmount) : "");
|
|
14052
|
+
setSelectedSlidingAmountInput(slidingScale?.suggestedAmount !== null && slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput$1(slidingScale.suggestedAmount) : "");
|
|
13888
14053
|
setSelectedAttendanceMode((event.deliveryMode ?? "in_person") === "hybrid" ? null : (event.deliveryMode ?? "in_person") === "online" ? "online" : "in_person");
|
|
13889
14054
|
setSelectedTicketLines([]);
|
|
13890
14055
|
dispatchFlow({
|
|
@@ -14128,82 +14293,1421 @@ function useEventRegistrationControllerWithDeps(options, deps) {
|
|
|
14128
14293
|
}, [directPaymentOptions, wizard]);
|
|
14129
14294
|
const next = useCallback(async () => {
|
|
14130
14295
|
switch (wizard.step) {
|
|
14131
|
-
case "select-event":
|
|
14132
|
-
if (!wizard.selectedEvent) return {
|
|
14133
|
-
ok: false,
|
|
14134
|
-
reason: "blocked",
|
|
14135
|
-
message: "Select an event to continue."
|
|
14136
|
-
};
|
|
14137
|
-
wizard.setStep("select-tickets");
|
|
14138
|
-
return { ok: true };
|
|
14139
|
-
case "select-tickets":
|
|
14140
|
-
if (wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection) return {
|
|
14296
|
+
case "select-event":
|
|
14297
|
+
if (!wizard.selectedEvent) return {
|
|
14298
|
+
ok: false,
|
|
14299
|
+
reason: "blocked",
|
|
14300
|
+
message: "Select an event to continue."
|
|
14301
|
+
};
|
|
14302
|
+
wizard.setStep("select-tickets");
|
|
14303
|
+
return { ok: true };
|
|
14304
|
+
case "select-tickets":
|
|
14305
|
+
if (wizard.ticketTypeSelectionRequired && !wizard.hasValidTicketSelection) return {
|
|
14306
|
+
ok: false,
|
|
14307
|
+
reason: "blocked",
|
|
14308
|
+
message: "Choose at least one available ticket to continue."
|
|
14309
|
+
};
|
|
14310
|
+
wizard.setStep("enter-details");
|
|
14311
|
+
return { ok: true };
|
|
14312
|
+
case "enter-details": {
|
|
14313
|
+
const result = await wizard.handleDetailsComplete();
|
|
14314
|
+
return result.ok ? { ok: true } : result;
|
|
14315
|
+
}
|
|
14316
|
+
case "select-payment": {
|
|
14317
|
+
const result = await submit({ redirect: "manual" });
|
|
14318
|
+
return result.ok ? { ok: true } : {
|
|
14319
|
+
ok: false,
|
|
14320
|
+
reason: result.reason === "submission-failed" ? "submission-failed" : "blocked",
|
|
14321
|
+
message: result.message
|
|
14322
|
+
};
|
|
14323
|
+
}
|
|
14324
|
+
case "error":
|
|
14325
|
+
case "success":
|
|
14326
|
+
case "submitting":
|
|
14327
|
+
case "redirecting":
|
|
14328
|
+
case "verifying-payment":
|
|
14329
|
+
case "verifying-timeout":
|
|
14330
|
+
case "payment-failed": return {
|
|
14331
|
+
ok: false,
|
|
14332
|
+
reason: "blocked",
|
|
14333
|
+
message: "This registration step cannot continue."
|
|
14334
|
+
};
|
|
14335
|
+
}
|
|
14336
|
+
}, [submit, wizard]);
|
|
14337
|
+
const back = useCallback(() => {
|
|
14338
|
+
switch (wizard.step) {
|
|
14339
|
+
case "enter-details":
|
|
14340
|
+
wizard.setStep("select-tickets");
|
|
14341
|
+
return;
|
|
14342
|
+
case "select-payment":
|
|
14343
|
+
wizard.setStep("enter-details");
|
|
14344
|
+
return;
|
|
14345
|
+
case "select-tickets":
|
|
14346
|
+
if (!wizard.hasPreSelectedContext) wizard.setStep("select-event");
|
|
14347
|
+
return;
|
|
14348
|
+
case "select-event":
|
|
14349
|
+
case "error":
|
|
14350
|
+
case "success":
|
|
14351
|
+
case "submitting":
|
|
14352
|
+
case "redirecting":
|
|
14353
|
+
case "verifying-payment":
|
|
14354
|
+
case "verifying-timeout":
|
|
14355
|
+
case "payment-failed": return;
|
|
14356
|
+
}
|
|
14357
|
+
}, [wizard]);
|
|
14358
|
+
const updateAttendee = useCallback((values) => {
|
|
14359
|
+
wizard.setFormData(values);
|
|
14360
|
+
}, [wizard]);
|
|
14361
|
+
const updateGuests = useCallback((guests) => {
|
|
14362
|
+
wizard.setGuests(guests);
|
|
14363
|
+
}, [wizard]);
|
|
14364
|
+
const selectPayment = useCallback((selection) => {
|
|
14365
|
+
wizard.handlePaymentSelectionChange(normalizeEventRegistrationDirectPaymentSelection({
|
|
14366
|
+
options: directPaymentOptions,
|
|
14367
|
+
selection: toInternalPaymentSelection(selection)
|
|
14368
|
+
}));
|
|
14369
|
+
}, [directPaymentOptions, wizard]);
|
|
14370
|
+
const selectedTicketTypeId = getSingleSelectedTicketTypeId(wizard.selectedTicketLines);
|
|
14371
|
+
const spamProtection = options.spamProtectionEnabled ?? isSpamProtectionEnabled() ? {
|
|
14372
|
+
enabled: true,
|
|
14373
|
+
provider: "altcha",
|
|
14374
|
+
challenge: {
|
|
14375
|
+
url: getChallengeUrl(),
|
|
14376
|
+
auto: "onfocus"
|
|
14377
|
+
},
|
|
14378
|
+
solution: wizard.altchaSolution
|
|
14379
|
+
} : { enabled: false };
|
|
14380
|
+
const payment = resolvePaymentModel(wizard, directPaymentOptions);
|
|
14381
|
+
return {
|
|
14382
|
+
flow: {
|
|
14383
|
+
status: resolveHeadlessEventRegistrationStatus(wizard),
|
|
14384
|
+
view: resolveHeadlessEventRegistrationView(wizard),
|
|
14385
|
+
steps,
|
|
14386
|
+
currentStep,
|
|
14387
|
+
events: {
|
|
14388
|
+
items: wizard.events,
|
|
14389
|
+
scoped: wizard.scopedEvents,
|
|
14390
|
+
selected: wizard.selectedEvent,
|
|
14391
|
+
preSelected: wizard.preSelectedEvent,
|
|
14392
|
+
hasPreSelectedContext: wizard.hasPreSelectedContext,
|
|
14393
|
+
target: wizard.registrationTarget,
|
|
14394
|
+
occurrenceContext: wizard.occurrenceContext,
|
|
14395
|
+
contentEntry: wizard.contentEntry
|
|
14396
|
+
},
|
|
14397
|
+
tickets: {
|
|
14398
|
+
count: wizard.ticketsCount,
|
|
14399
|
+
max: wizard.maxTicketsNum,
|
|
14400
|
+
selections: wizard.ticketSelections,
|
|
14401
|
+
summaryLines: wizard.ticketSelectionSummaryLines,
|
|
14402
|
+
subtotalCents: wizard.ticketSelectionSubtotalCents,
|
|
14403
|
+
selectedTicketTypeId,
|
|
14404
|
+
selectedTicketType: wizard.selectedTicketType,
|
|
14405
|
+
visibleTicketTypes: wizard.visibleTicketTypes,
|
|
14406
|
+
selectionRequired: wizard.ticketTypeSelectionRequired,
|
|
14407
|
+
hasValidSelection: wizard.hasValidTicketSelection,
|
|
14408
|
+
eventRequiresPayment: wizard.eventRequiresPayment,
|
|
14409
|
+
selectedAttendanceMode: wizard.selectedAttendanceMode
|
|
14410
|
+
},
|
|
14411
|
+
attendee: {
|
|
14412
|
+
values: wizard.formData,
|
|
14413
|
+
errors: wizard.errors
|
|
14414
|
+
},
|
|
14415
|
+
guests: {
|
|
14416
|
+
required: wizard.requireGuestDetails,
|
|
14417
|
+
items: wizard.guests,
|
|
14418
|
+
errors: wizard.guestErrors,
|
|
14419
|
+
shake: wizard.guestSectionShake
|
|
14420
|
+
},
|
|
14421
|
+
payment,
|
|
14422
|
+
discount: {
|
|
14423
|
+
code: wizard.discountCode,
|
|
14424
|
+
isOpen: wizard.discountUiOpen,
|
|
14425
|
+
available: wizard.discountsAvailable,
|
|
14426
|
+
manualCodeEntryAllowed: wizard.manualCodeEntryAllowed,
|
|
14427
|
+
loading: wizard.discountsAvailableLoading,
|
|
14428
|
+
autoAppliedDiscount: wizard.autoAppliedDiscount
|
|
14429
|
+
},
|
|
14430
|
+
portalAuth: {
|
|
14431
|
+
state: wizard.portalAuthState,
|
|
14432
|
+
profile: wizard.portalProfile,
|
|
14433
|
+
isAuthenticated: wizard.portalAuthState === "authenticated",
|
|
14434
|
+
showMagicLinkModal: wizard.showMagicLinkModal
|
|
14435
|
+
},
|
|
14436
|
+
existingRegistration: {
|
|
14437
|
+
state: resolveExistingRegistrationState(wizard),
|
|
14438
|
+
registration: wizard.existingRegistration
|
|
14439
|
+
},
|
|
14440
|
+
waitlistClaim: wizard.waitlistClaim,
|
|
14441
|
+
spamProtection,
|
|
14442
|
+
terminal: {
|
|
14443
|
+
result: wizard.registrationResult,
|
|
14444
|
+
errorMessage: wizard.errorMessage,
|
|
14445
|
+
verification: wizard.verification
|
|
14446
|
+
},
|
|
14447
|
+
actions: {
|
|
14448
|
+
selectEvent: wizard.handleEventSelect,
|
|
14449
|
+
selectAttendanceMode: wizard.setSelectedAttendanceMode,
|
|
14450
|
+
selectTicketType: (ticketTypeId) => {
|
|
14451
|
+
wizard.setSelectedTicketLines(ticketTypeId ? [{
|
|
14452
|
+
ticketTypeId,
|
|
14453
|
+
quantity: 1
|
|
14454
|
+
}] : []);
|
|
14455
|
+
},
|
|
14456
|
+
setTicketSelections: wizard.setSelectedTicketLines,
|
|
14457
|
+
setTicketsCount: wizard.setTicketsCount,
|
|
14458
|
+
updateAttendee,
|
|
14459
|
+
updateGuests,
|
|
14460
|
+
selectPayment,
|
|
14461
|
+
setDiscountCode: wizard.setDiscountCode,
|
|
14462
|
+
setDiscountOpen: wizard.setDiscountUiOpen,
|
|
14463
|
+
setAltchaSolution: wizard.setAltchaSolution,
|
|
14464
|
+
requestLogin: () => wizard.setShowMagicLinkModal(true),
|
|
14465
|
+
logout: wizard.handleLogout,
|
|
14466
|
+
next,
|
|
14467
|
+
back,
|
|
14468
|
+
submit,
|
|
14469
|
+
retry: wizard.handleRetry
|
|
14470
|
+
}
|
|
14471
|
+
},
|
|
14472
|
+
wizard
|
|
14473
|
+
};
|
|
14474
|
+
}
|
|
14475
|
+
function useEventRegistrationWizardControllerWithDeps(options, deps) {
|
|
14476
|
+
const maxTicketsNum = normalizeEventRegistrationMaxTickets(options.maxTickets);
|
|
14477
|
+
return { wizard: deps.useEventRegistrationWizard({
|
|
14478
|
+
anchorId: options.anchorId ?? "event-registration",
|
|
14479
|
+
occurrenceContext: options.occurrenceContext ?? null,
|
|
14480
|
+
contentEntry: options.contentEntry ?? null,
|
|
14481
|
+
events: [...options.events ?? []],
|
|
14482
|
+
maxTicketsNum
|
|
14483
|
+
}) };
|
|
14484
|
+
}
|
|
14485
|
+
function resolveExistingRegistrationState(wizard) {
|
|
14486
|
+
switch (wizard.existingRegistrationState.tag) {
|
|
14487
|
+
case "idle": return {
|
|
14488
|
+
tag: "idle",
|
|
14489
|
+
value: wizard.existingRegistration
|
|
14490
|
+
};
|
|
14491
|
+
case "loading": return {
|
|
14492
|
+
tag: "loading",
|
|
14493
|
+
value: wizard.existingRegistration
|
|
14494
|
+
};
|
|
14495
|
+
case "resolved": return {
|
|
14496
|
+
tag: "loaded",
|
|
14497
|
+
value: wizard.existingRegistration
|
|
14498
|
+
};
|
|
14499
|
+
}
|
|
14500
|
+
}
|
|
14501
|
+
function resolvePaymentModel(wizard, directPaymentOptions) {
|
|
14502
|
+
const internalSelection = normalizeEventRegistrationDirectPaymentSelection({
|
|
14503
|
+
options: directPaymentOptions,
|
|
14504
|
+
selection: wizard.paymentSelection
|
|
14505
|
+
});
|
|
14506
|
+
const selection = toHeadlessPaymentSelection(internalSelection);
|
|
14507
|
+
const directPaymentSelectionState = resolveEventRegistrationDirectPaymentSelection({
|
|
14508
|
+
options: directPaymentOptions,
|
|
14509
|
+
selection: internalSelection
|
|
14510
|
+
});
|
|
14511
|
+
if (wizard.step !== "select-payment") return {
|
|
14512
|
+
kind: "hidden",
|
|
14513
|
+
selection,
|
|
14514
|
+
directPaymentOptions,
|
|
14515
|
+
directPaymentSelectionState,
|
|
14516
|
+
stepState: wizard.paymentStepState
|
|
14517
|
+
};
|
|
14518
|
+
return {
|
|
14519
|
+
kind: wizard.paymentStepState.status,
|
|
14520
|
+
selection,
|
|
14521
|
+
directPaymentOptions,
|
|
14522
|
+
directPaymentSelectionState,
|
|
14523
|
+
stepState: wizard.paymentStepState,
|
|
14524
|
+
eligibility: wizard.eligibility,
|
|
14525
|
+
eligibilityError: wizard.eligibilityError
|
|
14526
|
+
};
|
|
14527
|
+
}
|
|
14528
|
+
function resolveHeadlessDirectPaymentOptions(wizard) {
|
|
14529
|
+
const eligibility = wizard.eligibility;
|
|
14530
|
+
if (!eligibility?.eligible || !eligibility.canPayDirectly || !eligibility.price) return [];
|
|
14531
|
+
const event = wizard.selectedEvent ?? wizard.preSelectedEvent;
|
|
14532
|
+
return buildEventRegistrationPaymentOptionsViewModel({
|
|
14533
|
+
eventTitle: event?.title ?? "Event",
|
|
14534
|
+
paymentTerms: event?.paymentTerms,
|
|
14535
|
+
totalPriceCents: eligibility.price,
|
|
14536
|
+
currency: eligibility.currency,
|
|
14537
|
+
startsAt: wizard.occurrenceContext?.startsAt ?? event?.startsAt
|
|
14538
|
+
}).options;
|
|
14539
|
+
}
|
|
14540
|
+
//#endregion
|
|
14541
|
+
//#region ../blocks/src/system/blocks/courses/shared/pricing.ts
|
|
14542
|
+
function isSaleWindowOpen(option, now) {
|
|
14543
|
+
if (!option.isActive) return false;
|
|
14544
|
+
if (option.saleStartsAt && new Date(option.saleStartsAt) > now) return false;
|
|
14545
|
+
if (option.saleEndsAt && new Date(option.saleEndsAt) < now) return false;
|
|
14546
|
+
return true;
|
|
14547
|
+
}
|
|
14548
|
+
function toExactOrFreeDisplay(amount, currency) {
|
|
14549
|
+
if (amount <= 0) return {
|
|
14550
|
+
kind: "free",
|
|
14551
|
+
currency
|
|
14552
|
+
};
|
|
14553
|
+
return {
|
|
14554
|
+
kind: "exact",
|
|
14555
|
+
amount,
|
|
14556
|
+
currency
|
|
14557
|
+
};
|
|
14558
|
+
}
|
|
14559
|
+
function getSelectableCoursePricingOptionsForNow(course, now) {
|
|
14560
|
+
if (!course.pricing || course.pricing.pricingStrategy !== "tiered") return [];
|
|
14561
|
+
return [...course.pricing.options].filter((option) => isSaleWindowOpen(option, now)).sort((left, right) => {
|
|
14562
|
+
if (left.sortOrder !== right.sortOrder) return left.sortOrder - right.sortOrder;
|
|
14563
|
+
if (left.priceAmount !== right.priceAmount) return left.priceAmount - right.priceAmount;
|
|
14564
|
+
return left.name.localeCompare(right.name);
|
|
14565
|
+
});
|
|
14566
|
+
}
|
|
14567
|
+
function resolveCoursePricingState(course, selectedPricingOptionId, selectedSlidingAmountOrNowInput, nowInput = {}) {
|
|
14568
|
+
const selectedSlidingAmount = typeof selectedSlidingAmountOrNowInput === "number" || selectedSlidingAmountOrNowInput === null ? selectedSlidingAmountOrNowInput : null;
|
|
14569
|
+
const effectiveNowInput = typeof selectedSlidingAmountOrNowInput === "object" && selectedSlidingAmountOrNowInput !== null ? selectedSlidingAmountOrNowInput : nowInput;
|
|
14570
|
+
const currency = course.pricing?.currency ?? course.currency;
|
|
14571
|
+
if (!course.pricing) {
|
|
14572
|
+
const legacyAmount = course.priceCents ?? 0;
|
|
14573
|
+
return {
|
|
14574
|
+
currency,
|
|
14575
|
+
display: toExactOrFreeDisplay(legacyAmount, currency),
|
|
14576
|
+
selectableOptions: [],
|
|
14577
|
+
requiresSelection: false,
|
|
14578
|
+
selectedOption: null,
|
|
14579
|
+
slidingScale: null,
|
|
14580
|
+
selectedSlidingAmount: null,
|
|
14581
|
+
selectedPriceAmount: legacyAmount,
|
|
14582
|
+
selectedRequiresPayment: legacyAmount > 0,
|
|
14583
|
+
hasPaidSelection: legacyAmount > 0,
|
|
14584
|
+
hasFreeSelection: legacyAmount <= 0
|
|
14585
|
+
};
|
|
14586
|
+
}
|
|
14587
|
+
switch (course.pricing.pricingStrategy) {
|
|
14588
|
+
case "free": return {
|
|
14589
|
+
currency,
|
|
14590
|
+
display: {
|
|
14591
|
+
kind: "free",
|
|
14592
|
+
currency
|
|
14593
|
+
},
|
|
14594
|
+
selectableOptions: [],
|
|
14595
|
+
requiresSelection: false,
|
|
14596
|
+
selectedOption: null,
|
|
14597
|
+
slidingScale: null,
|
|
14598
|
+
selectedSlidingAmount: null,
|
|
14599
|
+
selectedPriceAmount: 0,
|
|
14600
|
+
selectedRequiresPayment: false,
|
|
14601
|
+
hasPaidSelection: false,
|
|
14602
|
+
hasFreeSelection: true
|
|
14603
|
+
};
|
|
14604
|
+
case "single": {
|
|
14605
|
+
const amount = course.pricing.singlePriceAmount ?? 0;
|
|
14606
|
+
return {
|
|
14607
|
+
currency,
|
|
14608
|
+
display: toExactOrFreeDisplay(amount, currency),
|
|
14609
|
+
selectableOptions: [],
|
|
14610
|
+
requiresSelection: false,
|
|
14611
|
+
selectedOption: null,
|
|
14612
|
+
slidingScale: null,
|
|
14613
|
+
selectedSlidingAmount: null,
|
|
14614
|
+
selectedPriceAmount: amount,
|
|
14615
|
+
selectedRequiresPayment: amount > 0,
|
|
14616
|
+
hasPaidSelection: amount > 0,
|
|
14617
|
+
hasFreeSelection: amount <= 0
|
|
14618
|
+
};
|
|
14619
|
+
}
|
|
14620
|
+
case "tiered": {
|
|
14621
|
+
const selectableOptions = getSelectableCoursePricingOptionsForNow(course, resolvePlanningDateInput(effectiveNowInput));
|
|
14622
|
+
const selectedOption = (selectedPricingOptionId ? selectableOptions.find((option) => option.id === selectedPricingOptionId) : null) ?? (selectableOptions.length === 1 ? selectableOptions[0] ?? null : null);
|
|
14623
|
+
const lowestAmount = selectableOptions.reduce((lowest, option) => {
|
|
14624
|
+
if (lowest === null || option.priceAmount < lowest) return option.priceAmount;
|
|
14625
|
+
return lowest;
|
|
14626
|
+
}, null);
|
|
14627
|
+
return {
|
|
14628
|
+
currency,
|
|
14629
|
+
display: lowestAmount === null ? {
|
|
14630
|
+
kind: "unavailable",
|
|
14631
|
+
currency
|
|
14632
|
+
} : selectableOptions.length > 1 && lowestAmount > 0 ? {
|
|
14633
|
+
kind: "from",
|
|
14634
|
+
amount: lowestAmount,
|
|
14635
|
+
currency
|
|
14636
|
+
} : toExactOrFreeDisplay(lowestAmount, currency),
|
|
14637
|
+
selectableOptions,
|
|
14638
|
+
requiresSelection: selectableOptions.length > 1,
|
|
14639
|
+
selectedOption,
|
|
14640
|
+
slidingScale: null,
|
|
14641
|
+
selectedSlidingAmount: null,
|
|
14642
|
+
selectedPriceAmount: selectedOption?.priceAmount ?? null,
|
|
14643
|
+
selectedRequiresPayment: (selectedOption?.priceAmount ?? 0) > 0,
|
|
14644
|
+
hasPaidSelection: selectableOptions.some((option) => option.priceAmount > 0),
|
|
14645
|
+
hasFreeSelection: selectableOptions.some((option) => option.priceAmount === 0)
|
|
14646
|
+
};
|
|
14647
|
+
}
|
|
14648
|
+
case "sliding_scale": {
|
|
14649
|
+
const minAmount = course.pricing.slidingMinAmount ?? null;
|
|
14650
|
+
const maxAmount = course.pricing.slidingMaxAmount ?? null;
|
|
14651
|
+
if (minAmount === null || maxAmount === null || minAmount < 0 || maxAmount < minAmount) return {
|
|
14652
|
+
currency,
|
|
14653
|
+
display: {
|
|
14654
|
+
kind: "unavailable",
|
|
14655
|
+
currency
|
|
14656
|
+
},
|
|
14657
|
+
selectableOptions: [],
|
|
14658
|
+
requiresSelection: true,
|
|
14659
|
+
selectedOption: null,
|
|
14660
|
+
slidingScale: null,
|
|
14661
|
+
selectedSlidingAmount: null,
|
|
14662
|
+
selectedPriceAmount: null,
|
|
14663
|
+
selectedRequiresPayment: false,
|
|
14664
|
+
hasPaidSelection: false,
|
|
14665
|
+
hasFreeSelection: false
|
|
14666
|
+
};
|
|
14667
|
+
const normalizedSelectedAmount = typeof selectedSlidingAmount === "number" && Number.isFinite(selectedSlidingAmount) ? selectedSlidingAmount : null;
|
|
14668
|
+
return {
|
|
14669
|
+
currency,
|
|
14670
|
+
display: {
|
|
14671
|
+
kind: "range",
|
|
14672
|
+
minAmount,
|
|
14673
|
+
maxAmount,
|
|
14674
|
+
currency
|
|
14675
|
+
},
|
|
14676
|
+
selectableOptions: [],
|
|
14677
|
+
requiresSelection: normalizedSelectedAmount === null,
|
|
14678
|
+
selectedOption: null,
|
|
14679
|
+
slidingScale: {
|
|
14680
|
+
minAmount,
|
|
14681
|
+
maxAmount,
|
|
14682
|
+
suggestedAmount: course.pricing.slidingSuggestedAmount ?? null
|
|
14683
|
+
},
|
|
14684
|
+
selectedSlidingAmount: normalizedSelectedAmount,
|
|
14685
|
+
selectedPriceAmount: normalizedSelectedAmount,
|
|
14686
|
+
selectedRequiresPayment: (normalizedSelectedAmount ?? 0) > 0,
|
|
14687
|
+
hasPaidSelection: maxAmount > 0,
|
|
14688
|
+
hasFreeSelection: minAmount === 0
|
|
14689
|
+
};
|
|
14690
|
+
}
|
|
14691
|
+
}
|
|
14692
|
+
}
|
|
14693
|
+
//#endregion
|
|
14694
|
+
//#region ../blocks/src/system/runtime/nodes/course-registration/utils.ts
|
|
14695
|
+
/**
|
|
14696
|
+
* Anchor ID for the registration block, used for scroll targeting.
|
|
14697
|
+
*/
|
|
14698
|
+
const COURSE_REGISTRATION_ANCHOR_ID = "course-registration";
|
|
14699
|
+
//#endregion
|
|
14700
|
+
//#region ../blocks/src/system/runtime/nodes/course-registration/wizardSteps.ts
|
|
14701
|
+
/**
|
|
14702
|
+
* Step labels for the wizard indicator
|
|
14703
|
+
*/
|
|
14704
|
+
const STEP_LABELS = {
|
|
14705
|
+
"select-course": "Course",
|
|
14706
|
+
"enter-details": "Details",
|
|
14707
|
+
"booking-mode": "Method",
|
|
14708
|
+
"select-payment": "Payment",
|
|
14709
|
+
submitting: "Booking",
|
|
14710
|
+
redirecting: "Redirecting",
|
|
14711
|
+
"verifying-payment": "Verifying",
|
|
14712
|
+
"verifying-timeout": "Timeout",
|
|
14713
|
+
"payment-failed": "Failed",
|
|
14714
|
+
success: "Complete",
|
|
14715
|
+
waitlist: "Waitlist",
|
|
14716
|
+
error: "Error"
|
|
14717
|
+
};
|
|
14718
|
+
/**
|
|
14719
|
+
* Determine which wizard steps to show based on context and eligibility.
|
|
14720
|
+
*
|
|
14721
|
+
* @param hasPreSelectedCourse - Whether course is pre-selected (skips course selection)
|
|
14722
|
+
* @param requiresPayment - Whether the course requires payment
|
|
14723
|
+
* @param hasEligibleMemberships - Whether user has eligible memberships
|
|
14724
|
+
* @param bookingMode - Current booking mode selection
|
|
14725
|
+
* @param isMembershipFastTrack - Whether user qualifies for single-step membership flow
|
|
14726
|
+
* @returns Array of wizard steps to display
|
|
14727
|
+
*/
|
|
14728
|
+
function getWizardStepsForContext(hasPreSelectedCourse, requiresPayment, hasEligibleMemberships, bookingMode, isMembershipFastTrack) {
|
|
14729
|
+
if (isMembershipFastTrack) return hasPreSelectedCourse ? ["enter-details"] : ["select-course", "enter-details"];
|
|
14730
|
+
if (!requiresPayment) return hasPreSelectedCourse ? ["enter-details"] : ["select-course", "enter-details"];
|
|
14731
|
+
if (hasEligibleMemberships) {
|
|
14732
|
+
const skipPayment = bookingMode === "membership";
|
|
14733
|
+
if (hasPreSelectedCourse) return skipPayment ? ["enter-details", "booking-mode"] : [
|
|
14734
|
+
"enter-details",
|
|
14735
|
+
"booking-mode",
|
|
14736
|
+
"select-payment"
|
|
14737
|
+
];
|
|
14738
|
+
return skipPayment ? [
|
|
14739
|
+
"select-course",
|
|
14740
|
+
"enter-details",
|
|
14741
|
+
"booking-mode"
|
|
14742
|
+
] : [
|
|
14743
|
+
"select-course",
|
|
14744
|
+
"enter-details",
|
|
14745
|
+
"booking-mode",
|
|
14746
|
+
"select-payment"
|
|
14747
|
+
];
|
|
14748
|
+
}
|
|
14749
|
+
return hasPreSelectedCourse ? ["enter-details", "select-payment"] : [
|
|
14750
|
+
"select-course",
|
|
14751
|
+
"enter-details",
|
|
14752
|
+
"select-payment"
|
|
14753
|
+
];
|
|
14754
|
+
}
|
|
14755
|
+
/**
|
|
14756
|
+
* Get labels for a list of wizard steps
|
|
14757
|
+
*/
|
|
14758
|
+
function getStepLabels(steps) {
|
|
14759
|
+
return steps.map((step) => STEP_LABELS[step] ?? step);
|
|
14760
|
+
}
|
|
14761
|
+
//#endregion
|
|
14762
|
+
//#region ../blocks/src/system/runtime/nodes/course-page-surface-scope.ts
|
|
14763
|
+
/**
|
|
14764
|
+
* Resolves native course-page ownership without falling back to entry or slug
|
|
14765
|
+
* coincidence when a page-surface subject is present but invalid.
|
|
14766
|
+
*/
|
|
14767
|
+
function resolveCoursePageSurfaceScope(courses, subjectValue) {
|
|
14768
|
+
if (subjectValue === null || subjectValue === void 0) return { kind: "absent" };
|
|
14769
|
+
const parsed = parseEventPageSurfaceSubject(subjectValue);
|
|
14770
|
+
if (!parsed.ok) return {
|
|
14771
|
+
kind: "unsupported",
|
|
14772
|
+
reason: parsed.error.kind
|
|
14773
|
+
};
|
|
14774
|
+
const seriesIds = eventSeriesIdsForSubject(parsed.value);
|
|
14775
|
+
const allowedSeriesIds = new Set(seriesIds);
|
|
14776
|
+
return {
|
|
14777
|
+
kind: "scoped",
|
|
14778
|
+
subject: parsed.value,
|
|
14779
|
+
courses: courses.filter((course) => allowedSeriesIds.has(course.seriesId))
|
|
14780
|
+
};
|
|
14781
|
+
}
|
|
14782
|
+
function eventSeriesIdsForSubject(subject) {
|
|
14783
|
+
switch (subject.kind) {
|
|
14784
|
+
case "eventSeries": return [subject.eventSeriesId];
|
|
14785
|
+
case "eventOffering": return subject.availableEventSeriesIds;
|
|
14786
|
+
default: return assertNever$3(subject);
|
|
14787
|
+
}
|
|
14788
|
+
}
|
|
14789
|
+
//#endregion
|
|
14790
|
+
//#region ../blocks/src/system/runtime/nodes/course-registration/useCourseRegistrationWizard.ts
|
|
14791
|
+
function parseCurrencyInputToCents(value) {
|
|
14792
|
+
const trimmed = value.trim();
|
|
14793
|
+
if (!trimmed) return null;
|
|
14794
|
+
const amount = Number(trimmed);
|
|
14795
|
+
if (!Number.isFinite(amount) || amount < 0) return null;
|
|
14796
|
+
return Math.round(amount * 100);
|
|
14797
|
+
}
|
|
14798
|
+
function formatCentsAsCurrencyInput(amount) {
|
|
14799
|
+
const major = amount / 100;
|
|
14800
|
+
return Number.isInteger(major) ? String(major) : major.toFixed(2);
|
|
14801
|
+
}
|
|
14802
|
+
function shouldFetchCourseEligibility(course, hasPaidSelection, portalAuthState, hasWaitlistClaimToken) {
|
|
14803
|
+
if (!course || portalAuthState === "checking") return false;
|
|
14804
|
+
if (hasWaitlistClaimToken) return false;
|
|
14805
|
+
const needsMembershipEligibility = portalAuthState === "authenticated" && hasPaidSelection && course.acceptsMemberships;
|
|
14806
|
+
const needsWaitlistAvailabilityCheck = course.availableSpots !== null && course.availableSpots <= 0;
|
|
14807
|
+
return needsMembershipEligibility || needsWaitlistAvailabilityCheck;
|
|
14808
|
+
}
|
|
14809
|
+
/**
|
|
14810
|
+
* Extracts session_id from URL, checking both query params and hash fragment.
|
|
14811
|
+
*
|
|
14812
|
+
* Stripe appends session_id to the success URL, but if our URL contains a hash
|
|
14813
|
+
* (e.g., #course-registration), Stripe ends up appending session_id after the hash:
|
|
14814
|
+
* Expected: ?enrollment=success&session_id=cs_test_...#course-registration
|
|
14815
|
+
* Actual: ?enrollment=success#course-registration&session_id=cs_test_...
|
|
14816
|
+
*
|
|
14817
|
+
* This helper checks both locations to handle this edge case.
|
|
14818
|
+
*/
|
|
14819
|
+
function getSessionIdFromUrl() {
|
|
14820
|
+
const fromSearch = new URLSearchParams(window.location.search).get("session_id");
|
|
14821
|
+
if (fromSearch) return fromSearch;
|
|
14822
|
+
return window.location.hash.match(/[?&]session_id=([^&]+)/)?.[1] ?? null;
|
|
14823
|
+
}
|
|
14824
|
+
function getMissingCoursePricingSelectionMessage(pricing) {
|
|
14825
|
+
if (pricing?.requiresSelection && !pricing.selectedOption) {
|
|
14826
|
+
if (pricing.slidingScale) return "Choose an amount to continue.";
|
|
14827
|
+
return "Choose a pricing option to continue.";
|
|
14828
|
+
}
|
|
14829
|
+
if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount < pricing.slidingScale.minAmount) return "Choose an amount within the sliding scale.";
|
|
14830
|
+
if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null && pricing.selectedSlidingAmount > pricing.slidingScale.maxAmount) return "Choose an amount within the sliding scale.";
|
|
14831
|
+
return null;
|
|
14832
|
+
}
|
|
14833
|
+
function buildCoursePricingOptionPayload(pricing) {
|
|
14834
|
+
if (pricing?.selectedOption) return { pricingOptionId: pricing.selectedOption.id };
|
|
14835
|
+
if (pricing?.slidingScale && pricing.selectedSlidingAmount !== null) return { selectedSlidingAmount: pricing.selectedSlidingAmount };
|
|
14836
|
+
return {};
|
|
14837
|
+
}
|
|
14838
|
+
function resolveHasCoursePayment(pricing) {
|
|
14839
|
+
if (!pricing) return false;
|
|
14840
|
+
if (pricing.selectedOption) return pricing.selectedRequiresPayment;
|
|
14841
|
+
return pricing.hasPaidSelection;
|
|
14842
|
+
}
|
|
14843
|
+
function useCourseRegistrationWizard(props, options = {}) {
|
|
14844
|
+
const api = useBlockApi();
|
|
14845
|
+
const { contentEntry, courses, entrySubrouteContext, subject } = props;
|
|
14846
|
+
const scopedCourses = useMemo(() => {
|
|
14847
|
+
const allCourses = courses ?? [];
|
|
14848
|
+
if (entrySubrouteContext?.kind === "course-run") {
|
|
14849
|
+
const matched = allCourses.find((c) => c.id === entrySubrouteContext.run.courseId) ?? null;
|
|
14850
|
+
if (matched) return [matched];
|
|
14851
|
+
}
|
|
14852
|
+
const pageSurfaceScope = resolveCoursePageSurfaceScope(allCourses, subject);
|
|
14853
|
+
if (pageSurfaceScope.kind === "unsupported") return [];
|
|
14854
|
+
if (pageSurfaceScope.kind === "scoped") return [...pageSurfaceScope.courses];
|
|
14855
|
+
if (contentEntry?.id) {
|
|
14856
|
+
const matchedCourses = allCourses.filter((c) => c.contentEntryId === contentEntry.id);
|
|
14857
|
+
if (matchedCourses.length > 0) return matchedCourses;
|
|
14858
|
+
}
|
|
14859
|
+
if (contentEntry?.slug) {
|
|
14860
|
+
const matchedCourse = allCourses.find((c) => c.slug === contentEntry.slug);
|
|
14861
|
+
if (matchedCourse) return [matchedCourse];
|
|
14862
|
+
}
|
|
14863
|
+
return allCourses;
|
|
14864
|
+
}, [
|
|
14865
|
+
courses,
|
|
14866
|
+
contentEntry?.id,
|
|
14867
|
+
contentEntry?.slug,
|
|
14868
|
+
entrySubrouteContext,
|
|
14869
|
+
subject
|
|
14870
|
+
]);
|
|
14871
|
+
const [step, setStep] = useState(() => {
|
|
14872
|
+
const enrollment = new URLSearchParams(window.location.search).get("enrollment");
|
|
14873
|
+
const sessionId = getSessionIdFromUrl();
|
|
14874
|
+
if (enrollment === "success" && sessionId) return "verifying-payment";
|
|
14875
|
+
return scopedCourses.length === 1 ? "enter-details" : "select-course";
|
|
14876
|
+
});
|
|
14877
|
+
const [selectedCourse, setSelectedCourse] = useState(scopedCourses.length === 1 ? scopedCourses[0] ?? null : null);
|
|
14878
|
+
const [selectedPricingOptionId, setSelectedPricingOptionId] = useState(null);
|
|
14879
|
+
const [selectedSlidingAmountInput, setSelectedSlidingAmountInput] = useState("");
|
|
14880
|
+
const [formData, setFormData] = useState({
|
|
14881
|
+
name: "",
|
|
14882
|
+
email: "",
|
|
14883
|
+
phone: "",
|
|
14884
|
+
notes: ""
|
|
14885
|
+
});
|
|
14886
|
+
const [errors, setErrors] = useState({});
|
|
14887
|
+
const [enrollmentResult, setEnrollmentResult] = useState(null);
|
|
14888
|
+
const [errorMessage, setErrorMessage] = useState("");
|
|
14889
|
+
const [portalAuthState, setPortalAuthState] = useState("checking");
|
|
14890
|
+
const [altchaSolution, setAltchaSolution] = useState(null);
|
|
14891
|
+
const showSpamProtection = isSpamProtectionEnabled();
|
|
14892
|
+
const [eligibilityLoading, setEligibilityLoading] = useState(false);
|
|
14893
|
+
const [eligibilityError, setEligibilityError] = useState(null);
|
|
14894
|
+
const [courseEligibility, setCourseEligibility] = useState(null);
|
|
14895
|
+
const [eligibleMemberships, setEligibleMemberships] = useState([]);
|
|
14896
|
+
const [paymentChoice, setPaymentChoice] = useState("checkout");
|
|
14897
|
+
const [selectedMembershipId, setSelectedMembershipId] = useState(null);
|
|
14898
|
+
const [bookingMode, setBookingMode] = useState(null);
|
|
14899
|
+
const waitlistClaim = useWaitlistClaim();
|
|
14900
|
+
const selectedCoursePricing = useMemo(() => selectedCourse ? resolveCoursePricingState(selectedCourse, selectedPricingOptionId, parseCurrencyInputToCents(selectedSlidingAmountInput)) : null, [
|
|
14901
|
+
selectedCourse,
|
|
14902
|
+
selectedPricingOptionId,
|
|
14903
|
+
selectedSlidingAmountInput
|
|
14904
|
+
]);
|
|
14905
|
+
const missingPricingSelectionMessage = getMissingCoursePricingSelectionMessage(selectedCoursePricing);
|
|
14906
|
+
const selectedCoursePricingPayload = buildCoursePricingOptionPayload(selectedCoursePricing);
|
|
14907
|
+
const showSoldOutCourseError = () => {
|
|
14908
|
+
setErrorMessage(courseEligibility?.reason ?? "This course is fully booked.");
|
|
14909
|
+
setStep("error");
|
|
14910
|
+
return true;
|
|
14911
|
+
};
|
|
14912
|
+
useEffect(() => {
|
|
14913
|
+
let cancelled = false;
|
|
14914
|
+
async function checkPortalAuth() {
|
|
14915
|
+
if (!(api.config.auth.type === "bearer" || api.config.authOverrides?.portal?.type === "bearer")) {
|
|
14916
|
+
setPortalAuthState("unauthenticated");
|
|
14917
|
+
return;
|
|
14918
|
+
}
|
|
14919
|
+
setPortalAuthState("checking");
|
|
14920
|
+
try {
|
|
14921
|
+
const me = await api.getPortalProfile();
|
|
14922
|
+
if (cancelled) return;
|
|
14923
|
+
setPortalAuthState("authenticated");
|
|
14924
|
+
setFormData((prev) => ({
|
|
14925
|
+
...prev,
|
|
14926
|
+
email: me.profile.email,
|
|
14927
|
+
name: prev.name || me.profile.name,
|
|
14928
|
+
phone: prev.phone || me.profile.phone || ""
|
|
14929
|
+
}));
|
|
14930
|
+
} catch {
|
|
14931
|
+
if (cancelled) return;
|
|
14932
|
+
setPortalAuthState("unauthenticated");
|
|
14933
|
+
}
|
|
14934
|
+
}
|
|
14935
|
+
checkPortalAuth();
|
|
14936
|
+
return () => {
|
|
14937
|
+
cancelled = true;
|
|
14938
|
+
};
|
|
14939
|
+
}, [api]);
|
|
14940
|
+
useEffect(() => {
|
|
14941
|
+
const claim = waitlistClaim.claim;
|
|
14942
|
+
if (!claim || claim.subject.kind !== "course") return;
|
|
14943
|
+
const courseId = claim.subject.courseId;
|
|
14944
|
+
const matchedCourse = scopedCourses.find((course) => course.id === courseId) ?? null;
|
|
14945
|
+
if (!matchedCourse) {
|
|
14946
|
+
setErrorMessage("This waitlist claim is for a different course.");
|
|
14947
|
+
setStep("error");
|
|
14948
|
+
return;
|
|
14949
|
+
}
|
|
14950
|
+
setSelectedCourse(matchedCourse);
|
|
14951
|
+
setFormData((prev) => ({
|
|
14952
|
+
...prev,
|
|
14953
|
+
email: claim.prefill.email,
|
|
14954
|
+
name: claim.prefill.name,
|
|
14955
|
+
phone: claim.prefill.phone ?? "",
|
|
14956
|
+
notes: claim.prefill.notes ?? ""
|
|
14957
|
+
}));
|
|
14958
|
+
if (step === "select-course") setStep("enter-details");
|
|
14959
|
+
}, [
|
|
14960
|
+
waitlistClaim.claim,
|
|
14961
|
+
scopedCourses,
|
|
14962
|
+
step
|
|
14963
|
+
]);
|
|
14964
|
+
useEffect(() => {
|
|
14965
|
+
if (waitlistClaim.requiresPortalLogin) return;
|
|
14966
|
+
if (!waitlistClaim.error) return;
|
|
14967
|
+
setErrorMessage(waitlistClaim.error);
|
|
14968
|
+
setStep("error");
|
|
14969
|
+
}, [waitlistClaim.error, waitlistClaim.requiresPortalLogin]);
|
|
14970
|
+
useEffect(() => {
|
|
14971
|
+
if (!selectedCourse) {
|
|
14972
|
+
setSelectedPricingOptionId(null);
|
|
14973
|
+
setSelectedSlidingAmountInput("");
|
|
14974
|
+
return;
|
|
14975
|
+
}
|
|
14976
|
+
const defaultPricing = resolveCoursePricingState(selectedCourse, null);
|
|
14977
|
+
setSelectedSlidingAmountInput(defaultPricing.slidingScale?.suggestedAmount !== null && defaultPricing.slidingScale?.suggestedAmount !== void 0 ? formatCentsAsCurrencyInput(defaultPricing.slidingScale.suggestedAmount) : "");
|
|
14978
|
+
setSelectedPricingOptionId((previous) => {
|
|
14979
|
+
if (previous && defaultPricing.selectableOptions.some((option) => option.id === previous)) return previous;
|
|
14980
|
+
return defaultPricing.selectedOption?.id ?? null;
|
|
14981
|
+
});
|
|
14982
|
+
}, [selectedCourse]);
|
|
14983
|
+
useEffect(() => {
|
|
14984
|
+
let cancelled = false;
|
|
14985
|
+
async function fetchEligibility() {
|
|
14986
|
+
setCourseEligibility(null);
|
|
14987
|
+
setEligibleMemberships([]);
|
|
14988
|
+
setSelectedMembershipId(null);
|
|
14989
|
+
setEligibilityError(null);
|
|
14990
|
+
setPaymentChoice("checkout");
|
|
14991
|
+
const course = selectedCourse;
|
|
14992
|
+
if (!shouldFetchCourseEligibility(course, selectedCoursePricing?.hasPaidSelection ?? false, portalAuthState, waitlistClaim.token !== null)) return;
|
|
14993
|
+
if (!course) return;
|
|
14994
|
+
setEligibilityLoading(true);
|
|
14995
|
+
try {
|
|
14996
|
+
const res = await api.checkCourseEligibility({ courseId: course.id });
|
|
14997
|
+
if (cancelled) return;
|
|
14998
|
+
setCourseEligibility(res);
|
|
14999
|
+
const memberships = res.eligibleMemberships ?? [];
|
|
15000
|
+
setEligibleMemberships(memberships);
|
|
15001
|
+
if (portalAuthState === "authenticated" && memberships.length > 0) {
|
|
15002
|
+
setPaymentChoice("membership");
|
|
15003
|
+
if (memberships.length === 1) setSelectedMembershipId(memberships[0]?.customerMembershipId ?? null);
|
|
15004
|
+
}
|
|
15005
|
+
} catch (error) {
|
|
15006
|
+
if (cancelled) return;
|
|
15007
|
+
setEligibilityError(error instanceof Error ? error.message : "Failed to check membership eligibility");
|
|
15008
|
+
} finally {
|
|
15009
|
+
if (!cancelled) setEligibilityLoading(false);
|
|
15010
|
+
}
|
|
15011
|
+
}
|
|
15012
|
+
fetchEligibility();
|
|
15013
|
+
return () => {
|
|
15014
|
+
cancelled = true;
|
|
15015
|
+
};
|
|
15016
|
+
}, [
|
|
15017
|
+
api,
|
|
15018
|
+
selectedCourse,
|
|
15019
|
+
selectedCoursePricing?.hasPaidSelection,
|
|
15020
|
+
portalAuthState,
|
|
15021
|
+
waitlistClaim.token
|
|
15022
|
+
]);
|
|
15023
|
+
useEffect(() => {
|
|
15024
|
+
let cancelled = false;
|
|
15025
|
+
async function verifyAfterCheckout() {
|
|
15026
|
+
const enrollment = new URLSearchParams(window.location.search).get("enrollment");
|
|
15027
|
+
const sessionId = getSessionIdFromUrl();
|
|
15028
|
+
if (enrollment === "cancelled") {
|
|
15029
|
+
scrollToBlock(COURSE_REGISTRATION_ANCHOR_ID);
|
|
15030
|
+
setErrorMessage("Payment was cancelled. You can try again.");
|
|
15031
|
+
setStep("error");
|
|
15032
|
+
return;
|
|
15033
|
+
}
|
|
15034
|
+
if (enrollment !== "success" || !sessionId) return;
|
|
15035
|
+
scrollToBlock(COURSE_REGISTRATION_ANCHOR_ID);
|
|
15036
|
+
setStep("verifying-payment");
|
|
15037
|
+
const startedAt = Date.now();
|
|
15038
|
+
const timeoutMs = 3e4;
|
|
15039
|
+
while (!cancelled) {
|
|
15040
|
+
try {
|
|
15041
|
+
const status = await api.getCourseRegistrationStatus({ sessionId });
|
|
15042
|
+
if (cancelled) return;
|
|
15043
|
+
if (status.status === "enrolled" || status.status === "completed") {
|
|
15044
|
+
setEnrollmentResult({
|
|
15045
|
+
status: "enrolled",
|
|
15046
|
+
usedMembership: false
|
|
15047
|
+
});
|
|
15048
|
+
setStep("success");
|
|
15049
|
+
return;
|
|
15050
|
+
}
|
|
15051
|
+
if (status.status === "waitlist") {
|
|
15052
|
+
setEnrollmentResult({
|
|
15053
|
+
status: "waitlist",
|
|
15054
|
+
usedMembership: false
|
|
15055
|
+
});
|
|
15056
|
+
setStep("waitlist");
|
|
15057
|
+
return;
|
|
15058
|
+
}
|
|
15059
|
+
if (status.status === "cancelled") {
|
|
15060
|
+
setErrorMessage("Payment did not complete. Please try again.");
|
|
15061
|
+
setStep("error");
|
|
15062
|
+
return;
|
|
15063
|
+
}
|
|
15064
|
+
} catch (error) {
|
|
15065
|
+
setErrorMessage(error instanceof Error ? error.message : "Failed to verify payment");
|
|
15066
|
+
}
|
|
15067
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
15068
|
+
setErrorMessage("Payment is still processing. Please check your email for confirmation.");
|
|
15069
|
+
setStep("error");
|
|
15070
|
+
return;
|
|
15071
|
+
}
|
|
15072
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
15073
|
+
}
|
|
15074
|
+
}
|
|
15075
|
+
verifyAfterCheckout();
|
|
15076
|
+
return () => {
|
|
15077
|
+
cancelled = true;
|
|
15078
|
+
};
|
|
15079
|
+
}, [api]);
|
|
15080
|
+
const handleValidateForm = () => {
|
|
15081
|
+
const newErrors = validateFormData$1(formData);
|
|
15082
|
+
setErrors(newErrors);
|
|
15083
|
+
return Object.keys(newErrors).length === 0;
|
|
15084
|
+
};
|
|
15085
|
+
const handleCourseSelect = (course) => {
|
|
15086
|
+
setSelectedCourse(course);
|
|
15087
|
+
setStep("enter-details");
|
|
15088
|
+
};
|
|
15089
|
+
const handleSubmit = async () => {
|
|
15090
|
+
if (!selectedCourse) return {
|
|
15091
|
+
kind: "blocked",
|
|
15092
|
+
message: "Choose an available set of dates to continue."
|
|
15093
|
+
};
|
|
15094
|
+
if (!handleValidateForm()) return { kind: "validation-failed" };
|
|
15095
|
+
if (missingPricingSelectionMessage) {
|
|
15096
|
+
setErrorMessage(missingPricingSelectionMessage);
|
|
15097
|
+
setStep("error");
|
|
15098
|
+
return {
|
|
15099
|
+
kind: "blocked",
|
|
15100
|
+
message: missingPricingSelectionMessage
|
|
15101
|
+
};
|
|
15102
|
+
}
|
|
15103
|
+
const requiresPayment = selectedCoursePricing?.selectedRequiresPayment ?? false;
|
|
15104
|
+
const canUseMembership = requiresPayment && selectedCourse.acceptsMemberships && portalAuthState === "authenticated" && eligibleMemberships.length > 0;
|
|
15105
|
+
if (showSpamProtection && !altchaSolution) {
|
|
15106
|
+
const message = "Please complete the verification check.";
|
|
15107
|
+
setErrorMessage(message);
|
|
15108
|
+
setStep("error");
|
|
15109
|
+
return {
|
|
15110
|
+
kind: "blocked",
|
|
15111
|
+
message
|
|
15112
|
+
};
|
|
15113
|
+
}
|
|
15114
|
+
if (!waitlistClaim.claim && courseEligibility?.isFull && !courseEligibility.canJoinWaitlist && showSoldOutCourseError()) return {
|
|
15115
|
+
kind: "blocked",
|
|
15116
|
+
message: courseEligibility.reason ?? "This course is fully booked."
|
|
15117
|
+
};
|
|
15118
|
+
if (courseEligibility?.canJoinWaitlist) {
|
|
15119
|
+
setStep("submitting");
|
|
15120
|
+
try {
|
|
15121
|
+
const result = await api.enrollInCourse({
|
|
15122
|
+
courseId: selectedCourse.id,
|
|
15123
|
+
...selectedCoursePricingPayload,
|
|
15124
|
+
email: formData.email.trim().toLowerCase(),
|
|
15125
|
+
name: formData.name.trim(),
|
|
15126
|
+
phone: formData.phone.trim() || void 0,
|
|
15127
|
+
formData: { notes: formData.notes.trim() || void 0 },
|
|
15128
|
+
altchaSolution,
|
|
15129
|
+
paymentMethod: "free",
|
|
15130
|
+
claimToken: waitlistClaim.token ?? void 0
|
|
15131
|
+
});
|
|
15132
|
+
setEnrollmentResult({
|
|
15133
|
+
status: result.status,
|
|
15134
|
+
waitlistPosition: result.waitlistPosition ?? void 0,
|
|
15135
|
+
usedMembership: false
|
|
15136
|
+
});
|
|
15137
|
+
setStep(result.status === "waitlist" ? "waitlist" : "success");
|
|
15138
|
+
return { kind: "state-updated" };
|
|
15139
|
+
} catch (error) {
|
|
15140
|
+
const message = error instanceof Error ? error.message : "Booking failed";
|
|
15141
|
+
setErrorMessage(message);
|
|
15142
|
+
setStep("error");
|
|
15143
|
+
return {
|
|
15144
|
+
kind: "failed",
|
|
15145
|
+
message
|
|
15146
|
+
};
|
|
15147
|
+
}
|
|
15148
|
+
}
|
|
15149
|
+
if (requiresPayment && canUseMembership) {
|
|
15150
|
+
setStep("select-payment");
|
|
15151
|
+
return { kind: "state-updated" };
|
|
15152
|
+
}
|
|
15153
|
+
if (requiresPayment) {
|
|
15154
|
+
setStep("submitting");
|
|
15155
|
+
try {
|
|
15156
|
+
const { successUrl, cancelUrl } = buildCheckoutReturnUrls("enrollment", COURSE_REGISTRATION_ANCHOR_ID);
|
|
15157
|
+
const checkoutResult = await api.createCourseCheckout({
|
|
15158
|
+
courseId: selectedCourse.id,
|
|
15159
|
+
...selectedCoursePricingPayload,
|
|
15160
|
+
email: formData.email.trim().toLowerCase(),
|
|
15161
|
+
name: formData.name.trim(),
|
|
15162
|
+
phone: formData.phone.trim() || void 0,
|
|
15163
|
+
formData: { notes: formData.notes.trim() || void 0 },
|
|
15164
|
+
altchaSolution,
|
|
15165
|
+
discountCode: discountCode.trim() ? discountCode.trim() : void 0,
|
|
15166
|
+
successUrl,
|
|
15167
|
+
cancelUrl,
|
|
15168
|
+
claimToken: waitlistClaim.token ?? void 0
|
|
15169
|
+
});
|
|
15170
|
+
if (checkoutResult.bypassed) {
|
|
15171
|
+
setEnrollmentResult({
|
|
15172
|
+
status: "enrolled",
|
|
15173
|
+
waitlistPosition: void 0,
|
|
15174
|
+
usedMembership: false
|
|
15175
|
+
});
|
|
15176
|
+
setStep("success");
|
|
15177
|
+
return { kind: "state-updated" };
|
|
15178
|
+
}
|
|
15179
|
+
if (!checkoutResult.checkoutUrl) throw new Error("Checkout URL missing");
|
|
15180
|
+
setStep("redirecting");
|
|
15181
|
+
if (options.onCheckoutRedirect) options.onCheckoutRedirect(checkoutResult.checkoutUrl);
|
|
15182
|
+
else window.location.href = checkoutResult.checkoutUrl;
|
|
15183
|
+
return {
|
|
15184
|
+
kind: "checkout-redirect",
|
|
15185
|
+
checkoutUrl: checkoutResult.checkoutUrl
|
|
15186
|
+
};
|
|
15187
|
+
} catch (error) {
|
|
15188
|
+
const message = error instanceof Error ? error.message : "Checkout failed";
|
|
15189
|
+
setErrorMessage(message);
|
|
15190
|
+
setStep("error");
|
|
15191
|
+
return {
|
|
15192
|
+
kind: "failed",
|
|
15193
|
+
message
|
|
15194
|
+
};
|
|
15195
|
+
}
|
|
15196
|
+
}
|
|
15197
|
+
setStep("submitting");
|
|
15198
|
+
try {
|
|
15199
|
+
const result = await api.enrollInCourse({
|
|
15200
|
+
courseId: selectedCourse.id,
|
|
15201
|
+
...selectedCoursePricingPayload,
|
|
15202
|
+
email: formData.email.trim().toLowerCase(),
|
|
15203
|
+
name: formData.name.trim(),
|
|
15204
|
+
phone: formData.phone.trim() || void 0,
|
|
15205
|
+
formData: { notes: formData.notes.trim() || void 0 },
|
|
15206
|
+
altchaSolution,
|
|
15207
|
+
paymentMethod: "free",
|
|
15208
|
+
claimToken: waitlistClaim.token ?? void 0
|
|
15209
|
+
});
|
|
15210
|
+
setEnrollmentResult({
|
|
15211
|
+
status: result.status,
|
|
15212
|
+
waitlistPosition: result.waitlistPosition ?? void 0,
|
|
15213
|
+
usedMembership: result.paymentMethod === "membership"
|
|
15214
|
+
});
|
|
15215
|
+
setStep(result.status === "waitlist" ? "waitlist" : "success");
|
|
15216
|
+
return { kind: "state-updated" };
|
|
15217
|
+
} catch (error) {
|
|
15218
|
+
const message = error instanceof Error ? error.message : "Booking failed";
|
|
15219
|
+
setErrorMessage(message);
|
|
15220
|
+
setStep("error");
|
|
15221
|
+
return {
|
|
15222
|
+
kind: "failed",
|
|
15223
|
+
message
|
|
15224
|
+
};
|
|
15225
|
+
}
|
|
15226
|
+
};
|
|
15227
|
+
const handlePaymentContinue = async () => {
|
|
15228
|
+
if (!selectedCourse) return {
|
|
15229
|
+
kind: "blocked",
|
|
15230
|
+
message: "Choose an available set of dates to continue."
|
|
15231
|
+
};
|
|
15232
|
+
if (!handleValidateForm()) return { kind: "validation-failed" };
|
|
15233
|
+
if (missingPricingSelectionMessage) {
|
|
15234
|
+
setErrorMessage(missingPricingSelectionMessage);
|
|
15235
|
+
setStep("error");
|
|
15236
|
+
return {
|
|
15237
|
+
kind: "blocked",
|
|
15238
|
+
message: missingPricingSelectionMessage
|
|
15239
|
+
};
|
|
15240
|
+
}
|
|
15241
|
+
const requiresPayment = selectedCoursePricing?.selectedRequiresPayment ?? false;
|
|
15242
|
+
if (!waitlistClaim.claim && courseEligibility?.isFull && !courseEligibility.canJoinWaitlist && showSoldOutCourseError()) return {
|
|
15243
|
+
kind: "blocked",
|
|
15244
|
+
message: courseEligibility.reason ?? "This course is fully booked."
|
|
15245
|
+
};
|
|
15246
|
+
if (!requiresPayment) {
|
|
15247
|
+
setStep("enter-details");
|
|
15248
|
+
return { kind: "state-updated" };
|
|
15249
|
+
}
|
|
15250
|
+
if (showSpamProtection && !altchaSolution) {
|
|
15251
|
+
const message = "Please complete the verification check.";
|
|
15252
|
+
setErrorMessage(message);
|
|
15253
|
+
setStep("error");
|
|
15254
|
+
return {
|
|
15255
|
+
kind: "blocked",
|
|
15256
|
+
message
|
|
15257
|
+
};
|
|
15258
|
+
}
|
|
15259
|
+
if (paymentChoice === "membership") {
|
|
15260
|
+
if (!selectedMembershipId) {
|
|
15261
|
+
const message = "Select a membership to sign up.";
|
|
15262
|
+
setErrorMessage(message);
|
|
15263
|
+
setStep("error");
|
|
15264
|
+
return {
|
|
15265
|
+
kind: "blocked",
|
|
15266
|
+
message
|
|
15267
|
+
};
|
|
15268
|
+
}
|
|
15269
|
+
setStep("submitting");
|
|
15270
|
+
try {
|
|
15271
|
+
const result = await api.enrollInCourse({
|
|
15272
|
+
courseId: selectedCourse.id,
|
|
15273
|
+
...selectedCoursePricingPayload,
|
|
15274
|
+
email: formData.email.trim().toLowerCase(),
|
|
15275
|
+
name: formData.name.trim(),
|
|
15276
|
+
phone: formData.phone.trim() || void 0,
|
|
15277
|
+
formData: { notes: formData.notes.trim() || void 0 },
|
|
15278
|
+
altchaSolution,
|
|
15279
|
+
paymentMethod: "membership",
|
|
15280
|
+
customerMembershipId: selectedMembershipId,
|
|
15281
|
+
claimToken: waitlistClaim.token ?? void 0
|
|
15282
|
+
});
|
|
15283
|
+
setEnrollmentResult({
|
|
15284
|
+
status: result.status,
|
|
15285
|
+
waitlistPosition: result.waitlistPosition ?? void 0,
|
|
15286
|
+
usedMembership: true
|
|
15287
|
+
});
|
|
15288
|
+
setStep(result.status === "waitlist" ? "waitlist" : "success");
|
|
15289
|
+
return { kind: "state-updated" };
|
|
15290
|
+
} catch (error) {
|
|
15291
|
+
const message = error instanceof Error ? error.message : "Booking failed";
|
|
15292
|
+
setErrorMessage(message);
|
|
15293
|
+
setStep("error");
|
|
15294
|
+
return {
|
|
15295
|
+
kind: "failed",
|
|
15296
|
+
message
|
|
15297
|
+
};
|
|
15298
|
+
}
|
|
15299
|
+
}
|
|
15300
|
+
setStep("submitting");
|
|
15301
|
+
try {
|
|
15302
|
+
const { successUrl, cancelUrl } = buildCheckoutReturnUrls("enrollment", COURSE_REGISTRATION_ANCHOR_ID);
|
|
15303
|
+
const checkoutResult = await api.createCourseCheckout({
|
|
15304
|
+
courseId: selectedCourse.id,
|
|
15305
|
+
...selectedCoursePricingPayload,
|
|
15306
|
+
email: formData.email.trim().toLowerCase(),
|
|
15307
|
+
name: formData.name.trim(),
|
|
15308
|
+
phone: formData.phone.trim() || void 0,
|
|
15309
|
+
formData: { notes: formData.notes.trim() || void 0 },
|
|
15310
|
+
altchaSolution,
|
|
15311
|
+
discountCode: discountCode.trim() ? discountCode.trim() : void 0,
|
|
15312
|
+
successUrl,
|
|
15313
|
+
cancelUrl,
|
|
15314
|
+
claimToken: waitlistClaim.token ?? void 0
|
|
15315
|
+
});
|
|
15316
|
+
if (checkoutResult.bypassed) {
|
|
15317
|
+
setEnrollmentResult({
|
|
15318
|
+
status: "enrolled",
|
|
15319
|
+
waitlistPosition: void 0,
|
|
15320
|
+
usedMembership: false
|
|
15321
|
+
});
|
|
15322
|
+
setStep("success");
|
|
15323
|
+
return { kind: "state-updated" };
|
|
15324
|
+
}
|
|
15325
|
+
if (!checkoutResult.checkoutUrl) throw new Error("Checkout URL missing");
|
|
15326
|
+
setStep("redirecting");
|
|
15327
|
+
if (options.onCheckoutRedirect) options.onCheckoutRedirect(checkoutResult.checkoutUrl);
|
|
15328
|
+
else window.location.href = checkoutResult.checkoutUrl;
|
|
15329
|
+
return {
|
|
15330
|
+
kind: "checkout-redirect",
|
|
15331
|
+
checkoutUrl: checkoutResult.checkoutUrl
|
|
15332
|
+
};
|
|
15333
|
+
} catch (error) {
|
|
15334
|
+
const message = error instanceof Error ? error.message : "Checkout failed";
|
|
15335
|
+
setErrorMessage(message);
|
|
15336
|
+
setStep("error");
|
|
15337
|
+
return {
|
|
15338
|
+
kind: "failed",
|
|
15339
|
+
message
|
|
15340
|
+
};
|
|
15341
|
+
}
|
|
15342
|
+
};
|
|
15343
|
+
const handleRetry = () => {
|
|
15344
|
+
setStep(scopedCourses.length === 1 ? "enter-details" : "select-course");
|
|
15345
|
+
setErrorMessage("");
|
|
15346
|
+
};
|
|
15347
|
+
const handleBookingModeChange = (mode) => {
|
|
15348
|
+
setBookingMode(mode);
|
|
15349
|
+
if (mode === "membership") setPaymentChoice("membership");
|
|
15350
|
+
else setPaymentChoice("checkout");
|
|
15351
|
+
};
|
|
15352
|
+
const discountUi = useDiscountCodeUi({
|
|
15353
|
+
api,
|
|
15354
|
+
discountContext: useMemo(() => {
|
|
15355
|
+
if (!selectedCourse) return null;
|
|
15356
|
+
if (!selectedCoursePricing?.selectedRequiresPayment) return null;
|
|
15357
|
+
if (paymentChoice !== "checkout") return null;
|
|
15358
|
+
return {
|
|
15359
|
+
type: "course",
|
|
15360
|
+
courseId: selectedCourse.id
|
|
15361
|
+
};
|
|
15362
|
+
}, [
|
|
15363
|
+
selectedCourse,
|
|
15364
|
+
selectedCoursePricing?.selectedRequiresPayment,
|
|
15365
|
+
paymentChoice
|
|
15366
|
+
]),
|
|
15367
|
+
subtotalCents: selectedCoursePricing?.selectedPriceAmount ?? void 0
|
|
15368
|
+
});
|
|
15369
|
+
const discountCode = discountUi.discountCode;
|
|
15370
|
+
const hasCoursePayment = resolveHasCoursePayment(selectedCoursePricing);
|
|
15371
|
+
const canUseMembership = hasCoursePayment && selectedCourse?.acceptsMemberships === true && portalAuthState === "authenticated" && eligibleMemberships.length > 0;
|
|
15372
|
+
const hasPreSelectedCourse = scopedCourses.length === 1;
|
|
15373
|
+
const isMembershipFastTrack = canUseMembership && eligibleMemberships.length === 1 && bookingMode === "membership";
|
|
15374
|
+
const wizardSteps = useMemo(() => getWizardStepsForContext(hasPreSelectedCourse, hasCoursePayment, canUseMembership, bookingMode, isMembershipFastTrack), [
|
|
15375
|
+
hasPreSelectedCourse,
|
|
15376
|
+
hasCoursePayment,
|
|
15377
|
+
canUseMembership,
|
|
15378
|
+
bookingMode,
|
|
15379
|
+
isMembershipFastTrack
|
|
15380
|
+
]);
|
|
15381
|
+
const currentStepNumber = getStepNumber(step, wizardSteps);
|
|
15382
|
+
const totalSteps = wizardSteps.length;
|
|
15383
|
+
const stepLabels = getStepLabels(wizardSteps);
|
|
15384
|
+
const canShowPortalAuthSidebarOnCurrentStep = step !== "success" && step !== "waitlist" && step !== "error";
|
|
15385
|
+
const showPortalAuthSidebar = portalAuthState === "unauthenticated" && waitlistClaim.requiresPortalLogin && canShowPortalAuthSidebarOnCurrentStep || portalAuthState === "unauthenticated" && hasCoursePayment && selectedCourse?.acceptsMemberships === true && step !== "select-course" && canShowPortalAuthSidebarOnCurrentStep;
|
|
15386
|
+
return {
|
|
15387
|
+
api,
|
|
15388
|
+
scopedCourses,
|
|
15389
|
+
step,
|
|
15390
|
+
setStep,
|
|
15391
|
+
selectedCourse,
|
|
15392
|
+
selectedPricingOptionId,
|
|
15393
|
+
setSelectedPricingOptionId,
|
|
15394
|
+
selectedSlidingAmountInput,
|
|
15395
|
+
setSelectedSlidingAmountInput,
|
|
15396
|
+
selectedCoursePricing,
|
|
15397
|
+
setSelectedCourse,
|
|
15398
|
+
formData,
|
|
15399
|
+
setFormData,
|
|
15400
|
+
errors,
|
|
15401
|
+
enrollmentResult,
|
|
15402
|
+
errorMessage,
|
|
15403
|
+
portalAuthState,
|
|
15404
|
+
handleLogout: portalAuthState === "authenticated" ? () => logoutPortal(COURSE_REGISTRATION_ANCHOR_ID) : void 0,
|
|
15405
|
+
altchaSolution,
|
|
15406
|
+
setAltchaSolution,
|
|
15407
|
+
showSpamProtection,
|
|
15408
|
+
eligibilityLoading,
|
|
15409
|
+
eligibilityError,
|
|
15410
|
+
courseEligibility,
|
|
15411
|
+
eligibleMemberships,
|
|
15412
|
+
paymentChoice,
|
|
15413
|
+
setPaymentChoice,
|
|
15414
|
+
selectedMembershipId,
|
|
15415
|
+
setSelectedMembershipId,
|
|
15416
|
+
discountUiOpen: discountUi.discountUiOpen,
|
|
15417
|
+
setDiscountUiOpen: discountUi.setDiscountUiOpen,
|
|
15418
|
+
discountCode: discountUi.discountCode,
|
|
15419
|
+
setDiscountCode: discountUi.setDiscountCode,
|
|
15420
|
+
discountsAvailable: discountUi.discountsAvailable,
|
|
15421
|
+
manualCodeEntryAllowed: discountUi.manualCodeEntryAllowed,
|
|
15422
|
+
discountsAvailableLoading: discountUi.discountsAvailableLoading,
|
|
15423
|
+
canUseMembership,
|
|
15424
|
+
waitlistClaim,
|
|
15425
|
+
bookingMode,
|
|
15426
|
+
wizardSteps,
|
|
15427
|
+
currentStepNumber,
|
|
15428
|
+
totalSteps,
|
|
15429
|
+
stepLabels,
|
|
15430
|
+
showPortalAuthSidebar,
|
|
15431
|
+
hasPreSelectedCourse,
|
|
15432
|
+
hasCoursePayment,
|
|
15433
|
+
handleCourseSelect,
|
|
15434
|
+
handleSubmit,
|
|
15435
|
+
handlePaymentContinue,
|
|
15436
|
+
handleRetry,
|
|
15437
|
+
handleBookingModeChange
|
|
15438
|
+
};
|
|
15439
|
+
}
|
|
15440
|
+
//#endregion
|
|
15441
|
+
//#region ../blocks/src/system/runtime/nodes/course-registration/whole-series-registration.headless.planning.ts
|
|
15442
|
+
const STEP_IDS = {
|
|
15443
|
+
"select-course": "select-run",
|
|
15444
|
+
"enter-details": "enter-details",
|
|
15445
|
+
"booking-mode": "select-booking-method",
|
|
15446
|
+
"select-payment": "select-payment"
|
|
15447
|
+
};
|
|
15448
|
+
function toPublicStepId(step) {
|
|
15449
|
+
switch (step) {
|
|
15450
|
+
case "select-course":
|
|
15451
|
+
case "enter-details":
|
|
15452
|
+
case "booking-mode":
|
|
15453
|
+
case "select-payment": return STEP_IDS[step];
|
|
15454
|
+
case "submitting":
|
|
15455
|
+
case "redirecting":
|
|
15456
|
+
case "verifying-payment":
|
|
15457
|
+
case "verifying-timeout":
|
|
15458
|
+
case "payment-failed":
|
|
15459
|
+
case "success":
|
|
15460
|
+
case "waitlist":
|
|
15461
|
+
case "error": return null;
|
|
15462
|
+
}
|
|
15463
|
+
}
|
|
15464
|
+
function deriveWholeSeriesRegistrationSteps(input) {
|
|
15465
|
+
const currentId = toPublicStepId(input.step);
|
|
15466
|
+
const currentIndex = currentId ? input.wizardSteps.findIndex((step) => toPublicStepId(step) === currentId) : input.step === "success" || input.step === "waitlist" ? input.wizardSteps.length : -1;
|
|
15467
|
+
return input.wizardSteps.flatMap((step, index) => {
|
|
15468
|
+
const id = toPublicStepId(step);
|
|
15469
|
+
if (!id) return [];
|
|
15470
|
+
const state = index < currentIndex ? "complete" : index === currentIndex ? "active" : currentIndex >= 0 ? "available" : "blocked";
|
|
15471
|
+
return [{
|
|
15472
|
+
id,
|
|
15473
|
+
state,
|
|
15474
|
+
index,
|
|
15475
|
+
canEnter: state === "active" || state === "complete"
|
|
15476
|
+
}];
|
|
15477
|
+
});
|
|
15478
|
+
}
|
|
15479
|
+
function resolveWholeSeriesRegistrationStatus(wizard) {
|
|
15480
|
+
switch (wizard.step) {
|
|
15481
|
+
case "submitting": return { tag: "submitting" };
|
|
15482
|
+
case "redirecting": return { tag: "redirecting" };
|
|
15483
|
+
case "verifying-payment": return { tag: "verifying-payment" };
|
|
15484
|
+
case "verifying-timeout": return {
|
|
15485
|
+
tag: "verifying-timeout",
|
|
15486
|
+
message: wizard.errorMessage
|
|
15487
|
+
};
|
|
15488
|
+
case "payment-failed": return {
|
|
15489
|
+
tag: "payment-failed",
|
|
15490
|
+
message: wizard.errorMessage
|
|
15491
|
+
};
|
|
15492
|
+
case "success": return wizard.enrollmentResult ? {
|
|
15493
|
+
tag: "success",
|
|
15494
|
+
result: wizard.enrollmentResult
|
|
15495
|
+
} : {
|
|
15496
|
+
tag: "error",
|
|
15497
|
+
message: "Registration completed without a result."
|
|
15498
|
+
};
|
|
15499
|
+
case "waitlist": return wizard.enrollmentResult ? {
|
|
15500
|
+
tag: "waitlist",
|
|
15501
|
+
result: wizard.enrollmentResult
|
|
15502
|
+
} : {
|
|
15503
|
+
tag: "error",
|
|
15504
|
+
message: "Waitlist registration completed without a result."
|
|
15505
|
+
};
|
|
15506
|
+
case "error": return {
|
|
15507
|
+
tag: "error",
|
|
15508
|
+
message: wizard.errorMessage
|
|
15509
|
+
};
|
|
15510
|
+
case "select-course":
|
|
15511
|
+
case "enter-details":
|
|
15512
|
+
case "booking-mode":
|
|
15513
|
+
case "select-payment": return { tag: "ready" };
|
|
15514
|
+
}
|
|
15515
|
+
}
|
|
15516
|
+
function resolveWholeSeriesRegistrationView(wizard) {
|
|
15517
|
+
switch (wizard.step) {
|
|
15518
|
+
case "submitting":
|
|
15519
|
+
case "redirecting":
|
|
15520
|
+
case "verifying-payment": return {
|
|
15521
|
+
kind: "verifying",
|
|
15522
|
+
message: "Completing your sign-up."
|
|
15523
|
+
};
|
|
15524
|
+
case "verifying-timeout":
|
|
15525
|
+
case "payment-failed":
|
|
15526
|
+
case "error": return {
|
|
15527
|
+
kind: "error",
|
|
15528
|
+
message: wizard.errorMessage
|
|
15529
|
+
};
|
|
15530
|
+
case "success": return wizard.enrollmentResult ? {
|
|
15531
|
+
kind: "success",
|
|
15532
|
+
result: wizard.enrollmentResult
|
|
15533
|
+
} : {
|
|
15534
|
+
kind: "error",
|
|
15535
|
+
message: "Registration completed without a result."
|
|
15536
|
+
};
|
|
15537
|
+
case "waitlist": return wizard.enrollmentResult ? {
|
|
15538
|
+
kind: "waitlist",
|
|
15539
|
+
result: wizard.enrollmentResult
|
|
15540
|
+
} : {
|
|
15541
|
+
kind: "error",
|
|
15542
|
+
message: "Waitlist registration completed without a result."
|
|
15543
|
+
};
|
|
15544
|
+
case "select-course":
|
|
15545
|
+
case "enter-details":
|
|
15546
|
+
case "booking-mode":
|
|
15547
|
+
case "select-payment":
|
|
15548
|
+
if (wizard.scopedRunsCount === 0) return {
|
|
15549
|
+
kind: "empty",
|
|
15550
|
+
message: "There are no dates available to sign up for."
|
|
15551
|
+
};
|
|
15552
|
+
if (wizard.selectedRun && !wizard.selectedRun.enrollmentOpen) return {
|
|
15553
|
+
kind: "unavailable",
|
|
15554
|
+
message: "Sign-up is closed."
|
|
15555
|
+
};
|
|
15556
|
+
return { kind: "form" };
|
|
15557
|
+
}
|
|
15558
|
+
}
|
|
15559
|
+
function resolveWholeSeriesPricingSelection(pricing) {
|
|
15560
|
+
if (!pricing) return { tag: "not-required" };
|
|
15561
|
+
if (pricing.display.kind === "unavailable") return { tag: "unavailable" };
|
|
15562
|
+
if (pricing.slidingScale && pricing.selectedSlidingAmount !== null) {
|
|
15563
|
+
if (pricing.selectedSlidingAmount < pricing.slidingScale.minAmount || pricing.selectedSlidingAmount > pricing.slidingScale.maxAmount) return {
|
|
15564
|
+
tag: "invalid",
|
|
15565
|
+
message: "Choose an amount within the available range."
|
|
15566
|
+
};
|
|
15567
|
+
}
|
|
15568
|
+
if (pricing.requiresSelection && !pricing.selectedOption && pricing.selectedSlidingAmount === null) return { tag: "required" };
|
|
15569
|
+
return pricing.requiresSelection || pricing.selectedOption || pricing.selectedSlidingAmount !== null ? { tag: "valid" } : { tag: "not-required" };
|
|
15570
|
+
}
|
|
15571
|
+
function resolveWholeSeriesPaymentSelection(input) {
|
|
15572
|
+
if (!input.required) return { method: "none" };
|
|
15573
|
+
if (input.paymentChoice === "membership") return {
|
|
15574
|
+
method: "membership",
|
|
15575
|
+
membershipId: input.selectedMembershipId
|
|
15576
|
+
};
|
|
15577
|
+
return { method: "card" };
|
|
15578
|
+
}
|
|
15579
|
+
//#endregion
|
|
15580
|
+
//#region ../blocks/src/system/runtime/hooks/useHeadlessWholeSeriesRegistrationFlow.ts
|
|
15581
|
+
const wholeSeriesRegistrationControllerDeps = { useCourseRegistrationWizard };
|
|
15582
|
+
function createWholeSeriesRegistrationBlockApiConfig(input) {
|
|
15583
|
+
return {
|
|
15584
|
+
baseUrl: input.apiBaseUrl,
|
|
15585
|
+
auth: input.previewToken ? {
|
|
15586
|
+
type: "bearer",
|
|
15587
|
+
token: input.previewToken
|
|
15588
|
+
} : { type: "none" },
|
|
15589
|
+
siteId: input.siteId,
|
|
15590
|
+
isPreview: input.stage === "preview",
|
|
15591
|
+
...input.portalToken ? { authOverrides: { portal: {
|
|
15592
|
+
type: "bearer",
|
|
15593
|
+
token: input.portalToken
|
|
15594
|
+
} } } : {}
|
|
15595
|
+
};
|
|
15596
|
+
}
|
|
15597
|
+
function HeadlessWholeSeriesRegistrationProvider$1({ config, children }) {
|
|
15598
|
+
return React.createElement(BlockApiProvider, {
|
|
15599
|
+
config,
|
|
15600
|
+
children
|
|
15601
|
+
});
|
|
15602
|
+
}
|
|
15603
|
+
function useHeadlessWholeSeriesRegistrationFlow(options) {
|
|
15604
|
+
return useWholeSeriesRegistrationControllerWithDeps(options, wholeSeriesRegistrationControllerDeps);
|
|
15605
|
+
}
|
|
15606
|
+
function useWholeSeriesRegistrationControllerWithDeps(options, deps) {
|
|
15607
|
+
const wizard = deps.useCourseRegistrationWizard({
|
|
15608
|
+
courses: (options.runs ?? []).map(toPublicCourse),
|
|
15609
|
+
contentEntry: options.contentEntry ?? null,
|
|
15610
|
+
subject: options.subject ?? null
|
|
15611
|
+
}, { onCheckoutRedirect: () => {} });
|
|
15612
|
+
const steps = useMemo(() => deriveWholeSeriesRegistrationSteps({
|
|
15613
|
+
wizardSteps: wizard.wizardSteps,
|
|
15614
|
+
step: wizard.step
|
|
15615
|
+
}), [wizard.step, wizard.wizardSteps]);
|
|
15616
|
+
const currentStep = steps.find((step) => step.state === "active") ?? null;
|
|
15617
|
+
const pricingSelection = resolveWholeSeriesPricingSelection(wizard.selectedCoursePricing);
|
|
15618
|
+
const paymentSelection = resolveWholeSeriesPaymentSelection({
|
|
15619
|
+
paymentChoice: wizard.paymentChoice,
|
|
15620
|
+
selectedMembershipId: wizard.selectedMembershipId,
|
|
15621
|
+
required: wizard.selectedCoursePricing?.selectedRequiresPayment ?? false
|
|
15622
|
+
});
|
|
15623
|
+
const updateRegistrant = useCallback((values) => wizard.setFormData(values), [wizard]);
|
|
15624
|
+
const setSlidingAmountCents = useCallback((amount) => {
|
|
15625
|
+
wizard.setSelectedSlidingAmountInput(amount === null || !Number.isFinite(amount) || amount < 0 ? "" : String(amount / 100));
|
|
15626
|
+
}, [wizard]);
|
|
15627
|
+
const selectPayment = useCallback((selection) => {
|
|
15628
|
+
switch (selection.method) {
|
|
15629
|
+
case "none":
|
|
15630
|
+
wizard.handleBookingModeChange(null);
|
|
15631
|
+
wizard.setSelectedMembershipId(null);
|
|
15632
|
+
return;
|
|
15633
|
+
case "card":
|
|
15634
|
+
wizard.handleBookingModeChange("card");
|
|
15635
|
+
wizard.setSelectedMembershipId(null);
|
|
15636
|
+
return;
|
|
15637
|
+
case "membership":
|
|
15638
|
+
wizard.handleBookingModeChange("membership");
|
|
15639
|
+
wizard.setSelectedMembershipId(selection.membershipId);
|
|
15640
|
+
return;
|
|
15641
|
+
}
|
|
15642
|
+
}, [wizard]);
|
|
15643
|
+
const runCurrentAction = useCallback(async () => {
|
|
15644
|
+
const blocked = resolveActionBlocker(wizard);
|
|
15645
|
+
if (blocked) return blocked;
|
|
15646
|
+
switch (wizard.step) {
|
|
15647
|
+
case "select-course":
|
|
15648
|
+
if (!wizard.selectedCourse) return {
|
|
14141
15649
|
ok: false,
|
|
14142
15650
|
reason: "blocked",
|
|
14143
|
-
message: "Choose
|
|
15651
|
+
message: "Choose an available set of dates to continue."
|
|
14144
15652
|
};
|
|
14145
15653
|
wizard.setStep("enter-details");
|
|
14146
|
-
return {
|
|
14147
|
-
|
|
14148
|
-
|
|
14149
|
-
return result.ok ? { ok: true } : result;
|
|
14150
|
-
}
|
|
14151
|
-
case "select-payment": {
|
|
14152
|
-
const result = await submit({ redirect: "manual" });
|
|
14153
|
-
return result.ok ? { ok: true } : {
|
|
14154
|
-
ok: false,
|
|
14155
|
-
reason: result.reason === "submission-failed" ? "submission-failed" : "blocked",
|
|
14156
|
-
message: result.message
|
|
15654
|
+
return {
|
|
15655
|
+
ok: true,
|
|
15656
|
+
outcome: { kind: "state-updated" }
|
|
14157
15657
|
};
|
|
14158
|
-
|
|
14159
|
-
case "
|
|
14160
|
-
case "
|
|
15658
|
+
case "enter-details": return toHeadlessActionResult(await wizard.handleSubmit());
|
|
15659
|
+
case "booking-mode":
|
|
15660
|
+
case "select-payment": return toHeadlessActionResult(await wizard.handlePaymentContinue());
|
|
14161
15661
|
case "submitting":
|
|
14162
15662
|
case "redirecting":
|
|
14163
15663
|
case "verifying-payment":
|
|
14164
15664
|
case "verifying-timeout":
|
|
14165
|
-
case "payment-failed":
|
|
15665
|
+
case "payment-failed":
|
|
15666
|
+
case "success":
|
|
15667
|
+
case "waitlist":
|
|
15668
|
+
case "error": return {
|
|
14166
15669
|
ok: false,
|
|
14167
15670
|
reason: "blocked",
|
|
14168
15671
|
message: "This registration step cannot continue."
|
|
14169
15672
|
};
|
|
14170
15673
|
}
|
|
14171
|
-
}, [
|
|
15674
|
+
}, [pricingSelection, wizard]);
|
|
14172
15675
|
const back = useCallback(() => {
|
|
14173
15676
|
switch (wizard.step) {
|
|
14174
15677
|
case "enter-details":
|
|
14175
|
-
wizard.setStep("select-
|
|
15678
|
+
if (!wizard.hasPreSelectedCourse) wizard.setStep("select-course");
|
|
14176
15679
|
return;
|
|
14177
|
-
case "
|
|
15680
|
+
case "booking-mode":
|
|
14178
15681
|
wizard.setStep("enter-details");
|
|
14179
15682
|
return;
|
|
14180
|
-
case "select-
|
|
14181
|
-
|
|
15683
|
+
case "select-payment":
|
|
15684
|
+
wizard.setStep(wizard.canUseMembership ? "booking-mode" : "enter-details");
|
|
14182
15685
|
return;
|
|
14183
|
-
case "select-
|
|
14184
|
-
case "error":
|
|
14185
|
-
case "success":
|
|
15686
|
+
case "select-course":
|
|
14186
15687
|
case "submitting":
|
|
14187
15688
|
case "redirecting":
|
|
14188
15689
|
case "verifying-payment":
|
|
14189
15690
|
case "verifying-timeout":
|
|
14190
|
-
case "payment-failed":
|
|
15691
|
+
case "payment-failed":
|
|
15692
|
+
case "success":
|
|
15693
|
+
case "waitlist":
|
|
15694
|
+
case "error": return;
|
|
14191
15695
|
}
|
|
14192
15696
|
}, [wizard]);
|
|
14193
|
-
const
|
|
14194
|
-
wizard.
|
|
14195
|
-
|
|
14196
|
-
|
|
14197
|
-
wizard.
|
|
14198
|
-
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
const spamProtection =
|
|
15697
|
+
const payment = {
|
|
15698
|
+
required: wizard.selectedCoursePricing?.selectedRequiresPayment ?? false,
|
|
15699
|
+
selection: paymentSelection,
|
|
15700
|
+
canUseMembership: wizard.canUseMembership,
|
|
15701
|
+
eligibleMemberships: wizard.eligibleMemberships.map((membership) => ({
|
|
15702
|
+
id: membership.customerMembershipId,
|
|
15703
|
+
name: membership.membershipName
|
|
15704
|
+
})),
|
|
15705
|
+
eligibility: wizard.eligibilityLoading ? { tag: "loading" } : wizard.eligibilityError ? {
|
|
15706
|
+
tag: "error",
|
|
15707
|
+
message: wizard.eligibilityError
|
|
15708
|
+
} : wizard.courseEligibility || wizard.portalAuthState !== "checking" ? { tag: "loaded" } : { tag: "idle" }
|
|
15709
|
+
};
|
|
15710
|
+
const spamProtection = wizard.showSpamProtection ? {
|
|
14207
15711
|
enabled: true,
|
|
14208
15712
|
provider: "altcha",
|
|
14209
15713
|
challenge: {
|
|
@@ -14212,165 +15716,280 @@ function useEventRegistrationControllerWithDeps(options, deps) {
|
|
|
14212
15716
|
},
|
|
14213
15717
|
solution: wizard.altchaSolution
|
|
14214
15718
|
} : { enabled: false };
|
|
14215
|
-
const
|
|
15719
|
+
const selectedRun = wizard.selectedCourse;
|
|
15720
|
+
const isFull = wizard.courseEligibility?.isFull ?? (selectedRun?.availableSpots !== null && selectedRun?.availableSpots !== void 0 ? selectedRun.availableSpots <= 0 : false);
|
|
14216
15721
|
return {
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
eventRequiresPayment: wizard.eventRequiresPayment,
|
|
14244
|
-
selectedAttendanceMode: wizard.selectedAttendanceMode
|
|
14245
|
-
},
|
|
14246
|
-
attendee: {
|
|
14247
|
-
values: wizard.formData,
|
|
14248
|
-
errors: wizard.errors
|
|
14249
|
-
},
|
|
14250
|
-
guests: {
|
|
14251
|
-
required: wizard.requireGuestDetails,
|
|
14252
|
-
items: wizard.guests,
|
|
14253
|
-
errors: wizard.guestErrors,
|
|
14254
|
-
shake: wizard.guestSectionShake
|
|
14255
|
-
},
|
|
14256
|
-
payment,
|
|
14257
|
-
discount: {
|
|
14258
|
-
code: wizard.discountCode,
|
|
14259
|
-
isOpen: wizard.discountUiOpen,
|
|
14260
|
-
available: wizard.discountsAvailable,
|
|
14261
|
-
manualCodeEntryAllowed: wizard.manualCodeEntryAllowed,
|
|
14262
|
-
loading: wizard.discountsAvailableLoading,
|
|
14263
|
-
autoAppliedDiscount: wizard.autoAppliedDiscount
|
|
14264
|
-
},
|
|
14265
|
-
portalAuth: {
|
|
14266
|
-
state: wizard.portalAuthState,
|
|
14267
|
-
profile: wizard.portalProfile,
|
|
14268
|
-
isAuthenticated: wizard.portalAuthState === "authenticated",
|
|
14269
|
-
showMagicLinkModal: wizard.showMagicLinkModal
|
|
14270
|
-
},
|
|
14271
|
-
existingRegistration: {
|
|
14272
|
-
state: resolveExistingRegistrationState(wizard),
|
|
14273
|
-
registration: wizard.existingRegistration
|
|
14274
|
-
},
|
|
14275
|
-
waitlistClaim: wizard.waitlistClaim,
|
|
14276
|
-
spamProtection,
|
|
14277
|
-
terminal: {
|
|
14278
|
-
result: wizard.registrationResult,
|
|
14279
|
-
errorMessage: wizard.errorMessage,
|
|
14280
|
-
verification: wizard.verification
|
|
14281
|
-
},
|
|
14282
|
-
actions: {
|
|
14283
|
-
selectEvent: wizard.handleEventSelect,
|
|
14284
|
-
selectAttendanceMode: wizard.setSelectedAttendanceMode,
|
|
14285
|
-
selectTicketType: (ticketTypeId) => {
|
|
14286
|
-
wizard.setSelectedTicketLines(ticketTypeId ? [{
|
|
14287
|
-
ticketTypeId,
|
|
14288
|
-
quantity: 1
|
|
14289
|
-
}] : []);
|
|
14290
|
-
},
|
|
14291
|
-
setTicketSelections: wizard.setSelectedTicketLines,
|
|
14292
|
-
setTicketsCount: wizard.setTicketsCount,
|
|
14293
|
-
updateAttendee,
|
|
14294
|
-
updateGuests,
|
|
14295
|
-
selectPayment,
|
|
14296
|
-
setDiscountCode: wizard.setDiscountCode,
|
|
14297
|
-
setDiscountOpen: wizard.setDiscountUiOpen,
|
|
14298
|
-
setAltchaSolution: wizard.setAltchaSolution,
|
|
14299
|
-
requestLogin: () => wizard.setShowMagicLinkModal(true),
|
|
14300
|
-
logout: wizard.handleLogout,
|
|
14301
|
-
next,
|
|
14302
|
-
back,
|
|
14303
|
-
submit,
|
|
14304
|
-
retry: wizard.handleRetry
|
|
14305
|
-
}
|
|
15722
|
+
status: resolveWholeSeriesRegistrationStatus(wizard),
|
|
15723
|
+
view: resolveWholeSeriesRegistrationView({
|
|
15724
|
+
step: wizard.step,
|
|
15725
|
+
scopedRunsCount: wizard.scopedCourses.length,
|
|
15726
|
+
selectedRun,
|
|
15727
|
+
enrollmentResult: wizard.enrollmentResult,
|
|
15728
|
+
errorMessage: wizard.errorMessage
|
|
15729
|
+
}),
|
|
15730
|
+
steps,
|
|
15731
|
+
currentStep,
|
|
15732
|
+
runs: {
|
|
15733
|
+
items: (options.runs ?? []).map((run) => toWholeSeriesRegistrationRun(toPublicCourse(run))),
|
|
15734
|
+
scoped: wizard.scopedCourses.map(toWholeSeriesRegistrationRun),
|
|
15735
|
+
selected: selectedRun ? toWholeSeriesRegistrationRun(selectedRun) : null,
|
|
15736
|
+
hasPreSelectedRun: wizard.hasPreSelectedCourse,
|
|
15737
|
+
contentEntry: options.contentEntry ?? null,
|
|
15738
|
+
subject: options.subject ?? null
|
|
15739
|
+
},
|
|
15740
|
+
registrant: {
|
|
15741
|
+
values: wizard.formData,
|
|
15742
|
+
errors: wizard.errors
|
|
15743
|
+
},
|
|
15744
|
+
pricing: {
|
|
15745
|
+
...toWholeSeriesRegistrationPricing(wizard.selectedCoursePricing),
|
|
15746
|
+
selectedOptionId: wizard.selectedPricingOptionId,
|
|
15747
|
+
selection: pricingSelection
|
|
14306
15748
|
},
|
|
14307
|
-
|
|
14308
|
-
|
|
14309
|
-
|
|
14310
|
-
|
|
14311
|
-
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
|
|
14315
|
-
|
|
14316
|
-
|
|
14317
|
-
|
|
14318
|
-
|
|
15749
|
+
payment,
|
|
15750
|
+
discount: {
|
|
15751
|
+
code: wizard.discountCode,
|
|
15752
|
+
isOpen: wizard.discountUiOpen,
|
|
15753
|
+
available: wizard.discountsAvailable,
|
|
15754
|
+
manualCodeEntryAllowed: wizard.manualCodeEntryAllowed,
|
|
15755
|
+
loading: wizard.discountsAvailableLoading
|
|
15756
|
+
},
|
|
15757
|
+
availability: {
|
|
15758
|
+
enrollmentOpen: selectedRun?.enrollmentOpen ?? false,
|
|
15759
|
+
availableSpots: selectedRun?.availableSpots ?? null,
|
|
15760
|
+
isFull,
|
|
15761
|
+
canJoinWaitlist: wizard.courseEligibility?.canJoinWaitlist ?? false,
|
|
15762
|
+
message: wizard.courseEligibility?.reason ?? null
|
|
15763
|
+
},
|
|
15764
|
+
portalAuth: {
|
|
15765
|
+
state: wizard.portalAuthState,
|
|
15766
|
+
isAuthenticated: wizard.portalAuthState === "authenticated"
|
|
15767
|
+
},
|
|
15768
|
+
waitlistClaim: resolveWaitlistClaim(wizard),
|
|
15769
|
+
spamProtection,
|
|
15770
|
+
terminal: {
|
|
15771
|
+
result: wizard.enrollmentResult,
|
|
15772
|
+
errorMessage: wizard.errorMessage
|
|
15773
|
+
},
|
|
15774
|
+
actions: {
|
|
15775
|
+
selectRun: (runId) => {
|
|
15776
|
+
const run = wizard.scopedCourses.find((candidate) => candidate.seriesId === runId) ?? null;
|
|
15777
|
+
if (run) wizard.handleCourseSelect(run);
|
|
15778
|
+
},
|
|
15779
|
+
updateRegistrant,
|
|
15780
|
+
selectPricingOption: wizard.setSelectedPricingOptionId,
|
|
15781
|
+
setSlidingAmountCents,
|
|
15782
|
+
selectPayment,
|
|
15783
|
+
setDiscountCode: wizard.setDiscountCode,
|
|
15784
|
+
setDiscountOpen: wizard.setDiscountUiOpen,
|
|
15785
|
+
setAltchaSolution: wizard.setAltchaSolution,
|
|
15786
|
+
continue: runCurrentAction,
|
|
15787
|
+
back,
|
|
15788
|
+
submit: runCurrentAction,
|
|
15789
|
+
retry: wizard.handleRetry,
|
|
15790
|
+
logout: () => wizard.handleLogout?.()
|
|
15791
|
+
}
|
|
15792
|
+
};
|
|
15793
|
+
}
|
|
15794
|
+
function toHeadlessActionResult(result) {
|
|
15795
|
+
switch (result.kind) {
|
|
15796
|
+
case "state-updated": return {
|
|
15797
|
+
ok: true,
|
|
15798
|
+
outcome: result
|
|
15799
|
+
};
|
|
15800
|
+
case "checkout-redirect": return {
|
|
15801
|
+
ok: true,
|
|
15802
|
+
outcome: result
|
|
15803
|
+
};
|
|
15804
|
+
case "validation-failed": return {
|
|
15805
|
+
ok: false,
|
|
15806
|
+
reason: "validation-failed",
|
|
15807
|
+
message: "Check the highlighted fields and try again."
|
|
15808
|
+
};
|
|
15809
|
+
case "blocked": return {
|
|
15810
|
+
ok: false,
|
|
15811
|
+
reason: "blocked",
|
|
15812
|
+
message: result.message
|
|
15813
|
+
};
|
|
15814
|
+
case "failed": return {
|
|
15815
|
+
ok: false,
|
|
15816
|
+
reason: "failed",
|
|
15817
|
+
message: result.message
|
|
15818
|
+
};
|
|
15819
|
+
}
|
|
14319
15820
|
}
|
|
14320
|
-
function
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
15821
|
+
function toPublicCourse(run) {
|
|
15822
|
+
const pricing = toCoursePricing(run.pricing);
|
|
15823
|
+
return {
|
|
15824
|
+
id: run.registrationTarget.courseId,
|
|
15825
|
+
seriesId: run.runId,
|
|
15826
|
+
title: run.title,
|
|
15827
|
+
slug: run.slug,
|
|
15828
|
+
description: run.description,
|
|
15829
|
+
teamMembers: run.teamMembers ? [...run.teamMembers] : void 0,
|
|
15830
|
+
enrollmentOpen: run.registrationOpen,
|
|
15831
|
+
pricing,
|
|
15832
|
+
priceCents: run.pricing.pricingStrategy === "single" ? run.pricing.amountCents : null,
|
|
15833
|
+
currency: run.pricing.currency,
|
|
15834
|
+
paymentTerms: run.pricing.paymentTerms,
|
|
15835
|
+
enrollmentCapacity: run.capacity,
|
|
15836
|
+
acceptsMemberships: run.acceptsMemberships,
|
|
15837
|
+
status: run.lifecycleStatus,
|
|
15838
|
+
sessionsCount: run.includedDates.length,
|
|
15839
|
+
enrolledCount: run.registeredCount,
|
|
15840
|
+
availableSpots: run.availableSpots,
|
|
15841
|
+
sessions: run.includedDates.map((date) => ({
|
|
15842
|
+
...date,
|
|
15843
|
+
overrides: date.overrides ? { ...date.overrides } : date.overrides
|
|
15844
|
+
})),
|
|
15845
|
+
venue: run.venue,
|
|
15846
|
+
contentEntryId: run.contentEntryId
|
|
15847
|
+
};
|
|
15848
|
+
}
|
|
15849
|
+
function toCoursePricing(pricing) {
|
|
15850
|
+
const common = {
|
|
15851
|
+
bookingRequirement: pricing.bookingRequirement,
|
|
15852
|
+
pricingStrategy: pricing.pricingStrategy,
|
|
15853
|
+
currency: pricing.currency,
|
|
15854
|
+
paymentTerms: pricing.paymentTerms
|
|
15855
|
+
};
|
|
15856
|
+
switch (pricing.pricingStrategy) {
|
|
15857
|
+
case "free": return {
|
|
15858
|
+
...common,
|
|
15859
|
+
singlePriceAmount: null,
|
|
15860
|
+
options: []
|
|
14325
15861
|
};
|
|
14326
|
-
case "
|
|
14327
|
-
|
|
14328
|
-
|
|
15862
|
+
case "single": return {
|
|
15863
|
+
...common,
|
|
15864
|
+
singlePriceAmount: pricing.amountCents,
|
|
15865
|
+
options: []
|
|
14329
15866
|
};
|
|
14330
|
-
case "
|
|
14331
|
-
|
|
14332
|
-
|
|
15867
|
+
case "tiered": return {
|
|
15868
|
+
...common,
|
|
15869
|
+
singlePriceAmount: null,
|
|
15870
|
+
options: pricing.options
|
|
15871
|
+
};
|
|
15872
|
+
case "sliding_scale": return {
|
|
15873
|
+
...common,
|
|
15874
|
+
singlePriceAmount: null,
|
|
15875
|
+
slidingMinAmount: pricing.minAmountCents,
|
|
15876
|
+
slidingMaxAmount: pricing.maxAmountCents,
|
|
15877
|
+
slidingSuggestedAmount: pricing.suggestedAmountCents,
|
|
15878
|
+
options: []
|
|
14333
15879
|
};
|
|
14334
15880
|
}
|
|
14335
15881
|
}
|
|
14336
|
-
function
|
|
14337
|
-
|
|
14338
|
-
|
|
14339
|
-
|
|
14340
|
-
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
|
|
14344
|
-
|
|
14345
|
-
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14351
|
-
|
|
15882
|
+
function toWholeSeriesRegistrationRun(run) {
|
|
15883
|
+
return {
|
|
15884
|
+
id: run.seriesId,
|
|
15885
|
+
title: run.title,
|
|
15886
|
+
slug: run.slug,
|
|
15887
|
+
description: run.description,
|
|
15888
|
+
registrationOpen: run.enrollmentOpen,
|
|
15889
|
+
capacity: run.enrollmentCapacity,
|
|
15890
|
+
registeredCount: run.enrolledCount,
|
|
15891
|
+
availableSpots: run.availableSpots,
|
|
15892
|
+
includedDates: run.sessions.map((session) => ({
|
|
15893
|
+
id: session.id,
|
|
15894
|
+
startsAt: session.startsAt,
|
|
15895
|
+
endsAt: session.endsAt,
|
|
15896
|
+
timeZone: session.timeZone
|
|
15897
|
+
})),
|
|
15898
|
+
venue: run.venue
|
|
15899
|
+
};
|
|
15900
|
+
}
|
|
15901
|
+
function toWholeSeriesRegistrationPricing(pricing) {
|
|
15902
|
+
if (!pricing) return {
|
|
15903
|
+
currency: null,
|
|
15904
|
+
display: null,
|
|
15905
|
+
options: [],
|
|
15906
|
+
slidingScale: null,
|
|
15907
|
+
selectedAmountCents: null,
|
|
15908
|
+
selectedPriceCents: null,
|
|
15909
|
+
requiresPayment: false
|
|
14352
15910
|
};
|
|
14353
15911
|
return {
|
|
14354
|
-
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
|
|
15912
|
+
currency: pricing.currency,
|
|
15913
|
+
display: toWholeSeriesPriceDisplay(pricing.display),
|
|
15914
|
+
options: pricing.selectableOptions.map((option) => ({
|
|
15915
|
+
id: option.id,
|
|
15916
|
+
name: option.name,
|
|
15917
|
+
description: option.description,
|
|
15918
|
+
amountCents: option.priceAmount
|
|
15919
|
+
})),
|
|
15920
|
+
slidingScale: pricing.slidingScale ? {
|
|
15921
|
+
minAmountCents: pricing.slidingScale.minAmount,
|
|
15922
|
+
maxAmountCents: pricing.slidingScale.maxAmount,
|
|
15923
|
+
suggestedAmountCents: pricing.slidingScale.suggestedAmount
|
|
15924
|
+
} : null,
|
|
15925
|
+
selectedAmountCents: pricing.selectedSlidingAmount,
|
|
15926
|
+
selectedPriceCents: pricing.selectedPriceAmount,
|
|
15927
|
+
requiresPayment: pricing.selectedRequiresPayment
|
|
15928
|
+
};
|
|
15929
|
+
}
|
|
15930
|
+
function toWholeSeriesPriceDisplay(display) {
|
|
15931
|
+
switch (display.kind) {
|
|
15932
|
+
case "free": return display;
|
|
15933
|
+
case "exact": return {
|
|
15934
|
+
kind: "exact",
|
|
15935
|
+
amountCents: display.amount,
|
|
15936
|
+
currency: display.currency
|
|
15937
|
+
};
|
|
15938
|
+
case "from": return {
|
|
15939
|
+
kind: "from",
|
|
15940
|
+
amountCents: display.amount,
|
|
15941
|
+
currency: display.currency
|
|
15942
|
+
};
|
|
15943
|
+
case "range": return {
|
|
15944
|
+
kind: "range",
|
|
15945
|
+
minAmountCents: display.minAmount,
|
|
15946
|
+
maxAmountCents: display.maxAmount,
|
|
15947
|
+
currency: display.currency
|
|
15948
|
+
};
|
|
15949
|
+
case "unavailable": return display;
|
|
15950
|
+
}
|
|
15951
|
+
}
|
|
15952
|
+
function resolveWaitlistClaim(wizard) {
|
|
15953
|
+
const waitlistClaim = wizard.waitlistClaim;
|
|
15954
|
+
if (waitlistClaim.isLoading) return { tag: "loading" };
|
|
15955
|
+
if (waitlistClaim.requiresPortalLogin) return {
|
|
15956
|
+
tag: "login-required",
|
|
15957
|
+
message: waitlistClaim.loginMessage ?? "Log in to continue with your waitlist place."
|
|
15958
|
+
};
|
|
15959
|
+
if (waitlistClaim.error) return {
|
|
15960
|
+
tag: "error",
|
|
15961
|
+
message: waitlistClaim.error
|
|
15962
|
+
};
|
|
15963
|
+
if (waitlistClaim.claim) return {
|
|
15964
|
+
tag: "ready",
|
|
15965
|
+
expiresAt: waitlistClaim.claim.expiresAt,
|
|
15966
|
+
prefill: {
|
|
15967
|
+
email: waitlistClaim.claim.prefill.email,
|
|
15968
|
+
name: waitlistClaim.claim.prefill.name,
|
|
15969
|
+
phone: waitlistClaim.claim.prefill.phone,
|
|
15970
|
+
notes: waitlistClaim.claim.prefill.notes
|
|
15971
|
+
}
|
|
14361
15972
|
};
|
|
15973
|
+
return { tag: "none" };
|
|
14362
15974
|
}
|
|
14363
|
-
function
|
|
14364
|
-
|
|
14365
|
-
if (!
|
|
14366
|
-
|
|
14367
|
-
|
|
14368
|
-
|
|
14369
|
-
|
|
14370
|
-
|
|
14371
|
-
|
|
14372
|
-
|
|
14373
|
-
|
|
15975
|
+
function resolveActionBlocker(wizard) {
|
|
15976
|
+
if (!wizard.selectedCourse) return null;
|
|
15977
|
+
if (!wizard.selectedCourse.enrollmentOpen) return {
|
|
15978
|
+
ok: false,
|
|
15979
|
+
reason: "blocked",
|
|
15980
|
+
message: "Sign-up is closed."
|
|
15981
|
+
};
|
|
15982
|
+
if (wizard.eligibilityLoading || wizard.portalAuthState === "checking") return {
|
|
15983
|
+
ok: false,
|
|
15984
|
+
reason: "blocked",
|
|
15985
|
+
message: "Availability is still being checked."
|
|
15986
|
+
};
|
|
15987
|
+
if (wizard.courseEligibility?.isFull && !wizard.courseEligibility.canJoinWaitlist) return {
|
|
15988
|
+
ok: false,
|
|
15989
|
+
reason: "blocked",
|
|
15990
|
+
message: wizard.courseEligibility.reason ?? "There are no places available."
|
|
15991
|
+
};
|
|
15992
|
+
return null;
|
|
14374
15993
|
}
|
|
14375
15994
|
//#endregion
|
|
14376
15995
|
//#region ../blocks/src/system/runtime/hooks/useBookingFormConfig.state.ts
|
|
@@ -14581,8 +16200,11 @@ const HeadlessBookingProvider = (props) => {
|
|
|
14581
16200
|
const HeadlessEventRegistrationProvider = (props) => {
|
|
14582
16201
|
return React$1.createElement(HeadlessEventRegistrationProvider$1, props);
|
|
14583
16202
|
};
|
|
16203
|
+
const HeadlessWholeSeriesRegistrationProvider = (props) => {
|
|
16204
|
+
return React$1.createElement(HeadlessWholeSeriesRegistrationProvider$1, props);
|
|
16205
|
+
};
|
|
14584
16206
|
const HeadlessBookingPaymentSelectionStep = (props) => {
|
|
14585
16207
|
return React$1.createElement(HeadlessBookingPaymentSelectionStep$1, props);
|
|
14586
16208
|
};
|
|
14587
16209
|
//#endregion
|
|
14588
|
-
export { BOOKING_FORM_DATA_RESERVED_KEY_VALUES, BookingFormClient, AltchaWidget as HeadlessBookingAltchaWidget, AltchaWidget as HeadlessEventRegistrationAltchaWidget, HeadlessBookingPaymentSelectionStep, HeadlessBookingProvider, HeadlessEventRegistrationProvider, createBookingBlockApiConfig, createEventRegistrationBlockApiConfig, getAppointmentBookingOverrideInput, getEventRegistrationOverrideInput, useBookingFormConfig, useHeadlessBookingFlow, useHeadlessEventRegistrationFlow };
|
|
16210
|
+
export { BOOKING_FORM_DATA_RESERVED_KEY_VALUES, BookingFormClient, AltchaWidget as HeadlessBookingAltchaWidget, AltchaWidget as HeadlessEventRegistrationAltchaWidget, AltchaWidget as HeadlessWholeSeriesRegistrationAltchaWidget, HeadlessBookingPaymentSelectionStep, HeadlessBookingProvider, HeadlessEventRegistrationProvider, HeadlessWholeSeriesRegistrationProvider, createBookingBlockApiConfig, createEventRegistrationBlockApiConfig, createWholeSeriesRegistrationBlockApiConfig, getAppointmentBookingOverrideInput, getEventRegistrationOverrideInput, useBookingFormConfig, useHeadlessBookingFlow, useHeadlessEventRegistrationFlow, useHeadlessWholeSeriesRegistrationFlow };
|