@sbaiahmed1/react-native-blur 4.0.0 → 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.
Files changed (45) hide show
  1. package/README.md +155 -47
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/BlurType.kt +63 -0
  4. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurPackage.kt +1 -0
  5. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurView.kt +63 -43
  6. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeBlurViewManager.kt +14 -26
  7. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurView.kt +320 -0
  8. package/android/src/main/java/com/sbaiahmed1/reactnativeblur/ReactNativeProgressiveBlurViewManager.kt +81 -0
  9. package/ios/Helpers/BlurStyleHelpers.swift +20 -0
  10. package/ios/Helpers/ReactNativeProgressiveBlurViewHelper.swift +39 -0
  11. package/ios/ReactNativeLiquidGlassView.mm +8 -1
  12. package/ios/ReactNativeProgressiveBlurView.h +14 -0
  13. package/ios/ReactNativeProgressiveBlurView.mm +213 -0
  14. package/ios/ReactNativeProgressiveBlurViewManager.h +4 -0
  15. package/ios/ReactNativeProgressiveBlurViewManager.mm +137 -0
  16. package/ios/Views/LiquidGlassContainerView.swift +8 -30
  17. package/ios/Views/ProgressiveBlurView.swift +124 -0
  18. package/ios/Views/VariableBlurView.swift +142 -0
  19. package/lib/module/BlurView.js +23 -12
  20. package/lib/module/BlurView.js.map +1 -1
  21. package/lib/module/LiquidGlassView.js +3 -1
  22. package/lib/module/LiquidGlassView.js.map +1 -1
  23. package/lib/module/ProgressiveBlurView.js +98 -0
  24. package/lib/module/ProgressiveBlurView.js.map +1 -0
  25. package/lib/module/ReactNativeBlurViewNativeComponent.ts +11 -1
  26. package/lib/module/ReactNativeProgressiveBlurViewNativeComponent.ts +45 -0
  27. package/lib/module/index.js +2 -0
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/typescript/src/BlurView.d.ts.map +1 -1
  30. package/lib/typescript/src/LiquidGlassView.d.ts.map +1 -1
  31. package/lib/typescript/src/ProgressiveBlurView.d.ts +97 -0
  32. package/lib/typescript/src/ProgressiveBlurView.d.ts.map +1 -0
  33. package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts +1 -1
  34. package/lib/typescript/src/ReactNativeBlurViewNativeComponent.d.ts.map +1 -1
  35. package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts +14 -0
  36. package/lib/typescript/src/ReactNativeProgressiveBlurViewNativeComponent.d.ts.map +1 -0
  37. package/lib/typescript/src/index.d.ts +4 -0
  38. package/lib/typescript/src/index.d.ts.map +1 -1
  39. package/package.json +5 -5
  40. package/src/BlurView.tsx +21 -17
  41. package/src/LiquidGlassView.tsx +3 -4
  42. package/src/ProgressiveBlurView.tsx +161 -0
  43. package/src/ReactNativeBlurViewNativeComponent.ts +11 -1
  44. package/src/ReactNativeProgressiveBlurViewNativeComponent.ts +45 -0
  45. package/src/index.tsx +6 -0
@@ -1,7 +1,7 @@
1
1
  package com.sbaiahmed1.reactnativeblur
2
2
 
3
3
  import com.facebook.react.module.annotations.ReactModule
4
- import com.facebook.react.uimanager.SimpleViewManager
4
+ import com.facebook.react.uimanager.ViewGroupManager
5
5
  import com.facebook.react.uimanager.ThemedReactContext
6
6
  import com.facebook.react.uimanager.ViewManagerDelegate
7
7
  import com.facebook.react.uimanager.annotations.ReactProp
@@ -9,7 +9,7 @@ import com.facebook.react.viewmanagers.ReactNativeBlurViewManagerInterface
9
9
  import com.facebook.react.viewmanagers.ReactNativeBlurViewManagerDelegate
10
10
 
11
11
  @ReactModule(name = ReactNativeBlurViewManager.NAME)
