@sbaiahmed1/react-native-blur 4.0.1 → 4.1.1

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 (44) hide show
  1. package/README.md +155 -47
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/BlurType.kt +63 -0
  4. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurPackage.kt +1 -0
  5. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +63 -43
  6. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +14 -26
  7. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurView.kt +320 -0
  8. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurViewManager.kt +81 -0
  9. package/ios/Helpers/BlurStyleHelpers.swift +20 -0
  10. package/ios/Helpers/ReactNativeProgressiveBlurViewHelper.swift +39 -0
  11. package/ios/ReactNativeBlurView.mm +2 -4
  12. package/ios/ReactNativeProgressiveBlurView.h +14 -0
  13. package/ios/ReactNativeProgressiveBlurView.mm +213 -0
  14. package/ios/ReactNativeProgressiveBlurViewManager.h +4 -0
  15. package/ios/ReactNativeProgressiveBlurViewManager.mm +137 -0
  16. package/ios/Views/ProgressiveBlurView.swift +124 -0
  17. package/ios/Views/VariableBlurView.swift +142 -0
  18. package/lib/module/BlurView.js +23 -12
  19. package/lib/module/BlurView.js.map +1 -1
  20. package/lib/module/LiquidGlassView.js +3 -1
  21. package/lib/module/LiquidGlassView.js.map +1 -1
  22. package/lib/module/ProgressiveBlurView.js +98 -0
  23. package/lib/module/ProgressiveBlurView.js.map +1 -0
  24. package/lib/module/ReactNativeBlurViewNativeComponent.ts +11 -1
  25. package/lib/module/ReactNativeProgressiveBlurViewNativeComponent.ts +45 -0
  26. package/lib/module/index.js +2 -0
  27. package/lib/module/index.js.map +1 -1
  28. package/lib/typescript/src/BlurView.d.ts.map +1 -1
  29. package/lib/typescript/src/LiquidGlassView.d.ts.map +1 -1
  30. package/lib/typescript/src/ProgressiveBlurView.d.ts +97 -0
  31. package/lib/typescript/src/ProgressiveBlurView.d.ts.map +1 -0
  32. package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts +1 -1
  33. package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts.map +1 -1
  34. package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts +14 -0
  35. package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts.map +1 -0
  36. package/lib/typescript/src/index.d.ts +4 -0
  37. package/lib/typescript/src/index.d.ts.map +1 -1
  38. package/package.json +3 -2
  39. package/src/BlurView.tsx +21 -17
  40. package/src/LiquidGlassView.tsx +3 -4
  41. package/src/ProgressiveBlurView.tsx +161 -0
  42. package/src/ReactNativeBlurViewNativeComponent.ts +11 -1
  43. package/src/ReactNativeProgressiveBlurViewNativeComponent.ts +45 -0
  44. package/src/index.tsx +6 -0
