⚡ (engine) Improve engine overall robustness
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import { TypingBubble } from '@/components/bubbles/TypingBubble'
|
||||
import { AudioBubbleContent } from 'models'
|
||||
import { TypingBubble } from '@/components'
|
||||
import type { AudioBubbleContent } from 'models'
|
||||
import { createSignal, onCleanup, onMount } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { TypingBubble } from '@/components/bubbles/TypingBubble'
|
||||
import { EmbedBubbleContent } from 'models'
|
||||
import { TypingBubble } from '@/components'
|
||||
import type { EmbedBubbleContent } from 'models'
|
||||
import { createSignal, onMount } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { TypingBubble } from '@/components/bubbles/TypingBubble'
|
||||
import { ImageBubbleContent } from 'models'
|
||||
import { TypingBubble } from '@/components'
|
||||
import type { ImageBubbleContent } from 'models'
|
||||
import { createSignal, onMount } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { TypingBubble } from '@/components/bubbles/TypingBubble'
|
||||
import { TextBubbleContent, TypingEmulation } from 'models'
|
||||
import { TypingBubble } from '@/components'
|
||||
import type { TextBubbleContent, TypingEmulation } from 'models'
|
||||
import { createSignal, onMount } from 'solid-js'
|
||||
import { computeTypingDuration } from '../utils/computeTypingDuration'
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { TypingEmulation } from 'models'
|
||||
import type { TypingEmulation } from 'models'
|
||||
|
||||
export const computeTypingDuration = (
|
||||
bubbleContent: string,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { TypingBubble } from '@/components/bubbles/TypingBubble'
|
||||
import { VideoBubbleContent, VideoBubbleContentType } from 'models'
|
||||
import { TypingBubble } from '@/components'
|
||||
import type { VideoBubbleContent } from 'models'
|
||||
import { VideoBubbleContentType } from 'models/features/blocks/bubbles/video/enums'
|
||||
import { createSignal, Match, onMount, Switch } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
@ -64,10 +65,7 @@ const VideoContent = (props: VideoContentProps) => {
|
||||
<Match
|
||||
when={
|
||||
props.content?.type &&
|
||||
[
|
||||
VideoBubbleContentType.VIMEO,
|
||||
VideoBubbleContentType.YOUTUBE,
|
||||
].includes(props.content.type)
|
||||
props.content.type === VideoBubbleContentType.URL
|
||||
}
|
||||
>
|
||||
<video
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { ChoiceInputBlock } from 'models'
|
||||
import type { ChoiceInputBlock } from 'models'
|
||||
import { createSignal, For } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
@ -12,8 +12,7 @@ type Props = {
|
||||
export const ChoiceForm = (props: Props) => {
|
||||
const [selectedIndices, setSelectedIndices] = createSignal<number[]>([])
|
||||
|
||||
const handleClick = (itemIndex: number) => (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
const handleClick = (itemIndex: number) => {
|
||||
if (props.block.options?.isMultipleChoice)
|
||||
toggleSelectedItemIndex(itemIndex)
|
||||
else props.onSubmit({ value: props.block.items[itemIndex].content ?? '' })
|
||||
@ -47,7 +46,8 @@ export const ChoiceForm = (props: Props) => {
|
||||
role={
|
||||
props.block.options?.isMultipleChoice ? 'checkbox' : 'button'
|
||||
}
|
||||
onClick={(event) => handleClick(index())(event)}
|
||||
type="button"
|
||||
on:click={() => handleClick(index())}
|
||||
class={
|
||||
'py-2 px-4 text-left font-semibold rounded-md transition-all filter hover:brightness-90 active:brightness-75 duration-100 focus:outline-none typebot-button ' +
|
||||
(selectedIndices().some(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { DateInputOptions } from 'models'
|
||||
import type { DateInputOptions } from 'models'
|
||||
import { createSignal } from 'solid-js'
|
||||
import { parseReadableDate } from '../utils/parseReadableDate'
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ShortTextInput } from '@/components/inputs'
|
||||
import { ShortTextInput } from '@/components'
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { isMobile } from '@/utils/isMobileSignal'
|
||||
import { EmailInputBlock } from 'models'
|
||||
import type { EmailInputBlock } from 'models'
|
||||
import { createSignal, onMount } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
@ -59,7 +59,7 @@ export const EmailInput = (props: Props) => {
|
||||
type="button"
|
||||
isDisabled={inputValue() === ''}
|
||||
class="my-2 ml-2"
|
||||
onClick={submit}
|
||||
on:click={submit}
|
||||
>
|
||||
{props.block.options?.labels?.button ?? 'Send'}
|
||||
</SendButton>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { SendButton, Spinner } from '@/components/SendButton'
|
||||
import { BotContext, InputSubmitContent } from '@/types'
|
||||
import { defaultFileInputOptions, FileInputBlock } from 'models'
|
||||
import { FileInputBlock } from 'models'
|
||||
import { defaultFileInputOptions } from 'models/features/blocks/inputs/file'
|
||||
import { createSignal, Match, Show, Switch } from 'solid-js'
|
||||
import { uploadFiles } from 'utils'
|
||||
|
||||
@ -140,7 +141,7 @@ export const FileUploadForm = (props: Props) => {
|
||||
<span class="relative">
|
||||
<FileIcon />
|
||||
<div
|
||||
class="total-files-indicator flex items-center justify-center absolute -right-1 rounded-full px-1 h-4"
|
||||
class="total-files-indicator flex items-center justify-center absolute -right-1 rounded-full px-1 w-4 h-4"
|
||||
style={{ bottom: '5px' }}
|
||||
>
|
||||
{selectedFiles().length}
|
||||
@ -177,7 +178,7 @@ export const FileUploadForm = (props: Props) => {
|
||||
class={
|
||||
'py-2 px-4 justify-center font-semibold rounded-md text-white focus:outline-none flex items-center disabled:opacity-50 disabled:cursor-not-allowed disabled:brightness-100 transition-all filter hover:brightness-90 active:brightness-75 typebot-button '
|
||||
}
|
||||
onClick={() => props.onSkip()}
|
||||
on:click={() => props.onSkip()}
|
||||
>
|
||||
{props.block.options.labels.skip ??
|
||||
defaultFileInputOptions.labels.skip}
|
||||
@ -198,7 +199,7 @@ export const FileUploadForm = (props: Props) => {
|
||||
class={
|
||||
'secondary-button py-2 px-4 justify-center font-semibold rounded-md text-white focus:outline-none flex items-center disabled:opacity-50 disabled:cursor-not-allowed disabled:brightness-100 transition-all filter hover:brightness-90 active:brightness-75 mr-2'
|
||||
}
|
||||
onClick={clearFiles}
|
||||
on:click={clearFiles}
|
||||
>
|
||||
{props.block.options.labels.clear ??
|
||||
defaultFileInputOptions.labels.clear}
|
||||
@ -233,7 +234,7 @@ const UploadIcon = () => (
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mb-3"
|
||||
class="mb-3 text-gray-500"
|
||||
>
|
||||
<polyline points="16 16 12 12 8 16" />
|
||||
<line x1="12" y1="12" x2="12" y2="21" />
|
||||
@ -244,7 +245,6 @@ const UploadIcon = () => (
|
||||
|
||||
const FileIcon = () => (
|
||||
<svg
|
||||
class="mb-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
@ -254,6 +254,7 @@ const FileIcon = () => (
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="mb-3 text-gray-500"
|
||||
>
|
||||
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" />
|
||||
<polyline points="13 2 13 9 20 9" />
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ShortTextInput } from '@/components/inputs'
|
||||
import { ShortTextInput } from '@/components'
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { isMobile } from '@/utils/isMobileSignal'
|
||||
import { NumberInputBlock } from 'models'
|
||||
import type { NumberInputBlock } from 'models'
|
||||
import { createSignal, onMount } from 'solid-js'
|
||||
|
||||
type NumberInputProps = {
|
||||
@ -62,7 +62,7 @@ export const NumberInput = (props: NumberInputProps) => {
|
||||
type="button"
|
||||
isDisabled={inputValue() === ''}
|
||||
class="my-2 ml-2"
|
||||
onClick={submit}
|
||||
on:click={submit}
|
||||
>
|
||||
{props.block.options?.labels?.button ?? 'Send'}
|
||||
</SendButton>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { BotContext } from '@/types'
|
||||
import { PaymentInputOptions, PaymentProvider, RuntimeOptions } from 'models'
|
||||
import type { PaymentInputOptions, RuntimeOptions } from 'models'
|
||||
import { PaymentProvider } from 'models/features/blocks/inputs/payment/enums'
|
||||
import { Match, Switch } from 'solid-js'
|
||||
import { StripePaymentForm } from './StripePaymentForm'
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { createSignal, onMount, Show } from 'solid-js'
|
||||
import { loadStripe } from '@stripe/stripe-js/pure'
|
||||
import type { Stripe, StripeElements } from '@stripe/stripe-js'
|
||||
import { BotContext } from '@/types'
|
||||
import { PaymentInputOptions, RuntimeOptions } from 'models'
|
||||
import type { PaymentInputOptions, RuntimeOptions } from 'models'
|
||||
import { loadStripe } from '@/lib/stripe'
|
||||
|
||||
type Props = {
|
||||
context: BotContext
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ShortTextInput } from '@/components/inputs'
|
||||
import { ShortTextInput } from '@/components'
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { isMobile } from '@/utils/isMobileSignal'
|
||||
@ -99,7 +99,7 @@ export const PhoneInput = (props: PhoneInputProps) => {
|
||||
type="button"
|
||||
isDisabled={inputValue() === ''}
|
||||
class="my-2 ml-2"
|
||||
onClick={submit}
|
||||
on:click={submit}
|
||||
>
|
||||
{props.block.options?.labels?.button ?? 'Send'}
|
||||
</SendButton>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { RatingInputBlock, RatingInputOptions } from 'models'
|
||||
import type { RatingInputBlock, RatingInputOptions } from 'models'
|
||||
import { createSignal, For, Match, Switch } from 'solid-js'
|
||||
import { isDefined, isEmpty, isNotDefined } from 'utils'
|
||||
|
||||
@ -84,7 +84,7 @@ const RatingButton = (props: RatingButtonProps) => {
|
||||
<Switch>
|
||||
<Match when={props.buttonType === 'Numbers'}>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
on:click={(e) => {
|
||||
e.preventDefault()
|
||||
props.onClick(props.idx)
|
||||
}}
|
||||
@ -111,7 +111,7 @@ const RatingButton = (props: RatingButtonProps) => {
|
||||
? props.customIcon.svg
|
||||
: defaultIcon
|
||||
}
|
||||
onClick={() => props.onClick(props.idx)}
|
||||
on:click={() => props.onClick(props.idx)}
|
||||
/>
|
||||
</Match>
|
||||
</Switch>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Textarea, ShortTextInput } from '@/components/inputs'
|
||||
import { Textarea, ShortTextInput } from '@/components'
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { isMobile } from '@/utils/isMobileSignal'
|
||||
import { TextInputBlock } from 'models'
|
||||
import type { TextInputBlock } from 'models'
|
||||
import { createSignal, onMount } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
@ -69,7 +69,7 @@ export const TextInput = (props: Props) => {
|
||||
type="button"
|
||||
isDisabled={inputValue() === ''}
|
||||
class="my-2 ml-2"
|
||||
onClick={submit}
|
||||
on:click={submit}
|
||||
>
|
||||
{props.block.options?.labels?.button ?? 'Send'}
|
||||
</SendButton>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ShortTextInput } from '@/components/inputs'
|
||||
import { ShortTextInput } from '@/components'
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import { isMobile } from '@/utils/isMobileSignal'
|
||||
import { UrlInputBlock } from 'models'
|
||||
import type { UrlInputBlock } from 'models'
|
||||
import { createSignal, onMount } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
@ -65,7 +65,7 @@ export const UrlInput = (props: Props) => {
|
||||
type="button"
|
||||
isDisabled={inputValue() === ''}
|
||||
class="my-2 ml-2"
|
||||
onClick={submit}
|
||||
on:click={submit}
|
||||
>
|
||||
{props.block.options?.labels?.button ?? 'Send'}
|
||||
</SendButton>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { executeCode } from '@/features/blocks/logic/code'
|
||||
import { CodeToExecute } from 'models'
|
||||
import type { CodeToExecute } from 'models'
|
||||
|
||||
export const executeChatwoot = (chatwoot: { codeToExecute: CodeToExecute }) => {
|
||||
executeCode(chatwoot.codeToExecute)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { sendGaEvent } from '@/lib/gtag'
|
||||
import { GoogleAnalyticsOptions } from 'models'
|
||||
import type { GoogleAnalyticsOptions } from 'models'
|
||||
|
||||
export const executeGoogleAnalyticsBlock = async (
|
||||
options: GoogleAnalyticsOptions
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { CodeToExecute } from 'models'
|
||||
import type { CodeToExecute } from 'models'
|
||||
|
||||
export const executeCode = async ({ content, args }: CodeToExecute) => {
|
||||
const func = Function(...args.map((arg) => arg.id), content)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { RedirectOptions } from 'models'
|
||||
import type { RedirectOptions } from 'models'
|
||||
|
||||
export const executeRedirect = ({ url, isNewTab }: RedirectOptions) => {
|
||||
if (!url) return
|
||||
|
@ -1,11 +1,11 @@
|
||||
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 styles from '../../../assets/index.css'
|
||||
import { CommandData } from '../../commands'
|
||||
import { BubbleButton } from './BubbleButton'
|
||||
import { PreviewMessage, PreviewMessageProps } from './PreviewMessage'
|
||||
import { isDefined } from 'utils'
|
||||
import { BubbleParams } from '../types'
|
||||
import { Bot, BotProps } from '../../../components/Bot'
|
||||
|
||||
export type BubbleProps = BotProps &
|
||||
BubbleParams & {
|
||||
@ -131,7 +131,11 @@ export const Bubble = (props: BubbleProps) => {
|
||||
}
|
||||
>
|
||||
<Show when={isBotStarted()}>
|
||||
<Bot {...botProps} prefilledVariables={prefilledVariables()} />
|
||||
<Bot
|
||||
{...botProps}
|
||||
prefilledVariables={prefilledVariables()}
|
||||
class="rounded-lg"
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
</>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Show } from 'solid-js'
|
||||
import { isNotDefined } from 'utils'
|
||||
import { ButtonTheme } from '../types'
|
||||
|
||||
type Props = ButtonTheme & {
|
||||
@ -7,6 +8,7 @@ type Props = ButtonTheme & {
|
||||
}
|
||||
|
||||
const defaultButtonColor = '#0042DA'
|
||||
const defaultIconColor = 'white'
|
||||
|
||||
export const BubbleButton = (props: Props) => {
|
||||
return (
|
||||
@ -20,27 +22,23 @@ export const BubbleButton = (props: Props) => {
|
||||
'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 when={isNotDefined(props.customIconSrc)} keyed>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
style={{
|
||||
stroke: props.iconColor ?? defaultIconColor,
|
||||
}}
|
||||
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}>
|
||||
<Show when={props.customIconSrc}>
|
||||
<img
|
||||
src={props.icon?.url}
|
||||
src={props.customIconSrc}
|
||||
class="w-7 h-7 rounded-full object-cover"
|
||||
alt="Bubble button icon"
|
||||
/>
|
||||
@ -48,7 +46,7 @@ export const BubbleButton = (props: Props) => {
|
||||
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
style={{ fill: props.icon?.color ?? 'white' }}
|
||||
style={{ fill: props.iconColor ?? 'white' }}
|
||||
class={
|
||||
`w-7 absolute duration-200 transition ` +
|
||||
(props.isBotOpened
|
||||
|
@ -10,8 +10,8 @@ export type PreviewMessageProps = Pick<
|
||||
onCloseClick: () => void
|
||||
}
|
||||
|
||||
const defaultFontFamily =
|
||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'"
|
||||
const defaultBackgroundColor = '#F7F8FF'
|
||||
const defaultTextColor = '#303235'
|
||||
|
||||
export const PreviewMessage = (props: PreviewMessageProps) => {
|
||||
const [isPreviewMessageHovered, setIsPreviewMessageHovered] =
|
||||
@ -23,11 +23,9 @@ export const PreviewMessage = (props: PreviewMessageProps) => {
|
||||
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.previewMessageTheme?.fontFamily ?? defaultFontFamily,
|
||||
'background-color':
|
||||
props.previewMessageTheme?.backgroundColor ?? '#F7F8FF',
|
||||
color: props.previewMessageTheme?.color ?? '#303235',
|
||||
props.previewMessageTheme?.backgroundColor ?? defaultBackgroundColor,
|
||||
color: props.previewMessageTheme?.textColor ?? defaultTextColor,
|
||||
}}
|
||||
onMouseEnter={() => setIsPreviewMessageHovered(true)}
|
||||
onMouseLeave={() => setIsPreviewMessageHovered(false)}
|
||||
@ -43,8 +41,10 @@ export const PreviewMessage = (props: PreviewMessageProps) => {
|
||||
}}
|
||||
style={{
|
||||
'background-color':
|
||||
props.previewMessageTheme?.closeButtonBgColor ?? '#F7F8FF',
|
||||
color: props.previewMessageTheme?.closeButtonColor ?? '#303235',
|
||||
props.previewMessageTheme?.closeButtonBackgroundColor ??
|
||||
defaultBackgroundColor,
|
||||
color:
|
||||
props.previewMessageTheme?.closeButtonIconColor ?? defaultTextColor,
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
|
@ -10,10 +10,8 @@ export type BubbleTheme = {
|
||||
|
||||
export type ButtonTheme = {
|
||||
backgroundColor?: string
|
||||
icon?: {
|
||||
color?: string
|
||||
url?: string
|
||||
}
|
||||
iconColor?: string
|
||||
customIconSrc?: string
|
||||
}
|
||||
|
||||
export type PreviewMessageParams = {
|
||||
@ -24,8 +22,7 @@ export type PreviewMessageParams = {
|
||||
|
||||
export type PreviewMessageTheme = {
|
||||
backgroundColor?: string
|
||||
color?: string
|
||||
fontFamily?: string
|
||||
closeButtonBgColor?: string
|
||||
closeButtonColor?: string
|
||||
textColor?: string
|
||||
closeButtonBackgroundColor?: string
|
||||
closeButtonIconColor?: string
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ import {
|
||||
onCleanup,
|
||||
createEffect,
|
||||
} from 'solid-js'
|
||||
import { Bot, BotProps } from '../../../components/Bot'
|
||||
import { CommandData } from '@/features/commands'
|
||||
import { isDefined } from 'utils'
|
||||
import { CommandData } from '../../commands'
|
||||
import { isDefined, isNotDefined } from 'utils'
|
||||
import { PopupParams } from '../types'
|
||||
import { Bot, BotProps } from '../../../components/Bot'
|
||||
|
||||
export type PopupProps = BotProps &
|
||||
PopupParams & {
|
||||
@ -43,8 +43,6 @@ export const Popup = (props: PopupProps) => {
|
||||
)
|
||||
|
||||
onMount(() => {
|
||||
document.addEventListener('pointerdown', processWindowClick)
|
||||
botContainer?.addEventListener('pointerdown', stopPropagation)
|
||||
window.addEventListener('message', processIncomingEvent)
|
||||
const autoShowDelay = popupProps.autoShowDelay
|
||||
if (isDefined(autoShowDelay)) {
|
||||
@ -54,20 +52,14 @@ export const Popup = (props: PopupProps) => {
|
||||
}
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
const isOpen = popupProps.isOpen
|
||||
if (isDefined(isOpen)) setIsBotOpened(isOpen)
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
document.removeEventListener('pointerdown', processWindowClick)
|
||||
botContainer?.removeEventListener('pointerdown', stopPropagation)
|
||||
window.removeEventListener('message', processIncomingEvent)
|
||||
})
|
||||
|
||||
const processWindowClick = () => {
|
||||
setIsBotOpened(false)
|
||||
}
|
||||
createEffect(() => {
|
||||
if (isNotDefined(props.isOpen) || props.isOpen === isBotOpened()) return
|
||||
toggleBot()
|
||||
})
|
||||
|
||||
const stopPropagation = (event: MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
@ -87,24 +79,28 @@ export const Popup = (props: PopupProps) => {
|
||||
}
|
||||
|
||||
const openBot = () => {
|
||||
if (isBotOpened()) popupProps.onOpen?.()
|
||||
if (isDefined(props.isOpen)) return
|
||||
setIsBotOpened(true)
|
||||
popupProps.onOpen?.()
|
||||
document.body.style.overflow = 'hidden'
|
||||
document.addEventListener('pointerdown', closeBot)
|
||||
botContainer?.addEventListener('pointerdown', stopPropagation)
|
||||
}
|
||||
|
||||
const closeBot = () => {
|
||||
if (isBotOpened()) popupProps.onClose?.()
|
||||
if (isDefined(props.isOpen)) return
|
||||
setIsBotOpened(false)
|
||||
popupProps.onClose?.()
|
||||
document.body.style.overflow = 'auto'
|
||||
document.removeEventListener('pointerdown', closeBot)
|
||||
botContainer?.removeEventListener('pointerdown', stopPropagation)
|
||||
}
|
||||
|
||||
const toggleBot = () => {
|
||||
if (isDefined(props.isOpen)) return
|
||||
isBotOpened() ? closeBot() : openBot()
|
||||
}
|
||||
|
||||
return (
|
||||
<Show when={isBotOpened()}>
|
||||
<style>{styles}</style>
|
||||
<div
|
||||
class="relative z-10"
|
||||
aria-labelledby="modal-title"
|
||||
|
@ -2,6 +2,5 @@ export type PopupParams = {
|
||||
autoShowDelay?: number
|
||||
theme?: {
|
||||
width?: string
|
||||
backgroundColor?: string
|
||||
}
|
||||
}
|
||||
|
47
packages/js/src/features/standard/components/Standard.tsx
Normal file
47
packages/js/src/features/standard/components/Standard.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import styles from '../../../assets/index.css'
|
||||
import { Bot, BotProps } from '@/components/Bot'
|
||||
import { createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||
|
||||
const hostElementCss = `
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
`
|
||||
|
||||
export const Standard = (props: BotProps) => {
|
||||
const [isBotDisplayed, setIsBotDisplayed] = createSignal(false)
|
||||
|
||||
const launchBot = () => {
|
||||
setIsBotDisplayed(true)
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver((intersections) => {
|
||||
if (intersections.some((intersection) => intersection.isIntersecting))
|
||||
launchBot()
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
const standardElement = document.querySelector('typebot-standard')
|
||||
if (!standardElement) return
|
||||
observer.observe(standardElement)
|
||||
})
|
||||
|
||||
onCleanup(() => {
|
||||
observer.disconnect()
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>
|
||||
{styles}
|
||||
{hostElementCss}
|
||||
</style>
|
||||
<Show when={isBotDisplayed()}>
|
||||
<Bot {...props} />
|
||||
</Show>
|
||||
</>
|
||||
)
|
||||
}
|
1
packages/js/src/features/standard/components/index.ts
Normal file
1
packages/js/src/features/standard/components/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './Standard'
|
1
packages/js/src/features/standard/index.ts
Normal file
1
packages/js/src/features/standard/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './components'
|
Reference in New Issue
Block a user