@sbaiahmed1/react-native-blur 3.1.2 → 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.
Files changed (56) hide show
  1. package/README.md +319 -308
  2. package/ReactNativeBlur.podspec +1 -1
  3. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeBlurViewManagerDelegate.java +18 -3
  4. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeBlurViewManagerInterface.java +6 -1
  5. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassEffectContainerManagerDelegate.java +53 -0
  6. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassEffectContainerManagerInterface.java +25 -0
  7. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassViewManagerDelegate.java +38 -0
  8. package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/ReactNativeGlassViewManagerInterface.java +20 -0
  9. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.cpp +1 -0
  10. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ComponentDescriptors.h +1 -0
  11. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.cpp +1 -0
  12. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/EventEmitters.h +7 -0
  13. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.cpp +21 -2
  14. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/Props.h +70 -2
  15. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.cpp +1 -0
  16. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/ShadowNodes.h +11 -0
  17. package/android/app/build/generated/source/codegen/jni/react/renderer/components/ReactNativeBlurViewSpec/States.h +12 -0
  18. package/android/build.gradle +2 -3
  19. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +62 -269
  20. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +13 -8
  21. package/ios/Helpers/BlurStyleHelpers.swift +1 -1
  22. package/ios/Helpers/ReactNativeBlurViewHelper.swift +8 -32
  23. package/ios/Helpers/ReactNativeLiquidGlassViewHelper.swift +44 -0
  24. package/ios/ReactNativeBlurView.mm +28 -74
  25. package/ios/{ReactNativeBlurViewManager.m → ReactNativeBlurViewManager.mm} +15 -39
  26. package/ios/ReactNativeLiquidGlassView.h +14 -0
  27. package/ios/ReactNativeLiquidGlassView.mm +284 -0
  28. package/ios/ReactNativeLiquidGlassViewManager.h +6 -0
  29. package/ios/ReactNativeLiquidGlassViewManager.mm +20 -0
  30. package/ios/Views/AdvancedBlurView.swift +6 -34
  31. package/ios/Views/BasicColoredView.swift +37 -44
  32. package/ios/Views/LiquidGlassContainerView.swift +173 -0
  33. package/lib/module/BlurView.js +17 -31
  34. package/lib/module/BlurView.js.map +1 -1
  35. package/lib/module/LiquidGlassView.js +75 -0
  36. package/lib/module/LiquidGlassView.js.map +1 -0
  37. package/lib/module/ReactNativeBlurViewNativeComponent.ts +1 -7
  38. package/lib/module/ReactNativeLiquidGlassViewNativeComponent.ts +57 -0
  39. package/lib/module/index.js +2 -0
  40. package/lib/module/index.js.map +1 -1
  41. package/lib/typescript/src/BlurView.d.ts +19 -39
  42. package/lib/typescript/src/BlurView.d.ts.map +1 -1
  43. package/lib/typescript/src/LiquidGlassView.d.ts +85 -0
  44. package/lib/typescript/src/LiquidGlassView.d.ts.map +1 -0
  45. package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts +1 -6
  46. package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts.map +1 -1
  47. package/lib/typescript/src/ReactNativeLiquidGlassViewNativeComponent.d.ts +44 -0
  48. package/lib/typescript/src/ReactNativeLiquidGlassViewNativeComponent.d.ts.map +1 -0
  49. package/lib/typescript/src/index.d.ts +4 -0
  50. package/lib/typescript/src/index.d.ts.map +1 -1
  51. package/package.json +6 -3
  52. package/src/BlurView.tsx +37 -68
  53. package/src/LiquidGlassView.tsx +138 -0
  54. package/src/ReactNativeBlurViewNativeComponent.ts +1 -7
  55. package/src/ReactNativeLiquidGlassViewNativeComponent.ts +57 -0
  56. package/src/index.tsx +6 -0
@@ -28,13 +28,13 @@ using namespace facebook::react;
28
28
  if (!colorString || [colorString isEqualToString:@""] || colorString.length == 0) {
29
29
  return [UIColor clearColor]; // Default color
30
30
  }
31
-
31
+
32
32
  // Prevent excessively long strings that could cause performance issues
33
33
  if (colorString.length > 50) {
34
34
  NSLog(@"[ReactNativeBlurView] Warning: Color string too long, using default clear color");
35
35
  return [UIColor clearColor];
36
36
  }
37
-
37
+
38
38
  // Handle common color names
39
39
  NSDictionary *colorMap = @{
40
40
  @"red": [UIColor redColor],
@@ -49,12 +49,12 @@ using namespace facebook::react;
49
49
  @"clear": [UIColor clearColor],
50
50
  @"transparent": [UIColor clearColor]
51
51
  };