@@ -0,0 +1,213 @@
1
+ #import "ReactNativeProgressiveBlurView.h"
2
+
3
+ #import <react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.h>
4
+ #import <react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.h>
5
+ #import <react/renderer/components/ReactNativeBlurViewSpec/Props.h>
6
+ #import <react/renderer/components/ReactNativeBlurViewSpec/RCTComponentViewHelpers.h>
7
+
8
+ #import "RCTFabricComponentsPlugins.h"
9
+
10
+ #if __has_include("ReactNativeBlur-Swift.h")
11
+ #import "ReactNativeBlur-Swift.h"
12
+ #else
13
+ #import <ReactNativeBlur/ReactNativeBlur-Swift.h>
14
+ #endif
15
+
16
+ using namespace facebook::react;
17
+
18
+ @interface ReactNativeProgressiveBlurView () <RCTReactNativeProgressiveBlurViewViewProtocol>
19
+ @end
20
+
21
+ @implementation ReactNativeProgressiveBlurView {
22
+ ProgressiveBlurView *_progressiveBlurView;
23
+ Props::Shared _props;
24
+ }
25
+
26
+ + (UIColor *)colorFromString:(NSString *)colorString {
27
+ // Input validation
28
+ if (!colorString || [colorString isEqualToString:@""] || colorString.length == 0) {
29
+ return [UIColor clearColor];
30
+ }
31
+
32
+ if (colorString.length > 50) {
33
+ NSLog(@"[ReactNativeProgressiveBlurView] Warning: Color string too long, using default clear color");
34
+ return [UIColor clearColor];
35
+ }
36
+
37
+ // Handle common color names
38
+ NSDictionary *colorMap = @{
39
+ @"red": [UIColor redColor],
40
+ @"blue": [UIColor blueColor],
41
+ @"green": [UIColor greenColor],
42
+ @"yellow": [UIColor yellowColor],
43
+ @"orange": [UIColor orangeColor],
44
+ @"purple": [UIColor purpleColor],
45
+ @"black": [UIColor blackColor],
46
+ @"white": [UIColor whiteColor],
47
+ @"gray": [UIColor grayColor],
48
+ @"clear": [UIColor clearColor],
49
+ @"transparent": [UIColor clearColor]
50
+ };
51
+
52
+ UIColor *namedColor = colorMap[colorString.lowercaseString];
53
+ if (namedColor) {
54
+ return namedColor;
55
+ }
56
+
57
+ // Handle hex colors
58
+ NSString *hexString = colorString;
59
+ if ([hexString hasPrefix:@"#"]) {
60
+ if (hexString.length < 2) {
61
+ NSLog(@"[ReactNativeProgressiveBlurView] Warning: Invalid hex color format '%@'", colorString);
62
+ return [UIColor clearColor];
63
+ }
64
+ hexString = [hexString substringFromIndex:1];
65
+ }
66
+
67
+ NSCharacterSet *hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
68
+ NSCharacterSet *invalidCharacters = [hexCharacterSet invertedSet];
69
+ if ([hexString rangeOfCharacterFromSet:invalidCharacters].location != NSNotFound) {
70
+ NSLog(@"[ReactNativeProgressiveBlurView] Warning: Invalid hex color format '%@'", colorString);
71
+ return [UIColor clearColor];
72
+ }
73
+
74
+ if (hexString.length == 6) {
75
+ unsigned int hexValue;
76
+ NSScanner *scanner = [NSScanner scannerWithString:hexString];
77
+ if ([scanner scanHexInt:&hexValue] && [scanner isAtEnd]) {
78
+ return [UIColor colorWithRed:((hexValue & 0xFF0000) >> 16) / 255.0
79
+ green:((hexValue & 0x00FF00) >> 8) / 255.0
80
+ blue:(hexValue & 0x0000FF) / 255.0
81
+ alpha:1.0];
82
+ }
83
+ } else if (hexString.length == 8) {
84
+ unsigned long long hexValue;
85
+ NSScanner *scanner = [NSScanner scannerWithString:hexString];
86
+ if ([scanner scanHexLongLong:&hexValue] && [scanner isAtEnd]) {
87
+ return [UIColor colorWithRed:((hexValue & 0xFF000000) >> 24) / 255.0
88
+ green:((hexValue & 0x00FF0000) >> 16) / 255.0
89
+ blue:((hexValue & 0x0000FF00) >> 8) / 255.0
90
+ alpha:(hexValue & 0x000000FF) / 255.0];
91
+ }
92
+ } else if (hexString.length == 3) {
93
+ unsigned int hexValue;
94
+ NSScanner *scanner = [NSScanner scannerWithString:hexString];
95
+ if ([scanner scanHexInt:&hexValue] && [scanner isAtEnd]) {
96
+ unsigned int r = (hexValue & 0xF00) >> 8;
97
+ unsigned int g = (hexValue & 0x0F0) >> 4;
98
+ unsigned int b = (hexValue & 0x00F);
99
+ return [UIColor colorWithRed:(r | (r << 4)) / 255.0
100
+ green:(g | (g << 4)) / 255.0
101
+ blue:(b | (b << 4)) / 255.0
102
+ alpha:1.0];
103
+ }
104
+ }
105
+
106
+ NSLog(@"[ReactNativeProgressiveBlurView] Warning: Could not parse color '%@'", colorString);
107
+ return [UIColor clearColor];
108
+ }
109
+
110
+ + (ComponentDescriptorProvider)componentDescriptorProvider
111
+ {
112
+ return concreteComponentDescriptorProvider<ReactNativeProgressiveBlurViewComponentDescriptor>();
113
+ }
114
+
115
+ - (instancetype)initWithFrame:(CGRect)frame
116
+ {
117
+ if (self = [super initWithFrame:frame]) {
118
+ static const auto defaultProps = std::make_shared<const ReactNativeProgressiveBlurViewProps>();
119
+ _props = defaultProps;
120
+
121
+ const auto &pbvProps = *std::static_pointer_cast<const ReactNativeProgressiveBlurViewProps>(defaultProps);
122
+
123
+ _progressiveBlurView = [ReactNativeProgressiveBlurViewHelper createProgressiveBlurViewWithFrame:frame];
124
+
125
+ // Set initial properties from default props
126
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withBlurAmount:pbvProps.blurAmount];
127
+
128
+ if (pbvProps.blurType != facebook::react::ReactNativeProgressiveBlurViewBlurType::Xlight) {
129
+ NSString *blurTypeString = [[NSString alloc] initWithUTF8String:toString(pbvProps.blurType).c_str()];
130
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withBlurType:blurTypeString];
131
+ }
132
+
133
+ if (pbvProps.direction != facebook::react::ReactNativeProgressiveBlurViewDirection::BlurredTopClearBottom) {
134
+ NSString *directionString = [[NSString alloc] initWithUTF8String:toString(pbvProps.direction).c_str()];
135
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withDirection:directionString];
136
+ }
137
+
138
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withStartOffset:pbvProps.startOffset];
139
+
140
+ if (!pbvProps.reducedTransparencyFallbackColor.empty()) {
141
+ NSString *fallbackColorString = [[NSString alloc] initWithUTF8String:pbvProps.reducedTransparencyFallbackColor.c_str()];
142
+ UIColor *fallbackColor = [ReactNativeProgressiveBlurView colorFromString:fallbackColorString];
143
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withReducedTransparencyFallbackColor:fallbackColor];
144
+ }
145
+
146
+ [self addSubview:_progressiveBlurView];
147
+ }
148
+ return self;
149
+ }
150
+
151
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
152
+ {
153
+ const auto &oldViewProps = *std::static_pointer_cast<ReactNativeProgressiveBlurViewProps const>(_props);
154
+ const auto &newViewProps = *std::static_pointer_cast<ReactNativeProgressiveBlurViewProps const>(props);
155
+
156
+ if (oldViewProps.blurAmount != newViewProps.blurAmount) {
157
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withBlurAmount:newViewProps.blurAmount];
158
+ }
159
+
160
+ if (oldViewProps.blurType != newViewProps.blurType) {
161
+ NSString *blurTypeString = [[NSString alloc] initWithUTF8String:toString(newViewProps.blurType).c_str()];
162
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withBlurType:blurTypeString];
163
+ }
164
+
165
+ if (oldViewProps.direction != newViewProps.direction) {
166
+ NSString *directionString = [[NSString alloc] initWithUTF8String:toString(newViewProps.direction).c_str()];
167
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withDirection:directionString];
168
+ }
169
+
170
+ if (oldViewProps.startOffset != newViewProps.startOffset) {
171
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withStartOffset:newViewProps.startOffset];
172
+ }
173
+
174
+ if (oldViewProps.reducedTransparencyFallbackColor != newViewProps.reducedTransparencyFallbackColor) {
175
+ if (!newViewProps.reducedTransparencyFallbackColor.empty()) {
176
+ NSString *fallbackColorString = [[NSString alloc] initWithUTF8String:newViewProps.reducedTransparencyFallbackColor.c_str()];
177
+ UIColor *fallbackColor = [ReactNativeProgressiveBlurView colorFromString:fallbackColorString];
178
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:_progressiveBlurView withReducedTransparencyFallbackColor:fallbackColor];
179
+ }
180
+ }
181
+
182
+ _props = props;
183
+ [super updateProps:props oldProps:oldProps];
184
+ }
185
+
186
+ - (void)layoutSubviews
187
+ {
188
+ [super layoutSubviews];
189
+ _progressiveBlurView.frame = self.bounds;
190
+ }
191
+
192
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
193
+ {
194
+ [_progressiveBlurView addSubview:childComponentView];
195
+ }
196
+
197
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
198
+ {
199
+ [childComponentView removeFromSuperview];
200
+ }
201
+
202
+ - (void)dealloc
203
+ {
204
+ [_progressiveBlurView removeFromSuperview];
205
+ _progressiveBlurView = nil;
206
+ }
207
+
208
+ @end
209
+
210
+ Class<RCTComponentViewProtocol> ProgressiveBlurryViewCls(void)
211
+ {
212
+ return ReactNativeProgressiveBlurView.class;
213
+ }
@@ -0,0 +1,4 @@
1
+ #import <React/RCTViewManager.h>
2
+
3
+ @interface ReactNativeProgressiveBlurViewManager : RCTViewManager
4
+ @end
@@ -0,0 +1,137 @@
1
+ #import "ReactNativeProgressiveBlurViewManager.h"
2
+
3
+ #if __has_include("ReactNativeBlur-Swift.h")
4
+ #import "ReactNativeBlur-Swift.h"
5
+ #else
6
+ #import <ReactNativeBlur/ReactNativeBlur-Swift.h>
7
+ #endif
8
+
9
+ #import <React/RCTUIManager.h>
10
+ #import <React/RCTBridge.h>
11
+
12
+ @interface ReactNativeProgressiveBlurViewManager ()
13
+
14
+ @end
15
+
16
+ @implementation ReactNativeProgressiveBlurViewManager
17
+
18
+ RCT_EXPORT_MODULE(ReactNativeProgressiveBlurView)
19
+
20
+ - (UIView *)view
21
+ {
22
+ return [ReactNativeProgressiveBlurViewHelper createProgressiveBlurViewWithFrame:CGRectZero];
23
+ }
24
+
25
+ // Export properties
26
+
27
+ RCT_CUSTOM_VIEW_PROPERTY(blurAmount, NSNumber, ProgressiveBlurView)
28
+ {
29
+ double amount = json ? [RCTConvert double:json] : 20.0;
30
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:view withBlurAmount:amount];
31
+ }
32
+
33
+ RCT_CUSTOM_VIEW_PROPERTY(blurType, NSString, ProgressiveBlurView)
34
+ {
35
+ NSString *blurType = json ? [RCTConvert NSString:json] : @"regular";
36
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:view withBlurType:blurType];
37
+ }
38
+
39
+ RCT_CUSTOM_VIEW_PROPERTY(direction, NSString, ProgressiveBlurView)
40
+ {
41
+ NSString *direction = json ? [RCTConvert NSString:json] : @"blurredTopClearBottom";
42
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:view withDirection:direction];
43
+ }
44
+
45
+ RCT_CUSTOM_VIEW_PROPERTY(startOffset, NSNumber, ProgressiveBlurView)
46
+ {
47
+ double offset = json ? [RCTConvert double:json] : 0.0;
48
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:view withStartOffset:offset];
49
+ }
50
+
51
+ RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, ProgressiveBlurView)
52
+ {
53
+ NSString *colorString = json ? [RCTConvert NSString:json] : @"#FFFFFF";
54
+ UIColor *color = [self colorFromString:colorString];
55
+ [ReactNativeProgressiveBlurViewHelper updateProgressiveBlurView:view withReducedTransparencyFallbackColor:color];
56
+ }
57
+
58
+ // Color parsing helper method
59
+ - (UIColor *)colorFromString:(NSString *)colorString {
60
+ if (!colorString || [colorString isEqualToString:@""] || colorString.length == 0) {
61
+ return [UIColor clearColor];
62
+ }
63
+
64
+ if (colorString.length > 50) {
65
+ NSLog(@"[ReactNativeProgressiveBlurViewManager] Warning: Color string too long");
66
+ return [UIColor clearColor];
67
+ }
68
+
69
+ NSDictionary *colorMap = @{
70
+ @"red": [UIColor redColor],
71
+ @"blue": [UIColor blueColor],
72
+ @"green": [UIColor greenColor],
73
+ @"yellow": [UIColor yellowColor],
74
+ @"orange": [UIColor orangeColor],
75
+ @"purple": [UIColor purpleColor],
76
+ @"black": [UIColor blackColor],
77
+ @"white": [UIColor whiteColor],
78
+ @"gray": [UIColor grayColor],
79
+ @"clear": [UIColor clearColor],
80
+ @"transparent": [UIColor clearColor]
81
+ };
82
+
83
+ UIColor *namedColor = colorMap[colorString.lowercaseString];
84
+ if (namedColor) {
85
+ return namedColor;
86
+ }
87
+
88
+ NSString *hexString = colorString;
89
+ if ([hexString hasPrefix:@"#"]) {
90
+ if (hexString.length < 2) {
91
+ return [UIColor clearColor];
92
+ }
93
+ hexString = [hexString substringFromIndex:1];
94
+ }
95
+
96
+ NSCharacterSet *hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
97
+ NSCharacterSet *invalidCharacters = [hexCharacterSet invertedSet];
98
+ if ([hexString rangeOfCharacterFromSet:invalidCharacters].location != NSNotFound) {
99
+ return [UIColor clearColor];
100
+ }
101
+
102
+ if (hexString.length == 6) {
103
+ unsigned int hexValue;
104
+ NSScanner *scanner = [NSScanner scannerWithString:hexString];
105
+ if ([scanner scanHexInt:&hexValue] && [scanner isAtEnd]) {
106
+ return [UIColor colorWithRed:((hexValue & 0xFF0000) >> 16) / 255.0
107
+ green:((hexValue & 0x00FF00) >> 8) / 255.0
108
+ blue:(hexValue & 0x0000FF) / 255.0
109
+ alpha:1.0];
110
+ }
111
+ } else if (hexString.length == 8) {
112
+ unsigned long long hexValue;
113
+ NSScanner *scanner = [NSScanner scannerWithString:hexString];
114
+ if ([scanner scanHexLongLong:&hexValue] && [scanner isAtEnd]) {
115
+ return [UIColor colorWithRed:((hexValue & 0xFF000000) >> 24) / 255.0
116
+ green:((hexValue & 0x00FF0000) >> 16) / 255.0
117
+ blue:((hexValue & 0x0000FF00) >> 8) / 255.0
118
+ alpha:(hexValue & 0x000000FF) / 255.0];
119
+ }
120
+ } else if (hexString.length == 3) {
121
+ unsigned int hexValue;
122
+ NSScanner *scanner = [NSScanner scannerWithString:hexString];
123
+ if ([scanner scanHexInt:&hexValue] && [scanner isAtEnd]) {
124
+ unsigned int r = (hexValue & 0xF00) >> 8;
125
+ unsigned int g = (hexValue & 0x0F0) >> 4;
126
+ unsigned int b = (hexValue & 0x00F);
127
+ return [UIColor colorWithRed:(r | (r << 4)) / 255.0
128
+ green:(g | (g << 4)) / 255.0
129
+ blue:(b | (b << 4)) / 255.0
130
+ alpha:1.0];
131
+ }
132
+ }
133
+
134
+ return [UIColor clearColor];
135
+ }
136
+
137
+ @end
@@ -0,0 +1,124 @@
1
+ // ProgressiveBlurView.swift
2
+ // React Native wrapper for VariableBlurView
3
+
4
+ import SwiftUI
5
+ import UIKit
6
+
7
+ @objc public class ProgressiveBlurView: UIView {
8
+
9
+ private var variableBlurView: VariableBlurView?
10
+
11
+ @objc public var blurAmount: Double = 20.0 {
12
+ didSet {
13
+ updateBlur()
14
+ }
15
+ }
16
+
17
+ @objc public var direction: String = "blurredTopClearBottom" {
18
+ didSet {
19
+ updateBlur()
20
+ }
21
+ }
22
+
23
+ @objc public var startOffset: Double = 0.0 {
24
+ didSet {
25
+ updateBlur()
26
+ }
27
+ }
28
+
29
+ @objc public var blurTypeString: String = "regular" {
30
+ didSet {
31
+ updateBlur()
32
+ }
33
+ }
34
+
35
+ @objc public var reducedTransparencyFallbackColor: UIColor = .white {
36
+ didSet {
37
+ updateBlur()
38
+ }
39
+ }
40
+
41
+ public override init(frame: CGRect) {
42
+ super.init(frame: frame)
43
+ setupView()
44
+ }
45
+
46
+ required init?(coder: NSCoder) {
47
+ super.init(coder: coder)
48
+ setupView()
49
+ }
50
+
51
+ private func setupView() {
52
+ // Remove old view if exists
53
+ variableBlurView?.removeFromSuperview()
54
+
55
+ let blurStyle = blurStyleFromString(blurTypeString)
56
+ let blurDirection = VariableBlurDirection(fromString: direction)
57
+
58
+ let variableBlur = VariableBlurView(
59
+ maxBlurRadius: CGFloat(blurAmount),
60
+ direction: blurDirection,
61
+ startOffset: CGFloat(startOffset),
62
+ blurStyle: blurStyle
63
+ )
64
+
65
+ variableBlur.translatesAutoresizingMaskIntoConstraints = false
66
+ addSubview(variableBlur)
67
+
68
+ NSLayoutConstraint.activate([
69
+ variableBlur.topAnchor.constraint(equalTo: topAnchor),
70
+ variableBlur.leadingAnchor.constraint(equalTo: leadingAnchor),
71
+ variableBlur.trailingAnchor.constraint(equalTo: trailingAnchor),
72
+ variableBlur.bottomAnchor.constraint(equalTo: bottomAnchor)
73
+ ])
74
+
75
+ self.variableBlurView = variableBlur
76
+
77
+ // Handle reduced transparency
78
+ if UIAccessibility.isReduceTransparencyEnabled {
79
+ variableBlur.isHidden = true
80
+ backgroundColor = reducedTransparencyFallbackColor
81
+ } else {
82
+ variableBlur.isHidden = false
83
+ backgroundColor = .clear
84
+ }
85
+ }
86
+
87
+ private func updateBlur() {
88
+ guard let variableBlurView = variableBlurView else {
89
+ setupView()
90
+ return
91
+ }
92
+
93
+ let blurStyle = blurStyleFromString(blurTypeString)
94
+ let blurDirection = VariableBlurDirection(fromString: direction)
95
+
96
+ variableBlurView.updateBlur(
97
+ maxBlurRadius: CGFloat(blurAmount),
98
+ direction: blurDirection,
99
+ startOffset: CGFloat(startOffset),
100
+ blurStyle: blurStyle
101
+ )
102
+
103
+ // Handle reduced transparency
104
+ if UIAccessibility.isReduceTransparencyEnabled {
105
+ variableBlurView.isHidden = true
106
+ backgroundColor = reducedTransparencyFallbackColor
107
+ } else {
108
+ variableBlurView.isHidden = false
109
+ backgroundColor = .clear
110
+ }
111
+ }
112
+
113
+ public override func didMoveToWindow() {
114
+ super.didMoveToWindow()
115
+ if window != nil {
116
+ updateBlur()
117
+ }
118
+ }
119
+
120
+ deinit {
121
+ variableBlurView?.removeFromSuperview()
122
+ variableBlurView = nil
123
+ }
124
+ }
@@ -0,0 +1,142 @@
1
+ // VariableBlurView.swift
2
+ // Progressive/Variable Blur implementation based on VariableBlur library
3
+
4
+ import SwiftUI
5
+ import UIKit
6
+ import CoreImage.CIFilterBuiltins
7
+ import QuartzCore
8
+
9
+ public enum VariableBlurDirection: String {
10
+ case blurredTopClearBottom
11
+ case blurredBottomClearTop
12
+
13
+ init(fromString string: String) {
14
+ switch string.lowercased() {
15
+ case "blurredbottomcleartop", "bottomtotop", "bottom":
16
+ self = .blurredBottomClearTop
17
+ default:
18
+ self = .blurredTopClearBottom
19
+ }
20
+ }
21
+ }
22
+
23
+ open class VariableBlurView: UIVisualEffectView {
24
+
25
+ private var maxBlurRadius: CGFloat = 20
26
+ private var direction: VariableBlurDirection = .blurredTopClearBottom
27
+ private var startOffset: CGFloat = 0
28
+
29
+ public init(
30
+ maxBlurRadius: CGFloat = 20,
31
+ direction: VariableBlurDirection = .blurredTopClearBottom,
32
+ startOffset: CGFloat = 0,
33
+ blurStyle: UIBlurEffect.Style = .regular
34
+ ) {
35
+ self.maxBlurRadius = maxBlurRadius
36
+ self.direction = direction
37
+ self.startOffset = startOffset
38
+
39
+ super.init(effect: UIBlurEffect(style: blurStyle))
40
+
41
+ setupVariableBlur()
42
+ }
43
+
44
+ required public init?(coder: NSCoder) {
45
+ super.init(coder: coder)
46
+ setupVariableBlur()
47
+ }
48
+
49
+ public func updateBlur(
50
+ maxBlurRadius: CGFloat,
51
+ direction: VariableBlurDirection,
52
+ startOffset: CGFloat,
53
+ blurStyle: UIBlurEffect.Style = .regular
54
+ ) {
55
+ self.maxBlurRadius = maxBlurRadius
56
+ self.direction = direction
57
+ self.startOffset = startOffset
58
+ self.effect = UIBlurEffect(style: blurStyle)
59
+
60
+ setupVariableBlur()
61
+ }
62
+
63
+ private func setupVariableBlur() {
64
+ // Creates filter via runtime reflection
65
+ // This uses a private Core Animation filter called "variableBlur"
66
+ let clsName = String("retliFAC".reversed()) // CAFilter
67
+ guard let Cls = NSClassFromString(clsName) as? NSObject.Type else {
68
+ print("[VariableBlur] Error: Can't find filter class")
69
+ return
70
+ }
71
+
72
+ let selName = String(":epyThtiWretlif".reversed()) // filterWithType:
73
+ guard let variableBlur = Cls.self.perform(
74
+ NSSelectorFromString(selName),
75
+ with: "variableBlur"
76
+ )?.takeUnretainedValue() as? NSObject else {
77
+ print("[VariableBlur] Error: Can't create variableBlur filter")
78
+ return
79
+ }
80
+
81
+ let gradientImage = makeGradientImage(
82
+ startOffset: startOffset,
83
+ direction: direction
84
+ )
85
+
86
+ variableBlur.setValue(maxBlurRadius, forKey: "inputRadius")
87
+ variableBlur.setValue(gradientImage, forKey: "inputMaskImage")
88
+ variableBlur.setValue(true, forKey: "inputNormalizeEdges")
89
+
90
+ let backdropLayer = subviews.first?.layer
91
+ backdropLayer?.filters = [variableBlur]
92
+
93
+ // Hide the default visual effect view overlays
94
+ for subview in subviews.dropFirst() {
95
+ subview.alpha = 0
96
+ }
97
+ }
98
+
99
+ open override func didMoveToWindow() {
100
+ super.didMoveToWindow()
101
+ guard let window, let backdropLayer = subviews.first?.layer else { return }
102
+ backdropLayer.setValue(
103
+ window.traitCollection.displayScale,
104
+ forKey: "scale"
105
+ )
106
+ }
107
+
108
+ open override func traitCollectionDidChange(
109
+ _ previousTraitCollection: UITraitCollection?
110
+ ) {
111
+ super.traitCollectionDidChange(previousTraitCollection)
112
+ // Re-setup blur if needed when trait collection changes
113
+ if let previousTraitCollection = previousTraitCollection,
114
+ traitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle {
115
+ setupVariableBlur()
116
+ }
117
+ }
118
+
119
+ private func makeGradientImage(
120
+ width: CGFloat = 100,
121
+ height: CGFloat = 100,
122
+ startOffset: CGFloat,
123
+ direction: VariableBlurDirection
124
+ ) -> CGImage {
125
+ // Try smoothLinearGradient for smoother transitions
126
+ let ciGradientFilter = CIFilter.smoothLinearGradient()
127
+ ciGradientFilter.color0 = CIColor.black
128
+ ciGradientFilter.color1 = CIColor.clear
129
+ ciGradientFilter.point0 = CGPoint(x: 0, y: height)
130
+ ciGradientFilter.point1 = CGPoint(x: 0, y: startOffset * height)
131
+
132
+ if case .blurredBottomClearTop = direction {
133
+ ciGradientFilter.point0.y = 0
134
+ ciGradientFilter.point1.y = height - ciGradientFilter.point1.y
135
+ }
136
+
137
+ return CIContext().createCGImage(
138
+ ciGradientFilter.outputImage!,
139
+ from: CGRect(x: 0, y: 0, width: width, height: height)
140
+ )!
141
+ }
142
+ }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
- import React from 'react';
4
- import { StyleSheet, View } from 'react-native';
3
+ import React, { Children } from 'react';
4
+ import { Platform, StyleSheet, View } from 'react-native';
5
5
  import ReactNativeBlurView from './ReactNativeBlurViewNativeComponent';
