@k-workspace/react-native-liquidglass-view 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.
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # @k-workspace/react-native-liquidglass-view
2
+
3
+ iOS 26 Liquid Glass effect for React Native. Wraps Apple's native `UIGlassEffect` with configurable styles, shadows, press animations, entrance transitions, and glass container merging.
4
+
5
+ > **iOS 26+ only.** On older iOS versions and Android, a translucent fallback view is rendered automatically.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @k-workspace/react-native-liquidglass-view
11
+ ```
12
+
13
+ Then install the native iOS dependency:
14
+
15
+ ```bash
16
+ cd ios && pod install
17
+ ```
18
+
19
+ ## Requirements
20
+
21
+ | Requirement | Version |
22
+ | -------------- | ----------------------- |
23
+ | React Native | >= 0.73 |
24
+ | iOS Deployment | >= 15.1 |
25
+ | Xcode | 26+ (for UIGlassEffect) |
26
+ | Swift | 5.0+ |
27
+
28
+ ## Usage
29
+
30
+ ### GlassCard
31
+
32
+ An opinionated card component with sensible defaults — the easiest way to add glass surfaces.
33
+
34
+ ```tsx
35
+ import { GlassCard } from "@k-workspace/react-native-liquidglass-view";
36
+
37
+ <GlassCard cornerRadius={20} effect="clear">
38
+ <Text>Hello, Glass</Text>
39
+ </GlassCard>;
40
+ ```
41
+
42
+ ### GlassView
43
+
44
+ A lower-level component exposing every native prop for full control.
45
+
46
+ ```tsx
47
+ import { GlassView } from "@k-workspace/react-native-liquidglass-view";
48
+
49
+ <GlassView
50
+ style={{ width: 300, height: 200 }}
51
+ effect="regular"
52
+ cornerRadius={24}
53
+ tintColor="rgba(100, 120, 255, 0.15)"
54
+ colorScheme="dark"
55
+ interactive={true}
56
+ shadowIntensity={0.2}
57
+ enablePressAnimation
58
+ enableEntrance
59
+ >
60
+ <Text>Full control</Text>
61
+ </GlassView>;
62
+ ```
63
+
64
+ ### GlassContainer
65
+
66
+ Groups child glass views so their edges merge together (uses `UIGlassContainerEffect`).
67
+
68
+ ```tsx
69
+ import {
70
+ GlassContainer,
71
+ GlassView,
72
+ } from "@k-workspace/react-native-liquidglass-view";
73
+
74
+ <GlassContainer spacing={4}>
75
+ <GlassView style={{ flex: 1 }}>
76
+ <Text>Left</Text>
77
+ </GlassView>
78
+ <GlassView style={{ flex: 1 }}>
79
+ <Text>Right</Text>
80
+ </GlassView>
81
+ </GlassContainer>;
82
+ ```
83
+
84
+ ## Props
85
+
86
+ ### LiquidGlassProps (GlassCard & GlassView)
87
+
88
+ | Prop | Type | Default | Description |
89
+ | ---------------------- | ---------------------- | ----------- | -------------------------------------------------- |
90
+ | `effect` | `'regular' \| 'clear'` | `'clear'` | Visual weight of the glass material. |
91
+ | `cornerRadius` | `number` | `16` | Corner radius with continuous (Apple-style) curve. |
92
+ | `tintColor` | `string` | `undefined` | Semi-transparent color blended over the glass. |
93
+ | `colorScheme` | `'light' \| 'dark'` | System | Override the system color scheme for this view. |
94
+ | `interactive` | `boolean` | `true` | Whether the glass responds to touch. |
95
+ | `shadowIntensity` | `number` | `0.15` | Elevation shadow opacity (0 – 1). |
96
+ | `enablePressAnimation` | `boolean` | `false` | Spring scale animation + haptic on press. |
97
+ | `enableEntrance` | `boolean` | `false` | Fade + translate-up entrance animation. |
98
+
99
+ ### LiquidGlassContainerProps (GlassContainer)
100
+
101
+ | Prop | Type | Default | Description |
102
+ | --------- | -------- | ------- | ------------------------------------------------------ |
103
+ | `spacing` | `number` | `0` | Distance at which child glass elements begin to merge. |
104
+
105
+ ## Platform Support Check
106
+
107
+ ```ts
108
+ import { isLiquidGlassSupported } from "@k-workspace/react-native-liquidglass-view";
109
+
110
+ if (isLiquidGlassSupported) {
111
+ // iOS 26+ — real glass
112
+ } else {
113
+ // Fallback rendered automatically
114
+ }
115
+ ```
116
+
117
+ ## Platform Support
118
+
119
+ | Platform | Status |
120
+ | -------- | ----------------------------------- |
121
+ | iOS 26+ | Full native `UIGlassEffect` support |
122
+ | iOS < 26 | Translucent fallback view |
123
+ | Android | In progress |
124
+
125
+ > Android native support is currently being developed. In the meantime, a translucent `<View>` fallback is rendered automatically so your layout remains intact on all platforms.
126
+
127
+ ## How It Works
128
+
129
+ - On **iOS 26+**, the native view creates a `UIVisualEffectView` backed by `UIGlassEffect` (or `UIGlassContainerEffect` for the container). It adds:
130
+ - A subtle white edge border for glass definition
131
+ - A specular top-highlight gradient simulating overhead light
132
+ - Dual-layer shadows (contact + elevation) for depth
133
+ - Optional spring press animation with haptic feedback
134
+ - Optional fade-in entrance animation
135
+
136
+ - On **older iOS** and **Android**, a styled `<View>` with translucent background, border, and shadow is rendered as a fallback.
137
+
138
+ ## License
139
+
140
+ MIT
@@ -0,0 +1,89 @@
1
+ import UIKit
2
+
3
+ @objcMembers
4
+ @objc(BNGlassContainerView)
5
+ public class BNGlassContainerView: UIView {
6
+
7
+ private var containerEffectView: UIVisualEffectView?
8
+
9
+ // MARK: - React Native Props
10
+
11
+ @objc public var spacing: CGFloat = 0 {
12
+ didSet { rebuildEffect() }
13
+ }
14
+
15
+ // MARK: - Init
16
+
17
+ public override init(frame: CGRect) {
18
+ super.init(frame: frame)
19
+ commonInit()
20
+ }
21
+
22
+ public required init?(coder: NSCoder) {
23
+ super.init(coder: coder)
24
+ commonInit()
25
+ }
26
+
27
+ private func commonInit() {
28
+ backgroundColor = .clear
29
+ clipsToBounds = false
30
+ buildEffect()
31
+ }
32
+
33
+ // MARK: - Container Effect
34
+
35
+ private func buildEffect() {
36
+ let reactChildren: [UIView] = subviews
37
+ .filter { $0 !== containerEffectView }
38
+
39
+ containerEffectView?.removeFromSuperview()
40
+ containerEffectView = nil
41
+
42
+ #if compiler(>=6.2)
43
+ if #available(iOS 26.0, *) {
44
+ guard NSClassFromString("UIGlassContainerEffect") != nil else { return }
45
+
46
+ let containerEffect = UIGlassContainerEffect()
47
+ containerEffect.spacing = spacing
48
+
49
+ let ev = UIVisualEffectView(effect: containerEffect)
50
+ ev.autoresizingMask = [.flexibleWidth, .flexibleHeight]
51
+ ev.frame = bounds
52
+ insertSubview(ev, at: 0)
53
+ containerEffectView = ev
54
+
55
+ for child in reactChildren {
56
+ insertSubview(child, aboveSubview: ev)
57
+ }
58
+ }
59
+ #endif
60
+ }
61
+
62
+ private func rebuildEffect() {
63
+ buildEffect()
64
+ }
65
+
66
+ // MARK: - Layout
67
+
68
+ public override func layoutSubviews() {
69
+ super.layoutSubviews()
70
+ containerEffectView?.frame = bounds
71
+ if let ev = containerEffectView {
72
+ sendSubviewToBack(ev)
73
+ }
74
+ }
75
+
76
+ // MARK: - React Native Subview Management
77
+
78
+ @objc public func insertReactSubview(_ subview: UIView!, at atIndex: Int) {
79
+ if let ev = containerEffectView {
80
+ insertSubview(subview, aboveSubview: ev)
81
+ } else {
82
+ insertSubview(subview, at: atIndex)
83
+ }
84
+ }
85
+
86
+ @objc public func removeReactSubview(_ subview: UIView!) {
87
+ subview?.removeFromSuperview()
88
+ }
89
+ }
@@ -0,0 +1,319 @@
1
+ import UIKit
2
+
3
+ // MARK: - Effect Style Enum
4
+
5
+ @objc public enum BNGlassEffectStyle: Int {
6
+ case regular
7
+ case clear
8
+
9
+ #if compiler(>=6.2)
10
+ @available(iOS 26.0, *)
11
+ var uiGlassStyle: UIGlassEffect.Style {
12
+ switch self {
13
+ case .regular: return .regular
14
+ case .clear: return .clear
15
+ }
16
+ }
17
+ #endif
18
+ }
19
+
20
+ // MARK: - BNGlassView
21
+
22
+ @objcMembers
23
+ @objc(BNGlassView)
24
+ public class BNGlassView: UIView {
25
+
26
+ // MARK: - Sublayers & Subviews
27
+
28
+ private var glassEffectView: UIVisualEffectView?
29
+ private var contactShadowLayer: CALayer?
30
+ private var elevationShadowLayer: CALayer?
31
+ private var specularLayer: CAGradientLayer?
32
+ private lazy var feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
33
+
34
+ // MARK: - React Native Props
35
+
36
+ @objc public var cornerRadius: CGFloat = 16 {
37
+ didSet { applyCornerRadius() }
38
+ }
39
+
40
+ @objc public var glassTintColor: UIColor? {
41
+ didSet { rebuildEffect() }
42
+ }
43
+
44
+ @objc public var effect: NSString = "regular" {
45
+ didSet { rebuildEffect() }
46
+ }
47
+
48
+ @objc public var interactive: Bool = true {
49
+ didSet { rebuildEffect() }
50
+ }
51
+
52
+ @objc public var colorScheme: NSString? {
53
+ didSet { applyColorScheme() }
54
+ }
55
+
56
+ @objc public var shadowIntensity: CGFloat = 0.15 {
57
+ didSet { updateShadows() }
58
+ }
59
+
60
+ @objc public var enablePressAnimation: Bool = false
61
+
62
+ @objc public var enableEntrance: Bool = false
63
+
64
+ // MARK: - Private State
65
+
66
+ private var isPressed = false
67
+ private var hasAnimatedEntrance = false
68
+ private var currentEffectStyle: BNGlassEffectStyle = .regular
69
+
70
+ // MARK: - Init
71
+
72
+ public override init(frame: CGRect) {
73
+ super.init(frame: frame)
74
+ commonInit()
75
+ }
76
+
77
+ public required init?(coder: NSCoder) {
78
+ super.init(coder: coder)
79
+ commonInit()
80
+ }
81
+
82
+ private func commonInit() {
83
+ backgroundColor = .clear
84
+ clipsToBounds = false
85
+ layer.cornerCurve = .continuous
86
+ setupShadowLayers()
87
+ buildEffect()
88
+ }
89
+
90
+ // MARK: - Glass Effect
91
+
92
+ private func buildEffect() {
93
+ currentEffectStyle = (effect as String) == "clear" ? .clear : .regular
94
+
95
+ let reactChildren: [UIView] = subviews
96
+ .filter { $0 !== glassEffectView }
97
+
98
+ specularLayer?.removeFromSuperlayer()
99
+ specularLayer = nil
100
+ glassEffectView?.removeFromSuperview()
101
+ glassEffectView = nil
102
+
103
+ #if compiler(>=6.2)
104
+ if #available(iOS 26.0, *) {
105
+ guard let glassEffectClass = NSClassFromString("UIGlassEffect") as? NSObject.Type else { return }
106
+ guard glassEffectClass.responds(to: Selector(("effectWithStyle:"))) else { return }
107
+
108
+ let glass = UIGlassEffect(style: currentEffectStyle.uiGlassStyle)
109
+ glass.isInteractive = interactive
110
+
111
+ if let tint = glassTintColor {
112
+ glass.tintColor = tint
113
+ }
114
+
115
+ let ev = UIVisualEffectView(effect: glass)
116
+ ev.autoresizingMask = [.flexibleWidth, .flexibleHeight]
117
+ ev.frame = bounds
118
+ ev.clipsToBounds = true
119
+ ev.layer.cornerRadius = cornerRadius
120
+ ev.layer.cornerCurve = .continuous
121
+
122
+ ev.layer.borderWidth = 0.5
123
+ ev.layer.borderColor = UIColor.white.withAlphaComponent(0.3).cgColor
124
+
125
+ insertSubview(ev, at: 0)
126
+ glassEffectView = ev
127
+
128
+ let specular = CAGradientLayer()
129
+ specular.colors = [
130
+ UIColor.white.withAlphaComponent(0.15).cgColor,
131
+ UIColor.white.withAlphaComponent(0.0).cgColor,
132
+ ]
133
+ specular.startPoint = CGPoint(x: 0.5, y: 0)
134
+ specular.endPoint = CGPoint(x: 0.5, y: 1)
135
+ specular.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 6)
136
+ specular.cornerRadius = cornerRadius
137
+ specular.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
138
+ ev.contentView.layer.addSublayer(specular)
139
+ specularLayer = specular
140
+
141
+ for child in reactChildren {
142
+ insertSubview(child, aboveSubview: ev)
143
+ }
144
+
145
+ applyCornerRadius()
146
+ }
147
+ #endif
148
+ }
149
+
150
+ private func rebuildEffect() {
151
+ buildEffect()
152
+ updateShadows()
153
+ }
154
+
155
+ // MARK: - Shadow System
156
+
157
+ private func setupShadowLayers() {
158
+ let contact = CALayer()
159
+ contact.shadowColor = UIColor.black.cgColor
160
+ contact.shadowOffset = CGSize(width: 0, height: 2)
161
+ contact.shadowRadius = 4
162
+ contact.shadowOpacity = 0.08
163
+ layer.insertSublayer(contact, at: 0)
164
+ contactShadowLayer = contact
165
+
166
+ let elevation = CALayer()
167
+ elevation.shadowColor = UIColor.black.cgColor
168
+ elevation.shadowOffset = CGSize(width: 0, height: 12)
169
+ elevation.shadowRadius = 24
170
+ elevation.shadowOpacity = Float(shadowIntensity)
171
+ layer.insertSublayer(elevation, at: 0)
172
+ elevationShadowLayer = elevation
173
+ }
174
+
175
+ private func updateShadows() {
176
+ guard bounds.width > 0, bounds.height > 0 else { return }
177
+
178
+ let shadowPath = UIBezierPath(
179
+ roundedRect: bounds,
180
+ cornerRadius: cornerRadius
181
+ ).cgPath
182
+
183
+ contactShadowLayer?.shadowPath = shadowPath
184
+ contactShadowLayer?.frame = bounds
185
+
186
+ elevationShadowLayer?.shadowPath = shadowPath
187
+ elevationShadowLayer?.frame = bounds
188
+ elevationShadowLayer?.shadowOpacity = Float(shadowIntensity)
189
+ }
190
+
191
+ // MARK: - Corner Radius
192
+
193
+ private func applyCornerRadius() {
194
+ layer.cornerRadius = cornerRadius
195
+ glassEffectView?.layer.cornerRadius = cornerRadius
196
+ specularLayer?.cornerRadius = cornerRadius
197
+ updateShadows()
198
+ }
199
+
200
+ // MARK: - Color Scheme
201
+
202
+ private func applyColorScheme() {
203
+ guard let scheme = colorScheme as String? else {
204
+ overrideUserInterfaceStyle = .unspecified
205
+ return
206
+ }
207
+ switch scheme {
208
+ case "dark": overrideUserInterfaceStyle = .dark
209
+ case "light": overrideUserInterfaceStyle = .light
210
+ default: overrideUserInterfaceStyle = .unspecified
211
+ }
212
+ }
213
+
214
+ // MARK: - Touch Animation
215
+
216
+ public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
217
+ super.touchesBegan(touches, with: event)
218
+ guard enablePressAnimation, !isPressed else { return }
219
+ isPressed = true
220
+ feedbackGenerator.impactOccurred()
221
+ animatePress(pressed: true)
222
+ }
223
+
224
+ public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
225
+ super.touchesEnded(touches, with: event)
226
+ guard enablePressAnimation, isPressed else { return }
227
+ isPressed = false
228
+ animatePress(pressed: false)
229
+ }
230
+
231
+ public override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
232
+ super.touchesCancelled(touches, with: event)
233
+ guard enablePressAnimation, isPressed else { return }
234
+ isPressed = false
235
+ animatePress(pressed: false)
236
+ }
237
+
238
+ private func animatePress(pressed: Bool) {
239
+ let scale: CGFloat = pressed ? 0.97 : 1.0
240
+ let elevationOpacity: Float = pressed
241
+ ? Float(shadowIntensity * 0.4)
242
+ : Float(shadowIntensity)
243
+ let contactOpacity: Float = pressed ? 0.12 : 0.08
244
+
245
+ UIView.animate(
246
+ withDuration: 0.4,
247
+ delay: 0,
248
+ usingSpringWithDamping: pressed ? 0.65 : 0.5,
249
+ initialSpringVelocity: pressed ? 0 : 0.8,
250
+ options: [.allowUserInteraction, .beginFromCurrentState]
251
+ ) {
252
+ self.transform = CGAffineTransform(scaleX: scale, y: scale)
253
+ }
254
+
255
+ let shadowAnim = CABasicAnimation(keyPath: "shadowOpacity")
256
+ shadowAnim.toValue = elevationOpacity
257
+ shadowAnim.duration = 0.3
258
+ shadowAnim.fillMode = .forwards
259
+ shadowAnim.isRemovedOnCompletion = false
260
+ elevationShadowLayer?.add(shadowAnim, forKey: "shadowOpacity")
261
+
262
+ let contactAnim = CABasicAnimation(keyPath: "shadowOpacity")
263
+ contactAnim.toValue = contactOpacity
264
+ contactAnim.duration = 0.3
265
+ contactAnim.fillMode = .forwards
266
+ contactAnim.isRemovedOnCompletion = false
267
+ contactShadowLayer?.add(contactAnim, forKey: "shadowOpacity")
268
+ }
269
+
270
+ // MARK: - Entrance Animation
271
+
272
+ public override func didMoveToWindow() {
273
+ super.didMoveToWindow()
274
+ guard enableEntrance, !hasAnimatedEntrance, window != nil else { return }
275
+ hasAnimatedEntrance = true
276
+
277
+ alpha = 0
278
+ transform = CGAffineTransform(translationX: 0, y: 8)
279
+
280
+ UIView.animate(
281
+ withDuration: 0.6,
282
+ delay: 0,
283
+ usingSpringWithDamping: 0.7,
284
+ initialSpringVelocity: 0,
285
+ options: [.allowUserInteraction]
286
+ ) {
287
+ self.alpha = 1
288
+ self.transform = .identity
289
+ }
290
+ }
291
+
292
+ // MARK: - Layout
293
+
294
+ public override func layoutSubviews() {
295
+ super.layoutSubviews()
296
+ glassEffectView?.frame = bounds
297
+ specularLayer?.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 6)
298
+
299
+ if let ev = glassEffectView {
300
+ sendSubviewToBack(ev)
301
+ }
302
+
303
+ updateShadows()
304
+ }
305
+
306
+ // MARK: - React Native Subview Management
307
+
308
+ @objc public func insertReactSubview(_ subview: UIView!, at atIndex: Int) {
309
+ if let ev = glassEffectView {
310
+ insertSubview(subview, aboveSubview: ev)
311
+ } else {
312
+ insertSubview(subview, at: atIndex)
313
+ }
314
+ }
315
+
316
+ @objc public func removeReactSubview(_ subview: UIView!) {
317
+ subview?.removeFromSuperview()
318
+ }
319
+ }
@@ -0,0 +1,21 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import "react_native_liquidGlass_view-Swift.h"
3
+
4
+ @interface LiquidGlassContainerManager : RCTViewManager
5
+ @end
6
+
7
+ @implementation LiquidGlassContainerManager
8
+
9
+ RCT_EXPORT_MODULE(RNLiquidGlassContainer)
10
+
11
+ - (UIView *)view {
12
+ return [[BNGlassContainerView alloc] init];
13
+ }
14
+
15
+ RCT_EXPORT_VIEW_PROPERTY(spacing, CGFloat)
16
+
17
+ + (BOOL)requiresMainQueueSetup {
18
+ return YES;
19
+ }
20
+
21
+ @end
@@ -0,0 +1,36 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import <React/RCTConvert.h>
3
+ #import "react_native_liquidGlass_view-Swift.h"
4
+
5
+ @interface LiquidGlassViewManager : RCTViewManager
6
+ @end
7
+
8
+ @implementation LiquidGlassViewManager
9
+
10
+ RCT_EXPORT_MODULE(RNLiquidGlass)
11
+
12
+ - (UIView *)view {
13
+ return [[BNGlassView alloc] init];
14
+ }
15
+
16
+ RCT_EXPORT_VIEW_PROPERTY(cornerRadius, CGFloat)
17
+ RCT_EXPORT_VIEW_PROPERTY(effect, NSString)
18
+ RCT_EXPORT_VIEW_PROPERTY(interactive, BOOL)
19
+ RCT_EXPORT_VIEW_PROPERTY(colorScheme, NSString)
20
+
21
+ // Map JS "tintColor" to the native "glassTintColor" property
22
+ // to avoid conflicting with UIView's built-in tintColor.
23
+ RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, BNGlassView)
24
+ {
25
+ view.glassTintColor = json ? [RCTConvert UIColor:json] : nil;
26
+ }
27
+
28
+ RCT_EXPORT_VIEW_PROPERTY(shadowIntensity, CGFloat)
29
+ RCT_EXPORT_VIEW_PROPERTY(enablePressAnimation, BOOL)
30
+ RCT_EXPORT_VIEW_PROPERTY(enableEntrance, BOOL)
31
+
32
+ + (BOOL)requiresMainQueueSetup {
33
+ return YES;
34
+ }
35
+
36
+ @end
@@ -0,0 +1,63 @@
1
+ import React from "react";
2
+ import { StyleProp, ViewStyle } from "react-native";
3
+ export interface LiquidGlassProps {
4
+ style?: StyleProp<ViewStyle>;
5
+ children?: React.ReactNode;
6
+ /**
7
+ * Blends a semi-transparent color over the glass surface.
8
+ * Accepts any React Native color string (e.g. "rgba(255,0,0,0.2)").
9
+ */
10
+ tintColor?: string;
11
+ /**
12
+ * When false, touch events pass through the glass to views below.
13
+ * @default true
14
+ */
15
+ interactive?: boolean;
16
+ /**
17
+ * Force the glass material to render in a specific colour scheme
18
+ * regardless of the system setting.
19
+ */
20
+ colorScheme?: "light" | "dark";
21
+ /**
22
+ * Visual weight of the glass material.
23
+ * - "regular" — full glass (default)
24
+ * - "clear" — lighter, more transparent glass
25
+ * @default "regular"
26
+ */
27
+ effect?: "regular" | "clear";
28
+ /**
29
+ * Corner radius applied to the glass surface.
30
+ * Uses continuous corner curve for Apple-style rounded corners.
31
+ * @default 16
32
+ */
33
+ cornerRadius?: number;
34
+ /**
35
+ * Controls the opacity of the main elevation shadow.
36
+ * Range: 0 (no shadow) to 1 (fully opaque shadow).
37
+ * @default 0.15
38
+ */
39
+ shadowIntensity?: number;
40
+ /**
41
+ * Enables a spring press-in/release scale animation with haptic feedback.
42
+ * @default false
43
+ */
44
+ enablePressAnimation?: boolean;
45
+ /**
46
+ * Enables a fade+translate entrance animation when the view first appears.
47
+ * @default false
48
+ */
49
+ enableEntrance?: boolean;
50
+ }
51
+ export interface LiquidGlassContainerProps {
52
+ style?: StyleProp<ViewStyle>;
53
+ children?: React.ReactNode;
54
+ /**
55
+ * The distance between child glass elements at which they begin to merge.
56
+ * @default 0
57
+ */
58
+ spacing?: number;
59
+ }
60
+ export declare const isLiquidGlassSupported: boolean;
61
+ export declare const NativeLiquidGlassView: import("react-native").HostComponent<LiquidGlassProps> | null;
62
+ export declare const NativeLiquidGlassContainerView: import("react-native").HostComponent<LiquidGlassContainerProps> | null;
63
+ //# sourceMappingURL=NativeLiquidGlass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeLiquidGlass.d.ts","sourceRoot":"","sources":["../src/NativeLiquidGlass.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAGL,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC7B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,sBAAsB,SACsC,CAAC;AAE1E,eAAO,MAAM,qBAAqB,+DAE1B,CAAC;AAET,eAAO,MAAM,8BAA8B,wEAEnC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { Platform, requireNativeComponent, } from "react-native";
2
+ export const isLiquidGlassSupported = Platform.OS === "ios" && parseInt(Platform.Version, 10) >= 26;
3
+ export const NativeLiquidGlassView = isLiquidGlassSupported
4
+ ? requireNativeComponent("RNLiquidGlass")
5
+ : null;
6
+ export const NativeLiquidGlassContainerView = isLiquidGlassSupported
7
+ ? requireNativeComponent("RNLiquidGlassContainer")
8
+ : null;
9
+ //# sourceMappingURL=NativeLiquidGlass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeLiquidGlass.js","sourceRoot":"","sources":["../src/NativeLiquidGlass.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,EACR,sBAAsB,GAGvB,MAAM,cAAc,CAAC;AA6DtB,MAAM,CAAC,MAAM,sBAAsB,GACjC,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAiB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;AAE1E,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB;IACzD,CAAC,CAAC,sBAAsB,CAAmB,eAAe,CAAC;IAC3D,CAAC,CAAC,IAAI,CAAC;AAET,MAAM,CAAC,MAAM,8BAA8B,GAAG,sBAAsB;IAClE,CAAC,CAAC,sBAAsB,CAA4B,wBAAwB,CAAC;IAC7E,CAAC,CAAC,IAAI,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import { StyleProp, ViewStyle } from "react-native";
3
+ import { isLiquidGlassSupported } from "./NativeLiquidGlass";
4
+ import type { LiquidGlassProps, LiquidGlassContainerProps } from "./NativeLiquidGlass";
5
+ export type { LiquidGlassProps, LiquidGlassContainerProps };
6
+ export { isLiquidGlassSupported };
7
+ export interface GlassCardProps extends Pick<LiquidGlassProps, "tintColor" | "colorScheme" | "effect" | "cornerRadius" | "shadowIntensity" | "enablePressAnimation" | "enableEntrance"> {
8
+ children: React.ReactNode;
9
+ style?: StyleProp<ViewStyle>;
10
+ }
11
+ export declare const GlassCard: React.FC<GlassCardProps>;
12
+ export interface GlassViewProps extends LiquidGlassProps {
13
+ children: React.ReactNode;
14
+ }
15
+ export declare const GlassView: React.FC<GlassViewProps>;
16
+ export interface GlassContainerProps extends LiquidGlassContainerProps {
17
+ children: React.ReactNode;
18
+ }
19
+ export declare const GlassContainer: React.FC<GlassContainerProps>;
20
+ export default GlassCard;
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAoB,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EACL,sBAAsB,EAGvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,gBAAgB,EAChB,yBAAyB,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAIlC,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,gBAAgB,EACd,WAAW,GACX,aAAa,GACb,QAAQ,GACR,cAAc,GACd,iBAAiB,GACjB,sBAAsB,GACtB,gBAAgB,CACnB;IACC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAiC9C,CAAC;AAIF,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAmC9C,CAAC;AAIF,MAAM,WAAW,mBAAoB,SAAQ,yBAAyB;IACpE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAcxD,CAAC;AAeF,eAAe,SAAS,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { StyleSheet, View } from "react-native";
3
+ import { isLiquidGlassSupported, NativeLiquidGlassView, NativeLiquidGlassContainerView, } from "./NativeLiquidGlass";
4
+ export { isLiquidGlassSupported };
5
+ export const GlassCard = ({ children, style, tintColor, colorScheme, effect = "clear", cornerRadius = 16, shadowIntensity, enablePressAnimation, enableEntrance, }) => {
6
+ if (!isLiquidGlassSupported || !NativeLiquidGlassView) {
7
+ return (_jsx(View, { style: [styles.fallback, { borderRadius: cornerRadius }, style], children: children }));
8
+ }
9
+ return (_jsx(NativeLiquidGlassView, { style: style, tintColor: tintColor, colorScheme: colorScheme, effect: effect, cornerRadius: cornerRadius, shadowIntensity: shadowIntensity, enablePressAnimation: enablePressAnimation, enableEntrance: enableEntrance, children: children }));
10
+ };
11
+ export const GlassView = ({ children, style, tintColor, interactive, colorScheme, effect = "clear", cornerRadius = 16, shadowIntensity, enablePressAnimation, enableEntrance, }) => {
12
+ if (!isLiquidGlassSupported || !NativeLiquidGlassView) {
13
+ return (_jsx(View, { style: [styles.fallback, { borderRadius: cornerRadius }, style], children: children }));
14
+ }
15
+ return (_jsx(NativeLiquidGlassView, { style: [{ borderRadius: cornerRadius }, style], tintColor: tintColor, colorScheme: colorScheme, interactive: interactive, effect: effect, cornerRadius: cornerRadius, shadowIntensity: shadowIntensity, enablePressAnimation: enablePressAnimation, enableEntrance: enableEntrance, children: children }));
16
+ };
17
+ export const GlassContainer = ({ children, style, spacing = 0, }) => {
18
+ if (!isLiquidGlassSupported || !NativeLiquidGlassContainerView) {
19
+ return _jsx(View, { style: style, children: children });
20
+ }
21
+ return (_jsx(NativeLiquidGlassContainerView, { style: style, spacing: spacing, children: children }));
22
+ };
23
+ const styles = StyleSheet.create({
24
+ fallback: {
25
+ backgroundColor: "rgba(225, 234, 240, 0.45)",
26
+ borderWidth: 0.5,
27
+ borderColor: "rgba(255, 255, 255, 0.4)",
28
+ shadowColor: "#000D2E",
29
+ shadowOffset: { width: 0, height: 12 },
30
+ shadowOpacity: 0.1,
31
+ shadowRadius: 24,
32
+ elevation: 18,
33
+ },
34
+ });
35
+ export default GlassCard;
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@k-workspace/react-native-liquidglass-view",
3
+ "version": "0.1.0",
4
+ "description": "iOS 26 Liquid Glass effect for React Native — UIGlassEffect with configurable styles, shadows, press animations, and entrance transitions.",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "react-native": "src/index",
8
+ "source": "src/index",
9
+ "files": [
10
+ "src",
11
+ "lib",
12
+ "ios",
13
+ "react-native-liquidGlass-view.podspec",
14
+ "react-native.config.js",
15
+ "!**/__tests__"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc --project tsconfig.build.json",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "keywords": [
22
+ "react-native",
23
+ "ios",
24
+ "liquid-glass",
25
+ "glass-effect",
26
+ "ios26",
27
+ "uiglasseffect",
28
+ "blur",
29
+ "glassmorphism",
30
+ "apple",
31
+ "native-module"
32
+ ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/techytypes/react-native-liquidGlass-view.git"
36
+ },
37
+ "author": "techytypes",
38
+ "license": "MIT",
39
+ "bugs": {
40
+ "url": "https://github.com/techytypes/react-native-liquidGlass-view/issues"
41
+ },
42
+ "homepage": "https://github.com/techytypes/react-native-liquidGlass-view#readme",
43
+ "peerDependencies": {
44
+ "react": ">=18.0.0",
45
+ "react-native": ">=0.73.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/react": "^18.0.0",
49
+ "react": "^18.0.0",
50
+ "react-native": "^0.84.0",
51
+ "typescript": "^5.0.0"
52
+ }
53
+ }
@@ -0,0 +1,21 @@
1
+ Pod::Spec.new do |s|
2
+ s.name = 'react-native-liquidGlass-view'
3
+ s.version = '0.1.0'
4
+ s.summary = 'iOS 26 Liquid Glass effect for React Native'
5
+ s.description = 'Native UIGlassEffect wrapper for React Native with configurable styles, shadows, press animations, entrance transitions, and glass container merging.'
6
+ s.author = 'techytypes'
7
+ s.homepage = 'https://github.com/techytypes/react-native-liquidGlass-view'
8
+ s.license = { :type => 'MIT' }
9
+ s.platforms = { :ios => '15.1' }
10
+ s.source = { :git => 'https://github.com/techytypes/react-native-liquidGlass-view.git', :tag => s.version.to_s }
11
+ s.static_framework = true
12
+
13
+ s.dependency 'React-Core'
14
+
15
+ s.pod_target_xcconfig = {
16
+ 'DEFINES_MODULE' => 'YES',
17
+ 'SWIFT_VERSION' => '5.0',
18
+ }
19
+
20
+ s.source_files = 'ios/**/*.{swift,h,m}'
21
+ end
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ ios: {
5
+ podspecPath: __dirname + "/react-native-liquidGlass-view.podspec",
6
+ },
7
+ android: null, // iOS only
8
+ },
9
+ },
10
+ };
@@ -0,0 +1,77 @@
1
+ import React from "react";
2
+ import {
3
+ Platform,
4
+ requireNativeComponent,
5
+ StyleProp,
6
+ ViewStyle,
7
+ } from "react-native";
8
+
9
+ export interface LiquidGlassProps {
10
+ style?: StyleProp<ViewStyle>;
11
+ children?: React.ReactNode;
12
+ /**
13
+ * Blends a semi-transparent color over the glass surface.
14
+ * Accepts any React Native color string (e.g. "rgba(255,0,0,0.2)").
15
+ */
16
+ tintColor?: string;
17
+ /**
18
+ * When false, touch events pass through the glass to views below.
19
+ * @default true
20
+ */
21
+ interactive?: boolean;
22
+ /**
23
+ * Force the glass material to render in a specific colour scheme
24
+ * regardless of the system setting.
25
+ */
26
+ colorScheme?: "light" | "dark";
27
+ /**
28
+ * Visual weight of the glass material.
29
+ * - "regular" — full glass (default)
30
+ * - "clear" — lighter, more transparent glass
31
+ * @default "regular"
32
+ */
33
+ effect?: "regular" | "clear";
34
+ /**
35
+ * Corner radius applied to the glass surface.
36
+ * Uses continuous corner curve for Apple-style rounded corners.
37
+ * @default 16
38
+ */
39
+ cornerRadius?: number;
40
+ /**
41
+ * Controls the opacity of the main elevation shadow.
42
+ * Range: 0 (no shadow) to 1 (fully opaque shadow).
43
+ * @default 0.15
44
+ */
45
+ shadowIntensity?: number;
46
+ /**
47
+ * Enables a spring press-in/release scale animation with haptic feedback.
48
+ * @default false
49
+ */
50
+ enablePressAnimation?: boolean;
51
+ /**
52
+ * Enables a fade+translate entrance animation when the view first appears.
53
+ * @default false
54
+ */
55
+ enableEntrance?: boolean;
56
+ }
57
+
58
+ export interface LiquidGlassContainerProps {
59
+ style?: StyleProp<ViewStyle>;
60
+ children?: React.ReactNode;
61
+ /**
62
+ * The distance between child glass elements at which they begin to merge.
63
+ * @default 0
64
+ */
65
+ spacing?: number;
66
+ }
67
+
68
+ export const isLiquidGlassSupported =
69
+ Platform.OS === "ios" && parseInt(Platform.Version as string, 10) >= 26;
70
+
71
+ export const NativeLiquidGlassView = isLiquidGlassSupported
72
+ ? requireNativeComponent<LiquidGlassProps>("RNLiquidGlass")
73
+ : null;
74
+
75
+ export const NativeLiquidGlassContainerView = isLiquidGlassSupported
76
+ ? requireNativeComponent<LiquidGlassContainerProps>("RNLiquidGlassContainer")
77
+ : null;
package/src/index.tsx ADDED
@@ -0,0 +1,145 @@
1
+ import React from "react";
2
+ import { StyleSheet, View, StyleProp, ViewStyle } from "react-native";
3
+ import {
4
+ isLiquidGlassSupported,
5
+ NativeLiquidGlassView,
6
+ NativeLiquidGlassContainerView,
7
+ } from "./NativeLiquidGlass";
8
+ import type {
9
+ LiquidGlassProps,
10
+ LiquidGlassContainerProps,
11
+ } from "./NativeLiquidGlass";
12
+
13
+ export type { LiquidGlassProps, LiquidGlassContainerProps };
14
+ export { isLiquidGlassSupported };
15
+
16
+ // GlassCard — opinionated card wrapper with sensible defaults
17
+
18
+ export interface GlassCardProps extends Pick<
19
+ LiquidGlassProps,
20
+ | "tintColor"
21
+ | "colorScheme"
22
+ | "effect"
23
+ | "cornerRadius"
24
+ | "shadowIntensity"
25
+ | "enablePressAnimation"
26
+ | "enableEntrance"
27
+ > {
28
+ children: React.ReactNode;
29
+ style?: StyleProp<ViewStyle>;
30
+ }
31
+
32
+ export const GlassCard: React.FC<GlassCardProps> = ({
33
+ children,
34
+ style,
35
+ tintColor,
36
+ colorScheme,
37
+ effect = "clear",
38
+ cornerRadius = 16,
39
+ shadowIntensity,
40
+ enablePressAnimation,
41
+ enableEntrance,
42
+ }) => {
43
+ if (!isLiquidGlassSupported || !NativeLiquidGlassView) {
44
+ return (
45
+ <View style={[styles.fallback, { borderRadius: cornerRadius }, style]}>
46
+ {children}
47
+ </View>
48
+ );
49
+ }
50
+
51
+ return (
52
+ <NativeLiquidGlassView
53
+ style={style}
54
+ tintColor={tintColor}
55
+ colorScheme={colorScheme}
56
+ effect={effect}
57
+ cornerRadius={cornerRadius}
58
+ shadowIntensity={shadowIntensity}
59
+ enablePressAnimation={enablePressAnimation}
60
+ enableEntrance={enableEntrance}
61
+ >
62
+ {children}
63
+ </NativeLiquidGlassView>
64
+ );
65
+ };
66
+
67
+ // GlassView — lower-level view exposing all native props
68
+
69
+ export interface GlassViewProps extends LiquidGlassProps {
70
+ children: React.ReactNode;
71
+ }
72
+
73
+ export const GlassView: React.FC<GlassViewProps> = ({
74
+ children,
75
+ style,
76
+ tintColor,
77
+ interactive,
78
+ colorScheme,
79
+ effect = "clear",
80
+ cornerRadius = 16,
81
+ shadowIntensity,
82
+ enablePressAnimation,
83
+ enableEntrance,
84
+ }) => {
85
+ if (!isLiquidGlassSupported || !NativeLiquidGlassView) {
86
+ return (
87
+ <View style={[styles.fallback, { borderRadius: cornerRadius }, style]}>
88
+ {children}
89
+ </View>
90
+ );
91
+ }
92
+
93
+ return (
94
+ <NativeLiquidGlassView
95
+ style={[{ borderRadius: cornerRadius }, style]}
96
+ tintColor={tintColor}
97
+ colorScheme={colorScheme}
98
+ interactive={interactive}
99
+ effect={effect}
100
+ cornerRadius={cornerRadius}
101
+ shadowIntensity={shadowIntensity}
102
+ enablePressAnimation={enablePressAnimation}
103
+ enableEntrance={enableEntrance}
104
+ >
105
+ {children}
106
+ </NativeLiquidGlassView>
107
+ );
108
+ };
109
+
110
+ // GlassContainer — groups child glass views so they merge together
111
+
112
+ export interface GlassContainerProps extends LiquidGlassContainerProps {
113
+ children: React.ReactNode;
114
+ }
115
+
116
+ export const GlassContainer: React.FC<GlassContainerProps> = ({
117
+ children,
118
+ style,
119
+ spacing = 0,
120
+ }) => {
121
+ if (!isLiquidGlassSupported || !NativeLiquidGlassContainerView) {
122
+ return <View style={style}>{children}</View>;
123
+ }
124
+
125
+ return (
126
+ <NativeLiquidGlassContainerView style={style} spacing={spacing}>
127
+ {children}
128
+ </NativeLiquidGlassContainerView>
129
+ );
130
+ };
131
+
132
+ const styles = StyleSheet.create({
133
+ fallback: {
134
+ backgroundColor: "rgba(225, 234, 240, 0.45)",
135
+ borderWidth: 0.5,
136
+ borderColor: "rgba(255, 255, 255, 0.4)",
137
+ shadowColor: "#000D2E",
138
+ shadowOffset: { width: 0, height: 12 },
139
+ shadowOpacity: 0.1,
140
+ shadowRadius: 24,
141
+ elevation: 18,
142
+ },
143
+ });
144
+
145
+ export default GlassCard;