52
-
52
+
53
53
  UIColor *namedColor = colorMap[colorString.lowercaseString];
54
54
  if (namedColor) {
55
55
  return namedColor;
56
56
  }
57
-
57
+
58
58
  // Handle hex colors (e.g., "#FF0000", "FF0000", "#FF00FF00", "FF00FF00")
59
59
  NSString *hexString = colorString;
60
60
  if ([hexString hasPrefix:@"#"]) {
@@ -64,7 +64,7 @@ using namespace facebook::react;
64
64
  }
65
65
  hexString = [hexString substringFromIndex:1];
66
66
  }
67
-
67
+
68
68
  // Validate hex string contains only valid hex characters
69
69
  NSCharacterSet *hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
70
70
  NSCharacterSet *invalidCharacters = [hexCharacterSet invertedSet];
@@ -72,7 +72,7 @@ using namespace facebook::react;
72
72
  NSLog(@"[ReactNativeBlurView] Warning: Invalid hex color format '%@', contains non-hex characters", colorString);
73
73
  return [UIColor clearColor];
74
74
  }
75
-
75
+
76
76
  // Handle 6-character hex (RGB)
77
77
  if (hexString.length == 6) {
78
78
  unsigned int hexValue;
@@ -104,7 +104,7 @@ using namespace facebook::react;
104
104
  unsigned int r = (hexValue & 0xF00) >> 8;
105
105
  unsigned int g = (hexValue & 0x0F0) >> 4;
106
106
  unsigned int b = (hexValue & 0x00F);
107
-
107
+
108
108
  return [UIColor colorWithRed:(r | (r << 4)) / 255.0
109
109
  green:(g | (g << 4)) / 255.0
110
110
  blue:(b | (b << 4)) / 255.0
@@ -112,10 +112,10 @@ using namespace facebook::react;
112
112
  }
113
113
  }
114
114
  else {
115
- NSLog(@"[ReactNativeBlurView] Warning: Unsupported hex color length (%lu) for '%@', expected 3, 6, or 8 characters",
115
+ NSLog(@"[ReactNativeBlurView] Warning: Unsupported hex color length (%lu) for '%@', expected 3, 6, or 8 characters",
116
116
  (unsigned long)hexString.length, colorString);
117
117
  }
118
-
118
+
119
119
  NSLog(@"[ReactNativeBlurView] Warning: Could not parse color '%@', using default clear color", colorString);
120
120
  return [UIColor clearColor]; // Fallback to clear
121
121
  }
@@ -132,48 +132,30 @@ using namespace facebook::react;
132
132
  if (self = [super initWithFrame:frame]) {
133
133
  static const auto defaultProps = std::make_shared<const ReactNativeBlurViewProps>();
134
134
  _props = defaultProps;
135
-
135
+
136
136
  const auto &bvProps = *std::static_pointer_cast<const ReactNativeBlurViewProps>(defaultProps);
137
-
137
+
138
138
  _advancedBlurView = [ReactNativeBlurViewHelper createBlurViewWithFrame:frame];
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
-
139
+
148
140
  // Set initial blurAmount from default props
149
141
  [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withBlurAmount:bvProps.blurAmount];
150
-
142
+
151
143
  // Set initial blurType from default props
152
144
  if (bvProps.blurType != facebook::react::ReactNativeBlurViewBlurType::Xlight) {
153
145
  NSString *blurTypeString = [[NSString alloc] initWithUTF8String:toString(bvProps.blurType).c_str()];
154
146
  [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withBlurType:blurTypeString];
155
147
  }
156
-
157
- // Set initial isInteractive from default props
158
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIsInteractive:bvProps.isInteractive];
159
-
160
- // Set initial glassType from default props
161
- if (bvProps.glassType != facebook::react::ReactNativeBlurViewGlassType::Clear) {
162
- NSString *glassTypeString = [[NSString alloc] initWithUTF8String:toString(bvProps.glassType).c_str()];
163
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassType:glassTypeString];
164
- }
165
-
166
- // Set initial type from default props
167
- NSString *blurTypeString = [[NSString alloc] initWithUTF8String:toString(bvProps.type).c_str()];
168
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withType:blurTypeString];
169
-
148
+
170
149
  // Set initial reducedTransparencyFallbackColor from default props
171
150
  if (!bvProps.reducedTransparencyFallbackColor.empty()) {
172
151
  NSString *fallbackColorString = [[NSString alloc] initWithUTF8String:bvProps.reducedTransparencyFallbackColor.c_str()];
173
152
  UIColor *fallbackColor = [ReactNativeBlurView colorFromString:fallbackColorString];
174
153
  [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withReducedTransparencyFallbackColor:fallbackColor];
175
154
  }
