react-native-inapp-inspector 2.2.2 → 2.2.3

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 (97) hide show
  1. package/dist/commonjs/constants/version.d.ts +1 -1
  2. package/dist/commonjs/constants/version.js +1 -1
  3. package/dist/esm/constants/version.d.ts +1 -1
  4. package/dist/esm/constants/version.js +1 -1
  5. package/package.json +2 -1
  6. package/src/analytics.ts +35 -0
  7. package/src/bundle.ts +25 -0
  8. package/src/components/AnalyticsDetail.tsx +865 -0
  9. package/src/components/AnalyticsEventCard.tsx +441 -0
  10. package/src/components/AnalyticsGraph.tsx +583 -0
  11. package/src/components/AnimatedEntrance.tsx +64 -0
  12. package/src/components/AppHeaderLogo.tsx +109 -0
  13. package/src/components/BrandCircleIcon.tsx +144 -0
  14. package/src/components/BrandSquareIcon.tsx +144 -0
  15. package/src/components/CodeSnippet.tsx +725 -0
  16. package/src/components/ConsoleLogCard.tsx +628 -0
  17. package/src/components/CopyButton.tsx +87 -0
  18. package/src/components/DiffViewer.tsx +82 -0
  19. package/src/components/DomainHeader.tsx +237 -0
  20. package/src/components/EmptyState.tsx +73 -0
  21. package/src/components/EndOfListFooter.tsx +100 -0
  22. package/src/components/ErrorBoundary.tsx +688 -0
  23. package/src/components/HeadersSection.tsx +192 -0
  24. package/src/components/HighlightText.tsx +100 -0
  25. package/src/components/Inspector/AnalyticsFilterModal.tsx +1250 -0
  26. package/src/components/Inspector/AnalyticsTab.tsx +1336 -0
  27. package/src/components/Inspector/BundleTab.tsx +4731 -0
  28. package/src/components/Inspector/ConsoleTab.tsx +702 -0
  29. package/src/components/Inspector/CrashDetail.tsx +941 -0
  30. package/src/components/Inspector/CrashFilterModal.tsx +721 -0
  31. package/src/components/Inspector/CrashTab.tsx +871 -0
  32. package/src/components/Inspector/FabLauncher.tsx +80 -0
  33. package/src/components/Inspector/InspectorContext.tsx +28 -0
  34. package/src/components/Inspector/InspectorHeader.tsx +973 -0
  35. package/src/components/Inspector/LogDetail.tsx +1427 -0
  36. package/src/components/Inspector/MainScreen.tsx +258 -0
  37. package/src/components/Inspector/NavigationTracker.tsx +13 -0
  38. package/src/components/Inspector/NetworkDetail.tsx +794 -0
  39. package/src/components/Inspector/NetworkTab.tsx +1095 -0
  40. package/src/components/Inspector/NpmUpdateToast.tsx +392 -0
  41. package/src/components/Inspector/PerformanceTab.tsx +1894 -0
  42. package/src/components/Inspector/ReduxDetail.tsx +1651 -0
  43. package/src/components/Inspector/ReduxTab.tsx +954 -0
  44. package/src/components/Inspector/SettingsPanel.tsx +3181 -0
  45. package/src/components/Inspector/TabBar.tsx +187 -0
  46. package/src/components/Inspector/TelemetryConsentModal.tsx +392 -0
  47. package/src/components/Inspector/UpdateAvailableModal.tsx +545 -0
  48. package/src/components/JsonViewer.tsx +486 -0
  49. package/src/components/LogCard.tsx +491 -0
  50. package/src/components/LogSyntaxHighlighter.tsx +178 -0
  51. package/src/components/MetaAccordion.tsx +340 -0
  52. package/src/components/MiniBarChart.tsx +42 -0
  53. package/src/components/MiniLineChart.tsx +33 -0
  54. package/src/components/NetworkIcons.tsx +2118 -0
  55. package/src/components/SectionHeader.tsx +113 -0
  56. package/src/components/SegmentedTabs.tsx +83 -0
  57. package/src/components/Slider.tsx +300 -0
  58. package/src/components/SourcePageCard.tsx +148 -0
  59. package/src/components/Toast.tsx +131 -0
  60. package/src/components/TouchableScale.tsx +91 -0
  61. package/src/components/TreeNode.tsx +186 -0
  62. package/src/console.ts +24 -0
  63. package/src/constants/index.ts +38 -0
  64. package/src/constants/version.ts +3 -0
  65. package/src/crash.ts +32 -0
  66. package/src/customHooks/analyticsLogger.ts +336 -0
  67. package/src/customHooks/bundleAnalyzer.ts +1231 -0
  68. package/src/customHooks/consoleLogger.ts +497 -0
  69. package/src/customHooks/crashHandler.ts +944 -0
  70. package/src/customHooks/logFilters.ts +32 -0
  71. package/src/customHooks/networkLogger.ts +419 -0
  72. package/src/customHooks/performanceTracker.ts +1014 -0
  73. package/src/customHooks/reduxLogger.ts +406 -0
  74. package/src/customHooks/useAccordion.tsx +60 -0
  75. package/src/decorators/index.ts +184 -0
  76. package/src/helpers/gaAnalyticsRegistry.ts +204 -0
  77. package/src/helpers/index.ts +860 -0
  78. package/src/helpers/memoryManager.ts +138 -0
  79. package/src/helpers/searchQueryParser.ts +283 -0
  80. package/src/helpers/settingsStore.ts +171 -0
  81. package/src/helpers/telemetry.ts +505 -0
  82. package/src/helpers/toast.ts +17 -0
  83. package/src/i18n/index.ts +69 -0
  84. package/src/i18n/locales/en.json +1052 -0
  85. package/src/index.tsx +2336 -0
  86. package/src/native/NativeInspector.ts +397 -0
  87. package/src/native/NativeNetworkInspector.ts +24 -0
  88. package/src/network.ts +22 -0
  89. package/src/performance.ts +38 -0
  90. package/src/redux.ts +23 -0
  91. package/src/styles/AppColors.ts +408 -0
  92. package/src/styles/AppFonts.ts +8 -0
  93. package/src/styles/common.ts +209 -0
  94. package/src/styles/index.ts +1570 -0
  95. package/src/types/enums.ts +194 -0
  96. package/src/types/index.ts +34 -0
  97. package/src/types/interfaces.ts +515 -0
