@simula/ads 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/dist/InChatAdSlot.d.ts +4 -0
- package/dist/InChatAdSlot.d.ts.map +1 -0
- package/dist/SimulaProvider.d.ts +5 -0
- package/dist/SimulaProvider.d.ts.map +1 -0
- package/dist/hooks/useBotDetection.d.ts +3 -0
- package/dist/hooks/useBotDetection.d.ts.map +1 -0
- package/dist/hooks/useDebounce.d.ts +2 -0
- package/dist/hooks/useDebounce.d.ts.map +1 -0
- package/dist/hooks/useOMIDViewability.d.ts +24 -0
- package/dist/hooks/useOMIDViewability.d.ts.map +1 -0
- package/dist/hooks/useViewability.d.ts +6 -0
- package/dist/hooks/useViewability.d.ts.map +1 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2240 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2224 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/api.d.ts +18 -0
- package/dist/utils/api.d.ts.map +1 -0
- package/dist/utils/colorThemes.d.ts +21 -0
- package/dist/utils/colorThemes.d.ts.map +1 -0
- package/dist/utils/styling.d.ts +4 -0
- package/dist/utils/styling.d.ts.map +1 -0
- package/dist/utils/validation.d.ts +22 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Simula
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# Simula Ad SDK
|
|
2
|
+
|
|
3
|
+
**React SDK for AI-Powered Contextual Ads**
|
|
4
|
+
|
|
5
|
+
Simula delivers **contextually relevant ads** for conversational AI apps and LLM-based interfaces. Itβs lightweight, easy to integrate, and MRC-compliant out of the box.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## π Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @simula/ads
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## β‘ Quick Start
|
|
18
|
+
|
|
19
|
+
Integrate in **two steps**:
|
|
20
|
+
|
|
21
|
+
1. **Wrap your chat/conversation component** with `SimulaProvider`
|
|
22
|
+
2. **Insert** `<InChatAdSlot />` where you want ads
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { SimulaProvider, InChatAdSlot } from "@simula/ads";
|
|
26
|
+
|
|
27
|
+
function App() {
|
|
28
|
+
return (
|
|
29
|
+
<div>
|
|
30
|
+
<Header />
|
|
31
|
+
<ChatInterface /> {/* SimulaProvider wraps individual conversations */}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function ChatInterface() {
|
|
37
|
+
const [messages, setMessages] = useState([]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<SimulaProvider apiKey="SIMULA_xxx">
|
|
41
|
+
<div>
|
|
42
|
+
{messages.map((msg, i) => (
|
|
43
|
+
<div key={i}>
|
|
44
|
+
<p><strong>{msg.role}:</strong> {msg.content}</p>
|
|
45
|
+
{msg.role === "assistant" && (
|
|
46
|
+
<InChatAdSlot
|
|
47
|
+
messages={messages.slice(0, i + 1)}
|
|
48
|
+
formats="all"
|
|
49
|
+
theme={{ theme: "light", accent: "blue" }}
|
|
50
|
+
/>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
))}
|
|
54
|
+
</div>
|
|
55
|
+
</SimulaProvider>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## π§© Components
|
|
63
|
+
|
|
64
|
+
### `SimulaProvider`
|
|
65
|
+
|
|
66
|
+
Initializes the SDK and manages session state.
|
|
67
|
+
|
|
68
|
+
| Prop | Type | Required | Default | Description |
|
|
69
|
+
| --------------- | ----------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
70
|
+
| `apiKey` | `string` | β
| β | Your Simula API key from the [dashboard](https://simula.ad) |
|
|
71
|
+
| `children` | `ReactNode` | β
| β | Your app components |
|
|
72
|
+
| `devMode` | `boolean` | β | `false` | Enables development mode |
|
|
73
|
+
| `primaryUserID` | `string` | β | β | Publisher-provided user identifier. **Recommended** for consistent tracking across devices and sessions. |
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
// Wrap individual chat/conversation components
|
|
77
|
+
function ChatInterface({ conversationId }) {
|
|
78
|
+
const [messages, setMessages] = useState([]);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<SimulaProvider apiKey="SIMULA_xxx">
|
|
82
|
+
{/* Your chat UI */}
|
|
83
|
+
</SimulaProvider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// For authenticated apps with user tracking (recommended)
|
|
88
|
+
function ChatInterface({ conversationId, userId }) {
|
|
89
|
+
const [messages, setMessages] = useState([]);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<SimulaProvider apiKey="SIMULA_xxx" primaryUserID={userId}>
|
|
93
|
+
{/* Your chat UI */}
|
|
94
|
+
</SimulaProvider>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
> **Provider Best Practices**
|
|
100
|
+
>
|
|
101
|
+
> * **Wrap individual conversations** β Place `SimulaProvider` around each chat or character component so that each conversation is treated as a separate session. This provides better ad targeting based on conversation context.
|
|
102
|
+
>
|
|
103
|
+
> * **Provide `primaryUserID`** β Use your user's ID to enable cross-device tracking and cookie-independent identification. This approach delivers:
|
|
104
|
+
> * **Higher CPMs** β Better user attribution leads to more valuable ad placements
|
|
105
|
+
> * **Frequency capping** β Prevents oversending ads to the same user
|
|
106
|
+
> * **Better ad experience** β Optimized targeting based on consistent user history
|
|
107
|
+
> * **Accurate analytics** β Reliable performance metrics across devices and sessions
|
|
108
|
+
>
|
|
109
|
+
> * **One provider per conversation** β Don't nest multiple `SimulaProvider` instances. Each conversation/chat component should have its own provider at the top level.
|
|
110
|
+
>
|
|
111
|
+
> For anonymous users, you can still use `SimulaProvider` without `primaryUserID`, but tracking will rely on cookies.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### `InChatAdSlot`
|
|
116
|
+
|
|
117
|
+
Displays an ad based on conversation context.
|
|
118
|
+
|
|
119
|
+
| Prop | Type | Required | Default | Description |
|
|
120
|
+
| -------------- | ---------------------- | -------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
121
|
+
| `messages` | `Message[]` | β
| β | Array of `{ role, content }`; pass recent conversation (e.g. last 6 turns). |
|
|
122
|
+
| `trigger` | `Promise<any>` | β | Fires immediately on viewability | Promise to await before fetching the ad (e.g. LLM call). |
|
|
123
|
+
| `formats` | `string \| string[]` | β | `['all']` | Preferred ad formats: `'all'`, `'tips'`, `'interactive'`, `'suggestions'`, `'text'`, `'highlight'`, `'visual_banner'`, `'image_feature'`, or an array like `['text', 'highlight']`. See [Appendix: Ad Formats](#appendix-ad-formats) for visual examples.<br>**A/B Testing:** Pass an array to automatically A/B test different formats and let Simula pick the best over time. |
|
|
124
|
+
| `theme` | `SimulaTheme` | β | `{ theme: 'auto', width: 'auto', accent: ['neutral','image'], font: 'sans-serif', cornerRadius: 8 }` | Customize ad appearance (see Theme Options). Arrays trigger A/B testing. |
|
|
125
|
+
| `charDesc` | `string` | β | `undefined` | Character description for additional context to improve ad targeting. |
|
|
126
|
+
| `debounceMs` | `number` | β | `0` | Delay in milliseconds before fetching. |
|
|
127
|
+
| `onImpression` | `(ad: AdData) => void` | β | `undefined` | Callback when ad is viewable (50% visible for β₯1s). |
|
|
128
|
+
| `onClick` | `(ad: AdData) => void` | β | `undefined` | Callback when ad is clicked. |
|
|
129
|
+
| `onError` | `(err: Error) => void` | β | `undefined` | Callback when ad fails or no-fill occurs. |
|
|
130
|
+
|
|
131
|
+
**Behavior:**
|
|
132
|
+
|
|
133
|
+
* Fetches **once** per slot (static)
|
|
134
|
+
* Triggers on **viewport visibility** (50% visible)
|
|
135
|
+
* Includes built-in **bot protection**
|
|
136
|
+
* Tracks impressions **MRC-compliantly**
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## π¨ Theme Options
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
interface SimulaTheme {
|
|
144
|
+
theme?: "light" | "dark" | "auto"; // default: "auto"
|
|
145
|
+
accent?: AccentOption | AccentOption[]; // default: ["neutral", "image"] (A/B tested)
|
|
146
|
+
font?: FontOption | FontOption[]; // default: "sans-serif"
|
|
147
|
+
width?: number | string; // default: "auto" (min 320px)
|
|
148
|
+
cornerRadius?: number; // default: 8
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Modes:** `light` | `dark` | `auto`
|
|
153
|
+
**Accents:**
|
|
154
|
+
`blue`, `red`, `green`, `yellow`, `purple`, `pink`, `orange`, `neutral`, `gray`, `tan`, `transparent`, `image`
|
|
155
|
+
**Fonts:** `sans-serif`, `serif`, `monospace`
|
|
156
|
+
|
|
157
|
+
> **Height:** fixed at **265px**
|
|
158
|
+
> **Width:** min **320px**, accepts px/%, or `auto`
|
|
159
|
+
|
|
160
|
+
> **A/B Testing:**
|
|
161
|
+
> When you pass an **array** (e.g., `accent: ['blue', 'green', 'purple']`), Simula will **automatically A/B test** across the provided optionsβcolors, fonts, or formatsβand **optimize over time for the best-performing variant**.
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
// Default theme (auto)
|
|
165
|
+
<InChatAdSlot messages={messages} />
|
|
166
|
+
|
|
167
|
+
// Light theme
|
|
168
|
+
<InChatAdSlot messages={messages} theme={{ theme: "light", accent: "blue" }} />
|
|
169
|
+
|
|
170
|
+
// Dark theme with custom width
|
|
171
|
+
<InChatAdSlot
|
|
172
|
+
messages={messages}
|
|
173
|
+
theme={{ theme: "dark", accent: "purple", width: 600, cornerRadius: 12 }}
|
|
174
|
+
/>
|
|
175
|
+
|
|
176
|
+
// A/B testing
|
|
177
|
+
<InChatAdSlot
|
|
178
|
+
messages={messages}
|
|
179
|
+
theme={{
|
|
180
|
+
accent: ["blue", "green", "purple"], // A/B test colors
|
|
181
|
+
font: ["sans-serif", "serif"], // A/B test fonts
|
|
182
|
+
width: "100%"
|
|
183
|
+
}}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## π¬ Integration Example
|
|
190
|
+
|
|
191
|
+
### Chat App with OpenAI
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import { useState } from "react";
|
|
195
|
+
import { SimulaProvider, InChatAdSlot } from "@simula/ads";
|
|
196
|
+
import OpenAI from "openai";
|
|
197
|
+
|
|
198
|
+
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
199
|
+
|
|
200
|
+
export default function App() {
|
|
201
|
+
return (
|
|
202
|
+
<div>
|
|
203
|
+
<Header />
|
|
204
|
+
<ChatApp /> {/* Each conversation has its own SimulaProvider */}
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function ChatApp() {
|
|
210
|
+
const [messages, setMessages] = useState([]);
|
|
211
|
+
const [input, setInput] = useState("");
|
|
212
|
+
const [loading, setLoading] = useState(false);
|
|
213
|
+
|
|
214
|
+
async function sendMessage() {
|
|
215
|
+
if (!input.trim()) return;
|
|
216
|
+
|
|
217
|
+
const userMessage = { role: "user", content: input.trim() };
|
|
218
|
+
const newMessages = [...messages, userMessage];
|
|
219
|
+
setMessages(newMessages);
|
|
220
|
+
setInput("");
|
|
221
|
+
setLoading(true);
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
const llmPromise = client.chat.completions.create({
|
|
225
|
+
model: "gpt-4o-mini",
|
|
226
|
+
messages: newMessages,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const res = await llmPromise;
|
|
230
|
+
const reply = res.choices[0].message;
|
|
231
|
+
|
|
232
|
+
setMessages((prev) => [...prev, { ...reply, llmPromise }]);
|
|
233
|
+
} finally {
|
|
234
|
+
setLoading(false);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<SimulaProvider apiKey="SIMULA_xxx">
|
|
240
|
+
<div className="chat">
|
|
241
|
+
{messages.map((msg, i) => (
|
|
242
|
+
<div key={i}>
|
|
243
|
+
<p><strong>{msg.role}:</strong> {msg.content}</p>
|
|
244
|
+
|
|
245
|
+
{msg.role === "assistant" && (
|
|
246
|
+
<InChatAdSlot
|
|
247
|
+
key={`adslot-${i}`} // β
Required if rendering in a list
|
|
248
|
+
trigger={msg.llmPromise} // default: fires immediately if not provided
|
|
249
|
+
messages={messages.slice(0, i + 1)}
|
|
250
|
+
formats="all"
|
|
251
|
+
theme={{ theme: "light", accent: "blue", width: "auto" }}
|
|
252
|
+
/>
|
|
253
|
+
)}
|
|
254
|
+
</div>
|
|
255
|
+
))}
|
|
256
|
+
|
|
257
|
+
<input
|
|
258
|
+
value={input}
|
|
259
|
+
onChange={(e) => setInput(e.target.value)}
|
|
260
|
+
onKeyDown={(e) => e.key === "Enter" && sendMessage()}
|
|
261
|
+
/>
|
|
262
|
+
<button onClick={sendMessage} disabled={loading}>Send</button>
|
|
263
|
+
</div>
|
|
264
|
+
</SimulaProvider>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
> **Tips:**
|
|
270
|
+
>
|
|
271
|
+
> * **Wrap `SimulaProvider` around the chat component** β This treats each conversation as a separate session for better ad targeting.
|
|
272
|
+
> * Use `key` prop when `<InChatAdSlot />` is rendered inside a list or dynamic loop.
|
|
273
|
+
> * The `trigger` prop waits for the LLM response before fetching ads. If omitted, the ad fetches immediately when viewable.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## π Features
|
|
278
|
+
|
|
279
|
+
* **Contextual Targeting** β AI-powered ad matching to conversation content
|
|
280
|
+
* **Bot Protection** β via [@fingerprintjs/botd](https://github.com/fingerprintjs/botd)
|
|
281
|
+
* **MRC-Compliant Viewability** β 50% visible for β₯1s
|
|
282
|
+
* **Responsive** β Flexible widths with enforced minimums
|
|
283
|
+
* **Static Fetch** β Each slot fetches once and stays fixed
|
|
284
|
+
* **Session Management** β Automatic
|
|
285
|
+
* **Robust Error Handling** β Graceful degradation & callbacks
|
|
286
|
+
* **TypeScript Support** β Built-in type definitions
|
|
287
|
+
* **Built-in A/B Testing** β Test multiple colors, formats, or fonts by passing arrays and let Simula optimize performance over time
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## βοΈ Advanced Usage
|
|
292
|
+
|
|
293
|
+
### Event Handlers
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
<InChatAdSlot
|
|
297
|
+
messages={messages}
|
|
298
|
+
onImpression={(ad) => console.log("Impression:", ad.id)} // default: none
|
|
299
|
+
onClick={(ad) => console.log("Clicked:", ad.id)} // default: none
|
|
300
|
+
onError={(err) => console.error("Ad error:", err)} // default: none
|
|
301
|
+
/>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Debounce Fetching
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
<InChatAdSlot
|
|
308
|
+
messages={messages}
|
|
309
|
+
debounceMs={500} // default: 0
|
|
310
|
+
/>
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## π¦ TypeScript Types
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
import type {
|
|
319
|
+
SimulaTheme,
|
|
320
|
+
Message,
|
|
321
|
+
AdData,
|
|
322
|
+
InChatAdSlotProps,
|
|
323
|
+
SimulaProviderProps
|
|
324
|
+
} from "@simula/ads";
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## π Resources
|
|
330
|
+
|
|
331
|
+
* [Website](https://simula.ad)
|
|
332
|
+
* [GitHub Issues](https://github.com/Simula-AI-SDK/simula-ad-sdk/issues)
|
|
333
|
+
* Support: **[admin@simula.ad](mailto:admin@simula.ad)**
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## π License
|
|
338
|
+
|
|
339
|
+
MIT
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## π Appendix: Ad Formats
|
|
344
|
+
|
|
345
|
+
Visual examples of all available ad formats across mobile and desktop:
|
|
346
|
+
|
|
347
|
+
| Format | Mobile | Desktop |
|
|
348
|
+
|--------|--------|---------|
|
|
349
|
+
| **tips** | <img src="./assets/tips_mobile.png" width="200" alt="Tips format on mobile" /> | <img src="./assets/tips_desktop.png" width="400" alt="Tips format on desktop" /> |
|
|
350
|
+
| **interactive** | <img src="./assets/interactive_mobile.png" width="200" alt="Interactive format on mobile" /> | <img src="./assets/interactive_desktop.png" width="400" alt="Interactive format on desktop" /> |
|
|
351
|
+
| **suggestions** | <img src="./assets/suggestions_mobile.png" width="200" alt="Suggestions format on mobile" /> | <img src="./assets/suggestions_desktop.png" width="400" alt="Suggestions format on desktop" /> |
|
|
352
|
+
| **text** | <img src="./assets/text_mobile.png" width="200" alt="Text format on mobile" /> | <img src="./assets/text_desktop.png" width="400" alt="Text format on desktop" /> |
|
|
353
|
+
| **highlight** | <img src="./assets/highlight_mobile.png" width="200" alt="Highlight format on mobile" /> | <img src="./assets/highlight_desktop.png" width="400" alt="Highlight format on desktop" /> |
|
|
354
|
+
| **visual_banner** | <img src="./assets/visual_banner_mobile.png" width="200" alt="Visual banner format on mobile" /> | <img src="./assets/visual_banner_desktop.png" width="400" alt="Visual banner format on desktop" /> |
|
|
355
|
+
| **image_feature** | <img src="./assets/image_feature_mobile.png" width="200" alt="Image feature format on mobile" /> | <img src="./assets/image_feature_desktop.png" width="400" alt="Image feature format on desktop" /> |
|
|
356
|
+
|
|
357
|
+
> **Note:** The `'all'` format allows Simula to automatically select the best format based on context and performance.
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## π Appendix: Invalid Format & Accent Combinations
|
|
362
|
+
|
|
363
|
+
Certain ad formats have restrictions on which accent colors can be used. **These restrictions only apply when you specify an invalid combination with no other valid options.** When A/B testing with arrays, Simula automatically selects valid combinations from the available options.
|
|
364
|
+
|
|
365
|
+
| Format | Allowed Accents | Restrictions |
|
|
366
|
+
|--------|----------------|--------------|
|
|
367
|
+
| **interactive** | All colors, `'image'`, `'neutral'`, `'gray'`, `'tan'` | β Cannot use `'transparent'` |
|
|
368
|
+
| **tips** | All colors, `'image'`, `'neutral'`, `'gray'`, `'tan'` | β Cannot use `'transparent'` |
|
|
369
|
+
| **text** | **Only** `'transparent'` | β Cannot use colors or `'image'` |
|
|
370
|
+
| **highlight** | All colors, `'image'`, `'neutral'`, `'gray'`, `'tan'` | β Cannot use `'transparent'` |
|
|
371
|
+
| **visual_banner** | All colors, `'neutral'`, `'gray'`, `'tan'` | β Cannot use `'image'` or `'transparent'` |
|
|
372
|
+
| **image_feature** | All colors, `'neutral'`, `'gray'`, `'tan'` | β Cannot use `'image'` or `'transparent'` |
|
|
373
|
+
| **suggestions** | All accents allowed | β
No restrictions |
|
|
374
|
+
|
|
375
|
+
**Color accents:** `'blue'`, `'red'`, `'green'`, `'yellow'`, `'purple'`, `'pink'`, `'orange'`, `'neutral'`, `'gray'`, `'tan'`
|
|
376
|
+
|
|
377
|
+
### Examples
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
// β
Valid - single format, single accent
|
|
381
|
+
<InChatAdSlot formats="interactive" theme={{ accent: "blue" }} />
|
|
382
|
+
<InChatAdSlot formats="text" theme={{ accent: "transparent" }} />
|
|
383
|
+
<InChatAdSlot formats="visual_banner" theme={{ accent: "purple" }} />
|
|
384
|
+
|
|
385
|
+
// β
Valid - A/B testing with arrays (Simula auto-selects valid combinations)
|
|
386
|
+
<InChatAdSlot
|
|
387
|
+
formats={['text', 'highlight']}
|
|
388
|
+
theme={{ accent: ['image', 'transparent'] }}
|
|
389
|
+
/>
|
|
390
|
+
// If 'text' is selected β uses 'transparent' (skips 'image')
|
|
391
|
+
// If 'highlight' is selected β uses 'image' (skips 'transparent')
|
|
392
|
+
|
|
393
|
+
<InChatAdSlot
|
|
394
|
+
formats={['interactive', 'visual_banner']}
|
|
395
|
+
theme={{ accent: ['blue', 'transparent'] }}
|
|
396
|
+
/>
|
|
397
|
+
// If 'interactive' is selected β uses 'blue' (skips 'transparent')
|
|
398
|
+
// If 'visual_banner' is selected β uses 'blue' (skips 'transparent')
|
|
399
|
+
|
|
400
|
+
// β Invalid - no valid options available
|
|
401
|
+
<InChatAdSlot formats="interactive" theme={{ accent: "transparent" }} /> // interactive cannot use transparent (no fallback)
|
|
402
|
+
<InChatAdSlot formats="text" theme={{ accent: "blue" }} /> // text can ONLY use transparent (no fallback)
|
|
403
|
+
<InChatAdSlot formats="text" theme={{ accent: ['blue', 'red', 'image'] }} /> // text needs transparent but none provided
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
> **Key Point:** Restrictions only matter when there are **no valid alternatives**. When A/B testing with multiple formats or accents, Simula intelligently matches compatible combinations.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InChatAdSlot.d.ts","sourceRoot":"","sources":["../src/InChatAdSlot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AASjF,OAAO,EAAE,iBAAiB,EAAU,MAAM,SAAS,CAAC;AAepD,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAyXpD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SimulaProviderProps, SimulaContextValue } from './types';
|
|
3
|
+
export declare const useSimula: () => SimulaContextValue;
|
|
4
|
+
export declare const SimulaProvider: React.FC<SimulaProviderProps>;
|
|
5
|
+
//# sourceMappingURL=SimulaProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SimulaProvider.d.ts","sourceRoot":"","sources":["../src/SimulaProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyD,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAMlE,eAAO,MAAM,SAAS,QAAO,kBAM5B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAmCxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBotDetection.d.ts","sourceRoot":"","sources":["../../src/hooks/useBotDetection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C,eAAO,MAAM,eAAe,QAAO,kBAmClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDebounce.d.ts","sourceRoot":"","sources":["../../src/hooks/useDebounce.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,IAAI,EAAE,OAAO,MAAM,EAAE,MAAM,GAAG,EAAE,SAwB3E,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface OMIDViewabilityResult {
|
|
2
|
+
isViewable: boolean;
|
|
3
|
+
hasBeenViewed: boolean;
|
|
4
|
+
impressionTracked: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface OMIDOptions {
|
|
7
|
+
threshold?: number;
|
|
8
|
+
durationMs?: number;
|
|
9
|
+
partnerName?: string;
|
|
10
|
+
partnerVersion?: string;
|
|
11
|
+
onImpressionTracked?: (adId: string) => void;
|
|
12
|
+
}
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
omidSessionClient?: any;
|
|
16
|
+
omidSessionService?: any;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export declare const useOMIDViewability: (options?: OMIDOptions) => OMIDViewabilityResult & {
|
|
20
|
+
elementRef: React.RefObject<HTMLDivElement>;
|
|
21
|
+
trackImpression: (adId?: string) => void;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=useOMIDViewability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOMIDViewability.d.ts","sourceRoot":"","sources":["../../src/hooks/useOMIDViewability.ts"],"names":[],"mappings":"AAEA,UAAU,qBAAqB;IAC7B,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iBAAiB,CAAC,EAAE,GAAG,CAAC;QACxB,kBAAkB,CAAC,EAAE,GAAG,CAAC;KAC1B;CACF;AAED,eAAO,MAAM,kBAAkB,GAAI,UAAS,WAAgB,KAAG,qBAAqB,GAAG;IACrF,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC5C,eAAe,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CA0P1C,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ViewabilityResult, ViewabilityOptions } from '../types';
|
|
2
|
+
export declare const useViewability: (options?: ViewabilityOptions) => ViewabilityResult & {
|
|
3
|
+
elementRef: React.RefObject<HTMLDivElement>;
|
|
4
|
+
trackImpression: (adId?: string) => void;
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=useViewability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useViewability.d.ts","sourceRoot":"","sources":["../../src/hooks/useViewability.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEtE,eAAO,MAAM,cAAc,GAAI,UAAS,kBAAuB,KAAG,iBAAiB,GAAG;IACpF,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC5C,eAAe,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CA8E1C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import React$1 from 'react';
|
|
2
|
+
|
|
3
|
+
type AccentOption = 'blue' | 'red' | 'green' | 'yellow' | 'purple' | 'pink' | 'orange' | 'neutral' | 'gray' | 'tan' | 'transparent' | 'image';
|
|
4
|
+
type FontOption = 'san-serif' | 'serif' | 'monospace';
|
|
5
|
+
interface SimulaTheme {
|
|
6
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
7
|
+
accent?: AccentOption | AccentOption[];
|
|
8
|
+
font?: FontOption | FontOption[];
|
|
9
|
+
width?: number | string;
|
|
10
|
+
cornerRadius?: number;
|
|
11
|
+
}
|
|
12
|
+
interface ColorPalette$1 {
|
|
13
|
+
backgroundGradient1: string;
|
|
14
|
+
backgroundGradient2: string;
|
|
15
|
+
primary: string;
|
|
16
|
+
primaryHover: string;
|
|
17
|
+
secondary: string;
|
|
18
|
+
text: string;
|
|
19
|
+
border: string;
|
|
20
|
+
buttonText: string;
|
|
21
|
+
}
|
|
22
|
+
interface FontPalette$1 {
|
|
23
|
+
primary: string;
|
|
24
|
+
secondary: string;
|
|
25
|
+
}
|
|
26
|
+
interface Message {
|
|
27
|
+
role: string;
|
|
28
|
+
content: string;
|
|
29
|
+
}
|
|
30
|
+
interface AdData {
|
|
31
|
+
id: string;
|
|
32
|
+
format: string;
|
|
33
|
+
iframeUrl?: string;
|
|
34
|
+
}
|
|
35
|
+
interface InChatAdSlotProps {
|
|
36
|
+
messages: Message[];
|
|
37
|
+
trigger?: Promise<any>;
|
|
38
|
+
formats?: string | string[];
|
|
39
|
+
theme?: SimulaTheme;
|
|
40
|
+
debounceMs?: number;
|
|
41
|
+
charDesc?: string;
|
|
42
|
+
onImpression?: (ad: AdData) => void;
|
|
43
|
+
onClick?: (ad: AdData) => void;
|
|
44
|
+
onError?: (error: Error) => void;
|
|
45
|
+
}
|
|
46
|
+
interface SimulaProviderProps {
|
|
47
|
+
apiKey: string;
|
|
48
|
+
children: React.ReactNode;
|
|
49
|
+
devMode?: boolean;
|
|
50
|
+
primaryUserID?: string;
|
|
51
|
+
}
|
|
52
|
+
interface SimulaContextValue {
|
|
53
|
+
apiKey: string;
|
|
54
|
+
devMode: boolean;
|
|
55
|
+
sessionId?: string;
|
|
56
|
+
}
|
|
57
|
+
interface BotDetectionResult {
|
|
58
|
+
isBot: boolean;
|
|
59
|
+
reasons: string[];
|
|
60
|
+
}
|
|
61
|
+
interface OMIDViewabilityOptions {
|
|
62
|
+
threshold?: number;
|
|
63
|
+
durationMs?: number;
|
|
64
|
+
partnerName?: string;
|
|
65
|
+
partnerVersion?: string;
|
|
66
|
+
onImpressionTracked?: (adId: string) => void;
|
|
67
|
+
}
|
|
68
|
+
interface OMIDViewabilityResult$1 {
|
|
69
|
+
isViewable: boolean;
|
|
70
|
+
hasBeenViewed: boolean;
|
|
71
|
+
impressionTracked: boolean;
|
|
72
|
+
}
|
|
73
|
+
interface ViewabilityOptions {
|
|
74
|
+
threshold?: number;
|
|
75
|
+
durationMs?: number;
|
|
76
|
+
onImpressionTracked?: (adId: string) => void;
|
|
77
|
+
}
|
|
78
|
+
interface ViewabilityResult {
|
|
79
|
+
isViewable: boolean;
|
|
80
|
+
isInstantViewable: boolean;
|
|
81
|
+
hasBeenViewed: boolean;
|
|
82
|
+
impressionTracked: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
declare const useSimula: () => SimulaContextValue;
|
|
86
|
+
declare const SimulaProvider: React$1.FC<SimulaProviderProps>;
|
|
87
|
+
|
|
88
|
+
declare const InChatAdSlot: React$1.FC<InChatAdSlotProps>;
|
|
89
|
+
|
|
90
|
+
declare const useBotDetection: () => BotDetectionResult;
|
|
91
|
+
|
|
92
|
+
declare const useViewability: (options?: ViewabilityOptions) => ViewabilityResult & {
|
|
93
|
+
elementRef: React.RefObject<HTMLDivElement>;
|
|
94
|
+
trackImpression: (adId?: string) => void;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
interface OMIDViewabilityResult {
|
|
98
|
+
isViewable: boolean;
|
|
99
|
+
hasBeenViewed: boolean;
|
|
100
|
+
impressionTracked: boolean;
|
|
101
|
+
}
|
|
102
|
+
interface OMIDOptions {
|
|
103
|
+
threshold?: number;
|
|
104
|
+
durationMs?: number;
|
|
105
|
+
partnerName?: string;
|
|
106
|
+
partnerVersion?: string;
|
|
107
|
+
onImpressionTracked?: (adId: string) => void;
|
|
108
|
+
}
|
|
109
|
+
declare global {
|
|
110
|
+
interface Window {
|
|
111
|
+
omidSessionClient?: any;
|
|
112
|
+
omidSessionService?: any;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
declare const useOMIDViewability: (options?: OMIDOptions) => OMIDViewabilityResult & {
|
|
116
|
+
elementRef: React.RefObject<HTMLDivElement>;
|
|
117
|
+
trackImpression: (adId?: string) => void;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
interface ColorPalette {
|
|
121
|
+
background: string;
|
|
122
|
+
text: string;
|
|
123
|
+
primary: string;
|
|
124
|
+
primaryHover: string;
|
|
125
|
+
border: string;
|
|
126
|
+
}
|
|
127
|
+
interface FontPalette {
|
|
128
|
+
primary: string;
|
|
129
|
+
secondary: string;
|
|
130
|
+
}
|
|
131
|
+
declare const fonts: Record<string, FontPalette>;
|
|
132
|
+
declare function getColorTheme(themeMode: 'light' | 'dark' | 'auto', _accent?: string): ColorPalette;
|
|
133
|
+
declare const getSolidBackground: (colors: ColorPalette) => string;
|
|
134
|
+
declare const getBackgroundGradient: (colors: ColorPalette) => string;
|
|
135
|
+
declare const getTextMuted: (colors: ColorPalette) => string;
|
|
136
|
+
declare const getTextSecondary: (colors: ColorPalette) => string;
|
|
137
|
+
declare const getBorderLight: (colors: ColorPalette) => string;
|
|
138
|
+
declare const getShadow: (colors: ColorPalette) => string;
|
|
139
|
+
declare const getFontStyles: (font?: string) => FontPalette;
|
|
140
|
+
|
|
141
|
+
export { InChatAdSlot, SimulaProvider, fonts, getBackgroundGradient, getBorderLight, getColorTheme, getFontStyles, getShadow, getSolidBackground, getTextMuted, getTextSecondary, useBotDetection, useOMIDViewability, useSimula, useViewability };
|
|
142
|
+
export type { AdData, BotDetectionResult, ColorPalette$1 as ColorPalette, FontPalette$1 as FontPalette, InChatAdSlotProps, Message, OMIDViewabilityOptions, OMIDViewabilityResult$1 as OMIDViewabilityResult, SimulaContextValue, SimulaProviderProps, SimulaTheme, ViewabilityOptions, ViewabilityResult };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAGhE,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,EACL,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,SAAS,EACV,MAAM,qBAAqB,CAAC;AAI7B,YAAY,EACV,WAAW,EACX,OAAO,EACP,MAAM,EACN,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACZ,MAAM,SAAS,CAAC"}
|