@wireai/activation 0.14.2 → 0.15.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 (67) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +144 -0
  3. package/README.md +23 -9
  4. package/dist/analytics/index.d.mts +5 -5
  5. package/dist/analytics/index.d.ts +5 -5
  6. package/dist/analytics/index.js.map +1 -1
  7. package/dist/analytics/index.mjs.map +1 -1
  8. package/dist/coachmarks/index.d.mts +13 -5
  9. package/dist/coachmarks/index.d.ts +13 -5
  10. package/dist/coachmarks/index.js +252 -58
  11. package/dist/coachmarks/index.js.map +1 -1
  12. package/dist/coachmarks/index.mjs +204 -9
  13. package/dist/coachmarks/index.mjs.map +1 -1
  14. package/dist/{currentSession-CW_5Mq4O.d.ts → currentSession-CFSRZ2wg.d.ts} +10 -4
  15. package/dist/{currentSession-CUvTOchb.d.mts → currentSession-orZy5p1e.d.mts} +10 -4
  16. package/dist/{decision-Bgo17oH7.d.mts → decision-3vWLuBlO.d.ts} +11 -2
  17. package/dist/{decision-Bkh_LigV.d.ts → decision-yBj2AyPW.d.mts} +11 -2
  18. package/dist/index.d.mts +2 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/questionnaire/index.d.mts +3 -3
  23. package/dist/questionnaire/index.d.ts +3 -3
  24. package/dist/questionnaire/index.js +48 -3
  25. package/dist/questionnaire/index.js.map +1 -1
  26. package/dist/questionnaire/index.mjs +48 -3
  27. package/dist/questionnaire/index.mjs.map +1 -1
  28. package/dist/reviews/index.d.mts +10 -6
  29. package/dist/reviews/index.d.ts +10 -6
  30. package/dist/reviews/index.js +167 -18
  31. package/dist/reviews/index.js.map +1 -1
  32. package/dist/reviews/index.mjs +167 -18
  33. package/dist/reviews/index.mjs.map +1 -1
  34. package/dist/showcase/index.d.mts +1 -1
  35. package/dist/showcase/index.d.ts +1 -1
  36. package/dist/showcase/index.js +282 -48
  37. package/dist/showcase/index.js.map +1 -1
  38. package/dist/showcase/index.mjs +248 -12
  39. package/dist/showcase/index.mjs.map +1 -1
  40. package/dist/{transport-j5gFfJhK.d.mts → transport-s5QxA-ci.d.mts} +18 -13
  41. package/dist/{transport-B_0SgCBe.d.ts → transport-xqqSFqxs.d.ts} +18 -13
  42. package/dist/{types-Cju-1_jT.d.mts → types-Byx306Kv.d.mts} +25 -10
  43. package/dist/{types-BcmagF6K.d.mts → types-D_0B0yay.d.mts} +7 -2
  44. package/dist/{types-BcmagF6K.d.ts → types-D_0B0yay.d.ts} +7 -2
  45. package/dist/{types-h2BZvl1t.d.ts → types-tdATL5z0.d.ts} +25 -10
  46. package/metro/index.js +16 -5
  47. package/package.json +1 -1
  48. package/src/WireOnboarding.tsx +4 -1
  49. package/src/coachmarks/GestureHint.tsx +16 -7
  50. package/src/coachmarks/SpotlightOverlay.tsx +19 -13
  51. package/src/coachmarks/index.ts +7 -2
  52. package/src/coachmarks/reanimated.ts +342 -0
  53. package/src/coachmarks/runtime.ts +103 -2
  54. package/src/coachmarks/types.ts +7 -2
  55. package/src/context/deviceId.ts +32 -0
  56. package/src/reviews/ReviewGate.tsx +86 -37
  57. package/src/reviews/decision.ts +11 -1
  58. package/src/reviews/idempotency.ts +71 -0
  59. package/src/reviews/index.ts +4 -2
  60. package/src/reviews/runtime.ts +5 -3
  61. package/src/reviews/transport.ts +17 -12
  62. package/src/reviews/types.ts +7 -0
  63. package/src/showcase/FeatureShowcase.tsx +25 -9
  64. package/src/showcase/blazejOnboarding.ts +136 -0
  65. package/src/showcase/index.ts +8 -4
  66. package/src/types.ts +10 -4
  67. package/src/utils/submitResult.ts +17 -9
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { ReactNode } from 'react';
3
3
  import { a as WireFeatures, b as WireFeaturesConfig } from '../types-BpwiRpA8.mjs';
