@wireai/activation 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -1
- package/CHANGELOG.md +116 -3
- package/README.md +82 -0
- package/dist/analytics/index.d.mts +2 -2
- package/dist/analytics/index.d.ts +2 -2
- package/dist/analytics/index.js +61 -2
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +61 -2
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/{currentSession-_GynvhzT.d.mts → currentSession-ClkLjcJ0.d.mts} +298 -13
- package/dist/{currentSession-D7zabMXK.d.ts → currentSession-DOVZEWJl.d.ts} +298 -13
- package/dist/index.d.mts +195 -4
- package/dist/index.d.ts +195 -4
- package/dist/index.js +909 -340
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +693 -145
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.js +12 -1
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +12 -1
- package/dist/reviews/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/OnboardingFlow.tsx +131 -0
- package/src/WireOnboarding.tsx +63 -2
- package/src/analytics/analyticsEvent.ts +16 -1
- package/src/analytics/eventQueue.ts +2 -0
- package/src/analytics/reportClientEvent.ts +68 -12
- package/src/cards/PermissionCard.tsx +438 -0
- package/src/cards/index.ts +7 -0
- package/src/illustrations/defaultIllustrations.tsx +44 -3
- package/src/index.ts +38 -0
- package/src/permissions/index.ts +64 -0
- package/src/permissions/permissionCopy.ts +87 -0
- package/src/permissions/permissionEvents.ts +76 -0
- package/src/permissions/permissionMemory.ts +88 -0
- package/src/permissions/placement.ts +88 -0
- package/src/permissions/types.ts +131 -0
- package/src/session/persistedSession.ts +10 -3
- package/src/types.ts +66 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var reactNative = require('react-native');
|
|
4
|
-
var
|
|
4
|
+
var React19 = require('react');
|
|
5
5
|
var wireaiRn = require('wireai-rn');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var reactNativeSafeAreaContext = require('react-native-safe-area-context');
|
|
@@ -9,7 +9,7 @@ var zod = require('zod');
|
|
|
9
9
|
|
|
10
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var React19__default = /*#__PURE__*/_interopDefault(React19);
|
|
13
13
|
|
|
14
14
|
var __defProp = Object.defineProperty;
|
|
15
15
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -464,33 +464,33 @@ var mergeTheme = (override) => {
|
|
|
464
464
|
button: { ...defaultOnboardingTheme.button, ...override.button }
|
|
465
465
|
};
|
|
466
466
|
};
|
|
467
|
-
var OnboardingThemeContext =
|
|
467
|
+
var OnboardingThemeContext = React19.createContext(null);
|
|
468
468
|
var OnboardingThemeProvider = ({
|
|
469
469
|
theme,
|
|
470
470
|
children
|
|
471
471
|
}) => {
|
|
472
|
-
const resolved =
|
|
472
|
+
const resolved = React19.useMemo(() => mergeTheme(theme), [theme]);
|
|
473
473
|
return /* @__PURE__ */ jsxRuntime.jsx(OnboardingThemeContext.Provider, { value: resolved, children });
|
|
474
474
|
};
|
|
475
475
|
var useOnboardingTheme = () => {
|
|
476
|
-
const ctx =
|
|
476
|
+
const ctx = React19.useContext(OnboardingThemeContext);
|
|
477
477
|
return ctx != null ? ctx : mergeTheme();
|
|
478
478
|
};
|
|
479
479
|
var EMPTY_REGISTRY = {};
|
|
480
|
-
var IllustrationContext =
|
|
480
|
+
var IllustrationContext = React19.createContext(EMPTY_REGISTRY);
|
|
481
481
|
var IllustrationProvider = ({
|
|
482
482
|
registry,
|
|
483
483
|
children
|
|
484
484
|
}) => {
|
|
485
|
-
const value =
|
|
485
|
+
const value = React19.useMemo(() => registry != null ? registry : EMPTY_REGISTRY, [registry]);
|
|
486
486
|
return /* @__PURE__ */ jsxRuntime.jsx(IllustrationContext.Provider, { value, children });
|
|
487
487
|
};
|
|
488
488
|
var useIllustration = (name2) => {
|
|
489
|
-
const registry =
|
|
489
|
+
const registry = React19.useContext(IllustrationContext);
|
|
490
490
|
if (!name2) return void 0;
|
|
491
491
|
return registry[name2];
|
|
492
492
|
};
|
|
493
|
-
var
|
|
493
|
+
var Disc = ({ children }) => {
|
|
494
494
|
const t = useOnboardingTheme();
|
|
495
495
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
496
496
|
reactNative.View,
|
|
@@ -499,11 +499,23 @@ var Glyph = ({ children }) => {
|
|
|
499
499
|
styles.disc,
|
|
500
500
|
{ backgroundColor: t.colors.primarySoft, borderRadius: t.radius.full }
|
|
501
501
|
],
|
|
502
|
-
children
|
|
502
|
+
children
|
|
503
503
|
}
|
|
504
504
|
);
|
|
505
505
|
};
|
|
506
|
+
var Glyph = ({ children }) => {
|
|
507
|
+
const t = useOnboardingTheme();
|
|
508
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Disc, { children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.glyphText, { color: t.colors.primary }], allowFontScaling: false, children }) });
|
|
509
|
+
};
|
|
506
510
|
var MomentumGlyph = () => /* @__PURE__ */ jsxRuntime.jsx(Glyph, { children: "\u2197" });
|
|
511
|
+
var NotificationsGlyph = () => {
|
|
512
|
+
const t = useOnboardingTheme();
|
|
513
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Disc, { children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.bell, children: [
|
|
514
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.bellBody, { backgroundColor: t.colors.primary }] }),
|
|
515
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.bellRim, { backgroundColor: t.colors.primary }] }),
|
|
516
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.bellClapper, { backgroundColor: t.colors.primary }] })
|
|
517
|
+
] }) });
|
|
518
|
+
};
|
|
507
519
|
var BeforeAfterGlyph = () => {
|
|
508
520
|
const t = useOnboardingTheme();
|
|
509
521
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles.row, children: [
|
|
@@ -530,7 +542,8 @@ var BeforeAfterGlyph = () => {
|
|
|
530
542
|
};
|
|
531
543
|
var defaultIllustrations = {
|
|
532
544
|
momentum: /* @__PURE__ */ jsxRuntime.jsx(MomentumGlyph, {}),
|
|
533
|
-
"before-after": /* @__PURE__ */ jsxRuntime.jsx(BeforeAfterGlyph, {})
|
|
545
|
+
"before-after": /* @__PURE__ */ jsxRuntime.jsx(BeforeAfterGlyph, {}),
|
|
546
|
+
notifications: /* @__PURE__ */ jsxRuntime.jsx(NotificationsGlyph, {})
|
|
534
547
|
};
|
|
535
548
|
var styles = reactNative.StyleSheet.create({
|
|
536
549
|
disc: {
|
|
@@ -558,19 +571,24 @@ var styles = reactNative.StyleSheet.create({
|
|
|
558
571
|
arrow: {
|
|
559
572
|
fontSize: 28,
|
|
560
573
|
fontWeight: "700"
|
|
561
|
-
}
|
|
574
|
+
},
|
|
575
|
+
// The bell: a domed body over a wider rim, with the clapper hanging below it.
|
|
576
|
+
bell: { alignItems: "center", justifyContent: "center" },
|
|
577
|
+
bellBody: { width: 34, height: 30, borderTopLeftRadius: 17, borderTopRightRadius: 17 },
|
|
578
|
+
bellRim: { width: 44, height: 5, borderRadius: 3, marginTop: 2 },
|
|
579
|
+
bellClapper: { width: 9, height: 9, borderRadius: 5, marginTop: 3 }
|
|
562
580
|
});
|
|
563
581
|
var EMPTY_REGISTRY2 = {};
|
|
564
|
-
var IconContext =
|
|
582
|
+
var IconContext = React19.createContext(EMPTY_REGISTRY2);
|
|
565
583
|
var IconRegistryProvider = ({
|
|
566
584
|
registry,
|
|
567
585
|
children
|
|
568
586
|
}) => {
|
|
569
|
-
const value =
|
|
587
|
+
const value = React19.useMemo(() => registry != null ? registry : EMPTY_REGISTRY2, [registry]);
|
|
570
588
|
return /* @__PURE__ */ jsxRuntime.jsx(IconContext.Provider, { value, children });
|
|
571
589
|
};
|
|
572
590
|
var useHostIcon = (name2) => {
|
|
573
|
-
const registry =
|
|
591
|
+
const registry = React19.useContext(IconContext);
|
|
574
592
|
if (!name2) return void 0;
|
|
575
593
|
if (!Object.prototype.hasOwnProperty.call(registry, name2)) return void 0;
|
|
576
594
|
return registry[name2];
|
|
@@ -729,8 +747,8 @@ var stateChangeDuration = (reduced, durationMs) => reduced ? 0 : durationMs;
|
|
|
729
747
|
var loopEnabled = (reduced) => !reduced;
|
|
730
748
|
var lastKnown = false;
|
|
731
749
|
var useReducedMotion = () => {
|
|
732
|
-
const [reduced, setReduced] =
|
|
733
|
-
|
|
750
|
+
const [reduced, setReduced] = React19.useState(lastKnown);
|
|
751
|
+
React19.useEffect(() => {
|
|
734
752
|
let mounted = true;
|
|
735
753
|
reactNative.AccessibilityInfo.isReduceMotionEnabled().then((value) => {
|
|
736
754
|
lastKnown = value;
|
|
@@ -752,8 +770,8 @@ var ROTATION_MS = 1800;
|
|
|
752
770
|
var _AnimatedSparkle = ({ size = 30, color, variant = "spin" }) => {
|
|
753
771
|
const t = useOnboardingTheme();
|
|
754
772
|
const reduced = useReducedMotion();
|
|
755
|
-
const progress =
|
|
756
|
-
|
|
773
|
+
const progress = React19.useRef(new reactNative.Animated.Value(0)).current;
|
|
774
|
+
React19.useEffect(() => {
|
|
757
775
|
if (!loopEnabled(reduced)) {
|
|
758
776
|
progress.setValue(0);
|
|
759
777
|
return;
|
|
@@ -808,7 +826,7 @@ var _AnimatedSparkle = ({ size = 30, color, variant = "spin" }) => {
|
|
|
808
826
|
}
|
|
809
827
|
) });
|
|
810
828
|
};
|
|
811
|
-
var AnimatedSparkle =
|
|
829
|
+
var AnimatedSparkle = React19__default.default.memo(_AnimatedSparkle);
|
|
812
830
|
var styles2 = reactNative.StyleSheet.create({
|
|
813
831
|
box: { alignItems: "center", justifyContent: "center" },
|
|
814
832
|
glyph: {
|
|
@@ -820,8 +838,8 @@ var styles2 = reactNative.StyleSheet.create({
|
|
|
820
838
|
var STAGE_SIZE = 96;
|
|
821
839
|
var ORBIT_DOT = 9;
|
|
822
840
|
var OrbitDot = ({ color, reduced }) => {
|
|
823
|
-
const spin =
|
|
824
|
-
|
|
841
|
+
const spin = React19.useRef(new reactNative.Animated.Value(0)).current;
|
|
842
|
+
React19.useEffect(() => {
|
|
825
843
|
if (!loopEnabled(reduced)) return;
|
|
826
844
|
const loop = reactNative.Animated.loop(
|
|
827
845
|
reactNative.Animated.timing(spin, {
|
|
@@ -844,8 +862,8 @@ var SkeletonLine = ({
|
|
|
844
862
|
color,
|
|
845
863
|
reduced
|
|
846
864
|
}) => {
|
|
847
|
-
const pulse =
|
|
848
|
-
|
|
865
|
+
const pulse = React19.useRef(new reactNative.Animated.Value(1)).current;
|
|
866
|
+
React19.useEffect(() => {
|
|
849
867
|
if (!loopEnabled(reduced)) return;
|
|
850
868
|
const loop = reactNative.Animated.loop(
|
|
851
869
|
reactNative.Animated.sequence([
|
|
@@ -880,8 +898,8 @@ var _LoadingBlock = ({
|
|
|
880
898
|
}) => {
|
|
881
899
|
const t = useOnboardingTheme();
|
|
882
900
|
const reduced = useReducedMotion();
|
|
883
|
-
const [showSkeleton, setShowSkeleton] =
|
|
884
|
-
|
|
901
|
+
const [showSkeleton, setShowSkeleton] = React19.useState(false);
|
|
902
|
+
React19.useEffect(() => {
|
|
885
903
|
const timer = setTimeout(() => setShowSkeleton(true), SKELETON_DELAY_MS);
|
|
886
904
|
return () => clearTimeout(timer);
|
|
887
905
|
}, []);
|
|
@@ -911,7 +929,7 @@ var _LoadingBlock = ({
|
|
|
911
929
|
)
|
|
912
930
|
] });
|
|
913
931
|
};
|
|
914
|
-
var LoadingBlock =
|
|
932
|
+
var LoadingBlock = React19__default.default.memo(_LoadingBlock);
|
|
915
933
|
var styles3 = reactNative.StyleSheet.create({
|
|
916
934
|
center: { flex: 1, alignItems: "center", justifyContent: "center" },
|
|
917
935
|
// Absolutely-positioned label column, pinned just under the centered stage: its top
|
|
@@ -956,7 +974,7 @@ var _LoadingScreen = ({ title, hint }) => {
|
|
|
956
974
|
}
|
|
957
975
|
);
|
|
958
976
|
};
|
|
959
|
-
var LoadingScreen =
|
|
977
|
+
var LoadingScreen = React19__default.default.memo(_LoadingScreen);
|
|
960
978
|
var styles4 = reactNative.StyleSheet.create({
|
|
961
979
|
flex: { flex: 1 }
|
|
962
980
|
});
|
|
@@ -975,8 +993,8 @@ var targetFor = (step, complete, approxScreens) => {
|
|
|
975
993
|
var _StepProgress = ({ step, complete, approxScreens }) => {
|
|
976
994
|
const t = useOnboardingTheme();
|
|
977
995
|
const reduced = useReducedMotion();
|
|
978
|
-
const fill =
|
|
979
|
-
|
|
996
|
+
const fill = React19.useRef(new reactNative.Animated.Value(targetFor(step, complete, approxScreens))).current;
|
|
997
|
+
React19.useEffect(() => {
|
|
980
998
|
reactNative.Animated.timing(fill, {
|
|
981
999
|
toValue: targetFor(step, complete, approxScreens),
|
|
982
1000
|
duration: scaledMs(stateChangeDuration(reduced, PROGRESS_MS)),
|
|
@@ -996,7 +1014,7 @@ var _StepProgress = ({ step, complete, approxScreens }) => {
|
|
|
996
1014
|
}
|
|
997
1015
|
) });
|
|
998
1016
|
};
|
|
999
|
-
var StepProgress =
|
|
1017
|
+
var StepProgress = React19__default.default.memo(_StepProgress);
|
|
1000
1018
|
var styles5 = reactNative.StyleSheet.create({
|
|
1001
1019
|
track: { height: 6, width: "100%", overflow: "hidden" },
|
|
1002
1020
|
fill: { height: 6 }
|
|
@@ -1012,31 +1030,31 @@ var _OnboardingScaffold = ({
|
|
|
1012
1030
|
children
|
|
1013
1031
|
}) => {
|
|
1014
1032
|
const t = useOnboardingTheme();
|
|
1015
|
-
const
|
|
1033
|
+
const styles18 = React19.useMemo(() => makeStyles(t), [t]);
|
|
1016
1034
|
const hit = { top: 12, bottom: 12, left: 12, right: 12 };
|
|
1017
1035
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1018
1036
|
reactNativeSafeAreaContext.SafeAreaView,
|
|
1019
1037
|
{
|
|
1020
1038
|
edges: ["top", "bottom"],
|
|
1021
|
-
style: [
|
|
1039
|
+
style: [styles18.flex, { backgroundColor: t.colors.background }],
|
|
1022
1040
|
children: [
|
|
1023
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1024
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1025
|
-
onSkip ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onSkip, hitSlop: hit, style:
|
|
1041
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles18.header, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }], children: [
|
|
1042
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles18.progressWrap, children: /* @__PURE__ */ jsxRuntime.jsx(StepProgress, { step, complete, approxScreens }) }),
|
|
1043
|
+
onSkip ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onSkip, hitSlop: hit, style: styles18.skip, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: skipLabel }) }) : null
|
|
1026
1044
|
] }),
|
|
1027
1045
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1028
1046
|
reactNative.View,
|
|
1029
1047
|
{
|
|
1030
|
-
style: [
|
|
1048
|
+
style: [styles18.body, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }],
|
|
1031
1049
|
children
|
|
1032
1050
|
}
|
|
1033
1051
|
),
|
|
1034
|
-
onBack ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
1052
|
+
onBack ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles18.footer, { paddingHorizontal: t.spacing.md, paddingBottom: t.spacing.sm }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onBack, hitSlop: hit, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: backLabel }) }) }) : null
|
|
1035
1053
|
]
|
|
1036
1054
|
}
|
|
1037
1055
|
);
|
|
1038
1056
|
};
|
|
1039
|
-
var OnboardingScaffold =
|
|
1057
|
+
var OnboardingScaffold = React19__default.default.memo(_OnboardingScaffold);
|
|
1040
1058
|
function makeStyles(t) {
|
|
1041
1059
|
return reactNative.StyleSheet.create({
|
|
1042
1060
|
flex: { flex: 1 },
|
|
@@ -1057,8 +1075,8 @@ var _Button = ({
|
|
|
1057
1075
|
const t = useOnboardingTheme();
|
|
1058
1076
|
const reduced = useReducedMotion();
|
|
1059
1077
|
const isPrimary = variant === "primary";
|
|
1060
|
-
const pressT =
|
|
1061
|
-
const pressTo =
|
|
1078
|
+
const pressT = React19.useRef(new reactNative.Animated.Value(0)).current;
|
|
1079
|
+
const pressTo = React19.useCallback(
|
|
1062
1080
|
(to) => {
|
|
1063
1081
|
if (reduced) {
|
|
1064
1082
|
reactNative.Animated.timing(pressT, {
|
|
@@ -1077,16 +1095,16 @@ var _Button = ({
|
|
|
1077
1095
|
},
|
|
1078
1096
|
[pressT, reduced]
|
|
1079
1097
|
);
|
|
1080
|
-
const lastPress =
|
|
1081
|
-
const handlePress =
|
|
1098
|
+
const lastPress = React19.useRef(0);
|
|
1099
|
+
const handlePress = React19.useCallback(() => {
|
|
1082
1100
|
if (!onPress) return;
|
|
1083
1101
|
const now = Date.now();
|
|
1084
1102
|
if (now - lastPress.current < 500) return;
|
|
1085
1103
|
lastPress.current = now;
|
|
1086
1104
|
onPress();
|
|
1087
1105
|
}, [onPress]);
|
|
1088
|
-
const handlePressIn =
|
|
1089
|
-
const handlePressOut =
|
|
1106
|
+
const handlePressIn = React19.useCallback(() => pressTo(1), [pressTo]);
|
|
1107
|
+
const handlePressOut = React19.useCallback(() => pressTo(0), [pressTo]);
|
|
1090
1108
|
const scale = pressT.interpolate({
|
|
1091
1109
|
inputRange: [0, 1],
|
|
1092
1110
|
outputRange: [1, reduced ? 1 : BUTTON_PRESS_SCALE]
|
|
@@ -1137,7 +1155,7 @@ var _Button = ({
|
|
|
1137
1155
|
}
|
|
1138
1156
|
);
|
|
1139
1157
|
};
|
|
1140
|
-
var Button =
|
|
1158
|
+
var Button = React19__default.default.memo(_Button);
|
|
1141
1159
|
var styles6 = reactNative.StyleSheet.create({
|
|
1142
1160
|
base: { alignItems: "center", justifyContent: "center" },
|
|
1143
1161
|
fill: { width: "100%" }
|
|
@@ -1155,7 +1173,7 @@ var _ErrorBlock = ({
|
|
|
1155
1173
|
onRetry ? /* @__PURE__ */ jsxRuntime.jsx(Button, { title: retryLabel, onPress: onRetry, variant: "outline" }) : null
|
|
1156
1174
|
] });
|
|
1157
1175
|
};
|
|
1158
|
-
var ErrorBlock =
|
|
1176
|
+
var ErrorBlock = React19__default.default.memo(_ErrorBlock);
|
|
1159
1177
|
var styles7 = reactNative.StyleSheet.create({
|
|
1160
1178
|
center: { flex: 1, alignItems: "center", justifyContent: "center" }
|
|
1161
1179
|
});
|
|
@@ -1168,10 +1186,10 @@ var _CardLayout = ({
|
|
|
1168
1186
|
titleNode
|
|
1169
1187
|
}) => {
|
|
1170
1188
|
const t = useOnboardingTheme();
|
|
1171
|
-
const
|
|
1189
|
+
const styles18 = React19.useMemo(() => makeStyles2(t), [t]);
|
|
1172
1190
|
const hasHeader = !!title || !!subtitle || !!titleNode;
|
|
1173
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.KeyboardAvoidingView, { style:
|
|
1174
|
-
hasHeader ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1191
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.KeyboardAvoidingView, { style: styles18.fill, behavior: "padding", children: [
|
|
1192
|
+
hasHeader ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles18.header, children: [
|
|
1175
1193
|
titleNode != null ? titleNode : title ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [labelStyle(t.fonts), { color: t.colors.text }], children: title }) : null,
|
|
1176
1194
|
subtitle ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1177
1195
|
reactNative.Text,
|
|
@@ -1187,10 +1205,10 @@ var _CardLayout = ({
|
|
|
1187
1205
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1188
1206
|
reactNative.ScrollView,
|
|
1189
1207
|
{
|
|
1190
|
-
style:
|
|
1208
|
+
style: styles18.fill,
|
|
1191
1209
|
contentContainerStyle: [
|
|
1192
|
-
|
|
1193
|
-
align === "center" &&
|
|
1210
|
+
styles18.scrollContent,
|
|
1211
|
+
align === "center" && styles18.center
|
|
1194
1212
|
],
|
|
1195
1213
|
keyboardShouldPersistTaps: "handled",
|
|
1196
1214
|
keyboardDismissMode: "on-drag",
|
|
@@ -1198,10 +1216,10 @@ var _CardLayout = ({
|
|
|
1198
1216
|
children
|
|
1199
1217
|
}
|
|
1200
1218
|
),
|
|
1201
|
-
footer ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1219
|
+
footer ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles18.footer, children: footer }) : null
|
|
1202
1220
|
] });
|
|
1203
1221
|
};
|
|
1204
|
-
var CardLayout =
|
|
1222
|
+
var CardLayout = React19__default.default.memo(_CardLayout);
|
|
1205
1223
|
function makeStyles2(t) {
|
|
1206
1224
|
return reactNative.StyleSheet.create({
|
|
1207
1225
|
fill: { flex: 1 },
|
|
@@ -1224,12 +1242,12 @@ var _CompletionView = ({
|
|
|
1224
1242
|
}) => {
|
|
1225
1243
|
const t = useOnboardingTheme();
|
|
1226
1244
|
const reduced = useReducedMotion();
|
|
1227
|
-
const [submitted, setSubmitted] =
|
|
1228
|
-
const pop =
|
|
1229
|
-
const burst =
|
|
1230
|
-
const titleT =
|
|
1231
|
-
const messageT =
|
|
1232
|
-
|
|
1245
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
1246
|
+
const pop = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
1247
|
+
const burst = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
1248
|
+
const titleT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
1249
|
+
const messageT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
1250
|
+
React19.useEffect(() => {
|
|
1233
1251
|
if (reduced) {
|
|
1234
1252
|
pop.setValue(1);
|
|
1235
1253
|
burst.setValue(1);
|
|
@@ -1264,7 +1282,7 @@ var _CompletionView = ({
|
|
|
1264
1282
|
anims.forEach((a) => a.start());
|
|
1265
1283
|
return () => anims.forEach((a) => a.stop());
|
|
1266
1284
|
}, [reduced, pop, burst, titleT, messageT]);
|
|
1267
|
-
const handlePress =
|
|
1285
|
+
const handlePress = React19.useCallback(() => {
|
|
1268
1286
|
if (submitted) return;
|
|
1269
1287
|
setSubmitted(true);
|
|
1270
1288
|
onContinue();
|
|
@@ -1326,7 +1344,7 @@ var _CompletionView = ({
|
|
|
1326
1344
|
}
|
|
1327
1345
|
);
|
|
1328
1346
|
};
|
|
1329
|
-
var CompletionView =
|
|
1347
|
+
var CompletionView = React19__default.default.memo(_CompletionView);
|
|
1330
1348
|
var styles8 = reactNative.StyleSheet.create({
|
|
1331
1349
|
center: { width: "100%", alignItems: "center", justifyContent: "center" },
|
|
1332
1350
|
badgeStage: {
|
|
@@ -1348,13 +1366,13 @@ var _CardHandoff = ({
|
|
|
1348
1366
|
children
|
|
1349
1367
|
}) => {
|
|
1350
1368
|
const reduced = useReducedMotion();
|
|
1351
|
-
const [leaving, setLeaving] =
|
|
1352
|
-
const enterT =
|
|
1353
|
-
const exitT =
|
|
1354
|
-
const prev =
|
|
1355
|
-
const running =
|
|
1356
|
-
const mounted =
|
|
1357
|
-
|
|
1369
|
+
const [leaving, setLeaving] = React19.useState(null);
|
|
1370
|
+
const enterT = React19.useRef(new reactNative.Animated.Value(0)).current;
|
|
1371
|
+
const exitT = React19.useRef(new reactNative.Animated.Value(0)).current;
|
|
1372
|
+
const prev = React19.useRef({ key: transitionKey, node: children, variant });
|
|
1373
|
+
const running = React19.useRef({});
|
|
1374
|
+
const mounted = React19.useRef(false);
|
|
1375
|
+
React19.useEffect(() => {
|
|
1358
1376
|
var _a2, _b;
|
|
1359
1377
|
const last = prev.current;
|
|
1360
1378
|
prev.current = { key: transitionKey, node: children, variant };
|
|
@@ -1387,7 +1405,7 @@ var _CardHandoff = ({
|
|
|
1387
1405
|
);
|
|
1388
1406
|
running.current.enter = enter;
|
|
1389
1407
|
});
|
|
1390
|
-
|
|
1408
|
+
React19.useEffect(
|
|
1391
1409
|
() => () => {
|
|
1392
1410
|
var _a2, _b;
|
|
1393
1411
|
(_a2 = running.current.enter) == null ? void 0 : _a2.stop();
|
|
@@ -1456,7 +1474,7 @@ var transformFor = (variant, t, reduced, layer, travel) => {
|
|
|
1456
1474
|
}
|
|
1457
1475
|
];
|
|
1458
1476
|
};
|
|
1459
|
-
var CardHandoff =
|
|
1477
|
+
var CardHandoff = React19__default.default.memo(_CardHandoff);
|
|
1460
1478
|
var styles9 = reactNative.StyleSheet.create({
|
|
1461
1479
|
fill: { flex: 1 }
|
|
1462
1480
|
});
|
|
@@ -1509,13 +1527,24 @@ var readProgress = (response) => {
|
|
|
1509
1527
|
|
|
1510
1528
|
// src/analytics/reportClientEvent.ts
|
|
1511
1529
|
var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1530
|
+
var toWireEvents = (events) => events.map((event) => {
|
|
1531
|
+
if (typeof event.ts !== "number") return event;
|
|
1532
|
+
const { ts, ...rest } = event;
|
|
1533
|
+
if (!Number.isFinite(ts)) return rest;
|
|
1534
|
+
try {
|
|
1535
|
+
return { ...rest, ts: new Date(ts).toISOString() };
|
|
1536
|
+
} catch {
|
|
1537
|
+
return rest;
|
|
1538
|
+
}
|
|
1539
|
+
});
|
|
1512
1540
|
var buildEventsRequest = (target, events) => {
|
|
1513
1541
|
if (!(target == null ? void 0 : target.serverUrl) || events.length === 0) return null;
|
|
1514
1542
|
try {
|
|
1515
1543
|
const url = `${target.serverUrl.replace(/\/$/, "")}/v1/events`;
|
|
1516
1544
|
const headers = { "Content-Type": "application/json" };
|
|
1517
1545
|
if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
|
|
1518
|
-
|
|
1546
|
+
const body = JSON.stringify({ events: toWireEvents(events) });
|
|
1547
|
+
return { url, init: { method: "POST", headers, body } };
|
|
1519
1548
|
} catch {
|
|
1520
1549
|
return null;
|
|
1521
1550
|
}
|
|
@@ -1527,7 +1556,13 @@ var readEventsAck = async (res) => {
|
|
|
1527
1556
|
const body = await Promise.resolve(json.call(res));
|
|
1528
1557
|
const skipped = body == null ? void 0 : body.skipped;
|
|
1529
1558
|
if (typeof skipped !== "number" || !Number.isFinite(skipped)) return void 0;
|
|
1530
|
-
const reasons = Array.isArray(body == null ? void 0 : body.errors) ? body.errors.map((e) =>
|
|
1559
|
+
const reasons = Array.isArray(body == null ? void 0 : body.errors) ? body.errors.map((e) => {
|
|
1560
|
+
const entry = e;
|
|
1561
|
+
const reason = entry == null ? void 0 : entry.reason;
|
|
1562
|
+
if (typeof reason !== "string") return void 0;
|
|
1563
|
+
const field = entry == null ? void 0 : entry.field;
|
|
1564
|
+
return typeof field === "string" && field.length > 0 ? `${reason} (field: ${field})` : reason;
|
|
1565
|
+
}).filter((r) => typeof r === "string") : [];
|
|
1531
1566
|
return { written: typeof (body == null ? void 0 : body.written) === "number" ? body.written : void 0, skipped, reasons };
|
|
1532
1567
|
} catch {
|
|
1533
1568
|
return void 0;
|
|
@@ -1597,6 +1632,382 @@ var sendPreview = (target, { sessionId, userMessage }) => {
|
|
|
1597
1632
|
} catch {
|
|
1598
1633
|
}
|
|
1599
1634
|
};
|
|
1635
|
+
|
|
1636
|
+
// src/permissions/permissionEvents.ts
|
|
1637
|
+
var WIRE_PERMISSION_EVENTS = {
|
|
1638
|
+
/** The priming screen became visible. The denominator for every rate below. */
|
|
1639
|
+
screenShown: "wire_permission_screen_shown",
|
|
1640
|
+
/** The user tapped the primary, so the OS dialog is about to open. The rationale worked. */
|
|
1641
|
+
primerAccepted: "wire_permission_primer_accepted",
|
|
1642
|
+
/** The OS granted it. */
|
|
1643
|
+
granted: "wire_permission_granted",
|
|
1644
|
+
/** The OS refused it (a permanently blocked answer reports here too, with `status: "blocked"`). */
|
|
1645
|
+
denied: "wire_permission_denied",
|
|
1646
|
+
/** The user took the secondary. The one native prompt was NOT spent. */
|
|
1647
|
+
skipped: "wire_permission_skipped",
|
|
1648
|
+
/** A blocked user was redirected to the OS settings page. */
|
|
1649
|
+
settingsOpened: "wire_permission_settings_opened"
|
|
1650
|
+
};
|
|
1651
|
+
var permissionEventName = (stage) => {
|
|
1652
|
+
switch (stage) {
|
|
1653
|
+
case "shown":
|
|
1654
|
+
return WIRE_PERMISSION_EVENTS.screenShown;
|
|
1655
|
+
case "accepted":
|
|
1656
|
+
return WIRE_PERMISSION_EVENTS.primerAccepted;
|
|
1657
|
+
case "granted":
|
|
1658
|
+
return WIRE_PERMISSION_EVENTS.granted;
|
|
1659
|
+
case "denied":
|
|
1660
|
+
return WIRE_PERMISSION_EVENTS.denied;
|
|
1661
|
+
case "skipped":
|
|
1662
|
+
return WIRE_PERMISSION_EVENTS.skipped;
|
|
1663
|
+
case "settings":
|
|
1664
|
+
return WIRE_PERMISSION_EVENTS.settingsOpened;
|
|
1665
|
+
default: {
|
|
1666
|
+
const _exhaustive = stage;
|
|
1667
|
+
return _exhaustive;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
var permissionEventProps = (permission, status) => status ? { permission, status } : { permission };
|
|
1672
|
+
var normalizePermissionStatus = (value) => value === "granted" || value === "denied" || value === "blocked" ? value : "denied";
|
|
1673
|
+
|
|
1674
|
+
// src/haptics/haptics.ts
|
|
1675
|
+
var play = async (tone) => {
|
|
1676
|
+
try {
|
|
1677
|
+
const mod = await import('expo-haptics');
|
|
1678
|
+
if (!mod) return false;
|
|
1679
|
+
if (tone === "selection") ;
|
|
1680
|
+
if (tone === "light") ;
|
|
1681
|
+
await mod.notificationAsync(mod.NotificationFeedbackType.Success);
|
|
1682
|
+
return true;
|
|
1683
|
+
} catch {
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
var playHaptic = (tone) => {
|
|
1688
|
+
void play(tone);
|
|
1689
|
+
};
|
|
1690
|
+
|
|
1691
|
+
// src/utils/warnInDev.ts
|
|
1692
|
+
var warnInDev = (message) => {
|
|
1693
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
1694
|
+
console.warn(message);
|
|
1695
|
+
return true;
|
|
1696
|
+
}
|
|
1697
|
+
return false;
|
|
1698
|
+
};
|
|
1699
|
+
var easeWire4 = reactNative.Easing.bezier(...WIRE_BEZIER);
|
|
1700
|
+
var RISE_PX = 10;
|
|
1701
|
+
var PERMISSION_CARD_NAME = "PermissionCard";
|
|
1702
|
+
var REQUEST_WATCHDOG_MS = 9e4;
|
|
1703
|
+
var schema = zod.z.object({
|
|
1704
|
+
permission: zod.z.string().describe("Which OS permission this screen primes, e.g. 'notifications'"),
|
|
1705
|
+
title: zod.z.string().describe("Headline for the ask"),
|
|
1706
|
+
message: zod.z.string().describe("Why the app needs it, in the user's terms"),
|
|
1707
|
+
primaryLabel: zod.z.string().describe("Primary button, the only control that can open the OS dialog"),
|
|
1708
|
+
secondaryLabel: zod.z.string().describe("Secondary button, advances without spending the OS prompt"),
|
|
1709
|
+
blockedTitle: zod.z.string().optional().describe("Headline once the permission is permanently refused"),
|
|
1710
|
+
blockedMessage: zod.z.string().optional().describe("Rationale for the settings route"),
|
|
1711
|
+
settingsLabel: zod.z.string().optional().describe("Primary button label on the blocked route"),
|
|
1712
|
+
continueLabel: zod.z.string().optional().describe("Primary button label when there is nothing to ask"),
|
|
1713
|
+
illustration: zod.z.string().optional().describe("Name of an app-provided illustration (defaults to the permission name)")
|
|
1714
|
+
});
|
|
1715
|
+
var _PermissionCard = ({
|
|
1716
|
+
permission,
|
|
1717
|
+
title,
|
|
1718
|
+
message,
|
|
1719
|
+
primaryLabel,
|
|
1720
|
+
secondaryLabel,
|
|
1721
|
+
blockedTitle,
|
|
1722
|
+
blockedMessage,
|
|
1723
|
+
settingsLabel,
|
|
1724
|
+
continueLabel,
|
|
1725
|
+
illustration,
|
|
1726
|
+
request,
|
|
1727
|
+
getStatus,
|
|
1728
|
+
openSettings,
|
|
1729
|
+
onStage,
|
|
1730
|
+
onSettled
|
|
1731
|
+
}) => {
|
|
1732
|
+
const t = useOnboardingTheme();
|
|
1733
|
+
const reduced = useReducedMotion();
|
|
1734
|
+
const art = useIllustration(illustration != null ? illustration : permission);
|
|
1735
|
+
const [status, setStatus] = React19.useState(void 0);
|
|
1736
|
+
const [busy, setBusy] = React19.useState(false);
|
|
1737
|
+
const settledRef = React19.useRef(false);
|
|
1738
|
+
const acceptedRef = React19.useRef(false);
|
|
1739
|
+
const watchdogRef = React19.useRef(null);
|
|
1740
|
+
const clearWatchdog = React19.useCallback(() => {
|
|
1741
|
+
if (watchdogRef.current) {
|
|
1742
|
+
clearTimeout(watchdogRef.current);
|
|
1743
|
+
watchdogRef.current = null;
|
|
1744
|
+
}
|
|
1745
|
+
}, []);
|
|
1746
|
+
React19.useEffect(() => clearWatchdog, [clearWatchdog]);
|
|
1747
|
+
const onStageRef = React19.useRef(onStage);
|
|
1748
|
+
onStageRef.current = onStage;
|
|
1749
|
+
const onSettledRef = React19.useRef(onSettled);
|
|
1750
|
+
onSettledRef.current = onSettled;
|
|
1751
|
+
const getStatusRef = React19.useRef(getStatus);
|
|
1752
|
+
getStatusRef.current = getStatus;
|
|
1753
|
+
const shownRef = React19.useRef(false);
|
|
1754
|
+
React19.useEffect(() => {
|
|
1755
|
+
var _a2;
|
|
1756
|
+
if (shownRef.current) return;
|
|
1757
|
+
shownRef.current = true;
|
|
1758
|
+
(_a2 = onStageRef.current) == null ? void 0 : _a2.call(onStageRef, "shown");
|
|
1759
|
+
}, []);
|
|
1760
|
+
React19.useEffect(() => {
|
|
1761
|
+
const probe = getStatusRef.current;
|
|
1762
|
+
if (!probe) return;
|
|
1763
|
+
let cancelled = false;
|
|
1764
|
+
try {
|
|
1765
|
+
void Promise.resolve(probe()).then((value) => {
|
|
1766
|
+
if (!cancelled) setStatus(normalizePermissionStatus(value));
|
|
1767
|
+
}).catch(() => {
|
|
1768
|
+
});
|
|
1769
|
+
} catch {
|
|
1770
|
+
}
|
|
1771
|
+
return () => {
|
|
1772
|
+
cancelled = true;
|
|
1773
|
+
};
|
|
1774
|
+
}, []);
|
|
1775
|
+
const requestRef = React19.useRef(request);
|
|
1776
|
+
requestRef.current = request;
|
|
1777
|
+
React19.useEffect(() => {
|
|
1778
|
+
if (requestRef.current) return;
|
|
1779
|
+
warnInDev(
|
|
1780
|
+
`[wireai] <WireOnboarding> got a permission screen for "${permission}" with no \`request\` function, so it cannot open the OS dialog and renders as a plain continue. Pass request: () => Promise<'granted' | 'denied' | 'blocked'> (5 lines around expo-notifications, see the README).`
|
|
1781
|
+
);
|
|
1782
|
+
}, [permission]);
|
|
1783
|
+
const settle = React19.useCallback((outcome) => {
|
|
1784
|
+
var _a2;
|
|
1785
|
+
if (settledRef.current) return;
|
|
1786
|
+
settledRef.current = true;
|
|
1787
|
+
clearWatchdog();
|
|
1788
|
+
(_a2 = onSettledRef.current) == null ? void 0 : _a2.call(onSettledRef, outcome);
|
|
1789
|
+
}, [clearWatchdog]);
|
|
1790
|
+
const primaryAction = status === "blocked" ? "settings" : status === "granted" || !request ? "continue" : "ask";
|
|
1791
|
+
const handlePrimary = React19.useCallback(() => {
|
|
1792
|
+
var _a2, _b, _c, _d;
|
|
1793
|
+
if (settledRef.current || busy) return;
|
|
1794
|
+
if (primaryAction === "settings") {
|
|
1795
|
+
(_a2 = onStageRef.current) == null ? void 0 : _a2.call(onStageRef, "settings", "blocked");
|
|
1796
|
+
try {
|
|
1797
|
+
void Promise.resolve(openSettings == null ? void 0 : openSettings()).catch(() => {
|
|
1798
|
+
});
|
|
1799
|
+
} catch {
|
|
1800
|
+
}
|
|
1801
|
+
settle("blocked");
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
if (primaryAction === "continue") {
|
|
1805
|
+
if (status === "granted") {
|
|
1806
|
+
(_b = onStageRef.current) == null ? void 0 : _b.call(onStageRef, "granted", "granted");
|
|
1807
|
+
settle("granted");
|
|
1808
|
+
} else {
|
|
1809
|
+
(_c = onStageRef.current) == null ? void 0 : _c.call(onStageRef, "skipped");
|
|
1810
|
+
settle("skipped");
|
|
1811
|
+
}
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
if (!acceptedRef.current) {
|
|
1815
|
+
acceptedRef.current = true;
|
|
1816
|
+
(_d = onStageRef.current) == null ? void 0 : _d.call(onStageRef, "accepted");
|
|
1817
|
+
}
|
|
1818
|
+
setBusy(true);
|
|
1819
|
+
const finish = (value) => {
|
|
1820
|
+
var _a3, _b2;
|
|
1821
|
+
if (settledRef.current) return;
|
|
1822
|
+
clearWatchdog();
|
|
1823
|
+
const resolved = normalizePermissionStatus(value);
|
|
1824
|
+
setBusy(false);
|
|
1825
|
+
setStatus(resolved);
|
|
1826
|
+
if (resolved === "granted") {
|
|
1827
|
+
playHaptic("success");
|
|
1828
|
+
(_a3 = onStageRef.current) == null ? void 0 : _a3.call(onStageRef, "granted", "granted");
|
|
1829
|
+
} else {
|
|
1830
|
+
(_b2 = onStageRef.current) == null ? void 0 : _b2.call(onStageRef, "denied", resolved);
|
|
1831
|
+
}
|
|
1832
|
+
settle(resolved);
|
|
1833
|
+
};
|
|
1834
|
+
clearWatchdog();
|
|
1835
|
+
watchdogRef.current = setTimeout(() => {
|
|
1836
|
+
watchdogRef.current = null;
|
|
1837
|
+
if (settledRef.current) return;
|
|
1838
|
+
setBusy(false);
|
|
1839
|
+
warnInDev(
|
|
1840
|
+
`[wireai] the \`request\` for the "${permission}" permission screen has not settled after ${Math.round(REQUEST_WATCHDOG_MS / 1e3)}s, so the kit handed the controls back rather than leaving the user on a dead-end screen. It recorded NO outcome, because a pending request is not a denial. Make sure your request resolves to 'granted' | 'denied' | 'blocked' on every branch, including the one where the user dismisses the OS dialog.`
|
|
1841
|
+
);
|
|
1842
|
+
}, REQUEST_WATCHDOG_MS);
|
|
1843
|
+
try {
|
|
1844
|
+
void Promise.resolve(request == null ? void 0 : request()).then(finish, () => finish("denied"));
|
|
1845
|
+
} catch {
|
|
1846
|
+
finish("denied");
|
|
1847
|
+
}
|
|
1848
|
+
}, [busy, primaryAction, status, request, openSettings, settle, clearWatchdog, permission]);
|
|
1849
|
+
const handleSecondary = React19.useCallback(() => {
|
|
1850
|
+
var _a2;
|
|
1851
|
+
if (settledRef.current || busy) return;
|
|
1852
|
+
(_a2 = onStageRef.current) == null ? void 0 : _a2.call(onStageRef, "skipped");
|
|
1853
|
+
settle("skipped");
|
|
1854
|
+
}, [busy, settle]);
|
|
1855
|
+
const popT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
1856
|
+
const titleT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
1857
|
+
const bodyT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
1858
|
+
React19.useEffect(() => {
|
|
1859
|
+
if (reduced) {
|
|
1860
|
+
popT.setValue(1);
|
|
1861
|
+
titleT.setValue(1);
|
|
1862
|
+
bodyT.setValue(1);
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
const rise = (value, delay) => reactNative.Animated.timing(value, {
|
|
1866
|
+
toValue: 1,
|
|
1867
|
+
duration: scaledMs(INTERSTITIAL_HEAD_MS),
|
|
1868
|
+
delay,
|
|
1869
|
+
easing: easeWire4,
|
|
1870
|
+
useNativeDriver: true
|
|
1871
|
+
});
|
|
1872
|
+
const anims = [
|
|
1873
|
+
reactNative.Animated.spring(popT, {
|
|
1874
|
+
toValue: 1,
|
|
1875
|
+
friction: STATUS_POP_SPRING.friction,
|
|
1876
|
+
tension: STATUS_POP_SPRING.tension,
|
|
1877
|
+
useNativeDriver: true
|
|
1878
|
+
}),
|
|
1879
|
+
rise(titleT, scaledMs(INTERSTITIAL_HEAD_STAGGER_MS)),
|
|
1880
|
+
rise(bodyT, scaledMs(INTERSTITIAL_HEAD_STAGGER_MS * 2))
|
|
1881
|
+
];
|
|
1882
|
+
anims.forEach((a) => a.start());
|
|
1883
|
+
return () => anims.forEach((a) => a.stop());
|
|
1884
|
+
}, [reduced, popT, titleT, bodyT]);
|
|
1885
|
+
const popScale = popT.interpolate({
|
|
1886
|
+
inputRange: [0, 1],
|
|
1887
|
+
outputRange: [STATUS_POP_SCALE_FROM, 1]
|
|
1888
|
+
});
|
|
1889
|
+
const riseStyle = (value) => ({
|
|
1890
|
+
opacity: value,
|
|
1891
|
+
transform: [
|
|
1892
|
+
{ translateY: value.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX, 0] }) }
|
|
1893
|
+
]
|
|
1894
|
+
});
|
|
1895
|
+
const blocked = status === "blocked";
|
|
1896
|
+
const shownTitle = blocked ? blockedTitle != null ? blockedTitle : title : title;
|
|
1897
|
+
const shownMessage = blocked ? blockedMessage != null ? blockedMessage : message : message;
|
|
1898
|
+
const primaryTitle = primaryAction === "settings" ? settingsLabel != null ? settingsLabel : primaryLabel : primaryAction === "continue" ? continueLabel != null ? continueLabel : primaryLabel : primaryLabel;
|
|
1899
|
+
const showSecondary = status !== "granted";
|
|
1900
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1901
|
+
CardLayout,
|
|
1902
|
+
{
|
|
1903
|
+
align: "center",
|
|
1904
|
+
footer: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles10.footer, { gap: t.spacing.sm }], children: [
|
|
1905
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { title: primaryTitle, onPress: handlePrimary, variant: "primary", disabled: busy }),
|
|
1906
|
+
showSecondary ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1907
|
+
Button,
|
|
1908
|
+
{
|
|
1909
|
+
title: secondaryLabel,
|
|
1910
|
+
onPress: handleSecondary,
|
|
1911
|
+
variant: "outline",
|
|
1912
|
+
disabled: busy
|
|
1913
|
+
}
|
|
1914
|
+
) : null
|
|
1915
|
+
] }),
|
|
1916
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles10.center, { gap: t.spacing.md }], children: [
|
|
1917
|
+
art ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1918
|
+
reactNative.Animated.View,
|
|
1919
|
+
{
|
|
1920
|
+
style: [styles10.art, { opacity: popT, transform: [{ scale: popScale }] }],
|
|
1921
|
+
children: art
|
|
1922
|
+
}
|
|
1923
|
+
) : null,
|
|
1924
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: riseStyle(titleT), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [headingStyle(t.fonts), { color: t.colors.text, textAlign: "center" }], children: shownTitle }) }),
|
|
1925
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: riseStyle(bodyT), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted, textAlign: "center" }], children: shownMessage }) })
|
|
1926
|
+
] })
|
|
1927
|
+
}
|
|
1928
|
+
);
|
|
1929
|
+
};
|
|
1930
|
+
var PermissionCardView = React19__default.default.memo(_PermissionCard);
|
|
1931
|
+
var PermissionCard = {
|
|
1932
|
+
name: PERMISSION_CARD_NAME,
|
|
1933
|
+
description: "A priming screen shown BEFORE an OS permission dialog: it explains why the app wants the permission and asks only on the primary tap. Never first, never last. The user is never blocked by it: the secondary advances the flow with the OS prompt unspent.",
|
|
1934
|
+
component: PermissionCardView,
|
|
1935
|
+
propsSchema: schema
|
|
1936
|
+
};
|
|
1937
|
+
var styles10 = reactNative.StyleSheet.create({
|
|
1938
|
+
center: { width: "100%", alignItems: "center", justifyContent: "center" },
|
|
1939
|
+
art: { alignItems: "center", justifyContent: "center" },
|
|
1940
|
+
footer: { width: "100%", alignItems: "center" }
|
|
1941
|
+
});
|
|
1942
|
+
|
|
1943
|
+
// src/permissions/placement.ts
|
|
1944
|
+
var DEFAULT_PERMISSION_PLACEMENT = "beforeEnd";
|
|
1945
|
+
var normalizeAfterCard = (value) => Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
|
|
1946
|
+
var targetIndex = (placement) => {
|
|
1947
|
+
if (placement === "beforeEnd") return void 0;
|
|
1948
|
+
if (placement === "start") return 0;
|
|
1949
|
+
return normalizeAfterCard(placement.afterCard);
|
|
1950
|
+
};
|
|
1951
|
+
var isPermissionDue = (placement, position) => {
|
|
1952
|
+
if (position.cardIndex < 0) return false;
|
|
1953
|
+
const target = targetIndex(placement);
|
|
1954
|
+
if (target === void 0) return position.isTerminal;
|
|
1955
|
+
return position.cardIndex >= target || position.isTerminal;
|
|
1956
|
+
};
|
|
1957
|
+
var permissionScreenId = (screen, index) => {
|
|
1958
|
+
var _a2;
|
|
1959
|
+
return (_a2 = screen.id) != null ? _a2 : `${screen.permission}:${index}`;
|
|
1960
|
+
};
|
|
1961
|
+
var selectDuePermissionScreen = (screens, settled, position) => {
|
|
1962
|
+
var _a2;
|
|
1963
|
+
if (!screens || screens.length === 0) return void 0;
|
|
1964
|
+
for (let index = 0; index < screens.length; index++) {
|
|
1965
|
+
const screen = screens[index];
|
|
1966
|
+
if (!screen) continue;
|
|
1967
|
+
const id = permissionScreenId(screen, index);
|
|
1968
|
+
if (settled.includes(id)) continue;
|
|
1969
|
+
if (isPermissionDue((_a2 = screen.placement) != null ? _a2 : DEFAULT_PERMISSION_PLACEMENT, position)) {
|
|
1970
|
+
return { screen, id };
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
return void 0;
|
|
1974
|
+
};
|
|
1975
|
+
|
|
1976
|
+
// src/permissions/permissionCopy.ts
|
|
1977
|
+
var NOTIFICATIONS_PERMISSION_COPY = {
|
|
1978
|
+
title: "Want a nudge at the right moment?",
|
|
1979
|
+
message: "Turn notifications on and we will remind you when it actually helps. No daily noise, and you can turn them off any time.",
|
|
1980
|
+
primaryLabel: "Enable notifications",
|
|
1981
|
+
secondaryLabel: "Maybe later",
|
|
1982
|
+
blockedTitle: "Notifications are switched off",
|
|
1983
|
+
blockedMessage: "Notifications are turned off for this app, so we cannot ask from here. You can switch them back on in Settings.",
|
|
1984
|
+
settingsLabel: "Open settings",
|
|
1985
|
+
continueLabel: "Continue"
|
|
1986
|
+
};
|
|
1987
|
+
var GENERIC_PERMISSION_COPY = {
|
|
1988
|
+
title: "One quick permission",
|
|
1989
|
+
message: "We need your permission for this part to work. You can change it any time.",
|
|
1990
|
+
primaryLabel: "Allow",
|
|
1991
|
+
secondaryLabel: "Maybe later",
|
|
1992
|
+
blockedTitle: "Permission is switched off",
|
|
1993
|
+
blockedMessage: "This permission is turned off for this app, so we cannot ask from here. You can switch it back on in Settings.",
|
|
1994
|
+
settingsLabel: "Open settings",
|
|
1995
|
+
continueLabel: "Continue"
|
|
1996
|
+
};
|
|
1997
|
+
var DEFAULT_PERMISSION_COPY = {
|
|
1998
|
+
notifications: NOTIFICATIONS_PERMISSION_COPY
|
|
1999
|
+
};
|
|
2000
|
+
var resolvePermissionCopy = (permission, overrides) => {
|
|
2001
|
+
var _a2;
|
|
2002
|
+
const base = (_a2 = DEFAULT_PERMISSION_COPY[permission]) != null ? _a2 : GENERIC_PERMISSION_COPY;
|
|
2003
|
+
if (!overrides) return base;
|
|
2004
|
+
const merged = { ...base };
|
|
2005
|
+
for (const key of Object.keys(overrides)) {
|
|
2006
|
+
const value = overrides[key];
|
|
2007
|
+
if (typeof value === "string" && value.length > 0) merged[key] = value;
|
|
2008
|
+
}
|
|
2009
|
+
return merged;
|
|
2010
|
+
};
|
|
1600
2011
|
var SKIP_ONE_SENTINEL = "__wireai_skip__";
|
|
1601
2012
|
var ANSWER_CALLBACKS = ["onSubmit", "onSelect", "onConfirm", "onPress"];
|
|
1602
2013
|
var DEFAULT_COPY = {
|
|
@@ -1625,53 +2036,60 @@ var OnboardingFlow = ({
|
|
|
1625
2036
|
reportTarget,
|
|
1626
2037
|
sessionId,
|
|
1627
2038
|
resumed = false,
|
|
1628
|
-
clientContext
|
|
2039
|
+
clientContext,
|
|
2040
|
+
permissionScreens,
|
|
2041
|
+
settledPermissions,
|
|
2042
|
+
permissionsPending = false,
|
|
2043
|
+
onPermissionSettled
|
|
1629
2044
|
}) => {
|
|
1630
2045
|
var _a2, _b, _c, _d, _e, _f;
|
|
1631
2046
|
const { messages, error, isLoading, sendMessage, reset } = wireaiRn.useWireAIThread();
|
|
1632
2047
|
const makeActions = wireaiRn.useWireAIAction(sendMessage);
|
|
1633
|
-
const c =
|
|
1634
|
-
const onEventRef =
|
|
2048
|
+
const c = React19.useMemo(() => ({ ...DEFAULT_COPY, ...copy }), [copy]);
|
|
2049
|
+
const onEventRef = React19.useRef(onEvent);
|
|
1635
2050
|
onEventRef.current = onEvent;
|
|
1636
|
-
const onErrorRef =
|
|
2051
|
+
const onErrorRef = React19.useRef(onError);
|
|
1637
2052
|
onErrorRef.current = onError;
|
|
1638
|
-
const onCompleteRef =
|
|
2053
|
+
const onCompleteRef = React19.useRef(onComplete);
|
|
1639
2054
|
onCompleteRef.current = onComplete;
|
|
1640
|
-
const validatorsRef =
|
|
2055
|
+
const validatorsRef = React19.useRef(validators);
|
|
1641
2056
|
validatorsRef.current = validators;
|
|
1642
|
-
const reportTargetRef =
|
|
2057
|
+
const reportTargetRef = React19.useRef(reportTarget);
|
|
1643
2058
|
reportTargetRef.current = reportTarget;
|
|
1644
|
-
const sessionIdRef =
|
|
2059
|
+
const sessionIdRef = React19.useRef(sessionId);
|
|
1645
2060
|
sessionIdRef.current = sessionId;
|
|
1646
|
-
const clientContextRef =
|
|
2061
|
+
const clientContextRef = React19.useRef(clientContext);
|
|
1647
2062
|
clientContextRef.current = clientContext;
|
|
1648
|
-
const lastScreenIndexRef =
|
|
1649
|
-
const previewTimer =
|
|
1650
|
-
const started =
|
|
1651
|
-
const finished =
|
|
1652
|
-
const errored =
|
|
1653
|
-
const attempts =
|
|
1654
|
-
const degradedRef =
|
|
1655
|
-
const [degraded, setDegraded] =
|
|
1656
|
-
const [timedOut, setTimedOut] =
|
|
1657
|
-
const [validationError, setValidationError] =
|
|
1658
|
-
const [validating, setValidating] =
|
|
1659
|
-
const
|
|
2063
|
+
const lastScreenIndexRef = React19.useRef(-1);
|
|
2064
|
+
const previewTimer = React19.useRef(null);
|
|
2065
|
+
const started = React19.useRef(false);
|
|
2066
|
+
const finished = React19.useRef(false);
|
|
2067
|
+
const errored = React19.useRef(false);
|
|
2068
|
+
const attempts = React19.useRef(0);
|
|
2069
|
+
const degradedRef = React19.useRef(false);
|
|
2070
|
+
const [degraded, setDegraded] = React19.useState(false);
|
|
2071
|
+
const [timedOut, setTimedOut] = React19.useState(false);
|
|
2072
|
+
const [validationError, setValidationError] = React19.useState();
|
|
2073
|
+
const [validating, setValidating] = React19.useState(false);
|
|
2074
|
+
const [locallySettledPermissions, setLocallySettledPermissions] = React19.useState([]);
|
|
2075
|
+
const onPermissionSettledRef = React19.useRef(onPermissionSettled);
|
|
2076
|
+
onPermissionSettledRef.current = onPermissionSettled;
|
|
2077
|
+
const lastCard = React19.useMemo(
|
|
1660
2078
|
() => [...messages].reverse().find((m) => {
|
|
1661
2079
|
var _a3;
|
|
1662
2080
|
return m.role === "assistant" && ((_a3 = m.response) == null ? void 0 : _a3.action) === "render";
|
|
1663
2081
|
}),
|
|
1664
2082
|
[messages]
|
|
1665
2083
|
);
|
|
1666
|
-
const renderedCount =
|
|
2084
|
+
const renderedCount = React19.useMemo(
|
|
1667
2085
|
() => messages.filter((m) => {
|
|
1668
2086
|
var _a3;
|
|
1669
2087
|
return m.role === "assistant" && ((_a3 = m.response) == null ? void 0 : _a3.action) === "render";
|
|
1670
2088
|
}).length,
|
|
1671
2089
|
[messages]
|
|
1672
2090
|
);
|
|
1673
|
-
const progress =
|
|
1674
|
-
|
|
2091
|
+
const progress = React19.useMemo(() => readProgress(lastCard == null ? void 0 : lastCard.response), [lastCard]);
|
|
2092
|
+
React19.useEffect(() => {
|
|
1675
2093
|
var _a3;
|
|
1676
2094
|
if (started.current) return;
|
|
1677
2095
|
started.current = true;
|
|
@@ -1681,12 +2099,12 @@ var OnboardingFlow = ({
|
|
|
1681
2099
|
resumed ? { type: "resumed", contextId: sessionId } : { type: "started", contextId: sessionId }
|
|
1682
2100
|
);
|
|
1683
2101
|
}, [sendMessage, startMessage, resumed, sessionId]);
|
|
1684
|
-
|
|
2102
|
+
React19.useEffect(() => {
|
|
1685
2103
|
if (lastCard) return;
|
|
1686
2104
|
const timer = setTimeout(() => setTimedOut(true), startTimeoutMs);
|
|
1687
2105
|
return () => clearTimeout(timer);
|
|
1688
2106
|
}, [lastCard, startTimeoutMs]);
|
|
1689
|
-
|
|
2107
|
+
React19.useEffect(() => {
|
|
1690
2108
|
var _a3, _b2, _c2, _d2;
|
|
1691
2109
|
setValidationError(void 0);
|
|
1692
2110
|
if (!(lastCard == null ? void 0 : lastCard.id)) return;
|
|
@@ -1704,7 +2122,7 @@ var OnboardingFlow = ({
|
|
|
1704
2122
|
});
|
|
1705
2123
|
}
|
|
1706
2124
|
}, [lastCard == null ? void 0 : lastCard.id]);
|
|
1707
|
-
|
|
2125
|
+
React19.useEffect(() => {
|
|
1708
2126
|
return () => {
|
|
1709
2127
|
var _a3, _b2, _c2;
|
|
1710
2128
|
if (finished.current || degradedRef.current) return;
|
|
@@ -1718,13 +2136,13 @@ var OnboardingFlow = ({
|
|
|
1718
2136
|
});
|
|
1719
2137
|
};
|
|
1720
2138
|
}, []);
|
|
1721
|
-
const restartThread =
|
|
2139
|
+
const restartThread = React19.useCallback(() => {
|
|
1722
2140
|
setTimedOut(false);
|
|
1723
2141
|
started.current = false;
|
|
1724
2142
|
errored.current = false;
|
|
1725
2143
|
reset();
|
|
1726
2144
|
}, [reset]);
|
|
1727
|
-
|
|
2145
|
+
React19.useEffect(() => {
|
|
1728
2146
|
var _a3, _b2, _c2, _d2, _e2, _f2, _g;
|
|
1729
2147
|
if (errored.current) return;
|
|
1730
2148
|
if (!error && !timedOut) return;
|
|
@@ -1751,22 +2169,52 @@ var OnboardingFlow = ({
|
|
|
1751
2169
|
(_g = onErrorRef.current) == null ? void 0 : _g.call(onErrorRef, error != null ? error : new Error("Onboarding timed out"));
|
|
1752
2170
|
}
|
|
1753
2171
|
}, [error, timedOut, maxRetries]);
|
|
1754
|
-
const handleFinish =
|
|
2172
|
+
const handleFinish = React19.useCallback(() => {
|
|
1755
2173
|
if (finished.current) return;
|
|
1756
2174
|
finished.current = true;
|
|
1757
2175
|
onCompleteRef.current({ answers: deriveAnswers(messages), raw: messages });
|
|
1758
2176
|
}, [messages]);
|
|
1759
|
-
const handleRetry =
|
|
2177
|
+
const handleRetry = React19.useCallback(() => {
|
|
1760
2178
|
attempts.current = 0;
|
|
1761
2179
|
degradedRef.current = false;
|
|
1762
2180
|
setDegraded(false);
|
|
1763
2181
|
restartThread();
|
|
1764
2182
|
}, [restartThread]);
|
|
1765
|
-
const skipQuestion =
|
|
2183
|
+
const skipQuestion = React19.useCallback(() => {
|
|
1766
2184
|
if (isLoading) return;
|
|
1767
2185
|
sendMessage(SKIP_ONE_SENTINEL);
|
|
1768
2186
|
}, [isLoading, sendMessage]);
|
|
1769
|
-
const
|
|
2187
|
+
const emitPermissionStage = React19.useCallback(
|
|
2188
|
+
(permission, stage, status) => {
|
|
2189
|
+
var _a3, _b2, _c2, _d2;
|
|
2190
|
+
(_a3 = onEventRef.current) == null ? void 0 : _a3.call(onEventRef, { type: "permission", permission, stage, status });
|
|
2191
|
+
reportClientEvent(reportTargetRef.current, {
|
|
2192
|
+
event_type: "app_event",
|
|
2193
|
+
session_id: sessionIdRef.current,
|
|
2194
|
+
question_key: permissionEventName(stage),
|
|
2195
|
+
component: PERMISSION_CARD_NAME,
|
|
2196
|
+
screen_index: lastScreenIndexRef.current >= 0 ? lastScreenIndexRef.current : void 0,
|
|
2197
|
+
meta: JSON.stringify(permissionEventProps(permission, status)),
|
|
2198
|
+
device: (_b2 = clientContextRef.current) == null ? void 0 : _b2.device,
|
|
2199
|
+
user_context: (_c2 = clientContextRef.current) == null ? void 0 : _c2.userContext,
|
|
2200
|
+
user_id: (_d2 = clientContextRef.current) == null ? void 0 : _d2.userId
|
|
2201
|
+
});
|
|
2202
|
+
},
|
|
2203
|
+
[]
|
|
2204
|
+
);
|
|
2205
|
+
const settlePermission = React19.useCallback(
|
|
2206
|
+
(id, screen, outcome) => {
|
|
2207
|
+
var _a3, _b2;
|
|
2208
|
+
setLocallySettledPermissions((prev) => prev.includes(id) ? prev : [...prev, id]);
|
|
2209
|
+
(_a3 = onPermissionSettledRef.current) == null ? void 0 : _a3.call(onPermissionSettledRef, id, outcome);
|
|
2210
|
+
try {
|
|
2211
|
+
(_b2 = screen.onResult) == null ? void 0 : _b2.call(screen, screen.permission, outcome);
|
|
2212
|
+
} catch {
|
|
2213
|
+
}
|
|
2214
|
+
},
|
|
2215
|
+
[]
|
|
2216
|
+
);
|
|
2217
|
+
const previewOnSelect = React19.useCallback((value) => {
|
|
1770
2218
|
const target = reportTargetRef.current;
|
|
1771
2219
|
if (!(target == null ? void 0 : target.serverUrl)) return;
|
|
1772
2220
|
if (Array.isArray(value) ? value.length === 0 : !value) return;
|
|
@@ -1778,10 +2226,10 @@ var OnboardingFlow = ({
|
|
|
1778
2226
|
});
|
|
1779
2227
|
}, 300);
|
|
1780
2228
|
}, []);
|
|
1781
|
-
|
|
2229
|
+
React19.useEffect(() => () => {
|
|
1782
2230
|
if (previewTimer.current) clearTimeout(previewTimer.current);
|
|
1783
2231
|
}, []);
|
|
1784
|
-
const wrappedActions =
|
|
2232
|
+
const wrappedActions = React19.useCallback(
|
|
1785
2233
|
(messageId) => {
|
|
1786
2234
|
var _a3;
|
|
1787
2235
|
const base = makeActions(messageId);
|
|
@@ -1836,6 +2284,36 @@ var OnboardingFlow = ({
|
|
|
1836
2284
|
const step = (_a2 = progress.step) != null ? _a2 : renderedCount;
|
|
1837
2285
|
const total = (_b = progress.total) != null ? _b : approxScreens;
|
|
1838
2286
|
const isTerminal = response.action === "render" && response.component === "StatusCard";
|
|
2287
|
+
const duePermission = permissionsPending ? void 0 : selectDuePermissionScreen(
|
|
2288
|
+
permissionScreens,
|
|
2289
|
+
settledPermissions ? [...settledPermissions, ...locallySettledPermissions] : locallySettledPermissions,
|
|
2290
|
+
{ cardIndex: renderedCount - 1, isTerminal }
|
|
2291
|
+
);
|
|
2292
|
+
if (duePermission) {
|
|
2293
|
+
const { screen, id } = duePermission;
|
|
2294
|
+
const copy2 = resolvePermissionCopy(screen.permission, screen.copy);
|
|
2295
|
+
return /* @__PURE__ */ jsxRuntime.jsx(OnboardingScaffold, { step, approxScreens: total, children: /* @__PURE__ */ jsxRuntime.jsx(CardHandoff, { transitionKey: `permission:${id}`, variant: "spring", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2296
|
+
PermissionCardView,
|
|
2297
|
+
{
|
|
2298
|
+
permission: screen.permission,
|
|
2299
|
+
title: copy2.title,
|
|
2300
|
+
message: copy2.message,
|
|
2301
|
+
primaryLabel: copy2.primaryLabel,
|
|
2302
|
+
secondaryLabel: copy2.secondaryLabel,
|
|
2303
|
+
blockedTitle: copy2.blockedTitle,
|
|
2304
|
+
blockedMessage: copy2.blockedMessage,
|
|
2305
|
+
settingsLabel: copy2.settingsLabel,
|
|
2306
|
+
continueLabel: copy2.continueLabel,
|
|
2307
|
+
illustration: screen.illustration,
|
|
2308
|
+
request: screen.request,
|
|
2309
|
+
getStatus: screen.getStatus,
|
|
2310
|
+
openSettings: screen.openSettings,
|
|
2311
|
+
onStage: (stage, status) => emitPermissionStage(screen.permission, stage, status),
|
|
2312
|
+
onSettled: (outcome) => settlePermission(id, screen, outcome)
|
|
2313
|
+
},
|
|
2314
|
+
id
|
|
2315
|
+
) }) });
|
|
2316
|
+
}
|
|
1839
2317
|
if (isTerminal) {
|
|
1840
2318
|
const props = (_c = response.props) != null ? _c : {};
|
|
1841
2319
|
return /* @__PURE__ */ jsxRuntime.jsx(OnboardingScaffold, { step, complete: true, approxScreens: total, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1894,8 +2372,8 @@ var OnboardingFlow = ({
|
|
|
1894
2372
|
}
|
|
1895
2373
|
);
|
|
1896
2374
|
};
|
|
1897
|
-
var
|
|
1898
|
-
var
|
|
2375
|
+
var easeWire5 = reactNative.Easing.bezier(...WIRE_BEZIER);
|
|
2376
|
+
var schema2 = zod.z.object({
|
|
1899
2377
|
title: zod.z.string().describe("Question or section header, e.g. 'Which season?'"),
|
|
1900
2378
|
chips: zod.z.array(zod.z.string()).min(1).describe("List of option labels shown as chips, e.g. ['Spring','Summer','Autumn','Winter']"),
|
|
1901
2379
|
multiSelect: zod.z.boolean().optional().describe("Allow multiple chips selected at once, default true"),
|
|
@@ -1905,9 +2383,9 @@ var schema = zod.z.object({
|
|
|
1905
2383
|
var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
|
|
1906
2384
|
const t = useOnboardingTheme();
|
|
1907
2385
|
const reduced = useReducedMotion();
|
|
1908
|
-
const handlePress =
|
|
1909
|
-
const pressScale =
|
|
1910
|
-
const pressTo =
|
|
2386
|
+
const handlePress = React19.useCallback(() => onToggle(chip), [chip, onToggle]);
|
|
2387
|
+
const pressScale = React19.useRef(new reactNative.Animated.Value(1)).current;
|
|
2388
|
+
const pressTo = React19.useCallback(
|
|
1911
2389
|
(to) => {
|
|
1912
2390
|
if (reduced) return;
|
|
1913
2391
|
reactNative.Animated.spring(pressScale, {
|
|
@@ -1919,21 +2397,21 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
|
|
|
1919
2397
|
},
|
|
1920
2398
|
[pressScale, reduced]
|
|
1921
2399
|
);
|
|
1922
|
-
const handlePressIn =
|
|
1923
|
-
const handlePressOut =
|
|
1924
|
-
const fillT =
|
|
1925
|
-
|
|
2400
|
+
const handlePressIn = React19.useCallback(() => pressTo(CHIP_PRESS_SCALE), [pressTo]);
|
|
2401
|
+
const handlePressOut = React19.useCallback(() => pressTo(1), [pressTo]);
|
|
2402
|
+
const fillT = React19.useRef(new reactNative.Animated.Value(isSelected ? 1 : 0)).current;
|
|
2403
|
+
React19.useEffect(() => {
|
|
1926
2404
|
const anim = reactNative.Animated.timing(fillT, {
|
|
1927
2405
|
toValue: isSelected ? 1 : 0,
|
|
1928
2406
|
duration: scaledMs(stateChangeDuration(reduced, CHIP_FILL_MS)),
|
|
1929
|
-
easing:
|
|
2407
|
+
easing: easeWire5,
|
|
1930
2408
|
useNativeDriver: true
|
|
1931
2409
|
});
|
|
1932
2410
|
anim.start();
|
|
1933
2411
|
return () => anim.stop();
|
|
1934
2412
|
}, [isSelected, reduced, fillT]);
|
|
1935
|
-
const checkT =
|
|
1936
|
-
|
|
2413
|
+
const checkT = React19.useRef(new reactNative.Animated.Value(isSelected ? 1 : 0)).current;
|
|
2414
|
+
React19.useEffect(() => {
|
|
1937
2415
|
if (!isSelected) {
|
|
1938
2416
|
checkT.setValue(0);
|
|
1939
2417
|
return;
|
|
@@ -1966,7 +2444,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
|
|
|
1966
2444
|
reactNative.Animated.View,
|
|
1967
2445
|
{
|
|
1968
2446
|
style: [
|
|
1969
|
-
|
|
2447
|
+
styles11.chip,
|
|
1970
2448
|
{
|
|
1971
2449
|
borderRadius: t.radius.full,
|
|
1972
2450
|
paddingHorizontal: t.spacing.md,
|
|
@@ -1983,7 +2461,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
|
|
|
1983
2461
|
pointerEvents: "none",
|
|
1984
2462
|
style: [
|
|
1985
2463
|
reactNative.StyleSheet.absoluteFill,
|
|
1986
|
-
|
|
2464
|
+
styles11.fillOverlay,
|
|
1987
2465
|
{
|
|
1988
2466
|
borderRadius: t.radius.full,
|
|
1989
2467
|
borderColor: t.colors.primary,
|
|
@@ -1997,7 +2475,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
|
|
|
1997
2475
|
reactNative.Animated.Text,
|
|
1998
2476
|
{
|
|
1999
2477
|
style: [
|
|
2000
|
-
|
|
2478
|
+
styles11.check,
|
|
2001
2479
|
{ color: t.colors.onPrimary, opacity: checkT, transform: [{ scale: checkScale }] }
|
|
2002
2480
|
],
|
|
2003
2481
|
children: "\u2713"
|
|
@@ -2008,7 +2486,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
|
|
|
2008
2486
|
{
|
|
2009
2487
|
style: [
|
|
2010
2488
|
captionStyle(t.fonts),
|
|
2011
|
-
|
|
2489
|
+
styles11.chipLabel,
|
|
2012
2490
|
{ color: isSelected ? t.colors.onPrimary : t.colors.textMuted }
|
|
2013
2491
|
],
|
|
2014
2492
|
children: chip
|
|
@@ -2020,7 +2498,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
|
|
|
2020
2498
|
}
|
|
2021
2499
|
);
|
|
2022
2500
|
};
|
|
2023
|
-
var ChipItem =
|
|
2501
|
+
var ChipItem = React19__default.default.memo(_ChipItem);
|
|
2024
2502
|
var _ChipSelectCard = ({
|
|
2025
2503
|
title,
|
|
2026
2504
|
chips,
|
|
@@ -2031,12 +2509,12 @@ var _ChipSelectCard = ({
|
|
|
2031
2509
|
onSelectionChange
|
|
2032
2510
|
}) => {
|
|
2033
2511
|
const t = useOnboardingTheme();
|
|
2034
|
-
const [selected, setSelected] =
|
|
2035
|
-
const [submitted, setSubmitted] =
|
|
2036
|
-
|
|
2512
|
+
const [selected, setSelected] = React19.useState([]);
|
|
2513
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
2514
|
+
React19.useEffect(() => {
|
|
2037
2515
|
if (!submitted && selected.length) onSelectionChange == null ? void 0 : onSelectionChange(multiSelect ? selected : selected[0]);
|
|
2038
2516
|
}, [selected, submitted, multiSelect, onSelectionChange]);
|
|
2039
|
-
const toggle =
|
|
2517
|
+
const toggle = React19.useCallback(
|
|
2040
2518
|
(chip) => {
|
|
2041
2519
|
if (submitted) return;
|
|
2042
2520
|
if (multiSelect) {
|
|
@@ -2051,7 +2529,7 @@ var _ChipSelectCard = ({
|
|
|
2051
2529
|
},
|
|
2052
2530
|
[submitted, multiSelect, maxSelections]
|
|
2053
2531
|
);
|
|
2054
|
-
const handleSubmit =
|
|
2532
|
+
const handleSubmit = React19.useCallback(() => {
|
|
2055
2533
|
if (!selected.length || !onSelect || submitted) return;
|
|
2056
2534
|
setSubmitted(true);
|
|
2057
2535
|
onSelect(multiSelect ? selected : selected[0]);
|
|
@@ -2070,7 +2548,7 @@ var _ChipSelectCard = ({
|
|
|
2070
2548
|
disabled: selected.length === 0 || submitted
|
|
2071
2549
|
}
|
|
2072
2550
|
),
|
|
2073
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
2551
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles11.chipsRow, { gap: t.spacing.sm + t.spacing.xs }], children: chips.map((chip) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2074
2552
|
ChipItem,
|
|
2075
2553
|
{
|
|
2076
2554
|
chip,
|
|
@@ -2086,18 +2564,18 @@ var _ChipSelectCard = ({
|
|
|
2086
2564
|
var ChipSelectCard = {
|
|
2087
2565
|
name: "ChipSelectCard",
|
|
2088
2566
|
description: "Use for compact short labels: seasons, activities, travel styles, moods, categories. Ideal for 4\u201312 single-word or two-word options. Use SelectionCard instead when options need descriptions; use CardGridSelectCard for a smaller set (2\u20136) of visual choices that each deserve an icon.",
|
|
2089
|
-
component:
|
|
2090
|
-
propsSchema:
|
|
2567
|
+
component: React19__default.default.memo(_ChipSelectCard),
|
|
2568
|
+
propsSchema: schema2,
|
|
2091
2569
|
defaultProps: { multiSelect: true, submitLabel: "Continue" }
|
|
2092
2570
|
};
|
|
2093
|
-
var
|
|
2571
|
+
var styles11 = reactNative.StyleSheet.create({
|
|
2094
2572
|
chipsRow: { flexDirection: "row", flexWrap: "wrap" },
|
|
2095
2573
|
chip: { borderWidth: 1.5, flexDirection: "row", alignItems: "center", gap: 6, overflow: "hidden" },
|
|
2096
2574
|
fillOverlay: { borderWidth: 1.5 },
|
|
2097
2575
|
chipLabel: { fontWeight: "600" },
|
|
2098
2576
|
check: { fontSize: 13, fontWeight: "800", lineHeight: 15 }
|
|
2099
2577
|
});
|
|
2100
|
-
var
|
|
2578
|
+
var schema3 = zod.z.object({
|
|
2101
2579
|
label: zod.z.string().describe("Input field label / the question being asked"),
|
|
2102
2580
|
hint: zod.z.string().optional().describe(
|
|
2103
2581
|
"One short line under the question giving context: what the answer is used for or why you ask. Add it whenever the question alone might be unclear."
|
|
@@ -2122,14 +2600,14 @@ var _TextInputCard = ({
|
|
|
2122
2600
|
lines = 6
|
|
2123
2601
|
}) => {
|
|
2124
2602
|
const t = useOnboardingTheme();
|
|
2125
|
-
const
|
|
2603
|
+
const styles18 = React19.useMemo(() => makeStyles3(t), [t]);
|
|
2126
2604
|
const { height: screenHeight } = reactNative.useWindowDimensions();
|
|
2127
|
-
const [value, setValue] =
|
|
2128
|
-
const [submitted, setSubmitted] =
|
|
2605
|
+
const [value, setValue] = React19.useState("");
|
|
2606
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
2129
2607
|
const locked = submitted && !validationError;
|
|
2130
2608
|
const APPROX_ROW_HEIGHT = 26;
|
|
2131
2609
|
const minHeight = multiline ? Math.min(Math.max(lines, 4) * APPROX_ROW_HEIGHT + t.spacing.md * 2, screenHeight * 0.4) : 52;
|
|
2132
|
-
const handleSubmit =
|
|
2610
|
+
const handleSubmit = React19.useCallback(() => {
|
|
2133
2611
|
if (value.trim() && onSubmit && !locked) {
|
|
2134
2612
|
setSubmitted(true);
|
|
2135
2613
|
onSubmit(value.trim());
|
|
@@ -2149,7 +2627,7 @@ var _TextInputCard = ({
|
|
|
2149
2627
|
disabled: !value.trim() || locked
|
|
2150
2628
|
}
|
|
2151
2629
|
),
|
|
2152
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2630
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles18.row, children: [
|
|
2153
2631
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2154
2632
|
reactNative.TextInput,
|
|
2155
2633
|
{
|
|
@@ -2163,7 +2641,7 @@ var _TextInputCard = ({
|
|
|
2163
2641
|
textAlignVertical: multiline ? "top" : "center",
|
|
2164
2642
|
style: [
|
|
2165
2643
|
bodyStyle(t.fonts),
|
|
2166
|
-
|
|
2644
|
+
styles18.input,
|
|
2167
2645
|
{
|
|
2168
2646
|
color: t.colors.text,
|
|
2169
2647
|
backgroundColor: t.colors.surface,
|
|
@@ -2183,8 +2661,8 @@ var _TextInputCard = ({
|
|
|
2183
2661
|
var TextInputCard = {
|
|
2184
2662
|
name: "TextInputCard",
|
|
2185
2663
|
description: "Use when the user needs to type a free-text answer: an open-ended goal, notes, feedback, a name, a destination, a search query. Multi-line by default (great for open-ended goals); set multiline:false for a short single-line field like a name. Use NumberStepperCard for numeric ranges with known bounds.",
|
|
2186
|
-
component:
|
|
2187
|
-
propsSchema:
|
|
2664
|
+
component: React19__default.default.memo(_TextInputCard),
|
|
2665
|
+
propsSchema: schema3,
|
|
2188
2666
|
defaultProps: { submitLabel: "Submit", multiline: true, lines: 6 }
|
|
2189
2667
|
};
|
|
2190
2668
|
function makeStyles3(t) {
|
|
@@ -2339,7 +2817,7 @@ var _WireIcon = ({ name: name2, size = 20, color, requireModule }) => {
|
|
|
2339
2817
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2340
2818
|
reactNative.View,
|
|
2341
2819
|
{
|
|
2342
|
-
style:
|
|
2820
|
+
style: styles12.decorative,
|
|
2343
2821
|
accessible: false,
|
|
2344
2822
|
importantForAccessibility: "no-hide-descendants",
|
|
2345
2823
|
children: hostIcon
|
|
@@ -2353,7 +2831,7 @@ var _WireIcon = ({ name: name2, size = 20, color, requireModule }) => {
|
|
|
2353
2831
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2354
2832
|
reactNative.View,
|
|
2355
2833
|
{
|
|
2356
|
-
style:
|
|
2834
|
+
style: styles12.decorative,
|
|
2357
2835
|
accessible: false,
|
|
2358
2836
|
importantForAccessibility: "no-hide-descendants",
|
|
2359
2837
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2368,9 +2846,9 @@ var _WireIcon = ({ name: name2, size = 20, color, requireModule }) => {
|
|
|
2368
2846
|
}
|
|
2369
2847
|
);
|
|
2370
2848
|
};
|
|
2371
|
-
var WireIcon =
|
|
2849
|
+
var WireIcon = React19__default.default.memo(_WireIcon);
|
|
2372
2850
|
WireIcon.displayName = "WireIcon";
|
|
2373
|
-
var
|
|
2851
|
+
var styles12 = reactNative.StyleSheet.create({
|
|
2374
2852
|
// No size/margin of its own: the glyph decides its footprint, so an absent icon and a
|
|
2375
2853
|
// present one differ by exactly the glyph — never by a wrapper.
|
|
2376
2854
|
decorative: {}
|
|
@@ -2384,8 +2862,8 @@ var optionObjectSchema = zod.z.object({
|
|
|
2384
2862
|
var coerceOptions = (arr) => Array.isArray(arr) ? arr.map((item) => typeof item === "string" ? { value: item, label: item } : item) : arr;
|
|
2385
2863
|
var optionsField = (description) => zod.z.preprocess(coerceOptions, zod.z.array(optionObjectSchema).min(1)).describe(description);
|
|
2386
2864
|
var normalizeOptions = (options) => options.map((opt) => typeof opt === "string" ? { value: opt, label: opt } : opt);
|
|
2387
|
-
var
|
|
2388
|
-
var
|
|
2865
|
+
var easeWire6 = reactNative.Easing.bezier(...WIRE_BEZIER);
|
|
2866
|
+
var schema4 = zod.z.object({
|
|
2389
2867
|
title: zod.z.string().describe("Question or prompt for the user"),
|
|
2390
2868
|
options: optionsField("List of choices"),
|
|
2391
2869
|
submitLabel: zod.z.string().optional().describe("Submit button label, default: Continue"),
|
|
@@ -2394,9 +2872,9 @@ var schema3 = zod.z.object({
|
|
|
2394
2872
|
var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
2395
2873
|
const t = useOnboardingTheme();
|
|
2396
2874
|
const reduced = useReducedMotion();
|
|
2397
|
-
const handlePress =
|
|
2398
|
-
const pressScale =
|
|
2399
|
-
const pressTo =
|
|
2875
|
+
const handlePress = React19.useCallback(() => onToggle(opt.value), [opt.value, onToggle]);
|
|
2876
|
+
const pressScale = React19.useRef(new reactNative.Animated.Value(1)).current;
|
|
2877
|
+
const pressTo = React19.useCallback(
|
|
2400
2878
|
(to) => {
|
|
2401
2879
|
if (reduced) return;
|
|
2402
2880
|
reactNative.Animated.spring(pressScale, {
|
|
@@ -2408,21 +2886,21 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2408
2886
|
},
|
|
2409
2887
|
[pressScale, reduced]
|
|
2410
2888
|
);
|
|
2411
|
-
const handlePressIn =
|
|
2412
|
-
const handlePressOut =
|
|
2413
|
-
const selectT =
|
|
2414
|
-
|
|
2889
|
+
const handlePressIn = React19.useCallback(() => pressTo(ROW_PRESS_SCALE), [pressTo]);
|
|
2890
|
+
const handlePressOut = React19.useCallback(() => pressTo(1), [pressTo]);
|
|
2891
|
+
const selectT = React19.useRef(new reactNative.Animated.Value(isSelected ? 1 : 0)).current;
|
|
2892
|
+
React19.useEffect(() => {
|
|
2415
2893
|
const anim = reactNative.Animated.timing(selectT, {
|
|
2416
2894
|
toValue: isSelected ? 1 : 0,
|
|
2417
2895
|
duration: scaledMs(stateChangeDuration(reduced, SELECT_FILL_MS)),
|
|
2418
|
-
easing:
|
|
2896
|
+
easing: easeWire6,
|
|
2419
2897
|
useNativeDriver: true
|
|
2420
2898
|
});
|
|
2421
2899
|
anim.start();
|
|
2422
2900
|
return () => anim.stop();
|
|
2423
2901
|
}, [isSelected, reduced, selectT]);
|
|
2424
|
-
const checkT =
|
|
2425
|
-
|
|
2902
|
+
const checkT = React19.useRef(new reactNative.Animated.Value(isSelected ? 1 : 0)).current;
|
|
2903
|
+
React19.useEffect(() => {
|
|
2426
2904
|
if (!isSelected) {
|
|
2427
2905
|
checkT.setValue(0);
|
|
2428
2906
|
return;
|
|
@@ -2455,7 +2933,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2455
2933
|
reactNative.Animated.View,
|
|
2456
2934
|
{
|
|
2457
2935
|
style: [
|
|
2458
|
-
|
|
2936
|
+
styles13.option,
|
|
2459
2937
|
{
|
|
2460
2938
|
padding: t.spacing.md,
|
|
2461
2939
|
borderRadius: t.radius.md,
|
|
@@ -2472,7 +2950,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2472
2950
|
pointerEvents: "none",
|
|
2473
2951
|
style: [
|
|
2474
2952
|
reactNative.StyleSheet.absoluteFill,
|
|
2475
|
-
|
|
2953
|
+
styles13.selectedOverlay,
|
|
2476
2954
|
{
|
|
2477
2955
|
borderRadius: t.radius.md,
|
|
2478
2956
|
borderColor: t.colors.primary,
|
|
@@ -2486,7 +2964,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2486
2964
|
reactNative.View,
|
|
2487
2965
|
{
|
|
2488
2966
|
style: [
|
|
2489
|
-
|
|
2967
|
+
styles13.indicator,
|
|
2490
2968
|
{ borderRadius: t.radius.full },
|
|
2491
2969
|
isSelected ? { borderColor: t.colors.primary, backgroundColor: t.colors.primary } : { borderColor: t.colors.borderStrong, backgroundColor: "transparent" }
|
|
2492
2970
|
],
|
|
@@ -2494,7 +2972,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2494
2972
|
reactNative.Animated.Text,
|
|
2495
2973
|
{
|
|
2496
2974
|
style: [
|
|
2497
|
-
|
|
2975
|
+
styles13.check,
|
|
2498
2976
|
{ color: t.colors.onPrimary, opacity: checkT, transform: [{ scale: checkScale }] }
|
|
2499
2977
|
],
|
|
2500
2978
|
children: "\u2713"
|
|
@@ -2510,7 +2988,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2510
2988
|
}
|
|
2511
2989
|
);
|
|
2512
2990
|
};
|
|
2513
|
-
var OptionRow =
|
|
2991
|
+
var OptionRow = React19__default.default.memo(_OptionRow);
|
|
2514
2992
|
var _SelectionCard = ({
|
|
2515
2993
|
title,
|
|
2516
2994
|
options,
|
|
@@ -2520,13 +2998,13 @@ var _SelectionCard = ({
|
|
|
2520
2998
|
onSelectionChange
|
|
2521
2999
|
}) => {
|
|
2522
3000
|
const t = useOnboardingTheme();
|
|
2523
|
-
const opts =
|
|
2524
|
-
const [selected, setSelected] =
|
|
2525
|
-
const [submitted, setSubmitted] =
|
|
2526
|
-
|
|
3001
|
+
const opts = React19__default.default.useMemo(() => normalizeOptions(options), [options]);
|
|
3002
|
+
const [selected, setSelected] = React19.useState([]);
|
|
3003
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
3004
|
+
React19.useEffect(() => {
|
|
2527
3005
|
if (!submitted && selected.length) onSelectionChange == null ? void 0 : onSelectionChange(multiSelect ? selected : selected[0]);
|
|
2528
3006
|
}, [selected, submitted, multiSelect, onSelectionChange]);
|
|
2529
|
-
const toggle =
|
|
3007
|
+
const toggle = React19.useCallback(
|
|
2530
3008
|
(value) => {
|
|
2531
3009
|
if (submitted) return;
|
|
2532
3010
|
if (multiSelect) {
|
|
@@ -2537,7 +3015,7 @@ var _SelectionCard = ({
|
|
|
2537
3015
|
},
|
|
2538
3016
|
[submitted, multiSelect]
|
|
2539
3017
|
);
|
|
2540
|
-
const handleSubmit =
|
|
3018
|
+
const handleSubmit = React19.useCallback(() => {
|
|
2541
3019
|
if (!selected.length || !onSelect || submitted) return;
|
|
2542
3020
|
setSubmitted(true);
|
|
2543
3021
|
onSelect(multiSelect ? selected : selected[0]);
|
|
@@ -2571,18 +3049,18 @@ var _SelectionCard = ({
|
|
|
2571
3049
|
var SelectionCard = {
|
|
2572
3050
|
name: "SelectionCard",
|
|
2573
3051
|
description: "Use for mutually exclusive (radio) or multi-select (checkbox) choices from 2\u20138 options, as a vertical list of rows. Best when options are wordy or need reading. Options may carry an optional `icon` from the vocabulary to make the list scannable. Use ChipSelectCard instead when options are short single words; use CardGridSelectCard when the options are visual and each has an obvious icon (occasions, channels, categories).",
|
|
2574
|
-
component:
|
|
2575
|
-
propsSchema:
|
|
3052
|
+
component: React19__default.default.memo(_SelectionCard),
|
|
3053
|
+
propsSchema: schema4,
|
|
2576
3054
|
defaultProps: { submitLabel: "Continue", multiSelect: false }
|
|
2577
3055
|
};
|
|
2578
|
-
var
|
|
3056
|
+
var styles13 = reactNative.StyleSheet.create({
|
|
2579
3057
|
option: { borderWidth: 1.5, flexDirection: "row", alignItems: "center", overflow: "hidden" },
|
|
2580
3058
|
selectedOverlay: { borderWidth: 1.5 },
|
|
2581
3059
|
indicator: { width: 24, height: 24, borderWidth: 2, alignItems: "center", justifyContent: "center" },
|
|
2582
3060
|
check: { fontSize: 13, fontWeight: "800", lineHeight: 15 }
|
|
2583
3061
|
});
|
|
2584
|
-
var
|
|
2585
|
-
var
|
|
3062
|
+
var easeWire7 = reactNative.Easing.bezier(...WIRE_BEZIER);
|
|
3063
|
+
var schema5 = zod.z.object({
|
|
2586
3064
|
title: zod.z.string().describe("Question or prompt for the user, e.g. 'What brings you here?'"),
|
|
2587
3065
|
options: optionsField(
|
|
2588
3066
|
"The choices, 2-6 of them. Give EVERY option an `icon` from the vocabulary \u2014 the icon is the point of this card, and an option without one renders as a bare label next to icon-bearing neighbours. Keep labels short (1-3 words) so they fit a half-width card."
|
|
@@ -2593,9 +3071,9 @@ var schema4 = zod.z.object({
|
|
|
2593
3071
|
var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
2594
3072
|
const t = useOnboardingTheme();
|
|
2595
3073
|
const reduced = useReducedMotion();
|
|
2596
|
-
const handlePress =
|
|
2597
|
-
const pressScale =
|
|
2598
|
-
const pressTo =
|
|
3074
|
+
const handlePress = React19.useCallback(() => onToggle(opt.value), [opt.value, onToggle]);
|
|
3075
|
+
const pressScale = React19.useRef(new reactNative.Animated.Value(1)).current;
|
|
3076
|
+
const pressTo = React19.useCallback(
|
|
2599
3077
|
(to) => {
|
|
2600
3078
|
if (reduced) return;
|
|
2601
3079
|
reactNative.Animated.spring(pressScale, {
|
|
@@ -2607,14 +3085,14 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2607
3085
|
},
|
|
2608
3086
|
[pressScale, reduced]
|
|
2609
3087
|
);
|
|
2610
|
-
const handlePressIn =
|
|
2611
|
-
const handlePressOut =
|
|
2612
|
-
const selectT =
|
|
2613
|
-
|
|
3088
|
+
const handlePressIn = React19.useCallback(() => pressTo(ROW_PRESS_SCALE), [pressTo]);
|
|
3089
|
+
const handlePressOut = React19.useCallback(() => pressTo(1), [pressTo]);
|
|
3090
|
+
const selectT = React19.useRef(new reactNative.Animated.Value(isSelected ? 1 : 0)).current;
|
|
3091
|
+
React19.useEffect(() => {
|
|
2614
3092
|
const anim = reactNative.Animated.timing(selectT, {
|
|
2615
3093
|
toValue: isSelected ? 1 : 0,
|
|
2616
3094
|
duration: scaledMs(stateChangeDuration(reduced, SELECT_FILL_MS)),
|
|
2617
|
-
easing:
|
|
3095
|
+
easing: easeWire7,
|
|
2618
3096
|
useNativeDriver: true
|
|
2619
3097
|
});
|
|
2620
3098
|
anim.start();
|
|
@@ -2629,12 +3107,12 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2629
3107
|
accessibilityRole: multiSelect ? "checkbox" : "radio",
|
|
2630
3108
|
accessibilityState: multiSelect ? { checked: isSelected } : { selected: isSelected },
|
|
2631
3109
|
accessibilityLabel: opt.label,
|
|
2632
|
-
style:
|
|
3110
|
+
style: styles14.cell,
|
|
2633
3111
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2634
3112
|
reactNative.Animated.View,
|
|
2635
3113
|
{
|
|
2636
3114
|
style: [
|
|
2637
|
-
|
|
3115
|
+
styles14.card,
|
|
2638
3116
|
{
|
|
2639
3117
|
padding: t.spacing.md,
|
|
2640
3118
|
borderRadius: t.radius.lg,
|
|
@@ -2651,7 +3129,7 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2651
3129
|
pointerEvents: "none",
|
|
2652
3130
|
style: [
|
|
2653
3131
|
reactNative.StyleSheet.absoluteFill,
|
|
2654
|
-
|
|
3132
|
+
styles14.selectedOverlay,
|
|
2655
3133
|
{
|
|
2656
3134
|
borderRadius: t.radius.lg,
|
|
2657
3135
|
borderColor: t.colors.primary,
|
|
@@ -2669,7 +3147,7 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
|
|
|
2669
3147
|
}
|
|
2670
3148
|
);
|
|
2671
3149
|
};
|
|
2672
|
-
var OptionCard =
|
|
3150
|
+
var OptionCard = React19__default.default.memo(_OptionCard);
|
|
2673
3151
|
var _CardGridSelectCard = ({
|
|
2674
3152
|
title,
|
|
2675
3153
|
options,
|
|
@@ -2679,13 +3157,13 @@ var _CardGridSelectCard = ({
|
|
|
2679
3157
|
onSelectionChange
|
|
2680
3158
|
}) => {
|
|
2681
3159
|
const t = useOnboardingTheme();
|
|
2682
|
-
const opts =
|
|
2683
|
-
const [selected, setSelected] =
|
|
2684
|
-
const [submitted, setSubmitted] =
|
|
2685
|
-
|
|
3160
|
+
const opts = React19__default.default.useMemo(() => normalizeOptions(options), [options]);
|
|
3161
|
+
const [selected, setSelected] = React19.useState([]);
|
|
3162
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
3163
|
+
React19.useEffect(() => {
|
|
2686
3164
|
if (!submitted && selected.length) onSelectionChange == null ? void 0 : onSelectionChange(multiSelect ? selected : selected[0]);
|
|
2687
3165
|
}, [selected, submitted, multiSelect, onSelectionChange]);
|
|
2688
|
-
const toggle =
|
|
3166
|
+
const toggle = React19.useCallback(
|
|
2689
3167
|
(value) => {
|
|
2690
3168
|
if (submitted) return;
|
|
2691
3169
|
if (multiSelect) {
|
|
@@ -2698,7 +3176,7 @@ var _CardGridSelectCard = ({
|
|
|
2698
3176
|
},
|
|
2699
3177
|
[submitted, multiSelect]
|
|
2700
3178
|
);
|
|
2701
|
-
const handleSubmit =
|
|
3179
|
+
const handleSubmit = React19.useCallback(() => {
|
|
2702
3180
|
if (!selected.length || !onSelect || submitted) return;
|
|
2703
3181
|
setSubmitted(true);
|
|
2704
3182
|
onSelect(multiSelect ? selected : selected[0]);
|
|
@@ -2716,7 +3194,7 @@ var _CardGridSelectCard = ({
|
|
|
2716
3194
|
disabled: selected.length === 0 || submitted
|
|
2717
3195
|
}
|
|
2718
3196
|
),
|
|
2719
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
3197
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles14.grid, { gap: t.spacing.sm }], children: opts.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2720
3198
|
OptionCard,
|
|
2721
3199
|
{
|
|
2722
3200
|
opt,
|
|
@@ -2732,19 +3210,19 @@ var _CardGridSelectCard = ({
|
|
|
2732
3210
|
var CardGridSelectCard = {
|
|
2733
3211
|
name: "CardGridSelectCard",
|
|
2734
3212
|
description: "Use for VISUAL, icon-led choices shown as a 2-column grid of tappable cards (icon on top, short label beneath). Ideal for 2\u20136 concrete options that each have an obvious icon \u2014 occasions, channels, goals, categories \u2014 e.g. 'What brings you here?' or 'Where did you hear about us?'. Multi-select by default. Every option should carry an `icon`. Use SelectionCard instead when options need descriptions or have no natural icon; use ChipSelectCard for many short word-like tags.",
|
|
2735
|
-
component:
|
|
2736
|
-
propsSchema:
|
|
3213
|
+
component: React19__default.default.memo(_CardGridSelectCard),
|
|
3214
|
+
propsSchema: schema5,
|
|
2737
3215
|
defaultProps: { submitLabel: "Continue", multiSelect: true }
|
|
2738
3216
|
};
|
|
2739
|
-
var
|
|
3217
|
+
var styles14 = reactNative.StyleSheet.create({
|
|
2740
3218
|
grid: { flexDirection: "row", flexWrap: "wrap" },
|
|
2741
3219
|
// Two per row: ~47% basis leaves room for the gap, flexGrow fills the remainder exactly.
|
|
2742
3220
|
cell: { flexBasis: "47%", flexGrow: 1 },
|
|
2743
3221
|
card: { borderWidth: 1.5, alignItems: "flex-start", overflow: "hidden" },
|
|
2744
3222
|
selectedOverlay: { borderWidth: 1.5 }
|
|
2745
3223
|
});
|
|
2746
|
-
var
|
|
2747
|
-
var
|
|
3224
|
+
var easeWire8 = reactNative.Easing.bezier(...WIRE_BEZIER);
|
|
3225
|
+
var schema6 = zod.z.object({
|
|
2748
3226
|
status: zod.z.enum(["success", "warning", "error", "info"]).describe("Status type"),
|
|
2749
3227
|
title: zod.z.string().describe("Status title"),
|
|
2750
3228
|
message: zod.z.string().optional().describe("Supporting message"),
|
|
@@ -2762,8 +3240,8 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
|
|
|
2762
3240
|
var _a2;
|
|
2763
3241
|
const t = useOnboardingTheme();
|
|
2764
3242
|
const reduced = useReducedMotion();
|
|
2765
|
-
const [submitted, setSubmitted] =
|
|
2766
|
-
const color =
|
|
3243
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
3244
|
+
const color = React19.useMemo(() => {
|
|
2767
3245
|
switch (status) {
|
|
2768
3246
|
case "success":
|
|
2769
3247
|
return t.colors.success;
|
|
@@ -2775,9 +3253,9 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
|
|
|
2775
3253
|
return t.colors.info;
|
|
2776
3254
|
}
|
|
2777
3255
|
}, [status, t.colors]);
|
|
2778
|
-
const popT =
|
|
2779
|
-
const copyT =
|
|
2780
|
-
|
|
3256
|
+
const popT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
3257
|
+
const copyT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
3258
|
+
React19.useEffect(() => {
|
|
2781
3259
|
if (reduced) {
|
|
2782
3260
|
popT.setValue(1);
|
|
2783
3261
|
copyT.setValue(1);
|
|
@@ -2794,7 +3272,7 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
|
|
|
2794
3272
|
toValue: 1,
|
|
2795
3273
|
duration: scaledMs(STATUS_COPY_MS),
|
|
2796
3274
|
delay: scaledMs(STATUS_COPY_STAGGER_MS),
|
|
2797
|
-
easing:
|
|
3275
|
+
easing: easeWire8,
|
|
2798
3276
|
useNativeDriver: true
|
|
2799
3277
|
})
|
|
2800
3278
|
];
|
|
@@ -2803,7 +3281,7 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
|
|
|
2803
3281
|
}, [reduced, popT, copyT]);
|
|
2804
3282
|
const popScale = popT.interpolate({ inputRange: [0, 1], outputRange: [STATUS_POP_SCALE_FROM, 1] });
|
|
2805
3283
|
const copyRise = copyT.interpolate({ inputRange: [0, 1], outputRange: [10, 0] });
|
|
2806
|
-
const handleContinue =
|
|
3284
|
+
const handleContinue = React19.useCallback(() => {
|
|
2807
3285
|
if (!submitted) {
|
|
2808
3286
|
setSubmitted(true);
|
|
2809
3287
|
if (onContinue) onContinue();
|
|
@@ -2816,8 +3294,8 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
|
|
|
2816
3294
|
{
|
|
2817
3295
|
align: "center",
|
|
2818
3296
|
footer: ctaLabel ? /* @__PURE__ */ jsxRuntime.jsx(Button, { title: ctaLabel, onPress: handleContinue, variant: "primary", disabled: submitted }) : void 0,
|
|
2819
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
2820
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
3297
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles15.center, { gap: t.spacing.sm }], children: [
|
|
3298
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles15.titleRow, { gap: t.spacing.sm }], children: [
|
|
2821
3299
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2822
3300
|
reactNative.Animated.Text,
|
|
2823
3301
|
{
|
|
@@ -2861,14 +3339,14 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
|
|
|
2861
3339
|
var StatusCard = {
|
|
2862
3340
|
name: "StatusCard",
|
|
2863
3341
|
description: "Use ONLY for real outcomes: booking confirmed, data saved, action completed. NEVER for 'you just viewed X' acknowledgments. Always include ctaLabel so the user can continue after seeing the status.",
|
|
2864
|
-
component:
|
|
2865
|
-
propsSchema:
|
|
3342
|
+
component: React19__default.default.memo(_StatusCard),
|
|
3343
|
+
propsSchema: schema6
|
|
2866
3344
|
};
|
|
2867
|
-
var
|
|
3345
|
+
var styles15 = reactNative.StyleSheet.create({
|
|
2868
3346
|
center: { width: "100%", alignItems: "center", justifyContent: "center" },
|
|
2869
3347
|
titleRow: { flexDirection: "row", alignItems: "center", justifyContent: "center" }
|
|
2870
3348
|
});
|
|
2871
|
-
var
|
|
3349
|
+
var schema7 = zod.z.object({
|
|
2872
3350
|
label: zod.z.string().describe("What is being counted, e.g. 'Number of days' or 'Travellers'"),
|
|
2873
3351
|
min: zod.z.number().optional().describe("Minimum value, default 1"),
|
|
2874
3352
|
max: zod.z.number().optional().describe("Maximum value, default 30"),
|
|
@@ -2889,22 +3367,22 @@ var _NumberStepperCard = ({
|
|
|
2889
3367
|
onSubmit
|
|
2890
3368
|
}) => {
|
|
2891
3369
|
const t = useOnboardingTheme();
|
|
2892
|
-
const
|
|
3370
|
+
const styles18 = React19.useMemo(() => makeStyles4(t), [t]);
|
|
2893
3371
|
const safeMin = safeNum(min, 1);
|
|
2894
3372
|
const safeMaxRaw = safeNum(max, 30);
|
|
2895
3373
|
const safeMax = safeMaxRaw < safeMin ? safeMin : safeMaxRaw;
|
|
2896
3374
|
const safeStepRaw = safeNum(step, 1);
|
|
2897
3375
|
const safeStep = safeStepRaw > 0 ? safeStepRaw : 1;
|
|
2898
3376
|
const safeDefault = safeNum(defaultValue, safeMin);
|
|
2899
|
-
const [value, setValue] =
|
|
2900
|
-
const [submitted, setSubmitted] =
|
|
2901
|
-
const handleDecrement =
|
|
3377
|
+
const [value, setValue] = React19.useState(Math.min(Math.max(safeDefault, safeMin), safeMax));
|
|
3378
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
3379
|
+
const handleDecrement = React19.useCallback(() => {
|
|
2902
3380
|
if (!submitted) setValue((v) => Math.max(v - safeStep, safeMin));
|
|
2903
3381
|
}, [submitted, safeStep, safeMin]);
|
|
2904
|
-
const handleIncrement =
|
|
3382
|
+
const handleIncrement = React19.useCallback(() => {
|
|
2905
3383
|
if (!submitted) setValue((v) => Math.min(v + safeStep, safeMax));
|
|
2906
3384
|
}, [submitted, safeStep, safeMax]);
|
|
2907
|
-
const handleSubmit =
|
|
3385
|
+
const handleSubmit = React19.useCallback(() => {
|
|
2908
3386
|
if (!submitted) {
|
|
2909
3387
|
setSubmitted(true);
|
|
2910
3388
|
onSubmit == null ? void 0 : onSubmit(value);
|
|
@@ -2913,7 +3391,7 @@ var _NumberStepperCard = ({
|
|
|
2913
3391
|
const atMin = value <= safeMin;
|
|
2914
3392
|
const atMax = value >= safeMax;
|
|
2915
3393
|
const stepBtnStyle = (disabled) => [
|
|
2916
|
-
|
|
3394
|
+
styles18.stepBtn,
|
|
2917
3395
|
{ borderRadius: t.radius.full, backgroundColor: t.colors.background, borderColor: disabled ? t.colors.border : t.colors.primary }
|
|
2918
3396
|
];
|
|
2919
3397
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2922,10 +3400,10 @@ var _NumberStepperCard = ({
|
|
|
2922
3400
|
title: label,
|
|
2923
3401
|
align: "center",
|
|
2924
3402
|
footer: /* @__PURE__ */ jsxRuntime.jsx(Button, { title: submitLabel, onPress: handleSubmit, variant: "primary", disabled: submitted }),
|
|
2925
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2926
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
3403
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles18.wrap, children: [
|
|
3404
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles18.stepper, { gap: t.spacing.lg }], children: [
|
|
2927
3405
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: atMin || submitted ? void 0 : handleDecrement, disabled: atMin || submitted, style: stepBtnStyle(atMin), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [headingStyle(t.fonts), { color: atMin ? t.colors.textMuted : t.colors.primary }], children: "\u2212" }) }),
|
|
2928
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
3406
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles18.valueBox, children: [
|
|
2929
3407
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [headingStyle(t.fonts), { color: t.colors.primary }], children: String(value) }),
|
|
2930
3408
|
unit ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [captionStyle(t.fonts), { color: t.colors.textMuted }], children: unit }) : null
|
|
2931
3409
|
] }),
|
|
@@ -2939,8 +3417,8 @@ var _NumberStepperCard = ({
|
|
|
2939
3417
|
var NumberStepperCard = {
|
|
2940
3418
|
name: "NumberStepperCard",
|
|
2941
3419
|
description: "Use for any bounded numeric input: days, people, portions, budget tiers, ratings. Best for ranges 1\u201399. Set unit (e.g. 'days', 'people') for clarity.",
|
|
2942
|
-
component:
|
|
2943
|
-
propsSchema:
|
|
3420
|
+
component: React19__default.default.memo(_NumberStepperCard),
|
|
3421
|
+
propsSchema: schema7,
|
|
2944
3422
|
defaultProps: { min: 1, max: 30, defaultValue: 1, step: 1, submitLabel: "Confirm" }
|
|
2945
3423
|
};
|
|
2946
3424
|
function makeStyles4(t) {
|
|
@@ -2951,9 +3429,9 @@ function makeStyles4(t) {
|
|
|
2951
3429
|
valueBox: { alignItems: "center", minWidth: 80 }
|
|
2952
3430
|
});
|
|
2953
3431
|
}
|
|
2954
|
-
var
|
|
2955
|
-
var
|
|
2956
|
-
var
|
|
3432
|
+
var easeWire9 = reactNative.Easing.bezier(...WIRE_BEZIER);
|
|
3433
|
+
var RISE_PX2 = 10;
|
|
3434
|
+
var schema8 = zod.z.object({
|
|
2957
3435
|
title: zod.z.string().describe("Short, warm headline for the value/momentum moment"),
|
|
2958
3436
|
body: zod.z.string().optional().describe("One or two supporting lines that reflect the user's answers back and build momentum"),
|
|
2959
3437
|
items: zod.z.array(zod.z.string()).max(4).optional().describe(
|
|
@@ -2977,9 +3455,9 @@ var _WorkItem = ({
|
|
|
2977
3455
|
reduced
|
|
2978
3456
|
}) => {
|
|
2979
3457
|
const t = useOnboardingTheme();
|
|
2980
|
-
const rowT =
|
|
2981
|
-
const checkT =
|
|
2982
|
-
|
|
3458
|
+
const rowT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
3459
|
+
const checkT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
3460
|
+
React19.useEffect(() => {
|
|
2983
3461
|
if (reduced) {
|
|
2984
3462
|
rowT.setValue(1);
|
|
2985
3463
|
checkT.setValue(1);
|
|
@@ -2990,7 +3468,7 @@ var _WorkItem = ({
|
|
|
2990
3468
|
toValue: 1,
|
|
2991
3469
|
duration: scaledMs(INTERSTITIAL_ITEM_MS),
|
|
2992
3470
|
delay: scaledMs(interstitialItemDelay(index)),
|
|
2993
|
-
easing:
|
|
3471
|
+
easing: easeWire9,
|
|
2994
3472
|
useNativeDriver: true
|
|
2995
3473
|
}),
|
|
2996
3474
|
reactNative.Animated.spring(checkT, {
|
|
@@ -3004,7 +3482,7 @@ var _WorkItem = ({
|
|
|
3004
3482
|
anims.forEach((a) => a.start());
|
|
3005
3483
|
return () => anims.forEach((a) => a.stop());
|
|
3006
3484
|
}, [reduced, index, rowT, checkT]);
|
|
3007
|
-
const rise = rowT.interpolate({ inputRange: [0, 1], outputRange: [
|
|
3485
|
+
const rise = rowT.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX2, 0] });
|
|
3008
3486
|
const checkScale = checkT.interpolate({
|
|
3009
3487
|
inputRange: [0, 1],
|
|
3010
3488
|
outputRange: [INTERSTITIAL_CHECK_SCALE_FROM, 1]
|
|
@@ -3012,20 +3490,20 @@ var _WorkItem = ({
|
|
|
3012
3490
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3013
3491
|
reactNative.Animated.View,
|
|
3014
3492
|
{
|
|
3015
|
-
style: [
|
|
3493
|
+
style: [styles16.itemRow, { gap: t.spacing.sm + t.spacing.xs, opacity: rowT, transform: [{ translateY: rise }] }],
|
|
3016
3494
|
children: [
|
|
3017
3495
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3018
3496
|
reactNative.View,
|
|
3019
3497
|
{
|
|
3020
3498
|
style: [
|
|
3021
|
-
|
|
3499
|
+
styles16.itemBadge,
|
|
3022
3500
|
{ backgroundColor: t.colors.primarySoft, borderRadius: t.radius.full }
|
|
3023
3501
|
],
|
|
3024
3502
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3025
3503
|
reactNative.Animated.Text,
|
|
3026
3504
|
{
|
|
3027
3505
|
style: [
|
|
3028
|
-
|
|
3506
|
+
styles16.itemCheck,
|
|
3029
3507
|
{ color: t.colors.primary, opacity: checkT, transform: [{ scale: checkScale }] }
|
|
3030
3508
|
],
|
|
3031
3509
|
children: "\u2713"
|
|
@@ -3033,12 +3511,12 @@ var _WorkItem = ({
|
|
|
3033
3511
|
)
|
|
3034
3512
|
}
|
|
3035
3513
|
),
|
|
3036
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts),
|
|
3514
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), styles16.itemText, { color: t.colors.text }], children: text })
|
|
3037
3515
|
]
|
|
3038
3516
|
}
|
|
3039
3517
|
);
|
|
3040
3518
|
};
|
|
3041
|
-
var WorkItem =
|
|
3519
|
+
var WorkItem = React19__default.default.memo(_WorkItem);
|
|
3042
3520
|
var _InterstitialCard = ({
|
|
3043
3521
|
title,
|
|
3044
3522
|
body,
|
|
@@ -3054,17 +3532,17 @@ var _InterstitialCard = ({
|
|
|
3054
3532
|
const reduced = useReducedMotion();
|
|
3055
3533
|
const node = useIllustration(illustration);
|
|
3056
3534
|
const fallbackNode = useIllustration(illustrationFallback);
|
|
3057
|
-
const [submitted, setSubmitted] =
|
|
3058
|
-
const [imgFailed, setImgFailed] =
|
|
3059
|
-
const [canAdvance, setCanAdvance] =
|
|
3060
|
-
|
|
3535
|
+
const [submitted, setSubmitted] = React19.useState(false);
|
|
3536
|
+
const [imgFailed, setImgFailed] = React19.useState(false);
|
|
3537
|
+
const [canAdvance, setCanAdvance] = React19.useState(false);
|
|
3538
|
+
React19.useEffect(() => {
|
|
3061
3539
|
const timer = setTimeout(() => setCanAdvance(true), MIN_DISPLAY_MS);
|
|
3062
3540
|
return () => clearTimeout(timer);
|
|
3063
3541
|
}, []);
|
|
3064
|
-
const artT =
|
|
3065
|
-
const titleT =
|
|
3066
|
-
const bodyT =
|
|
3067
|
-
|
|
3542
|
+
const artT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
3543
|
+
const titleT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
3544
|
+
const bodyT = React19.useRef(new reactNative.Animated.Value(reduced ? 1 : 0)).current;
|
|
3545
|
+
React19.useEffect(() => {
|
|
3068
3546
|
if (reduced) {
|
|
3069
3547
|
artT.setValue(1);
|
|
3070
3548
|
titleT.setValue(1);
|
|
@@ -3075,7 +3553,7 @@ var _InterstitialCard = ({
|
|
|
3075
3553
|
toValue: 1,
|
|
3076
3554
|
duration: scaledMs(INTERSTITIAL_HEAD_MS),
|
|
3077
3555
|
delay,
|
|
3078
|
-
easing:
|
|
3556
|
+
easing: easeWire9,
|
|
3079
3557
|
useNativeDriver: true
|
|
3080
3558
|
});
|
|
3081
3559
|
const anims = [
|
|
@@ -3088,9 +3566,9 @@ var _InterstitialCard = ({
|
|
|
3088
3566
|
}, [reduced, artT, titleT, bodyT]);
|
|
3089
3567
|
const riseStyle = (value) => ({
|
|
3090
3568
|
opacity: value,
|
|
3091
|
-
transform: [{ translateY: value.interpolate({ inputRange: [0, 1], outputRange: [
|
|
3569
|
+
transform: [{ translateY: value.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX2, 0] }) }]
|
|
3092
3570
|
});
|
|
3093
|
-
const handleContinue =
|
|
3571
|
+
const handleContinue = React19.useCallback(() => {
|
|
3094
3572
|
if (submitted || !canAdvance) return;
|
|
3095
3573
|
setSubmitted(true);
|
|
3096
3574
|
if (onSubmit) onSubmit("continue");
|
|
@@ -3111,18 +3589,18 @@ var _InterstitialCard = ({
|
|
|
3111
3589
|
disabled: submitted || !canAdvance
|
|
3112
3590
|
}
|
|
3113
3591
|
),
|
|
3114
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
3115
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: [
|
|
3592
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles16.center, { gap: t.spacing.md }], children: [
|
|
3593
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: [styles16.fullWidth, riseStyle(artT)], children: showImage ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3116
3594
|
reactNative.Image,
|
|
3117
3595
|
{
|
|
3118
3596
|
source: { uri: imageUrl },
|
|
3119
|
-
style:
|
|
3597
|
+
style: styles16.image,
|
|
3120
3598
|
resizeMode: "contain",
|
|
3121
3599
|
onError: () => setImgFailed(true)
|
|
3122
3600
|
}
|
|
3123
|
-
) : art ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
3601
|
+
) : art ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles16.art, children: art }) : null }),
|
|
3124
3602
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: riseStyle(titleT), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [headingStyle(t.fonts), { color: t.colors.text, textAlign: "center" }], children: title }) }),
|
|
3125
|
-
(items == null ? void 0 : items.length) ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
3603
|
+
(items == null ? void 0 : items.length) ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles16.items, { gap: t.spacing.md, marginTop: t.spacing.sm }], children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(WorkItem, { text: item, index: i, reduced }, `${item}-${i}`)) }) : body ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: riseStyle(bodyT), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted, textAlign: "center" }], children: body }) }) : null
|
|
3126
3604
|
] })
|
|
3127
3605
|
}
|
|
3128
3606
|
);
|
|
@@ -3130,11 +3608,11 @@ var _InterstitialCard = ({
|
|
|
3130
3608
|
var InterstitialCard = {
|
|
3131
3609
|
name: "InterstitialCard",
|
|
3132
3610
|
description: "Use ONCE mid-flow (never first, never last) as a momentum/value screen between questions \u2014 an illustration + a warm line that reflects answers back, like Duolingo/Cal-AI. NOT a question; the user just taps Continue. Set `illustration` to an app-registered artwork name. Prefer `items` (2-3 short ticked lines, each reflecting a real answer) when you have the signal. Skip it if you don't have enough signal to make the line specific.",
|
|
3133
|
-
component:
|
|
3134
|
-
propsSchema:
|
|
3611
|
+
component: React19__default.default.memo(_InterstitialCard),
|
|
3612
|
+
propsSchema: schema8,
|
|
3135
3613
|
defaultProps: { ctaLabel: "Continue", illustrationFallback: "momentum" }
|
|
3136
3614
|
};
|
|
3137
|
-
var
|
|
3615
|
+
var styles16 = reactNative.StyleSheet.create({
|
|
3138
3616
|
center: { width: "100%", alignItems: "center", justifyContent: "center" },
|
|
3139
3617
|
fullWidth: { width: "100%", alignItems: "center" },
|
|
3140
3618
|
art: { alignItems: "center", justifyContent: "center" },
|
|
@@ -3454,15 +3932,6 @@ var resetAutoDeviceKeys = () => {
|
|
|
3454
3932
|
(_a2 = registry.pending) == null ? void 0 : _a2.clear();
|
|
3455
3933
|
};
|
|
3456
3934
|
|
|
3457
|
-
// src/utils/warnInDev.ts
|
|
3458
|
-
var warnInDev = (message) => {
|
|
3459
|
-
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
3460
|
-
console.warn(message);
|
|
3461
|
-
return true;
|
|
3462
|
-
}
|
|
3463
|
-
return false;
|
|
3464
|
-
};
|
|
3465
|
-
|
|
3466
3935
|
// src/analytics/currentSession.ts
|
|
3467
3936
|
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
3468
3937
|
"@wireai/activation:currentSessionId"
|
|
@@ -3667,6 +4136,43 @@ var resolveUserContext = (ctx = {}, opts = {}) => {
|
|
|
3667
4136
|
if (Object.keys(bucket).length > 0) result.userContext = bucket;
|
|
3668
4137
|
return result;
|
|
3669
4138
|
};
|
|
4139
|
+
|
|
4140
|
+
// src/permissions/permissionMemory.ts
|
|
4141
|
+
var permissionStorageKey = (appId) => `wireai:permissions:${appId}`;
|
|
4142
|
+
var readSettledPermissions = (raw, sessionId) => {
|
|
4143
|
+
if (!raw || !sessionId) return [];
|
|
4144
|
+
try {
|
|
4145
|
+
const parsed = JSON.parse(raw);
|
|
4146
|
+
if (typeof parsed !== "object" || parsed === null) return [];
|
|
4147
|
+
const record = parsed;
|
|
4148
|
+
if (record.sessionId !== sessionId || !Array.isArray(record.ids)) return [];
|
|
4149
|
+
return record.ids.filter((id) => typeof id === "string" && id.length > 0);
|
|
4150
|
+
} catch {
|
|
4151
|
+
return [];
|
|
4152
|
+
}
|
|
4153
|
+
};
|
|
4154
|
+
var loadSettledPermissions = async (storage, key, sessionId) => {
|
|
4155
|
+
try {
|
|
4156
|
+
return readSettledPermissions(await withTimeout(storage.getItem(key), READ_TIMEOUT_MS), sessionId);
|
|
4157
|
+
} catch {
|
|
4158
|
+
return [];
|
|
4159
|
+
}
|
|
4160
|
+
};
|
|
4161
|
+
var saveSettledPermissions = (storage, key, sessionId, ids) => {
|
|
4162
|
+
try {
|
|
4163
|
+
const record = { sessionId, ids: [...ids] };
|
|
4164
|
+
void storage.setItem(key, JSON.stringify(record)).catch(() => {
|
|
4165
|
+
});
|
|
4166
|
+
} catch {
|
|
4167
|
+
}
|
|
4168
|
+
};
|
|
4169
|
+
var clearSettledPermissions = (storage, key) => {
|
|
4170
|
+
try {
|
|
4171
|
+
void storage.removeItem(key).catch(() => {
|
|
4172
|
+
});
|
|
4173
|
+
} catch {
|
|
4174
|
+
}
|
|
4175
|
+
};
|
|
3670
4176
|
var AUTO_JOIN_HYDRATION_TIMEOUT_MS = 1500;
|
|
3671
4177
|
var WireOnboarding = ({
|
|
3672
4178
|
config,
|
|
@@ -3691,20 +4197,21 @@ var WireOnboarding = ({
|
|
|
3691
4197
|
retainSessionOnComplete,
|
|
3692
4198
|
userContext,
|
|
3693
4199
|
userId,
|
|
3694
|
-
autoJoinKey = true
|
|
4200
|
+
autoJoinKey = true,
|
|
4201
|
+
permissionScreens
|
|
3695
4202
|
}) => {
|
|
3696
|
-
var _a2, _b, _c, _d, _e;
|
|
3697
|
-
const boundUserId =
|
|
3698
|
-
const device =
|
|
4203
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
4204
|
+
const boundUserId = React19.useMemo(() => sanitizeUserId(userId), [userId]);
|
|
4205
|
+
const device = React19.useMemo(() => {
|
|
3699
4206
|
const collected = collectDeviceContext();
|
|
3700
4207
|
return config.appVersion ? { ...collected, appVersion: config.appVersion } : collected;
|
|
3701
4208
|
}, [config.appVersion]);
|
|
3702
4209
|
const userContextKey = userContext ? JSON.stringify(userContext) : "";
|
|
3703
|
-
const userContextStable =
|
|
4210
|
+
const userContextStable = React19.useMemo(
|
|
3704
4211
|
() => userContextKey ? JSON.parse(userContextKey) : void 0,
|
|
3705
4212
|
[userContextKey]
|
|
3706
4213
|
);
|
|
3707
|
-
const hostJoinIdentity =
|
|
4214
|
+
const hostJoinIdentity = React19.useMemo(
|
|
3708
4215
|
() => resolveIdentity({
|
|
3709
4216
|
value: userContextStable == null ? void 0 : userContextStable.device_key,
|
|
3710
4217
|
space: "device",
|
|
@@ -3716,8 +4223,8 @@ var WireOnboarding = ({
|
|
|
3716
4223
|
const missingJoinKey = !hostJoinIdentity;
|
|
3717
4224
|
const autoJoinPossible = Boolean(storage) && autoJoinKey !== false;
|
|
3718
4225
|
const wantsAutoJoin = missingJoinKey && autoJoinPossible;
|
|
3719
|
-
const [autoJoinOutcome, setAutoJoinOutcome] =
|
|
3720
|
-
|
|
4226
|
+
const [autoJoinOutcome, setAutoJoinOutcome] = React19.useState(void 0);
|
|
4227
|
+
React19.useEffect(() => {
|
|
3721
4228
|
if (!wantsAutoJoin || autoJoinOutcome !== void 0 || !storage) return;
|
|
3722
4229
|
let cancelled = false;
|
|
3723
4230
|
const timer = setTimeout(() => {
|
|
@@ -3737,22 +4244,22 @@ var WireOnboarding = ({
|
|
|
3737
4244
|
}, [wantsAutoJoin, autoJoinOutcome, config.appId, storage]);
|
|
3738
4245
|
const injectedJoinKey = wantsAutoJoin ? (_a2 = autoJoinOutcome == null ? void 0 : autoJoinOutcome.key) != null ? _a2 : void 0 : void 0;
|
|
3739
4246
|
const autoJoinPending = wantsAutoJoin && autoJoinOutcome === void 0;
|
|
3740
|
-
const effectiveUserContext =
|
|
4247
|
+
const effectiveUserContext = React19.useMemo(
|
|
3741
4248
|
() => injectedJoinKey ? { ...userContextStable, ...activationJoinContext(injectedJoinKey) } : userContextStable,
|
|
3742
4249
|
[userContextStable, injectedJoinKey]
|
|
3743
4250
|
);
|
|
3744
|
-
const frozenWireContextRef =
|
|
4251
|
+
const frozenWireContextRef = React19.useRef(null);
|
|
3745
4252
|
if (!autoJoinPending && frozenWireContextRef.current === null) {
|
|
3746
4253
|
frozenWireContextRef.current = effectiveUserContext ? JSON.stringify(effectiveUserContext) : "";
|
|
3747
4254
|
}
|
|
3748
4255
|
const startupUserContextKey = (_b = frozenWireContextRef.current) != null ? _b : "";
|
|
3749
|
-
const startupUserContext =
|
|
4256
|
+
const startupUserContext = React19.useMemo(
|
|
3750
4257
|
() => startupUserContextKey ? JSON.parse(startupUserContextKey) : void 0,
|
|
3751
4258
|
[startupUserContextKey]
|
|
3752
4259
|
);
|
|
3753
4260
|
const warnMissingJoinKey = missingJoinKey && !injectedJoinKey && !autoJoinPending;
|
|
3754
4261
|
const autoJoinReason = autoJoinKey === false ? "you passed autoJoinKey={false}." : !storage ? "it got no `storage` prop, and without persistence its key would be different on every launch, which corrupts min_sessions instead of merely leaving the join empty." : (autoJoinOutcome == null ? void 0 : autoJoinOutcome.key) === null && autoJoinOutcome.reason === "not-durable" ? "your `storage` adapter answered but could not persist the key (the read or the write failed), so the key would be different on every launch, which corrupts min_sessions instead of merely leaving the join empty. Check the adapter you passed as `storage`." : "your `storage` adapter did not answer in time.";
|
|
3755
|
-
|
|
4262
|
+
React19.useEffect(() => {
|
|
3756
4263
|
if (!warnMissingJoinKey) return;
|
|
3757
4264
|
warnInDev(
|
|
3758
4265
|
"[wireai] <WireOnboarding> got no user_context.device_key, so this onboarding session can never be joined to the app's later events and the `activated` funnel will read zero. Pass userContext={activationJoinContext(deviceKey)} \u2014 and if your app owns no device id, userContext={activationJoinContext(resolveAutoDeviceKey({ appId, storage }))} returns the SAME id the analytics side stamps. Never hand-write userContext={{ deviceKey }}. The kit did NOT auto-inject its own key here because " + autoJoinReason
|
|
@@ -3760,28 +4267,29 @@ var WireOnboarding = ({
|
|
|
3760
4267
|
}, [warnMissingJoinKey, autoJoinReason]);
|
|
3761
4268
|
const hostKeyElsewhere = missingJoinKey ? hostIdentity("device", config.appId) : void 0;
|
|
3762
4269
|
const warnHostKeyElsewhere = Boolean(hostKeyElsewhere) && Boolean(injectedJoinKey);
|
|
3763
|
-
|
|
4270
|
+
React19.useEffect(() => {
|
|
3764
4271
|
if (!warnHostKeyElsewhere) return;
|
|
3765
4272
|
warnInDev(
|
|
3766
4273
|
`[wireai] <WireOnboarding> got no user_context.device_key, so the kit injected its own \u2014 but another surface in this app was constructed WITH a host-supplied device key ("${hostKeyElsewhere}"). Your app events carry that id and this onboarding session carries the kit's, so the two land in disjoint id spaces and the \`activated\` funnel still reads zero. Pass the SAME id here: userContext={activationJoinContext(deviceKey)}.`
|
|
3767
4274
|
);
|
|
3768
4275
|
}, [warnHostKeyElsewhere, hostKeyElsewhere]);
|
|
3769
4276
|
const misspelledJoinKey = missingJoinKey && typeof (userContextStable == null ? void 0 : userContextStable.deviceKey) === "string" && Boolean(userContextStable.deviceKey.trim());
|
|
3770
|
-
|
|
4277
|
+
React19.useEffect(() => {
|
|
3771
4278
|
if (!misspelledJoinKey || !injectedJoinKey) return;
|
|
3772
4279
|
warnInDev(
|
|
3773
4280
|
"[wireai] <WireOnboarding> got userContext={{ deviceKey }}, which is NOT the wire key \u2014 the server's device lookup reads `device_key`. The kit auto-injected its own device_key so this session is at least self-consistent, but your app's own events carry YOUR id, so the two still will not join and the `activated` funnel stays zero. Pass userContext={activationJoinContext(deviceKey)} instead."
|
|
3774
4281
|
);
|
|
3775
4282
|
}, [misspelledJoinKey, injectedJoinKey]);
|
|
3776
|
-
const clientContext =
|
|
4283
|
+
const clientContext = React19.useMemo(
|
|
3777
4284
|
() => ({ device, userContext: effectiveUserContext, userId: boundUserId }),
|
|
3778
4285
|
[device, effectiveUserContext, boundUserId]
|
|
3779
4286
|
);
|
|
3780
|
-
const [session, setSession] =
|
|
4287
|
+
const [session, setSession] = React19.useState(
|
|
3781
4288
|
() => storage ? null : { id: makeSessionId(), resumed: false }
|
|
3782
4289
|
);
|
|
3783
4290
|
const storageKey = persistKey != null ? persistKey : sessionStorageKey(config.appId);
|
|
3784
|
-
|
|
4291
|
+
const permissionsKey = permissionStorageKey(config.appId);
|
|
4292
|
+
React19.useEffect(() => {
|
|
3785
4293
|
if (!storage || session) return;
|
|
3786
4294
|
let cancelled = false;
|
|
3787
4295
|
void loadPersistedSession(storage, storageKey, sessionTtlMs).then((loaded) => {
|
|
@@ -3791,20 +4299,51 @@ var WireOnboarding = ({
|
|
|
3791
4299
|
cancelled = true;
|
|
3792
4300
|
};
|
|
3793
4301
|
}, [storage, storageKey, sessionTtlMs, session]);
|
|
3794
|
-
const handleComplete =
|
|
4302
|
+
const handleComplete = React19.useCallback(
|
|
3795
4303
|
(result) => {
|
|
3796
|
-
if (storage && shouldClearOnComplete(retainSessionOnComplete))
|
|
4304
|
+
if (storage && shouldClearOnComplete(retainSessionOnComplete)) {
|
|
4305
|
+
clearPersistedSession(storage, storageKey);
|
|
4306
|
+
clearSettledPermissions(storage, permissionsKey);
|
|
4307
|
+
}
|
|
3797
4308
|
onComplete(result);
|
|
3798
4309
|
},
|
|
3799
|
-
[storage, storageKey, retainSessionOnComplete, onComplete]
|
|
4310
|
+
[storage, storageKey, permissionsKey, retainSessionOnComplete, onComplete]
|
|
3800
4311
|
);
|
|
3801
4312
|
const sessionId = (_c = session == null ? void 0 : session.id) != null ? _c : "";
|
|
3802
|
-
const
|
|
4313
|
+
const wantsPermissionMemory = Boolean(storage) && ((_d = permissionScreens == null ? void 0 : permissionScreens.length) != null ? _d : 0) > 0;
|
|
4314
|
+
const [settledPermissions, setSettledPermissions] = React19.useState(void 0);
|
|
4315
|
+
React19.useEffect(() => {
|
|
4316
|
+
if (!wantsPermissionMemory || !storage || !sessionId || settledPermissions !== void 0) return;
|
|
4317
|
+
let cancelled = false;
|
|
4318
|
+
void loadSettledPermissions(storage, permissionsKey, sessionId).then((ids) => {
|
|
4319
|
+
if (!cancelled) setSettledPermissions(ids);
|
|
4320
|
+
});
|
|
4321
|
+
return () => {
|
|
4322
|
+
cancelled = true;
|
|
4323
|
+
};
|
|
4324
|
+
}, [wantsPermissionMemory, storage, permissionsKey, sessionId, settledPermissions]);
|
|
4325
|
+
const settledPermissionsRef = React19.useRef(void 0);
|
|
4326
|
+
settledPermissionsRef.current = settledPermissions;
|
|
4327
|
+
const handlePermissionSettled = React19.useCallback(
|
|
4328
|
+
(id) => {
|
|
4329
|
+
var _a3;
|
|
4330
|
+
const current = (_a3 = settledPermissionsRef.current) != null ? _a3 : [];
|
|
4331
|
+
if (current.includes(id)) return;
|
|
4332
|
+
const next = [...current, id];
|
|
4333
|
+
settledPermissionsRef.current = next;
|
|
4334
|
+
setSettledPermissions(next);
|
|
4335
|
+
if (storage && wantsPermissionMemory && sessionId) {
|
|
4336
|
+
saveSettledPermissions(storage, permissionsKey, sessionId, next);
|
|
4337
|
+
}
|
|
4338
|
+
},
|
|
4339
|
+
[storage, wantsPermissionMemory, permissionsKey, sessionId]
|
|
4340
|
+
);
|
|
4341
|
+
const startupUserIdRef = React19.useRef(boundUserId);
|
|
3803
4342
|
const metadataKey = config.metadata ? JSON.stringify(config.metadata) : "";
|
|
3804
|
-
const metadataStable =
|
|
4343
|
+
const metadataStable = React19.useMemo(() => metadataKey ? JSON.parse(metadataKey) : void 0, [metadataKey]);
|
|
3805
4344
|
const componentNamesKey = (components != null ? components : onboardingComponents).map((c) => c.name).join(",");
|
|
3806
|
-
const componentsStable =
|
|
3807
|
-
const llm =
|
|
4345
|
+
const componentsStable = React19.useMemo(() => components != null ? components : onboardingComponents, [componentNamesKey]);
|
|
4346
|
+
const llm = React19.useMemo(() => {
|
|
3808
4347
|
const baseUrl = config.serverUrl.replace(/\/$/, "");
|
|
3809
4348
|
return {
|
|
3810
4349
|
provider: "a2a",
|
|
@@ -3834,13 +4373,13 @@ var WireOnboarding = ({
|
|
|
3834
4373
|
timeoutMs: 6e4
|
|
3835
4374
|
};
|
|
3836
4375
|
}, [config.serverUrl, config.appId, config.apiKey, metadataStable, sessionId, componentsStable, device, startupUserContext]);
|
|
3837
|
-
const reportTarget =
|
|
4376
|
+
const reportTarget = React19.useMemo(
|
|
3838
4377
|
() => ({ serverUrl: config.serverUrl, apiKey: config.apiKey }),
|
|
3839
4378
|
[config.serverUrl, config.apiKey]
|
|
3840
4379
|
);
|
|
3841
|
-
const identifiedRef =
|
|
3842
|
-
const identifySeededRef =
|
|
3843
|
-
|
|
4380
|
+
const identifiedRef = React19.useRef(void 0);
|
|
4381
|
+
const identifySeededRef = React19.useRef(false);
|
|
4382
|
+
React19.useEffect(() => {
|
|
3844
4383
|
if (!session || !sessionId) return;
|
|
3845
4384
|
if (!identifySeededRef.current) {
|
|
3846
4385
|
identifySeededRef.current = true;
|
|
@@ -3859,8 +4398,8 @@ var WireOnboarding = ({
|
|
|
3859
4398
|
return /* @__PURE__ */ jsxRuntime.jsx(OnboardingThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3860
4399
|
LoadingScreen,
|
|
3861
4400
|
{
|
|
3862
|
-
title: (
|
|
3863
|
-
hint: (
|
|
4401
|
+
title: (_e = copy == null ? void 0 : copy.restoringTitle) != null ? _e : DEFAULT_COPY.restoringTitle,
|
|
4402
|
+
hint: (_f = copy == null ? void 0 : copy.restoringHint) != null ? _f : DEFAULT_COPY.restoringHint
|
|
3864
4403
|
}
|
|
3865
4404
|
) });
|
|
3866
4405
|
}
|
|
@@ -3881,7 +4420,11 @@ var WireOnboarding = ({
|
|
|
3881
4420
|
reportTarget,
|
|
3882
4421
|
sessionId,
|
|
3883
4422
|
resumed: session.resumed,
|
|
3884
|
-
clientContext
|
|
4423
|
+
clientContext,
|
|
4424
|
+
permissionScreens,
|
|
4425
|
+
settledPermissions,
|
|
4426
|
+
permissionsPending: wantsPermissionMemory && settledPermissions === void 0,
|
|
4427
|
+
onPermissionSettled: handlePermissionSettled
|
|
3885
4428
|
}
|
|
3886
4429
|
) }) }) }) });
|
|
3887
4430
|
};
|
|
@@ -3895,16 +4438,16 @@ function DemoOnboarding({
|
|
|
3895
4438
|
onComplete,
|
|
3896
4439
|
renderTrigger
|
|
3897
4440
|
}) {
|
|
3898
|
-
const [open, setOpen] =
|
|
3899
|
-
const [runId, setRunId] =
|
|
3900
|
-
const t =
|
|
3901
|
-
const
|
|
3902
|
-
const openDemo =
|
|
4441
|
+
const [open, setOpen] = React19.useState(false);
|
|
4442
|
+
const [runId, setRunId] = React19.useState(0);
|
|
4443
|
+
const t = React19.useMemo(() => mergeTheme(theme != null ? theme : {}), [theme]);
|
|
4444
|
+
const styles18 = React19.useMemo(() => makeStyles5(t), [t]);
|
|
4445
|
+
const openDemo = React19.useCallback(() => {
|
|
3903
4446
|
setRunId((n) => n + 1);
|
|
3904
4447
|
setOpen(true);
|
|
3905
4448
|
}, []);
|
|
3906
|
-
const close =
|
|
3907
|
-
const finish =
|
|
4449
|
+
const close = React19.useCallback(() => setOpen(false), []);
|
|
4450
|
+
const finish = React19.useCallback(
|
|
3908
4451
|
(result) => {
|
|
3909
4452
|
onComplete == null ? void 0 : onComplete(result);
|
|
3910
4453
|
setOpen(false);
|
|
@@ -3912,7 +4455,7 @@ function DemoOnboarding({
|
|
|
3912
4455
|
[onComplete]
|
|
3913
4456
|
);
|
|
3914
4457
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3915
|
-
renderTrigger ? renderTrigger(openDemo) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: openDemo, style:
|
|
4458
|
+
renderTrigger ? renderTrigger(openDemo) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: openDemo, style: styles18.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles18.triggerText, children: label }) }),
|
|
3916
4459
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3917
4460
|
reactNative.Modal,
|
|
3918
4461
|
{
|
|
@@ -3920,7 +4463,7 @@ function DemoOnboarding({
|
|
|
3920
4463
|
animationType: "slide",
|
|
3921
4464
|
presentationStyle: "fullScreen",
|
|
3922
4465
|
onRequestClose: close,
|
|
3923
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
4466
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles18.modal, children: config ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3924
4467
|
WireOnboarding,
|
|
3925
4468
|
{
|
|
3926
4469
|
config,
|
|
@@ -3933,10 +4476,10 @@ function DemoOnboarding({
|
|
|
3933
4476
|
onError: close
|
|
3934
4477
|
},
|
|
3935
4478
|
runId
|
|
3936
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
3937
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
3938
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
3939
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: close, style:
|
|
4479
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles18.notice, children: [
|
|
4480
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles18.noticeTitle, children: "Wire AI not configured" }),
|
|
4481
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles18.noticeBody, children: "Set the Wire AI key + server URL (e.g. via wireConfigFromEnv) to demo the AI onboarding here." }),
|
|
4482
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: close, style: styles18.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles18.triggerText, children: "Close" }) })
|
|
3940
4483
|
] }) })
|
|
3941
4484
|
}
|
|
3942
4485
|
)
|
|
@@ -4022,13 +4565,13 @@ var CENTERED_MODAL_ANIM = {
|
|
|
4022
4565
|
/** Peak dim of the backdrop at progress 1. */
|
|
4023
4566
|
backdropOpacity: 0.55
|
|
4024
4567
|
};
|
|
4025
|
-
var _CenteredModal =
|
|
4568
|
+
var _CenteredModal = React19.forwardRef(
|
|
4026
4569
|
({ theme, dismissible = true, onDismiss, children }, ref) => {
|
|
4027
|
-
const progress =
|
|
4028
|
-
const [open, setOpen] =
|
|
4029
|
-
const closingRef =
|
|
4570
|
+
const progress = React19.useRef(new reactNative.Animated.Value(0)).current;
|
|
4571
|
+
const [open, setOpen] = React19.useState(true);
|
|
4572
|
+
const closingRef = React19.useRef(false);
|
|
4030
4573
|
const reduced = useReducedMotion();
|
|
4031
|
-
|
|
4574
|
+
React19.useEffect(() => {
|
|
4032
4575
|
const anim = reduced ? reactNative.Animated.timing(progress, {
|
|
4033
4576
|
toValue: 1,
|
|
4034
4577
|
duration: REDUCED_FADE_MS,
|
|
@@ -4042,7 +4585,7 @@ var _CenteredModal = React18.forwardRef(
|
|
|
4042
4585
|
anim.start();
|
|
4043
4586
|
return () => anim.stop();
|
|
4044
4587
|
}, [progress, reduced]);
|
|
4045
|
-
const close =
|
|
4588
|
+
const close = React19.useCallback(() => {
|
|
4046
4589
|
if (closingRef.current) return;
|
|
4047
4590
|
closingRef.current = true;
|
|
4048
4591
|
reactNative.Animated.timing(progress, {
|
|
@@ -4055,15 +4598,15 @@ var _CenteredModal = React18.forwardRef(
|
|
|
4055
4598
|
onDismiss();
|
|
4056
4599
|
});
|
|
4057
4600
|
}, [progress, onDismiss, reduced]);
|
|
4058
|
-
|
|
4059
|
-
|
|
4601
|
+
React19.useImperativeHandle(ref, () => ({ close }), [close]);
|
|
4602
|
+
React19.useEffect(() => {
|
|
4060
4603
|
const sub = reactNative.BackHandler.addEventListener("hardwareBackPress", () => {
|
|
4061
4604
|
if (dismissible) close();
|
|
4062
4605
|
return true;
|
|
4063
4606
|
});
|
|
4064
4607
|
return () => sub.remove();
|
|
4065
4608
|
}, [dismissible, close]);
|
|
4066
|
-
const onBackdrop =
|
|
4609
|
+
const onBackdrop = React19.useCallback(() => {
|
|
4067
4610
|
if (dismissible) close();
|
|
4068
4611
|
}, [dismissible, close]);
|
|
4069
4612
|
const backdropOpacity = progress.interpolate({
|
|
@@ -4086,25 +4629,25 @@ var _CenteredModal = React18.forwardRef(
|
|
|
4086
4629
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4087
4630
|
reactNative.Animated.View,
|
|
4088
4631
|
{
|
|
4089
|
-
style: [
|
|
4632
|
+
style: [styles17.backdrop, { opacity: backdropOpacity }],
|
|
4090
4633
|
pointerEvents: "none"
|
|
4091
4634
|
}
|
|
4092
4635
|
),
|
|
4093
4636
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4094
4637
|
reactNative.Pressable,
|
|
4095
4638
|
{
|
|
4096
|
-
style:
|
|
4639
|
+
style: styles17.fill,
|
|
4097
4640
|
onPress: onBackdrop,
|
|
4098
4641
|
accessibilityRole: "button",
|
|
4099
4642
|
accessibilityLabel: "Dismiss",
|
|
4100
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSafeAreaContext.SafeAreaView, { style:
|
|
4101
|
-
}, style:
|
|
4643
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSafeAreaContext.SafeAreaView, { style: styles17.center, pointerEvents: "box-none", children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: () => {
|
|
4644
|
+
}, style: styles17.cardWrap, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4102
4645
|
reactNative.Animated.View,
|
|
4103
4646
|
{
|
|
4104
4647
|
accessibilityViewIsModal: true,
|
|
4105
4648
|
accessibilityRole: "alert",
|
|
4106
4649
|
style: [
|
|
4107
|
-
|
|
4650
|
+
styles17.card,
|
|
4108
4651
|
{
|
|
4109
4652
|
backgroundColor: theme.colors.surface,
|
|
4110
4653
|
borderRadius: theme.radius.lg,
|
|
@@ -4125,8 +4668,8 @@ var _CenteredModal = React18.forwardRef(
|
|
|
4125
4668
|
}
|
|
4126
4669
|
);
|
|
4127
4670
|
_CenteredModal.displayName = "CenteredModal";
|
|
4128
|
-
var CenteredModal =
|
|
4129
|
-
var
|
|
4671
|
+
var CenteredModal = React19__default.default.memo(_CenteredModal);
|
|
4672
|
+
var styles17 = reactNative.StyleSheet.create({
|
|
4130
4673
|
fill: { flex: 1 },
|
|
4131
4674
|
backdrop: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "#000" },
|
|
4132
4675
|
center: { flex: 1, alignItems: "center", justifyContent: "center", padding: 24 },
|
|
@@ -4255,16 +4798,16 @@ var fetchWireFeatures = async (config) => {
|
|
|
4255
4798
|
}
|
|
4256
4799
|
};
|
|
4257
4800
|
var useStableValue = (value, isEqual) => {
|
|
4258
|
-
const ref =
|
|
4801
|
+
const ref = React19.useRef(value);
|
|
4259
4802
|
if (!isEqual(ref.current, value)) ref.current = value;
|
|
4260
4803
|
return ref.current;
|
|
4261
4804
|
};
|
|
4262
4805
|
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);
|
|
4263
4806
|
var useWireFeatures = (config) => {
|
|
4264
4807
|
const stableConfig = useStableValue(config, sameFetchKey);
|
|
4265
|
-
const [flags, setFlags] =
|
|
4808
|
+
const [flags, setFlags] = React19.useState(defaultWireFeatures);
|
|
4266
4809
|
const canFetch = !!(stableConfig == null ? void 0 : stableConfig.serverUrl) && !!(stableConfig == null ? void 0 : stableConfig.apiKey);
|
|
4267
|
-
|
|
4810
|
+
React19.useEffect(() => {
|
|
4268
4811
|
if (!canFetch) {
|
|
4269
4812
|
setFlags((prev) => featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures);
|
|
4270
4813
|
return;
|
|
@@ -4283,7 +4826,7 @@ var useWireFeatures = (config) => {
|
|
|
4283
4826
|
var CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.context");
|
|
4284
4827
|
var globalObj = global;
|
|
4285
4828
|
if (!globalObj[CONTEXT_SYMBOL]) {
|
|
4286
|
-
globalObj[CONTEXT_SYMBOL] =
|
|
4829
|
+
globalObj[CONTEXT_SYMBOL] = React19.createContext(null);
|
|
4287
4830
|
}
|
|
4288
4831
|
var WireFeaturesContext = globalObj[CONTEXT_SYMBOL];
|
|
4289
4832
|
var WireFeaturesProvider = ({
|
|
@@ -4293,11 +4836,11 @@ var WireFeaturesProvider = ({
|
|
|
4293
4836
|
}) => {
|
|
4294
4837
|
const fetched = useWireFeatures(flags ? void 0 : config);
|
|
4295
4838
|
const value = flags != null ? flags : fetched;
|
|
4296
|
-
const stable =
|
|
4839
|
+
const stable = React19.useMemo(() => value, [value]);
|
|
4297
4840
|
return /* @__PURE__ */ jsxRuntime.jsx(WireFeaturesContext.Provider, { value: stable, children });
|
|
4298
4841
|
};
|
|
4299
4842
|
WireFeaturesProvider.displayName = "WireFeaturesProvider";
|
|
4300
|
-
var useWireFeaturesContext = () =>
|
|
4843
|
+
var useWireFeaturesContext = () => React19.useContext(WireFeaturesContext);
|
|
4301
4844
|
var useResolvedFeatures = (options) => {
|
|
4302
4845
|
var _a2, _b, _c;
|
|
4303
4846
|
const ctx = useWireFeaturesContext();
|
|
@@ -4377,6 +4920,11 @@ var toAnalyticsEvent = (event) => {
|
|
|
4377
4920
|
};
|
|
4378
4921
|
case "fallback":
|
|
4379
4922
|
return { name: WIRE_ONBOARDING_EVENTS.fallback, params: { reason: event.reason } };
|
|
4923
|
+
case "permission":
|
|
4924
|
+
return {
|
|
4925
|
+
name: permissionEventName(event.stage),
|
|
4926
|
+
params: permissionEventProps(event.permission, event.status)
|
|
4927
|
+
};
|
|
4380
4928
|
default: {
|
|
4381
4929
|
const _exhaustive = event;
|
|
4382
4930
|
return _exhaustive;
|
|
@@ -4486,15 +5034,15 @@ var createWireActivation = (config) => {
|
|
|
4486
5034
|
getRevalidationVersion: getActivationRevalidationVersion
|
|
4487
5035
|
};
|
|
4488
5036
|
};
|
|
4489
|
-
var useActivationRevalidation = () =>
|
|
5037
|
+
var useActivationRevalidation = () => React19.useSyncExternalStore(
|
|
4490
5038
|
subscribeActivationRevalidation,
|
|
4491
5039
|
getActivationRevalidationVersion,
|
|
4492
5040
|
getActivationRevalidationVersion
|
|
4493
5041
|
);
|
|
4494
5042
|
var useWireActivation = (config) => {
|
|
4495
5043
|
var _a2;
|
|
4496
|
-
const ref =
|
|
4497
|
-
const prevKeys =
|
|
5044
|
+
const ref = React19.useRef(void 0);
|
|
5045
|
+
const prevKeys = React19.useRef("");
|
|
4498
5046
|
const currentKeys = [
|
|
4499
5047
|
config.serverUrl,
|
|
4500
5048
|
config.apiKey,
|
|
@@ -4719,9 +5267,9 @@ var reportSessionStart = (opts) => {
|
|
|
4719
5267
|
};
|
|
4720
5268
|
var BACKGROUND_SESSION_MS = 30 * 60 * 1e3;
|
|
4721
5269
|
var useSessionStart = (config, options = {}) => {
|
|
4722
|
-
const latest =
|
|
5270
|
+
const latest = React19.useRef({ config, options });
|
|
4723
5271
|
latest.current = { config, options };
|
|
4724
|
-
|
|
5272
|
+
React19.useEffect(() => {
|
|
4725
5273
|
const resolveDeviceKey = (cfg, opts) => {
|
|
4726
5274
|
const host = typeof opts.deviceKey === "string" && opts.deviceKey.trim() ? opts.deviceKey : void 0;
|
|
4727
5275
|
if (host) return host;
|
|
@@ -5095,10 +5643,10 @@ var createEventQueue = (options) => {
|
|
|
5095
5643
|
|
|
5096
5644
|
// src/session-analytics/useLifecycleEvents.ts
|
|
5097
5645
|
var useLifecycleEvents = (config, options = {}) => {
|
|
5098
|
-
const latest =
|
|
5646
|
+
const latest = React19.useRef({ config, options });
|
|
5099
5647
|
latest.current = { config, options };
|
|
5100
|
-
const queueRef =
|
|
5101
|
-
|
|
5648
|
+
const queueRef = React19.useRef(void 0);
|
|
5649
|
+
React19.useEffect(() => {
|
|
5102
5650
|
const resolveSink = () => {
|
|
5103
5651
|
var _a2, _b;
|
|
5104
5652
|
const { config: cfg, options: opts } = latest.current;
|
|
@@ -5213,22 +5761,29 @@ exports.CenteredModal = CenteredModal;
|
|
|
5213
5761
|
exports.ChipSelectCard = ChipSelectCard;
|
|
5214
5762
|
exports.CompletionView = CompletionView;
|
|
5215
5763
|
exports.DEFAULT_FEATURES_TTL_MS = DEFAULT_FEATURES_TTL_MS;
|
|
5764
|
+
exports.DEFAULT_PERMISSION_COPY = DEFAULT_PERMISSION_COPY;
|
|
5765
|
+
exports.DEFAULT_PERMISSION_PLACEMENT = DEFAULT_PERMISSION_PLACEMENT;
|
|
5216
5766
|
exports.DEFAULT_SESSION_TTL_MS = DEFAULT_SESSION_TTL_MS;
|
|
5217
5767
|
exports.DemoOnboarding = DemoOnboarding;
|
|
5218
5768
|
exports.EXTRA_KEY_PREFIX = EXTRA_KEY_PREFIX;
|
|
5219
5769
|
exports.ErrorBlock = ErrorBlock;
|
|
5220
5770
|
exports.FIRST_OPEN_EVENT = FIRST_OPEN_EVENT;
|
|
5771
|
+
exports.GENERIC_PERMISSION_COPY = GENERIC_PERMISSION_COPY;
|
|
5221
5772
|
exports.IconRegistryProvider = IconRegistryProvider;
|
|
5222
5773
|
exports.IllustrationProvider = IllustrationProvider;
|
|
5223
5774
|
exports.InterstitialCard = InterstitialCard;
|
|
5224
5775
|
exports.LoadingBlock = LoadingBlock;
|
|
5225
5776
|
exports.LoadingScreen = LoadingScreen;
|
|
5777
|
+
exports.NOTIFICATIONS_PERMISSION_COPY = NOTIFICATIONS_PERMISSION_COPY;
|
|
5226
5778
|
exports.NumberStepperCard = NumberStepperCard;
|
|
5227
5779
|
exports.OnboardingButton = Button;
|
|
5228
5780
|
exports.OnboardingFlow = OnboardingFlow;
|
|
5229
5781
|
exports.OnboardingScaffold = OnboardingScaffold;
|
|
5230
5782
|
exports.OnboardingThemeProvider = OnboardingThemeProvider;
|
|
5783
|
+
exports.PERMISSION_CARD_NAME = PERMISSION_CARD_NAME;
|
|
5231
5784
|
exports.PLAN_TIER_CONTEXT_KEY = PLAN_TIER_CONTEXT_KEY;
|
|
5785
|
+
exports.PermissionCard = PermissionCard;
|
|
5786
|
+
exports.PermissionCardView = PermissionCardView;
|
|
5232
5787
|
exports.SESSION_STARTED_EVENT = SESSION_STARTED_EVENT;
|
|
5233
5788
|
exports.SelectionCard = SelectionCard;
|
|
5234
5789
|
exports.StatusCard = StatusCard;
|
|
@@ -5239,6 +5794,7 @@ exports.WIRE_ENV_VARS = WIRE_ENV_VARS;
|
|
|
5239
5794
|
exports.WIRE_ICON_GLYPHS = WIRE_ICON_GLYPHS;
|
|
5240
5795
|
exports.WIRE_ICON_NAMES = WIRE_ICON_NAMES;
|
|
5241
5796
|
exports.WIRE_ONBOARDING_EVENTS = WIRE_ONBOARDING_EVENTS;
|
|
5797
|
+
exports.WIRE_PERMISSION_EVENTS = WIRE_PERMISSION_EVENTS;
|
|
5242
5798
|
exports.WIRE_PURCHASE_EVENTS = WIRE_PURCHASE_EVENTS;
|
|
5243
5799
|
exports.WireFeaturesProvider = WireFeaturesProvider;
|
|
5244
5800
|
exports.WireIcon = WireIcon;
|
|
@@ -5250,6 +5806,7 @@ exports.attributionMetadata = attributionMetadata;
|
|
|
5250
5806
|
exports.bumpActivationRevalidation = bumpActivationRevalidation;
|
|
5251
5807
|
exports.clearPersistedSession = clearPersistedSession;
|
|
5252
5808
|
exports.clearPiiFromContext = clearPiiFromContext;
|
|
5809
|
+
exports.clearSettledPermissions = clearSettledPermissions;
|
|
5253
5810
|
exports.clearUserContext = clearUserContext;
|
|
5254
5811
|
exports.collectDeviceContext = collectDeviceContext;
|
|
5255
5812
|
exports.createRevenueCatBridge = createRevenueCatBridge;
|
|
@@ -5278,9 +5835,11 @@ exports.hydrateDeviceIdentity = hydrateDeviceIdentity;
|
|
|
5278
5835
|
exports.identifyOnboarding = identifyOnboarding;
|
|
5279
5836
|
exports.isFeaturesFresh = isFeaturesFresh;
|
|
5280
5837
|
exports.isOnboardingEnabled = isOnboardingEnabled;
|
|
5838
|
+
exports.isPermissionDue = isPermissionDue;
|
|
5281
5839
|
exports.isUserCancelled = isUserCancelled;
|
|
5282
5840
|
exports.isWireScalar = isWireScalar;
|
|
5283
5841
|
exports.loadPersistedSession = loadPersistedSession;
|
|
5842
|
+
exports.loadSettledPermissions = loadSettledPermissions;
|
|
5284
5843
|
exports.looksLikeEmail = looksLikeEmail;
|
|
5285
5844
|
exports.lookupIconGlyph = lookupIconGlyph;
|
|
5286
5845
|
exports.makeSessionId = makeSessionId;
|
|
@@ -5288,11 +5847,18 @@ exports.mergeTheme = mergeTheme;
|
|
|
5288
5847
|
exports.mintDeviceId = mintDeviceId;
|
|
5289
5848
|
exports.motionSpec = motionSpec_exports;
|
|
5290
5849
|
exports.namespaceExtra = namespaceExtra;
|
|
5850
|
+
exports.normalizeAfterCard = normalizeAfterCard;
|
|
5851
|
+
exports.normalizePermissionStatus = normalizePermissionStatus;
|
|
5291
5852
|
exports.onboardingComponents = onboardingComponents;
|
|
5292
5853
|
exports.parseWireFeatures = parseWireFeatures;
|
|
5293
5854
|
exports.peekPersistedSession = peekPersistedSession;
|
|
5855
|
+
exports.permissionEventName = permissionEventName;
|
|
5856
|
+
exports.permissionEventProps = permissionEventProps;
|
|
5857
|
+
exports.permissionScreenId = permissionScreenId;
|
|
5858
|
+
exports.permissionStorageKey = permissionStorageKey;
|
|
5294
5859
|
exports.readCachedFeatures = readCachedFeatures;
|
|
5295
5860
|
exports.readProgress = readProgress;
|
|
5861
|
+
exports.readSettledPermissions = readSettledPermissions;
|
|
5296
5862
|
exports.reportClientEvent = reportClientEvent;
|
|
5297
5863
|
exports.reportClientEventAwait = reportClientEventAwait;
|
|
5298
5864
|
exports.reportClientEvents = reportClientEvents;
|
|
@@ -5307,10 +5873,13 @@ exports.resetIdentityProvenance = resetIdentityProvenance;
|
|
|
5307
5873
|
exports.resetSessionStartGuard = resetSessionStartGuard;
|
|
5308
5874
|
exports.resolveAutoDeviceKey = resolveAutoDeviceKey;
|
|
5309
5875
|
exports.resolveIdentity = resolveIdentity;
|
|
5876
|
+
exports.resolvePermissionCopy = resolvePermissionCopy;
|
|
5310
5877
|
exports.resolvePlanTier = resolvePlanTier;
|
|
5311
5878
|
exports.resolveUserContext = resolveUserContext;
|
|
5312
5879
|
exports.sanitizeUserId = sanitizeUserId;
|
|
5313
5880
|
exports.savePersistedSession = savePersistedSession;
|
|
5881
|
+
exports.saveSettledPermissions = saveSettledPermissions;
|
|
5882
|
+
exports.selectDuePermissionScreen = selectDuePermissionScreen;
|
|
5314
5883
|
exports.sessionStorageKey = sessionStorageKey;
|
|
5315
5884
|
exports.setCurrentSessionId = setCurrentSessionId;
|
|
5316
5885
|
exports.subscribeActivationRevalidation = subscribeActivationRevalidation;
|