@coxwave/tap-sdk 0.0.3 → 0.0.5
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/README.md +114 -334
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.global.js +3 -3
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,390 +1,170 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @coxwave/tap-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A vanilla JavaScript SDK for embedding AI chat widgets into web applications with seamless iframe communication.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
- [Installation](#installation)
|
|
8
|
-
- [Quick Use](#quick-use)
|
|
9
|
-
- [Types](#types)
|
|
10
|
-
- [Legacy](#legacy)
|
|
11
|
-
- [License](#license)
|
|
12
|
-
|
|
13
|
-
## installation
|
|
14
|
-
|
|
15
|
-
### npm
|
|
5
|
+
## Installation
|
|
16
6
|
|
|
17
7
|
```bash
|
|
18
|
-
npm
|
|
8
|
+
npm install @coxwave/tap-sdk
|
|
19
9
|
```
|
|
20
10
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
yarn add ax-sdk-chatbot
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Quick Use
|
|
28
|
-
|
|
29
|
-
### vite
|
|
30
|
-
|
|
31
|
-
#### Use In Root
|
|
11
|
+
## Quick Start
|
|
32
12
|
|
|
33
|
-
```
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
import { createRoot } from "react-dom/client";
|
|
37
|
-
|
|
38
|
-
import TapSDK from "ax-sdk-chatbot";
|
|
39
|
-
|
|
40
|
-
import App from "./App.tsx";
|
|
41
|
-
|
|
42
|
-
import "./index.css";
|
|
13
|
+
```javascript
|
|
14
|
+
import TapSDK from "@coxwave/tap-sdk";
|
|
43
15
|
|
|
44
16
|
const sdk = new TapSDK({
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
isProd: false,
|
|
17
|
+
pluginKey: "your-plugin-key",
|
|
18
|
+
isProd: true,
|
|
48
19
|
});
|
|
49
20
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
sdk.initChat({
|
|
21
|
+
await sdk.initChat({
|
|
53
22
|
chatApiParams: {
|
|
54
|
-
userId: "
|
|
55
|
-
courseId: "
|
|
56
|
-
courseName: "
|
|
57
|
-
courseCategory: "
|
|
58
|
-
courseSubCategory: "
|
|
59
|
-
clipId:
|
|
60
|
-
clipPlayHead:
|
|
61
|
-
},
|
|
62
|
-
shortcutKey: {
|
|
63
|
-
openChat: { key: "/", modifier: "" },
|
|
64
|
-
sendChat: { key: "Enter", modifier: "" },
|
|
65
|
-
},
|
|
66
|
-
customStyles: {
|
|
67
|
-
floatingButton: {
|
|
68
|
-
isInElement: true,
|
|
69
|
-
parentElementId: "root-button", // <------ here is your Floating Button parent element Id
|
|
70
|
-
},
|
|
23
|
+
userId: "user-123",
|
|
24
|
+
courseId: "course-456",
|
|
25
|
+
courseName: "JavaScript Fundamentals",
|
|
26
|
+
courseCategory: "Programming",
|
|
27
|
+
courseSubCategory: "Frontend",
|
|
28
|
+
clipId: null,
|
|
29
|
+
clipPlayHead: null,
|
|
71
30
|
},
|
|
72
31
|
});
|
|
32
|
+
```
|
|
73
33
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
import { useEffect, useState } from "react";
|
|
77
|
-
|
|
78
|
-
import "./App.css";
|
|
34
|
+
## Features
|
|
79
35
|
|
|
80
|
-
|
|
36
|
+
- 🎯 **Iframe Communication** - Secure cross-origin messaging with handshake protocol
|
|
37
|
+
- 🎨 **Customizable UI** - Floating button, chat body, and popup styling
|
|
38
|
+
- 📊 **Event System** - Timeline sync, chat events, alarms, and PDF integration
|
|
39
|
+
- 🔔 **Smart Notifications** - Auto-fading alarm system with custom styling
|
|
40
|
+
- 📱 **Responsive Design** - Mobile-friendly with automatic positioning
|
|
41
|
+
- 🚀 **Zero Dependencies** - Self-contained with tree-shaking optimization
|
|
81
42
|
|
|
82
|
-
|
|
83
|
-
const [clipPlayHead, setClipPlayHead] = useState(0);
|
|
43
|
+
## API Reference
|
|
84
44
|
|
|
85
|
-
|
|
86
|
-
const interval = setInterval(() => {
|
|
87
|
-
setClipPlayHead((prev) => prev + 5);
|
|
88
|
-
}, 1000);
|
|
45
|
+
### Constructor
|
|
89
46
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
sdk.postChatInfo({
|
|
95
|
-
clipId: "58767",
|
|
96
|
-
clipPlayHead,
|
|
97
|
-
});
|
|
98
|
-
}, [clipPlayHead]);
|
|
99
|
-
|
|
100
|
-
return (
|
|
101
|
-
<>
|
|
102
|
-
<div id="root-button">{Your Floating Button styles Element}</div> // <------ This is your floating button parent element. It must have the same ID as parentElementId.
|
|
103
|
-
</>
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export default App;
|
|
47
|
+
```javascript
|
|
48
|
+
new TapSDK(options);
|
|
108
49
|
```
|
|
109
50
|
|
|
110
|
-
|
|
51
|
+
**Options:**
|
|
111
52
|
|
|
112
|
-
-
|
|
53
|
+
- `pluginKey` (string) - Your unique plugin identifier
|
|
54
|
+
- `isProd` (boolean) - Production mode flag (default: false)
|
|
55
|
+
- `isLocal` (boolean) - Local development flag (default: false)
|
|
113
56
|
|
|
114
|
-
|
|
115
|
-
import { useEffect, useState } from "react";
|
|
57
|
+
### Methods
|
|
116
58
|
|
|
117
|
-
|
|
59
|
+
#### `initChat(config)`
|
|
118
60
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
61
|
+
```javascript
|
|
62
|
+
await sdk.initChat({
|
|
63
|
+
chatApiParams: {
|
|
64
|
+
userId: string,
|
|
65
|
+
courseId: string | null,
|
|
66
|
+
courseName: string,
|
|
67
|
+
courseCategory: string,
|
|
68
|
+
courseSubCategory: string,
|
|
69
|
+
clipId: string | null,
|
|
70
|
+
clipPlayHead: number | null
|
|
71
|
+
},
|
|
72
|
+
customStyles?: {
|
|
73
|
+
floatingButton?: {
|
|
74
|
+
isInElement?: boolean,
|
|
75
|
+
parentElementId?: string,
|
|
76
|
+
style?: Partial<CSSStyleDeclaration>
|
|
77
|
+
},
|
|
78
|
+
chatBody?: {
|
|
79
|
+
position?: { top?: string, right?: string, left?: string, bottom?: string },
|
|
80
|
+
width?: string,
|
|
81
|
+
height?: string,
|
|
82
|
+
borderRadius?: string
|
|
83
|
+
}
|
|
84
|
+
}
|
|
125
85
|
});
|
|
86
|
+
```
|
|
126
87
|
|
|
88
|
+
#### `seekTimeline(params)`
|
|
127
89
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
userId: "user_id",
|
|
135
|
-
courseId: "course_id",
|
|
136
|
-
courseName: "course_name",
|
|
137
|
-
courseCategory: "course_category",
|
|
138
|
-
courseSubCategory: "course_sub_category",
|
|
139
|
-
clipId: "clip_id",
|
|
140
|
-
clipPlayHead: clip_play_head_number,
|
|
141
|
-
},
|
|
142
|
-
customStyles: {
|
|
143
|
-
floatingButton: {
|
|
144
|
-
isInElement: true,
|
|
145
|
-
parentElementId: "root-button",
|
|
146
|
-
},
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
return () => {
|
|
151
|
-
sdk.removeChat(); // this is sdk cleanup function
|
|
152
|
-
};
|
|
153
|
-
}, []);
|
|
154
|
-
|
|
155
|
-
useEffect(() => {
|
|
156
|
-
const interval = setInterval(() => {
|
|
157
|
-
setClipPlayHead((prev) => prev + 5);
|
|
158
|
-
}, 1000);
|
|
159
|
-
|
|
160
|
-
return () => clearInterval(interval);
|
|
161
|
-
}, []);
|
|
162
|
-
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
sdk.postChatInfo({
|
|
165
|
-
clipId: "58767",
|
|
166
|
-
clipPlayHead,
|
|
167
|
-
});
|
|
168
|
-
}, [clipPlayHead]);
|
|
169
|
-
|
|
170
|
-
return (
|
|
171
|
-
<S.LayoutContainer $isWhiteBack={true}>
|
|
172
|
-
<S.ContentBox>
|
|
173
|
-
<S.RootButton id="root-button">
|
|
174
|
-
<S.BotImage src={BotImage} />
|
|
175
|
-
<S.Text>AI 튜터</S.Text>
|
|
176
|
-
</S.RootButton>
|
|
177
|
-
</S.ContentBox>
|
|
178
|
-
</S.LayoutContainer>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export default Test;
|
|
90
|
+
```javascript
|
|
91
|
+
sdk.seekTimeline({
|
|
92
|
+
clipId: "clip-123",
|
|
93
|
+
clipPlayHead: 150.5,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
183
96
|
|
|
184
|
-
|
|
185
|
-
~
|
|
186
|
-
} // your styles (this example is for styled-components)
|
|
97
|
+
#### `removeChat()`
|
|
187
98
|
|
|
99
|
+
```javascript
|
|
100
|
+
sdk.removeChat();
|
|
188
101
|
```
|
|
189
102
|
|
|
190
|
-
###
|
|
191
|
-
|
|
192
|
-
- page.tsx
|
|
103
|
+
### Event Listeners
|
|
193
104
|
|
|
194
|
-
```
|
|
195
|
-
|
|
105
|
+
```javascript
|
|
106
|
+
// Timeline seek events
|
|
107
|
+
sdk.events.onTimelineSeek((clipPlayHead, clipId) => {
|
|
108
|
+
console.log(`Seek to ${clipPlayHead}s in ${clipId}`);
|
|
109
|
+
});
|
|
196
110
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
);
|
|
201
|
-
}
|
|
111
|
+
// Chat state events
|
|
112
|
+
sdk.events.onChatOpened(() => console.log("Chat opened"));
|
|
113
|
+
sdk.events.onChatClosed(() => console.log("Chat closed"));
|
|
202
114
|
|
|
115
|
+
// Notification events
|
|
116
|
+
sdk.events.onAlarmFadeIn((messageInfo) => {
|
|
117
|
+
console.log("Alarm notification:", messageInfo);
|
|
118
|
+
});
|
|
203
119
|
```
|
|
204
120
|
|
|
205
|
-
|
|
121
|
+
## Framework Integration
|
|
206
122
|
|
|
207
|
-
|
|
208
|
-
"use client"; // if you use this sdk in Next.js, you must use this
|
|
123
|
+
### React
|
|
209
124
|
|
|
125
|
+
```jsx
|
|
210
126
|
import { useEffect, useRef } from "react";
|
|
127
|
+
import TapSDK from "@coxwave/tap-sdk";
|
|
211
128
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const clientUrl = process.env.NEXT_PUBLIC_HOST_CLIENT_URL; // your client url (if you use localhost, your client url is http://localhost:3000)
|
|
215
|
-
const pluginKey = process.env.NEXT_PUBLIC_COXWAVE_PLUGIN_KEY;
|
|
216
|
-
|
|
217
|
-
if (!clientUrl) {
|
|
218
|
-
throw new Error("NEXT_PUBLIC_COXWAVE_CLIENT_URL is not set");
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (!pluginKey) {
|
|
222
|
-
throw new Error("NEXT_PUBLIC_COXWAVE_PLUGIN_KEY is not set");
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function Sdk() {
|
|
226
|
-
const iframeRef = useRef<HTMLDivElement>(null);
|
|
129
|
+
function ChatWidget({ userId, courseId }) {
|
|
130
|
+
const sdkRef = useRef(null);
|
|
227
131
|
|
|
228
132
|
useEffect(() => {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
await TapSDKInstance.initChat({
|
|
239
|
-
chatApiParams: {
|
|
240
|
-
userId: "user_id",
|
|
241
|
-
courseId: "course_id",
|
|
242
|
-
courseName: "course_name",
|
|
243
|
-
courseCategory: "course_category",
|
|
244
|
-
courseSubCategory: "course_sub_category",
|
|
245
|
-
clipId: "clip_id",
|
|
246
|
-
clipPlayHead: clip_play_head_number,
|
|
247
|
-
},
|
|
248
|
-
customStyles: {
|
|
249
|
-
floatingButton: {
|
|
250
|
-
isInElement: true,
|
|
251
|
-
parentElementId: "root-button", // <------ here is your Floating Button parent element Id
|
|
252
|
-
},
|
|
253
|
-
},
|
|
254
|
-
});
|
|
255
|
-
} catch (err) {
|
|
256
|
-
console.error("SDK initChat 실패:", err);
|
|
257
|
-
}
|
|
133
|
+
const initSDK = async () => {
|
|
134
|
+
sdkRef.current = new TapSDK({
|
|
135
|
+
pluginKey: process.env.REACT_APP_TAP_PLUGIN_KEY,
|
|
136
|
+
isProd: process.env.NODE_ENV === "production",
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
await sdkRef.current.initChat({
|
|
140
|
+
chatApiParams: { userId, courseId /* ... */ },
|
|
141
|
+
});
|
|
258
142
|
};
|
|
259
143
|
|
|
260
|
-
|
|
144
|
+
initSDK();
|
|
145
|
+
return () => sdkRef.current?.removeChat();
|
|
146
|
+
}, [userId, courseId]);
|
|
261
147
|
|
|
262
|
-
|
|
263
|
-
TapSDKInstance.removeChat();
|
|
264
|
-
};
|
|
265
|
-
}, [clientUrl]);
|
|
266
|
-
|
|
267
|
-
return (
|
|
268
|
-
<div
|
|
269
|
-
ref={iframeRef}
|
|
270
|
-
id="root-button" // <------ This is your floating button parent element. It must have the same ID as parentElementId.
|
|
271
|
-
style={{
|
|
272
|
-
width: "50px",
|
|
273
|
-
height: "50px",
|
|
274
|
-
backgroundColor: "red",
|
|
275
|
-
cursor: "pointer",
|
|
276
|
-
}}
|
|
277
|
-
>
|
|
278
|
-
<button>Open Chat</button>
|
|
279
|
-
</div>
|
|
280
|
-
);
|
|
148
|
+
return <div id="chat-container" />;
|
|
281
149
|
}
|
|
282
|
-
|
|
283
|
-
export default Sdk;
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
## Types
|
|
287
|
-
|
|
288
|
-
### SDK Class
|
|
289
|
-
|
|
290
|
-
```ts
|
|
291
|
-
const TapSDKInstance = new TapSDK({
|
|
292
|
-
hostClientUrl: "~",
|
|
293
|
-
pluginKey: "~",
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
type TapSDKType = {
|
|
297
|
-
hostClientUrl: string;
|
|
298
|
-
pluginKey: string;
|
|
299
|
-
isProd?: boolean;
|
|
300
|
-
};
|
|
301
150
|
```
|
|
302
151
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
```ts
|
|
306
|
-
async initChat({
|
|
307
|
-
chatApiParams,
|
|
308
|
-
customStyles,
|
|
309
|
-
shortcutKey,
|
|
310
|
-
}: {
|
|
311
|
-
chatApiParams: ChatApiParamsType;
|
|
312
|
-
customStyles?: CustomStylesType;
|
|
313
|
-
shortcutKey?: ShortcutKeyType;
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
type ChatApiParamsType = {
|
|
317
|
-
userId: string;
|
|
318
|
-
courseId: string;
|
|
319
|
-
courseName: string;
|
|
320
|
-
courseCategory: string;
|
|
321
|
-
courseSubCategory: string;
|
|
322
|
-
clipId: string | null;
|
|
323
|
-
clipPlayHead: number | null;
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
type CustomStylesType = {
|
|
327
|
-
floatingButton?: FloatingButtonType;
|
|
328
|
-
chatBody?: ChatBodyType;
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
type ShortcutKeyType = {
|
|
332
|
-
openChat: ShortcutKeyPropertiesType;
|
|
333
|
-
sendChat: ShortcutKeyPropertiesType;
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
type FloatingButtonType = {
|
|
337
|
-
isInElement?: boolean;
|
|
338
|
-
parentElementId?: string;
|
|
339
|
-
style?: Partial<CSSStyleDeclaration>;
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
type ChatBodyType = {
|
|
343
|
-
position?: PositionType;
|
|
344
|
-
width?: string;
|
|
345
|
-
height?: string;
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
type PositionType = {
|
|
349
|
-
top?: string;
|
|
350
|
-
left?: string;
|
|
351
|
-
right?: string;
|
|
352
|
-
bottom?: string;
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
type ShortcutKeyPropertiesType = {
|
|
356
|
-
key: string;
|
|
357
|
-
modifier: "ctrlKey" | "altKey" | "shiftKey" | "metaKey" | "";
|
|
358
|
-
};
|
|
152
|
+
## Build Formats
|
|
359
153
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
```ts
|
|
365
|
-
postChatInfo({
|
|
366
|
-
clipId,
|
|
367
|
-
clipPlayHead,
|
|
368
|
-
}: {
|
|
369
|
-
clipId: string;
|
|
370
|
-
clipPlayHead: number;
|
|
371
|
-
})
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
- you must use postChatInfo method after initChat method
|
|
375
|
-
|
|
376
|
-
### removeChat Method
|
|
377
|
-
|
|
378
|
-
```ts
|
|
379
|
-
removeChat();
|
|
380
|
-
```
|
|
154
|
+
- **ESM**: `dist/index.mjs` - Modern ES modules
|
|
155
|
+
- **CJS**: `dist/index.js` - CommonJS for Node.js
|
|
156
|
+
- **IIFE**: `dist/index.global.js` - Browser global variable
|
|
157
|
+
- **Types**: `dist/index.d.ts` - TypeScript declarations
|
|
381
158
|
|
|
382
|
-
##
|
|
159
|
+
## Browser Support
|
|
383
160
|
|
|
384
|
-
|
|
161
|
+
- Chrome 60+
|
|
162
|
+
- Firefox 60+
|
|
163
|
+
- Safari 12+
|
|
164
|
+
- Edge 79+
|
|
385
165
|
|
|
386
|
-
##
|
|
166
|
+
## License
|
|
387
167
|
|
|
388
|
-
|
|
168
|
+
MIT
|
|
389
169
|
|
|
390
170
|
Copyright (c) 2025-present, Coxwave
|
package/dist/index.d.cts
CHANGED
|
@@ -40,7 +40,7 @@ declare class TapIframeBridge extends Messenger<ToTapMessage, FromTapMessage> {
|
|
|
40
40
|
hostClientUrl: string;
|
|
41
41
|
pluginKey: string;
|
|
42
42
|
});
|
|
43
|
-
protected isValidOrigin(
|
|
43
|
+
protected isValidOrigin(_event: MessageEvent): boolean;
|
|
44
44
|
protected getMessageTarget(): Window | null;
|
|
45
45
|
protected getTargetOrigin(): string;
|
|
46
46
|
renderIframe({ chatBody, isProd, isLocal, }: {
|
|
@@ -50,7 +50,7 @@ declare class TapIframeBridge extends Messenger<ToTapMessage, FromTapMessage> {
|
|
|
50
50
|
}): Promise<HTMLIFrameElement>;
|
|
51
51
|
hasIframe(): boolean;
|
|
52
52
|
removeIframe(): void;
|
|
53
|
-
get postToTap(): (message: ToTapMessage) => boolean;
|
|
53
|
+
get postToTap(): (() => void) | ((message: ToTapMessage) => boolean);
|
|
54
54
|
listenToTap: <T extends "timeline:seek" | "chat:opened" | "chat:initiated" | "chat:closed" | "alarm:fadeIn" | "popUp:open" | "pdf:open" | "pdf:close">(messageType: T, callback: (data: Extract<TimelineSeekMessage, {
|
|
55
55
|
type: T;
|
|
56
56
|
}> | Extract<ChatInitiatedMessage, {
|
package/dist/index.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ declare class TapIframeBridge extends Messenger<ToTapMessage, FromTapMessage> {
|
|
|
40
40
|
hostClientUrl: string;
|
|
41
41
|
pluginKey: string;
|
|
42
42
|
});
|
|
43
|
-
protected isValidOrigin(
|
|
43
|
+
protected isValidOrigin(_event: MessageEvent): boolean;
|
|
44
44
|
protected getMessageTarget(): Window | null;
|
|
45
45
|
protected getTargetOrigin(): string;
|
|
46
46
|
renderIframe({ chatBody, isProd, isLocal, }: {
|
|
@@ -50,7 +50,7 @@ declare class TapIframeBridge extends Messenger<ToTapMessage, FromTapMessage> {
|
|
|
50
50
|
}): Promise<HTMLIFrameElement>;
|
|
51
51
|
hasIframe(): boolean;
|
|
52
52
|
removeIframe(): void;
|
|
53
|
-
get postToTap(): (message: ToTapMessage) => boolean;
|
|
53
|
+
get postToTap(): (() => void) | ((message: ToTapMessage) => boolean);
|
|
54
54
|
listenToTap: <T extends "timeline:seek" | "chat:opened" | "chat:initiated" | "chat:closed" | "alarm:fadeIn" | "popUp:open" | "pdf:open" | "pdf:close">(messageType: T, callback: (data: Extract<TimelineSeekMessage, {
|
|
55
55
|
type: T;
|
|
56
56
|
}> | Extract<ChatInitiatedMessage, {
|