react-native-blur-vibe 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
- # react-native-blur-vibe
2
-
3
- A modern, actively maintained blur view for React Native. Works on **iOS** and **Android** with full New Architecture (Fabric) support.
1
+ # React Native Blur-Vibe
2
+
3
+ <img width="1500" height="500" alt="github-banner" src="https://github.com/user-attachments/assets/78b2e5ec-5b57-48c0-b984-69cb57cbcf26" />
4
+ <br></br>
5
+ A modern, actively maintained blur view for React Native. Works on <b>iOS</b> and <b>Android</b> with full New Architecture (Fabric) support.
4
6
 
5
7
  > The key difference from other blur libraries: `overlayColor` works on **both iOS and Android** — letting you control blur visibility the same way CSS `backdrop-filter` + `background-color` works on the web.
6
-
8
+ <br></br>
7
9
  [![npm version](https://img.shields.io/npm/v/react-native-blur-vibe)](https://www.npmjs.com/package/react-native-blur-vibe)
8
10
  [![Build iOS](https://github.com/I-am-Pritam-20/react-native-blur-vibe/actions/workflows/build-ios.yml/badge.svg)](https://github.com/I-am-Pritam-20/react-native-blur-vibe/actions/workflows/build-ios.yml)
9
11
  [![Build Android](https://github.com/I-am-Pritam-20/react-native-blur-vibe/actions/workflows/build-android.yml/badge.svg)](https://github.com/I-am-Pritam-20/react-native-blur-vibe/actions/workflows/build-android.yml)
@@ -46,6 +48,20 @@ The `overlayColor` alpha channel is what controls blur visibility:
46
48
  **This works on both iOS and Android.** Not just Android like other libraries.
47
49
 
48
50
  ---
51
+
52
+ <details>
53
+ <summary><h3>Screenshots (Expand to see)</h3></summary>
54
+ <table>
55
+ <tr>
56
+ <td align="center"> <h3>Android</h3>
57
+ <img width="244" height="462" alt="Android-Demo" src="https://github.com/user-attachments/assets/e1cd120e-1ce1-4bba-aef1-4182aa023fbb" />
58
+ </td>
59
+ <td align="center"> <h3>iOS</h3>
60
+ <img width="244" height="462" alt="iPhone-Demo" src="https://github.com/user-attachments/assets/4b8ad035-d2ff-471e-b3e6-a645c87ea066" />
61
+ </td>
62
+ </tr>
63
+ </table>
64
+ </details>
49
65
 
50
66
  ## Installation
51
67
 
@@ -19,11 +19,14 @@ import android.widget.FrameLayout
19
19
  /**
20
20
  * BlurVibeView — Android implementation
21
21
  *
22
- * API 31+ : RenderEffect (hardware accelerated)
23
- * API 24-30: RenderScript (built into Android SDK, no extra dep needed)
22
+ * API 31+ : RenderEffect (hardware accelerated)
23
+ * API 24-30: RenderScript (built-in SDK, no extra dep)
24
24
  *
25
- * overlayColor sits on top of blur — like CSS:
26
- * backdrop-filter: blur(Xpx) + background-color: overlayColor
25
+ * Color props (overlayColor, reducedTransparencyFallbackColor) are
26
+ * received as hex strings from JS and parsed manually here.
27
+ * This gives full control over alpha channel handling.
28
+ *
29
+ * Supports: "#RGB" "#RRGGBB" "#RRGGBBAA" "transparent"
27
30
  */
28
31
  @SuppressLint("NewApi")
29
32
  class BlurVibeView(context: Context) : FrameLayout(context) {
@@ -31,7 +34,7 @@ class BlurVibeView(context: Context) : FrameLayout(context) {
31
34
  private val overlayView = View(context)
32
35
  private var blurAmountValue: Float = 10f
33
36
  private var overlayColorValue: Int = Color.TRANSPARENT
34
- private var reducedTransparencyFallbackColorValue: Int = Color.parseColor("#F2F2F2")
37
+ private var fallbackColorValue: Int = Color.parseColor("#F2F2F2")
35
38
  private var blurRadiusDownscale: Int = 4
36
39
 
37
40
  init {
@@ -43,18 +46,20 @@ class BlurVibeView(context: Context) : FrameLayout(context) {
43
46
  applyBlur()
44
47
  }
45
48
 
49
+ // MARK: - Public setters (called by ViewManager)
50
+
46
51
  fun setBlurAmount(amount: Float) {
47
52
  blurAmountValue = amount.coerceIn(0f, 100f)
48
53
  applyBlur()
49
54
  }
50
55
 
51
- fun setOverlayColor(color: Int) {
52
- overlayColorValue = color
56
+ fun setOverlayColor(colorString: String) {
57
+ overlayColorValue = parseHexColor(colorString) ?: Color.TRANSPARENT
53
58
  updateOverlay()
54
59
  }
55
60
 
56
- fun setReducedTransparencyFallbackColor(color: Int) {
57
- reducedTransparencyFallbackColorValue = color
61
+ fun setReducedTransparencyFallbackColor(colorString: String) {
62
+ fallbackColorValue = parseHexColor(colorString) ?: Color.parseColor("#F2F2F2")
58
63
  }
59
64
 
60
65
  fun setBlurRadius(radius: Int) {
@@ -62,6 +67,8 @@ class BlurVibeView(context: Context) : FrameLayout(context) {
62
67
  applyBlur()
63
68
  }
64
69
 
70
+ // MARK: - Blur
71
+
65
72
  private fun applyBlur() {
66
73
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
67
74
  applyRenderEffect()
@@ -106,10 +113,12 @@ class BlurVibeView(context: Context) : FrameLayout(context) {
106
113
 
107
114
  background = android.graphics.drawable.BitmapDrawable(resources, bitmap)
108
115
  } catch (e: Exception) {
109
- setBackgroundColor(reducedTransparencyFallbackColorValue)
116
+ setBackgroundColor(fallbackColorValue)
110
117
  }
111
118
  }
112
119
 
120
+ // MARK: - Overlay
121
+
113
122
  private fun updateOverlay() {
114
123
  overlayView.setBackgroundColor(overlayColorValue)
115
124
  bringChildToFront(overlayView)
@@ -125,4 +134,41 @@ class BlurVibeView(context: Context) : FrameLayout(context) {
125
134
  post { renderScriptBlur() }
126
135
  }
127
136
  }
137
+
138
+ // MARK: - Color parser
139
+ // Supports: "transparent", "#RGB", "#RRGGBB", "#RRGGBBAA"
140
+ // Returns null if unparseable (caller uses fallback)
141
+ private fun parseHexColor(colorString: String): Int? {
142
+ val s = colorString.trim()
143
+ if (s.equals("transparent", ignoreCase = true)) return Color.TRANSPARENT
144
+ if (!s.startsWith("#")) return null
145
+
146
+ val hex = s.removePrefix("#")
147
+ return try {
148
+ when (hex.length) {
149
+ 3 -> { // #RGB → #RRGGBB
150
+ val r = hex[0].toString().repeat(2).toInt(16)
151
+ val g = hex[1].toString().repeat(2).toInt(16)
152
+ val b = hex[2].toString().repeat(2).toInt(16)
153
+ Color.argb(255, r, g, b)
154
+ }
155
+ 6 -> { // #RRGGBB
156
+ val r = hex.substring(0, 2).toInt(16)
157
+ val g = hex.substring(2, 4).toInt(16)
158
+ val b = hex.substring(4, 6).toInt(16)
159
+ Color.argb(255, r, g, b)
160
+ }
161
+ 8 -> { // #RRGGBBAA — note: AA is alpha, last two digits
162
+ val r = hex.substring(0, 2).toInt(16)
163
+ val g = hex.substring(2, 4).toInt(16)
164
+ val b = hex.substring(4, 6).toInt(16)
165
+ val a = hex.substring(6, 8).toInt(16)
166
+ Color.argb(a, r, g, b)
167
+ }
168
+ else -> null
169
+ }
170
+ } catch (e: NumberFormatException) {
171
+ null
172
+ }
173
+ }
128
174
  }
@@ -10,26 +10,33 @@ class BlurVibeViewManager : SimpleViewManager<BlurVibeView>() {
10
10
 
11
11
  override fun createViewInstance(context: ThemedReactContext) = BlurVibeView(context)
12
12
 
13
+ // Float — matches TS codegen Float type ✅
13
14
  @ReactProp(name = "blurAmount", defaultFloat = 10f)
14
15
  fun setBlurAmount(view: BlurVibeView, amount: Float) {
15
16
  view.setBlurAmount(amount)
16
17
  }
17
18
 
19
+ // String — matches TS codegen string type ✅ (no-op on Android)
18
20
  @ReactProp(name = "blurType")
19
21
  fun setBlurType(view: BlurVibeView, type: String?) {
20
22
  // No-op on Android — blurType is iOS UIBlurEffectStyle only
21
23
  }
22
24
 
25
+ // String — matches TS codegen string type ✅
26
+ // We parse hex manually in BlurVibeView for full alpha control
27
+ // Do NOT use Int with customType="Color" — RN reorders alpha bytes unexpectedly
23
28
  @ReactProp(name = "overlayColor")
24
- fun setOverlayColor(view: BlurVibeView, color: Int) {
25
- view.setOverlayColor(color)
29
+ fun setOverlayColor(view: BlurVibeView, color: String?) {
30
+ view.setOverlayColor(color ?: "transparent")
26
31
  }
27
32
 
33
+ // String — matches TS codegen string type ✅
28
34
  @ReactProp(name = "reducedTransparencyFallbackColor")
29
- fun setReducedTransparencyFallbackColor(view: BlurVibeView, color: Int) {
30
- view.setReducedTransparencyFallbackColor(color)
35
+ fun setReducedTransparencyFallbackColor(view: BlurVibeView, color: String?) {
36
+ view.setReducedTransparencyFallbackColor(color ?: "#F2F2F2")
31
37
  }
32
38
 
39
+ // Int32 — matches TS codegen Int32 type ✅
33
40
  @ReactProp(name = "blurRadius", defaultInt = 4)
34
41
  fun setBlurRadius(view: BlurVibeView, radius: Int) {
35
42
  view.setBlurRadius(radius)
@@ -7,18 +7,25 @@ class BlurVibeView: UIView {
7
7
  private var blurEffectView: UIVisualEffectView?
8
8
  private let overlayView = UIView()
9
9
 
10
- // MARK: - Properties
10
+ // MARK: - Props
11
11
 
12
+ /// Blur intensity 0–100. Maps to UIBlurEffect intensity via animator.
12
13
  @objc var blurAmount: NSNumber = 10 { didSet { updateBlur() } }
14
+
15
+ /// iOS blur style — maps to UIBlurEffectStyle
13
16
  @objc var blurType: NSString = "light" { didSet { updateBlur() } }
14
17
 
15
- /// Overlay color ON TOP of blur layer — works on iOS AND Android.
16
- /// Alpha channel controls visibility, just like CSS:
17
- /// backdrop-filter: blur(Xpx) + background-color: overlayColor
18
- /// "#00000000" = pure blur, "#00000080" = tinted blur, "#000000FF" = hidden blur
18
+ /// Overlay color on top of blur. Works on iOS AND Android.
19
+ /// Alpha controls blur visibility like CSS backdrop-filter + background-color.
20
+ /// Supports: "transparent", "#RGB", "#RRGGBB", "#RRGGBBAA"
19
21
  @objc var overlayColor: NSString = "transparent" { didSet { updateOverlay() } }
22
+
23
+ /// Fallback color when Reduce Transparency is enabled.
20
24
  @objc var reducedTransparencyFallbackColor: NSString = "#F2F2F2" { didSet { updateBlur() } }
21
25
 
26
+ /// Android-only downscale factor. Accepted on iOS to avoid prop warning — no-op.
27
+ @objc var blurRadius: NSNumber = 4
28
+
22
29
  // MARK: - Init
23
30
  override init(frame: CGRect) { super.init(frame: frame); commonInit() }
24
31
  required init?(coder: NSCoder) { super.init(coder: coder); commonInit() }
@@ -47,7 +54,8 @@ class BlurVibeView: UIView {
47
54
  if UIAccessibility.isReduceTransparencyEnabled {
48
55
  blurEffectView?.removeFromSuperview()
49
56
  blurEffectView = nil
50
- backgroundColor = parseColor(reducedTransparencyFallbackColor as String) ?? UIColor(white: 0.95, alpha: 1)
57
+ backgroundColor = parseColor(reducedTransparencyFallbackColor as String)
58
+ ?? UIColor(white: 0.95, alpha: 1)
51
59
  return
52
60
  }
53
61
  backgroundColor = .clear
@@ -102,7 +110,8 @@ class BlurVibeView: UIView {
102
110
  }
103
111
  }
104
112
 
105
- // MARK: - Color Parser — supports #RGB, #RRGGBB, #RRGGBBAA
113
+ // MARK: - Color Parser
114
+ // Supports: "transparent", "#RGB", "#RRGGBB", "#RRGGBBAA"
106
115
  private func parseColor(_ colorString: String) -> UIColor? {
107
116
  var hex = colorString.trimmingCharacters(in: .whitespacesAndNewlines)
108
117
  guard hex.hasPrefix("#") else { return nil }
@@ -110,23 +119,26 @@ class BlurVibeView: UIView {
110
119
  var rgbValue: UInt64 = 0
111
120
  Scanner(string: hex).scanHexInt64(&rgbValue)
112
121
  switch hex.count {
113
- case 3:
122
+ case 3: // #RGB
114
123
  return UIColor(
115
- red: CGFloat((rgbValue & 0xF00) >> 8) / 15,
124
+ red: CGFloat((rgbValue & 0xF00) >> 8) / 15,
116
125
  green: CGFloat((rgbValue & 0x0F0) >> 4) / 15,
117
- blue: CGFloat(rgbValue & 0x00F) / 15, alpha: 1)
118
- case 6:
126
+ blue: CGFloat( rgbValue & 0x00F ) / 15,
127
+ alpha: 1)
128
+ case 6: // #RRGGBB
119
129
  return UIColor(
120
- red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255,
121
- green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255,
122
- blue: CGFloat(rgbValue & 0x0000FF) / 255, alpha: 1)
130
+ red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255,
131
+ green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255,
132
+ blue: CGFloat( rgbValue & 0x0000FF ) / 255,
133
+ alpha: 1)
123
134
  case 8: // #RRGGBBAA
124
135
  return UIColor(
125
- red: CGFloat((rgbValue & 0xFF000000) >> 24) / 255,
136
+ red: CGFloat((rgbValue & 0xFF000000) >> 24) / 255,
126
137
  green: CGFloat((rgbValue & 0x00FF0000) >> 16) / 255,
127
- blue: CGFloat((rgbValue & 0x0000FF00) >> 8) / 255,
128
- alpha: CGFloat(rgbValue & 0x000000FF) / 255)
129
- default: return nil
138
+ blue: CGFloat((rgbValue & 0x0000FF00) >> 8) / 255,
139
+ alpha: CGFloat( rgbValue & 0x000000FF ) / 255)
140
+ default:
141
+ return nil
130
142
  }
131
143
  }
132
144
  }
@@ -6,4 +6,5 @@ RCT_EXTERN_MODULE(BlurVibeViewManager, RCTViewManager)
6
6
  RCT_EXPORT_VIEW_PROPERTY(blurAmount, NSNumber)
7
7
  RCT_EXPORT_VIEW_PROPERTY(blurType, NSString)
8
8
  RCT_EXPORT_VIEW_PROPERTY(overlayColor, NSString)
9
- RCT_EXPORT_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString)
9
+ RCT_EXPORT_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString)
10
+ RCT_EXPORT_VIEW_PROPERTY(blurRadius, NSNumber)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-blur-vibe",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "React Native package implementing Blur View in iOS and Android",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/module/index.js",