@coxwave/tap-sdk 0.0.1

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 ADDED
@@ -0,0 +1,390 @@
1
+ # ax-sdk-chatbot
2
+
3
+ ## version: 1.1.0
4
+
5
+ ## 📚 Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Use](#quick-use)
9
+ - [Types](#types)
10
+ - [Legacy](#legacy)
11
+ - [License](#license)
12
+
13
+ ## installation
14
+
15
+ ### npm
16
+
17
+ ```bash
18
+ npm i ax-sdk-chatbot
19
+ ```
20
+
21
+ ### yarn
22
+
23
+ ```bash
24
+ yarn add ax-sdk-chatbot
25
+ ```
26
+
27
+ ## Quick Use
28
+
29
+ ### vite
30
+
31
+ #### Use In Root
32
+
33
+ ```ts
34
+ -main.tsx;
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";
43
+
44
+ const sdk = new TapSDK({
45
+ hostClientUrl: import.meta.env.VITE_CLIENT_URL, // your client url (if you use localhost, your client url is http://localhost:5173)
46
+ pluginKey: import.meta.env.VITE_FIRSTBRAIN_PLUGIN_KEY,
47
+ isProd: false,
48
+ });
49
+
50
+ createRoot(document.getElementById("root")!).render(<App />);
51
+
52
+ sdk.initChat({
53
+ chatApiParams: {
54
+ userId: "user_id",
55
+ courseId: "course_id",
56
+ courseName: "course_name",
57
+ courseCategory: "course_category",
58
+ courseSubCategory: "course_sub_category",
59
+ clipId: "clip_id",
60
+ clipPlayHead: clip_play_head_number,
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
+ },
71
+ },
72
+ });
73
+
74
+ -App.tsx;
75
+
76
+ import { useEffect, useState } from "react";
77
+
78
+ import "./App.css";
79
+
80
+ import TapSDK from "coxwave-sdk";
81
+
82
+ function App({ sdk }: { sdk: TapSDK }) {
83
+ const [clipPlayHead, setClipPlayHead] = useState(0);
84
+
85
+ useEffect(() => {
86
+ const interval = setInterval(() => {
87
+ setClipPlayHead((prev) => prev + 5);
88
+ }, 1000);
89
+
90
+ return () => clearInterval(interval);
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;
108
+ ```
109
+
110
+ #### Use Custom Hook (with useEffect)
111
+
112
+ - Test.tsx (can use any component)
113
+
114
+ ```ts
115
+ import { useEffect, useState } from "react";
116
+
117
+ import TapSDK from "ax-sdk-chatbot";
118
+
119
+ import BotImage from "./assets/quick-menu.png";
120
+
121
+ const sdk = new TapSDK({
122
+ hostClientUrl: import.meta.env.VITE_CLIENT_URL,
123
+ pluginKey: import.meta.env.VITE_FIRSTBRAIN_PLUGIN_KEY,
124
+ isProd: import.meta.env.VITE_IS_PROD === "true",
125
+ });
126
+
127
+
128
+ function Test() {
129
+ const [clipPlayHead, setClipPlayHead] = useState(0);
130
+
131
+ useEffect(() => {
132
+ sdk.initChat({
133
+ chatApiParams: {
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;
183
+
184
+ const S = {
185
+ ~
186
+ } // your styles (this example is for styled-components)
187
+
188
+ ```
189
+
190
+ ### Next.js
191
+
192
+ - page.tsx
193
+
194
+ ```ts
195
+ import Sdk from "./Sdk";
196
+
197
+ export default function Home() {
198
+ return (
199
+ <Sdk />
200
+ );
201
+ }
202
+
203
+ ```
204
+
205
+ - Sdk.tsx
206
+
207
+ ```ts
208
+ "use client"; // if you use this sdk in Next.js, you must use this
209
+
210
+ import { useEffect, useRef } from "react";
211
+
212
+ import TapSDK from "ax-sdk-chatbot";
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);
227
+
228
+ useEffect(() => {
229
+ if (!clientUrl || !pluginKey) return;
230
+
231
+ const TapSDKInstance = new TapSDK({
232
+ hostClientUrl: clientUrl,
233
+ pluginKey: pluginKey,
234
+ });
235
+
236
+ const init = async () => {
237
+ try {
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
+ }
258
+ };
259
+
260
+ init(); // 즉시 실행
261
+
262
+ return () => {
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
+ );
281
+ }
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
+ ```
302
+
303
+ ### initChat Method
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
+ };
359
+
360
+ ```
361
+
362
+ ### postChatInfo Method
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
+ ```
381
+
382
+ ## legacy
383
+
384
+ Ver 0.x.x: https://www.npmjs.com/package/ax-sdk-chatbot/v/0.3.7
385
+
386
+ ## license
387
+
388
+ [MIT](https://opensource.org/licenses/MIT)
389
+
390
+ Copyright (c) 2025-present, Coxwave
package/dist/index.css ADDED
@@ -0,0 +1,2 @@
1
+ @keyframes _1mlv4me0{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}@keyframes _1mlv4me1{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(30px);display:none}}._1mlv4me2{opacity:0;transform:translateY(30px);transition:opacity .4s ease,transform .4s ease;pointer-events:none;display:none}._1mlv4me3{animation:_1mlv4me0 .4s ease forwards;pointer-events:auto}._1mlv4me4{animation:_1mlv4me1 .4s ease forwards;pointer-events:none}._1mlv4me5{border:none!important}@keyframes _6j1ub50{0%{opacity:1;pointer-events:auto}50%{opacity:1}to{opacity:0}}._6j1ub51{pointer-events:none;opacity:0;display:flex;position:absolute;width:max-content;top:calc(100% + 5px);right:0;flex-direction:column;justify-content:center;align-items:flex-end;padding-top:2px;cursor:pointer;z-index:999;transition:opacity .3s ease}._6j1ub52{pointer-events:auto;animation:_6j1ub50 18s forwards}._6j1ub53{opacity:0;pointer-events:none;animation:none}._6j1ub54{display:flex;justify-content:flex-end;border-radius:var(--Radius-radiusSM, 8px);width:max-content;gap:5px}._6j1ub55{display:flex;padding:8px 12px 6px;justify-content:flex-end;align-items:center;border-radius:var(--Radius-radiusSM, 8px);max-width:340px}._6j1ub56{background-color:#171b1f}._6j1ub57{background-color:#fa6b4b}._6j1ub58{color:#fff;text-align:right;font-family:Pretendard;font-size:14px;font-style:normal;font-weight:400;line-height:20px;white-space:pre-wrap;word-break:keep-all;overflow-wrap:break-word}._6j1ub59{display:flex;padding:0 23px;align-items:flex-start;gap:10px}._6j1ub5a{width:15px}._6j1ub5b{color:#171b1f}._6j1ub5c{color:#fa6b4b}._6j1ub5d{cursor:pointer;justify-content:center;align-items:center;width:20px;height:20px;border-radius:100px;z-index:999;transition:all .2s ease}._6j1ub5d:hover{width:63px;left:-72px}._6j1ub54:hover ._6j1ub5d{display:flex}._6j1ub5e,._6j1ub5f{display:none;background-color:#171b1f}._6j1ub5g{color:#fff}._6j1ub5d:hover ._6j1ub5g{display:none}._6j1ub5h{color:#fff;text-align:center;font-family:Pretendard;font-size:12px;font-style:normal;font-weight:400;line-height:20px;display:none}._6j1ub5d:hover ._6j1ub5h{display:block}.wu2gm60{width:100%;min-width:max-content;table-layout:auto;border-collapse:separate;border-spacing:0;border:.4px solid rgba(118,118,128,.12);border-radius:8px;overflow:auto;background-color:#fff;cursor:pointer}.wu2gm61{border:.4px solid rgba(118,118,128,.12);padding:10px;background-color:#f2f2f2;text-align:left;font-family:Pretendard;color:#090909;font-size:12px;font-weight:500;white-space:normal;overflow-wrap:break-word;word-break:break-word}.wu2gm62{border:.4px solid rgba(118,118,128,.12);padding:10px;color:#090909;font-family:Pretendard;font-size:12px;font-weight:400;width:fit-content;max-width:400px;white-space:normal;overflow-wrap:break-word;word-break:break-word}.wu2gm63{position:relative;background-color:#fafafa;border-radius:8px;padding:8px;overflow-y:auto}.wu2gm64{display:flex;align-items:center;justify-content:space-between;padding-bottom:4px}.wu2gm65{color:#4a5568;padding:2px 6px;font-size:12px;border-radius:4px;z-index:10;font-family:Pretendard}.wu2gm66{z-index:10;cursor:pointer;display:flex;align-items:center;width:max-content;color:#4a5568;padding:2px 6px;font-size:12px;border:none;font-family:Pretendard}.wu2gm67{white-space:nowrap}.wu2gm68{display:flex;width:12px;height:12px;margin-bottom:4px;color:#4a5568;flex-shrink:0}
2
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["vanilla-extract-css-ns:chatBody/chatBody.css.ts.vanilla.css?source=QGtleWZyYW1lcyBfMW1sdjRtZTAgewogIGZyb20gewogICAgb3BhY2l0eTogMDsKICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgzMHB4KTsKICB9CiAgdG8gewogICAgb3BhY2l0eTogMTsKICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgwKTsKICB9Cn0KQGtleWZyYW1lcyBfMW1sdjRtZTEgewogIGZyb20gewogICAgb3BhY2l0eTogMTsKICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgwKTsKICB9CiAgdG8gewogICAgb3BhY2l0eTogMDsKICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgzMHB4KTsKICAgIGRpc3BsYXk6IG5vbmU7CiAgfQp9Ci5fMW1sdjRtZTIgewogIG9wYWNpdHk6IDA7CiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKDMwcHgpOwogIHRyYW5zaXRpb246IG9wYWNpdHkgMC40cyBlYXNlLCB0cmFuc2Zvcm0gMC40cyBlYXNlOwogIHBvaW50ZXItZXZlbnRzOiBub25lOwogIGRpc3BsYXk6IG5vbmU7Cn0KLl8xbWx2NG1lMyB7CiAgYW5pbWF0aW9uOiBfMW1sdjRtZTAgMC40cyBlYXNlIGZvcndhcmRzOwogIHBvaW50ZXItZXZlbnRzOiBhdXRvOwp9Ci5fMW1sdjRtZTQgewogIGFuaW1hdGlvbjogXzFtbHY0bWUxIDAuNHMgZWFzZSBmb3J3YXJkczsKICBwb2ludGVyLWV2ZW50czogbm9uZTsKfQouXzFtbHY0bWU1IHsKICBib3JkZXI6IG5vbmUgIWltcG9ydGFudDsKfQ==","vanilla-extract-css-ns:floatingButton/alarm/styles/alarm.css.ts.vanilla.css?source=#H4sIAAAAAAAAE61Uy27bMBC8+ysWKAqkaBlI8iMxfWlzyK1A0X5AQYsrizFNCiQVyyny7wUpOtbDblK0J1s7u8vZmSU/b/FQGLZDCz8XD2m9nifwawKQvA8/ALpiuXAHCukqfFdaKIeG4CMqZymw2mmPPE8A5heqPJYmYzBpwefJdTw7DRnDI5RW6DP7dVzYSrIDhUJiswplVjihFQW2tlrWLhTtBXclhR1rSK6VQ+V81OmKQs5kfhV4fYR51XzwgBGb0sUTfGPChcG8bZtrWe+URx5q60RxOHakkKNn7CEmxUYR4XBnW2oEFQ/0GOdCbUg4OqsC5bw2Vht6nNiHnohQHBsKy+UyMDVMHeeKAkByPbWAzOKqo112VrujPUyJHWu7vPic3lootNkzw2230zR06qt9yZNO3zZ0ajMLbUY2jbTrirTWhqMhhnFRWwqPzFwR8j18xeCPr5/gNpp13tsNq6j3s8tlfp5L9IT6jpBmVQOL+OdVpj2fT/b/3QCeeRxiOkv6lBeB8prl243RteIk19Lvyrv0Jr1L77upN5dS778s7mZ33dTbkHrEi6IIO4aNI2Eg2l6AsP1aOVKwnZAHCt8MOlScGf4CWfGEFNJZq1UbcgeJfhHMjsmX6B7bOzVLwiZJoZCUMZYlbfm+FA6JrViOFCqDZG9YFQBtOFkbZFsKW8SKMBk660c0hdT7kEghZBCf3B12+YrrSdVANm0ZjO+tdcycFiod2MNC72heOli3dU/lsWF5Dx+7xFt8/Dq89eE5hSPDo9BD4Qf7miYx/qdniEkJyXU2foI4Lb0vXWUWUV6JhaNAbrK+ULNY0R984NgpHfvw8RF60yUp/qF20/Ur7Oq5sfvZg5NO6eVrV/Bk3hvvYPZf7uBFwsP5yv58a6nz7Wry/Bv1tBtfSwgAAA==","vanilla-extract-css-ns:popUpImage/popUpImage.css.ts.vanilla.css?source=#H4sIAAAAAAAAE7VU7Y7bIBD8n6dYqap0lUKEXSd1uZfoK2B77dBgQIDPzlX37hX4o07qXq9qK0tY7AIzOztw6Lu0aU8Uvu0AelH5M4OE0vePO4BWKDKFWj6QUiuPyoeM54VEIvlVd54B77wO0ULbCi0ptZTcOGTg0HDLPa6SzvBSqIYB/RFkQA+ZGcBpKSqwTcEfkiTfwzik+R7oIUk/rE6xvBKdY5CbIUT1E9pa6n5FhZeXxupOVYGOtgze1XUdMmVnXZgbLZRH+7h72R1GDZKowR9TMryqYkUJHdlsYafhi8rh4AmXolEMJNZRzVorT2reCnll8MWiR1VxW0W20wH0c/iWxU48I4MkHQFjqEfRnD2DI43K9mfhMaqNDJS2LZdrpUhvuWFQWOQX0usRLPxJDN1mFoXSf6TQL6raluB3BWdTwaNRa+HXRg2+nTIZndD/izQfozRGO+GFVgwsSu7FE24bwjbFQ3qke5iHV8y9qHdndnKd7b6QyCKJSjgj+ZVBLTHuiHYjwmPrGJQ42h7ga+e8qK+zXAyiJKRA3yOqFTQptPe6ZZAFBgvaMaLNvcz48XjKbwinZoDTqmO3TbyrNhujz0SoCofglVd9sbA4RRZ323665G9XZfvB+8sqg88Uvq2gT+NTfGvS4MnVmny70fP7PWGfpxsyz1tuG6Fuu7lVWjiOuLMV6hLf6ZfvG7kHlyUGAAA="],"sourcesContent":["@keyframes _1mlv4me0 {\n from {\n opacity: 0;\n transform: translateY(30px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@keyframes _1mlv4me1 {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(30px);\n display: none;\n }\n}\n._1mlv4me2 {\n opacity: 0;\n transform: translateY(30px);\n transition: opacity 0.4s ease, transform 0.4s ease;\n pointer-events: none;\n display: none;\n}\n._1mlv4me3 {\n animation: _1mlv4me0 0.4s ease forwards;\n pointer-events: auto;\n}\n._1mlv4me4 {\n animation: _1mlv4me1 0.4s ease forwards;\n pointer-events: none;\n}\n._1mlv4me5 {\n border: none !important;\n}","@keyframes _6j1ub50 {\n 0% {\n opacity: 1;\n pointer-events: auto;\n }\n 50% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n}\n._6j1ub51 {\n pointer-events: none;\n opacity: 0;\n display: flex;\n position: absolute;\n width: max-content;\n top: calc(100% + 5px);\n right: 0;\n flex-direction: column;\n justify-content: center;\n align-items: flex-end;\n padding-top: 2px;\n cursor: pointer;\n z-index: 999;\n transition: opacity 0.3s ease;\n}\n._6j1ub52 {\n pointer-events: auto;\n animation: _6j1ub50 18s forwards;\n}\n._6j1ub53 {\n opacity: 0;\n pointer-events: none;\n animation: none;\n}\n._6j1ub54 {\n display: flex;\n justify-content: flex-end;\n border-radius: var(--Radius-radiusSM, 8px);\n width: max-content;\n gap: 5px;\n}\n._6j1ub55 {\n display: flex;\n padding: 8px 12px 6px 12px;\n justify-content: flex-end;\n align-items: center;\n border-radius: var(--Radius-radiusSM, 8px);\n max-width: 340px;\n}\n._6j1ub56 {\n background-color: #171B1F;\n}\n._6j1ub57 {\n background-color: #FA6B4B;\n}\n._6j1ub58 {\n color: #fff;\n text-align: right;\n font-family: Pretendard;\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n line-height: 20px;\n white-space: pre-wrap;\n word-break: keep-all;\n overflow-wrap: break-word;\n}\n._6j1ub59 {\n display: flex;\n padding: 0px 23px;\n align-items: flex-start;\n gap: 10px;\n}\n._6j1ub5a {\n width: 15px;\n}\n._6j1ub5b {\n color: #171B1F;\n}\n._6j1ub5c {\n color: #FA6B4B;\n}\n._6j1ub5d {\n cursor: pointer;\n justify-content: center;\n align-items: center;\n width: 20px;\n height: 20px;\n border-radius: 100px;\n z-index: 999;\n transition: all 0.2s ease;\n}\n._6j1ub5d:hover {\n width: 63px;\n left: -72px;\n}\n._6j1ub54:hover ._6j1ub5d {\n display: flex;\n}\n._6j1ub5e {\n display: none;\n background-color: #171B1F;\n}\n._6j1ub5f {\n display: none;\n background-color: #171B1F;\n}\n._6j1ub5g {\n color: white;\n}\n._6j1ub5d:hover ._6j1ub5g {\n display: none;\n}\n._6j1ub5h {\n color: #fff;\n text-align: center;\n font-family: Pretendard;\n font-size: 12px;\n font-style: normal;\n font-weight: 400;\n line-height: 20px;\n display: none;\n}\n._6j1ub5d:hover ._6j1ub5h {\n display: block;\n}",".wu2gm60 {\n width: 100%;\n min-width: max-content;\n table-layout: auto;\n border-collapse: separate;\n border-spacing: 0;\n border: 0.4px solid rgba(118, 118, 128, 0.12);\n border-radius: 8px;\n overflow: auto;\n background-color: #fff;\n cursor: pointer;\n}\n.wu2gm61 {\n border: 0.4px solid rgba(118, 118, 128, 0.12);\n padding: 10px;\n background-color: #f2f2f2;\n text-align: left;\n font-family: Pretendard;\n color: #090909;\n font-size: 12px;\n font-weight: 500;\n white-space: normal;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n.wu2gm62 {\n border: 0.4px solid rgba(118, 118, 128, 0.12);\n padding: 10px;\n color: #090909;\n font-family: Pretendard;\n font-size: 12px;\n font-weight: 400;\n width: fit-content;\n max-width: 400px;\n white-space: normal;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n.wu2gm63 {\n position: relative;\n background-color: rgb(250, 250, 250);\n border-radius: 8px;\n padding: 8px;\n overflow-y: auto;\n}\n.wu2gm64 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-bottom: 4px;\n}\n.wu2gm65 {\n color: #4a5568;\n padding: 2px 6px;\n font-size: 12px;\n border-radius: 4px;\n z-index: 10;\n font-family: Pretendard;\n}\n.wu2gm66 {\n z-index: 10;\n cursor: pointer;\n display: flex;\n align-items: center;\n width: max-content;\n color: #4a5568;\n padding: 2px 6px;\n font-size: 12px;\n border: none;\n font-family: Pretendard;\n}\n.wu2gm67 {\n white-space: nowrap;\n}\n.wu2gm68 {\n display: flex;\n width: 12px;\n height: 12px;\n margin-bottom: 4px;\n color: #4a5568;\n flex-shrink: 0;\n}"],"mappings":"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","names":[]}
@@ -0,0 +1,189 @@
1
+ import { ChatInitMessage, ChatOpenMessage, ChatCloseMessage, TimelineSeekMessage, AlarmClickMessage, PopUpCloseMessage, PdfEnlargedMessage, PdfShrinkedMessage, ChatInitiatedMessage, ChatOpenedMessage, ChatClosedMessage, AlarmFadeInMessage, PopUpOpenMessage, PdfOpenMessage, PdfCloseMessage, AlarmMessageInstanceType } from '@coxwave/tap-messages';
2
+
3
+ type Unsubscribe = () => void;
4
+ type Message = {
5
+ type: string;
6
+ [key: string]: any;
7
+ };
8
+ declare abstract class Messenger<TToTargetMessages extends Message = Message, TFromTargetMessage extends Message = Message> {
9
+ protected listeners: Map<TFromTargetMessage["type"], ((event: MessageEvent) => void)[]>;
10
+ protected unifiedMessageHandler: ((event: MessageEvent) => void) | null;
11
+ protected on<T extends TFromTargetMessage["type"]>(messageType: T, callback: (data: Extract<TFromTargetMessage, {
12
+ type: T;
13
+ }>) => void): Unsubscribe;
14
+ removeListener(messageType: TFromTargetMessage["type"]): void;
15
+ removeAllListeners(): void;
16
+ postMessage(message: TToTargetMessages): boolean;
17
+ protected abstract isValidOrigin(event: MessageEvent): boolean;
18
+ protected abstract getMessageTarget(): Window | null;
19
+ protected abstract getTargetOrigin(): string;
20
+ }
21
+
22
+ interface HandshakeOptions {
23
+ timeout?: number;
24
+ maxRetries?: number;
25
+ retryInterval?: number;
26
+ }
27
+
28
+ type ToTapMessage = ChatInitMessage | ChatOpenMessage | ChatCloseMessage | TimelineSeekMessage | AlarmClickMessage | PopUpCloseMessage | PdfEnlargedMessage | PdfShrinkedMessage;
29
+ type FromTapMessage = ChatInitiatedMessage | ChatOpenedMessage | ChatClosedMessage | AlarmFadeInMessage | PopUpOpenMessage | PdfOpenMessage | PdfCloseMessage | TimelineSeekMessage;
30
+ interface ChatInitConfig {
31
+ chatApiParams: any;
32
+ customStyles?: any;
33
+ gaId?: string;
34
+ }
35
+ declare class TapIframeBridge extends Messenger<ToTapMessage, FromTapMessage> {
36
+ protected hostClientUrl: string;
37
+ protected pluginKey: string;
38
+ protected iframe: HTMLIFrameElement | null;
39
+ constructor({ hostClientUrl, pluginKey, }: {
40
+ hostClientUrl: string;
41
+ pluginKey: string;
42
+ });
43
+ protected isValidOrigin(event: MessageEvent): boolean;
44
+ protected getMessageTarget(): Window | null;
45
+ protected getTargetOrigin(): string;
46
+ renderIframe({ chatBody, isProd, isLocal, }: {
47
+ chatBody: HTMLElement;
48
+ isProd: boolean;
49
+ isLocal?: boolean;
50
+ }): Promise<HTMLIFrameElement>;
51
+ hasIframe(): boolean;
52
+ removeIframe(): void;
53
+ get postToTap(): (message: ToTapMessage) => boolean;
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
+ type: T;
56
+ }> | Extract<ChatInitiatedMessage, {
57
+ type: T;
58
+ }> | Extract<ChatOpenedMessage, {
59
+ type: T;
60
+ }> | Extract<ChatClosedMessage, {
61
+ type: T;
62
+ }> | Extract<AlarmFadeInMessage, {
63
+ type: T;
64
+ }> | Extract<PopUpOpenMessage, {
65
+ type: T;
66
+ }> | Extract<PdfOpenMessage, {
67
+ type: T;
68
+ }> | Extract<PdfCloseMessage, {
69
+ type: T;
70
+ }>) => void) => () => void;
71
+ performHandshake(config: ChatInitConfig, options?: HandshakeOptions): Promise<ChatInitiatedMessage>;
72
+ }
73
+
74
+ type TapSDKType = {
75
+ pluginKey: string;
76
+ isProd?: boolean;
77
+ isLocal?: boolean;
78
+ };
79
+ type ChatApiParamsType = {
80
+ userId: string;
81
+ courseId: string | null;
82
+ courseName: string;
83
+ courseCategory: string;
84
+ courseSubCategory: string;
85
+ clipId: string | null;
86
+ clipPlayHead: number | null;
87
+ };
88
+ type CustomStylesType = {
89
+ floatingButton?: FloatingButtonType;
90
+ chatBody?: ChatBodyType;
91
+ theme?: ThemeType;
92
+ };
93
+ type ShortcutKeyType = {
94
+ openChat: ShortcutKeyPropertiesType;
95
+ sendChat: ShortcutKeyPropertiesType;
96
+ };
97
+ type FloatingButtonType = {
98
+ isInElement?: boolean;
99
+ parentElementId?: string;
100
+ style?: Partial<CSSStyleDeclaration>;
101
+ };
102
+ type ChatBodyType = {
103
+ position?: PositionType;
104
+ width?: string;
105
+ height?: string;
106
+ borderRadius?: string;
107
+ };
108
+ type ThemeType = {
109
+ iconColor?: string;
110
+ chatBody?: colorsType;
111
+ highlightBar?: colorsType;
112
+ components?: colorsType;
113
+ AIRecommendGradient?: {
114
+ base: string;
115
+ move: string;
116
+ };
117
+ };
118
+ type PositionType = {
119
+ top?: string;
120
+ left?: string;
121
+ right?: string;
122
+ bottom?: string;
123
+ };
124
+
125
+ type ShortcutKeyPropertiesType = {
126
+ key: string;
127
+ modifier: "ctrlKey" | "altKey" | "shiftKey" | "metaKey" | "";
128
+ };
129
+ type colorsType = {
130
+ color?: string;
131
+ backgroundColor?: string;
132
+ };
133
+ type SeekTimelineParamsType = {
134
+ clipId: string;
135
+ clipPlayHead: number;
136
+ };
137
+
138
+ declare class EventManager {
139
+ private iframeBridge;
140
+ constructor(iframeBridge: TapIframeBridge);
141
+ onTimelineSeek(handler: (clipPlayHead: number, clipId: string) => void): void;
142
+ onChatOpened(handler: () => void): void;
143
+ onChatClosed(handler: () => void): void;
144
+ onChatInitiated(handler: () => void): void;
145
+ onAlarmFadeIn(handler: (messageInfo: AlarmMessageInstanceType) => void): void;
146
+ onPopUpOpen(handler: (popUpInfo: PopUpOpenMessage["popUpInfo"]) => void): void;
147
+ onPdfOpen(handler: () => void): void;
148
+ onPdfClose(handler: () => void): void;
149
+ }
150
+
151
+ declare class TapSDK {
152
+ #private;
153
+ private pluginKey;
154
+ private iframeBridge;
155
+ events: EventManager;
156
+ private chatBody;
157
+ private chatBodyMaker;
158
+ private floatingButtonMaker;
159
+ private shortcutKey;
160
+ private isProd;
161
+ private isLocal;
162
+ private isOpen;
163
+ private isPdfOpen;
164
+ constructor({ pluginKey, isProd, isLocal }: TapSDKType);
165
+ private setIsOpen;
166
+ private setIsPdfOpen;
167
+ seekTimeline({ clipId, clipPlayHead }: SeekTimelineParamsType): void;
168
+ initChat({ chatApiParams, customStyles, shortcutKey, }: {
169
+ chatApiParams: ChatApiParamsType;
170
+ customStyles?: CustomStylesType;
171
+ shortcutKey?: ShortcutKeyType;
172
+ }): Promise<void>;
173
+ removeChat(): void;
174
+ /**
175
+ * @deprecated use `seekTimeline` method. gotta be expired at v1.0.0
176
+ */
177
+ postChatInfo({ clipId, clipPlayHead, }: {
178
+ clipId: string;
179
+ clipPlayHead: number;
180
+ }): void;
181
+ /**
182
+ * @deprecated use `events.onTimelineSeek` method. gotta be expired at v1.0.0
183
+ */
184
+ getTimelineInfo({ callback, }: {
185
+ callback: (clipPlayHead: number, clipId: string) => void;
186
+ }): void;
187
+ }
188
+
189
+ export { TapSDK as default };