react-native-blur-vibe 0.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 (52) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +232 -0
  3. package/android/build.gradle +68 -0
  4. package/android/src/main/AndroidManifest.xml +2 -0
  5. package/android/src/main/java/com/blurvibe/BlurVibePackage.kt +12 -0
  6. package/android/src/main/java/com/blurvibe/BlurVibeView.kt +128 -0
  7. package/android/src/main/java/com/blurvibe/BlurVibeViewManager.kt +37 -0
  8. package/ios/BlurVibeView.m +3 -0
  9. package/ios/BlurVibeView.swift +132 -0
  10. package/ios/BlurVibeViewManager.m +9 -0
  11. package/ios/BlurVibeViewManager.swift +17 -0
  12. package/ios/react-native-blur-vibe.podspec +21 -0
  13. package/lib/commonjs/BlurVibeViewNativeComponent.ts +17 -0
  14. package/lib/commonjs/BlurView.js +56 -0
  15. package/lib/commonjs/BlurView.js.map +1 -0
  16. package/lib/commonjs/index.js +14 -0
  17. package/lib/commonjs/index.js.map +1 -0
  18. package/lib/commonjs/package.json +1 -0
  19. package/lib/commonjs/types.js +6 -0
  20. package/lib/commonjs/types.js.map +1 -0
  21. package/lib/module/BlurVibeViewNativeComponent.ts +17 -0
  22. package/lib/module/BlurView.js +53 -0
  23. package/lib/module/BlurView.js.map +1 -0
  24. package/lib/module/index.js +4 -0
  25. package/lib/module/index.js.map +1 -0
  26. package/lib/module/package.json +1 -0
  27. package/lib/module/types.js +4 -0
  28. package/lib/module/types.js.map +1 -0
  29. package/lib/typescript/commonjs/package.json +1 -0
  30. package/lib/typescript/commonjs/src/BlurVibeViewNativeComponent.d.ts +12 -0
  31. package/lib/typescript/commonjs/src/BlurVibeViewNativeComponent.d.ts.map +1 -0
  32. package/lib/typescript/commonjs/src/BlurView.d.ts +24 -0
  33. package/lib/typescript/commonjs/src/BlurView.d.ts.map +1 -0
  34. package/lib/typescript/commonjs/src/index.d.ts +3 -0
  35. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  36. package/lib/typescript/commonjs/src/types.d.ts +40 -0
  37. package/lib/typescript/commonjs/src/types.d.ts.map +1 -0
  38. package/lib/typescript/module/package.json +1 -0
  39. package/lib/typescript/module/src/BlurVibeViewNativeComponent.d.ts +12 -0
  40. package/lib/typescript/module/src/BlurVibeViewNativeComponent.d.ts.map +1 -0
  41. package/lib/typescript/module/src/BlurView.d.ts +24 -0
  42. package/lib/typescript/module/src/BlurView.d.ts.map +1 -0
  43. package/lib/typescript/module/src/index.d.ts +3 -0
  44. package/lib/typescript/module/src/index.d.ts.map +1 -0
  45. package/lib/typescript/module/src/types.d.ts +40 -0
  46. package/lib/typescript/module/src/types.d.ts.map +1 -0
  47. package/package.json +155 -0
  48. package/react-native.config.js +7 -0
  49. package/src/BlurVibeViewNativeComponent.ts +17 -0
  50. package/src/BlurView.tsx +58 -0
  51. package/src/index.ts +2 -0
  52. package/src/types.ts +65 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pritam Nanda
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,232 @@
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.
4
+
5
+ > 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
+
7
+ [![npm version](https://img.shields.io/npm/v/react-native-blur-vibe)](https://www.npmjs.com/package/react-native-blur-vibe)
8
+ [![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
+ [![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)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+
12
+ ---
13
+
14
+ ## Why another blur library?
15
+
16
+ Existing libraries like `@react-native-community/blur` and `react-native-blurview` suffer from:
17
+ - Build failures with React Native 0.73+ and the New Architecture
18
+ - Android 16KB page size build errors
19
+ - `overlayColor` only working on Android, not iOS
20
+ - Unmaintained or slow to update
21
+ `react-native-blur-vibe` is built from the ground up for modern React Native, with CI builds on every commit.
22
+
23
+ ---
24
+
25
+ ## The overlayColor concept
26
+
27
+ Think of it exactly like CSS:
28
+
29
+ ```css
30
+ /* Web equivalent of what this library does */
31
+ .blur-view {
32
+ backdrop-filter: blur(10px); /* ← blurAmount */
33
+ background-color: #00000050; /* ← overlayColor */
34
+ }
35
+ ```
36
+
37
+ The `overlayColor` alpha channel is what controls blur visibility:
38
+
39
+ | `overlayColor` | Result |
40
+ |-----------------|---------------------------------------------|
41
+ | `#00000000` | Fully transparent → pure blur shows through |
42
+ | `#00000080` | Semi-transparent black tint over blur |
43
+ | `#FFFFFFFF` | Fully opaque white → blur completely hidden |
44
+ | `#FFFFFF30` | Frosted glass / white tint effect |
45
+
46
+ **This works on both iOS and Android.** Not just Android like other libraries.
47
+
48
+ ---
49
+
50
+ ## Installation
51
+
52
+ ```sh
53
+ yarn add react-native-blur-vibe
54
+ # or
55
+ npm install react-native-blur-vibe
56
+ ```
57
+
58
+ ### iOS
59
+
60
+ ```sh
61
+ cd ios && pod install
62
+ ```
63
+
64
+ Minimum iOS version: **13.0**
65
+
66
+ ### Android
67
+
68
+ No extra steps needed. Minimum SDK: **21**
69
+
70
+ - API 31+ (Android 12): Uses `RenderEffect` — hardware accelerated
71
+ - API 21-30: Uses `RenderScript` — bitmap-based fallback
72
+ ---
73
+
74
+ ## Usage
75
+
76
+ ```tsx
77
+ import { BlurView } from 'react-native-blur-vibe';
78
+ import { StyleSheet, ImageBackground, Text } from 'react-native';
79
+
80
+ export default function App() {
81
+ return (
82
+ <ImageBackground source={require('./background.jpg')} style={styles.image}>
83
+ {/* Pure blur — transparent overlay */}
84
+ <BlurView
85
+ blurAmount={15}
86
+ blurType="systemMaterial"
87
+ overlayColor="#00000000"
88
+ style={styles.blur}
89
+ />
90
+
91
+ {/* Dark tinted blur — like a modal backdrop */}
92
+ <BlurView
93
+ blurAmount={20}
94
+ overlayColor="#00000060"
95
+ style={styles.blur}
96
+ />
97
+
98
+ {/* Frosted glass card */}
99
+ <BlurView
100
+ blurAmount={10}
101
+ blurType="systemUltraThinMaterialLight"
102
+ overlayColor="#FFFFFF25"
103
+ style={styles.card}
104
+ >
105
+ <Text style={styles.text}>Frosted Glass Card</Text>
106
+ </BlurView>
107
+ </ImageBackground>
108
+ );
109
+ }
110
+
111
+ const styles = StyleSheet.create({
112
+ image: { flex: 1 },
113
+ blur: { ...StyleSheet.absoluteFillObject },
114
+ card: {
115
+ margin: 20,
116
+ padding: 20,
117
+ borderRadius: 16,
118
+ },
119
+ text: { color: 'white', fontSize: 18 },
120
+ });
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Props
126
+
127
+ | Prop | Type | Default | Platform | Description |
128
+ |------|------|---------|----------|-------------|
129
+ | `blurAmount` | `number` (0–100) | `10` | iOS, Android | Blur intensity |
130
+ | `blurType` | `BlurType` | `'light'` | iOS | Maps to `UIBlurEffectStyle` |
131
+ | `overlayColor` | `string` (hex) | `'transparent'` on iOS, `'#00000030'` on Android | **iOS & Android** | Color composited on top of blur. Alpha controls blur visibility |
132
+ | `reducedTransparencyFallbackColor` | `string` (hex) | `'#F2F2F2'` | iOS, Android | Shown when blur is unavailable (Reduce Transparency enabled, API < 18) |
133
+ | `blurRadius` | `number` (1–8) | `4` | Android | Downscale factor for RenderScript path. Higher = faster, slightly softer |
134
+
135
+ All standard `ViewProps` (style, children, onLayout, etc.) are also supported.
136
+
137
+ ---
138
+
139
+ ## BlurType values (iOS)
140
+
141
+ ```
142
+ light · dark · extraLight · regular · prominent
143
+ systemUltraThinMaterial · systemThinMaterial · systemMaterial
144
+ systemThickMaterial · systemChromeMaterial
145
+ systemUltraThinMaterialLight · systemThinMaterialLight · systemMaterialLight
146
+ systemThickMaterialLight · systemChromeMaterialLight
147
+ systemUltraThinMaterialDark · systemThinMaterialDark · systemMaterialDark
148
+ systemThickMaterialDark · systemChromeMaterialDark
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Recipes
154
+
155
+ ### Modal backdrop (dark blur)
156
+ ```tsx
157
+ <BlurView
158
+ blurAmount={25}
159
+ overlayColor="#00000070"
160
+ style={StyleSheet.absoluteFill}
161
+ />
162
+ ```
163
+
164
+ ### Frosted glass navbar
165
+ ```tsx
166
+ <BlurView
167
+ blurAmount={12}
168
+ blurType="systemChromeMaterial"
169
+ overlayColor="#FFFFFF20"
170
+ style={styles.navbar}
171
+ />
172
+ ```
173
+
174
+ ### Light frosted card
175
+ ```tsx
176
+ <BlurView
177
+ blurAmount={8}
178
+ blurType="systemUltraThinMaterialLight"
179
+ overlayColor="#FFFFFF30"
180
+ style={{ borderRadius: 12, padding: 16 }}
181
+ >
182
+ {children}
183
+ </BlurView>
184
+ ```
185
+
186
+ ### Completely invisible overlay (just blur, no tint)
187
+ ```tsx
188
+ <BlurView
189
+ blurAmount={15}
190
+ overlayColor="#00000000"
191
+ style={StyleSheet.absoluteFill}
192
+ />
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Architecture support
198
+
199
+ | Architecture | iOS | Android |
200
+ |---|---|---|
201
+ | Old Architecture (JSC/Bridge) | ✅ | ✅ |
202
+ | New Architecture (Fabric/JSI) | ✅ | ✅ |
203
+ | Expo (bare workflow) | ✅ | ✅ |
204
+ | Expo Go | ❌ (native module) | ❌ |
205
+
206
+ ---
207
+
208
+ ## Android API compatibility
209
+
210
+ | Android API | Blur Method | Notes |
211
+ |---|---|---|
212
+ | 31+ (Android 12) | `RenderEffect` | Hardware accelerated, best quality |
213
+ | 21–30 | `RenderScript` | Bitmap-based, `blurRadius` tunable |
214
+ | < 21 | `reducedTransparencyFallbackColor` | Solid color only |
215
+
216
+ ---
217
+
218
+ ## Contributing
219
+
220
+ **See [CONTRIBUTING.md](./CONTRIBUTING.md).**
221
+
222
+ - [Development workflow](CONTRIBUTING.md#development-workflow)
223
+ - [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
224
+ - [Code of conduct](CODE_OF_CONDUCT.md)
225
+
226
+ ## License
227
+
228
+ MIT © [Pritam Nanda](https://github.com/I-am-Pritam-20)
229
+
230
+ ---
231
+
232
+ Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
@@ -0,0 +1,68 @@
1
+ buildscript {
2
+ ext.BlurVibe = [
3
+ kotlinVersion: "2.0.21",
4
+ minSdkVersion: 24,
5
+ compileSdkVersion: 36,
6
+ targetSdkVersion: 36
7
+ ]
8
+
9
+ ext.getExtOrDefault = { prop ->
10
+ if (rootProject.ext.has(prop)) {
11
+ return rootProject.ext.get(prop)
12
+ }
13
+ return BlurVibe[prop]
14
+ }
15
+
16
+ repositories {
17
+ google()
18
+ mavenCentral()
19
+ }
20
+
21
+ dependencies {
22
+ classpath "com.android.tools.build:gradle:8.7.2"
23
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
24
+ }
25
+ }
26
+
27
+ apply plugin: "com.android.library"
28
+ apply plugin: "kotlin-android"
29
+ apply plugin: "com.facebook.react"
30
+
31
+ android {
32
+ namespace "com.blurvibe"
33
+
34
+ compileSdkVersion getExtOrDefault("compileSdkVersion")
35
+
36
+ defaultConfig {
37
+ minSdkVersion getExtOrDefault("minSdkVersion")
38
+ targetSdkVersion getExtOrDefault("targetSdkVersion")
39
+ }
40
+
41
+ buildFeatures {
42
+ buildConfig true
43
+ }
44
+
45
+ buildTypes {
46
+ release {
47
+ minifyEnabled false
48
+ }
49
+ }
50
+
51
+ lint {
52
+ disable "GradleCompatible"
53
+ }
54
+
55
+ compileOptions {
56
+ sourceCompatibility JavaVersion.VERSION_17
57
+ targetCompatibility JavaVersion.VERSION_17
58
+ }
59
+
60
+ kotlinOptions {
61
+ jvmTarget = "17"
62
+ freeCompilerArgs += ["-nowarn"]
63
+ }
64
+ }
65
+
66
+ dependencies {
67
+ implementation "com.facebook.react:react-android"
68
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,12 @@
1
+ package com.blurvibe
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class BlurVibePackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> = emptyList()
10
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
11
+ listOf(BlurVibeViewManager())
12
+ }
@@ -0,0 +1,128 @@
1
+ package com.blurvibe
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.graphics.Bitmap
6
+ import android.graphics.Canvas
7
+ import android.graphics.Color
8
+ import android.graphics.RenderEffect
9
+ import android.graphics.Shader
10
+ import android.os.Build
11
+ import android.renderscript.Allocation
12
+ import android.renderscript.Element
13
+ import android.renderscript.RenderScript
14
+ import android.renderscript.ScriptIntrinsicBlur
15
+ import android.view.View
16
+ import android.view.ViewGroup
17
+ import android.widget.FrameLayout
18
+
19
+ /**
20
+ * BlurVibeView — Android implementation
21
+ *
22
+ * API 31+ : RenderEffect (hardware accelerated)
23
+ * API 24-30: RenderScript (built into Android SDK, no extra dep needed)
24
+ *
25
+ * overlayColor sits on top of blur — like CSS:
26
+ * backdrop-filter: blur(Xpx) + background-color: overlayColor
27
+ */
28
+ @SuppressLint("NewApi")
29
+ class BlurVibeView(context: Context) : FrameLayout(context) {
30
+
31
+ private val overlayView = View(context)
32
+ private var blurAmountValue: Float = 10f
33
+ private var overlayColorValue: Int = Color.TRANSPARENT
34
+ private var reducedTransparencyFallbackColorValue: Int = Color.parseColor("#F2F2F2")
35
+ private var blurRadiusDownscale: Int = 4
36
+
37
+ init {
38
+ setWillNotDraw(false)
39
+ overlayView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
40
+ overlayView.isClickable = false
41
+ overlayView.isFocusable = false
42
+ addView(overlayView)
43
+ applyBlur()
44
+ }
45
+
46
+ fun setBlurAmount(amount: Float) {
47
+ blurAmountValue = amount.coerceIn(0f, 100f)
48
+ applyBlur()
49
+ }
50
+
51
+ fun setOverlayColor(color: Int) {
52
+ overlayColorValue = color
53
+ updateOverlay()
54
+ }
55
+
56
+ fun setReducedTransparencyFallbackColor(color: Int) {
57
+ reducedTransparencyFallbackColorValue = color
58
+ }
59
+
60
+ fun setBlurRadius(radius: Int) {
61
+ blurRadiusDownscale = radius.coerceIn(1, 8)
62
+ applyBlur()
63
+ }
64
+
65
+ private fun applyBlur() {
66
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
67
+ applyRenderEffect()
68
+ } else {
69
+ post { renderScriptBlur() }
70
+ }
71
+ updateOverlay()
72
+ }
73
+
74
+ private fun applyRenderEffect() {
75
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
76
+ val sigma = (blurAmountValue * 0.5f).coerceAtLeast(0.01f)
77
+ setRenderEffect(
78
+ RenderEffect.createBlurEffect(sigma, sigma, Shader.TileMode.MIRROR)
79
+ )
80
+ }
81
+ }
82
+
83
+ @Suppress("DEPRECATION")
84
+ private fun renderScriptBlur() {
85
+ val parentView = parent as? ViewGroup ?: return
86
+ if (width <= 0 || height <= 0) return
87
+ try {
88
+ val scaledW = (width / blurRadiusDownscale).coerceAtLeast(1)
89
+ val scaledH = (height / blurRadiusDownscale).coerceAtLeast(1)
90
+ val bitmap = Bitmap.createBitmap(scaledW, scaledH, Bitmap.Config.ARGB_8888)
91
+ val canvas = Canvas(bitmap)
92
+ canvas.scale(1f / blurRadiusDownscale, 1f / blurRadiusDownscale)
93
+ canvas.translate(-left.toFloat(), -top.toFloat())
94
+ parentView.draw(canvas)
95
+
96
+ val rs = RenderScript.create(context)
97
+ val input = Allocation.createFromBitmap(rs, bitmap)
98
+ val output = Allocation.createTyped(rs, input.type)
99
+ val script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
100
+ val sigma = (blurAmountValue / 100f * 25f).coerceIn(1f, 25f)
101
+ script.setRadius(sigma)
102
+ script.setInput(input)
103
+ script.forEach(output)
104
+ output.copyTo(bitmap)
105
+ rs.destroy()
106
+
107
+ background = android.graphics.drawable.BitmapDrawable(resources, bitmap)
108
+ } catch (e: Exception) {
109
+ setBackgroundColor(reducedTransparencyFallbackColorValue)
110
+ }
111
+ }
112
+
113
+ private fun updateOverlay() {
114
+ overlayView.setBackgroundColor(overlayColorValue)
115
+ bringChildToFront(overlayView)
116
+ for (i in 0 until childCount) {
117
+ val child = getChildAt(i)
118
+ if (child !== overlayView) bringChildToFront(child)
119
+ }
120
+ }
121
+
122
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
123
+ super.onLayout(changed, l, t, r, b)
124
+ if (changed && Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
125
+ post { renderScriptBlur() }
126
+ }
127
+ }
128
+ }
@@ -0,0 +1,37 @@
1
+ package com.blurvibe
2
+
3
+ import com.facebook.react.uimanager.SimpleViewManager
4
+ import com.facebook.react.uimanager.ThemedReactContext
5
+ import com.facebook.react.uimanager.annotations.ReactProp
6
+
7
+ class BlurVibeViewManager : SimpleViewManager<BlurVibeView>() {
8
+
9
+ override fun getName() = "BlurVibeView"
10
+
11
+ override fun createViewInstance(context: ThemedReactContext) = BlurVibeView(context)
12
+
13
+ @ReactProp(name = "blurAmount", defaultFloat = 10f)
14
+ fun setBlurAmount(view: BlurVibeView, amount: Float) {
15
+ view.setBlurAmount(amount)
16
+ }
17
+
18
+ @ReactProp(name = "blurType")
19
+ fun setBlurType(view: BlurVibeView, type: String?) {
20
+ // No-op on Android — blurType is iOS UIBlurEffectStyle only
21
+ }
22
+
23
+ @ReactProp(name = "overlayColor")
24
+ fun setOverlayColor(view: BlurVibeView, color: Int) {
25
+ view.setOverlayColor(color)
26
+ }
27
+
28
+ @ReactProp(name = "reducedTransparencyFallbackColor")
29
+ fun setReducedTransparencyFallbackColor(view: BlurVibeView, color: Int) {
30
+ view.setReducedTransparencyFallbackColor(color)
31
+ }
32
+
33
+ @ReactProp(name = "blurRadius", defaultInt = 4)
34
+ fun setBlurRadius(view: BlurVibeView, radius: Int) {
35
+ view.setBlurRadius(radius)
36
+ }
37
+ }
@@ -0,0 +1,3 @@
1
+ // BlurVibeView.m
2
+ // Required for Swift-ObjC interop. All logic is in BlurVibeView.swift
3
+ #import <UIKit/UIKit.h>
@@ -0,0 +1,132 @@
1
+ import UIKit
2
+
3
+ @objc(BlurVibeView)
4
+ class BlurVibeView: UIView {
5
+
6
+ // MARK: - Private Views
7
+ private var blurEffectView: UIVisualEffectView?
8
+ private let overlayView = UIView()
9
+
10
+ // MARK: - Properties
11
+
12
+ @objc var blurAmount: NSNumber = 10 { didSet { updateBlur() } }
13
+ @objc var blurType: NSString = "light" { didSet { updateBlur() } }
14
+
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
19
+ @objc var overlayColor: NSString = "transparent" { didSet { updateOverlay() } }
20
+ @objc var reducedTransparencyFallbackColor: NSString = "#F2F2F2" { didSet { updateBlur() } }
21
+
22
+ // MARK: - Init
23
+ override init(frame: CGRect) { super.init(frame: frame); commonInit() }
24
+ required init?(coder: NSCoder) { super.init(coder: coder); commonInit() }
25
+
26
+ private func commonInit() {
27
+ backgroundColor = .clear
28
+ clipsToBounds = true
29
+ overlayView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
30
+ overlayView.isUserInteractionEnabled = false
31
+ updateBlur()
32
+ }
33
+
34
+ // MARK: - Layout
35
+ override func layoutSubviews() {
36
+ super.layoutSubviews()
37
+ blurEffectView?.frame = bounds
38
+ overlayView.frame = bounds
39
+ bringSubviewToFront(overlayView)
40
+ for subview in subviews where subview !== blurEffectView && subview !== overlayView {
41
+ bringSubviewToFront(subview)
42
+ }
43
+ }
44
+
45
+ // MARK: - Blur
46
+ private func updateBlur() {
47
+ if UIAccessibility.isReduceTransparencyEnabled {
48
+ blurEffectView?.removeFromSuperview()
49
+ blurEffectView = nil
50
+ backgroundColor = parseColor(reducedTransparencyFallbackColor as String) ?? UIColor(white: 0.95, alpha: 1)
51
+ return
52
+ }
53
+ backgroundColor = .clear
54
+ let effect = UIBlurEffect(style: blurEffectStyle(for: blurType as String))
55
+ if let existing = blurEffectView {
56
+ existing.effect = effect
57
+ } else {
58
+ let newBlurView = UIVisualEffectView(effect: effect)
59
+ newBlurView.frame = bounds
60
+ newBlurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
61
+ blurEffectView = newBlurView
62
+ insertSubview(newBlurView, at: 0)
63
+ }
64
+ if overlayView.superview == nil {
65
+ insertSubview(overlayView, aboveSubview: blurEffectView!)
66
+ }
67
+ updateOverlay()
68
+ }
69
+
70
+ private func updateOverlay() {
71
+ let colorString = overlayColor as String
72
+ if colorString.lowercased() == "transparent" {
73
+ overlayView.backgroundColor = .clear
74
+ } else {
75
+ overlayView.backgroundColor = parseColor(colorString) ?? .clear
76
+ }
77
+ }
78
+
79
+ // MARK: - Blur Style Map
80
+ private func blurEffectStyle(for type: String) -> UIBlurEffect.Style {
81
+ switch type {
82
+ case "dark": return .dark
83
+ case "extraLight": return .extraLight
84
+ case "regular": return .regular
85
+ case "prominent": return .prominent
86
+ case "systemUltraThinMaterial": return .systemUltraThinMaterial
87
+ case "systemThinMaterial": return .systemThinMaterial
88
+ case "systemThickMaterial": return .systemThickMaterial
89
+ case "systemChromeMaterial": return .systemChromeMaterial
90
+ case "systemUltraThinMaterialLight": return .systemUltraThinMaterialLight
91
+ case "systemThinMaterialLight": return .systemThinMaterialLight
92
+ case "systemMaterialLight": return .systemMaterialLight
93
+ case "systemThickMaterialLight": return .systemThickMaterialLight
94
+ case "systemChromeMaterialLight": return .systemChromeMaterialLight
95
+ case "systemUltraThinMaterialDark": return .systemUltraThinMaterialDark
96
+ case "systemThinMaterialDark": return .systemThinMaterialDark
97
+ case "systemMaterialDark": return .systemMaterialDark
98
+ case "systemThickMaterialDark": return .systemThickMaterialDark
99
+ case "systemChromeMaterialDark": return .systemChromeMaterialDark
100
+ case "systemMaterial": return .systemMaterial
101
+ default: return .light
102
+ }
103
+ }
104
+
105
+ // MARK: - Color Parser — supports #RGB, #RRGGBB, #RRGGBBAA
106
+ private func parseColor(_ colorString: String) -> UIColor? {
107
+ var hex = colorString.trimmingCharacters(in: .whitespacesAndNewlines)
108
+ guard hex.hasPrefix("#") else { return nil }
109
+ hex.removeFirst()
110
+ var rgbValue: UInt64 = 0
111
+ Scanner(string: hex).scanHexInt64(&rgbValue)
112
+ switch hex.count {
113
+ case 3:
114
+ return UIColor(
115
+ red: CGFloat((rgbValue & 0xF00) >> 8) / 15,
116
+ green: CGFloat((rgbValue & 0x0F0) >> 4) / 15,
117
+ blue: CGFloat(rgbValue & 0x00F) / 15, alpha: 1)
118
+ case 6:
119
+ return UIColor(
120
+ red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255,
121
+ green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255,
122
+ blue: CGFloat(rgbValue & 0x0000FF) / 255, alpha: 1)
123
+ case 8: // #RRGGBBAA
124
+ return UIColor(
125
+ red: CGFloat((rgbValue & 0xFF000000) >> 24) / 255,
126
+ green: CGFloat((rgbValue & 0x00FF0000) >> 16) / 255,
127
+ blue: CGFloat((rgbValue & 0x0000FF00) >> 8) / 255,
128
+ alpha: CGFloat(rgbValue & 0x000000FF) / 255)
129
+ default: return nil
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,9 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import <React/RCTUIManager.h>
3
+
4
+ RCT_EXTERN_MODULE(BlurVibeViewManager, RCTViewManager)
5
+
6
+ RCT_EXPORT_VIEW_PROPERTY(blurAmount, NSNumber)
7
+ RCT_EXPORT_VIEW_PROPERTY(blurType, NSString)
8
+ RCT_EXPORT_VIEW_PROPERTY(overlayColor, NSString)
9
+ RCT_EXPORT_VIEW_PROPERTY(reducedTransparencyFallbackColor, NSString)
@@ -0,0 +1,17 @@
1
+ import Foundation
2
+
3
+ @objc(BlurVibeViewManager)
4
+ class BlurVibeViewManager: RCTViewManager {
5
+
6
+ override func view() -> UIView! {
7
+ return BlurVibeView()
8
+ }
9
+
10
+ override static func requiresMainQueueSetup() -> Bool {
11
+ return true
12
+ }
13
+
14
+ @objc override func constantsToExport() -> [AnyHashable: Any]! {
15
+ return [:]
16
+ }
17
+ }
@@ -0,0 +1,21 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "..", "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "react-native-blur-vibe"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+ s.platforms = { :ios => "13.0" }
13
+ s.source = { :git => "https://github.com/I-am-Pritam-20/react-native-blur-vibe.git", :tag => "#{s.version}" }
14
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
15
+ s.requires_arc = true
16
+
17
+ s.dependency "React-Core"
18
+
19
+ # New Architecture (Fabric) support
20
+ install_modules_dependencies(s)
21
+ end