reactnatively-glass 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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Hakizimana Fred
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.
@@ -0,0 +1,93 @@
1
+ import { GlassElevation, GlassTintVariant, GlassHighlight, ResolvedColorScheme } from 'reactnatively-theme';
2
+ import React, { ReactNode } from 'react';
3
+ import { StyleProp, ViewStyle, AccessibilityRole } from 'react-native';
4
+
5
+ type GlassCapability = 'full' | 'partial' | 'none';
6
+ declare const GLASS_CAPABILITY: GlassCapability;
7
+ declare const SUPPORTS_BLUR: boolean;
8
+ declare const IS_FULL_GLASS: boolean;
9
+ declare const IS_PARTIAL_GLASS: boolean;
10
+ declare const IS_NO_GLASS: boolean;
11
+ declare function adjustBlurForCapability(intensity: number): number;
12
+
13
+ interface GlassConfig {
14
+ elevation?: GlassElevation;
15
+ variant?: GlassTintVariant;
16
+ highlight?: GlassHighlight | boolean;
17
+ border?: boolean;
18
+ borderWidth?: number;
19
+ blurOverride?: number;
20
+ tintOverride?: string;
21
+ glow?: {
22
+ color: string;
23
+ radius?: number;
24
+ opacity?: number;
25
+ } | false;
26
+ }
27
+ interface ResolvedGlassStyle {
28
+ blurAmount: number;
29
+ blurTint: 'light' | 'dark' | 'default';
30
+ tintColor: string;
31
+ highlightColor: string;
32
+ borderColor: string;
33
+ borderWidth: number;
34
+ shadowColor: string;
35
+ shadowOpacity: number;
36
+ shadowRadius: number;
37
+ shadowOffset: {
38
+ width: number;
39
+ height: number;
40
+ };
41
+ androidElevation: number;
42
+ capability: GlassCapability;
43
+ }
44
+
45
+ declare function resolveGlass(config: GlassConfig, colorScheme: ResolvedColorScheme): ResolvedGlassStyle;
46
+
47
+ interface GlassViewProps {
48
+ elevation?: GlassElevation;
49
+ variant?: GlassTintVariant;
50
+ highlight?: GlassHighlight | boolean;
51
+ border?: boolean;
52
+ borderWidth?: number;
53
+ borderRadius?: number;
54
+ blurOverride?: number;
55
+ tintOverride?: string;
56
+ glow?: {
57
+ color: string;
58
+ radius?: number;
59
+ opacity?: number;
60
+ } | false;
61
+ style?: StyleProp<ViewStyle>;
62
+ contentStyle?: StyleProp<ViewStyle>;
63
+ children?: ReactNode;
64
+ testID?: string;
65
+ animated?: boolean;
66
+ accessible?: boolean;
67
+ accessibilityLabel?: string;
68
+ accessibilityRole?: AccessibilityRole;
69
+ }
70
+
71
+ /**
72
+ * GlassView — the foundational rendering primitive of the Liquid Glass system.
73
+ *
74
+ * Layer stack (bottom → top):
75
+ * 1. Shadow shell — drop shadow / elevation (outer view, NO overflow:hidden)
76
+ * 2. Clip shell — clips all glass layers to border radius (overflow:hidden)
77
+ * 3. BlurView — native platform blur
78
+ * 4. Tint overlay — semi-transparent color layer
79
+ * 5. Highlight — top-edge refraction shimmer (LinearGradient)
80
+ * 6. Border ring — 1px glass edge line
81
+ * 7. Content — children, above all glass layers
82
+ */
83
+ declare const GlassView: React.NamedExoticComponent<GlassViewProps>;
84
+
85
+ interface FrostPanelProps extends Omit<GlassViewProps, 'style'> {
86
+ style?: StyleProp<ViewStyle>;
87
+ edges?: ('top' | 'bottom' | 'left' | 'right')[];
88
+ }
89
+ declare const FrostPanel: React.NamedExoticComponent<FrostPanelProps>;
90
+
91
+ declare function useGlassStyle(config: GlassConfig): ResolvedGlassStyle;
92
+
93
+ export { FrostPanel, type FrostPanelProps, GLASS_CAPABILITY, type GlassCapability, type GlassConfig, GlassView, type GlassViewProps, IS_FULL_GLASS, IS_NO_GLASS, IS_PARTIAL_GLASS, type ResolvedGlassStyle, SUPPORTS_BLUR, adjustBlurForCapability, resolveGlass, useGlassStyle };
@@ -0,0 +1,93 @@
1
+ import { GlassElevation, GlassTintVariant, GlassHighlight, ResolvedColorScheme } from 'reactnatively-theme';
2
+ import React, { ReactNode } from 'react';
3
+ import { StyleProp, ViewStyle, AccessibilityRole } from 'react-native';
4
+
5
+ type GlassCapability = 'full' | 'partial' | 'none';
6
+ declare const GLASS_CAPABILITY: GlassCapability;
7
+ declare const SUPPORTS_BLUR: boolean;
8
+ declare const IS_FULL_GLASS: boolean;
9
+ declare const IS_PARTIAL_GLASS: boolean;
10
+ declare const IS_NO_GLASS: boolean;
11
+ declare function adjustBlurForCapability(intensity: number): number;
12
+
13
+ interface GlassConfig {
14
+ elevation?: GlassElevation;
15
+ variant?: GlassTintVariant;
16
+ highlight?: GlassHighlight | boolean;
17
+ border?: boolean;
18
+ borderWidth?: number;
19
+ blurOverride?: number;
20
+ tintOverride?: string;
21
+ glow?: {
22
+ color: string;
23
+ radius?: number;
24
+ opacity?: number;
25
+ } | false;
26
+ }
27
+ interface ResolvedGlassStyle {
28
+ blurAmount: number;
29
+ blurTint: 'light' | 'dark' | 'default';
30
+ tintColor: string;
31
+ highlightColor: string;
32
+ borderColor: string;
33
+ borderWidth: number;
34
+ shadowColor: string;
35
+ shadowOpacity: number;
36
+ shadowRadius: number;
37
+ shadowOffset: {
38
+ width: number;
39
+ height: number;
40
+ };
41
+ androidElevation: number;
42
+ capability: GlassCapability;
43
+ }
44
+
45
+ declare function resolveGlass(config: GlassConfig, colorScheme: ResolvedColorScheme): ResolvedGlassStyle;
46
+
47
+ interface GlassViewProps {
48
+ elevation?: GlassElevation;
49
+ variant?: GlassTintVariant;
50
+ highlight?: GlassHighlight | boolean;
51
+ border?: boolean;
52
+ borderWidth?: number;
53
+ borderRadius?: number;
54
+ blurOverride?: number;
55
+ tintOverride?: string;
56
+ glow?: {
57
+ color: string;
58
+ radius?: number;
59
+ opacity?: number;
60
+ } | false;
61
+ style?: StyleProp<ViewStyle>;
62
+ contentStyle?: StyleProp<ViewStyle>;
63
+ children?: ReactNode;
64
+ testID?: string;
65
+ animated?: boolean;
66
+ accessible?: boolean;
67
+ accessibilityLabel?: string;
68
+ accessibilityRole?: AccessibilityRole;
69
+ }
70
+
71
+ /**
72
+ * GlassView — the foundational rendering primitive of the Liquid Glass system.
73
+ *
74
+ * Layer stack (bottom → top):
75
+ * 1. Shadow shell — drop shadow / elevation (outer view, NO overflow:hidden)
76
+ * 2. Clip shell — clips all glass layers to border radius (overflow:hidden)
77
+ * 3. BlurView — native platform blur
78
+ * 4. Tint overlay — semi-transparent color layer
79
+ * 5. Highlight — top-edge refraction shimmer (LinearGradient)
80
+ * 6. Border ring — 1px glass edge line
81
+ * 7. Content — children, above all glass layers
82
+ */
83
+ declare const GlassView: React.NamedExoticComponent<GlassViewProps>;
84
+
85
+ interface FrostPanelProps extends Omit<GlassViewProps, 'style'> {
86
+ style?: StyleProp<ViewStyle>;
87
+ edges?: ('top' | 'bottom' | 'left' | 'right')[];
88
+ }
89
+ declare const FrostPanel: React.NamedExoticComponent<FrostPanelProps>;
90
+
91
+ declare function useGlassStyle(config: GlassConfig): ResolvedGlassStyle;
92
+
93
+ export { FrostPanel, type FrostPanelProps, GLASS_CAPABILITY, type GlassCapability, type GlassConfig, GlassView, type GlassViewProps, IS_FULL_GLASS, IS_NO_GLASS, IS_PARTIAL_GLASS, type ResolvedGlassStyle, SUPPORTS_BLUR, adjustBlurForCapability, resolveGlass, useGlassStyle };
package/dist/index.js ADDED
@@ -0,0 +1,336 @@
1
+ 'use strict';
2
+
3
+ var reactnativelyTheme = require('reactnatively-theme');
4
+ var reactnativelyUtils = require('reactnatively-utils');
5
+ var React = require('react');
6
+ var reactNative = require('react-native');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var React__default = /*#__PURE__*/_interopDefault(React);
12
+
13
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
14
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
15
+ }) : x)(function(x) {
16
+ if (typeof require !== "undefined") return require.apply(this, arguments);
17
+ throw Error('Dynamic require of "' + x + '" is not supported');
18
+ });
19
+ function detectCapability() {
20
+ if (reactnativelyUtils.IS_IOS) return "full";
21
+ if (reactnativelyUtils.IS_ANDROID) {
22
+ const version = reactnativelyUtils.getAndroidVersion();
23
+ return version >= 31 ? "partial" : "none";
24
+ }
25
+ if (reactnativelyUtils.IS_WEB) return "partial";
26
+ return "none";
27
+ }
28
+ var GLASS_CAPABILITY = detectCapability();
29
+ var SUPPORTS_BLUR = GLASS_CAPABILITY !== "none";
30
+ var IS_FULL_GLASS = GLASS_CAPABILITY === "full";
31
+ var IS_PARTIAL_GLASS = GLASS_CAPABILITY === "partial";
32
+ var IS_NO_GLASS = GLASS_CAPABILITY === "none";
33
+ function adjustBlurForCapability(intensity) {
34
+ if (GLASS_CAPABILITY === "full") return intensity;
35
+ if (GLASS_CAPABILITY === "partial") return Math.round(intensity * 0.65);
36
+ return 0;
37
+ }
38
+ var ANDROID_BLUR_METHOD = reactnativelyUtils.IS_ANDROID ? "dimezisBlurView" : void 0;
39
+
40
+ // src/engine/GlassEngine.ts
41
+ function resolveGlass(config, colorScheme) {
42
+ const {
43
+ elevation = 2,
44
+ variant = "surface",
45
+ highlight = true,
46
+ border = true,
47
+ borderWidth = 1,
48
+ blurOverride,
49
+ tintOverride
50
+ } = config;
51
+ const elevationConfig = reactnativelyTheme.glassTokens.elevation[elevation];
52
+ const rawBlur = blurOverride ?? elevationConfig.blur;
53
+ const blurAmount = adjustBlurForCapability(rawBlur);
54
+ const tintColor = tintOverride ?? reactnativelyTheme.glassTokens.tint[colorScheme][variant];
55
+ let highlightColor = "transparent";
56
+ if (highlight === true) {
57
+ highlightColor = reactnativelyTheme.glassTokens.highlight.medium;
58
+ } else if (highlight !== false && highlight !== "none") {
59
+ highlightColor = reactnativelyTheme.glassTokens.highlight[highlight];
60
+ }
61
+ const borderColor = border ? reactnativelyTheme.glassTokens.border[colorScheme].medium : "transparent";
62
+ const shadowColor = colorScheme === "dark" ? "#000" : "#1a1a2e";
63
+ const shadowOpacity = elevationConfig.shadowOpacity;
64
+ const shadowRadius = elevationConfig.shadowRadius;
65
+ const shadowOffset = { width: 0, height: elevationConfig.shadowY };
66
+ const androidElevation = Math.round(elevation * 3);
67
+ const blurTint = colorScheme === "dark" ? "dark" : "light";
68
+ return {
69
+ blurAmount,
70
+ blurTint,
71
+ tintColor,
72
+ highlightColor,
73
+ borderColor,
74
+ borderWidth,
75
+ shadowColor,
76
+ shadowOpacity,
77
+ shadowRadius,
78
+ shadowOffset,
79
+ androidElevation,
80
+ capability: GLASS_CAPABILITY
81
+ };
82
+ }
83
+ var BlurViewImpl = null;
84
+ var blurLoaded = false;
85
+ var LinearGradientImpl = null;
86
+ var gradientLoaded = false;
87
+ function loadBlurView() {
88
+ if (blurLoaded) return BlurViewImpl;
89
+ blurLoaded = true;
90
+ try {
91
+ BlurViewImpl = __require("expo-blur").BlurView;
92
+ } catch {
93
+ BlurViewImpl = null;
94
+ }
95
+ return BlurViewImpl;
96
+ }
97
+ function loadLinearGradient() {
98
+ if (gradientLoaded) return LinearGradientImpl;
99
+ gradientLoaded = true;
100
+ try {
101
+ const gradientModule = __require("react-native-linear-gradient");
102
+ LinearGradientImpl = gradientModule?.default ?? gradientModule;
103
+ } catch {
104
+ LinearGradientImpl = null;
105
+ }
106
+ return LinearGradientImpl;
107
+ }
108
+ var GlassView = React__default.default.memo(
109
+ ({
110
+ elevation = 2,
111
+ variant = "surface",
112
+ highlight = true,
113
+ border = true,
114
+ borderWidth = 1,
115
+ borderRadius = 16,
116
+ blurOverride,
117
+ tintOverride,
118
+ glow,
119
+ style,
120
+ contentStyle,
121
+ children,
122
+ testID,
123
+ accessible,
124
+ accessibilityLabel,
125
+ accessibilityRole
126
+ }) => {
127
+ const { colorScheme } = reactnativelyTheme.useTheme();
128
+ const resolved = React.useMemo(
129
+ () => resolveGlass(
130
+ { elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride },
131
+ colorScheme
132
+ ),
133
+ [elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride, colorScheme]
134
+ );
135
+ const shadowStyle = React.useMemo(() => {
136
+ if (reactNative.Platform.OS === "android") {
137
+ return { elevation: resolved.androidElevation };
138
+ }
139
+ return {
140
+ shadowColor: resolved.shadowColor,
141
+ shadowOffset: resolved.shadowOffset,
142
+ shadowOpacity: resolved.shadowOpacity,
143
+ shadowRadius: resolved.shadowRadius
144
+ };
145
+ }, [resolved]);
146
+ const glowStyle = React.useMemo(() => {
147
+ if (!glow || reactNative.Platform.OS !== "ios") return {};
148
+ return {
149
+ shadowColor: glow.color,
150
+ shadowOffset: { width: 0, height: 0 },
151
+ shadowOpacity: glow.opacity ?? 0.35,
152
+ shadowRadius: glow.radius ?? 24
153
+ };
154
+ }, [glow]);
155
+ const BlurViewComponent = loadBlurView();
156
+ const LinearGradientComponent = loadLinearGradient();
157
+ if (IS_NO_GLASS) {
158
+ return /* @__PURE__ */ jsxRuntime.jsx(
159
+ reactNative.View,
160
+ {
161
+ testID,
162
+ accessible,
163
+ accessibilityLabel,
164
+ accessibilityRole,
165
+ style: [styles.shadowShell, { borderRadius }, shadowStyle, style],
166
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.clipShell, { borderRadius }], children: [
167
+ /* @__PURE__ */ jsxRuntime.jsx(
168
+ reactNative.View,
169
+ {
170
+ style: [
171
+ reactNative.StyleSheet.absoluteFill,
172
+ { backgroundColor: resolved.tintColor }
173
+ ]
174
+ }
175
+ ),
176
+ resolved.highlightColor !== "transparent" && (LinearGradientComponent ? /* @__PURE__ */ jsxRuntime.jsx(
177
+ LinearGradientComponent,
178
+ {
179
+ colors: [resolved.highlightColor, "transparent"],
180
+ start: { x: 0, y: 0 },
181
+ end: { x: 0, y: 1 },
182
+ style: styles.highlightGradient
183
+ }
184
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
185
+ reactNative.View,
186
+ {
187
+ pointerEvents: "none",
188
+ style: [
189
+ styles.highlightGradient,
190
+ { backgroundColor: resolved.highlightColor, opacity: 0.2 }
191
+ ]
192
+ }
193
+ )),
194
+ border && /* @__PURE__ */ jsxRuntime.jsx(
195
+ reactNative.View,
196
+ {
197
+ pointerEvents: "none",
198
+ style: [
199
+ reactNative.StyleSheet.absoluteFill,
200
+ { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor }
201
+ ]
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.content, contentStyle], children })
205
+ ] })
206
+ }
207
+ );
208
+ }
209
+ return /* @__PURE__ */ jsxRuntime.jsx(
210
+ reactNative.View,
211
+ {
212
+ testID,
213
+ accessible,
214
+ accessibilityLabel,
215
+ accessibilityRole,
216
+ style: [styles.shadowShell, { borderRadius }, shadowStyle, glowStyle, style],
217
+ children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.clipShell, { borderRadius }], children: [
218
+ BlurViewComponent ? /* @__PURE__ */ jsxRuntime.jsx(
219
+ BlurViewComponent,
220
+ {
221
+ intensity: resolved.blurAmount,
222
+ tint: resolved.blurTint,
223
+ experimentalBlurMethod: ANDROID_BLUR_METHOD,
224
+ style: reactNative.StyleSheet.absoluteFill
225
+ }
226
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
227
+ reactNative.View,
228
+ {
229
+ pointerEvents: "none",
230
+ style: [reactNative.StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]
231
+ }
232
+ ),
233
+ /* @__PURE__ */ jsxRuntime.jsx(
234
+ reactNative.View,
235
+ {
236
+ pointerEvents: "none",
237
+ style: [reactNative.StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]
238
+ }
239
+ ),
240
+ resolved.highlightColor !== "transparent" && (LinearGradientComponent ? /* @__PURE__ */ jsxRuntime.jsx(
241
+ LinearGradientComponent,
242
+ {
243
+ colors: [resolved.highlightColor, "transparent"],
244
+ start: { x: 0, y: 0 },
245
+ end: { x: 0, y: 1 },
246
+ style: styles.highlightGradient,
247
+ pointerEvents: "none"
248
+ }
249
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
250
+ reactNative.View,
251
+ {
252
+ pointerEvents: "none",
253
+ style: [
254
+ styles.highlightGradient,
255
+ { backgroundColor: resolved.highlightColor, opacity: 0.18 }
256
+ ]
257
+ }
258
+ )),
259
+ border && /* @__PURE__ */ jsxRuntime.jsx(
260
+ reactNative.View,
261
+ {
262
+ pointerEvents: "none",
263
+ style: [
264
+ reactNative.StyleSheet.absoluteFill,
265
+ { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor }
266
+ ]
267
+ }
268
+ ),
269
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles.content, contentStyle], children })
270
+ ] })
271
+ }
272
+ );
273
+ }
274
+ );
275
+ GlassView.displayName = "GlassView";
276
+ var styles = reactNative.StyleSheet.create({
277
+ shadowShell: {
278
+ // Shadow lives here — no overflow:hidden so Android elevation renders
279
+ },
280
+ clipShell: {
281
+ overflow: "hidden"
282
+ },
283
+ highlightGradient: {
284
+ position: "absolute",
285
+ top: 0,
286
+ left: 0,
287
+ right: 0,
288
+ height: "35%"
289
+ },
290
+ content: {
291
+ position: "relative"
292
+ }
293
+ });
294
+ var FrostPanel = React__default.default.memo(
295
+ ({ style, edges, borderRadius, children, ...glassProps }) => {
296
+ const radiusStyle = edges ? {
297
+ borderTopLeftRadius: edges.includes("top") ? borderRadius ?? 20 : 0,
298
+ borderTopRightRadius: edges.includes("top") ? borderRadius ?? 20 : 0,
299
+ borderBottomLeftRadius: edges.includes("bottom") ? borderRadius ?? 20 : 0,
300
+ borderBottomRightRadius: edges.includes("bottom") ? borderRadius ?? 20 : 0
301
+ } : { borderRadius: borderRadius ?? 20 };
302
+ return /* @__PURE__ */ jsxRuntime.jsx(
303
+ GlassView,
304
+ {
305
+ elevation: glassProps.elevation ?? 3,
306
+ style: [styles2.panel, style],
307
+ borderRadius: 0,
308
+ ...glassProps,
309
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: radiusStyle, children })
310
+ }
311
+ );
312
+ }
313
+ );
314
+ FrostPanel.displayName = "FrostPanel";
315
+ var styles2 = reactNative.StyleSheet.create({
316
+ panel: {
317
+ width: "100%"
318
+ }
319
+ });
320
+ function useGlassStyle(config) {
321
+ const { colorScheme } = reactnativelyTheme.useTheme();
322
+ return React.useMemo(() => resolveGlass(config, colorScheme), [config, colorScheme]);
323
+ }
324
+
325
+ exports.FrostPanel = FrostPanel;
326
+ exports.GLASS_CAPABILITY = GLASS_CAPABILITY;
327
+ exports.GlassView = GlassView;
328
+ exports.IS_FULL_GLASS = IS_FULL_GLASS;
329
+ exports.IS_NO_GLASS = IS_NO_GLASS;
330
+ exports.IS_PARTIAL_GLASS = IS_PARTIAL_GLASS;
331
+ exports.SUPPORTS_BLUR = SUPPORTS_BLUR;
332
+ exports.adjustBlurForCapability = adjustBlurForCapability;
333
+ exports.resolveGlass = resolveGlass;
334
+ exports.useGlassStyle = useGlassStyle;
335
+ //# sourceMappingURL=index.js.map
336
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/CapabilityDetector.ts","../src/engine/GlassEngine.ts","../src/components/GlassView/GlassView.tsx","../src/components/FrostPanel/FrostPanel.tsx","../src/hooks/useGlassStyle.ts"],"names":["IS_IOS","IS_ANDROID","getAndroidVersion","IS_WEB","glassTokens","React","useTheme","useMemo","Platform","jsx","View","jsxs","StyleSheet","styles"],"mappings":"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","file":"index.js","sourcesContent":["import { IS_IOS, IS_ANDROID, IS_WEB, getAndroidVersion } from 'reactnatively-utils';\n\nexport type GlassCapability = 'full' | 'partial' | 'none';\n\nfunction detectCapability(): GlassCapability {\n if (IS_IOS) return 'full';\n if (IS_ANDROID) {\n const version = getAndroidVersion();\n return version >= 31 ? 'partial' : 'none';\n }\n if (IS_WEB) return 'partial';\n return 'none';\n}\n\nexport const GLASS_CAPABILITY: GlassCapability = detectCapability();\nexport const SUPPORTS_BLUR: boolean = GLASS_CAPABILITY !== 'none';\nexport const IS_FULL_GLASS: boolean = GLASS_CAPABILITY === 'full';\nexport const IS_PARTIAL_GLASS: boolean = GLASS_CAPABILITY === 'partial';\nexport const IS_NO_GLASS: boolean = GLASS_CAPABILITY === 'none';\n\nexport function adjustBlurForCapability(intensity: number): number {\n if (GLASS_CAPABILITY === 'full') return intensity;\n if (GLASS_CAPABILITY === 'partial') return Math.round(intensity * 0.65);\n return 0;\n}\n\nexport const ANDROID_BLUR_METHOD = IS_ANDROID ? 'dimezisBlurView' : undefined;\n","import { glassTokens } from 'reactnatively-theme';\nimport type { ResolvedColorScheme } from 'reactnatively-theme';\nimport type { GlassConfig, ResolvedGlassStyle } from './GlassEngine.types';\nimport { GLASS_CAPABILITY, adjustBlurForCapability } from './CapabilityDetector';\n\n// Core resolver: takes a GlassConfig + color scheme, returns a fully\n// resolved style recipe that GlassView uses to render all layers.\nexport function resolveGlass(\n config: GlassConfig,\n colorScheme: ResolvedColorScheme,\n): ResolvedGlassStyle {\n const {\n elevation = 2,\n variant = 'surface',\n highlight = true,\n border = true,\n borderWidth = 1,\n blurOverride,\n tintOverride,\n } = config;\n\n const elevationConfig = glassTokens.elevation[elevation];\n\n // Blur\n const rawBlur = blurOverride ?? elevationConfig.blur;\n const blurAmount = adjustBlurForCapability(rawBlur);\n\n // Tint\n const tintColor = tintOverride ?? glassTokens.tint[colorScheme][variant];\n\n // Highlight\n let highlightColor = 'transparent';\n if (highlight === true) {\n highlightColor = glassTokens.highlight.medium;\n } else if (highlight !== false && highlight !== 'none') {\n highlightColor = glassTokens.highlight[highlight];\n }\n\n // Border\n const borderColor = border\n ? glassTokens.border[colorScheme].medium\n : 'transparent';\n\n // Shadow — glass shadows use a deep, soft spread\n const shadowColor = colorScheme === 'dark' ? '#000' : '#1a1a2e';\n const shadowOpacity = elevationConfig.shadowOpacity;\n const shadowRadius = elevationConfig.shadowRadius;\n const shadowOffset = { width: 0, height: elevationConfig.shadowY };\n const androidElevation = Math.round(elevation * 3);\n\n // BlurView tint hint — 'light' | 'dark' | 'default'\n const blurTint = colorScheme === 'dark' ? 'dark' : 'light';\n\n return {\n blurAmount,\n blurTint,\n tintColor,\n highlightColor,\n borderColor,\n borderWidth,\n shadowColor,\n shadowOpacity,\n shadowRadius,\n shadowOffset,\n androidElevation,\n capability: GLASS_CAPABILITY,\n };\n}\n","import React, { useMemo } from 'react';\nimport {\n View,\n StyleSheet,\n Platform,\n type ViewStyle,\n} from 'react-native';\nimport { useTheme } from 'reactnatively-theme';\nimport { resolveGlass } from '../../engine/GlassEngine';\nimport { IS_NO_GLASS, ANDROID_BLUR_METHOD } from '../../engine/CapabilityDetector';\nimport type { GlassViewProps } from './GlassView.types';\n\nlet BlurViewImpl: typeof import('expo-blur').BlurView | null = null;\nlet blurLoaded = false;\n\nlet LinearGradientImpl:\n | typeof import('react-native-linear-gradient').default\n | null = null;\nlet gradientLoaded = false;\n\nfunction loadBlurView(): typeof import('expo-blur').BlurView | null {\n if (blurLoaded) return BlurViewImpl;\n blurLoaded = true;\n try {\n // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires\n BlurViewImpl = require('expo-blur').BlurView;\n } catch {\n BlurViewImpl = null;\n }\n return BlurViewImpl;\n}\n\nfunction loadLinearGradient():\n | typeof import('react-native-linear-gradient').default\n | null {\n if (gradientLoaded) return LinearGradientImpl;\n gradientLoaded = true;\n try {\n // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires\n const gradientModule = require('react-native-linear-gradient');\n LinearGradientImpl = gradientModule?.default ?? gradientModule;\n } catch {\n LinearGradientImpl = null;\n }\n return LinearGradientImpl;\n}\n\n/**\n * GlassView — the foundational rendering primitive of the Liquid Glass system.\n *\n * Layer stack (bottom → top):\n * 1. Shadow shell — drop shadow / elevation (outer view, NO overflow:hidden)\n * 2. Clip shell — clips all glass layers to border radius (overflow:hidden)\n * 3. BlurView — native platform blur\n * 4. Tint overlay — semi-transparent color layer\n * 5. Highlight — top-edge refraction shimmer (LinearGradient)\n * 6. Border ring — 1px glass edge line\n * 7. Content — children, above all glass layers\n */\nexport const GlassView = React.memo<GlassViewProps>(\n ({\n elevation = 2,\n variant = 'surface',\n highlight = true,\n border = true,\n borderWidth = 1,\n borderRadius = 16,\n blurOverride,\n tintOverride,\n glow,\n style,\n contentStyle,\n children,\n testID,\n accessible,\n accessibilityLabel,\n accessibilityRole,\n }) => {\n const { colorScheme } = useTheme();\n\n const resolved = useMemo(\n () =>\n resolveGlass(\n { elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride },\n colorScheme,\n ),\n [elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride, colorScheme],\n );\n\n const shadowStyle = useMemo((): ViewStyle => {\n if (Platform.OS === 'android') {\n return { elevation: resolved.androidElevation };\n }\n return {\n shadowColor: resolved.shadowColor,\n shadowOffset: resolved.shadowOffset,\n shadowOpacity: resolved.shadowOpacity,\n shadowRadius: resolved.shadowRadius,\n };\n }, [resolved]);\n\n const glowStyle = useMemo((): ViewStyle => {\n if (!glow || Platform.OS !== 'ios') return {};\n return {\n shadowColor: glow.color,\n shadowOffset: { width: 0, height: 0 },\n shadowOpacity: glow.opacity ?? 0.35,\n shadowRadius: glow.radius ?? 24,\n };\n }, [glow]);\n\n const BlurViewComponent = loadBlurView();\n const LinearGradientComponent = loadLinearGradient();\n\n // Fallback: no-blur devices — solid semi-transparent + gradient only\n if (IS_NO_GLASS) {\n return (\n <View\n testID={testID}\n accessible={accessible}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n style={[styles.shadowShell, { borderRadius }, shadowStyle, style]}\n >\n <View style={[styles.clipShell, { borderRadius }]}>\n <View\n style={[\n StyleSheet.absoluteFill,\n { backgroundColor: resolved.tintColor },\n ]}\n />\n {resolved.highlightColor !== 'transparent' && (\n LinearGradientComponent ? (\n <LinearGradientComponent\n colors={[resolved.highlightColor, 'transparent']}\n start={{ x: 0, y: 0 }}\n end={{ x: 0, y: 1 }}\n style={styles.highlightGradient}\n />\n ) : (\n <View\n pointerEvents=\"none\"\n style={[\n styles.highlightGradient,\n { backgroundColor: resolved.highlightColor, opacity: 0.2 },\n ]}\n />\n )\n )}\n {border && (\n <View\n pointerEvents=\"none\"\n style={[\n StyleSheet.absoluteFill,\n { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor },\n ]}\n />\n )}\n <View style={[styles.content, contentStyle]}>{children}</View>\n </View>\n </View>\n );\n }\n\n return (\n <View\n testID={testID}\n accessible={accessible}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n style={[styles.shadowShell, { borderRadius }, shadowStyle, glowStyle, style]}\n >\n <View style={[styles.clipShell, { borderRadius }]}>\n {/* Layer 1: Native blur */}\n {BlurViewComponent ? (\n <BlurViewComponent\n intensity={resolved.blurAmount}\n tint={resolved.blurTint}\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore — experimentalBlurMethod is Android-only, conditionally applied\n experimentalBlurMethod={ANDROID_BLUR_METHOD}\n style={StyleSheet.absoluteFill}\n />\n ) : (\n <View\n pointerEvents=\"none\"\n style={[StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]}\n />\n )}\n\n {/* Layer 2: Tint overlay */}\n <View\n pointerEvents=\"none\"\n style={[StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]}\n />\n\n {/* Layer 3: Top-edge highlight — the \"liquid glass\" refraction shimmer */}\n {resolved.highlightColor !== 'transparent' && (\n LinearGradientComponent ? (\n <LinearGradientComponent\n colors={[resolved.highlightColor, 'transparent']}\n start={{ x: 0, y: 0 }}\n end={{ x: 0, y: 1 }}\n style={styles.highlightGradient}\n pointerEvents=\"none\"\n />\n ) : (\n <View\n pointerEvents=\"none\"\n style={[\n styles.highlightGradient,\n { backgroundColor: resolved.highlightColor, opacity: 0.18 },\n ]}\n />\n )\n )}\n\n {/* Layer 4: Glass edge border */}\n {border && (\n <View\n pointerEvents=\"none\"\n style={[\n StyleSheet.absoluteFill,\n { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor },\n ]}\n />\n )}\n\n {/* Layer 5: Children */}\n <View style={[styles.content, contentStyle]}>{children}</View>\n </View>\n </View>\n );\n },\n);\n\nGlassView.displayName = 'GlassView';\n\nconst styles = StyleSheet.create({\n shadowShell: {\n // Shadow lives here — no overflow:hidden so Android elevation renders\n },\n clipShell: {\n overflow: 'hidden',\n },\n highlightGradient: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '35%',\n },\n content: {\n position: 'relative',\n },\n});\n","import React from 'react';\nimport { View, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';\nimport { GlassView } from '../GlassView';\nimport type { GlassViewProps } from '../GlassView/GlassView.types';\n\n// FrostPanel: full-width glass surface for bottom sheets, headers, sidebars.\n// Unlike GlassView (which sizes to content), FrostPanel fills its container.\nexport interface FrostPanelProps extends Omit<GlassViewProps, 'style'> {\n style?: StyleProp<ViewStyle>;\n edges?: ('top' | 'bottom' | 'left' | 'right')[];\n}\n\nexport const FrostPanel = React.memo<FrostPanelProps>(\n ({ style, edges, borderRadius, children, ...glassProps }) => {\n // For panels, we typically want sharp edges on some sides\n // e.g., bottom sheet: round top, flat bottom (or vice versa)\n const radiusStyle = edges\n ? {\n borderTopLeftRadius: edges.includes('top') ? (borderRadius ?? 20) : 0,\n borderTopRightRadius: edges.includes('top') ? (borderRadius ?? 20) : 0,\n borderBottomLeftRadius: edges.includes('bottom') ? (borderRadius ?? 20) : 0,\n borderBottomRightRadius: edges.includes('bottom') ? (borderRadius ?? 20) : 0,\n }\n : { borderRadius: borderRadius ?? 20 };\n\n return (\n <GlassView\n elevation={glassProps.elevation ?? 3}\n style={[styles.panel, style]}\n borderRadius={0} // We handle radius manually for panels\n {...glassProps}\n >\n <View style={radiusStyle}>\n {children}\n </View>\n </GlassView>\n );\n },\n);\n\nFrostPanel.displayName = 'FrostPanel';\n\nconst styles = StyleSheet.create({\n panel: {\n width: '100%',\n },\n});\n","import { useMemo } from 'react';\nimport { useTheme } from 'reactnatively-theme';\nimport { resolveGlass } from '../engine/GlassEngine';\nimport type { GlassConfig, ResolvedGlassStyle } from '../engine/GlassEngine.types';\n\n// Hook: resolves the full glass style recipe using the current theme's color scheme.\n// Use this when building custom glass components outside of GlassView.\nexport function useGlassStyle(config: GlassConfig): ResolvedGlassStyle {\n const { colorScheme } = useTheme();\n return useMemo(() => resolveGlass(config, colorScheme), [config, colorScheme]);\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,321 @@
1
+ import { useTheme, glassTokens } from 'reactnatively-theme';
2
+ import { IS_IOS, IS_ANDROID, getAndroidVersion, IS_WEB } from 'reactnatively-utils';
3
+ import React, { useMemo } from 'react';
4
+ import { Platform, View, StyleSheet } from 'react-native';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ function detectCapability() {
14
+ if (IS_IOS) return "full";
15
+ if (IS_ANDROID) {
16
+ const version = getAndroidVersion();
17
+ return version >= 31 ? "partial" : "none";
18
+ }
19
+ if (IS_WEB) return "partial";
20
+ return "none";
21
+ }
22
+ var GLASS_CAPABILITY = detectCapability();
23
+ var SUPPORTS_BLUR = GLASS_CAPABILITY !== "none";
24
+ var IS_FULL_GLASS = GLASS_CAPABILITY === "full";
25
+ var IS_PARTIAL_GLASS = GLASS_CAPABILITY === "partial";
26
+ var IS_NO_GLASS = GLASS_CAPABILITY === "none";
27
+ function adjustBlurForCapability(intensity) {
28
+ if (GLASS_CAPABILITY === "full") return intensity;
29
+ if (GLASS_CAPABILITY === "partial") return Math.round(intensity * 0.65);
30
+ return 0;
31
+ }
32
+ var ANDROID_BLUR_METHOD = IS_ANDROID ? "dimezisBlurView" : void 0;
33
+
34
+ // src/engine/GlassEngine.ts
35
+ function resolveGlass(config, colorScheme) {
36
+ const {
37
+ elevation = 2,
38
+ variant = "surface",
39
+ highlight = true,
40
+ border = true,
41
+ borderWidth = 1,
42
+ blurOverride,
43
+ tintOverride
44
+ } = config;
45
+ const elevationConfig = glassTokens.elevation[elevation];
46
+ const rawBlur = blurOverride ?? elevationConfig.blur;
47
+ const blurAmount = adjustBlurForCapability(rawBlur);
48
+ const tintColor = tintOverride ?? glassTokens.tint[colorScheme][variant];
49
+ let highlightColor = "transparent";
50
+ if (highlight === true) {
51
+ highlightColor = glassTokens.highlight.medium;
52
+ } else if (highlight !== false && highlight !== "none") {
53
+ highlightColor = glassTokens.highlight[highlight];
54
+ }
55
+ const borderColor = border ? glassTokens.border[colorScheme].medium : "transparent";
56
+ const shadowColor = colorScheme === "dark" ? "#000" : "#1a1a2e";
57
+ const shadowOpacity = elevationConfig.shadowOpacity;
58
+ const shadowRadius = elevationConfig.shadowRadius;
59
+ const shadowOffset = { width: 0, height: elevationConfig.shadowY };
60
+ const androidElevation = Math.round(elevation * 3);
61
+ const blurTint = colorScheme === "dark" ? "dark" : "light";
62
+ return {
63
+ blurAmount,
64
+ blurTint,
65
+ tintColor,
66
+ highlightColor,
67
+ borderColor,
68
+ borderWidth,
69
+ shadowColor,
70
+ shadowOpacity,
71
+ shadowRadius,
72
+ shadowOffset,
73
+ androidElevation,
74
+ capability: GLASS_CAPABILITY
75
+ };
76
+ }
77
+ var BlurViewImpl = null;
78
+ var blurLoaded = false;
79
+ var LinearGradientImpl = null;
80
+ var gradientLoaded = false;
81
+ function loadBlurView() {
82
+ if (blurLoaded) return BlurViewImpl;
83
+ blurLoaded = true;
84
+ try {
85
+ BlurViewImpl = __require("expo-blur").BlurView;
86
+ } catch {
87
+ BlurViewImpl = null;
88
+ }
89
+ return BlurViewImpl;
90
+ }
91
+ function loadLinearGradient() {
92
+ if (gradientLoaded) return LinearGradientImpl;
93
+ gradientLoaded = true;
94
+ try {
95
+ const gradientModule = __require("react-native-linear-gradient");
96
+ LinearGradientImpl = gradientModule?.default ?? gradientModule;
97
+ } catch {
98
+ LinearGradientImpl = null;
99
+ }
100
+ return LinearGradientImpl;
101
+ }
102
+ var GlassView = React.memo(
103
+ ({
104
+ elevation = 2,
105
+ variant = "surface",
106
+ highlight = true,
107
+ border = true,
108
+ borderWidth = 1,
109
+ borderRadius = 16,
110
+ blurOverride,
111
+ tintOverride,
112
+ glow,
113
+ style,
114
+ contentStyle,
115
+ children,
116
+ testID,
117
+ accessible,
118
+ accessibilityLabel,
119
+ accessibilityRole
120
+ }) => {
121
+ const { colorScheme } = useTheme();
122
+ const resolved = useMemo(
123
+ () => resolveGlass(
124
+ { elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride },
125
+ colorScheme
126
+ ),
127
+ [elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride, colorScheme]
128
+ );
129
+ const shadowStyle = useMemo(() => {
130
+ if (Platform.OS === "android") {
131
+ return { elevation: resolved.androidElevation };
132
+ }
133
+ return {
134
+ shadowColor: resolved.shadowColor,
135
+ shadowOffset: resolved.shadowOffset,
136
+ shadowOpacity: resolved.shadowOpacity,
137
+ shadowRadius: resolved.shadowRadius
138
+ };
139
+ }, [resolved]);
140
+ const glowStyle = useMemo(() => {
141
+ if (!glow || Platform.OS !== "ios") return {};
142
+ return {
143
+ shadowColor: glow.color,
144
+ shadowOffset: { width: 0, height: 0 },
145
+ shadowOpacity: glow.opacity ?? 0.35,
146
+ shadowRadius: glow.radius ?? 24
147
+ };
148
+ }, [glow]);
149
+ const BlurViewComponent = loadBlurView();
150
+ const LinearGradientComponent = loadLinearGradient();
151
+ if (IS_NO_GLASS) {
152
+ return /* @__PURE__ */ jsx(
153
+ View,
154
+ {
155
+ testID,
156
+ accessible,
157
+ accessibilityLabel,
158
+ accessibilityRole,
159
+ style: [styles.shadowShell, { borderRadius }, shadowStyle, style],
160
+ children: /* @__PURE__ */ jsxs(View, { style: [styles.clipShell, { borderRadius }], children: [
161
+ /* @__PURE__ */ jsx(
162
+ View,
163
+ {
164
+ style: [
165
+ StyleSheet.absoluteFill,
166
+ { backgroundColor: resolved.tintColor }
167
+ ]
168
+ }
169
+ ),
170
+ resolved.highlightColor !== "transparent" && (LinearGradientComponent ? /* @__PURE__ */ jsx(
171
+ LinearGradientComponent,
172
+ {
173
+ colors: [resolved.highlightColor, "transparent"],
174
+ start: { x: 0, y: 0 },
175
+ end: { x: 0, y: 1 },
176
+ style: styles.highlightGradient
177
+ }
178
+ ) : /* @__PURE__ */ jsx(
179
+ View,
180
+ {
181
+ pointerEvents: "none",
182
+ style: [
183
+ styles.highlightGradient,
184
+ { backgroundColor: resolved.highlightColor, opacity: 0.2 }
185
+ ]
186
+ }
187
+ )),
188
+ border && /* @__PURE__ */ jsx(
189
+ View,
190
+ {
191
+ pointerEvents: "none",
192
+ style: [
193
+ StyleSheet.absoluteFill,
194
+ { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor }
195
+ ]
196
+ }
197
+ ),
198
+ /* @__PURE__ */ jsx(View, { style: [styles.content, contentStyle], children })
199
+ ] })
200
+ }
201
+ );
202
+ }
203
+ return /* @__PURE__ */ jsx(
204
+ View,
205
+ {
206
+ testID,
207
+ accessible,
208
+ accessibilityLabel,
209
+ accessibilityRole,
210
+ style: [styles.shadowShell, { borderRadius }, shadowStyle, glowStyle, style],
211
+ children: /* @__PURE__ */ jsxs(View, { style: [styles.clipShell, { borderRadius }], children: [
212
+ BlurViewComponent ? /* @__PURE__ */ jsx(
213
+ BlurViewComponent,
214
+ {
215
+ intensity: resolved.blurAmount,
216
+ tint: resolved.blurTint,
217
+ experimentalBlurMethod: ANDROID_BLUR_METHOD,
218
+ style: StyleSheet.absoluteFill
219
+ }
220
+ ) : /* @__PURE__ */ jsx(
221
+ View,
222
+ {
223
+ pointerEvents: "none",
224
+ style: [StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]
225
+ }
226
+ ),
227
+ /* @__PURE__ */ jsx(
228
+ View,
229
+ {
230
+ pointerEvents: "none",
231
+ style: [StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]
232
+ }
233
+ ),
234
+ resolved.highlightColor !== "transparent" && (LinearGradientComponent ? /* @__PURE__ */ jsx(
235
+ LinearGradientComponent,
236
+ {
237
+ colors: [resolved.highlightColor, "transparent"],
238
+ start: { x: 0, y: 0 },
239
+ end: { x: 0, y: 1 },
240
+ style: styles.highlightGradient,
241
+ pointerEvents: "none"
242
+ }
243
+ ) : /* @__PURE__ */ jsx(
244
+ View,
245
+ {
246
+ pointerEvents: "none",
247
+ style: [
248
+ styles.highlightGradient,
249
+ { backgroundColor: resolved.highlightColor, opacity: 0.18 }
250
+ ]
251
+ }
252
+ )),
253
+ border && /* @__PURE__ */ jsx(
254
+ View,
255
+ {
256
+ pointerEvents: "none",
257
+ style: [
258
+ StyleSheet.absoluteFill,
259
+ { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor }
260
+ ]
261
+ }
262
+ ),
263
+ /* @__PURE__ */ jsx(View, { style: [styles.content, contentStyle], children })
264
+ ] })
265
+ }
266
+ );
267
+ }
268
+ );
269
+ GlassView.displayName = "GlassView";
270
+ var styles = StyleSheet.create({
271
+ shadowShell: {
272
+ // Shadow lives here — no overflow:hidden so Android elevation renders
273
+ },
274
+ clipShell: {
275
+ overflow: "hidden"
276
+ },
277
+ highlightGradient: {
278
+ position: "absolute",
279
+ top: 0,
280
+ left: 0,
281
+ right: 0,
282
+ height: "35%"
283
+ },
284
+ content: {
285
+ position: "relative"
286
+ }
287
+ });
288
+ var FrostPanel = React.memo(
289
+ ({ style, edges, borderRadius, children, ...glassProps }) => {
290
+ const radiusStyle = edges ? {
291
+ borderTopLeftRadius: edges.includes("top") ? borderRadius ?? 20 : 0,
292
+ borderTopRightRadius: edges.includes("top") ? borderRadius ?? 20 : 0,
293
+ borderBottomLeftRadius: edges.includes("bottom") ? borderRadius ?? 20 : 0,
294
+ borderBottomRightRadius: edges.includes("bottom") ? borderRadius ?? 20 : 0
295
+ } : { borderRadius: borderRadius ?? 20 };
296
+ return /* @__PURE__ */ jsx(
297
+ GlassView,
298
+ {
299
+ elevation: glassProps.elevation ?? 3,
300
+ style: [styles2.panel, style],
301
+ borderRadius: 0,
302
+ ...glassProps,
303
+ children: /* @__PURE__ */ jsx(View, { style: radiusStyle, children })
304
+ }
305
+ );
306
+ }
307
+ );
308
+ FrostPanel.displayName = "FrostPanel";
309
+ var styles2 = StyleSheet.create({
310
+ panel: {
311
+ width: "100%"
312
+ }
313
+ });
314
+ function useGlassStyle(config) {
315
+ const { colorScheme } = useTheme();
316
+ return useMemo(() => resolveGlass(config, colorScheme), [config, colorScheme]);
317
+ }
318
+
319
+ export { FrostPanel, GLASS_CAPABILITY, GlassView, IS_FULL_GLASS, IS_NO_GLASS, IS_PARTIAL_GLASS, SUPPORTS_BLUR, adjustBlurForCapability, resolveGlass, useGlassStyle };
320
+ //# sourceMappingURL=index.mjs.map
321
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/engine/CapabilityDetector.ts","../src/engine/GlassEngine.ts","../src/components/GlassView/GlassView.tsx","../src/components/FrostPanel/FrostPanel.tsx","../src/hooks/useGlassStyle.ts"],"names":["React","jsx","styles","View","StyleSheet","useTheme","useMemo"],"mappings":"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","file":"index.mjs","sourcesContent":["import { IS_IOS, IS_ANDROID, IS_WEB, getAndroidVersion } from 'reactnatively-utils';\n\nexport type GlassCapability = 'full' | 'partial' | 'none';\n\nfunction detectCapability(): GlassCapability {\n if (IS_IOS) return 'full';\n if (IS_ANDROID) {\n const version = getAndroidVersion();\n return version >= 31 ? 'partial' : 'none';\n }\n if (IS_WEB) return 'partial';\n return 'none';\n}\n\nexport const GLASS_CAPABILITY: GlassCapability = detectCapability();\nexport const SUPPORTS_BLUR: boolean = GLASS_CAPABILITY !== 'none';\nexport const IS_FULL_GLASS: boolean = GLASS_CAPABILITY === 'full';\nexport const IS_PARTIAL_GLASS: boolean = GLASS_CAPABILITY === 'partial';\nexport const IS_NO_GLASS: boolean = GLASS_CAPABILITY === 'none';\n\nexport function adjustBlurForCapability(intensity: number): number {\n if (GLASS_CAPABILITY === 'full') return intensity;\n if (GLASS_CAPABILITY === 'partial') return Math.round(intensity * 0.65);\n return 0;\n}\n\nexport const ANDROID_BLUR_METHOD = IS_ANDROID ? 'dimezisBlurView' : undefined;\n","import { glassTokens } from 'reactnatively-theme';\nimport type { ResolvedColorScheme } from 'reactnatively-theme';\nimport type { GlassConfig, ResolvedGlassStyle } from './GlassEngine.types';\nimport { GLASS_CAPABILITY, adjustBlurForCapability } from './CapabilityDetector';\n\n// Core resolver: takes a GlassConfig + color scheme, returns a fully\n// resolved style recipe that GlassView uses to render all layers.\nexport function resolveGlass(\n config: GlassConfig,\n colorScheme: ResolvedColorScheme,\n): ResolvedGlassStyle {\n const {\n elevation = 2,\n variant = 'surface',\n highlight = true,\n border = true,\n borderWidth = 1,\n blurOverride,\n tintOverride,\n } = config;\n\n const elevationConfig = glassTokens.elevation[elevation];\n\n // Blur\n const rawBlur = blurOverride ?? elevationConfig.blur;\n const blurAmount = adjustBlurForCapability(rawBlur);\n\n // Tint\n const tintColor = tintOverride ?? glassTokens.tint[colorScheme][variant];\n\n // Highlight\n let highlightColor = 'transparent';\n if (highlight === true) {\n highlightColor = glassTokens.highlight.medium;\n } else if (highlight !== false && highlight !== 'none') {\n highlightColor = glassTokens.highlight[highlight];\n }\n\n // Border\n const borderColor = border\n ? glassTokens.border[colorScheme].medium\n : 'transparent';\n\n // Shadow — glass shadows use a deep, soft spread\n const shadowColor = colorScheme === 'dark' ? '#000' : '#1a1a2e';\n const shadowOpacity = elevationConfig.shadowOpacity;\n const shadowRadius = elevationConfig.shadowRadius;\n const shadowOffset = { width: 0, height: elevationConfig.shadowY };\n const androidElevation = Math.round(elevation * 3);\n\n // BlurView tint hint — 'light' | 'dark' | 'default'\n const blurTint = colorScheme === 'dark' ? 'dark' : 'light';\n\n return {\n blurAmount,\n blurTint,\n tintColor,\n highlightColor,\n borderColor,\n borderWidth,\n shadowColor,\n shadowOpacity,\n shadowRadius,\n shadowOffset,\n androidElevation,\n capability: GLASS_CAPABILITY,\n };\n}\n","import React, { useMemo } from 'react';\nimport {\n View,\n StyleSheet,\n Platform,\n type ViewStyle,\n} from 'react-native';\nimport { useTheme } from 'reactnatively-theme';\nimport { resolveGlass } from '../../engine/GlassEngine';\nimport { IS_NO_GLASS, ANDROID_BLUR_METHOD } from '../../engine/CapabilityDetector';\nimport type { GlassViewProps } from './GlassView.types';\n\nlet BlurViewImpl: typeof import('expo-blur').BlurView | null = null;\nlet blurLoaded = false;\n\nlet LinearGradientImpl:\n | typeof import('react-native-linear-gradient').default\n | null = null;\nlet gradientLoaded = false;\n\nfunction loadBlurView(): typeof import('expo-blur').BlurView | null {\n if (blurLoaded) return BlurViewImpl;\n blurLoaded = true;\n try {\n // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires\n BlurViewImpl = require('expo-blur').BlurView;\n } catch {\n BlurViewImpl = null;\n }\n return BlurViewImpl;\n}\n\nfunction loadLinearGradient():\n | typeof import('react-native-linear-gradient').default\n | null {\n if (gradientLoaded) return LinearGradientImpl;\n gradientLoaded = true;\n try {\n // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires\n const gradientModule = require('react-native-linear-gradient');\n LinearGradientImpl = gradientModule?.default ?? gradientModule;\n } catch {\n LinearGradientImpl = null;\n }\n return LinearGradientImpl;\n}\n\n/**\n * GlassView — the foundational rendering primitive of the Liquid Glass system.\n *\n * Layer stack (bottom → top):\n * 1. Shadow shell — drop shadow / elevation (outer view, NO overflow:hidden)\n * 2. Clip shell — clips all glass layers to border radius (overflow:hidden)\n * 3. BlurView — native platform blur\n * 4. Tint overlay — semi-transparent color layer\n * 5. Highlight — top-edge refraction shimmer (LinearGradient)\n * 6. Border ring — 1px glass edge line\n * 7. Content — children, above all glass layers\n */\nexport const GlassView = React.memo<GlassViewProps>(\n ({\n elevation = 2,\n variant = 'surface',\n highlight = true,\n border = true,\n borderWidth = 1,\n borderRadius = 16,\n blurOverride,\n tintOverride,\n glow,\n style,\n contentStyle,\n children,\n testID,\n accessible,\n accessibilityLabel,\n accessibilityRole,\n }) => {\n const { colorScheme } = useTheme();\n\n const resolved = useMemo(\n () =>\n resolveGlass(\n { elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride },\n colorScheme,\n ),\n [elevation, variant, highlight, border, borderWidth, blurOverride, tintOverride, colorScheme],\n );\n\n const shadowStyle = useMemo((): ViewStyle => {\n if (Platform.OS === 'android') {\n return { elevation: resolved.androidElevation };\n }\n return {\n shadowColor: resolved.shadowColor,\n shadowOffset: resolved.shadowOffset,\n shadowOpacity: resolved.shadowOpacity,\n shadowRadius: resolved.shadowRadius,\n };\n }, [resolved]);\n\n const glowStyle = useMemo((): ViewStyle => {\n if (!glow || Platform.OS !== 'ios') return {};\n return {\n shadowColor: glow.color,\n shadowOffset: { width: 0, height: 0 },\n shadowOpacity: glow.opacity ?? 0.35,\n shadowRadius: glow.radius ?? 24,\n };\n }, [glow]);\n\n const BlurViewComponent = loadBlurView();\n const LinearGradientComponent = loadLinearGradient();\n\n // Fallback: no-blur devices — solid semi-transparent + gradient only\n if (IS_NO_GLASS) {\n return (\n <View\n testID={testID}\n accessible={accessible}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n style={[styles.shadowShell, { borderRadius }, shadowStyle, style]}\n >\n <View style={[styles.clipShell, { borderRadius }]}>\n <View\n style={[\n StyleSheet.absoluteFill,\n { backgroundColor: resolved.tintColor },\n ]}\n />\n {resolved.highlightColor !== 'transparent' && (\n LinearGradientComponent ? (\n <LinearGradientComponent\n colors={[resolved.highlightColor, 'transparent']}\n start={{ x: 0, y: 0 }}\n end={{ x: 0, y: 1 }}\n style={styles.highlightGradient}\n />\n ) : (\n <View\n pointerEvents=\"none\"\n style={[\n styles.highlightGradient,\n { backgroundColor: resolved.highlightColor, opacity: 0.2 },\n ]}\n />\n )\n )}\n {border && (\n <View\n pointerEvents=\"none\"\n style={[\n StyleSheet.absoluteFill,\n { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor },\n ]}\n />\n )}\n <View style={[styles.content, contentStyle]}>{children}</View>\n </View>\n </View>\n );\n }\n\n return (\n <View\n testID={testID}\n accessible={accessible}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole={accessibilityRole}\n style={[styles.shadowShell, { borderRadius }, shadowStyle, glowStyle, style]}\n >\n <View style={[styles.clipShell, { borderRadius }]}>\n {/* Layer 1: Native blur */}\n {BlurViewComponent ? (\n <BlurViewComponent\n intensity={resolved.blurAmount}\n tint={resolved.blurTint}\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore — experimentalBlurMethod is Android-only, conditionally applied\n experimentalBlurMethod={ANDROID_BLUR_METHOD}\n style={StyleSheet.absoluteFill}\n />\n ) : (\n <View\n pointerEvents=\"none\"\n style={[StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]}\n />\n )}\n\n {/* Layer 2: Tint overlay */}\n <View\n pointerEvents=\"none\"\n style={[StyleSheet.absoluteFill, { backgroundColor: resolved.tintColor }]}\n />\n\n {/* Layer 3: Top-edge highlight — the \"liquid glass\" refraction shimmer */}\n {resolved.highlightColor !== 'transparent' && (\n LinearGradientComponent ? (\n <LinearGradientComponent\n colors={[resolved.highlightColor, 'transparent']}\n start={{ x: 0, y: 0 }}\n end={{ x: 0, y: 1 }}\n style={styles.highlightGradient}\n pointerEvents=\"none\"\n />\n ) : (\n <View\n pointerEvents=\"none\"\n style={[\n styles.highlightGradient,\n { backgroundColor: resolved.highlightColor, opacity: 0.18 },\n ]}\n />\n )\n )}\n\n {/* Layer 4: Glass edge border */}\n {border && (\n <View\n pointerEvents=\"none\"\n style={[\n StyleSheet.absoluteFill,\n { borderWidth: resolved.borderWidth, borderColor: resolved.borderColor },\n ]}\n />\n )}\n\n {/* Layer 5: Children */}\n <View style={[styles.content, contentStyle]}>{children}</View>\n </View>\n </View>\n );\n },\n);\n\nGlassView.displayName = 'GlassView';\n\nconst styles = StyleSheet.create({\n shadowShell: {\n // Shadow lives here — no overflow:hidden so Android elevation renders\n },\n clipShell: {\n overflow: 'hidden',\n },\n highlightGradient: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '35%',\n },\n content: {\n position: 'relative',\n },\n});\n","import React from 'react';\nimport { View, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';\nimport { GlassView } from '../GlassView';\nimport type { GlassViewProps } from '../GlassView/GlassView.types';\n\n// FrostPanel: full-width glass surface for bottom sheets, headers, sidebars.\n// Unlike GlassView (which sizes to content), FrostPanel fills its container.\nexport interface FrostPanelProps extends Omit<GlassViewProps, 'style'> {\n style?: StyleProp<ViewStyle>;\n edges?: ('top' | 'bottom' | 'left' | 'right')[];\n}\n\nexport const FrostPanel = React.memo<FrostPanelProps>(\n ({ style, edges, borderRadius, children, ...glassProps }) => {\n // For panels, we typically want sharp edges on some sides\n // e.g., bottom sheet: round top, flat bottom (or vice versa)\n const radiusStyle = edges\n ? {\n borderTopLeftRadius: edges.includes('top') ? (borderRadius ?? 20) : 0,\n borderTopRightRadius: edges.includes('top') ? (borderRadius ?? 20) : 0,\n borderBottomLeftRadius: edges.includes('bottom') ? (borderRadius ?? 20) : 0,\n borderBottomRightRadius: edges.includes('bottom') ? (borderRadius ?? 20) : 0,\n }\n : { borderRadius: borderRadius ?? 20 };\n\n return (\n <GlassView\n elevation={glassProps.elevation ?? 3}\n style={[styles.panel, style]}\n borderRadius={0} // We handle radius manually for panels\n {...glassProps}\n >\n <View style={radiusStyle}>\n {children}\n </View>\n </GlassView>\n );\n },\n);\n\nFrostPanel.displayName = 'FrostPanel';\n\nconst styles = StyleSheet.create({\n panel: {\n width: '100%',\n },\n});\n","import { useMemo } from 'react';\nimport { useTheme } from 'reactnatively-theme';\nimport { resolveGlass } from '../engine/GlassEngine';\nimport type { GlassConfig, ResolvedGlassStyle } from '../engine/GlassEngine.types';\n\n// Hook: resolves the full glass style recipe using the current theme's color scheme.\n// Use this when building custom glass components outside of GlassView.\nexport function useGlassStyle(config: GlassConfig): ResolvedGlassStyle {\n const { colorScheme } = useTheme();\n return useMemo(() => resolveGlass(config, colorScheme), [config, colorScheme]);\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "reactnatively-glass",
3
+ "version": "0.1.0",
4
+ "description": "Liquid Glass rendering engine for Reactnatively — blur, vibrancy, depth",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "sideEffects": false,
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "dependencies": {
20
+ "reactnatively-animations": "0.1.0",
21
+ "reactnatively-theme": "0.1.0",
22
+ "reactnatively-utils": "0.1.0"
23
+ },
24
+ "peerDependencies": {
25
+ "expo-blur": ">=13.0.0",
26
+ "react": ">=18.0.0",
27
+ "react-native": ">=0.73.0",
28
+ "react-native-linear-gradient": ">=2.8.0",
29
+ "react-native-reanimated": ">=3.6.0"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "expo-blur": {
33
+ "optional": true
34
+ },
35
+ "react-native-linear-gradient": {
36
+ "optional": true
37
+ },
38
+ "react-native-reanimated": {
39
+ "optional": false
40
+ }
41
+ },
42
+ "devDependencies": {
43
+ "tsup": "^8.2.4",
44
+ "typescript": "^5.5.3",
45
+ "@reactnatively/tsconfig": "0.0.0"
46
+ },
47
+ "keywords": [
48
+ "react-native",
49
+ "expo",
50
+ "glass",
51
+ "liquid-glass",
52
+ "blur",
53
+ "vibrancy",
54
+ "glassmorphism",
55
+ "ui",
56
+ "design-system",
57
+ "typescript"
58
+ ],
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "https://github.com/hakizimana-fred/reactnatively.git",
62
+ "directory": "packages/glass"
63
+ },
64
+ "license": "MIT",
65
+ "publishConfig": {
66
+ "access": "public"
67
+ },
68
+ "scripts": {
69
+ "build": "tsup",
70
+ "dev": "tsup --watch",
71
+ "typecheck": "tsc --noEmit",
72
+ "clean": "rm -rf dist"
73
+ }
74
+ }