@@ -0,0 +1,583 @@
1
+ import React from 'react';
2
+ import {View, Text, ScrollView, Dimensions, StyleSheet} from 'react-native';
3
+ import Svg, {
4
+ Rect,
5
+ Text as SvgText,
6
+ Line,
7
+ Circle,
8
+ Path,
9
+ Defs,
10
+ LinearGradient,
11
+ Stop,
12
+ } from 'react-native-svg';
13
+ import {AppColors} from '../styles/AppColors';
14
+ import {AppFonts} from '../styles/AppFonts';
15
+ import {AnalyticsGraphProps} from '../types';
16
+
17
+ const BAR_HEIGHT = 24;
18
+ const PADDING_Y = 12;
19
+
20
+ const AnalyticsGraph = ({event, accentColor}: AnalyticsGraphProps) => {
21
+ const params = event.params || {};
22
+
23
+ // 1. Check for E-commerce items array
24
+ const itemsArray = Array.isArray(params.items) ? params.items : null;
25
+ const filteredItems =
26
+ itemsArray?.filter((item: any) => typeof item.price === 'number') || [];
27
+
28
+ // 2. Discover root-level numeric fields (exclude ids)
29
+ const rootNumericKeys: {key: string; value: number}[] = [];
30
+ Object.entries(params).forEach(([k, v]) => {
31
+ if (
32
+ typeof v === 'number' &&
33
+ !k.toLowerCase().includes('id') &&
34
+ !k.toLowerCase().includes('timestamp')
35
+ ) {
36
+ rootNumericKeys.push({key: k, value: v});
37
+ }
38
+ });
39
+
40
+ // 3. Discover dates (YYYY-MM-DD format commonly used in booking/flights)
41
+ const dateKeys: {key: string; date: Date}[] = [];
42
+ Object.entries(params).forEach(([k, v]) => {
43
+ if (
44
+ typeof v === 'string' &&
45
+ v.length >= 10 &&
46
+ /^\d{4}-\d{2}-\d{2}/.test(v)
47
+ ) {
48
+ const d = new Date(v);
49
+ if (!isNaN(d.getTime())) {
50
+ dateKeys.push({key: k, date: d});
51
+ }
52
+ }
53
+ });
54
+
55
+ // 4. Calculate parameter types
56
+ const paramTypes = {string: 0, number: 0, boolean: 0, object: 0};
57
+ const strings: {label: string; value: number}[] = [];
58
+
59
+ Object.entries(params).forEach(([k, v]) => {
60
+ const t = typeof v;
61
+ if (t === 'string') {
62
+ paramTypes.string++;
63
+ strings.push({label: k, value: (v as string).length});
64
+ } else if (t === 'number') {
65
+ paramTypes.number++;
66
+ } else if (t === 'boolean') {
67
+ paramTypes.boolean++;
68
+ } else if (t === 'object' && v !== null) {
69
+ paramTypes.object++;
70
+ }
71
+ });
72
+
73
+ const typeData = [
74
+ {label: 'Strings', value: paramTypes.string, color: AppColors.purple},
75
+ {label: 'Numbers', value: paramTypes.number, color: AppColors.skyBlue},
76
+ {label: 'Booleans', value: paramTypes.boolean, color: AppColors.amber500}, // Amber
77
+ {label: 'Objects', value: paramTypes.object, color: AppColors.greenColor},
78
+ ].filter(d => d.value > 0);
79
+
80
+ strings.sort((a, b) => b.value - a.value);
81
+ const topStrings = strings.slice(0, 5);
82
+
83
+ const hasItemsChart = filteredItems.length > 0;
84
+ const hasRootNumericChart = rootNumericKeys.length > 0;
85
+ const hasDatesChart = dateKeys.length > 0;
86
+ const hasStringsChart = topStrings.length > 0;
87
+ const hasTypeData = typeData.length > 0;
88
+
89
+ const screenWidth = Dimensions.get('window').width - 60; // Padding adjustments
90
+ const rightMargin = 40; // Space for labels at the end of the bar
91
+ const maxBarWidth = screenWidth - rightMargin;
92
+
93
+ return (
94
+ <View style={graphStyles.container}>
95
+ <Text style={graphStyles.headerTitle}>Data Visualization</Text>
96
+
97
+ {hasTypeData && (
98
+ <View style={graphStyles.chartBlock}>
99
+ <Text style={graphStyles.chartTitle}>Data Types Breakdown</Text>
100
+ <DonutChart data={typeData} />
101
+ </View>
102
+ )}
103
+
104
+ {hasStringsChart && (
105
+ <View style={graphStyles.chartBlock}>
106
+ <Text style={graphStyles.chartTitle}>Highest Payload Strings</Text>
107
+ <BarChart
108
+ data={topStrings}
109
+ accentColor={AppColors.purple}
110
+ maxBarWidth={maxBarWidth}
111
+ isGradient
112
+ />
113
+ </View>
114
+ )}
115
+
116
+ {hasRootNumericChart && (
117
+ <View style={graphStyles.chartBlock}>
118
+ <Text style={graphStyles.chartTitle}>Top-Level Metrics</Text>
119
+ <GaugeChart
120
+ data={rootNumericKeys.map(d => ({label: d.key, value: d.value}))}
121
+ accentColor={accentColor}
122
+ />
123
+ </View>
124
+ )}
125
+
126
+ {hasDatesChart && (
127
+ <View style={graphStyles.chartBlock}>
128
+ <Text style={graphStyles.chartTitle}>Important Dates</Text>
129
+ <CalendarChart
130
+ data={dateKeys.map(d => ({label: d.key, date: d.date}))}
131
+ accentColor={accentColor}
132
+ />
133
+ </View>
134
+ )}
135
+
136
+ {hasItemsChart && (
137
+ <View style={graphStyles.chartBlock}>
138
+ <Text style={graphStyles.chartTitle}>Item Prices</Text>
139
+ <BarChart
140
+ data={filteredItems.map((item: any, i) => ({
141
+ label: item.item_name || item.item_id || `Item ${i + 1}`,
142
+ value: item.price,
143
+ }))}
144
+ accentColor={AppColors.successGreen}
145
+ maxBarWidth={maxBarWidth}
146
+ isGradient={false}
147
+ />
148
+ </View>
149
+ )}
150
+ </View>
151
+ );
152
+ };
153
+
154
+ // --- Donut Chart Helpers ---
155
+ const polarToCartesian = (
156
+ centerX: number,
157
+ centerY: number,
158
+ radius: number,
159
+ angleInDegrees: number,
160
+ ) => {
161
+ const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
162
+ return {
163
+ x: centerX + radius * Math.cos(angleInRadians),
164
+ y: centerY + radius * Math.sin(angleInRadians),
165
+ };
166
+ };
167
+
168
+ const getPiePath = (
169
+ x: number,
170
+ y: number,
171
+ radius: number,
172
+ innerRadius: number,
173
+ startAngle: number,
174
+ endAngle: number,
175
+ ) => {
176
+ const start = polarToCartesian(x, y, radius, endAngle);
177
+ const end = polarToCartesian(x, y, radius, startAngle);
178
+ const startInner = polarToCartesian(x, y, innerRadius, endAngle);
179
+ const endInner = polarToCartesian(x, y, innerRadius, startAngle);
180
+ const largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1';
181
+
182
+ return `
183
+ M ${start.x} ${start.y}
184
+ A ${radius} ${radius} 0 ${largeArcFlag} 0 ${end.x} ${end.y}
185
+ L ${endInner.x} ${endInner.y}
186
+ A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 1 ${startInner.x} ${startInner.y}
187
+ Z
188
+ `;
189
+ };
190
+
191
+ const DonutChart = ({
192
+ data,
193
+ }: {
194
+ data: {label: string; value: number; color: string}[];
195
+ }) => {
196
+ const total = data.reduce((sum, d) => sum + d.value, 0);
197
+ if (total === 0) return null;
198
+
199
+ let currentAngle = 0;
200
+ const radius = 50;
201
+ const innerRadius = 30;
202
+ const center = 60;
203
+
204
+ return (
205
+ <View style={{flexDirection: 'row', alignItems: 'center'}}>
206
+ <Svg width="120" height="120" viewBox="0 0 120 120">
207
+ {data.map((d, i) => {
208
+ if (d.value === 0) return null;
209
+ const angle = (d.value / total) * 360;
210
+ const startAngle = currentAngle;
211
+ const endAngle = currentAngle + angle;
212
+ currentAngle += angle;
213
+
214
+ if (angle === 360) {
215
+ return (
216
+ <React.Fragment key={i}>
217
+ <Circle cx={center} cy={center} r={radius} fill={d.color} />
218
+ <Circle
219
+ cx={center}
220
+ cy={center}
221
+ r={innerRadius}
222
+ fill={AppColors.primaryLight}
223
+ />
224
+ </React.Fragment>
225
+ );
226
+ }
227
+
228
+ const path = getPiePath(
229
+ center,
230
+ center,
231
+ radius,
232
+ innerRadius,
233
+ startAngle,
234
+ endAngle,
235
+ );
236
+ return <Path key={i} d={path} fill={d.color} />;
237
+ })}
238
+ </Svg>
239
+ <View style={{marginLeft: 16, flex: 1, gap: 6}}>
240
+ {data.map((d, i) => {
241
+ if (d.value === 0) return null;
242
+ return (
243
+ <View
244
+ key={i}
245
+ style={{flexDirection: 'row', alignItems: 'center', gap: 6}}>
246
+ <View
247
+ style={{
248
+ width: 10,
249
+ height: 10,
250
+ borderRadius: 5,
251
+ backgroundColor: d.color,
252
+ }}
253
+ />
254
+ <Text
255
+ style={{
256
+ fontFamily: AppFonts.interMedium,
257
+ fontSize: 11,
258
+ color: AppColors.grayTextStrong,
259
+ }}>
260
+ {d.label} ({d.value})
261
+ </Text>
262
+ </View>
263
+ );
264
+ })}
265
+ </View>
266
+ </View>
267
+ );
268
+ };
269
+
270
+ const GaugeChart = ({
271
+ data,
272
+ accentColor,
273
+ }: {
274
+ data: {label: string; value: number}[];
275
+ accentColor: string;
276
+ }) => {
277
+ const maxVal = Math.max(...data.map(d => Math.abs(d.value)), 1);
278
+ const radius = 26;
279
+ const stroke = 5;
280
+ const circumference = 2 * Math.PI * radius;
281
+
282
+ return (
283
+ <ScrollView
284
+ horizontal
285
+ showsHorizontalScrollIndicator={false}
286
+ contentContainerStyle={{
287
+ gap: 16,
288
+ paddingRight: 16,
289
+ paddingTop: 6,
290
+ paddingBottom: 6,
291
+ }}>
292
+ {data.map(d => {
293
+ const fillPct = Math.min(Math.abs(d.value) / maxVal, 1);
294
+ const strokeDashoffset = Math.max(
295
+ circumference - fillPct * circumference,
296
+ 0.001,
297
+ ); // avoid exact 0
298
+
299
+ return (
300
+ <View key={d.label} style={{alignItems: 'center', width: 70}}>
301
+ <Svg width="60" height="60" viewBox="0 0 60 60">
302
+ <Circle
303
+ cx="30"
304
+ cy="30"
305
+ r={radius}
306
+ stroke={AppColors.grayBorderSecondary}
307
+ strokeWidth={stroke}
308
+ fill="none"
309
+ />
310
+ <Circle
311
+ cx="30"
312
+ cy="30"
313
+ r={radius}
314
+ stroke={accentColor}
315
+ strokeWidth={stroke}
316
+ fill="none"
317
+ strokeLinecap="round"
318
+ strokeDasharray={circumference}
319
+ strokeDashoffset={strokeDashoffset}
320
+ rotation="-90"
321
+ origin="30, 30"
322
+ />
323
+ </Svg>
324
+ <View
325
+ style={{
326
+ position: 'absolute',
327
+ top: 20,
328
+ height: 20,
329
+ width: 60,
330
+ justifyContent: 'center',
331
+ alignItems: 'center',
332
+ }}>
333
+ <Text
334
+ style={{
335
+ fontFamily: AppFonts.interBold,
336
+ fontSize: 13,
337
+ color: AppColors.primaryBlack,
338
+ textAlign: 'center',
339
+ }}>
340
+ {d.value >= 1000 ? (d.value / 1000).toFixed(1) + 'k' : d.value}
341
+ </Text>
342
+ </View>
343
+ <Text
344
+ style={{
345
+ fontFamily: AppFonts.interMedium,
346
+ fontSize: 10,
347
+ color: AppColors.grayTextWeak,
348
+ marginTop: 6,
349
+ textAlign: 'center',
350
+ }}
351
+ numberOfLines={1}>
352
+ {d.label}
353
+ </Text>
354
+ </View>
355
+ );
356
+ })}
357
+ </ScrollView>
358
+ );
359
+ };
360
+
361
+ const CalendarChart = ({
362
+ data,
363
+ accentColor,
364
+ }: {
365
+ data: {label: string; date: Date}[];
366
+ accentColor: string;
367
+ }) => {
368
+ const months = [
369
+ 'Jan',
370
+ 'Feb',
371
+ 'Mar',
372
+ 'Apr',
373
+ 'May',
374
+ 'Jun',
375
+ 'Jul',
376
+ 'Aug',
377
+ 'Sep',
378
+ 'Oct',
379
+ 'Nov',
380
+ 'Dec',
381
+ ];
382
+
383
+ return (
384
+ <ScrollView
385
+ horizontal
386
+ showsHorizontalScrollIndicator={false}
387
+ contentContainerStyle={{
388
+ gap: 16,
389
+ paddingRight: 16,
390
+ paddingTop: 6,
391
+ paddingBottom: 6,
392
+ }}>
393
+ {data.map((d, i) => {
394
+ const monthText = months[d.date.getMonth()];
395
+ const dayText = d.date.getDate();
396
+ const yearText = d.date.getFullYear();
397
+
398
+ return (
399
+ <View key={d.label + i} style={{width: 70, alignItems: 'center'}}>
400
+ <View
401
+ style={{
402
+ width: 58,
403
+ height: 62,
404
+ backgroundColor: AppColors.white,
405
+ borderRadius: 8,
406
+ borderWidth: 1,
407
+ borderColor: AppColors.grayBorderSecondary,
408
+ overflow: 'hidden',
409
+ shadowColor: AppColors.black,
410
+ shadowOpacity: 0.05,
411
+ shadowRadius: 4,
412
+ shadowOffset: {width: 0, height: 2},
413
+ elevation: 2,
414
+ }}>
415
+ {/* Calendar Header with Accent Color */}
416
+ <View
417
+ style={{
418
+ backgroundColor: accentColor,
419
+ height: 18,
420
+ justifyContent: 'center',
421
+ alignItems: 'center',
422
+ }}>
423
+ <Text
424
+ style={{
425
+ fontFamily: AppFonts.interBold,
426
+ fontSize: 9,
427
+ color: AppColors.white,
428
+ textTransform: 'uppercase',
429
+ letterSpacing: 0.5,
430
+ }}>
431
+ {monthText} {yearText}
432
+ </Text>
433
+ </View>
434
+ {/* Calendar Body */}
435
+ <View
436
+ style={{
437
+ flex: 1,
438
+ justifyContent: 'center',
439
+ alignItems: 'center',
440
+ backgroundColor: AppColors.grayBackground,
441
+ }}>
442
+ <Text
443
+ style={{
444
+ fontFamily: AppFonts.interBold,
445
+ fontSize: 24,
446
+ color: AppColors.primaryBlack,
447
+ }}>
448
+ {dayText}
449
+ </Text>
450
+ </View>
451
+ </View>
452
+
453
+ <Text
454
+ style={{
455
+ fontFamily: AppFonts.interMedium,
456
+ fontSize: 10,
457
+ color: AppColors.grayTextWeak,
458
+ marginTop: 8,
459
+ textAlign: 'center',
460
+ }}
461
+ numberOfLines={2}>
462
+ {d.label.replace(/_/g, ' ')}
463
+ </Text>
464
+ </View>
465
+ );
466
+ })}
467
+ </ScrollView>
468
+ );
469
+ };
470
+
471
+ const BarChart = ({
472
+ data,
473
+ accentColor,
474
+ maxBarWidth,
475
+ isGradient = false,
476
+ }: {
477
+ data: {label: string; value: number}[];
478
+ accentColor: string;
479
+ maxBarWidth: number;
480
+ isGradient?: boolean;
481
+ }) => {
482
+ const maxVal = Math.max(...data.map(d => d.value), 1);
483
+ const chartHeight = data.length * (BAR_HEIGHT + PADDING_Y) + 10;
484
+
485
+ return (
486
+ <View style={graphStyles.svgContainer}>
487
+ <Svg width="100%" height={chartHeight}>
488
+ <Defs>
489
+ <LinearGradient id="barGrad" x1="0" y1="0" x2="1" y2="0">
490
+ <Stop offset="0" stopColor={accentColor} stopOpacity="0.6" />
491
+ <Stop offset="1" stopColor={accentColor} stopOpacity="1" />
492
+ </LinearGradient>
493
+ </Defs>
494
+ {data.map((d, i) => {
495
+ const y = i * (BAR_HEIGHT + PADDING_Y);
496
+ const barWidth = Math.max((d.value / maxVal) * maxBarWidth, 2);
497
+
498
+ return (
499
+ <React.Fragment key={d.label}>
500
+ {/* Label above bar */}
501
+ <SvgText
502
+ x={0}
503
+ y={y + 12}
504
+ fill={AppColors.grayTextStrong}
505
+ fontSize="11"
506
+ fontFamily={AppFonts.interMedium}>
507
+ {d.label}
508
+ </SvgText>
509
+
510
+ {/* Background trace line */}
511
+ <Line
512
+ x1={0}
513
+ y1={y + 24}
514
+ x2={maxBarWidth}
515
+ y2={y + 24}
516
+ stroke={AppColors.grayBorderSecondary}
517
+ strokeDasharray="4"
518
+ />
519
+
520
+ {/* The actual Bar */}
521
+ <Rect
522
+ x={0}
523
+ y={y + 16}
524
+ width={barWidth}
525
+ height={14}
526
+ fill={isGradient ? 'url(#barGrad)' : accentColor}
527
+ rx={4}
528
+ opacity={0.85}
529
+ />
530
+
531
+ {/* Value Text at the end of the bar */}
532
+ <SvgText
533
+ x={barWidth + 6}
534
+ y={y + 26}
535
+ fill={AppColors.primaryBlack}
536
+ fontSize="11"
537
+ fontFamily={AppFonts.interBold}>
538
+ {d.value}
539
+ </SvgText>
540
+ </React.Fragment>
541
+ );
542
+ })}
543
+ </Svg>
544
+ </View>
545
+ );
546
+ };
547
+
548
+ const graphStyles = StyleSheet.create({
549
+ container: {
550
+ backgroundColor: AppColors.primaryLight,
551
+ borderWidth: 1,
552
+ borderColor: AppColors.grayBorderSecondary,
553
+ borderRadius: 12,
554
+ marginBottom: 10,
555
+ padding: 14,
556
+ overflow: 'hidden',
557
+ },
558
+ headerTitle: {
559
+ fontFamily: AppFonts.interBold,
560
+ color: AppColors.primaryBlack,
561
+ fontSize: 14,
562
+ marginBottom: 12,
563
+ borderBottomWidth: 1,
564
+ borderBottomColor: AppColors.dividerColor,
565
+ paddingBottom: 8,
566
+ },
567
+ chartBlock: {
568
+ marginBottom: 16,
569
+ },
570
+ chartTitle: {
571
+ fontFamily: AppFonts.interMedium,
572
+ color: AppColors.grayTextWeak,
573
+ fontSize: 12,
574
+ textTransform: 'uppercase',
575
+ letterSpacing: 0.5,
576
+ marginBottom: 8,
577
+ },
578
+ svgContainer: {
579
+ marginTop: 4,
580
+ },
581
+ });
582
+
583
+ export default AnalyticsGraph;
@@ -0,0 +1,64 @@
1
+ import React, {useEffect, useRef} from 'react';
2
+ import {Animated, Platform, View, ViewStyle} from 'react-native';
3
+
4
+ interface AnimatedEntranceProps {
5
+ children: React.ReactNode;
6
+ delay?: number;
7
+ distance?: number;
8
+ duration?: number;
9
+ index?: number;
10
+ style?: ViewStyle | ViewStyle[];
11
+ }
12
+
13
+ const AnimatedEntrance = React.memo(function AnimatedEntrance({
14
+ children,
15
+ delay = 0,
16
+ distance = 10,
17
+ duration = 220,
18
+ index = 0,
19
+ style,
20
+ }: AnimatedEntranceProps) {
21
+ if (Platform.OS === 'android') {
22
+ return <View style={style}>{children}</View>;
23
+ }
24
+
25
+ const progress = useRef(new Animated.Value(0)).current;
26
+
27
+ useEffect(() => {
28
+ progress.setValue(0);
29
+ Animated.timing(progress, {
30
+ toValue: 1,
31
+ duration,
32
+ delay: delay + Math.min(index, 12) * 18,
33
+ useNativeDriver: true,
34
+ }).start();
35
+ }, [delay, duration, index, progress]);
36
+
37
+ return (
38
+ <Animated.View
39
+ style={[
40
+ style,
41
+ {
42
+ opacity: progress,
43
+ transform: [
44
+ {
45
+ translateY: progress.interpolate({
46
+ inputRange: [0, 1],
47
+ outputRange: [distance, 0],
48
+ }),
49
+ },
50
+ {
51
+ scale: progress.interpolate({
52
+ inputRange: [0, 1],
53
+ outputRange: [0.985, 1],
54
+ }),
55
+ },
56
+ ],
57
+ },
58
+ ]}>
59
+ {children}
60
+ </Animated.View>
61
+ );
62
+ });
63
+
64
+ export default AnimatedEntrance;