🧑💻 (typebot-js) Implement easier commands: open / close / toggle
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "typebot-js",
|
||||
"version": "2.2.13",
|
||||
"version": "2.2.14",
|
||||
"main": "dist/index.js",
|
||||
"unpkg": "dist/index.global.js",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
|
9
packages/typebot-js/src/commands/close.ts
Normal file
9
packages/typebot-js/src/commands/close.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { closeIframe } from '../embedTypes/chat/iframe'
|
||||
import { closePopup } from '../embedTypes/popup'
|
||||
|
||||
export const close = () => {
|
||||
const existingPopup = document.querySelector('#typebot-popup')
|
||||
if (existingPopup) closePopup(existingPopup)
|
||||
const existingBubble = document.querySelector('#typebot-bubble')
|
||||
if (existingBubble) closeIframe(existingBubble)
|
||||
}
|
6
packages/typebot-js/src/commands/hideMessage.ts
Normal file
6
packages/typebot-js/src/commands/hideMessage.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { closeProactiveMessage } from '../embedTypes/chat/proactiveMessage'
|
||||
|
||||
export const hideMessage = () => {
|
||||
const existingBubble = document.querySelector('#typebot-bubble')
|
||||
if (existingBubble) closeProactiveMessage(existingBubble)
|
||||
}
|
5
packages/typebot-js/src/commands/index.ts
Normal file
5
packages/typebot-js/src/commands/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export * from './close'
|
||||
export * from './hideMessage'
|
||||
export * from './open'
|
||||
export * from './showMessage'
|
||||
export * from './toggle'
|
9
packages/typebot-js/src/commands/open.ts
Normal file
9
packages/typebot-js/src/commands/open.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { openIframe } from '../embedTypes/chat/iframe'
|
||||
import { openPopup } from '../embedTypes/popup'
|
||||
|
||||
export const open = () => {
|
||||
const existingPopup = document.querySelector('#typebot-popup')
|
||||
if (existingPopup) openPopup(existingPopup)
|
||||
const existingBubble = document.querySelector('#typebot-bubble')
|
||||
if (existingBubble) openIframe(existingBubble)
|
||||
}
|
6
packages/typebot-js/src/commands/showMessage.ts
Normal file
6
packages/typebot-js/src/commands/showMessage.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { openProactiveMessage } from '../embedTypes/chat/proactiveMessage'
|
||||
|
||||
export const showMessage = () => {
|
||||
const existingBubble = document.querySelector('#typebot-bubble')
|
||||
if (existingBubble) openProactiveMessage(existingBubble)
|
||||
}
|
20
packages/typebot-js/src/commands/toggle.ts
Normal file
20
packages/typebot-js/src/commands/toggle.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import {
|
||||
closeIframe,
|
||||
isIframeOpened,
|
||||
openIframe,
|
||||
} from '../embedTypes/chat/iframe'
|
||||
import { closePopup, isPopupOpened, openPopup } from '../embedTypes/popup'
|
||||
|
||||
export const toggle = () => {
|
||||
const existingPopup = document.querySelector('#typebot-popup')
|
||||
if (existingPopup)
|
||||
isPopupOpened(existingPopup)
|
||||
? closePopup(existingPopup)
|
||||
: openPopup(existingPopup)
|
||||
const existingBubble = document.querySelector('#typebot-bubble')
|
||||
console.log(existingBubble)
|
||||
if (existingBubble)
|
||||
isIframeOpened(existingBubble)
|
||||
? closeIframe(existingBubble)
|
||||
: openIframe(existingBubble)
|
||||
}
|
@ -9,20 +9,16 @@ export const createIframeContainer = (
|
||||
return iframe
|
||||
}
|
||||
|
||||
export const openIframe = (
|
||||
bubble: HTMLDivElement,
|
||||
iframe: HTMLIFrameElement
|
||||
): void => {
|
||||
export const openIframe = (bubble: Element): void => {
|
||||
const iframe = bubble.querySelector('.typebot-iframe') as HTMLIFrameElement
|
||||
loadTypebotIfFirstOpen(iframe)
|
||||
iframe.style.display = 'flex'
|
||||
setTimeout(() => bubble.classList.add('iframe-opened'), 50)
|
||||
bubble.classList.remove('message-opened')
|
||||
}
|
||||
|
||||
export const closeIframe = (
|
||||
bubble: HTMLDivElement,
|
||||
iframe: HTMLIFrameElement
|
||||
): void => {
|
||||
export const closeIframe = (bubble: Element): void => {
|
||||
const iframe = bubble.querySelector('.typebot-iframe') as HTMLIFrameElement
|
||||
bubble.classList.remove('iframe-opened')
|
||||
setTimeout(() => (iframe.style.display = 'none'), 550)
|
||||
}
|
||||
@ -32,3 +28,6 @@ export const loadTypebotIfFirstOpen = (iframe: HTMLIFrameElement): void => {
|
||||
iframe.src = iframe.dataset.src
|
||||
iframe.removeAttribute('data-src')
|
||||
}
|
||||
|
||||
export const isIframeOpened = (bubble: Element): boolean =>
|
||||
bubble.classList.contains('iframe-opened')
|
||||
|
@ -5,12 +5,7 @@ import {
|
||||
ProactiveMessageParams,
|
||||
} from '../../types'
|
||||
import { createButton } from './button'
|
||||
import {
|
||||
closeIframe,
|
||||
createIframeContainer,
|
||||
loadTypebotIfFirstOpen,
|
||||
openIframe,
|
||||
} from './iframe'
|
||||
import { closeIframe, createIframeContainer, openIframe } from './iframe'
|
||||
import {
|
||||
createProactiveMessage,
|
||||
openProactiveMessage,
|
||||
@ -33,10 +28,7 @@ export const initBubble = (params: BubbleParams): BubbleActions => {
|
||||
!hasBeenClosed()
|
||||
) {
|
||||
setRememberCloseInStorage()
|
||||
setTimeout(
|
||||
() => openIframe(bubbleElement, iframeElement),
|
||||
params.autoOpenDelay
|
||||
)
|
||||
setTimeout(() => openIframe(bubbleElement), params.autoOpenDelay)
|
||||
}
|
||||
!document.body
|
||||
? (window.onload = () => document.body.appendChild(bubbleElement))
|
||||
@ -62,8 +54,8 @@ const createBubble = (
|
||||
const iframeElement = createIframeContainer(params)
|
||||
buttonElement.addEventListener('click', () => {
|
||||
iframeElement.style.display === 'none'
|
||||
? openIframe(bubbleElement, iframeElement)
|
||||
: closeIframe(bubbleElement, iframeElement)
|
||||
? openIframe(bubbleElement)
|
||||
: closeIframe(bubbleElement)
|
||||
})
|
||||
if (proactiveMessageElement)
|
||||
proactiveMessageElement.addEventListener('click', () =>
|
||||
@ -77,9 +69,7 @@ const onProactiveMessageClick = (
|
||||
bubble: HTMLDivElement,
|
||||
iframe: HTMLIFrameElement
|
||||
): void => {
|
||||
iframe.style.display === 'none'
|
||||
? openIframe(bubble, iframe)
|
||||
: closeIframe(bubble, iframe)
|
||||
iframe.style.display === 'none' ? openIframe(bubble) : closeIframe(bubble)
|
||||
bubble.classList.remove('message-opened')
|
||||
}
|
||||
|
||||
@ -107,10 +97,10 @@ export const getBubbleActions = (
|
||||
}
|
||||
: undefined,
|
||||
open: () => {
|
||||
openIframe(existingBubbleElement, existingIframeElement)
|
||||
openIframe(existingBubbleElement)
|
||||
},
|
||||
close: () => {
|
||||
closeIframe(existingBubbleElement, existingIframeElement)
|
||||
closeIframe(existingBubbleElement)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ const createCloseButton = (bubble: HTMLDivElement): HTMLButtonElement => {
|
||||
return button
|
||||
}
|
||||
|
||||
const openProactiveMessage = (bubble: HTMLDivElement): void => {
|
||||
const openProactiveMessage = (bubble: Element): void => {
|
||||
bubble.classList.add('message-opened')
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ const onCloseButtonClick = (
|
||||
closeProactiveMessage(proactiveMessageElement)
|
||||
}
|
||||
|
||||
const closeProactiveMessage = (bubble: HTMLDivElement): void => {
|
||||
const closeProactiveMessage = (bubble: Element): void => {
|
||||
setRememberCloseInStorage()
|
||||
bubble.classList.remove('message-opened')
|
||||
}
|
||||
|
@ -30,6 +30,10 @@
|
||||
filter: brightness(0.75);
|
||||
}
|
||||
|
||||
#typebot-bubble > button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#typebot-bubble > button > .icon {
|
||||
transition: opacity 500ms ease-out 0s, transform 500ms ease-out 0s;
|
||||
}
|
||||
|
@ -1,87 +1,89 @@
|
||||
import { createIframe } from "../../iframe";
|
||||
import { PopupActions, PopupParams } from "../../types";
|
||||
import "./style.css";
|
||||
import { createIframe } from '../../iframe'
|
||||
import { PopupActions, PopupParams } from '../../types'
|
||||
import './style.css'
|
||||
|
||||
export const initPopup = (params: PopupParams): PopupActions => {
|
||||
if (document.readyState !== "complete") {
|
||||
window.addEventListener("load", () => initPopup(params));
|
||||
return { close: () => {}, open: () => {} };
|
||||
if (document.readyState !== 'complete') {
|
||||
window.addEventListener('load', () => initPopup(params))
|
||||
return { close: () => {}, open: () => {} }
|
||||
}
|
||||
const existingPopup = document.getElementById("typebot-popup");
|
||||
if (existingPopup) existingPopup.remove();
|
||||
const popupElement = createPopup(params);
|
||||
const existingPopup = document.getElementById('typebot-popup')
|
||||
if (existingPopup) existingPopup.remove()
|
||||
const popupElement = createPopup(params)
|
||||
!document.body
|
||||
? (window.onload = () => document.body.append(popupElement))
|
||||
: document.body.append(popupElement);
|
||||
: document.body.append(popupElement)
|
||||
return {
|
||||
open: () => openPopup(popupElement),
|
||||
close: () => closePopup(popupElement),
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const createPopup = (params: PopupParams): HTMLElement => {
|
||||
const { delay } = params;
|
||||
const overlayElement = createOverlayElement(delay);
|
||||
listenForOutsideClicks(overlayElement);
|
||||
const { delay } = params
|
||||
const overlayElement = createOverlayElement(delay)
|
||||
listenForOutsideClicks(overlayElement)
|
||||
const iframeElement = createIframe({
|
||||
...params,
|
||||
loadWhenVisible: true,
|
||||
});
|
||||
overlayElement.appendChild(iframeElement);
|
||||
return overlayElement;
|
||||
};
|
||||
})
|
||||
overlayElement.appendChild(iframeElement)
|
||||
return overlayElement
|
||||
}
|
||||
|
||||
const createOverlayElement = (delay: number | undefined) => {
|
||||
const overlayElement = document.createElement("div");
|
||||
overlayElement.id = "typebot-popup";
|
||||
if (delay !== undefined) setShowTimeout(overlayElement, delay);
|
||||
return overlayElement;
|
||||
};
|
||||
const overlayElement = document.createElement('div')
|
||||
overlayElement.id = 'typebot-popup'
|
||||
if (delay !== undefined) setShowTimeout(overlayElement, delay)
|
||||
return overlayElement
|
||||
}
|
||||
|
||||
export const openPopup = (popupElement: HTMLElement): void => {
|
||||
const iframe = popupElement.children[0] as HTMLIFrameElement;
|
||||
if (iframe.dataset.src) lazyLoadSrc(iframe);
|
||||
document.body.style.overflowY = "hidden";
|
||||
popupElement.classList.add("opened");
|
||||
};
|
||||
export const openPopup = (popupElement: Element): void => {
|
||||
const iframe = popupElement.children[0] as HTMLIFrameElement
|
||||
if (iframe.dataset.src) lazyLoadSrc(iframe)
|
||||
document.body.style.overflowY = 'hidden'
|
||||
popupElement.classList.add('opened')
|
||||
}
|
||||
|
||||
export const closePopup = (popupElement: HTMLElement): void => {
|
||||
document.body.style.overflowY = "auto";
|
||||
popupElement.classList.remove("opened");
|
||||
};
|
||||
export const closePopup = (popupElement: Element): void => {
|
||||
document.body.style.overflowY = 'auto'
|
||||
popupElement.classList.remove('opened')
|
||||
}
|
||||
|
||||
export const isPopupOpened = (popupElement: Element): boolean =>
|
||||
popupElement.classList.contains('opened')
|
||||
|
||||
const listenForOutsideClicks = (popupElement: HTMLDivElement) =>
|
||||
popupElement.addEventListener("click", (e) => onPopupClick(e, popupElement));
|
||||
popupElement.addEventListener('click', (e) => onPopupClick(e, popupElement))
|
||||
|
||||
const onPopupClick = (e: Event, popupElement: HTMLDivElement) => {
|
||||
e.preventDefault();
|
||||
const clickedElement = e.target as HTMLElement;
|
||||
if (clickedElement.tagName !== "iframe") closePopup(popupElement);
|
||||
};
|
||||
e.preventDefault()
|
||||
const clickedElement = e.target as HTMLElement
|
||||
if (clickedElement.tagName !== 'iframe') closePopup(popupElement)
|
||||
}
|
||||
|
||||
const setShowTimeout = (overlayElement: HTMLDivElement, delay: number) => {
|
||||
setTimeout(() => {
|
||||
openPopup(overlayElement);
|
||||
}, delay);
|
||||
};
|
||||
openPopup(overlayElement)
|
||||
}, delay)
|
||||
}
|
||||
|
||||
const lazyLoadSrc = (iframe: HTMLIFrameElement) => {
|
||||
iframe.src = iframe.dataset.src as string;
|
||||
iframe.removeAttribute("data-src");
|
||||
};
|
||||
iframe.src = iframe.dataset.src as string
|
||||
iframe.removeAttribute('data-src')
|
||||
}
|
||||
|
||||
export const getPopupActions = (
|
||||
popupElement?: HTMLDivElement
|
||||
): PopupActions => {
|
||||
const existingPopupElement =
|
||||
popupElement ??
|
||||
(document.querySelector("#typebot-popup") as HTMLDivElement);
|
||||
popupElement ?? (document.querySelector('#typebot-popup') as HTMLDivElement)
|
||||
return {
|
||||
open: () => {
|
||||
openPopup(existingPopupElement);
|
||||
openPopup(existingPopupElement)
|
||||
},
|
||||
close: () => {
|
||||
closePopup(existingPopupElement);
|
||||
closePopup(existingPopupElement)
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { closeIframe } from '../embedTypes/chat/iframe'
|
||||
import { close } from '../commands'
|
||||
import { TypebotPostMessageData, IframeCallbacks, IframeParams } from '../types'
|
||||
import './style.css'
|
||||
|
||||
@ -56,15 +56,6 @@ export const listenForTypebotMessages = (callbacks: IframeCallbacks) => {
|
||||
})
|
||||
}
|
||||
|
||||
const closeChatBubbleIfExisting = () => {
|
||||
const bubble = document.querySelector('#typebot-bubble') as
|
||||
| HTMLDivElement
|
||||
| undefined
|
||||
if (!bubble) return
|
||||
const iframe = bubble.querySelector('.typebot-iframe') as HTMLIFrameElement
|
||||
closeIframe(bubble, iframe)
|
||||
}
|
||||
|
||||
const processMessage = (
|
||||
data: TypebotPostMessageData,
|
||||
callbacks: IframeCallbacks
|
||||
@ -73,5 +64,5 @@ const processMessage = (
|
||||
if (data.newVariableValue && callbacks.onNewVariableValue)
|
||||
callbacks.onNewVariableValue(data.newVariableValue)
|
||||
if (data.codeToExecute) Function(data.codeToExecute)()
|
||||
if (data.closeChatBubble) closeChatBubbleIfExisting()
|
||||
if (data.closeChatBubble) close()
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { initContainer } from './embedTypes/container'
|
||||
import { initPopup, getPopupActions } from './embedTypes/popup'
|
||||
import { initBubble, getBubbleActions } from './embedTypes/chat'
|
||||
import { open, close, toggle, showMessage, hideMessage } from './commands'
|
||||
|
||||
export {
|
||||
initContainer,
|
||||
@ -8,6 +9,11 @@ export {
|
||||
initBubble,
|
||||
getPopupActions,
|
||||
getBubbleActions,
|
||||
open,
|
||||
close,
|
||||
toggle,
|
||||
showMessage,
|
||||
hideMessage,
|
||||
}
|
||||
|
||||
export default {
|
||||
@ -16,6 +22,11 @@ export default {
|
||||
initBubble,
|
||||
getPopupActions,
|
||||
getBubbleActions,
|
||||
open,
|
||||
close,
|
||||
toggle,
|
||||
showMessage,
|
||||
hideMessage,
|
||||
}
|
||||
|
||||
export * from './types'
|
||||
|
Reference in New Issue
Block a user