🐛 Fix bot libs mount behavior and prop types
This commit is contained in:
13
.github/workflows/publish-typebot-js.yml
vendored
13
.github/workflows/publish-typebot-js.yml
vendored
@@ -8,15 +8,16 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: ./packages/js
|
|
||||||
env:
|
env:
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: pnpm/action-setup@v2.2.2
|
- uses: pnpm/action-setup@v2.2.2
|
||||||
- run: pnpm i --frozen-lockfile
|
- run: pnpm i --frozen-lockfile
|
||||||
- run: pnpm build
|
- run: pnpm turbo build --filter=@typebot.io/js...
|
||||||
- run: pnpm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
|
- name: Set NPM_TOKEN in config
|
||||||
- run: pnpm publish --no-git-checks --access public
|
run: pnpm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
|
||||||
|
working-directory: ./packages/js
|
||||||
|
- name: Publish
|
||||||
|
run: pnpm publish --no-git-checks --access public
|
||||||
|
working-directory: ./packages/js
|
||||||
|
|||||||
13
.github/workflows/publish-typebot-react.yml
vendored
13
.github/workflows/publish-typebot-react.yml
vendored
@@ -8,15 +8,16 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: ./packages/react
|
|
||||||
env:
|
env:
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: pnpm/action-setup@v2.2.2
|
- uses: pnpm/action-setup@v2.2.2
|
||||||
- run: pnpm i --frozen-lockfile
|
- run: pnpm i --frozen-lockfile
|
||||||
- run: pnpm build
|
- run: pnpm turbo build --filter=@typebot.io/react...
|
||||||
- run: pnpm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
|
- name: Set NPM_TOKEN in config
|
||||||
- run: pnpm publish --no-git-checks --access public
|
run: pnpm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
|
||||||
|
working-directory: ./packages/react
|
||||||
|
- name: Publish
|
||||||
|
run: pnpm publish --no-git-checks --access public
|
||||||
|
working-directory: ./packages/react
|
||||||
|
|||||||
@@ -52,11 +52,10 @@ export const continueBotFlow =
|
|||||||
|
|
||||||
const formattedReply = formatReply(reply, block.type)
|
const formattedReply = formatReply(reply, block.type)
|
||||||
|
|
||||||
if (
|
if (!formattedReply && !canSkip(block.type)) {
|
||||||
!formattedReply ||
|
return parseRetryMessage(block)
|
||||||
!isReplyValid(formattedReply, block) ||
|
}
|
||||||
(!formatReply && !canSkip(block.type))
|
if (formattedReply && !isReplyValid(formattedReply, block))
|
||||||
)
|
|
||||||
return parseRetryMessage(block)
|
return parseRetryMessage(block)
|
||||||
|
|
||||||
const newVariables = await processAndSaveAnswer(
|
const newVariables = await processAndSaveAnswer(
|
||||||
@@ -98,7 +97,8 @@ const processAndSaveAnswer =
|
|||||||
state: Pick<SessionState, 'result' | 'typebot' | 'isPreview'>,
|
state: Pick<SessionState, 'result' | 'typebot' | 'isPreview'>,
|
||||||
block: InputBlock
|
block: InputBlock
|
||||||
) =>
|
) =>
|
||||||
async (reply: string): Promise<Variable[]> => {
|
async (reply: string | null): Promise<Variable[]> => {
|
||||||
|
if (!reply) return state.typebot.variables
|
||||||
if (!state.isPreview && state.result) {
|
if (!state.isPreview && state.result) {
|
||||||
await saveAnswer(state.result.id, block)(reply)
|
await saveAnswer(state.result.id, block)(reply)
|
||||||
if (!state.result.hasStarted) await setResultAsStarted(state.result.id)
|
if (!state.result.hasStarted) await setResultAsStarted(state.result.id)
|
||||||
@@ -201,7 +201,7 @@ const computeStorageUsed = async (reply: string) => {
|
|||||||
|
|
||||||
const getOutgoingEdgeId =
|
const getOutgoingEdgeId =
|
||||||
({ typebot: { variables } }: Pick<SessionState, 'typebot'>) =>
|
({ typebot: { variables } }: Pick<SessionState, 'typebot'>) =>
|
||||||
(block: InputBlock, reply?: string) => {
|
(block: InputBlock, reply: string | null) => {
|
||||||
if (
|
if (
|
||||||
block.type === InputBlockType.CHOICE &&
|
block.type === InputBlockType.CHOICE &&
|
||||||
!block.options.isMultipleChoice &&
|
!block.options.isMultipleChoice &&
|
||||||
|
|||||||
6
packages/js/.npmignore
Normal file
6
packages/js/.npmignore
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
src
|
||||||
|
.eslintignore
|
||||||
|
.eslintrc.cjs
|
||||||
|
rollup.config.js
|
||||||
|
tailwind.config.cjs
|
||||||
|
tsconfig.json
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@typebot.io/js",
|
"name": "@typebot.io/js",
|
||||||
"version": "0.0.5",
|
"version": "0.0.6",
|
||||||
"description": "Javascript library to display typebots on your website",
|
"description": "Javascript library to display typebots on your website",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ const BotContent = (props: BotContentProps) => {
|
|||||||
const font = document.createElement('link')
|
const font = document.createElement('link')
|
||||||
font.href = `https://fonts.googleapis.com/css2?family=${
|
font.href = `https://fonts.googleapis.com/css2?family=${
|
||||||
props.initialChatReply.typebot?.theme?.general?.font ?? 'Open Sans'
|
props.initialChatReply.typebot?.theme?.general?.font ?? 'Open Sans'
|
||||||
}:wght@300;400;600&display=swap')`
|
}:ital,wght@0,300;0,400;0,600;1,300;1,400;1,600&display=swap');')`
|
||||||
font.rel = 'stylesheet'
|
font.rel = 'stylesheet'
|
||||||
document.head.appendChild(font)
|
document.head.appendChild(font)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ export const InputChatBlock = (props: Props) => {
|
|||||||
props.onSubmit(value ?? label)
|
props.onSubmit(value ?? label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSkip = (label: string) => {
|
||||||
|
setAnswer(label)
|
||||||
|
props.onSkip()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={answer()} keyed>
|
<Match when={answer()} keyed>
|
||||||
@@ -75,7 +80,7 @@ export const InputChatBlock = (props: Props) => {
|
|||||||
inputIndex={props.inputIndex}
|
inputIndex={props.inputIndex}
|
||||||
isInputPrefillEnabled={props.isInputPrefillEnabled}
|
isInputPrefillEnabled={props.isInputPrefillEnabled}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
onSkip={() => props.onSkip()}
|
onSkip={handleSkip}
|
||||||
hasGuestAvatar={props.guestAvatar?.isEnabled ?? false}
|
hasGuestAvatar={props.guestAvatar?.isEnabled ?? false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,7 +96,7 @@ const Input = (props: {
|
|||||||
hasGuestAvatar: boolean
|
hasGuestAvatar: boolean
|
||||||
isInputPrefillEnabled: boolean
|
isInputPrefillEnabled: boolean
|
||||||
onSubmit: (answer: InputSubmitContent) => void
|
onSubmit: (answer: InputSubmitContent) => void
|
||||||
onSkip: () => void
|
onSkip: (label: string) => void
|
||||||
}) => {
|
}) => {
|
||||||
const onSubmit = (answer: InputSubmitContent) => props.onSubmit(answer)
|
const onSubmit = (answer: InputSubmitContent) => props.onSubmit(answer)
|
||||||
|
|
||||||
@@ -165,7 +170,6 @@ const Input = (props: {
|
|||||||
context={props.context}
|
context={props.context}
|
||||||
block={props.block as FileInputBlock}
|
block={props.block as FileInputBlock}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
// eslint-disable-next-line solid/reactivity
|
|
||||||
onSkip={props.onSkip}
|
onSkip={props.onSkip}
|
||||||
/>
|
/>
|
||||||
</Match>
|
</Match>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const Avatar = (props: { initialAvatarSrc?: string }) => {
|
|||||||
>
|
>
|
||||||
<figure
|
<figure
|
||||||
class={
|
class={
|
||||||
'flex justify-center items-center rounded-full text-white relative animate-fade-in ' +
|
'flex justify-center items-center rounded-full text-white relative animate-fade-in flex-shrink-0 ' +
|
||||||
(isMobile() ? 'w-6 h-6 text-sm' : 'w-10 h-10 text-xl')
|
(isMobile() ? 'w-6 h-6 text-sm' : 'w-10 h-10 text-xl')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type Props = {
|
|||||||
context: BotContext
|
context: BotContext
|
||||||
block: FileInputBlock
|
block: FileInputBlock
|
||||||
onSubmit: (url: InputSubmitContent) => void
|
onSubmit: (url: InputSubmitContent) => void
|
||||||
onSkip: () => void
|
onSkip: (label: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FileUploadForm = (props: Props) => {
|
export const FileUploadForm = (props: Props) => {
|
||||||
@@ -178,7 +178,12 @@ export const FileUploadForm = (props: Props) => {
|
|||||||
class={
|
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 '
|
'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 '
|
||||||
}
|
}
|
||||||
on:click={() => props.onSkip()}
|
on:click={() =>
|
||||||
|
props.onSkip(
|
||||||
|
props.block.options.labels.skip ??
|
||||||
|
defaultFileInputOptions.labels.skip
|
||||||
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{props.block.options.labels.skip ??
|
{props.block.options.labels.skip ??
|
||||||
defaultFileInputOptions.labels.skip}
|
defaultFileInputOptions.labels.skip}
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ export const Bubble = (props: BubbleProps) => {
|
|||||||
'transform-origin': 'bottom right',
|
'transform-origin': 'bottom right',
|
||||||
transform: isBotOpened() ? 'scale3d(1, 1, 1)' : 'scale3d(0, 0, 1)',
|
transform: isBotOpened() ? 'scale3d(1, 1, 1)' : 'scale3d(0, 0, 1)',
|
||||||
'box-shadow': 'rgb(0 0 0 / 16%) 0px 5px 40px',
|
'box-shadow': 'rgb(0 0 0 / 16%) 0px 5px 40px',
|
||||||
|
'background-color': bubbleProps.theme?.chatWindow?.backgroundColor,
|
||||||
}}
|
}}
|
||||||
class={
|
class={
|
||||||
'absolute bottom-20 sm:right-4 rounded-lg w-full sm:w-[400px] max-h-[704px] ' +
|
'absolute bottom-20 sm:right-4 rounded-lg w-full sm:w-[400px] max-h-[704px] ' +
|
||||||
|
|||||||
@@ -4,10 +4,15 @@ export type BubbleParams = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type BubbleTheme = {
|
export type BubbleTheme = {
|
||||||
|
chatWindow?: ChatWindowTheme
|
||||||
button?: ButtonTheme
|
button?: ButtonTheme
|
||||||
previewMessage?: PreviewMessageTheme
|
previewMessage?: PreviewMessageTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ChatWindowTheme = {
|
||||||
|
backgroundColor?: string
|
||||||
|
}
|
||||||
|
|
||||||
export type ButtonTheme = {
|
export type ButtonTheme = {
|
||||||
backgroundColor?: string
|
backgroundColor?: string
|
||||||
iconColor?: string
|
iconColor?: string
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const fileInputStepSchema = blockBaseSchema.and(
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
export const defaultFileInputOptions: FileInputOptions = {
|
export const defaultFileInputOptions = {
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
isMultipleAllowed: false,
|
isMultipleAllowed: false,
|
||||||
labels: {
|
labels: {
|
||||||
@@ -35,7 +35,7 @@ export const defaultFileInputOptions: FileInputOptions = {
|
|||||||
clear: 'Clear',
|
clear: 'Clear',
|
||||||
skip: 'Skip',
|
skip: 'Skip',
|
||||||
},
|
},
|
||||||
}
|
} satisfies FileInputOptions
|
||||||
|
|
||||||
export type FileInputBlock = z.infer<typeof fileInputStepSchema>
|
export type FileInputBlock = z.infer<typeof fileInputStepSchema>
|
||||||
export type FileInputOptions = z.infer<typeof fileInputOptionsSchema>
|
export type FileInputOptions = z.infer<typeof fileInputOptionsSchema>
|
||||||
|
|||||||
6
packages/react/.npmignore
Normal file
6
packages/react/.npmignore
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
src
|
||||||
|
.env.local.example
|
||||||
|
.eslintignore
|
||||||
|
.eslintrc.cjs
|
||||||
|
rollup.config.js
|
||||||
|
tsconfig.json
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@typebot.io/react",
|
"name": "@typebot.io/react",
|
||||||
"version": "0.0.5",
|
"version": "0.0.6",
|
||||||
"description": "React library to display typebots on your website",
|
"description": "React library to display typebots on your website",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"utils": "workspace:*"
|
"utils": "workspace:*"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "18.0.0",
|
"react": "18.x",
|
||||||
"@typebot.io/js": "workspace:*"
|
"@typebot.io/js": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,17 @@ export const Bubble = (props: Props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
await import('@typebot.io/js/dist/web')
|
await import('@typebot.io/js/dist/web')
|
||||||
|
initBubble()
|
||||||
})()
|
})()
|
||||||
|
return () => {
|
||||||
|
ref.current?.remove()
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateProps(ref.current, props)
|
||||||
|
}, [props])
|
||||||
|
|
||||||
const updateProps = (element: BubbleElement | null, props: Props) => {
|
const updateProps = (element: BubbleElement | null, props: Props) => {
|
||||||
if (!element) return
|
if (!element) return
|
||||||
Object.assign(element, props)
|
Object.assign(element, props)
|
||||||
@@ -34,20 +42,10 @@ export const Bubble = (props: Props) => {
|
|||||||
const bubbleElement = document.createElement(
|
const bubbleElement = document.createElement(
|
||||||
'typebot-bubble'
|
'typebot-bubble'
|
||||||
) as BubbleElement
|
) as BubbleElement
|
||||||
|
if (ref.current) return
|
||||||
ref.current = bubbleElement
|
ref.current = bubbleElement
|
||||||
document.body.append(bubbleElement)
|
document.body.append(ref.current)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
;(async () => {
|
|
||||||
if (!ref.current) await initBubble()
|
|
||||||
updateProps(ref.current, props)
|
|
||||||
})()
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
ref.current?.remove()
|
|
||||||
}
|
|
||||||
}, [props])
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,30 +22,28 @@ export const Popup = (props: Props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
await import('@typebot.io/js/dist/web')
|
await import('@typebot.io/js/dist/web')
|
||||||
|
initPopup()
|
||||||
})()
|
})()
|
||||||
|
return () => {
|
||||||
|
ref.current?.remove()
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateProps(ref.current, props)
|
||||||
|
}, [props])
|
||||||
|
|
||||||
const updateProps = (element: PopupElement | null, props: Props) => {
|
const updateProps = (element: PopupElement | null, props: Props) => {
|
||||||
if (!element) return
|
if (!element) return
|
||||||
Object.assign(element, props)
|
Object.assign(element, props)
|
||||||
}
|
}
|
||||||
|
|
||||||
const initBubble = async () => {
|
const initPopup = async () => {
|
||||||
const popupElement = document.createElement('typebot-popup') as PopupElement
|
const popupElement = document.createElement('typebot-popup') as PopupElement
|
||||||
|
if (ref.current) return
|
||||||
ref.current = popupElement
|
ref.current = popupElement
|
||||||
document.body.append(popupElement)
|
document.body.append(ref.current)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
;(async () => {
|
|
||||||
if (!ref.current) await initBubble()
|
|
||||||
updateProps(ref.current, props)
|
|
||||||
})()
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
ref.current?.remove()
|
|
||||||
}
|
|
||||||
}, [props])
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user