@nativescript-community/ui-bottom-navigation 0.0.0-stage → 1.0.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/index.ios.js ADDED
@@ -0,0 +1,1022 @@
1
+ // Types
2
+ import { BottomAccessory } from './bottom-accessory';
3
+ import { BottomSearchContent } from './search-content';
4
+ import { TabContentItem } from '@nativescript-community/ui-core-tabs/tab-content-item';
5
+ import { TabNavigationBase, getIconSpecSize, itemsProperty, selectedIndexProperty, tabStripProperty } from '@nativescript-community/ui-core-tabs/tab-navigation-base';
6
+ import { TabsPosition } from '@nativescript-community/ui-core-tabs/tab-navigation/index-common';
7
+ import { TabStrip } from '@nativescript-community/ui-core-tabs/tab-strip';
8
+ import { TabStripItem } from '@nativescript-community/ui-core-tabs/tab-strip-item';
9
+ // Types
10
+ // Requires
11
+ import { CSSType, Color, Device, Font, Frame, IOSHelper, ImageSource, Property, Utils, View, booleanConverter } from '@nativescript/core';
12
+ import { getTransformedText } from '@nativescript/core/ui/text-base';
13
+ import { SDK_VERSION } from '@nativescript/core/utils';
14
+ export { TabContentItem, TabStrip, TabStripItem };
15
+ const maxTabsCount = 5;
16
+ const isPhone = Device.deviceType === 'Phone';
17
+ // Liquid Glass (iOS 26+) ignores unselectedItemTintColor and UITabBarAppearance item colors when rendering
18
+ // template images, so state colors have to be baked into AlwaysOriginal images.
19
+ const preTintIcons = SDK_VERSION >= 26;
20
+ var MDTabBarControllerImpl = /** @class */ (function (_super) {
21
+ __extends(MDTabBarControllerImpl, _super);
22
+ function MDTabBarControllerImpl() {
23
+ return _super !== null && _super.apply(this, arguments) || this;
24
+ }
25
+ MDTabBarControllerImpl.initWithOwner = function (owner) {
26
+ var handler = MDTabBarControllerImpl.alloc().init();
27
+ handler._owner = owner;
28
+ handler._preventTraitCollectionChanges = false;
29
+ return handler;
30
+ };
31
+ MDTabBarControllerImpl.prototype.viewDidLoad = function () {
32
+ _super.prototype.viewDidLoad.call(this);
33
+ // the system tab bar style is used (Liquid Glass on iOS 26+): no forced background or size class
34
+ };
35
+ MDTabBarControllerImpl.prototype.viewWillAppear = function (animated) {
36
+ _super.prototype.viewWillAppear.call(this, animated);
37
+ var owner = this._owner.get();
38
+ if (!owner) {
39
+ return;
40
+ }
41
+ // Unify translucent and opaque bars layout
42
+ this.extendedLayoutIncludesOpaqueBars = true;
43
+ IOSHelper.updateAutoAdjustScrollInsets(this, owner);
44
+ if (!owner.parent) {
45
+ owner.callLoaded();
46
+ }
47
+ };
48
+ MDTabBarControllerImpl.prototype.viewDidDisappear = function (animated) {
49
+ var _a;
50
+ _super.prototype.viewDidDisappear.call(this, animated);
51
+ var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.get();
52
+ if (owner && !owner.parent && owner.isLoaded && !this.presentedViewController) {
53
+ owner.callUnloaded();
54
+ }
55
+ };
56
+ MDTabBarControllerImpl.prototype.viewWillTransitionToSizeWithTransitionCoordinator = function (size, coordinator) {
57
+ var _this = this;
58
+ var _a;
59
+ _super.prototype.viewWillTransitionToSizeWithTransitionCoordinator.call(this, size, coordinator);
60
+ if (!((_a = this._owner) === null || _a === void 0 ? void 0 : _a.get())) {
61
+ return;
62
+ }
63
+ coordinator.animateAlongsideTransitionCompletion(function () {
64
+ var _a, _b;
65
+ var owner = (_a = _this._owner) === null || _a === void 0 ? void 0 : _a.get();
66
+ if ((_b = owner === null || owner === void 0 ? void 0 : owner.tabStrip) === null || _b === void 0 ? void 0 : _b.items) {
67
+ var tabStrip_1 = owner.tabStrip;
68
+ tabStrip_1.items.forEach(function (tabStripItem) {
69
+ updateBackgroundPositions(tabStrip_1, tabStripItem);
70
+ var index = tabStripItem.index;
71
+ var tabBarItemController = owner.mItemControllers[index];
72
+ if (tabBarItemController) {
73
+ updateTitleAndIconPositions(tabStripItem, tabBarItemController.tabBarItem, tabBarItemController);
74
+ }
75
+ });
76
+ }
77
+ }, null);
78
+ };
79
+ // Mind implementation for other controllers
80
+ MDTabBarControllerImpl.prototype.traitCollectionDidChange = function (previousTraitCollection) {
81
+ var _a, _b, _c;
82
+ _super.prototype.traitCollectionDidChange.call(this, previousTraitCollection);
83
+ if (this._preventTraitCollectionChanges) {
84
+ return;
85
+ }
86
+ if (SDK_VERSION >= 13) {
87
+ var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.get();
88
+ if (owner && ((_c = (_b = this.traitCollection).hasDifferentColorAppearanceComparedToTraitCollection) === null || _c === void 0 ? void 0 : _c.call(_b, previousTraitCollection))) {
89
+ owner.notify({
90
+ eventName: IOSHelper.traitCollectionColorAppearanceChangedEvent,
91
+ object: owner
92
+ });
93
+ }
94
+ }
95
+ };
96
+ return MDTabBarControllerImpl;
97
+ }(UITabBarController));
98
+ var SearchHandlerImpl = /** @class */ (function (_super) {
99
+ __extends(SearchHandlerImpl, _super);
100
+ function SearchHandlerImpl() {
101
+ return _super !== null && _super.apply(this, arguments) || this;
102
+ }
103
+ SearchHandlerImpl.initWithOwner = function (owner) {
104
+ var handler = SearchHandlerImpl.new();
105
+ handler._owner = owner;
106
+ return handler;
107
+ };
108
+ SearchHandlerImpl.prototype.updateSearchResultsForSearchController = function (searchController) {
109
+ var _a;
110
+ (_a = this._owner.get()) === null || _a === void 0 ? void 0 : _a._onSearchText(searchController.searchBar.text);
111
+ };
112
+ SearchHandlerImpl.prototype.searchBarSearchButtonClicked = function (searchBar) {
113
+ var _a;
114
+ (_a = this._owner.get()) === null || _a === void 0 ? void 0 : _a._onSearchSubmit(searchBar.text);
115
+ };
116
+ SearchHandlerImpl.ObjCProtocols = [UISearchResultsUpdating, UISearchBarDelegate];
117
+ return SearchHandlerImpl;
118
+ }(NSObject));
119
+ var BNTabBarControllerDelegateImpl = /** @class */ (function (_super) {
120
+ __extends(BNTabBarControllerDelegateImpl, _super);
121
+ function BNTabBarControllerDelegateImpl() {
122
+ return _super !== null && _super.apply(this, arguments) || this;
123
+ }
124
+ BNTabBarControllerDelegateImpl.initWithOwner = function (owner) {
125
+ var delegate = BNTabBarControllerDelegateImpl.alloc().init();
126
+ delegate._owner = owner;
127
+ return delegate;
128
+ };
129
+ BNTabBarControllerDelegateImpl.prototype.tabBarControllerShouldSelectViewController = function (tabBarController, viewController) {
130
+ // TODO
131
+ // if (Trace.isEnabled()) {
132
+ // Trace.write("TabView.delegate.SHOULD_select(" + tabBarController + ", " + viewController + ");", Trace.categories.Debug);
133
+ // }
134
+ var owner = this._owner.get();
135
+ if (owner) {
136
+ // "< More" cannot be visible after clicking on the main tab bar buttons.
137
+ var backToMoreWillBeVisible = false;
138
+ owner._handleTwoNavigationBars(backToMoreWillBeVisible);
139
+ if (owner.mItemControllers.length) {
140
+ var position = owner.mItemControllers.indexOf(viewController);
141
+ if (position > -1) {
142
+ var tabStrip = owner.tabStrip;
143
+ var tabStripItems = tabStrip && tabStrip.items;
144
+ if (tabStripItems && tabStripItems[position]) {
145
+ tabStripItems[position]._emit(TabStripItem.tapEvent);
146
+ tabStrip.notify({
147
+ eventName: TabStrip.itemTapEvent,
148
+ object: tabStrip,
149
+ index: position
150
+ });
151
+ }
152
+ }
153
+ }
154
+ }
155
+ if (tabBarController.selectedViewController === viewController) {
156
+ return false;
157
+ }
158
+ tabBarController._willSelectViewController = viewController;
159
+ return true;
160
+ };
161
+ /**
162
+ * tabs mode (search tab): the identifiers of the item tabs are `tab-<index>`, the search tab keeps the selected index
163
+ */
164
+ BNTabBarControllerDelegateImpl.prototype.tabBarControllerDidSelectTabPreviousTab = function (tabBarController, tab, previousTab) {
165
+ var owner = this._owner.get();
166
+ var identifier = tab === null || tab === void 0 ? void 0 : tab.identifier;
167
+ if (owner && identifier && identifier.startsWith('tab-')) {
168
+ var index = parseInt(identifier.slice(4), 10);
169
+ var controller = owner.mItemControllers[index];
170
+ if (controller) {
171
+ owner._onViewControllerShown(controller);
172
+ }
173
+ }
174
+ };
175
+ BNTabBarControllerDelegateImpl.prototype.tabBarControllerDidSelectViewController = function (tabBarController, viewController) {
176
+ // TODO
177
+ // if (Trace.isEnabled()) {
178
+ // Trace.write("TabView.delegate.DID_select(" + tabBarController + ", " + viewController + ");", Trace.categories.Debug);
179
+ // }
180
+ var owner = this._owner.get();
181
+ if (owner) {
182
+ owner._onViewControllerShown(viewController);
183
+ }
184
+ tabBarController._willSelectViewController = undefined;
185
+ };
186
+ BNTabBarControllerDelegateImpl.ObjCProtocols = [UITabBarControllerDelegate];
187
+ return BNTabBarControllerDelegateImpl;
188
+ }(NSObject));
189
+ var BNNavigationControllerDelegateImpl = /** @class */ (function (_super) {
190
+ __extends(BNNavigationControllerDelegateImpl, _super);
191
+ function BNNavigationControllerDelegateImpl() {
192
+ return _super !== null && _super.apply(this, arguments) || this;
193
+ }
194
+ BNNavigationControllerDelegateImpl.initWithOwner = function (owner) {
195
+ var delegate = BNNavigationControllerDelegateImpl.alloc().init();
196
+ delegate._owner = owner;
197
+ return delegate;
198
+ };
199
+ BNNavigationControllerDelegateImpl.prototype.navigationControllerWillShowViewControllerAnimated = function (navigationController, viewController, animated) {
200
+ // TODO
201
+ // if (Trace.isEnabled()) {
202
+ // Trace.write("TabView.moreNavigationController.WILL_show(" + navigationController + ", " + viewController + ", " + animated + ");", Trace.categories.Debug);
203
+ // }
204
+ var owner = this._owner.get();
205
+ if (owner) {
206
+ // If viewController is one of our tab item controllers, then "< More" will be visible shortly.
207
+ // Otherwise viewController is the UIMoreListController which shows the list of all tabs beyond the 4th tab.
208
+ var backToMoreWillBeVisible = owner.mItemControllers.indexOf(viewController) > -1;
209
+ owner._handleTwoNavigationBars(backToMoreWillBeVisible);
210
+ }
211
+ };
212
+ BNNavigationControllerDelegateImpl.prototype.navigationControllerDidShowViewControllerAnimated = function (navigationController, viewController, animated) {
213
+ // TODO
214
+ // if (Trace.isEnabled()) {
215
+ // Trace.write("TabView.moreNavigationController.DID_show(" + navigationController + ", " + viewController + ", " + animated + ");", Trace.categories.Debug);
216
+ // }
217
+ // We don't need Edit button in More screen.
218
+ navigationController.navigationBar.topItem.rightBarButtonItem = null;
219
+ var owner = this._owner.get();
220
+ if (owner) {
221
+ owner._onViewControllerShown(viewController);
222
+ }
223
+ };
224
+ BNNavigationControllerDelegateImpl.ObjCProtocols = [UINavigationControllerDelegate];
225
+ return BNNavigationControllerDelegateImpl;
226
+ }(NSObject));
227
+ function updateBackgroundPositions(tabStrip, tabStripItem) {
228
+ let bgView = tabStripItem.bgView;
229
+ const index = tabStripItem.index;
230
+ const width = tabStrip.nativeView.frame.size.width / tabStrip.items.length;
231
+ const frame = CGRectMake(width * index, 0, width, tabStrip.nativeView.frame.size.width);
232
+ if (!bgView) {
233
+ bgView = UIView.alloc().initWithFrame(frame);
234
+ tabStrip.nativeView.insertSubviewAtIndex(bgView, 0);
235
+ tabStripItem.bgView = bgView;
236
+ }
237
+ else {
238
+ bgView.frame = frame;
239
+ }
240
+ const backgroundColor = tabStripItem.style.backgroundColor;
241
+ if (backgroundColor) {
242
+ bgView.backgroundColor = backgroundColor instanceof Color ? backgroundColor.ios : backgroundColor;
243
+ }
244
+ else {
245
+ // always default to at least a solid white background as fallback
246
+ // building with Xcode 13 causes bgView with no background to be fully transparent unless a css background-color is set - this allows original default behavior to work as it always did
247
+ bgView.backgroundColor = null;
248
+ }
249
+ }
250
+ function updateTitleAndIconPositions(tabStripItem, tabBarItem, controller) {
251
+ if (!tabStripItem || !tabBarItem) {
252
+ return;
253
+ }
254
+ // For iOS <11 icon is *always* above the text.
255
+ // For iOS 11 icon is above the text *only* on phones in portrait mode.
256
+ const orientation = controller.interfaceOrientation;
257
+ const isPortrait = orientation !== 4 /* UIInterfaceOrientation.LandscapeLeft */ && orientation !== 3 /* UIInterfaceOrientation.LandscapeRight */;
258
+ const isIconAboveTitle = SDK_VERSION < 11 || (isPhone && isPortrait);
259
+ if (!tabStripItem.iconSource) {
260
+ if (isIconAboveTitle) {
261
+ tabBarItem.titlePositionAdjustment = {
262
+ horizontal: 0,
263
+ vertical: -20
264
+ };
265
+ }
266
+ else {
267
+ tabBarItem.titlePositionAdjustment = { horizontal: 0, vertical: 0 };
268
+ }
269
+ }
270
+ if (!tabStripItem.title) {
271
+ if (isIconAboveTitle) {
272
+ tabBarItem.imageInsets = new UIEdgeInsets({
273
+ top: 6,
274
+ left: 0,
275
+ bottom: -6,
276
+ right: 0
277
+ });
278
+ }
279
+ else {
280
+ tabBarItem.imageInsets = new UIEdgeInsets({
281
+ top: 0,
282
+ left: 0,
283
+ bottom: 0,
284
+ right: 0
285
+ });
286
+ }
287
+ }
288
+ }
289
+ export const iosCustomPositioningProperty = new Property({
290
+ name: 'iosCustomPositioning',
291
+ defaultValue: false,
292
+ valueConverter: booleanConverter
293
+ });
294
+ export { BottomAccessory, BottomSearchContent };
295
+ const MINIMIZE_BEHAVIORS = { automatic: 0, never: 1, onScrollDown: 2, onScrollUp: 3 };
296
+ export const minimizeBehaviorProperty = new Property({ name: 'minimizeBehavior', defaultValue: 'automatic' });
297
+ export const searchTabProperty = new Property({ name: 'searchTab', defaultValue: false, valueConverter: booleanConverter });
298
+ export const searchHintProperty = new Property({ name: 'searchHint', defaultValue: '' });
299
+ export const searchContentProperty = new Property({
300
+ name: 'searchContent',
301
+ valueChanged: (target, oldValue, newValue) => {
302
+ if (oldValue) {
303
+ target._removeView(oldValue);
304
+ }
305
+ if (newValue) {
306
+ target._addView(newValue);
307
+ }
308
+ target.updateSearchTab();
309
+ }
310
+ });
311
+ export const accessoryProperty = new Property({
312
+ name: 'accessory',
313
+ valueChanged: (target, oldValue, newValue) => {
314
+ if (oldValue) {
315
+ target._removeView(oldValue);
316
+ }
317
+ if (newValue) {
318
+ target._addView(newValue);
319
+ }
320
+ target.updateAccessory();
321
+ }
322
+ });
323
+ let BottomNavigation = class BottomNavigation extends TabNavigationBase {
324
+ constructor() {
325
+ super();
326
+ /** the controllers of the items: `viewControllers` is null when the tab bar uses `tabs` (search tab) */
327
+ this.mItemControllers = [];
328
+ /** the UITab of each item controller: a controller can not be in two UITab */
329
+ this.mItemTabs = new Map();
330
+ this.tabsPosition = TabsPosition.Bottom;
331
+ this.mIconsCache = {};
332
+ this.viewController = MDTabBarControllerImpl.initWithOwner(new WeakRef(this));
333
+ }
334
+ createNativeView() {
335
+ return this.viewController.view;
336
+ }
337
+ initNativeView() {
338
+ super.initNativeView();
339
+ this.mDelegate = BNTabBarControllerDelegateImpl.initWithOwner(new WeakRef(this));
340
+ this.mMoreNavigationControllerDelegate = BNNavigationControllerDelegateImpl.initWithOwner(new WeakRef(this));
341
+ if (!this.tabStrip) {
342
+ this.viewController.tabBar.hidden = true;
343
+ }
344
+ }
345
+ disposeNativeView() {
346
+ this.mDelegate = null;
347
+ this.mMoreNavigationControllerDelegate = null;
348
+ super.disposeNativeView();
349
+ }
350
+ onLoaded() {
351
+ super.onLoaded();
352
+ this.setViewControllers(this.items);
353
+ this.updateAccessory();
354
+ this.updateSearchTab();
355
+ const selectedIndex = this.selectedIndex;
356
+ const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].content;
357
+ if (selectedView instanceof Frame) {
358
+ selectedView._pushInFrameStackRecursive();
359
+ }
360
+ this.viewController.delegate = this.mDelegate;
361
+ this.onSelectedIndexChanged(selectedIndex, selectedIndex);
362
+ }
363
+ // the accessory is a child of the view, but it is not in the native tree of the controller
364
+ _addChildFromBuilder(name, value) {
365
+ if (value instanceof BottomAccessory) {
366
+ this.accessory = value;
367
+ return;
368
+ }
369
+ if (name === 'SearchContent' || (value && value.__searchContent)) {
370
+ this.searchContent = value;
371
+ return;
372
+ }
373
+ super._addChildFromBuilder(name, value);
374
+ }
375
+ eachChild(callback) {
376
+ super.eachChild(callback);
377
+ if (this.accessory) {
378
+ callback(this.accessory);
379
+ }
380
+ if (this.searchContent) {
381
+ callback(this.searchContent);
382
+ }
383
+ }
384
+ eachChildView(callback) {
385
+ super.eachChildView(callback);
386
+ if (this.accessory) {
387
+ callback(this.accessory);
388
+ }
389
+ if (this.searchContent) {
390
+ callback(this.searchContent);
391
+ }
392
+ }
393
+ _addViewToNativeVisualTree(child, atIndex) {
394
+ if (child === this.accessory || child === this.searchContent) {
395
+ return true;
396
+ }
397
+ return super._addViewToNativeVisualTree(child, atIndex);
398
+ }
399
+ _removeViewFromNativeVisualTree(child) {
400
+ if (child === this.accessory || child === this.searchContent) {
401
+ return;
402
+ }
403
+ super._removeViewFromNativeVisualTree(child);
404
+ }
405
+ _onSearchText(text) {
406
+ this.notify({ eventName: 'search', object: this, text: text || '' });
407
+ }
408
+ _onSearchSubmit(text) {
409
+ this.notify({ eventName: 'searchSubmit', object: this, text: text || '' });
410
+ }
411
+ /**
412
+ * iOS 18+: the UISearchTab at the end of the tab bar. The regular tabs stay view controllers, the search tab is added with the `tabs` API.
413
+ */
414
+ stripItemsLoaded() {
415
+ const items = this.tabStrip?.items;
416
+ return !items || items.every((item) => item.isLoaded);
417
+ }
418
+ updateSearchTab() {
419
+ const controller = this.viewController;
420
+ const UISearchTab = global.UISearchTab;
421
+ if (!controller || !UISearchTab || !('tabs' in controller) || !this.isLoaded) {
422
+ return;
423
+ }
424
+ // The tabs copy the title and the icons of the bar items. The property setters of the native init call us before the strip items are loaded
425
+ // (empty bar items): the pass of `onLoaded` has them.
426
+ if (this.searchTab && !this.stripItemsLoaded()) {
427
+ return;
428
+ }
429
+ if (!this.searchTab) {
430
+ if (this.mSearchTab) {
431
+ controller.tabs = NSArray.arrayWithArray(this.getRegularTabs());
432
+ this.mSearchTab = null;
433
+ }
434
+ return;
435
+ }
436
+ if (this.mSearchTab) {
437
+ this.updateSearchController();
438
+ return;
439
+ }
440
+ // the content of the search tab: a view controller hosting `searchContent`
441
+ const content = this.searchContent;
442
+ let viewController;
443
+ if (content) {
444
+ viewController = IOSHelper.UILayoutViewController.initWithOwner(new WeakRef(content));
445
+ viewController.view.addSubview(content.nativeViewProtected);
446
+ content.viewController = viewController;
447
+ }
448
+ else {
449
+ viewController = UIViewController.new();
450
+ }
451
+ this.mSearchViewController = viewController;
452
+ this.mSearchHandler = this.mSearchHandler || SearchHandlerImpl.initWithOwner(new WeakRef(this));
453
+ const searchController = UISearchController.alloc().initWithSearchResultsController(null);
454
+ searchController.searchResultsUpdater = this.mSearchHandler;
455
+ searchController.searchBar.delegate = this.mSearchHandler;
456
+ // the results are in the content of the tab, not in a controller of the search controller
457
+ searchController.obscuresBackgroundDuringPresentation = false;
458
+ this.mSearchController = searchController;
459
+ viewController.navigationItem.searchController = searchController;
460
+ const searchTab = UISearchTab.alloc().initWithViewControllerProvider(() => {
461
+ const navigation = UINavigationController.alloc().initWithRootViewController(viewController);
462
+ return navigation;
463
+ });
464
+ searchTab.automaticallyActivatesSearch = true;
465
+ this.mSearchTab = searchTab;
466
+ this.updateSearchController();
467
+ const before = this.getRegularTabs();
468
+ // the tabs of the controllers are reused: detach the previous ones first
469
+ if (this.viewController.tabs && this.viewController.tabs.count) {
470
+ this.viewController.tabs = NSArray.array();
471
+ }
472
+ controller.tabs = NSArray.arrayWithArray([...before, searchTab]);
473
+ }
474
+ /**
475
+ * `viewControllers` and `tabs` are exclusive: with a search tab every tab is a UITab wrapping the controller of the item
476
+ */
477
+ getRegularTabs() {
478
+ const UITab = global.UITab;
479
+ const tabs = [];
480
+ for (let i = 0; i < this.mItemControllers.length; i++) {
481
+ const controller = this.mItemControllers[i];
482
+ // the tab bar item of the strip item: it has the title and the icons
483
+ const item = this.tabStrip?.items?.[i]?.nativeView || controller.tabBarItem;
484
+ let tab = this.mItemTabs.get(controller);
485
+ if (!tab) {
486
+ tab = UITab.alloc().initWithTitleImageIdentifierViewControllerProvider(item?.title || '', item?.image || null, `tab-${i}`, () => controller);
487
+ this.mItemTabs.set(controller, tab);
488
+ }
489
+ else {
490
+ // follows the tab bar item (title, icon, badge)
491
+ tab.title = item?.title || '';
492
+ tab.image = item?.image || null;
493
+ }
494
+ tab.badgeValue = item?.badgeValue || null;
495
+ tabs.push(tab);
496
+ }
497
+ return tabs;
498
+ }
499
+ updateSearchController() {
500
+ if (this.mSearchController) {
501
+ this.mSearchController.searchBar.placeholder = this.searchHint || null;
502
+ }
503
+ }
504
+ /**
505
+ * iOS 26: the UITabAccessory of the tab bar controller
506
+ */
507
+ updateAccessory() {
508
+ const controller = this.viewController;
509
+ const UITabAccessory = global.UITabAccessory;
510
+ if (!controller || !UITabAccessory || !('bottomAccessory' in controller)) {
511
+ return;
512
+ }
513
+ const content = this.accessory?.nativeViewProtected;
514
+ controller.bottomAccessory = content ? UITabAccessory.alloc().initWithContentView(content) : null;
515
+ }
516
+ [searchTabProperty.setNative](value) {
517
+ this.updateSearchTab();
518
+ }
519
+ [searchHintProperty.setNative](value) {
520
+ this.updateSearchController();
521
+ }
522
+ [minimizeBehaviorProperty.setNative](value) {
523
+ const controller = this.viewController;
524
+ if ('tabBarMinimizeBehavior' in controller) {
525
+ controller.tabBarMinimizeBehavior = MINIMIZE_BEHAVIORS[value] ?? 0;
526
+ }
527
+ }
528
+ onUnloaded() {
529
+ this.viewController.delegate = null;
530
+ this.viewController.moreNavigationController.delegate = null;
531
+ super.onUnloaded();
532
+ this.items.forEach((item, i) => {
533
+ item.unloadView(item.content);
534
+ });
535
+ }
536
+ // @ts-ignore
537
+ get ios() {
538
+ return this.viewController;
539
+ }
540
+ layoutNativeView(left, top, right, bottom) {
541
+ if (this.iosCustomPositioning) {
542
+ super.layoutNativeView(left, top, right, bottom);
543
+ }
544
+ }
545
+ _setNativeViewFrame(nativeView, frame) {
546
+ if (this.iosCustomPositioning) {
547
+ super._setNativeViewFrame(nativeView, frame);
548
+ }
549
+ }
550
+ onSelectedIndexChanged(oldIndex, newIndex) {
551
+ const items = this.items;
552
+ if (!items) {
553
+ return;
554
+ }
555
+ if (this.unloadOnTabChange) {
556
+ const oldItem = items[oldIndex];
557
+ if (oldItem) {
558
+ oldItem.canBeLoaded = false;
559
+ oldItem.unloadView(oldItem.content);
560
+ }
561
+ }
562
+ const newItem = items[newIndex];
563
+ if (newItem && this.isLoaded) {
564
+ const selectedView = items[newIndex].content;
565
+ if (selectedView instanceof Frame) {
566
+ selectedView._pushInFrameStackRecursive();
567
+ }
568
+ newItem.canBeLoaded = true;
569
+ newItem.loadView(newItem.content);
570
+ }
571
+ const tabStripItems = this.tabStrip && this.tabStrip.items;
572
+ if (tabStripItems) {
573
+ if (tabStripItems[newIndex]) {
574
+ tabStripItems[newIndex]._emit(TabStripItem.selectEvent);
575
+ }
576
+ if (oldIndex !== newIndex && tabStripItems[oldIndex]) {
577
+ tabStripItems[oldIndex]._emit(TabStripItem.unselectEvent);
578
+ }
579
+ }
580
+ super.onSelectedIndexChanged(oldIndex, newIndex);
581
+ }
582
+ getTabBarBackgroundColor() {
583
+ return this.viewController.tabBar.barTintColor;
584
+ }
585
+ setTabBarBackgroundColor(value) {
586
+ this.viewController.tabBar.backgroundColor = this.viewController.tabBar.barTintColor = value instanceof Color ? value.ios : value;
587
+ this.updateAllItemsColors();
588
+ }
589
+ setTabBarItemTitle(tabStripItem, value) {
590
+ tabStripItem.nativeView.title = value;
591
+ this.syncSearchTabs();
592
+ }
593
+ /**
594
+ * With a search tab, every tab is a UITab: they follow the title, the icons and the badge of the bar items
595
+ */
596
+ syncSearchTabs() {
597
+ if (this.mSearchTab) {
598
+ this.getRegularTabs();
599
+ }
600
+ }
601
+ setTabBarItemBackgroundColor(tabStripItem, value) {
602
+ if (!this.tabStrip || !tabStripItem) {
603
+ return;
604
+ }
605
+ updateBackgroundPositions(this.tabStrip, tabStripItem);
606
+ }
607
+ setTabBarItemColor(tabStripItem, value) {
608
+ this.setViewAttributes(tabStripItem.nativeView, tabStripItem.label);
609
+ }
610
+ setItemColors() {
611
+ if (this.mSelectedItemColor) {
612
+ this.viewController.tabBar.selectedImageTintColor = this.mSelectedItemColor.ios;
613
+ }
614
+ if (this.mUnSelectedItemColor) {
615
+ this.viewController.tabBar.unselectedItemTintColor = this.mUnSelectedItemColor.ios;
616
+ }
617
+ }
618
+ setIconColor(tabStripItem, forceReload = false) {
619
+ if (forceReload || (!this.mUnSelectedItemColor && !this.mSelectedItemColor)) {
620
+ if (preTintIcons && (this.mUnSelectedItemColor || this.mSelectedItemColor)) {
621
+ this.setPreTintedIcons(tabStripItem);
622
+ return;
623
+ }
624
+ // if selectedItemColor or unSelectedItemColor is set we don't respect the color from the style
625
+ const tabStripColor = this.selectedIndex === tabStripItem.index ? this.mSelectedItemColor : this.mUnSelectedItemColor;
626
+ const image = this.getIcon(tabStripItem, tabStripColor);
627
+ tabStripItem.nativeView.image = image;
628
+ tabStripItem.nativeView.selectedImage = image;
629
+ }
630
+ }
631
+ setPreTintedIcons(tabStripItem) {
632
+ // selectedImage is always set: when nil, UIKit falls back to the (pre-tinted) unselected image
633
+ tabStripItem.nativeView.image = this.getIcon(tabStripItem, this.mUnSelectedItemColor, true);
634
+ tabStripItem.nativeView.selectedImage = this.getIcon(tabStripItem, this.mSelectedItemColor, true);
635
+ }
636
+ setTabBarIconColor(tabStripItem, value) {
637
+ this.setIconColor(tabStripItem);
638
+ this.syncSearchTabs();
639
+ }
640
+ setTabBarIconSource(tabStripItem, value) {
641
+ this.updateItemColors(tabStripItem);
642
+ this.syncSearchTabs();
643
+ }
644
+ setTabBarItemFontInternal(tabStripItem, value) {
645
+ this.setViewAttributes(tabStripItem.nativeView, tabStripItem.label);
646
+ }
647
+ setTabBarItemTextTransform(tabStripItem, value) {
648
+ tabStripItem.nativeView.title = getTransformedText(tabStripItem.label.text, value);
649
+ }
650
+ getTabBarHighlightColor() {
651
+ return this.viewController.tabBar.tintColor;
652
+ }
653
+ setTabBarHighlightColor(value) {
654
+ this.viewController.tabBar.tintColor = value instanceof Color ? value.ios : value;
655
+ }
656
+ getTabBarSelectedItemColor() {
657
+ return this.mSelectedItemColor;
658
+ }
659
+ setTabBarSelectedItemColor(value) {
660
+ this.mSelectedItemColor = value;
661
+ this.updateAllItemsColors();
662
+ }
663
+ getTabBarUnSelectedItemColor() {
664
+ return this.mUnSelectedItemColor;
665
+ }
666
+ setTabBarUnSelectedItemColor(value) {
667
+ this.mUnSelectedItemColor = value;
668
+ this.updateAllItemsColors();
669
+ }
670
+ onMeasure(widthMeasureSpec, heightMeasureSpec) {
671
+ const width = Utils.layout.getMeasureSpecSize(widthMeasureSpec);
672
+ const widthMode = Utils.layout.getMeasureSpecMode(widthMeasureSpec);
673
+ const height = Utils.layout.getMeasureSpecSize(heightMeasureSpec);
674
+ const heightMode = Utils.layout.getMeasureSpecMode(heightMeasureSpec);
675
+ const widthAndState = View.resolveSizeAndState(width, width, widthMode, 0);
676
+ const heightAndState = View.resolveSizeAndState(height, height, heightMode, 0);
677
+ this.setMeasuredDimension(widthAndState, heightAndState);
678
+ }
679
+ _onViewControllerShown(viewController) {
680
+ // This method could be called with the moreNavigationController or its list controller, so we have to check.
681
+ // TODO
682
+ // if (Trace.isEnabled()) {
683
+ // Trace.write("TabView._onViewControllerShown(" + viewController + ");", Trace.categories.Debug);
684
+ // }
685
+ const shownIndex = this.mItemControllers.indexOf(viewController);
686
+ if (shownIndex > -1) {
687
+ this.selectedIndex = shownIndex;
688
+ }
689
+ else {
690
+ // TODO
691
+ // if (Trace.isEnabled()) {
692
+ // Trace.write("TabView._onViewControllerShown: viewController is not one of our viewControllers", Trace.categories.Debug);
693
+ // }
694
+ }
695
+ }
696
+ _handleTwoNavigationBars(backToMoreWillBeVisible) {
697
+ // TODO
698
+ // if (Trace.isEnabled()) {
699
+ // Trace.write(`TabView._handleTwoNavigationBars(backToMoreWillBeVisible: ${backToMoreWillBeVisible})`, Trace.categories.Debug);
700
+ // }
701
+ // The "< Back" and "< More" navigation bars should not be visible simultaneously.
702
+ const page = this.page || this._selectedView.page || this._selectedView.currentPage;
703
+ if (!page || !page.frame) {
704
+ return;
705
+ }
706
+ const actionBarVisible = page.frame._getNavBarVisible(page);
707
+ if (backToMoreWillBeVisible && actionBarVisible) {
708
+ page.frame.ios._disableNavBarAnimation = true;
709
+ page.actionBarHidden = true;
710
+ page.frame.ios._disableNavBarAnimation = false;
711
+ this._actionBarHiddenByTabView = true;
712
+ // TODO
713
+ // if (Trace.isEnabled()) {
714
+ // Trace.write(`TabView hid action bar`, Trace.categories.Debug);
715
+ // }
716
+ return;
717
+ }
718
+ if (!backToMoreWillBeVisible && this._actionBarHiddenByTabView) {
719
+ page.frame.ios._disableNavBarAnimation = true;
720
+ page.actionBarHidden = false;
721
+ page.frame.ios._disableNavBarAnimation = false;
722
+ this._actionBarHiddenByTabView = undefined;
723
+ // TODO
724
+ // if (Trace.isEnabled()) {
725
+ // Trace.write(`TabView restored action bar`, Trace.categories.Debug);
726
+ // }
727
+ return;
728
+ }
729
+ }
730
+ getViewController(item) {
731
+ let newController = item.content ? item.content.viewController : null;
732
+ if (newController) {
733
+ item.setViewController(newController, newController.view);
734
+ return newController;
735
+ }
736
+ if (item.content.ios instanceof UIViewController) {
737
+ newController = item.content.ios;
738
+ item.setViewController(newController, newController.view);
739
+ }
740
+ else if (item.content.ios && item.content.ios.controller instanceof UIViewController) {
741
+ newController = item.content.ios.controller;
742
+ item.setViewController(newController, newController.view);
743
+ }
744
+ else {
745
+ newController = IOSHelper.UILayoutViewController.initWithOwner(new WeakRef(item.content));
746
+ newController.view.addSubview(item.content.nativeViewProtected);
747
+ item.content.viewController = newController;
748
+ item.setViewController(newController, item.content.nativeViewProtected);
749
+ }
750
+ return newController;
751
+ }
752
+ setViewControllers(items) {
753
+ const length = items ? items.length : 0;
754
+ if (length === 0) {
755
+ this.viewController.viewControllers = null;
756
+ return;
757
+ }
758
+ // Limit both tabContentItems and tabStripItems to 5 in order to prevent iOS 'more' button
759
+ items = items.slice(0, maxTabsCount);
760
+ const controllers = NSMutableArray.alloc().initWithCapacity(length);
761
+ if (this.tabStrip) {
762
+ this.tabStrip.setNativeView(this.viewController.tabBar);
763
+ }
764
+ items.forEach((item, i) => {
765
+ const controller = this.getViewController(item);
766
+ if (this.tabStrip && this.tabStrip.items && this.tabStrip.items[i]) {
767
+ const tabStripItem = this.tabStrip.items[i];
768
+ const tabBarItem = this.createTabBarItem(tabStripItem, i);
769
+ updateTitleAndIconPositions(tabStripItem, tabBarItem, controller);
770
+ this.setViewAttributes(tabBarItem, tabStripItem.label);
771
+ controller.tabBarItem = tabBarItem;
772
+ tabStripItem.index = i;
773
+ tabStripItem.setNativeView(tabBarItem);
774
+ }
775
+ controllers.addObject(controller);
776
+ });
777
+ this.setItemImages();
778
+ this.mItemControllers = [];
779
+ for (let i = 0; i < controllers.count; i++) {
780
+ this.mItemControllers.push(controllers.objectAtIndex(i));
781
+ }
782
+ this.viewController.viewControllers = controllers;
783
+ this.viewController.customizableViewControllers = null;
784
+ // When we set this.viewController.viewControllers, someone is clearing the moreNavigationController.delegate, so we have to reassign it each time here.
785
+ this.viewController.moreNavigationController.delegate = this.mMoreNavigationControllerDelegate;
786
+ // `viewControllers` replaced the tabs: the search tab is added again
787
+ this.mSearchTab = null;
788
+ this.updateSearchTab();
789
+ }
790
+ setItemImages() {
791
+ if (this.mSelectedItemColor || this.mUnSelectedItemColor) {
792
+ if (this.tabStrip && this.tabStrip.items) {
793
+ this.tabStrip.items.forEach((item) => {
794
+ if (preTintIcons) {
795
+ if (item.nativeView) {
796
+ this.setPreTintedIcons(item);
797
+ }
798
+ return;
799
+ }
800
+ if (this.mUnSelectedItemColor && item.nativeView) {
801
+ item.nativeView.image = this.getIcon(item, this.mUnSelectedItemColor);
802
+ item.nativeView.tintColor = this.mUnSelectedItemColor;
803
+ }
804
+ if (this.mSelectedItemColor && item.nativeView) {
805
+ item.nativeView.selectedImage = this.getIcon(item, this.mSelectedItemColor);
806
+ item.nativeView.tintColor = this.mSelectedItemColor;
807
+ }
808
+ });
809
+ }
810
+ }
811
+ }
812
+ updateAllItemsColors() {
813
+ this.setItemColors();
814
+ if (this.tabStrip && this.tabStrip.items) {
815
+ this.tabStrip.items.forEach((tabStripItem) => {
816
+ this.updateItemColors(tabStripItem);
817
+ });
818
+ }
819
+ }
820
+ updateItemColors(tabStripItem) {
821
+ updateBackgroundPositions(this.tabStrip, tabStripItem);
822
+ this.setIconColor(tabStripItem, true);
823
+ }
824
+ createTabBarItem(item, index) {
825
+ let image;
826
+ let title;
827
+ if (item.isLoaded) {
828
+ image = this.getIcon(item);
829
+ title = item.label.text;
830
+ const textTransform = item.label.style.textTransform;
831
+ if (textTransform) {
832
+ title = getTransformedText(title, textTransform);
833
+ }
834
+ }
835
+ return UITabBarItem.alloc().initWithTitleImageTag(title, image, index);
836
+ }
837
+ getIconRenderingMode() {
838
+ switch (this.tabStrip && this.tabStrip.iosIconRenderingMode) {
839
+ case 'alwaysOriginal':
840
+ return 1 /* UIImageRenderingMode.AlwaysOriginal */;
841
+ case 'alwaysTemplate':
842
+ return 2 /* UIImageRenderingMode.AlwaysTemplate */;
843
+ case 'automatic':
844
+ default:
845
+ return 0 /* UIImageRenderingMode.Automatic */;
846
+ }
847
+ }
848
+ getIcon(tabStripItem, color, tint = false) {
849
+ // Image and Label children of TabStripItem
850
+ // take priority over its `iconSource` and `title` properties
851
+ const iconSource = tabStripItem.image && tabStripItem.image.src;
852
+ if (!iconSource) {
853
+ return null;
854
+ }
855
+ // only explicit colors are baked in, so an unset selected color keeps following the tab bar tintColor
856
+ const tintColor = tint ? color : null;
857
+ const target = tabStripItem.image;
858
+ const font = target.style.fontInternal || Font.default;
859
+ if (!color) {
860
+ color = target.style.color;
861
+ }
862
+ const iconTag = [iconSource, font.fontStyle, font.fontWeight, font.fontSize, font.fontFamily, color, tintColor ? 'tinted' : ''].join(';');
863
+ let isFontIcon = false;
864
+ let image = this.mIconsCache[iconTag];
865
+ if (!image) {
866
+ let is;
867
+ if (typeof iconSource === 'string') {
868
+ if (Utils.isFontIconURI(iconSource)) {
869
+ isFontIcon = true;
870
+ const fontIconCode = iconSource.split('//')[1];
871
+ const target = tabStripItem.image ? tabStripItem.image : tabStripItem;
872
+ const font = target.style.fontInternal;
873
+ if (!color) {
874
+ color = target.style.color;
875
+ }
876
+ is = ImageSource.fromFontIconCodeSync(fontIconCode, font, color);
877
+ }
878
+ else {
879
+ is = ImageSource.fromFileOrResourceSync(iconSource);
880
+ }
881
+ }
882
+ else {
883
+ is = iconSource;
884
+ }
885
+ image = is?.ios;
886
+ if (image) {
887
+ image = is.ios;
888
+ if (this.tabStrip && this.tabStrip.isIconSizeFixed) {
889
+ image = this.getFixedSizeIcon(image);
890
+ }
891
+ let renderingMode = 1 /* UIImageRenderingMode.AlwaysOriginal */;
892
+ if (!isFontIcon) {
893
+ renderingMode = this.getIconRenderingMode();
894
+ }
895
+ let originalRenderedImage = image.imageWithRenderingMode(renderingMode);
896
+ if (tintColor && renderingMode !== 1 /* UIImageRenderingMode.AlwaysOriginal */) {
897
+ originalRenderedImage = image.imageWithTintColorRenderingMode(tintColor.ios, 1 /* UIImageRenderingMode.AlwaysOriginal */);
898
+ }
899
+ this.mIconsCache[iconTag] = originalRenderedImage;
900
+ image = originalRenderedImage;
901
+ }
902
+ else {
903
+ // TODO
904
+ // traceMissingIcon(iconSource);
905
+ }
906
+ }
907
+ return image;
908
+ }
909
+ getFixedSizeIcon(image) {
910
+ const inWidth = image.size.width;
911
+ const inHeight = image.size.height;
912
+ const iconSpecSize = getIconSpecSize({
913
+ width: inWidth,
914
+ height: inHeight
915
+ });
916
+ const widthPts = iconSpecSize.width;
917
+ const heightPts = iconSpecSize.height;
918
+ UIGraphicsBeginImageContextWithOptions({ width: widthPts, height: heightPts }, false, Utils.layout.getDisplayDensity());
919
+ image.drawInRect(CGRectMake(0, 0, widthPts, heightPts));
920
+ const resultImage = UIGraphicsGetImageFromCurrentImageContext();
921
+ UIGraphicsEndImageContext();
922
+ return resultImage;
923
+ }
924
+ // private _updateIOSTabBarColorsAndFonts(): void {
925
+ // if (!this.tabStrip || !this.tabStrip.items || !this.tabStrip.items.length) {
926
+ // return;
927
+ // }
928
+ // const tabBar = <UITabBar>this.ios.tabBar;
929
+ // const states = getTitleAttributesForStates(this);
930
+ // for (let i = 0; i < tabBar.items.count; i++) {
931
+ // applyStatesToItem(tabBar.items[i], states);
932
+ // }
933
+ // }
934
+ // TODO: Move this to TabStripItem
935
+ // [fontInternalProperty.getDefault](): Font {
936
+ // return null;
937
+ // }
938
+ // [fontInternalProperty.setNative](value: Font) {
939
+ // this._updateIOSTabBarColorsAndFonts();
940
+ // }
941
+ [selectedIndexProperty.setNative](value) {
942
+ // TODO
943
+ // if (Trace.isEnabled()) {
944
+ // Trace.write("TabView._onSelectedIndexPropertyChangedSetNativeValue(" + value + ")", Trace.categories.Debug);
945
+ // }
946
+ if (value > -1) {
947
+ this.viewController._willSelectViewController = this.mItemControllers[value];
948
+ if (this.mSearchTab && this.viewController.viewControllers == null) {
949
+ // tabs mode: the tabs have the identifiers `tab-<index>`
950
+ const tab = this.viewController.tabForIdentifier(`tab-${value}`);
951
+ if (tab) {
952
+ this.viewController.selectedTab = tab;
953
+ }
954
+ }
955
+ else {
956
+ this.viewController.selectedIndex = value;
957
+ }
958
+ }
959
+ }
960
+ [itemsProperty.getDefault]() {
961
+ return null;
962
+ }
963
+ [itemsProperty.setNative](value) {
964
+ if (value) {
965
+ value.forEach((item, i) => {
966
+ item.index = i;
967
+ });
968
+ }
969
+ this.setViewControllers(value);
970
+ selectedIndexProperty.coerce(this);
971
+ }
972
+ [tabStripProperty.getDefault]() {
973
+ return null;
974
+ }
975
+ [tabStripProperty.setNative](value) {
976
+ this.setViewControllers(this.items);
977
+ selectedIndexProperty.coerce(this);
978
+ }
979
+ setViewAttributes(item, view) {
980
+ if (!view) {
981
+ return null;
982
+ }
983
+ const defaultTabItemFontSize = 10;
984
+ const tabItemFontSize = view.style.fontSize || defaultTabItemFontSize;
985
+ const font = (view.style.fontInternal || Font.default).getUIFont(UIFont.systemFontOfSize(tabItemFontSize));
986
+ const tabItemTextColor = view.style.color;
987
+ const textColor = tabItemTextColor instanceof Color ? tabItemTextColor.ios : null;
988
+ const attributes = { [NSFontAttributeName]: font };
989
+ // if selectedItemColor or unSelectedItemColor is set we don't respect the color from the style
990
+ if (!this.mSelectedItemColor && !this.mUnSelectedItemColor) {
991
+ if (textColor) {
992
+ attributes[UITextAttributeTextColor] = textColor;
993
+ attributes[NSForegroundColorAttributeName] = textColor;
994
+ }
995
+ }
996
+ else {
997
+ this.viewController.tabBar.unselectedItemTintColor = this.mUnSelectedItemColor && this.mUnSelectedItemColor.ios;
998
+ this.viewController.tabBar.selectedImageTintColor = this.mSelectedItemColor && this.mSelectedItemColor.ios;
999
+ }
1000
+ item.setTitleTextAttributesForState(attributes, 4 /* UIControlState.Selected */);
1001
+ item.setTitleTextAttributesForState(attributes, 0 /* UIControlState.Normal */);
1002
+ // there's a bug when setting the item color on ios 13 if there's no background set to the tabstrip
1003
+ // https://books.google.bg/books?id=99_BDwAAQBAJ&q=tabBar.unselectedItemTintColor
1004
+ // to fix the above issue we are applying the selected fix only for the case, when there is no background set
1005
+ // in that case we have the following known issue:
1006
+ // // we will set the color to all unselected items, so you won't be able to set different colors for the different not selected items
1007
+ if (!this.viewController.tabBar.barTintColor && attributes[UITextAttributeTextColor] && SDK_VERSION > 9) {
1008
+ this.viewController.tabBar.unselectedItemTintColor = attributes[UITextAttributeTextColor];
1009
+ }
1010
+ }
1011
+ };
1012
+ BottomNavigation = __decorate([
1013
+ CSSType('BottomNavigation')
1014
+ ], BottomNavigation);
1015
+ export { BottomNavigation };
1016
+ iosCustomPositioningProperty.register(BottomNavigation);
1017
+ minimizeBehaviorProperty.register(BottomNavigation);
1018
+ accessoryProperty.register(BottomNavigation);
1019
+ searchTabProperty.register(BottomNavigation);
1020
+ searchHintProperty.register(BottomNavigation);
1021
+ searchContentProperty.register(BottomNavigation);
1022
+ //# sourceMappingURL=index.ios.js.map