@wireai/activation 0.1.0

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 (142) hide show
  1. package/AGENTS.md +73 -0
  2. package/CHANGELOG.md +572 -0
  3. package/INTEGRATION_PROMPT.md +55 -0
  4. package/LICENSE +21 -0
  5. package/README.md +923 -0
  6. package/dist/CenteredModal-C3qQBHsA.d.mts +38 -0
  7. package/dist/CenteredModal-Cdgns6--.d.ts +38 -0
  8. package/dist/coachmarks/index.d.mts +352 -0
  9. package/dist/coachmarks/index.d.ts +352 -0
  10. package/dist/coachmarks/index.js +944 -0
  11. package/dist/coachmarks/index.js.map +1 -0
  12. package/dist/coachmarks/index.mjs +918 -0
  13. package/dist/coachmarks/index.mjs.map +1 -0
  14. package/dist/decision-CFvGY6nP.d.ts +228 -0
  15. package/dist/decision-Cl8OFYzu.d.mts +228 -0
  16. package/dist/index.d.mts +1390 -0
  17. package/dist/index.d.ts +1390 -0
  18. package/dist/index.js +3260 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/index.mjs +3186 -0
  21. package/dist/index.mjs.map +1 -0
  22. package/dist/questionnaire/index.d.mts +249 -0
  23. package/dist/questionnaire/index.d.ts +249 -0
  24. package/dist/questionnaire/index.js +922 -0
  25. package/dist/questionnaire/index.js.map +1 -0
  26. package/dist/questionnaire/index.mjs +906 -0
  27. package/dist/questionnaire/index.mjs.map +1 -0
  28. package/dist/reviews/index.d.mts +213 -0
  29. package/dist/reviews/index.d.ts +213 -0
  30. package/dist/reviews/index.js +1001 -0
  31. package/dist/reviews/index.js.map +1 -0
  32. package/dist/reviews/index.mjs +971 -0
  33. package/dist/reviews/index.mjs.map +1 -0
  34. package/dist/showcase/index.d.mts +119 -0
  35. package/dist/showcase/index.d.ts +119 -0
  36. package/dist/showcase/index.js +660 -0
  37. package/dist/showcase/index.js.map +1 -0
  38. package/dist/showcase/index.mjs +651 -0
  39. package/dist/showcase/index.mjs.map +1 -0
  40. package/dist/types-BKfpdZzX.d.mts +84 -0
  41. package/dist/types-BKfpdZzX.d.ts +84 -0
  42. package/dist/types-CMuOexw0.d.mts +116 -0
  43. package/dist/types-CMuOexw0.d.ts +116 -0
  44. package/dist/types-GL_hQ0TN.d.mts +46 -0
  45. package/dist/types-GL_hQ0TN.d.ts +46 -0
  46. package/llms.txt +36 -0
  47. package/metro/index.d.ts +32 -0
  48. package/metro/index.js +83 -0
  49. package/package.json +171 -0
  50. package/src/DemoOnboarding.tsx +133 -0
  51. package/src/OnboardingFlow.tsx +504 -0
  52. package/src/WireOnboarding.tsx +248 -0
  53. package/src/analytics/analyticsEvent.ts +69 -0
  54. package/src/analytics/reportClientEvent.ts +119 -0
  55. package/src/analytics/sendPreview.ts +73 -0
  56. package/src/attribution/attribution.ts +46 -0
  57. package/src/cards/ChipSelectCard.tsx +265 -0
  58. package/src/cards/InterstitialCard.tsx +299 -0
  59. package/src/cards/NumberStepperCard.tsx +121 -0
  60. package/src/cards/SelectionCard.tsx +270 -0
  61. package/src/cards/StatusCard.tsx +170 -0
  62. package/src/cards/TextInputCard.tsx +147 -0
  63. package/src/cards/index.ts +23 -0
  64. package/src/coachmarks/CoachmarkOverlayHost.tsx +44 -0
  65. package/src/coachmarks/CoachmarkProvider.tsx +108 -0
  66. package/src/coachmarks/GestureHint.tsx +331 -0
  67. package/src/coachmarks/SpotlightOverlay.tsx +254 -0
  68. package/src/coachmarks/coachmarkAnchorRegistry.ts +70 -0
  69. package/src/coachmarks/coachmarkOverlayStore.ts +63 -0
  70. package/src/coachmarks/index.ts +62 -0
  71. package/src/coachmarks/runtime.ts +103 -0
  72. package/src/coachmarks/selectTourSteps.ts +45 -0
  73. package/src/coachmarks/types.ts +58 -0
  74. package/src/coachmarks/useCoachmarkAnchor.ts +49 -0
  75. package/src/coachmarks/useCoachmarkTour.ts +200 -0
  76. package/src/components/AnimatedSparkle.tsx +101 -0
  77. package/src/components/Button.tsx +129 -0
  78. package/src/components/CardHandoff.tsx +212 -0
  79. package/src/components/CardLayout.tsx +103 -0
  80. package/src/components/CenteredModal.tsx +184 -0
  81. package/src/components/CompletionView.tsx +186 -0
  82. package/src/components/DoneBlock.tsx +37 -0
  83. package/src/components/ErrorBlock.tsx +42 -0
  84. package/src/components/Illustration.tsx +36 -0
  85. package/src/components/LoadingBlock.tsx +182 -0
  86. package/src/components/LoadingScreen.tsx +35 -0
  87. package/src/components/OnboardingScaffold.tsx +105 -0
  88. package/src/components/StepProgress.tsx +85 -0
  89. package/src/components/loaderChrome.ts +28 -0
  90. package/src/config/onboardingFlag.ts +39 -0
  91. package/src/config/wireConfigFromEnv.ts +52 -0
  92. package/src/device/deviceContext.ts +158 -0
  93. package/src/features/WireFeaturesProvider.tsx +81 -0
  94. package/src/features/cache.ts +92 -0
  95. package/src/features/defaults.ts +67 -0
  96. package/src/features/fetchWireFeatures.ts +86 -0
  97. package/src/features/index.ts +39 -0
  98. package/src/features/types.ts +61 -0
  99. package/src/features/useWireFeatures.ts +57 -0
  100. package/src/identity/userIdentity.ts +100 -0
  101. package/src/illustrations/defaultIllustrations.tsx +99 -0
  102. package/src/index.ts +159 -0
  103. package/src/motion/centeredModalMotion.ts +45 -0
  104. package/src/motion/motionSpec.ts +133 -0
  105. package/src/motion/useReducedMotion.ts +43 -0
  106. package/src/questionnaire/QuestionnaireGate.tsx +235 -0
  107. package/src/questionnaire/decision.ts +63 -0
  108. package/src/questionnaire/index.ts +54 -0
  109. package/src/questionnaire/runtime.ts +20 -0
  110. package/src/questionnaire/transport.ts +83 -0
  111. package/src/questionnaire/types.ts +182 -0
  112. package/src/questionnaire/useQuestionnaireGate.ts +159 -0
  113. package/src/reviews/ReviewGate.tsx +316 -0
  114. package/src/reviews/ReviewModal.tsx +13 -0
  115. package/src/reviews/decision.ts +120 -0
  116. package/src/reviews/equality.ts +54 -0
  117. package/src/reviews/expo-store-review.d.ts +16 -0
  118. package/src/reviews/feedbackForm.ts +41 -0
  119. package/src/reviews/index.ts +78 -0
  120. package/src/reviews/presentation.ts +29 -0
  121. package/src/reviews/runtime.ts +45 -0
  122. package/src/reviews/storeReview.ts +62 -0
  123. package/src/reviews/transport.ts +89 -0
  124. package/src/reviews/types.ts +172 -0
  125. package/src/reviews/useReviewGate.ts +137 -0
  126. package/src/session/persistedSession.ts +143 -0
  127. package/src/session-analytics/index.ts +18 -0
  128. package/src/session-analytics/reportSessionStart.ts +144 -0
  129. package/src/session-analytics/useSessionStart.ts +114 -0
  130. package/src/showcase/FeatureShowcase.tsx +233 -0
  131. package/src/showcase/index.ts +19 -0
  132. package/src/showcase/selectShowcaseSlides.ts +45 -0
  133. package/src/showcase/showcaseColors.ts +91 -0
  134. package/src/showcase/types.ts +74 -0
  135. package/src/theme/ThemeContext.tsx +38 -0
  136. package/src/theme/defaultTheme.ts +70 -0
  137. package/src/theme/themeFromBrand.ts +93 -0
  138. package/src/theme/types.ts +88 -0
  139. package/src/theme/typography.ts +46 -0
  140. package/src/types.ts +215 -0
  141. package/src/utils/deriveAnswers.ts +43 -0
  142. package/src/utils/readProgress.ts +33 -0
