Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 16 additions & 46 deletions src/EmbeddedWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class EmbeddedWidget {
}

private initialize(hideButton = false): void {
// Add font import
// Add font import for button
const fontLink = document.createElement("link");
fontLink.rel = "stylesheet";
fontLink.href = "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap";
Expand All @@ -68,18 +68,16 @@ export class EmbeddedWidget {
padding: 0;
border: none;
border-radius: 10px;
box-shadow: 0 10px 19px hsla(241, 51%, 20%, 16%);
max-width: 90vw;
max-height: 90vh;
width: 1200px;
height: 800px;
background: white;
font-family: Inter, Helvetica, Arial, sans-serif;
width: 500px;
height: 722px;
background: none;
position: relative;
overflow: hidden;
}

.airbyte-widget-dialog::backdrop {
background: hsla(241, 51%, 20%, 50%);
backdrop-filter: blur(4px);
background-color: hsl(241, 51%, 20%);
opacity: 60%;
}

.airbyte-widget-button {
Expand Down Expand Up @@ -113,33 +111,6 @@ export class EmbeddedWidget {
.airbyte-widget-button:focus-visible {
outline: 3px solid hsl(240, 100%, 98%);
}

.airbyte-widget-iframe {
width: 100%;
height: 100%;
border: none;
border-radius: 10px;
}

.airbyte-widget-close {
position: absolute;
top: 16px;
right: 16px;
background-color: transparent;
color: hsl(240, 13%, 72%);
box-shadow: none;
padding: 0;
height: 32px;
}

.airbyte-widget-close:hover {
color: hsl(240, 10%, 59%);
background-color: transparent;
}

.airbyte-widget-close:active {
color: hsl(240, 10%, 59%);
}
`;
document.head.appendChild(style);

Expand All @@ -148,11 +119,12 @@ export class EmbeddedWidget {
this.dialog.classList.add("airbyte-widget-dialog");

// Create iframe

this.iframe.setAttribute("src", this.decodedToken.widgetUrl);
this.iframe.setAttribute("frameborder", "0");
this.iframe.setAttribute("allow", "fullscreen");
this.iframe.classList.add("airbyte-widget-iframe");
this.iframe.style.width = "100%";
this.iframe.style.height = "100%";
this.iframe.style.border = "none";
this.dialog.appendChild(this.iframe);

// Listen for messages from the iframe
Expand Down Expand Up @@ -182,6 +154,11 @@ export class EmbeddedWidget {
}
}

// Handle close dialog message from the webapp
if (event.data && event.data === "CLOSE_DIALOG") {
this.dialog.close();
}

// Pass the event to the callback if provided
if (this.onEvent && event.data && event.data.type) {
this.onEvent(event.data as WidgetEvent);
Expand All @@ -197,13 +174,6 @@ export class EmbeddedWidget {
document.body.appendChild(button);
}

// Add close button to dialog
const closeButton = document.createElement("button");
closeButton.textContent = "Close";
closeButton.classList.add("airbyte-widget-button", "airbyte-widget-close");
closeButton.addEventListener("click", () => this.dialog.close());
this.dialog.appendChild(closeButton);

// Add dialog to document
document.body.appendChild(this.dialog);
}
Expand Down
43 changes: 20 additions & 23 deletions tests/EmbeddedWidget.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ describe("EmbeddedWidget", () => {
let mockShowModal: jest.Mock;
let mockClose: jest.Mock;
let mockButton: HTMLButtonElement;
let mockCloseButton: HTMLButtonElement;
let mockIframe: HTMLIFrameElement;
let originalCreateElement: typeof document.createElement;
let buttonCount = 0;

/**
* The tests below are minimal due to limitations in jsdom's implementation of:
Expand All @@ -25,9 +23,6 @@ describe("EmbeddedWidget", () => {
*/

beforeEach(() => {
// Reset button count
buttonCount = 0;

// Store original createElement
originalCreateElement = document.createElement;

Expand All @@ -53,15 +48,6 @@ describe("EmbeddedWidget", () => {
}
});

mockCloseButton = originalCreateElement.call(document, "button");
mockCloseButton.textContent = "Close";
mockCloseButton.classList.add("airbyte-widget-button", "airbyte-widget-close");
mockCloseButton.addEventListener = jest.fn((event, handler: EventListener) => {
if (event === "click") {
mockCloseButton.onclick = handler as (ev: MouseEvent) => any;
}
});

mockIframe = {
...originalCreateElement.call(document, "iframe"),
addEventListener: jest.fn((event, handler: EventListener) => {
Expand All @@ -85,19 +71,24 @@ describe("EmbeddedWidget", () => {
src: "https://foo.airbyte.com/embedded-widget&workspaceId=foo&allowedOrigin=https%3A%2F%2Flocalhost%3A3003",
frameBorder: "0",
allow: "fullscreen",
style: {
width: "",
height: "",
border: "",
},
classList: {
add: jest.fn(),
contains: jest.fn().mockReturnValue(true),
contains: jest.fn((className) => {
if (className === "airbyte-widget-iframe") return true;
return false;
}),
},
} as unknown as HTMLIFrameElement;

// Mock document.createElement
document.createElement = jest.fn((tagName: string) => {
if (tagName === "dialog") return mockDialog;
if (tagName === "button") {
buttonCount++;
return buttonCount === 1 ? mockButton : mockCloseButton;
}
if (tagName === "button") return mockButton;
if (tagName === "iframe") return mockIframe;
return originalCreateElement.call(document, tagName);
});
Expand All @@ -111,7 +102,6 @@ describe("EmbeddedWidget", () => {
// Mock querySelector
jest.spyOn(document, "querySelector").mockImplementation((selector: string) => {
if (selector === "button") return mockButton;
if (selector === "button.airbyte-widget-close") return mockCloseButton;
if (selector === "iframe") return mockIframe;
return null;
});
Expand Down Expand Up @@ -175,9 +165,16 @@ describe("EmbeddedWidget", () => {
expect(mockShowModal).toHaveBeenCalled();
});

test("closes dialog when close button is clicked", () => {
const closeButton = document.querySelector("button.airbyte-widget-close") as HTMLButtonElement;
closeButton.onclick?.({} as MouseEvent);
test("closes dialog when CLOSE_DIALOG message is received", () => {
// Simulate receiving the CLOSE_DIALOG message
const messageEvent = new MessageEvent("message", {
data: "CLOSE_DIALOG",
origin: "https://foo.airbyte.com",
source: mockIframe.contentWindow as Window,
});
window.dispatchEvent(messageEvent);

// Verify that the dialog's close method was called
expect(mockClose).toHaveBeenCalled();
});
});
Loading