@pxlabz/tracey-react 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.
Files changed (135) hide show
  1. package/README.md +83 -0
  2. package/dist/LauncherTrigger-5pNAvA05.js +1056 -0
  3. package/dist/LauncherTrigger-5pNAvA05.js.map +1 -0
  4. package/dist/LauncherTrigger-DjXDXHTm.cjs +1055 -0
  5. package/dist/LauncherTrigger-DjXDXHTm.cjs.map +1 -0
  6. package/dist/__tests__/api-client.test.d.ts +2 -0
  7. package/dist/__tests__/api-client.test.d.ts.map +1 -0
  8. package/dist/__tests__/events.test.d.ts +2 -0
  9. package/dist/__tests__/events.test.d.ts.map +1 -0
  10. package/dist/__tests__/survey-logic.test.d.ts +2 -0
  11. package/dist/__tests__/survey-logic.test.d.ts.map +1 -0
  12. package/dist/components/announcements/AnnouncementBell.d.ts +9 -0
  13. package/dist/components/announcements/AnnouncementBell.d.ts.map +1 -0
  14. package/dist/components/announcements/AnnouncementList.d.ts +7 -0
  15. package/dist/components/announcements/AnnouncementList.d.ts.map +1 -0
  16. package/dist/components/announcements/AnnouncementModal.d.ts +9 -0
  17. package/dist/components/announcements/AnnouncementModal.d.ts.map +1 -0
  18. package/dist/components/announcements/headless/AnnouncementClose.d.ts +9 -0
  19. package/dist/components/announcements/headless/AnnouncementClose.d.ts.map +1 -0
  20. package/dist/components/announcements/headless/AnnouncementContent.d.ts +7 -0
  21. package/dist/components/announcements/headless/AnnouncementContent.d.ts.map +1 -0
  22. package/dist/components/announcements/headless/AnnouncementNavigation.d.ts +15 -0
  23. package/dist/components/announcements/headless/AnnouncementNavigation.d.ts.map +1 -0
  24. package/dist/components/announcements/headless/AnnouncementPortal.d.ts +7 -0
  25. package/dist/components/announcements/headless/AnnouncementPortal.d.ts.map +1 -0
  26. package/dist/components/announcements/headless/AnnouncementRoot.d.ts +24 -0
  27. package/dist/components/announcements/headless/AnnouncementRoot.d.ts.map +1 -0
  28. package/dist/components/announcements/headless/AnnouncementSlidePrimitive.d.ts +14 -0
  29. package/dist/components/announcements/headless/AnnouncementSlidePrimitive.d.ts.map +1 -0
  30. package/dist/components/announcements/headless/AnnouncementTrigger.d.ts +9 -0
  31. package/dist/components/announcements/headless/AnnouncementTrigger.d.ts.map +1 -0
  32. package/dist/components/announcements/headless/index.d.ts +8 -0
  33. package/dist/components/announcements/headless/index.d.ts.map +1 -0
  34. package/dist/components/announcements/index.d.ts +4 -0
  35. package/dist/components/announcements/index.d.ts.map +1 -0
  36. package/dist/components/feedback/FeedbackForm.d.ts +8 -0
  37. package/dist/components/feedback/FeedbackForm.d.ts.map +1 -0
  38. package/dist/components/feedback/FeedbackWidget.d.ts +9 -0
  39. package/dist/components/feedback/FeedbackWidget.d.ts.map +1 -0
  40. package/dist/components/feedback/headless/FeedbackClose.d.ts +9 -0
  41. package/dist/components/feedback/headless/FeedbackClose.d.ts.map +1 -0
  42. package/dist/components/feedback/headless/FeedbackContent.d.ts +6 -0
  43. package/dist/components/feedback/headless/FeedbackContent.d.ts.map +1 -0
  44. package/dist/components/feedback/headless/FeedbackFormPrimitive.d.ts +28 -0
  45. package/dist/components/feedback/headless/FeedbackFormPrimitive.d.ts.map +1 -0
  46. package/dist/components/feedback/headless/FeedbackPortal.d.ts +7 -0
  47. package/dist/components/feedback/headless/FeedbackPortal.d.ts.map +1 -0
  48. package/dist/components/feedback/headless/FeedbackRoot.d.ts +16 -0
  49. package/dist/components/feedback/headless/FeedbackRoot.d.ts.map +1 -0
  50. package/dist/components/feedback/headless/FeedbackTrigger.d.ts +9 -0
  51. package/dist/components/feedback/headless/FeedbackTrigger.d.ts.map +1 -0
  52. package/dist/components/feedback/headless/index.d.ts +7 -0
  53. package/dist/components/feedback/headless/index.d.ts.map +1 -0
  54. package/dist/components/feedback/index.d.ts +4 -0
  55. package/dist/components/feedback/index.d.ts.map +1 -0
  56. package/dist/components/index.d.ts +5 -0
  57. package/dist/components/index.d.ts.map +1 -0
  58. package/dist/components/launcher/TraceyLauncher.d.ts +8 -0
  59. package/dist/components/launcher/TraceyLauncher.d.ts.map +1 -0
  60. package/dist/components/launcher/headless/LauncherBadge.d.ts +8 -0
  61. package/dist/components/launcher/headless/LauncherBadge.d.ts.map +1 -0
  62. package/dist/components/launcher/headless/LauncherMenu.d.ts +6 -0
  63. package/dist/components/launcher/headless/LauncherMenu.d.ts.map +1 -0
  64. package/dist/components/launcher/headless/LauncherMenuItem.d.ts +9 -0
  65. package/dist/components/launcher/headless/LauncherMenuItem.d.ts.map +1 -0
  66. package/dist/components/launcher/headless/LauncherPanel.d.ts +6 -0
  67. package/dist/components/launcher/headless/LauncherPanel.d.ts.map +1 -0
  68. package/dist/components/launcher/headless/LauncherPortal.d.ts +7 -0
  69. package/dist/components/launcher/headless/LauncherPortal.d.ts.map +1 -0
  70. package/dist/components/launcher/headless/LauncherRoot.d.ts +21 -0
  71. package/dist/components/launcher/headless/LauncherRoot.d.ts.map +1 -0
  72. package/dist/components/launcher/headless/LauncherTab.d.ts +8 -0
  73. package/dist/components/launcher/headless/LauncherTab.d.ts.map +1 -0
  74. package/dist/components/launcher/headless/LauncherTabContent.d.ts +8 -0
  75. package/dist/components/launcher/headless/LauncherTabContent.d.ts.map +1 -0
  76. package/dist/components/launcher/headless/LauncherTrigger.d.ts +10 -0
  77. package/dist/components/launcher/headless/LauncherTrigger.d.ts.map +1 -0
  78. package/dist/components/launcher/headless/index.d.ts +10 -0
  79. package/dist/components/launcher/headless/index.d.ts.map +1 -0
  80. package/dist/components/launcher/index.d.ts +3 -0
  81. package/dist/components/launcher/index.d.ts.map +1 -0
  82. package/dist/components/surveys/SurveyWidget.d.ts +10 -0
  83. package/dist/components/surveys/SurveyWidget.d.ts.map +1 -0
  84. package/dist/components/surveys/index.d.ts +2 -0
  85. package/dist/components/surveys/index.d.ts.map +1 -0
  86. package/dist/core/api-client.d.ts +33 -0
  87. package/dist/core/api-client.d.ts.map +1 -0
  88. package/dist/core/events.d.ts +11 -0
  89. package/dist/core/events.d.ts.map +1 -0
  90. package/dist/core/index.d.ts +4 -0
  91. package/dist/core/index.d.ts.map +1 -0
  92. package/dist/core/screenshot.d.ts +12 -0
  93. package/dist/core/screenshot.d.ts.map +1 -0
  94. package/dist/core/survey-logic.d.ts +7 -0
  95. package/dist/core/survey-logic.d.ts.map +1 -0
  96. package/dist/headless.cjs +100 -0
  97. package/dist/headless.cjs.map +1 -0
  98. package/dist/headless.d.ts +11 -0
  99. package/dist/headless.d.ts.map +1 -0
  100. package/dist/headless.js +101 -0
  101. package/dist/headless.js.map +1 -0
  102. package/dist/hooks/index.d.ts +7 -0
  103. package/dist/hooks/index.d.ts.map +1 -0
  104. package/dist/hooks/useAnnouncements.d.ts +14 -0
  105. package/dist/hooks/useAnnouncements.d.ts.map +1 -0
  106. package/dist/hooks/useFeedback.d.ts +10 -0
  107. package/dist/hooks/useFeedback.d.ts.map +1 -0
  108. package/dist/hooks/useMyFeedback.d.ts +16 -0
  109. package/dist/hooks/useMyFeedback.d.ts.map +1 -0
  110. package/dist/hooks/useSurvey.d.ts +22 -0
  111. package/dist/hooks/useSurvey.d.ts.map +1 -0
  112. package/dist/hooks/useTracey.d.ts +3 -0
  113. package/dist/hooks/useTracey.d.ts.map +1 -0
  114. package/dist/hooks/useTraceyEvents.d.ts +14 -0
  115. package/dist/hooks/useTraceyEvents.d.ts.map +1 -0
  116. package/dist/index.cjs +4913 -0
  117. package/dist/index.cjs.map +1 -0
  118. package/dist/index.d.ts +19 -0
  119. package/dist/index.d.ts.map +1 -0
  120. package/dist/index.js +4892 -0
  121. package/dist/index.js.map +1 -0
  122. package/dist/lib/utils.d.ts +3 -0
  123. package/dist/lib/utils.d.ts.map +1 -0
  124. package/dist/provider/MockTraceyProvider.d.ts +14 -0
  125. package/dist/provider/MockTraceyProvider.d.ts.map +1 -0
  126. package/dist/provider/TraceyProvider.d.ts +11 -0
  127. package/dist/provider/TraceyProvider.d.ts.map +1 -0
  128. package/dist/provider/context.d.ts +19 -0
  129. package/dist/provider/context.d.ts.map +1 -0
  130. package/dist/provider/index.d.ts +4 -0
  131. package/dist/provider/index.d.ts.map +1 -0
  132. package/dist/styles.css +800 -0
  133. package/dist/types.d.ts +188 -0
  134. package/dist/types.d.ts.map +1 -0
  135. package/package.json +94 -0
