@movingwaldo/chatbot
v0.2.0
Published
MovingWaldo chatbot
Readme
@movingwaldo/chatbot
React library to embed the MovingWaldo chatbot: a floating chat bubble launcher and the chatbot panel (iframe), plus a hook to control and observe it.
Dependencies
- React 19+
Install
yarn add @movingwaldo/chatbotImport the stylesheet ONCE (e.g. in your app entry point):
import '@movingwaldo/chatbot/styles.css'Public API
Two components are exposed:
MovingWaldoChatbot- renders the chat bubble launcher and the chatbot panel. If it is not already wrapped in aMovingWaldoChatbotProvider, it self-wraps in one, so it works standalone.MovingWaldoChatbotProvider- optional. Only needed if you want to calluseMovingWaldoChatbot()from your own components.
And one hook: useMovingWaldoChatbot().
Usage
Standalone
import { MovingWaldoChatbot } from '@movingwaldo/chatbot'
export const App = () => <MovingWaldoChatbot config={{ lang: 'fr' }} />With the provider (to use the hook)
import {
MovingWaldoChatbot,
MovingWaldoChatbotProvider,
useMovingWaldoChatbot,
} from '@movingwaldo/chatbot'
const Launcher = () => {
const { open, status } = useMovingWaldoChatbot()
return (
<button onClick={open}>Chat with us (status: {status})</button>
)
}
export const App = () => (
<MovingWaldoChatbotProvider config={{ lang: 'en', url: 'https://booking.movingwaldo.com' }}>
<Launcher />
<MovingWaldoChatbot />
</MovingWaldoChatbotProvider>
)Configuration
All config lives under a single object, accepted by both the provider and the
chatbot. Config on MovingWaldoChatbot overrides config on the provider.
| Field | Type | Default | Notes |
| ---------------- | ---------------- | ------------------------------------ | --------------------------------------------------------------------- |
| lang | 'en' \| 'fr' | 'en' | Selects the language. |
| url | string | 'https://booking.movingwaldo.com' | /embed/chatbot/v1 is appended. |
| primaryColor | string | 'rgb(250, 55, 44)' (MovingWaldo red) | Any CSS color. |
| moveId | string | empty (not provided) | UUID v4 of the move (job) to associate the conversation with. Any non-UUID-v4 value is silently ignored. Runtime-updatable via setConfig({ moveId }). |
| hideButton | boolean | false | Hides the floating launcher bubble. |
| position | 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' | empty (CSS default: bottom-right) | Anchors both the bubble and the panel to a corner. Leave it unset to rely on CSS instead (see below). |
| buttonSize | number \| string | empty (CSS default: 56) | Diameter of the launcher bubble. A number is px; a string is any CSS length (e.g. '4rem'). Sets --mwcb-button-size. Leave empty to rely on CSS. |
| chatWindowSize | { width: number \| string; height: number \| string } | empty (CSS default: 440×850) | Desktop chat window size. Each dimension is a number (px) or any CSS length string (e.g. '80vh'). Sets --mwcb-window-width / --mwcb-window-height. Ignored on mobile (full-screen). |
| fullScreenChatWindowSize | { width: number \| string; height: number \| string } | calc(100vw - 2 * var(--mwcb-edge-distance)) × calc(100dvh - 2 * var(--mwcb-edge-distance)) | Desktop chat window size while fullscreen is active. Sets --mwcb-fs-window-width / --mwcb-fs-window-height. Ignored on mobile (already full-screen). Toggle fullscreen via the in-iframe header button or useMovingWaldoChatbot() (see below). |
| edgeDistance | number \| string | empty (CSS default: 24) | Distance from the bubble/window to the viewport edge. A number is px; a string is any CSS length. Sets --mwcb-edge-distance. |
| gapDistance | number \| string | empty (CSS default: 16) | Distance between the bubble and the chat window. A number is px; a string is any CSS length. Sets --mwcb-gap-distance. |
Every field except lang / url / primaryColor defaults to empty, in
which case the library sets nothing and defers to the bundled CSS. This means
you can either drive them from config, or leave them empty and control them with
your own CSS (see below) - and clearing a field at runtime falls back to CSS.
Sizes and distances (buttonSize, chatWindowSize, fullScreenChatWindowSize, edgeDistance,
gapDistance) accept either a number or any CSS length string. A bare
number is interpreted as pixels - the number 56 and the unitless string
'56' both become 56px - while any string carrying a unit or function is used
verbatim, so relative units and functions work too:
<MovingWaldoChatbot
config={{
buttonSize: '4rem',
chatWindowSize: { width: 'clamp(320px, 40vw, 560px)', height: '80vh' },
edgeDistance: '2rem',
}}
/>Sizing & positioning with CSS
The sizes and distances are backed by CSS custom properties on the
.mw-chatbot-root wrapper. When a config field is unset the variable is not
written, so the stylesheet's fallback (the "CSS default" above) applies. Set the
matching variable - or override the resolved property on the marker classes - to
control everything from CSS:
| CSS variable | Config field | CSS default |
| ----------------------- | ---------------- | ----------- |
| --mwcb-button-size | buttonSize | 3.5rem (56px) |
| --mwcb-window-width | chatWindowSize | 440px |
| --mwcb-window-height | chatWindowSize | 850px |
| --mwcb-fs-window-width | fullScreenChatWindowSize | calc(100vw - 2 * var(--mwcb-edge-distance)) |
| --mwcb-fs-window-height | fullScreenChatWindowSize | calc(100dvh - 2 * var(--mwcb-edge-distance)) |
| --mwcb-edge-distance | edgeDistance | 1.5rem (24px) |
| --mwcb-gap-distance | gapDistance | 1rem (16px) |
| --mwcb-color-primary | primaryColor | MovingWaldo red |
/* Re-size and re-space the chatbot entirely from CSS. */
.mw-chatbot-root {
--mwcb-button-size: 64px;
--mwcb-window-width: 500px;
--mwcb-window-height: 720px;
--mwcb-edge-distance: 2rem;
--mwcb-gap-distance: 0.75rem;
}On desktop the chat window is offset from its corner by
edgeDistance + buttonSize + gapDistance so it clears the launcher bubble. When
the button is hidden (hideButton: true) there is nothing to clear, so the
window collapses that offset down to just edgeDistance, sitting closer to the
edge. This is derived purely from the tokens above, so it behaves identically
whether you drive the sizes/distances from config or from your own CSS.
Positioning defers to CSS the same way: by default both the launcher bubble and
the chat panel are anchored bottom-right by scoped, overridable rules. Target
the marker classes (.mw-chatbot-button for the bubble, .mw-chatbot-panel-card
for the desktop panel):
/* Move the launcher bubble to the bottom-left instead. */
.mw-chatbot-button {
right: auto;
left: var(--mwcb-edge-distance);
}
/* Anchor the desktop panel to match (sm and up). */
@media (min-width: 40rem) {
.mw-chatbot-panel-card {
right: auto;
left: var(--mwcb-edge-distance);
}
}Prefer config over CSS? Just set the fields instead:
<MovingWaldoChatbot
config={{
position: 'bottom-left',
buttonSize: 64,
chatWindowSize: { width: 500, height: 720 },
}}
/>useMovingWaldoChatbot()
const {
status,
config,
setConfig,
isOpen,
open,
close,
toggle,
isFullScreen,
setFullScreen,
toggleFullScreen,
type,
clear
} = useMovingWaldoChatbot()status:'stalled' | 'loading' | 'loaded' | 'error'config: the resolved configurationsetConfig(partial): merges a partial config on top of the current one atisOpen: return true if the chat window is openedopen(),close(),toggle(): open/hide chatbot windowisFullScreen: return true if the chat window is in fullscreen modesetFullScreen(next),toggleFullScreen(): control fullscreen mode programmatically. Fullscreen resizes the desktop panel tofullScreenChatWindowSizewith a smooth transition (disabled underprefers-reduced-motion). The in-iframe header also exposes a fullscreen toggle button (shown only when embedded, hidden on mobile); both stay in sync.type(text: string): Sendstextas the customer - opens the panel if closed and submitstextas a user message in the conversation.clear(): Clears the current conversation without a confirmation dialog - closes the panel, expires the conversation-id cookie, drops the in-memory id, and resets the thread to greeting-only. The next message afterwards starts a fresh conversation. Mirrors the "Start over" UI action but is confirmation-free and programmatic.
MovingWaldoChatbot also accepts a controlled open prop.
