@sbaiahmed1/react-native-blur 4.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -47
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/BlurType.kt +63 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurPackage.kt +1 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +63 -43
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +14 -26
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurView.kt +320 -0
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurViewManager.kt +81 -0
- package/ios/Helpers/BlurStyleHelpers.swift +20 -0
- package/ios/Helpers/ReactNativeProgressiveBlurViewHelper.swift +39 -0
- package/ios/ReactNativeProgressiveBlurView.h +14 -0
- package/ios/ReactNativeProgressiveBlurView.mm +213 -0
- package/ios/ReactNativeProgressiveBlurViewManager.h +4 -0
- package/ios/ReactNativeProgressiveBlurViewManager.mm +137 -0
- package/ios/Views/ProgressiveBlurView.swift +124 -0
- package/ios/Views/VariableBlurView.swift +142 -0
- package/lib/module/BlurView.js +23 -12
- package/lib/module/BlurView.js.map +1 -1
- package/lib/module/LiquidGlassView.js +3 -1
- package/lib/module/LiquidGlassView.js.map +1 -1
- package/lib/module/ProgressiveBlurView.js +98 -0
- package/lib/module/ProgressiveBlurView.js.map +1 -0
- package/lib/module/ReactNativeBlurViewNativeComponent.ts +11 -1
- package/lib/module/ReactNativeProgressiveBlurViewNativeComponent.ts +45 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/BlurView.d.ts.map +1 -1
- package/lib/typescript/src/LiquidGlassView.d.ts.map +1 -1
- package/lib/typescript/src/ProgressiveBlurView.d.ts +97 -0
- package/lib/typescript/src/ProgressiveBlurView.d.ts.map +1 -0
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts +1 -1
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts +14 -0
- package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/BlurView.tsx +21 -17
- package/src/LiquidGlassView.tsx +3 -4
- package/src/ProgressiveBlurView.tsx +161 -0
- package/src/ReactNativeBlurViewNativeComponent.ts +11 -1
- package/src/ReactNativeProgressiveBlurViewNativeComponent.ts +45 -0
- 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,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
|
+
}
|
package/lib/module/BlurView.js
CHANGED
|
@@ -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 (
|
|
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
|
|
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","
|
|
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":[]}
|