@ -28,7 +28,7 @@ export const AvatarSideContainer = (props: Props) => {
|
||||
<div
|
||||
ref={avatarContainer}
|
||||
class={
|
||||
'flex w-10 mr-2 mb-2 flex-shrink-0 items-center relative typebot-avatar-container ' +
|
||||
'flex mr-2 mb-2 flex-shrink-0 items-center relative typebot-avatar-container ' +
|
||||
(isMobile() ? 'w-6' : 'w-10')
|
||||
}
|
||||
>
|
||||
|
@ -42,7 +42,7 @@ export const ConversationContainer = (props: Props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="overflow-y-scroll w-full lg:w-3/4 min-h-full rounded lg:px-5 px-3 pt-10 relative scrollable-container typebot-chat-view">
|
||||
<div class="overflow-y-scroll w-full min-h-full rounded px-3 pt-10 relative scrollable-container typebot-chat-view">
|
||||
<For each={chatChunks()}>
|
||||
{(chatChunk, index) => (
|
||||
<ChatChunk
|
||||
|
@ -1,52 +1,124 @@
|
||||
import styles from '../../../assets/index.css'
|
||||
import { createSignal } from 'solid-js'
|
||||
import { createSignal, onMount, Show, splitProps, onCleanup } from 'solid-js'
|
||||
import { Bot, BotProps } from '../../../components/Bot'
|
||||
import { CommandData } from '@/features/commands'
|
||||
import { BubbleButton } from './BubbleButton'
|
||||
import { PreviewMessage, PreviewMessageProps } from './PreviewMessage'
|
||||
import { isDefined } from 'utils'
|
||||
import { BubbleParams } from '../types'
|
||||
|
||||
export type BubbleProps = BotProps &
|
||||
BubbleParams & {
|
||||
onOpen?: () => void
|
||||
onClose?: () => void
|
||||
onPreviewMessageClick?: () => void
|
||||
}
|
||||
|
||||
export const Bubble = (props: BubbleProps) => {
|
||||
const [bubbleProps, botProps] = splitProps(props, [
|
||||
'onOpen',
|
||||
'onClose',
|
||||
'previewMessage',
|
||||
'onPreviewMessageClick',
|
||||
'button',
|
||||
])
|
||||
const [prefilledVariables, setPrefilledVariables] = createSignal(
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
botProps.prefilledVariables
|
||||
)
|
||||
const [isPreviewMessageDisplayed, setIsPreviewMessageDisplayed] =
|
||||
createSignal(false)
|
||||
const [previewMessage, setPreviewMessage] = createSignal<
|
||||
Pick<PreviewMessageProps, 'avatarUrl' | 'message'>
|
||||
>({
|
||||
message: bubbleProps.previewMessage?.message ?? '',
|
||||
avatarUrl: bubbleProps.previewMessage?.avatarUrl,
|
||||
})
|
||||
|
||||
export const Bubble = () => {
|
||||
const [isBotOpened, setIsBotOpened] = createSignal(false)
|
||||
const [isBotStarted, setIsBotStarted] = createSignal(false)
|
||||
|
||||
onMount(() => {
|
||||
window.addEventListener('message', processIncomingEvent)
|
||||
const autoShowDelay = bubbleProps.previewMessage?.autoShowDelay
|
||||
if (isDefined(autoShowDelay)) {
|
||||
setTimeout(() => {
|
||||
showMessage()
|
||||
}, autoShowDelay)
|
||||
}
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
window.removeEventListener('message', processIncomingEvent)
|
||||
})
|
||||
|
||||
const processIncomingEvent = (event: MessageEvent<CommandData>) => {
|
||||
const { data } = event
|
||||
if (!data.isFromTypebot) return
|
||||
if (data.command === 'open') openBot()
|
||||
if (data.command === 'close') closeBot()
|
||||
if (data.command === 'toggle') toggleBot()
|
||||
if (data.command === 'showPreviewMessage') showMessage(data.message)
|
||||
if (data.command === 'hidePreviewMessage') hideMessage()
|
||||
if (data.command === 'setPrefilledVariables')
|
||||
setPrefilledVariables((existingPrefilledVariables) => ({
|
||||
...existingPrefilledVariables,
|
||||
...data.variables,
|
||||
}))
|
||||
}
|
||||
|
||||
const openBot = () => {
|
||||
if (!isBotStarted()) setIsBotStarted(true)
|
||||
hideMessage()
|
||||
setIsBotOpened(true)
|
||||
if (isBotOpened()) bubbleProps.onOpen?.()
|
||||
}
|
||||
|
||||
const closeBot = () => {
|
||||
setIsBotOpened(false)
|
||||
if (isBotOpened()) bubbleProps.onClose?.()
|
||||
}
|
||||
|
||||
const toggleBot = () => {
|
||||
setIsBotOpened(!isBotOpened())
|
||||
isBotOpened() ? closeBot() : openBot()
|
||||
}
|
||||
|
||||
const handlePreviewMessageClick = () => {
|
||||
bubbleProps.onPreviewMessageClick?.()
|
||||
openBot()
|
||||
}
|
||||
|
||||
const showMessage = (
|
||||
previewMessage?: Pick<PreviewMessageProps, 'avatarUrl' | 'message'>
|
||||
) => {
|
||||
if (previewMessage) setPreviewMessage(previewMessage)
|
||||
if (isBotOpened()) return
|
||||
setIsPreviewMessageDisplayed(true)
|
||||
}
|
||||
|
||||
const hideMessage = () => {
|
||||
setIsPreviewMessageDisplayed(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{styles}</style>
|
||||
<button
|
||||
onClick={toggleBot}
|
||||
class="bg-blue-500 text-red-300 absolute bottom-4 right-4 w-12 h-12 rounded-full hover:scale-110 active:scale-95 transition-transform duration-200 flex justify-center items-center"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
style={{ transition: 'transform 200ms, opacity 200ms' }}
|
||||
class={
|
||||
'w-7 stroke-white stroke-2 fill-transparent absolute ' +
|
||||
(isBotOpened() ? 'scale-0 opacity-0' : 'scale-100 opacity-100')
|
||||
}
|
||||
>
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
|
||||
</svg>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
style={{ transition: 'transform 200ms, opacity 200ms' }}
|
||||
class={
|
||||
'w-7 fill-white absolute ' +
|
||||
(isBotOpened()
|
||||
? 'scale-100 rotate-0 opacity-100'
|
||||
: 'scale-0 -rotate-180 opacity-0')
|
||||
}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M18.601 8.39897C18.269 8.06702 17.7309 8.06702 17.3989 8.39897L12 13.7979L6.60099 8.39897C6.26904 8.06702 5.73086 8.06702 5.39891 8.39897C5.06696 8.73091 5.06696 9.2691 5.39891 9.60105L11.3989 15.601C11.7309 15.933 12.269 15.933 12.601 15.601L18.601 9.60105C18.9329 9.2691 18.9329 8.73091 18.601 8.39897Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<Show when={isPreviewMessageDisplayed()}>
|
||||
<PreviewMessage
|
||||
{...previewMessage()}
|
||||
button={bubbleProps.button}
|
||||
onClick={handlePreviewMessageClick}
|
||||
onCloseClick={hideMessage}
|
||||
/>
|
||||
</Show>
|
||||
<BubbleButton
|
||||
{...bubbleProps.button}
|
||||
toggleBot={toggleBot}
|
||||
isBotOpened={isBotOpened()}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: '400px',
|
||||
height: 'calc(100% - 104px)',
|
||||
'max-height': '704px',
|
||||
height: 'calc(100% - 80px)',
|
||||
transition:
|
||||
'transform 200ms cubic-bezier(0, 1.2, 1, 1), opacity 150ms ease-out',
|
||||
'transform-origin': 'bottom right',
|
||||
@ -54,10 +126,14 @@ export const Bubble = () => {
|
||||
'box-shadow': 'rgb(0 0 0 / 16%) 0px 5px 40px',
|
||||
}}
|
||||
class={
|
||||
'absolute bottom-20 right-4 rounded-2xl ' +
|
||||
'absolute bottom-20 sm:right-4 rounded-lg bg-white w-full sm:w-[400px] max-h-[704px] ' +
|
||||
(isBotOpened() ? 'opacity-1' : 'opacity-0 pointer-events-none')
|
||||
}
|
||||
/>
|
||||
>
|
||||
<Show when={isBotStarted()}>
|
||||
<Bot {...botProps} prefilledVariables={prefilledVariables()} />
|
||||
</Show>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
67
packages/js/src/features/bubble/components/BubbleButton.tsx
Normal file
67
packages/js/src/features/bubble/components/BubbleButton.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import { Show } from 'solid-js'
|
||||
import { ButtonParams } from '../types'
|
||||
|
||||
type Props = ButtonParams & {
|
||||
isBotOpened: boolean
|
||||
toggleBot: () => void
|
||||
}
|
||||
|
||||
const defaultButtonColor = '#0042DA'
|
||||
|
||||
export const BubbleButton = (props: Props) => {
|
||||
return (
|
||||
<button
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
onClick={props.toggleBot}
|
||||
class={
|
||||
'absolute bottom-4 right-4 shadow-md w-12 h-12 rounded-full hover:scale-110 active:scale-95 transition-transform duration-200 flex justify-center items-center animate-fade-in'
|
||||
}
|
||||
style={{
|
||||
'background-color': props.backgroundColor ?? defaultButtonColor,
|
||||
}}
|
||||
>
|
||||
<Show when={props.icon?.color} keyed>
|
||||
{(color) => (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
style={{
|
||||
stroke: color,
|
||||
}}
|
||||
class={
|
||||
`w-7 stroke-2 fill-transparent absolute duration-200 transition ` +
|
||||
(props.isBotOpened
|
||||
? 'scale-0 opacity-0'
|
||||
: 'scale-100 opacity-100')
|
||||
}
|
||||
>
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
|
||||
</svg>
|
||||
)}
|
||||
</Show>
|
||||
<Show when={props.icon?.url}>
|
||||
<img
|
||||
src={props.icon?.url}
|
||||
class="w-7 h-7 rounded-full object-cover"
|
||||
alt="Bubble button icon"
|
||||
/>
|
||||
</Show>
|
||||
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
style={{ fill: props.icon?.color ?? 'white' }}
|
||||
class={
|
||||
`w-7 absolute duration-200 transition ` +
|
||||
(props.isBotOpened
|
||||
? 'scale-100 rotate-0 opacity-100'
|
||||
: 'scale-0 -rotate-180 opacity-0')
|
||||
}
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M18.601 8.39897C18.269 8.06702 17.7309 8.06702 17.3989 8.39897L12 13.7979L6.60099 8.39897C6.26904 8.06702 5.73086 8.06702 5.39891 8.39897C5.06696 8.73091 5.06696 9.2691 5.39891 9.60105L11.3989 15.601C11.7309 15.933 12.269 15.933 12.601 15.601L18.601 9.60105C18.9329 9.2691 18.9329 8.73091 18.601 8.39897Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
)
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import { createSignal } from 'solid-js'
|
||||
import { BubbleParams, PreviewMessageParams } from '../types'
|
||||
|
||||
export type PreviewMessageProps = Pick<
|
||||
PreviewMessageParams,
|
||||
'avatarUrl' | 'message' | 'style'
|
||||
> &
|
||||
Pick<BubbleParams, 'button'> & {
|
||||
onClick: () => void
|
||||
onCloseClick: () => void
|
||||
}
|
||||
|
||||
const defaultFontFamily =
|
||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
|
||||
|
||||
export const PreviewMessage = (props: PreviewMessageProps) => {
|
||||
const [isPreviewMessageHovered, setIsPreviewMessageHovered] =
|
||||
createSignal(false)
|
||||
|
||||
return (
|
||||
<div
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
onClick={props.onClick}
|
||||
class="absolute bottom-20 right-4 w-64 rounded-md duration-200 flex items-center gap-4 shadow-md animate-fade-in cursor-pointer hover:shadow-lg p-4"
|
||||
style={{
|
||||
'font-family': props.style?.fontFamily ?? defaultFontFamily,
|
||||
'background-color': props.style?.backgroundColor ?? '#F7F8FF',
|
||||
color: props.style?.color ?? '#303235',
|
||||
}}
|
||||
onMouseEnter={() => setIsPreviewMessageHovered(true)}
|
||||
onMouseLeave={() => setIsPreviewMessageHovered(false)}
|
||||
>
|
||||
<button
|
||||
class={
|
||||
`absolute -top-3 -right-3 rounded-full w-6 h-6 p-1 hover:brightness-95 active:brightness-90 transition-all ` +
|
||||
(isPreviewMessageHovered() ? 'opacity-100' : 'opacity-0')
|
||||
}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
return props.onCloseClick()
|
||||
}}
|
||||
style={{
|
||||
'background-color': props.style?.closeButtonBgColor ?? '#F7F8FF',
|
||||
color: props.style?.closeButtonColor ?? '#303235',
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="18" y1="6" x2="6" y2="18" />
|
||||
<line x1="6" y1="6" x2="18" y2="18" />
|
||||
</svg>
|
||||
</button>
|
||||
<img
|
||||
src={props.avatarUrl}
|
||||
class="rounded-full w-8 h-8 object-cover"
|
||||
alt="Bot avatar"
|
||||
/>
|
||||
<p>{props.message}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
27
packages/js/src/features/bubble/types.ts
Normal file
27
packages/js/src/features/bubble/types.ts
Normal file
@ -0,0 +1,27 @@
|
||||
export type BubbleParams = {
|
||||
button: ButtonParams
|
||||
previewMessage: PreviewMessageParams
|
||||
}
|
||||
|
||||
export type ButtonParams = {
|
||||
backgroundColor?: string
|
||||
icon?: {
|
||||
color?: string
|
||||
url?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type PreviewMessageParams = {
|
||||
avatarUrl?: string
|
||||
message: string
|
||||
autoShowDelay?: number
|
||||
style?: PreviewMessageStyle
|
||||
}
|
||||
|
||||
type PreviewMessageStyle = Partial<{
|
||||
backgroundColor: string
|
||||
color: string
|
||||
fontFamily: string
|
||||
closeButtonBgColor: string
|
||||
closeButtonColor: string
|
||||
}>
|
2
packages/js/src/features/commands/index.ts
Normal file
2
packages/js/src/features/commands/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './types'
|
||||
export * from './utils'
|
21
packages/js/src/features/commands/types.ts
Normal file
21
packages/js/src/features/commands/types.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { PreviewMessageParams } from '../bubble/types'
|
||||
|
||||
export type CommandData = {
|
||||
isFromTypebot: boolean
|
||||
} & (
|
||||
| {
|
||||
command: 'open' | 'toggle' | 'close' | 'hidePreviewMessage'
|
||||
}
|
||||
| ShowMessageCommandData
|
||||
| SetPrefilledVariablesCommandData
|
||||
)
|
||||
|
||||
export type ShowMessageCommandData = {
|
||||
command: 'showPreviewMessage'
|
||||
message?: Pick<PreviewMessageParams, 'avatarUrl' | 'message'>
|
||||
}
|
||||
|
||||
export type SetPrefilledVariablesCommandData = {
|
||||
command: 'setPrefilledVariables'
|
||||
variables: Record<string, string | number | boolean>
|
||||
}
|
9
packages/js/src/features/commands/utils/close.ts
Normal file
9
packages/js/src/features/commands/utils/close.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { CommandData } from '../types'
|
||||
|
||||
export const close = () => {
|
||||
const message: CommandData = {
|
||||
isFromTypebot: true,
|
||||
command: 'close',
|
||||
}
|
||||
window.postMessage(message)
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { CommandData } from '../types'
|
||||
|
||||
export const hidePreviewMessage = () => {
|
||||
const message: CommandData = {
|
||||
isFromTypebot: true,
|
||||
command: 'hidePreviewMessage',
|
||||
}
|
||||
window.postMessage(message)
|
||||
}
|
6
packages/js/src/features/commands/utils/index.ts
Normal file
6
packages/js/src/features/commands/utils/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './close'
|
||||
export * from './hidePreviewMessage'
|
||||
export * from './open'
|
||||
export * from './setPrefilledVariables'
|
||||
export * from './showPreviewMessage'
|
||||
export * from './toggle'
|
9
packages/js/src/features/commands/utils/open.ts
Normal file
9
packages/js/src/features/commands/utils/open.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { CommandData } from '../types'
|
||||
|
||||
export const open = () => {
|
||||
const message: CommandData = {
|
||||
isFromTypebot: true,
|
||||
command: 'open',
|
||||
}
|
||||
window.postMessage(message)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import { CommandData } from '../types'
|
||||
|
||||
export const setPrefilledVariables = (
|
||||
variables: Record<string, string | number | boolean>
|
||||
) => {
|
||||
const message: CommandData = {
|
||||
isFromTypebot: true,
|
||||
command: 'setPrefilledVariables',
|
||||
variables,
|
||||
}
|
||||
window.postMessage(message)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import { CommandData, ShowMessageCommandData } from '../types'
|
||||
|
||||
export const showPreviewMessage = (
|
||||
proactiveMessage?: ShowMessageCommandData['message']
|
||||
) => {
|
||||
const message: CommandData = {
|
||||
isFromTypebot: true,
|
||||
command: 'showPreviewMessage',
|
||||
message: proactiveMessage,
|
||||
}
|
||||
window.postMessage(message)
|
||||
}
|
9
packages/js/src/features/commands/utils/toggle.ts
Normal file
9
packages/js/src/features/commands/utils/toggle.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { CommandData } from '../types'
|
||||
|
||||
export const toggle = () => {
|
||||
const message: CommandData = {
|
||||
isFromTypebot: true,
|
||||
command: 'toggle',
|
||||
}
|
||||
window.postMessage(message)
|
||||
}
|
@ -1,3 +1,106 @@
|
||||
export const Popup = () => {
|
||||
return <div />
|
||||
import styles from '../../../assets/index.css'
|
||||
import { createSignal, onMount, Show, splitProps, onCleanup } from 'solid-js'
|
||||
import { Bot, BotProps } from '../../../components/Bot'
|
||||
import { CommandData } from '@/features/commands'
|
||||
import { isDefined } from 'utils'
|
||||
import { PopupParams } from '../types'
|
||||
|
||||
export type PopupProps = BotProps &
|
||||
PopupParams & {
|
||||
onOpen?: () => void
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
export const Popup = (props: PopupProps) => {
|
||||
let botContainer: HTMLDivElement | undefined
|
||||
|
||||
const [popupProps, botProps] = splitProps(props, [
|
||||
'onOpen',
|
||||
'onClose',
|
||||
'autoShowDelay',
|
||||
'style',
|
||||
])
|
||||
|
||||
const [prefilledVariables, setPrefilledVariables] = createSignal(
|
||||
// eslint-disable-next-line solid/reactivity
|
||||
botProps.prefilledVariables
|
||||
)
|
||||
|
||||
const [isBotOpened, setIsBotOpened] = createSignal(false)
|
||||
|
||||
onMount(() => {
|
||||
window.addEventListener('click', processWindowClick)
|
||||
window.addEventListener('message', processIncomingEvent)
|
||||
const autoShowDelay = popupProps.autoShowDelay
|
||||
if (isDefined(autoShowDelay)) {
|
||||
setTimeout(() => {
|
||||
openBot()
|
||||
}, autoShowDelay)
|
||||
}
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
window.removeEventListener('message', processIncomingEvent)
|
||||
window.removeEventListener('click', processWindowClick)
|
||||
})
|
||||
|
||||
const processWindowClick = (event: MouseEvent) => {
|
||||
if (!botContainer || botContainer.contains(event.target as Node)) return
|
||||
setIsBotOpened(false)
|
||||
}
|
||||
|
||||
const processIncomingEvent = (event: MessageEvent<CommandData>) => {
|
||||
const { data } = event
|
||||
if (!data.isFromTypebot) return
|
||||
if (data.command === 'open') openBot()
|
||||
if (data.command === 'close') closeBot()
|
||||
if (data.command === 'toggle') toggleBot()
|
||||
if (data.command === 'setPrefilledVariables')
|
||||
setPrefilledVariables((existingPrefilledVariables) => ({
|
||||
...existingPrefilledVariables,
|
||||
...data.variables,
|
||||
}))
|
||||
}
|
||||
|
||||
const openBot = () => {
|
||||
setIsBotOpened(true)
|
||||
if (isBotOpened()) popupProps.onOpen?.()
|
||||
}
|
||||
|
||||
const closeBot = () => {
|
||||
setIsBotOpened(false)
|
||||
if (isBotOpened()) popupProps.onClose?.()
|
||||
}
|
||||
|
||||
const toggleBot = () => {
|
||||
isBotOpened() ? closeBot() : openBot()
|
||||
}
|
||||
|
||||
return (
|
||||
<Show when={isBotOpened()}>
|
||||
<div
|
||||
class="relative z-10"
|
||||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<style>{styles}</style>
|
||||
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity animate-fade-in" />
|
||||
<div class="fixed inset-0 z-10 overflow-y-auto">
|
||||
<div class="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
|
||||
<div
|
||||
class="relative h-[80vh] transform overflow-hidden rounded-lg text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg"
|
||||
style={{
|
||||
width: popupProps.style?.width ?? '100%',
|
||||
'background-color': popupProps.style?.backgroundColor ?? '#fff',
|
||||
}}
|
||||
ref={botContainer}
|
||||
>
|
||||
<Bot {...botProps} prefilledVariables={prefilledVariables()} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
|
7
packages/js/src/features/popup/types.ts
Normal file
7
packages/js/src/features/popup/types.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export type PopupParams = {
|
||||
autoShowDelay?: number
|
||||
style?: {
|
||||
width?: string
|
||||
backgroundColor?: string
|
||||
}
|
||||
}
|
@ -1,2 +1,5 @@
|
||||
export { registerWebComponents } from './register'
|
||||
export * from './register'
|
||||
export type { BotProps } from './components/Bot'
|
||||
export type { BubbleProps } from './features/bubble'
|
||||
export type { PopupProps } from './features/popup'
|
||||
export * from './features/commands'
|
||||
|
@ -1,7 +1,19 @@
|
||||
/* eslint-disable solid/reactivity */
|
||||
import { customElement } from 'solid-element'
|
||||
import { Bot, BotProps } from './components/Bot'
|
||||
import { Bubble, BubbleProps } from './features/bubble'
|
||||
import { Popup, PopupProps } from './features/popup'
|
||||
|
||||
export const registerWebComponents = (props: BotProps) => {
|
||||
export const registerStandardComponent = (props: BotProps) => {
|
||||
if (typeof window === 'undefined') return
|
||||
customElement('typebot-standard', props, Bot)
|
||||
}
|
||||
|
||||
export const registerBubbleComponent = (props: BubbleProps) => {
|
||||
if (typeof window === 'undefined') return
|
||||
customElement('typebot-bubble', props, Bubble)
|
||||
}
|
||||
|
||||
export const registerPopupComponent = (props: PopupProps) => {
|
||||
if (typeof window === 'undefined') return
|
||||
customElement('typebot-popup', props, Popup)
|
||||
}
|
||||
|
Reference in New Issue
Block a user