reflet-sdk 0.6.5 → 0.6.6
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/CHANGELOG.md +17 -0
- package/README.md +100 -2
- package/dist/{client-DAdWdIFY.js → client-oFFfRxAM.js} +135 -59
- package/dist/client-oFFfRxAM.js.map +1 -0
- package/dist/client-transport-B7BdVU7J.d.ts +150 -0
- package/dist/client-transport-B7BdVU7J.d.ts.map +1 -0
- package/dist/{devtools-layer-CEjzYGBB.js → devtools-layer-B91EVgqg.js} +417 -916
- package/dist/devtools-layer-B91EVgqg.js.map +1 -0
- package/dist/devtools-next.js +1 -1
- package/dist/devtools-vite.js +2 -2
- package/dist/feedback.d.ts +7 -1
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +105 -57
- package/dist/feedback.js.map +1 -1
- package/dist/{handler-BSNmdHXv.js → handler-yA_knIf3.js} +4 -4
- package/dist/{handler-BSNmdHXv.js.map → handler-yA_knIf3.js.map} +1 -1
- package/dist/index-Buum9tIY.d.ts +230 -0
- package/dist/index-Buum9tIY.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/options-CIBazDPp.d.ts.map +1 -1
- package/dist/protocol-vJhQHTcB.js +390 -0
- package/dist/protocol-vJhQHTcB.js.map +1 -0
- package/dist/{react-context-Caq1fodf.js → react-context-Kazo_JCz.js} +3 -14
- package/dist/react-context-Kazo_JCz.js.map +1 -0
- package/dist/react.d.ts +43 -3
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +389 -3
- package/dist/react.js.map +1 -1
- package/dist/selection-outline-NzAAAZXR.js +51 -0
- package/dist/selection-outline-NzAAAZXR.js.map +1 -0
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/sessions-panel-DVyWzZ3C.js +6011 -0
- package/dist/sessions-panel-DVyWzZ3C.js.map +1 -0
- package/dist/{submit-MvVjNdYc.js → submit-DYGZQVdG.js} +44 -70
- package/dist/submit-DYGZQVdG.js.map +1 -0
- package/dist/surveys.d.ts +3 -0
- package/dist/surveys.js +2 -0
- package/dist/team-activation-DCqh71bl.js +24 -0
- package/dist/team-activation-DCqh71bl.js.map +1 -0
- package/dist/team-layer-F-9BE4hc.js +423 -0
- package/dist/team-layer-F-9BE4hc.js.map +1 -0
- package/dist/{types-DnaDEN9Y.d.ts → types-B3XiHPqy.d.ts} +4 -9
- package/dist/types-B3XiHPqy.d.ts.map +1 -0
- package/dist/use-survey-session-LK6sN1Fg.js +1247 -0
- package/dist/use-survey-session-LK6sN1Fg.js.map +1 -0
- package/dist/z-index-CwokqVq_.js +15 -0
- package/dist/z-index-CwokqVq_.js.map +1 -0
- package/package.json +6 -2
- package/dist/client-DAdWdIFY.js.map +0 -1
- package/dist/client-DF1fdsSC.d.ts +0 -131
- package/dist/client-DF1fdsSC.d.ts.map +0 -1
- package/dist/devtools-layer-CEjzYGBB.js.map +0 -1
- package/dist/protocol-ClqTFzwR.js +0 -35
- package/dist/protocol-ClqTFzwR.js.map +0 -1
- package/dist/react-context-Caq1fodf.js.map +0 -1
- package/dist/submit-MvVjNdYc.js.map +0 -1
- package/dist/types-DnaDEN9Y.d.ts.map +0 -1
package/dist/react.js
CHANGED
|
@@ -1,7 +1,115 @@
|
|
|
1
|
-
import { n as Reflet } from "./client-
|
|
2
|
-
import { a as
|
|
1
|
+
import { i as surveyRegistryKey, n as Reflet, r as surveyControllers } from "./client-oFFfRxAM.js";
|
|
2
|
+
import { a as SurveySession, c as displayOf, i as SurveyCard, n as useSurveySession, o as previewTransport, r as createRefletSurveyTransport, t as useSessionHandle } from "./use-survey-session-LK6sN1Fg.js";
|
|
3
|
+
import { i as useRefletContext, n as RefletProvider, r as useRefletClient, t as RefletContext } from "./react-context-Kazo_JCz.js";
|
|
4
|
+
import { t as REFLET_Z_INDEX } from "./z-index-CwokqVq_.js";
|
|
3
5
|
import { cloneElement, isValidElement, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { createPortal } from "react-dom";
|
|
8
|
+
//#region ../survey-core/src/targeting.ts
|
|
9
|
+
const PATTERN_SEPARATOR = /[,\n]/;
|
|
10
|
+
const REGEX_SPECIAL_CHARS = /[.+?^${}()|[\]\\]/g;
|
|
11
|
+
const WILDCARD = /\*/g;
|
|
12
|
+
const TRAILING_SLASHES = /\/+$/;
|
|
13
|
+
const stripTrailingSlash = (path) => path.replace(TRAILING_SLASHES, "") || "/";
|
|
14
|
+
const patternToRegex = (pattern) => {
|
|
15
|
+
const escaped = stripTrailingSlash(pattern).replace(REGEX_SPECIAL_CHARS, "\\$&").replace(WILDCARD, ".*");
|
|
16
|
+
return new RegExp(`^${escaped}/?$`, "i");
|
|
17
|
+
};
|
|
18
|
+
const HASH_ROUTE_PREFIX = "#/";
|
|
19
|
+
const HASH_ROUTE_QUERY = /\?.*$/;
|
|
20
|
+
const hashRoutePathOf = (url) => url.hash.startsWith(HASH_ROUTE_PREFIX) ? [stripTrailingSlash(url.hash.slice(1).replace(HASH_ROUTE_QUERY, ""))] : [];
|
|
21
|
+
/**
|
|
22
|
+
* Comma- or newline-separated patterns with `*` wildcards. A pattern starting
|
|
23
|
+
* with `/` matches the path (or a `#/` hash route); one with a scheme matches
|
|
24
|
+
* the full URL; anything else matches host and path. Empty matches every page.
|
|
25
|
+
*/
|
|
26
|
+
const matchesPageUrl = (patterns, href) => {
|
|
27
|
+
const list = (patterns ?? "").split(PATTERN_SEPARATOR).map((pattern) => pattern.trim()).filter(Boolean);
|
|
28
|
+
if (list.length === 0) return true;
|
|
29
|
+
let url;
|
|
30
|
+
try {
|
|
31
|
+
url = new URL(href);
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
const path = stripTrailingSlash(url.pathname);
|
|
36
|
+
const paths = [path, ...hashRoutePathOf(url)];
|
|
37
|
+
const candidatesFor = (pattern) => {
|
|
38
|
+
if (pattern.startsWith("/")) return paths;
|
|
39
|
+
return pattern.includes("://") ? [`${url.origin}${path}`] : [`${url.host}${path}`];
|
|
40
|
+
};
|
|
41
|
+
return list.some((pattern) => {
|
|
42
|
+
const regex = patternToRegex(pattern);
|
|
43
|
+
return candidatesFor(pattern).some((candidate) => regex.test(candidate));
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region ../survey-core/src/triggers.ts
|
|
48
|
+
const URL_POLL_INTERVAL_MS = 1e3;
|
|
49
|
+
/**
|
|
50
|
+
* Arms every survey's trigger on the page: page visits (including client-side
|
|
51
|
+
* navigation), time on page, exit intent, custom events and submitted feedback.
|
|
52
|
+
* Each survey fires at most once per page session.
|
|
53
|
+
*/
|
|
54
|
+
const createSurveyTriggers = (options) => {
|
|
55
|
+
const win = options.window ?? window;
|
|
56
|
+
const fired = /* @__PURE__ */ new Set();
|
|
57
|
+
const timers = /* @__PURE__ */ new Map();
|
|
58
|
+
let surveys = options.surveys;
|
|
59
|
+
let lastHref = win.location.href;
|
|
60
|
+
const onCurrentPage = (survey) => matchesPageUrl(survey.triggerConfig?.pageUrl, win.location.href);
|
|
61
|
+
const fire = (survey) => {
|
|
62
|
+
if (fired.has(survey._id) || !onCurrentPage(survey)) return;
|
|
63
|
+
if (options.onTrigger(survey)) fired.add(survey._id);
|
|
64
|
+
};
|
|
65
|
+
const clearTimers = () => {
|
|
66
|
+
for (const timer of timers.values()) win.clearTimeout(timer);
|
|
67
|
+
timers.clear();
|
|
68
|
+
};
|
|
69
|
+
const armPage = () => {
|
|
70
|
+
clearTimers();
|
|
71
|
+
for (const survey of surveys) {
|
|
72
|
+
if (fired.has(survey._id) || !onCurrentPage(survey)) continue;
|
|
73
|
+
if (survey.triggerType === "page_visit") fire(survey);
|
|
74
|
+
if (survey.triggerType === "time_delay") {
|
|
75
|
+
const delayMs = survey.triggerConfig?.delayMs ?? 5e3;
|
|
76
|
+
timers.set(survey._id, win.setTimeout(() => fire(survey), delayMs));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const fireAll = (matches) => {
|
|
81
|
+
for (const survey of surveys) if (matches(survey)) fire(survey);
|
|
82
|
+
};
|
|
83
|
+
const onMouseOut = (event) => {
|
|
84
|
+
if (event.relatedTarget === null && event.clientY <= 0) fireAll((survey) => survey.triggerType === "exit_intent");
|
|
85
|
+
};
|
|
86
|
+
const onNavigation = () => {
|
|
87
|
+
if (win.location.href === lastHref) return;
|
|
88
|
+
lastHref = win.location.href;
|
|
89
|
+
armPage();
|
|
90
|
+
};
|
|
91
|
+
win.document.addEventListener("mouseout", onMouseOut);
|
|
92
|
+
win.addEventListener("popstate", onNavigation);
|
|
93
|
+
win.addEventListener("hashchange", onNavigation);
|
|
94
|
+
const urlPoll = win.setInterval(onNavigation, URL_POLL_INTERVAL_MS);
|
|
95
|
+
armPage();
|
|
96
|
+
return {
|
|
97
|
+
destroy: () => {
|
|
98
|
+
clearTimers();
|
|
99
|
+
win.clearInterval(urlPoll);
|
|
100
|
+
win.document.removeEventListener("mouseout", onMouseOut);
|
|
101
|
+
win.removeEventListener("popstate", onNavigation);
|
|
102
|
+
win.removeEventListener("hashchange", onNavigation);
|
|
103
|
+
},
|
|
104
|
+
notifyFeedbackSubmitted: () => fireAll((survey) => survey.triggerType === "feedback_submitted"),
|
|
105
|
+
setSurveys: (next) => {
|
|
106
|
+
surveys = next;
|
|
107
|
+
armPage();
|
|
108
|
+
},
|
|
109
|
+
track: (eventName) => fireAll((survey) => survey.triggerType === "event" && survey.triggerConfig?.eventName === eventName)
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
5
113
|
//#region src/react-changelog-widget.tsx
|
|
6
114
|
/**
|
|
7
115
|
* React component that wraps the Reflet Changelog Widget.
|
|
@@ -1217,6 +1325,284 @@ function useUnreadChangelogCount(publicKey) {
|
|
|
1217
1325
|
};
|
|
1218
1326
|
}
|
|
1219
1327
|
//#endregion
|
|
1220
|
-
|
|
1328
|
+
//#region src/surveys/controller.ts
|
|
1329
|
+
/**
|
|
1330
|
+
* Owns in-app delivery for one Reflet project: eligible surveys, armed
|
|
1331
|
+
* triggers and the survey on screen. Lives outside React so signals sent
|
|
1332
|
+
* before `<RefletSurveys />` has loaded surveys are queued, not lost.
|
|
1333
|
+
*/
|
|
1334
|
+
var SurveyController = class {
|
|
1335
|
+
callbacks = {};
|
|
1336
|
+
active = null;
|
|
1337
|
+
client = null;
|
|
1338
|
+
generation = 0;
|
|
1339
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1340
|
+
pending = [];
|
|
1341
|
+
surveys = null;
|
|
1342
|
+
triggers = null;
|
|
1343
|
+
subscribe = (listener) => {
|
|
1344
|
+
this.listeners.add(listener);
|
|
1345
|
+
return () => this.listeners.delete(listener);
|
|
1346
|
+
};
|
|
1347
|
+
getActiveSession = () => this.active;
|
|
1348
|
+
attach(client) {
|
|
1349
|
+
this.generation += 1;
|
|
1350
|
+
const generation = this.generation;
|
|
1351
|
+
this.client = client;
|
|
1352
|
+
this.triggers = createSurveyTriggers({
|
|
1353
|
+
onTrigger: (survey) => this.activate(survey),
|
|
1354
|
+
surveys: []
|
|
1355
|
+
});
|
|
1356
|
+
this.refresh();
|
|
1357
|
+
return () => {
|
|
1358
|
+
if (generation !== this.generation) return;
|
|
1359
|
+
this.generation += 1;
|
|
1360
|
+
this.triggers?.destroy();
|
|
1361
|
+
this.triggers = null;
|
|
1362
|
+
this.client = null;
|
|
1363
|
+
this.surveys = null;
|
|
1364
|
+
this.active?.dismiss();
|
|
1365
|
+
this.setActive(null);
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
track(eventName) {
|
|
1369
|
+
if (this.triggers && this.surveys) {
|
|
1370
|
+
this.triggers.track(eventName);
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
this.enqueue({
|
|
1374
|
+
eventName,
|
|
1375
|
+
kind: "track"
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
notifyFeedbackSubmitted() {
|
|
1379
|
+
if (this.triggers && this.surveys) {
|
|
1380
|
+
this.triggers.notifyFeedbackSubmitted();
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
this.enqueue({ kind: "feedback_submitted" });
|
|
1384
|
+
}
|
|
1385
|
+
showSurvey(surveyId) {
|
|
1386
|
+
if (!this.surveys) {
|
|
1387
|
+
this.enqueue({
|
|
1388
|
+
kind: "show",
|
|
1389
|
+
surveyId
|
|
1390
|
+
});
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
const survey = this.surveys.find((candidate) => candidate._id === surveyId);
|
|
1394
|
+
if (survey) this.activate(survey);
|
|
1395
|
+
}
|
|
1396
|
+
dismissSurvey() {
|
|
1397
|
+
this.active?.dismiss();
|
|
1398
|
+
}
|
|
1399
|
+
async refresh() {
|
|
1400
|
+
const client = this.client;
|
|
1401
|
+
const generation = this.generation;
|
|
1402
|
+
if (!client) return;
|
|
1403
|
+
let surveys;
|
|
1404
|
+
try {
|
|
1405
|
+
surveys = await client.getEligibleSurveys();
|
|
1406
|
+
} catch {
|
|
1407
|
+
surveys = [];
|
|
1408
|
+
}
|
|
1409
|
+
if (generation !== this.generation) return;
|
|
1410
|
+
this.surveys = surveys;
|
|
1411
|
+
this.triggers?.setSurveys(surveys);
|
|
1412
|
+
const pending = this.pending;
|
|
1413
|
+
this.pending = [];
|
|
1414
|
+
for (const call of pending) if (call.kind === "track") this.track(call.eventName);
|
|
1415
|
+
else if (call.kind === "feedback_submitted") this.notifyFeedbackSubmitted();
|
|
1416
|
+
else this.showSurvey(call.surveyId);
|
|
1417
|
+
}
|
|
1418
|
+
enqueue(call) {
|
|
1419
|
+
this.pending = [...this.pending, call].slice(-50);
|
|
1420
|
+
}
|
|
1421
|
+
activate(survey) {
|
|
1422
|
+
const client = this.client;
|
|
1423
|
+
if (this.active || !client) return false;
|
|
1424
|
+
const session = new SurveySession({
|
|
1425
|
+
callbacks: {
|
|
1426
|
+
onAnswer: (event) => this.callbacks.onSurveyAnswer?.(event),
|
|
1427
|
+
onComplete: (event) => this.callbacks.onSurveyComplete?.(event),
|
|
1428
|
+
onDismiss: (event) => this.callbacks.onSurveyDismiss?.(event),
|
|
1429
|
+
onStart: (event) => this.callbacks.onSurveyStart?.(event)
|
|
1430
|
+
},
|
|
1431
|
+
survey,
|
|
1432
|
+
transport: createRefletSurveyTransport(client)
|
|
1433
|
+
});
|
|
1434
|
+
const unsubscribe = session.subscribe(() => {
|
|
1435
|
+
if (session.getSnapshot().phase !== "dismissed") return;
|
|
1436
|
+
unsubscribe();
|
|
1437
|
+
if (this.active === session) {
|
|
1438
|
+
this.setActive(null);
|
|
1439
|
+
this.refresh();
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
this.setActive(session);
|
|
1443
|
+
session.start().then(() => {
|
|
1444
|
+
if (session.getSnapshot().phase === "start_failed" && this.active === session) {
|
|
1445
|
+
unsubscribe();
|
|
1446
|
+
this.setActive(null);
|
|
1447
|
+
}
|
|
1448
|
+
});
|
|
1449
|
+
return true;
|
|
1450
|
+
}
|
|
1451
|
+
setActive(session) {
|
|
1452
|
+
this.active = session;
|
|
1453
|
+
for (const listener of this.listeners) listener();
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
/** Shared by `<RefletSurveys />`, `useRefletSurveys()` and the client's feedback signal. */
|
|
1457
|
+
const surveyControllerFor = (publicKey, baseUrl) => {
|
|
1458
|
+
const key = surveyRegistryKey(publicKey, baseUrl ?? "https://harmless-clam-802.convex.site");
|
|
1459
|
+
let controller = surveyControllers.get(key);
|
|
1460
|
+
if (!controller) {
|
|
1461
|
+
controller = new SurveyController();
|
|
1462
|
+
surveyControllers.set(key, controller);
|
|
1463
|
+
}
|
|
1464
|
+
return controller;
|
|
1465
|
+
};
|
|
1466
|
+
//#endregion
|
|
1467
|
+
//#region src/surveys/survey-portal.tsx
|
|
1468
|
+
const SURVEY_HOST_ATTRIBUTE = "data-reflet-survey";
|
|
1469
|
+
const LAYER_STYLES = `
|
|
1470
|
+
:host { all: initial; }
|
|
1471
|
+
.rfs-layer {
|
|
1472
|
+
position: fixed;
|
|
1473
|
+
z-index: ${REFLET_Z_INDEX.surveyLayer};
|
|
1474
|
+
bottom: 20px;
|
|
1475
|
+
width: min(360px, calc(100vw - 32px));
|
|
1476
|
+
}
|
|
1477
|
+
.rfs-layer[data-position="bottom_right"] { right: 20px; }
|
|
1478
|
+
.rfs-layer[data-position="bottom_left"] { left: 20px; }
|
|
1479
|
+
.rfs-layer[data-position="center"] {
|
|
1480
|
+
inset: 0;
|
|
1481
|
+
display: grid;
|
|
1482
|
+
place-items: center;
|
|
1483
|
+
width: auto;
|
|
1484
|
+
padding: 16px;
|
|
1485
|
+
background: rgb(15 15 15 / 28%);
|
|
1486
|
+
animation: rfs-layer-fade 240ms ease-out;
|
|
1487
|
+
}
|
|
1488
|
+
.rfs-layer[data-position="center"] > .rf-survey { max-width: 420px; }
|
|
1489
|
+
@media (max-width: 480px) {
|
|
1490
|
+
.rfs-layer[data-position^="bottom"] { right: 16px; bottom: 16px; left: 16px; width: auto; }
|
|
1491
|
+
}
|
|
1492
|
+
@keyframes rfs-layer-fade { from { opacity: 0; } }
|
|
1493
|
+
@media (prefers-reduced-motion: reduce) { .rfs-layer { animation: none; } }
|
|
1494
|
+
`;
|
|
1495
|
+
/**
|
|
1496
|
+
* Hosts an in-app survey in its own shadow root so page CSS can't restyle it.
|
|
1497
|
+
* Direct DOM work is unavoidable: React can't create a shadow root declaratively.
|
|
1498
|
+
*/
|
|
1499
|
+
function SurveyPortal({ children, position }) {
|
|
1500
|
+
const [shadowRoot, setShadowRoot] = useState(null);
|
|
1501
|
+
useEffect(() => {
|
|
1502
|
+
const host = document.createElement("div");
|
|
1503
|
+
host.setAttribute(SURVEY_HOST_ATTRIBUTE, "");
|
|
1504
|
+
const root = host.attachShadow({ mode: "open" });
|
|
1505
|
+
const style = document.createElement("style");
|
|
1506
|
+
style.textContent = LAYER_STYLES;
|
|
1507
|
+
root.append(style);
|
|
1508
|
+
document.body.append(host);
|
|
1509
|
+
setShadowRoot(root);
|
|
1510
|
+
return () => host.remove();
|
|
1511
|
+
}, []);
|
|
1512
|
+
if (!shadowRoot) return null;
|
|
1513
|
+
return createPortal(/* @__PURE__ */ jsx("div", {
|
|
1514
|
+
className: "rfs-layer",
|
|
1515
|
+
"data-position": position,
|
|
1516
|
+
children
|
|
1517
|
+
}), shadowRoot);
|
|
1518
|
+
}
|
|
1519
|
+
//#endregion
|
|
1520
|
+
//#region src/surveys/reflet-surveys.tsx
|
|
1521
|
+
const ENDING_AUTO_CLOSE_MS = 6e3;
|
|
1522
|
+
function useOrganizationColor(client, override) {
|
|
1523
|
+
const [organizationColor, setOrganizationColor] = useState();
|
|
1524
|
+
useEffect(() => {
|
|
1525
|
+
if (override) return;
|
|
1526
|
+
let cancelled = false;
|
|
1527
|
+
client.getConfig().then((config) => {
|
|
1528
|
+
if (!cancelled) setOrganizationColor(config.primaryColor);
|
|
1529
|
+
}).catch(() => void 0);
|
|
1530
|
+
return () => {
|
|
1531
|
+
cancelled = true;
|
|
1532
|
+
};
|
|
1533
|
+
}, [client, override]);
|
|
1534
|
+
return override ?? organizationColor;
|
|
1535
|
+
}
|
|
1536
|
+
function ActiveSurvey({ primaryColor, session, theme }) {
|
|
1537
|
+
const handle = useSessionHandle(session);
|
|
1538
|
+
const { ending, phase } = handle.snapshot;
|
|
1539
|
+
const endsQuietly = ending !== null && !(ending.buttonUrl || ending.buttonLabel);
|
|
1540
|
+
useEffect(() => {
|
|
1541
|
+
if (!endsQuietly) return;
|
|
1542
|
+
const timer = window.setTimeout(() => session.dismiss(), ENDING_AUTO_CLOSE_MS);
|
|
1543
|
+
return () => window.clearTimeout(timer);
|
|
1544
|
+
}, [endsQuietly, session]);
|
|
1545
|
+
if (phase !== "question" && phase !== "ending") return null;
|
|
1546
|
+
return /* @__PURE__ */ jsx(SurveyPortal, {
|
|
1547
|
+
position: displayOf(session.survey.display).position ?? "bottom_right",
|
|
1548
|
+
children: /* @__PURE__ */ jsx(SurveyCard, {
|
|
1549
|
+
primaryColor,
|
|
1550
|
+
session: handle,
|
|
1551
|
+
theme,
|
|
1552
|
+
variant: "floating"
|
|
1553
|
+
})
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* In-app survey delivery. Mount once inside `RefletProvider`: it loads the
|
|
1558
|
+
* surveys this visitor is eligible for, arms their triggers and shows one at a time.
|
|
1559
|
+
*/
|
|
1560
|
+
function RefletSurveys({ enabled = true, onSurveyAnswer, onSurveyComplete, onSurveyDismiss, onSurveyStart, primaryColor, theme = "auto" }) {
|
|
1561
|
+
const { baseUrl, client, publicKey } = useRefletContext();
|
|
1562
|
+
const controller = surveyControllerFor(publicKey, baseUrl);
|
|
1563
|
+
const color = useOrganizationColor(client, primaryColor);
|
|
1564
|
+
const session = useSyncExternalStore(controller.subscribe, controller.getActiveSession, () => null);
|
|
1565
|
+
useEffect(() => {
|
|
1566
|
+
controller.callbacks = {
|
|
1567
|
+
onSurveyAnswer,
|
|
1568
|
+
onSurveyComplete,
|
|
1569
|
+
onSurveyDismiss,
|
|
1570
|
+
onSurveyStart
|
|
1571
|
+
};
|
|
1572
|
+
});
|
|
1573
|
+
useEffect(() => {
|
|
1574
|
+
if (!enabled) return;
|
|
1575
|
+
return controller.attach(client);
|
|
1576
|
+
}, [
|
|
1577
|
+
client,
|
|
1578
|
+
controller,
|
|
1579
|
+
enabled
|
|
1580
|
+
]);
|
|
1581
|
+
if (!session) return null;
|
|
1582
|
+
return /* @__PURE__ */ jsx(ActiveSurvey, {
|
|
1583
|
+
primaryColor: color,
|
|
1584
|
+
session,
|
|
1585
|
+
theme
|
|
1586
|
+
}, session.survey._id);
|
|
1587
|
+
}
|
|
1588
|
+
//#endregion
|
|
1589
|
+
//#region src/surveys/use-reflet-surveys.ts
|
|
1590
|
+
/**
|
|
1591
|
+
* Drives `<RefletSurveys />` from anywhere inside `RefletProvider`. Calls made
|
|
1592
|
+
* before surveys load are queued and replayed once they do.
|
|
1593
|
+
*/
|
|
1594
|
+
function useRefletSurveys() {
|
|
1595
|
+
const { baseUrl, publicKey } = useRefletContext();
|
|
1596
|
+
const controller = surveyControllerFor(publicKey, baseUrl);
|
|
1597
|
+
const activeSurveyId = useSyncExternalStore(controller.subscribe, () => controller.getActiveSession()?.survey._id ?? null, () => null);
|
|
1598
|
+
return useMemo(() => ({
|
|
1599
|
+
activeSurveyId,
|
|
1600
|
+
dismissSurvey: () => controller.dismissSurvey(),
|
|
1601
|
+
showSurvey: (surveyId) => controller.showSurvey(surveyId),
|
|
1602
|
+
track: (eventName) => controller.track(eventName)
|
|
1603
|
+
}), [activeSurveyId, controller]);
|
|
1604
|
+
}
|
|
1605
|
+
//#endregion
|
|
1606
|
+
export { ChangelogWidget, FeedbackButton, FeedbackDialog, Reflet, RefletContext, RefletProvider, RefletSurveys, SurveyCard, SurveySession, createRefletSurveyTransport, previewTransport, useAddComment, useChangelog, useComments, useCreateFeedback, useFeedback, useFeedbackList, useOrganizationConfig, useRefletClient, useRefletContext, useRefletSurveys, useRoadmap, useSubscription, useSurveySession, useUnreadChangelogCount, useVote };
|
|
1221
1607
|
|
|
1222
1608
|
//# sourceMappingURL=react.js.map
|