@sparrowdesk/react-chat 0.1.0 → 0.1.2
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/dist/index.d.ts +4 -3
- package/dist/index.js +1 -400
- package/package.json +10 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import * as React
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { FC } from "react";
|
|
2
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
4
|
|
|
4
5
|
//#region src/internal/sparrowDeskWidget.d.ts
|
|
@@ -76,7 +77,7 @@ interface ChatProps {
|
|
|
76
77
|
*/
|
|
77
78
|
readyTimeoutMs?: number;
|
|
78
79
|
}
|
|
79
|
-
declare const Chat:
|
|
80
|
+
declare const Chat: FC<ChatProps>;
|
|
80
81
|
//#endregion
|
|
81
82
|
//#region src/SparrowDeskProvider.d.ts
|
|
82
83
|
type SparrowDeskProviderProps = {
|
|
@@ -84,7 +85,7 @@ type SparrowDeskProviderProps = {
|
|
|
84
85
|
domain: string;
|
|
85
86
|
/** SparrowDesk widget token */
|
|
86
87
|
token: string;
|
|
87
|
-
children: React
|
|
88
|
+
children: React.ReactNode;
|
|
88
89
|
/**
|
|
89
90
|
* Controls whether this provider should set globals and inject the widget script.
|
|
90
91
|
* Set to `false` if SparrowDesk is loaded elsewhere (e.g. via Segment) and you only
|
package/dist/index.js
CHANGED
|
@@ -1,400 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
-
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
|
|
5
|
-
//#region src/internal/sparrowDeskWidget.ts
|
|
6
|
-
const DEFAULT_SCRIPT_SRC = "https://assets.cdn.sparrowdesk.com/chatbot/bundle/main.js";
|
|
7
|
-
const DEFAULT_READY_TIMEOUT_MS = 1e4;
|
|
8
|
-
const WIDGET_SCRIPT_SELECTOR = "script[data-sd-chat-widget=\"true\"]";
|
|
9
|
-
function isBrowser() {
|
|
10
|
-
return globalThis.document !== void 0;
|
|
11
|
-
}
|
|
12
|
-
function normalizeRequired(value) {
|
|
13
|
-
return value.trim();
|
|
14
|
-
}
|
|
15
|
-
function setWidgetGlobals(domain, token) {
|
|
16
|
-
const w = globalThis;
|
|
17
|
-
w.SD_WIDGET_DOMAIN = domain;
|
|
18
|
-
w.SD_WIDGET_TOKEN = token;
|
|
19
|
-
}
|
|
20
|
-
const scriptEntriesBySrc = /* @__PURE__ */ new Map();
|
|
21
|
-
function removeOtherWidgetScripts(keepSrc) {
|
|
22
|
-
document.querySelectorAll(WIDGET_SCRIPT_SELECTOR).forEach((script) => {
|
|
23
|
-
if (script.src !== keepSrc) script.remove();
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
function acquireWidgetScript(src, cleanupOnUnmount) {
|
|
27
|
-
const cached = scriptEntriesBySrc.get(src);
|
|
28
|
-
if (cached) {
|
|
29
|
-
cached.refCount += 1;
|
|
30
|
-
cached.cleanupWhenUnused ||= cleanupOnUnmount;
|
|
31
|
-
return { release() {
|
|
32
|
-
cached.refCount -= 1;
|
|
33
|
-
if (cached.refCount > 0) return;
|
|
34
|
-
if (cached.cleanupWhenUnused) cached.script.remove();
|
|
35
|
-
scriptEntriesBySrc.delete(src);
|
|
36
|
-
} };
|
|
37
|
-
}
|
|
38
|
-
const existing = document.querySelector(WIDGET_SCRIPT_SELECTOR);
|
|
39
|
-
const entry = {
|
|
40
|
-
script: existing?.src === src ? existing : (() => {
|
|
41
|
-
const el = document.createElement("script");
|
|
42
|
-
el.async = true;
|
|
43
|
-
el.src = src;
|
|
44
|
-
el.dataset["sdChatWidget"] = "true";
|
|
45
|
-
document.body.appendChild(el);
|
|
46
|
-
return el;
|
|
47
|
-
})(),
|
|
48
|
-
refCount: 1,
|
|
49
|
-
cleanupWhenUnused: cleanupOnUnmount
|
|
50
|
-
};
|
|
51
|
-
scriptEntriesBySrc.set(src, entry);
|
|
52
|
-
return { release() {
|
|
53
|
-
entry.refCount -= 1;
|
|
54
|
-
if (entry.refCount > 0) return;
|
|
55
|
-
if (entry.cleanupWhenUnused) entry.script.remove();
|
|
56
|
-
scriptEntriesBySrc.delete(src);
|
|
57
|
-
} };
|
|
58
|
-
}
|
|
59
|
-
async function waitForSparrowDeskApi(timeoutMs) {
|
|
60
|
-
const w = globalThis;
|
|
61
|
-
if (w.sparrowDesk) return w.sparrowDesk;
|
|
62
|
-
if (timeoutMs <= 0) return null;
|
|
63
|
-
const startedAt = Date.now();
|
|
64
|
-
while (Date.now() - startedAt < timeoutMs) {
|
|
65
|
-
if (w.sparrowDesk) return w.sparrowDesk;
|
|
66
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/internal/useLatest.ts
|
|
73
|
-
function useLatest(value) {
|
|
74
|
-
const ref = useRef(value);
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
ref.current = value;
|
|
77
|
-
}, [value]);
|
|
78
|
-
return ref;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
//#endregion
|
|
82
|
-
//#region src/Chat.tsx
|
|
83
|
-
const Chat = ({ domain, token, tags, contactFields, conversationFields, onReady, onOpen, onClose, openOnInit = false, hideOnInit = false, shouldInitialize = true, connectOnPageLoad = true, initializeOnInteraction = true, cleanupOnUnmount = false, readyTimeoutMs = DEFAULT_READY_TIMEOUT_MS }) => {
|
|
84
|
-
const normalized = useMemo(() => {
|
|
85
|
-
return {
|
|
86
|
-
domain: normalizeRequired(domain),
|
|
87
|
-
token: normalizeRequired(token)
|
|
88
|
-
};
|
|
89
|
-
}, [domain, token]);
|
|
90
|
-
const onOpenRef = useLatest(onOpen);
|
|
91
|
-
const onCloseRef = useLatest(onClose);
|
|
92
|
-
const onReadyRef = useLatest(onReady);
|
|
93
|
-
const tagsRef = useLatest(tags);
|
|
94
|
-
const contactFieldsRef = useLatest(contactFields);
|
|
95
|
-
const conversationFieldsRef = useLatest(conversationFields);
|
|
96
|
-
const registeredCallbacksRef = useRef(false);
|
|
97
|
-
const apiRef = useRef(null);
|
|
98
|
-
const didOpenOnceRef = useRef(false);
|
|
99
|
-
const didHideOnceRef = useRef(false);
|
|
100
|
-
const [shouldStart, setShouldStart] = useState(connectOnPageLoad);
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
didOpenOnceRef.current = false;
|
|
103
|
-
didHideOnceRef.current = false;
|
|
104
|
-
apiRef.current = null;
|
|
105
|
-
registeredCallbacksRef.current = false;
|
|
106
|
-
setShouldStart(connectOnPageLoad);
|
|
107
|
-
}, [normalized.domain, normalized.token]);
|
|
108
|
-
useEffect(() => {
|
|
109
|
-
if (!isBrowser()) return;
|
|
110
|
-
if (!normalized.domain || !normalized.token) return;
|
|
111
|
-
setWidgetGlobals(normalized.domain, normalized.token);
|
|
112
|
-
if (!shouldInitialize) return;
|
|
113
|
-
if (!shouldStart) return;
|
|
114
|
-
removeOtherWidgetScripts(DEFAULT_SCRIPT_SRC);
|
|
115
|
-
const handle = acquireWidgetScript(DEFAULT_SCRIPT_SRC, cleanupOnUnmount);
|
|
116
|
-
return () => {
|
|
117
|
-
handle.release();
|
|
118
|
-
};
|
|
119
|
-
}, [
|
|
120
|
-
normalized.domain,
|
|
121
|
-
normalized.token,
|
|
122
|
-
cleanupOnUnmount,
|
|
123
|
-
shouldInitialize,
|
|
124
|
-
shouldStart
|
|
125
|
-
]);
|
|
126
|
-
useEffect(() => {
|
|
127
|
-
if (!isBrowser()) return;
|
|
128
|
-
if (!normalized.domain || !normalized.token) return;
|
|
129
|
-
if (!shouldStart) return;
|
|
130
|
-
let cancelled = false;
|
|
131
|
-
(async () => {
|
|
132
|
-
const api = await waitForSparrowDeskApi(readyTimeoutMs);
|
|
133
|
-
if (cancelled || !api) return;
|
|
134
|
-
apiRef.current = api;
|
|
135
|
-
if (!registeredCallbacksRef.current) {
|
|
136
|
-
api.onOpen?.(() => onOpenRef.current?.());
|
|
137
|
-
api.onClose?.(() => onCloseRef.current?.());
|
|
138
|
-
registeredCallbacksRef.current = true;
|
|
139
|
-
}
|
|
140
|
-
onReadyRef.current?.(api);
|
|
141
|
-
const latestTags = tagsRef.current;
|
|
142
|
-
const latestContactFields = contactFieldsRef.current;
|
|
143
|
-
const latestConversationFields = conversationFieldsRef.current;
|
|
144
|
-
if (Array.isArray(latestTags) && latestTags.length) api.setTags?.(latestTags);
|
|
145
|
-
if (latestContactFields && Object.keys(latestContactFields).length) api.setContactFields?.(latestContactFields);
|
|
146
|
-
if (latestConversationFields && Object.keys(latestConversationFields).length) api.setConversationFields?.(latestConversationFields);
|
|
147
|
-
if (hideOnInit && !didHideOnceRef.current) {
|
|
148
|
-
api.hideWidget?.();
|
|
149
|
-
didHideOnceRef.current = true;
|
|
150
|
-
}
|
|
151
|
-
if (openOnInit && !didOpenOnceRef.current) {
|
|
152
|
-
api.openWidget?.();
|
|
153
|
-
didOpenOnceRef.current = true;
|
|
154
|
-
}
|
|
155
|
-
})();
|
|
156
|
-
return () => {
|
|
157
|
-
cancelled = true;
|
|
158
|
-
};
|
|
159
|
-
}, [
|
|
160
|
-
normalized.domain,
|
|
161
|
-
normalized.token,
|
|
162
|
-
openOnInit,
|
|
163
|
-
hideOnInit,
|
|
164
|
-
readyTimeoutMs,
|
|
165
|
-
shouldStart
|
|
166
|
-
]);
|
|
167
|
-
useEffect(() => {
|
|
168
|
-
if (!isBrowser()) return;
|
|
169
|
-
if (connectOnPageLoad) return;
|
|
170
|
-
if (!initializeOnInteraction) return;
|
|
171
|
-
if (shouldStart) return;
|
|
172
|
-
if (!normalized.domain || !normalized.token) return;
|
|
173
|
-
const onFirstInteraction = () => {
|
|
174
|
-
setShouldStart(true);
|
|
175
|
-
cleanup();
|
|
176
|
-
};
|
|
177
|
-
const cleanup = () => {
|
|
178
|
-
document.removeEventListener("pointerdown", onFirstInteraction, true);
|
|
179
|
-
document.removeEventListener("keydown", onFirstInteraction, true);
|
|
180
|
-
};
|
|
181
|
-
document.addEventListener("pointerdown", onFirstInteraction, true);
|
|
182
|
-
document.addEventListener("keydown", onFirstInteraction, true);
|
|
183
|
-
return cleanup;
|
|
184
|
-
}, [
|
|
185
|
-
connectOnPageLoad,
|
|
186
|
-
initializeOnInteraction,
|
|
187
|
-
normalized.domain,
|
|
188
|
-
normalized.token,
|
|
189
|
-
shouldStart
|
|
190
|
-
]);
|
|
191
|
-
useEffect(() => {
|
|
192
|
-
const api = apiRef.current;
|
|
193
|
-
if (!api) return;
|
|
194
|
-
if (Array.isArray(tags) && tags.length) api.setTags?.(tags);
|
|
195
|
-
if (contactFields && Object.keys(contactFields).length) api.setContactFields?.(contactFields);
|
|
196
|
-
if (conversationFields && Object.keys(conversationFields).length) api.setConversationFields?.(conversationFields);
|
|
197
|
-
}, [
|
|
198
|
-
tags,
|
|
199
|
-
contactFields,
|
|
200
|
-
conversationFields
|
|
201
|
-
]);
|
|
202
|
-
if (!normalized.domain || !normalized.token) return null;
|
|
203
|
-
return /* @__PURE__ */ jsx("div", { "data-sd-chat-widget-container": "" });
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
//#endregion
|
|
207
|
-
//#region src/SparrowDeskProvider.tsx
|
|
208
|
-
const SparrowDeskContext = React.createContext(null);
|
|
209
|
-
function useSparrowDesk() {
|
|
210
|
-
const value = React.useContext(SparrowDeskContext);
|
|
211
|
-
if (!value) throw new Error("useSparrowDesk must be used within <SparrowDeskProvider />");
|
|
212
|
-
return value;
|
|
213
|
-
}
|
|
214
|
-
function SparrowDeskProvider({ domain, token, children, shouldInitialize = true, connectOnPageLoad = true, initializeOnInteraction = true, tags, contactFields, conversationFields, onReady, onOpen, onClose, openOnInit = false, hideOnInit = false, cleanupOnUnmount = false, readyTimeoutMs = DEFAULT_READY_TIMEOUT_MS }) {
|
|
215
|
-
const normalized = useMemo(() => {
|
|
216
|
-
return {
|
|
217
|
-
domain: normalizeRequired(domain),
|
|
218
|
-
token: normalizeRequired(token)
|
|
219
|
-
};
|
|
220
|
-
}, [domain, token]);
|
|
221
|
-
const onReadyRef = useLatest(onReady);
|
|
222
|
-
const onOpenRef = useLatest(onOpen);
|
|
223
|
-
const onCloseRef = useLatest(onClose);
|
|
224
|
-
const tagsRef = useLatest(tags);
|
|
225
|
-
const contactFieldsRef = useLatest(contactFields);
|
|
226
|
-
const conversationFieldsRef = useLatest(conversationFields);
|
|
227
|
-
const openOnInitRef = useLatest(openOnInit);
|
|
228
|
-
const hideOnInitRef = useLatest(hideOnInit);
|
|
229
|
-
const apiRef = useRef(null);
|
|
230
|
-
const registeredCallbacksRef = useRef(false);
|
|
231
|
-
const didOpenOnceRef = useRef(false);
|
|
232
|
-
const didHideOnceRef = useRef(false);
|
|
233
|
-
const scriptHandleRef = useRef(null);
|
|
234
|
-
const initStartedRef = useRef(false);
|
|
235
|
-
const initCancelRef = useRef(null);
|
|
236
|
-
const pendingCallsRef = useRef([]);
|
|
237
|
-
const [isReady, setIsReady] = useState(false);
|
|
238
|
-
const [shouldStart, setShouldStart] = useState(connectOnPageLoad);
|
|
239
|
-
useEffect(() => {
|
|
240
|
-
setShouldStart(connectOnPageLoad);
|
|
241
|
-
}, [connectOnPageLoad]);
|
|
242
|
-
useEffect(() => {
|
|
243
|
-
didOpenOnceRef.current = false;
|
|
244
|
-
didHideOnceRef.current = false;
|
|
245
|
-
apiRef.current = null;
|
|
246
|
-
registeredCallbacksRef.current = false;
|
|
247
|
-
initStartedRef.current = false;
|
|
248
|
-
initCancelRef.current?.();
|
|
249
|
-
initCancelRef.current = null;
|
|
250
|
-
pendingCallsRef.current = [];
|
|
251
|
-
scriptHandleRef.current?.release();
|
|
252
|
-
scriptHandleRef.current = null;
|
|
253
|
-
setIsReady(false);
|
|
254
|
-
setShouldStart(connectOnPageLoad);
|
|
255
|
-
}, [
|
|
256
|
-
normalized.domain,
|
|
257
|
-
normalized.token,
|
|
258
|
-
connectOnPageLoad
|
|
259
|
-
]);
|
|
260
|
-
const initialize = React.useCallback(() => {
|
|
261
|
-
if (!isBrowser()) return;
|
|
262
|
-
if (!normalized.domain || !normalized.token) return;
|
|
263
|
-
setWidgetGlobals(normalized.domain, normalized.token);
|
|
264
|
-
if (shouldInitialize && !scriptHandleRef.current) {
|
|
265
|
-
removeOtherWidgetScripts(DEFAULT_SCRIPT_SRC);
|
|
266
|
-
scriptHandleRef.current = acquireWidgetScript(DEFAULT_SCRIPT_SRC, cleanupOnUnmount);
|
|
267
|
-
}
|
|
268
|
-
if (initStartedRef.current) return;
|
|
269
|
-
initStartedRef.current = true;
|
|
270
|
-
let cancelled = false;
|
|
271
|
-
initCancelRef.current = () => {
|
|
272
|
-
cancelled = true;
|
|
273
|
-
};
|
|
274
|
-
(async () => {
|
|
275
|
-
const api = await waitForSparrowDeskApi(readyTimeoutMs);
|
|
276
|
-
if (cancelled || !api) return;
|
|
277
|
-
apiRef.current = api;
|
|
278
|
-
setIsReady(true);
|
|
279
|
-
if (!registeredCallbacksRef.current) {
|
|
280
|
-
api.onOpen?.(() => onOpenRef.current?.());
|
|
281
|
-
api.onClose?.(() => onCloseRef.current?.());
|
|
282
|
-
registeredCallbacksRef.current = true;
|
|
283
|
-
}
|
|
284
|
-
onReadyRef.current?.(api);
|
|
285
|
-
const latestTags = tagsRef.current;
|
|
286
|
-
const latestContactFields = contactFieldsRef.current;
|
|
287
|
-
const latestConversationFields = conversationFieldsRef.current;
|
|
288
|
-
if (Array.isArray(latestTags) && latestTags.length) api.setTags?.(latestTags);
|
|
289
|
-
if (latestContactFields && Object.keys(latestContactFields).length) api.setContactFields?.(latestContactFields);
|
|
290
|
-
if (latestConversationFields && Object.keys(latestConversationFields).length) api.setConversationFields?.(latestConversationFields);
|
|
291
|
-
if (hideOnInitRef.current && !didHideOnceRef.current) {
|
|
292
|
-
api.hideWidget?.();
|
|
293
|
-
didHideOnceRef.current = true;
|
|
294
|
-
}
|
|
295
|
-
if (openOnInitRef.current && !didOpenOnceRef.current) {
|
|
296
|
-
api.openWidget?.();
|
|
297
|
-
didOpenOnceRef.current = true;
|
|
298
|
-
}
|
|
299
|
-
const pending = pendingCallsRef.current;
|
|
300
|
-
pendingCallsRef.current = [];
|
|
301
|
-
pending.forEach((fn) => fn(api));
|
|
302
|
-
})();
|
|
303
|
-
}, [
|
|
304
|
-
cleanupOnUnmount,
|
|
305
|
-
normalized.domain,
|
|
306
|
-
normalized.token,
|
|
307
|
-
readyTimeoutMs,
|
|
308
|
-
shouldInitialize
|
|
309
|
-
]);
|
|
310
|
-
useEffect(() => {
|
|
311
|
-
if (!isBrowser()) return;
|
|
312
|
-
if (!normalized.domain || !normalized.token) return;
|
|
313
|
-
setWidgetGlobals(normalized.domain, normalized.token);
|
|
314
|
-
if (!shouldStart) return;
|
|
315
|
-
initialize();
|
|
316
|
-
return () => {
|
|
317
|
-
initCancelRef.current?.();
|
|
318
|
-
initCancelRef.current = null;
|
|
319
|
-
if (!apiRef.current) initStartedRef.current = false;
|
|
320
|
-
scriptHandleRef.current?.release();
|
|
321
|
-
scriptHandleRef.current = null;
|
|
322
|
-
};
|
|
323
|
-
}, [
|
|
324
|
-
initialize,
|
|
325
|
-
normalized.domain,
|
|
326
|
-
normalized.token,
|
|
327
|
-
shouldStart
|
|
328
|
-
]);
|
|
329
|
-
useEffect(() => {
|
|
330
|
-
if (!isBrowser()) return;
|
|
331
|
-
if (connectOnPageLoad) return;
|
|
332
|
-
if (!initializeOnInteraction) return;
|
|
333
|
-
if (shouldStart) return;
|
|
334
|
-
if (!normalized.domain || !normalized.token) return;
|
|
335
|
-
const onFirstInteraction = () => {
|
|
336
|
-
setShouldStart(true);
|
|
337
|
-
cleanup();
|
|
338
|
-
};
|
|
339
|
-
const cleanup = () => {
|
|
340
|
-
document.removeEventListener("pointerdown", onFirstInteraction, true);
|
|
341
|
-
document.removeEventListener("keydown", onFirstInteraction, true);
|
|
342
|
-
};
|
|
343
|
-
document.addEventListener("pointerdown", onFirstInteraction, true);
|
|
344
|
-
document.addEventListener("keydown", onFirstInteraction, true);
|
|
345
|
-
return cleanup;
|
|
346
|
-
}, [
|
|
347
|
-
connectOnPageLoad,
|
|
348
|
-
initializeOnInteraction,
|
|
349
|
-
normalized.domain,
|
|
350
|
-
normalized.token,
|
|
351
|
-
shouldStart
|
|
352
|
-
]);
|
|
353
|
-
useEffect(() => {
|
|
354
|
-
const api = apiRef.current;
|
|
355
|
-
if (!api) return;
|
|
356
|
-
if (Array.isArray(tags) && tags.length) api.setTags?.(tags);
|
|
357
|
-
if (contactFields && Object.keys(contactFields).length) api.setContactFields?.(contactFields);
|
|
358
|
-
if (conversationFields && Object.keys(conversationFields).length) api.setConversationFields?.(conversationFields);
|
|
359
|
-
}, [
|
|
360
|
-
tags,
|
|
361
|
-
contactFields,
|
|
362
|
-
conversationFields
|
|
363
|
-
]);
|
|
364
|
-
const methods = useMemo(() => {
|
|
365
|
-
const callOrQueue = (fn) => {
|
|
366
|
-
const api = apiRef.current;
|
|
367
|
-
if (api) {
|
|
368
|
-
fn(api);
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
if (!connectOnPageLoad) {
|
|
372
|
-
initialize();
|
|
373
|
-
pendingCallsRef.current.push(fn);
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
return {
|
|
377
|
-
initialize,
|
|
378
|
-
openWidget: () => callOrQueue((api) => api.openWidget?.()),
|
|
379
|
-
closeWidget: () => callOrQueue((api) => api.closeWidget?.()),
|
|
380
|
-
hideWidget: () => callOrQueue((api) => api.hideWidget?.()),
|
|
381
|
-
setTags: (t) => callOrQueue((api) => api.setTags?.(t)),
|
|
382
|
-
setContactFields: (f) => callOrQueue((api) => api.setContactFields?.(f)),
|
|
383
|
-
setConversationFields: (f) => callOrQueue((api) => api.setConversationFields?.(f))
|
|
384
|
-
};
|
|
385
|
-
}, [connectOnPageLoad, initialize]);
|
|
386
|
-
const value = useMemo(() => {
|
|
387
|
-
return {
|
|
388
|
-
...methods,
|
|
389
|
-
isReady,
|
|
390
|
-
api: apiRef.current
|
|
391
|
-
};
|
|
392
|
-
}, [methods, isReady]);
|
|
393
|
-
return /* @__PURE__ */ jsx(SparrowDeskContext.Provider, {
|
|
394
|
-
value,
|
|
395
|
-
children
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
//#endregion
|
|
400
|
-
export { Chat, SparrowDeskProvider, useSparrowDesk };
|
|
1
|
+
import*as e from"react";import{useEffect as t,useMemo as n,useRef as r,useState as i}from"react";import{jsx as a}from"react/jsx-runtime";const o=`https://assets.cdn.sparrowdesk.com/chatbot/bundle/main.js`,s=1e4,c=`script[data-sd-chat-widget="true"]`;function l(){return globalThis.document!==void 0}function u(e){return e.trim()}function d(e,t){let n=globalThis;n.SD_WIDGET_DOMAIN=e,n.SD_WIDGET_TOKEN=t}const f=new Map;function p(e){document.querySelectorAll(c).forEach(t=>{t.src!==e&&t.remove()})}function m(e,t){let n=f.get(e);if(n)return n.refCount+=1,{release(){--n.refCount,!(n.refCount>0)&&(t&&n.script.remove(),f.delete(e))}};let r=document.querySelector(c),i={script:r?.src===e?r:(()=>{let t=document.createElement(`script`);return t.async=!0,t.src=e,t.dataset.sdChatWidget=`true`,document.body.appendChild(t),t})(),refCount:1};return f.set(e,i),{release(){--i.refCount,!(i.refCount>0)&&(t&&i.script.remove(),f.delete(e))}}}async function h(e){let t=globalThis;if(t.sparrowDesk)return t.sparrowDesk;if(e<=0)return null;let n=Date.now();for(;Date.now()-n<e;){if(t.sparrowDesk)return t.sparrowDesk;await new Promise(e=>setTimeout(e,50))}return null}function g(e){let n=r(e);return t(()=>{n.current=e},[e]),n}const _=({domain:e,token:c,tags:f,contactFields:_,conversationFields:v,onReady:y,onOpen:b,onClose:x,openOnInit:S=!1,hideOnInit:C=!1,shouldInitialize:w=!0,connectOnPageLoad:T=!0,initializeOnInteraction:E=!0,cleanupOnUnmount:D=!1,readyTimeoutMs:O=s})=>{let k=n(()=>({domain:u(e),token:u(c)}),[e,c]),A=g(b),j=g(x),M=g(y),N=g(f),P=g(_),F=g(v),I=r(!1),L=r(null),R=r(!1),z=r(!1),[B,V]=i(T);return t(()=>{V(T)},[T]),t(()=>{R.current=!1,z.current=!1,L.current=null,I.current=!1,V(T)},[k.domain,k.token,T]),t(()=>{if(!l()||!k.domain||!k.token||(d(k.domain,k.token),!w)||!B)return;p(o);let e=m(o,D);return()=>{e.release()}},[k.domain,k.token,D,w,B]),t(()=>{if(!l()||!k.domain||!k.token||!B)return;let e=!1;return(async()=>{let t=await h(O);if(e||!t)return;L.current=t,I.current||=(t.onOpen?.(()=>A.current?.()),t.onClose?.(()=>j.current?.()),!0),M.current?.(t);let n=N.current,r=P.current,i=F.current;Array.isArray(n)&&n.length&&t.setTags?.(n),r&&Object.keys(r).length&&t.setContactFields?.(r),i&&Object.keys(i).length&&t.setConversationFields?.(i),C&&!z.current&&(t.hideWidget?.(),z.current=!0),S&&!R.current&&(t.openWidget?.(),R.current=!0)})(),()=>{e=!0}},[k.domain,k.token,S,C,O,B]),t(()=>{if(!l()||T||!E||B||!k.domain||!k.token)return;let e=()=>{V(!0),t()},t=()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,e,!0)};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,e,!0),t},[T,E,k.domain,k.token,B]),t(()=>{let e=L.current;e&&(Array.isArray(f)&&f.length&&e.setTags?.(f),_&&Object.keys(_).length&&e.setContactFields?.(_),v&&Object.keys(v).length&&e.setConversationFields?.(v))},[f,_,v]),!k.domain||!k.token?null:a(`div`,{"data-sd-chat-widget-container":``})},v=e.createContext(null);function y(){let t=e.useContext(v);if(!t)throw Error(`useSparrowDesk must be used within <SparrowDeskProvider />`);return t}function b({domain:c,token:f,children:_,shouldInitialize:y=!0,connectOnPageLoad:b=!0,initializeOnInteraction:x=!0,tags:S,contactFields:C,conversationFields:w,onReady:T,onOpen:E,onClose:D,openOnInit:O=!1,hideOnInit:k=!1,cleanupOnUnmount:A=!1,readyTimeoutMs:j=s}){let M=n(()=>({domain:u(c),token:u(f)}),[c,f]),N=g(T),P=g(E),F=g(D),I=g(S),L=g(C),R=g(w),z=g(O),B=g(k),V=r(null),H=r(!1),U=r(!1),W=r(!1),G=r(null),K=r(!1),q=r(null),J=r([]),[Y,X]=i(!1),[Z,Q]=i(b);t(()=>{Q(b)},[b]),t(()=>{U.current=!1,W.current=!1,V.current=null,H.current=!1,K.current=!1,q.current?.(),q.current=null,J.current=[],G.current?.release(),G.current=null,X(!1),Q(b)},[M.domain,M.token,b]);let $=e.useCallback(()=>{if(!l()||!M.domain||!M.token||(d(M.domain,M.token),y&&!G.current&&(p(o),G.current=m(o,A)),K.current))return;K.current=!0;let e=!1;q.current=()=>{e=!0},(async()=>{let t=await h(j);if(e||!t)return;V.current=t,X(!0),H.current||=(t.onOpen?.(()=>P.current?.()),t.onClose?.(()=>F.current?.()),!0),N.current?.(t);let n=I.current,r=L.current,i=R.current;Array.isArray(n)&&n.length&&t.setTags?.(n),r&&Object.keys(r).length&&t.setContactFields?.(r),i&&Object.keys(i).length&&t.setConversationFields?.(i),B.current&&!W.current&&(t.hideWidget?.(),W.current=!0),z.current&&!U.current&&(t.openWidget?.(),U.current=!0);let a=J.current;J.current=[],a.forEach(e=>e(t))})()},[A,M.domain,M.token,j,y]);t(()=>{if(l()&&!(!M.domain||!M.token)&&(d(M.domain,M.token),Z))return $(),()=>{q.current?.(),q.current=null,V.current||(K.current=!1),G.current?.release(),G.current=null}},[$,M.domain,M.token,Z]),t(()=>{if(!l()||b||!x||Z||!M.domain||!M.token)return;let e=()=>{Q(!0),t()},t=()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,e,!0)};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,e,!0),t},[b,x,M.domain,M.token,Z]),t(()=>{let e=V.current;e&&(Array.isArray(S)&&S.length&&e.setTags?.(S),C&&Object.keys(C).length&&e.setContactFields?.(C),w&&Object.keys(w).length&&e.setConversationFields?.(w))},[S,C,w]);let ee=n(()=>{let e=e=>{let t=V.current;if(t){e(t);return}$(),J.current.length<50&&J.current.push(e)};return{initialize:$,openWidget:()=>e(e=>e.openWidget?.()),closeWidget:()=>e(e=>e.closeWidget?.()),hideWidget:()=>e(e=>e.hideWidget?.()),setTags:t=>e(e=>e.setTags?.(t)),setContactFields:t=>e(e=>e.setContactFields?.(t)),setConversationFields:t=>e(e=>e.setConversationFields?.(t))}},[$]),te=n(()=>({...ee,isReady:Y,api:V.current}),[ee,Y]);return a(v.Provider,{value:te,children:_})}export{_ as Chat,b as SparrowDeskProvider,y as useSparrowDesk};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sparrowdesk/react-chat",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2",
|
|
5
5
|
"description": "SparrowDesk Chat Widget for React.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"sparrowdesk",
|
|
@@ -37,15 +37,6 @@
|
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "tsdown",
|
|
42
|
-
"dev": "tsdown --watch",
|
|
43
|
-
"test": "vitest run",
|
|
44
|
-
"test:watch": "vitest",
|
|
45
|
-
"typecheck": "tsc --noEmit",
|
|
46
|
-
"release": "bumpp && pnpm publish",
|
|
47
|
-
"prepublishOnly": "pnpm run build"
|
|
48
|
-
},
|
|
49
40
|
"peerDependencies": {
|
|
50
41
|
"react": "^19.2.0",
|
|
51
42
|
"react-dom": "^19.2.0"
|
|
@@ -64,5 +55,13 @@
|
|
|
64
55
|
"typescript": "^5.9.3",
|
|
65
56
|
"vitest": "^4.0.16",
|
|
66
57
|
"vitest-browser-react": "^2.0.2"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsdown",
|
|
61
|
+
"dev": "tsdown --watch",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:watch": "vitest",
|
|
64
|
+
"typecheck": "tsc --noEmit",
|
|
65
|
+
"release": "bumpp && pnpm publish"
|
|
67
66
|
}
|
|
68
|
-
}
|
|
67
|
+
}
|