@billdog.io/react-native 1.0.0-beta.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/BillDogReactNative.podspec +30 -0
- package/LICENSE +21 -0
- package/README.md +330 -0
- package/android/build.gradle +99 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogABTestModule.kt +317 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogAnalyticsModule.kt +389 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogModule.kt +817 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogPaywallViewManager.kt +383 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogSurveyModule.kt +427 -0
- package/android/src/main/kotlin/io/billdog/reactnative/BillDogVirtualCurrencyModule.kt +407 -0
- package/android/src/main/kotlin/io/billdog/virtualcurrency/BillDogVirtualCurrencyPackage.kt +44 -0
- package/dist/AdvancedPaywallCache.d.ts +70 -0
- package/dist/AdvancedPaywallCache.js +344 -0
- package/dist/BillDog.d.ts +255 -0
- package/dist/BillDog.js +918 -0
- package/dist/BillDogConfiguration.d.ts +145 -0
- package/dist/BillDogConfiguration.js +229 -0
- package/dist/ComponentRenderer.d.ts +17 -0
- package/dist/ComponentRenderer.js +886 -0
- package/dist/LayoutEngine.d.ts +101 -0
- package/dist/LayoutEngine.js +394 -0
- package/dist/LocalizationResolver.d.ts +99 -0
- package/dist/LocalizationResolver.js +266 -0
- package/dist/NativePaywallView.d.ts +36 -0
- package/dist/NativePaywallView.js +59 -0
- package/dist/PaywallCache.d.ts +74 -0
- package/dist/PaywallCache.js +293 -0
- package/dist/PaywallStateManager.d.ts +62 -0
- package/dist/PaywallStateManager.js +147 -0
- package/dist/PaywallView.d.ts +42 -0
- package/dist/PaywallView.js +275 -0
- package/dist/ProductVariableProvider.d.ts +60 -0
- package/dist/ProductVariableProvider.js +239 -0
- package/dist/VariableResolver.d.ts +120 -0
- package/dist/VariableResolver.js +379 -0
- package/dist/WebViewPaywall.d.ts +75 -0
- package/dist/WebViewPaywall.js +360 -0
- package/dist/animations/presets.d.ts +49 -0
- package/dist/animations/presets.js +367 -0
- package/dist/components/AccoladeCpsComponent.d.ts +13 -0
- package/dist/components/AccoladeCpsComponent.js +248 -0
- package/dist/components/AccordionComponent.d.ts +10 -0
- package/dist/components/AccordionComponent.js +187 -0
- package/dist/components/AnimatedWrapper.d.ts +35 -0
- package/dist/components/AnimatedWrapper.js +277 -0
- package/dist/components/CarouselComponent.d.ts +23 -0
- package/dist/components/CarouselComponent.js +484 -0
- package/dist/components/ChartCurveComponent.d.ts +13 -0
- package/dist/components/ChartCurveComponent.js +333 -0
- package/dist/components/CheckboxComponent.d.ts +9 -0
- package/dist/components/CheckboxComponent.js +172 -0
- package/dist/components/ConfettiComponent.d.ts +9 -0
- package/dist/components/ConfettiComponent.js +172 -0
- package/dist/components/CountdownComponent.d.ts +16 -0
- package/dist/components/CountdownComponent.js +414 -0
- package/dist/components/DelayedXComponent.d.ts +12 -0
- package/dist/components/DelayedXComponent.js +240 -0
- package/dist/components/DrawerModalComponent.d.ts +20 -0
- package/dist/components/DrawerModalComponent.js +286 -0
- package/dist/components/GradientView.d.ts +38 -0
- package/dist/components/GradientView.js +126 -0
- package/dist/components/HapticFeedbackComponent.d.ts +16 -0
- package/dist/components/HapticFeedbackComponent.js +64 -0
- package/dist/components/HorizontalProductsComponent.d.ts +17 -0
- package/dist/components/HorizontalProductsComponent.js +284 -0
- package/dist/components/MultiChoiceGridComponent.d.ts +13 -0
- package/dist/components/MultiChoiceGridComponent.js +234 -0
- package/dist/components/NPSScaleComponent.d.ts +16 -0
- package/dist/components/NPSScaleComponent.js +260 -0
- package/dist/components/NavigationComponent.d.ts +26 -0
- package/dist/components/NavigationComponent.js +302 -0
- package/dist/components/OAuthButtonComponent.d.ts +20 -0
- package/dist/components/OAuthButtonComponent.js +237 -0
- package/dist/components/ProgressLoaderComponent.d.ts +13 -0
- package/dist/components/ProgressLoaderComponent.js +308 -0
- package/dist/components/ProgressStepperComponent.d.ts +18 -0
- package/dist/components/ProgressStepperComponent.js +228 -0
- package/dist/components/SegmentedPickerComponent.d.ts +10 -0
- package/dist/components/SegmentedPickerComponent.js +221 -0
- package/dist/components/ShareButtonsComponent.d.ts +21 -0
- package/dist/components/ShareButtonsComponent.js +265 -0
- package/dist/components/ShareCodeComponent.d.ts +16 -0
- package/dist/components/ShareCodeComponent.js +274 -0
- package/dist/components/SingleChoiceGridComponent.d.ts +13 -0
- package/dist/components/SingleChoiceGridComponent.js +210 -0
- package/dist/components/SliderComponent.d.ts +9 -0
- package/dist/components/SliderComponent.js +263 -0
- package/dist/components/StarRatingInputComponent.d.ts +20 -0
- package/dist/components/StarRatingInputComponent.js +198 -0
- package/dist/components/StickerCompositeComponent.d.ts +13 -0
- package/dist/components/StickerCompositeComponent.js +136 -0
- package/dist/components/TabsComponent.d.ts +19 -0
- package/dist/components/TabsComponent.js +431 -0
- package/dist/components/TextInputComponent.d.ts +18 -0
- package/dist/components/TextInputComponent.js +227 -0
- package/dist/components/TimelineComponent.d.ts +19 -0
- package/dist/components/TimelineComponent.js +104 -0
- package/dist/components/ToggleComponent.d.ts +14 -0
- package/dist/components/ToggleComponent.js +132 -0
- package/dist/components/VerticalProductsComponent.d.ts +17 -0
- package/dist/components/VerticalProductsComponent.js +311 -0
- package/dist/dynamicValues.d.ts +36 -0
- package/dist/dynamicValues.js +142 -0
- package/dist/filters/dateFilters.d.ts +50 -0
- package/dist/filters/dateFilters.js +390 -0
- package/dist/filters/index.d.ts +18 -0
- package/dist/filters/index.js +253 -0
- package/dist/hooks/useOfferings.d.ts +76 -0
- package/dist/hooks/useOfferings.js +99 -0
- package/dist/hooks/usePaywall.d.ts +27 -0
- package/dist/hooks/usePaywall.js +114 -0
- package/dist/hooks/usePlacement.d.ts +34 -0
- package/dist/hooks/usePlacement.js +89 -0
- package/dist/hooks/useSubscription.d.ts +40 -0
- package/dist/hooks/useSubscription.js +97 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.js +198 -0
- package/dist/models/BillDogError.d.ts +40 -0
- package/dist/models/BillDogError.js +11 -0
- package/dist/models/CacheFetchPolicy.d.ts +8 -0
- package/dist/models/CacheFetchPolicy.js +4 -0
- package/dist/models/CustomProduct.d.ts +32 -0
- package/dist/models/CustomProduct.js +15 -0
- package/dist/models/CustomerInfo.d.ts +17 -0
- package/dist/models/CustomerInfo.js +11 -0
- package/dist/models/Delegate.d.ts +20 -0
- package/dist/models/Delegate.js +11 -0
- package/dist/models/EntitlementInfo.d.ts +19 -0
- package/dist/models/EntitlementInfo.js +2 -0
- package/dist/models/Placement.d.ts +54 -0
- package/dist/models/Placement.js +15 -0
- package/dist/models/PurchaseParams.d.ts +39 -0
- package/dist/models/PurchaseParams.js +60 -0
- package/dist/models/PurchaseResult.d.ts +30 -0
- package/dist/models/PurchaseResult.js +15 -0
- package/dist/models/RestoreResult.d.ts +30 -0
- package/dist/models/RestoreResult.js +22 -0
- package/dist/models/RestoredItem.d.ts +26 -0
- package/dist/models/RestoredItem.js +13 -0
- package/dist/modules/ABTest.d.ts +65 -0
- package/dist/modules/ABTest.js +113 -0
- package/dist/modules/Analytics.d.ts +91 -0
- package/dist/modules/Analytics.js +182 -0
- package/dist/modules/Survey.d.ts +65 -0
- package/dist/modules/Survey.js +82 -0
- package/dist/modules/VirtualCurrency.d.ts +63 -0
- package/dist/modules/VirtualCurrency.js +147 -0
- package/dist/murmur.d.ts +23 -0
- package/dist/murmur.js +104 -0
- package/dist/notifications/LiveActivitiesManager.d.ts +47 -0
- package/dist/notifications/LiveActivitiesManager.js +106 -0
- package/dist/notifications/NotificationScheduler.d.ts +55 -0
- package/dist/notifications/NotificationScheduler.js +199 -0
- package/dist/notifications/PurchaseNotificationHandler.d.ts +24 -0
- package/dist/notifications/PurchaseNotificationHandler.js +55 -0
- package/dist/notifications/useDeviceToken.d.ts +36 -0
- package/dist/notifications/useDeviceToken.js +97 -0
- package/dist/notifications/useLiveActivity.d.ts +39 -0
- package/dist/notifications/useLiveActivity.js +104 -0
- package/dist/review/ReviewAnalytics.d.ts +34 -0
- package/dist/review/ReviewAnalytics.js +73 -0
- package/dist/review/ReviewManager.d.ts +83 -0
- package/dist/review/ReviewManager.js +339 -0
- package/dist/review/ReviewTimingManager.d.ts +82 -0
- package/dist/review/ReviewTimingManager.js +224 -0
- package/dist/survey-core/types.d.ts +215 -0
- package/dist/survey-core/types.js +8 -0
- package/dist/types.d.ts +438 -0
- package/dist/types.js +158 -0
- package/dist/utils/ApiClient.d.ts +65 -0
- package/dist/utils/ApiClient.js +132 -0
- package/dist/utils/CSSConverter.d.ts +49 -0
- package/dist/utils/CSSConverter.js +470 -0
- package/dist/utils/animations.d.ts +41 -0
- package/dist/utils/animations.js +194 -0
- package/dist/utils/calendarIntegration.d.ts +36 -0
- package/dist/utils/calendarIntegration.js +89 -0
- package/dist/utils/configurationResolver.d.ts +23 -0
- package/dist/utils/configurationResolver.js +78 -0
- package/dist/utils/deviceDetection.d.ts +38 -0
- package/dist/utils/deviceDetection.js +59 -0
- package/dist/utils/hapticFeedback.d.ts +17 -0
- package/dist/utils/hapticFeedback.js +53 -0
- package/dist/utils/iconMapper.d.ts +26 -0
- package/dist/utils/iconMapper.js +113 -0
- package/dist/utils/notificationPermissions.d.ts +13 -0
- package/dist/utils/notificationPermissions.js +51 -0
- package/dist/utils/priceFormatting.d.ts +19 -0
- package/dist/utils/priceFormatting.js +99 -0
- package/dist/utils/shareSheet.d.ts +17 -0
- package/dist/utils/shareSheet.js +42 -0
- package/dist/utils/subscriptionUpgrade.d.ts +84 -0
- package/dist/utils/subscriptionUpgrade.js +100 -0
- package/dist/valueUtils.d.ts +48 -0
- package/dist/valueUtils.js +129 -0
- package/dist/xFlowTags.d.ts +18 -0
- package/dist/xFlowTags.js +385 -0
- package/ios/BillDogABTest.m +50 -0
- package/ios/BillDogABTest.swift +188 -0
- package/ios/BillDogAnalytics.m +105 -0
- package/ios/BillDogAnalytics.swift +324 -0
- package/ios/BillDogBridge.m +222 -0
- package/ios/BillDogBridge.swift +715 -0
- package/ios/BillDogLiveActivities.m +41 -0
- package/ios/BillDogLiveActivities.swift +104 -0
- package/ios/BillDogPaywallViewManager.m +39 -0
- package/ios/BillDogPaywallViewManager.swift +361 -0
- package/ios/BillDogSurvey.m +34 -0
- package/ios/BillDogSurvey.swift +257 -0
- package/ios/BillDogVirtualCurrencyBridge.m +63 -0
- package/ios/BillDogVirtualCurrencyBridge.swift +511 -0
- package/junit.xml +25 -0
- package/package.json +61 -0
- package/react-native.config.js +13 -0
- package/src/AdvancedPaywallCache.ts +433 -0
- package/src/BillDog.ts +983 -0
- package/src/BillDogConfiguration.ts +318 -0
- package/src/ComponentRenderer.tsx +1325 -0
- package/src/LayoutEngine.ts +459 -0
- package/src/LocalizationResolver.ts +311 -0
- package/src/NativePaywallView.tsx +132 -0
- package/src/PaywallCache.ts +358 -0
- package/src/PaywallStateManager.ts +154 -0
- package/src/PaywallView.tsx +328 -0
- package/src/ProductVariableProvider.ts +282 -0
- package/src/VariableResolver.ts +516 -0
- package/src/WebViewPaywall.tsx +454 -0
- package/src/animations/presets.ts +421 -0
- package/src/components/AccoladeCpsComponent.tsx +259 -0
- package/src/components/AccordionComponent.tsx +213 -0
- package/src/components/AnimatedWrapper.tsx +316 -0
- package/src/components/CarouselComponent.tsx +615 -0
- package/src/components/ChartCurveComponent.tsx +452 -0
- package/src/components/CheckboxComponent.tsx +185 -0
- package/src/components/ConfettiComponent.tsx +178 -0
- package/src/components/CountdownComponent.tsx +454 -0
- package/src/components/DelayedXComponent.tsx +266 -0
- package/src/components/DrawerModalComponent.tsx +324 -0
- package/src/components/GradientView.tsx +129 -0
- package/src/components/HapticFeedbackComponent.tsx +39 -0
- package/src/components/HorizontalProductsComponent.tsx +329 -0
- package/src/components/MultiChoiceGridComponent.tsx +265 -0
- package/src/components/NPSScaleComponent.tsx +294 -0
- package/src/components/NavigationComponent.tsx +329 -0
- package/src/components/OAuthButtonComponent.tsx +266 -0
- package/src/components/ProgressLoaderComponent.tsx +366 -0
- package/src/components/ProgressStepperComponent.tsx +250 -0
- package/src/components/SegmentedPickerComponent.tsx +245 -0
- package/src/components/ShareButtonsComponent.tsx +299 -0
- package/src/components/ShareCodeComponent.tsx +303 -0
- package/src/components/SingleChoiceGridComponent.tsx +229 -0
- package/src/components/SliderComponent.tsx +280 -0
- package/src/components/StarRatingInputComponent.tsx +223 -0
- package/src/components/StickerCompositeComponent.tsx +168 -0
- package/src/components/TabsComponent.tsx +496 -0
- package/src/components/TextInputComponent.tsx +258 -0
- package/src/components/TimelineComponent.tsx +129 -0
- package/src/components/ToggleComponent.tsx +142 -0
- package/src/components/VerticalProductsComponent.tsx +357 -0
- package/src/dynamicValues.ts +180 -0
- package/src/filters/dateFilters.ts +411 -0
- package/src/filters/index.ts +281 -0
- package/src/hooks/useOfferings.ts +192 -0
- package/src/hooks/usePaywall.ts +154 -0
- package/src/hooks/usePlacement.ts +143 -0
- package/src/hooks/useSubscription.ts +154 -0
- package/src/index.ts +245 -0
- package/src/models/BillDogError.ts +24 -0
- package/src/models/CacheFetchPolicy.ts +13 -0
- package/src/models/CustomProduct.ts +33 -0
- package/src/models/CustomerInfo.ts +26 -0
- package/src/models/Delegate.ts +22 -0
- package/src/models/EntitlementInfo.ts +27 -0
- package/src/models/Placement.ts +50 -0
- package/src/models/PurchaseParams.ts +81 -0
- package/src/models/PurchaseResult.ts +32 -0
- package/src/models/RestoreResult.ts +27 -0
- package/src/models/RestoredItem.ts +25 -0
- package/src/modules/ABTest.ts +131 -0
- package/src/modules/Analytics.ts +227 -0
- package/src/modules/Survey.ts +126 -0
- package/src/modules/VirtualCurrency.ts +223 -0
- package/src/murmur.ts +102 -0
- package/src/notifications/LiveActivitiesManager.ts +140 -0
- package/src/notifications/NotificationScheduler.ts +292 -0
- package/src/notifications/PurchaseNotificationHandler.ts +67 -0
- package/src/notifications/useDeviceToken.ts +116 -0
- package/src/notifications/useLiveActivity.ts +125 -0
- package/src/review/ReviewAnalytics.ts +89 -0
- package/src/review/ReviewManager.ts +355 -0
- package/src/review/ReviewTimingManager.ts +265 -0
- package/src/survey-core/types.ts +244 -0
- package/src/types/ambient.d.ts +9 -0
- package/src/types.ts +680 -0
- package/src/utils/ApiClient.ts +163 -0
- package/src/utils/CSSConverter.ts +552 -0
- package/src/utils/animations.ts +232 -0
- package/src/utils/calendarIntegration.ts +113 -0
- package/src/utils/configurationResolver.ts +106 -0
- package/src/utils/deviceDetection.ts +83 -0
- package/src/utils/hapticFeedback.ts +55 -0
- package/src/utils/iconMapper.ts +102 -0
- package/src/utils/notificationPermissions.ts +48 -0
- package/src/utils/priceFormatting.ts +119 -0
- package/src/utils/shareSheet.ts +55 -0
- package/src/utils/subscriptionUpgrade.ts +183 -0
- package/src/valueUtils.ts +108 -0
- package/src/xFlowTags.ts +463 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Animation utilities for React Native tap behavior transitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Animated, Easing } from 'react-native';
|
|
6
|
+
|
|
7
|
+
export type TransitionType = 'none' | 'shrink' | 'grow' | 'fade' | 'bounce' | 'slide' | 'rotate' | 'pulse';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Play a transition animation on an Animated.Value
|
|
11
|
+
*/
|
|
12
|
+
export async function playTransition(
|
|
13
|
+
scaleValue: Animated.Value,
|
|
14
|
+
opacityValue: Animated.Value,
|
|
15
|
+
type: TransitionType,
|
|
16
|
+
duration: number
|
|
17
|
+
): Promise<void> {
|
|
18
|
+
if (type === 'none') return;
|
|
19
|
+
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
const animation = getTransitionAnimation(scaleValue, opacityValue, type, duration);
|
|
22
|
+
animation.start(() => resolve());
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the appropriate animation for a transition type
|
|
28
|
+
*/
|
|
29
|
+
function getTransitionAnimation(
|
|
30
|
+
scaleValue: Animated.Value,
|
|
31
|
+
opacityValue: Animated.Value,
|
|
32
|
+
type: TransitionType,
|
|
33
|
+
duration: number
|
|
34
|
+
): Animated.CompositeAnimation {
|
|
35
|
+
const halfDuration = duration / 2;
|
|
36
|
+
const quarterDuration = duration / 4;
|
|
37
|
+
|
|
38
|
+
switch (type) {
|
|
39
|
+
case 'shrink':
|
|
40
|
+
return Animated.sequence([
|
|
41
|
+
Animated.timing(scaleValue, {
|
|
42
|
+
toValue: 0.95,
|
|
43
|
+
duration: halfDuration,
|
|
44
|
+
easing: Easing.out(Easing.ease),
|
|
45
|
+
useNativeDriver: true,
|
|
46
|
+
}),
|
|
47
|
+
Animated.timing(scaleValue, {
|
|
48
|
+
toValue: 1,
|
|
49
|
+
duration: halfDuration,
|
|
50
|
+
easing: Easing.out(Easing.ease),
|
|
51
|
+
useNativeDriver: true,
|
|
52
|
+
}),
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
case 'grow':
|
|
56
|
+
return Animated.sequence([
|
|
57
|
+
Animated.timing(scaleValue, {
|
|
58
|
+
toValue: 1.05,
|
|
59
|
+
duration: halfDuration,
|
|
60
|
+
easing: Easing.out(Easing.ease),
|
|
61
|
+
useNativeDriver: true,
|
|
62
|
+
}),
|
|
63
|
+
Animated.timing(scaleValue, {
|
|
64
|
+
toValue: 1,
|
|
65
|
+
duration: halfDuration,
|
|
66
|
+
easing: Easing.out(Easing.ease),
|
|
67
|
+
useNativeDriver: true,
|
|
68
|
+
}),
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
case 'fade':
|
|
72
|
+
return Animated.sequence([
|
|
73
|
+
Animated.timing(opacityValue, {
|
|
74
|
+
toValue: 0.5,
|
|
75
|
+
duration: halfDuration,
|
|
76
|
+
easing: Easing.out(Easing.ease),
|
|
77
|
+
useNativeDriver: true,
|
|
78
|
+
}),
|
|
79
|
+
Animated.timing(opacityValue, {
|
|
80
|
+
toValue: 1,
|
|
81
|
+
duration: halfDuration,
|
|
82
|
+
easing: Easing.out(Easing.ease),
|
|
83
|
+
useNativeDriver: true,
|
|
84
|
+
}),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
case 'bounce':
|
|
88
|
+
return Animated.sequence([
|
|
89
|
+
Animated.timing(scaleValue, {
|
|
90
|
+
toValue: 0.9,
|
|
91
|
+
duration: quarterDuration,
|
|
92
|
+
easing: Easing.out(Easing.ease),
|
|
93
|
+
useNativeDriver: true,
|
|
94
|
+
}),
|
|
95
|
+
Animated.spring(scaleValue, {
|
|
96
|
+
toValue: 1,
|
|
97
|
+
friction: 3,
|
|
98
|
+
tension: 100,
|
|
99
|
+
useNativeDriver: true,
|
|
100
|
+
}),
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
case 'pulse':
|
|
104
|
+
return Animated.sequence([
|
|
105
|
+
Animated.parallel([
|
|
106
|
+
Animated.timing(scaleValue, {
|
|
107
|
+
toValue: 1.1,
|
|
108
|
+
duration: halfDuration,
|
|
109
|
+
easing: Easing.out(Easing.ease),
|
|
110
|
+
useNativeDriver: true,
|
|
111
|
+
}),
|
|
112
|
+
Animated.timing(opacityValue, {
|
|
113
|
+
toValue: 0.8,
|
|
114
|
+
duration: halfDuration,
|
|
115
|
+
easing: Easing.out(Easing.ease),
|
|
116
|
+
useNativeDriver: true,
|
|
117
|
+
}),
|
|
118
|
+
]),
|
|
119
|
+
Animated.parallel([
|
|
120
|
+
Animated.timing(scaleValue, {
|
|
121
|
+
toValue: 1,
|
|
122
|
+
duration: halfDuration,
|
|
123
|
+
easing: Easing.out(Easing.ease),
|
|
124
|
+
useNativeDriver: true,
|
|
125
|
+
}),
|
|
126
|
+
Animated.timing(opacityValue, {
|
|
127
|
+
toValue: 1,
|
|
128
|
+
duration: halfDuration,
|
|
129
|
+
easing: Easing.out(Easing.ease),
|
|
130
|
+
useNativeDriver: true,
|
|
131
|
+
}),
|
|
132
|
+
]),
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
case 'slide':
|
|
136
|
+
// For slide, we need a translateX value - this is a simplified version
|
|
137
|
+
return Animated.sequence([
|
|
138
|
+
Animated.timing(scaleValue, {
|
|
139
|
+
toValue: 0.98,
|
|
140
|
+
duration: quarterDuration,
|
|
141
|
+
easing: Easing.out(Easing.ease),
|
|
142
|
+
useNativeDriver: true,
|
|
143
|
+
}),
|
|
144
|
+
Animated.timing(scaleValue, {
|
|
145
|
+
toValue: 1.02,
|
|
146
|
+
duration: quarterDuration,
|
|
147
|
+
easing: Easing.inOut(Easing.ease),
|
|
148
|
+
useNativeDriver: true,
|
|
149
|
+
}),
|
|
150
|
+
Animated.timing(scaleValue, {
|
|
151
|
+
toValue: 1,
|
|
152
|
+
duration: quarterDuration,
|
|
153
|
+
easing: Easing.out(Easing.ease),
|
|
154
|
+
useNativeDriver: true,
|
|
155
|
+
}),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
case 'rotate':
|
|
159
|
+
// Note: Rotation requires a different animated value
|
|
160
|
+
return Animated.sequence([
|
|
161
|
+
Animated.timing(scaleValue, {
|
|
162
|
+
toValue: 0.98,
|
|
163
|
+
duration: quarterDuration,
|
|
164
|
+
easing: Easing.out(Easing.ease),
|
|
165
|
+
useNativeDriver: true,
|
|
166
|
+
}),
|
|
167
|
+
Animated.timing(scaleValue, {
|
|
168
|
+
toValue: 1,
|
|
169
|
+
duration: quarterDuration,
|
|
170
|
+
easing: Easing.out(Easing.ease),
|
|
171
|
+
useNativeDriver: true,
|
|
172
|
+
}),
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
default:
|
|
176
|
+
return Animated.timing(scaleValue, {
|
|
177
|
+
toValue: 1,
|
|
178
|
+
duration: 0,
|
|
179
|
+
useNativeDriver: true,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Create animation values for a button
|
|
186
|
+
*/
|
|
187
|
+
export function createAnimationValues(): {
|
|
188
|
+
scale: Animated.Value;
|
|
189
|
+
opacity: Animated.Value;
|
|
190
|
+
translateX: Animated.Value;
|
|
191
|
+
rotate: Animated.Value;
|
|
192
|
+
} {
|
|
193
|
+
return {
|
|
194
|
+
scale: new Animated.Value(1),
|
|
195
|
+
opacity: new Animated.Value(1),
|
|
196
|
+
translateX: new Animated.Value(0),
|
|
197
|
+
rotate: new Animated.Value(0),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Reset animation values to default
|
|
203
|
+
*/
|
|
204
|
+
export function resetAnimationValues(values: {
|
|
205
|
+
scale: Animated.Value;
|
|
206
|
+
opacity: Animated.Value;
|
|
207
|
+
translateX: Animated.Value;
|
|
208
|
+
rotate: Animated.Value;
|
|
209
|
+
}): void {
|
|
210
|
+
values.scale.setValue(1);
|
|
211
|
+
values.opacity.setValue(1);
|
|
212
|
+
values.translateX.setValue(0);
|
|
213
|
+
values.rotate.setValue(0);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get animated style from animation values
|
|
218
|
+
*/
|
|
219
|
+
export function getAnimatedStyle(values: {
|
|
220
|
+
scale: Animated.Value;
|
|
221
|
+
opacity: Animated.Value;
|
|
222
|
+
translateX: Animated.Value;
|
|
223
|
+
rotate: Animated.Value;
|
|
224
|
+
}): {
|
|
225
|
+
transform: { scale: Animated.Value }[];
|
|
226
|
+
opacity: Animated.Value;
|
|
227
|
+
} {
|
|
228
|
+
return {
|
|
229
|
+
transform: [{ scale: values.scale }],
|
|
230
|
+
opacity: values.opacity,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Platform, PermissionsAndroid } from 'react-native';
|
|
2
|
+
// Note: Requires 'react-native-calendar-events' package to be installed
|
|
3
|
+
|
|
4
|
+
export interface CalendarEvent {
|
|
5
|
+
title: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
location?: string;
|
|
8
|
+
startDate: Date;
|
|
9
|
+
endDate: Date;
|
|
10
|
+
allDay?: boolean;
|
|
11
|
+
url?: string;
|
|
12
|
+
notes?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface CalendarPermissionStatus {
|
|
16
|
+
granted: boolean;
|
|
17
|
+
canRequest: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CalendarResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
eventId?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Request calendar permissions
|
|
28
|
+
* Note: Requires react-native-calendar-events package
|
|
29
|
+
*/
|
|
30
|
+
export async function requestCalendarPermission(): Promise<CalendarPermissionStatus> {
|
|
31
|
+
try {
|
|
32
|
+
// Dynamic import to avoid errors if package not installed
|
|
33
|
+
const RNCalendarEvents = require('react-native-calendar-events');
|
|
34
|
+
|
|
35
|
+
if (Platform.OS === 'android' && Platform.Version >= 23) {
|
|
36
|
+
const granted = await PermissionsAndroid.request(
|
|
37
|
+
PermissionsAndroid.PERMISSIONS.WRITE_CALENDAR
|
|
38
|
+
);
|
|
39
|
+
return {
|
|
40
|
+
granted: granted === PermissionsAndroid.RESULTS.GRANTED,
|
|
41
|
+
canRequest: granted !== PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const status = await RNCalendarEvents.requestPermissions();
|
|
46
|
+
return {
|
|
47
|
+
granted: status === 'authorized',
|
|
48
|
+
canRequest: status === 'undetermined',
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.warn('react-native-calendar-events not installed');
|
|
52
|
+
return { granted: false, canRequest: false };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check current calendar permission status
|
|
58
|
+
*/
|
|
59
|
+
export async function checkCalendarPermission(): Promise<CalendarPermissionStatus> {
|
|
60
|
+
try {
|
|
61
|
+
const RNCalendarEvents = require('react-native-calendar-events');
|
|
62
|
+
const status = await RNCalendarEvents.checkPermissions();
|
|
63
|
+
return {
|
|
64
|
+
granted: status === 'authorized',
|
|
65
|
+
canRequest: status === 'undetermined',
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return { granted: false, canRequest: false };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Add event to calendar
|
|
74
|
+
*/
|
|
75
|
+
export async function addCalendarEvent(event: CalendarEvent): Promise<CalendarResult> {
|
|
76
|
+
try {
|
|
77
|
+
const RNCalendarEvents = require('react-native-calendar-events');
|
|
78
|
+
|
|
79
|
+
const permission = await checkCalendarPermission();
|
|
80
|
+
if (!permission.granted) {
|
|
81
|
+
return { success: false, error: 'Calendar permission not granted' };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const eventId = await RNCalendarEvents.saveEvent(event.title, {
|
|
85
|
+
startDate: event.startDate.toISOString(),
|
|
86
|
+
endDate: event.endDate.toISOString(),
|
|
87
|
+
description: event.description,
|
|
88
|
+
location: event.location,
|
|
89
|
+
allDay: event.allDay,
|
|
90
|
+
notes: event.notes,
|
|
91
|
+
url: event.url,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return { success: true, eventId };
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
error: error instanceof Error ? error.message : 'Failed to add event',
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if calendar is supported
|
|
105
|
+
*/
|
|
106
|
+
export function isCalendarSupported(): boolean {
|
|
107
|
+
try {
|
|
108
|
+
require('react-native-calendar-events');
|
|
109
|
+
return true;
|
|
110
|
+
} catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration resolver for React Native
|
|
3
|
+
* Implements fallback logic for multi-device configurations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { PaywallConfiguration } from '../types';
|
|
7
|
+
import { DeviceCategory } from './deviceDetection';
|
|
8
|
+
|
|
9
|
+
export interface MultiPaywallConfig {
|
|
10
|
+
phone_portrait?: PaywallConfiguration;
|
|
11
|
+
phone_landscape?: PaywallConfiguration;
|
|
12
|
+
xl_phone_portrait?: PaywallConfiguration;
|
|
13
|
+
xl_phone_landscape?: PaywallConfiguration;
|
|
14
|
+
tablet_portrait?: PaywallConfiguration;
|
|
15
|
+
tablet_landscape?: PaywallConfiguration;
|
|
16
|
+
desktop_web?: PaywallConfiguration;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const DEVICE_GROUPS = {
|
|
20
|
+
phone_portrait: { group: 'phone', orientation: 'portrait' },
|
|
21
|
+
phone_landscape: { group: 'phone', orientation: 'landscape' },
|
|
22
|
+
xl_phone_portrait: { group: 'xl_phone', orientation: 'portrait' },
|
|
23
|
+
xl_phone_landscape: { group: 'xl_phone', orientation: 'landscape' },
|
|
24
|
+
tablet_portrait: { group: 'tablet', orientation: 'portrait' },
|
|
25
|
+
tablet_landscape: { group: 'tablet', orientation: 'landscape' },
|
|
26
|
+
desktop_web: { group: 'desktop', orientation: 'landscape' },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find the nearest existing configuration for fallback
|
|
31
|
+
*/
|
|
32
|
+
export function findNearestConfig(
|
|
33
|
+
multiConfig: MultiPaywallConfig,
|
|
34
|
+
targetCategory: DeviceCategory
|
|
35
|
+
): DeviceCategory | null {
|
|
36
|
+
const targetInfo = DEVICE_GROUPS[targetCategory];
|
|
37
|
+
|
|
38
|
+
// Priority 1: Same device group, same orientation
|
|
39
|
+
const sameGroupSameOrientation = (Object.keys(DEVICE_GROUPS) as DeviceCategory[])
|
|
40
|
+
.find(cat =>
|
|
41
|
+
cat !== targetCategory &&
|
|
42
|
+
DEVICE_GROUPS[cat].group === targetInfo.group &&
|
|
43
|
+
DEVICE_GROUPS[cat].orientation === targetInfo.orientation &&
|
|
44
|
+
multiConfig[cat]
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (sameGroupSameOrientation) return sameGroupSameOrientation;
|
|
48
|
+
|
|
49
|
+
// Priority 2: Same device group, different orientation
|
|
50
|
+
const sameGroupDiffOrientation = (Object.keys(DEVICE_GROUPS) as DeviceCategory[])
|
|
51
|
+
.find(cat =>
|
|
52
|
+
cat !== targetCategory &&
|
|
53
|
+
DEVICE_GROUPS[cat].group === targetInfo.group &&
|
|
54
|
+
multiConfig[cat]
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (sameGroupDiffOrientation) return sameGroupDiffOrientation;
|
|
58
|
+
|
|
59
|
+
// Priority 3: Fallback to smaller device in same orientation
|
|
60
|
+
if (targetInfo.group === 'xl_phone') {
|
|
61
|
+
const phoneEquivalent = targetInfo.orientation === 'portrait'
|
|
62
|
+
? 'phone_portrait'
|
|
63
|
+
: 'phone_landscape';
|
|
64
|
+
if (multiConfig[phoneEquivalent]) return phoneEquivalent;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (targetInfo.group === 'tablet') {
|
|
68
|
+
const xlPhoneEquivalent = targetInfo.orientation === 'portrait'
|
|
69
|
+
? 'xl_phone_portrait'
|
|
70
|
+
: 'xl_phone_landscape';
|
|
71
|
+
if (multiConfig[xlPhoneEquivalent]) return xlPhoneEquivalent;
|
|
72
|
+
|
|
73
|
+
const phoneEquivalent = targetInfo.orientation === 'portrait'
|
|
74
|
+
? 'phone_portrait'
|
|
75
|
+
: 'phone_landscape';
|
|
76
|
+
if (multiConfig[phoneEquivalent]) return phoneEquivalent;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Priority 4: Phone portrait (base config - ALWAYS exists)
|
|
80
|
+
if (multiConfig.phone_portrait && targetCategory !== 'phone_portrait') {
|
|
81
|
+
return 'phone_portrait';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the appropriate configuration with fallback logic
|
|
89
|
+
*/
|
|
90
|
+
export function resolveConfiguration(
|
|
91
|
+
multiConfig: MultiPaywallConfig,
|
|
92
|
+
targetCategory: DeviceCategory
|
|
93
|
+
): PaywallConfiguration | null {
|
|
94
|
+
// Try to get specific configuration
|
|
95
|
+
let config = multiConfig[targetCategory];
|
|
96
|
+
|
|
97
|
+
// If not found, use fallback logic
|
|
98
|
+
if (!config) {
|
|
99
|
+
const nearestCategory = findNearestConfig(multiConfig, targetCategory);
|
|
100
|
+
if (nearestCategory) {
|
|
101
|
+
config = multiConfig[nearestCategory];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return config || null;
|
|
106
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device detection utilities for React Native
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Dimensions, Platform } from 'react-native';
|
|
6
|
+
|
|
7
|
+
export type DeviceCategory =
|
|
8
|
+
| 'phone_portrait'
|
|
9
|
+
| 'phone_landscape'
|
|
10
|
+
| 'xl_phone_portrait'
|
|
11
|
+
| 'xl_phone_landscape'
|
|
12
|
+
| 'tablet_portrait'
|
|
13
|
+
| 'tablet_landscape'
|
|
14
|
+
| 'desktop_web';
|
|
15
|
+
|
|
16
|
+
export interface DeviceCategoryInfo {
|
|
17
|
+
category: DeviceCategory;
|
|
18
|
+
label: string;
|
|
19
|
+
dimensions: { width: number; height: number };
|
|
20
|
+
orientation: 'portrait' | 'landscape';
|
|
21
|
+
group: 'phone' | 'xl_phone' | 'tablet' | 'desktop';
|
|
22
|
+
osName: string;
|
|
23
|
+
osVersion: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Detect device category based on current dimensions
|
|
28
|
+
*/
|
|
29
|
+
export function detectDeviceCategory(): DeviceCategory {
|
|
30
|
+
const { width, height } = Dimensions.get('window');
|
|
31
|
+
const isLandscape = width > height;
|
|
32
|
+
|
|
33
|
+
// Desktop web (viewport >= 1200px)
|
|
34
|
+
if (width >= 1200) return 'desktop_web';
|
|
35
|
+
|
|
36
|
+
// Tablet range (700-1200px)
|
|
37
|
+
if (width >= 700 && width < 1200) {
|
|
38
|
+
return isLandscape ? 'tablet_landscape' : 'tablet_portrait';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// XL Phone range (430-700px width)
|
|
42
|
+
if (width >= 430 && width < 700) {
|
|
43
|
+
return isLandscape ? 'xl_phone_landscape' : 'xl_phone_portrait';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Standard phone (<430px)
|
|
47
|
+
return isLandscape ? 'phone_landscape' : 'phone_portrait';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get device info including OS details
|
|
52
|
+
*/
|
|
53
|
+
export function getDeviceInfo() {
|
|
54
|
+
const { width, height } = Dimensions.get('window');
|
|
55
|
+
const category = detectDeviceCategory();
|
|
56
|
+
|
|
57
|
+
// Get OS name (capitalize first letter)
|
|
58
|
+
const osName = Platform.OS === 'ios' ? 'iOS' : Platform.OS === 'android' ? 'Android' : 'Web';
|
|
59
|
+
|
|
60
|
+
// Get OS version
|
|
61
|
+
const osVersion = String(Platform.Version || 'Unknown');
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
width,
|
|
65
|
+
height,
|
|
66
|
+
category,
|
|
67
|
+
platform: Platform.OS,
|
|
68
|
+
osName,
|
|
69
|
+
osVersion,
|
|
70
|
+
isTablet: category.includes('tablet'),
|
|
71
|
+
isPhone: category.includes('phone'),
|
|
72
|
+
orientation: width > height ? 'landscape' : 'portrait',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check if device is a tablet
|
|
78
|
+
*/
|
|
79
|
+
export function isTablet(): boolean {
|
|
80
|
+
const { width, height } = Dimensions.get('window');
|
|
81
|
+
const minDimension = Math.min(width, height);
|
|
82
|
+
return minDimension >= 700;
|
|
83
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Haptic feedback utilities for React Native
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Platform, Vibration } from 'react-native';
|
|
6
|
+
|
|
7
|
+
export type HapticType = 'light' | 'medium' | 'heavy' | 'success' | 'warning' | 'error';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Trigger haptic feedback
|
|
11
|
+
* Phase 4.5: Integrated with paywall action execution
|
|
12
|
+
*/
|
|
13
|
+
export function triggerHaptic(type: HapticType, intensity: number = 1.0): void {
|
|
14
|
+
if (Platform.OS === 'ios') {
|
|
15
|
+
// iOS uses native haptic feedback (requires expo-haptics or react-native-haptic-feedback)
|
|
16
|
+
// For now, use basic vibration
|
|
17
|
+
const duration = getHapticDuration(type, intensity);
|
|
18
|
+
Vibration.vibrate(duration);
|
|
19
|
+
} else if (Platform.OS === 'android') {
|
|
20
|
+
// Android vibration
|
|
21
|
+
const duration = getHapticDuration(type, intensity);
|
|
22
|
+
Vibration.vibrate(duration);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Trigger haptic from WebView action (Phase 4.5)
|
|
28
|
+
*/
|
|
29
|
+
export function triggerHapticFromAction(hapticType?: string): void {
|
|
30
|
+
const type = (hapticType || 'medium') as HapticType;
|
|
31
|
+
triggerHaptic(type);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get vibration duration for haptic type
|
|
36
|
+
*/
|
|
37
|
+
function getHapticDuration(type: HapticType, intensity: number): number {
|
|
38
|
+
const baseDurations: Record<HapticType, number> = {
|
|
39
|
+
light: 10,
|
|
40
|
+
medium: 20,
|
|
41
|
+
heavy: 40,
|
|
42
|
+
success: 15,
|
|
43
|
+
warning: 25,
|
|
44
|
+
error: 30,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return Math.round(baseDurations[type] * intensity);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if haptic feedback is available
|
|
52
|
+
*/
|
|
53
|
+
export function isHapticAvailable(): boolean {
|
|
54
|
+
return Platform.OS === 'ios' || Platform.OS === 'android';
|
|
55
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as LucideIcons from 'lucide-react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* React Native uses Lucide directly - no mapping needed
|
|
5
|
+
* This file exists for consistency with other platforms
|
|
6
|
+
* and to provide a unified API
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface IconMapperResult {
|
|
10
|
+
component: React.ComponentType<any> | null;
|
|
11
|
+
fallback: string | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get Lucide icon component by name
|
|
16
|
+
* React Native renders Lucide icons directly (best cross-platform solution for RN)
|
|
17
|
+
*/
|
|
18
|
+
export function getLucideIcon(iconName: string): IconMapperResult {
|
|
19
|
+
const icons = LucideIcons as any;
|
|
20
|
+
const IconComponent = icons[iconName];
|
|
21
|
+
|
|
22
|
+
if (IconComponent && typeof IconComponent === 'function') {
|
|
23
|
+
return {
|
|
24
|
+
component: IconComponent,
|
|
25
|
+
fallback: null,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Return fallback
|
|
30
|
+
return {
|
|
31
|
+
component: null,
|
|
32
|
+
fallback: iconName,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check if icon exists in Lucide library
|
|
38
|
+
*/
|
|
39
|
+
export function hasLucideIcon(iconName: string): boolean {
|
|
40
|
+
const icons = LucideIcons as any;
|
|
41
|
+
return iconName in icons && typeof icons[iconName] === 'function';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get all available Lucide icon names
|
|
46
|
+
*/
|
|
47
|
+
export function getAvailableIcons(): string[] {
|
|
48
|
+
const icons = LucideIcons as any;
|
|
49
|
+
return Object.keys(icons).filter(key => typeof icons[key] === 'function');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Recommended cross-platform icons (guaranteed to look good everywhere)
|
|
54
|
+
*/
|
|
55
|
+
export const RECOMMENDED_ICONS = [
|
|
56
|
+
// Core Navigation & Actions
|
|
57
|
+
'Star', 'Heart', 'Home', 'Settings', 'User', 'Search', 'Menu', 'X', 'Check',
|
|
58
|
+
'ChevronRight', 'ChevronLeft', 'ChevronDown', 'ChevronUp', 'Plus', 'Minus',
|
|
59
|
+
'Edit', 'Trash', 'Calendar', 'Clock', 'Mail', 'Phone', 'Camera', 'Image',
|
|
60
|
+
'Video', 'Music', 'Download', 'Upload', 'Share', 'Info', 'AlertTriangle',
|
|
61
|
+
'Lock', 'Eye', 'Bell', 'ShoppingCart', 'Gift', 'Globe', 'ArrowRight', 'ArrowLeft',
|
|
62
|
+
|
|
63
|
+
// Forms & Controls (expanded)
|
|
64
|
+
'CheckSquare', 'Square', 'ToggleRight', 'Bold', 'Italic', 'AlignLeft',
|
|
65
|
+
'AlignCenter', 'AlignRight', 'List', 'Palette', 'Crop', 'RotateCw',
|
|
66
|
+
|
|
67
|
+
// Arrows & Navigation (expanded)
|
|
68
|
+
'ArrowUp', 'ArrowDown', 'ArrowUpRight', 'ChevronsRight', 'Repeat', 'Undo',
|
|
69
|
+
'Redo', 'Navigation', 'Compass', 'Expand', 'Minimize',
|
|
70
|
+
|
|
71
|
+
// E-commerce (expanded)
|
|
72
|
+
'Store', 'ShoppingBag', 'Wallet', 'CreditCard', 'Package', 'Truck',
|
|
73
|
+
'Receipt', 'Barcode', 'QrCode', 'Tag', 'Percent',
|
|
74
|
+
|
|
75
|
+
// Communication (expanded)
|
|
76
|
+
'MessageCircle', 'MessageSquare', 'MailOpen', 'Inbox', 'Send', 'Reply',
|
|
77
|
+
'Phone', 'Mic', 'Users', 'UserPlus', 'Contact', 'Award',
|
|
78
|
+
|
|
79
|
+
// Files & Documents (expanded)
|
|
80
|
+
'File', 'FileText', 'Folder', 'FolderOpen', 'Save', 'Copy', 'Clipboard',
|
|
81
|
+
'Paperclip', 'Link', 'Database',
|
|
82
|
+
|
|
83
|
+
// Media (expanded)
|
|
84
|
+
'Play', 'Pause', 'SkipForward', 'Volume2', 'Film', 'Radio', 'Tv',
|
|
85
|
+
|
|
86
|
+
// Charts & Data (expanded)
|
|
87
|
+
'BarChart', 'LineChart', 'PieChart', 'Activity', 'TrendingUp', 'TrendingDown',
|
|
88
|
+
'Zap', 'Signal', 'Network',
|
|
89
|
+
|
|
90
|
+
// Transportation
|
|
91
|
+
'Car', 'Bus', 'Train', 'Plane', 'Bike', 'MapPin', 'Map',
|
|
92
|
+
|
|
93
|
+
// Health & Lifestyle
|
|
94
|
+
'Heart', 'Pill', 'Coffee', 'Pizza', 'Leaf', 'Accessibility',
|
|
95
|
+
|
|
96
|
+
// Weather
|
|
97
|
+
'Sun', 'Moon', 'Cloud', 'CloudRain', 'CloudSnow', 'Droplet', 'Wind',
|
|
98
|
+
|
|
99
|
+
// System & Miscellaneous
|
|
100
|
+
'Grid', 'Layers', 'Filter', 'RefreshCw', 'Code', 'Power', 'Battery',
|
|
101
|
+
'Sparkles', 'Crown', 'Shield', 'Timer', 'Flag', 'Target',
|
|
102
|
+
];
|