12
- class ReactNativeBlurViewManager : SimpleViewManager<ReactNativeBlurView>(),
12
+ class ReactNativeBlurViewManager : ViewGroupManager<ReactNativeBlurView>(),
13
13
  ReactNativeBlurViewManagerInterface<ReactNativeBlurView> {
14
14
  private val mDelegate: ViewManagerDelegate<ReactNativeBlurView>
15
15
 
@@ -31,7 +31,7 @@ class ReactNativeBlurViewManager : SimpleViewManager<ReactNativeBlurView>(),
31
31
 
32
32
  @ReactProp(name = "blurType")
33
33
  override fun setBlurType(view: ReactNativeBlurView?, blurType: String?) {
34
- view?.setBlurType(blurType ?: "light")
34
+ view?.setBlurType(blurType ?: "xlight")
35
35
  }
36
36
 
37
37
  @ReactProp(name = "blurAmount")
@@ -44,29 +44,9 @@ class ReactNativeBlurViewManager : SimpleViewManager<ReactNativeBlurView>(),
44
44
  view?.setReducedTransparencyFallbackColor(reducedTransparencyFallbackColor)
45
45
  }
46
46
 
47
- @ReactProp(name = "glassTintColor")
48
- fun setGlassTintColor(view: ReactNativeBlurView?, glassTintColor: String?) {
49
- view?.setGlassTintColor(glassTintColor)
50
- }
51
-
52
- @ReactProp(name = "glassOpacity")
53
- fun setGlassOpacity(view: ReactNativeBlurView?, glassOpacity: Double) {
54
- view?.setGlassOpacity(glassOpacity.toFloat())
55
- }
56
-
57
- @ReactProp(name = "type")
58
- fun setType(view: ReactNativeBlurView?, type: String?) {
59
- view?.setType(type ?: "blur")
60
- }
61
-
62
- @ReactProp(name = "glassType")
63
- fun setGlassType(view: ReactNativeBlurView?, glassType: String?) {
64
- view?.setGlassType(glassType ?: "clear")
65
- }
66
-
67
- @ReactProp(name = "isInteractive")
68
- fun setIsInteractive(view: ReactNativeBlurView?, isInteractive: Boolean) {
69
- view?.setIsInteractive(isInteractive)
47
+ @ReactProp(name = "borderRadius")
48
+ override fun setBorderRadius(view: ReactNativeBlurView?, borderRadius: Float) {
49
+ view?.setBorderRadius(borderRadius)
70
50
  }
71
51
 
72
52
  @ReactProp(name = "ignoreSafeArea")
@@ -84,6 +64,14 @@ class ReactNativeBlurViewManager : SimpleViewManager<ReactNativeBlurView>(),
84
64
  view.cleanup()
85
65
  }
86
66
 
67
+ /**
68
+ * Indicates that React Native's Yoga layout should handle child positioning.
69
+ * Returns false to let React Native manage the layout of children.
70
+ */
71
+ override fun needsCustomLayoutForChildren(): Boolean {
72
+ return false
73
+ }
74
+
87
75
  companion object {
88
76
  const val NAME = "ReactNativeBlurView"
89
77
  }