@@ -0,0 +1,944 @@
1
+ 'use strict';
2
+
3
+ var React3 = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var expoBlur = require('expo-blur');
6
+ var reactNative = require('react-native');
7
+ var Animated = require('react-native-reanimated');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var React3__default = /*#__PURE__*/_interopDefault(React3);
12
+ var Animated__default = /*#__PURE__*/_interopDefault(Animated);
13
+
14
+ // src/coachmarks/CoachmarkProvider.tsx
15
+
16
+ // src/features/defaults.ts
17
+ var defaultWireFeatures = Object.freeze({
18
+ coachmarks: Object.freeze({ enabled: true }),
19
+ showcase: Object.freeze({ enabled: true }),
20
+ onboarding: Object.freeze({ mode: "ai" }),
21
+ review: Object.freeze({ enabled: true }),
22
+ questionnaire: Object.freeze({ enabled: true }),
23
+ announcements: Object.freeze({ enabled: true })
24
+ });
25
+ var VALID_MODES = ["ai", "static", "off"];
26
+ var readEnabled = (raw) => {
27
+ if (raw && typeof raw === "object" && typeof raw.enabled === "boolean") {
28
+ return { enabled: raw.enabled };
29
+ }
30
+ return { enabled: true };
31
+ };
32
+ var parseWireFeatures = (raw) => {
33
+ var _a;
34
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return defaultWireFeatures;
35
+ const src = raw;
36
+ const modeRaw = (_a = src.onboarding) == null ? void 0 : _a.mode;
37
+ const mode = typeof modeRaw === "string" && VALID_MODES.includes(modeRaw) ? modeRaw : "ai";
38
+ return {
39
+ coachmarks: readEnabled(src.coachmarks),
40
+ showcase: readEnabled(src.showcase),
41
+ onboarding: { mode },
42
+ review: readEnabled(src.review),
43
+ questionnaire: readEnabled(src.questionnaire),
44
+ announcements: readEnabled(src.announcements)
45
+ };
46
+ };
47
+ var featuresEqual = (a, b) => a === b || a.coachmarks.enabled === b.coachmarks.enabled && a.showcase.enabled === b.showcase.enabled && a.onboarding.mode === b.onboarding.mode && a.review.enabled === b.review.enabled && a.questionnaire.enabled === b.questionnaire.enabled && a.announcements.enabled === b.announcements.enabled;
48
+
49
+ // src/features/cache.ts
50
+ var READ_TIMEOUT_MS = 1500;
51
+ var featuresCacheKey = (appId) => `wireai:features:${appId && appId.length > 0 ? appId : "default"}`;
52
+ var withTimeout = (p, ms) => {
53
+ let timer;
54
+ const timeout = new Promise((resolve) => {
55
+ timer = setTimeout(() => resolve(void 0), ms);
56
+ });
57
+ return Promise.race([p, timeout]).finally(() => clearTimeout(timer));
58
+ };
59
+ var readCachedFeatures = async (storage, key) => {
60
+ let raw;
61
+ try {
62
+ raw = await withTimeout(storage.getItem(key), READ_TIMEOUT_MS);
63
+ } catch {
64
+ return void 0;
65
+ }
66
+ if (!raw) return void 0;
67
+ try {
68
+ const parsed = JSON.parse(raw);
69
+ if (parsed && typeof parsed === "object" && typeof parsed.ts === "number") {
70
+ const ts = parsed.ts;
71
+ return {
72
+ features: parseWireFeatures(parsed.features),
73
+ ageMs: Date.now() - ts
74
+ };
75
+ }
76
+ } catch {
77
+ }
78
+ return void 0;
79
+ };
80
+ var writeCachedFeatures = (storage, key, features) => {
81
+ try {
82
+ void storage.setItem(key, JSON.stringify({ features, ts: Date.now() })).catch(() => {
83
+ });
84
+ } catch {
85
+ }
86
+ };
87
+
88
+ // src/features/fetchWireFeatures.ts
89
+ var DEFAULT_TIMEOUT_MS = 4e3;
90
+ var failOpen = async (storage, key) => {
91
+ var _a;
92
+ if (!storage) return defaultWireFeatures;
93
+ const cached = await readCachedFeatures(storage, key);
94
+ return (_a = cached == null ? void 0 : cached.features) != null ? _a : defaultWireFeatures;
95
+ };
96
+ var fetchWithTimeout = async (url, apiKey, timeoutMs) => {
97
+ const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
98
+ const timer = setTimeout(() => controller == null ? void 0 : controller.abort(), timeoutMs);
99
+ try {
100
+ return await fetch(url, {
101
+ method: "GET",
102
+ headers: { Accept: "application/json", Authorization: `Bearer ${apiKey}` },
103
+ signal: controller == null ? void 0 : controller.signal
104
+ });
105
+ } finally {
106
+ clearTimeout(timer);
107
+ }
108
+ };
109
+ var fetchWireFeatures = async (config) => {
110
+ const key = featuresCacheKey(config == null ? void 0 : config.appId);
111
+ const storage = config == null ? void 0 : config.storage;
112
+ if (!(config == null ? void 0 : config.serverUrl) || !(config == null ? void 0 : config.apiKey)) return failOpen(storage, key);
113
+ const url = `${config.serverUrl.replace(/\/$/, "")}/v1/features`;
114
+ const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;
115
+ try {
116
+ const res = await fetchWithTimeout(url, config.apiKey, timeoutMs);
117
+ if (!res || !res.ok) return failOpen(storage, key);
118
+ const json = await res.json();
119
+ const features = parseWireFeatures(json);
120
+ if (storage) writeCachedFeatures(storage, key, features);
121
+ return features;
122
+ } catch {
123
+ return failOpen(storage, key);
124
+ }
125
+ };
126
+
127
+ // src/features/useWireFeatures.ts
128
+ var useStableValue = (value, isEqual) => {
129
+ const ref = React3.useRef(value);
130
+ if (!isEqual(ref.current, value)) ref.current = value;
131
+ return ref.current;
132
+ };
133
+ var sameFetchKey = (a, b) => (a == null ? void 0 : a.serverUrl) === (b == null ? void 0 : b.serverUrl) && (a == null ? void 0 : a.apiKey) === (b == null ? void 0 : b.apiKey) && (a == null ? void 0 : a.appId) === (b == null ? void 0 : b.appId);
134
+ var useWireFeatures = (config) => {
135
+ const stableConfig = useStableValue(config, sameFetchKey);
136
+ const [flags, setFlags] = React3.useState(defaultWireFeatures);
137
+ const canFetch = !!(stableConfig == null ? void 0 : stableConfig.serverUrl) && !!(stableConfig == null ? void 0 : stableConfig.apiKey);
138
+ React3.useEffect(() => {
139
+ if (!canFetch) {
140
+ setFlags((prev) => featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures);
141
+ return;
142
+ }
143
+ let alive = true;
144
+ void fetchWireFeatures(stableConfig).then((next) => {
145
+ if (!alive) return;
146
+ setFlags((prev) => featuresEqual(prev, next) ? prev : next);
147
+ });
148
+ return () => {
149
+ alive = false;
150
+ };
151
+ }, [canFetch, stableConfig]);
152
+ return flags;
153
+ };
154
+ var WireFeaturesContext = React3.createContext(null);
155
+ var useWireFeaturesContext = () => React3.useContext(WireFeaturesContext);
156
+ var useResolvedFeatures = (options) => {
157
+ var _a, _b, _c;
158
+ const ctx = useWireFeaturesContext();
159
+ const shouldFetch = !(options == null ? void 0 : options.flags) && ctx == null;
160
+ const fetched = useWireFeatures(shouldFetch ? options == null ? void 0 : options.config : void 0);
161
+ return (_c = (_b = (_a = options == null ? void 0 : options.flags) != null ? _a : ctx) != null ? _b : fetched) != null ? _c : defaultWireFeatures;
162
+ };
163
+
164
+ // src/coachmarks/runtime.ts
165
+ var storageSingleton = null;
166
+ var testing = false;
167
+ var coachmarksEnabled = true;
168
+ var setCoachmarksEnabled = (value) => {
169
+ coachmarksEnabled = value;
170
+ };
171
+ var areCoachmarksEnabled = () => coachmarksEnabled;
172
+ var setCoachmarkStorage = (storage) => {
173
+ storageSingleton = storage;
174
+ };
175
+ var getCoachmarkStorage = () => storageSingleton;
176
+ var setCoachmarkTesting = (value) => {
177
+ testing = value;
178
+ };
179
+ var isCoachmarkTesting = () => testing;
180
+ var coachmarkGateKey = (tourId) => `wire_coachmark_${tourId}_seen`;
181
+ var showcaseGateKey = (showcaseId) => `wire_showcase_${showcaseId}_seen`;
182
+ var SEEN_VALUE = "1";
183
+ var hasSeenGate = (key, storageOverride, testingOverride) => {
184
+ if (testingOverride != null ? testingOverride : testing) return false;
185
+ const storage = storageOverride != null ? storageOverride : storageSingleton;
186
+ if (!storage) return false;
187
+ try {
188
+ return storage.getItem(key) === SEEN_VALUE;
189
+ } catch {
190
+ return false;
191
+ }
192
+ };
193
+ var markSeenGate = (key, storageOverride, testingOverride) => {
194
+ if (testingOverride != null ? testingOverride : testing) return;
195
+ const storage = storageOverride != null ? storageOverride : storageSingleton;
196
+ if (!storage) return;
197
+ try {
198
+ storage.setItem(key, SEEN_VALUE);
199
+ } catch {
200
+ }
201
+ };
202
+
203
+ // src/coachmarks/coachmarkOverlayStore.ts
204
+ var current = null;
205
+ var listeners = /* @__PURE__ */ new Set();
206
+ var emit = () => {
207
+ for (const listener of listeners) listener();
208
+ };
209
+ var coachmarkOverlay = {
210
+ show(state) {
211
+ if (!areCoachmarksEnabled()) return;
212
+ current = state;
213
+ emit();
214
+ },
215
+ hide() {
216
+ if (current === null) return;
217
+ current = null;
218
+ emit();
219
+ },
220
+ subscribe(listener) {
221
+ listeners.add(listener);
222
+ return () => {
223
+ listeners.delete(listener);
224
+ };
225
+ },
226
+ getSnapshot() {
227
+ return current;
228
+ }
229
+ };
230
+ var useCoachmarkOverlay = () => React3.useSyncExternalStore(
231
+ coachmarkOverlay.subscribe,
232
+ coachmarkOverlay.getSnapshot,
233
+ coachmarkOverlay.getSnapshot
234
+ );
235
+
236
+ // src/theme/defaultTheme.ts
237
+ var defaultOnboardingTheme = {
238
+ colors: {
239
+ background: "#FFFFFF",
240
+ surface: "#F7F7F8",
241
+ text: "#101114",
242
+ textMuted: "#6B7280",
243
+ primary: "#111111",
244
+ onPrimary: "#FFFFFF",
245
+ primarySoft: "rgba(17,17,17,0.06)",
246
+ border: "#E4E4E7",
247
+ borderStrong: "#C7C7CC",
248
+ disabled: "#EBEBEB",
249
+ success: "#16A34A",
250
+ warning: "#D97706",
251
+ error: "#DC2626",
252
+ info: "#2563EB"
253
+ },
254
+ fonts: {
255
+ regular: void 0,
256
+ medium: void 0,
257
+ bold: void 0,
258
+ baseSize: 16,
259
+ scale: 1
260
+ },
261
+ radius: {
262
+ sm: 8,
263
+ md: 12,
264
+ lg: 16,
265
+ full: 9999
266
+ },
267
+ spacing: {
268
+ xs: 4,
269
+ sm: 8,
270
+ md: 16,
271
+ lg: 24,
272
+ xl: 32
273
+ },
274
+ // Circled (pill) CTA by default; an app can pass `button: { radius: 12 }` for
275
+ // a rounded rectangle, or override height/paddingX to match its design system.
276
+ button: {
277
+ radius: 9999,
278
+ height: 52,
279
+ paddingX: 24
280
+ }
281
+ };
282
+ var mergeTheme = (override) => {
283
+ return defaultOnboardingTheme;
284
+ };
285
+ var OnboardingThemeContext = React3.createContext(null);
286
+ var useOnboardingTheme = () => {
287
+ const ctx = React3.useContext(OnboardingThemeContext);
288
+ return ctx != null ? ctx : mergeTheme();
289
+ };
290
+ var SWIPE_MS = 700;
291
+ var TAP_MS = 320;
292
+ var SPREAD_MS = 620;
293
+ var GLYPH_ROTATION = {
294
+ swipe_up: "0deg",
295
+ swipe_down: "180deg",
296
+ swipe_left: "-90deg",
297
+ swipe_right: "90deg"
298
+ };
299
+ var FingerPair = ({ size, color }) => {
300
+ const { row, index, middle } = React3.useMemo(() => {
301
+ const w = size * 0.2;
302
+ const r = w / 2;
303
+ return {
304
+ row: { flexDirection: "row", alignItems: "flex-end", gap: size * 0.08 },
305
+ index: { width: w, height: size * 0.54, borderRadius: r, backgroundColor: color },
306
+ middle: { width: w, height: size * 0.44, borderRadius: r, backgroundColor: color }
307
+ };
308
+ }, [size, color]);
309
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: row, pointerEvents: "none", children: [
310
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: index }),
311
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: middle })
312
+ ] });
313
+ };
314
+ var MotionTrack = ({ size, color }) => {
315
+ const { wrap, tick0, tick1 } = React3.useMemo(() => {
316
+ const h = Math.max(2, size * 0.05);
317
+ return {
318
+ wrap: { alignItems: "center", marginTop: size * 0.1, gap: size * 0.06 },
319
+ tick0: {
320
+ width: size * 0.3,
321
+ height: h,
322
+ borderRadius: h / 2,
323
+ backgroundColor: color,
324
+ opacity: 0.4
325
+ },
326
+ tick1: {
327
+ width: size * 0.18,
328
+ height: h,
329
+ borderRadius: h / 2,
330
+ backgroundColor: color,
331
+ opacity: 0.16
332
+ }
333
+ };
334
+ }, [size, color]);
335
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: wrap, pointerEvents: "none", children: [
336
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: tick0 }),
337
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: tick1 })
338
+ ] });
339
+ };
340
+ var GestureHintComponent = ({
341
+ type,
342
+ size = 34,
343
+ color = "white",
344
+ renderHand
345
+ }) => {
346
+ var _a;
347
+ const translate = Animated.useSharedValue(0);
348
+ const opacity = Animated.useSharedValue(1);
349
+ const pulse = Animated.useSharedValue(1);
350
+ const spread = Animated.useSharedValue(0);
351
+ const reduced = Animated.useReducedMotion();
352
+ const isSwipe = type === "swipe_up" || type === "swipe_down" || type === "swipe_left" || type === "swipe_right";
353
+ const isSpread = type === "pinch" || type === "zoom";
354
+ const isTap = type === "tap" || type === "double_tap";
355
+ React3.useEffect(() => {
356
+ if (type === "none" || reduced) return void 0;
357
+ if (isTap) {
358
+ pulse.value = Animated.withRepeat(
359
+ Animated.withSequence(
360
+ Animated.withTiming(0.82, { duration: TAP_MS }),
361
+ Animated.withTiming(1, { duration: TAP_MS })
362
+ ),
363
+ -1,
364
+ false
365
+ );
366
+ opacity.value = Animated.withRepeat(
367
+ Animated.withSequence(
368
+ Animated.withTiming(0.55, { duration: TAP_MS }),
369
+ Animated.withTiming(1, { duration: TAP_MS })
370
+ ),
371
+ -1,
372
+ false
373
+ );
374
+ return void 0;
375
+ }
376
+ if (isSpread) {
377
+ spread.value = Animated.withRepeat(
378
+ Animated.withSequence(
379
+ Animated.withTiming(size * 0.26, { duration: SPREAD_MS }),
380
+ Animated.withTiming(0, { duration: SPREAD_MS })
381
+ ),
382
+ -1,
383
+ false
384
+ );
385
+ return void 0;
386
+ }
387
+ translate.value = Animated.withRepeat(
388
+ Animated.withSequence(
389
+ Animated.withTiming(0, { duration: 0 }),
390
+ Animated.withTiming(-26, { duration: SWIPE_MS }),
391
+ Animated.withDelay(140, Animated.withTiming(0, { duration: 0 }))
392
+ ),
393
+ -1,
394
+ false
395
+ );
396
+ opacity.value = Animated.withRepeat(
397
+ Animated.withSequence(
398
+ Animated.withTiming(1, { duration: SWIPE_MS / 2 }),
399
+ Animated.withTiming(0, { duration: SWIPE_MS / 2 }),
400
+ Animated.withDelay(140, Animated.withTiming(1, { duration: 0 }))
401
+ ),
402
+ -1,
403
+ false
404
+ );
405
+ return void 0;
406
+ }, [type, reduced, isTap, isSpread, translate, opacity, pulse, spread, size]);
407
+ const swipeAnimatedStyle = Animated.useAnimatedStyle(() => ({
408
+ opacity: opacity.value,
409
+ transform: [{ translateY: translate.value }]
410
+ }));
411
+ const tapAnimatedStyle = Animated.useAnimatedStyle(() => ({
412
+ opacity: opacity.value,
413
+ transform: [{ scale: pulse.value }]
414
+ }));
415
+ const spreadLeftStyle = Animated.useAnimatedStyle(() => ({
416
+ transform: [{ translateX: -spread.value }]
417
+ }));
418
+ const spreadRightStyle = Animated.useAnimatedStyle(() => ({
419
+ transform: [{ translateX: spread.value }]
420
+ }));
421
+ if (type === "none") return null;
422
+ const customGlyph = renderHand ? renderHand({ size, color }) : null;
423
+ if (isSwipe) {
424
+ return /* @__PURE__ */ jsxRuntime.jsx(
425
+ reactNative.View,
426
+ {
427
+ style: { transform: [{ rotate: (_a = GLYPH_ROTATION[type]) != null ? _a : "0deg" }] },
428
+ pointerEvents: "none",
429
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.swipeStack, children: [
430
+ /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: swipeAnimatedStyle, pointerEvents: "none", children: customGlyph != null ? customGlyph : /* @__PURE__ */ jsxRuntime.jsx(FingerPair, { size, color }) }),
431
+ /* @__PURE__ */ jsxRuntime.jsx(MotionTrack, { size, color })
432
+ ] })
433
+ }
434
+ );
435
+ }
436
+ if (isSpread) {
437
+ const w = size * 0.2;
438
+ const capsule = {
439
+ width: w,
440
+ height: size * 0.5,
441
+ borderRadius: w / 2,
442
+ backgroundColor: color
443
+ };
444
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.spreadRow, { gap: size * 0.12 }], pointerEvents: "none", children: [
445
+ /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: spreadLeftStyle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: capsule }) }),
446
+ /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: spreadRightStyle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: capsule }) })
447
+ ] });
448
+ }
449
+ const ringSize = size * 0.86;
450
+ const ringBorder = Math.max(2, size * 0.08);
451
+ const dotSize = size * 0.32;
452
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.tapWrap, { width: size, height: size }], pointerEvents: "none", children: customGlyph ? /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: tapAnimatedStyle, pointerEvents: "none", children: customGlyph }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
453
+ /* @__PURE__ */ jsxRuntime.jsx(
454
+ Animated__default.default.View,
455
+ {
456
+ style: [
457
+ styles.tapRing,
458
+ {
459
+ width: ringSize,
460
+ height: ringSize,
461
+ borderRadius: ringSize / 2,
462
+ borderWidth: ringBorder,
463
+ borderColor: color
464
+ },
465
+ tapAnimatedStyle
466
+ ],
467
+ pointerEvents: "none"
468
+ }
469
+ ),
470
+ /* @__PURE__ */ jsxRuntime.jsx(
471
+ reactNative.View,
472
+ {
473
+ style: {
474
+ position: "absolute",
475
+ width: dotSize,
476
+ height: dotSize,
477
+ borderRadius: dotSize / 2,
478
+ backgroundColor: color
479
+ }
480
+ }
481
+ )
482
+ ] }) });
483
+ };
484
+ var styles = reactNative.StyleSheet.create({
485
+ swipeStack: {
486
+ alignItems: "center",
487
+ justifyContent: "center"
488
+ },
489
+ spreadRow: {
490
+ flexDirection: "row",
491
+ alignItems: "center",
492
+ justifyContent: "center"
493
+ },
494
+ tapWrap: {
495
+ alignItems: "center",
496
+ justifyContent: "center"
497
+ },
498
+ tapRing: {
499
+ backgroundColor: "transparent"
500
+ }
501
+ });
502
+ var GestureHint = React3__default.default.memo(GestureHintComponent);
503
+ GestureHint.displayName = "GestureHint";
504
+ var AnimatedBlurView = Animated__default.default.createAnimatedComponent(expoBlur.BlurView);
505
+ var BLUR_INTENSITY = 26;
506
+ var FADE_MS = 280;
507
+ var RING_PADDING = 10;
508
+ var TOOLTIP_GAP = 14;
509
+ var SIDE_MARGIN = 20;
510
+ var PILL_MAX_WIDTH = 260;
511
+ var SpotlightOverlayComponent = ({
512
+ message,
513
+ targetRect,
514
+ gesture = "none",
515
+ placement = "bottom",
516
+ onEngage,
517
+ onDismiss,
518
+ accentColor,
519
+ accentTextColor
520
+ }) => {
521
+ const { height: screenH } = reactNative.useWindowDimensions();
522
+ const reduced = Animated.useReducedMotion();
523
+ const theme = useOnboardingTheme();
524
+ const accent = accentColor != null ? accentColor : theme.colors.primary;
525
+ const accentText = accentTextColor != null ? accentTextColor : theme.colors.onPrimary;
526
+ const showGesture = gesture !== "none" && gesture !== "tap" && gesture !== "double_tap";
527
+ const intensity = Animated.useSharedValue(0);
528
+ const ringScale = Animated.useSharedValue(1);
529
+ React3.useEffect(() => {
530
+ intensity.value = Animated.withTiming(BLUR_INTENSITY, { duration: FADE_MS });
531
+ }, [intensity]);
532
+ React3.useEffect(() => {
533
+ if (reduced) return;
534
+ ringScale.value = Animated.withRepeat(
535
+ Animated.withSequence(
536
+ Animated.withTiming(1.06, { duration: 700 }),
537
+ Animated.withTiming(1, { duration: 700 })
538
+ ),
539
+ -1,
540
+ true
541
+ );
542
+ }, [reduced, ringScale]);
543
+ const blurAnimatedProps = Animated.useAnimatedProps(() => ({
544
+ intensity: intensity.value
545
+ }));
546
+ const ringAnimatedStyle = Animated.useAnimatedStyle(() => ({
547
+ transform: [{ scale: ringScale.value }]
548
+ }));
549
+ const geometry = React3.useMemo(() => {
550
+ if (!targetRect) return null;
551
+ const ringLeft = targetRect.x - RING_PADDING;
552
+ const ringTop = targetRect.y - RING_PADDING;
553
+ const ringW = targetRect.width + RING_PADDING * 2;
554
+ const ringH = targetRect.height + RING_PADDING * 2;
555
+ return {
556
+ ring: {
557
+ left: ringLeft,
558
+ top: ringTop,
559
+ width: ringW,
560
+ height: ringH,
561
+ borderRadius: Math.min(ringW, ringH) / 2
562
+ },
563
+ // Tooltip above or below the ring depending on placement.
564
+ tooltip: placement === "top" ? { bottom: screenH - ringTop + TOOLTIP_GAP } : { top: ringTop + ringH + TOOLTIP_GAP }
565
+ };
566
+ }, [targetRect, placement, screenH]);
567
+ return /* @__PURE__ */ jsxRuntime.jsxs(
568
+ Animated__default.default.View,
569
+ {
570
+ style: [reactNative.StyleSheet.absoluteFill, styles2.root],
571
+ entering: Animated.FadeIn.duration(FADE_MS),
572
+ exiting: Animated.FadeOut.duration(FADE_MS),
573
+ children: [
574
+ /* @__PURE__ */ jsxRuntime.jsx(
575
+ AnimatedBlurView,
576
+ {
577
+ tint: "dark",
578
+ animatedProps: blurAnimatedProps,
579
+ style: reactNative.StyleSheet.absoluteFill
580
+ }
581
+ ),
582
+ /* @__PURE__ */ jsxRuntime.jsx(
583
+ reactNative.Pressable,
584
+ {
585
+ style: reactNative.StyleSheet.absoluteFill,
586
+ onPress: onDismiss,
587
+ accessibilityRole: "button",
588
+ accessibilityLabel: "Next hint"
589
+ }
590
+ ),
591
+ geometry && /* @__PURE__ */ jsxRuntime.jsx(
592
+ Animated__default.default.View,
593
+ {
594
+ style: [
595
+ styles2.ring,
596
+ geometry.ring,
597
+ { borderColor: accent, shadowColor: accent },
598
+ ringAnimatedStyle
599
+ ],
600
+ pointerEvents: "box-none",
601
+ children: /* @__PURE__ */ jsxRuntime.jsx(
602
+ reactNative.Pressable,
603
+ {
604
+ style: reactNative.StyleSheet.absoluteFill,
605
+ onPress: onEngage,
606
+ accessibilityRole: "button",
607
+ accessibilityLabel: message
608
+ }
609
+ )
610
+ }
611
+ ),
612
+ /* @__PURE__ */ jsxRuntime.jsxs(
613
+ reactNative.View,
614
+ {
615
+ style: [
616
+ styles2.tooltipWrapper,
617
+ geometry ? geometry.tooltip : { top: screenH * 0.42, alignItems: "center" }
618
+ ],
619
+ pointerEvents: "box-none",
620
+ children: [
621
+ showGesture && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.gestureSlot, pointerEvents: "none", children: /* @__PURE__ */ jsxRuntime.jsx(GestureHint, { type: gesture, color: accent }) }),
622
+ /* @__PURE__ */ jsxRuntime.jsx(
623
+ reactNative.Pressable,
624
+ {
625
+ onPress: onEngage,
626
+ style: [styles2.pill, { backgroundColor: accent }],
627
+ accessibilityRole: "button",
628
+ accessibilityLabel: message,
629
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { numberOfLines: 3, style: [styles2.pillText, { color: accentText }], children: message })
630
+ }
631
+ )
632
+ ]
633
+ }
634
+ )
635
+ ]
636
+ }
637
+ );
638
+ };
639
+ var styles2 = reactNative.StyleSheet.create({
640
+ // High elevation/zIndex so the whole overlay (incl. the frosted blur) sits
641
+ // above the bottom tab bar on Android, where sibling z-order follows
642
+ // elevation, not tree order.
643
+ root: {
644
+ zIndex: 9999,
645
+ elevation: 9999
646
+ },
647
+ ring: {
648
+ position: "absolute",
649
+ borderWidth: 2.5,
650
+ backgroundColor: "transparent",
651
+ shadowOffset: { width: 0, height: 0 },
652
+ shadowOpacity: 0.9,
653
+ shadowRadius: 12,
654
+ elevation: 10
655
+ },
656
+ tooltipWrapper: {
657
+ position: "absolute",
658
+ left: SIDE_MARGIN,
659
+ right: SIDE_MARGIN,
660
+ alignItems: "center",
661
+ gap: 10
662
+ },
663
+ gestureSlot: {
664
+ alignItems: "center",
665
+ justifyContent: "center"
666
+ },
667
+ pill: {
668
+ maxWidth: PILL_MAX_WIDTH,
669
+ paddingVertical: 12,
670
+ paddingHorizontal: 18,
671
+ borderRadius: 18,
672
+ shadowColor: "#000",
673
+ shadowOffset: { width: 0, height: 2 },
674
+ shadowOpacity: 0.25,
675
+ shadowRadius: 6,
676
+ elevation: 6
677
+ },
678
+ pillText: {
679
+ fontSize: 14,
680
+ fontWeight: "800",
681
+ textAlign: "center"
682
+ }
683
+ });
684
+ var SpotlightOverlay = React3__default.default.memo(SpotlightOverlayComponent);
685
+ SpotlightOverlay.displayName = "SpotlightOverlay";
686
+ var CoachmarkOverlayHostComponent = ({
687
+ accentColor,
688
+ accentTextColor
689
+ }) => {
690
+ const active = useCoachmarkOverlay();
691
+ if (!active) return null;
692
+ return /* @__PURE__ */ jsxRuntime.jsx(
693
+ SpotlightOverlay,
694
+ {
695
+ message: active.message,
696
+ targetRect: active.targetRect,
697
+ gesture: active.gesture,
698
+ placement: active.placement,
699
+ onEngage: active.onEngage,
700
+ onDismiss: active.onDismiss,
701
+ accentColor,
702
+ accentTextColor
703
+ }
704
+ );
705
+ };
706
+ var CoachmarkOverlayHost = React3__default.default.memo(CoachmarkOverlayHostComponent);
707
+ CoachmarkOverlayHost.displayName = "CoachmarkOverlayHost";
708
+ var CoachmarkProvider = ({
709
+ storage,
710
+ isTestingCoachmark = false,
711
+ accentColor,
712
+ accentTextColor,
713
+ features,
714
+ featuresConfig,
715
+ children
716
+ }) => {
717
+ const flags = useResolvedFeatures({ flags: features, config: featuresConfig });
718
+ const coachmarksOn = flags.coachmarks.enabled;
719
+ setCoachmarkStorage(storage);
720
+ setCoachmarkTesting(isTestingCoachmark);
721
+ setCoachmarksEnabled(coachmarksOn);
722
+ React3.useEffect(() => {
723
+ setCoachmarkStorage(storage);
724
+ setCoachmarkTesting(isTestingCoachmark);
725
+ setCoachmarksEnabled(coachmarksOn);
726
+ return () => {
727
+ if (getCoachmarkStorage() === storage) {
728
+ setCoachmarkStorage(null);
729
+ }
730
+ setCoachmarksEnabled(true);
731
+ };
732
+ }, [storage, isTestingCoachmark, coachmarksOn]);
733
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
734
+ children,
735
+ /* @__PURE__ */ jsxRuntime.jsx(
736
+ CoachmarkOverlayHost,
737
+ {
738
+ accentColor,
739
+ accentTextColor
740
+ }
741
+ )
742
+ ] });
743
+ };
744
+ CoachmarkProvider.displayName = "CoachmarkProvider";
745
+
746
+ // src/coachmarks/coachmarkAnchorRegistry.ts
747
+ var anchors = /* @__PURE__ */ new Map();
748
+ var coachmarkAnchors = {
749
+ register(id, measurer) {
750
+ anchors.set(id, measurer);
751
+ },
752
+ /**
753
+ * Only clears the id when `measurer` is still the current registration, so a
754
+ * screen unmounting after a newer screen registered the same id does not wipe
755
+ * the live measurer. Omit `measurer` to force-delete regardless.
756
+ */
757
+ unregister(id, measurer) {
758
+ if (measurer !== void 0 && anchors.get(id) !== measurer) return;
759
+ anchors.delete(id);
760
+ },
761
+ get(id) {
762
+ return anchors.get(id);
763
+ },
764
+ /**
765
+ * Resolve an anchor to a rect, retrying briefly while the target lays out
766
+ * (e.g. the first feed post, or a screen just navigated to). Cancellable via
767
+ * `shouldCancel` so a superseded step abandons its retry loop immediately.
768
+ */
769
+ async resolve(id, {
770
+ retries = 6,
771
+ intervalMs = 120,
772
+ shouldCancel
773
+ } = {}) {
774
+ for (let attempt = 0; attempt <= retries; attempt++) {
775
+ if (shouldCancel == null ? void 0 : shouldCancel()) return null;
776
+ const measurer = anchors.get(id);
777
+ if (measurer) {
778
+ const rect = await measurer();
779
+ if (rect && rect.width > 0 && rect.height > 0) return rect;
780
+ }
781
+ if (attempt < retries) {
782
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
783
+ }
784
+ }
785
+ return null;
786
+ }
787
+ };
788
+
789
+ // src/coachmarks/useCoachmarkAnchor.ts
790
+ var useCoachmarkAnchor = (id) => {
791
+ const ref = React3.useRef(null);
792
+ React3.useEffect(() => {
793
+ if (!id) return void 0;
794
+ const measure = () => new Promise((resolve) => {
795
+ const node = ref.current;
796
+ if (!node || typeof node.measureInWindow !== "function") {
797
+ return resolve(null);
798
+ }
799
+ node.measureInWindow((x, y, width, height) => {
800
+ if ([x, y, width, height].some(
801
+ (value) => value == null || Number.isNaN(value)
802
+ )) {
803
+ return resolve(null);
804
+ }
805
+ resolve({ x, y, width, height });
806
+ });
807
+ });
808
+ coachmarkAnchors.register(id, measure);
809
+ return () => coachmarkAnchors.unregister(id, measure);
810
+ }, [id]);
811
+ return ref;
812
+ };
813
+ var DEFAULT_START_DELAY_MS = 3e3;
814
+ var useCoachmarkTour = (steps, {
815
+ tourId,
816
+ showOnce = true,
817
+ enabled,
818
+ startDelayMs = DEFAULT_START_DELAY_MS,
819
+ onComplete,
820
+ onStepShown,
821
+ onStepEngaged,
822
+ onStepDismissed
823
+ }) => {
824
+ const [activeIndex, setActiveIndex] = React3.useState(null);
825
+ const startedRef = React3.useRef(false);
826
+ const finishedRef = React3.useRef(false);
827
+ const lastShownStepIdRef = React3.useRef(null);
828
+ const callbacksRef = React3.useRef({ onStepShown, onStepEngaged, onStepDismissed });
829
+ callbacksRef.current = { onStepShown, onStepEngaged, onStepDismissed };
830
+ const finish = React3.useCallback(() => {
831
+ if (finishedRef.current) return;
832
+ finishedRef.current = true;
833
+ if (showOnce) markSeenGate(coachmarkGateKey(tourId));
834
+ coachmarkOverlay.hide();
835
+ setActiveIndex(null);
836
+ onComplete == null ? void 0 : onComplete();
837
+ }, [onComplete, showOnce, tourId]);
838
+ React3.useEffect(() => {
839
+ if (!enabled || startedRef.current) return void 0;
840
+ if (!areCoachmarksEnabled()) return void 0;
841
+ if (showOnce && hasSeenGate(coachmarkGateKey(tourId))) return void 0;
842
+ const timer = setTimeout(() => {
843
+ startedRef.current = true;
844
+ setActiveIndex(0);
845
+ }, startDelayMs);
846
+ return () => clearTimeout(timer);
847
+ }, [enabled, startDelayMs, showOnce, tourId]);
848
+ React3.useEffect(() => {
849
+ if (activeIndex === null) return void 0;
850
+ if (!enabled) {
851
+ if (startedRef.current && !finishedRef.current) coachmarkOverlay.hide();
852
+ return void 0;
853
+ }
854
+ if (activeIndex >= steps.length) {
855
+ finish();
856
+ return void 0;
857
+ }
858
+ const step = steps[activeIndex];
859
+ if (!step) {
860
+ finish();
861
+ return void 0;
862
+ }
863
+ let cancelled = false;
864
+ (async () => {
865
+ var _a, _b, _c, _d;
866
+ const rect = step.anchorId ? await coachmarkAnchors.resolve(step.anchorId, {
867
+ shouldCancel: () => cancelled
868
+ }) : null;
869
+ if (cancelled) return;
870
+ if (lastShownStepIdRef.current !== step.id) {
871
+ lastShownStepIdRef.current = step.id;
872
+ (_b = (_a = callbacksRef.current).onStepShown) == null ? void 0 : _b.call(_a, step.id);
873
+ }
874
+ coachmarkOverlay.show({
875
+ message: step.message,
876
+ targetRect: rect,
877
+ gesture: (_c = step.gesture) != null ? _c : "none",
878
+ placement: (_d = step.placement) != null ? _d : "bottom",
879
+ onEngage: () => {
880
+ var _a2, _b2, _c2;
881
+ (_b2 = (_a2 = callbacksRef.current).onStepEngaged) == null ? void 0 : _b2.call(_a2, step.id);
882
+ (_c2 = step.onEngage) == null ? void 0 : _c2.call(step);
883
+ setActiveIndex((index) => (index != null ? index : 0) + 1);
884
+ },
885
+ onDismiss: () => {
886
+ var _a2, _b2;
887
+ (_b2 = (_a2 = callbacksRef.current).onStepDismissed) == null ? void 0 : _b2.call(_a2, step.id);
888
+ if (activeIndex >= steps.length - 1) {
889
+ finish();
890
+ } else {
891
+ setActiveIndex((index) => (index != null ? index : 0) + 1);
892
+ }
893
+ }
894
+ });
895
+ })();
896
+ return () => {
897
+ cancelled = true;
898
+ };
899
+ }, [activeIndex, steps, finish, enabled]);
900
+ React3.useEffect(
901
+ () => () => {
902
+ if (!finishedRef.current) coachmarkOverlay.hide();
903
+ },
904
+ []
905
+ );
906
+ };
907
+
908
+ // src/coachmarks/selectTourSteps.ts
909
+ var selectTourSteps = (catalog, selection) => {
910
+ if (!selection) return catalog;
911
+ const byId = new Map(catalog.map((item) => [item.id, item]));
912
+ const seen = /* @__PURE__ */ new Set();
913
+ const ordered = [];
914
+ for (const id of selection) {
915
+ if (seen.has(id)) continue;
916
+ seen.add(id);
917
+ const item = byId.get(id);
918
+ if (item) ordered.push(item);
919
+ }
920
+ return ordered;
921
+ };
922
+
923
+ exports.CoachmarkOverlayHost = CoachmarkOverlayHost;
924
+ exports.CoachmarkProvider = CoachmarkProvider;
925
+ exports.GestureHint = GestureHint;
926
+ exports.SpotlightOverlay = SpotlightOverlay;
927
+ exports.areCoachmarksEnabled = areCoachmarksEnabled;
928
+ exports.coachmarkAnchors = coachmarkAnchors;
929
+ exports.coachmarkGateKey = coachmarkGateKey;
930
+ exports.coachmarkOverlay = coachmarkOverlay;
931
+ exports.getCoachmarkStorage = getCoachmarkStorage;
932
+ exports.hasSeenGate = hasSeenGate;
933
+ exports.isCoachmarkTesting = isCoachmarkTesting;
934
+ exports.markSeenGate = markSeenGate;
935
+ exports.selectTourSteps = selectTourSteps;
936
+ exports.setCoachmarkStorage = setCoachmarkStorage;
937
+ exports.setCoachmarkTesting = setCoachmarkTesting;
938
+ exports.setCoachmarksEnabled = setCoachmarksEnabled;
939
+ exports.showcaseGateKey = showcaseGateKey;
940
+ exports.useCoachmarkAnchor = useCoachmarkAnchor;
941
+ exports.useCoachmarkOverlay = useCoachmarkOverlay;
942
+ exports.useCoachmarkTour = useCoachmarkTour;
943
+ //# sourceMappingURL=index.js.map
944
+ //# sourceMappingURL=index.js.map