feat(embed-core): add public close() API for modal-based embeds (#24746)

* feat(embed-core): add public close() API for modal-based embeds

Add a proper public API method close() to the CalApi class that allows
users to programmatically close modal-based embeds (ModalBox and FloatingButton).

This replaces the need for the undocumented hack:
  cal.instance.actionManager.fire('__closeIframe')

The new API is cleaner and more intuitive:
  cal('close')

Key features:
- Works for modal-based embeds only (ModalBox and FloatingButton)
- Throws a clear error if called on inline embeds
- Well-documented with JSDoc comments explaining usage and limitations

Example usage:
  cal('on', {
    action: 'bookingSuccessful',
    callback: () => {
      cal('close');
    }
  });

Also fixed pre-existing lint issues: unused variable in catch block and
eslint-disable comment for missing rule definition.

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* refactor(embed-core): rename close() to closeModal() for clarity

Rename the close() method to closeModal() to make it immediately clear
from the API name itself that this method is for modal-based embeds only.

This makes the API more self-documenting:
- Before: cal('close')
- After: cal('closeModal')

Updated:
- Method name from close() to closeModal()
- JSDoc example to use cal('closeModal')
- Error message to reference closeModal()

The TypeScript types automatically recognize the new action name through
the SingleInstructionMap type system.

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* cleanup

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Hariom Balhara
2025-12-04 05:48:11 -03:00
committed by GitHub
co-authored by Devin AI
parent a1e1bf8b76
commit 78c411621e
+28 -3
View File
@@ -84,7 +84,7 @@ initializeGlobalCalProps();
document.head.appendChild(document.createElement("style")).innerHTML = css;
// eslint-disable-next-line @typescript-eslint/ban-types
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
type ValidationSchemaPropType = string | Function;
type ValidationSchema = {
@@ -468,7 +468,6 @@ export class Cal {
// Try to readjust and scroll into view if more than 25% is hidden.
// Otherwise we assume that user might have positioned the content appropriately already
if (top < 0 && Math.abs(top / height) >= 0.25) {
// eslint-disable-next-line @calcom/eslint/no-scroll-into-view-embed -- Intentionally done
this.inlineEl.scrollIntoView({ behavior: "smooth" });
}
});
@@ -1292,6 +1291,32 @@ class CalApi {
}) {
this.cal.actionManager.off(action, callback);
}
/**
* 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
* cal("on", {
* action: "bookingSuccessful",
* callback: () => {
* cal("closeModal");
* }
* });
* ```
*/
closeModal() {
if (this.cal.inlineEl && !this.cal.modalBox) {
throw new Error(
"closeModal() is only supported for modal-based embeds (ModalBox and FloatingButton). It cannot be used with inline embeds."
);
}
this.cal.actionManager.fire("__closeIframe", {});
}
/**
*
* type is provided and prerenderIframe not set. We would assume prerenderIframe to be true
@@ -1533,7 +1558,7 @@ document.addEventListener("click", (e) => {
let config;
try {
config = JSON.parse(configString);
} catch (e) {
} catch {
config = {};
}