@ajuarezso/capacitor-liquid-glass 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -9,12 +9,23 @@ export interface LiquidGlassTabItem {
|
|
|
9
9
|
/** Optional badge value (e.g. "3" or "•"). */
|
|
10
10
|
badge?: string;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Visual style of the tab bar background.
|
|
14
|
+
* - `'default'` (default): Liquid Glass on iOS 26+ (translucent blurred).
|
|
15
|
+
* - `'ultraThin'`: minimal blur (`UIBlurEffect.Style.systemUltraThinMaterial`),
|
|
16
|
+
* more see-through than default.
|
|
17
|
+
* - `'transparent'`: no background, no blur — content behind shows through 100%.
|
|
18
|
+
* Trade-off: legibilidad puede sufrir sobre contenido caótico.
|
|
19
|
+
*/
|
|
20
|
+
export type TabBarStyle = 'default' | 'ultraThin' | 'transparent';
|
|
12
21
|
export interface ShowTabBarOptions {
|
|
13
22
|
items: LiquidGlassTabItem[];
|
|
14
23
|
/** Index of the initially selected item. Defaults to 0. */
|
|
15
24
|
selectedIndex?: number;
|
|
16
25
|
/** Tint color for selected state, hex "#RRGGBB". Defaults to iOS system tint. */
|
|
17
26
|
tintColor?: string;
|
|
27
|
+
/** Visual style of the tab bar background. Defaults to `'default'`. */
|
|
28
|
+
tabBarStyle?: TabBarStyle;
|
|
18
29
|
}
|
|
19
30
|
export interface SetSelectedTabOptions {
|
|
20
31
|
/** Either pass numeric index or the item id. */
|
|
@@ -23,6 +23,7 @@ public class LiquidGlassPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
23
23
|
}
|
|
24
24
|
let selectedIndex = call.getInt("selectedIndex") ?? 0
|
|
25
25
|
let tintHex = call.getString("tintColor")
|
|
26
|
+
let styleRaw = call.getString("tabBarStyle") ?? "default"
|
|
26
27
|
|
|
27
28
|
let items = rawItems.compactMap { LiquidGlassTabItem(dictionary: $0) }
|
|
28
29
|
guard !items.isEmpty else {
|
|
@@ -32,7 +33,7 @@ public class LiquidGlassPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
32
33
|
|
|
33
34
|
DispatchQueue.main.async { [weak self] in
|
|
34
35
|
guard let self else { return }
|
|
35
|
-
self.presentTabBar(items: items, selectedIndex: selectedIndex, tintHex: tintHex)
|
|
36
|
+
self.presentTabBar(items: items, selectedIndex: selectedIndex, tintHex: tintHex, styleRaw: styleRaw)
|
|
36
37
|
call.resolve()
|
|
37
38
|
}
|
|
38
39
|
}
|
|
@@ -85,7 +86,7 @@ public class LiquidGlassPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
private func presentTabBar(items: [LiquidGlassTabItem], selectedIndex: Int, tintHex: String
|
|
89
|
+
private func presentTabBar(items: [LiquidGlassTabItem], selectedIndex: Int, tintHex: String?, styleRaw: String) {
|
|
89
90
|
guard let window = UIApplication.shared.capacitorWindow else { return }
|
|
90
91
|
|
|
91
92
|
if tabBarOverlay == nil {
|
|
@@ -102,8 +103,9 @@ public class LiquidGlassPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
102
103
|
tabBarOverlay = overlay
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
let style = LiquidGlassTabBarStyle(rawValue: styleRaw) ?? .default
|
|
105
107
|
tabBarOverlay?.attach(to: window)
|
|
106
|
-
tabBarOverlay?.configure(items: items, selectedIndex: selectedIndex, tintHex: tintHex)
|
|
108
|
+
tabBarOverlay?.configure(items: items, selectedIndex: selectedIndex, tintHex: tintHex, style: style)
|
|
107
109
|
tabBarOverlay?.show()
|
|
108
110
|
}
|
|
109
111
|
}
|
|
@@ -21,6 +21,16 @@ struct LiquidGlassTabItem {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/// Visual style of the tab bar background.
|
|
25
|
+
enum LiquidGlassTabBarStyle: String {
|
|
26
|
+
/// Translucent blurred — auto-applies Liquid Glass on iOS 26+ SDK.
|
|
27
|
+
case `default`
|
|
28
|
+
/// Minimal blur (`systemUltraThinMaterial`) — more see-through than default.
|
|
29
|
+
case ultraThin
|
|
30
|
+
/// No background, no blur — content behind shows through 100%.
|
|
31
|
+
case transparent
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
/// A floating UITabBar overlay that adopts iOS 26 Liquid Glass automatically
|
|
25
35
|
/// when the app is built against the iOS 26 SDK. On earlier iOS the bar falls
|
|
26
36
|
/// back to the translucent blurred UITabBar appearance.
|
|
@@ -43,13 +53,9 @@ final class LiquidGlassTabBarOverlay: NSObject {
|
|
|
43
53
|
tabBar.translatesAutoresizingMaskIntoConstraints = false
|
|
44
54
|
tabBar.delegate = self
|
|
45
55
|
|
|
46
|
-
// Default appearance triggers Liquid Glass automatically on iOS 26
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
tabBar.standardAppearance = appearance
|
|
50
|
-
if #available(iOS 15.0, *) {
|
|
51
|
-
tabBar.scrollEdgeAppearance = appearance
|
|
52
|
-
}
|
|
56
|
+
// Default appearance: triggers Liquid Glass automatically on iOS 26+.
|
|
57
|
+
// (Sobreescrito en `configure(...)` si el caller pidió otro estilo).
|
|
58
|
+
applyAppearance(tabBar, style: .default)
|
|
53
59
|
|
|
54
60
|
window.addSubview(tabBar)
|
|
55
61
|
|
|
@@ -63,7 +69,32 @@ final class LiquidGlassTabBarOverlay: NSObject {
|
|
|
63
69
|
emitLayout()
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
/// Aplica el appearance correspondiente al estilo solicitado.
|
|
73
|
+
/// - `default`: Liquid Glass (iOS 26+) o blur translúcido como fallback.
|
|
74
|
+
/// - `ultraThin`: blur mínimo `systemUltraThinMaterial` — más ver-through.
|
|
75
|
+
/// - `transparent`: sin background ni blur — content behind se ve completo.
|
|
76
|
+
private func applyAppearance(_ tabBar: UITabBar, style: LiquidGlassTabBarStyle) {
|
|
77
|
+
let appearance = UITabBarAppearance()
|
|
78
|
+
switch style {
|
|
79
|
+
case .default:
|
|
80
|
+
appearance.configureWithDefaultBackground()
|
|
81
|
+
case .ultraThin:
|
|
82
|
+
appearance.configureWithDefaultBackground()
|
|
83
|
+
appearance.backgroundEffect = UIBlurEffect(style: .systemUltraThinMaterial)
|
|
84
|
+
appearance.backgroundColor = UIColor.clear
|
|
85
|
+
case .transparent:
|
|
86
|
+
appearance.configureWithTransparentBackground()
|
|
87
|
+
appearance.backgroundEffect = nil
|
|
88
|
+
appearance.backgroundColor = UIColor.clear
|
|
89
|
+
appearance.shadowColor = UIColor.clear
|
|
90
|
+
}
|
|
91
|
+
tabBar.standardAppearance = appearance
|
|
92
|
+
if #available(iOS 15.0, *) {
|
|
93
|
+
tabBar.scrollEdgeAppearance = appearance
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func configure(items: [LiquidGlassTabItem], selectedIndex: Int, tintHex: String?, style: LiquidGlassTabBarStyle) {
|
|
67
98
|
guard let tabBar else { return }
|
|
68
99
|
|
|
69
100
|
// Preserve selection across re-configs (badge changes, etc.)
|
|
@@ -73,6 +104,9 @@ final class LiquidGlassTabBarOverlay: NSObject {
|
|
|
73
104
|
|
|
74
105
|
self.items = items
|
|
75
106
|
|
|
107
|
+
// Re-aplica appearance por si el caller cambió de estilo en runtime.
|
|
108
|
+
applyAppearance(tabBar, style: style)
|
|
109
|
+
|
|
76
110
|
let uiItems: [UITabBarItem] = items.enumerated().map { index, item in
|
|
77
111
|
let tab = UITabBarItem(
|
|
78
112
|
title: item.label,
|
|
@@ -108,12 +142,46 @@ final class LiquidGlassTabBarOverlay: NSObject {
|
|
|
108
142
|
}
|
|
109
143
|
|
|
110
144
|
func show() {
|
|
111
|
-
tabBar
|
|
145
|
+
guard let tabBar = tabBar else { return }
|
|
146
|
+
// Si ya está visible, no hacer nada (evita flicker en re-show consecutivos)
|
|
147
|
+
if !tabBar.isHidden && tabBar.alpha == 1.0 { emitLayout(); return }
|
|
148
|
+
// Reset estado pre-animación
|
|
149
|
+
tabBar.isHidden = false
|
|
150
|
+
tabBar.alpha = 0
|
|
151
|
+
tabBar.transform = CGAffineTransform(translationX: 0, y: 20)
|
|
152
|
+
// Fade-in + slide-up (curva native iOS para apariciones)
|
|
153
|
+
UIView.animate(
|
|
154
|
+
withDuration: 0.28,
|
|
155
|
+
delay: 0,
|
|
156
|
+
usingSpringWithDamping: 0.85,
|
|
157
|
+
initialSpringVelocity: 0,
|
|
158
|
+
options: [.curveEaseOut, .allowUserInteraction],
|
|
159
|
+
animations: {
|
|
160
|
+
tabBar.alpha = 1
|
|
161
|
+
tabBar.transform = .identity
|
|
162
|
+
},
|
|
163
|
+
completion: nil
|
|
164
|
+
)
|
|
112
165
|
emitLayout()
|
|
113
166
|
}
|
|
114
167
|
|
|
115
168
|
func hide() {
|
|
116
|
-
tabBar
|
|
169
|
+
guard let tabBar = tabBar else { return }
|
|
170
|
+
if tabBar.isHidden { return }
|
|
171
|
+
// Fade-out + slide-down (más rápido que el show — el exit es snappy)
|
|
172
|
+
UIView.animate(
|
|
173
|
+
withDuration: 0.18,
|
|
174
|
+
delay: 0,
|
|
175
|
+
options: [.curveEaseIn, .allowUserInteraction],
|
|
176
|
+
animations: {
|
|
177
|
+
tabBar.alpha = 0
|
|
178
|
+
tabBar.transform = CGAffineTransform(translationX: 0, y: 20)
|
|
179
|
+
},
|
|
180
|
+
completion: { _ in
|
|
181
|
+
tabBar.isHidden = true
|
|
182
|
+
tabBar.transform = .identity
|
|
183
|
+
}
|
|
184
|
+
)
|
|
117
185
|
}
|
|
118
186
|
|
|
119
187
|
func setSelectedIndex(_ index: Int) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ajuarezso/capacitor-liquid-glass",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "iOS 26 Liquid Glass native chrome (TabBar, NavigationBar, Alerts, Sheets) for Capacitor apps. Falls back gracefully on iOS < 26 and Android.",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|