@honeypathkar/react-native-lq-bottom-bar 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/ios/LQBottomBarView.swift +46 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -288,6 +288,14 @@ choice would force every consuming app to add that repository to its own
|
|
|
288
288
|
**Labels show but glyphs do not.** Your icon component is not forwarding its
|
|
289
289
|
ref to an `<Svg>`. See the warning section above — this is nearly always it.
|
|
290
290
|
|
|
291
|
+
**The bar is lit on the wrong tab.** Fixed in 0.1.1. The bar restores its
|
|
292
|
+
highlight to `selectedIndex` after every press, to honour the report-not-commit
|
|
293
|
+
contract; before 0.1.1 it did so synchronously inside UIKit's own selection
|
|
294
|
+
callback, where UIKit overrode it. The highlight stuck to the tapped tab, and
|
|
295
|
+
since `selectedIndex` had not changed value nothing re-applied it — so the bar
|
|
296
|
+
stayed out of step with the app until some other prop change happened to
|
|
297
|
+
correct it. Upgrade.
|
|
298
|
+
|
|
291
299
|
**A white or mismatched strip under the bar.** The bar is in flow and the
|
|
292
300
|
translucent material has only your root view behind it. Give that container a
|
|
293
301
|
background colour, or move to the overlaid layout.
|
|
@@ -43,7 +43,24 @@ public final class LQBottomBarView: UIView, UITabBarDelegate {
|
|
|
43
43
|
|
|
44
44
|
/// `[{ title, icon }]`, set from JS. Re-builds the items in place.
|
|
45
45
|
@objc public var items: NSArray = [] {
|
|
46
|
-
didSet {
|
|
46
|
+
didSet {
|
|
47
|
+
/*
|
|
48
|
+
REBUILD ONLY WHEN THE ITEMS ACTUALLY CHANGED.
|
|
49
|
+
|
|
50
|
+
The JS side rebuilds its `items` array on every render, so this prop
|
|
51
|
+
arrives constantly with identical contents. Acting on each one calls
|
|
52
|
+
`setItems`, which THROWS AWAY the existing `UITabBarItem`s and the
|
|
53
|
+
selection animation running on them — a rebuild landing mid-animation
|
|
54
|
+
is how a press ends up looking like it half-happened.
|
|
55
|
+
|
|
56
|
+
`isEqual` on the arrays is a deep compare of the dictionaries inside,
|
|
57
|
+
which is what "the same bar" means here. The icon values are cached
|
|
58
|
+
data URIs on the JS side, so equal renders really do produce equal
|
|
59
|
+
strings rather than merely equivalent ones.
|
|
60
|
+
*/
|
|
61
|
+
if items.isEqual(oldValue) { return }
|
|
62
|
+
rebuildItems()
|
|
63
|
+
}
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
/// Which item is lit. Setting it animates, which is the point.
|
|
@@ -264,7 +281,11 @@ public final class LQBottomBarView: UIView, UITabBarDelegate {
|
|
|
264
281
|
guard let items = tabBar.items, index >= 0, index < items.count else {
|
|
265
282
|
return
|
|
266
283
|
}
|
|
267
|
-
|
|
284
|
+
let target = items[index]
|
|
285
|
+
// Already there. Re-assigning restarts the capsule animation, and this
|
|
286
|
+
// runs on every prop transaction, so the bar would shimmer continuously.
|
|
287
|
+
if tabBar.selectedItem === target { return }
|
|
288
|
+
tabBar.selectedItem = target
|
|
268
289
|
}
|
|
269
290
|
|
|
270
291
|
// MARK: - UITabBarDelegate
|
|
@@ -280,8 +301,28 @@ public final class LQBottomBarView: UIView, UITabBarDelegate {
|
|
|
280
301
|
*/
|
|
281
302
|
onTabSelected?(["index": item.tag])
|
|
282
303
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
304
|
+
/*
|
|
305
|
+
THE SNAP-BACK HAS TO WAIT A TURN, and this is the whole reason the bar
|
|
306
|
+
can end up lit on a tab the app is not showing.
|
|
307
|
+
|
|
308
|
+
UIKit calls this delegate method while it is still settling its OWN
|
|
309
|
+
selection — on iOS 26 the capsule is mid-animation — so assigning
|
|
310
|
+
`selectedItem` from in here is assigning into a change that has not
|
|
311
|
+
finished. UIKit wins, the highlight stays on the tapped item, and because
|
|
312
|
+
`selectedIndex` never changed VALUE, the prop never fires `didSet` again
|
|
313
|
+
and nothing ever corrects it. The bar is then permanently out of step with
|
|
314
|
+
the app: Events lit while the Profile screen is on screen.
|
|
315
|
+
|
|
316
|
+
Hopping to the next runloop turn puts the assignment after UIKit has
|
|
317
|
+
finished, where it sticks.
|
|
318
|
+
|
|
319
|
+
Reading `selectedIndex` late is a second benefit rather than a hazard: if
|
|
320
|
+
JS accepted the press and sent a new index in the meantime, this applies
|
|
321
|
+
THAT, so an accepted press does not visibly bounce back before moving
|
|
322
|
+
forward again.
|
|
323
|
+
*/
|
|
324
|
+
DispatchQueue.main.async { [weak self] in
|
|
325
|
+
self?.applySelection()
|
|
326
|
+
}
|
|
286
327
|
}
|
|
287
328
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honeypathkar/react-native-lq-bottom-bar",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The real iOS UITabBar (liquid glass on iOS 26) and a matching blurred Android bar, taking React icons rather than only images",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|