6
6
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  /**
@@ -35,27 +35,38 @@ export const BlurView = ({
35
35
  ignoreSafeArea = false,
36
36
  ...props
37
37
  }) => {
38
+ const commonProps = {
39
+ blurType,
40
+ blurAmount,
41
+ ignoreSafeArea,
42
+ reducedTransparencyFallbackColor
43
+ };
44
+
38
45
  // If no children, render the blur view directly (for background use)
39
- if (React.Children.count(children) === 0) {
46
+ if (!Children.count(children)) {
40
47
  return /*#__PURE__*/_jsx(ReactNativeBlurView, {
41
- ignoreSafeArea: ignoreSafeArea,
42
- blurType: blurType,
43
- blurAmount: blurAmount,
44
- reducedTransparencyFallbackColor: reducedTransparencyFallbackColor,
45
48
  style: style,
49
+ ...commonProps,
46
50
  ...props
47
51
  });
48
52
  }
49
53
 
50
- // If children exist, use the absolute positioning pattern
54
+ // If children exist, use the style default for Android
55
+ if (Platform.OS === 'android') {
56
+ return /*#__PURE__*/_jsx(ReactNativeBlurView, {
57
+ style: style,
58
+ ...commonProps,
59
+ ...props,
60
+ children: children
61
+ });
62
+ }
63
+
64
+ // If children exist, use the absolute positioning pattern for iOS and others
51
65
  return /*#__PURE__*/_jsxs(View, {
52
66
  style: [styles.container, style],
53
67
  children: [/*#__PURE__*/_jsx(ReactNativeBlurView, {
54
- ignoreSafeArea: ignoreSafeArea,
55
- blurType: blurType,
56
- blurAmount: blurAmount,
57
- reducedTransparencyFallbackColor: reducedTransparencyFallbackColor,
58
68
  style: StyleSheet.absoluteFill,
69
+ ...commonProps,
59
70
  ...props
60
71
  }), /*#__PURE__*/_jsx(View, {
61
72
  style: styles.children,
@@ -1 +1 @@
1
- {"version":3,"names":["React","StyleSheet","View","ReactNativeBlurView","jsx","_jsx","jsxs","_jsxs","BlurView","blurType","blurAmount","reducedTransparencyFallbackColor","style","children","ignoreSafeArea","props","Children","count","styles","container","absoluteFill","create","position","overflow","zIndex"],"sourceRoot":"../../src","sources":["BlurView.tsx"],"mappings":";;AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,UAAU,EAAEC,IAAI,QAAQ,cAAc;AAE/C,OAAOC,mBAAmB,MAEnB,sCAAsC;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAgD9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,QAAiC,GAAGA,CAAC;EAChDC,QAAQ,GAAG,QAAQ;EACnBC,UAAU,GAAG,EAAE;EACfC,gCAAgC,GAAG,SAAS;EAC5CC,KAAK;EACLC,QAAQ;EACRC,cAAc,GAAG,KAAK;EACtB,GAAGC;AACL,CAAC,KAAK;EACJ;EACA,IAAIf,KAAK,CAACgB,QAAQ,CAACC,KAAK,CAACJ,QAAQ,CAAC,KAAK,CAAC,EAAE;IACxC,oBACER,IAAA,CAACF,mBAAmB;MAClBW,cAAc,EAAEA,cAAe;MAC/BL,QAAQ,EAAEA,QAAS;MACnBC,UAAU,EAAEA,UAAW;MACvBC,gCAAgC,EAAEA,gCAAiC;MACnEC,KAAK,EAAEA,KAAM;MAAA,GACTG;IAAK,CACV,CAAC;EAEN;;EAEA;EACA,oBACER,KAAA,CAACL,IAAI;IAACU,KAAK,EAAE,CAACM,MAAM,CAACC,SAAS,EAAEP,KAAK,CAAE;IAAAC,QAAA,gBAErCR,IAAA,CAACF,mBAAmB;MAClBW,cAAc,EAAEA,cAAe;MAC/BL,QAAQ,EAAEA,QAAS;MACnBC,UAAU,EAAEA,UAAW;MACvBC,gCAAgC,EAAEA,gCAAiC;MACnEC,KAAK,EAAEX,UAAU,CAACmB,YAAa;MAAA,GAC3BL;IAAK,CACV,CAAC,eAEFV,IAAA,CAACH,IAAI;MAACU,KAAK,EAAEM,MAAM,CAACL,QAAS;MAAAA,QAAA,EAAEA;IAAQ,CAAO,CAAC;EAAA,CAC3C,CAAC;AAEX,CAAC;AAED,eAAeL,QAAQ;AAEvB,MAAMU,MAAM,GAAGjB,UAAU,CAACoB,MAAM,CAAC;EAC/BF,SAAS,EAAE;IACTG,QAAQ,EAAE,UAAU;IACpBC,QAAQ,EAAE;EACZ,CAAC;EACDV,QAAQ,EAAE;IACRS,QAAQ,EAAE,UAAU;IACpBE,MAAM,EAAE;EACV;AACF,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["React","Children","Platform","StyleSheet","View","ReactNativeBlurView","jsx","_jsx","jsxs","_jsxs","BlurView","blurType","blurAmount","reducedTransparencyFallbackColor","style","children","ignoreSafeArea","props","commonProps","count","OS","styles","container","absoluteFill","create","position","overflow","zIndex"],"sourceRoot":"../../src","sources":["BlurView.tsx"],"mappings":";;AAAA,OAAOA,KAAK,IAAIC,QAAQ,QAAQ,OAAO;AACvC,SAASC,QAAQ,EAAEC,UAAU,EAAEC,IAAI,QAAQ,cAAc;AAEzD,OAAOC,mBAAmB,MAEnB,sCAAsC;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAgD9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,QAAiC,GAAGA,CAAC;EAChDC,QAAQ,GAAG,QAAQ;EACnBC,UAAU,GAAG,EAAE;EACfC,gCAAgC,GAAG,SAAS;EAC5CC,KAAK;EACLC,QAAQ;EACRC,cAAc,GAAG,KAAK;EACtB,GAAGC;AACL,CAAC,KAAK;EACJ,MAAMC,WAA0B,GAAG;IACjCP,QAAQ;IACRC,UAAU;IACVI,cAAc;IACdH;EACF,CAAC;;EAED;EACA,IAAI,CAACZ,QAAQ,CAACkB,KAAK,CAACJ,QAAQ,CAAC,EAAE;IAC7B,oBAAOR,IAAA,CAACF,mBAAmB;MAACS,KAAK,EAAEA,KAAM;MAAA,GAAKI,WAAW;MAAA,GAAMD;IAAK,CAAG,CAAC;EAC1E;;EAEA;EACA,IAAIf,QAAQ,CAACkB,EAAE,KAAK,SAAS,EAAE;IAC7B,oBACEb,IAAA,CAACF,mBAAmB;MAACS,KAAK,EAAEA,KAAM;MAAA,GAAKI,WAAW;MAAA,GAAMD,KAAK;MAAAF,QAAA,EAC1DA;IAAQ,CACU,CAAC;EAE1B;;EAEA;EACA,oBACEN,KAAA,CAACL,IAAI;IAACU,KAAK,EAAE,CAACO,MAAM,CAACC,SAAS,EAAER,KAAK,CAAE;IAAAC,QAAA,gBAErCR,IAAA,CAACF,mBAAmB;MAClBS,KAAK,EAAEX,UAAU,CAACoB,YAAa;MAAA,GAC3BL,WAAW;MAAA,GACXD;IAAK,CACV,CAAC,eAEFV,IAAA,CAACH,IAAI;MAACU,KAAK,EAAEO,MAAM,CAACN,QAAS;MAAAA,QAAA,EAAEA;IAAQ,CAAO,CAAC;EAAA,CAC3C,CAAC;AAEX,CAAC;AAED,eAAeL,QAAQ;AAEvB,MAAMW,MAAM,GAAGlB,UAAU,CAACqB,MAAM,CAAC;EAC/BF,SAAS,EAAE;IACTG,QAAQ,EAAE,UAAU;IACpBC,QAAQ,EAAE;EACZ,CAAC;EACDX,QAAQ,EAAE;IACRU,QAAQ,EAAE,UAAU;IACpBE,MAAM,EAAE;EACV;AACF,CAAC,CAAC","ignoreList":[]}