From d86e98071a0a42960f5e5cd9cd851ad0db61c990 Mon Sep 17 00:00:00 2001 From: tiagocandido Date: Mon, 28 Sep 2026 17:10:07 +0200 Subject: [PATCH] Show received Universal Checkout events in the sample overlay --- platforms/web/sample/styles.css | 14 +- platforms/web/sample/universal-main.ts | 66 +++- platforms/web/sample/universal.html | 44 ++- .../sample/universal/event-history.test.ts | 212 +++++++++++ .../web/sample/universal/event-history.ts | 346 ++++++++++++++++++ .../web/sample/universal/overlay-view.ts | 200 ++++++++++ platforms/web/sample/universal/overlay.css | 293 +++++++++++++++ .../web/sample/universal/overlay.test.ts | 236 ++++++++++++ platforms/web/sample/universal/overlay.ts | 155 ++++++++ .../sample/universal/source-selection.test.ts | 69 ++++ .../web/sample/universal/source-selection.ts | 106 ++++++ .../web/sample/universal/source-view.test.ts | 55 +++ platforms/web/sample/universal/source-view.ts | 43 +++ 13 files changed, 1836 insertions(+), 3 deletions(-) create mode 100644 platforms/web/sample/universal/event-history.test.ts create mode 100644 platforms/web/sample/universal/event-history.ts create mode 100644 platforms/web/sample/universal/overlay-view.ts create mode 100644 platforms/web/sample/universal/overlay.css create mode 100644 platforms/web/sample/universal/overlay.test.ts create mode 100644 platforms/web/sample/universal/overlay.ts create mode 100644 platforms/web/sample/universal/source-selection.test.ts create mode 100644 platforms/web/sample/universal/source-selection.ts create mode 100644 platforms/web/sample/universal/source-view.test.ts create mode 100644 platforms/web/sample/universal/source-view.ts diff --git a/platforms/web/sample/styles.css b/platforms/web/sample/styles.css index b5c4255aa..13e366293 100644 --- a/platforms/web/sample/styles.css +++ b/platforms/web/sample/styles.css @@ -1264,6 +1264,19 @@ button:disabled { display: none; } +.universal-page .product-scroll { + flex: none; + overflow: visible; +} + +@media (min-width: 1181px) { + .universal-page .workspace { + overflow-y: auto; + scrollbar-gutter: stable; + overscroll-behavior: contain; + } +} + @media (max-width: 1180px) { html.universal-page { height: auto; @@ -1297,7 +1310,6 @@ button:disabled { overflow: visible; } - body.universal-page .product-scroll, body.universal-page .runtime-scroll { overflow: visible; } diff --git a/platforms/web/sample/universal-main.ts b/platforms/web/sample/universal-main.ts index cb19e75bb..b2bfe7387 100644 --- a/platforms/web/sample/universal-main.ts +++ b/platforms/web/sample/universal-main.ts @@ -1,10 +1,19 @@ +import "@shopify/checkout-kit/universal"; + import { normalizeQuantity } from "./cart"; import { createColumnResizer } from "./column-resizer"; -import { setDevelopmentContinuationHost } from "./universal/browser-policy"; +import { $ } from "./dom"; +import { + isConfiguredContinuationUrl, + setDevelopmentContinuationHost, +} from "./universal/browser-policy"; import { loadSampleConfiguration } from "./universal/configuration"; import { createUniversalController } from "./universal/controller"; +import { mountUniversalOverlay } from "./universal/overlay"; import { createSessionPreparationController } from "./universal/preparation"; import { isBuyerCountry, isCheckoutEnvironment } from "./universal/policy"; +import { createSourceSelection } from "./universal/source-selection"; +import { querySourceViewRefs, renderSourceView } from "./universal/source-view"; import { createInitialState, createUniversalStore, @@ -22,9 +31,24 @@ import { queryUniversalRefs, renderUniversalApp, renderUniversalChange } from ". import "./styles.css"; const refs = queryUniversalRefs(); +const sourceRefs = querySourceViewRefs(); const store = createUniversalStore(createInitialState(loadUniversalDisplay())); const controller = createUniversalController({ store }); const preparation = createSessionPreparationController({ store }); +const sourceSelection = createSourceSelection(isConfiguredContinuationUrl); +const overlay = mountUniversalOverlay({ + parent: document.body, + hostLog: $("#event-log"), + hostHeader: $(".events-header"), + hostNotice: refs.runtimeNotice, + validateSource: (value) => + isConfiguredContinuationUrl(value, store.getState().environment) ? value : undefined, + onChange: (snapshot) => { + if (store.getState().runtime.notice !== snapshot.notice) { + controller.setRuntimeNotice(snapshot.notice); + } + }, +}); const resizer = createColumnResizer({ layout: refs.layout, leftPanel: refs.settingsPanel, @@ -37,9 +61,22 @@ const resizer = createColumnResizer({ const unsubscribe = store.subscribe((state, previous) => { renderUniversalChange(refs, state, previous); + syncSelectedSource(); resizer.reposition(); }); +function syncSelectedSource(): void { + const state = store.getState(); + const selected = sourceSelection.select(state.preparation, state.environment); + renderSourceView(sourceRefs, sourceSelection.mode, sourceSelection.pastedDraft, selected); + overlay.configure({ + src: selected.url, + target: state.display.target, + appearance: state.display.appearance, + logLevel: state.display.logLevel, + }); +} + function updateDisplay(partial: Partial): void { const display = { ...store.getState().display, ...partial }; store.update((state) => ({ ...state, display })); @@ -56,6 +93,30 @@ refs.form.addEventListener("submit", (event) => { refs.domainInput.addEventListener("input", controller.clearAddError); +sourceRefs.generatedInput.addEventListener("change", () => { + if (!sourceRefs.generatedInput.checked) return; + sourceSelection.setMode("generated"); + syncSelectedSource(); +}); + +sourceRefs.pastedInput.addEventListener("change", () => { + if (!sourceRefs.pastedInput.checked) return; + sourceSelection.setMode("pasted"); + syncSelectedSource(); + sourceRefs.pastedUrl.focus(); +}); + +sourceRefs.pastedUrl.addEventListener("input", () => { + sourceSelection.setPastedDraft(sourceRefs.pastedUrl.value); + syncSelectedSource(); +}); + +sourceRefs.openButton.addEventListener("click", () => { + const state = store.getState(); + if (!sourceSelection.select(state.preparation, state.environment).ready) return; + overlay.attemptOpen(); +}); + refs.form.addEventListener("change", (event) => { const target = event.target; if (!(target instanceof HTMLSelectElement)) return; @@ -150,6 +211,7 @@ refs.shopList.addEventListener("change", (event) => { }); renderUniversalApp(refs, store.getState()); +syncSelectedSource(); resizer.applyWidths(); void loadSampleConfiguration() .then((configuration) => { @@ -158,6 +220,7 @@ void loadSampleConfiguration() if (!store.getState().shops.some((shop) => shop.domain === domain)) controller.addShop(domain); } + syncSelectedSource(); return undefined; }) .catch(() => { @@ -169,6 +232,7 @@ window.addEventListener("resize", resizer.reposition); window.addEventListener("pagehide", (event) => { if (event.persisted) return; unsubscribe(); + overlay.dispose(); controller.dispose(); preparation.dispose(); window.removeEventListener("resize", resizer.reposition); diff --git a/platforms/web/sample/universal.html b/platforms/web/sample/universal.html index fa8a3d64d..723beb20b 100644 --- a/platforms/web/sample/universal.html +++ b/platforms/web/sample/universal.html @@ -77,7 +77,7 @@

Settings

target