4
- import { C as CoachmarkStorage, a as CoachmarkStep, G as GestureKind, T as TargetRect, P as Placement } from '../types-BcmagF6K.mjs';
4
+ import { C as CoachmarkStorage, a as CoachmarkStep, G as GestureKind, T as TargetRect, P as Placement } from '../types-D_0B0yay.mjs';
5
5
  import { View } from 'react-native';
6
6
 
7
7
  interface CoachmarkProviderProps {
@@ -245,10 +245,18 @@ declare const selectTourSteps: <T extends {
245
245
  }>(catalog: T[], selection?: string[]) => T[];
246
246
 
247
247
  /**
248
- * Abstract gesture pictogram shown beside a coachmark tooltip. Pure reanimated
249
- * every animation runs on the UI thread (shared values + worklets), never
250
- * setState, so it costs nothing on the JS thread. Honors Reduce Motion by
251
- * dropping the motion loop and rendering the glyph static.
248
+ * Abstract gesture pictogram shown beside a coachmark tooltip. With the OPTIONAL
249
+ * `react-native-reanimated` peer installed every animation runs on the UI thread
250
+ * (shared values + worklets), never setState, so it costs nothing on the JS
251
+ * thread. Honors Reduce Motion by dropping the motion loop and rendering the
252
+ * glyph static.
253
+ *
254
+ * The peer is reached through the guarded lazy require in `reanimated.ts`, never
255
+ * a static import, so `@wireai/activation/coachmarks` (and `/showcase`, which
256
+ * reaches this component through FeatureShowcase) builds on a host that never
257
+ * installed it. Absent, the glyph renders STATICALLY at its resting frame — the
258
+ * same capsules, ring, dot and motion track, at full opacity and no travel, with
259
+ * one render instead of a UI-thread loop. The pictogram never disappears.
252
260
  *
253
261
  * NO drawn-hand anatomy. Swipes render the standard two-finger swipe glyph: two
254
262
  * rounded vertical capsules (an abstract index + middle finger, slightly
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { ReactNode } from 'react';
3
3
  import { a as WireFeatures, b as WireFeaturesConfig } from '../types-BpwiRpA8.js';
4
- import { C as CoachmarkStorage, a as CoachmarkStep, G as GestureKind, T as TargetRect, P as Placement } from '../types-BcmagF6K.js';
4
+ import { C as CoachmarkStorage, a as CoachmarkStep, G as GestureKind, T as TargetRect, P as Placement } from '../types-D_0B0yay.js';
5
5
  import { View } from 'react-native';
6
6
 
7
7
  interface CoachmarkProviderProps {
@@ -245,10 +245,18 @@ declare const selectTourSteps: <T extends {
245
245
  }>(catalog: T[], selection?: string[]) => T[];
246
246
 
247
247
  /**
248
- * Abstract gesture pictogram shown beside a coachmark tooltip. Pure reanimated
249
- * every animation runs on the UI thread (shared values + worklets), never
250
- * setState, so it costs nothing on the JS thread. Honors Reduce Motion by
251
- * dropping the motion loop and rendering the glyph static.
248
+ * Abstract gesture pictogram shown beside a coachmark tooltip. With the OPTIONAL
249
+ * `react-native-reanimated` peer installed every animation runs on the UI thread
250
+ * (shared values + worklets), never setState, so it costs nothing on the JS
251
+ * thread. Honors Reduce Motion by dropping the motion loop and rendering the
252
+ * glyph static.
253
+ *
254
+ * The peer is reached through the guarded lazy require in `reanimated.ts`, never
255
+ * a static import, so `@wireai/activation/coachmarks` (and `/showcase`, which
256
+ * reaches this component through FeatureShowcase) builds on a host that never
257
+ * installed it. Absent, the glyph renders STATICALLY at its resting frame — the
258
+ * same capsules, ring, dot and motion track, at full opacity and no travel, with
259
+ * one render instead of a UI-thread loop. The pictogram never disappears.
252
260
  *
253
261
  * NO drawn-hand anatomy. Swipes render the standard two-finger swipe glyph: two
254
262
  * rounded vertical capsules (an abstract index + middle finger, slightly
@@ -3,12 +3,10 @@
3
3
  var React3 = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var reactNative = require('react-native');
6
- var Animated = require('react-native-reanimated');
7
6
 
8
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
8
 
10
9
  var React3__default = /*#__PURE__*/_interopDefault(React3);
11
- var Animated__default = /*#__PURE__*/_interopDefault(Animated);
12
10
 
13
11
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
14
12
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -94,8 +92,8 @@ var DEFAULT_TIMEOUT_MS = 4e3;
94
92
  var failOpen = async (storage, key) => {
95
93
  var _a;
96
94
  if (!storage) return defaultWireFeatures;
97
- const cached2 = await readCachedFeatures(storage, key);
98
- return (_a = cached2 == null ? void 0 : cached2.features) != null ? _a : defaultWireFeatures;
95
+ const cached3 = await readCachedFeatures(storage, key);
96
+ return (_a = cached3 == null ? void 0 : cached3.features) != null ? _a : defaultWireFeatures;
99
97
  };
100
98
  var fetchWithTimeout = async (url, apiKey, timeoutMs) => {
101
99
  const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
@@ -221,9 +219,54 @@ var isCoachmarkTesting = () => coachmarkRuntime().testing;
221
219
  var coachmarkGateKey = (tourId) => `wire_coachmark_${tourId}_seen`;
222
220
  var showcaseGateKey = (showcaseId) => `wire_showcase_${showcaseId}_seen`;
223
221
  var SEEN_VALUE = "1";
222
+ var GATE_PROBE_KEY = "wire_gate_probe";
223
+ var ASYNC_GATE_STORAGE_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
224
+ "@wireai/activation:asyncGateStorageWarned"
225
+ );
226
+ var asyncGateWarnGlobal = globalThis;
227
+ var closedGateStorage = Object.freeze({
228
+ getItem: () => SEEN_VALUE,
229
+ setItem: () => {
230
+ }
231
+ });
232
+ var syncGateAdapters = /* @__PURE__ */ new WeakSet();
233
+ var asyncGateAdapters = /* @__PURE__ */ new WeakSet();
234
+ var warnAsyncGateStorage = () => {
235
+ if (asyncGateWarnGlobal[ASYNC_GATE_STORAGE_WARNED_SLOT]) return;
236
+ if (typeof __DEV__ === "undefined" || !__DEV__) return;
237
+ if (typeof console === "undefined" || !console.warn) return;
238
+ asyncGateWarnGlobal[ASYNC_GATE_STORAGE_WARNED_SLOT] = true;
239
+ console.warn(
240
+ "[wireai] the gate storage's getItem returned a Promise \u2014 an async adapter (e.g. AsyncStorage) cannot drive the once-per-user gates, so coachmark tours, showcases and the review/questionnaire gates are all DISABLED (fail closed: nothing shows, nothing fires) until a synchronous adapter is provided. Pass a sync adapter (e.g. MMKV: `{ getItem: (k) => mmkv.getString(k) ?? null, setItem: (k, v) => mmkv.set(k, v) }`) to CoachmarkProvider or the gate's `storage` prop."
241
+ );
242
+ };
243
+ var validateGateStorage = (storage) => {
244
+ if (!storage) return null;
245
+ if (syncGateAdapters.has(storage)) return storage;
246
+ if (asyncGateAdapters.has(storage)) return closedGateStorage;
247
+ let probed;
248
+ try {
249
+ probed = storage.getItem(GATE_PROBE_KEY);
250
+ } catch {
251
+ syncGateAdapters.add(storage);
252
+ return storage;
253
+ }
254
+ if (probed != null && typeof probed.then === "function") {
255
+ asyncGateAdapters.add(storage);
256
+ try {
257
+ probed.then(void 0, () => {
258
+ });
259
+ } catch {
260
+ }
261
+ warnAsyncGateStorage();
262
+ return closedGateStorage;
263
+ }
264
+ syncGateAdapters.add(storage);
265
+ return storage;
266
+ };
224
267
  var hasSeenGate = (key, storageOverride, testingOverride) => {
225
268
  if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return false;
226
- const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
269
+ const storage = validateGateStorage(storageOverride != null ? storageOverride : getCoachmarkStorage());
227
270
  if (!storage) return false;
228
271
  try {
229
272
  return storage.getItem(key) === SEEN_VALUE;
@@ -233,7 +276,7 @@ var hasSeenGate = (key, storageOverride, testingOverride) => {
233
276
  };
234
277
  var markSeenGate = (key, storageOverride, testingOverride) => {
235
278
  if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return;
236
- const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
279
+ const storage = validateGateStorage(storageOverride != null ? storageOverride : getCoachmarkStorage());
237
280
  if (!storage) return;
238
281
  try {
239
282
  storage.setItem(key, SEEN_VALUE);
@@ -374,6 +417,157 @@ var resolveBlurView = (requireModule = runtimeRequire) => {
374
417
  return void 0;
375
418
  }
376
419
  };
420
+ var lastKnown = false;
421
+ var useReducedMotion = () => {
422
+ const [reduced, setReduced] = React3.useState(lastKnown);
423
+ React3.useEffect(() => {
424
+ let mounted = true;
425
+ reactNative.AccessibilityInfo.isReduceMotionEnabled().then((value) => {
426
+ lastKnown = value;
427
+ if (mounted) setReduced(value);
428
+ }).catch(() => {
429
+ });
430
+ const sub = reactNative.AccessibilityInfo.addEventListener("reduceMotionChanged", (value) => {
431
+ lastKnown = value;
432
+ setReduced(value);
433
+ });
434
+ return () => {
435
+ mounted = false;
436
+ sub == null ? void 0 : sub.remove();
437
+ };
438
+ }, []);
439
+ return reduced;
440
+ };
441
+
442
+ // src/coachmarks/reanimated.ts
443
+ var runtimeRequire2 = (moduleName) => {
444
+ if (moduleName !== "react-native-reanimated") return void 0;
445
+ if (typeof __require !== "function") return void 0;
446
+ try {
447
+ return require("react-native-reanimated");
448
+ } catch {
449
+ return void 0;
450
+ }
451
+ };
452
+ var useStaticSharedValue = (initial) => {
453
+ const [, bump] = React3.useReducer((n) => n + 1, 0);
454
+ const box = React3.useRef(null);
455
+ if (box.current === null) {
456
+ let current2 = initial;
457
+ box.current = {
458
+ get value() {
459
+ return current2;
460
+ },
461
+ set value(next) {
462
+ if (Object.is(next, current2)) return;
463
+ current2 = next;
464
+ bump();
465
+ }
466
+ };
467
+ }
468
+ return box.current;
469
+ };
470
+ var runWorklet = (factory, fallback) => {
471
+ var _a;
472
+ try {
473
+ return (_a = factory()) != null ? _a : fallback;
474
+ } catch {
475
+ return fallback;
476
+ }
477
+ };
478
+ var StaticAnimatedView = React3.forwardRef(function StaticAnimatedView2({ entering: _entering, exiting: _exiting, children, ...rest }, ref) {
479
+ return React3.createElement(reactNative.View, { ...rest, ref }, children);
480
+ });
481
+ var staticCreateAnimatedComponent = (component) => function StaticAnimatedComponent({ animatedProps, ...rest }) {
482
+ return React3.createElement(component, { ...rest, ...animatedProps });
483
+ };
484
+ var staticApi = {
485
+ present: false,
486
+ View: StaticAnimatedView,
487
+ createAnimatedComponent: staticCreateAnimatedComponent,
488
+ useSharedValue: useStaticSharedValue,
489
+ useAnimatedStyle: (factory) => runWorklet(factory, {}),
490
+ useAnimatedProps: (factory) => runWorklet(factory, {}),
491
+ useReducedMotion,
492
+ withTiming: (toValue) => toValue,
493
+ withRepeat: (animation) => animation,
494
+ withSequence: (...animations) => {
495
+ var _a;
496
+ return (_a = animations[animations.length - 1]) != null ? _a : 0;
497
+ },
498
+ withDelay: (_ms, animation) => animation,
499
+ fadeIn: () => void 0,
500
+ fadeOut: () => void 0
501
+ };
502
+ var isFunction = (value) => typeof value === "function";
503
+ var isComponent = (value) => typeof value === "function" || !!value && typeof value === "object" && "$$typeof" in value;
504
+ var fromModule = (mod) => {
505
+ var _a, _b;
506
+ if (!mod || typeof mod !== "object") return void 0;
507
+ const ns = mod;
508
+ const def = ns.default && typeof ns.default === "object" ? ns.default : void 0;
509
+ const pick = (name) => {
510
+ var _a2;
511
+ return (_a2 = ns[name]) != null ? _a2 : def == null ? void 0 : def[name];
512
+ };
513
+ const view = (_a = def == null ? void 0 : def.View) != null ? _a : ns.View;
514
+ const createAnimated = (_b = def == null ? void 0 : def.createAnimatedComponent) != null ? _b : ns.createAnimatedComponent;
515
+ const hooks = {
516
+ useSharedValue: pick("useSharedValue"),
517
+ useAnimatedStyle: pick("useAnimatedStyle"),
518
+ useAnimatedProps: pick("useAnimatedProps"),
519
+ useReducedMotion: pick("useReducedMotion"),
520
+ withTiming: pick("withTiming"),
521
+ withRepeat: pick("withRepeat"),
522
+ withSequence: pick("withSequence"),
523
+ withDelay: pick("withDelay")
524
+ };
525
+ const fadeIn = pick("FadeIn");
526
+ const fadeOut = pick("FadeOut");
527
+ if (!isComponent(view) || !isFunction(createAnimated)) return void 0;
528
+ if (Object.values(hooks).some((member) => !isFunction(member))) return void 0;
529
+ if (!fadeIn || !fadeOut) return void 0;
530
+ const api2 = {
531
+ present: true,
532
+ View: view,
533
+ createAnimatedComponent: createAnimated,
534
+ ...hooks,
535
+ fadeIn: (durationMs) => fadeIn.duration(durationMs),
536
+ fadeOut: (durationMs) => fadeOut.duration(durationMs)
537
+ };
538
+ return api2;
539
+ };
540
+ var cached2;
541
+ var resolveReanimated = (requireModule = runtimeRequire2) => {
542
+ var _a;
543
+ try {
544
+ if (cached2 === void 0 || requireModule !== runtimeRequire2) {
545
+ const resolved = (_a = fromModule(requireModule("react-native-reanimated"))) != null ? _a : staticApi;
546
+ if (requireModule === runtimeRequire2) cached2 = resolved;
547
+ return resolved;
548
+ }
549
+ return cached2;
550
+ } catch {
551
+ return staticApi;
552
+ }
553
+ };
554
+ var api = () => resolveReanimated();
555
+ var Animated = {
556
+ get View() {
557
+ return api().View;
558
+ },
559
+ createAnimatedComponent: (component) => api().createAnimatedComponent(component)
560
+ };
561
+ var FadeIn = { duration: (durationMs) => api().fadeIn(durationMs) };
562
+ var FadeOut = { duration: (durationMs) => api().fadeOut(durationMs) };
563
+ var useSharedValue = (initial) => api().useSharedValue(initial);
564
+ var useAnimatedStyle = (factory) => api().useAnimatedStyle(factory);
565
+ var useAnimatedProps = (factory) => api().useAnimatedProps(factory);
566
+ var useReducedMotion2 = () => api().useReducedMotion();
567
+ var withTiming = (toValue, config) => api().withTiming(toValue, config);
568
+ var withRepeat = (animation, count, reverse) => api().withRepeat(animation, count, reverse);
569
+ var withSequence = (...animations) => api().withSequence(...animations);
570
+ var withDelay = (ms, animation) => api().withDelay(ms, animation);
377
571
  var SWIPE_MS = 700;
378
572
  var TAP_MS = 320;
379
573
  var SPREAD_MS = 620;
@@ -431,29 +625,29 @@ var GestureHintComponent = ({
431
625
  renderHand
432
626
  }) => {
433
627
  var _a;
434
- const translate = Animated.useSharedValue(0);
435
- const opacity = Animated.useSharedValue(1);
436
- const pulse = Animated.useSharedValue(1);
437
- const spread = Animated.useSharedValue(0);
438
- const reduced = Animated.useReducedMotion();
628
+ const translate = useSharedValue(0);
629
+ const opacity = useSharedValue(1);
630
+ const pulse = useSharedValue(1);
631
+ const spread = useSharedValue(0);
632
+ const reduced = useReducedMotion2();
439
633
  const isSwipe = type === "swipe_up" || type === "swipe_down" || type === "swipe_left" || type === "swipe_right";
440
634
  const isSpread = type === "pinch" || type === "zoom";
441
635
  const isTap = type === "tap" || type === "double_tap";
442
636
  React3.useEffect(() => {
443
637
  if (type === "none" || reduced) return void 0;
444
638
  if (isTap) {
445
- pulse.value = Animated.withRepeat(
446
- Animated.withSequence(
447
- Animated.withTiming(0.82, { duration: TAP_MS }),
448
- Animated.withTiming(1, { duration: TAP_MS })
639
+ pulse.value = withRepeat(
640
+ withSequence(
641
+ withTiming(0.82, { duration: TAP_MS }),
642
+ withTiming(1, { duration: TAP_MS })
449
643
  ),
450
644
  -1,
451
645
  false
452
646
  );
453
- opacity.value = Animated.withRepeat(
454
- Animated.withSequence(
455
- Animated.withTiming(0.55, { duration: TAP_MS }),
456
- Animated.withTiming(1, { duration: TAP_MS })
647
+ opacity.value = withRepeat(
648
+ withSequence(
649
+ withTiming(0.55, { duration: TAP_MS }),
650
+ withTiming(1, { duration: TAP_MS })
457
651
  ),
458
652
  -1,
459
653
  false
@@ -461,48 +655,48 @@ var GestureHintComponent = ({
461
655
  return void 0;
462
656
  }
463
657
  if (isSpread) {
464
- spread.value = Animated.withRepeat(
465
- Animated.withSequence(
466
- Animated.withTiming(size * 0.26, { duration: SPREAD_MS }),
467
- Animated.withTiming(0, { duration: SPREAD_MS })
658
+ spread.value = withRepeat(
659
+ withSequence(
660
+ withTiming(size * 0.26, { duration: SPREAD_MS }),
661
+ withTiming(0, { duration: SPREAD_MS })
468
662
  ),
469
663
  -1,
470
664
  false
471
665
  );
472
666
  return void 0;
473
667
  }
474
- translate.value = Animated.withRepeat(
475
- Animated.withSequence(
476
- Animated.withTiming(0, { duration: 0 }),
477
- Animated.withTiming(-26, { duration: SWIPE_MS }),
478
- Animated.withDelay(140, Animated.withTiming(0, { duration: 0 }))
668
+ translate.value = withRepeat(
669
+ withSequence(
670
+ withTiming(0, { duration: 0 }),
671
+ withTiming(-26, { duration: SWIPE_MS }),
672
+ withDelay(140, withTiming(0, { duration: 0 }))
479
673
  ),
480
674
  -1,
481
675
  false
482
676
  );
483
- opacity.value = Animated.withRepeat(
484
- Animated.withSequence(
485
- Animated.withTiming(1, { duration: SWIPE_MS / 2 }),
486
- Animated.withTiming(0, { duration: SWIPE_MS / 2 }),
487
- Animated.withDelay(140, Animated.withTiming(1, { duration: 0 }))
677
+ opacity.value = withRepeat(
678
+ withSequence(
679
+ withTiming(1, { duration: SWIPE_MS / 2 }),
680
+ withTiming(0, { duration: SWIPE_MS / 2 }),
681
+ withDelay(140, withTiming(1, { duration: 0 }))
488
682
  ),
489
683
  -1,
490
684
  false
491
685
  );
492
686
  return void 0;
493
687
  }, [type, reduced, isTap, isSpread, translate, opacity, pulse, spread, size]);
494
- const swipeAnimatedStyle = Animated.useAnimatedStyle(() => ({
688
+ const swipeAnimatedStyle = useAnimatedStyle(() => ({
495
689
  opacity: opacity.value,
496
690
  transform: [{ translateY: translate.value }]
497
691
  }));
498
- const tapAnimatedStyle = Animated.useAnimatedStyle(() => ({
692
+ const tapAnimatedStyle = useAnimatedStyle(() => ({
499
693
  opacity: opacity.value,
500
694
  transform: [{ scale: pulse.value }]
501
695
  }));
502
- const spreadLeftStyle = Animated.useAnimatedStyle(() => ({
696
+ const spreadLeftStyle = useAnimatedStyle(() => ({
503
697
  transform: [{ translateX: -spread.value }]
504
698
  }));
505
- const spreadRightStyle = Animated.useAnimatedStyle(() => ({
699
+ const spreadRightStyle = useAnimatedStyle(() => ({
506
700
  transform: [{ translateX: spread.value }]
507
701
  }));
508
702
  if (type === "none") return null;
@@ -514,7 +708,7 @@ var GestureHintComponent = ({
514
708
  style: { transform: [{ rotate: (_a = GLYPH_ROTATION[type]) != null ? _a : "0deg" }] },
515
709
  pointerEvents: "none",
516
710
  children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.swipeStack, children: [
517
- /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: swipeAnimatedStyle, pointerEvents: "none", children: customGlyph != null ? customGlyph : /* @__PURE__ */ jsxRuntime.jsx(FingerPair, { size, color }) }),
711
+ /* @__PURE__ */ jsxRuntime.jsx(Animated.View, { style: swipeAnimatedStyle, pointerEvents: "none", children: customGlyph != null ? customGlyph : /* @__PURE__ */ jsxRuntime.jsx(FingerPair, { size, color }) }),
518
712
  /* @__PURE__ */ jsxRuntime.jsx(MotionTrack, { size, color })
519
713
  ] })
520
714
  }
@@ -529,16 +723,16 @@ var GestureHintComponent = ({
529
723
  backgroundColor: color
530
724
  };
531
725
  return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.spreadRow, { gap: size * 0.12 }], pointerEvents: "none", children: [
532
- /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: spreadLeftStyle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: capsule }) }),
533
- /* @__PURE__ */ jsxRuntime.jsx(Animated__default.default.View, { style: spreadRightStyle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: capsule }) })
726
+ /* @__PURE__ */ jsxRuntime.jsx(Animated.View, { style: spreadLeftStyle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: capsule }) }),
727
+ /* @__PURE__ */ jsxRuntime.jsx(Animated.View, { style: spreadRightStyle, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: capsule }) })
534
728
  ] });
535
729
  }
536
730
  const ringSize = size * 0.86;
537
731
  const ringBorder = Math.max(2, size * 0.08);
538
732
  const dotSize = size * 0.32;
539
- 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: [
733
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.tapWrap, { width: size, height: size }], pointerEvents: "none", children: customGlyph ? /* @__PURE__ */ jsxRuntime.jsx(Animated.View, { style: tapAnimatedStyle, pointerEvents: "none", children: customGlyph }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
540
734
  /* @__PURE__ */ jsxRuntime.jsx(
541
- Animated__default.default.View,
735
+ Animated.View,
542
736
  {
543
737
  style: [
544
738
  styles.tapRing,
@@ -605,35 +799,35 @@ var SpotlightOverlayComponent = ({
605
799
  accentTextColor
606
800
  }) => {
607
801
  const { height: screenH } = reactNative.useWindowDimensions();
608
- const reduced = Animated.useReducedMotion();
802
+ const reduced = useReducedMotion2();
609
803
  const theme = useOnboardingTheme();
610
804
  const accent = accentColor != null ? accentColor : theme.colors.primary;
611
805
  const accentText = accentTextColor != null ? accentTextColor : theme.colors.onPrimary;
612
806
  const AnimatedBlurView = React3.useMemo(() => {
613
807
  const BlurView = resolveBlurView();
614
- return BlurView ? Animated__default.default.createAnimatedComponent(BlurView) : null;
808
+ return BlurView ? Animated.createAnimatedComponent(BlurView) : null;
615
809
  }, []);
616
810
  const showGesture = gesture !== "none" && gesture !== "tap" && gesture !== "double_tap";
617
- const intensity = Animated.useSharedValue(0);
618
- const ringScale = Animated.useSharedValue(1);
811
+ const intensity = useSharedValue(0);
812
+ const ringScale = useSharedValue(1);
619
813
  React3.useEffect(() => {
620
- intensity.value = Animated.withTiming(BLUR_INTENSITY, { duration: FADE_MS });
814
+ intensity.value = withTiming(BLUR_INTENSITY, { duration: FADE_MS });
621
815
  }, [intensity]);
622
816
  React3.useEffect(() => {
623
817
  if (reduced) return;
624
- ringScale.value = Animated.withRepeat(
625
- Animated.withSequence(
626
- Animated.withTiming(1.06, { duration: 700 }),
627
- Animated.withTiming(1, { duration: 700 })
818
+ ringScale.value = withRepeat(
819
+ withSequence(
820
+ withTiming(1.06, { duration: 700 }),
821
+ withTiming(1, { duration: 700 })
628
822
  ),
629
823
  -1,
630
824
  true
631
825
  );
632
826
  }, [reduced, ringScale]);
633
- const blurAnimatedProps = Animated.useAnimatedProps(() => ({
827
+ const blurAnimatedProps = useAnimatedProps(() => ({
634
828
  intensity: intensity.value
635
829
  }));
636
- const ringAnimatedStyle = Animated.useAnimatedStyle(() => ({
830
+ const ringAnimatedStyle = useAnimatedStyle(() => ({
637
831
  transform: [{ scale: ringScale.value }]
638
832
  }));
639
833
  const geometry = React3.useMemo(() => {
@@ -655,11 +849,11 @@ var SpotlightOverlayComponent = ({
655
849
  };
656
850
  }, [targetRect, placement, screenH]);
657
851
  return /* @__PURE__ */ jsxRuntime.jsxs(
658
- Animated__default.default.View,
852
+ Animated.View,
659
853
  {
660
854
  style: [reactNative.StyleSheet.absoluteFill, styles2.root],
661
- entering: Animated.FadeIn.duration(FADE_MS),
662
- exiting: Animated.FadeOut.duration(FADE_MS),
855
+ entering: FadeIn.duration(FADE_MS),
856
+ exiting: FadeOut.duration(FADE_MS),
663
857
  children: [
664
858
  AnimatedBlurView ? /* @__PURE__ */ jsxRuntime.jsx(
665
859
  AnimatedBlurView,
@@ -672,7 +866,7 @@ var SpotlightOverlayComponent = ({
672
866
  // `expo-blur` absent → a plain dimmed scrim stands in for the frost. Same dark backdrop
673
867
  // the tour reads against, so the ring, tooltip and gestures behave identically.
674
868
  /* @__PURE__ */ jsxRuntime.jsx(
675
- Animated__default.default.View,
869
+ Animated.View,
676
870
  {
677
871
  style: [reactNative.StyleSheet.absoluteFill, styles2.scrim],
678
872
  pointerEvents: "none"
@@ -689,7 +883,7 @@ var SpotlightOverlayComponent = ({
689
883
  }
690
884
  ),
691
885
  geometry && /* @__PURE__ */ jsxRuntime.jsx(
692
- Animated__default.default.View,
886
+ Animated.View,
693
887
  {
694
888
  style: [
695
889
  styles2.ring,