diff --git a/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts b/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts
index 34e7fe4973..529100955d 100644
--- a/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts
+++ b/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts
@@ -321,6 +321,13 @@ test.describe("Popup Tests", () => {
await expect(embedIframe).toBeEmbedCalLink(calNamespace, embeds.getActionFiredDetails, {
pathname: "/free/30min",
});
+
+ if (!embedIframe) {
+ throw new Error("Embed iframe not found");
+ }
+
+ // Verify that event type details are hidden (hideEventTypeDetails: true was set via ui() call)
+ await expect(embedIframe.locator('[data-testid="event-meta"]')).toBeHidden();
});
});
diff --git a/packages/embeds/embed-core/src/embed.ts b/packages/embeds/embed-core/src/embed.ts
index 7dcbcddd18..71bd7a86a0 100644
--- a/packages/embeds/embed-core/src/embed.ts
+++ b/packages/embeds/embed-core/src/embed.ts
@@ -1,33 +1,35 @@
///
-import { FloatingButton } from "./FloatingButton/FloatingButton";
-import { Inline } from "./Inline/inline";
-import { ModalBox } from "./ModalBox/ModalBox";
+
import {
EMBED_MODAL_IFRAME_FORCE_RELOAD_THRESHOLD_MS,
EMBED_MODAL_IFRAME_SLOT_STALE_TIME,
EMBED_MODAL_PRERENDER_PREVENT_THRESHOLD_MS,
} from "./constants";
-import type { InterfaceWithParent, interfaceWithParent } from "./embed-iframe";
import css from "./embed.css?inline";
+import type { InterfaceWithParent, interfaceWithParent } from "./embed-iframe";
+import { FloatingButton } from "./FloatingButton/FloatingButton";
+import { Inline } from "./Inline/inline";
import { getScrollableAncestor } from "./lib/domUtils";
import { getScrollByDistanceHandler } from "./lib/eventHandlers/scrollByDistanceEventHandler";
import {
+ buildConfigWithPrerenderRelatedFields,
fromEntriesWithDuplicateKeys,
- isRouterPath,
generateDataAttributes,
getConfigProp,
+ isRouterPath,
isSameBookingLink,
- buildConfigWithPrerenderRelatedFields,
} from "./lib/utils";
-import { SdkActionManager } from "./sdk-action-manager";
+import { ModalBox } from "./ModalBox/ModalBox";
import type { EventData, EventDataMap } from "./sdk-action-manager";
+import { SdkActionManager } from "./sdk-action-manager";
import tailwindCss from "./tailwindCss";
-import type { UiConfig, EmbedPageType, PrefillAndIframeAttrsConfig, ModalPrerenderOptions } from "./types";
+import type { EmbedPageType, ModalPrerenderOptions, PrefillAndIframeAttrsConfig, UiConfig } from "./types";
import { getMaxHeightForModal } from "./ui-utils";
// Exporting for consumption by @calcom/embed-core user
export type { EmbedEvent } from "./sdk-action-manager";
export type { PrefillAndIframeAttrsConfig } from "./types";
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Rest = T extends [any, ...infer U] ? U : never;
export type Message = {
@@ -177,8 +179,8 @@ type SingleInstructionMap = {
off: ["off", allPossibleCallbacksAndActions];
} & {
[K in Exclude]: CalApi[K] extends (...args: never[]) => void
- ? [K, ...Parameters]
- : never;
+ ? [K, ...Parameters]
+ : never;
};
type SingleInstruction = SingleInstructionMap[keyof SingleInstructionMap];
@@ -231,6 +233,11 @@ export class Cal {
api: CalApi;
+ /**
+ * Commands for which the queue persists across iframe resets
+ */
+ commandsPersistAcrossIframeResets: DoInIframeArg['method'][] = ["ui"];
+
isPrerendering?: boolean;
static actionsManagers: Record;
@@ -361,14 +368,13 @@ export class Cal {
}
// Merge searchParams from config onto the URL which might have query params already
- // @ts-ignore TS2802: URLSearchParams iteration requires downlevelIteration
- for (const [key, value] of searchParams) {
+ searchParams.forEach((value, key) => {
urlInstance.searchParams.append(key, value);
- }
+ });
- // Very Important:Reset iframe ready flag and clear queue, as iframe might load a fresh URL and we need to check when it is ready.
+ // Very Important: Reset iframe ready flag and clear queue, as iframe might load a fresh URL and we need to check correctly when it is ready.
this.iframeReset();
-
+
if (iframe.src === urlInstance.toString()) {
// Ensure reload occurs even if the url is same - Though browser normally does it, but would be better to ensure it
// This param has no other purpose except to ensure forced reload.
@@ -408,7 +414,10 @@ export class Cal {
iframeReset() {
this.iframeReady = false;
- this.iframeDoQueue = [];
+ // Only keep UI related instructions in the queue, as we want to ensure that newly loaded iframe has the same UI configuration applied automatically
+ this.iframeDoQueue = this.iframeDoQueue.filter((doInIframeArg) =>
+ this.commandsPersistAcrossIframeResets.includes(doInIframeArg.method)
+ );
}
constructor(namespace: string, q: Queue) {
@@ -604,7 +613,7 @@ export class Cal {
: 0;
const crossedReloadThreshold = previousEmbedRenderStartTime
? timeSinceLastRender >
- (prerenderOptions?.iframeForceReloadThresholdMs ?? EMBED_MODAL_IFRAME_FORCE_RELOAD_THRESHOLD_MS)
+ (prerenderOptions?.iframeForceReloadThresholdMs ?? EMBED_MODAL_IFRAME_FORCE_RELOAD_THRESHOLD_MS)
: false;
const areSlotsStale = previousEmbedRenderStartTime
@@ -862,7 +871,7 @@ class CalApi {
CalApi.initializedNamespaces.push(this.cal.namespace);
- const { calOrigin: calOrigin, origin: origin, ...restConfig } = config;
+ const { calOrigin, origin, ...restConfig } = config;
this.cal.__config.calOrigin = calOrigin || origin || this.cal.__config.calOrigin;
@@ -950,10 +959,10 @@ class CalApi {
template.innerHTML = `
`;
@@ -1187,7 +1196,7 @@ class CalApi {
config: enrichedConfig,
});
// Send reloadInitiated message to iframe so it can track it
- // Send it after loadInIframe so that new iframe can process it.
+ // Send it after loadInIframe so that new iframe can process it.
this.cal.doInIframe({ method: "__reloadInitiated", arg: {} });
} else if (actionToTake === "connect" || actionToTake === "connect-no-slots-fetch") {
const paramsToAdd = fromEntriesWithDuplicateKeys(calLinkUrlObject.searchParams.entries());
@@ -1196,8 +1205,8 @@ class CalApi {
...enrichedConfig,
...(actionToTake === "connect-no-slots-fetch"
? {
- "cal.embed.noSlotsFetchOnConnect": "true",
- }
+ "cal.embed.noSlotsFetchOnConnect": "true",
+ }
: {}),
},
params: paramsToAdd,
@@ -1239,10 +1248,10 @@ class CalApi {
template.innerHTML = `
`;
this.cal.modalBox = template.content.children[0];
@@ -1303,9 +1312,9 @@ class CalApi {
/**
* Closes modal-based embeds programmatically.
- *
+ *
* @throws {Error} If called on an inline embed (only works for modal-based embeds)
- *
+ *
* @example
* ```javascript
* // Close the modal after a successful booking
@@ -1487,6 +1496,7 @@ class CalApi {
},
});
+
this.cal.doInIframe({ method: "ui", arg: uiConfig });
}
}