@@ -0,0 +1,1055 @@
1
+ "use strict";
2
+ var __typeError = (msg) => {
3
+ throw TypeError(msg);
4
+ };
5
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
6
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
7
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
8
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
9
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
10
+ var _apiKey, _baseUrl, _customerId, _TraceyApiClient_instances, request_fn, _listeners;
11
+ const jsxRuntime = require("react/jsx-runtime");
12
+ const react = require("react");
13
+ const reactDom = require("react-dom");
14
+ const TraceyContext = react.createContext(null);
15
+ class TraceyApiClient {
16
+ constructor(config) {
17
+ __privateAdd(this, _TraceyApiClient_instances);
18
+ __privateAdd(this, _apiKey);
19
+ __privateAdd(this, _baseUrl);
20
+ __privateAdd(this, _customerId, null);
21
+ __privateSet(this, _apiKey, config.apiKey);
22
+ __privateSet(this, _baseUrl, config.baseUrl ?? "https://api.tracey.dev");
23
+ }
24
+ setCustomerId(id) {
25
+ __privateSet(this, _customerId, id);
26
+ }
27
+ getCustomerId() {
28
+ return __privateGet(this, _customerId);
29
+ }
30
+ async identify(user) {
31
+ const { userHash, ...userData } = user;
32
+ return __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, "/api/sdk/identify", {
33
+ method: "POST",
34
+ body: JSON.stringify({
35
+ ...userData,
36
+ ...userHash ? { userHash } : {}
37
+ })
38
+ });
39
+ }
40
+ async getAnnouncements(filter = "unread") {
41
+ const params = new URLSearchParams();
42
+ if (__privateGet(this, _customerId)) {
43
+ params.set("customerId", __privateGet(this, _customerId));
44
+ }
45
+ params.set("filter", filter);
46
+ return __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, `/api/sdk/announcements?${params.toString()}`);
47
+ }
48
+ async getUnreadCount() {
49
+ if (!__privateGet(this, _customerId)) {
50
+ throw new Error("Customer ID not set. Call identify first.");
51
+ }
52
+ return __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, `/api/sdk/announcements/unread-count?customerId=${encodeURIComponent(__privateGet(this, _customerId))}`);
53
+ }
54
+ async trackAnnouncementView(announcementId) {
55
+ if (!__privateGet(this, _customerId)) {
56
+ throw new Error("Customer ID not set. Call identify first.");
57
+ }
58
+ await __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, `/api/sdk/announcements/${announcementId}/view`, {
59
+ method: "POST",
60
+ body: JSON.stringify({ customerId: __privateGet(this, _customerId) })
61
+ });
62
+ }
63
+ async trackAnnouncementCta(announcementId) {
64
+ if (!__privateGet(this, _customerId)) {
65
+ throw new Error("Customer ID not set. Call identify first.");
66
+ }
67
+ await __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, `/api/sdk/announcements/${announcementId}/cta`, {
68
+ method: "POST",
69
+ body: JSON.stringify({ customerId: __privateGet(this, _customerId) })
70
+ });
71
+ }
72
+ async submitFeedback(feedback) {
73
+ return __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, "/api/sdk/feedback", {
74
+ method: "POST",
75
+ body: JSON.stringify({
76
+ ...feedback,
77
+ customerId: __privateGet(this, _customerId) ?? void 0
78
+ })
79
+ });
80
+ }
81
+ async getMyFeedback(params) {
82
+ if (!__privateGet(this, _customerId)) {
83
+ throw new Error("Customer ID not set. Call identify first.");
84
+ }
85
+ const searchParams = new URLSearchParams();
86
+ searchParams.set("customerId", __privateGet(this, _customerId));
87
+ if ((params == null ? void 0 : params.limit) !== void 0) {
88
+ searchParams.set("limit", String(params.limit));
89
+ }
90
+ if ((params == null ? void 0 : params.offset) !== void 0) {
91
+ searchParams.set("offset", String(params.offset));
92
+ }
93
+ return __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, `/api/sdk/feedback/mine?${searchParams.toString()}`);
94
+ }
95
+ async getActiveSurvey(context) {
96
+ const params = new URLSearchParams();
97
+ if (__privateGet(this, _customerId)) params.set("customerId", __privateGet(this, _customerId));
98
+ if (context == null ? void 0 : context.anonymousSessionId) {
99
+ params.set("anonymousSessionId", context.anonymousSessionId);
100
+ }
101
+ if (context == null ? void 0 : context.url) params.set("url", context.url);
102
+ const query = params.toString();
103
+ const response = await __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, `/api/sdk/surveys${query ? `?${query}` : ""}`);
104
+ return response.survey;
105
+ }
106
+ async submitSurveyResponse(surveyId, payload) {
107
+ return __privateMethod(this, _TraceyApiClient_instances, request_fn).call(this, `/api/sdk/surveys/${surveyId}/responses`, {
108
+ method: "POST",
109
+ body: JSON.stringify({
110
+ customerId: __privateGet(this, _customerId) ?? void 0,
111
+ anonymousSessionId: payload.anonymousSessionId,
112
+ respondentEmail: payload.respondentEmail,
113
+ respondentName: payload.respondentName,
114
+ metadata: payload.metadata,
115
+ answers: payload.answers
116
+ })
117
+ });
118
+ }
119
+ }
120
+ _apiKey = new WeakMap();
121
+ _baseUrl = new WeakMap();
122
+ _customerId = new WeakMap();
123
+ _TraceyApiClient_instances = new WeakSet();
124
+ request_fn = async function(path, options = {}) {
125
+ const url = `${__privateGet(this, _baseUrl)}${path}`;
126
+ const headers = new Headers(options.headers);
127
+ headers.set("Authorization", `Bearer ${__privateGet(this, _apiKey)}`);
128
+ headers.set("Content-Type", "application/json");
129
+ const response = await fetch(url, {
130
+ ...options,
131
+ headers
132
+ });
133
+ if (!response.ok) {
134
+ const error = await response.json().catch(() => ({
135
+ message: `HTTP ${response.status}: ${response.statusText}`
136
+ }));
137
+ throw new Error(error.message);
138
+ }
139
+ return response.json();
140
+ };
141
+ class TraceyEventEmitter {
142
+ constructor() {
143
+ __privateAdd(this, _listeners, /* @__PURE__ */ new Map());
144
+ }
145
+ subscribe(event, callback) {
146
+ if (!__privateGet(this, _listeners).has(event)) {
147
+ __privateGet(this, _listeners).set(event, /* @__PURE__ */ new Set());
148
+ }
149
+ const listeners = __privateGet(this, _listeners).get(event);
150
+ listeners.add(callback);
151
+ return () => {
152
+ listeners.delete(callback);
153
+ };
154
+ }
155
+ unsubscribe(event, callback) {
156
+ const listeners = __privateGet(this, _listeners).get(event);
157
+ if (listeners) {
158
+ listeners.delete(callback);
159
+ }
160
+ }
161
+ emit(event, data) {
162
+ const listeners = __privateGet(this, _listeners).get(event);
163
+ if (listeners) {
164
+ listeners.forEach((callback) => {
165
+ try {
166
+ callback(data);
167
+ } catch (error) {
168
+ console.error(`Error in event listener for ${event}:`, error);
169
+ }
170
+ });
171
+ }
172
+ }
173
+ clear() {
174
+ __privateGet(this, _listeners).clear();
175
+ }
176
+ }
177
+ _listeners = new WeakMap();
178
+ const UNREAD_POLL_INTERVAL_MS = 5 * 60 * 1e3;
179
+ function getUnreadCacheKey(apiKey, userId) {
180
+ return `tracey:unread:${apiKey}:${userId}`;
181
+ }
182
+ function readCachedUnreadCount(apiKey, userId) {
183
+ try {
184
+ const raw = localStorage.getItem(getUnreadCacheKey(apiKey, userId));
185
+ if (raw !== null) {
186
+ const parsed = parseInt(raw, 10);
187
+ return isNaN(parsed) ? 0 : parsed;
188
+ }
189
+ } catch {
190
+ }
191
+ return 0;
192
+ }
193
+ function writeCachedUnreadCount(apiKey, userId, count) {
194
+ try {
195
+ localStorage.setItem(getUnreadCacheKey(apiKey, userId), String(count));
196
+ } catch {
197
+ }
198
+ }
199
+ function TraceyProvider({
200
+ apiKey,
201
+ baseUrl,
202
+ user,
203
+ children,
204
+ debug = false
205
+ }) {
206
+ const config = react.useMemo(
207
+ () => ({ apiKey, baseUrl, debug }),
208
+ [apiKey, baseUrl, debug]
209
+ );
210
+ const client = react.useMemo(() => new TraceyApiClient(config), [config]);
211
+ const events = react.useMemo(() => new TraceyEventEmitter(), []);
212
+ const [isIdentified, setIsIdentified] = react.useState(false);
213
+ const [isLoading, setIsLoading] = react.useState(true);
214
+ const [error, setError] = react.useState(null);
215
+ const [announcements, setAnnouncements] = react.useState([]);
216
+ const [announcementsLoading, setAnnouncementsLoading] = react.useState(false);
217
+ const [unreadCount, setUnreadCountState] = react.useState(
218
+ () => readCachedUnreadCount(apiKey, user.id)
219
+ );
220
+ const unreadCountRef = react.useRef(unreadCount);
221
+ const setUnreadCount = react.useCallback(
222
+ (count) => {
223
+ const previousCount = unreadCountRef.current;
224
+ unreadCountRef.current = count;
225
+ setUnreadCountState(count);
226
+ writeCachedUnreadCount(apiKey, user.id, count);
227
+ if (count !== previousCount) {
228
+ events.emit("unread-count-changed", {
229
+ count,
230
+ previousCount
231
+ });
232
+ }
233
+ },
234
+ [apiKey, user.id, events]
235
+ );
236
+ const fetchUnreadCount = react.useCallback(async () => {
237
+ try {
238
+ const { count } = await client.getUnreadCount();
239
+ setUnreadCount(count);
240
+ } catch {
241
+ }
242
+ }, [client, setUnreadCount]);
243
+ react.useEffect(() => {
244
+ let mounted = true;
245
+ const identify = async () => {
246
+ setIsLoading(true);
247
+ setError(null);
248
+ try {
249
+ await client.identify(user);
250
+ client.setCustomerId(user.id);
251
+ if (mounted) {
252
+ setIsIdentified(true);
253
+ events.emit("user:identified", { user });
254
+ }
255
+ } catch (err) {
256
+ if (mounted) {
257
+ const error2 = err instanceof Error ? err : new Error("Failed to identify user");
258
+ setError(error2);
259
+ events.emit("error", { error: error2, context: "identify" });
260
+ }
261
+ } finally {
262
+ if (mounted) {
263
+ setIsLoading(false);
264
+ }
265
+ }
266
+ };
267
+ identify();
268
+ return () => {
269
+ mounted = false;
270
+ };
271
+ }, [client, user, events]);
272
+ const fetchAnnouncements = react.useCallback(async () => {
273
+ if (!isIdentified) return;
274
+ setAnnouncementsLoading(true);
275
+ try {
276
+ const data = await client.getAnnouncements();
277
+ setAnnouncements(data);
278
+ } catch (err) {
279
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch announcements");
280
+ events.emit("error", { error: error2, context: "announcements" });
281
+ } finally {
282
+ setAnnouncementsLoading(false);
283
+ }
284
+ }, [client, events, isIdentified]);
285
+ react.useEffect(() => {
286
+ if (isIdentified) {
287
+ fetchAnnouncements();
288
+ fetchUnreadCount();
289
+ }
290
+ }, [isIdentified, fetchAnnouncements, fetchUnreadCount]);
291
+ react.useEffect(() => {
292
+ if (!isIdentified) return;
293
+ const interval = setInterval(fetchUnreadCount, UNREAD_POLL_INTERVAL_MS);
294
+ return () => clearInterval(interval);
295
+ }, [isIdentified, fetchUnreadCount]);
296
+ const contextValue = react.useMemo(
297
+ () => ({
298
+ config,
299
+ client,
300
+ events,
301
+ user: isIdentified ? user : null,
302
+ isIdentified,
303
+ isLoading,
304
+ error,
305
+ announcements,
306
+ announcementsLoading,
307
+ refetchAnnouncements: fetchAnnouncements,
308
+ unreadCount,
309
+ setUnreadCount
310
+ }),
311
+ [
312
+ config,
313
+ client,
314
+ events,
315
+ user,
316
+ isIdentified,
317
+ isLoading,
318
+ error,
319
+ announcements,
320
+ announcementsLoading,
321
+ fetchAnnouncements,
322
+ unreadCount,
323
+ setUnreadCount
324
+ ]
325
+ );
326
+ return /* @__PURE__ */ jsxRuntime.jsx(TraceyContext.Provider, { value: contextValue, children });
327
+ }
328
+ const defaultMockUser = {
329
+ id: "mock-user-1",
330
+ email: "demo@example.com",
331
+ name: "Demo User",
332
+ role: "user"
333
+ };
334
+ const defaultMockAnnouncements = [
335
+ {
336
+ id: 1,
337
+ title: "Welcome to Our App!",
338
+ status: "published",
339
+ displayType: "modal",
340
+ publishAt: null,
341
+ expiresAt: null,
342
+ slides: [
343
+ {
344
+ id: 1,
345
+ order: 0,
346
+ title: "Getting Started",
347
+ body: "Here's how to get the most out of our platform.",
348
+ imageUrl: null,
349
+ videoUrl: null,
350
+ ctaText: "Learn More",
351
+ ctaUrl: "https://example.com/docs"
352
+ }
353
+ ],
354
+ viewed: false,
355
+ ctaClicked: false
356
+ }
357
+ ];
358
+ function MockTraceyProvider({
359
+ children,
360
+ mockUser = defaultMockUser,
361
+ mockAnnouncements = defaultMockAnnouncements
362
+ }) {
363
+ const config = react.useMemo(
364
+ () => ({
365
+ apiKey: "mock-api-key",
366
+ baseUrl: "https://mock.tracey.dev",
367
+ debug: true
368
+ }),
369
+ []
370
+ );
371
+ const client = react.useMemo(() => {
372
+ const apiClient = new TraceyApiClient(config);
373
+ apiClient.setCustomerId(mockUser.id);
374
+ apiClient.trackAnnouncementView = async () => {
375
+ };
376
+ apiClient.trackAnnouncementCta = async () => {
377
+ };
378
+ apiClient.submitFeedback = async (feedback) => ({
379
+ id: Date.now(),
380
+ title: feedback.title,
381
+ description: feedback.description ?? null,
382
+ type: feedback.type,
383
+ status: "new",
384
+ category: feedback.category ?? null,
385
+ tags: feedback.tags ?? null,
386
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
387
+ });
388
+ apiClient.identify = async () => ({ success: true });
389
+ apiClient.getAnnouncements = async () => mockAnnouncements;
390
+ apiClient.getUnreadCount = async () => ({
391
+ count: mockAnnouncements.filter((a) => !a.viewed).length
392
+ });
393
+ apiClient.getActiveSurvey = async () => null;
394
+ apiClient.submitSurveyResponse = async () => ({
395
+ success: true,
396
+ responseId: Date.now()
397
+ });
398
+ return apiClient;
399
+ }, [config, mockUser, mockAnnouncements]);
400
+ const events = react.useMemo(() => new TraceyEventEmitter(), []);
401
+ const [announcements, setAnnouncements] = react.useState(mockAnnouncements);
402
+ const [unreadCount, setUnreadCount] = react.useState(
403
+ () => mockAnnouncements.filter((a) => !a.viewed).length
404
+ );
405
+ const refetchAnnouncements = react.useCallback(async () => {
406
+ setAnnouncements(mockAnnouncements);
407
+ }, [mockAnnouncements]);
408
+ const contextValue = react.useMemo(
409
+ () => ({
410
+ config,
411
+ client,
412
+ events,
413
+ user: mockUser,
414
+ isIdentified: true,
415
+ isLoading: false,
416
+ error: null,
417
+ announcements,
418
+ announcementsLoading: false,
419
+ refetchAnnouncements,
420
+ unreadCount,
421
+ setUnreadCount
422
+ }),
423
+ [
424
+ config,
425
+ client,
426
+ events,
427
+ mockUser,
428
+ announcements,
429
+ refetchAnnouncements,
430
+ unreadCount
431
+ ]
432
+ );
433
+ return /* @__PURE__ */ jsxRuntime.jsx(TraceyContext.Provider, { value: contextValue, children });
434
+ }
435
+ function useTracey() {
436
+ const context = react.useContext(TraceyContext);
437
+ if (!context) {
438
+ throw new Error("useTracey must be used within a TraceyProvider");
439
+ }
440
+ return context;
441
+ }
442
+ const MAX_SUBMISSIONS_PER_MINUTE = 5;
443
+ const RATE_LIMIT_WINDOW_MS = 6e4;
444
+ function useFeedback() {
445
+ const { client, events } = useTracey();
446
+ const [isSubmitting, setIsSubmitting] = react.useState(false);
447
+ const [error, setError] = react.useState(null);
448
+ const [lastSubmission, setLastSubmission] = react.useState(
449
+ null
450
+ );
451
+ const submissionTimestamps = react.useRef([]);
452
+ const submit = react.useCallback(
453
+ async (feedback) => {
454
+ const now = Date.now();
455
+ submissionTimestamps.current = submissionTimestamps.current.filter(
456
+ (ts) => now - ts < RATE_LIMIT_WINDOW_MS
457
+ );
458
+ if (submissionTimestamps.current.length >= MAX_SUBMISSIONS_PER_MINUTE) {
459
+ const oldestInWindow = submissionTimestamps.current[0];
460
+ const retryAfterMs = RATE_LIMIT_WINDOW_MS - (now - oldestInWindow);
461
+ const rateLimitError = new Error(
462
+ "Too many submissions. Please wait before submitting again."
463
+ );
464
+ setError(rateLimitError);
465
+ events.emit("feedback:rate-limited", { retryAfterMs });
466
+ return null;
467
+ }
468
+ setIsSubmitting(true);
469
+ setError(null);
470
+ try {
471
+ const response = await client.submitFeedback(feedback);
472
+ submissionTimestamps.current.push(Date.now());
473
+ setLastSubmission(response);
474
+ events.emit("feedback:submitted", { feedback: response });
475
+ return response;
476
+ } catch (err) {
477
+ const error2 = err instanceof Error ? err : new Error("Failed to submit feedback");
478
+ setError(error2);
479
+ events.emit("feedback:error", { error: error2 });
480
+ return null;
481
+ } finally {
482
+ setIsSubmitting(false);
483
+ }
484
+ },
485
+ [client, events]
486
+ );
487
+ const reset = react.useCallback(() => {
488
+ setError(null);
489
+ setLastSubmission(null);
490
+ }, []);
491
+ return {
492
+ submit,
493
+ isSubmitting,
494
+ error,
495
+ lastSubmission,
496
+ reset
497
+ };
498
+ }
499
+ function useAnnouncements() {
500
+ const {
501
+ client,
502
+ events,
503
+ announcements,
504
+ announcementsLoading,
505
+ refetchAnnouncements,
506
+ unreadCount,
507
+ setUnreadCount
508
+ } = useTracey();
509
+ const unread = react.useMemo(
510
+ () => announcements.filter((a) => !a.viewed),
511
+ [announcements]
512
+ );
513
+ const markAsViewed = react.useCallback(
514
+ async (announcementId) => {
515
+ try {
516
+ await client.trackAnnouncementView(announcementId);
517
+ const announcement = announcements.find((a) => a.id === announcementId);
518
+ if (announcement) {
519
+ events.emit("announcement:viewed", { announcement });
520
+ }
521
+ setUnreadCount(Math.max(0, unreadCount - 1));
522
+ await refetchAnnouncements();
523
+ } catch (err) {
524
+ const error = err instanceof Error ? err : new Error("Failed to mark announcement as viewed");
525
+ events.emit("error", { error, context: "announcement:view" });
526
+ }
527
+ },
528
+ [
529
+ client,
530
+ events,
531
+ announcements,
532
+ refetchAnnouncements,
533
+ unreadCount,
534
+ setUnreadCount
535
+ ]
536
+ );
537
+ const markAsRead = react.useCallback(
538
+ async (announcementId) => {
539
+ await markAsViewed(announcementId);
540
+ },
541
+ [markAsViewed]
542
+ );
543
+ const markAllAsRead = react.useCallback(async () => {
544
+ const unreadAnnouncements = announcements.filter((a) => !a.viewed);
545
+ if (unreadAnnouncements.length === 0) return;
546
+ setUnreadCount(0);
547
+ try {
548
+ await Promise.all(
549
+ unreadAnnouncements.map((a) => client.trackAnnouncementView(a.id))
550
+ );
551
+ await refetchAnnouncements();
552
+ } catch (err) {
553
+ const error = err instanceof Error ? err : new Error("Failed to mark all announcements as read");
554
+ events.emit("error", { error, context: "announcement:mark-all-read" });
555
+ setUnreadCount(unreadAnnouncements.length);
556
+ }
557
+ }, [announcements, client, events, refetchAnnouncements, setUnreadCount]);
558
+ const markCtaClicked = react.useCallback(
559
+ async (announcementId, slideIndex) => {
560
+ try {
561
+ await client.trackAnnouncementCta(announcementId);
562
+ const announcement = announcements.find((a) => a.id === announcementId);
563
+ if (announcement) {
564
+ events.emit("announcement:cta-clicked", {
565
+ announcement,
566
+ slideIndex
567
+ });
568
+ }
569
+ } catch (err) {
570
+ const error = err instanceof Error ? err : new Error("Failed to track CTA click");
571
+ events.emit("error", { error, context: "announcement:cta" });
572
+ }
573
+ },
574
+ [client, events, announcements]
575
+ );
576
+ return {
577
+ announcements,
578
+ unread,
579
+ unreadCount,
580
+ isLoading: announcementsLoading,
581
+ markAsViewed,
582
+ markAsRead,
583
+ markAllAsRead,
584
+ markCtaClicked,
585
+ refetch: refetchAnnouncements
586
+ };
587
+ }
588
+ function useTraceyEvents() {
589
+ const { events } = useTracey();
590
+ const subscribe = react.useCallback(
591
+ (event, callback) => {
592
+ return events.subscribe(event, callback);
593
+ },
594
+ [events]
595
+ );
596
+ const emit = react.useCallback(
597
+ (event, data) => {
598
+ events.emit(event, data);
599
+ },
600
+ [events]
601
+ );
602
+ return { subscribe, emit };
603
+ }
604
+ const FeedbackContext = react.createContext(null);
605
+ function useFeedbackContext() {
606
+ const context = react.useContext(FeedbackContext);
607
+ if (!context) {
608
+ throw new Error(
609
+ "Feedback compound components must be used within FeedbackRoot"
610
+ );
611
+ }
612
+ return context;
613
+ }
614
+ function FeedbackRoot({
615
+ children,
616
+ defaultOpen = false,
617
+ open,
618
+ onOpenChange
619
+ }) {
620
+ const [internalOpen, setInternalOpen] = react.useState(defaultOpen);
621
+ const isOpen = open ?? internalOpen;
622
+ const setIsOpen = react.useCallback(
623
+ (newOpen) => {
624
+ if (open === void 0) {
625
+ setInternalOpen(newOpen);
626
+ }
627
+ onOpenChange == null ? void 0 : onOpenChange(newOpen);
628
+ },
629
+ [open, onOpenChange]
630
+ );
631
+ const toggle = react.useCallback(() => {
632
+ setIsOpen(!isOpen);
633
+ }, [isOpen, setIsOpen]);
634
+ return /* @__PURE__ */ jsxRuntime.jsx(FeedbackContext.Provider, { value: { isOpen, setIsOpen, toggle }, children });
635
+ }
636
+ function FeedbackClose({
637
+ children,
638
+ asChild = true
639
+ }) {
640
+ const { setIsOpen } = useFeedbackContext();
641
+ const handleClose = (e) => {
642
+ var _a, _b;
643
+ (_b = (_a = children.props).onClick) == null ? void 0 : _b.call(_a, e);
644
+ setIsOpen(false);
645
+ };
646
+ if (asChild) {
647
+ return react.cloneElement(children, { onClick: handleClose });
648
+ }
649
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: handleClose, children });
650
+ }
651
+ function FeedbackFormPrimitive({
652
+ children,
653
+ onSuccess,
654
+ closeOnSuccess = true
655
+ }) {
656
+ const { setIsOpen } = useFeedbackContext();
657
+ const { submit, isSubmitting, error } = useFeedback();
658
+ const [title, setTitle] = react.useState("");
659
+ const [description, setDescription] = react.useState("");
660
+ const [type, setType] = react.useState("general");
661
+ const [screenshot, setScreenshot] = react.useState(null);
662
+ const handleSubmit = react.useCallback(
663
+ async (e) => {
664
+ e.preventDefault();
665
+ const result = await submit({
666
+ title,
667
+ description: description || void 0,
668
+ type,
669
+ screenshot: screenshot ?? void 0
670
+ });
671
+ if (result) {
672
+ setTitle("");
673
+ setDescription("");
674
+ setType("general");
675
+ setScreenshot(null);
676
+ onSuccess == null ? void 0 : onSuccess();
677
+ if (closeOnSuccess) {
678
+ setIsOpen(false);
679
+ }
680
+ }
681
+ },
682
+ [
683
+ submit,
684
+ title,
685
+ description,
686
+ type,
687
+ screenshot,
688
+ onSuccess,
689
+ closeOnSuccess,
690
+ setIsOpen
691
+ ]
692
+ );
693
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({
694
+ title,
695
+ setTitle,
696
+ description,
697
+ setDescription,
698
+ type,
699
+ setType,
700
+ screenshot,
701
+ setScreenshot,
702
+ isSubmitting,
703
+ error,
704
+ handleSubmit
705
+ }) });
706
+ }
707
+ function FeedbackContent({ children, ...props }) {
708
+ const { isOpen } = useFeedbackContext();
709
+ if (!isOpen) {
710
+ return null;
711
+ }
712
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "dialog", "aria-modal": "true", ...props, children });
713
+ }
714
+ function FeedbackPortal({ children, container }) {
715
+ const [mounted, setMounted] = react.useState(false);
716
+ react.useEffect(() => {
717
+ setMounted(true);
718
+ }, []);
719
+ if (!mounted) {
720
+ return null;
721
+ }
722
+ const target = container ?? document.body;
723
+ return reactDom.createPortal(children, target);
724
+ }
725
+ function FeedbackTrigger({
726
+ children,
727
+ asChild = true
728
+ }) {
729
+ const { toggle } = useFeedbackContext();
730
+ if (asChild) {
731
+ return react.cloneElement(children, {
732
+ onClick: (e) => {
733
+ var _a, _b;
734
+ (_b = (_a = children.props).onClick) == null ? void 0 : _b.call(_a, e);
735
+ toggle();
736
+ }
737
+ });
738
+ }
739
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: toggle, children });
740
+ }
741
+ const AnnouncementContext = react.createContext(
742
+ null
743
+ );
744
+ function useAnnouncementContext() {
745
+ const context = react.useContext(AnnouncementContext);
746
+ if (!context) {
747
+ throw new Error(
748
+ "Announcement compound components must be used within AnnouncementRoot"
749
+ );
750
+ }
751
+ return context;
752
+ }
753
+ function AnnouncementRoot({
754
+ children,
755
+ announcement = null,
756
+ defaultOpen = false,
757
+ open,
758
+ onOpenChange
759
+ }) {
760
+ const [internalOpen, setInternalOpen] = react.useState(defaultOpen);
761
+ const [currentAnnouncement, setCurrentAnnouncement] = react.useState(announcement);
762
+ const [currentSlideIndex, setCurrentSlideIndex] = react.useState(0);
763
+ react.useEffect(() => {
764
+ setCurrentAnnouncement(announcement);
765
+ setCurrentSlideIndex(0);
766
+ }, [announcement]);
767
+ const isOpen = open ?? internalOpen;
768
+ const totalSlides = (currentAnnouncement == null ? void 0 : currentAnnouncement.slides.length) ?? 0;
769
+ const setIsOpen = react.useCallback(
770
+ (newOpen) => {
771
+ if (open === void 0) {
772
+ setInternalOpen(newOpen);
773
+ }
774
+ onOpenChange == null ? void 0 : onOpenChange(newOpen);
775
+ },
776
+ [open, onOpenChange]
777
+ );
778
+ const nextSlide = react.useCallback(() => {
779
+ if (currentSlideIndex < totalSlides - 1) {
780
+ setCurrentSlideIndex((prev) => prev + 1);
781
+ }
782
+ }, [currentSlideIndex, totalSlides]);
783
+ const prevSlide = react.useCallback(() => {
784
+ if (currentSlideIndex > 0) {
785
+ setCurrentSlideIndex((prev) => prev - 1);
786
+ }
787
+ }, [currentSlideIndex]);
788
+ return /* @__PURE__ */ jsxRuntime.jsx(
789
+ AnnouncementContext.Provider,
790
+ {
791
+ value: {
792
+ isOpen,
793
+ setIsOpen,
794
+ currentAnnouncement,
795
+ setCurrentAnnouncement,
796
+ currentSlideIndex,
797
+ setCurrentSlideIndex,
798
+ nextSlide,
799
+ prevSlide,
800
+ totalSlides
801
+ },
802
+ children
803
+ }
804
+ );
805
+ }
806
+ function AnnouncementClose({
807
+ children,
808
+ asChild = true
809
+ }) {
810
+ const { setIsOpen } = useAnnouncementContext();
811
+ const handleClose = (e) => {
812
+ var _a, _b;
813
+ (_b = (_a = children.props).onClick) == null ? void 0 : _b.call(_a, e);
814
+ setIsOpen(false);
815
+ };
816
+ if (asChild) {
817
+ return react.cloneElement(children, { onClick: handleClose });
818
+ }
819
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: handleClose, children });
820
+ }
821
+ function AnnouncementContent({
822
+ children,
823
+ trackView = true,
824
+ ...props
825
+ }) {
826
+ const { isOpen, currentAnnouncement } = useAnnouncementContext();
827
+ const { markAsViewed } = useAnnouncements();
828
+ const viewedRef = react.useRef(/* @__PURE__ */ new Set());
829
+ react.useEffect(() => {
830
+ if (isOpen && trackView && currentAnnouncement && !currentAnnouncement.viewed && !viewedRef.current.has(currentAnnouncement.id)) {
831
+ viewedRef.current.add(currentAnnouncement.id);
832
+ markAsViewed(currentAnnouncement.id);
833
+ }
834
+ }, [isOpen, trackView, currentAnnouncement, markAsViewed]);
835
+ if (!isOpen) {
836
+ return null;
837
+ }
838
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "dialog", "aria-modal": "true", ...props, children });
839
+ }
840
+ function AnnouncementNavigation({
841
+ children
842
+ }) {
843
+ const {
844
+ currentSlideIndex,
845
+ totalSlides,
846
+ nextSlide,
847
+ prevSlide,
848
+ setCurrentSlideIndex
849
+ } = useAnnouncementContext();
850
+ const canGoNext = currentSlideIndex < totalSlides - 1;
851
+ const canGoPrev = currentSlideIndex > 0;
852
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({
853
+ currentSlide: currentSlideIndex,
854
+ totalSlides,
855
+ canGoNext,
856
+ canGoPrev,
857
+ nextSlide,
858
+ prevSlide,
859
+ goToSlide: setCurrentSlideIndex
860
+ }) });
861
+ }
862
+ function AnnouncementPortal({
863
+ children,
864
+ container
865
+ }) {
866
+ const [mounted, setMounted] = react.useState(false);
867
+ react.useEffect(() => {
868
+ setMounted(true);
869
+ }, []);
870
+ if (!mounted) {
871
+ return null;
872
+ }
873
+ const target = container ?? document.body;
874
+ return reactDom.createPortal(children, target);
875
+ }
876
+ function LauncherBadge({
877
+ count,
878
+ children,
879
+ max = 99
880
+ }) {
881
+ if (count <= 0) {
882
+ return null;
883
+ }
884
+ if (children) {
885
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children(count) });
886
+ }
887
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: count > max ? `${max}+` : count });
888
+ }
889
+ const LauncherContext = react.createContext(null);
890
+ function useLauncherContext() {
891
+ const context = react.useContext(LauncherContext);
892
+ if (!context) {
893
+ throw new Error(
894
+ "Launcher compound components must be used within LauncherRoot"
895
+ );
896
+ }
897
+ return context;
898
+ }
899
+ function LauncherRoot({
900
+ children,
901
+ defaultOpen = false,
902
+ open,
903
+ onOpenChange,
904
+ defaultActiveItem = null
905
+ }) {
906
+ const [internalOpen, setInternalOpen] = react.useState(defaultOpen);
907
+ const [activeItem, setActiveItem] = react.useState(defaultActiveItem);
908
+ const triggerRef = react.useRef(null);
909
+ const isOpen = open ?? internalOpen;
910
+ const setIsOpen = react.useCallback(
911
+ (newOpen) => {
912
+ if (open === void 0) {
913
+ setInternalOpen(newOpen);
914
+ }
915
+ if (!newOpen) {
916
+ setActiveItem(defaultActiveItem);
917
+ }
918
+ onOpenChange == null ? void 0 : onOpenChange(newOpen);
919
+ },
920
+ [open, onOpenChange, defaultActiveItem]
921
+ );
922
+ const toggle = react.useCallback(() => {
923
+ setIsOpen(!isOpen);
924
+ }, [isOpen, setIsOpen]);
925
+ return /* @__PURE__ */ jsxRuntime.jsx(
926
+ LauncherContext.Provider,
927
+ {
928
+ value: {
929
+ isOpen,
930
+ setIsOpen,
931
+ toggle,
932
+ activeItem,
933
+ setActiveItem,
934
+ triggerRef
935
+ },
936
+ children
937
+ }
938
+ );
939
+ }
940
+ function LauncherPanel({ children, ...props }) {
941
+ const { isOpen, setIsOpen, triggerRef } = useLauncherContext();
942
+ const panelRef = react.useRef(null);
943
+ react.useEffect(() => {
944
+ if (!isOpen) return;
945
+ const handleClickOutside = (e) => {
946
+ const target = e.target;
947
+ if (panelRef.current && !panelRef.current.contains(target) && triggerRef.current && !triggerRef.current.contains(target)) {
948
+ setIsOpen(false);
949
+ }
950
+ };
951
+ const handleEscape = (e) => {
952
+ if (e.key === "Escape") {
953
+ setIsOpen(false);
954
+ }
955
+ };
956
+ document.addEventListener("mousedown", handleClickOutside);
957
+ document.addEventListener("keydown", handleEscape);
958
+ return () => {
959
+ document.removeEventListener("mousedown", handleClickOutside);
960
+ document.removeEventListener("keydown", handleEscape);
961
+ };
962
+ }, [isOpen, setIsOpen, triggerRef]);
963
+ if (!isOpen) {
964
+ return null;
965
+ }
966
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: panelRef, role: "dialog", "aria-label": "Tracey widget", ...props, children });
967
+ }
968
+ function LauncherPortal({ children, container }) {
969
+ const [mounted, setMounted] = react.useState(false);
970
+ react.useEffect(() => {
971
+ setMounted(true);
972
+ }, []);
973
+ if (!mounted) {
974
+ return null;
975
+ }
976
+ const target = container ?? document.body;
977
+ return reactDom.createPortal(children, target);
978
+ }
979
+ function LauncherTab({ value, children, ...props }) {
980
+ const { activeItem, setActiveItem } = useLauncherContext();
981
+ const isActive = activeItem === value;
982
+ return /* @__PURE__ */ jsxRuntime.jsx(
983
+ "button",
984
+ {
985
+ type: "button",
986
+ role: "tab",
987
+ "aria-selected": isActive,
988
+ "data-state": isActive ? "active" : "inactive",
989
+ onClick: () => setActiveItem(value),
990
+ ...props,
991
+ children
992
+ }
993
+ );
994
+ }
995
+ function LauncherTabContent({
996
+ value,
997
+ children,
998
+ ...props
999
+ }) {
1000
+ const { activeItem } = useLauncherContext();
1001
+ if (activeItem !== value) {
1002
+ return null;
1003
+ }
1004
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tabpanel", ...props, children });
1005
+ }
1006
+ function LauncherTrigger({
1007
+ children,
1008
+ asChild = true
1009
+ }) {
1010
+ const { toggle, triggerRef } = useLauncherContext();
1011
+ const refCallback = react.useCallback(
1012
+ (node) => {
1013
+ triggerRef.current = node;
1014
+ },
1015
+ [triggerRef]
1016
+ );
1017
+ if (asChild) {
1018
+ return react.cloneElement(children, {
1019
+ ref: refCallback,
1020
+ onClick: (e) => {
1021
+ var _a, _b;
1022
+ (_b = (_a = children.props).onClick) == null ? void 0 : _b.call(_a, e);
1023
+ toggle();
1024
+ }
1025
+ });
1026
+ }
1027
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", ref: refCallback, onClick: toggle, children });
1028
+ }
1029
+ exports.AnnouncementClose = AnnouncementClose;
1030
+ exports.AnnouncementContent = AnnouncementContent;
1031
+ exports.AnnouncementNavigation = AnnouncementNavigation;
1032
+ exports.AnnouncementPortal = AnnouncementPortal;
1033
+ exports.AnnouncementRoot = AnnouncementRoot;
1034
+ exports.FeedbackClose = FeedbackClose;
1035
+ exports.FeedbackContent = FeedbackContent;
1036
+ exports.FeedbackFormPrimitive = FeedbackFormPrimitive;
1037
+ exports.FeedbackPortal = FeedbackPortal;
1038
+ exports.FeedbackRoot = FeedbackRoot;
1039
+ exports.FeedbackTrigger = FeedbackTrigger;
1040
+ exports.LauncherBadge = LauncherBadge;
1041
+ exports.LauncherPanel = LauncherPanel;
1042
+ exports.LauncherPortal = LauncherPortal;
1043
+ exports.LauncherRoot = LauncherRoot;
1044
+ exports.LauncherTab = LauncherTab;
1045
+ exports.LauncherTabContent = LauncherTabContent;
1046
+ exports.LauncherTrigger = LauncherTrigger;
1047
+ exports.MockTraceyProvider = MockTraceyProvider;
1048
+ exports.TraceyProvider = TraceyProvider;
1049
+ exports.useAnnouncementContext = useAnnouncementContext;
1050
+ exports.useAnnouncements = useAnnouncements;
1051
+ exports.useFeedback = useFeedback;
1052
+ exports.useLauncherContext = useLauncherContext;
1053
+ exports.useTracey = useTracey;
1054
+ exports.useTraceyEvents = useTraceyEvents;
1055
+ //# sourceMappingURL=LauncherTrigger-DjXDXHTm.cjs.map