176
-
155
+
156
+ // Set initial ignoreSafeArea from default props
157
+ [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIgnoringSafeArea:bvProps.ignoreSafeArea];
158
+
177
159
  [self addSubview:_advancedBlurView];
178
160
  }
179
161
  return self;
@@ -183,26 +165,12 @@ using namespace facebook::react;
183
165
  {
184
166
  const auto &oldViewProps = *std::static_pointer_cast<ReactNativeBlurViewProps const>(_props);
185
167
  const auto &newViewProps = *std::static_pointer_cast<ReactNativeBlurViewProps const>(props);
186
-
187
- // Update glassTintColor if it has changed
188
- if (oldViewProps.glassTintColor != newViewProps.glassTintColor) {
189
- if (!newViewProps.glassTintColor.empty()) {
190
- NSString *glassTintColorString = [[NSString alloc] initWithUTF8String:newViewProps.glassTintColor.c_str()];
191
- UIColor *newGlassTintColor = [ReactNativeBlurView colorFromString:glassTintColorString];
192
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassTintColor:newGlassTintColor];
193
- }
194
- }
195
-
196
- // Update glassOpacity if it has changed
197
- if (oldViewProps.glassOpacity != newViewProps.glassOpacity) {
198
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassOpacity:newViewProps.glassOpacity];
199
- }
200
-
168
+
201
169
  // Update blurAmount if it has changed
202
170
  if (oldViewProps.blurAmount != newViewProps.blurAmount) {
203
171
  [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withBlurAmount:newViewProps.blurAmount];
204
172
  }
205
-
173
+
206
174
  // Update blurType if it has changed
207
175
  if (oldViewProps.blurType != newViewProps.blurType) {
208
176
  if (newViewProps.blurType != facebook::react::ReactNativeBlurViewBlurType::Xlight) {
@@ -210,26 +178,7 @@ using namespace facebook::react;
210
178
  [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withBlurType:blurTypeString];
211
179
  }
212
180
  }
213
-
214
- // Update glassType if it has changed
215
- if (oldViewProps.glassType != newViewProps.glassType) {
216
- if (newViewProps.glassType != facebook::react::ReactNativeBlurViewGlassType::Clear) {
217
- NSString *glassTypeString = [[NSString alloc] initWithUTF8String:toString(newViewProps.glassType).c_str()];
218
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withGlassType:glassTypeString];
219
- }
220
- }
221
-
222
- // Update type if it has changed
223
- if (oldViewProps.type != newViewProps.type) {
224
- NSString *blurTypeString = [[NSString alloc] initWithUTF8String:toString(newViewProps.type).c_str()];
225
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withType:blurTypeString];
226
- }
227
-
228
- // Update isInteractive if it has changed
229
- if (oldViewProps.isInteractive != newViewProps.isInteractive) {
230
- [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIsInteractive:newViewProps.isInteractive];
231
- }
232
-
181
+
233
182
  // Update reducedTransparencyFallbackColor if it has changed
234
183
  if (oldViewProps.reducedTransparencyFallbackColor != newViewProps.reducedTransparencyFallbackColor) {
235
184
  if (!newViewProps.reducedTransparencyFallbackColor.empty()) {
@@ -238,10 +187,15 @@ using namespace facebook::react;
238
187
  [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withReducedTransparencyFallbackColor:fallbackColor];
239
188
  }
240
189
  }
241
-
190
+
191
+ // Update ignoreSafeArea if it has changed
192
+ if (oldViewProps.ignoreSafeArea != newViewProps.ignoreSafeArea) {
193
+ [ReactNativeBlurViewHelper updateBlurView:_advancedBlurView withIgnoringSafeArea:newViewProps.ignoreSafeArea];
194
+ }
195
+
242
196
  // Store the new props
243
197
  _props = props;
244
-
198
+
245
199
  [super updateProps:props oldProps:oldProps];
246
200
  }
247
201
 
@@ -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,24 +38,6 @@ RCT_CUSTOM_VIEW_PROPERTY(blurType, NSString, AdvancedBlurView)
50
38
  [ReactNativeBlurViewHelper updateBlurView:view withBlurType:blurType];
51
39
  }
52
40
 
53
- RCT_CUSTOM_VIEW_PROPERTY(glassType, NSString, AdvancedBlurView)
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)
66
- {
67
- BOOL isInteractive = json ? [RCTConvert BOOL:json] : YES;
68
- [ReactNativeBlurViewHelper updateBlurView:view withIsInteractive:isInteractive];
69
- }
70
-
71
41
  RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlurView)
