@mochabug/adapt-web
Version:
Browser client library for Adapt automation platform
482 lines (382 loc) • 16.9 kB
Markdown
# @mochabug/adapt-web
Embed Adapt automations in any website.
```bash
npm install @mochabug/adapt-web
```
**CDN base:** `https://cdn.mochabug.com/adapt/web/__VERSION__/`
| Bundle | File | Includes |
|--------|------|----------|
| Full | `adapt-web.min.js` | Automation + Cap.js challenges |
| Core | `adapt-web.core.min.js` | Automation only (~40KB smaller) |
| Cap | `adapt-web.cap.min.js` | Cap.js challenge widget only |
| Headless | `adapt-core.min.js` | Headless client (no UI) |
### Composable loading
Bundles merge into a single `MbAdapt` global, so you can combine them. For example, headless + Cap for automations that need proof-of-work but no UI:
```html
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-core.min.js"></script>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.cap.min.js"></script>
<script>
// MbAdapt has exports from both scripts
var client = MbAdapt.createAdaptClient(
MbAdapt.createConnectClient({ id: "YOUR_ID" }),
"YOUR_ID"
);
</script>
```
---
## 1. `<adapt-automation>`
The main component. Drop it in, set `automation-id`, done.
### Optimal — `<head>` access available
Preload the script and load the stylesheet in `<head>` to eliminate flash of unstyled content.
```html
<head>
<link rel="preload" href="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.min.js" as="script">
<link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/__VERSION__/styles.css">
</head>
<body>
<adapt-automation automation-id="YOUR_ID" requires-challenge style="height: 600px"></adapt-automation>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.min.js"></script>
</body>
```
No challenges? Use the core bundle and drop `requires-challenge`:
```html
<head>
<link rel="preload" href="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.core.min.js" as="script">
<link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/__VERSION__/styles.css">
</head>
<body>
<adapt-automation automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.core.min.js"></script>
</body>
```
### Embedded — no `<head>` access (Wix, Squarespace, WordPress, etc.)
Just the element and script. CSS is auto-injected at runtime.
```html
<adapt-automation automation-id="YOUR_ID" requires-challenge style="height: 600px"></adapt-automation>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.min.js"></script>
```
Without challenges:
```html
<adapt-automation automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.core.min.js"></script>
```
### ESM
```typescript
import '@mochabug/adapt-web'; // with challenges
import '@mochabug/adapt-web/styles.css';
```
```typescript
import '@mochabug/adapt-web/core'; // without challenges (lighter)
import '@mochabug/adapt-web/styles.css';
```
```html
<adapt-automation automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
```
### Attributes
| Attribute | Description |
|-----------|-------------|
| `automation-id` | **Required.** Automation ID |
| `requires-challenge` | Require proof-of-work before starting (full bundle only) |
| `auth-token` | Client-side auth token |
| `session-token` | Server-created session token |
| `inherit-token` | Join an existing session |
| `challenge-token` | Pre-solved challenge token |
| `transmitter` | Transmitter ID |
| `inherit-from` | JSON object: `{"hash":"mb_session"}` or `{"param":"token"}` |
| `signals` | JSON object of initial signal values |
| `fork-display-mode` | `side-by-side` (default) or `dialog` |
| `side-by-side-split` | Split percentage, e.g. `60` |
| `dark-mode` | Enable dark mode |
| `auto-resizing` | Container follows iframe content height |
| `allow-floating` | Set to `"false"` to hide pop-out buttons and block user-initiated floating |
| `allow-docking` | Set to `"false"` to hide dock buttons and block user-initiated docking |
| `allow-dialog-docking` | Set to `"false"` to prevent tab splits inside floating dialog overlays |
| `floating-auto-resize` | Floating overlays auto-resize based on iframe content height |
| `persist` | Persist session across page refreshes |
| `confirm-on-close` | Show a confirmation dialog before the user leaves the page while a session is active |
Initial JSON options can be written directly on the element:
```html
<adapt-automation
automation-id="YOUR_ID"
inherit-from='{"hash":"mb_session"}'
signals='{"key":"value"}'
style="height: 600px"
></adapt-automation>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.core.min.js"></script>
```
For complex values that are easier to build in JavaScript, set properties before loading the bundle:
```html
<adapt-automation id="automation" automation-id="YOUR_ID" style="height: 600px"></adapt-automation>
<script>
const el = document.getElementById('automation');
el.inheritFrom = { hash: 'mb_session' };
el.signals = { key: 'value' };
</script>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.core.min.js"></script>
```
### JS-only properties
Set via element reference — not available as HTML attributes.
| Property | Type |
|----------|------|
| `capWidgetOptions` | `{ workerCount?: number; i18n?: CapWidgetI18n }` |
| `classNames` | `{ root?: string; iframe?: string; statusMessage?: string; statusCard?: string }` |
| `styles` | `Partial<CSSStyleDeclaration>` |
| `persistOptions` | `{ storage?: 'session' \| 'local'; ttl?: number; key?: string }` |
| `text` | `StatusText` |
| `theme` | `AdaptTheme` |
`signals` and `inheritFrom` are also available as JS properties. They are initial options; set them before the element initializes.
### Events
| Event | Detail |
|-------|--------|
| `adapt-session` | `{ status: StatusJson, fork?: string }` |
| `adapt-output` | `{ output: Output }` |
| `adapt-fork-active` | `{ active: boolean }` |
### Methods
| Method | Description |
|--------|-------------|
| `newSession()` | Ends the current session and starts a new one. Returns a `Promise<void>`. |
---
## 2. `<adapt-cap>`
Standalone proof-of-work challenge widget. Use when you manage the automation client yourself.
Requires a `client` JS property — set it after the element is in the DOM.
### Optimal
```html
<head>
<link rel="preload" href="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.cap.min.js" as="script">
<link rel="stylesheet" href="https://cdn.mochabug.com/adapt/web/__VERSION__/styles.css">
</head>
<body>
<adapt-cap automation-id="YOUR_ID"></adapt-cap>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.cap.min.js"></script>
<script>
var el = document.querySelector('adapt-cap');
el.client = MbAdapt.createConnectClient({ id: 'YOUR_ID' });
el.addEventListener('adapt-cap-solve', function(e) {
console.log('Token:', e.detail.token);
});
</script>
</body>
```
### Embedded
```html
<adapt-cap automation-id="YOUR_ID"></adapt-cap>
<script src="https://cdn.mochabug.com/adapt/web/__VERSION__/adapt-web.cap.min.js"></script>
<script>
var el = document.querySelector('adapt-cap');
el.client = MbAdapt.createConnectClient({ id: 'YOUR_ID' });
el.addEventListener('adapt-cap-solve', function(e) {
console.log('Token:', e.detail.token);
});
</script>
```
### ESM
```typescript
import { createConnectClient } from '@mochabug/adapt-web/cap';
import '@mochabug/adapt-web/styles.css';
const el = document.querySelector('adapt-cap')!;
el.client = createConnectClient({ id: 'YOUR_ID' });
el.addEventListener('adapt-cap-solve', (e) => {
console.log('Token:', e.detail.token);
});
```
### Attributes
| Attribute | Description |
|-----------|-------------|
| `automation-id` | **Required.** Automation ID |
| `dark-mode` | Enable dark mode |
| `worker-count` | Number of WASM workers |
### JS-only properties
| Property | Type |
|----------|------|
| `client` | `AutomationClient` — **required**, set via JS |
| `i18n` | `CapWidgetI18n` — label overrides (set before `client`) |
### Events
| Event | Detail |
|-------|--------|
| `adapt-cap-solve` | `{ token: string, expires: Date }` |
| `adapt-cap-error` | `{ error: Error }` |
---
## Styling
Three ways to theme, from simplest to most powerful:
### 1. `theme` prop (recommended)
Set the `theme` JS property for semantic theming. Derives 30+ CSS variables from a few tokens.
```javascript
const el = document.querySelector('adapt-automation');
el.theme = {
mode: 'dark',
primary: '#6366f1',
background: '#0f172a',
surface: '#1e293b',
text: '#f1f5f9',
border: '#334155',
font: '"Inter", sans-serif',
};
```
**`AdaptTheme` interface:**
| Token | Effect |
|-------|--------|
| `mode` | `'light'` or `'dark'` — toggles dark mode class |
| `primary` | Accent color — derives separator, drop target, spinner colors |
| `background` | Root bg, active tab bg, status card bg |
| `surface` | Panel content bg, tab bar bg |
| `text` | Active tab text, status text, cap widget text |
| `textSecondary` | Inactive tab text |
| `border` | Tab separators, status card border, cap border |
| `font` | All panel UI text + cap widget |
| `vars` | `Record<string, string>` — direct variable overrides (key = name without `--mb-adapt-` prefix) |
The `vars` escape hatch lets you override any variable:
```javascript
el.theme = {
primary: '#6366f1',
vars: {
'floating-shadow': 'none',
'floating-border': '2px solid #6366f1',
'cap-border-radius': '0px',
},
};
```
### 2. CSS custom properties
Set `--mb-adapt-*` variables on `.mb-adapt` or any ancestor. No Shadow DOM — standard CSS inheritance works.
```css
.mb-adapt {
--mb-adapt-fork-bg: #ffffff;
--mb-adapt-fork-tab-bg: #f5f5f5;
--mb-adapt-fork-tab-color: #1a1a1a;
--mb-adapt-fork-separator: #e0e0e0;
}
.mb-adapt--dark {
--mb-adapt-fork-bg: #1e1e1e;
--mb-adapt-fork-tab-bg: #2a2a2a;
--mb-adapt-fork-tab-color: #e0e0e0;
--mb-adapt-fork-separator: #3a3a3a;
}
```
### 3. Direct CSS on internal classes
No Shadow DOM — all internal elements use plain CSS classes. Target them directly for effects that CSS variables can't express: animations, pseudo-elements, transitions, media queries.
**Animated gradient toolbar (liquid glass):**
```css
@keyframes toolbar-glow {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
/* Light mode — warm aurora */
.mb-adapt .mb-group-header {
background: linear-gradient(
135deg,
rgba(99, 102, 241, 0.08) 0%,
rgba(168, 85, 247, 0.08) 25%,
rgba(236, 72, 153, 0.06) 50%,
rgba(99, 102, 241, 0.08) 100%
) !important;
background-size: 300% 300%;
animation: toolbar-glow 8s ease infinite;
}
/* Dark mode — deep neon */
.mb-adapt--dark .mb-group-header {
background: linear-gradient(
135deg,
rgba(99, 102, 241, 0.15) 0%,
rgba(168, 85, 247, 0.12) 25%,
rgba(236, 72, 153, 0.10) 50%,
rgba(99, 102, 241, 0.15) 100%
) !important;
background-size: 300% 300%;
animation: toolbar-glow 8s ease infinite;
}
```
**Key classes you can target:**
| Class | Element |
|-------|---------|
| `.mb-group-header` | Tab toolbar |
| `.mb-tab` | Individual tab |
| `.mb-tab[data-active="true"]` | Active tab |
| `.mb-group-content` | Panel content area |
| `.mb-floating-overlay` | Floating panel container |
| `.mb-layout-separator` | Resize handle between panels |
| `.mb-drag-ghost` | Tab drag preview |
| `.mb-adapt__status-card` | Error/stopped status card |
| `.mb-adapt__status-icon` | Status card icon |
| `.mb-adapt-minimized-tab` | Minimized panel tab |
| `.mb-drop-overlay` | Drop target highlight |
All three approaches compose — use `theme` for colors, CSS variables for fine-tuning, and direct class targeting for animations.
<details>
<summary>Full CSS variable reference</summary>
### General
| Variable | Light default | Dark default | Description |
|---|---|---|---|
| `--mb-adapt-bg` | `transparent` | | Root & group backgrounds |
| `--mb-adapt-font` | `system-ui, -apple-system, sans-serif` | | All panel UI text |
| `--mb-adapt-button-hover-bg` | `rgba(128,128,128,0.2)` | `rgba(128,128,128,0.3)` | Close/popout/action button hover |
| `--mb-adapt-separator-active` | `rgba(59,130,246,0.5)` | `rgba(99,130,246,0.6)` | Resize handle hover/active |
| `--mb-adapt-border-radius` | `8px` | | Iframe border radius |
### Toolbar and tabs
| Variable | Light default | Dark default | Description |
|---|---|---|---|
| `--mb-adapt-fork-bg` | `#ffffff` | `#1e1e1e` | Panel content background |
| `--mb-adapt-fork-tab-bg` | `#f3f3f3` | `#252526` | Toolbar / inactive tab bg |
| `--mb-adapt-fork-tab-active-bg` | `#ffffff` | `#1e1e1e` | Active tab background |
| `--mb-adapt-fork-tab-color` | `rgb(51,51,51)` | `#ffffff` | Active tab text |
| `--mb-adapt-fork-tab-inactive-color` | `rgba(51,51,51,0.7)` | `#969696` | Inactive tab text |
| `--mb-adapt-fork-separator` | `rgba(128,128,128,0.35)` | `rgb(68,68,68)` | Tab/panel borders |
| `--mb-adapt-tab-radius` | `0` | | Tab border-radius (use `999px` for pill shape) |
| `--mb-adapt-tab-shadow` | `none` | | Tab box-shadow |
| `--mb-adapt-tab-active-shadow` | `none` | | Active tab box-shadow |
| `--mb-adapt-tab-gap` | `0px` | | Tab margin (spacing between tabs) |
| `--mb-adapt-tab-padding` | `0 14px` | | Tab padding |
| `--mb-adapt-tab-font-size` | `13px` | | Tab label font size |
| `--mb-adapt-toolbar-height` | `40px` | | Toolbar / tab bar height |
| `--mb-adapt-toolbar-padding` | `0` | | Toolbar inner padding (standard CSS shorthand) |
| `--mb-adapt-tab-min-width` | `100px` | | Tab minimum width |
| `--mb-adapt-tab-spacing` | `6px` | | Gap between tab label and action buttons |
### Floating panels (elevation)
| Variable | Light default | Dark default | Description |
|---|---|---|---|
| `--mb-adapt-floating-shadow` | `0 25px 50px -12px rgba(0,0,0,0.25), 0 12px 24px -8px rgba(0,0,0,0.15)` | `… rgba(0,0,0,0.5), … rgba(0,0,0,0.3)` | Overlay box-shadow |
| `--mb-adapt-floating-border` | `none` | `1px solid rgba(255,255,255,0.06)` | Overlay border |
| `--mb-adapt-floating-backdrop` | `none` | | Overlay backdrop-filter |
| `--mb-adapt-floating-radius` | `8px` | | Overlay border-radius |
| `--mb-adapt-status-card-shadow` | `0 4px 24px rgba(0,0,0,0.08), 0 2px 8px rgba(0,0,0,0.04)` | `… rgba(0,0,0,0.25), … rgba(0,0,0,0.15)` | Status card box-shadow |
| `--mb-adapt-drag-ghost-shadow` | `0 4px 12px rgba(0,0,0,0.15)` | `0 4px 12px rgba(0,0,0,0.35)` | Drag ghost box-shadow |
### Drop targets
| Variable | Light default | Dark default |
|---|---|---|
| `--mb-adapt-drop-header-bg` | `rgba(99,102,241,0.18)` | `rgba(129,140,248,0.22)` |
| `--mb-adapt-drop-center-bg` | `rgba(99,102,241,0.12)` | `rgba(129,140,248,0.15)` |
| `--mb-adapt-drop-split-bg` | `rgba(99,102,241,0.14)` | `rgba(129,140,248,0.18)` |
| `--mb-adapt-drop-border` | `rgba(99,102,241,0.55)` | `rgba(129,140,248,0.6)` |
### Status cards
| Variable | Light default | Dark default |
|---|---|---|
| `--mb-adapt-status-card-bg` | `#ffffff` | `#1e293b` |
| `--mb-adapt-status-card-border` | `#e5e7eb` | `#334155` |
| `--mb-adapt-status-icon-bg` | `#fef2f2` | `#351c1c` |
| `--mb-adapt-status-text` | `#374151` | `#e2e8f0` |
### Cap widget
| Variable | Light default | Dark default |
|---|---|---|
| `--mb-adapt-cap-background` | `#ffffff` | `#1e293b` |
| `--mb-adapt-cap-border-color` | `#e2e8f0` | `#334155` |
| `--mb-adapt-cap-border-radius` | `16px` | |
| `--mb-adapt-cap-height` | `72px` | |
| `--mb-adapt-cap-width` | `380px` | |
| `--mb-adapt-cap-padding` | `20px 28px` | |
| `--mb-adapt-cap-gap` | `20px` | |
| `--mb-adapt-cap-color` | `#1e293b` | `#f1f5f9` |
| `--mb-adapt-cap-checkbox-size` | `36px` | |
| `--mb-adapt-cap-checkbox-border` | `2px solid #cbd5e1` | `2px solid #475569` |
| `--mb-adapt-cap-checkbox-radius` | `10px` | |
| `--mb-adapt-cap-checkbox-background` | `#f8fafc` | `#0f172a` |
| `--mb-adapt-cap-spinner-color` | `#6366f1` | `#818cf8` |
| `--mb-adapt-cap-spinner-bg` | `#e2e8f0` | `#334155` |
| `--mb-adapt-cap-spinner-thickness` | `3px` | |
| `--mb-adapt-cap-font` | `inherit` | |
### Z-index / stacking
| Variable | Default | Description |
|---|---|---|
| `--mb-adapt-z-base` | `0` | Base z-index offset — added to all internal z-index values |
Set `--mb-adapt-z-base` to shift all internal z-index values. Useful when embedding inside modals or drawers that have their own stacking context. Example: `--mb-adapt-z-base: 10000` lifts all layers by 10000.
Internal stacking order from low to high: separators (1), resize handles (10), minimized tabs (100), floating panels (100000+), status/cap (200000), confirm dialog (300000), drop targets (999998), drag ghost (999999). All values are offset by `--mb-adapt-z-base`.
</details>
---
## License
ISC (c) mochabug AB