@sbaiahmed1/react-native-blur 3.2.0 → 4.0.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 +319 -309
- package/ReactNativeBlur.podspec +1 -1
- package/android/build.gradle +2 -3
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +62 -269
- package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +9 -9
- package/ios/Helpers/BlurStyleHelpers.swift +1 -1
- package/ios/Helpers/ReactNativeBlurViewHelper.swift +6 -35
- package/ios/Helpers/ReactNativeLiquidGlassViewHelper.swift +44 -0
- package/ios/ReactNativeBlurView.mm +8 -61
- package/ios/{ReactNativeBlurViewManager.m → ReactNativeBlurViewManager.mm} +5 -35
- package/ios/ReactNativeLiquidGlassView.h +14 -0
- package/ios/ReactNativeLiquidGlassView.mm +284 -0
- package/ios/ReactNativeLiquidGlassViewManager.h +6 -0
- package/ios/ReactNativeLiquidGlassViewManager.mm +20 -0
- package/ios/Views/AdvancedBlurView.swift +5 -40
- package/ios/Views/BasicColoredView.swift +6 -50
- package/ios/Views/LiquidGlassContainerView.swift +173 -0
- package/lib/module/BlurView.js +16 -33
- package/lib/module/BlurView.js.map +1 -1
- package/lib/module/LiquidGlassView.js +75 -0
- package/lib/module/LiquidGlassView.js.map +1 -0
- package/lib/module/ReactNativeBlurViewNativeComponent.ts +0 -7
- package/lib/module/ReactNativeLiquidGlassViewNativeComponent.ts +57 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/BlurView.d.ts +19 -45
- package/lib/typescript/src/BlurView.d.ts.map +1 -1
- package/lib/typescript/src/LiquidGlassView.d.ts +85 -0
- package/lib/typescript/src/LiquidGlassView.d.ts.map +1 -0
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts +0 -6
- package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/ReactNativeLiquidGlassViewNativeComponent.d.ts +44 -0
- package/lib/typescript/src/ReactNativeLiquidGlassViewNativeComponent.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 +6 -3
- package/src/BlurView.tsx +36 -77
- package/src/LiquidGlassView.tsx +138 -0
- package/src/ReactNativeBlurViewNativeComponent.ts +0 -7
- package/src/ReactNativeLiquidGlassViewNativeComponent.ts +57 -0
- package/src/index.tsx +6 -0
|
@@ -137,14 +137,6 @@ using namespace facebook::react;
|
|
|
137
137
|
|
|
138
138
|
_advancedBlurView = [ReactNativeBlurViewHelper createBlurViewWithFrame:frame];
|
|
139
139
|
|
|
140
|
-
// Set initial glassTintColor from default props
|
|
141
|
-
NSString *defaultGlassTintColorString = [[NSString alloc] initWithUTF8String:bvProps.glassTintColor.c_str()];
|
|
142
|
-
UIColor *defaultGlassTintColor = [ReactNativeBlurView colorFromString:defaultGlassTintColorString];
|
|
143
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassTintColor:defaultGlassTintColor];
|
|
144
|
-
|
|
145
|
-
// Set initial glassOpacity from default props
|
|
146
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassOpacity:bvProps.glassOpacity];
|
|
147
|
-
|
|
148
140
|
// Set initial blurAmount from default props
|
|
149
141
|
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withBlurAmount:bvProps.blurAmount];
|
|
150
142
|
|
|
@@ -154,22 +146,6 @@ using namespace facebook::react;
|
|
|
154
146
|
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withBlurType:blurTypeString];
|
|
155
147
|
}
|
|
156
148
|
|
|
157
|
-
// Set initial isInteractive from default props
|
|
158
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIsInteractive:bvProps.isInteractive];
|
|
159
|
-
|
|
160
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIgnoringSafeArea:bvProps.ignoreSafeArea];
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// Set initial glassType from default props
|
|
164
|
-
if (bvProps.glassType != facebook::react::ReactNativeBlurViewGlassType::Clear) {
|
|
165
|
-
NSString *glassTypeString = [[NSString alloc] initWithUTF8String:toString(bvProps.glassType).c_str()];
|
|
166
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassType:glassTypeString];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Set initial type from default props
|
|
170
|
-
NSString *blurTypeString = [[NSString alloc] initWithUTF8String:toString(bvProps.type).c_str()];
|
|
171
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withType:blurTypeString];
|
|
172
|
-
|
|
173
149
|
// Set initial reducedTransparencyFallbackColor from default props
|
|
174
150
|
if (!bvProps.reducedTransparencyFallbackColor.empty()) {
|
|
175
151
|
NSString *fallbackColorString = [[NSString alloc] initWithUTF8String:bvProps.reducedTransparencyFallbackColor.c_str()];
|
|
@@ -177,6 +153,9 @@ using namespace facebook::react;
|
|
|
177
153
|
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withReducedTransparencyFallbackColor:fallbackColor];
|
|
178
154
|
}
|
|
179
155
|
|
|
156
|
+
// Set initial ignoreSafeArea from default props
|
|
157
|
+
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIgnoringSafeArea:bvProps.ignoreSafeArea];
|
|
158
|
+
|
|
180
159
|
[self addSubview:_advancedBlurView];
|
|
181
160
|
}
|
|
182
161
|
return self;
|
|
@@ -187,20 +166,6 @@ using namespace facebook::react;
|
|
|
187
166
|
const auto &oldViewProps = *std::static_pointer_cast<ReactNativeBlurViewProps const>(_props);
|
|
188
167
|
const auto &newViewProps = *std::static_pointer_cast<ReactNativeBlurViewProps const>(props);
|
|
189
168
|
|
|
190
|
-
// Update glassTintColor if it has changed
|
|
191
|
-
if (oldViewProps.glassTintColor != newViewProps.glassTintColor) {
|
|
192
|
-
if (!newViewProps.glassTintColor.empty()) {
|
|
193
|
-
NSString *glassTintColorString = [[NSString alloc] initWithUTF8String:newViewProps.glassTintColor.c_str()];
|
|
194
|
-
UIColor *newGlassTintColor = [ReactNativeBlurView colorFromString:glassTintColorString];
|
|
195
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassTintColor:newGlassTintColor];
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Update glassOpacity if it has changed
|
|
200
|
-
if (oldViewProps.glassOpacity != newViewProps.glassOpacity) {
|
|
201
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassOpacity:newViewProps.glassOpacity];
|
|
202
|
-
}
|
|
203
|
-
|
|
204
169
|
// Update blurAmount if it has changed
|
|
205
170
|
if (oldViewProps.blurAmount != newViewProps.blurAmount) {
|
|
206
171
|
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withBlurAmount:newViewProps.blurAmount];
|
|
@@ -214,29 +179,6 @@ using namespace facebook::react;
|
|
|
214
179
|
}
|
|
215
180
|
}
|
|
216
181
|
|
|
217
|
-
// Update glassType if it has changed
|
|
218
|
-
if (oldViewProps.glassType != newViewProps.glassType) {
|
|
219
|
-
if (newViewProps.glassType != facebook::react::ReactNativeBlurViewGlassType::Clear) {
|
|
220
|
-
NSString *glassTypeString = [[NSString alloc] initWithUTF8String:toString(newViewProps.glassType).c_str()];
|
|
221
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassType:glassTypeString];
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Update type if it has changed
|
|
226
|
-
if (oldViewProps.type != newViewProps.type) {
|
|
227
|
-
NSString *blurTypeString = [[NSString alloc] initWithUTF8String:toString(newViewProps.type).c_str()];
|
|
228
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withType:blurTypeString];
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Update isInteractive if it has changed
|
|
232
|
-
if (oldViewProps.isInteractive != newViewProps.isInteractive) {
|
|
233
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIsInteractive:newViewProps.isInteractive];
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (oldViewProps.ignoreSafeArea != newViewProps.ignoreSafeArea) {
|
|
237
|
-
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIgnoringSafeArea:newViewProps.ignoreSafeArea];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
182
|
// Update reducedTransparencyFallbackColor if it has changed
|
|
241
183
|
if (oldViewProps.reducedTransparencyFallbackColor != newViewProps.reducedTransparencyFallbackColor) {
|
|
242
184
|
if (!newViewProps.reducedTransparencyFallbackColor.empty()) {
|
|
@@ -246,6 +188,11 @@ using namespace facebook::react;
|
|
|
246
188
|
}
|
|
247
189
|
}
|
|
248
190
|
|
|
191
|
+
// Update ignoreSafeArea if it has changed
|
|
192
|
+
if (oldViewProps.ignoreSafeArea != newViewProps.ignoreSafeArea) {
|
|
193
|
+
[ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIgnoringSafeArea:newViewProps.ignoreSafeArea];
|
|
194
|
+
}
|
|
195
|
+
|
|
249
196
|
// Store the new props
|
|
250
197
|
_props = props;
|
|
251
198
|
|
|
@@ -25,18 +25,6 @@ RCT_EXPORT_MODULE(ReactNativeBlurView)
|
|
|
25
25
|
// Export properties
|
|
26
26
|
|
|
27
27
|
// Custom setters for proper type conversion
|
|
28
|
-
RCT_CUSTOM_VIEW_PROPERTY(glassTintColor, NSString, AdvancedBlurView)
|
|
29
|
-
{
|
|
30
|
-
NSString *colorString = json ? [RCTConvert NSString:json] : @"clear";
|
|
31
|
-
UIColor *color = [self colorFromString:colorString];
|
|
32
|
-
[ReactNativeBlurViewHelper updateBlurView:view withGlassTintColor:color];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
RCT_CUSTOM_VIEW_PROPERTY(glassOpacity, NSNumber, AdvancedBlurView)
|
|
36
|
-
{
|
|
37
|
-
double opacity = json ? [RCTConvert double:json] : 1.0;
|
|
38
|
-
[ReactNativeBlurViewHelper updateBlurView:view withGlassOpacity:opacity];
|
|
39
|
-
}
|
|
40
28
|
|
|
41
29
|
RCT_CUSTOM_VIEW_PROPERTY(blurAmount, NSNumber, AdvancedBlurView)
|
|
42
30
|
{
|
|
@@ -50,37 +38,19 @@ RCT_CUSTOM_VIEW_PROPERTY(blurType, NSString, AdvancedBlurView)
|
|
|
50
38
|
[ReactNativeBlurViewHelper updateBlurView:view withBlurType:blurType];
|
|
51
39
|
}
|
|
52
40
|
|
|
53
|
-
RCT_CUSTOM_VIEW_PROPERTY(
|
|
54
|
-
{
|
|
55
|
-
NSString *glassType = json ? [RCTConvert NSString:json] : @"clear";
|
|
56
|
-
[ReactNativeBlurViewHelper updateBlurView:view withGlassType:glassType];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
RCT_CUSTOM_VIEW_PROPERTY(type, NSString, AdvancedBlurView)
|
|
60
|
-
{
|
|
61
|
-
NSString *type = json ? [RCTConvert NSString:json] : @"blur";
|
|
62
|
-
[ReactNativeBlurViewHelper updateBlurView:view withType:type];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
RCT_CUSTOM_VIEW_PROPERTY(isInteractive, NSNumber, AdvancedBlurView)
|
|
41
|
+
RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlurView)
|
|
66
42
|
{
|
|
67
|
-
|
|
68
|
-
[
|
|
43
|
+
NSString *colorString = json ? [RCTConvert NSString:json] : @"#FFFFFF";
|
|
44
|
+
UIColor *color = [self colorFromString:colorString];
|
|
45
|
+
[ReactNativeBlurViewHelper updateBlurView:view withReducedTransparencyFallbackColor:color];
|
|
69
46
|
}
|
|
70
47
|
|
|
71
|
-
RCT_CUSTOM_VIEW_PROPERTY(ignoreSafeArea,
|
|
48
|
+
RCT_CUSTOM_VIEW_PROPERTY(ignoreSafeArea, BOOL, AdvancedBlurView)
|
|
72
49
|
{
|
|
73
50
|
BOOL ignoreSafeArea = json ? [RCTConvert BOOL:json] : NO;
|
|
74
51
|
[ReactNativeBlurViewHelper updateBlurView:view withIgnoringSafeArea:ignoreSafeArea];
|
|
75
52
|
}
|
|
76
53
|
|
|
77
|
-
RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlurView)
|
|
78
|
-
{
|
|
79
|
-
NSString *colorString = json ? [RCTConvert NSString:json] : @"#FFFFFF";
|
|
80
|
-
UIColor *color = [self colorFromString:colorString];
|
|
81
|
-
[ReactNativeBlurViewHelper updateBlurView:view withReducedTransparencyFallbackColor:color];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
54
|
// Color parsing helper method (copied from ReactNativeBlurView.mm)
|
|
85
55
|
- (UIColor *)colorFromString:(NSString *)colorString {
|
|
86
56
|
// Input validation
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#import <React/RCTViewComponentView.h>
|
|
2
|
+
#import <UIKit/UIKit.h>
|
|
3
|
+
|
|
4
|
+
#ifndef ReactNativeLiquidGlassViewNativeComponent_h
|
|
5
|
+
#define ReactNativeLiquidGlassViewNativeComponent_h
|
|
6
|
+
|
|
7
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
+
|
|
9
|
+
@interface ReactNativeLiquidGlassView : RCTViewComponentView
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
NS_ASSUME_NONNULL_END
|
|
13
|
+
|
|
14
|
+
#endif /* ReactNativeLiquidGlassViewNativeComponent_h */
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
#import "ReactNativeLiquidGlassView.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 ReactNativeLiquidGlassView () <RCTReactNativeLiquidGlassViewViewProtocol>
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@implementation ReactNativeLiquidGlassView {
|
|
22
|
+
LiquidGlassContainerView *_liquidGlassView;
|
|
23
|
+
Props::Shared _props;
|
|
24
|
+
LayoutMetrics _layoutMetrics;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
+ (UIColor *)colorFromString:(NSString *)colorString {
|
|
28
|
+
// Input validation
|
|
29
|
+
if (!colorString || [colorString isEqualToString:@""] || colorString.length == 0) {
|
|
30
|
+
return [UIColor clearColor]; // Default color
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Prevent excessively long strings that could cause performance issues
|
|
34
|
+
if (colorString.length > 50) {
|
|
35
|
+
NSLog(@"[ReactNativeLiquidGlassView] Warning: Color string too long, using default clear color");
|
|
36
|
+
return [UIColor clearColor];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Handle common color names
|
|
40
|
+
NSDictionary *colorMap = @{
|
|
41
|
+
@"red": [UIColor redColor],
|
|
42
|
+
@"blue": [UIColor blueColor],
|
|
43
|
+
@"green": [UIColor greenColor],
|
|
44
|
+
@"yellow": [UIColor yellowColor],
|
|
45
|
+
@"orange": [UIColor orangeColor],
|
|
46
|
+
@"purple": [UIColor purpleColor],
|
|
47
|
+
@"black": [UIColor blackColor],
|
|
48
|
+
@"white": [UIColor whiteColor],
|
|
49
|
+
@"gray": [UIColor grayColor],
|
|
50
|
+
@"clear": [UIColor clearColor],
|
|
51
|
+
@"transparent": [UIColor clearColor]
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
UIColor *namedColor = colorMap[colorString.lowercaseString];
|
|
55
|
+
if (namedColor) {
|
|
56
|
+
return namedColor;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Handle hex colors (e.g., "#FF0000", "FF0000", "#FF00FF00", "FF00FF00")
|
|
60
|
+
NSString *hexString = colorString;
|
|
61
|
+
if ([hexString hasPrefix:@"#"]) {
|
|
62
|
+
if (hexString.length < 2) {
|
|
63
|
+
NSLog(@"[ReactNativeLiquidGlassView] Warning: Invalid hex color format '%@', using default clear color", colorString);
|
|
64
|
+
return [UIColor clearColor];
|
|
65
|
+
}
|
|
66
|
+
hexString = [hexString substringFromIndex:1];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Validate hex string contains only valid hex characters
|
|
70
|
+
NSCharacterSet *hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
|
|
71
|
+
NSCharacterSet *invalidCharacters = [hexCharacterSet invertedSet];
|
|
72
|
+
if ([hexString rangeOfCharacterFromSet:invalidCharacters].location != NSNotFound) {
|
|
73
|
+
NSLog(@"[ReactNativeLiquidGlassView] Warning: Invalid hex color format '%@', contains non-hex characters", colorString);
|
|
74
|
+
return [UIColor clearColor];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Handle 6-character hex (RGB)
|
|
78
|
+
if (hexString.length == 6) {
|
|
79
|
+
unsigned int hexValue;
|
|
80
|
+
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
|
81
|
+
if ([scanner scanHexInt:&hexValue] && [scanner isAtEnd]) {
|
|
82
|
+
return [UIColor colorWithRed:((hexValue & 0xFF0000) >> 16) / 255.0
|
|
83
|
+
green:((hexValue & 0x00FF00) >> 8) / 255.0
|
|
84
|
+
blue:(hexValue & 0x0000FF) / 255.0
|
|
85
|
+
alpha:1.0];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Handle 8-character hex (RGBA)
|
|
89
|
+
else if (hexString.length == 8) {
|
|
90
|
+
unsigned long long hexValue;
|
|
91
|
+
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
|
92
|
+
if ([scanner scanHexLongLong:&hexValue] && [scanner isAtEnd]) {
|
|
93
|
+
return [UIColor colorWithRed:((hexValue & 0xFF000000) >> 24) / 255.0
|
|
94
|
+
green:((hexValue & 0x00FF0000) >> 16) / 255.0
|
|
95
|
+
blue:((hexValue & 0x0000FF00) >> 8) / 255.0
|
|
96
|
+
alpha:(hexValue & 0x000000FF) / 255.0];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Handle 3-character hex (RGB shorthand)
|
|
100
|
+
else if (hexString.length == 3) {
|
|
101
|
+
unsigned int hexValue;
|
|
102
|
+
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
|
103
|
+
if ([scanner scanHexInt:&hexValue] && [scanner isAtEnd]) {
|
|
104
|
+
// Expand 3-digit hex to 6-digit (e.g., "F0A" -> "FF00AA")
|
|
105
|
+
unsigned int r = (hexValue & 0xF00) >> 8;
|
|
106
|
+
unsigned int g = (hexValue & 0x0F0) >> 4;
|
|
107
|
+
unsigned int b = (hexValue & 0x00F);
|
|
108
|
+
|
|
109
|
+
return [UIColor colorWithRed:(r | (r << 4)) / 255.0
|
|
110
|
+
green:(g | (g << 4)) / 255.0
|
|
111
|
+
blue:(b | (b << 4)) / 255.0
|
|
112
|
+
alpha:1.0];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
NSLog(@"[ReactNativeLiquidGlassView] Warning: Unsupported hex color length (%lu) for '%@', expected 3, 6, or 8 characters",
|
|
117
|
+
(unsigned long)hexString.length, colorString);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
NSLog(@"[ReactNativeLiquidGlassView] Warning: Could not parse color '%@', using default clear color", colorString);
|
|
121
|
+
return [UIColor clearColor]; // Fallback to clear
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
125
|
+
{
|
|
126
|
+
return concreteComponentDescriptorProvider<ReactNativeLiquidGlassViewComponentDescriptor>();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
130
|
+
{
|
|
131
|
+
if (self = [super initWithFrame:frame]) {
|
|
132
|
+
static const auto defaultProps = std::make_shared<const ReactNativeLiquidGlassViewProps>();
|
|
133
|
+
_props = defaultProps;
|
|
134
|
+
|
|
135
|
+
const auto &lgProps = *std::static_pointer_cast<const ReactNativeLiquidGlassViewProps>(defaultProps);
|
|
136
|
+
|
|
137
|
+
_liquidGlassView = [ReactNativeLiquidGlassViewHelper createLiquidGlassViewWithFrame:frame];
|
|
138
|
+
|
|
139
|
+
// Set initial glassTintColor from default props
|
|
140
|
+
NSString *defaultGlassTintColorString = [[NSString alloc] initWithUTF8String:lgProps.glassTintColor.c_str()];
|
|
141
|
+
UIColor *defaultGlassTintColor = [ReactNativeLiquidGlassView colorFromString:defaultGlassTintColorString];
|
|
142
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withGlassTintColor:defaultGlassTintColor];
|
|
143
|
+
|
|
144
|
+
// Set initial glassOpacity from default props
|
|
145
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withGlassOpacity:lgProps.glassOpacity];
|
|
146
|
+
|
|
147
|
+
// Set initial glassType from default props
|
|
148
|
+
if (lgProps.glassType != facebook::react::ReactNativeLiquidGlassViewGlassType::Clear) {
|
|
149
|
+
NSString *glassTypeString = [[NSString alloc] initWithUTF8String:toString(lgProps.glassType).c_str()];
|
|
150
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withGlassType:glassTypeString];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Set initial isInteractive from default props
|
|
154
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withIsInteractive:lgProps.isInteractive];
|
|
155
|
+
|
|
156
|
+
// Set initial ignoreSafeArea from default props
|
|
157
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withIgnoringSafeArea:lgProps.ignoreSafeArea];
|
|
158
|
+
|
|
159
|
+
// Set initial reducedTransparencyFallbackColor from default props
|
|
160
|
+
if (!lgProps.reducedTransparencyFallbackColor.empty()) {
|
|
161
|
+
NSString *fallbackColorString = [[NSString alloc] initWithUTF8String:lgProps.reducedTransparencyFallbackColor.c_str()];
|
|
162
|
+
UIColor *fallbackColor = [ReactNativeLiquidGlassView colorFromString:fallbackColorString];
|
|
163
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withReducedTransparencyFallbackColor:fallbackColor];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
[self addSubview:_liquidGlassView];
|
|
167
|
+
}
|
|
168
|
+
return self;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
172
|
+
{
|
|
173
|
+
const auto &oldViewProps = *std::static_pointer_cast<ReactNativeLiquidGlassViewProps const>(_props);
|
|
174
|
+
const auto &newViewProps = *std::static_pointer_cast<ReactNativeLiquidGlassViewProps const>(props);
|
|
175
|
+
|
|
176
|
+
// Update glassTintColor if it has changed
|
|
177
|
+
if (oldViewProps.glassTintColor != newViewProps.glassTintColor) {
|
|
178
|
+
if (!newViewProps.glassTintColor.empty()) {
|
|
179
|
+
NSString *glassTintColorString = [[NSString alloc] initWithUTF8String:newViewProps.glassTintColor.c_str()];
|
|
180
|
+
UIColor *newGlassTintColor = [ReactNativeLiquidGlassView colorFromString:glassTintColorString];
|
|
181
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withGlassTintColor:newGlassTintColor];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Update glassOpacity if it has changed
|
|
186
|
+
if (oldViewProps.glassOpacity != newViewProps.glassOpacity) {
|
|
187
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withGlassOpacity:newViewProps.glassOpacity];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Update glassType if it has changed
|
|
191
|
+
if (oldViewProps.glassType != newViewProps.glassType) {
|
|
192
|
+
if (newViewProps.glassType != facebook::react::ReactNativeLiquidGlassViewGlassType::Clear) {
|
|
193
|
+
NSString *glassTypeString = [[NSString alloc] initWithUTF8String:toString(newViewProps.glassType).c_str()];
|
|
194
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withGlassType:glassTypeString];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Update isInteractive if it has changed
|
|
199
|
+
if (oldViewProps.isInteractive != newViewProps.isInteractive) {
|
|
200
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withIsInteractive:newViewProps.isInteractive];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Update ignoreSafeArea if it has changed
|
|
204
|
+
if (oldViewProps.ignoreSafeArea != newViewProps.ignoreSafeArea) {
|
|
205
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withIgnoringSafeArea:newViewProps.ignoreSafeArea];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Update reducedTransparencyFallbackColor if it has changed
|
|
209
|
+
if (oldViewProps.reducedTransparencyFallbackColor != newViewProps.reducedTransparencyFallbackColor) {
|
|
210
|
+
if (!newViewProps.reducedTransparencyFallbackColor.empty()) {
|
|
211
|
+
NSString *fallbackColorString = [[NSString alloc] initWithUTF8String:newViewProps.reducedTransparencyFallbackColor.c_str()];
|
|
212
|
+
UIColor *fallbackColor = [ReactNativeLiquidGlassView colorFromString:fallbackColorString];
|
|
213
|
+
[ReactNativeLiquidGlassViewHelper updateLiquidGlassView:_liquidGlassView withReducedTransparencyFallbackColor:fallbackColor];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Store the new props
|
|
218
|
+
_props = props;
|
|
219
|
+
|
|
220
|
+
[super updateProps:props oldProps:oldProps];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
- (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
|
|
224
|
+
{
|
|
225
|
+
[super finalizeUpdates:updateMask];
|
|
226
|
+
|
|
227
|
+
// Apply border radius from layout metrics to the inner glass view (Callstack pattern)
|
|
228
|
+
if (@available(iOS 26.0, *)) {
|
|
229
|
+
const auto &props = *std::static_pointer_cast<ReactNativeLiquidGlassViewProps const>(_props);
|
|
230
|
+
const auto borderMetrics = props.resolveBorderMetrics(_layoutMetrics);
|
|
231
|
+
|
|
232
|
+
// Use topLeft.horizontal same as React Native RCTViewComponentView implementation
|
|
233
|
+
CGFloat radius = borderMetrics.borderRadii.topLeft.horizontal;
|
|
234
|
+
|
|
235
|
+
if (radius > 0) {
|
|
236
|
+
[_liquidGlassView setBorderRadius:radius];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
- (void)layoutSubviews
|
|
242
|
+
{
|
|
243
|
+
[super layoutSubviews];
|
|
244
|
+
_liquidGlassView.frame = self.bounds;
|
|
245
|
+
|
|
246
|
+
// Copy corner radius from the Fabric view to the inner glass view (Callstack pattern)
|
|
247
|
+
_liquidGlassView.layer.cornerRadius = self.layer.cornerRadius;
|
|
248
|
+
_liquidGlassView.layer.cornerCurve = self.layer.cornerCurve;
|
|
249
|
+
_liquidGlassView.layer.masksToBounds = YES;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
|
|
253
|
+
{
|
|
254
|
+
_layoutMetrics = layoutMetrics;
|
|
255
|
+
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
259
|
+
{
|
|
260
|
+
UIView *contentView = [_liquidGlassView getContentView];
|
|
261
|
+
if (contentView) {
|
|
262
|
+
[contentView insertSubview:childComponentView atIndex:index];
|
|
263
|
+
} else {
|
|
264
|
+
[_liquidGlassView addSubview:childComponentView];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
|
|
269
|
+
{
|
|
270
|
+
[childComponentView removeFromSuperview];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
- (void)dealloc
|
|
274
|
+
{
|
|
275
|
+
[_liquidGlassView removeFromSuperview];
|
|
276
|
+
_liquidGlassView = nil;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@end
|
|
280
|
+
|
|
281
|
+
Class<RCTComponentViewProtocol> LiquidGlassViewCls(void)
|
|
282
|
+
{
|
|
283
|
+
return ReactNativeLiquidGlassView.class;
|
|
284
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#import "ReactNativeLiquidGlassViewManager.h"
|
|
2
|
+
#import "ReactNativeLiquidGlassView.h"
|
|
3
|
+
|
|
4
|
+
@implementation ReactNativeLiquidGlassViewManager
|
|
5
|
+
|
|
6
|
+
RCT_EXPORT_MODULE(ReactNativeLiquidGlassView)
|
|
7
|
+
|
|
8
|
+
- (UIView *)view
|
|
9
|
+
{
|
|
10
|
+
return [[ReactNativeLiquidGlassView alloc] init];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
RCT_EXPORT_VIEW_PROPERTY(glassType, NSString)
|
|
14
|
+
RCT_EXPORT_VIEW_PROPERTY(glassTintColor, NSString)
|
|
15
|
+
RCT_EXPORT_VIEW_PROPERTY(glassOpacity, NSNumber)
|
|
16
|
+
RCT_EXPORT_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString)
|
|
17
|
+
RCT_EXPORT_VIEW_PROPERTY(isInteractive, BOOL)
|
|
18
|
+
RCT_EXPORT_VIEW_PROPERTY(ignoreSafeArea, BOOL)
|
|
19
|
+
|
|
20
|
+
@end
|
|
@@ -1,65 +1,35 @@
|
|
|
1
1
|
import SwiftUI
|
|
2
2
|
import UIKit
|
|
3
3
|
|
|
4
|
-
// MARK: - UIKit Wrapper
|
|
4
|
+
// MARK: - UIKit Wrapper for Blur
|
|
5
5
|
|
|
6
6
|
@objc public class AdvancedBlurView: UIView {
|
|
7
7
|
|
|
8
8
|
private var hostingController: UIHostingController<BasicColoredView>?
|
|
9
9
|
|
|
10
|
-
@objc public var glassTintColor: UIColor = .clear {
|
|
11
|
-
didSet {
|
|
12
|
-
updateView()
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
@objc public var glassOpacity: Double = 1.0 {
|
|
17
|
-
didSet {
|
|
18
|
-
updateView()
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
10
|
@objc public var blurAmount: Double = 10.0 {
|
|
23
11
|
didSet {
|
|
24
12
|
updateView()
|
|
25
13
|
}
|
|
26
14
|
}
|
|
27
15
|
|
|
28
|
-
@objc public var type: String = "blur" {
|
|
29
|
-
didSet {
|
|
30
|
-
updateView()
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
16
|
@objc public var blurTypeString: String = "xlight" {
|
|
35
17
|
didSet {
|
|
36
18
|
updateView()
|
|
37
19
|
}
|
|
38
20
|
}
|
|
39
21
|
|
|
40
|
-
@objc public var glassType: String = "clear" {
|
|
41
|
-
didSet {
|
|
42
|
-
updateView()
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
22
|
@objc public var reducedTransparencyFallbackColor: UIColor = .white {
|
|
47
23
|
didSet {
|
|
48
24
|
updateView()
|
|
49
25
|
}
|
|
50
26
|
}
|
|
51
27
|
|
|
52
|
-
@objc public var isInteractive: Bool = true {
|
|
53
|
-
didSet {
|
|
54
|
-
updateView()
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
28
|
@objc public var ignoreSafeArea: Bool = false {
|
|
59
29
|
didSet {
|
|
60
30
|
updateView()
|
|
61
31
|
}
|
|
62
|
-
|
|
32
|
+
}
|
|
63
33
|
|
|
64
34
|
public override init(frame: CGRect) {
|
|
65
35
|
super.init(frame: frame)
|
|
@@ -88,15 +58,10 @@ import UIKit
|
|
|
88
58
|
|
|
89
59
|
let blurStyle = blurStyleFromString(blurTypeString)
|
|
90
60
|
let swiftUIView = BasicColoredView(
|
|
91
|
-
glassTintColor: glassTintColor,
|
|
92
|
-
glassOpacity: glassOpacity,
|
|
93
61
|
blurAmount: blurAmount,
|
|
94
62
|
blurStyle: blurStyle,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
reducedTransparencyFallbackColor: reducedTransparencyFallbackColor,
|
|
98
|
-
isInteractive: isInteractive,
|
|
99
|
-
ignoreSafeArea: ignoreSafeArea
|
|
63
|
+
ignoreSafeArea: ignoreSafeArea,
|
|
64
|
+
reducedTransparencyFallbackColor: reducedTransparencyFallbackColor
|
|
100
65
|
)
|
|
101
66
|
|
|
102
67
|
let hosting = UIHostingController(rootView: swiftUIView)
|
|
@@ -124,7 +89,7 @@ import UIKit
|
|
|
124
89
|
setupHostingController()
|
|
125
90
|
}
|
|
126
91
|
}
|
|
127
|
-
|
|
92
|
+
|
|
128
93
|
public override func didMoveToWindow() {
|
|
129
94
|
super.didMoveToWindow()
|
|
130
95
|
if window != nil {
|
|
@@ -3,42 +3,25 @@
|
|
|
3
3
|
import SwiftUI
|
|
4
4
|
import UIKit
|
|
5
5
|
|
|
6
|
-
// MARK: - SwiftUI View Component
|
|
6
|
+
// MARK: - SwiftUI View Component for Blur
|
|
7
7
|
|
|
8
8
|
struct BasicColoredView: View {
|
|
9
|
-
let glassTintColor: UIColor
|
|
10
|
-
let glassOpacity: Double
|
|
11
9
|
let blurAmount: Double
|
|
12
10
|
let blurStyle: UIBlurEffect.Style
|
|
13
|
-
let type: String
|
|
14
|
-
let glassType: String
|
|
15
11
|
let reducedTransparencyFallbackColor: UIColor
|
|
16
|
-
let isInteractive: Bool
|
|
17
12
|
let blurIntensity: Double
|
|
18
13
|
let ignoreSafeArea: Bool
|
|
19
14
|
|
|
20
15
|
let isReducedTransparencyEnabled = UIAccessibility.isReduceTransparencyEnabled
|
|
21
16
|
|
|
22
|
-
|
|
23
|
-
init(glassTintColor: UIColor,
|
|
24
|
-
glassOpacity: Double,
|
|
25
|
-
blurAmount: Double,
|
|
17
|
+
init(blurAmount: Double,
|
|
26
18
|
blurStyle: UIBlurEffect.Style,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
reducedTransparencyFallbackColor: UIColor,
|
|
30
|
-
isInteractive: Bool,
|
|
31
|
-
ignoreSafeArea: Bool = false) {
|
|
32
|
-
self.glassTintColor = glassTintColor
|
|
33
|
-
self.glassOpacity = glassOpacity
|
|
19
|
+
ignoreSafeArea: Bool,
|
|
20
|
+
reducedTransparencyFallbackColor: UIColor) {
|
|
34
21
|
self.blurAmount = blurAmount
|
|
35
22
|
self.blurStyle = blurStyle
|
|
36
|
-
self.type = type
|
|
37
|
-
self.glassType = glassType
|
|
38
|
-
self.reducedTransparencyFallbackColor = reducedTransparencyFallbackColor
|
|
39
|
-
self.isInteractive = isInteractive
|
|
40
23
|
self.ignoreSafeArea = ignoreSafeArea
|
|
41
|
-
|
|
24
|
+
self.reducedTransparencyFallbackColor = reducedTransparencyFallbackColor
|
|
42
25
|
self.blurIntensity = mapBlurAmountToIntensity(blurAmount)
|
|
43
26
|
}
|
|
44
27
|
|
|
@@ -54,34 +37,7 @@ struct BasicColoredView: View {
|
|
|
54
37
|
.fill(Color(reducedTransparencyFallbackColor))
|
|
55
38
|
)
|
|
56
39
|
} else {
|
|
57
|
-
|
|
58
|
-
AnyView(liquidGlassBlurView)
|
|
59
|
-
} else {
|
|
60
|
-
AnyView(regularBlurView)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private var liquidGlassBlurView: some View {
|
|
66
|
-
Group {
|
|
67
|
-
if #available(iOS 26.0, *) {
|
|
68
|
-
let baseGlassEffect = glassEffectFromString(glassType)
|
|
69
|
-
Rectangle()
|
|
70
|
-
.glassEffect(
|
|
71
|
-
baseGlassEffect
|
|
72
|
-
.tint(Color(glassTintColor).opacity(glassOpacity))
|
|
73
|
-
.interactive(isInteractive), in: .rect
|
|
74
|
-
)
|
|
75
|
-
} else {
|
|
76
|
-
// Use proper blur intensity control for liquid glass fallback
|
|
77
|
-
Rectangle()
|
|
78
|
-
.fill(Color(.clear))
|
|
79
|
-
.background(Blur(style: blurStyle, intensity: blurIntensity))
|
|
80
|
-
.overlay(
|
|
81
|
-
Color(glassTintColor)
|
|
82
|
-
.opacity(glassOpacity)
|
|
83
|
-
)
|
|
84
|
-
}
|
|
40
|
+
AnyView(regularBlurView)
|
|
85
41
|
}
|
|
86
42
|
}
|
|
87
43
|
|