72
42
  {
73
43
  NSString *colorString = json ? [RCTConvert NSString:json] : @"#FFFFFF";
@@ -75,19 +45,25 @@ RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlu
75
45
  [ReactNativeBlurViewHelper updateBlurView:view withReducedTransparencyFallbackColor:color];
76
46
  }
77
47
 
48
+ RCT_CUSTOM_VIEW_PROPERTY(ignoreSafeArea, BOOL, AdvancedBlurView)
49
+ {
50
+ BOOL ignoreSafeArea = json ? [RCTConvert BOOL:json] : NO;
51
+ [ReactNativeBlurViewHelper updateBlurView:view withIgnoringSafeArea:ignoreSafeArea];
52
+ }
53
+
78
54
  // Color parsing helper method (copied from ReactNativeBlurView.mm)
79
55
  - (UIColor *)colorFromString:(NSString *)colorString {
80
56
  // Input validation
81
57
  if (!colorString || [colorString isEqualToString:@""] || colorString.length == 0) {
82
58
  return [UIColor clearColor]; // Default color
83
59
  }
84
-
60
+
85
61
  // Prevent excessively long strings that could cause performance issues
86
62
  if (colorString.length > 50) {
87
63
  NSLog(@"[ReactNativeBlurViewManager] Warning: Color string too long, using default clear color");
88
64
  return [UIColor clearColor];
89
65
  }
90
-
66
+
91
67
  // Handle common color names
92
68
  NSDictionary *colorMap = @{
93
69
  @"red": [UIColor redColor],
@@ -102,12 +78,12 @@ RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlu
102
78
  @"clear": [UIColor clearColor],
103
79
  @"transparent": [UIColor clearColor]
104
80
  };
105
-
81
+
106
82
  UIColor *namedColor = colorMap[colorString.lowercaseString];
107
83
  if (namedColor) {
108
84
  return namedColor;
109
85
  }
110
-
86
+
111
87
  // Handle hex colors (e.g., "#FF0000", "FF0000", "#FF00FF00", "FF00FF00")
112
88
  NSString *hexString = colorString;
113
89
  if ([hexString hasPrefix:@"#"]) {
@@ -117,7 +93,7 @@ RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlu
117
93
  }
118
94
  hexString = [hexString substringFromIndex:1];
119
95
  }
120
-
96
+
121
97
  // Validate hex string contains only valid hex characters
122
98
  NSCharacterSet *hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
123
99
  NSCharacterSet *invalidCharacters = [hexCharacterSet invertedSet];
@@ -125,7 +101,7 @@ RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlu
125
101
  NSLog(@"[ReactNativeBlurViewManager] Warning: Invalid hex color format '%@', contains non-hex characters", colorString);
126
102
  return [UIColor clearColor];
127
103
  }
128
-
104
+
129
105
  // Handle 6-character hex (RGB)
130
106
  if (hexString.length == 6) {
131
107
  unsigned int hexValue;
@@ -157,7 +133,7 @@ RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlu
157
133
  unsigned int r = (hexValue & 0xF00) >> 8;
158
134
  unsigned int g = (hexValue & 0x0F0) >> 4;
159
135
  unsigned int b = (hexValue & 0x00F);
160
-
136
+
161
137
  return [UIColor colorWithRed:(r | (r << 4)) / 255.0
162
138
  green:(g | (g << 4)) / 255.0
163
139
  blue:(b | (b << 4)) / 255.0
@@ -165,10 +141,10 @@ RCT_CUSTOM_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString, AdvancedBlu
165
141
  }
166
142
  }
167
143
  else {
168
- NSLog(@"[ReactNativeBlurViewManager] Warning: Unsupported hex color length (%lu) for '%@', expected 3, 6, or 8 characters",
144
+ NSLog(@"[ReactNativeBlurViewManager] Warning: Unsupported hex color length (%lu) for '%@', expected 3, 6, or 8 characters",
169
145
  (unsigned long)hexString.length, colorString);
170
146
  }
171
-
147
+
172
148
  NSLog(@"[ReactNativeBlurViewManager] Warning: Could not parse color '%@', using default clear color", colorString);
173
149
  return [UIColor clearColor]; // Fallback to clear
174
150
  }
@@ -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,6 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import <React/RCTUIManager.h>
3
+ #import "RCTBridge.h"
4
+
5
+ @interface ReactNativeLiquidGlassViewManager : RCTViewManager
6
+ @end
@@ -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