@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,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Dynamic Values System for React Native SDK
|
|
4
|
+
* Supports nested condition groups with AND/OR logic
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.isDynamicValue = isDynamicValue;
|
|
8
|
+
exports.evaluateDynamicValue = evaluateDynamicValue;
|
|
9
|
+
exports.evaluateConditionGroup = evaluateConditionGroup;
|
|
10
|
+
exports.processComponentProperties = processComponentProperties;
|
|
11
|
+
exports.processFullComponent = processFullComponent;
|
|
12
|
+
exports.createConditionGroup = createConditionGroup;
|
|
13
|
+
exports.createDynamicValue = createDynamicValue;
|
|
14
|
+
exports.createCondition = createCondition;
|
|
15
|
+
exports.createSimpleValueEntry = createSimpleValueEntry;
|
|
16
|
+
const valueUtils_1 = require("./valueUtils");
|
|
17
|
+
function isDynamicValue(value) {
|
|
18
|
+
return typeof value === 'object' && value !== null && value._isDynamic === true;
|
|
19
|
+
}
|
|
20
|
+
function evaluateDynamicValue(dynamicValue, variables) {
|
|
21
|
+
if (!isDynamicValue(dynamicValue))
|
|
22
|
+
return dynamicValue;
|
|
23
|
+
try {
|
|
24
|
+
const entries = dynamicValue.values || [];
|
|
25
|
+
for (const entry of entries) {
|
|
26
|
+
if (evaluateConditionGroup(entry.rootGroup, variables)) {
|
|
27
|
+
return entry.value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return dynamicValue.default;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.warn('[DynamicValue] Evaluation failed, using default:', error);
|
|
34
|
+
return dynamicValue.default;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function evaluateConditionGroup(group, variables) {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
// `?? []` — a group commonly omits `conditions` or `groups` when empty (the conformance corpus and
|
|
40
|
+
// DB-stored dynamic values both do). `.map` on the missing array throws, the throw is swallowed by
|
|
41
|
+
// evaluateDynamicValue's try/catch, and the value silently collapses to its default. The web copy had
|
|
42
|
+
// this guard; it was never propagated here.
|
|
43
|
+
const conditionResults = ((_a = group.conditions) !== null && _a !== void 0 ? _a : []).map(c => evaluateSingleCondition(c, variables));
|
|
44
|
+
const groupResults = ((_b = group.groups) !== null && _b !== void 0 ? _b : []).map(g => evaluateConditionGroup(g, variables));
|
|
45
|
+
const allResults = [...conditionResults, ...groupResults];
|
|
46
|
+
// Empty group evaluates to true
|
|
47
|
+
if (allResults.length === 0)
|
|
48
|
+
return true;
|
|
49
|
+
return group.logic === 'AND'
|
|
50
|
+
? allResults.every(Boolean)
|
|
51
|
+
: allResults.some(Boolean);
|
|
52
|
+
}
|
|
53
|
+
function evaluateSingleCondition(condition, variables) {
|
|
54
|
+
if (!condition.variableName)
|
|
55
|
+
return false;
|
|
56
|
+
const varValue = (0, valueUtils_1.getNestedValue)(variables, condition.variableName);
|
|
57
|
+
switch (condition.operator) {
|
|
58
|
+
case 'equals': return (0, valueUtils_1.isEqual)(varValue, condition.value);
|
|
59
|
+
case 'not_equals': return !(0, valueUtils_1.isEqual)(varValue, condition.value);
|
|
60
|
+
// toNumber (not Number()): non-numeric → 0, matching native `toDouble`. `Number()` yields NaN, which
|
|
61
|
+
// makes every ordering comparison silently false and disagrees with the device.
|
|
62
|
+
case 'greater_than': return (0, valueUtils_1.toNumber)(varValue) > (0, valueUtils_1.toNumber)(condition.value);
|
|
63
|
+
case 'less_than': return (0, valueUtils_1.toNumber)(varValue) < (0, valueUtils_1.toNumber)(condition.value);
|
|
64
|
+
case 'greater_than_or_equal': return (0, valueUtils_1.toNumber)(varValue) >= (0, valueUtils_1.toNumber)(condition.value);
|
|
65
|
+
case 'less_than_or_equal': return (0, valueUtils_1.toNumber)(varValue) <= (0, valueUtils_1.toNumber)(condition.value);
|
|
66
|
+
case 'contains':
|
|
67
|
+
if (varValue == null)
|
|
68
|
+
return false;
|
|
69
|
+
return (0, valueUtils_1.stringify)(varValue).toLowerCase().includes((0, valueUtils_1.stringify)(condition.value).toLowerCase());
|
|
70
|
+
case 'exists': return varValue != null && (0, valueUtils_1.stringify)(varValue) !== '';
|
|
71
|
+
default: return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function processComponentProperties(properties, variables) {
|
|
75
|
+
const safeProps = (properties && typeof properties === 'object') ? properties : {};
|
|
76
|
+
const processed = {};
|
|
77
|
+
for (const [key, value] of Object.entries(safeProps)) {
|
|
78
|
+
if (isDynamicValue(value)) {
|
|
79
|
+
processed[key] = evaluateDynamicValue(value, variables);
|
|
80
|
+
}
|
|
81
|
+
else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
82
|
+
processed[key] = processComponentProperties(value, variables);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
processed[key] = value;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return processed;
|
|
89
|
+
}
|
|
90
|
+
function processFullComponent(component, variables) {
|
|
91
|
+
const result = { ...component };
|
|
92
|
+
const nestedKeys = ['properties', 'appearance', 'size', 'containerLayout', 'layout', 'border', 'shadow', 'selectedAppearance', 'selectedProperties', 'selectedLayout', 'selectedSize', 'activeAppearance', 'completedAppearance', 'tapBehavior'];
|
|
93
|
+
for (const key of nestedKeys) {
|
|
94
|
+
if (component[key] && typeof component[key] === 'object') {
|
|
95
|
+
result[key] = processComponentProperties(component[key], variables);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (isDynamicValue(component.visible)) {
|
|
99
|
+
result.visible = evaluateDynamicValue(component.visible, variables);
|
|
100
|
+
}
|
|
101
|
+
// Recursive children processing
|
|
102
|
+
if (Array.isArray(component.children)) {
|
|
103
|
+
result.children = component.children.map((child) => processFullComponent(child, variables));
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
// Factory functions
|
|
108
|
+
function createConditionGroup(logic = 'AND') {
|
|
109
|
+
return {
|
|
110
|
+
id: generateId(),
|
|
111
|
+
logic,
|
|
112
|
+
conditions: [],
|
|
113
|
+
groups: [],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function createDynamicValue(defaultValue, values = []) {
|
|
117
|
+
return { _isDynamic: true, default: defaultValue, values };
|
|
118
|
+
}
|
|
119
|
+
function createCondition(variableName, operator, value) {
|
|
120
|
+
return {
|
|
121
|
+
id: generateId(),
|
|
122
|
+
type: 'variable',
|
|
123
|
+
variableName,
|
|
124
|
+
operator,
|
|
125
|
+
value,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function createSimpleValueEntry(variableName, operator, value, returnValue) {
|
|
129
|
+
const condition = createCondition(variableName, operator, value);
|
|
130
|
+
const group = {
|
|
131
|
+
...createConditionGroup('AND'),
|
|
132
|
+
conditions: [condition],
|
|
133
|
+
};
|
|
134
|
+
return {
|
|
135
|
+
id: generateId(),
|
|
136
|
+
rootGroup: group,
|
|
137
|
+
value: returnValue,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function generateId() {
|
|
141
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
142
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xFlow Date/Time Filters — React Native SDK.
|
|
3
|
+
*
|
|
4
|
+
* Verbatim mirror of src/lib/filters/dateFilters.ts (pure TypeScript, only
|
|
5
|
+
* Date + Intl — no web dependencies). Kept in lockstep with the web file;
|
|
6
|
+
* the shared conformance corpus (tests/parity/xflow-corpus/) enforces parity.
|
|
7
|
+
*/
|
|
8
|
+
export type MaxUnit = 'days' | 'hours' | 'minutes' | 'seconds';
|
|
9
|
+
export type CountdownFormat = 'digital' | 'digital_full' | 'long' | 'long_most_significant' | 'short' | 'short_most_significant' | 'narrow' | 'narrow_most_significant' | 'wide' | 'wide_most_significant' | 'column' | 'days_only' | 'hours_only' | 'minutes_only' | 'seconds_only' | 'compact';
|
|
10
|
+
export interface TimeRemaining {
|
|
11
|
+
days: number;
|
|
12
|
+
hours: number;
|
|
13
|
+
minutes: number;
|
|
14
|
+
seconds: number;
|
|
15
|
+
totalSeconds: number;
|
|
16
|
+
isExpired: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function parseDate(value: string | number | Date): Date;
|
|
19
|
+
export declare function formatDate(date: Date | string | number, format: string, locale?: string): string;
|
|
20
|
+
export declare function parseMsString(value: string): {
|
|
21
|
+
amount: number;
|
|
22
|
+
unit: 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months' | 'years';
|
|
23
|
+
} | null;
|
|
24
|
+
export declare function dateAdd(date: Date | string | number, amount: number | string, unit?: 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months' | 'years'): Date;
|
|
25
|
+
export declare function dateSubtract(date: Date | string | number, amount: number | string, unit?: 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'months' | 'years'): Date;
|
|
26
|
+
export declare function calculateTimeRemaining(endDate: Date | string | number, startDate?: Date | string | number): TimeRemaining;
|
|
27
|
+
export declare function formatCountdown(timeRemaining: TimeRemaining, format?: CountdownFormat, maxUnit?: MaxUnit): string;
|
|
28
|
+
export declare function toOrdinal(num: number): string;
|
|
29
|
+
export declare function toMonthName(month: number, format?: 'short' | 'long', locale?: string): string;
|
|
30
|
+
export declare function toDayName(day: number, format?: 'short' | 'long', locale?: string): string;
|
|
31
|
+
export declare function relativeTime(date: Date | string | number, locale?: string): string;
|
|
32
|
+
export declare function countdownDaysTotal(startDate: Date | string | number, endDate: Date | string | number): number;
|
|
33
|
+
export declare function countdownHoursTotal(startDate: Date | string | number, endDate: Date | string | number): number;
|
|
34
|
+
export declare function countdownMinutesTotal(startDate: Date | string | number, endDate: Date | string | number): number;
|
|
35
|
+
export declare function countdownSecondsTotal(startDate: Date | string | number, endDate: Date | string | number): number;
|
|
36
|
+
export declare function countdownFrom(endDate: Date | string | number, startDate?: Date | string | number, format?: CountdownFormat, maxUnit?: MaxUnit): string;
|
|
37
|
+
export declare const DATE_FILTERS: {
|
|
38
|
+
date: typeof formatDate;
|
|
39
|
+
date_add: typeof dateAdd;
|
|
40
|
+
date_subtract: typeof dateSubtract;
|
|
41
|
+
countdown_from: typeof countdownFrom;
|
|
42
|
+
countdown_days_total: typeof countdownDaysTotal;
|
|
43
|
+
countdown_hours_total: typeof countdownHoursTotal;
|
|
44
|
+
countdown_minutes_total: typeof countdownMinutesTotal;
|
|
45
|
+
countdown_seconds_total: typeof countdownSecondsTotal;
|
|
46
|
+
to_ordinal: typeof toOrdinal;
|
|
47
|
+
to_month_name: typeof toMonthName;
|
|
48
|
+
to_day_name: typeof toDayName;
|
|
49
|
+
relative_time: typeof relativeTime;
|
|
50
|
+
};
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* xFlow Date/Time Filters — React Native SDK.
|
|
4
|
+
*
|
|
5
|
+
* Verbatim mirror of src/lib/filters/dateFilters.ts (pure TypeScript, only
|
|
6
|
+
* Date + Intl — no web dependencies). Kept in lockstep with the web file;
|
|
7
|
+
* the shared conformance corpus (tests/parity/xflow-corpus/) enforces parity.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DATE_FILTERS = void 0;
|
|
11
|
+
exports.parseDate = parseDate;
|
|
12
|
+
exports.formatDate = formatDate;
|
|
13
|
+
exports.parseMsString = parseMsString;
|
|
14
|
+
exports.dateAdd = dateAdd;
|
|
15
|
+
exports.dateSubtract = dateSubtract;
|
|
16
|
+
exports.calculateTimeRemaining = calculateTimeRemaining;
|
|
17
|
+
exports.formatCountdown = formatCountdown;
|
|
18
|
+
exports.toOrdinal = toOrdinal;
|
|
19
|
+
exports.toMonthName = toMonthName;
|
|
20
|
+
exports.toDayName = toDayName;
|
|
21
|
+
exports.relativeTime = relativeTime;
|
|
22
|
+
exports.countdownDaysTotal = countdownDaysTotal;
|
|
23
|
+
exports.countdownHoursTotal = countdownHoursTotal;
|
|
24
|
+
exports.countdownMinutesTotal = countdownMinutesTotal;
|
|
25
|
+
exports.countdownSecondsTotal = countdownSecondsTotal;
|
|
26
|
+
exports.countdownFrom = countdownFrom;
|
|
27
|
+
// ============= Date Format Tokens (strftime-like) =============
|
|
28
|
+
const FORMAT_TOKENS = {
|
|
29
|
+
'%Y': (d) => d.getFullYear().toString(),
|
|
30
|
+
'%y': (d) => d.getFullYear().toString().slice(-2),
|
|
31
|
+
'%m': (d) => String(d.getMonth() + 1).padStart(2, '0'),
|
|
32
|
+
'%B': (d, locale = 'en-US') => d.toLocaleDateString(locale, { month: 'long' }),
|
|
33
|
+
'%b': (d, locale = 'en-US') => d.toLocaleDateString(locale, { month: 'short' }),
|
|
34
|
+
'%d': (d) => String(d.getDate()).padStart(2, '0'),
|
|
35
|
+
'%e': (d) => String(d.getDate()),
|
|
36
|
+
'%j': (d) => {
|
|
37
|
+
const start = new Date(d.getFullYear(), 0, 0);
|
|
38
|
+
const diff = d.getTime() - start.getTime();
|
|
39
|
+
return String(Math.floor(diff / (1000 * 60 * 60 * 24))).padStart(3, '0');
|
|
40
|
+
},
|
|
41
|
+
'%A': (d, locale = 'en-US') => d.toLocaleDateString(locale, { weekday: 'long' }),
|
|
42
|
+
'%a': (d, locale = 'en-US') => d.toLocaleDateString(locale, { weekday: 'short' }),
|
|
43
|
+
'%w': (d) => d.getDay().toString(),
|
|
44
|
+
'%u': (d) => (d.getDay() || 7).toString(),
|
|
45
|
+
'%H': (d) => String(d.getHours()).padStart(2, '0'),
|
|
46
|
+
'%I': (d) => String(d.getHours() % 12 || 12).padStart(2, '0'),
|
|
47
|
+
'%k': (d) => String(d.getHours()),
|
|
48
|
+
'%l': (d) => String(d.getHours() % 12 || 12),
|
|
49
|
+
'%M': (d) => String(d.getMinutes()).padStart(2, '0'),
|
|
50
|
+
'%S': (d) => String(d.getSeconds()).padStart(2, '0'),
|
|
51
|
+
'%p': (d) => (d.getHours() >= 12 ? 'PM' : 'AM'),
|
|
52
|
+
'%P': (d) => (d.getHours() >= 12 ? 'pm' : 'am'),
|
|
53
|
+
'%z': (d) => {
|
|
54
|
+
const offset = d.getTimezoneOffset();
|
|
55
|
+
const sign = offset <= 0 ? '+' : '-';
|
|
56
|
+
const hours = String(Math.floor(Math.abs(offset) / 60)).padStart(2, '0');
|
|
57
|
+
const mins = String(Math.abs(offset) % 60).padStart(2, '0');
|
|
58
|
+
return `${sign}${hours}${mins}`;
|
|
59
|
+
},
|
|
60
|
+
'%Z': () => Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
61
|
+
'%F': (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`,
|
|
62
|
+
'%T': (d) => `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`,
|
|
63
|
+
'%R': (d) => `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`,
|
|
64
|
+
'%%': () => '%',
|
|
65
|
+
};
|
|
66
|
+
// ============= Core Date Parsing =============
|
|
67
|
+
function parseDate(value) {
|
|
68
|
+
if (value instanceof Date)
|
|
69
|
+
return value;
|
|
70
|
+
if (typeof value === 'number')
|
|
71
|
+
return new Date(value);
|
|
72
|
+
const trimmed = String(value).trim();
|
|
73
|
+
const relativeMatch = trimmed.match(/^([+-])(\d+)([smhdwMy])$/);
|
|
74
|
+
if (relativeMatch) {
|
|
75
|
+
const [, sign, amount, unit] = relativeMatch;
|
|
76
|
+
const multiplier = sign === '+' ? 1 : -1;
|
|
77
|
+
const unitMs = getUnitMilliseconds(unit);
|
|
78
|
+
return new Date(Date.now() + multiplier * parseInt(amount) * unitMs);
|
|
79
|
+
}
|
|
80
|
+
const parsed = new Date(trimmed);
|
|
81
|
+
if (!isNaN(parsed.getTime()))
|
|
82
|
+
return parsed;
|
|
83
|
+
console.warn('[parseDate] Could not parse date value:', value, '- defaulting to 5 minutes');
|
|
84
|
+
return new Date(Date.now() + 5 * 60 * 1000);
|
|
85
|
+
}
|
|
86
|
+
function getUnitMilliseconds(unit) {
|
|
87
|
+
const units = {
|
|
88
|
+
s: 1000,
|
|
89
|
+
m: 60 * 1000,
|
|
90
|
+
h: 60 * 60 * 1000,
|
|
91
|
+
d: 24 * 60 * 60 * 1000,
|
|
92
|
+
w: 7 * 24 * 60 * 60 * 1000,
|
|
93
|
+
M: 30 * 24 * 60 * 60 * 1000,
|
|
94
|
+
y: 365 * 24 * 60 * 60 * 1000,
|
|
95
|
+
};
|
|
96
|
+
return units[unit] || units.d;
|
|
97
|
+
}
|
|
98
|
+
// ============= Date Formatting =============
|
|
99
|
+
function formatDate(date, format, locale) {
|
|
100
|
+
const d = parseDate(date);
|
|
101
|
+
const presetFormats = {
|
|
102
|
+
iso: '%Y-%m-%dT%H:%M:%S',
|
|
103
|
+
date: '%Y-%m-%d',
|
|
104
|
+
time: '%H:%M:%S',
|
|
105
|
+
datetime: '%Y-%m-%d %H:%M:%S',
|
|
106
|
+
short: '%m/%d/%Y',
|
|
107
|
+
long: '%B %e, %Y',
|
|
108
|
+
full: '%A, %B %e, %Y',
|
|
109
|
+
time12: '%I:%M %p',
|
|
110
|
+
time24: '%H:%M',
|
|
111
|
+
};
|
|
112
|
+
const formatString = presetFormats[format] || format;
|
|
113
|
+
return formatString.replace(/%[A-Za-z%]/g, (token) => {
|
|
114
|
+
const formatter = FORMAT_TOKENS[token];
|
|
115
|
+
return formatter ? formatter(d, locale) : token;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// ============= ms-string Parser =============
|
|
119
|
+
const MS_STRING_UNITS = {
|
|
120
|
+
s: 'seconds',
|
|
121
|
+
m: 'minutes',
|
|
122
|
+
h: 'hours',
|
|
123
|
+
d: 'days',
|
|
124
|
+
w: 'weeks',
|
|
125
|
+
M: 'months',
|
|
126
|
+
y: 'years',
|
|
127
|
+
};
|
|
128
|
+
function parseMsString(value) {
|
|
129
|
+
const match = String(value).match(/^(-?\d+(?:\.\d+)?)\s*([smhdwMy])$/);
|
|
130
|
+
if (!match)
|
|
131
|
+
return null;
|
|
132
|
+
const unit = MS_STRING_UNITS[match[2]];
|
|
133
|
+
if (!unit)
|
|
134
|
+
return null;
|
|
135
|
+
return { amount: parseFloat(match[1]), unit };
|
|
136
|
+
}
|
|
137
|
+
// ============= Date Arithmetic =============
|
|
138
|
+
function dateAdd(date, amount, unit) {
|
|
139
|
+
if (typeof amount === 'string') {
|
|
140
|
+
const parsed = parseMsString(amount);
|
|
141
|
+
if (parsed) {
|
|
142
|
+
amount = parsed.amount;
|
|
143
|
+
unit = parsed.unit;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
amount = parseFloat(amount) || 0;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!unit)
|
|
150
|
+
unit = 'days';
|
|
151
|
+
const d = parseDate(date);
|
|
152
|
+
const result = new Date(d);
|
|
153
|
+
switch (unit) {
|
|
154
|
+
case 'seconds':
|
|
155
|
+
result.setSeconds(result.getSeconds() + amount);
|
|
156
|
+
break;
|
|
157
|
+
case 'minutes':
|
|
158
|
+
result.setMinutes(result.getMinutes() + amount);
|
|
159
|
+
break;
|
|
160
|
+
case 'hours':
|
|
161
|
+
result.setHours(result.getHours() + amount);
|
|
162
|
+
break;
|
|
163
|
+
case 'days':
|
|
164
|
+
result.setDate(result.getDate() + amount);
|
|
165
|
+
break;
|
|
166
|
+
case 'weeks':
|
|
167
|
+
result.setDate(result.getDate() + amount * 7);
|
|
168
|
+
break;
|
|
169
|
+
case 'months':
|
|
170
|
+
result.setMonth(result.getMonth() + amount);
|
|
171
|
+
break;
|
|
172
|
+
case 'years':
|
|
173
|
+
result.setFullYear(result.getFullYear() + amount);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
178
|
+
function dateSubtract(date, amount, unit) {
|
|
179
|
+
if (typeof amount === 'string') {
|
|
180
|
+
const parsed = parseMsString(amount);
|
|
181
|
+
if (parsed)
|
|
182
|
+
return dateAdd(date, -parsed.amount, parsed.unit);
|
|
183
|
+
}
|
|
184
|
+
return dateAdd(date, -(typeof amount === 'number' ? amount : parseFloat(amount) || 0), unit);
|
|
185
|
+
}
|
|
186
|
+
// ============= Countdown Calculations =============
|
|
187
|
+
function calculateTimeRemaining(endDate, startDate = new Date()) {
|
|
188
|
+
const end = parseDate(endDate);
|
|
189
|
+
const start = parseDate(startDate);
|
|
190
|
+
const totalSeconds = Math.max(0, Math.floor((end.getTime() - start.getTime()) / 1000));
|
|
191
|
+
const days = Math.floor(totalSeconds / 86400);
|
|
192
|
+
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
193
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
194
|
+
const seconds = totalSeconds % 60;
|
|
195
|
+
return { days, hours, minutes, seconds, totalSeconds, isExpired: totalSeconds <= 0 };
|
|
196
|
+
}
|
|
197
|
+
function applyMaxUnit(time, maxUnit) {
|
|
198
|
+
const { totalSeconds, isExpired } = time;
|
|
199
|
+
switch (maxUnit) {
|
|
200
|
+
case 'hours':
|
|
201
|
+
return { days: 0, hours: Math.floor(totalSeconds / 3600), minutes: Math.floor((totalSeconds % 3600) / 60), seconds: totalSeconds % 60, totalSeconds, isExpired };
|
|
202
|
+
case 'minutes':
|
|
203
|
+
return { days: 0, hours: 0, minutes: Math.floor(totalSeconds / 60), seconds: totalSeconds % 60, totalSeconds, isExpired };
|
|
204
|
+
case 'seconds':
|
|
205
|
+
return { days: 0, hours: 0, minutes: 0, seconds: totalSeconds, totalSeconds, isExpired };
|
|
206
|
+
case 'days':
|
|
207
|
+
default:
|
|
208
|
+
return time;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function resolveFormatAlias(format) {
|
|
212
|
+
switch (format) {
|
|
213
|
+
case 'narrow': return 'short';
|
|
214
|
+
case 'narrow_most_significant': return 'short_most_significant';
|
|
215
|
+
case 'wide': return 'long';
|
|
216
|
+
case 'wide_most_significant': return 'long_most_significant';
|
|
217
|
+
default: return format;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function formatCountdown(timeRemaining, format = 'digital', maxUnit) {
|
|
221
|
+
const resolved = resolveFormatAlias(format);
|
|
222
|
+
const capped = maxUnit ? applyMaxUnit(timeRemaining, maxUnit) : timeRemaining;
|
|
223
|
+
const { days, hours, minutes, seconds, totalSeconds } = capped;
|
|
224
|
+
if (resolved === 'column') {
|
|
225
|
+
const colParts = [];
|
|
226
|
+
if (days > 0)
|
|
227
|
+
colParts.push(`${days}d`);
|
|
228
|
+
if (hours > 0 || days > 0)
|
|
229
|
+
colParts.push(`${hours}h`);
|
|
230
|
+
if (minutes > 0 || hours > 0 || days > 0)
|
|
231
|
+
colParts.push(`${minutes}m`);
|
|
232
|
+
colParts.push(`${seconds}s`);
|
|
233
|
+
return colParts.join('\n');
|
|
234
|
+
}
|
|
235
|
+
switch (resolved) {
|
|
236
|
+
case 'digital':
|
|
237
|
+
return [
|
|
238
|
+
String(hours + days * 24).padStart(2, '0'),
|
|
239
|
+
String(minutes).padStart(2, '0'),
|
|
240
|
+
String(seconds).padStart(2, '0'),
|
|
241
|
+
].join(':');
|
|
242
|
+
case 'digital_full':
|
|
243
|
+
return [
|
|
244
|
+
String(days).padStart(2, '0'),
|
|
245
|
+
String(hours).padStart(2, '0'),
|
|
246
|
+
String(minutes).padStart(2, '0'),
|
|
247
|
+
String(seconds).padStart(2, '0'),
|
|
248
|
+
].join(':');
|
|
249
|
+
case 'long': {
|
|
250
|
+
const parts = [];
|
|
251
|
+
if (days > 0)
|
|
252
|
+
parts.push(`${days} day${days !== 1 ? 's' : ''}`);
|
|
253
|
+
if (hours > 0)
|
|
254
|
+
parts.push(`${hours} hour${hours !== 1 ? 's' : ''}`);
|
|
255
|
+
if (minutes > 0)
|
|
256
|
+
parts.push(`${minutes} minute${minutes !== 1 ? 's' : ''}`);
|
|
257
|
+
if (seconds > 0 || parts.length === 0)
|
|
258
|
+
parts.push(`${seconds} second${seconds !== 1 ? 's' : ''}`);
|
|
259
|
+
return parts.join(', ');
|
|
260
|
+
}
|
|
261
|
+
case 'long_most_significant':
|
|
262
|
+
if (days > 0)
|
|
263
|
+
return `${days} day${days !== 1 ? 's' : ''}`;
|
|
264
|
+
if (hours > 0)
|
|
265
|
+
return `${hours} hour${hours !== 1 ? 's' : ''}`;
|
|
266
|
+
if (minutes > 0)
|
|
267
|
+
return `${minutes} minute${minutes !== 1 ? 's' : ''}`;
|
|
268
|
+
return `${seconds} second${seconds !== 1 ? 's' : ''}`;
|
|
269
|
+
case 'short': {
|
|
270
|
+
const shortParts = [];
|
|
271
|
+
if (days > 0)
|
|
272
|
+
shortParts.push(`${days}d`);
|
|
273
|
+
if (hours > 0)
|
|
274
|
+
shortParts.push(`${hours}h`);
|
|
275
|
+
if (minutes > 0)
|
|
276
|
+
shortParts.push(`${minutes}m`);
|
|
277
|
+
if (seconds > 0 || shortParts.length === 0)
|
|
278
|
+
shortParts.push(`${seconds}s`);
|
|
279
|
+
return shortParts.join(' ');
|
|
280
|
+
}
|
|
281
|
+
case 'short_most_significant':
|
|
282
|
+
if (days > 0)
|
|
283
|
+
return `${days}d`;
|
|
284
|
+
if (hours > 0)
|
|
285
|
+
return `${hours}h`;
|
|
286
|
+
if (minutes > 0)
|
|
287
|
+
return `${minutes}m`;
|
|
288
|
+
return `${seconds}s`;
|
|
289
|
+
case 'days_only':
|
|
290
|
+
return `${days} day${days !== 1 ? 's' : ''}`;
|
|
291
|
+
case 'hours_only': {
|
|
292
|
+
const totalHours = days * 24 + hours;
|
|
293
|
+
return `${totalHours} hour${totalHours !== 1 ? 's' : ''}`;
|
|
294
|
+
}
|
|
295
|
+
case 'minutes_only': {
|
|
296
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
297
|
+
return `${totalMinutes} minute${totalMinutes !== 1 ? 's' : ''}`;
|
|
298
|
+
}
|
|
299
|
+
case 'seconds_only':
|
|
300
|
+
return `${totalSeconds} second${totalSeconds !== 1 ? 's' : ''}`;
|
|
301
|
+
case 'compact':
|
|
302
|
+
return `${days}:${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
303
|
+
default:
|
|
304
|
+
return formatCountdown(timeRemaining, 'digital', maxUnit);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// ============= Helper Filters =============
|
|
308
|
+
function toOrdinal(num) {
|
|
309
|
+
const suffixes = ['th', 'st', 'nd', 'rd'];
|
|
310
|
+
const v = num % 100;
|
|
311
|
+
return num + (suffixes[(v - 20) % 10] || suffixes[v] || suffixes[0]);
|
|
312
|
+
}
|
|
313
|
+
function toMonthName(month, format = 'long', locale = 'en-US') {
|
|
314
|
+
const date = new Date(2000, month - 1, 1);
|
|
315
|
+
return date.toLocaleDateString(locale, { month: format });
|
|
316
|
+
}
|
|
317
|
+
function toDayName(day, format = 'long', locale = 'en-US') {
|
|
318
|
+
const date = new Date(2000, 0, 2 + day);
|
|
319
|
+
return date.toLocaleDateString(locale, { weekday: format });
|
|
320
|
+
}
|
|
321
|
+
function relativeTime(date, locale = 'en-US') {
|
|
322
|
+
const d = parseDate(date);
|
|
323
|
+
const now = new Date();
|
|
324
|
+
const diffMs = d.getTime() - now.getTime();
|
|
325
|
+
const diffSeconds = Math.abs(Math.floor(diffMs / 1000));
|
|
326
|
+
const isPast = diffMs < 0;
|
|
327
|
+
let value;
|
|
328
|
+
let unit;
|
|
329
|
+
if (diffSeconds < 60) {
|
|
330
|
+
value = diffSeconds;
|
|
331
|
+
unit = 'second';
|
|
332
|
+
}
|
|
333
|
+
else if (diffSeconds < 3600) {
|
|
334
|
+
value = Math.floor(diffSeconds / 60);
|
|
335
|
+
unit = 'minute';
|
|
336
|
+
}
|
|
337
|
+
else if (diffSeconds < 86400) {
|
|
338
|
+
value = Math.floor(diffSeconds / 3600);
|
|
339
|
+
unit = 'hour';
|
|
340
|
+
}
|
|
341
|
+
else if (diffSeconds < 604800) {
|
|
342
|
+
value = Math.floor(diffSeconds / 86400);
|
|
343
|
+
unit = 'day';
|
|
344
|
+
}
|
|
345
|
+
else if (diffSeconds < 2592000) {
|
|
346
|
+
value = Math.floor(diffSeconds / 604800);
|
|
347
|
+
unit = 'week';
|
|
348
|
+
}
|
|
349
|
+
else if (diffSeconds < 31536000) {
|
|
350
|
+
value = Math.floor(diffSeconds / 2592000);
|
|
351
|
+
unit = 'month';
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
value = Math.floor(diffSeconds / 31536000);
|
|
355
|
+
unit = 'year';
|
|
356
|
+
}
|
|
357
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
|
|
358
|
+
return rtf.format(isPast ? -value : value, unit);
|
|
359
|
+
}
|
|
360
|
+
// ============= Countdown Specific Filters =============
|
|
361
|
+
function countdownDaysTotal(startDate, endDate) {
|
|
362
|
+
return Math.floor(calculateTimeRemaining(endDate, startDate).totalSeconds / 86400);
|
|
363
|
+
}
|
|
364
|
+
function countdownHoursTotal(startDate, endDate) {
|
|
365
|
+
return Math.floor(calculateTimeRemaining(endDate, startDate).totalSeconds / 3600);
|
|
366
|
+
}
|
|
367
|
+
function countdownMinutesTotal(startDate, endDate) {
|
|
368
|
+
return Math.floor(calculateTimeRemaining(endDate, startDate).totalSeconds / 60);
|
|
369
|
+
}
|
|
370
|
+
function countdownSecondsTotal(startDate, endDate) {
|
|
371
|
+
return calculateTimeRemaining(endDate, startDate).totalSeconds;
|
|
372
|
+
}
|
|
373
|
+
function countdownFrom(endDate, startDate = new Date(), format = 'digital', maxUnit) {
|
|
374
|
+
return formatCountdown(calculateTimeRemaining(endDate, startDate), format, maxUnit);
|
|
375
|
+
}
|
|
376
|
+
// ============= Export All Filters =============
|
|
377
|
+
exports.DATE_FILTERS = {
|
|
378
|
+
date: formatDate,
|
|
379
|
+
date_add: dateAdd,
|
|
380
|
+
date_subtract: dateSubtract,
|
|
381
|
+
countdown_from: countdownFrom,
|
|
382
|
+
countdown_days_total: countdownDaysTotal,
|
|
383
|
+
countdown_hours_total: countdownHoursTotal,
|
|
384
|
+
countdown_minutes_total: countdownMinutesTotal,
|
|
385
|
+
countdown_seconds_total: countdownSecondsTotal,
|
|
386
|
+
to_ordinal: toOrdinal,
|
|
387
|
+
to_month_name: toMonthName,
|
|
388
|
+
to_day_name: toDayName,
|
|
389
|
+
relative_time: relativeTime,
|
|
390
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter Registry and Chain Processor — React Native SDK.
|
|
3
|
+
*
|
|
4
|
+
* Verbatim mirror of src/lib/filters/index.ts (pure TypeScript, no web
|
|
5
|
+
* dependencies). Handles xFlow filter syntax: {{ variable | filter: arg }}
|
|
6
|
+
* and {% assign x = value | filter %}. Kept in lockstep with the web file;
|
|
7
|
+
* the shared conformance corpus enforces parity.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ALL_FILTERS: Record<string, (...args: any[]) => any>;
|
|
10
|
+
export declare function applyFilterChain(value: any, filterChain: string): any;
|
|
11
|
+
/**
|
|
12
|
+
* Replace {{ variable }} and {{ variable | filter: arg }} occurrences in text.
|
|
13
|
+
* Mirror of the web replaceVariablesWithFilters — unresolved variables are
|
|
14
|
+
* left untouched.
|
|
15
|
+
*/
|
|
16
|
+
export declare function replaceVariablesWithFilters(text: string, variables: Record<string, any>): string;
|
|
17
|
+
export { DATE_FILTERS } from './dateFilters';
|
|
18
|
+
export type { CountdownFormat, TimeRemaining, MaxUnit } from './dateFilters';
|