@cxpinsight/react-native 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/babel.js +101 -0
  4. package/instrumented/Pressable.d.ts +2 -0
  5. package/instrumented/Pressable.js +2 -0
  6. package/instrumented/ScrollView.d.ts +2 -0
  7. package/instrumented/ScrollView.js +2 -0
  8. package/instrumented/TextInput.d.ts +2 -0
  9. package/instrumented/TextInput.js +2 -0
  10. package/instrumented/TouchableOpacity.d.ts +2 -0
  11. package/instrumented/TouchableOpacity.js +2 -0
  12. package/lib/CXPinsight.d.ts +113 -0
  13. package/lib/CXPinsight.d.ts.map +1 -0
  14. package/lib/CXPinsight.js +831 -0
  15. package/lib/CXPinsight.js.map +1 -0
  16. package/lib/CXPinsightProvider.d.ts +19 -0
  17. package/lib/CXPinsightProvider.d.ts.map +1 -0
  18. package/lib/CXPinsightProvider.js +382 -0
  19. package/lib/CXPinsightProvider.js.map +1 -0
  20. package/lib/core/autoScreenTracker.d.ts +20 -0
  21. package/lib/core/autoScreenTracker.d.ts.map +1 -0
  22. package/lib/core/autoScreenTracker.js +66 -0
  23. package/lib/core/autoScreenTracker.js.map +1 -0
  24. package/lib/core/deepLinkTracker.d.ts +17 -0
  25. package/lib/core/deepLinkTracker.d.ts.map +1 -0
  26. package/lib/core/deepLinkTracker.js +81 -0
  27. package/lib/core/deepLinkTracker.js.map +1 -0
  28. package/lib/core/deviceInfo.d.ts +14 -0
  29. package/lib/core/deviceInfo.d.ts.map +1 -0
  30. package/lib/core/deviceInfo.js +166 -0
  31. package/lib/core/deviceInfo.js.map +1 -0
  32. package/lib/core/eventQueue.d.ts +23 -0
  33. package/lib/core/eventQueue.d.ts.map +1 -0
  34. package/lib/core/eventQueue.js +240 -0
  35. package/lib/core/eventQueue.js.map +1 -0
  36. package/lib/core/lifecycle.d.ts +18 -0
  37. package/lib/core/lifecycle.d.ts.map +1 -0
  38. package/lib/core/lifecycle.js +127 -0
  39. package/lib/core/lifecycle.js.map +1 -0
  40. package/lib/core/mobileRecorder.d.ts +15 -0
  41. package/lib/core/mobileRecorder.d.ts.map +1 -0
  42. package/lib/core/mobileRecorder.js +231 -0
  43. package/lib/core/mobileRecorder.js.map +1 -0
  44. package/lib/core/network.d.ts +10 -0
  45. package/lib/core/network.d.ts.map +1 -0
  46. package/lib/core/network.js +74 -0
  47. package/lib/core/network.js.map +1 -0
  48. package/lib/core/networkCapture.d.ts +22 -0
  49. package/lib/core/networkCapture.d.ts.map +1 -0
  50. package/lib/core/networkCapture.js +100 -0
  51. package/lib/core/networkCapture.js.map +1 -0
  52. package/lib/core/scrollCapture.d.ts +48 -0
  53. package/lib/core/scrollCapture.d.ts.map +1 -0
  54. package/lib/core/scrollCapture.js +221 -0
  55. package/lib/core/scrollCapture.js.map +1 -0
  56. package/lib/core/session.d.ts +15 -0
  57. package/lib/core/session.d.ts.map +1 -0
  58. package/lib/core/session.js +157 -0
  59. package/lib/core/session.js.map +1 -0
  60. package/lib/core/storage.d.ts +11 -0
  61. package/lib/core/storage.d.ts.map +1 -0
  62. package/lib/core/storage.js +59 -0
  63. package/lib/core/storage.js.map +1 -0
  64. package/lib/core/triggerEngine.d.ts +56 -0
  65. package/lib/core/triggerEngine.d.ts.map +1 -0
  66. package/lib/core/triggerEngine.js +432 -0
  67. package/lib/core/triggerEngine.js.map +1 -0
  68. package/lib/index.d.ts +7 -0
  69. package/lib/index.d.ts.map +1 -0
  70. package/lib/index.js +11 -0
  71. package/lib/index.js.map +1 -0
  72. package/lib/instrumented/Pressable.d.ts +9 -0
  73. package/lib/instrumented/Pressable.d.ts.map +1 -0
  74. package/lib/instrumented/Pressable.js +96 -0
  75. package/lib/instrumented/Pressable.js.map +1 -0
  76. package/lib/instrumented/ScrollView.d.ts +6 -0
  77. package/lib/instrumented/ScrollView.d.ts.map +1 -0
  78. package/lib/instrumented/ScrollView.js +101 -0
  79. package/lib/instrumented/ScrollView.js.map +1 -0
  80. package/lib/instrumented/TextInput.d.ts +9 -0
  81. package/lib/instrumented/TextInput.d.ts.map +1 -0
  82. package/lib/instrumented/TextInput.js +75 -0
  83. package/lib/instrumented/TextInput.js.map +1 -0
  84. package/lib/instrumented/TouchableOpacity.d.ts +11 -0
  85. package/lib/instrumented/TouchableOpacity.d.ts.map +1 -0
  86. package/lib/instrumented/TouchableOpacity.js +96 -0
  87. package/lib/instrumented/TouchableOpacity.js.map +1 -0
  88. package/lib/instrumented/index.d.ts +19 -0
  89. package/lib/instrumented/index.d.ts.map +1 -0
  90. package/lib/instrumented/index.js +28 -0
  91. package/lib/instrumented/index.js.map +1 -0
  92. package/lib/instrumented/interactionObserver.d.ts +29 -0
  93. package/lib/instrumented/interactionObserver.d.ts.map +1 -0
  94. package/lib/instrumented/interactionObserver.js +38 -0
  95. package/lib/instrumented/interactionObserver.js.map +1 -0
  96. package/lib/setup/AccessibilityScanner.d.ts +32 -0
  97. package/lib/setup/AccessibilityScanner.d.ts.map +1 -0
  98. package/lib/setup/AccessibilityScanner.js +127 -0
  99. package/lib/setup/AccessibilityScanner.js.map +1 -0
  100. package/lib/setup/ElementIdentifier.d.ts +65 -0
  101. package/lib/setup/ElementIdentifier.d.ts.map +1 -0
  102. package/lib/setup/ElementIdentifier.js +114 -0
  103. package/lib/setup/ElementIdentifier.js.map +1 -0
  104. package/lib/setup/ElementRegistry.d.ts +22 -0
  105. package/lib/setup/ElementRegistry.d.ts.map +1 -0
  106. package/lib/setup/ElementRegistry.js +47 -0
  107. package/lib/setup/ElementRegistry.js.map +1 -0
  108. package/lib/setup/SetupCodeEntry.d.ts +15 -0
  109. package/lib/setup/SetupCodeEntry.d.ts.map +1 -0
  110. package/lib/setup/SetupCodeEntry.js +198 -0
  111. package/lib/setup/SetupCodeEntry.js.map +1 -0
  112. package/lib/setup/SetupController.d.ts +29 -0
  113. package/lib/setup/SetupController.d.ts.map +1 -0
  114. package/lib/setup/SetupController.js +189 -0
  115. package/lib/setup/SetupController.js.map +1 -0
  116. package/lib/setup/SetupOverlay.d.ts +10 -0
  117. package/lib/setup/SetupOverlay.d.ts.map +1 -0
  118. package/lib/setup/SetupOverlay.js +408 -0
  119. package/lib/setup/SetupOverlay.js.map +1 -0
  120. package/lib/setup/TapInterceptor.d.ts +19 -0
  121. package/lib/setup/TapInterceptor.d.ts.map +1 -0
  122. package/lib/setup/TapInterceptor.js +98 -0
  123. package/lib/setup/TapInterceptor.js.map +1 -0
  124. package/lib/setup/TouchObserver.d.ts +25 -0
  125. package/lib/setup/TouchObserver.d.ts.map +1 -0
  126. package/lib/setup/TouchObserver.js +88 -0
  127. package/lib/setup/TouchObserver.js.map +1 -0
  128. package/lib/setup/TouchPatcher.d.ts +27 -0
  129. package/lib/setup/TouchPatcher.d.ts.map +1 -0
  130. package/lib/setup/TouchPatcher.js +182 -0
  131. package/lib/setup/TouchPatcher.js.map +1 -0
  132. package/lib/setup/index.d.ts +13 -0
  133. package/lib/setup/index.d.ts.map +1 -0
  134. package/lib/setup/index.js +45 -0
  135. package/lib/setup/index.js.map +1 -0
  136. package/lib/setup/useCXPElement.d.ts +25 -0
  137. package/lib/setup/useCXPElement.d.ts.map +1 -0
  138. package/lib/setup/useCXPElement.js +33 -0
  139. package/lib/setup/useCXPElement.js.map +1 -0
  140. package/lib/survey/SurveyModal.d.ts +10 -0
  141. package/lib/survey/SurveyModal.d.ts.map +1 -0
  142. package/lib/survey/SurveyModal.js +1650 -0
  143. package/lib/survey/SurveyModal.js.map +1 -0
  144. package/lib/survey/expressionEval.d.ts +10 -0
  145. package/lib/survey/expressionEval.d.ts.map +1 -0
  146. package/lib/survey/expressionEval.js +287 -0
  147. package/lib/survey/expressionEval.js.map +1 -0
  148. package/lib/survey/frequencyCap.d.ts +15 -0
  149. package/lib/survey/frequencyCap.d.ts.map +1 -0
  150. package/lib/survey/frequencyCap.js +116 -0
  151. package/lib/survey/frequencyCap.js.map +1 -0
  152. package/lib/survey/handsFreeVoice.d.ts +30 -0
  153. package/lib/survey/handsFreeVoice.d.ts.map +1 -0
  154. package/lib/survey/handsFreeVoice.js +312 -0
  155. package/lib/survey/handsFreeVoice.js.map +1 -0
  156. package/lib/survey/interpolate.d.ts +6 -0
  157. package/lib/survey/interpolate.d.ts.map +1 -0
  158. package/lib/survey/interpolate.js +61 -0
  159. package/lib/survey/interpolate.js.map +1 -0
  160. package/lib/survey/pagesFromV1.d.ts +6 -0
  161. package/lib/survey/pagesFromV1.d.ts.map +1 -0
  162. package/lib/survey/pagesFromV1.js +83 -0
  163. package/lib/survey/pagesFromV1.js.map +1 -0
  164. package/lib/survey/questions/CSATQuestion.d.ts +16 -0
  165. package/lib/survey/questions/CSATQuestion.d.ts.map +1 -0
  166. package/lib/survey/questions/CSATQuestion.js +37 -0
  167. package/lib/survey/questions/CSATQuestion.js.map +1 -0
  168. package/lib/survey/questions/DateQuestion.d.ts +20 -0
  169. package/lib/survey/questions/DateQuestion.d.ts.map +1 -0
  170. package/lib/survey/questions/DateQuestion.js +103 -0
  171. package/lib/survey/questions/DateQuestion.js.map +1 -0
  172. package/lib/survey/questions/ImagePickerQuestion.d.ts +33 -0
  173. package/lib/survey/questions/ImagePickerQuestion.d.ts.map +1 -0
  174. package/lib/survey/questions/ImagePickerQuestion.js +68 -0
  175. package/lib/survey/questions/ImagePickerQuestion.js.map +1 -0
  176. package/lib/survey/questions/ImageQuestion.d.ts +26 -0
  177. package/lib/survey/questions/ImageQuestion.d.ts.map +1 -0
  178. package/lib/survey/questions/ImageQuestion.js +24 -0
  179. package/lib/survey/questions/ImageQuestion.js.map +1 -0
  180. package/lib/survey/questions/MatrixCell.d.ts +45 -0
  181. package/lib/survey/questions/MatrixCell.d.ts.map +1 -0
  182. package/lib/survey/questions/MatrixCell.js +54 -0
  183. package/lib/survey/questions/MatrixCell.js.map +1 -0
  184. package/lib/survey/questions/MatrixDropdownQuestion.d.ts +29 -0
  185. package/lib/survey/questions/MatrixDropdownQuestion.d.ts.map +1 -0
  186. package/lib/survey/questions/MatrixDropdownQuestion.js +42 -0
  187. package/lib/survey/questions/MatrixDropdownQuestion.js.map +1 -0
  188. package/lib/survey/questions/MatrixDynamicQuestion.d.ts +26 -0
  189. package/lib/survey/questions/MatrixDynamicQuestion.d.ts.map +1 -0
  190. package/lib/survey/questions/MatrixDynamicQuestion.js +52 -0
  191. package/lib/survey/questions/MatrixDynamicQuestion.js.map +1 -0
  192. package/lib/survey/questions/MatrixQuestion.d.ts +38 -0
  193. package/lib/survey/questions/MatrixQuestion.d.ts.map +1 -0
  194. package/lib/survey/questions/MatrixQuestion.js +64 -0
  195. package/lib/survey/questions/MatrixQuestion.js.map +1 -0
  196. package/lib/survey/questions/MultiTextQuestion.d.ts +19 -0
  197. package/lib/survey/questions/MultiTextQuestion.d.ts.map +1 -0
  198. package/lib/survey/questions/MultiTextQuestion.js +64 -0
  199. package/lib/survey/questions/MultiTextQuestion.js.map +1 -0
  200. package/lib/survey/questions/MultipleChoiceQuestion.d.ts +25 -0
  201. package/lib/survey/questions/MultipleChoiceQuestion.d.ts.map +1 -0
  202. package/lib/survey/questions/MultipleChoiceQuestion.js +111 -0
  203. package/lib/survey/questions/MultipleChoiceQuestion.js.map +1 -0
  204. package/lib/survey/questions/NPSQuestion.d.ts +18 -0
  205. package/lib/survey/questions/NPSQuestion.d.ts.map +1 -0
  206. package/lib/survey/questions/NPSQuestion.js +62 -0
  207. package/lib/survey/questions/NPSQuestion.js.map +1 -0
  208. package/lib/survey/questions/PanelDynamicQuestion.d.ts +50 -0
  209. package/lib/survey/questions/PanelDynamicQuestion.d.ts.map +1 -0
  210. package/lib/survey/questions/PanelDynamicQuestion.js +62 -0
  211. package/lib/survey/questions/PanelDynamicQuestion.js.map +1 -0
  212. package/lib/survey/questions/RankingQuestion.d.ts +34 -0
  213. package/lib/survey/questions/RankingQuestion.d.ts.map +1 -0
  214. package/lib/survey/questions/RankingQuestion.js +85 -0
  215. package/lib/survey/questions/RankingQuestion.js.map +1 -0
  216. package/lib/survey/questions/RatingQuestion.d.ts +20 -0
  217. package/lib/survey/questions/RatingQuestion.d.ts.map +1 -0
  218. package/lib/survey/questions/RatingQuestion.js +53 -0
  219. package/lib/survey/questions/RatingQuestion.js.map +1 -0
  220. package/lib/survey/questions/TextQuestion.d.ts +17 -0
  221. package/lib/survey/questions/TextQuestion.d.ts.map +1 -0
  222. package/lib/survey/questions/TextQuestion.js +46 -0
  223. package/lib/survey/questions/TextQuestion.js.map +1 -0
  224. package/lib/survey/styleContract.d.ts +230 -0
  225. package/lib/survey/styleContract.d.ts.map +1 -0
  226. package/lib/survey/styleContract.js +365 -0
  227. package/lib/survey/styleContract.js.map +1 -0
  228. package/lib/survey/themePalette.d.ts +56 -0
  229. package/lib/survey/themePalette.d.ts.map +1 -0
  230. package/lib/survey/themePalette.js +63 -0
  231. package/lib/survey/themePalette.js.map +1 -0
  232. package/lib/survey/translationLookup.d.ts +4 -0
  233. package/lib/survey/translationLookup.d.ts.map +1 -0
  234. package/lib/survey/translationLookup.js +62 -0
  235. package/lib/survey/translationLookup.js.map +1 -0
  236. package/lib/survey/validate.d.ts +3 -0
  237. package/lib/survey/validate.d.ts.map +1 -0
  238. package/lib/survey/validate.js +159 -0
  239. package/lib/survey/validate.js.map +1 -0
  240. package/lib/survey/variablesResolver.d.ts +10 -0
  241. package/lib/survey/variablesResolver.d.ts.map +1 -0
  242. package/lib/survey/variablesResolver.js +107 -0
  243. package/lib/survey/variablesResolver.js.map +1 -0
  244. package/lib/survey/voiceParsers.d.ts +47 -0
  245. package/lib/survey/voiceParsers.d.ts.map +1 -0
  246. package/lib/survey/voiceParsers.js +310 -0
  247. package/lib/survey/voiceParsers.js.map +1 -0
  248. package/lib/types.d.ts +349 -0
  249. package/lib/types.d.ts.map +1 -0
  250. package/lib/types.js +20 -0
  251. package/lib/types.js.map +1 -0
  252. package/metro.js +55 -0
  253. package/package.json +78 -0
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getDeviceId = getDeviceId;
37
+ exports.onSetupStateChange = onSetupStateChange;
38
+ exports.getSetupState = getSetupState;
39
+ exports.isSetupActive = isSetupActive;
40
+ exports.claimSetup = claimSetup;
41
+ exports.endSetup = endSetup;
42
+ exports.restoreSetupState = restoreSetupState;
43
+ exports.clearSetupState = clearSetupState;
44
+ const react_native_1 = require("react-native");
45
+ const network_1 = require("../core/network");
46
+ const deviceInfo_1 = require("../core/deviceInfo");
47
+ const storage = __importStar(require("../core/storage"));
48
+ const DEVICE_ID_KEY = '@cxpinsight:deviceId';
49
+ const SETUP_STATE_KEY = '@cxpinsight:setupState';
50
+ let currentState = null;
51
+ let heartbeatTimer = null;
52
+ let listeners = [];
53
+ let debugMode = false;
54
+ function log(...args) {
55
+ if (debugMode)
56
+ console.log('[CXPinsight:Setup]', ...args);
57
+ }
58
+ /** Generate or retrieve a stable device ID */
59
+ async function getDeviceId() {
60
+ const saved = await storage.get(DEVICE_ID_KEY);
61
+ if (saved)
62
+ return saved;
63
+ const device = (0, deviceInfo_1.getDeviceInfo)();
64
+ const id = [
65
+ 'cxp_device',
66
+ react_native_1.Platform.OS,
67
+ device.osVersion,
68
+ Date.now().toString(36),
69
+ Math.random().toString(36).substring(2, 10),
70
+ ].join('_');
71
+ await storage.set(DEVICE_ID_KEY, id);
72
+ return id;
73
+ }
74
+ /** Subscribe to setup state changes */
75
+ function onSetupStateChange(listener) {
76
+ listeners.push(listener);
77
+ return () => {
78
+ listeners = listeners.filter(l => l !== listener);
79
+ };
80
+ }
81
+ function notifyListeners(active) {
82
+ listeners.forEach(l => l(active));
83
+ }
84
+ /** Get current setup state */
85
+ function getSetupState() {
86
+ return currentState;
87
+ }
88
+ function isSetupActive() {
89
+ return currentState?.active === true;
90
+ }
91
+ /** Claim a mobile setup session with a 6-digit code */
92
+ async function claimSetup(siteId, setupCode, debug) {
93
+ debugMode = debug ?? false;
94
+ const deviceId = await getDeviceId();
95
+ log('Claiming setup:', { siteId, setupCode: '***', deviceId });
96
+ const result = await (0, network_1.sdkFetch)('POST', '/api/engagement/sites/claim-mobile-setup', {
97
+ siteId,
98
+ setupCode,
99
+ deviceId,
100
+ });
101
+ if (!result.success || !result.data) {
102
+ const errMsg = result.data?.error || result.error || 'Failed to claim setup';
103
+ log('Claim failed:', errMsg);
104
+ return { success: false, error: errMsg };
105
+ }
106
+ const data = result.data.data ?? result.data;
107
+ currentState = {
108
+ active: true,
109
+ siteId: data.siteId || siteId,
110
+ apiKey: data.apiKey || '',
111
+ deviceId,
112
+ expiresAt: data.expiresAt,
113
+ enteredAt: Date.now(),
114
+ };
115
+ await storage.set(SETUP_STATE_KEY, currentState);
116
+ startHeartbeat();
117
+ notifyListeners(true);
118
+ log('Setup claimed successfully, expires:', data.expiresAt);
119
+ return { success: true };
120
+ }
121
+ /** End the setup session */
122
+ async function endSetup() {
123
+ if (!currentState)
124
+ return;
125
+ log('Ending setup session');
126
+ stopHeartbeat();
127
+ // Tell the server
128
+ (0, network_1.sdkFetch)('POST', `/api/engagement/sites/${currentState.siteId}/end-mobile-setup`).catch(() => { });
129
+ currentState = null;
130
+ await storage.remove(SETUP_STATE_KEY);
131
+ notifyListeners(false);
132
+ }
133
+ /** Heartbeat — validates session is still active every 30s */
134
+ function startHeartbeat() {
135
+ stopHeartbeat();
136
+ heartbeatTimer = setInterval(async () => {
137
+ if (!currentState) {
138
+ stopHeartbeat();
139
+ return;
140
+ }
141
+ // Check expiry locally first
142
+ if (new Date(currentState.expiresAt).getTime() < Date.now()) {
143
+ log('Setup session expired locally');
144
+ await endSetup();
145
+ return;
146
+ }
147
+ // Validate with server
148
+ const result = await (0, network_1.sdkFetch)('POST', '/api/engagement/sites/validate-mobile-setup', {
149
+ siteId: currentState.siteId,
150
+ deviceId: currentState.deviceId,
151
+ });
152
+ const data = result.data?.data ?? result.data;
153
+ if (!data?.active) {
154
+ log('Setup session invalidated by server');
155
+ await endSetup();
156
+ }
157
+ }, 30000);
158
+ }
159
+ function stopHeartbeat() {
160
+ if (heartbeatTimer) {
161
+ clearInterval(heartbeatTimer);
162
+ heartbeatTimer = null;
163
+ }
164
+ }
165
+ /** Restore setup state on SDK init (in case app was restarted during setup) */
166
+ async function restoreSetupState(debug) {
167
+ debugMode = debug ?? false;
168
+ const saved = await storage.get(SETUP_STATE_KEY);
169
+ if (!saved || !saved.active)
170
+ return;
171
+ // Check if still valid
172
+ if (new Date(saved.expiresAt).getTime() < Date.now()) {
173
+ log('Saved setup session expired, clearing');
174
+ await storage.remove(SETUP_STATE_KEY);
175
+ return;
176
+ }
177
+ currentState = saved;
178
+ startHeartbeat();
179
+ notifyListeners(true);
180
+ log('Restored active setup session');
181
+ }
182
+ /** Clear all setup state (called on SDK reset) */
183
+ async function clearSetupState() {
184
+ stopHeartbeat();
185
+ currentState = null;
186
+ await storage.multiRemove([SETUP_STATE_KEY]);
187
+ notifyListeners(false);
188
+ }
189
+ //# sourceMappingURL=SetupController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SetupController.js","sourceRoot":"","sources":["../../src/setup/SetupController.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ElementInfo } from './ElementIdentifier';
2
+ interface SetupOverlayProps {
3
+ visible: boolean;
4
+ screenName: string;
5
+ elements: ElementInfo[];
6
+ onRefreshElements: () => void;
7
+ }
8
+ export declare function SetupOverlay({ visible, screenName, elements, onRefreshElements }: SetupOverlayProps): import("react/jsx-runtime").JSX.Element | null;
9
+ export {};
10
+ //# sourceMappingURL=SetupOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SetupOverlay.d.ts","sourceRoot":"","sources":["../../src/setup/SetupOverlay.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAA2B,MAAM,qBAAqB,CAAC;AAoBhF,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B;AA8CD,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,EAAE,EAAE,iBAAiB,kDAsanG"}
@@ -0,0 +1,408 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SetupOverlay = SetupOverlay;
37
+ const jsx_runtime_1 = require("react/jsx-runtime");
38
+ const react_1 = __importStar(require("react"));
39
+ const react_native_1 = require("react-native");
40
+ const network_1 = require("../core/network");
41
+ const SetupController_1 = require("./SetupController");
42
+ const ElementIdentifier_1 = require("./ElementIdentifier");
43
+ const ElementRegistry_1 = require("./ElementRegistry");
44
+ const interactionObserver_1 = require("../instrumented/interactionObserver");
45
+ const EVENT_TYPES = [
46
+ { value: 'tap', label: 'Tap' },
47
+ { value: 'long_press', label: 'Long Press' },
48
+ { value: 'input_focus', label: 'Input Focus' },
49
+ { value: 'input_blur', label: 'Input Blur' },
50
+ { value: 'value_change', label: 'Value Change' },
51
+ { value: 'custom', label: 'Custom' },
52
+ ];
53
+ const CAPTURE_OPTIONS = [
54
+ { value: 'element_text', label: 'Element Text' },
55
+ { value: 'element_value', label: 'Element Value' },
56
+ { value: 'screen_context', label: 'Screen Context' },
57
+ { value: 'timestamp', label: 'Timestamp' },
58
+ ];
59
+ const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = react_native_1.Dimensions.get('window');
60
+ // ── FAB (Floating Action Button) ──
61
+ // Simple TouchableOpacity positioned at bottom-right. No PanResponder to avoid
62
+ // touch-stealing from the responder system.
63
+ function FloatingButton({ onPress, visible }) {
64
+ if (!visible)
65
+ return null;
66
+ // Render FAB directly — no container view.
67
+ // position: 'absolute' makes it float over content.
68
+ // It's only 56x56px so it can't block the screen.
69
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { onPress: onPress, activeOpacity: 0.8, style: styles.fab, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.fabText, children: "CXP" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.fabBadge, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.fabBadgeText, children: "SETUP" }) })] }));
70
+ }
71
+ // ── Main Setup Overlay ──
72
+ function SetupOverlay({ visible, screenName, elements, onRefreshElements }) {
73
+ const [panelOpen, setPanelOpen] = (0, react_1.useState)(false);
74
+ const [activeTab, setActiveTab] = (0, react_1.useState)('elements');
75
+ const [configuredEvents, setConfiguredEvents] = (0, react_1.useState)([]);
76
+ const [selectedElement, setSelectedElement] = (0, react_1.useState)(null);
77
+ const [showEventForm, setShowEventForm] = (0, react_1.useState)(false);
78
+ const [loading, setLoading] = (0, react_1.useState)(false);
79
+ const [registryElements, setRegistryElements] = (0, react_1.useState)((0, ElementRegistry_1.getRegisteredElements)(screenName));
80
+ const [tappedHistory, setTappedHistory] = (0, react_1.useState)([]);
81
+ // Event form state
82
+ const [eventName, setEventName] = (0, react_1.useState)('');
83
+ const [eventType, setEventType] = (0, react_1.useState)('tap');
84
+ const [captureData, setCaptureData] = (0, react_1.useState)(['element_text']);
85
+ const [formTestID, setFormTestID] = (0, react_1.useState)('');
86
+ const [formAccessibilityLabel, setFormAccessibilityLabel] = (0, react_1.useState)('');
87
+ const state = (0, SetupController_1.getSetupState)();
88
+ // Listen for interactions from instrumented components
89
+ (0, react_1.useEffect)(() => {
90
+ if (!visible)
91
+ return;
92
+ const unsubscribe = (0, interactionObserver_1.setInteractionListener)((event) => {
93
+ // Add to tapped history (most recent first, max 30)
94
+ setTappedHistory(prev => {
95
+ const key = event.testID || event.accessibilityLabel || event.text;
96
+ const exists = prev.find(e => (e.testID || e.accessibilityLabel || e.text) === key);
97
+ if (exists) {
98
+ // Move to top with fresh timestamp
99
+ return [
100
+ { ...event, tappedAt: Date.now() },
101
+ ...prev.filter(e => e !== exists),
102
+ ].slice(0, 30);
103
+ }
104
+ return [{ ...event, tappedAt: Date.now() }, ...prev].slice(0, 30);
105
+ });
106
+ });
107
+ return unsubscribe;
108
+ }, [visible]);
109
+ // Listen for registry changes (elements mounting/unmounting)
110
+ (0, react_1.useEffect)(() => {
111
+ const unsubscribe = (0, ElementRegistry_1.onRegistryChange)(() => {
112
+ setRegistryElements((0, ElementRegistry_1.getRegisteredElements)(screenName));
113
+ });
114
+ return unsubscribe;
115
+ }, [screenName]);
116
+ // Update registry elements when screen changes
117
+ (0, react_1.useEffect)(() => {
118
+ setRegistryElements((0, ElementRegistry_1.getRegisteredElements)(screenName));
119
+ }, [screenName]);
120
+ // Merge registry elements with scanned elements (deduplicated)
121
+ const allElements = react_1.default.useMemo(() => {
122
+ const merged = [...registryElements];
123
+ const seen = new Set(registryElements.map(e => e.testID || e.accessibilityLabel || e.text || '').filter(Boolean));
124
+ for (const el of elements) {
125
+ const key = el.testID || el.accessibilityLabel || el.text || '';
126
+ if (key && !seen.has(key)) {
127
+ seen.add(key);
128
+ merged.push(el);
129
+ }
130
+ }
131
+ return merged;
132
+ }, [elements, registryElements]);
133
+ // Fetch configured events for this screen
134
+ const fetchEvents = (0, react_1.useCallback)(async () => {
135
+ if (!state?.siteId)
136
+ return;
137
+ try {
138
+ const result = await (0, network_1.sdkFetch)('GET', `/api/engagement/setup/mobile-element-configs?siteId=${state.siteId}&screenName=${encodeURIComponent(screenName)}`);
139
+ const data = result.data?.data ?? result.data ?? [];
140
+ setConfiguredEvents(Array.isArray(data) ? data : []);
141
+ }
142
+ catch (err) {
143
+ console.warn('[CXPinsight:Setup] Failed to fetch events:', err);
144
+ }
145
+ }, [state?.siteId, screenName]);
146
+ (0, react_1.useEffect)(() => {
147
+ if (panelOpen)
148
+ fetchEvents();
149
+ }, [panelOpen, fetchEvents]);
150
+ // Handle element selection
151
+ const handleSelectElement = (element) => {
152
+ setSelectedElement(element);
153
+ setEventName((0, ElementIdentifier_1.extractLabel)(element));
154
+ setEventType(element.elementType === 'text_input' ? 'input_focus' : 'tap');
155
+ setFormTestID(element.testID || '');
156
+ setFormAccessibilityLabel(element.accessibilityLabel || '');
157
+ // Close panel first, then show form — avoids stacking two Modals
158
+ setPanelOpen(false);
159
+ setTimeout(() => setShowEventForm(true), 300);
160
+ };
161
+ // Save event config
162
+ const handleSaveEvent = async () => {
163
+ if (!state?.siteId || !eventName.trim())
164
+ return;
165
+ if (!formTestID.trim() && !formAccessibilityLabel.trim()) {
166
+ react_native_1.Alert.alert('Identifier Required', 'Please enter a testID or accessibility label to identify the element.');
167
+ return;
168
+ }
169
+ setLoading(true);
170
+ try {
171
+ const identifier = {
172
+ testID: formTestID.trim() || undefined,
173
+ accessibilityLabel: formAccessibilityLabel.trim() || undefined,
174
+ hierarchyPath: selectedElement?.hierarchyPath || undefined,
175
+ };
176
+ await (0, network_1.sdkFetch)('POST', '/api/engagement/setup/mobile-element-configs', {
177
+ siteId: state.siteId,
178
+ name: eventName.trim(),
179
+ screenName,
180
+ elementIdentifier: identifier,
181
+ elementLabel: eventName.trim(),
182
+ elementType: selectedElement?.elementType || 'button',
183
+ eventType,
184
+ trigger: eventType,
185
+ captureData,
186
+ createdVia: 'sdk_setup',
187
+ });
188
+ setShowEventForm(false);
189
+ setSelectedElement(null);
190
+ setEventName('');
191
+ setFormTestID('');
192
+ setFormAccessibilityLabel('');
193
+ await fetchEvents();
194
+ }
195
+ catch (err) {
196
+ react_native_1.Alert.alert('Error', 'Failed to save event configuration');
197
+ }
198
+ finally {
199
+ setLoading(false);
200
+ }
201
+ };
202
+ // Delete event config
203
+ const handleDeleteEvent = async (configId) => {
204
+ react_native_1.Alert.alert('Delete Event', 'Remove this event configuration?', [
205
+ { text: 'Cancel', style: 'cancel' },
206
+ {
207
+ text: 'Delete',
208
+ style: 'destructive',
209
+ onPress: async () => {
210
+ await (0, network_1.sdkFetch)('DELETE', `/api/engagement/setup/mobile-element-configs/${configId}`);
211
+ await fetchEvents();
212
+ },
213
+ },
214
+ ]);
215
+ };
216
+ // Handle exit setup
217
+ const handleExit = () => {
218
+ react_native_1.Alert.alert('Exit Setup', 'End the setup session?', [
219
+ { text: 'Cancel', style: 'cancel' },
220
+ { text: 'Exit', style: 'destructive', onPress: () => (0, SetupController_1.endSetup)() },
221
+ ]);
222
+ };
223
+ if (!visible)
224
+ return null;
225
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!panelOpen && !showEventForm && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.fabAnchor, pointerEvents: "box-none", children: (0, jsx_runtime_1.jsx)(FloatingButton, { visible: true, onPress: () => setPanelOpen(true) }) })), panelOpen && (0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: true, animationType: "slide", transparent: true, statusBarTranslucent: true, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.panelBackdrop, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.panel, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.panelHeader, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.panelTitle, children: "CXP Setup Mode" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.panelSubtitle, children: screenName })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.panelHeaderActions, children: [(0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { onPress: handleExit, style: styles.exitButton, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.exitButtonText, children: "Exit" }) }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { onPress: () => setPanelOpen(false), style: styles.closeButton, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.closeButtonText, children: "\u00D7" }) })] })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.tabs, children: [(0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.tab, activeTab === 'elements' && styles.tabActive], onPress: () => setActiveTab('elements'), children: (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: [styles.tabText, activeTab === 'elements' && styles.tabTextActive], children: ["Tapped (", tappedHistory.length, ")"] }) }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.tab, activeTab === 'events' && styles.tabActive], onPress: () => setActiveTab('events'), children: (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: [styles.tabText, activeTab === 'events' && styles.tabTextActive], children: ["Events (", configuredEvents.length, ")"] }) })] }), (0, jsx_runtime_1.jsx)(react_native_1.ScrollView, { style: styles.panelContent, children: activeTab === 'elements' ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
226
+ padding: 12,
227
+ marginBottom: 8,
228
+ backgroundColor: 'rgba(214,245,81,0.08)',
229
+ borderRadius: 8,
230
+ borderWidth: 1,
231
+ borderColor: 'rgba(214,245,81,0.2)',
232
+ }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { color: '#D6F551', fontSize: 13, fontWeight: '600', marginBottom: 4 }, children: "Close this panel and use your app" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { color: 'rgba(255,255,255,0.6)', fontSize: 12, lineHeight: 18 }, children: "Navigate to any screen and tap buttons, links, or inputs. Every interaction appears here. Then tap \"Track This\" to create an event." })] }), tappedHistory.length > 0 && ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.refreshButton, { marginBottom: 8 }], onPress: () => setTappedHistory([]), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.refreshButtonText, children: "Clear History" }) })), tappedHistory.length === 0 ? ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.emptyState, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.emptyText, children: "No interactions captured yet." }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.emptySubtext, children: "Close this panel, navigate your app, and tap any button or input. Come back to see what was captured." })] })) : (tappedHistory.map((element, index) => {
233
+ const quality = (0, ElementIdentifier_1.identifierQuality)((0, ElementIdentifier_1.buildIdentifier)(element));
234
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.elementRow, onPress: () => handleSelectElement(element), children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.elementIcon, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.elementIconText, children: element.elementType === 'button' ? '⬚' :
235
+ element.elementType === 'text_input' ? '⌨' :
236
+ element.elementType === 'switch' ? '⇆' :
237
+ element.elementType === 'link' ? '🔗' : '◉' }) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.elementInfo, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.elementLabel, numberOfLines: 1, children: (0, ElementIdentifier_1.extractLabel)(element) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.elementMeta, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.elementType, children: element.elementType }), element.testID && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.testIdBadge, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.testIdText, children: "testID" }) })), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.qualityDot, {
238
+ backgroundColor: quality === 'excellent' ? '#10B981' :
239
+ quality === 'good' ? '#F59E0B' :
240
+ quality === 'fair' ? '#F97316' : '#EF4444'
241
+ }] })] })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { alignItems: 'center', gap: 2 }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { fontSize: 10, color: 'rgba(255,255,255,0.3)' }, children: new Date(element.tappedAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { fontSize: 11, color: '#D6F551', fontWeight: '600' }, children: "Track" })] })] }, `${element.testID || element.hierarchyPath || index}`));
242
+ }))] })) : ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: configuredEvents.length === 0 ? ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.emptyState, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.emptyText, children: "No events configured for this screen." }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.emptySubtext, children: "Select an element from the Elements tab to create one." })] })) : (configuredEvents.map((event) => ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.eventRow, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.eventInfo, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.eventName, children: event.name }), (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.eventMeta, children: [event.eventType, " \u00B7 ", event.elementType, " \u00B7 ", event.isActive ? 'Active' : 'Inactive'] })] }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { onPress: () => handleDeleteEvent(event.configId), style: styles.deleteButton, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.deleteButtonText, children: "\u2715" }) })] }, event.configId)))) })) })] }) }) }), showEventForm && (0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: true, animationType: "slide", transparent: true, statusBarTranslucent: true, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.formBackdrop, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.formPanel, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.formTitle, children: "Configure Event" }), selectedElement && ((0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: styles.formSubtitle, children: [selectedElement.elementType, " \u2014 ", (0, ElementIdentifier_1.extractLabel)(selectedElement), selectedElement.testID && `\ntestID: ${selectedElement.testID}`] })), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.fieldLabel, children: "Event Name" }), (0, jsx_runtime_1.jsx)(react_native_1.TextInput, { style: styles.textInput, value: eventName, onChangeText: setEventName, placeholder: "e.g. Checkout Button Tap", placeholderTextColor: "#666" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.fieldLabel, children: "Element testID" }), (0, jsx_runtime_1.jsx)(react_native_1.TextInput, { style: styles.textInput, value: formTestID, onChangeText: setFormTestID, placeholder: "e.g. checkout-btn, submit-order", placeholderTextColor: "#666", autoCapitalize: "none", autoCorrect: false }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.fieldLabel, children: "Accessibility Label (alternative)" }), (0, jsx_runtime_1.jsx)(react_native_1.TextInput, { style: styles.textInput, value: formAccessibilityLabel, onChangeText: setFormAccessibilityLabel, placeholder: "e.g. Place Order, Submit", placeholderTextColor: "#666" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.fieldLabel, children: "Event Type" }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.chipRow, children: EVENT_TYPES.map(({ value, label }) => ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.chip, eventType === value && styles.chipActive], onPress: () => setEventType(value), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.chipText, eventType === value && styles.chipTextActive], children: label }) }, value))) }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.fieldLabel, children: "Capture Data" }), CAPTURE_OPTIONS.map(({ value, label }) => ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.checkRow, children: [(0, jsx_runtime_1.jsx)(react_native_1.Switch, { value: captureData.includes(value), onValueChange: (on) => {
243
+ setCaptureData(prev => on ? [...prev, value] : prev.filter(v => v !== value));
244
+ }, trackColor: { true: '#D6F551', false: '#333' }, thumbColor: "#fff" }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.checkLabel, children: label })] }, value))), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.formActions, children: [(0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: styles.cancelButton, onPress: () => { setShowEventForm(false); setSelectedElement(null); setFormTestID(''); setFormAccessibilityLabel(''); }, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.cancelButtonText, children: "Cancel" }) }), (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.saveButton, loading && { opacity: 0.6 }], onPress: handleSaveEvent, disabled: loading || !eventName.trim(), children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.saveButtonText, children: loading ? 'Saving...' : 'Save Event' }) })] })] }) }) })] }));
245
+ }
246
+ // ── Styles ──
247
+ const styles = react_native_1.StyleSheet.create({
248
+ // Zero-size anchor for FAB — no layout impact, just provides positioning context
249
+ fabAnchor: {
250
+ position: 'absolute',
251
+ top: 0,
252
+ left: 0,
253
+ right: 0,
254
+ bottom: 0,
255
+ },
256
+ // FAB button
257
+ fab: {
258
+ position: 'absolute',
259
+ bottom: 160,
260
+ right: 16,
261
+ width: 56,
262
+ height: 56,
263
+ borderRadius: 28,
264
+ backgroundColor: '#D6F551',
265
+ justifyContent: 'center',
266
+ alignItems: 'center',
267
+ elevation: 8,
268
+ shadowColor: '#000',
269
+ shadowOffset: { width: 0, height: 4 },
270
+ shadowOpacity: 0.3,
271
+ shadowRadius: 8,
272
+ zIndex: 999999,
273
+ },
274
+ fabText: { fontSize: 12, fontWeight: '900', color: '#030712', letterSpacing: 1 },
275
+ fabBadge: {
276
+ position: 'absolute',
277
+ top: -4,
278
+ right: -4,
279
+ backgroundColor: '#EF4444',
280
+ borderRadius: 6,
281
+ paddingHorizontal: 4,
282
+ paddingVertical: 1,
283
+ },
284
+ fabBadgeText: { fontSize: 7, fontWeight: '700', color: '#fff', letterSpacing: 0.5 },
285
+ // Panel
286
+ panelBackdrop: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end' },
287
+ panel: {
288
+ maxHeight: SCREEN_HEIGHT * 0.8,
289
+ backgroundColor: '#111827',
290
+ borderTopLeftRadius: 20,
291
+ borderTopRightRadius: 20,
292
+ overflow: 'hidden',
293
+ },
294
+ panelHeader: {
295
+ flexDirection: 'row',
296
+ justifyContent: 'space-between',
297
+ alignItems: 'center',
298
+ padding: 16,
299
+ borderBottomWidth: 1,
300
+ borderBottomColor: 'rgba(255,255,255,0.1)',
301
+ },
302
+ panelTitle: { fontSize: 16, fontWeight: '700', color: '#D6F551' },
303
+ panelSubtitle: { fontSize: 12, color: 'rgba(255,255,255,0.5)', marginTop: 2 },
304
+ panelHeaderActions: { flexDirection: 'row', alignItems: 'center', gap: 8 },
305
+ exitButton: {
306
+ paddingHorizontal: 12,
307
+ paddingVertical: 6,
308
+ backgroundColor: 'rgba(239,68,68,0.15)',
309
+ borderRadius: 6,
310
+ borderWidth: 1,
311
+ borderColor: 'rgba(239,68,68,0.3)',
312
+ },
313
+ exitButtonText: { fontSize: 12, fontWeight: '600', color: '#EF4444' },
314
+ closeButton: { padding: 4 },
315
+ closeButtonText: { fontSize: 24, color: 'rgba(255,255,255,0.5)' },
316
+ // Tabs
317
+ tabs: { flexDirection: 'row', borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.1)' },
318
+ tab: { flex: 1, paddingVertical: 12, alignItems: 'center' },
319
+ tabActive: { borderBottomWidth: 2, borderBottomColor: '#D6F551' },
320
+ tabText: { fontSize: 13, fontWeight: '500', color: 'rgba(255,255,255,0.5)' },
321
+ tabTextActive: { color: '#D6F551' },
322
+ // Content
323
+ panelContent: { padding: 12 },
324
+ refreshButton: {
325
+ padding: 10,
326
+ marginBottom: 8,
327
+ backgroundColor: 'rgba(255,255,255,0.05)',
328
+ borderRadius: 8,
329
+ alignItems: 'center',
330
+ },
331
+ refreshButtonText: { fontSize: 13, fontWeight: '500', color: '#D6F551' },
332
+ // Elements
333
+ elementRow: {
334
+ flexDirection: 'row',
335
+ alignItems: 'center',
336
+ padding: 12,
337
+ marginBottom: 4,
338
+ backgroundColor: 'rgba(255,255,255,0.03)',
339
+ borderRadius: 8,
340
+ borderWidth: 1,
341
+ borderColor: 'rgba(255,255,255,0.06)',
342
+ },
343
+ elementIcon: { width: 36, height: 36, borderRadius: 8, backgroundColor: 'rgba(214,245,81,0.1)', justifyContent: 'center', alignItems: 'center', marginRight: 12 },
344
+ elementIconText: { fontSize: 16 },
345
+ elementInfo: { flex: 1 },
346
+ elementLabel: { fontSize: 14, fontWeight: '500', color: '#fff' },
347
+ elementMeta: { flexDirection: 'row', alignItems: 'center', gap: 6, marginTop: 4 },
348
+ elementType: { fontSize: 11, color: 'rgba(255,255,255,0.4)' },
349
+ testIdBadge: { backgroundColor: 'rgba(16,185,129,0.15)', paddingHorizontal: 6, paddingVertical: 1, borderRadius: 4 },
350
+ testIdText: { fontSize: 9, fontWeight: '600', color: '#10B981' },
351
+ qualityDot: { width: 6, height: 6, borderRadius: 3 },
352
+ addArrow: { fontSize: 20, color: '#D6F551', fontWeight: '300', marginLeft: 8 },
353
+ // Events
354
+ eventRow: {
355
+ flexDirection: 'row',
356
+ alignItems: 'center',
357
+ padding: 12,
358
+ marginBottom: 4,
359
+ backgroundColor: 'rgba(255,255,255,0.03)',
360
+ borderRadius: 8,
361
+ borderWidth: 1,
362
+ borderColor: 'rgba(255,255,255,0.06)',
363
+ },
364
+ eventInfo: { flex: 1 },
365
+ eventName: { fontSize: 14, fontWeight: '500', color: '#fff' },
366
+ eventMeta: { fontSize: 11, color: 'rgba(255,255,255,0.4)', marginTop: 2 },
367
+ deleteButton: { padding: 8 },
368
+ deleteButtonText: { fontSize: 14, color: '#EF4444' },
369
+ // Empty
370
+ emptyState: { paddingVertical: 40, alignItems: 'center' },
371
+ emptyText: { fontSize: 14, color: 'rgba(255,255,255,0.5)', textAlign: 'center' },
372
+ emptySubtext: { fontSize: 12, color: 'rgba(255,255,255,0.3)', textAlign: 'center', marginTop: 8, paddingHorizontal: 32 },
373
+ // Form
374
+ formBackdrop: { flex: 1, backgroundColor: 'rgba(0,0,0,0.6)', justifyContent: 'center', padding: 20 },
375
+ formPanel: { backgroundColor: '#111827', borderRadius: 16, padding: 20, maxHeight: SCREEN_HEIGHT * 0.75 },
376
+ formTitle: { fontSize: 18, fontWeight: '700', color: '#D6F551', marginBottom: 4 },
377
+ formSubtitle: { fontSize: 12, color: 'rgba(255,255,255,0.5)', marginBottom: 16 },
378
+ fieldLabel: { fontSize: 12, fontWeight: '600', color: 'rgba(255,255,255,0.7)', marginBottom: 6, marginTop: 12 },
379
+ textInput: {
380
+ backgroundColor: 'rgba(255,255,255,0.05)',
381
+ borderWidth: 1,
382
+ borderColor: 'rgba(255,255,255,0.1)',
383
+ borderRadius: 8,
384
+ padding: 12,
385
+ color: '#fff',
386
+ fontSize: 14,
387
+ },
388
+ chipRow: { flexDirection: 'row', flexWrap: 'wrap', gap: 6 },
389
+ chip: {
390
+ paddingHorizontal: 12,
391
+ paddingVertical: 6,
392
+ backgroundColor: 'rgba(255,255,255,0.05)',
393
+ borderRadius: 16,
394
+ borderWidth: 1,
395
+ borderColor: 'rgba(255,255,255,0.1)',
396
+ },
397
+ chipActive: { backgroundColor: 'rgba(214,245,81,0.15)', borderColor: 'rgba(214,245,81,0.3)' },
398
+ chipText: { fontSize: 12, color: 'rgba(255,255,255,0.6)' },
399
+ chipTextActive: { color: '#D6F551', fontWeight: '600' },
400
+ checkRow: { flexDirection: 'row', alignItems: 'center', gap: 10, marginVertical: 4 },
401
+ checkLabel: { fontSize: 13, color: 'rgba(255,255,255,0.7)' },
402
+ formActions: { flexDirection: 'row', justifyContent: 'flex-end', gap: 12, marginTop: 20 },
403
+ cancelButton: { paddingHorizontal: 16, paddingVertical: 10, borderRadius: 8 },
404
+ cancelButtonText: { fontSize: 14, color: 'rgba(255,255,255,0.5)' },
405
+ saveButton: { paddingHorizontal: 20, paddingVertical: 10, backgroundColor: '#D6F551', borderRadius: 8 },
406
+ saveButtonText: { fontSize: 14, fontWeight: '600', color: '#030712' },
407
+ });
408
+ //# sourceMappingURL=SetupOverlay.js.map