@@ -0,0 +1,320 @@
1
+ package com.sbaiahmed1.reactnativeblur
2
+
3
+ import android.content.Context
4
+ import android.graphics.Canvas
5
+ import android.graphics.Color
6
+ import android.graphics.LinearGradient
7
+ import android.graphics.Paint
8
+ import android.graphics.PorterDuff
9
+ import android.graphics.PorterDuffXfermode
10
+ import android.graphics.Shader
11
+ import android.util.AttributeSet
12
+ import android.util.Log
13
+ import android.widget.FrameLayout
14
+ import com.qmdeve.blurview.widget.BlurView
15
+ import androidx.core.graphics.toColorInt
16
+
17
+ /**
18
+ * Android implementation of React Native ProgressiveBlurView component.
19
+ * Uses a combination of normal blur (BlurView) + linear gradient mask to create
20
+ * a progressive blur effect that transitions from blurred to clear.
21
+ *
22
+ * This approach is more reliable than using the library's ProgressiveBlurView,
23
+ * which has limited control over gradient direction and appearance.
24
+ */
25
+ class ReactNativeProgressiveBlurView : FrameLayout {
26
+ private var blurView: BlurView? = null
27
+ private val gradientPaint = Paint(Paint.ANTI_ALIAS_FLAG)
28
+
29
+ private var currentBlurRadius = DEFAULT_BLUR_RADIUS
30
+ private var currentOverlayColor = Color.TRANSPARENT
31
+ private var currentDirection = "topToBottom"
32
+ private var currentStartOffset = 0.0f
33
+ private var hasExplicitBackground: Boolean = false
34
+
35
+ companion object {
36
+ private const val TAG = "ReactNativeProgressiveBlur"
37
+ private const val MAX_BLUR_RADIUS = 25f
38
+ private const val DEFAULT_BLUR_RADIUS = 10f
39
+ private const val DEBUG = true
40
+
41
+ // Cross-platform blur amount constants
42
+ private const val MIN_BLUR_AMOUNT = 0f
43
+ private const val MAX_BLUR_AMOUNT = 100f
44
+
45
+ private fun logDebug(message: String) {
46
+ if (DEBUG) {
47
+ Log.d(TAG, message)
48
+ }
49
+ }
50
+
51
+ private fun logWarning(message: String) {
52
+ Log.w(TAG, message)
53
+ }
54
+
55
+ private fun logError(message: String, throwable: Throwable? = null) {
56
+ Log.e(TAG, message, throwable)
57
+ }
58
+
59
+ /**
60
+ * Maps blur amount (0-100) to Android blur radius (0-25).
61
+ */
62
+ private fun mapBlurAmountToRadius(amount: Float): Float {
63
+ if (amount.isNaN() || amount.isInfinite()) {
64
+ logWarning("Invalid blur amount: $amount, using default")
65
+ return DEFAULT_BLUR_RADIUS
66
+ }
67
+ val clampedAmount = amount.coerceIn(MIN_BLUR_AMOUNT, MAX_BLUR_AMOUNT)
68
+ return (clampedAmount / MAX_BLUR_RADIUS) * MAX_BLUR_RADIUS
69
+ }
70
+ }
71
+
72
+ constructor(context: Context) : super(context) {
73
+ initializeProgressiveBlur()
74
+ }
75
+
76
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
77
+ initializeProgressiveBlur()
78
+ }
79
+
80
+ /**
81
+ * Initialize the progressive blur view with blur + gradient approach.
82
+ */
83
+ private fun initializeProgressiveBlur() {
84
+ try {
85
+ // Create and add the blur view as a child
86
+ blurView = BlurView(context, null).apply {
87
+ layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
88
+ setBlurRadius(currentBlurRadius)
89
+ setOverlayColor(currentOverlayColor)
90
+ setBackgroundColor(Color.TRANSPARENT)
91
+ }
92
+ addView(blurView)
93
+
94
+ // Set up the gradient paint
95
+ gradientPaint.style = Paint.Style.FILL
96
+ setWillNotDraw(false) // Enable onDraw for gradient overlay
97
+
98
+ // Set transparent background for the container
99
+ super.setBackgroundColor(Color.TRANSPARENT)
100
+
101
+ logDebug("Initialized progressive blur with blur + gradient approach")
102
+ updateGradient()
103
+
104
+ } catch (e: Exception) {
105
+ logError("Failed to initialize progressive blur view: ${e.message}", e)
106
+ }
107
+ }
108
+
109
+ override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
110
+ super.onSizeChanged(w, h, oldw, oldh)
111
+ if (w > 0 && h > 0) {
112
+ updateGradient()
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Update the gradient shader based on current direction and startOffset.
118
+ */
119
+ private fun updateGradient() {
120
+ if (width <= 0 || height <= 0) {
121
+ return
122
+ }
123
+
124
+ try {
125
+ val (x0, y0, x1, y1) = when (currentDirection) {
126
+ "bottomToTop" -> {
127
+ // Blur at bottom, clear at top
128
+ // point0 (TRANSPARENT/clear) at top, point1 (WHITE/blur) at bottom adjusted by offset
129
+ val offsetPixels = height * currentStartOffset
130
+ floatArrayOf(0f, 0f, 0f, height - offsetPixels)
131
+ }
132
+ "topToBottom" -> {
133
+ // Blur at top, clear at bottom (default)
134
+ // point0 (TRANSPARENT/clear) at bottom, point1 (WHITE/blur) at top adjusted by offset
135
+ val offsetPixels = height * currentStartOffset
136
+ floatArrayOf(0f, height.toFloat(), 0f, offsetPixels)
137
+ }
138
+ "leftToRight" -> {
139
+ val offsetPixels = width * currentStartOffset
140
+ floatArrayOf(offsetPixels, 0f, width.toFloat(), 0f)
141
+ }
142
+ "rightToLeft" -> {
143
+ val offsetPixels = width * currentStartOffset
144
+ floatArrayOf(width.toFloat(), 0f, offsetPixels, 0f)
145
+ }
146
+ else -> floatArrayOf(0f, 0f, 0f, height.toFloat())
147
+ }
148
+
149
+ // Create gradient: fully transparent -> fully opaque
150
+ // This masks the blur: opaque = blur visible, transparent = blur hidden (clear)
151
+ val gradient = LinearGradient(
152
+ x0, y0, x1, y1,
153
+ intArrayOf(Color.TRANSPARENT, Color.WHITE),
154
+ floatArrayOf(0f, 1f),
155
+ Shader.TileMode.CLAMP
156
+ )
157
+
158
+ gradientPaint.shader = gradient
159
+
160
+ logDebug("Updated gradient: direction=$currentDirection, start=($x0,$y0), end=($x1,$y1), offset=$currentStartOffset")
161
+ invalidate()
162
+
163
+ } catch (e: Exception) {
164
+ logError("Failed to update gradient: ${e.message}", e)
165
+ }
166
+ }
167
+
168
+ override fun dispatchDraw(canvas: Canvas) {
169
+ if (width <= 0 || height <= 0) {
170
+ super.dispatchDraw(canvas)
171
+ return
172
+ }
173
+
174
+ // Use a layer to apply the gradient mask
175
+ val saveCount = canvas.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null)
176
+
177
+ // Draw the blur view
178
+ super.dispatchDraw(canvas)
179
+
180
+ // Apply gradient mask using DST_IN to make the blur gradually transparent
181
+ gradientPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
182
+ canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), gradientPaint)
183
+ gradientPaint.xfermode = null
184
+
185
+ canvas.restoreToCount(saveCount)
186
+ }
187
+
188
+ /**
189
+ * Override setBackgroundColor to handle background preservation.
190
+ */
191
+ override fun setBackgroundColor(color: Int) {
192
+ logDebug("setBackgroundColor called: $color")
193
+
194
+ if (color != Color.TRANSPARENT) {
195
+ hasExplicitBackground = true
196
+ logDebug("Stored explicit background color: $color")
197
+ }
198
+
199
+ if (hasExplicitBackground && color != Color.TRANSPARENT) {
200
+ logDebug("Applying background color: $color")
201
+ super.setBackgroundColor(color)
202
+ } else {
203
+ logDebug("Keeping transparent background for blur effect")
204
+ super.setBackgroundColor(Color.TRANSPARENT)
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Called when the view is detached from a window.
210
+ */
211
+ override fun onDetachedFromWindow() {
212
+ super.onDetachedFromWindow()
213
+ cleanup()
214
+ }
215
+
216
+ /**
217
+ * Cleanup method to prevent memory leaks.
218
+ */
219
+ fun cleanup() {
220
+ hasExplicitBackground = false
221
+ removeCallbacks(null)
222
+ blurView = null
223
+ logDebug("View cleaned up")
224
+ }
225
+
226
+ /**
227
+ * Set the blur amount with cross-platform mapping.
228
+ * @param amount The blur amount value (0-100), will be mapped to Android's 0-25 radius range
229
+ */
230
+ fun setBlurAmount(amount: Float) {
231
+ currentBlurRadius = mapBlurAmountToRadius(amount)
232
+ logDebug("setBlurAmount: $amount -> $currentBlurRadius")
233
+
234
+ try {
235
+ blurView?.setBlurRadius(currentBlurRadius)
236
+ invalidate()
237
+ } catch (e: Exception) {
238
+ logError("Failed to set blur radius: ${e.message}", e)
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Set the direction of the progressive blur gradient.
244
+ * @param direction The direction string: "blurredTopClearBottom" or "blurredBottomClearTop"
245
+ */
246
+ fun setDirection(direction: String) {
247
+ currentDirection = when (direction.lowercase()) {
248
+ "blurredbottomcleartop", "bottomtotop", "bottom" -> "bottomToTop"
249
+ "blurredtopclearbottom", "toptobottom", "top" -> "topToBottom"
250
+ "blurredlefttoclearright", "lefttoright", "left" -> "leftToRight"
251
+ "blurredrightoclearleft", "righttoleft", "right" -> "rightToLeft"
252
+ else -> {
253
+ logWarning("Unknown direction: $direction, defaulting to topToBottom")
254
+ "topToBottom"
255
+ }
256
+ }
257
+ logDebug("setDirection: $direction -> $currentDirection")
258
+
259
+ try {
260
+ updateGradient()
261
+ } catch (e: Exception) {
262
+ logError("Failed to set gradient direction: ${e.message}", e)
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Set the start offset for the progressive blur.
268
+ * Controls where the gradient transition begins.
269
+ *
270
+ * @param offset The offset value (0.0 to 1.0) - where 0 starts immediately, 1 delays to the end
271
+ */
272
+ fun setStartOffset(offset: Float) {
273
+ currentStartOffset = offset.coerceIn(0.0f, 1.0f)
274
+ logDebug("setStartOffset: $offset -> clamped to $currentStartOffset")
275
+
276
+ try {
277
+ updateGradient()
278
+ } catch (e: Exception) {
279
+ logError("Failed to update startOffset: ${e.message}", e)
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Set the blur type which determines the overlay color.
285
+ * @param type The blur type string (case-insensitive)
286
+ */
287
+ fun setBlurType(type: String) {
288
+ val blurType = BlurType.fromString(type)
289
+ currentOverlayColor = blurType.overlayColor
290
+ logDebug("setBlurType: $type -> ${blurType.name} -> ${Integer.toHexString(currentOverlayColor)}")
291
+
292
+ try {
293
+ blurView?.setOverlayColor(currentOverlayColor)
294
+ invalidate()
295
+ } catch (e: Exception) {
296
+ logError("Failed to set overlay color: ${e.message}", e)
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Set the fallback color for reduced transparency accessibility mode.
302
+ * @param color The color string in hex format (e.g., "#FF0000") or null to clear
303
+ */
304
+ fun setReducedTransparencyFallbackColor(color: String?) {
305
+ if (color.isNullOrBlank()) {
306
+ logDebug("Cleared reduced transparency fallback color")
307
+ return
308
+ }
309
+
310
+ try {
311
+ val fallbackColor = color.toColorInt()
312
+ logDebug("setReducedTransparencyFallbackColor: $color -> ${Integer.toHexString(fallbackColor)}")
313
+ // Android doesn't have a direct equivalent to iOS's "Reduce Transparency" setting
314
+ } catch (e: IllegalArgumentException) {
315
+ logWarning("Invalid color format for reduced transparency fallback: $color - ${e.message}")
316
+ } catch (e: Exception) {
317
+ logError("Error parsing reduced transparency fallback color: $color", e)
318
+ }
319
+ }
320
+ }
@@ -0,0 +1,81 @@
1
+ package com.sbaiahmed1.reactnativeblur
2
+
3
+ import com.facebook.react.module.annotations.ReactModule
4
+ import com.facebook.react.uimanager.SimpleViewManager
5
+ import com.facebook.react.uimanager.ThemedReactContext
6
+ import com.facebook.react.uimanager.ViewManagerDelegate
7
+ import com.facebook.react.uimanager.annotations.ReactProp
8
+ import com.facebook.react.viewmanagers.ReactNativeProgressiveBlurViewManagerInterface
9
+ import com.facebook.react.viewmanagers.ReactNativeProgressiveBlurViewManagerDelegate
10
+
11
+ /**
12
+ * View manager for the ReactNativeProgressiveBlurView component.
13
+ * Handles prop updates and view lifecycle for progressive blur effects on Android.
14
+ */
15
+ @ReactModule(name = ReactNativeProgressiveBlurViewManager.NAME)
16
+ class ReactNativeProgressiveBlurViewManager : SimpleViewManager<ReactNativeProgressiveBlurView>(),
17
+ ReactNativeProgressiveBlurViewManagerInterface<ReactNativeProgressiveBlurView> {
18
+ private val mDelegate: ViewManagerDelegate<ReactNativeProgressiveBlurView>
19
+
20
+ init {
21
+ mDelegate = ReactNativeProgressiveBlurViewManagerDelegate(this)
22
+ }
23
+
24
+ override fun getDelegate(): ViewManagerDelegate<ReactNativeProgressiveBlurView>? {
25
+ return mDelegate
26
+ }
27
+
28
+ override fun getName(): String {
29
+ return NAME
30
+ }
31
+
32
+ public override fun createViewInstance(context: ThemedReactContext): ReactNativeProgressiveBlurView {
33
+ return ReactNativeProgressiveBlurView(context)
34
+ }
35
+
36
+ @ReactProp(name = "blurType")
37
+ override fun setBlurType(view: ReactNativeProgressiveBlurView?, blurType: String?) {
38
+ // Provide default value if blurType is null or empty
39
+ val safeBlurType = if (blurType.isNullOrBlank()) "regular" else blurType
40
+ view?.setBlurType(safeBlurType)
41
+ }
42
+
43
+ @ReactProp(name = "blurAmount")
44
+ override fun setBlurAmount(view: ReactNativeProgressiveBlurView?, blurAmount: Double) {
45
+ view?.setBlurAmount(blurAmount.toFloat())
46
+ }
47
+
48
+ @ReactProp(name = "direction")
49
+ override fun setDirection(view: ReactNativeProgressiveBlurView?, direction: String?) {
50
+ // Provide default value if direction is null or empty
51
+ val safeDirection = if (direction.isNullOrBlank()) "blurredTopClearBottom" else direction
52
+ view?.setDirection(safeDirection)
53
+ }
54
+
55
+ @ReactProp(name = "startOffset")
56
+ override fun setStartOffset(view: ReactNativeProgressiveBlurView?, startOffset: Double) {
57
+ view?.setStartOffset(startOffset.toFloat())
58
+ }
59
+
60
+ @ReactProp(name = "reducedTransparencyFallbackColor")
61
+ override fun setReducedTransparencyFallbackColor(
62
+ view: ReactNativeProgressiveBlurView?,
63
+ reducedTransparencyFallbackColor: String?
64
+ ) {
65
+ view?.setReducedTransparencyFallbackColor(reducedTransparencyFallbackColor)
66
+ }
67
+
68
+ /**
69
+ * Called when view is detached from view hierarchy and allows for cleanup.
70
+ * This prevents the white screen issue during navigation transitions on Android.
71
+ */
72
+ override fun onDropViewInstance(view: ReactNativeProgressiveBlurView) {
73
+ super.onDropViewInstance(view)
74
+ // Call cleanup to reset state and prevent white screen artifacts
75
+ view.cleanup()
76
+ }
77
+
78
+ companion object {
79
+ const val NAME = "ReactNativeProgressiveBlurView"
80
+ }
81
+ }
@@ -30,6 +30,26 @@ func blurStyleFromString(_ styleString: String) -> UIBlurEffect.Style {
30
30
  return .systemThickMaterial
31
31
  case "systemChromeMaterial":
32
32
  return .systemChromeMaterial
33
+ case "systemUltraThinMaterialLight":
34
+ return .systemUltraThinMaterialLight
35
+ case "systemThinMaterialLight":
36
+ return .systemThinMaterialLight
37
+ case "systemMaterialLight":
38
+ return .systemMaterialLight
39
+ case "systemThickMaterialLight":
40
+ return .systemThickMaterialLight
41
+ case "systemChromeMaterialLight":
42
+ return .systemChromeMaterialLight
43
+ case "systemUltraThinMaterialDark":
44
+ return .systemUltraThinMaterialDark
45
+ case "systemThinMaterialDark":
46
+ return .systemThinMaterialDark
47
+ case "systemMaterialDark":
48
+ return .systemMaterialDark
49
+ case "systemThickMaterialDark":
50
+ return .systemThickMaterialDark
51
+ case "systemChromeMaterialDark":
52
+ return .systemChromeMaterialDark
33
53
  default:
34
54
  return .extraLight
35
55
  }
@@ -0,0 +1,39 @@
1
+ // ReactNativeProgressiveBlurViewHelper.swift
2
+
3
+ import SwiftUI
4
+ import UIKit
5
+
6
+ // MARK: - Objective-C Bridging Helpers for Progressive Blur
7
+
8
+ @objc public class ReactNativeProgressiveBlurViewHelper: NSObject {
9
+
10
+ /// Creates and returns a progressive blur view.
11
+ @objc public static func createProgressiveBlurViewWithFrame(_ frame: CGRect) -> ProgressiveBlurView {
12
+ return ProgressiveBlurView(frame: frame)
13
+ }
14
+
15
+ /// Updates the progressive blur view with a new blur amount.
16
+ @objc public static func updateProgressiveBlurView(_ blurView: ProgressiveBlurView, withBlurAmount blurAmount: Double) {
17
+ blurView.blurAmount = blurAmount
18
+ }
19
+
20
+ /// Updates the progressive blur view with a new direction.
21
+ @objc public static func updateProgressiveBlurView(_ blurView: ProgressiveBlurView, withDirection direction: String) {
22
+ blurView.direction = direction
23
+ }
24
+
25
+ /// Updates the progressive blur view with a new start offset.
26
+ @objc public static func updateProgressiveBlurView(_ blurView: ProgressiveBlurView, withStartOffset startOffset: Double) {
27
+ blurView.startOffset = startOffset
28
+ }
29
+
30
+ /// Updates the progressive blur view with a new blur type.
31
+ @objc public static func updateProgressiveBlurView(_ blurView: ProgressiveBlurView, withBlurType blurType: String) {
32
+ blurView.blurTypeString = blurType
33
+ }
34
+
35
+ /// Updates the progressive blur view with a new reduced transparency fallback color.
36
+ @objc public static func updateProgressiveBlurView(_ blurView: ProgressiveBlurView, withReducedTransparencyFallbackColor reducedTransparencyFallbackColor: UIColor) {
37
+ blurView.reducedTransparencyFallbackColor = reducedTransparencyFallbackColor
38
+ }
39
+ }
@@ -246,7 +246,14 @@ using namespace facebook::react;
246
246
  // Copy corner radius from the Fabric view to the inner glass view (Callstack pattern)
247
247
  _liquidGlassView.layer.cornerRadius = self.layer.cornerRadius;
248
248
  _liquidGlassView.layer.cornerCurve = self.layer.cornerCurve;
249
- _liquidGlassView.layer.masksToBounds = YES;
249
+
250
+ // On iOS 26+, don't clip bounds to allow interactive glass animations to be visible
251
+ // The glass effect view handles its own clipping via cornerConfiguration
252
+ if (@available(iOS 26.0, *)) {
253
+ _liquidGlassView.layer.masksToBounds = NO;
254
+ } else {
255
+ _liquidGlassView.layer.masksToBounds = YES;
256
+ }
250
257
  }
251
258
 
252
259
  - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
@@ -0,0 +1,14 @@
1
+ #import <React/RCTViewComponentView.h>
2
+ #import <UIKit/UIKit.h>
3
+
4
+ #ifndef NativeComponentExampleComponentView_h
5
+ #define NativeComponentExampleComponentView_h
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ @interface ReactNativeProgressiveBlurView : RCTViewComponentView
10
+ @end
11
+
12
+ NS_ASSUME_NONNULL_END
13
+
14
+ #endif /* NativeComponentExampleComponentView_h */